File indexing completed on 2024-11-24 04:53:23
0001 /* Copyright (C) 2006 - 2014 Jan Kundrát <jkt@flaska.net> 0002 Copyright (C) 2013 Pali Rohár <pali.rohar@gmail.com> 0003 0004 This file is part of the Trojita Qt IMAP e-mail client, 0005 http://trojita.flaska.net/ 0006 0007 This program is free software; you can redistribute it and/or 0008 modify it under the terms of the GNU General Public License as 0009 published by the Free Software Foundation; either version 2 of 0010 the License or (at your option) version 3 or any later version 0011 accepted by the membership of KDE e.V. (or its successor approved 0012 by the membership of KDE e.V.), which shall act as a proxy 0013 defined in Section 14 of version 3 of the license. 0014 0015 This program is distributed in the hope that it will be useful, 0016 but WITHOUT ANY WARRANTY; without even the implied warranty of 0017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0018 GNU General Public License for more details. 0019 0020 You should have received a copy of the GNU General Public License 0021 along with this program. If not, see <http://www.gnu.org/licenses/>. 0022 */ 0023 #include "SMTP.h" 0024 #include "UiUtils/Formatting.h" 0025 0026 namespace MSA 0027 { 0028 0029 SMTP::SMTP(QObject *parent, const QString &host, quint16 port, bool encryptedConnect, bool startTls, bool auth, 0030 const QString &user): 0031 AbstractMSA(parent), host(host), port(port), 0032 encryptedConnect(encryptedConnect), startTls(startTls), auth(auth), 0033 user(user), failed(false), isWaitingForPassword(false), sendingMode(MODE_SMTP_INVALID) 0034 { 0035 qwwSmtp = new QwwSmtpClient(this); 0036 // FIXME: handle SSL errors in the same way as we handle IMAP TLS errors, with key pinning, etc. 0037 connect(qwwSmtp, &QwwSmtpClient::sslErrors, this, &SMTP::handleSslErrors); 0038 connect(qwwSmtp, &QwwSmtpClient::connected, this, &AbstractMSA::sending); 0039 connect(qwwSmtp, &QwwSmtpClient::done, this, &SMTP::handleDone); 0040 connect(qwwSmtp, &QwwSmtpClient::socketError, this, &SMTP::handleError); 0041 connect(qwwSmtp, &QwwSmtpClient::logReceived, this, [this](const QByteArray& data) { 0042 emit logged(Common::LogKind::LOG_IO_READ, QStringLiteral("SMTP"), QString::fromUtf8(data)); 0043 }); 0044 connect(qwwSmtp, &QwwSmtpClient::logSent, this, [this](const QByteArray& data) { 0045 emit logged(Common::LogKind::LOG_IO_WRITTEN, QStringLiteral("SMTP"), QString::fromUtf8(data)); 0046 }); 0047 } 0048 0049 void SMTP::cancel() 0050 { 0051 qwwSmtp->disconnectFromHost(); 0052 if (!failed) { 0053 failed = true; 0054 emit error(tr("Sending of the message was cancelled")); 0055 } 0056 } 0057 0058 void SMTP::handleDone(bool ok) 0059 { 0060 if (failed) { 0061 // This is a duplicate notification. The QwwSmtpClient is known to send contradicting results, see e.g. bug 321272. 0062 return; 0063 } 0064 if (ok) { 0065 emit sent(); 0066 } else { 0067 failed = true; 0068 if (qwwSmtp->errorString().isEmpty()) 0069 emit error(tr("Sending of the message failed.")); 0070 else 0071 emit error(tr("Sending of the message failed with the following error: %1").arg(qwwSmtp->errorString())); 0072 } 0073 } 0074 0075 void SMTP::handleError(QAbstractSocket::SocketError err, const QString &msg) 0076 { 0077 Q_UNUSED(err); 0078 failed = true; 0079 emit error(msg); 0080 } 0081 0082 void SMTP::handleSslErrors(const QList<QSslError>& errors) 0083 { 0084 auto msg = UiUtils::Formatting::sslErrorsToHtml(errors); 0085 emit error(tr("<p>Cannot send message due to an SSL/TLS error</p>\n%1").arg(msg)); 0086 } 0087 0088 void SMTP::setPassword(const QString &password) 0089 { 0090 pass = password; 0091 if (isWaitingForPassword) 0092 sendContinueGotPassword(); 0093 } 0094 0095 void SMTP::sendMail(const QByteArray &from, const QList<QByteArray> &to, const QByteArray &data) 0096 { 0097 this->from = from; 0098 this->to = to; 0099 this->data = data; 0100 this->sendingMode = MODE_SMTP_DATA; 0101 this->isWaitingForPassword = true; 0102 emit progressMax(data.size()); 0103 emit progress(0); 0104 emit connecting(); 0105 if (!auth || !pass.isEmpty()) { 0106 sendContinueGotPassword(); 0107 return; 0108 } 0109 emit passwordRequested(user, host); 0110 } 0111 0112 void SMTP::sendContinueGotPassword() 0113 { 0114 isWaitingForPassword = false; 0115 if (encryptedConnect) 0116 qwwSmtp->connectToHostEncrypted(host, port); 0117 else 0118 qwwSmtp->connectToHost(host, port); 0119 if (startTls) 0120 qwwSmtp->startTls(); 0121 if (auth) 0122 qwwSmtp->authenticate(user, pass, QwwSmtpClient::AuthAny); 0123 emit sending(); // FIXME: later 0124 switch (sendingMode) { 0125 case MODE_SMTP_DATA: 0126 { 0127 //RFC5321 specifies to prepend a period to lines starting with a period in section 4.5.2 0128 if (data.startsWith('.')) 0129 data.prepend('.'); 0130 data.replace("\n.", "\n.."); 0131 qwwSmtp->sendMail(from, to, data); 0132 } 0133 break; 0134 case MODE_SMTP_BURL: 0135 qwwSmtp->sendMailBurl(from, to, data); 0136 break; 0137 default: 0138 failed = true; 0139 emit error(tr("Unknown SMTP mode")); 0140 break; 0141 } 0142 qwwSmtp->disconnectFromHost(); 0143 } 0144 0145 bool SMTP::supportsBurl() const 0146 { 0147 return true; 0148 } 0149 0150 void SMTP::sendBurl(const QByteArray &from, const QList<QByteArray> &to, const QByteArray &imapUrl) 0151 { 0152 this->from = from; 0153 this->to = to; 0154 this->data = imapUrl; 0155 this->sendingMode = MODE_SMTP_BURL; 0156 this->isWaitingForPassword = true; 0157 emit progressMax(1); 0158 emit progress(0); 0159 emit connecting(); 0160 if (!auth || !pass.isEmpty()) { 0161 sendContinueGotPassword(); 0162 return; 0163 } 0164 emit passwordRequested(user, host); 0165 } 0166 0167 SMTPFactory::SMTPFactory(const QString &host, quint16 port, bool encryptedConnect, bool startTls, 0168 bool auth, const QString &user): 0169 m_host(host), m_port(port), m_encryptedConnect(encryptedConnect), m_startTls(startTls), 0170 m_auth(auth), m_user(user) 0171 { 0172 } 0173 0174 SMTPFactory::~SMTPFactory() 0175 { 0176 } 0177 0178 AbstractMSA *SMTPFactory::create(QObject *parent) const 0179 { 0180 return new SMTP(parent, m_host, m_port, m_encryptedConnect, m_startTls, m_auth, m_user); 0181 } 0182 0183 }