18 #include "clientbase.h"
19 #include "compressionbase.h"
20 #include "compressionzlib.h"
21 #include "connectionbase.h"
22 #include "connectionlistener.h"
23 #include "connectiontcpclient.h"
26 #include "eventhandler.h"
29 #include "iqhandler.h"
31 #include "loghandler.h"
34 #include "messagehandler.h"
35 #include "messagesessionhandler.h"
36 #include "mucinvitationhandler.h"
38 #include "mutexguard.h"
40 #include "presencehandler.h"
41 #include "rosterlistener.h"
42 #include "stanzaextensionfactory.h"
44 #include "subscription.h"
45 #include "subscriptionhandler.h"
47 #include "taghandler.h"
49 #include "tlsdefault.h"
64 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
67 # ifndef SecureZeroMemory
68 # define SecureZeroMemory(p,s) RtlFillMemory((p),(s),0)
77 ClientBase::Ping::Ping()
82 ClientBase::Ping::~Ping()
86 const std::string& ClientBase::Ping::filterString()
const
88 static const std::string filter =
"/iq/ping[@xmlns='" +
XMLNS_XMPP_PING +
"']";
95 : m_connection( 0 ), m_encryption( 0 ), m_compression( 0 ), m_disco( 0 ), m_namespace( ns ),
96 m_xmllang(
"en" ), m_server( server ), m_compressionActive( false ), m_encryptionActive( false ),
97 m_compress( true ), m_authed( false ), m_resourceBound( false ), m_block( false ), m_sasl( true ),
99 m_availableSaslMechs(
SaslMechAll ), m_smContext( CtxSMInvalid ), m_smHandled( 0 ),
100 m_statisticsHandler( 0 ), m_mucInvitationHandler( 0 ),
101 m_messageSessionHandlerChat( 0 ), m_messageSessionHandlerGroupchat( 0 ),
102 m_messageSessionHandlerHeadline( 0 ), m_messageSessionHandlerNormal( 0 ),
105 m_selectedSaslMech(
SaslMechNone ), m_customConnection( false ),
106 m_uniqueBaseId( (unsigned int)( ( (unsigned long long)time( 0 ) & 0xFFFF ) << 16 ) | ( ( (unsigned long long) & m_nextId ) & 0xFFFF ) ),
113 const std::string& server,
int port )
114 : m_connection( 0 ), m_encryption( 0 ), m_compression( 0 ), m_disco( 0 ), m_namespace( ns ),
115 m_password( password ),
116 m_xmllang(
"en" ), m_server( server ), m_compressionActive( false ), m_encryptionActive( false ),
117 m_compress( true ), m_authed( false ), m_resourceBound( false ), m_block( false ), m_sasl( true ),
119 m_availableSaslMechs(
SaslMechAll ), m_smContext( CtxSMInvalid ), m_smHandled( 0 ),
120 m_statisticsHandler( 0 ), m_mucInvitationHandler( 0 ),
121 m_messageSessionHandlerChat( 0 ), m_messageSessionHandlerGroupchat( 0 ),
122 m_messageSessionHandlerHeadline( 0 ), m_messageSessionHandlerNormal( 0 ),
125 m_selectedSaslMech(
SaslMechNone ), m_customConnection( false ),
126 m_uniqueBaseId( (unsigned int)( ( (unsigned long long)time( 0 ) & 0xFFFF ) << 16 ) | ( ( (unsigned long long) & m_nextId ) & 0xFFFF ) ),
132 void ClientBase::init()
149 memset( &m_stats, 0,
sizeof( m_stats ) );
155 m_iqHandlerMapMutex.
lock();
156 m_iqIDHandlers.clear();
157 m_iqHandlerMapMutex.
unlock();
159 m_iqExtHandlerMapMutex.
lock();
160 m_iqExtHandlers.clear();
161 m_iqExtHandlerMapMutex.
unlock();
176 PresenceJidHandlerList::const_iterator it1 = m_presenceJidHandlers.begin();
177 for( ; it1 != m_presenceJidHandlers.end(); ++it1 )
207 +
m_server + ( ( m_customConnection )?(
" using a custom connection" ):(
m_port > 0 ? (
":" + util::int2string(
m_port ) ) :
EmptyString ) ) +
"..." );
233 const std::string& version = tag->
findAttribute(
"version" );
237 " (it does not send a 'version' attribute). Please fix it or try another one.\n" );
243 handleStartNode( tag );
247 handleStreamError( tag );
252 if( !handleNormalNode( tag ) )
256 if( tag->
name() ==
"iq" )
262 notifyIqHandlers( iq );
267 else if( tag->
name() ==
"message" )
273 notifyMessageHandlers( msg );
278 else if( tag->
name() ==
"presence" )
281 if( type ==
"subscribe" || type ==
"unsubscribe"
282 || type ==
"subscribed" || type ==
"unsubscribed" )
288 notifySubscriptionHandlers( sub );
297 notifyPresenceHandlers( pres );
308 notifyTagHandlers( tag );
313 if( m_statisticsHandler )
399 notifyOnDisconnect( reason );
408 send(
"</stream:stream>" );
423 notifyOnDisconnect( reason );
425 #ifdef CLIENTBASE_TEST
430 void ClientBase::parse(
const std::string& data )
432 std::string copy = data;
434 if( ( i = m_parser.
feed( copy ) ) >= 0 )
436 std::string error =
"parse error (at pos ";
437 error += util::int2string( i );
440 Tag* e =
new Tag(
"stream:error" );
449 std::string head =
"<?xml version='1.0' ?>";
451 head +=
"xmlns:stream='http://etherx.jabber.org/streams' xml:lang='" +
m_xmllang +
"' ";
458 #if defined( HAVE_GNUTLS ) || defined( HAVE_OPENSSL ) || defined( HAVE_WINTLS )
485 m_selectedSaslMech = type;
504 m_gs2Header =
"p=tls-unique,";
510 m_gs2Header +=
"a=" + t;
514 m_clientFirstMessageBare =
"n=";
516 m_clientFirstMessageBare += t;
518 m_clientFirstMessageBare += t;
520 m_clientFirstMessageBare +=
",r=" +
getRandom();
555 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
570 "SASL GSSAPI is not supported on this platform. You should never see this." );
576 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
578 SEC_WINNT_AUTH_IDENTITY_W identity, *ident = 0;
579 memset( &identity, 0,
sizeof( identity ) );
581 WCHAR *usernameW = 0, *domainW = 0, *passwordW = 0;
582 int cchUsernameW = 0, cchDomainW = 0, cchPasswordW = 0;
589 cchUsernameW = ::MultiByteToWideChar( CP_UTF8, 0,
m_jid.
username().c_str(), -1, 0, 0 );
590 if( cchUsernameW > 0 )
592 usernameW =
new WCHAR[cchUsernameW];
593 ::MultiByteToWideChar( CP_UTF8, 0,
m_jid.
username().c_str(), -1, usernameW, cchUsernameW );
595 usernameW[cchUsernameW-1] = L
'\0';
597 cchDomainW = ::MultiByteToWideChar( CP_UTF8, 0, m_ntlmDomain.c_str(), -1, 0, 0 );
600 domainW =
new WCHAR[cchDomainW];
601 ::MultiByteToWideChar( CP_UTF8, 0, m_ntlmDomain.c_str(), -1, domainW, cchDomainW );
603 domainW[cchDomainW-1] = L
'\0';
605 cchPasswordW = ::MultiByteToWideChar( CP_UTF8, 0,
m_password.c_str(), -1, 0, 0 );
606 if( cchPasswordW > 0 )
608 passwordW =
new WCHAR[cchPasswordW];
609 ::MultiByteToWideChar( CP_UTF8, 0,
m_password.c_str(), -1, passwordW, cchPasswordW );
611 passwordW[cchPasswordW-1] = L
'\0';
613 identity.User = (
unsigned short*)usernameW;
614 identity.UserLength = (
unsigned long)cchUsernameW-1;
615 identity.Domain = (
unsigned short*)domainW;
616 identity.DomainLength = (
unsigned long)cchDomainW-1;
617 identity.Password = (
unsigned short*)passwordW;
618 identity.PasswordLength = (
unsigned long)cchPasswordW-1;
619 identity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
623 AcquireCredentialsHandleW( 0, L
"NTLM", SECPKG_CRED_OUTBOUND, 0, ident, 0, 0, &m_credHandle, 0 );
637 ::SecureZeroMemory( passwordW, cchPasswordW*
sizeof( WCHAR ) );
644 "SASL NTLM is not supported on this platform. You should never see this." );
655 std::string ClientBase::hmac(
const std::string& key,
const std::string& str )
658 std::string key_ = key;
659 if( key_.length() > 64 )
665 unsigned char ipad[65];
666 unsigned char opad[65];
667 memset( ipad,
'\0',
sizeof( ipad ) );
668 memset( opad,
'\0',
sizeof( opad ) );
669 memcpy( ipad, key_.c_str(), key_.length() );
670 memcpy( opad, key_.c_str(), key_.length() );
671 for(
int i = 0; i < 64; i++ )
676 sha.
feed( ipad, 64 );
680 sha.
feed( opad, 64 );
686 std::string ClientBase::hi(
const std::string& str,
const std::string& salt,
int iter )
688 unsigned char xored[20];
689 memset( xored,
'\0',
sizeof( xored ) );
690 std::string tmp = salt;
691 tmp.append(
"\0\0\0\1", 4 );
692 for(
int i = 0; i < iter; ++i )
694 tmp = hmac( str, tmp );
695 for(
int j = 0; j < 20; ++j )
696 xored[j] ^= tmp.c_str()[j];
698 return std::string( (
char*)xored, 20 );
707 switch( m_selectedSaslMech )
712 std::string snonce, salt, tmp;
714 std::string::size_type posn = decoded.find(
"r=" );
715 std::string::size_type poss = decoded.find(
"s=" );
716 std::string::size_type posi = decoded.find(
"i=" );
717 if( posn == std::string::npos || poss == std::string::npos || posi == std::string::npos )
720 snonce = decoded.substr( posn + 2, poss - posn - 3 );
722 tmp = decoded.substr( posi + 2, decoded.length() - posi - 2 );
723 iter = atoi( tmp.c_str() );
728 std::string saltedPwd = hi( tmp, salt, iter );
729 std::string ck = hmac( saltedPwd,
"Client Key" );
732 std::string storedKey = sha.
binary();
738 tmp +=
",r=" + snonce;
740 std::string authMessage = m_clientFirstMessageBare +
"," + decoded +
"," + tmp;
741 std::string clientSignature = hmac( storedKey, authMessage );
742 unsigned char clientProof[20];
743 memcpy( clientProof, ck.c_str(), 20 );
744 for(
int i = 0; i < 20; ++i )
745 clientProof[i] ^= clientSignature.c_str()[i];
746 std::string serverKey = hmac( saltedPwd,
"Server Key" );
747 m_serverSignature = hmac( serverKey, authMessage );
758 if( !decoded.compare( 0, 7,
"rspauth" ) )
762 std::string::size_type end = 0;
763 std::string::size_type pos = decoded.find(
"realm=" );
764 if( pos != std::string::npos )
766 end = decoded.find(
'"', pos + 7 );
767 realm = decoded.substr( pos + 7, end - ( pos + 7 ) );
772 pos = decoded.find(
"nonce=" );
773 if( pos == std::string::npos )
776 end = decoded.find(
'"', pos + 7 );
777 while( decoded[end-1] ==
'\\' )
778 end = decoded.find(
'"', end + 1 );
779 std::string nonce = decoded.substr( pos + 7, end - ( pos + 7 ) );
790 const std::string& a1_h = md5.
binary();
798 const std::string& a1 = md5.
hex();
800 md5.
feed(
"AUTHENTICATE:xmpp/" );
803 const std::string& a2 = md5.
hex();
808 md5.
feed(
":00000001:" );
810 md5.
feed(
":auth:" );
814 std::string response =
"username=\"";
816 response +=
"\",realm=\"";
818 response +=
"\",nonce=\"";
820 response +=
"\",cnonce=\"";
822 response +=
"\",nc=00000001,qop=auth,digest-uri=\"xmpp/";
824 response +=
"\",response=";
825 response += md5.
hex();
826 response +=
",charset=utf-8";
836 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
840 "Huh, received GSSAPI challenge?! This should have never happened!" );
845 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
846 bool type1 = ( decoded.length() < 7 ) ?
true :
false;
848 SecBuffer bufferIn = { type1 ? 0 : (
unsigned long)decoded.length(),
850 (
void*)decoded.c_str() };
851 SecBufferDesc secIn = { 0, 1, &bufferIn };
855 SecBuffer bufferOut = {
sizeof( buffer ), SECBUFFER_TOKEN, buffer };
856 SecBufferDesc secOut = { 0, 1, &bufferOut };
859 unsigned long contextAttr;
861 SECURITY_STATUS status = InitializeSecurityContext( &m_credHandle, type1 ? 0 : &m_ctxtHandle,
862 0, ISC_REQ_MUTUAL_AUTH, 0, 0, &secIn, 0,
863 &m_ctxtHandle, &secOut, &contextAttr,
865 std::string response;
866 if( SUCCEEDED( status ) )
868 response = std::string( (
const char *)bufferOut.pvBuffer, bufferOut.cbBuffer );
873 "InitializeSecurityContext() failed, return value "
874 + util::int2string( status ) );
880 "Huh, received NTLM challenge?! This should have never happened!" );
897 else if( tag->
hasChild(
"incorrect-encoding" ) )
899 else if( tag->
hasChild(
"invalid-authzid" ) )
901 else if( tag->
hasChild(
"invalid-mechanism" ) )
903 else if( tag->
hasChild(
"malformed-request" ) )
905 else if( tag->
hasChild(
"mechanism-too-weak" ) )
907 else if( tag->
hasChild(
"not-authorized" ) )
909 else if( tag->
hasChild(
"temporary-auth-failure" ) )
912 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
915 FreeCredentialsHandle( &m_credHandle );
916 DeleteSecurityContext( &m_ctxtHandle );
923 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
926 FreeCredentialsHandle( &m_credHandle );
927 DeleteSecurityContext( &m_ctxtHandle );
933 if( decoded.length() < 3 ||
Base64::decode64( decoded.substr( 2 ) ) != m_serverSignature )
944 if( iq.
id().empty() )
949 track.context = context;
951 m_iqHandlerMapMutex.
lock();
952 m_iqIDHandlers[iq.
id()] = track;
953 m_iqHandlerMapMutex.
unlock();
965 send( tag,
true,
false );
974 send( tag,
true,
false );
983 send( tag,
true,
false );
995 send( tag,
true,
false );
1003 send( tag,
false,
true );
1015 if( m_statisticsHandler )
1020 m_queueMutex.
lock();
1021 m_smQueue.insert( std::make_pair( ++m_smSent, tag ) );
1049 SMQueueMap::iterator it = m_smQueue.begin();
1050 while( it != m_smQueue.end() )
1052 if( (*it).first <= handled )
1054 delete (*it).second;
1055 m_smQueue.erase( it++ );
1057 else if( resend && (*it).first > handled )
1059 send( (*it).second,
false,
false );
1073 SMQueueMap::iterator it = m_smQueue.begin();
1074 for( ; it != m_smQueue.end(); ++it )
1075 l.push_back( (*it).second->clone() );
1080 void ClientBase::addFrom(
Tag* tag )
1088 void ClientBase::addNamespace( Tag* tag )
1090 if( !tag || !tag->xmlns().empty() )
1132 const std::string&
id =
getID();
1136 send( iq,
this, XMPPPing );
1139 bool ClientBase::handleIq(
const IQ& iq )
1152 void ClientBase::handleIqID(
const IQ& iq,
int context )
1154 if( context == XMPPPing )
1159 handleIqIDForward( iq, context );
1164 #ifdef CLIENTBASE_TEST // to create predictable UIDs in test mode
1165 return "uid" + util::int2string( m_nextId.
increment() );
1168 sprintf( r,
"uid-%08x-%08x", m_uniqueBaseId, m_nextId.
increment() );
1169 std::string ret( r, 21 );
1176 if( version.empty() )
1183 size_t dot = version.find(
'.' );
1184 if( !version.empty() && dot && dot != std::string::npos )
1186 major = atoi( version.substr( 0, dot ).c_str() );
1190 return myMajor >= major;
1197 m_customConnection =
true;
1218 void ClientBase::handleStreamError(
Tag* tag )
1222 TagList::const_iterator it = c.begin();
1223 for( ; it != c.end(); ++it )
1225 const std::string& name = (*it)->name();
1226 if( name ==
"bad-format" )
1228 else if( name ==
"bad-namespace-prefix" )
1230 else if( name ==
"conflict" )
1232 else if( name ==
"connection-timeout" )
1234 else if( name ==
"host-gone" )
1236 else if( name ==
"host-unknown" )
1238 else if( name ==
"improper-addressing" )
1240 else if( name ==
"internal-server-error" )
1242 else if( name ==
"invalid-from" )
1244 else if( name ==
"invalid-id" )
1246 else if( name ==
"invalid-namespace" )
1248 else if( name ==
"invalid-xml" )
1250 else if( name ==
"not-authorized" )
1252 else if( name ==
"policy-violation" )
1254 else if( name ==
"remote-connection-failed" )
1256 else if( name ==
"resource-constraint" )
1258 else if( name ==
"restricted-xml" )
1260 else if( name ==
"see-other-host" )
1263 m_streamErrorCData = tag->
findChild(
"see-other-host" )->
cdata();
1265 else if( name ==
"system-shutdown" )
1267 else if( name ==
"undefined-condition" )
1269 else if( name ==
"unsupported-encoding" )
1271 else if( name ==
"unsupported-stanza-type" )
1273 else if( name ==
"unsupported-version" )
1275 else if( name ==
"xml-not-well-formed" )
1277 else if( name ==
"text" )
1279 const std::string& lang = (*it)->findAttribute(
"xml:lang" );
1281 m_streamErrorText[lang] = (*it)->cdata();
1283 m_streamErrorText[
"default"] = (*it)->cdata();
1286 m_streamErrorAppCondition = (*it);
1289 m_streamError = err;
1295 StringMap::const_iterator it = m_streamErrorText.find( lang );
1296 return ( it != m_streamErrorText.end() ) ? (*it).second :
EmptyString;
1302 m_messageSessionHandlerChat = msh;
1305 m_messageSessionHandlerNormal = msh;
1308 m_messageSessionHandlerGroupchat = msh;
1311 m_messageSessionHandlerHeadline = msh;
1317 m_presenceHandlers.push_back( ph );
1323 m_presenceHandlers.remove( ph );
1330 JidPresHandlerStruct jph;
1331 jph.jid =
new JID( jid.
bare() );
1333 m_presenceJidHandlers.push_back( jph );
1339 PresenceJidHandlerList::iterator t;
1340 PresenceJidHandlerList::iterator it = m_presenceJidHandlers.begin();
1341 while( it != m_presenceJidHandlers.end() )
1345 if( ( !ph || (*t).ph == ph ) && (*t).jid->bare() == jid.
bare() )
1348 m_presenceJidHandlers.erase( t );
1355 IqTrackMap::iterator t;
1356 m_iqHandlerMapMutex.
lock();
1357 IqTrackMap::iterator it = m_iqIDHandlers.begin();
1358 while( it != m_iqIDHandlers.end() )
1362 if( ih == (*t).second.ih )
1363 m_iqIDHandlers.erase( t );
1365 m_iqHandlerMapMutex.
unlock();
1374 typedef IqHandlerMap::const_iterator IQci;
1375 std::pair<IQci, IQci> g = m_iqExtHandlers.equal_range( exttype );
1376 for( IQci it = g.first; it != g.second; ++it )
1378 if( (*it).second == ih )
1382 m_iqExtHandlers.insert( std::make_pair( exttype, ih ) );
1391 typedef IqHandlerMap::iterator IQi;
1392 std::pair<IQi, IQi> g = m_iqExtHandlers.equal_range( exttype );
1395 while( it != g.second )
1398 if( (*it2).second == ih )
1399 m_iqExtHandlers.erase( it2 );
1406 m_messageSessions.push_back( session );
1414 MessageSessionList::iterator it = std::find( m_messageSessions.begin(),
1415 m_messageSessions.end(),
1417 if( it != m_messageSessions.end() )
1420 m_messageSessions.erase( it );
1427 m_messageHandlers.push_back( mh );
1433 m_messageHandlers.remove( mh );
1439 m_subscriptionHandlers.push_back( sh );
1445 m_subscriptionHandlers.remove( sh );
1450 if( th && !tag.empty() )
1452 TagHandlerStruct ths;
1456 m_tagHandlers.push_back( ths );
1464 for( TagHandlerList::iterator it = m_tagHandlers.begin(); it != m_tagHandlers.end(); )
1466 if( (*it).th == th && (*it).tag == tag && (*it).xmlns == xmlns )
1473 m_tagHandlers.erase( it++ );
1486 m_statisticsHandler = sh;
1491 m_statisticsHandler = 0;
1498 m_mucInvitationHandler = mih;
1505 m_mucInvitationHandler = 0;
1512 m_connectionListeners.push_back( cl );
1518 m_connectionListeners.remove( cl );
1534 ConnectionListenerList::const_iterator it = m_connectionListeners.begin();
1535 for( ; it != m_connectionListeners.end() && (*it)->onTLSConnect( info ); ++it )
1537 return m_stats.
encryption = ( it == m_connectionListeners.end() );
1560 void ClientBase::notifyPresenceHandlers(
Presence& pres )
1563 PresenceJidHandlerList::const_iterator t;
1564 PresenceJidHandlerList::const_iterator itj = m_presenceJidHandlers.begin();
1565 while( itj != m_presenceJidHandlers.end() )
1568 if( (*t).jid->bare() == pres.
from().
bare() && (*t).ph )
1570 (*t).ph->handlePresence( pres );
1578 PresenceHandlerList::const_iterator it = m_presenceHandlers.begin();
1579 for( ; it != m_presenceHandlers.end(); ++it )
1581 (*it)->handlePresence( pres );
1587 void ClientBase::notifySubscriptionHandlers( Subscription& s10n )
1590 SubscriptionHandlerList::const_iterator it = m_subscriptionHandlers.begin();
1591 for( ; it != m_subscriptionHandlers.end(); ++it )
1593 (*it)->handleSubscription( s10n );
1599 void ClientBase::notifyIqHandlers( IQ& iq )
1601 m_iqHandlerMapMutex.
lock();
1602 IqTrackMap::iterator it_id = m_iqIDHandlers.find( iq.id() );
1603 bool haveIdHandler = ( it_id != m_iqIDHandlers.end() );
1604 m_iqHandlerMapMutex.
unlock();
1607 (*it_id).second.ih->handleIqID( iq, (*it_id).second.context );
1608 if( (*it_id).second.del )
1609 delete (*it_id).second.ih;
1610 m_iqHandlerMapMutex.
lock();
1611 m_iqIDHandlers.erase( it_id );
1612 m_iqHandlerMapMutex.
unlock();
1616 if( iq.extensions().empty() )
1627 bool handled =
false;
1640 m_iqExtHandlerMapMutex.
lock();
1641 typedef IqHandlerMap::const_iterator IQci;
1643 StanzaExtensionList::const_iterator itse = sel.begin();
1644 for( ; !handled && itse != sel.end(); ++itse )
1646 std::pair<IQci, IQci> g = m_iqExtHandlers.equal_range( (*itse)->extensionType() );
1647 for( IQci it = g.first; !handled && it != g.second; ++it )
1649 if( (*it).second->handleIq( iq ) )
1653 m_iqExtHandlerMapMutex.
unlock();
1655 if( !handled && ( iq.subtype() ==
IQ::Get || iq.subtype() ==
IQ::Set ) )
1663 void ClientBase::notifyMessageHandlers( Message& msg )
1665 if( m_mucInvitationHandler )
1667 const MUCRoom::MUCUser* mu = msg.findExtension<MUCRoom::MUCUser>(
ExtMUCUser );
1672 mu->jid() ? JID( *(mu->jid()) ) : JID(),
1682 MessageSessionList::const_iterator it1 = m_messageSessions.begin();
1683 for( ; it1 != m_messageSessions.end(); ++it1 )
1685 if( (*it1)->target().full() == msg.from().full() &&
1686 ( msg.thread().empty()
1687 || (*it1)->threadID() == msg.thread()
1688 || (*it1)->honorThreadID() ) &&
1690 ( (*it1)->types() & msg.subtype() || (*it1)->types() == 0 ) )
1692 (*it1)->handleMessage( msg );
1697 it1 = m_messageSessions.begin();
1698 for( ; it1 != m_messageSessions.end(); ++it1 )
1700 if( (*it1)->target().bare() == msg.from().bare() &&
1701 ( msg.thread().empty()
1702 || (*it1)->threadID() == msg.thread()
1703 || (*it1)->honorThreadID() ) &&
1705 ( (*it1)->types() & msg.subtype() || (*it1)->types() == 0 ) )
1707 (*it1)->handleMessage( msg );
1712 MessageSessionHandler* msHandler = 0;
1714 switch( msg.subtype() )
1717 msHandler = m_messageSessionHandlerChat;
1720 msHandler = m_messageSessionHandlerNormal;
1723 msHandler = m_messageSessionHandlerGroupchat;
1726 msHandler = m_messageSessionHandlerHeadline;
1734 MessageSession* session =
new MessageSession(
this, msg.from(),
true, msg.subtype() );
1736 session->handleMessage( msg );
1741 MessageHandlerList::const_iterator it = m_messageHandlers.begin();
1742 for( ; it != m_messageHandlers.end(); ++it )
1744 (*it)->handleMessage( msg );
1751 void ClientBase::notifyTagHandlers( Tag* tag )
1753 TagHandlerList::const_iterator it = m_tagHandlers.begin();
1754 for( ; it != m_tagHandlers.end(); ++it )
1756 if( (*it).tag == tag->name() && tag->hasAttribute(
XMLNS, (*it).xmlns ) )
1757 (*it).th->handleTag( tag );
1775 if( (*it)->extensionType() == type )
1789 for(
int i = 0; i < 4; ++i )
1790 sprintf( cn + i*8,
"%08x", rand() );
1791 return std::string( cn, 4*8 );;
1809 TLSBase* ClientBase::getDefaultEncryption()
1814 TLSDefault*
tls =
new TLSDefault(
this,
m_server );
An abstract base class for a connection.
const TagList & children() const
const std::string & server() const
long int totalBytesReceived
virtual void handleMessageSession(MessageSession *session)=0
void processSASLChallenge(const std::string &challenge)
void addFeature(const std::string &feature)
void removeStatisticsHandler()
void registerEventHandler(EventHandler *eh, const std::string &context)
A simple implementation of a mutex guard.
void setServer(const std::string &server)
virtual void handleConnect(const ConnectionBase *connection)
std::list< const StanzaExtension * > StanzaExtensionList
long int messageStanzasSent
virtual void onConnect()=0
void removeIDHandler(IqHandler *ih)
ConnectionBase * m_connection
virtual void handleStatistics(const StatisticsStruct stats)=0
const std::string XMLNS_STREAM_TLS
void registerConnectionListener(ConnectionListener *cl)
An abstraction of a message session between any two entities.
void setClientCert(const std::string &clientKey, const std::string &clientCerts)
A virtual interface which can be reimplemented to receive incoming subscription stanzas.
void err(LogArea area, const std::string &message) const
const std::string XMLNS_STREAM_SASL
const std::string XMLNS_XMPP_PING
An base class for event handlers.
void registerMessageSessionHandler(MessageSessionHandler *msh, int types=0)
void clearList(std::list< T * > &L)
void registerSubscriptionHandler(SubscriptionHandler *sh)
void removeConnectionListener(ConnectionListener *cl)
An abstraction of an IQ stanza.
This is an abstract base class for stream compression implementations.
virtual const std::string channelBinding() const
void removeIqHandler(IqHandler *ih, int exttype)
void registerIqHandler(IqHandler *ih, int exttype)
const std::string XMPP_STREAM_VERSION_MAJOR
void addExtension(const StanzaExtension *se)
const std::string binary()
void removeTagHandler(TagHandler *th, const std::string &tag, const std::string &xmlns)
void registerMUCInvitationHandler(MUCInvitationHandler *mih)
void notifyOnResourceBind(const std::string &resource)
virtual bool encrypt(const std::string &data)=0
const std::string XMLNS_CLIENT
void registerMessageHandler(MessageHandler *mh)
void registerStanzaExtension(StanzaExtension *ext)
virtual void onSessionCreateError(const Error *error)
virtual void decompress(const std::string &data)=0
bool removePresenceExtension(int type)
virtual void onDisconnect(ConnectionError e)=0
std::list< Tag * > TagList
const TagList sendQueue()
virtual void onResourceBindError(const Error *error)
void notifyOnResourceBindError(const Error *error)
void setServer(const std::string &server, int port=-1)
StatisticsStruct getStatistics()
A virtual interface which can be reimplemented to receive incoming message sessions.
int extensionType() const
const std::string & streamErrorText(const std::string &lang="default") const
void addExtensions(Stanza &stanza, Tag *tag)
A stanza error abstraction implemented as a StanzaExtension.
virtual void disconnect()=0
virtual ConnectionError connect()=0
An abstraction of a presence stanza.
bool removeStanzaExtension(int ext)
bool setCData(const std::string &cdata)
Stanza * embeddedStanza() const
void removeMUCInvitationHandler()
This is an implementation of a simple TCP connection.
virtual void handleReceivedData(const ConnectionBase *connection, const std::string &data)
const std::string XMPP_STREAM_VERSION_MINOR
ConnectionState state() const
void clearMap(std::map< Key, T * > &M)
void addChild(Tag *child)
const std::string decode64(const std::string &input)
virtual void onResourceBind(const std::string &resource)
An abstraction of a message stanza.
bool processSASLSuccess(const std::string &payload)
long int totalStanzasReceived
void feed(const unsigned char *data, int bytes)
const std::string & bare() const
virtual void handleDecryptedData(const TLSBase *base, const std::string &data)
virtual Tag * tag() const
void removeMessageHandler(MessageHandler *mh)
The namespace for the gloox library.
A virtual interface which can be reimplemented to receive incoming message stanzas.
const std::string encode64(const std::string &input)
virtual void handleCompressedData(const std::string &data)
This class abstracts a stanza extension, which is usually an XML child element in a specific namespac...
virtual ConnectionError recv(int timeout=-1)
StanzaExtensionList m_presenceExtensions
void notifyOnSessionCreateError(const Error *error)
long int iqStanzasReceived
virtual bool send(const std::string &data)=0
A virtual interface which can be reimplemented to receive non-XMPP Core stanzas.
virtual void handleMUCInvitation(const JID &room, const JID &from, const std::string &reason, const std::string &body, const std::string &password, bool cont, const std::string &thread)=0
CompressionBase * m_compression
A virtual interface which can be reimplemented to receive presence stanzas.
const std::string & findAttribute(const std::string &name) const
bool removeExtension(int ext)
void xmppPing(const JID &to, EventHandler *eh)
bool hasAttribute(const std::string &name, const std::string &value=EmptyString) const
A Factory that creates StanzaExtensions from Tags.
virtual void disconnect(ConnectionError reason)
bool connect(bool block=true)
const std::string XMLNS_XMPP_STREAM
long int s10nStanzasReceived
void registerMessageSession(MessageSession *session)
virtual void handleDisconnect(const ConnectionBase *connection, ConnectionError reason)
const std::string cdata() const
virtual void handleTag(Tag *tag)
ClientBase(const std::string &ns, const std::string &server, int port=-1)
void disposeMessageSession(MessageSession *session)
void dispatch(const Event &event, const std::string &context, bool remove)
virtual bool checkStreamVersion(const std::string &version)
void feed(const unsigned char *data, unsigned length)
const std::string XMLNS_STREAM
const std::string GLOOX_VERSION
void removePresenceHandler(PresenceHandler *ph)
An implementation of SHA1.
virtual Tag * tag() const
void setVersion(const std::string &name, const std::string &version, const std::string &os=EmptyString)
virtual ConnectionError receive()=0
bool addAttribute(Attribute *attr)
virtual void onStreamEvent(StreamEvent event)
long int presenceStanzasReceived
virtual ConnectionError recv(int timeout=-1)=0
bool hasChild(const std::string &name, const std::string &attr=EmptyString, const std::string &value=EmptyString) const
virtual void handleHandshakeResult(const TLSBase *base, bool success, CertInfo &certinfo)
const std::string xmlns() const
void processSASLError(Tag *tag)
std::string m_clientCerts
const std::string & name() const
void registerPresenceHandler(PresenceHandler *ph)
A virtual interface which can be reimplemented to receive IQ stanzas.
virtual void getStatistics(long int &totalIn, long int &totalOut)=0
const std::string & username() const
bool saslprep(const std::string &input, std::string &out)
void setCompressionImpl(CompressionBase *cb)
A handler that can be used to receive invitations to MUC rooms.
virtual void handleEncryptedData(const TLSBase *base, const std::string &data)
This class implements XEP-0030 (Service Discovery) and XEP-0092 (Software Version).
const std::string getID()
const std::string xml() const
void dbg(LogArea area, const std::string &message) const
virtual void handleDecompressedData(const std::string &data)
const std::string & full() const
void setConnectionImpl(ConnectionBase *cb)
bool hasEmbeddedStanza() const
void notifyStreamEvent(StreamEvent event)
void setEncryptionImpl(TLSBase *tb)
An abstraction of a subscription stanza.
ConnectionState state() const
void removeSubscriptionHandler(SubscriptionHandler *sh)
void checkQueue(int handled, bool resend)
const std::string & server() const
virtual void compress(const std::string &data)=0
virtual const std::string & password() const
long int presenceStanzasSent
long int messageStanzasReceived
void removeFeature(const std::string &feature)
An abstract base class for TLS implementations.
void addPresenceExtension(StanzaExtension *se)
void registerExtension(StanzaExtension *ext)
void startSASL(SaslMechanism type)
Tag * findChild(const std::string &name) const
const std::string & id() const
Derived classes can be registered as ConnectionListeners with the Client.
const std::string binary()
void registerStatisticsHandler(StatisticsHandler *sh)
const std::string EmptyString
Tag * embeddedTag() const
const StanzaExtension * findExtension(int type) const
virtual Tag * tag() const
This is an abstraction of an XML element.
bool notifyOnTLSConnect(const CertInfo &info)
A virtual interface which can be reimplemented to receive connection statistics.
virtual Tag * tag() const
virtual int decrypt(const std::string &data)=0
int feed(std::string &data)
const std::string XMLNS_MUC
long int totalStanzasSent
void registerTagHandler(TagHandler *th, const std::string &tag, const std::string &xmlns)