Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(741)

Unified Diff: webrtc/libjingle/xmpp/rostermoduleimpl.cc

Issue 2618633003: Revert of Remove webrtc/libjingle/{xmllite,xmpp} (Closed)
Patch Set: Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « webrtc/libjingle/xmpp/rostermoduleimpl.h ('k') | webrtc/libjingle/xmpp/saslcookiemechanism.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: webrtc/libjingle/xmpp/rostermoduleimpl.cc
diff --git a/webrtc/libjingle/xmpp/rostermoduleimpl.cc b/webrtc/libjingle/xmpp/rostermoduleimpl.cc
new file mode 100644
index 0000000000000000000000000000000000000000..b9752896efad84b0d4970be44f3e125b4260b452
--- /dev/null
+++ b/webrtc/libjingle/xmpp/rostermoduleimpl.cc
@@ -0,0 +1,1064 @@
+/*
+ * 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 <algorithm>
+#include <iostream>
+#include <map>
+#include <sstream>
+#include <string>
+#include <vector>
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/libjingle/xmpp/rostermoduleimpl.h"
+#include "webrtc/base/common.h"
+#include "webrtc/base/stringencode.h"
+
+namespace buzz {
+
+// enum prase and persist helpers ----------------------------------------------
+static bool
+StringToPresenceShow(const std::string& input, XmppPresenceShow* show) {
+ // If this becomes a perf issue we can use a hash or a map here
+ if (STR_SHOW_AWAY == input)
+ *show = XMPP_PRESENCE_AWAY;
+ else if (STR_SHOW_DND == input)
+ *show = XMPP_PRESENCE_DND;
+ else if (STR_SHOW_XA == input)
+ *show = XMPP_PRESENCE_XA;
+ else if (STR_SHOW_CHAT == input)
+ *show = XMPP_PRESENCE_CHAT;
+ else if (STR_EMPTY == input)
+ *show = XMPP_PRESENCE_DEFAULT;
+ else
+ return false;
+
+ return true;
+}
+
+static bool
+PresenceShowToString(XmppPresenceShow show, const char** output) {
+ switch(show) {
+ case XMPP_PRESENCE_AWAY:
+ *output = STR_SHOW_AWAY;
+ return true;
+ case XMPP_PRESENCE_CHAT:
+ *output = STR_SHOW_CHAT;
+ return true;
+ case XMPP_PRESENCE_XA:
+ *output = STR_SHOW_XA;
+ return true;
+ case XMPP_PRESENCE_DND:
+ *output = STR_SHOW_DND;
+ return true;
+ case XMPP_PRESENCE_DEFAULT:
+ *output = STR_EMPTY;
+ return true;
+ }
+
+ *output = STR_EMPTY;
+ return false;
+}
+
+static bool
+StringToSubscriptionState(const std::string& subscription,
+ const std::string& ask,
+ XmppSubscriptionState* state)
+{
+ if (ask == "subscribe")
+ {
+ if (subscription == "none") {
+ *state = XMPP_SUBSCRIPTION_NONE_ASKED;
+ return true;
+ }
+ if (subscription == "from") {
+ *state = XMPP_SUBSCRIPTION_FROM_ASKED;
+ return true;
+ }
+ } else if (ask == STR_EMPTY)
+ {
+ if (subscription == "none") {
+ *state = XMPP_SUBSCRIPTION_NONE;
+ return true;
+ }
+ if (subscription == "from") {
+ *state = XMPP_SUBSCRIPTION_FROM;
+ return true;
+ }
+ if (subscription == "to") {
+ *state = XMPP_SUBSCRIPTION_TO;
+ return true;
+ }
+ if (subscription == "both") {
+ *state = XMPP_SUBSCRIPTION_BOTH;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool
+StringToSubscriptionRequestType(const std::string& string,
+ XmppSubscriptionRequestType* type)
+{
+ if (string == "subscribe")
+ *type = XMPP_REQUEST_SUBSCRIBE;
+ else if (string == "unsubscribe")
+ *type = XMPP_REQUEST_UNSUBSCRIBE;
+ else if (string == "subscribed")
+ *type = XMPP_REQUEST_SUBSCRIBED;
+ else if (string == "unsubscribed")
+ *type = XMPP_REQUEST_UNSUBSCRIBED;
+ else
+ return false;
+ return true;
+}
+
+// XmppPresenceImpl class ------------------------------------------------------
+XmppPresence*
+XmppPresence::Create() {
+ return new XmppPresenceImpl();
+}
+
+XmppPresenceImpl::XmppPresenceImpl() {
+}
+
+const Jid
+XmppPresenceImpl::jid() const {
+ if (!raw_xml_)
+ return Jid();
+
+ return Jid(raw_xml_->Attr(QN_FROM));
+}
+
+XmppPresenceAvailable
+XmppPresenceImpl::available() const {
+ if (!raw_xml_)
+ return XMPP_PRESENCE_UNAVAILABLE;
+
+ if (raw_xml_->Attr(QN_TYPE) == "unavailable")
+ return XMPP_PRESENCE_UNAVAILABLE;
+ else if (raw_xml_->Attr(QN_TYPE) == "error")
+ return XMPP_PRESENCE_ERROR;
+ else
+ return XMPP_PRESENCE_AVAILABLE;
+}
+
+XmppReturnStatus
+XmppPresenceImpl::set_available(XmppPresenceAvailable available) {
+ if (!raw_xml_)
+ CreateRawXmlSkeleton();
+
+ if (available == XMPP_PRESENCE_AVAILABLE)
+ raw_xml_->ClearAttr(QN_TYPE);
+ else if (available == XMPP_PRESENCE_UNAVAILABLE)
+ raw_xml_->SetAttr(QN_TYPE, "unavailable");
+ else if (available == XMPP_PRESENCE_ERROR)
+ raw_xml_->SetAttr(QN_TYPE, "error");
+ return XMPP_RETURN_OK;
+}
+
+XmppPresenceShow
+XmppPresenceImpl::presence_show() const {
+ if (!raw_xml_)
+ return XMPP_PRESENCE_DEFAULT;
+
+ XmppPresenceShow show = XMPP_PRESENCE_DEFAULT;
+ StringToPresenceShow(raw_xml_->TextNamed(QN_SHOW), &show);
+ return show;
+}
+
+XmppReturnStatus
+XmppPresenceImpl::set_presence_show(XmppPresenceShow show) {
+ if (!raw_xml_)
+ CreateRawXmlSkeleton();
+
+ const char* show_string;
+
+ if(!PresenceShowToString(show, &show_string))
+ return XMPP_RETURN_BADARGUMENT;
+
+ raw_xml_->ClearNamedChildren(QN_SHOW);
+
+ if (show!=XMPP_PRESENCE_DEFAULT) {
+ raw_xml_->AddElement(new XmlElement(QN_SHOW));
+ raw_xml_->AddText(show_string, 1);
+ }
+
+ return XMPP_RETURN_OK;
+}
+
+int
+XmppPresenceImpl::priority() const {
+ if (!raw_xml_)
+ return 0;
+
+ int raw_priority = 0;
+ if (!rtc::FromString(raw_xml_->TextNamed(QN_PRIORITY), &raw_priority))
+ raw_priority = 0;
+ if (raw_priority < -128)
+ raw_priority = -128;
+ if (raw_priority > 127)
+ raw_priority = 127;
+
+ return raw_priority;
+}
+
+XmppReturnStatus
+XmppPresenceImpl::set_priority(int priority) {
+ if (!raw_xml_)
+ CreateRawXmlSkeleton();
+
+ if (priority < -128 || priority > 127)
+ return XMPP_RETURN_BADARGUMENT;
+
+ raw_xml_->ClearNamedChildren(QN_PRIORITY);
+ if (0 != priority) {
+ std::string priority_string;
+ if (rtc::ToString(priority, &priority_string)) {
+ raw_xml_->AddElement(new XmlElement(QN_PRIORITY));
+ raw_xml_->AddText(priority_string, 1);
+ }
+ }
+
+ return XMPP_RETURN_OK;
+}
+
+const std::string
+XmppPresenceImpl::status() const {
+ if (!raw_xml_)
+ return STR_EMPTY;
+
+ XmlElement* status_element;
+ XmlElement* element;
+
+ // Search for a status element with no xml:lang attribute on it. if we can't
+ // find that then just return the first status element in the stanza.
+ for (status_element = element = raw_xml_->FirstNamed(QN_STATUS);
+ element;
+ element = element->NextNamed(QN_STATUS)) {
+ if (!element->HasAttr(QN_XML_LANG)) {
+ status_element = element;
+ break;
+ }
+ }
+
+ if (status_element) {
+ return status_element->BodyText();
+ }
+
+ return STR_EMPTY;
+}
+
+XmppReturnStatus
+XmppPresenceImpl::set_status(const std::string& status) {
+ if (!raw_xml_)
+ CreateRawXmlSkeleton();
+
+ raw_xml_->ClearNamedChildren(QN_STATUS);
+
+ if (status != STR_EMPTY) {
+ raw_xml_->AddElement(new XmlElement(QN_STATUS));
+ raw_xml_->AddText(status, 1);
+ }
+
+ return XMPP_RETURN_OK;
+}
+
+XmppPresenceConnectionStatus
+XmppPresenceImpl::connection_status() const {
+ if (!raw_xml_)
+ return XMPP_CONNECTION_STATUS_UNKNOWN;
+
+ XmlElement* con = raw_xml_->FirstNamed(QN_GOOGLE_PSTN_CONFERENCE_STATUS);
+ if (con) {
+ std::string status = con->Attr(QN_ATTR_STATUS);
+ if (status == STR_PSTN_CONFERENCE_STATUS_CONNECTING)
+ return XMPP_CONNECTION_STATUS_CONNECTING;
+ else if (status == STR_PSTN_CONFERENCE_STATUS_CONNECTED)
+ return XMPP_CONNECTION_STATUS_CONNECTED;
+ else if (status == STR_PSTN_CONFERENCE_STATUS_JOINING)
+ return XMPP_CONNECTION_STATUS_JOINING;
+ else if (status == STR_PSTN_CONFERENCE_STATUS_HANGUP)
+ return XMPP_CONNECTION_STATUS_HANGUP;
+ }
+
+ return XMPP_CONNECTION_STATUS_CONNECTED;
+}
+
+const std::string
+XmppPresenceImpl::google_user_id() const {
+ if (!raw_xml_)
+ return std::string();
+
+ XmlElement* muc_user_x = raw_xml_->FirstNamed(QN_MUC_USER_X);
+ if (muc_user_x) {
+ XmlElement* muc_user_item = muc_user_x->FirstNamed(QN_MUC_USER_ITEM);
+ if (muc_user_item) {
+ return muc_user_item->Attr(QN_GOOGLE_USER_ID);
+ }
+ }
+
+ return std::string();
+}
+
+const std::string
+XmppPresenceImpl::nickname() const {
+ if (!raw_xml_)
+ return std::string();
+
+ XmlElement* nickname = raw_xml_->FirstNamed(QN_NICKNAME);
+ if (nickname) {
+ return nickname->BodyText();
+ }
+
+ return std::string();
+}
+
+const XmlElement*
+XmppPresenceImpl::raw_xml() const {
+ if (!raw_xml_)
+ const_cast<XmppPresenceImpl*>(this)->CreateRawXmlSkeleton();
+ return raw_xml_.get();
+}
+
+XmppReturnStatus
+XmppPresenceImpl::set_raw_xml(const XmlElement * xml) {
+ if (!xml ||
+ xml->Name() != QN_PRESENCE)
+ return XMPP_RETURN_BADARGUMENT;
+
+ raw_xml_.reset(new XmlElement(*xml));
+ return XMPP_RETURN_OK;
+}
+
+void
+XmppPresenceImpl::CreateRawXmlSkeleton() {
+ raw_xml_.reset(new XmlElement(QN_PRESENCE));
+}
+
+// XmppRosterContactImpl -------------------------------------------------------
+XmppRosterContact*
+XmppRosterContact::Create() {
+ return new XmppRosterContactImpl();
+}
+
+XmppRosterContactImpl::XmppRosterContactImpl() {
+ ResetGroupCache();
+}
+
+void
+XmppRosterContactImpl::SetXmlFromWire(const XmlElement* xml) {
+ ResetGroupCache();
+ if (xml)
+ raw_xml_.reset(new XmlElement(*xml));
+ else
+ raw_xml_.reset(NULL);
+}
+
+void
+XmppRosterContactImpl::ResetGroupCache() {
+ group_count_ = -1;
+ group_index_returned_ = -1;
+ group_returned_ = NULL;
+}
+
+const Jid
+XmppRosterContactImpl::jid() const {
+ return Jid(raw_xml_->Attr(QN_JID));
+}
+
+XmppReturnStatus
+XmppRosterContactImpl::set_jid(const Jid& jid)
+{
+ if (!raw_xml_)
+ CreateRawXmlSkeleton();
+
+ if (!jid.IsValid())
+ return XMPP_RETURN_BADARGUMENT;
+
+ raw_xml_->SetAttr(QN_JID, jid.Str());
+
+ return XMPP_RETURN_OK;
+}
+
+const std::string
+XmppRosterContactImpl::name() const {
+ return raw_xml_->Attr(QN_NAME);
+}
+
+XmppReturnStatus
+XmppRosterContactImpl::set_name(const std::string& name) {
+ if (!raw_xml_)
+ CreateRawXmlSkeleton();
+
+ if (name == STR_EMPTY)
+ raw_xml_->ClearAttr(QN_NAME);
+ else
+ raw_xml_->SetAttr(QN_NAME, name);
+
+ return XMPP_RETURN_OK;
+}
+
+XmppSubscriptionState
+XmppRosterContactImpl::subscription_state() const {
+ if (!raw_xml_)
+ return XMPP_SUBSCRIPTION_NONE;
+
+ XmppSubscriptionState state = XMPP_SUBSCRIPTION_NONE;
+
+ if (StringToSubscriptionState(raw_xml_->Attr(QN_SUBSCRIPTION),
+ raw_xml_->Attr(QN_ASK),
+ &state))
+ return state;
+
+ return XMPP_SUBSCRIPTION_NONE;
+}
+
+size_t
+XmppRosterContactImpl::GetGroupCount() const {
+ if (!raw_xml_)
+ return 0;
+
+ if (-1 == group_count_) {
+ XmlElement *group_element = raw_xml_->FirstNamed(QN_ROSTER_GROUP);
+ int group_count = 0;
+ while(group_element) {
+ group_count++;
+ group_element = group_element->NextNamed(QN_ROSTER_GROUP);
+ }
+
+ ASSERT(group_count > 0); // protect the cast
+ XmppRosterContactImpl * me = const_cast<XmppRosterContactImpl*>(this);
+ me->group_count_ = group_count;
+ }
+
+ return group_count_;
+}
+
+const std::string
+XmppRosterContactImpl::GetGroup(size_t index) const {
+ if (index >= GetGroupCount())
+ return STR_EMPTY;
+
+ // We cache the last group index and element that we returned. This way
+ // going through the groups in order is order n and not n^2. This could be
+ // enhanced if necessary by starting at the cached value if the index asked
+ // is after the cached one.
+ if (group_index_returned_ >= 0 &&
+ index == static_cast<size_t>(group_index_returned_) + 1)
+ {
+ XmppRosterContactImpl * me = const_cast<XmppRosterContactImpl*>(this);
+ me->group_returned_ = group_returned_->NextNamed(QN_ROSTER_GROUP);
+ ASSERT(group_returned_ != NULL);
+ me->group_index_returned_++;
+ } else if (group_index_returned_ < 0 ||
+ static_cast<size_t>(group_index_returned_) != index) {
+ XmlElement * group_element = raw_xml_->FirstNamed(QN_ROSTER_GROUP);
+ size_t group_index = 0;
+ while(group_index < index) {
+ ASSERT(group_element != NULL);
+ group_index++;
+ group_element = group_element->NextNamed(QN_ROSTER_GROUP);
+ }
+
+ XmppRosterContactImpl * me = const_cast<XmppRosterContactImpl*>(this);
+ me->group_index_returned_ = static_cast<int>(group_index);
+ me->group_returned_ = group_element;
+ }
+
+ return group_returned_->BodyText();
+}
+
+XmppReturnStatus
+XmppRosterContactImpl::AddGroup(const std::string& group) {
+ if (group == STR_EMPTY)
+ return XMPP_RETURN_BADARGUMENT;
+
+ if (!raw_xml_)
+ CreateRawXmlSkeleton();
+
+ if (FindGroup(group, NULL, NULL))
+ return XMPP_RETURN_OK;
+
+ raw_xml_->AddElement(new XmlElement(QN_ROSTER_GROUP));
+ raw_xml_->AddText(group, 1);
+ ++group_count_;
+
+ return XMPP_RETURN_OK;
+}
+
+XmppReturnStatus
+XmppRosterContactImpl::RemoveGroup(const std::string& group) {
+ if (group == STR_EMPTY)
+ return XMPP_RETURN_BADARGUMENT;
+
+ if (!raw_xml_)
+ return XMPP_RETURN_OK;
+
+ XmlChild * child_before;
+ if (FindGroup(group, NULL, &child_before)) {
+ raw_xml_->RemoveChildAfter(child_before);
+ ResetGroupCache();
+ }
+ return XMPP_RETURN_OK;
+}
+
+bool
+XmppRosterContactImpl::FindGroup(const std::string& group,
+ XmlElement** element,
+ XmlChild** child_before) {
+ XmlChild * prev_child = NULL;
+ XmlChild * next_child;
+ XmlChild * child;
+ for (child = raw_xml_->FirstChild(); child; child = next_child) {
+ next_child = child->NextChild();
+ if (!child->IsText() &&
+ child->AsElement()->Name() == QN_ROSTER_GROUP &&
+ child->AsElement()->BodyText() == group) {
+ if (element)
+ *element = child->AsElement();
+ if (child_before)
+ *child_before = prev_child;
+ return true;
+ }
+ prev_child = child;
+ }
+
+ return false;
+}
+
+const XmlElement*
+XmppRosterContactImpl::raw_xml() const {
+ if (!raw_xml_)
+ const_cast<XmppRosterContactImpl*>(this)->CreateRawXmlSkeleton();
+ return raw_xml_.get();
+}
+
+XmppReturnStatus
+XmppRosterContactImpl::set_raw_xml(const XmlElement* xml) {
+ if (!xml ||
+ xml->Name() != QN_ROSTER_ITEM ||
+ xml->HasAttr(QN_SUBSCRIPTION) ||
+ xml->HasAttr(QN_ASK))
+ return XMPP_RETURN_BADARGUMENT;
+
+ ResetGroupCache();
+
+ raw_xml_.reset(new XmlElement(*xml));
+
+ return XMPP_RETURN_OK;
+}
+
+void
+XmppRosterContactImpl::CreateRawXmlSkeleton() {
+ raw_xml_.reset(new XmlElement(QN_ROSTER_ITEM));
+}
+
+// XmppRosterModuleImpl --------------------------------------------------------
+XmppRosterModule *
+XmppRosterModule::Create() {
+ return new XmppRosterModuleImpl();
+}
+
+XmppRosterModuleImpl::XmppRosterModuleImpl() :
+ roster_handler_(NULL),
+ incoming_presence_map_(new JidPresenceVectorMap()),
+ incoming_presence_vector_(new PresenceVector()),
+ contacts_(new ContactVector()) {
+
+}
+
+XmppRosterModuleImpl::~XmppRosterModuleImpl() {
+ DeleteIncomingPresence();
+ DeleteContacts();
+}
+
+XmppReturnStatus
+XmppRosterModuleImpl::set_roster_handler(XmppRosterHandler * handler) {
+ roster_handler_ = handler;
+ return XMPP_RETURN_OK;
+}
+
+XmppRosterHandler*
+XmppRosterModuleImpl::roster_handler() {
+ return roster_handler_;
+}
+
+XmppPresence*
+XmppRosterModuleImpl::outgoing_presence() {
+ return &outgoing_presence_;
+}
+
+XmppReturnStatus
+XmppRosterModuleImpl::BroadcastPresence() {
+ // Scrub the outgoing presence
+ const XmlElement* element = outgoing_presence_.raw_xml();
+
+ ASSERT(!element->HasAttr(QN_TO) &&
+ !element->HasAttr(QN_FROM) &&
+ (element->Attr(QN_TYPE) == STR_EMPTY ||
+ element->Attr(QN_TYPE) == "unavailable"));
+
+ if (!engine())
+ return XMPP_RETURN_BADSTATE;
+
+ return engine()->SendStanza(element);
+}
+
+XmppReturnStatus
+XmppRosterModuleImpl::SendDirectedPresence(const XmppPresence* presence,
+ const Jid& to_jid) {
+ if (!presence)
+ return XMPP_RETURN_BADARGUMENT;
+
+ if (!engine())
+ return XMPP_RETURN_BADSTATE;
+
+ XmlElement element(*(presence->raw_xml()));
+
+ if (element.Name() != QN_PRESENCE ||
+ element.HasAttr(QN_TO) ||
+ element.HasAttr(QN_FROM))
+ return XMPP_RETURN_BADARGUMENT;
+
+ if (element.HasAttr(QN_TYPE)) {
+ if (element.Attr(QN_TYPE) != STR_EMPTY &&
+ element.Attr(QN_TYPE) != "unavailable") {
+ return XMPP_RETURN_BADARGUMENT;
+ }
+ }
+
+ element.SetAttr(QN_TO, to_jid.Str());
+
+ return engine()->SendStanza(&element);
+}
+
+size_t
+XmppRosterModuleImpl::GetIncomingPresenceCount() {
+ return incoming_presence_vector_->size();
+}
+
+const XmppPresence*
+XmppRosterModuleImpl::GetIncomingPresence(size_t index) {
+ if (index >= incoming_presence_vector_->size())
+ return NULL;
+ return (*incoming_presence_vector_)[index];
+}
+
+size_t
+XmppRosterModuleImpl::GetIncomingPresenceForJidCount(const Jid& jid)
+{
+ // find the vector in the map
+ JidPresenceVectorMap::iterator pos;
+ pos = incoming_presence_map_->find(jid);
+ if (pos == incoming_presence_map_->end())
+ return 0;
+
+ ASSERT(pos->second != NULL);
+
+ return pos->second->size();
+}
+
+const XmppPresence*
+XmppRosterModuleImpl::GetIncomingPresenceForJid(const Jid& jid,
+ size_t index) {
+ JidPresenceVectorMap::iterator pos;
+ pos = incoming_presence_map_->find(jid);
+ if (pos == incoming_presence_map_->end())
+ return NULL;
+
+ ASSERT(pos->second != NULL);
+
+ if (index >= pos->second->size())
+ return NULL;
+
+ return (*pos->second)[index];
+}
+
+XmppReturnStatus
+XmppRosterModuleImpl::RequestRosterUpdate() {
+ if (!engine())
+ return XMPP_RETURN_BADSTATE;
+
+ XmlElement roster_get(QN_IQ);
+ roster_get.AddAttr(QN_TYPE, "get");
+ roster_get.AddAttr(QN_ID, engine()->NextId());
+ roster_get.AddElement(new XmlElement(QN_ROSTER_QUERY, true));
+ return engine()->SendIq(&roster_get, this, NULL);
+}
+
+size_t
+XmppRosterModuleImpl::GetRosterContactCount() {
+ return contacts_->size();
+}
+
+const XmppRosterContact*
+XmppRosterModuleImpl::GetRosterContact(size_t index) {
+ if (index >= contacts_->size())
+ return NULL;
+ return (*contacts_)[index];
+}
+
+class RosterPredicate {
+public:
+ explicit RosterPredicate(const Jid& jid) : jid_(jid) {
+ }
+
+ bool operator() (XmppRosterContactImpl *& contact) {
+ return contact->jid() == jid_;
+ }
+
+private:
+ Jid jid_;
+};
+
+const XmppRosterContact*
+XmppRosterModuleImpl::FindRosterContact(const Jid& jid) {
+ ContactVector::iterator pos;
+
+ pos = std::find_if(contacts_->begin(),
+ contacts_->end(),
+ RosterPredicate(jid));
+ if (pos == contacts_->end())
+ return NULL;
+
+ return *pos;
+}
+
+XmppReturnStatus
+XmppRosterModuleImpl::RequestRosterChange(
+ const XmppRosterContact* contact) {
+ if (!contact)
+ return XMPP_RETURN_BADARGUMENT;
+
+ Jid jid = contact->jid();
+
+ if (!jid.IsValid())
+ return XMPP_RETURN_BADARGUMENT;
+
+ if (!engine())
+ return XMPP_RETURN_BADSTATE;
+
+ const XmlElement* contact_xml = contact->raw_xml();
+ if (contact_xml->Name() != QN_ROSTER_ITEM ||
+ contact_xml->HasAttr(QN_SUBSCRIPTION) ||
+ contact_xml->HasAttr(QN_ASK))
+ return XMPP_RETURN_BADARGUMENT;
+
+ XmlElement roster_add(QN_IQ);
+ roster_add.AddAttr(QN_TYPE, "set");
+ roster_add.AddAttr(QN_ID, engine()->NextId());
+ roster_add.AddElement(new XmlElement(QN_ROSTER_QUERY, true));
+ roster_add.AddElement(new XmlElement(*contact_xml), 1);
+
+ return engine()->SendIq(&roster_add, this, NULL);
+}
+
+XmppReturnStatus
+XmppRosterModuleImpl::RequestRosterRemove(const Jid& jid) {
+ if (!jid.IsValid())
+ return XMPP_RETURN_BADARGUMENT;
+
+ if (!engine())
+ return XMPP_RETURN_BADSTATE;
+
+ XmlElement roster_add(QN_IQ);
+ roster_add.AddAttr(QN_TYPE, "set");
+ roster_add.AddAttr(QN_ID, engine()->NextId());
+ roster_add.AddElement(new XmlElement(QN_ROSTER_QUERY, true));
+ roster_add.AddAttr(QN_JID, jid.Str(), 1);
+ roster_add.AddAttr(QN_SUBSCRIPTION, "remove", 1);
+
+ return engine()->SendIq(&roster_add, this, NULL);
+}
+
+XmppReturnStatus
+XmppRosterModuleImpl::RequestSubscription(const Jid& jid) {
+ return SendSubscriptionRequest(jid, "subscribe");
+}
+
+XmppReturnStatus
+XmppRosterModuleImpl::CancelSubscription(const Jid& jid) {
+ return SendSubscriptionRequest(jid, "unsubscribe");
+}
+
+XmppReturnStatus
+XmppRosterModuleImpl::ApproveSubscriber(const Jid& jid) {
+ return SendSubscriptionRequest(jid, "subscribed");
+}
+
+XmppReturnStatus
+XmppRosterModuleImpl::CancelSubscriber(const Jid& jid) {
+ return SendSubscriptionRequest(jid, "unsubscribed");
+}
+
+void
+XmppRosterModuleImpl::IqResponse(XmppIqCookie, const XmlElement * stanza) {
+ // The only real Iq response that we expect to recieve are initial roster
+ // population
+ if (stanza->Attr(QN_TYPE) == "error")
+ {
+ if (roster_handler_)
+ roster_handler_->RosterError(this, stanza);
+
+ return;
+ }
+
+ ASSERT(stanza->Attr(QN_TYPE) == "result");
+
+ InternalRosterItems(stanza);
+}
+
+bool
+XmppRosterModuleImpl::HandleStanza(const XmlElement * stanza)
+{
+ ASSERT(engine() != NULL);
+
+ // There are two types of stanzas that we care about: presence and roster push
+ // Iqs
+ if (stanza->Name() == QN_PRESENCE) {
+ const std::string& jid_string = stanza->Attr(QN_FROM);
+ Jid jid(jid_string);
+
+ if (!jid.IsValid())
+ return false; // if the Jid isn't valid, don't process
+
+ const std::string& type = stanza->Attr(QN_TYPE);
+ XmppSubscriptionRequestType request_type;
+ if (StringToSubscriptionRequestType(type, &request_type))
+ InternalSubscriptionRequest(jid, stanza, request_type);
+ else if (type == "unavailable" || type == STR_EMPTY)
+ InternalIncomingPresence(jid, stanza);
+ else if (type == "error")
+ InternalIncomingPresenceError(jid, stanza);
+ else
+ return false;
+
+ return true;
+ } else if (stanza->Name() == QN_IQ) {
+ const XmlElement * roster_query = stanza->FirstNamed(QN_ROSTER_QUERY);
+ if (!roster_query || stanza->Attr(QN_TYPE) != "set")
+ return false;
+
+ InternalRosterItems(stanza);
+
+ // respond to the IQ
+ XmlElement result(QN_IQ);
+ result.AddAttr(QN_TYPE, "result");
+ result.AddAttr(QN_TO, stanza->Attr(QN_FROM));
+ result.AddAttr(QN_ID, stanza->Attr(QN_ID));
+
+ engine()->SendStanza(&result);
+ return true;
+ }
+
+ return false;
+}
+
+void
+XmppRosterModuleImpl::DeleteIncomingPresence() {
+ // Clear out the vector of all presence notifications
+ {
+ PresenceVector::iterator pos;
+ for (pos = incoming_presence_vector_->begin();
+ pos < incoming_presence_vector_->end();
+ ++pos) {
+ XmppPresenceImpl * presence = *pos;
+ *pos = NULL;
+ delete presence;
+ }
+ incoming_presence_vector_->clear();
+ }
+
+ // Clear out all of the small presence vectors per Jid
+ {
+ JidPresenceVectorMap::iterator pos;
+ for (pos = incoming_presence_map_->begin();
+ pos != incoming_presence_map_->end();
+ ++pos) {
+ PresenceVector* presence_vector = pos->second;
+ pos->second = NULL;
+ delete presence_vector;
+ }
+ incoming_presence_map_->clear();
+ }
+}
+
+void
+XmppRosterModuleImpl::DeleteContacts() {
+ ContactVector::iterator pos;
+ for (pos = contacts_->begin();
+ pos < contacts_->end();
+ ++pos) {
+ XmppRosterContact* contact = *pos;
+ *pos = NULL;
+ delete contact;
+ }
+ contacts_->clear();
+}
+
+XmppReturnStatus
+XmppRosterModuleImpl::SendSubscriptionRequest(const Jid& jid,
+ const std::string& type) {
+ if (!jid.IsValid())
+ return XMPP_RETURN_BADARGUMENT;
+
+ if (!engine())
+ return XMPP_RETURN_BADSTATE;
+
+ XmlElement presence_request(QN_PRESENCE);
+ presence_request.AddAttr(QN_TO, jid.Str());
+ presence_request.AddAttr(QN_TYPE, type);
+
+ return engine()->SendStanza(&presence_request);
+}
+
+
+void
+XmppRosterModuleImpl::InternalSubscriptionRequest(const Jid& jid,
+ const XmlElement* stanza,
+ XmppSubscriptionRequestType
+ request_type) {
+ if (roster_handler_)
+ roster_handler_->SubscriptionRequest(this, jid, request_type, stanza);
+}
+
+class PresencePredicate {
+public:
+ explicit PresencePredicate(const Jid& jid) : jid_(jid) {
+ }
+
+ bool operator() (XmppPresenceImpl *& contact) {
+ return contact->jid() == jid_;
+ }
+
+private:
+ Jid jid_;
+};
+
+void
+XmppRosterModuleImpl::InternalIncomingPresence(const Jid& jid,
+ const XmlElement* stanza) {
+ bool added = false;
+ Jid bare_jid = jid.BareJid();
+
+ // First add the presence to the map
+ JidPresenceVectorMap::iterator pos;
+ pos = incoming_presence_map_->find(jid.BareJid());
+ if (pos == incoming_presence_map_->end()) {
+ // Insert a new entry into the map. Get the position of this new entry
+ pos = (incoming_presence_map_->insert(
+ std::make_pair(bare_jid, new PresenceVector()))).first;
+ }
+
+ PresenceVector * presence_vector = pos->second;
+ ASSERT(presence_vector != NULL);
+
+ // Try to find this jid in the bare jid bucket
+ PresenceVector::iterator presence_pos;
+ XmppPresenceImpl* presence;
+ presence_pos = std::find_if(presence_vector->begin(),
+ presence_vector->end(),
+ PresencePredicate(jid));
+
+ // Update/add it to the bucket
+ if (presence_pos == presence_vector->end()) {
+ presence = new XmppPresenceImpl();
+ if (XMPP_RETURN_OK == presence->set_raw_xml(stanza)) {
+ added = true;
+ presence_vector->push_back(presence);
+ } else {
+ delete presence;
+ presence = NULL;
+ }
+ } else {
+ presence = *presence_pos;
+ presence->set_raw_xml(stanza);
+ }
+
+ // now add to the comprehensive vector
+ if (added)
+ incoming_presence_vector_->push_back(presence);
+
+ // Call back to the user with the changed presence information
+ if (roster_handler_)
+ roster_handler_->IncomingPresenceChanged(this, presence);
+}
+
+
+void
+XmppRosterModuleImpl::InternalIncomingPresenceError(const Jid& jid,
+ const XmlElement* stanza) {
+ if (roster_handler_)
+ roster_handler_->SubscriptionError(this, jid, stanza);
+}
+
+void
+XmppRosterModuleImpl::InternalRosterItems(const XmlElement* stanza) {
+ const XmlElement* result_data = stanza->FirstNamed(QN_ROSTER_QUERY);
+ if (!result_data)
+ return; // unknown stuff in result!
+
+ bool all_new = contacts_->empty();
+
+ for (const XmlElement* roster_item = result_data->FirstNamed(QN_ROSTER_ITEM);
+ roster_item;
+ roster_item = roster_item->NextNamed(QN_ROSTER_ITEM))
+ {
+ const std::string& jid_string = roster_item->Attr(QN_JID);
+ Jid jid(jid_string);
+ if (!jid.IsValid())
+ continue;
+
+ // This algorithm is N^2 on the number of incoming contacts after the
+ // initial load. There is no way to do this faster without allowing
+ // duplicates, introducing more data structures or write a custom data
+ // structure. We'll see if this becomes a perf problem and fix it if it
+ // does.
+ ContactVector::iterator pos = contacts_->end();
+
+ if (!all_new) {
+ pos = std::find_if(contacts_->begin(),
+ contacts_->end(),
+ RosterPredicate(jid));
+ }
+
+ if (pos != contacts_->end()) { // Update/remove a current contact
+ if (roster_item->Attr(QN_SUBSCRIPTION) == "remove") {
+ XmppRosterContact* contact = *pos;
+ contacts_->erase(pos);
+ if (roster_handler_)
+ roster_handler_->ContactRemoved(this, contact,
+ std::distance(contacts_->begin(), pos));
+ delete contact;
+ } else {
+ XmppRosterContact* old_contact = *pos;
+ *pos = new XmppRosterContactImpl();
+ (*pos)->SetXmlFromWire(roster_item);
+ if (roster_handler_)
+ roster_handler_->ContactChanged(this, old_contact,
+ std::distance(contacts_->begin(), pos));
+ delete old_contact;
+ }
+ } else { // Add a new contact
+ XmppRosterContactImpl* contact = new XmppRosterContactImpl();
+ contact->SetXmlFromWire(roster_item);
+ contacts_->push_back(contact);
+ if (roster_handler_ && !all_new)
+ roster_handler_->ContactsAdded(this, contacts_->size() - 1, 1);
+ }
+ }
+
+ // Send a consolidated update if all contacts are new
+ if (roster_handler_ && all_new)
+ roster_handler_->ContactsAdded(this, 0, contacts_->size());
+}
+
+}
« no previous file with comments | « webrtc/libjingle/xmpp/rostermoduleimpl.h ('k') | webrtc/libjingle/xmpp/saslcookiemechanism.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698