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_block( false ), m_sasl( true ), m_tls(
TLSOptional ), m_port( port ),
98 m_availableSaslMechs(
SaslMechAll ), m_smContext( CtxSMInvalid ), m_smHandled( 0 ),
99 m_statisticsHandler( 0 ), m_mucInvitationHandler( 0 ),
100 m_messageSessionHandlerChat( 0 ), m_messageSessionHandlerGroupchat( 0 ),
101 m_messageSessionHandlerHeadline( 0 ), m_messageSessionHandlerNormal( 0 ),
104 m_selectedSaslMech(
SaslMechNone ), m_customConnection( false ),
105 m_uniqueBaseId( (unsigned int)( ( (unsigned long long)time( 0 ) & 0xFFFF ) << 16 ) | ( ( (unsigned long long) & m_nextId ) & 0xFFFF ) ),
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_block( false ), m_sasl( true ), m_tls(
TLSOptional ),
117 m_port( port ), m_availableSaslMechs(
SaslMechAll ), m_smContext( CtxSMInvalid ), m_smHandled( 0 ),
118 m_statisticsHandler( 0 ), m_mucInvitationHandler( 0 ),
119 m_messageSessionHandlerChat( 0 ), m_messageSessionHandlerGroupchat( 0 ),
120 m_messageSessionHandlerHeadline( 0 ), m_messageSessionHandlerNormal( 0 ),
123 m_selectedSaslMech(
SaslMechNone ), m_customConnection( false ),
124 m_uniqueBaseId( (unsigned int)( ( (unsigned long long)time( 0 ) & 0xFFFF ) << 16 ) | ( ( (unsigned long long) & m_nextId ) & 0xFFFF ) ),
130 void ClientBase::init()
147 memset( &m_stats, 0,
sizeof( m_stats ) );
153 m_iqHandlerMapMutex.
lock();
154 m_iqIDHandlers.clear();
155 m_iqHandlerMapMutex.
unlock();
157 m_iqExtHandlerMapMutex.
lock();
158 m_iqExtHandlers.clear();
159 m_iqExtHandlerMapMutex.
unlock();
174 PresenceJidHandlerList::const_iterator it1 = m_presenceJidHandlers.begin();
175 for( ; it1 != m_presenceJidHandlers.end(); ++it1 )
205 +
m_server + ( ( m_customConnection )?(
" using a custom connection" ):(
m_port > 0 ? (
":" + util::int2string(
m_port ) ) :
EmptyString ) ) +
"..." );
231 const std::string& version = tag->
findAttribute(
"version" );
235 " (it does not send a 'version' attribute). Please fix it or try another one.\n" );
241 handleStartNode( tag );
245 handleStreamError( tag );
250 if( !handleNormalNode( tag ) )
254 if( tag->
name() ==
"iq" )
260 notifyIqHandlers( iq );
265 else if( tag->
name() ==
"message" )
271 notifyMessageHandlers( msg );
276 else if( tag->
name() ==
"presence" )
279 if( type ==
"subscribe" || type ==
"unsubscribe"
280 || type ==
"subscribed" || type ==
"unsubscribed" )
286 notifySubscriptionHandlers( sub );
295 notifyPresenceHandlers( pres );
306 notifyTagHandlers( tag );
311 if( m_statisticsHandler )
397 notifyOnDisconnect( reason );
406 send(
"</stream:stream>" );
421 notifyOnDisconnect( reason );
423 #ifdef CLIENTBASE_TEST
428 void ClientBase::parse(
const std::string& data )
430 std::string copy = data;
432 if( ( i = m_parser.
feed( copy ) ) >= 0 )
434 std::string error =
"parse error (at pos ";
435 error += util::int2string( i );
438 Tag* e =
new Tag(
"stream:error" );
447 std::string head =
"<?xml version='1.0' ?>";
449 head +=
"xmlns:stream='http://etherx.jabber.org/streams' xml:lang='" +
m_xmllang +
"' ";
456 #if defined( HAVE_GNUTLS ) || defined( HAVE_OPENSSL ) || defined( HAVE_WINTLS )
483 m_selectedSaslMech = type;
502 m_gs2Header =
"p=tls-unique,";
508 m_gs2Header +=
"a=" + t;
512 m_clientFirstMessageBare =
"n=";
514 m_clientFirstMessageBare += t;
516 m_clientFirstMessageBare += t;
518 m_clientFirstMessageBare +=
",r=" +
getRandom();
553 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
568 "SASL GSSAPI is not supported on this platform. You should never see this." );
574 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
576 SEC_WINNT_AUTH_IDENTITY_W identity, *ident = 0;
577 memset( &identity, 0,
sizeof( identity ) );
579 WCHAR *usernameW = 0, *domainW = 0, *passwordW = 0;
580 int cchUsernameW = 0, cchDomainW = 0, cchPasswordW = 0;
587 cchUsernameW = ::MultiByteToWideChar( CP_UTF8, 0,
m_jid.
username().c_str(), -1, 0, 0 );
588 if( cchUsernameW > 0 )
590 usernameW =
new WCHAR[cchUsernameW];
591 ::MultiByteToWideChar( CP_UTF8, 0,
m_jid.
username().c_str(), -1, usernameW, cchUsernameW );
593 usernameW[cchUsernameW-1] = L
'\0';
595 cchDomainW = ::MultiByteToWideChar( CP_UTF8, 0, m_ntlmDomain.c_str(), -1, 0, 0 );
598 domainW =
new WCHAR[cchDomainW];
599 ::MultiByteToWideChar( CP_UTF8, 0, m_ntlmDomain.c_str(), -1, domainW, cchDomainW );
601 domainW[cchDomainW-1] = L
'\0';
603 cchPasswordW = ::MultiByteToWideChar( CP_UTF8, 0,
m_password.c_str(), -1, 0, 0 );
604 if( cchPasswordW > 0 )
606 passwordW =
new WCHAR[cchPasswordW];
607 ::MultiByteToWideChar( CP_UTF8, 0,
m_password.c_str(), -1, passwordW, cchPasswordW );
609 passwordW[cchPasswordW-1] = L
'\0';
611 identity.User = (
unsigned short*)usernameW;
612 identity.UserLength = (
unsigned long)cchUsernameW-1;
613 identity.Domain = (
unsigned short*)domainW;
614 identity.DomainLength = (
unsigned long)cchDomainW-1;
615 identity.Password = (
unsigned short*)passwordW;
616 identity.PasswordLength = (
unsigned long)cchPasswordW-1;
617 identity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
621 AcquireCredentialsHandleW( 0, L
"NTLM", SECPKG_CRED_OUTBOUND, 0, ident, 0, 0, &m_credHandle, 0 );
635 ::SecureZeroMemory( passwordW, cchPasswordW*
sizeof( WCHAR ) );
642 "SASL NTLM is not supported on this platform. You should never see this." );
653 std::string ClientBase::hmac(
const std::string& key,
const std::string& str )
656 std::string key_ = key;
657 if( key_.length() > 64 )
663 unsigned char ipad[65];
664 unsigned char opad[65];
665 memset( ipad,
'\0',
sizeof( ipad ) );
666 memset( opad,
'\0',
sizeof( opad ) );
667 memcpy( ipad, key_.c_str(), key_.length() );
668 memcpy( opad, key_.c_str(), key_.length() );
669 for(
int i = 0; i < 64; i++ )
674 sha.
feed( ipad, 64 );
678 sha.
feed( opad, 64 );
684 std::string ClientBase::hi(
const std::string& str,
const std::string& salt,
int iter )
686 unsigned char xored[20];
687 memset( xored,
'\0',
sizeof( xored ) );
688 std::string tmp = salt;
689 tmp.append(
"\0\0\0\1", 4 );
690 for(
int i = 0; i < iter; ++i )
692 tmp = hmac( str, tmp );
693 for(
int j = 0; j < 20; ++j )
694 xored[j] ^= tmp.c_str()[j];
696 return std::string( (
char*)xored, 20 );
705 switch( m_selectedSaslMech )
710 std::string snonce, salt, tmp;
712 std::string::size_type posn = decoded.find(
"r=" );
713 std::string::size_type poss = decoded.find(
"s=" );
714 std::string::size_type posi = decoded.find(
"i=" );
715 if( posn == std::string::npos || poss == std::string::npos || posi == std::string::npos )
718 snonce = decoded.substr( posn + 2, poss - posn - 3 );
720 tmp = decoded.substr( posi + 2, decoded.length() - posi - 2 );
721 iter = atoi( tmp.c_str() );
726 std::string saltedPwd = hi( tmp, salt, iter );
727 std::string ck = hmac( saltedPwd,
"Client Key" );
730 std::string storedKey = sha.
binary();
736 tmp +=
",r=" + snonce;
738 std::string authMessage = m_clientFirstMessageBare +
"," + decoded +
"," + tmp;
739 std::string clientSignature = hmac( storedKey, authMessage );
740 unsigned char clientProof[20];
741 memcpy( clientProof, ck.c_str(), 20 );
742 for(
int i = 0; i < 20; ++i )
743 clientProof[i] ^= clientSignature.c_str()[i];
744 std::string serverKey = hmac( saltedPwd,
"Server Key" );
745 m_serverSignature = hmac( serverKey, authMessage );
756 if( !decoded.compare( 0, 7,
"rspauth" ) )
760 std::string::size_type end = 0;
761 std::string::size_type pos = decoded.find(
"realm=" );
762 if( pos != std::string::npos )
764 end = decoded.find(
'"', pos + 7 );
765 realm = decoded.substr( pos + 7, end - ( pos + 7 ) );
770 pos = decoded.find(
"nonce=" );
771 if( pos == std::string::npos )
774 end = decoded.find(
'"', pos + 7 );
775 while( decoded[end-1] ==
'\\' )
776 end = decoded.find(
'"', end + 1 );
777 std::string nonce = decoded.substr( pos + 7, end - ( pos + 7 ) );
788 const std::string& a1_h = md5.
binary();
796 const std::string& a1 = md5.
hex();
798 md5.
feed(
"AUTHENTICATE:xmpp/" );
801 const std::string& a2 = md5.
hex();
806 md5.
feed(
":00000001:" );
808 md5.
feed(
":auth:" );
812 std::string response =
"username=\"";
814 response +=
"\",realm=\"";
816 response +=
"\",nonce=\"";
818 response +=
"\",cnonce=\"";
820 response +=
"\",nc=00000001,qop=auth,digest-uri=\"xmpp/";
822 response +=
"\",response=";
823 response += md5.
hex();
824 response +=
",charset=utf-8";
834 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
838 "Huh, received GSSAPI challenge?! This should have never happened!" );
843 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
844 bool type1 = ( decoded.length() < 7 ) ?
true :
false;
846 SecBuffer bufferIn = { type1 ? 0 : (
unsigned long)decoded.length(),
848 (
void*)decoded.c_str() };
849 SecBufferDesc secIn = { 0, 1, &bufferIn };
853 SecBuffer bufferOut = {
sizeof( buffer ), SECBUFFER_TOKEN, buffer };
854 SecBufferDesc secOut = { 0, 1, &bufferOut };
857 unsigned long contextAttr;
859 SECURITY_STATUS status = InitializeSecurityContext( &m_credHandle, type1 ? 0 : &m_ctxtHandle,
860 0, ISC_REQ_MUTUAL_AUTH, 0, 0, &secIn, 0,
861 &m_ctxtHandle, &secOut, &contextAttr,
863 std::string response;
864 if( SUCCEEDED( status ) )
866 response = std::string( (
const char *)bufferOut.pvBuffer, bufferOut.cbBuffer );
871 "InitializeSecurityContext() failed, return value "
872 + util::int2string( status ) );
878 "Huh, received NTLM challenge?! This should have never happened!" );
895 else if( tag->
hasChild(
"incorrect-encoding" ) )
897 else if( tag->
hasChild(
"invalid-authzid" ) )
899 else if( tag->
hasChild(
"invalid-mechanism" ) )
901 else if( tag->
hasChild(
"malformed-request" ) )
903 else if( tag->
hasChild(
"mechanism-too-weak" ) )
905 else if( tag->
hasChild(
"not-authorized" ) )
907 else if( tag->
hasChild(
"temporary-auth-failure" ) )
910 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
913 FreeCredentialsHandle( &m_credHandle );
914 DeleteSecurityContext( &m_ctxtHandle );
921 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
924 FreeCredentialsHandle( &m_credHandle );
925 DeleteSecurityContext( &m_ctxtHandle );
931 if( decoded.length() < 3 ||
Base64::decode64( decoded.substr( 2 ) ) != m_serverSignature )
942 if( iq.
id().empty() )
947 track.context = context;
949 m_iqHandlerMapMutex.
lock();
950 m_iqIDHandlers[iq.
id()] = track;
951 m_iqHandlerMapMutex.
unlock();
963 send( tag,
true,
false );
972 send( tag,
true,
false );
981 send( tag,
true,
false );
993 send( tag,
true,
false );
1001 send( tag,
false,
true );
1013 if( m_statisticsHandler )
1018 m_queueMutex.
lock();
1019 m_smQueue.insert( std::make_pair( ++m_smSent, tag ) );
1047 SMQueueMap::iterator it = m_smQueue.begin();
1048 while( it != m_smQueue.end() )
1050 if( (*it).first <= handled )
1052 delete (*it).second;
1053 m_smQueue.erase( it++ );
1055 else if( resend && (*it).first > handled )
1057 send( (*it).second,
false,
false );
1071 SMQueueMap::iterator it = m_smQueue.begin();
1072 for( ; it != m_smQueue.end(); ++it )
1073 l.push_back( (*it).second->clone() );
1078 void ClientBase::addFrom(
Tag* tag )
1086 void ClientBase::addNamespace( Tag* tag )
1088 if( !tag || !tag->xmlns().empty() )
1130 const std::string&
id =
getID();
1134 send( iq,
this, XMPPPing );
1137 bool ClientBase::handleIq(
const IQ& iq )
1150 void ClientBase::handleIqID(
const IQ& iq,
int context )
1152 if( context == XMPPPing )
1157 handleIqIDForward( iq, context );
1162 #ifdef CLIENTBASE_TEST // to create predictable UIDs in test mode
1163 return "uid" + util::int2string( m_nextId.
increment() );
1166 sprintf( r,
"uid-%08x-%08x", m_uniqueBaseId, m_nextId.
increment() );
1167 std::string ret( r, 21 );
1174 if( version.empty() )
1181 size_t dot = version.find(
'.' );
1182 if( !version.empty() && dot && dot != std::string::npos )
1184 major = atoi( version.substr( 0, dot ).c_str() );
1188 return myMajor >= major;
1195 m_customConnection =
true;
1216 void ClientBase::handleStreamError(
Tag* tag )
1220 TagList::const_iterator it = c.begin();
1221 for( ; it != c.end(); ++it )
1223 const std::string& name = (*it)->name();
1224 if( name ==
"bad-format" )
1226 else if( name ==
"bad-namespace-prefix" )
1228 else if( name ==
"conflict" )
1230 else if( name ==
"connection-timeout" )
1232 else if( name ==
"host-gone" )
1234 else if( name ==
"host-unknown" )
1236 else if( name ==
"improper-addressing" )
1238 else if( name ==
"internal-server-error" )
1240 else if( name ==
"invalid-from" )
1242 else if( name ==
"invalid-id" )
1244 else if( name ==
"invalid-namespace" )
1246 else if( name ==
"invalid-xml" )
1248 else if( name ==
"not-authorized" )
1250 else if( name ==
"policy-violation" )
1252 else if( name ==
"remote-connection-failed" )
1254 else if( name ==
"resource-constraint" )
1256 else if( name ==
"restricted-xml" )
1258 else if( name ==
"see-other-host" )
1261 m_streamErrorCData = tag->
findChild(
"see-other-host" )->
cdata();
1263 else if( name ==
"system-shutdown" )
1265 else if( name ==
"undefined-condition" )
1267 else if( name ==
"unsupported-encoding" )
1269 else if( name ==
"unsupported-stanza-type" )
1271 else if( name ==
"unsupported-version" )
1273 else if( name ==
"xml-not-well-formed" )
1275 else if( name ==
"text" )
1277 const std::string& lang = (*it)->findAttribute(
"xml:lang" );
1279 m_streamErrorText[lang] = (*it)->cdata();
1281 m_streamErrorText[
"default"] = (*it)->cdata();
1284 m_streamErrorAppCondition = (*it);
1287 m_streamError = err;
1293 StringMap::const_iterator it = m_streamErrorText.find( lang );
1294 return ( it != m_streamErrorText.end() ) ? (*it).second :
EmptyString;
1300 m_messageSessionHandlerChat = msh;
1303 m_messageSessionHandlerNormal = msh;
1306 m_messageSessionHandlerGroupchat = msh;
1309 m_messageSessionHandlerHeadline = msh;
1315 m_presenceHandlers.push_back( ph );
1321 m_presenceHandlers.remove( ph );
1328 JidPresHandlerStruct jph;
1329 jph.jid =
new JID( jid.
bare() );
1331 m_presenceJidHandlers.push_back( jph );
1337 PresenceJidHandlerList::iterator t;
1338 PresenceJidHandlerList::iterator it = m_presenceJidHandlers.begin();
1339 while( it != m_presenceJidHandlers.end() )
1343 if( ( !ph || (*t).ph == ph ) && (*t).jid->bare() == jid.
bare() )
1346 m_presenceJidHandlers.erase( t );
1353 IqTrackMap::iterator t;
1354 m_iqHandlerMapMutex.
lock();
1355 IqTrackMap::iterator it = m_iqIDHandlers.begin();
1356 while( it != m_iqIDHandlers.end() )
1360 if( ih == (*t).second.ih )
1361 m_iqIDHandlers.erase( t );
1363 m_iqHandlerMapMutex.
unlock();
1372 typedef IqHandlerMap::const_iterator IQci;
1373 std::pair<IQci, IQci> g = m_iqExtHandlers.equal_range( exttype );
1374 for( IQci it = g.first; it != g.second; ++it )
1376 if( (*it).second == ih )
1380 m_iqExtHandlers.insert( std::make_pair( exttype, ih ) );
1389 typedef IqHandlerMap::iterator IQi;
1390 std::pair<IQi, IQi> g = m_iqExtHandlers.equal_range( exttype );
1393 while( it != g.second )
1396 if( (*it2).second == ih )
1397 m_iqExtHandlers.erase( it2 );
1404 m_messageSessions.push_back( session );
1412 MessageSessionList::iterator it = std::find( m_messageSessions.begin(),
1413 m_messageSessions.end(),
1415 if( it != m_messageSessions.end() )
1418 m_messageSessions.erase( it );
1425 m_messageHandlers.push_back( mh );
1431 m_messageHandlers.remove( mh );
1437 m_subscriptionHandlers.push_back( sh );
1443 m_subscriptionHandlers.remove( sh );
1448 if( th && !tag.empty() )
1450 TagHandlerStruct ths;
1454 m_tagHandlers.push_back( ths );
1462 for( TagHandlerList::iterator it = m_tagHandlers.begin(); it != m_tagHandlers.end(); )
1464 if( (*it).th == th && (*it).tag == tag && (*it).xmlns == xmlns )
1471 m_tagHandlers.erase( it++ );
1484 m_statisticsHandler = sh;
1489 m_statisticsHandler = 0;
1496 m_mucInvitationHandler = mih;
1503 m_mucInvitationHandler = 0;
1510 m_connectionListeners.push_back( cl );
1516 m_connectionListeners.remove( cl );
1532 ConnectionListenerList::const_iterator it = m_connectionListeners.begin();
1533 for( ; it != m_connectionListeners.end() && (*it)->onTLSConnect( info ); ++it )
1535 return m_stats.
encryption = ( it == m_connectionListeners.end() );
1558 void ClientBase::notifyPresenceHandlers(
Presence& pres )
1561 PresenceJidHandlerList::const_iterator t;
1562 PresenceJidHandlerList::const_iterator itj = m_presenceJidHandlers.begin();
1563 while( itj != m_presenceJidHandlers.end() )
1566 if( (*t).jid->bare() == pres.
from().
bare() && (*t).ph )
1568 (*t).ph->handlePresence( pres );
1576 PresenceHandlerList::const_iterator it = m_presenceHandlers.begin();
1577 for( ; it != m_presenceHandlers.end(); ++it )
1579 (*it)->handlePresence( pres );
1585 void ClientBase::notifySubscriptionHandlers( Subscription& s10n )
1588 SubscriptionHandlerList::const_iterator it = m_subscriptionHandlers.begin();
1589 for( ; it != m_subscriptionHandlers.end(); ++it )
1591 (*it)->handleSubscription( s10n );
1597 void ClientBase::notifyIqHandlers( IQ& iq )
1599 m_iqHandlerMapMutex.
lock();
1600 IqTrackMap::iterator it_id = m_iqIDHandlers.find( iq.id() );
1601 bool haveIdHandler = ( it_id != m_iqIDHandlers.end() );
1602 m_iqHandlerMapMutex.
unlock();
1605 (*it_id).second.ih->handleIqID( iq, (*it_id).second.context );
1606 if( (*it_id).second.del )
1607 delete (*it_id).second.ih;
1608 m_iqHandlerMapMutex.
lock();
1609 m_iqIDHandlers.erase( it_id );
1610 m_iqHandlerMapMutex.
unlock();
1614 if( iq.extensions().empty() )
1625 bool handled =
false;
1638 m_iqExtHandlerMapMutex.
lock();
1639 typedef IqHandlerMap::const_iterator IQci;
1641 StanzaExtensionList::const_iterator itse = sel.begin();
1642 for( ; !handled && itse != sel.end(); ++itse )
1644 std::pair<IQci, IQci> g = m_iqExtHandlers.equal_range( (*itse)->extensionType() );
1645 for( IQci it = g.first; !handled && it != g.second; ++it )
1647 if( (*it).second->handleIq( iq ) )
1651 m_iqExtHandlerMapMutex.
unlock();
1653 if( !handled && ( iq.subtype() ==
IQ::Get || iq.subtype() ==
IQ::Set ) )
1661 void ClientBase::notifyMessageHandlers( Message& msg )
1663 if( m_mucInvitationHandler )
1665 const MUCRoom::MUCUser* mu = msg.findExtension<MUCRoom::MUCUser>(
ExtMUCUser );
1670 mu->jid() ? JID( *(mu->jid()) ) : JID(),
1680 MessageSessionList::const_iterator it1 = m_messageSessions.begin();
1681 for( ; it1 != m_messageSessions.end(); ++it1 )
1683 if( (*it1)->target().full() == msg.from().full() &&
1684 ( msg.thread().empty()
1685 || (*it1)->threadID() == msg.thread()
1686 || (*it1)->honorThreadID() ) &&
1688 ( (*it1)->types() & msg.subtype() || (*it1)->types() == 0 ) )
1690 (*it1)->handleMessage( msg );
1695 it1 = m_messageSessions.begin();
1696 for( ; it1 != m_messageSessions.end(); ++it1 )
1698 if( (*it1)->target().bare() == msg.from().bare() &&
1699 ( msg.thread().empty()
1700 || (*it1)->threadID() == msg.thread()
1701 || (*it1)->honorThreadID() ) &&
1703 ( (*it1)->types() & msg.subtype() || (*it1)->types() == 0 ) )
1705 (*it1)->handleMessage( msg );
1710 MessageSessionHandler* msHandler = 0;
1712 switch( msg.subtype() )
1715 msHandler = m_messageSessionHandlerChat;
1718 msHandler = m_messageSessionHandlerNormal;
1721 msHandler = m_messageSessionHandlerGroupchat;
1724 msHandler = m_messageSessionHandlerHeadline;
1732 MessageSession* session =
new MessageSession(
this, msg.from(),
true, msg.subtype() );
1734 session->handleMessage( msg );
1739 MessageHandlerList::const_iterator it = m_messageHandlers.begin();
1740 for( ; it != m_messageHandlers.end(); ++it )
1742 (*it)->handleMessage( msg );
1749 void ClientBase::notifyTagHandlers( Tag* tag )
1751 TagHandlerList::const_iterator it = m_tagHandlers.begin();
1752 for( ; it != m_tagHandlers.end(); ++it )
1754 if( (*it).tag == tag->name() && tag->hasAttribute(
XMLNS, (*it).xmlns ) )
1755 (*it).th->handleTag( tag );
1773 if( (*it)->extensionType() == type )
1787 for(
int i = 0; i < 4; ++i )
1788 sprintf( cn + i*8,
"%08x", rand() );
1789 return std::string( cn, 4*8 );;
1807 TLSBase* ClientBase::getDefaultEncryption()
1812 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 element in a specific namespace...
virtual ConnectionError recv(int timeout=-1)
const std::string & xmlns() const
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)
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)