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 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> 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. 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. 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 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. 102 void ParseRetract(const XmlElement* retract_elem, 103 std::vector<PubSubItem>* items) { 104 ParseItem(retract_elem, items); 105 } 106 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 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 147 PubSubRequestTask::PubSubRequestTask(XmppTaskParentInterface* parent, 148 const Jid& pubsubjid, 149 const std::string& node) 150 : IqTask(parent, STR_GET, pubsubjid, CreatePubSubItemsElem(node)) { 151 } 152 153 void PubSubRequestTask::HandleResult(const XmlElement* stanza) { 154 std::vector<PubSubItem> items; 155 ParsePubSubItemsElem(stanza, &items); 156 SignalResult(this, items); 157 } 158 159 int PubSubReceiveTask::ProcessStart() { 160 if (SignalUpdate.is_empty()) { 161 return STATE_DONE; 162 } 163 return ReceiveTask::ProcessStart(); 164 } 165 166 bool PubSubReceiveTask::WantsStanza(const XmlElement* stanza) { 167 return MatchStanzaFrom(stanza, pubsubjid_) && 168 IsPubSubEventItemsElem(stanza, node_) && !SignalUpdate.is_empty(); 169 } 170 171 void PubSubReceiveTask::ReceiveStanza(const XmlElement* stanza) { 172 std::vector<PubSubItem> items; 173 ParseEventItemsElem(stanza, &items); 174 SignalUpdate(this, items); 175 } 176 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 187 void PubSubPublishTask::HandleResult(const XmlElement* stanza) { 188 SignalResult(this); 189 } 190 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 200 void PubSubRetractTask::HandleResult(const XmlElement* stanza) { 201 SignalResult(this); 202 } 203 204 } // namespace buzz 205