00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
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
00030
00031 static const char* affiliationValues [] = {
00032 "none",
00033 "outcast",
00034 "member",
00035 "owner",
00036 "admin"
00037 };
00038
00039
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
00186
00187
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
00296
00297
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
00538
00539
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
00614
00615
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
00646
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* )
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& , 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& , 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& , 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& , const 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& , const std::string& )
01295 {
01296 return StringList();
01297 }
01298
01299 Disco::IdentityList MUCRoom::handleDiscoNodeIdentities( const JID& ,
01300 const std::string& )
01301 {
01302 return Disco::IdentityList();
01303 }
01304
01305 Disco::ItemList MUCRoom::handleDiscoNodeItems( const JID& , const JID& ,
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 }