2 * Copyright 2004 The WebRTC Project Authors. All rights reserved.
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.
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"
24 // forward declarations
25 class XmppChatroomImpl;
26 class XmppChatroomMemberImpl;
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 {
35 // Creates a chatroom with specified Jid
36 XmppChatroomModuleImpl();
37 ~XmppChatroomModuleImpl();
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);
60 virtual void IqResponse(XmppIqCookie cookie, const XmlElement * pelStanza) {RTC_UNUSED2(cookie, pelStanza);}
61 virtual bool HandleStanza(const XmlElement *);
64 friend class XmppChatroomMemberEnumeratorImpl;
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);
73 bool CheckEnterChatroomStateOk();
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);
84 typedef std::map<Jid, XmppChatroomMemberImpl*> JidMemberMap;
86 XmppChatroomHandler* chatroom_handler_;
88 std::string nickname_;
89 XmppChatroomState chatroom_state_;
90 JidMemberMap chatroom_jid_members_;
91 int chatroom_jid_members_version_;
95 class XmppChatroomMemberImpl : public XmppChatroomMember {
97 ~XmppChatroomMemberImpl() {}
98 XmppReturnStatus SetPresence(const XmppPresence* presence);
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;
107 rtc::scoped_ptr<XmppPresence> presence_;
110 class XmppChatroomMemberEnumeratorImpl :
111 public XmppChatroomMemberEnumerator {
113 XmppChatroomMemberEnumeratorImpl(XmppChatroomModuleImpl::JidMemberMap* chatroom_jid_members,
116 // XmppChatroomMemberEnumerator
117 virtual XmppChatroomMember* current();
120 virtual bool IsValid();
121 virtual bool IsBeforeBeginning();
122 virtual bool IsAfterEnd();
125 XmppChatroomModuleImpl::JidMemberMap* map_;
126 int map_version_created_;
128 XmppChatroomModuleImpl::JidMemberMap::iterator iterator_;
129 bool before_beginning_;
133 // XmppChatroomModuleImpl ------------------------------------------------
135 XmppChatroomModule::Create() {
136 return new XmppChatroomModuleImpl();
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) {
146 XmppChatroomModuleImpl::~XmppChatroomModuleImpl() {
147 JidMemberMap::iterator iterator = chatroom_jid_members_.begin();
148 while (iterator != chatroom_jid_members_.end()) {
149 delete iterator->second;
156 XmppChatroomModuleImpl::HandleStanza(const XmlElement* stanza) {
157 ASSERT(engine() != NULL);
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
165 // handle presence stanza
166 if (stanza->Name() == QN_PRESENCE) {
167 if (from_jid == member_jid()) {
168 ServerChangeMyPresence(*stanza);
170 ServerChangedOtherPresence(*stanza);
172 } else if (stanza->Name() == QN_MESSAGE) {
173 FireMessageReceived(*stanza);
181 XmppChatroomModuleImpl::set_chatroom_handler(XmppChatroomHandler* handler) {
182 // Calling with NULL removes the handler.
183 chatroom_handler_ = handler;
184 return XMPP_RETURN_OK;
189 XmppChatroomModuleImpl::chatroom_handler() {
190 return chatroom_handler_;
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?
198 if (chatroom_jid != chatroom_jid.BareJid()) {
199 // chatroom_jid must be a bare jid
200 return XMPP_RETURN_BADARGUMENT;
203 chatroom_jid_ = chatroom_jid;
204 return XMPP_RETURN_OK;
208 XmppChatroomModuleImpl::chatroom_jid() const {
209 return chatroom_jid_;
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?
217 nickname_ = nickname;
218 return XMPP_RETURN_OK;
222 XmppChatroomModuleImpl::nickname() const {
227 XmppChatroomModuleImpl::member_jid() const {
228 return Jid(chatroom_jid_.node(), chatroom_jid_.domain(), nickname_);
233 XmppChatroomModuleImpl::CheckEnterChatroomStateOk() {
234 if (chatroom_jid_.IsValid() == false) {
238 if (nickname_ == STR_EMPTY) {
245 std::string GetAttrValueFor(XmppPresenceConnectionStatus connection_status) {
246 switch (connection_status) {
248 case XMPP_CONNECTION_STATUS_UNKNOWN:
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;
258 XmppChatroomModuleImpl::RequestEnterChatroom(
259 const std::string& password,
260 const std::string& client_version,
261 const std::string& locale) {
262 RTC_UNUSED(password);
264 return XMPP_RETURN_BADSTATE;
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?
269 if (CheckEnterChatroomStateOk() == false) {
270 return XMPP_RETURN_BADSTATE;
273 // entering a chatroom is a presence request to the server
274 XmlElement element(QN_PRESENCE);
275 element.AddAttr(QN_TO, member_jid().Str());
277 XmlElement* muc_x = new XmlElement(QN_MUC_X);
278 element.AddElement(muc_x);
280 if (!client_version.empty()) {
281 XmlElement* client_version_element = new XmlElement(QN_CLIENT_VERSION,
283 client_version_element->SetBodyText(client_version);
284 muc_x->AddElement(client_version_element);
287 if (!locale.empty()) {
288 XmlElement* locale_element = new XmlElement(QN_LOCALE, false);
290 locale_element->SetBodyText(locale);
291 muc_x->AddElement(locale_element);
294 XmppReturnStatus status = engine()->SendStanza(&element);
295 if (status == XMPP_RETURN_OK) {
296 return ClientChangeMyPresence(XMPP_CHATROOM_STATE_REQUESTED_ENTER);
302 XmppChatroomModuleImpl::RequestExitChatroom() {
304 return XMPP_RETURN_BADSTATE;
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);
319 XmppChatroomModuleImpl::RequestConnectionStatusChange(
320 XmppPresenceConnectionStatus connection_status) {
322 return XMPP_RETURN_BADSTATE;
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;
329 if (CheckEnterChatroomStateOk() == false) {
330 return XMPP_RETURN_BADSTATE;
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);
343 XmppReturnStatus status = engine()->SendStanza(&element);
349 XmppChatroomModuleImpl::GetChatroomMemberCount() {
350 return chatroom_jid_members_.size();
354 XmppChatroomModuleImpl::CreateMemberEnumerator(XmppChatroomMemberEnumerator** enumerator) {
355 *enumerator = new XmppChatroomMemberEnumeratorImpl(&chatroom_jid_members_, &chatroom_jid_members_version_);
356 return XMPP_RETURN_OK;
360 XmppChatroomModuleImpl::subject() {
365 XmppChatroomModuleImpl::SendMessage(const XmlElement& message) {
366 XmppReturnStatus xmpp_status = XMPP_RETURN_OK;
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?
373 if (message.Name() != QN_MESSAGE) {
374 IFR(XMPP_RETURN_BADARGUMENT);
377 const std::string& type = message.Attr(QN_TYPE);
378 if (type != "groupchat") {
379 IFR(XMPP_RETURN_BADARGUMENT);
382 if (message.HasAttr(QN_FROM)) {
383 IFR(XMPP_RETURN_BADARGUMENT);
386 if (message.Attr(QN_TO) != chatroom_jid_.Str()) {
387 IFR(XMPP_RETURN_BADARGUMENT);
390 IFR(engine()->SendStanza(&message));
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,
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;
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, },
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);
439 XmppChatroomModuleImpl::FireExitStatus(XmppChatroomExitedStatus status) {
440 if (chatroom_handler_)
441 chatroom_handler_->ChatroomExitedStatus(this, status);
445 XmppChatroomModuleImpl::FireMessageReceived(const XmlElement& message) {
446 if (chatroom_handler_)
447 chatroom_handler_->MessageReceived(this, message);
451 XmppChatroomModuleImpl::FireMemberEntered(const XmppChatroomMember* entered_member) {
452 if (chatroom_handler_)
453 chatroom_handler_->MemberEntered(this, entered_member);
457 XmppChatroomModuleImpl::FireMemberChanged(
458 const XmppChatroomMember* changed_member) {
459 if (chatroom_handler_)
460 chatroom_handler_->MemberChanged(this, changed_member);
464 XmppChatroomModuleImpl::FireMemberExited(const XmppChatroomMember* exited_member) {
465 if (chatroom_handler_)
466 chatroom_handler_->MemberExited(this, exited_member);
471 XmppChatroomModuleImpl::ServerChangedOtherPresence(const XmlElement&
473 XmppReturnStatus xmpp_status = XMPP_RETURN_OK;
474 rtc::scoped_ptr<XmppPresence> presence(XmppPresence::Create());
475 IFR(presence->set_raw_xml(&presence_element));
477 JidMemberMap::iterator pos = chatroom_jid_members_.find(presence->jid());
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);
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);
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);
507 XmppChatroomModuleImpl::ClientChangeMyPresence(XmppChatroomState new_state) {
508 return ChangePresence(new_state, NULL, false);
512 XmppChatroomModuleImpl::ServerChangeMyPresence(const XmlElement& presence) {
513 XmppChatroomState new_state;
515 if (presence.HasAttr(QN_TYPE) == false) {
516 new_state = XMPP_CHATROOM_STATE_IN_ROOM;
518 new_state = XMPP_CHATROOM_STATE_NOT_IN_ROOM;
520 return ChangePresence(new_state, &presence, true);
525 XmppChatroomModuleImpl::ChangePresence(XmppChatroomState new_state,
526 const XmlElement* presence,
528 RTC_UNUSED(presence);
530 XmppChatroomState old_state = chatroom_state_;
532 // do nothing if state hasn't changed
533 if (old_state == new_state)
534 return XMPP_RETURN_OK;
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];
546 if (transition_desc == NULL) {
548 return XMPP_RETURN_BADSTATE;
551 // we assert for any invalid transition states, and we'll
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;
560 if (transition_desc->is_valid_client_transition == false) {
562 return XMPP_RETURN_BADARGUMENT;
566 // set the new state and then fire any notifications to the handler
567 chatroom_state_ = new_state;
569 switch (transition_desc->transition_type) {
570 case TRANSITION_TYPE_ENTER_SUCCESS:
571 FireEnteredStatus(presence, XMPP_CHATROOM_ENTERED_SUCCESS);
573 case TRANSITION_TYPE_ENTER_FAILURE:
574 FireEnteredStatus(presence, GetEnterFailureFromXml(presence));
576 case TRANSITION_TYPE_EXIT_INVOLUNTARILY:
577 FireExitStatus(GetExitFailureFromXml(presence));
579 case TRANSITION_TYPE_EXIT_VOLUNTARILY:
580 FireExitStatus(XMPP_CHATROOM_EXITED_REQUESTED);
582 case TRANSITION_TYPE_NONE:
586 return XMPP_RETURN_OK;
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());
596 case 401: status = XMPP_CHATROOM_ENTERED_FAILURE_PASSWORD_REQUIRED; break;
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;
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;
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());
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;
636 XmppChatroomMemberImpl::SetPresence(const XmppPresence* presence) {
637 ASSERT(presence != NULL);
640 presence_.reset(XmppPresence::Create());
641 presence_->set_raw_xml(presence->raw_xml());
642 return XMPP_RETURN_OK;
646 XmppChatroomMemberImpl::member_jid() const {
647 return presence_->jid();
651 XmppChatroomMemberImpl::full_jid() const {
656 XmppChatroomMemberImpl::name() const {
657 return member_jid().resource();
661 XmppChatroomMemberImpl::presence() const {
662 return presence_.get();
666 // XmppChatroomMemberEnumeratorImpl --------------------------------------
667 XmppChatroomMemberEnumeratorImpl::XmppChatroomMemberEnumeratorImpl(
668 XmppChatroomModuleImpl::JidMemberMap* map, int* map_version) {
670 map_version_ = map_version;
671 map_version_created_ = *map_version_;
672 iterator_ = map->begin();
673 before_beginning_ = true;
677 XmppChatroomMemberEnumeratorImpl::current() {
678 if (IsValid() == false) {
680 } else if (IsBeforeBeginning() || IsAfterEnd()) {
683 return iterator_->second;
688 XmppChatroomMemberEnumeratorImpl::Prev() {
689 if (IsValid() == false) {
691 } else if (IsBeforeBeginning()) {
693 } else if (iterator_ == map_->begin()) {
694 before_beginning_ = true;
698 return current() != NULL;
703 XmppChatroomMemberEnumeratorImpl::Next() {
704 if (IsValid() == false) {
706 } else if (IsBeforeBeginning()) {
707 before_beginning_ = false;
708 iterator_ = map_->begin();
709 return current() != NULL;
710 } else if (IsAfterEnd()) {
714 return current() != NULL;
719 XmppChatroomMemberEnumeratorImpl::IsValid() {
720 return map_version_created_ == *map_version_;
724 XmppChatroomMemberEnumeratorImpl::IsBeforeBeginning() {
725 return before_beginning_;
729 XmppChatroomMemberEnumeratorImpl::IsAfterEnd() {
730 return (iterator_ == map_->end());