28e2075280
trunk/talk git-svn-id: http://webrtc.googlecode.com/svn/trunk@4318 4adac7df-926f-26a2-2b94-8c16560cd09d
218 lines
7.3 KiB
C++
218 lines
7.3 KiB
C++
/*
|
|
* libjingle
|
|
* Copyright 2004--2006, Google Inc.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
* and/or other materials provided with the distribution.
|
|
* 3. The name of the author may not be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
|
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
|
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "talk/xmpp/pubsub_task.h"
|
|
|
|
#include <map>
|
|
#include <string>
|
|
|
|
#include "talk/base/common.h"
|
|
#include "talk/xmpp/constants.h"
|
|
#include "talk/xmpp/xmppengine.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;
|
|
talk_base::scoped_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;
|
|
}
|
|
}
|
|
|
|
}
|