glooxd  0.3-svn
sm.cpp
1 /*
2  Copyright (c) 2008-2009 by Jakob Schroeter <js@camaya.net>
3  This file is part of the glooxd library. http://camaya.net/glooxd
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 "glooxd.h"
15 #include "plugin.h"
16 #include "rosterprovider.h"
17 #include "sm.h"
18 
19 #include <gloox/adhoc.h>
20 #include <gloox/dataform.h>
21 #include <gloox/dataformfield.h>
22 #include <gloox/error.h>
23 #include <gloox/iq.h>
24 #include <gloox/jid.h>
25 #include <gloox/logsink.h>
26 #include <gloox/mutexguard.h>
27 #include <gloox/sha.h>
28 #include <gloox/util.h>
29 
30 #include <cstdio>
31 #include <ctime>
32 
33 namespace glooxd
34 {
35 
36  SM::SM( Router& _router, ConfigManager& cm, const gloox::LogSink& _logInstance,
37  RosterProvider* rp, bool threading,
38  const gloox::JID& _name )
39  : ComponentBase( _router, cm, _name, _logInstance ), m_rosterProvider( rp ),
40  m_threading( threading )
41  {
42  }
43 
45  {
46  gloox::util::clearList( m_plugins );
47  gloox::util::clearList( m_queue );
48  SessionList::iterator it = m_sessions.begin();
49  for( ; it != m_sessions.end(); ++it )
50  {
51  delete (*it).second.presence;
52  (*it).second.presence = 0;
53  }
54  }
55 
56  void SM::run()
57  {
58  if( !m_threading && !m_queue.size() )
59  return;
60 
61  do
62  {
63  m_queueSemaphore.wait();
64  gloox::Tag* t = m_queue.front();
65  m_queueMutex.lock();
66  m_queue.pop_front();
67  m_queueMutex.unlock();
68  handleTag( t );
69  } while( m_threading );
70  }
71 
72  bool SM::createSession( gloox::JID& jid, const std::string& id )
73  {
74  if( jid.username().empty() || jid.server().empty() )
75  {
76  m_logInstance.dbg( static_cast<gloox::LogArea>( LogAreaSM ),
77  "Cannot create session for " + jid.full()
78  + ". Need a username and server." );
79  return false;
80  }
81 
82  if( jid.resource().empty() )
83  {
84  gloox::SHA sha;
85  sha.feed( id );
86  sha.feed( jid.full() );
87  sha.feed( gloox::util::int2string( time( 0 ) ) );
88  jid.setResource( sha.hex() );
89  }
90 
91  m_sessionMutex.lock();
92  SessionList::iterator it = m_sessions.find( jid.full() );
93  if( it != m_sessions.end() )
94  {
95  const std::string tid = (*it).second.id;
96  m_sessionMutex.unlock();
97  m_logInstance.dbg( static_cast<gloox::LogArea>( LogAreaSM ),
98  "Session for " + jid.full() + " already " "exists. Replacing by new session." );
99  gloox::Tag* d = new gloox::Tag( "disconnect" );
100  d->setXmlns( XMLNS_GLOOXD );
101  gloox::Tag* c = new gloox::Tag( d, "conflict" );
102  c->setXmlns( gloox::XMLNS_XMPP_STREAM );
103  gloox::Tag* t = new gloox::Tag( c, "text", "conflicting resource connected." );
104  t->setXmlns( gloox::XMLNS_XMPP_STREAM );
105  t->addAttribute( "xml:lang", "en" );
106  gloox::JID j( jid );
107  j.setResource( tid );
108  d->addAttribute( "to", j.full() );
109  m_router.handleIncomingTag( d );
110  m_sessionMutex.lock();
111  }
112 
113  Session s;
114  s.id = id;
115  s.presence = 0;
116  m_sessions.insert( std::make_pair( jid.full(), s ) );
117  m_sessionMutex.unlock();
118  m_logInstance.dbg( static_cast<gloox::LogArea>( LogAreaSM ),
119  "Created session for " + jid.full()
120  + ", id: " + id );
121  return true;
122  }
123 
124  const SM::SessionList SM::findSessions( const gloox::JID& jid )
125  {
126  SessionList sl;
127  m_sessionMutex.lock();
128  SessionList::iterator it = m_sessions.begin();
129  for( ; it != m_sessions.end(); ++it )
130  {
131  gloox::JID j( (*it).first );
132  if( j.bare() == jid.bare() )
133  sl.insert( std::make_pair( (*it).first, (*it).second ) );
134  }
135  m_sessionMutex.unlock();
136 
137  return sl;
138  }
139 
140  bool SM::removeSession( const std::string& jid )
141  {
142 #ifdef DEBUG
143  printf( "--------------------removing sessions for client instance %s\n", jid.c_str() );
144 #endif
145  gloox::util::MutexGuard mg( m_sessionMutex );
146  SessionList::iterator it = m_sessions.find( jid );
147  if( it != m_sessions.end() )
148  {
149  delete (*it).second.presence;
150  m_sessions.erase( it );
151  return true;
152  }
153 
154  return false;
155  }
156 
157  void SM::dispatchPresence( const gloox::Tag* pres )
158  {
159  if( !m_rosterProvider || !pres )
160  return;
161 
162  const gloox::JID& from( pres->findAttribute( "from" ) );
163 
164 #ifdef DEBUG
165  printf( "dispatching presence for %s\n", from.full().c_str() );
166 #endif
167 
168  bool first = false;
169  SessionList::iterator itsl = m_sessions.find( from.full() );
170  if( itsl != m_sessions.end() )
171  {
172  first = !( (*itsl).second.presence );
173  }
174 
175  const Roster& rm = m_rosterProvider->getRoster( from.bare() );
176  Roster::const_iterator it = rm.begin();
177  for( ; it != rm.end(); ++it )
178  {
179 #ifdef DEBUG
180  printf( "looking for sessions for %s ...", (*it).first.c_str() );
181 #endif
182  const SessionList cl = findSessions( (*it).first );
183  if( cl.size() )
184  {
185 #ifdef DEBUG
186  printf( " found %d\n", cl.size() );
187 #endif
188  SessionList::const_iterator its = cl.begin();
189  for( ; its != cl.end(); ++its )
190  {
191  gloox::Tag* p = 0;
192  if( (*it).second == gloox::S10nBoth
193  || (*it).second == gloox::S10nFrom )
194  { // send own presence to contact
195  p = pres->clone();
196 #ifdef DEBUG
197  printf( "in for: stamping 'to': %s\n", (*its).first.c_str() );
198 #endif
199  p->addAttribute( "to", (*its).first );
200  m_router.handleIncomingTag( p );
201  }
202  if( first && (*its).second.presence
203  && ( (*it).second == gloox::S10nBoth
204  || (*it).second == gloox::S10nTo ) )
205  { // send contact presence to self, if not already known
206  p = (*its).second.presence->clone();
207 #ifdef DEBUG
208  printf( "in for/if: stamping 'to': %s\n", from.full().c_str() );
209 #endif
210  p->addAttribute( "to", from.full() );
211  m_router.handleIncomingTag( p );
212  }
213  }
214  }
215 #ifdef DEBUG
216  else
217  printf( " none found\n" );
218 #endif
219  }
220 
221  if( itsl != m_sessions.end() )
222  {
223  delete (*itsl).second.presence;
224  (*itsl).second.presence = pres->clone();
225  }
226  }
227 
228  bool SM::dispatchMessage( const gloox::Tag* msg )
229  {
230  if( !msg )
231  return false;
232 
233  gloox::JID jid( msg->findAttribute( "to" ) );
234  const SessionList sl = findSessions( jid );
235  SessionList::const_iterator it = sl.begin();
236  for( ; it != sl.end(); ++it )
237  {
238  gloox::Tag* m = msg->clone();
239  m->addAttribute( "to", (*it).first );
240  m_router.handleIncomingTag( m );
241  }
242 
243  if( !sl.size() )
244  return false;
245 
246  return true;
247  }
248 
249  void SM::handleIncomingTag( gloox::Tag* tag )
250  {
251  if( !tag )
252  return;
253 
254  m_queueMutex.lock();
255  m_queue.push_back( tag );
256  m_queueMutex.unlock();
257  m_queueSemaphore.post();
258  }
259 
260  void SM::handleTag( gloox::Tag* tag )
261  {
262  if( !tag )
263  return;
264 
265  m_logInstance.dbg( static_cast<gloox::LogArea>( LogAreaSM ),
266  tag->xml() );
267 
268  bool handled = false;
269  PluginList::const_iterator it = m_plugins.begin();
270  for( ; it != m_plugins.end(); ++it )
271  {
272  const std::string& xpath = (*it)->filterString();
273  const gloox::Tag* x = tag->findTag( xpath );
274  if( x && (*it)->handleTag( x ) )
275  {
276  handled = true;
277  break;
278  }
279  }
280 
281  if( !handled )
282  {
283 #ifdef DEBUG
284  printf( "!_____________!!!!!!!!!!!!______returningError for id: %s\n", tag->findAttribute( "id" ).c_str() );
285 #endif
286  gloox::Tag* t = returnError( tag );
287  m_router.handleIncomingTag( t );
288  }
289 
290  delete tag;
291  }
292 
293  void SM::handleDomainAdded( const std::string& domain )
294  {
295  if( domain.empty() )
296  return;
297 
298  m_router.registerDomain( this, domain, false );
299  }
300 
301  void SM::handleDomainRemoved( const std::string& domain )
302  {
303  if( domain.empty() )
304  return;
305 
306  m_router.removeDomain( this, domain, false );
307  }
308 
310  {
311  m_threading = false;
312  m_queueMutex.lock();
313  m_queue.push_back( 0 );
314  m_queueMutex.unlock();
315  }
316 
317 }