12#include "mailtransportplugin_smtp_debug.h"
13#include "precommandjob.h"
14#include "sessionuiproxy.h"
16#include "xoauthpasswordrequester.h"
21#include "mailtransport_debug.h"
22#include <KLocalizedString>
23#include <KPasswordDialog>
25#include <KSMTP/LoginJob>
26#include <KSMTP/SendJob>
28#include <KGAPI/Account>
29#include <KGAPI/AccountManager>
30#include <KGAPI/AuthJob>
32using namespace MailTransport;
42 qCDebug(MAILTRANSPORT_SMTP_LOG) <<
"Removing session" << session <<
"from the pool";
43 int key = sessions.
key(session);
56Q_GLOBAL_STATIC(SessionPool, s_sessionPool)
65 explicit SmtpJobPrivate(
SmtpJob *parent)
74 KSmtp::SessionUiProxy::Ptr uiProxy;
85 , d(new SmtpJobPrivate(this))
87 d->currentState = SmtpJobPrivate::Idle;
90 d->uiProxy = KSmtp::SessionUiProxy::Ptr(
new SmtpSessionUiProxy);
91 if (!s_sessionPool.isDestroyed()) {
98 if (!s_sessionPool.isDestroyed()) {
100 if (s_sessionPool->ref == 0) {
101 qCDebug(MAILTRANSPORT_SMTP_LOG) <<
"clearing SMTP session pool" << s_sessionPool->sessions.count();
102 while (!s_sessionPool->sessions.isEmpty()) {
103 s_sessionPool->removeSession(*(s_sessionPool->sessions.begin()));
111 if (s_sessionPool.isDestroyed()) {
115 if ((!s_sessionPool->sessions.isEmpty() && s_sessionPool->sessions.contains(
transport()->
id())) ||
transport()->precommand().isEmpty()) {
116 d->currentState = SmtpJobPrivate::Smtp;
119 d->currentState = SmtpJobPrivate::Precommand;
126void SmtpJob::startSmtpJob()
128 if (s_sessionPool.isDestroyed()) {
132 d->session = s_sessionPool->sessions.value(
transport()->
id());
135 d->session->setUseNetworkProxy(
transport()->useProxy());
136 d->session->setUiProxy(d->uiProxy);
138 case Transport::EnumEncryption::None:
141 case Transport::EnumEncryption::TLS:
144 case Transport::EnumEncryption::SSL:
148 qCWarning(MAILTRANSPORT_SMTP_LOG) <<
"Unknown encryption mode" <<
transport()->encryption();
152 d->session->setCustomHostname(
transport()->localHostname());
154 s_sessionPool->sessions.insert(
transport()->
id(), d->session);
158 connect(d->session, &KSmtp::Session::connectionError,
this, [
this](
const QString &err) {
159 setError(KJob::UserDefinedError);
161 s_sessionPool->removeSession(d->session);
169 startPasswordRetrieval();
179 startPasswordRetrieval();
185void SmtpJob::startPasswordRetrieval(
bool forceRefresh)
187 if (!
transport()->requiresAuthentication() && !forceRefresh) {
192 auto xoauthRequester = createXOAuthPasswordRequester(
transport(),
this);
193 if (xoauthRequester !=
nullptr) {
195 &XOAuthPasswordRequester::done,
197 [
this, xoauthRequester](XOAuthPasswordRequester::Result
result,
const QString &password) {
198 xoauthRequester->deleteLater();
199 if (
result == XOAuthPasswordRequester::Error) {
208 xoauthRequester->requestPassword(forceRefresh);
214void SmtpJob::startLoginJob()
216 if (!
transport()->requiresAuthentication()) {
223 if ((user.isEmpty() || passwd.isEmpty()) &&
transport()->authenticationType() != Transport::EnumAuthenticationType::GSSAPI) {
227 i18n(
"You need to supply a username and a password "
228 "to use this SMTP server."));
229 dlg->setKeepPassword(
transport()->storePassword());
231 dlg->setUsername(user);
232 dlg->setPassword(passwd);
233 dlg->setRevealPasswordMode(
KAuthorized::authorize(QStringLiteral(
"lineedit_reveal_password")) ? KPassword::RevealMode::OnlyNew
234 : KPassword::RevealMode::Never);
245 transport()->setUserName(dlg->username());
247 transport()->setStorePassword(dlg->keepPassword());
260void SmtpJobPrivate::doLogin()
262 QString passwd = q->transport()->password();
263 if (q->transport()->authenticationType() == Transport::EnumAuthenticationType::XOAUTH2) {
268 login->setUserName(q->transport()->userName());
269 login->setPassword(passwd);
270 switch (q->transport()->authenticationType()) {
271 case TransportBase::EnumAuthenticationType::PLAIN:
272 login->setPreferedAuthMode(KSmtp::LoginJob::Plain);
274 case TransportBase::EnumAuthenticationType::LOGIN:
275 login->setPreferedAuthMode(KSmtp::LoginJob::Login);
277 case TransportBase::EnumAuthenticationType::CRAM_MD5:
278 login->setPreferedAuthMode(KSmtp::LoginJob::CramMD5);
280 case TransportBase::EnumAuthenticationType::XOAUTH2:
281 login->setPreferedAuthMode(KSmtp::LoginJob::XOAuth2);
283 case TransportBase::EnumAuthenticationType::DIGEST_MD5:
284 login->setPreferedAuthMode(KSmtp::LoginJob::DigestMD5);
286 case TransportBase::EnumAuthenticationType::NTLM:
287 login->setPreferedAuthMode(KSmtp::LoginJob::NTLM);
289 case TransportBase::EnumAuthenticationType::GSSAPI:
290 login->setPreferedAuthMode(KSmtp::LoginJob::GSSAPI);
293 qCWarning(MAILTRANSPORT_SMTP_LOG) <<
"Unknown authentication mode" << q->transport()->authenticationTypeString();
299 qCDebug(MAILTRANSPORT_SMTP_LOG) <<
"Login started";
302void SmtpJob::startSendJob()
309 send->setData(
data());
315 qCDebug(MAILTRANSPORT_SMTP_LOG) <<
"Send started";
318bool SmtpJob::doKill()
320 if (s_sessionPool.isDestroyed()) {
327 if (d->currentState == SmtpJobPrivate::Precommand) {
328 return subjobs().first()->kill();
329 }
else if (d->currentState == SmtpJobPrivate::Smtp) {
331 s_sessionPool->removeSession(d->session);
337void SmtpJob::slotResult(
KJob *job)
339 if (s_sessionPool.isDestroyed()) {
344 if (job->
error() == KSmtp::LoginJob::TokenExpired) {
346 startPasswordRetrieval(
true);
372 int errorCode =
error();
374 errorCode = job->
error();
377 if (errorCode && d->currentState == SmtpJobPrivate::Smtp) {
378 s_sessionPool->removeSession(d->session);
384 if (!
error() && d->currentState == SmtpJobPrivate::Precommand) {
385 d->currentState = SmtpJobPrivate::Smtp;
394#include "moc_smtpjob.cpp"
static Q_INVOKABLE bool authorize(const QString &action)
virtual bool addSubjob(KJob *job)
const QList< KJob * > & subjobs() const
virtual bool removeSubjob(KJob *job)
virtual void slotResult(KJob *job)
void setError(int errorCode)
Job to execute a command.
Mail transport job for SMTP.
~SmtpJob() override
Deletes this job.
SmtpJob(Transport *transport, QObject *parent=nullptr)
Creates a SmtpJob.
void doStart() override
Do the actual work, implement in your subclass.
Abstract base class for all mail transport jobs.
Transport * transport() const
Returns the Transport object containing the mail transport settings.
QByteArray data() const
Returns the data of the mail.
QString sender() const
Returns the sender of the mail.
QStringList bcc() const
Returns the "Bcc" receiver(s) of the mail.
bool deliveryStatusNotification() const
Returns true if DSN is enabled.
QStringList to() const
Returns the "To" receiver(s) of the mail.
QStringList cc() const
Returns the "Cc" receiver(s) of the mail.
Represents the settings of a specific mail transport.
void setPassword(const QString &passwd)
Sets the password of this transport.
QString i18n(const char *text, const TYPE &arg...)
Internal file containing constant definitions etc.
QString name(StandardAction id)
void finished(int result)
Key key(const T &value) const const
bool remove(const Key &key)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
T qobject_cast(QObject *object)
qsizetype indexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs) const const
QString left(qsizetype n) const const