From fe6c55bf935449d28a697530b3c83b461be7bb48 Mon Sep 17 00:00:00 2001 From: Stefan Radomski Date: Wed, 22 Jan 2014 17:36:59 +0100 Subject: Email Attachments and Prolog Version Fixes --- CMakeLists.txt | 4 +- contrib/cmake/FindLibPurple.cmake | 28 ++ contrib/cmake/FindSWI.cmake | 72 +++- src/uscxml/plugins/datamodel/CMakeLists.txt | 3 + .../plugins/datamodel/prolog/swi/SWIConfig.h.in | 3 + .../plugins/datamodel/prolog/swi/SWIDataModel.cpp | 6 + .../plugins/datamodel/prolog/swi/SWIDataModel.h | 2 + src/uscxml/plugins/invoker/CMakeLists.txt | 23 ++ src/uscxml/plugins/invoker/im/IMConfig.h.in | 0 src/uscxml/plugins/invoker/im/IMInvoker.h | 4 +- src/uscxml/plugins/invoker/imap/IMAPInvoker.cpp | 365 +++++++++++++++++++++ src/uscxml/plugins/invoker/imap/IMAPInvoker.h | 78 +++++ src/uscxml/plugins/invoker/smtp/SMTPInvoker.cpp | 4 +- src/uscxml/plugins/invoker/smtp/SMTPInvoker.h | 2 +- src/uscxml/server/InterpreterServlet.cpp | 2 +- test/samples/uscxml/test-smtp.scxml | 14 +- 16 files changed, 595 insertions(+), 15 deletions(-) create mode 100644 src/uscxml/plugins/datamodel/prolog/swi/SWIConfig.h.in create mode 100644 src/uscxml/plugins/invoker/im/IMConfig.h.in create mode 100644 src/uscxml/plugins/invoker/imap/IMAPInvoker.cpp create mode 100644 src/uscxml/plugins/invoker/imap/IMAPInvoker.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d21b59d..166acfc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -280,8 +280,8 @@ if (CMAKE_CROSSCOMPILING) OPTION(BUILD_TESTS "Build USCXML tests" OFF) else() OPTION(BUILD_TESTS "Build USCXML tests" ON) - OPTION(BUILD_TESTS_W3C_ECMA "Run W3C ECMAScript tests" OFF) - OPTION(BUILD_TESTS_W3C_XPATH "Run W3C XPath tests" OFF) + OPTION(BUILD_TESTS_W3C_ECMA "Run W3C ECMAScript tests" ON) + OPTION(BUILD_TESTS_W3C_XPATH "Run W3C XPath tests" ON) endif() OPTION(ENABLE_GCOV "Compile with gcov support" OFF) diff --git a/contrib/cmake/FindLibPurple.cmake b/contrib/cmake/FindLibPurple.cmake index fd9b3bc..327f6a4 100644 --- a/contrib/cmake/FindLibPurple.cmake +++ b/contrib/cmake/FindLibPurple.cmake @@ -1,3 +1,5 @@ +include(CheckCXXSourceCompiles) + FIND_PATH(LIBPURPLE_INCLUDE_DIR purple.h PATH_SUFFIXES include/libpurple src/libpurple PATHS @@ -32,4 +34,30 @@ endif() INCLUDE(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBPURPLE DEFAULT_MSG LIBPURPLE_LIBRARY LIBPURPLE_INCLUDE_DIR) + +# we need to check the API of libpurple, but need a couple more libraries +find_package(ICONV) +find_package(GLIB2) +find_package(GObject) +if (LIBPURPLE_FOUND AND GLIB2_FOUND AND ICONV_FOUND AND GOBJECT_FOUND) + set(CMAKE_REQUIRED_INCLUDES ${LIBPURPLE_INCLUDE_DIR} ${GLIB2_INCLUDE_DIRS} ${ICONV_INCLUDE_DIR} ${GOBJECT_INCLUDE_DIR}) + set(CMAKE_REQUIRED_LIBRARIES ${LIBPURPLE_LIBRARY} ${GLIB2_LIBRARIES} ${ICONV_LIBRARIES} ${GOBJECT_LIBRARIES}) + if (LIBPURPLE_FOUND) + check_cxx_source_compiles(" + extern \"C\" { + #include + } + int main(){ + /* + * There was a refactoring to glib datastructures, + * The PurpleRequestFeature occured at the same time. + */ + PurpleRequestFeature _features; + } + " LIBPURPLE_GLIB_DATASTRUCTS) + endif() + set(CMAKE_REQUIRED_INCLUDES) + set(CMAKE_REQUIRED_LIBRARIES) +endif() + MARK_AS_ADVANCED(LIBPURPLE_LIBRARY LIBPURPLE_INCLUDE_DIR) diff --git a/contrib/cmake/FindSWI.cmake b/contrib/cmake/FindSWI.cmake index 0953307..7aa5f32 100644 --- a/contrib/cmake/FindSWI.cmake +++ b/contrib/cmake/FindSWI.cmake @@ -1,3 +1,15 @@ +set (SWI_SEARCH_PATHS) +list (APPEND SWI_SEARCH_PATHS + $ENV{SWI_HOME} + ${CMAKE_FIND_ROOT_PATH} + "/usr/lib/swi-prolog/" + "/opt/local/" + "/usr/local/" + "C:/Program Files (x86)/swipl" + "C:/Program Files/swipl" +) + + if (NOT WIN32) include(FindPkgConfig) pkg_check_modules(SWI swipl) @@ -11,6 +23,7 @@ if (SWI_FOUND) # message("SWI_INCLUDE_DIRS: ${SWI_INCLUDE_DIRS}") # message("SWI_CFLAGS: ${SWI_CFLAGS}") # message("SWI_CFLAGS_OTHER: ${SWI_CFLAGS_OTHER}") + # message("SWI_VERSION: ${SWI_VERSION}") # # message("SWI_LIBRARIES_STATIC: ${SWI_LIBRARIES_STATIC}") # message("SWI_LIBRARY_DIRS_STATIC: ${SWI_LIBRARY_DIRS_STATIC}") @@ -21,7 +34,16 @@ if (SWI_FOUND) # message("SWI_CFLAGS_OTHER_STATIC: ${SWI_CFLAGS_OTHER_STATIC}") # message(FATAL_ERROR "") - set(SWI_INCLUDE_DIR ${SWI_INCLUDE_DIRS}) + if (SWI_INCLUDE_DIRS) + set(SWI_INCLUDE_DIR ${SWI_INCLUDE_DIRS}) + else() + FIND_PATH(SWI_INCLUDE_DIR SWI-Prolog.h + PATH_SUFFIXES + include + lib/swipl-${SWI_VERSION}/include + PATHS ${SWI_SEARCH_PATHS} + ) + endif() FIND_LIBRARY(SWI_LIBRARY NAMES libswipl swipl @@ -57,7 +79,6 @@ else() #message("SWI_PLATFORM_ID: ${SWI_PLATFORM_ID}") - set (SWI_SEARCH_PATHS) list (APPEND SWI_SEARCH_PATHS $ENV{SWI_HOME} ${CMAKE_FIND_ROOT_PATH} @@ -166,4 +187,51 @@ endif() INCLUDE(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(SWI DEFAULT_MSG SWI_LIBRARY SWI_BINARY SWI_INCLUDE_DIR SWI_CPP_INCLUDE_DIR) + + +if (SWI_FOUND) + include(CheckCXXSourceCompiles) + + set(CMAKE_REQUIRED_INCLUDES ${SWI_INCLUDE_DIR}) + set(CMAKE_REQUIRED_LIBRARIES ${SWI_LIBRARY}) + + check_cxx_source_compiles(" + #include + int main(){ + int a = 0; + switch(a) { + case PL_NIL: + break; + } + } + " SWI_HAS_PL_NIL) + + check_cxx_source_compiles(" + #include + int main(){ + int a = 0; + switch(a) { + case PL_DICT: + break; + } + } + " SWI_HAS_PL_DICT) + + check_cxx_source_compiles(" + #include + int main(){ + int a = 0; + switch(a) { + case PL_LIST_PAIR: + break; + } + } + " SWI_HAS_PL_LIST_PAIR) + + set(CMAKE_REQUIRED_INCLUDES) + set(CMAKE_REQUIRED_LIBRARIES) +endif() + MARK_AS_ADVANCED(SWI_LIBRARY SWI_INCLUDE_DIR) + + diff --git a/src/uscxml/plugins/datamodel/CMakeLists.txt b/src/uscxml/plugins/datamodel/CMakeLists.txt index e23d534..3e2aaae 100644 --- a/src/uscxml/plugins/datamodel/CMakeLists.txt +++ b/src/uscxml/plugins/datamodel/CMakeLists.txt @@ -105,6 +105,9 @@ endif() if (SWI_FOUND AND BUILD_DM_PROLOG) set(USCXML_DATAMODELS "prolog ${USCXML_DATAMODELS}") + + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/prolog/swi/SWIConfig.h.in ${CMAKE_BINARY_DIR}/uscxml/SWIConfig.h) + # message(FATAL_ERROR "SWI_INCLUDE_DIR: ${SWI_INCLUDE_DIR}") # if(${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang") diff --git a/src/uscxml/plugins/datamodel/prolog/swi/SWIConfig.h.in b/src/uscxml/plugins/datamodel/prolog/swi/SWIConfig.h.in new file mode 100644 index 0000000..2c0dc72 --- /dev/null +++ b/src/uscxml/plugins/datamodel/prolog/swi/SWIConfig.h.in @@ -0,0 +1,3 @@ +#cmakedefine SWI_HAS_PL_NIL +#cmakedefine SWI_HAS_PL_DICT +#cmakedefine SWI_HAS_PL_LIST_PAIR \ No newline at end of file diff --git a/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp b/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp index de94088..b52daa9 100644 --- a/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp +++ b/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp @@ -408,9 +408,12 @@ Data SWIDataModel::termAsData(PlTerm term) { data.atom = std::string(term); data.type = Data::VERBATIM; break; +#ifdef SWI_HAS_PL_NIL case PL_NIL: data.array.push_back(Data("", Data::VERBATIM)); break; +#endif +#ifdef SWI_HAS_PL_LIST_PAIR case PL_LIST_PAIR: { PlTail tail(term); PlTerm item; @@ -419,6 +422,8 @@ Data SWIDataModel::termAsData(PlTerm term) { } break; } +#endif +#ifdef SWI_HAS_DICT case PL_DICT: { std::string key(term); size_t curlyPos = key.find_first_of("{"); @@ -432,6 +437,7 @@ Data SWIDataModel::termAsData(PlTerm term) { } break; } +#endif default: LOG(ERROR) << "Prolog type " << term.type() << " at '" << (char*)term << "' not supported"; break; diff --git a/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.h b/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.h index 66a9257..0855d89 100644 --- a/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.h +++ b/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.h @@ -24,6 +24,8 @@ #include #include +#include "uscxml/SWIConfig.h" + #ifdef BUILD_AS_PLUGINS #include "uscxml/plugins/Plugins.h" #endif diff --git a/src/uscxml/plugins/invoker/CMakeLists.txt b/src/uscxml/plugins/invoker/CMakeLists.txt index e731d74..aec337b 100644 --- a/src/uscxml/plugins/invoker/CMakeLists.txt +++ b/src/uscxml/plugins/invoker/CMakeLists.txt @@ -137,6 +137,26 @@ else() endif() +# IMAP invoker via curl + +set(USCXML_INVOKERS "imap ${USCXML_INVOKERS}") +file(GLOB_RECURSE IMAP_INVOKER + imap/*.cpp + imap/*.h +) +if (BUILD_AS_PLUGINS) + source_group("" FILES IMAP_INVOKER) + add_library( + invoker_imap SHARED + IMAP_INVOKER} + "../Plugins.cpp") + target_link_libraries(invoker_imap uscxml) + set_target_properties(invoker_imap PROPERTIES FOLDER "Plugin Invoker") +else() + list (APPEND USCXML_FILES ${IMAP_INVOKER}) +endif() + + # SQLite3 SQL Invoker if (SQLITE3_FOUND) @@ -184,10 +204,13 @@ endif() if (LIBPURPLE_FOUND) set(USCXML_INVOKERS "im ${USCXML_INVOKERS}") + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/im/IMConfig.h.in ${CMAKE_BINARY_DIR}/uscxml/IMConfig.h) + file(GLOB_RECURSE LIBPURPLE_INVOKER im/*.cpp im/*.h ) + if (BUILD_AS_PLUGINS) source_group("" FILES ${LIBPURPLE_INVOKER}) add_library( diff --git a/src/uscxml/plugins/invoker/im/IMConfig.h.in b/src/uscxml/plugins/invoker/im/IMConfig.h.in new file mode 100644 index 0000000..e69de29 diff --git a/src/uscxml/plugins/invoker/im/IMInvoker.h b/src/uscxml/plugins/invoker/im/IMInvoker.h index 2198cc3..cb7032b 100644 --- a/src/uscxml/plugins/invoker/im/IMInvoker.h +++ b/src/uscxml/plugins/invoker/im/IMInvoker.h @@ -23,9 +23,11 @@ #include extern "C" { -#include +#include } +#include "uscxml/IMConfig.h" + #ifdef BUILD_AS_PLUGINS #include "uscxml/plugins/Plugins.h" #endif diff --git a/src/uscxml/plugins/invoker/imap/IMAPInvoker.cpp b/src/uscxml/plugins/invoker/imap/IMAPInvoker.cpp new file mode 100644 index 0000000..22e32da --- /dev/null +++ b/src/uscxml/plugins/invoker/imap/IMAPInvoker.cpp @@ -0,0 +1,365 @@ +/** + * @file + * @author 2012-2013 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de) + * @copyright Simplified BSD + * + * @cond + * This program is free software: you can redistribute it and/or modify + * it under the terms of the FreeBSD license as published by the FreeBSD + * project. + * + * 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. + * + * You should have received a copy of the FreeBSD license along with this + * program. If not, see . + * @endcond + */ + +#include "IMAPInvoker.h" +#include + +#ifdef BUILD_AS_PLUGINS +#include +#endif + +#include +#include "uscxml/UUID.h" + +namespace uscxml { + +#ifdef BUILD_AS_PLUGINS +PLUMA_CONNECTOR +bool pluginConnect(pluma::Host& host) { + host.add( new IMAPInvokerProvider() ); + return true; +} +#endif + +IMAPInvoker::IMAPInvoker() { +} + +IMAPInvoker::~IMAPInvoker() { +}; + +boost::shared_ptr IMAPInvoker::create(InterpreterImpl* interpreter) { + boost::shared_ptr invoker = boost::shared_ptr(new IMAPInvoker()); + return invoker; +} + +Data IMAPInvoker::getDataModelVariables() { + Data data; + return data; +} + +size_t IMAPInvoker::writeCurlData(void *ptr, size_t size, size_t nmemb, void *userdata) { + if (!userdata) + return 0; + + IMAPContext* ctx = (IMAPContext*)userdata; + + size_t toWrite = std::min(ctx->content.length() - ctx->readPtr, size * nmemb); + if (toWrite > 0) { + memcpy (ptr, ctx->content.c_str() + ctx->readPtr, toWrite); + ctx->readPtr += toWrite; + } + + return toWrite; +} + +std::list IMAPInvoker::getAtoms(std::list list) { + std::list atoms; + + std::list::const_iterator iter = list.begin(); + while(iter != list.end()) { + const Data& data = *iter; + if (data.atom.size() > 0) { + atoms.push_back(data.atom); + } else if (data.array.size() > 0) { + std::list::const_iterator arrIter = data.array.begin(); + while(arrIter != data.array.end()) { + if (arrIter->atom.size() > 0) { + atoms.push_back(arrIter->atom); + arrIter++; + } + } + } + iter++; + } + return atoms; +} + +void IMAPInvoker::getAttachments(std::list list, std::list& attachments) { + // accumulate attachments with filename, mimetype and data + std::list::const_iterator iter = list.begin(); + while(iter != list.end()) { + const Data& data = *iter; + if (data.hasKey("data")) { + // compound structure with all information + Data att = data; + + if (!att.hasKey("mimetype")) { + if (att["data"].binary && att["data"].binary->mimeType.size() > 0) { + att.compound["mimetype"] = Data(att["data"].binary->mimeType, Data::VERBATIM); + } else { + att.compound["mimetype"] = Data("text/plain", Data::VERBATIM); + } + } + + if (!att.hasKey("filename")) { + std::stringstream filenameSS; + filenameSS << "attachment" << attachments.size() + 1; + if (boost::starts_with(att.compound["mimetype"].atom, "text")) { + filenameSS << ".txt"; + } else { + filenameSS << ".bin"; + } + att.compound["filename"] = Data(filenameSS.str(), Data::VERBATIM); + } + + attachments.push_back(att); + + } else if (data.binary) { + // a single binary blob + Data att; + + att.compound["data"].binary = data.binary; + + if (data.binary->mimeType.size() > 0) { + att.compound["mimetype"] = Data(attachments.back()["data"].binary->mimeType, Data::VERBATIM); + } else { + att.compound["mimetype"] = Data("application/octet-stream", Data::VERBATIM); + } + + std::stringstream filenameSS; + filenameSS << "attachment" << attachments.size() + 1; + if (boost::starts_with(att.compound["mimetype"].atom, "text")) { + filenameSS << ".txt"; + } else { + filenameSS << ".bin"; + } + att.compound["filename"] = Data(filenameSS.str(), Data::VERBATIM); + + attachments.push_back(att); + + } else if (data.compound.size() > 0) { + // data is some compound, descent to find attachment structures or binaries + std::map::const_iterator compIter = data.compound.begin(); + while(compIter != data.compound.end()) { + std::list tmp; + tmp.push_back(compIter->second); + getAttachments(tmp, attachments); + compIter++; + } + } else if (data.array.size() > 0) { + // descent into array + getAttachments(data.array, attachments); + } + iter++; + } +} + +void IMAPInvoker::send(const SendRequest& req) { + if (iequals(req.name, "mail.send")) { + + struct curl_slist* recipients = NULL; + CURLcode curlError; + std::string multipartSep; + + bool verbose; + bool useSSL; + std::string from; + std::string subject; + std::string contentType; + std::list headerParams; + std::list toParams; + std::list ccParams; + std::list bccParams; + std::list attachmentParams; + + Event::getParam(req.params, "verbose", verbose); + Event::getParam(req.params, "ssl", useSSL); + Event::getParam(req.params, "Content-Type", contentType); + Event::getParam(req.params, "attachment", attachmentParams); + Event::getParam(req.params, "from", from); + Event::getParam(req.params, "subject", subject); + Event::getParam(req.params, "header", headerParams); + Event::getParam(req.params, "to", toParams); + Event::getParam(req.params, "cc", ccParams); + Event::getParam(req.params, "bcc", bccParams); + + if (contentType.size() == 0) + contentType = "text/plain; charset=\"UTF-8\""; + + IMAPContext* ctx = new IMAPContext(); + std::stringstream contentSS; + + std::list::const_iterator recIter; + std::list to = getAtoms(toParams); + std::list cc = getAtoms(ccParams); + std::list bcc = getAtoms(bccParams); + std::list headers = getAtoms(headerParams); + std::list attachments; getAttachments(attachmentParams, attachments); + + if (to.size() == 0) + return; + + recIter = to.begin(); + recIter++; // skip first as we need it in CURLOPT_MAIL_RCPT + while(recIter != to.end()) { + contentSS << "TO: " << *recIter << std::endl; + recIter++; + } + recIter = cc.begin(); + while(recIter != cc.end()) { + contentSS << "CC: " << *recIter << std::endl; + recIter++; + } + recIter = bcc.begin(); + while(recIter != bcc.end()) { + contentSS << "BCC: " << *recIter << std::endl; + recIter++; + } + + recIter = headers.begin(); + while(recIter != headers.end()) { + contentSS << *recIter << std::endl; + recIter++; + } + + if (subject.length() > 0) { + boost::replace_all(subject, "\n\r", " "); + boost::replace_all(subject, "\r\n", " "); + boost::replace_all(subject, "\n", " "); + boost::replace_all(subject, "\r", " "); + contentSS << "Subject: " << subject << "\n"; + } + + // content type is different when we have attachments + if (attachments.size() > 0) { + multipartSep = UUID::getUUID(); + boost::replace_all(multipartSep, "-", ""); + contentSS << "Content-Type: multipart/mixed; boundary=\"" << multipartSep << "\"\n"; + contentSS << "MIME-Version: 1.0\n"; + contentSS << "\n"; + contentSS << "--" << multipartSep << "\n"; + contentSS << "Content-Type: " << contentType << "\n"; + } else { + // when we have no attachment, respect user-defined or use text/plain + contentSS << "Content-Type: " << contentType << "\n"; + } + + contentSS << "\n"; + contentSS << req.content; + + std::list::iterator attIter = attachments.begin(); + while(attIter != attachments.end()) { + // only send valid attachments + if(!attIter->hasKey("filename") || !attIter->hasKey("mimetype") || !attIter->hasKey("data")) { + LOG(ERROR) << "Not sending attachment as filename, mimetype or data is missing: " << *attIter; + } else { + contentSS << "\n\n"; + contentSS << "--" << multipartSep << "\n"; + contentSS << "Content-Disposition: attachment; filename=\"" << attIter->compound["filename"].atom << "\""; + contentSS << "\n"; + + contentSS << "Content-Type: " << attIter->compound["mimetype"].atom << "; "; + contentSS << "name=\"" << attIter->compound["filename"].atom << "\""; + contentSS << "\n"; + + if (attIter->compound["data"].binary) { + contentSS << "Content-Transfer-Encoding: base64"; + contentSS << "\n\n"; + contentSS << attIter->compound["data"].binary->base64(); + } else { + contentSS << "Content-Transfer-Encoding: 7Bit"; + contentSS << "\n\n"; + contentSS << attIter->compound["data"].atom; + } + } + attIter++; + } + + ctx->content = contentSS.str(); + ctx->invoker = this; + + + // see http://curl.haxx.se/libcurl/c/imap-tls.html + _curl = curl_easy_init(); + if(_curl) { + (curlError = curl_easy_setopt(_curl, CURLOPT_USERNAME, _username.c_str())) == CURLE_OK || + LOG(ERROR) << "Cannot set username: " << curl_easy_strerror(curlError); + (curlError = curl_easy_setopt(_curl, CURLOPT_PASSWORD, _password.c_str())) == CURLE_OK || + LOG(ERROR) << "Cannot set password: " << curl_easy_strerror(curlError); + (curlError = curl_easy_setopt(_curl, CURLOPT_URL, _server.c_str())) == CURLE_OK || + LOG(ERROR) << "Cannot set server string: " << curl_easy_strerror(curlError); + + if (useSSL) { + (curlError = curl_easy_setopt(_curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL)) == CURLE_OK || + LOG(ERROR) << "Cannot use SSL: " << curl_easy_strerror(curlError); +#if 1 + (curlError = curl_easy_setopt(_curl, CURLOPT_SSL_VERIFYPEER, 0L)) == CURLE_OK || + LOG(ERROR) << "Cannot unset verify peer with SSL: " << curl_easy_strerror(curlError); + (curlError = curl_easy_setopt(_curl, CURLOPT_SSL_VERIFYHOST, 0L)) == CURLE_OK || + LOG(ERROR) << "Cannot unset verify host with SSL: " << curl_easy_strerror(curlError); +#else + (curlError = curl_easy_setopt(_curl, CURLOPT_CAINFO, "/path/to/certificate.pem")) == CURLE_OK || + LOG(ERROR) << "Cannot set CA info path: " << curl_easy_strerror(curlError); +#endif + + } + + // this is needed, even if we have a callback function + recipients = curl_slist_append(recipients, to.begin()->c_str()); + (curlError = curl_easy_setopt(_curl, CURLOPT_MAIL_RCPT, recipients)) == CURLE_OK || + LOG(ERROR) << "Cannot set mail recipient: " << curl_easy_strerror(curlError); + + (curlError = curl_easy_setopt(_curl, CURLOPT_READFUNCTION, IMAPInvoker::writeCurlData)) == CURLE_OK || + LOG(ERROR) << "Cannot register read function: " << curl_easy_strerror(curlError); + (curlError = curl_easy_setopt(_curl, CURLOPT_READDATA, ctx)) == CURLE_OK || + LOG(ERROR) << "Cannot register userdata for read function: " << curl_easy_strerror(curlError); + (curlError = curl_easy_setopt(_curl, CURLOPT_UPLOAD, 1L)) == CURLE_OK || + LOG(ERROR) << "Cannot set upload parameter: " << curl_easy_strerror(curlError); + + if (from.length() > 0) { + (curlError = curl_easy_setopt(_curl, CURLOPT_MAIL_FROM, from.c_str())) == CURLE_OK || + LOG(ERROR) << "Cannot set from parameter: " << curl_easy_strerror(curlError); + } + + if (verbose) { + (curlError = curl_easy_setopt(_curl, CURLOPT_VERBOSE, 1L)) == CURLE_OK || + LOG(ERROR) << "Cannot set curl to verbose: " << curl_easy_strerror(curlError); + } + + CURLcode res = curl_easy_perform(_curl); + + /* Check for errors */ + if(res != CURLE_OK){ + LOG(ERROR) << "curl_easy_perform() failed: " << curl_easy_strerror(res); + returnErrorExecution("error.mail.send"); + } else { + returnErrorExecution("success.mail.send"); + } + /* Free the list of recipients */ + if (recipients) + curl_slist_free_all(recipients); + + /* Always cleanup */ + curl_easy_cleanup(_curl); + + } + + } +} + +void IMAPInvoker::cancel(const std::string sendId) { +} + +void IMAPInvoker::invoke(const InvokeRequest& req) { + Event::getParam(req.params, "username", _username); + Event::getParam(req.params, "password", _password); + Event::getParam(req.params, "server", _server); +} + +} \ No newline at end of file diff --git a/src/uscxml/plugins/invoker/imap/IMAPInvoker.h b/src/uscxml/plugins/invoker/imap/IMAPInvoker.h new file mode 100644 index 0000000..b772bdd --- /dev/null +++ b/src/uscxml/plugins/invoker/imap/IMAPInvoker.h @@ -0,0 +1,78 @@ +/** + * @file + * @author 2012-2013 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de) + * @copyright Simplified BSD + * + * @cond + * This program is free software: you can redistribute it and/or modify + * it under the terms of the FreeBSD license as published by the FreeBSD + * project. + * + * 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. + * + * You should have received a copy of the FreeBSD license along with this + * program. If not, see . + * @endcond + */ + +#ifndef IMAPINVOKER_H_W09JFED0 +#define IMAPINVOKER_H_W09JFED0 + +#include + +#ifdef BUILD_AS_PLUGINS +#include "uscxml/plugins/Plugins.h" +#endif + +#include + +namespace uscxml { + +class IMAPInvoker : public InvokerImpl { +public: + IMAPInvoker(); + virtual ~IMAPInvoker(); + virtual boost::shared_ptr create(InterpreterImpl* interpreter); + + virtual std::set getNames() { + std::set names; + names.insert("imap"); + names.insert("http://uscxml.tk.informatik.tu-darmstadt.de/#imap"); + return names; + } + + virtual Data getDataModelVariables(); + virtual void send(const SendRequest& req); + virtual void cancel(const std::string sendId); + virtual void invoke(const InvokeRequest& req); + +protected: + + class IMAPContext { + public: + IMAPContext() : readPtr(0) {} + std::string content; + size_t readPtr; + IMAPInvoker* invoker; + }; + + CURL* _curl; + std::string _username; + std::string _password; + std::string _server; + + std::list getAtoms(std::list list); + void getAttachments(std::list list, std::list& attachments); + static size_t writeCurlData(void *ptr, size_t size, size_t nmemb, void *userdata); +}; + +#ifdef BUILD_AS_PLUGINS +PLUMA_INHERIT_PROVIDER(IMAPInvoker, InvokerImpl); +#endif + +} + + +#endif /* end of include guard: IMAPINVOKER_H_W09JFED0 */ diff --git a/src/uscxml/plugins/invoker/smtp/SMTPInvoker.cpp b/src/uscxml/plugins/invoker/smtp/SMTPInvoker.cpp index 420ab52..9234fc5 100644 --- a/src/uscxml/plugins/invoker/smtp/SMTPInvoker.cpp +++ b/src/uscxml/plugins/invoker/smtp/SMTPInvoker.cpp @@ -53,7 +53,7 @@ Data SMTPInvoker::getDataModelVariables() { return data; } -size_t SMTPInvoker::readCurlData(void *ptr, size_t size, size_t nmemb, void *userdata) { +size_t SMTPInvoker::writeCurlData(void *ptr, size_t size, size_t nmemb, void *userdata) { if (!userdata) return 0; @@ -300,7 +300,7 @@ void SMTPInvoker::send(const SendRequest& req) { (curlError = curl_easy_setopt(_curl, CURLOPT_MAIL_RCPT, recipients)) == CURLE_OK || LOG(ERROR) << "Cannot set mail recipient: " << curl_easy_strerror(curlError); - (curlError = curl_easy_setopt(_curl, CURLOPT_READFUNCTION, SMTPInvoker::readCurlData)) == CURLE_OK || + (curlError = curl_easy_setopt(_curl, CURLOPT_READFUNCTION, SMTPInvoker::writeCurlData)) == CURLE_OK || LOG(ERROR) << "Cannot register read function: " << curl_easy_strerror(curlError); (curlError = curl_easy_setopt(_curl, CURLOPT_READDATA, ctx)) == CURLE_OK || LOG(ERROR) << "Cannot register userdata for read function: " << curl_easy_strerror(curlError); diff --git a/src/uscxml/plugins/invoker/smtp/SMTPInvoker.h b/src/uscxml/plugins/invoker/smtp/SMTPInvoker.h index f3876bd..1167153 100644 --- a/src/uscxml/plugins/invoker/smtp/SMTPInvoker.h +++ b/src/uscxml/plugins/invoker/smtp/SMTPInvoker.h @@ -65,7 +65,7 @@ protected: std::list getAtoms(std::list list); void getAttachments(std::list list, std::list& attachments); - static size_t readCurlData(void *ptr, size_t size, size_t nmemb, void *userdata); + static size_t writeCurlData(void *ptr, size_t size, size_t nmemb, void *userdata); }; #ifdef BUILD_AS_PLUGINS diff --git a/src/uscxml/server/InterpreterServlet.cpp b/src/uscxml/server/InterpreterServlet.cpp index a62a6eb..af56ba3 100644 --- a/src/uscxml/server/InterpreterServlet.cpp +++ b/src/uscxml/server/InterpreterServlet.cpp @@ -138,7 +138,7 @@ bool InterpreterWebSocketServlet::wsRecvRequest(struct evws_connection *conn, co Data InterpreterWebSocketServlet::getDataModelVariables() { Data data; - if(_url.length() > 0); + if(_url.length() > 0) data.compound["location"] = Data(_url, Data::VERBATIM); return data; } diff --git a/test/samples/uscxml/test-smtp.scxml b/test/samples/uscxml/test-smtp.scxml index 7c3ad22..44a0176 100644 --- a/test/samples/uscxml/test-smtp.scxml +++ b/test/samples/uscxml/test-smtp.scxml @@ -12,18 +12,20 @@ + - -- cgit v0.12