service/MailServerDiscovery.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "MailServerDiscovery.h" | ||
| 2 | #include <QDnsLookup> | ||
| 3 | #include <QElapsedTimer> | ||
| 4 | #include <QLoggingCategory> | ||
| 5 | #include <QNetworkAccessManager> | ||
| 6 | #include <QNetworkReply> | ||
| 7 | #include <QPointer> | ||
| 8 | #include <QRegularExpression> | ||
| 9 | #include <QSslSocket> | ||
| 10 | #include <QXmlStreamReader> | ||
| 11 | #include <algorithm> | ||
| 12 | #include <memory> | ||
| 13 | |||
| 14 |
4/7✓ Branch 2 → 3 taken 2 times.
✓ Branch 2 → 8 taken 114 times.
✓ Branch 4 → 5 taken 2 times.
✗ Branch 4 → 8 not taken.
✓ Branch 5 → 6 taken 2 times.
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 12 not taken.
|
116 | Q_LOGGING_CATEGORY(lcDiscovery, "mailjd.settings.discovery") |
| 15 | |||
| 16 | namespace { | ||
| 17 | 812 | MailServerDiscovery::SrvLookup defaultSrv() { | |
| 18 | 812 | return [](QObject *owner, const QString &name, std::function<void(QList<MailServerDiscovery::SrvRecord>)> done) { | |
| 19 | ✗ | auto *lookup = new QDnsLookup(QDnsLookup::SRV, name, owner); | |
| 20 | ✗ | QObject::connect(lookup, &QDnsLookup::finished, lookup, [lookup, done] { | |
| 21 | ✗ | QList<MailServerDiscovery::SrvRecord> records; | |
| 22 | ✗ | if (lookup->error() == QDnsLookup::NoError) | |
| 23 | ✗ | for (const auto &record : lookup->serviceRecords()) | |
| 24 | ✗ | records.append({record.target(), record.port(), record.priority()}); | |
| 25 | ✗ | lookup->deleteLater(); | |
| 26 | ✗ | done(records); | |
| 27 | ✗ | }); | |
| 28 | ✗ | lookup->lookup(); | |
| 29 | 812 | }; | |
| 30 | } | ||
| 31 | |||
| 32 | 812 | MailServerDiscovery::HttpGet defaultHttp(QObject *parent) { | |
| 33 |
2/5✓ Branch 3 → 4 taken 812 times.
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 812 times.
✗ Branch 9 → 10 not taken.
✗ Branch 9 → 11 not taken.
|
812 | auto *manager = new QNetworkAccessManager(parent); |
| 34 | 812 | return [manager](QObject *owner, const QUrl &url, std::function<void(int, QByteArray)> done) { | |
| 35 | ✗ | QNetworkRequest request(url); | |
| 36 | // Rule 11: never follow a redirect silently (it may leave the domain). | ||
| 37 | ✗ | request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::ManualRedirectPolicy); | |
| 38 | ✗ | request.setTransferTimeout(4000); | |
| 39 | ✗ | request.setHeader(QNetworkRequest::UserAgentHeader, QStringLiteral("MailJD")); | |
| 40 | ✗ | QNetworkReply *reply = manager->get(request); | |
| 41 | ✗ | QObject::connect(owner, &QObject::destroyed, reply, &QNetworkReply::abort); | |
| 42 | ✗ | QObject::connect(reply, &QNetworkReply::finished, reply, [reply, done] { | |
| 43 | ✗ | const int status = reply->error() == QNetworkReply::NoError | |
| 44 | ✗ | ? reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() : 0; | |
| 45 | ✗ | const QByteArray body = status == 200 ? reply->read(512 * 1024) : QByteArray(); | |
| 46 | ✗ | reply->deleteLater(); | |
| 47 | ✗ | done(status, body); | |
| 48 | ✗ | }); | |
| 49 | 1624 | }; | |
| 50 | } | ||
| 51 | |||
| 52 | 812 | MailServerDiscovery::TlsProbe defaultTls() { | |
| 53 | 812 | return [](QObject *owner, const QString &host, quint16 port, std::function<void(bool)> done) { | |
| 54 | ✗ | auto *socket = new QSslSocket(owner); | |
| 55 | ✗ | auto reported = std::make_shared<bool>(false); | |
| 56 | ✗ | const auto report = [socket, reported, done](bool ok) { | |
| 57 | ✗ | if (*reported) return; | |
| 58 | ✗ | *reported = true; | |
| 59 | ✗ | socket->abort(); | |
| 60 | ✗ | socket->deleteLater(); | |
| 61 | ✗ | done(ok); | |
| 62 | ✗ | }; | |
| 63 | ✗ | QObject::connect(socket, &QSslSocket::encrypted, socket, [report] { report(true); }); | |
| 64 | ✗ | QObject::connect(socket, &QSslSocket::errorOccurred, socket, [report](QAbstractSocket::SocketError) { report(false); }); | |
| 65 | ✗ | QObject::connect(socket, &QSslSocket::sslErrors, socket, [report](const QList<QSslError> &) { report(false); }); | |
| 66 | ✗ | QTimer::singleShot(4000, socket, [report] { report(false); }); | |
| 67 | ✗ | socket->connectToHostEncrypted(host, port); | |
| 68 | 812 | }; | |
| 69 | } | ||
| 70 | |||
| 71 | 44 | QString security(const QString &socketType) { | |
| 72 |
2/2✓ Branch 2 → 3 taken 44 times.
✓ Branch 3 → 4 taken 44 times.
|
44 | const QString type = socketType.trimmed().toUpper(); |
| 73 |
2/2✓ Branch 7 → 8 taken 25 times.
✓ Branch 7 → 13 taken 19 times.
|
69 | if (type == QLatin1String("SSL")) return QStringLiteral("ssl"); |
| 74 |
2/2✓ Branch 15 → 16 taken 10 times.
✓ Branch 15 → 21 taken 9 times.
|
29 | if (type == QLatin1String("STARTTLS")) return QStringLiteral("starttls"); |
| 75 | 9 | return {}; // "plain" and unknown types are never used (rule 11) | |
| 76 | 44 | } | |
| 77 | |||
| 78 | 88 | QString resolvePlaceholders(QString text, const QString &address) { | |
| 79 |
1/1✓ Branch 5 → 6 taken 88 times.
|
176 | return text.replace(QStringLiteral("%EMAILADDRESS%"), address) |
| 80 |
2/2✓ Branch 8 → 9 taken 88 times.
✓ Branch 12 → 13 taken 88 times.
|
264 | .replace(QStringLiteral("%EMAILLOCALPART%"), address.section('@', 0, 0)) |
| 81 |
3/3✓ Branch 15 → 16 taken 88 times.
✓ Branch 16 → 17 taken 88 times.
✓ Branch 20 → 21 taken 88 times.
|
264 | .replace(QStringLiteral("%EMAILDOMAIN%"), address.section('@', 1).toLower()); |
| 82 | } | ||
| 83 | } // namespace | ||
| 84 | |||
| 85 | 812 | MailServerDiscovery::MailServerDiscovery(QObject *parent) | |
| 86 |
2/2✓ Branch 8 → 9 taken 812 times.
✓ Branch 10 → 11 taken 812 times.
|
812 | : QObject(parent), m_srv(defaultSrv()), m_http(defaultHttp(this)), m_tls(defaultTls()) { |
| 87 |
1/1✓ Branch 12 → 13 taken 812 times.
|
812 | m_overall.setSingleShot(true); |
| 88 |
1/1✓ Branch 13 → 14 taken 812 times.
|
812 | connect(&m_overall, &QTimer::timeout, this, [this] { |
| 89 | ✗ | for (auto it = m_sources.begin(); it != m_sources.end(); ++it) | |
| 90 | ✗ | if (it.value() == QLatin1String("pending")) it.value() = QStringLiteral("none"); | |
| 91 | ✗ | emit sourcesChanged(); | |
| 92 | ✗ | finishIfDone(); | |
| 93 | ✗ | }); | |
| 94 | 812 | } | |
| 95 | |||
| 96 | 24 | void MailServerDiscovery::setSeams(SrvLookup srv, HttpGet http, TlsProbe tls) { | |
| 97 | 24 | m_srv = std::move(srv); | |
| 98 | 24 | m_http = std::move(http); | |
| 99 | 24 | m_tls = std::move(tls); | |
| 100 | 24 | } | |
| 101 | |||
| 102 | 44 | QString MailServerDiscovery::resolveUsername(const QString &pattern, const QString &address) { | |
| 103 |
5/9✓ Branch 2 → 3 taken 44 times.
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 44 times.
✓ Branch 6 → 7 taken 44 times.
✓ Branch 7 → 8 taken 44 times.
✓ Branch 9 → 10 taken 44 times.
✗ Branch 9 → 11 not taken.
✗ Branch 14 → 15 not taken.
✗ Branch 14 → 16 not taken.
|
44 | return pattern.trimmed().isEmpty() ? address : resolvePlaceholders(pattern.trimmed(), address); |
| 104 | } | ||
| 105 | |||
| 106 | 34 | bool MailServerDiscovery::hostInDomain(const QString &host, const QString &domain) { | |
| 107 |
3/3✓ Branch 2 → 3 taken 34 times.
✓ Branch 7 → 8 taken 34 times.
✓ Branch 8 → 9 taken 34 times.
|
68 | const QString h = host.toLower().remove(QRegularExpression(QStringLiteral("\\.$"))); |
| 108 |
1/1✓ Branch 14 → 15 taken 34 times.
|
34 | const QString d = domain.toLower(); |
| 109 |
9/12✓ Branch 16 → 17 taken 34 times.
✗ Branch 16 → 25 not taken.
✓ Branch 18 → 19 taken 31 times.
✓ Branch 18 → 24 taken 3 times.
✓ Branch 21 → 22 taken 31 times.
✓ Branch 22 → 23 taken 31 times.
✓ Branch 23 → 24 taken 9 times.
✓ Branch 23 → 25 taken 22 times.
✓ Branch 27 → 28 taken 31 times.
✓ Branch 27 → 29 taken 3 times.
✗ Branch 46 → 47 not taken.
✗ Branch 46 → 48 not taken.
|
68 | return !d.isEmpty() && (h == d || h.endsWith(QLatin1Char('.') + d)); |
| 110 | 34 | } | |
| 111 | |||
| 112 | 34 | int MailServerDiscovery::rank(const Result &result) { | |
| 113 |
5/10✓ Branch 2 → 3 taken 2 times.
✓ Branch 2 → 16 taken 32 times.
✓ Branch 4 → 5 taken 2 times.
✗ Branch 4 → 16 not taken.
✓ Branch 13 → 14 taken 8 times.
✓ Branch 13 → 15 taken 2 times.
✗ Branch 31 → 32 not taken.
✗ Branch 31 → 33 not taken.
✗ Branch 44 → 45 not taken.
✗ Branch 44 → 46 not taken.
|
44 | static const QHash<QString, int> sources = {{"autoconfig", 40}, {"srv", 30}, {"probe", 20}, {"ispdb", 10}}; |
| 114 |
5/6✓ Branch 17 → 18 taken 27 times.
✓ Branch 17 → 19 taken 7 times.
✓ Branch 20 → 21 taken 24 times.
✓ Branch 20 → 22 taken 10 times.
✓ Branch 24 → 25 taken 34 times.
✗ Branch 24 → 26 not taken.
|
34 | return (result.complete() ? 1000 : 0) + (result.trusted ? 500 : 0) + (result.imap.valid() ? 100 : 0) + |
| 115 | 34 | sources.value(result.source); | |
| 116 | 2 | } | |
| 117 | |||
| 118 | 17 | QList<MailServerDiscovery::Result> MailServerDiscovery::parseAutoconfig(const QByteArray &xml, const QString &address, | |
| 119 | const QString &source, bool trusted) { | ||
| 120 |
1/1✓ Branch 2 → 3 taken 17 times.
|
17 | QXmlStreamReader reader(xml); |
| 121 | 17 | QList<Server> incoming, outgoing; | |
| 122 |
7/8✓ Branch 141 → 142 taken 1336 times.
✓ Branch 142 → 143 taken 1319 times.
✓ Branch 142 → 146 taken 17 times.
✓ Branch 143 → 144 taken 1319 times.
✓ Branch 144 → 145 taken 1319 times.
✗ Branch 144 → 146 not taken.
✓ Branch 147 → 4 taken 1319 times.
✓ Branch 147 → 148 taken 17 times.
|
1336 | while (!reader.atEnd() && !reader.hasError()) { |
| 123 |
1/1✓ Branch 4 → 5 taken 1319 times.
|
1319 | reader.readNext(); |
| 124 |
3/3✓ Branch 5 → 6 taken 1319 times.
✓ Branch 6 → 7 taken 956 times.
✓ Branch 6 → 8 taken 363 times.
|
1648 | if (!reader.isStartElement()) continue; |
| 125 |
2/2✓ Branch 8 → 9 taken 363 times.
✓ Branch 9 → 10 taken 363 times.
|
363 | const QString element = reader.name().toString(); |
| 126 |
2/2✓ Branch 10 → 11 taken 363 times.
✓ Branch 16 → 17 taken 363 times.
|
726 | const QString type = reader.attributes().value(QStringLiteral("type")).toString(); |
| 127 |
4/4✓ Branch 22 → 23 taken 32 times.
✓ Branch 22 → 27 taken 331 times.
✓ Branch 25 → 26 taken 23 times.
✓ Branch 25 → 27 taken 9 times.
|
363 | const bool imap = element == QLatin1String("incomingServer") && type == QLatin1String("imap"); |
| 128 |
3/4✓ Branch 30 → 31 taken 21 times.
✓ Branch 30 → 35 taken 342 times.
✓ Branch 33 → 34 taken 21 times.
✗ Branch 33 → 35 not taken.
|
363 | const bool smtp = element == QLatin1String("outgoingServer") && type == QLatin1String("smtp"); |
| 129 |
4/4✓ Branch 36 → 37 taken 340 times.
✓ Branch 36 → 39 taken 23 times.
✓ Branch 37 → 38 taken 319 times.
✓ Branch 37 → 39 taken 21 times.
|
363 | if (!imap && !smtp) continue; |
| 130 | 44 | Server server; | |
| 131 | 44 | QString socketType, username; | |
| 132 |
13/16✓ Branch 88 → 89 taken 432 times.
✓ Branch 89 → 90 taken 237 times.
✓ Branch 89 → 94 taken 195 times.
✓ Branch 90 → 91 taken 237 times.
✓ Branch 91 → 92 taken 237 times.
✓ Branch 93 → 94 taken 193 times.
✓ Branch 93 → 97 taken 44 times.
✓ Branch 94 → 95 taken 388 times.
✓ Branch 95 → 96 taken 388 times.
✗ Branch 95 → 97 not taken.
✓ Branch 98 → 99 taken 237 times.
✓ Branch 98 → 100 taken 195 times.
✓ Branch 100 → 40 taken 388 times.
✓ Branch 100 → 101 taken 44 times.
✗ Branch 201 → 202 not taken.
✗ Branch 201 → 203 not taken.
|
432 | while (!(reader.isEndElement() && reader.name().toString() == element) && !reader.atEnd()) { |
| 133 |
1/1✓ Branch 40 → 41 taken 388 times.
|
388 | reader.readNext(); |
| 134 |
3/3✓ Branch 41 → 42 taken 388 times.
✓ Branch 42 → 43 taken 195 times.
✓ Branch 42 → 44 taken 193 times.
|
388 | if (!reader.isStartElement()) continue; |
| 135 |
2/2✓ Branch 44 → 45 taken 193 times.
✓ Branch 45 → 46 taken 193 times.
|
193 | const QString field = reader.name().toString(); |
| 136 |
5/5✓ Branch 48 → 49 taken 44 times.
✓ Branch 48 → 57 taken 149 times.
✓ Branch 49 → 50 taken 44 times.
✓ Branch 50 → 51 taken 44 times.
✓ Branch 51 → 52 taken 44 times.
|
193 | if (field == QLatin1String("hostname")) server.host = resolvePlaceholders(reader.readElementText().trimmed(), address); |
| 137 |
2/2✓ Branch 59 → 60 taken 44 times.
✓ Branch 59 → 71 taken 105 times.
|
149 | else if (field == QLatin1String("port")) { |
| 138 | // S106-203: out of range is no port (the server is dropped), not a | ||
| 139 | // truncated one (65600 used to become 64). | ||
| 140 | 44 | bool ok = false; | |
| 141 |
3/3✓ Branch 60 → 61 taken 44 times.
✓ Branch 61 → 62 taken 44 times.
✓ Branch 62 → 63 taken 44 times.
|
44 | const uint port = reader.readElementText().trimmed().toUInt(&ok); |
| 142 |
4/6✓ Branch 65 → 66 taken 44 times.
✗ Branch 65 → 69 not taken.
✓ Branch 66 → 67 taken 44 times.
✗ Branch 66 → 69 not taken.
✓ Branch 67 → 68 taken 43 times.
✓ Branch 67 → 69 taken 1 time.
|
44 | server.port = ok && port >= 1 && port <= 65535 ? quint16(port) : 0; |
| 143 | } | ||
| 144 |
3/3✓ Branch 73 → 74 taken 44 times.
✓ Branch 73 → 78 taken 61 times.
✓ Branch 74 → 75 taken 44 times.
|
105 | else if (field == QLatin1String("socketType")) socketType = reader.readElementText(); |
| 145 |
3/3✓ Branch 80 → 81 taken 44 times.
✓ Branch 80 → 85 taken 17 times.
✓ Branch 81 → 82 taken 44 times.
|
61 | else if (field == QLatin1String("username")) username = reader.readElementText(); |
| 146 | 193 | } | |
| 147 |
1/1✓ Branch 101 → 102 taken 44 times.
|
44 | server.security = security(socketType); |
| 148 |
1/1✓ Branch 104 → 105 taken 44 times.
|
44 | server.username = resolveUsername(username, address); |
| 149 |
6/6✓ Branch 108 → 109 taken 43 times.
✓ Branch 108 → 111 taken 1 time.
✓ Branch 110 → 111 taken 9 times.
✓ Branch 110 → 112 taken 34 times.
✓ Branch 113 → 114 taken 10 times.
✓ Branch 113 → 115 taken 34 times.
|
44 | if (!server.valid() || server.security.isEmpty()) continue; |
| 150 |
3/3✓ Branch 115 → 116 taken 17 times.
✓ Branch 115 → 117 taken 17 times.
✓ Branch 118 → 119 taken 34 times.
|
34 | (imap ? incoming : outgoing).append(server); |
| 151 | 722 | } | |
| 152 |
7/7✓ Branch 148 → 149 taken 17 times.
✓ Branch 149 → 150 taken 16 times.
✓ Branch 149 → 152 taken 1 time.
✓ Branch 151 → 152 taken 2 times.
✓ Branch 151 → 153 taken 14 times.
✓ Branch 154 → 155 taken 3 times.
✓ Branch 154 → 156 taken 14 times.
|
17 | if (reader.hasError() || incoming.isEmpty()) return {}; |
| 153 | // Implicit TLS first (RFC 8314), then STARTTLS. | ||
| 154 | 28 | const auto preferSsl = [](const QList<Server> &list) { | |
| 155 |
2/2✓ Branch 11 → 4 taken 29 times.
✓ Branch 11 → 12 taken 4 times.
|
33 | for (const auto &server : list) |
| 156 |
2/2✓ Branch 7 → 8 taken 24 times.
✓ Branch 7 → 9 taken 5 times.
|
29 | if (server.security == QLatin1String("ssl")) return server; |
| 157 |
1/2✗ Branch 13 → 15 not taken.
✓ Branch 13 → 16 taken 4 times.
|
4 | return list.isEmpty() ? Server{} : list.first(); |
| 158 | }; | ||
| 159 |
2/4✓ Branch 161 → 162 taken 14 times.
✓ Branch 161 → 163 taken 14 times.
✗ Branch 220 → 221 not taken.
✗ Branch 220 → 222 not taken.
|
28 | return {Result{preferSsl(incoming), preferSsl(outgoing), source, trusted}}; |
| 160 | 31 | } | |
| 161 | |||
| 162 | 25 | void MailServerDiscovery::start(const QString &address) { | |
| 163 | 25 | cancel(); | |
| 164 |
1/1✓ Branch 3 → 4 taken 25 times.
|
25 | m_address = address.trimmed(); |
| 165 |
2/2✓ Branch 8 → 9 taken 25 times.
✓ Branch 9 → 10 taken 25 times.
|
25 | m_domain = m_address.section('@', 1).toLower(); |
| 166 | 25 | m_results.clear(); | |
| 167 | 25 | m_best = {}; | |
| 168 |
2/4✓ Branch 23 → 24 taken 75 times.
✓ Branch 23 → 25 taken 25 times.
✗ Branch 53 → 54 not taken.
✗ Branch 53 → 55 not taken.
|
100 | m_sources = {{"srv", "pending"}, {"autoconfig", "pending"}, {"probe", "pending"}}; |
| 169 | 25 | m_running = true; | |
| 170 | 25 | const quint64 run = ++m_run; | |
| 171 |
2/5✓ Branch 26 → 27 taken 25 times.
✗ Branch 27 → 28 not taken.
✓ Branch 27 → 29 taken 25 times.
✗ Branch 63 → 64 not taken.
✗ Branch 63 → 65 not taken.
|
25 | m_owner = new QObject(this); |
| 172 | 25 | m_overall.start(m_overallMs); | |
| 173 |
5/5✓ Branch 30 → 31 taken 25 times.
✓ Branch 34 → 35 taken 25 times.
✓ Branch 35 → 36 taken 25 times.
✓ Branch 39 → 32 taken 25 times.
✓ Branch 39 → 40 taken 25 times.
|
50 | qCInfo(lcDiscovery) << "discovery started"; |
| 174 | 25 | emit sourcesChanged(); | |
| 175 | 25 | runSrv(run); | |
| 176 | 25 | runAutoconfig(run); | |
| 177 | 25 | runProbe(run); | |
| 178 | 50 | } | |
| 179 | |||
| 180 | 54 | void MailServerDiscovery::cancel() { | |
| 181 | 54 | m_running = false; | |
| 182 | 54 | m_overall.stop(); | |
| 183 | // Deferred: cancel() may run inside a callback of a request it owns. | ||
| 184 |
2/2✓ Branch 3 → 4 taken 9 times.
✓ Branch 3 → 5 taken 45 times.
|
54 | if (m_owner) m_owner->deleteLater(); |
| 185 | 54 | m_owner = nullptr; | |
| 186 | 54 | } | |
| 187 | |||
| 188 | 2 | void MailServerDiscovery::lookupIspdb() { | |
| 189 |
1/2✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 2 times.
|
2 | if (m_domain.isEmpty()) return; |
| 190 |
1/2✓ Branch 5 → 6 taken 2 times.
✗ Branch 5 → 15 not taken.
|
2 | if (!m_running) { |
| 191 | 2 | m_running = true; | |
| 192 |
2/12✓ Branch 6 → 7 taken 2 times.
✗ Branch 6 → 8 not taken.
✗ Branch 8 → 9 not taken.
✗ Branch 9 → 10 not taken.
✗ Branch 11 → 12 not taken.
✓ Branch 11 → 14 taken 2 times.
✗ Branch 12 → 13 not taken.
✗ Branch 12 → 14 not taken.
✗ Branch 58 → 59 not taken.
✗ Branch 58 → 61 not taken.
✗ Branch 59 → 60 not taken.
✗ Branch 59 → 61 not taken.
|
2 | m_owner = m_owner ? m_owner : new QObject(this); |
| 193 |
1/1✓ Branch 14 → 15 taken 2 times.
|
2 | m_overall.start(m_overallMs); |
| 194 | } | ||
| 195 | 2 | const quint64 run = m_run; | |
| 196 |
1/1✓ Branch 22 → 23 taken 2 times.
|
6 | m_sources.insert(QStringLiteral("ispdb"), QStringLiteral("pending")); |
| 197 |
1/1✓ Branch 28 → 29 taken 2 times.
|
2 | emit sourcesChanged(); |
| 198 |
5/5✓ Branch 29 → 30 taken 2 times.
✓ Branch 33 → 34 taken 2 times.
✓ Branch 34 → 35 taken 2 times.
✓ Branch 38 → 31 taken 2 times.
✓ Branch 38 → 39 taken 2 times.
|
4 | qCInfo(lcDiscovery) << "ISPDB lookup requested"; |
| 199 |
1/1✓ Branch 39 → 40 taken 2 times.
|
2 | QPointer<MailServerDiscovery> guard(this); |
| 200 |
3/3✓ Branch 45 → 46 taken 2 times.
✓ Branch 46 → 47 taken 2 times.
✓ Branch 47 → 48 taken 2 times.
|
4 | m_http(m_owner, QUrl(QStringLiteral("https://autoconfig.thunderbird.net/v1.1/") + m_domain), |
| 201 |
1/3✓ Branch 41 → 42 taken 2 times.
✗ Branch 98 → 99 not taken.
✗ Branch 98 → 100 not taken.
|
4 | [guard, run](int status, const QByteArray &body) { |
| 202 |
3/6✓ Branch 3 → 4 taken 2 times.
✗ Branch 3 → 7 not taken.
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 2 times.
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 2 times.
|
2 | if (!guard || !guard->current(run)) return; |
| 203 | 2 | QList<Result> results; | |
| 204 |
1/2✓ Branch 11 → 12 taken 2 times.
✗ Branch 11 → 39 not taken.
|
2 | if (status == 200) { |
| 205 |
1/1✓ Branch 16 → 17 taken 2 times.
|
2 | results = parseAutoconfig(body, guard->m_address, QStringLiteral("ispdb"), false); |
| 206 |
4/4✓ Branch 21 → 22 taken 2 times.
✓ Branch 22 → 23 taken 2 times.
✓ Branch 37 → 24 taken 2 times.
✓ Branch 37 → 38 taken 2 times.
|
4 | for (auto &result : results) |
| 207 |
3/3✓ Branch 26 → 27 taken 2 times.
✓ Branch 27 → 28 taken 1 time.
✓ Branch 27 → 34 taken 1 time.
|
3 | result.trusted = hostInDomain(result.imap.host, guard->m_domain) && |
| 208 |
3/5✓ Branch 29 → 30 taken 1 time.
✗ Branch 29 → 33 not taken.
✓ Branch 31 → 32 taken 1 time.
✓ Branch 32 → 33 taken 1 time.
✗ Branch 32 → 34 not taken.
|
1 | (!result.smtp.valid() || hostInDomain(result.smtp.host, guard->m_domain)); |
| 209 | } | ||
| 210 |
1/1✓ Branch 43 → 44 taken 2 times.
|
4 | guard->sourceDone(QStringLiteral("ispdb"), results); |
| 211 | 2 | }); | |
| 212 | 2 | } | |
| 213 | |||
| 214 | 25 | void MailServerDiscovery::runSrv(quint64 run) { | |
| 215 | struct State { | ||
| 216 | QList<SrvRecord> imaps, submissions, submission; | ||
| 217 | int pending = 3; | ||
| 218 | }; | ||
| 219 |
1/1✓ Branch 2 → 3 taken 25 times.
|
25 | auto state = std::make_shared<State>(); |
| 220 |
1/1✓ Branch 3 → 4 taken 25 times.
|
25 | QPointer<MailServerDiscovery> guard(this); |
| 221 | 69 | const auto first = [](QList<SrvRecord> records) { | |
| 222 |
3/4✓ Branch 3 → 4 taken 12 times.
✓ Branch 3 → 7 taken 1 time.
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 12 times.
|
82 | records.removeIf([](const SrvRecord &record) { return record.target.isEmpty() || record.target == QLatin1String("."); }); |
| 223 | 69 | std::sort(records.begin(), records.end(), [](const SrvRecord &a, const SrvRecord &b) { return a.priority < b.priority; }); | |
| 224 |
2/2✓ Branch 7 → 8 taken 57 times.
✓ Branch 7 → 9 taken 12 times.
|
69 | return records.isEmpty() ? SrvRecord{} : records.first(); |
| 225 | }; | ||
| 226 | 94 | const auto finish = [guard, run, state, first, this] { | |
| 227 |
6/8✓ Branch 3 → 4 taken 69 times.
✗ Branch 3 → 8 not taken.
✓ Branch 5 → 6 taken 69 times.
✗ Branch 5 → 8 not taken.
✓ Branch 7 → 8 taken 46 times.
✓ Branch 7 → 9 taken 23 times.
✓ Branch 10 → 11 taken 46 times.
✓ Branch 10 → 12 taken 23 times.
|
69 | if (!guard || !current(run) || --state->pending > 0) return; |
| 228 | 23 | Result result; | |
| 229 | 23 | result.source = QStringLiteral("srv"); | |
| 230 |
1/1✓ Branch 20 → 21 taken 23 times.
|
23 | const SrvRecord imap = first(state->imaps); |
| 231 |
2/2✓ Branch 23 → 24 taken 6 times.
✓ Branch 23 → 33 taken 17 times.
|
29 | if (!imap.target.isEmpty()) result.imap = {imap.target, imap.port, QStringLiteral("ssl"), m_address}; |
| 232 |
2/2✓ Branch 35 → 36 taken 23 times.
✓ Branch 39 → 40 taken 23 times.
|
23 | const SrvRecord smtps = first(state->submissions), smtp = first(state->submission); |
| 233 |
2/2✓ Branch 42 → 43 taken 3 times.
✓ Branch 42 → 52 taken 20 times.
|
26 | if (!smtps.target.isEmpty()) result.smtp = {smtps.target, smtps.port, QStringLiteral("ssl"), m_address}; |
| 234 |
2/2✓ Branch 53 → 54 taken 3 times.
✓ Branch 53 → 63 taken 17 times.
|
23 | else if (!smtp.target.isEmpty()) result.smtp = {smtp.target, smtp.port, QStringLiteral("starttls"), m_address}; |
| 235 |
3/3✓ Branch 63 → 64 taken 23 times.
✓ Branch 64 → 65 taken 4 times.
✓ Branch 64 → 70 taken 19 times.
|
27 | result.trusted = hostInDomain(result.imap.host, m_domain) && |
| 236 |
3/5✓ Branch 66 → 67 taken 4 times.
✗ Branch 66 → 69 not taken.
✓ Branch 67 → 68 taken 4 times.
✓ Branch 68 → 69 taken 4 times.
✗ Branch 68 → 70 not taken.
|
4 | (!result.smtp.valid() || hostInDomain(result.smtp.host, m_domain)); |
| 237 |
7/11✓ Branch 72 → 73 taken 6 times.
✓ Branch 72 → 75 taken 17 times.
✓ Branch 79 → 80 taken 23 times.
✓ Branch 83 → 84 taken 6 times.
✓ Branch 83 → 87 taken 17 times.
✓ Branch 85 → 86 taken 6 times.
✓ Branch 85 → 87 taken 6 times.
✗ Branch 111 → 112 not taken.
✗ Branch 111 → 115 not taken.
✗ Branch 113 → 114 not taken.
✗ Branch 113 → 115 not taken.
|
52 | sourceDone(QStringLiteral("srv"), result.imap.valid() ? QList<Result>{result} : QList<Result>{}); |
| 238 |
1/7✓ Branch 74 → 76 taken 6 times.
✗ Branch 117 → 118 not taken.
✗ Branch 117 → 122 not taken.
✗ Branch 118 → 119 not taken.
✗ Branch 118 → 122 not taken.
✗ Branch 120 → 121 not taken.
✗ Branch 120 → 122 not taken.
|
78 | }; |
| 239 |
3/5✓ Branch 8 → 9 taken 25 times.
✓ Branch 12 → 13 taken 25 times.
✓ Branch 13 → 14 taken 25 times.
✗ Branch 65 → 66 not taken.
✗ Branch 65 → 67 not taken.
|
73 | m_srv(m_owner, QStringLiteral("_imaps._tcp.") + m_domain, [state, finish](QList<SrvRecord> r) { state->imaps = r; finish(); }); |
| 240 |
2/2✓ Branch 25 → 26 taken 25 times.
✓ Branch 26 → 27 taken 25 times.
|
50 | m_srv(m_owner, QStringLiteral("_submissions._tcp.") + m_domain, |
| 241 |
1/3✓ Branch 21 → 22 taken 25 times.
✗ Branch 83 → 84 not taken.
✗ Branch 83 → 85 not taken.
|
73 | [state, finish](QList<SrvRecord> r) { state->submissions = r; finish(); }); |
| 242 |
2/2✓ Branch 38 → 39 taken 25 times.
✓ Branch 39 → 40 taken 25 times.
|
50 | m_srv(m_owner, QStringLiteral("_submission._tcp.") + m_domain, |
| 243 |
1/3✓ Branch 34 → 35 taken 25 times.
✗ Branch 101 → 102 not taken.
✗ Branch 101 → 103 not taken.
|
73 | [state, finish](QList<SrvRecord> r) { state->submission = r; finish(); }); |
| 244 |
1/3✓ Branch 46 → 47 taken 25 times.
✗ Branch 108 → 109 not taken.
✗ Branch 108 → 110 not taken.
|
25 | QTimer::singleShot(m_sourceMs, m_owner, [guard, run, this] { |
| 245 |
13/29✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 14 not taken.
✓ Branch 5 → 6 taken 1 time.
✗ Branch 5 → 14 not taken.
✓ Branch 7 → 8 taken 1 time.
✓ Branch 9 → 10 taken 1 time.
✓ Branch 10 → 11 taken 1 time.
✓ Branch 11 → 12 taken 1 time.
✓ Branch 12 → 13 taken 1 time.
✗ Branch 12 → 14 not taken.
✓ Branch 15 → 16 taken 1 time.
✗ Branch 15 → 17 not taken.
✓ Branch 17 → 18 taken 1 time.
✗ Branch 17 → 19 not taken.
✓ Branch 19 → 20 taken 1 time.
✗ Branch 19 → 21 not taken.
✓ Branch 21 → 22 taken 1 time.
✗ Branch 21 → 23 not taken.
✓ Branch 23 → 24 taken 1 time.
✗ Branch 23 → 33 not taken.
✓ Branch 28 → 29 taken 1 time.
✗ Branch 34 → 35 not taken.
✗ Branch 34 → 36 not taken.
✗ Branch 38 → 39 not taken.
✗ Branch 38 → 40 not taken.
✗ Branch 42 → 43 not taken.
✗ Branch 42 → 44 not taken.
✗ Branch 46 → 47 not taken.
✗ Branch 46 → 48 not taken.
|
2 | if (guard && current(run) && m_sources.value("srv") == QLatin1String("pending")) sourceDone(QStringLiteral("srv"), {}); |
| 246 | 1 | }); | |
| 247 | 25 | } | |
| 248 | |||
| 249 | 25 | void MailServerDiscovery::runAutoconfig(quint64 run) { | |
| 250 | const QList<QUrl> urls = { | ||
| 251 | 50 | QUrl(QStringLiteral("https://autoconfig.%1/mail/config-v1.1.xml?emailaddress=%2") | |
| 252 |
3/3✓ Branch 7 → 8 taken 25 times.
✓ Branch 8 → 9 taken 25 times.
✓ Branch 9 → 10 taken 25 times.
|
50 | .arg(m_domain, QString::fromUtf8(QUrl::toPercentEncoding(m_address)))), |
| 253 |
3/5✓ Branch 15 → 16 taken 25 times.
✓ Branch 19 → 20 taken 50 times.
✓ Branch 19 → 21 taken 25 times.
✗ Branch 57 → 58 not taken.
✗ Branch 57 → 59 not taken.
|
125 | QUrl(QStringLiteral("https://%1/.well-known/autoconfig/mail/config-v1.1.xml").arg(m_domain))}; |
| 254 |
1/1✓ Branch 32 → 33 taken 25 times.
|
25 | auto pending = std::make_shared<int>(int(urls.size())); |
| 255 |
1/1✓ Branch 33 → 34 taken 25 times.
|
25 | auto found = std::make_shared<bool>(false); |
| 256 |
1/1✓ Branch 34 → 35 taken 25 times.
|
25 | QPointer<MailServerDiscovery> guard(this); |
| 257 |
2/2✓ Branch 47 → 37 taken 50 times.
✓ Branch 47 → 48 taken 25 times.
|
75 | for (const auto &url : urls) { |
| 258 |
2/8✓ Branch 41 → 42 taken 50 times.
✓ Branch 42 → 43 taken 50 times.
✗ Branch 103 → 104 not taken.
✗ Branch 103 → 105 not taken.
✗ Branch 106 → 107 not taken.
✗ Branch 106 → 108 not taken.
✗ Branch 109 → 110 not taken.
✗ Branch 109 → 111 not taken.
|
50 | m_http(m_owner, url, [guard, run, pending, found, this](int status, const QByteArray &body) { |
| 259 |
6/8✓ Branch 3 → 4 taken 46 times.
✗ Branch 3 → 8 not taken.
✓ Branch 5 → 6 taken 36 times.
✓ Branch 5 → 8 taken 10 times.
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 36 times.
✓ Branch 10 → 11 taken 10 times.
✓ Branch 10 → 12 taken 36 times.
|
46 | if (!guard || !current(run) || *found) return; |
| 260 |
4/8✓ Branch 18 → 19 taken 10 times.
✓ Branch 18 → 20 taken 26 times.
✓ Branch 20 → 21 taken 10 times.
✓ Branch 20 → 22 taken 26 times.
✗ Branch 44 → 45 not taken.
✗ Branch 44 → 46 not taken.
✗ Branch 48 → 49 not taken.
✗ Branch 48 → 50 not taken.
|
46 | const auto results = status == 200 ? parseAutoconfig(body, m_address, QStringLiteral("autoconfig"), true) |
| 261 |
3/3✓ Branch 12 → 13 taken 10 times.
✓ Branch 12 → 17 taken 26 times.
✓ Branch 16 → 18 taken 10 times.
|
46 | : QList<Result>{}; |
| 262 |
2/2✓ Branch 23 → 24 taken 10 times.
✓ Branch 23 → 26 taken 26 times.
|
36 | if (!results.isEmpty()) *found = true; |
| 263 |
7/7✓ Branch 27 → 28 taken 26 times.
✓ Branch 27 → 30 taken 10 times.
✓ Branch 29 → 30 taken 13 times.
✓ Branch 29 → 31 taken 13 times.
✓ Branch 32 → 33 taken 23 times.
✓ Branch 32 → 40 taken 13 times.
✓ Branch 36 → 37 taken 23 times.
|
59 | if (!results.isEmpty() || --*pending == 0) sourceDone(QStringLiteral("autoconfig"), results); |
| 264 | 36 | }); | |
| 265 | } | ||
| 266 |
1/3✓ Branch 49 → 50 taken 25 times.
✗ Branch 117 → 118 not taken.
✗ Branch 117 → 119 not taken.
|
25 | QTimer::singleShot(m_sourceMs, m_owner, [guard, run, this] { |
| 267 |
12/28✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 14 not taken.
✓ Branch 5 → 6 taken 1 time.
✗ Branch 5 → 14 not taken.
✓ Branch 7 → 8 taken 1 time.
✓ Branch 9 → 10 taken 1 time.
✓ Branch 10 → 11 taken 1 time.
✓ Branch 11 → 12 taken 1 time.
✓ Branch 12 → 13 taken 1 time.
✗ Branch 12 → 14 not taken.
✓ Branch 15 → 16 taken 1 time.
✗ Branch 15 → 17 not taken.
✓ Branch 17 → 18 taken 1 time.
✗ Branch 17 → 19 not taken.
✓ Branch 19 → 20 taken 1 time.
✗ Branch 19 → 21 not taken.
✓ Branch 21 → 22 taken 1 time.
✗ Branch 21 → 23 not taken.
✓ Branch 23 → 24 taken 1 time.
✗ Branch 23 → 33 not taken.
✗ Branch 34 → 35 not taken.
✗ Branch 34 → 36 not taken.
✗ Branch 38 → 39 not taken.
✗ Branch 38 → 40 not taken.
✗ Branch 42 → 43 not taken.
✗ Branch 42 → 44 not taken.
✗ Branch 46 → 47 not taken.
✗ Branch 46 → 48 not taken.
|
1 | if (guard && current(run) && m_sources.value("autoconfig") == QLatin1String("pending")) |
| 268 |
1/1✓ Branch 28 → 29 taken 1 time.
|
2 | sourceDone(QStringLiteral("autoconfig"), {}); |
| 269 | 1 | }); | |
| 270 | 100 | } | |
| 271 | |||
| 272 | 25 | void MailServerDiscovery::runProbe(quint64 run) { | |
| 273 | struct State { | ||
| 274 | QString imap, smtp; | ||
| 275 | int pending = 4; | ||
| 276 | }; | ||
| 277 |
1/1✓ Branch 2 → 3 taken 25 times.
|
25 | auto state = std::make_shared<State>(); |
| 278 |
1/1✓ Branch 3 → 4 taken 25 times.
|
25 | QPointer<MailServerDiscovery> guard(this); |
| 279 | 92 | const auto finish = [guard, run, state, this] { | |
| 280 |
7/8✓ Branch 3 → 4 taken 92 times.
✗ Branch 3 → 8 not taken.
✓ Branch 5 → 6 taken 48 times.
✓ Branch 5 → 8 taken 44 times.
✓ Branch 7 → 8 taken 36 times.
✓ Branch 7 → 9 taken 12 times.
✓ Branch 10 → 11 taken 80 times.
✓ Branch 10 → 12 taken 12 times.
|
92 | if (!guard || !current(run) || --state->pending > 0) return; |
| 281 | 12 | Result result; | |
| 282 | 12 | result.source = QStringLiteral("probe"); | |
| 283 | 12 | result.trusted = true; // the names are built from the address domain | |
| 284 |
2/2✓ Branch 20 → 21 taken 7 times.
✓ Branch 20 → 31 taken 5 times.
|
19 | if (!state->imap.isEmpty()) result.imap = {state->imap, 993, QStringLiteral("ssl"), m_address}; |
| 285 |
2/2✓ Branch 33 → 34 taken 3 times.
✓ Branch 33 → 44 taken 9 times.
|
15 | if (!state->smtp.isEmpty()) result.smtp = {state->smtp, 465, QStringLiteral("ssl"), m_address}; |
| 286 |
7/11✓ Branch 45 → 46 taken 7 times.
✓ Branch 45 → 48 taken 5 times.
✓ Branch 52 → 53 taken 12 times.
✓ Branch 56 → 57 taken 7 times.
✓ Branch 56 → 60 taken 5 times.
✓ Branch 58 → 59 taken 7 times.
✓ Branch 58 → 60 taken 7 times.
✗ Branch 72 → 73 not taken.
✗ Branch 72 → 76 not taken.
✗ Branch 74 → 75 not taken.
✗ Branch 74 → 76 not taken.
|
31 | sourceDone(QStringLiteral("probe"), result.imap.valid() ? QList<Result>{result} : QList<Result>{}); |
| 287 |
1/7✓ Branch 47 → 49 taken 7 times.
✗ Branch 78 → 79 not taken.
✗ Branch 78 → 83 not taken.
✗ Branch 79 → 80 not taken.
✗ Branch 79 → 83 not taken.
✗ Branch 81 → 82 not taken.
✗ Branch 81 → 83 not taken.
|
64 | }; |
| 288 | // Earlier names win: imap. before mail., smtp. before mail. | ||
| 289 | 100 | const auto probe = [this, state, finish](const QString &host, quint16 port, bool incoming, bool preferred) { | |
| 290 |
2/8✓ Branch 5 → 6 taken 100 times.
✓ Branch 6 → 7 taken 100 times.
✗ Branch 14 → 15 not taken.
✗ Branch 14 → 16 not taken.
✗ Branch 17 → 18 not taken.
✗ Branch 17 → 19 not taken.
✗ Branch 20 → 21 not taken.
✗ Branch 20 → 22 not taken.
|
100 | m_tls(m_owner, host, port, [state, finish, host, incoming, preferred](bool ok) { |
| 291 |
2/2✓ Branch 2 → 3 taken 46 times.
✓ Branch 2 → 5 taken 46 times.
|
92 | QString &slot = incoming ? state->imap : state->smtp; |
| 292 |
7/8✓ Branch 7 → 8 taken 19 times.
✓ Branch 7 → 12 taken 73 times.
✓ Branch 9 → 10 taken 1 time.
✓ Branch 9 → 11 taken 18 times.
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 1 time.
✓ Branch 13 → 14 taken 18 times.
✓ Branch 13 → 15 taken 74 times.
|
92 | if (ok && (slot.isEmpty() || preferred)) slot = host; |
| 293 | 92 | finish(); | |
| 294 | 92 | }); | |
| 295 | 125 | }; | |
| 296 |
2/2✓ Branch 11 → 12 taken 25 times.
✓ Branch 12 → 13 taken 25 times.
|
50 | probe(QStringLiteral("imap.") + m_domain, 993, true, true); |
| 297 |
2/2✓ Branch 19 → 20 taken 25 times.
✓ Branch 20 → 21 taken 25 times.
|
50 | probe(QStringLiteral("mail.") + m_domain, 993, true, false); |
| 298 |
2/2✓ Branch 27 → 28 taken 25 times.
✓ Branch 28 → 29 taken 25 times.
|
50 | probe(QStringLiteral("smtp.") + m_domain, 465, false, true); |
| 299 |
2/2✓ Branch 35 → 36 taken 25 times.
✓ Branch 36 → 37 taken 25 times.
|
50 | probe(QStringLiteral("mail.") + m_domain, 465, false, false); |
| 300 |
1/3✓ Branch 41 → 42 taken 25 times.
✗ Branch 86 → 87 not taken.
✗ Branch 86 → 88 not taken.
|
25 | QTimer::singleShot(m_sourceMs, m_owner, [guard, run, this] { |
| 301 |
13/29✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 14 not taken.
✓ Branch 5 → 6 taken 1 time.
✗ Branch 5 → 14 not taken.
✓ Branch 7 → 8 taken 1 time.
✓ Branch 9 → 10 taken 1 time.
✓ Branch 10 → 11 taken 1 time.
✓ Branch 11 → 12 taken 1 time.
✓ Branch 12 → 13 taken 1 time.
✗ Branch 12 → 14 not taken.
✓ Branch 15 → 16 taken 1 time.
✗ Branch 15 → 17 not taken.
✓ Branch 17 → 18 taken 1 time.
✗ Branch 17 → 19 not taken.
✓ Branch 19 → 20 taken 1 time.
✗ Branch 19 → 21 not taken.
✓ Branch 21 → 22 taken 1 time.
✗ Branch 21 → 23 not taken.
✓ Branch 23 → 24 taken 1 time.
✗ Branch 23 → 33 not taken.
✓ Branch 28 → 29 taken 1 time.
✗ Branch 34 → 35 not taken.
✗ Branch 34 → 36 not taken.
✗ Branch 38 → 39 not taken.
✗ Branch 38 → 40 not taken.
✗ Branch 42 → 43 not taken.
✗ Branch 42 → 44 not taken.
✗ Branch 46 → 47 not taken.
✗ Branch 46 → 48 not taken.
|
2 | if (guard && current(run) && m_sources.value("probe") == QLatin1String("pending")) sourceDone(QStringLiteral("probe"), {}); |
| 302 | 1 | }); | |
| 303 | 25 | } | |
| 304 | |||
| 305 | 63 | void MailServerDiscovery::sourceDone(const QString &source, const QList<Result> &results) { | |
| 306 |
4/5✓ Branch 3 → 4 taken 63 times.
✓ Branch 5 → 6 taken 63 times.
✓ Branch 6 → 7 taken 63 times.
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 63 times.
|
63 | if (m_sources.value(source) != QLatin1String("pending")) return; |
| 307 |
7/11✓ Branch 13 → 14 taken 38 times.
✓ Branch 13 → 17 taken 25 times.
✓ Branch 21 → 22 taken 63 times.
✓ Branch 24 → 25 taken 25 times.
✓ Branch 24 → 26 taken 38 times.
✓ Branch 26 → 27 taken 38 times.
✓ Branch 26 → 28 taken 25 times.
✗ Branch 78 → 79 not taken.
✗ Branch 78 → 80 not taken.
✗ Branch 82 → 83 not taken.
✗ Branch 82 → 84 not taken.
|
126 | m_sources.insert(source, results.isEmpty() ? QStringLiteral("none") : QStringLiteral("found")); |
| 308 | 63 | m_results += results; | |
| 309 |
4/4✓ Branch 29 → 30 taken 63 times.
✓ Branch 30 → 31 taken 63 times.
✓ Branch 44 → 32 taken 35 times.
✓ Branch 44 → 45 taken 63 times.
|
98 | for (const auto &result : m_results) |
| 310 |
8/8✓ Branch 34 → 35 taken 15 times.
✓ Branch 34 → 38 taken 20 times.
✓ Branch 35 → 36 taken 15 times.
✓ Branch 36 → 37 taken 15 times.
✓ Branch 37 → 38 taken 5 times.
✓ Branch 37 → 39 taken 10 times.
✓ Branch 40 → 41 taken 25 times.
✓ Branch 40 → 42 taken 10 times.
|
35 | if (!m_best.imap.valid() || rank(result) > rank(m_best)) m_best = result; |
| 311 |
9/9✓ Branch 45 → 46 taken 63 times.
✓ Branch 49 → 50 taken 63 times.
✓ Branch 50 → 51 taken 63 times.
✓ Branch 51 → 52 taken 63 times.
✓ Branch 53 → 54 taken 38 times.
✓ Branch 53 → 55 taken 25 times.
✓ Branch 56 → 57 taken 63 times.
✓ Branch 60 → 47 taken 63 times.
✓ Branch 60 → 61 taken 63 times.
|
126 | qCInfo(lcDiscovery) << "discovery source" << source << (results.isEmpty() ? "none" : "found"); |
| 312 | 63 | emit sourcesChanged(); | |
| 313 | 63 | finishIfDone(); | |
| 314 | } | ||
| 315 | |||
| 316 | 63 | void MailServerDiscovery::finishIfDone() { | |
| 317 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 63 times.
|
63 | if (!m_running) return; |
| 318 | 63 | const bool allDone = std::none_of(m_sources.cbegin(), m_sources.cend(), | |
| 319 |
2/2✓ Branch 3 → 4 taken 119 times.
✓ Branch 4 → 5 taken 119 times.
|
119 | [](const QVariant &state) { return state == QLatin1String("pending"); }); |
| 320 | // The first trusted, complete answer from the provider itself ends early; | ||
| 321 | // SRV waits for the provider's autoconfig, which names the preferred ports. | ||
| 322 |
3/3✓ Branch 8 → 9 taken 63 times.
✓ Branch 13 → 14 taken 63 times.
✓ Branch 14 → 15 taken 63 times.
|
126 | const bool autoconfigDone = m_sources.value(QStringLiteral("autoconfig")) != QLatin1String("pending"); |
| 323 |
6/6✓ Branch 21 → 22 taken 26 times.
✓ Branch 21 → 31 taken 37 times.
✓ Branch 22 → 23 taken 19 times.
✓ Branch 22 → 31 taken 7 times.
✓ Branch 25 → 26 taken 9 times.
✓ Branch 25 → 30 taken 10 times.
|
91 | const bool early = m_best.complete() && m_best.trusted && |
| 324 |
2/2✓ Branch 28 → 29 taken 5 times.
✓ Branch 28 → 31 taken 4 times.
|
28 | (m_best.source == QLatin1String("autoconfig") || |
| 325 |
2/2✓ Branch 29 → 30 taken 1 time.
✓ Branch 29 → 31 taken 4 times.
|
14 | (m_best.source == QLatin1String("srv") && autoconfigDone)); |
| 326 |
4/4✓ Branch 32 → 33 taken 48 times.
✓ Branch 32 → 35 taken 15 times.
✓ Branch 33 → 34 taken 37 times.
✓ Branch 33 → 35 taken 11 times.
|
63 | if (!allDone && !early) return; |
| 327 | 26 | m_running = false; | |
| 328 | 26 | m_overall.stop(); | |
| 329 |
8/8✓ Branch 36 → 37 taken 26 times.
✓ Branch 40 → 41 taken 26 times.
✓ Branch 41 → 42 taken 26 times.
✓ Branch 42 → 43 taken 26 times.
✓ Branch 43 → 44 taken 26 times.
✓ Branch 44 → 45 taken 26 times.
✓ Branch 48 → 38 taken 26 times.
✓ Branch 48 → 49 taken 26 times.
|
52 | qCInfo(lcDiscovery) << "discovery finished, source" << m_best.source << "trusted" << m_best.trusted; |
| 330 | 26 | emit finished(m_best.imap.valid()); | |
| 331 | } | ||
| 332 |