1 | /* |
2 | Copyright (c) 2009 Constantin Berzan <exit3219@gmail.com> |
3 | |
4 | Based on MailTransport code by: |
5 | Copyright (c) 2006 - 2007 Volker Krause <vkrause@kde.org> |
6 | Copyright (c) 2007 KovoKs <kovoks@kovoks.nl> |
7 | |
8 | Based on KMail code by: |
9 | Copyright (c) 2001-2002 Michael Haeckel <haeckel@kde.org> |
10 | |
11 | This library is free software; you can redistribute it and/or modify it |
12 | under the terms of the GNU Library General Public License as published by |
13 | the Free Software Foundation; either version 2 of the License, or (at your |
14 | option) any later version. |
15 | |
16 | This library is distributed in the hope that it will be useful, but WITHOUT |
17 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
18 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public |
19 | License for more details. |
20 | |
21 | You should have received a copy of the GNU Library General Public License |
22 | along with this library; see the file COPYING.LIB. If not, write to the |
23 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
24 | 02110-1301, USA. |
25 | */ |
26 | |
27 | #include "smtpconfigwidget.h" |
28 | #include "transportconfigwidget_p.h" |
29 | #include "transport.h" |
30 | #include "transportmanager.h" |
31 | #include "servertest.h" |
32 | #include "mailtransport_defs.h" |
33 | |
34 | #ifndef KDEPIM_MOBILE_UI |
35 | #include "ui_smtpsettings_desktop.h" |
36 | #else |
37 | #include "ui_smtpsettings_mobile.h" |
38 | #endif |
39 | |
40 | #include <QAbstractButton> |
41 | #include <QButtonGroup> |
42 | |
43 | #include <KProtocolInfo> |
44 | #include <KDebug> |
45 | #include <KMessageBox> |
46 | |
47 | namespace { |
48 | |
49 | // TODO: is this really necessary? |
50 | class BusyCursorHelper : public QObject |
51 | { |
52 | public: |
53 | inline BusyCursorHelper( QObject *parent ) : QObject( parent ) |
54 | { |
55 | #ifndef QT_NO_CURSOR |
56 | qApp->setOverrideCursor( Qt::BusyCursor ); |
57 | #endif |
58 | } |
59 | |
60 | inline ~BusyCursorHelper() |
61 | { |
62 | #ifndef QT_NO_CURSOR |
63 | qApp->restoreOverrideCursor(); |
64 | #endif |
65 | } |
66 | }; |
67 | |
68 | } |
69 | |
70 | using namespace MailTransport; |
71 | |
72 | class MailTransport::SMTPConfigWidgetPrivate : public TransportConfigWidgetPrivate |
73 | { |
74 | public: |
75 | ::Ui::SMTPSettings ui; |
76 | |
77 | ServerTest *serverTest; |
78 | QButtonGroup *encryptionGroup; |
79 | |
80 | // detected authentication capabilities |
81 | QList<int> noEncCapa, sslCapa, tlsCapa; |
82 | |
83 | bool serverTestFailed; |
84 | |
85 | static void addAuthenticationItem( KComboBox *combo, |
86 | int authenticationType ) |
87 | { |
88 | combo->addItem( Transport::authenticationTypeString( authenticationType ), |
89 | QVariant( authenticationType ) ); |
90 | } |
91 | |
92 | void resetAuthCapabilities() |
93 | { |
94 | noEncCapa.clear(); |
95 | noEncCapa << Transport::EnumAuthenticationType::LOGIN |
96 | << Transport::EnumAuthenticationType::PLAIN |
97 | << Transport::EnumAuthenticationType::CRAM_MD5 |
98 | << Transport::EnumAuthenticationType::DIGEST_MD5 |
99 | << Transport::EnumAuthenticationType::NTLM |
100 | << Transport::EnumAuthenticationType::GSSAPI; |
101 | sslCapa = tlsCapa = noEncCapa; |
102 | updateAuthCapbilities(); |
103 | |
104 | } |
105 | |
106 | void updateAuthCapbilities() |
107 | { |
108 | if ( serverTestFailed ) { |
109 | return; |
110 | } |
111 | |
112 | QList<int> capa = noEncCapa; |
113 | if ( ui.ssl->isChecked() ) { |
114 | capa = sslCapa; |
115 | } else if ( ui.tls->isChecked() ) { |
116 | capa = tlsCapa; |
117 | } |
118 | |
119 | ui.authCombo->clear(); |
120 | foreach ( int authType, capa ) { |
121 | addAuthenticationItem( ui.authCombo, authType ); |
122 | } |
123 | |
124 | if ( transport->isValid() ) { |
125 | const int idx = ui.authCombo->findData( transport->authenticationType() ); |
126 | |
127 | if ( idx != -1 ) { |
128 | ui.authCombo->setCurrentIndex( idx ); |
129 | } |
130 | } |
131 | |
132 | if ( capa.count() == 0 ) { |
133 | ui.noAuthPossible->setVisible( true ); |
134 | ui.kcfg_requiresAuthentication->setChecked( false ); |
135 | ui.kcfg_requiresAuthentication->setEnabled( false ); |
136 | ui.kcfg_requiresAuthentication->setVisible( false ); |
137 | ui.authCombo->setEnabled( false ); |
138 | ui.authLabel->setEnabled( false ); |
139 | } else { |
140 | ui.noAuthPossible->setVisible( false ); |
141 | ui.kcfg_requiresAuthentication->setEnabled( true ); |
142 | ui.kcfg_requiresAuthentication->setVisible( true ); |
143 | ui.authCombo->setEnabled( true ); |
144 | ui.authLabel->setEnabled( true ); |
145 | } |
146 | } |
147 | }; |
148 | |
149 | SMTPConfigWidget::SMTPConfigWidget( Transport *transport, QWidget *parent ) |
150 | : TransportConfigWidget( *new SMTPConfigWidgetPrivate, transport, parent ) |
151 | { |
152 | init(); |
153 | } |
154 | |
155 | SMTPConfigWidget::SMTPConfigWidget( SMTPConfigWidgetPrivate &dd, |
156 | Transport *transport, QWidget *parent ) |
157 | : TransportConfigWidget( dd, transport, parent ) |
158 | { |
159 | init(); |
160 | } |
161 | |
162 | static void checkHighestEnabledButton( QButtonGroup *group ) |
163 | { |
164 | Q_ASSERT( group ); |
165 | |
166 | for ( int i = group->buttons().count() - 1; i >= 0; --i ) { |
167 | QAbstractButton *b = group->buttons().at( i ); |
168 | if ( b && b->isEnabled() ) { |
169 | b->animateClick(); |
170 | return; |
171 | } |
172 | } |
173 | } |
174 | |
175 | void SMTPConfigWidget::init() |
176 | { |
177 | Q_D( SMTPConfigWidget ); |
178 | d->serverTest = 0; |
179 | |
180 | connect( TransportManager::self(), SIGNAL(passwordsChanged()), |
181 | SLOT(passwordsLoaded()) ); |
182 | |
183 | d->serverTestFailed = false; |
184 | |
185 | d->ui.setupUi( this ); |
186 | d->manager->addWidget( this ); // otherwise it doesn't find out about these widgets |
187 | d->manager->updateWidgets(); |
188 | |
189 | d->encryptionGroup = new QButtonGroup( this ); |
190 | d->encryptionGroup->addButton( d->ui.none, Transport::EnumEncryption::None ); |
191 | d->encryptionGroup->addButton( d->ui.ssl, Transport::EnumEncryption::SSL ); |
192 | d->encryptionGroup->addButton( d->ui.tls, Transport::EnumEncryption::TLS ); |
193 | |
194 | d->resetAuthCapabilities(); |
195 | |
196 | if ( KProtocolInfo::capabilities( SMTP_PROTOCOL ).contains( QLatin1String( "SASL" ) ) == 0 ) { |
197 | d->ui.authCombo->removeItem( d->ui.authCombo->findData( |
198 | Transport::EnumAuthenticationType::NTLM ) ); |
199 | d->ui.authCombo->removeItem( d->ui.authCombo->findData( |
200 | Transport::EnumAuthenticationType::GSSAPI ) ); |
201 | } |
202 | |
203 | connect( d->ui.checkCapabilities, SIGNAL(clicked()), |
204 | SLOT(checkSmtpCapabilities()) ); |
205 | connect( d->ui.kcfg_host, SIGNAL(textChanged(QString)), |
206 | SLOT(hostNameChanged(QString)) ); |
207 | connect( d->encryptionGroup, SIGNAL(buttonClicked(int)), |
208 | SLOT(encryptionChanged(int)) ); |
209 | connect( d->ui.kcfg_requiresAuthentication, SIGNAL(toggled(bool)), |
210 | SLOT(ensureValidAuthSelection()) ); |
211 | |
212 | if ( !d->transport->isValid() ) { |
213 | checkHighestEnabledButton( d->encryptionGroup ); |
214 | } |
215 | |
216 | // load the password |
217 | d->transport->updatePasswordState(); |
218 | if ( d->transport->isComplete() ) { |
219 | d->ui.password->setText( d->transport->password() ); |
220 | } else { |
221 | if ( d->transport->requiresAuthentication() ) { |
222 | TransportManager::self()->loadPasswordsAsync(); |
223 | } |
224 | } |
225 | |
226 | hostNameChanged( d->transport->host() ); |
227 | |
228 | #ifdef KDEPIM_MOBILE_UI |
229 | d->ui.smtpSettingsGroupBox->hide(); |
230 | #endif |
231 | } |
232 | |
233 | void SMTPConfigWidget::checkSmtpCapabilities() |
234 | { |
235 | Q_D( SMTPConfigWidget ); |
236 | |
237 | d->serverTest = new ServerTest( this ); |
238 | d->serverTest->setProtocol( SMTP_PROTOCOL ); |
239 | d->serverTest->setServer( d->ui.kcfg_host->text().trimmed() ); |
240 | if ( d->ui.kcfg_specifyHostname->isChecked() ) { |
241 | d->serverTest->setFakeHostname( d->ui.kcfg_localHostname->text() ); |
242 | } |
243 | QAbstractButton *encryptionChecked = d->encryptionGroup->checkedButton(); |
244 | if (encryptionChecked == d->ui.none) { |
245 | d->serverTest->setPort( Transport::EnumEncryption::None, d->ui.kcfg_port->value()); |
246 | } else if (encryptionChecked == d->ui.ssl) { |
247 | d->serverTest->setPort( Transport::EnumEncryption::SSL, d->ui.kcfg_port->value()); |
248 | } |
249 | d->serverTest->setProgressBar( d->ui.checkCapabilitiesProgress ); |
250 | d->ui.checkCapabilitiesStack->setCurrentIndex( 1 ); |
251 | BusyCursorHelper *busyCursorHelper = new BusyCursorHelper( d->serverTest ); |
252 | |
253 | connect( d->serverTest, SIGNAL(finished(QList<int>)), |
254 | SLOT(slotFinished(QList<int>))); |
255 | connect( d->serverTest, SIGNAL(finished(QList<int>)), |
256 | busyCursorHelper, SLOT(deleteLater()) ); |
257 | d->ui.checkCapabilities->setEnabled( false ); |
258 | d->serverTest->start(); |
259 | d->serverTestFailed = false; |
260 | } |
261 | |
262 | void SMTPConfigWidget::apply() |
263 | { |
264 | Q_D( SMTPConfigWidget ); |
265 | Q_ASSERT( d->manager ); |
266 | d->manager->updateSettings(); |
267 | d->transport->setPassword( d->ui.password->text() ); |
268 | |
269 | KConfigGroup group( d->transport->config(), d->transport->currentGroup() ); |
270 | const int index = d->ui.authCombo->currentIndex(); |
271 | if ( index >= 0 ) { |
272 | group.writeEntry( "authtype" , d->ui.authCombo->itemData( index ).toInt() ); |
273 | } |
274 | |
275 | TransportConfigWidget::apply(); |
276 | } |
277 | |
278 | void SMTPConfigWidget::passwordsLoaded() |
279 | { |
280 | Q_D( SMTPConfigWidget ); |
281 | |
282 | // Load the password from the original to our cloned copy |
283 | d->transport->updatePasswordState(); |
284 | |
285 | if ( d->ui.password->text().isEmpty() ) { |
286 | d->ui.password->setText( d->transport->password() ); |
287 | } |
288 | } |
289 | |
290 | // TODO rename |
291 | void SMTPConfigWidget::slotFinished( QList<int> results ) |
292 | { |
293 | Q_D( SMTPConfigWidget ); |
294 | |
295 | d->ui.checkCapabilitiesStack->setCurrentIndex( 0 ); |
296 | |
297 | d->ui.checkCapabilities->setEnabled( true ); |
298 | d->serverTest->deleteLater(); |
299 | |
300 | // If the servertest did not find any useable authentication modes, assume the |
301 | // connection failed and don't disable any of the radioboxes. |
302 | if ( results.isEmpty() ) { |
303 | KMessageBox::error(this, i18n("Failed to check capabilities. Please verify port and authentication mode." ), i18n("Check Capabilities Failed" )); |
304 | d->serverTestFailed = true; |
305 | d->serverTest->deleteLater(); |
306 | return; |
307 | } |
308 | |
309 | // encryption method |
310 | d->ui.none->setEnabled( results.contains( Transport::EnumEncryption::None ) ); |
311 | d->ui.ssl->setEnabled( results.contains( Transport::EnumEncryption::SSL ) ); |
312 | d->ui.tls->setEnabled( results.contains( Transport::EnumEncryption::TLS ) ); |
313 | checkHighestEnabledButton( d->encryptionGroup ); |
314 | |
315 | d->noEncCapa = d->serverTest->normalProtocols(); |
316 | if ( d->ui.tls->isEnabled() ) { |
317 | d->tlsCapa = d->serverTest->tlsProtocols(); |
318 | } else { |
319 | d->tlsCapa.clear(); |
320 | } |
321 | d->sslCapa = d->serverTest->secureProtocols(); |
322 | d->updateAuthCapbilities(); |
323 | //Show correct port from capabilities. |
324 | if (d->ui.ssl->isEnabled()) { |
325 | const int portValue = d->serverTest->port(Transport::EnumEncryption::SSL); |
326 | d->ui.kcfg_port->setValue(portValue == -1 ? SMTPS_PORT : portValue); |
327 | } else if (d->ui.none->isEnabled()) { |
328 | const int portValue = d->serverTest->port(Transport::EnumEncryption::None); |
329 | d->ui.kcfg_port->setValue(portValue == -1 ? SMTP_PORT : portValue); |
330 | } |
331 | d->serverTest->deleteLater(); |
332 | } |
333 | |
334 | void SMTPConfigWidget::hostNameChanged( const QString &text ) |
335 | { |
336 | // TODO: really? is this done at every change? wtf |
337 | |
338 | Q_D( SMTPConfigWidget ); |
339 | |
340 | // sanitize hostname... |
341 | int pos = d->ui.kcfg_host->cursorPosition(); |
342 | d->ui.kcfg_host->blockSignals( true ); |
343 | d->ui.kcfg_host->setText( text.trimmed() ); |
344 | d->ui.kcfg_host->blockSignals( false ); |
345 | d->ui.kcfg_host->setCursorPosition( pos ); |
346 | |
347 | d->resetAuthCapabilities(); |
348 | for ( int i = 0; d->encryptionGroup && i < d->encryptionGroup->buttons().count(); i++ ) { |
349 | d->encryptionGroup->buttons().at( i )->setEnabled( true ); |
350 | } |
351 | } |
352 | |
353 | void SMTPConfigWidget::ensureValidAuthSelection() |
354 | { |
355 | Q_D( SMTPConfigWidget ); |
356 | |
357 | // adjust available authentication methods |
358 | d->updateAuthCapbilities(); |
359 | } |
360 | |
361 | void SMTPConfigWidget::encryptionChanged( int enc ) |
362 | { |
363 | Q_D( SMTPConfigWidget ); |
364 | kDebug() << enc; |
365 | |
366 | // adjust port |
367 | if ( enc == Transport::EnumEncryption::SSL ) { |
368 | if ( d->ui.kcfg_port->value() == SMTP_PORT ) { |
369 | d->ui.kcfg_port->setValue( SMTPS_PORT ); |
370 | } |
371 | } else { |
372 | if ( d->ui.kcfg_port->value() == SMTPS_PORT ) { |
373 | d->ui.kcfg_port->setValue( SMTP_PORT ); |
374 | } |
375 | } |
376 | |
377 | ensureValidAuthSelection(); |
378 | } |
379 | |
380 | |