clientbase.cpp

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

Generated on Tue May 1 14:20:20 2007 for gloox by  doxygen 1.5.1