Index: webrtc/libjingle/xmpp/pubsubtasks.cc |
diff --git a/webrtc/libjingle/xmpp/pubsubtasks.cc b/webrtc/libjingle/xmpp/pubsubtasks.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..d6532598b564075304808433795cc25fcb024e82 |
--- /dev/null |
+++ b/webrtc/libjingle/xmpp/pubsubtasks.cc |
@@ -0,0 +1,204 @@ |
+/* |
+ * Copyright 2011 The WebRTC Project Authors. All rights reserved. |
+ * |
+ * Use of this source code is governed by a BSD-style license |
+ * that can be found in the LICENSE file in the root of the source |
+ * tree. An additional intellectual property rights grant can be found |
+ * in the file PATENTS. All contributing project authors may |
+ * be found in the AUTHORS file in the root of the source tree. |
+ */ |
+ |
+#include "webrtc/libjingle/xmpp/pubsubtasks.h" |
+ |
+#include <string> |
+#include <vector> |
+ |
+#include "webrtc/libjingle/xmpp/constants.h" |
+#include "webrtc/libjingle/xmpp/receivetask.h" |
+ |
+// An implementation of the tasks for XEP-0060 |
+// (http://xmpp.org/extensions/xep-0060.html). |
+ |
+namespace buzz { |
+ |
+namespace { |
+ |
+bool IsPubSubEventItemsElem(const XmlElement* stanza, |
+ const std::string& expected_node) { |
+ if (stanza->Name() != QN_MESSAGE) { |
+ return false; |
+ } |
+ |
+ const XmlElement* event_elem = stanza->FirstNamed(QN_PUBSUB_EVENT); |
+ if (event_elem == NULL) { |
+ return false; |
+ } |
+ |
+ const XmlElement* items_elem = event_elem->FirstNamed(QN_PUBSUB_EVENT_ITEMS); |
+ if (items_elem == NULL) { |
+ return false; |
+ } |
+ |
+ const std::string& actual_node = items_elem->Attr(QN_NODE); |
+ return (actual_node == expected_node); |
+} |
+ |
+ |
+// Creates <pubsub node="node"><items></pubsub> |
+XmlElement* CreatePubSubItemsElem(const std::string& node) { |
+ XmlElement* items_elem = new XmlElement(QN_PUBSUB_ITEMS, false); |
+ items_elem->AddAttr(QN_NODE, node); |
+ XmlElement* pubsub_elem = new XmlElement(QN_PUBSUB, false); |
+ pubsub_elem->AddElement(items_elem); |
+ return pubsub_elem; |
+} |
+ |
+// Creates <pubsub node="node"><publish><item id="itemid">payload</item>... |
+// Takes ownership of payload. |
+XmlElement* CreatePubSubPublishItemElem( |
+ const std::string& node, |
+ const std::string& itemid, |
+ const std::vector<XmlElement*>& children) { |
+ XmlElement* pubsub_elem = new XmlElement(QN_PUBSUB, true); |
+ XmlElement* publish_elem = new XmlElement(QN_PUBSUB_PUBLISH, false); |
+ publish_elem->AddAttr(QN_NODE, node); |
+ XmlElement* item_elem = new XmlElement(QN_PUBSUB_ITEM, false); |
+ item_elem->AddAttr(QN_ID, itemid); |
+ for (std::vector<XmlElement*>::const_iterator child = children.begin(); |
+ child != children.end(); ++child) { |
+ item_elem->AddElement(*child); |
+ } |
+ publish_elem->AddElement(item_elem); |
+ pubsub_elem->AddElement(publish_elem); |
+ return pubsub_elem; |
+} |
+ |
+// Creates <pubsub node="node"><publish><item id="itemid">payload</item>... |
+// Takes ownership of payload. |
+XmlElement* CreatePubSubRetractItemElem(const std::string& node, |
+ const std::string& itemid) { |
+ XmlElement* pubsub_elem = new XmlElement(QN_PUBSUB, true); |
+ XmlElement* retract_elem = new XmlElement(QN_PUBSUB_RETRACT, false); |
+ retract_elem->AddAttr(QN_NODE, node); |
+ retract_elem->AddAttr(QN_NOTIFY, "true"); |
+ XmlElement* item_elem = new XmlElement(QN_PUBSUB_ITEM, false); |
+ item_elem->AddAttr(QN_ID, itemid); |
+ retract_elem->AddElement(item_elem); |
+ pubsub_elem->AddElement(retract_elem); |
+ return pubsub_elem; |
+} |
+ |
+void ParseItem(const XmlElement* item_elem, |
+ std::vector<PubSubItem>* items) { |
+ PubSubItem item; |
+ item.itemid = item_elem->Attr(QN_ID); |
+ item.elem = item_elem; |
+ items->push_back(item); |
+} |
+ |
+// Right now, <retract>s are treated the same as items with empty |
+// payloads. We may want to change it in the future, but right now |
+// it's sufficient for our needs. |
+void ParseRetract(const XmlElement* retract_elem, |
+ std::vector<PubSubItem>* items) { |
+ ParseItem(retract_elem, items); |
+} |
+ |
+void ParseEventItemsElem(const XmlElement* stanza, |
+ std::vector<PubSubItem>* items) { |
+ const XmlElement* event_elem = stanza->FirstNamed(QN_PUBSUB_EVENT); |
+ if (event_elem != NULL) { |
+ const XmlElement* items_elem = |
+ event_elem->FirstNamed(QN_PUBSUB_EVENT_ITEMS); |
+ if (items_elem != NULL) { |
+ for (const XmlElement* item_elem = |
+ items_elem->FirstNamed(QN_PUBSUB_EVENT_ITEM); |
+ item_elem != NULL; |
+ item_elem = item_elem->NextNamed(QN_PUBSUB_EVENT_ITEM)) { |
+ ParseItem(item_elem, items); |
+ } |
+ for (const XmlElement* retract_elem = |
+ items_elem->FirstNamed(QN_PUBSUB_EVENT_RETRACT); |
+ retract_elem != NULL; |
+ retract_elem = retract_elem->NextNamed(QN_PUBSUB_EVENT_RETRACT)) { |
+ ParseRetract(retract_elem, items); |
+ } |
+ } |
+ } |
+} |
+ |
+void ParsePubSubItemsElem(const XmlElement* stanza, |
+ std::vector<PubSubItem>* items) { |
+ const XmlElement* pubsub_elem = stanza->FirstNamed(QN_PUBSUB); |
+ if (pubsub_elem != NULL) { |
+ const XmlElement* items_elem = pubsub_elem->FirstNamed(QN_PUBSUB_ITEMS); |
+ if (items_elem != NULL) { |
+ for (const XmlElement* item_elem = items_elem->FirstNamed(QN_PUBSUB_ITEM); |
+ item_elem != NULL; |
+ item_elem = item_elem->NextNamed(QN_PUBSUB_ITEM)) { |
+ ParseItem(item_elem, items); |
+ } |
+ } |
+ } |
+} |
+ |
+} // namespace |
+ |
+PubSubRequestTask::PubSubRequestTask(XmppTaskParentInterface* parent, |
+ const Jid& pubsubjid, |
+ const std::string& node) |
+ : IqTask(parent, STR_GET, pubsubjid, CreatePubSubItemsElem(node)) { |
+} |
+ |
+void PubSubRequestTask::HandleResult(const XmlElement* stanza) { |
+ std::vector<PubSubItem> items; |
+ ParsePubSubItemsElem(stanza, &items); |
+ SignalResult(this, items); |
+} |
+ |
+int PubSubReceiveTask::ProcessStart() { |
+ if (SignalUpdate.is_empty()) { |
+ return STATE_DONE; |
+ } |
+ return ReceiveTask::ProcessStart(); |
+} |
+ |
+bool PubSubReceiveTask::WantsStanza(const XmlElement* stanza) { |
+ return MatchStanzaFrom(stanza, pubsubjid_) && |
+ IsPubSubEventItemsElem(stanza, node_) && !SignalUpdate.is_empty(); |
+} |
+ |
+void PubSubReceiveTask::ReceiveStanza(const XmlElement* stanza) { |
+ std::vector<PubSubItem> items; |
+ ParseEventItemsElem(stanza, &items); |
+ SignalUpdate(this, items); |
+} |
+ |
+PubSubPublishTask::PubSubPublishTask(XmppTaskParentInterface* parent, |
+ const Jid& pubsubjid, |
+ const std::string& node, |
+ const std::string& itemid, |
+ const std::vector<XmlElement*>& children) |
+ : IqTask(parent, STR_SET, pubsubjid, |
+ CreatePubSubPublishItemElem(node, itemid, children)), |
+ itemid_(itemid) { |
+} |
+ |
+void PubSubPublishTask::HandleResult(const XmlElement* stanza) { |
+ SignalResult(this); |
+} |
+ |
+PubSubRetractTask::PubSubRetractTask(XmppTaskParentInterface* parent, |
+ const Jid& pubsubjid, |
+ const std::string& node, |
+ const std::string& itemid) |
+ : IqTask(parent, STR_SET, pubsubjid, |
+ CreatePubSubRetractItemElem(node, itemid)), |
+ itemid_(itemid) { |
+} |
+ |
+void PubSubRetractTask::HandleResult(const XmlElement* stanza) { |
+ SignalResult(this); |
+} |
+ |
+} // namespace buzz |