MailTransport

smtpconfigwidget.cpp
1/*
2 SPDX-FileCopyrightText: 2009 Constantin Berzan <exit3219@gmail.com>
3
4 Based on MailTransport code by:
5 SPDX-FileCopyrightText: 2006-2007 Volker Krause <vkrause@kde.org>
6 SPDX-FileCopyrightText: 2007 KovoKs <kovoks@kovoks.nl>
7
8 Based on KMail code by:
9 SPDX-FileCopyrightText: 2001-2002 Michael Haeckel <haeckel@kde.org>
10
11 SPDX-License-Identifier: LGPL-2.0-or-later
12*/
13
14#include "smtpconfigwidget.h"
15using namespace Qt::Literals::StringLiterals;
16
17#include "ui_smtpsettings.h"
18
19#include "mailtransport_defs.h"
20#include "mailtransportplugin_smtp_debug.h"
21#include "servertest.h"
22#include "transport.h"
23#include "transportmanager.h"
24#include "widgets/transportactivitiesabstractplugin.h"
25#include "widgets/transportconfigwidget_p.h"
26
27#include <QAbstractButton>
28#include <QButtonGroup>
29
30#include <KAuthorized>
31#include <KLocalizedString>
32#include <KMessageBox>
33#include <KPluginFactory>
34#include <KPluginMetaData>
35#include <KProtocolInfo>
36
37using namespace MailTransport;
38
39class MailTransport::SMTPConfigWidgetPrivate : public TransportConfigWidgetPrivate
40{
41public:
42 ::Ui::SMTPSettings ui;
43
44 ServerTest *serverTest = nullptr;
45 QButtonGroup *encryptionGroup = nullptr;
46
47 // detected authentication capabilities
48 QList<int> noEncCapa, sslCapa, tlsCapa;
49
50 bool serverTestFailed;
51
52 static void addAuthenticationItem(QComboBox *combo, int authenticationType)
53 {
54 combo->addItem(Transport::authenticationTypeString(authenticationType), QVariant(authenticationType));
55 }
56
57 void resetAuthCapabilities()
58 {
59 noEncCapa.clear();
60 noEncCapa << Transport::EnumAuthenticationType::LOGIN << Transport::EnumAuthenticationType::PLAIN << Transport::EnumAuthenticationType::CRAM_MD5
61 << Transport::EnumAuthenticationType::DIGEST_MD5 << Transport::EnumAuthenticationType::NTLM << Transport::EnumAuthenticationType::GSSAPI
62 << Transport::EnumAuthenticationType::XOAUTH2;
63 sslCapa = tlsCapa = noEncCapa;
64 updateAuthCapbilities();
65 }
66
67 void enablePasswordLine()
68 {
69 ui.password->setEnabled(ui.kcfg_storePassword->isChecked());
70 }
71
72 void updateAuthCapbilities()
73 {
74 if (serverTestFailed) {
75 return;
76 }
77
78 QList<int> capa = noEncCapa;
79 if (ui.encryptionSsl->isChecked()) {
80 capa = sslCapa;
81 } else if (ui.encryptionTls->isChecked()) {
82 capa = tlsCapa;
83 }
84
85 ui.authCombo->clear();
86 for (int authType : std::as_const(capa)) {
87 addAuthenticationItem(ui.authCombo, authType);
88 }
89
90 if (transport->isValid()) {
91 const int idx = ui.authCombo->findData(transport->authenticationType());
92
93 if (idx != -1) {
94 ui.authCombo->setCurrentIndex(idx);
95 }
96 }
97
98 if (capa.isEmpty()) {
99 ui.noAuthPossible->setVisible(true);
100 ui.kcfg_requiresAuthentication->setChecked(false);
101 ui.kcfg_requiresAuthentication->setEnabled(false);
102 ui.kcfg_requiresAuthentication->setVisible(false);
103 ui.authCombo->setEnabled(false);
104 ui.authLabel->setEnabled(false);
105 } else {
106 ui.noAuthPossible->setVisible(false);
107 ui.kcfg_requiresAuthentication->setEnabled(true);
108 ui.kcfg_requiresAuthentication->setVisible(true);
109 ui.authCombo->setEnabled(true);
110 ui.authLabel->setEnabled(true);
111 enablePasswordLine();
112 }
113 }
114};
115
116SMTPConfigWidget::SMTPConfigWidget(Transport *transport, QWidget *parent)
117 : TransportConfigWidget(*new SMTPConfigWidgetPrivate, transport, parent)
118{
119 init();
120}
121
122static void checkHighestEnabledButton(QButtonGroup *group)
123{
124 Q_ASSERT(group);
125
126 for (int i = group->buttons().count() - 1; i >= 0; --i) {
127 QAbstractButton *b = group->buttons().at(i);
128 if (b && b->isEnabled()) {
129 b->animateClick();
130 return;
131 }
132 }
133}
134
135void SMTPConfigWidget::init()
136{
138 d->serverTest = nullptr;
139
140 connect(TransportManager::self(), &TransportManager::passwordsChanged, this, &SMTPConfigWidget::passwordsLoaded);
141
142 d->serverTestFailed = false;
143
144 d->ui.setupUi(this);
145 d->ui.password->setRevealPasswordMode(KAuthorized::authorize(QStringLiteral("lineedit_reveal_password")) ? KPassword::RevealMode::OnlyNew
146 : KPassword::RevealMode::Never);
147 d->manager->addWidget(this); // otherwise it doesn't find out about these widgets
148 d->manager->updateWidgets();
149
150 d->ui.password->setWhatsThis(i18n("The password to send to the server for authorization."));
151
152 d->ui.kcfg_userName->setClearButtonEnabled(true);
153 d->encryptionGroup = new QButtonGroup(this);
154 d->encryptionGroup->addButton(d->ui.encryptionNone, Transport::EnumEncryption::None);
155 d->encryptionGroup->addButton(d->ui.encryptionSsl, Transport::EnumEncryption::SSL);
156 d->encryptionGroup->addButton(d->ui.encryptionTls, Transport::EnumEncryption::TLS);
157
158 d->ui.encryptionNone->setChecked(d->transport->encryption() == Transport::EnumEncryption::None);
159 d->ui.encryptionSsl->setChecked(d->transport->encryption() == Transport::EnumEncryption::SSL);
160 d->ui.encryptionTls->setChecked(d->transport->encryption() == Transport::EnumEncryption::TLS);
161
162 d->ui.checkCapabilitiesProgress->setFormat(i18nc("Percent value; %p is the value, % is the percent sign", "%p%"));
163
164 d->resetAuthCapabilities();
165
166 if (!KProtocolInfo::capabilities(SMTP_PROTOCOL).contains("SASL"_L1)) {
167 d->ui.authCombo->removeItem(d->ui.authCombo->findData(Transport::EnumAuthenticationType::NTLM));
168 d->ui.authCombo->removeItem(d->ui.authCombo->findData(Transport::EnumAuthenticationType::GSSAPI));
169 }
170
171 connect(d->ui.checkCapabilities, &QPushButton::clicked, this, &SMTPConfigWidget::checkSmtpCapabilities);
172 connect(d->ui.kcfg_host, &QLineEdit::textChanged, this, &SMTPConfigWidget::hostNameChanged);
173
174 connect(d->encryptionGroup, &QButtonGroup::buttonClicked, this, &SMTPConfigWidget::encryptionAbstractButtonChanged);
175 connect(d->ui.kcfg_requiresAuthentication, &QCheckBox::toggled, this, &SMTPConfigWidget::ensureValidAuthSelection);
176 connect(d->ui.kcfg_storePassword, &QCheckBox::toggled, this, &SMTPConfigWidget::enablePasswordLine);
177 if (!d->transport->isValid()) {
178 checkHighestEnabledButton(d->encryptionGroup);
179 }
180
181 // load the password
182 d->transport->updatePasswordState();
183 if (d->transport->isComplete()) {
184 d->ui.password->setPassword(d->transport->password());
185 } else {
186 if (d->transport->requiresAuthentication()) {
188 }
189 }
190
191 hostNameChanged(d->transport->host());
192
193 const KPluginMetaData editWidgetPlugin(QStringLiteral("pim6/mailtransportactivities/kmailtransportactivitiesplugin"));
194
195 const auto result = KPluginFactory::instantiatePlugin<MailTransport::TransportActivitiesAbstractPlugin>(editWidgetPlugin);
196 if (result) {
197 mTransportActivitiesPlugin = result.plugin;
198 }
199 if (mTransportActivitiesPlugin) {
200 d->ui.tabWidget->addTab(mTransportActivitiesPlugin, i18n("Activities"));
201 TransportActivitiesAbstractPlugin::ActivitySettings settings{
202 d->transport->activities(),
203 d->transport->activitiesEnabled(),
204 };
205 mTransportActivitiesPlugin->setActivitiesSettings(settings);
206 }
207}
208
209void SMTPConfigWidget::enablePasswordLine()
210{
212 d->enablePasswordLine();
213}
214
215void SMTPConfigWidget::checkSmtpCapabilities()
216{
218
219 d->serverTest = new ServerTest(this);
220 d->serverTest->setProtocol(SMTP_PROTOCOL);
221 d->serverTest->setServer(d->ui.kcfg_host->text().trimmed());
222 if (d->ui.kcfg_specifyHostname->isChecked()) {
223 d->serverTest->setFakeHostname(d->ui.kcfg_localHostname->text());
224 }
225 QAbstractButton *encryptionChecked = d->encryptionGroup->checkedButton();
226 if (encryptionChecked == d->ui.encryptionNone) {
227 d->serverTest->setPort(Transport::EnumEncryption::None, d->ui.kcfg_port->value());
228 } else if (encryptionChecked == d->ui.encryptionSsl) {
229 d->serverTest->setPort(Transport::EnumEncryption::SSL, d->ui.kcfg_port->value());
230 }
231 d->serverTest->setProgressBar(d->ui.checkCapabilitiesProgress);
232 d->ui.checkCapabilitiesStack->setCurrentIndex(1);
233 qApp->setOverrideCursor(Qt::BusyCursor);
234
235 connect(d->serverTest, &ServerTest::finished, this, &SMTPConfigWidget::slotTestFinished);
236 connect(d->serverTest, &ServerTest::finished, qApp, []() {
237 qApp->restoreOverrideCursor();
238 });
239 d->ui.checkCapabilities->setEnabled(false);
240 d->serverTest->start();
241 d->serverTestFailed = false;
242}
243
245{
247 Q_ASSERT(d->manager);
248 d->manager->updateSettings();
249 if (!d->ui.kcfg_storePassword->isChecked() && d->ui.kcfg_requiresAuthentication->isChecked()) {
250 // Delete stored password
251 TransportManager::self()->removePasswordFromWallet(d->transport->id());
252 }
253 d->transport->setPassword(d->ui.password->password());
254
255 KConfigGroup group(d->transport->config(), d->transport->currentGroup());
256 const int index = d->ui.authCombo->currentIndex();
257 if (index >= 0) {
258 group.writeEntry("authtype", d->ui.authCombo->itemData(index).toInt());
259 }
260
261 if (d->ui.encryptionNone->isChecked()) {
262 d->transport->setEncryption(Transport::EnumEncryption::None);
263 } else if (d->ui.encryptionSsl->isChecked()) {
264 d->transport->setEncryption(Transport::EnumEncryption::SSL);
265 } else if (d->ui.encryptionTls->isChecked()) {
266 d->transport->setEncryption(Transport::EnumEncryption::TLS);
267 }
268
269 if (mTransportActivitiesPlugin) {
270 const TransportActivitiesAbstractPlugin::ActivitySettings settings = mTransportActivitiesPlugin->activitiesSettings();
271 d->transport->setActivities(settings.activities);
272 d->transport->setActivitiesEnabled(settings.enabled);
273 }
274
276}
277
278void SMTPConfigWidget::passwordsLoaded()
279{
281
282 // Load the password from the original to our cloned copy
283 d->transport->updatePasswordState();
284
285 if (d->ui.password->password().isEmpty()) {
286 d->ui.password->setPassword(d->transport->password());
287 }
288}
289
290void SMTPConfigWidget::slotTestFinished(const QList<int> &results)
291{
293
294 d->ui.checkCapabilitiesStack->setCurrentIndex(0);
295
296 d->ui.checkCapabilities->setEnabled(true);
297 d->serverTest->deleteLater();
298
299 // If the servertest did not find any usable authentication modes, assume the
300 // connection failed and don't disable any of the radioboxes.
301 if (results.isEmpty()) {
303 i18n("Failed to check capabilities. Please verify port and authentication mode."),
304 i18nc("@title:window", "Check Capabilities Failed"));
305 d->serverTestFailed = true;
306 d->serverTest->deleteLater();
307 return;
308 }
309
310 // encryption method
311 d->ui.encryptionNone->setEnabled(results.contains(Transport::EnumEncryption::None));
312 d->ui.encryptionSsl->setEnabled(results.contains(Transport::EnumEncryption::SSL));
313 d->ui.encryptionTls->setEnabled(results.contains(Transport::EnumEncryption::TLS));
314 checkHighestEnabledButton(d->encryptionGroup);
315
316 d->noEncCapa = d->serverTest->normalProtocols();
317 if (d->ui.encryptionTls->isEnabled()) {
318 d->tlsCapa = d->serverTest->tlsProtocols();
319 } else {
320 d->tlsCapa.clear();
321 }
322 d->sslCapa = d->serverTest->secureProtocols();
323 d->updateAuthCapbilities();
324 // Show correct port from capabilities.
325 if (d->ui.encryptionSsl->isEnabled()) {
326 const int portValue = d->serverTest->port(Transport::EnumEncryption::SSL);
327 d->ui.kcfg_port->setValue(portValue == -1 ? SMTPS_PORT : portValue);
328 } else if (d->ui.encryptionNone->isEnabled()) {
329 const int portValue = d->serverTest->port(Transport::EnumEncryption::None);
330 d->ui.kcfg_port->setValue(portValue == -1 ? SMTP_PORT : portValue);
331 }
332 d->serverTest->deleteLater();
333}
334
335void SMTPConfigWidget::hostNameChanged(const QString &text)
336{
337 // TODO: really? is this done at every change? wtf
338
340
341 // sanitize hostname...
342 const int pos = d->ui.kcfg_host->cursorPosition();
343 d->ui.kcfg_host->blockSignals(true);
344 d->ui.kcfg_host->setText(text.trimmed());
345 d->ui.kcfg_host->blockSignals(false);
346 d->ui.kcfg_host->setCursorPosition(pos);
347
348 d->resetAuthCapabilities();
349 if (d->encryptionGroup) {
350 for (int i = 0; i < d->encryptionGroup->buttons().count(); ++i) {
351 d->encryptionGroup->buttons().at(i)->setEnabled(true);
352 }
353 }
354}
355
356void SMTPConfigWidget::ensureValidAuthSelection()
357{
359
360 // adjust available authentication methods
361 d->updateAuthCapbilities();
362 d->enablePasswordLine();
363}
364
365void SMTPConfigWidget::encryptionAbstractButtonChanged(QAbstractButton *button)
366{
368 if (button) {
369 encryptionChanged(d->encryptionGroup->id(button));
370 }
371}
372
373void SMTPConfigWidget::encryptionChanged(int enc)
374{
376 qCDebug(MAILTRANSPORT_SMTP_LOG) << enc;
377
378 // adjust port
379 if (enc == Transport::EnumEncryption::SSL) {
380 if (d->ui.kcfg_port->value() == SMTP_PORT) {
381 d->ui.kcfg_port->setValue(SMTPS_PORT);
382 }
383 } else {
384 if (d->ui.kcfg_port->value() == SMTPS_PORT) {
385 d->ui.kcfg_port->setValue(SMTP_PORT);
386 }
387 }
388
389 ensureValidAuthSelection();
390}
391
392#include "moc_smtpconfigwidget.cpp"
static Q_INVOKABLE bool authorize(const QString &action)
void writeEntry(const char *key, const char *value, WriteConfigFlags pFlags=Normal)
This class can be used to test certain server to see if they support stuff.
Definition servertest.h:30
void finished(const QList< int > &)
This will be emitted when the test is done.
virtual void apply()
Saves the transport's settings.
void loadPasswordsAsync()
Tries to load passwords asynchronously from KWallet if needed.
void passwordsChanged()
Emitted when passwords have been loaded from the wallet.
static TransportManager * self()
Returns the TransportManager instance.
Represents the settings of a specific mail transport.
Definition transport.h:33
QString authenticationTypeString() const
Returns a string representation of the authentication type.
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
Internal file containing constant definitions etc.
void init(KXmlGuiWindow *window, KGameDifficulty *difficulty=nullptr)
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
void clicked(bool checked)
void toggled(bool checked)
void buttonClicked(QAbstractButton *button)
QList< QAbstractButton * > buttons() const const
void addItem(const QIcon &icon, const QString &text, const QVariant &userData)
void textChanged(const QString &text)
void clear()
bool contains(const AT &value) const const
bool isEmpty() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QString trimmed() const const
BusyCursor
bool isEnabled() const const
Q_D(Todo)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Oct 11 2024 12:15:51 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.