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