disco.cpp
/*
Copyright (c) 2004-2023 by Jakob Schröter <js@camaya.net>
This file is part of the gloox library. http://camaya.net/gloox
This software is distributed under a license. The full license
agreement can be found in the file LICENSE in this distribution.
This software may not be copied, modified, sold or distributed
other than expressed in the named license agreement.
This software is distributed without any warranty.
*/
#include "disco.h"
#include "discohandler.h"
#include "dataform.h"
#include "error.h"
#include "clientbase.h"
#include "disconodehandler.h"
#include "softwareversion.h"
#include "util.h"
namespace gloox
{
// ---- Disco::Identity ----
Disco::Identity::Identity( const std::string& category,
const std::string& type,
const std::string& name )
: m_category( category ), m_type( type ), m_name( name )
{
}
Disco::Identity::Identity( const Tag* tag )
{
if( !tag || tag->name() != "identity" )
return;
m_category = tag->findAttribute( "category" );
m_type = tag->findAttribute( "type" );
m_name = tag->findAttribute( "name" );
}
Disco::Identity::Identity( const Identity& id )
: m_category( id.m_category ), m_type( id.m_type ), m_name( id.m_name )
{
}
Disco::Identity::~Identity()
{
}
Tag* Disco::Identity::tag() const
{
if( m_category.empty() || m_type.empty() )
return 0;
Tag* i = new Tag( "identity" );
i->addAttribute( "category", m_category );
i->addAttribute( "type", m_type );
if( !m_name.empty() )
i->addAttribute( "name", m_name );
return i;
}
// ---- ~Disco::Identity ----
// ---- Disco::Info ----
Disco::Info::Info( const std::string& node, bool defaultFeatures )
: StanzaExtension( ExtDiscoInfo ), m_node( node ), m_form( 0 )
{
if( defaultFeatures )
{
m_features.push_back( XMLNS_DISCO_INFO );
m_features.push_back( XMLNS_DISCO_ITEMS );
}
}
Disco::Info::Info( const Tag* tag )
: StanzaExtension( ExtDiscoInfo ), m_form( 0 )
{
if( !tag || tag->name() != "query" || tag->xmlns() != XMLNS_DISCO_INFO )
return;
m_node = tag->findAttribute( "node" );
const TagList& l = tag->children();
TagList::const_iterator it = l.begin();
for( ; it != l.end(); ++it )
{
const std::string& name = (*it)->name();
if( name == "identity" )
m_identities.push_back( new Identity( (*it) ) );
else if( name == "feature" && (*it)->hasAttribute( "var" ) )
m_features.push_back( (*it)->findAttribute( "var" ) );
else if( !m_form && name == "x" && (*it)->xmlns() == XMLNS_X_DATA )
m_form = new DataForm( (*it) );
}
}
Disco::Info::Info( const Info& info )
: StanzaExtension( ExtDiscoInfo ), m_node( info.m_node ), m_features( info.m_features ),
m_identities( info.m_identities ), m_form( info.m_form ? new DataForm( *(info.m_form) ) : 0 )
{
}
Disco::Info::~Info()
{
delete m_form;
util::clearList( m_identities );
}
void Disco::Info::setForm( DataForm* form )
{
delete m_form;
m_form = form;
}
bool Disco::Info::hasFeature( const std::string& feature ) const
{
StringList::const_iterator it = m_features.begin();
for( ; it != m_features.end() && (*it) != feature; ++it )
;
return it != m_features.end();
}
const std::string& Disco::Info::filterString() const
{
static const std::string filter = "/iq/query[@xmlns='" + XMLNS_DISCO_INFO + "']";
return filter;
}
Tag* Disco::Info::tag() const
{
Tag* t = new Tag( "query", XMLNS, XMLNS_DISCO_INFO );
if( !m_node.empty() )
t->addAttribute( "node", m_node );
IdentityList::const_iterator it_i = m_identities.begin();
for( ; it_i != m_identities.end(); ++it_i )
t->addChild( (*it_i)->tag() );
StringList::const_iterator it_f = m_features.begin();
for( ; it_f != m_features.end(); ++it_f )
new Tag( t, "feature", "var", (*it_f) );
if( m_form )
t->addChild( m_form->tag() );
return t;
}
// ---- ~Disco::Info ----
// ---- Disco::Item ----
Disco::Item::Item( const Tag* tag )
{
if( !tag || tag->name() != "item" )
return;
m_jid = tag->findAttribute( "jid" );
m_node = tag->findAttribute( "node" );
m_name = tag->findAttribute( "name" );
}
Tag* Disco::Item::tag() const
{
if( !m_jid )
return 0;
Tag* i = new Tag( "item" );
i->addAttribute( "jid", m_jid.full() );
if( !m_node.empty() )
i->addAttribute( "node", m_node );
if( !m_name.empty() )
i->addAttribute( "name", m_name );
return i;
}
// ---- ~Disco::Item ----
// ---- Disco::Items ----
Disco::Items::Items( const std::string& node )
: StanzaExtension( ExtDiscoItems ), m_node( node )
{
}
Disco::Items::Items( const Tag* tag )
: StanzaExtension( ExtDiscoItems )
{
if( !tag || tag->name() != "query" || tag->xmlns() != XMLNS_DISCO_ITEMS )
return;
m_node = tag->findAttribute( "node" );
const TagList& l = tag->children();
TagList::const_iterator it = l.begin();
for( ; it != l.end(); ++it )
{
const std::string& name = (*it)->name();
if( name == "item" )
m_items.push_back( new Item( (*it) ) );
}
}
Disco::Items::~Items()
{
util::clearList( m_items );
}
void Disco::Items::setItems( const ItemList& items )
{
util::clearList( m_items );
m_items = items;
}
const std::string& Disco::Items::filterString() const
{
static const std::string filter = "/iq/query[@xmlns='" + XMLNS_DISCO_ITEMS + "']";
return filter;
}
Tag* Disco::Items::tag() const
{
Tag* t = new Tag( "query", XMLNS, XMLNS_DISCO_ITEMS );
if( !m_node.empty() )
t->addAttribute( "node", m_node );
ItemList::const_iterator it_i = m_items.begin();
for( ; it_i != m_items.end(); ++it_i )
t->addChild( (*it_i)->tag() );
return t;
}
// ---- ~Disco::Items ----
// ---- Disco ----
Disco::Disco( ClientBase* parent )
: m_parent( parent ), m_form( 0 )
{
addFeature( XMLNS_VERSION );
// addFeature( XMLNS_DISCO_INFO ); //handled by Disco::Info now
// addFeature( XMLNS_DISCO_ITEMS ); //handled by Disco::Info now
if( m_parent )
{
m_parent->registerIqHandler( this, ExtDiscoInfo );
m_parent->registerIqHandler( this, ExtDiscoItems );
m_parent->registerIqHandler( this, ExtVersion );
m_parent->registerStanzaExtension( new Disco::Info() );
m_parent->registerStanzaExtension( new Disco::Items() );
m_parent->registerStanzaExtension( new SoftwareVersion() );
}
}
Disco::~Disco()
{
util::clearList( m_identities );
delete m_form;
if( m_parent )
{
m_parent->removeIqHandler( this, ExtDiscoInfo );
m_parent->removeIqHandler( this, ExtDiscoItems );
m_parent->removeIqHandler( this, ExtVersion );
m_parent->removeStanzaExtension( ExtDiscoInfo );
m_parent->removeStanzaExtension( ExtDiscoItems );
m_parent->removeStanzaExtension( ExtVersion );
m_parent->removeIDHandler( this );
}
}
void Disco::setForm( DataForm* form )
{
delete m_form;
m_form = form;
}
bool Disco::handleIq( const IQ& iq )
{
switch( iq.subtype() )
{
case IQ::Get:
{
IQ re( IQ::Result, iq.from(), iq.id() );
re.setFrom( iq.to() );
const SoftwareVersion* sv = iq.findExtension<SoftwareVersion>( ExtVersion );
if( sv )
{
re.addExtension( new SoftwareVersion( m_versionName, m_versionVersion, m_versionOs ) );
m_parent->send( re );
return true;
}
const Info *info = iq.findExtension<Info>( ExtDiscoInfo );
if( info )
{
Info *i = new Info( EmptyString, true );
if( !info->node().empty() )
{
i->setNode( info->node() );
IdentityList identities;
StringList features;
DiscoNodeHandlerMap::const_iterator it = m_nodeHandlers.find( info->node() );
if( it == m_nodeHandlers.end() )
{
delete i;
IQ re( IQ::Error, iq.from(), iq.id() );
re.addExtension( new Error( StanzaErrorTypeCancel, StanzaErrorItemNotFound ) );
m_parent->send( re );
return true;
}
else
{
DiscoNodeHandlerList::const_iterator in = (*it).second.begin();
for( ; in != (*it).second.end(); ++in )
{
IdentityList il = (*in)->handleDiscoNodeIdentities( iq.from(), info->node() );
il.sort(); // needed on win32
identities.merge( il );
StringList fl = (*in)->handleDiscoNodeFeatures( iq.from(), info->node() );
fl.sort(); // needed on win32
features.merge( fl );
}
}
i->setIdentities( identities );
i->setFeatures( features );
}
else
{
IdentityList il;
IdentityList::const_iterator it = m_identities.begin();
for( ; it != m_identities.end(); ++it )
{
il.push_back( new Identity( *(*it) ) );
}
i->setIdentities( il );
i->setFeatures( m_features );
if( m_form )
i->setForm( new DataForm( *m_form ) );
}
re.addExtension( i );
m_parent->send( re );
return true;
}
const Items *items = iq.findExtension<Items>( ExtDiscoItems );
if( items )
{
Items *i = new Items( items->node() );
if( !items->node().empty() )
{
DiscoNodeHandlerMap::const_iterator it = m_nodeHandlers.find( items->node() );
if( it == m_nodeHandlers.end() )
{
delete i;
IQ re( IQ::Error, iq.from(), iq.id() );
re.addExtension( new Error( StanzaErrorTypeCancel, StanzaErrorItemNotFound ) );
m_parent->send( re );
return true;
}
else
{
ItemList itemlist;
DiscoNodeHandlerList::const_iterator in = (*it).second.begin();
for( ; in != (*it).second.end(); ++in )
{
ItemList il = (*in)->handleDiscoNodeItems( iq.from(), iq.to(), items->node() );
il.sort(); // needed on win32
itemlist.merge( il );
}
i->setItems( itemlist );
}
}
re.addExtension( i );
m_parent->send( re );
return true;
}
break;
}
case IQ::Set:
{
bool res = false;
DiscoHandlerList::const_iterator it = m_discoHandlers.begin();
for( ; it != m_discoHandlers.end(); ++it )
{
if( (*it)->handleDiscoSet( iq ) )
res = true;
}
return res;
break;
}
default:
break;
}
return false;
}
void Disco::handleIqID( const IQ& iq, int context )
{
DiscoHandlerMap::iterator it = m_track.find( iq.id() );
if( it != m_track.end() && (*it).second.dh )
{
switch( iq.subtype() )
{
case IQ::Result:
switch( context )
{
case GetDiscoInfo:
{
const Info* di = iq.findExtension<Info>( ExtDiscoInfo );
if( di )
(*it).second.dh->handleDiscoInfo( iq.from(), *di, (*it).second.context );
break;
}
case GetDiscoItems:
{
const Items* di = iq.findExtension<Items>( ExtDiscoItems );
if( di )
(*it).second.dh->handleDiscoItems( iq.from(), *di, (*it).second.context );
break;
}
}
break;
case IQ::Error:
{
(*it).second.dh->handleDiscoError( iq.from(), iq.error(), (*it).second.context );
break;
}
default:
break;
}
m_track.erase( it );
}
}
void Disco::getDisco( const JID& to, const std::string& node, DiscoHandler* dh, int context,
IdType idType, const std::string& tid )
{
const std::string& id = tid.empty() ? m_parent->getID() : tid;
IQ iq( IQ::Get, to, id );
if( idType == GetDiscoInfo )
iq.addExtension( new Info( node ) );
else
iq.addExtension( new Items( node ) );
DiscoHandlerContext ct;
ct.dh = dh;
ct.context = context;
m_track[id] = ct;
m_parent->send( iq, this, idType );
}
void Disco::setVersion( const std::string& name, const std::string& version, const std::string& os )
{
m_versionName = name;
m_versionVersion = version;
m_versionOs = os;
}
void Disco::setIdentity( const std::string& category, const std::string& type,
const std::string& name )
{
util::clearList( m_identities );
addIdentity( category, type, name );
}
void Disco::removeDiscoHandler( DiscoHandler* dh )
{
m_discoHandlers.remove( dh );
DiscoHandlerMap::iterator t;
DiscoHandlerMap::iterator it = m_track.begin();
while( it != m_track.end() )
{
t = it;
++it;
if( dh == (*t).second.dh )
{
m_track.erase( t );
}
}
}
void Disco::registerNodeHandler( DiscoNodeHandler* nh, const std::string& node )
{
m_nodeHandlers[node].push_back( nh );
}
void Disco::removeNodeHandler( DiscoNodeHandler* nh, const std::string& node )
{
DiscoNodeHandlerMap::iterator it = m_nodeHandlers.find( node );
if( it != m_nodeHandlers.end() )
{
(*it).second.remove( nh );
if( (*it).second.empty() )
m_nodeHandlers.erase( it );
}
}
void Disco::removeNodeHandlers( DiscoNodeHandler* nh )
{
DiscoNodeHandlerMap::iterator it = m_nodeHandlers.begin();
DiscoNodeHandlerMap::iterator it2;
while( it != m_nodeHandlers.end() )
{
it2 = it++;
removeNodeHandler( nh, (*it2).first );
}
}
const StringList Disco::features( bool defaultFeatures ) const
{
StringList f = m_features;
if( defaultFeatures )
{
f.push_back( XMLNS_DISCO_INFO );
f.push_back( XMLNS_DISCO_ITEMS );
}
return f;
}
}
gloox::ClientBase::getID
const std::string getID()
Definition clientbase.cpp:1168
gloox::ClientBase::removeIqHandler
void removeIqHandler(IqHandler *ih, int exttype)
Definition clientbase.cpp:1391
gloox::ClientBase::removeIDHandler
void removeIDHandler(IqHandler *ih)
Definition clientbase.cpp:1359
gloox::ClientBase::removeStanzaExtension
bool removeStanzaExtension(int ext)
Definition clientbase.cpp:1110
gloox::ClientBase::send
void send(Tag *tag)
Definition clientbase.cpp:1004
gloox::DataForm
An abstraction of a XEP-0004 Data Form.
Definition dataform.h:57
gloox::DiscoHandler
A virtual interface that enables objects to receive Service Discovery (XEP-0030) events.
Definition discohandler.h:35
gloox::DiscoNodeHandler
Derived classes can be registered as NodeHandlers for certain nodes with the Disco object.
Definition disconodehandler.h:36
gloox::Disco::Identity
An abstraction of a Disco identity (Service Discovery, XEP-0030).
Definition disco.h:197
gloox::Disco::Identity::category
const std::string & category() const
Definition disco.h:228
gloox::Disco::Identity::name
const std::string & name() const
Definition disco.h:240
gloox::Disco::Identity::~Identity
~Identity()
Definition disco.cpp:50
gloox::Disco::Identity::type
const std::string & type() const
Definition disco.h:234
gloox::Disco::Identity::Identity
Identity(const std::string &category, const std::string &type, const std::string &name)
Definition disco.cpp:28
gloox::Disco::Identity::tag
Tag * tag() const
Definition disco.cpp:54
gloox::Disco::Info
An abstraction of a Disco Info element (from Service Discovery, XEP-0030) as a StanzaExtension.
Definition disco.h:66
gloox::Disco::Info::node
const std::string & node() const
Definition disco.h:74
gloox::Disco::Info::form
const DataForm * form() const
Definition disco.h:99
gloox::Disco::Info::setForm
void setForm(DataForm *form)
Definition disco.cpp:115
gloox::Disco::Info::filterString
virtual const std::string & filterString() const
Definition disco.cpp:129
gloox::Disco::Info::hasFeature
bool hasFeature(const std::string &feature) const
Definition disco.cpp:121
gloox::Disco::Info::tag
virtual Tag * tag() const
Definition disco.cpp:135
gloox::Disco::Item::Item
Item(const JID &jid, const std::string &node, const std::string &name)
Definition disco.h:363
gloox::Disco::Item::tag
Tag * tag() const
Definition disco.cpp:168
gloox::Disco::Items
An abstraction of a Disco query element (from Service Discovery, XEP-0030) in the disco::items namesp...
Definition disco.h:276
gloox::Disco::Items::node
const std::string & node() const
Definition disco.h:305
gloox::Disco::Items::~Items
virtual ~Items()
Definition disco.cpp:209
gloox::Disco::Items::items
const ItemList & items() const
Definition disco.h:311
gloox::Disco::Items::filterString
virtual const std::string & filterString() const
Definition disco.cpp:221
gloox::Disco::Items::Items
Items(const std::string &node=EmptyString)
Definition disco.cpp:186
gloox::Disco::Items::tag
virtual Tag * tag() const
Definition disco.cpp:227
gloox::Disco::Items::setItems
void setItems(const ItemList &items)
Definition disco.cpp:214
gloox::Disco::removeDiscoHandler
void removeDiscoHandler(DiscoHandler *dh)
Definition disco.cpp:481
gloox::Disco::name
const std::string & name() const
Definition disco.h:485
gloox::Disco::form
const DataForm * form() const
Definition disco.h:544
gloox::Disco::setForm
void setForm(DataForm *form)
Definition disco.cpp:277
gloox::Disco::removeNodeHandler
void removeNodeHandler(DiscoNodeHandler *nh, const std::string &node)
Definition disco.cpp:502
gloox::Disco::version
const std::string & version() const
Definition disco.h:491
gloox::Disco::handleIqID
virtual void handleIqID(const IQ &iq, int context)
Definition disco.cpp:408
gloox::Disco::handleIq
virtual bool handleIq(const IQ &iq)
Definition disco.cpp:283
gloox::Disco::identities
const IdentityList & identities() const
Definition disco.h:529
gloox::Disco::os
const std::string & os() const
Definition disco.h:497
gloox::Disco::removeNodeHandlers
void removeNodeHandlers(DiscoNodeHandler *nh)
Definition disco.cpp:513
gloox::Disco::registerNodeHandler
void registerNodeHandler(DiscoNodeHandler *nh, const std::string &node)
Definition disco.cpp:497
gloox::Disco::setIdentity
void setIdentity(const std::string &category, const std::string &type, const std::string &name=EmptyString)
Definition disco.cpp:474
gloox::Disco::addFeature
void addFeature(const std::string &feature)
Definition disco.h:422
gloox::Disco::setVersion
void setVersion(const std::string &name, const std::string &version, const std::string &os=EmptyString)
Definition disco.cpp:467
gloox::Disco::features
const StringList features(bool defaultFeatures=false) const
Definition disco.cpp:524
gloox::Disco::IdentityList
std::list< Identity * > IdentityList
Definition disco.h:56
gloox::Disco::addIdentity
void addIdentity(const std::string &category, const std::string &type, const std::string &name=EmptyString)
Definition disco.h:521
gloox::Disco::ItemList
std::list< Item * > ItemList
Definition disco.h:266
gloox::Error
A stanza error abstraction implemented as a StanzaExtension.
Definition error.h:35
gloox::IQ
An abstraction of an IQ stanza.
Definition iq.h:34
gloox::IQ::subtype
IqType subtype() const
Definition iq.h:74
gloox::IQ::Set
@ Set
Definition iq.h:46
gloox::IQ::Error
@ Error
Definition iq.h:49
gloox::IQ::Result
@ Result
Definition iq.h:48
gloox::IQ::Get
@ Get
Definition iq.h:45
gloox::JID
An abstraction of a JID.
Definition jid.h:31
gloox::SoftwareVersion
This is an implementation of XEP-0092 as a StanzaExtension.
Definition softwareversion.h:35
gloox::StanzaExtension
This class abstracts a stanza extension, which is usually an XML child element in a specific namespac...
Definition stanzaextension.h:204
gloox::StanzaExtension::StanzaExtension
StanzaExtension(int type)
Definition stanzaextension.h:211
gloox::Stanza::addExtension
void addExtension(const StanzaExtension *se)
Definition stanza.cpp:52
gloox::Stanza::setFrom
void setFrom(const JID &from)
Definition stanza.h:45
gloox::Stanza::id
const std::string & id() const
Definition stanza.h:63
gloox::Stanza::error
const Error * error() const
Definition stanza.cpp:47
gloox::Stanza::from
const JID & from() const
Definition stanza.h:51
gloox::Stanza::to
const JID & to() const
Definition stanza.h:57
gloox::Stanza::findExtension
const StanzaExtension * findExtension(int type) const
Definition stanza.cpp:57
gloox::Tag
This is an abstraction of an XML element.
Definition tag.h:47
gloox::Tag::name
const std::string & name() const
Definition tag.h:394
gloox::Tag::xmlns
const std::string xmlns() const
Definition tag.cpp:543
gloox::Tag::addAttribute
bool addAttribute(Attribute *attr)
Definition tag.cpp:354
gloox::Tag::addChild
void addChild(Tag *child)
Definition tag.cpp:424
gloox::Tag::findAttribute
const std::string & findAttribute(const std::string &name) const
Definition tag.cpp:589
gloox::Tag::children
const TagList & children() const
Definition tag.cpp:510
gloox::util::clearList
void clearList(std::list< T * > &L)
Definition util.h:152
gloox
The namespace for the gloox library.
Definition adhoc.cpp:28
gloox::TagList
std::list< Tag * > TagList
Definition tag.h:31
gloox::XMLNS_VERSION
const std::string XMLNS_VERSION
Definition gloox.cpp:39
gloox::StringList
std::list< std::string > StringList
Definition gloox.h:1251
gloox::XMLNS_DISCO_ITEMS
const std::string XMLNS_DISCO_ITEMS
Definition gloox.cpp:24
gloox::XMLNS_DISCO_INFO
const std::string XMLNS_DISCO_INFO
Definition gloox.cpp:23
gloox::EmptyString
const std::string EmptyString
Definition gloox.cpp:124
gloox::XMLNS
const std::string XMLNS
Definition gloox.cpp:122
gloox::StanzaErrorItemNotFound
@ StanzaErrorItemNotFound
Definition gloox.h:893
gloox::StanzaErrorTypeCancel
@ StanzaErrorTypeCancel
Definition gloox.h:859
gloox::ExtVersion
@ ExtVersion
Definition stanzaextension.h:56
gloox::ExtDiscoItems
@ ExtDiscoItems
Definition stanzaextension.h:61
gloox::ExtDiscoInfo
@ ExtDiscoInfo
Definition stanzaextension.h:60