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