From 161bc918e745801bcf7fa5a9f504c721aab08258 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Sun, 10 Apr 2016 10:56:55 +0200 Subject: Added a mailtransport resource for smtp --- examples/CMakeLists.txt | 1 + examples/mailtransportresource/CMakeLists.txt | 16 +++ examples/mailtransportresource/facade.cpp | 142 ++++++++++++++++++ examples/mailtransportresource/facade.h | 36 +++++ examples/mailtransportresource/mailtransport.cpp | 160 +++++++++++++++++++++ examples/mailtransportresource/mailtransport.h | 28 ++++ .../mailtransportresource.cpp | 39 +++++ .../mailtransportresource/mailtransportresource.h | 39 +++++ 8 files changed, 461 insertions(+) create mode 100644 examples/mailtransportresource/CMakeLists.txt create mode 100644 examples/mailtransportresource/facade.cpp create mode 100644 examples/mailtransportresource/facade.h create mode 100644 examples/mailtransportresource/mailtransport.cpp create mode 100644 examples/mailtransportresource/mailtransport.h create mode 100644 examples/mailtransportresource/mailtransportresource.cpp create mode 100644 examples/mailtransportresource/mailtransportresource.h (limited to 'examples') diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 837903a..d5fcacf 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -8,3 +8,4 @@ if (BUILD_MAILDIR) # a maildir resource implementation add_subdirectory(maildirresource) endif() +add_subdirectory(mailtransportresource) diff --git a/examples/mailtransportresource/CMakeLists.txt b/examples/mailtransportresource/CMakeLists.txt new file mode 100644 index 0000000..c9b0401 --- /dev/null +++ b/examples/mailtransportresource/CMakeLists.txt @@ -0,0 +1,16 @@ +project(sink_resource_mailtransport) + +add_definitions(-DQT_PLUGIN) +include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) + +find_package(KF5 COMPONENTS REQUIRED Mime) +find_package(CURL 7.20.0 REQUIRED) + +include_directories(${CURL_INCLUDE_DIRS}) + + +add_library(${PROJECT_NAME} SHARED facade.cpp mailtransportresource.cpp mailtransport.cpp) +qt5_use_modules(${PROJECT_NAME} Core Network) +target_link_libraries(${PROJECT_NAME} sink KF5::Mime ${CURL_LIBRARIES}) + +install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${SINK_RESOURCE_PLUGINS_PATH}) diff --git a/examples/mailtransportresource/facade.cpp b/examples/mailtransportresource/facade.cpp new file mode 100644 index 0000000..b90df16 --- /dev/null +++ b/examples/mailtransportresource/facade.cpp @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2014 Christian Mollekopf + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 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. + */ + +#include "facade.h" + +#include +#include +#include +#include +#include +#include + +#include "resultprovider.h" +#include "mailtransport.h" +#include +#include + +static QString dataDirectory(const QByteArray &identifier) +{ + return QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/sink/mailtransport/" + identifier; +} + +class Outbox { +public: + Outbox(const QByteArray &identifier) : mIdentifier(identifier) + { + + } + + static QString fileName(const QByteArray &resourceId, const QByteArray &messageId) + { + return dataDirectory(resourceId)+"/" + messageId; + } + + void add(const QByteArray &messageId, const QString &messagePath, QMap config) + { + QDir dir; + dir.mkpath(dataDirectory(mIdentifier)); + if (!QFile(messagePath).rename(fileName(mIdentifier, messageId))) { + ErrorMsg() << "Failed to move the file:"; + ErrorMsg() << messagePath << " to " << fileName(mIdentifier, messageId); + } + //TODO store settings + // QSettings settings(dataDirectory(mIdentifier) + "/messageId.ini", QSettings::IniFormat); + } + + void dispatch(const QByteArray &messageId) + { + QFile mimeMessage(fileName(mIdentifier, messageId)); + if (!mimeMessage.open(QIODevice::ReadOnly)) { + ErrorMsg() << "Failed to open mime message: " << mimeMessage.errorString(); + ErrorMsg() << fileName(mIdentifier, messageId); + return; + } + + auto msg = KMime::Message::Ptr::create(); + msg->setHead(KMime::CRLFtoLF(mimeMessage.readAll())); + msg->parse(); + MailTransport::sendMessage(msg, mServer, mUsername, mPassword, mCaCert); + Trace() << "Sent message: " << msg->subject(); + } + + void setServer(const QByteArray &server, const QByteArray &username, const QByteArray &caCert) + { + mServer = server; + mUsername = username; + mCaCert = caCert; + } + + void setPassword(const QByteArray &password) + { + mPassword = password; + } + +private: + QByteArray mServer; + QByteArray mUsername; + QByteArray mPassword; + QByteArray mCaCert; + QByteArray mIdentifier; +}; + +MailtransportFacade::MailtransportFacade(const QByteArray &identifier) : Sink::StoreFacade(), mIdentifier(identifier) +{ +} + +MailtransportFacade::~MailtransportFacade() +{ +} + +KAsync::Job MailtransportFacade::create(const Sink::ApplicationDomain::Mail &mail) +{ + Trace() << "Called create: "; + return KAsync::start([mail, this]() { + auto config = ResourceConfig::getConfiguration(mIdentifier); + + auto identifier = QUuid::createUuid().toByteArray(); + Trace() << "Sending new message: " << identifier; + Trace() << config.value("server").toByteArray() << config.value("username").toByteArray() << config.value("cacert").toByteArray(); + + Outbox outbox(mIdentifier); + outbox.setServer(config.value("server").toByteArray(), config.value("username").toByteArray(), config.value("cacert").toByteArray()); + //FIXME remove and somehow retrieve the password on demand + outbox.setPassword(config.value("password").toByteArray()); + + const QByteArray mimeMessage = mail.getProperty("mimeMessage").toByteArray(); + QMap configurationValues; + outbox.add(identifier, mimeMessage, configurationValues); + outbox.dispatch(identifier); + }); +} + +KAsync::Job MailtransportFacade::modify(const Sink::ApplicationDomain::Mail &mail) +{ + return KAsync::error(0, "Not implemented."); +} + +KAsync::Job MailtransportFacade::remove(const Sink::ApplicationDomain::Mail &mail) +{ + return KAsync::error(0, "Not implemented."); +} + +QPair, typename Sink::ResultEmitter::Ptr> MailtransportFacade::load(const Sink::Query &query) +{ + return qMakePair(KAsync::error(0, "Not implemented."), Sink::ResultEmitter::Ptr()); +} diff --git a/examples/mailtransportresource/facade.h b/examples/mailtransportresource/facade.h new file mode 100644 index 0000000..858f73a --- /dev/null +++ b/examples/mailtransportresource/facade.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2014 Christian Mollekopf + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 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. + */ + +#pragma once + +#include "common/facade.h" + +class MailtransportFacade : public Sink::StoreFacade +{ +public: + MailtransportFacade(const QByteArray &instanceIdentifier); + virtual ~MailtransportFacade(); + KAsync::Job create(const Sink::ApplicationDomain::Mail &resource) Q_DECL_OVERRIDE; + KAsync::Job modify(const Sink::ApplicationDomain::Mail &resource) Q_DECL_OVERRIDE; + KAsync::Job remove(const Sink::ApplicationDomain::Mail &resource) Q_DECL_OVERRIDE; + QPair, typename Sink::ResultEmitter::Ptr> load(const Sink::Query &query) Q_DECL_OVERRIDE; +private: + QByteArray mIdentifier; +}; + diff --git a/examples/mailtransportresource/mailtransport.cpp b/examples/mailtransportresource/mailtransport.cpp new file mode 100644 index 0000000..49d858e --- /dev/null +++ b/examples/mailtransportresource/mailtransport.cpp @@ -0,0 +1,160 @@ +/* + Copyright (c) 2016 Christian Mollekopf + + 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 "mailtransport.h" + +#include +#include +#include + +extern "C" { + +#include +#include +#include + +struct upload_status { + int offset; + const char *data; +}; + +static size_t payload_source(void *ptr, size_t size, size_t nmemb, void *userp) +{ + struct upload_status *upload_ctx = (struct upload_status *)userp; + const char *data; + + if((size == 0) || (nmemb == 0) || ((size*nmemb) < 1)) { + return 0; + } + + data = &upload_ctx->data[upload_ctx->offset]; + if(data) { + size_t len = strlen(data); + if (len > size * nmemb) { + len = size * nmemb; + } + fprintf(stderr, "read n bytes: %d\n",len); + memcpy(ptr, data, len); + upload_ctx->offset += len; + return len; + } + + return 0; +} + + +void sendMessageCurl(const char *to[], int numTos, const char *cc[], int numCcs, const char *msg, bool useTls, const char* from, const char *username, const char *password, const char *server, bool verifyPeer) +{ + //For ssl use "smtps://mainserver.example.net + const char* cacert = 0; // = "/path/to/certificate.pem"; + + CURL *curl; + CURLcode res = CURLE_OK; + struct curl_slist *recipients = NULL; + struct upload_status upload_ctx; + + upload_ctx.offset = 0; + upload_ctx.data = msg; + + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_USERNAME, username); + curl_easy_setopt(curl, CURLOPT_PASSWORD, password); + + curl_easy_setopt(curl, CURLOPT_URL, server); + + if (useTls) { + curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_TRY); + } + + if (!verifyPeer) { + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); + } + if (cacert) { + curl_easy_setopt(curl, CURLOPT_CAINFO, cacert); + } + + if (from) { + curl_easy_setopt(curl, CURLOPT_MAIL_FROM, from); + } + + for (int i = 0; i < numTos; i++) { + recipients = curl_slist_append(recipients, to[i]); + } + for (int i = 0; i < numCcs; i++) { + recipients = curl_slist_append(recipients, cc[i]); + } + curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients); + + /* We're using a callback function to specify the payload (the headers and + * body of the message). You could just use the CURLOPT_READDATA option to + * specify a FILE pointer to read from. */ + curl_easy_setopt(curl, CURLOPT_READFUNCTION, payload_source); + curl_easy_setopt(curl, CURLOPT_READDATA, &upload_ctx); + curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); + + /* Since the traffic will be encrypted, it is very useful to turn on debug + * information within libcurl to see what is happening during the transfer. + */ + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + + res = curl_easy_perform(curl); + if(res != CURLE_OK) { + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + } + curl_slist_free_all(recipients); + curl_easy_cleanup(curl); + } +} + +}; + +void MailTransport::sendMessage(const KMime::Message::Ptr &message, const QByteArray &server, const QByteArray &username, const QByteArray &password, const QByteArray &cacert) +{ + QByteArray msg = message->encodedContent(); + qWarning() << "Sending message " << msg; + + QByteArray from(message->from(true)->mailboxes().isEmpty() ? QByteArray() : message->from(true)->mailboxes().first().address()); + QList toList; + for (const auto &mb : message->to(true)->mailboxes()) { + toList << mb.address(); + } + QList ccList; + for (const auto &mb : message->cc(true)->mailboxes()) { + ccList << mb.address(); + } + bool useTls = true; + bool verifyPeer = false; + + const int numTos = toList.size(); + const char* to[numTos]; + for (int i = 0; i < numTos; i++) { + to[i] = toList.at(i); + } + + const int numCcs = ccList.size(); + const char* cc[numCcs]; + for (int i = 0; i < numCcs; i++) { + cc[i] = ccList.at(i); + } + + sendMessageCurl(to, numTos, cc, numCcs, msg, useTls, from.isEmpty() ? nullptr : from, username, password, server, verifyPeer); + qWarning() << "Message sent"; +} diff --git a/examples/mailtransportresource/mailtransport.h b/examples/mailtransportresource/mailtransport.h new file mode 100644 index 0000000..2eb30a0 --- /dev/null +++ b/examples/mailtransportresource/mailtransport.h @@ -0,0 +1,28 @@ +/* + Copyright (c) 2016 Christian Mollekopf + + 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. +*/ + +#pragma once + +#include +#include + +namespace MailTransport +{ + void sendMessage(const KMime::Message::Ptr &message, const QByteArray &server, const QByteArray &username, const QByteArray &password, const QByteArray &cacert); +}; diff --git a/examples/mailtransportresource/mailtransportresource.cpp b/examples/mailtransportresource/mailtransportresource.cpp new file mode 100644 index 0000000..6c0f0b3 --- /dev/null +++ b/examples/mailtransportresource/mailtransportresource.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2015 Christian Mollekopf + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 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. + */ + +#include "mailtransportresource.h" +#include "facade.h" +#include "facadefactory.h" + +MailtransportResourceFactory::MailtransportResourceFactory(QObject *parent) + : Sink::ResourceFactory(parent) +{ + +} + +Sink::Resource *MailtransportResourceFactory::createResource(const QByteArray &instanceIdentifier) +{ + return nullptr; +} + +void MailtransportResourceFactory::registerFacades(Sink::FacadeFactory &factory) +{ + factory.registerFacade(PLUGIN_NAME); +} + diff --git a/examples/mailtransportresource/mailtransportresource.h b/examples/mailtransportresource/mailtransportresource.h new file mode 100644 index 0000000..2ccca0a --- /dev/null +++ b/examples/mailtransportresource/mailtransportresource.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2015 Christian Mollekopf + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 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. + */ + +#pragma once + +#include "common/resource.h" + +//TODO: a little ugly to have this in two places, once here and once in Q_PLUGIN_METADATA +#define PLUGIN_NAME "org.kde.mailtransport" + +class MailtransportResourceFactory : public Sink::ResourceFactory +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.kde.mailtransport") + Q_INTERFACES(Sink::ResourceFactory) + +public: + MailtransportResourceFactory(QObject *parent = 0); + + Sink::Resource *createResource(const QByteArray &instanceIdentifier) Q_DECL_OVERRIDE; + void registerFacades(Sink::FacadeFactory &factory) Q_DECL_OVERRIDE; +}; + -- cgit v1.2.3