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   const std::string ClientBase::getID()
00401   {
00402     std::ostringstream oss;
00403     oss << ++m_idCount;
00404     return std::string( "uid" ) + oss.str();
00405   }
00406 
00407   bool ClientBase::checkStreamVersion( const std::string& version )
00408   {
00409     if( version.empty() )
00410       return false;
00411 
00412     int major = 0;
00413     int minor = 0;
00414     int myMajor = XMPP_STREAM_VERSION_MAJOR;
00415 
00416     size_t dot = version.find( "." );
00417     if( !version.empty() && dot && dot != std::string::npos )
00418     {
00419       major = atoi( version.substr( 0, dot ).c_str() );
00420       minor = atoi( version.substr( dot ).c_str() );
00421     }
00422 
00423     if( myMajor < major )
00424       return false;
00425     else
00426       return true;
00427   }
00428 
00429   LogSink& ClientBase::logInstance()
00430   {
00431     return m_logInstance;
00432   }
00433 
00434   void ClientBase::handleStreamError( Stanza *stanza )
00435   {
00436     Tag::TagList& c = stanza->children();
00437     Tag::TagList::const_iterator it = c.begin();
00438     for( ; it != c.end(); ++it )
00439     {
00440       if( (*it)->name() == "bad-format" && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00441         m_streamError = StreamErrorBadFormat;
00442       else if( (*it)->name() == "bad-namespace-prefix" && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00443         m_streamError = StreamErrorBadNamespacePrefix;
00444       else if( (*it)->name() == "conflict" && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00445         m_streamError = StreamErrorConflict;
00446       else if( (*it)->name() == "connection-timeout" && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00447         m_streamError = StreamErrorConnectionTimeout;
00448       else if( (*it)->name() == "host-gone" && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00449         m_streamError = StreamErrorHostGone;
00450       else if( (*it)->name() == "host-unknown" && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00451         m_streamError = StreamErrorHostUnknown;
00452       else if( (*it)->name() == "improper-addressing" && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00453         m_streamError = StreamErrorImproperAddressing;
00454       else if( (*it)->name() == "internal-server-error" && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00455         m_streamError = StreamErrorInternalServerError;
00456       else if( (*it)->name() == "invalid-from" && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00457         m_streamError = StreamErrorInvalidFrom;
00458       else if( (*it)->name() == "invalid-id" && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00459         m_streamError = StreamErrorInvalidId;
00460       else if( (*it)->name() == "invalid-namespace" && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00461         m_streamError = StreamErrorInvalidNamespace;
00462       else if( (*it)->name() == "invalid-xml" && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00463         m_streamError = StreamErrorInvalidXml;
00464       else if( (*it)->name() == "not-authorized" && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00465         m_streamError = StreamErrorNotAuthorized;
00466       else if( (*it)->name() == "policy-violation" && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00467         m_streamError = StreamErrorPolicyViolation;
00468       else if( (*it)->name() == "remote-connection-failed" &&
00469                  (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00470         m_streamError = StreamErrorRemoteConnectionFailed;
00471       else if( (*it)->name() == "resource-constraint" && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00472         m_streamError = StreamErrorResourceConstraint;
00473       else if( (*it)->name() == "restricted-xml" && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00474         m_streamError = StreamErrorRestrictedXml;
00475       else if( (*it)->name() == "see-other-host" && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00476       {
00477         m_streamError = StreamErrorSeeOtherHost;
00478         m_streamErrorCData = stanza->findChild( "see-other-host" )->cdata();
00479       }
00480       else if( (*it)->name() == "system-shutdown" && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00481         m_streamError = StreamErrorSystemShutdown;
00482       else if( (*it)->name() == "undefined-condition" && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00483         m_streamError = StreamErrorUndefinedCondition;
00484       else if( (*it)->name() == "unsupported-encoding" && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00485         m_streamError = StreamErrorUnsupportedEncoding;
00486       else if( (*it)->name() == "unsupported-stanza-type" &&
00487                  (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00488         m_streamError = StreamErrorUnsupportedStanzaType;
00489       else if( (*it)->name() == "unsupported-version" && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00490         m_streamError = StreamErrorUnsupportedVersion;
00491       else if( (*it)->name() == "xml-not-well-formed" && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00492         m_streamError = StreamErrorXmlNotWellFormed;
00493       else if( (*it)->name() == "text" && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) )
00494       {
00495         const std::string lang = (*it)->findAttribute( "xml:lang" );
00496         if( !lang.empty() )
00497           m_streamErrorText[lang] = (*it)->cdata();
00498         else
00499           m_streamErrorText["default"] = (*it)->cdata();
00500       }
00501       else
00502         m_streamErrorAppCondition = (*it);
00503     }
00504   }
00505 
00506   const std::string ClientBase::streamErrorText( const std::string& lang ) const
00507   {
00508     StringMap::const_iterator it = m_streamErrorText.find( lang );
00509     if( it != m_streamErrorText.end() )
00510       return (*it).second;
00511     else
00512       return "";
00513   }
00514 
00515   void ClientBase::setAutoMessageSession( bool autoMS, MessageSessionHandler *msh )
00516   {
00517     if( autoMS && msh )
00518     {
00519       m_messageSessionHandler = msh;
00520       m_autoMessageSession = true;
00521     }
00522     else
00523     {
00524       m_autoMessageSession = false;
00525       m_messageSessionHandler = 0;
00526     }
00527   }
00528 
00529   int ClientBase::fileDescriptor()
00530   {
00531     if( m_connection )
00532     {
00533       m_fdRequested = true;
00534       return m_connection->fileDescriptor();
00535     }
00536     else
00537       return -1;
00538   }
00539 
00540   void ClientBase::registerPresenceHandler( PresenceHandler *ph )
00541   {
00542     if( ph )
00543       m_presenceHandlers.push_back( ph );
00544   }
00545 
00546   void ClientBase::removePresenceHandler( PresenceHandler *ph )
00547   {
00548     if( ph )
00549       m_presenceHandlers.remove( ph );
00550   }
00551 
00552   void ClientBase::registerIqHandler( IqHandler *ih, const std::string& xmlns )
00553   {
00554     if( ih && !xmlns.empty() )
00555       m_iqNSHandlers[xmlns] = ih;
00556   }
00557 
00558   void ClientBase::trackID( IqHandler *ih, const std::string& id, int context )
00559   {
00560     if( ih && !id.empty() )
00561     {
00562       TrackStruct track;
00563       track.ih = ih;
00564       track.context = context;
00565       m_iqIDHandlers[id] = track;
00566     }
00567   }
00568 
00569   void ClientBase::removeIqHandler( const std::string& xmlns )
00570   {
00571     if( !xmlns.empty() )
00572       m_iqNSHandlers.erase( xmlns );
00573   }
00574 
00575   void ClientBase::registerMessageHandler( const std::string& jid, MessageHandler *mh )
00576   {
00577     if( mh && !jid.empty() )
00578       m_messageJidHandlers[jid] = mh;
00579   }
00580 
00581   void ClientBase::registerMessageHandler( MessageHandler *mh )
00582   {
00583     if( mh )
00584       m_messageHandlers.push_back( mh );
00585   }
00586 
00587   void ClientBase::removeMessageHandler( const std::string& jid )
00588   {
00589     MessageHandlerMap::iterator it = m_messageJidHandlers.find( jid );
00590     if( it != m_messageJidHandlers.end() )
00591       m_messageJidHandlers.erase( it );
00592   }
00593 
00594   void ClientBase::removeMessageHandler( MessageHandler *mh )
00595   {
00596     if( mh )
00597       m_messageHandlers.remove( mh );
00598   }
00599 
00600   void ClientBase::registerSubscriptionHandler( SubscriptionHandler *sh )
00601   {
00602     if( sh )
00603       m_subscriptionHandlers.push_back( sh );
00604   }
00605 
00606   void ClientBase::registerTagHandler( TagHandler *th, const std::string& tag, const std::string& xmlns )
00607   {
00608     if( th && !tag.empty() )
00609     {
00610       TagHandlerStruct ths;
00611       ths.tag = tag;
00612       ths.xmlns = xmlns;
00613       ths.th = th;
00614       m_tagHandlers.push_back( ths );
00615     }
00616   }
00617 
00618   void ClientBase::removeSubscriptionHandler( SubscriptionHandler *sh )
00619   {
00620     if( sh )
00621       m_subscriptionHandlers.remove( sh );
00622   }
00623 
00624   void ClientBase::registerConnectionListener( ConnectionListener *cl )
00625   {
00626     if( cl )
00627       m_connectionListeners.push_back( cl );
00628   }
00629 
00630   void ClientBase::removeConnectionListener( ConnectionListener *cl )
00631   {
00632     if( cl )
00633       m_connectionListeners.remove( cl );
00634   }
00635 
00636   void ClientBase::removeTagHandler( TagHandler *th, const std::string& tag, const std::string& xmlns )
00637   {
00638     if( th )
00639     {
00640       TagHandlerList::iterator it = m_tagHandlers.begin();
00641       for( ; it != m_tagHandlers.end(); ++it )
00642       {
00643         if( (*it).th == th && (*it).tag == tag && (*it).xmlns == xmlns )
00644           m_tagHandlers.erase( it );
00645       }
00646     }
00647   }
00648 
00649   void ClientBase::notifyOnConnect()
00650   {
00651     ConnectionListenerList::const_iterator it = m_connectionListeners.begin();
00652     for( ; it != m_connectionListeners.end(); ++it )
00653     {
00654       (*it)->onConnect();
00655     }
00656   }
00657 
00658   void ClientBase::notifyOnDisconnect( ConnectionError e )
00659   {
00660     ConnectionListenerList::const_iterator it = m_connectionListeners.begin();
00661     for( ; it != m_connectionListeners.end(); ++it )
00662     {
00663       (*it)->onDisconnect( e );
00664     }
00665 
00666     cleanup();
00667   }
00668 
00669   bool ClientBase::notifyOnTLSConnect( const CertInfo& info )
00670   {
00671     ConnectionListenerList::const_iterator it = m_connectionListeners.begin();
00672     for( ; it != m_connectionListeners.end(); ++it )
00673     {
00674       if( !(*it)->onTLSConnect( info ) )
00675         return false;
00676     }
00677 
00678     return true;
00679   }
00680 
00681   void ClientBase::notifyOnResourceBindError( ResourceBindError error )
00682   {
00683     ConnectionListenerList::const_iterator it = m_connectionListeners.begin();
00684     for( ; it != m_connectionListeners.end(); ++it )
00685     {
00686       (*it)->onResourceBindError( error );
00687     }
00688   }
00689 
00690   void ClientBase::notifyOnSessionCreateError( SessionCreateError error )
00691   {
00692     ConnectionListenerList::const_iterator it = m_connectionListeners.begin();
00693     for( ; it != m_connectionListeners.end(); ++it )
00694     {
00695       (*it)->onSessionCreateError( error );
00696     }
00697   }
00698 
00699   void ClientBase::notifyPresenceHandlers( Stanza *stanza )
00700   {
00701     PresenceHandlerList::const_iterator it = m_presenceHandlers.begin();
00702     for( ; it != m_presenceHandlers.end(); ++it )
00703     {
00704       (*it)->handlePresence( stanza );
00705     }
00706   }
00707 
00708   void ClientBase::notifySubscriptionHandlers( Stanza *stanza )
00709   {
00710     SubscriptionHandlerList::const_iterator it = m_subscriptionHandlers.begin();
00711     for( ; it != m_subscriptionHandlers.end(); ++it )
00712     {
00713       (*it)->handleSubscription( stanza );
00714     }
00715   }
00716 
00717   void ClientBase::notifyIqHandlers( Stanza *stanza )
00718   {
00719     bool res = false;
00720 
00721     IqHandlerMap::const_iterator it = m_iqNSHandlers.begin();
00722     for( ; it != m_iqNSHandlers.end(); ++it )
00723     {
00724       if( stanza->hasChildWithAttrib( "xmlns", (*it).first ) )
00725       {
00726         if( (*it).second->handleIq( stanza ) )
00727           res = true;
00728       }
00729     }
00730 
00731     IqTrackMap::iterator it_id = m_iqIDHandlers.find( stanza->id() );
00732     if( it_id != m_iqIDHandlers.end() )
00733     {
00734       if( (*it_id).second.ih->handleIqID( stanza, (*it_id).second.context ) )
00735         res = true;
00736       m_iqIDHandlers.erase( it_id );
00737     }
00738 
00739     if( !res && ( stanza->type() == StanzaIq ) &&
00740          ( ( stanza->subtype() == StanzaIqGet ) || ( stanza->subtype() == StanzaIqSet ) ) )
00741     {
00742       Tag *iq = new Tag( "iq" );
00743       iq->addAttribute( "type", "result" );
00744       iq->addAttribute( "id", stanza->id() );
00745       iq->addAttribute( "to", stanza->from().full() );
00746       send( iq );
00747     }
00748   }
00749 
00750   void ClientBase::notifyMessageHandlers( Stanza *stanza )
00751   {
00752     MessageHandlerMap::const_iterator it1 = m_messageJidHandlers.find( stanza->from().full() );
00753     if( it1 != m_messageJidHandlers.end() )
00754     {
00755       (*it1).second->handleMessage( stanza );
00756       return;
00757     }
00758 
00759     if( m_autoMessageSession && m_messageSessionHandler )
00760     {
00761       MessageSession *session = new MessageSession( this, stanza->from() );
00762       m_messageSessionHandler->handleMessageSession( session );
00763       notifyMessageHandlers( stanza );
00764       return;
00765     }
00766 
00767     MessageHandlerList::const_iterator it = m_messageHandlers.begin();
00768     for( ; it != m_messageHandlers.end(); ++it )
00769     {
00770       (*it)->handleMessage( stanza );
00771     }
00772   }
00773 
00774   void ClientBase::notifyTagHandlers( Stanza *stanza )
00775   {
00776     TagHandlerList::const_iterator it = m_tagHandlers.begin();
00777     for( ; it != m_tagHandlers.end(); ++it )
00778     {
00779       if( (*it).tag == stanza->name() && (*it).xmlns == stanza->xmlns() )
00780         (*it).th->handleTag( stanza );
00781     }
00782   }
00783 
00784   void ClientBase::cleanup()
00785   {
00786 
00787   }
00788 
00789 }

Generated on Wed Sep 13 21:33:46 2006 for gloox by  doxygen 1.4.7