1 /*
2 * Copyright 2011 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "webrtc/libjingle/xmpp/pubsubtasks.h"
12
13 #include <string>
14 #include <vector>
15
16 #include "webrtc/libjingle/xmpp/constants.h"
17 #include "webrtc/libjingle/xmpp/receivetask.h"
18
19 // An implementation of the tasks for XEP-0060
20 // (http://xmpp.org/extensions/xep-0060.html).
21
22 namespace buzz {
23
24 namespace {
25
IsPubSubEventItemsElem(const XmlElement * stanza,const std::string & expected_node)26 bool IsPubSubEventItemsElem(const XmlElement* stanza,
27 const std::string& expected_node) {
28 if (stanza->Name() != QN_MESSAGE) {
29 return false;
30 }
31
32 const XmlElement* event_elem = stanza->FirstNamed(QN_PUBSUB_EVENT);
33 if (event_elem == NULL) {
34 return false;
35 }
36
37 const XmlElement* items_elem = event_elem->FirstNamed(QN_PUBSUB_EVENT_ITEMS);
38 if (items_elem == NULL) {
39 return false;
40 }
41
42 const std::string& actual_node = items_elem->Attr(QN_NODE);
43 return (actual_node == expected_node);
44 }
45
46
47 // Creates <pubsub node="node"><items></pubsub>
CreatePubSubItemsElem(const std::string & node)48 XmlElement* CreatePubSubItemsElem(const std::string& node) {
49 XmlElement* items_elem = new XmlElement(QN_PUBSUB_ITEMS, false);
50 items_elem->AddAttr(QN_NODE, node);
51 XmlElement* pubsub_elem = new XmlElement(QN_PUBSUB, false);
52 pubsub_elem->AddElement(items_elem);
53 return pubsub_elem;
54 }
55
56 // Creates <pubsub node="node"><publish><item id="itemid">payload</item>...
57 // Takes ownership of payload.
CreatePubSubPublishItemElem(const std::string & node,const std::string & itemid,const std::vector<XmlElement * > & children)58 XmlElement* CreatePubSubPublishItemElem(
59 const std::string& node,
60 const std::string& itemid,
61 const std::vector<XmlElement*>& children) {
62 XmlElement* pubsub_elem = new XmlElement(QN_PUBSUB, true);
63 XmlElement* publish_elem = new XmlElement(QN_PUBSUB_PUBLISH, false);
64 publish_elem->AddAttr(QN_NODE, node);
65 XmlElement* item_elem = new XmlElement(QN_PUBSUB_ITEM, false);
66 item_elem->AddAttr(QN_ID, itemid);
67 for (std::vector<XmlElement*>::const_iterator child = children.begin();
68 child != children.end(); ++child) {
69 item_elem->AddElement(*child);
70 }
71 publish_elem->AddElement(item_elem);
72 pubsub_elem->AddElement(publish_elem);
73 return pubsub_elem;
74 }
75
76 // Creates <pubsub node="node"><publish><item id="itemid">payload</item>...
77 // Takes ownership of payload.
CreatePubSubRetractItemElem(const std::string & node,const std::string & itemid)78 XmlElement* CreatePubSubRetractItemElem(const std::string& node,
79 const std::string& itemid) {
80 XmlElement* pubsub_elem = new XmlElement(QN_PUBSUB, true);
81 XmlElement* retract_elem = new XmlElement(QN_PUBSUB_RETRACT, false);
82 retract_elem->AddAttr(QN_NODE, node);
83 retract_elem->AddAttr(QN_NOTIFY, "true");
84 XmlElement* item_elem = new XmlElement(QN_PUBSUB_ITEM, false);
85 item_elem->AddAttr(QN_ID, itemid);
86 retract_elem->AddElement(item_elem);
87 pubsub_elem->AddElement(retract_elem);
88 return pubsub_elem;
89 }
90
ParseItem(const XmlElement * item_elem,std::vector<PubSubItem> * items)91 void ParseItem(const XmlElement* item_elem,
92 std::vector<PubSubItem>* items) {
93 PubSubItem item;
94 item.itemid = item_elem->Attr(QN_ID);
95 item.elem = item_elem;
96 items->push_back(item);
97 }
98
99 // Right now, <retract>s are treated the same as items with empty
100 // payloads. We may want to change it in the future, but right now
101 // it's sufficient for our needs.
ParseRetract(const XmlElement * retract_elem,std::vector<PubSubItem> * items)102 void ParseRetract(const XmlElement* retract_elem,
103 std::vector<PubSubItem>* items) {
104 ParseItem(retract_elem, items);
105 }
106
ParseEventItemsElem(const XmlElement * stanza,std::vector<PubSubItem> * items)107 void ParseEventItemsElem(const XmlElement* stanza,
108 std::vector<PubSubItem>* items) {
109 const XmlElement* event_elem = stanza->FirstNamed(QN_PUBSUB_EVENT);
110 if (event_elem != NULL) {
111 const XmlElement* items_elem =
112 event_elem->FirstNamed(QN_PUBSUB_EVENT_ITEMS);
113 if (items_elem != NULL) {
114 for (const XmlElement* item_elem =
115 items_elem->FirstNamed(QN_PUBSUB_EVENT_ITEM);
116 item_elem != NULL;
117 item_elem = item_elem->NextNamed(QN_PUBSUB_EVENT_ITEM)) {
118 ParseItem(item_elem, items);
119 }
120 for (const XmlElement* retract_elem =
121 items_elem->FirstNamed(QN_PUBSUB_EVENT_RETRACT);
122 retract_elem != NULL;
123 retract_elem = retract_elem->NextNamed(QN_PUBSUB_EVENT_RETRACT)) {
124 ParseRetract(retract_elem, items);
125 }
126 }
127 }
128 }
129
ParsePubSubItemsElem(const XmlElement * stanza,std::vector<PubSubItem> * items)130 void ParsePubSubItemsElem(const XmlElement* stanza,
131 std::vector<PubSubItem>* items) {
132 const XmlElement* pubsub_elem = stanza->FirstNamed(QN_PUBSUB);
133 if (pubsub_elem != NULL) {
134 const XmlElement* items_elem = pubsub_elem->FirstNamed(QN_PUBSUB_ITEMS);
135 if (items_elem != NULL) {
136 for (const XmlElement* item_elem = items_elem->FirstNamed(QN_PUBSUB_ITEM);
137 item_elem != NULL;
138 item_elem = item_elem->NextNamed(QN_PUBSUB_ITEM)) {
139 ParseItem(item_elem, items);
140 }
141 }
142 }
143 }
144
145 } // namespace
146
PubSubRequestTask(XmppTaskParentInterface * parent,const Jid & pubsubjid,const std::string & node)147 PubSubRequestTask::PubSubRequestTask(XmppTaskParentInterface* parent,
148 const Jid& pubsubjid,
149 const std::string& node)
150 : IqTask(parent, STR_GET, pubsubjid, CreatePubSubItemsElem(node)) {
151 }
152
HandleResult(const XmlElement * stanza)153 void PubSubRequestTask::HandleResult(const XmlElement* stanza) {
154 std::vector<PubSubItem> items;
155 ParsePubSubItemsElem(stanza, &items);
156 SignalResult(this, items);
157 }
158
ProcessStart()159 int PubSubReceiveTask::ProcessStart() {
160 if (SignalUpdate.is_empty()) {
161 return STATE_DONE;
162 }
163 return ReceiveTask::ProcessStart();
164 }
165
WantsStanza(const XmlElement * stanza)166 bool PubSubReceiveTask::WantsStanza(const XmlElement* stanza) {
167 return MatchStanzaFrom(stanza, pubsubjid_) &&
168 IsPubSubEventItemsElem(stanza, node_) && !SignalUpdate.is_empty();
169 }
170
ReceiveStanza(const XmlElement * stanza)171 void PubSubReceiveTask::ReceiveStanza(const XmlElement* stanza) {
172 std::vector<PubSubItem> items;
173 ParseEventItemsElem(stanza, &items);
174 SignalUpdate(this, items);
175 }
176
PubSubPublishTask(XmppTaskParentInterface * parent,const Jid & pubsubjid,const std::string & node,const std::string & itemid,const std::vector<XmlElement * > & children)177 PubSubPublishTask::PubSubPublishTask(XmppTaskParentInterface* parent,
178 const Jid& pubsubjid,
179 const std::string& node,
180 const std::string& itemid,
181 const std::vector<XmlElement*>& children)
182 : IqTask(parent, STR_SET, pubsubjid,
183 CreatePubSubPublishItemElem(node, itemid, children)),
184 itemid_(itemid) {
185 }
186
HandleResult(const XmlElement * stanza)187 void PubSubPublishTask::HandleResult(const XmlElement* stanza) {
188 SignalResult(this);
189 }
190
PubSubRetractTask(XmppTaskParentInterface * parent,const Jid & pubsubjid,const std::string & node,const std::string & itemid)191 PubSubRetractTask::PubSubRetractTask(XmppTaskParentInterface* parent,
192 const Jid& pubsubjid,
193 const std::string& node,
194 const std::string& itemid)
195 : IqTask(parent, STR_SET, pubsubjid,
196 CreatePubSubRetractItemElem(node, itemid)),
197 itemid_(itemid) {
198 }
199
HandleResult(const XmlElement * stanza)200 void PubSubRetractTask::HandleResult(const XmlElement* stanza) {
201 SignalResult(this);
202 }
203
204 } // namespace buzz
205