diff --git a/src/kmailtransport/mailtransport_defs.h b/src/kmailtransport/mailtransport_defs.h --- a/src/kmailtransport/mailtransport_defs.h +++ b/src/kmailtransport/mailtransport_defs.h @@ -48,10 +48,16 @@ #define POP_PROTOCOL QStringLiteral("pop") #define POPS_PROTOCOL QStringLiteral("pops") +#define NNTP_PROTOCOL QStringLiteral("nntp") +#define NNTPS_PROTOCOL QStringLiteral("nntps") + #define IMAP_PORT 143 #define IMAPS_PORT 993 #define POP_PORT 110 #define POPS_PORT 995 +#define NNTP_PORT 119 +#define NNTPS_PORT 563 + #endif diff --git a/src/kmailtransport/servertest.h b/src/kmailtransport/servertest.h --- a/src/kmailtransport/servertest.h +++ b/src/kmailtransport/servertest.h @@ -91,6 +91,7 @@ * SMTP: 25, 465 * POP: 110, 995 * IMAP: 143, 993 + * NNTP: 119, 563 * * @param encryptionMode the port will only be used in this encryption mode. * Valid values for this are only 'None' and 'SSL'. diff --git a/src/kmailtransport/servertest.cpp b/src/kmailtransport/servertest.cpp --- a/src/kmailtransport/servertest.cpp +++ b/src/kmailtransport/servertest.cpp @@ -77,6 +77,7 @@ void handleSMTPIMAPResponse(int type, const QString &text); void sendInitialCapabilityQuery(MailTransport::Socket *socket); bool handlePopConversation(MailTransport::Socket *socket, int type, int stage, const QString &response, bool *shouldStartTLS); + bool handleNntpConversation(MailTransport::Socket *socket, int type, int *stage, const QString &response, bool *shouldStartTLS); QVector parseAuthenticationList(const QStringList &authentications); // slots @@ -320,6 +321,71 @@ return false; } +bool ServerTestPrivate::handleNntpConversation(MailTransport::Socket *socket, int type, int *stage, const QString &response, bool *shouldStartTLS) +{ + Q_ASSERT(shouldStartTLS != nullptr); + Q_ASSERT(stage != nullptr); + + // Initial Greeting + if (*stage == 0) { + if (response.startsWith(QLatin1String("382 "))) { + return true; + } + if (!response.isEmpty() && !response.startsWith(QLatin1String("200 "))) { + return false; + } + + socket->write(QStringLiteral("CAPABILITIES")); + return true; + } + + // CAPABILITIES result + else if (*stage == 1) { + // Check whether we got "500 command 'CAPABILITIES' not recognized" + if (response.startsWith(QLatin1String("500 "))) { + return false; + } + +// Example: +// 101 Capability list: +// VERSION 2 +// IMPLEMENTATION INN 2.5.4 +// AUTHINFO USER SASL +// HDR +// LIST ACTIVE [etc] +// OVER +// POST +// READER +// SASL DIGEST-MD5 CRAM-MD5 NTLM PLAIN LOGIN +// STARTTLS +// . + const QVector lines = response.splitRef(QLatin1String("\r\n"), QString::SkipEmptyParts); + for (const QStringRef &line : lines) { + if (line.compare(QLatin1String("STARTTLS"), Qt::CaseInsensitive) == 0) { + *shouldStartTLS = true; + } else if (line.startsWith(QLatin1String("AUTHINFO "), Qt::CaseInsensitive)) { + const QVector authinfos = line.split(QLatin1Char(' '), QString::SkipEmptyParts); + const QString s(QStringLiteral("USER")); + const QStringRef ref(&s); + if (authinfos.contains(ref)) { + authenticationResults[type].append(Transport::EnumAuthenticationType::CLEAR); // XXX + } + } else if (line.startsWith(QLatin1String("SASL "), Qt::CaseInsensitive)) { + const QStringList auths = line.mid(5).toString().split(QLatin1Char(' '), QString::SkipEmptyParts); + authenticationResults[type] += parseAuthenticationList(auths); + } else if (line == QLatin1String(".")) { + return false; + } + } + // We have not hit the end of the capabilities list yet, + // so avoid the stage counter to rise without reason. + --(*stage); + return true; + } + + return false; +} + // slotReadNormal() handles normal (no) encryption and TLS encryption. // At first, the communication is not encrypted, but if the server supports // the STARTTLS/STLS keyword, the same authentication query is done again @@ -345,13 +411,18 @@ bool shouldStartTLS = false; normalStage++; - // Handle the whole POP converstation separatly, it is very different from - // IMAP and SMTP + // Handle the whole POP and NNTP converstations separatly, as + // they are very different from IMAP and SMTP if (testProtocol == POP_PROTOCOL) { if (handlePopConversation(normalSocket, encryptionMode, normalStage, text, &shouldStartTLS)) { return; } + } else if (testProtocol == NNTP_PROTOCOL) { + if (handleNntpConversation(normalSocket, encryptionMode, &normalStage, text, + &shouldStartTLS)) { + return; + } } else { // Handle the SMTP/IMAP conversation here. We just send the EHLO command in // sendInitialCapabilityQuery. @@ -403,6 +474,12 @@ secureStage, text, &dummy)) { return; } + } else if (testProtocol == NNTP_PROTOCOL) { + bool dummy; + if (handleNntpConversation(secureSocket, Transport::EnumEncryption::SSL, + &secureStage, text, &dummy)) { + return; + } } else { if (secureStage == 0) { sendInitialCapabilityQuery(secureSocket); @@ -503,6 +580,9 @@ } else if (d->testProtocol == POP_PROTOCOL) { d->normalSocket->setPort(POP_PORT); d->secureSocket->setPort(POPS_PORT); + } else if (d->testProtocol == NNTP_PROTOCOL) { + d->normalSocket->setPort(NNTP_PORT); + d->secureSocket->setPort(NNTPS_PORT); } if (d->customPorts.contains(Transport::EnumEncryption::None)) {