gloox  1.0.14
pubsubmanager.cpp
1 /*
2  Copyright (c) 2007-2015 by Jakob Schröter <js@camaya.net>
3  This file is part of the gloox library. http://camaya.net/gloox
4 
5  This software is distributed under a license. The full license
6  agreement can be found in the file LICENSE in this distribution.
7  This software may not be copied, modified, sold or distributed
8  other than expressed in the named license agreement.
9 
10  This software is distributed without any warranty.
11 */
12 
13 #include "pubsubmanager.h"
14 #include "clientbase.h"
15 #include "dataform.h"
16 #include "iq.h"
17 #include "pubsub.h"
18 #include "pubsubresulthandler.h"
19 #include "pubsubitem.h"
20 #include "shim.h"
21 #include "util.h"
22 #include "error.h"
23 
24 namespace gloox
25 {
26 
27  namespace PubSub
28  {
29 
30  static const std::string
31  XMLNS_PUBSUB_NODE_CONFIG = "http://jabber.org/protocol/pubsub#node_config",
32  XMLNS_PUBSUB_SUBSCRIBE_OPTIONS = "http://jabber.org/protocol/pubsub#subscribe_options";
33 
40 /* static PubSubFeature featureType( const std::string& str )
41  {
42  static const char* values [] = {
43  "collections",
44  "config-node",
45  "create-and-configure",
46  "create-nodes",
47  "delete-any",
48  "delete-nodes",
49  "get-pending",
50  "instant-nodes",
51  "item-ids",
52  "leased-subscription",
53  "manage-subscriptions",
54  "meta-data",
55  "modify-affiliations",
56  "multi-collection",
57  "multi-subscribe",
58  "outcast-affiliation",
59  "persistent-items",
60  "presence-notifications",
61  "publish",
62  "publisher-affiliation",
63  "purge-nodes",
64  "retract-items",
65  "retrieve-affiliations",
66  "retrieve-default",
67  "retrieve-items",
68  "retrieve-subscriptions",
69  "subscribe",
70  "subscription-options",
71  "subscription-notifications",
72  "owner",
73  "event",
74  };
75  return static_cast< PubSubFeature >( util::lookup2( str, values ) );
76  }
77 */
78 
79  static const char* subscriptionValues[] = {
80  "none", "subscribed", "pending", "unconfigured"
81  };
82 
83  static inline SubscriptionType subscriptionType( const std::string& subscription )
84  {
85  return (SubscriptionType)util::lookup( subscription, subscriptionValues );
86  }
87 
88  static inline const std::string subscriptionValue( SubscriptionType subscription )
89  {
90  return util::lookup( subscription, subscriptionValues );
91  }
92 
93  static const char* affiliationValues[] = {
94  "none", "publisher", "owner", "outcast"
95  };
96 
97  static inline AffiliationType affiliationType( const std::string& affiliation )
98  {
99  return (AffiliationType)util::lookup( affiliation, affiliationValues );
100  }
101 
102  static inline const std::string affiliationValue( AffiliationType affiliation )
103  {
104  return util::lookup( affiliation, affiliationValues );
105  }
106 
107  // ---- Manager::PubSubOwner ----
108  Manager::PubSubOwner::PubSubOwner( TrackContext context )
109  : StanzaExtension( ExtPubSubOwner ), m_ctx( context ), m_form( 0 )
110  {
111  }
112 
113  Manager::PubSubOwner::PubSubOwner( const Tag* tag )
114  : StanzaExtension( ExtPubSubOwner ), m_ctx( InvalidContext ), m_form( 0 )
115  {
116  const Tag* d = tag->findTag( "pubsub/delete" );
117  if( d )
118  {
119  m_ctx = DeleteNode;
120  m_node = d->findAttribute( "node" );
121  return;
122  }
123  const Tag* p = tag->findTag( "pubsub/purge" );
124  if( p )
125  {
126  m_ctx = PurgeNodeItems;
127  m_node = p->findAttribute( "node" );
128  return;
129  }
130  const Tag* c = tag->findTag( "pubsub/configure" );
131  if( c )
132  {
133  m_ctx = SetNodeConfig;
134  m_node = c->findAttribute( "node" );
135  if( c->hasChild( "x", "xmlns", XMLNS_X_DATA ) )
136  {
137  m_ctx = GetNodeConfig;
138  m_form = new DataForm( c->findChild( "x", "xmlns", XMLNS_X_DATA ) );
139  }
140  return;
141  }
142  const Tag* de = tag->findTag( "pubsub/default" );
143  if( de )
144  {
145  m_ctx = DefaultNodeConfig;
146  return;
147  }
148  const Tag* s = tag->findTag( "pubsub/subscriptions" );
149  if( s )
150  {
151  m_ctx = GetSubscriberList;
152  m_node = s->findAttribute( "node" );
153  const TagList& l = s->children();
154  TagList::const_iterator it =l.begin();
155  for( ; it != l.end(); ++it )
156  {
157  if( (*it)->name() == "subscription" )
158  {
159  Subscriber sub( (*it)->findAttribute( "jid" ),
160  subscriptionType( (*it)->findAttribute( "subscription" ) ),
161  (*it)->findAttribute( "subid" ) );
162  m_subList.push_back( sub );
163  }
164  }
165  return;
166  }
167  const Tag* a = tag->findTag( "pubsub/affiliations" );
168  if( a )
169  {
170  m_ctx = GetAffiliateList;
171  m_node = a->findAttribute( "node" );
172  const TagList& l = a->children();
173  TagList::const_iterator it = l.begin();
174  for( ; it != l.end(); ++it )
175  {
176  if( (*it)->name() == "affiliation" )
177  {
178  Affiliate aff( (*it)->findAttribute( "jid" ),
179  affiliationType( (*it)->findAttribute( "affiliation" ) ) );
180  m_affList.push_back( aff );
181  }
182  }
183  return;
184  }
185  }
186 
187  Manager::PubSubOwner::~PubSubOwner()
188  {
189  delete m_form;
190  }
191 
192  const std::string& Manager::PubSubOwner::filterString() const
193  {
194  static const std::string filter = "/iq/pubsub[@xmlns='" + XMLNS_PUBSUB_OWNER + "']";
195  return filter;
196  }
197 
198  Tag* Manager::PubSubOwner::tag() const
199  {
200  if( m_ctx == InvalidContext )
201  return 0;
202 
203  Tag* t = new Tag( "pubsub" );
204  t->setXmlns( XMLNS_PUBSUB_OWNER );
205  Tag* c = 0;
206 
207  switch( m_ctx )
208  {
209  case DeleteNode:
210  {
211  c = new Tag( t, "delete", "node", m_node );
212  break;
213  }
214  case PurgeNodeItems:
215  {
216  c = new Tag( t, "purge", "node", m_node );
217  break;
218  }
219  case GetNodeConfig:
220  case SetNodeConfig:
221  {
222  c = new Tag( t, "configure" );
223  c->addAttribute( "node", m_node );
224  if( m_form )
225  c->addChild( m_form->tag() );
226  break;
227  }
228  case GetSubscriberList:
229  case SetSubscriberList:
230 
231  {
232  c = new Tag( t, "subscriptions" );
233  c->addAttribute( "node", m_node );
234  if( m_subList.size() )
235  {
236  Tag* s;
237  SubscriberList::const_iterator it = m_subList.begin();
238  for( ; it != m_subList.end(); ++it )
239  {
240  s = new Tag( c, "subscription" );
241  s->addAttribute( "jid", (*it).jid.full() );
242  s->addAttribute( "subscription", util::lookup( (*it).type, subscriptionValues ) );
243  if( !(*it).subid.empty() )
244  s->addAttribute( "subid", (*it).subid );
245  }
246  }
247  break;
248  }
249  case GetAffiliateList:
250  case SetAffiliateList:
251  {
252  c = new Tag( t, "affiliations" );
253  c->addAttribute( "node", m_node );
254  if( m_affList.size() )
255  {
256  Tag* a;
257  AffiliateList::const_iterator it = m_affList.begin();
258  for( ; it != m_affList.end(); ++it )
259  {
260  a = new Tag( c, "affiliation", "jid", (*it).jid.full() );
261  a->addAttribute( "affiliation", util::lookup( (*it).type, affiliationValues ) );
262  }
263  }
264  break;
265  }
266  case DefaultNodeConfig:
267  {
268  c = new Tag( t, "default" );
269  break;
270  }
271  default:
272  break;
273  }
274 
275  return t;
276  }
277  // ---- ~Manager::PubSubOwner ----
278 
279  // ---- Manager::PubSub ----
280  Manager::PubSub::PubSub( TrackContext context )
281  : StanzaExtension( ExtPubSub ), m_ctx( context ), m_maxItems( 0 ),
282  m_notify( false )
283  {
284  m_options.df = 0;
285  }
286 
287  Manager::PubSub::PubSub( const Tag* tag )
288  : StanzaExtension( ExtPubSub ), m_ctx( InvalidContext ),
289  m_maxItems( 0 ), m_notify( false )
290  {
291  m_options.df = 0;
292  if( !tag )
293  return;
294 
295  const Tag* sl = tag->findTag( "pubsub/subscriptions" );
296  if( sl )
297  {
298  TagList l = sl->children();
299  if( l.size() )
300  {
301  m_ctx = GetSubscriptionList;
302  SubscriptionList lst;
303  m_node = sl->findAttribute( "node" );
304  m_subscriptionMap.insert( std::make_pair( m_node, lst ) );
305  TagList::const_iterator it = l.begin();
306  for( ; it != l.end(); ++it )
307  {
308  const std::string& sub = (*it)->findAttribute( "subscription" );
309  const std::string& subid = (*it)->findAttribute( "subid" );
310  SubscriptionInfo si;
311  si.jid.setJID( (*it)->findAttribute( "jid" ) );
312  si.type = subscriptionType( sub );
313  si.subid = subid;
314  lst.push_back( si );
315  }
316  return;
317  }
318  }
319  ConstTagList l = tag->findTagList( "pubsub/affiliations/affiliation" );
320  if( l.size() )
321  {
322  m_ctx = GetAffiliationList;
323  ConstTagList::const_iterator it = l.begin();
324  for( ; it != l.end(); ++it )
325  {
326  const std::string& node = (*it)->findAttribute( "node" );
327  const std::string& aff = (*it)->findAttribute( "affiliation" );
328  m_affiliationMap[node] = affiliationType( aff );
329  }
330  return;
331  }
332  const Tag* s = tag->findTag( "pubsub/subscribe" );
333  if( s )
334  {
335  m_ctx = Subscription;
336  m_node = s->findAttribute( "node" );
337  m_jid = s->findAttribute( "jid" );
338  }
339  const Tag* u = tag->findTag( "pubsub/unsubscribe" );
340  if( u )
341  {
342  m_ctx = Unsubscription;
343  m_node = u->findAttribute( "node" );
344  m_jid = u->findAttribute( "jid" );
345  m_subid = u->findAttribute( "subid" );
346  }
347  const Tag* o = tag->findTag( "pubsub/options" );
348  if( o )
349  {
350  if( m_ctx == InvalidContext )
351  {
352  Tag* parent = tag->parent();
353  if( parent && parent->findAttribute("type") == "set" )
354  m_ctx = SetSubscriptionOptions;
355  else
356  m_ctx = GetSubscriptionOptions;
357  }
358  if( m_ctx == SetSubscriptionOptions || m_ctx == GetSubscriptionOptions )
359  {
360  // We set both m_node and m_options.node for
361  // get/set options, since m_options.node is not exposed externally
362  m_node = o->findAttribute( "node" );
363  m_jid.setJID( o->findAttribute( "jid" ) );
364  m_subid = o->findAttribute( "subid" );
365  }
366  m_options.node = o->findAttribute( "node" );
367  m_options.df = new DataForm( o->findChild( "x", "xmlns", XMLNS_X_DATA ) );
368  }
369  const Tag* su = tag->findTag( "pubsub/subscription" );
370  if( su )
371  {
372  SubscriptionInfo si;
373  si.jid.setJID( su->findAttribute( "jid" ) );
374  si.subid = su->findAttribute( "subid" );
375  si.type = subscriptionType( su->findAttribute( "subscription" ) );
376  SubscriptionList& lst = m_subscriptionMap[su->findAttribute( "node" )];
377  lst.push_back( si );
378  return;
379  }
380  const Tag* i = tag->findTag( "pubsub/items" );
381  if( i )
382  {
383  m_ctx = RequestItems;
384  m_node = i->findAttribute( "node" );
385  m_subid = i->findAttribute( "subid" );
386  m_maxItems = atoi( i->findAttribute( "max_items" ).c_str() );
387  const TagList& l = i->children();
388  TagList::const_iterator it = l.begin();
389  for( ; it != l.end(); ++it )
390  m_items.push_back( new Item( (*it) ) );
391  return;
392  }
393  const Tag* p = tag->findTag( "pubsub/publish" );
394  if( p )
395  {
396  m_ctx = PublishItem;
397  m_node = p->findAttribute( "node" );
398  const TagList& l = p->children();
399  TagList::const_iterator it = l.begin();
400  for( ; it != l.end(); ++it )
401  m_items.push_back( new Item( (*it) ) );
402  return;
403  }
404  const Tag* r = tag->findTag( "pubsub/retract" );
405  if( r )
406  {
407  m_ctx = DeleteItem;
408  m_node = r->findAttribute( "node" );
409  m_notify = r->hasAttribute( "notify", "1" ) || r->hasAttribute( "notify", "true" );
410  const TagList& l = r->children();
411  TagList::const_iterator it = l.begin();
412  for( ; it != l.end(); ++it )
413  m_items.push_back( new Item( (*it) ) );
414  return;
415  }
416  const Tag* c = tag->findTag( "pubsub/create" );
417  if( c )
418  {
419  m_ctx = CreateNode;
420  m_node = c->findAttribute( "node" );
421  const Tag* config = tag->findTag( "pubsub/configure" );
422  if( config && config->hasChild( "x", XMLNS_X_DATA ) )
423  m_options.df = new DataForm( config->findChild( "x", XMLNS_X_DATA ) );
424  }
425  }
426 
427  Manager::PubSub::~PubSub()
428  {
429  delete m_options.df;
430  util::clearList( m_items );
431  }
432 
433  const std::string& Manager::PubSub::filterString() const
434  {
435  static const std::string filter = "/iq/pubsub[@xmlns='" + XMLNS_PUBSUB + "']";
436  return filter;
437  }
438 
439  Tag* Manager::PubSub::tag() const
440  {
441  if( m_ctx == InvalidContext )
442  return 0;
443 
444  Tag* t = new Tag( "pubsub" );
445  t->setXmlns( XMLNS_PUBSUB );
446 
447  if( m_ctx == GetSubscriptionList )
448  {
449  Tag* sub = new Tag( t, "subscriptions" );
450  SubscriptionMap::const_iterator it = m_subscriptionMap.begin();
451  for( ; it != m_subscriptionMap.end(); ++it )
452  {
453  const SubscriptionList& lst = (*it).second;
454  SubscriptionList::const_iterator it2 = lst.begin();
455  for( ; it2 != lst.end(); ++it2 )
456  {
457  Tag* s = new Tag( sub, "subscription" );
458  s->addAttribute( "node", (*it).first );
459  s->addAttribute( "jid", (*it2).jid );
460  s->addAttribute( "subscription", subscriptionValue( (*it2).type ) );
461  s->addAttribute( "sid", (*it2).subid );
462  }
463  }
464  }
465  else if( m_ctx == GetAffiliationList )
466  {
467 
468  Tag* aff = new Tag( t, "affiliations" );
469  AffiliationMap::const_iterator it = m_affiliationMap.begin();
470  for( ; it != m_affiliationMap.end(); ++it )
471  {
472  Tag* a = new Tag( aff, "affiliation" );
473  a->addAttribute( "node", (*it).first );
474  a->addAttribute( "affiliation", affiliationValue( (*it).second ) );
475  }
476  }
477  else if( m_ctx == Subscription )
478  {
479  Tag* s = new Tag( t, "subscribe" );
480  s->addAttribute( "node", m_node );
481  s->addAttribute( "jid", m_jid.full() );
482  if( m_options.df )
483  {
484  Tag* o = new Tag( t, "options" );
485  o->addChild( m_options.df->tag() );
486  }
487  }
488  else if( m_ctx == Unsubscription )
489  {
490  Tag* u = new Tag( t, "unsubscribe" );
491  u->addAttribute( "node", m_node );
492  u->addAttribute( "jid", m_jid.full() );
493  u->addAttribute( "subid", m_subid );
494  }
495  else if( m_ctx == GetSubscriptionOptions
496  || m_ctx == SetSubscriptionOptions )
497  {
498  Tag* o = new Tag( t, "options" );
499  o->addAttribute( "node", m_options.node );
500  o->addAttribute( "jid", m_jid.full() );
501  if( !m_subid.empty() )
502  o->addAttribute( "subid", m_subid );
503  if( m_options.df )
504  o->addChild( m_options.df->tag() );
505  }
506  else if( m_ctx == RequestItems )
507  {
508  Tag* i = new Tag( t, "items" );
509  i->addAttribute( "node", m_node );
510  if( m_maxItems )
511  i->addAttribute( "max_items", m_maxItems );
512  i->addAttribute( "subid", m_subid );
513  ItemList::const_iterator it = m_items.begin();
514  for( ; it != m_items.end(); ++it )
515  i->addChild( (*it)->tag() );
516  }
517  else if( m_ctx == PublishItem )
518  {
519  Tag* p = new Tag( t, "publish" );
520  p->addAttribute( "node", m_node );
521  ItemList::const_iterator it = m_items.begin();
522  for( ; it != m_items.end(); ++it )
523  p->addChild( (*it)->tag() );
524  if( m_options.df )
525  {
526  Tag* po = new Tag( "publish-options" );
527  po->addChild( m_options.df->tag() );
528  }
529  }
530  else if( m_ctx == DeleteItem )
531  {
532  Tag* r = new Tag( t, "retract" );
533  r->addAttribute( "node", m_node );
534  if( m_notify )
535  r->addAttribute( "notify", "true" );
536  ItemList::const_iterator it = m_items.begin();
537  for( ; it != m_items.end(); ++it )
538  r->addChild( (*it)->tag() );
539  }
540  else if( m_ctx == CreateNode )
541  {
542  Tag* c = new Tag( t, "create" );
543  c->addAttribute( "node", m_node );
544  Tag* config = new Tag( t, "configure" );
545  if( m_options.df )
546  config->addChild( m_options.df->tag() );
547  }
548  return t;
549  }
550 
551  StanzaExtension* Manager::PubSub::clone() const
552  {
553  PubSub* p = new PubSub();
554  p->m_affiliationMap = m_affiliationMap;
555  p->m_subscriptionMap = m_subscriptionMap;
556  p->m_ctx = m_ctx;
557 
558  p->m_options.node = m_options.node;
559  p->m_options.df = m_options.df ? new DataForm( *(m_options.df) ) : 0;
560 
561  p->m_jid = m_jid;
562  p->m_node = m_node;
563  p->m_subid = m_subid;
564  ItemList::const_iterator it = m_items.begin();
565  for( ; it != m_items.end(); ++it )
566  p->m_items.push_back( new Item( *(*it) ) );
567 
568  p->m_maxItems = m_maxItems;
569  p->m_notify = m_notify;
570  return p;
571  }
572  // ---- ~Manager::PubSub ----
573 
574  // ---- Manager ----
576  : m_parent( parent )
577  {
578  if( m_parent )
579  {
580  m_parent->registerStanzaExtension( new PubSub() );
581  m_parent->registerStanzaExtension( new PubSubOwner() );
582  m_parent->registerStanzaExtension( new SHIM() );
583  }
584  }
585 
586  const std::string Manager::getSubscriptionsOrAffiliations( const JID& service,
587  ResultHandler* handler,
588  TrackContext context )
589  {
590  if( !m_parent || !handler || !service || context == InvalidContext )
591  return EmptyString;
592 
593  const std::string& id = m_parent->getID();
594  IQ iq( IQ::Get, service, id );
595  iq.addExtension( new PubSub( context ) );
596 
597  m_trackMapMutex.lock();
598  m_resultHandlerTrackMap[id] = handler;
599  m_trackMapMutex.unlock();
600  m_parent->send( iq, this, context );
601  return id;
602  }
603 
604  const std::string Manager::subscribe( const JID& service,
605  const std::string& node,
606  ResultHandler* handler,
607  const JID& jid,
608  SubscriptionObject type,
609  int depth,
610  const std::string& expire
611  )
612  {
613  if( !m_parent || !handler || !service || node.empty() )
614  return EmptyString;
615 
616  DataForm* options = 0;
617  if( type != SubscriptionNodes || depth != 1 )
618  {
619  options = new DataForm( TypeSubmit );
620  options->addField( DataFormField::TypeHidden, "FORM_TYPE", XMLNS_PUBSUB_SUBSCRIBE_OPTIONS );
621 
622  if( type == SubscriptionItems )
623  options->addField( DataFormField::TypeNone, "pubsub#subscription_type", "items" );
624 
625  if( depth != 1 )
626  {
627  DataFormField* field = options->addField( DataFormField::TypeNone, "pubsub#subscription_depth" );
628  if( depth == 0 )
629  field->setValue( "all" );
630  else
631  field->setValue( util::int2string( depth ) );
632  }
633 
634  if( !expire.empty() )
635  {
636  DataFormField* field = options->addField( DataFormField::TypeNone, "pubsub#expire" );
637  field->setValue( expire );
638  }
639  }
640 
641  return subscribe( service, node, handler, jid, options );
642  }
643 
644  const std::string Manager::subscribe( const JID& service,
645  const std::string& node,
646  ResultHandler* handler,
647  const JID& jid,
648  DataForm* options
649  )
650  {
651  if( !m_parent || !handler || !service || node.empty() )
652  return EmptyString;
653 
654  const std::string& id = m_parent->getID();
655  IQ iq( IQ::Set, service, id );
656  PubSub* ps = new PubSub( Subscription );
657  ps->setJID( jid ? jid : m_parent->jid() );
658  ps->setNode( node );
659  if( options != NULL )
660  ps->setOptions( node, options );
661  iq.addExtension( ps );
662 
663  m_trackMapMutex.lock();
664  m_resultHandlerTrackMap[id] = handler;
665  m_nopTrackMap[id] = node;
666  m_trackMapMutex.unlock();
667  m_parent->send( iq, this, Subscription );
668  return id;
669  }
670 
671  const std::string Manager::unsubscribe( const JID& service,
672  const std::string& node,
673  const std::string& subid,
674  ResultHandler* handler,
675  const JID& jid )
676  {
677  if( !m_parent || !handler || !service )
678  return EmptyString;
679 
680  const std::string& id = m_parent->getID();
681  IQ iq( IQ::Set, service, id );
682  PubSub* ps = new PubSub( Unsubscription );
683  ps->setNode( node );
684  ps->setJID( jid ? jid : m_parent->jid() );
685  ps->setSubscriptionID( subid );
686  iq.addExtension( ps );
687 
688  m_trackMapMutex.lock();
689  m_resultHandlerTrackMap[id] = handler;
690  m_trackMapMutex.unlock();
691  // FIXME? need to track info for handler
692  m_parent->send( iq, this, Unsubscription );
693  return id;
694  }
695 
696  const std::string Manager::subscriptionOptions( TrackContext context,
697  const JID& service,
698  const JID& jid,
699  const std::string& node,
700  ResultHandler* handler,
701  DataForm* df,
702  const std::string& subid )
703  {
704  if( !m_parent || !handler || !service )
705  return EmptyString;
706 
707  const std::string& id = m_parent->getID();
708  IQ iq( df ? IQ::Set : IQ::Get, service, id );
709  PubSub* ps = new PubSub( context );
710  ps->setJID( jid ? jid : m_parent->jid() );
711  if( !subid.empty() )
712  ps->setSubscriptionID( subid );
713  ps->setOptions( node, df );
714  iq.addExtension( ps );
715 
716  m_trackMapMutex.lock();
717  m_resultHandlerTrackMap[id] = handler;
718  m_trackMapMutex.unlock();
719  m_parent->send( iq, this, context );
720  return id;
721  }
722 
723  const std::string Manager::requestItems( const JID& service,
724  const std::string& node,
725  const std::string& subid,
726  int maxItems,
727  ResultHandler* handler )
728  {
729  if( !m_parent || !service || !handler )
730  return EmptyString;
731 
732  const std::string& id = m_parent->getID();
733  IQ iq( IQ::Get, service, id );
734  PubSub* ps = new PubSub( RequestItems );
735  ps->setNode( node );
736  ps->setSubscriptionID( subid );
737  ps->setMaxItems( maxItems );
738  iq.addExtension( ps );
739 
740  m_trackMapMutex.lock();
741  m_resultHandlerTrackMap[id] = handler;
742  m_trackMapMutex.unlock();
743  m_parent->send( iq, this, RequestItems );
744  return id;
745  }
746 
747  const std::string Manager::requestItems( const JID& service,
748  const std::string& node,
749  const std::string& subid,
750  const ItemList& items,
751  ResultHandler* handler )
752  {
753  if( !m_parent || !service || !handler )
754  return EmptyString;
755 
756  const std::string& id = m_parent->getID();
757  IQ iq( IQ::Get, service, id );
758  PubSub* ps = new PubSub( RequestItems );
759  ps->setNode( node );
760  ps->setSubscriptionID( subid );
761  ps->setItems( items );
762  iq.addExtension( ps );
763 
764  m_trackMapMutex.lock();
765  m_resultHandlerTrackMap[id] = handler;
766  m_trackMapMutex.unlock();
767  m_parent->send( iq, this, RequestItems );
768  return id;
769  }
770 
771  const std::string Manager::publishItem( const JID& service,
772  const std::string& node,
773  ItemList& items,
774  DataForm* options,
775  ResultHandler* handler )
776  {
777  if( !m_parent || !handler )
778  {
779  util::clearList( items );
780  return EmptyString;
781  }
782 
783  const std::string& id = m_parent->getID();
784  IQ iq( IQ::Set, service, id );
785  PubSub* ps = new PubSub( PublishItem );
786  ps->setNode( node );
787  ps->setItems( items );
788  ps->setOptions( EmptyString, options );
789  iq.addExtension( ps );
790 
791  m_trackMapMutex.lock();
792  m_resultHandlerTrackMap[id] = handler;
793  m_trackMapMutex.unlock();
794  m_parent->send( iq, this, PublishItem );
795  return id;
796  }
797 
798  const std::string Manager::deleteItem( const JID& service,
799  const std::string& node,
800  const ItemList& items,
801  bool notify,
802  ResultHandler* handler )
803  {
804  if( !m_parent || !handler || !service )
805  return EmptyString;
806 
807  const std::string& id = m_parent->getID();
808  IQ iq( IQ::Set, service, id );
809  PubSub* ps = new PubSub( DeleteItem );
810  ps->setNode( node );
811  ps->setItems( items );
812  ps->setNotify( notify );
813  iq.addExtension( ps );
814 
815  m_trackMapMutex.lock();
816  m_resultHandlerTrackMap[id] = handler;
817  m_trackMapMutex.unlock();
818  m_parent->send( iq, this, DeleteItem );
819  return id;
820  }
821 
822  const std::string Manager::createNode( const JID& service,
823  const std::string& node,
824  DataForm* config,
825  ResultHandler* handler )
826  {
827  if( !m_parent || !handler || !service || node.empty() )
828  return EmptyString;
829 
830  const std::string& id = m_parent->getID();
831  IQ iq( IQ::Set, service, id );
832  PubSub* ps = new PubSub( CreateNode );
833  ps->setNode( node );
834  ps->setOptions( EmptyString, config );
835  iq.addExtension( ps );
836 
837  m_trackMapMutex.lock();
838  m_nopTrackMap[id] = node;
839  m_resultHandlerTrackMap[id] = handler;
840  m_trackMapMutex.unlock();
841  m_parent->send( iq, this, CreateNode );
842  return id;
843  }
844 
845  const std::string Manager::deleteNode( const JID& service,
846  const std::string& node,
847  ResultHandler* handler )
848  {
849  if( !m_parent || !handler || !service || node.empty() )
850  return EmptyString;
851 
852  const std::string& id = m_parent->getID();
853  IQ iq( IQ::Set, service, id );
854  PubSubOwner* pso = new PubSubOwner( DeleteNode );
855  pso->setNode( node );
856  iq.addExtension( pso );
857 
858  m_trackMapMutex.lock();
859  m_nopTrackMap[id] = node;
860  m_resultHandlerTrackMap[id] = handler;
861  m_trackMapMutex.unlock();
862  m_parent->send( iq, this, DeleteNode );
863  return id;
864  }
865 
866  const std::string Manager::getDefaultNodeConfig( const JID& service,
867  NodeType type,
868  ResultHandler* handler )
869  {
870  if( !m_parent || !handler || !service )
871  return EmptyString;
872 
873  const std::string& id = m_parent->getID();
874  IQ iq( IQ::Get, service, id );
875  PubSubOwner* pso = new PubSubOwner( DefaultNodeConfig );
876  if( type == NodeCollection )
877  {
878  DataForm* df = new DataForm( TypeSubmit );
879  df->addField( DataFormField::TypeHidden, "FORM_TYPE", XMLNS_PUBSUB_NODE_CONFIG );
880  df->addField( DataFormField::TypeNone, "pubsub#node_type", "collection" );
881  pso->setConfig( df );
882  }
883  iq.addExtension( pso );
884 
885  m_trackMapMutex.lock();
886  m_resultHandlerTrackMap[id] = handler;
887  m_trackMapMutex.unlock();
888  m_parent->send( iq, this, DefaultNodeConfig );
889  return id;
890  }
891 
892  const std::string Manager::nodeConfig( const JID& service,
893  const std::string& node,
894  DataForm* config,
895  ResultHandler* handler )
896  {
897  if( !m_parent || !handler || !service || node.empty() )
898  return EmptyString;
899 
900  const std::string& id = m_parent->getID();
901  IQ iq( config ? IQ::Set : IQ::Get, service, id );
902  PubSubOwner* pso = new PubSubOwner( config ? SetNodeConfig : GetNodeConfig );
903  pso->setNode( node );
904  if( config )
905  pso->setConfig( config );
906  iq.addExtension( pso );
907 
908  m_trackMapMutex.lock();
909  m_nopTrackMap[id] = node;
910  m_resultHandlerTrackMap[id] = handler;
911  m_trackMapMutex.unlock();
912  m_parent->send( iq, this, config ? SetNodeConfig : GetNodeConfig );
913  return id;
914  }
915 
916  const std::string Manager::subscriberList( TrackContext ctx,
917  const JID& service,
918  const std::string& node,
919  const SubscriberList& subList,
920  ResultHandler* handler )
921  {
922  if( !m_parent || !handler || !service || node.empty() )
923  return EmptyString;
924 
925  const std::string& id = m_parent->getID();
926  IQ iq( ctx == SetSubscriberList ? IQ::Set : IQ::Get, service, id );
927  PubSubOwner* pso = new PubSubOwner( ctx );
928  pso->setNode( node );
929  pso->setSubscriberList( subList );
930  iq.addExtension( pso );
931 
932  m_trackMapMutex.lock();
933  m_nopTrackMap[id] = node;
934  m_resultHandlerTrackMap[id] = handler;
935  m_trackMapMutex.unlock();
936  m_parent->send( iq, this, ctx );
937  return id;
938  }
939 
940  const std::string Manager::affiliateList( TrackContext ctx,
941  const JID& service,
942  const std::string& node,
943  const AffiliateList& affList,
944  ResultHandler* handler )
945  {
946  if( !m_parent || !handler || !service || node.empty() )
947  return EmptyString;
948 
949  const std::string& id = m_parent->getID();
950  IQ iq( ctx == SetAffiliateList ? IQ::Set : IQ::Get, service, id );
951  PubSubOwner* pso = new PubSubOwner( ctx );
952  pso->setNode( node );
953  pso->setAffiliateList( affList );
954  iq.addExtension( pso );
955 
956  m_trackMapMutex.lock();
957  m_nopTrackMap[id] = node;
958  m_resultHandlerTrackMap[id] = handler;
959  m_trackMapMutex.unlock();
960  m_parent->send( iq, this, ctx );
961  return id;
962  }
963 
964  const std::string Manager::purgeNode( const JID& service,
965  const std::string& node,
966  ResultHandler* handler )
967  {
968  if( !m_parent || !handler || !service || node.empty() )
969  return EmptyString;
970 
971  const std::string& id = m_parent->getID();
972  IQ iq( IQ::Set, service, id );
973  PubSubOwner* pso = new PubSubOwner( PurgeNodeItems );
974  pso->setNode( node );
975  iq.addExtension( pso );
976 
977  m_trackMapMutex.lock();
978  m_nopTrackMap[id] = node;
979  m_resultHandlerTrackMap[id] = handler;
980  m_trackMapMutex.unlock();
981  m_parent->send( iq, this, PurgeNodeItems );
982  return id;
983  }
984 
985  bool Manager::removeID( const std::string& id )
986  {
987  m_trackMapMutex.lock();
988  ResultHandlerTrackMap::iterator ith = m_resultHandlerTrackMap.find( id );
989  if( ith == m_resultHandlerTrackMap.end() )
990  {
991  m_trackMapMutex.unlock();
992  return false;
993  }
994  m_resultHandlerTrackMap.erase( ith );
995  m_trackMapMutex.unlock();
996  return true;
997  }
998 
999  void Manager::handleIqID( const IQ& iq, int context )
1000  {
1001  const JID& service = iq.from();
1002  const std::string& id = iq.id();
1003 
1004  m_trackMapMutex.lock();
1005  ResultHandlerTrackMap::iterator ith = m_resultHandlerTrackMap.find( id );
1006  if( ith == m_resultHandlerTrackMap.end() )
1007  {
1008  m_trackMapMutex.unlock();
1009  return;
1010  }
1011  ResultHandler* rh = (*ith).second;
1012  m_resultHandlerTrackMap.erase( ith );
1013  m_trackMapMutex.unlock();
1014 
1015  switch( iq.subtype() )
1016  {
1017  case IQ::Error:
1018  case IQ::Result:
1019  {
1020  const Error* error = iq.error();
1021  switch( context )
1022  {
1023  case Subscription:
1024  {
1025  const PubSub* ps = iq.findExtension<PubSub>( ExtPubSub );
1026  if( !ps )
1027  return;
1028  SubscriptionMap sm = ps->subscriptions();
1029  if( !sm.empty() )
1030  {
1031  SubscriptionMap::const_iterator it = sm.begin();
1032  const SubscriptionList& lst = (*it).second;
1033  if( lst.size() == 1 )
1034  {
1035  SubscriptionList::const_iterator it2 = lst.begin();
1036  rh->handleSubscriptionResult( id, service, (*it).first, (*it2).subid, (*it2).jid,
1037  (*it2).type, error );
1038  }
1039  }
1040  break;
1041  }
1042  case Unsubscription:
1043  {
1044  rh->handleUnsubscriptionResult( iq.id(), service, error );
1045  break;
1046  }
1047  case GetSubscriptionList:
1048  {
1049  const PubSub* ps = iq.findExtension<PubSub>( ExtPubSub );
1050  if( !ps )
1051  return;
1052 
1053  rh->handleSubscriptions( id, service,
1054  ps->subscriptions(),
1055  error );
1056  break;
1057  }
1058  case GetAffiliationList:
1059  {
1060  const PubSub* ps = iq.findExtension<PubSub>( ExtPubSub );
1061  if( !ps )
1062  return;
1063 
1064  rh->handleAffiliations( id, service,
1065  ps->affiliations(),
1066  error );
1067  break;
1068  }
1069  case RequestItems:
1070  {
1071  const PubSub* ps = iq.findExtension<PubSub>( ExtPubSub );
1072  if( !ps )
1073  return;
1074 
1075  rh->handleItems( id, service, ps->node(),
1076  ps->items(), error );
1077  break;
1078  }
1079  case PublishItem:
1080  {
1081  const PubSub* ps = iq.findExtension<PubSub>( ExtPubSub );
1082  rh->handleItemPublication( id, service, "",
1083  ps ? ps->items() : ItemList(),
1084  error );
1085  break;
1086  }
1087  case DeleteItem:
1088  {
1089  const PubSub* ps = iq.findExtension<PubSub>( ExtPubSub );
1090  if( ps )
1091  {
1092  rh->handleItemDeletion( id, service,
1093  ps->node(),
1094  ps->items(),
1095  error );
1096  }
1097  break;
1098  }
1099  case DefaultNodeConfig:
1100  {
1101  const PubSubOwner* pso = iq.findExtension<PubSubOwner>( ExtPubSubOwner );
1102  if( pso )
1103  {
1104  rh->handleDefaultNodeConfig( id, service,
1105  pso->config(),
1106  error );
1107  }
1108  break;
1109  }
1110  case GetSubscriptionOptions:
1111  case GetSubscriberList:
1112  case SetSubscriberList:
1113  case GetAffiliateList:
1114  case SetAffiliateList:
1115  case GetNodeConfig:
1116  case SetNodeConfig:
1117  case CreateNode:
1118  case DeleteNode:
1119  case PurgeNodeItems:
1120  {
1121  switch( context )
1122  {
1123  case GetSubscriptionOptions:
1124  {
1125  const PubSub* ps = iq.findExtension<PubSub>( ExtPubSub );
1126  if( ps )
1127  {
1128  rh->handleSubscriptionOptions( id, service,
1129  ps->jid(),
1130  ps->node(),
1131  ps->options(),
1132  ps->subscriptionID(),
1133  error );
1134  }
1135  break;
1136  }
1137  case GetSubscriberList:
1138  {
1139  const PubSub* ps = iq.findExtension<PubSub>( ExtPubSub );
1140  if( ps )
1141  {
1142  const SubscriptionMap& sm = ps->subscriptions();
1143  SubscriptionMap::const_iterator itsm = sm.find( ps->node() );
1144  if( itsm != sm.end() )
1145  rh->handleSubscribers( iq.id(), service, ps->node(), (*itsm).second, 0 );
1146  }
1147  break;
1148  }
1149  case SetSubscriptionOptions:
1150  case SetSubscriberList:
1151  case SetAffiliateList:
1152  case SetNodeConfig:
1153  case CreateNode:
1154  case DeleteNode:
1155  case PurgeNodeItems:
1156  {
1157  m_trackMapMutex.lock();
1158  NodeOperationTrackMap::iterator it = m_nopTrackMap.find( id );
1159  if( it != m_nopTrackMap.end() )
1160  {
1161  const std::string& node = (*it).second;
1162  switch( context )
1163  {
1164  case SetSubscriptionOptions:
1165  {
1166  const PubSub* ps = iq.findExtension<PubSub>( ExtPubSub );
1167  if( ps )
1168  {
1169  rh->handleSubscriptionOptionsResult( id, service,
1170  ps->jid(),
1171  node,
1172  ps->subscriptionID(),
1173  error );
1174  }
1175  else
1176  {
1177  rh->handleSubscriptionOptionsResult( id, service, JID( /* FIXME */ ), node, /* FIXME */ EmptyString, error );
1178  }
1179  break;
1180  }
1181  case SetSubscriberList:
1182  rh->handleSubscribersResult( id, service, node, 0, error );
1183  break;
1184  case SetAffiliateList:
1185  rh->handleAffiliatesResult( id, service, node, 0, error );
1186  break;
1187  case SetNodeConfig:
1188  rh->handleNodeConfigResult( id, service, node, error );
1189  break;
1190  case CreateNode:
1191  rh->handleNodeCreation( id, service, node, error );
1192  break;
1193  case DeleteNode:
1194  rh->handleNodeDeletion( id, service, node, error );
1195  break;
1196  case PurgeNodeItems:
1197  rh->handleNodePurge( id, service, node, error );
1198  break;
1199  }
1200  m_nopTrackMap.erase( it );
1201  }
1202  m_trackMapMutex.unlock();
1203  break;
1204  }
1205  case GetAffiliateList:
1206  {
1207  const PubSubOwner* pso = iq.findExtension<PubSubOwner>( ExtPubSubOwner );
1208  if( pso )
1209  {
1210  rh->handleAffiliates( id, service, pso->node(), pso->affiliateList(), error );
1211  }
1212  break;
1213  }
1214  case GetNodeConfig:
1215  {
1216  const PubSubOwner* pso = iq.findExtension<PubSubOwner>( ExtPubSubOwner );
1217  if( pso )
1218  {
1219  rh->handleNodeConfig( id, service,
1220  pso->node(),
1221  pso->config(),
1222  error );
1223  }
1224  break;
1225  }
1226  default:
1227  break;
1228  }
1229 
1230  break;
1231  }
1232  }
1233  break;
1234  }
1235  default:
1236  break;
1237  }
1238 
1239  }
1240 
1241  }
1242 
1243 }
1244 
virtual void handleItemPublication(const std::string &id, const JID &service, const std::string &node, const ItemList &itemList, const Error *error=0)=0
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
virtual void handleSubscriptions(const std::string &id, const JID &service, const SubscriptionMap &subMap, const Error *error=0)=0
const std::string purgeNode(const JID &service, const std::string &node, ResultHandler *handler)
virtual void handleNodeConfigResult(const std::string &id, const JID &service, const std::string &node, const Error *error=0)=0
const std::string deleteNode(const JID &service, const std::string &node, ResultHandler *handler)
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
void clearList(std::list< T * > &L)
Definition: util.h:152
An abstraction of an IQ stanza.
Definition: iq.h:33
An abstraction of a XEP-0004 Data Form.
Definition: dataform.h:56
const std::string getDefaultNodeConfig(const JID &service, NodeType type, ResultHandler *handler)
void addExtension(const StanzaExtension *se)
Definition: stanza.cpp:52
virtual void handleNodeConfig(const std::string &id, const JID &service, const std::string &node, const DataForm *config, const Error *error=0)=0
An abstraction of a single field in a XEP-0004 Data Form.
Definition: dataformfield.h:33
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)
void send(Tag *tag)
Definition: clientbase.cpp:996
const std::string createNode(const JID &service, const std::string &node, DataForm *config, ResultHandler *handler)
virtual void addField(DataFormField *field)
void registerStanzaExtension(StanzaExtension *ext)
SubscriptionObject
Definition: pubsub.h:96
virtual void handleSubscribers(const std::string &id, const JID &service, const std::string &node, const SubscriptionList &list, const Error *error=0)=0
std::list< Tag * > TagList
Definition: tag.h:26
virtual void handleUnsubscriptionResult(const std::string &id, const JID &service, const Error *error=0)=0
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
virtual void handleAffiliatesResult(const std::string &id, const JID &service, const std::string &node, const AffiliateList *list, const Error *error=0)=0
std::list< const Tag * > ConstTagList
Definition: tag.h:36
virtual void handleIqID(const IQ &iq, int context)
const std::string XMLNS_PUBSUB_OWNER
Definition: gloox.cpp:80
const std::string publishItem(const JID &service, const std::string &node, ItemList &items, DataForm *options, ResultHandler *handler)
A stanza error abstraction implemented as a StanzaExtension.
Definition: error.h:34
const std::string unsubscribe(const JID &service, const std::string &node, const std::string &subid, ResultHandler *handler, const JID &jid=JID())
virtual void handleNodePurge(const std::string &id, const JID &service, const std::string &node, const Error *error=0)=0
virtual void handleNodeDeletion(const std::string &id, const JID &service, const std::string &node, const Error *error=0)=0
const JID & jid()
Definition: clientbase.h:147
const std::string XMLNS_X_DATA
Definition: gloox.cpp:49
virtual void handleItems(const std::string &id, const JID &service, const std::string &node, const ItemList &itemList, const Error *error=0)=0
virtual void handleAffiliates(const std::string &id, const JID &service, const std::string &node, const AffiliateList *list, const Error *error=0)=0
bool removeID(const std::string &id)
void setValue(const std::string &value)
The namespace for the gloox library.
Definition: adhoc.cpp:27
virtual void handleSubscribersResult(const std::string &id, const JID &service, const std::string &node, const SubscriberList *list, const Error *error=0)=0
virtual void handleNodeCreation(const std::string &id, const JID &service, const std::string &node, const Error *error=0)=0
A virtual interface to receive item related requests results.
const std::string XMLNS_PUBSUB
Definition: gloox.cpp:77
An abstraction of a JID.
Definition: jid.h:30
virtual void handleItemDeletion(const std::string &id, const JID &service, const std::string &node, const ItemList &itemList, const Error *error=0)=0
Manager(ClientBase *parent)
IqType subtype() const
Definition: iq.h:74
const std::string requestItems(const JID &service, const std::string &node, const std::string &subid, int maxItems, ResultHandler *handler)
const std::string getID()
const Error * error() const
Definition: stanza.cpp:47
An abstraction of a subscription stanza.
Definition: subscription.h:31
An implementation/abstraction of Stanza Headers and Internet Metadata (SHIM, XEP-0131).
Definition: shim.h:35
SubscriptionType
Definition: pubsub.h:60
virtual void handleDefaultNodeConfig(const std::string &id, const JID &service, const DataForm *config, const Error *error=0)=0
const std::string & id() const
Definition: stanza.h:63
virtual void handleAffiliations(const std::string &id, const JID &service, const AffiliationMap &affMap, const Error *error=0)=0
const std::string EmptyString
Definition: gloox.cpp:123
const std::string deleteItem(const JID &service, const std::string &node, const ItemList &items, bool notify, ResultHandler *handler)
This is the common base class for a Jabber/XMPP Client and a Jabber Component.
Definition: clientbase.h:76
const StanzaExtension * findExtension(int type) const
Definition: stanza.cpp:57
const JID & from() const
Definition: stanza.h:51