From 87bfbefebab8bf25cfcbfd0b4935d8e6822f4508 Mon Sep 17 00:00:00 2001 From: Fabio Bas Date: Sat, 13 Feb 2010 11:21:16 +0000 Subject: server config: changed "supportsSTARTTLS" to "enabledSTARTTLS" and enabled by default; this option is now meaningful only as a way to force STARTTLS disabled on a server that supports it; server config: added "enabledSASL", "SaslNick", "SaslPass" options main config: added global "enable SASL" option sparser: handle CAP LS, REQ, ACK, NAK, END ircconnection: added SASL support (only PLAIN method is supported by now) git-svn-id: https://svn.kvirc.de/svn/trunk/kvirc@3958 17fca916-40b9-46aa-a4ea-0a15b648b75c --- src/kvilib/irc/kvi_ircserver.cpp | 37 +++++++++++--- src/kvilib/irc/kvi_ircserver.h | 60 ++++++++++++++++++++--- src/kvilib/irc/kvi_ircserverdb.cpp | 4 +- src/kvirc/kernel/kvi_ircconnection.cpp | 62 +++++++++++++++++++++--- src/kvirc/kernel/kvi_ircconnection.h | 26 +++++++--- src/kvirc/kernel/kvi_ircconnectionserverinfo.cpp | 21 +++++++- src/kvirc/kernel/kvi_ircconnectionserverinfo.h | 8 ++- src/kvirc/kernel/kvi_ircconnectionstatedata.cpp | 1 + src/kvirc/kernel/kvi_ircconnectionstatedata.h | 4 ++ src/kvirc/kernel/kvi_irccontext.cpp | 6 +-- src/kvirc/kernel/kvi_options.cpp | 6 ++- src/kvirc/kernel/kvi_options.h | 5 +- src/kvirc/kernel/kvi_out.h | 3 +- src/kvirc/sparser/kvi_numeric.h | 9 +++- src/kvirc/sparser/kvi_sp_literal.cpp | 47 ++++++++++++++++-- src/kvirc/sparser/kvi_sp_numeric.cpp | 46 +++++++++++++++++- src/kvirc/sparser/kvi_sp_tables.cpp | 47 +++++++++--------- src/kvirc/sparser/kvi_sparser.h | 8 ++- src/modules/options/optw_connection.cpp | 6 ++- src/modules/options/optw_servers.cpp | 49 ++++++++++++++----- src/modules/options/optw_servers.h | 5 +- 21 files changed, 377 insertions(+), 83 deletions(-) diff --git a/src/kvilib/irc/kvi_ircserver.cpp b/src/kvilib/irc/kvi_ircserver.cpp index ff81d171a..598fe99fc 100644 --- a/src/kvilib/irc/kvi_ircserver.cpp +++ b/src/kvilib/irc/kvi_ircserver.cpp @@ -87,6 +87,8 @@ KviServer::KviServer(const KviServer & serv) m_iProxy = serv.m_iProxy; m_szUserIdentityId = serv.m_szUserIdentityId; m_bAutoConnect = serv.m_bAutoConnect; + m_szSaslNick = serv.m_szSaslNick; + m_szSaslPass = serv.m_szSaslPass; if(serv.m_pAutoJoinChannelList) m_pAutoJoinChannelList = new QStringList(*(serv.m_pAutoJoinChannelList)); @@ -118,6 +120,8 @@ void KviServer::operator=(const KviServer & serv) m_szUserIdentityId = serv.m_szUserIdentityId; m_iProxy = serv.m_iProxy; m_bAutoConnect = serv.m_bAutoConnect; + m_szSaslNick = serv.m_szSaslNick; + m_szSaslPass = serv.m_szSaslPass; if(m_pAutoJoinChannelList) delete m_pAutoJoinChannelList; if(serv.m_pAutoJoinChannelList) @@ -154,7 +158,7 @@ void KviServer::generateUniqueId() QString KviServer::ircUri() { QString szUri("irc"); - if(useSSL() || supportsSTARTTLS()) szUri += "s"; + if(useSSL()) szUri += "s"; if(isIPv6()) szUri += "6"; szUri += "://"; szUri += m_szHostname; @@ -192,6 +196,10 @@ bool KviServer::load(KviConfig * cfg, const QString & szPrefix) m_szPass = cfg->readQStringEntry(szTmp); KviQString::sprintf(szTmp,"%QNick",&szPrefix); m_szNick = cfg->readQStringEntry(szTmp); + KviQString::sprintf(szTmp,"%QSaslPass",&szPrefix); + m_szSaslPass = cfg->readQStringEntry(szTmp); + KviQString::sprintf(szTmp,"%QSaslNick",&szPrefix); + m_szSaslNick = cfg->readQStringEntry(szTmp); KviQString::sprintf(szTmp,"%QRealName",&szPrefix); m_szRealName = cfg->readQStringEntry(szTmp); KviQString::sprintf(szTmp,"%QInitUmode",&szPrefix); @@ -224,8 +232,10 @@ bool KviServer::load(KviConfig * cfg, const QString & szPrefix) setCacheIp(cfg->readBoolEntry(szTmp,false)); // true ? KviQString::sprintf(szTmp,"%QSSL",&szPrefix); setUseSSL(cfg->readBoolEntry(szTmp,false)); - KviQString::sprintf(szTmp,"%QSupportsSTARTTLS",&szPrefix); - setSupportsSTARTTLS(cfg->readBoolEntry(szTmp,false)); + KviQString::sprintf(szTmp,"%QEnabledSTARTTLS",&szPrefix); + setEnabledSTARTTLS(cfg->readBoolEntry(szTmp,true)); + KviQString::sprintf(szTmp,"%QEnabledSASL",&szPrefix); + setEnabledSASL(cfg->readBoolEntry(szTmp,false)); KviQString::sprintf(szTmp,"%QProxy",&szPrefix); setProxy(cfg->readIntEntry(szTmp,-2)); KviQString::sprintf(szTmp,"%QUserIdentityId",&szPrefix); @@ -265,6 +275,16 @@ void KviServer::save(KviConfig * cfg, const QString & szPrefix) KviQString::sprintf(szTmp,"%QNick",&szPrefix); cfg->writeEntry(szTmp,m_szNick); } + if(!m_szSaslPass.isEmpty()) + { + KviQString::sprintf(szTmp,"%QSaslPass",&szPrefix); + cfg->writeEntry(szTmp,m_szSaslPass); + } + if(!m_szSaslNick.isEmpty()) + { + KviQString::sprintf(szTmp,"%QSaslNick",&szPrefix); + cfg->writeEntry(szTmp,m_szSaslNick); + } if(!m_szRealName.isEmpty()) { KviQString::sprintf(szTmp,"%QRealName",&szPrefix); @@ -330,10 +350,15 @@ void KviServer::save(KviConfig * cfg, const QString & szPrefix) KviQString::sprintf(szTmp,"%QSSL",&szPrefix); cfg->writeEntry(szTmp,useSSL()); } - if(supportsSTARTTLS()) + if(!enabledSTARTTLS()) + { + KviQString::sprintf(szTmp,"%QEnabledSTARTTLS",&szPrefix); + cfg->writeEntry(szTmp,enabledSTARTTLS()); + } + if(enabledSASL()) { - KviQString::sprintf(szTmp,"%QSupportsSTARTTLS",&szPrefix); - cfg->writeEntry(szTmp,supportsSTARTTLS()); + KviQString::sprintf(szTmp,"%QEnabledSASL",&szPrefix); + cfg->writeEntry(szTmp,enabledSASL()); } if(proxy()!=-2) { diff --git a/src/kvilib/irc/kvi_ircserver.h b/src/kvilib/irc/kvi_ircserver.h index abadae0f6..cbfe24f24 100644 --- a/src/kvilib/irc/kvi_ircserver.h +++ b/src/kvilib/irc/kvi_ircserver.h @@ -32,7 +32,8 @@ * \def KVI_IRCSERVER_FLAG_IPV6 Defines if the server uses IPv6 * \def KVI_IRCSERVER_FLAG_CACHEIP Defines if the server caches the IP * \def KVI_IRCSERVER_FLAG_SSL Defines if the server uses SSL -* \def KVI_IRCSERVER_FLAG_STARTTLS Defines if the server uses STARTTLS +* \def KVI_IRCSERVER_FLAG_STARTTLS Defines if the server can use STARTTLS +* \def KVI_IRCSERVER_FLAG_SASL Defines if the server can use SASL */ #include "kvi_settings.h" @@ -52,6 +53,7 @@ class KviServer; #define KVI_IRCSERVER_FLAG_CACHEIP 2 #define KVI_IRCSERVER_FLAG_SSL 4 #define KVI_IRCSERVER_FLAG_STARTTLS 8 +#define KVI_IRCSERVER_FLAG_SASL 16 /** * \class KviServerReconnectInfo @@ -135,6 +137,9 @@ public: bool m_bAutoConnect; // autoconnect QString m_szId; // the server's may-be-unique id, may be auto-generated int m_iProxy; // proxy server's id + QString m_szSaslNick; // nickname for sasl auth + QString m_szSaslPass; // password for sasl auth + public: /** * \brief Returns the proxy server's id @@ -161,6 +166,18 @@ public: */ inline const QString & password() const { return m_szPass; }; + /** + * \brief Returns the nickname used for sasl auth + * \return const QString & + */ + inline const QString & saslNick() const { return m_szSaslNick; }; + + /** + * \brief Returns the password used for sasl auth + * \return const QString & + */ + inline const QString & saslPass() const { return m_szSaslPass; }; + /** * \brief Returns the nickname of the user associated to the server * \return const QString & @@ -273,10 +290,16 @@ public: inline bool useSSL() const { return (m_uFlags & KVI_IRCSERVER_FLAG_SSL); }; /** - * \brief Returns true if the server supports the STARTTLS protocol + * \brief Returns true if the STARTTLS protocol is enabled for this server * \return bool */ - inline bool supportsSTARTTLS() const { return (m_uFlags & KVI_IRCSERVER_FLAG_STARTTLS); }; + inline bool enabledSTARTTLS() const { return (m_uFlags & KVI_IRCSERVER_FLAG_STARTTLS); }; + + /** + * \brief Returns true if the SASL protocol is enabled for this server + * \return bool + */ + inline bool enabledSASL() const { return (m_uFlags & KVI_IRCSERVER_FLAG_SASL); }; /** * \brief Returns true if the server caches the IP @@ -347,6 +370,20 @@ public: */ inline void setNickName(const QString & szNick){ m_szNick = szNick; }; + /** + * \brief Sets the password used for sasl auth + * \param szPass The password of the user + * \return void + */ + inline void setSaslPass(const QString & szPass){ m_szSaslPass = szPass; }; + + /** + * \brief Sets the nickname used for sasl auth + * \param szNick The nick name of the user + * \return void + */ + inline void setSaslNick(const QString & szNick){ m_szSaslNick = szNick; }; + /** * \brief Sets the realname of the user associated to the server * \param szReal The real name of the user @@ -445,16 +482,27 @@ public: }; /** - * \brief Sets if the server supports the STARTTLS protocol - * \param bSet Whether to set the support for STARTTLS + * \brief Sets if STARTTLS support is enabled/disabled for this server + * \param bSet Whether to enable the support for STARTTLS * \return void */ - inline void setSupportsSTARTTLS(bool bSet) + inline void setEnabledSTARTTLS(bool bSet) { if(bSet)m_uFlags |= KVI_IRCSERVER_FLAG_STARTTLS; else m_uFlags &= ((unsigned short)~KVI_IRCSERVER_FLAG_STARTTLS); }; + /** + * \brief Sets if SASL support is enabled/disabled for this server + * \param bSet Whether to enable the support for SASL + * \return void + */ + inline void setEnabledSASL(bool bSet) + { + if(bSet)m_uFlags |= KVI_IRCSERVER_FLAG_SASL; + else m_uFlags &= ((unsigned short)~KVI_IRCSERVER_FLAG_SASL); + }; + /** * \brief Sets if the server caches the IP * \param bSet Whether to set the cache for the IP diff --git a/src/kvilib/irc/kvi_ircserverdb.cpp b/src/kvilib/irc/kvi_ircserverdb.cpp index e2f839f2f..8819fe854 100644 --- a/src/kvilib/irc/kvi_ircserverdb.cpp +++ b/src/kvilib/irc/kvi_ircserverdb.cpp @@ -201,7 +201,7 @@ bool KviServerDataBase::makeCurrentServer(KviServerDefinition * d, QString & szE { if(d->bIPv6 == srv->isIPv6()) { - if((d->bSSL == srv->useSSL()) || (d->bSTARTTLS == srv->supportsSTARTTLS())) + if(d->bSSL == srv->useSSL()) { if(d->bPortIsValid) { @@ -319,7 +319,7 @@ search_finished: s->m_szInitUMode = d->szInitUMode; s->setIPv6(d->bIPv6); s->setUseSSL(d->bSSL); - s->setSupportsSTARTTLS(d->bSTARTTLS); + s->setEnabledSTARTTLS(d->bSTARTTLS); r->insertServer(s); m_szCurrentNetwork = r->name(); r->setCurrentServer(s); diff --git a/src/kvirc/kernel/kvi_ircconnection.cpp b/src/kvirc/kernel/kvi_ircconnection.cpp index d736fe5ed..347064414 100644 --- a/src/kvirc/kernel/kvi_ircconnection.cpp +++ b/src/kvirc/kernel/kvi_ircconnection.cpp @@ -77,7 +77,6 @@ KviIrcConnection::KviIrcConnection(KviIrcContext * pContext,KviIrcConnectionTarg : QObject() { m_bIdentdAttached = false; - m_bInsideCapLsRequest = false; m_pContext = pContext; m_pConsole = pContext->console(); m_pTarget = pTarget; @@ -324,20 +323,23 @@ void KviIrcConnection::linkEstabilished() // And, probably, NICK hack is better then PING hack as soon as freenode // not answer to ping! - m_bInsideCapLsRequest = true; + m_pStateData->setInsideCapLs(true); sendFmtData("CAP LS\r\nPING :%s",target()->server()->hostName().data()); } void KviIrcConnection::handleCapLs() { qDebug("handleCapLs"); - m_bInsideCapLsRequest = false; + m_pStateData->setInsideCapLs(false); + + // STARTTLS support: this has to be checked first because it could imply + // a full cap renegotiation #ifdef COMPILE_SSL_SUPPORT if( KVI_OPTION_BOOL(KviOption_boolUseStartTlsIfAvailable) && (!link()->socket()->usingSSL()) && - (serverInfo()->supportedCaps().contains("tls",Qt::CaseInsensitive) || - target()->server()->supportsSTARTTLS()) + target()->server()->enabledSTARTTLS() && + serverInfo()->supportedCaps().contains("tls",Qt::CaseInsensitive) ) { trySTARTTLS(); @@ -345,6 +347,54 @@ void KviIrcConnection::handleCapLs() } #endif + QString szRequests; + + //SASL + if(KVI_OPTION_BOOL(KviOption_boolUseSaslIfAvailable) && + target()->server()->enabledSASL() && + serverInfo()->supportedCaps().contains("sasl",Qt::CaseInsensitive) + ) + { + szRequests.append("sasl "); + } + + //TODO MULTI-PREFIX, others goes here + + if(szRequests.isEmpty()) endCapLs(); + else sendFmtData("CAP REQ :%s",szRequests.trimmed().toUtf8().data()); +} + +void KviIrcConnection::handleCapAck() +{ + qDebug("handleCapAck"); + + //SASL + if(KVI_OPTION_BOOL(KviOption_boolUseSaslIfAvailable) && + target()->server()->enabledSASL() && + serverInfo()->enabledCaps().contains("sasl",Qt::CaseInsensitive) + ) + { + sendFmtData("AUTHENTICATE PLAIN"); + //server will send us a "AUTHENTICATE +" answer; we won't wait for this extra step + QByteArray szAuth = encodeText(target()->server()->saslNick()); + szAuth.append('\0'); + szAuth.append(encodeText(target()->server()->saslNick())); + szAuth.append('\0'); + szAuth.append(encodeText(target()->server()->saslPass())); + sendFmtData("AUTHENTICATE %s",szAuth.toBase64().data()); + } + + endCapLs(); +} + +void KviIrcConnection::handleCapNak() +{ + qDebug("handleCapNak"); + endCapLs(); +} + +void KviIrcConnection::endCapLs() +{ sendFmtData("CAP END"); loginToIrcServer(); } @@ -352,7 +402,7 @@ void KviIrcConnection::handleCapLs() void KviIrcConnection::handleFailedCapLs() { qDebug("handleFailedCapLs"); - m_bInsideCapLsRequest = false; + m_pStateData->setInsideCapLs(false); loginToIrcServer(); } diff --git a/src/kvirc/kernel/kvi_ircconnection.h b/src/kvirc/kernel/kvi_ircconnection.h index 9944ea219..0928244e3 100644 --- a/src/kvirc/kernel/kvi_ircconnection.h +++ b/src/kvirc/kernel/kvi_ircconnection.h @@ -178,8 +178,6 @@ private: QTextCodec * m_pSrvCodec; // connection codec: never null QTextCodec * m_pTextCodec; // connection codec: never null KviRequestQueue * m_pRequestQueue; // owned, never null - - bool m_bInsideCapLsRequest; public: /** * \brief Returns a pointer to the owning console @@ -220,12 +218,6 @@ public: * \return State */ inline State state(){ return m_eState; }; - - /** - * \brief Returns true if the connection is waiting for an answer to a "CAP LS" request - * \return bool - */ - inline bool isInsideCapLsRequest(){ return m_bInsideCapLsRequest; }; /** * \brief Returns a pointer to the big connection user database. @@ -742,6 +734,24 @@ protected: */ void handleFailedCapLs(); + /** + * \brief Called when CAP ACK answer is received + * \return void + */ + void handleCapAck(); + + /** + * \brief Called when CAP NAK answer is received + * \return void + */ + void handleCapNak(); + + /** + * \brief Called when we want to end CAP negotiation and go on wi the login + * \return void + */ + void endCapLs(); + /** * \brief Called to update the away state * \param bAway Whether we enter the away mode diff --git a/src/kvirc/kernel/kvi_ircconnectionserverinfo.cpp b/src/kvirc/kernel/kvi_ircconnectionserverinfo.cpp index ca8f91286..040d309a6 100644 --- a/src/kvirc/kernel/kvi_ircconnectionserverinfo.cpp +++ b/src/kvirc/kernel/kvi_ircconnectionserverinfo.cpp @@ -58,9 +58,28 @@ void KviIrcConnectionServerInfo::setSupportsCaps(QString szCaps) { m_bSupportsCap=true; qDebug("server support caps: %s",szCaps.toUtf8().data()); - m_szaCap = szCaps.split(' ', QString::SkipEmptyParts); + m_szaSupportedCaps = szCaps.split(' ', QString::SkipEmptyParts); } +void KviIrcConnectionServerInfo::setEnableCaps(QString szCaps) +{ + qDebug("server enabled caps: %s",szCaps.toUtf8().data()); + m_szaEnabledCaps.append(szCaps.split(' ', QString::SkipEmptyParts)); + m_szaEnabledCaps.removeDuplicates(); +} + +void KviIrcConnectionServerInfo::setDisableCaps(QString szCaps) +{ + qDebug("server disabled caps: %s",szCaps.toUtf8().data()); + QStringList szaDisabled = szCaps.split(' ', QString::SkipEmptyParts); + + for (int i = 0; i < szaDisabled.size(); ++i) + { + m_szaEnabledCaps.removeOne(szaDisabled.at(i)); + } +} + + void KviIrcConnectionServerInfo::setSupportedChannelModes(const QString &szSupportedChannelModes) { int pos=-1; diff --git a/src/kvirc/kernel/kvi_ircconnectionserverinfo.h b/src/kvirc/kernel/kvi_ircconnectionserverinfo.h index d1f1bdc84..293564940 100644 --- a/src/kvirc/kernel/kvi_ircconnectionserverinfo.h +++ b/src/kvirc/kernel/kvi_ircconnectionserverinfo.h @@ -100,7 +100,8 @@ private: QString m_szListModes; QString m_szPlainModes; bool m_bSupportsCap; - QStringList m_szaCap; + QStringList m_szaSupportedCaps; + QStringList m_szaEnabledCaps; public: char registerModeChar() { return m_pServInfo ? m_pServInfo->getRegisterModeChar() : 0; }; const QString & name(){ return m_szName; }; @@ -114,7 +115,8 @@ public: bool supportsModesIe(){ return m_bSupportsModesIe; }; bool supportsModeq(){ return m_bSupportsModeq; }; bool supportsCap(){ return m_bSupportsCap; }; - QStringList supportedCaps(){ return m_szaCap; }; + QStringList supportedCaps(){ return m_szaSupportedCaps; }; + QStringList enabledCaps(){ return m_szaEnabledCaps; }; bool supportsWatchList(){ return m_bSupportsWatchList; }; bool supportsCodePages(){ return m_bSupportsCodePages; }; @@ -141,6 +143,8 @@ protected: void setSupportsWatchList(bool bSupportsWatchList){ m_bSupportsWatchList = bSupportsWatchList; }; void setSupportsCodePages(bool bSupportsCodePages){ m_bSupportsCodePages = bSupportsCodePages; }; void setSupportsCaps(QString szCaps); + void setEnableCaps(QString szCaps); + void setDisableCaps(QString szCaps); void setMaxTopicLen( int iTopLen ) { m_iMaxTopicLen=iTopLen; }; void setMaxModeChanges(int iModes ) { m_iMaxModeChanges=iModes; }; private: diff --git a/src/kvirc/kernel/kvi_ircconnectionstatedata.cpp b/src/kvirc/kernel/kvi_ircconnectionstatedata.cpp index 0102a227b..163ad8b28 100644 --- a/src/kvirc/kernel/kvi_ircconnectionstatedata.cpp +++ b/src/kvirc/kernel/kvi_ircconnectionstatedata.cpp @@ -30,6 +30,7 @@ KviIrcConnectionStateData::KviIrcConnectionStateData() { m_bSentStartTls = false; m_bSentQuit = false; + m_bInsideCapLs = false; m_uLoginNickIndex = 0; m_bSimulateUnexpectedDisconnect = false; m_tLastReceivedChannelWhoReply = kvi_unixTime(); diff --git a/src/kvirc/kernel/kvi_ircconnectionstatedata.h b/src/kvirc/kernel/kvi_ircconnectionstatedata.h index 790456740..6fcebbef5 100644 --- a/src/kvirc/kernel/kvi_ircconnectionstatedata.h +++ b/src/kvirc/kernel/kvi_ircconnectionstatedata.h @@ -44,6 +44,7 @@ public: KviIrcConnectionStateData(); ~KviIrcConnectionStateData(); protected: + bool m_bInsideCapLs; // true if there's a CAP LS request pending bool m_bSentStartTls; // the state of STARTTLS protocol bool m_bSentQuit; // have we sent the quit message for this connection ? unsigned int m_uLoginNickIndex; // the index of the identity nicknames used until now (see KviIrcConnection::loginToIrcServer()) @@ -56,6 +57,9 @@ public: bool sentStartTls(){ return m_bSentStartTls; }; void setSentStartTls(){ m_bSentStartTls = true; }; + bool isInsideCapLs(){ return m_bInsideCapLs; }; + void setInsideCapLs(bool bInside){ m_bInsideCapLs = bInside; }; + bool sentQuit(){ return m_bSentQuit; }; void setSentQuit(){ m_bSentQuit = true; }; diff --git a/src/kvirc/kernel/kvi_irccontext.cpp b/src/kvirc/kernel/kvi_irccontext.cpp index c723b8ba8..edbbb785f 100644 --- a/src/kvirc/kernel/kvi_irccontext.cpp +++ b/src/kvirc/kernel/kvi_irccontext.cpp @@ -570,7 +570,7 @@ void KviIrcContext::connectToCurrentServer() m_pSavedAsynchronousConnectionData->bPortIsOk = true; m_pSavedAsynchronousConnectionData->bUseIPv6 = srv->isIPv6(); m_pSavedAsynchronousConnectionData->bUseSSL = srv->useSSL(); - m_pSavedAsynchronousConnectionData->bSTARTTLS = srv->supportsSTARTTLS(); + m_pSavedAsynchronousConnectionData->bSTARTTLS = srv->enabledSTARTTLS(); m_pSavedAsynchronousConnectionData->szPass = srv->password(); m_pSavedAsynchronousConnectionData->szServerId = srv->id(); m_pSavedAsynchronousConnectionData->szInitUMode = srv->m_szInitUMode; @@ -627,7 +627,7 @@ void KviIrcContext::connectionFailed(int iError) d->bPortIsOk = true; d->bUseIPv6 = oldServer.isIPv6(); d->bUseSSL = oldServer.useSSL(); - d->bSTARTTLS = oldServer.supportsSTARTTLS(); + d->bSTARTTLS = oldServer.enabledSTARTTLS(); d->szPass = oldServer.password(); d->szNick = oldNickname; d->szInitUMode = oldServer.m_szInitUMode; @@ -811,7 +811,7 @@ void KviIrcContext::connectionTerminated() d->bPortIsOk = true; d->bUseIPv6 = oldServer.isIPv6(); d->bUseSSL = oldServer.useSSL(); - d->bSTARTTLS = oldServer.supportsSTARTTLS(); + d->bSTARTTLS = oldServer.enabledSTARTTLS(); d->szPass = oldServer.password(); d->szInitUMode = oldServer.m_szInitUMode; d->m_pReconnectInfo = new KviServerReconnectInfo(*(pInfo)); diff --git a/src/kvirc/kernel/kvi_options.cpp b/src/kvirc/kernel/kvi_options.cpp index c8f5ddea2..1c095c1df 100644 --- a/src/kvirc/kernel/kvi_options.cpp +++ b/src/kvirc/kernel/kvi_options.cpp @@ -322,7 +322,8 @@ KviBoolOption g_boolOptionsTable[KVI_NUM_BOOL_OPTIONS]= BOOL_OPTION("FlashDccChatWindowOnNewMessages",true,KviOption_sectFlagFrame), BOOL_OPTION("PopupNotifierOnNewDccChatMessages",true,KviOption_sectFlagFrame), BOOL_OPTION("UseAwayMessage",true,KviOption_sectFlagConnection), - BOOL_OPTION("DisableQuietBanListRequestOnJoin",true,KviOption_sectFlagConnection) + BOOL_OPTION("DisableQuietBanListRequestOnJoin",true,KviOption_sectFlagConnection), + BOOL_OPTION("UseSaslIfAvailable",true,KviOption_sectFlagConnection) }; #define STRING_OPTION(_txt,_val,_flags) KviStringOption(KVI_STRING_OPTIONS_PREFIX _txt,_val,_flags) @@ -854,7 +855,8 @@ KviMsgTypeOption g_msgtypeOptionsTable[KVI_NUM_MSGTYPE_OPTIONS]= MSGTYPE_OPTION("IrcOp",__tr_no_lookup("IRC Op status set"),KVI_SMALLICON_IRCOP,KVI_MSGTYPE_LEVEL_5), MSGTYPE_OPTION("DeIrcOp",__tr_no_lookup("IRC Op status unset"),KVI_SMALLICON_DEIRCOP,KVI_MSGTYPE_LEVEL_5), MSGTYPE_OPTION("MeIrcOp",__tr_no_lookup("Own IRC Op status set"),KVI_SMALLICON_MEIRCOP,KVI_MSGTYPE_LEVEL_5), - MSGTYPE_OPTION("MeDeIrcOp",__tr_no_lookup("Own IRC Op status unset"),KVI_SMALLICON_MEDEIRCOP,KVI_MSGTYPE_LEVEL_5) + MSGTYPE_OPTION("MeDeIrcOp",__tr_no_lookup("Own IRC Op status unset"),KVI_SMALLICON_MEDEIRCOP,KVI_MSGTYPE_LEVEL_5), + MSGTYPE_OPTION("Cap",__tr_no_lookup("Extended capability message"),KVI_SMALLICON_SERVERINFO,KVI_MSGTYPE_LEVEL_1) }; static const char * options_section_table[KVI_NUM_OPTION_SECT_FLAGS] = diff --git a/src/kvirc/kernel/kvi_options.h b/src/kvirc/kernel/kvi_options.h index 289149cab..129f77f20 100644 --- a/src/kvirc/kernel/kvi_options.h +++ b/src/kvirc/kernel/kvi_options.h @@ -330,8 +330,9 @@ DECLARE_OPTION_STRUCT(KviStringListOption,QStringList) #define KviOption_boolPopupNotifierOnNewDccChatMessages 236 /* dcc:chat */ #define KviOption_boolUseAwayMessage 237 /* away */ #define KviOption_boolDisableQuietBanListRequestOnJoin 238 /* channel */ +#define KviOption_boolUseSaslIfAvailable 239 -#define KVI_NUM_BOOL_OPTIONS 239 +#define KVI_NUM_BOOL_OPTIONS 240 #define KVI_STRING_OPTIONS_PREFIX "string" @@ -631,7 +632,7 @@ namespace KviIdentdOutputMode { #define KVI_MSGTYPE_OPTIONS_PREFIX "msgtype" #define KVI_MSGTYPE_OPTIONS_PREFIX_LEN 7 -#define KVI_NUM_MSGTYPE_OPTIONS 141 +#define KVI_NUM_MSGTYPE_OPTIONS 142 diff --git a/src/kvirc/kernel/kvi_out.h b/src/kvirc/kernel/kvi_out.h index 210ad6178..ce0317d77 100644 --- a/src/kvirc/kernel/kvi_out.h +++ b/src/kvirc/kernel/kvi_out.h @@ -165,8 +165,9 @@ #define KVI_OUT_DEIRCOP 138 #define KVI_OUT_MEIRCOP 139 #define KVI_OUT_MEDEIRCOP 140 +#define KVI_OUT_CAP 141 -//#define KVI_NUM_MSGTYPE_OPTIONS 141 +//#define KVI_NUM_MSGTYPE_OPTIONS 142 // UPDATE THE TOTAL COUNT IN kvi_options.h !!!! diff --git a/src/kvirc/sparser/kvi_numeric.h b/src/kvirc/sparser/kvi_numeric.h index f88ac5285..4692d87be 100644 --- a/src/kvirc/sparser/kvi_numeric.h +++ b/src/kvirc/sparser/kvi_numeric.h @@ -368,10 +368,17 @@ #define RPL_ENDOFWATCH 607 /* :End of WATCH [D] # */ // STARTTLS extension #define RPL_STARTTLSOK 670 /* :test2.chatspike.net 670 nickname :STARTTLS successful, go ahead with TLS handshake */ -#define RPL_STARTTLSFAIL 671 /* :test2.chatspike.net 671 nickname :STARTTLS failure */ +#define RPL_STARTTLSFAIL 691 /* :test2.chatspike.net 671 nickname :STARTTLS failure */ // WeNet codepage extension #define RPL_CODEPAGESET 700 /* :irc.wenet.ru 700 Pragma CP1251 :is now your translation scheme # */ #define RPL_WHOISSCHEME 703 /* :interdacom.vgd.wenet.ru 703 Alexey Begemot KOI8-R :translation scheme */ +//SASL EXTENSION +#define RPL_SASLLOGIN 900 /* :jaguar.test 900 jilles jilles!jilles@localhost.stack.nl jilles :You are now logged in as jilles. */ +#define RPL_SASLSUCCESS 903 /* :jaguar.test 903 jilles :SASL authentication successful */ +#define RPL_SASLFAILED 904 /* :lindbohm.freenode.net 904 * :SASL authentication failed */ +#define RPL_SASLERROR 905 // alternative error message +#define RPL_SASLABORT 906 // sasl authentication aborted +#define RPL_SASLALREADYAUTH 907 // can't authenticate: already authenticated ///* 303 */ RPL_ISON, ":", ///* 304 */ RPL_TEXT, (char *)NULL, diff --git a/src/kvirc/sparser/kvi_sp_literal.cpp b/src/kvirc/sparser/kvi_sp_literal.cpp index 0eb384424..24ff39e8e 100644 --- a/src/kvirc/sparser/kvi_sp_literal.cpp +++ b/src/kvirc/sparser/kvi_sp_literal.cpp @@ -1988,19 +1988,58 @@ void KviServerParser::parseLiteralCap(KviIrcMessage *msg) // CAP // CAP LS // :prefix CAP * LS :tls userhost-in-names multi-prefix sasl - // Other subcommands: - // LIST, REQ, ACK, NAK, CLEAR, END + + // Server2client subcommands: + // LIST, LS, ACK, NAK + // Client2server subcommands: + // LIST, LS, REQ, CLEAR, END debug("Parsing literal CAP..."); QString szPrefix = msg->connection()->decodeText(msg->safePrefix()); QString szCmd = msg->connection()->decodeText(msg->safeParam(1)); QString szProtocols = msg->connection()->decodeText(msg->safeParam(2)); - debug("Prefix: %s\nPar1: %s\nPar2: %s",szPrefix.toUtf8().data(),szCmd.toUtf8().data(),szProtocols.toUtf8().data()); - if(szCmd == "LS") { msg->connection()->serverInfo()->setSupportsCaps(szProtocols); msg->connection()->handleCapLs(); + } else if(szCmd == "ACK") { + if(!msg->haltOutput()) + { + msg->console()->output(KVI_OUT_CAP, + __tr2qs("Enabled CAP Extensions: %Q"), + &szProtocols); + } + msg->connection()->serverInfo()->setEnableCaps(szProtocols); + msg->connection()->handleCapAck(); + } else if(szCmd == "NAK") { + if(!msg->haltOutput()) + { + msg->console()->output(KVI_OUT_CAP, + __tr2qs("Disabled CAP Extensions: %Q"), + &szProtocols); + } + msg->connection()->serverInfo()->setDisableCaps(szProtocols); + msg->connection()->handleCapNak(); + } else if(szCmd == "LIST") { + if(!msg->haltOutput()) + { + msg->console()->output(KVI_OUT_CAP, + __tr2qs("Currently enabled CAP Extensions: %Q"), + &szProtocols); + } + } else { + if(!msg->haltOutput()) + { + msg->console()->output(KVI_OUT_CAP, + __tr2qs("Received unknown extended capability message: %Q %Q"), + &szCmd, &szProtocols); + } } } + +void KviServerParser::parseLiteralAuthenticate(KviIrcMessage *) +{ + // :prefix AUTHENTICATE + + // we don't wait for this when authenticating, so no real handling is needed here +} \ No newline at end of file diff --git a/src/kvirc/sparser/kvi_sp_numeric.cpp b/src/kvirc/sparser/kvi_sp_numeric.cpp index f946682fc..16088be58 100644 --- a/src/kvirc/sparser/kvi_sp_numeric.cpp +++ b/src/kvirc/sparser/kvi_sp_numeric.cpp @@ -2193,6 +2193,50 @@ void KviServerParser::parseNumericNotRegistered(KviIrcMessage * msg) // 451: ERR_NOTREGISTERED // :prefix 451 PING :You have not registered - if(msg->connection()->isInsideCapLsRequest()) + if(msg->connection()->stateData()->isInsideCapLs()) msg->connection()->handleFailedCapLs(); } + +// SASL support +void KviServerParser::parseNumericSaslLogin(KviIrcMessage * msg) +{ + // 900: RPL_SASLLOGIN + // :prefix 900 : You are now logged in as + if(!msg->haltOutput()) + { + KviWindow * pOut = (KviWindow *)(msg->console()); + QString szParam=msg->connection()->decodeText(msg->safeParam(2)); + pOut->output(KVI_OUT_SERVERINFO,__tr2qs("Authenticated as %Q"), + &szParam + ); + } +} + +void KviServerParser::parseNumericSaslSuccess(KviIrcMessage * msg) +{ + // 903: RPL_SASLSUCCESS + // :prefix 903 :SASL authentication successful + if(!msg->haltOutput()) + { + KviWindow * pOut = (KviWindow *)(msg->console()); + pOut->outputNoFmt(KVI_OUT_SERVERINFO,__tr2qs("SASL authentication successful")); + } +} + +void KviServerParser::parseNumericSaslFail(KviIrcMessage * msg) +{ + // 904: RPL_SASLFAILED + // :prefix 904 * :SASL authentication failed + + // 906: RPL_SASLBORTED + // :prefix 906 :SASL authentication aborted + + if(!msg->haltOutput()) + { + KviWindow * pOut = (KviWindow *)(msg->console()); + QString szParam=msg->connection()->decodeText(msg->safeTrailing()); + pOut->output(KVI_OUT_SERVERINFO,__tr2qs("SASL Authentication error: %Q"), + &szParam + ); + } +} diff --git a/src/kvirc/sparser/kvi_sp_tables.cpp b/src/kvirc/sparser/kvi_sp_tables.cpp index 7528af073..53d113cfc 100644 --- a/src/kvirc/sparser/kvi_sp_tables.cpp +++ b/src/kvirc/sparser/kvi_sp_tables.cpp @@ -29,22 +29,23 @@ KviLiteralMessageParseStruct KviServerParser::m_literalParseProcTable[]= { - { "CAP" , PTM(parseLiteralCap) }, - { "ERROR" , PTM(parseLiteralError) }, - { "INVITE" , PTM(parseLiteralInvite) }, - { "JOIN" , PTM(parseLiteralJoin) }, - { "KICK" , PTM(parseLiteralKick) }, - { "MODE" , PTM(parseLiteralMode) }, - { "NICK" , PTM(parseLiteralNick) }, - { "NOTICE" , PTM(parseLiteralNotice) }, - { "PART" , PTM(parseLiteralPart) }, - { "PING" , PTM(parseLiteralPing) }, - { "PONG" , PTM(parseLiteralPong) }, - { "PRIVMSG" , PTM(parseLiteralPrivmsg)}, - { "QUIT" , PTM(parseLiteralQuit) }, - { "TOPIC" , PTM(parseLiteralTopic) }, - { "WALLOPS" , PTM(parseLiteralWallops)}, - { 0 , 0 } + { "AUTHENTICATE" , PTM(parseLiteralAuthenticate) }, + { "CAP" , PTM(parseLiteralCap) }, + { "ERROR" , PTM(parseLiteralError) }, + { "INVITE" , PTM(parseLiteralInvite) }, + { "JOIN" , PTM(parseLiteralJoin) }, + { "KICK" , PTM(parseLiteralKick) }, + { "MODE" , PTM(parseLiteralMode) }, + { "NICK" , PTM(parseLiteralNick) }, + { "NOTICE" , PTM(parseLiteralNotice) }, + { "PART" , PTM(parseLiteralPart) }, + { "PING" , PTM(parseLiteralPing) }, + { "PONG" , PTM(parseLiteralPong) }, + { "PRIVMSG" , PTM(parseLiteralPrivmsg) }, + { "QUIT" , PTM(parseLiteralQuit) }, + { "TOPIC" , PTM(parseLiteralTopic) }, + { "WALLOPS" , PTM(parseLiteralWallops) }, + { 0 , 0 } }; // FIXME: #warning "Merge these two tables into one" @@ -987,14 +988,14 @@ messageParseProc KviServerParser::m_numericParseProcTable[1000]= 0, // 897 0, // 898 0, // 899 - 0, // 900 - 0, // 901 + PTM(parseNumericSaslLogin), // 900 RPL_SASLLOGIN + 0, // 901 0, // 902 - 0, // 903 - 0, // 904 - 0, // 905 - 0, // 906 - 0, // 907 + PTM(parseNumericSaslSuccess), // 903 RPL_SASLSUCCESS + PTM(parseNumericSaslFail), // 904 RPL_SASLFAILED + PTM(parseNumericSaslFail), // 905 RPL_SASLERROR + PTM(parseNumericSaslFail), // 906 RPL_SASLABORT + PTM(parseNumericSaslFail), // 907 RPL_SASLALREADYAUTH 0, // 908 0, // 909 0, // 910 diff --git a/src/kvirc/sparser/kvi_sparser.h b/src/kvirc/sparser/kvi_sparser.h index 2e0777440..9bb928760 100644 --- a/src/kvirc/sparser/kvi_sparser.h +++ b/src/kvirc/sparser/kvi_sparser.h @@ -222,7 +222,8 @@ private: void parseChannelMode(const QString &szNick,const QString &szUser,const QString &szHost,KviChannel * chan,KviStr &modefl,KviIrcMessage *msg,int curParam); void parseUserMode(KviIrcMessage *msg,const char * modeflptr); void parseLiteralCap(KviIrcMessage * msg); - + void parseLiteralAuthenticate(KviIrcMessage * msg); + void parseCtcpRequest(KviCtcpMessage *msg); void parseCtcpReply(KviCtcpMessage *msg); void echoCtcpRequest(KviCtcpMessage *msg); @@ -249,6 +250,11 @@ private: // STARTTLS support void parseNumericStartTls(KviIrcMessage * msg); void parseNumericNotRegistered(KviIrcMessage * msg); + //sasl + void parseNumericSaslSuccess(KviIrcMessage * msg); + void parseNumericSaslLogin(KviIrcMessage * msg); + void parseNumericSaslFail(KviIrcMessage * msg); + public: static void encodeCtcpParameter(const char * param,KviStr &buffer,bool bSpaceBreaks = true); static void encodeCtcpParameter(const char * param,QString &buffer,bool bSpaceBreaks = true); diff --git a/src/modules/options/optw_connection.cpp b/src/modules/options/optw_connection.cpp index 41779fabf..8b09172cc 100644 --- a/src/modules/options/optw_connection.cpp +++ b/src/modules/options/optw_connection.cpp @@ -86,7 +86,11 @@ KviConnectionOptionsWidget::KviConnectionOptionsWidget(QWidget * parent) connect(b,SIGNAL(toggled(bool)),u,SLOT(setEnabled(bool))); mergeTip(u,__tr2qs_ctx("
Minimum value: 0 sec
Maximum value: 86400 sec
","options")); - addRowSpacer(0,2,4,2); + b = addBoolSelector(this,__tr2qs_ctx("Use the SASL authentication protocol if available","options"),&(KVI_OPTION_BOOL(KviOption_boolUseSaslIfAvailable)),true); + mergeTip(b,__tr2qs_ctx("
When available and enabled of the specific server, KVIrc will try to authenticate the user using the SASL procotol
","options")); + addWidgetToLayout(b,0,2,0,2); + + addRowSpacer(0,3,4,3); } KviConnectionOptionsWidget::~KviConnectionOptionsWidget() diff --git a/src/modules/options/optw_servers.cpp b/src/modules/options/optw_servers.cpp index 3f2fdebac..c1c49ff26 100644 --- a/src/modules/options/optw_servers.cpp +++ b/src/modules/options/optw_servers.cpp @@ -585,8 +585,6 @@ KviServerDetailsWidget::KviServerDetailsWidget(QWidget * par,KviServer * s) KviTalToolTip::add(m_pPortEditor,__tr2qs_ctx("
This is the default port that this server will be contacted on.
Usually 6667 is OK.
","options")); connect(m_pPortEditor,SIGNAL(textChanged(const QString &)),this,SLOT(portEditorTextChanged(const QString &))); - - l = new QLabel(__tr2qs_ctx("IP address:","options"),tab); gl->addWidget(l,1,0); m_pIpEditor = new KviIpEditor(tab,KviIpEditor::IPv4); @@ -644,14 +642,14 @@ KviServerDetailsWidget::KviServerDetailsWidget(QWidget * par,KviServer * s) #endif m_pUseSSLCheck->setChecked(s->useSSL()); - m_pSupportsSTARTTLSCheck = new QCheckBox(__tr2qs_ctx("Supports STARTTLS protocol","options"),tab); - gl->addWidget(m_pSupportsSTARTTLSCheck,5,0,1,2); - KviTalToolTip::add(m_pSupportsSTARTTLSCheck,__tr2qs_ctx("
This check marks the server as dynamically supporting the Transport Layer Security " \ - "protocol. If you enable the proper global option in the Connection/SSL tab, the TLS protocol will be used for this server.
","options")); + m_pEnableSTARTTLSCheck = new QCheckBox(__tr2qs_ctx("Enable STARTTLS protocol","options"),tab); + gl->addWidget(m_pEnableSTARTTLSCheck,5,0,1,2); + KviTalToolTip::add(m_pEnableSTARTTLSCheck,__tr2qs_ctx("
This check enables the use of the Transport Layer Security " \ + "protocol. If you enable the proper global option in the Connection/SSL tab, the TLS protocol will be used for this server if available.
","options")); #ifndef COMPILE_SSL_SUPPORT - m_pSupportsSTARTTLSCheck->setEnabled(false); + m_pEnableSTARTTLSCheck->setEnabled(false); #endif - m_pSupportsSTARTTLSCheck->setChecked(s->supportsSTARTTLS()); + m_pEnableSTARTTLSCheck->setChecked(s->enabledSTARTTLS()); m_pUseAutoConnect = new QCheckBox(__tr2qs_ctx("Connect to this server at startup","options"),tab); m_pUseAutoConnect->setChecked(s->autoConnect()); @@ -772,11 +770,30 @@ KviServerDetailsWidget::KviServerDetailsWidget(QWidget * par,KviServer * s) if(m_pProxyEditor->count() > (s->proxy()+2)) m_pProxyEditor->setCurrentIndex(s->proxy()+2); + m_pEnableSASLCheck = new QCheckBox(__tr2qs_ctx("Enable SASL authentication","options"),tab); + gl->addWidget(m_pEnableSASLCheck,12,0,1,2); + KviTalToolTip::add(m_pEnableSASLCheck,__tr2qs_ctx("
This check enables the use of the SASL authentication procotol" \ + "If you enable the proper global option in the Connection/SSL tab and fill the Sasl Nickname and Sasl Password fields in this page, the SASL protocol will be used for this server if available.
","options")); + m_pEnableSASLCheck->setChecked(s->enabledSASL()); + + l = new QLabel(__tr2qs_ctx("Sasl Nickname:","options"),tab); + gl->addWidget(l,13,0); + m_pSaslNickEditor = new QLineEdit(tab); + m_pSaslNickEditor->setText(s->saslNick()); + KviTalToolTip::add(m_pSaslNickEditor,__tr2qs_ctx("
If you want to enable SASL authentication, insert your nickname here.
","options")); + gl->addWidget(m_pSaslNickEditor,13,1); + + l = new QLabel(__tr2qs_ctx("Sasl Password:","options"),tab); + gl->addWidget(l,14,0); + m_pSaslPassEditor = new KviPasswordLineEdit(tab); + m_pSaslPassEditor->setText(s->saslPass()); + KviTalToolTip::add(m_pSaslPassEditor,__tr2qs_ctx("
If you want to enable SASL authentication, insert your password here.
","options")); + gl->addWidget(m_pSaslPassEditor,14,1); l = new QLabel("",tab); - gl->addWidget(l,12,0,1,2); + gl->addWidget(l,15,0,1,2); - gl->setRowStretch(12,1); + gl->setRowStretch(15,1); tw->addTab(tab,*(g_pIconManager->getSmallIcon(KVI_SMALLICON_SOCKETWARNING)),__tr2qs_ctx("Connection","options")); @@ -925,8 +942,16 @@ void KviServerDetailsWidget::fillData(KviServer * s) s->setCacheIp(m_pCacheIpCheck->isChecked()); if(m_pUseSSLCheck) s->setUseSSL(m_pUseSSLCheck->isChecked()); - if(m_pSupportsSTARTTLSCheck) - s->setSupportsSTARTTLS(m_pSupportsSTARTTLSCheck->isChecked()); + if(m_pEnableSTARTTLSCheck) + s->setEnabledSTARTTLS(m_pEnableSTARTTLSCheck->isChecked()); + + s->setSaslNick(m_pSaslNickEditor->text()); + s->setSaslPass(m_pSaslPassEditor->text()); + s->setEnabledSASL( m_pEnableSASLCheck->isChecked() && + !m_pSaslNickEditor->text().isEmpty() && + !m_pSaslPassEditor->text().isEmpty() + ); + if(m_pIdEditor) s->setId(m_pIdEditor->text()); if(s->id().isEmpty())s->generateUniqueId(); diff --git a/src/modules/options/optw_servers.h b/src/modules/options/optw_servers.h index 9ba0046d4..5b14e8f22 100644 --- a/src/modules/options/optw_servers.h +++ b/src/modules/options/optw_servers.h @@ -115,7 +115,9 @@ protected: KviScriptEditor * m_pOnLoginEditor; QLineEdit * m_pUserEditor; KviPasswordLineEdit * m_pPassEditor; + KviPasswordLineEdit * m_pSaslPassEditor; QLineEdit * m_pNickEditor; + QLineEdit * m_pSaslNickEditor; QLineEdit * m_pRealEditor; QLineEdit * m_pDescEditor; QLineEdit * m_pIdEditor; @@ -125,7 +127,8 @@ protected: KviIpEditor * m_pIpEditor; QCheckBox * m_pCacheIpCheck; QCheckBox * m_pUseSSLCheck; - QCheckBox * m_pSupportsSTARTTLSCheck; + QCheckBox * m_pEnableSTARTTLSCheck; + QCheckBox * m_pEnableSASLCheck; QCheckBox * m_pUseDefaultInitUMode; QCheckBox * m_pIMode; QCheckBox * m_pWMode; -- cgit v1.3.1-10-gc9f91