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 +
"']";
94 ClientBase::ClientBase(
const std::string& ns,
const std::string& server,
int port )
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 ),
112 const std::string& server,
int port )
113 : m_connection( 0 ), m_encryption( 0 ), m_compression( 0 ), m_disco( 0 ), m_namespace( ns ),
114 m_password( password ),
115 m_xmllang(
"en" ), m_server( server ), m_compressionActive( false ), m_encryptionActive( false ),
116 m_compress( true ), m_authed( false ), m_resourceBound( false ), m_block( false ), m_sasl( true ),
118 m_availableSaslMechs(
SaslMechAll ), m_smContext( CtxSMInvalid ), m_smHandled( 0 ),
119 m_statisticsHandler( 0 ), m_mucInvitationHandler( 0 ),
120 m_messageSessionHandlerChat( 0 ), m_messageSessionHandlerGroupchat( 0 ),
121 m_messageSessionHandlerHeadline( 0 ), m_messageSessionHandlerNormal( 0 ),
124 m_selectedSaslMech(
SaslMechNone ), m_customConnection( false ),
130 void ClientBase::init()
132 srand(
static_cast<unsigned int>( time( 0 ) ) );
134 sha.
feed( util::long2string( time( 0 ) ) );
135 sha.
feed( util::int2string( rand() ) );
136 m_uniqueBaseId = sha.
hex();
151 memset( &m_stats, 0,
sizeof( m_stats ) );
157 m_iqHandlerMapMutex.
lock();
158 m_iqIDHandlers.clear();
159 m_iqHandlerMapMutex.
unlock();
161 m_iqExtHandlerMapMutex.
lock();
162 m_iqExtHandlers.clear();
163 m_iqExtHandlerMapMutex.
unlock();
178 PresenceJidHandlerList::const_iterator it1 = m_presenceJidHandlers.begin();
179 for( ; it1 != m_presenceJidHandlers.end(); ++it1 )
209 +
m_server + ( ( m_customConnection )?(
" using a custom connection" ):(
m_port > 0 ? (
":" + util::int2string(
m_port ) ) :
EmptyString ) ) +
"..." );
235 const std::string& version = tag->
findAttribute(
"version" );
239 " (it does not send a 'version' attribute). Please fix it or try another one.\n" );
245 handleStartNode( tag );
249 handleStreamError( tag );
254 if( !handleNormalNode( tag ) )
258 if( tag->
name() ==
"iq" )
264 notifyIqHandlers( iq );
269 else if( tag->
name() ==
"message" )
275 notifyMessageHandlers( msg );
280 else if( tag->
name() ==
"presence" )
283 if( type ==
"subscribe" || type ==
"unsubscribe"
284 || type ==
"subscribed" || type ==
"unsubscribed" )
290 notifySubscriptionHandlers( sub );
299 notifyPresenceHandlers( pres );
310 notifyTagHandlers( tag );
315 if( m_statisticsHandler )
401 notifyOnDisconnect( reason );
410 send(
"</stream:stream>" );
425 notifyOnDisconnect( reason );
427 #ifdef CLIENTBASE_TEST
432 void ClientBase::parse(
const std::string& data )
434 std::string copy = data;
436 if( ( i = m_parser.
feed( copy ) ) >= 0 )
438 std::string error =
"parse error (at pos ";
439 error += util::int2string( i );
442 Tag* e =
new Tag(
"stream:error" );
451 std::string head =
"<?xml version='1.0' ?>";
453 head +=
"xmlns:stream='http://etherx.jabber.org/streams' xml:lang='" +
m_xmllang +
"' ";
460 #if defined( HAVE_GNUTLS ) || defined( HAVE_OPENSSL ) || defined( HAVE_WINTLS )
487 m_selectedSaslMech = type;
506 m_gs2Header =
"p=tls-unique,";
512 m_gs2Header +=
"a=" + t;
516 m_clientFirstMessageBare =
"n=";
518 m_clientFirstMessageBare += t;
520 m_clientFirstMessageBare += t;
522 m_clientFirstMessageBare +=
",r=" +
getRandom();
557 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
572 "SASL GSSAPI is not supported on this platform. You should never see this." );
578 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
580 SEC_WINNT_AUTH_IDENTITY_W identity, *ident = 0;
581 memset( &identity, 0,
sizeof( identity ) );
583 WCHAR *usernameW = 0, *domainW = 0, *passwordW = 0;
584 int cchUsernameW = 0, cchDomainW = 0, cchPasswordW = 0;
591 cchUsernameW = ::MultiByteToWideChar( CP_UTF8, 0,
m_jid.
username().c_str(), -1, 0, 0 );
592 if( cchUsernameW > 0 )
594 usernameW =
new WCHAR[cchUsernameW];
595 ::MultiByteToWideChar( CP_UTF8, 0,
m_jid.
username().c_str(), -1, usernameW, cchUsernameW );
597 usernameW[cchUsernameW-1] = L
'\0';
599 cchDomainW = ::MultiByteToWideChar( CP_UTF8, 0, m_ntlmDomain.c_str(), -1, 0, 0 );
602 domainW =
new WCHAR[cchDomainW];
603 ::MultiByteToWideChar( CP_UTF8, 0, m_ntlmDomain.c_str(), -1, domainW, cchDomainW );
605 domainW[cchDomainW-1] = L
'\0';
607 cchPasswordW = ::MultiByteToWideChar( CP_UTF8, 0,
m_password.c_str(), -1, 0, 0 );
608 if( cchPasswordW > 0 )
610 passwordW =
new WCHAR[cchPasswordW];
611 ::MultiByteToWideChar( CP_UTF8, 0,
m_password.c_str(), -1, passwordW, cchPasswordW );
613 passwordW[cchPasswordW-1] = L
'\0';
615 identity.User = (
unsigned short*)usernameW;
616 identity.UserLength = (
unsigned long)cchUsernameW-1;
617 identity.Domain = (
unsigned short*)domainW;
618 identity.DomainLength = (
unsigned long)cchDomainW-1;
619 identity.Password = (
unsigned short*)passwordW;
620 identity.PasswordLength = (
unsigned long)cchPasswordW-1;
621 identity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
625 AcquireCredentialsHandleW( 0, L
"NTLM", SECPKG_CRED_OUTBOUND, 0, ident, 0, 0, &m_credHandle, 0 );
639 ::SecureZeroMemory( passwordW, cchPasswordW*
sizeof( WCHAR ) );
646 "SASL NTLM is not supported on this platform. You should never see this." );
657 std::string ClientBase::hmac(
const std::string& key,
const std::string& str )
660 std::string key_ = key;
661 if( key_.length() > 64 )
667 unsigned char ipad[65];
668 unsigned char opad[65];
669 memset( ipad,
'\0',
sizeof( ipad ) );
670 memset( opad,
'\0',
sizeof( opad ) );
671 memcpy( ipad, key_.c_str(), key_.length() );
672 memcpy( opad, key_.c_str(), key_.length() );
673 for(
int i = 0; i < 64; i++ )
678 sha.
feed( ipad, 64 );
682 sha.
feed( opad, 64 );
688 std::string ClientBase::hi(
const std::string& str,
const std::string& salt,
int iter )
691 memset( xored,
'\0',
sizeof( xored ) );
692 std::string tmp = salt;
693 tmp.append(
"\0\0\0\1", 4 );
694 for(
int i = 0; i < iter; ++i )
696 tmp = hmac( str, tmp );
697 for(
int j = 0; j < 20; ++j )
698 xored[j] ^= tmp.c_str()[j];
701 for(
int i=0; i < 20 ;++i )
702 n.push_back(
static_cast<char>( xored[i] ) );
713 switch( m_selectedSaslMech )
718 std::string snonce, salt, tmp;
720 std::string::size_type posn = decoded.find(
"r=" );
721 std::string::size_type poss = decoded.find(
"s=" );
722 std::string::size_type posi = decoded.find(
"i=" );
723 if( posn == std::string::npos || poss == std::string::npos || posi == std::string::npos )
726 snonce = decoded.substr( posn + 2, poss - posn - 3 );
728 tmp = decoded.substr( posi + 2, decoded.length() - posi - 2 );
729 iter = atoi( tmp.c_str() );
734 std::string saltedPwd = hi( tmp, salt, iter );
735 std::string ck = hmac( saltedPwd,
"Client Key" );
738 std::string storedKey = sha.
binary();
744 tmp +=
",r=" + snonce;
746 std::string authMessage = m_clientFirstMessageBare +
"," + decoded +
"," + tmp;
747 std::string clientSignature = hmac( storedKey, authMessage );
748 unsigned char clientProof[20];
749 memcpy( clientProof, ck.c_str(), 20 );
750 for(
int i = 0; i < 20; ++i )
751 clientProof[i] ^= clientSignature.c_str()[i];
752 std::string serverKey = hmac( saltedPwd,
"Server Key" );
753 m_serverSignature = hmac( serverKey, authMessage );
756 tmp.append(
Base64::encode64( std::string(
reinterpret_cast<const char*
>( clientProof ), 20 ) ) );
764 if( !decoded.compare( 0, 7,
"rspauth" ) )
768 std::string::size_type end = 0;
769 std::string::size_type pos = decoded.find(
"realm=" );
770 if( pos != std::string::npos )
772 end = decoded.find(
'"', pos + 7 );
773 realm = decoded.substr( pos + 7, end - ( pos + 7 ) );
778 pos = decoded.find(
"nonce=" );
779 if( pos == std::string::npos )
782 end = decoded.find(
'"', pos + 7 );
783 while( decoded[end-1] ==
'\\' )
784 end = decoded.find(
'"', end + 1 );
785 std::string nonce = decoded.substr( pos + 7, end - ( pos + 7 ) );
796 const std::string& a1_h = md5.
binary();
804 const std::string& a1 = md5.
hex();
806 md5.
feed(
"AUTHENTICATE:xmpp/" );
809 const std::string& a2 = md5.
hex();
814 md5.
feed(
":00000001:" );
816 md5.
feed(
":auth:" );
820 std::string response =
"username=\"";
822 response +=
"\",realm=\"";
824 response +=
"\",nonce=\"";
826 response +=
"\",cnonce=\"";
828 response +=
"\",nc=00000001,qop=auth,digest-uri=\"xmpp/";
830 response +=
"\",response=";
831 response += md5.
hex();
832 response +=
",charset=utf-8";
842 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
846 "Huh, received GSSAPI challenge?! This should have never happened!" );
851 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
852 bool type1 = ( decoded.length() < 7 ) ?
true :
false;
854 SecBuffer bufferIn = { type1 ? 0 : (
unsigned long)decoded.length(),
856 (
void*)decoded.c_str() };
857 SecBufferDesc secIn = { 0, 1, &bufferIn };
861 SecBuffer bufferOut = {
sizeof( buffer ), SECBUFFER_TOKEN, buffer };
862 SecBufferDesc secOut = { 0, 1, &bufferOut };
865 unsigned long contextAttr;
867 SECURITY_STATUS status = InitializeSecurityContext( &m_credHandle, type1 ? 0 : &m_ctxtHandle,
868 0, ISC_REQ_MUTUAL_AUTH, 0, 0, &secIn, 0,
869 &m_ctxtHandle, &secOut, &contextAttr,
871 std::string response;
872 if( SUCCEEDED( status ) )
874 response = std::string( (
const char *)bufferOut.pvBuffer, bufferOut.cbBuffer );
879 "InitializeSecurityContext() failed, return value "
880 + util::int2string( status ) );
886 "Huh, received NTLM challenge?! This should have never happened!" );
903 else if( tag->
hasChild(
"incorrect-encoding" ) )
905 else if( tag->
hasChild(
"invalid-authzid" ) )
907 else if( tag->
hasChild(
"invalid-mechanism" ) )
909 else if( tag->
hasChild(
"malformed-request" ) )
911 else if( tag->
hasChild(
"mechanism-too-weak" ) )
913 else if( tag->
hasChild(
"not-authorized" ) )
915 else if( tag->
hasChild(
"temporary-auth-failure" ) )
918 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
921 FreeCredentialsHandle( &m_credHandle );
922 DeleteSecurityContext( &m_ctxtHandle );
929 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
932 FreeCredentialsHandle( &m_credHandle );
933 DeleteSecurityContext( &m_ctxtHandle );
939 if( decoded.length() < 3 ||
Base64::decode64( decoded.substr( 2 ) ) != m_serverSignature )
950 if( iq.
id().empty() )
955 track.context = context;
957 m_iqHandlerMapMutex.
lock();
958 m_iqIDHandlers[iq.
id()] = track;
959 m_iqHandlerMapMutex.
unlock();
971 send( tag,
true,
false );
980 send( tag,
true,
false );
989 send( tag,
true,
false );
1000 addNamespace( tag );
1001 send( tag,
true,
false );
1009 send( tag,
false,
true );
1021 if( m_statisticsHandler )
1026 m_queueMutex.
lock();
1027 m_smQueue.insert( std::make_pair( ++m_smSent, tag ) );
1055 SMQueueMap::iterator it = m_smQueue.begin();
1056 while( it != m_smQueue.end() )
1058 if( (*it).first <= handled )
1060 delete (*it).second;
1061 m_smQueue.erase( it++ );
1063 else if( resend && (*it).first > handled )
1065 send( (*it).second,
false,
false );
1079 SMQueueMap::iterator it = m_smQueue.begin();
1080 for( ; it != m_smQueue.end(); ++it )
1081 l.push_back( (*it).second->clone() );
1086 void ClientBase::addFrom(
Tag* tag )
1094 void ClientBase::addNamespace( Tag* tag )
1096 if( !tag || !tag->xmlns().empty() )
1138 const std::string&
id =
getID();
1142 send( iq,
this, XMPPPing );
1145 bool ClientBase::handleIq(
const IQ& iq )
1158 void ClientBase::handleIqID(
const IQ& iq,
int context )
1160 if( context == XMPPPing )
1165 handleIqIDForward( iq, context );
1170 #ifdef CLIENTBASE_TEST
1171 return "uid" + util::int2string( m_nextId.
increment() );
1174 sprintf( r,
"%s%08x", m_uniqueBaseId.c_str(), m_nextId.
increment() );
1175 std::string ret( r, 48 );
1182 if( version.empty() )
1189 size_t dot = version.find(
'.' );
1190 if( !version.empty() && dot && dot != std::string::npos )
1192 major = atoi( version.substr( 0, dot ).c_str() );
1196 return myMajor >= major;
1203 m_customConnection =
true;
1224 void ClientBase::handleStreamError(
Tag* tag )
1228 TagList::const_iterator it = c.begin();
1229 for( ; it != c.end(); ++it )
1231 const std::string& name = (*it)->name();
1232 if( name ==
"bad-format" )
1234 else if( name ==
"bad-namespace-prefix" )
1236 else if( name ==
"conflict" )
1238 else if( name ==
"connection-timeout" )
1240 else if( name ==
"host-gone" )
1242 else if( name ==
"host-unknown" )
1244 else if( name ==
"improper-addressing" )
1246 else if( name ==
"internal-server-error" )
1248 else if( name ==
"invalid-from" )
1250 else if( name ==
"invalid-id" )
1252 else if( name ==
"invalid-namespace" )
1254 else if( name ==
"invalid-xml" )
1256 else if( name ==
"not-authorized" )
1258 else if( name ==
"policy-violation" )
1260 else if( name ==
"remote-connection-failed" )
1262 else if( name ==
"resource-constraint" )
1264 else if( name ==
"restricted-xml" )
1266 else if( name ==
"see-other-host" )
1269 m_streamErrorCData = tag->
findChild(
"see-other-host" )->
cdata();
1271 else if( name ==
"system-shutdown" )
1273 else if( name ==
"undefined-condition" )
1275 else if( name ==
"unsupported-encoding" )
1277 else if( name ==
"unsupported-stanza-type" )
1279 else if( name ==
"unsupported-version" )
1281 else if( name ==
"not-well-formed" )
1283 else if( name ==
"text" )
1285 const std::string& lang = (*it)->findAttribute(
"xml:lang" );
1287 m_streamErrorText[lang] = (*it)->cdata();
1289 m_streamErrorText[
"default"] = (*it)->cdata();
1292 m_streamErrorAppCondition = (*it);
1295 m_streamError = err;
1301 StringMap::const_iterator it = m_streamErrorText.find( lang );
1302 return ( it != m_streamErrorText.end() ) ? (*it).second :
EmptyString;
1308 m_messageSessionHandlerChat = msh;
1311 m_messageSessionHandlerNormal = msh;
1314 m_messageSessionHandlerGroupchat = msh;
1317 m_messageSessionHandlerHeadline = msh;
1323 m_presenceHandlers.push_back( ph );
1329 m_presenceHandlers.remove( ph );
1336 JidPresHandlerStruct jph;
1339 m_presenceJidHandlers.push_back( jph );
1345 PresenceJidHandlerList::iterator t;
1346 PresenceJidHandlerList::iterator it = m_presenceJidHandlers.begin();
1347 while( it != m_presenceJidHandlers.end() )
1351 if( ( !ph || (*t).ph == ph ) && (*t).jid->bare() ==
jid.
bare() )
1354 m_presenceJidHandlers.erase( t );
1361 IqTrackMap::iterator t;
1362 m_iqHandlerMapMutex.
lock();
1363 IqTrackMap::iterator it = m_iqIDHandlers.begin();
1364 while( it != m_iqIDHandlers.end() )
1368 if( ih == (*t).second.ih )
1369 m_iqIDHandlers.erase( t );
1371 m_iqHandlerMapMutex.
unlock();
1380 typedef IqHandlerMap::const_iterator IQci;
1381 std::pair<IQci, IQci> g = m_iqExtHandlers.equal_range( exttype );
1382 for( IQci it = g.first; it != g.second; ++it )
1384 if( (*it).second == ih )
1388 m_iqExtHandlers.insert( std::make_pair( exttype, ih ) );
1397 typedef IqHandlerMap::iterator IQi;
1398 std::pair<IQi, IQi> g = m_iqExtHandlers.equal_range( exttype );
1401 while( it != g.second )
1404 if( (*it2).second == ih )
1405 m_iqExtHandlers.erase( it2 );
1412 m_messageSessions.push_back( session );
1420 MessageSessionList::iterator it = std::find( m_messageSessions.begin(),
1421 m_messageSessions.end(),
1423 if( it != m_messageSessions.end() )
1426 m_messageSessions.erase( it );
1433 m_messageHandlers.push_back( mh );
1439 m_messageHandlers.remove( mh );
1445 m_subscriptionHandlers.push_back( sh );
1451 m_subscriptionHandlers.remove( sh );
1456 if( th && !tag.empty() )
1458 TagHandlerStruct ths;
1462 m_tagHandlers.push_back( ths );
1470 for( TagHandlerList::iterator it = m_tagHandlers.begin(); it != m_tagHandlers.end(); )
1472 if( (*it).th == th && (*it).tag == tag && (*it).xmlns == xmlns )
1479 m_tagHandlers.erase( it++ );
1492 m_statisticsHandler = sh;
1497 m_statisticsHandler = 0;
1504 m_mucInvitationHandler = mih;
1511 m_mucInvitationHandler = 0;
1518 m_connectionListeners.push_back( cl );
1524 m_connectionListeners.remove( cl );
1540 ConnectionListenerList::const_iterator it = m_connectionListeners.begin();
1541 for( ; it != m_connectionListeners.end() && (*it)->onTLSConnect( info ); ++it )
1543 return m_stats.
encryption = ( it == m_connectionListeners.end() );
1566 void ClientBase::notifyPresenceHandlers(
Presence& pres )
1569 PresenceJidHandlerList::const_iterator t;
1570 PresenceJidHandlerList::const_iterator itj = m_presenceJidHandlers.begin();
1571 while( itj != m_presenceJidHandlers.end() )
1574 if( (*t).jid->bare() == pres.
from().
bare() && (*t).ph )
1576 (*t).ph->handlePresence( pres );
1584 PresenceHandlerList::const_iterator it = m_presenceHandlers.begin();
1585 for( ; it != m_presenceHandlers.end(); ++it )
1587 (*it)->handlePresence( pres );
1593 void ClientBase::notifySubscriptionHandlers( Subscription& s10n )
1596 SubscriptionHandlerList::const_iterator it = m_subscriptionHandlers.begin();
1597 for( ; it != m_subscriptionHandlers.end(); ++it )
1599 (*it)->handleSubscription( s10n );
1605 void ClientBase::notifyIqHandlers( IQ& iq )
1607 m_iqHandlerMapMutex.
lock();
1608 IqTrackMap::iterator it_id = m_iqIDHandlers.find( iq.id() );
1609 bool haveIdHandler = ( it_id != m_iqIDHandlers.end() );
1610 m_iqHandlerMapMutex.
unlock();
1613 (*it_id).second.ih->handleIqID( iq, (*it_id).second.context );
1614 if( (*it_id).second.del )
1615 delete (*it_id).second.ih;
1616 m_iqHandlerMapMutex.
lock();
1617 m_iqIDHandlers.erase( it_id );
1618 m_iqHandlerMapMutex.
unlock();
1622 if( iq.extensions().empty() )
1633 bool handled =
false;
1646 m_iqExtHandlerMapMutex.
lock();
1647 typedef IqHandlerMap::const_iterator IQci;
1649 StanzaExtensionList::const_iterator itse = sel.begin();
1650 for( ; !handled && itse != sel.end(); ++itse )
1652 std::pair<IQci, IQci> g = m_iqExtHandlers.equal_range( (*itse)->extensionType() );
1653 for( IQci it = g.first; !handled && it != g.second; ++it )
1655 if( (*it).second->handleIq( iq ) )
1659 m_iqExtHandlerMapMutex.
unlock();
1661 if( !handled && ( iq.subtype() ==
IQ::Get || iq.subtype() ==
IQ::Set ) )
1669 void ClientBase::notifyMessageHandlers( Message& msg )
1671 if( m_mucInvitationHandler )
1673 const MUCRoom::MUCUser* mu = msg.findExtension<MUCRoom::MUCUser>(
ExtMUCUser );
1678 mu->jid() ? JID( *(mu->jid()) ) : JID(),
1688 MessageSessionList::const_iterator it1 = m_messageSessions.begin();
1689 for( ; it1 != m_messageSessions.end(); ++it1 )
1691 if( (*it1)->target().full() == msg.from().full() &&
1692 ( msg.thread().empty()
1693 || (*it1)->threadID() == msg.thread()
1694 || !(*it1)->honorThreadID() ) &&
1696 ( (*it1)->types() & msg.subtype() || (*it1)->types() == 0 ) )
1698 (*it1)->handleMessage( msg );
1703 it1 = m_messageSessions.begin();
1704 for( ; it1 != m_messageSessions.end(); ++it1 )
1706 if( (*it1)->target().bare() == msg.from().bare() &&
1707 ( msg.thread().empty()
1708 || (*it1)->threadID() == msg.thread()
1709 || !(*it1)->honorThreadID() ) &&
1711 ( (*it1)->types() & msg.subtype() || (*it1)->types() == 0 ) )
1713 (*it1)->handleMessage( msg );
1718 MessageSessionHandler* msHandler = 0;
1720 switch( msg.subtype() )
1723 msHandler = m_messageSessionHandlerChat;
1726 msHandler = m_messageSessionHandlerNormal;
1729 msHandler = m_messageSessionHandlerGroupchat;
1732 msHandler = m_messageSessionHandlerHeadline;
1740 MessageSession* session =
new MessageSession(
this, msg.from(),
true, msg.subtype() );
1741 msHandler->handleMessageSession( session );
1742 session->handleMessage( msg );
1747 MessageHandlerList::const_iterator it = m_messageHandlers.begin();
1748 for( ; it != m_messageHandlers.end(); ++it )
1750 (*it)->handleMessage( msg );
1757 void ClientBase::notifyTagHandlers( Tag* tag )
1759 TagHandlerList::const_iterator it = m_tagHandlers.begin();
1760 for( ; it != m_tagHandlers.end(); ++it )
1762 if( (*it).tag == tag->name() && tag->hasAttribute(
XMLNS, (*it).xmlns ) )
1763 (*it).th->handleTag( tag );
1781 if( (*it)->extensionType() == type )
1795 for(
int i = 0; i < 4; ++i )
1796 sprintf( cn + i*8,
"%08x", rand() );
1797 return std::string( cn, 4*8 );;
1815 TLSBase* ClientBase::getDefaultEncryption()
1820 TLSDefault*
tls =
new TLSDefault(
this,
m_server );
const std::string getID()
virtual void handleEncryptedData(const TLSBase *base, const std::string &data)
void addPresenceExtension(StanzaExtension *se)
const std::string & server() const
void processSASLError(Tag *tag)
std::string m_clientCerts
void registerMessageSessionHandler(MessageSessionHandler *msh, int types=0)
void registerStatisticsHandler(StatisticsHandler *sh)
void setCompressionImpl(CompressionBase *cb)
virtual void handleDisconnect(const ConnectionBase *connection, ConnectionError reason)
void registerPresenceHandler(PresenceHandler *ph)
void xmppPing(const JID &to, EventHandler *eh)
virtual void handleCompressedData(const std::string &data)
bool removePresenceExtension(int type)
virtual ConnectionError recv(int timeout=-1)
void checkQueue(int handled, bool resend)
void removeSubscriptionHandler(SubscriptionHandler *sh)
void registerConnectionListener(ConnectionListener *cl)
void processSASLChallenge(const std::string &challenge)
virtual void handleTag(Tag *tag)
ConnectionState state() const
void registerMessageHandler(MessageHandler *mh)
const std::string & streamErrorText(const std::string &lang="default") const
StanzaExtensionList m_presenceExtensions
virtual void handleConnect(const ConnectionBase *connection)
virtual void handleReceivedData(const ConnectionBase *connection, const std::string &data)
void removeIqHandler(IqHandler *ih, int exttype)
StatisticsStruct getStatistics()
bool processSASLSuccess(const std::string &payload)
virtual void handleDecompressedData(const std::string &data)
void setClientCert(const std::string &clientKey, const std::string &clientCerts)
virtual void handleDecryptedData(const TLSBase *base, const std::string &data)
void registerSubscriptionHandler(SubscriptionHandler *sh)
void removeStatisticsHandler()
void notifyOnSessionCreateError(const Error *error)
bool notifyOnTLSConnect(const CertInfo &info)
void removeIDHandler(IqHandler *ih)
ClientBase(const std::string &ns, const std::string &server, int port=-1)
CompressionBase * m_compression
virtual void disconnect(ConnectionError reason)
virtual bool checkStreamVersion(const std::string &version)
void setEncryptionImpl(TLSBase *tb)
bool removeStanzaExtension(int ext)
bool connect(bool block=true)
void removeMUCInvitationHandler()
const TagList sendQueue()
void setConnectionImpl(ConnectionBase *cb)
void disposeMessageSession(MessageSession *session)
void removeTagHandler(TagHandler *th, const std::string &tag, const std::string &xmlns)
void registerTagHandler(TagHandler *th, const std::string &tag, const std::string &xmlns)
void removeConnectionListener(ConnectionListener *cl)
void notifyOnResourceBindError(const Error *error)
virtual const std::string & password() const
void registerIqHandler(IqHandler *ih, int exttype)
virtual void handleHandshakeResult(const TLSBase *base, bool success, CertInfo &certinfo)
void removeMessageHandler(MessageHandler *mh)
void registerMessageSession(MessageSession *session)
void setServer(const std::string &server)
void startSASL(SaslMechanism type)
void notifyStreamEvent(StreamEvent event)
void registerStanzaExtension(StanzaExtension *ext)
ConnectionBase * m_connection
void registerMUCInvitationHandler(MUCInvitationHandler *mih)
void removePresenceHandler(PresenceHandler *ph)
void notifyOnResourceBind(const std::string &resource)
This is an abstract base class for stream compression implementations.
virtual void compress(const std::string &data)=0
virtual void decompress(const std::string &data)=0
An abstract base class for a connection.
ConnectionState state() const
virtual ConnectionError recv(int timeout=-1)=0
virtual bool send(const std::string &data)=0
virtual ConnectionError connect()=0
virtual ConnectionError receive()=0
virtual void getStatistics(long int &totalIn, long int &totalOut)=0
virtual void disconnect()=0
void setServer(const std::string &server, int port=-1)
Derived classes can be registered as ConnectionListeners with the Client.
virtual void onConnect()=0
virtual void onDisconnect(ConnectionError e)=0
virtual void onResourceBind(const std::string &resource)
virtual void onResourceBindError(const Error *error)
virtual void onStreamEvent(StreamEvent event)
virtual void onSessionCreateError(const Error *error)
This is an implementation of a simple TCP connection.
This class implements XEP-0030 (Service Discovery) and XEP-0092 (Software Version).
void removeFeature(const std::string &feature)
void addFeature(const std::string &feature)
void setVersion(const std::string &name, const std::string &version, const std::string &os=EmptyString)
A stanza error abstraction implemented as a StanzaExtension.
void registerEventHandler(EventHandler *eh, const std::string &context)
void dispatch(const Event &event, const std::string &context, bool remove)
An base class for event handlers.
An abstraction of an IQ stanza.
virtual Tag * tag() const
A virtual interface which can be reimplemented to receive IQ stanzas.
const std::string & server() const
const std::string & username() const
const std::string & full() const
const std::string & bare() const
void dbg(LogArea area, const std::string &message) const
void err(LogArea area, const std::string &message) const
void feed(const unsigned char *data, int bytes)
const std::string binary()
A handler that can be used to receive invitations to MUC rooms.
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
A virtual interface which can be reimplemented to receive incoming message stanzas.
A virtual interface which can be reimplemented to receive incoming message sessions.
An abstraction of a message session between any two entities.
An abstraction of a message stanza.
virtual Tag * tag() const
int feed(std::string &data)
A virtual interface which can be reimplemented to receive presence stanzas.
An abstraction of a presence stanza.
virtual Tag * tag() const
An implementation of SHA1.
void feed(const unsigned char *data, unsigned length)
const std::string binary()
A Factory that creates StanzaExtensions from Tags.
void registerExtension(StanzaExtension *ext)
void addExtensions(Stanza &stanza, Tag *tag)
bool removeExtension(int ext)
This class abstracts a stanza extension, which is usually an XML child element in a specific namespac...
int extensionType() const
void addExtension(const StanzaExtension *se)
Stanza * embeddedStanza() const
Tag * embeddedTag() const
bool hasEmbeddedStanza() const
const std::string & id() const
const StanzaExtension * findExtension(int type) const
A virtual interface which can be reimplemented to receive connection statistics.
virtual void handleStatistics(const StatisticsStruct stats)=0
A virtual interface which can be reimplemented to receive incoming subscription stanzas.
An abstraction of a subscription stanza.
virtual Tag * tag() const
An abstract base class for TLS implementations.
virtual bool encrypt(const std::string &data)=0
virtual int decrypt(const std::string &data)=0
virtual const std::string channelBinding() const
A virtual interface which can be reimplemented to receive non-XMPP Core stanzas.
This is an abstraction of an XML element.
Tag * findChild(const std::string &name) const
bool setCData(const std::string &cdata)
const std::string xmlns() const
bool addAttribute(Attribute *attr)
bool hasChild(const std::string &name, const std::string &attr=EmptyString, const std::string &value=EmptyString) const
void addChild(Tag *child)
bool hasAttribute(const std::string &name, const std::string &value=EmptyString) const
const std::string cdata() const
const std::string & findAttribute(const std::string &name) const
const std::string & name() const
const std::string xml() const
const TagList & children() const
A simple implementation of a mutex guard.
const std::string decode64(const std::string &input)
const std::string encode64(const std::string &input)
bool saslprep(const std::string &input, std::string &out)
void clearMap(std::map< Key, T * > &M)
void clearList(std::list< T * > &L)
The namespace for the gloox library.
const std::string XMLNS_STREAM
std::list< Tag * > TagList
const std::string GLOOX_VERSION
const std::string XMLNS_XMPP_PING
const std::string XMLNS_XMPP_STREAM
std::list< const StanzaExtension * > StanzaExtensionList
const std::string XMPP_STREAM_VERSION_MAJOR
@ SaslTemporaryAuthFailure
const std::string XMLNS_CLIENT
const std::string XMLNS_STREAM_SASL
const std::string XMPP_STREAM_VERSION_MINOR
const std::string EmptyString
@ StanzaErrorServiceUnavailable
@ StanzaErrorFeatureNotImplemented
@ StreamErrorBadNamespacePrefix
@ StreamErrorPolicyViolation
@ StreamErrorSeeOtherHost
@ StreamErrorRemoteConnectionFailed
@ StreamErrorRestrictedXml
@ StreamErrorImproperAddressing
@ StreamErrorInvalidNamespace
@ StreamErrorResourceConstraint
@ StreamErrorInternalServerError
@ StreamErrorUnsupportedEncoding
@ StreamErrorUnsupportedStanzaType
@ StreamErrorSystemShutdown
@ StreamErrorUnsupportedVersion
@ StreamErrorConnectionTimeout
@ StreamErrorNotAuthorized
@ StreamErrorXmlNotWellFormed
@ StreamErrorUndefinedCondition
const std::string XMLNS_STREAM_TLS
const std::string XMLNS_MUC
long int totalStanzasSent
long int messageStanzasSent
long int messageStanzasReceived
long int iqStanzasReceived
long int totalStanzasReceived
long int totalBytesReceived
long int presenceStanzasReceived
long int s10nStanzasReceived
long int presenceStanzasSent