gloox
1.0
|
00001 /* 00002 Copyright (c) 2005-2009 by Jakob Schroeter <js@camaya.net> 00003 This file is part of the gloox library. http://camaya.net/gloox 00004 00005 This software is distributed under a license. The full license 00006 agreement can be found in the file LICENSE in this distribution. 00007 This software may not be copied, modified, sold or distributed 00008 other than expressed in the named license agreement. 00009 00010 This software is distributed without any warranty. 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> // for memset() 00060 00061 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ ) 00062 #include <tchar.h> 00063 #endif 00064 00065 namespace gloox 00066 { 00067 00068 // ---- ClientBase::Ping ---- 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 // ---- ~ClientBase::Ping ---- 00084 00085 // ---- ClientBase ---- 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; // to avoid usage when Disco gets deleted below 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* /*base*/, 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* /*base*/, 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* /*base*/, 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* /*connection*/, 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* /*connection*/ ) 00340 { 00341 header(); 00342 } 00343 00344 void ClientBase::handleDisconnect( const ConnectionBase* /*connection*/, 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 // The client calls GSS_Init_sec_context, passing in 0 for 00478 // input_context_handle (initially) and a targ_name equal to output_name 00479 // from GSS_Import_Name called with input_name_type of 00480 // GSS_C_NT_HOSTBASED_SERVICE and input_name_string of 00481 // "service@hostname" where "service" is the service name specified in 00482 // the protocol's profile, and "hostname" is the fully qualified host 00483 // name of the server. The client then responds with the resulting 00484 // output_token. 00485 std::string token; 00486 a->setCData( Base64::encode64( token ) ); 00487 // etc... see gssapi-sasl-draft.txt 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 // see gssapi-sasl-draft.txt 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 // should never happen. 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 /*for IQ Auth */ || !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 // FIXME remove this for() for 1.1: 01287 PresenceHandlerList::const_iterator it = m_presenceHandlers.begin(); 01288 for( ; it != m_presenceHandlers.end(); ++it ) 01289 { 01290 (*it)->handlePresence( pres ); 01291 } 01292 // FIXME and reinstantiate this: 01293 // util::ForEach( m_presenceHandlers, &PresenceHandler::handlePresence, pres ); 01294 } 01295 01296 void ClientBase::notifySubscriptionHandlers( Subscription& s10n ) 01297 { 01298 // FIXME remove this for() for 1.1: 01299 SubscriptionHandlerList::const_iterator it = m_subscriptionHandlers.begin(); 01300 for( ; it != m_subscriptionHandlers.end(); ++it ) 01301 { 01302 (*it)->handleSubscription( s10n ); 01303 } 01304 // FIXME and reinstantiate this: 01305 // util::ForEach( m_subscriptionHandlers, &SubscriptionHandler::handleSubscription, s10n ); 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 // FIXME remove for 1.1 01330 // typedef IqHandlerMapXmlns::const_iterator IQciXmlns 01331 // Tag *tag = iq.tag()->xmlns(); 01332 // std::pair<IQciXmlns, IQciXmlns> g = m_iqNSHandlers.equal_range( tag->xmlns() ); 01333 // for( IQciXmlns it = g.first; it != g.second; ++it ) 01334 // { 01335 // if( (*it).second->handleIq( iq ) ) 01336 // res = true; 01337 // } 01338 // delete tag; 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 // FIXME don't use '== 0' here 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 // FIXME don't use '== 0' here 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; // don't want a new MS for empty messages 01434 MessageSession* session = new MessageSession( this, msg.from(), true, msg.subtype() ); 01435 msHandler->handleMessageSession( session ); 01436 session->handleMessage( msg ); 01437 } 01438 else 01439 { 01440 // FIXME remove this for() for 1.1: 01441 MessageHandlerList::const_iterator it = m_messageHandlers.begin(); 01442 for( ; it != m_messageHandlers.end(); ++it ) 01443 { 01444 (*it)->handleMessage( msg ); 01445 } 01446 // FIXME and reinstantiate this: 01447 // util::ForEach( m_messageHandlers, &MessageHandler::handleMessage, msg ); // FIXME remove for 1.1 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 }