00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
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
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
00080
00081
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
00124
00125
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
00162
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
00206
00207
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
00234
00235
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
00262
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
00294
00295
00296 Disco::Disco( ClientBase* parent )
00297 : m_parent( parent )
00298 {
00299 addFeature( XMLNS_VERSION );
00300
00301
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
00316
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
00528
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 }