gloox 1.0.24
pubsubmanager.cpp
1/*
2 Copyright (c) 2007-2019 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
24namespace 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 if( !m_node.empty() )
550 c->addAttribute( "node", m_node );
551 Tag* config = new Tag( t, "configure" );
552 if( m_options.df )
553 config->addChild( m_options.df->tag() );
554 }
555 return t;
556 }
557
558 StanzaExtension* Manager::PubSub::clone() const
559 {
560 PubSub* p = new PubSub();
561 p->m_affiliationMap = m_affiliationMap;
562 p->m_subscriptionMap = m_subscriptionMap;
563 p->m_ctx = m_ctx;
564
565 p->m_options.node = m_options.node;
566 p->m_options.df = m_options.df ? new DataForm( *(m_options.df) ) : 0;
567
568 p->m_jid = m_jid;
569 p->m_node = m_node;
570 p->m_subid = m_subid;
571 ItemList::const_iterator it = m_items.begin();
572 for( ; it != m_items.end(); ++it )
573 p->m_items.push_back( new Item( *(*it) ) );
574
575 p->m_maxItems = m_maxItems;
576 p->m_notify = m_notify;
577 return p;
578 }
579 // ---- ~Manager::PubSub ----
580
581 // ---- Manager ----
582 Manager::Manager( ClientBase* parent )
583 : m_parent( parent )
584 {
585 if( m_parent )
586 {
587 m_parent->registerStanzaExtension( new PubSub() );
588 m_parent->registerStanzaExtension( new PubSubOwner() );
589 m_parent->registerStanzaExtension( new SHIM() );
590 }
591 }
592
593 const std::string Manager::getSubscriptionsOrAffiliations( const JID& service,
594 ResultHandler* handler,
595 TrackContext context )
596 {
597 if( !m_parent || !handler || !service || context == InvalidContext )
598 return EmptyString;
599
600 const std::string& id = m_parent->getID();
601 IQ iq( IQ::Get, service, id );
602 iq.addExtension( new PubSub( context ) );
603
604 m_trackMapMutex.lock();
605 m_resultHandlerTrackMap[id] = handler;
606 m_trackMapMutex.unlock();
607 m_parent->send( iq, this, context );
608 return id;
609 }
610
611 const std::string Manager::subscribe( const JID& service,
612 const std::string& node,
613 ResultHandler* handler,
614 const JID& jid,
616 int depth,
617 const std::string& expire
618 )
619 {
620 if( !m_parent || !handler || !service || node.empty() )
621 return EmptyString;
622
623 DataForm* options = 0;
624 if( type != SubscriptionNodes || depth != 1 )
625 {
626 options = new DataForm( TypeSubmit );
627 options->addField( DataFormField::TypeHidden, "FORM_TYPE", XMLNS_PUBSUB_SUBSCRIBE_OPTIONS );
628
629 if( type == SubscriptionItems )
630 options->addField( DataFormField::TypeNone, "pubsub#subscription_type", "items" );
631
632 if( depth != 1 )
633 {
634 DataFormField* field = options->addField( DataFormField::TypeNone, "pubsub#subscription_depth" );
635 if( depth == 0 )
636 field->setValue( "all" );
637 else
638 field->setValue( util::int2string( depth ) );
639 }
640
641 if( !expire.empty() )
642 {
643 DataFormField* field = options->addField( DataFormField::TypeNone, "pubsub#expire" );
644 field->setValue( expire );
645 }
646 }
647
648 return subscribe( service, node, handler, jid, options );
649 }
650
651 const std::string Manager::subscribe( const JID& service,
652 const std::string& node,
653 ResultHandler* handler,
654 const JID& jid,
655 DataForm* options
656 )
657 {
658 if( !m_parent || !handler || !service || node.empty() )
659 return EmptyString;
660
661 const std::string& id = m_parent->getID();
662 IQ iq( IQ::Set, service, id );
663 PubSub* ps = new PubSub( Subscription );
664 ps->setJID( jid ? jid : m_parent->jid() );
665 ps->setNode( node );
666 if( options != NULL )
667 ps->setOptions( node, options );
668 iq.addExtension( ps );
669
670 m_trackMapMutex.lock();
671 m_resultHandlerTrackMap[id] = handler;
672 m_nopTrackMap[id] = node;
673 m_trackMapMutex.unlock();
674 m_parent->send( iq, this, Subscription );
675 return id;
676 }
677
678 const std::string Manager::unsubscribe( const JID& service,
679 const std::string& node,
680 const std::string& subid,
681 ResultHandler* handler,
682 const JID& jid )
683 {
684 if( !m_parent || !handler || !service )
685 return EmptyString;
686
687 const std::string& id = m_parent->getID();
688 IQ iq( IQ::Set, service, id );
689 PubSub* ps = new PubSub( Unsubscription );
690 ps->setNode( node );
691 ps->setJID( jid ? jid : m_parent->jid() );
692 ps->setSubscriptionID( subid );
693 iq.addExtension( ps );
694
695 m_trackMapMutex.lock();
696 m_resultHandlerTrackMap[id] = handler;
697 m_trackMapMutex.unlock();
698 // FIXME? need to track info for handler
699 m_parent->send( iq, this, Unsubscription );
700 return id;
701 }
702
703 const std::string Manager::subscriptionOptions( TrackContext context,
704 const JID& service,
705 const JID& jid,
706 const std::string& node,
707 ResultHandler* handler,
708 DataForm* df,
709 const std::string& subid )
710 {
711 if( !m_parent || !handler || !service )
712 return EmptyString;
713
714 const std::string& id = m_parent->getID();
715 IQ iq( df ? IQ::Set : IQ::Get, service, id );
716 PubSub* ps = new PubSub( context );
717 ps->setJID( jid ? jid : m_parent->jid() );
718 if( !subid.empty() )
719 ps->setSubscriptionID( subid );
720 ps->setOptions( node, df );
721 iq.addExtension( ps );
722
723 m_trackMapMutex.lock();
724 m_resultHandlerTrackMap[id] = handler;
725 m_trackMapMutex.unlock();
726 m_parent->send( iq, this, context );
727 return id;
728 }
729
730 const std::string Manager::requestItems( const JID& service,
731 const std::string& node,
732 const std::string& subid,
733 int maxItems,
734 ResultHandler* handler )
735 {
736 if( !m_parent || !service || !handler )
737 return EmptyString;
738
739 const std::string& id = m_parent->getID();
740 IQ iq( IQ::Get, service, id );
741 PubSub* ps = new PubSub( RequestItems );
742 ps->setNode( node );
743 ps->setSubscriptionID( subid );
744 ps->setMaxItems( maxItems );
745 iq.addExtension( ps );
746
747 m_trackMapMutex.lock();
748 m_resultHandlerTrackMap[id] = handler;
749 m_trackMapMutex.unlock();
750 m_parent->send( iq, this, RequestItems );
751 return id;
752 }
753
754 const std::string Manager::requestItems( const JID& service,
755 const std::string& node,
756 const std::string& subid,
757 const ItemList& items,
758 ResultHandler* handler )
759 {
760 if( !m_parent || !service || !handler )
761 return EmptyString;
762
763 const std::string& id = m_parent->getID();
764 IQ iq( IQ::Get, service, id );
765 PubSub* ps = new PubSub( RequestItems );
766 ps->setNode( node );
767 ps->setSubscriptionID( subid );
768 ps->setItems( items );
769 iq.addExtension( ps );
770
771 m_trackMapMutex.lock();
772 m_resultHandlerTrackMap[id] = handler;
773 m_trackMapMutex.unlock();
774 m_parent->send( iq, this, RequestItems );
775 return id;
776 }
777
778 const std::string Manager::publishItem( const JID& service,
779 const std::string& node,
780 ItemList& items,
781 DataForm* options,
782 ResultHandler* handler )
783 {
784 if( !m_parent || !handler )
785 {
786 util::clearList( items );
787 return EmptyString;
788 }
789
790 const std::string& id = m_parent->getID();
791 IQ iq( IQ::Set, service, id );
792 PubSub* ps = new PubSub( PublishItem );
793 ps->setNode( node );
794 ps->setItems( items );
795 ps->setOptions( EmptyString, options );
796 iq.addExtension( ps );
797
798 m_trackMapMutex.lock();
799 m_resultHandlerTrackMap[id] = handler;
800 m_trackMapMutex.unlock();
801 m_parent->send( iq, this, PublishItem );
802 return id;
803 }
804
805 const std::string Manager::deleteItem( const JID& service,
806 const std::string& node,
807 const ItemList& items,
808 bool notify,
809 ResultHandler* handler )
810 {
811 if( !m_parent || !handler || !service )
812 return EmptyString;
813
814 const std::string& id = m_parent->getID();
815 IQ iq( IQ::Set, service, id );
816 PubSub* ps = new PubSub( DeleteItem );
817 ps->setNode( node );
818 ps->setItems( items );
819 ps->setNotify( notify );
820 iq.addExtension( ps );
821
822 m_trackMapMutex.lock();
823 m_resultHandlerTrackMap[id] = handler;
824 m_trackMapMutex.unlock();
825 m_parent->send( iq, this, DeleteItem );
826 return id;
827 }
828
829 const std::string Manager::createNode( const JID& service,
830 const std::string& node,
831 DataForm* config,
832 ResultHandler* handler )
833 {
834 if( !m_parent || !handler || !service )
835 return EmptyString;
836
837 const std::string& id = m_parent->getID();
838 IQ iq( IQ::Set, service, id );
839 PubSub* ps = new PubSub( CreateNode );
840 if( !node.empty() )
841 ps->setNode( node );
842 ps->setOptions( EmptyString, config );
843 iq.addExtension( ps );
844
845 m_trackMapMutex.lock();
846 m_nopTrackMap[id] = node;
847 m_resultHandlerTrackMap[id] = handler;
848 m_trackMapMutex.unlock();
849 m_parent->send( iq, this, CreateNode );
850 return id;
851 }
852
853 const std::string Manager::deleteNode( const JID& service,
854 const std::string& node,
855 ResultHandler* handler )
856 {
857 if( !m_parent || !handler || !service || node.empty() )
858 return EmptyString;
859
860 const std::string& id = m_parent->getID();
861 IQ iq( IQ::Set, service, id );
862 PubSubOwner* pso = new PubSubOwner( DeleteNode );
863 pso->setNode( node );
864 iq.addExtension( pso );
865
866 m_trackMapMutex.lock();
867 m_nopTrackMap[id] = node;
868 m_resultHandlerTrackMap[id] = handler;
869 m_trackMapMutex.unlock();
870 m_parent->send( iq, this, DeleteNode );
871 return id;
872 }
873
874 const std::string Manager::getDefaultNodeConfig( const JID& service,
875 NodeType type,
876 ResultHandler* handler )
877 {
878 if( !m_parent || !handler || !service )
879 return EmptyString;
880
881 const std::string& id = m_parent->getID();
882 IQ iq( IQ::Get, service, id );
883 PubSubOwner* pso = new PubSubOwner( DefaultNodeConfig );
884 if( type == NodeCollection )
885 {
886 DataForm* df = new DataForm( TypeSubmit );
887 df->addField( DataFormField::TypeHidden, "FORM_TYPE", XMLNS_PUBSUB_NODE_CONFIG );
888 df->addField( DataFormField::TypeNone, "pubsub#node_type", "collection" );
889 pso->setConfig( df );
890 }
891 iq.addExtension( pso );
892
893 m_trackMapMutex.lock();
894 m_resultHandlerTrackMap[id] = handler;
895 m_trackMapMutex.unlock();
896 m_parent->send( iq, this, DefaultNodeConfig );
897 return id;
898 }
899
900 const std::string Manager::nodeConfig( const JID& service,
901 const std::string& node,
902 DataForm* config,
903 ResultHandler* handler )
904 {
905 if( !m_parent || !handler || !service || node.empty() )
906 return EmptyString;
907
908 const std::string& id = m_parent->getID();
909 IQ iq( config ? IQ::Set : IQ::Get, service, id );
910 PubSubOwner* pso = new PubSubOwner( config ? SetNodeConfig : GetNodeConfig );
911 pso->setNode( node );
912 if( config )
913 pso->setConfig( config );
914 iq.addExtension( pso );
915
916 m_trackMapMutex.lock();
917 m_nopTrackMap[id] = node;
918 m_resultHandlerTrackMap[id] = handler;
919 m_trackMapMutex.unlock();
920 m_parent->send( iq, this, config ? SetNodeConfig : GetNodeConfig );
921 return id;
922 }
923
924 const std::string Manager::subscriberList( TrackContext ctx,
925 const JID& service,
926 const std::string& node,
927 const SubscriberList& subList,
928 ResultHandler* handler )
929 {
930 if( !m_parent || !handler || !service || node.empty() )
931 return EmptyString;
932
933 const std::string& id = m_parent->getID();
934 IQ iq( ctx == SetSubscriberList ? IQ::Set : IQ::Get, service, id );
935 PubSubOwner* pso = new PubSubOwner( ctx );
936 pso->setNode( node );
937 pso->setSubscriberList( subList );
938 iq.addExtension( pso );
939
940 m_trackMapMutex.lock();
941 m_nopTrackMap[id] = node;
942 m_resultHandlerTrackMap[id] = handler;
943 m_trackMapMutex.unlock();
944 m_parent->send( iq, this, ctx );
945 return id;
946 }
947
948 const std::string Manager::affiliateList( TrackContext ctx,
949 const JID& service,
950 const std::string& node,
951 const AffiliateList& affList,
952 ResultHandler* handler )
953 {
954 if( !m_parent || !handler || !service || node.empty() )
955 return EmptyString;
956
957 const std::string& id = m_parent->getID();
958 IQ iq( ctx == SetAffiliateList ? IQ::Set : IQ::Get, service, id );
959 PubSubOwner* pso = new PubSubOwner( ctx );
960 pso->setNode( node );
961 pso->setAffiliateList( affList );
962 iq.addExtension( pso );
963
964 m_trackMapMutex.lock();
965 m_nopTrackMap[id] = node;
966 m_resultHandlerTrackMap[id] = handler;
967 m_trackMapMutex.unlock();
968 m_parent->send( iq, this, ctx );
969 return id;
970 }
971
972 const std::string Manager::purgeNode( const JID& service,
973 const std::string& node,
974 ResultHandler* handler )
975 {
976 if( !m_parent || !handler || !service || node.empty() )
977 return EmptyString;
978
979 const std::string& id = m_parent->getID();
980 IQ iq( IQ::Set, service, id );
981 PubSubOwner* pso = new PubSubOwner( PurgeNodeItems );
982 pso->setNode( node );
983 iq.addExtension( pso );
984
985 m_trackMapMutex.lock();
986 m_nopTrackMap[id] = node;
987 m_resultHandlerTrackMap[id] = handler;
988 m_trackMapMutex.unlock();
989 m_parent->send( iq, this, PurgeNodeItems );
990 return id;
991 }
992
993 bool Manager::removeID( const std::string& id )
994 {
995 m_trackMapMutex.lock();
996 ResultHandlerTrackMap::iterator ith = m_resultHandlerTrackMap.find( id );
997 if( ith == m_resultHandlerTrackMap.end() )
998 {
999 m_trackMapMutex.unlock();
1000 return false;
1001 }
1002 m_resultHandlerTrackMap.erase( ith );
1003 m_trackMapMutex.unlock();
1004 return true;
1005 }
1006
1007 void Manager::handleIqID( const IQ& iq, int context )
1008 {
1009 const JID& service = iq.from();
1010 const std::string& id = iq.id();
1011
1012 m_trackMapMutex.lock();
1013 ResultHandlerTrackMap::iterator ith = m_resultHandlerTrackMap.find( id );
1014 if( ith == m_resultHandlerTrackMap.end() )
1015 {
1016 m_trackMapMutex.unlock();
1017 return;
1018 }
1019 ResultHandler* rh = (*ith).second;
1020 m_resultHandlerTrackMap.erase( ith );
1021 m_trackMapMutex.unlock();
1022
1023 switch( iq.subtype() )
1024 {
1025 case IQ::Error:
1026 case IQ::Result:
1027 {
1028 const Error* error = iq.error();
1029 switch( context )
1030 {
1031 case Subscription:
1032 {
1033 const PubSub* ps = iq.findExtension<PubSub>( ExtPubSub );
1034 if( !ps )
1035 return;
1036 SubscriptionMap sm = ps->subscriptions();
1037 if( sm.empty() )
1038 {
1039 /* If the reply is an error, it will not contain a
1040 "subscription" child. It may however contain the
1041 original "subscribe" request. If that is the case, then
1042 we can still retrieve the node and JID of the request and
1043 notify the handler callback of the error. */
1044 if( ps->context() == Subscription )
1045 rh->handleSubscriptionResult( id, service, ps->node(), "", ps->jid(),
1046 SubscriptionInvalid, error );
1047 }
1048 else
1049 {
1050 SubscriptionMap::const_iterator it = sm.begin();
1051 const SubscriptionList& lst = (*it).second;
1052 if( lst.size() == 1 )
1053 {
1054 SubscriptionList::const_iterator it2 = lst.begin();
1055 rh->handleSubscriptionResult( id, service, (*it).first, (*it2).subid, (*it2).jid,
1056 (*it2).type, error );
1057 }
1058 }
1059 break;
1060 }
1061 case Unsubscription:
1062 {
1063 rh->handleUnsubscriptionResult( iq.id(), service, error );
1064 break;
1065 }
1066 case GetSubscriptionList:
1067 {
1068 const PubSub* ps = iq.findExtension<PubSub>( ExtPubSub );
1069 if( !ps )
1070 return;
1071
1072 rh->handleSubscriptions( id, service,
1073 ps->subscriptions(),
1074 error );
1075 break;
1076 }
1077 case GetAffiliationList:
1078 {
1079 const PubSub* ps = iq.findExtension<PubSub>( ExtPubSub );
1080 if( !ps )
1081 return;
1082
1083 rh->handleAffiliations( id, service,
1084 ps->affiliations(),
1085 error );
1086 break;
1087 }
1088 case RequestItems:
1089 {
1090 const PubSub* ps = iq.findExtension<PubSub>( ExtPubSub );
1091 if( !ps )
1092 return;
1093
1094 rh->handleItems( id, service, ps->node(),
1095 ps->items(), error );
1096 break;
1097 }
1098 case PublishItem:
1099 {
1100 const PubSub* ps = iq.findExtension<PubSub>( ExtPubSub );
1101 rh->handleItemPublication( id, service, ps->node(),
1102 ps ? ps->items() : ItemList(),
1103 error );
1104 break;
1105 }
1106 case DeleteItem:
1107 {
1108 const PubSub* ps = iq.findExtension<PubSub>( ExtPubSub );
1109 if( ps )
1110 {
1111 rh->handleItemDeletion( id, service,
1112 ps->node(),
1113 ps->items(),
1114 error );
1115 }
1116 break;
1117 }
1118 case DefaultNodeConfig:
1119 {
1120 const PubSubOwner* pso = iq.findExtension<PubSubOwner>( ExtPubSubOwner );
1121 if( pso )
1122 {
1123 rh->handleDefaultNodeConfig( id, service,
1124 pso->config(),
1125 error );
1126 }
1127 break;
1128 }
1129 case GetSubscriptionOptions:
1130 case GetSubscriberList:
1131 case SetSubscriberList:
1132 case GetAffiliateList:
1133 case SetAffiliateList:
1134 case GetNodeConfig:
1135 case SetNodeConfig:
1136 case CreateNode:
1137 case DeleteNode:
1138 case PurgeNodeItems:
1139 {
1140 switch( context )
1141 {
1142 case GetSubscriptionOptions:
1143 {
1144 const PubSub* ps = iq.findExtension<PubSub>( ExtPubSub );
1145 if( ps )
1146 {
1147 rh->handleSubscriptionOptions( id, service,
1148 ps->jid(),
1149 ps->node(),
1150 ps->options(),
1151 ps->subscriptionID(),
1152 error );
1153 }
1154 break;
1155 }
1156 case GetSubscriberList:
1157 {
1158 const PubSub* ps = iq.findExtension<PubSub>( ExtPubSub );
1159 if( ps )
1160 {
1161 const SubscriptionMap& sm = ps->subscriptions();
1162 SubscriptionMap::const_iterator itsm = sm.find( ps->node() );
1163 if( itsm != sm.end() )
1164 rh->handleSubscribers( iq.id(), service, ps->node(), (*itsm).second, 0 );
1165 }
1166 break;
1167 }
1168 case SetSubscriptionOptions:
1169 case SetSubscriberList:
1170 case SetAffiliateList:
1171 case SetNodeConfig:
1172 case CreateNode:
1173 case DeleteNode:
1174 case PurgeNodeItems:
1175 {
1176 m_trackMapMutex.lock();
1177 NodeOperationTrackMap::iterator it = m_nopTrackMap.find( id );
1178 if( it != m_nopTrackMap.end() )
1179 {
1180 const std::string& node = (*it).second;
1181 const PubSub* ps = iq.findExtension<PubSub>( ExtPubSub );
1182 switch( context )
1183 {
1184 case SetSubscriptionOptions:
1185 {
1186 if( ps )
1187 {
1188 rh->handleSubscriptionOptionsResult( id, service,
1189 ps->jid(),
1190 node,
1191 ps->subscriptionID(),
1192 error );
1193 }
1194 else
1195 {
1196 rh->handleSubscriptionOptionsResult( id, service, JID( /* FIXME */ ), node, /* FIXME */ EmptyString, error );
1197 }
1198 break;
1199 }
1200 case SetSubscriberList:
1201 rh->handleSubscribersResult( id, service, node, 0, error );
1202 break;
1203 case SetAffiliateList:
1204 rh->handleAffiliatesResult( id, service, node, 0, error );
1205 break;
1206 case SetNodeConfig:
1207 rh->handleNodeConfigResult( id, service, node, error );
1208 break;
1209 case CreateNode:
1210 if( ps )
1211 rh->handleNodeCreation( id, service, ps->node(), error );
1212 else
1213 rh->handleNodeCreation( id, service, node, error );
1214 break;
1215 case DeleteNode:
1216 rh->handleNodeDeletion( id, service, node, error );
1217 break;
1218 case PurgeNodeItems:
1219 rh->handleNodePurge( id, service, node, error );
1220 break;
1221 }
1222 m_nopTrackMap.erase( it );
1223 }
1224 m_trackMapMutex.unlock();
1225 break;
1226 }
1227 case GetAffiliateList:
1228 {
1229 const PubSubOwner* pso = iq.findExtension<PubSubOwner>( ExtPubSubOwner );
1230 if( pso )
1231 {
1232 rh->handleAffiliates( id, service, pso->node(), pso->affiliateList(), error );
1233 }
1234 break;
1235 }
1236 case GetNodeConfig:
1237 {
1238 const PubSubOwner* pso = iq.findExtension<PubSubOwner>( ExtPubSubOwner );
1239 if( pso )
1240 {
1241 rh->handleNodeConfig( id, service,
1242 pso->node(),
1243 pso->config(),
1244 error );
1245 }
1246 break;
1247 }
1248 default:
1249 break;
1250 }
1251
1252 break;
1253 }
1254 }
1255 break;
1256 }
1257 default:
1258 break;
1259 }
1260
1261 }
1262
1263 }
1264
1265}
1266
This is the common base class for a Jabber/XMPP Client and a Jabber Component.
Definition: clientbase.h:79
const std::string getID()
void send(Tag *tag)
const JID & jid()
Definition: clientbase.h:147
void registerStanzaExtension(StanzaExtension *ext)
virtual void addField(DataFormField *field)
An abstraction of a single field in a XEP-0004 Data Form.
Definition: dataformfield.h:34
void setValue(const std::string &value)
An abstraction of a XEP-0004 Data Form.
Definition: dataform.h:57
A stanza error abstraction implemented as a StanzaExtension.
Definition: error.h:35
An abstraction of an IQ stanza.
Definition: iq.h:34
IqType subtype() const
Definition: iq.h:74
@ Set
Definition: iq.h:46
@ Error
Definition: iq.h:49
@ Result
Definition: iq.h:48
@ Get
Definition: iq.h:45
An abstraction of a JID.
Definition: jid.h:31
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)
const std::string createNode(const JID &service, const std::string &node, DataForm *config, ResultHandler *handler)
bool removeID(const std::string &id)
const std::string requestItems(const JID &service, const std::string &node, const std::string &subid, int maxItems, ResultHandler *handler)
const std::string unsubscribe(const JID &service, const std::string &node, const std::string &subid, ResultHandler *handler, const JID &jid=JID())
virtual void handleIqID(const IQ &iq, int context)
const std::string deleteItem(const JID &service, const std::string &node, const ItemList &items, bool notify, ResultHandler *handler)
const std::string getDefaultNodeConfig(const JID &service, NodeType type, ResultHandler *handler)
const std::string purgeNode(const JID &service, const std::string &node, ResultHandler *handler)
const std::string publishItem(const JID &service, const std::string &node, ItemList &items, DataForm *options, ResultHandler *handler)
const std::string deleteNode(const JID &service, const std::string &node, ResultHandler *handler)
A virtual interface to receive item related requests results.
virtual void handleItems(const std::string &id, const JID &service, const std::string &node, const ItemList &itemList, 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 handleAffiliations(const std::string &id, const JID &service, const AffiliationMap &affMap, const Error *error=0)=0
virtual void handleDefaultNodeConfig(const std::string &id, const JID &service, const DataForm *config, const Error *error=0)=0
virtual void handleNodeDeletion(const std::string &id, const JID &service, const std::string &node, const Error *error=0)=0
virtual void handleNodeConfigResult(const std::string &id, const JID &service, const std::string &node, 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
virtual void handleUnsubscriptionResult(const std::string &id, const JID &service, const Error *error=0)=0
virtual void handleSubscribers(const std::string &id, const JID &service, const std::string &node, const SubscriptionList &list, const Error *error=0)=0
virtual void handleItemPublication(const std::string &id, const JID &service, const std::string &node, const ItemList &itemList, const Error *error=0)=0
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
virtual void handleAffiliatesResult(const std::string &id, const JID &service, const std::string &node, const AffiliateList *list, 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
virtual void handleNodePurge(const std::string &id, const JID &service, const std::string &node, const Error *error=0)=0
virtual void handleItemDeletion(const std::string &id, const JID &service, const std::string &node, const ItemList &itemList, const Error *error=0)=0
virtual void handleNodeCreation(const std::string &id, const JID &service, const std::string &node, const Error *error=0)=0
virtual void handleNodeConfig(const std::string &id, const JID &service, const std::string &node, const DataForm *config, const Error *error=0)=0
virtual void handleSubscribersResult(const std::string &id, const JID &service, const std::string &node, const SubscriberList *list, const Error *error=0)=0
An implementation/abstraction of Stanza Headers and Internet Metadata (SHIM, XEP-0131).
Definition: shim.h:36
void addExtension(const StanzaExtension *se)
Definition: stanza.cpp:52
const std::string & id() const
Definition: stanza.h:63
const Error * error() const
Definition: stanza.cpp:47
const JID & from() const
Definition: stanza.h:51
const StanzaExtension * findExtension(int type) const
Definition: stanza.cpp:57
An abstraction of a subscription stanza.
Definition: subscription.h:32
SubscriptionObject
Definition: pubsub.h:97
@ SubscriptionItems
Definition: pubsub.h:99
@ SubscriptionNodes
Definition: pubsub.h:98
SubscriptionType
Definition: pubsub.h:61
@ SubscriptionInvalid
Definition: pubsub.h:75
@ NodeCollection
Definition: pubsub.h:39
void clearList(std::list< T * > &L)
Definition: util.h:152
The namespace for the gloox library.
Definition: adhoc.cpp:28
std::list< Tag * > TagList
Definition: tag.h:31
const std::string EmptyString
Definition: gloox.cpp:124
std::list< const Tag * > ConstTagList
Definition: tag.h:36
const std::string XMLNS_PUBSUB_OWNER
Definition: gloox.cpp:80
@ ExtPubSubOwner
@ TypeSubmit
Definition: dataform.h:37
const std::string XMLNS_PUBSUB
Definition: gloox.cpp:77