Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | Related Pages

clientbase.cpp

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

Generated on Mon Jun 23 10:50:17 2008 for gloox by  doxygen 1.4.1