gloox 1.0

rostermanager.cpp

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 }