clientbase.cpp

00001 /*
00002   Copyright (c) 2005-2006 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 #else
00018 #include "config.h"
00019 #endif
00020 
00021 #include "clientbase.h"
00022 #include "connection.h"
00023 #include "messagesessionhandler.h"
00024 #include "parser.h"
00025 #include "tag.h"
00026 #include "stanza.h"
00027 #include "connectionlistener.h"
00028 #include "iqhandler.h"
00029 #include "messagehandler.h"
00030 #include "presencehandler.h"
00031 #include "rosterlistener.h"
00032 #include "subscriptionhandler.h"
00033 #include "loghandler.h"
00034 #include "taghandler.h"
00035 #include "jid.h"
00036 #include "base64.h"
00037 
00038 #include <iksemel.h>
00039 
00040 #include <string>
00041 #include <map>
00042 #include <list>
00043 #include <sstream>
00044 
00045 namespace gloox
00046 {
00047 
00048   ClientBase::ClientBase( const std::string& ns, const std::string& server, int port )
00049     : m_connection( 0 ), m_namespace( ns ), m_xmllang( "en" ), m_server( server ),
00050       m_authed( false ), m_sasl( true ), m_tls( true ), m_port( port ),
00051       m_messageSessionHandler( 0 ), m_parser( 0 ),
00052       m_authError( AuthErrorUndefined ), m_streamError( StreamErrorUndefined ),
00053       m_streamErrorAppCondition( 0 ), m_idCount( 0 ), m_autoMessageSession( false ),
00054       m_fdRequested( false )
00055   {
00056   }
00057 
00058   ClientBase::ClientBase( const std::string& ns, const std::string& password,
00059                           const std::string& server, int port )
00060     : m_connection( 0 ), m_namespace( ns ), m_password( password ), m_xmllang( "en" ), m_server( server ),
00061       m_authed( false ), m_sasl( true ), m_tls( true ), m_port( port ),
00062       m_messageSessionHandler( 0 ), m_parser( 0 ),
00063       m_authError( AuthErrorUndefined ), m_streamError( StreamErrorUndefined ),
00064       m_streamErrorAppCondition( 0 ), m_idCount( 0 ), m_autoMessageSession( false ),
00065       m_fdRequested( false )
00066   {
00067   }
00068 
00069   ClientBase::~ClientBase()
00070   {
00071     delete m_connection;
00072     delete m_parser;
00073   }
00074 
00075   ConnectionError ClientBase::recv( int timeout )
00076   {
00077     if( !m_connection || m_connection->state() == StateDisconnected )
00078       return ConnNotConnected;
00079 
00080     ConnectionError e = m_connection->recv( timeout );
00081     if( e != ConnNoError )
00082       notifyOnDisconnect( e );
00083     return e;
00084   }
00085 
00086   bool ClientBase::connect( bool block )
00087   {
00088     if( m_server.empty() )
00089       return false;
00090 
00091     if( !m_parser )
00092       m_parser = new Parser( this );
00093 
00094     if( !m_connection )
00095       m_connection = new Connection( m_parser, m_logInstance, m_server, m_port );
00096 
00097 #ifdef HAVE_TLS
00098     m_connection->setCACerts( m_cacerts );
00099     if( !m_clientKey.empty() && !m_clientCerts.empty() )
00100       m_connection->setClientCert( m_clientKey, m_clientCerts );
00101 #endif
00102 
00103     int ret = m_connection->connect();
00104     if( ret == StateConnected )
00105     {
00106       header();
00107       if( block )
00108       {
00109         ConnectionError e = m_connection->receive();
00110         notifyOnDisconnect( e );
00111         return false;
00112       }
00113       else
00114         return true;
00115     }
00116     else
00117       return false;
00118   }
00119 
00120   void ClientBase::filter( NodeType type, Stanza *stanza )
00121   {
00122     if( stanza )
00123       logInstance().log( LogLevelDebug, LogAreaXmlIncoming, stanza->xml() );
00124 
00125     switch( type )
00126     {
00127       case NODE_STREAM_START:
00128       {
00129         const std::string version = stanza->findAttribute( "version" );
00130         if( !checkStreamVersion( version ) )
00131         {
00132           logInstance().log( LogLevelDebug, LogAreaClassClientbase, "This server is not XMPP-compliant"
00133               " (it does not send a 'version' attribute). Please fix it or try another one.\n" );
00134           disconnect( ConnStreamError );
00135         }
00136 
00137         m_sid = stanza->findAttribute( "id" );
00138         handleStartNode();
00139         break;
00140       }
00141       case NODE_STREAM_CHILD:
00142         if( !handleNormalNode( stanza ) )
00143         {
00144           switch( stanza->type() )
00145           {
00146             case StanzaIq:
00147               notifyIqHandlers( stanza );
00148               break;
00149             case StanzaPresence:
00150               notifyPresenceHandlers( stanza );
00151               break;
00152             case StanzaS10n:
00153               notifySubscriptionHandlers( stanza );
00154               break;
00155             case StanzaMessage:
00156               notifyMessageHandlers( stanza );
00157               break;
00158             default:
00159               notifyTagHandlers( stanza );
00160               break;
00161           }
00162         }
00163         break;
00164       case NODE_STREAM_ERROR:
00165         handleStreamError( stanza );
00166         disconnect( ConnStreamError );
00167         break;
00168       case NODE_STREAM_CLOSE:
00169         logInstance().log( LogLevelDebug, LogAreaClassClientbase, "stream closed" );
00170         disconnect( ConnStreamClosed );
00171         break;
00172     }
00173   }
00174 
00175   void ClientBase::disconnect( ConnectionError reason )
00176   {
00177     if( m_connection )
00178     {
00179       if( reason != ConnStreamError )
00180        send ( "</stream:stream>" );
00181       if( reason == ConnUserDisconnected )
00182         m_streamError = StreamErrorUndefined;
00183       m_connection->disconnect( reason );
00184     }
00185 
00186     notifyOnDisconnect( reason );
00187   }
00188 
00189   void ClientBase::header()
00190   {
00191     std::ostringstream oss;
00192     oss << "<?xml version='1.0' ?>";
00193     oss << "<stream:stream to='" + m_jid.server()+ "' xmlns='" + m_namespace + "' ";
00194     oss << "xmlns:stream='http://etherx.jabber.org/streams'  xml:lang='" + m_xmllang + "' ";
00195     oss << "version='";
00196     oss << XMPP_STREAM_VERSION_MAJOR;
00197     oss << ".";
00198     oss << XMPP_STREAM_VERSION_MINOR;
00199     oss << "'>";
00200     send( oss.str() );
00201   }
00202 
00203   bool ClientBase::hasTls()
00204   {
00205 #ifdef HAVE_TLS
00206     return true;
00207 #else
00208     return false;
00209 #endif
00210   }
00211 
00212 #ifdef HAVE_TLS
00213   void ClientBase::startTls()
00214   {
00215     Tag *start = new Tag( "starttls" );
00216     start->addAttribute( "xmlns", XMLNS_STREAM_TLS );
00217     send( start );
00218   }
00219 
00220   void ClientBase::setClientCert( const std::string& clientKey, const std::string& clientCerts )
00221   {
00222     m_clientKey = clientKey;
00223     m_clientCerts = clientCerts;
00224   }
00225 #endif
00226 
00227   void ClientBase::startSASL( SaslMechanisms type )
00228   {
00229     Tag *a = new Tag( "auth" );
00230     a->addAttribute( "xmlns", XMLNS_STREAM_SASL );
00231 
00232     switch( type )
00233     {
00234       case SaslDigestMd5:
00235         a->addAttribute( "mechanism", "DIGEST-MD5" );
00236         break;
00237       case SaslPlain:
00238       {
00239         a->addAttribute( "mechanism", "PLAIN" );
00240         size_t len = m_jid.username().length() + m_password.length() + 2;
00241         char *tmp = (char*)malloc( len + 80 );
00242         sprintf( tmp, "%c%s%c%s", 0, m_jid.username().c_str(), 0, m_password.c_str() );
00243         std::string dec;
00244         dec.assign( tmp, len );
00245         a->setCData( Base64::encode64( dec ) );
00246         free( tmp );
00247         break;
00248       }
00249       case SaslAnonymous:
00250         a->addAttribute( "mechanism", "ANONYMOUS" );
00251         a->setCData( getID() );
00252         break;
00253       case SaslExternal:
00254         a->addAttribute( "mechanism", "EXTERNAL" );
00255         a->setCData( Base64::encode64( m_jid.bare() ) );
00256         break;
00257     }
00258 
00259     send( a );
00260   }
00261 
00262   void ClientBase::processSASLChallenge( const std::string& challenge )
00263   {
00264     const int CNONCE_LEN = 4;
00265     Tag *t;
00266     std::string decoded, nonce, realm, response;
00267     decoded = Base64::decode64( challenge.c_str() );
00268 
00269     if( decoded.substr( 0, 7 ) == "rspauth" )
00270     {
00271       t = new Tag( "response" );
00272     }
00273     else
00274     {
00275       char cnonce[CNONCE_LEN*8 + 1];
00276       unsigned char a1_h[16];
00277       char a1[33], a2[33], response_value[33];
00278       iksmd5 *md5;
00279       int i;
00280 
00281       size_t r_pos = decoded.find( "realm=" );
00282       if( r_pos != std::string::npos )
00283       {
00284         size_t r_end = decoded.find( "\"", r_pos + 7 );
00285         realm = decoded.substr( r_pos + 7, r_end - (r_pos + 7 ) );
00286       }
00287       else
00288         realm = m_jid.server();
00289 
00290       size_t n_pos = decoded.find( "nonce=" );
00291       if( n_pos != std::string::npos )
00292       {
00293         size_t n_end = decoded.find( "\"", n_pos + 7 );
00294         while( decoded.substr( n_end-1, 1 ) == "\\" )
00295           n_end = decoded.find( "\"", n_end + 1 );
00296         nonce = decoded.substr( n_pos + 7, n_end - ( n_pos + 7 ) );
00297       }
00298       else
00299       {
00300         return;
00301       }
00302 
00303       for( i=0; i<CNONCE_LEN; ++i )
00304         sprintf( cnonce + i*8, "%08x", rand() );
00305 
00306       md5 = iks_md5_new();
00307       iks_md5_hash( md5, (const unsigned char*)m_jid.username().c_str(), m_jid.username().length(), 0 );
00308       iks_md5_hash( md5, (const unsigned char*)":", 1, 0 );
00309       iks_md5_hash( md5, (const unsigned char*)realm.c_str(), realm.length(), 0 );
00310       iks_md5_hash( md5, (const unsigned char*)":", 1, 0 );
00311       iks_md5_hash( md5, (const unsigned char*)m_password.c_str(), m_password.length(), 1 );
00312       iks_md5_digest( md5, a1_h );
00313       iks_md5_reset( md5 );
00314       iks_md5_hash( md5, a1_h, 16, 0 );
00315       iks_md5_hash( md5, (const unsigned char*)":", 1, 0 );
00316       iks_md5_hash( md5, (const unsigned char*)nonce.c_str(), nonce.length(), 0 );
00317       iks_md5_hash( md5, (const unsigned char*)":", 1, 0 );
00318       iks_md5_hash( md5, (const unsigned char*)cnonce, iks_strlen( cnonce ), 1 );
00319       iks_md5_print( md5, a1 );
00320       iks_md5_reset( md5 );
00321       iks_md5_hash( md5, (const unsigned char*)"AUTHENTICATE:xmpp/", 18, 0 );
00322       iks_md5_hash( md5, (const unsigned char*)m_jid.server().c_str(), m_jid.server().length(), 1 );
00323       iks_md5_print( md5, a2 );
00324       iks_md5_reset( md5 );
00325       iks_md5_hash( md5, (const unsigned char*)a1, 32, 0 );
00326       iks_md5_hash( md5, (const unsigned char*)":", 1, 0 );
00327       iks_md5_hash( md5, (const unsigned char*)nonce.c_str(), nonce.length(), 0 );
00328       iks_md5_hash( md5, (const unsigned char*)":00000001:", 10, 0 );
00329       iks_md5_hash( md5, (const unsigned char*)cnonce, iks_strlen( cnonce ), 0 );
00330       iks_md5_hash( md5, (const unsigned char*)":auth:", 6, 0 );
00331       iks_md5_hash( md5, (const unsigned char*)a2, 32, 1 );
00332       iks_md5_print( md5, response_value );
00333       iks_md5_delete( md5 );
00334 
00335       i = m_jid.username().length() + realm.length() +
00336           nonce.length() + m_jid.server().length() +
00337           CNONCE_LEN*8 + 136;
00338 
00339       std::string response = "username=\"" + m_jid.username() + "\",realm=\"" + realm;
00340       response += "\",nonce=\""+ nonce + "\",cnonce=\"";
00341       response += cnonce;
00342       response += "\",nc=00000001,qop=auth,digest-uri=\"xmpp/" + m_jid.server() + "\",response=";
00343       response += response_value;
00344       response += ",charset=utf-8";
00345 
00346       t = new Tag( "response", Base64::encode64( response ) );
00347     }
00348     t->addAttribute( "xmlns", XMLNS_STREAM_SASL );
00349     send( t );
00350 
00351   }
00352 
00353   void ClientBase::processSASLError( Stanza *stanza )
00354   {
00355     if( stanza->hasChild( "aborted" ) )
00356       m_authError = SaslAborted;
00357     else if( stanza->hasChild( "incorrect-encoding" ) )
00358       m_authError = SaslIncorrectEncoding;
00359     else if( stanza->hasChild( "invalid-authzid" ) )
00360       m_authError = SaslInvalidAuthzid;
00361     else if( stanza->hasChild( "invalid-mechanism" ) )
00362       m_authError = SaslInvalidMechanism;
00363     else if( stanza->hasChild( "mechanism-too-weak" ) )
00364       m_authError = SaslMechanismTooWeak;
00365     else if( stanza->hasChild( "not-authorized" ) )
00366       m_authError = SaslNotAuthorized;
00367     else if( stanza->hasChild( "temporary-auth-failure" ) )
00368       m_authError = SaslTemporaryAuthFailure;
00369   }
00370 
00371   void ClientBase::send( Tag *tag )
00372   {
00373     if( !tag )
00374       return;
00375 
00376     send( tag->xml() );
00377 
00378     if( tag->type() == StanzaUndefined )
00379       delete tag;
00380     else
00381     {
00382       Stanza *s = dynamic_cast<Stanza*>( tag );
00383       delete s;
00384     }
00385   }
00386 
00387   void ClientBase::send( const std::string& xml )
00388   {
00389     if( m_connection && m_connection->state() == StateConnected )
00390     {
00391       logInstance().log( LogLevelDebug, LogAreaXmlOutgoing, xml );
00392 
00393       m_connection->send( xml );
00394     }
00395   }
00396 
00397   ConnectionState ClientBase::state() const{
00398     if( m_connection )
00399       return m_connection->state();
00400     else
00401       return StateDisconnected;
00402   }
00403 
00404   void ClientBase::ping()
00405   {
00406     send( " " );
00407   }
00408 
00409   const std::string ClientBase::getID()
00410   {
00411     std::ostringstream oss;
00412     oss << ++m_idCount;
00413     return std::string( "uid" ) + oss.str();
00414   }
00415 
00416   bool ClientBase::checkStreamVersion( const std::string& version )
00417   {
00418     if( version.empty() )
00419       return false;
00420 
00421     int major = 0;
00422     int minor = 0;
00423     int myMajor = XMPP_STREAM_VERSION_MAJOR;
00424 
00425     size_t dot = version.find( "." );
00426     if( !version.empty() && dot && dot != std::string::npos )
00427     {
00428       major = atoi( version.substr( 0, dot ).c_str() );
00429       minor = atoi( version.substr( dot ).c_str() );
00430     }
00431 
00432     if( myMajor < major )
00433       return false;
00434     else
00435       return true;
00436   }
00437 
00438   LogSink& ClientBase::logInstance()
00439   {
00440     return m_logInstance;
00441   }
00442 
00443   void ClientBase::handleStreamError( Stanza *stanza )
00444   {
00445     Tag::TagList& c = stanza->children();
00446     Tag::TagList::const_iterator it = c.begin();
00447     for( ; it != c.end(); ++it )
00448     {
00449       if( (*it)->name() == "bad-format" && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00450         m_streamError = StreamErrorBadFormat;
00451       else if( (*it)->name() == "bad-namespace-prefix" && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00452         m_streamError = StreamErrorBadNamespacePrefix;
00453       else if( (*it)->name() == "conflict" && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00454         m_streamError = StreamErrorConflict;
00455       else if( (*it)->name() == "connection-timeout" && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00456         m_streamError = StreamErrorConnectionTimeout;
00457       else if( (*it)->name() == "host-gone" && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00458         m_streamError = StreamErrorHostGone;
00459       else if( (*it)->name() == "host-unknown" && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00460         m_streamError = StreamErrorHostUnknown;
00461       else if( (*it)->name() == "improper-addressing" && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00462         m_streamError = StreamErrorImproperAddressing;
00463       else if( (*it)->name() == "internal-server-error" && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00464         m_streamError = StreamErrorInternalServerError;
00465       else if( (*it)->name() == "invalid-from" && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00466         m_streamError = StreamErrorInvalidFrom;
00467       else if( (*it)->name() == "invalid-id" && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00468         m_streamError = StreamErrorInvalidId;
00469       else if( (*it)->name() == "invalid-namespace" && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00470         m_streamError = StreamErrorInvalidNamespace;
00471       else if( (*it)->name() == "invalid-xml" && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00472         m_streamError = StreamErrorInvalidXml;
00473       else if( (*it)->name() == "not-authorized" && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00474         m_streamError = StreamErrorNotAuthorized;
00475       else if( (*it)->name() == "policy-violation" && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00476         m_streamError = StreamErrorPolicyViolation;
00477       else if( (*it)->name() == "remote-connection-failed" &&
00478                  (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00479         m_streamError = StreamErrorRemoteConnectionFailed;
00480       else if( (*it)->name() == "resource-constraint" && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00481         m_streamError = StreamErrorResourceConstraint;
00482       else if( (*it)->name() == "restricted-xml" && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00483         m_streamError = StreamErrorRestrictedXml;
00484       else if( (*it)->name() == "see-other-host" && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00485       {
00486         m_streamError = StreamErrorSeeOtherHost;
00487         m_streamErrorCData = stanza->findChild( "see-other-host" )->cdata();
00488       }
00489       else if( (*it)->name() == "system-shutdown" && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00490         m_streamError = StreamErrorSystemShutdown;
00491       else if( (*it)->name() == "undefined-condition" && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00492         m_streamError = StreamErrorUndefinedCondition;
00493       else if( (*it)->name() == "unsupported-encoding" && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00494         m_streamError = StreamErrorUnsupportedEncoding;
00495       else if( (*it)->name() == "unsupported-stanza-type" &&
00496                  (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00497         m_streamError = StreamErrorUnsupportedStanzaType;
00498       else if( (*it)->name() == "unsupported-version" && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00499         m_streamError = StreamErrorUnsupportedVersion;
00500       else if( (*it)->name() == "xml-not-well-formed" && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00501         m_streamError = StreamErrorXmlNotWellFormed;
00502       else if( (*it)->name() == "text" && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00503       {
00504         const std::string lang = (*it)->findAttribute( "xml:lang" );
00505         if( !lang.empty() )
00506           m_streamErrorText[lang] = (*it)->cdata();
00507         else
00508           m_streamErrorText["default"] = (*it)->cdata();
00509       }
00510       else
00511         m_streamErrorAppCondition = (*it);
00512     }
00513   }
00514 
00515   const std::string ClientBase::streamErrorText( const std::string& lang ) const
00516   {
00517     StringMap::const_iterator it = m_streamErrorText.find( lang );
00518     if( it != m_streamErrorText.end() )
00519       return (*it).second;
00520     else
00521       return "";
00522   }
00523 
00524   void ClientBase::setAutoMessageSession( bool autoMS, MessageSessionHandler *msh )
00525   {
00526     if( autoMS && msh )
00527     {
00528       m_messageSessionHandler = msh;
00529       m_autoMessageSession = true;
00530     }
00531     else
00532     {
00533       m_autoMessageSession = false;
00534       m_messageSessionHandler = 0;
00535     }
00536   }
00537 
00538   int ClientBase::fileDescriptor()
00539   {
00540     if( m_connection )
00541     {
00542       m_fdRequested = true;
00543       return m_connection->fileDescriptor();
00544     }
00545     else
00546       return -1;
00547   }
00548 
00549   void ClientBase::registerPresenceHandler( PresenceHandler *ph )
00550   {
00551     if( ph )
00552       m_presenceHandlers.push_back( ph );
00553   }
00554 
00555   void ClientBase::removePresenceHandler( PresenceHandler *ph )
00556   {
00557     if( ph )
00558       m_presenceHandlers.remove( ph );
00559   }
00560 
00561   void ClientBase::registerIqHandler( IqHandler *ih, const std::string& xmlns )
00562   {
00563     if( ih && !xmlns.empty() )
00564       m_iqNSHandlers[xmlns] = ih;
00565   }
00566 
00567   void ClientBase::trackID( IqHandler *ih, const std::string& id, int context )
00568   {
00569     if( ih && !id.empty() )
00570     {
00571       TrackStruct track;
00572       track.ih = ih;
00573       track.context = context;
00574       m_iqIDHandlers[id] = track;
00575     }
00576   }
00577 
00578   void ClientBase::removeIqHandler( const std::string& xmlns )
00579   {
00580     if( !xmlns.empty() )
00581       m_iqNSHandlers.erase( xmlns );
00582   }
00583 
00584   void ClientBase::registerMessageHandler( const std::string& jid, MessageHandler *mh, bool wantUpgrade )
00585   {
00586     if( mh && !jid.empty() )
00587     {
00588       JidHandlerStruct jhs;
00589       jhs.mh = mh;
00590       jhs.wantUpgrade = wantUpgrade;
00591       m_messageJidHandlers[jid] = jhs;
00592     }
00593   }
00594 
00595   void ClientBase::registerMessageHandler( MessageHandler *mh )
00596   {
00597     if( mh )
00598       m_messageHandlers.push_back( mh );
00599   }
00600 
00601   void ClientBase::removeMessageHandler( const std::string& jid )
00602   {
00603     MessageJidHandlerMap::iterator it = m_messageJidHandlers.find( jid );
00604     if( it != m_messageJidHandlers.end() )
00605       m_messageJidHandlers.erase( it );
00606   }
00607 
00608   void ClientBase::removeMessageHandler( MessageHandler *mh )
00609   {
00610     if( mh )
00611       m_messageHandlers.remove( mh );
00612   }
00613 
00614   void ClientBase::registerSubscriptionHandler( SubscriptionHandler *sh )
00615   {
00616     if( sh )
00617       m_subscriptionHandlers.push_back( sh );
00618   }
00619 
00620   void ClientBase::registerTagHandler( TagHandler *th, const std::string& tag, const std::string& xmlns )
00621   {
00622     if( th && !tag.empty() )
00623     {
00624       TagHandlerStruct ths;
00625       ths.tag = tag;
00626       ths.xmlns = xmlns;
00627       ths.th = th;
00628       m_tagHandlers.push_back( ths );
00629     }
00630   }
00631 
00632   void ClientBase::removeSubscriptionHandler( SubscriptionHandler *sh )
00633   {
00634     if( sh )
00635       m_subscriptionHandlers.remove( sh );
00636   }
00637 
00638   void ClientBase::registerConnectionListener( ConnectionListener *cl )
00639   {
00640     if( cl )
00641       m_connectionListeners.push_back( cl );
00642   }
00643 
00644   void ClientBase::removeConnectionListener( ConnectionListener *cl )
00645   {
00646     if( cl )
00647       m_connectionListeners.remove( cl );
00648   }
00649 
00650   void ClientBase::removeTagHandler( TagHandler *th, const std::string& tag, const std::string& xmlns )
00651   {
00652     if( th )
00653     {
00654       TagHandlerList::iterator it = m_tagHandlers.begin();
00655       for( ; it != m_tagHandlers.end(); ++it )
00656       {
00657         if( (*it).th == th && (*it).tag == tag && (*it).xmlns == xmlns )
00658           m_tagHandlers.erase( it );
00659       }
00660     }
00661   }
00662 
00663   void ClientBase::notifyOnConnect()
00664   {
00665     ConnectionListenerList::const_iterator it = m_connectionListeners.begin();
00666     for( ; it != m_connectionListeners.end(); ++it )
00667     {
00668       (*it)->onConnect();
00669     }
00670   }
00671 
00672   void ClientBase::notifyOnDisconnect( ConnectionError e )
00673   {
00674     ConnectionListenerList::const_iterator it = m_connectionListeners.begin();
00675     for( ; it != m_connectionListeners.end(); ++it )
00676     {
00677       (*it)->onDisconnect( e );
00678     }
00679 
00680     cleanup();
00681   }
00682 
00683   bool ClientBase::notifyOnTLSConnect( const CertInfo& info )
00684   {
00685     ConnectionListenerList::const_iterator it = m_connectionListeners.begin();
00686     for( ; it != m_connectionListeners.end(); ++it )
00687     {
00688       if( !(*it)->onTLSConnect( info ) )
00689         return false;
00690     }
00691 
00692     return true;
00693   }
00694 
00695   void ClientBase::notifyOnResourceBindError( ResourceBindError error )
00696   {
00697     ConnectionListenerList::const_iterator it = m_connectionListeners.begin();
00698     for( ; it != m_connectionListeners.end(); ++it )
00699     {
00700       (*it)->onResourceBindError( error );
00701     }
00702   }
00703 
00704   void ClientBase::notifyOnSessionCreateError( SessionCreateError error )
00705   {
00706     ConnectionListenerList::const_iterator it = m_connectionListeners.begin();
00707     for( ; it != m_connectionListeners.end(); ++it )
00708     {
00709       (*it)->onSessionCreateError( error );
00710     }
00711   }
00712 
00713   void ClientBase::notifyPresenceHandlers( Stanza *stanza )
00714   {
00715     PresenceHandlerList::const_iterator it = m_presenceHandlers.begin();
00716     for( ; it != m_presenceHandlers.end(); ++it )
00717     {
00718       (*it)->handlePresence( stanza );
00719     }
00720   }
00721 
00722   void ClientBase::notifySubscriptionHandlers( Stanza *stanza )
00723   {
00724     SubscriptionHandlerList::const_iterator it = m_subscriptionHandlers.begin();
00725     for( ; it != m_subscriptionHandlers.end(); ++it )
00726     {
00727       (*it)->handleSubscription( stanza );
00728     }
00729   }
00730 
00731   void ClientBase::notifyIqHandlers( Stanza *stanza )
00732   {
00733     bool res = false;
00734 
00735     IqHandlerMap::const_iterator it = m_iqNSHandlers.begin();
00736     for( ; it != m_iqNSHandlers.end(); ++it )
00737     {
00738       if( stanza->hasChildWithAttrib( "xmlns", (*it).first ) )
00739       {
00740         if( (*it).second->handleIq( stanza ) )
00741           res = true;
00742       }
00743     }
00744 
00745     IqTrackMap::iterator it_id = m_iqIDHandlers.find( stanza->id() );
00746     if( it_id != m_iqIDHandlers.end() )
00747     {
00748       if( (*it_id).second.ih->handleIqID( stanza, (*it_id).second.context ) )
00749         res = true;
00750       m_iqIDHandlers.erase( it_id );
00751     }
00752 
00753     if( !res && ( stanza->type() == StanzaIq ) &&
00754          ( ( stanza->subtype() == StanzaIqGet ) || ( stanza->subtype() == StanzaIqSet ) ) )
00755     {
00756       Tag *iq = new Tag( "iq" );
00757       iq->addAttribute( "type", "result" );
00758       iq->addAttribute( "id", stanza->id() );
00759       iq->addAttribute( "to", stanza->from().full() );
00760       send( iq );
00761     }
00762   }
00763 
00764   void ClientBase::notifyMessageHandlers( Stanza *stanza )
00765   {
00766     MessageJidHandlerMap::const_iterator it1 = m_messageJidHandlers.find( stanza->from().full() );
00767     if( it1 != m_messageJidHandlers.end() )
00768     {
00769       (*it1).second.mh->handleMessage( stanza );
00770       return;
00771     }
00772 
00773     if( m_autoMessageSession && m_messageSessionHandler )
00774     {
00775       it1 = m_messageJidHandlers.begin();
00776       for( ; it1 != m_messageJidHandlers.end(); ++it1 )
00777       {
00778         if( (*it1).first == stanza->from().bare() )
00779         {
00780           (*it1).second.mh->handleMessage( stanza );
00781           return;
00782         }
00783       }
00784 
00785       MessageSession *session = new MessageSession( this, stanza->from() );
00786       m_messageSessionHandler->handleMessageSession( session );
00787       notifyMessageHandlers( stanza );
00788       return;
00789     }
00790 
00791     MessageHandlerList::const_iterator it = m_messageHandlers.begin();
00792     for( ; it != m_messageHandlers.end(); ++it )
00793     {
00794       (*it)->handleMessage( stanza );
00795     }
00796   }
00797 
00798   void ClientBase::notifyTagHandlers( Stanza *stanza )
00799   {
00800     TagHandlerList::const_iterator it = m_tagHandlers.begin();
00801     for( ; it != m_tagHandlers.end(); ++it )
00802     {
00803       if( (*it).tag == stanza->name() && (*it).xmlns == stanza->xmlns() )
00804         (*it).th->handleTag( stanza );
00805     }
00806   }
00807 
00808   void ClientBase::cleanup()
00809   {
00810 
00811   }
00812 
00813 }

Generated on Wed Dec 20 18:25:28 2006 for gloox by  doxygen 1.5.1