Upstream version 11.40.271.0
[platform/framework/web/crosswalk.git] / src / third_party / webrtc / libjingle / xmpp / chatroommoduleimpl.cc
1 /*
2  *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10
11 #include <algorithm>
12 #include <iostream>
13 #include <map>
14 #include <sstream>
15 #include <string>
16 #include <vector>
17 #include "webrtc/libjingle/xmpp/chatroommodule.h"
18 #include "webrtc/libjingle/xmpp/constants.h"
19 #include "webrtc/libjingle/xmpp/moduleimpl.h"
20 #include "webrtc/base/common.h"
21
22 namespace buzz {
23
24 // forward declarations
25 class XmppChatroomImpl;
26 class XmppChatroomMemberImpl;
27
28 //! Module that encapsulates multiple chatrooms.
29 //! Each chatroom is represented by an XmppChatroomImpl instance
30 class XmppChatroomModuleImpl : public XmppChatroomModule,
31   public XmppModuleImpl, public XmppIqHandler {
32 public:
33   IMPLEMENT_XMPPMODULE
34
35    // Creates a chatroom with specified Jid
36   XmppChatroomModuleImpl();
37   ~XmppChatroomModuleImpl();
38
39   // XmppChatroomModule
40   virtual XmppReturnStatus set_chatroom_handler(XmppChatroomHandler* handler);
41   virtual XmppChatroomHandler* chatroom_handler();
42   virtual XmppReturnStatus set_chatroom_jid(const Jid& chatroom_jid);
43   virtual const Jid& chatroom_jid() const;
44   virtual XmppReturnStatus set_nickname(const std::string& nickname);
45   virtual const std::string& nickname() const;
46   virtual const Jid member_jid() const;
47   virtual XmppReturnStatus RequestEnterChatroom(const std::string& password,
48       const std::string& client_version,
49       const std::string& locale);
50   virtual XmppReturnStatus RequestExitChatroom();
51   virtual XmppReturnStatus RequestConnectionStatusChange(
52       XmppPresenceConnectionStatus connection_status);
53   virtual size_t GetChatroomMemberCount();
54   virtual XmppReturnStatus CreateMemberEnumerator(XmppChatroomMemberEnumerator** enumerator);
55   virtual const std::string subject();
56   virtual XmppChatroomState state() { return chatroom_state_; }
57   virtual XmppReturnStatus SendMessage(const XmlElement& message);
58
59   // XmppModule
60   virtual void IqResponse(XmppIqCookie cookie, const XmlElement * pelStanza) {RTC_UNUSED2(cookie, pelStanza);}
61   virtual bool HandleStanza(const XmlElement *);
62
63 private:
64   friend class XmppChatroomMemberEnumeratorImpl;
65
66   XmppReturnStatus ServerChangeMyPresence(const XmlElement& presence);
67   XmppReturnStatus ClientChangeMyPresence(XmppChatroomState new_state);
68   XmppReturnStatus ChangePresence(XmppChatroomState new_state, const XmlElement* presence, bool isServer);
69   XmppReturnStatus ServerChangedOtherPresence(const XmlElement& presence_element);
70   XmppChatroomEnteredStatus GetEnterFailureFromXml(const XmlElement* presence);
71   XmppChatroomExitedStatus GetExitFailureFromXml(const XmlElement* presence);
72
73   bool CheckEnterChatroomStateOk();
74
75   void FireEnteredStatus(const XmlElement* presence,
76                          XmppChatroomEnteredStatus status);
77   void FireExitStatus(XmppChatroomExitedStatus status);
78   void FireMessageReceived(const XmlElement& message);
79   void FireMemberEntered(const XmppChatroomMember* entered_member);
80   void FireMemberChanged(const XmppChatroomMember* changed_member);
81   void FireMemberExited(const XmppChatroomMember* exited_member);
82
83
84   typedef std::map<Jid, XmppChatroomMemberImpl*> JidMemberMap;
85
86   XmppChatroomHandler*              chatroom_handler_;
87   Jid                               chatroom_jid_;
88   std::string                       nickname_;
89   XmppChatroomState                 chatroom_state_;
90   JidMemberMap                      chatroom_jid_members_;
91   int                               chatroom_jid_members_version_;
92 };
93
94
95 class XmppChatroomMemberImpl : public XmppChatroomMember {
96 public:
97   ~XmppChatroomMemberImpl() {}
98   XmppReturnStatus SetPresence(const XmppPresence* presence);
99
100   // XmppChatroomMember
101   const Jid member_jid() const;
102   const Jid full_jid() const;
103   const std::string name() const;
104   const XmppPresence* presence() const;
105
106 private:
107   rtc::scoped_ptr<XmppPresence>  presence_;
108 };
109
110 class XmppChatroomMemberEnumeratorImpl :
111         public XmppChatroomMemberEnumerator  {
112 public:
113   XmppChatroomMemberEnumeratorImpl(XmppChatroomModuleImpl::JidMemberMap* chatroom_jid_members,
114                                         int* map_version);
115
116   // XmppChatroomMemberEnumerator
117   virtual XmppChatroomMember* current();
118   virtual bool Next();
119   virtual bool Prev();
120   virtual bool IsValid();
121   virtual bool IsBeforeBeginning();
122   virtual bool IsAfterEnd();
123
124 private:
125   XmppChatroomModuleImpl::JidMemberMap*           map_;
126   int                                             map_version_created_;
127   int*                                            map_version_;
128   XmppChatroomModuleImpl::JidMemberMap::iterator  iterator_;
129   bool                                            before_beginning_;
130 };
131
132
133 // XmppChatroomModuleImpl ------------------------------------------------
134 XmppChatroomModule *
135 XmppChatroomModule::Create() {
136   return new XmppChatroomModuleImpl();
137 }
138
139 XmppChatroomModuleImpl::XmppChatroomModuleImpl() :
140   chatroom_handler_(NULL),
141   chatroom_jid_(STR_EMPTY),
142   chatroom_state_(XMPP_CHATROOM_STATE_NOT_IN_ROOM),
143   chatroom_jid_members_version_(0) {
144 }
145
146 XmppChatroomModuleImpl::~XmppChatroomModuleImpl() {
147   JidMemberMap::iterator iterator = chatroom_jid_members_.begin();
148   while (iterator != chatroom_jid_members_.end()) {
149     delete iterator->second;
150     iterator++;
151   }
152 }
153
154
155 bool
156 XmppChatroomModuleImpl::HandleStanza(const XmlElement* stanza) {
157   ASSERT(engine() != NULL);
158
159   // we handle stanzas that are for one of our chatrooms
160   Jid from_jid = Jid(stanza->Attr(QN_FROM));
161   // see if it's one of our chatrooms
162   if (chatroom_jid_ != from_jid.BareJid()) {
163     return false; // not one of our chatrooms
164   } else {
165     // handle presence stanza
166     if (stanza->Name() == QN_PRESENCE) {
167       if (from_jid == member_jid()) {
168         ServerChangeMyPresence(*stanza);
169       } else {
170         ServerChangedOtherPresence(*stanza);
171       }
172     } else if (stanza->Name() == QN_MESSAGE) {
173       FireMessageReceived(*stanza);
174     }
175     return true;
176   }
177 }
178
179
180 XmppReturnStatus
181 XmppChatroomModuleImpl::set_chatroom_handler(XmppChatroomHandler* handler) {
182   // Calling with NULL removes the handler.
183   chatroom_handler_ = handler;
184   return XMPP_RETURN_OK;
185 }
186
187
188 XmppChatroomHandler*
189 XmppChatroomModuleImpl::chatroom_handler() {
190   return chatroom_handler_;
191 }
192
193 XmppReturnStatus
194 XmppChatroomModuleImpl::set_chatroom_jid(const Jid& chatroom_jid) {
195   if (chatroom_state_ != XMPP_CHATROOM_STATE_NOT_IN_ROOM) {
196     return XMPP_RETURN_BADSTATE; // $TODO - this isn't a bad state, it's a bad call,  diff error code?
197   }
198   if (chatroom_jid != chatroom_jid.BareJid()) {
199     // chatroom_jid must be a bare jid
200     return XMPP_RETURN_BADARGUMENT;
201   }
202
203   chatroom_jid_ = chatroom_jid;
204   return XMPP_RETURN_OK;
205 }
206
207 const Jid&
208 XmppChatroomModuleImpl::chatroom_jid() const {
209   return chatroom_jid_;
210 }
211
212  XmppReturnStatus
213  XmppChatroomModuleImpl::set_nickname(const std::string& nickname) {
214   if (chatroom_state_ != XMPP_CHATROOM_STATE_NOT_IN_ROOM) {
215     return XMPP_RETURN_BADSTATE; // $TODO - this isn't a bad state, it's a bad call,  diff error code?
216   }
217   nickname_ = nickname;
218   return XMPP_RETURN_OK;
219  }
220
221  const std::string&
222  XmppChatroomModuleImpl::nickname() const {
223   return nickname_;
224  }
225
226 const Jid
227 XmppChatroomModuleImpl::member_jid() const {
228   return Jid(chatroom_jid_.node(), chatroom_jid_.domain(), nickname_);
229 }
230
231
232 bool
233 XmppChatroomModuleImpl::CheckEnterChatroomStateOk() {
234   if (chatroom_jid_.IsValid() == false) {
235     ASSERT(0);
236     return false;
237   }
238   if (nickname_ == STR_EMPTY) {
239     ASSERT(0);
240     return false;
241   }
242   return true;
243 }
244
245 std::string GetAttrValueFor(XmppPresenceConnectionStatus connection_status) {
246   switch (connection_status) {
247     default:
248     case XMPP_CONNECTION_STATUS_UNKNOWN:
249       return "";
250     case XMPP_CONNECTION_STATUS_CONNECTING:
251       return STR_PSTN_CONFERENCE_STATUS_CONNECTING;
252     case XMPP_CONNECTION_STATUS_CONNECTED:
253       return STR_PSTN_CONFERENCE_STATUS_CONNECTED;
254   }
255 }
256
257 XmppReturnStatus
258 XmppChatroomModuleImpl::RequestEnterChatroom(
259     const std::string& password,
260     const std::string& client_version,
261     const std::string& locale) {
262   RTC_UNUSED(password);
263   if (!engine())
264     return XMPP_RETURN_BADSTATE;
265
266   if (chatroom_state_ != XMPP_CHATROOM_STATE_NOT_IN_ROOM)
267     return XMPP_RETURN_BADSTATE; // $TODO - this isn't a bad state, it's a bad call,  diff error code?
268
269   if (CheckEnterChatroomStateOk() == false) {
270     return XMPP_RETURN_BADSTATE;
271   }
272
273   // entering a chatroom is a presence request to the server
274   XmlElement element(QN_PRESENCE);
275   element.AddAttr(QN_TO, member_jid().Str());
276
277   XmlElement* muc_x = new XmlElement(QN_MUC_X);
278   element.AddElement(muc_x);
279
280   if (!client_version.empty()) {
281     XmlElement* client_version_element = new XmlElement(QN_CLIENT_VERSION,
282                                                         false);
283     client_version_element->SetBodyText(client_version);
284     muc_x->AddElement(client_version_element);
285   }
286
287   if (!locale.empty()) {
288     XmlElement* locale_element = new XmlElement(QN_LOCALE, false);
289
290     locale_element->SetBodyText(locale);
291     muc_x->AddElement(locale_element);
292   }
293
294   XmppReturnStatus status = engine()->SendStanza(&element);
295   if (status == XMPP_RETURN_OK) {
296     return ClientChangeMyPresence(XMPP_CHATROOM_STATE_REQUESTED_ENTER);
297   }
298   return status;
299 }
300
301 XmppReturnStatus
302 XmppChatroomModuleImpl::RequestExitChatroom() {
303   if (!engine())
304     return XMPP_RETURN_BADSTATE;
305
306   // exiting a chatroom is a presence request to the server
307   XmlElement element(QN_PRESENCE);
308   element.AddAttr(QN_TO, member_jid().Str());
309   element.AddAttr(QN_TYPE, "unavailable");
310   XmppReturnStatus status = engine()->SendStanza(&element);
311   if (status == XMPP_RETURN_OK &&
312       chatroom_state_ == XMPP_CHATROOM_STATE_IN_ROOM) {
313     return ClientChangeMyPresence(XMPP_CHATROOM_STATE_REQUESTED_EXIT);
314   }
315   return status;
316 }
317
318 XmppReturnStatus
319 XmppChatroomModuleImpl::RequestConnectionStatusChange(
320     XmppPresenceConnectionStatus connection_status) {
321   if (!engine())
322     return XMPP_RETURN_BADSTATE;
323
324   if (chatroom_state_ != XMPP_CHATROOM_STATE_IN_ROOM) {
325     // $TODO - this isn't a bad state, it's a bad call,  diff error code?
326     return XMPP_RETURN_BADSTATE;
327   }
328
329   if (CheckEnterChatroomStateOk() == false) {
330     return XMPP_RETURN_BADSTATE;
331   }
332
333   // entering a chatroom is a presence request to the server
334   XmlElement element(QN_PRESENCE);
335   element.AddAttr(QN_TO, member_jid().Str());
336   element.AddElement(new XmlElement(QN_MUC_X));
337   if (connection_status != XMPP_CONNECTION_STATUS_UNKNOWN) {
338     XmlElement* con_status_element =
339         new XmlElement(QN_GOOGLE_PSTN_CONFERENCE_STATUS);
340     con_status_element->AddAttr(QN_STATUS, GetAttrValueFor(connection_status));
341     element.AddElement(con_status_element);
342   }
343   XmppReturnStatus status = engine()->SendStanza(&element);
344
345   return status;
346 }
347
348 size_t
349 XmppChatroomModuleImpl::GetChatroomMemberCount() {
350   return chatroom_jid_members_.size();
351 }
352
353 XmppReturnStatus
354 XmppChatroomModuleImpl::CreateMemberEnumerator(XmppChatroomMemberEnumerator** enumerator) {
355   *enumerator = new XmppChatroomMemberEnumeratorImpl(&chatroom_jid_members_, &chatroom_jid_members_version_);
356   return XMPP_RETURN_OK;
357 }
358
359 const std::string
360 XmppChatroomModuleImpl::subject() {
361   return ""; //NYI
362 }
363
364 XmppReturnStatus
365 XmppChatroomModuleImpl::SendMessage(const XmlElement& message) {
366   XmppReturnStatus xmpp_status = XMPP_RETURN_OK;
367
368   // can only send a message if we're in the room
369   if (chatroom_state_ != XMPP_CHATROOM_STATE_IN_ROOM) {
370     return XMPP_RETURN_BADSTATE; // $TODO - this isn't a bad state, it's a bad call,  diff error code?
371   }
372
373   if (message.Name() != QN_MESSAGE) {
374     IFR(XMPP_RETURN_BADARGUMENT);
375   }
376
377   const std::string& type = message.Attr(QN_TYPE);
378   if (type != "groupchat") {
379     IFR(XMPP_RETURN_BADARGUMENT);
380   }
381
382   if (message.HasAttr(QN_FROM)) {
383     IFR(XMPP_RETURN_BADARGUMENT);
384   }
385
386   if (message.Attr(QN_TO) != chatroom_jid_.Str()) {
387     IFR(XMPP_RETURN_BADARGUMENT);
388   }
389
390   IFR(engine()->SendStanza(&message));
391
392   return xmpp_status;
393 }
394
395 enum TransitionType {
396   TRANSITION_TYPE_NONE                 = 0,
397   TRANSITION_TYPE_ENTER_SUCCESS        = 1,
398   TRANSITION_TYPE_ENTER_FAILURE        = 2,
399   TRANSITION_TYPE_EXIT_VOLUNTARILY     = 3,
400   TRANSITION_TYPE_EXIT_INVOLUNTARILY   = 4,
401 };
402
403 struct StateTransitionDescription {
404   XmppChatroomState old_state;
405   XmppChatroomState new_state;
406   bool              is_valid_server_transition;
407   bool              is_valid_client_transition;
408   TransitionType    transition_type;
409 };
410
411 StateTransitionDescription Transitions[] = {
412   { XMPP_CHATROOM_STATE_NOT_IN_ROOM,     XMPP_CHATROOM_STATE_REQUESTED_ENTER, false, true,  TRANSITION_TYPE_NONE, },
413   { XMPP_CHATROOM_STATE_NOT_IN_ROOM,     XMPP_CHATROOM_STATE_IN_ROOM,         false, false, TRANSITION_TYPE_ENTER_SUCCESS, },
414   { XMPP_CHATROOM_STATE_NOT_IN_ROOM,     XMPP_CHATROOM_STATE_REQUESTED_EXIT,  false, false, TRANSITION_TYPE_NONE, },
415   { XMPP_CHATROOM_STATE_REQUESTED_ENTER, XMPP_CHATROOM_STATE_NOT_IN_ROOM,     true,  false, TRANSITION_TYPE_ENTER_FAILURE, },
416   { XMPP_CHATROOM_STATE_REQUESTED_ENTER, XMPP_CHATROOM_STATE_IN_ROOM,         true,  false, TRANSITION_TYPE_ENTER_SUCCESS, },
417   { XMPP_CHATROOM_STATE_REQUESTED_ENTER, XMPP_CHATROOM_STATE_REQUESTED_EXIT,  false, false, TRANSITION_TYPE_NONE, },
418   { XMPP_CHATROOM_STATE_IN_ROOM,         XMPP_CHATROOM_STATE_NOT_IN_ROOM,     true,  false, TRANSITION_TYPE_EXIT_INVOLUNTARILY,  },
419   { XMPP_CHATROOM_STATE_IN_ROOM,         XMPP_CHATROOM_STATE_REQUESTED_ENTER, false, false, TRANSITION_TYPE_NONE, },
420   { XMPP_CHATROOM_STATE_IN_ROOM,         XMPP_CHATROOM_STATE_REQUESTED_EXIT,  false, true,  TRANSITION_TYPE_NONE, },
421   { XMPP_CHATROOM_STATE_REQUESTED_EXIT,  XMPP_CHATROOM_STATE_NOT_IN_ROOM,     true,  false, TRANSITION_TYPE_EXIT_VOLUNTARILY, },
422   { XMPP_CHATROOM_STATE_REQUESTED_EXIT,  XMPP_CHATROOM_STATE_REQUESTED_ENTER, false, false, TRANSITION_TYPE_NONE, },
423   { XMPP_CHATROOM_STATE_REQUESTED_EXIT,  XMPP_CHATROOM_STATE_IN_ROOM,         false, false, TRANSITION_TYPE_NONE, },
424 };
425
426
427
428 void
429 XmppChatroomModuleImpl::FireEnteredStatus(const XmlElement* presence,
430                                           XmppChatroomEnteredStatus status) {
431   if (chatroom_handler_) {
432     rtc::scoped_ptr<XmppPresence> xmpp_presence(XmppPresence::Create());
433     xmpp_presence->set_raw_xml(presence);
434     chatroom_handler_->ChatroomEnteredStatus(this, xmpp_presence.get(), status);
435   }
436 }
437
438 void
439 XmppChatroomModuleImpl::FireExitStatus(XmppChatroomExitedStatus status) {
440   if (chatroom_handler_)
441     chatroom_handler_->ChatroomExitedStatus(this, status);
442 }
443
444 void
445 XmppChatroomModuleImpl::FireMessageReceived(const XmlElement& message) {
446   if (chatroom_handler_)
447     chatroom_handler_->MessageReceived(this, message);
448 }
449
450 void
451 XmppChatroomModuleImpl::FireMemberEntered(const XmppChatroomMember* entered_member) {
452   if (chatroom_handler_)
453     chatroom_handler_->MemberEntered(this, entered_member);
454 }
455
456 void
457 XmppChatroomModuleImpl::FireMemberChanged(
458     const XmppChatroomMember* changed_member) {
459   if (chatroom_handler_)
460     chatroom_handler_->MemberChanged(this, changed_member);
461 }
462
463 void
464 XmppChatroomModuleImpl::FireMemberExited(const XmppChatroomMember* exited_member) {
465   if (chatroom_handler_)
466     chatroom_handler_->MemberExited(this, exited_member);
467 }
468
469
470 XmppReturnStatus
471 XmppChatroomModuleImpl::ServerChangedOtherPresence(const XmlElement&
472                                                    presence_element) {
473   XmppReturnStatus xmpp_status = XMPP_RETURN_OK;
474   rtc::scoped_ptr<XmppPresence> presence(XmppPresence::Create());
475   IFR(presence->set_raw_xml(&presence_element));
476
477   JidMemberMap::iterator pos = chatroom_jid_members_.find(presence->jid());
478
479   if (pos == chatroom_jid_members_.end()) {
480     if (presence->available() == XMPP_PRESENCE_AVAILABLE) {
481       XmppChatroomMemberImpl* member = new XmppChatroomMemberImpl();
482       member->SetPresence(presence.get());
483       chatroom_jid_members_.insert(std::make_pair(member->member_jid(), member));
484       chatroom_jid_members_version_++;
485       FireMemberEntered(member);
486     }
487   } else {
488     XmppChatroomMemberImpl* member = pos->second;
489     if (presence->available() == XMPP_PRESENCE_AVAILABLE) {
490       member->SetPresence(presence.get());
491       chatroom_jid_members_version_++;
492       FireMemberChanged(member);
493     }
494     else if (presence->available() == XMPP_PRESENCE_UNAVAILABLE) {
495       member->SetPresence(presence.get());
496       chatroom_jid_members_.erase(pos);
497       chatroom_jid_members_version_++;
498       FireMemberExited(member);
499       delete member;
500     }
501   }
502
503   return xmpp_status;
504 }
505
506 XmppReturnStatus
507 XmppChatroomModuleImpl::ClientChangeMyPresence(XmppChatroomState new_state) {
508   return ChangePresence(new_state, NULL, false);
509 }
510
511 XmppReturnStatus
512 XmppChatroomModuleImpl::ServerChangeMyPresence(const XmlElement& presence) {
513    XmppChatroomState new_state;
514
515    if (presence.HasAttr(QN_TYPE) == false) {
516       new_state = XMPP_CHATROOM_STATE_IN_ROOM;
517    } else {
518      new_state = XMPP_CHATROOM_STATE_NOT_IN_ROOM;
519    }
520   return ChangePresence(new_state, &presence, true);
521
522 }
523
524 XmppReturnStatus
525 XmppChatroomModuleImpl::ChangePresence(XmppChatroomState new_state,
526                                        const XmlElement* presence,
527                                        bool isServer) {
528   RTC_UNUSED(presence);
529
530   XmppChatroomState old_state = chatroom_state_;
531
532   // do nothing if state hasn't changed
533   if (old_state == new_state)
534     return XMPP_RETURN_OK;
535
536   // find the right transition description
537   StateTransitionDescription* transition_desc = NULL;
538   for (int i=0; i < ARRAY_SIZE(Transitions); i++) {
539     if (Transitions[i].old_state == old_state &&
540         Transitions[i].new_state == new_state) {
541         transition_desc = &Transitions[i];
542         break;
543     }
544   }
545
546   if (transition_desc == NULL) {
547     ASSERT(0);
548     return XMPP_RETURN_BADSTATE;
549   }
550
551   // we assert for any invalid transition states, and we'll
552   if (isServer) {
553     // $TODO send original stanza back to server and log an error?
554     // Disable the assert because of b/6133072
555     // ASSERT(transition_desc->is_valid_server_transition);
556     if (!transition_desc->is_valid_server_transition) {
557       return XMPP_RETURN_BADSTATE;
558     }
559   } else {
560     if (transition_desc->is_valid_client_transition == false) {
561       ASSERT(0);
562       return XMPP_RETURN_BADARGUMENT;
563     }
564   }
565
566   // set the new state and then fire any notifications to the handler
567   chatroom_state_ = new_state;
568
569   switch (transition_desc->transition_type) {
570     case TRANSITION_TYPE_ENTER_SUCCESS:
571       FireEnteredStatus(presence, XMPP_CHATROOM_ENTERED_SUCCESS);
572       break;
573     case TRANSITION_TYPE_ENTER_FAILURE:
574       FireEnteredStatus(presence, GetEnterFailureFromXml(presence));
575       break;
576     case TRANSITION_TYPE_EXIT_INVOLUNTARILY:
577       FireExitStatus(GetExitFailureFromXml(presence));
578       break;
579     case TRANSITION_TYPE_EXIT_VOLUNTARILY:
580       FireExitStatus(XMPP_CHATROOM_EXITED_REQUESTED);
581       break;
582     case TRANSITION_TYPE_NONE:
583       break;
584   }
585
586   return XMPP_RETURN_OK;
587 }
588
589 XmppChatroomEnteredStatus
590 XmppChatroomModuleImpl::GetEnterFailureFromXml(const XmlElement* presence) {
591   XmppChatroomEnteredStatus status = XMPP_CHATROOM_ENTERED_FAILURE_UNSPECIFIED;
592   const XmlElement* error = presence->FirstNamed(QN_ERROR);
593   if (error != NULL && error->HasAttr(QN_CODE)) {
594     int code = atoi(error->Attr(QN_CODE).c_str());
595     switch (code) {
596       case 401: status = XMPP_CHATROOM_ENTERED_FAILURE_PASSWORD_REQUIRED; break;
597       case 403: {
598         status = XMPP_CHATROOM_ENTERED_FAILURE_MEMBER_BANNED;
599         if (error->FirstNamed(QN_GOOGLE_SESSION_BLOCKED)) {
600           status = XMPP_CHATROOM_ENTERED_FAILURE_MEMBER_BLOCKED;
601         } else if (error->FirstNamed(QN_GOOGLE_SESSION_BLOCKING)) {
602           status = XMPP_CHATROOM_ENTERED_FAILURE_MEMBER_BLOCKING;
603         }
604         break;
605       }
606       case 405: status = XMPP_CHATROOM_ENTERED_FAILURE_ROOM_LOCKED; break;
607       case 406: status = XMPP_CHATROOM_ENTERED_FAILURE_OUTDATED_CLIENT; break;
608       case 407: status = XMPP_CHATROOM_ENTERED_FAILURE_NOT_A_MEMBER; break;
609       case 409: status = XMPP_CHATROOM_ENTERED_FAILURE_NICKNAME_CONFLICT; break;
610       // http://xmpp.org/extensions/xep-0045.html#enter-maxusers
611       case 503: status = XMPP_CHATROOM_ENTERED_FAILURE_MAX_USERS; break;
612     }
613   }
614   return status;
615 }
616
617 XmppChatroomExitedStatus
618 XmppChatroomModuleImpl::GetExitFailureFromXml(const XmlElement* presence) {
619   XmppChatroomExitedStatus status = XMPP_CHATROOM_EXITED_UNSPECIFIED;
620   const XmlElement* muc_user = presence->FirstNamed(QN_MUC_USER_X);
621   if (muc_user != NULL) {
622     const XmlElement* user_status = muc_user->FirstNamed(QN_MUC_USER_STATUS);
623     if (user_status != NULL && user_status->HasAttr(QN_CODE)) {
624       int code = atoi(user_status->Attr(QN_CODE).c_str());
625       switch (code) {
626         case 307: status = XMPP_CHATROOM_EXITED_KICKED; break;
627         case 322: status = XMPP_CHATROOM_EXITED_NOT_A_MEMBER; break;
628         case 332: status = XMPP_CHATROOM_EXITED_SYSTEM_SHUTDOWN; break;
629       }
630     }
631   }
632   return status;
633 }
634
635 XmppReturnStatus
636 XmppChatroomMemberImpl::SetPresence(const XmppPresence* presence) {
637   ASSERT(presence != NULL);
638
639   // copy presence
640   presence_.reset(XmppPresence::Create());
641   presence_->set_raw_xml(presence->raw_xml());
642   return XMPP_RETURN_OK;
643 }
644
645 const Jid
646 XmppChatroomMemberImpl::member_jid() const {
647   return presence_->jid();
648 }
649
650 const Jid
651 XmppChatroomMemberImpl::full_jid() const {
652   return Jid("");
653 }
654
655 const std::string
656 XmppChatroomMemberImpl::name() const {
657   return member_jid().resource();
658 }
659
660 const XmppPresence*
661 XmppChatroomMemberImpl::presence() const {
662   return presence_.get();
663 }
664
665
666 // XmppChatroomMemberEnumeratorImpl --------------------------------------
667 XmppChatroomMemberEnumeratorImpl::XmppChatroomMemberEnumeratorImpl(
668         XmppChatroomModuleImpl::JidMemberMap* map, int* map_version) {
669   map_ = map;
670   map_version_ = map_version;
671   map_version_created_ = *map_version_;
672   iterator_ = map->begin();
673   before_beginning_ = true;
674 }
675
676 XmppChatroomMember*
677 XmppChatroomMemberEnumeratorImpl::current() {
678   if (IsValid() == false) {
679     return NULL;
680   } else if (IsBeforeBeginning() || IsAfterEnd()) {
681     return NULL;
682   } else {
683     return iterator_->second;
684   }
685 }
686
687 bool
688 XmppChatroomMemberEnumeratorImpl::Prev() {
689   if (IsValid() == false) {
690     return false;
691   } else if (IsBeforeBeginning()) {
692     return false;
693   } else if (iterator_ == map_->begin()) {
694     before_beginning_ = true;
695     return false;
696   } else {
697     iterator_--;
698     return current() != NULL;
699   }
700 }
701
702 bool
703 XmppChatroomMemberEnumeratorImpl::Next() {
704   if (IsValid() == false) {
705     return false;
706   } else if (IsBeforeBeginning()) {
707     before_beginning_ = false;
708     iterator_ = map_->begin();
709     return current() != NULL;
710   } else if (IsAfterEnd()) {
711     return false;
712   } else {
713     iterator_++;
714     return current() != NULL;
715   }
716 }
717
718 bool
719 XmppChatroomMemberEnumeratorImpl::IsValid() {
720   return map_version_created_ == *map_version_;
721 }
722
723 bool
724 XmppChatroomMemberEnumeratorImpl::IsBeforeBeginning() {
725   return before_beginning_;
726 }
727
728 bool
729 XmppChatroomMemberEnumeratorImpl::IsAfterEnd() {
730   return (iterator_ == map_->end());
731 }
732
733
734
735 } // namespace buzz