17 #include "clientbase.h"
18 #include "connectionbase.h"
20 #include "compressionbase.h"
21 #include "connectiontcpclient.h"
23 #include "messagesessionhandler.h"
27 #include "subscription.h"
29 #include "connectionlistener.h"
30 #include "iqhandler.h"
31 #include "messagehandler.h"
32 #include "presencehandler.h"
33 #include "rosterlistener.h"
34 #include "subscriptionhandler.h"
35 #include "loghandler.h"
36 #include "taghandler.h"
37 #include "mucinvitationhandler.h"
44 #include "tlsdefault.h"
45 #include "compressionzlib.h"
46 #include "stanzaextensionfactory.h"
47 #include "eventhandler.h"
61 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
69 ClientBase::Ping::Ping()
74 ClientBase::Ping::~Ping()
78 const std::string& ClientBase::Ping::filterString()
const
80 static const std::string filter =
"/iq/ping[@xmlns='" +
XMLNS_XMPP_PING +
"']";
87 : m_connection( 0 ), m_encryption( 0 ), m_compression( 0 ), m_disco( 0 ), m_namespace( ns ),
88 m_xmllang(
"en" ), m_server( server ), m_compressionActive( false ), m_encryptionActive( false ),
89 m_compress( true ), m_authed( false ), m_block( false ), m_sasl( true ), m_tls(
TLSOptional ), m_port( port ),
91 m_statisticsHandler( 0 ), m_mucInvitationHandler( 0 ),
92 m_messageSessionHandlerChat( 0 ), m_messageSessionHandlerGroupchat( 0 ),
93 m_messageSessionHandlerHeadline( 0 ), m_messageSessionHandlerNormal( 0 ),
96 m_selectedSaslMech(
SaslMechNone ), m_autoMessageSession( false )
102 const std::string& server,
int port )
103 : m_connection( 0 ), m_encryption( 0 ), m_compression( 0 ), m_disco( 0 ), m_namespace( ns ),
104 m_password( password ),
105 m_xmllang(
"en" ), m_server( server ), m_compressionActive( false ), m_encryptionActive( false ),
106 m_compress( true ), m_authed( false ), m_block( false ), m_sasl( true ), m_tls(
TLSOptional ),
107 m_port( port ), m_availableSaslMechs(
SaslMechAll ),
108 m_statisticsHandler( 0 ), m_mucInvitationHandler( 0 ),
109 m_messageSessionHandlerChat( 0 ), m_messageSessionHandlerGroupchat( 0 ),
110 m_messageSessionHandlerHeadline( 0 ), m_messageSessionHandlerNormal( 0 ),
113 m_selectedSaslMech(
SaslMechNone ), m_autoMessageSession( false )
118 void ClientBase::init()
133 memset( &m_stats, 0,
sizeof( m_stats ) );
149 PresenceJidHandlerList::const_iterator it1 = m_presenceJidHandlers.begin();
150 for( ; it1 != m_presenceJidHandlers.end(); ++it1 )
206 const std::string& version = tag->
findAttribute(
"version" );
210 " (it does not send a 'version' attribute). Please fix it or try another one.\n" );
220 handleStreamError( tag );
225 if( !handleNormalNode( tag ) )
229 if( tag->
name() ==
"iq" )
233 notifyIqHandlers( iq );
236 else if( tag->
name() ==
"message" )
240 notifyMessageHandlers( msg );
243 else if( tag->
name() ==
"presence" )
246 if( type ==
"subscribe" || type ==
"unsubscribe"
247 || type ==
"subscribed" || type ==
"unsubscribed" )
251 notifySubscriptionHandlers( sub );
258 notifyPresenceHandlers( pres );
267 notifyTagHandlers( tag );
272 if( m_statisticsHandler )
358 notifyOnDisconnect( reason );
367 send(
"</stream:stream>" );
381 notifyOnDisconnect( reason );
384 void ClientBase::parse(
const std::string& data )
386 std::string copy = data;
388 if( ( i = m_parser.
feed( copy ) ) >= 0 )
390 std::string error =
"parse error (at pos ";
391 error += util::int2string( i );
394 Tag* e =
new Tag(
"stream:error" );
403 std::string head =
"<?xml version='1.0' ?>";
405 head +=
"xmlns:stream='http://etherx.jabber.org/streams' xml:lang='" +
m_xmllang +
"' ";
412 #if defined( HAVE_GNUTLS ) || defined( HAVE_OPENSSL ) || defined( HAVE_WINTLS )
439 m_selectedSaslMech = type;
475 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
490 "SASL GSSAPI is not supported on this platform. You should never see this." );
496 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
498 SEC_WINNT_AUTH_IDENTITY identity, *ident = 0;
499 memset( &identity, 0,
sizeof( identity ) );
503 identity.UserLength = (
unsigned long)
m_jid.
username().length();
504 identity.Domain = (
unsigned char*)m_ntlmDomain.c_str();
505 identity.DomainLength = (
unsigned long)m_ntlmDomain.length();
506 identity.Password = (
unsigned char*)
m_password.c_str();
507 identity.PasswordLength = (
unsigned long)
m_password.length();
508 identity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
511 AcquireCredentialsHandle( 0, _T(
"NTLM" ), SECPKG_CRED_OUTBOUND, 0, ident, 0, 0, &m_credHandle, 0 );
514 "SASL NTLM is not supported on this platform. You should never see this." );
531 switch( m_selectedSaslMech )
535 if( !decoded.compare( 0, 7,
"rspauth" ) )
539 std::string::size_type end = 0;
540 std::string::size_type pos = decoded.find(
"realm=" );
541 if( pos != std::string::npos )
543 end = decoded.find(
'"', pos + 7 );
544 realm = decoded.substr( pos + 7, end - ( pos + 7 ) );
549 pos = decoded.find(
"nonce=" );
550 if( pos == std::string::npos )
553 end = decoded.find(
'"', pos + 7 );
554 while( decoded[end-1] ==
'\\' )
555 end = decoded.find(
'"', end + 1 );
556 std::string nonce = decoded.substr( pos + 7, end - ( pos + 7 ) );
560 for(
int i = 0; i < 4; ++i )
561 sprintf( cn + i*8,
"%08x", rand() );
562 cnonce.assign( cn, 4*8 );
571 const std::string& a1_h = md5.
binary();
579 const std::string& a1 = md5.
hex();
581 md5.
feed(
"AUTHENTICATE:xmpp/" );
584 const std::string& a2 = md5.
hex();
589 md5.
feed(
":00000001:" );
591 md5.
feed(
":auth:" );
595 std::string response =
"username=\"";
597 response +=
"\",realm=\"";
599 response +=
"\",nonce=\"";
601 response +=
"\",cnonce=\"";
603 response +=
"\",nc=00000001,qop=auth,digest-uri=\"xmpp/";
605 response +=
"\",response=";
606 response += md5.
hex();
607 response +=
",charset=utf-8";
617 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
621 "Huh, received GSSAPI challenge?! This should have never happened!" );
626 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
627 bool type1 = ( decoded.length() < 7 ) ?
true :
false;
629 SecBuffer bufferIn = { type1 ? 0 : (
unsigned long)decoded.length(),
631 (
void*)decoded.c_str() };
632 SecBufferDesc secIn = { 0, 1, &bufferIn };
636 SecBuffer bufferOut = {
sizeof( buffer ), SECBUFFER_TOKEN, buffer };
637 SecBufferDesc secOut = { 0, 1, &bufferOut };
640 unsigned long contextAttr;
642 SECURITY_STATUS status = InitializeSecurityContext( &m_credHandle, type1 ? 0 : &m_ctxtHandle,
643 0, ISC_REQ_MUTUAL_AUTH, 0, 0, &secIn, 0,
644 &m_ctxtHandle, &secOut, &contextAttr,
646 std::string response;
647 if( SUCCEEDED( status ) )
649 response = std::string( (
const char *)bufferOut.pvBuffer, bufferOut.cbBuffer );
654 "InitializeSecurityContext() failed, return value "
655 + util::int2string( status ) );
661 "Huh, received NTLM challenge?! This should have never happened!" );
678 else if( tag->
hasChild(
"incorrect-encoding" ) )
680 else if( tag->
hasChild(
"invalid-authzid" ) )
682 else if( tag->
hasChild(
"invalid-mechanism" ) )
684 else if( tag->
hasChild(
"malformed-request" ) )
686 else if( tag->
hasChild(
"mechanism-too-weak" ) )
688 else if( tag->
hasChild(
"not-authorized" ) )
690 else if( tag->
hasChild(
"temporary-auth-failure" ) )
693 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
696 FreeCredentialsHandle( &m_credHandle );
697 DeleteSecurityContext( &m_ctxtHandle );
704 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
707 FreeCredentialsHandle( &m_credHandle );
708 DeleteSecurityContext( &m_ctxtHandle );
717 if( iq.
id().empty() )
722 track.context = context;
724 m_iqHandlerMapMutex.
lock();
725 m_iqIDHandlers[iq.
id()] = track;
726 m_iqHandlerMapMutex.
unlock();
780 if( m_statisticsHandler )
801 void ClientBase::addFrom( Tag* tag )
803 if( !
m_authed || !tag || tag->hasAttribute(
"from" ) )
807 tag->addAttribute(
"from",
m_jid.
bare() );
812 void ClientBase::addNamespace( Tag* tag )
814 if( !tag || !tag->xmlns().empty() )
856 const std::string&
id =
getID();
860 send( iq,
this, XMPPPing );
863 bool ClientBase::handleIq(
const IQ& iq )
876 void ClientBase::handleIqID(
const IQ& iq,
int context )
878 if( context == XMPPPing )
883 handleIqIDForward( iq, context );
888 static unsigned int uniqueBaseID = (
unsigned int)time( 0 );
890 sprintf( r,
"uid:%08x:%08x", uniqueBaseID, rand() );
891 std::string ret( r, 21 );
897 if( version.empty() )
904 size_t dot = version.find(
'.' );
905 if( !version.empty() && dot && dot != std::string::npos )
907 major = atoi( version.substr( 0, dot ).c_str() );
908 minor = atoi( version.substr( dot ).c_str() );
911 return myMajor >= major;
941 void ClientBase::handleStreamError(
Tag* tag )
945 TagList::const_iterator it = c.begin();
946 for( ; it != c.end(); ++it )
948 const std::string& name = (*it)->name();
949 if( name ==
"bad-format" )
951 else if( name ==
"bad-namespace-prefix" )
953 else if( name ==
"conflict" )
955 else if( name ==
"connection-timeout" )
957 else if( name ==
"host-gone" )
959 else if( name ==
"host-unknown" )
961 else if( name ==
"improper-addressing" )
963 else if( name ==
"internal-server-error" )
965 else if( name ==
"invalid-from" )
967 else if( name ==
"invalid-id" )
969 else if( name ==
"invalid-namespace" )
971 else if( name ==
"invalid-xml" )
973 else if( name ==
"not-authorized" )
975 else if( name ==
"policy-violation" )
977 else if( name ==
"remote-connection-failed" )
979 else if( name ==
"resource-constraint" )
981 else if( name ==
"restricted-xml" )
983 else if( name ==
"see-other-host" )
988 else if( name ==
"system-shutdown" )
990 else if( name ==
"undefined-condition" )
992 else if( name ==
"unsupported-encoding" )
994 else if( name ==
"unsupported-stanza-type" )
996 else if( name ==
"unsupported-version" )
998 else if( name ==
"xml-not-well-formed" )
1000 else if( name ==
"text" )
1002 const std::string& lang = (*it)->findAttribute(
"xml:lang" );
1004 m_streamErrorText[lang] = (*it)->cdata();
1006 m_streamErrorText[
"default"] = (*it)->cdata();
1009 m_streamErrorAppCondition = (*it);
1012 m_streamError = err;
1018 StringMap::const_iterator it = m_streamErrorText.find( lang );
1019 return ( it != m_streamErrorText.end() ) ? (*it).second :
EmptyString;
1025 m_messageSessionHandlerChat = msh;
1028 m_messageSessionHandlerNormal = msh;
1031 m_messageSessionHandlerGroupchat = msh;
1034 m_messageSessionHandlerHeadline = msh;
1040 m_presenceHandlers.push_back( ph );
1046 m_presenceHandlers.remove( ph );
1053 JidPresHandlerStruct jph;
1054 jph.jid =
new JID( jid.
bare() );
1056 m_presenceJidHandlers.push_back( jph );
1062 PresenceJidHandlerList::iterator t;
1063 PresenceJidHandlerList::iterator it = m_presenceJidHandlers.begin();
1064 while( it != m_presenceJidHandlers.end() )
1068 if( ( !ph || (*t).ph == ph ) && (*t).jid->bare() == jid.
bare() )
1071 m_presenceJidHandlers.erase( t );
1078 IqTrackMap::iterator t;
1079 m_iqHandlerMapMutex.
lock();
1080 IqTrackMap::iterator it = m_iqIDHandlers.begin();
1081 while( it != m_iqIDHandlers.end() )
1085 if( ih == (*t).second.ih )
1086 m_iqIDHandlers.erase( t );
1088 m_iqHandlerMapMutex.
unlock();
1096 typedef IqHandlerMap::const_iterator IQci;
1097 std::pair<IQci, IQci> g = m_iqExtHandlers.equal_range( exttype );
1098 for( IQci it = g.first; it != g.second; ++it )
1099 if( (*it).second == ih )
1102 m_iqExtHandlers.insert( std::make_pair( exttype, ih ) );
1110 typedef IqHandlerMap::iterator IQi;
1111 std::pair<IQi, IQi> g = m_iqExtHandlers.equal_range( exttype );
1114 while( it != g.second )
1117 if( (*it2).second == ih )
1118 m_iqExtHandlers.erase( it2 );
1125 m_messageSessions.push_back( session );
1133 MessageSessionList::iterator it = std::find( m_messageSessions.begin(),
1134 m_messageSessions.end(),
1136 if( it != m_messageSessions.end() )
1139 m_messageSessions.erase( it );
1146 m_messageHandlers.push_back( mh );
1152 m_messageHandlers.remove( mh );
1158 m_subscriptionHandlers.push_back( sh );
1164 m_subscriptionHandlers.remove( sh );
1169 if( th && !tag.empty() )
1171 TagHandlerStruct ths;
1175 m_tagHandlers.push_back( ths );
1183 TagHandlerList::iterator it = m_tagHandlers.begin();
1184 for( ; it != m_tagHandlers.end(); ++it )
1186 if( (*it).th == th && (*it).tag == tag && (*it).xmlns == xmlns )
1187 m_tagHandlers.erase( it );
1195 m_statisticsHandler = sh;
1200 m_statisticsHandler = 0;
1207 m_mucInvitationHandler = mih;
1214 m_mucInvitationHandler = 0;
1221 m_connectionListeners.push_back( cl );
1227 m_connectionListeners.remove( cl );
1243 ConnectionListenerList::const_iterator it = m_connectionListeners.begin();
1244 for( ; it != m_connectionListeners.end() && (*it)->onTLSConnect( info ); ++it )
1246 return m_stats.
encryption = ( it == m_connectionListeners.end() );
1269 void ClientBase::notifyPresenceHandlers(
Presence& pres )
1272 PresenceJidHandlerList::const_iterator t;
1273 PresenceJidHandlerList::const_iterator itj = m_presenceJidHandlers.begin();
1274 while( itj != m_presenceJidHandlers.end() )
1277 if( (*t).jid->bare() == pres.
from().
bare() && (*t).ph )
1279 (*t).ph->handlePresence( pres );
1287 PresenceHandlerList::const_iterator it = m_presenceHandlers.begin();
1288 for( ; it != m_presenceHandlers.end(); ++it )
1290 (*it)->handlePresence( pres );
1296 void ClientBase::notifySubscriptionHandlers( Subscription& s10n )
1299 SubscriptionHandlerList::const_iterator it = m_subscriptionHandlers.begin();
1300 for( ; it != m_subscriptionHandlers.end(); ++it )
1302 (*it)->handleSubscription( s10n );
1308 void ClientBase::notifyIqHandlers( IQ& iq )
1310 m_iqHandlerMapMutex.
lock();
1311 IqTrackMap::iterator it_id = m_iqIDHandlers.find( iq.id() );
1312 m_iqHandlerMapMutex.
unlock();
1315 (*it_id).second.ih->handleIqID( iq, (*it_id).second.context );
1316 if( (*it_id).second.del )
1317 delete (*it_id).second.ih;
1318 m_iqHandlerMapMutex.
lock();
1319 m_iqIDHandlers.erase( it_id );
1320 m_iqHandlerMapMutex.
unlock();
1324 if( iq.extensions().empty() )
1340 typedef IqHandlerMap::const_iterator IQci;
1342 StanzaExtensionList::const_iterator itse = sel.begin();
1343 for( ; itse != sel.end(); ++itse )
1345 std::pair<IQci, IQci> g = m_iqExtHandlers.equal_range( (*itse)->extensionType() );
1346 for( IQci it = g.first; it != g.second; ++it )
1348 if( (*it).second->handleIq( iq ) )
1361 void ClientBase::notifyMessageHandlers( Message& msg )
1363 if( m_mucInvitationHandler )
1365 const MUCRoom::MUCUser* mu = msg.findExtension<MUCRoom::MUCUser>(
ExtMUCUser );
1370 mu->jid() ? JID( *(mu->jid()) ) : JID(),
1380 MessageSessionList::const_iterator it1 = m_messageSessions.begin();
1381 for( ; it1 != m_messageSessions.end(); ++it1 )
1383 if( (*it1)->target().full() == msg.from().full() &&
1384 ( msg.thread().empty()
1385 || (*it1)->threadID() == msg.thread()
1386 || (*it1)->honorThreadID() ) &&
1388 ( (*it1)->types() & msg.subtype() || (*it1)->types() == 0 ) )
1390 (*it1)->handleMessage( msg );
1395 it1 = m_messageSessions.begin();
1396 for( ; it1 != m_messageSessions.end(); ++it1 )
1398 if( (*it1)->target().bare() == msg.from().bare() &&
1399 ( msg.thread().empty()
1400 || (*it1)->threadID() == msg.thread()
1401 || (*it1)->honorThreadID() ) &&
1403 ( (*it1)->types() & msg.subtype() || (*it1)->types() == 0 ) )
1405 (*it1)->handleMessage( msg );
1410 MessageSessionHandler* msHandler = 0;
1412 switch( msg.subtype() )
1415 msHandler = m_messageSessionHandlerChat;
1418 msHandler = m_messageSessionHandlerNormal;
1421 msHandler = m_messageSessionHandlerGroupchat;
1424 msHandler = m_messageSessionHandlerHeadline;
1434 MessageSession* session =
new MessageSession(
this, msg.from(),
true, msg.subtype() );
1436 session->handleMessage( msg );
1441 MessageHandlerList::const_iterator it = m_messageHandlers.begin();
1442 for( ; it != m_messageHandlers.end(); ++it )
1444 (*it)->handleMessage( msg );
1451 void ClientBase::notifyTagHandlers( Tag* tag )
1453 TagHandlerList::const_iterator it = m_tagHandlers.begin();
1454 for( ; it != m_tagHandlers.end(); ++it )
1456 if( (*it).tag == tag->name() && tag->hasAttribute(
XMLNS, (*it).xmlns ) )
1457 (*it).th->handleTag( tag );
1475 if( (*it)->extensionType() == type )
1501 TLSBase* ClientBase::getDefaultEncryption()
1506 TLSDefault*
tls =
new TLSDefault(
this,
m_server );