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;
75 enum State { Idle, Precommand, Smtp } currentState;
81 , d(new SmtpJobPrivate(this))
83 d->currentState = SmtpJobPrivate::Idle;
86 d->uiProxy = KSmtp::SessionUiProxy::Ptr(
new SmtpSessionUiProxy);
87 if (!s_sessionPool.isDestroyed()) {
94 if (!s_sessionPool.isDestroyed()) {
96 if (s_sessionPool->ref == 0) {
97 qCDebug(MAILTRANSPORT_SMTP_LOG) <<
"clearing SMTP session pool" << s_sessionPool->sessions.count();
98 while (!s_sessionPool->sessions.isEmpty()) {
99 s_sessionPool->removeSession(*(s_sessionPool->sessions.begin()));
107 if (s_sessionPool.isDestroyed()) {
111 if ((!s_sessionPool->sessions.isEmpty() && s_sessionPool->sessions.contains(
transport()->
id())) ||
transport()->precommand().isEmpty()) {
112 d->currentState = SmtpJobPrivate::Smtp;
115 d->currentState = SmtpJobPrivate::Precommand;
122void SmtpJob::startSmtpJob()
124 if (s_sessionPool.isDestroyed()) {
128 d->session = s_sessionPool->sessions.value(
transport()->
id());
131 d->session->setUseNetworkProxy(
transport()->useProxy());
132 d->session->setUiProxy(d->uiProxy);
134 case Transport::EnumEncryption::None:
137 case Transport::EnumEncryption::TLS:
140 case Transport::EnumEncryption::SSL:
144 qCWarning(MAILTRANSPORT_SMTP_LOG) <<
"Unknown encryption mode" <<
transport()->encryption();
148 d->session->setCustomHostname(
transport()->localHostname());
150 s_sessionPool->sessions.insert(
transport()->
id(), d->session);
154 connect(d->session, &KSmtp::Session::connectionError,
this, [
this](
const QString &err) {
155 setError(KJob::UserDefinedError);
157 s_sessionPool->removeSession(d->session);
165 startPasswordRetrieval();
175 startPasswordRetrieval();
181void SmtpJob::startPasswordRetrieval(
bool forceRefresh)
183 if (!
transport()->requiresAuthentication() && !forceRefresh) {
188 auto xoauthRequester = createXOAuthPasswordRequester(
transport(),
this);
189 if (xoauthRequester !=
nullptr) {
191 &XOAuthPasswordRequester::done,
193 [
this, xoauthRequester](XOAuthPasswordRequester::Result
result,
const QString &password) {
194 xoauthRequester->deleteLater();
195 if (
result == XOAuthPasswordRequester::Error) {
204 xoauthRequester->requestPassword(forceRefresh);
210void SmtpJob::startLoginJob()
212 if (!
transport()->requiresAuthentication()) {
219 if ((user.isEmpty() || passwd.isEmpty()) &&
transport()->authenticationType() != Transport::EnumAuthenticationType::GSSAPI) {
223 i18n(
"You need to supply a username and a password "
224 "to use this SMTP server."));
225 dlg->setKeepPassword(
transport()->storePassword());
227 dlg->setUsername(user);
228 dlg->setPassword(passwd);
229 dlg->setRevealPasswordMode(
KAuthorized::authorize(QStringLiteral(
"lineedit_reveal_password")) ? KPassword::RevealMode::OnlyNew
230 : KPassword::RevealMode::Never);
241 transport()->setUserName(dlg->username());
243 transport()->setStorePassword(dlg->keepPassword());
256void SmtpJobPrivate::doLogin()
258 QString passwd = q->transport()->password();
259 if (q->transport()->authenticationType() == Transport::EnumAuthenticationType::XOAUTH2) {
264 login->setUserName(q->transport()->userName());
265 login->setPassword(passwd);
266 switch (q->transport()->authenticationType()) {
267 case TransportBase::EnumAuthenticationType::PLAIN:
268 login->setPreferedAuthMode(KSmtp::LoginJob::Plain);
270 case TransportBase::EnumAuthenticationType::LOGIN:
271 login->setPreferedAuthMode(KSmtp::LoginJob::Login);
273 case TransportBase::EnumAuthenticationType::CRAM_MD5:
274 login->setPreferedAuthMode(KSmtp::LoginJob::CramMD5);
276 case TransportBase::EnumAuthenticationType::XOAUTH2:
277 login->setPreferedAuthMode(KSmtp::LoginJob::XOAuth2);
279 case TransportBase::EnumAuthenticationType::DIGEST_MD5:
280 login->setPreferedAuthMode(KSmtp::LoginJob::DigestMD5);
282 case TransportBase::EnumAuthenticationType::NTLM:
283 login->setPreferedAuthMode(KSmtp::LoginJob::NTLM);
285 case TransportBase::EnumAuthenticationType::GSSAPI:
286 login->setPreferedAuthMode(KSmtp::LoginJob::GSSAPI);
289 qCWarning(MAILTRANSPORT_SMTP_LOG) <<
"Unknown authentication mode" << q->transport()->authenticationTypeString();
295 qCDebug(MAILTRANSPORT_SMTP_LOG) <<
"Login started";
298void SmtpJob::startSendJob()
305 send->setData(
data());
311 qCDebug(MAILTRANSPORT_SMTP_LOG) <<
"Send started";
314bool SmtpJob::doKill()
316 if (s_sessionPool.isDestroyed()) {
323 if (d->currentState == SmtpJobPrivate::Precommand) {
324 return subjobs().first()->kill();
325 }
else if (d->currentState == SmtpJobPrivate::Smtp) {
327 s_sessionPool->removeSession(d->session);
333void SmtpJob::slotResult(
KJob *job)
335 if (s_sessionPool.isDestroyed()) {
340 if (job->
error() == KSmtp::LoginJob::TokenExpired) {
342 startPasswordRetrieval(
true);
368 int errorCode =
error();
370 errorCode = job->
error();
373 if (errorCode && d->currentState == SmtpJobPrivate::Smtp) {
374 s_sessionPool->removeSession(d->session);
380 if (!
error() && d->currentState == SmtpJobPrivate::Precommand) {
381 d->currentState = SmtpJobPrivate::Smtp;
390#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