/* Copyright (c) 2009 Constantin Berzan Based on MailTransport code by: Copyright (c) 2006 - 2007 Volker Krause Copyright (c) 2007 KovoKs Based on KMail code by: Copyright (c) 2001-2002 Michael Haeckel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "smtpconfigwidget.h" #include "transportconfigwidget_p.h" #include "transport.h" #include "transportmanager.h" #include "servertest.h" #include "mailtransport_defs.h" #include "ui_smtpsettings_desktop.h" #include #include #include #include #include namespace { // TODO: is this really necessary? class BusyCursorHelper : public QObject { public: inline BusyCursorHelper( QObject *parent ) : QObject( parent ) { #ifndef QT_NO_CURSOR qApp->setOverrideCursor( Qt::BusyCursor ); #endif } inline ~BusyCursorHelper() { #ifndef QT_NO_CURSOR qApp->restoreOverrideCursor(); #endif } }; } using namespace MailTransport; class MailTransport::SMTPConfigWidgetPrivate : public TransportConfigWidgetPrivate { public: ::Ui::SMTPSettings ui; ServerTest *serverTest; QButtonGroup *encryptionGroup; // detected authentication capabilities QList noEncCapa, sslCapa, tlsCapa; bool serverTestFailed; static void addAuthenticationItem( KComboBox *combo, int authenticationType ) { combo->addItem( Transport::authenticationTypeString( authenticationType ), QVariant( authenticationType ) ); } void resetAuthCapabilities() { noEncCapa.clear(); noEncCapa << Transport::EnumAuthenticationType::LOGIN << Transport::EnumAuthenticationType::PLAIN << Transport::EnumAuthenticationType::CRAM_MD5 << Transport::EnumAuthenticationType::DIGEST_MD5 << Transport::EnumAuthenticationType::NTLM << Transport::EnumAuthenticationType::GSSAPI; sslCapa = tlsCapa = noEncCapa; updateAuthCapbilities(); } void updateAuthCapbilities() { if ( serverTestFailed ) { return; } QList capa = noEncCapa; if ( ui.ssl->isChecked() ) { capa = sslCapa; } else if ( ui.tls->isChecked() ) { capa = tlsCapa; } ui.authCombo->clear(); foreach ( int authType, capa ) { addAuthenticationItem( ui.authCombo, authType ); } if ( transport->isValid() ) { const int idx = ui.authCombo->findData( transport->authenticationType() ); if ( idx != -1 ) { ui.authCombo->setCurrentIndex( idx ); } } if ( capa.count() == 0 ) { ui.noAuthPossible->setVisible( true ); ui.kcfg_requiresAuthentication->setChecked( false ); ui.kcfg_requiresAuthentication->setEnabled( false ); ui.kcfg_requiresAuthentication->setVisible( false ); ui.authCombo->setEnabled( false ); ui.authLabel->setEnabled( false ); } else { ui.noAuthPossible->setVisible( false ); ui.kcfg_requiresAuthentication->setEnabled( true ); ui.kcfg_requiresAuthentication->setVisible( true ); ui.authCombo->setEnabled( true ); ui.authLabel->setEnabled( true ); } } }; SMTPConfigWidget::SMTPConfigWidget( Transport *transport, QWidget *parent ) : TransportConfigWidget( *new SMTPConfigWidgetPrivate, transport, parent ) { init(); } SMTPConfigWidget::SMTPConfigWidget( SMTPConfigWidgetPrivate &dd, Transport *transport, QWidget *parent ) : TransportConfigWidget( dd, transport, parent ) { init(); } static void checkHighestEnabledButton( QButtonGroup *group ) { Q_ASSERT( group ); for ( int i = group->buttons().count() - 1; i >= 0; --i ) { QAbstractButton *b = group->buttons().at( i ); if ( b && b->isEnabled() ) { b->animateClick(); return; } } } void SMTPConfigWidget::init() { Q_D( SMTPConfigWidget ); d->serverTest = 0; connect( TransportManager::self(), SIGNAL(passwordsChanged()), SLOT(passwordsLoaded()) ); d->serverTestFailed = false; d->ui.setupUi( this ); d->manager->addWidget( this ); // otherwise it doesn't find out about these widgets d->manager->updateWidgets(); d->encryptionGroup = new QButtonGroup( this ); d->encryptionGroup->addButton( d->ui.none, Transport::EnumEncryption::None ); d->encryptionGroup->addButton( d->ui.ssl, Transport::EnumEncryption::SSL ); d->encryptionGroup->addButton( d->ui.tls, Transport::EnumEncryption::TLS ); d->resetAuthCapabilities(); if ( KProtocolInfo::capabilities( SMTP_PROTOCOL ).contains( QLatin1String( "SASL" ) ) == 0 ) { d->ui.authCombo->removeItem( d->ui.authCombo->findData( Transport::EnumAuthenticationType::NTLM ) ); d->ui.authCombo->removeItem( d->ui.authCombo->findData( Transport::EnumAuthenticationType::GSSAPI ) ); } connect( d->ui.checkCapabilities, SIGNAL(clicked()), SLOT(checkSmtpCapabilities()) ); connect( d->ui.kcfg_host, SIGNAL(textChanged(QString)), SLOT(hostNameChanged(QString)) ); connect( d->encryptionGroup, SIGNAL(buttonClicked(int)), SLOT(encryptionChanged(int)) ); connect( d->ui.kcfg_requiresAuthentication, SIGNAL(toggled(bool)), SLOT(ensureValidAuthSelection()) ); if ( !d->transport->isValid() ) { checkHighestEnabledButton( d->encryptionGroup ); } // load the password d->transport->updatePasswordState(); if ( d->transport->isComplete() ) { d->ui.password->setText( d->transport->password() ); } else { if ( d->transport->requiresAuthentication() ) { TransportManager::self()->loadPasswordsAsync(); } } hostNameChanged( d->transport->host() ); #ifdef KDEPIM_MOBILE_UI d->ui.smtpSettingsGroupBox->hide(); #endif } void SMTPConfigWidget::checkSmtpCapabilities() { Q_D( SMTPConfigWidget ); d->serverTest = new ServerTest( this ); d->serverTest->setProtocol( SMTP_PROTOCOL ); d->serverTest->setServer( d->ui.kcfg_host->text().trimmed() ); if ( d->ui.kcfg_specifyHostname->isChecked() ) { d->serverTest->setFakeHostname( d->ui.kcfg_localHostname->text() ); } QAbstractButton *encryptionChecked = d->encryptionGroup->checkedButton(); if (encryptionChecked == d->ui.none) { d->serverTest->setPort( Transport::EnumEncryption::None, d->ui.kcfg_port->value()); } else if (encryptionChecked == d->ui.ssl) { d->serverTest->setPort( Transport::EnumEncryption::SSL, d->ui.kcfg_port->value()); } d->serverTest->setProgressBar( d->ui.checkCapabilitiesProgress ); d->ui.checkCapabilitiesStack->setCurrentIndex( 1 ); BusyCursorHelper *busyCursorHelper = new BusyCursorHelper( d->serverTest ); connect( d->serverTest, SIGNAL(finished(QList)), SLOT(slotFinished(QList))); connect( d->serverTest, SIGNAL(finished(QList)), busyCursorHelper, SLOT(deleteLater()) ); d->ui.checkCapabilities->setEnabled( false ); d->serverTest->start(); d->serverTestFailed = false; } void SMTPConfigWidget::apply() { Q_D( SMTPConfigWidget ); Q_ASSERT( d->manager ); d->manager->updateSettings(); d->transport->setPassword( d->ui.password->text() ); KConfigGroup group( d->transport->config(), d->transport->currentGroup() ); const int index = d->ui.authCombo->currentIndex(); if ( index >= 0 ) { group.writeEntry( "authtype", d->ui.authCombo->itemData( index ).toInt() ); } TransportConfigWidget::apply(); } void SMTPConfigWidget::passwordsLoaded() { Q_D( SMTPConfigWidget ); // Load the password from the original to our cloned copy d->transport->updatePasswordState(); if ( d->ui.password->text().isEmpty() ) { d->ui.password->setText( d->transport->password() ); } } // TODO rename void SMTPConfigWidget::slotFinished( QList results ) { Q_D( SMTPConfigWidget ); d->ui.checkCapabilitiesStack->setCurrentIndex( 0 ); d->ui.checkCapabilities->setEnabled( true ); d->serverTest->deleteLater(); // If the servertest did not find any useable authentication modes, assume the // connection failed and don't disable any of the radioboxes. if ( results.isEmpty() ) { KMessageBox::error(this, i18n("Failed to check capabilities. Please verify port and authentication mode."), i18n("Check Capabilities Failed")); d->serverTestFailed = true; d->serverTest->deleteLater(); return; } // encryption method d->ui.none->setEnabled( results.contains( Transport::EnumEncryption::None ) ); d->ui.ssl->setEnabled( results.contains( Transport::EnumEncryption::SSL ) ); d->ui.tls->setEnabled( results.contains( Transport::EnumEncryption::TLS ) ); checkHighestEnabledButton( d->encryptionGroup ); d->noEncCapa = d->serverTest->normalProtocols(); if ( d->ui.tls->isEnabled() ) { d->tlsCapa = d->serverTest->tlsProtocols(); } else { d->tlsCapa.clear(); } d->sslCapa = d->serverTest->secureProtocols(); d->updateAuthCapbilities(); //Show correct port from capabilities. if (d->ui.ssl->isEnabled()) { const int portValue = d->serverTest->port(Transport::EnumEncryption::SSL); d->ui.kcfg_port->setValue(portValue == -1 ? SMTPS_PORT : portValue); } else if (d->ui.none->isEnabled()) { const int portValue = d->serverTest->port(Transport::EnumEncryption::None); d->ui.kcfg_port->setValue(portValue == -1 ? SMTP_PORT : portValue); } d->serverTest->deleteLater(); } void SMTPConfigWidget::hostNameChanged( const QString &text ) { // TODO: really? is this done at every change? wtf Q_D( SMTPConfigWidget ); // sanitize hostname... int pos = d->ui.kcfg_host->cursorPosition(); d->ui.kcfg_host->blockSignals( true ); d->ui.kcfg_host->setText( text.trimmed() ); d->ui.kcfg_host->blockSignals( false ); d->ui.kcfg_host->setCursorPosition( pos ); d->resetAuthCapabilities(); for ( int i = 0; d->encryptionGroup && i < d->encryptionGroup->buttons().count(); i++ ) { d->encryptionGroup->buttons().at( i )->setEnabled( true ); } } void SMTPConfigWidget::ensureValidAuthSelection() { Q_D( SMTPConfigWidget ); // adjust available authentication methods d->updateAuthCapbilities(); } void SMTPConfigWidget::encryptionChanged( int enc ) { Q_D( SMTPConfigWidget ); kDebug() << enc; // adjust port if ( enc == Transport::EnumEncryption::SSL ) { if ( d->ui.kcfg_port->value() == SMTP_PORT ) { d->ui.kcfg_port->setValue( SMTPS_PORT ); } } else { if ( d->ui.kcfg_port->value() == SMTPS_PORT ) { d->ui.kcfg_port->setValue( SMTP_PORT ); } } ensureValidAuthSelection(); }