Commit 41707df9 authored by Laurent Montel's avatar Laurent Montel 😁
Browse files

Move smtp kioslave here

parent 38b8d988
......@@ -38,7 +38,7 @@ ecm_setup_version(${KMAILTRANSPORT_LIB_VERSION} VARIABLE_PREFIX MAILTRANSPORT
find_package(KF5KCMUtils ${KF5_VERSION} CONFIG REQUIRED)
find_package(KF5ConfigWidgets ${KF5_VERSION} CONFIG REQUIRED)
find_package(KF5Wallet ${KF5_VERSION} CONFIG REQUIRED)
find_package(KF5DocTools ${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)
......@@ -77,12 +77,12 @@ install(EXPORT KF5MailTransportTargets DESTINATION "${CMAKECONFIG_INSTALL_DIR}"
########### Targets ###########
add_subdirectory(cmake)
add_subdirectory(src)
add_subdirectory(kioslave)
if(BUILD_TESTING)
add_subdirectory(tests)
add_subdirectory(autotests)
endif()
install( FILES kmailtransport.categories DESTINATION ${KDE_INSTALL_CONFDIR} )
feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES)
SKIP /tests/
add_definitions("-DQT_NO_CAST_FROM_ASCII -DQT_NO_CAST_TO_ASCII")
add_subdirectory(src)
add_subdirectory(docs)
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 copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
#
# - Try to find the sasl2 directory library
# Once done this will define
#
# Sasl2_FOUND - system has SASL2
# Sasl2_INCLUDE_DIRS - the SASL2 include directory
# Sasl2_LIBRARIES - The libraries needed to use SASL2
# Copyright (c) 2006, 2007 Laurent Montel, <montel@kde.org>
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
# Note: libsasl2.pc doesn't export the include dir.
find_package(PkgConfig QUIET)
pkg_check_modules(PC_Sasl2 libsasl2)
find_path(Sasl2_INCLUDE_DIRS sasl/sasl.h
)
# libsasl2 add for windows, because the windows package of cyrus-sasl2
# contains a libsasl2 also for msvc which is not standard conform
find_library(Sasl2_LIBRARIES
NAMES sasl2 libsasl2
HINTS ${PC_Sasl2_LIBRARY_DIRS}
)
set(Sasl2_VERSION ${PC_Sasl2_VERSION})
if(NOT Sasl2_VERSION)
if(EXISTS ${Sasl2_INCLUDE_DIRS}/sasl/sasl.h)
file(READ ${Sasl2_INCLUDE_DIRS}/sasl/sasl.h SASL2_H_CONTENT)
string(REGEX MATCH "#define SASL_VERSION_MAJOR[ ]+[0-9]+" SASL2_VERSION_MAJOR_MATCH ${SASL2_H_CONTENT})
string(REGEX MATCH "#define SASL_VERSION_MINOR[ ]+[0-9]+" SASL2_VERSION_MINOR_MATCH ${SASL2_H_CONTENT})
string(REGEX MATCH "#define SASL_VERSION_STEP[ ]+[0-9]+" SASL2_VERSION_STEP_MATCH ${SASL2_H_CONTENT})
string(REGEX REPLACE ".*_MAJOR[ ]+(.*)" "\\1" SASL2_VERSION_MAJOR ${SASL2_VERSION_MAJOR_MATCH})
string(REGEX REPLACE ".*_MINOR[ ]+(.*)" "\\1" SASL2_VERSION_MINOR ${SASL2_VERSION_MINOR_MATCH})
string(REGEX REPLACE ".*_STEP[ ]+(.*)" "\\1" SASL2_VERSION_STEP ${SASL2_VERSION_STEP_MATCH})
set(Sasl2_VERSION "${SASL2_VERSION_MAJOR}.${SASL2_VERSION_MINOR}.${SASL2_VERSION_STEP}")
endif()
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Sasl2
FOUND_VAR Sasl2_FOUND
REQUIRED_VARS Sasl2_LIBRARIES Sasl2_INCLUDE_DIRS
VERSION_VAR Sasl2_VERSION
)
mark_as_advanced(Sasl2_LIBRARIES Sasl2_INCLUDE_DIRS Sasl2_VERSION)
add_subdirectory(smtp)
########### install files ###############
kdoctools_create_handbook(index.docbook INSTALL_DESTINATION ${KDE_INSTALL_DOCBUNDLEDIR}/en SUBDIR kioslave5/smtp)
<?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>
remove_definitions(-DQT_NO_CAST_FROM_BYTEARRAY)
add_subdirectory(smtp)
/* This file is part of the KDE project
Copyright (C) 2008 Jarosław Staniek <staniek@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>
extern "C" {
#include <sasl/sasl.h>
}
inline bool initSASL()
{
#ifdef Q_OS_WIN32 //krazy:exclude=cpp
QByteArray libInstallPath(QFile::encodeName(QDir::toNativeSeparators(KGlobal::dirs()->installPath("lib") + QLatin1String("sasl2"))));
QByteArray configPath(QFile::encodeName(QDir::toNativeSeparators(KGlobal::dirs()->installPath("config") + QLatin1String("sasl2"))));
if (sasl_set_path(SASL_PATH_TYPE_PLUGIN, libInstallPath.data()) != SASL_OK ||
sasl_set_path(SASL_PATH_TYPE_CONFIG, configPath.data()) != SASL_OK) {
fprintf(stderr, "SASL path initialization failed!\n");
return false;
}
#endif
if (sasl_client_init(NULL) != SASL_OK) {
fprintf(stderr, "SASL library initialization failed!\n");
return false;
}
return true;
}
#endif
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 log_smtp)
add_library(kio_smtp MODULE ${kio_smtp_PART_SRCS})
target_link_libraries(kio_smtp KF5::KIOCore KF5::I18n Qt5::Network ${smtp_optional_libs})
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} )
#! /usr/bin/env bash
$XGETTEXT *.cpp -o $podir/kio_smtp.pot
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 ;-)
/* -*- c++ -*-
capabilities.cc
This file is part of kio_smtp, the KDE SMTP kioslave.
Copyright (c) 2003 Marc Mutz <mutz@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(); it != l.constEnd(); ++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(QStringLiteral(" "));
}
QStringList Capabilities::saslMethodsQSL() const
{
QStringList result;
for (QMap<QString, QStringList>::const_iterator it = mCapabilities.begin();
it != mCapabilities.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
/* -*- c++ -*-
capabilities.h
This file is part of kio_smtp, the KDE SMTP kioslave.
Copyright (c) 2003 Marc Mutz <mutz@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__
/* -*- c++ -*-
command.cc
This file is part of kio_smtp, the KDE SMTP kioslave.
Copyright (c) 2003 Marc Mutz <mutz@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 <QtCore/QUrl>
#include <assert.h>
namespace KioSMTP
{
static const sasl_callback_t callbacks[] = {
{ SASL_CB_ECHOPROMPT, NULL, NULL },
{ SASL_CB_NOECHOPROMPT, NULL, NULL },
{ SASL_CB_GETREALM, NULL, NULL },
{ SASL_CB_USER, NULL, NULL },
{ SASL_CB_AUTHNAME, NULL, NULL },
{ SASL_CB_PASS, NULL, NULL },
{ SASL_CB_CANON_USER, NULL, NULL },
{ SASL_CB_LIST_END, NULL, NULL }
};
//
// 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 0;
}
}
//
// 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...