blob: 91e2c729bfc002e28631735f1dae86512078ac84 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:361/*
2 * libjingle
3 * Copyright 2004--2006, Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include "talk/xmpp/pubsub_task.h"
29
30#include <map>
31#include <string>
32
33#include "talk/base/common.h"
34#include "talk/xmpp/constants.h"
35#include "talk/xmpp/xmppengine.h"
36
37namespace buzz {
38
39PubsubTask::PubsubTask(XmppTaskParentInterface* parent,
40 const buzz::Jid& pubsub_node_jid)
41 : buzz::XmppTask(parent, buzz::XmppEngine::HL_SENDER),
42 pubsub_node_jid_(pubsub_node_jid) {
43}
44
45PubsubTask::~PubsubTask() {
46}
47
48// Checks for pubsub publish events as well as responses to get IQs.
49bool PubsubTask::HandleStanza(const buzz::XmlElement* stanza) {
50 const buzz::QName& stanza_name(stanza->Name());
51 if (stanza_name == buzz::QN_MESSAGE) {
52 if (MatchStanzaFrom(stanza, pubsub_node_jid_)) {
53 const buzz::XmlElement* pubsub_event_item =
54 stanza->FirstNamed(QN_PUBSUB_EVENT);
55 if (pubsub_event_item != NULL) {
56 QueueStanza(pubsub_event_item);
57 return true;
58 }
59 }
60 } else if (stanza_name == buzz::QN_IQ) {
61 if (MatchResponseIq(stanza, pubsub_node_jid_, task_id())) {
62 const buzz::XmlElement* pubsub_item = stanza->FirstNamed(QN_PUBSUB);
63 if (pubsub_item != NULL) {
64 QueueStanza(pubsub_item);
65 return true;
66 }
67 }
68 }
69 return false;
70}
71
72int PubsubTask::ProcessResponse() {
73 const buzz::XmlElement* stanza = NextStanza();
74 if (stanza == NULL) {
75 return STATE_BLOCKED;
76 }
77
78 if (stanza->Attr(buzz::QN_TYPE) == buzz::STR_ERROR) {
79 OnPubsubError(stanza->FirstNamed(buzz::QN_ERROR));
80 return STATE_RESPONSE;
81 }
82
83 const buzz::QName& stanza_name(stanza->Name());
84 if (stanza_name == QN_PUBSUB_EVENT) {
85 HandlePubsubEventMessage(stanza);
86 } else if (stanza_name == QN_PUBSUB) {
87 HandlePubsubIqGetResponse(stanza);
88 }
89
90 return STATE_RESPONSE;
91}
92
93// Registers a function pointer to be called when the value of the pubsub
94// node changes.
95// Note that this does not actually change the XMPP pubsub
96// subscription. All publish events are always received by everyone in the
97// MUC. This function just controls whether the handle function will get
98// called when the event is received.
99bool PubsubTask::SubscribeToNode(const std::string& pubsub_node,
100 NodeHandler handler) {
101 subscribed_nodes_[pubsub_node] = handler;
102 talk_base::scoped_ptr<buzz::XmlElement> get_iq_request(
103 MakeIq(buzz::STR_GET, pubsub_node_jid_, task_id()));
104 if (!get_iq_request) {
105 return false;
106 }
107 buzz::XmlElement* pubsub_element = new buzz::XmlElement(QN_PUBSUB, true);
108 buzz::XmlElement* items_element = new buzz::XmlElement(QN_PUBSUB_ITEMS, true);
109
110 items_element->AddAttr(buzz::QN_NODE, pubsub_node);
111 pubsub_element->AddElement(items_element);
112 get_iq_request->AddElement(pubsub_element);
113
114 if (SendStanza(get_iq_request.get()) != buzz::XMPP_RETURN_OK) {
115 return false;
116 }
117
118 return true;
119}
120
121void PubsubTask::UnsubscribeFromNode(const std::string& pubsub_node) {
122 subscribed_nodes_.erase(pubsub_node);
123}
124
125void PubsubTask::OnPubsubError(const buzz::XmlElement* error_stanza) {
126}
127
128// Checks for a pubsub event message like the following:
129//
130// <message from="muvc-private-chat-some-id@groupchat.google.com"
131// to="john@site.com/gcomm582B14C9">
132// <event xmlns:"http://jabber.org/protocol/pubsub#event">
133// <items node="node-name">
134// <item id="some-id">
135// <payload/>
136// </item>
137// </items>
138// </event>
139// </message>
140//
141// It also checks for retraction event messages like the following:
142//
143// <message from="muvc-private-chat-some-id@groupchat.google.com"
144// to="john@site.com/gcomm582B14C9">
145// <event xmlns:"http://jabber.org/protocol/pubsub#event">
146// <items node="node-name">
147// <retract id="some-id"/>
148// </items>
149// </event>
150// </message>
151void PubsubTask::HandlePubsubEventMessage(
152 const buzz::XmlElement* pubsub_event) {
153 ASSERT(pubsub_event->Name() == QN_PUBSUB_EVENT);
154 for (const buzz::XmlChild* child = pubsub_event->FirstChild();
155 child != NULL;
156 child = child->NextChild()) {
157 const buzz::XmlElement* child_element = child->AsElement();
158 const buzz::QName& child_name(child_element->Name());
159 if (child_name == QN_PUBSUB_EVENT_ITEMS) {
160 HandlePubsubItems(child_element);
161 }
162 }
163}
164
165// Checks for a response to an pubsub IQ get like the following:
166//
167// <iq from="muvc-private-chat-some-id@groupchat.google.com"
168// to="john@site.com/gcomm582B14C9"
169// type="result">
170// <pubsub xmlns:"http://jabber.org/protocol/pubsub">
171// <items node="node-name">
172// <item id="some-id">
173// <payload/>
174// </item>
175// </items>
176// </event>
177// </message>
178void PubsubTask::HandlePubsubIqGetResponse(
179 const buzz::XmlElement* pubsub_iq_response) {
180 ASSERT(pubsub_iq_response->Name() == QN_PUBSUB);
181 for (const buzz::XmlChild* child = pubsub_iq_response->FirstChild();
182 child != NULL;
183 child = child->NextChild()) {
184 const buzz::XmlElement* child_element = child->AsElement();
185 const buzz::QName& child_name(child_element->Name());
186 if (child_name == QN_PUBSUB_ITEMS) {
187 HandlePubsubItems(child_element);
188 }
189 }
190}
191
192// Calls registered handlers in response to pubsub event or response to
193// IQ pubsub get.
194// 'items' is the child of a pubsub#event:event node or pubsub:pubsub node.
195void PubsubTask::HandlePubsubItems(const buzz::XmlElement* items) {
196 ASSERT(items->HasAttr(QN_NODE));
197 const std::string& node_name(items->Attr(QN_NODE));
198 NodeSubscriptions::iterator iter = subscribed_nodes_.find(node_name);
199 if (iter != subscribed_nodes_.end()) {
200 NodeHandler handler = iter->second;
201 const buzz::XmlElement* item = items->FirstElement();
202 while (item != NULL) {
203 const buzz::QName& item_name(item->Name());
204 if (item_name != QN_PUBSUB_EVENT_ITEM &&
205 item_name != QN_PUBSUB_EVENT_RETRACT &&
206 item_name != QN_PUBSUB_ITEM) {
207 continue;
208 }
209
210 (this->*handler)(item);
211 item = item->NextElement();
212 }
213 return;
214 }
215}
216
217}