1 /* 2 * libjingle 3 * Copyright 2004--2006, Google Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include "talk/xmpp/xmpptask.h" 29 #include "talk/xmpp/xmppclient.h" 30 #include "talk/xmpp/xmppengine.h" 31 #include "talk/xmpp/constants.h" 32 33 namespace buzz { 34 35 XmppClientInterface::XmppClientInterface() { 36 } 37 38 XmppClientInterface::~XmppClientInterface() { 39 } 40 41 XmppTask::XmppTask(XmppTaskParentInterface* parent, 42 XmppEngine::HandlerLevel level) 43 : XmppTaskBase(parent), stopped_(false) { 44 #ifdef _DEBUG 45 debug_force_timeout_ = false; 46 #endif 47 48 id_ = GetClient()->NextId(); 49 GetClient()->AddXmppTask(this, level); 50 GetClient()->SignalDisconnected.connect(this, &XmppTask::OnDisconnect); 51 } 52 53 XmppTask::~XmppTask() { 54 StopImpl(); 55 } 56 57 void XmppTask::StopImpl() { 58 while (NextStanza() != NULL) {} 59 if (!stopped_) { 60 GetClient()->RemoveXmppTask(this); 61 GetClient()->SignalDisconnected.disconnect(this); 62 stopped_ = true; 63 } 64 } 65 66 XmppReturnStatus XmppTask::SendStanza(const XmlElement* stanza) { 67 if (stopped_) 68 return XMPP_RETURN_BADSTATE; 69 return GetClient()->SendStanza(stanza); 70 } 71 72 XmppReturnStatus XmppTask::SendStanzaError(const XmlElement* element_original, 73 XmppStanzaError code, 74 const std::string& text) { 75 if (stopped_) 76 return XMPP_RETURN_BADSTATE; 77 return GetClient()->SendStanzaError(element_original, code, text); 78 } 79 80 void XmppTask::Stop() { 81 StopImpl(); 82 Task::Stop(); 83 } 84 85 void XmppTask::OnDisconnect() { 86 Error(); 87 } 88 89 void XmppTask::QueueStanza(const XmlElement* stanza) { 90 #ifdef _DEBUG 91 if (debug_force_timeout_) 92 return; 93 #endif 94 95 stanza_queue_.push_back(new XmlElement(*stanza)); 96 Wake(); 97 } 98 99 const XmlElement* XmppTask::NextStanza() { 100 XmlElement* result = NULL; 101 if (!stanza_queue_.empty()) { 102 result = stanza_queue_.front(); 103 stanza_queue_.pop_front(); 104 } 105 next_stanza_.reset(result); 106 return result; 107 } 108 109 XmlElement* XmppTask::MakeIq(const std::string& type, 110 const buzz::Jid& to, 111 const std::string& id) { 112 XmlElement* result = new XmlElement(QN_IQ); 113 if (!type.empty()) 114 result->AddAttr(QN_TYPE, type); 115 if (!to.IsEmpty()) 116 result->AddAttr(QN_TO, to.Str()); 117 if (!id.empty()) 118 result->AddAttr(QN_ID, id); 119 return result; 120 } 121 122 XmlElement* XmppTask::MakeIqResult(const XmlElement * query) { 123 XmlElement* result = new XmlElement(QN_IQ); 124 result->AddAttr(QN_TYPE, STR_RESULT); 125 if (query->HasAttr(QN_FROM)) { 126 result->AddAttr(QN_TO, query->Attr(QN_FROM)); 127 } 128 result->AddAttr(QN_ID, query->Attr(QN_ID)); 129 return result; 130 } 131 132 bool XmppTask::MatchResponseIq(const XmlElement* stanza, 133 const Jid& to, 134 const std::string& id) { 135 if (stanza->Name() != QN_IQ) 136 return false; 137 138 if (stanza->Attr(QN_ID) != id) 139 return false; 140 141 return MatchStanzaFrom(stanza, to); 142 } 143 144 bool XmppTask::MatchStanzaFrom(const XmlElement* stanza, 145 const Jid& to) { 146 Jid from(stanza->Attr(QN_FROM)); 147 if (from == to) 148 return true; 149 150 // We address the server as "", check if we are doing so here. 151 if (!to.IsEmpty()) 152 return false; 153 154 // It is legal for the server to identify itself with "domain" or 155 // "myself@domain" 156 Jid me = GetClient()->jid(); 157 return (from == Jid(me.domain())) || (from == me.BareJid()); 158 } 159 160 bool XmppTask::MatchRequestIq(const XmlElement* stanza, 161 const std::string& type, 162 const QName& qn) { 163 if (stanza->Name() != QN_IQ) 164 return false; 165 166 if (stanza->Attr(QN_TYPE) != type) 167 return false; 168 169 if (stanza->FirstNamed(qn) == NULL) 170 return false; 171 172 return true; 173 } 174 175 } 176