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

Generated on Tue May 4 16:35:11 2010 for gloox by  doxygen 1.4.1