16 # include "../config.h.win"
17 #elif defined( _WIN32_WCE )
18 # include "../config.h.win"
23 #include "clientbase.h"
24 #include "connectionbase.h"
26 #include "compressionbase.h"
27 #include "connectiontcpclient.h"
29 #include "messagesessionhandler.h"
33 #include "connectionlistener.h"
34 #include "iqhandler.h"
35 #include "messagehandler.h"
36 #include "presencehandler.h"
37 #include "rosterlistener.h"
38 #include "subscriptionhandler.h"
39 #include "loghandler.h"
40 #include "taghandler.h"
41 #include "mucinvitationhandler.h"
45 #include "tlsdefault.h"
46 #include "compressionzlib.h"
63 : m_connection( 0 ), m_encryption( 0 ), m_compression( 0 ), m_disco( 0 ), m_namespace( ns ),
64 m_xmllang(
"en" ), m_server( server ), m_compressionActive( false ), m_encryptionActive( false ),
65 m_compress( true ), m_authed( false ), m_sasl( true ), m_tls(
TLSOptional ), m_port( port ),
67 m_statisticsHandler( 0 ), m_mucInvitationHandler( 0 ),
68 m_messageSessionHandlerChat( 0 ), m_messageSessionHandlerGroupchat( 0 ),
69 m_messageSessionHandlerHeadline( 0 ), m_messageSessionHandlerNormal( 0 ),
71 m_streamErrorAppCondition( 0 ), m_selectedSaslMech(
SaslMechNone ),
72 m_idCount( 0 ), m_autoMessageSession( false )
78 const std::string& server,
int port )
79 : m_connection( 0 ), m_encryption( 0 ), m_compression( 0 ), m_disco( 0 ), m_namespace( ns ),
80 m_password( password ),
81 m_xmllang(
"en" ), m_server( server ), m_compressionActive( false ), m_encryptionActive( false ),
82 m_compress( true ), m_authed( false ), m_block( false ), m_sasl( true ), m_tls(
TLSOptional ),
83 m_port( port ), m_availableSaslMechs(
SaslMechAll ),
84 m_statisticsHandler( 0 ), m_mucInvitationHandler( 0 ),
85 m_messageSessionHandlerChat( 0 ), m_messageSessionHandlerGroupchat( 0 ),
86 m_messageSessionHandlerHeadline( 0 ), m_messageSessionHandlerNormal( 0 ),
88 m_streamErrorAppCondition( 0 ), m_selectedSaslMech(
SaslMechNone ),
89 m_idCount( 0 ), m_autoMessageSession( false )
94 void ClientBase::init()
98 m_disco =
new Disco(
this );
132 delete m_compression;
136 MessageSessionList::const_iterator it = m_messageSessions.begin();
137 for( ; it != m_messageSessions.end(); ++it )
140 PresenceJidHandlerList::const_iterator it1 = m_presenceJidHandlers.begin();
141 for( ; it1 != m_presenceJidHandlers.end(); ++it1 )
150 return m_connection->
recv( timeout );
155 if( m_server.empty() )
159 m_parser =
new Parser(
this );
168 m_encryption = getDefaultEncryption();
177 m_compression = getDefaultCompression();
180 +
", connecting..." );
200 if( tag->
name() ==
"stream:stream" )
202 const std::string& version = stanza->
findAttribute(
"version" );
203 if( !checkStreamVersion( version ) )
206 " (it does not send a 'version' attribute). Please fix it or try another one.\n" );
214 else if( tag->
name() ==
"stream:error" )
216 handleStreamError( stanza );
221 if( !handleNormalNode( stanza ) )
223 switch( stanza->
type() )
226 notifyIqHandlers( stanza );
230 notifyPresenceHandlers( stanza );
234 notifySubscriptionHandlers( stanza );
238 notifyMessageHandlers( stanza );
242 notifyTagHandlers( tag );
248 if( m_statisticsHandler )
256 if( m_encryption && m_encryptionActive )
258 else if( m_connection )
259 m_connection->
send( data );
275 m_connection->
send( data );
282 if( m_compression && m_compressionActive )
294 if( !notifyOnTLSConnect( certinfo ) )
314 if( m_encryption && m_encryptionActive )
316 else if( m_compression && m_compressionActive )
327 if( m_block && m_connection )
337 notifyOnDisconnect( reason );
345 send(
"</stream:stream>" );
354 m_encryptionActive =
false;
355 m_compressionActive =
false;
357 notifyOnDisconnect( reason );
361 void ClientBase::parse(
const std::string& data )
363 if( m_parser && !m_parser->
feed( data ) )
366 Tag* e =
new Tag(
"stream:error" );
373 void ClientBase::header()
375 std::string head =
"<?xml version='1.0' ?>";
376 head +=
"<stream:stream to='" + m_jid.
server() +
"' xmlns='" + m_namespace +
"' ";
377 head +=
"xmlns:stream='http://etherx.jabber.org/streams' xml:lang='" + m_xmllang +
"' ";
382 bool ClientBase::hasTls()
384 #if defined( HAVE_GNUTLS ) || defined( HAVE_OPENSSL ) || defined( HAVE_WINTLS )
391 void ClientBase::startTls()
393 Tag *start =
new Tag(
"starttls" );
407 m_clientKey = clientKey;
408 m_clientCerts = clientCerts;
413 m_selectedSaslMech = type;
415 Tag *a =
new Tag(
"auth" );
429 tmp += m_authzid.
bare();
466 "GSSAPI is not supported on this platform. You should never see this." );
477 void ClientBase::processSASLChallenge(
const std::string& challenge )
479 Tag *t =
new Tag(
"response" );
484 switch( m_selectedSaslMech )
488 if( decoded.substr( 0, 7 ) ==
"rspauth" )
493 size_t r_pos = decoded.find(
"realm=" );
494 if( r_pos != std::string::npos )
496 size_t r_end = decoded.find(
"\"", r_pos + 7 );
497 realm = decoded.substr( r_pos + 7, r_end - (r_pos + 7 ) );
502 size_t n_pos = decoded.find(
"nonce=" );
503 if( n_pos == std::string::npos )
508 size_t n_end = decoded.find(
"\"", n_pos + 7 );
509 while( decoded.substr( n_end-1, 1 ) ==
"\\" )
510 n_end = decoded.find(
"\"", n_end + 1 );
511 std::string nonce = decoded.substr( n_pos + 7, n_end - ( n_pos + 7 ) );
516 for(
int i = 0; i < 4; ++i )
517 sprintf( cn + i*8,
"%08x", rand() );
518 cnonce.assign( cn, 4*8 );
520 std::ostringstream cn;
521 for(
int i = 0; i < 4; ++i )
522 cn << std::hex << std::setw( 8 ) << std::setfill(
'0' ) << rand();
531 md5.feed( m_password );
533 const std::string& a1_h = md5.binary();
541 const std::string& a1 = md5.hex();
543 md5.feed(
"AUTHENTICATE:xmpp/" );
544 md5.feed( m_jid.
server() );
546 const std::string& a2 = md5.hex();
551 md5.feed(
":00000001:" );
553 md5.feed(
":auth:" );
556 const std::string& response_value = md5.hex();
558 std::string response =
"username=\"" + m_jid.
username() +
"\",realm=\"" + realm;
559 response +=
"\",nonce=\""+ nonce +
"\",cnonce=\"" + cnonce;
560 response +=
"\",nc=00000001,qop=auth,digest-uri=\"xmpp/" + m_jid.
server() +
"\",response=";
561 response += response_value;
562 response +=
",charset=utf-8";
565 response +=
",authzid=" + m_authzid.
bare();
576 "Huh, received GSSAPI challenge?! This should have never happened!" );
587 void ClientBase::processSASLError( Stanza *stanza )
589 if( stanza->hasChild(
"aborted" ) )
591 else if( stanza->hasChild(
"incorrect-encoding" ) )
593 else if( stanza->hasChild(
"invalid-authzid" ) )
595 else if( stanza->hasChild(
"invalid-mechanism" ) )
597 else if( stanza->hasChild(
"mechanism-too-weak" ) )
599 else if( stanza->hasChild(
"not-authorized" ) )
601 else if( stanza->hasChild(
"temporary-auth-failure" ) )
612 switch( tag->
type() )
633 if( m_statisticsHandler )
641 if( m_compression && m_compressionActive )
643 else if( m_encryption && m_encryptionActive )
646 m_connection->
send( xml );
674 const std::string&
id =
getID();
676 Tag *iq =
new Tag(
"iq" );
680 Tag *p =
new Tag( iq,
"ping" );
690 sprintf( r,
"%08x", rand() );
691 std::string ret( r, 8 );
692 return std::string(
"uid" ) + ret;
694 std::ostringstream oss;
696 return std::string(
"uid" ) + oss.str();
700 bool ClientBase::checkStreamVersion(
const std::string& version )
702 if( version.empty() )
709 size_t dot = version.find(
"." );
710 if( !version.empty() && dot && dot != std::string::npos )
712 major = atoi( version.substr( 0, dot ).c_str() );
713 minor = atoi( version.substr( dot ).c_str() );
716 return myMajor >= major;
721 return m_logInstance;
746 delete m_compression;
751 void ClientBase::handleStreamError(
Stanza *stanza )
755 Tag::TagList::const_iterator it = c.begin();
756 for( ; it != c.end(); ++it )
758 if( (*it)->name() ==
"bad-format" )
760 else if( (*it)->name() ==
"bad-namespace-prefix" )
762 else if( (*it)->name() ==
"conflict" )
764 else if( (*it)->name() ==
"connection-timeout" )
766 else if( (*it)->name() ==
"host-gone" )
768 else if( (*it)->name() ==
"host-unknown" )
770 else if( (*it)->name() ==
"improper-addressing" )
772 else if( (*it)->name() ==
"internal-server-error" )
774 else if( (*it)->name() ==
"invalid-from" )
776 else if( (*it)->name() ==
"invalid-id" )
778 else if( (*it)->name() ==
"invalid-namespace" )
780 else if( (*it)->name() ==
"invalid-xml" )
782 else if( (*it)->name() ==
"not-authorized" )
784 else if( (*it)->name() ==
"policy-violation" )
786 else if( (*it)->name() ==
"remote-connection-failed" )
788 else if( (*it)->name() ==
"resource-constraint" )
790 else if( (*it)->name() ==
"restricted-xml" )
792 else if( (*it)->name() ==
"see-other-host" )
795 m_streamErrorCData = stanza->
findChild(
"see-other-host" )->
cdata();
797 else if( (*it)->name() ==
"system-shutdown" )
799 else if( (*it)->name() ==
"undefined-condition" )
801 else if( (*it)->name() ==
"unsupported-encoding" )
803 else if( (*it)->name() ==
"unsupported-stanza-type" )
805 else if( (*it)->name() ==
"unsupported-version" )
807 else if( (*it)->name() ==
"xml-not-well-formed" )
809 else if( (*it)->name() ==
"text" )
811 const std::string& lang = (*it)->findAttribute(
"xml:lang" );
813 m_streamErrorText[lang] = (*it)->cdata();
815 m_streamErrorText[
"default"] = (*it)->cdata();
818 m_streamErrorAppCondition = (*it);
827 StringMap::const_iterator it = m_streamErrorText.find( lang );
828 return ( it != m_streamErrorText.end() ) ? (*it).second : std::string();
834 m_messageSessionHandlerChat = msh;
837 m_messageSessionHandlerNormal = msh;
840 m_messageSessionHandlerGroupchat = msh;
843 m_messageSessionHandlerHeadline = msh;
849 m_presenceHandlers.push_back( ph );
855 m_presenceHandlers.remove( ph );
862 JidPresHandlerStruct jph;
863 jph.jid =
new JID( jid.
bare() );
865 m_presenceJidHandlers.push_back( jph );
871 PresenceJidHandlerList::iterator t;
872 PresenceJidHandlerList::iterator it = m_presenceJidHandlers.begin();
873 while( it != m_presenceJidHandlers.end() )
877 if( ( !ph || (*t).ph == ph ) && (*t).jid->bare() == jid.
bare() )
880 m_presenceJidHandlers.erase( t );
887 if( ih && !
id.empty() )
891 track.context = context;
892 m_iqIDHandlers[id] = track;
898 IqTrackMap::iterator t;
899 IqTrackMap::iterator it = m_iqIDHandlers.begin();
900 while( it != m_iqIDHandlers.end() )
904 if( ih == (*t).second.ih )
905 m_iqIDHandlers.erase( t );
911 if( ih && !xmlns.empty() )
912 m_iqNSHandlers[xmlns] = ih;
918 m_iqNSHandlers.erase( xmlns );
924 m_messageSessions.push_back( session );
932 MessageSessionList::iterator it = std::find( m_messageSessions.begin(), m_messageSessions.end(),
934 if( it != m_messageSessions.end() )
937 m_messageSessions.erase( it );
944 m_messageHandlers.push_back( mh );
950 m_messageHandlers.remove( mh );
956 m_subscriptionHandlers.push_back( sh );
962 m_subscriptionHandlers.remove( sh );
967 if( th && !tag.empty() )
969 TagHandlerStruct ths;
973 m_tagHandlers.push_back( ths );
981 TagHandlerList::iterator it = m_tagHandlers.begin();
982 for( ; it != m_tagHandlers.end(); ++it )
984 if( (*it).th == th && (*it).tag == tag && (*it).xmlns == xmlns )
985 m_tagHandlers.erase( it );
993 m_statisticsHandler = sh;
998 m_statisticsHandler = 0;
1005 m_mucInvitationHandler = mih;
1012 m_mucInvitationHandler = 0;
1019 m_connectionListeners.push_back( cl );
1025 m_connectionListeners.remove( cl );
1028 void ClientBase::notifyOnConnect()
1030 ConnectionListenerList::const_iterator it = m_connectionListeners.begin();
1031 for( ; it != m_connectionListeners.end(); ++it )
1039 ConnectionListenerList::const_iterator it = m_connectionListeners.begin();
1040 for( ; it != m_connectionListeners.end(); ++it )
1042 (*it)->onDisconnect( e );
1047 bool ClientBase::notifyOnTLSConnect(
const CertInfo& info )
1049 ConnectionListenerList::const_iterator it = m_connectionListeners.begin();
1050 for( ; it != m_connectionListeners.end() && (*it)->onTLSConnect( info ); ++it )
1052 return m_stats.
encryption = ( it == m_connectionListeners.end() );
1057 ConnectionListenerList::const_iterator it = m_connectionListeners.begin();
1058 for( ; it != m_connectionListeners.end(); ++it )
1060 (*it)->onResourceBindError( error );
1066 ConnectionListenerList::const_iterator it = m_connectionListeners.begin();
1067 for( ; it != m_connectionListeners.end(); ++it )
1069 (*it)->onSessionCreateError( error );
1073 void ClientBase::notifyStreamEvent(
StreamEvent event )
1075 ConnectionListenerList::const_iterator it = m_connectionListeners.begin();
1076 for( ; it != m_connectionListeners.end(); ++it )
1078 (*it)->onStreamEvent( event );
1082 void ClientBase::notifyPresenceHandlers( Stanza *stanza )
1085 PresenceJidHandlerList::const_iterator t;
1086 PresenceJidHandlerList::const_iterator itj = m_presenceJidHandlers.begin();
1087 while( itj != m_presenceJidHandlers.end() )
1090 if( (*t).jid->bare() == stanza->from().bare() && (*t).ph )
1092 (*t).ph->handlePresence( stanza );
1099 PresenceHandlerList::const_iterator it = m_presenceHandlers.begin();
1100 for( ; it != m_presenceHandlers.end(); ++it )
1102 (*it)->handlePresence( stanza );
1106 void ClientBase::notifySubscriptionHandlers( Stanza *stanza )
1108 SubscriptionHandlerList::const_iterator it = m_subscriptionHandlers.begin();
1109 for( ; it != m_subscriptionHandlers.end(); ++it )
1111 (*it)->handleSubscription( stanza );
1115 void ClientBase::notifyIqHandlers( Stanza *stanza )
1119 IqHandlerMap::const_iterator it = m_iqNSHandlers.begin();
1120 for( ; it != m_iqNSHandlers.end(); ++it )
1122 if( stanza->hasChildWithAttrib(
"xmlns", (*it).first ) )
1124 if( (*it).second->handleIq( stanza ) )
1129 IqTrackMap::iterator it_id = m_iqIDHandlers.find( stanza->id() );
1130 if( it_id != m_iqIDHandlers.end() )
1132 if( (*it_id).second.ih->handleIqID( stanza, (*it_id).second.context ) )
1134 m_iqIDHandlers.erase( it_id );
1137 if( !res && ( stanza->type() ==
StanzaIq ) &&
1140 Tag *iq =
new Tag(
"iq" );
1141 iq->addAttribute(
"type",
"error" );
1142 iq->addAttribute(
"id", stanza->id() );
1143 iq->addAttribute(
"to", stanza->from().full() );
1144 Tag *e =
new Tag( iq,
"error",
"type",
"cancel",
false );
1150 void ClientBase::notifyMessageHandlers( Stanza *stanza )
1152 if( m_mucInvitationHandler )
1155 if( x && x->hasChild(
"invite" ) )
1157 Tag *i = x->findChild(
"invite" );
1158 JID invitee( i->findAttribute(
"from" ) );
1160 Tag * t = i->findChild(
"reason" );
1161 std::string reason ( t ? t->cdata() :
"" );
1163 t = x->findChild(
"password" );
1164 std::string
password ( t ? t->cdata() :
"" );
1166 m_mucInvitationHandler->handleMUCInvitation( stanza->from(), invitee,
1168 i->hasChild(
"continue" ) );
1173 MessageSessionList::const_iterator it1 = m_messageSessions.begin();
1174 for( ; it1 != m_messageSessions.end(); ++it1 )
1176 if( (*it1)->target().full() == stanza->from().full() &&
1177 ( stanza->thread().empty() || (*it1)->threadID() == stanza->thread() ) &&
1180 (*it1)->handleMessage( stanza );
1185 it1 = m_messageSessions.begin();
1186 for( ; it1 != m_messageSessions.end(); ++it1 )
1188 if( (*it1)->target().bare() == stanza->from().bare() &&
1189 ( stanza->thread().empty() || (*it1)->threadID() == stanza->thread() ) &&
1192 (*it1)->handleMessage( stanza );
1197 MessageSessionHandler *msHandler = 0;
1199 switch( stanza->subtype() )
1202 msHandler = m_messageSessionHandlerChat;
1205 msHandler = m_messageSessionHandlerNormal;
1208 msHandler = m_messageSessionHandlerGroupchat;
1211 msHandler = m_messageSessionHandlerHeadline;
1219 MessageSession *session =
new MessageSession(
this, stanza->from(),
true, stanza->subtype() );
1221 session->handleMessage( stanza );
1225 MessageHandlerList::const_iterator it = m_messageHandlers.begin();
1226 for( ; it != m_messageHandlers.end(); ++it )
1228 (*it)->handleMessage( stanza );
1233 void ClientBase::notifyTagHandlers( Tag *tag )
1235 TagHandlerList::const_iterator it = m_tagHandlers.begin();
1236 for( ; it != m_tagHandlers.end(); ++it )
1238 if( (*it).tag == tag->name() && tag->hasAttribute(
"xmlns", (*it).xmlns ) )
1239 (*it).th->handleTag( tag );
1243 CompressionBase* ClientBase::getDefaultCompression()
1249 return new CompressionZlib(
this );
1255 TLSBase* ClientBase::getDefaultEncryption()
1260 return new TLSDefault(
this, m_server );