gloox  1.0.1
rostermanager.cpp
1 /*
2  Copyright (c) 2004-2012 by Jakob Schroeter <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 
26 namespace 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 ----
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 
199  void RosterManager::handlePresence( const Presence& presence )
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 }