gloox 1.0.27
rostermanager.cpp
1/*
2 Copyright (c) 2004-2023 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
14#include "clientbase.h"
15#include "rostermanager.h"
16#include "disco.h"
17#include "rosteritem.h"
18#include "rosteritemdata.h"
19#include "rosterlistener.h"
20#include "privatexml.h"
21#include "util.h"
22#include "stanzaextension.h"
23#include "capabilities.h"
24
25
26namespace gloox
27{
28
29 // ---- RosterManager::Query ----
30 RosterManager::Query::Query( const JID& jid, const std::string& name, const StringList& groups )
31 : StanzaExtension( ExtRoster )
32 {
33 m_roster.push_back( new RosterItemData( jid, name, groups ) );
34 }
35
36 RosterManager::Query::Query( const JID& jid )
37 : StanzaExtension( ExtRoster )
38 {
39 m_roster.push_back( new RosterItemData( jid ) );
40 }
41
42 RosterManager::Query::Query( const Tag* tag )
43 : StanzaExtension( ExtRoster )
44 {
45 if( !tag || tag->name() != "query" || tag->xmlns() != XMLNS_ROSTER )
46 return;
47
48 const ConstTagList& l = tag->findTagList( "query/item" );
49 ConstTagList::const_iterator it = l.begin();
50 for( ; it != l.end(); ++it )
51 {
52 StringList groups;
53 const ConstTagList& g = (*it)->findTagList( "item/group" );
54 ConstTagList::const_iterator it_g = g.begin();
55 for( ; it_g != g.end(); ++it_g )
56 groups.push_back( (*it_g)->cdata() );
57
58 const std::string sub = (*it)->findAttribute( "subscription" );
59 if( sub == "remove" )
60 m_roster.push_back( new RosterItemData( JID( (*it)->findAttribute( "jid" ) ) ) );
61 else
62 {
63 RosterItemData* rid = new RosterItemData( JID( (*it)->findAttribute( "jid" ) ),
64 (*it)->findAttribute( "name" ),
65 groups );
66 rid->setSubscription( sub, (*it)->findAttribute( "ask" ) );
67 m_roster.push_back( rid );
68 }
69 }
70 }
71
72 RosterManager::Query::~Query()
73 {
74 util::clearList( m_roster );
75 }
76
77 const std::string& RosterManager::Query::filterString() const
78 {
79 static const std::string filter = "/iq/query[@xmlns='" + XMLNS_ROSTER + "']";
80 return filter;
81 }
82
83 Tag* RosterManager::Query::tag() const
84 {
85 Tag* t = new Tag( "query" );
86 t->setXmlns( XMLNS_ROSTER );
87
88 RosterData::const_iterator it = m_roster.begin();
89 for( ; it != m_roster.end(); ++it )
90 t->addChild( (*it)->tag() );
91
92 return t;
93 }
94
95 StanzaExtension* RosterManager::Query::clone() const
96 {
97 Query* q = new Query();
98 RosterData::const_iterator it = m_roster.begin();
99 for( ; it != m_roster.end(); ++it )
100 {
101 q->m_roster.push_back( new RosterItemData( *(*it) ) );
102 }
103 return q;
104 }
105 // ---- ~RosterManager::Query ----
106
107 // ---- RosterManager ----
108 RosterManager::RosterManager( ClientBase* parent )
109 : m_rosterListener( 0 ), m_parent( parent ), m_privateXML( 0 ),
110 m_syncSubscribeReq( false )
111 {
112 if( m_parent )
113 {
114 m_parent->registerIqHandler( this, ExtRoster );
115 m_parent->registerPresenceHandler( this );
116 m_parent->registerSubscriptionHandler( this );
117 m_parent->registerStanzaExtension( new Query() );
118
119 m_self = new RosterItem( m_parent->jid().bare() );
120 m_privateXML = new PrivateXML( m_parent );
121 }
122 }
123
125 {
126 if( m_parent )
127 {
128 m_parent->removeIqHandler( this, ExtRoster );
129 m_parent->removeIDHandler( this );
130 m_parent->removePresenceHandler( this );
131 m_parent->removeSubscriptionHandler( this );
132 m_parent->removeStanzaExtension( ExtRoster );
133 delete m_self;
134 delete m_privateXML;
135 }
136
137 util::clearMap( m_roster );
138 }
139
141 {
142 return &m_roster;
143 }
144
146 {
147 if( !m_parent )
148 return;
149
150 util::clearMap( m_roster );
151 m_privateXML->requestXML( "roster", XMLNS_ROSTER_DELIMITER, this );
152 IQ iq( IQ::Get, JID(), m_parent->getID() );
153 iq.addExtension( new Query() );
154 m_parent->send( iq, this, RequestRoster );
155 }
156
157 bool RosterManager::handleIq( const IQ& iq )
158 {
159 if( iq.subtype() != IQ::Set ) // FIXME add checks for 'from' attribute (empty or bare self jid?)
160 return false;
161
162 // single roster item push
163 const Query* q = iq.findExtension<Query>( ExtRoster );
164 if( q && q->roster().size() )
165 mergePush( q->roster() );
166
167 IQ re( IQ::Result, JID(), iq.id() );
168 m_parent->send( re );
169 return true;
170 }
171
172 void RosterManager::handleIqID( const IQ& iq, int context )
173 {
174 if( iq.subtype() == IQ::Result ) // initial roster
175 {
176 const Query* q = iq.findExtension<Query>( ExtRoster );
177 if( q )
178 mergeRoster( q->roster() );
179
180 if( context == RequestRoster )
181 {
182 if( m_parent )
183 m_parent->rosterFilled();
184
185 if( m_rosterListener )
186 m_rosterListener->handleRoster( m_roster );
187 }
188 }
189 else if( iq.subtype() == IQ::Error )
190 {
191 if( context == RequestRoster && m_parent )
192 m_parent->rosterFilled();
193
194 if( m_rosterListener )
195 m_rosterListener->handleRosterError( iq );
196 }
197 }
198
200 {
201 if( presence.subtype() == Presence::Error )
202 return;
203
204 bool self = false;
205 Roster::iterator it = m_roster.find( presence.from().bare() );
206 if( it != m_roster.end() || ( self = ( presence.from().bareJID() == m_self->jidJID() ) ) )
207 {
208 RosterItem* ri = self ? m_self : (*it).second;
209 const std::string& resource = presence.from().resource();
210
211 if( presence.presence() == Presence::Unavailable )
212 ri->removeResource( resource );
213 else
214 {
215 ri->setPresence( resource, presence.presence() );
216 ri->setStatus( resource, presence.status() );
217 ri->setPriority( resource, presence.priority() );
218 ri->setExtensions( resource, presence.extensions() );
219 }
220
221 if( m_rosterListener && !self )
222 m_rosterListener->handleRosterPresence( *ri, resource,
223 presence.presence(), presence.status() );
224 else if( m_rosterListener && self )
225 m_rosterListener->handleSelfPresence( *ri, resource,
226 presence.presence(), presence.status() );
227 }
228 else
229 {
230 if( m_rosterListener )
231 m_rosterListener->handleNonrosterPresence( presence );
232 }
233 }
234
235 void RosterManager::subscribe( const JID& jid, const std::string& name,
236 const StringList& groups, const std::string& msg )
237 {
238 if( !jid )
239 return;
240
241 add( jid, name, groups );
242
244 m_parent->send( s );
245 }
246
247
248 void RosterManager::add( const JID& jid, const std::string& name, const StringList& groups )
249 {
250 if( !jid )
251 return;
252
253 IQ iq( IQ::Set, JID(), m_parent->getID() );
254 iq.addExtension( new Query( jid, name, groups) );
255
256 m_parent->send( iq, this, AddRosterItem );
257 }
258
259 void RosterManager::unsubscribe( const JID& jid, const std::string& msg )
260 {
262 m_parent->send( p );
263 }
264
265 void RosterManager::cancel( const JID& jid, const std::string& msg )
266 {
268 m_parent->send( p );
269 }
270
271 void RosterManager::remove( const JID& jid )
272 {
273 if( !jid )
274 return;
275
276 IQ iq( IQ::Set, JID(), m_parent->getID() );
277 iq.addExtension( new Query( jid ) );
278
279 m_parent->send( iq, this, RemoveRosterItem );
280 }
281
283 {
284 Roster::const_iterator it = m_roster.begin();
285 for( ; it != m_roster.end(); ++it )
286 {
287 if( !(*it).second->changed() )
288 continue;
289
290 IQ iq( IQ::Set, JID(), m_parent->getID() );
291 iq.addExtension( new Query( (*it).second->jidJID(), (*it).second->name(), (*it).second->groups() ) );
292 m_parent->send( iq, this, SynchronizeRoster );
293 }
294 }
295
296 void RosterManager::ackSubscriptionRequest( const JID& to, bool ack )
297 {
300 m_parent->send( p );
301 }
302
304 {
305 if( !m_rosterListener )
306 return;
307
308 switch( s10n.subtype() )
309 {
311 {
312 bool answer = m_rosterListener->handleSubscriptionRequest( s10n.from(), s10n.status() );
313 if( m_syncSubscribeReq )
314 {
315 ackSubscriptionRequest( s10n.from(), answer );
316 }
317 break;
318 }
320 {
321 m_rosterListener->handleItemSubscribed( s10n.from() );
322 break;
323 }
324
326 {
328 m_parent->send( p );
329
330 bool answer = m_rosterListener->handleUnsubscriptionRequest( s10n.from(), s10n.status() );
331 if( m_syncSubscribeReq && answer )
332 remove( s10n.from().bare() );
333 break;
334 }
335
337 {
338 m_rosterListener->handleItemUnsubscribed( s10n.from() );
339 break;
340 }
341
342 default:
343 break;
344 }
345 }
346
347 void RosterManager::registerRosterListener( RosterListener* rl, bool syncSubscribeReq )
348 {
349 m_syncSubscribeReq = syncSubscribeReq;
350 m_rosterListener = rl;
351 }
352
354 {
355 m_syncSubscribeReq = false;
356 m_rosterListener = 0;
357 }
358
359 void RosterManager::setDelimiter( const std::string& delimiter )
360 {
361 m_delimiter = delimiter;
362 Tag* t = new Tag( "roster", m_delimiter );
364 m_privateXML->storeXML( t, this );
365 }
366
368 {
369 if( xml )
370 m_delimiter = xml->cdata();
371 }
372
373 void RosterManager::handlePrivateXMLResult( const std::string& /*uid*/, PrivateXMLResult /*result*/ )
374 {
375 }
376
378 {
379 Roster::const_iterator it = m_roster.find( jid.bare() );
380 return it != m_roster.end() ? (*it).second : 0;
381 }
382
383 void RosterManager::mergePush( const RosterData& data )
384 {
385 RosterData::const_iterator it = data.begin();
386 for( ; it != data.end(); ++it )
387 {
388 Roster::iterator itr = m_roster.find( (*it)->jidJID().full() );
389 if( itr != m_roster.end() )
390 {
391 if( (*it)->remove() )
392 {
393 if( m_rosterListener )
394 m_rosterListener->handleItemRemoved( (*it)->jidJID().full() );
395 delete (*itr).second;
396 m_roster.erase( itr );
397 }
398 else
399 {
400 (*itr).second->setData( *(*it) );
401 if( m_rosterListener )
402 m_rosterListener->handleItemUpdated( (*it)->jidJID().full() );
403 }
404 }
405 else if( !(*it)->remove() )
406 {
407 m_roster.insert( std::make_pair( (*it)->jidJID().full(), new RosterItem( *(*it) ) ) );
408 if( m_rosterListener )
409 m_rosterListener->handleItemAdded( (*it)->jidJID().full() );
410 }
411 }
412 }
413
414 void RosterManager::mergeRoster( const RosterData& data )
415 {
416 RosterData::const_iterator it = data.begin();
417 for( ; it != data.end(); ++it )
418 m_roster.insert( std::make_pair( (*it)->jidJID().full(), new RosterItem( *(*it) ) ) );
419 }
420
421}
This is the common base class for a Jabber/XMPP Client and a Jabber Component.
Definition: clientbase.h:79
const std::string getID()
void registerPresenceHandler(PresenceHandler *ph)
void removeSubscriptionHandler(SubscriptionHandler *sh)
void removeIqHandler(IqHandler *ih, int exttype)
void registerSubscriptionHandler(SubscriptionHandler *sh)
void removeIDHandler(IqHandler *ih)
bool removeStanzaExtension(int ext)
void send(Tag *tag)
const JID & jid()
Definition: clientbase.h:147
void registerIqHandler(IqHandler *ih, int exttype)
void registerStanzaExtension(StanzaExtension *ext)
void removePresenceHandler(PresenceHandler *ph)
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 & resource() const
Definition: jid.h:116
JID bareJID() const
Definition: jid.h:74
const std::string & bare() const
Definition: jid.h:67
An abstraction of a presence stanza.
Definition: presence.h:33
int priority() const
Definition: presence.h:131
PresenceType presence() const
Definition: presence.h:89
PresenceType subtype() const
Definition: presence.h:76
const std::string status(const std::string &lang="default") const
Definition: presence.h:106
This class implements XEP-0049 (Private XML Storage).
Definition: privatexml.h:38
std::string requestXML(const std::string &tag, const std::string &xmlns, PrivateXMLHandler *pxh)
Definition: privatexml.cpp:74
std::string storeXML(const Tag *tag, PrivateXMLHandler *pxh)
Definition: privatexml.cpp:88
An abstraction of a roster item.
Definition: rosteritem.h:41
void setPriority(const std::string &resource, int priority)
Definition: rosteritem.cpp:128
const JID & jidJID() const
Definition: rosteritem.cpp:54
void removeResource(const std::string &resource)
Definition: rosteritem.cpp:160
void setStatus(const std::string &resource, const std::string &msg)
Definition: rosteritem.cpp:120
void setExtensions(const std::string &resource, const StanzaExtensionList &exts)
Definition: rosteritem.cpp:152
void setPresence(const std::string &resource, Presence::PresenceType presence)
Definition: rosteritem.cpp:112
A virtual interface which can be reimplemented to receive roster updates.
virtual bool handleSubscriptionRequest(const JID &jid, const std::string &msg)=0
virtual void handleItemUnsubscribed(const JID &jid)=0
virtual void handleItemRemoved(const JID &jid)=0
virtual void handleRoster(const Roster &roster)=0
virtual void handleItemSubscribed(const JID &jid)=0
virtual void handleNonrosterPresence(const Presence &presence)=0
virtual void handleItemAdded(const JID &jid)=0
virtual void handleItemUpdated(const JID &jid)=0
virtual void handleRosterPresence(const RosterItem &item, const std::string &resource, Presence::PresenceType presence, const std::string &msg)=0
virtual void handleSelfPresence(const RosterItem &item, const std::string &resource, Presence::PresenceType presence, const std::string &msg)=0
virtual bool handleUnsubscriptionRequest(const JID &jid, const std::string &msg)=0
virtual void handleRosterError(const IQ &iq)=0
void add(const JID &jid, const std::string &name, const StringList &groups)
void subscribe(const JID &jid, const std::string &name=EmptyString, const StringList &groups=StringList(), const std::string &msg=EmptyString)
void unsubscribe(const JID &jid, const std::string &msg=EmptyString)
virtual void handleSubscription(const Subscription &subscription)
virtual void handleIqID(const IQ &iq, int context)
const std::string & delimiter() const
virtual bool handleIq(const IQ &iq)
void setDelimiter(const std::string &delimiter)
virtual void handlePrivateXML(const Tag *xml)
virtual void handlePresence(const Presence &presence)
void cancel(const JID &jid, const std::string &msg=EmptyString)
RosterItem * getRosterItem(const JID &jid)
virtual void handlePrivateXMLResult(const std::string &uid, PrivateXMLResult pxResult)
void ackSubscriptionRequest(const JID &to, bool ack)
void remove(const JID &jid)
void registerRosterListener(RosterListener *rl, bool syncSubscribeReq=true)
void addExtension(const StanzaExtension *se)
Definition: stanza.cpp:52
const std::string & id() const
Definition: stanza.h:63
const StanzaExtensionList & extensions() const
Definition: stanza.h:113
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
S10nType subtype() const
Definition: subscription.h:69
const std::string status(const std::string &lang="default") const
Definition: subscription.h:80
This is an abstraction of an XML element.
Definition: tag.h:47
bool addAttribute(Attribute *attr)
Definition: tag.cpp:354
const std::string cdata() const
Definition: tag.cpp:497
void clearMap(std::map< Key, T * > &M)
Definition: util.h:169
The namespace for the gloox library.
Definition: adhoc.cpp:28
std::list< std::string > StringList
Definition: gloox.h:1251
const std::string XMLNS
Definition: gloox.cpp:122
std::list< const Tag * > ConstTagList
Definition: tag.h:36
const std::string XMLNS_ROSTER
Definition: gloox.cpp:38
std::map< const std::string, RosterItem * > Roster
const std::string XMLNS_ROSTER_DELIMITER
Definition: gloox.cpp:61