1 /*
2   SPDX-FileCopyrightText: 2006-2007 Volker Krause <vkrause@kde.org>
3   SPDX-FileCopyrightText: 2007 KovoKs <info@kovoks.nl>
4   SPDX-FileCopyrightText: 2008 Thomas McGuire <thomas.mcguire@gmx.net>
5 
6   SPDX-License-Identifier: LGPL-2.0-or-later
7 */
8 
9 // Own
10 #include "servertest.h"
11 #include "socket.h"
12 
13 #include <mailtransport_defs.h>
14 #include <transportbase.h>
15 
16 // Qt
17 #include <QHash>
18 #include <QHostInfo>
19 #include <QProgressBar>
20 #include <QRegularExpression>
21 #include <QSet>
22 #include <QTimer>
23 
24 // KDE
25 #include "mailtransport_debug.h"
26 
27 using namespace MailTransport;
28 
29 namespace MailTransport
30 {
31 class ServerTestPrivate
32 {
33 public:
34     ServerTestPrivate(ServerTest *test);
35 
36     ServerTest *const q;
37     QString server;
38     QString fakeHostname;
39     QString testProtocol;
40 
41     MailTransport::Socket *normalSocket = nullptr;
42     MailTransport::Socket *secureSocket = nullptr;
43 
44     QSet<int> connectionResults;
45     QHash<int, QVector<int>> authenticationResults;
46     QSet<ServerTest::Capability> capabilityResults;
47     QHash<int, uint> customPorts;
48     QTimer *normalSocketTimer = nullptr;
49     QTimer *secureSocketTimer = nullptr;
50     QTimer *progressTimer = nullptr;
51 
52     QProgressBar *testProgress = nullptr;
53 
54     bool secureSocketFinished = false;
55     bool normalSocketFinished = false;
56     bool tlsFinished = false;
57     bool popSupportsTLS;
58     int normalStage;
59     int secureStage;
60     int encryptionMode;
61 
62     bool normalPossible = true;
63     bool securePossible = true;
64 
65     void finalResult();
66     void handleSMTPIMAPResponse(int type, const QString &text);
67     void sendInitialCapabilityQuery(MailTransport::Socket *socket);
68     bool handlePopConversation(MailTransport::Socket *socket, int type, int stage, const QString &response, bool *shouldStartTLS);
69     bool handleNntpConversation(MailTransport::Socket *socket, int type, int *stage, const QString &response, bool *shouldStartTLS);
70     QVector<int> parseAuthenticationList(const QStringList &authentications);
71 
isGmail(const QString & server) const72     inline bool isGmail(const QString &server) const
73     {
74         return server.endsWith(QLatin1String("gmail.com")) || server.endsWith(QLatin1String("googlemail.com"));
75     }
76 
77     // slots
78     void slotNormalPossible();
79     void slotNormalNotPossible();
80     void slotSslPossible();
81     void slotSslNotPossible();
82     void slotTlsDone();
83     void slotReadNormal(const QString &text);
84     void slotReadSecure(const QString &text);
85     void slotUpdateProgress();
86 };
87 }
88 
ServerTestPrivate(ServerTest * test)89 ServerTestPrivate::ServerTestPrivate(ServerTest *test)
90     : q(test)
91 {
92 }
93 
finalResult()94 void ServerTestPrivate::finalResult()
95 {
96     if (!secureSocketFinished || !normalSocketFinished || !tlsFinished) {
97         return;
98     }
99 
100     qCDebug(MAILTRANSPORT_LOG) << "Modes:" << connectionResults;
101     qCDebug(MAILTRANSPORT_LOG) << "Capabilities:" << capabilityResults;
102     qCDebug(MAILTRANSPORT_LOG) << "Normal:" << q->normalProtocols();
103     qCDebug(MAILTRANSPORT_LOG) << "SSL:" << q->secureProtocols();
104     qCDebug(MAILTRANSPORT_LOG) << "TLS:" << q->tlsProtocols();
105 
106     if (testProgress) {
107         testProgress->hide();
108     }
109     progressTimer->stop();
110     secureSocketFinished = false;
111     normalSocketFinished = false;
112     tlsFinished = false;
113 
114     QVector<int> resultsAsVector;
115     resultsAsVector.reserve(connectionResults.size());
116     for (int res : std::as_const(connectionResults)) {
117         resultsAsVector.append(res);
118     }
119 
120     Q_EMIT q->finished(resultsAsVector);
121 }
122 
parseAuthenticationList(const QStringList & authentications)123 QVector<int> ServerTestPrivate::parseAuthenticationList(const QStringList &authentications)
124 {
125     QVector<int> result;
126     for (QStringList::ConstIterator it = authentications.begin(); it != authentications.end(); ++it) {
127         QString current = (*it).toUpper();
128         if (current == QLatin1String("LOGIN")) {
129             result << Transport::EnumAuthenticationType::LOGIN;
130         } else if (current == QLatin1String("PLAIN")) {
131             result << Transport::EnumAuthenticationType::PLAIN;
132         } else if (current == QLatin1String("CRAM-MD5")) {
133             result << Transport::EnumAuthenticationType::CRAM_MD5;
134         } else if (current == QLatin1String("DIGEST-MD5")) {
135             result << Transport::EnumAuthenticationType::DIGEST_MD5;
136         } else if (current == QLatin1String("NTLM")) {
137             result << Transport::EnumAuthenticationType::NTLM;
138         } else if (current == QLatin1String("GSSAPI")) {
139             result << Transport::EnumAuthenticationType::GSSAPI;
140         } else if (current == QLatin1String("ANONYMOUS")) {
141             result << Transport::EnumAuthenticationType::ANONYMOUS;
142         } else if (current == QLatin1String("XOAUTH2")) {
143             if (isGmail(server)) {
144                 result << Transport::EnumAuthenticationType::XOAUTH2;
145             }
146         }
147         // APOP is handled by handlePopConversation()
148     }
149     qCDebug(MAILTRANSPORT_LOG) << authentications << result;
150 
151     // LOGIN doesn't offer anything over PLAIN, requires more server
152     // roundtrips and is not an official SASL mechanism, but a MS-ism,
153     // so only enable it if PLAIN isn't available:
154     if (result.contains(Transport::EnumAuthenticationType::PLAIN)) {
155         result.removeAll(Transport::EnumAuthenticationType::LOGIN);
156     }
157 
158     return result;
159 }
160 
handleSMTPIMAPResponse(int type,const QString & text)161 void ServerTestPrivate::handleSMTPIMAPResponse(int type, const QString &text)
162 {
163     if (!text.contains(QLatin1String("AUTH"), Qt::CaseInsensitive)) {
164         qCDebug(MAILTRANSPORT_LOG) << "No authentication possible";
165         return;
166     }
167 
168     QStringList protocols;
169     if (isGmail(server)) {
170         protocols << QStringLiteral("XOAUTH2");
171     }
172 
173     protocols << QStringLiteral("LOGIN") << QStringLiteral("PLAIN") << QStringLiteral("CRAM-MD5") << QStringLiteral("DIGEST-MD5") << QStringLiteral("NTLM")
174               << QStringLiteral("GSSAPI") << QStringLiteral("ANONYMOUS");
175 
176     QStringList results;
177     for (int i = 0; i < protocols.count(); ++i) {
178         if (text.contains(protocols.at(i), Qt::CaseInsensitive)) {
179             results.append(protocols.at(i));
180         }
181     }
182 
183     authenticationResults[type] = parseAuthenticationList(results);
184 
185     // if we couldn't parse any authentication modes, default to clear-text
186     if (authenticationResults[type].isEmpty()) {
187         authenticationResults[type] << Transport::EnumAuthenticationType::CLEAR;
188     }
189 
190     qCDebug(MAILTRANSPORT_LOG) << "For type" << type << ", we have:" << authenticationResults[type];
191 }
192 
slotNormalPossible()193 void ServerTestPrivate::slotNormalPossible()
194 {
195     normalSocketTimer->stop();
196     connectionResults << Transport::EnumEncryption::None;
197 }
198 
sendInitialCapabilityQuery(MailTransport::Socket * socket)199 void ServerTestPrivate::sendInitialCapabilityQuery(MailTransport::Socket *socket)
200 {
201     if (testProtocol == IMAP_PROTOCOL) {
202         socket->write(QStringLiteral("1 CAPABILITY"));
203     } else if (testProtocol == SMTP_PROTOCOL) {
204         // Detect the hostname which we send with the EHLO command.
205         // If there is a fake one set, use that, otherwise use the
206         // local host name (and make sure it contains a domain, so the
207         // server thinks it is valid).
208         QString hostname;
209         if (!fakeHostname.isNull()) {
210             hostname = fakeHostname;
211         } else {
212             hostname = QHostInfo::localHostName();
213             if (hostname.isEmpty()) {
214                 hostname = QStringLiteral("localhost.invalid");
215             } else if (!hostname.contains(QChar::fromLatin1('.'))) {
216                 hostname += QLatin1String(".localnet");
217             }
218         }
219         qCDebug(MAILTRANSPORT_LOG) << "Hostname for EHLO is" << hostname;
220 
221         socket->write(QLatin1String("EHLO ") + hostname);
222     }
223 }
224 
slotTlsDone()225 void ServerTestPrivate::slotTlsDone()
226 {
227     // The server will not send a response after starting TLS. Therefore, we have to manually
228     // call slotReadNormal(), because this is not triggered by a data received signal this time.
229     slotReadNormal(QString());
230 }
231 
handlePopConversation(MailTransport::Socket * socket,int type,int stage,const QString & response,bool * shouldStartTLS)232 bool ServerTestPrivate::handlePopConversation(MailTransport::Socket *socket, int type, int stage, const QString &response, bool *shouldStartTLS)
233 {
234     Q_ASSERT(shouldStartTLS != nullptr);
235 
236     // Initial Greeting
237     if (stage == 0) {
238         // Regexp taken from POP3 ioslave
239         const QString responseWithoutCRLF = response.isEmpty() ? response : response.chopped(2);
240         static const QRegularExpression re(QStringLiteral("<[A-Za-z0-9\\.\\-_]+@[A-Za-z0-9\\.\\-_]+>$"), QRegularExpression::CaseInsensitiveOption);
241         if (responseWithoutCRLF.indexOf(re) != -1) {
242             authenticationResults[type] << Transport::EnumAuthenticationType::APOP;
243         }
244 
245         // Each server is supposed to support clear text login
246         authenticationResults[type] << Transport::EnumAuthenticationType::CLEAR;
247 
248         // If we are in TLS stage, the server does not send the initial greeting.
249         // Assume that the APOP availability is the same as with an unsecured connection.
250         if (type == Transport::EnumEncryption::TLS
251             && authenticationResults[Transport::EnumEncryption::None].contains(Transport::EnumAuthenticationType::APOP)) {
252             authenticationResults[Transport::EnumEncryption::TLS] << Transport::EnumAuthenticationType::APOP;
253         }
254 
255         socket->write(QStringLiteral("CAPA"));
256         return true;
257     }
258     // CAPA result
259     else if (stage == 1) {
260         //     Example:
261         //     CAPA
262         //     +OK
263         //     TOP
264         //     USER
265         //     SASL LOGIN CRAM-MD5
266         //     UIDL
267         //     RESP-CODES
268         //     .
269         if (response.contains(QLatin1String("TOP"))) {
270             capabilityResults += ServerTest::Top;
271         }
272         if (response.contains(QLatin1String("PIPELINING"))) {
273             capabilityResults += ServerTest::Pipelining;
274         }
275         if (response.contains(QLatin1String("UIDL"))) {
276             capabilityResults += ServerTest::UIDL;
277         }
278         if (response.contains(QLatin1String("STLS"))) {
279             connectionResults << Transport::EnumEncryption::TLS;
280             popSupportsTLS = true;
281         }
282         socket->write(QStringLiteral("AUTH"));
283         return true;
284     }
285     // AUTH response
286     else if (stage == 2) {
287         //     Example:
288         //     C: AUTH
289         //     S: +OK List of supported authentication methods follows
290         //     S: LOGIN
291         //     S: CRAM-MD5
292         //     S:.
293         QString formattedReply = response;
294 
295         // Get rid of trailing ".CRLF"
296         formattedReply.chop(3);
297 
298         // Get rid of the first +OK line
299         formattedReply = formattedReply.right(formattedReply.size() - formattedReply.indexOf(QLatin1Char('\n')) - 1);
300         formattedReply = formattedReply.replace(QLatin1Char(' '), QLatin1Char('-')).replace(QLatin1String("\r\n"), QLatin1String(" "));
301 
302         authenticationResults[type] += parseAuthenticationList(formattedReply.split(QLatin1Char(' ')));
303     }
304 
305     *shouldStartTLS = popSupportsTLS;
306     return false;
307 }
308 
handleNntpConversation(MailTransport::Socket * socket,int type,int * stage,const QString & response,bool * shouldStartTLS)309 bool ServerTestPrivate::handleNntpConversation(MailTransport::Socket *socket, int type, int *stage, const QString &response, bool *shouldStartTLS)
310 {
311     Q_ASSERT(shouldStartTLS != nullptr);
312     Q_ASSERT(stage != nullptr);
313 
314     // Initial Greeting
315     if (*stage == 0) {
316         if (response.startsWith(QLatin1String("382 "))) {
317             return true;
318         }
319         if (!response.isEmpty() && !response.startsWith(QLatin1String("200 "))) {
320             return false;
321         }
322 
323         socket->write(QStringLiteral("CAPABILITIES"));
324         return true;
325     }
326     // CAPABILITIES result
327     else if (*stage == 1) {
328         // Check whether we got "500 command 'CAPABILITIES' not recognized"
329         if (response.startsWith(QLatin1String("500 "))) {
330             return false;
331         }
332 
333         //     Example:
334         //     101 Capability list:
335         //     VERSION 2
336         //     IMPLEMENTATION INN 2.5.4
337         //     AUTHINFO USER SASL
338         //     HDR
339         //     LIST ACTIVE [etc]
340         //     OVER
341         //     POST
342         //     READER
343         //     SASL DIGEST-MD5 CRAM-MD5 NTLM PLAIN LOGIN
344         //     STARTTLS
345         //     .
346 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
347         const QVector<QStringView> lines = QStringView(response).split(QStringLiteral("\r\n"), Qt::SkipEmptyParts);
348         for (const QStringView line : lines) {
349 #else
350         const QVector<QStringRef> lines = response.splitRef(QStringLiteral("\r\n"), Qt::SkipEmptyParts);
351         for (const QStringRef &line : lines) {
352 #endif
353             if (line.compare(QLatin1String("STARTTLS"), Qt::CaseInsensitive) == 0) {
354                 *shouldStartTLS = true;
355             } else if (line.startsWith(QLatin1String("AUTHINFO "), Qt::CaseInsensitive)) {
356                 const QVector<QStringRef> authinfos = line.split(QLatin1Char(' '), Qt::SkipEmptyParts);
357                 const QString s(QStringLiteral("USER"));
358                 const QStringRef ref(&s);
359                 if (authinfos.contains(ref)) {
360                     authenticationResults[type].append(Transport::EnumAuthenticationType::CLEAR); // XXX
361                 }
362             } else if (line.startsWith(QLatin1String("SASL "), Qt::CaseInsensitive)) {
363                 const QStringList auths = line.mid(5).toString().split(QLatin1Char(' '), Qt::SkipEmptyParts);
364                 authenticationResults[type] += parseAuthenticationList(auths);
365             } else if (line == QLatin1Char('.')) {
366                 return false;
367             }
368         }
369         // We have not hit the end of the capabilities list yet,
370         // so avoid the stage counter to rise without reason.
371         --(*stage);
372         return true;
373     }
374 
375     return false;
376 }
377 
378 // slotReadNormal() handles normal (no) encryption and TLS encryption.
379 // At first, the communication is not encrypted, but if the server supports
380 // the STARTTLS/STLS keyword, the same authentication query is done again
381 // with TLS.
382 void ServerTestPrivate::slotReadNormal(const QString &text)
383 {
384     Q_ASSERT(encryptionMode != Transport::EnumEncryption::SSL);
385     static const int tlsHandshakeStage = 42;
386 
387     qCDebug(MAILTRANSPORT_LOG) << "Stage" << normalStage + 1 << ", Mode" << encryptionMode;
388 
389     // If we are in stage 42, we just do the handshake for TLS encryption and
390     // then reset the stage to -1, so that all authentication modes and
391     // capabilities are queried again for TLS encryption (some servers have
392     // different authentication  methods in normal and in TLS mode).
393     if (normalStage == tlsHandshakeStage) {
394         Q_ASSERT(encryptionMode == Transport::EnumEncryption::TLS);
395         normalStage = -1;
396         normalSocket->startTLS();
397         return;
398     }
399 
400     bool shouldStartTLS = false;
401     normalStage++;
402 
403     // Handle the whole POP and NNTP conversations separately, as
404     // they are very different from IMAP and SMTP
405     if (testProtocol == POP_PROTOCOL) {
406         if (handlePopConversation(normalSocket, encryptionMode, normalStage, text, &shouldStartTLS)) {
407             return;
408         }
409     } else if (testProtocol == NNTP_PROTOCOL) {
410         if (handleNntpConversation(normalSocket, encryptionMode, &normalStage, text, &shouldStartTLS)) {
411             return;
412         }
413     } else {
414         // Handle the SMTP/IMAP conversation here. We just send the EHLO command in
415         // sendInitialCapabilityQuery.
416         if (normalStage == 0) {
417             sendInitialCapabilityQuery(normalSocket);
418             return;
419         }
420 
421         if (text.contains(QLatin1String("STARTTLS"), Qt::CaseInsensitive)) {
422             connectionResults << Transport::EnumEncryption::TLS;
423             shouldStartTLS = true;
424         }
425         handleSMTPIMAPResponse(encryptionMode, text);
426     }
427 
428     // If we reach here, the normal authentication/capabilities query is completed.
429     // Now do the same for TLS.
430     normalSocketFinished = true;
431 
432     // If the server announced that STARTTLS/STLS is available, we'll add TLS to the
433     // connection result, do the command and set the stage to 42 to start the handshake.
434     if (shouldStartTLS && encryptionMode == Transport::EnumEncryption::None) {
435         qCDebug(MAILTRANSPORT_LOG) << "Trying TLS...";
436         connectionResults << Transport::EnumEncryption::TLS;
437         if (testProtocol == POP_PROTOCOL) {
438             normalSocket->write(QStringLiteral("STLS"));
439         } else if (testProtocol == IMAP_PROTOCOL) {
440             normalSocket->write(QStringLiteral("2 STARTTLS"));
441         } else {
442             normalSocket->write(QStringLiteral("STARTTLS"));
443         }
444         encryptionMode = Transport::EnumEncryption::TLS;
445         normalStage = tlsHandshakeStage;
446         return;
447     }
448 
449     // If we reach here, either the TLS authentication/capabilities query is finished
450     // or the server does not support the STARTTLS/STLS command.
451     tlsFinished = true;
452     finalResult();
453 }
454 
455 void ServerTestPrivate::slotReadSecure(const QString &text)
456 {
457     secureStage++;
458     if (testProtocol == POP_PROTOCOL) {
459         bool dummy;
460         if (handlePopConversation(secureSocket, Transport::EnumEncryption::SSL, secureStage, text, &dummy)) {
461             return;
462         }
463     } else if (testProtocol == NNTP_PROTOCOL) {
464         bool dummy;
465         if (handleNntpConversation(secureSocket, Transport::EnumEncryption::SSL, &secureStage, text, &dummy)) {
466             return;
467         }
468     } else {
469         if (secureStage == 0) {
470             sendInitialCapabilityQuery(secureSocket);
471             return;
472         }
473         handleSMTPIMAPResponse(Transport::EnumEncryption::SSL, text);
474     }
475     secureSocketFinished = true;
476     finalResult();
477 }
478 
479 void ServerTestPrivate::slotNormalNotPossible()
480 {
481     if (testProtocol == SMTP_PROTOCOL && normalSocket->port() == SMTP_PORT) {
482         // For SMTP, fallback to port 25
483         normalSocket->setPort(SMTP_OLD_PORT);
484         normalSocket->reconnect();
485         normalSocketTimer->start(10000);
486         return;
487     }
488 
489     normalSocketTimer->stop();
490     normalPossible = false;
491     normalSocketFinished = true;
492     tlsFinished = true;
493     finalResult();
494 }
495 
496 void ServerTestPrivate::slotSslPossible()
497 {
498     secureSocketTimer->stop();
499     connectionResults << Transport::EnumEncryption::SSL;
500 }
501 
502 void ServerTestPrivate::slotSslNotPossible()
503 {
504     secureSocketTimer->stop();
505     securePossible = false;
506     secureSocketFinished = true;
507     finalResult();
508 }
509 
510 void ServerTestPrivate::slotUpdateProgress()
511 {
512     if (testProgress) {
513         testProgress->setValue(testProgress->value() + 1);
514     }
515 }
516 
517 //---------------------- end private class -----------------------//
518 
519 ServerTest::ServerTest(QObject *parent)
520     : QObject(parent)
521     , d(new ServerTestPrivate(this))
522 {
523     d->normalSocketTimer = new QTimer(this);
524     d->normalSocketTimer->setSingleShot(true);
525     connect(d->normalSocketTimer, SIGNAL(timeout()), SLOT(slotNormalNotPossible()));
526 
527     d->secureSocketTimer = new QTimer(this);
528     d->secureSocketTimer->setSingleShot(true);
529     connect(d->secureSocketTimer, SIGNAL(timeout()), SLOT(slotSslNotPossible()));
530 
531     d->progressTimer = new QTimer(this);
532     connect(d->progressTimer, SIGNAL(timeout()), SLOT(slotUpdateProgress()));
533 }
534 
535 ServerTest::~ServerTest() = default;
536 
537 void ServerTest::start()
538 {
539     qCDebug(MAILTRANSPORT_LOG) << d.get();
540 
541     d->connectionResults.clear();
542     d->authenticationResults.clear();
543     d->capabilityResults.clear();
544     d->popSupportsTLS = false;
545     d->normalStage = -1;
546     d->secureStage = -1;
547     d->encryptionMode = Transport::EnumEncryption::None;
548     d->normalPossible = true;
549     d->securePossible = true;
550 
551     if (d->testProgress) {
552         d->testProgress->setMaximum(20);
553         d->testProgress->setValue(0);
554         d->testProgress->setTextVisible(true);
555         d->testProgress->show();
556         d->progressTimer->start(1000);
557     }
558 
559     d->normalSocket = new MailTransport::Socket(this);
560     d->secureSocket = new MailTransport::Socket(this);
561     d->normalSocket->setObjectName(QStringLiteral("normal"));
562     d->normalSocket->setServer(d->server);
563     d->normalSocket->setProtocol(d->testProtocol);
564     if (d->testProtocol == IMAP_PROTOCOL) {
565         d->normalSocket->setPort(IMAP_PORT);
566         d->secureSocket->setPort(IMAPS_PORT);
567     } else if (d->testProtocol == SMTP_PROTOCOL) {
568         d->normalSocket->setPort(SMTP_PORT);
569         d->secureSocket->setPort(SMTPS_PORT);
570     } else if (d->testProtocol == POP_PROTOCOL) {
571         d->normalSocket->setPort(POP_PORT);
572         d->secureSocket->setPort(POPS_PORT);
573     } else if (d->testProtocol == NNTP_PROTOCOL) {
574         d->normalSocket->setPort(NNTP_PORT);
575         d->secureSocket->setPort(NNTPS_PORT);
576     }
577 
578     if (d->customPorts.contains(Transport::EnumEncryption::None)) {
579         d->normalSocket->setPort(d->customPorts.value(Transport::EnumEncryption::None));
580     }
581     if (d->customPorts.contains(Transport::EnumEncryption::SSL)) {
582         d->secureSocket->setPort(d->customPorts.value(Transport::EnumEncryption::SSL));
583     }
584 
585     connect(d->normalSocket, SIGNAL(connected()), SLOT(slotNormalPossible()));
586     connect(d->normalSocket, SIGNAL(failed()), SLOT(slotNormalNotPossible()));
587     connect(d->normalSocket, SIGNAL(data(QString)), SLOT(slotReadNormal(QString)));
588     connect(d->normalSocket, SIGNAL(tlsDone()), SLOT(slotTlsDone()));
589     d->normalSocket->reconnect();
590     d->normalSocketTimer->start(10000);
591 
592     if (d->secureSocket->port() > 0) {
593         d->secureSocket->setObjectName(QStringLiteral("secure"));
594         d->secureSocket->setServer(d->server);
595         d->secureSocket->setProtocol(d->testProtocol + QLatin1Char('s'));
596         d->secureSocket->setSecure(true);
597         connect(d->secureSocket, SIGNAL(connected()), SLOT(slotSslPossible()));
598         connect(d->secureSocket, SIGNAL(failed()), SLOT(slotSslNotPossible()));
599         connect(d->secureSocket, SIGNAL(data(QString)), SLOT(slotReadSecure(QString)));
600         d->secureSocket->reconnect();
601         d->secureSocketTimer->start(10000);
602     } else {
603         d->slotSslNotPossible();
604     }
605 }
606 
607 void ServerTest::setFakeHostname(const QString &fakeHostname)
608 {
609     d->fakeHostname = fakeHostname;
610 }
611 
612 QString ServerTest::fakeHostname() const
613 {
614     return d->fakeHostname;
615 }
616 
617 void ServerTest::setServer(const QString &server)
618 {
619     d->server = server;
620 }
621 
622 void ServerTest::setPort(Transport::EnumEncryption::type encryptionMode, uint port)
623 {
624     Q_ASSERT(encryptionMode == Transport::EnumEncryption::None || encryptionMode == Transport::EnumEncryption::SSL);
625     d->customPorts.insert(encryptionMode, port);
626 }
627 
628 void ServerTest::setProgressBar(QProgressBar *pb)
629 {
630     d->testProgress = pb;
631 }
632 
633 void ServerTest::setProtocol(const QString &protocol)
634 {
635     d->testProtocol = protocol;
636     d->customPorts.clear();
637 }
638 
639 QString ServerTest::protocol() const
640 {
641     return d->testProtocol;
642 }
643 
644 QString ServerTest::server() const
645 {
646     return d->server;
647 }
648 
649 int ServerTest::port(TransportBase::EnumEncryption::type encryptionMode) const
650 {
651     Q_ASSERT(encryptionMode == Transport::EnumEncryption::None || encryptionMode == Transport::EnumEncryption::SSL);
652     if (d->customPorts.contains(encryptionMode)) {
653         return d->customPorts.value(static_cast<int>(encryptionMode));
654     } else {
655         return -1;
656     }
657 }
658 
659 QProgressBar *ServerTest::progressBar() const
660 {
661     return d->testProgress;
662 }
663 
664 QVector<int> ServerTest::normalProtocols() const
665 {
666     return d->authenticationResults[TransportBase::EnumEncryption::None];
667 }
668 
669 bool ServerTest::isNormalPossible() const
670 {
671     return d->normalPossible;
672 }
673 
674 QVector<int> ServerTest::tlsProtocols() const
675 {
676     return d->authenticationResults[TransportBase::EnumEncryption::TLS];
677 }
678 
679 QVector<int> ServerTest::secureProtocols() const
680 {
681     return d->authenticationResults[Transport::EnumEncryption::SSL];
682 }
683 
684 bool ServerTest::isSecurePossible() const
685 {
686     return d->securePossible;
687 }
688 
689 QList<ServerTest::Capability> ServerTest::capabilities() const
690 {
691     return d->capabilityResults.values();
692 }
693 
694 #include "moc_servertest.cpp"
695