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

Generated on Sun Sep 24 21:57:31 2006 for gloox by  doxygen 1.4.7