summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorStefan Radomski <radomski@tk.informatik.tu-darmstadt.de>2013-10-07 23:13:54 (GMT)
committerStefan Radomski <radomski@tk.informatik.tu-darmstadt.de>2013-10-07 23:13:54 (GMT)
commit36b5c7614cc896d043ddeebae1cdb4e8e94afe18 (patch)
treee14ac52189363b252aa8ea10fdd66efef069d665 /src
parent567df9318fff6d1bb570191c33ea68cd6ef88bee (diff)
downloaduscxml-36b5c7614cc896d043ddeebae1cdb4e8e94afe18.zip
uscxml-36b5c7614cc896d043ddeebae1cdb4e8e94afe18.tar.gz
uscxml-36b5c7614cc896d043ddeebae1cdb4e8e94afe18.tar.bz2
Reduced compile times
- new commandline argument handling - compiles on windows again
Diffstat (limited to 'src')
-rw-r--r--src/bindings/swig/php/uscxmlNativePHP.php68
-rw-r--r--src/uscxml/Interpreter.cpp167
-rw-r--r--src/uscxml/Interpreter.h47
-rw-r--r--src/uscxml/concurrency/eventqueue/DelayedEventQueue.cpp12
-rw-r--r--src/uscxml/concurrency/eventqueue/DelayedEventQueue.h6
-rw-r--r--src/uscxml/pch.h14
-rw-r--r--src/uscxml/plugins/datamodel/CMakeLists.txt106
-rw-r--r--src/uscxml/plugins/datamodel/ecmascript/TypedArray.h1
-rw-r--r--src/uscxml/plugins/datamodel/ecmascript/v8/V8DOM.h1
-rw-r--r--src/uscxml/plugins/invoker/im/IMInvoker.cpp412
-rw-r--r--src/uscxml/plugins/invoker/im/IMInvoker.h46
-rw-r--r--src/uscxml/server/HTTPServer.cpp162
-rw-r--r--src/uscxml/server/HTTPServer.h21
13 files changed, 813 insertions, 250 deletions
diff --git a/src/bindings/swig/php/uscxmlNativePHP.php b/src/bindings/swig/php/uscxmlNativePHP.php
index 668e01b..dccfbaf 100644
--- a/src/bindings/swig/php/uscxmlNativePHP.php
+++ b/src/bindings/swig/php/uscxmlNativePHP.php
@@ -2,7 +2,7 @@
/* ----------------------------------------------------------------------------
* This file was automatically generated by SWIG (http://www.swig.org).
- * Version 2.0.7
+ * Version 2.0.9
*
* This file is not intended to be easily readable and contains a number of
* coding conventions designed to improve portability and efficiency. Do not make
@@ -226,6 +226,42 @@ class Params {
}
}
+class Blob {
+ public $_cPtr=null;
+ protected $_pData=array();
+
+ function __set($var,$value) {
+ $func = 'Blob_'.$var.'_set';
+ if (function_exists($func)) return call_user_func($func,$this->_cPtr,$value);
+ if ($var === 'thisown') return swig_uscxmlNativePHP_alter_newobject($this->_cPtr,$value);
+ $this->_pData[$var] = $value;
+ }
+
+ function __isset($var) {
+ if (function_exists('Blob_'.$var.'_set')) return true;
+ if ($var === 'thisown') return true;
+ return array_key_exists($var, $this->_pData);
+ }
+
+ function __get($var) {
+ $func = 'Blob_'.$var.'_get';
+ if (function_exists($func)) return call_user_func($func,$this->_cPtr);
+ if ($var === 'thisown') return swig_uscxmlNativePHP_get_newobject($this->_cPtr);
+ return $this->_pData[$var];
+ }
+
+ function __construct($size_or_data,$size=null,$adopt=false) {
+ if (is_resource($size_or_data) && get_resource_type($size_or_data) === '_p_uscxml__Blob') {
+ $this->_cPtr=$size_or_data;
+ return;
+ }
+ switch (func_num_args()) {
+ case 1: $this->_cPtr=new_Blob($size_or_data); break;
+ default: $this->_cPtr=new_Blob($size_or_data,$size,$adopt);
+ }
+ }
+}
+
class Data {
public $_cPtr=null;
protected $_pData=array();
@@ -254,17 +290,16 @@ class Data {
const INTERPRETED = Data_INTERPRETED;
- const BINARY = Data_BINARY;
-
- function __construct($atom__or_dom=null,$type_=null) {
- if (is_resource($atom__or_dom) && get_resource_type($atom__or_dom) === '_p_uscxml__Data') {
- $this->_cPtr=$atom__or_dom;
+ function __construct($atom__or_data_or_dom=null,$type__or_size=null,$adopt=null) {
+ if (is_resource($atom__or_data_or_dom) && get_resource_type($atom__or_data_or_dom) === '_p_uscxml__Data') {
+ $this->_cPtr=$atom__or_data_or_dom;
return;
}
switch (func_num_args()) {
case 0: $this->_cPtr=new_Data(); break;
- case 1: $this->_cPtr=new_Data($atom__or_dom); break;
- default: $this->_cPtr=new_Data($atom__or_dom,$type_);
+ case 1: $this->_cPtr=new_Data($atom__or_data_or_dom); break;
+ case 2: $this->_cPtr=new_Data($atom__or_data_or_dom,$type__or_size); break;
+ default: $this->_cPtr=new_Data($atom__or_data_or_dom,$type__or_size,$adopt);
}
}
@@ -359,7 +394,6 @@ class Event {
}
function __get($var) {
- if ($var === 'namelist') return new StringMap(Event_namelist_get($this->_cPtr));
if ($var === 'data') return new Data(Event_data_get($this->_cPtr));
$func = 'Event_'.$var.'_get';
if (function_exists($func)) return call_user_func($func,$this->_cPtr);
@@ -502,18 +536,16 @@ class Event {
}
function getNameList() {
- $r=Event_getNameList($this->_cPtr);
- if (is_resource($r)) {
- $c=substr(get_resource_type($r), (strpos(get_resource_type($r), '__') ? strpos(get_resource_type($r), '__') + 2 : 3));
- if (class_exists($c)) return new $c($r);
- return new StringMap($r);
- }
- return $r;
+ return Event_getNameList($this->_cPtr);
}
function getParams() {
return Event_getParams($this->_cPtr);
}
+
+ static function getParam($params,$name,$target) {
+ return Event_getParam($params,$name,$target);
+ }
}
class InvokeRequest extends Event {
@@ -980,10 +1012,6 @@ class Interpreter {
return Interpreter_getProperAncestors($this->_cPtr,$s1,$s2);
}
- static function getUUID() {
- return Interpreter_getUUID();
- }
-
function getImpl() {
return Interpreter_getImpl($this->_cPtr);
}
diff --git a/src/uscxml/Interpreter.cpp b/src/uscxml/Interpreter.cpp
index 7e61ed7..065b61e 100644
--- a/src/uscxml/Interpreter.cpp
+++ b/src/uscxml/Interpreter.cpp
@@ -1,3 +1,4 @@
+#include "uscxml/config.h"
#include "uscxml/Common.h"
#include "uscxml/Interpreter.h"
#include "uscxml/URL.h"
@@ -40,6 +41,145 @@ namespace uscxml {
using namespace Arabica::XPath;
using namespace Arabica::DOM;
+void InterpreterOptions::printUsageAndExit(const char* progName) {
+ printf("%s version " USCXML_VERSION " (" CMAKE_BUILD_TYPE " build - " CMAKE_COMPILER_STRING ")\n", progName);
+ printf("Usage\n");
+ printf("\t%s", progName);
+#ifdef BUILD_AS_PLUGINS
+ printf(" [-e pluginPath]");
+#endif
+ printf("[-v] [-pN] URL\n");
+ printf("\n");
+ printf("Options\n");
+ printf("\t-v : be verbose\n");
+ printf("\t-pN : port for HTTP server\n");
+ printf("\t-d : write each configuration as a dot file\n");
+ printf("\n");
+ exit(1);
+}
+
+unsigned int InterpreterOptions::getCapabilities() {
+ unsigned int capabilities = CAN_NOTHING;
+ if (withHTTP)
+ capabilities = capabilities | CAN_GENERIC_HTTP | CAN_BASIC_HTTP;
+
+ return capabilities;
+}
+
+InterpreterOptions InterpreterOptions::fromCmdLine(int argc, char** argv) {
+ InterpreterOptions options;
+ struct option longOptions[] = {
+ {"verbose", no_argument, 0, 'v'},
+ {"dot", no_argument, 0, 'd'},
+ {"port", required_argument, 0, 't'},
+ {"ssl-port", required_argument, 0, 's'},
+ {"certificate", required_argument, 0, 'c'},
+ {"private-key", required_argument, 0, 0},
+ {"public-key", required_argument, 0, 0},
+ {"plugin-path", required_argument, 0, 'p'},
+ {"loglevel", required_argument, 0, 'l'},
+ {"disable-http", no_argument, 0, 0},
+ {0, 0, 0, 0}
+ };
+
+ opterr = 0;
+ if (argc < 2) {
+ options.error = "No SCXML document to evaluate";
+ return options;
+ }
+
+ InterpreterOptions* currOptions = &options;
+
+ // parse global options
+ int optionInd = 0;
+ int option;
+ for (;;) {
+ option = getopt_long_only(argc, argv, "+vdt:s:c:p:l:", longOptions, &optionInd);
+ if (option == -1) {
+ if (optind == argc)
+ // we are done with parsing
+ goto DONE_PARSING_CMD;
+
+ std::string url = argv[optind];
+ options.interpreters[url] = new InterpreterOptions();
+ currOptions = options.interpreters[url];
+
+ argc -= optind;
+ argv += optind;
+ optind = 0;
+
+ if (argc <= 1)
+ goto DONE_PARSING_CMD;
+
+ }
+ switch(option) {
+ // cases without short option
+ case 0: {
+ if (boost::equals(longOptions[optionInd].name, "disable-http")) {
+ currOptions->withHTTP = false;
+ } else if (boost::equals(longOptions[optionInd].name, "private-key")) {
+ currOptions->privateKey = optarg;
+ } else if (boost::equals(longOptions[optionInd].name, "public-key")) {
+ currOptions->publicKey = optarg;
+ }
+ break;
+ }
+ // cases with short-hand options
+ case 'l':
+ currOptions->logLevel = strTo<unsigned int>(optarg);
+ break;
+ case 'p':
+ currOptions->pluginPath = optarg;
+ break;
+ case 'd':
+ currOptions->useDot = true;
+ break;
+ case 'c':
+ currOptions->certificate = optarg;
+ break;
+ case 't':
+ currOptions->httpPort = strTo<unsigned short>(optarg);
+ break;
+ case 's':
+ currOptions->httpsPort = strTo<unsigned short>(optarg);
+ break;
+ case 'v':
+ currOptions->verbose = true;
+ break;
+ case '?': {
+ std::string param = argv[optind - 1];
+ if (boost::starts_with(param, "--")) {
+ param = param.substr(2, param.length() - 2);
+ } else if (boost::starts_with(param, "-")) {
+ param = param.substr(1, param.length() - 1);
+ } else {
+ break;
+ }
+ boost::trim(param);
+
+ size_t equalPos = param.find("=");
+ if (equalPos != std::string::npos) {
+ std::string key = param.substr(0, equalPos);
+ std::string value = param.substr(equalPos + 1, param.length() - (equalPos + 1));
+ currOptions->additionalParameters[key] = value;
+ } else {
+ currOptions->additionalParameters[param] = "";
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+DONE_PARSING_CMD:
+
+ if (options.interpreters.size() == 0)
+ options.error = "No SCXML document to evaluate";
+
+ return options;
+}
+
std::map<std::string, boost::weak_ptr<InterpreterImpl> > Interpreter::_instances;
tthread::recursive_mutex Interpreter::_instanceMutex;
@@ -1761,26 +1901,15 @@ IOProcessor InterpreterImpl::getIOProcessor(const std::string& type) {
return _ioProcessors[type];
}
-void InterpreterImpl::setCmdLineOptions(int argc, char** argv) {
- char* key = NULL;
- char* value = NULL;
- for (int i = 0; i < argc; i++) {
- if (false) {
- } else if (strlen(argv[i]) > 2 && strncmp(&argv[i][0], "-", 1) == 0 && strncmp(&argv[i][1], "-", 1) == 0) {
- // longopt
- key = &argv[i][2];
- } else if (strlen(argv[i]) > 1 && strncmp(&argv[i][0], "-", 1) == 0 && strncmp(&argv[i][1], "-", 1) != 0) {
- // shortopt
- key = &argv[i][1];
- }
- if (key != NULL) {
- if (i + 1 < argc && strncmp(&argv[i + 1][0], "-", 1) != 0) {
- value = argv[++i];
- _cmdLineOptions.compound[key] = Data(value, Data::VERBATIM);
- } else {
- _cmdLineOptions.compound[key] = Data("true");
- }
+void InterpreterImpl::setCmdLineOptions(std::map<std::string, std::string> params) {
+ std::map<std::string, std::string>::iterator paramIter = params.begin();
+ while (paramIter != params.end()) {
+ if (paramIter->second.length() > 0) {
+ _cmdLineOptions.compound[paramIter->first] = Data(paramIter->second, Data::VERBATIM);
+ } else {
+ _cmdLineOptions.compound[paramIter->first] = Data("true");
}
+ paramIter++;
}
}
diff --git a/src/uscxml/Interpreter.h b/src/uscxml/Interpreter.h
index aadef72..b8093ab 100644
--- a/src/uscxml/Interpreter.h
+++ b/src/uscxml/Interpreter.h
@@ -1,7 +1,10 @@
#ifndef RUNTIME_H_SQ1MBKGN
#define RUNTIME_H_SQ1MBKGN
+// this has to be the first include or MSVC will run amok
#include "uscxml/Common.h"
+#include "getopt.h"
+
#include "uscxml/URL.h"
#include <boost/algorithm/string.hpp>
@@ -61,6 +64,44 @@ enum Capabilities {
CAN_GENERIC_HTTP = 2,
};
+class InterpreterOptions {
+public:
+ bool useDot;
+ bool verbose;
+ bool withHTTP;
+ bool withHTTPS;
+ int logLevel;
+ unsigned short httpPort;
+ unsigned short httpsPort;
+ std::string pluginPath;
+ std::string certificate;
+ std::string privateKey;
+ std::string publicKey;
+ std::map<std::string, InterpreterOptions*> interpreters;
+ std::map<std::string, std::string> additionalParameters;
+
+ std::string error;
+
+ operator bool() {
+ return error.length() == 0;
+ }
+
+ static void printUsageAndExit(const char* progName);
+ static InterpreterOptions fromCmdLine(int argc, char** argv);
+ unsigned int getCapabilities();
+
+protected:
+ InterpreterOptions() :
+ useDot(false),
+ verbose(false),
+ withHTTP(true),
+ withHTTPS(true),
+ logLevel(0),
+ httpPort(8080),
+ httpsPort(8443)
+ {}
+};
+
class InterpreterImpl : public boost::enable_shared_from_this<InterpreterImpl> {
public:
@@ -100,7 +141,7 @@ public:
return _baseURI;
}
- void setCmdLineOptions(int argc, char** argv);
+ void setCmdLineOptions(std::map<std::string, std::string> params);
Data getCmdLineOptions() {
return _cmdLineOptions;
}
@@ -400,8 +441,8 @@ public:
return _impl->getNameSpaceInfo();
}
- void setCmdLineOptions(int argc, char** argv) {
- return _impl->setCmdLineOptions(argc, argv);
+ void setCmdLineOptions(std::map<std::string, std::string> params) {
+ return _impl->setCmdLineOptions(params);
}
Data getCmdLineOptions() {
return _impl->getCmdLineOptions();
diff --git a/src/uscxml/concurrency/eventqueue/DelayedEventQueue.cpp b/src/uscxml/concurrency/eventqueue/DelayedEventQueue.cpp
index cbb82eb..fe16361 100644
--- a/src/uscxml/concurrency/eventqueue/DelayedEventQueue.cpp
+++ b/src/uscxml/concurrency/eventqueue/DelayedEventQueue.cpp
@@ -26,14 +26,12 @@ DelayedEventQueue::~DelayedEventQueue() {
}
void DelayedEventQueue::run(void* instance) {
- DelayedEventQueue* THIS = (DelayedEventQueue*)instance;
+ DelayedEventQueue* INSTANCE = (DelayedEventQueue*)instance;
int result;
- while(THIS->_isStarted) {
- {
- //result = event_base_dispatch(THIS->_eventLoop);
- result = event_base_loop(THIS->_eventLoop, EVLOOP_NO_EXIT_ON_EMPTY);
- (void)result;
- }
+ while(INSTANCE->_isStarted) {
+ //result = event_base_dispatch(THIS->_eventLoop);
+ result = event_base_loop(INSTANCE->_eventLoop, EVLOOP_NO_EXIT_ON_EMPTY);
+ (void)result;
}
}
diff --git a/src/uscxml/concurrency/eventqueue/DelayedEventQueue.h b/src/uscxml/concurrency/eventqueue/DelayedEventQueue.h
index 0b72719..fa76c3f 100644
--- a/src/uscxml/concurrency/eventqueue/DelayedEventQueue.h
+++ b/src/uscxml/concurrency/eventqueue/DelayedEventQueue.h
@@ -19,9 +19,9 @@ class DelayedEventQueue {
public:
enum OpMask {
- FD_READ = EV_READ,
- FD_WRITE = EV_WRITE,
- FD_SIGNAL = EV_SIGNAL
+ DEQ_READ = EV_READ,
+ DEQ_WRITE = EV_WRITE,
+ DEQ_SIGNAL = EV_SIGNAL
};
struct callbackData {
diff --git a/src/uscxml/pch.h b/src/uscxml/pch.h
new file mode 100644
index 0000000..e4ae2d1
--- /dev/null
+++ b/src/uscxml/pch.h
@@ -0,0 +1,14 @@
+#include "uscxml/Common.h"
+
+#include <boost/algorithm/string.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/lexical_cast.hpp>
+
+#include <iostream>
+#include <set>
+#include <map>
+#include <list>
+#include <vector>
+#include <string>
+
+#include <DOM/Document.hpp> \ No newline at end of file
diff --git a/src/uscxml/plugins/datamodel/CMakeLists.txt b/src/uscxml/plugins/datamodel/CMakeLists.txt
index 5fe82b7..3b6a852 100644
--- a/src/uscxml/plugins/datamodel/CMakeLists.txt
+++ b/src/uscxml/plugins/datamodel/CMakeLists.txt
@@ -1,63 +1,65 @@
-if (JSC_FOUND AND BUILD_DM_ECMA)
- set(USCXML_DATAMODELS "ecmascript(JSC) ${USCXML_DATAMODELS}")
- # JavaScriptCore ecmascript datamodel
- file(GLOB JSC_DATAMODEL
- ecmascript/JavaScriptCore/*.cpp
- ecmascript/JavaScriptCore/*.h
- ecmascript/*.cpp
- ecmascript/*.h
- )
- source_group("Datamodel\\jsc" FILES ${JSC_DATAMODEL})
- file(GLOB_RECURSE JSC_DOM
- ecmascript/JavaScriptCore/dom/*.cpp
- ecmascript/JavaScriptCore/dom/*.h
- )
- source_group("Datamodel\\DOM" FILES ${JSC_DOM})
- if (BUILD_AS_PLUGINS)
- add_library(
- datamodel_jsc SHARED
- ${JSC_DATAMODEL}
- ${JSC_DOM})
- target_link_libraries(datamodel_jsc
- uscxml
- ${JSC_LIBRARY})
- set_target_properties(datamodel_jsc PROPERTIES FOLDER "Plugin DataModel")
- else()
- list (APPEND USCXML_FILES ${JSC_DATAMODEL})
- list (APPEND USCXML_FILES ${JSC_DOM})
- list (APPEND USCXML_OPT_LIBS ${JSC_LIBRARY})
- endif()
-else()
-
-# GOOGLE V8 ecmascript datamodel
- set(USCXML_DATAMODELS "ecmascript(V8) ${USCXML_DATAMODELS}")
- # set(ENV{V8_SRC} ${CMAKE_SOURCE_DIR}/../v8)
- if (V8_FOUND AND BUILD_DM_ECMA)
- file(GLOB V8_DATAMODEL
- ecmascript/v8/*.cpp
- ecmascript/v8/*.h
+if (BUILD_DM_ECMA)
+ if (JSC_FOUND)
+ set(USCXML_DATAMODELS "ecmascript(JSC) ${USCXML_DATAMODELS}")
+ # JavaScriptCore ecmascript datamodel
+ file(GLOB JSC_DATAMODEL
+ ecmascript/JavaScriptCore/*.cpp
+ ecmascript/JavaScriptCore/*.h
ecmascript/*.cpp
ecmascript/*.h
)
- source_group("Datamodel\\v8" FILES ${V8_DATAMODEL})
- file(GLOB_RECURSE V8_DOM
- ecmascript/v8/dom/*.cpp
- ecmascript/v8/dom/*.h
+ source_group("Datamodel\\jsc" FILES ${JSC_DATAMODEL})
+ file(GLOB_RECURSE JSC_DOM
+ ecmascript/JavaScriptCore/dom/*.cpp
+ ecmascript/JavaScriptCore/dom/*.h
)
- source_group("Datamodel\\v8\\DOM" FILES ${V8_DOM})
-
+ source_group("Datamodel\\DOM" FILES ${JSC_DOM})
if (BUILD_AS_PLUGINS)
add_library(
- datamodel_v8 SHARED
- ${V8_DATAMODEL}
- ${V8_DOM})
- target_link_libraries(datamodel_v8
+ datamodel_jsc SHARED
+ ${JSC_DATAMODEL}
+ ${JSC_DOM})
+ target_link_libraries(datamodel_jsc
uscxml
- ${V8_LIBRARY})
- set_target_properties(datamodel_v8 PROPERTIES FOLDER "Plugin DataModel")
+ ${JSC_LIBRARY})
+ set_target_properties(datamodel_jsc PROPERTIES FOLDER "Plugin DataModel")
else()
- list (APPEND USCXML_FILES ${V8_DATAMODEL})
- list (APPEND USCXML_FILES ${V8_DOM})
+ list (APPEND USCXML_FILES ${JSC_DATAMODEL})
+ list (APPEND USCXML_FILES ${JSC_DOM})
+ list (APPEND USCXML_OPT_LIBS ${JSC_LIBRARY})
+ endif()
+ else()
+
+ # GOOGLE V8 ecmascript datamodel
+ set(USCXML_DATAMODELS "ecmascript(V8) ${USCXML_DATAMODELS}")
+ # set(ENV{V8_SRC} ${CMAKE_SOURCE_DIR}/../v8)
+ if (V8_FOUND AND BUILD_DM_ECMA)
+ file(GLOB V8_DATAMODEL
+ ecmascript/v8/*.cpp
+ ecmascript/v8/*.h
+ ecmascript/*.cpp
+ ecmascript/*.h
+ )
+ source_group("Datamodel\\v8" FILES ${V8_DATAMODEL})
+ file(GLOB_RECURSE V8_DOM
+ ecmascript/v8/dom/*.cpp
+ ecmascript/v8/dom/*.h
+ )
+ source_group("Datamodel\\v8\\DOM" FILES ${V8_DOM})
+
+ if (BUILD_AS_PLUGINS)
+ add_library(
+ datamodel_v8 SHARED
+ ${V8_DATAMODEL}
+ ${V8_DOM})
+ target_link_libraries(datamodel_v8
+ uscxml
+ ${V8_LIBRARY})
+ set_target_properties(datamodel_v8 PROPERTIES FOLDER "Plugin DataModel")
+ else()
+ list (APPEND USCXML_FILES ${V8_DATAMODEL})
+ list (APPEND USCXML_FILES ${V8_DOM})
+ endif()
endif()
endif()
endif()
diff --git a/src/uscxml/plugins/datamodel/ecmascript/TypedArray.h b/src/uscxml/plugins/datamodel/ecmascript/TypedArray.h
index 460afd4..e7d7e4c 100644
--- a/src/uscxml/plugins/datamodel/ecmascript/TypedArray.h
+++ b/src/uscxml/plugins/datamodel/ecmascript/TypedArray.h
@@ -1,6 +1,7 @@
#ifndef TYPEDARRAY_H_99815BLY
#define TYPEDARRAY_H_99815BLY
+#include "uscxml/Common.h"
#include "uscxml/Message.h"
#include <string>
diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DOM.h b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DOM.h
index 43b98ce..f35b13f 100644
--- a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DOM.h
+++ b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DOM.h
@@ -1,6 +1,7 @@
#ifndef V8DOM_H_LKE1HKJK
#define V8DOM_H_LKE1HKJK
+#include "uscxml/Common.h"
#include "uscxml/Interpreter.h"
#include <v8.h>
#include <XPath/XPath.hpp>
diff --git a/src/uscxml/plugins/invoker/im/IMInvoker.cpp b/src/uscxml/plugins/invoker/im/IMInvoker.cpp
index cff9b5f..1e12650 100644
--- a/src/uscxml/plugins/invoker/im/IMInvoker.cpp
+++ b/src/uscxml/plugins/invoker/im/IMInvoker.cpp
@@ -7,12 +7,13 @@
#endif
#define GET_INSTANCE_IN_CALLBACK(account) \
-tthread::lock_guard<tthread::mutex> lock(_accountMutex); \
+tthread::lock_guard<tthread::recursive_mutex> lock(_accountMutex); \
+IMInvoker* inst = NULL;\
if (_accountInstances.find(account) == _accountInstances.end()) { \
LOG(ERROR) << "Callback for unknown account called"; \
- return; \
-} \
-IMInvoker* inst = _accountInstances[account];\
+} else {\
+ inst = _accountInstances[account];\
+}
namespace uscxml {
@@ -35,13 +36,19 @@ PurpleEventLoopUiOps IMInvoker::_uiEventLoopOps =
purpleEventTimeoutRemove,
purpleEventInputAdd,
purpleEventInputRemove,
- NULL, //purpleEventInputGetError,
+ purpleEventInputGetError,
purpleEventTimeoutAddSec,
NULL,
NULL,
NULL
};
-
+
+PurpleDebugUiOps IMInvoker::_uiDebugOps = {
+ purpleDebugPrint,
+ purpleDebugIsEnabled,
+ NULL, NULL, NULL, NULL
+};
+
PurpleAccountUiOps IMInvoker::_uiAccountOps = {
accountNotifyAdded,
accountStatusChanged,
@@ -181,7 +188,7 @@ PurpleWhiteboardUiOps IMInvoker::_uiWhiteboardOps = {
};
PurpleCoreUiOps IMInvoker::_uiCoreOps = {
- NULL,
+ purplePrefsInit,
NULL,
purpleUIInit,
NULL,
@@ -196,9 +203,39 @@ DelayedEventQueue* IMInvoker::_eventQueue = NULL;
tthread::mutex IMInvoker::_initMutex;
tthread::condition_variable IMInvoker::_initCond;
-tthread::mutex IMInvoker::_accountMutex;
+tthread::recursive_mutex IMInvoker::_accountMutex;
std::map<PurpleAccount*, IMInvoker*> IMInvoker::_accountInstances;
+
+void IMInvoker::setupPurpleSignals() {
+ int handle;
+ // connection signals
+ purple_signal_connect(purple_connections_get_handle(), "signed-on", &handle, PURPLE_CALLBACK(signedOnCB), NULL);
+
+ // conversation signals
+ purple_signal_connect(purple_conversations_get_handle(), "conversation-created", &handle, PURPLE_CALLBACK(conversationCreatedCB), NULL);
+ purple_signal_connect(purple_conversations_get_handle(), "chat-joined", &handle, PURPLE_CALLBACK(chatJoinedCB), NULL);
+ purple_signal_connect(purple_conversations_get_handle(), "chat-join-failed", &handle, PURPLE_CALLBACK(chatJoinFailedCB), NULL);
+ purple_signal_connect(purple_conversations_get_handle(), "buddy-typing", &handle, PURPLE_CALLBACK(buddyTypingCB), NULL);
+ purple_signal_connect(purple_conversations_get_handle(), "buddy-typed", &handle, PURPLE_CALLBACK(buddyTypedCB), NULL);
+ purple_signal_connect(purple_conversations_get_handle(), "buddy-typing-stopped", &handle, PURPLE_CALLBACK(buddyTypingStoppedCB), NULL);
+
+ // buddy signals
+ purple_signal_connect(purple_blist_get_handle(), "buddy-signed-on", &handle, PURPLE_CALLBACK(buddyEventCB), GINT_TO_POINTER(PURPLE_BUDDY_SIGNON));
+ purple_signal_connect(purple_blist_get_handle(), "buddy-signed-off", &handle, PURPLE_CALLBACK(buddyEventCB), GINT_TO_POINTER(PURPLE_BUDDY_SIGNOFF));
+ purple_signal_connect(purple_blist_get_handle(), "buddy-got-login-time", &handle, PURPLE_CALLBACK(buddyEventCB), GINT_TO_POINTER(PURPLE_BUDDY_SIGNON_TIME));
+ purple_signal_connect(purple_blist_get_handle(), "buddy-idle-changed", &handle, PURPLE_CALLBACK(buddyIdleChangedCB), NULL);
+ purple_signal_connect(purple_blist_get_handle(), "buddy-status-changed", &handle, PURPLE_CALLBACK(buddyStatusChangedCB), NULL);
+ purple_signal_connect(purple_blist_get_handle(), "buddy-icon-changed", &handle, PURPLE_CALLBACK(buddyEventCB), GINT_TO_POINTER(PURPLE_BUDDY_ICON));
+ purple_signal_connect(purple_blist_get_handle(), "buddy-added", &handle, PURPLE_CALLBACK(buddyAddedCB), NULL);
+ purple_signal_connect(purple_blist_get_handle(), "buddy-removed", &handle, PURPLE_CALLBACK(buddyRemovedCB), NULL);
+ purple_signal_connect(purple_blist_get_handle(), "blist-node-aliased", &handle, PURPLE_CALLBACK(blistNodeAliasedCB), NULL);
+ purple_signal_connect(purple_blist_get_handle(), "buddy-caps-changed", &handle, PURPLE_CALLBACK(buddyCapsChangedCB), NULL);
+
+ // xfer signals
+ purple_signal_connect(purple_xfers_get_handle(), "file-recv-request", &handle, PURPLE_CALLBACK(fileRecvRequestCB), NULL);
+}
+
void IMInvoker::initLibPurple(void *userdata, const std::string event) {
_initMutex.lock();
@@ -218,7 +255,6 @@ void IMInvoker::initLibPurple(void *userdata, const std::string event) {
purple_debug_set_enabled(false);
purple_core_set_ui_ops(&_uiCoreOps);
-// purple_eventloop_set_ui_ops(&glib_eventloops);
purple_eventloop_set_ui_ops(&_uiEventLoopOps);
purple_plugins_add_search_path("/usr/local/lib/purple-3");
@@ -257,64 +293,153 @@ void IMInvoker::initLibPurple(void *userdata, const std::string event) {
_initMutex.unlock();
_initCond.notify_all();
+}
+// purple event callbacks
+void IMInvoker::signedOnCB(PurpleConnection *gc, gpointer null) {
+ PurpleAccount *account = purple_connection_get_account(gc);
+ GET_INSTANCE_IN_CALLBACK(account);
+ if (!inst)
+ return;
+
+#if 0
+ GSList *buddies = purple_find_buddies(purple_connection_get_account(gc), NULL);
+ GSList *cur;
+ for (cur = buddies; cur; cur = cur->next) {
+ buddyAddedCB((PurpleBuddy *)cur->data);
+ }
+ g_slist_free(buddies);
+#endif
+
+ // set my status to active
+ PurpleSavedStatus* status = purple_savedstatus_new(NULL, PURPLE_STATUS_AVAILABLE);
+ purple_savedstatus_activate(status);
+
+ Event retEv("im.signed.on");
+ inst->returnEvent(retEv);
}
-void IMInvoker::buddyStatusChangedCB(PurpleBuddy *buddy, PurpleStatus *old, PurpleStatus *newstatus) {
+void IMInvoker::conversationCreatedCB(PurpleConversation *conv, void *data) {}
+void IMInvoker::chatJoinedCB(PurpleConversation *conv, void *data) {}
+void IMInvoker::chatJoinFailedCB(PurpleConnection *gc, GHashTable *components) {}
+void IMInvoker::buddyTypingCB(PurpleAccount *account, const char *name, void *data) {}
+void IMInvoker::buddyTypedCB(PurpleAccount *account, const char *name, void *data) {}
+void IMInvoker::buddyTypingStoppedCB(PurpleAccount *account, const char *name, void *data) {}
+
+void IMInvoker::buddyEventCB(PurpleBuddy *buddy, PurpleBuddyEvent event) {
+ if (!buddy)
+ return;
+
PurpleAccount *account = purple_buddy_get_account(buddy);
GET_INSTANCE_IN_CALLBACK(account);
+ if (!inst)
+ return;
+
+ switch (event) {
+ case PURPLE_BUDDY_SIGNOFF:
+ case PURPLE_BUDDY_SIGNON: {
+ PurplePresence* presence = purple_buddy_get_presence(buddy);
+ PurpleStatus* status = purple_presence_get_active_status(presence);
+ buddyStatusChangedCB(buddy, NULL, status, event);
+ break;
+ }
+ case PURPLE_BUDDY_ICON:
+ break;
+
+ default:
+ break;
+ }
- std::string buddyName = purple_buddy_get_name(buddy);
- inst->_dataModelVars.compound["buddies"].compound[buddyName] = buddyToData(buddy);
}
-void IMInvoker::buddyIdleChangeCB(PurpleBuddy *buddy, gboolean old_idle, gboolean idle) {
+void IMInvoker::buddyIdleChangedCB(PurpleBuddy *buddy, gboolean old_idle, gboolean idle, PurpleBuddyEvent event) {
+}
+
+void IMInvoker::buddyStatusChangedCB(PurpleBuddy *buddy, PurpleStatus *old, PurpleStatus *newstatus, PurpleBuddyEvent event) {
PurpleAccount *account = purple_buddy_get_account(buddy);
GET_INSTANCE_IN_CALLBACK(account);
-}
+
+ std::string buddyName = purple_buddy_get_name(buddy);
+ Data buddyData = buddyToData(buddy);
+ inst->_dataModelVars.compound["buddies"].compound[buddyName] = buddyData;
+
+ Event retEv("im.buddy.status.changed");
+ retEv.data = buddyData;
+ inst->returnEvent(retEv);
-void IMInvoker::buddyUpdateIdleCB() {
}
void IMInvoker::buddyAddedCB(PurpleBuddy* buddy) {
PurpleAccount *account = purple_buddy_get_account(buddy);
GET_INSTANCE_IN_CALLBACK(account);
+ if (!inst)
+ return;
+
+ std::string buddyName = purple_buddy_get_name(buddy);
+
+ Event retEv("im.buddy.added");
+ retEv.data.compound["name"] = Data(buddyName, Data::VERBATIM);
+ inst->returnEvent(retEv);
+
+ buddyStatusChangedCB(buddy, NULL, purple_presence_get_active_status(purple_buddy_get_presence(buddy)), PURPLE_BUDDY_NONE);
+
}
void IMInvoker::buddyRemovedCB(PurpleBuddy* buddy) {
PurpleAccount *account = purple_buddy_get_account(buddy);
GET_INSTANCE_IN_CALLBACK(account);
+ std::string buddyName = purple_buddy_get_name(buddy);
+
+ Event retEv("im.buddy.removed");
+ retEv.data.compound["name"] = Data(buddyName, Data::VERBATIM);
+ inst->returnEvent(retEv);
+
+ inst->_dataModelVars.compound["buddies"].compound.erase(buddyName);
+
}
-void IMInvoker::buddyCapsChangedCB(PurpleBuddy* buddy, PurpleMediaCaps newcaps, PurpleMediaCaps oldcaps) {
- PurpleAccount *account = purple_buddy_get_account(buddy);
- GET_INSTANCE_IN_CALLBACK(account);
+void IMInvoker::blistNodeAliasedCB(PurpleBlistNode *node, char *old_alias) {
}
-gboolean IMInvoker::jabberRcvdPresenceCB(PurpleConnection *gc, const char *type, const char *from, xmlnode *presence) {
- PurpleAccount *account = purple_connection_get_account(gc);
- GET_INSTANCE_IN_CALLBACK(account);
+void IMInvoker::fileRecvRequestCB(PurpleXfer *xfer) {
+ purple_xfer_set_local_filename(xfer, "");
}
-void IMInvoker::buddySignOnOffCB(PurpleBuddy *buddy) {
+
+void IMInvoker::buddyCapsChangedCB(PurpleBuddy* buddy, PurpleMediaCaps newcaps, PurpleMediaCaps oldcaps) {
PurpleAccount *account = purple_buddy_get_account(buddy);
- tthread::lock_guard<tthread::mutex> lock(_accountMutex);
- if (_accountInstances.find(account) == _accountInstances.end()) {
- LOG(ERROR) << "Callback for unknown account called";
- return;
- }
- IMInvoker* inst = _accountInstances[account];
-
- std::string buddyName = purple_buddy_get_name(buddy);
- inst->_dataModelVars.compound["buddies"].compound[buddyName] = buddyToData(buddy);
+ GET_INSTANCE_IN_CALLBACK(account);
}
-void IMInvoker::signedOnCB(PurpleConnection *gc, gpointer null) {
- PurpleSavedStatus* status = purple_savedstatus_new(NULL, PURPLE_STATUS_AVAILABLE);
- purple_savedstatus_activate(status);
+Data IMInvoker::statusToData(PurpleStatus *status) {
+ Data data;
+ const char* statusName = purple_status_get_name(status);
+ if (statusName) data.compound["name"] = Data(statusName, Data::VERBATIM);
+
+ PurpleStatusType* statusType = purple_status_get_type(status);
+
+ GList *statusAttrElem;
+ GList *statusAttrList = purple_status_type_get_attrs(statusType);
+ PurpleStatusAttr* statusAttr;
+ for(statusAttrElem = statusAttrList; statusAttrElem; statusAttrElem = statusAttrElem->next) {
+ statusAttr = (PurpleStatusAttr*)statusAttrElem->data;
+ const char* statusAttrId = purple_status_attr_get_id(statusAttr);
+ PurpleValue* statusValue = purple_status_get_attr_value(status, statusAttrId);
+ if (statusValue) {
+ data.compound[statusAttrId] = purpleValueToData(statusValue);
+ }
+ }
+
+ data.compound["active"] = Data((bool)purple_status_is_active(status));
+ data.compound["available"] = Data((bool)purple_status_is_available(status));
+ data.compound["exclusive"] = Data((bool)purple_status_is_exclusive(status));
+ data.compound["active"] = Data((bool)purple_status_is_active(status));
+ data.compound["independent"] = Data((bool)purple_status_is_independent(status));
+ data.compound["online"] = Data((bool)purple_status_is_online(status));
+
+ return data;
}
-
Data IMInvoker::buddyToData(PurpleBuddy *buddy) {
Data data;
std::string buddyName = purple_buddy_get_name(buddy);
@@ -346,53 +471,16 @@ Data IMInvoker::buddyToData(PurpleBuddy *buddy) {
for(statusElem = statusList; statusElem; statusElem = statusElem->next) {
status = (PurpleStatus*)statusElem->data;
const char* statusId = purple_status_get_id(status);
- const char* statusName = purple_status_get_name(status);
PurpleStatusPrimitive statusPrimitive = purple_primitive_get_type_from_id(statusId);
-
+
// only include active states
if(statusPrimitive == PURPLE_STATUS_UNSET || !purple_presence_is_status_primitive_active(presence, statusPrimitive))
continue;
-
- if (statusName) data.compound["status"].compound[statusId] = Data(statusName, Data::VERBATIM);
-
- PurpleStatusType* statusType = purple_status_get_type(status);
-
- GList *statusAttrElem;
- GList *statusAttrList = purple_status_type_get_attrs(statusType);
- PurpleStatusAttr* statusAttr;
- for(statusAttrElem = statusAttrList; statusAttrElem; statusAttrElem = statusAttrElem->next) {
- statusAttr = (PurpleStatusAttr*)statusAttrElem->data;
- const char* statusAttrId = purple_status_attr_get_id(statusAttr);
- const char* statusAttrName = purple_status_attr_get_name(statusAttr);
-
- PurpleValue* statusAttrValue = purple_status_attr_get_value(statusAttr);
- if (statusAttrValue) {
- Data purpleValue = purpleValueToData(statusAttrValue);
- if (purpleValue) {
- data.compound["status"].compound[statusId].compound[statusAttrId].compound["value"] = purpleValue;
- if (statusAttrName) {
- data.compound["status"].compound[statusId].compound[statusAttrId].compound["name"] = Data(statusAttrName, Data::VERBATIM);
- }
- }
- }
- }
-
- data.compound["status"].compound[statusId].compound["active"] = Data((bool)purple_status_is_active(status));
- data.compound["status"].compound[statusId].compound["available"] = Data((bool)purple_status_is_available(status));
- data.compound["status"].compound[statusId].compound["exclusive"] = Data((bool)purple_status_is_exclusive(status));
- data.compound["status"].compound[statusId].compound["active"] = Data((bool)purple_status_is_active(status));
- data.compound["status"].compound[statusId].compound["independent"] = Data((bool)purple_status_is_independent(status));
- data.compound["status"].compound[statusId].compound["online"] = Data((bool)purple_status_is_online(status));
-
-
- PurpleValue* statusValue = purple_status_get_attr_value(status, statusId);
- if (statusValue)
- data.compound["status"].compound[statusId].compound["value"] = purpleValueToData(statusValue);
-
+ data.compound["status"].compound[statusId] = statusToData(status);
}
}
- std::cout << Data::toJSON(data);
+
return data;
}
@@ -407,7 +495,6 @@ Data IMInvoker::purpleValueToData(PurpleValue* value) {
case PURPLE_TYPE_STRING:
if (purple_value_get_string(value)) {
data = Data(purple_value_get_string(value), Data::VERBATIM);
- std::cout << purple_value_get_string(value) << std::endl;
}
break;
case PURPLE_TYPE_CHAR:
@@ -480,7 +567,7 @@ boost::shared_ptr<InvokerImpl> IMInvoker::create(InterpreterImpl* interpreter) {
}
Data IMInvoker::getDataModelVariables() {
- tthread::lock_guard<tthread::mutex> lock(_accountMutex);
+ tthread::lock_guard<tthread::recursive_mutex> lock(_accountMutex);
return _dataModelVars;
}
@@ -497,7 +584,7 @@ void IMInvoker::send(const SendRequest& req) {
void IMInvoker::send(void *userdata, const std::string event) {
// we are in the thread that manages all of libpurple
EventContext* ctx = (EventContext*)userdata;
-#if 0
+
if (boost::iequals(ctx->sendReq.name, "im.send")) {
if (ctx->instance->_account) {
std::string receiver;
@@ -510,7 +597,6 @@ void IMInvoker::send(void *userdata, const std::string event) {
PurpleConversation* conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, ctx->instance->_account, receiver.c_str());
purple_conv_im_send(purple_conversation_get_im_data(conv), ctx->sendReq.content.c_str());
-#if 0
if (data.binary) {
PurpleConnection *gc = purple_account_get_connection(ctx->instance->_account);
PurplePlugin *prpl;
@@ -521,18 +607,30 @@ void IMInvoker::send(void *userdata, const std::string event) {
prpl = purple_connection_get_prpl(gc);
prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
-// if (prpl_info->send_file &&
-// (prpl_info->can_receive_file
-// && prpl_info->can_receive_file(gc, receiver.c_str())))
-// prpl_info->send_file(gc, receiver.c_str(), file);
- prpl_info->send_raw(gc, data.binary->_data, data.binary->_size);
+// if (prpl_info && prpl_info->new_xfer) {
+// PurpleXfer* xfer = (prpl_info->new_xfer)(purple_account_get_connection(ctx->instance->_account), receiver.c_str());
+// purple_xfer_set_local_filename(xfer, "/Users/sradomski/Documents/W3C Standards.pdf");
+// purple_xfer_set_filename(xfer, "asdfadsf.pdf");
+// purple_xfer_request(xfer);
+// purple_xfer_request_accepted(xfer, "/Users/sradomski/Documents/W3C Standards.pdf");
+// }
+
+ //Set the filename
+// purple_xfer_set_local_filename(xfer, [[fileTransfer localFilename] UTF8String]);
+// purple_xfer_set_filename(xfer, [[[fileTransfer localFilename] lastPathComponent] UTF8String]);
+// xfer->ui_data
+// purple_xfer_request(xfer);
+
+ serv_send_file(gc, "sradomski@localhost", "/Users/sradomski/Documents/W3C Standards.pdf");
+// if (prpl_info->send_file && (prpl_info->can_receive_file && prpl_info->can_receive_file(gc, receiver.c_str()))) {
+// prpl_info->send_file(gc, receiver.c_str(), "/Users/sradomski/Documents/W3C Standards.pdf");
+// }
+// prpl_info->send_raw(gc, data.binary->data, data.binary->size);
}
}
-#endif
}
}
-#endif
delete(ctx);
}
@@ -565,23 +663,8 @@ void IMInvoker::invoke(void *userdata, const std::string event) {
_accountInstances[instance->_account] = instance;
purple_account_set_password(instance->_account, password.c_str(), NULL, NULL);
-
purple_account_set_enabled(instance->_account, "uscxml", true);
- int handle;
- purple_signal_connect(purple_connections_get_handle(), "signed-on", &handle, PURPLE_CALLBACK(signedOnCB), NULL);
-
- purple_signal_connect(purple_blist_get_handle(), "buddy-signed-on", &handle, PURPLE_CALLBACK(buddySignOnOffCB), NULL);
- purple_signal_connect(purple_blist_get_handle(), "buddy-signed-off", &handle, PURPLE_CALLBACK(buddySignOnOffCB), NULL);
- purple_signal_connect(purple_blist_get_handle(), "buddy-status-changed", &handle, PURPLE_CALLBACK(buddyStatusChangedCB), NULL);
-
- purple_signal_connect(purple_blist_get_handle(), "buddy-idle-changed", &handle, PURPLE_CALLBACK(buddyIdleChangeCB), NULL);
- purple_signal_connect(purple_blist_get_handle(), "update-idle", &handle, PURPLE_CALLBACK(buddyUpdateIdleCB), NULL);
- purple_signal_connect(purple_blist_get_handle(), "buddy-added", &handle, PURPLE_CALLBACK(buddyAddedCB), NULL);
- purple_signal_connect(purple_blist_get_handle(), "buddy-removed", &handle, PURPLE_CALLBACK(buddyRemovedCB), NULL);
- purple_signal_connect(purple_blist_get_handle(), "buddy-caps-changed", &handle, PURPLE_CALLBACK(buddyCapsChangedCB), NULL);
- purple_signal_connect(purple_blist_get_handle(), "jabber-receiving-presence", &handle, PURPLE_CALLBACK(jabberRcvdPresenceCB), NULL);
-
delete(ctx);
_accountMutex.unlock();
}
@@ -616,24 +699,65 @@ guint IMInvoker::purpleEventInputAdd(int fd, PurpleInputCondition cond, PurpleIn
short opMask = 0;
if (cond & PURPLE_INPUT_READ)
- opMask |= DelayedEventQueue::FD_READ;
+ opMask |= DelayedEventQueue::DEQ_READ;
if (cond & PURPLE_INPUT_WRITE)
- opMask |= DelayedEventQueue::FD_WRITE;
+ opMask |= DelayedEventQueue::DEQ_WRITE;
guint eventId = g_rand_int(_gRand);
+// std::cout << "-- Input add " << eventId << " --------" << fd << std::endl;
_eventQueue->addEvent(toStr(eventId), fd, opMask, purpleCallback, ctx, true);
return eventId;
}
gboolean IMInvoker::purpleEventInputRemove(guint handle) {
+// std::cout << "-- Input del " << handle << std::endl;
_eventQueue->cancelEvent(toStr(handle));
return true;
}
int IMInvoker::purpleEventInputGetError(int fd, int *error) {
- // unused
- std::cout << "purpleEventInputGetError" << std::endl;
- return 0;
+ int ret;
+ socklen_t len;
+ len = sizeof(*error);
+
+ ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, error, &len);
+ if (!ret && !(*error)) {
+ /*
+ * Taken from Fire's FaimP2PConnection.m:
+ * The job of this function is to detect if the connection failed or not
+ * There has to be a better way to do this
+ *
+ * Any socket that fails to connect will select for reading and writing
+ * and all reads and writes will fail
+ * Any listening socket will select for reading, and any read will fail
+ * So, select for writing, if you can write, and the write fails, not connected
+ */
+
+ {
+ fd_set thisfd;
+ struct timeval timeout;
+
+ FD_ZERO(&thisfd);
+ FD_SET(fd, &thisfd);
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+ select(fd+1, NULL, &thisfd, NULL, &timeout);
+ if(FD_ISSET(fd, &thisfd)){
+ ssize_t length = 0;
+ char buffer[4] = {0, 0, 0, 0};
+
+ length = write(fd, buffer, length);
+ if(length == -1)
+ {
+ /* Not connected */
+ ret = -1;
+ *error = ENOTCONN;
+ }
+ }
+ }
+ }
+
+ return ret;
}
void IMInvoker::purpleCallback(void *userdata, const std::string event) {
@@ -642,16 +766,20 @@ void IMInvoker::purpleCallback(void *userdata, const std::string event) {
ctx->function(ctx->data);
delete ctx;
} else if(ctx->input) {
+// std::cout << "operating on " << ctx->inputFD << std::endl;
ctx->input(ctx->data, ctx->inputFD, ctx->cond);
}
}
-void IMInvoker::purplePrefsInit(void) {}
+void IMInvoker::purplePrefsInit(void) {
+ purple_prefs_add_bool("/auto-login", false);
+}
+
void IMInvoker::purpleDebugInit(void) {}
void IMInvoker::purpleUIInit(void) {
purple_accounts_set_ui_ops(&_uiAccountOps);
- purple_xfers_set_ui_ops(&_uiXferOps);
+// purple_xfers_set_ui_ops(&_uiXferOps);
// purple_blist_set_ui_ops(&_uiBuddyOps);
// purple_notify_set_ui_ops(&_uiNotifyOps);
// purple_privacy_set_ui_ops(&_uiPrivacyOps);
@@ -659,6 +787,10 @@ void IMInvoker::purpleUIInit(void) {
// purple_connections_set_ui_ops(&_uiConnectOps);
// purple_whiteboard_set_ui_ops(&_uiWhiteboardOps);
purple_conversations_set_ui_ops(&_uiConvOps);
+ purple_debug_set_ui_ops(&_uiDebugOps);
+
+ setupPurpleSignals();
+
}
void IMInvoker::purpleQuit(void) {}
@@ -697,7 +829,7 @@ void* IMInvoker::accountRequestAuthorize(PurpleAccount *account,
PurpleAccountRequestAuthorizationCb authorize_cb,
PurpleAccountRequestAuthorizationCb deny_cb,
void *user_data) {
- // always accept all requests
+ // always accept all "may I add you as a buddy?" requests
authorize_cb(message, user_data);
return user_data;
}
@@ -788,9 +920,11 @@ void IMInvoker::purpleCancelRemote(PurpleXfer *xfer) {
}
gssize IMInvoker::purpleWrite(PurpleXfer *xfer, const guchar *buffer, gssize size) {
std::cout << "purpleWrite" << std::endl;
+ return 0;
}
gssize IMInvoker::purpleRead(PurpleXfer *xfer, guchar **buffer, gssize size) {
std::cout << "purpleRead" << std::endl;
+ return 0;
}
void IMInvoker::purpleDataNotSent(PurpleXfer *xfer, const guchar *buffer, gsize size) {
std::cout << "purpleDataNotSent" << std::endl;
@@ -837,34 +971,66 @@ void* IMInvoker::purpleRequestInput(const char *title, const char *primary,
gboolean multiline, gboolean masked, gchar *hint,
const char *ok_text, GCallback ok_cb,
const char *cancel_text, GCallback cancel_cb,
- PurpleRequestCommonParameters *cpar, void *user_data) {}
+ PurpleRequestCommonParameters *cpar, void *user_data) {
+ return NULL;
+}
void* IMInvoker::purpleRequestChoice(const char *title, const char *primary,
const char *secondary, gpointer default_value,
const char *ok_text, GCallback ok_cb, const char *cancel_text,
GCallback cancel_cb, PurpleRequestCommonParameters *cpar,
- void *user_data, va_list choices) {}
+ void *user_data, va_list choices) {
+ return NULL;
+}
void* IMInvoker::purpleRequestAction(const char *title, const char *primary,
const char *secondary, int default_action,
PurpleRequestCommonParameters *cpar, void *user_data,
- size_t action_count, va_list actions) {}
+ size_t action_count, va_list actions) {
+ return NULL;
+}
void* IMInvoker::purpleRequestWait(const char *title, const char *primary,
const char *secondary, gboolean with_progress,
PurpleRequestCancelCb cancel_cb,
- PurpleRequestCommonParameters *cpar, void *user_data) {}
+ PurpleRequestCommonParameters *cpar, void *user_data) {
+ return NULL;
+}
+
+void IMInvoker::purpleRequestWaitUpdate(void *ui_handle, gboolean pulse, gfloat fraction) {
-void IMInvoker::purpleRequestWaitUpdate(void *ui_handle, gboolean pulse, gfloat fraction) {}
+}
void* IMInvoker::purpleRequestFields(const char *title, const char *primary,
const char *secondary, PurpleRequestFields *fields,
const char *ok_text, GCallback ok_cb,
const char *cancel_text, GCallback cancel_cb,
- PurpleRequestCommonParameters *cpar, void *user_data) {}
+ PurpleRequestCommonParameters *cpar, void *user_data) {
+ return NULL;
+}
void* IMInvoker::purpleRequestFile(const char *title, const char *filename,
gboolean savedialog, GCallback ok_cb, GCallback cancel_cb,
- PurpleRequestCommonParameters *cpar, void *user_data) {}
+ PurpleRequestCommonParameters *cpar, void *user_data) {
+ // click ok
+ PurpleXfer *xfer = (PurpleXfer *)user_data;
+ PurpleXferType xferType = purple_xfer_get_type(xfer);
+ if (xferType == PURPLE_XFER_RECEIVE) {
+ ((PurpleRequestFileCb)ok_cb)(user_data, filename);
+ } else if (xferType == PURPLE_XFER_SEND) {
+ if (xfer->local_filename != NULL && xfer->filename != NULL) {
+ ((PurpleRequestFileCb)ok_cb)(user_data, xfer->local_filename);
+ } else {
+ ((PurpleRequestFileCb)cancel_cb)(user_data, xfer->local_filename);
+ }
+ }
+ return NULL;
+}
+
void* IMInvoker::purpleRequestFolder(const char *title, const char *dirname,
GCallback ok_cb, GCallback cancel_cb,
- PurpleRequestCommonParameters *cpar, void *user_data) {}
-void IMInvoker::purpleRequestClose(PurpleRequestType type, void *ui_handle) {}
+ PurpleRequestCommonParameters *cpar, void *user_data) {
+ return NULL;
+}
+
+void IMInvoker::purpleRequestClose(PurpleRequestType type, void *ui_handle) {
+
+}
// connection ui operations
@@ -885,4 +1051,14 @@ void IMInvoker::purpleDrawPont(PurpleWhiteboard *wb, int x, int y, int color, in
void IMInvoker::purpleDrawLine(PurpleWhiteboard *wb, int x1, int y1, int x2, int y2, int color, int size) {}
void IMInvoker::purpleClearWB(PurpleWhiteboard *wb) {}
+// debug ui operations
+void IMInvoker::purpleDebugPrint(PurpleDebugLevel level, const char *category, const char *arg_s) {
+// std::cout << category << ": " << arg_s << std::endl;
+}
+
+gboolean IMInvoker::purpleDebugIsEnabled(PurpleDebugLevel level, const char *category) {
+ return true;
+}
+
+
} \ No newline at end of file
diff --git a/src/uscxml/plugins/invoker/im/IMInvoker.h b/src/uscxml/plugins/invoker/im/IMInvoker.h
index b8a57f6..51af8f8 100644
--- a/src/uscxml/plugins/invoker/im/IMInvoker.h
+++ b/src/uscxml/plugins/invoker/im/IMInvoker.h
@@ -13,6 +13,20 @@ extern "C" {
namespace uscxml {
+typedef enum {
+ PURPLE_BUDDY_NONE = 0x00, /**< No events. */
+ PURPLE_BUDDY_SIGNON = 0x01, /**< The buddy signed on. */
+ PURPLE_BUDDY_SIGNOFF = 0x02, /**< The buddy signed off. */
+ PURPLE_BUDDY_INFO_UPDATED = 0x10, /**< The buddy's information (profile) changed. */
+ PURPLE_BUDDY_ICON = 0x40, /**< The buddy's icon changed. */
+ PURPLE_BUDDY_MISCELLANEOUS = 0x80, /**< The buddy's service-specific miscalleneous info changed. */
+ PURPLE_BUDDY_SIGNON_TIME = 0x11, /**< The buddy's signon time changed. */
+ PURPLE_BUDDY_EVIL = 0x12, /**< The buddy's warning level changed. */
+ PURPLE_BUDDY_DIRECTIM_CONNECTED = 0x14, /**< Connected to the buddy via DirectIM. */
+ PURPLE_BUDDY_DIRECTIM_DISCONNECTED = 0x18, /**< Disconnected from the buddy via DirectIM. */
+ PURPLE_BUDDY_NAME = 0x20 /**<Buddy name (UID) changed. */
+} PurpleBuddyEvent;
+
class IMInvoker : public InvokerImpl {
public:
struct EventContext {
@@ -38,13 +52,14 @@ public:
virtual void cancel(const std::string sendId);
virtual void invoke(const InvokeRequest& req);
-protected:
+private:
static bool _libPurpleIsInitialized;
static Data _pluginData;
Data _dataModelVars;
static Data buddyToData(PurpleBuddy *buddy);
+ static Data statusToData(PurpleStatus *status);
static Data purpleValueToData(PurpleValue* value);
static PurpleAccountUiOps _uiAccountOps;
@@ -58,31 +73,39 @@ protected:
static PurpleRequestUiOps _uiRequestOps;
static PurpleConnectionUiOps _uiConnectOps;
static PurpleWhiteboardUiOps _uiWhiteboardOps;
+ static PurpleDebugUiOps _uiDebugOps;
static PurpleRequestFeature _features;
static GHashTable* _uiInfo;
static GRand* _gRand;
- static tthread::mutex _accountMutex;
+ static tthread::recursive_mutex _accountMutex;
static std::map<PurpleAccount*, IMInvoker*> _accountInstances;
static tthread::mutex _initMutex;
static tthread::condition_variable _initCond;
static DelayedEventQueue* _eventQueue;
- // event callbacks
+ // libpurple event callbacks
static void signedOnCB(PurpleConnection *gc, gpointer null);
- static void buddySignOnOffCB(PurpleBuddy *buddy);
- static void buddyStatusChangedCB(PurpleBuddy *buddy, PurpleStatus *oldstatus, PurpleStatus *newstatus);
- static void buddyIdleChangeCB(PurpleBuddy *buddy, gboolean old_idle, gboolean idle);
- static void buddyUpdateIdleCB();
+ static void conversationCreatedCB(PurpleConversation *conv, void *data);
+ static void chatJoinedCB(PurpleConversation *conv, void *data);
+ static void chatJoinFailedCB(PurpleConnection *gc, GHashTable *components);
+ static void buddyTypingCB(PurpleAccount *account, const char *name, void *data);
+ static void buddyTypedCB(PurpleAccount *account, const char *name, void *data);
+ static void buddyTypingStoppedCB(PurpleAccount *account, const char *name, void *data);
+ static void buddyIdleChangedCB(PurpleBuddy *buddy, gboolean old_idle, gboolean idle, PurpleBuddyEvent event);
+ static void blistNodeAliasedCB(PurpleBlistNode *node, char *old_alias);
+ static void buddyEventCB(PurpleBuddy *buddy, PurpleBuddyEvent event);
+ static void buddyStatusChangedCB(PurpleBuddy *buddy, PurpleStatus *oldstatus, PurpleStatus *newstatus, PurpleBuddyEvent event);
static void buddyAddedCB(PurpleBuddy* buddy);
static void buddyRemovedCB(PurpleBuddy* buddy);
+ static void fileRecvRequestCB(PurpleXfer *xfer);
static void buddyCapsChangedCB(PurpleBuddy* buddy, PurpleMediaCaps newcaps, PurpleMediaCaps oldcaps);
- static gboolean jabberRcvdPresenceCB(PurpleConnection *gc, const char *type, const char *from, xmlnode *presence);
-
// these are only being called from the delayed queue's thread
static void initLibPurple(void *userdata, const std::string event);
+ static void setupPurpleSignals();
+
static void send(void *userdata, const std::string event);
static void invoke(void *userdata, const std::string event);
@@ -104,6 +127,11 @@ protected:
};
static void purpleCallback(void *userdata, const std::string event);
+ // libpurple debug
+ static void purpleDebugPrint(PurpleDebugLevel level, const char *category, const char *arg_s);
+ static gboolean purpleDebugIsEnabled(PurpleDebugLevel level, const char *category);
+
+
// libpurple core operations
static void purplePrefsInit(void);
static void purpleDebugInit(void);
diff --git a/src/uscxml/server/HTTPServer.cpp b/src/uscxml/server/HTTPServer.cpp
index 8799fc2..28b3ba4 100644
--- a/src/uscxml/server/HTTPServer.cpp
+++ b/src/uscxml/server/HTTPServer.cpp
@@ -8,6 +8,8 @@
#include "uscxml/server/HTTPServer.h"
#include "uscxml/Message.h"
#include "uscxml/Factory.h"
+
+#include <string>
#include <iostream>
#include <event2/dns.h>
#include <event2/event.h>
@@ -17,9 +19,6 @@
#include <event2/http_struct.h>
#include <event2/thread.h>
-#include <string>
-#include <iostream>
-
#include <glog/logging.h>
#include <boost/algorithm/string.hpp>
@@ -28,28 +27,38 @@
#include <arpa/inet.h>
#endif
+#if (defined EVENT_SSL_FOUND && defined OPENSSL_FOUND)
+#include <openssl/ssl.h>
+#include <openssl/bio.h>
+#include <openssl/err.h>
+#include <openssl/pem.h>
+#include <event2/bufferevent_ssl.h>
+#endif
+
#ifdef BUILD_AS_PLUGINS
#include <Pluma/Connector.hpp>
#endif
namespace uscxml {
-HTTPServer::HTTPServer(unsigned short port) {
+HTTPServer::HTTPServer(unsigned short port, SSLConfig* sslConf) {
_port = port;
_base = event_base_new();
_http = evhttp_new(_base);
_thread = NULL;
-
- evhttp_set_allowed_methods(_http,
- EVHTTP_REQ_GET |
- EVHTTP_REQ_POST |
- EVHTTP_REQ_HEAD |
- EVHTTP_REQ_PUT |
- EVHTTP_REQ_DELETE |
- EVHTTP_REQ_OPTIONS |
- EVHTTP_REQ_TRACE |
- EVHTTP_REQ_CONNECT |
- EVHTTP_REQ_PATCH); // allow all methods
+
+ unsigned int allowedMethods =
+ EVHTTP_REQ_GET |
+ EVHTTP_REQ_POST |
+ EVHTTP_REQ_HEAD |
+ EVHTTP_REQ_PUT |
+ EVHTTP_REQ_DELETE |
+ EVHTTP_REQ_OPTIONS |
+ EVHTTP_REQ_TRACE |
+ EVHTTP_REQ_CONNECT |
+ EVHTTP_REQ_PATCH;
+
+ evhttp_set_allowed_methods(_http, allowedMethods); // allow all methods
_handle = NULL;
while((_handle = evhttp_bind_socket_with_handle(_http, INADDR_ANY, _port)) == NULL) {
@@ -57,6 +66,46 @@ HTTPServer::HTTPServer(unsigned short port) {
}
determineAddress();
+#if (defined EVENT_SSL_FOUND && defined OPENSSL_FOUND)
+ if (!sslConf) {
+ _https = NULL;
+ _sslHandle = NULL;
+ _sslPort = 0;
+ } else {
+ _sslPort = sslConf->port;
+
+ // Initialize OpenSSL
+ SSL_library_init();
+ ERR_load_crypto_strings();
+ SSL_load_error_strings();
+ OpenSSL_add_all_algorithms();
+
+ _https = evhttp_new(_base);
+ evhttp_set_allowed_methods(_https, allowedMethods); // allow all methods
+
+ SSL_CTX* ctx = SSL_CTX_new (SSLv23_server_method ());
+ SSL_CTX_set_options(ctx,
+ SSL_OP_SINGLE_DH_USE |
+ SSL_OP_SINGLE_ECDH_USE |
+ SSL_OP_NO_SSLv2);
+
+ EC_KEY* ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
+ SSL_CTX_set_tmp_ecdh (ctx, ecdh);
+
+ SSL_CTX_use_certificate_chain_file(ctx, sslConf->publicKey.c_str());
+ SSL_CTX_use_PrivateKey_file(ctx, sslConf->privateKey.c_str(), SSL_FILETYPE_PEM);
+ SSL_CTX_check_private_key(ctx);
+
+ evhttp_set_bevcb(_https, sslBufferEventCallback, ctx);
+ evhttp_set_gencb(_https, sslGeneralBufferEventCallback, NULL);
+
+ _sslHandle = NULL;
+ while((_sslHandle = evhttp_bind_socket_with_handle(_https, INADDR_ANY, _sslPort)) == NULL) {
+ _sslPort++;
+ }
+ }
+#endif
+
// evhttp_set_timeout(_http, 5);
// generic callback
@@ -72,7 +121,7 @@ HTTPServer::~HTTPServer() {
HTTPServer* HTTPServer::_instance = NULL;
tthread::recursive_mutex HTTPServer::_instanceMutex;
-HTTPServer* HTTPServer::getInstance(int port) {
+HTTPServer* HTTPServer::getInstance(unsigned short port, SSLConfig* sslConf) {
// tthread::lock_guard<tthread::recursive_mutex> lock(_instanceMutex);
if (_instance == NULL) {
#ifdef _WIN32
@@ -84,12 +133,91 @@ HTTPServer* HTTPServer::getInstance(int port) {
#else
evthread_use_windows_threads();
#endif
- _instance = new HTTPServer(port);
+ _instance = new HTTPServer(port, sslConf);
_instance->start();
}
return _instance;
}
+#if (defined EVENT_SSL_FOUND && defined OPENSSL_FOUND)
+// see https://github.com/ppelleti/https-example/blob/master/https-server.c
+struct bufferevent* HTTPServer::sslBufferEventCallback(struct event_base *base, void *arg) {
+ struct bufferevent* r;
+ SSL_CTX *ctx = (SSL_CTX *) arg;
+ r = bufferevent_openssl_socket_new (base,
+ -1,
+ SSL_new (ctx),
+ BUFFEREVENT_SSL_ACCEPTING,
+ BEV_OPT_CLOSE_ON_FREE);
+ return r;
+}
+
+
+void HTTPServer::sslGeneralBufferEventCallback (struct evhttp_request *req, void *arg) {
+ struct evbuffer *evb = NULL;
+ const char *uri = evhttp_request_get_uri (req);
+ struct evhttp_uri *decoded = NULL;
+
+ /* We only handle POST requests. */
+ if (evhttp_request_get_command (req) != EVHTTP_REQ_POST)
+ { evhttp_send_reply (req, 200, "OK", NULL);
+ return;
+ }
+
+ printf ("Got a POST request for <%s>\n", uri);
+
+ /* Decode the URI */
+ decoded = evhttp_uri_parse (uri);
+ if (! decoded)
+ { printf ("It's not a good URI. Sending BADREQUEST\n");
+ evhttp_send_error (req, HTTP_BADREQUEST, 0);
+ return;
+ }
+
+ /* Decode the payload */
+ struct evkeyvalq kv;
+ memset (&kv, 0, sizeof (kv));
+ struct evbuffer *buf = evhttp_request_get_input_buffer (req);
+ evbuffer_add (buf, "", 1); /* NUL-terminate the buffer */
+ char *payload = (char *) evbuffer_pullup (buf, -1);
+ if (0 != evhttp_parse_query_str (payload, &kv))
+ { printf ("Malformed payload. Sending BADREQUEST\n");
+ evhttp_send_error (req, HTTP_BADREQUEST, 0);
+ return;
+ }
+
+ /* Determine peer */
+ char *peer_addr;
+ ev_uint16_t peer_port;
+ struct evhttp_connection *con = evhttp_request_get_connection (req);
+ evhttp_connection_get_peer (con, &peer_addr, &peer_port);
+
+ /* Extract passcode */
+ const char *passcode = evhttp_find_header (&kv, "passcode");
+ char response[256];
+ evutil_snprintf (response, sizeof (response),
+ "Hi %s! I %s your passcode.\n", peer_addr,
+ (0 == strcmp (passcode, "R23")
+ ? "liked"
+ : "didn't like"));
+ evhttp_clear_headers (&kv); /* to free memory held by kv */
+
+ /* This holds the content we're sending. */
+ evb = evbuffer_new ();
+
+ evhttp_add_header (evhttp_request_get_output_headers (req),
+ "Content-Type", "application/x-yaml");
+ evbuffer_add (evb, response, strlen (response));
+
+ evhttp_send_reply (req, 200, "OK", evb);
+
+ if (decoded)
+ evhttp_uri_free (decoded);
+ if (evb)
+ evbuffer_free (evb);
+}
+#endif
+
/**
* This callback is registered for all HTTP requests
*/
diff --git a/src/uscxml/server/HTTPServer.h b/src/uscxml/server/HTTPServer.h
index 3e0d91c..141ce7e 100644
--- a/src/uscxml/server/HTTPServer.h
+++ b/src/uscxml/server/HTTPServer.h
@@ -26,6 +26,14 @@ public:
}
};
+ class SSLConfig {
+ public:
+ SSLConfig() : port(8443) {}
+ std::string privateKey;
+ std::string publicKey;
+ unsigned short port;
+ };
+
class Reply {
public:
Reply(Request req) : status(200), type(req.data.compound["type"].atom), curlReq(req.curlReq) {}
@@ -41,7 +49,7 @@ public:
evhttp_request* httpReq;
};
- static HTTPServer* getInstance(int port = 8080);
+ static HTTPServer* getInstance(unsigned short port = 8080, SSLConfig* sslConf = NULL);
static std::string getBaseURL();
static void reply(const Reply& reply);
@@ -58,7 +66,7 @@ private:
};
};
- HTTPServer(unsigned short port);
+ HTTPServer(unsigned short port, SSLConfig* sslConf = NULL);
~HTTPServer();
void start();
@@ -90,6 +98,15 @@ private:
bool _isRunning;
friend class HTTPServlet;
+
+#if (defined EVENT_SSL_FOUND && defined OPENSSL_FOUND)
+ struct evhttp* _https;
+ struct evhttp_bound_socket* _sslHandle;
+ unsigned short _sslPort;
+
+ static struct bufferevent* sslBufferEventCallback(struct event_base *base, void *arg);
+ static void sslGeneralBufferEventCallback (struct evhttp_request *req, void *arg);
+#endif
};
class HTTPServlet {