1 /*
2 * libjingle
3 * Copyright 2004--2005, Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include <vector>
29 #include <string>
30 #include <map>
31 #include <algorithm>
32 #include <sstream>
33 #include <iostream>
34 #include "talk/base/common.h"
35 #include "talk/xmpp/constants.h"
36 #include "talk/xmpp/moduleimpl.h"
37 #include "talk/xmpp/chatroommodule.h"
38
39 namespace buzz {
40
41 // forward declarations
42 class XmppChatroomImpl;
43 class XmppChatroomMemberImpl;
44
45 //! Module that encapsulates multiple chatrooms.
46 //! Each chatroom is represented by an XmppChatroomImpl instance
47 class XmppChatroomModuleImpl : public XmppChatroomModule,
48 public XmppModuleImpl, public XmppIqHandler {
49 public:
50 IMPLEMENT_XMPPMODULE
51
52 // Creates a chatroom with specified Jid
53 XmppChatroomModuleImpl();
54 ~XmppChatroomModuleImpl();
55
56 // XmppChatroomModule
57 virtual XmppReturnStatus set_chatroom_handler(XmppChatroomHandler* handler);
58 virtual XmppChatroomHandler* chatroom_handler();
59 virtual XmppReturnStatus set_chatroom_jid(const Jid& chatroom_jid);
60 virtual const Jid& chatroom_jid() const;
61 virtual XmppReturnStatus set_nickname(const std::string& nickname);
62 virtual const std::string& nickname() const;
63 virtual const Jid member_jid() const;
64 virtual XmppReturnStatus RequestEnterChatroom(const std::string& password);
65 virtual XmppReturnStatus RequestExitChatroom();
66 virtual XmppReturnStatus RequestStatusChange(XmppPresenceShow status,
67 const std::string& extended_status);
68 virtual size_t GetChatroomMemberCount();
69 virtual XmppReturnStatus CreateMemberEnumerator(XmppChatroomMemberEnumerator** enumerator);
70 virtual const std::string& subject();
state()71 virtual XmppChatroomState state() { return chatroom_state_; }
72 virtual XmppReturnStatus SendMessage(const XmlElement& message);
73
74 // XmppModule
IqResponse(XmppIqCookie cookie,const XmlElement * pelStanza)75 virtual void IqResponse(XmppIqCookie cookie, const XmlElement * pelStanza) {UNUSED2(cookie, pelStanza);}
76 virtual bool HandleStanza(const XmlElement *);
77
78 private:
79 friend class XmppChatroomMemberEnumeratorImpl;
80
81 XmppReturnStatus ServerChangeMyPresence(const XmlElement& presence);
82 XmppReturnStatus ClientChangeMyPresence(XmppChatroomState new_state);
83 XmppReturnStatus ChangePresence(XmppChatroomState new_state, const XmlElement* presence, bool isServer);
84 XmppReturnStatus ServerChangedOtherPresence(const XmlElement& presence_element);
85 XmppChatroomEnteredStatus GetEnterFailureFromXml(const XmlElement* presence);
86 XmppChatroomExitedStatus GetExitFailureFromXml(const XmlElement* presence);
87
88 bool CheckEnterChatroomStateOk();
89
90 void FireEnteredStatus(XmppChatroomEnteredStatus status);
91 void FireExitStatus(XmppChatroomExitedStatus status);
92 void FireMessageReceived(const XmlElement& message);
93 void FireMemberEntered(const XmppChatroomMember* entered_member);
94 void FireMemberExited(const XmppChatroomMember* exited_member);
95
96 typedef std::map<Jid, XmppChatroomMemberImpl*> JidMemberMap;
97
98 XmppChatroomHandler* chatroom_handler_;
99 Jid chatroom_jid_;
100 std::string nickname_;
101 XmppChatroomState chatroom_state_;
102 JidMemberMap chatroom_jid_members_;
103 int chatroom_jid_members_version_;
104 };
105
106 class XmppChatroomMemberImpl : public XmppChatroomMember {
107 public:
~XmppChatroomMemberImpl()108 ~XmppChatroomMemberImpl() {}
109 XmppReturnStatus SetPresence(const XmppPresence* presence);
110
111 // XmppChatroomMember
112 const Jid member_jid() const;
113 const Jid full_jid() const;
114 const std::string name() const;
115 const XmppPresence* presence() const;
116
117 private:
118 talk_base::scoped_ptr<XmppPresence> presence_;
119 };
120
121 class XmppChatroomMemberEnumeratorImpl :
122 public XmppChatroomMemberEnumerator {
123 public:
124 XmppChatroomMemberEnumeratorImpl(XmppChatroomModuleImpl::JidMemberMap* chatroom_jid_members,
125 int* map_version);
126
127 // XmppChatroomMemberEnumerator
128 virtual XmppChatroomMember* current();
129 virtual bool Next();
130 virtual bool Prev();
131 virtual bool IsValid();
132 virtual bool IsBeforeBeginning();
133 virtual bool IsAfterEnd();
134
135 private:
136 XmppChatroomModuleImpl::JidMemberMap* map_;
137 int map_version_created_;
138 int* map_version_;
139 XmppChatroomModuleImpl::JidMemberMap::iterator iterator_;
140 bool before_beginning_;
141 };
142
143 // XmppChatroomModuleImpl ------------------------------------------------
144 XmppChatroomModule *
Create()145 XmppChatroomModule::Create() {
146 return new XmppChatroomModuleImpl();
147 }
148
XmppChatroomModuleImpl()149 XmppChatroomModuleImpl::XmppChatroomModuleImpl() :
150 chatroom_handler_(NULL),
151 chatroom_jid_(STR_EMPTY),
152 chatroom_state_(XMPP_CHATROOM_STATE_NOT_IN_ROOM),
153 chatroom_jid_members_version_(0) {
154 }
155
~XmppChatroomModuleImpl()156 XmppChatroomModuleImpl::~XmppChatroomModuleImpl() {
157 JidMemberMap::iterator iterator = chatroom_jid_members_.begin();
158 while (iterator != chatroom_jid_members_.end()) {
159 delete iterator->second;
160 iterator++;
161 }
162 }
163
164 bool
HandleStanza(const XmlElement * stanza)165 XmppChatroomModuleImpl::HandleStanza(const XmlElement* stanza) {
166 ASSERT(engine() != NULL);
167
168 // we handle stanzas that are for one of our chatrooms
169 Jid from_jid = Jid(stanza->Attr(QN_FROM));
170 // see if it's one of our chatrooms
171 if (chatroom_jid_ != from_jid.BareJid()) {
172 return false; // not one of our chatrooms
173 } else {
174 // handle presence stanza
175 if (stanza->Name() == QN_PRESENCE) {
176 if (from_jid == member_jid()) {
177 ServerChangeMyPresence(*stanza);
178 } else {
179 ServerChangedOtherPresence(*stanza);
180 }
181 } else if (stanza->Name() == QN_MESSAGE) {
182 FireMessageReceived(*stanza);
183 }
184 return true;
185 }
186 }
187
188 XmppReturnStatus
set_chatroom_handler(XmppChatroomHandler * handler)189 XmppChatroomModuleImpl::set_chatroom_handler(XmppChatroomHandler* handler) {
190 // Calling with NULL removes the handler.
191 chatroom_handler_ = handler;
192 return XMPP_RETURN_OK;
193 }
194
195 XmppChatroomHandler*
chatroom_handler()196 XmppChatroomModuleImpl::chatroom_handler() {
197 return chatroom_handler_;
198 }
199
200 XmppReturnStatus
set_chatroom_jid(const Jid & chatroom_jid)201 XmppChatroomModuleImpl::set_chatroom_jid(const Jid& chatroom_jid) {
202 if (chatroom_state_ != XMPP_CHATROOM_STATE_NOT_IN_ROOM) {
203 return XMPP_RETURN_BADSTATE; // $TODO - this isn't a bad state, it's a bad call, diff error code?
204 }
205 if (chatroom_jid != chatroom_jid.BareJid()) {
206 // chatroom_jid must be a bare jid
207 return XMPP_RETURN_BADARGUMENT;
208 }
209
210 chatroom_jid_ = chatroom_jid;
211 return XMPP_RETURN_OK;
212 }
213
214 const Jid&
chatroom_jid() const215 XmppChatroomModuleImpl::chatroom_jid() const {
216 return chatroom_jid_;
217 }
218
219 XmppReturnStatus
set_nickname(const std::string & nickname)220 XmppChatroomModuleImpl::set_nickname(const std::string& nickname) {
221 if (chatroom_state_ != XMPP_CHATROOM_STATE_NOT_IN_ROOM) {
222 return XMPP_RETURN_BADSTATE; // $TODO - this isn't a bad state, it's a bad call, diff error code?
223 }
224 nickname_ = nickname;
225 return XMPP_RETURN_OK;
226 }
227
228 const std::string&
nickname() const229 XmppChatroomModuleImpl::nickname() const {
230 return nickname_;
231 }
232
233 const Jid
member_jid() const234 XmppChatroomModuleImpl::member_jid() const {
235 return Jid(chatroom_jid_.node(), chatroom_jid_.domain(), nickname_);
236 }
237
238 bool
CheckEnterChatroomStateOk()239 XmppChatroomModuleImpl::CheckEnterChatroomStateOk() {
240 if (chatroom_jid_.IsValid() == false) {
241 ASSERT(0);
242 return false;
243 }
244 if (nickname_ == STR_EMPTY) {
245 ASSERT(0);
246 return false;
247 }
248 return true;
249 }
250
251 XmppReturnStatus
RequestEnterChatroom(const std::string & password)252 XmppChatroomModuleImpl::RequestEnterChatroom(const std::string& password) {
253 UNUSED(password);
254 if (!engine())
255 return XMPP_RETURN_BADSTATE;
256
257 if (chatroom_state_ != XMPP_CHATROOM_STATE_NOT_IN_ROOM)
258 return XMPP_RETURN_BADSTATE; // $TODO - this isn't a bad state, it's a bad call, diff error code?
259
260 if (CheckEnterChatroomStateOk() == false) {
261 return XMPP_RETURN_BADSTATE;
262 }
263
264 // entering a chatroom is a presence request to the server
265 XmlElement element(QN_PRESENCE);
266 element.AddAttr(QN_TO, member_jid().Str());
267 element.AddElement(new XmlElement(QN_MUC_X));
268 XmppReturnStatus status = engine()->SendStanza(&element);
269 if (status == XMPP_RETURN_OK) {
270 return ClientChangeMyPresence(XMPP_CHATROOM_STATE_REQUESTED_ENTER);
271 }
272 return status;
273 }
274
275 XmppReturnStatus
RequestExitChatroom()276 XmppChatroomModuleImpl::RequestExitChatroom() {
277 if (!engine())
278 return XMPP_RETURN_BADSTATE;
279
280 // currently, can't leave a room unless you've entered
281 // no way to cancel a pending enter call - is that bad?
282 if (chatroom_state_ != XMPP_CHATROOM_STATE_IN_ROOM)
283 return XMPP_RETURN_BADSTATE; // $TODO - this isn't a bad state, it's a bad call, diff error code?
284
285 // exiting a chatroom is a presence request to the server
286 XmlElement element(QN_PRESENCE);
287 element.AddAttr(QN_TO, member_jid().Str());
288 element.AddAttr(QN_TYPE, "unavailable");
289 XmppReturnStatus status = engine()->SendStanza(&element);
290 if (status == XMPP_RETURN_OK) {
291 return ClientChangeMyPresence(XMPP_CHATROOM_STATE_REQUESTED_EXIT);
292 }
293 return status;
294 }
295
296 XmppReturnStatus
RequestStatusChange(XmppPresenceShow status,const std::string & extended_status)297 XmppChatroomModuleImpl::RequestStatusChange(XmppPresenceShow status,
298 const std::string& extended_status) {
299 UNUSED2(status, extended_status);
300 return XMPP_RETURN_BADSTATE; //NYI
301 }
302
303 size_t
GetChatroomMemberCount()304 XmppChatroomModuleImpl::GetChatroomMemberCount() {
305 return chatroom_jid_members_.size();
306 }
307
308 XmppReturnStatus
CreateMemberEnumerator(XmppChatroomMemberEnumerator ** enumerator)309 XmppChatroomModuleImpl::CreateMemberEnumerator(XmppChatroomMemberEnumerator** enumerator) {
310 *enumerator = new XmppChatroomMemberEnumeratorImpl(&chatroom_jid_members_, &chatroom_jid_members_version_);
311 return XMPP_RETURN_OK;
312 }
313
314 const std::string&
subject()315 XmppChatroomModuleImpl::subject() {
316 return STR_EMPTY; //NYI
317 }
318
319 XmppReturnStatus
SendMessage(const XmlElement & message)320 XmppChatroomModuleImpl::SendMessage(const XmlElement& message) {
321 XmppReturnStatus xmpp_status = XMPP_RETURN_OK;
322
323 // can only send a message if we're in the room
324 if (chatroom_state_ != XMPP_CHATROOM_STATE_IN_ROOM) {
325 return XMPP_RETURN_BADSTATE; // $TODO - this isn't a bad state, it's a bad call, diff error code?
326 }
327
328 if (message.Name() != QN_MESSAGE) {
329 IFR(XMPP_RETURN_BADARGUMENT);
330 }
331
332 const std::string& type = message.Attr(QN_TYPE);
333 if (type != "groupchat") {
334 IFR(XMPP_RETURN_BADARGUMENT);
335 }
336
337 if (message.HasAttr(QN_FROM)) {
338 IFR(XMPP_RETURN_BADARGUMENT);
339 }
340
341 if (message.Attr(QN_TO) != chatroom_jid_.Str()) {
342 IFR(XMPP_RETURN_BADARGUMENT);
343 }
344
345 IFR(engine()->SendStanza(&message));
346
347 return xmpp_status;
348 }
349
350 enum TransitionType {
351 TRANSITION_TYPE_NONE = 0,
352 TRANSITION_TYPE_ENTER_SUCCESS = 1,
353 TRANSITION_TYPE_ENTER_FAILURE = 2,
354 TRANSITION_TYPE_EXIT_VOLUNTARILY = 3,
355 TRANSITION_TYPE_EXIT_INVOLUNTARILY = 4,
356 };
357
358 struct StateTransitionDescription {
359 XmppChatroomState old_state;
360 XmppChatroomState new_state;
361 bool is_valid_server_transition;
362 bool is_valid_client_transition;
363 TransitionType transition_type;
364 };
365
366 StateTransitionDescription Transitions[] = {
367 { XMPP_CHATROOM_STATE_NOT_IN_ROOM, XMPP_CHATROOM_STATE_REQUESTED_ENTER, false, true, TRANSITION_TYPE_NONE, },
368 { XMPP_CHATROOM_STATE_NOT_IN_ROOM, XMPP_CHATROOM_STATE_IN_ROOM, false, false, TRANSITION_TYPE_ENTER_SUCCESS, },
369 { XMPP_CHATROOM_STATE_NOT_IN_ROOM, XMPP_CHATROOM_STATE_REQUESTED_EXIT, false, false, TRANSITION_TYPE_NONE, },
370 { XMPP_CHATROOM_STATE_REQUESTED_ENTER, XMPP_CHATROOM_STATE_NOT_IN_ROOM, true, false, TRANSITION_TYPE_ENTER_FAILURE, },
371 { XMPP_CHATROOM_STATE_REQUESTED_ENTER, XMPP_CHATROOM_STATE_IN_ROOM, true, false, TRANSITION_TYPE_ENTER_SUCCESS, },
372 { XMPP_CHATROOM_STATE_REQUESTED_ENTER, XMPP_CHATROOM_STATE_REQUESTED_EXIT, false, false, TRANSITION_TYPE_NONE, },
373 { XMPP_CHATROOM_STATE_IN_ROOM, XMPP_CHATROOM_STATE_NOT_IN_ROOM, true, false, TRANSITION_TYPE_EXIT_INVOLUNTARILY, },
374 { XMPP_CHATROOM_STATE_IN_ROOM, XMPP_CHATROOM_STATE_REQUESTED_ENTER, false, false, TRANSITION_TYPE_NONE, },
375 { XMPP_CHATROOM_STATE_IN_ROOM, XMPP_CHATROOM_STATE_REQUESTED_EXIT, false, true, TRANSITION_TYPE_NONE, },
376 { XMPP_CHATROOM_STATE_REQUESTED_EXIT, XMPP_CHATROOM_STATE_NOT_IN_ROOM, true, false, TRANSITION_TYPE_EXIT_VOLUNTARILY, },
377 { XMPP_CHATROOM_STATE_REQUESTED_EXIT, XMPP_CHATROOM_STATE_REQUESTED_ENTER, false, false, TRANSITION_TYPE_NONE, },
378 { XMPP_CHATROOM_STATE_REQUESTED_EXIT, XMPP_CHATROOM_STATE_IN_ROOM, false, false, TRANSITION_TYPE_NONE, },
379 };
380
381 void
FireEnteredStatus(XmppChatroomEnteredStatus status)382 XmppChatroomModuleImpl::FireEnteredStatus(XmppChatroomEnteredStatus status) {
383 if (chatroom_handler_)
384 chatroom_handler_->ChatroomEnteredStatus(this, status);
385 }
386
387 void
FireExitStatus(XmppChatroomExitedStatus status)388 XmppChatroomModuleImpl::FireExitStatus(XmppChatroomExitedStatus status) {
389 if (chatroom_handler_)
390 chatroom_handler_->ChatroomExitedStatus(this, status);
391 }
392
393 void
FireMessageReceived(const XmlElement & message)394 XmppChatroomModuleImpl::FireMessageReceived(const XmlElement& message) {
395 if (chatroom_handler_)
396 chatroom_handler_->MessageReceived(this, message);
397 }
398
399 void
FireMemberEntered(const XmppChatroomMember * entered_member)400 XmppChatroomModuleImpl::FireMemberEntered(const XmppChatroomMember* entered_member) {
401 // only fire if we're in the room
402 if (chatroom_state_ == XMPP_CHATROOM_STATE_IN_ROOM) {
403 if (chatroom_handler_)
404 chatroom_handler_->MemberEntered(this, entered_member);
405 }
406 }
407
408 void
FireMemberExited(const XmppChatroomMember * exited_member)409 XmppChatroomModuleImpl::FireMemberExited(const XmppChatroomMember* exited_member) {
410 // only fire if we're in the room
411 if (chatroom_state_ == XMPP_CHATROOM_STATE_IN_ROOM) {
412 if (chatroom_handler_)
413 chatroom_handler_->MemberExited(this, exited_member);
414 }
415 }
416
417 XmppReturnStatus
ServerChangedOtherPresence(const XmlElement & presence_element)418 XmppChatroomModuleImpl::ServerChangedOtherPresence(const XmlElement&
419 presence_element) {
420 XmppReturnStatus xmpp_status = XMPP_RETURN_OK;
421 talk_base::scoped_ptr<XmppPresence> presence(XmppPresence::Create());
422 IFR(presence->set_raw_xml(&presence_element));
423
424 JidMemberMap::iterator pos = chatroom_jid_members_.find(presence->jid());
425
426 if (pos == chatroom_jid_members_.end()) {
427 if (presence->available() == XMPP_PRESENCE_AVAILABLE) {
428 XmppChatroomMemberImpl* member = new XmppChatroomMemberImpl();
429 member->SetPresence(presence.get());
430 chatroom_jid_members_.insert(std::make_pair(member->member_jid(), member));
431 chatroom_jid_members_version_++;
432 FireMemberEntered(member);
433 }
434 } else {
435 XmppChatroomMemberImpl* member = pos->second;
436 if (presence->available() == XMPP_PRESENCE_AVAILABLE) {
437 member->SetPresence(presence.get());
438 chatroom_jid_members_version_++;
439 // $TODO - fire change
440 }
441 else if (presence->available() == XMPP_PRESENCE_UNAVAILABLE) {
442 chatroom_jid_members_.erase(pos);
443 chatroom_jid_members_version_++;
444 FireMemberExited(member);
445 delete member;
446 }
447 }
448
449 return xmpp_status;
450 }
451
452 XmppReturnStatus
ClientChangeMyPresence(XmppChatroomState new_state)453 XmppChatroomModuleImpl::ClientChangeMyPresence(XmppChatroomState new_state) {
454 return ChangePresence(new_state, NULL, false);
455 }
456
457 XmppReturnStatus
ServerChangeMyPresence(const XmlElement & presence)458 XmppChatroomModuleImpl::ServerChangeMyPresence(const XmlElement& presence) {
459 XmppChatroomState new_state;
460
461 if (presence.HasAttr(QN_TYPE) == false) {
462 new_state = XMPP_CHATROOM_STATE_IN_ROOM;
463 } else {
464 new_state = XMPP_CHATROOM_STATE_NOT_IN_ROOM;
465 }
466 return ChangePresence(new_state, &presence, true);
467
468 }
469
470 XmppReturnStatus
ChangePresence(XmppChatroomState new_state,const XmlElement * presence,bool isServer)471 XmppChatroomModuleImpl::ChangePresence(XmppChatroomState new_state,
472 const XmlElement* presence,
473 bool isServer) {
474 UNUSED(presence);
475
476 XmppChatroomState old_state = chatroom_state_;
477
478 // do nothing if state hasn't changed
479 if (old_state == new_state)
480 return XMPP_RETURN_OK;
481
482 // find the right transition description
483 StateTransitionDescription* transition_desc = NULL;
484 for (int i=0; i < ARRAY_SIZE(Transitions); i++) {
485 if (Transitions[i].old_state == old_state &&
486 Transitions[i].new_state == new_state) {
487 transition_desc = &Transitions[i];
488 break;
489 }
490 }
491
492 if (transition_desc == NULL) {
493 ASSERT(0);
494 return XMPP_RETURN_BADSTATE;
495 }
496
497 // we assert for any invalid transition states, and we'll
498 if (isServer) {
499 // $TODO send original stanza back to server and log an error?
500 ASSERT(transition_desc->is_valid_server_transition);
501 } else {
502 if (transition_desc->is_valid_client_transition == false) {
503 ASSERT(0);
504 return XMPP_RETURN_BADARGUMENT;
505 }
506 }
507
508 // set the new state and then fire any notifications to the handler
509 chatroom_state_ = new_state;
510
511 switch (transition_desc->transition_type) {
512 case TRANSITION_TYPE_ENTER_SUCCESS:
513 FireEnteredStatus(XMPP_CHATROOM_ENTERED_SUCCESS);
514 break;
515 case TRANSITION_TYPE_ENTER_FAILURE:
516 FireEnteredStatus(GetEnterFailureFromXml(presence));
517 break;
518 case TRANSITION_TYPE_EXIT_INVOLUNTARILY:
519 FireExitStatus(GetExitFailureFromXml(presence));
520 break;
521 case TRANSITION_TYPE_EXIT_VOLUNTARILY:
522 FireExitStatus(XMPP_CHATROOM_EXITED_REQUESTED);
523 break;
524 case TRANSITION_TYPE_NONE:
525 break;
526 }
527
528 return XMPP_RETURN_OK;
529 }
530
531 XmppChatroomEnteredStatus
GetEnterFailureFromXml(const XmlElement * presence)532 XmppChatroomModuleImpl::GetEnterFailureFromXml(const XmlElement* presence) {
533 XmppChatroomEnteredStatus status = XMPP_CHATROOM_ENTERED_FAILURE_UNSPECIFIED;
534 const XmlElement* error = presence->FirstNamed(QN_ERROR);
535 if (error != NULL && error->HasAttr(QN_CODE)) {
536 int code = atoi(error->Attr(QN_CODE).c_str());
537 switch (code) {
538 case 401: status = XMPP_CHATROOM_ENTERED_FAILURE_PASSWORD_REQUIRED; break;
539 case 403: status = XMPP_CHATROOM_ENTERED_FAILURE_MEMBER_BANNED; break;
540 case 405: status = XMPP_CHATROOM_ENTERED_FAILURE_MAX_USERS; break;
541 case 407: status = XMPP_CHATROOM_ENTERED_FAILURE_NOT_A_MEMBER; break;
542 case 409: status = XMPP_CHATROOM_ENTERED_FAILURE_NICKNAME_CONFLICT; break;
543 }
544 }
545 return status;
546 }
547
548 XmppChatroomExitedStatus
GetExitFailureFromXml(const XmlElement * presence)549 XmppChatroomModuleImpl::GetExitFailureFromXml(const XmlElement* presence) {
550 XmppChatroomExitedStatus status = XMPP_CHATROOM_EXITED_UNSPECIFIED;
551 const XmlElement* error = presence->FirstNamed(QN_ERROR);
552 if (error != NULL && error->HasAttr(QN_CODE)) {
553 int code = atoi(error->Attr(QN_CODE).c_str());
554 switch (code) {
555 case 307: status = XMPP_CHATROOM_EXITED_KICKED; break;
556 case 322: status = XMPP_CHATROOM_EXITED_NOT_A_MEMBER; break;
557 case 332: status = XMPP_CHATROOM_EXITED_SYSTEM_SHUTDOWN; break;
558 }
559 }
560 return status;
561 }
562
563 XmppReturnStatus
SetPresence(const XmppPresence * presence)564 XmppChatroomMemberImpl::SetPresence(const XmppPresence* presence) {
565 ASSERT(presence != NULL);
566
567 // copy presence
568 presence_.reset(XmppPresence::Create());
569 presence_->set_raw_xml(presence->raw_xml());
570 return XMPP_RETURN_OK;
571 }
572
573 const Jid
member_jid() const574 XmppChatroomMemberImpl::member_jid() const {
575 return presence_->jid();
576 }
577
578 const Jid
full_jid() const579 XmppChatroomMemberImpl::full_jid() const {
580 return Jid("");
581 }
582
583 const std::string
name() const584 XmppChatroomMemberImpl::name() const {
585 return member_jid().resource();
586 }
587
588 const XmppPresence*
presence() const589 XmppChatroomMemberImpl::presence() const {
590 return presence_.get();
591 }
592
593 // XmppChatroomMemberEnumeratorImpl --------------------------------------
XmppChatroomMemberEnumeratorImpl(XmppChatroomModuleImpl::JidMemberMap * map,int * map_version)594 XmppChatroomMemberEnumeratorImpl::XmppChatroomMemberEnumeratorImpl(
595 XmppChatroomModuleImpl::JidMemberMap* map, int* map_version) {
596 map_ = map;
597 map_version_ = map_version;
598 map_version_created_ = *map_version_;
599 iterator_ = map->begin();
600 before_beginning_ = true;
601 }
602
603 XmppChatroomMember*
current()604 XmppChatroomMemberEnumeratorImpl::current() {
605 if (IsValid() == false) {
606 return NULL;
607 } else if (IsBeforeBeginning() || IsAfterEnd()) {
608 return NULL;
609 } else {
610 return iterator_->second;
611 }
612 }
613
614 bool
Prev()615 XmppChatroomMemberEnumeratorImpl::Prev() {
616 if (IsValid() == false) {
617 return false;
618 } else if (IsBeforeBeginning()) {
619 return false;
620 } else if (iterator_ == map_->begin()) {
621 before_beginning_ = true;
622 return false;
623 } else {
624 iterator_--;
625 return current() != NULL;
626 }
627 }
628
629 bool
Next()630 XmppChatroomMemberEnumeratorImpl::Next() {
631 if (IsValid() == false) {
632 return false;
633 } else if (IsBeforeBeginning()) {
634 before_beginning_ = false;
635 iterator_ = map_->begin();
636 return current() != NULL;
637 } else if (IsAfterEnd()) {
638 return false;
639 } else {
640 iterator_++;
641 return current() != NULL;
642 }
643 }
644
645 bool
IsValid()646 XmppChatroomMemberEnumeratorImpl::IsValid() {
647 return map_version_created_ == *map_version_;
648 }
649
650 bool
IsBeforeBeginning()651 XmppChatroomMemberEnumeratorImpl::IsBeforeBeginning() {
652 return before_beginning_;
653 }
654
655 bool
IsAfterEnd()656 XmppChatroomMemberEnumeratorImpl::IsAfterEnd() {
657 return (iterator_ == map_->end());
658 }
659
660 } // namespace buzz
661