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 "rosterlistener.h"
00019 #include "privatexml.h"
00020 
00021 
00022 namespace gloox
00023 {
00024 
00025   RosterManager::RosterManager( ClientBase *parent )
00026     : m_rosterListener( 0 ), m_parent( parent ), m_privateXML( 0 ),
00027       m_syncSubscribeReq( false )
00028   {
00029     if( m_parent )
00030     {
00031       m_parent->registerIqHandler( this, XMLNS_ROSTER );
00032       m_parent->registerPresenceHandler( this );
00033       m_parent->registerSubscriptionHandler( this );
00034 
00035       m_self = new RosterItem( m_parent->jid().bare() );
00036 
00037       m_privateXML = new PrivateXML( m_parent );
00038     }
00039   }
00040 
00041   RosterManager::~RosterManager()
00042   {
00043     if( m_parent )
00044     {
00045       m_parent->removeIqHandler( XMLNS_ROSTER );
00046       m_parent->removeIDHandler( this );
00047       m_parent->removePresenceHandler( this );
00048       m_parent->removeSubscriptionHandler( this );
00049       delete m_self;
00050       delete m_privateXML;
00051     }
00052 
00053     Roster::iterator it = m_roster.begin();
00054     for( ; it != m_roster.end(); ++it )
00055       delete (*it).second;
00056     m_roster.clear();
00057   }
00058 
00059   Roster* RosterManager::roster()
00060   {
00061     return &m_roster;
00062   }
00063 
00064   void RosterManager::fill()
00065   {
00066     m_privateXML->requestXML( "roster", XMLNS_ROSTER_DELIMITER, this );
00067 
00068     Tag *iq = new Tag( "iq" );
00069     iq->addAttribute( "type", "get" );
00070     iq->addAttribute( "id", m_parent->getID() );
00071     Tag *q = new Tag( iq, "query" );
00072     q->addAttribute( "xmlns", XMLNS_ROSTER );
00073     m_parent->send( iq );
00074   }
00075 
00076   bool RosterManager::handleIq( Stanza *stanza )
00077   {
00078     if( stanza->subtype() == StanzaIqResult ) // initial roster
00079     {
00080       extractItems( stanza, false );
00081 
00082       if( m_rosterListener )
00083         m_rosterListener->handleRoster( m_roster );
00084 
00085       m_parent->rosterFilled();
00086 
00087       return true;
00088     }
00089     else if( stanza->subtype() == StanzaIqSet ) // roster item push
00090     {
00091       extractItems( stanza, true );
00092 
00093       Tag *iq = new Tag( "iq" );
00094       iq->addAttribute( "id", stanza->id() );
00095       iq->addAttribute( "type", "result" );
00096       m_parent->send( iq );
00097 
00098       return true;
00099     }
00100     else if( stanza->subtype() == StanzaIqError )
00101     {
00102       if( m_rosterListener )
00103         m_rosterListener->handleRosterError( stanza );
00104     }
00105 
00106     return false;
00107   }
00108 
00109   bool RosterManager::handleIqID( Stanza * /*stanza*/, int /*context*/ )
00110   {
00111     return false;
00112   }
00113 
00114   void RosterManager::handlePresence( Stanza *stanza )
00115   {
00116     if( stanza->subtype() == StanzaPresenceError )
00117       return;
00118 
00119     StringList caps;
00120     const Tag::TagList& l = stanza->children();
00121     Tag::TagList::const_iterator it_c = l.begin();
00122     for( ; it_c != l.end(); ++it_c )
00123     {
00124       if( (*it_c)->name() == "c" )
00125       {
00126         std::string cap;
00127         cap.append( (*it_c)->findAttribute( "node" ).c_str() );
00128         cap.append( "#" );
00129         cap.append( (*it_c)->findAttribute( "ver" ).c_str() );
00130         if( (*it_c)->findAttribute( "ext" ).size ())
00131         {
00132           cap.append( "#" );
00133           cap.append( (*it_c)->findAttribute( "ext" ).c_str() );
00134         }
00135         caps.push_back( cap );
00136       }
00137     }
00138 
00139     Roster::iterator it = m_roster.find( stanza->from().bare() );
00140     if( it != m_roster.end() )
00141     {
00142       if( stanza->presence() == PresenceUnavailable )
00143         (*it).second->removeResource( stanza->from().resource() );
00144       else
00145       {
00146         (*it).second->setPresence( stanza->from().resource(), stanza->presence() );
00147         (*it).second->setStatus( stanza->from().resource(), stanza->status() );
00148         (*it).second->setPriority( stanza->from().resource(), stanza->priority() );
00149   //       (*it).second->setCaps ( caps );
00150       }
00151 
00152       if( m_rosterListener )
00153         m_rosterListener->handleRosterPresence( (*(*it).second), stanza->from().resource(),
00154                                                 stanza->presence(), stanza->status() );
00155     }
00156     else if( stanza->from().bare() == m_self->jid() )
00157     {
00158       if( stanza->presence() == PresenceUnavailable )
00159         m_self->removeResource( stanza->from().resource() );
00160       else
00161       {
00162         m_self->setPresence( stanza->from().resource(), stanza->presence() );
00163         m_self->setStatus( stanza->from().resource(), stanza->status() );
00164         m_self->setPriority( stanza->from().resource(), stanza->priority() );
00165   //       (*it).second->setCaps ( caps );
00166       }
00167 
00168       if( m_rosterListener )
00169         m_rosterListener->handleSelfPresence( *m_self, stanza->from().resource(),
00170                                               stanza->presence(), stanza->status() );
00171     }
00172     else
00173     {
00174       if( m_rosterListener )
00175         m_rosterListener->handleNonrosterPresence( stanza );
00176     }
00177   }
00178 
00179   void RosterManager::subscribe( const JID& jid, const std::string& name,
00180                                  const StringList& groups, const std::string& msg )
00181   {
00182     if( !jid )
00183       return;
00184 
00185     add( jid, name, groups );
00186 
00187     Tag *s = new Tag( "presence" );
00188     s->addAttribute( "type", "subscribe" );
00189     s->addAttribute( "to", jid.bare() );
00190     s->addAttribute( "from", m_parent->jid().full() );
00191     if( !msg.empty() )
00192       new Tag( s, "status", msg );
00193 
00194     m_parent->send( s );
00195   }
00196 
00197 
00198   void RosterManager::add( const JID& jid, const std::string& name, const StringList& groups )
00199   {
00200     if( !jid )
00201       return;
00202 
00203     const std::string& id = m_parent->getID();
00204 
00205     Tag *iq = new Tag( "iq" );
00206     iq->addAttribute( "type", "set" );
00207     iq->addAttribute( "id", id );
00208     Tag *q = new Tag( iq, "query" );
00209     q->addAttribute( "xmlns", XMLNS_ROSTER );
00210     Tag *i = new Tag( q, "item" );
00211     i->addAttribute( "jid", jid.bare() );
00212     if( !name.empty() )
00213       i->addAttribute( "name", name );
00214 
00215     if( groups.size() != 0 )
00216     {
00217       StringList::const_iterator it = groups.begin();
00218       for( ; it != groups.end(); ++it )
00219         new Tag( i, "group", (*it) );
00220     }
00221 
00222     m_parent->send( iq );
00223   }
00224 
00225   void RosterManager::unsubscribe( const JID& jid, const std::string& msg )
00226   {
00227     Tag *s = new Tag( "presence" );
00228     s->addAttribute( "type", "unsubscribe" );
00229     s->addAttribute( "to", jid.bare() );
00230     if( !msg.empty() )
00231       new Tag( s, "status", msg );
00232 
00233     m_parent->send( s );
00234 
00235   }
00236 
00237   void RosterManager::cancel( const JID& jid, const std::string& msg )
00238   {
00239     Tag *s = new Tag( "presence" );
00240     s->addAttribute( "type", "unsubscribed" );
00241     s->addAttribute( "to", jid.bare() );
00242     if( !msg.empty() )
00243       new Tag( s, "status", msg );
00244 
00245     m_parent->send( s );
00246 
00247   }
00248 
00249   void RosterManager::remove( const JID& jid )
00250   {
00251     const std::string& id = m_parent->getID();
00252 
00253     Tag *iq = new Tag( "iq" );
00254     iq->addAttribute( "type", "set" );
00255     iq->addAttribute( "id", id );
00256     Tag *q = new Tag( iq, "query" );
00257     q->addAttribute( "xmlns", XMLNS_ROSTER );
00258     Tag *i = new Tag( q, "item" );
00259     i->addAttribute( "jid", jid.bare() );
00260     i->addAttribute( "subscription", "remove" );
00261 
00262     m_parent->send( iq );
00263   }
00264 
00265   void RosterManager::synchronize()
00266   {
00267     Roster::const_iterator it = m_roster.begin();
00268     for( ; it != m_roster.end(); ++it )
00269     {
00270       if( (*it).second->changed() )
00271       {
00272         const std::string& id = m_parent->getID();
00273 
00274         Tag *iq = new Tag( "iq" );
00275         iq->addAttribute( "type", "set" );
00276         iq->addAttribute( "id", id );
00277         Tag *q = new Tag( iq, "query" );
00278         q->addAttribute( "xmlns", XMLNS_ROSTER );
00279         Tag *i = new Tag( q, "item" );
00280         i->addAttribute( "jid", (*it).second->jid() );
00281         if( !(*it).second->name().empty() )
00282           i->addAttribute( "name", (*it).second->name() );
00283 
00284         if( (*it).second->groups().size() != 0 )
00285         {
00286           StringList::const_iterator g_it = (*it).second->groups().begin();
00287           for( ; g_it != (*it).second->groups().end(); ++g_it )
00288             new Tag( i, "group", (*g_it) );
00289         }
00290 
00291         m_parent->send( iq );
00292       }
00293     }
00294   }
00295 
00296   void RosterManager::ackSubscriptionRequest( const JID& to, bool ack )
00297   {
00298     Tag *p = new Tag( "presence" );
00299     if( ack )
00300       p->addAttribute( "type", "subscribed" );
00301     else
00302       p->addAttribute( "type", "unsubscribed" );
00303 
00304     p->addAttribute( "to", to.bare() );
00305     m_parent->send( p );
00306   }
00307 
00308   void RosterManager::handleSubscription( Stanza *stanza )
00309   {
00310     if( !m_rosterListener )
00311       return;
00312 
00313     switch( stanza->subtype() )
00314     {
00315       case StanzaS10nSubscribe:
00316       {
00317         bool answer = m_rosterListener->handleSubscriptionRequest( stanza->from(), stanza->status() );
00318         if( m_syncSubscribeReq )
00319         {
00320           ackSubscriptionRequest( stanza->from(), answer );
00321         }
00322         break;
00323       }
00324       case StanzaS10nSubscribed:
00325       {
00326 //         Tag *p = new Tag( "presence" );
00327 //         p->addAttribute( "type", "subscribe" );
00328 //         p->addAttribute( "to", stanza->from().bare() );
00329 //         m_parent->send( p );
00330 
00331         m_rosterListener->handleItemSubscribed( stanza->from() );
00332         break;
00333       }
00334 
00335       case StanzaS10nUnsubscribe:
00336       {
00337         Tag *p = new Tag( "presence" );
00338         p->addAttribute( "type", "unsubscribed" );
00339         p->addAttribute( "to", stanza->from().bare() );
00340         m_parent->send( p );
00341 
00342         bool answer = m_rosterListener->handleUnsubscriptionRequest( stanza->from(), stanza->status() );
00343         if( m_syncSubscribeReq && answer )
00344           remove( stanza->from().bare() );
00345         break;
00346       }
00347 
00348       case StanzaS10nUnsubscribed:
00349       {
00350 //         Tag *p = new Tag( "presence" );
00351 //         p->addAttribute( "type", "unsubscribe" );
00352 //         p->addAttribute( "to", stanza->from().bare() );
00353 //         m_parent->send( p );
00354 
00355         m_rosterListener->handleItemUnsubscribed( stanza->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::extractItems( Tag *tag, bool isPush )
00377   {
00378     Tag *t = tag->findChild( "query" );
00379     const Tag::TagList& l = t->children();
00380     Tag::TagList::const_iterator it = l.begin();
00381     for( ; it != l.end(); ++it )
00382     {
00383       if( (*it)->name() == "item" )
00384       {
00385         StringList gl;
00386         if( (*it)->hasChild( "group" ) )
00387         {
00388           const Tag::TagList& g = (*it)->children();
00389           Tag::TagList::const_iterator it_g = g.begin();
00390           for( ; it_g != g.end(); ++it_g )
00391           {
00392             gl.push_back( (*it_g)->cdata() );
00393           }
00394         }
00395 
00396         const JID& jid = (*it)->findAttribute( "jid" );
00397         Roster::iterator it_d = m_roster.find( jid.bare() );
00398         if( it_d != m_roster.end() )
00399         {
00400           (*it_d).second->setName( (*it)->findAttribute( "name" ) );
00401           const std::string& sub = (*it)->findAttribute( "subscription" );
00402           if( sub == "remove" )
00403           {
00404             delete (*it_d).second;
00405             m_roster.erase( it_d );
00406             if( m_rosterListener )
00407               m_rosterListener->handleItemRemoved( jid );
00408             continue;
00409           }
00410           const std::string& ask = (*it)->findAttribute( "ask" );
00411           bool a = false;
00412           if( !ask.empty() )
00413             a = true;
00414           (*it_d).second->setSubscription( sub, a );
00415           (*it_d).second->setGroups( gl );
00416           (*it_d).second->setSynchronized();
00417 
00418           if( isPush && m_rosterListener )
00419             m_rosterListener->handleItemUpdated( jid );
00420         }
00421         else
00422         {
00423           const std::string& sub = (*it)->findAttribute( "subscription" );
00424           if( sub == "remove" )
00425             continue;
00426           const std::string& name = (*it)->findAttribute( "name" );
00427           const std::string& ask = (*it)->findAttribute( "ask" );
00428           bool a = false;
00429           if( !ask.empty() )
00430             a = true;
00431 
00432           StringList caps;
00433           add( jid.bare(), name, gl, caps, sub, a );
00434           if( isPush && m_rosterListener )
00435             m_rosterListener->handleItemAdded( jid );
00436         }
00437       }
00438     }
00439   }
00440 
00441   void RosterManager::add( const std::string& jid, const std::string& name,
00442                            const StringList& groups, const StringList& caps,
00443                            const std::string& sub, bool ask )
00444   {
00445     if( m_roster.find( jid ) == m_roster.end() )
00446       m_roster[jid] = new RosterItem( jid, name );
00447 
00448     m_roster[jid]->setSubscription( sub, ask );
00449     m_roster[jid]->setGroups( groups );
00450 //     m_roster[jid]->setCaps( caps );
00451     m_roster[jid]->setSynchronized();
00452   }
00453 
00454   void RosterManager::setDelimiter( const std::string& delimiter )
00455   {
00456     m_delimiter = delimiter;
00457     Tag *t = new Tag( "roster", m_delimiter );
00458     t->addAttribute( "xmlns", XMLNS_ROSTER_DELIMITER );
00459     m_privateXML->storeXML( t, this );
00460   }
00461 
00462   void RosterManager::handlePrivateXML( const std::string& /*tag*/, Tag *xml )
00463   {
00464     m_delimiter = xml->cdata();
00465   }
00466 
00467   void RosterManager::handlePrivateXMLResult( const std::string& /*uid*/, PrivateXMLResult /*result*/ )
00468   {
00469   }
00470 
00471   RosterItem* RosterManager::getRosterItem( const JID& jid )
00472   {
00473     Roster::const_iterator it = m_roster.find( jid.bare() );
00474     if( it != m_roster.end() )
00475       return (*it).second;
00476     else
00477       return 0;
00478   }
00479 
00480 }

Generated on Fri Oct 10 15:26:11 2008 for gloox by  doxygen 1.5.6