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

disco.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 "disco.h"
00015 #include "discohandler.h"
00016 #include "dataform.h"
00017 #include "error.h"
00018 #include "clientbase.h"
00019 #include "disconodehandler.h"
00020 #include "util.h"
00021 
00022 
00023 namespace gloox
00024 {
00025 
00026   // ---- Disco::SoftwareVersion ----
00027   Disco::SoftwareVersion::SoftwareVersion( const std::string& name,
00028                                     const std::string& version,
00029                                     const std::string& os )
00030     : StanzaExtension( ExtVersion ), m_name( name ), m_version( version ), m_os( os )
00031   {
00032   }
00033 
00034   Disco::SoftwareVersion::SoftwareVersion( const Tag* tag )
00035     : StanzaExtension( ExtVersion )
00036   {
00037     if( !tag )
00038       return;
00039 
00040     Tag* t = tag->findChild( "name" );
00041     if( t )
00042       m_name = t->cdata();
00043 
00044     t = tag->findChild( "version" );
00045     if( t )
00046       m_version = t->cdata();
00047 
00048     t = tag->findChild( "os" );
00049     if( t )
00050       m_os = t->cdata();
00051   }
00052 
00053   Disco::SoftwareVersion::~SoftwareVersion()
00054   {
00055   }
00056 
00057   const std::string& Disco::SoftwareVersion::filterString() const
00058   {
00059     static const std::string filter = "/iq/query[@xmlns='" + XMLNS_VERSION + "']";
00060     return filter;
00061   }
00062 
00063   Tag* Disco::SoftwareVersion::tag() const
00064   {
00065     Tag* t = new Tag( "query" );
00066     t->setXmlns( XMLNS_VERSION );
00067 
00068     if( !m_name.empty() )
00069       new Tag( t, "name", m_name );
00070 
00071     if( !m_version.empty() )
00072       new Tag( t, "version", m_version );
00073 
00074     if( !m_os.empty() )
00075       new Tag( t, "os", m_os );
00076 
00077     return t;
00078   }
00079   // ---- Disco::SoftwareVersion ----
00080 
00081   // ---- Disco::Identity ----
00082 
00083   Disco::Identity::Identity( const std::string& category,
00084                              const std::string& type,
00085                              const std::string& name )
00086     : m_category( category ), m_type( type ), m_name( name )
00087   {
00088   }
00089 
00090   Disco::Identity::Identity( const Tag* tag )
00091   {
00092     if( !tag || tag->name() != "identity" )
00093       return;
00094 
00095     m_category = tag->findAttribute( "category" );
00096     m_type = tag->findAttribute( "type" );
00097     m_name = tag->findAttribute( "name" );
00098   }
00099 
00100   Disco::Identity::Identity( const Identity& id )
00101     : m_category( id.m_category ), m_type( id.m_type ), m_name( id.m_name )
00102   {
00103   }
00104 
00105   Disco::Identity::~Identity()
00106   {
00107   }
00108 
00109   Tag* Disco::Identity::tag() const
00110   {
00111     if( m_category.empty() || m_type.empty() )
00112       return 0;
00113 
00114     Tag* i = new Tag( "identity" );
00115     i->addAttribute( "category", m_category );
00116     i->addAttribute( "type", m_type );
00117 
00118     if( !m_name.empty() )
00119       i->addAttribute( "name", m_name );
00120 
00121     return i;
00122   }
00123   // ---- ~Disco::Identity ----
00124 
00125   // ---- Disco::Info ----
00126   Disco::Info::Info( const std::string& node, bool defaultFeatures )
00127     : StanzaExtension( ExtDiscoInfo ), m_node( node ), m_form( 0 )
00128   {
00129     if( defaultFeatures )
00130     {
00131       m_features.push_back( XMLNS_DISCO_INFO );
00132       m_features.push_back( XMLNS_DISCO_ITEMS );
00133     }
00134   }
00135 
00136   Disco::Info::Info( const Tag* tag )
00137     : StanzaExtension( ExtDiscoInfo ), m_form( 0 )
00138   {
00139     if( !tag || tag->name() != "query" || tag->xmlns() != XMLNS_DISCO_INFO )
00140       return;
00141 
00142     m_node = tag->findAttribute( "node" );
00143 
00144     const TagList& l = tag->children();
00145     TagList::const_iterator it = l.begin();
00146     for( ; it != l.end(); ++it )
00147     {
00148       const std::string& name = (*it)->name();
00149       if( name == "identity" )
00150         m_identities.push_back( new Identity( (*it) ) );
00151       else if( name == "feature" && (*it)->hasAttribute( "var" ) )
00152         m_features.push_back( (*it)->findAttribute( "var" ) );
00153       else if( !m_form && name == "x" && (*it)->xmlns() == XMLNS_X_DATA )
00154         m_form = new DataForm( (*it) );
00155     }
00156   }
00157 
00158   Disco::Info::~Info()
00159   {
00160     delete m_form;
00161 //     util::clearList( m_identities );
00162     // FIXME
00163     IdentityList::iterator it = m_identities.begin();
00164     IdentityList::iterator it2;
00165     while( it != m_identities.end() )
00166     {
00167       it2 = it++;
00168       delete (*it2);
00169       m_identities.erase( it2 );
00170     }
00171     // ~
00172   }
00173 
00174   bool Disco::Info::hasFeature( const std::string& feature ) const
00175   {
00176     StringList::const_iterator it = m_features.begin();
00177     for( ; it != m_features.end() && (*it) != feature; ++it )
00178       ;
00179     return it != m_features.end();
00180   }
00181 
00182   const std::string& Disco::Info::filterString() const
00183   {
00184     static const std::string filter = "/iq/query[@xmlns='" + XMLNS_DISCO_INFO + "']";
00185     return filter;
00186   }
00187 
00188   Tag* Disco::Info::tag() const
00189   {
00190     Tag* t = new Tag( "query", XMLNS, XMLNS_DISCO_INFO );
00191 
00192     if( !m_node.empty() )
00193       t->addAttribute( "node", m_node );
00194 
00195     IdentityList::const_iterator it_i = m_identities.begin();
00196     for( ; it_i != m_identities.end(); ++it_i )
00197       t->addChild( (*it_i)->tag() );
00198 
00199     StringList::const_iterator it_f = m_features.begin();
00200     for( ; it_f != m_features.end(); ++it_f )
00201       new Tag( t, "feature", "var", (*it_f) );
00202 
00203     return t;
00204   }
00205   // ---- ~Disco::Info ----
00206 
00207   // ---- Disco::Item ----
00208   Disco::Item::Item( const Tag* tag )
00209   {
00210     if( !tag || tag->name() != "item" )
00211       return;
00212 
00213     m_jid = tag->findAttribute( "jid" );
00214     m_node = tag->findAttribute( "node" );
00215     m_name = tag->findAttribute( "name" );
00216   }
00217 
00218   Tag* Disco::Item::tag() const
00219   {
00220     if( !m_jid )
00221       return 0;
00222 
00223     Tag* i = new Tag( "item" );
00224     i->addAttribute( "jid", m_jid.full() );
00225 
00226     if( !m_node.empty() )
00227       i->addAttribute( "node", m_node );
00228     if( !m_name.empty() )
00229       i->addAttribute( "name", m_name );
00230 
00231     return i;
00232   }
00233   // ---- ~Disco::Item ----
00234 
00235   // ---- Disco::Items ----
00236   Disco::Items::Items( const std::string& node )
00237     : StanzaExtension( ExtDiscoItems ), m_node( node )
00238   {
00239   }
00240 
00241   Disco::Items::Items( const Tag* tag )
00242   : StanzaExtension( ExtDiscoItems )
00243   {
00244     if( !tag || tag->name() != "query" || tag->xmlns() != XMLNS_DISCO_ITEMS )
00245       return;
00246 
00247     m_node = tag->findAttribute( "node" );
00248 
00249     const TagList& l = tag->children();
00250     TagList::const_iterator it = l.begin();
00251     for( ; it != l.end(); ++it )
00252     {
00253       const std::string& name = (*it)->name();
00254       if( name == "item" )
00255         m_items.push_back( new Item( (*it) ) );
00256     }
00257   }
00258 
00259   Disco::Items::~Items()
00260   {
00261 //     util::clearList( m_items );
00262     // FIXME
00263     ItemList::iterator it = m_items.begin();
00264     ItemList::iterator it2;
00265     while( it != m_items.end() )
00266     {
00267       it2 = it++;
00268       delete (*it2);
00269       m_items.erase( it2 );
00270     }
00271     // ~
00272   }
00273 
00274   const std::string& Disco::Items::filterString() const
00275   {
00276     static const std::string filter = "/iq/query[@xmlns='" + XMLNS_DISCO_ITEMS + "']";
00277     return filter;
00278   }
00279 
00280   Tag* Disco::Items::tag() const
00281   {
00282     Tag* t = new Tag( "query", XMLNS, XMLNS_DISCO_ITEMS );
00283 
00284     if( !m_node.empty() )
00285       t->addAttribute( "node", m_node );
00286 
00287     ItemList::const_iterator it_i = m_items.begin();
00288     for( ; it_i != m_items.end(); ++it_i )
00289       t->addChild( (*it_i)->tag() );
00290 
00291     return t;
00292   }
00293   // ---- ~Disco::Items ----
00294 
00295   // ---- Disco ----
00296   Disco::Disco( ClientBase* parent )
00297     : m_parent( parent )
00298   {
00299     addFeature( XMLNS_VERSION );
00300 //     addFeature( XMLNS_DISCO_INFO ); //handled by Disco::Info now
00301 //     addFeature( XMLNS_DISCO_ITEMS ); //handled by Disco::Info now
00302     if( m_parent )
00303     {
00304       m_parent->registerIqHandler( this, ExtDiscoInfo );
00305       m_parent->registerIqHandler( this, ExtDiscoItems );
00306       m_parent->registerIqHandler( this, ExtVersion );
00307       m_parent->registerStanzaExtension( new Disco::Info() );
00308       m_parent->registerStanzaExtension( new Disco::Items() );
00309       m_parent->registerStanzaExtension( new SoftwareVersion() );
00310     }
00311   }
00312 
00313   Disco::~Disco()
00314   {
00315 //     util::clearList( m_identities );
00316     // FIXME
00317     IdentityList::iterator it = m_identities.begin();
00318     IdentityList::iterator it2;
00319     while( it != m_identities.end() )
00320     {
00321       it2 = it++;
00322       delete (*it2);
00323       m_identities.erase( it2 );
00324     }
00325     // ~
00326 
00327     if( m_parent )
00328     {
00329       m_parent->removeIqHandler( this, ExtDiscoInfo );
00330       m_parent->removeIqHandler( this, ExtDiscoItems );
00331       m_parent->removeIqHandler( this, ExtVersion );
00332       m_parent->removeStanzaExtension( ExtDiscoInfo );
00333       m_parent->removeStanzaExtension( ExtDiscoItems );
00334       m_parent->removeStanzaExtension( ExtVersion );
00335       m_parent->removeIDHandler( this );
00336     }
00337   }
00338 
00339   bool Disco::handleIq( const IQ& iq )
00340   {
00341     switch( iq.subtype() )
00342     {
00343       case IQ::Get:
00344       {
00345         IQ re( IQ::Result, iq.from(), iq.id() );
00346 
00347         const SoftwareVersion* sv = iq.findExtension<SoftwareVersion>( ExtVersion );
00348         if( sv )
00349         {
00350           re.addExtension( new SoftwareVersion( m_versionName, m_versionVersion, m_versionOs ) );
00351           m_parent->send( re );
00352           return true;
00353         }
00354 
00355         const Info *info = iq.findExtension<Info>( ExtDiscoInfo );
00356         if( info )
00357         {
00358           Info *i = new Info( EmptyString, true );
00359           if( !info->node().empty() )
00360           {
00361             i->setNode( info->node() );
00362             IdentityList identities;
00363             StringList features;
00364             DiscoNodeHandlerMap::const_iterator it = m_nodeHandlers.find( info->node() );
00365             if( it == m_nodeHandlers.end() )
00366             {
00367               delete i;
00368               IQ re( IQ::Error, iq.from(), iq.id() );
00369               re.addExtension( new Error( StanzaErrorTypeCancel, StanzaErrorItemNotFound ) );
00370               m_parent->send( re );
00371               return true;
00372             }
00373             else
00374             {
00375               DiscoNodeHandlerList::const_iterator in = (*it).second.begin();
00376               for( ; in != (*it).second.end(); ++in )
00377               {
00378                 IdentityList il = (*in)->handleDiscoNodeIdentities( iq.from(), info->node() );
00379                 identities.merge( il );
00380                 StringList fl = (*in)->handleDiscoNodeFeatures( iq.from(), info->node() );
00381                 features.merge( fl );
00382               }
00383             }
00384             i->setIdentities( identities );
00385             i->setFeatures( features );
00386           }
00387           else
00388           {
00389             IdentityList il;
00390             IdentityList::const_iterator it = m_identities.begin();
00391             for( ; it != m_identities.end(); ++it )
00392             {
00393               il.push_back( new Identity( *(*it) ) );
00394             }
00395             i->setIdentities( il );
00396             i->setFeatures( m_features );
00397           }
00398 
00399           re.addExtension( i );
00400           m_parent->send( re );
00401           return true;
00402         }
00403 
00404         const Items *items = iq.findExtension<Items>( ExtDiscoItems );
00405         if( items )
00406         {
00407           Items *i = new Items( items->node() );
00408           if( !items->node().empty() )
00409           {
00410             DiscoNodeHandlerMap::const_iterator it = m_nodeHandlers.find( items->node() );
00411             if( it == m_nodeHandlers.end() )
00412             {
00413               delete i;
00414               IQ re( IQ::Error, iq.from(), iq.id() );
00415               re.addExtension( new Error( StanzaErrorTypeCancel, StanzaErrorItemNotFound ) );
00416               m_parent->send( re );
00417               return true;
00418             }
00419             else
00420             {
00421               ItemList itemlist;
00422               DiscoNodeHandlerList::const_iterator in = (*it).second.begin();
00423               for( ; in != (*it).second.end(); ++in )
00424               {
00425                 ItemList il = (*in)->handleDiscoNodeItems( iq.from(), items->node() );
00426                 itemlist.merge( il );
00427               }
00428               i->setItems( itemlist );
00429             }
00430           }
00431 
00432           re.addExtension( i );
00433           m_parent->send( re );
00434           return true;
00435         }
00436         break;
00437       }
00438 
00439       case IQ::Set:
00440       {
00441         bool res = false;
00442         DiscoHandlerList::const_iterator it = m_discoHandlers.begin();
00443         for( ; it != m_discoHandlers.end(); ++it )
00444         {
00445           if( (*it)->handleDiscoSet( iq ) )
00446             res = true;
00447         }
00448         return res;
00449         break;
00450       }
00451 
00452       default:
00453         break;
00454     }
00455     return false;
00456   }
00457 
00458   void Disco::handleIqID( const IQ& iq, int context )
00459   {
00460     DiscoHandlerMap::iterator it = m_track.find( iq.id() );
00461     if( it != m_track.end() )
00462     {
00463       switch( iq.subtype() )
00464       {
00465         case IQ::Result:
00466           switch( context )
00467           {
00468             case GetDiscoInfo:
00469             {
00470               const Info* di = iq.findExtension<Info>( ExtDiscoInfo );
00471               if( di )
00472                 (*it).second.dh->handleDiscoInfo( iq.from(), *di, (*it).second.context );
00473               break;
00474             }
00475             case GetDiscoItems:
00476             {
00477               const Items* di = iq.findExtension<Items>( ExtDiscoItems );
00478               if( di )
00479                 (*it).second.dh->handleDiscoItems( iq.from(), *di, (*it).second.context );
00480               break;
00481             }
00482           }
00483           break;
00484 
00485         case IQ::Error:
00486         {
00487           (*it).second.dh->handleDiscoError( iq.from(), iq.error(), (*it).second.context );
00488           break;
00489         }
00490 
00491         default:
00492           break;
00493       }
00494 
00495       m_track.erase( it );
00496     }
00497   }
00498 
00499   void Disco::getDisco( const JID& to, const std::string& node, DiscoHandler* dh, int context,
00500                         IdType idType, const std::string& tid )
00501   {
00502     const std::string& id = tid.empty() ? m_parent->getID() : tid;
00503 
00504     IQ iq( IQ::Get, to, id );
00505     if( idType == GetDiscoInfo )
00506       iq.addExtension( new Info( node ) );
00507     else
00508       iq.addExtension( new Items( node ) );
00509 
00510     DiscoHandlerContext ct;
00511     ct.dh = dh;
00512     ct.context = context;
00513     m_track[id] = ct;
00514     m_parent->send( iq, this, idType );
00515   }
00516 
00517   void Disco::setVersion( const std::string& name, const std::string& version, const std::string& os )
00518   {
00519     m_versionName = name;
00520     m_versionVersion = version;
00521     m_versionOs = os;
00522   }
00523 
00524   void Disco::setIdentity( const std::string& category, const std::string& type,
00525                            const std::string& name )
00526   {
00527 //     util::clearList( m_identities );
00528     // FIXME
00529     IdentityList::iterator it = m_identities.begin();
00530     IdentityList::iterator it2;
00531     while( it != m_identities.end() )
00532     {
00533       it2 = it++;
00534       delete (*it2);
00535       m_identities.erase( it2 );
00536     }
00537     // ~
00538 
00539     addIdentity( category, type, name );
00540   }
00541 
00542   void Disco::registerNodeHandler( DiscoNodeHandler* nh, const std::string& node )
00543   {
00544     m_nodeHandlers[node].push_back( nh );
00545   }
00546 
00547   void Disco::removeNodeHandler( DiscoNodeHandler* nh, const std::string& node )
00548   {
00549     DiscoNodeHandlerMap::iterator it = m_nodeHandlers.find( node );
00550     if( it != m_nodeHandlers.end() )
00551     {
00552       (*it).second.remove( nh );
00553       if( (*it).second.empty() )
00554         m_nodeHandlers.erase( it );
00555     }
00556   }
00557 
00558   void Disco::removeNodeHandlers( DiscoNodeHandler* nh )
00559   {
00560     DiscoNodeHandlerMap::iterator it = m_nodeHandlers.begin();
00561     DiscoNodeHandlerMap::iterator it2;
00562     while( it != m_nodeHandlers.end() )
00563     {
00564       it2 = it++;
00565       removeNodeHandler( nh, (*it2).first );
00566     }
00567   }
00568 
00569 }

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