mucroom.cpp

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 }

Generated by  doxygen 1.6.2