Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | Related Pages

rostermanager.cpp

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

Generated on Mon Jun 23 10:50:19 2008 for gloox by  doxygen 1.4.1