File indexing completed on 2024-05-12 05:21:35
0001 /* 0002 SPDX-FileCopyrightText: 2010 BetterInbox <contact@betterinbox.com> 0003 SPDX-FileContributor: Christophe Laveault <christophe@betterinbox.com> 0004 SPDX-FileContributor: Gregory Schlomoff <gregory.schlomoff@gmail.com> 0005 0006 SPDX-License-Identifier: LGPL-2.1-or-later 0007 */ 0008 0009 #include "smtptest.h" 0010 0011 #include "fakeserver.h" 0012 #include "loginjob.h" 0013 #include "sendjob.h" 0014 #include "session.h" 0015 #include <QTest> 0016 0017 void SmtpTest::testHello_data() 0018 { 0019 QTest::addColumn<QList<QByteArray>>("scenario"); 0020 QTest::addColumn<QString>("hostname"); 0021 0022 QList<QByteArray> scenario; 0023 scenario << FakeServer::greeting() << "C: EHLO 127.0.0.1" 0024 << "S: 250 Localhost ready to roll" << FakeServer::bye(); 0025 QTest::newRow("EHLO OK") << scenario << QStringLiteral("127.0.0.1"); 0026 0027 scenario.clear(); 0028 scenario << FakeServer::greeting() << "C: EHLO 127.0.0.1" 0029 << "S: 500 Command was not recognized" 0030 << "C: HELO 127.0.0.1" 0031 << "S: 250 Localhost ready to roll" << FakeServer::bye(); 0032 QTest::newRow("EHLO unknown") << scenario << QStringLiteral("127.0.0.1"); 0033 0034 scenario.clear(); 0035 scenario << FakeServer::greeting() << "C: EHLO 127.0.0.1" 0036 << "S: 502 Command not implemented" 0037 << "C: HELO 127.0.0.1" 0038 << "S: 250 Localhost ready to roll" << FakeServer::bye(); 0039 QTest::newRow("EHLO not implemented") << scenario << QStringLiteral("127.0.0.1"); 0040 0041 scenario.clear(); 0042 scenario << FakeServer::greeting() << "C: EHLO 127.0.0.1" 0043 << "S: 502 Command not implemented" 0044 << "C: HELO 127.0.0.1" 0045 << "S: 500 Command was not recognized" << FakeServer::bye(); 0046 QTest::newRow("ERROR") << scenario << QStringLiteral("127.0.0.1"); 0047 0048 scenario.clear(); 0049 scenario << FakeServer::greeting() << "C: EHLO random.stranger" 0050 << "S: 250 random.stranger ready to roll" << FakeServer::bye(); 0051 QTest::newRow("EHLO hostname") << scenario << QStringLiteral("random.stranger"); 0052 } 0053 0054 void SmtpTest::testHello() 0055 { 0056 QFETCH(QList<QByteArray>, scenario); 0057 QFETCH(QString, hostname); 0058 0059 FakeServer fakeServer; 0060 fakeServer.setScenario(scenario); 0061 fakeServer.startAndWait(); 0062 KSmtp::Session session(QStringLiteral("127.0.0.1"), 5989); 0063 session.setCustomHostname(hostname); 0064 QEventLoop loop; 0065 connect(&session, &KSmtp::Session::stateChanged, this, [&loop](auto state) { 0066 qDebug() << state; 0067 if (state == KSmtp::Session::NotAuthenticated || state == KSmtp::Session::Disconnected) { 0068 loop.quit(); 0069 } 0070 }); 0071 session.open(); 0072 loop.exec(); 0073 0074 qDebug() << "### Session state is:" << session.state(); 0075 0076 QEXPECT_FAIL("ERROR", "Expected failure if HELO command not recognized", Continue); 0077 QVERIFY2(session.state() == KSmtp::Session::NotAuthenticated, "Handshake failed"); 0078 0079 session.quit(); 0080 if (session.state() != KSmtp::Session::Disconnected) { 0081 loop.exec(); 0082 } 0083 0084 QVERIFY(fakeServer.isAllScenarioDone()); 0085 fakeServer.quit(); 0086 } 0087 0088 void SmtpTest::testLoginJob_data() 0089 { 0090 QTest::addColumn<QList<QByteArray>>("scenario"); 0091 QTest::addColumn<QString>("authMode"); 0092 QTest::addColumn<int>("errorCode"); 0093 0094 QList<QByteArray> scenario; 0095 scenario << FakeServer::greetingAndEhlo() << "S: 250 AUTH PLAIN LOGIN" 0096 << "C: AUTH PLAIN AGxvZ2luAHBhc3N3b3Jk" // [\0 + "login" + \0 + "password"].toBase64() 0097 << "S: 235 Authenticated" << FakeServer::bye(); 0098 QTest::newRow("Plain auth ok") << scenario << "Plain" << 0; 0099 0100 scenario.clear(); 0101 scenario << FakeServer::greetingAndEhlo() << "S: 250 AUTH PLAIN LOGIN" 0102 << "C: AUTH LOGIN" 0103 << "S: 334 VXNlcm5hbWU6" // "Username:".toBase64() 0104 << "C: bG9naW4=" // "login".toBase64() 0105 << "S: 334 UGFzc3dvcmQ6" // "Password:".toBase64() 0106 << "C: cGFzc3dvcmQ=" // "password".toBase64() 0107 << "S: 235 Authenticated" << FakeServer::bye(); 0108 QTest::newRow("Login auth ok") << scenario << "Login" << 0; 0109 0110 scenario.clear(); 0111 scenario << FakeServer::greetingAndEhlo() << "S: 250 AUTH PLAIN" 0112 << "C: AUTH PLAIN AGxvZ2luAHBhc3N3b3Jk" // [\0 + "login" + \0 + "password"].toBase64() 0113 << "S: 235 Authenticated" << FakeServer::bye(); 0114 QTest::newRow("Login not supported") << scenario << "Login" << 0; 0115 0116 scenario.clear(); 0117 scenario << FakeServer::greetingAndEhlo(false) 0118 // The login job won't even try to send AUTH, because it does not 0119 // have any mechanisms to use 0120 //<< "C: AUTH PLAIN AGxvZ2luAHBhc3N3b3Jk" // [\0 + "login" + \0 + "password"].toBase64() 0121 //<< "S: 235 Authenticated" 0122 << FakeServer::bye(); 0123 QTest::newRow("Auth not supported") << scenario << "Login" << 100; 0124 0125 scenario.clear(); 0126 scenario << FakeServer::greetingAndEhlo() << "S: 250 AUTH PLAIN" 0127 << "C: AUTH PLAIN AGxvZ2luAHBhc3N3b3Jk" // [\0 + "login" + \0 + "password"].toBase64() 0128 << "S: 535 Authorization failed" << FakeServer::bye(); 0129 QTest::newRow("Wrong password") << scenario << "Plain" << 100; 0130 } 0131 0132 void SmtpTest::testLoginJob() 0133 { 0134 QFETCH(QList<QByteArray>, scenario); 0135 QFETCH(QString, authMode); 0136 QFETCH(int, errorCode); 0137 0138 KSmtp::LoginJob::AuthMode mode = KSmtp::LoginJob::UnknownAuth; 0139 if (authMode == QLatin1StringView("Plain")) { 0140 mode = KSmtp::LoginJob::Plain; 0141 } else if (authMode == QLatin1StringView("Login")) { 0142 mode = KSmtp::LoginJob::Login; 0143 } 0144 0145 FakeServer fakeServer; 0146 fakeServer.setScenario(scenario); 0147 fakeServer.startAndWait(); 0148 KSmtp::Session session(QStringLiteral("127.0.0.1"), 5989); 0149 session.setCustomHostname(QStringLiteral("127.0.0.1")); 0150 QEventLoop loop; 0151 connect(&session, &KSmtp::Session::stateChanged, this, [&loop](auto state) { 0152 if (state == KSmtp::Session::NotAuthenticated || state == KSmtp::Session::Disconnected) { 0153 loop.quit(); 0154 } 0155 }); 0156 session.open(); 0157 loop.exec(); 0158 0159 auto login = new KSmtp::LoginJob(&session); 0160 login->setPreferedAuthMode(mode); 0161 login->setUserName(QStringLiteral("login")); 0162 login->setPassword(QStringLiteral("password")); 0163 login->exec(); 0164 0165 // Checking job error code: 0166 QVERIFY2(login->error() == errorCode, "Unexpected LoginJob error code"); 0167 0168 // Checking session state: 0169 QEXPECT_FAIL("Auth not supported", "Expected failure if not authentication method supported", Continue); 0170 QEXPECT_FAIL("Wrong password", "Expected failure if wrong password", Continue); 0171 QVERIFY2(session.state() == KSmtp::Session::Authenticated, "Authentication failed"); 0172 0173 session.quit(); 0174 loop.exec(); 0175 0176 QVERIFY(fakeServer.isAllScenarioDone()); 0177 0178 fakeServer.quit(); 0179 } 0180 0181 void SmtpTest::testSendJob_data() 0182 { 0183 QTest::addColumn<QList<QByteArray>>("scenario"); 0184 QTest::addColumn<int>("errorCode"); 0185 0186 QList<QByteArray> scenario; 0187 scenario << FakeServer::greetingAndEhlo(false) << "C: MAIL FROM:<foo@bar.com>" 0188 << "S: 530 Not allowed" << FakeServer::bye(); 0189 QTest::newRow("Send not allowed") << scenario << 100; 0190 0191 scenario.clear(); 0192 scenario << FakeServer::greetingAndEhlo(false) << "C: MAIL FROM:<foo@bar.com>" 0193 << "S: 250 ok" 0194 << "C: RCPT TO:<bar@foo.com>" 0195 << "S: 250 ok" 0196 << "C: DATA" 0197 << "S: 354 Ok go ahead" 0198 << "C: From: foo@bar.com" 0199 << "C: To: bar@foo.com" 0200 << "C: Hello world." 0201 << "C: .." // Single dot becomes two 0202 << "C: .." // Single dot becomes two 0203 << "C: ..." // Two dots become three 0204 << "C: ..Foo" // .Foo becomes ..Foo 0205 << "C: End" 0206 << "C: " 0207 << "C: ." 0208 << "S: 250 Ok transfer done" << FakeServer::bye(); 0209 QTest::newRow("ok") << scenario << 0; 0210 0211 scenario.clear(); 0212 } 0213 0214 void SmtpTest::testSendJob() 0215 { 0216 QFETCH(QList<QByteArray>, scenario); 0217 QFETCH(int, errorCode); 0218 0219 FakeServer fakeServer; 0220 fakeServer.setScenario(scenario); 0221 fakeServer.startAndWait(); 0222 KSmtp::Session session(QStringLiteral("127.0.0.1"), 5989); 0223 session.setCustomHostname(QStringLiteral("127.0.0.1")); 0224 QEventLoop loop; 0225 connect(&session, &KSmtp::Session::stateChanged, this, [&loop](auto state) { 0226 if (state == KSmtp::Session::NotAuthenticated || state == KSmtp::Session::Disconnected) { 0227 loop.quit(); 0228 } 0229 }); 0230 session.open(); 0231 loop.exec(); 0232 0233 auto send = new KSmtp::SendJob(&session); 0234 send->setData("From: foo@bar.com\r\nTo: bar@foo.com\r\nHello world.\r\n.\r\n.\r\n..\r\n.Foo\r\nEnd"); 0235 send->setFrom(QStringLiteral("foo@bar.com")); 0236 send->setTo({QStringLiteral("bar@foo.com")}); 0237 send->exec(); 0238 0239 // Checking job error code: 0240 QVERIFY2(send->error() == errorCode, qPrintable(QStringLiteral("Unexpected LoginJob error: ") + send->errorString())); 0241 0242 session.quit(); 0243 loop.exec(); 0244 0245 QVERIFY(fakeServer.isAllScenarioDone()); 0246 fakeServer.quit(); 0247 } 0248 0249 SmtpTest::SmtpTest() = default; 0250 0251 void SmtpTest::initTestCase() 0252 { 0253 } 0254 0255 void SmtpTest::cleanupTestCase() 0256 { 0257 } 0258 0259 QTEST_MAIN(SmtpTest) 0260 0261 #include "moc_smtptest.cpp"