gloox 1.0
|
00001 /* 00002 Copyright (c) 2006-2009 by Jakob Schroeter <js@camaya.net> 00003 This file is part of the gloox library. http://camaya.net/gloox 00004 00005 This software is distributed under a license. The full license 00006 agreement can be found in the file LICENSE in this distribution. 00007 This software may not be copied, modified, sold or distributed 00008 other than expressed in the named license agreement. 00009 00010 This software is distributed without any warranty. 00011 */ 00012 00013 00014 00015 #include "mucroom.h" 00016 #include "clientbase.h" 00017 #include "dataform.h" 00018 #include "presence.h" 00019 #include "disco.h" 00020 #include "mucmessagesession.h" 00021 #include "message.h" 00022 #include "error.h" 00023 #include "util.h" 00024 #include "tag.h" 00025 00026 namespace gloox 00027 { 00028 00029 // ---- MUCRoom::MUCAdmin ---- 00030 /* Error type values */ 00031 static const char* affiliationValues [] = { 00032 "none", 00033 "outcast", 00034 "member", 00035 "owner", 00036 "admin" 00037 }; 00038 00039 /* Stanza error values */ 00040 static const char* roleValues [] = { 00041 "none", 00042 "visitor", 00043 "participant", 00044 "moderator", 00045 }; 00046 00048 const char* historyTypeValues[] = 00049 { 00050 "maxchars", "maxstanzas", "seconds", "since" 00051 }; 00052 00053 static inline MUCRoomAffiliation affiliationType( const std::string& type ) 00054 { 00055 return (MUCRoomAffiliation)util::lookup( type, affiliationValues ); 00056 } 00057 00058 static inline MUCRoomRole roleType( const std::string& type ) 00059 { 00060 return (MUCRoomRole)util::lookup( type, roleValues ); 00061 } 00062 00063 MUCRoom::MUCAdmin::MUCAdmin( MUCRoomRole role, const std::string& nick, 00064 const std::string& reason ) 00065 : StanzaExtension( ExtMUCAdmin ), m_affiliation( AffiliationInvalid ), m_role( role ) 00066 { 00067 m_list.push_back( MUCListItem( nick, role, reason ) ); 00068 } 00069 00070 MUCRoom::MUCAdmin::MUCAdmin( MUCRoomAffiliation affiliation, const std::string& nick, 00071 const std::string& reason ) 00072 : StanzaExtension( ExtMUCAdmin ), m_affiliation( affiliation ), m_role( RoleInvalid ) 00073 { 00074 m_list.push_back( MUCListItem( nick, affiliation, reason ) ); 00075 } 00076 00077 MUCRoom::MUCAdmin::MUCAdmin( MUCOperation operation, const MUCListItemList& jids ) 00078 : StanzaExtension( ExtMUCAdmin ), m_list( jids ), m_affiliation( AffiliationInvalid ), 00079 m_role( RoleInvalid ) 00080 { 00081 switch( operation ) 00082 { 00083 case StoreVoiceList: 00084 case RequestVoiceList: 00085 m_role = RoleParticipant; 00086 break; 00087 case StoreModeratorList: 00088 case RequestModeratorList: 00089 m_role = RoleModerator; 00090 break; 00091 case StoreBanList: 00092 case RequestBanList: 00093 m_affiliation = AffiliationOutcast; 00094 break; 00095 case StoreMemberList: 00096 case RequestMemberList: 00097 m_affiliation = AffiliationMember; 00098 break; 00099 case StoreOwnerList: 00100 case RequestOwnerList: 00101 m_affiliation = AffiliationOwner; 00102 break; 00103 case StoreAdminList: 00104 case RequestAdminList: 00105 m_affiliation = AffiliationAdmin; 00106 break; 00107 default: 00108 return; 00109 break; 00110 } 00111 00112 if( m_list.empty() ) 00113 m_list.push_back( MUCListItem( JID() ) ); 00114 } 00115 00116 MUCRoom::MUCAdmin::MUCAdmin( const Tag* tag ) 00117 : StanzaExtension( ExtMUCAdmin ), m_affiliation( AffiliationInvalid ), m_role( RoleInvalid ) 00118 { 00119 if( !tag || tag->name() != "query" || tag->xmlns() != XMLNS_MUC_ADMIN ) 00120 return; 00121 00122 const TagList& items = tag->findChildren( "item" ); 00123 TagList::const_iterator it = items.begin(); 00124 for( ; it != items.end(); ++it ) 00125 { 00126 m_list.push_back( MUCListItem( JID( (*it)->findAttribute( "jid" ) ), 00127 roleType( (*it)->findAttribute( "role" ) ), 00128 affiliationType( (*it)->findAttribute( "affiliation" ) ), 00129 (*it)->findAttribute( "nick" ) ) ); 00130 if( m_role == RoleInvalid ) 00131 m_role = roleType( (*it)->findAttribute( "role" ) ); 00132 if( m_affiliation == AffiliationInvalid ) 00133 m_affiliation = affiliationType( (*it)->findAttribute( "affiliation" ) ); 00134 } 00135 } 00136 00137 MUCRoom::MUCAdmin::~MUCAdmin() 00138 { 00139 } 00140 00141 const std::string& MUCRoom::MUCAdmin::filterString() const 00142 { 00143 static const std::string filter = "/iq/query[@xmlns='" + XMLNS_MUC_ADMIN + "']"; 00144 return filter; 00145 } 00146 00147 Tag* MUCRoom::MUCAdmin::tag() const 00148 { 00149 Tag* t = new Tag( "query" ); 00150 t->setXmlns( XMLNS_MUC_ADMIN ); 00151 00152 if( m_list.empty() || ( m_affiliation == AffiliationInvalid && m_role == RoleInvalid ) ) 00153 return t; 00154 00155 MUCListItemList::const_iterator it = m_list.begin(); 00156 for( ; it != m_list.end(); ++it ) 00157 { 00158 Tag* i = new Tag( t, "item" ); 00159 if( (*it).jid() ) 00160 i->addAttribute( "jid", (*it).jid().bare() ); 00161 if( !(*it).nick().empty() ) 00162 i->addAttribute( "nick", (*it).nick() ); 00163 00164 MUCRoomRole rol = RoleInvalid; 00165 if( (*it).role() != RoleInvalid ) 00166 rol = (*it).role(); 00167 else if( m_role != RoleInvalid ) 00168 rol = m_role; 00169 if( rol != RoleInvalid ) 00170 i->addAttribute( "role", util::lookup( rol, roleValues ) ); 00171 00172 MUCRoomAffiliation aff = AffiliationInvalid; 00173 if( (*it).affiliation() != AffiliationInvalid ) 00174 aff = (*it).affiliation(); 00175 else if( m_affiliation != AffiliationInvalid ) 00176 aff = m_affiliation; 00177 if( aff != AffiliationInvalid ) 00178 i->addAttribute( "affiliation", util::lookup( aff, affiliationValues ) ); 00179 if( !(*it).reason().empty() ) 00180 new Tag( i, "reason", (*it).reason() ); 00181 } 00182 00183 return t; 00184 } 00185 // ---- ~MUCRoom::MUCAdmin ---- 00186 00187 // ---- MUCRoom::MUCOwner ---- 00188 MUCRoom::MUCOwner::MUCOwner( QueryType type, DataForm* form ) 00189 : StanzaExtension( ExtMUCOwner ), m_type( type ), m_form( form ) 00190 { 00191 m_valid = true; 00192 00193 if( m_form ) 00194 return; 00195 00196 switch( type ) 00197 { 00198 case TypeCancelConfig: 00199 m_form = new DataForm( TypeCancel ); 00200 break; 00201 case TypeInstantRoom: 00202 m_form = new DataForm( TypeSubmit ); 00203 break; 00204 default: 00205 break; 00206 } 00207 } 00208 00209 MUCRoom::MUCOwner::MUCOwner( const JID& alternate, const std::string& reason, 00210 const std::string& password ) 00211 : StanzaExtension( ExtMUCOwner ), m_type( TypeDestroy ), m_jid( alternate ), 00212 m_reason( reason ), m_pwd( password ), m_form( 0 ) 00213 { 00214 m_valid = true; 00215 } 00216 00217 MUCRoom::MUCOwner::MUCOwner( const Tag* tag ) 00218 : StanzaExtension( ExtMUCOwner ), m_type( TypeIncomingTag ), m_form( 0 ) 00219 { 00220 if( !tag || tag->name() != "query" || tag->xmlns() != XMLNS_MUC_OWNER ) 00221 return; 00222 00223 const TagList& l = tag->children(); 00224 TagList::const_iterator it = l.begin(); 00225 for( ; it != l.end(); ++it ) 00226 { 00227 const std::string& name = (*it)->name(); 00228 if( name == "x" && (*it)->xmlns() == XMLNS_X_DATA ) 00229 { 00230 m_form = new DataForm( (*it) ); 00231 break; 00232 } 00233 else if( name == "destroy" ) 00234 { 00235 m_type = TypeDestroy; 00236 m_jid = (*it)->findAttribute( "jid" ); 00237 m_pwd = (*it)->findCData( "/query/destroy/password" ); 00238 m_reason = (*it)->findCData( "/query/destroy/reason" ); 00239 break; 00240 } 00241 } 00242 m_valid = true; 00243 } 00244 00245 MUCRoom::MUCOwner::~MUCOwner() 00246 { 00247 delete m_form; 00248 } 00249 00250 const std::string& MUCRoom::MUCOwner::filterString() const 00251 { 00252 static const std::string filter = "/iq/query[@xmlns='" + XMLNS_MUC_OWNER + "']"; 00253 return filter; 00254 } 00255 00256 Tag* MUCRoom::MUCOwner::tag() const 00257 { 00258 if( !m_valid ) 00259 return 0; 00260 00261 Tag* t = new Tag( "query" ); 00262 t->setXmlns( XMLNS_MUC_OWNER ); 00263 00264 switch( m_type ) 00265 { 00266 case TypeInstantRoom: 00267 case TypeSendConfig: 00268 case TypeCancelConfig: 00269 case TypeIncomingTag: 00270 if( m_form ) 00271 t->addChild( m_form->tag() ); 00272 break; 00273 case TypeDestroy: 00274 { 00275 Tag* d = new Tag( t, "destroy" ); 00276 if( m_jid ) 00277 d->addAttribute( "jid", m_jid.bare() ); 00278 00279 if( !m_reason.empty() ) 00280 new Tag( d, "reason", m_reason ); 00281 00282 if( !m_pwd.empty() ) 00283 new Tag( d, "password", m_pwd ); 00284 00285 break; 00286 } 00287 case TypeRequestConfig: 00288 case TypeCreate: 00289 default: 00290 break; 00291 } 00292 00293 return t; 00294 } 00295 // ---- ~MUCRoom::MUCOwner ---- 00296 00297 // ---- MUCRoom::MUCUser ---- 00298 MUCRoom::MUCUser::MUCUser( MUCUserOperation operation, const std::string& to, 00299 const std::string& reason, const std::string& thread ) 00300 : StanzaExtension( ExtMUCUser ), m_affiliation( AffiliationInvalid ), m_role( RoleInvalid ), 00301 m_jid( new std::string( to ) ), m_actor( 0 ), 00302 m_thread( thread.empty() ? 0 : new std::string( thread ) ), 00303 m_reason( new std::string( reason ) ), m_newNick( 0 ), m_password( 0 ), m_alternate( 0 ), 00304 m_operation( operation ), 00305 m_flags( 0 ), m_del( false ), m_continue( !thread.empty() ) 00306 { 00307 } 00308 00309 MUCRoom::MUCUser::MUCUser( const Tag* tag ) 00310 : StanzaExtension( ExtMUCUser ), m_affiliation( AffiliationInvalid ), m_role( RoleInvalid ), 00311 m_jid( 0 ), m_actor( 0 ), m_thread( 0 ), m_reason( 0 ), m_newNick( 0 ), 00312 m_password( 0 ), m_alternate( 0 ), m_operation( OpNone ), 00313 m_flags( 0 ), m_del( false ), m_continue( false ) 00314 { 00315 if( !tag || tag->name() != "x" || tag->xmlns() != XMLNS_MUC_USER ) 00316 return; 00317 00318 const Tag* t = 0; 00319 const TagList& l = tag->children(); 00320 TagList::const_iterator it = l.begin(); 00321 for( ; it != l.end(); ++it ) 00322 { 00323 if( (*it)->name() == "item" ) 00324 { 00325 m_affiliation = getEnumAffiliation( (*it)->findAttribute( "affiliation" ) ); 00326 m_role = getEnumRole( (*it)->findAttribute( "role" ) ); 00327 00328 if( (*it)->hasAttribute( "jid" ) ) 00329 m_jid = new std::string( (*it)->findAttribute( "jid" ) ); 00330 00331 if( ( t = (*it)->findChild( "actor" ) ) ) 00332 m_actor = new std::string( t->findAttribute( "jid" ) ); 00333 00334 if( ( t = (*it)->findChild( "reason" ) ) ) 00335 m_reason = new std::string( t->cdata() ); 00336 00337 if( (*it)->hasAttribute( "nick" ) ) 00338 m_newNick = new std::string( (*it)->findAttribute( "nick" ) ); 00339 } 00340 else if( (*it)->name() == "status" ) 00341 { 00342 const std::string& code = (*it)->findAttribute( "code" ); 00343 if( code == "100" ) 00344 m_flags |= FlagNonAnonymous; 00345 else if( code == "101" ) 00346 m_flags |= UserAffiliationChangedWNR; 00347 else if( code == "110" ) 00348 m_flags |= UserSelf; 00349 else if( code == "170" ) 00350 m_flags |= FlagPublicLogging; 00351 else if( code == "201" ) 00352 m_flags |= UserNewRoom; 00353 else if( code == "210" ) 00354 m_flags |= UserNickAssigned; 00355 else if( code == "301" ) 00356 m_flags |= UserBanned; 00357 else if( code == "303" ) 00358 m_flags |= UserNickChanged; 00359 else if( code == "307" ) 00360 m_flags |= UserKicked; 00361 else if( code == "321" ) 00362 m_flags |= UserAffiliationChanged; 00363 else if( code == "322" ) 00364 m_flags |= UserMembershipRequired; 00365 else if( code == "332" ) 00366 m_flags |= UserRoomShutdown; 00367 } 00368 else if( (*it)->name() == "destroy" ) 00369 { 00370 m_del = true; 00371 if( (*it)->hasAttribute( "jid" ) ) 00372 m_alternate = new std::string( (*it)->findAttribute( "jid" ) ); 00373 00374 if( ( t = (*it)->findChild( "reason" ) ) ) 00375 m_reason = new std::string( t->cdata() ); 00376 00377 m_flags |= UserRoomDestroyed; 00378 } 00379 else if( (*it)->name() == "invite" ) 00380 { 00381 m_operation = OpInviteFrom; 00382 m_jid = new std::string( (*it)->findAttribute( "from" ) ); 00383 if( m_jid->empty() ) 00384 { 00385 m_operation = OpInviteTo; 00386 m_jid->assign( (*it)->findAttribute( "to" ) ); 00387 } 00388 if( (*it)->hasChild( "reason" ) ) 00389 m_reason = new std::string( (*it)->findChild( "reason" )->cdata() ); 00390 if( (*it)->hasChild( "continue" ) ) 00391 { 00392 m_continue = true; 00393 m_thread = new std::string( (*it)->findChild( "continue" )->findAttribute( "thread" ) ); 00394 } 00395 } 00396 else if( (*it)->name() == "decline" ) 00397 { 00398 m_operation = OpDeclineFrom; 00399 m_jid = new std::string( (*it)->findAttribute( "from" ) ); 00400 if( m_jid->empty() ) 00401 { 00402 m_operation = OpDeclineTo; 00403 m_jid->assign( (*it)->findAttribute( "from" ) ); 00404 } 00405 if( (*it)->hasChild( "reason" ) ) 00406 m_reason = new std::string( (*it)->findChild( "reason" )->cdata() ); 00407 } 00408 else if( (*it)->name() == "password" ) 00409 { 00410 m_password = new std::string( (*it)->cdata() ); 00411 } 00412 } 00413 } 00414 00415 MUCRoom::MUCUser::~MUCUser() 00416 { 00417 delete m_jid; 00418 delete m_actor; 00419 delete m_thread; 00420 delete m_reason; 00421 delete m_newNick; 00422 delete m_password; 00423 delete m_alternate; 00424 } 00425 00426 MUCRoomRole MUCRoom::MUCUser::getEnumRole( const std::string& role ) 00427 { 00428 if( role == "moderator" ) 00429 return RoleModerator; 00430 if( role == "participant" ) 00431 return RoleParticipant; 00432 if( role == "visitor" ) 00433 return RoleVisitor; 00434 return RoleNone; 00435 } 00436 00437 MUCRoomAffiliation MUCRoom::MUCUser::getEnumAffiliation( const std::string& affiliation ) 00438 { 00439 if( affiliation == "owner" ) 00440 return AffiliationOwner; 00441 if( affiliation == "admin" ) 00442 return AffiliationAdmin; 00443 if( affiliation == "member" ) 00444 return AffiliationMember; 00445 if( affiliation == "outcast" ) 00446 return AffiliationOutcast; 00447 return AffiliationNone; 00448 } 00449 00450 const std::string& MUCRoom::MUCUser::filterString() const 00451 { 00452 static const std::string filter = "/presence/x[@xmlns='" + XMLNS_MUC_USER + "']" 00453 "|/message/x[@xmlns='" + XMLNS_MUC_USER + "']"; 00454 return filter; 00455 } 00456 00457 Tag* MUCRoom::MUCUser::tag() const 00458 { 00459 Tag* t = new Tag( "x" ); 00460 t->setXmlns( XMLNS_MUC_USER ); 00461 00462 if( m_affiliation != AffiliationInvalid || m_role != RoleInvalid ) 00463 { 00464 Tag* i = new Tag( t, "item" ); 00465 if( m_jid ) 00466 i->addAttribute( "jid", *m_jid ); 00467 if( m_role != RoleInvalid ) 00468 i->addAttribute( "role", util::lookup( m_role, roleValues ) ); 00469 if( m_affiliation != AffiliationInvalid ) 00470 i->addAttribute( "affiliation", util::lookup( m_affiliation, affiliationValues ) ); 00471 00472 if( m_actor ) 00473 new Tag( i, "actor", "jid", *m_actor ); 00474 00475 if( m_flags & FlagNonAnonymous ) 00476 new Tag( t, "status", "code", "100" ); 00477 if( m_flags & UserAffiliationChangedWNR ) 00478 new Tag( t, "status", "code", "101" ); 00479 if( m_flags & UserSelf ) 00480 new Tag( t, "status", "code", "110" ); 00481 if( m_flags & FlagPublicLogging ) 00482 new Tag( t, "status", "code", "170" ); 00483 if( m_flags & UserNewRoom ) 00484 new Tag( t, "status", "code", "201" ); 00485 if( m_flags & UserNickAssigned ) 00486 new Tag( t, "status", "code", "210" ); 00487 if( m_flags & UserBanned ) 00488 new Tag( t, "status", "code", "301" ); 00489 if( m_flags & UserNickChanged ) 00490 new Tag( t, "status", "code", "303" ); 00491 if( m_flags & UserKicked ) 00492 new Tag( t, "status", "code", "307" ); 00493 if( m_flags & UserAffiliationChanged ) 00494 new Tag( t, "status", "code", "321" ); 00495 if( m_flags & UserMembershipRequired ) 00496 new Tag( t, "status", "code", "322" ); 00497 if( m_flags & UserRoomShutdown ) 00498 new Tag( t, "status", "code", "332" ); 00499 } 00500 else if( m_del ) 00501 { 00502 Tag* d = new Tag( t, "destroy" ); 00503 if( m_alternate ) 00504 d->addAttribute( "jid", *m_alternate ); 00505 if( m_reason ) 00506 new Tag( d, "reason", *m_reason ); 00507 } 00508 else if( m_operation != OpNone && m_jid ) 00509 { 00510 Tag* d = 0; 00511 if( m_operation == OpInviteTo ) 00512 d = new Tag( t, "invite", "to", *m_jid ); 00513 else if( m_operation == OpInviteFrom ) 00514 d = new Tag( t, "invite", "from", *m_jid ); 00515 else if( m_operation == OpDeclineTo ) 00516 d = new Tag( t, "decline", "to", *m_jid ); 00517 else if( m_operation == OpDeclineFrom ) 00518 d = new Tag( t, "decline", "from", *m_jid ); 00519 00520 if( m_reason ) 00521 new Tag( d, "reason", *m_reason ); 00522 00523 if( m_continue ) 00524 { 00525 Tag* c = new Tag( d, "continue" ); 00526 if( m_thread ) 00527 c->addAttribute( "thread", *m_thread ); 00528 } 00529 00530 if( m_password ) 00531 new Tag( t, "password", *m_password ); 00532 00533 } 00534 00535 return t; 00536 } 00537 // ---- ~MUCRoom::MUCUser ---- 00538 00539 // ---- MUCRoom::MUC ---- 00540 MUCRoom::MUC::MUC( const std::string& password, 00541 MUCRoom::HistoryRequestType historyType, 00542 const std::string& historySince, 00543 int historyValue ) 00544 : StanzaExtension( ExtMUC ), 00545 m_password( password.empty() ? 0 : new std::string( password ) ), 00546 m_historySince( new std::string( historySince ) ), 00547 m_historyType( historyType ), m_historyValue( historyValue ) 00548 { 00549 } 00550 00551 MUCRoom::MUC::MUC( const Tag* tag ) 00552 : StanzaExtension( ExtMUC ), 00553 m_password( 0 ), m_historySince( 0 ), 00554 m_historyType( HistoryUnknown ), m_historyValue( 0 ) 00555 { 00556 if( !tag || tag->name() != "x" || tag->xmlns() != XMLNS_MUC_USER ) 00557 return; 00558 00559 const TagList& l = tag->children(); 00560 TagList::const_iterator it = l.begin(); 00561 for( ; it != l.end(); ++it ) 00562 { 00563 if( (*it)->name() == "history" ) 00564 { 00565 if( (*it)->hasAttribute( "seconds" ) ) 00566 m_historyValue = atoi( (*it)->findAttribute( "seconds" ).c_str() ); 00567 else if( (*it)->hasAttribute( "maxstanzas" ) ) 00568 m_historyValue = atoi( (*it)->findAttribute( "maxstanzas" ).c_str() ); 00569 else if( (*it)->hasAttribute( "maxchars" ) ) 00570 m_historyValue = atoi( (*it)->findAttribute( "maxchars" ).c_str() ); 00571 else if( (*it)->hasAttribute( "since" ) ) 00572 m_historySince = new std::string( (*it)->findAttribute( "since" ) ); 00573 } 00574 else if( (*it)->name() == "password" ) 00575 { 00576 m_password = new std::string( (*it)->cdata() ); 00577 } 00578 } 00579 } 00580 00581 MUCRoom::MUC::~MUC() 00582 { 00583 delete m_password; 00584 delete m_historySince; 00585 } 00586 00587 const std::string& MUCRoom::MUC::filterString() const 00588 { 00589 static const std::string filter = "/presence/x[@xmlns='" + XMLNS_MUC + "']"; 00590 return filter; 00591 } 00592 00593 Tag* MUCRoom::MUC::tag() const 00594 { 00595 Tag* t = new Tag( "x" ); 00596 t->setXmlns( XMLNS_MUC ); 00597 00598 if( m_historyType != HistoryUnknown ) 00599 { 00600 const std::string& histStr = util::lookup( m_historyType, historyTypeValues ); 00601 Tag* h = new Tag( t, "history" ); 00602 if( m_historyType == HistorySince && m_historySince ) 00603 h->addAttribute( histStr, *m_historySince ); 00604 else 00605 h->addAttribute( histStr, m_historyValue ); 00606 } 00607 00608 if( m_password ) 00609 new Tag( t, "password", *m_password ); 00610 00611 return t; 00612 } 00613 // ---- ~MUCRoom::MUC ---- 00614 00615 // --- MUCRoom ---- 00616 MUCRoom::MUCRoom( ClientBase* parent, const JID& nick, MUCRoomHandler* mrh, 00617 MUCRoomConfigHandler* mrch ) 00618 : m_parent( parent ), m_nick( nick ), m_joined( false ), m_roomHandler( mrh ), 00619 m_roomConfigHandler( mrch ), m_affiliation( AffiliationNone ), m_role( RoleNone ), 00620 m_historyType( HistoryUnknown ), m_historyValue( 0 ), m_flags( 0 ), 00621 m_creationInProgress( false ), m_configChanged( false ), 00622 m_publishNick( false ), m_publish( false ), m_unique( false ) 00623 { 00624 if( m_parent ) 00625 { 00626 m_parent->registerStanzaExtension( new MUCAdmin() ); 00627 m_parent->registerStanzaExtension( new MUCOwner() ); 00628 m_parent->registerStanzaExtension( new MUCUser() ); 00629 m_parent->registerStanzaExtension( new MUC() ); 00630 m_parent->registerStanzaExtension( new DelayedDelivery() ); 00631 } 00632 } 00633 00634 MUCRoom::~MUCRoom() 00635 { 00636 if( m_joined ) 00637 leave(); 00638 00639 if( m_parent ) 00640 { 00641 if( m_publish ) 00642 m_parent->disco()->removeNodeHandler( this, XMLNS_MUC_ROOMS ); 00643 00644 m_parent->removeIDHandler( this ); 00645 // m_parent->removeStanzaExtension( ExtMUCAdmin ); // don't remove, other rooms might need it 00646 // m_parent->removeStanzaExtension( ExtMUCOwner ); 00647 m_parent->removePresenceHandler( m_nick.bareJID(), this ); 00648 m_parent->disco()->removeDiscoHandler( this ); 00649 } 00650 } 00651 00652 void MUCRoom::join( Presence::PresenceType type, const std::string& status, int priority ) 00653 { 00654 if( m_joined || !m_parent ) 00655 return; 00656 00657 m_parent->registerPresenceHandler( m_nick.bareJID(), this ); 00658 00659 m_session = new MUCMessageSession( m_parent, m_nick.bareJID() ); 00660 m_session->registerMessageHandler( this ); 00661 00662 Presence pres( type, m_nick.full(), status, priority ); 00663 pres.addExtension( new MUC( m_password, m_historyType, m_historySince, m_historyValue ) ); 00664 m_joined = true; 00665 m_parent->send( pres ); 00666 } 00667 00668 void MUCRoom::leave( const std::string& msg ) 00669 { 00670 if( !m_joined ) 00671 return; 00672 00673 if( m_parent ) 00674 { 00675 Presence pres( Presence::Unavailable, m_nick.full(), msg ); 00676 m_parent->send( pres ); 00677 m_parent->removePresenceHandler( m_nick.bareJID(), this ); 00678 m_parent->disposeMessageSession( m_session ); 00679 } 00680 00681 m_session = 0; 00682 m_joined = false; 00683 } 00684 00685 void MUCRoom::destroy( const std::string& reason, const JID& alternate, const std::string& password ) 00686 { 00687 if( !m_parent ) 00688 return; 00689 00690 const std::string& id = m_parent->getID(); 00691 IQ iq( IQ::Set, m_nick.bareJID(), id ); 00692 iq.addExtension( new MUCOwner( alternate, reason, password ) ); 00693 m_parent->send( iq, this, DestroyRoom ); 00694 } 00695 00696 void MUCRoom::send( const std::string& message ) 00697 { 00698 if( m_session && m_joined ) 00699 m_session->send( message ); 00700 } 00701 00702 void MUCRoom::setSubject( const std::string& subject ) 00703 { 00704 if( m_session && m_joined ) 00705 m_session->setSubject( subject ); 00706 } 00707 00708 void MUCRoom::setNick( const std::string& nick ) 00709 { 00710 if( m_parent && m_joined ) 00711 { 00712 m_newNick = nick; 00713 00714 Presence p( Presence::Available, m_nick.bare() + "/" + m_newNick ); 00715 m_parent->send( p ); 00716 } 00717 else 00718 m_nick.setResource( nick ); 00719 } 00720 00721 void MUCRoom::getRoomInfo() 00722 { 00723 if( m_parent ) 00724 m_parent->disco()->getDiscoInfo( m_nick.bare(), EmptyString, this, GetRoomInfo ); 00725 } 00726 00727 void MUCRoom::getRoomItems() 00728 { 00729 if( m_parent ) 00730 m_parent->disco()->getDiscoItems( m_nick.bare(), EmptyString, this, GetRoomItems ); 00731 } 00732 00733 void MUCRoom::setPresence( Presence::PresenceType presence, const std::string& msg ) 00734 { 00735 if( m_parent && presence != Presence::Unavailable && m_joined ) 00736 { 00737 Presence p( presence, m_nick.full(), msg ); 00738 m_parent->send( p ); 00739 } 00740 } 00741 00742 void MUCRoom::invite( const JID& invitee, const std::string& reason, const std::string& thread ) 00743 { 00744 if( !m_parent || !m_joined ) 00745 return; 00746 00747 Message msg( Message::Normal, m_nick.bareJID() ); 00748 msg.addExtension( new MUCUser( OpInviteTo, invitee.bare(), reason, thread ) ); 00749 m_parent->send( msg ); 00750 } 00751 00752 Message* MUCRoom::declineInvitation( const JID& room, const JID& invitor, const std::string& reason ) 00753 { 00754 Message* msg = new Message( Message::Normal, room.bare() ); 00755 msg->addExtension( new MUCUser( OpDeclineTo, invitor.bare(), reason ) ); 00756 return msg; 00757 } 00758 00759 void MUCRoom::setPublish( bool publish, bool publishNick ) 00760 { 00761 m_publish = publish; 00762 m_publishNick = publishNick; 00763 00764 if( !m_parent ) 00765 return; 00766 00767 if( m_publish ) 00768 m_parent->disco()->registerNodeHandler( this, XMLNS_MUC_ROOMS ); 00769 else 00770 m_parent->disco()->removeNodeHandler( this, XMLNS_MUC_ROOMS ); 00771 } 00772 00773 void MUCRoom::addHistory( const std::string& message, const JID& from, const std::string& stamp ) 00774 { 00775 if( !m_joined || !m_parent ) 00776 return; 00777 00778 Message m( Message::Groupchat, m_nick.bareJID(), message ); 00779 m.addExtension( new DelayedDelivery( from, stamp ) ); 00780 m_parent->send( m ); 00781 } 00782 00783 void MUCRoom::setRequestHistory( int value, MUCRoom::HistoryRequestType type ) 00784 { 00785 m_historyType = type; 00786 m_historySince = EmptyString; 00787 m_historyValue = value; 00788 } 00789 00790 void MUCRoom::setRequestHistory( const std::string& since ) 00791 { 00792 m_historyType = HistorySince; 00793 m_historySince = since; 00794 m_historyValue = 0; 00795 } 00796 00797 Message* MUCRoom::createDataForm( const JID& room, const DataForm* df ) 00798 { 00799 Message* m = new Message( Message::Normal, room.bare() ); 00800 m->addExtension( df ); 00801 return m; 00802 } 00803 00804 void MUCRoom::requestVoice() 00805 { 00806 if( !m_parent || !m_joined ) 00807 return; 00808 00809 DataForm* df = new DataForm( TypeSubmit ); 00810 df->addField( DataFormField::TypeNone, "FORM_TYPE", XMLNS_MUC_REQUEST ); 00811 df->addField( DataFormField::TypeTextSingle, "muc#role", "participant", "Requested role" ); 00812 00813 Message m( Message::Normal, m_nick.bare() ); 00814 m.addExtension( df ); 00815 00816 m_parent->send( m ); 00817 } 00818 00819 void MUCRoom::setRole( const std::string& nick, MUCRoomRole role, 00820 const std::string& reason ) 00821 { 00822 if( !m_parent || !m_joined || nick.empty() || role == RoleInvalid ) 00823 return; 00824 00825 MUCOperation action = InvalidOperation; 00826 switch( role ) 00827 { 00828 case RoleNone: 00829 action = SetRNone; 00830 break; 00831 case RoleVisitor: 00832 action = SetVisitor; 00833 break; 00834 case RoleParticipant: 00835 action = SetParticipant; 00836 break; 00837 case RoleModerator: 00838 action = SetModerator; 00839 break; 00840 default: 00841 break; 00842 } 00843 00844 IQ iq( IQ::Set, m_nick.bareJID() ); 00845 iq.addExtension( new MUCAdmin( role, nick, reason ) ); 00846 00847 m_parent->send( iq, this, action ); 00848 } 00849 00850 void MUCRoom::setAffiliation( const std::string& nick, MUCRoomAffiliation affiliation, 00851 const std::string& reason ) 00852 { 00853 if( !m_parent || !m_joined || nick.empty() || affiliation == AffiliationInvalid ) 00854 return; 00855 00856 MUCOperation action = InvalidOperation; 00857 switch( affiliation ) 00858 { 00859 case AffiliationOutcast: 00860 action = SetOutcast; 00861 break; 00862 case AffiliationNone: 00863 action = SetANone; 00864 break; 00865 case AffiliationMember: 00866 action = SetMember; 00867 break; 00868 case AffiliationAdmin: 00869 action = SetAdmin; 00870 break; 00871 case AffiliationOwner: 00872 action = SetOwner; 00873 break; 00874 default: 00875 break; 00876 } 00877 00878 IQ iq( IQ::Set, m_nick.bareJID() ); 00879 iq.addExtension( new MUCAdmin( affiliation, nick, reason ) ); 00880 00881 m_parent->send( iq, this, action ); 00882 } 00883 00884 void MUCRoom::requestList( MUCOperation operation ) 00885 { 00886 if( !m_parent || !m_joined || !m_roomConfigHandler ) 00887 return; 00888 00889 IQ iq( IQ::Get, m_nick.bareJID() ); 00890 iq.addExtension( new MUCAdmin( operation ) ); 00891 m_parent->send( iq, this, operation ); 00892 } 00893 00894 void MUCRoom::storeList( const MUCListItemList items, MUCOperation operation ) 00895 { 00896 if( !m_parent || !m_joined ) 00897 return; 00898 00899 IQ iq( IQ::Set, m_nick.bareJID() ); 00900 iq.addExtension( new MUCAdmin( operation , items ) ); 00901 m_parent->send( iq, this, operation ); 00902 } 00903 00904 void MUCRoom::handlePresence( const Presence& presence ) 00905 { 00906 if( ( presence.from().bare() != m_nick.bare() ) || !m_roomHandler ) 00907 return; 00908 00909 if( presence.subtype() == Presence::Error ) 00910 { 00911 if( m_newNick.empty() ) 00912 { 00913 m_parent->removePresenceHandler( m_nick.bareJID(), this ); 00914 m_parent->disposeMessageSession( m_session ); 00915 m_joined = false; 00916 m_session = 0; 00917 } 00918 else 00919 m_newNick = ""; 00920 00921 m_roomHandler->handleMUCError( this, presence.error() 00922 ? presence.error()->error() 00923 : StanzaErrorUndefined ); 00924 } 00925 else 00926 { 00927 const MUCUser* mu = presence.findExtension<MUCUser>( ExtMUCUser ); 00928 if( !mu ) 00929 return; 00930 00931 MUCRoomParticipant party; 00932 party.nick = new JID( presence.from() ); 00933 party.status = presence.status(); 00934 party.affiliation = mu->affiliation(); 00935 party.role = mu->role(); 00936 party.jid = mu->jid() ? new JID( *(mu->jid()) ) : 0; 00937 party.actor = mu->actor() ? new JID( *(mu->actor()) ) : 0; 00938 party.reason = mu->reason() ? *(mu->reason()) : EmptyString; 00939 party.newNick = mu->newNick() ? *(mu->newNick()) : EmptyString; 00940 party.alternate = mu->alternate() ? new JID( *(mu->alternate()) ) : 0; 00941 party.flags = mu->flags(); 00942 00943 if( party.flags & FlagNonAnonymous ) 00944 setNonAnonymous(); 00945 00946 if( party.flags & UserSelf ) 00947 { 00948 m_role = party.role; 00949 m_affiliation = party.affiliation; 00950 } 00951 if( party.flags & UserNewRoom ) 00952 { 00953 m_creationInProgress = true; 00954 if( instantRoomHook() || m_roomHandler->handleMUCRoomCreation( this ) ) 00955 acknowledgeInstantRoom(); 00956 } 00957 if( party.flags & UserNickAssigned ) 00958 m_nick.setResource( presence.from().resource() ); 00959 00960 if( party.flags & UserNickChanged && !party.newNick.empty() 00961 && m_nick.resource() == presence.from().resource() 00962 && party.newNick == m_newNick ) 00963 party.flags |= UserSelf; 00964 00965 if( party.flags & UserNickChanged && party.flags & UserSelf && !party.newNick.empty() ) 00966 m_nick.setResource( party.newNick ); 00967 00968 if( m_roomHandler ) 00969 m_roomHandler->handleMUCParticipantPresence( this, party, presence ); 00970 00971 delete party.nick; 00972 } 00973 } 00974 00975 void MUCRoom::instantRoom( int context ) 00976 { 00977 if( !m_creationInProgress || !m_parent || !m_joined ) 00978 return; 00979 00980 IQ iq( IQ::Set, m_nick.bareJID() ); 00981 iq.addExtension( new MUCOwner( context == CreateInstantRoom 00982 ? MUCOwner::TypeInstantRoom : MUCOwner::TypeCancelConfig ) ); 00983 00984 m_parent->send( iq, this, context ); 00985 00986 m_creationInProgress = false; 00987 } 00988 00989 void MUCRoom::requestRoomConfig() 00990 { 00991 if( !m_parent || !m_joined ) 00992 return; 00993 00994 IQ iq( IQ::Get, m_nick.bareJID() ); 00995 iq.addExtension( new MUCOwner( MUCOwner::TypeRequestConfig ) ); 00996 00997 m_parent->send( iq, this, RequestRoomConfig ); 00998 00999 if( m_creationInProgress ) 01000 m_creationInProgress = false; 01001 } 01002 01003 void MUCRoom::setRoomConfig( DataForm* form ) 01004 { 01005 if( !m_parent || !m_joined ) 01006 return; 01007 01008 IQ iq( IQ::Set, m_nick.bareJID() ); 01009 iq.addExtension( new MUCOwner( MUCOwner::TypeSendConfig, form ) ); 01010 01011 m_parent->send( iq, this, SendRoomConfig ); 01012 } 01013 01014 void MUCRoom::setNonAnonymous() 01015 { 01016 m_flags |= FlagNonAnonymous; 01017 m_flags &= ~( FlagSemiAnonymous | FlagFullyAnonymous ); 01018 } 01019 01020 void MUCRoom::setSemiAnonymous() 01021 { 01022 m_flags &= ~( FlagNonAnonymous | FlagFullyAnonymous ); 01023 m_flags |= FlagSemiAnonymous; 01024 } 01025 01026 void MUCRoom::setFullyAnonymous() 01027 { 01028 m_flags &= ~( FlagNonAnonymous | FlagSemiAnonymous ); 01029 m_flags |= FlagFullyAnonymous; 01030 } 01031 01032 void MUCRoom::handleMessage( const Message& msg, MessageSession* /*session*/ ) 01033 { 01034 if( !m_roomHandler ) 01035 return; 01036 01037 if( msg.subtype() == Message::Error ) 01038 { 01039 m_roomHandler->handleMUCError( this, msg.error() ? msg.error()->error() : StanzaErrorUndefined ); 01040 } 01041 else 01042 { 01043 const MUCUser* mu = msg.findExtension<MUCUser>( ExtMUCUser ); 01044 if( mu ) 01045 { 01046 const int flags = mu->flags(); 01047 if( flags & FlagNonAnonymous ) 01048 setNonAnonymous(); 01049 if( flags & FlagPublicLogging ) 01050 { 01051 m_flags &= ~FlagPublicLoggingOff; 01052 m_flags |= FlagPublicLogging; 01053 } 01054 if( flags & FlagPublicLoggingOff ) 01055 { 01056 m_flags &= ~FlagPublicLogging; 01057 m_flags |= FlagPublicLoggingOff; 01058 } 01059 if( flags & FlagSemiAnonymous ) 01060 setSemiAnonymous(); 01061 if( flags & FlagFullyAnonymous ) 01062 setFullyAnonymous(); 01063 01064 if( mu->operation() == OpDeclineFrom && mu->jid() ) 01065 m_roomHandler->handleMUCInviteDecline( this, JID( *(mu->jid()) ), 01066 mu->reason() ? *(mu->reason()) : EmptyString ); 01067 } 01068 01069 const DataForm* df = msg.findExtension<DataForm>( ExtDataForm ); 01070 if( m_roomConfigHandler && df ) 01071 { 01072 m_roomConfigHandler->handleMUCRequest( this, *df ); 01073 return; 01074 } 01075 01076 if( !msg.subject().empty() ) 01077 { 01078 m_roomHandler->handleMUCSubject( this, msg.from().resource(), msg.subject() ); 01079 } 01080 else if( !msg.body().empty() ) 01081 { 01082 std::string when; 01083 bool privMsg = false; 01084 bool history = false; 01085 if( msg.when() ) 01086 { 01087 when = msg.when()->stamp(); 01088 history = true; 01089 } 01090 if( msg.subtype() & ( Message::Chat | Message::Normal ) ) 01091 privMsg = true; 01092 01093 m_roomHandler->handleMUCMessage( this, msg, privMsg ); 01094 } 01095 } 01096 } 01097 01098 void MUCRoom::handleIqID( const IQ& iq, int context ) 01099 { 01100 if( !m_roomConfigHandler ) 01101 return; 01102 01103 switch( iq.subtype() ) 01104 { 01105 case IQ::Result: 01106 handleIqResult( iq, context ); 01107 break; 01108 case IQ::Error: 01109 handleIqError( iq, context ); 01110 break; 01111 default: 01112 break; 01113 } 01114 } 01115 01116 void MUCRoom::handleIqResult( const IQ& iq, int context ) 01117 { 01118 switch( context ) 01119 { 01120 case SetRNone: 01121 case SetVisitor: 01122 case SetParticipant: 01123 case SetModerator: 01124 case SetANone: 01125 case SetOutcast: 01126 case SetMember: 01127 case SetAdmin: 01128 case SetOwner: 01129 case CreateInstantRoom: 01130 case CancelRoomCreation: 01131 case DestroyRoom: 01132 case StoreVoiceList: 01133 case StoreBanList: 01134 case StoreMemberList: 01135 case StoreModeratorList: 01136 case StoreAdminList: 01137 m_roomConfigHandler->handleMUCConfigResult( this, true, (MUCOperation)context ); 01138 break; 01139 case RequestRoomConfig: 01140 { 01141 const MUCOwner* mo = iq.findExtension<MUCOwner>( ExtMUCOwner ); 01142 if( !mo ) 01143 break; 01144 01145 if( mo->form() ) 01146 m_roomConfigHandler->handleMUCConfigForm( this, *(mo->form()) ); 01147 break; 01148 } 01149 case RequestVoiceList: 01150 case RequestBanList: 01151 case RequestMemberList: 01152 case RequestModeratorList: 01153 case RequestOwnerList: 01154 case RequestAdminList: 01155 { 01156 const MUCAdmin* ma = iq.findExtension<MUCAdmin>( ExtMUCAdmin ); 01157 if( !ma ) 01158 break; 01159 01160 m_roomConfigHandler->handleMUCConfigList( this, ma->list(), (MUCOperation)context ); 01161 break; 01162 } 01163 default: 01164 break; 01165 } 01166 } 01167 01168 void MUCRoom::handleIqError( const IQ& /*iq*/, int context ) 01169 { 01170 switch( context ) 01171 { 01172 case SetRNone: 01173 case SetVisitor: 01174 case SetParticipant: 01175 case SetModerator: 01176 case SetANone: 01177 case SetOutcast: 01178 case SetMember: 01179 case SetAdmin: 01180 case SetOwner: 01181 case CreateInstantRoom: 01182 case CancelRoomCreation: 01183 case RequestRoomConfig: 01184 case DestroyRoom: 01185 case RequestVoiceList: 01186 case StoreVoiceList: 01187 case RequestBanList: 01188 case StoreBanList: 01189 case RequestMemberList: 01190 case StoreMemberList: 01191 case RequestModeratorList: 01192 case StoreModeratorList: 01193 case RequestOwnerList: 01194 case StoreOwnerList: 01195 case RequestAdminList: 01196 case StoreAdminList: 01197 m_roomConfigHandler->handleMUCConfigResult( this, false, (MUCOperation)context ); 01198 break; 01199 } 01200 } 01201 01202 void MUCRoom::handleDiscoInfo( const JID& /*from*/, const Disco::Info& info, int context ) 01203 { 01204 switch( context ) 01205 { 01206 case GetRoomInfo: 01207 { 01208 int oldflags = m_flags; 01209 m_flags = 0; 01210 if( oldflags & FlagPublicLogging ) 01211 m_flags |= FlagPublicLogging; 01212 01213 std::string name; 01214 const StringList& l = info.features(); 01215 StringList::const_iterator it = l.begin(); 01216 for( ; it != l.end(); ++it ) 01217 { 01218 if( (*it) == "muc_hidden" ) 01219 m_flags |= FlagHidden; 01220 else if( (*it) == "muc_membersonly" ) 01221 m_flags |= FlagMembersOnly; 01222 else if( (*it) == "muc_moderated" ) 01223 m_flags |= FlagModerated; 01224 else if( (*it) == "muc_nonanonymous" ) 01225 setNonAnonymous(); 01226 else if( (*it) == "muc_open" ) 01227 m_flags |= FlagOpen; 01228 else if( (*it) == "muc_passwordprotected" ) 01229 m_flags |= FlagPasswordProtected; 01230 else if( (*it) == "muc_persistent" ) 01231 m_flags |= FlagPersistent; 01232 else if( (*it) == "muc_public" ) 01233 m_flags |= FlagPublic; 01234 else if( (*it) == "muc_semianonymous" ) 01235 setSemiAnonymous(); 01236 else if( (*it) == "muc_temporary" ) 01237 m_flags |= FlagTemporary; 01238 else if( (*it) == "muc_fullyanonymous" ) 01239 setFullyAnonymous(); 01240 else if( (*it) == "muc_unmoderated" ) 01241 m_flags |= FlagUnmoderated; 01242 else if( (*it) == "muc_unsecured" ) 01243 m_flags |= FlagUnsecured; 01244 } 01245 01246 const Disco::IdentityList& il = info.identities(); 01247 if( il.size() ) 01248 name = il.front()->name(); 01249 01250 if( m_roomHandler ) 01251 m_roomHandler->handleMUCInfo( this, m_flags, name, info.form() ); 01252 break; 01253 } 01254 default: 01255 break; 01256 } 01257 } 01258 01259 void MUCRoom::handleDiscoItems( const JID& /*from*/, const Disco::Items& items, int context ) 01260 { 01261 if( !m_roomHandler ) 01262 return; 01263 01264 switch( context ) 01265 { 01266 case GetRoomItems: 01267 { 01268 m_roomHandler->handleMUCItems( this, items.items() ); 01269 break; 01270 } 01271 default: 01272 break; 01273 } 01274 } 01275 01276 void MUCRoom::handleDiscoError( const JID& /*from*/, const Error* /*error*/, int context ) 01277 { 01278 if( !m_roomHandler ) 01279 return; 01280 01281 switch( context ) 01282 { 01283 case GetRoomInfo: 01284 m_roomHandler->handleMUCInfo( this, 0, EmptyString, 0 ); 01285 break; 01286 case GetRoomItems: 01287 m_roomHandler->handleMUCItems( this, Disco::ItemList() ); 01288 break; 01289 default: 01290 break; 01291 } 01292 } 01293 01294 StringList MUCRoom::handleDiscoNodeFeatures( const JID& /*from*/, const std::string& /*node*/ ) 01295 { 01296 return StringList(); 01297 } 01298 01299 Disco::IdentityList MUCRoom::handleDiscoNodeIdentities( const JID& /*from*/, 01300 const std::string& /*node*/ ) 01301 { 01302 return Disco::IdentityList(); 01303 } 01304 01305 Disco::ItemList MUCRoom::handleDiscoNodeItems( const JID& /*from*/, const JID& /*to*/, 01306 const std::string& node ) 01307 { 01308 Disco::ItemList l; 01309 if( node == XMLNS_MUC_ROOMS && m_publish ) 01310 { 01311 l.push_back( new Disco::Item( m_nick.bareJID(), EmptyString, 01312 m_publishNick ? m_nick.resource() : EmptyString ) ); 01313 } 01314 return l; 01315 } 01316 01317 }