00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "config.h"
00016
00017 #include "clientbase.h"
00018 #include "connectionbase.h"
00019 #include "tlsbase.h"
00020 #include "compressionbase.h"
00021 #include "connectiontcpclient.h"
00022 #include "disco.h"
00023 #include "messagesessionhandler.h"
00024 #include "tag.h"
00025 #include "iq.h"
00026 #include "message.h"
00027 #include "subscription.h"
00028 #include "presence.h"
00029 #include "connectionlistener.h"
00030 #include "iqhandler.h"
00031 #include "messagehandler.h"
00032 #include "presencehandler.h"
00033 #include "rosterlistener.h"
00034 #include "subscriptionhandler.h"
00035 #include "loghandler.h"
00036 #include "taghandler.h"
00037 #include "mucinvitationhandler.h"
00038 #include "mucroom.h"
00039 #include "jid.h"
00040 #include "base64.h"
00041 #include "error.h"
00042 #include "md5.h"
00043 #include "util.h"
00044 #include "tlsdefault.h"
00045 #include "compressionzlib.h"
00046 #include "stanzaextensionfactory.h"
00047 #include "eventhandler.h"
00048 #include "event.h"
00049
00050 #include <cstdlib>
00051 #include <string>
00052 #include <map>
00053 #include <list>
00054 #include <algorithm>
00055 #include <cmath>
00056 #include <ctime>
00057 #include <cstdio>
00058
00059 #include <string.h>
00060
00061 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
00062 #include <tchar.h>
00063 #endif
00064
00065 namespace gloox
00066 {
00067
00068
00069 ClientBase::Ping::Ping()
00070 : StanzaExtension( ExtPing )
00071 {
00072 }
00073
00074 ClientBase::Ping::~Ping()
00075 {
00076 }
00077
00078 const std::string& ClientBase::Ping::filterString() const
00079 {
00080 static const std::string filter = "/iq/ping[@xmlns='" + XMLNS_XMPP_PING + "']";
00081 return filter;
00082 }
00083
00084
00085
00086 ClientBase::ClientBase( const std::string& ns, const std::string& server, int port )
00087 : m_connection( 0 ), m_encryption( 0 ), m_compression( 0 ), m_disco( 0 ), m_namespace( ns ),
00088 m_xmllang( "en" ), m_server( server ), m_compressionActive( false ), m_encryptionActive( false ),
00089 m_compress( true ), m_authed( false ), m_block( false ), m_sasl( true ), m_tls( TLSOptional ), m_port( port ),
00090 m_availableSaslMechs( SaslMechAll ),
00091 m_statisticsHandler( 0 ), m_mucInvitationHandler( 0 ),
00092 m_messageSessionHandlerChat( 0 ), m_messageSessionHandlerGroupchat( 0 ),
00093 m_messageSessionHandlerHeadline( 0 ), m_messageSessionHandlerNormal( 0 ),
00094 m_parser( this ), m_seFactory( 0 ), m_authError( AuthErrorUndefined ),
00095 m_streamError( StreamErrorUndefined ), m_streamErrorAppCondition( 0 ),
00096 m_selectedSaslMech( SaslMechNone ), m_autoMessageSession( false )
00097 {
00098 init();
00099 }
00100
00101 ClientBase::ClientBase( const std::string& ns, const std::string& password,
00102 const std::string& server, int port )
00103 : m_connection( 0 ), m_encryption( 0 ), m_compression( 0 ), m_disco( 0 ), m_namespace( ns ),
00104 m_password( password ),
00105 m_xmllang( "en" ), m_server( server ), m_compressionActive( false ), m_encryptionActive( false ),
00106 m_compress( true ), m_authed( false ), m_block( false ), m_sasl( true ), m_tls( TLSOptional ),
00107 m_port( port ), m_availableSaslMechs( SaslMechAll ),
00108 m_statisticsHandler( 0 ), m_mucInvitationHandler( 0 ),
00109 m_messageSessionHandlerChat( 0 ), m_messageSessionHandlerGroupchat( 0 ),
00110 m_messageSessionHandlerHeadline( 0 ), m_messageSessionHandlerNormal( 0 ),
00111 m_parser( this ), m_seFactory( 0 ), m_authError( AuthErrorUndefined ),
00112 m_streamError( StreamErrorUndefined ), m_streamErrorAppCondition( 0 ),
00113 m_selectedSaslMech( SaslMechNone ), m_autoMessageSession( false )
00114 {
00115 init();
00116 }
00117
00118 void ClientBase::init()
00119 {
00120 if( !m_disco )
00121 {
00122 m_disco = new Disco( this );
00123 m_disco->setVersion( "based on gloox", GLOOX_VERSION );
00124 m_disco->addFeature( XMLNS_XMPP_PING );
00125 }
00126
00127 registerStanzaExtension( new Error() );
00128 registerStanzaExtension( new Ping() );
00129 registerIqHandler( this, ExtPing );
00130
00131 m_streamError = StreamErrorUndefined;
00132 m_block = false;
00133 memset( &m_stats, 0, sizeof( m_stats ) );
00134 cleanup();
00135 }
00136
00137 ClientBase::~ClientBase()
00138 {
00139 delete m_connection;
00140 delete m_encryption;
00141 delete m_compression;
00142 delete m_seFactory;
00143 m_seFactory = 0;
00144 delete m_disco;
00145 m_disco = 0;
00146
00147 util::clearList( m_messageSessions );
00148
00149 PresenceJidHandlerList::const_iterator it1 = m_presenceJidHandlers.begin();
00150 for( ; it1 != m_presenceJidHandlers.end(); ++it1 )
00151 delete (*it1).jid;
00152 }
00153
00154 ConnectionError ClientBase::recv( int timeout )
00155 {
00156 if( !m_connection || m_connection->state() == StateDisconnected )
00157 return ConnNotConnected;
00158
00159 return m_connection->recv( timeout );
00160 }
00161
00162 bool ClientBase::connect( bool block )
00163 {
00164 if( m_server.empty() )
00165 return false;
00166
00167 if( !m_connection )
00168 m_connection = new ConnectionTCPClient( this, m_logInstance, m_server, m_port );
00169
00170 if( m_connection->state() >= StateConnecting )
00171 return true;
00172
00173 if( !m_encryption )
00174 m_encryption = getDefaultEncryption();
00175
00176 if( !m_compression )
00177 m_compression = getDefaultCompression();
00178
00179 m_logInstance.dbg( LogAreaClassClientbase, "This is gloox " + GLOOX_VERSION + ", connecting to "
00180 + m_server + ":" + util::int2string( m_port ) + "..." );
00181 m_block = block;
00182 ConnectionError ret = m_connection->connect();
00183 if( ret != ConnNoError )
00184 return false;
00185
00186 if( m_block )
00187 m_connection->receive();
00188
00189 return true;
00190 }
00191
00192 void ClientBase::handleTag( Tag* tag )
00193 {
00194 if( !tag )
00195 {
00196 logInstance().dbg( LogAreaClassClientbase, "stream closed" );
00197 disconnect( ConnStreamClosed );
00198 return;
00199 }
00200
00201 logInstance().dbg( LogAreaXmlIncoming, tag->xml() );
00202 ++m_stats.totalStanzasReceived;
00203
00204 if( tag->name() == "stream" && tag->xmlns() == XMLNS_STREAM )
00205 {
00206 const std::string& version = tag->findAttribute( "version" );
00207 if( !checkStreamVersion( version ) )
00208 {
00209 logInstance().dbg( LogAreaClassClientbase, "This server is not XMPP-compliant"
00210 " (it does not send a 'version' attribute). Please fix it or try another one.\n" );
00211 disconnect( ConnStreamVersionError );
00212 return;
00213 }
00214
00215 m_sid = tag->findAttribute( "id" );
00216 handleStartNode();
00217 }
00218 else if( tag->name() == "error" && tag->xmlns() == XMLNS_STREAM )
00219 {
00220 handleStreamError( tag );
00221 disconnect( ConnStreamError );
00222 }
00223 else
00224 {
00225 if( !handleNormalNode( tag ) )
00226 {
00227 if( tag->xmlns().empty() || tag->xmlns() == XMLNS_CLIENT )
00228 {
00229 if( tag->name() == "iq" )
00230 {
00231 IQ iq( tag );
00232 m_seFactory->addExtensions( iq, tag );
00233 notifyIqHandlers( iq );
00234 ++m_stats.iqStanzasReceived;
00235 }
00236 else if( tag->name() == "message" )
00237 {
00238 Message msg( tag );
00239 m_seFactory->addExtensions( msg, tag );
00240 notifyMessageHandlers( msg );
00241 ++m_stats.messageStanzasReceived;
00242 }
00243 else if( tag->name() == "presence" )
00244 {
00245 const std::string& type = tag->findAttribute( TYPE );
00246 if( type == "subscribe" || type == "unsubscribe"
00247 || type == "subscribed" || type == "unsubscribed" )
00248 {
00249 Subscription sub( tag );
00250 m_seFactory->addExtensions( sub, tag );
00251 notifySubscriptionHandlers( sub );
00252 ++m_stats.s10nStanzasReceived;
00253 }
00254 else
00255 {
00256 Presence pres( tag );
00257 m_seFactory->addExtensions( pres, tag );
00258 notifyPresenceHandlers( pres );
00259 ++m_stats.presenceStanzasReceived;
00260 }
00261 }
00262 else
00263 m_logInstance.err( LogAreaClassClientbase, "Received invalid stanza." );
00264 }
00265 else
00266 {
00267 notifyTagHandlers( tag );
00268 }
00269 }
00270 }
00271
00272 if( m_statisticsHandler )
00273 m_statisticsHandler->handleStatistics( getStatistics() );
00274 }
00275
00276 void ClientBase::handleCompressedData( const std::string& data )
00277 {
00278 if( m_encryption && m_encryptionActive )
00279 m_encryption->encrypt( data );
00280 else if( m_connection )
00281 m_connection->send( data );
00282 else
00283 m_logInstance.err( LogAreaClassClientbase, "Compression finished, but chain broken" );
00284 }
00285
00286 void ClientBase::handleDecompressedData( const std::string& data )
00287 {
00288 parse( data );
00289 }
00290
00291 void ClientBase::handleEncryptedData( const TLSBase* , const std::string& data )
00292 {
00293 if( m_connection )
00294 m_connection->send( data );
00295 else
00296 m_logInstance.err( LogAreaClassClientbase, "Encryption finished, but chain broken" );
00297 }
00298
00299 void ClientBase::handleDecryptedData( const TLSBase* , const std::string& data )
00300 {
00301 if( m_compression && m_compressionActive )
00302 m_compression->decompress( data );
00303 else
00304 parse( data );
00305 }
00306
00307 void ClientBase::handleHandshakeResult( const TLSBase* , bool success, CertInfo &certinfo )
00308 {
00309 if( success )
00310 {
00311 if( !notifyOnTLSConnect( certinfo ) )
00312 {
00313 logInstance().err( LogAreaClassClientbase, "Server's certificate rejected!" );
00314 disconnect( ConnTlsFailed );
00315 }
00316 else
00317 {
00318 logInstance().dbg( LogAreaClassClientbase, "connection encryption active" );
00319 header();
00320 }
00321 }
00322 else
00323 {
00324 logInstance().err( LogAreaClassClientbase, "TLS handshake failed!" );
00325 disconnect( ConnTlsFailed );
00326 }
00327 }
00328
00329 void ClientBase::handleReceivedData( const ConnectionBase* , const std::string& data )
00330 {
00331 if( m_encryption && m_encryptionActive )
00332 m_encryption->decrypt( data );
00333 else if( m_compression && m_compressionActive )
00334 m_compression->decompress( data );
00335 else
00336 parse( data );
00337 }
00338
00339 void ClientBase::handleConnect( const ConnectionBase* )
00340 {
00341 header();
00342 }
00343
00344 void ClientBase::handleDisconnect( const ConnectionBase* , ConnectionError reason )
00345 {
00346 if( m_connection )
00347 m_connection->cleanup();
00348
00349 if( m_encryption )
00350 m_encryption->cleanup();
00351
00352 if( m_compression )
00353 m_compression->cleanup();
00354
00355 m_encryptionActive = false;
00356 m_compressionActive = false;
00357
00358 notifyOnDisconnect( reason );
00359 }
00360
00361 void ClientBase::disconnect( ConnectionError reason )
00362 {
00363 if( !m_connection || m_connection->state() < StateConnecting )
00364 return;
00365
00366 if( reason != ConnTlsFailed )
00367 send( "</stream:stream>" );
00368
00369 m_connection->disconnect();
00370 m_connection->cleanup();
00371
00372 if( m_encryption )
00373 m_encryption->cleanup();
00374
00375 if( m_compression )
00376 m_compression->cleanup();
00377
00378 m_encryptionActive = false;
00379 m_compressionActive = false;
00380
00381 notifyOnDisconnect( reason );
00382 }
00383
00384 void ClientBase::parse( const std::string& data )
00385 {
00386 std::string copy = data;
00387 int i = 0;
00388 if( ( i = m_parser.feed( copy ) ) >= 0 )
00389 {
00390 std::string error = "parse error (at pos ";
00391 error += util::int2string( i );
00392 error += "): ";
00393 m_logInstance.err( LogAreaClassClientbase, error + copy );
00394 Tag* e = new Tag( "stream:error" );
00395 new Tag( e, "restricted-xml", "xmlns", XMLNS_XMPP_STREAM );
00396 send( e );
00397 disconnect( ConnParseError );
00398 }
00399 }
00400
00401 void ClientBase::header()
00402 {
00403 std::string head = "<?xml version='1.0' ?>";
00404 head += "<stream:stream to='" + m_jid.server() + "' xmlns='" + m_namespace + "' ";
00405 head += "xmlns:stream='http://etherx.jabber.org/streams' xml:lang='" + m_xmllang + "' ";
00406 head += "version='" + XMPP_STREAM_VERSION_MAJOR + "." + XMPP_STREAM_VERSION_MINOR + "'>";
00407 send( head );
00408 }
00409
00410 bool ClientBase::hasTls()
00411 {
00412 #if defined( HAVE_GNUTLS ) || defined( HAVE_OPENSSL ) || defined( HAVE_WINTLS )
00413 return true;
00414 #else
00415 return false;
00416 #endif
00417 }
00418
00419 void ClientBase::startTls()
00420 {
00421 send( new Tag( "starttls", XMLNS, XMLNS_STREAM_TLS ) );
00422 }
00423
00424 void ClientBase::setServer( const std::string &server )
00425 {
00426 m_server = server;
00427 if( m_connection )
00428 m_connection->setServer( server );
00429 }
00430
00431 void ClientBase::setClientCert( const std::string& clientKey, const std::string& clientCerts )
00432 {
00433 m_clientKey = clientKey;
00434 m_clientCerts = clientCerts;
00435 }
00436
00437 void ClientBase::startSASL( SaslMechanism type )
00438 {
00439 m_selectedSaslMech = type;
00440
00441 Tag* a = new Tag( "auth", XMLNS, XMLNS_STREAM_SASL );
00442
00443 switch( type )
00444 {
00445 case SaslMechDigestMd5:
00446 a->addAttribute( "mechanism", "DIGEST-MD5" );
00447 break;
00448 case SaslMechPlain:
00449 {
00450 a->addAttribute( "mechanism", "PLAIN" );
00451
00452 std::string tmp;
00453 if( m_authzid )
00454 tmp += m_authzid.bare();
00455
00456 tmp += '\0';
00457 if( !m_authcid.empty() )
00458 tmp += m_authcid;
00459 else
00460 tmp += m_jid.username();
00461 tmp += '\0';
00462 tmp += m_password;
00463 a->setCData( Base64::encode64( tmp ) );
00464 break;
00465 }
00466 case SaslMechAnonymous:
00467 a->addAttribute( "mechanism", "ANONYMOUS" );
00468 break;
00469 case SaslMechExternal:
00470 a->addAttribute( "mechanism", "EXTERNAL" );
00471 a->setCData( Base64::encode64( m_authzid ? m_authzid.bare() : m_jid.bare() ) );
00472 break;
00473 case SaslMechGssapi:
00474 {
00475 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
00476 a->addAttribute( "mechanism", "GSSAPI" );
00477
00478
00479
00480
00481
00482
00483
00484
00485 std::string token;
00486 a->setCData( Base64::encode64( token ) );
00487
00488 #else
00489 logInstance().err( LogAreaClassClientbase,
00490 "SASL GSSAPI is not supported on this platform. You should never see this." );
00491 #endif
00492 break;
00493 }
00494 case SaslMechNTLM:
00495 {
00496 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
00497 a->addAttribute( "mechanism", "NTLM" );
00498 SEC_WINNT_AUTH_IDENTITY identity, *ident = 0;
00499 memset( &identity, 0, sizeof( identity ) );
00500 if( m_jid.username().length() > 0 )
00501 {
00502 identity.User = (unsigned char*)m_jid.username().c_str();
00503 identity.UserLength = (unsigned long)m_jid.username().length();
00504 identity.Domain = (unsigned char*)m_ntlmDomain.c_str();
00505 identity.DomainLength = (unsigned long)m_ntlmDomain.length();
00506 identity.Password = (unsigned char*)m_password.c_str();
00507 identity.PasswordLength = (unsigned long)m_password.length();
00508 identity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
00509 ident = &identity;
00510 }
00511 AcquireCredentialsHandle( 0, _T( "NTLM" ), SECPKG_CRED_OUTBOUND, 0, ident, 0, 0, &m_credHandle, 0 );
00512 #else
00513 logInstance().err( LogAreaClassClientbase,
00514 "SASL NTLM is not supported on this platform. You should never see this." );
00515 #endif
00516 break;
00517 }
00518 default:
00519 break;
00520 }
00521
00522 send( a );
00523 }
00524
00525 void ClientBase::processSASLChallenge( const std::string& challenge )
00526 {
00527 Tag* t = new Tag( "response", XMLNS, XMLNS_STREAM_SASL );
00528
00529 const std::string& decoded = Base64::decode64( challenge );
00530
00531 switch( m_selectedSaslMech )
00532 {
00533 case SaslMechDigestMd5:
00534 {
00535 if( !decoded.compare( 0, 7, "rspauth" ) )
00536 break;
00537
00538 std::string realm;
00539 std::string::size_type end = 0;
00540 std::string::size_type pos = decoded.find( "realm=" );
00541 if( pos != std::string::npos )
00542 {
00543 end = decoded.find( '"', pos + 7 );
00544 realm = decoded.substr( pos + 7, end - ( pos + 7 ) );
00545 }
00546 else
00547 realm = m_jid.server();
00548
00549 pos = decoded.find( "nonce=" );
00550 if( pos == std::string::npos )
00551 return;
00552
00553 end = decoded.find( '"', pos + 7 );
00554 while( decoded[end-1] == '\\' )
00555 end = decoded.find( '"', end + 1 );
00556 std::string nonce = decoded.substr( pos + 7, end - ( pos + 7 ) );
00557
00558 std::string cnonce;
00559 char cn[4*8+1];
00560 for( int i = 0; i < 4; ++i )
00561 sprintf( cn + i*8, "%08x", rand() );
00562 cnonce.assign( cn, 4*8 );
00563
00564 MD5 md5;
00565 md5.feed( m_jid.username() );
00566 md5.feed( ":" );
00567 md5.feed( realm );
00568 md5.feed( ":" );
00569 md5.feed( m_password );
00570 md5.finalize();
00571 const std::string& a1_h = md5.binary();
00572 md5.reset();
00573 md5.feed( a1_h );
00574 md5.feed( ":" );
00575 md5.feed( nonce );
00576 md5.feed( ":" );
00577 md5.feed( cnonce );
00578 md5.finalize();
00579 const std::string& a1 = md5.hex();
00580 md5.reset();
00581 md5.feed( "AUTHENTICATE:xmpp/" );
00582 md5.feed( m_jid.server() );
00583 md5.finalize();
00584 const std::string& a2 = md5.hex();
00585 md5.reset();
00586 md5.feed( a1 );
00587 md5.feed( ":" );
00588 md5.feed( nonce );
00589 md5.feed( ":00000001:" );
00590 md5.feed( cnonce );
00591 md5.feed( ":auth:" );
00592 md5.feed( a2 );
00593 md5.finalize();
00594
00595 std::string response = "username=\"";
00596 response += m_jid.username();
00597 response += "\",realm=\"";
00598 response += realm;
00599 response += "\",nonce=\"";
00600 response += nonce;
00601 response += "\",cnonce=\"";
00602 response += cnonce;
00603 response += "\",nc=00000001,qop=auth,digest-uri=\"xmpp/";
00604 response += m_jid.server();
00605 response += "\",response=";
00606 response += md5.hex();
00607 response += ",charset=utf-8";
00608
00609 if( m_authzid )
00610 response += ",authzid=" + m_authzid.bare();
00611
00612 t->setCData( Base64::encode64( response ) );
00613
00614 break;
00615 }
00616 case SaslMechGssapi:
00617 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
00618
00619 #else
00620 m_logInstance.err( LogAreaClassClientbase,
00621 "Huh, received GSSAPI challenge?! This should have never happened!" );
00622 #endif
00623 break;
00624 case SaslMechNTLM:
00625 {
00626 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
00627 bool type1 = ( decoded.length() < 7 ) ? true : false;
00628
00629 SecBuffer bufferIn = { type1 ? 0 : (unsigned long)decoded.length(),
00630 SECBUFFER_TOKEN,
00631 (void*)decoded.c_str() };
00632 SecBufferDesc secIn = { 0, 1, &bufferIn };
00633
00634 char buffer[4096];
00635
00636 SecBuffer bufferOut = { sizeof( buffer ), SECBUFFER_TOKEN, buffer };
00637 SecBufferDesc secOut = { 0, 1, &bufferOut };
00638
00639 TimeStamp timestamp;
00640 unsigned long contextAttr;
00641
00642 SECURITY_STATUS status = InitializeSecurityContext( &m_credHandle, type1 ? 0 : &m_ctxtHandle,
00643 0, ISC_REQ_MUTUAL_AUTH, 0, 0, &secIn, 0,
00644 &m_ctxtHandle, &secOut, &contextAttr,
00645 ×tamp );
00646 std::string response;
00647 if( SUCCEEDED( status ) )
00648 {
00649 response = std::string( (const char *)bufferOut.pvBuffer, bufferOut.cbBuffer );
00650 }
00651 else
00652 {
00653 logInstance().err( LogAreaClassClientbase,
00654 "InitializeSecurityContext() failed, return value "
00655 + util::int2string( status ) );
00656 }
00657
00658 t->setCData( Base64::encode64( response ) );
00659 #else
00660 m_logInstance.err( LogAreaClassClientbase,
00661 "Huh, received NTLM challenge?! This should have never happened!" );
00662 #endif
00663 break;
00664 }
00665
00666 default:
00667
00668 break;
00669 }
00670
00671 send( t );
00672 }
00673
00674 void ClientBase::processSASLError( Tag* tag )
00675 {
00676 if( tag->hasChild( "aborted" ) )
00677 m_authError = SaslAborted;
00678 else if( tag->hasChild( "incorrect-encoding" ) )
00679 m_authError = SaslIncorrectEncoding;
00680 else if( tag->hasChild( "invalid-authzid" ) )
00681 m_authError = SaslInvalidAuthzid;
00682 else if( tag->hasChild( "invalid-mechanism" ) )
00683 m_authError = SaslInvalidMechanism;
00684 else if( tag->hasChild( "malformed-request" ) )
00685 m_authError = SaslMalformedRequest;
00686 else if( tag->hasChild( "mechanism-too-weak" ) )
00687 m_authError = SaslMechanismTooWeak;
00688 else if( tag->hasChild( "not-authorized" ) )
00689 m_authError = SaslNotAuthorized;
00690 else if( tag->hasChild( "temporary-auth-failure" ) )
00691 m_authError = SaslTemporaryAuthFailure;
00692
00693 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
00694 if( m_selectedSaslMech == SaslMechNTLM )
00695 {
00696 FreeCredentialsHandle( &m_credHandle );
00697 DeleteSecurityContext( &m_ctxtHandle );
00698 }
00699 #endif
00700 }
00701
00702 void ClientBase::processSASLSuccess()
00703 {
00704 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
00705 if( m_selectedSaslMech == SaslMechNTLM )
00706 {
00707 FreeCredentialsHandle( &m_credHandle );
00708 DeleteSecurityContext( &m_ctxtHandle );
00709 }
00710 #endif
00711 }
00712
00713 void ClientBase::send( IQ& iq, IqHandler* ih, int context, bool del )
00714 {
00715 if( ih && ( iq.subtype() == IQ::Set || iq.subtype() == IQ::Get ) )
00716 {
00717 if( iq.id().empty() )
00718 iq.setID( getID() );
00719
00720 TrackStruct track;
00721 track.ih = ih;
00722 track.context = context;
00723 track.del = del;
00724 m_iqHandlerMapMutex.lock();
00725 m_iqIDHandlers[iq.id()] = track;
00726 m_iqHandlerMapMutex.unlock();
00727 }
00728
00729 send( iq );
00730 }
00731
00732 void ClientBase::send( const IQ& iq )
00733 {
00734 ++m_stats.iqStanzasSent;
00735 Tag* tag = iq.tag();
00736 addFrom( tag );
00737 addNamespace( tag );
00738 send( tag );
00739 }
00740
00741 void ClientBase::send( const Message& msg )
00742 {
00743 ++m_stats.messageStanzasSent;
00744 Tag* tag = msg.tag();
00745 addFrom( tag );
00746 addNamespace( tag );
00747 send( tag );
00748 }
00749
00750 void ClientBase::send( const Subscription& sub )
00751 {
00752 ++m_stats.s10nStanzasSent;
00753 Tag* tag = sub.tag();
00754 addFrom( tag );
00755 addNamespace( tag );
00756 send( tag );
00757 }
00758
00759 void ClientBase::send( Presence& pres )
00760 {
00761 ++m_stats.presenceStanzasSent;
00762 Tag* tag = pres.tag();
00763 StanzaExtensionList::const_iterator it = m_presenceExtensions.begin();
00764 for( ; it != m_presenceExtensions.end(); ++it )
00765 tag->addChild( (*it)->tag() );
00766 addFrom( tag );
00767 addNamespace( tag );
00768 send( tag );
00769 }
00770
00771 void ClientBase::send( Tag* tag )
00772 {
00773 if( !tag )
00774 return;
00775
00776 send( tag->xml() );
00777
00778 ++m_stats.totalStanzasSent;
00779
00780 if( m_statisticsHandler )
00781 m_statisticsHandler->handleStatistics( getStatistics() );
00782
00783 delete tag;
00784 }
00785
00786 void ClientBase::send( const std::string& xml )
00787 {
00788 if( m_connection && m_connection->state() == StateConnected )
00789 {
00790 if( m_compression && m_compressionActive )
00791 m_compression->compress( xml );
00792 else if( m_encryption && m_encryptionActive )
00793 m_encryption->encrypt( xml );
00794 else
00795 m_connection->send( xml );
00796
00797 logInstance().dbg( LogAreaXmlOutgoing, xml );
00798 }
00799 }
00800
00801 void ClientBase::addFrom( Tag* tag )
00802 {
00803 if( !m_authed || !tag || tag->hasAttribute( "from" ) )
00804 return;
00805
00806 if ( m_selectedResource.empty() )
00807 tag->addAttribute( "from", m_jid.bare() );
00808 else
00809 tag->addAttribute( "from", m_jid.bare() + '/' + m_selectedResource );
00810 }
00811
00812 void ClientBase::addNamespace( Tag* tag )
00813 {
00814 if( !tag || !tag->xmlns().empty() )
00815 return;
00816
00817 tag->setXmlns( m_namespace );
00818 }
00819
00820 void ClientBase::registerStanzaExtension( StanzaExtension* ext )
00821 {
00822 if( !m_seFactory )
00823 m_seFactory = new StanzaExtensionFactory();
00824
00825 m_seFactory->registerExtension( ext );
00826 }
00827
00828 bool ClientBase::removeStanzaExtension( int ext )
00829 {
00830 if( !m_seFactory )
00831 return false;
00832
00833 return m_seFactory->removeExtension( ext );
00834 }
00835
00836 StatisticsStruct ClientBase::getStatistics()
00837 {
00838 if( m_connection )
00839 m_connection->getStatistics( m_stats.totalBytesReceived, m_stats.totalBytesSent );
00840
00841 return m_stats;
00842 }
00843
00844 ConnectionState ClientBase::state() const
00845 {
00846 return m_connection ? m_connection->state() : StateDisconnected;
00847 }
00848
00849 void ClientBase::whitespacePing()
00850 {
00851 send( " " );
00852 }
00853
00854 void ClientBase::xmppPing( const JID& to, EventHandler* eh )
00855 {
00856 const std::string& id = getID();
00857 IQ iq( IQ::Get, to, id );
00858 iq.addExtension( new Ping() );
00859 m_dispatcher.registerEventHandler( eh, id );
00860 send( iq, this, XMPPPing );
00861 }
00862
00863 bool ClientBase::handleIq( const IQ& iq )
00864 {
00865 const Ping* p = iq.findExtension<Ping>( ExtPing );
00866 if( !p || iq.subtype() != IQ::Get )
00867 return false;
00868
00869 m_dispatcher.dispatch( Event( Event::PingPing, iq ) );
00870 IQ re( IQ::Result, iq.from(), iq.id() );
00871 send( re );
00872
00873 return true;
00874 }
00875
00876 void ClientBase::handleIqID( const IQ& iq, int context )
00877 {
00878 if( context == XMPPPing )
00879 m_dispatcher.dispatch( Event( ( iq.subtype() == IQ::Result ) ? Event::PingPong
00880 : Event::PingError, iq ),
00881 iq.id(), true );
00882 else
00883 handleIqIDForward( iq, context );
00884 }
00885
00886 const std::string ClientBase::getID()
00887 {
00888 static unsigned int uniqueBaseID = (unsigned int)time( 0 );
00889 char r[21+1];
00890 sprintf( r, "uid:%08x:%08x", uniqueBaseID, rand() );
00891 std::string ret( r, 21 );
00892 return ret;
00893 }
00894
00895 bool ClientBase::checkStreamVersion( const std::string& version )
00896 {
00897 if( version.empty() )
00898 return false;
00899
00900 int major = 0;
00901 int minor = 0;
00902 int myMajor = atoi( XMPP_STREAM_VERSION_MAJOR.c_str() );
00903
00904 size_t dot = version.find( '.' );
00905 if( !version.empty() && dot && dot != std::string::npos )
00906 {
00907 major = atoi( version.substr( 0, dot ).c_str() );
00908 minor = atoi( version.substr( dot ).c_str() );
00909 }
00910
00911 return myMajor >= major;
00912 }
00913
00914 void ClientBase::setConnectionImpl( ConnectionBase* cb )
00915 {
00916 if( m_connection )
00917 {
00918 delete m_connection;
00919 }
00920 m_connection = cb;
00921 }
00922
00923 void ClientBase::setEncryptionImpl( TLSBase* tb )
00924 {
00925 if( m_encryption )
00926 {
00927 delete m_encryption;
00928 }
00929 m_encryption = tb;
00930 }
00931
00932 void ClientBase::setCompressionImpl( CompressionBase* cb )
00933 {
00934 if( m_compression )
00935 {
00936 delete m_compression;
00937 }
00938 m_compression = cb;
00939 }
00940
00941 void ClientBase::handleStreamError( Tag* tag )
00942 {
00943 StreamError err = StreamErrorUndefined;
00944 const TagList& c = tag->children();
00945 TagList::const_iterator it = c.begin();
00946 for( ; it != c.end(); ++it )
00947 {
00948 const std::string& name = (*it)->name();
00949 if( name == "bad-format" )
00950 err = StreamErrorBadFormat;
00951 else if( name == "bad-namespace-prefix" )
00952 err = StreamErrorBadNamespacePrefix;
00953 else if( name == "conflict" )
00954 err = StreamErrorConflict;
00955 else if( name == "connection-timeout" )
00956 err = StreamErrorConnectionTimeout;
00957 else if( name == "host-gone" )
00958 err = StreamErrorHostGone;
00959 else if( name == "host-unknown" )
00960 err = StreamErrorHostUnknown;
00961 else if( name == "improper-addressing" )
00962 err = StreamErrorImproperAddressing;
00963 else if( name == "internal-server-error" )
00964 err = StreamErrorInternalServerError;
00965 else if( name == "invalid-from" )
00966 err = StreamErrorInvalidFrom;
00967 else if( name == "invalid-id" )
00968 err = StreamErrorInvalidId;
00969 else if( name == "invalid-namespace" )
00970 err = StreamErrorInvalidNamespace;
00971 else if( name == "invalid-xml" )
00972 err = StreamErrorInvalidXml;
00973 else if( name == "not-authorized" )
00974 err = StreamErrorNotAuthorized;
00975 else if( name == "policy-violation" )
00976 err = StreamErrorPolicyViolation;
00977 else if( name == "remote-connection-failed" )
00978 err = StreamErrorRemoteConnectionFailed;
00979 else if( name == "resource-constraint" )
00980 err = StreamErrorResourceConstraint;
00981 else if( name == "restricted-xml" )
00982 err = StreamErrorRestrictedXml;
00983 else if( name == "see-other-host" )
00984 {
00985 err = StreamErrorSeeOtherHost;
00986 m_streamErrorCData = tag->findChild( "see-other-host" )->cdata();
00987 }
00988 else if( name == "system-shutdown" )
00989 err = StreamErrorSystemShutdown;
00990 else if( name == "undefined-condition" )
00991 err = StreamErrorUndefinedCondition;
00992 else if( name == "unsupported-encoding" )
00993 err = StreamErrorUnsupportedEncoding;
00994 else if( name == "unsupported-stanza-type" )
00995 err = StreamErrorUnsupportedStanzaType;
00996 else if( name == "unsupported-version" )
00997 err = StreamErrorUnsupportedVersion;
00998 else if( name == "xml-not-well-formed" )
00999 err = StreamErrorXmlNotWellFormed;
01000 else if( name == "text" )
01001 {
01002 const std::string& lang = (*it)->findAttribute( "xml:lang" );
01003 if( !lang.empty() )
01004 m_streamErrorText[lang] = (*it)->cdata();
01005 else
01006 m_streamErrorText["default"] = (*it)->cdata();
01007 }
01008 else
01009 m_streamErrorAppCondition = (*it);
01010
01011 if( err != StreamErrorUndefined && (*it)->hasAttribute( XMLNS, XMLNS_XMPP_STREAM ) )
01012 m_streamError = err;
01013 }
01014 }
01015
01016 const std::string& ClientBase::streamErrorText( const std::string& lang ) const
01017 {
01018 StringMap::const_iterator it = m_streamErrorText.find( lang );
01019 return ( it != m_streamErrorText.end() ) ? (*it).second : EmptyString;
01020 }
01021
01022 void ClientBase::registerMessageSessionHandler( MessageSessionHandler* msh, int types )
01023 {
01024 if( types & Message::Chat || types == 0 )
01025 m_messageSessionHandlerChat = msh;
01026
01027 if( types & Message::Normal || types == 0 )
01028 m_messageSessionHandlerNormal = msh;
01029
01030 if( types & Message::Groupchat || types == 0 )
01031 m_messageSessionHandlerGroupchat = msh;
01032
01033 if( types & Message::Headline || types == 0 )
01034 m_messageSessionHandlerHeadline = msh;
01035 }
01036
01037 void ClientBase::registerPresenceHandler( PresenceHandler* ph )
01038 {
01039 if( ph )
01040 m_presenceHandlers.push_back( ph );
01041 }
01042
01043 void ClientBase::removePresenceHandler( PresenceHandler* ph )
01044 {
01045 if( ph )
01046 m_presenceHandlers.remove( ph );
01047 }
01048
01049 void ClientBase::registerPresenceHandler( const JID& jid, PresenceHandler* ph )
01050 {
01051 if( ph && jid )
01052 {
01053 JidPresHandlerStruct jph;
01054 jph.jid = new JID( jid.bare() );
01055 jph.ph = ph;
01056 m_presenceJidHandlers.push_back( jph );
01057 }
01058 }
01059
01060 void ClientBase::removePresenceHandler( const JID& jid, PresenceHandler* ph )
01061 {
01062 PresenceJidHandlerList::iterator t;
01063 PresenceJidHandlerList::iterator it = m_presenceJidHandlers.begin();
01064 while( it != m_presenceJidHandlers.end() )
01065 {
01066 t = it;
01067 ++it;
01068 if( ( !ph || (*t).ph == ph ) && (*t).jid->bare() == jid.bare() )
01069 {
01070 delete (*t).jid;
01071 m_presenceJidHandlers.erase( t );
01072 }
01073 }
01074 }
01075
01076 void ClientBase::removeIDHandler( IqHandler* ih )
01077 {
01078 IqTrackMap::iterator t;
01079 m_iqHandlerMapMutex.lock();
01080 IqTrackMap::iterator it = m_iqIDHandlers.begin();
01081 while( it != m_iqIDHandlers.end() )
01082 {
01083 t = it;
01084 ++it;
01085 if( ih == (*t).second.ih )
01086 m_iqIDHandlers.erase( t );
01087 }
01088 m_iqHandlerMapMutex.unlock();
01089 }
01090
01091 void ClientBase::registerIqHandler( IqHandler* ih, int exttype )
01092 {
01093 if( !ih )
01094 return;
01095
01096 typedef IqHandlerMap::const_iterator IQci;
01097 std::pair<IQci, IQci> g = m_iqExtHandlers.equal_range( exttype );
01098 for( IQci it = g.first; it != g.second; ++it )
01099 if( (*it).second == ih )
01100 return;
01101
01102 m_iqExtHandlers.insert( std::make_pair( exttype, ih ) );
01103 }
01104
01105 void ClientBase::removeIqHandler( IqHandler* ih, int exttype )
01106 {
01107 if( !ih )
01108 return;
01109
01110 typedef IqHandlerMap::iterator IQi;
01111 std::pair<IQi, IQi> g = m_iqExtHandlers.equal_range( exttype );
01112 IQi it2;
01113 IQi it = g.first;
01114 while( it != g.second )
01115 {
01116 it2 = it++;
01117 if( (*it2).second == ih )
01118 m_iqExtHandlers.erase( it2 );
01119 }
01120 }
01121
01122 void ClientBase::registerMessageSession( MessageSession* session )
01123 {
01124 if( session )
01125 m_messageSessions.push_back( session );
01126 }
01127
01128 void ClientBase::disposeMessageSession( MessageSession* session )
01129 {
01130 if( !session )
01131 return;
01132
01133 MessageSessionList::iterator it = std::find( m_messageSessions.begin(),
01134 m_messageSessions.end(),
01135 session );
01136 if( it != m_messageSessions.end() )
01137 {
01138 delete (*it);
01139 m_messageSessions.erase( it );
01140 }
01141 }
01142
01143 void ClientBase::registerMessageHandler( MessageHandler* mh )
01144 {
01145 if( mh )
01146 m_messageHandlers.push_back( mh );
01147 }
01148
01149 void ClientBase::removeMessageHandler( MessageHandler* mh )
01150 {
01151 if( mh )
01152 m_messageHandlers.remove( mh );
01153 }
01154
01155 void ClientBase::registerSubscriptionHandler( SubscriptionHandler* sh )
01156 {
01157 if( sh )
01158 m_subscriptionHandlers.push_back( sh );
01159 }
01160
01161 void ClientBase::removeSubscriptionHandler( SubscriptionHandler* sh )
01162 {
01163 if( sh )
01164 m_subscriptionHandlers.remove( sh );
01165 }
01166
01167 void ClientBase::registerTagHandler( TagHandler* th, const std::string& tag, const std::string& xmlns )
01168 {
01169 if( th && !tag.empty() )
01170 {
01171 TagHandlerStruct ths;
01172 ths.tag = tag;
01173 ths.xmlns = xmlns;
01174 ths.th = th;
01175 m_tagHandlers.push_back( ths );
01176 }
01177 }
01178
01179 void ClientBase::removeTagHandler( TagHandler* th, const std::string& tag, const std::string& xmlns )
01180 {
01181 if( th )
01182 {
01183 TagHandlerList::iterator it = m_tagHandlers.begin();
01184 for( ; it != m_tagHandlers.end(); ++it )
01185 {
01186 if( (*it).th == th && (*it).tag == tag && (*it).xmlns == xmlns )
01187 m_tagHandlers.erase( it );
01188 }
01189 }
01190 }
01191
01192 void ClientBase::registerStatisticsHandler( StatisticsHandler* sh )
01193 {
01194 if( sh )
01195 m_statisticsHandler = sh;
01196 }
01197
01198 void ClientBase::removeStatisticsHandler()
01199 {
01200 m_statisticsHandler = 0;
01201 }
01202
01203 void ClientBase::registerMUCInvitationHandler( MUCInvitationHandler* mih )
01204 {
01205 if( mih )
01206 {
01207 m_mucInvitationHandler = mih;
01208 m_disco->addFeature( XMLNS_MUC );
01209 }
01210 }
01211
01212 void ClientBase::removeMUCInvitationHandler()
01213 {
01214 m_mucInvitationHandler = 0;
01215 m_disco->removeFeature( XMLNS_MUC );
01216 }
01217
01218 void ClientBase::registerConnectionListener( ConnectionListener* cl )
01219 {
01220 if( cl )
01221 m_connectionListeners.push_back( cl );
01222 }
01223
01224 void ClientBase::removeConnectionListener( ConnectionListener* cl )
01225 {
01226 if( cl )
01227 m_connectionListeners.remove( cl );
01228 }
01229
01230 void ClientBase::notifyOnConnect()
01231 {
01232 util::ForEach( m_connectionListeners, &ConnectionListener::onConnect );
01233 }
01234
01235 void ClientBase::notifyOnDisconnect( ConnectionError e )
01236 {
01237 util::ForEach( m_connectionListeners, &ConnectionListener::onDisconnect, e );
01238 init();
01239 }
01240
01241 bool ClientBase::notifyOnTLSConnect( const CertInfo& info )
01242 {
01243 ConnectionListenerList::const_iterator it = m_connectionListeners.begin();
01244 for( ; it != m_connectionListeners.end() && (*it)->onTLSConnect( info ); ++it )
01245 ;
01246 return m_stats.encryption = ( it == m_connectionListeners.end() );
01247 }
01248
01249 void ClientBase::notifyOnResourceBindError( const Error* error )
01250 {
01251 util::ForEach( m_connectionListeners, &ConnectionListener::onResourceBindError, error );
01252 }
01253
01254 void ClientBase::notifyOnResourceBind( const std::string& resource )
01255 {
01256 util::ForEach( m_connectionListeners, &ConnectionListener::onResourceBind, resource );
01257 }
01258
01259 void ClientBase::notifyOnSessionCreateError( const Error* error )
01260 {
01261 util::ForEach( m_connectionListeners, &ConnectionListener::onSessionCreateError, error );
01262 }
01263
01264 void ClientBase::notifyStreamEvent( StreamEvent event )
01265 {
01266 util::ForEach( m_connectionListeners, &ConnectionListener::onStreamEvent, event );
01267 }
01268
01269 void ClientBase::notifyPresenceHandlers( Presence& pres )
01270 {
01271 bool match = false;
01272 PresenceJidHandlerList::const_iterator t;
01273 PresenceJidHandlerList::const_iterator itj = m_presenceJidHandlers.begin();
01274 while( itj != m_presenceJidHandlers.end() )
01275 {
01276 t = itj++;
01277 if( (*t).jid->bare() == pres.from().bare() && (*t).ph )
01278 {
01279 (*t).ph->handlePresence( pres );
01280 match = true;
01281 }
01282 }
01283 if( match )
01284 return;
01285
01286
01287 PresenceHandlerList::const_iterator it = m_presenceHandlers.begin();
01288 for( ; it != m_presenceHandlers.end(); ++it )
01289 {
01290 (*it)->handlePresence( pres );
01291 }
01292
01293
01294 }
01295
01296 void ClientBase::notifySubscriptionHandlers( Subscription& s10n )
01297 {
01298
01299 SubscriptionHandlerList::const_iterator it = m_subscriptionHandlers.begin();
01300 for( ; it != m_subscriptionHandlers.end(); ++it )
01301 {
01302 (*it)->handleSubscription( s10n );
01303 }
01304
01305
01306 }
01307
01308 void ClientBase::notifyIqHandlers( IQ& iq )
01309 {
01310 m_iqHandlerMapMutex.lock();
01311 IqTrackMap::iterator it_id = m_iqIDHandlers.find( iq.id() );
01312 m_iqHandlerMapMutex.unlock();
01313 if( it_id != m_iqIDHandlers.end() && iq.subtype() & ( IQ::Result | IQ::Error ) )
01314 {
01315 (*it_id).second.ih->handleIqID( iq, (*it_id).second.context );
01316 if( (*it_id).second.del )
01317 delete (*it_id).second.ih;
01318 m_iqHandlerMapMutex.lock();
01319 m_iqIDHandlers.erase( it_id );
01320 m_iqHandlerMapMutex.unlock();
01321 return;
01322 }
01323
01324 if( iq.extensions().empty() )
01325 return;
01326
01327 bool res = false;
01328
01329
01330
01331
01332
01333
01334
01335
01336
01337
01338
01339
01340 typedef IqHandlerMap::const_iterator IQci;
01341 const StanzaExtensionList& sel = iq.extensions();
01342 StanzaExtensionList::const_iterator itse = sel.begin();
01343 for( ; itse != sel.end(); ++itse )
01344 {
01345 std::pair<IQci, IQci> g = m_iqExtHandlers.equal_range( (*itse)->extensionType() );
01346 for( IQci it = g.first; it != g.second; ++it )
01347 {
01348 if( (*it).second->handleIq( iq ) )
01349 res = true;
01350 }
01351 }
01352
01353 if( !res && iq.subtype() & ( IQ::Get | IQ::Set ) )
01354 {
01355 IQ re( IQ::Error, iq.from(), iq.id() );
01356 re.addExtension( new Error( StanzaErrorTypeCancel, StanzaErrorServiceUnavailable ) );
01357 send( re );
01358 }
01359 }
01360
01361 void ClientBase::notifyMessageHandlers( Message& msg )
01362 {
01363 if( m_mucInvitationHandler )
01364 {
01365 const MUCRoom::MUCUser* mu = msg.findExtension<MUCRoom::MUCUser>( ExtMUCUser );
01366 if( mu && mu->operation() != MUCRoom::OpInviteTo )
01367 {
01368
01369 m_mucInvitationHandler->handleMUCInvitation( msg.from(),
01370 mu->jid() ? JID( *(mu->jid()) ) : JID(),
01371 mu->reason() ? *(mu->reason()) : EmptyString,
01372 msg.body(),
01373 mu->password() ? *(mu->password()) : EmptyString,
01374 mu->continued(),
01375 mu->thread() ? *(mu->thread()) : EmptyString );
01376 return;
01377 }
01378 }
01379
01380 MessageSessionList::const_iterator it1 = m_messageSessions.begin();
01381 for( ; it1 != m_messageSessions.end(); ++it1 )
01382 {
01383 if( (*it1)->target().full() == msg.from().full() &&
01384 ( msg.thread().empty()
01385 || (*it1)->threadID() == msg.thread()
01386 || (*it1)->honorThreadID() ) &&
01387
01388 ( (*it1)->types() & msg.subtype() || (*it1)->types() == 0 ) )
01389 {
01390 (*it1)->handleMessage( msg );
01391 return;
01392 }
01393 }
01394
01395 it1 = m_messageSessions.begin();
01396 for( ; it1 != m_messageSessions.end(); ++it1 )
01397 {
01398 if( (*it1)->target().bare() == msg.from().bare() &&
01399 ( msg.thread().empty()
01400 || (*it1)->threadID() == msg.thread()
01401 || (*it1)->honorThreadID() ) &&
01402
01403 ( (*it1)->types() & msg.subtype() || (*it1)->types() == 0 ) )
01404 {
01405 (*it1)->handleMessage( msg );
01406 return;
01407 }
01408 }
01409
01410 MessageSessionHandler* msHandler = 0;
01411
01412 switch( msg.subtype() )
01413 {
01414 case Message::Chat:
01415 msHandler = m_messageSessionHandlerChat;
01416 break;
01417 case Message::Normal:
01418 msHandler = m_messageSessionHandlerNormal;
01419 break;
01420 case Message::Groupchat:
01421 msHandler = m_messageSessionHandlerGroupchat;
01422 break;
01423 case Message::Headline:
01424 msHandler = m_messageSessionHandlerHeadline;
01425 break;
01426 default:
01427 break;
01428 }
01429
01430 if( msHandler )
01431 {
01432 if( msg.subtype() == Message::Chat && msg.body().empty() )
01433 return;
01434 MessageSession* session = new MessageSession( this, msg.from(), true, msg.subtype() );
01435 msHandler->handleMessageSession( session );
01436 session->handleMessage( msg );
01437 }
01438 else
01439 {
01440
01441 MessageHandlerList::const_iterator it = m_messageHandlers.begin();
01442 for( ; it != m_messageHandlers.end(); ++it )
01443 {
01444 (*it)->handleMessage( msg );
01445 }
01446
01447
01448 }
01449 }
01450
01451 void ClientBase::notifyTagHandlers( Tag* tag )
01452 {
01453 TagHandlerList::const_iterator it = m_tagHandlers.begin();
01454 for( ; it != m_tagHandlers.end(); ++it )
01455 {
01456 if( (*it).tag == tag->name() && tag->hasAttribute( XMLNS, (*it).xmlns ) )
01457 (*it).th->handleTag( tag );
01458 }
01459 }
01460
01461 void ClientBase::addPresenceExtension( StanzaExtension* se )
01462 {
01463 if( !se )
01464 return;
01465
01466 removePresenceExtension( se->extensionType() );
01467 m_presenceExtensions.push_back( se );
01468 }
01469
01470 bool ClientBase::removePresenceExtension( int type )
01471 {
01472 StanzaExtensionList::iterator it = m_presenceExtensions.begin();
01473 for( ; it != m_presenceExtensions.end(); ++it )
01474 {
01475 if( (*it)->extensionType() == type )
01476 {
01477 delete (*it);
01478 m_presenceExtensions.erase( it );
01479 return true;
01480 }
01481 }
01482
01483 return false;
01484 }
01485
01486 CompressionBase* ClientBase::getDefaultCompression()
01487 {
01488 if( !m_compress )
01489 return 0;
01490
01491 #ifdef HAVE_ZLIB
01492 CompressionBase* cmp = new CompressionZlib( this );
01493 if( cmp->init() )
01494 return cmp;
01495
01496 delete cmp;
01497 #endif
01498 return 0;
01499 }
01500
01501 TLSBase* ClientBase::getDefaultEncryption()
01502 {
01503 if( m_tls == TLSDisabled || !hasTls() )
01504 return 0;
01505
01506 TLSDefault* tls = new TLSDefault( this, m_server );
01507 if( tls->init( m_clientKey, m_clientCerts, m_cacerts ) )
01508 return tls;
01509 else
01510 {
01511 delete tls;
01512 return 0;
01513 }
01514 }
01515
01516 }