MailTransport

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

KDE's Doxygen guidelines are available online.