[kmailtransport] /: Replace SMTP KIO Slave with KSMTP library

Daniel Vrátil null at kde.org
Mon Jul 31 19:39:09 UTC 2017


Git commit b2198b447ab2c4d048035aeacd71a8b05f3c53df by Daniel Vrátil.
Committed on 31/07/2017 at 19:37.
Pushed by dvratil into branch 'master'.

Replace SMTP KIO Slave with KSMTP library

Instead of using a KIO Slave for sending emails via SMTP, for which
KIO wasn't really designed, use a KSMTP library. This has no
functional or performance impacts, but improves maintainability
of our SMTP code and opens doors to further improvements (like
native Gmail authentication)

Differential Revision: https://phabricator.kde.org/D6879

M  +2    -1    CMakeLists.txt
D  +0    -1    kioslave/.krazy
D  +0    -3    kioslave/CMakeLists.txt
D  +0    -1    kioslave/doc/CMakeLists.txt
D  +0    -3    kioslave/doc/smtp/CMakeLists.txt
D  +0    -23   kioslave/doc/smtp/index.docbook
D  +0    -2    kioslave/src/CMakeLists.txt
D  +0    -55   kioslave/src/common.h
D  +0    -47   kioslave/src/smtp/CMakeLists.txt
D  +0    -2    kioslave/src/smtp/Messages.sh
D  +0    -11   kioslave/src/smtp/TODO
D  +0    -121  kioslave/src/smtp/capabilities.cpp
D  +0    -86   kioslave/src/smtp/capabilities.h
D  +0    -648  kioslave/src/smtp/command.cpp
D  +0    -331  kioslave/src/smtp/command.h
D  +0    -33   kioslave/src/smtp/compliance.txt
D  +0    -88   kioslave/src/smtp/kioslavesession.cpp
D  +0    -49   kioslave/src/smtp/kioslavesession.h
D  +0    -193  kioslave/src/smtp/request.cpp
D  +0    -192  kioslave/src/smtp/request.h
D  +0    -165  kioslave/src/smtp/response.cpp
D  +0    -178  kioslave/src/smtp/response.h
D  +0    -652  kioslave/src/smtp/smtp.cpp
D  +0    -125  kioslave/src/smtp/smtp.h
D  +0    -16   kioslave/src/smtp/smtp.protocol
D  +0    -16   kioslave/src/smtp/smtps.protocol
D  +0    -61   kioslave/src/smtp/smtpsessioninterface.cpp
D  +0    -92   kioslave/src/smtp/smtpsessioninterface.h
D  +0    -71   kioslave/src/smtp/tests/CMakeLists.txt
D  +0    -131  kioslave/src/smtp/tests/fakesession.h
D  +0    -211  kioslave/src/smtp/tests/interactivesmtpserver.cpp
D  +0    -85   kioslave/src/smtp/tests/interactivesmtpserver.h
D  +0    -83   kioslave/src/smtp/tests/requesttest.cpp
D  +0    -37   kioslave/src/smtp/tests/requesttest.h
D  +0    -26   kioslave/src/smtp/tests/test_capabilities.cpp
D  +0    -676  kioslave/src/smtp/tests/test_commands.cpp
D  +0    -89   kioslave/src/smtp/tests/test_headergeneration.cpp
D  +0    -106  kioslave/src/smtp/tests/test_responseparser.cpp
D  +0    -32   kioslave/src/smtp/tests/test_responseparser.h
D  +0    -124  kioslave/src/smtp/transactionstate.cpp
D  +0    -237  kioslave/src/smtp/transactionstate.h
M  +6    -1    src/kmailtransport/plugins/smtp/CMakeLists.txt
A  +19   -0    src/kmailtransport/plugins/smtp/autotests/CMakeLists.txt
A  +232  -0    src/kmailtransport/plugins/smtp/autotests/fakeserver.cpp     [License: LGPL (v2.1+)]
A  +67   -0    src/kmailtransport/plugins/smtp/autotests/fakeserver.h     [License: LGPL (v2.1+)]
A  +132  -0    src/kmailtransport/plugins/smtp/autotests/smtpjobtest.cpp     [License: LGPL (v2+)]
A  +33   -0    src/kmailtransport/plugins/smtp/sessionuiproxy.h     [License: GPL (v2)]
M  +171  -156  src/kmailtransport/plugins/smtp/smtpjob.cpp
M  +4    -4    src/kmailtransport/plugins/smtp/smtpjob.h

https://commits.kde.org/kmailtransport/b2198b447ab2c4d048035aeacd71a8b05f3c53df

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 188c465..8161bbc 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -30,6 +30,7 @@ set(KMAILTRANSPORT_LIB_VERSION ${PIM_VERSION})
 set(KMIME_LIB_VERSION "5.6.40")
 set(AKONADI_LIB_VERSION "5.6.40")
 set(AKONADIMIME_LIB_VERSION "5.6.40")
+set(KSMTP_LIB_VERSION "5.6.40")
 set(CMAKECONFIG_INSTALL_DIR "${KDE_INSTALL_CMAKEPACKAGEDIR}/KF5MailTransport")
 
 ########### Find packages ###########
@@ -42,6 +43,7 @@ find_package(KF5KIO ${KF5_VERSION} CONFIG REQUIRED)
 find_package(KF5Mime ${KMIME_LIB_VERSION} CONFIG REQUIRED)
 find_package(KF5Akonadi ${AKONADI_LIB_VERSION} CONFIG REQUIRED)
 find_package(KF5AkonadiMime ${AKONADIMIME_LIB_VERSION} CONFIG REQUIRED)
+find_package(KPimSMTP ${KSMTP_LIB_VERSION} CONFIG VERSION)
 
 add_definitions("-DQT_NO_CAST_FROM_ASCII -DQT_NO_CAST_TO_ASCII")
 add_definitions(-DQT_NO_NARROWING_CONVERSIONS_IN_CONNECT)
@@ -61,7 +63,6 @@ endif(BUILD_TESTING)
 ########### Targets ###########
 add_subdirectory(cmake)
 add_subdirectory(src)
-add_subdirectory(kioslave)
 
 install( FILES kmailtransport.renamecategories kmailtransport.categories DESTINATION ${KDE_INSTALL_CONFDIR} )
 feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES)
