kde-playground/kdepimlibs/mailtransport/smtpconfigwidget.cpp
2015-09-23 10:02:40 +00:00

375 lines
11 KiB
C++

/*
Copyright (c) 2009 Constantin Berzan <exit3219@gmail.com>
Based on MailTransport code by:
Copyright (c) 2006 - 2007 Volker Krause <vkrause@kde.org>
Copyright (c) 2007 KovoKs <kovoks@kovoks.nl>
Based on KMail code by:
Copyright (c) 2001-2002 Michael Haeckel <haeckel@kde.org>
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 <QAbstractButton>
#include <QButtonGroup>
#include <KProtocolInfo>
#include <KDebug>
#include <KMessageBox>
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<int> 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<int> 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<int>)),
SLOT(slotFinished(QList<int>)));
connect( d->serverTest, SIGNAL(finished(QList<int>)),
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<int> 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();
}