00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
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 }