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

Side by Side Diff: third_party/libjingle_xmpp/xmpp/rostermoduleimpl.cc

Issue 2443903004: Add xmllite and xmpp sources to third_party/ (Closed)
Patch Set: Fix GN and sort includes Created 4 years 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2004 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <algorithm>
6 #include <iostream>
7 #include <map>
8 #include <sstream>
9 #include <string>
10 #include <vector>
11 #include "third_party/libjingle_xmpp/xmpp/constants.h"
12 #include "third_party/libjingle_xmpp/xmpp/rostermoduleimpl.h"
13 #include "webrtc/base/common.h"
14 #include "webrtc/base/stringencode.h"
15
16 namespace buzz {
17
18 // enum prase and persist helpers ----------------------------------------------
19 static bool
20 StringToPresenceShow(const std::string& input, XmppPresenceShow* show) {
21 // If this becomes a perf issue we can use a hash or a map here
22 if (STR_SHOW_AWAY == input)
23 *show = XMPP_PRESENCE_AWAY;
24 else if (STR_SHOW_DND == input)
25 *show = XMPP_PRESENCE_DND;
26 else if (STR_SHOW_XA == input)
27 *show = XMPP_PRESENCE_XA;
28 else if (STR_SHOW_CHAT == input)
29 *show = XMPP_PRESENCE_CHAT;
30 else if (STR_EMPTY == input)
31 *show = XMPP_PRESENCE_DEFAULT;
32 else
33 return false;
34
35 return true;
36 }
37
38 static bool
39 PresenceShowToString(XmppPresenceShow show, const char** output) {
40 switch(show) {
41 case XMPP_PRESENCE_AWAY:
42 *output = STR_SHOW_AWAY;
43 return true;
44 case XMPP_PRESENCE_CHAT:
45 *output = STR_SHOW_CHAT;
46 return true;
47 case XMPP_PRESENCE_XA:
48 *output = STR_SHOW_XA;
49 return true;
50 case XMPP_PRESENCE_DND:
51 *output = STR_SHOW_DND;
52 return true;
53 case XMPP_PRESENCE_DEFAULT:
54 *output = STR_EMPTY;
55 return true;
56 }
57
58 *output = STR_EMPTY;
59 return false;
60 }
61
62 static bool
63 StringToSubscriptionState(const std::string& subscription,
64 const std::string& ask,
65 XmppSubscriptionState* state)
66 {
67 if (ask == "subscribe")
68 {
69 if (subscription == "none") {
70 *state = XMPP_SUBSCRIPTION_NONE_ASKED;
71 return true;
72 }
73 if (subscription == "from") {
74 *state = XMPP_SUBSCRIPTION_FROM_ASKED;
75 return true;
76 }
77 } else if (ask == STR_EMPTY)
78 {
79 if (subscription == "none") {
80 *state = XMPP_SUBSCRIPTION_NONE;
81 return true;
82 }
83 if (subscription == "from") {
84 *state = XMPP_SUBSCRIPTION_FROM;
85 return true;
86 }
87 if (subscription == "to") {
88 *state = XMPP_SUBSCRIPTION_TO;
89 return true;
90 }
91 if (subscription == "both") {
92 *state = XMPP_SUBSCRIPTION_BOTH;
93 return true;
94 }
95 }
96
97 return false;
98 }
99
100 static bool
101 StringToSubscriptionRequestType(const std::string& string,
102 XmppSubscriptionRequestType* type)
103 {
104 if (string == "subscribe")
105 *type = XMPP_REQUEST_SUBSCRIBE;
106 else if (string == "unsubscribe")
107 *type = XMPP_REQUEST_UNSUBSCRIBE;
108 else if (string == "subscribed")
109 *type = XMPP_REQUEST_SUBSCRIBED;
110 else if (string == "unsubscribed")
111 *type = XMPP_REQUEST_UNSUBSCRIBED;
112 else
113 return false;
114 return true;
115 }
116
117 // XmppPresenceImpl class ------------------------------------------------------
118 XmppPresence*
119 XmppPresence::Create() {
120 return new XmppPresenceImpl();
121 }
122
123 XmppPresenceImpl::XmppPresenceImpl() {
124 }
125
126 const Jid
127 XmppPresenceImpl::jid() const {
128 if (!raw_xml_)
129 return Jid();
130
131 return Jid(raw_xml_->Attr(QN_FROM));
132 }
133
134 XmppPresenceAvailable
135 XmppPresenceImpl::available() const {
136 if (!raw_xml_)
137 return XMPP_PRESENCE_UNAVAILABLE;
138
139 if (raw_xml_->Attr(QN_TYPE) == "unavailable")
140 return XMPP_PRESENCE_UNAVAILABLE;
141 else if (raw_xml_->Attr(QN_TYPE) == "error")
142 return XMPP_PRESENCE_ERROR;
143 else
144 return XMPP_PRESENCE_AVAILABLE;
145 }
146
147 XmppReturnStatus
148 XmppPresenceImpl::set_available(XmppPresenceAvailable available) {
149 if (!raw_xml_)
150 CreateRawXmlSkeleton();
151
152 if (available == XMPP_PRESENCE_AVAILABLE)
153 raw_xml_->ClearAttr(QN_TYPE);
154 else if (available == XMPP_PRESENCE_UNAVAILABLE)
155 raw_xml_->SetAttr(QN_TYPE, "unavailable");
156 else if (available == XMPP_PRESENCE_ERROR)
157 raw_xml_->SetAttr(QN_TYPE, "error");
158 return XMPP_RETURN_OK;
159 }
160
161 XmppPresenceShow
162 XmppPresenceImpl::presence_show() const {
163 if (!raw_xml_)
164 return XMPP_PRESENCE_DEFAULT;
165
166 XmppPresenceShow show = XMPP_PRESENCE_DEFAULT;
167 StringToPresenceShow(raw_xml_->TextNamed(QN_SHOW), &show);
168 return show;
169 }
170
171 XmppReturnStatus
172 XmppPresenceImpl::set_presence_show(XmppPresenceShow show) {
173 if (!raw_xml_)
174 CreateRawXmlSkeleton();
175
176 const char* show_string;
177
178 if(!PresenceShowToString(show, &show_string))
179 return XMPP_RETURN_BADARGUMENT;
180
181 raw_xml_->ClearNamedChildren(QN_SHOW);
182
183 if (show!=XMPP_PRESENCE_DEFAULT) {
184 raw_xml_->AddElement(new XmlElement(QN_SHOW));
185 raw_xml_->AddText(show_string, 1);
186 }
187
188 return XMPP_RETURN_OK;
189 }
190
191 int
192 XmppPresenceImpl::priority() const {
193 if (!raw_xml_)
194 return 0;
195
196 int raw_priority = 0;
197 if (!rtc::FromString(raw_xml_->TextNamed(QN_PRIORITY), &raw_priority))
198 raw_priority = 0;
199 if (raw_priority < -128)
200 raw_priority = -128;
201 if (raw_priority > 127)
202 raw_priority = 127;
203
204 return raw_priority;
205 }
206
207 XmppReturnStatus
208 XmppPresenceImpl::set_priority(int priority) {
209 if (!raw_xml_)
210 CreateRawXmlSkeleton();
211
212 if (priority < -128 || priority > 127)
213 return XMPP_RETURN_BADARGUMENT;
214
215 raw_xml_->ClearNamedChildren(QN_PRIORITY);
216 if (0 != priority) {
217 std::string priority_string;
218 if (rtc::ToString(priority, &priority_string)) {
219 raw_xml_->AddElement(new XmlElement(QN_PRIORITY));
220 raw_xml_->AddText(priority_string, 1);
221 }
222 }
223
224 return XMPP_RETURN_OK;
225 }
226
227 const std::string
228 XmppPresenceImpl::status() const {
229 if (!raw_xml_)
230 return STR_EMPTY;
231
232 XmlElement* status_element;
233 XmlElement* element;
234
235 // Search for a status element with no xml:lang attribute on it. if we can't
236 // find that then just return the first status element in the stanza.
237 for (status_element = element = raw_xml_->FirstNamed(QN_STATUS);
238 element;
239 element = element->NextNamed(QN_STATUS)) {
240 if (!element->HasAttr(QN_XML_LANG)) {
241 status_element = element;
242 break;
243 }
244 }
245
246 if (status_element) {
247 return status_element->BodyText();
248 }
249
250 return STR_EMPTY;
251 }
252
253 XmppReturnStatus
254 XmppPresenceImpl::set_status(const std::string& status) {
255 if (!raw_xml_)
256 CreateRawXmlSkeleton();
257
258 raw_xml_->ClearNamedChildren(QN_STATUS);
259
260 if (status != STR_EMPTY) {
261 raw_xml_->AddElement(new XmlElement(QN_STATUS));
262 raw_xml_->AddText(status, 1);
263 }
264
265 return XMPP_RETURN_OK;
266 }
267
268 XmppPresenceConnectionStatus
269 XmppPresenceImpl::connection_status() const {
270 if (!raw_xml_)
271 return XMPP_CONNECTION_STATUS_UNKNOWN;
272
273 XmlElement* con = raw_xml_->FirstNamed(QN_GOOGLE_PSTN_CONFERENCE_STATUS);
274 if (con) {
275 std::string status = con->Attr(QN_ATTR_STATUS);
276 if (status == STR_PSTN_CONFERENCE_STATUS_CONNECTING)
277 return XMPP_CONNECTION_STATUS_CONNECTING;
278 else if (status == STR_PSTN_CONFERENCE_STATUS_CONNECTED)
279 return XMPP_CONNECTION_STATUS_CONNECTED;
280 else if (status == STR_PSTN_CONFERENCE_STATUS_JOINING)
281 return XMPP_CONNECTION_STATUS_JOINING;
282 else if (status == STR_PSTN_CONFERENCE_STATUS_HANGUP)
283 return XMPP_CONNECTION_STATUS_HANGUP;
284 }
285
286 return XMPP_CONNECTION_STATUS_CONNECTED;
287 }
288
289 const std::string
290 XmppPresenceImpl::google_user_id() const {
291 if (!raw_xml_)
292 return std::string();
293
294 XmlElement* muc_user_x = raw_xml_->FirstNamed(QN_MUC_USER_X);
295 if (muc_user_x) {
296 XmlElement* muc_user_item = muc_user_x->FirstNamed(QN_MUC_USER_ITEM);
297 if (muc_user_item) {
298 return muc_user_item->Attr(QN_GOOGLE_USER_ID);
299 }
300 }
301
302 return std::string();
303 }
304
305 const std::string
306 XmppPresenceImpl::nickname() const {
307 if (!raw_xml_)
308 return std::string();
309
310 XmlElement* nickname = raw_xml_->FirstNamed(QN_NICKNAME);
311 if (nickname) {
312 return nickname->BodyText();
313 }
314
315 return std::string();
316 }
317
318 const XmlElement*
319 XmppPresenceImpl::raw_xml() const {
320 if (!raw_xml_)
321 const_cast<XmppPresenceImpl*>(this)->CreateRawXmlSkeleton();
322 return raw_xml_.get();
323 }
324
325 XmppReturnStatus
326 XmppPresenceImpl::set_raw_xml(const XmlElement * xml) {
327 if (!xml ||
328 xml->Name() != QN_PRESENCE)
329 return XMPP_RETURN_BADARGUMENT;
330
331 raw_xml_.reset(new XmlElement(*xml));
332 return XMPP_RETURN_OK;
333 }
334
335 void
336 XmppPresenceImpl::CreateRawXmlSkeleton() {
337 raw_xml_.reset(new XmlElement(QN_PRESENCE));
338 }
339
340 // XmppRosterContactImpl -------------------------------------------------------
341 XmppRosterContact*
342 XmppRosterContact::Create() {
343 return new XmppRosterContactImpl();
344 }
345
346 XmppRosterContactImpl::XmppRosterContactImpl() {
347 ResetGroupCache();
348 }
349
350 void
351 XmppRosterContactImpl::SetXmlFromWire(const XmlElement* xml) {
352 ResetGroupCache();
353 if (xml)
354 raw_xml_.reset(new XmlElement(*xml));
355 else
356 raw_xml_.reset(NULL);
357 }
358
359 void
360 XmppRosterContactImpl::ResetGroupCache() {
361 group_count_ = -1;
362 group_index_returned_ = -1;
363 group_returned_ = NULL;
364 }
365
366 const Jid
367 XmppRosterContactImpl::jid() const {
368 return Jid(raw_xml_->Attr(QN_JID));
369 }
370
371 XmppReturnStatus
372 XmppRosterContactImpl::set_jid(const Jid& jid)
373 {
374 if (!raw_xml_)
375 CreateRawXmlSkeleton();
376
377 if (!jid.IsValid())
378 return XMPP_RETURN_BADARGUMENT;
379
380 raw_xml_->SetAttr(QN_JID, jid.Str());
381
382 return XMPP_RETURN_OK;
383 }
384
385 const std::string
386 XmppRosterContactImpl::name() const {
387 return raw_xml_->Attr(QN_NAME);
388 }
389
390 XmppReturnStatus
391 XmppRosterContactImpl::set_name(const std::string& name) {
392 if (!raw_xml_)
393 CreateRawXmlSkeleton();
394
395 if (name == STR_EMPTY)
396 raw_xml_->ClearAttr(QN_NAME);
397 else
398 raw_xml_->SetAttr(QN_NAME, name);
399
400 return XMPP_RETURN_OK;
401 }
402
403 XmppSubscriptionState
404 XmppRosterContactImpl::subscription_state() const {
405 if (!raw_xml_)
406 return XMPP_SUBSCRIPTION_NONE;
407
408 XmppSubscriptionState state = XMPP_SUBSCRIPTION_NONE;
409
410 if (StringToSubscriptionState(raw_xml_->Attr(QN_SUBSCRIPTION),
411 raw_xml_->Attr(QN_ASK),
412 &state))
413 return state;
414
415 return XMPP_SUBSCRIPTION_NONE;
416 }
417
418 size_t
419 XmppRosterContactImpl::GetGroupCount() const {
420 if (!raw_xml_)
421 return 0;
422
423 if (-1 == group_count_) {
424 XmlElement *group_element = raw_xml_->FirstNamed(QN_ROSTER_GROUP);
425 int group_count = 0;
426 while(group_element) {
427 group_count++;
428 group_element = group_element->NextNamed(QN_ROSTER_GROUP);
429 }
430
431 ASSERT(group_count > 0); // protect the cast
432 XmppRosterContactImpl * me = const_cast<XmppRosterContactImpl*>(this);
433 me->group_count_ = group_count;
434 }
435
436 return group_count_;
437 }
438
439 const std::string
440 XmppRosterContactImpl::GetGroup(size_t index) const {
441 if (index >= GetGroupCount())
442 return STR_EMPTY;
443
444 // We cache the last group index and element that we returned. This way
445 // going through the groups in order is order n and not n^2. This could be
446 // enhanced if necessary by starting at the cached value if the index asked
447 // is after the cached one.
448 if (group_index_returned_ >= 0 &&
449 index == static_cast<size_t>(group_index_returned_) + 1)
450 {
451 XmppRosterContactImpl * me = const_cast<XmppRosterContactImpl*>(this);
452 me->group_returned_ = group_returned_->NextNamed(QN_ROSTER_GROUP);
453 ASSERT(group_returned_ != NULL);
454 me->group_index_returned_++;
455 } else if (group_index_returned_ < 0 ||
456 static_cast<size_t>(group_index_returned_) != index) {
457 XmlElement * group_element = raw_xml_->FirstNamed(QN_ROSTER_GROUP);
458 size_t group_index = 0;
459 while(group_index < index) {
460 ASSERT(group_element != NULL);
461 group_index++;
462 group_element = group_element->NextNamed(QN_ROSTER_GROUP);
463 }
464
465 XmppRosterContactImpl * me = const_cast<XmppRosterContactImpl*>(this);
466 me->group_index_returned_ = static_cast<int>(group_index);
467 me->group_returned_ = group_element;
468 }
469
470 return group_returned_->BodyText();
471 }
472
473 XmppReturnStatus
474 XmppRosterContactImpl::AddGroup(const std::string& group) {
475 if (group == STR_EMPTY)
476 return XMPP_RETURN_BADARGUMENT;
477
478 if (!raw_xml_)
479 CreateRawXmlSkeleton();
480
481 if (FindGroup(group, NULL, NULL))
482 return XMPP_RETURN_OK;
483
484 raw_xml_->AddElement(new XmlElement(QN_ROSTER_GROUP));
485 raw_xml_->AddText(group, 1);
486 ++group_count_;
487
488 return XMPP_RETURN_OK;
489 }
490
491 XmppReturnStatus
492 XmppRosterContactImpl::RemoveGroup(const std::string& group) {
493 if (group == STR_EMPTY)
494 return XMPP_RETURN_BADARGUMENT;
495
496 if (!raw_xml_)
497 return XMPP_RETURN_OK;
498
499 XmlChild * child_before;
500 if (FindGroup(group, NULL, &child_before)) {
501 raw_xml_->RemoveChildAfter(child_before);
502 ResetGroupCache();
503 }
504 return XMPP_RETURN_OK;
505 }
506
507 bool
508 XmppRosterContactImpl::FindGroup(const std::string& group,
509 XmlElement** element,
510 XmlChild** child_before) {
511 XmlChild * prev_child = NULL;
512 XmlChild * next_child;
513 XmlChild * child;
514 for (child = raw_xml_->FirstChild(); child; child = next_child) {
515 next_child = child->NextChild();
516 if (!child->IsText() &&
517 child->AsElement()->Name() == QN_ROSTER_GROUP &&
518 child->AsElement()->BodyText() == group) {
519 if (element)
520 *element = child->AsElement();
521 if (child_before)
522 *child_before = prev_child;
523 return true;
524 }
525 prev_child = child;
526 }
527
528 return false;
529 }
530
531 const XmlElement*
532 XmppRosterContactImpl::raw_xml() const {
533 if (!raw_xml_)
534 const_cast<XmppRosterContactImpl*>(this)->CreateRawXmlSkeleton();
535 return raw_xml_.get();
536 }
537
538 XmppReturnStatus
539 XmppRosterContactImpl::set_raw_xml(const XmlElement* xml) {
540 if (!xml ||
541 xml->Name() != QN_ROSTER_ITEM ||
542 xml->HasAttr(QN_SUBSCRIPTION) ||
543 xml->HasAttr(QN_ASK))
544 return XMPP_RETURN_BADARGUMENT;
545
546 ResetGroupCache();
547
548 raw_xml_.reset(new XmlElement(*xml));
549
550 return XMPP_RETURN_OK;
551 }
552
553 void
554 XmppRosterContactImpl::CreateRawXmlSkeleton() {
555 raw_xml_.reset(new XmlElement(QN_ROSTER_ITEM));
556 }
557
558 // XmppRosterModuleImpl --------------------------------------------------------
559 XmppRosterModule *
560 XmppRosterModule::Create() {
561 return new XmppRosterModuleImpl();
562 }
563
564 XmppRosterModuleImpl::XmppRosterModuleImpl() :
565 roster_handler_(NULL),
566 incoming_presence_map_(new JidPresenceVectorMap()),
567 incoming_presence_vector_(new PresenceVector()),
568 contacts_(new ContactVector()) {
569
570 }
571
572 XmppRosterModuleImpl::~XmppRosterModuleImpl() {
573 DeleteIncomingPresence();
574 DeleteContacts();
575 }
576
577 XmppReturnStatus
578 XmppRosterModuleImpl::set_roster_handler(XmppRosterHandler * handler) {
579 roster_handler_ = handler;
580 return XMPP_RETURN_OK;
581 }
582
583 XmppRosterHandler*
584 XmppRosterModuleImpl::roster_handler() {
585 return roster_handler_;
586 }
587
588 XmppPresence*
589 XmppRosterModuleImpl::outgoing_presence() {
590 return &outgoing_presence_;
591 }
592
593 XmppReturnStatus
594 XmppRosterModuleImpl::BroadcastPresence() {
595 // Scrub the outgoing presence
596 const XmlElement* element = outgoing_presence_.raw_xml();
597
598 ASSERT(!element->HasAttr(QN_TO) &&
599 !element->HasAttr(QN_FROM) &&
600 (element->Attr(QN_TYPE) == STR_EMPTY ||
601 element->Attr(QN_TYPE) == "unavailable"));
602
603 if (!engine())
604 return XMPP_RETURN_BADSTATE;
605
606 return engine()->SendStanza(element);
607 }
608
609 XmppReturnStatus
610 XmppRosterModuleImpl::SendDirectedPresence(const XmppPresence* presence,
611 const Jid& to_jid) {
612 if (!presence)
613 return XMPP_RETURN_BADARGUMENT;
614
615 if (!engine())
616 return XMPP_RETURN_BADSTATE;
617
618 XmlElement element(*(presence->raw_xml()));
619
620 if (element.Name() != QN_PRESENCE ||
621 element.HasAttr(QN_TO) ||
622 element.HasAttr(QN_FROM))
623 return XMPP_RETURN_BADARGUMENT;
624
625 if (element.HasAttr(QN_TYPE)) {
626 if (element.Attr(QN_TYPE) != STR_EMPTY &&
627 element.Attr(QN_TYPE) != "unavailable") {
628 return XMPP_RETURN_BADARGUMENT;
629 }
630 }
631
632 element.SetAttr(QN_TO, to_jid.Str());
633
634 return engine()->SendStanza(&element);
635 }
636
637 size_t
638 XmppRosterModuleImpl::GetIncomingPresenceCount() {
639 return incoming_presence_vector_->size();
640 }
641
642 const XmppPresence*
643 XmppRosterModuleImpl::GetIncomingPresence(size_t index) {
644 if (index >= incoming_presence_vector_->size())
645 return NULL;
646 return (*incoming_presence_vector_)[index];
647 }
648
649 size_t
650 XmppRosterModuleImpl::GetIncomingPresenceForJidCount(const Jid& jid)
651 {
652 // find the vector in the map
653 JidPresenceVectorMap::iterator pos;
654 pos = incoming_presence_map_->find(jid);
655 if (pos == incoming_presence_map_->end())
656 return 0;
657
658 ASSERT(pos->second != NULL);
659
660 return pos->second->size();
661 }
662
663 const XmppPresence*
664 XmppRosterModuleImpl::GetIncomingPresenceForJid(const Jid& jid,
665 size_t index) {
666 JidPresenceVectorMap::iterator pos;
667 pos = incoming_presence_map_->find(jid);
668 if (pos == incoming_presence_map_->end())
669 return NULL;
670
671 ASSERT(pos->second != NULL);
672
673 if (index >= pos->second->size())
674 return NULL;
675
676 return (*pos->second)[index];
677 }
678
679 XmppReturnStatus
680 XmppRosterModuleImpl::RequestRosterUpdate() {
681 if (!engine())
682 return XMPP_RETURN_BADSTATE;
683
684 XmlElement roster_get(QN_IQ);
685 roster_get.AddAttr(QN_TYPE, "get");
686 roster_get.AddAttr(QN_ID, engine()->NextId());
687 roster_get.AddElement(new XmlElement(QN_ROSTER_QUERY, true));
688 return engine()->SendIq(&roster_get, this, NULL);
689 }
690
691 size_t
692 XmppRosterModuleImpl::GetRosterContactCount() {
693 return contacts_->size();
694 }
695
696 const XmppRosterContact*
697 XmppRosterModuleImpl::GetRosterContact(size_t index) {
698 if (index >= contacts_->size())
699 return NULL;
700 return (*contacts_)[index];
701 }
702
703 class RosterPredicate {
704 public:
705 explicit RosterPredicate(const Jid& jid) : jid_(jid) {
706 }
707
708 bool operator() (XmppRosterContactImpl *& contact) {
709 return contact->jid() == jid_;
710 }
711
712 private:
713 Jid jid_;
714 };
715
716 const XmppRosterContact*
717 XmppRosterModuleImpl::FindRosterContact(const Jid& jid) {
718 ContactVector::iterator pos;
719
720 pos = std::find_if(contacts_->begin(),
721 contacts_->end(),
722 RosterPredicate(jid));
723 if (pos == contacts_->end())
724 return NULL;
725
726 return *pos;
727 }
728
729 XmppReturnStatus
730 XmppRosterModuleImpl::RequestRosterChange(
731 const XmppRosterContact* contact) {
732 if (!contact)
733 return XMPP_RETURN_BADARGUMENT;
734
735 Jid jid = contact->jid();
736
737 if (!jid.IsValid())
738 return XMPP_RETURN_BADARGUMENT;
739
740 if (!engine())
741 return XMPP_RETURN_BADSTATE;
742
743 const XmlElement* contact_xml = contact->raw_xml();
744 if (contact_xml->Name() != QN_ROSTER_ITEM ||
745 contact_xml->HasAttr(QN_SUBSCRIPTION) ||
746 contact_xml->HasAttr(QN_ASK))
747 return XMPP_RETURN_BADARGUMENT;
748
749 XmlElement roster_add(QN_IQ);
750 roster_add.AddAttr(QN_TYPE, "set");
751 roster_add.AddAttr(QN_ID, engine()->NextId());
752 roster_add.AddElement(new XmlElement(QN_ROSTER_QUERY, true));
753 roster_add.AddElement(new XmlElement(*contact_xml), 1);
754
755 return engine()->SendIq(&roster_add, this, NULL);
756 }
757
758 XmppReturnStatus
759 XmppRosterModuleImpl::RequestRosterRemove(const Jid& jid) {
760 if (!jid.IsValid())
761 return XMPP_RETURN_BADARGUMENT;
762
763 if (!engine())
764 return XMPP_RETURN_BADSTATE;
765
766 XmlElement roster_add(QN_IQ);
767 roster_add.AddAttr(QN_TYPE, "set");
768 roster_add.AddAttr(QN_ID, engine()->NextId());
769 roster_add.AddElement(new XmlElement(QN_ROSTER_QUERY, true));
770 roster_add.AddAttr(QN_JID, jid.Str(), 1);
771 roster_add.AddAttr(QN_SUBSCRIPTION, "remove", 1);
772
773 return engine()->SendIq(&roster_add, this, NULL);
774 }
775
776 XmppReturnStatus
777 XmppRosterModuleImpl::RequestSubscription(const Jid& jid) {
778 return SendSubscriptionRequest(jid, "subscribe");
779 }
780
781 XmppReturnStatus
782 XmppRosterModuleImpl::CancelSubscription(const Jid& jid) {
783 return SendSubscriptionRequest(jid, "unsubscribe");
784 }
785
786 XmppReturnStatus
787 XmppRosterModuleImpl::ApproveSubscriber(const Jid& jid) {
788 return SendSubscriptionRequest(jid, "subscribed");
789 }
790
791 XmppReturnStatus
792 XmppRosterModuleImpl::CancelSubscriber(const Jid& jid) {
793 return SendSubscriptionRequest(jid, "unsubscribed");
794 }
795
796 void
797 XmppRosterModuleImpl::IqResponse(XmppIqCookie, const XmlElement * stanza) {
798 // The only real Iq response that we expect to recieve are initial roster
799 // population
800 if (stanza->Attr(QN_TYPE) == "error")
801 {
802 if (roster_handler_)
803 roster_handler_->RosterError(this, stanza);
804
805 return;
806 }
807
808 ASSERT(stanza->Attr(QN_TYPE) == "result");
809
810 InternalRosterItems(stanza);
811 }
812
813 bool
814 XmppRosterModuleImpl::HandleStanza(const XmlElement * stanza)
815 {
816 ASSERT(engine() != NULL);
817
818 // There are two types of stanzas that we care about: presence and roster push
819 // Iqs
820 if (stanza->Name() == QN_PRESENCE) {
821 const std::string& jid_string = stanza->Attr(QN_FROM);
822 Jid jid(jid_string);
823
824 if (!jid.IsValid())
825 return false; // if the Jid isn't valid, don't process
826
827 const std::string& type = stanza->Attr(QN_TYPE);
828 XmppSubscriptionRequestType request_type;
829 if (StringToSubscriptionRequestType(type, &request_type))
830 InternalSubscriptionRequest(jid, stanza, request_type);
831 else if (type == "unavailable" || type == STR_EMPTY)
832 InternalIncomingPresence(jid, stanza);
833 else if (type == "error")
834 InternalIncomingPresenceError(jid, stanza);
835 else
836 return false;
837
838 return true;
839 } else if (stanza->Name() == QN_IQ) {
840 const XmlElement * roster_query = stanza->FirstNamed(QN_ROSTER_QUERY);
841 if (!roster_query || stanza->Attr(QN_TYPE) != "set")
842 return false;
843
844 InternalRosterItems(stanza);
845
846 // respond to the IQ
847 XmlElement result(QN_IQ);
848 result.AddAttr(QN_TYPE, "result");
849 result.AddAttr(QN_TO, stanza->Attr(QN_FROM));
850 result.AddAttr(QN_ID, stanza->Attr(QN_ID));
851
852 engine()->SendStanza(&result);
853 return true;
854 }
855
856 return false;
857 }
858
859 void
860 XmppRosterModuleImpl::DeleteIncomingPresence() {
861 // Clear out the vector of all presence notifications
862 {
863 PresenceVector::iterator pos;
864 for (pos = incoming_presence_vector_->begin();
865 pos < incoming_presence_vector_->end();
866 ++pos) {
867 XmppPresenceImpl * presence = *pos;
868 *pos = NULL;
869 delete presence;
870 }
871 incoming_presence_vector_->clear();
872 }
873
874 // Clear out all of the small presence vectors per Jid
875 {
876 JidPresenceVectorMap::iterator pos;
877 for (pos = incoming_presence_map_->begin();
878 pos != incoming_presence_map_->end();
879 ++pos) {
880 PresenceVector* presence_vector = pos->second;
881 pos->second = NULL;
882 delete presence_vector;
883 }
884 incoming_presence_map_->clear();
885 }
886 }
887
888 void
889 XmppRosterModuleImpl::DeleteContacts() {
890 ContactVector::iterator pos;
891 for (pos = contacts_->begin();
892 pos < contacts_->end();
893 ++pos) {
894 XmppRosterContact* contact = *pos;
895 *pos = NULL;
896 delete contact;
897 }
898 contacts_->clear();
899 }
900
901 XmppReturnStatus
902 XmppRosterModuleImpl::SendSubscriptionRequest(const Jid& jid,
903 const std::string& type) {
904 if (!jid.IsValid())
905 return XMPP_RETURN_BADARGUMENT;
906
907 if (!engine())
908 return XMPP_RETURN_BADSTATE;
909
910 XmlElement presence_request(QN_PRESENCE);
911 presence_request.AddAttr(QN_TO, jid.Str());
912 presence_request.AddAttr(QN_TYPE, type);
913
914 return engine()->SendStanza(&presence_request);
915 }
916
917
918 void
919 XmppRosterModuleImpl::InternalSubscriptionRequest(const Jid& jid,
920 const XmlElement* stanza,
921 XmppSubscriptionRequestType
922 request_type) {
923 if (roster_handler_)
924 roster_handler_->SubscriptionRequest(this, jid, request_type, stanza);
925 }
926
927 class PresencePredicate {
928 public:
929 explicit PresencePredicate(const Jid& jid) : jid_(jid) {
930 }
931
932 bool operator() (XmppPresenceImpl *& contact) {
933 return contact->jid() == jid_;
934 }
935
936 private:
937 Jid jid_;
938 };
939
940 void
941 XmppRosterModuleImpl::InternalIncomingPresence(const Jid& jid,
942 const XmlElement* stanza) {
943 bool added = false;
944 Jid bare_jid = jid.BareJid();
945
946 // First add the presence to the map
947 JidPresenceVectorMap::iterator pos;
948 pos = incoming_presence_map_->find(jid.BareJid());
949 if (pos == incoming_presence_map_->end()) {
950 // Insert a new entry into the map. Get the position of this new entry
951 pos = (incoming_presence_map_->insert(
952 std::make_pair(bare_jid, new PresenceVector()))).first;
953 }
954
955 PresenceVector * presence_vector = pos->second;
956 ASSERT(presence_vector != NULL);
957
958 // Try to find this jid in the bare jid bucket
959 PresenceVector::iterator presence_pos;
960 XmppPresenceImpl* presence;
961 presence_pos = std::find_if(presence_vector->begin(),
962 presence_vector->end(),
963 PresencePredicate(jid));
964
965 // Update/add it to the bucket
966 if (presence_pos == presence_vector->end()) {
967 presence = new XmppPresenceImpl();
968 if (XMPP_RETURN_OK == presence->set_raw_xml(stanza)) {
969 added = true;
970 presence_vector->push_back(presence);
971 } else {
972 delete presence;
973 presence = NULL;
974 }
975 } else {
976 presence = *presence_pos;
977 presence->set_raw_xml(stanza);
978 }
979
980 // now add to the comprehensive vector
981 if (added)
982 incoming_presence_vector_->push_back(presence);
983
984 // Call back to the user with the changed presence information
985 if (roster_handler_)
986 roster_handler_->IncomingPresenceChanged(this, presence);
987 }
988
989
990 void
991 XmppRosterModuleImpl::InternalIncomingPresenceError(const Jid& jid,
992 const XmlElement* stanza) {
993 if (roster_handler_)
994 roster_handler_->SubscriptionError(this, jid, stanza);
995 }
996
997 void
998 XmppRosterModuleImpl::InternalRosterItems(const XmlElement* stanza) {
999 const XmlElement* result_data = stanza->FirstNamed(QN_ROSTER_QUERY);
1000 if (!result_data)
1001 return; // unknown stuff in result!
1002
1003 bool all_new = contacts_->empty();
1004
1005 for (const XmlElement* roster_item = result_data->FirstNamed(QN_ROSTER_ITEM);
1006 roster_item;
1007 roster_item = roster_item->NextNamed(QN_ROSTER_ITEM))
1008 {
1009 const std::string& jid_string = roster_item->Attr(QN_JID);
1010 Jid jid(jid_string);
1011 if (!jid.IsValid())
1012 continue;
1013
1014 // This algorithm is N^2 on the number of incoming contacts after the
1015 // initial load. There is no way to do this faster without allowing
1016 // duplicates, introducing more data structures or write a custom data
1017 // structure. We'll see if this becomes a perf problem and fix it if it
1018 // does.
1019 ContactVector::iterator pos = contacts_->end();
1020
1021 if (!all_new) {
1022 pos = std::find_if(contacts_->begin(),
1023 contacts_->end(),
1024 RosterPredicate(jid));
1025 }
1026
1027 if (pos != contacts_->end()) { // Update/remove a current contact
1028 if (roster_item->Attr(QN_SUBSCRIPTION) == "remove") {
1029 XmppRosterContact* contact = *pos;
1030 contacts_->erase(pos);
1031 if (roster_handler_)
1032 roster_handler_->ContactRemoved(this, contact,
1033 std::distance(contacts_->begin(), pos));
1034 delete contact;
1035 } else {
1036 XmppRosterContact* old_contact = *pos;
1037 *pos = new XmppRosterContactImpl();
1038 (*pos)->SetXmlFromWire(roster_item);
1039 if (roster_handler_)
1040 roster_handler_->ContactChanged(this, old_contact,
1041 std::distance(contacts_->begin(), pos));
1042 delete old_contact;
1043 }
1044 } else { // Add a new contact
1045 XmppRosterContactImpl* contact = new XmppRosterContactImpl();
1046 contact->SetXmlFromWire(roster_item);
1047 contacts_->push_back(contact);
1048 if (roster_handler_ && !all_new)
1049 roster_handler_->ContactsAdded(this, contacts_->size() - 1, 1);
1050 }
1051 }
1052
1053 // Send a consolidated update if all contacts are new
1054 if (roster_handler_ && all_new)
1055 roster_handler_->ContactsAdded(this, 0, contacts_->size());
1056 }
1057
1058 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698