3 * Copyright 2004--2005, Google Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
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.
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.
34 #include "talk/base/common.h"
35 #include "talk/base/stringencode.h"
36 #include "talk/xmpp/constants.h"
37 #include "talk/xmpp/rostermoduleimpl.h"
41 // enum prase and persist helpers ----------------------------------------------
43 StringToPresenceShow(const std::string& input, XmppPresenceShow* show) {
44 // If this becomes a perf issue we can use a hash or a map here
45 if (STR_SHOW_AWAY == input)
46 *show = XMPP_PRESENCE_AWAY;
47 else if (STR_SHOW_DND == input)
48 *show = XMPP_PRESENCE_DND;
49 else if (STR_SHOW_XA == input)
50 *show = XMPP_PRESENCE_XA;
51 else if (STR_SHOW_CHAT == input)
52 *show = XMPP_PRESENCE_CHAT;
53 else if (STR_EMPTY == input)
54 *show = XMPP_PRESENCE_DEFAULT;
62 PresenceShowToString(XmppPresenceShow show, const char** output) {
64 case XMPP_PRESENCE_AWAY:
65 *output = STR_SHOW_AWAY;
67 case XMPP_PRESENCE_CHAT:
68 *output = STR_SHOW_CHAT;
70 case XMPP_PRESENCE_XA:
71 *output = STR_SHOW_XA;
73 case XMPP_PRESENCE_DND:
74 *output = STR_SHOW_DND;
76 case XMPP_PRESENCE_DEFAULT:
86 StringToSubscriptionState(const std::string& subscription,
87 const std::string& ask,
88 XmppSubscriptionState* state)
90 if (ask == "subscribe")
92 if (subscription == "none") {
93 *state = XMPP_SUBSCRIPTION_NONE_ASKED;
96 if (subscription == "from") {
97 *state = XMPP_SUBSCRIPTION_FROM_ASKED;
100 } else if (ask == STR_EMPTY)
102 if (subscription == "none") {
103 *state = XMPP_SUBSCRIPTION_NONE;
106 if (subscription == "from") {
107 *state = XMPP_SUBSCRIPTION_FROM;
110 if (subscription == "to") {
111 *state = XMPP_SUBSCRIPTION_TO;
114 if (subscription == "both") {
115 *state = XMPP_SUBSCRIPTION_BOTH;
124 StringToSubscriptionRequestType(const std::string& string,
125 XmppSubscriptionRequestType* type)
127 if (string == "subscribe")
128 *type = XMPP_REQUEST_SUBSCRIBE;
129 else if (string == "unsubscribe")
130 *type = XMPP_REQUEST_UNSUBSCRIBE;
131 else if (string == "subscribed")
132 *type = XMPP_REQUEST_SUBSCRIBED;
133 else if (string == "unsubscribed")
134 *type = XMPP_REQUEST_UNSUBSCRIBED;
140 // XmppPresenceImpl class ------------------------------------------------------
142 XmppPresence::Create() {
143 return new XmppPresenceImpl();
146 XmppPresenceImpl::XmppPresenceImpl() {
150 XmppPresenceImpl::jid() const {
154 return Jid(raw_xml_->Attr(QN_FROM));
157 XmppPresenceAvailable
158 XmppPresenceImpl::available() const {
160 return XMPP_PRESENCE_UNAVAILABLE;
162 if (raw_xml_->Attr(QN_TYPE) == "unavailable")
163 return XMPP_PRESENCE_UNAVAILABLE;
164 else if (raw_xml_->Attr(QN_TYPE) == "error")
165 return XMPP_PRESENCE_ERROR;
167 return XMPP_PRESENCE_AVAILABLE;
171 XmppPresenceImpl::set_available(XmppPresenceAvailable available) {
173 CreateRawXmlSkeleton();
175 if (available == XMPP_PRESENCE_AVAILABLE)
176 raw_xml_->ClearAttr(QN_TYPE);
177 else if (available == XMPP_PRESENCE_UNAVAILABLE)
178 raw_xml_->SetAttr(QN_TYPE, "unavailable");
179 else if (available == XMPP_PRESENCE_ERROR)
180 raw_xml_->SetAttr(QN_TYPE, "error");
181 return XMPP_RETURN_OK;
185 XmppPresenceImpl::presence_show() const {
187 return XMPP_PRESENCE_DEFAULT;
189 XmppPresenceShow show = XMPP_PRESENCE_DEFAULT;
190 StringToPresenceShow(raw_xml_->TextNamed(QN_SHOW), &show);
195 XmppPresenceImpl::set_presence_show(XmppPresenceShow show) {
197 CreateRawXmlSkeleton();
199 const char* show_string;
201 if(!PresenceShowToString(show, &show_string))
202 return XMPP_RETURN_BADARGUMENT;
204 raw_xml_->ClearNamedChildren(QN_SHOW);
206 if (show!=XMPP_PRESENCE_DEFAULT) {
207 raw_xml_->AddElement(new XmlElement(QN_SHOW));
208 raw_xml_->AddText(show_string, 1);
211 return XMPP_RETURN_OK;
215 XmppPresenceImpl::priority() const {
219 int raw_priority = 0;
220 if (!talk_base::FromString(raw_xml_->TextNamed(QN_PRIORITY), &raw_priority))
222 if (raw_priority < -128)
224 if (raw_priority > 127)
231 XmppPresenceImpl::set_priority(int priority) {
233 CreateRawXmlSkeleton();
235 if (priority < -128 || priority > 127)
236 return XMPP_RETURN_BADARGUMENT;
238 raw_xml_->ClearNamedChildren(QN_PRIORITY);
240 std::string priority_string;
241 if (talk_base::ToString(priority, &priority_string)) {
242 raw_xml_->AddElement(new XmlElement(QN_PRIORITY));
243 raw_xml_->AddText(priority_string, 1);
247 return XMPP_RETURN_OK;
251 XmppPresenceImpl::status() const {
255 XmlElement* status_element;
258 // Search for a status element with no xml:lang attribute on it. if we can't
259 // find that then just return the first status element in the stanza.
260 for (status_element = element = raw_xml_->FirstNamed(QN_STATUS);
262 element = element->NextNamed(QN_STATUS)) {
263 if (!element->HasAttr(QN_XML_LANG)) {
264 status_element = element;
269 if (status_element) {
270 return status_element->BodyText();
277 XmppPresenceImpl::set_status(const std::string& status) {
279 CreateRawXmlSkeleton();
281 raw_xml_->ClearNamedChildren(QN_STATUS);
283 if (status != STR_EMPTY) {
284 raw_xml_->AddElement(new XmlElement(QN_STATUS));
285 raw_xml_->AddText(status, 1);
288 return XMPP_RETURN_OK;
291 XmppPresenceConnectionStatus
292 XmppPresenceImpl::connection_status() const {
294 return XMPP_CONNECTION_STATUS_UNKNOWN;
296 XmlElement* con = raw_xml_->FirstNamed(QN_GOOGLE_PSTN_CONFERENCE_STATUS);
298 std::string status = con->Attr(QN_ATTR_STATUS);
299 if (status == STR_PSTN_CONFERENCE_STATUS_CONNECTING)
300 return XMPP_CONNECTION_STATUS_CONNECTING;
301 else if (status == STR_PSTN_CONFERENCE_STATUS_CONNECTED)
302 return XMPP_CONNECTION_STATUS_CONNECTED;
303 else if (status == STR_PSTN_CONFERENCE_STATUS_JOINING)
304 return XMPP_CONNECTION_STATUS_JOINING;
305 else if (status == STR_PSTN_CONFERENCE_STATUS_HANGUP)
306 return XMPP_CONNECTION_STATUS_HANGUP;
309 return XMPP_CONNECTION_STATUS_CONNECTED;
313 XmppPresenceImpl::google_user_id() const {
315 return std::string();
317 XmlElement* muc_user_x = raw_xml_->FirstNamed(QN_MUC_USER_X);
319 XmlElement* muc_user_item = muc_user_x->FirstNamed(QN_MUC_USER_ITEM);
321 return muc_user_item->Attr(QN_GOOGLE_USER_ID);
325 return std::string();
329 XmppPresenceImpl::nickname() const {
331 return std::string();
333 XmlElement* nickname = raw_xml_->FirstNamed(QN_NICKNAME);
335 return nickname->BodyText();
338 return std::string();
342 XmppPresenceImpl::raw_xml() const {
344 const_cast<XmppPresenceImpl*>(this)->CreateRawXmlSkeleton();
345 return raw_xml_.get();
349 XmppPresenceImpl::set_raw_xml(const XmlElement * xml) {
351 xml->Name() != QN_PRESENCE)
352 return XMPP_RETURN_BADARGUMENT;
354 raw_xml_.reset(new XmlElement(*xml));
355 return XMPP_RETURN_OK;
359 XmppPresenceImpl::CreateRawXmlSkeleton() {
360 raw_xml_.reset(new XmlElement(QN_PRESENCE));
363 // XmppRosterContactImpl -------------------------------------------------------
365 XmppRosterContact::Create() {
366 return new XmppRosterContactImpl();
369 XmppRosterContactImpl::XmppRosterContactImpl() {
374 XmppRosterContactImpl::SetXmlFromWire(const XmlElement* xml) {
377 raw_xml_.reset(new XmlElement(*xml));
379 raw_xml_.reset(NULL);
383 XmppRosterContactImpl::ResetGroupCache() {
385 group_index_returned_ = -1;
386 group_returned_ = NULL;
390 XmppRosterContactImpl::jid() const {
391 return Jid(raw_xml_->Attr(QN_JID));
395 XmppRosterContactImpl::set_jid(const Jid& jid)
398 CreateRawXmlSkeleton();
401 return XMPP_RETURN_BADARGUMENT;
403 raw_xml_->SetAttr(QN_JID, jid.Str());
405 return XMPP_RETURN_OK;
409 XmppRosterContactImpl::name() const {
410 return raw_xml_->Attr(QN_NAME);
414 XmppRosterContactImpl::set_name(const std::string& name) {
416 CreateRawXmlSkeleton();
418 if (name == STR_EMPTY)
419 raw_xml_->ClearAttr(QN_NAME);
421 raw_xml_->SetAttr(QN_NAME, name);
423 return XMPP_RETURN_OK;
426 XmppSubscriptionState
427 XmppRosterContactImpl::subscription_state() const {
429 return XMPP_SUBSCRIPTION_NONE;
431 XmppSubscriptionState state = XMPP_SUBSCRIPTION_NONE;
433 if (StringToSubscriptionState(raw_xml_->Attr(QN_SUBSCRIPTION),
434 raw_xml_->Attr(QN_ASK),
438 return XMPP_SUBSCRIPTION_NONE;
442 XmppRosterContactImpl::GetGroupCount() const {
446 if (-1 == group_count_) {
447 XmlElement *group_element = raw_xml_->FirstNamed(QN_ROSTER_GROUP);
449 while(group_element) {
451 group_element = group_element->NextNamed(QN_ROSTER_GROUP);
454 ASSERT(group_count > 0); // protect the cast
455 XmppRosterContactImpl * me = const_cast<XmppRosterContactImpl*>(this);
456 me->group_count_ = group_count;
463 XmppRosterContactImpl::GetGroup(size_t index) const {
464 if (index >= GetGroupCount())
467 // We cache the last group index and element that we returned. This way
468 // going through the groups in order is order n and not n^2. This could be
469 // enhanced if necessary by starting at the cached value if the index asked
470 // is after the cached one.
471 if (group_index_returned_ >= 0 &&
472 index == static_cast<size_t>(group_index_returned_) + 1)
474 XmppRosterContactImpl * me = const_cast<XmppRosterContactImpl*>(this);
475 me->group_returned_ = group_returned_->NextNamed(QN_ROSTER_GROUP);
476 ASSERT(group_returned_ != NULL);
477 me->group_index_returned_++;
478 } else if (group_index_returned_ < 0 ||
479 static_cast<size_t>(group_index_returned_) != index) {
480 XmlElement * group_element = raw_xml_->FirstNamed(QN_ROSTER_GROUP);
481 size_t group_index = 0;
482 while(group_index < index) {
483 ASSERT(group_element != NULL);
485 group_element = group_element->NextNamed(QN_ROSTER_GROUP);
488 XmppRosterContactImpl * me = const_cast<XmppRosterContactImpl*>(this);
489 me->group_index_returned_ = static_cast<int>(group_index);
490 me->group_returned_ = group_element;
493 return group_returned_->BodyText();
497 XmppRosterContactImpl::AddGroup(const std::string& group) {
498 if (group == STR_EMPTY)
499 return XMPP_RETURN_BADARGUMENT;
502 CreateRawXmlSkeleton();
504 if (FindGroup(group, NULL, NULL))
505 return XMPP_RETURN_OK;
507 raw_xml_->AddElement(new XmlElement(QN_ROSTER_GROUP));
508 raw_xml_->AddText(group, 1);
511 return XMPP_RETURN_OK;
515 XmppRosterContactImpl::RemoveGroup(const std::string& group) {
516 if (group == STR_EMPTY)
517 return XMPP_RETURN_BADARGUMENT;
520 return XMPP_RETURN_OK;
522 XmlChild * child_before;
523 if (FindGroup(group, NULL, &child_before)) {
524 raw_xml_->RemoveChildAfter(child_before);
527 return XMPP_RETURN_OK;
531 XmppRosterContactImpl::FindGroup(const std::string& group,
532 XmlElement** element,
533 XmlChild** child_before) {
534 XmlChild * prev_child = NULL;
535 XmlChild * next_child;
537 for (child = raw_xml_->FirstChild(); child; child = next_child) {
538 next_child = child->NextChild();
539 if (!child->IsText() &&
540 child->AsElement()->Name() == QN_ROSTER_GROUP &&
541 child->AsElement()->BodyText() == group) {
543 *element = child->AsElement();
545 *child_before = prev_child;
555 XmppRosterContactImpl::raw_xml() const {
557 const_cast<XmppRosterContactImpl*>(this)->CreateRawXmlSkeleton();
558 return raw_xml_.get();
562 XmppRosterContactImpl::set_raw_xml(const XmlElement* xml) {
564 xml->Name() != QN_ROSTER_ITEM ||
565 xml->HasAttr(QN_SUBSCRIPTION) ||
566 xml->HasAttr(QN_ASK))
567 return XMPP_RETURN_BADARGUMENT;
571 raw_xml_.reset(new XmlElement(*xml));
573 return XMPP_RETURN_OK;
577 XmppRosterContactImpl::CreateRawXmlSkeleton() {
578 raw_xml_.reset(new XmlElement(QN_ROSTER_ITEM));
581 // XmppRosterModuleImpl --------------------------------------------------------
583 XmppRosterModule::Create() {
584 return new XmppRosterModuleImpl();
587 XmppRosterModuleImpl::XmppRosterModuleImpl() :
588 roster_handler_(NULL),
589 incoming_presence_map_(new JidPresenceVectorMap()),
590 incoming_presence_vector_(new PresenceVector()),
591 contacts_(new ContactVector()) {
595 XmppRosterModuleImpl::~XmppRosterModuleImpl() {
596 DeleteIncomingPresence();
601 XmppRosterModuleImpl::set_roster_handler(XmppRosterHandler * handler) {
602 roster_handler_ = handler;
603 return XMPP_RETURN_OK;
607 XmppRosterModuleImpl::roster_handler() {
608 return roster_handler_;
612 XmppRosterModuleImpl::outgoing_presence() {
613 return &outgoing_presence_;
617 XmppRosterModuleImpl::BroadcastPresence() {
618 // Scrub the outgoing presence
619 const XmlElement* element = outgoing_presence_.raw_xml();
621 ASSERT(!element->HasAttr(QN_TO) &&
622 !element->HasAttr(QN_FROM) &&
623 (element->Attr(QN_TYPE) == STR_EMPTY ||
624 element->Attr(QN_TYPE) == "unavailable"));
627 return XMPP_RETURN_BADSTATE;
629 return engine()->SendStanza(element);
633 XmppRosterModuleImpl::SendDirectedPresence(const XmppPresence* presence,
636 return XMPP_RETURN_BADARGUMENT;
639 return XMPP_RETURN_BADSTATE;
641 XmlElement element(*(presence->raw_xml()));
643 if (element.Name() != QN_PRESENCE ||
644 element.HasAttr(QN_TO) ||
645 element.HasAttr(QN_FROM))
646 return XMPP_RETURN_BADARGUMENT;
648 if (element.HasAttr(QN_TYPE)) {
649 if (element.Attr(QN_TYPE) != STR_EMPTY &&
650 element.Attr(QN_TYPE) != "unavailable") {
651 return XMPP_RETURN_BADARGUMENT;
655 element.SetAttr(QN_TO, to_jid.Str());
657 return engine()->SendStanza(&element);
661 XmppRosterModuleImpl::GetIncomingPresenceCount() {
662 return incoming_presence_vector_->size();
666 XmppRosterModuleImpl::GetIncomingPresence(size_t index) {
667 if (index >= incoming_presence_vector_->size())
669 return (*incoming_presence_vector_)[index];
673 XmppRosterModuleImpl::GetIncomingPresenceForJidCount(const Jid& jid)
675 // find the vector in the map
676 JidPresenceVectorMap::iterator pos;
677 pos = incoming_presence_map_->find(jid);
678 if (pos == incoming_presence_map_->end())
681 ASSERT(pos->second != NULL);
683 return pos->second->size();
687 XmppRosterModuleImpl::GetIncomingPresenceForJid(const Jid& jid,
689 JidPresenceVectorMap::iterator pos;
690 pos = incoming_presence_map_->find(jid);
691 if (pos == incoming_presence_map_->end())
694 ASSERT(pos->second != NULL);
696 if (index >= pos->second->size())
699 return (*pos->second)[index];
703 XmppRosterModuleImpl::RequestRosterUpdate() {
705 return XMPP_RETURN_BADSTATE;
707 XmlElement roster_get(QN_IQ);
708 roster_get.AddAttr(QN_TYPE, "get");
709 roster_get.AddAttr(QN_ID, engine()->NextId());
710 roster_get.AddElement(new XmlElement(QN_ROSTER_QUERY, true));
711 return engine()->SendIq(&roster_get, this, NULL);
715 XmppRosterModuleImpl::GetRosterContactCount() {
716 return contacts_->size();
719 const XmppRosterContact*
720 XmppRosterModuleImpl::GetRosterContact(size_t index) {
721 if (index >= contacts_->size())
723 return (*contacts_)[index];
726 class RosterPredicate {
728 explicit RosterPredicate(const Jid& jid) : jid_(jid) {
731 bool operator() (XmppRosterContactImpl *& contact) {
732 return contact->jid() == jid_;
739 const XmppRosterContact*
740 XmppRosterModuleImpl::FindRosterContact(const Jid& jid) {
741 ContactVector::iterator pos;
743 pos = std::find_if(contacts_->begin(),
745 RosterPredicate(jid));
746 if (pos == contacts_->end())
753 XmppRosterModuleImpl::RequestRosterChange(
754 const XmppRosterContact* contact) {
756 return XMPP_RETURN_BADARGUMENT;
758 Jid jid = contact->jid();
761 return XMPP_RETURN_BADARGUMENT;
764 return XMPP_RETURN_BADSTATE;
766 const XmlElement* contact_xml = contact->raw_xml();
767 if (contact_xml->Name() != QN_ROSTER_ITEM ||
768 contact_xml->HasAttr(QN_SUBSCRIPTION) ||
769 contact_xml->HasAttr(QN_ASK))
770 return XMPP_RETURN_BADARGUMENT;
772 XmlElement roster_add(QN_IQ);
773 roster_add.AddAttr(QN_TYPE, "set");
774 roster_add.AddAttr(QN_ID, engine()->NextId());
775 roster_add.AddElement(new XmlElement(QN_ROSTER_QUERY, true));
776 roster_add.AddElement(new XmlElement(*contact_xml), 1);
778 return engine()->SendIq(&roster_add, this, NULL);
782 XmppRosterModuleImpl::RequestRosterRemove(const Jid& jid) {
784 return XMPP_RETURN_BADARGUMENT;
787 return XMPP_RETURN_BADSTATE;
789 XmlElement roster_add(QN_IQ);
790 roster_add.AddAttr(QN_TYPE, "set");
791 roster_add.AddAttr(QN_ID, engine()->NextId());
792 roster_add.AddElement(new XmlElement(QN_ROSTER_QUERY, true));
793 roster_add.AddAttr(QN_JID, jid.Str(), 1);
794 roster_add.AddAttr(QN_SUBSCRIPTION, "remove", 1);
796 return engine()->SendIq(&roster_add, this, NULL);
800 XmppRosterModuleImpl::RequestSubscription(const Jid& jid) {
801 return SendSubscriptionRequest(jid, "subscribe");
805 XmppRosterModuleImpl::CancelSubscription(const Jid& jid) {
806 return SendSubscriptionRequest(jid, "unsubscribe");
810 XmppRosterModuleImpl::ApproveSubscriber(const Jid& jid) {
811 return SendSubscriptionRequest(jid, "subscribed");
815 XmppRosterModuleImpl::CancelSubscriber(const Jid& jid) {
816 return SendSubscriptionRequest(jid, "unsubscribed");
820 XmppRosterModuleImpl::IqResponse(XmppIqCookie, const XmlElement * stanza) {
821 // The only real Iq response that we expect to recieve are initial roster
823 if (stanza->Attr(QN_TYPE) == "error")
826 roster_handler_->RosterError(this, stanza);
831 ASSERT(stanza->Attr(QN_TYPE) == "result");
833 InternalRosterItems(stanza);
837 XmppRosterModuleImpl::HandleStanza(const XmlElement * stanza)
839 ASSERT(engine() != NULL);
841 // There are two types of stanzas that we care about: presence and roster push
843 if (stanza->Name() == QN_PRESENCE) {
844 const std::string& jid_string = stanza->Attr(QN_FROM);
848 return false; // if the Jid isn't valid, don't process
850 const std::string& type = stanza->Attr(QN_TYPE);
851 XmppSubscriptionRequestType request_type;
852 if (StringToSubscriptionRequestType(type, &request_type))
853 InternalSubscriptionRequest(jid, stanza, request_type);
854 else if (type == "unavailable" || type == STR_EMPTY)
855 InternalIncomingPresence(jid, stanza);
856 else if (type == "error")
857 InternalIncomingPresenceError(jid, stanza);
862 } else if (stanza->Name() == QN_IQ) {
863 const XmlElement * roster_query = stanza->FirstNamed(QN_ROSTER_QUERY);
864 if (!roster_query || stanza->Attr(QN_TYPE) != "set")
867 InternalRosterItems(stanza);
870 XmlElement result(QN_IQ);
871 result.AddAttr(QN_TYPE, "result");
872 result.AddAttr(QN_TO, stanza->Attr(QN_FROM));
873 result.AddAttr(QN_ID, stanza->Attr(QN_ID));
875 engine()->SendStanza(&result);
883 XmppRosterModuleImpl::DeleteIncomingPresence() {
884 // Clear out the vector of all presence notifications
886 PresenceVector::iterator pos;
887 for (pos = incoming_presence_vector_->begin();
888 pos < incoming_presence_vector_->end();
890 XmppPresenceImpl * presence = *pos;
894 incoming_presence_vector_->clear();
897 // Clear out all of the small presence vectors per Jid
899 JidPresenceVectorMap::iterator pos;
900 for (pos = incoming_presence_map_->begin();
901 pos != incoming_presence_map_->end();
903 PresenceVector* presence_vector = pos->second;
905 delete presence_vector;
907 incoming_presence_map_->clear();
912 XmppRosterModuleImpl::DeleteContacts() {
913 ContactVector::iterator pos;
914 for (pos = contacts_->begin();
915 pos < contacts_->end();
917 XmppRosterContact* contact = *pos;
925 XmppRosterModuleImpl::SendSubscriptionRequest(const Jid& jid,
926 const std::string& type) {
928 return XMPP_RETURN_BADARGUMENT;
931 return XMPP_RETURN_BADSTATE;
933 XmlElement presence_request(QN_PRESENCE);
934 presence_request.AddAttr(QN_TO, jid.Str());
935 presence_request.AddAttr(QN_TYPE, type);
937 return engine()->SendStanza(&presence_request);
942 XmppRosterModuleImpl::InternalSubscriptionRequest(const Jid& jid,
943 const XmlElement* stanza,
944 XmppSubscriptionRequestType
947 roster_handler_->SubscriptionRequest(this, jid, request_type, stanza);
950 class PresencePredicate {
952 explicit PresencePredicate(const Jid& jid) : jid_(jid) {
955 bool operator() (XmppPresenceImpl *& contact) {
956 return contact->jid() == jid_;
964 XmppRosterModuleImpl::InternalIncomingPresence(const Jid& jid,
965 const XmlElement* stanza) {
967 Jid bare_jid = jid.BareJid();
969 // First add the presence to the map
970 JidPresenceVectorMap::iterator pos;
971 pos = incoming_presence_map_->find(jid.BareJid());
972 if (pos == incoming_presence_map_->end()) {
973 // Insert a new entry into the map. Get the position of this new entry
974 pos = (incoming_presence_map_->insert(
975 std::make_pair(bare_jid, new PresenceVector()))).first;
978 PresenceVector * presence_vector = pos->second;
979 ASSERT(presence_vector != NULL);
981 // Try to find this jid in the bare jid bucket
982 PresenceVector::iterator presence_pos;
983 XmppPresenceImpl* presence;
984 presence_pos = std::find_if(presence_vector->begin(),
985 presence_vector->end(),
986 PresencePredicate(jid));
988 // Update/add it to the bucket
989 if (presence_pos == presence_vector->end()) {
990 presence = new XmppPresenceImpl();
991 if (XMPP_RETURN_OK == presence->set_raw_xml(stanza)) {
993 presence_vector->push_back(presence);
999 presence = *presence_pos;
1000 presence->set_raw_xml(stanza);
1003 // now add to the comprehensive vector
1005 incoming_presence_vector_->push_back(presence);
1007 // Call back to the user with the changed presence information
1008 if (roster_handler_)
1009 roster_handler_->IncomingPresenceChanged(this, presence);
1014 XmppRosterModuleImpl::InternalIncomingPresenceError(const Jid& jid,
1015 const XmlElement* stanza) {
1016 if (roster_handler_)
1017 roster_handler_->SubscriptionError(this, jid, stanza);
1021 XmppRosterModuleImpl::InternalRosterItems(const XmlElement* stanza) {
1022 const XmlElement* result_data = stanza->FirstNamed(QN_ROSTER_QUERY);
1024 return; // unknown stuff in result!
1026 bool all_new = contacts_->empty();
1028 for (const XmlElement* roster_item = result_data->FirstNamed(QN_ROSTER_ITEM);
1030 roster_item = roster_item->NextNamed(QN_ROSTER_ITEM))
1032 const std::string& jid_string = roster_item->Attr(QN_JID);
1033 Jid jid(jid_string);
1037 // This algorithm is N^2 on the number of incoming contacts after the
1038 // initial load. There is no way to do this faster without allowing
1039 // duplicates, introducing more data structures or write a custom data
1040 // structure. We'll see if this becomes a perf problem and fix it if it
1042 ContactVector::iterator pos = contacts_->end();
1045 pos = std::find_if(contacts_->begin(),
1047 RosterPredicate(jid));
1050 if (pos != contacts_->end()) { // Update/remove a current contact
1051 if (roster_item->Attr(QN_SUBSCRIPTION) == "remove") {
1052 XmppRosterContact* contact = *pos;
1053 contacts_->erase(pos);
1054 if (roster_handler_)
1055 roster_handler_->ContactRemoved(this, contact,
1056 std::distance(contacts_->begin(), pos));
1059 XmppRosterContact* old_contact = *pos;
1060 *pos = new XmppRosterContactImpl();
1061 (*pos)->SetXmlFromWire(roster_item);
1062 if (roster_handler_)
1063 roster_handler_->ContactChanged(this, old_contact,
1064 std::distance(contacts_->begin(), pos));
1067 } else { // Add a new contact
1068 XmppRosterContactImpl* contact = new XmppRosterContactImpl();
1069 contact->SetXmlFromWire(roster_item);
1070 contacts_->push_back(contact);
1071 if (roster_handler_ && !all_new)
1072 roster_handler_->ContactsAdded(this, contacts_->size() - 1, 1);
1076 // Send a consolidated update if all contacts are new
1077 if (roster_handler_ && all_new)
1078 roster_handler_->ContactsAdded(this, 0, contacts_->size());