rostermanager.cpp

00001 /*
00002   Copyright (c) 2004-2006 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, bool self )
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       if( self )
00036       {
00037         RosterItem *i = new RosterItem( m_parent->jid().bare() );
00038         i->setSynchronized();
00039         m_roster[m_parent->jid().bare()] = i;
00040       }
00041 
00042       m_privateXML = new PrivateXML( m_parent );
00043     }
00044   }
00045 
00046   RosterManager::~RosterManager()
00047   {
00048     if( m_parent )
00049     {
00050       m_parent->removeIqHandler( XMLNS_ROSTER );
00051       m_parent->removePresenceHandler( this );
00052       m_parent->removeSubscriptionHandler( this );
00053     }
00054 
00055     RosterListener::Roster::iterator it = m_roster.begin();
00056     for( ; it != m_roster.end(); ++it )
00057       delete (*it).second;
00058     m_roster.clear();
00059 
00060     if( m_privateXML )
00061       delete m_privateXML;
00062   }
00063 
00064   RosterListener::Roster* RosterManager::roster()
00065   {
00066     return &m_roster;
00067   }
00068 
00069   void RosterManager::fill()
00070   {
00071     m_privateXML->requestXML( "roster", XMLNS_ROSTER_DELIMITER, this );
00072 
00073     Tag *iq = new Tag( "iq" );
00074     iq->addAttribute( "type", "get" );
00075     iq->addAttribute( "id", m_parent->getID() );
00076     Tag *q = new Tag( iq, "query" );
00077     q->addAttribute( "xmlns", XMLNS_ROSTER );
00078     m_parent->send( iq );
00079   }
00080 
00081   bool RosterManager::handleIq( Stanza *stanza )
00082   {
00083     if( stanza->subtype() == StanzaIqResult ) // initial roster
00084     {
00085       extractItems( stanza, false );
00086 
00087       if( m_rosterListener )
00088         m_rosterListener->roster( m_roster );
00089 
00090       m_parent->rosterFilled();
00091 
00092       return true;
00093     }
00094     else if( stanza->subtype() == StanzaIqSet ) // roster item push
00095     {
00096       extractItems( stanza, true );
00097 
00098       Tag *iq = new Tag( "iq" );
00099       iq->addAttribute( "id", stanza->id() );
00100       iq->addAttribute( "type", "result" );
00101       m_parent->send( iq );
00102 
00103       return true;
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     RosterListener::Roster::iterator it = m_roster.find( stanza->from().bare() );
00120     if( it != m_roster.end() )
00121     {
00122       bool online = (*it).second->online();
00123 
00124       (*it).second->setStatus( stanza->from().resource(), stanza->show() );
00125       (*it).second->setStatusMsg( stanza->from().resource(), stanza->status() );
00126       (*it).second->setPriority( stanza->from().resource(), stanza->priority() );
00127 
00128       if( m_rosterListener && stanza->show() == PresenceAvailable )
00129       {
00130         if( !online )
00131           m_rosterListener->itemAvailable( (*(*it).second), stanza->status(), stanza->from() );
00132         else
00133           m_rosterListener->presenceUpdated( (*(*it).second), stanza->show(), stanza->status() );
00134       }
00135       else if( stanza->show() == PresenceUnavailable )
00136       {
00137         (*it).second->removeResource( stanza->from().resource() );
00138         if( m_rosterListener )
00139           m_rosterListener->itemUnavailable( (*(*it).second), stanza->status(), stanza->from() );
00140       }
00141       else
00142         if( m_rosterListener )
00143           m_rosterListener->presenceUpdated( (*(*it).second), stanza->show(), stanza->status() );
00144     }
00145     else
00146     {
00147       StringList sl;
00148       add( stanza->from().bare(), "", sl, "none", false );
00149       m_roster[stanza->from().bare()]->setStatus( stanza->from().resource(), stanza->show() );
00150       m_roster[stanza->from().bare()]->setStatusMsg( stanza->from().resource(), stanza->status() );
00151       m_roster[stanza->from().bare()]->setPriority( stanza->from().resource(), stanza->priority() );
00152       if( m_rosterListener )
00153         m_rosterListener->nonrosterPresenceReceived( stanza->from() );
00154     }
00155   }
00156 
00157   void RosterManager::subscribe( const std::string& jid, const std::string& name,
00158                                  StringList& groups, const std::string& msg )
00159   {
00160     if( jid.empty() )
00161       return;
00162 
00163     add( jid, name, groups );
00164 
00165     Tag *s = new Tag( "presence" );
00166     s->addAttribute( "type", "subscribe" );
00167     s->addAttribute( "to", jid );
00168     s->addAttribute( "from", m_parent->jid().full() );
00169     if( !msg.empty() )
00170       new Tag( s, "status", msg );
00171 
00172     m_parent->send( s );
00173   }
00174 
00175 
00176   void RosterManager::add( const std::string& jid, const std::string& name, StringList& groups )
00177   {
00178     if( jid.empty() )
00179       return;
00180 
00181     std::string id = m_parent->getID();
00182 
00183     Tag *iq = new Tag( "iq" );
00184     iq->addAttribute( "type", "set" );
00185     iq->addAttribute( "id", id );
00186     Tag *q = new Tag( iq, "query" );
00187     q->addAttribute( "xmlns", XMLNS_ROSTER );
00188     Tag *i = new Tag( q, "item" );
00189     i->addAttribute( "jid", jid );
00190     if( !name.empty() )
00191       i->addAttribute( "name", name );
00192 
00193     if( groups.size() != 0 )
00194     {
00195       StringList::const_iterator it = groups.begin();
00196       for( ; it != groups.end(); ++it )
00197         new Tag( i, "group", (*it) );
00198     }
00199 
00200     m_parent->send( iq );
00201   }
00202 
00203   void RosterManager::unsubscribe( const std::string& jid, const std::string& msg, bool remove )
00204   {
00205     Tag *s = new Tag( "presence" );
00206     s->addAttribute( "type", "unsubscribe" );
00207     s->addAttribute( "from", m_parent->jid().bare() );
00208     s->addAttribute( "to", jid );
00209     if( !msg.empty() )
00210       new Tag( s, "status", msg );
00211 
00212     m_parent->send( s );
00213 
00214     if( remove )
00215     {
00216       std::string id = m_parent->getID();
00217 
00218       Tag *iq = new Tag( "iq" );
00219       iq->addAttribute( "type", "set" );
00220       iq->addAttribute( "id", id );
00221       Tag *q = new Tag( iq, "query" );
00222       q->addAttribute( "xmlns", XMLNS_ROSTER );
00223       Tag *i = new Tag( q, "item" );
00224       i->addAttribute( "jid", jid );
00225       i->addAttribute( "subscription", "remove" );
00226 
00227       m_parent->send( iq );
00228     }
00229   }
00230 
00231   void RosterManager::synchronize()
00232   {
00233     RosterListener::Roster::const_iterator it = m_roster.begin();
00234     for( ; it != m_roster.end(); ++it )
00235     {
00236       if( (*it).second->changed() )
00237       {
00238         std::string id = m_parent->getID();
00239 
00240         Tag *iq = new Tag( "iq" );
00241         iq->addAttribute( "type", "set" );
00242         iq->addAttribute( "id", id );
00243         Tag *q = new Tag( iq, "query" );
00244         q->addAttribute( "xmlns", XMLNS_ROSTER );
00245         Tag *i = new Tag( q, "item" );
00246         i->addAttribute( "jid", (*it).second->jid() );
00247         if( !(*it).second->name().empty() )
00248           i->addAttribute( "name", (*it).second->name() );
00249 
00250         if( (*it).second->groups().size() != 0 )
00251         {
00252           StringList::const_iterator g_it = (*it).second->groups().begin();
00253           for( ; g_it != (*it).second->groups().end(); ++g_it )
00254             new Tag( i, "group", (*g_it) );
00255         }
00256 
00257         m_parent->send( iq );
00258       }
00259     }
00260   }
00261 
00262   void RosterManager::ackSubscriptionRequest( const JID& to, bool ack )
00263   {
00264     Tag *p = new Tag( "presence" );
00265     if( ack )
00266       p->addAttribute( "type", "subscribed" );
00267     else
00268       p->addAttribute( "type", "unsubscribed" );
00269 
00270     p->addAttribute( "from", m_parent->jid().bare() );
00271     p->addAttribute( "to", to.bare() );
00272     m_parent->send( p );
00273   }
00274 
00275   void RosterManager::handleSubscription( Stanza *stanza )
00276   {
00277     if( !m_rosterListener )
00278       return;
00279 
00280     switch( stanza->subtype() )
00281     {
00282       case StanzaS10nSubscribe:
00283       {
00284         bool answer = m_rosterListener->subscriptionRequest( stanza->from().bare(), stanza->status() );
00285         if( m_syncSubscribeReq )
00286         {
00287           ackSubscriptionRequest( stanza->from(), answer );
00288         }
00289         break;
00290       }
00291       case StanzaS10nSubscribed:
00292       {
00293 //         Tag *p = new Tag( "presence" );
00294 //         p->addAttribute( "type", "subscribe" );
00295 //         p->addAttribute( "from", m_parent->jid().bare() );
00296 //         p->addAttribute( "to", stanza->from().bare() );
00297 //         m_parent->send( p );
00298 
00299         m_rosterListener->itemSubscribed( stanza->from().bare() );
00300         break;
00301       }
00302 
00303       case StanzaS10nUnsubscribe:
00304       {
00305         Tag *p = new Tag( "presence" );
00306         p->addAttribute( "type", "unsubscribed" );
00307         p->addAttribute( "from", m_parent->jid().bare() );
00308         p->addAttribute( "to", stanza->from().bare() );
00309         m_parent->send( p );
00310 
00311         bool answer = m_rosterListener->unsubscriptionRequest( stanza->from().bare(), stanza->status() );
00312         if( m_syncSubscribeReq && answer )
00313           unsubscribe( stanza->from().bare(), "", true );
00314         break;
00315       }
00316 
00317       case StanzaS10nUnsubscribed:
00318       {
00319 //         Tag *p = new Tag( "presence" );
00320 //         p->addAttribute( "type", "unsubscribe" );
00321 //         p->addAttribute( "from", m_parent->jid().bare() );
00322 //         p->addAttribute( "to", stanza->from().bare() );
00323 //         m_parent->send( p );
00324 
00325         m_rosterListener->itemUnsubscribed( stanza->from().bare() );
00326         break;
00327       }
00328 
00329       default:
00330         break;
00331     }
00332   }
00333 
00334   void RosterManager::registerRosterListener( RosterListener *rl, bool syncSubscribeReq )
00335   {
00336     m_syncSubscribeReq = syncSubscribeReq;
00337     m_rosterListener = rl;
00338   }
00339 
00340   void RosterManager::removeRosterListener()
00341   {
00342     m_syncSubscribeReq = false;
00343     m_rosterListener = 0;
00344   }
00345 
00346   void RosterManager::extractItems( Tag *tag, bool isPush )
00347   {
00348     Tag *t = tag->findChild( "query" );
00349     Tag::TagList l = t->children();
00350     Tag::TagList::iterator it = l.begin();
00351     for( ; it != l.end(); ++it )
00352     {
00353       if( (*it)->name() == "item" )
00354       {
00355         StringList gl;
00356         if( (*it)->hasChild( "group" ) )
00357         {
00358           Tag::TagList g = (*it)->children();
00359           Tag::TagList::const_iterator it_g = g.begin();
00360           for( ; it_g != g.end(); ++it_g )
00361           {
00362             gl.push_back( (*it_g)->cdata() );
00363           }
00364         }
00365 
00366         const std::string jid = (*it)->findAttribute( "jid" );
00367         RosterListener::Roster::iterator it_d = m_roster.find( jid );
00368         if( it_d != m_roster.end() )
00369         {
00370           (*it_d).second->setName( (*it)->findAttribute( "name" ) );
00371           const std::string sub = (*it)->findAttribute( "subscription" );
00372           if( sub == "remove" )
00373           {
00374             delete (*it_d).second;
00375             m_roster.erase( it_d );
00376             if( m_rosterListener )
00377               m_rosterListener->itemRemoved( jid );
00378             continue;
00379           }
00380           const std::string ask = (*it)->findAttribute( "ask" );
00381           bool a = false;
00382           if( !ask.empty() )
00383             a = true;
00384           (*it_d).second->setSubscription( sub, a );
00385           (*it_d).second->setGroups( gl );
00386           (*it_d).second->setSynchronized();
00387 
00388           if( isPush && m_rosterListener )
00389             m_rosterListener->itemUpdated( jid );
00390         }
00391         else
00392         {
00393           const std::string sub = (*it)->findAttribute( "subscription" );
00394           if( sub == "remove" )
00395             continue;
00396           const std::string name = (*it)->findAttribute( "name" );
00397           const std::string ask = (*it)->findAttribute( "ask" );
00398           bool a = false;
00399           if( !ask.empty() )
00400             a = true;
00401 
00402           add( jid, name, gl, sub, a );
00403           if( isPush && m_rosterListener )
00404             m_rosterListener->itemAdded( jid );
00405         }
00406       }
00407     }
00408   }
00409 
00410   void RosterManager::add( const std::string& jid, const std::string& name,
00411                            StringList& groups, const std::string& sub, bool ask )
00412   {
00413     if( m_roster.find( jid ) == m_roster.end() )
00414       m_roster[jid] = new RosterItem( jid, name );
00415 
00416     m_roster[jid]->setSubscription( sub, ask );
00417     m_roster[jid]->setGroups( groups );
00418     m_roster[jid]->setSynchronized();
00419   }
00420 
00421   void RosterManager::setDelimiter( const std::string& delimiter )
00422   {
00423     m_delimiter = delimiter;
00424     Tag *t = new Tag( "roster", m_delimiter );
00425     t->addAttribute( "xmlns", XMLNS_ROSTER_DELIMITER );
00426     m_privateXML->storeXML( t, this );
00427   }
00428 
00429   void RosterManager::handlePrivateXML( const std::string& /*tag*/, Tag *xml )
00430   {
00431     m_delimiter = xml->cdata();
00432   }
00433 
00434   void RosterManager::handlePrivateXMLResult( const std::string& /*uid*/, PrivateXMLResult /*result*/ )
00435   {
00436   }
00437 
00438   RosterItem* RosterManager::getRosterItem( const JID& jid )
00439   {
00440     RosterListener::Roster::const_iterator it = m_roster.find( jid.bare() );
00441     if( it != m_roster.end() )
00442       return (*it).second;
00443     else
00444       return 0;
00445   }
00446 
00447 }

Generated on Tue May 1 14:20:20 2007 for gloox by  doxygen 1.5.1