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 <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 }