pubsubmanager.cpp
/*
Copyright (c) 2007-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 "pubsubmanager.h"
#include "clientbase.h"
#include "dataform.h"
#include "iq.h"
#include "pubsub.h"
#include "pubsubresulthandler.h"
#include "pubsubitem.h"
#include "shim.h"
#include "util.h"
#include "error.h"
namespace gloox
{
namespace PubSub
{
static const std::string
XMLNS_PUBSUB_NODE_CONFIG = "http://jabber.org/protocol/pubsub#node_config",
XMLNS_PUBSUB_SUBSCRIBE_OPTIONS = "http://jabber.org/protocol/pubsub#subscribe_options";
/* static PubSubFeature featureType( const std::string& str )
{
static const char* values [] = {
"collections",
"config-node",
"create-and-configure",
"create-nodes",
"delete-any",
"delete-nodes",
"get-pending",
"instant-nodes",
"item-ids",
"leased-subscription",
"manage-subscriptions",
"meta-data",
"modify-affiliations",
"multi-collection",
"multi-subscribe",
"outcast-affiliation",
"persistent-items",
"presence-notifications",
"publish",
"publisher-affiliation",
"purge-nodes",
"retract-items",
"retrieve-affiliations",
"retrieve-default",
"retrieve-items",
"retrieve-subscriptions",
"subscribe",
"subscription-options",
"subscription-notifications",
"owner",
"event",
};
return static_cast< PubSubFeature >( util::lookup2( str, values ) );
}
*/
static const char* subscriptionValues[] = {
"none", "subscribed", "pending", "unconfigured"
};
static inline SubscriptionType subscriptionType( const std::string& subscription )
{
return static_cast<SubscriptionType>( util::lookup( subscription, subscriptionValues ) );
}
static inline const std::string subscriptionValue( SubscriptionType subscription )
{
return util::lookup( subscription, subscriptionValues );
}
static const char* affiliationValues[] = {
"none", "publisher", "owner", "outcast"
};
static inline AffiliationType affiliationType( const std::string& affiliation )
{
return static_cast<AffiliationType>( util::lookup( affiliation, affiliationValues ) );
}
static inline const std::string affiliationValue( AffiliationType affiliation )
{
return util::lookup( affiliation, affiliationValues );
}
// ---- Manager::PubSubOwner ----
Manager::PubSubOwner::PubSubOwner( TrackContext context )
: StanzaExtension( ExtPubSubOwner ), m_ctx( context ), m_form( 0 )
{
}
Manager::PubSubOwner::PubSubOwner( const Tag* tag )
: StanzaExtension( ExtPubSubOwner ), m_ctx( InvalidContext ), m_form( 0 )
{
const Tag* d = tag->findTag( "pubsub/delete" );
if( d )
{
m_ctx = DeleteNode;
m_node = d->findAttribute( "node" );
return;
}
const Tag* p = tag->findTag( "pubsub/purge" );
if( p )
{
m_ctx = PurgeNodeItems;
m_node = p->findAttribute( "node" );
return;
}
const Tag* c = tag->findTag( "pubsub/configure" );
if( c )
{
m_ctx = SetNodeConfig;
m_node = c->findAttribute( "node" );
if( c->hasChild( "x", "xmlns", XMLNS_X_DATA ) )
{
m_ctx = GetNodeConfig;
m_form = new DataForm( c->findChild( "x", "xmlns", XMLNS_X_DATA ) );
}
return;
}
const Tag* de = tag->findTag( "pubsub/default" );
if( de )
{
m_ctx = DefaultNodeConfig;
return;
}
const Tag* s = tag->findTag( "pubsub/subscriptions" );
if( s )
{
m_ctx = GetSubscriberList;
m_node = s->findAttribute( "node" );
const TagList& l = s->children();
TagList::const_iterator it =l.begin();
for( ; it != l.end(); ++it )
{
if( (*it)->name() == "subscription" )
{
Subscriber sub( (*it)->findAttribute( "jid" ),
subscriptionType( (*it)->findAttribute( "subscription" ) ),
(*it)->findAttribute( "subid" ) );
m_subList.push_back( sub );
}
}
return;
}
const Tag* a = tag->findTag( "pubsub/affiliations" );
if( a )
{
m_ctx = GetAffiliateList;
m_node = a->findAttribute( "node" );
const TagList& l = a->children();
TagList::const_iterator it = l.begin();
for( ; it != l.end(); ++it )
{
if( (*it)->name() == "affiliation" )
{
Affiliate aff( (*it)->findAttribute( "jid" ),
affiliationType( (*it)->findAttribute( "affiliation" ) ) );
m_affList.push_back( aff );
}
}
return;
}
}
Manager::PubSubOwner::~PubSubOwner()
{
delete m_form;
}
const std::string& Manager::PubSubOwner::filterString() const
{
static const std::string filter = "/iq/pubsub[@xmlns='" + XMLNS_PUBSUB_OWNER + "']";
return filter;
}
Tag* Manager::PubSubOwner::tag() const
{
if( m_ctx == InvalidContext )
return 0;
Tag* t = new Tag( "pubsub" );
t->setXmlns( XMLNS_PUBSUB_OWNER );
Tag* c = 0;
switch( m_ctx )
{
case DeleteNode:
{
c = new Tag( t, "delete", "node", m_node );
break;
}
case PurgeNodeItems:
{
c = new Tag( t, "purge", "node", m_node );
break;
}
case GetNodeConfig:
case SetNodeConfig:
{
c = new Tag( t, "configure" );
c->addAttribute( "node", m_node );
if( m_form )
c->addChild( m_form->tag() );
break;
}
case GetSubscriberList:
case SetSubscriberList:
{
c = new Tag( t, "subscriptions" );
c->addAttribute( "node", m_node );
if( m_subList.size() )
{
Tag* s;
SubscriberList::const_iterator it = m_subList.begin();
for( ; it != m_subList.end(); ++it )
{
s = new Tag( c, "subscription" );
s->addAttribute( "jid", (*it).jid.full() );
s->addAttribute( "subscription", util::lookup( (*it).type, subscriptionValues ) );
if( !(*it).subid.empty() )
s->addAttribute( "subid", (*it).subid );
}
}
break;
}
case GetAffiliateList:
case SetAffiliateList:
{
c = new Tag( t, "affiliations" );
c->addAttribute( "node", m_node );
if( m_affList.size() )
{
Tag* a;
AffiliateList::const_iterator it = m_affList.begin();
for( ; it != m_affList.end(); ++it )
{
a = new Tag( c, "affiliation", "jid", (*it).jid.full() );
a->addAttribute( "affiliation", util::lookup( (*it).type, affiliationValues ) );
}
}
break;
}
case DefaultNodeConfig:
{
c = new Tag( t, "default" );
break;
}
default:
break;
}
return t;
}
// ---- ~Manager::PubSubOwner ----
// ---- Manager::PubSub ----
Manager::PubSub::PubSub( TrackContext context )
: StanzaExtension( ExtPubSub ), m_ctx( context ), m_maxItems( 0 ),
m_notify( false )
{
m_options.df = 0;
}
Manager::PubSub::PubSub( const Tag* tag )
: StanzaExtension( ExtPubSub ), m_ctx( InvalidContext ),
m_maxItems( 0 ), m_notify( false )
{
m_options.df = 0;
if( !tag )
return;
const Tag* sl = tag->findTag( "pubsub/subscriptions" );
if( sl )
{
TagList l = sl->children();
if( l.size() )
{
m_ctx = GetSubscriptionList;
TagList::const_iterator it = l.begin();
for( ; it != l.end(); ++it )
{
const std::string& node = (*it)->findAttribute( "node" );
const std::string& sub = (*it)->findAttribute( "subscription" );
const std::string& subid = (*it)->findAttribute( "subid" );
SubscriptionInfo si;
si.jid.setJID( (*it)->findAttribute( "jid" ) );
si.type = subscriptionType( sub );
si.subid = subid;
SubscriptionMap::iterator iter = m_subscriptionMap.find( node );
if( iter == m_subscriptionMap.end() )
{
iter = m_subscriptionMap.insert( std::make_pair( node, SubscriptionList() ) ).first;
}
SubscriptionList& lst = iter->second;
lst.push_back( si );
}
return;
}
}
ConstTagList l = tag->findTagList( "pubsub/affiliations/affiliation" );
if( l.size() )
{
m_ctx = GetAffiliationList;
ConstTagList::const_iterator it = l.begin();
for( ; it != l.end(); ++it )
{
const std::string& node = (*it)->findAttribute( "node" );
const std::string& aff = (*it)->findAttribute( "affiliation" );
m_affiliationMap[node] = affiliationType( aff );
}
return;
}
const Tag* s = tag->findTag( "pubsub/subscribe" );
if( s )
{
m_ctx = Subscription;
m_node = s->findAttribute( "node" );
m_jid = s->findAttribute( "jid" );
}
const Tag* u = tag->findTag( "pubsub/unsubscribe" );
if( u )
{
m_ctx = Unsubscription;
m_node = u->findAttribute( "node" );
m_jid = u->findAttribute( "jid" );
m_subid = u->findAttribute( "subid" );
}
const Tag* o = tag->findTag( "pubsub/options" );
if( o )
{
if( m_ctx == InvalidContext )
{
Tag* parent = tag->parent();
if( parent && parent->findAttribute("type") == "set" )
m_ctx = SetSubscriptionOptions;
else
m_ctx = GetSubscriptionOptions;
}
if( m_ctx == SetSubscriptionOptions || m_ctx == GetSubscriptionOptions )
{
// We set both m_node and m_options.node for
// get/set options, since m_options.node is not exposed externally
m_node = o->findAttribute( "node" );
m_jid.setJID( o->findAttribute( "jid" ) );
m_subid = o->findAttribute( "subid" );
}
m_options.node = o->findAttribute( "node" );
m_options.df = new DataForm( o->findChild( "x", "xmlns", XMLNS_X_DATA ) );
}
const Tag* su = tag->findTag( "pubsub/subscription" );
if( su )
{
SubscriptionInfo si;
si.jid.setJID( su->findAttribute( "jid" ) );
si.subid = su->findAttribute( "subid" );
si.type = subscriptionType( su->findAttribute( "subscription" ) );
SubscriptionList& lst = m_subscriptionMap[su->findAttribute( "node" )];
lst.push_back( si );
return;
}
const Tag* i = tag->findTag( "pubsub/items" );
if( i )
{
m_ctx = RequestItems;
m_node = i->findAttribute( "node" );
m_subid = i->findAttribute( "subid" );
m_maxItems = atoi( i->findAttribute( "max_items" ).c_str() );
const TagList& l = i->children();
TagList::const_iterator it = l.begin();
for( ; it != l.end(); ++it )
m_items.push_back( new Item( (*it) ) );
return;
}
const Tag* p = tag->findTag( "pubsub/publish" );
if( p )
{
m_ctx = PublishItem;
m_node = p->findAttribute( "node" );
const TagList& l = p->children();
TagList::const_iterator it = l.begin();
for( ; it != l.end(); ++it )
m_items.push_back( new Item( (*it) ) );
return;
}
const Tag* r = tag->findTag( "pubsub/retract" );
if( r )
{
m_ctx = DeleteItem;
m_node = r->findAttribute( "node" );
m_notify = r->hasAttribute( "notify", "1" ) || r->hasAttribute( "notify", "true" );
const TagList& l = r->children();
TagList::const_iterator it = l.begin();
for( ; it != l.end(); ++it )
m_items.push_back( new Item( (*it) ) );
return;
}
const Tag* c = tag->findTag( "pubsub/create" );
if( c )
{
m_ctx = CreateNode;
m_node = c->findAttribute( "node" );
const Tag* config = tag->findTag( "pubsub/configure" );
if( config && config->hasChild( "x", XMLNS_X_DATA ) )
m_options.df = new DataForm( config->findChild( "x", XMLNS_X_DATA ) );
}
}
Manager::PubSub::~PubSub()
{
delete m_options.df;
util::clearList( m_items );
}
const std::string& Manager::PubSub::filterString() const
{
static const std::string filter = "/iq/pubsub[@xmlns='" + XMLNS_PUBSUB + "']";
return filter;
}
Tag* Manager::PubSub::tag() const
{
if( m_ctx == InvalidContext )
return 0;
Tag* t = new Tag( "pubsub" );
t->setXmlns( XMLNS_PUBSUB );
if( m_ctx == GetSubscriptionList )
{
Tag* sub = new Tag( t, "subscriptions" );
SubscriptionMap::const_iterator it = m_subscriptionMap.begin();
for( ; it != m_subscriptionMap.end(); ++it )
{
const SubscriptionList& lst = (*it).second;
SubscriptionList::const_iterator it2 = lst.begin();
for( ; it2 != lst.end(); ++it2 )
{
Tag* s = new Tag( sub, "subscription" );
s->addAttribute( "node", (*it).first );
s->addAttribute( "jid", (*it2).jid );
s->addAttribute( "subscription", subscriptionValue( (*it2).type ) );
s->addAttribute( "sid", (*it2).subid );
}
}
}
else if( m_ctx == GetAffiliationList )
{
Tag* aff = new Tag( t, "affiliations" );
AffiliationMap::const_iterator it = m_affiliationMap.begin();
for( ; it != m_affiliationMap.end(); ++it )
{
Tag* a = new Tag( aff, "affiliation" );
a->addAttribute( "node", (*it).first );
a->addAttribute( "affiliation", affiliationValue( (*it).second ) );
}
}
else if( m_ctx == Subscription )
{
Tag* s = new Tag( t, "subscribe" );
s->addAttribute( "node", m_node );
s->addAttribute( "jid", m_jid.full() );
if( m_options.df )
{
Tag* o = new Tag( t, "options" );
o->addChild( m_options.df->tag() );
}
}
else if( m_ctx == Unsubscription )
{
Tag* u = new Tag( t, "unsubscribe" );
u->addAttribute( "node", m_node );
u->addAttribute( "jid", m_jid.full() );
u->addAttribute( "subid", m_subid );
}
else if( m_ctx == GetSubscriptionOptions
|| m_ctx == SetSubscriptionOptions )
{
Tag* o = new Tag( t, "options" );
o->addAttribute( "node", m_options.node );
o->addAttribute( "jid", m_jid.full() );
if( !m_subid.empty() )
o->addAttribute( "subid", m_subid );
if( m_options.df )
o->addChild( m_options.df->tag() );
}
else if( m_ctx == RequestItems )
{
Tag* i = new Tag( t, "items" );
i->addAttribute( "node", m_node );
if( m_maxItems )
i->addAttribute( "max_items", m_maxItems );
i->addAttribute( "subid", m_subid );
ItemList::const_iterator it = m_items.begin();
for( ; it != m_items.end(); ++it )
i->addChild( (*it)->tag() );
}
else if( m_ctx == PublishItem )
{
Tag* p = new Tag( t, "publish" );
p->addAttribute( "node", m_node );
ItemList::const_iterator it = m_items.begin();
for( ; it != m_items.end(); ++it )
p->addChild( (*it)->tag() );
if( m_options.df )
{
Tag* po = new Tag( p, "publish-options" );
po->addChild( m_options.df->tag() );
}
}
else if( m_ctx == DeleteItem )
{
Tag* r = new Tag( t, "retract" );
r->addAttribute( "node", m_node );
if( m_notify )
r->addAttribute( "notify", "true" );
ItemList::const_iterator it = m_items.begin();
for( ; it != m_items.end(); ++it )
r->addChild( (*it)->tag() );
}
else if( m_ctx == CreateNode )
{
Tag* c = new Tag( t, "create" );
if( !m_node.empty() )
c->addAttribute( "node", m_node );
Tag* config = new Tag( t, "configure" );
if( m_options.df )
config->addChild( m_options.df->tag() );
}
return t;
}
StanzaExtension* Manager::PubSub::clone() const
{
PubSub* p = new PubSub();
p->m_affiliationMap = m_affiliationMap;
p->m_subscriptionMap = m_subscriptionMap;
p->m_ctx = m_ctx;
p->m_options.node = m_options.node;
p->m_options.df = m_options.df ? new DataForm( *(m_options.df) ) : 0;
p->m_jid = m_jid;
p->m_node = m_node;
p->m_subid = m_subid;
ItemList::const_iterator it = m_items.begin();
for( ; it != m_items.end(); ++it )
p->m_items.push_back( new Item( *(*it) ) );
p->m_maxItems = m_maxItems;
p->m_notify = m_notify;
return p;
}
// ---- ~Manager::PubSub ----
// ---- Manager ----
Manager::Manager( ClientBase* parent )
: m_parent( parent )
{
if( m_parent )
{
m_parent->registerStanzaExtension( new PubSub() );
m_parent->registerStanzaExtension( new PubSubOwner() );
m_parent->registerStanzaExtension( new SHIM() );
}
}
const std::string Manager::getSubscriptionsOrAffiliations( const JID& service,
ResultHandler* handler,
TrackContext context )
{
if( !m_parent || !handler || !service || context == InvalidContext )
return EmptyString;
const std::string& id = m_parent->getID();
IQ iq( IQ::Get, service, id );
iq.addExtension( new PubSub( context ) );
m_trackMapMutex.lock();
m_resultHandlerTrackMap[id] = handler;
m_trackMapMutex.unlock();
m_parent->send( iq, this, context );
return id;
}
const std::string Manager::subscribe( const JID& service,
const std::string& node,
ResultHandler* handler,
const JID& jid,
SubscriptionObject type,
int depth,
const std::string& expire
)
{
if( !m_parent || !handler || !service || node.empty() )
return EmptyString;
DataForm* options = 0;
if( type != SubscriptionNodes || depth != 1 )
{
options = new DataForm( TypeSubmit );
options->addField( DataFormField::TypeHidden, "FORM_TYPE", XMLNS_PUBSUB_SUBSCRIBE_OPTIONS );
if( type == SubscriptionItems )
options->addField( DataFormField::TypeNone, "pubsub#subscription_type", "items" );
if( depth != 1 )
{
DataFormField* field = options->addField( DataFormField::TypeNone, "pubsub#subscription_depth" );
if( depth == 0 )
field->setValue( "all" );
else
field->setValue( util::int2string( depth ) );
}
if( !expire.empty() )
{
DataFormField* field = options->addField( DataFormField::TypeNone, "pubsub#expire" );
field->setValue( expire );
}
}
return subscribe( service, node, handler, jid, options );
}
const std::string Manager::subscribe( const JID& service,
const std::string& node,
ResultHandler* handler,
const JID& jid,
DataForm* options
)
{
if( !m_parent || !handler || !service || node.empty() )
return EmptyString;
const std::string& id = m_parent->getID();
IQ iq( IQ::Set, service, id );
PubSub* ps = new PubSub( Subscription );
ps->setJID( jid ? jid : m_parent->jid() );
ps->setNode( node );
if( options != NULL )
ps->setOptions( node, options );
iq.addExtension( ps );
m_trackMapMutex.lock();
m_resultHandlerTrackMap[id] = handler;
m_nopTrackMap[id] = node;
m_trackMapMutex.unlock();
m_parent->send( iq, this, Subscription );
return id;
}
const std::string Manager::unsubscribe( const JID& service,
const std::string& node,
const std::string& subid,
ResultHandler* handler,
const JID& jid )
{
if( !m_parent || !handler || !service )
return EmptyString;
const std::string& id = m_parent->getID();
IQ iq( IQ::Set, service, id );
PubSub* ps = new PubSub( Unsubscription );
ps->setNode( node );
ps->setJID( jid ? jid : m_parent->jid() );
ps->setSubscriptionID( subid );
iq.addExtension( ps );
m_trackMapMutex.lock();
m_resultHandlerTrackMap[id] = handler;
m_trackMapMutex.unlock();
// FIXME? need to track info for handler
m_parent->send( iq, this, Unsubscription );
return id;
}
const std::string Manager::subscriptionOptions( TrackContext context,
const JID& service,
const JID& jid,
const std::string& node,
ResultHandler* handler,
DataForm* df,
const std::string& subid )
{
if( !m_parent || !handler || !service )
return EmptyString;
const std::string& id = m_parent->getID();
IQ iq( df ? IQ::Set : IQ::Get, service, id );
PubSub* ps = new PubSub( context );
ps->setJID( jid ? jid : m_parent->jid() );
if( !subid.empty() )
ps->setSubscriptionID( subid );
ps->setOptions( node, df );
iq.addExtension( ps );
m_trackMapMutex.lock();
m_resultHandlerTrackMap[id] = handler;
m_trackMapMutex.unlock();
m_parent->send( iq, this, context );
return id;
}
const std::string Manager::requestItems( const JID& service,
const std::string& node,
const std::string& subid,
int maxItems,
ResultHandler* handler )
{
if( !m_parent || !service || !handler )
return EmptyString;
const std::string& id = m_parent->getID();
IQ iq( IQ::Get, service, id );
PubSub* ps = new PubSub( RequestItems );
ps->setNode( node );
ps->setSubscriptionID( subid );
ps->setMaxItems( maxItems );
iq.addExtension( ps );
m_trackMapMutex.lock();
m_resultHandlerTrackMap[id] = handler;
m_trackMapMutex.unlock();
m_parent->send( iq, this, RequestItems );
return id;
}
const std::string Manager::requestItems( const JID& service,
const std::string& node,
const std::string& subid,
const ItemList& items,
ResultHandler* handler )
{
if( !m_parent || !service || !handler )
return EmptyString;
const std::string& id = m_parent->getID();
IQ iq( IQ::Get, service, id );
PubSub* ps = new PubSub( RequestItems );
ps->setNode( node );
ps->setSubscriptionID( subid );
ps->setItems( items );
iq.addExtension( ps );
m_trackMapMutex.lock();
m_resultHandlerTrackMap[id] = handler;
m_trackMapMutex.unlock();
m_parent->send( iq, this, RequestItems );
return id;
}
const std::string Manager::publishItem( const JID& service,
const std::string& node,
ItemList& items,
DataForm* options,
ResultHandler* handler )
{
if( !m_parent || !handler )
{
util::clearList( items );
return EmptyString;
}
const std::string& id = m_parent->getID();
IQ iq( IQ::Set, service, id );
PubSub* ps = new PubSub( PublishItem );
ps->setNode( node );
ps->setItems( items );
ps->setOptions( EmptyString, options );
iq.addExtension( ps );
m_trackMapMutex.lock();
m_resultHandlerTrackMap[id] = handler;
m_trackMapMutex.unlock();
m_parent->send( iq, this, PublishItem );
return id;
}
const std::string Manager::deleteItem( const JID& service,
const std::string& node,
const ItemList& items,
bool notify,
ResultHandler* handler )
{
if( !m_parent || !handler || !service )
return EmptyString;
const std::string& id = m_parent->getID();
IQ iq( IQ::Set, service, id );
PubSub* ps = new PubSub( DeleteItem );
ps->setNode( node );
ps->setItems( items );
ps->setNotify( notify );
iq.addExtension( ps );
m_trackMapMutex.lock();
m_resultHandlerTrackMap[id] = handler;
m_trackMapMutex.unlock();
m_parent->send( iq, this, DeleteItem );
return id;
}
const std::string Manager::createNode( const JID& service,
const std::string& node,
DataForm* config,
ResultHandler* handler )
{
if( !m_parent || !handler || !service )
return EmptyString;
const std::string& id = m_parent->getID();
IQ iq( IQ::Set, service, id );
PubSub* ps = new PubSub( CreateNode );
if( !node.empty() )
ps->setNode( node );
ps->setOptions( EmptyString, config );
iq.addExtension( ps );
m_trackMapMutex.lock();
m_nopTrackMap[id] = node;
m_resultHandlerTrackMap[id] = handler;
m_trackMapMutex.unlock();
m_parent->send( iq, this, CreateNode );
return id;
}
const std::string Manager::deleteNode( const JID& service,
const std::string& node,
ResultHandler* handler )
{
if( !m_parent || !handler || !service || node.empty() )
return EmptyString;
const std::string& id = m_parent->getID();
IQ iq( IQ::Set, service, id );
PubSubOwner* pso = new PubSubOwner( DeleteNode );
pso->setNode( node );
iq.addExtension( pso );
m_trackMapMutex.lock();
m_nopTrackMap[id] = node;
m_resultHandlerTrackMap[id] = handler;
m_trackMapMutex.unlock();
m_parent->send( iq, this, DeleteNode );
return id;
}
const std::string Manager::getDefaultNodeConfig( const JID& service,
NodeType type,
ResultHandler* handler )
{
if( !m_parent || !handler || !service )
return EmptyString;
const std::string& id = m_parent->getID();
IQ iq( IQ::Get, service, id );
PubSubOwner* pso = new PubSubOwner( DefaultNodeConfig );
if( type == NodeCollection )
{
DataForm* df = new DataForm( TypeSubmit );
df->addField( DataFormField::TypeHidden, "FORM_TYPE", XMLNS_PUBSUB_NODE_CONFIG );
df->addField( DataFormField::TypeNone, "pubsub#node_type", "collection" );
pso->setConfig( df );
}
iq.addExtension( pso );
m_trackMapMutex.lock();
m_resultHandlerTrackMap[id] = handler;
m_trackMapMutex.unlock();
m_parent->send( iq, this, DefaultNodeConfig );
return id;
}
const std::string Manager::nodeConfig( const JID& service,
const std::string& node,
DataForm* config,
ResultHandler* handler )
{
if( !m_parent || !handler || !service || node.empty() )
return EmptyString;
const std::string& id = m_parent->getID();
IQ iq( config ? IQ::Set : IQ::Get, service, id );
PubSubOwner* pso = new PubSubOwner( config ? SetNodeConfig : GetNodeConfig );
pso->setNode( node );
if( config )
pso->setConfig( config );
iq.addExtension( pso );
m_trackMapMutex.lock();
m_nopTrackMap[id] = node;
m_resultHandlerTrackMap[id] = handler;
m_trackMapMutex.unlock();
m_parent->send( iq, this, config ? SetNodeConfig : GetNodeConfig );
return id;
}
const std::string Manager::subscriberList( TrackContext ctx,
const JID& service,
const std::string& node,
const SubscriberList& subList,
ResultHandler* handler )
{
if( !m_parent || !handler || !service || node.empty() )
return EmptyString;
const std::string& id = m_parent->getID();
IQ iq( ctx == SetSubscriberList ? IQ::Set : IQ::Get, service, id );
PubSubOwner* pso = new PubSubOwner( ctx );
pso->setNode( node );
pso->setSubscriberList( subList );
iq.addExtension( pso );
m_trackMapMutex.lock();
m_nopTrackMap[id] = node;
m_resultHandlerTrackMap[id] = handler;
m_trackMapMutex.unlock();
m_parent->send( iq, this, ctx );
return id;
}
const std::string Manager::affiliateList( TrackContext ctx,
const JID& service,
const std::string& node,
const AffiliateList& affList,
ResultHandler* handler )
{
if( !m_parent || !handler || !service || node.empty() )
return EmptyString;
const std::string& id = m_parent->getID();
IQ iq( ctx == SetAffiliateList ? IQ::Set : IQ::Get, service, id );
PubSubOwner* pso = new PubSubOwner( ctx );
pso->setNode( node );
pso->setAffiliateList( affList );
iq.addExtension( pso );
m_trackMapMutex.lock();
m_nopTrackMap[id] = node;
m_resultHandlerTrackMap[id] = handler;
m_trackMapMutex.unlock();
m_parent->send( iq, this, ctx );
return id;
}
const std::string Manager::purgeNode( const JID& service,
const std::string& node,
ResultHandler* handler )
{
if( !m_parent || !handler || !service || node.empty() )
return EmptyString;
const std::string& id = m_parent->getID();
IQ iq( IQ::Set, service, id );
PubSubOwner* pso = new PubSubOwner( PurgeNodeItems );
pso->setNode( node );
iq.addExtension( pso );
m_trackMapMutex.lock();
m_nopTrackMap[id] = node;
m_resultHandlerTrackMap[id] = handler;
m_trackMapMutex.unlock();
m_parent->send( iq, this, PurgeNodeItems );
return id;
}
bool Manager::removeID( const std::string& id )
{
m_trackMapMutex.lock();
ResultHandlerTrackMap::iterator ith = m_resultHandlerTrackMap.find( id );
if( ith == m_resultHandlerTrackMap.end() )
{
m_trackMapMutex.unlock();
return false;
}
m_resultHandlerTrackMap.erase( ith );
m_trackMapMutex.unlock();
return true;
}
void Manager::handleIqID( const IQ& iq, int context )
{
const JID& service = iq.from();
const std::string& id = iq.id();
m_trackMapMutex.lock();
ResultHandlerTrackMap::iterator ith = m_resultHandlerTrackMap.find( id );
if( ith == m_resultHandlerTrackMap.end() )
{
m_trackMapMutex.unlock();
return;
}
ResultHandler* rh = (*ith).second;
m_resultHandlerTrackMap.erase( ith );
m_trackMapMutex.unlock();
switch( iq.subtype() )
{
case IQ::Error:
case IQ::Result:
{
const Error* error = iq.error();
switch( context )
{
case Subscription:
{
const PubSub* ps = iq.findExtension<PubSub>( ExtPubSub );
if( !ps )
return;
SubscriptionMap sm = ps->subscriptions();
if( sm.empty() )
{
/* If the reply is an error, it will not contain a
"subscription" child. It may however contain the
original "subscribe" request. If that is the case, then
we can still retrieve the node and JID of the request and
notify the handler callback of the error. */
if( ps->context() == Subscription )
rh->handleSubscriptionResult( id, service, ps->node(), "", ps->jid(),
SubscriptionInvalid, error );
}
else
{
SubscriptionMap::const_iterator it = sm.begin();
const SubscriptionList& lst = (*it).second;
if( lst.size() == 1 )
{
SubscriptionList::const_iterator it2 = lst.begin();
rh->handleSubscriptionResult( id, service, (*it).first, (*it2).subid, (*it2).jid,
(*it2).type, error );
}
}
break;
}
case Unsubscription:
{
rh->handleUnsubscriptionResult( iq.id(), service, error );
break;
}
case GetSubscriptionList:
{
const PubSub* ps = iq.findExtension<PubSub>( ExtPubSub );
if( !ps )
return;
rh->handleSubscriptions( id, service,
ps->subscriptions(),
error );
break;
}
case GetAffiliationList:
{
const PubSub* ps = iq.findExtension<PubSub>( ExtPubSub );
if( !ps )
return;
rh->handleAffiliations( id, service,
ps->affiliations(),
error );
break;
}
case RequestItems:
{
const PubSub* ps = iq.findExtension<PubSub>( ExtPubSub );
if( !ps )
return;
rh->handleItems( id, service, ps->node(),
ps->items(), error );
break;
}
case PublishItem:
{
const PubSub* ps = iq.findExtension<PubSub>( ExtPubSub );
rh->handleItemPublication( id, service, ps->node(),
ps ? ps->items() : ItemList(),
error );
break;
}
case DeleteItem:
{
const PubSub* ps = iq.findExtension<PubSub>( ExtPubSub );
if( ps )
{
rh->handleItemDeletion( id, service,
ps->node(),
ps->items(),
error );
}
break;
}
case DefaultNodeConfig:
{
const PubSubOwner* pso = iq.findExtension<PubSubOwner>( ExtPubSubOwner );
if( pso )
{
rh->handleDefaultNodeConfig( id, service,
pso->config(),
error );
}
break;
}
case GetSubscriptionOptions:
case GetSubscriberList:
case SetSubscriberList:
case GetAffiliateList:
case SetAffiliateList:
case GetNodeConfig:
case SetNodeConfig:
case CreateNode:
case DeleteNode:
case PurgeNodeItems:
{
switch( context )
{
case GetSubscriptionOptions:
{
const PubSub* ps = iq.findExtension<PubSub>( ExtPubSub );
if( ps )
{
rh->handleSubscriptionOptions( id, service,
ps->jid(),
ps->node(),
ps->options(),
ps->subscriptionID(),
error );
}
break;
}
case GetSubscriberList:
{
const PubSub* ps = iq.findExtension<PubSub>( ExtPubSub );
if( ps )
{
const SubscriptionMap& sm = ps->subscriptions();
SubscriptionMap::const_iterator itsm = sm.find( ps->node() );
if( itsm != sm.end() )
rh->handleSubscribers( iq.id(), service, ps->node(), (*itsm).second, 0 );
}
break;
}
case SetSubscriptionOptions:
case SetSubscriberList:
case SetAffiliateList:
case SetNodeConfig:
case CreateNode:
case DeleteNode:
case PurgeNodeItems:
{
m_trackMapMutex.lock();
NodeOperationTrackMap::iterator it = m_nopTrackMap.find( id );
if( it != m_nopTrackMap.end() )
{
const std::string& node = (*it).second;
const PubSub* ps = iq.findExtension<PubSub>( ExtPubSub );
switch( context )
{
case SetSubscriptionOptions:
{
if( ps )
{
rh->handleSubscriptionOptionsResult( id, service,
ps->jid(),
node,
ps->subscriptionID(),
error );
}
else
{
rh->handleSubscriptionOptionsResult( id, service, JID( /* FIXME */ ), node, /* FIXME */ EmptyString, error );
}
break;
}
case SetSubscriberList:
rh->handleSubscribersResult( id, service, node, 0, error );
break;
case SetAffiliateList:
rh->handleAffiliatesResult( id, service, node, 0, error );
break;
case SetNodeConfig:
rh->handleNodeConfigResult( id, service, node, error );
break;
case CreateNode:
if( ps )
rh->handleNodeCreation( id, service, ps->node(), error );
else
rh->handleNodeCreation( id, service, node, error );
break;
case DeleteNode:
rh->handleNodeDeletion( id, service, node, error );
break;
case PurgeNodeItems:
rh->handleNodePurge( id, service, node, error );
break;
}
m_nopTrackMap.erase( it );
}
m_trackMapMutex.unlock();
break;
}
case GetAffiliateList:
{
const PubSubOwner* pso = iq.findExtension<PubSubOwner>( ExtPubSubOwner );
if( pso )
{
rh->handleAffiliates( id, service, pso->node(), pso->affiliateList(), error );
}
break;
}
case GetNodeConfig:
{
const PubSubOwner* pso = iq.findExtension<PubSubOwner>( ExtPubSubOwner );
if( pso )
{
rh->handleNodeConfig( id, service,
pso->node(),
pso->config(),
error );
}
break;
}
default:
break;
}
break;
}
}
break;
}
default:
break;
}
}
}
}
gloox::ClientBase
This is the common base class for a Jabber/XMPP Client and a Jabber Component.
Definition clientbase.h:79
gloox::ClientBase::getID
const std::string getID()
Definition clientbase.cpp:1168
gloox::ClientBase::send
void send(Tag *tag)
Definition clientbase.cpp:1004
gloox::ClientBase::jid
const JID & jid()
Definition clientbase.h:147
gloox::DataFormFieldContainer::addField
virtual void addField(DataFormField *field)
Definition dataformfieldcontainer.h:99
gloox::DataFormField
An abstraction of a single field in a XEP-0004 Data Form.
Definition dataformfield.h:34
gloox::DataFormField::TypeHidden
@ TypeHidden
Definition dataformfield.h:49
gloox::DataFormField::TypeNone
@ TypeNone
Definition dataformfield.h:68
gloox::DataFormField::setValue
void setValue(const std::string &value)
Definition dataformfield.h:195
gloox::DataForm
An abstraction of a XEP-0004 Data Form.
Definition dataform.h:57
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::PubSub::Manager::subscribe
const std::string subscribe(const JID &service, const std::string &node, ResultHandler *handler, const JID &jid=JID(), SubscriptionObject type=SubscriptionNodes, int depth=1, const std::string &expire=EmptyString)
Definition pubsubmanager.cpp:611
gloox::PubSub::Manager::createNode
const std::string createNode(const JID &service, const std::string &node, DataForm *config, ResultHandler *handler)
Definition pubsubmanager.cpp:829
gloox::PubSub::Manager::removeID
bool removeID(const std::string &id)
Definition pubsubmanager.cpp:993
gloox::PubSub::Manager::requestItems
const std::string requestItems(const JID &service, const std::string &node, const std::string &subid, int maxItems, ResultHandler *handler)
Definition pubsubmanager.cpp:730
gloox::PubSub::Manager::unsubscribe
const std::string unsubscribe(const JID &service, const std::string &node, const std::string &subid, ResultHandler *handler, const JID &jid=JID())
Definition pubsubmanager.cpp:678
gloox::PubSub::Manager::handleIqID
virtual void handleIqID(const IQ &iq, int context)
Definition pubsubmanager.cpp:1007
gloox::PubSub::Manager::deleteItem
const std::string deleteItem(const JID &service, const std::string &node, const ItemList &items, bool notify, ResultHandler *handler)
Definition pubsubmanager.cpp:805
gloox::PubSub::Manager::getDefaultNodeConfig
const std::string getDefaultNodeConfig(const JID &service, NodeType type, ResultHandler *handler)
Definition pubsubmanager.cpp:874
gloox::PubSub::Manager::purgeNode
const std::string purgeNode(const JID &service, const std::string &node, ResultHandler *handler)
Definition pubsubmanager.cpp:972
gloox::PubSub::Manager::Manager
Manager(ClientBase *parent)
Definition pubsubmanager.cpp:582
gloox::PubSub::Manager::publishItem
const std::string publishItem(const JID &service, const std::string &node, ItemList &items, DataForm *options, ResultHandler *handler)
Definition pubsubmanager.cpp:778
gloox::PubSub::Manager::deleteNode
const std::string deleteNode(const JID &service, const std::string &node, ResultHandler *handler)
Definition pubsubmanager.cpp:853
gloox::PubSub::ResultHandler
A virtual interface to receive item related requests results.
Definition pubsubresulthandler.h:50
gloox::PubSub::ResultHandler::handleItems
virtual void handleItems(const std::string &id, const JID &service, const std::string &node, const ItemList &itemList, const Error *error=0)=0
gloox::PubSub::ResultHandler::handleSubscriptionOptionsResult
virtual void handleSubscriptionOptionsResult(const std::string &id, const JID &service, const JID &jid, const std::string &node, const std::string &sid=EmptyString, const Error *error=0)=0
gloox::PubSub::ResultHandler::handleAffiliations
virtual void handleAffiliations(const std::string &id, const JID &service, const AffiliationMap &affMap, const Error *error=0)=0
gloox::PubSub::ResultHandler::handleDefaultNodeConfig
virtual void handleDefaultNodeConfig(const std::string &id, const JID &service, const DataForm *config, const Error *error=0)=0
gloox::PubSub::ResultHandler::handleNodeDeletion
virtual void handleNodeDeletion(const std::string &id, const JID &service, const std::string &node, const Error *error=0)=0
gloox::PubSub::ResultHandler::handleNodeConfigResult
virtual void handleNodeConfigResult(const std::string &id, const JID &service, const std::string &node, const Error *error=0)=0
gloox::PubSub::ResultHandler::handleSubscriptionOptions
virtual void handleSubscriptionOptions(const std::string &id, const JID &service, const JID &jid, const std::string &node, const DataForm *options, const std::string &sid=EmptyString, const Error *error=0)=0
gloox::PubSub::ResultHandler::handleSubscriptions
virtual void handleSubscriptions(const std::string &id, const JID &service, const SubscriptionMap &subMap, const Error *error=0)=0
gloox::PubSub::ResultHandler::handleUnsubscriptionResult
virtual void handleUnsubscriptionResult(const std::string &id, const JID &service, const Error *error=0)=0
gloox::PubSub::ResultHandler::handleSubscribers
virtual void handleSubscribers(const std::string &id, const JID &service, const std::string &node, const SubscriptionList &list, const Error *error=0)=0
gloox::PubSub::ResultHandler::handleItemPublication
virtual void handleItemPublication(const std::string &id, const JID &service, const std::string &node, const ItemList &itemList, const Error *error=0)=0
gloox::PubSub::ResultHandler::handleSubscriptionResult
virtual void handleSubscriptionResult(const std::string &id, const JID &service, const std::string &node, const std::string &sid, const JID &jid, const SubscriptionType subType, const Error *error=0)=0
gloox::PubSub::ResultHandler::handleAffiliatesResult
virtual void handleAffiliatesResult(const std::string &id, const JID &service, const std::string &node, const AffiliateList *list, const Error *error=0)=0
gloox::PubSub::ResultHandler::handleAffiliates
virtual void handleAffiliates(const std::string &id, const JID &service, const std::string &node, const AffiliateList *list, const Error *error=0)=0
gloox::PubSub::ResultHandler::handleNodePurge
virtual void handleNodePurge(const std::string &id, const JID &service, const std::string &node, const Error *error=0)=0
gloox::PubSub::ResultHandler::handleItemDeletion
virtual void handleItemDeletion(const std::string &id, const JID &service, const std::string &node, const ItemList &itemList, const Error *error=0)=0
gloox::PubSub::ResultHandler::handleNodeCreation
virtual void handleNodeCreation(const std::string &id, const JID &service, const std::string &node, const Error *error=0)=0
gloox::PubSub::ResultHandler::handleNodeConfig
virtual void handleNodeConfig(const std::string &id, const JID &service, const std::string &node, const DataForm *config, const Error *error=0)=0
gloox::PubSub::ResultHandler::handleSubscribersResult
virtual void handleSubscribersResult(const std::string &id, const JID &service, const std::string &node, const SubscriberList *list, const Error *error=0)=0
gloox::SHIM
An implementation/abstraction of Stanza Headers and Internet Metadata (SHIM, XEP-0131).
Definition shim.h:36
gloox::Stanza::addExtension
void addExtension(const StanzaExtension *se)
Definition stanza.cpp:52
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::findExtension
const StanzaExtension * findExtension(int type) const
Definition stanza.cpp:57
gloox::util::Mutex::unlock
void unlock()
Definition mutex.cpp:131
gloox::util::Mutex::lock
void lock()
Definition mutex.cpp:121
gloox::PubSub
Namespace holding all the Pubsub-related structures and definitions.
Definition pubsub.h:28
gloox::PubSub::SubscriptionObject
SubscriptionObject
Definition pubsub.h:97
gloox::PubSub::SubscriptionItems
@ SubscriptionItems
Definition pubsub.h:99
gloox::PubSub::SubscriptionNodes
@ SubscriptionNodes
Definition pubsub.h:98
gloox::PubSub::SubscriptionType
SubscriptionType
Definition pubsub.h:61
gloox::PubSub::SubscriptionInvalid
@ SubscriptionInvalid
Definition pubsub.h:75
gloox::PubSub::AffiliationType
AffiliationType
Definition pubsub.h:49
gloox::PubSub::NodeType
NodeType
Definition pubsub.h:36
gloox::PubSub::NodeCollection
@ NodeCollection
Definition pubsub.h:39
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::EmptyString
const std::string EmptyString
Definition gloox.cpp:124
gloox::ConstTagList
std::list< const Tag * > ConstTagList
Definition tag.h:36
gloox::XMLNS_PUBSUB_OWNER
const std::string XMLNS_PUBSUB_OWNER
Definition gloox.cpp:80
gloox::ExtPubSub
@ ExtPubSub
Definition stanzaextension.h:84
gloox::ExtPubSubOwner
@ ExtPubSubOwner
Definition stanzaextension.h:85
gloox::TypeSubmit
@ TypeSubmit
Definition dataform.h:37
gloox::XMLNS_PUBSUB
const std::string XMLNS_PUBSUB
Definition gloox.cpp:77