| /* |
| * 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 |