gloox  0.9.9.12
rostermanager.cpp
1 /*
2  Copyright (c) 2004-2008 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 "rosterlistener.h"
19 #include "privatexml.h"
20 
21 
22 namespace gloox
23 {
24 
26  : m_rosterListener( 0 ), m_parent( parent ), m_privateXML( 0 ),
27  m_syncSubscribeReq( false )
28  {
29  if( m_parent )
30  {
31  m_parent->registerIqHandler( this, XMLNS_ROSTER );
32  m_parent->registerPresenceHandler( this );
33  m_parent->registerSubscriptionHandler( this );
34 
35  m_self = new RosterItem( m_parent->jid().bare() );
36 
37  m_privateXML = new PrivateXML( m_parent );
38  }
39  }
40 
42  {
43  if( m_parent )
44  {
45  m_parent->removeIqHandler( XMLNS_ROSTER );
46  m_parent->removeIDHandler( this );
47  m_parent->removePresenceHandler( this );
48  m_parent->removeSubscriptionHandler( this );
49  delete m_self;
50  delete m_privateXML;
51  }
52 
53  Roster::iterator it = m_roster.begin();
54  for( ; it != m_roster.end(); ++it )
55  delete (*it).second;
56  m_roster.clear();
57  }
58 
60  {
61  return &m_roster;
62  }
63 
65  {
66  Roster::iterator it2;
67  Roster::iterator it = m_roster.begin();
68  while( it != m_roster.end() )
69  {
70  it2 = it++;
71  delete (*it2).second;
72  m_roster.erase( it2 );
73  }
74 
75  m_privateXML->requestXML( "roster", XMLNS_ROSTER_DELIMITER, this );
76 
77  Tag *iq = new Tag( "iq" );
78  iq->addAttribute( "type", "get" );
79  iq->addAttribute( "id", m_parent->getID() );
80  Tag *q = new Tag( iq, "query" );
81  q->addAttribute( "xmlns", XMLNS_ROSTER );
82  m_parent->send( iq );
83  }
84 
86  {
87  if( stanza->subtype() == StanzaIqResult ) // initial roster
88  {
89  extractItems( stanza, false );
90 
91  if( m_rosterListener )
92  m_rosterListener->handleRoster( m_roster );
93 
94  m_parent->rosterFilled();
95 
96  return true;
97  }
98  else if( stanza->subtype() == StanzaIqSet ) // roster item push
99  {
100  extractItems( stanza, true );
101 
102  Tag *iq = new Tag( "iq" );
103  iq->addAttribute( "id", stanza->id() );
104  iq->addAttribute( "type", "result" );
105  m_parent->send( iq );
106 
107  return true;
108  }
109  else if( stanza->subtype() == StanzaIqError )
110  {
111  if( m_rosterListener )
112  m_rosterListener->handleRosterError( stanza );
113  }
114 
115  return false;
116  }
117 
118  bool RosterManager::handleIqID( Stanza * /*stanza*/, int /*context*/ )
119  {
120  return false;
121  }
122 
124  {
125  if( stanza->subtype() == StanzaPresenceError )
126  return;
127 
128  StringList caps;
129  const Tag::TagList& l = stanza->children();
130  Tag::TagList::const_iterator it_c = l.begin();
131  for( ; it_c != l.end(); ++it_c )
132  {
133  if( (*it_c)->name() == "c" )
134  {
135  std::string cap;
136  cap.append( (*it_c)->findAttribute( "node" ).c_str() );
137  cap.append( "#" );
138  cap.append( (*it_c)->findAttribute( "ver" ).c_str() );
139  if( (*it_c)->findAttribute( "ext" ).size ())
140  {
141  cap.append( "#" );
142  cap.append( (*it_c)->findAttribute( "ext" ).c_str() );
143  }
144  caps.push_back( cap );
145  }
146  }
147 
148  Roster::iterator it = m_roster.find( stanza->from().bare() );
149  if( it != m_roster.end() )
150  {
151  if( stanza->presence() == PresenceUnavailable )
152  (*it).second->removeResource( stanza->from().resource() );
153  else
154  {
155  (*it).second->setPresence( stanza->from().resource(), stanza->presence() );
156  (*it).second->setStatus( stanza->from().resource(), stanza->status() );
157  (*it).second->setPriority( stanza->from().resource(), stanza->priority() );
158  // (*it).second->setCaps ( caps );
159  }
160 
161  if( m_rosterListener )
162  m_rosterListener->handleRosterPresence( (*(*it).second), stanza->from().resource(),
163  stanza->presence(), stanza->status() );
164  }
165  else if( stanza->from().bare() == m_self->jid() )
166  {
167  if( stanza->presence() == PresenceUnavailable )
168  m_self->removeResource( stanza->from().resource() );
169  else
170  {
171  m_self->setPresence( stanza->from().resource(), stanza->presence() );
172  m_self->setStatus( stanza->from().resource(), stanza->status() );
173  m_self->setPriority( stanza->from().resource(), stanza->priority() );
174  // (*it).second->setCaps ( caps );
175  }
176 
177  if( m_rosterListener )
178  m_rosterListener->handleSelfPresence( *m_self, stanza->from().resource(),
179  stanza->presence(), stanza->status() );
180  }
181  else
182  {
183  if( m_rosterListener )
184  m_rosterListener->handleNonrosterPresence( stanza );
185  }
186  }
187 
188  void RosterManager::subscribe( const JID& jid, const std::string& name,
189  const StringList& groups, const std::string& msg )
190  {
191  if( !jid )
192  return;
193 
194  add( jid, name, groups );
195 
196  Tag *s = new Tag( "presence" );
197  s->addAttribute( "type", "subscribe" );
198  s->addAttribute( "to", jid.bare() );
199  s->addAttribute( "from", m_parent->jid().full() );
200  if( !msg.empty() )
201  new Tag( s, "status", msg );
202 
203  m_parent->send( s );
204  }
205 
206 
207  void RosterManager::add( const JID& jid, const std::string& name, const StringList& groups )
208  {
209  if( !jid )
210  return;
211 
212  const std::string& id = m_parent->getID();
213 
214  Tag *iq = new Tag( "iq" );
215  iq->addAttribute( "type", "set" );
216  iq->addAttribute( "id", id );
217  Tag *q = new Tag( iq, "query" );
218  q->addAttribute( "xmlns", XMLNS_ROSTER );
219  Tag *i = new Tag( q, "item" );
220  i->addAttribute( "jid", jid.bare() );
221  if( !name.empty() )
222  i->addAttribute( "name", name );
223 
224  if( groups.size() != 0 )
225  {
226  StringList::const_iterator it = groups.begin();
227  for( ; it != groups.end(); ++it )
228  new Tag( i, "group", (*it) );
229  }
230 
231  m_parent->send( iq );
232  }
233 
234  void RosterManager::unsubscribe( const JID& jid, const std::string& msg )
235  {
236  Tag *s = new Tag( "presence" );
237  s->addAttribute( "type", "unsubscribe" );
238  s->addAttribute( "to", jid.bare() );
239  if( !msg.empty() )
240  new Tag( s, "status", msg );
241 
242  m_parent->send( s );
243 
244  }
245 
246  void RosterManager::cancel( const JID& jid, const std::string& msg )
247  {
248  Tag *s = new Tag( "presence" );
249  s->addAttribute( "type", "unsubscribed" );
250  s->addAttribute( "to", jid.bare() );
251  if( !msg.empty() )
252  new Tag( s, "status", msg );
253 
254  m_parent->send( s );
255 
256  }
257 
258  void RosterManager::remove( const JID& jid )
259  {
260  const std::string& id = m_parent->getID();
261 
262  Tag *iq = new Tag( "iq" );
263  iq->addAttribute( "type", "set" );
264  iq->addAttribute( "id", id );
265  Tag *q = new Tag( iq, "query" );
266  q->addAttribute( "xmlns", XMLNS_ROSTER );
267  Tag *i = new Tag( q, "item" );
268  i->addAttribute( "jid", jid.bare() );
269  i->addAttribute( "subscription", "remove" );
270 
271  m_parent->send( iq );
272  }
273 
275  {
276  Roster::const_iterator it = m_roster.begin();
277  for( ; it != m_roster.end(); ++it )
278  {
279  if( (*it).second->changed() )
280  {
281  const std::string& id = m_parent->getID();
282 
283  Tag *iq = new Tag( "iq" );
284  iq->addAttribute( "type", "set" );
285  iq->addAttribute( "id", id );
286  Tag *q = new Tag( iq, "query" );
287  q->addAttribute( "xmlns", XMLNS_ROSTER );
288  Tag *i = new Tag( q, "item" );
289  i->addAttribute( "jid", (*it).second->jid() );
290  if( !(*it).second->name().empty() )
291  i->addAttribute( "name", (*it).second->name() );
292 
293  if( (*it).second->groups().size() != 0 )
294  {
295  StringList::const_iterator g_it = (*it).second->groups().begin();
296  for( ; g_it != (*it).second->groups().end(); ++g_it )
297  new Tag( i, "group", (*g_it) );
298  }
299 
300  m_parent->send( iq );
301  }
302  }
303  }
304 
305  void RosterManager::ackSubscriptionRequest( const JID& to, bool ack )
306  {
307  Tag *p = new Tag( "presence" );
308  if( ack )
309  p->addAttribute( "type", "subscribed" );
310  else
311  p->addAttribute( "type", "unsubscribed" );
312 
313  p->addAttribute( "to", to.bare() );
314  m_parent->send( p );
315  }
316 
318  {
319  if( !m_rosterListener )
320  return;
321 
322  switch( stanza->subtype() )
323  {
324  case StanzaS10nSubscribe:
325  {
326  bool answer = m_rosterListener->handleSubscriptionRequest( stanza->from(), stanza->status() );
327  if( m_syncSubscribeReq )
328  {
329  ackSubscriptionRequest( stanza->from(), answer );
330  }
331  break;
332  }
334  {
335 // Tag *p = new Tag( "presence" );
336 // p->addAttribute( "type", "subscribe" );
337 // p->addAttribute( "to", stanza->from().bare() );
338 // m_parent->send( p );
339 
340  m_rosterListener->handleItemSubscribed( stanza->from() );
341  break;
342  }
343 
345  {
346  Tag *p = new Tag( "presence" );
347  p->addAttribute( "type", "unsubscribed" );
348  p->addAttribute( "to", stanza->from().bare() );
349  m_parent->send( p );
350 
351  bool answer = m_rosterListener->handleUnsubscriptionRequest( stanza->from(), stanza->status() );
352  if( m_syncSubscribeReq && answer )
353  remove( stanza->from().bare() );
354  break;
355  }
356 
358  {
359 // Tag *p = new Tag( "presence" );
360 // p->addAttribute( "type", "unsubscribe" );
361 // p->addAttribute( "to", stanza->from().bare() );
362 // m_parent->send( p );
363 
364  m_rosterListener->handleItemUnsubscribed( stanza->from() );
365  break;
366  }
367 
368  default:
369  break;
370  }
371  }
372 
373  void RosterManager::registerRosterListener( RosterListener *rl, bool syncSubscribeReq )
374  {
375  m_syncSubscribeReq = syncSubscribeReq;
376  m_rosterListener = rl;
377  }
378 
380  {
381  m_syncSubscribeReq = false;
382  m_rosterListener = 0;
383  }
384 
385  void RosterManager::extractItems( Tag *tag, bool isPush )
386  {
387  Tag *t = tag->findChild( "query" );
388  const Tag::TagList& l = t->children();
389  Tag::TagList::const_iterator it = l.begin();
390  for( ; it != l.end(); ++it )
391  {
392  if( (*it)->name() == "item" )
393  {
394  StringList gl;
395  if( (*it)->hasChild( "group" ) )
396  {
397  const Tag::TagList& g = (*it)->children();
398  Tag::TagList::const_iterator it_g = g.begin();
399  for( ; it_g != g.end(); ++it_g )
400  {
401  gl.push_back( (*it_g)->cdata() );
402  }
403  }
404 
405  const JID& jid = (*it)->findAttribute( "jid" );
406  Roster::iterator it_d = m_roster.find( jid.bare() );
407  if( it_d != m_roster.end() )
408  {
409  (*it_d).second->setName( (*it)->findAttribute( "name" ) );
410  const std::string& sub = (*it)->findAttribute( "subscription" );
411  if( sub == "remove" )
412  {
413  delete (*it_d).second;
414  m_roster.erase( it_d );
415  if( m_rosterListener )
416  m_rosterListener->handleItemRemoved( jid );
417  continue;
418  }
419  const std::string& ask = (*it)->findAttribute( "ask" );
420  bool a = false;
421  if( !ask.empty() )
422  a = true;
423  (*it_d).second->setSubscription( sub, a );
424  (*it_d).second->setGroups( gl );
425  (*it_d).second->setSynchronized();
426 
427  if( isPush && m_rosterListener )
428  m_rosterListener->handleItemUpdated( jid );
429  }
430  else
431  {
432  const std::string& sub = (*it)->findAttribute( "subscription" );
433  if( sub == "remove" )
434  continue;
435  const std::string& name = (*it)->findAttribute( "name" );
436  const std::string& ask = (*it)->findAttribute( "ask" );
437  bool a = false;
438  if( !ask.empty() )
439  a = true;
440 
441  StringList caps;
442  add( jid.bare(), name, gl, caps, sub, a );
443  if( isPush && m_rosterListener )
444  m_rosterListener->handleItemAdded( jid );
445  }
446  }
447  }
448  }
449 
450  void RosterManager::add( const std::string& jid, const std::string& name,
451  const StringList& groups, const StringList& caps,
452  const std::string& sub, bool ask )
453  {
454  if( m_roster.find( jid ) == m_roster.end() )
455  m_roster[jid] = new RosterItem( jid, name );
456 
457  m_roster[jid]->setSubscription( sub, ask );
458  m_roster[jid]->setGroups( groups );
459 // m_roster[jid]->setCaps( caps );
460  m_roster[jid]->setSynchronized();
461  }
462 
463  void RosterManager::setDelimiter( const std::string& delimiter )
464  {
465  m_delimiter = delimiter;
466  Tag *t = new Tag( "roster", m_delimiter );
467  t->addAttribute( "xmlns", XMLNS_ROSTER_DELIMITER );
468  m_privateXML->storeXML( t, this );
469  }
470 
471  void RosterManager::handlePrivateXML( const std::string& /*tag*/, Tag *xml )
472  {
473  m_delimiter = xml->cdata();
474  }
475 
476  void RosterManager::handlePrivateXMLResult( const std::string& /*uid*/, PrivateXMLResult /*result*/ )
477  {
478  }
479 
481  {
482  Roster::const_iterator it = m_roster.find( jid.bare() );
483  if( it != m_roster.end() )
484  return (*it).second;
485  else
486  return 0;
487  }
488 
489 }