summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt4
-rw-r--r--contrib/cmake/FindLibPurple.cmake28
-rw-r--r--contrib/cmake/FindSWI.cmake72
-rw-r--r--src/uscxml/plugins/datamodel/CMakeLists.txt3
-rw-r--r--src/uscxml/plugins/datamodel/prolog/swi/SWIConfig.h.in3
-rw-r--r--src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp6
-rw-r--r--src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.h2
-rw-r--r--src/uscxml/plugins/invoker/CMakeLists.txt23
-rw-r--r--src/uscxml/plugins/invoker/im/IMConfig.h.in0
-rw-r--r--src/uscxml/plugins/invoker/im/IMInvoker.h4
-rw-r--r--src/uscxml/plugins/invoker/imap/IMAPInvoker.cpp365
-rw-r--r--src/uscxml/plugins/invoker/imap/IMAPInvoker.h78
-rw-r--r--src/uscxml/plugins/invoker/smtp/SMTPInvoker.cpp4
-rw-r--r--src/uscxml/plugins/invoker/smtp/SMTPInvoker.h2
-rw-r--r--src/uscxml/server/InterpreterServlet.cpp2
-rw-r--r--test/samples/uscxml/test-smtp.scxml14
16 files changed, 595 insertions, 15 deletions
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 <purple.h>
+ }
+ 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 <SWI-Prolog.h>
+ int main(){
+ int a = 0;
+ switch(a) {
+ case PL_NIL:
+ break;
+ }
+ }
+ " SWI_HAS_PL_NIL)
+
+ check_cxx_source_compiles("
+ #include <SWI-Prolog.h>
+ int main(){
+ int a = 0;
+ switch(a) {
+ case PL_DICT:
+ break;
+ }
+ }
+ " SWI_HAS_PL_DICT)
+
+ check_cxx_source_compiles("
+ #include <SWI-Prolog.h>
+ 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 <list>
#include <SWI-cpp.h>
+#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
--- /dev/null
+++ b/src/uscxml/plugins/invoker/im/IMConfig.h.in
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 <uscxml/Interpreter.h>
extern "C" {
-#include <libpurple/purple.h>
+#include <purple.h>
}
+#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 <http://www.opensource.org/licenses/bsd-license>.
+ * @endcond
+ */
+
+#include "IMAPInvoker.h"
+#include <glog/logging.h>
+
+#ifdef BUILD_AS_PLUGINS
+#include <Pluma/Connector.hpp>
+#endif
+
+#include <boost/algorithm/string.hpp>
+#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<InvokerImpl> IMAPInvoker::create(InterpreterImpl* interpreter) {
+ boost::shared_ptr<IMAPInvoker> invoker = boost::shared_ptr<IMAPInvoker>(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<std::string> IMAPInvoker::getAtoms(std::list<Data> list) {
+ std::list<std::string> atoms;
+
+ std::list<Data>::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<Data>::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<Data> list, std::list<Data>& attachments) {
+ // accumulate attachments with filename, mimetype and data
+ std::list<Data>::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<std::string, Data>::const_iterator compIter = data.compound.begin();
+ while(compIter != data.compound.end()) {
+ std::list<Data> 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<Data> headerParams;
+ std::list<Data> toParams;
+ std::list<Data> ccParams;
+ std::list<Data> bccParams;
+ std::list<Data> 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<std::string>::const_iterator recIter;
+ std::list<std::string> to = getAtoms(toParams);
+ std::list<std::string> cc = getAtoms(ccParams);
+ std::list<std::string> bcc = getAtoms(bccParams);
+ std::list<std::string> headers = getAtoms(headerParams);
+ std::list<Data> 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<Data>::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 <http://www.opensource.org/licenses/bsd-license>.
+ * @endcond
+ */
+
+#ifndef IMAPINVOKER_H_W09JFED0
+#define IMAPINVOKER_H_W09JFED0
+
+#include <uscxml/Interpreter.h>
+
+#ifdef BUILD_AS_PLUGINS
+#include "uscxml/plugins/Plugins.h"
+#endif
+
+#include <curl/curl.h>
+
+namespace uscxml {
+
+class IMAPInvoker : public InvokerImpl {
+public:
+ IMAPInvoker();
+ virtual ~IMAPInvoker();
+ virtual boost::shared_ptr<InvokerImpl> create(InterpreterImpl* interpreter);
+
+ virtual std::set<std::string> getNames() {
+ std::set<std::string> 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<std::string> getAtoms(std::list<Data> list);
+ void getAttachments(std::list<Data> list, std::list<Data>& 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<std::string> getAtoms(std::list<Data> list);
void getAttachments(std::list<Data> list, std::list<Data>& 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 @@
<state id="main">
<invoke type="smtp" id="smtp">
+ <param name="ssl" expr="'true'" />
<param name="username" expr="'username'" />
<param name="password" expr="'password'" />
<param name="server" expr="'smtp://example.com:587'" />
</invoke>
<transition event="invoke.success.smtp">
- <file operation="read"
- sandbox="off"
- url="file:///Users/sradomski/Documents/TK/Presentations/umundo/umundo-techtalk.pdf"
- callback="file.load.success"
- type="binary"
- mimetype="application/pdf"
+ <file
+ operation="read"
+ sandbox="off"
+ url="file:///Users/sradomski/Documents/TK/Presentations/umundo/umundo-techtalk.pdf"
+ callback="file.load.success"
+ type="binary"
+ mimetype="application/pdf"
/>
</transition>