Index: webrtc/libjingle/xmpp/pubsub_task.cc |
diff --git a/webrtc/libjingle/xmpp/pubsub_task.cc b/webrtc/libjingle/xmpp/pubsub_task.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..812cb95832cfef34d3116c2381511031e8532969 |
--- /dev/null |
+++ b/webrtc/libjingle/xmpp/pubsub_task.cc |
@@ -0,0 +1,201 @@ |
+/* |
+ * Copyright 2004 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/pubsub_task.h" |
+ |
+#include <map> |
+#include <memory> |
+#include <string> |
+ |
+#include "webrtc/libjingle/xmpp/constants.h" |
+#include "webrtc/libjingle/xmpp/xmppengine.h" |
+#include "webrtc/base/common.h" |
+ |
+namespace buzz { |
+ |
+PubsubTask::PubsubTask(XmppTaskParentInterface* parent, |
+ const buzz::Jid& pubsub_node_jid) |
+ : buzz::XmppTask(parent, buzz::XmppEngine::HL_SENDER), |
+ pubsub_node_jid_(pubsub_node_jid) { |
+} |
+ |
+PubsubTask::~PubsubTask() { |
+} |
+ |
+// Checks for pubsub publish events as well as responses to get IQs. |
+bool PubsubTask::HandleStanza(const buzz::XmlElement* stanza) { |
+ const buzz::QName& stanza_name(stanza->Name()); |
+ if (stanza_name == buzz::QN_MESSAGE) { |
+ if (MatchStanzaFrom(stanza, pubsub_node_jid_)) { |
+ const buzz::XmlElement* pubsub_event_item = |
+ stanza->FirstNamed(QN_PUBSUB_EVENT); |
+ if (pubsub_event_item != NULL) { |
+ QueueStanza(pubsub_event_item); |
+ return true; |
+ } |
+ } |
+ } else if (stanza_name == buzz::QN_IQ) { |
+ if (MatchResponseIq(stanza, pubsub_node_jid_, task_id())) { |
+ const buzz::XmlElement* pubsub_item = stanza->FirstNamed(QN_PUBSUB); |
+ if (pubsub_item != NULL) { |
+ QueueStanza(pubsub_item); |
+ return true; |
+ } |
+ } |
+ } |
+ return false; |
+} |
+ |
+int PubsubTask::ProcessResponse() { |
+ const buzz::XmlElement* stanza = NextStanza(); |
+ if (stanza == NULL) { |
+ return STATE_BLOCKED; |
+ } |
+ |
+ if (stanza->Attr(buzz::QN_TYPE) == buzz::STR_ERROR) { |
+ OnPubsubError(stanza->FirstNamed(buzz::QN_ERROR)); |
+ return STATE_RESPONSE; |
+ } |
+ |
+ const buzz::QName& stanza_name(stanza->Name()); |
+ if (stanza_name == QN_PUBSUB_EVENT) { |
+ HandlePubsubEventMessage(stanza); |
+ } else if (stanza_name == QN_PUBSUB) { |
+ HandlePubsubIqGetResponse(stanza); |
+ } |
+ |
+ return STATE_RESPONSE; |
+} |
+ |
+// Registers a function pointer to be called when the value of the pubsub |
+// node changes. |
+// Note that this does not actually change the XMPP pubsub |
+// subscription. All publish events are always received by everyone in the |
+// MUC. This function just controls whether the handle function will get |
+// called when the event is received. |
+bool PubsubTask::SubscribeToNode(const std::string& pubsub_node, |
+ NodeHandler handler) { |
+ subscribed_nodes_[pubsub_node] = handler; |
+ std::unique_ptr<buzz::XmlElement> get_iq_request( |
+ MakeIq(buzz::STR_GET, pubsub_node_jid_, task_id())); |
+ if (!get_iq_request) { |
+ return false; |
+ } |
+ buzz::XmlElement* pubsub_element = new buzz::XmlElement(QN_PUBSUB, true); |
+ buzz::XmlElement* items_element = new buzz::XmlElement(QN_PUBSUB_ITEMS, true); |
+ |
+ items_element->AddAttr(buzz::QN_NODE, pubsub_node); |
+ pubsub_element->AddElement(items_element); |
+ get_iq_request->AddElement(pubsub_element); |
+ |
+ if (SendStanza(get_iq_request.get()) != buzz::XMPP_RETURN_OK) { |
+ return false; |
+ } |
+ |
+ return true; |
+} |
+ |
+void PubsubTask::UnsubscribeFromNode(const std::string& pubsub_node) { |
+ subscribed_nodes_.erase(pubsub_node); |
+} |
+ |
+void PubsubTask::OnPubsubError(const buzz::XmlElement* error_stanza) { |
+} |
+ |
+// Checks for a pubsub event message like the following: |
+// |
+// <message from="muvc-private-chat-some-id@groupchat.google.com" |
+// to="john@site.com/gcomm582B14C9"> |
+// <event xmlns:"http://jabber.org/protocol/pubsub#event"> |
+// <items node="node-name"> |
+// <item id="some-id"> |
+// <payload/> |
+// </item> |
+// </items> |
+// </event> |
+// </message> |
+// |
+// It also checks for retraction event messages like the following: |
+// |
+// <message from="muvc-private-chat-some-id@groupchat.google.com" |
+// to="john@site.com/gcomm582B14C9"> |
+// <event xmlns:"http://jabber.org/protocol/pubsub#event"> |
+// <items node="node-name"> |
+// <retract id="some-id"/> |
+// </items> |
+// </event> |
+// </message> |
+void PubsubTask::HandlePubsubEventMessage( |
+ const buzz::XmlElement* pubsub_event) { |
+ ASSERT(pubsub_event->Name() == QN_PUBSUB_EVENT); |
+ for (const buzz::XmlChild* child = pubsub_event->FirstChild(); |
+ child != NULL; |
+ child = child->NextChild()) { |
+ const buzz::XmlElement* child_element = child->AsElement(); |
+ const buzz::QName& child_name(child_element->Name()); |
+ if (child_name == QN_PUBSUB_EVENT_ITEMS) { |
+ HandlePubsubItems(child_element); |
+ } |
+ } |
+} |
+ |
+// Checks for a response to an pubsub IQ get like the following: |
+// |
+// <iq from="muvc-private-chat-some-id@groupchat.google.com" |
+// to="john@site.com/gcomm582B14C9" |
+// type="result"> |
+// <pubsub xmlns:"http://jabber.org/protocol/pubsub"> |
+// <items node="node-name"> |
+// <item id="some-id"> |
+// <payload/> |
+// </item> |
+// </items> |
+// </event> |
+// </message> |
+void PubsubTask::HandlePubsubIqGetResponse( |
+ const buzz::XmlElement* pubsub_iq_response) { |
+ ASSERT(pubsub_iq_response->Name() == QN_PUBSUB); |
+ for (const buzz::XmlChild* child = pubsub_iq_response->FirstChild(); |
+ child != NULL; |
+ child = child->NextChild()) { |
+ const buzz::XmlElement* child_element = child->AsElement(); |
+ const buzz::QName& child_name(child_element->Name()); |
+ if (child_name == QN_PUBSUB_ITEMS) { |
+ HandlePubsubItems(child_element); |
+ } |
+ } |
+} |
+ |
+// Calls registered handlers in response to pubsub event or response to |
+// IQ pubsub get. |
+// 'items' is the child of a pubsub#event:event node or pubsub:pubsub node. |
+void PubsubTask::HandlePubsubItems(const buzz::XmlElement* items) { |
+ ASSERT(items->HasAttr(QN_NODE)); |
+ const std::string& node_name(items->Attr(QN_NODE)); |
+ NodeSubscriptions::iterator iter = subscribed_nodes_.find(node_name); |
+ if (iter != subscribed_nodes_.end()) { |
+ NodeHandler handler = iter->second; |
+ const buzz::XmlElement* item = items->FirstElement(); |
+ while (item != NULL) { |
+ const buzz::QName& item_name(item->Name()); |
+ if (item_name != QN_PUBSUB_EVENT_ITEM && |
+ item_name != QN_PUBSUB_EVENT_RETRACT && |
+ item_name != QN_PUBSUB_ITEM) { |
+ continue; |
+ } |
+ |
+ (this->*handler)(item); |
+ item = item->NextElement(); |
+ } |
+ return; |
+ } |
+} |
+ |
+} |