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

Generated on Sun Sep 24 21:57:32 2006 for gloox by  doxygen 1.4.7