MailTransport

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

KDE's Doxygen guidelines are available online.