gloox  1.0.20
pubsubmanager.cpp
1 /*
2  Copyright (c) 2007-2017 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 static_cast<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 static_cast<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  TagList::const_iterator it = l.begin();
303  for( ; it != l.end(); ++it )
304  {
305  const std::string& node = (*it)->findAttribute( "node" );
306  const std::string& sub = (*it)->findAttribute( "subscription" );
307  const std::string& subid = (*it)->findAttribute( "subid" );
308  SubscriptionInfo si;
309  si.jid.setJID( (*it)->findAttribute( "jid" ) );
310  si.type = subscriptionType( sub );
311  si.subid = subid;
312 
313  SubscriptionMap::iterator iter = m_subscriptionMap.find( node );
314  if( iter == m_subscriptionMap.end() )
315  {
316  iter = m_subscriptionMap.insert( std::make_pair( node, SubscriptionList() ) ).first;
317  }
318 
319  SubscriptionList& lst = iter->second;
320  lst.push_back( si );
321  }
322  return;
323  }
324  }
325  ConstTagList l = tag->findTagList( "pubsub/affiliations/affiliation" );
326  if( l.size() )
327  {
328  m_ctx = GetAffiliationList;
329  ConstTagList::const_iterator it = l.begin();
330  for( ; it != l.end(); ++it )
331  {
332  const std::string& node = (*it)->findAttribute( "node" );
333  const std::string& aff = (*it)->findAttribute( "affiliation" );
334  m_affiliationMap[node] = affiliationType( aff );
335  }
336  return;
337  }
338  const Tag* s = tag->findTag( "pubsub/subscribe" );
339  if( s )
340  {
341  m_ctx = Subscription;
342  m_node = s->findAttribute( "node" );
343  m_jid = s->findAttribute( "jid" );
344  }
345  const Tag* u = tag->findTag( "pubsub/unsubscribe" );
346  if( u )
347  {
348  m_ctx = Unsubscription;
349  m_node = u->findAttribute( "node" );
350  m_jid = u->findAttribute( "jid" );
351  m_subid = u->findAttribute( "subid" );
352  }
353  const Tag* o = tag->findTag( "pubsub/options" );
354  if( o )
355  {
356  if( m_ctx == InvalidContext )
357  {
358  Tag* parent = tag->parent();
359  if( parent && parent->findAttribute("type") == "set" )
360  m_ctx = SetSubscriptionOptions;
361  else
362  m_ctx = GetSubscriptionOptions;
363  }
364  if( m_ctx == SetSubscriptionOptions || m_ctx == GetSubscriptionOptions )
365  {
366  // We set both m_node and m_options.node for
367  // get/set options, since m_options.node is not exposed externally
368  m_node = o->findAttribute( "node" );
369  m_jid.setJID( o->findAttribute( "jid" ) );
370  m_subid = o->findAttribute( "subid" );
371  }
372  m_options.node = o->findAttribute( "node" );
373  m_options.df = new DataForm( o->findChild( "x", "xmlns", XMLNS_X_DATA ) );
374  }
375  const Tag* su = tag->findTag( "pubsub/subscription" );
376  if( su )
377  {
378  SubscriptionInfo si;
379  si.jid.setJID( su->findAttribute( "jid" ) );
380  si.subid = su->findAttribute( "subid" );
381  si.type = subscriptionType( su->findAttribute( "subscription" ) );
382  SubscriptionList& lst = m_subscriptionMap[su->findAttribute( "node" )];
383  lst.push_back( si );
384  return;
385  }
386  const Tag* i = tag->findTag( "pubsub/items" );
387  if( i )
388  {
389  m_ctx = RequestItems;
390  m_node = i->findAttribute( "node" );
391  m_subid = i->findAttribute( "subid" );
392  m_maxItems = atoi( i->findAttribute( "max_items" ).c_str() );
393  const TagList& l = i->children();
394  TagList::const_iterator it = l.begin();
395  for( ; it != l.end(); ++it )
396  m_items.push_back( new Item( (*it) ) );
397  return;
398  }
399  const Tag* p = tag->findTag( "pubsub/publish" );
400  if( p )
401  {
402  m_ctx = PublishItem;
403  m_node = p->findAttribute( "node" );
404  const TagList& l = p->children();
405  TagList::const_iterator it = l.begin();
406  for( ; it != l.end(); ++it )
407  m_items.push_back( new Item( (*it) ) );
408  return;
409  }
410  const Tag* r = tag->findTag( "pubsub/retract" );
411  if( r )
412  {
413  m_ctx = DeleteItem;
414  m_node = r->findAttribute( "node" );
415  m_notify = r->hasAttribute( "notify", "1" ) || r->hasAttribute( "notify", "true" );
416  const TagList& l = r->children();
417  TagList::const_iterator it = l.begin();
418  for( ; it != l.end(); ++it )
419  m_items.push_back( new Item( (*it) ) );
420  return;
421  }
422  const Tag* c = tag->findTag( "pubsub/create" );
423  if( c )
424  {
425  m_ctx = CreateNode;
426  m_node = c->findAttribute( "node" );
427  const Tag* config = tag->findTag( "pubsub/configure" );
428  if( config && config->hasChild( "x", XMLNS_X_DATA ) )
429  m_options.df = new DataForm( config->findChild( "x", XMLNS_X_DATA ) );
430  }
431  }
432 
433  Manager::PubSub::~PubSub()
434  {
435  delete m_options.df;
436  util::clearList( m_items );
437  }
438 
439  const std::string& Manager::PubSub::filterString() const
440  {
441  static const std::string filter = "/iq/pubsub[@xmlns='" + XMLNS_PUBSUB + "']";
442  return filter;
443  }
444 
445  Tag* Manager::PubSub::tag() const
446  {
447  if( m_ctx == InvalidContext )
448  return 0;
449 
450  Tag* t = new Tag( "pubsub" );
451  t->setXmlns( XMLNS_PUBSUB );
452 
453  if( m_ctx == GetSubscriptionList )
454  {
455  Tag* sub = new Tag( t, "subscriptions" );
456  SubscriptionMap::const_iterator it = m_subscriptionMap.begin();
457  for( ; it != m_subscriptionMap.end(); ++it )
458  {
459  const SubscriptionList& lst = (*it).second;
460  SubscriptionList::const_iterator it2 = lst.begin();
461  for( ; it2 != lst.end(); ++it2 )
462  {
463  Tag* s = new Tag( sub, "subscription" );
464  s->addAttribute( "node", (*it).first );
465  s->addAttribute( "jid", (*it2).jid );
466  s->addAttribute( "subscription", subscriptionValue( (*it2).type ) );
467  s->addAttribute( "sid", (*it2).subid );
468  }
469  }
470  }
471  else if( m_ctx == GetAffiliationList )
472  {
473 
474  Tag* aff = new Tag( t, "affiliations" );
475  AffiliationMap::const_iterator it = m_affiliationMap.begin();
476  for( ; it != m_affiliationMap.end(); ++it )
477  {
478  Tag* a = new Tag( aff, "affiliation" );
479  a->addAttribute( "node", (*it).first );
480  a->addAttribute( "affiliation", affiliationValue( (*it).second ) );
481  }
482  }
483  else if( m_ctx == Subscription )
484  {
485  Tag* s = new Tag( t, "subscribe" );
486  s->addAttribute( "node", m_node );
487  s->addAttribute( "jid", m_jid.full() );
488  if( m_options.df )
489  {
490  Tag* o = new Tag( t, "options" );
491  o->addChild( m_options.df->tag() );
492  }
493  }
494  else if( m_ctx == Unsubscription )
495  {
496  Tag* u = new Tag( t, "unsubscribe" );
497  u->addAttribute( "node", m_node );
498  u->addAttribute( "jid", m_jid.full() );
499  u->addAttribute( "subid", m_subid );
500  }
501  else if( m_ctx == GetSubscriptionOptions
502  || m_ctx == SetSubscriptionOptions )
503  {
504  Tag* o = new Tag( t, "options" );
505  o->addAttribute( "node", m_options.node );
506  o->addAttribute( "jid", m_jid.full() );
507  if( !m_subid.empty() )
508  o->addAttribute( "subid", m_subid );
509  if( m_options.df )
510  o->addChild( m_options.df->tag() );
511  }
512  else if( m_ctx == RequestItems )
513  {
514  Tag* i = new Tag( t, "items" );
515  i->addAttribute( "node", m_node );
516  if( m_maxItems )
517  i->addAttribute( "max_items", m_maxItems );
518  i->addAttribute( "subid", m_subid );
519  ItemList::const_iterator it = m_items.begin();
520  for( ; it != m_items.end(); ++it )
521  i->addChild( (*it)->tag() );
522  }
523  else if( m_ctx == PublishItem )
524  {
525  Tag* p = new Tag( t, "publish" );
526  p->addAttribute( "node", m_node );
527  ItemList::const_iterator it = m_items.begin();
528  for( ; it != m_items.end(); ++it )
529  p->addChild( (*it)->tag() );
530  if( m_options.df )
531  {
532  Tag* po = new Tag( p, "publish-options" );
533  po->addChild( m_options.df->tag() );
534  }
535  }
536  else if( m_ctx == DeleteItem )
537  {
538  Tag* r = new Tag( t, "retract" );
539  r->addAttribute( "node", m_node );
540  if( m_notify )
541  r->addAttribute( "notify", "true" );
542  ItemList::const_iterator it = m_items.begin();
543  for( ; it != m_items.end(); ++it )
544  r->addChild( (*it)->tag() );
545  }
546  else if( m_ctx == CreateNode )
547  {
548  Tag* c = new Tag( t, "create" );
549  c->addAttribute( "node", m_node );
550  Tag* config = new Tag( t, "configure" );
551  if( m_options.df )
552  config->addChild( m_options.df->tag() );
553  }
554  return t;
555  }
556 
557  StanzaExtension* Manager::PubSub::clone() const
558  {
559  PubSub* p = new PubSub();
560  p->m_affiliationMap = m_affiliationMap;
561  p->m_subscriptionMap = m_subscriptionMap;
562  p->m_ctx = m_ctx;
563 
564  p->m_options.node = m_options.node;
565  p->m_options.df = m_options.df ? new DataForm( *(m_options.df) ) : 0;
566 
567  p->m_jid = m_jid;
568  p->m_node = m_node;
569  p->m_subid = m_subid;
570  ItemList::const_iterator it = m_items.begin();
571  for( ; it != m_items.end(); ++it )
572  p->m_items.push_back( new Item( *(*it) ) );
573 
574  p->m_maxItems = m_maxItems;
575  p->m_notify = m_notify;
576  return p;
577  }
578  // ---- ~Manager::PubSub ----
579 
580  // ---- Manager ----
582  : m_parent( parent )
583  {
584  if( m_parent )
585  {
586  m_parent->registerStanzaExtension( new PubSub() );
587  m_parent->registerStanzaExtension( new PubSubOwner() );
588  m_parent->registerStanzaExtension( new SHIM() );
589  }
590  }
591 
592  const std::string Manager::getSubscriptionsOrAffiliations( const JID& service,
593  ResultHandler* handler,
594  TrackContext context )
595  {
596  if( !m_parent || !handler || !service || context == InvalidContext )
597  return EmptyString;
598 
599  const std::string& id = m_parent->getID();
600  IQ iq( IQ::Get, service, id );
601  iq.addExtension( new PubSub( context ) );
602 
603  m_trackMapMutex.lock();
604  m_resultHandlerTrackMap[id] = handler;
605  m_trackMapMutex.unlock();
606  m_parent->send( iq, this, context );
607  return id;
608  }
609 
610  const std::string Manager::subscribe( const JID& service,
611  const std::string& node,
612  ResultHandler* handler,
613  const JID& jid,
614  SubscriptionObject type,
615  int depth,
616  const std::string& expire
617  )
618  {
619  if( !m_parent || !handler || !service || node.empty() )
620  return EmptyString;
621 
622  DataForm* options = 0;
623  if( type != SubscriptionNodes || depth != 1 )
624  {
625  options = new DataForm( TypeSubmit );
626  options->addField( DataFormField::TypeHidden, "FORM_TYPE", XMLNS_PUBSUB_SUBSCRIBE_OPTIONS );
627 
628  if( type == SubscriptionItems )
629  options->addField( DataFormField::TypeNone, "pubsub#subscription_type", "items" );
630 
631  if( depth != 1 )
632  {
633  DataFormField* field = options->addField( DataFormField::TypeNone, "pubsub#subscription_depth" );
634  if( depth == 0 )
635  field->setValue( "all" );
636  else
637  field->setValue( util::int2string( depth ) );
638  }
639 
640  if( !expire.empty() )
641  {
642  DataFormField* field = options->addField( DataFormField::TypeNone, "pubsub#expire" );
643  field->setValue( expire );
644  }
645  }
646 
647  return subscribe( service, node, handler, jid, options );
648  }
649 
650  const std::string Manager::subscribe( const JID& service,
651  const std::string& node,
652  ResultHandler* handler,
653  const JID& jid,
654  DataForm* options
655  )
656  {
657  if( !m_parent || !handler || !service || node.empty() )
658  return EmptyString;
659 
660  const std::string& id = m_parent->getID();
661  IQ iq( IQ::Set, service, id );
662  PubSub* ps = new PubSub( Subscription );
663  ps->setJID( jid ? jid : m_parent->jid() );
664  ps->setNode( node );
665  if( options != NULL )
666  ps->setOptions( node, options );
667  iq.addExtension( ps );
668 
669  m_trackMapMutex.lock();
670  m_resultHandlerTrackMap[id] = handler;
671  m_nopTrackMap[id] = node;
672  m_trackMapMutex.unlock();
673  m_parent->send( iq, this, Subscription );
674  return id;
675  }
676 
677  const std::string Manager::unsubscribe( const JID& service,
678  const std::string& node,
679  const std::string& subid,
680  ResultHandler* handler,
681  const JID& jid )
682  {
683  if( !m_parent || !handler || !service )
684  return EmptyString;
685 
686  const std::string& id = m_parent->getID();
687  IQ iq( IQ::Set, service, id );
688  PubSub* ps = new PubSub( Unsubscription );
689  ps->setNode( node );
690  ps->setJID( jid ? jid : m_parent->jid() );
691  ps->setSubscriptionID( subid );
692  iq.addExtension( ps );
693 
694  m_trackMapMutex.lock();
695  m_resultHandlerTrackMap[id] = handler;
696  m_trackMapMutex.unlock();
697  // FIXME? need to track info for handler
698  m_parent->send( iq, this, Unsubscription );
699  return id;
700  }
701 
702  const std::string Manager::subscriptionOptions( TrackContext context,
703  const JID& service,
704  const JID& jid,
705  const std::string& node,
706  ResultHandler* handler,
707  DataForm* df,
708  const std::string& subid )
709  {
710  if( !m_parent || !handler || !service )
711  return EmptyString;
712 
713  const std::string& id = m_parent->getID();
714  IQ iq( df ? IQ::Set : IQ::Get, service, id );
715  PubSub* ps = new PubSub( context );
716  ps->setJID( jid ? jid : m_parent->jid() );
717  if( !subid.empty() )
718  ps->setSubscriptionID( subid );
719  ps->setOptions( node, df );
720  iq.addExtension( ps );
721 
722  m_trackMapMutex.lock();
723  m_resultHandlerTrackMap[id] = handler;
724  m_trackMapMutex.unlock();
725  m_parent->send( iq, this, context );
726  return id;
727  }
728 
729  const std::string Manager::requestItems( const JID& service,
730  const std::string& node,
731  const std::string& subid,
732  int maxItems,
733  ResultHandler* handler )
734  {
735  if( !m_parent || !service || !handler )
736  return EmptyString;
737 
738  const std::string& id = m_parent->getID();
739  IQ iq( IQ::Get, service, id );
740  PubSub* ps = new PubSub( RequestItems );
741  ps->setNode( node );
742  ps->setSubscriptionID( subid );
743  ps->setMaxItems( maxItems );
744  iq.addExtension( ps );
745 
746  m_trackMapMutex.lock();
747  m_resultHandlerTrackMap[id] = handler;
748  m_trackMapMutex.unlock();
749  m_parent->send( iq, this, RequestItems );
750  return id;
751  }
752 
753  const std::string Manager::requestItems( const JID& service,
754  const std::string& node,
755  const std::string& subid,
756  const ItemList& items,
757  ResultHandler* handler )
758  {
759  if( !m_parent || !service || !handler )
760  return EmptyString;
761 
762  const std::string& id = m_parent->getID();
763  IQ iq( IQ::Get, service, id );
764  PubSub* ps = new PubSub( RequestItems );
765  ps->setNode( node );
766  ps->setSubscriptionID( subid );
767  ps->setItems( items );
768  iq.addExtension( ps );
769 
770  m_trackMapMutex.lock();
771  m_resultHandlerTrackMap[id] = handler;
772  m_trackMapMutex.unlock();
773  m_parent->send( iq, this, RequestItems );
774  return id;
775  }
776 
777  const std::string Manager::publishItem( const JID& service,
778  const std::string& node,
779  ItemList& items,
780  DataForm* options,
781  ResultHandler* handler )
782  {
783  if( !m_parent || !handler )
784  {
785  util::clearList( items );
786  return EmptyString;
787  }
788 
789  const std::string& id = m_parent->getID();
790  IQ iq( IQ::Set, service, id );
791  PubSub* ps = new PubSub( PublishItem );
792  ps->setNode( node );
793  ps->setItems( items );
794  ps->setOptions( EmptyString, options );
795  iq.addExtension( ps );
796 
797  m_trackMapMutex.lock();
798  m_resultHandlerTrackMap[id] = handler;
799  m_trackMapMutex.unlock();
800  m_parent->send( iq, this, PublishItem );
801  return id;
802  }
803 
804  const std::string Manager::deleteItem( const JID& service,
805  const std::string& node,
806  const ItemList& items,
807  bool notify,
808  ResultHandler* handler )
809  {
810  if( !m_parent || !handler || !service )
811  return EmptyString;
812 
813  const std::string& id = m_parent->getID();
814  IQ iq( IQ::Set, service, id );
815  PubSub* ps = new PubSub( DeleteItem );
816  ps->setNode( node );
817  ps->setItems( items );
818  ps->setNotify( notify );
819  iq.addExtension( ps );
820 
821  m_trackMapMutex.lock();
822  m_resultHandlerTrackMap[id] = handler;
823  m_trackMapMutex.unlock();
824  m_parent->send( iq, this, DeleteItem );
825  return id;
826  }
827 
828  const std::string Manager::createNode( const JID& service,
829  const std::string& node,
830  DataForm* config,
831  ResultHandler* handler )
832  {
833  if( !m_parent || !handler || !service || node.empty() )
834  return EmptyString;
835 
836  const std::string& id = m_parent->getID();
837  IQ iq( IQ::Set, service, id );
838  PubSub* ps = new PubSub( CreateNode );
839  ps->setNode( node );
840  ps->setOptions( EmptyString, config );
841  iq.addExtension( ps );
842 
843  m_trackMapMutex.lock();
844  m_nopTrackMap[id] = node;
845  m_resultHandlerTrackMap[id] = handler;
846  m_trackMapMutex.unlock();
847  m_parent->send( iq, this, CreateNode );
848  return id;
849  }
850 
851  const std::string Manager::deleteNode( const JID& service,
852  const std::string& node,
853  ResultHandler* handler )
854  {
855  if( !m_parent || !handler || !service || node.empty() )
856  return EmptyString;
857 
858  const std::string& id = m_parent->getID();
859  IQ iq( IQ::Set, service, id );
860  PubSubOwner* pso = new PubSubOwner( DeleteNode );
861  pso->setNode( node );
862  iq.addExtension( pso );
863 
864  m_trackMapMutex.lock();
865  m_nopTrackMap[id] = node;
866  m_resultHandlerTrackMap[id] = handler;
867  m_trackMapMutex.unlock();
868  m_parent->send( iq, this, DeleteNode );
869  return id;
870  }
871 
872  const std::string Manager::getDefaultNodeConfig( const JID& service,
873  NodeType type,
874  ResultHandler* handler )
875  {
876  if( !m_parent || !handler || !service )
877  return EmptyString;
878 
879  const std::string& id = m_parent->getID();
880  IQ iq( IQ::Get, service, id );
881  PubSubOwner* pso = new PubSubOwner( DefaultNodeConfig );
882  if( type == NodeCollection )
883  {
884  DataForm* df = new DataForm( TypeSubmit );
885  df->addField( DataFormField::TypeHidden, "FORM_TYPE", XMLNS_PUBSUB_NODE_CONFIG );
886  df->addField( DataFormField::TypeNone, "pubsub#node_type", "collection" );
887  pso->setConfig( df );
888  }
889  iq.addExtension( pso );
890 
891  m_trackMapMutex.lock();
892  m_resultHandlerTrackMap[id] = handler;
893  m_trackMapMutex.unlock();
894  m_parent->send( iq, this, DefaultNodeConfig );
895  return id;
896  }
897 
898  const std::string Manager::nodeConfig( const JID& service,
899  const std::string& node,
900  DataForm* config,
901  ResultHandler* handler )
902  {
903  if( !m_parent || !handler || !service || node.empty() )
904  return EmptyString;
905 
906  const std::string& id = m_parent->getID();
907  IQ iq( config ? IQ::Set : IQ::Get, service, id );
908  PubSubOwner* pso = new PubSubOwner( config ? SetNodeConfig : GetNodeConfig );
909  pso->setNode( node );
910  if( config )
911  pso->setConfig( config );
912  iq.addExtension( pso );
913 
914  m_trackMapMutex.lock();
915  m_nopTrackMap[id] = node;
916  m_resultHandlerTrackMap[id] = handler;
917  m_trackMapMutex.unlock();
918  m_parent->send( iq, this, config ? SetNodeConfig : GetNodeConfig );
919  return id;
920  }
921 
922  const std::string Manager::subscriberList( TrackContext ctx,
923  const JID& service,
924  const std::string& node,
925  const SubscriberList& subList,
926  ResultHandler* handler )
927  {
928  if( !m_parent || !handler || !service || node.empty() )
929  return EmptyString;
930 
931  const std::string& id = m_parent->getID();
932  IQ iq( ctx == SetSubscriberList ? IQ::Set : IQ::Get, service, id );
933  PubSubOwner* pso = new PubSubOwner( ctx );
934  pso->setNode( node );
935  pso->setSubscriberList( subList );
936  iq.addExtension( pso );
937 
938  m_trackMapMutex.lock();
939  m_nopTrackMap[id] = node;
940  m_resultHandlerTrackMap[id] = handler;
941  m_trackMapMutex.unlock();
942  m_parent->send( iq, this, ctx );
943  return id;
944  }
945 
946  const std::string Manager::affiliateList( TrackContext ctx,
947  const JID& service,
948  const std::string& node,
949  const AffiliateList& affList,
950  ResultHandler* handler )
951  {
952  if( !m_parent || !handler || !service || node.empty() )
953  return EmptyString;
954 
955  const std::string& id = m_parent->getID();
956  IQ iq( ctx == SetAffiliateList ? IQ::Set : IQ::Get, service, id );
957  PubSubOwner* pso = new PubSubOwner( ctx );
958  pso->setNode( node );
959  pso->setAffiliateList( affList );
960  iq.addExtension( pso );
961 
962  m_trackMapMutex.lock();
963  m_nopTrackMap[id] = node;
964  m_resultHandlerTrackMap[id] = handler;
965  m_trackMapMutex.unlock();
966  m_parent->send( iq, this, ctx );
967  return id;
968  }
969 
970  const std::string Manager::purgeNode( const JID& service,
971  const std::string& node,
972  ResultHandler* handler )
973  {
974  if( !m_parent || !handler || !service || node.empty() )
975  return EmptyString;
976 
977  const std::string& id = m_parent->getID();
978  IQ iq( IQ::Set, service, id );
979  PubSubOwner* pso = new PubSubOwner( PurgeNodeItems );
980  pso->setNode( node );
981  iq.addExtension( pso );
982 
983  m_trackMapMutex.lock();
984  m_nopTrackMap[id] = node;
985  m_resultHandlerTrackMap[id] = handler;
986  m_trackMapMutex.unlock();
987  m_parent->send( iq, this, PurgeNodeItems );
988  return id;
989  }
990 
991  bool Manager::removeID( const std::string& id )
992  {
993  m_trackMapMutex.lock();
994  ResultHandlerTrackMap::iterator ith = m_resultHandlerTrackMap.find( id );
995  if( ith == m_resultHandlerTrackMap.end() )
996  {
997  m_trackMapMutex.unlock();
998  return false;
999  }
1000  m_resultHandlerTrackMap.erase( ith );
1001  m_trackMapMutex.unlock();
1002  return true;
1003  }
1004 
1005  void Manager::handleIqID( const IQ& iq, int context )
1006  {
1007  const JID& service = iq.from();
1008  const std::string& id = iq.id();
1009 
1010  m_trackMapMutex.lock();
1011  ResultHandlerTrackMap::iterator ith = m_resultHandlerTrackMap.find( id );
1012  if( ith == m_resultHandlerTrackMap.end() )
1013  {
1014  m_trackMapMutex.unlock();
1015  return;
1016  }
1017  ResultHandler* rh = (*ith).second;
1018  m_resultHandlerTrackMap.erase( ith );
1019  m_trackMapMutex.unlock();
1020 
1021  switch( iq.subtype() )
1022  {
1023  case IQ::Error:
1024  case IQ::Result:
1025  {
1026  const Error* error = iq.error();
1027  switch( context )
1028  {
1029  case Subscription:
1030  {
1031  const PubSub* ps = iq.findExtension<PubSub>( ExtPubSub );
1032  if( !ps )
1033  return;
1034  SubscriptionMap sm = ps->subscriptions();
1035  if( !sm.empty() )
1036  {
1037  SubscriptionMap::const_iterator it = sm.begin();
1038  const SubscriptionList& lst = (*it).second;
1039  if( lst.size() == 1 )
1040  {
1041  SubscriptionList::const_iterator it2 = lst.begin();
1042  rh->handleSubscriptionResult( id, service, (*it).first, (*it2).subid, (*it2).jid,
1043  (*it2).type, error );
1044  }
1045  }
1046  break;
1047  }
1048  case Unsubscription:
1049  {
1050  rh->handleUnsubscriptionResult( iq.id(), service, error );
1051  break;
1052  }
1053  case GetSubscriptionList:
1054  {
1055  const PubSub* ps = iq.findExtension<PubSub>( ExtPubSub );
1056  if( !ps )
1057  return;
1058 
1059  rh->handleSubscriptions( id, service,
1060  ps->subscriptions(),
1061  error );
1062  break;
1063  }
1064  case GetAffiliationList:
1065  {
1066  const PubSub* ps = iq.findExtension<PubSub>( ExtPubSub );
1067  if( !ps )
1068  return;
1069 
1070  rh->handleAffiliations( id, service,
1071  ps->affiliations(),
1072  error );
1073  break;
1074  }
1075  case RequestItems:
1076  {
1077  const PubSub* ps = iq.findExtension<PubSub>( ExtPubSub );
1078  if( !ps )
1079  return;
1080 
1081  rh->handleItems( id, service, ps->node(),
1082  ps->items(), error );
1083  break;
1084  }
1085  case PublishItem:
1086  {
1087  const PubSub* ps = iq.findExtension<PubSub>( ExtPubSub );
1088  rh->handleItemPublication( id, service, "",
1089  ps ? ps->items() : ItemList(),
1090  error );
1091  break;
1092  }
1093  case DeleteItem:
1094  {
1095  const PubSub* ps = iq.findExtension<PubSub>( ExtPubSub );
1096  if( ps )
1097  {
1098  rh->handleItemDeletion( id, service,
1099  ps->node(),
1100  ps->items(),
1101  error );
1102  }
1103  break;
1104  }
1105  case DefaultNodeConfig:
1106  {
1107  const PubSubOwner* pso = iq.findExtension<PubSubOwner>( ExtPubSubOwner );
1108  if( pso )
1109  {
1110  rh->handleDefaultNodeConfig( id, service,
1111  pso->config(),
1112  error );
1113  }
1114  break;
1115  }
1116  case GetSubscriptionOptions:
1117  case GetSubscriberList:
1118  case SetSubscriberList:
1119  case GetAffiliateList:
1120  case SetAffiliateList:
1121  case GetNodeConfig:
1122  case SetNodeConfig:
1123  case CreateNode:
1124  case DeleteNode:
1125  case PurgeNodeItems:
1126  {
1127  switch( context )
1128  {
1129  case GetSubscriptionOptions:
1130  {
1131  const PubSub* ps = iq.findExtension<PubSub>( ExtPubSub );
1132  if( ps )
1133  {
1134  rh->handleSubscriptionOptions( id, service,
1135  ps->jid(),
1136  ps->node(),
1137  ps->options(),
1138  ps->subscriptionID(),
1139  error );
1140  }
1141  break;
1142  }
1143  case GetSubscriberList:
1144  {
1145  const PubSub* ps = iq.findExtension<PubSub>( ExtPubSub );
1146  if( ps )
1147  {
1148  const SubscriptionMap& sm = ps->subscriptions();
1149  SubscriptionMap::const_iterator itsm = sm.find( ps->node() );
1150  if( itsm != sm.end() )
1151  rh->handleSubscribers( iq.id(), service, ps->node(), (*itsm).second, 0 );
1152  }
1153  break;
1154  }
1155  case SetSubscriptionOptions:
1156  case SetSubscriberList:
1157  case SetAffiliateList:
1158  case SetNodeConfig:
1159  case CreateNode:
1160  case DeleteNode:
1161  case PurgeNodeItems:
1162  {
1163  m_trackMapMutex.lock();
1164  NodeOperationTrackMap::iterator it = m_nopTrackMap.find( id );
1165  if( it != m_nopTrackMap.end() )
1166  {
1167  const std::string& node = (*it).second;
1168  switch( context )
1169  {
1170  case SetSubscriptionOptions:
1171  {
1172  const PubSub* ps = iq.findExtension<PubSub>( ExtPubSub );
1173  if( ps )
1174  {
1175  rh->handleSubscriptionOptionsResult( id, service,
1176  ps->jid(),
1177  node,
1178  ps->subscriptionID(),
1179  error );
1180  }
1181  else
1182  {
1183  rh->handleSubscriptionOptionsResult( id, service, JID( /* FIXME */ ), node, /* FIXME */ EmptyString, error );
1184  }
1185  break;
1186  }
1187  case SetSubscriberList:
1188  rh->handleSubscribersResult( id, service, node, 0, error );
1189  break;
1190  case SetAffiliateList:
1191  rh->handleAffiliatesResult( id, service, node, 0, error );
1192  break;
1193  case SetNodeConfig:
1194  rh->handleNodeConfigResult( id, service, node, error );
1195  break;
1196  case CreateNode:
1197  rh->handleNodeCreation( id, service, node, error );
1198  break;
1199  case DeleteNode:
1200  rh->handleNodeDeletion( id, service, node, error );
1201  break;
1202  case PurgeNodeItems:
1203  rh->handleNodePurge( id, service, node, error );
1204  break;
1205  }
1206  m_nopTrackMap.erase( it );
1207  }
1208  m_trackMapMutex.unlock();
1209  break;
1210  }
1211  case GetAffiliateList:
1212  {
1213  const PubSubOwner* pso = iq.findExtension<PubSubOwner>( ExtPubSubOwner );
1214  if( pso )
1215  {
1216  rh->handleAffiliates( id, service, pso->node(), pso->affiliateList(), error );
1217  }
1218  break;
1219  }
1220  case GetNodeConfig:
1221  {
1222  const PubSubOwner* pso = iq.findExtension<PubSubOwner>( ExtPubSubOwner );
1223  if( pso )
1224  {
1225  rh->handleNodeConfig( id, service,
1226  pso->node(),
1227  pso->config(),
1228  error );
1229  }
1230  break;
1231  }
1232  default:
1233  break;
1234  }
1235 
1236  break;
1237  }
1238  }
1239  break;
1240  }
1241  default:
1242  break;
1243  }
1244 
1245  }
1246 
1247  }
1248 
1249 }
1250 
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)
const StanzaExtension * findExtension(int type) const
Definition: stanza.cpp:57
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)
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
IqType subtype() const
Definition: iq.h:74
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())
Tag * tag() const
Definition: pubsubitem.cpp:57
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
const Error * error() const
Definition: stanza.cpp:47
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)
const JID & from() const
Definition: stanza.h:51
const std::string requestItems(const JID &service, const std::string &node, const std::string &subid, int maxItems, ResultHandler *handler)
const std::string getID()
An abstraction of a subscription stanza.
Definition: subscription.h:31
const std::string & id() const
Definition: stanza.h:63
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
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:124
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