aboutsummaryrefslogtreecommitdiff
path: root/webrtc/libjingle/xmpp/chatroommoduleimpl.cc
diff options
context:
space:
mode:
authorChih-hung Hsieh <chh@google.com>2015-12-01 17:07:48 +0000
committerandroid-build-merger <android-build-merger@google.com>2015-12-01 17:07:48 +0000
commita4acd9d6bc9b3b033d7d274316e75ee067df8d20 (patch)
tree672a185b294789cf991f385c3e395dd63bea9063 /webrtc/libjingle/xmpp/chatroommoduleimpl.cc
parent3681b90ba4fe7a27232dd3e27897d5d7ed9d651c (diff)
parentfe8b4a657979b49e1701bd92f6d5814a99e0b2be (diff)
downloadwebrtc-a4acd9d6bc9b3b033d7d274316e75ee067df8d20.tar.gz
Merge changes I7bbf776e,I1b827825
am: fe8b4a6579 * commit 'fe8b4a657979b49e1701bd92f6d5814a99e0b2be': (7237 commits) WIP: Changes after merge commit 'cb3f9bd' Make the nonlinear beamformer steerable Utilize bitrate above codec max to protect video. Enable VP9 internal resize by default. Filter overlapping RTP header extensions. Make VCMEncodedFrameCallback const. MediaCodecVideoEncoder: Add number of quality resolution downscales to Encoded callback. Remove redudant encoder rate calls. Create isolate files for nonparallel tests. Register header extensions in RtpRtcpObserver to avoid log spam. Make an enum class out of NetEqDecoder, and hide the neteq_decoders_ table ACM: Move NACK functionality inside NetEq Fix chromium-style warnings in webrtc/sound/. Create a 'webrtc_nonparallel_tests' target. Update scalability structure data according to updates in the RTP payload profile. audio_coding: rename interface -> include Rewrote perform_action_on_all_files to be parallell. Update reference indices according to updates in the RTP payload profile. Disable P2PTransport...TestFailoverControlledSide on Memcheck pass clangcl compile options to ignore warnings in gflags.cc ...
Diffstat (limited to 'webrtc/libjingle/xmpp/chatroommoduleimpl.cc')
-rw-r--r--webrtc/libjingle/xmpp/chatroommoduleimpl.cc735
1 files changed, 735 insertions, 0 deletions
diff --git a/webrtc/libjingle/xmpp/chatroommoduleimpl.cc b/webrtc/libjingle/xmpp/chatroommoduleimpl.cc
new file mode 100644
index 0000000000..546aa75f92
--- /dev/null
+++ b/webrtc/libjingle/xmpp/chatroommoduleimpl.cc
@@ -0,0 +1,735 @@
+/*
+ * Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <algorithm>
+#include <iostream>
+#include <map>
+#include <sstream>
+#include <string>
+#include <vector>
+#include "webrtc/libjingle/xmpp/chatroommodule.h"
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/libjingle/xmpp/moduleimpl.h"
+#include "webrtc/base/common.h"
+
+namespace buzz {
+
+// forward declarations
+class XmppChatroomImpl;
+class XmppChatroomMemberImpl;
+
+//! Module that encapsulates multiple chatrooms.
+//! Each chatroom is represented by an XmppChatroomImpl instance
+class XmppChatroomModuleImpl : public XmppChatroomModule,
+ public XmppModuleImpl, public XmppIqHandler {
+public:
+ IMPLEMENT_XMPPMODULE
+
+ // Creates a chatroom with specified Jid
+ XmppChatroomModuleImpl();
+ ~XmppChatroomModuleImpl();
+
+ // XmppChatroomModule
+ virtual XmppReturnStatus set_chatroom_handler(XmppChatroomHandler* handler);
+ virtual XmppChatroomHandler* chatroom_handler();
+ virtual XmppReturnStatus set_chatroom_jid(const Jid& chatroom_jid);
+ virtual const Jid& chatroom_jid() const;
+ virtual XmppReturnStatus set_nickname(const std::string& nickname);
+ virtual const std::string& nickname() const;
+ virtual const Jid member_jid() const;
+ virtual XmppReturnStatus RequestEnterChatroom(const std::string& password,
+ const std::string& client_version,
+ const std::string& locale);
+ virtual XmppReturnStatus RequestExitChatroom();
+ virtual XmppReturnStatus RequestConnectionStatusChange(
+ XmppPresenceConnectionStatus connection_status);
+ virtual size_t GetChatroomMemberCount();
+ virtual XmppReturnStatus CreateMemberEnumerator(XmppChatroomMemberEnumerator** enumerator);
+ virtual const std::string subject();
+ virtual XmppChatroomState state() { return chatroom_state_; }
+ virtual XmppReturnStatus SendMessage(const XmlElement& message);
+
+ // XmppModule
+ virtual void IqResponse(XmppIqCookie cookie, const XmlElement * pelStanza) {RTC_UNUSED2(cookie, pelStanza);}
+ virtual bool HandleStanza(const XmlElement *);
+
+private:
+ friend class XmppChatroomMemberEnumeratorImpl;
+
+ XmppReturnStatus ServerChangeMyPresence(const XmlElement& presence);
+ XmppReturnStatus ClientChangeMyPresence(XmppChatroomState new_state);
+ XmppReturnStatus ChangePresence(XmppChatroomState new_state, const XmlElement* presence, bool isServer);
+ XmppReturnStatus ServerChangedOtherPresence(const XmlElement& presence_element);
+ XmppChatroomEnteredStatus GetEnterFailureFromXml(const XmlElement* presence);
+ XmppChatroomExitedStatus GetExitFailureFromXml(const XmlElement* presence);
+
+ bool CheckEnterChatroomStateOk();
+
+ void FireEnteredStatus(const XmlElement* presence,
+ XmppChatroomEnteredStatus status);
+ void FireExitStatus(XmppChatroomExitedStatus status);
+ void FireMessageReceived(const XmlElement& message);
+ void FireMemberEntered(const XmppChatroomMember* entered_member);
+ void FireMemberChanged(const XmppChatroomMember* changed_member);
+ void FireMemberExited(const XmppChatroomMember* exited_member);
+
+
+ typedef std::map<Jid, XmppChatroomMemberImpl*> JidMemberMap;
+
+ XmppChatroomHandler* chatroom_handler_;
+ Jid chatroom_jid_;
+ std::string nickname_;
+ XmppChatroomState chatroom_state_;
+ JidMemberMap chatroom_jid_members_;
+ int chatroom_jid_members_version_;
+};
+
+
+class XmppChatroomMemberImpl : public XmppChatroomMember {
+public:
+ ~XmppChatroomMemberImpl() {}
+ XmppReturnStatus SetPresence(const XmppPresence* presence);
+
+ // XmppChatroomMember
+ const Jid member_jid() const;
+ const Jid full_jid() const;
+ const std::string name() const;
+ const XmppPresence* presence() const;
+
+private:
+ rtc::scoped_ptr<XmppPresence> presence_;
+};
+
+class XmppChatroomMemberEnumeratorImpl :
+ public XmppChatroomMemberEnumerator {
+public:
+ XmppChatroomMemberEnumeratorImpl(XmppChatroomModuleImpl::JidMemberMap* chatroom_jid_members,
+ int* map_version);
+
+ // XmppChatroomMemberEnumerator
+ virtual XmppChatroomMember* current();
+ virtual bool Next();
+ virtual bool Prev();
+ virtual bool IsValid();
+ virtual bool IsBeforeBeginning();
+ virtual bool IsAfterEnd();
+
+private:
+ XmppChatroomModuleImpl::JidMemberMap* map_;
+ int map_version_created_;
+ int* map_version_;
+ XmppChatroomModuleImpl::JidMemberMap::iterator iterator_;
+ bool before_beginning_;
+};
+
+
+// XmppChatroomModuleImpl ------------------------------------------------
+XmppChatroomModule *
+XmppChatroomModule::Create() {
+ return new XmppChatroomModuleImpl();
+}
+
+XmppChatroomModuleImpl::XmppChatroomModuleImpl() :
+ chatroom_handler_(NULL),
+ chatroom_jid_(STR_EMPTY),
+ chatroom_state_(XMPP_CHATROOM_STATE_NOT_IN_ROOM),
+ chatroom_jid_members_version_(0) {
+}
+
+XmppChatroomModuleImpl::~XmppChatroomModuleImpl() {
+ JidMemberMap::iterator iterator = chatroom_jid_members_.begin();
+ while (iterator != chatroom_jid_members_.end()) {
+ delete iterator->second;
+ iterator++;
+ }
+}
+
+
+bool
+XmppChatroomModuleImpl::HandleStanza(const XmlElement* stanza) {
+ ASSERT(engine() != NULL);
+
+ // we handle stanzas that are for one of our chatrooms
+ Jid from_jid = Jid(stanza->Attr(QN_FROM));
+ // see if it's one of our chatrooms
+ if (chatroom_jid_ != from_jid.BareJid()) {
+ return false; // not one of our chatrooms
+ } else {
+ // handle presence stanza
+ if (stanza->Name() == QN_PRESENCE) {
+ if (from_jid == member_jid()) {
+ ServerChangeMyPresence(*stanza);
+ } else {
+ ServerChangedOtherPresence(*stanza);
+ }
+ } else if (stanza->Name() == QN_MESSAGE) {
+ FireMessageReceived(*stanza);
+ }
+ return true;
+ }
+}
+
+
+XmppReturnStatus
+XmppChatroomModuleImpl::set_chatroom_handler(XmppChatroomHandler* handler) {
+ // Calling with NULL removes the handler.
+ chatroom_handler_ = handler;
+ return XMPP_RETURN_OK;
+}
+
+
+XmppChatroomHandler*
+XmppChatroomModuleImpl::chatroom_handler() {
+ return chatroom_handler_;
+}
+
+XmppReturnStatus
+XmppChatroomModuleImpl::set_chatroom_jid(const Jid& chatroom_jid) {
+ if (chatroom_state_ != XMPP_CHATROOM_STATE_NOT_IN_ROOM) {
+ return XMPP_RETURN_BADSTATE; // $TODO - this isn't a bad state, it's a bad call, diff error code?
+ }
+ if (chatroom_jid != chatroom_jid.BareJid()) {
+ // chatroom_jid must be a bare jid
+ return XMPP_RETURN_BADARGUMENT;
+ }
+
+ chatroom_jid_ = chatroom_jid;
+ return XMPP_RETURN_OK;
+}
+
+const Jid&
+XmppChatroomModuleImpl::chatroom_jid() const {
+ return chatroom_jid_;
+}
+
+ XmppReturnStatus
+ XmppChatroomModuleImpl::set_nickname(const std::string& nickname) {
+ if (chatroom_state_ != XMPP_CHATROOM_STATE_NOT_IN_ROOM) {
+ return XMPP_RETURN_BADSTATE; // $TODO - this isn't a bad state, it's a bad call, diff error code?
+ }
+ nickname_ = nickname;
+ return XMPP_RETURN_OK;
+ }
+
+ const std::string&
+ XmppChatroomModuleImpl::nickname() const {
+ return nickname_;
+ }
+
+const Jid
+XmppChatroomModuleImpl::member_jid() const {
+ return Jid(chatroom_jid_.node(), chatroom_jid_.domain(), nickname_);
+}
+
+
+bool
+XmppChatroomModuleImpl::CheckEnterChatroomStateOk() {
+ if (chatroom_jid_.IsValid() == false) {
+ ASSERT(0);
+ return false;
+ }
+ if (nickname_ == STR_EMPTY) {
+ ASSERT(0);
+ return false;
+ }
+ return true;
+}
+
+std::string GetAttrValueFor(XmppPresenceConnectionStatus connection_status) {
+ switch (connection_status) {
+ default:
+ case XMPP_CONNECTION_STATUS_UNKNOWN:
+ return "";
+ case XMPP_CONNECTION_STATUS_CONNECTING:
+ return STR_PSTN_CONFERENCE_STATUS_CONNECTING;
+ case XMPP_CONNECTION_STATUS_CONNECTED:
+ return STR_PSTN_CONFERENCE_STATUS_CONNECTED;
+ }
+}
+
+XmppReturnStatus
+XmppChatroomModuleImpl::RequestEnterChatroom(
+ const std::string& password,
+ const std::string& client_version,
+ const std::string& locale) {
+ RTC_UNUSED(password);
+ if (!engine())
+ return XMPP_RETURN_BADSTATE;
+
+ if (chatroom_state_ != XMPP_CHATROOM_STATE_NOT_IN_ROOM)
+ return XMPP_RETURN_BADSTATE; // $TODO - this isn't a bad state, it's a bad call, diff error code?
+
+ if (CheckEnterChatroomStateOk() == false) {
+ return XMPP_RETURN_BADSTATE;
+ }
+
+ // entering a chatroom is a presence request to the server
+ XmlElement element(QN_PRESENCE);
+ element.AddAttr(QN_TO, member_jid().Str());
+
+ XmlElement* muc_x = new XmlElement(QN_MUC_X);
+ element.AddElement(muc_x);
+
+ if (!client_version.empty()) {
+ XmlElement* client_version_element = new XmlElement(QN_CLIENT_VERSION,
+ false);
+ client_version_element->SetBodyText(client_version);
+ muc_x->AddElement(client_version_element);
+ }
+
+ if (!locale.empty()) {
+ XmlElement* locale_element = new XmlElement(QN_LOCALE, false);
+
+ locale_element->SetBodyText(locale);
+ muc_x->AddElement(locale_element);
+ }
+
+ XmppReturnStatus status = engine()->SendStanza(&element);
+ if (status == XMPP_RETURN_OK) {
+ return ClientChangeMyPresence(XMPP_CHATROOM_STATE_REQUESTED_ENTER);
+ }
+ return status;
+}
+
+XmppReturnStatus
+XmppChatroomModuleImpl::RequestExitChatroom() {
+ if (!engine())
+ return XMPP_RETURN_BADSTATE;
+
+ // exiting a chatroom is a presence request to the server
+ XmlElement element(QN_PRESENCE);
+ element.AddAttr(QN_TO, member_jid().Str());
+ element.AddAttr(QN_TYPE, "unavailable");
+ XmppReturnStatus status = engine()->SendStanza(&element);
+ if (status == XMPP_RETURN_OK &&
+ chatroom_state_ == XMPP_CHATROOM_STATE_IN_ROOM) {
+ return ClientChangeMyPresence(XMPP_CHATROOM_STATE_REQUESTED_EXIT);
+ }
+ return status;
+}
+
+XmppReturnStatus
+XmppChatroomModuleImpl::RequestConnectionStatusChange(
+ XmppPresenceConnectionStatus connection_status) {
+ if (!engine())
+ return XMPP_RETURN_BADSTATE;
+
+ if (chatroom_state_ != XMPP_CHATROOM_STATE_IN_ROOM) {
+ // $TODO - this isn't a bad state, it's a bad call, diff error code?
+ return XMPP_RETURN_BADSTATE;
+ }
+
+ if (CheckEnterChatroomStateOk() == false) {
+ return XMPP_RETURN_BADSTATE;
+ }
+
+ // entering a chatroom is a presence request to the server
+ XmlElement element(QN_PRESENCE);
+ element.AddAttr(QN_TO, member_jid().Str());
+ element.AddElement(new XmlElement(QN_MUC_X));
+ if (connection_status != XMPP_CONNECTION_STATUS_UNKNOWN) {
+ XmlElement* con_status_element =
+ new XmlElement(QN_GOOGLE_PSTN_CONFERENCE_STATUS);
+ con_status_element->AddAttr(QN_STATUS, GetAttrValueFor(connection_status));
+ element.AddElement(con_status_element);
+ }
+ XmppReturnStatus status = engine()->SendStanza(&element);
+
+ return status;
+}
+
+size_t
+XmppChatroomModuleImpl::GetChatroomMemberCount() {
+ return chatroom_jid_members_.size();
+}
+
+XmppReturnStatus
+XmppChatroomModuleImpl::CreateMemberEnumerator(XmppChatroomMemberEnumerator** enumerator) {
+ *enumerator = new XmppChatroomMemberEnumeratorImpl(&chatroom_jid_members_, &chatroom_jid_members_version_);
+ return XMPP_RETURN_OK;
+}
+
+const std::string
+XmppChatroomModuleImpl::subject() {
+ return ""; //NYI
+}
+
+XmppReturnStatus
+XmppChatroomModuleImpl::SendMessage(const XmlElement& message) {
+ XmppReturnStatus xmpp_status = XMPP_RETURN_OK;
+
+ // can only send a message if we're in the room
+ if (chatroom_state_ != XMPP_CHATROOM_STATE_IN_ROOM) {
+ return XMPP_RETURN_BADSTATE; // $TODO - this isn't a bad state, it's a bad call, diff error code?
+ }
+
+ if (message.Name() != QN_MESSAGE) {
+ IFR(XMPP_RETURN_BADARGUMENT);
+ }
+
+ const std::string& type = message.Attr(QN_TYPE);
+ if (type != "groupchat") {
+ IFR(XMPP_RETURN_BADARGUMENT);
+ }
+
+ if (message.HasAttr(QN_FROM)) {
+ IFR(XMPP_RETURN_BADARGUMENT);
+ }
+
+ if (message.Attr(QN_TO) != chatroom_jid_.Str()) {
+ IFR(XMPP_RETURN_BADARGUMENT);
+ }
+
+ IFR(engine()->SendStanza(&message));
+
+ return xmpp_status;
+}
+
+enum TransitionType {
+ TRANSITION_TYPE_NONE = 0,
+ TRANSITION_TYPE_ENTER_SUCCESS = 1,
+ TRANSITION_TYPE_ENTER_FAILURE = 2,
+ TRANSITION_TYPE_EXIT_VOLUNTARILY = 3,
+ TRANSITION_TYPE_EXIT_INVOLUNTARILY = 4,
+};
+
+struct StateTransitionDescription {
+ XmppChatroomState old_state;
+ XmppChatroomState new_state;
+ bool is_valid_server_transition;
+ bool is_valid_client_transition;
+ TransitionType transition_type;
+};
+
+StateTransitionDescription Transitions[] = {
+ { XMPP_CHATROOM_STATE_NOT_IN_ROOM, XMPP_CHATROOM_STATE_REQUESTED_ENTER, false, true, TRANSITION_TYPE_NONE, },
+ { XMPP_CHATROOM_STATE_NOT_IN_ROOM, XMPP_CHATROOM_STATE_IN_ROOM, false, false, TRANSITION_TYPE_ENTER_SUCCESS, },
+ { XMPP_CHATROOM_STATE_NOT_IN_ROOM, XMPP_CHATROOM_STATE_REQUESTED_EXIT, false, false, TRANSITION_TYPE_NONE, },
+ { XMPP_CHATROOM_STATE_REQUESTED_ENTER, XMPP_CHATROOM_STATE_NOT_IN_ROOM, true, false, TRANSITION_TYPE_ENTER_FAILURE, },
+ { XMPP_CHATROOM_STATE_REQUESTED_ENTER, XMPP_CHATROOM_STATE_IN_ROOM, true, false, TRANSITION_TYPE_ENTER_SUCCESS, },
+ { XMPP_CHATROOM_STATE_REQUESTED_ENTER, XMPP_CHATROOM_STATE_REQUESTED_EXIT, false, false, TRANSITION_TYPE_NONE, },
+ { XMPP_CHATROOM_STATE_IN_ROOM, XMPP_CHATROOM_STATE_NOT_IN_ROOM, true, false, TRANSITION_TYPE_EXIT_INVOLUNTARILY, },
+ { XMPP_CHATROOM_STATE_IN_ROOM, XMPP_CHATROOM_STATE_REQUESTED_ENTER, false, false, TRANSITION_TYPE_NONE, },
+ { XMPP_CHATROOM_STATE_IN_ROOM, XMPP_CHATROOM_STATE_REQUESTED_EXIT, false, true, TRANSITION_TYPE_NONE, },
+ { XMPP_CHATROOM_STATE_REQUESTED_EXIT, XMPP_CHATROOM_STATE_NOT_IN_ROOM, true, false, TRANSITION_TYPE_EXIT_VOLUNTARILY, },
+ { XMPP_CHATROOM_STATE_REQUESTED_EXIT, XMPP_CHATROOM_STATE_REQUESTED_ENTER, false, false, TRANSITION_TYPE_NONE, },
+ { XMPP_CHATROOM_STATE_REQUESTED_EXIT, XMPP_CHATROOM_STATE_IN_ROOM, false, false, TRANSITION_TYPE_NONE, },
+};
+
+
+
+void
+XmppChatroomModuleImpl::FireEnteredStatus(const XmlElement* presence,
+ XmppChatroomEnteredStatus status) {
+ if (chatroom_handler_) {
+ rtc::scoped_ptr<XmppPresence> xmpp_presence(XmppPresence::Create());
+ xmpp_presence->set_raw_xml(presence);
+ chatroom_handler_->ChatroomEnteredStatus(this, xmpp_presence.get(), status);
+ }
+}
+
+void
+XmppChatroomModuleImpl::FireExitStatus(XmppChatroomExitedStatus status) {
+ if (chatroom_handler_)
+ chatroom_handler_->ChatroomExitedStatus(this, status);
+}
+
+void
+XmppChatroomModuleImpl::FireMessageReceived(const XmlElement& message) {
+ if (chatroom_handler_)
+ chatroom_handler_->MessageReceived(this, message);
+}
+
+void
+XmppChatroomModuleImpl::FireMemberEntered(const XmppChatroomMember* entered_member) {
+ if (chatroom_handler_)
+ chatroom_handler_->MemberEntered(this, entered_member);
+}
+
+void
+XmppChatroomModuleImpl::FireMemberChanged(
+ const XmppChatroomMember* changed_member) {
+ if (chatroom_handler_)
+ chatroom_handler_->MemberChanged(this, changed_member);
+}
+
+void
+XmppChatroomModuleImpl::FireMemberExited(const XmppChatroomMember* exited_member) {
+ if (chatroom_handler_)
+ chatroom_handler_->MemberExited(this, exited_member);
+}
+
+
+XmppReturnStatus
+XmppChatroomModuleImpl::ServerChangedOtherPresence(const XmlElement&
+ presence_element) {
+ XmppReturnStatus xmpp_status = XMPP_RETURN_OK;
+ rtc::scoped_ptr<XmppPresence> presence(XmppPresence::Create());
+ IFR(presence->set_raw_xml(&presence_element));
+
+ JidMemberMap::iterator pos = chatroom_jid_members_.find(presence->jid());
+
+ if (pos == chatroom_jid_members_.end()) {
+ if (presence->available() == XMPP_PRESENCE_AVAILABLE) {
+ XmppChatroomMemberImpl* member = new XmppChatroomMemberImpl();
+ member->SetPresence(presence.get());
+ chatroom_jid_members_.insert(std::make_pair(member->member_jid(), member));
+ chatroom_jid_members_version_++;
+ FireMemberEntered(member);
+ }
+ } else {
+ XmppChatroomMemberImpl* member = pos->second;
+ if (presence->available() == XMPP_PRESENCE_AVAILABLE) {
+ member->SetPresence(presence.get());
+ chatroom_jid_members_version_++;
+ FireMemberChanged(member);
+ }
+ else if (presence->available() == XMPP_PRESENCE_UNAVAILABLE) {
+ member->SetPresence(presence.get());
+ chatroom_jid_members_.erase(pos);
+ chatroom_jid_members_version_++;
+ FireMemberExited(member);
+ delete member;
+ }
+ }
+
+ return xmpp_status;
+}
+
+XmppReturnStatus
+XmppChatroomModuleImpl::ClientChangeMyPresence(XmppChatroomState new_state) {
+ return ChangePresence(new_state, NULL, false);
+}
+
+XmppReturnStatus
+XmppChatroomModuleImpl::ServerChangeMyPresence(const XmlElement& presence) {
+ XmppChatroomState new_state;
+
+ if (presence.HasAttr(QN_TYPE) == false) {
+ new_state = XMPP_CHATROOM_STATE_IN_ROOM;
+ } else {
+ new_state = XMPP_CHATROOM_STATE_NOT_IN_ROOM;
+ }
+ return ChangePresence(new_state, &presence, true);
+
+}
+
+XmppReturnStatus
+XmppChatroomModuleImpl::ChangePresence(XmppChatroomState new_state,
+ const XmlElement* presence,
+ bool isServer) {
+ RTC_UNUSED(presence);
+
+ XmppChatroomState old_state = chatroom_state_;
+
+ // do nothing if state hasn't changed
+ if (old_state == new_state)
+ return XMPP_RETURN_OK;
+
+ // find the right transition description
+ StateTransitionDescription* transition_desc = NULL;
+ for (int i=0; i < ARRAY_SIZE(Transitions); i++) {
+ if (Transitions[i].old_state == old_state &&
+ Transitions[i].new_state == new_state) {
+ transition_desc = &Transitions[i];
+ break;
+ }
+ }
+
+ if (transition_desc == NULL) {
+ ASSERT(0);
+ return XMPP_RETURN_BADSTATE;
+ }
+
+ // we assert for any invalid transition states, and we'll
+ if (isServer) {
+ // $TODO send original stanza back to server and log an error?
+ // Disable the assert because of b/6133072
+ // ASSERT(transition_desc->is_valid_server_transition);
+ if (!transition_desc->is_valid_server_transition) {
+ return XMPP_RETURN_BADSTATE;
+ }
+ } else {
+ if (transition_desc->is_valid_client_transition == false) {
+ ASSERT(0);
+ return XMPP_RETURN_BADARGUMENT;
+ }
+ }
+
+ // set the new state and then fire any notifications to the handler
+ chatroom_state_ = new_state;
+
+ switch (transition_desc->transition_type) {
+ case TRANSITION_TYPE_ENTER_SUCCESS:
+ FireEnteredStatus(presence, XMPP_CHATROOM_ENTERED_SUCCESS);
+ break;
+ case TRANSITION_TYPE_ENTER_FAILURE:
+ FireEnteredStatus(presence, GetEnterFailureFromXml(presence));
+ break;
+ case TRANSITION_TYPE_EXIT_INVOLUNTARILY:
+ FireExitStatus(GetExitFailureFromXml(presence));
+ break;
+ case TRANSITION_TYPE_EXIT_VOLUNTARILY:
+ FireExitStatus(XMPP_CHATROOM_EXITED_REQUESTED);
+ break;
+ case TRANSITION_TYPE_NONE:
+ break;
+ }
+
+ return XMPP_RETURN_OK;
+}
+
+XmppChatroomEnteredStatus
+XmppChatroomModuleImpl::GetEnterFailureFromXml(const XmlElement* presence) {
+ XmppChatroomEnteredStatus status = XMPP_CHATROOM_ENTERED_FAILURE_UNSPECIFIED;
+ const XmlElement* error = presence->FirstNamed(QN_ERROR);
+ if (error != NULL && error->HasAttr(QN_CODE)) {
+ int code = atoi(error->Attr(QN_CODE).c_str());
+ switch (code) {
+ case 401: status = XMPP_CHATROOM_ENTERED_FAILURE_PASSWORD_REQUIRED; break;
+ case 403: {
+ status = XMPP_CHATROOM_ENTERED_FAILURE_MEMBER_BANNED;
+ if (error->FirstNamed(QN_GOOGLE_SESSION_BLOCKED)) {
+ status = XMPP_CHATROOM_ENTERED_FAILURE_MEMBER_BLOCKED;
+ } else if (error->FirstNamed(QN_GOOGLE_SESSION_BLOCKING)) {
+ status = XMPP_CHATROOM_ENTERED_FAILURE_MEMBER_BLOCKING;
+ }
+ break;
+ }
+ case 405: status = XMPP_CHATROOM_ENTERED_FAILURE_ROOM_LOCKED; break;
+ case 406: status = XMPP_CHATROOM_ENTERED_FAILURE_OUTDATED_CLIENT; break;
+ case 407: status = XMPP_CHATROOM_ENTERED_FAILURE_NOT_A_MEMBER; break;
+ case 409: status = XMPP_CHATROOM_ENTERED_FAILURE_NICKNAME_CONFLICT; break;
+ // http://xmpp.org/extensions/xep-0045.html#enter-maxusers
+ case 503: status = XMPP_CHATROOM_ENTERED_FAILURE_MAX_USERS; break;
+ }
+ }
+ return status;
+}
+
+XmppChatroomExitedStatus
+XmppChatroomModuleImpl::GetExitFailureFromXml(const XmlElement* presence) {
+ XmppChatroomExitedStatus status = XMPP_CHATROOM_EXITED_UNSPECIFIED;
+ const XmlElement* muc_user = presence->FirstNamed(QN_MUC_USER_X);
+ if (muc_user != NULL) {
+ const XmlElement* user_status = muc_user->FirstNamed(QN_MUC_USER_STATUS);
+ if (user_status != NULL && user_status->HasAttr(QN_CODE)) {
+ int code = atoi(user_status->Attr(QN_CODE).c_str());
+ switch (code) {
+ case 307: status = XMPP_CHATROOM_EXITED_KICKED; break;
+ case 322: status = XMPP_CHATROOM_EXITED_NOT_A_MEMBER; break;
+ case 332: status = XMPP_CHATROOM_EXITED_SYSTEM_SHUTDOWN; break;
+ }
+ }
+ }
+ return status;
+}
+
+XmppReturnStatus
+XmppChatroomMemberImpl::SetPresence(const XmppPresence* presence) {
+ ASSERT(presence != NULL);
+
+ // copy presence
+ presence_.reset(XmppPresence::Create());
+ presence_->set_raw_xml(presence->raw_xml());
+ return XMPP_RETURN_OK;
+}
+
+const Jid
+XmppChatroomMemberImpl::member_jid() const {
+ return presence_->jid();
+}
+
+const Jid
+XmppChatroomMemberImpl::full_jid() const {
+ return Jid("");
+}
+
+const std::string
+XmppChatroomMemberImpl::name() const {
+ return member_jid().resource();
+}
+
+const XmppPresence*
+XmppChatroomMemberImpl::presence() const {
+ return presence_.get();
+}
+
+
+// XmppChatroomMemberEnumeratorImpl --------------------------------------
+XmppChatroomMemberEnumeratorImpl::XmppChatroomMemberEnumeratorImpl(
+ XmppChatroomModuleImpl::JidMemberMap* map, int* map_version) {
+ map_ = map;
+ map_version_ = map_version;
+ map_version_created_ = *map_version_;
+ iterator_ = map->begin();
+ before_beginning_ = true;
+}
+
+XmppChatroomMember*
+XmppChatroomMemberEnumeratorImpl::current() {
+ if (IsValid() == false) {
+ return NULL;
+ } else if (IsBeforeBeginning() || IsAfterEnd()) {
+ return NULL;
+ } else {
+ return iterator_->second;
+ }
+}
+
+bool
+XmppChatroomMemberEnumeratorImpl::Prev() {
+ if (IsValid() == false) {
+ return false;
+ } else if (IsBeforeBeginning()) {
+ return false;
+ } else if (iterator_ == map_->begin()) {
+ before_beginning_ = true;
+ return false;
+ } else {
+ iterator_--;
+ return current() != NULL;
+ }
+}
+
+bool
+XmppChatroomMemberEnumeratorImpl::Next() {
+ if (IsValid() == false) {
+ return false;
+ } else if (IsBeforeBeginning()) {
+ before_beginning_ = false;
+ iterator_ = map_->begin();
+ return current() != NULL;
+ } else if (IsAfterEnd()) {
+ return false;
+ } else {
+ iterator_++;
+ return current() != NULL;
+ }
+}
+
+bool
+XmppChatroomMemberEnumeratorImpl::IsValid() {
+ return map_version_created_ == *map_version_;
+}
+
+bool
+XmppChatroomMemberEnumeratorImpl::IsBeforeBeginning() {
+ return before_beginning_;
+}
+
+bool
+XmppChatroomMemberEnumeratorImpl::IsAfterEnd() {
+ return (iterator_ == map_->end());
+}
+
+
+
+} // namespace buzz