 28e2075280
			
		
	
	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;
 | |
|   }
 | |
| }
 | |
| 
 | |
| }
 |