MailJDTourDownloadDocsQualityTestsCoverage

Which source lines and branches the tests execute. Lines 91.5 %, branches 75.0 % (minimum 85 % and 72 %). main @ 1ccc50e9 · 21 October 2026 · pipeline 7246.

GCC Code Coverage Report


Directory: src/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 84.4% 206 / 0 / 244
Functions: 95.2% 20 / 0 / 21
Branches: 78.6% 217 / 0 / 276

service/MailLoginProbe.cpp
Line Branch Exec Source
1 #include "MailLoginProbe.h"
2 #include <QLoggingCategory>
3
4
4/7
✓ Branch 2 → 3 taken 2 times.
✓ Branch 2 → 8 taken 64 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.
66 Q_LOGGING_CATEGORY(lcLoginProbe, "mailjd.settings.probe")
5
6 namespace {
7 // IMAP quoted string (RFC 3501): backslash and quote escaped.
8 22 QByteArray quoted(const QByteArray &value) {
9 22 QByteArray result = value;
10
2/2
✓ Branch 4 → 5 taken 22 times.
✓ Branch 6 → 7 taken 22 times.
22 result.replace('\\', "\\\\").replace('"', "\\\"");
11
2/2
✓ Branch 7 → 8 taken 22 times.
✓ Branch 8 → 9 taken 22 times.
44 return '"' + result + '"';
12 22 }
13 3 bool imapRateLimited(const QByteArray &line) {
14
1/1
✓ Branch 2 → 3 taken 3 times.
3 const QByteArray upper = line.toUpper();
15
4/6
✓ Branch 5 → 6 taken 2 times.
✓ Branch 5 → 12 taken 1 time.
✓ Branch 8 → 9 taken 2 times.
✗ Branch 8 → 12 not taken.
✗ Branch 11 → 12 not taken.
✓ Branch 11 → 13 taken 2 times.
6 return upper.contains("[UNAVAILABLE]") || upper.contains("TOO MANY") || upper.contains("[LIMIT]");
16 3 }
17 } // namespace
18
19
3/3
✓ Branch 3 → 4 taken 33 times.
✓ Branch 4 → 5 taken 33 times.
✓ Branch 5 → 6 taken 33 times.
33 MailLoginProbe::MailLoginProbe(QObject *parent) : QObject(parent) {
20
1/1
✓ Branch 9 → 10 taken 33 times.
33 m_deadline.setSingleShot(true);
21
1/1
✓ Branch 10 → 11 taken 33 times.
33 connect(&m_deadline, &QTimer::timeout, this, [this] {
22 ✗ auto input = baseInput();
23 ✗ input.socketFailed = true;
24 ✗ input.socketError = QAbstractSocket::SocketTimeoutError;
25 ✗ fail(input);
26 ✗ });
27
1/1
✓ Branch 12 → 13 taken 33 times.
33 connect(&m_socket, &QSslSocket::readyRead, this, &MailLoginProbe::readLines);
28
1/1
✓ Branch 14 → 15 taken 33 times.
33 connect(&m_socket, &QSslSocket::encrypted, this, &MailLoginProbe::encrypted);
29
1/1
✓ Branch 16 → 17 taken 33 times.
33 connect(&m_socket, &QSslSocket::sslErrors, this, [this](const QList<QSslError> &errors) {
30 // Never ignored: a certificate problem ends the check with its details
31 // (D-24: no "trust anyway").
32 2 m_sslErrors = errors;
33 2 });
34
1/1
✓ Branch 18 → 19 taken 33 times.
33 connect(&m_socket, &QSslSocket::errorOccurred, this, [this](QAbstractSocket::SocketError error) {
35
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 3 times.
3 if (!m_running) return;
36 3 auto input = baseInput();
37 3 input.sslErrors = m_sslErrors;
38 3 input.socketFailed = true;
39 3 input.socketError = error;
40
1/1
✓ Branch 6 → 7 taken 3 times.
3 input.serverText = m_socket.errorString();
41
1/1
✓ Branch 10 → 11 taken 3 times.
3 fail(input);
42 3 });
43 33 }
44
45 114 ConnectionDiagnosis::Input MailLoginProbe::baseInput() const {
46 114 ConnectionDiagnosis::Input input;
47 114 input.service = m_request.service;
48 114 input.host = m_request.host;
49 114 input.port = m_request.port;
50 114 input.account = m_request.account;
51 114 return input;
52 }
53
54 33 void MailLoginProbe::start(const Request &request) {
55 33 cancel();
56 33 m_request = request;
57 33 m_step = Step::Greeting;
58 33 m_sslErrors.clear();
59 33 m_capabilities.clear();
60 33 m_tls = false;
61 33 m_running = true;
62 33 m_socket.setSslConfiguration(m_sslConfiguration);
63 33 m_socket.setPeerVerifyName(request.host);
64 33 m_deadline.start(m_timeoutMs);
65
9/9
✓ Branch 9 → 10 taken 33 times.
✓ Branch 13 → 14 taken 33 times.
✓ Branch 14 → 15 taken 33 times.
✓ Branch 15 → 16 taken 33 times.
✓ Branch 16 → 17 taken 33 times.
✓ Branch 17 → 18 taken 33 times.
✓ Branch 18 → 19 taken 33 times.
✓ Branch 22 → 11 taken 33 times.
✓ Branch 22 → 23 taken 33 times.
66 qCDebug(lcLoginProbe) << "login check" << request.service << request.host << request.port << request.security;
66
2/2
✓ Branch 25 → 26 taken 31 times.
✓ Branch 25 → 29 taken 2 times.
33 if (request.security == QLatin1String("ssl")) {
67 31 m_tls = true;
68
1/1
✓ Branch 27 → 28 taken 31 times.
31 m_socket.connectToHostEncrypted(request.host, request.port);
69 } else {
70
1/1
✓ Branch 30 → 31 taken 2 times.
2 m_socket.connectToHost(request.host, request.port);
71 }
72 33 }
73
74 33 void MailLoginProbe::cancel() {
75 33 m_running = false;
76 33 m_deadline.stop();
77 33 m_socket.abort();
78 33 }
79
80
2/2
✓ Branch 2 → 3 taken 74 times.
✓ Branch 3 → 4 taken 74 times.
74 void MailLoginProbe::send(const QByteArray &line) { m_socket.write(line + "\r\n"); }
81
82 18 void MailLoginProbe::fail(ConnectionDiagnosis::Input input) {
83
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 18 times.
18 if (!m_running) return;
84 18 m_running = false;
85
1/1
✓ Branch 4 → 5 taken 18 times.
18 m_deadline.stop();
86
1/1
✓ Branch 5 → 6 taken 18 times.
18 m_socket.abort();
87
1/1
✓ Branch 6 → 7 taken 18 times.
18 m_request.password.fill('\0');
88
1/1
✓ Branch 7 → 8 taken 18 times.
18 const Diagnosis diagnosis = ConnectionDiagnosis::diagnose(input);
89
8/8
✓ Branch 8 → 9 taken 18 times.
✓ Branch 12 → 13 taken 18 times.
✓ Branch 13 → 14 taken 18 times.
✓ Branch 14 → 15 taken 18 times.
✓ Branch 15 → 16 taken 18 times.
✓ Branch 16 → 17 taken 18 times.
✓ Branch 20 → 10 taken 18 times.
✓ Branch 20 → 21 taken 18 times.
36 qCInfo(lcLoginProbe) << "login check" << m_request.service << "failed:" << diagnosis.kind;
90
1/1
✓ Branch 21 → 22 taken 18 times.
18 emit finished(diagnosis);
91 18 }
92
93 15 void MailLoginProbe::succeed() {
94
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 15 times.
15 if (!m_running) return;
95 15 m_running = false;
96 15 m_deadline.stop();
97 15 m_request.password.fill('\0');
98 15 m_socket.disconnectFromHost();
99
7/7
✓ Branch 7 → 8 taken 15 times.
✓ Branch 11 → 12 taken 15 times.
✓ Branch 12 → 13 taken 15 times.
✓ Branch 13 → 14 taken 15 times.
✓ Branch 14 → 15 taken 15 times.
✓ Branch 18 → 9 taken 15 times.
✓ Branch 18 → 19 taken 15 times.
30 qCInfo(lcLoginProbe) << "login check" << m_request.service << "succeeded";
100
2/2
✓ Branch 19 → 20 taken 15 times.
✓ Branch 20 → 21 taken 15 times.
15 emit finished(ConnectionDiagnosis::success(m_request.service));
101 }
102
103 28 void MailLoginProbe::encrypted() {
104
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 28 times.
28 if (!m_running) return;
105 28 m_tls = true;
106 // Implicit TLS waits for the greeting; after STARTTLS the dialogue goes on.
107
1/2
✓ Branch 6 → 7 taken 28 times.
✗ Branch 6 → 8 not taken.
28 if (m_request.security != QLatin1String("starttls")) return;
108 ✗ if (m_request.service == QLatin1String("imap")) imapLogin();
109 ✗ else smtpHello();
110 }
111
112 89 void MailLoginProbe::readLines() {
113
6/6
✓ Branch 13 → 14 taken 168 times.
✓ Branch 13 → 17 taken 30 times.
✓ Branch 15 → 16 taken 109 times.
✓ Branch 15 → 17 taken 59 times.
✓ Branch 18 → 3 taken 109 times.
✓ Branch 18 → 19 taken 89 times.
198 while (m_running && m_socket.canReadLine()) {
114
2/2
✓ Branch 3 → 4 taken 109 times.
✓ Branch 4 → 5 taken 109 times.
109 const QByteArray line = m_socket.readLine(4096).trimmed();
115
3/3
✓ Branch 8 → 9 taken 26 times.
✓ Branch 8 → 10 taken 83 times.
✓ Branch 9 → 11 taken 26 times.
109 if (m_request.service == QLatin1String("imap")) handleImap(line);
116
1/1
✓ Branch 10 → 11 taken 83 times.
83 else handleSmtp(line);
117 109 }
118 89 }
119
120 // S106-202: the username goes into an IMAP quoted string and raw SMTP
121 // MAIL FROM/RCPT TO lines — a CR, LF or NUL in it (an autoconfig answer)
122 // would inject a command, like one in the password.
123 39 static bool breaksALine(const QByteArray &value) {
124
4/6
✓ Branch 3 → 4 taken 37 times.
✓ Branch 3 → 8 taken 2 times.
✓ Branch 5 → 6 taken 37 times.
✗ Branch 5 → 8 not taken.
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 37 times.
39 return value.contains('\r') || value.contains('\n') || value.contains('\0');
125 }
126
127 12 void MailLoginProbe::imapLogin() {
128
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 12 times.
12 if (!m_tls) return; // never a password over plain text
129
9/13
✓ Branch 4 → 5 taken 12 times.
✓ Branch 5 → 6 taken 12 times.
✗ Branch 5 → 9 not taken.
✓ Branch 6 → 7 taken 12 times.
✓ Branch 7 → 8 taken 12 times.
✓ Branch 8 → 9 taken 1 time.
✓ Branch 8 → 10 taken 11 times.
✓ Branch 11 → 12 taken 12 times.
✗ Branch 11 → 13 not taken.
✓ Branch 13 → 14 taken 1 time.
✓ Branch 13 → 20 taken 11 times.
✗ Branch 35 → 36 not taken.
✗ Branch 35 → 37 not taken.
12 if (breaksALine(m_request.password) || breaksALine(m_request.username.toUtf8())) {
130 1 auto input = baseInput();
131 1 input.authRejected = true;
132
1/1
✓ Branch 16 → 17 taken 1 time.
1 fail(input);
133 1 return;
134 1 }
135 11 m_step = Step::Login;
136
7/7
✓ Branch 20 → 21 taken 11 times.
✓ Branch 21 → 22 taken 11 times.
✓ Branch 22 → 23 taken 11 times.
✓ Branch 23 → 24 taken 11 times.
✓ Branch 24 → 25 taken 11 times.
✓ Branch 25 → 26 taken 11 times.
✓ Branch 26 → 27 taken 11 times.
11 send("A1 LOGIN " + quoted(m_request.username.toUtf8()) + ' ' + quoted(m_request.password));
137 }
138
139 26 void MailLoginProbe::handleImap(const QByteArray &line) {
140 26 auto input = baseInput();
141
2/2
✓ Branch 3 → 4 taken 26 times.
✓ Branch 4 → 5 taken 26 times.
26 input.serverText = QString::fromUtf8(line.left(300));
142
2/2
✓ Branch 8 → 9 taken 14 times.
✓ Branch 8 → 31 taken 12 times.
26 if (m_step == Step::Greeting) {
143
5/6
✓ Branch 11 → 12 taken 1 time.
✓ Branch 11 → 16 taken 13 times.
✓ Branch 14 → 15 taken 1 time.
✗ Branch 14 → 16 not taken.
✓ Branch 17 → 18 taken 1 time.
✓ Branch 17 → 22 taken 13 times.
14 if (!line.startsWith("* OK") && !line.startsWith("* PREAUTH")) {
144 1 input.protocolMismatch = true;
145
1/1
✓ Branch 19 → 20 taken 1 time.
1 fail(input);
146 1 return;
147 }
148
2/2
✓ Branch 24 → 25 taken 1 time.
✓ Branch 24 → 29 taken 12 times.
13 if (m_request.security == QLatin1String("starttls")) {
149 1 m_step = Step::StartTls;
150
2/2
✓ Branch 25 → 26 taken 1 time.
✓ Branch 26 → 27 taken 1 time.
1 send("A0 STARTTLS");
151 } else {
152
1/1
✓ Branch 29 → 30 taken 12 times.
12 imapLogin();
153 }
154 13 return;
155 }
156
2/2
✓ Branch 31 → 32 taken 1 time.
✓ Branch 31 → 45 taken 11 times.
12 if (m_step == Step::StartTls) {
157
1/2
✗ Branch 34 → 35 not taken.
✓ Branch 34 → 36 taken 1 time.
1 if (line.startsWith("*")) return;
158
1/2
✓ Branch 38 → 39 taken 1 time.
✗ Branch 38 → 43 not taken.
1 if (!line.startsWith("A0 OK")) {
159 1 input.tlsUnavailable = true;
160
1/1
✓ Branch 40 → 41 taken 1 time.
1 fail(input);
161 1 return;
162 }
163 ✗ m_socket.startClientEncryption();
164 ✗ return;
165 }
166
1/2
✓ Branch 45 → 46 taken 11 times.
✗ Branch 45 → 66 not taken.
11 if (m_step == Step::Login) {
167
1/2
✗ Branch 48 → 49 not taken.
✓ Branch 48 → 50 taken 11 times.
11 if (line.startsWith("*")) return;
168
2/2
✓ Branch 52 → 53 taken 8 times.
✓ Branch 52 → 58 taken 3 times.
11 if (line.startsWith("A1 OK")) {
169
2/2
✓ Branch 53 → 54 taken 8 times.
✓ Branch 54 → 55 taken 8 times.
8 send("A2 LOGOUT");
170
1/1
✓ Branch 56 → 57 taken 8 times.
8 succeed();
171 8 return;
172 }
173
3/3
✓ Branch 58 → 59 taken 3 times.
✓ Branch 59 → 60 taken 1 time.
✓ Branch 59 → 61 taken 2 times.
3 if (imapRateLimited(line)) input.rateLimited = true;
174 2 else input.authRejected = true;
175
1/1
✓ Branch 63 → 64 taken 3 times.
3 fail(input);
176 }
177 26 }
178
179 16 void MailLoginProbe::smtpHello() {
180 16 m_step = Step::Capabilities;
181 16 m_capabilities.clear();
182
2/2
✓ Branch 3 → 4 taken 16 times.
✓ Branch 4 → 5 taken 16 times.
16 send("EHLO mailjd.localhost");
183 16 }
184
185 15 void MailLoginProbe::smtpAuthenticate() {
186
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 9 taken 15 times.
15 if (!m_tls) {
187 ✗ auto input = baseInput();
188 ✗ input.tlsUnavailable = true;
189 ✗ fail(input);
190 ✗ return;
191 ✗ }
192
4/4
✓ Branch 9 → 10 taken 15 times.
✓ Branch 10 → 11 taken 15 times.
✓ Branch 12 → 13 taken 1 time.
✓ Branch 12 → 19 taken 14 times.
15 if (breaksALine(m_request.username.toUtf8())) {
193 1 auto input = baseInput();
194 1 input.authRejected = true;
195
1/1
✓ Branch 15 → 16 taken 1 time.
1 fail(input);
196 1 return;
197 1 }
198
1/1
✓ Branch 19 → 20 taken 14 times.
14 const QByteArray caps = m_capabilities.toUpper();
199
1/2
✗ Branch 22 → 23 not taken.
✓ Branch 22 → 31 taken 14 times.
14 if (!caps.contains("AUTH")) { // a server that relays without login
200 // F-31: still verify the envelope — relaying policy decides whether
201 // this server is usable for sending, not the absence of a login.
202 ✗ m_step = Step::MailFrom;
203 ✗ send("MAIL FROM:<" + m_request.username.toUtf8() + ">");
204 ✗ return;
205 }
206
2/2
✓ Branch 33 → 34 taken 13 times.
✓ Branch 33 → 53 taken 1 time.
14 if (caps.contains("PLAIN")) {
207 13 m_step = Step::AuthPlain;
208
6/6
✓ Branch 34 → 35 taken 13 times.
✓ Branch 35 → 36 taken 13 times.
✓ Branch 36 → 37 taken 13 times.
✓ Branch 37 → 38 taken 13 times.
✓ Branch 38 → 39 taken 13 times.
✓ Branch 39 → 40 taken 13 times.
13 const QByteArray token = QByteArray(1, '\0') + m_request.username.toUtf8() + QByteArray(1, '\0') + m_request.password;
209
3/3
✓ Branch 46 → 47 taken 13 times.
✓ Branch 47 → 48 taken 13 times.
✓ Branch 48 → 49 taken 13 times.
13 send("AUTH PLAIN " + token.toBase64());
210 13 } else {
211 1 m_step = Step::AuthUser;
212
2/2
✓ Branch 53 → 54 taken 1 time.
✓ Branch 54 → 55 taken 1 time.
1 send("AUTH LOGIN");
213 }
214 14 }
215
216 83 void MailLoginProbe::handleSmtp(const QByteArray &line) {
217 83 auto input = baseInput();
218
2/2
✓ Branch 3 → 4 taken 83 times.
✓ Branch 4 → 5 taken 83 times.
83 input.serverText = QString::fromUtf8(line.left(300));
219
2/2
✓ Branch 8 → 9 taken 83 times.
✓ Branch 9 → 10 taken 83 times.
83 const int code = line.left(3).toInt();
220
3/4
✓ Branch 12 → 13 taken 83 times.
✗ Branch 12 → 15 not taken.
✓ Branch 14 → 15 taken 63 times.
✓ Branch 14 → 16 taken 20 times.
83 const bool last = line.size() < 4 || line.at(3) != '-';
221
7/9
✓ Branch 17 → 18 taken 16 times.
✓ Branch 17 → 26 taken 36 times.
✗ Branch 17 → 60 not taken.
✓ Branch 17 → 67 taken 1 time.
✓ Branch 17 → 76 taken 1 time.
✓ Branch 17 → 83 taken 14 times.
✓ Branch 17 → 93 taken 8 times.
✓ Branch 17 → 111 taken 7 times.
✗ Branch 17 → 127 not taken.
83 switch (m_step) {
222 16 case Step::Greeting:
223
1/2
✗ Branch 18 → 19 not taken.
✓ Branch 18 → 23 taken 16 times.
16 if (code != 220) {
224 ✗ input.protocolMismatch = true;
225 ✗ fail(input);
226 ✗ return;
227 }
228
2/3
✓ Branch 23 → 24 taken 16 times.
✗ Branch 23 → 25 not taken.
✓ Branch 24 → 25 taken 16 times.
16 if (last) smtpHello();
229 16 return;
230 36 case Step::Capabilities:
231
1/2
✗ Branch 26 → 27 not taken.
✓ Branch 26 → 31 taken 36 times.
36 if (code != 250) {
232 ✗ fail(input);
233 ✗ return;
234 }
235
3/3
✓ Branch 31 → 32 taken 36 times.
✓ Branch 32 → 33 taken 36 times.
✓ Branch 33 → 34 taken 36 times.
36 m_capabilities += line.mid(4) + '\n';
236
2/2
✓ Branch 36 → 37 taken 20 times.
✓ Branch 36 → 38 taken 16 times.
36 if (!last) return;
237
5/6
✓ Branch 38 → 39 taken 1 time.
✓ Branch 38 → 43 taken 15 times.
✓ Branch 41 → 42 taken 1 time.
✗ Branch 41 → 43 not taken.
✓ Branch 44 → 45 taken 1 time.
✓ Branch 44 → 58 taken 15 times.
16 if (!m_tls && m_request.security == QLatin1String("starttls")) {
238
2/3
✓ Branch 45 → 46 taken 1 time.
✓ Branch 49 → 50 taken 1 time.
✗ Branch 49 → 54 not taken.
1 if (!m_capabilities.toUpper().contains("STARTTLS")) {
239 1 input.tlsUnavailable = true;
240
1/1
✓ Branch 51 → 52 taken 1 time.
1 fail(input);
241 1 return;
242 }
243 ✗ m_step = Step::StartTls;
244 ✗ send("STARTTLS");
245 ✗ return;
246 }
247
1/1
✓ Branch 58 → 59 taken 15 times.
15 smtpAuthenticate();
248 15 return;
249 ✗ case Step::StartTls:
250 ✗ if (code != 220) {
251 ✗ input.tlsUnavailable = true;
252 ✗ fail(input);
253 ✗ return;
254 }
255 ✗ m_socket.startClientEncryption();
256 ✗ return;
257 1 case Step::AuthUser:
258
1/2
✗ Branch 67 → 68 not taken.
✓ Branch 67 → 69 taken 1 time.
1 if (code != 334) break;
259 1 m_step = Step::AuthPassword;
260
3/3
✓ Branch 69 → 70 taken 1 time.
✓ Branch 71 → 72 taken 1 time.
✓ Branch 72 → 73 taken 1 time.
2 send(m_request.username.toUtf8().toBase64());
261 1 return;
262 1 case Step::AuthPassword:
263
1/2
✗ Branch 76 → 77 not taken.
✓ Branch 76 → 78 taken 1 time.
1 if (code != 334) break;
264 1 m_step = Step::AuthPlain;
265
2/2
✓ Branch 79 → 80 taken 1 time.
✓ Branch 80 → 81 taken 1 time.
1 send(m_request.password.toBase64());
266 1 return;
267 14 case Step::AuthPlain:
268
2/2
✓ Branch 83 → 84 taken 8 times.
✓ Branch 83 → 92 taken 6 times.
14 if (code == 235) {
269 // F-31 (SPRINT-104): the login check performs the same envelope
270 // probe the send path uses — a server may accept AUTH and still
271 // refuse every MAIL FROM/RCPT TO (relaying denied), and setup used
272 // to call such a server usable.
273 8 m_step = Step::MailFrom;
274
4/4
✓ Branch 84 → 85 taken 8 times.
✓ Branch 85 → 86 taken 8 times.
✓ Branch 86 → 87 taken 8 times.
✓ Branch 87 → 88 taken 8 times.
8 send("MAIL FROM:<" + m_request.username.toUtf8() + ">");
275 8 return;
276 }
277 6 break;
278 8 case Step::MailFrom:
279
2/2
✓ Branch 93 → 94 taken 7 times.
✓ Branch 93 → 102 taken 1 time.
8 if (code == 250) {
280 7 m_step = Step::RcptTo;
281
4/4
✓ Branch 94 → 95 taken 7 times.
✓ Branch 95 → 96 taken 7 times.
✓ Branch 96 → 97 taken 7 times.
✓ Branch 97 → 98 taken 7 times.
7 send("RCPT TO:<" + m_request.username.toUtf8() + ">");
282 7 return;
283 }
284 // F-31: the login works but the server refuses the envelope (e.g.
285 // relaying denied) — not usable for sending; the server's text says
286 // why.
287 1 input.protocolMismatch = true;
288
2/2
✓ Branch 102 → 103 taken 1 time.
✓ Branch 103 → 104 taken 1 time.
1 input.serverText = QString::fromUtf8(line.left(300));
289
1/1
✓ Branch 108 → 109 taken 1 time.
1 fail(input);
290 1 return;
291 7 case Step::RcptTo:
292
1/4
✗ Branch 111 → 112 not taken.
✓ Branch 111 → 113 taken 7 times.
✗ Branch 112 → 113 not taken.
✗ Branch 112 → 118 not taken.
7 if (code == 250 || code == 251) {
293
2/2
✓ Branch 113 → 114 taken 7 times.
✓ Branch 114 → 115 taken 7 times.
7 send("QUIT");
294
1/1
✓ Branch 116 → 117 taken 7 times.
7 succeed();
295 7 return;
296 }
297 ✗ input.protocolMismatch = true;
298 ✗ input.serverText = QString::fromUtf8(line.left(300));
299 ✗ fail(input);
300 ✗ return;
301 ✗ default:
302 ✗ return;
303 }
304 // 535 (bad credentials), 534/538 (needs stronger auth), 454/421 (try later).
305
4/6
✓ Branch 128 → 129 taken 5 times.
✓ Branch 128 → 131 taken 1 time.
✓ Branch 129 → 130 taken 5 times.
✗ Branch 129 → 131 not taken.
✗ Branch 130 → 131 not taken.
✓ Branch 130 → 132 taken 5 times.
6 if (code == 454 || code == 421 || code == 450) input.rateLimited = true;
306 5 else input.authRejected = true;
307
1/1
✓ Branch 134 → 135 taken 6 times.
6 fail(input);
308 83 }
309