File indexing completed on 2024-06-23 05:15:11

0001 /*
0002   SPDX-FileCopyrightText: 2006-2007 Volker Krause <vkrause@kde.org>
0003   SPDX-FileCopyrightText: 2007 KovoKs <info@kovoks.nl>
0004   SPDX-FileCopyrightText: 2008 Thomas McGuire <thomas.mcguire@gmx.net>
0005 
0006   SPDX-License-Identifier: LGPL-2.0-or-later
0007 */
0008 
0009 // Own
0010 #include "servertest.h"
0011 #include "socket.h"
0012 
0013 #include "mailtransport_defs.h"
0014 #include <transportbase.h>
0015 
0016 // Qt
0017 #include <QHash>
0018 #include <QHostInfo>
0019 #include <QProgressBar>
0020 #include <QRegularExpression>
0021 #include <QSet>
0022 #include <QTimer>
0023 
0024 // KDE
0025 #include "mailtransport_debug.h"
0026 
0027 using namespace MailTransport;
0028 
0029 namespace MailTransport
0030 {
0031 class ServerTestPrivate
0032 {
0033 public:
0034     ServerTestPrivate(ServerTest *test);
0035 
0036     ServerTest *const q;
0037     QString server;
0038     QString fakeHostname;
0039     QString testProtocol;
0040 
0041     MailTransport::Socket *normalSocket = nullptr;
0042     MailTransport::Socket *secureSocket = nullptr;
0043 
0044     QSet<int> connectionResults;
0045     QHash<int, QList<int>> authenticationResults;
0046     QSet<ServerTest::Capability> capabilityResults;
0047     QHash<int, uint> customPorts;
0048     QTimer *normalSocketTimer = nullptr;
0049     QTimer *secureSocketTimer = nullptr;
0050     QTimer *progressTimer = nullptr;
0051 
0052     QProgressBar *testProgress = nullptr;
0053 
0054     bool secureSocketFinished = false;
0055     bool normalSocketFinished = false;
0056     bool tlsFinished = false;
0057     bool popSupportsTLS;
0058     int normalStage;
0059     int secureStage;
0060     int encryptionMode;
0061 
0062     bool normalPossible = true;
0063     bool securePossible = true;
0064 
0065     void finalResult();
0066     void handleSMTPIMAPResponse(int type, const QString &text);
0067     void sendInitialCapabilityQuery(MailTransport::Socket *socket);
0068     bool handlePopConversation(MailTransport::Socket *socket, int type, int stage, const QString &response, bool *shouldStartTLS);
0069     bool handleNntpConversation(MailTransport::Socket *socket, int type, int *stage, const QString &response, bool *shouldStartTLS);
0070     QList<int> parseAuthenticationList(const QStringList &authentications);
0071 
0072     [[nodiscard]] inline bool isGmail(const QString &server) const
0073     {
0074         return server.endsWith(QLatin1StringView("gmail.com")) || server.endsWith(QLatin1StringView("googlemail.com"));
0075     }
0076 
0077     // slots
0078     void slotNormalPossible();
0079     void slotNormalNotPossible();
0080     void slotSslPossible();
0081     void slotSslNotPossible();
0082     void slotTlsDone();
0083     void slotReadNormal(const QString &text);
0084     void slotReadSecure(const QString &text);
0085     void slotUpdateProgress();
0086 };
0087 }
0088 
0089 ServerTestPrivate::ServerTestPrivate(ServerTest *test)
0090     : q(test)
0091 {
0092 }
0093 
0094 void ServerTestPrivate::finalResult()
0095 {
0096     if (!secureSocketFinished || !normalSocketFinished || !tlsFinished) {
0097         return;
0098     }
0099 
0100     qCDebug(MAILTRANSPORT_LOG) << "Modes:" << connectionResults;
0101     qCDebug(MAILTRANSPORT_LOG) << "Capabilities:" << capabilityResults;
0102     qCDebug(MAILTRANSPORT_LOG) << "Normal:" << q->normalProtocols();
0103     qCDebug(MAILTRANSPORT_LOG) << "SSL:" << q->secureProtocols();
0104     qCDebug(MAILTRANSPORT_LOG) << "TLS:" << q->tlsProtocols();
0105 
0106     if (testProgress) {
0107         testProgress->hide();
0108     }
0109     progressTimer->stop();
0110     secureSocketFinished = false;
0111     normalSocketFinished = false;
0112     tlsFinished = false;
0113 
0114     QList<int> resultsAsVector;
0115     resultsAsVector.reserve(connectionResults.size());
0116     for (int res : std::as_const(connectionResults)) {
0117         resultsAsVector.append(res);
0118     }
0119 
0120     Q_EMIT q->finished(resultsAsVector);
0121 }
0122 
0123 QList<int> ServerTestPrivate::parseAuthenticationList(const QStringList &authentications)
0124 {
0125     QList<int> result;
0126     for (QStringList::ConstIterator it = authentications.begin(); it != authentications.end(); ++it) {
0127         QString current = (*it).toUpper();
0128         if (current == QLatin1StringView("LOGIN")) {
0129             result << Transport::EnumAuthenticationType::LOGIN;
0130         } else if (current == QLatin1StringView("PLAIN")) {
0131             result << Transport::EnumAuthenticationType::PLAIN;
0132         } else if (current == QLatin1StringView("CRAM-MD5")) {
0133             result << Transport::EnumAuthenticationType::CRAM_MD5;
0134         } else if (current == QLatin1StringView("DIGEST-MD5")) {
0135             result << Transport::EnumAuthenticationType::DIGEST_MD5;
0136         } else if (current == QLatin1StringView("NTLM")) {
0137             result << Transport::EnumAuthenticationType::NTLM;
0138         } else if (current == QLatin1StringView("GSSAPI")) {
0139             result << Transport::EnumAuthenticationType::GSSAPI;
0140         } else if (current == QLatin1StringView("ANONYMOUS")) {
0141             result << Transport::EnumAuthenticationType::ANONYMOUS;
0142         } else if (current == QLatin1StringView("XOAUTH2")) {
0143             if (isGmail(server)) {
0144                 result << Transport::EnumAuthenticationType::XOAUTH2;
0145             }
0146         }
0147         // APOP is handled by handlePopConversation()
0148     }
0149     qCDebug(MAILTRANSPORT_LOG) << authentications << result;
0150 
0151     // LOGIN doesn't offer anything over PLAIN, requires more server
0152     // roundtrips and is not an official SASL mechanism, but a MS-ism,
0153     // so only enable it if PLAIN isn't available:
0154     if (result.contains(Transport::EnumAuthenticationType::PLAIN)) {
0155         result.removeAll(Transport::EnumAuthenticationType::LOGIN);
0156     }
0157 
0158     return result;
0159 }
0160 
0161 void ServerTestPrivate::handleSMTPIMAPResponse(int type, const QString &text)
0162 {
0163     if (!text.contains(QLatin1StringView("AUTH"), Qt::CaseInsensitive)) {
0164         qCDebug(MAILTRANSPORT_LOG) << "No authentication possible";
0165         return;
0166     }
0167 
0168     QStringList protocols;
0169     if (isGmail(server)) {
0170         protocols << QStringLiteral("XOAUTH2");
0171     }
0172 
0173     protocols << QStringLiteral("LOGIN") << QStringLiteral("PLAIN") << QStringLiteral("CRAM-MD5") << QStringLiteral("DIGEST-MD5") << QStringLiteral("NTLM")
0174               << QStringLiteral("GSSAPI") << QStringLiteral("ANONYMOUS");
0175 
0176     QStringList results;
0177     for (int i = 0; i < protocols.count(); ++i) {
0178         if (text.contains(protocols.at(i), Qt::CaseInsensitive)) {
0179             results.append(protocols.at(i));
0180         }
0181     }
0182 
0183     authenticationResults[type] = parseAuthenticationList(results);
0184 
0185     // if we couldn't parse any authentication modes, default to clear-text
0186     if (authenticationResults[type].isEmpty()) {
0187         authenticationResults[type] << Transport::EnumAuthenticationType::CLEAR;
0188     }
0189 
0190     qCDebug(MAILTRANSPORT_LOG) << "For type" << type << ", we have:" << authenticationResults[type];
0191 }
0192 
0193 void ServerTestPrivate::slotNormalPossible()
0194 {
0195     normalSocketTimer->stop();
0196     connectionResults << Transport::EnumEncryption::None;
0197 }
0198 
0199 void ServerTestPrivate::sendInitialCapabilityQuery(MailTransport::Socket *socket)
0200 {
0201     if (testProtocol == IMAP_PROTOCOL) {
0202         socket->write(QStringLiteral("1 CAPABILITY"));
0203     } else if (testProtocol == SMTP_PROTOCOL) {
0204         // Detect the hostname which we send with the EHLO command.
0205         // If there is a fake one set, use that, otherwise use the
0206         // local host name (and make sure it contains a domain, so the
0207         // server thinks it is valid).
0208         QString hostname;
0209         if (!fakeHostname.isNull()) {
0210             hostname = fakeHostname;
0211         } else {
0212             hostname = QHostInfo::localHostName();
0213             if (hostname.isEmpty()) {
0214                 hostname = QStringLiteral("localhost.invalid");
0215             } else if (!hostname.contains(QChar::fromLatin1('.'))) {
0216                 hostname += QLatin1StringView(".localnet");
0217             }
0218         }
0219         qCDebug(MAILTRANSPORT_LOG) << "Hostname for EHLO is" << hostname;
0220 
0221         socket->write(QLatin1StringView("EHLO ") + hostname);
0222     }
0223 }
0224 
0225 void ServerTestPrivate::slotTlsDone()
0226 {
0227     // The server will not send a response after starting TLS. Therefore, we have to manually
0228     // call slotReadNormal(), because this is not triggered by a data received signal this time.
0229     slotReadNormal(QString());
0230 }
0231 
0232 bool ServerTestPrivate::handlePopConversation(MailTransport::Socket *socket, int type, int stage, const QString &response, bool *shouldStartTLS)
0233 {
0234     Q_ASSERT(shouldStartTLS != nullptr);
0235 
0236     // Initial Greeting
0237     if (stage == 0) {
0238         // Regexp taken from POP3 ioslave
0239         const QString responseWithoutCRLF = response.isEmpty() ? response : response.chopped(2);
0240         static const QRegularExpression re(QStringLiteral("<[A-Za-z0-9\\.\\-_]+@[A-Za-z0-9\\.\\-_]+>$"), QRegularExpression::CaseInsensitiveOption);
0241         if (responseWithoutCRLF.indexOf(re) != -1) {
0242             authenticationResults[type] << Transport::EnumAuthenticationType::APOP;
0243         }
0244 
0245         // Each server is supposed to support clear text login
0246         authenticationResults[type] << Transport::EnumAuthenticationType::CLEAR;
0247 
0248         // If we are in TLS stage, the server does not send the initial greeting.
0249         // Assume that the APOP availability is the same as with an unsecured connection.
0250         if (type == Transport::EnumEncryption::TLS
0251             && authenticationResults[Transport::EnumEncryption::None].contains(Transport::EnumAuthenticationType::APOP)) {
0252             authenticationResults[Transport::EnumEncryption::TLS] << Transport::EnumAuthenticationType::APOP;
0253         }
0254 
0255         socket->write(QStringLiteral("CAPA"));
0256         return true;
0257     }
0258     // CAPA result
0259     else if (stage == 1) {
0260         //     Example:
0261         //     CAPA
0262         //     +OK
0263         //     TOP
0264         //     USER
0265         //     SASL LOGIN CRAM-MD5
0266         //     UIDL
0267         //     RESP-CODES
0268         //     .
0269         if (response.contains(QLatin1StringView("TOP"))) {
0270             capabilityResults += ServerTest::Top;
0271         }
0272         if (response.contains(QLatin1StringView("PIPELINING"))) {
0273             capabilityResults += ServerTest::Pipelining;
0274         }
0275         if (response.contains(QLatin1StringView("UIDL"))) {
0276             capabilityResults += ServerTest::UIDL;
0277         }
0278         if (response.contains(QLatin1StringView("STLS"))) {
0279             connectionResults << Transport::EnumEncryption::TLS;
0280             popSupportsTLS = true;
0281         }
0282         socket->write(QStringLiteral("AUTH"));
0283         return true;
0284     }
0285     // AUTH response
0286     else if (stage == 2) {
0287         //     Example:
0288         //     C: AUTH
0289         //     S: +OK List of supported authentication methods follows
0290         //     S: LOGIN
0291         //     S: CRAM-MD5
0292         //     S:.
0293         QString formattedReply = response;
0294 
0295         // Get rid of trailing ".CRLF"
0296         formattedReply.chop(3);
0297 
0298         // Get rid of the first +OK line
0299         formattedReply = formattedReply.right(formattedReply.size() - formattedReply.indexOf(QLatin1Char('\n')) - 1);
0300         formattedReply = formattedReply.replace(QLatin1Char(' '), QLatin1Char('-')).replace(QLatin1StringView("\r\n"), QLatin1StringView(" "));
0301 
0302         authenticationResults[type] += parseAuthenticationList(formattedReply.split(QLatin1Char(' ')));
0303     }
0304 
0305     *shouldStartTLS = popSupportsTLS;
0306     return false;
0307 }
0308 
0309 bool ServerTestPrivate::handleNntpConversation(MailTransport::Socket *socket, int type, int *stage, const QString &response, bool *shouldStartTLS)
0310 {
0311     Q_ASSERT(shouldStartTLS != nullptr);
0312     Q_ASSERT(stage != nullptr);
0313 
0314     // Initial Greeting
0315     if (*stage == 0) {
0316         if (response.startsWith(QLatin1StringView("382 "))) {
0317             return true;
0318         }
0319         if (!response.isEmpty() && !response.startsWith(QLatin1StringView("200 "))) {
0320             return false;
0321         }
0322 
0323         socket->write(QStringLiteral("CAPABILITIES"));
0324         return true;
0325     }
0326     // CAPABILITIES result
0327     else if (*stage == 1) {
0328         // Check whether we got "500 command 'CAPABILITIES' not recognized"
0329         if (response.startsWith(QLatin1StringView("500 "))) {
0330             return false;
0331         }
0332 
0333         //     Example:
0334         //     101 Capability list:
0335         //     VERSION 2
0336         //     IMPLEMENTATION INN 2.5.4
0337         //     AUTHINFO USER SASL
0338         //     HDR
0339         //     LIST ACTIVE [etc]
0340         //     OVER
0341         //     POST
0342         //     READER
0343         //     SASL DIGEST-MD5 CRAM-MD5 NTLM PLAIN LOGIN
0344         //     STARTTLS
0345         //     .
0346         const QList<QStringView> lines = QStringView(response).split(QStringLiteral("\r\n"), Qt::SkipEmptyParts);
0347         for (const QStringView line : lines) {
0348             if (line.compare(QLatin1StringView("STARTTLS"), Qt::CaseInsensitive) == 0) {
0349                 *shouldStartTLS = true;
0350             } else if (line.startsWith(QLatin1StringView("AUTHINFO "), Qt::CaseInsensitive)) {
0351                 const QList<QStringView> authinfos = QStringView(line).split(QLatin1Char(' '), Qt::SkipEmptyParts);
0352                 const QString s(QStringLiteral("USER"));
0353                 const QStringView ref(s);
0354                 if (authinfos.contains(ref)) {
0355                     authenticationResults[type].append(Transport::EnumAuthenticationType::CLEAR); // XXX
0356                 }
0357             } else if (line.startsWith(QLatin1StringView("SASL "), Qt::CaseInsensitive)) {
0358                 const QStringList auths = line.mid(5).toString().split(QLatin1Char(' '), Qt::SkipEmptyParts);
0359                 authenticationResults[type] += parseAuthenticationList(auths);
0360             } else if (line == QLatin1Char('.')) {
0361                 return false;
0362             }
0363         }
0364         // We have not hit the end of the capabilities list yet,
0365         // so avoid the stage counter to rise without reason.
0366         --(*stage);
0367         return true;
0368     }
0369 
0370     return false;
0371 }
0372 
0373 // slotReadNormal() handles normal (no) encryption and TLS encryption.
0374 // At first, the communication is not encrypted, but if the server supports
0375 // the STARTTLS/STLS keyword, the same authentication query is done again
0376 // with TLS.
0377 void ServerTestPrivate::slotReadNormal(const QString &text)
0378 {
0379     Q_ASSERT(encryptionMode != Transport::EnumEncryption::SSL);
0380     static const int tlsHandshakeStage = 42;
0381 
0382     qCDebug(MAILTRANSPORT_LOG) << "Stage" << normalStage + 1 << ", Mode" << encryptionMode;
0383 
0384     // If we are in stage 42, we just do the handshake for TLS encryption and
0385     // then reset the stage to -1, so that all authentication modes and
0386     // capabilities are queried again for TLS encryption (some servers have
0387     // different authentication  methods in normal and in TLS mode).
0388     if (normalStage == tlsHandshakeStage) {
0389         Q_ASSERT(encryptionMode == Transport::EnumEncryption::TLS);
0390         normalStage = -1;
0391         normalSocket->startTLS();
0392         return;
0393     }
0394 
0395     bool shouldStartTLS = false;
0396     normalStage++;
0397 
0398     // Handle the whole POP and NNTP conversations separately, as
0399     // they are very different from IMAP and SMTP
0400     if (testProtocol == POP_PROTOCOL) {
0401         if (handlePopConversation(normalSocket, encryptionMode, normalStage, text, &shouldStartTLS)) {
0402             return;
0403         }
0404     } else if (testProtocol == NNTP_PROTOCOL) {
0405         if (handleNntpConversation(normalSocket, encryptionMode, &normalStage, text, &shouldStartTLS)) {
0406             return;
0407         }
0408     } else {
0409         // Handle the SMTP/IMAP conversation here. We just send the EHLO command in
0410         // sendInitialCapabilityQuery.
0411         if (normalStage == 0) {
0412             sendInitialCapabilityQuery(normalSocket);
0413             return;
0414         }
0415 
0416         if (text.contains(QLatin1StringView("STARTTLS"), Qt::CaseInsensitive)) {
0417             connectionResults << Transport::EnumEncryption::TLS;
0418             shouldStartTLS = true;
0419         }
0420         handleSMTPIMAPResponse(encryptionMode, text);
0421     }
0422 
0423     // If we reach here, the normal authentication/capabilities query is completed.
0424     // Now do the same for TLS.
0425     normalSocketFinished = true;
0426 
0427     // If the server announced that STARTTLS/STLS is available, we'll add TLS to the
0428     // connection result, do the command and set the stage to 42 to start the handshake.
0429     if (shouldStartTLS && encryptionMode == Transport::EnumEncryption::None) {
0430         qCDebug(MAILTRANSPORT_LOG) << "Trying TLS...";
0431         connectionResults << Transport::EnumEncryption::TLS;
0432         if (testProtocol == POP_PROTOCOL) {
0433             normalSocket->write(QStringLiteral("STLS"));
0434         } else if (testProtocol == IMAP_PROTOCOL) {
0435             normalSocket->write(QStringLiteral("2 STARTTLS"));
0436         } else {
0437             normalSocket->write(QStringLiteral("STARTTLS"));
0438         }
0439         encryptionMode = Transport::EnumEncryption::TLS;
0440         normalStage = tlsHandshakeStage;
0441         return;
0442     }
0443 
0444     // If we reach here, either the TLS authentication/capabilities query is finished
0445     // or the server does not support the STARTTLS/STLS command.
0446     tlsFinished = true;
0447     finalResult();
0448 }
0449 
0450 void ServerTestPrivate::slotReadSecure(const QString &text)
0451 {
0452     secureStage++;
0453     if (testProtocol == POP_PROTOCOL) {
0454         bool dummy;
0455         if (handlePopConversation(secureSocket, Transport::EnumEncryption::SSL, secureStage, text, &dummy)) {
0456             return;
0457         }
0458     } else if (testProtocol == NNTP_PROTOCOL) {
0459         bool dummy;
0460         if (handleNntpConversation(secureSocket, Transport::EnumEncryption::SSL, &secureStage, text, &dummy)) {
0461             return;
0462         }
0463     } else {
0464         if (secureStage == 0) {
0465             sendInitialCapabilityQuery(secureSocket);
0466             return;
0467         }
0468         handleSMTPIMAPResponse(Transport::EnumEncryption::SSL, text);
0469     }
0470     secureSocketFinished = true;
0471     finalResult();
0472 }
0473 
0474 void ServerTestPrivate::slotNormalNotPossible()
0475 {
0476     if (testProtocol == SMTP_PROTOCOL && normalSocket->port() == SMTP_PORT) {
0477         // For SMTP, fallback to port 25
0478         normalSocket->setPort(SMTP_OLD_PORT);
0479         normalSocket->reconnect();
0480         normalSocketTimer->start(10000);
0481         return;
0482     }
0483 
0484     normalSocketTimer->stop();
0485     normalPossible = false;
0486     normalSocketFinished = true;
0487     tlsFinished = true;
0488     finalResult();
0489 }
0490 
0491 void ServerTestPrivate::slotSslPossible()
0492 {
0493     secureSocketTimer->stop();
0494     connectionResults << Transport::EnumEncryption::SSL;
0495 }
0496 
0497 void ServerTestPrivate::slotSslNotPossible()
0498 {
0499     secureSocketTimer->stop();
0500     securePossible = false;
0501     secureSocketFinished = true;
0502     finalResult();
0503 }
0504 
0505 void ServerTestPrivate::slotUpdateProgress()
0506 {
0507     if (testProgress) {
0508         testProgress->setValue(testProgress->value() + 1);
0509     }
0510 }
0511 
0512 //---------------------- end private class -----------------------//
0513 
0514 ServerTest::ServerTest(QObject *parent)
0515     : QObject(parent)
0516     , d(new ServerTestPrivate(this))
0517 {
0518     d->normalSocketTimer = new QTimer(this);
0519     d->normalSocketTimer->setSingleShot(true);
0520     connect(d->normalSocketTimer, SIGNAL(timeout()), SLOT(slotNormalNotPossible()));
0521 
0522     d->secureSocketTimer = new QTimer(this);
0523     d->secureSocketTimer->setSingleShot(true);
0524     connect(d->secureSocketTimer, SIGNAL(timeout()), SLOT(slotSslNotPossible()));
0525 
0526     d->progressTimer = new QTimer(this);
0527     connect(d->progressTimer, SIGNAL(timeout()), SLOT(slotUpdateProgress()));
0528 }
0529 
0530 ServerTest::~ServerTest() = default;
0531 
0532 void ServerTest::start()
0533 {
0534     qCDebug(MAILTRANSPORT_LOG) << d.get();
0535 
0536     d->connectionResults.clear();
0537     d->authenticationResults.clear();
0538     d->capabilityResults.clear();
0539     d->popSupportsTLS = false;
0540     d->normalStage = -1;
0541     d->secureStage = -1;
0542     d->encryptionMode = Transport::EnumEncryption::None;
0543     d->normalPossible = true;
0544     d->securePossible = true;
0545 
0546     if (d->testProgress) {
0547         d->testProgress->setMaximum(20);
0548         d->testProgress->setValue(0);
0549         d->testProgress->setTextVisible(true);
0550         d->testProgress->show();
0551         d->progressTimer->start(1000);
0552     }
0553 
0554     d->normalSocket = new MailTransport::Socket(this);
0555     d->secureSocket = new MailTransport::Socket(this);
0556     d->normalSocket->setObjectName(QLatin1StringView("normal"));
0557     d->normalSocket->setServer(d->server);
0558     d->normalSocket->setProtocol(d->testProtocol);
0559     if (d->testProtocol == IMAP_PROTOCOL) {
0560         d->normalSocket->setPort(IMAP_PORT);
0561         d->secureSocket->setPort(IMAPS_PORT);
0562     } else if (d->testProtocol == SMTP_PROTOCOL) {
0563         d->normalSocket->setPort(SMTP_PORT);
0564         d->secureSocket->setPort(SMTPS_PORT);
0565     } else if (d->testProtocol == POP_PROTOCOL) {
0566         d->normalSocket->setPort(POP_PORT);
0567         d->secureSocket->setPort(POPS_PORT);
0568     } else if (d->testProtocol == NNTP_PROTOCOL) {
0569         d->normalSocket->setPort(NNTP_PORT);
0570         d->secureSocket->setPort(NNTPS_PORT);
0571     }
0572 
0573     if (d->customPorts.contains(Transport::EnumEncryption::None)) {
0574         d->normalSocket->setPort(d->customPorts.value(Transport::EnumEncryption::None));
0575     }
0576     if (d->customPorts.contains(Transport::EnumEncryption::SSL)) {
0577         d->secureSocket->setPort(d->customPorts.value(Transport::EnumEncryption::SSL));
0578     }
0579 
0580     connect(d->normalSocket, SIGNAL(connected()), SLOT(slotNormalPossible()));
0581     connect(d->normalSocket, SIGNAL(failed()), SLOT(slotNormalNotPossible()));
0582     connect(d->normalSocket, SIGNAL(data(QString)), SLOT(slotReadNormal(QString)));
0583     connect(d->normalSocket, SIGNAL(tlsDone()), SLOT(slotTlsDone()));
0584     d->normalSocket->reconnect();
0585     d->normalSocketTimer->start(10000);
0586 
0587     if (d->secureSocket->port() > 0) {
0588         d->secureSocket->setObjectName(QLatin1StringView("secure"));
0589         d->secureSocket->setServer(d->server);
0590         d->secureSocket->setProtocol(d->testProtocol + QLatin1Char('s'));
0591         d->secureSocket->setSecure(true);
0592         connect(d->secureSocket, SIGNAL(connected()), SLOT(slotSslPossible()));
0593         connect(d->secureSocket, SIGNAL(failed()), SLOT(slotSslNotPossible()));
0594         connect(d->secureSocket, SIGNAL(data(QString)), SLOT(slotReadSecure(QString)));
0595         d->secureSocket->reconnect();
0596         d->secureSocketTimer->start(10000);
0597     } else {
0598         d->slotSslNotPossible();
0599     }
0600 }
0601 
0602 void ServerTest::setFakeHostname(const QString &fakeHostname)
0603 {
0604     d->fakeHostname = fakeHostname;
0605 }
0606 
0607 QString ServerTest::fakeHostname() const
0608 {
0609     return d->fakeHostname;
0610 }
0611 
0612 void ServerTest::setServer(const QString &server)
0613 {
0614     d->server = server;
0615 }
0616 
0617 void ServerTest::setPort(Transport::EnumEncryption encryptionMode, uint port)
0618 {
0619     Q_ASSERT(encryptionMode == Transport::EnumEncryption::None || encryptionMode == Transport::EnumEncryption::SSL);
0620     d->customPorts.insert(encryptionMode, port);
0621 }
0622 
0623 void ServerTest::setProgressBar(QProgressBar *pb)
0624 {
0625     d->testProgress = pb;
0626 }
0627 
0628 void ServerTest::setProtocol(const QString &protocol)
0629 {
0630     d->testProtocol = protocol;
0631     d->customPorts.clear();
0632 }
0633 
0634 QString ServerTest::protocol() const
0635 {
0636     return d->testProtocol;
0637 }
0638 
0639 QString ServerTest::server() const
0640 {
0641     return d->server;
0642 }
0643 
0644 int ServerTest::port(TransportBase::EnumEncryption encryptionMode) const
0645 {
0646     Q_ASSERT(encryptionMode == Transport::EnumEncryption::None || encryptionMode == Transport::EnumEncryption::SSL);
0647     if (d->customPorts.contains(encryptionMode)) {
0648         return d->customPorts.value(static_cast<int>(encryptionMode));
0649     } else {
0650         return -1;
0651     }
0652 }
0653 
0654 QProgressBar *ServerTest::progressBar() const
0655 {
0656     return d->testProgress;
0657 }
0658 
0659 QList<int> ServerTest::normalProtocols() const
0660 {
0661     return d->authenticationResults[TransportBase::EnumEncryption::None];
0662 }
0663 
0664 bool ServerTest::isNormalPossible() const
0665 {
0666     return d->normalPossible;
0667 }
0668 
0669 QList<int> ServerTest::tlsProtocols() const
0670 {
0671     return d->authenticationResults[TransportBase::EnumEncryption::TLS];
0672 }
0673 
0674 QList<int> ServerTest::secureProtocols() const
0675 {
0676     return d->authenticationResults[Transport::EnumEncryption::SSL];
0677 }
0678 
0679 bool ServerTest::isSecurePossible() const
0680 {
0681     return d->securePossible;
0682 }
0683 
0684 QList<ServerTest::Capability> ServerTest::capabilities() const
0685 {
0686     return d->capabilityResults.values();
0687 }
0688 
0689 #include "moc_servertest.cpp"