gloox 1.0
|
00001 /* 00002 Copyright (c) 2004-2009 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 "softwareversion.h" 00021 #include "util.h" 00022 00023 00024 namespace gloox 00025 { 00026 00027 // ---- Disco::Identity ---- 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 // ---- ~Disco::Identity ---- 00069 00070 // ---- Disco::Info ---- 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 // ---- ~Disco::Info ---- 00156 00157 // ---- Disco::Item ---- 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 // ---- ~Disco::Item ---- 00184 00185 // ---- Disco::Items ---- 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 // ---- ~Disco::Items ---- 00241 00242 // ---- Disco ---- 00243 Disco::Disco( ClientBase* parent ) 00244 : m_parent( parent ), m_form( 0 ) 00245 { 00246 addFeature( XMLNS_VERSION ); 00247 // addFeature( XMLNS_DISCO_INFO ); //handled by Disco::Info now 00248 // addFeature( XMLNS_DISCO_ITEMS ); //handled by Disco::Info now 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(); // needed on win32 00325 identities.merge( il ); 00326 StringList fl = (*in)->handleDiscoNodeFeatures( iq.from(), info->node() ); 00327 fl.sort(); // needed on win32 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(); // needed on win32 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 }