rostermanager.cpp

00001 /*
00002   Copyright (c) 2004-2005 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 ), m_delimiterFetched( false ),
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         m_roster[m_parent->jid().bare()] = i;
00039       }
00040 
00041       m_privateXML = new PrivateXML( m_parent );
00042     }
00043   }
00044 
00045   RosterManager::~RosterManager()
00046   {
00047     if( m_parent )
00048     {
00049       m_parent->removeIqHandler( XMLNS_ROSTER );
00050       m_parent->removePresenceHandler( this );
00051       m_parent->removeSubscriptionHandler( this );
00052     }
00053 
00054     RosterListener::Roster::iterator it = m_roster.begin();
00055     for( ; it != m_roster.end(); ++it )
00056       delete( (*it).second );
00057     m_roster.clear();
00058 
00059     if( m_privateXML )
00060       delete m_privateXML;
00061   }
00062 
00063   RosterListener::Roster* RosterManager::roster()
00064   {
00065     return &m_roster;
00066   }
00067 
00068   void RosterManager::fill()
00069   {
00070     if( !m_delimiterFetched )
00071     {
00072       m_privateXML->requestXML( "roster", XMLNS_ROSTER_DELIMITER, this );
00073       return;
00074     }
00075 
00076     Tag *iq = new Tag( "iq" );
00077     iq->addAttrib( "type", "get" );
00078     iq->addAttrib( "id", m_parent->getID() );
00079     Tag *q = new Tag( "query" );
00080     q->addAttrib( "xmlns", XMLNS_ROSTER );
00081     iq->addChild( q );
00082     m_parent->send( iq );
00083   }
00084 
00085   bool RosterManager::handleIq( Stanza *stanza )
00086   {
00087     if( stanza->subtype() == STANZA_IQ_RESULT ) // initial roster
00088     {
00089       extractItems( stanza, false );
00090 
00091       if( m_rosterListener )
00092         m_rosterListener->roster( m_roster );
00093 
00094       return true;
00095     }
00096     else if( stanza->subtype() == STANZA_IQ_SET ) // roster item push
00097     {
00098       extractItems( stanza, true );
00099 
00100       Tag *iq = new Tag( "iq" );
00101       iq->addAttrib( "id", stanza->id() );
00102       iq->addAttrib( "type", "result" );
00103       m_parent->send( iq );
00104 
00105       return true;
00106     }
00107     return false;
00108   }
00109 
00110   void RosterManager::handlePresence( Stanza *stanza )
00111   {
00112     RosterListener::Roster::iterator it = m_roster.find( stanza->from().bare() );
00113     if( it != m_roster.end() )
00114     {
00115       PresenceStatus oldStat = (*it).second->status();
00116 
00117       (*it).second->setStatus( stanza->show() );
00118       (*it).second->setStatusMsg( stanza->status() );
00119 
00120       if( m_rosterListener )
00121       {
00122         if( stanza->show() == PRESENCE_AVAILABLE )
00123         {
00124           if( oldStat == PRESENCE_UNAVAILABLE )
00125             m_rosterListener->itemAvailable( (*(*it).second), stanza->status() );
00126           else
00127             m_rosterListener->itemChanged( (*(*it).second), stanza->show(), stanza->status() );
00128         }
00129         else if( stanza->show() == PRESENCE_UNAVAILABLE )
00130           m_rosterListener->itemUnavailable( (*(*it).second), stanza->status() );
00131         else
00132           m_rosterListener->itemChanged( (*(*it).second), stanza->show(), stanza->status() );
00133       }
00134     }
00135     else
00136     {
00137       StringList sl;
00138       add( stanza->from().bare(), std::string(), sl, "none", false );
00139       m_roster[stanza->from().bare()]->setStatus( stanza->show() );
00140       m_roster[stanza->from().bare()]->setStatusMsg( stanza->status() );
00141     }
00142   }
00143 
00144   void RosterManager::subscribe( const std::string& jid, const std::string& name,
00145                                  StringList& groups, const std::string& msg )
00146   {
00147     if( jid.empty() )
00148       return;
00149 
00150     add( jid, name, groups );
00151 
00152     Tag *s = new Tag( "presence" );
00153     s->addAttrib( "type", "subscribe" );
00154     s->addAttrib( "to", jid );
00155     s->addAttrib( "from", m_parent->jid().full() );
00156     if( !msg.empty() )
00157       new Tag( s, "status", msg );
00158 
00159     m_parent->send( s );
00160   }
00161 
00162 
00163   void RosterManager::add( const std::string& jid, const std::string& name, StringList& groups )
00164   {
00165     if( jid.empty() )
00166       return;
00167 
00168     std::string id = m_parent->getID();
00169 
00170     Tag *iq = new Tag( "iq" );
00171     iq->addAttrib( "type", "set" );
00172     iq->addAttrib( "id", id );
00173     Tag *q = new Tag( "query" );
00174     q->addAttrib( "xmlns", XMLNS_ROSTER );
00175     Tag *i = new Tag( "item" );
00176     i->addAttrib( "jid", jid );
00177     if( !name.empty() )
00178       i->addAttrib( "name", name );
00179 
00180     if( groups.size() != 0 )
00181     {
00182       StringList::const_iterator it = groups.begin();
00183       for( ; it != groups.end(); ++it )
00184       {
00185         Tag *g = new Tag( "group", (*it) );
00186         i->addChild( g );
00187       }
00188     }
00189     q->addChild( i );
00190     iq->addChild( q );
00191     m_parent->send( iq );
00192   }
00193 
00194   void RosterManager::unsubscribe( const std::string& jid, const std::string& msg, bool remove )
00195   {
00196     Tag *s = new Tag( "presence" );
00197     s->addAttrib( "type", "unsubscribe" );
00198     s->addAttrib( "from", m_parent->jid().bare() );
00199     s->addAttrib( "to", jid );
00200     if( !msg.empty() )
00201       new Tag( s, "status", msg );
00202 
00203     m_parent->send( s );
00204 
00205     if( remove )
00206     {
00207       std::string id = m_parent->getID();
00208 
00209       Tag *iq = new Tag( "iq" );
00210       iq->addAttrib( "type", "set" );
00211       iq->addAttrib( "id", id );
00212       Tag *q = new Tag( "query" );
00213       q->addAttrib( "xmlns", XMLNS_ROSTER );
00214       Tag *i = new Tag( "item" );
00215       i->addAttrib( "jid", jid );
00216       i->addAttrib( "subscription", "remove" );
00217       q->addChild( i );
00218       iq->addChild( q );
00219 
00220       m_parent->send( iq );
00221     }
00222   }
00223 
00224   void RosterManager::synchronize()
00225   {
00226     RosterListener::Roster::const_iterator it = m_roster.begin();
00227     for( ; it != m_roster.end(); ++it )
00228     {
00229       if( (*it).second->changed() )
00230       {
00231         std::string id = m_parent->getID();
00232 
00233         Tag *iq = new Tag( "iq" );
00234         iq->addAttrib( "type", "set" );
00235         iq->addAttrib( "id", id );
00236         Tag *q = new Tag( "query" );
00237         q->addAttrib( "xmlns", XMLNS_ROSTER );
00238         Tag *i = new Tag( "item" );
00239         i->addAttrib( "jid", (*it).second->jid() );
00240         if( !(*it).second->name().empty() )
00241           i->addAttrib( "name", (*it).second->name() );
00242 
00243         if( (*it).second->groups().size() != 0 )
00244         {
00245           StringList::const_iterator g_it = (*it).second->groups().begin();
00246           for( ; g_it != (*it).second->groups().end(); ++g_it )
00247           {
00248             i->addChild( new Tag( "group", (*g_it) ) );
00249           }
00250         }
00251         q->addChild( i );
00252         iq->addChild( q );
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->addAttrib( "type", "subscribed" );
00264     else
00265       p->addAttrib( "type", "unsubscribed" );
00266 
00267     p->addAttrib( "from", m_parent->jid().bare() );
00268     p->addAttrib( "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 STANZA_S10N_SUBSCRIBE:
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 STANZA_S10N_SUBSCRIBED:
00289       {
00290 //         Tag *p = new Tag( "presence" );
00291 //         p->addAttrib( "type", "subscribe" );
00292 //         p->addAttrib( "from", m_parent->jid().bare() );
00293 //         p->addAttrib( "to", stanza->from().bare() );
00294 //         m_parent->send( p );
00295 
00296         m_rosterListener->itemSubscribed( stanza->from().bare() );
00297         break;
00298       }
00299 
00300       case STANZA_S10N_UNSUBSCRIBE:
00301       {
00302         Tag *p = new Tag( "presence" );
00303         p->addAttrib( "type", "unsubscribed" );
00304         p->addAttrib( "from", m_parent->jid().bare() );
00305         p->addAttrib( "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 STANZA_S10N_UNSUBSCRIBED:
00315       {
00316 //         Tag *p = new Tag( "presence" );
00317 //         p->addAttrib( "type", "unsubscribe" );
00318 //         p->addAttrib( "from", m_parent->jid().bare() );
00319 //         p->addAttrib( "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 
00384           if( m_rosterListener )
00385             m_rosterListener->itemUpdated( jid );
00386         }
00387         else
00388         {
00389           const std::string sub = (*it)->findAttribute( "subscription" );
00390           if( sub == "remove" )
00391             continue;
00392           const std::string name = (*it)->findAttribute( "name" );
00393           const std::string ask = (*it)->findAttribute( "ask" );
00394           bool a = false;
00395           if( !ask.empty() )
00396             a = true;
00397 
00398           add( jid, name, gl, sub, a );
00399           if( isPush && m_rosterListener )
00400             m_rosterListener->itemAdded( jid );
00401         }
00402       }
00403     }
00404   }
00405 
00406   void RosterManager::add( const std::string& jid, const std::string& name,
00407                            StringList& groups, const std::string& sub, bool ask )
00408   {
00409     if( m_roster.find( jid ) == m_roster.end() )
00410       m_roster[jid] = new RosterItem( jid, name );
00411 
00412     m_roster[jid]->setStatus( PRESENCE_UNAVAILABLE );
00413     m_roster[jid]->setSubscription( sub, ask );
00414     m_roster[jid]->setGroups( groups );
00415   }
00416 
00417   void RosterManager::setDelimiter( const std::string& delimiter )
00418   {
00419     m_delimiter = delimiter;
00420     Tag *t = new Tag( "roster", m_delimiter );
00421     t->addAttrib( "xmlns", XMLNS_ROSTER_DELIMITER );
00422     m_privateXML->storeXML( t, this );
00423   }
00424 
00425   void RosterManager::handlePrivateXML( const std::string& /*tag*/, Tag *xml )
00426   {
00427     m_delimiterFetched = true;
00428     m_delimiter = xml->cdata();
00429     fill();
00430   }
00431 
00432   void RosterManager::handlePrivateXMLResult( const std::string /*uid*/, PrivateXMLResult result )
00433   {
00434     m_delimiterFetched = true;
00435     if( result == PrivateXMLHandler::PXML_REQUEST_ERROR )
00436       fill();
00437   }
00438 
00439 }

Generated on Mon Jan 16 16:19:54 2006 for gloox by  doxygen 1.4.6