diff --git a/kioslave/.krazy b/kioslave/.krazy
deleted file mode 100644
index 0b16e7f..0000000
--- a/kioslave/.krazy
+++ /dev/null
@@ -1 +0,0 @@
-SKIP /tests/
diff --git a/kioslave/CMakeLists.txt b/kioslave/CMakeLists.txt
deleted file mode 100644
index ec4e2e8..0000000
--- a/kioslave/CMakeLists.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-add_definitions("-DQT_NO_CAST_FROM_ASCII -DQT_NO_CAST_TO_ASCII")
-add_subdirectory(src)
-add_subdirectory(doc)
diff --git a/kioslave/doc/CMakeLists.txt b/kioslave/doc/CMakeLists.txt
deleted file mode 100644
index 1751e50..0000000
--- a/kioslave/doc/CMakeLists.txt
+++ /dev/null
@@ -1 +0,0 @@
-add_subdirectory(smtp)
diff --git a/kioslave/doc/smtp/CMakeLists.txt b/kioslave/doc/smtp/CMakeLists.txt
deleted file mode 100644
index 11d31fa..0000000
--- a/kioslave/doc/smtp/CMakeLists.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-########### install files ###############
-kdoctools_create_handbook(index.docbook INSTALL_DESTINATION ${KDE_INSTALL_DOCBUNDLEDIR}/en SUBDIR kioslave5/smtp)
-
diff --git a/kioslave/doc/smtp/index.docbook b/kioslave/doc/smtp/index.docbook
deleted file mode 100644
index 1939851..0000000
--- a/kioslave/doc/smtp/index.docbook
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE article PUBLIC "-//KDE//DTD DocBook XML V4.5-Based Variant V1.1//EN"
-"dtd/kdedbx45.dtd" [
-<!ENTITY % addindex "IGNORE">
-<!ENTITY % English "INCLUDE" > <!-- change language only here -->
-]>
-	
-<article lang="&language;" id="smtp">
-<title>smtp</title>
-<articleinfo>
-<authorgroup>
-<author>&Ferdinand.Gassauer; &Ferdinand.Gassauer.mail;</author>
-<!-- TRANS:ROLES_OF_TRANSLATORS -->
-</authorgroup>
-</articleinfo>
-<para>
-A protocol to send mail from the client workstation to the mail server.
-</para>
-
-<para> See : <ulink url="http://cr.yp.to/smtp.html">Simple Mail Transfer Protocol </ulink>.
-</para>
-
-</article>
diff --git a/kioslave/src/CMakeLists.txt b/kioslave/src/CMakeLists.txt
deleted file mode 100644
index 50ed732..0000000
--- a/kioslave/src/CMakeLists.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-add_subdirectory(smtp)
-
diff --git a/kioslave/src/common.h b/kioslave/src/common.h
deleted file mode 100644
index 0b581e2..0000000
--- a/kioslave/src/common.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*  This file is part of the KDE project
-    Copyright (C) 2008 Jarosław Staniek <staniek at 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.
-*/
-
-#ifndef _KIOSLAVE_COMMON_H
-#define _KIOSLAVE_COMMON_H
-
-#include <stdio.h>
-#include <QFile>
-#include <QDir>
-#include <QCoreApplication>
-
-extern "C" {
-#include <sasl/sasl.h>
-}
-
-inline bool initSASL()
-{
-#ifdef Q_OS_WIN  //krazy:exclude=cpp
-    for (const auto &path : QCoreApplication::libraryPaths()) {
-        QDir dir(path);
-        if (dir.exists(QStringLiteral("sasl2"))) {
-            auto libInstallPath = QFile::encodeName(dir.absoluteFilePath(QStringLiteral("sasl2")));
-            if (sasl_set_path(SASL_PATH_TYPE_PLUGIN, libInstallPath.data()) != SASL_OK) {
-                fprintf(stderr, "SASL path initialization failed!\n");
-                return false;
-            }
-            break;
-        }
-    }
-#endif
-
-    if (sasl_client_init(NULL) != SASL_OK) {
-        fprintf(stderr, "SASL library initialization failed!\n");
-        return false;
-    }
-    return true;
-}
-
-#endif
diff --git a/kioslave/src/smtp/CMakeLists.txt b/kioslave/src/smtp/CMakeLists.txt
deleted file mode 100644
index e13aa63..0000000
--- a/kioslave/src/smtp/CMakeLists.txt
+++ /dev/null
@@ -1,47 +0,0 @@
-
-
-if (BUILD_TESTING)
-add_subdirectory(tests)
-endif()	
-set(smtp_optional_includes)
-set(smtp_optional_libs)
-
-if (Sasl2_FOUND)
-   set(smtp_optional_includes ${smtp_optional_includes} ${Sasl2_INCLUDE_DIRS})
-   set(smtp_optional_libs     ${smtp_optional_libs}     ${Sasl2_LIBRARIES})
-endif()
-
-
-include_directories(  ${smtp_optional_includes}  )
-
-
-########### next target ###############
-
-set(kio_smtp_PART_SRCS
-   smtp.cpp
-   request.cpp
-   response.cpp
-   capabilities.cpp
-   command.cpp
-   transactionstate.cpp
-   smtpsessioninterface.cpp
-   kioslavesession.cpp
-)
-
-ecm_qt_declare_logging_category(kio_smtp_PART_SRCS HEADER smtp_debug.h IDENTIFIER SMTP_LOG CATEGORY_NAME org.kde.pim.smtp)
-
-add_library(kio_smtp MODULE ${kio_smtp_PART_SRCS})
-
-
-target_link_libraries(kio_smtp  KF5::KIOCore KF5::I18n Qt5::Network ${smtp_optional_libs})
-if (WIN32)
-    target_link_libraries(kio_smtp ws2_32)
-endif()
-set_target_properties(kio_smtp PROPERTIES OUTPUT_NAME "smtp")
-
-install(TARGETS kio_smtp  DESTINATION ${KDE_INSTALL_PLUGINDIR}/kf5/kio/ )
-
-########### install files ###############
-
-install( FILES smtp.protocol smtps.protocol  DESTINATION  ${KDE_INSTALL_KSERVICES5DIR} )
-
diff --git a/kioslave/src/smtp/Messages.sh b/kioslave/src/smtp/Messages.sh
deleted file mode 100644
index c0be647..0000000
--- a/kioslave/src/smtp/Messages.sh
+++ /dev/null
@@ -1,2 +0,0 @@
-#! /usr/bin/env bash
-$XGETTEXT *.cpp -o $podir/kio_smtp.pot
diff --git a/kioslave/src/smtp/TODO b/kioslave/src/smtp/TODO
deleted file mode 100644
index cad79f1..0000000
--- a/kioslave/src/smtp/TODO
+++ /dev/null
@@ -1,11 +0,0 @@
-1. Double check the error handling and review error message in various
-   failure modes.
-2. Implement the CHUNKING extension (rfc 3030; as soon as I find an
-   SMTP server that supports it).
-3. Better error message (translated standard meanings of the known
-   response codes, ENHANCEDSTATUSCODES extension (rfc2034)).
-4. (KIO) MultiPutJob to support pipelining across messages.
-5. Ged rid of slave's header generation after checking who on earth
-   uses that...
-
-and further refactoring to make the code pleasant to look at ;-)
diff --git a/kioslave/src/smtp/capabilities.cpp b/kioslave/src/smtp/capabilities.cpp
deleted file mode 100644
index 489a35c..0000000
--- a/kioslave/src/smtp/capabilities.cpp
+++ /dev/null
@@ -1,121 +0,0 @@
-/*  -*- c++ -*-
-    capabilities.cc
-
-    This file is part of kio_smtp, the KDE SMTP kioslave.
-    Copyright (c) 2003 Marc Mutz <mutz at kde.org>
-
-    This program is free software; you can redistribute it and/or modify it
-    under the terms of the GNU General Public License, version 2, as
-    published by the Free Software Foundation.
-
-    This program 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
-    General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-    In addition, as a special exception, the copyright holders give
-    permission to link the code of this program with any edition of
-    the Qt library by Trolltech AS, Norway (or with modified versions
-    of Qt that use the same license as Qt), and distribute linked
-    combinations including the two.  You must obey the GNU General
-    Public License in all respects for all of the code used other than
-    Qt.  If you modify this file, you may extend this exception to
-    your version of the file, but you are not obligated to do so.  If
-    you do not wish to do so, delete this exception statement from
-    your version.
-*/
-
-#include "capabilities.h"
-#include "response.h"
-
-namespace KioSMTP {
-Capabilities Capabilities::fromResponse(const Response &ehlo)
-{
-    Capabilities c;
-
-    // first, check whether the response was valid and indicates success:
-    if (!ehlo.isOk()
-        || ehlo.code() / 10 != 25     // ### restrict to 250 only?
-        || ehlo.lines().empty()) {
-        return c;
-    }
-
-    QCStringList l = ehlo.lines();
-
-    for (QCStringList::const_iterator it = ++l.constBegin(), end(l.constEnd()); it != end; ++it) {
-        c.add(QString::fromLatin1(*it));
-    }
-
-    return c;
-}
-
-void Capabilities::add(const QString &cap, bool replace)
-{
-    QStringList tokens = cap.toUpper().split(QLatin1Char(' '));
-    if (tokens.empty()) {
-        return;
-    }
-    QString name = tokens.front();
-    tokens.pop_front();
-    add(name, tokens, replace);
-}
-
-void Capabilities::add(const QString &name, const QStringList &args, bool replace)
-{
-    if (replace) {
-        mCapabilities[name] = args;
-    } else {
-        mCapabilities[name] += args;
-    }
-}
-
-QString Capabilities::createSpecialResponse(bool tls) const
-{
-    QStringList result;
-    if (tls) {
-        result.push_back(QStringLiteral("STARTTLS"));
-    }
-    result += saslMethodsQSL();
-    if (have("PIPELINING")) {
-        result.push_back(QStringLiteral("PIPELINING"));
-    }
-    if (have("8BITMIME")) {
-        result.push_back(QStringLiteral("8BITMIME"));
-    }
-    if (have("SIZE")) {
-        bool ok = false;
-        unsigned int size = 0;
-        if (!mCapabilities[QStringLiteral("SIZE")].isEmpty()) {
-            size = mCapabilities[QStringLiteral("SIZE")].front().toUInt(&ok);
-        }
-        if (ok && !size) {
-            result.push_back(QStringLiteral("SIZE=*"));    // any size
-        } else if (ok) {
-            result.push_back(QStringLiteral("SIZE=%1").arg(size));    // fixed max
-        } else {
-            result.push_back(QStringLiteral("SIZE"));    // indetermined
-        }
-    }
-    return result.join(QLatin1Char(' '));
-}
-
-QStringList Capabilities::saslMethodsQSL() const
-{
-    QStringList result;
-    for (QMap<QString, QStringList>::const_iterator it = mCapabilities.begin(), end(mCapabilities.end());
-         it != end; ++it) {
-        if (it.key() == QLatin1String("AUTH")) {
-            result += it.value();
-        } else if (it.key().startsWith(QLatin1String("AUTH="))) {
-            result.push_back(it.key().mid(qstrlen("AUTH=")));
-            result += it.value();
-        }
-    }
-    result.removeDuplicates();
-    return result;
-}
-} // namespace KioSMTP
diff --git a/kioslave/src/smtp/capabilities.h b/kioslave/src/smtp/capabilities.h
deleted file mode 100644
index fac2f9c..0000000
--- a/kioslave/src/smtp/capabilities.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*  -*- c++ -*-
-    capabilities.h
-
-    This file is part of kio_smtp, the KDE SMTP kioslave.
-    Copyright (c) 2003 Marc Mutz <mutz at kde.org>
-
-    This program is free software; you can redistribute it and/or modify it
-    under the terms of the GNU General Public License, version 2, as
-    published by the Free Software Foundation.
-
-    This program 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
-    General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-    In addition, as a special exception, the copyright holders give
-    permission to link the code of this program with any edition of
-    the Qt library by Trolltech AS, Norway (or with modified versions
-    of Qt that use the same license as Qt), and distribute linked
-    combinations including the two.  You must obey the GNU General
-    Public License in all respects for all of the code used other than
-    Qt.  If you modify this file, you may extend this exception to
-    your version of the file, but you are not obligated to do so.  If
-    you do not wish to do so, delete this exception statement from
-    your version.
-*/
-
-#ifndef __KIOSMTP_CAPABILITIES_H__
-#define __KIOSMTP_CAPABILITIES_H__
-
-#include <QMap>
-
-#include <QStringList>
-
-namespace KioSMTP {
-class Response;
-
-class Capabilities
-{
-public:
-    Capabilities()
-    {
-    }
-
-    static Capabilities fromResponse(const Response &response);
-
-    void add(const QString &cap, bool replace = false);
-    void add(const QString &name, const QStringList &args, bool replace = false);
-    void clear()
-    {
-        mCapabilities.clear();
-    }
-
-    bool have(const QString &cap) const
-    {
-        return mCapabilities.find(cap.toUpper()) != mCapabilities.end();
-    }
-
-    bool have(const QByteArray &cap) const
-    {
-        return have(QString::fromLatin1(cap));
-    }
-
-    bool have(const char *cap) const
-    {
-        return have(QString::fromLatin1(cap));
-    }
-
-    QString asMetaDataString() const;
-
-    QString authMethodMetaData() const;
-
-    QString createSpecialResponse(bool tls) const;
-
-    QStringList saslMethodsQSL() const;
-private:
-
-    QMap<QString, QStringList> mCapabilities;
-};
-} // namespace KioSMTP
-
-#endif // __KIOSMTP_CAPABILITIES_H__
diff --git a/kioslave/src/smtp/command.cpp b/kioslave/src/smtp/command.cpp
deleted file mode 100644
index 60d0bb7..0000000
--- a/kioslave/src/smtp/command.cpp
+++ /dev/null
@@ -1,648 +0,0 @@
-/*  -*- c++ -*-
-    command.cc
-
-    This file is part of kio_smtp, the KDE SMTP kioslave.
-    Copyright (c) 2003 Marc Mutz <mutz at kde.org>
-
-    This program is free software; you can redistribute it and/or modify it
-    under the terms of the GNU General Public License, version 2, as
-    published by the Free Software Foundation.
-
-    This program 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
-    General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-    In addition, as a special exception, the copyright holders give
-    permission to link the code of this program with any edition of
-    the Qt library by Trolltech AS, Norway (or with modified versions
-    of Qt that use the same license as Qt), and distribute linked
-    combinations including the two.  You must obey the GNU General
-    Public License in all respects for all of the code used other than
-    Qt.  If you modify this file, you may extend this exception to
-    your version of the file, but you are not obligated to do so.  If
-    you do not wish to do so, delete this exception statement from
-    your version.
-*/
-
-#include "command.h"
-#include "smtp_debug.h"
-
-#include "smtpsessioninterface.h"
-#include "response.h"
-#include "transactionstate.h"
-
-#include <KLocalizedString>
-#include <kio/slavebase.h> // for test_commands, where SMTPProtocol is not derived from TCPSlaveBase
-
-#include <QUrl>
-
-#include <assert.h>
-
-namespace KioSMTP {
-static const sasl_callback_t callbacks[] = {
-    { SASL_CB_ECHOPROMPT, nullptr, nullptr },
-    { SASL_CB_NOECHOPROMPT, nullptr, nullptr },
-    { SASL_CB_GETREALM, nullptr, nullptr },
-    { SASL_CB_USER, nullptr, nullptr },
-    { SASL_CB_AUTHNAME, nullptr, nullptr },
-    { SASL_CB_PASS, nullptr, nullptr },
-    { SASL_CB_CANON_USER, nullptr, nullptr },
-    { SASL_CB_LIST_END, nullptr, nullptr }
-};
-
-//
-// Command (base class)
-//
-
-Command::Command(SMTPSessionInterface *smtp, int flags)
-    : mSMTP(smtp)
-    , mComplete(false)
-    , mNeedResponse(false)
-    , mFlags(flags)
-{
-    assert(smtp);
-}
-
-Command::~Command()
-{
-}
-
-bool Command::processResponse(const Response &r, TransactionState *ts)
-{
-    Q_UNUSED(ts)
-    mComplete = true;
-    mNeedResponse = false;
-    return r.isOk();
-}
-
-void Command::ungetCommandLine(const QByteArray &cmdLine, TransactionState *ts)
-{
-    Q_UNUSED(cmdLine)
-    Q_UNUSED(ts)
-    mComplete = false;
-}
-
-Command *Command::createSimpleCommand(int which, SMTPSessionInterface *smtp)
-{
-    switch (which) {
-    case STARTTLS:
-        return new StartTLSCommand(smtp);
-    case DATA:
-        return new DataCommand(smtp);
-    case NOOP:
-        return new NoopCommand(smtp);
-    case RSET:
-        return new RsetCommand(smtp);
-    case QUIT:
-        return new QuitCommand(smtp);
-    default:
-        return nullptr;
-    }
-}
-
-//
-// relay methods:
-//
-
-void Command::parseFeatures(const Response &r)
-{
-    mSMTP->parseFeatures(r);
-}
-
-int Command::startSsl()
-{
-    return mSMTP->startSsl();
-}
-
-bool Command::haveCapability(const char *cap) const
-{
-    return mSMTP->haveCapability(cap);
-}
-
-//
-// EHLO / HELO
-//
-
-QByteArray EHLOCommand::nextCommandLine(TransactionState *ts)
-{
-    Q_UNUSED(ts)
-    mNeedResponse = true;
-    mComplete = mEHLONotSupported;
-    const char *cmd = mEHLONotSupported ? "HELO " : "EHLO ";
-    return cmd + QUrl::toAce(mHostname) + "\r\n";   //krazy:exclude=qclasses
-}
-
-bool EHLOCommand::processResponse(const Response &r, TransactionState *ts)
-{
-    Q_UNUSED(ts)
-    mNeedResponse = false;
-    // "command not {recognized,implemented}" response:
-    if (r.code() == 500 || r.code() == 502) {
-        if (mEHLONotSupported) {   // HELO failed...
-            mSMTP->error(KIO::ERR_INTERNAL_SERVER,
-                         i18n("The server rejected both EHLO and HELO commands "
-                              "as unknown or unimplemented.\n"
-                              "Please contact the server's system administrator."));
-            return false;
-        }
-        mEHLONotSupported = true; // EHLO failed, but that's ok.
-        return true;
-    }
-    mComplete = true;
-    if (r.code() / 10 == 25) {    // 25x: success
-        parseFeatures(r);
-        return true;
-    }
-    mSMTP->error(KIO::ERR_UNKNOWN,
-                 i18n("Unexpected server response to %1 command.\n%2",
-                      (mEHLONotSupported ? QStringLiteral("HELO") : QStringLiteral("EHLO")),
-                      r.errorMessage()));
-    return false;
-}
-
-//
-// STARTTLS - rfc 3207
-//
-
-QByteArray StartTLSCommand::nextCommandLine(TransactionState *ts)
-{
-    Q_UNUSED(ts)
-    mComplete = true;
-    mNeedResponse = true;
-    return QByteArrayLiteral("STARTTLS\r\n");
-}
-
-bool StartTLSCommand::processResponse(const Response &r, TransactionState *ts)
-{
-    Q_UNUSED(ts)
-    mNeedResponse = false;
-    if (r.code() != 220) {
-        mSMTP->error(r.errorCode(),
-                     i18n("Your SMTP server does not support TLS. "
-                          "Disable TLS, if you want to connect "
-                          "without encryption."));
-        return false;
-    }
-
-    if (startSsl()) {
-        return true;
-    } else {
-        //qCDebug(SMTP_LOG) << "TLS negotiation failed!";
-        mSMTP->informationMessageBox(
-            i18n("Your SMTP server claims to "
-                 "support TLS, but negotiation "
-                 "was unsuccessful.\nYou can "
-                 "disable TLS in the SMTP account settings dialog."),
-            i18n("Connection Failed"));
-        return false;
-    }
-}
-
-#define SASLERROR mSMTP->error(KIO::ERR_COULD_NOT_AUTHENTICATE, \
-                               i18n("An error occurred during authentication: %1",  \
-                                    QString::fromUtf8(sasl_errdetail(conn))));
-
-//
-// AUTH - rfc 2554
-//
-AuthCommand::AuthCommand(SMTPSessionInterface *smtp, const char *mechanisms, const QString &aFQDN, KIO::AuthInfo &ai)
-    : Command(smtp, CloseConnectionOnError | OnlyLastInPipeline)
-    , mAi(&ai)
-    , mFirstTime(true)
-{
-    mMechusing = nullptr;
-    int result;
-    conn = nullptr;
-    client_interact = nullptr;
-    mOut = nullptr;
-    mOutlen = 0;
-    mOneStep = false;
-
-    const QByteArray ba = aFQDN.toLatin1();
-    result = sasl_client_new("smtp", ba.constData(),
-                             nullptr, nullptr, callbacks, 0, &conn);
-    if (result != SASL_OK) {
-        SASLERROR
-        return;
-    }
-    do {
-        result = sasl_client_start(conn, mechanisms,
-                                   &client_interact, &mOut, &mOutlen, &mMechusing);
-
-        if (result == SASL_INTERACT) {
-            if (!saslInteract(client_interact)) {
-                return;
-            }
-        }
-    } while (result == SASL_INTERACT);
-    if (result != SASL_CONTINUE && result != SASL_OK) {
-        SASLERROR
-        return;
-    }
-    if (result == SASL_OK) {
-        mOneStep = true;
-    }
-    qCDebug(SMTP_LOG) << "Mechanism: " << mMechusing << " one step: " << mOneStep;
-}
-
-AuthCommand::~AuthCommand()
-{
-    if (conn) {
-        qCDebug(SMTP_LOG) << "dispose sasl connection";
-        sasl_dispose(&conn);
-        conn = nullptr;
-    }
-}
-
-bool AuthCommand::saslInteract(void *in)
-{
-    qCDebug(SMTP_LOG) << "saslInteract: ";
-    sasl_interact_t *interact = (sasl_interact_t *)in;
-
-    //some mechanisms do not require username && pass, so don't need a popup
-    //window for getting this info
-    for (; interact->id != SASL_CB_LIST_END; ++interact) {
-        if (interact->id == SASL_CB_AUTHNAME
-            || interact->id == SASL_CB_PASS) {
-            if (mAi->username.isEmpty() || mAi->password.isEmpty()) {
-                if (!mSMTP->openPasswordDialog(*mAi)) {
-                    mSMTP->error(KIO::ERR_ABORTED, i18n("No authentication details supplied."));
-                    return false;
-                }
-            }
-            break;
-        }
-    }
-
-    interact = (sasl_interact_t *)in;
-    while (interact->id != SASL_CB_LIST_END) {
-        switch (interact->id) {
-        case SASL_CB_USER:
-        case SASL_CB_AUTHNAME:
-        {
-            qCDebug(SMTP_LOG) << "SASL_CB_[USER|AUTHNAME]: " << mAi->username;
-            const QByteArray baUserName = mAi->username.toUtf8();
-            interact->result = strdup(baUserName.constData());
-            interact->len = strlen((const char *)interact->result);
-            break;
-        }
-        case SASL_CB_PASS:
-        {
-            qCDebug(SMTP_LOG) << "SASL_CB_PASS: [HIDDEN]";
-            const QByteArray baPassword = mAi->password.toUtf8();
-            interact->result = strdup(baPassword.constData());
-            interact->len = strlen((const char *)interact->result);
-            break;
-        }
-        default:
-            interact->result = nullptr;
-            interact->len = 0;
-            break;
-        }
-        interact++;
-    }
-    return true;
-}
-
-bool AuthCommand::doNotExecute(const TransactionState *ts) const
-{
-    Q_UNUSED(ts)
-    return !mMechusing;
-}
-
-void AuthCommand::ungetCommandLine(const QByteArray &s, TransactionState *ts)
-{
-    Q_UNUSED(ts)
-    mUngetSASLResponse = s;
-    mComplete = false;
-}
-
-QByteArray AuthCommand::nextCommandLine(TransactionState *ts)
-{
-    Q_UNUSED(ts)
-    mNeedResponse = true;
-    QByteArray cmd;
-
-    QByteArray challenge;
-    if (!mUngetSASLResponse.isNull()) {
-        // implement un-ungetCommandLine
-        cmd = mUngetSASLResponse;
-        mUngetSASLResponse = nullptr;
-    } else if (mFirstTime) {
-        QString firstCommand = QLatin1String("AUTH ") + QString::fromLatin1(mMechusing);
-
-        challenge = QByteArray::fromRawData(mOut, mOutlen).toBase64();
-        if (!challenge.isEmpty()) {
-            firstCommand += QLatin1Char(' ');
-            firstCommand += QString::fromLatin1(challenge.data(), challenge.size());
-        }
-        cmd = firstCommand.toLatin1();
-
-        if (mOneStep) {
-            mComplete = true;
-        }
-    } else {
-//      qCDebug(SMTP_LOG) << "SS: '" << mLastChallenge << "'";
-        challenge = QByteArray::fromBase64(mLastChallenge);
-        int result;
-        do {
-            result = sasl_client_step(conn, challenge.isEmpty() ? nullptr : challenge.data(),
-                                      challenge.size(),
-                                      &client_interact,
-                                      &mOut, &mOutlen);
-            if (result == SASL_INTERACT) {
-                if (!saslInteract(client_interact)) {
-                    return "";
-                }
-            }
-        } while (result == SASL_INTERACT);
-        if (result != SASL_CONTINUE && result != SASL_OK) {
-            qCDebug(SMTP_LOG) << "sasl_client_step failed with: " << result;
-            SASLERROR
-            return "";
-        }
-        cmd = QByteArray::fromRawData(mOut, mOutlen).toBase64();
-
-//      qCDebug(SMTP_LOG) << "CC: '" << cmd << "'";
-        mComplete = (result == SASL_OK);
-    }
-    cmd += QByteArrayLiteral("\r\n");
-    return cmd;
-}
-
-bool AuthCommand::processResponse(const Response &r, TransactionState *ts)
-{
-    Q_UNUSED(ts)
-    if (!r.isOk()) {
-        if (mFirstTime) {
-            if (haveCapability("AUTH")) {
-                QString chooseADifferentMsg(i18n("Choose a different authentication method."));
-                mSMTP->error(KIO::ERR_COULD_NOT_LOGIN,
-                             (mMechusing ? i18n("Your SMTP server does not support %1.", QString::fromLatin1(mMechusing))
-                              : i18n("Your SMTP server does not support (unspecified method)."))
-                             + QLatin1Char('\n') + chooseADifferentMsg + QLatin1Char('\n') + r.errorMessage());
-            } else {
-                mSMTP->error(KIO::ERR_COULD_NOT_LOGIN,
-                             i18n("Your SMTP server does not support authentication.\n"
-                                  "%1", r.errorMessage()));
-            }
-        } else {
-            mSMTP->error(KIO::ERR_COULD_NOT_LOGIN,
-                         i18n("Authentication failed.\n"
-                              "Most likely the password is wrong.\n"
-                              "%1", r.errorMessage()));
-        }
-        return false;
-    }
-    mFirstTime = false;
-    mLastChallenge = r.lines().at(0); // ### better join all lines with \n?
-    mNeedResponse = false;
-    return true;
-}
-
-//
-// MAIL FROM:
-//
-
-QByteArray MailFromCommand::nextCommandLine(TransactionState *ts)
-{
-    Q_UNUSED(ts)
-    mComplete = true;
-    mNeedResponse = true;
-    QByteArray cmdLine = QByteArrayLiteral("MAIL FROM:<") + mAddr + '>';
-    if (m8Bit && haveCapability("8BITMIME")) {
-        cmdLine += QByteArrayLiteral(" BODY=8BITMIME");
-    }
-    if (mSize && haveCapability("SIZE")) {
-        cmdLine += QByteArrayLiteral(" SIZE=") + QByteArray().setNum(mSize);
-    }
-    return cmdLine + QByteArrayLiteral("\r\n");
-}
-
-bool MailFromCommand::processResponse(const Response &r, TransactionState *ts)
-{
-    assert(ts);
-    mNeedResponse = false;
-
-    if (r.code() == 250) {
-        return true;
-    }
-
-    ts->setMailFromFailed(QString::fromLatin1(mAddr), r);
-    return false;
-}
-
-//
-// RCPT TO:
-//
-
-QByteArray RcptToCommand::nextCommandLine(TransactionState *ts)
-{
-    Q_UNUSED(ts)
-    mComplete = true;
-    mNeedResponse = true;
-    return QByteArrayLiteral("RCPT TO:<") + mAddr + QByteArrayLiteral(">\r\n");
-}
-
-bool RcptToCommand::processResponse(const Response &r, TransactionState *ts)
-{
-    assert(ts);
-    mNeedResponse = false;
-
-    if (r.code() == 250) {
-        ts->setRecipientAccepted();
-        return true;
-    }
-
-    ts->addRejectedRecipient(QString::fromLatin1(mAddr), r.errorMessage());
-    return false;
-}
-
-//
-// DATA (only initial processing!)
-//
-
-QByteArray DataCommand::nextCommandLine(TransactionState *ts)
-{
-    assert(ts);
-    mComplete = true;
-    mNeedResponse = true;
-    ts->setDataCommandIssued(true);
-    return QByteArrayLiteral("DATA\r\n");
-}
-
-void DataCommand::ungetCommandLine(const QByteArray &cmd, TransactionState *ts)
-{
-    Q_UNUSED(cmd)
-    assert(ts);
-    mComplete = false;
-    ts->setDataCommandIssued(false);
-}
-
-bool DataCommand::processResponse(const Response &r, TransactionState *ts)
-{
-    assert(ts);
-    mNeedResponse = false;
-
-    if (r.code() == 354) {
-        ts->setDataCommandSucceeded(true, r);
-        return true;
-    }
-
-    ts->setDataCommandSucceeded(false, r);
-    return false;
-}
-
-//
-// DATA (data transfer)
-//
-void TransferCommand::ungetCommandLine(const QByteArray &cmd, TransactionState *ts)
-{
-    Q_UNUSED(ts)
-    if (cmd.isEmpty()) {
-        return;    // don't change state when we can't detect the unget in
-    }
-    // the next nextCommandLine !!
-    mWasComplete = mComplete;
-    mComplete = false;
-    mNeedResponse = false;
-    mUngetBuffer = cmd;
-}
-
-bool TransferCommand::doNotExecute(const TransactionState *ts) const
-{
-    assert(ts);
-    return ts->failed();
-}
-
-QByteArray TransferCommand::nextCommandLine(TransactionState *ts)
-{
-    assert(ts);   // let's rely on it ( at least for the moment )
-    assert(!isComplete());
-    assert(!ts->failed());
-
-    static const QByteArray dotCRLF = QByteArrayLiteral(".\r\n");
-    static const QByteArray CRLFdotCRLF = QByteArrayLiteral("\r\n.\r\n");
-
-    if (!mUngetBuffer.isEmpty()) {
-        const QByteArray ret = mUngetBuffer;
-        mUngetBuffer = nullptr;
-        if (mWasComplete) {
-            mComplete = true;
-            mNeedResponse = true;
-        }
-        return ret; // don't prepare(), it's slave-generated or already prepare()d
-    }
-
-    // normal processing:
-
-    qCDebug(SMTP_LOG) << "requesting data";
-    mSMTP->dataReq();
-    QByteArray ba;
-    int result = mSMTP->readData(ba);
-    qCDebug(SMTP_LOG) << "got " << result << " bytes";
-    if (result > 0) {
-        return prepare(ba);
-    } else if (result < 0) {
-        ts->setFailedFatally(KIO::ERR_INTERNAL,
-                             i18n("Could not read data from application."));
-        mComplete = true;
-        mNeedResponse = true;
-        return nullptr;
-    }
-    mComplete = true;
-    mNeedResponse = true;
-    return mLastChar == '\n' ? dotCRLF : CRLFdotCRLF;
-}
-
-bool TransferCommand::processResponse(const Response &r, TransactionState *ts)
-{
-    mNeedResponse = false;
-    assert(ts);
-    ts->setComplete();
-    if (!r.isOk()) {
-        ts->setFailed();
-        mSMTP->error(r.errorCode(),
-                     i18n("The message content was not accepted.\n"
-                          "%1", r.errorMessage()));
-        return false;
-    }
-    return true;
-}
-
-static QByteArray dotstuff_lf2crlf(const QByteArray &ba, char &last)
-{
-    QByteArray result(ba.size() * 2 + 1, 0);   // worst case: repeated "[.]\n"
-    const char *s = ba.data();
-    const char *const send = ba.data() + ba.size();
-    char *d = result.data();
-
-    while (s < send) {
-        const char ch = *s++;
-        if (ch == '\n' && last != '\r') {
-            *d++ = '\r';    // lf2crlf
-        } else if (ch == '.' && last == '\n') {
-            *d++ = '.';    // dotstuff
-        }
-        last = *d++ = ch;
-    }
-
-    result.truncate(d - result.data());
-    return result;
-}
-
-QByteArray TransferCommand::prepare(const QByteArray &ba)
-{
-    if (ba.isEmpty()) {
-        return nullptr;
-    }
-    if (mSMTP->lf2crlfAndDotStuffingRequested()) {
-        qCDebug(SMTP_LOG) << "performing dotstuffing and LF->CRLF transformation";
-        return dotstuff_lf2crlf(ba, mLastChar);
-    } else {
-        mLastChar = ba[ba.size() - 1];
-        return ba;
-    }
-}
-
-//
-// NOOP
-//
-
-QByteArray NoopCommand::nextCommandLine(TransactionState *ts)
-{
-    Q_UNUSED(ts)
-    mComplete = true;
-    mNeedResponse = true;
-    return QByteArrayLiteral("NOOP\r\n");
-}
-
-//
-// RSET
-//
-
-QByteArray RsetCommand::nextCommandLine(TransactionState *ts)
-{
-    Q_UNUSED(ts)
-    mComplete = true;
-    mNeedResponse = true;
-    return QByteArrayLiteral("RSET\r\n");
-}
-
-//
-// QUIT
-//
-
-QByteArray QuitCommand::nextCommandLine(TransactionState *ts)
-{
-    Q_UNUSED(ts)
-    mComplete = true;
-    mNeedResponse = true;
-    return QByteArrayLiteral("QUIT\r\n");
-}
-} // namespace KioSMTP
diff --git a/kioslave/src/smtp/command.h b/kioslave/src/smtp/command.h
deleted file mode 100644
index 1bbc0c8..0000000
--- a/kioslave/src/smtp/command.h
+++ /dev/null
@@ -1,331 +0,0 @@
-/*  -*- c++ -*-
-    command.h
-
-    This file is part of kio_smtp, the KDE SMTP kioslave.
-    Copyright (c) 2003 Marc Mutz <mutz at kde.org>
-
-    This program is free software; you can redistribute it and/or modify it
-    under the terms of the GNU General Public License, version 2, as
-    published by the Free Software Foundation.
-
-    This program 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
-    General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-    In addition, as a special exception, the copyright holders give
-    permission to link the code of this program with any edition of
-    the Qt library by Trolltech AS, Norway (or with modified versions
-    of Qt that use the same license as Qt), and distribute linked
-    combinations including the two.  You must obey the GNU General
-    Public License in all respects for all of the code used other than
-    Qt.  If you modify this file, you may extend this exception to
-    your version of the file, but you are not obligated to do so.  If
-    you do not wish to do so, delete this exception statement from
-    your version.
-*/
-
-#ifndef __KIOSMTP_COMMAND_H__
-#define __KIOSMTP_COMMAND_H__
-
-// workaround a bug in Cyrus-SASL 2.1.26 which is missing sys/types.h
-// include in sasl.h
-#include <sys/types.h>
-extern "C" {
-#include <sasl/sasl.h>
-}
-
-#include <kio/authinfo.h>
-
-namespace KioSMTP {
-class Response;
-class TransactionState;
-class SMTPSessionInterface;
-
-/**
- * @short Represents an SMTP command
- *
- * Semantics: A command consists of a series of "command lines"
- * (though that's stretching it a bit for @ref TransferJob and @ref
- * AuthCommand) and responses. There's typically one response for
- * one command line and the command is completed.
- *
- * However, some commands consist of a dialog (command line,
- * response, command line, response,...) where each successive
- * command line is dependant on the previously received response
- * (and thus those commands are not pipelinable). That's why each
- * command signals completion by having it's @ref #isComplete()
- * method return true @em after the last command line to be sent,
- * but @em before the last response to receive. @ref AuthCommand is
- * the principal representative of this kind of command. Because
- * @ref EHLOCommand automatically falls back to HELO in case EHLO
- * isn't supported, it is also of this kind. If completion is
- * signalled before the first command line is issued, it is not to
- * be executed at all.
- *
- * Other commands need to send multiple "command lines" before
- * receiving a single (final) response. @ref TransferCommand is the
- * only representative of this kind of "command". That's why each
- * command signals whether it now expects a response before being
- * able to issue the next command line (if any) by having it's @ref
- * #needsResponse() method return true.
- *
- * Commands whose @ref #nextCommandLine() does not support being
- * called multiple times in a row without changing command state,
- * must reimplement @ref #ungetCommandLine().
- **/
-class Command
-{
-public:
-    enum Flags {
-        OnlyLastInPipeline = 1,
-        OnlyFirstInPipeline = 2,
-        CloseConnectionOnError = 4
-    };
-
-    explicit Command(SMTPSessionInterface *smtp, int flags = 0);
-    virtual ~Command();
-
-    enum Type {
-        STARTTLS,
-        DATA,
-        NOOP,
-        RSET,
-        QUIT
-    };
-
-    static Command *createSimpleCommand(int which, SMTPSessionInterface *smtp);
-
-    virtual QByteArray nextCommandLine(TransactionState *ts = nullptr) = 0;
-    /* Reimplement this if your @ref #nextCommandLine() implementation
-       changes state other than @ref mComplete. The default
-       implementation just resets @ref mComplete to false. */
-    virtual void ungetCommandLine(const QByteArray &cmdLine, TransactionState *ts = nullptr);
-    /* Reimplement this if your command need more sophisicated
-       response processing than just checking for @ref
-       Response::isOk(). The default implementation sets @ref
-       mComplete to true, @ref mNeedResponse to false and returns
-       whether the response isOk(). */
-    virtual bool processResponse(const Response &response, TransactionState *ts = nullptr);
-
-    virtual bool doNotExecute(const TransactionState *ts) const
-    {
-        Q_UNUSED(ts)
-        return false;
-    }
-
-    bool isComplete() const
-    {
-        return mComplete;
-    }
-
-    /**
-     * @return whether the command expects a response now. Some
-     * commands (most notably AUTH) may consist of a series of
-     * commands and associated responses until they are
-     * complete. Others (most notably @ref TransferCommand usually
-     * send multiple "command lines" before expecting a response.
-     */
-    bool needsResponse() const
-    {
-        return mNeedResponse;
-    }
-
-    /**
-     * @return whether an error in executing this command is so fatal
-     * that closing the connection is the only option
-     */
-    bool closeConnectionOnError() const
-    {
-        return mFlags & CloseConnectionOnError;
-    }
-
-    bool mustBeLastInPipeline() const
-    {
-        return mFlags & OnlyLastInPipeline;
-    }
-
-    bool mustBeFirstInPipeline() const
-    {
-        return mFlags & OnlyFirstInPipeline;
-    }
-
-protected:
-    SMTPSessionInterface *mSMTP;
-    bool mComplete;
-    bool mNeedResponse;
-    const int mFlags;
-
-protected:
-    // only relay methods to enable access to slave-protected methods
-    // for subclasses of Command:
-    void parseFeatures(const Response &r);
-    int startSsl();
-    bool haveCapability(const char *cap) const;
-};
-
-class EHLOCommand : public Command
-{
-public:
-    EHLOCommand(SMTPSessionInterface *smtp, const QString &hostname)
-        : Command(smtp, CloseConnectionOnError | OnlyLastInPipeline)
-        , mEHLONotSupported(false)
-        , mHostname(hostname.trimmed())
-    {
-    }
-
-    QByteArray nextCommandLine(TransactionState *ts) override;
-    bool processResponse(const Response &response, TransactionState *ts) override;
-private:
-    bool mEHLONotSupported;
-    QString mHostname;
-};
-
-class StartTLSCommand : public Command
-{
-public:
-    StartTLSCommand(SMTPSessionInterface *smtp)
-        : Command(smtp, CloseConnectionOnError | OnlyLastInPipeline)
-    {
-    }
-
-    QByteArray nextCommandLine(TransactionState *ts) override;
-    bool processResponse(const Response &response, TransactionState *ts) override;
-};
-
-class AuthCommand : public Command
-{
-public:
-    AuthCommand(SMTPSessionInterface *smtp, const char *mechanisms, const QString &aFQDN, KIO::AuthInfo &ai);
-    ~AuthCommand();
-    bool doNotExecute(const TransactionState *ts) const override;
-    QByteArray nextCommandLine(TransactionState *ts) override;
-    void ungetCommandLine(const QByteArray &cmdLine, TransactionState *ts) override;
-    bool processResponse(const Response &response, TransactionState *ts) override;
-private:
-    bool saslInteract(void *in);
-
-    sasl_conn_t *conn;
-    sasl_interact_t *client_interact;
-    const char *mOut;
-    uint mOutlen;
-    bool mOneStep;
-
-    const char *mMechusing;
-    KIO::AuthInfo *mAi;
-    QByteArray mLastChallenge;
-    QByteArray mUngetSASLResponse;
-    bool mFirstTime;
-};
-
-class MailFromCommand : public Command
-{
-public:
-    MailFromCommand(SMTPSessionInterface *smtp, const QByteArray &addr, bool eightBit = false, unsigned int size = 0)
-        : Command(smtp)
-        , mAddr(addr)
-        , m8Bit(eightBit)
-        , mSize(size)
-    {
-    }
-
-    QByteArray nextCommandLine(TransactionState *ts) override;
-    bool processResponse(const Response &response, TransactionState *ts) override;
-private:
-    QByteArray mAddr;
-    bool m8Bit;
-    unsigned int mSize;
-};
-
-class RcptToCommand : public Command
-{
-public:
-    RcptToCommand(SMTPSessionInterface *smtp, const QByteArray &addr)
-        : Command(smtp)
-        , mAddr(addr)
-    {
-    }
-
-    QByteArray nextCommandLine(TransactionState *ts) override;
-    bool processResponse(const Response &response, TransactionState *ts) override;
-private:
-    QByteArray mAddr;
-};
-
-/** Handles only the initial intermediate response and compltetes at
-    the point where the mail contents need to be sent */
-class DataCommand : public Command
-{
-public:
-    DataCommand(SMTPSessionInterface *smtp)
-        : Command(smtp, OnlyLastInPipeline)
-    {
-    }
-
-    QByteArray nextCommandLine(TransactionState *ts) override;
-    void ungetCommandLine(const QByteArray &cmd, TransactionState *ts) override;
-    bool processResponse(const Response &response, TransactionState *ts) override;
-};
-
-/** Handles the data transfer following a successful DATA command */
-class TransferCommand : public Command
-{
-public:
-    TransferCommand(SMTPSessionInterface *smtp, const QByteArray &initialBuffer)
-        : Command(smtp, OnlyFirstInPipeline)
-        , mUngetBuffer(initialBuffer)
-        , mLastChar('\n')
-        , mWasComplete(false)
-    {
-    }
-
-    bool doNotExecute(const TransactionState *ts) const override;
-    QByteArray nextCommandLine(TransactionState *ts) override;
-    void ungetCommandLine(const QByteArray &cmd, TransactionState *ts) override;
-    bool processResponse(const Response &response, TransactionState *ts) override;
-private:
-    QByteArray prepare(const QByteArray &ba);
-    QByteArray mUngetBuffer;
-    char mLastChar;
-    bool mWasComplete; // ... before ungetting
-};
-
-class NoopCommand : public Command
-{
-public:
-    NoopCommand(SMTPSessionInterface *smtp)
-        : Command(smtp, OnlyLastInPipeline)
-    {
-    }
-
-    QByteArray nextCommandLine(TransactionState *ts) override;
-};
-
-class RsetCommand : public Command
-{
-public:
-    RsetCommand(SMTPSessionInterface *smtp)
-        : Command(smtp, CloseConnectionOnError)
-    {
-    }
-
-    QByteArray nextCommandLine(TransactionState *ts) override;
-};
-
-class QuitCommand : public Command
-{
-public:
-    QuitCommand(SMTPSessionInterface *smtp)
-        : Command(smtp, CloseConnectionOnError | OnlyLastInPipeline)
-    {
-    }
-
-    QByteArray nextCommandLine(TransactionState *ts) override;
-};
-} // namespace KioSMTP
-
-#endif // __KIOSMTP_COMMAND_H__
diff --git a/kioslave/src/smtp/compliance.txt b/kioslave/src/smtp/compliance.txt
deleted file mode 100644
index b6b9874..0000000
--- a/kioslave/src/smtp/compliance.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-The SMTP kioslave currently conforms to the following SMTP-related RFCs:
-
-Base Spec:
-2821 Simple Mail Transfer Protocol. J. Klensin, Ed.. April 2001.
-     (Format: TXT=192504 bytes) (Obsoletes RFC0821, RFC0974, RFC1869)
-     (Status: PROPOSED STANDARD)
-
-Encryption/Auth:
-3207 SMTP Service Extension for Secure SMTP over Transport Layer
-     Security. P. Hoffman. February 2002. (Format: TXT=18679 bytes)
-     (Obsoletes RFC2487) (Status: PROPOSED STANDARD)
-
-2554 SMTP Service Extension for Authentication. J. Myers. March 1999.
-     (Format: TXT=20534 bytes) (Status: PROPOSED STANDARD)
-(with all SASL mechanisms supported by KDESasl)
-
-General:
-1652 SMTP Service Extension for 8bit-MIMEtransport. J. Klensin, N.
-     Freed, M. Rose, E. Stefferud, D. Crocker. July 1994. (Format:
-     TXT=11842 bytes) (Obsoletes RFC1426) (Status: DRAFT STANDARD)
-
-1870 SMTP Service Extension for Message Size Declaration. J. Klensin,
-     N. Freed, K. Moore. November 1995. (Format: TXT=18226 bytes)
-     (Obsoletes RFC1653) (Also STD0010) (Status: STANDARD)
-
-2920 SMTP Service Extension for Command Pipelining. N. Freed.
-     September 2000. (Format: TXT=17065 bytes) (Obsoletes RFC2197) (Also
-     STD0060) (Status: STANDARD)
-
-Known shortcomings:
-- Doesn't enforce the CRLF lineending convention on user-supplied data.
-- Due to the lack of a Mulit_Put_ in the KIO infrastructure, pipelining
-  across messages isn't supported.
diff --git a/kioslave/src/smtp/kioslavesession.cpp b/kioslave/src/smtp/kioslavesession.cpp
deleted file mode 100644
index 3c770bd..0000000
--- a/kioslave/src/smtp/kioslavesession.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
-    Copyright (c) 2010 Volker Krause <vkrause at 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 "kioslavesession.h"
-
-using namespace KioSMTP;
-
-KioSMTP::KioSlaveSession::KioSlaveSession(SMTPProtocol *protocol)
-    : m_protocol(protocol)
-{
-}
-
-void KioSMTP::KioSlaveSession::error(int id, const QString &msg)
-{
-    m_protocol->error(id, msg);
-}
-
-void KioSlaveSession::informationMessageBox(const QString &msg, const QString &caption)
-{
-    m_protocol->messageBox(KIO::SlaveBase::Information, msg, caption);
-}
-
-bool KioSMTP::KioSlaveSession::openPasswordDialog(KIO::AuthInfo &authInfo)
-{
-    return m_protocol->openPasswordDialog(authInfo);
-}
-
-void KioSMTP::KioSlaveSession::dataReq()
-{
-    m_protocol->dataReq();
-}
-
-int KioSMTP::KioSlaveSession::readData(QByteArray &ba)
-{
-    return m_protocol->readData(ba);
-}
-
-bool KioSMTP::KioSlaveSession::startSsl()
-{
-    return m_protocol->startSsl();
-}
-
-bool KioSlaveSession::eightBitMimeRequested() const
-{
-    return m_protocol->metaData(QStringLiteral("8bitmime")) == QLatin1String("on");
-}
-
-bool KioSlaveSession::lf2crlfAndDotStuffingRequested() const
-{
-    return m_protocol->metaData(QStringLiteral("lf2crlf+dotstuff")) == QLatin1String("slave");
-}
-
-bool KioSlaveSession::pipeliningRequested() const
-{
-    return m_protocol->metaData(QStringLiteral("pipelining")) != QLatin1String("off");
-}
-
-QString KioSlaveSession::requestedSaslMethod() const
-{
-    return m_protocol->metaData(QStringLiteral("sasl"));
-}
-
-KioSMTP::SMTPSessionInterface::TLSRequestState KioSMTP::KioSlaveSession::tlsRequested() const
-{
-    if (m_protocol->metaData(QStringLiteral("tls")) == QLatin1String("off")) {
-        return ForceNoTLS;
-    }
-    if (m_protocol->metaData(QStringLiteral("tls")) == QLatin1String("on")) {
-        return ForceTLS;
-    }
-    return UseTLSIfAvailable;
-}
diff --git a/kioslave/src/smtp/kioslavesession.h b/kioslave/src/smtp/kioslavesession.h
deleted file mode 100644
index 772b82c..0000000
--- a/kioslave/src/smtp/kioslavesession.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
-    Copyright (c) 2010 Volker Krause <vkrause at 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.
-*/
-
-#ifndef KIOSMTP_KIOSLAVESESSION_H
-#define KIOSMTP_KIOSLAVESESSION_H
-
-#include "smtpsessioninterface.h"
-#include "smtp.h"
-
-namespace KioSMTP {
-class KioSlaveSession : public SMTPSessionInterface
-{
-public:
-    explicit KioSlaveSession(SMTPProtocol *protocol);
-    void error(int id, const QString &msg) override;
-    void informationMessageBox(const QString &msg, const QString &caption) override;
-    bool openPasswordDialog(KIO::AuthInfo &authInfo) override;
-    void dataReq() override;
-    int readData(QByteArray &ba) override;
-    bool startSsl() override;
-
-    QString requestedSaslMethod() const override;
-    bool eightBitMimeRequested() const override;
-    bool lf2crlfAndDotStuffingRequested() const override;
-    bool pipeliningRequested() const override;
-    TLSRequestState tlsRequested() const override;
-
-private:
-    SMTPProtocol *m_protocol;
-};
-}
-
-#endif
diff --git a/kioslave/src/smtp/request.cpp b/kioslave/src/smtp/request.cpp
deleted file mode 100644
index edbca5c..0000000
--- a/kioslave/src/smtp/request.cpp
+++ /dev/null
@@ -1,193 +0,0 @@
-/*  -*- c++ -*-
-    request.cc
-
-    This file is part of kio_smtp, the KDE SMTP kioslave.
-    Copyright (c) 2003 Marc Mutz <mutz at kde.org>
-
-    This program is free software; you can redistribute it and/or modify it
-    under the terms of the GNU General Public License, version 2, as
-    published by the Free Software Foundation.
-
-    This program 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
-    General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-    In addition, as a special exception, the copyright holders give
-    permission to link the code of this program with any edition of
-    the Qt library by Trolltech AS, Norway (or with modified versions
-    of Qt that use the same license as Qt), and distribute linked
-    combinations including the two.  You must obey the GNU General
-    Public License in all respects for all of the code used other than
-    Qt.  If you modify this file, you may extend this exception to
-    your version of the file, but you are not obligated to do so.  If
-    you do not wish to do so, delete this exception statement from
-    your version.
-*/
-
-#include "request.h"
-#include "smtp_debug.h"
-
-#include <QUrl>
-#include <QUrl>
-#include <qdebug.h>
-
-#include <assert.h>
-
-namespace KioSMTP {
-Request Request::fromURL(const QUrl &url)
-{
-    Request request;
-
-    const QStringList query = url.query().split(QLatin1Char('&'));
-#ifndef NDEBUG
-    qCDebug(SMTP_LOG) << "Parsing request from query:\n" << query.join(QLatin1Char('\n'));
-#endif
-    for (QStringList::const_iterator it = query.begin(), end(query.end()); it != end; ++it) {
-        int equalsPos = (*it).indexOf(QLatin1Char('='));
-        if (equalsPos <= 0) {
-            continue;
-        }
-
-        const QString key = (*it).left(equalsPos).toLower();
-        const QString value = QUrl::fromPercentEncoding((*it).mid(equalsPos + 1).toLatin1());     //krazy:exclude=qclasses
-
-        if (key == QLatin1String("to")) {
-            request.addTo(value);
-        } else if (key == QLatin1String("cc")) {
-            request.addCc(value);
-        } else if (key == QLatin1String("bcc")) {
-            request.addBcc(value);
-        } else if (key == QLatin1String("headers")) {
-            request.setEmitHeaders(value == QLatin1String("0"));
-            request.setEmitHeaders(false);   // ### ???
-        } else if (key == QLatin1String("subject")) {
-            request.setSubject(value);
-        } else if (key == QLatin1String("from")) {
-            request.setFromAddress(value);
-        } else if (key == QLatin1String("profile")) {
-            request.setProfileName(value);
-        } else if (key == QLatin1String("hostname")) {
-            request.setHeloHostname(value);
-        } else if (key == QLatin1String("body")) {
-            request.set8BitBody(value.toUpper() == QLatin1String("8BIT"));
-        } else if (key == QLatin1String("size")) {
-            request.setSize(value.toUInt());
-        } else {
-            qCWarning(SMTP_LOG) << "while parsing query: unknown query item \""
-                                << key << "\" with value \"" << value << "\"" << endl;
-        }
-    }
-
-    return request;
-}
-
-QByteArray Request::heloHostnameCString() const
-{
-    return QUrl::toAce(heloHostname());   //krazy:exclude=qclasses
-}
-
-static bool isUsAscii(const QString &s)
-{
-    for (int i = 0; i < s.length(); ++i) {
-        if (s[i].unicode() > 127) {
-            return false;
-        }
-    }
-    return true;
-}
-
-static inline bool isSpecial(char ch)
-{
-    static const QByteArray specials = "()<>[]:;@\\,.\"";
-    return specials.indexOf(ch) >= 0;
-}
-
-static inline bool needsQuoting(char ch)
-{
-    return ch == '\\' || ch == '"' || ch == '\n';
-}
-
-static inline QByteArray rfc2047Encode(const QString &s)
-{
-    QByteArray r = s.trimmed().toUtf8().toBase64();
-    return "=?utf-8?b?" + r + "?="; // use base64 since that always gives a valid encoded-word
-}
-
-static QByteArray quote(const QString &s)
-{
-    assert(isUsAscii(s));
-
-    QByteArray r(s.length() * 2, 0);
-    bool needsQuotes = false;
-
-    unsigned int j = 0;
-    for (int i = 0; i < s.length(); ++i) {
-        char ch = s[i].toLatin1();
-        if (isSpecial(ch)) {
-            if (needsQuoting(ch)) {
-                r[j++] = '\\';
-            }
-            needsQuotes = true;
-        }
-        r[j++] = ch;
-    }
-    r.truncate(j);
-
-    if (needsQuotes) {
-        return '"' + r + '"';
-    } else {
-        return r;
-    }
-}
-
-static QByteArray formatFromAddress(const QString &fromRealName, const QString &fromAddress)
-{
-    if (fromRealName.isEmpty()) {
-        return fromAddress.toLatin1();    // no real name: return "joe at user.org"
-    }
-
-    // return "Joe User <joe at user.org>", "\"User, Joe\" <joe at user.org>"
-    // or "=?utf-8?q?Joe_User?= <joe at user.org>", depending on real name's nature.
-    QByteArray r = isUsAscii(fromRealName) ? quote(fromRealName) : rfc2047Encode(fromRealName);
-    return r + " <" + fromAddress.toLatin1() + '>';
-}
-
-static QByteArray formatSubject(QString s)
-{
-    if (isUsAscii(s)) {
-        return s.remove(QLatin1Char('\n')).toLatin1();    // don't break header folding,
-    } else {
-        // so remove any line break
-        // that happen to be around
-        return rfc2047Encode(s);
-    }
-}
-
-QByteArray Request::headerFields(const QString &fromRealName) const
-{
-    if (!emitHeaders()) {
-        return nullptr;
-    }
-
-    assert(hasFromAddress());   // should have been checked for by
-    // caller (MAIL FROM comes before DATA)
-
-    QByteArray result = QByteArrayLiteral("From: ") + formatFromAddress(fromRealName, fromAddress()) + QByteArrayLiteral("\r\n");
-
-    if (!subject().isEmpty()) {
-        result += QByteArrayLiteral("Subject: ") + formatSubject(subject()) + QByteArrayLiteral("\r\n");
-    }
-    if (!to().empty()) {
-        result += QByteArrayLiteral("To: ") + to().join(QStringLiteral(",\r\n\t") /* line folding */).toLatin1() + "\r\n";
-    }
-    if (!cc().empty()) {
-        result += QByteArrayLiteral("Cc: ") + cc().join(QStringLiteral(",\r\n\t") /* line folding */).toLatin1() + "\r\n";
-    }
-    return result;
-}
-} // namespace KioSMTP
diff --git a/kioslave/src/smtp/request.h b/kioslave/src/smtp/request.h
deleted file mode 100644
index 35ed528..0000000
--- a/kioslave/src/smtp/request.h
+++ /dev/null
@@ -1,192 +0,0 @@
-/*  -*- c++ -*-
-    request.h
-
-    This file is part of kio_smtp, the KDE SMTP kioslave.
-    Copyright (c) 2003 Marc Mutz <mutz at kde.org>
-
-    This program is free software; you can redistribute it and/or modify it
-    under the terms of the GNU General Public License, version 2, as
-    published by the Free Software Foundation.
-
-    This program 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
-    General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-    In addition, as a special exception, the copyright holders give
-    permission to link the code of this program with any edition of
-    the Qt library by Trolltech AS, Norway (or with modified versions
-    of Qt that use the same license as Qt), and distribute linked
-    combinations including the two.  You must obey the GNU General
-    Public License in all respects for all of the code used other than
-    Qt.  If you modify this file, you may extend this exception to
-    your version of the file, but you are not obligated to do so.  If
-    you do not wish to do so, delete this exception statement from
-    your version.
-*/
-
-#ifndef __KIOSMTP_REQUEST_H__
-#define __KIOSMTP_REQUEST_H__
-
-#include <QStringList>
-#include <QByteArray>
-
-class QUrl;
-
-namespace KioSMTP {
-class Request
-{
-public:
-    Request()
-        : mSubject(QStringLiteral("missing subject"))
-        , mEmitHeaders(true)
-        , m8Bit(false)
-        , mSize(0)
-    {
-    }
-
-    static Request fromURL(const QUrl &url);
-
-    QString profileName() const
-    {
-        return mProfileName;
-    }
-
-    void setProfileName(const QString &profileName)
-    {
-        mProfileName = profileName;
-    }
-
-    bool hasProfile() const
-    {
-        return !profileName().isNull();
-    }
-
-    QString subject() const
-    {
-        return mSubject;
-    }
-
-    void setSubject(const QString &subject)
-    {
-        mSubject = subject;
-    }
-
-    QString fromAddress() const
-    {
-        return mFromAddress;
-    }
-
-    void setFromAddress(const QString &fromAddress)
-    {
-        mFromAddress = fromAddress;
-    }
-
-    bool hasFromAddress() const
-    {
-        return !mFromAddress.isEmpty();
-    }
-
-    QStringList recipients() const
-    {
-        return to() + cc() + bcc();
-    }
-
-    bool hasRecipients() const
-    {
-        return !to().empty() || !cc().empty() || !bcc().empty();
-    }
-
-    QStringList to() const
-    {
-        return mTo;
-    }
-
-    QStringList cc() const
-    {
-        return mCc;
-    }
-
-    QStringList bcc() const
-    {
-        return mBcc;
-    }
-
-    void addTo(const QString &to)
-    {
-        mTo.push_back(to);
-    }
-
-    void addCc(const QString &cc)
-    {
-        mCc.push_back(cc);
-    }
-
-    void addBcc(const QString &bcc)
-    {
-        mBcc.push_back(bcc);
-    }
-
-    QString heloHostname() const
-    {
-        return mHeloHostname;
-    }
-
-    QByteArray heloHostnameCString() const;
-    void setHeloHostname(const QString &hostname)
-    {
-        mHeloHostname = hostname;
-    }
-
-    bool emitHeaders() const
-    {
-        return mEmitHeaders;
-    }
-
-    void setEmitHeaders(bool emitHeaders)
-    {
-        mEmitHeaders = emitHeaders;
-    }
-
-    bool is8BitBody() const
-    {
-        return m8Bit;
-    }
-
-    void set8BitBody(bool a8Bit)
-    {
-        m8Bit = a8Bit;
-    }
-
-    unsigned int size() const
-    {
-        return mSize;
-    }
-
-    void setSize(unsigned int size)
-    {
-        mSize = size;
-    }
-
-    /**
-     * If @ref #emitHeaders() is true, returns the rfc2822
-     * serialization of the header fields "To", "Cc", "Subject" and
-     * "From", as determined by the respective settings. If @ref
-     * #emitHeaders() is false, returns a null string.
-     */
-    QByteArray headerFields(const QString &fromRealName = QString()) const;
-
-private:
-    QStringList mTo, mCc, mBcc;
-    QString mProfileName, mSubject, mFromAddress, mHeloHostname;
-    bool mEmitHeaders;
-    bool m8Bit;
-    unsigned int mSize;
-};
-} // namespace KioSMTP
-
-#endif // __KIOSMTP_REQUEST_H__
diff --git a/kioslave/src/smtp/response.cpp b/kioslave/src/smtp/response.cpp
deleted file mode 100644
index c12f824..0000000
--- a/kioslave/src/smtp/response.cpp
+++ /dev/null
@@ -1,165 +0,0 @@
-/*  -*- c++ -*-
-    response.cc
-
-    This file is part of kio_smtp, the KDE SMTP kioslave.
-    Copyright (c) 2003 Marc Mutz <mutz at kde.org>
-
-    This program is free software; you can redistribute it and/or modify it
-    under the terms of the GNU General Public License, version 2, as
-    published by the Free Software Foundation.
-
-    This program 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
-    General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-    In addition, as a special exception, the copyright holders give
-    permission to link the code of this program with any edition of
-    the Qt library by Trolltech AS, Norway (or with modified versions
-    of Qt that use the same license as Qt), and distribute linked
-    combinations including the two.  You must obey the GNU General
-    Public License in all respects for all of the code used other than
-    Qt.  If you modify this file, you may extend this exception to
-    your version of the file, but you are not obligated to do so.  If
-    you do not wish to do so, delete this exception statement from
-    your version.
-*/
-
-#include "response.h"
-
-#include <KLocalizedString>
-#include <kio/global.h>
-
-#include <QByteArray>
-
-namespace KioSMTP {
-void Response::parseLine(const char *line, int len)
-{
-    if (!isWellFormed()) {
-        return;    // don't bother
-    }
-
-    if (isComplete()) {
-        // if the response is already complete, there can't be another line
-        mValid = false;
-    }
-
-    if (len > 1 && line[len - 1] == '\n' && line[len - 2] == '\r') {
-        len -= 2;
-    }
-
-    if (len < 3) {
-        // can't be valid - too short
-        mValid = false;
-        mWellFormed = false;
-        return;
-    }
-
-    bool ok = false;
-    unsigned int code = QByteArray(line, 3).toUInt(&ok);
-    if (!ok || code < 100 || code > 559) {
-        // not a number or number out of range
-        mValid = false;
-        if (!ok || code < 100) {
-            mWellFormed = false;
-        }
-        return;
-    }
-    if (mCode && code != mCode) {
-        // different codes in one response are not allowed.
-        mValid = false;
-        return;
-    }
-    mCode = code;
-
-    if (len == 3 || line[3] == ' ') {
-        mSawLastLine = true;
-    } else if (line[3] != '-') {
-        // code must be followed by either SP or hyphen (len == 3 is
-        // also accepted since broken servers exist); all else is
-        // invalid
-        mValid = false;
-        mWellFormed = false;
-        return;
-    }
-
-    mLines.push_back(len > 4 ? QByteArray(line + 4, len - 4).trimmed() : QByteArray());
-}
-
-// hackishly fixing QCStringList flaws...
-static QByteArray join(char sep, const QCStringList &list)
-{
-    if (list.empty()) {
-        return QByteArray();
-    }
-    QByteArray result = list.front();
-    for (QCStringList::const_iterator it = ++list.begin(), end(list.end()); it != end; ++it) {
-        result += sep + *it;
-    }
-    return result;
-}
-
-QString Response::errorMessage() const
-{
-    QString msg;
-    if (lines().count() > 1) {
-        msg = i18n("The server responded:\n%1", QString::fromLatin1(join('\n', lines())));
-    } else {
-        msg = i18n("The server responded: \"%1\"", QString::fromLatin1(lines().at(0)));
-    }
-    if (first() == 4) {
-        msg += QLatin1Char('\n') + i18n("This is a temporary failure. You may try again later.");
-    }
-    return msg;
-}
-
-int Response::errorCode() const
-{
-    switch (code()) {
-    case 421: // Service not available, closing transmission channel
-    case 454: // TLS not available due to temporary reason
-    // Temporary authentication failure
-    case 554: // Transaction failed / No SMTP service here / No valid recipients
-        return KIO::ERR_SERVICE_NOT_AVAILABLE;
-
-    case 451: // Requested action aborted: local error in processing
-        return KIO::ERR_INTERNAL_SERVER;
-
-    case 452: // Requested action not taken: insufficient system storage
-    case 552: // Requested mail action aborted: exceeded storage allocation
-        return KIO::ERR_DISK_FULL;
-
-    case 500: // Syntax error, command unrecognized
-    case 501: // Syntax error in parameters or arguments
-    case 502: // Command not implemented
-    case 503: // Bad sequence of commands
-    case 504: // Command parameter not implemented
-        return KIO::ERR_INTERNAL;
-
-    case 450: // Requested mail action not taken: mailbox unavailable
-    case 550: // Requested action not taken: mailbox unavailable
-    case 551: // User not local; please try <forward-path>
-    case 553: // Requested action not taken: mailbox name not allowed
-        return KIO::ERR_DOES_NOT_EXIST;
-
-    case 530: // {STARTTLS,Authentication} required
-    case 538: // Encryption required for requested authentication mechanism
-    case 534: // Authentication mechanism is too weak
-        return KIO::ERR_UPGRADE_REQUIRED;
-
-    case 432: // A password transition is needed
-        return KIO::ERR_COULD_NOT_AUTHENTICATE;
-
-    default:
-        if (isPositive()) {
-            return 0;
-        } else {
-            return KIO::ERR_UNKNOWN;
-        }
-    }
-}
-} // namespace KioSMTP
diff --git a/kioslave/src/smtp/response.h b/kioslave/src/smtp/response.h
deleted file mode 100644
index 9f5acd7..0000000
--- a/kioslave/src/smtp/response.h
+++ /dev/null
@@ -1,178 +0,0 @@
-/*  -*- c++ -*-
-    response.h
-
-    This file is part of kio_smtp, the KDE SMTP kioslave.
-    Copyright (c) 2003 Marc Mutz <mutz at kde.org>
-
-    This program is free software; you can redistribute it and/or modify it
-    under the terms of the GNU General Public License, version 2, as
-    published by the Free Software Foundation.
-
-    This program 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
-    General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-    In addition, as a special exception, the copyright holders give
-    permission to link the code of this program with any edition of
-    the Qt library by Trolltech AS, Norway (or with modified versions
-    of Qt that use the same license as Qt), and distribute linked
-    combinations including the two.  You must obey the GNU General
-    Public License in all respects for all of the code used other than
-    Qt.  If you modify this file, you may extend this exception to
-    your version of the file, but you are not obligated to do so.  If
-    you do not wish to do so, delete this exception statement from
-    your version.
-*/
-
-#ifndef __KIOSMTP_RESPONSE_H__
-#define __KIOSMTP_RESPONSE_H__
-
-#include <QList>
-#include <QString>
-typedef QList<QByteArray> QCStringList;
-
-class QString;
-
-namespace KioSMTP {
-class Response
-{
-public:
-    Response()
-        : mCode(0)
-        , mValid(true)
-        , mSawLastLine(false)
-        , mWellFormed(true)
-    {
-    }
-
-    void parseLine(const char *line)
-    {
-        parseLine(line, qstrlen(line));
-    }
-
-    void parseLine(const char *line, int len);
-
-    /** Return an internationalized error message according to the
-     *  response's code. */
-    QString errorMessage() const;
-    /** Translate the SMTP error code into a KIO one */
-    int errorCode() const;
-
-    enum Reply {
-        UnknownReply = -1,
-        PositivePreliminary = 1,
-        PositiveCompletion = 2,
-        PositiveIntermediate = 3,
-        TransientNegative = 4,
-        PermanentNegative = 5
-    };
-
-    enum Category {
-        UnknownCategory = -1,
-        SyntaxError = 0,
-        Information = 1,
-        Connections = 2,
-        MailSystem = 5
-    };
-
-    unsigned int code() const
-    {
-        return mCode;
-    }
-
-    unsigned int first() const
-    {
-        return code() / 100;
-    }
-
-    unsigned int second() const
-    {
-        return (code() % 100) / 10;
-    }
-
-    unsigned int third() const
-    {
-        return code() % 10;
-    }
-
-    bool isPositive() const
-    {
-        return first() <= 3 && first() >= 1;
-    }
-
-    bool isNegative() const
-    {
-        return first() == 4 || first() == 5;
-    }
-
-    bool isUnknown() const
-    {
-        return !isPositive() && !isNegative();
-    }
-
-    QCStringList lines() const
-    {
-        return mLines;
-    }
-
-    bool isValid() const
-    {
-        return mValid;
-    }
-
-    bool isComplete() const
-    {
-        return mSawLastLine;
-    }
-
-    /** Shortcut method.
-     *  @return true iff the response is valid, complete and positive
-     */
-    bool isOk() const
-    {
-        return isValid() && isComplete() && isPositive();
-    }
-
-    /** Indicates whether the response was well-formed, meaning it
-     *  obeyed the syntax of smtp responses. That the response
-     *  nevertheless is not valid may be caused by e.g. different
-     *  response codes in a multilie response. A non-well-formed
-     *  response is never valid.
-     */
-    bool isWellFormed() const
-    {
-        return mWellFormed;
-    }
-
-    void clear()
-    {
-        *this = Response();
-    }
-
-#ifdef KIOSMTP_COMPARATORS
-    bool operator==(const Response &other) const
-    {
-        return mCode == other.mCode
-               && mValid == other.mValid
-               && mSawLastLine == other.mSawLastLine
-               && mWellFormed == other.mWellFormed
-               && mLines == other.mLines;
-    }
-
-#endif
-
-private:
-    unsigned int mCode;
-    QCStringList mLines;
-    bool mValid;
-    bool mSawLastLine;
-    bool mWellFormed;
-};
-} // namespace KioSMTP
-
-#endif // __KIOSMTP_RESPONSE_H__
diff --git a/kioslave/src/smtp/smtp.cpp b/kioslave/src/smtp/smtp.cpp
deleted file mode 100644
index 180c721..0000000
--- a/kioslave/src/smtp/smtp.cpp
+++ /dev/null
@@ -1,652 +0,0 @@
-/*
- * Copyright (c) 2000, 2001 Alex Zepeda <zipzippy at sonic.net>
- * Copyright (c) 2001 Michael H�kel <Michael at Haeckel.Net>
- * Copyright (c) 2002 Aaron J. Seigo <aseigo at olympusproject.org>
- * Copyright (c) 2003 Marc Mutz <mutz at kde.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- */
-
-#include "smtp.h"
-#include "smtp_debug.h"
-
-extern "C" {
-#include <sasl/sasl.h>
-}
-
-#include "../common.h"
-#include "request.h"
-#include "response.h"
-#include "transactionstate.h"
-#include "command.h"
-#include "kioslavesession.h"
-using KioSMTP::Capabilities;
-using KioSMTP::Command;
-using KioSMTP::EHLOCommand;
-using KioSMTP::AuthCommand;
-using KioSMTP::MailFromCommand;
-using KioSMTP::RcptToCommand;
-using KioSMTP::DataCommand;
-using KioSMTP::TransferCommand;
-using KioSMTP::Request;
-using KioSMTP::Response;
-using KioSMTP::TransactionState;
-using KioSMTP::SMTPSessionInterface;
-
-#include <kemailsettings.h>
-
-#include <qdebug.h>
-#include <kio/slaveinterface.h>
-#include <KLocalizedString>
-#include <QUrl>
-
-#include <QHostInfo>
-#include <QDataStream>
-
-#include <memory>
-using std::unique_ptr;
-
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <assert.h>
-#ifdef Q_OS_WIN
-#include <Winsock2.h>
-#else
-#include <netdb.h>
-#endif
-
-extern "C" {
-Q_DECL_EXPORT int kdemain(int argc, char **argv);
-}
-
-int kdemain(int argc, char **argv)
-{
-    QCoreApplication app(argc, argv);
-    app.setApplicationName(QStringLiteral("kio_smtp"));
-
-    if (argc != 4) {
-        fprintf(stderr,
-                "Usage: kio_smtp protocol domain-socket1 domain-socket2\n");
-        exit(-1);
-    }
-
-    if (!initSASL()) {
-        exit(-1);
-    }
-    SMTPProtocol slave(argv[2], argv[3], qstricmp(argv[1], "smtps") == 0);
-    slave.dispatchLoop();
-    sasl_done();
-    return 0;
-}
-
-SMTPProtocol::SMTPProtocol(const QByteArray &pool, const QByteArray &app, bool useSSL)
-    : TCPSlaveBase(useSSL ? "smtps" : "smtp", pool, app, useSSL)
-    , m_sOldPort(0)
-    , m_opened(false)
-    , m_sessionIface(new KioSMTP::KioSlaveSession(this))
-{
-    //qCDebug(SMTP_LOG) << "SMTPProtocol::SMTPProtocol";
-}
-
-SMTPProtocol::~SMTPProtocol()
-{
-    //qCDebug(SMTP_LOG) << "SMTPProtocol::~SMTPProtocol";
-    smtp_close();
-    delete m_sessionIface;
-}
-
-void SMTPProtocol::openConnection()
-{
-    // Don't actually call smtp_open() yet. Just pretend that we are connected.
-    // We can't call smtp_open() here, as that does EHLO, and the EHLO command
-    // needs the fake hostname. However, we only get the fake hostname in put(), so
-    // we call smtp_open() there.
-    connected();
-}
-
-void SMTPProtocol::closeConnection()
-{
-    smtp_close();
-}
-
-void SMTPProtocol::special(const QByteArray &aData)
-{
-    QDataStream s(aData);
-    int what;
-    s >> what;
-    if (what == 'c') {
-        const QString response = m_sessionIface->capabilities().createSpecialResponse(
-            (isUsingSsl() && !isAutoSsl())
-            || m_sessionIface->haveCapability("STARTTLS"));
-        infoMessage(response);
-    } else if (what == 'N') {
-        if (!execute(Command::NOOP)) {
-            return;
-        }
-    } else {
-        error(KIO::ERR_INTERNAL, i18n("The application sent an invalid request."));
-        return;
-    }
-    finished();
-}
-
-// Usage: smtp://smtphost:port/send?to=user@host.com&subject=blah
-// If smtphost is the name of a profile, it'll use the information
-// provided by that profile.  If it's not a profile name, it'll use it as
-// nature intended.
-// One can also specify in the query:
-// headers=0 (turns off header generation)
-// to=emailaddress
-// cc=emailaddress
-// bcc=emailaddress
-// subject=text
-// profile=text (this will override the "host" setting)
-// hostname=text (used in the HELO)
-// body={7bit,8bit} (default: 7bit; 8bit activates the use of the 8BITMIME SMTP extension)
-void SMTPProtocol::put(const QUrl &url, int permissions, KIO::JobFlags flags)
-{
-    Q_UNUSED(permissions);
-    Q_UNUSED(flags);
-    Request request = Request::fromURL(url);   // parse settings from URL's query
-
-    KEMailSettings mset;
-    QUrl open_url = url;
-    if (!request.hasProfile()) {
-        //qCDebug(SMTP_LOG) << "kio_smtp: Profile is null";
-        bool hasProfile = mset.profiles().contains(open_url.host());
-        if (hasProfile) {
-            mset.setProfile(open_url.host());
-            open_url.setHost(mset.getSetting(KEMailSettings::OutServer));
-            m_sUser = mset.getSetting(KEMailSettings::OutServerLogin);
-            m_sPass = mset.getSetting(KEMailSettings::OutServerPass);
-
-            if (m_sUser.isEmpty()) {
-                m_sUser.clear();
-            }
-            if (m_sPass.isEmpty()) {
-                m_sPass.clear();
-            }
-            open_url.setUserName(m_sUser);
-            open_url.setPassword(m_sPass);
-            m_sServer = open_url.host();
-            m_port = open_url.port();
-        } else {
-            mset.setProfile(mset.defaultProfileName());
-        }
-    } else {
-        mset.setProfile(request.profileName());
-    }
-
-    // Check KEMailSettings to see if we've specified an E-Mail address
-    // if that worked, check to see if we've specified a real name
-    // and then format accordingly (either: emailaddress at host.com or
-    // Real Name <emailaddress at host.com>)
-    if (!request.hasFromAddress()) {
-        const QString from = mset.getSetting(KEMailSettings::EmailAddress);
-        if (!from.isNull()) {
-            request.setFromAddress(from);
-        } else if (request.emitHeaders()) {
-            error(KIO::ERR_NO_CONTENT, i18n("The sender address is missing."));
-            return;
-        }
-    }
-
-    if (!smtp_open(request.heloHostname())) {
-        error(KIO::ERR_SERVICE_NOT_AVAILABLE,
-              i18n("SMTPProtocol::smtp_open failed (%1)", // ### better error message?
-                   open_url.path()));
-        return;
-    }
-
-    if (request.is8BitBody()
-        && !m_sessionIface->haveCapability("8BITMIME") && !m_sessionIface->eightBitMimeRequested()) {
-        error(KIO::ERR_SERVICE_NOT_AVAILABLE,
-              i18n("Your server (%1) does not support sending of 8-bit messages.\n"
-                   "Please use base64 or quoted-printable encoding.", m_sServer));
-        return;
-    }
-
-    queueCommand(new MailFromCommand(m_sessionIface, request.fromAddress().toLatin1(),
-                                     request.is8BitBody(), request.size()));
-
-    // Loop through our To and CC recipients, and send the proper
-    // SMTP commands, for the benefit of the server.
-    const QStringList recipients = request.recipients();
-    for (QStringList::const_iterator it = recipients.begin(), end(recipients.end()); it != end; ++it) {
-        queueCommand(new RcptToCommand(m_sessionIface, (*it).toLatin1()));
-    }
-
-    queueCommand(Command::DATA);
-    queueCommand(new TransferCommand(m_sessionIface, request.headerFields(mset.getSetting(KEMailSettings::RealName))));
-
-    TransactionState ts;
-    if (!executeQueuedCommands(&ts)) {
-        if (ts.errorCode()) {
-            error(ts.errorCode(), ts.errorMessage());
-        }
-    } else {
-        finished();
-    }
-}
-
-void SMTPProtocol::setHost(const QString &host, quint16 port, const QString &user, const QString &pass)
-{
-    m_sServer = host;
-    m_port = port;
-    m_sUser = user;
-    m_sPass = pass;
-}
-
-bool SMTPProtocol::sendCommandLine(const QByteArray &cmdline)
-{
-    //kDebug( cmdline.length() < 4096, 7112) << "C: " << cmdline.data();
-    //kDebug( cmdline.length() >= 4096, 7112) << "C: <" << cmdline.length() << " bytes>";
-    if (cmdline.length() < 4096) {
-        qCDebug(SMTP_LOG) << "C: >>" << cmdline.trimmed().data() << "<<";
-    } else {
-        qCDebug(SMTP_LOG) << "C: <" << cmdline.length() << " bytes>";
-    }
-    ssize_t numWritten, cmdline_len = cmdline.length();
-    if ((numWritten = write(cmdline.data(), cmdline_len)) != cmdline_len) {
-        qCDebug(SMTP_LOG) << "Tried to write " << cmdline_len << " bytes, but only "
-                          << numWritten << " were written!" << endl;
-        error(KIO::ERR_SLAVE_DEFINED, i18n("Writing to socket failed."));
-        return false;
-    }
-    return true;
-}
-
-Response SMTPProtocol::getResponse(bool *ok)
-{
-    if (ok) {
-        *ok = false;
-    }
-
-    Response response;
-    char buf[2048];
-
-    int recv_len = 0;
-    do {
-        // wait for data...
-        if (!waitForResponse(600)) {
-            error(KIO::ERR_SERVER_TIMEOUT, m_sServer);
-            return response;
-        }
-
-        // ...read data...
-        recv_len = readLine(buf, sizeof(buf) - 1);
-        if (recv_len < 1 && !isConnected()) {
-            error(KIO::ERR_CONNECTION_BROKEN, m_sServer);
-            return response;
-        }
-
-        qCDebug(SMTP_LOG) << "S: >>" << QByteArray(buf, recv_len).trimmed().data() << "<<";
-        // ...and parse lines...
-        response.parseLine(buf, recv_len);
-
-        // ...until the response is complete or the parser is so confused
-        // that it doesn't think a RSET would help anymore:
-    } while (!response.isComplete() && response.isWellFormed());
-
-    if (!response.isValid()) {
-        error(KIO::ERR_NO_CONTENT, i18n("Invalid SMTP response (%1) received.", response.code()));
-        return response;
-    }
-
-    if (ok) {
-        *ok = true;
-    }
-
-    return response;
-}
-
-bool SMTPProtocol::executeQueuedCommands(TransactionState *ts)
-{
-    assert(ts);
-
-    if (m_sessionIface->canPipelineCommands()) {
-        qDebug() << "using pipelining";
-    }
-
-    while (!mPendingCommandQueue.isEmpty()) {
-        QByteArray cmdline = collectPipelineCommands(ts);
-        if (ts->failedFatally()) {
-            smtp_close(false);   // _hard_ shutdown
-            return false;
-        }
-        if (ts->failed()) {
-            break;
-        }
-        if (cmdline.isEmpty()) {
-            continue;
-        }
-        if (!sendCommandLine(cmdline)
-            || !batchProcessResponses(ts)
-            || ts->failedFatally()) {
-            smtp_close(false);   // _hard_ shutdown
-            return false;
-        }
-    }
-
-    if (ts->failed()) {
-        if (!execute(Command::RSET)) {
-            smtp_close(false);
-        }
-        return false;
-    }
-    return true;
-}
-
-QByteArray SMTPProtocol::collectPipelineCommands(TransactionState *ts)
-{
-    assert(ts);
-
-    QByteArray cmdLine;
-    unsigned int cmdLine_len = 0;
-
-    while (!mPendingCommandQueue.isEmpty()) {
-        Command *cmd = mPendingCommandQueue.head();
-
-        if (cmd->doNotExecute(ts)) {
-            delete mPendingCommandQueue.dequeue();
-            if (cmdLine_len) {
-                break;
-            } else {
-                continue;
-            }
-        }
-
-        if (cmdLine_len && cmd->mustBeFirstInPipeline()) {
-            break;
-        }
-
-        if (cmdLine_len && !m_sessionIface->canPipelineCommands()) {
-            break;
-        }
-
-        while (!cmd->isComplete() && !cmd->needsResponse()) {
-            const QByteArray currentCmdLine = cmd->nextCommandLine(ts);
-            if (ts->failedFatally()) {
-                return cmdLine;
-            }
-            const unsigned int currentCmdLine_len = currentCmdLine.length();
-
-            cmdLine_len += currentCmdLine_len;
-            cmdLine += currentCmdLine;
-
-            // If we are executing the transfer command, don't collect the whole
-            // command line (which may be several MBs) before sending it, but instead
-            // send the data each time we have collected 32 KB of the command line.
-            //
-            // This way, the progress information in clients like KMail works correctly,
-            // because otherwise, the TransferCommand would read the whole data from the
-            // job at once, then sending it. The progress update on the client however
-            // happens when sending data to the job, not when this slave writes the data
-            // to the socket. Therefore that progress update is incorrect.
-            //
-            // 32 KB seems to be a sensible limit. Additionally, a job can only transfer
-            // 32 KB at once anyway.
-            if (dynamic_cast<TransferCommand *>(cmd) != nullptr
-                && cmdLine_len >= 32 * 1024) {
-                return cmdLine;
-            }
-        }
-
-        mSentCommandQueue.enqueue(mPendingCommandQueue.dequeue());
-
-        if (cmd->mustBeLastInPipeline()) {
-            break;
-        }
-    }
-
-    return cmdLine;
-}
-
-bool SMTPProtocol::batchProcessResponses(TransactionState *ts)
-{
-    assert(ts);
-
-    while (!mSentCommandQueue.isEmpty()) {
-        Command *cmd = mSentCommandQueue.head();
-        assert(cmd->isComplete());
-
-        bool ok = false;
-        Response r = getResponse(&ok);
-        if (!ok) {
-            return false;
-        }
-        cmd->processResponse(r, ts);
-        if (ts->failedFatally()) {
-            return false;
-        }
-
-        delete mSentCommandQueue.dequeue();
-    }
-
-    return true;
-}
-
-void SMTPProtocol::queueCommand(int type)
-{
-    queueCommand(Command::createSimpleCommand(type, m_sessionIface));
-}
-
-bool SMTPProtocol::execute(int type, TransactionState *ts)
-{
-    unique_ptr<Command> cmd(Command::createSimpleCommand(type, m_sessionIface));
-    if (!cmd.get()) {
-        qCritical() << "Command::createSimpleCommand( " << type << " ) returned null!";
-    }
-    return execute(cmd.get(), ts);
-}
-
-// ### fold into pipelining engine? How? (execute() is often called
-// ### when command queues are _not_ empty!)
-bool SMTPProtocol::execute(Command *cmd, TransactionState *ts)
-{
-    if (!cmd) {
-        qCritical() << "SMTPProtocol::execute() called with no command to run!";
-    }
-
-    if (cmd->doNotExecute(ts)) {
-        return true;
-    }
-
-    do {
-        while (!cmd->isComplete() && !cmd->needsResponse()) {
-            const QByteArray cmdLine = cmd->nextCommandLine(ts);
-            if (ts && ts->failedFatally()) {
-                smtp_close(false);
-                return false;
-            }
-            if (cmdLine.isEmpty()) {
-                continue;
-            }
-            if (!sendCommandLine(cmdLine)) {
-                smtp_close(false);
-                return false;
-            }
-        }
-
-        bool ok = false;
-        Response r = getResponse(&ok);
-        if (!ok) {
-            // Only close without sending QUIT if the responce was incomplete
-            // rfc5321 forbidds a client from closing a connection without sending
-            // QUIT (section 4.1.1.10)
-            if (r.isComplete()) {
-                smtp_close();
-            } else {
-                smtp_close(false);
-            }
-            return false;
-        }
-        if (!cmd->processResponse(r, ts)) {
-            if ((ts && ts->failedFatally())
-                || cmd->closeConnectionOnError()
-                || !execute(Command::RSET)) {
-                smtp_close(false);
-            }
-            return false;
-        }
-    } while (!cmd->isComplete());
-
-    return true;
-}
-
-bool SMTPProtocol::smtp_open(const QString &fakeHostname)
-{
-    if (m_opened
-        && m_sOldPort == m_port
-        && m_sOldServer == m_sServer
-        && m_sOldUser == m_sUser
-        && (fakeHostname.isNull() || m_hostname == fakeHostname)) {
-        return true;
-    }
-
-    smtp_close();
-    if (!connectToHost(isAutoSsl() ? QStringLiteral("smtps") : QStringLiteral("smtp"), m_sServer, m_port)) {
-        return false;    // connectToHost has already send an error message.
-    }
-    m_opened = true;
-
-    bool ok = false;
-    Response greeting = getResponse(&ok);
-    if (!ok || !greeting.isOk()) {
-        if (ok) {
-            error(KIO::ERR_COULD_NOT_LOGIN,
-                  i18n("The server (%1) did not accept the connection.\n"
-                       "%2", m_sServer, greeting.errorMessage()));
-        }
-        smtp_close();
-        return false;
-    }
-
-    if (!fakeHostname.isNull()) {
-        m_hostname = fakeHostname;
-    } else {
-        // FIXME: We need a way to find the FQDN again. Also change in servertest then.
-        m_hostname = QHostInfo::localHostName();
-        if (m_hostname.isEmpty()) {
-            m_hostname = QStringLiteral("localhost.invalid");
-        } else if (!m_hostname.contains(QLatin1Char('.'))) {
-            m_hostname += QLatin1String(".localnet");
-        }
-    }
-
-    EHLOCommand ehloCmdPreTLS(m_sessionIface, m_hostname);
-    if (!execute(&ehloCmdPreTLS)) {
-        smtp_close();
-        return false;
-    }
-
-    if ((m_sessionIface->haveCapability("STARTTLS") /*### && canUseTLS()*/ && m_sessionIface->tlsRequested() != SMTPSessionInterface::ForceNoTLS)
-        || m_sessionIface->tlsRequested() == SMTPSessionInterface::ForceTLS) {
-        // For now we're gonna force it on.
-
-        if (execute(Command::STARTTLS)) {
-            // re-issue EHLO to refresh the capability list (could be have
-            // been faked before TLS was enabled):
-            EHLOCommand ehloCmdPostTLS(m_sessionIface, m_hostname);
-            if (!execute(&ehloCmdPostTLS)) {
-                smtp_close();
-                return false;
-            }
-        }
-    }
-    // Now we try and login
-    if (!authenticate()) {
-        smtp_close();
-        return false;
-    }
-
-    m_sOldPort = m_port;
-    m_sOldServer = m_sServer;
-    m_sOldUser = m_sUser;
-    m_sOldPass = m_sPass;
-
-    return true;
-}
-
-bool SMTPProtocol::authenticate()
-{
-    // return with success if the server doesn't support SMTP-AUTH or an user
-    // name is not specified and metadata doesn't tell us to force it.
-    if ((m_sUser.isEmpty() || !m_sessionIface->haveCapability("AUTH"))
-        && m_sessionIface->requestedSaslMethod().isEmpty()) {
-        return true;
-    }
-
-    KIO::AuthInfo authInfo;
-    authInfo.username = m_sUser;
-    authInfo.password = m_sPass;
-    authInfo.prompt = i18n("Username and password for your SMTP account:");
-
-    QStringList strList;
-
-    if (!m_sessionIface->requestedSaslMethod().isEmpty()) {
-        strList.append(m_sessionIface->requestedSaslMethod());
-    } else {
-        strList = m_sessionIface->capabilities().saslMethodsQSL();
-    }
-
-    const QByteArray ba = strList.join(QLatin1Char(' ')).toLatin1();
-    AuthCommand authCmd(m_sessionIface, ba.constData(), m_sServer, authInfo);
-    bool ret = execute(&authCmd);
-    m_sUser = authInfo.username;
-    m_sPass = authInfo.password;
-    return ret;
-}
-
-void SMTPProtocol::smtp_close(bool nice)
-{
-    if (!m_opened) {                // We're already closed
-        return;
-    }
-
-    if (nice) {
-        execute(Command::QUIT);
-    }
-    qCDebug(SMTP_LOG) << "closing connection";
-    disconnectFromHost();
-    m_sOldServer.clear();
-    m_sOldUser.clear();
-    m_sOldPass.clear();
-
-    m_sessionIface->clearCapabilities();
-    qDeleteAll(mPendingCommandQueue);
-    mPendingCommandQueue.clear();
-    qDeleteAll(mSentCommandQueue);
-    mSentCommandQueue.clear();
-
-    m_opened = false;
-}
-
-void SMTPProtocol::stat(const QUrl &url)
-{
-    QString path = url.path();
-    error(KIO::ERR_DOES_NOT_EXIST, url.path());
-}
diff --git a/kioslave/src/smtp/smtp.h b/kioslave/src/smtp/smtp.h
deleted file mode 100644
index 95217d0..0000000
--- a/kioslave/src/smtp/smtp.h
+++ /dev/null
@@ -1,125 +0,0 @@
-/* -*- c++ -*-
- * Copyright (c) 2000, 2001 Alex Zepeda <zipzippy at sonic.net>
- * Copyright (c) 2001 Michael H�kel <Michael at Haeckel.Net>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- */
-
-#ifndef _SMTP_H
-#define _SMTP_H
-
-#include <kio/tcpslavebase.h>
-
-#include "capabilities.h"
-
-#include <QQueue>
-#include <QByteArray>
-
-class QUrl;
-
-namespace KioSMTP {
-class Response;
-class TransactionState;
-class Command;
-class SMTPSessionInterface;
-class KioSlaveSession;
-}
-
-class SMTPProtocol : public KIO::TCPSlaveBase
-{
-    friend class KioSMTP::KioSlaveSession;
-public:
-    SMTPProtocol(const QByteArray &pool, const QByteArray &app, bool useSSL);
-    virtual ~SMTPProtocol();
-
-    virtual void setHost(const QString &host, quint16 port, const QString &user, const QString &pass) override;
-
-    void special(const QByteArray &aData) override;
-    void put(const QUrl &url, int permissions, KIO::JobFlags flags) override;
-    void stat(const QUrl &url) override;
-    void openConnection() override;
-    void closeConnection() override;
-
-protected:
-
-    bool smtp_open(const QString &fakeHostName);
-
-    /** Closes the connection. If @p nice is true (default), then QUIT
-        is sent and it's reponse waited for. */
-    void smtp_close(bool nice = true);
-
-    /** Execute command @p cmd */
-    bool execute(KioSMTP::Command *cmd, KioSMTP::TransactionState *ts = nullptr);
-    /** Execute a command of type @p type */
-    bool execute(int type, KioSMTP::TransactionState *ts = nullptr);
-    /** Execute the queued commands. If something goes horribly wrong
-        (sending command oline fails, getting response fails or some
-        command raises the failedFatally() flag in @p ts, shuts down the
-        connection with <code>smtp_close( false )</code>. If The
-        transaction fails gracefully (<code>ts->failed()</code> is
-        true), issues a RSET command.
-
-        @return true if transaction succeeded, false otherwise.
-    **/
-    bool executeQueuedCommands(KioSMTP::TransactionState *ts);
-
-    /** Parse a single response from the server. Single- vs. multiline
-        responses are correctly detected.
-
-        @param ok if not 0, returns whether response parsing was
-                  successful. Don't confuse this with negative responses
-                  (e.g. 5xx), which you can check for using
-                  @ref Response::isNegative()
-        @return the @ref Response object representing the server response.
-    **/
-    KioSMTP::Response getResponse(bool *ok);
-
-    bool authenticate();
-
-    bool sendCommandLine(const QByteArray &cmd);
-    QByteArray collectPipelineCommands(KioSMTP::TransactionState *ts);
-    bool batchProcessResponses(KioSMTP::TransactionState *ts);
-
-    void queueCommand(KioSMTP::Command *command)
-    {
-        mPendingCommandQueue.enqueue(command);
-    }
-
-    void queueCommand(int type);
-
-    quint16 m_sOldPort;
-    quint16 m_port;
-    bool m_opened;
-    QString m_sServer, m_sOldServer;
-    QString m_sUser, m_sOldUser;
-    QString m_sPass, m_sOldPass;
-    QString m_hostname;
-
-    typedef QQueue<KioSMTP::Command *> CommandQueue;
-    CommandQueue mPendingCommandQueue;
-    CommandQueue mSentCommandQueue;
-    KioSMTP::SMTPSessionInterface *m_sessionIface;
-};
-
-#endif // _SMTP_H
diff --git a/kioslave/src/smtp/smtp.protocol b/kioslave/src/smtp/smtp.protocol
deleted file mode 100644
index c7bf05b..0000000
--- a/kioslave/src/smtp/smtp.protocol
+++ /dev/null
@@ -1,16 +0,0 @@
-[Protocol]
-exec=kf5/kio/smtp
-protocol=smtp
-Capabilities=SASL
-input=none
-output=filesystem
-listing=Name,Type,Size
-reading=false
-writing=true
-deleting=false
-source=true
-makedir=false
-linking=false
-moving=false
-X-DocPath=kioslave5/smtp/index.html
-Icon=mail-folder-outbox
diff --git a/kioslave/src/smtp/smtps.protocol b/kioslave/src/smtp/smtps.protocol
deleted file mode 100644
index 98222d7..0000000
--- a/kioslave/src/smtp/smtps.protocol
+++ /dev/null
@@ -1,16 +0,0 @@
-[Protocol]
-exec=kf5/kio/smtp
-protocol=smtps
-Capabilities=SASL
-input=none
-output=filesystem
-listing=Name,Type,Size
-reading=false
-writing=true
-deleting=false
-source=true
-makedir=false
-linking=false
-moving=false
-X-DocPath=kioslave5/smtp/index.html
-Icon=mail-folder-outbox
diff --git a/kioslave/src/smtp/smtpsessioninterface.cpp b/kioslave/src/smtp/smtpsessioninterface.cpp
deleted file mode 100644
index b0e33df..0000000
--- a/kioslave/src/smtp/smtpsessioninterface.cpp
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
-    Copyright (c) 2010 Volker Krause <vkrause at 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 "smtpsessioninterface.h"
-
-using namespace KioSMTP;
-
-SMTPSessionInterface::~SMTPSessionInterface()
-{
-}
-
-void SMTPSessionInterface::parseFeatures(const KioSMTP::Response &ehloResponse)
-{
-    m_capabilities = Capabilities::fromResponse(ehloResponse);
-}
-
-const Capabilities &KioSMTP::SMTPSessionInterface::capabilities() const
-{
-    return m_capabilities;
-}
-
-void SMTPSessionInterface::clearCapabilities()
-{
-    m_capabilities.clear();
-}
-
-bool SMTPSessionInterface::haveCapability(const char *cap) const
-{
-    return m_capabilities.have(cap);
-}
-
-bool SMTPSessionInterface::canPipelineCommands() const
-{
-    return haveCapability("PIPELINING") && pipeliningRequested();
-}
-
-bool KioSMTP::SMTPSessionInterface::eightBitMimeRequested() const
-{
-    return false;
-}
-
-bool KioSMTP::SMTPSessionInterface::pipeliningRequested() const
-{
-    return true;
-}
diff --git a/kioslave/src/smtp/smtpsessioninterface.h b/kioslave/src/smtp/smtpsessioninterface.h
deleted file mode 100644
index 6f66507..0000000
--- a/kioslave/src/smtp/smtpsessioninterface.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
-    Copyright (c) 2010 Volker Krause <vkrause at 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.
-*/
-
-#ifndef KIOSMTP_SMTPSESSIONINTERFACE_H
-#define KIOSMTP_SMTPSESSIONINTERFACE_H
-
-#include "capabilities.h"
-
-class QByteArray;
-class QString;
-
-namespace KIO {
-class AuthInfo;
-}
-
-namespace KioSMTP {
-class Response;
-
-/** Interface to the SMTP session for command classes.
- * There are sub-classes for the in-process mode, the KIO slave mode and for unit testing.
- * @since 4.6
- */
-class SMTPSessionInterface
-{
-public:
-    /** TLS request state. */
-    enum TLSRequestState {
-        UseTLSIfAvailable,
-        ForceTLS,
-        ForceNoTLS
-    };
-
-    virtual ~SMTPSessionInterface();
-    virtual bool startSsl() = 0;
-
-    /** Parse capability response from the server. */
-    void parseFeatures(const KioSMTP::Response &ehloResponse);
-
-    /** Returns the server reported capabilities. */
-    const Capabilities &capabilities() const;
-
-    /** Clear the capabilities reported by the server (e.g. when reconnecting the session) */
-    void clearCapabilities();
-
-    /** This is a pure convenience wrapper around
-     *  @ref KioSMTP::Capabilities::have()
-     */
-    virtual bool haveCapability(const char *cap) const;
-
-    /** @return true is pipelining is available and allowed by metadata */
-    bool canPipelineCommands() const;
-
-    virtual void error(int id, const QString &msg) = 0;
-    /** Show information message box with message @p msg and caption @p caption. */
-    virtual void informationMessageBox(const QString &msg, const QString &caption) = 0;
-    virtual bool openPasswordDialog(KIO::AuthInfo &authInfo) = 0;
-    virtual void dataReq() = 0;
-    virtual int readData(QByteArray &ba) = 0;
-
-    /** SASL method requested for authentication. */
-    virtual QString requestedSaslMethod() const = 0;
-    /** TLS requested for encryption. */
-    virtual TLSRequestState tlsRequested() const = 0;
-    /** LF2CRLF and dot stuffing requested. */
-    virtual bool lf2crlfAndDotStuffingRequested() const = 0;
-    /** 8bit MIME support requested. */
-    virtual bool eightBitMimeRequested() const;
-    /** Pipelining has been requested. */
-    virtual bool pipeliningRequested() const;
-
-private:
-    KioSMTP::Capabilities m_capabilities;
-};
-}
-
-#endif
diff --git a/kioslave/src/smtp/tests/CMakeLists.txt b/kioslave/src/smtp/tests/CMakeLists.txt
deleted file mode 100644
index 38e3d1f..0000000
--- a/kioslave/src/smtp/tests/CMakeLists.txt
+++ /dev/null
@@ -1,71 +0,0 @@
-include(ECMMarkAsTest)
-
-set(QT_REQUIRED_VERSION "5.7.0")
-find_package(Qt5Test ${QT_REQUIRED_VERSION} CONFIG REQUIRED)
-
-set( EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR} )
-
-########### next target ###############
-
-if (WIN32)
-    set(extra_LIB ws2_32)
-endif()
-
-set(test_responseparser_SRCS test_responseparser.cpp )
-
-add_executable( test_responseparser ${test_responseparser_SRCS} )
-add_test( test_responseparser test_responseparser )
-ecm_mark_as_test(smtp-responseparser)
-target_link_libraries(test_responseparser   Qt5::Test KF5::I18n KF5::KIOCore ${extra_LIB})
-
-########### next target ###############
-
-set(test_headergeneration_SRCS test_headergeneration.cpp)
-ecm_qt_declare_logging_category(test_headergeneration_SRCS HEADER smtp_debug.h IDENTIFIER SMTP_LOG CATEGORY_NAME org.kde.pim.smtp)
-
-add_executable( test_headergeneration  ${test_headergeneration_SRCS} )
-add_test( test_headergeneration test_headergeneration )
-ecm_mark_as_test(smtp-headergeneration)
-
-target_link_libraries(test_headergeneration  Qt5::Test ${extra_LIB})
-
-
-########### next target ###############
-set(test_commands_SRCS test_commands.cpp )
-ecm_qt_declare_logging_category(test_commands_SRCS HEADER smtp_debug.h IDENTIFIER SMTP_LOG CATEGORY_NAME org.kde.pim.smtp)
-
-include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/../../ ${Sasl2_INCLUDE_DIRS}  )
-
-add_executable( test_commands ${test_commands_SRCS} )
-add_test( test_commands test_commands )
-ecm_mark_as_test(smtp-commands)
-target_link_libraries(test_commands   KF5::KIOCore ${Sasl2_LIBRARIES} Qt5::Test KF5::I18n ${extra_LIB})
-
-
-########### next target ###############
-set(interactivesmtpserver_SRCS interactivesmtpserver.cpp )
-
-add_executable( interactivesmtpserver ${interactivesmtpserver_SRCS} )
-ecm_mark_as_test(smtp-interactivesmtpserver)
-target_link_libraries(interactivesmtpserver    Qt5::Test Qt5::Widgets Qt5::Network)
-
-
-########### next target ###############
-set(test_capabilities_SRCS test_capabilities.cpp ../capabilities.cpp )
-
-include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/../)
-
-add_executable( test_capabilities ${test_capabilities_SRCS} )
-ecm_mark_as_test(test-capabilities)
-target_link_libraries(test_capabilities   KF5::KIOCore)
-
-
-########### next target ###############
-set( test_request_source requesttest.cpp ../request.cpp )
-ecm_qt_declare_logging_category(test_request_source HEADER smtp_debug.h IDENTIFIER SMTP_LOG CATEGORY_NAME org.kde.pim.smtp)
-
-add_executable( requesttest ${test_request_source})
-add_test(requesttest requesttest)
-ecm_mark_as_test(requesttest)
-target_link_libraries( requesttest Qt5::Test Qt5::Gui)
-
diff --git a/kioslave/src/smtp/tests/fakesession.h b/kioslave/src/smtp/tests/fakesession.h
deleted file mode 100644
index 3dde50b..0000000
--- a/kioslave/src/smtp/tests/fakesession.h
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
-    Copyright (c) 2010 Volker Krause <vkrause at 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.
-*/
-
-#ifndef KIOSMTP_FAKESESSION_H
-#define KIOSMTP_FAKESESSION_H
-
-#include "smtpsessioninterface.h"
-
-#include <QStringList>
-#include <kio/slavebase.h>
-
-namespace KioSMTP {
-class FakeSession : public SMTPSessionInterface
-{
-public:
-    FakeSession()
-    {
-        clear();
-    }
-
-    //
-    // public members to control the API emulation below:
-    //
-    bool startTLSReturnCode;
-    bool usesTLS; // ### unused below, most likely something wrong in the tests...
-    int lastErrorCode;
-    QString lastErrorMessage;
-    QString lastMessageBoxText;
-    QByteArray nextData;
-    int nextDataReturnCode;
-    QStringList caps;
-
-    bool eightBitMime;
-    bool lf2crlfAndDotStuff;
-    bool pipelining;
-    QString saslMethod;
-
-    void clear()
-    {
-        startTLSReturnCode = true;
-        usesTLS = false;
-        lastErrorCode = 0;
-        lastErrorMessage.clear();
-        lastMessageBoxText.clear();
-        nextData.resize(0);
-        nextDataReturnCode = -1;
-        caps.clear();
-
-        lf2crlfAndDotStuff = false;
-        saslMethod.clear();
-    }
-
-    //
-    // emulated API:
-    //
-    bool startSsl() override
-    {
-        return startTLSReturnCode;
-    }
-
-    bool haveCapability(const char *cap) const override
-    {
-        return caps.contains(QLatin1String(cap));
-    }
-
-    void error(int id, const QString &msg) override
-    {
-        lastErrorCode = id;
-        lastErrorMessage = msg;
-        qWarning() << id << msg;
-    }
-
-    void informationMessageBox(const QString &msg, const QString &caption) override
-    {
-        Q_UNUSED(caption);
-        lastMessageBoxText = msg;
-    }
-
-    bool openPasswordDialog(KIO::AuthInfo &) override
-    {
-        return true;
-    }
-
-    void dataReq() override
-    {
-        /* noop */
-    }
-
-    int readData(QByteArray &ba) override
-    {
-        ba = nextData;
-        return nextDataReturnCode;
-    }
-
-    bool lf2crlfAndDotStuffingRequested() const override
-    {
-        return lf2crlfAndDotStuff;
-    }
-
-    QString requestedSaslMethod() const override
-    {
-        return saslMethod;
-    }
-
-    TLSRequestState tlsRequested() const override
-    {
-        return SMTPSessionInterface::UseTLSIfAvailable;
-    }
-};
-}
-
-#include "smtpsessioninterface.cpp"
-#include "capabilities.cpp"
-
-#endif
diff --git a/kioslave/src/smtp/tests/interactivesmtpserver.cpp b/kioslave/src/smtp/tests/interactivesmtpserver.cpp
deleted file mode 100644
index 7068db1..0000000
--- a/kioslave/src/smtp/tests/interactivesmtpserver.cpp
+++ /dev/null
@@ -1,211 +0,0 @@
-/*  -*- c++ -*-
-    interactivesmtpserver.cc
-
-    Code based on the serverSocket example by Jesper Pedersen.
-
-    This file is part of the testsuite of kio_smtp, the KDE SMTP kioslave.
-    Copyright (c) 2004 Marc Mutz <mutz at 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 program 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
-    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.
-
-    In addition, as a special exception, the copyright holders give
-    permission to link the code of this program with any edition of
-    the Qt library by Trolltech AS, Norway (or with modified versions
-    of Qt that use the same license as Qt), and distribute linked
-    combinations including the two.  You must obey the GNU General
-    Public License in all respects for all of the code used other than
-    Qt.  If you modify this file, you may extend this exception to
-    your version of the file, but you are not obligated to do so.  If
-    you do not wish to do so, delete this exception statement from
-    your version.
-*/
-
-#include <QString>
-#include <QTextStream>
-#include <QApplication>
-#include <QLabel>
-#include <QLineEdit>
-#include <QPushButton>
-#include <QTextEdit>
-#include <QWidget>
-#include <QTcpSocket>
-#include <QVBoxLayout>
-#include <QHBoxLayout>
-
-#include "interactivesmtpserver.h"
-
-static const QHostAddress localhost(0x7f000001);   // 127.0.0.1
-
-static QString err2str(QAbstractSocket::SocketError error)
-{
-    switch (error) {
-    case QAbstractSocket::ConnectionRefusedError:
-        return QStringLiteral("Connection refused");
-    case QAbstractSocket::HostNotFoundError:
-        return QStringLiteral("Host not found");
-    default:
-        return QStringLiteral("Unknown error");
-    }
-}
-
-static QString escape(QString s)
-{
-    return s
-           .replace(QLatin1Char('&'), QLatin1String("&"))
-           .replace(QLatin1Char('>'), QLatin1String(">"))
-           .replace(QLatin1Char('<'), QLatin1String("<"))
-           .replace(QLatin1Char('"'), QLatin1String("""))
-    ;
-}
-
-static QString trim(const QString &s)
-{
-    if (s.endsWith(QLatin1String("\r\n"))) {
-        return s.left(s.length() - 2);
-    }
-    if (s.endsWith(QLatin1String("\r")) || s.endsWith(QLatin1String("\n"))) {
-        return s.left(s.length() - 1);
-    }
-    return s;
-}
-
-InteractiveSMTPServerWindow::~InteractiveSMTPServerWindow()
-{
-    if (mSocket) {
-        mSocket->close();
-        if (mSocket->state() == QAbstractSocket::ClosingState) {
-            connect(mSocket, SIGNAL(disconnected()),
-                    mSocket, SLOT(deleteLater()));
-        } else {
-            mSocket->deleteLater();
-        }
-        mSocket = nullptr;
-    }
-}
-
-void InteractiveSMTPServerWindow::slotSendResponse()
-{
-    const QString line = mLineEdit->text();
-    mLineEdit->clear();
-    QTextStream s(mSocket);
-    s << line + QLatin1String("\r\n");
-    slotDisplayServer(line);
-}
-
-InteractiveSMTPServer::InteractiveSMTPServer(QObject *parent)
-    : QTcpServer(parent)
-{
-    listen(localhost, 2525);
-    setMaxPendingConnections(1);
-
-    connect(this, SIGNAL(newConnection()), this, SLOT(newConnectionAvailable()));
-}
-
-void InteractiveSMTPServer::newConnectionAvailable()
-{
-    InteractiveSMTPServerWindow *w = new InteractiveSMTPServerWindow(nextPendingConnection());
-    w->show();
-}
-
-int main(int argc, char *argv[])
-{
-    QApplication app(argc, argv);
-
-    InteractiveSMTPServer server;
-
-    qDebug("Server should now listen on localhost:2525");
-    qDebug("Hit CTRL-C to quit.");
-
-    return app.exec();
-}
-
-InteractiveSMTPServerWindow::InteractiveSMTPServerWindow(QTcpSocket *socket, QWidget *parent)
-    : QWidget(parent)
-    , mSocket(socket)
-{
-    QPushButton *but;
-    Q_ASSERT(socket);
-
-    QVBoxLayout *vlay = new QVBoxLayout(this);
-
-    mTextEdit = new QTextEdit(this);
-    vlay->addWidget(mTextEdit, 1);
-    QWidget *mLayoutWidget = new QWidget;
-    vlay->addWidget(mLayoutWidget);
-
-    QHBoxLayout *hlay = new QHBoxLayout(mLayoutWidget);
-
-    mLineEdit = new QLineEdit(this);
-    mLabel = new QLabel(QStringLiteral("&Response:"), this);
-    mLabel->setBuddy(mLineEdit);
-    but = new QPushButton(QStringLiteral("&Send"), this);
-    hlay->addWidget(mLabel);
-    hlay->addWidget(mLineEdit, 1);
-    hlay->addWidget(but);
-
-    connect(mLineEdit, SIGNAL(returnPressed()), SLOT(slotSendResponse()));
-    connect(but, SIGNAL(clicked()), SLOT(slotSendResponse()));
-
-    but = new QPushButton(QStringLiteral("&Close Connection"), this);
-    vlay->addWidget(but);
-
-    connect(but, SIGNAL(clicked()), SLOT(slotConnectionClosed()));
-
-    connect(socket, SIGNAL(disconnected()), SLOT(slotConnectionClosed()));
-    connect(socket, SIGNAL(error(QAbstractSocket::SocketError)),
-            SLOT(slotError(QAbstractSocket::SocketError)));
-    connect(socket, SIGNAL(readyRead()), SLOT(slotReadyRead()));
-
-    mLineEdit->setText(QStringLiteral("220 hi there"));
-    mLineEdit->setFocus();
-}
-
-void InteractiveSMTPServerWindow::slotDisplayClient(const QString &s)
-{
-    mTextEdit->append(QLatin1String("C:") + escape(s));
-}
-
-void InteractiveSMTPServerWindow::slotDisplayServer(const QString &s)
-{
-    mTextEdit->append(QLatin1String("S:") + escape(s));
-}
-
-void InteractiveSMTPServerWindow::slotDisplayMeta(const QString &s)
-{
-    mTextEdit->append(QLatin1String("<font color=\"red\">") + escape(s) + QLatin1String("</font>"));
-}
-
-void InteractiveSMTPServerWindow::slotReadyRead()
-{
-    while (mSocket->canReadLine()) {
-        slotDisplayClient(trim(QString::fromLatin1(mSocket->readLine())));
-    }
-}
-
-void InteractiveSMTPServerWindow::slotError(QAbstractSocket::SocketError error)
-{
-    slotDisplayMeta(QString::fromLatin1("E: %1").arg(err2str(error)));
-}
-
-void InteractiveSMTPServerWindow::slotConnectionClosed()
-{
-    slotDisplayMeta(QStringLiteral("Connection closed by peer"));
-}
-
-void InteractiveSMTPServerWindow::slotCloseConnection()
-{
-    mSocket->close();
-}
diff --git a/kioslave/src/smtp/tests/interactivesmtpserver.h b/kioslave/src/smtp/tests/interactivesmtpserver.h
deleted file mode 100644
index 7441776..0000000
--- a/kioslave/src/smtp/tests/interactivesmtpserver.h
+++ /dev/null
@@ -1,85 +0,0 @@
-#ifndef INTERACTIVESMTPSERVER_H
-#define INTERACTIVESMTPSERVER_H
-
-/*  -*- c++ -*-
-    interactivesmtpserver.h
-
-    Code based on the serverSocket example by Jesper Pedersen.
-
-    This file is part of the testsuite of kio_smtp, the KDE SMTP kioslave.
-    Copyright (c) 2004 Marc Mutz <mutz at 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 program 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
-    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.
-
-    In addition, as a special exception, the copyright holders give
-    permission to link the code of this program with any edition of
-    the Qt library by Trolltech AS, Norway (or with modified versions
-    of Qt that use the same license as Qt), and distribute linked
-    combinations including the two.  You must obey the GNU General
-    Public License in all respects for all of the code used other than
-    Qt.  If you modify this file, you may extend this exception to
-    your version of the file, but you are not obligated to do so.  If
-    you do not wish to do so, delete this exception statement from
-    your version.
-*/
-
-#include <QWidget>
-#include <QTcpServer>
-
-class QLabel;
-class QLineEdit;
-class QTcpServer;
-class QTextEdit;
-
-class InteractiveSMTPServerWindow : public QWidget
-{
-    Q_OBJECT
-public:
-    InteractiveSMTPServerWindow(QTcpSocket *socket, QWidget *parent = nullptr);
-    ~InteractiveSMTPServerWindow();
-
-public Q_SLOTS:
-    void slotSendResponse();
-    void slotDisplayClient(const QString &s);
-    void slotDisplayServer(const QString &s);
-    void slotDisplayMeta(const QString &s);
-    void slotReadyRead();
-    void slotError(QAbstractSocket::SocketError error);
-    void slotConnectionClosed();
-    void slotCloseConnection();
-
-private:
-    QTcpSocket *mSocket;
-    QTextEdit *mTextEdit;
-    QLineEdit *mLineEdit;
-    QLabel *mLabel;
-};
-
-class InteractiveSMTPServer : public QTcpServer
-{
-    Q_OBJECT
-
-public:
-    InteractiveSMTPServer(QObject *parent = nullptr);
-    ~InteractiveSMTPServer()
-    {
-    }
-
-private Q_SLOTS:
-    void newConnectionAvailable();
-};
-
-#endif
diff --git a/kioslave/src/smtp/tests/requesttest.cpp b/kioslave/src/smtp/tests/requesttest.cpp
deleted file mode 100644
index 65afd51..0000000
--- a/kioslave/src/smtp/tests/requesttest.cpp
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
-  Copyright (c) 2014-2017 Montel Laurent <montel at 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 "requesttest.h"
-#include "../request.h"
-#include <qtest.h>
-#include <QUrl>
-RequestTest::RequestTest(QObject *parent)
-    : QObject(parent)
-{
-}
-
-RequestTest::~RequestTest()
-{
-}
-
-void RequestTest::shouldHaveDefaultValue()
-{
-    KioSMTP::Request request;
-    QVERIFY(request.to().isEmpty());
-    QVERIFY(request.cc().isEmpty());
-    QVERIFY(request.bcc().isEmpty());
-    QVERIFY(request.emitHeaders());
-    QVERIFY(!request.is8BitBody());
-    QVERIFY(request.profileName().isEmpty());
-    QVERIFY(request.fromAddress().isEmpty());
-    QVERIFY(request.heloHostname().isEmpty());
-    QCOMPARE(request.size(), static_cast<unsigned int>(0));
-}
-
-void RequestTest::shouldParseRequest_data()
-{
-    QTest::addColumn<QUrl>("smtpurl");
-    QTest::addColumn<QString>("to");
-    QTest::addColumn<QString>("from");
-    QTest::addColumn<QString>("cc");
-    QTest::addColumn<QString>("bcc");
-    QTest::addColumn<bool>("emitheaders");
-    QTest::addColumn<unsigned int>("size");
-    QTest::newRow("correct url") <<  QUrl(QStringLiteral("smtps://smtp.kde.org:465/send?headers=0&from=foo%40kde.org&to=foo%40kde.org&size=617"))
-                                 << QStringLiteral("foo at kde.org")
-                                 << QStringLiteral("foo at kde.org")
-                                 << QString()
-                                 << QString()
-                                 << false
-                                 << static_cast<unsigned int>(617);
-}
-
-void RequestTest::shouldParseRequest()
-{
-    QFETCH(QUrl, smtpurl);
-    QFETCH(QString, to);
-    QFETCH(QString, from);
-    QFETCH(QString, cc);
-    QFETCH(QString, bcc);
-    QFETCH(bool, emitheaders);
-    QFETCH(unsigned int, size);
-
-    KioSMTP::Request request = KioSMTP::Request::fromURL(smtpurl);
-    QCOMPARE(request.to().join(QLatin1Char(',')), to);
-    QCOMPARE(request.cc().join(QLatin1Char(',')), cc);
-    QCOMPARE(request.fromAddress(), from);
-    QCOMPARE(request.bcc().join(QLatin1Char(',')), bcc);
-    QCOMPARE(request.size(), size);
-    QCOMPARE(request.emitHeaders(), emitheaders);
-}
-
-QTEST_MAIN(RequestTest)
diff --git a/kioslave/src/smtp/tests/requesttest.h b/kioslave/src/smtp/tests/requesttest.h
deleted file mode 100644
index 44cf653..0000000
--- a/kioslave/src/smtp/tests/requesttest.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
-  Copyright (c) 2014-2017 Montel Laurent <montel at 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.
-*/
-
-#ifndef REQUESTTEST_H
-#define REQUESTTEST_H
-
-#include <QObject>
-
-class RequestTest : public QObject
-{
-    Q_OBJECT
-public:
-    explicit RequestTest(QObject *parent = nullptr);
-    ~RequestTest();
-private Q_SLOTS:
-    void shouldHaveDefaultValue();
-    void shouldParseRequest_data();
-    void shouldParseRequest();
-};
-
-#endif // REQUESTTEST_H
diff --git a/kioslave/src/smtp/tests/test_capabilities.cpp b/kioslave/src/smtp/tests/test_capabilities.cpp
deleted file mode 100644
index f0a275c..0000000
--- a/kioslave/src/smtp/tests/test_capabilities.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-#include <assert.h>
-#include "capabilities.h"
-#include <QObject>
-
-using namespace KioSMTP;
-
-int main()
-{
-    Capabilities c;
-
-    const QString size_cap = QObject::tr("SIZE 12");
-    c.add(size_cap);
-    // Capability was added
-    assert(c.have("SIZE"));
-
-    const QString expected_response = QObject::tr("SIZE=12");
-    const QString actual_response = c.createSpecialResponse(false);
-    // SIZE actually handled
-    assert(actual_response == expected_response);
-
-    const QString auth_cap = QObject::tr("AUTH GSSAPI");
-    c.add(auth_cap);
-    c.add(auth_cap);
-    // Duplicate methods was removed
-    assert(c.saslMethodsQSL().length() == 1);
-}
diff --git a/kioslave/src/smtp/tests/test_commands.cpp b/kioslave/src/smtp/tests/test_commands.cpp
deleted file mode 100644
index 416fadc..0000000
--- a/kioslave/src/smtp/tests/test_commands.cpp
+++ /dev/null
@@ -1,676 +0,0 @@
-#include <kio/global.h>
-#include <kio/authinfo.h>
-#include <qdebug.h>
-
-#define KIOSMTP_COMPARATORS // for TransactionState::operator==
-#include "fakesession.h"
-#include "command.h"
-#include "response.h"
-#include "transactionstate.h"
-#include "common.h"
-#include "smtp_debug.h"
-#include <assert.h>
-
-using namespace KioSMTP;
-
-static const char *foobarbaz = ".Foo bar baz";
-static const unsigned int foobarbaz_len = qstrlen(foobarbaz);
-
-static const char *foobarbaz_dotstuffed = "..Foo bar baz";
-static const unsigned int foobarbaz_dotstuffed_len = qstrlen(foobarbaz_dotstuffed);
-
-static const char *foobarbaz_lf = ".Foo bar baz\n";
-static const unsigned int foobarbaz_lf_len = qstrlen(foobarbaz_lf);
-
-static const char *foobarbaz_crlf = "..Foo bar baz\r\n";
-static const unsigned int foobarbaz_crlf_len = qstrlen(foobarbaz_crlf);
-
-static void checkSuccessfulTransferCommand(bool, bool, bool, bool, bool);
-
-int main(int, char **)
-{
-    if (!initSASL()) {
-        exit(-1);
-    }
-
-    FakeSession smtp;
-    Response r;
-    TransactionState ts, ts2;
-
-    //
-    // EHLO / HELO
-    //
-
-    smtp.clear();
-    EHLOCommand ehlo(&smtp, QStringLiteral("mail.example.com"));
-    // flags
-    assert(ehlo.closeConnectionOnError());
-    assert(ehlo.mustBeLastInPipeline());
-    assert(!ehlo.mustBeFirstInPipeline());
-
-    // initial state
-    assert(!ehlo.isComplete());
-    assert(!ehlo.doNotExecute(nullptr));
-    assert(!ehlo.needsResponse());
-
-    // dynamics 1: EHLO succeeds
-    assert(ehlo.nextCommandLine(nullptr) == "EHLO mail.example.com\r\n");
-    assert(!ehlo.isComplete());   // EHLO may fail and we then try HELO
-    assert(ehlo.needsResponse());
-    r.clear();
-    r.parseLine("250-mail.example.net\r\n");
-    r.parseLine("250-PIPELINING\r\n");
-    r.parseLine("250 8BITMIME\r\n");
-    assert(ehlo.processResponse(r, nullptr) == true);
-    assert(ehlo.isComplete());
-    assert(!ehlo.needsResponse());
-    assert(smtp.lastErrorCode == 0);
-    assert(smtp.lastErrorMessage.isNull());
-
-    // dynamics 2: EHLO fails with "unknown command"
-    smtp.clear();
-    EHLOCommand ehlo2(&smtp, QStringLiteral("mail.example.com"));
-    ehlo2.nextCommandLine(nullptr);
-    r.clear();
-    r.parseLine("500 unknown command\r\n");
-    assert(ehlo2.processResponse(r, nullptr) == true);
-    assert(!ehlo2.isComplete());
-    assert(!ehlo2.needsResponse());
-    assert(ehlo2.nextCommandLine(nullptr) == "HELO mail.example.com\r\n");
-    assert(ehlo2.isComplete());
-    assert(ehlo2.needsResponse());
-    r.clear();
-    r.parseLine("250 mail.example.net\r\n");
-    assert(ehlo2.processResponse(r, nullptr) == true);
-    assert(!ehlo2.needsResponse());
-    assert(smtp.lastErrorCode == 0);
-    assert(smtp.lastErrorMessage.isNull());
-
-    // dynamics 3: EHLO fails with unknown response code
-    smtp.clear();
-    EHLOCommand ehlo3(&smtp, QStringLiteral("mail.example.com"));
-    ehlo3.nextCommandLine(nullptr);
-    r.clear();
-    r.parseLine("545 you don't know me\r\n");
-    assert(ehlo3.processResponse(r, nullptr) == false);
-    assert(ehlo3.isComplete());
-    assert(!ehlo3.needsResponse());
-    assert(smtp.lastErrorCode == KIO::ERR_UNKNOWN);
-
-    // dynamics 4: EHLO _and_ HELO fail with "command unknown"
-    smtp.clear();
-    EHLOCommand ehlo4(&smtp, QStringLiteral("mail.example.com"));
-    ehlo4.nextCommandLine(nullptr);
-    r.clear();
-    r.parseLine("500 unknown command\r\n");
-    ehlo4.processResponse(r, nullptr);
-    ehlo4.nextCommandLine(nullptr);
-    r.clear();
-    r.parseLine("500 unknown command\r\n");
-    assert(ehlo4.processResponse(r, nullptr) == false);
-    assert(ehlo4.isComplete());
-    assert(!ehlo4.needsResponse());
-    assert(smtp.lastErrorCode == KIO::ERR_INTERNAL_SERVER);
-
-    //
-    // STARTTLS
-    //
-
-    smtp.clear();
-    StartTLSCommand tls(&smtp);
-    // flags
-    assert(tls.closeConnectionOnError());
-    assert(tls.mustBeLastInPipeline());
-    assert(!tls.mustBeFirstInPipeline());
-
-    // initial state
-    assert(!tls.isComplete());
-    assert(!tls.doNotExecute(nullptr));
-    assert(!tls.needsResponse());
-
-    // dynamics 1: ok from server, TLS negotiation successful
-    ts.clear();
-    ts2 = ts;
-    assert(tls.nextCommandLine(&ts) == "STARTTLS\r\n");
-    assert(ts == ts2);
-    assert(tls.isComplete());
-    assert(tls.needsResponse());
-    r.clear();
-    r.parseLine("220 Go ahead");
-    smtp.startTLSReturnCode = true;
-    assert(tls.processResponse(r, &ts) == true);
-    assert(!tls.needsResponse());
-    assert(smtp.lastErrorCode == 0);
-
-    // dynamics 2: NAK from server
-    smtp.clear();
-    StartTLSCommand tls2(&smtp);
-    ts.clear();
-    tls2.nextCommandLine(&ts);
-    r.clear();
-    r.parseLine("454 TLS temporarily disabled");
-    smtp.startTLSReturnCode = true;
-    assert(tls2.processResponse(r, &ts) == false);
-    assert(!tls2.needsResponse());
-    assert(smtp.lastErrorCode == KIO::ERR_SERVICE_NOT_AVAILABLE);
-
-    // dynamics 3: ok from server, TLS negotiation unsuccessful
-    smtp.clear();
-    StartTLSCommand tls3(&smtp);
-    ts.clear();
-    tls3.nextCommandLine(&ts);
-    r.clear();
-    r.parseLine("220 Go ahead");
-    smtp.startTLSReturnCode = false;
-    assert(tls.processResponse(r, &ts) == false);
-    assert(!tls.needsResponse());
-
-    //
-    // AUTH
-    //
-
-    smtp.clear();
-    QStringList mechs;
-    mechs.append(QStringLiteral("PLAIN"));
-    smtp.saslMethod = QStringLiteral("PLAIN");
-    KIO::AuthInfo authInfo;
-    authInfo.username = QStringLiteral("user");
-    authInfo.password = QStringLiteral("pass");
-    AuthCommand auth(&smtp, "PLAIN", QStringLiteral("mail.example.com"), authInfo);
-    // flags
-    assert(auth.closeConnectionOnError());
-    assert(auth.mustBeLastInPipeline());
-    assert(!auth.mustBeFirstInPipeline());
-
-    // initial state
-    assert(!auth.isComplete());
-    assert(!auth.doNotExecute(nullptr));
-    assert(!auth.needsResponse());
-
-    // dynamics 1: TLS, so AUTH should include initial-response:
-    smtp.usesTLS = true;
-    ts.clear();
-    ts2 = ts;
-    assert(auth.nextCommandLine(&ts) == "AUTH PLAIN dXNlcgB1c2VyAHBhc3M=\r\n");
-    assert(auth.isComplete());
-    assert(auth.needsResponse());
-    assert(ts == ts2);
-    r.clear();
-    r.parseLine("250 OK");
-
-    // dynamics 2: No TLS, so AUTH should not include initial-response:
-    /* FIXME fails since nothing evaluates useTLS = false anywhere...
-    smtp.clear();
-    smtp.saslMethod = "PLAIN";
-    smtp.usesTLS = false;
-    authInfo = KIO::AuthInfo();
-    authInfo.username = "user";
-    authInfo.password = "pass";
-    AuthCommand auth2( &smtp, "PLAIN", "mail.example.com", authInfo );
-    ts.clear();
-    assert( auth2.nextCommandLine( &ts ) == "AUTH PLAIN\r\n" );
-    assert( !auth2.isComplete() );
-    assert( auth2.needsResponse() );
-    r.clear();
-    r.parseLine( "334 Go on" );
-    assert( auth2.processResponse( r, &ts ) == true );
-    assert( auth2.nextCommandLine( &ts ) == "dXNlcgB1c2VyAHBhc3M=\r\n" );
-    assert( auth2.isComplete() );
-    assert( auth2.needsResponse() );*/
-
-    // dynamics 3: LOGIN
-    smtp.clear();
-    smtp.saslMethod = QStringLiteral("LOGIN");
-    mechs.clear();
-    mechs.append(QStringLiteral("LOGIN"));
-    authInfo = KIO::AuthInfo();
-    authInfo.username = QStringLiteral("user");
-    authInfo.password = QStringLiteral("pass");
-    AuthCommand auth3(&smtp, "LOGIN", QStringLiteral("mail.example.com"), authInfo);
-    ts.clear();
-    ts2 = ts;
-    assert(auth3.nextCommandLine(&ts) == "AUTH LOGIN\r\n");
-    assert(!auth3.isComplete());
-    assert(auth3.needsResponse());
-    r.clear();
-    r.parseLine("334 VXNlcm5hbWU6");
-    assert(auth3.processResponse(r, &ts) == true);
-    assert(!auth3.needsResponse());
-    assert(auth3.nextCommandLine(&ts) == "dXNlcg==\r\n");
-    assert(!auth3.isComplete());
-    assert(auth3.needsResponse());
-    r.clear();
-    r.parseLine("334 go on");
-    assert(auth3.processResponse(r, &ts) == true);
-    assert(!auth3.needsResponse());
-    assert(auth3.nextCommandLine(&ts) == "cGFzcw==\r\n");
-    assert(auth3.isComplete());
-    assert(auth3.needsResponse());
-    r.clear();
-    r.parseLine("250 OK");
-    assert(auth3.processResponse(r, &ts) == true);
-    assert(!auth3.needsResponse());
-    assert(!smtp.lastErrorCode);
-    assert(ts == ts2);
-
-    //
-    // MAIL FROM:
-    //
-
-    smtp.clear();
-    MailFromCommand mail(&smtp, "joe at user.org");
-    // flags
-    assert(!mail.closeConnectionOnError());
-    assert(!mail.mustBeLastInPipeline());
-    assert(!mail.mustBeFirstInPipeline());
-
-    // initial state
-    assert(!mail.isComplete());
-    assert(!mail.doNotExecute(nullptr));
-    assert(!mail.needsResponse());
-
-    // dynamics: success, no size, no 8bit
-    ts.clear();
-    ts2 = ts;
-    assert(mail.nextCommandLine(&ts) == "MAIL FROM:<joe at user.org>\r\n");
-    assert(ts2 == ts);
-    assert(mail.isComplete());
-    assert(mail.needsResponse());
-    r.clear();
-    r.parseLine("250 Ok");
-    assert(mail.processResponse(r, &ts) == true);
-    assert(!mail.needsResponse());
-    assert(ts == ts2);
-    assert(smtp.lastErrorCode == 0);
-
-    // dynamics: success, size, 8bit, but no SIZE, 8BITMIME caps
-    smtp.clear();
-    MailFromCommand mail2(&smtp, "joe at user.org", true, 500);
-    ts.clear();
-    ts2 = ts;
-    assert(mail2.nextCommandLine(&ts) == "MAIL FROM:<joe at user.org>\r\n");
-    assert(ts == ts2);
-
-    // dynamics: success, size, 8bit, SIZE, 8BITMIME caps
-    smtp.clear();
-    MailFromCommand mail3(&smtp, "joe at user.org", true, 500);
-    ts.clear();
-    ts2 = ts;
-    smtp.caps << QStringLiteral("SIZE") << QStringLiteral("8BITMIME");
-    assert(mail3.nextCommandLine(&ts) == "MAIL FROM:<joe at user.org> BODY=8BITMIME SIZE=500\r\n");
-    assert(ts == ts2);
-
-    // dynamics: failure
-    smtp.clear();
-    MailFromCommand mail4(&smtp, "joe at user.org");
-    ts.clear();
-    mail4.nextCommandLine(&ts);
-    r.clear();
-    r.parseLine("503 Bad sequence of commands");
-    assert(mail4.processResponse(r, &ts) == false);
-    assert(mail4.isComplete());
-    assert(!mail4.needsResponse());
-    assert(ts.failed());
-    assert(!ts.failedFatally());
-    assert(smtp.lastErrorCode == 0);
-
-    //
-    // RCPT TO:
-    //
-
-    smtp.clear();
-    RcptToCommand rcpt(&smtp, "joe at user.org");
-    // flags
-    assert(!rcpt.closeConnectionOnError());
-    assert(!rcpt.mustBeLastInPipeline());
-    assert(!rcpt.mustBeFirstInPipeline());
-
-    // initial state
-    assert(!rcpt.isComplete());
-    assert(!rcpt.doNotExecute(nullptr));
-    assert(!rcpt.needsResponse());
-
-    // dynamics: success
-    ts.clear();
-    ts2 = ts;
-    assert(rcpt.nextCommandLine(&ts) == "RCPT TO:<joe at user.org>\r\n");
-    assert(ts == ts2);
-    assert(rcpt.isComplete());
-    assert(rcpt.needsResponse());
-    r.clear();
-    r.parseLine("250 Ok");
-    assert(rcpt.processResponse(r, &ts) == true);
-    assert(!rcpt.needsResponse());
-    assert(ts.atLeastOneRecipientWasAccepted());
-    assert(!ts.haveRejectedRecipients());
-    assert(!ts.failed());
-    assert(!ts.failedFatally());
-    assert(smtp.lastErrorCode == 0);
-
-    // dynamics: failure
-    smtp.clear();
-    RcptToCommand rcpt2(&smtp, "joe at user.org");
-    ts.clear();
-    rcpt2.nextCommandLine(&ts);
-    r.clear();
-    r.parseLine("530 5.7.1 Relaying not allowed!");
-    assert(rcpt2.processResponse(r, &ts) == false);
-    assert(rcpt2.isComplete());
-    assert(!rcpt2.needsResponse());
-    assert(!ts.atLeastOneRecipientWasAccepted());
-    assert(ts.haveRejectedRecipients());
-    assert(ts.rejectedRecipients().count() == 1);
-    assert(ts.rejectedRecipients().front().recipient == QLatin1String("joe at user.org"));
-    assert(ts.failed());
-    assert(!ts.failedFatally());
-    assert(smtp.lastErrorCode == 0);
-
-    // dynamics: success and failure combined
-    smtp.clear();
-    RcptToCommand rcpt3(&smtp, "info at example.com");
-    RcptToCommand rcpt4(&smtp, "halloween at microsoft.com");
-    RcptToCommand rcpt5(&smtp, "joe at user.org");
-    ts.clear();
-    rcpt3.nextCommandLine(&ts);
-    r.clear();
-    r.parseLine("530 5.7.1 Relaying not allowed!");
-    rcpt3.processResponse(r, &ts);
-
-    rcpt4.nextCommandLine(&ts);
-    r.clear();
-    r.parseLine("250 Ok");
-    rcpt4.processResponse(r, &ts);
-
-    rcpt5.nextCommandLine(&ts);
-    r.clear();
-    r.parseLine("250 Ok");
-    assert(ts.failed());
-    assert(!ts.failedFatally());
-    assert(ts.haveRejectedRecipients());
-    assert(ts.atLeastOneRecipientWasAccepted());
-    assert(smtp.lastErrorCode == 0);
-
-    //
-    // DATA (init)
-    //
-
-    smtp.clear();
-    DataCommand data(&smtp);
-    // flags
-    assert(!data.closeConnectionOnError());
-    assert(data.mustBeLastInPipeline());
-    assert(!data.mustBeFirstInPipeline());
-
-    // initial state
-    assert(!data.isComplete());
-    assert(!data.doNotExecute(nullptr));
-    assert(!data.needsResponse());
-
-    // dynamics: success
-    ts.clear();
-    assert(data.nextCommandLine(&ts) == "DATA\r\n");
-    assert(data.isComplete());
-    assert(data.needsResponse());
-    assert(ts.dataCommandIssued());
-    assert(!ts.dataCommandSucceeded());
-    r.clear();
-    r.parseLine("354 Send data, end in <CR><LF>.<CR><LF>");
-    assert(data.processResponse(r, &ts) == true);
-    assert(!data.needsResponse());
-    assert(ts.dataCommandSucceeded());
-    assert(ts.dataResponse() == r);
-    assert(smtp.lastErrorCode == 0);
-
-    // dynamics: failure
-    smtp.clear();
-    DataCommand data2(&smtp);
-    ts.clear();
-    data2.nextCommandLine(&ts);
-    r.clear();
-    r.parseLine("551 No valid recipients");
-    assert(data2.processResponse(r, &ts) == false);
-    assert(!data2.needsResponse());
-    assert(!ts.dataCommandSucceeded());
-    assert(ts.dataResponse() == r);
-    assert(smtp.lastErrorCode == 0);
-
-    //
-    // DATA (transfer)
-    //
-
-    TransferCommand xfer(&smtp, nullptr);
-    // flags
-    assert(!xfer.closeConnectionOnError());
-    assert(!xfer.mustBeLastInPipeline());
-    assert(xfer.mustBeFirstInPipeline());
-
-    // initial state
-    assert(!xfer.isComplete());
-    assert(!xfer.needsResponse());
-
-    // dynamics 1: DATA command failed
-    ts.clear();
-    r.clear();
-    r.parseLine("551 no valid recipients");
-    ts.setDataCommandIssued(true);
-    ts.setDataCommandSucceeded(false, r);
-    assert(xfer.doNotExecute(&ts));
-
-    // dynamics 2: some recipients rejected, but not all
-    smtp.clear();
-    TransferCommand xfer2(&smtp, nullptr);
-    ts.clear();
-    ts.setRecipientAccepted();
-    ts.addRejectedRecipient(QStringLiteral("joe at user.org"), QStringLiteral("No relaying allowed"));
-    ts.setDataCommandIssued(true);
-    r.clear();
-    r.parseLine("354 go on");
-    ts.setDataCommandSucceeded(true, r);
-    // ### will change with allow-partial-delivery option:
-    assert(xfer.doNotExecute(&ts));
-
-    // successful dynamics with all combinations of:
-    enum {
-        EndInLF = 1,
-        PerformDotStuff = 2,
-        UngetLast = 4,
-        Preloading = 8,
-        Error = 16,
-        EndOfOptions = 32
-    };
-    for (unsigned int i = 0; i < EndOfOptions; ++i) {
-        checkSuccessfulTransferCommand(i & Error, i & Preloading, i & UngetLast,
-                                       i & PerformDotStuff, i & EndInLF);
-    }
-
-    //
-    // NOOP
-    //
-
-    smtp.clear();
-    NoopCommand noop(&smtp);
-    // flags
-    assert(!noop.closeConnectionOnError());
-    assert(noop.mustBeLastInPipeline());
-    assert(!noop.mustBeFirstInPipeline());
-
-    // initial state
-    assert(!noop.isComplete());
-    assert(!noop.doNotExecute(&ts));
-    assert(!noop.needsResponse());
-
-    // dynamics: success (failure is tested with RSET)
-    assert(noop.nextCommandLine(nullptr) == "NOOP\r\n");
-    assert(noop.isComplete());
-    assert(noop.needsResponse());
-    r.clear();
-    r.parseLine("250 Ok");
-    assert(noop.processResponse(r, nullptr) == true);
-    assert(noop.isComplete());
-    assert(!noop.needsResponse());
-    assert(smtp.lastErrorCode == 0);
-    assert(smtp.lastErrorMessage.isNull());
-
-    //
-    // RSET
-    //
-
-    smtp.clear();
-    RsetCommand rset(&smtp);
-    // flags
-    assert(rset.closeConnectionOnError());
-    assert(!rset.mustBeLastInPipeline());
-    assert(!rset.mustBeFirstInPipeline());
-
-    // initial state
-    assert(!rset.isComplete());
-    assert(!rset.doNotExecute(&ts));
-    assert(!rset.needsResponse());
-
-    // dynamics: failure (success is tested with NOOP/QUIT)
-    assert(rset.nextCommandLine(nullptr) == "RSET\r\n");
-    assert(rset.isComplete());
-    assert(rset.needsResponse());
-    r.clear();
-    r.parseLine("502 command not implemented");
-    assert(rset.processResponse(r, nullptr) == false);
-    assert(rset.isComplete());
-    assert(!rset.needsResponse());
-    assert(smtp.lastErrorCode == 0);   // an RSET failure isn't worth it, is it?
-    assert(smtp.lastErrorMessage.isNull());
-
-    //
-    // QUIT
-    //
-
-    smtp.clear();
-    QuitCommand quit(&smtp);
-    // flags
-    assert(quit.closeConnectionOnError());
-    assert(quit.mustBeLastInPipeline());
-    assert(!quit.mustBeFirstInPipeline());
-
-    // initial state
-    assert(!quit.isComplete());
-    assert(!quit.doNotExecute(nullptr));
-    assert(!quit.needsResponse());
-
-    // dynamics 1: success
-    assert(quit.nextCommandLine(nullptr) == "QUIT\r\n");
-    assert(quit.isComplete());
-    assert(quit.needsResponse());
-    r.clear();
-    r.parseLine("221 Goodbye");
-    assert(quit.processResponse(r, nullptr) == true);
-    assert(quit.isComplete());
-    assert(!quit.needsResponse());
-    assert(smtp.lastErrorCode == 0);
-    assert(smtp.lastErrorMessage.isNull());
-
-    // dynamics 2: success
-    smtp.clear();
-    QuitCommand quit2(&smtp);
-    quit2.nextCommandLine(nullptr);
-    r.clear();
-    r.parseLine("500 unknown command");
-    assert(quit2.processResponse(r, nullptr) == false);
-    assert(quit2.isComplete());
-    assert(!quit2.needsResponse());
-    assert(smtp.lastErrorCode == 0);   // an QUIT failure isn't worth it, is it?
-    assert(smtp.lastErrorMessage.isNull());
-
-    return 0;
-}
-
-void checkSuccessfulTransferCommand(bool error, bool preload, bool ungetLast, bool slaveDotStuff, bool mailEndsInNewline)
-{
-    qDebug() << "   ===== checkTransferCommand( "
-             << error << ", "
-             << preload << ", "
-             << ungetLast << ", "
-             << slaveDotStuff << ", "
-             << mailEndsInNewline << " ) =====" << endl;
-
-    FakeSession smtp;
-    if (slaveDotStuff) {
-        smtp.lf2crlfAndDotStuff = true;
-    }
-
-    Response r;
-
-    const char *s_pre = slaveDotStuff
-                        ? mailEndsInNewline ? foobarbaz_lf : foobarbaz
-                        :
-                        mailEndsInNewline ? foobarbaz_crlf : foobarbaz_dotstuffed;
-    const unsigned int s_pre_len = qstrlen(s_pre);
-
-    const char *s_post = mailEndsInNewline ? foobarbaz_crlf : foobarbaz_dotstuffed;
-    //const unsigned int s_post_len = qstrlen( s_post );
-
-    TransferCommand xfer(&smtp, preload ? s_post : nullptr);
-
-    TransactionState ts;
-    ts.setRecipientAccepted();
-    ts.setDataCommandIssued(true);
-    r.clear();
-    r.parseLine("354 ok");
-    ts.setDataCommandSucceeded(true, r);
-    assert(!xfer.doNotExecute(&ts));
-    if (preload) {
-        assert(xfer.nextCommandLine(&ts) == s_post);
-        assert(!xfer.isComplete());
-        assert(!xfer.needsResponse());
-        assert(!ts.failed());
-        assert(smtp.lastErrorCode == 0);
-    }
-    smtp.nextData = QByteArray(s_pre, s_pre_len);
-    smtp.nextDataReturnCode = s_pre_len;
-    assert(xfer.nextCommandLine(&ts) == s_post);
-    assert(!xfer.isComplete());
-    assert(!xfer.needsResponse());
-    assert(!ts.failed());
-    assert(smtp.lastErrorCode == 0);
-    smtp.nextData.resize(0);
-    smtp.nextDataReturnCode = 0;
-    if (ungetLast) {
-        xfer.ungetCommandLine(xfer.nextCommandLine(&ts), &ts);
-        assert(!xfer.isComplete());
-        assert(!xfer.needsResponse());
-        assert(!ts.complete());
-        smtp.nextDataReturnCode = -1; // double read -> error
-    }
-    if (mailEndsInNewline) {
-        assert(xfer.nextCommandLine(&ts) == ".\r\n");
-    } else {
-        assert(xfer.nextCommandLine(&ts) == "\r\n.\r\n");
-    }
-    assert(xfer.isComplete());
-    assert(xfer.needsResponse());
-    assert(!ts.complete());
-    assert(!ts.failed());
-    assert(smtp.lastErrorCode == 0);
-    r.clear();
-    if (error) {
-        r.parseLine("552 Exceeded storage allocation");
-        assert(xfer.processResponse(r, &ts) == false);
-        assert(!xfer.needsResponse());
-        assert(ts.complete());
-        assert(ts.failed());
-        assert(smtp.lastErrorCode == KIO::ERR_DISK_FULL);
-    } else {
-        r.parseLine("250 Message accepted");
-        assert(xfer.processResponse(r, &ts) == true);
-        assert(!xfer.needsResponse());
-        assert(ts.complete());
-        assert(!ts.failed());
-        assert(smtp.lastErrorCode == 0);
-    }
-}
-
-#ifndef NDEBUG
-# define NDEBUG
-#endif
-
-#include "command.cpp"
-#include "response.cpp"
-#include "transactionstate.cpp"
diff --git a/kioslave/src/smtp/tests/test_headergeneration.cpp b/kioslave/src/smtp/tests/test_headergeneration.cpp
deleted file mode 100644
index a056b18..0000000
--- a/kioslave/src/smtp/tests/test_headergeneration.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-#include "../request.h"
-
-#include <iostream>
-
-//using std::cout;
-//using std::endl;
-
-int main(int, char **)
-{
-    static QByteArray expected
-        = "From: mutz at kde.org\r\n"
-          "Subject: missing subject\r\n"
-          "To: joe at user.org,\r\n"
-          "\tvalentine at 14th.february.org\r\n"
-          "Cc: boss at example.com\r\n"
-          "\n"
-          "From: Marc Mutz <mutz at kde.org>\r\n"
-          "Subject: missing subject\r\n"
-          "To: joe at user.org,\r\n"
-          "\tvalentine at 14th.february.org\r\n"
-          "Cc: boss at example.com\r\n"
-          "\n"
-          "From: \"Mutz, Marc\" <mutz at kde.org>\r\n"
-          "Subject: missing subject\r\n"
-          "To: joe at user.org,\r\n"
-          "\tvalentine at 14th.february.org\r\n"
-          "Cc: boss at example.com\r\n"
-          "\n"
-          "From: =?utf-8?b?TWFyYyBNw7Z0eg==?= <mutz at kde.org>\r\n"
-          "Subject: missing subject\r\n"
-          "To: joe at user.org,\r\n"
-          "\tvalentine at 14th.february.org\r\n"
-          "Cc: boss at example.com\r\n"
-          "\n"
-          "From: mutz at kde.org\r\n"
-          "Subject: =?utf-8?b?QmzDtmRlcyBTdWJqZWN0?=\r\n"
-          "To: joe at user.org,\r\n"
-          "\tvalentine at 14th.february.org\r\n"
-          "Cc: boss at example.com\r\n"
-          "\n"
-          "From: Marc Mutz <mutz at kde.org>\r\n"
-          "Subject: =?utf-8?b?QmzDtmRlcyBTdWJqZWN0?=\r\n"
-          "To: joe at user.org,\r\n"
-          "\tvalentine at 14th.february.org\r\n"
-          "Cc: boss at example.com\r\n"
-          "\n"
-          "From: \"Mutz, Marc\" <mutz at kde.org>\r\n"
-          "Subject: =?utf-8?b?QmzDtmRlcyBTdWJqZWN0?=\r\n"
-          "To: joe at user.org,\r\n"
-          "\tvalentine at 14th.february.org\r\n"
-          "Cc: boss at example.com\r\n"
-          "\n"
-          "From: =?utf-8?b?TWFyYyBNw7Z0eg==?= <mutz at kde.org>\r\n"
-          "Subject: =?utf-8?b?QmzDtmRlcyBTdWJqZWN0?=\r\n"
-          "To: joe at user.org,\r\n"
-          "\tvalentine at 14th.february.org\r\n"
-          "Cc: boss at example.com\r\n"
-          "\n";
-
-    KioSMTP::Request request;
-    QByteArray result;
-
-    request.setEmitHeaders(true);
-    request.setFromAddress(QStringLiteral("mutz at kde.org"));
-    request.addTo(QStringLiteral("joe at user.org"));
-    request.addTo(QStringLiteral("valentine at 14th.february.org"));
-    request.addCc(QStringLiteral("boss at example.com"));
-
-    result += request.headerFields() + '\n';
-    result += request.headerFields(QStringLiteral("Marc Mutz")) + '\n';
-    result += request.headerFields(QStringLiteral("Mutz, Marc")) + '\n';
-    result += request.headerFields(QString::fromUtf8("Marc Mötz")) + '\n';
-
-    request.setSubject(QString::fromUtf8("Blödes Subject"));
-
-    result += request.headerFields() + '\n';
-    result += request.headerFields(QStringLiteral("Marc Mutz")) + '\n';
-    result += request.headerFields(QStringLiteral("Mutz, Marc")) + '\n';
-    result += request.headerFields(QString::fromUtf8("Marc Mötz")) + '\n';
-
-    if (result != expected) {
-        std::cout << "Result:\n" << result.data() << std::endl;
-        std::cout << "Expected:\n" << expected.data() << std::endl;
-    }
-
-    return result == expected ? 0 : 1;
-}
-
-#include "../request.cpp"
diff --git a/kioslave/src/smtp/tests/test_responseparser.cpp b/kioslave/src/smtp/tests/test_responseparser.cpp
deleted file mode 100644
index 18c016b..0000000
--- a/kioslave/src/smtp/tests/test_responseparser.cpp
+++ /dev/null
@@ -1,106 +0,0 @@
-#include "test_responseparser.h"
-#include "../response.h"
-
-#include <qtest.h>
-#include <assert.h>
-
-QTEST_GUILESS_MAIN(ResponseParserTest)
-
-static const QByteArray singleLineResponseCRLF = "250 OK\r\n";
-static const QByteArray singleLineResponse = "250 OK";
-
-static const QByteArray multiLineResponse[] = {
-    "250-ktown.kde.org\r\n",
-    "250-STARTTLS\r\n",
-    "250-AUTH PLAIN DIGEST-MD5\r\n",
-    "250 PIPELINING\r\n"
-};
-static const unsigned int numMultiLineLines = sizeof multiLineResponse / sizeof *multiLineResponse;
-
-void ResponseParserTest::testResponseParser()
-{
-    KioSMTP::Response r;
-    QVERIFY(r.isValid());
-    QVERIFY(r.lines().empty());
-    QVERIFY(r.isWellFormed());
-    QCOMPARE(r.code(), 0u);
-    QVERIFY(r.isUnknown());
-    QVERIFY(!r.isComplete());
-    QVERIFY(!r.isOk());
-    r.parseLine(singleLineResponseCRLF.data(), singleLineResponseCRLF.length());
-    QVERIFY(r.isWellFormed());
-    QVERIFY(r.isComplete());
-    QVERIFY(r.isValid());
-    QVERIFY(r.isPositive());
-    QVERIFY(r.isOk());
-    QCOMPARE(r.code(), 250u);
-    QCOMPARE(r.errorCode(), 0);
-    QCOMPARE(r.first(), 2u);
-    QCOMPARE(r.second(), 5u);
-    QCOMPARE(r.third(), 0u);
-    QCOMPARE(r.lines().count(), 1);
-    QCOMPARE(r.lines().front(), QByteArray("OK"));
-    r.parseLine(singleLineResponse.data(), singleLineResponse.length());
-    QVERIFY(!r.isValid());
-    r.clear();
-    QVERIFY(r.isValid());
-    QVERIFY(r.lines().empty());
-
-    r.parseLine(singleLineResponse.data(), singleLineResponse.length());
-    QVERIFY(r.isWellFormed());
-    QVERIFY(r.isComplete());
-    QVERIFY(r.isValid());
-    QVERIFY(r.isPositive());
-    QVERIFY(r.isOk());
-    QCOMPARE(r.code(), 250u);
-    QCOMPARE(r.first(), 2u);
-    QCOMPARE(r.second(), 5u);
-    QCOMPARE(r.third(), 0u);
-    QCOMPARE(r.lines().count(), 1);
-    QCOMPARE(r.lines().front(), QByteArray("OK"));
-    r.parseLine(singleLineResponse.data(), singleLineResponse.length());
-    QVERIFY(!r.isValid());
-    r.clear();
-    QVERIFY(r.isValid());
-
-    for (unsigned int i = 0; i < numMultiLineLines; ++i) {
-        r.parseLine(multiLineResponse[i].data(), multiLineResponse[i].length());
-        QVERIFY(r.isWellFormed());
-        if (i < numMultiLineLines - 1) {
-            QVERIFY(!r.isComplete());
-        } else {
-            QVERIFY(r.isComplete());
-        }
-        QVERIFY(r.isValid());
-        QVERIFY(r.isPositive());
-        QCOMPARE(r.code(), 250u);
-        QCOMPARE(r.first(), 2u);
-        QCOMPARE(r.second(), 5u);
-        QCOMPARE(r.third(), 0u);
-        QCOMPARE(r.lines().count(), (int)i + 1);
-    }
-    QCOMPARE(r.lines().back(), QByteArray("PIPELINING"));
-
-    r.clear();
-    r.parseLine("230", 3);
-    QVERIFY(r.isValid());
-    QVERIFY(r.isWellFormed());   // even though it isn't ;-)
-    QCOMPARE(r.code(), 230u);
-    QCOMPARE(r.lines().count(), 1);
-    QVERIFY(r.lines().front().isNull());
-
-    r.clear();
-    r.parseLine("230\r\n", 5);
-    QVERIFY(r.isValid());
-    QVERIFY(r.isWellFormed());   // even though it isn't ;-)
-    QCOMPARE(r.code(), 230u);
-    QCOMPARE(r.lines().count(), 1);
-    QVERIFY(r.lines().front().isNull());
-
-    r.clear();
-    r.parseLine(" 23 ok", 6);
-    QVERIFY(!r.isValid());
-    QVERIFY(!r.isWellFormed());
-}
-
-#include "../response.cpp"
diff --git a/kioslave/src/smtp/tests/test_responseparser.h b/kioslave/src/smtp/tests/test_responseparser.h
deleted file mode 100644
index b637988..0000000
--- a/kioslave/src/smtp/tests/test_responseparser.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
-    Copyright (c) 2006 Volker Krause <vkrause at 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.
-*/
-
-#ifndef RESPONSEPARSER_TEST_H
-#define RESPONSEPARSER_TEST_H
-
-#include <QObject>
-
-class ResponseParserTest : public QObject
-{
-    Q_OBJECT
-private Q_SLOTS:
-    void testResponseParser();
-};
-
-#endif
diff --git a/kioslave/src/smtp/transactionstate.cpp b/kioslave/src/smtp/transactionstate.cpp
deleted file mode 100644
index 9577988..0000000
--- a/kioslave/src/smtp/transactionstate.cpp
+++ /dev/null
@@ -1,124 +0,0 @@
-/*  -*- c++ -*-
-    transactionstate.cc
-
-    This file is part of kio_smtp, the KDE SMTP kioslave.
-    Copyright (c) 2003 Marc Mutz <mutz at kde.org>
-
-    This program is free software; you can redistribute it and/or modify it
-    under the terms of the GNU General Public License, version 2, as
-    published by the Free Software Foundation.
-
-    This program 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
-    General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-    In addition, as a special exception, the copyright holders give
-    permission to link the code of this program with any edition of
-    the Qt library by Trolltech AS, Norway (or with modified versions
-    of Qt that use the same license as Qt), and distribute linked
-    combinations including the two.  You must obey the GNU General
-    Public License in all respects for all of the code used other than
-    Qt.  If you modify this file, you may extend this exception to
-    your version of the file, but you are not obligated to do so.  If
-    you do not wish to do so, delete this exception statement from
-    your version.
-*/
-
-#include "transactionstate.h"
-
-#include <kio/global.h>
-#include <KLocalizedString>
-
-namespace KioSMTP {
-void TransactionState::setFailedFatally(int code, const QString &msg)
-{
-    mFailed = mFailedFatally = true;
-    mErrorCode = code;
-    mErrorMessage = msg;
-}
-
-void TransactionState::setMailFromFailed(const QString &addr, const Response &r)
-{
-    setFailed();
-    mErrorCode = KIO::ERR_NO_CONTENT;
-    if (addr.isEmpty()) {
-        mErrorMessage = i18n("The server did not accept a blank sender address.\n"
-                             "%1", r.errorMessage());
-    } else {
-        mErrorMessage = i18n("The server did not accept the sender address \"%1\".\n"
-                             "%2", addr, r.errorMessage());
-    }
-}
-
-void TransactionState::addRejectedRecipient(const RecipientRejection &r)
-{
-    mRejectedRecipients.push_back(r);
-    if (mRcptToDenyIsFailure) {
-        setFailed();
-    }
-}
-
-void TransactionState::setDataCommandSucceeded(bool succeeded, const Response &r)
-{
-    mDataCommandSucceeded = succeeded;
-    mDataResponse = r;
-    if (!succeeded) {
-        setFailed();
-    } else if (failed()) {
-        // can happen with pipelining: the server accepts the DATA, but
-        // we don't want to send the data, so force a connection
-        // shutdown:
-        setFailedFatally();
-    }
-}
-
-int TransactionState::errorCode() const
-{
-    if (!failed()) {
-        return 0;
-    }
-    if (mErrorCode) {
-        return mErrorCode;
-    }
-    if (haveRejectedRecipients() || !dataCommandSucceeded()) {
-        return KIO::ERR_NO_CONTENT;
-    }
-    // ### what else?
-    return KIO::ERR_INTERNAL;
-}
-
-QString TransactionState::errorMessage() const
-{
-    if (!failed()) {
-        return QString();
-    }
-
-    if (!mErrorMessage.isEmpty()) {
-        return mErrorMessage;
-    }
-
-    if (haveRejectedRecipients()) {
-        QStringList recip;
-        recip.reserve(mRejectedRecipients.count());
-        for (RejectedRecipientList::const_iterator it = mRejectedRecipients.begin(), end(mRejectedRecipients.end());
-             it != end; ++it) {
-            recip.push_back((*it).recipient + QLatin1String(" (") + (*it).reason + QLatin1Char(')'));
-        }
-        return i18n("Message sending failed since the following recipients were rejected by the server:\n"
-                    "%1", recip.join(QLatin1Char('\n')));
-    }
-
-    if (!dataCommandSucceeded()) {
-        return i18n("The attempt to start sending the message content failed.\n"
-                    "%1", mDataResponse.errorMessage());
-    }
-
-    // ### what else?
-    return i18n("Unhandled error condition. Please send a bug report.");
-}
-}
diff --git a/kioslave/src/smtp/transactionstate.h b/kioslave/src/smtp/transactionstate.h
deleted file mode 100644
index 43fda12..0000000
--- a/kioslave/src/smtp/transactionstate.h
+++ /dev/null
@@ -1,237 +0,0 @@
-/*  -*- c++ -*-
-    transactionstate.h
-
-    This file is part of kio_smtp, the KDE SMTP kioslave.
-    Copyright (c) 2003 Marc Mutz <mutz at kde.org>
-
-    This program is free software; you can redistribute it and/or modify it
-    under the terms of the GNU General Public License, version 2, as
-    published by the Free Software Foundation.
-
-    This program 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
-    General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-    In addition, as a special exception, the copyright holders give
-    permission to link the code of this program with any edition of
-    the Qt library by Trolltech AS, Norway (or with modified versions
-    of Qt that use the same license as Qt), and distribute linked
-    combinations including the two.  You must obey the GNU General
-    Public License in all respects for all of the code used other than
-    Qt.  If you modify this file, you may extend this exception to
-    your version of the file, but you are not obligated to do so.  If
-    you do not wish to do so, delete this exception statement from
-    your version.
-*/
-
-#ifndef __KIOSMTP_TRANSACTIONSTATE_H__
-#define __KIOSMTP_TRANSACTIONSTATE_H__
-
-#include "response.h"
-
-#include <QString>
-
-namespace KioSMTP {
-/**
-   @short A class modelling an SMTP transaction's state
-
-   This class models SMTP transaction state, ie. the collective
-   result of the MAIL FROM:, RCPT TO: and DATA commands. This is
-   needed since e.g. a single failed RCPT TO: command does not
-   necessarily fail the whole transaction (servers are free to
-   accept delivery for some recipients, but not for others).
-
-   The class can operate in two modes, which differ in the way
-   failed recipients are handled. If @p rcptToDenyIsFailure is true
-   (the default), then any failing RCPT TO: will cause the
-   transaction to fail. Since at the point of RCPT TO: failure
-   detection, the DATA command may have already been sent
-   (pipelining), the only way to cancel the transaction is to take
-   down the connection hard (ie. without proper quit).
-
-   Since that is not very nice behaviour, a second mode that is more
-   to the spirit of SMTP is provided that can cope with partially
-   failed RCPT TO: commands.
-*/
-class TransactionState
-{
-public:
-    struct RecipientRejection {
-        RecipientRejection(const QString &who = QString(), const QString &why = QString())
-            : recipient(who)
-            , reason(why)
-        {
-        }
-
-        QString recipient;
-        QString reason;
-#ifdef KIOSMTP_COMPARATORS
-        bool operator==(const RecipientRejection &other) const
-        {
-            return recipient == other.recipient && reason == other.reason;
-        }
-
-#endif
-    };
-    typedef QList<RecipientRejection> RejectedRecipientList;
-
-    TransactionState(bool rcptToDenyIsFailure = true)
-        : mErrorCode(0)
-        , mRcptToDenyIsFailure(rcptToDenyIsFailure)
-        , mAtLeastOneRecipientWasAccepted(false)
-        , mDataCommandIssued(false)
-        , mDataCommandSucceeded(false)
-        , mFailed(false)
-        , mFailedFatally(false)
-        , mComplete(false)
-    {
-    }
-
-    /**
-     * @return whether the transaction failed (e.g. the server
-     * rejected all recipients. Graceful failure is handled after
-     * transaction ends.
-     */
-    bool failed() const
-    {
-        return mFailed || mFailedFatally;
-    }
-
-    void setFailed()
-    {
-        mFailed = true;
-    }
-
-    /**
-     * @return whether the failure was so grave that an immediate
-     * untidy connection shutdown is in order (ie. @ref
-     * smtp_close(false)). Fatal failure is handled immediately
-     */
-    bool failedFatally() const
-    {
-        return mFailedFatally;
-    }
-
-    void setFailedFatally(int code = 0, const QString &msg = QString());
-
-    /** @return whether the transaction was completed successfully */
-    bool complete() const
-    {
-        return mComplete;
-    }
-
-    void setComplete()
-    {
-        mComplete = true;
-    }
-
-    /**
-     * @return an appropriate KIO error code in case the transaction
-     * failed, or 0 otherwise
-     */
-    int errorCode() const;
-
-    /**
-     * @return an appropriate error message in case the transaction
-     * failed or QString() otherwise
-     */
-    QString errorMessage() const;
-
-    void setMailFromFailed(const QString &addr, const Response &r);
-
-    bool dataCommandIssued() const
-    {
-        return mDataCommandIssued;
-    }
-
-    void setDataCommandIssued(bool issued)
-    {
-        mDataCommandIssued = issued;
-    }
-
-    bool dataCommandSucceeded() const
-    {
-        return mDataCommandIssued && mDataCommandSucceeded;
-    }
-
-    void setDataCommandSucceeded(bool succeeded, const Response &r);
-
-    Response dataResponse() const
-    {
-        return mDataResponse;
-    }
-
-    bool atLeastOneRecipientWasAccepted() const
-    {
-        return mAtLeastOneRecipientWasAccepted;
-    }
-
-    void setRecipientAccepted()
-    {
-        mAtLeastOneRecipientWasAccepted = true;
-    }
-
-    bool haveRejectedRecipients() const
-    {
-        return !mRejectedRecipients.empty();
-    }
-
-    RejectedRecipientList rejectedRecipients() const
-    {
-        return mRejectedRecipients;
-    }
-
-    void addRejectedRecipient(const RecipientRejection &r);
-    void addRejectedRecipient(const QString &who, const QString &why)
-    {
-        addRejectedRecipient(RecipientRejection(who, why));
-    }
-
-    void clear()
-    {
-        mRejectedRecipients.clear();
-        mDataResponse.clear();
-        mAtLeastOneRecipientWasAccepted
-            = mDataCommandIssued
-                  = mDataCommandSucceeded
-                        = mFailed = mFailedFatally
-                                        = mComplete = false;
-    }
-
-#ifdef KIOSMTP_COMPARATORS
-    bool operator==(const TransactionState &other) const
-    {
-        return
-            mAtLeastOneRecipientWasAccepted == other.mAtLeastOneRecipientWasAccepted
-            && mDataCommandIssued == other.mDataCommandIssued
-            && mDataCommandSucceeded == other.mDataCommandSucceeded
-            && mFailed == other.mFailed
-            && mFailedFatally == other.mFailedFatally
-            && mComplete == other.mComplete
-            && mDataResponse.code() == other.mDataResponse.code()
-            && mRejectedRecipients == other.mRejectedRecipients;
-    }
-
-#endif
-
-private:
-    RejectedRecipientList mRejectedRecipients;
-    Response mDataResponse;
-    QString mErrorMessage;
-    int mErrorCode;
-    bool mRcptToDenyIsFailure;
-    bool mAtLeastOneRecipientWasAccepted;
-    bool mDataCommandIssued;
-    bool mDataCommandSucceeded;
-    bool mFailed;
-    bool mFailedFatally;
-    bool mComplete;
-};
-} // namespace KioSMTP
-
-#endif // __KIOSMTP_TRANSACTIONSTATE_H__
diff --git a/src/kmailtransport/plugins/smtp/CMakeLists.txt b/src/kmailtransport/plugins/smtp/CMakeLists.txt
index bae5343..f378daa 100644
--- a/src/kmailtransport/plugins/smtp/CMakeLists.txt
+++ b/src/kmailtransport/plugins/smtp/CMakeLists.txt
@@ -1,3 +1,7 @@
+if (BUILD_TESTING)
+    add_subdirectory(autotests)
+endif()
+
 set(mailtransport_smtpplugin_SRCS
     smtpmailtransportplugin.cpp
     smtpconfigdialog.cpp
@@ -18,6 +22,7 @@ target_link_libraries(mailtransport_smtpplugin
     KF5::MailTransport
     KF5::I18n
     KF5::ConfigWidgets
-    KF5::KIOCore
+    KF5::KIOWidgets
     KF5::Completion
+    KPim::SMTP
     )
diff --git a/src/kmailtransport/plugins/smtp/autotests/CMakeLists.txt b/src/kmailtransport/plugins/smtp/autotests/CMakeLists.txt
new file mode 100644
index 0000000..f85ae2a
--- /dev/null
+++ b/src/kmailtransport/plugins/smtp/autotests/CMakeLists.txt
@@ -0,0 +1,19 @@
+include(ECMAddTests)
+
+find_package(Qt5Test ${QT_REQUIRED_VERSION} REQUIRED)
+
+include_directories(${CMAKE_CURRENT_BINARY_DIR}/..)
+
+ecm_add_test(smtpjobtest.cpp
+             ../smtpjob.cpp
+             ${CMAKE_CURRENT_BINARY_DIR}/../mailtransportplugin_smtp_debug.cpp
+             fakeserver.cpp
+    LINK_LIBRARIES Qt5::Network
+                   Qt5::Test
+                   KF5::MailTransport
+                   KF5::I18n
+                   KF5::ConfigWidgets
+                   KF5::KIOWidgets
+                   KPim::SMTP
+    TEST_NAME smtpjobtest
+)
diff --git a/src/kmailtransport/plugins/smtp/autotests/fakeserver.cpp b/src/kmailtransport/plugins/smtp/autotests/fakeserver.cpp
new file mode 100644
index 0000000..be692bf
--- /dev/null
+++ b/src/kmailtransport/plugins/smtp/autotests/fakeserver.cpp
@@ -0,0 +1,232 @@
+/*
+  Copyright 2010 BetterInbox <contact at betterinbox.com>
+      Author: Christophe Laveault <christophe at betterinbox.com>
+              Gregory Schlomoff <gregory.schlomoff at gmail.com>
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 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
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "fakeserver.h"
+
+#include <QTest>
+#include <QFile>
+#include <QDebug>
+
+FakeServer::FakeServer(QObject *parent) :
+    QThread(parent),
+    m_tcpServer(nullptr)
+{
+    moveToThread(this);
+}
+
+QByteArray FakeServer::greeting()
+{
+    return "S: 220 localhost ESMTP xx777xx";
+}
+
+QList<QByteArray> FakeServer::greetingAndEhlo(bool multiline)
+{
+    return QList<QByteArray>() << greeting()
+           << "C: EHLO 127.0.0.1"
+           << QByteArray("S: 250") + (multiline ? '-' : ' ') + "Localhost ready to roll";
+}
+
+QList<QByteArray> FakeServer::bye()
+{
+    return { "C: QUIT",
+             "S: 221 So long, and thanks for all the fish",
+             "X: "
+           };
+}
+
+FakeServer::~FakeServer()
+{
+    quit();
+    wait();
+}
+
+void FakeServer::startAndWait()
+{
+    start();
+    // this will block until the event queue starts
+    QMetaObject::invokeMethod(this, "started", Qt::BlockingQueuedConnection);
+}
+
+void FakeServer::dataAvailable()
+{
+    QMutexLocker locker(&m_mutex);
+
+    QTcpSocket *socket = qobject_cast<QTcpSocket *>(sender());
+    Q_ASSERT(socket != nullptr);
+
+    int scenarioNumber = m_clientSockets.indexOf(socket);
+
+    QVERIFY(!m_scenarios[scenarioNumber].isEmpty());
+
+    readClientPart(scenarioNumber);
+    writeServerPart(scenarioNumber);
+}
+
+void FakeServer::newConnection()
+{
+    QMutexLocker locker(&m_mutex);
+
+    m_clientSockets << m_tcpServer->nextPendingConnection();
+    connect(m_clientSockets.last(), SIGNAL(readyRead()), this, SLOT(dataAvailable()));
+    //m_clientParsers << new KIMAP::ImapStreamParser( m_clientSockets.last(), true );
+
+    QVERIFY(m_clientSockets.size() <= m_scenarios.size());
+
+    writeServerPart(m_clientSockets.size() - 1);
+}
+
+void FakeServer::run()
+{
+    m_tcpServer = new QTcpServer();
+    if (!m_tcpServer->listen(QHostAddress(QHostAddress::LocalHost), 5989)) {
+        qFatal("Unable to start the server");
+        return;
+    }
+
+    connect(m_tcpServer, SIGNAL(newConnection()), this, SLOT(newConnection()));
+
+    exec();
+
+    qDeleteAll(m_clientSockets);
+
+    delete m_tcpServer;
+}
+
+void FakeServer::started()
+{
+    // do nothing: this is a dummy slot used by startAndWait()
+}
+
+void FakeServer::setScenario(const QList<QByteArray> &scenario)
+{
+    QMutexLocker locker(&m_mutex);
+
+    m_scenarios.clear();
+    m_scenarios << scenario;
+}
+
+void FakeServer::addScenario(const QList<QByteArray> &scenario)
+{
+    QMutexLocker locker(&m_mutex);
+
+    m_scenarios << scenario;
+}
+
+void FakeServer::addScenarioFromFile(const QString &fileName)
+{
+    QFile file(fileName);
+    file.open(QFile::ReadOnly);
+
+    QList<QByteArray> scenario;
+
+    // When loading from files we never have the authentication phase
+    // force jumping directly to authenticated state.
+    //scenario << preauth();
+
+    while (!file.atEnd()) {
+        scenario << file.readLine().trimmed();
+    }
+
+    file.close();
+
+    addScenario(scenario);
+}
+
+bool FakeServer::isScenarioDone(int scenarioNumber) const
+{
+    QMutexLocker locker(&m_mutex);
+
+    if (scenarioNumber < m_scenarios.size()) {
+        return m_scenarios[scenarioNumber].isEmpty();
+    } else {
+        return true; // Non existent hence empty, right?
+    }
+}
+
+bool FakeServer::isAllScenarioDone() const
+{
+    QMutexLocker locker(&m_mutex);
+
+    for (const auto &scenario : qAsConst(m_scenarios)) {
+        if (!scenario.isEmpty()) {
+            qDebug() << scenario;
+            return false;
+        }
+    }
+
+    return true;
+}
+
+void FakeServer::writeServerPart(int scenarioNumber)
+{
+    QList<QByteArray> scenario = m_scenarios[scenarioNumber];
+    QTcpSocket *clientSocket = m_clientSockets[scenarioNumber];
+
+    while (!scenario.isEmpty()
+            && (scenario.first().startsWith("S: ") || scenario.first().startsWith("W: "))) {
+        QByteArray rule = scenario.takeFirst();
+
+        if (rule.startsWith("S: ")) {
+            QByteArray payload = rule.mid(3);
+            clientSocket->write(payload + "\r\n");
+        } else {
+            int timeout = rule.mid(3).toInt();
+            QTest::qWait(timeout);
+        }
+    }
+
+    if (!scenario.isEmpty() && scenario.first().startsWith('X')) {
+        scenario.takeFirst();
+        clientSocket->close();
+    }
+
+    if (!scenario.isEmpty()) {
+        QVERIFY(scenario.first().startsWith("C: "));
+    }
+
+    m_scenarios[scenarioNumber] = scenario;
+}
+
+void FakeServer::readClientPart(int scenarioNumber)
+{
+    QList<QByteArray> scenario = m_scenarios[scenarioNumber];
+    QTcpSocket *clientSocket = m_clientSockets[scenarioNumber];
+
+    while (!scenario.isEmpty() && scenario.first().startsWith("C: ")) {
+        QByteArray line = clientSocket->readLine();
+        QByteArray received = "C: " + line.trimmed();
+        QByteArray expected = scenario.takeFirst();
+
+        if (expected == "C: SKIP" && !scenario.isEmpty()) {
+            expected = scenario.takeFirst();
+            while (received != expected) {
+                received = "C: " + clientSocket->readLine().trimmed();
+            }
+        }
+
+        QCOMPARE(QString::fromUtf8(received), QString::fromUtf8(expected));
+        QCOMPARE(received, expected);
+    }
+
+    if (!scenario.isEmpty()) {
+        QVERIFY(scenario.first().startsWith("S: "));
+    }
+
+    m_scenarios[scenarioNumber] = scenario;
+}
diff --git a/src/kmailtransport/plugins/smtp/autotests/fakeserver.h b/src/kmailtransport/plugins/smtp/autotests/fakeserver.h
new file mode 100644
index 0000000..6e252d6
--- /dev/null
+++ b/src/kmailtransport/plugins/smtp/autotests/fakeserver.h
@@ -0,0 +1,67 @@
+/*
+  Copyright 2010 BetterInbox <contact at betterinbox.com>
+      Author: Christophe Laveault <christophe at betterinbox.com>
+              Gregory Schlomoff <gregory.schlomoff at gmail.com>
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 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
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef KSMTP_FAKESERVER_H
+#define KSMTP_FAKESERVER_H
+
+#include <QThread>
+#include <QTcpServer>
+#include <QTcpSocket>
+#include <QMutex>
+#include <QStringList>
+
+Q_DECLARE_METATYPE(QList<QByteArray>)
+
+class FakeServer : public QThread
+{
+    Q_OBJECT
+
+public:
+    explicit FakeServer(QObject *parent = nullptr);
+    ~FakeServer() override;
+
+    void startAndWait();
+    void run() override;
+
+    static QByteArray greeting();
+    static QList<QByteArray> greetingAndEhlo(bool multiline = true);
+    static QList<QByteArray> bye();
+
+    void setScenario(const QList<QByteArray> &scenario);
+    void addScenario(const QList<QByteArray> &scenario);
+    void addScenarioFromFile(const QString &fileName);
+    bool isScenarioDone(int scenarioNumber) const;
+    bool isAllScenarioDone() const;
+
+private Q_SLOTS:
+    void newConnection();
+    void dataAvailable();
+    void started();
+
+private:
+    void writeServerPart(int scenarioNumber);
+    void readClientPart(int scenarioNumber);
+
+    QList< QList<QByteArray> > m_scenarios;
+    QTcpServer *m_tcpServer;
+    mutable QMutex m_mutex;
+    QList<QTcpSocket *> m_clientSockets;
+};
+
+#endif // KSMTP_FAKESERVER_H
diff --git a/src/kmailtransport/plugins/smtp/autotests/smtpjobtest.cpp b/src/kmailtransport/plugins/smtp/autotests/smtpjobtest.cpp
new file mode 100644
index 0000000..43dd9d1
--- /dev/null
+++ b/src/kmailtransport/plugins/smtp/autotests/smtpjobtest.cpp
@@ -0,0 +1,132 @@
+/*
+    Copyright (c) 2017 Daniel Vrátil <dvratil at 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 "../smtpjob.h"
+#include "fakeserver.h"
+
+#include "transportbase.h"
+#include "transportmanager.h"
+
+#include <QObject>
+#include <QTest>
+#include <QStandardPaths>
+
+Q_DECLARE_METATYPE(MailTransport::TransportBase::EnumAuthenticationType::type)
+
+class SmtpJobTest : public QObject
+{
+    Q_OBJECT
+
+private Q_SLOTS:
+    void initTestCase()
+    {
+        QStandardPaths::setTestModeEnabled(true);
+    }
+    
+    void smtpJobTest_data()
+    {
+        QTest::addColumn<QList<QByteArray>>("scenario");
+        QTest::addColumn<MailTransport::TransportBase::EnumAuthenticationType::type>("authType");
+        QTest::addColumn<QString>("from");
+        QTest::addColumn<QStringList>("to");
+        QTest::addColumn<QStringList>("cc");
+        QTest::addColumn<QByteArray>("data");
+        QTest::addColumn<bool>("success");
+
+        QList<QByteArray> scenario;
+        scenario << FakeServer::greetingAndEhlo()
+                 << "S: 250 AUTH PLAIN LOGIN"
+                 << "C: AUTH LOGIN"
+                 << "S: 334 VXNlcm5hbWU6"
+                 << "C: bG9naW4=" // "login".toBase64()
+                 << "S: 334 UGFzc3dvcmQ6"
+                 << "C: cGFzc3dvcmQ=" // "password".toBase64()
+                 << "S: 235 Authenticated."
+                 << "C: MAIL FROM:<foo at bar.com>"
+                 << "S: 250 ok"
+                 << "C: RCPT TO:<bar at foo.com>"
+                 << "S: 250 ok"
+                 << "C: RCPT TO:<bar at bar.foo>"
+                 << "S: 250 ok"
+                 << "C: DATA"
+                 << "S: 354 Ok go ahead"
+                 << "C: Hi Bob"
+                 << "C: "
+                 << "C: ."
+                 << "S: 250 Ok transfer done"
+                 << FakeServer::bye();
+        QTest::newRow("simple") << scenario << MailTransport::TransportBase::EnumAuthenticationType::LOGIN
+                                << QStringLiteral("Foo Bar <foo at bar.com>")
+                                << QStringList{}
+                                << QStringList{ QStringLiteral("bar at foo.com"), QStringLiteral("<bar at bar.foo>") }
+                                << QByteArray("Hi Bob")
+                                << true;
+    }
+
+    void smtpJobTest()
+    {
+        QFETCH(QList<QByteArray>, scenario);
+        QFETCH(MailTransport::TransportBase::EnumAuthenticationType::type, authType);
+        QFETCH(QString, from);
+        QFETCH(QStringList, to);
+        QFETCH(QStringList, cc);
+        QFETCH(QByteArray, data);
+        QFETCH(bool, success);
+
+        FakeServer server;
+        server.setScenario(scenario);
+        server.startAndWait();
+
+        auto transport = MailTransport::TransportManager::self()->createTransport();
+        transport->setHost(QStringLiteral("127.0.0.1"));
+        transport->setPort(5989);
+        transport->setRequiresAuthentication(true);
+        transport->setAuthenticationType(authType);
+        transport->setStorePassword(false);
+        transport->setUserName(QStringLiteral("login"));
+        transport->setPassword(QStringLiteral("password"));
+
+        {
+            MailTransport::SmtpJob smtpJob(transport);
+            smtpJob.setSender(from);
+            smtpJob.setTo(to);
+            smtpJob.setCc(cc);
+            smtpJob.setData(data);
+
+            QVERIFY(smtpJob.exec());
+            if (success) {
+                QCOMPARE(smtpJob.error(), 0);
+            } else {
+                QVERIFY(smtpJob.error() > 0);
+            }
+
+            // Make sure the smtpJob goes out-of-scope here and thus the
+            // internal session pool is destroyed
+        }
+        // KSMTP time to stop the session
+        QTest::qWait(10);
+
+        QVERIFY(server.isAllScenarioDone());
+        server.quit();
+    }
+};
+
+QTEST_MAIN(SmtpJobTest)
+
+#include "smtpjobtest.moc"
diff --git a/src/kmailtransport/plugins/smtp/sessionuiproxy.h b/src/kmailtransport/plugins/smtp/sessionuiproxy.h
new file mode 100644
index 0000000..0afe15c
--- /dev/null
+++ b/src/kmailtransport/plugins/smtp/sessionuiproxy.h
@@ -0,0 +1,33 @@
+/*
+  Copyright (c) 2017 Daniel Vrátil <dvratil at kde.org>
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License, version 2, as
+  published by the Free Software Foundation.
+
+  This program 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License along
+  with this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+#ifndef SESSIONUIPROXY_H_
+#define SESSIONUIPROXY_H_
+
+#include <KSMTP/SessionUiProxy>
+#include <kio/sslui.h>
+
+class SmtpSessionUiProxy : public KSmtp::SessionUiProxy
+{
+public:
+    bool ignoreSslError(const KSslErrorUiData &errorData) override
+    {
+        return KIO::SslUi::askIgnoreSslErrors(errorData, KIO::SslUi::RecallAndStoreRules);
+    }
+};
+
+#endif
diff --git a/src/kmailtransport/plugins/smtp/smtpjob.cpp b/src/kmailtransport/plugins/smtp/smtpjob.cpp
index 5f40e53..518cac8 100644
--- a/src/kmailtransport/plugins/smtp/smtpjob.cpp
+++ b/src/kmailtransport/plugins/smtp/smtpjob.cpp
@@ -24,6 +24,7 @@
 #include "transport.h"
 #include "mailtransport_defs.h"
 #include "precommandjob.h"
+#include "sessionuiproxy.h"
 #include "mailtransportplugin_smtp_debug.h"
 
 #include <QBuffer>
@@ -34,36 +35,42 @@
 #include <QUrl>
 #include <QUrlQuery>
 #include "mailtransport_debug.h"
-#include <KIO/Job>
-#include <KIO/Scheduler>
 #include <KPasswordDialog>
 
+#include <KSMTP/Session>
+#include <KSMTP/LoginJob>
+#include <KSMTP/SendJob>
+
 using namespace MailTransport;
 
-class SlavePool
+class SessionPool
 {
 public:
-    SlavePool() : ref(0)
+    SessionPool() : ref(0)
     {
     }
 
     int ref;
-    QHash<int, KIO::Slave *> slaves;
+    QHash<int, KSmtp::Session*> sessions;
 
-    void removeSlave(KIO::Slave *slave, bool disconnect = false)
+    void removeSession(KSmtp::Session *session)
     {
-        qCDebug(MAILTRANSPORT_SMTP_LOG) << "Removing slave" << slave << "from pool";
-        const int slaveKey = slaves.key(slave);
-        if (slaveKey > 0) {
-            slaves.remove(slaveKey);
-            if (disconnect) {
-                KIO::Scheduler::disconnectSlave(slave);
-            }
+        qCDebug(MAILTRANSPORT_SMTP_LOG) << "Removing session" << session << "from the pool";
+        int key = sessions.key(session);
+        if (key > 0) {
+            QObject::connect(session, &KSmtp::Session::stateChanged,
+                            [session](KSmtp::Session::State state) {
+                                if (state == KSmtp::Session::Disconnected) {
+                                    session->deleteLater();
+                                }
+                            });
+            session->quit();
+            sessions.remove(key);
         }
     }
 };
 
-Q_GLOBAL_STATIC(SlavePool, s_slavePool)
+Q_GLOBAL_STATIC(SessionPool, s_sessionPool)
 
 /**
  * Private class that helps to provide binary compatibility between releases.
@@ -77,7 +84,8 @@ public:
     }
 
     SmtpJob *q;
-    KIO::Slave *slave;
+    KSmtp::Session *session;
+    KSmtp::SessionUiProxy::Ptr uiProxy;
     enum State {
         Idle, Precommand, Smtp
     } currentState;
@@ -89,26 +97,23 @@ SmtpJob::SmtpJob(Transport *transport, QObject *parent)
     , d(new SmtpJobPrivate(this))
 {
     d->currentState = SmtpJobPrivate::Idle;
-    d->slave = nullptr;
+    d->session = nullptr;
     d->finished = false;
-    if (!s_slavePool.isDestroyed()) {
-        s_slavePool->ref++;
+    d->uiProxy = KSmtp::SessionUiProxy::Ptr(new SmtpSessionUiProxy);
+    if (!s_sessionPool.isDestroyed()) {
+        s_sessionPool->ref++;
     }
-    KIO::Scheduler::connect(SIGNAL(slaveError(KIO::Slave *,int,QString)), this, SLOT(slaveError(KIO::Slave *,int,QString)));
 }
 
 SmtpJob::~SmtpJob()
 {
-    if (!s_slavePool.isDestroyed()) {
-        s_slavePool->ref--;
-        if (s_slavePool->ref == 0) {
-            qCDebug(MAILTRANSPORT_SMTP_LOG) << "clearing SMTP slave pool" << s_slavePool->slaves.count();
-            foreach (KIO::Slave *slave, s_slavePool->slaves) {
-                if (slave) {
-                    KIO::Scheduler::disconnectSlave(slave);
-                }
+    if (!s_sessionPool.isDestroyed()) {
+        s_sessionPool->ref--;
+        if (s_sessionPool->ref == 0) {
+            qCDebug(MAILTRANSPORT_SMTP_LOG) << "clearing SMTP session pool" << s_sessionPool->sessions.count();
+            while (!s_sessionPool->sessions.isEmpty()) {
+                s_sessionPool->removeSession(*(s_sessionPool->sessions.begin()));
             }
-            s_slavePool->slaves.clear();
         }
     }
     delete d;
@@ -116,12 +121,12 @@ SmtpJob::~SmtpJob()
 
 void SmtpJob::doStart()
 {
-    if (s_slavePool.isDestroyed()) {
+    if (s_sessionPool.isDestroyed()) {
         return;
     }
 
-    if ((!s_slavePool->slaves.isEmpty()
-         && s_slavePool->slaves.contains(transport()->id()))
+    if ((!s_sessionPool->sessions.isEmpty()
+         && s_sessionPool->sessions.contains(transport()->id()))
         || transport()->precommand().isEmpty()) {
         d->currentState = SmtpJobPrivate::Smtp;
         startSmtpJob();
@@ -135,118 +140,161 @@ void SmtpJob::doStart()
 
 void SmtpJob::startSmtpJob()
 {
-    if (s_slavePool.isDestroyed()) {
+    if (s_sessionPool.isDestroyed()) {
         return;
     }
 
-    QUrl destination;
-    destination.setScheme((transport()->encryption() == Transport::EnumEncryption::SSL)
-                          ? SMTPS_PROTOCOL : SMTP_PROTOCOL);
-    destination.setHost(transport()->host().trimmed());
-    destination.setPort(transport()->port());
+    d->session = s_sessionPool->sessions.value(transport()->id());
+    if (!d->session) {
+        d->session = new KSmtp::Session(transport()->host(), transport()->port());
+        d->session->setUiProxy(d->uiProxy);
+        if (transport()->specifyHostname()) {
+            d->session->setCustomHostname(transport()->localHostname());
+        }
+        s_sessionPool->sessions.insert(transport()->id(), d->session);
+    }
 
-    QUrlQuery destinationQuery(destination);
-    destinationQuery.addQueryItem(QStringLiteral("headers"), QStringLiteral("0"));
-    destinationQuery.addQueryItem(QStringLiteral("from"), sender());
+    connect(d->session, &KSmtp::Session::stateChanged,
+            this, &SmtpJob::sessionStateChanged, Qt::UniqueConnection);
+    connect(d->session, &KSmtp::Session::connectionError,
+            this, [this](const QString &err) {
+                setError(KJob::UserDefinedError);
+                setErrorText(err);
+                s_sessionPool->removeSession(d->session);
+                emitResult();
+            });
 
-    for (const QString &str : to()) {
-        destinationQuery.addQueryItem(QStringLiteral("to"), str);
-    }
-    for (const QString &str : cc()) {
-        destinationQuery.addQueryItem(QStringLiteral("cc"), str);
+    if (d->session->state() == KSmtp::Session::Disconnected) {
+        d->session->open();
+    } else {
+        if (d->session->state() != KSmtp::Session::Authenticated) {
+            startLoginJob();
+        }
+
+        startSendJob();
     }
-    for (const QString &str : bcc()) {
-        destinationQuery.addQueryItem(QStringLiteral("bcc"), str);
+}
+
+void SmtpJob::sessionStateChanged(KSmtp::Session::State state)
+{
+    if (state == KSmtp::Session::Ready) {
+        startLoginJob();
+    } else if (state == KSmtp::Session::Authenticated) {
+        startSendJob();
     }
+}
 
-    if (transport()->specifyHostname()) {
-        destinationQuery.addQueryItem(QStringLiteral("hostname"), transport()->localHostname());
+void SmtpJob::startLoginJob()
+{
+    if (!transport()->requiresAuthentication()) {
+        startSendJob();
+        return;
     }
 
-    if (transport()->requiresAuthentication()) {
-        QString user = transport()->userName();
-        QString passwd = transport()->password();
-        if ((user.isEmpty() || passwd.isEmpty())
-            && transport()->authenticationType() != Transport::EnumAuthenticationType::GSSAPI) {
-            QPointer<KPasswordDialog> dlg
-                = new KPasswordDialog(
-                nullptr,
-                KPasswordDialog::ShowUsernameLine
-                |KPasswordDialog::ShowKeepPassword);
-            dlg->setPrompt(i18n("You need to supply a username and a password "
-                                "to use this SMTP server."));
-            dlg->setKeepPassword(transport()->storePassword());
-            dlg->addCommentLine(QString(), transport()->name());
-            dlg->setUsername(user);
-            dlg->setPassword(passwd);
-
-            bool gotIt = false;
-            if (dlg->exec()) {
-                transport()->setUserName(dlg->username());
-                transport()->setPassword(dlg->password());
-                transport()->setStorePassword(dlg->keepPassword());
-                transport()->save();
-                gotIt = true;
-            }
-            delete dlg;
+    auto login = new KSmtp::LoginJob(d->session);
+    auto user = transport()->userName();
+    auto passwd = transport()->password();
+    if ((user.isEmpty() || passwd.isEmpty())
+        && transport()->authenticationType() != Transport::EnumAuthenticationType::GSSAPI) {
+        QPointer<KPasswordDialog> dlg
+            = new KPasswordDialog(
+            nullptr,
+            KPasswordDialog::ShowUsernameLine
+            |KPasswordDialog::ShowKeepPassword);
+        dlg->setPrompt(i18n("You need to supply a username and a password "
+                            "to use this SMTP server."));
+        dlg->setKeepPassword(transport()->storePassword());
+        dlg->addCommentLine(QString(), transport()->name());
+        dlg->setUsername(user);
+        dlg->setPassword(passwd);
+
+        bool gotIt = false;
+        if (dlg->exec()) {
+            transport()->setUserName(dlg->username());
+            transport()->setPassword(dlg->password());
+            transport()->setStorePassword(dlg->keepPassword());
+            transport()->save();
+            gotIt = true;
+        }
+        delete dlg;
 
-            if (!gotIt) {
-                setError(KilledJobError);
-                emitResult();
-                return;
-            }
+        if (!gotIt) {
+            setError(KilledJobError);
+            emitResult();
+            return;
         }
-        destination.setUserName(transport()->userName());
-        destination.setPassword(transport()->password());
     }
 
-    // dotstuffing is now done by the slave (see setting of metadata)
-    if (!data().isEmpty()) {
-        // allow +5% for subsequent LF->CRLF and dotstuffing (an average
-        // over 2G-lines gives an average line length of 42-43):
-        destinationQuery.addQueryItem(QStringLiteral("size"),
-                                      QString::number(qRound(data().length() * 1.05)));
+    login->setUserName(transport()->userName());
+    login->setPassword(transport()->password());
+    switch (transport()->authenticationType()) {
+    case TransportBase::EnumAuthenticationType::PLAIN:
+        login->setPreferedAuthMode(KSmtp::LoginJob::Plain);
+        break;
+    case TransportBase::EnumAuthenticationType::LOGIN:
+        login->setPreferedAuthMode(KSmtp::LoginJob::Login);
+        break;
+    case TransportBase::EnumAuthenticationType::CRAM_MD5:
+        login->setPreferedAuthMode(KSmtp::LoginJob::CramMD5);
+        break;
+    case TransportBase::EnumAuthenticationType::XOAUTH2:
+        login->setPreferedAuthMode(KSmtp::LoginJob::XOAuth);
+        break;
+    case TransportBase::EnumAuthenticationType::DIGEST_MD5:
+        login->setPreferedAuthMode(KSmtp::LoginJob::DigestMD5);
+        break;
+    case TransportBase::EnumAuthenticationType::NTLM:
+        login->setPreferedAuthMode(KSmtp::LoginJob::NTLM);
+        break;
+    case TransportBase::EnumAuthenticationType::GSSAPI:
+        login->setPreferedAuthMode(KSmtp::LoginJob::GSSAPI);
+        break;
+    default:
+        qCWarning(MAILTRANSPORT_SMTP_LOG) << "Unknown authentication mode" << transport()->authenticationTypeString();
+        break;
     }
 
-    destination.setPath(QStringLiteral("/send"));
-    destination.setQuery(destinationQuery);
-
-    d->slave = s_slavePool->slaves.value(transport()->id());
-    if (!d->slave) {
-        KIO::MetaData slaveConfig;
-        slaveConfig.insert(QStringLiteral("tls"),
-                           (transport()->encryption() == Transport::EnumEncryption::TLS)
-                           ? QStringLiteral("on") : QStringLiteral("off"));
-        if (transport()->requiresAuthentication()) {
-            slaveConfig.insert(QStringLiteral("sasl"), transport()->authenticationTypeString());
-        }
-        d->slave = KIO::Scheduler::getConnectedSlave(destination, slaveConfig);
-        qCDebug(MAILTRANSPORT_SMTP_LOG) << "Created new SMTP slave" << d->slave;
-        s_slavePool->slaves.insert(transport()->id(), d->slave);
-    } else {
-        qCDebug(MAILTRANSPORT_SMTP_LOG) << "Re-using existing slave" << d->slave;
-    }
+    switch (transport()->encryption()) {
+    case Transport::EnumEncryption::None:
+        login->setEncryptionMode(KSmtp::LoginJob::Unencrypted);
+        break;
+    case Transport::EnumEncryption::TLS:
+        login->setEncryptionMode(KSmtp::LoginJob::TlsV1);
+        break;
+    case Transport::EnumEncryption::SSL:
+        login->setEncryptionMode(KSmtp::LoginJob::AnySslVersion);
+        break;
+    default:
+        qCWarning(MAILTRANSPORT_SMTP_LOG) << "Unknown encryption mode" << transport()->encryption();
+        break;
 
-    KIO::TransferJob *job = KIO::put(destination, -1, KIO::HideProgressInfo);
-    if (!d->slave || !job) {
-        setError(UserDefinedError);
-        setErrorText(i18n("Unable to create SMTP job."));
-        emitResult();
-        return;
     }
 
-    job->addMetaData(QStringLiteral("lf2crlf+dotstuff"), QStringLiteral("slave"));
-    connect(job, &KIO::TransferJob::dataReq, this, &SmtpJob::dataRequest);
-
-    addSubjob(job);
-    KIO::Scheduler::assignJobToSlave(d->slave, job);
+    connect(login, &KJob::result, this, &SmtpJob::slotResult);
+    addSubjob(login);
+    login->start();
+    qCDebug(MAILTRANSPORT_SMTP_LOG) << "Login started";
+}
 
-    setTotalAmount(KJob::Bytes, data().length());
+void SmtpJob::startSendJob()
+{
+    auto send = new KSmtp::SendJob(d->session);
+    send->setFrom(sender());
+    send->setTo(to());
+    send->setCc(cc());
+    send->setBcc(bcc());
+    send->setData(data());
+
+    connect(send, &KJob::result, this, &SmtpJob::slotResult);
+    addSubjob(send);
+    send->start();
+
+    qCDebug(MAILTRANSPORT_SMTP_LOG) << "Send started";
 }
 
 bool SmtpJob::doKill()
 {
-    if (s_slavePool.isDestroyed()) {
+    if (s_sessionPool.isDestroyed()) {
         return false;
     }
 
@@ -256,10 +304,8 @@ bool SmtpJob::doKill()
     if (d->currentState == SmtpJobPrivate::Precommand) {
         return subjobs().first()->kill();
     } else if (d->currentState == SmtpJobPrivate::Smtp) {
-        KIO::SimpleJob *job = static_cast<KIO::SimpleJob *>(subjobs().first());
         clearSubjobs();
-        KIO::Scheduler::cancelJob(job);
-        s_slavePool->removeSlave(d->slave);
+        s_sessionPool->removeSession(d->session);
         return true;
     }
     return false;
@@ -267,7 +313,7 @@ bool SmtpJob::doKill()
 
 void SmtpJob::slotResult(KJob *job)
 {
-    if (s_slavePool.isDestroyed()) {
+    if (s_sessionPool.isDestroyed()) {
         return;
     }
 
@@ -298,7 +344,7 @@ void SmtpJob::slotResult(KJob *job)
     }
 
     if (errorCode && d->currentState == SmtpJobPrivate::Smtp) {
-        s_slavePool->removeSlave(d->slave, errorCode != KIO::ERR_SLAVE_DIED);
+        s_sessionPool->removeSession(d->session);
         TransportJob::slotResult(job);
         return;
     }
@@ -309,38 +355,7 @@ void SmtpJob::slotResult(KJob *job)
         startSmtpJob();
         return;
     }
-    if (!error()) {
-        emitResult();
-    }
-}
-
-void SmtpJob::dataRequest(KIO::Job *job, QByteArray &data)
-{
-    if (s_slavePool.isDestroyed()) {
-        return;
-    }
-
-    Q_UNUSED(job);
-    Q_ASSERT(job);
-    if (buffer()->atEnd()) {
-        data.clear();
-    } else {
-        Q_ASSERT(buffer()->isOpen());
-        data = buffer()->read(32 * 1024);
-    }
-    setProcessedAmount(KJob::Bytes, buffer()->pos());
-}
-
-void SmtpJob::slaveError(KIO::Slave *slave, int errorCode, const QString &errorMsg)
-{
-    if (s_slavePool.isDestroyed()) {
-        return;
-    }
-
-    s_slavePool->removeSlave(slave, errorCode != KIO::ERR_SLAVE_DIED);
-    if (d->slave == slave && !d->finished) {
-        setError(errorCode);
-        setErrorText(KIO::buildErrorString(errorCode, errorMsg));
+    if (!error() && !hasSubjobs()) {
         emitResult();
     }
 }
diff --git a/src/kmailtransport/plugins/smtp/smtpjob.h b/src/kmailtransport/plugins/smtp/smtpjob.h
index b5fbc42..f0ded90 100644
--- a/src/kmailtransport/plugins/smtp/smtpjob.h
+++ b/src/kmailtransport/plugins/smtp/smtpjob.h
@@ -24,6 +24,7 @@
 #define MAILTRANSPORT_SMTPJOB_H
 
 #include <transportjob.h>
+#include <KSMTP/Session>
 
 namespace KIO {
 class Job;
@@ -65,13 +66,12 @@ protected:
 
 protected Q_SLOTS:
     void slotResult(KJob *job) override;
-    void slaveError(KIO::Slave *slave, int errorCode, const QString &errorMsg);
+    void sessionStateChanged(KSmtp::Session::State state);
 
 private:
     void startSmtpJob();
-
-private Q_SLOTS:
-    void dataRequest(KIO::Job *job, QByteArray &data);
+    void startLoginJob();
+    void startSendJob();
 
 private:
     friend class ::SmtpJobPrivate;


More information about the kde-doc-english mailing list