Git commit 208b28a9dfe5e30eec47773c86d3963434211754 by Nicolas Fella. Committed on 06/08/2022 at 14:41. Pushed by mlaurent into branch 'master'.
Remove kioslave It isn't used by anything, and there aren't really many use cases for it Furthermore it has been broken for over a year due to incorrect metadata and nobody complained M +0 -1 CMakeLists.txt D +0 -5 kioslave/CMakeLists.txt D +0 -3 kioslave/doc/CMakeLists.txt D +0 -5 kioslave/doc/sieve/CMakeLists.txt D +0 -30 kioslave/doc/sieve/index.docbook D +0 -6 kioslave/src/CMakeLists.txt D +0 -6 kioslave/src/autotests/CMakeLists.txt D +0 -68 kioslave/src/autotests/regexptest.cpp D +0 -20 kioslave/src/autotests/regexptest.h D +0 -37 kioslave/src/common.h D +0 -24 kioslave/src/sieve/CMakeLists.txt D +0 -4 kioslave/src/sieve/Messages.sh D +0 -2 kioslave/src/sieve/RFCs D +0 -1314 kioslave/src/sieve/sieve.cpp D +0 -119 kioslave/src/sieve/sieve.h D +0 -22 kioslave/src/sieve/sieve.json https://invent.kde.org/pim/libksieve/commit/208b28a9dfe5e30eec47773c86d3963434211754 diff --git a/CMakeLists.txt b/CMakeLists.txt index 696ab572..03288d29 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -122,7 +122,6 @@ if(BUILD_TESTING) endif() add_subdirectory(src) -add_subdirectory(kioslave) ecm_qt_install_logging_categories( EXPORT LIBKSIEVE FILE libksieve.categories diff --git a/kioslave/CMakeLists.txt b/kioslave/CMakeLists.txt deleted file mode 100644 index 03158f28..00000000 --- a/kioslave/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -# SPDX-FileCopyrightText: 2011-2022 Laurent Montel <[email protected]> -# SPDX-License-Identifier: BSD-3-Clause -add_subdirectory(src) -add_subdirectory(doc) - diff --git a/kioslave/doc/CMakeLists.txt b/kioslave/doc/CMakeLists.txt deleted file mode 100644 index 4328488c..00000000 --- a/kioslave/doc/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-FileCopyrightText: 2011-2022 Laurent Montel <[email protected]> -# SPDX-License-Identifier: BSD-3-Clause -add_subdirectory(sieve) diff --git a/kioslave/doc/sieve/CMakeLists.txt b/kioslave/doc/sieve/CMakeLists.txt deleted file mode 100644 index 12e7a0dc..00000000 --- a/kioslave/doc/sieve/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -# SPDX-FileCopyrightText: 2011-2022 Laurent Montel <[email protected]> -# SPDX-License-Identifier: BSD-3-Clause -########### install files ############### -kdoctools_create_handbook(index.docbook INSTALL_DESTINATION ${KDE_INSTALL_DOCBUNDLEDIR}/en SUBDIR kioslave5/sieve) - diff --git a/kioslave/doc/sieve/index.docbook b/kioslave/doc/sieve/index.docbook deleted file mode 100644 index 976e4a87..00000000 --- a/kioslave/doc/sieve/index.docbook +++ /dev/null @@ -1,30 +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="sieve"> -<title>sieve</title> -<articleinfo> - -<authorgroup> -<author><personname><firstname>Daniel</firstname><surname>Black</surname></personname> -<email>[email protected]</email></author> -<!-- TRANS:ROLES_OF_TRANSLATORS --> -</authorgroup> - -<date>2009-11-05</date> - - -</articleinfo> - -<para>Sieve is a protocol that is used to manage filters for email.</para> - -<para>The filters are stored and run on the email server.</para> - -<para><ulink url="https://www.ietf.org/rfc/rfc5228.txt">IETF -RF5228</ulink> provides more information.</para> - -</article> diff --git a/kioslave/src/CMakeLists.txt b/kioslave/src/CMakeLists.txt deleted file mode 100644 index 0060cce4..00000000 --- a/kioslave/src/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -# SPDX-FileCopyrightText: 2011-2022 Laurent Montel <[email protected]> -# SPDX-License-Identifier: BSD-3-Clause -add_subdirectory(sieve) -if(BUILD_TESTING) - add_subdirectory(autotests) -endif() diff --git a/kioslave/src/autotests/CMakeLists.txt b/kioslave/src/autotests/CMakeLists.txt deleted file mode 100644 index d803881c..00000000 --- a/kioslave/src/autotests/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -# SPDX-FileCopyrightText: 2011-2022 Laurent Montel <[email protected]> -# SPDX-License-Identifier: BSD-3-Clause -if (QT_MAJOR_VERSION STREQUAL "5") - ecm_add_tests( regexptest.cpp NAME_PREFIX "libksieve-" LINK_LIBRARIES Qt${QT_MAJOR_VERSION}::Test) -endif() - diff --git a/kioslave/src/autotests/regexptest.cpp b/kioslave/src/autotests/regexptest.cpp deleted file mode 100644 index e7bfc65f..00000000 --- a/kioslave/src/autotests/regexptest.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - SPDX-FileCopyrightText: 2018-2022 Laurent Montel <[email protected]> - - SPDX-License-Identifier: LGPL-2.0-or-later -*/ - -#include "regexptest.h" -#include <QRegExp> -#include <QRegularExpression> -#include <QTest> -QTEST_GUILESS_MAIN(RegexpTest) - -RegexpTest::RegexpTest(QObject *parent) - : QObject(parent) -{ -} - -void RegexpTest::compareRegexp_data() -{ - QTest::addColumn<QString>("input"); - QTest::addColumn<int>("major"); - QTest::addColumn<int>("minor"); - QTest::addColumn<int>("patch"); - QTest::addColumn<QString>("vendor"); - QTest::addColumn<bool>("valid"); - - QTest::newRow("empty") << QString() << 0 << 0 << 0 << QString() << false; - QTest::newRow("Cyrus timsieved v2.2.12") << QStringLiteral("Cyrus timsieved v2.2.12") << 2 << 2 << 12 << QString() << true; - QTest::newRow("Cyrus timsieved v2.2.12-kolab-nocaps") - << QStringLiteral("Cyrus timsieved v2.2.12-kolab-nocaps") << 2 << 2 << 12 << QStringLiteral("-kolab-nocaps") << true; - QTest::newRow("Cyrus timsieved v5.2.12") << QStringLiteral("Cyrus timsieved v5.2.12") << 5 << 2 << 12 << QString() << true; -} - -void RegexpTest::compareRegexp() -{ - QFETCH(QString, input); - QFETCH(int, major); - QFETCH(int, minor); - QFETCH(int, patch); - QFETCH(QString, vendor); - QFETCH(bool, valid); - - QRegExp regExp(QStringLiteral("Cyrus\\stimsieved\\sv(\\d+)\\.(\\d+)\\.(\\d+)([-\\w]*)"), Qt::CaseInsensitive); - bool ok; - if (regExp.indexIn(input) >= 0) { - QCOMPARE(regExp.cap(1).toInt(), major); - QCOMPARE(regExp.cap(2).toInt(), minor); - QCOMPARE(regExp.cap(3).toInt(), patch); - QCOMPARE(regExp.cap(4), vendor); - ok = true; - } else { - ok = false; - } - QCOMPARE(valid, ok); - - QRegularExpression re(QStringLiteral("Cyrus\\stimsieved\\sv(\\d+)\\.(\\d+)\\.(\\d+)([-\\w]*)"), QRegularExpression::CaseInsensitiveOption); - QRegularExpressionMatch match = re.match(input); - if (match.hasMatch()) { - QCOMPARE(match.captured(1).toInt(), major); - QCOMPARE(match.captured(2).toInt(), minor); - QCOMPARE(match.captured(3).toInt(), patch); - QCOMPARE(match.captured(4), vendor); - ok = true; - } else { - ok = false; - } - QCOMPARE(valid, ok); -} diff --git a/kioslave/src/autotests/regexptest.h b/kioslave/src/autotests/regexptest.h deleted file mode 100644 index e7c5b760..00000000 --- a/kioslave/src/autotests/regexptest.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - SPDX-FileCopyrightText: 2018-2022 Laurent Montel <[email protected]> - - SPDX-License-Identifier: LGPL-2.0-or-later -*/ - -#pragma once - -#include <QObject> - -class RegexpTest : public QObject -{ - Q_OBJECT -public: - explicit RegexpTest(QObject *parent = nullptr); - ~RegexpTest() override = default; -private Q_SLOTS: - void compareRegexp_data(); - void compareRegexp(); -}; diff --git a/kioslave/src/common.h b/kioslave/src/common.h deleted file mode 100644 index 549f0af2..00000000 --- a/kioslave/src/common.h +++ /dev/null @@ -1,37 +0,0 @@ -/* This file is part of the KDE project - SPDX-FileCopyrightText: 2008 Jarosław Staniek <[email protected]> - - SPDX-License-Identifier: LGPL-2.0-or-later -*/ - -#pragma once - -#include <QCoreApplication> -#include <QDir> -#include <QFile> -#include <cstdio> -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(nullptr) != SASL_OK) { - fprintf(stderr, "SASL library initialization failed!\n"); - return false; - } - return true; -} diff --git a/kioslave/src/sieve/CMakeLists.txt b/kioslave/src/sieve/CMakeLists.txt deleted file mode 100644 index 5de45470..00000000 --- a/kioslave/src/sieve/CMakeLists.txt +++ /dev/null @@ -1,24 +0,0 @@ -# SPDX-FileCopyrightText: 2011-2022 Laurent Montel <[email protected]> -# SPDX-License-Identifier: BSD-3-Clause - -add_library(kio_sieve MODULE) -target_sources(kio_sieve PRIVATE sieve.cpp sieve.h) -ecm_qt_declare_logging_category(kio_sieve HEADER sieve_debug.h IDENTIFIER SIEVE_LOG CATEGORY_NAME org.kde.pim.sieve - DESCRIPTION "kioslave (sieve)" - OLD_CATEGORY_NAMES log_sieve - EXPORT LIBKSIEVE - ) - - - -if (WIN32) - set(extra_LIBS ws2_32) -endif() - -target_link_libraries(kio_sieve KF5::KIOCore KF5::I18n Qt${QT_MAJOR_VERSION}::Network KF5::WidgetsAddons Sasl2::Sasl2 ${extra_LIBS}) -set_target_properties(kio_sieve PROPERTIES OUTPUT_NAME "sieve") -if (COMPILE_WITH_UNITY_CMAKE_SUPPORT) - set_target_properties(kio_sieve PROPERTIES UNITY_BUILD ON) -endif() - -install(TARGETS kio_sieve DESTINATION ${KDE_INSTALL_PLUGINDIR}/kf${QT_MAJOR_VERSION}/kio/) diff --git a/kioslave/src/sieve/Messages.sh b/kioslave/src/sieve/Messages.sh deleted file mode 100644 index 01f32cff..00000000 --- a/kioslave/src/sieve/Messages.sh +++ /dev/null @@ -1,4 +0,0 @@ -#! /bin/sh -# SPDX-License-Identifier: CC0-1.0 -# SPDX-FileCopyrightText: none -$XGETTEXT *.cpp -o $podir/kio_sieve.pot diff --git a/kioslave/src/sieve/RFCs b/kioslave/src/sieve/RFCs deleted file mode 100644 index aa71ffbc..00000000 --- a/kioslave/src/sieve/RFCs +++ /dev/null @@ -1,2 +0,0 @@ -3028: Sieve: A Mail Filtering Language -3431: Sieve Extension: Relational Tests diff --git a/kioslave/src/sieve/sieve.cpp b/kioslave/src/sieve/sieve.cpp deleted file mode 100644 index 4e9567b6..00000000 --- a/kioslave/src/sieve/sieve.cpp +++ /dev/null @@ -1,1314 +0,0 @@ -/* - sieve.cpp - - SPDX-FileCopyrightText: 2001 Hamish Rodda <[email protected]> - - SPDX-License-Identifier: GPL-2.0-only -*/ - -/** - * Portions adapted from the SMTP ioslave. - * SPDX-FileCopyrightText: 2000, 2001 Alex Zepeda <[email protected]> - * SPDX-FileCopyrightText: 2001 Michael Häckel <[email protected]> - * - * Policy: the function where the error occurs calls error(). A result of - * false, where it signifies an error, thus doesn't need to call error() itself. - */ - -#include "sieve.h" -#include "../common.h" -#include "sieve_debug.h" - -extern "C" { -#include <sasl/sasl.h> -} - -#include <QRegularExpression> -#include <QSslSocket> -#include <QUrlQuery> - -#include <KLocalizedString> -#include <KMessageBox> -#include <QApplication> -#include <QUrl> -#include <cassert> -#include <sys/stat.h> -namespace -{ -auto returnEndLine() -{ - return Qt::endl; -} -} -#define ksDebug qCDebug(SIEVE_LOG) - -#define SIEVE_DEFAULT_PORT 2000 - -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}}; - -static const unsigned int SIEVE_DEFAULT_RECIEVE_BUFFER = 512; - -// Pseudo plugin class to embed meta data -class KIOPluginForMetaData : public QObject -{ - Q_OBJECT - Q_PLUGIN_METADATA(IID "org.kde.kio.slave.sieve" FILE "sieve.json") -}; - -using namespace KIO; -extern "C" { -Q_DECL_EXPORT int kdemain(int argc, char **argv) -{ - QApplication app(argc, argv); - app.setApplicationName(QStringLiteral("kio_sieve")); - - ksDebug << "*** Starting kio_sieve " << returnEndLine(); - - if (argc != 4) { - ksDebug << "Usage: kio_sieve protocol domain-socket1 domain-socket2" << returnEndLine(); - return -1; - } - - if (!initSASL()) { - ::exit(-1); - } - - kio_sieveProtocol slave(argv[2], argv[3]); - slave.dispatchLoop(); - - sasl_done(); - - ksDebug << "*** kio_sieve Done" << returnEndLine(); - return 0; -} -} - -/* ---------------------------------------------------------------------------------- */ -kio_sieveResponse::kio_sieveResponse() -{ - clear(); -} - -/* ---------------------------------------------------------------------------------- */ -const uint &kio_sieveResponse::getType() const -{ - return rType; -} - -/* ---------------------------------------------------------------------------------- */ -uint kio_sieveResponse::getQuantity() const -{ - return quantity; -} - -/* ---------------------------------------------------------------------------------- */ -const QByteArray &kio_sieveResponse::getAction() const -{ - return key; -} - -/* ---------------------------------------------------------------------------------- */ -const QByteArray &kio_sieveResponse::getKey() const -{ - return key; -} - -/* ---------------------------------------------------------------------------------- */ -const QByteArray &kio_sieveResponse::getVal() const -{ - return val; -} - -/* ---------------------------------------------------------------------------------- */ -const QByteArray &kio_sieveResponse::getExtra() const -{ - return extra; -} - -/* ---------------------------------------------------------------------------------- */ -void kio_sieveResponse::setQuantity(uint newQty) -{ - rType = QUANTITY; - quantity = newQty; -} - -/* ---------------------------------------------------------------------------------- */ -void kio_sieveResponse::setAction(const QByteArray &newAction) -{ - rType = ACTION; - key = newAction; -} - -/* ---------------------------------------------------------------------------------- */ -void kio_sieveResponse::setKey(const QByteArray &newKey) -{ - rType = KEY_VAL_PAIR; - key = newKey; -} - -/* ---------------------------------------------------------------------------------- */ -void kio_sieveResponse::setVal(const QByteArray &newVal) -{ - val = newVal; -} - -/* ---------------------------------------------------------------------------------- */ -void kio_sieveResponse::setExtra(const QByteArray &newExtra) -{ - extra = newExtra; -} - -/* ---------------------------------------------------------------------------------- */ -void kio_sieveResponse::clear() -{ - rType = NONE; - extra = key = val = QByteArray(); - quantity = 0; -} - -/* ---------------------------------------------------------------------------------- */ -kio_sieveProtocol::kio_sieveProtocol(const QByteArray &pool_socket, const QByteArray &app_socket) - : TCPSlaveBase("sieve", pool_socket, app_socket, false) - , m_connMode(NORMAL) - , m_supportsTLS(false) - , m_shouldBeConnected(false) - , m_allowUnencrypted(false) - , m_port(SIEVE_DEFAULT_PORT) -{ -} - -/* ---------------------------------------------------------------------------------- */ -kio_sieveProtocol::~kio_sieveProtocol() -{ - if (isConnected()) { - disconnect(); - } -} - -/* ---------------------------------------------------------------------------------- */ -void kio_sieveProtocol::setHost(const QString &host, quint16 port, const QString &user, const QString &pass) -{ - if (isConnected() && (m_sServer != host || m_port != port || m_sUser != user || m_sPass != pass)) { - disconnect(); - } - m_sServer = host; - m_port = port ? port : SIEVE_DEFAULT_PORT; - m_sUser = user; - m_sPass = pass; - m_supportsTLS = false; -} - -/* ---------------------------------------------------------------------------------- */ -void kio_sieveProtocol::openConnection() -{ - m_connMode = CONNECTION_ORIENTED; - connect(); -} - -bool kio_sieveProtocol::parseCapabilities(bool requestCapabilities /* = false*/) -{ - ksDebug << returnEndLine(); - - // Setup... - bool ret = false; - - if (requestCapabilities) { - sendData("CAPABILITY"); - } - - while (receiveData()) { - ksDebug << "Looping receive" << returnEndLine(); - - if (r.getType() == kio_sieveResponse::ACTION) { - if (r.getAction().toLower().contains("ok")) { - ksDebug << "Sieve server ready & awaiting authentication." << returnEndLine(); - break; - } else { - ksDebug << "Unknown action " << r.getAction() << "." << returnEndLine(); - } - } else if (r.getKey() == "IMPLEMENTATION") { - ksDebug << "Connected to Sieve server: " << r.getVal() << returnEndLine(); - ret = true; - setMetaData(QStringLiteral("implementation"), QLatin1String(r.getVal())); - m_implementation = QLatin1String(r.getVal()); - } else if (r.getKey() == "SASL") { - // Save list of available SASL methods - const QString val = QLatin1String(r.getVal()); - m_sasl_caps = val.split(QLatin1Char(' ')); - ksDebug << "Server SASL authentication methods: " << m_sasl_caps.join(QLatin1String(", ")) << returnEndLine(); - setMetaData(QStringLiteral("saslMethods"), QLatin1String(r.getVal())); - } else if (r.getKey() == "SIEVE") { - // Save script capabilities; report back as meta data: - const QString val = QLatin1String(r.getVal()); - ksDebug << "Server script capabilities: " << val.split(QLatin1Char(' ')).join(QLatin1String(", ")) << returnEndLine(); - setMetaData(QStringLiteral("sieveExtensions"), QLatin1String(r.getVal())); - } else if (r.getKey() == "STARTTLS") { - // The server supports TLS - ksDebug << "Server supports TLS" << returnEndLine(); - m_supportsTLS = true; - setMetaData(QStringLiteral("tlsSupported"), QStringLiteral("true")); - } else { - ksDebug << "Unrecognised key " << r.getKey() << returnEndLine(); - } - } - - if (!m_supportsTLS) { - setMetaData(QStringLiteral("tlsSupported"), QStringLiteral("false")); - } - - return ret; -} - -/* ---------------------------------------------------------------------------------- */ -/** - * Checks if connection parameters have changed. - * If it it, close the current connection - */ -void kio_sieveProtocol::changeCheck(const QUrl &url) -{ - QString auth; - - // Check the SASL auth mechanism in the 'sasl' metadata... - if (!metaData(QStringLiteral("sasl")).isEmpty()) { - auth = metaData(QStringLiteral("sasl")).toUpper(); - } else { - // ... and if not found, check the x-mech=AUTH query part of the url. - QString query = url.query(); - if (query.startsWith(QLatin1Char('?'))) { - query.remove(0, 1); - } - QStringList q = query.split(QLatin1Char(',')); - - for (QStringList::iterator it = q.begin(), end(q.end()); it != end; ++it) { - if (((*it).section(QLatin1Char('='), 0, 0)).toLower() == QLatin1String("x-mech")) { - auth = ((*it).section(QLatin1Char('='), 1)).toUpper(); - break; - } - } - } - ksDebug << "auth: " << auth << " m_sAuth: " << m_sAuth << returnEndLine(); - if (m_sAuth != auth) { - m_sAuth = auth; - if (isConnected()) { - disconnect(); - } - } - // For TLS, only disconnect if we are unencrypted and are - // no longer allowed (otherwise, it's still fine): - const bool allowUnencryptedNow = QUrlQuery(url).queryItemValue(QStringLiteral("x-allow-unencrypted")) == QLatin1String("true"); - if (m_allowUnencrypted && !allowUnencryptedNow) { - if (isConnected()) { - disconnect(); - } - } - m_allowUnencrypted = allowUnencryptedNow; -} - -/* ---------------------------------------------------------------------------------- */ -/** - * Connects to the server. - * returns false and calls error() if an error occurred. - */ -bool kio_sieveProtocol::connect(bool useTLSIfAvailable) -{ - ksDebug << returnEndLine(); - - if (isConnected()) { - return true; - } - - infoMessage(i18n("Connecting to %1...", m_sServer)); - - if (m_connMode == CONNECTION_ORIENTED && m_shouldBeConnected) { - error(ERR_CONNECTION_BROKEN, i18n("The connection to the server was lost.")); - return false; - } - - setBlocking(true); - - if (!connectToHost(QStringLiteral("sieve"), m_sServer, m_port)) { - return false; - } - - if (!parseCapabilities()) { - disconnectFromHost(); - error(ERR_UNSUPPORTED_PROTOCOL, i18n("Server identification failed.")); - return false; - } - - // Attempt to start TLS - if (!m_allowUnencrypted && !QSslSocket::supportsSsl()) { - error(KIO::ERR_WORKER_DEFINED, i18n("Can not use TLS since the underlying Qt library does not support it.")); - disconnect(); - return false; - } - - if (!m_allowUnencrypted && useTLSIfAvailable && QSslSocket::supportsSsl() && !m_supportsTLS - && messageBox(WarningContinueCancel, - i18n("TLS encryption was requested, but your Sieve server does not advertise TLS in its capabilities.\n" - "You can choose to try to initiate TLS negotiations nonetheless, or cancel the operation."), - i18n("Server Does Not Advertise TLS"), - i18n("&Start TLS nonetheless"), - i18n("&Cancel")) - != KMessageBox::Continue) { - error(ERR_USER_CANCELED, i18n("TLS encryption requested, but not supported by server.")); - disconnect(); - return false; - } - - // FIXME find a test server and test that this works - if (useTLSIfAvailable && m_supportsTLS && QSslSocket::supportsSsl()) { - sendData("STARTTLS"); - if (operationSuccessful()) { - ksDebug << "TLS has been accepted. Starting TLS..." << returnEndLine() << "WARNING this is untested and may fail."; - if (startSsl()) { - ksDebug << "TLS enabled successfully." << returnEndLine(); - // reparse capabilities: - parseCapabilities(requestCapabilitiesAfterStartTLS()); - } else { - ksDebug << "TLS initiation failed."; - if (m_allowUnencrypted) { - disconnect(true); - return connect(false); - } - messageBox(Information, - i18n("Your Sieve server claims to support TLS, " - "but negotiation was unsuccessful."), - i18n("Connection Failed")); - disconnect(true); - return false; - } - } else if (!m_allowUnencrypted) { - ksDebug << "Server incapable of TLS."; - disconnect(); - error(KIO::ERR_WORKER_DEFINED, - i18n("The server does not seem to support TLS. " - "Disable TLS if you want to connect without encryption.")); - return false; - } else { - ksDebug << "Server incapable of TLS. Transmitted documents will be unencrypted." << returnEndLine(); - } - } else { - ksDebug << "We are incapable of TLS. Transmitted documents will be unencrypted." << returnEndLine(); - } - - assert(m_allowUnencrypted || isUsingSsl()); - - infoMessage(i18n("Authenticating user...")); - if (!authenticate()) { - disconnect(); - error(ERR_CANNOT_AUTHENTICATE, i18n("Authentication failed.")); - return false; - } - - m_shouldBeConnected = true; - return true; -} - -/* ---------------------------------------------------------------------------------- */ -void kio_sieveProtocol::closeConnection() -{ - m_connMode = CONNECTION_ORIENTED; - disconnect(); -} - -/* ---------------------------------------------------------------------------------- */ -void kio_sieveProtocol::disconnect(bool forcibly) -{ - if (!forcibly) { - sendData("LOGOUT"); - - if (!operationSuccessful()) { - ksDebug << "Server did not logout cleanly." << returnEndLine(); - } - } - - disconnectFromHost(); - m_shouldBeConnected = false; -} - -/* ---------------------------------------------------------------------------------- */ -/*void kio_sieveProtocol::slave_status() -{ - slaveStatus(isConnected() ? m_sServer : "", isConnected()); - - finished(); -}*/ - -/* ---------------------------------------------------------------------------------- */ -void kio_sieveProtocol::special(const QByteArray &data) -{ - int tmp; - QDataStream stream(data); - QUrl url; - - stream >> tmp; - - switch (tmp) { - case 1: - stream >> url; - if (!activate(url)) { - return; - } - break; - case 2: - if (!deactivate()) { - return; - } - break; - case 3: - parseCapabilities(true); - break; - } - - infoMessage(i18nc("special command completed", "Done.")); - - finished(); -} - -/* ---------------------------------------------------------------------------------- */ -bool kio_sieveProtocol::activate(const QUrl &url) -{ - changeCheck(url); - if (!connect()) { - return false; - } - - infoMessage(i18n("Activating script...")); - - QString filename = url.fileName(); - - if (filename.isEmpty()) { - error(ERR_DOES_NOT_EXIST, url.toDisplayString()); - return false; - } - - if (!sendData("SETACTIVE \"" + filename.toUtf8() + "\"")) { - return false; - } - - if (operationSuccessful()) { - ksDebug << "Script activation complete." << returnEndLine(); - return true; - } else { - error(ERR_INTERNAL_SERVER, i18n("There was an error activating the script.")); - return false; - } -} - -/* ---------------------------------------------------------------------------------- */ -bool kio_sieveProtocol::deactivate() -{ - if (!connect()) { - return false; - } - - if (!sendData("SETACTIVE \"\"")) { - return false; - } - - if (operationSuccessful()) { - ksDebug << "Script deactivation complete." << returnEndLine(); - return true; - } else { - error(ERR_INTERNAL_SERVER, i18n("There was an error deactivating the script.")); - return false; - } -} - -static void append_lf2crlf(QByteArray &out, const QByteArray &in) -{ - if (in.isEmpty()) { - return; - } - const unsigned int oldOutSize = out.size(); - out.resize(oldOutSize + 2 * in.size()); - const char *s = in.begin(); - const char *const end = in.end(); - char *d = out.begin() + oldOutSize; - char last = '\0'; - while (s < end) { - if (*s == '\n' && last != '\r') { - *d++ = '\r'; - } - *d++ = last = *s++; - } - out.resize(d - out.begin()); -} - -void kio_sieveProtocol::put(const QUrl &url, int /*permissions*/, KIO::JobFlags) -{ - changeCheck(url); - if (!connect()) { - return; - } - - infoMessage(i18n("Sending data...")); - - QString filename = url.fileName(); - - if (filename.isEmpty()) { - error(ERR_MALFORMED_URL, url.toDisplayString()); - return; - } - - QByteArray data; - for (;;) { - dataReq(); - QByteArray buffer; - const int newSize = readData(buffer); - append_lf2crlf(data, buffer); - if (newSize < 0) { - // read error: network in unknown state so disconnect - error(ERR_CANNOT_READ, i18n("KIO data supply error.")); - return; - } - if (newSize == 0) { - break; - } - } - - // script size - int bufLen = (int)data.size(); - totalSize(bufLen); - - // timsieved 1.1.0: - // C: HAVESPACE "rejected" 74 - // S: NO "Number expected" - // C: HAVESPACE 74 - // S: NO "Missing script name" - // S: HAVESPACE "rejected" "74" - // C: NO "Number expected" - // => broken, we can't use it :-( - // (will be fixed in Cyrus 2.1.10) - - if (!sendData("PUTSCRIPT \"" + filename.toUtf8() + "\" {" + QByteArray::number(bufLen) + "+}")) { - return; - } - - // atEnd() lies so the code below doesn't work. - /*if (!atEnd()) { - // We are not expecting any data here, so if the server has responded - // with anything but OK we treat it as an error. - char * buf = new char[2]; - while (!atEnd()) { - ksDebug << "Reading..." << returnEndLine(); - read(buf, 1); - ksDebug << "Trailing [" << buf[0] << "]" << returnEndLine(); - } - ksDebug << "End of data." << returnEndLine(); - delete[] buf; - - if (!operationSuccessful()) { - error(ERR_UNSUPPORTED_PROTOCOL, i18n("A protocol error occurred " - "while trying to negotiate script uploading.\n" - "The server responded:\n%1") - .arg(r.getAction().right(r.getAction().length() - 3))); - return; - } - }*/ - - // upload data to the server - if (write(data.constData(), bufLen) != bufLen) { - error(ERR_CANNOT_WRITE, i18n("Network error.")); - disconnect(true); - return; - } - - // finishing CR/LF - if (!sendData("")) { - return; - } - - processedSize(bufLen); - - infoMessage(i18n("Verifying upload completion...")); - - if (operationSuccessful()) { - ksDebug << "Script upload complete." << returnEndLine(); - } else { - /* The managesieve server parses received scripts and rejects - * scripts which are not syntactically correct. Here we expect - * to receive a message detailing the error (only the first - * error is reported. */ - if (r.getAction().length() > 3) { - // make a copy of the extra info - QByteArray extra = r.getAction().right(r.getAction().length() - 3); - - // send the extra message off for re-processing - receiveData(false, extra); - - if (r.getType() == kio_sieveResponse::QUANTITY) { - // length of the error message - uint len = r.getQuantity(); - - QByteArray errmsg(len, 0); - - read(errmsg.data(), len); - - error(ERR_INTERNAL_SERVER, - i18n("The script did not upload successfully.\n" - "This is probably due to errors in the script.\n" - "The server responded:\n%1", - QString::fromLatin1(errmsg.data(), errmsg.size()))); - - // clear the rest of the incoming data - receiveData(); - } else if (r.getType() == kio_sieveResponse::KEY_VAL_PAIR) { - error(ERR_INTERNAL_SERVER, - i18n("The script did not upload successfully.\n" - "This is probably due to errors in the script.\n" - "The server responded:\n%1", - QString::fromUtf8(r.getKey()))); - } else { - error(ERR_INTERNAL_SERVER, - i18n("The script did not upload successfully.\n" - "The script may contain errors.")); - } - } else { - error(ERR_INTERNAL_SERVER, - i18n("The script did not upload successfully.\n" - "The script may contain errors.")); - } - } - - // if ( permissions != -1 ) - // chmod( url, permissions ); - - infoMessage(i18nc("data upload complete", "Done.")); - - finished(); -} - -static void inplace_crlf2lf(QByteArray &in) -{ - if (in.isEmpty()) { - return; - } - QByteArray &out = in; // inplace - const char *s = in.begin(); - const char *const end = in.end(); - char *d = out.begin(); - char last = '\0'; - while (s < end) { - if (*s == '\n' && last == '\r') { - --d; - } - *d++ = last = *s++; - } - out.resize(d - out.begin()); -} - -/* ---------------------------------------------------------------------------------- */ -void kio_sieveProtocol::get(const QUrl &url) -{ - changeCheck(url); - if (!connect()) { - return; - } - - infoMessage(i18n("Retrieving data...")); - - QString filename = url.fileName(); - - if (filename.isEmpty()) { - error(ERR_MALFORMED_URL, url.toDisplayString()); - return; - } - - // SlaveBase::mimetype( QString("text/plain") ); // "application/sieve"); - - if (!sendData("GETSCRIPT \"" + filename.toUtf8() + "\"")) { - return; - } - - if (receiveData() && r.getType() == kio_sieveResponse::QUANTITY) { - // determine script size - ssize_t total_len = r.getQuantity(); - totalSize(total_len); - - ssize_t recv_len = 0; - do { - // wait for data... - if (!waitForResponse(600)) { - error(KIO::ERR_SERVER_TIMEOUT, m_sServer); - disconnect(true); - return; - } - - // ...read data... - // Only read as much as we need, otherwise we slurp in the OK that - // operationSuccessful() is expecting below. - QByteArray dat(qMin(total_len - recv_len, ssize_t(64 * 1024)), '\0'); - ssize_t this_recv_len = read(dat.data(), dat.size()); - - if (this_recv_len < 1 && !isConnected()) { - error(KIO::ERR_CONNECTION_BROKEN, m_sServer); - disconnect(true); - return; - } - - dat.resize(this_recv_len); - inplace_crlf2lf(dat); - // send data to slaveinterface - data(dat); - - recv_len += this_recv_len; - processedSize(recv_len); - } while (recv_len < total_len); - - infoMessage(i18n("Finishing up...")); - data(QByteArray()); - - if (operationSuccessful()) { - ksDebug << "Script retrieval complete." << returnEndLine(); - } else { - ksDebug << "Script retrieval failed." << returnEndLine(); - } - } else { - error(ERR_UNSUPPORTED_PROTOCOL, - i18n("A protocol error occurred " - "while trying to negotiate script downloading.")); - return; - } - - infoMessage(i18nc("data retrieval complete", "Done.")); - finished(); -} - -void kio_sieveProtocol::del(const QUrl &url, bool isfile) -{ - if (!isfile) { - error(ERR_INTERNAL, i18n("Folders are not supported.")); - return; - } - - changeCheck(url); - if (!connect()) { - return; - } - - infoMessage(i18n("Deleting file...")); - - QString filename = url.fileName(); - - if (filename.isEmpty()) { - error(ERR_MALFORMED_URL, url.toDisplayString()); - return; - } - - if (!sendData("DELETESCRIPT \"" + filename.toUtf8() + "\"")) { - return; - } - - if (operationSuccessful()) { - ksDebug << "Script deletion successful." << returnEndLine(); - } else { - error(ERR_INTERNAL_SERVER, i18n("The server would not delete the file.")); - return; - } - - infoMessage(i18nc("file removal complete", "Done.")); - - finished(); -} - -void kio_sieveProtocol::chmod(const QUrl &url, int permissions) -{ - switch (permissions) { - case 0700: // activate - activate(url); - break; - case 0600: // deactivate - deactivate(); - break; - default: // unsupported - error(ERR_CANNOT_CHMOD, i18n("Cannot chmod to anything but 0700 (active) or 0600 (inactive script).")); - return; - } - - finished(); -} - -void kio_sieveProtocol::urlStat(const QUrl &url) -{ - changeCheck(url); - if (!connect()) { - return; - } - - UDSEntry entry; - - QString filename = url.fileName(); - - if (filename.isEmpty()) { - entry.fastInsert(KIO::UDSEntry::UDS_NAME, QStringLiteral("/")); - - entry.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR); - - entry.fastInsert(KIO::UDSEntry::UDS_ACCESS, 0700); - - statEntry(entry); - } else { - if (!sendData("LISTSCRIPTS")) { - return; - } - - while (receiveData()) { - if (r.getType() == kio_sieveResponse::ACTION) { - if (r.getAction().toLower().count("ok") == 1) { - // Script list completed - break; - } - } else { - if (filename == QString::fromUtf8(r.getKey())) { - entry.clear(); - - entry.fastInsert(KIO::UDSEntry::UDS_NAME, QString::fromUtf8(r.getKey())); - - entry.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFREG); - - if (r.getExtra() == "ACTIVE") { - entry.fastInsert(KIO::UDSEntry::UDS_ACCESS, 0700); - } else { - entry.fastInsert(KIO::UDSEntry::UDS_ACCESS, 0600); - } - - entry.fastInsert(KIO::UDSEntry::UDS_MIME_TYPE, QStringLiteral("application/sieve")); - - // setMetaData("active", (r.getExtra() == "ACTIVE") ? "yes" : "no"); - - statEntry(entry); - // cannot break here because we need to clear - // the rest of the incoming data. - } - } - } - } - - finished(); -} - -void kio_sieveProtocol::listDir(const QUrl &url) -{ - changeCheck(url); - if (!connect()) { - return; - } - - if (!sendData("LISTSCRIPTS")) { - return; - } - - UDSEntry entry; - - while (receiveData()) { - if (r.getType() == kio_sieveResponse::ACTION) { - if (r.getAction().toLower().count("ok") == 1) { - // Script list completed. - break; - } - } else { - entry.clear(); - entry.fastInsert(KIO::UDSEntry::UDS_NAME, QString::fromUtf8(r.getKey())); - - entry.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFREG); - - if (r.getExtra() == "ACTIVE") { - entry.fastInsert(KIO::UDSEntry::UDS_ACCESS, 0700); // mark exec'able - } else { - entry.fastInsert(KIO::UDSEntry::UDS_ACCESS, 0600); - } - - entry.fastInsert(KIO::UDSEntry::UDS_MIME_TYPE, QStringLiteral("application/sieve")); - - // asetMetaData("active", (r.getExtra() == "ACTIVE") ? "true" : "false"); - - ksDebug << "Listing script " << r.getKey() << returnEndLine(); - listEntry(entry); - } - } - - finished(); -} - -/* ---------------------------------------------------------------------------------- */ -bool kio_sieveProtocol::saslInteract(void *in, AuthInfo &ai) -{ - ksDebug << "sasl_interact" << returnEndLine(); - auto *interact = (sasl_interact_t *)in; - - // some mechanisms do not require username && pass, so it doesn'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 (m_sUser.isEmpty() || m_sPass.isEmpty()) { - const int errorCode = openPasswordDialogV2(ai); - if (errorCode) { - // calling error() below is wrong for two reasons: - // - ERR_ABORTED is too harsh - // - higher layers already call error() and that can't happen twice. - // error(ERR_ABORTED, i18n("No authentication details supplied.")); - error(errorCode, QString()); - return false; - } - m_sUser = ai.username; - m_sPass = ai.password; - } - break; - } - } - - interact = (sasl_interact_t *)in; - while (interact->id != SASL_CB_LIST_END) { - ksDebug << "SASL_INTERACT id: " << interact->id << returnEndLine(); - switch (interact->id) { - case SASL_CB_USER: - case SASL_CB_AUTHNAME: - ksDebug << "SASL_CB_[AUTHNAME|USER]: '" << m_sUser << "'" << returnEndLine(); - interact->result = strdup(m_sUser.toUtf8().constData()); - interact->len = strlen((const char *)interact->result); - break; - case SASL_CB_PASS: - ksDebug << "SASL_CB_PASS: [hidden] " << returnEndLine(); - interact->result = strdup(m_sPass.toUtf8().constData()); - interact->len = strlen((const char *)interact->result); - break; - default: - interact->result = nullptr; - interact->len = 0; - break; - } - interact++; - } - return true; -} - -#define SASLERROR error(ERR_CANNOT_AUTHENTICATE, i18n("An error occurred during authentication: %1", QString::fromUtf8(sasl_errdetail(conn)))); - -bool kio_sieveProtocol::authenticate() -{ - int result; - sasl_conn_t *conn = nullptr; - sasl_interact_t *client_interact = nullptr; - const char *out = nullptr; - uint outlen; - const char *mechusing = nullptr; - QByteArray challenge; - - /* Retrieve authentication details from user. - * Note: should this require realm as well as user & pass details - * before it automatically skips the prompt? - * Note2: encoding issues with PLAIN login? */ - AuthInfo ai; - ai.url.setScheme(QStringLiteral("sieve")); - ai.url.setHost(m_sServer); - ai.url.setPort(m_port); - ai.username = m_sUser; - ai.password = m_sPass; - ai.keepPassword = true; - ai.caption = i18n("Sieve Authentication Details"); - ai.comment = i18n( - "Please enter your authentication details for your sieve account " - "(usually the same as your email password):"); - - result = sasl_client_new("sieve", m_sServer.toLatin1().constData(), nullptr, nullptr, callbacks, 0, &conn); - if (result != SASL_OK) { - ksDebug << "sasl_client_new failed with: " << result << returnEndLine(); - SASLERROR - return false; - } - - QStringList strList; - // strList.append("NTLM"); - - if (!m_sAuth.isEmpty()) { - strList.append(m_sAuth); - } else { - strList = m_sasl_caps; - } - - do { - result = sasl_client_start(conn, strList.join(QLatin1Char(' ')).toLatin1().constData(), &client_interact, &out, &outlen, &mechusing); - - if (result == SASL_INTERACT) { - if (!saslInteract(client_interact, ai)) { - sasl_dispose(&conn); - return false; - } - } - } while (result == SASL_INTERACT); - - if (result != SASL_CONTINUE && result != SASL_OK) { - ksDebug << "sasl_client_start failed with: " << result << returnEndLine(); - SASLERROR - sasl_dispose(&conn); - return false; - } - - ksDebug << "Preferred authentication method is " << mechusing << "." << returnEndLine(); - - QString firstCommand = QLatin1String("AUTHENTICATE \"") + QString::fromLatin1(mechusing) + QLatin1String("\""); - challenge = QByteArray::fromRawData(out, outlen).toBase64(); - if (!challenge.isEmpty()) { - firstCommand += QLatin1String(" \""); - firstCommand += QString::fromLatin1(challenge.data(), challenge.size()); - firstCommand += QLatin1Char('\"'); - } - - if (!sendData(firstCommand.toLatin1())) { - return false; - } - - do { - receiveData(); - - if (operationResult() != OTHER) { - break; - } - - ksDebug << "Challenge len " << r.getQuantity() << returnEndLine(); - - if (r.getType() != kio_sieveResponse::QUANTITY) { - sasl_dispose(&conn); - error(ERR_UNSUPPORTED_PROTOCOL, QString::fromLatin1(mechusing)); - return false; - } - - int qty = r.getQuantity(); - - receiveData(); - - if (r.getType() != kio_sieveResponse::ACTION && r.getAction().length() != qty) { - sasl_dispose(&conn); - error(ERR_UNSUPPORTED_PROTOCOL, - i18n("A protocol error occurred during authentication.\n" - "Choose a different authentication method to %1.", - QLatin1String(mechusing))); - return false; - } - challenge = QByteArray::fromBase64(QByteArray::fromRawData(r.getAction().data(), qty)); - // ksDebug << "S: [" << r.getAction() << "]." << returnEndLine(); - - do { - result = sasl_client_step(conn, challenge.isEmpty() ? nullptr : challenge.data(), challenge.size(), &client_interact, &out, &outlen); - - if (result == SASL_INTERACT) { - if (!saslInteract(client_interact, ai)) { - sasl_dispose(&conn); - return false; - } - } - } while (result == SASL_INTERACT); - - ksDebug << "sasl_client_step: " << result << returnEndLine(); - if (result != SASL_CONTINUE && result != SASL_OK) { - ksDebug << "sasl_client_step failed with: " << result << returnEndLine(); - SASLERROR - sasl_dispose(&conn); - return false; - } - - sendData('\"' + QByteArray::fromRawData(out, outlen).toBase64() + '\"'); - // ksDebug << "C-1: [" << out << "]." << returnEndLine(); - } while (true); - - ksDebug << "Challenges finished." << returnEndLine(); - sasl_dispose(&conn); - - if (operationResult() == OK) { - // Authentication succeeded. - return true; - } else { - // Authentication failed. - error(ERR_CANNOT_AUTHENTICATE, - i18n("Authentication failed.\nMost likely the password is wrong.\nThe server responded:\n%1", QString::fromLatin1(r.getAction()))); - return false; - } -} - -/* --------------------------------------------------------------------------- */ -void kio_sieveProtocol::mimetype(const QUrl &url) -{ - ksDebug << "Requesting mimetype for " << url.toDisplayString() << returnEndLine(); - - if (url.fileName().isEmpty()) { - mimeType(QStringLiteral("inode/directory")); - } else { - mimeType(QStringLiteral("application/sieve")); - } - - finished(); -} - -/* --------------------------------------------------------------------------- */ -bool kio_sieveProtocol::sendData(const QByteArray &data) -{ - QByteArray write_buf = data + "\r\n"; - - // ksDebug << "C: " << data << returnEndLine(); - - // Write the command - ssize_t write_buf_len = write_buf.length(); - if (write(write_buf.data(), write_buf_len) != write_buf_len) { - error(ERR_CANNOT_WRITE, i18n("Network error.")); - disconnect(true); - return false; - } - - return true; -} - -/* --------------------------------------------------------------------------- */ -bool kio_sieveProtocol::receiveData(bool waitForData, const QByteArray &reparse) -{ - QByteArray interpret; - int start; - int end; - - if (reparse.isEmpty()) { - if (!waitForData) { - // is there data waiting? - if (atEnd()) { - return false; - } - } - - // read data from the server - char buffer[SIEVE_DEFAULT_RECIEVE_BUFFER]; - const ssize_t numRead = readLine(buffer, SIEVE_DEFAULT_RECIEVE_BUFFER - 1); - if (numRead < 0) { - return false; - } - buffer[SIEVE_DEFAULT_RECIEVE_BUFFER - 1] = '\0'; - - // strip LF/CR - interpret = QByteArray(buffer, qstrlen(buffer) - 2); - } else { - interpret = reparse; - } - - r.clear(); - - // ksDebug << "S: " << interpret << returnEndLine(); - - switch (interpret[0]) { - case '{': { - // expecting {quantity} - start = 0; - end = interpret.indexOf("+}", start + 1); - // some older versions of Cyrus enclose the literal size just in { } instead of { +} - if (end == -1) { - end = interpret.indexOf('}', start + 1); - } - - bool ok = false; - r.setQuantity(interpret.mid(start + 1, end - start - 1).toUInt(&ok)); - if (!ok) { - disconnect(); - error(ERR_INTERNAL_SERVER, i18n("A protocol error occurred.")); - return false; - } - - return true; - } - case '"': - // expecting "key" "value" pairs - break; - default: - // expecting single string - r.setAction(interpret); - return true; - } - - start = 0; - - end = interpret.indexOf('"', start + 1); - if (end == -1) { - ksDebug << "Possible insufficient buffer size." << returnEndLine(); - r.setKey(interpret.right(interpret.length() - start)); - return true; - } - - r.setKey(interpret.mid(start + 1, end - start - 1)); - - start = interpret.indexOf('"', end + 1); - if (start == -1) { - if ((int)interpret.length() > end) { - // skip " and space - r.setExtra(interpret.right(interpret.length() - end - 2)); - } - - return true; - } - - end = interpret.indexOf('"', start + 1); - if (end == -1) { - ksDebug << "Possible insufficient buffer size." << returnEndLine(); - r.setVal(interpret.right(interpret.length() - start)); - return true; - } - - r.setVal(interpret.mid(start + 1, end - start - 1)); - return true; -} - -bool kio_sieveProtocol::operationSuccessful() -{ - while (receiveData(true)) { - if (r.getType() == kio_sieveResponse::ACTION) { - QByteArray response = r.getAction().left(2); - if (response == "OK") { - return true; - } else if (response == "NO") { - return false; - } - } - } - return false; -} - -int kio_sieveProtocol::operationResult() -{ - if (r.getType() == kio_sieveResponse::ACTION) { - QByteArray response = r.getAction().left(2); - if (response == "OK") { - return OK; - } else if (response == "NO") { - return NO; - } else if (response == "BY" /*E*/) { - return BYE; - } - } - - return OTHER; -} - -bool kio_sieveProtocol::requestCapabilitiesAfterStartTLS() const -{ - // Cyrus didn't send CAPABILITIES after STARTTLS until 2.3.11, which is - // not standard conform, but we need to support that anyway. - // m_implementation looks like this 'Cyrus timsieved v2.2.12' for Cyrus btw. - QRegularExpression regExp(QStringLiteral("Cyrus\\stimsieved\\sv(\\d+)\\.(\\d+)\\.(\\d+)([-\\w]*)"), QRegularExpression::CaseInsensitiveOption); - QRegularExpressionMatch match = regExp.match(m_implementation); - if (match.hasMatch()) { - const int major = match.captured(1).toInt(); - const int minor = match.captured(2).toInt(); - const int patch = match.captured(3).toInt(); - const QString vendor = match.captured(4); - if (major < 2 || (major == 2 && (minor < 3 || (minor == 3 && patch < 11))) || (vendor == QLatin1String("-kolab-nocaps"))) { - ksDebug << " kio_sieveProtocol::requestCapabilitiesAfterStartTLS : Enabling compat mode for Cyrus < 2.3.11 or Cyrus marked as \"kolab-nocaps\"" - << returnEndLine(); - return true; - } - } - return false; -} -#include "sieve.moc" diff --git a/kioslave/src/sieve/sieve.h b/kioslave/src/sieve/sieve.h deleted file mode 100644 index c8abc73f..00000000 --- a/kioslave/src/sieve/sieve.h +++ /dev/null @@ -1,119 +0,0 @@ -/* - sieve.h - - SPDX-FileCopyrightText: 2001 Hamish Rodda <[email protected]> - - SPDX-License-Identifier: GPL-2.0-only -*/ - -#pragma once - -#include <KIO/AuthInfo> -#include <KIO/TCPSlaveBase> - -#include <QByteArray> -#include <QString> -#include <QStringList> - -class kio_sieveResponse -{ -public: - enum responses { NONE, KEY_VAL_PAIR, ACTION, QUANTITY }; - - kio_sieveResponse(); - - const uint &getType() const; - - const QByteArray &getAction() const; - uint getQuantity() const; - const QByteArray &getKey() const; - const QByteArray &getVal() const; - const QByteArray &getExtra() const; - - void setQuantity(uint quantity); - void setAction(const QByteArray &newAction); - void setKey(const QByteArray &newKey); - void setVal(const QByteArray &newVal); - void setExtra(const QByteArray &newExtra); - - void clear(); - -protected: - uint rType; - uint quantity; - QByteArray key; - QByteArray val; - QByteArray extra; -}; - -class kio_sieveProtocol : public KIO::TCPSlaveBase -{ -public: - enum connectionModes { NORMAL, CONNECTION_ORIENTED }; - enum Results { OK, NO, BYE, OTHER }; - - kio_sieveProtocol(const QByteArray &pool_socket, const QByteArray &app_socket); - ~kio_sieveProtocol() override; - - void mimetype(const QUrl &url) override; - void get(const QUrl &url) override; - void put(const QUrl &url, int permissions, KIO::JobFlags flags) override; - void del(const QUrl &url, bool isfile) override; - - void listDir(const QUrl &url) override; - void chmod(const QUrl &url, int permissions) override; - virtual void urlStat(const QUrl &url); - - void setHost(const QString &host, quint16 port, const QString &user, const QString &pass) override; - void openConnection() override; - void closeConnection() override; - // virtual void slave_status(); - - /** - * Special commands supported by this slave: - * 1 - activate script - * 2 - deactivate (all - only one active at any one time) scripts - * 3 - request capabilities, returned as metadata - */ - void special(const QByteArray &data) override; - bool activate(const QUrl &url); - bool deactivate(); - -protected: - bool connect(bool useTLSIfAvailable = true); - bool authenticate(); - void disconnect(bool forcibly = false); - void changeCheck(const QUrl &url); - - bool sendData(const QByteArray &data); - bool receiveData(bool waitForData = true, const QByteArray &reparse = QByteArray()); - bool operationSuccessful(); - int operationResult(); - - bool parseCapabilities(bool requestCapabilities = false); - bool saslInteract(void *in, KIO::AuthInfo &ai); - - // IOSlave global data - uint m_connMode; - - // Host-specific data - QStringList m_sasl_caps; - bool m_supportsTLS; - - // Global server response class - kio_sieveResponse r; - - // connection details - QString m_sServer; - QString m_sUser; - QString m_sPass; - QString m_sAuth; - bool m_shouldBeConnected; - bool m_allowUnencrypted; - quint16 m_port; - -private: - bool requestCapabilitiesAfterStartTLS() const; - - QString m_implementation; -}; diff --git a/kioslave/src/sieve/sieve.json b/kioslave/src/sieve/sieve.json deleted file mode 100644 index e84da9b8..00000000 --- a/kioslave/src/sieve/sieve.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "KDE-KIO-Protocols": { - "ldap": { - "Icon": "view-filter", - "X-DocPath": "kioslave5/sieve/index.html", - "deleting": true, - "determineMimetypeFromExtension": false, - "input": "none", - "listing": [ - "Name", - "Access", - "Type", - "MimeType" - ], - "output": "filesystem", - "protocol": "sieve", - "reading": true, - "source": true, - "writing": true - } - } -}
