gloox  1.0.27
clientbase.cpp
1 /*
2  Copyright (c) 2005-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 
15 #include "config.h"
16 
17 #include "base64.h"
18 #include "clientbase.h"
19 #include "compressionbase.h"
20 #include "compressionzlib.h"
21 #include "connectionbase.h"
22 #include "connectionlistener.h"
23 #include "connectiontcpclient.h"
24 #include "disco.h"
25 #include "error.h"
26 #include "eventhandler.h"
27 #include "event.h"
28 #include "iq.h"
29 #include "iqhandler.h"
30 #include "jid.h"
31 #include "loghandler.h"
32 #include "md5.h"
33 #include "message.h"
34 #include "messagehandler.h"
35 #include "messagesessionhandler.h"
36 #include "mucinvitationhandler.h"
37 #include "mucroom.h"
38 #include "mutexguard.h"
39 #include "presence.h"
40 #include "presencehandler.h"
41 #include "rosterlistener.h"
42 #include "stanzaextensionfactory.h"
43 #include "sha.h"
44 #include "subscription.h"
45 #include "subscriptionhandler.h"
46 #include "tag.h"
47 #include "taghandler.h"
48 #include "tlsbase.h"
49 #include "tlsdefault.h"
50 #include "prep.h"
51 #include "util.h"
52 
53 #include <cstdlib>
54 #include <string>
55 #include <map>
56 #include <list>
57 #include <algorithm>
58 #include <cmath>
59 #include <ctime>
60 #include <cstdio>
61 
62 #include <string.h> // for memset()
63 
64 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
65 #include <tchar.h>
66 # ifdef __MINGW32__
67 # ifndef SecureZeroMemory
68 # define SecureZeroMemory(p,s) RtlFillMemory((p),(s),0)
69 # endif
70 # endif
71 #endif
72 
73 namespace gloox
74 {
75 
76  // ---- ClientBase::Ping ----
77  ClientBase::Ping::Ping()
78  : StanzaExtension( ExtPing )
79  {
80  }
81 
82  ClientBase::Ping::~Ping()
83  {
84  }
85 
86  const std::string& ClientBase::Ping::filterString() const
87  {
88  static const std::string filter = "/iq/ping[@xmlns='" + XMLNS_XMPP_PING + "']";
89  return filter;
90  }
91  // ---- ~ClientBase::Ping ----
92 
93  // ---- ClientBase ----
94  ClientBase::ClientBase( const std::string& ns, const std::string& server, int port )
95  : m_connection( 0 ), m_encryption( 0 ), m_compression( 0 ), m_disco( 0 ), m_namespace( ns ),
96  m_xmllang( "en" ), m_server( server ), m_compressionActive( false ), m_encryptionActive( false ),
97  m_compress( true ), m_authed( false ), m_resourceBound( false ), m_block( false ), m_sasl( true ),
98  m_tls( TLSOptional ), m_port( port ),
99  m_availableSaslMechs( SaslMechAll ), m_smContext( CtxSMInvalid ), m_smHandled( 0 ),
100  m_statisticsHandler( 0 ), m_mucInvitationHandler( 0 ),
101  m_messageSessionHandlerChat( 0 ), m_messageSessionHandlerGroupchat( 0 ),
102  m_messageSessionHandlerHeadline( 0 ), m_messageSessionHandlerNormal( 0 ),
103  m_parser( this ), m_seFactory( 0 ), m_authError( AuthErrorUndefined ),
104  m_streamError( StreamErrorUndefined ), m_streamErrorAppCondition( 0 ),
105  m_selectedSaslMech( SaslMechNone ), m_customConnection( false ),
106  m_smSent( 0 )
107  {
108  init();
109  }
110 
111  ClientBase::ClientBase( const std::string& ns, const std::string& password,
112  const std::string& server, int port )
113  : m_connection( 0 ), m_encryption( 0 ), m_compression( 0 ), m_disco( 0 ), m_namespace( ns ),
114  m_password( password ),
115  m_xmllang( "en" ), m_server( server ), m_compressionActive( false ), m_encryptionActive( false ),
116  m_compress( true ), m_authed( false ), m_resourceBound( false ), m_block( false ), m_sasl( true ),
117  m_tls( TLSOptional ), m_port( port ),
118  m_availableSaslMechs( SaslMechAll ), m_smContext( CtxSMInvalid ), m_smHandled( 0 ),
119  m_statisticsHandler( 0 ), m_mucInvitationHandler( 0 ),
120  m_messageSessionHandlerChat( 0 ), m_messageSessionHandlerGroupchat( 0 ),
121  m_messageSessionHandlerHeadline( 0 ), m_messageSessionHandlerNormal( 0 ),
122  m_parser( this ), m_seFactory( 0 ), m_authError( AuthErrorUndefined ),
123  m_streamError( StreamErrorUndefined ), m_streamErrorAppCondition( 0 ),
124  m_selectedSaslMech( SaslMechNone ), m_customConnection( false ),
125  m_smSent( 0 )
126  {
127  init();
128  }
129 
130  void ClientBase::init()
131  {
132  srand( static_cast<unsigned int>( time( 0 ) ) );
133  SHA sha;
134  sha.feed( util::long2string( time( 0 ) ) );
135  sha.feed( util::int2string( rand() ) );
136  m_uniqueBaseId = sha.hex();
137 
138  if( !m_disco )
139  {
140  m_disco = new Disco( this );
141  m_disco->setVersion( "based on gloox", GLOOX_VERSION );
143  }
144 
145  registerStanzaExtension( new Error() );
146  registerStanzaExtension( new Ping() );
147  registerIqHandler( this, ExtPing );
148 
149  m_streamError = StreamErrorUndefined;
150  m_block = false;
151  memset( &m_stats, 0, sizeof( m_stats ) );
152  cleanup();
153  }
154 
156  {
157  m_iqHandlerMapMutex.lock();
158  m_iqIDHandlers.clear();
159  m_iqHandlerMapMutex.unlock();
160 
161  m_iqExtHandlerMapMutex.lock();
162  m_iqExtHandlers.clear();
163  m_iqExtHandlerMapMutex.unlock();
164 
166  util::clearMap( m_smQueue );
167 
168  setConnectionImpl( 0 );
169  setEncryptionImpl( 0 );
170  setCompressionImpl( 0 );
171  delete m_seFactory;
172  m_seFactory = 0; // to avoid usage when Disco gets deleted below
173  delete m_disco;
174  m_disco = 0;
175 
176  util::clearList( m_messageSessions );
177 
178  PresenceJidHandlerList::const_iterator it1 = m_presenceJidHandlers.begin();
179  for( ; it1 != m_presenceJidHandlers.end(); ++it1 )
180  delete (*it1).jid;
181  }
182 
184  {
186  return ConnNotConnected;
187 
188  return m_connection->recv( timeout );
189  }
190 
191  bool ClientBase::connect( bool block )
192  {
193  if( m_server.empty() )
194  return false;
195 
196  if( !m_connection )
197  m_connection = new ConnectionTCPClient( this, m_logInstance, m_server, m_port );
198 
200  return true;
201 
202  if( !m_encryption )
203  m_encryption = getDefaultEncryption();
204 
205  if( !m_compression )
206  m_compression = getDefaultCompression();
207 
208  m_logInstance.dbg( LogAreaClassClientbase, "This is gloox " + GLOOX_VERSION + ", connecting to "
209  + m_server + ( ( m_customConnection )?( " using a custom connection" ):( m_port > 0 ? ( ":" + util::int2string( m_port ) ) : EmptyString ) ) + "..." );
210  m_block = block;
212  if( ret != ConnNoError )
213  return false;
214 
215  if( m_block )
217 
218  return true;
219  }
220 
222  {
223  if( !tag )
224  {
225  logInstance().dbg( LogAreaClassClientbase, "stream closed" );
227  return;
228  }
229 
230  logInstance().dbg( LogAreaXmlIncoming, tag->xml() );
231  ++m_stats.totalStanzasReceived;
232 
233  if( tag->name() == "stream" && tag->xmlns() == XMLNS_STREAM )
234  {
235  const std::string& version = tag->findAttribute( "version" );
236  if( !checkStreamVersion( version ) )
237  {
238  logInstance().dbg( LogAreaClassClientbase, "This server is not XMPP-compliant"
239  " (it does not send a 'version' attribute). Please fix it or try another one.\n" );
241  return;
242  }
243 
244  m_sid = tag->findAttribute( "id" );
245  handleStartNode( tag );
246  }
247  else if( tag->name() == "error" && tag->xmlns() == XMLNS_STREAM )
248  {
249  handleStreamError( tag );
251  }
252  else
253  {
254  if( !handleNormalNode( tag ) )
255  {
256  if( tag->xmlns().empty() || tag->xmlns() == XMLNS_CLIENT )
257  {
258  if( tag->name() == "iq" )
259  {
260  IQ iq( tag );
261  m_seFactory->addExtensions( iq, tag );
262  if( iq.hasEmbeddedStanza() )
263  m_seFactory->addExtensions( *iq.embeddedStanza(), iq.embeddedTag() );
264  notifyIqHandlers( iq );
265  ++m_stats.iqStanzasReceived;
266  if( m_smContext >= CtxSMEnabled )
267  ++m_smHandled;
268  }
269  else if( tag->name() == "message" )
270  {
271  Message msg( tag );
272  m_seFactory->addExtensions( msg, tag );
273  if( msg.hasEmbeddedStanza() )
274  m_seFactory->addExtensions( *msg.embeddedStanza(), msg.embeddedTag() );
275  notifyMessageHandlers( msg );
276  ++m_stats.messageStanzasReceived;
277  if( m_smContext >= CtxSMEnabled )
278  ++m_smHandled;
279  }
280  else if( tag->name() == "presence" )
281  {
282  const std::string& type = tag->findAttribute( TYPE );
283  if( type == "subscribe" || type == "unsubscribe"
284  || type == "subscribed" || type == "unsubscribed" )
285  {
286  Subscription sub( tag );
287  m_seFactory->addExtensions( sub, tag );
288  if( sub.hasEmbeddedStanza() )
289  m_seFactory->addExtensions( *sub.embeddedStanza(), sub.embeddedTag() );
290  notifySubscriptionHandlers( sub );
291  ++m_stats.s10nStanzasReceived;
292  }
293  else
294  {
295  Presence pres( tag );
296  m_seFactory->addExtensions( pres, tag );
297  if( pres.hasEmbeddedStanza() )
298  m_seFactory->addExtensions( *pres.embeddedStanza(), pres.embeddedTag() );
299  notifyPresenceHandlers( pres );
300  ++m_stats.presenceStanzasReceived;
301  }
302  if( m_smContext >= CtxSMEnabled )
303  ++m_smHandled;
304  }
305  else
306  m_logInstance.err( LogAreaClassClientbase, "Invalid stanza received: " + tag->name() );
307  }
308  else
309  {
310  notifyTagHandlers( tag );
311  }
312  }
313  }
314 
315  if( m_statisticsHandler )
316  m_statisticsHandler->handleStatistics( getStatistics() );
317  }
318 
319  void ClientBase::handleCompressedData( const std::string& data )
320  {
322  m_encryption->encrypt( data );
323  else if( m_connection )
324  m_connection->send( data );
325  else
326  m_logInstance.err( LogAreaClassClientbase, "Compression finished, but chain broken" );
327  }
328 
329  void ClientBase::handleDecompressedData( const std::string& data )
330  {
331  parse( data );
332  }
333 
334  void ClientBase::handleEncryptedData( const TLSBase* /*base*/, const std::string& data )
335  {
336  if( m_connection )
337  m_connection->send( data );
338  else
339  m_logInstance.err( LogAreaClassClientbase, "Encryption finished, but chain broken" );
340  }
341 
342  void ClientBase::handleDecryptedData( const TLSBase* /*base*/, const std::string& data )
343  {
345  m_compression->decompress( data );
346  else
347  parse( data );
348  }
349 
350  void ClientBase::handleHandshakeResult( const TLSBase* /*base*/, bool success, CertInfo &certinfo )
351  {
352  if( success )
353  {
354  if( !notifyOnTLSConnect( certinfo ) )
355  {
356  logInstance().err( LogAreaClassClientbase, "Server's certificate rejected!" );
358  }
359  else
360  {
361  logInstance().dbg( LogAreaClassClientbase, "connection encryption active" );
362  header();
363  }
364  }
365  else
366  {
367  logInstance().err( LogAreaClassClientbase, "TLS handshake failed!" );
369  }
370  }
371 
372  void ClientBase::handleReceivedData( const ConnectionBase* /*connection*/, const std::string& data )
373  {
375  m_encryption->decrypt( data );
376  else if( m_compression && m_compressionActive )
377  m_compression->decompress( data );
378  else
379  parse( data );
380  }
381 
382  void ClientBase::handleConnect( const ConnectionBase* /*connection*/ )
383  {
384  header();
385  }
386 
387  void ClientBase::handleDisconnect( const ConnectionBase* /*connection*/, ConnectionError reason )
388  {
389  if( m_connection )
391 
392  if( m_encryption )
394 
395  if( m_compression )
397 
398  m_encryptionActive = false;
399  m_compressionActive = false;
400 
401  notifyOnDisconnect( reason );
402  }
403 
405  {
407  return;
408 
409  if( reason != ConnTlsFailed )
410  send( "</stream:stream>" );
411 
414 
415  if( m_encryption )
417 
418  if( m_compression )
420 
421  m_encryptionActive = false;
422  m_compressionActive = false;
423  m_smSent = 0;
424 
425  notifyOnDisconnect( reason );
426 
427 #ifdef CLIENTBASE_TEST
428  m_nextId.reset();
429 #endif
430  }
431 
432  void ClientBase::parse( const std::string& data )
433  {
434  std::string copy = data;
435  int i = 0;
436  if( ( i = m_parser.feed( copy ) ) >= 0 )
437  {
438  std::string error = "parse error (at pos ";
439  error += util::int2string( i );
440  error += "): ";
441  m_logInstance.err( LogAreaClassClientbase, error + copy );
442  Tag* e = new Tag( "stream:error" );
443  new Tag( e, "restricted-xml", "xmlns", XMLNS_XMPP_STREAM );
444  send( e );
446  }
447  }
448 
450  {
451  std::string head = "<?xml version='1.0' ?>";
452  head += "<stream:stream to='" + m_jid.server() + "' xmlns='" + m_namespace + "' ";
453  head += "xmlns:stream='http://etherx.jabber.org/streams' xml:lang='" + m_xmllang + "' ";
454  head += "version='" + XMPP_STREAM_VERSION_MAJOR + "." + XMPP_STREAM_VERSION_MINOR + "'>";
455  send( head );
456  }
457 
459  {
460 #if defined( HAVE_GNUTLS ) || defined( HAVE_OPENSSL ) || defined( HAVE_WINTLS )
461  return true;
462 #else
463  return false;
464 #endif
465  }
466 
468  {
469  send( new Tag( "starttls", XMLNS, XMLNS_STREAM_TLS ) );
470  }
471 
472  void ClientBase::setServer( const std::string &server )
473  {
474  m_server = server;
475  if( m_connection )
477  }
478 
479  void ClientBase::setClientCert( const std::string& clientKey, const std::string& clientCerts )
480  {
481  m_clientKey = clientKey;
482  m_clientCerts = clientCerts;
483  }
484 
486  {
487  m_selectedSaslMech = type;
488 
489  Tag* a = new Tag( "auth", XMLNS, XMLNS_STREAM_SASL );
490 
491  switch( type )
492  {
494  case SaslMechScramSha1:
495  {
496  if( type == SaslMechScramSha1 )
497  {
499  m_gs2Header = "y,";
500  else
501  m_gs2Header = "n,";
502  a->addAttribute( "mechanism", "SCRAM-SHA-1" );
503  }
504  else // SaslMechScramSha1Plus
505  {
506  m_gs2Header = "p=tls-unique,";
507  a->addAttribute( "mechanism", "SCRAM-SHA-1-PLUS" );
508  }
509 
510  std::string t;
511  if( m_authzid && prep::saslprep( m_authzid.bare(), t ) )
512  m_gs2Header += "a=" + t;
513 
514  m_gs2Header += ",";
515 
516  m_clientFirstMessageBare = "n=";
517  if( !m_authcid.empty() && prep::saslprep( m_authcid, t ) )
518  m_clientFirstMessageBare += t;
519  else if( prep::saslprep( m_jid.username(), t ) )
520  m_clientFirstMessageBare += t;
521 
522  m_clientFirstMessageBare += ",r=" + getRandom();
523 
524  a->setCData( Base64::encode64( m_gs2Header + m_clientFirstMessageBare ) );
525  break;
526  }
527  case SaslMechDigestMd5:
528  a->addAttribute( "mechanism", "DIGEST-MD5" );
529  break;
530  case SaslMechPlain:
531  {
532  a->addAttribute( "mechanism", "PLAIN" );
533 
534  std::string tmp;
535  if( m_authzid )
536  tmp += m_authzid.bare();
537 
538  tmp += '\0';
539  if( !m_authcid.empty() )
540  tmp += m_authcid;
541  else
542  tmp += m_jid.username();
543  tmp += '\0';
544  tmp += m_password;
545  a->setCData( Base64::encode64( tmp ) );
546  break;
547  }
548  case SaslMechAnonymous:
549  a->addAttribute( "mechanism", "ANONYMOUS" );
550  break;
551  case SaslMechExternal:
552  a->addAttribute( "mechanism", "EXTERNAL" );
554  break;
555  case SaslMechGssapi:
556  {
557 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
558  a->addAttribute( "mechanism", "GSSAPI" );
559 // The client calls GSS_Init_sec_context, passing in 0 for
560 // input_context_handle (initially) and a targ_name equal to output_name
561 // from GSS_Import_Name called with input_name_type of
562 // GSS_C_NT_HOSTBASED_SERVICE and input_name_string of
563 // "service@hostname" where "service" is the service name specified in
564 // the protocol's profile, and "hostname" is the fully qualified host
565 // name of the server. The client then responds with the resulting
566 // output_token.
567  std::string token;
568  a->setCData( Base64::encode64( token ) );
569 // etc... see gssapi-sasl-draft.txt
570 #else
572  "SASL GSSAPI is not supported on this platform. You should never see this." );
573 #endif
574  break;
575  }
576  case SaslMechNTLM:
577  {
578 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
579  a->addAttribute( "mechanism", "NTLM" );
580  SEC_WINNT_AUTH_IDENTITY_W identity, *ident = 0;
581  memset( &identity, 0, sizeof( identity ) );
582 
583  WCHAR *usernameW = 0, *domainW = 0, *passwordW = 0;
584  int cchUsernameW = 0, cchDomainW = 0, cchPasswordW = 0;
585 
586  if( m_jid.username().length() > 0 )
587  {
588  // NOTE: The return values of MultiByteToWideChar will include room
589  // for the NUL character since we use -1 for the input length.
590 
591  cchUsernameW = ::MultiByteToWideChar( CP_UTF8, 0, m_jid.username().c_str(), -1, 0, 0 );
592  if( cchUsernameW > 0 )
593  {
594  usernameW = new WCHAR[cchUsernameW];
595  ::MultiByteToWideChar( CP_UTF8, 0, m_jid.username().c_str(), -1, usernameW, cchUsernameW );
596  // Guarantee its NUL terminated.
597  usernameW[cchUsernameW-1] = L'\0';
598  }
599  cchDomainW = ::MultiByteToWideChar( CP_UTF8, 0, m_ntlmDomain.c_str(), -1, 0, 0 );
600  if( cchDomainW > 0 )
601  {
602  domainW = new WCHAR[cchDomainW];
603  ::MultiByteToWideChar( CP_UTF8, 0, m_ntlmDomain.c_str(), -1, domainW, cchDomainW );
604  // Guarantee its NUL terminated.
605  domainW[cchDomainW-1] = L'\0';
606  }
607  cchPasswordW = ::MultiByteToWideChar( CP_UTF8, 0, m_password.c_str(), -1, 0, 0 );
608  if( cchPasswordW > 0 )
609  {
610  passwordW = new WCHAR[cchPasswordW];
611  ::MultiByteToWideChar( CP_UTF8, 0, m_password.c_str(), -1, passwordW, cchPasswordW );
612  // Guarantee its NUL terminated.
613  passwordW[cchPasswordW-1] = L'\0';
614  }
615  identity.User = (unsigned short*)usernameW;
616  identity.UserLength = (unsigned long)cchUsernameW-1;
617  identity.Domain = (unsigned short*)domainW;
618  identity.DomainLength = (unsigned long)cchDomainW-1;
619  identity.Password = (unsigned short*)passwordW;
620  identity.PasswordLength = (unsigned long)cchPasswordW-1;
621  identity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
622  ident = &identity;
623  }
624 
625  AcquireCredentialsHandleW( 0, L"NTLM", SECPKG_CRED_OUTBOUND, 0, ident, 0, 0, &m_credHandle, 0 );
626 
627  if( usernameW != 0 )
628  {
629  delete[] usernameW;
630  usernameW = 0;
631  }
632  if( domainW != 0 )
633  {
634  delete[] domainW;
635  domainW = 0;
636  }
637  if( passwordW != 0 )
638  {
639  ::SecureZeroMemory( passwordW, cchPasswordW* sizeof( WCHAR ) );
640  delete[] passwordW;
641  passwordW = 0;
642  }
643 
644 #else
646  "SASL NTLM is not supported on this platform. You should never see this." );
647 #endif
648  break;
649  }
650  default:
651  break;
652  }
653 
654  send( a );
655  }
656 
657  std::string ClientBase::hmac( const std::string& key, const std::string& str )
658  {
659  SHA sha;
660  std::string key_ = key;
661  if( key_.length() > 64 )
662  {
663  sha.feed( key_ );
664  key_ = sha.binary();
665  sha.reset();
666  }
667  unsigned char ipad[65];
668  unsigned char opad[65];
669  memset( ipad, '\0', sizeof( ipad ) );
670  memset( opad, '\0', sizeof( opad ) );
671  memcpy( ipad, key_.c_str(), key_.length() );
672  memcpy( opad, key_.c_str(), key_.length() );
673  for( int i = 0; i < 64; i++ )
674  {
675  ipad[i] ^= 0x36;
676  opad[i] ^= 0x5c;
677  }
678  sha.feed( ipad, 64 );
679  sha.feed( str );
680  key_ = sha.binary();
681  sha.reset();
682  sha.feed( opad, 64 );
683  sha.feed( key_ );
684 
685  return sha.binary(); // hex() for testing
686  }
687 
688  std::string ClientBase::hi( const std::string& str, const std::string& salt, int iter )
689  {
690  int xored[20];
691  memset( xored, '\0', sizeof( xored ) );
692  std::string tmp = salt;
693  tmp.append( "\0\0\0\1", 4 );
694  for( int i = 0; i < iter; ++i )
695  {
696  tmp = hmac( str, tmp );
697  for( int j = 0; j < 20; ++j )
698  xored[j] ^= tmp.c_str()[j];
699  }
700  std::string n;
701  for( int i=0; i < 20 ;++i )
702  n.push_back( static_cast<char>( xored[i] ) );
703 
704  return n;
705  }
706 
707  void ClientBase::processSASLChallenge( const std::string& challenge )
708  {
709  Tag* t = new Tag( "response", XMLNS, XMLNS_STREAM_SASL );
710 
711  const std::string& decoded = Base64::decode64( challenge );
712 
713  switch( m_selectedSaslMech )
714  {
716  case SaslMechScramSha1:
717  {
718  std::string snonce, salt, tmp;
719  int iter = 0;
720  std::string::size_type posn = decoded.find( "r=" );
721  std::string::size_type poss = decoded.find( "s=" );
722  std::string::size_type posi = decoded.find( "i=" );
723  if( posn == std::string::npos || poss == std::string::npos || posi == std::string::npos )
724  break;
725 
726  snonce = decoded.substr( posn + 2, poss - posn - 3 );
727  salt = Base64::decode64( decoded.substr( poss + 2, posi - poss - 3 ) );
728  tmp = decoded.substr( posi + 2, decoded.length() - posi - 2 );
729  iter = atoi( tmp.c_str() );
730 
731  if( !prep::saslprep( m_password, tmp ) )
732  break;
733 
734  std::string saltedPwd = hi( tmp, salt, iter );
735  std::string ck = hmac( saltedPwd, "Client Key" );
736  SHA sha;
737  sha.feed( ck );
738  std::string storedKey = sha.binary();
739 
740  if( m_selectedSaslMech == SaslMechScramSha1Plus )
741  tmp = "c=" + Base64::encode64( m_gs2Header + m_encryption->channelBinding() );
742  else
743  tmp = "c=biws";
744  tmp += ",r=" + snonce;
745 
746  std::string authMessage = m_clientFirstMessageBare + "," + decoded + "," + tmp; // client-final-message-without-proof
747  std::string clientSignature = hmac( storedKey, authMessage );
748  unsigned char clientProof[20]; // ck XOR clientSignature
749  memcpy( clientProof, ck.c_str(), 20 );
750  for( int i = 0; i < 20; ++i )
751  clientProof[i] ^= clientSignature.c_str()[i];
752  std::string serverKey = hmac( saltedPwd, "Server Key" );
753  m_serverSignature = hmac( serverKey, authMessage );
754 
755  tmp += ",p=";
756  tmp.append( Base64::encode64( std::string( reinterpret_cast<const char*>( clientProof ), 20 ) ) );
757 
758  t->setCData( Base64::encode64( tmp ) );
759 
760  break;
761  }
762  case SaslMechDigestMd5:
763  {
764  if( !decoded.compare( 0, 7, "rspauth" ) )
765  break;
766 
767  std::string realm;
768  std::string::size_type end = 0;
769  std::string::size_type pos = decoded.find( "realm=" );
770  if( pos != std::string::npos )
771  {
772  end = decoded.find( '"', pos + 7 );
773  realm = decoded.substr( pos + 7, end - ( pos + 7 ) );
774  }
775  else
776  realm = m_jid.server();
777 
778  pos = decoded.find( "nonce=" );
779  if( pos == std::string::npos )
780  return;
781 
782  end = decoded.find( '"', pos + 7 );
783  while( decoded[end-1] == '\\' )
784  end = decoded.find( '"', end + 1 );
785  std::string nonce = decoded.substr( pos + 7, end - ( pos + 7 ) );
786 
787  std::string cnonce = getRandom();
788 
789  MD5 md5;
790  md5.feed( m_jid.username() );
791  md5.feed( ":" );
792  md5.feed( realm );
793  md5.feed( ":" );
794  md5.feed( m_password );
795  md5.finalize();
796  const std::string& a1_h = md5.binary();
797  md5.reset();
798  md5.feed( a1_h );
799  md5.feed( ":" );
800  md5.feed( nonce );
801  md5.feed( ":" );
802  md5.feed( cnonce );
803  md5.finalize();
804  const std::string& a1 = md5.hex();
805  md5.reset();
806  md5.feed( "AUTHENTICATE:xmpp/" );
807  md5.feed( m_jid.server() );
808  md5.finalize();
809  const std::string& a2 = md5.hex();
810  md5.reset();
811  md5.feed( a1 );
812  md5.feed( ":" );
813  md5.feed( nonce );
814  md5.feed( ":00000001:" );
815  md5.feed( cnonce );
816  md5.feed( ":auth:" );
817  md5.feed( a2 );
818  md5.finalize();
819 
820  std::string response = "username=\"";
821  response += m_jid.username();
822  response += "\",realm=\"";
823  response += realm;
824  response += "\",nonce=\"";
825  response += nonce;
826  response += "\",cnonce=\"";
827  response += cnonce;
828  response += "\",nc=00000001,qop=auth,digest-uri=\"xmpp/";
829  response += m_jid.server();
830  response += "\",response=";
831  response += md5.hex();
832  response += ",charset=utf-8";
833 
834  if( m_authzid )
835  response += ",authzid=" + m_authzid.bare();
836 
837  t->setCData( Base64::encode64( response ) );
838 
839  break;
840  }
841  case SaslMechGssapi:
842 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
843  // see gssapi-sasl-draft.txt
844 #else
845  m_logInstance.err( LogAreaClassClientbase,
846  "Huh, received GSSAPI challenge?! This should have never happened!" );
847 #endif
848  break;
849  case SaslMechNTLM:
850  {
851 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
852  bool type1 = ( decoded.length() < 7 ) ? true : false;
853 
854  SecBuffer bufferIn = { type1 ? 0 : (unsigned long)decoded.length(),
855  SECBUFFER_TOKEN,
856  (void*)decoded.c_str() };
857  SecBufferDesc secIn = { 0, 1, &bufferIn };
858 
859  char buffer[4096];
860 
861  SecBuffer bufferOut = { sizeof( buffer ), SECBUFFER_TOKEN, buffer };
862  SecBufferDesc secOut = { 0, 1, &bufferOut };
863 
864  TimeStamp timestamp;
865  unsigned long contextAttr;
866 
867  SECURITY_STATUS status = InitializeSecurityContext( &m_credHandle, type1 ? 0 : &m_ctxtHandle,
868  0, ISC_REQ_MUTUAL_AUTH, 0, 0, &secIn, 0,
869  &m_ctxtHandle, &secOut, &contextAttr,
870  &timestamp );
871  std::string response;
872  if( SUCCEEDED( status ) )
873  {
874  response = std::string( (const char *)bufferOut.pvBuffer, bufferOut.cbBuffer );
875  }
876  else
877  {
879  "InitializeSecurityContext() failed, return value "
880  + util::int2string( status ) );
881  }
882 
883  t->setCData( Base64::encode64( response ) );
884 #else
885  m_logInstance.err( LogAreaClassClientbase,
886  "Huh, received NTLM challenge?! This should have never happened!" );
887 #endif
888  break;
889  }
890 
891  default:
892  // should never happen.
893  break;
894  }
895 
896  send( t );
897  }
898 
900  {
901  if( tag->hasChild( "aborted" ) )
902  m_authError = SaslAborted;
903  else if( tag->hasChild( "incorrect-encoding" ) )
904  m_authError = SaslIncorrectEncoding;
905  else if( tag->hasChild( "invalid-authzid" ) )
906  m_authError = SaslInvalidAuthzid;
907  else if( tag->hasChild( "invalid-mechanism" ) )
908  m_authError = SaslInvalidMechanism;
909  else if( tag->hasChild( "malformed-request" ) )
910  m_authError = SaslMalformedRequest;
911  else if( tag->hasChild( "mechanism-too-weak" ) )
912  m_authError = SaslMechanismTooWeak;
913  else if( tag->hasChild( "not-authorized" ) )
914  m_authError = SaslNotAuthorized;
915  else if( tag->hasChild( "temporary-auth-failure" ) )
916  m_authError = SaslTemporaryAuthFailure;
917 
918 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
919  if( m_selectedSaslMech == SaslMechNTLM )
920  {
921  FreeCredentialsHandle( &m_credHandle );
922  DeleteSecurityContext( &m_ctxtHandle );
923  }
924 #endif
925  }
926 
927  bool ClientBase::processSASLSuccess( const std::string& payload )
928  {
929 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
930  if( m_selectedSaslMech == SaslMechNTLM )
931  {
932  FreeCredentialsHandle( &m_credHandle );
933  DeleteSecurityContext( &m_ctxtHandle );
934  }
935 #endif
936  if( m_selectedSaslMech == SaslMechScramSha1 || m_selectedSaslMech == SaslMechScramSha1Plus )
937  {
938  const std::string decoded = Base64::decode64( payload );
939  if( decoded.length() < 3 || Base64::decode64( decoded.substr( 2 ) ) != m_serverSignature )
940  return false;
941  }
942 
943  return true;
944  }
945 
946  void ClientBase::send( IQ& iq, IqHandler* ih, int context, bool del )
947  {
948  if( ih && ( iq.subtype() == IQ::Set || iq.subtype() == IQ::Get ) )
949  {
950  if( iq.id().empty() )
951  iq.setID( getID() );
952 
953  TrackStruct track;
954  track.ih = ih;
955  track.context = context;
956  track.del = del;
957  m_iqHandlerMapMutex.lock();
958  m_iqIDHandlers[iq.id()] = track;
959  m_iqHandlerMapMutex.unlock();
960  }
961 
962  send( iq );
963  }
964 
965  void ClientBase::send( const IQ& iq )
966  {
967  ++m_stats.iqStanzasSent;
968  Tag* tag = iq.tag();
969  addFrom( tag );
970  addNamespace( tag );
971  send( tag, true, false );
972  }
973 
974  void ClientBase::send( const Message& msg )
975  {
976  ++m_stats.messageStanzasSent;
977  Tag* tag = msg.tag();
978  addFrom( tag );
979  addNamespace( tag );
980  send( tag, true, false );
981  }
982 
983  void ClientBase::send( const Subscription& sub )
984  {
985  ++m_stats.s10nStanzasSent;
986  Tag* tag = sub.tag();
987  addFrom( tag );
988  addNamespace( tag );
989  send( tag, true, false );
990  }
991 
992  void ClientBase::send( const Presence& pres )
993  {
994  ++m_stats.presenceStanzasSent;
995  Tag* tag = pres.tag();
996  StanzaExtensionList::const_iterator it = m_presenceExtensions.begin();
997  for( ; it != m_presenceExtensions.end(); ++it )
998  tag->addChild( (*it)->tag() );
999  addFrom( tag );
1000  addNamespace( tag );
1001  send( tag, true, false );
1002  }
1003 
1004  void ClientBase::send( Tag* tag )
1005  {
1006  if( !tag )
1007  return;
1008 
1009  send( tag, false, true );
1010  }
1011 
1012  void ClientBase::send( Tag* tag, bool queue, bool del )
1013  {
1014  if( !tag )
1015  return;
1016 
1017  send( tag->xml() );
1018 
1019  ++m_stats.totalStanzasSent;
1020 
1021  if( m_statisticsHandler )
1022  m_statisticsHandler->handleStatistics( getStatistics() );
1023 
1024  if( queue && m_smContext >= CtxSMEnabled )
1025  {
1026  m_queueMutex.lock();
1027  m_smQueue.insert( std::make_pair( ++m_smSent, tag ) );
1028  m_queueMutex.unlock();
1029  }
1030  else if( del || m_smContext < CtxSMEnabled )
1031  delete tag;
1032  }
1033 
1034  void ClientBase::send( const std::string& xml )
1035  {
1037  {
1039  m_compression->compress( xml );
1040  else if( m_encryption && m_encryptionActive )
1041  m_encryption->encrypt( xml );
1042  else
1043  m_connection->send( xml );
1044 
1046  }
1047  }
1048 
1049  void ClientBase::checkQueue( int handled, bool resend )
1050  {
1051  if( m_smContext < CtxSMEnabled || handled < 0 )
1052  return;
1053 
1054  util::MutexGuard mg( m_queueMutex );
1055  SMQueueMap::iterator it = m_smQueue.begin();
1056  while( it != m_smQueue.end() )
1057  {
1058  if( (*it).first <= handled )
1059  {
1060  delete (*it).second;
1061  m_smQueue.erase( it++ );
1062  }
1063  else if( resend && (*it).first > handled )
1064  {
1065  send( (*it).second, false, false );
1066  ++it;
1067  }
1068  else
1069  {
1070  ++it;
1071  }
1072  }
1073  }
1074 
1076  {
1077  TagList l;
1078  util::MutexGuard mg( m_queueMutex );
1079  SMQueueMap::iterator it = m_smQueue.begin();
1080  for( ; it != m_smQueue.end(); ++it )
1081  l.push_back( (*it).second->clone() );
1082 
1083  return l;
1084  }
1085 
1086  void ClientBase::addFrom( Tag* tag )
1087  {
1088  if( !m_authed /* for IQ Auth */ || !m_resourceBound /* for resource binding */ || !tag || tag->hasAttribute( "from" ) )
1089  return;
1090 
1091  tag->addAttribute( "from", m_jid.full() );
1092  }
1093 
1094  void ClientBase::addNamespace( Tag* tag )
1095  {
1096  if( !tag || !tag->xmlns().empty() )
1097  return;
1098 
1099  tag->setXmlns( m_namespace );
1100  }
1101 
1103  {
1104  if( !m_seFactory )
1105  m_seFactory = new StanzaExtensionFactory();
1106 
1107  m_seFactory->registerExtension( ext );
1108  }
1109 
1111  {
1112  if( !m_seFactory )
1113  return false;
1114 
1115  return m_seFactory->removeExtension( ext );
1116  }
1117 
1119  {
1120  if( m_connection )
1122 
1123  return m_stats;
1124  }
1125 
1127  {
1129  }
1130 
1132  {
1133  send( " " );
1134  }
1135 
1136  void ClientBase::xmppPing( const JID& to, EventHandler* eh )
1137  {
1138  const std::string& id = getID();
1139  IQ iq( IQ::Get, to, id );
1140  iq.addExtension( new Ping() );
1141  m_dispatcher.registerEventHandler( eh, id );
1142  send( iq, this, XMPPPing );
1143  }
1144 
1145  bool ClientBase::handleIq( const IQ& iq )
1146  {
1147  const Ping* p = iq.findExtension<Ping>( ExtPing );
1148  if( !p || iq.subtype() != IQ::Get )
1149  return false;
1150 
1151  m_dispatcher.dispatch( Event( Event::PingPing, iq ) );
1152  IQ re( IQ::Result, iq.from(), iq.id() );
1153  send( re );
1154 
1155  return true;
1156  }
1157 
1158  void ClientBase::handleIqID( const IQ& iq, int context )
1159  {
1160  if( context == XMPPPing )
1161  m_dispatcher.dispatch( Event( ( iq.subtype() == IQ::Result ) ? Event::PingPong
1162  : Event::PingError, iq ),
1163  iq.id(), true );
1164  else
1165  handleIqIDForward( iq, context );
1166  }
1167 
1168  const std::string ClientBase::getID()
1169  {
1170 #ifdef CLIENTBASE_TEST // to create predictable UIDs in test mode
1171  return "uid" + util::int2string( m_nextId.increment() );
1172 #else
1173  char r[48+1];
1174  sprintf( r, "%s%08x", m_uniqueBaseId.c_str(), m_nextId.increment() );
1175  std::string ret( r, 48 );
1176  return ret;
1177 #endif
1178  }
1179 
1180  bool ClientBase::checkStreamVersion( const std::string& version )
1181  {
1182  if( version.empty() )
1183  return false;
1184 
1185  int major = 0;
1186 // int minor = 0;
1187  int myMajor = atoi( XMPP_STREAM_VERSION_MAJOR.c_str() );
1188 
1189  size_t dot = version.find( '.' );
1190  if( !version.empty() && dot && dot != std::string::npos )
1191  {
1192  major = atoi( version.substr( 0, dot ).c_str() );
1193 // minor = atoi( version.substr( dot ).c_str() );
1194  }
1195 
1196  return myMajor >= major;
1197  }
1198 
1200  {
1202  m_connection = connection;
1203  m_customConnection = true;
1204  if( old )
1205  delete old;
1206  }
1207 
1209  {
1210  TLSBase* old = m_encryption;
1211  m_encryption = encryption;
1212  if( old )
1213  delete old;
1214  }
1215 
1217  {
1220  if( old )
1221  delete old;
1222  }
1223 
1224  void ClientBase::handleStreamError( Tag* tag )
1225  {
1227  const TagList& c = tag->children();
1228  TagList::const_iterator it = c.begin();
1229  for( ; it != c.end(); ++it )
1230  {
1231  const std::string& name = (*it)->name();
1232  if( name == "bad-format" )
1233  err = StreamErrorBadFormat;
1234  else if( name == "bad-namespace-prefix" )
1236  else if( name == "conflict" )
1237  err = StreamErrorConflict;
1238  else if( name == "connection-timeout" )
1240  else if( name == "host-gone" )
1241  err = StreamErrorHostGone;
1242  else if( name == "host-unknown" )
1243  err = StreamErrorHostUnknown;
1244  else if( name == "improper-addressing" )
1246  else if( name == "internal-server-error" )
1248  else if( name == "invalid-from" )
1249  err = StreamErrorInvalidFrom;
1250  else if( name == "invalid-id" )
1251  err = StreamErrorInvalidId;
1252  else if( name == "invalid-namespace" )
1254  else if( name == "invalid-xml" )
1255  err = StreamErrorInvalidXml;
1256  else if( name == "not-authorized" )
1258  else if( name == "policy-violation" )
1260  else if( name == "remote-connection-failed" )
1262  else if( name == "resource-constraint" )
1264  else if( name == "restricted-xml" )
1266  else if( name == "see-other-host" )
1267  {
1269  m_streamErrorCData = tag->findChild( "see-other-host" )->cdata();
1270  }
1271  else if( name == "system-shutdown" )
1273  else if( name == "undefined-condition" )
1275  else if( name == "unsupported-encoding" )
1277  else if( name == "unsupported-stanza-type" )
1279  else if( name == "unsupported-version" )
1281  else if( name == "not-well-formed" )
1283  else if( name == "text" )
1284  {
1285  const std::string& lang = (*it)->findAttribute( "xml:lang" );
1286  if( !lang.empty() )
1287  m_streamErrorText[lang] = (*it)->cdata();
1288  else
1289  m_streamErrorText["default"] = (*it)->cdata();
1290  }
1291  else
1292  m_streamErrorAppCondition = (*it);
1293 
1294  if( err != StreamErrorUndefined && (*it)->hasAttribute( XMLNS, XMLNS_XMPP_STREAM ) )
1295  m_streamError = err;
1296  }
1297  }
1298 
1299  const std::string& ClientBase::streamErrorText( const std::string& lang ) const
1300  {
1301  StringMap::const_iterator it = m_streamErrorText.find( lang );
1302  return ( it != m_streamErrorText.end() ) ? (*it).second : EmptyString;
1303  }
1304 
1306  {
1307  if( types & Message::Chat || types == 0 )
1308  m_messageSessionHandlerChat = msh;
1309 
1310  if( types & Message::Normal || types == 0 )
1311  m_messageSessionHandlerNormal = msh;
1312 
1313  if( types & Message::Groupchat || types == 0 )
1314  m_messageSessionHandlerGroupchat = msh;
1315 
1316  if( types & Message::Headline || types == 0 )
1317  m_messageSessionHandlerHeadline = msh;
1318  }
1319 
1321  {
1322  if( ph )
1323  m_presenceHandlers.push_back( ph );
1324  }
1325 
1327  {
1328  if( ph )
1329  m_presenceHandlers.remove( ph );
1330  }
1331 
1333  {
1334  if( ph && jid )
1335  {
1336  JidPresHandlerStruct jph;
1337  jph.jid = new JID( jid.bare() );
1338  jph.ph = ph;
1339  m_presenceJidHandlers.push_back( jph );
1340  }
1341  }
1342 
1344  {
1345  PresenceJidHandlerList::iterator t;
1346  PresenceJidHandlerList::iterator it = m_presenceJidHandlers.begin();
1347  while( it != m_presenceJidHandlers.end() )
1348  {
1349  t = it;
1350  ++it;
1351  if( ( !ph || (*t).ph == ph ) && (*t).jid->bare() == jid.bare() )
1352  {
1353  delete (*t).jid;
1354  m_presenceJidHandlers.erase( t );
1355  }
1356  }
1357  }
1358 
1360  {
1361  IqTrackMap::iterator t;
1362  m_iqHandlerMapMutex.lock();
1363  IqTrackMap::iterator it = m_iqIDHandlers.begin();
1364  while( it != m_iqIDHandlers.end() )
1365  {
1366  t = it;
1367  ++it;
1368  if( ih == (*t).second.ih )
1369  m_iqIDHandlers.erase( t );
1370  }
1371  m_iqHandlerMapMutex.unlock();
1372  }
1373 
1374  void ClientBase::registerIqHandler( IqHandler* ih, int exttype )
1375  {
1376  if( !ih )
1377  return;
1378 
1379  util::MutexGuard m( m_iqExtHandlerMapMutex );
1380  typedef IqHandlerMap::const_iterator IQci;
1381  std::pair<IQci, IQci> g = m_iqExtHandlers.equal_range( exttype );
1382  for( IQci it = g.first; it != g.second; ++it )
1383  {
1384  if( (*it).second == ih )
1385  return;
1386  }
1387 
1388  m_iqExtHandlers.insert( std::make_pair( exttype, ih ) );
1389  }
1390 
1391  void ClientBase::removeIqHandler( IqHandler* ih, int exttype )
1392  {
1393  if( !ih )
1394  return;
1395 
1396  util::MutexGuard m( m_iqExtHandlerMapMutex );
1397  typedef IqHandlerMap::iterator IQi;
1398  std::pair<IQi, IQi> g = m_iqExtHandlers.equal_range( exttype );
1399  IQi it2;
1400  IQi it = g.first;
1401  while( it != g.second )
1402  {
1403  it2 = it++;
1404  if( (*it2).second == ih )
1405  m_iqExtHandlers.erase( it2 );
1406  }
1407  }
1408 
1410  {
1411  if( session )
1412  m_messageSessions.push_back( session );
1413  }
1414 
1416  {
1417  if( !session )
1418  return;
1419 
1420  MessageSessionList::iterator it = std::find( m_messageSessions.begin(),
1421  m_messageSessions.end(),
1422  session );
1423  if( it != m_messageSessions.end() )
1424  {
1425  delete (*it);
1426  m_messageSessions.erase( it );
1427  }
1428  }
1429 
1431  {
1432  if( mh )
1433  m_messageHandlers.push_back( mh );
1434  }
1435 
1437  {
1438  if( mh )
1439  m_messageHandlers.remove( mh );
1440  }
1441 
1443  {
1444  if( sh )
1445  m_subscriptionHandlers.push_back( sh );
1446  }
1447 
1449  {
1450  if( sh )
1451  m_subscriptionHandlers.remove( sh );
1452  }
1453 
1454  void ClientBase::registerTagHandler( TagHandler* th, const std::string& tag, const std::string& xmlns )
1455  {
1456  if( th && !tag.empty() )
1457  {
1458  TagHandlerStruct ths;
1459  ths.tag = tag;
1460  ths.xmlns = xmlns;
1461  ths.th = th;
1462  m_tagHandlers.push_back( ths );
1463  }
1464  }
1465 
1466  void ClientBase::removeTagHandler( TagHandler* th, const std::string& tag, const std::string& xmlns )
1467  {
1468  if( th )
1469  {
1470  for( TagHandlerList::iterator it = m_tagHandlers.begin(); it != m_tagHandlers.end(); )
1471  {
1472  if( (*it).th == th && (*it).tag == tag && (*it).xmlns == xmlns )
1473  {
1474  // Normally we'd just assign it to the return value of the .erase() call,
1475  // which is either the next element, or .end(). However,
1476  // it's only since C++11 that this works; C++03 version returns void.
1477  // So instead, we do a post-increment. this increments the iterator to point
1478  // to the next element, then passes a copy of the old iterator (that is to the item to be deleted)
1479  m_tagHandlers.erase( it++ );
1480  }
1481  else
1482  {
1483  ++it;
1484  }
1485  }
1486  }
1487  }
1488 
1490  {
1491  if( sh )
1492  m_statisticsHandler = sh;
1493  }
1494 
1496  {
1497  m_statisticsHandler = 0;
1498  }
1499 
1501  {
1502  if( mih )
1503  {
1504  m_mucInvitationHandler = mih;
1506  }
1507  }
1508 
1510  {
1511  m_mucInvitationHandler = 0;
1513  }
1514 
1516  {
1517  if( cl )
1518  m_connectionListeners.push_back( cl );
1519  }
1520 
1522  {
1523  if( cl )
1524  m_connectionListeners.remove( cl );
1525  }
1526 
1528  {
1529  util::ForEach( m_connectionListeners, &ConnectionListener::onConnect );
1530  }
1531 
1532  void ClientBase::notifyOnDisconnect( ConnectionError e )
1533  {
1534  util::ForEach( m_connectionListeners, &ConnectionListener::onDisconnect, e );
1535  init();
1536  }
1537 
1539  {
1540  ConnectionListenerList::const_iterator it = m_connectionListeners.begin();
1541  for( ; it != m_connectionListeners.end() && (*it)->onTLSConnect( info ); ++it )
1542  ;
1543  return m_stats.encryption = ( it == m_connectionListeners.end() );
1544  }
1545 
1547  {
1548  util::ForEach( m_connectionListeners, &ConnectionListener::onResourceBindError, error );
1549  }
1550 
1551  void ClientBase::notifyOnResourceBind( const std::string& resource )
1552  {
1553  util::ForEach( m_connectionListeners, &ConnectionListener::onResourceBind, resource );
1554  }
1555 
1557  {
1558  util::ForEach( m_connectionListeners, &ConnectionListener::onSessionCreateError, error );
1559  }
1560 
1562  {
1563  util::ForEach( m_connectionListeners, &ConnectionListener::onStreamEvent, event );
1564  }
1565 
1566  void ClientBase::notifyPresenceHandlers( Presence& pres )
1567  {
1568  bool match = false;
1569  PresenceJidHandlerList::const_iterator t;
1570  PresenceJidHandlerList::const_iterator itj = m_presenceJidHandlers.begin();
1571  while( itj != m_presenceJidHandlers.end() )
1572  {
1573  t = itj++;
1574  if( (*t).jid->bare() == pres.from().bare() && (*t).ph )
1575  {
1576  (*t).ph->handlePresence( pres );
1577  match = true;
1578  }
1579  }
1580  if( match )
1581  return;
1582 
1583  // FIXME remove this for() for 1.1:
1584  PresenceHandlerList::const_iterator it = m_presenceHandlers.begin();
1585  for( ; it != m_presenceHandlers.end(); ++it )
1586  {
1587  (*it)->handlePresence( pres );
1588  }
1589  // FIXME and reinstantiate this:
1590 // util::ForEach( m_presenceHandlers, &PresenceHandler::handlePresence, pres );
1591  }
1592 
1593  void ClientBase::notifySubscriptionHandlers( Subscription& s10n )
1594  {
1595  // FIXME remove this for() for 1.1:
1596  SubscriptionHandlerList::const_iterator it = m_subscriptionHandlers.begin();
1597  for( ; it != m_subscriptionHandlers.end(); ++it )
1598  {
1599  (*it)->handleSubscription( s10n );
1600  }
1601  // FIXME and reinstantiate this:
1602 // util::ForEach( m_subscriptionHandlers, &SubscriptionHandler::handleSubscription, s10n );
1603  }
1604 
1605  void ClientBase::notifyIqHandlers( IQ& iq )
1606  {
1607  m_iqHandlerMapMutex.lock();
1608  IqTrackMap::iterator it_id = m_iqIDHandlers.find( iq.id() );
1609  bool haveIdHandler = ( it_id != m_iqIDHandlers.end() );
1610  m_iqHandlerMapMutex.unlock();
1611  if( haveIdHandler && ( iq.subtype() == IQ::Result || iq.subtype() == IQ::Error ) )
1612  {
1613  (*it_id).second.ih->handleIqID( iq, (*it_id).second.context );
1614  if( (*it_id).second.del )
1615  delete (*it_id).second.ih;
1616  m_iqHandlerMapMutex.lock();
1617  m_iqIDHandlers.erase( it_id );
1618  m_iqHandlerMapMutex.unlock();
1619  return;
1620  }
1621 
1622  if( iq.extensions().empty() )
1623  {
1624  if ( iq.subtype() == IQ::Get || iq.subtype() == IQ::Set )
1625  {
1626  IQ re( IQ::Error, iq.from(), iq.id() );
1627  re.addExtension( new Error( StanzaErrorTypeCancel, StanzaErrorFeatureNotImplemented ) );
1628  send( re );
1629  }
1630  return;
1631  }
1632 
1633  bool handled = false;
1634 
1635  // FIXME remove for 1.1
1636 // typedef IqHandlerMapXmlns::const_iterator IQciXmlns
1637 // Tag *tag = iq.tag()->xmlns();
1638 // std::pair<IQciXmlns, IQciXmlns> g = m_iqNSHandlers.equal_range( tag->xmlns() );
1639 // for( IQciXmlns it = g.first; it != g.second; ++it )
1640 // {
1641 // if( (*it).second->handleIq( iq ) )
1642 // res = true;
1643 // }
1644 // delete tag;
1645 
1646  m_iqExtHandlerMapMutex.lock();
1647  typedef IqHandlerMap::const_iterator IQci;
1648  const StanzaExtensionList& sel = iq.extensions();
1649  StanzaExtensionList::const_iterator itse = sel.begin();
1650  for( ; !handled && itse != sel.end(); ++itse )
1651  {
1652  std::pair<IQci, IQci> g = m_iqExtHandlers.equal_range( (*itse)->extensionType() );
1653  for( IQci it = g.first; !handled && it != g.second; ++it )
1654  {
1655  if( (*it).second->handleIq( iq ) )
1656  handled = true;
1657  }
1658  }
1659  m_iqExtHandlerMapMutex.unlock();
1660 
1661  if( !handled && ( iq.subtype() == IQ::Get || iq.subtype() == IQ::Set ) )
1662  {
1663  IQ re( IQ::Error, iq.from(), iq.id() );
1664  re.addExtension( new Error( StanzaErrorTypeCancel, StanzaErrorServiceUnavailable ) );
1665  send( re );
1666  }
1667  }
1668 
1669  void ClientBase::notifyMessageHandlers( Message& msg )
1670  {
1671  if( m_mucInvitationHandler )
1672  {
1673  const MUCRoom::MUCUser* mu = msg.findExtension<MUCRoom::MUCUser>( ExtMUCUser );
1674  if( mu && mu->operation() == MUCRoom::OpInviteFrom )
1675  {
1676 
1677  m_mucInvitationHandler->handleMUCInvitation( msg.from(),
1678  mu->jid() ? JID( *(mu->jid()) ) : JID(),
1679  mu->reason() ? *(mu->reason()) : EmptyString,
1680  msg.body(),
1681  mu->password() ? *(mu->password()) : EmptyString,
1682  mu->continued(),
1683  mu->thread() ? *(mu->thread()) : EmptyString );
1684  return;
1685  }
1686  }
1687 
1688  MessageSessionList::const_iterator it1 = m_messageSessions.begin();
1689  for( ; it1 != m_messageSessions.end(); ++it1 )
1690  {
1691  if( (*it1)->target().full() == msg.from().full() &&
1692  ( msg.thread().empty()
1693  || (*it1)->threadID() == msg.thread()
1694  || !(*it1)->honorThreadID() ) &&
1695 // FIXME don't use '== 0' here
1696  ( (*it1)->types() & msg.subtype() || (*it1)->types() == 0 ) )
1697  {
1698  (*it1)->handleMessage( msg );
1699  return;
1700  }
1701  }
1702 
1703  it1 = m_messageSessions.begin();
1704  for( ; it1 != m_messageSessions.end(); ++it1 )
1705  {
1706  if( (*it1)->target().bare() == msg.from().bare() &&
1707  ( msg.thread().empty()
1708  || (*it1)->threadID() == msg.thread()
1709  || !(*it1)->honorThreadID() ) &&
1710 // FIXME don't use '== 0' here
1711  ( (*it1)->types() & msg.subtype() || (*it1)->types() == 0 ) )
1712  {
1713  (*it1)->handleMessage( msg );
1714  return;
1715  }
1716  }
1717 
1718  MessageSessionHandler* msHandler = 0;
1719 
1720  switch( msg.subtype() )
1721  {
1722  case Message::Chat:
1723  msHandler = m_messageSessionHandlerChat;
1724  break;
1725  case Message::Normal:
1726  msHandler = m_messageSessionHandlerNormal;
1727  break;
1728  case Message::Groupchat:
1729  msHandler = m_messageSessionHandlerGroupchat;
1730  break;
1731  case Message::Headline:
1732  msHandler = m_messageSessionHandlerHeadline;
1733  break;
1734  default:
1735  break;
1736  }
1737 
1738  if( msHandler )
1739  {
1740  MessageSession* session = new MessageSession( this, msg.from(), true, msg.subtype() );
1741  msHandler->handleMessageSession( session );
1742  session->handleMessage( msg );
1743  }
1744  else
1745  {
1746  // FIXME remove this for() for 1.1:
1747  MessageHandlerList::const_iterator it = m_messageHandlers.begin();
1748  for( ; it != m_messageHandlers.end(); ++it )
1749  {
1750  (*it)->handleMessage( msg );
1751  }
1752  // FIXME and reinstantiate this:
1753 // util::ForEach( m_messageHandlers, &MessageHandler::handleMessage, msg ); // FIXME remove for 1.1
1754  }
1755  }
1756 
1757  void ClientBase::notifyTagHandlers( Tag* tag )
1758  {
1759  TagHandlerList::const_iterator it = m_tagHandlers.begin();
1760  for( ; it != m_tagHandlers.end(); ++it )
1761  {
1762  if( (*it).tag == tag->name() && tag->hasAttribute( XMLNS, (*it).xmlns ) )
1763  (*it).th->handleTag( tag );
1764  }
1765  }
1766 
1768  {
1769  if( !se )
1770  return;
1771 
1773  m_presenceExtensions.push_back( se );
1774  }
1775 
1777  {
1778  StanzaExtensionList::iterator it = m_presenceExtensions.begin();
1779  for( ; it != m_presenceExtensions.end(); ++it )
1780  {
1781  if( (*it)->extensionType() == type )
1782  {
1783  delete (*it);
1784  m_presenceExtensions.erase( it );
1785  return true;
1786  }
1787  }
1788 
1789  return false;
1790  }
1791 
1793  {
1794  char cn[4*8+1];
1795  for( int i = 0; i < 4; ++i )
1796  sprintf( cn + i*8, "%08x", rand() );
1797  return std::string( cn, 4*8 );;
1798  }
1799 
1800  CompressionBase* ClientBase::getDefaultCompression()
1801  {
1802  if( !m_compress )
1803  return 0;
1804 
1805 #ifdef HAVE_ZLIB
1806  CompressionBase* cmp = new CompressionZlib( this );
1807  if( cmp->init() )
1808  return cmp;
1809 
1810  delete cmp;
1811 #endif
1812  return 0;
1813  }
1814 
1815  TLSBase* ClientBase::getDefaultEncryption()
1816  {
1817  if( m_tls == TLSDisabled || !hasTls() )
1818  return 0;
1819 
1820  TLSDefault* tls = new TLSDefault( this, m_server );
1821  if( tls->init( m_clientKey, m_clientCerts, m_cacerts ) )
1822  return tls;
1823  else
1824  {
1825  delete tls;
1826  return 0;
1827  }
1828  }
1829 
1830 }
const std::string getID()
virtual void handleEncryptedData(const TLSBase *base, const std::string &data)
Definition: clientbase.cpp:334
SMContext m_smContext
Definition: clientbase.h:920
void addPresenceExtension(StanzaExtension *se)
const std::string & server() const
Definition: clientbase.h:196
void processSASLError(Tag *tag)
Definition: clientbase.cpp:899
bool compression() const
Definition: clientbase.h:214
std::string m_sid
Definition: clientbase.h:890
std::string m_clientCerts
Definition: clientbase.h:883
void registerMessageSessionHandler(MessageSessionHandler *msh, int types=0)
std::string m_authcid
Definition: clientbase.h:870
void registerStatisticsHandler(StatisticsHandler *sh)
void setCompressionImpl(CompressionBase *cb)
virtual void handleDisconnect(const ConnectionBase *connection, ConnectionError reason)
Definition: clientbase.cpp:387
void registerPresenceHandler(PresenceHandler *ph)
virtual ~ClientBase()
Definition: clientbase.cpp:155
TLSPolicy tls() const
Definition: clientbase.h:208
void xmppPing(const JID &to, EventHandler *eh)
virtual void handleCompressedData(const std::string &data)
Definition: clientbase.cpp:319
bool removePresenceExtension(int type)
virtual ConnectionError recv(int timeout=-1)
Definition: clientbase.cpp:183
void checkQueue(int handled, bool resend)
void removeSubscriptionHandler(SubscriptionHandler *sh)
void registerConnectionListener(ConnectionListener *cl)
void processSASLChallenge(const std::string &challenge)
Definition: clientbase.cpp:707
virtual void handleTag(Tag *tag)
Definition: clientbase.cpp:221
TLSBase * m_encryption
Definition: clientbase.h:872
ConnectionState state() const
void registerMessageHandler(MessageHandler *mh)
const std::string & streamErrorText(const std::string &lang="default") const
StanzaExtensionList m_presenceExtensions
Definition: clientbase.h:877
virtual void handleConnect(const ConnectionBase *connection)
Definition: clientbase.cpp:382
virtual void handleReceivedData(const ConnectionBase *connection, const std::string &data)
Definition: clientbase.cpp:372
void removeIqHandler(IqHandler *ih, int exttype)
StatisticsStruct getStatistics()
bool processSASLSuccess(const std::string &payload)
Definition: clientbase.cpp:927
std::string m_xmllang
Definition: clientbase.h:887
virtual void handleDecompressedData(const std::string &data)
Definition: clientbase.cpp:329
bool m_compressionActive
Definition: clientbase.h:891
std::string m_clientKey
Definition: clientbase.h:884
void setClientCert(const std::string &clientKey, const std::string &clientCerts)
Definition: clientbase.cpp:479
const JID & jid()
Definition: clientbase.h:147
virtual void handleDecryptedData(const TLSBase *base, const std::string &data)
Definition: clientbase.cpp:342
void registerSubscriptionHandler(SubscriptionHandler *sh)
void removeStatisticsHandler()
void notifyOnSessionCreateError(const Error *error)
bool notifyOnTLSConnect(const CertInfo &info)
void removeIDHandler(IqHandler *ih)
ClientBase(const std::string &ns, const std::string &server, int port=-1)
Definition: clientbase.cpp:94
CompressionBase * m_compression
Definition: clientbase.h:873
virtual void disconnect(ConnectionError reason)
Definition: clientbase.cpp:404
virtual bool checkStreamVersion(const std::string &version)
std::string m_password
Definition: clientbase.h:886
void setEncryptionImpl(TLSBase *tb)
bool removeStanzaExtension(int ext)
bool connect(bool block=true)
Definition: clientbase.cpp:191
std::string m_server
Definition: clientbase.h:888
std::string getRandom()
void removeMUCInvitationHandler()
const TagList sendQueue()
LogSink & logInstance()
Definition: clientbase.h:599
void send(Tag *tag)
void setConnectionImpl(ConnectionBase *cb)
void disposeMessageSession(MessageSession *session)
void removeTagHandler(TagHandler *th, const std::string &tag, const std::string &xmlns)
void registerTagHandler(TagHandler *th, const std::string &tag, const std::string &xmlns)
std::string m_namespace
Definition: clientbase.h:885
void removeConnectionListener(ConnectionListener *cl)
TLSPolicy m_tls
Definition: clientbase.h:901
void notifyOnResourceBindError(const Error *error)
virtual const std::string & password() const
Definition: clientbase.h:227
void registerIqHandler(IqHandler *ih, int exttype)
virtual void handleHandshakeResult(const TLSBase *base, bool success, CertInfo &certinfo)
Definition: clientbase.cpp:350
void removeMessageHandler(MessageHandler *mh)
void registerMessageSession(MessageSession *session)
void setServer(const std::string &server)
Definition: clientbase.cpp:472
void startSASL(SaslMechanism type)
Definition: clientbase.cpp:485
void notifyStreamEvent(StreamEvent event)
void registerStanzaExtension(StanzaExtension *ext)
ConnectionBase * m_connection
Definition: clientbase.h:871
void registerMUCInvitationHandler(MUCInvitationHandler *mih)
void removePresenceHandler(PresenceHandler *ph)
void notifyOnResourceBind(const std::string &resource)
This is an abstract base class for stream compression implementations.
virtual void compress(const std::string &data)=0
virtual void cleanup()=0
virtual bool init()=0
virtual void decompress(const std::string &data)=0
An abstract base class for a connection.
virtual void cleanup()
ConnectionState state() const
virtual ConnectionError recv(int timeout=-1)=0
virtual bool send(const std::string &data)=0
virtual ConnectionError connect()=0
virtual ConnectionError receive()=0
virtual void getStatistics(long int &totalIn, long int &totalOut)=0
virtual void disconnect()=0
void setServer(const std::string &server, int port=-1)
Derived classes can be registered as ConnectionListeners with the Client.
virtual void onConnect()=0
virtual void onDisconnect(ConnectionError e)=0
virtual void onResourceBind(const std::string &resource)
virtual void onResourceBindError(const Error *error)
virtual void onStreamEvent(StreamEvent event)
virtual void onSessionCreateError(const Error *error)
This is an implementation of a simple TCP connection.
This class implements XEP-0030 (Service Discovery) and XEP-0092 (Software Version).
Definition: disco.h:46
void removeFeature(const std::string &feature)
Definition: disco.h:430
void addFeature(const std::string &feature)
Definition: disco.h:422
void setVersion(const std::string &name, const std::string &version, const std::string &os=EmptyString)
Definition: disco.cpp:467
A stanza error abstraction implemented as a StanzaExtension.
Definition: error.h:35
void registerEventHandler(EventHandler *eh, const std::string &context)
void dispatch(const Event &event, const std::string &context, bool remove)
An base class for event handlers.
Definition: eventhandler.h:29
A base class for events.
Definition: event.h:29
@ PingError
Definition: event.h:39
@ PingPong
Definition: event.h:38
@ PingPing
Definition: event.h:37
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
virtual Tag * tag() const
Definition: iq.cpp:48
A virtual interface which can be reimplemented to receive IQ stanzas.
Definition: iqhandler.h:32
An abstraction of a JID.
Definition: jid.h:31
const std::string & server() const
Definition: jid.h:104
const std::string & username() const
Definition: jid.h:98
const std::string & full() const
Definition: jid.h:61
const std::string & bare() const
Definition: jid.h:67
void dbg(LogArea area, const std::string &message) const
Definition: logsink.h:66
void err(LogArea area, const std::string &message) const
Definition: logsink.h:84
An MD5 implementation.
Definition: md5.h:82
void feed(const unsigned char *data, int bytes)
Definition: md5.cpp:378
void finalize()
Definition: md5.cpp:416
const std::string binary()
Definition: md5.cpp:449
const std::string hex()
Definition: md5.cpp:436
void reset()
Definition: md5.cpp:461
A handler that can be used to receive invitations to MUC rooms.
virtual void handleMUCInvitation(const JID &room, const JID &from, const std::string &reason, const std::string &body, const std::string &password, bool cont, const std::string &thread)=0
A virtual interface which can be reimplemented to receive incoming message stanzas.
A virtual interface which can be reimplemented to receive incoming message sessions.
An abstraction of a message session between any two entities.
An abstraction of a message stanza.
Definition: message.h:34
virtual Tag * tag() const
Definition: message.cpp:69
int feed(std::string &data)
Definition: parser.cpp:161
A virtual interface which can be reimplemented to receive presence stanzas.
An abstraction of a presence stanza.
Definition: presence.h:33
virtual Tag * tag() const
Definition: presence.cpp:108
An implementation of SHA1.
Definition: sha.h:30
void feed(const unsigned char *data, unsigned length)
Definition: sha.cpp:89
const std::string binary()
Definition: sha.cpp:68
const std::string hex()
Definition: sha.cpp:53
void reset()
Definition: sha.cpp:48
A Factory that creates StanzaExtensions from Tags.
void registerExtension(StanzaExtension *ext)
void addExtensions(Stanza &stanza, Tag *tag)
This class abstracts a stanza extension, which is usually an XML child element in a specific namespac...
void addExtension(const StanzaExtension *se)
Definition: stanza.cpp:52
Stanza * embeddedStanza() const
Definition: stanza.cpp:69
Tag * embeddedTag() const
Definition: stanza.cpp:76
bool hasEmbeddedStanza() const
Definition: stanza.h:135
const std::string & id() const
Definition: stanza.h:63
const JID & from() const
Definition: stanza.h:51
const StanzaExtension * findExtension(int type) const
Definition: stanza.cpp:57
A virtual interface which can be reimplemented to receive connection statistics.
virtual void handleStatistics(const StatisticsStruct stats)=0
A virtual interface which can be reimplemented to receive incoming subscription stanzas.
An abstraction of a subscription stanza.
Definition: subscription.h:32
virtual Tag * tag() const
An abstract base class for TLS implementations.
Definition: tlsbase.h:32
virtual bool encrypt(const std::string &data)=0
virtual int decrypt(const std::string &data)=0
virtual const std::string channelBinding() const
Definition: tlsbase.h:117
virtual void cleanup()=0
A virtual interface which can be reimplemented to receive non-XMPP Core stanzas.
Definition: taghandler.h:33
This is an abstraction of an XML element.
Definition: tag.h:47
Tag * findChild(const std::string &name) const
Definition: tag.cpp:624
bool setCData(const std::string &cdata)
Definition: tag.cpp:447
const std::string xmlns() const
Definition: tag.cpp:543
bool addAttribute(Attribute *attr)
Definition: tag.cpp:354
bool hasChild(const std::string &name, const std::string &attr=EmptyString, const std::string &value=EmptyString) const
Definition: tag.cpp:615
void addChild(Tag *child)
Definition: tag.cpp:424
bool hasAttribute(const std::string &name, const std::string &value=EmptyString) const
Definition: tag.cpp:602
const std::string cdata() const
Definition: tag.cpp:497
const std::string & findAttribute(const std::string &name) const
Definition: tag.cpp:589
const std::string & name() const
Definition: tag.h:394
const std::string xml() const
Definition: tag.cpp:302
const TagList & children() const
Definition: tag.cpp:510
A simple implementation of a mutex guard.
Definition: mutexguard.h:32
const std::string decode64(const std::string &input)
Definition: base64.cpp:83
const std::string encode64(const std::string &input)
Definition: base64.cpp:38
bool saslprep(const std::string &input, std::string &out)
Definition: prep.cpp:95
void clearMap(std::map< Key, T * > &M)
Definition: util.h:169
void ForEach(T &t, F f)
Definition: util.h:96
void clearList(std::list< T * > &L)
Definition: util.h:152
The namespace for the gloox library.
Definition: adhoc.cpp:28
const std::string XMLNS_STREAM
Definition: gloox.cpp:84
std::list< Tag * > TagList
Definition: tag.h:26
const std::string GLOOX_VERSION
Definition: gloox.cpp:119
const std::string XMLNS_XMPP_PING
Definition: gloox.cpp:62
const std::string XMLNS_XMPP_STREAM
Definition: gloox.cpp:85
ConnectionError
Definition: gloox.h:684
@ ConnParseError
Definition: gloox.h:697
@ ConnNotConnected
Definition: gloox.h:715
@ ConnTlsFailed
Definition: gloox.h:705
@ ConnNoError
Definition: gloox.h:685
@ ConnStreamVersionError
Definition: gloox.h:688
@ ConnStreamClosed
Definition: gloox.h:689
@ ConnStreamError
Definition: gloox.h:686
std::list< const StanzaExtension * > StanzaExtensionList
Definition: gloox.h:1268
@ LogAreaXmlIncoming
Definition: gloox.h:1070
@ LogAreaXmlOutgoing
Definition: gloox.h:1071
@ LogAreaClassClientbase
Definition: gloox.h:1057
const std::string XMPP_STREAM_VERSION_MAJOR
Definition: gloox.cpp:117
@ SaslInvalidMechanism
Definition: gloox.h:1026
@ SaslMalformedRequest
Definition: gloox.h:1029
@ SaslIncorrectEncoding
Definition: gloox.h:1016
@ SaslMechanismTooWeak
Definition: gloox.h:1033
@ SaslTemporaryAuthFailure
Definition: gloox.h:1041
@ SaslAborted
Definition: gloox.h:1013
@ AuthErrorUndefined
Definition: gloox.h:1012
@ SaslNotAuthorized
Definition: gloox.h:1037
@ SaslInvalidAuthzid
Definition: gloox.h:1021
const std::string XMLNS_CLIENT
Definition: gloox.cpp:19
StreamEvent
Definition: gloox.h:653
const std::string XMLNS_STREAM_SASL
Definition: gloox.cpp:89
const std::string XMPP_STREAM_VERSION_MINOR
Definition: gloox.cpp:118
@ TLSOptional
Definition: gloox.h:724
@ TLSDisabled
Definition: gloox.h:723
const std::string EmptyString
Definition: gloox.cpp:124
const std::string XMLNS
Definition: gloox.cpp:122
const std::string TYPE
Definition: gloox.cpp:123
@ StanzaErrorServiceUnavailable
Definition: gloox.h:936
@ StanzaErrorFeatureNotImplemented
Definition: gloox.h:881
StreamError
Definition: gloox.h:775
@ StreamErrorBadNamespacePrefix
Definition: gloox.h:782
@ StreamErrorInvalidId
Definition: gloox.h:805
@ StreamErrorConflict
Definition: gloox.h:785
@ StreamErrorPolicyViolation
Definition: gloox.h:817
@ StreamErrorInvalidFrom
Definition: gloox.h:801
@ StreamErrorSeeOtherHost
Definition: gloox.h:827
@ StreamErrorRemoteConnectionFailed
Definition: gloox.h:820
@ StreamErrorRestrictedXml
Definition: gloox.h:824
@ StreamErrorUndefined
Definition: gloox.h:848
@ StreamErrorBadFormat
Definition: gloox.h:776
@ StreamErrorImproperAddressing
Definition: gloox.h:796
@ StreamErrorInvalidNamespace
Definition: gloox.h:807
@ StreamErrorResourceConstraint
Definition: gloox.h:822
@ StreamErrorInternalServerError
Definition: gloox.h:798
@ StreamErrorUnsupportedEncoding
Definition: gloox.h:837
@ StreamErrorUnsupportedStanzaType
Definition: gloox.h:840
@ StreamErrorSystemShutdown
Definition: gloox.h:832
@ StreamErrorUnsupportedVersion
Definition: gloox.h:842
@ StreamErrorConnectionTimeout
Definition: gloox.h:788
@ StreamErrorNotAuthorized
Definition: gloox.h:813
@ StreamErrorXmlNotWellFormed
Definition: gloox.h:846
@ StreamErrorUndefinedCondition
Definition: gloox.h:834
@ StreamErrorHostUnknown
Definition: gloox.h:793
@ StreamErrorHostGone
Definition: gloox.h:790
@ StreamErrorInvalidXml
Definition: gloox.h:811
@ StanzaErrorTypeCancel
Definition: gloox.h:859
SaslMechanism
Definition: gloox.h:757
@ SaslMechScramSha1Plus
Definition: gloox.h:760
@ SaslMechNTLM
Definition: gloox.h:767
@ SaslMechDigestMd5
Definition: gloox.h:761
@ SaslMechAll
Definition: gloox.h:768
@ SaslMechExternal
Definition: gloox.h:765
@ SaslMechGssapi
Definition: gloox.h:766
@ SaslMechScramSha1
Definition: gloox.h:759
@ SaslMechNone
Definition: gloox.h:758
@ SaslMechAnonymous
Definition: gloox.h:763
@ SaslMechPlain
Definition: gloox.h:762
ConnectionState
Definition: gloox.h:641
@ StateDisconnected
Definition: gloox.h:642
@ StateConnected
Definition: gloox.h:644
@ StateConnecting
Definition: gloox.h:643
const std::string XMLNS_STREAM_TLS
Definition: gloox.cpp:87
const std::string XMLNS_MUC
Definition: gloox.cpp:67