gloox 1.0
|
00001 /* 00002 Copyright (c) 2004-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 #include "clientbase.h" 00015 #include "rostermanager.h" 00016 #include "disco.h" 00017 #include "rosteritem.h" 00018 #include "rosteritemdata.h" 00019 #include "rosterlistener.h" 00020 #include "privatexml.h" 00021 #include "util.h" 00022 #include "stanzaextension.h" 00023 #include "capabilities.h" 00024 00025 00026 namespace gloox 00027 { 00028 00029 // ---- RosterManager::Query ---- 00030 RosterManager::Query::Query( const JID& jid, const std::string& name, const StringList& groups ) 00031 : StanzaExtension( ExtRoster ) 00032 { 00033 m_roster.push_back( new RosterItemData( jid.bare(), name, groups ) ); 00034 } 00035 00036 RosterManager::Query::Query( const JID& jid ) 00037 : StanzaExtension( ExtRoster ) 00038 { 00039 m_roster.push_back( new RosterItemData( jid.bare() ) ); 00040 } 00041 00042 RosterManager::Query::Query( const Tag* tag ) 00043 : StanzaExtension( ExtRoster ) 00044 { 00045 if( !tag || tag->name() != "query" || tag->xmlns() != XMLNS_ROSTER ) 00046 return; 00047 00048 const ConstTagList& l = tag->findTagList( "query/item" ); 00049 ConstTagList::const_iterator it = l.begin(); 00050 for( ; it != l.end(); ++it ) 00051 { 00052 StringList groups; 00053 const ConstTagList& g = (*it)->findTagList( "item/group" ); 00054 ConstTagList::const_iterator it_g = g.begin(); 00055 for( ; it_g != g.end(); ++it_g ) 00056 groups.push_back( (*it_g)->cdata() ); 00057 00058 const std::string sub = (*it)->findAttribute( "subscription" ); 00059 if( sub == "remove" ) 00060 m_roster.push_back( new RosterItemData( (*it)->findAttribute( "jid" ) ) ); 00061 else 00062 { 00063 RosterItemData* rid = new RosterItemData( (*it)->findAttribute( "jid" ), 00064 (*it)->findAttribute( "name" ), 00065 groups ); 00066 rid->setSubscription( sub, (*it)->findAttribute( "ask" ) ); 00067 m_roster.push_back( rid ); 00068 } 00069 } 00070 } 00071 00072 RosterManager::Query::~Query() 00073 { 00074 util::clearList( m_roster ); 00075 } 00076 00077 const std::string& RosterManager::Query::filterString() const 00078 { 00079 static const std::string filter = "/iq/query[@xmlns='" + XMLNS_ROSTER + "']"; 00080 return filter; 00081 } 00082 00083 Tag* RosterManager::Query::tag() const 00084 { 00085 Tag* t = new Tag( "query" ); 00086 t->setXmlns( XMLNS_ROSTER ); 00087 00088 RosterData::const_iterator it = m_roster.begin(); 00089 for( ; it != m_roster.end(); ++it ) 00090 t->addChild( (*it)->tag() ); 00091 00092 return t; 00093 } 00094 00095 StanzaExtension* RosterManager::Query::clone() const 00096 { 00097 Query* q = new Query(); 00098 RosterData::const_iterator it = m_roster.begin(); 00099 for( ; it != m_roster.end(); ++it ) 00100 { 00101 q->m_roster.push_back( new RosterItemData( *(*it) ) ); 00102 } 00103 return q; 00104 } 00105 // ---- ~RosterManager::Query ---- 00106 00107 // ---- RosterManager ---- 00108 RosterManager::RosterManager( ClientBase* parent ) 00109 : m_rosterListener( 0 ), m_parent( parent ), m_privateXML( 0 ), 00110 m_syncSubscribeReq( false ) 00111 { 00112 if( m_parent ) 00113 { 00114 m_parent->registerIqHandler( this, ExtRoster ); 00115 m_parent->registerPresenceHandler( this ); 00116 m_parent->registerSubscriptionHandler( this ); 00117 m_parent->registerStanzaExtension( new Query() ); 00118 00119 m_self = new RosterItem( m_parent->jid().bare() ); 00120 m_privateXML = new PrivateXML( m_parent ); 00121 } 00122 } 00123 00124 RosterManager::~RosterManager() 00125 { 00126 if( m_parent ) 00127 { 00128 m_parent->removeIqHandler( this, ExtRoster ); 00129 m_parent->removeIDHandler( this ); 00130 m_parent->removePresenceHandler( this ); 00131 m_parent->removeSubscriptionHandler( this ); 00132 m_parent->removeStanzaExtension( ExtRoster ); 00133 delete m_self; 00134 delete m_privateXML; 00135 } 00136 00137 util::clearMap( m_roster ); 00138 } 00139 00140 Roster* RosterManager::roster() 00141 { 00142 return &m_roster; 00143 } 00144 00145 void RosterManager::fill() 00146 { 00147 if( !m_parent ) 00148 return; 00149 00150 util::clearMap( m_roster ); 00151 m_privateXML->requestXML( "roster", XMLNS_ROSTER_DELIMITER, this ); 00152 IQ iq( IQ::Get, JID(), m_parent->getID() ); 00153 iq.addExtension( new Query() ); 00154 m_parent->send( iq, this, RequestRoster ); 00155 } 00156 00157 bool RosterManager::handleIq( const IQ& iq ) 00158 { 00159 if( iq.subtype() != IQ::Set ) // FIXME add checks for 'from' attribute (empty or bare self jid?) 00160 return false; 00161 00162 // single roster item push 00163 const Query* q = iq.findExtension<Query>( ExtRoster ); 00164 if( q && q->roster().size() ) 00165 mergePush( q->roster() ); 00166 00167 IQ re( IQ::Result, JID(), iq.id() ); 00168 m_parent->send( re ); 00169 return true; 00170 } 00171 00172 void RosterManager::handleIqID( const IQ& iq, int context ) 00173 { 00174 if( iq.subtype() == IQ::Result ) // initial roster 00175 { 00176 const Query* q = iq.findExtension<Query>( ExtRoster ); 00177 if( q ) 00178 mergeRoster( q->roster() ); 00179 00180 if( context == RequestRoster ) 00181 { 00182 if( m_parent ) 00183 m_parent->rosterFilled(); 00184 00185 if( m_rosterListener ) 00186 m_rosterListener->handleRoster( m_roster ); 00187 } 00188 } 00189 else if( iq.subtype() == IQ::Error ) 00190 { 00191 if( context == RequestRoster && m_parent ) 00192 m_parent->rosterFilled(); 00193 00194 if( m_rosterListener ) 00195 m_rosterListener->handleRosterError( iq ); 00196 } 00197 } 00198 00199 void RosterManager::handlePresence( const Presence& presence ) 00200 { 00201 if( presence.subtype() == Presence::Error ) 00202 return; 00203 00204 bool self = false; 00205 Roster::iterator it = m_roster.find( presence.from().bare() ); 00206 if( it != m_roster.end() || ( self = ( presence.from().bare() == m_self->jid() ) ) ) 00207 { 00208 RosterItem* ri = self ? m_self : (*it).second; 00209 const std::string& resource = presence.from().resource(); 00210 00211 if( presence.presence() == Presence::Unavailable ) 00212 ri->removeResource( resource ); 00213 else 00214 { 00215 ri->setPresence( resource, presence.presence() ); 00216 ri->setStatus( resource, presence.status() ); 00217 ri->setPriority( resource, presence.priority() ); 00218 ri->setExtensions( resource, presence.extensions() ); 00219 } 00220 00221 if( m_rosterListener && !self ) 00222 m_rosterListener->handleRosterPresence( *ri, resource, 00223 presence.presence(), presence.status() ); 00224 else if( m_rosterListener && self ) 00225 m_rosterListener->handleSelfPresence( *ri, resource, 00226 presence.presence(), presence.status() ); 00227 } 00228 else 00229 { 00230 if( m_rosterListener ) 00231 m_rosterListener->handleNonrosterPresence( presence ); 00232 } 00233 } 00234 00235 void RosterManager::subscribe( const JID& jid, const std::string& name, 00236 const StringList& groups, const std::string& msg ) 00237 { 00238 if( !jid ) 00239 return; 00240 00241 add( jid, name, groups ); 00242 00243 Subscription s( Subscription::Subscribe, jid.bareJID(), msg ); 00244 m_parent->send( s ); 00245 } 00246 00247 00248 void RosterManager::add( const JID& jid, const std::string& name, const StringList& groups ) 00249 { 00250 if( !jid ) 00251 return; 00252 00253 IQ iq( IQ::Set, JID(), m_parent->getID() ); 00254 iq.addExtension( new Query( jid, name, groups) ); 00255 00256 m_parent->send( iq, this, AddRosterItem ); 00257 } 00258 00259 void RosterManager::unsubscribe( const JID& jid, const std::string& msg ) 00260 { 00261 Subscription p( Subscription::Unsubscribe, jid.bareJID(), msg ); 00262 m_parent->send( p ); 00263 } 00264 00265 void RosterManager::cancel( const JID& jid, const std::string& msg ) 00266 { 00267 Subscription p( Subscription::Unsubscribed, jid.bareJID(), msg ); 00268 m_parent->send( p ); 00269 } 00270 00271 void RosterManager::remove( const JID& jid ) 00272 { 00273 if( !jid ) 00274 return; 00275 00276 IQ iq( IQ::Set, JID(), m_parent->getID() ); 00277 iq.addExtension( new Query( jid ) ); 00278 00279 m_parent->send( iq, this, RemoveRosterItem ); 00280 } 00281 00282 void RosterManager::synchronize() 00283 { 00284 Roster::const_iterator it = m_roster.begin(); 00285 for( ; it != m_roster.end(); ++it ) 00286 { 00287 if( !(*it).second->changed() ) 00288 continue; 00289 00290 IQ iq( IQ::Set, JID(), m_parent->getID() ); 00291 iq.addExtension( new Query( (*it).second->jid(), (*it).second->name(), (*it).second->groups() ) ); 00292 m_parent->send( iq, this, SynchronizeRoster ); 00293 } 00294 } 00295 00296 void RosterManager::ackSubscriptionRequest( const JID& to, bool ack ) 00297 { 00298 Subscription p( ack ? Subscription::Subscribed 00299 : Subscription::Unsubscribed, to.bareJID() ); 00300 m_parent->send( p ); 00301 } 00302 00303 void RosterManager::handleSubscription( const Subscription& s10n ) 00304 { 00305 if( !m_rosterListener ) 00306 return; 00307 00308 switch( s10n.subtype() ) 00309 { 00310 case Subscription::Subscribe: 00311 { 00312 bool answer = m_rosterListener->handleSubscriptionRequest( s10n.from(), s10n.status() ); 00313 if( m_syncSubscribeReq ) 00314 { 00315 ackSubscriptionRequest( s10n.from(), answer ); 00316 } 00317 break; 00318 } 00319 case Subscription::Subscribed: 00320 { 00321 m_rosterListener->handleItemSubscribed( s10n.from() ); 00322 break; 00323 } 00324 00325 case Subscription::Unsubscribe: 00326 { 00327 Subscription p( Subscription::Unsubscribed, s10n.from().bareJID() ); 00328 m_parent->send( p ); 00329 00330 bool answer = m_rosterListener->handleUnsubscriptionRequest( s10n.from(), s10n.status() ); 00331 if( m_syncSubscribeReq && answer ) 00332 remove( s10n.from().bare() ); 00333 break; 00334 } 00335 00336 case Subscription::Unsubscribed: 00337 { 00338 m_rosterListener->handleItemUnsubscribed( s10n.from() ); 00339 break; 00340 } 00341 00342 default: 00343 break; 00344 } 00345 } 00346 00347 void RosterManager::registerRosterListener( RosterListener* rl, bool syncSubscribeReq ) 00348 { 00349 m_syncSubscribeReq = syncSubscribeReq; 00350 m_rosterListener = rl; 00351 } 00352 00353 void RosterManager::removeRosterListener() 00354 { 00355 m_syncSubscribeReq = false; 00356 m_rosterListener = 0; 00357 } 00358 00359 void RosterManager::setDelimiter( const std::string& delimiter ) 00360 { 00361 m_delimiter = delimiter; 00362 Tag* t = new Tag( "roster", m_delimiter ); 00363 t->addAttribute( XMLNS, XMLNS_ROSTER_DELIMITER ); 00364 m_privateXML->storeXML( t, this ); 00365 } 00366 00367 void RosterManager::handlePrivateXML( const Tag* xml ) 00368 { 00369 if( xml ) 00370 m_delimiter = xml->cdata(); 00371 } 00372 00373 void RosterManager::handlePrivateXMLResult( const std::string& /*uid*/, PrivateXMLResult /*result*/ ) 00374 { 00375 } 00376 00377 RosterItem* RosterManager::getRosterItem( const JID& jid ) 00378 { 00379 Roster::const_iterator it = m_roster.find( jid.bare() ); 00380 return it != m_roster.end() ? (*it).second : 0; 00381 } 00382 00383 void RosterManager::mergePush( const RosterData& data ) 00384 { 00385 RosterData::const_iterator it = data.begin(); 00386 for( ; it != data.end(); ++it ) 00387 { 00388 Roster::iterator itr = m_roster.find( (*it)->jid() ); 00389 if( itr != m_roster.end() ) 00390 { 00391 if( (*it)->remove() ) 00392 { 00393 if( m_rosterListener ) 00394 m_rosterListener->handleItemRemoved( (*it)->jid() ); 00395 delete (*itr).second; 00396 m_roster.erase( itr ); 00397 } 00398 else 00399 { 00400 (*itr).second->setData( *(*it) ); 00401 if( m_rosterListener ) 00402 m_rosterListener->handleItemUpdated( (*it)->jid() ); 00403 } 00404 } 00405 else if( !(*it)->remove() ) 00406 { 00407 m_roster.insert( std::make_pair( (*it)->jid(), new RosterItem( *(*it) ) ) ); 00408 if( m_rosterListener ) 00409 m_rosterListener->handleItemAdded( (*it)->jid() ); 00410 } 00411 } 00412 } 00413 00414 void RosterManager::mergeRoster( const RosterData& data ) 00415 { 00416 RosterData::const_iterator it = data.begin(); 00417 for( ; it != data.end(); ++it ) 00418 m_roster.insert( std::make_pair( (*it)->jid(), new RosterItem( *(*it) ) ) ); 00419 } 00420 00421 }