| 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;
|
| + }
|
| +}
|
| +
|
| +}
|
|
|