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