📄 clientbase.cpp
字号:
case SaslMechPlain: { a->addAttribute( "mechanism", "PLAIN" ); std::string tmp; if( m_authzid ) tmp += m_authzid.bare(); tmp += '\0'; tmp += m_jid.username(); tmp += '\0'; tmp += m_password; a->setCData( Base64::encode64( tmp ) ); break; } case SaslMechAnonymous: a->addAttribute( "mechanism", "ANONYMOUS" ); a->setCData( getID() ); break; case SaslMechExternal: a->addAttribute( "mechanism", "EXTERNAL" ); if( m_authzid ) a->setCData( Base64::encode64( m_authzid.bare() ) ); else a->setCData( Base64::encode64( m_jid.bare() ) ); break; case SaslMechGssapi: {#ifdef _WIN32 a->addAttribute( "mechanism", "GSSAPI" );// The client calls GSS_Init_sec_context, passing in 0 for// input_context_handle (initially) and a targ_name equal to output_name// from GSS_Import_Name called with input_name_type of// GSS_C_NT_HOSTBASED_SERVICE and input_name_string of// "service@hostname" where "service" is the service name specified in// the protocol's profile, and "hostname" is the fully qualified host// name of the server. The client then responds with the resulting// output_token. std::string token; a->setCData( Base64::encode64( token ) );// etc... see gssapi-sasl-draft.txt#else logInstance().log( LogLevelError, LogAreaClassClientbase, "GSSAPI is not supported on this platform. You should never see this." );#endif break; } default: break; } send( a ); } void ClientBase::processSASLChallenge( const std::string& challenge ) { Tag *t = new Tag( "response" ); t->addAttribute( "xmlns", XMLNS_STREAM_SASL ); const std::string& decoded = Base64::decode64( challenge ); switch( m_selectedSaslMech ) { case SaslMechDigestMd5: { if( decoded.substr( 0, 7 ) == "rspauth" ) { break; } std::string realm; size_t r_pos = decoded.find( "realm=" ); if( r_pos != std::string::npos ) { size_t r_end = decoded.find( "\"", r_pos + 7 ); realm = decoded.substr( r_pos + 7, r_end - (r_pos + 7 ) ); } else realm = m_jid.server(); size_t n_pos = decoded.find( "nonce=" ); if( n_pos == std::string::npos ) { return; } size_t n_end = decoded.find( "\"", n_pos + 7 ); while( decoded.substr( n_end-1, 1 ) == "\\" ) n_end = decoded.find( "\"", n_end + 1 ); std::string nonce = decoded.substr( n_pos + 7, n_end - ( n_pos + 7 ) ); std::string cnonce;#ifdef _WIN32_WCE char cn[4*8+1]; for( int i = 0; i < 4; ++i ) sprintf( cn + i*8, "%08x", rand() ); cnonce.assign( cn, 4*8 );#else std::ostringstream cn; for( int i = 0; i < 4; ++i ) cn << std::hex << std::setw( 8 ) << std::setfill( '0' ) << rand(); cnonce = cn.str();#endif MD5 md5; md5.feed( m_jid.username() ); md5.feed( ":" ); md5.feed( realm ); md5.feed( ":" ); md5.feed( m_password ); md5.finalize(); const std::string& a1_h = md5.binary(); md5.reset(); md5.feed( a1_h ); md5.feed( ":" ); md5.feed( nonce ); md5.feed( ":" ); md5.feed( cnonce ); md5.finalize(); const std::string& a1 = md5.hex(); md5.reset(); md5.feed( "AUTHENTICATE:xmpp/" ); md5.feed( m_jid.server() ); md5.finalize(); const std::string& a2 = md5.hex(); md5.reset(); md5.feed( a1 ); md5.feed( ":" ); md5.feed( nonce ); md5.feed( ":00000001:" ); md5.feed( cnonce ); md5.feed( ":auth:" ); md5.feed( a2 ); md5.finalize(); const std::string& response_value = md5.hex(); std::string response = "username=\"" + m_jid.username() + "\",realm=\"" + realm; response += "\",nonce=\""+ nonce + "\",cnonce=\"" + cnonce; response += "\",nc=00000001,qop=auth,digest-uri=\"xmpp/" + m_jid.server() + "\",response="; response += response_value; response += ",charset=utf-8"; if( m_authzid ) response += ",authzid=" + m_authzid.bare(); t->setCData( Base64::encode64( response ) ); break; } case SaslMechGssapi:#ifdef _WIN32 // see gssapi-sasl-draft.txt#else m_logInstance.log( LogLevelError, LogAreaClassClientbase, "Huh, received GSSAPI challenge?! This should have never happened!" );#endif break; default: // should never happen. break; } send( t ); } void ClientBase::processSASLError( Stanza *stanza ) { if( stanza->hasChild( "aborted" ) ) m_authError = SaslAborted; else if( stanza->hasChild( "incorrect-encoding" ) ) m_authError = SaslIncorrectEncoding; else if( stanza->hasChild( "invalid-authzid" ) ) m_authError = SaslInvalidAuthzid; else if( stanza->hasChild( "invalid-mechanism" ) ) m_authError = SaslInvalidMechanism; else if( stanza->hasChild( "mechanism-too-weak" ) ) m_authError = SaslMechanismTooWeak; else if( stanza->hasChild( "not-authorized" ) ) m_authError = SaslNotAuthorized; else if( stanza->hasChild( "temporary-auth-failure" ) ) m_authError = SaslTemporaryAuthFailure; } void ClientBase::send( Tag *tag ) { if( !tag ) return; send( tag->xml() ); switch( tag->type() ) { case StanzaIq: ++m_stats.iqStanzasSent; break; case StanzaMessage: ++m_stats.messageStanzasSent; break; case StanzaS10n: ++m_stats.s10nStanzasSent; break; case StanzaPresence: ++m_stats.presenceStanzasSent; break; default: break; } ++m_stats.totalStanzasSent; delete tag; if( m_statisticsHandler ) m_statisticsHandler->handleStatistics( getStatistics() ); } void ClientBase::send( const std::string& xml ) { if( m_connection && m_connection->state() == StateConnected ) { if( m_compression && m_compressionActive ) m_compression->compress( xml ); else if( m_encryption && m_encryptionActive ) m_encryption->encrypt( xml ); else m_connection->send( xml ); logInstance().log( LogLevelDebug, LogAreaXmlOutgoing, xml ); } } StatisticsStruct ClientBase::getStatistics() {// if( m_connection )// m_connection->getStatistics( m_stats.totalBytesReceived, m_stats.totalBytesSent,// m_stats.compressedBytesReceived, m_stats.compressedBytesSent,// m_stats.uncompressedBytesReceived, m_stats.uncompressedBytesSent,// m_stats.compression ); return m_stats; } ConnectionState ClientBase::state() const { return m_connection ? m_connection->state() : StateDisconnected; } void ClientBase::whitespacePing() { send( " " ); } void ClientBase::xmppPing( const JID& to ) { const std::string& id = getID(); Tag *iq = new Tag( "iq" ); iq->addAttribute( "to", to.full() ); iq->addAttribute( "id", id ); iq->addAttribute( "type", "get" ); Tag *p = new Tag( iq, "ping" ); p->addAttribute( "xmlns", XMLNS_XMPP_PING ); send( iq ); } const std::string ClientBase::getID() {#ifdef _WIN32_WCE char r[8+1]; sprintf( r, "%08x", rand() ); std::string ret( r, 8 ); return std::string( "uid" ) + ret;#else std::ostringstream oss; oss << ++m_idCount; return std::string( "uid" ) + oss.str();#endif } bool ClientBase::checkStreamVersion( const std::string& version ) { if( version.empty() ) return false; int major = 0; int minor = 0; int myMajor = atoi( XMPP_STREAM_VERSION_MAJOR.c_str() ); size_t dot = version.find( "." ); if( !version.empty() && dot && dot != std::string::npos ) { major = atoi( version.substr( 0, dot ).c_str() ); minor = atoi( version.substr( dot ).c_str() ); } return myMajor >= major; } LogSink& ClientBase::logInstance() { return m_logInstance; } void ClientBase::setConnectionImpl( ConnectionBase *cb ) { if( m_connection ) { delete m_connection; } m_connection = cb; } void ClientBase::setEncryptionImpl( TLSBase *tb ) { if( m_encryption ) { delete m_encryption; } m_encryption = tb; } void ClientBase::setCompressionImpl( CompressionBase *cb ) { if( m_compression ) { delete m_compression; } m_compression = cb; } void ClientBase::handleStreamError( Stanza *stanza ) { StreamError err = StreamErrorUndefined; const Tag::TagList& c = stanza->children(); Tag::TagList::const_iterator it = c.begin(); for( ; it != c.end(); ++it ) { if( (*it)->name() == "bad-format" ) err = StreamErrorBadFormat; else if( (*it)->name() == "bad-namespace-prefix" ) err = StreamErrorBadNamespacePrefix; else if( (*it)->name() == "conflict" ) err = StreamErrorConflict; else if( (*it)->name() == "connection-timeout" ) err = StreamErrorConnectionTimeout; else if( (*it)->name() == "host-gone" ) err = StreamErrorHostGone; else if( (*it)->name() == "host-unknown" ) err = StreamErrorHostUnknown; else if( (*it)->name() == "improper-addressing" ) err = StreamErrorImproperAddressing; else if( (*it)->name() == "internal-server-error" ) err = StreamErrorInternalServerError; else if( (*it)->name() == "invalid-from" ) err = StreamErrorInvalidFrom; else if( (*it)->name() == "invalid-id" ) err = StreamErrorInvalidId; else if( (*it)->name() == "invalid-namespace" ) err = StreamErrorInvalidNamespace; else if( (*it)->name() == "invalid-xml" ) err = StreamErrorInvalidXml; else if( (*it)->name() == "not-authorized" ) err = StreamErrorNotAuthorized; else if( (*it)->name() == "policy-violation" ) err = StreamErrorPolicyViolation; else if( (*it)->name() == "remote-connection-failed" ) err = StreamErrorRemoteConnectionFailed; else if( (*it)->name() == "resource-constraint" ) err = StreamErrorResourceConstraint; else if( (*it)->name() == "restricted-xml" ) err = StreamErrorRestrictedXml; else if( (*it)->name() == "see-other-host" ) { err = StreamErrorSeeOtherHost; m_streamErrorCData = stanza->findChild( "see-other-host" )->cdata(); } else if( (*it)->name() == "system-shutdown" ) err = StreamErrorSystemShutdown; else if( (*it)->name() == "undefined-condition" ) err = StreamErrorUndefinedCondition; else if( (*it)->name() == "unsupported-encoding" ) err = StreamErrorUnsupportedEncoding; else if( (*it)->name() == "unsupported-stanza-type" ) err = StreamErrorUnsupportedStanzaType; else if( (*it)->name() == "unsupported-version" ) err = StreamErrorUnsupportedVersion; else if( (*it)->name() == "xml-not-well-formed" ) err = StreamErrorXmlNotWellFormed; else if( (*it)->name() == "text" ) { const std::string& lang = (*it)->findAttribute( "xml:lang" ); if( !lang.empty() ) m_streamErrorText[lang] = (*it)->cdata(); else m_streamErrorText["default"] = (*it)->cdata(); } else m_streamErrorAppCondition = (*it); if( err != StreamErrorUndefined && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STREAM ) ) m_streamError = err; } } const std::string ClientBase::streamErrorText( const std::string& lang ) const { StringMap::const_iterator it = m_streamErrorText.find( lang ); return ( it != m_streamErrorText.end() ) ? (*it).second : std::string(); } void ClientBase::registerMessageSessionHandler( MessageSessionHandler *msh, int types ) { if( types & StanzaMessageChat || types == 0 ) m_messageSessionHandlerChat = msh; if( types & StanzaMessageNormal || types == 0 ) m_messageSessionHandlerNormal = msh; if( types & StanzaMessageGroupchat || types == 0 ) m_messageSessionHandlerGroupchat = msh; if( types & StanzaMessageHeadline || types == 0 )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -