summaryrefslogtreecommitdiffstats
path: root/src/uscxml/plugins
diff options
context:
space:
mode:
authorStefan Radomski <radomski@tk.informatik.tu-darmstadt.de>2013-09-23 16:30:04 (GMT)
committerStefan Radomski <radomski@tk.informatik.tu-darmstadt.de>2013-09-23 16:30:04 (GMT)
commitbe3c180fec71866a91b5f9297708d581bc1d6435 (patch)
tree830acee295b8456d1e629a0db6c3734f629074a3 /src/uscxml/plugins
parent8dde1311719b29c63efb379566916cb1aa9a7cd7 (diff)
downloaduscxml-be3c180fec71866a91b5f9297708d581bc1d6435.zip
uscxml-be3c180fec71866a91b5f9297708d581bc1d6435.tar.gz
uscxml-be3c180fec71866a91b5f9297708d581bc1d6435.tar.bz2
Added instant messaging invoker
Diffstat (limited to 'src/uscxml/plugins')
-rw-r--r--src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp39
-rw-r--r--src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h2
-rw-r--r--src/uscxml/plugins/element/respond/RespondElement.cpp2
-rw-r--r--src/uscxml/plugins/invoker/CMakeLists.txt21
-rw-r--r--src/uscxml/plugins/invoker/ffmpeg/FFMPEGInvoker.h3
-rw-r--r--src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.cpp31
-rw-r--r--src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.h2
-rw-r--r--src/uscxml/plugins/invoker/graphics/openscenegraph/converter/OSGConverter.cpp26
-rw-r--r--src/uscxml/plugins/invoker/im/IMInvoker.cpp361
-rw-r--r--src/uscxml/plugins/invoker/im/IMInvoker.h117
-rw-r--r--src/uscxml/plugins/invoker/sample/SampleInvoker.cpp1
11 files changed, 583 insertions, 22 deletions
diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp
index 0e72c67..d479a63 100644
--- a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp
+++ b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp
@@ -124,11 +124,14 @@ boost::shared_ptr<DataModelImpl> V8DataModel::create(InterpreterImpl* interprete
V8DataModel::getIOProcessors,
V8DataModel::setWithException,
v8::External::New(reinterpret_cast<void*>(dm.get())));
+ context->Global()->SetAccessor(v8::String::New("_invokers"),
+ V8DataModel::getInvokers,
+ V8DataModel::setWithException,
+ v8::External::New(reinterpret_cast<void*>(dm.get())));
dm->_contexts.push_back(context);
// instantiate objects - we have to have a context for that!
- dm->eval(Element<std::string>(), "_invokers = {};");
dm->eval(Element<std::string>(), "_x = {};");
return dm;
@@ -147,21 +150,35 @@ void V8DataModel::setWithException(v8::Local<v8::String> property, v8::Local<v8:
v8::Handle<v8::Value> V8DataModel::getIOProcessors(v8::Local<v8::String> property, const v8::AccessorInfo& info) {
V8DataModel* dataModel = V8DOM::toClassPtr<V8DataModel>(info.Data());
- if (dataModel->_ioProcessors.IsEmpty()) {
- dataModel->_ioProcessors = v8::Persistent<v8::Object>::New(v8::Object::New());
- //v8::Handle<v8::Object> ioProcessorObj = v8::Object::New();
- std::map<std::string, IOProcessor> ioProcessors = dataModel->_interpreter->getIOProcessors();
- std::map<std::string, IOProcessor>::const_iterator ioProcIter = ioProcessors.begin();
- while(ioProcIter != ioProcessors.end()) {
+ dataModel->_ioProcessors = v8::Persistent<v8::Object>::New(v8::Object::New());
+ //v8::Handle<v8::Object> ioProcessorObj = v8::Object::New();
+ std::map<std::string, IOProcessor> ioProcessors = dataModel->_interpreter->getIOProcessors();
+ std::map<std::string, IOProcessor>::const_iterator ioProcIter = ioProcessors.begin();
+ while(ioProcIter != ioProcessors.end()) {
// std::cout << ioProcIter->first << std::endl;
- dataModel->_ioProcessors->Set(v8::String::New(ioProcIter->first.c_str()),
- dataModel->getDataAsValue(ioProcIter->second.getDataModelVariables()));
- ioProcIter++;
- }
+ dataModel->_ioProcessors->Set(v8::String::New(ioProcIter->first.c_str()),
+ dataModel->getDataAsValue(ioProcIter->second.getDataModelVariables()));
+ ioProcIter++;
}
return dataModel->_ioProcessors;
}
+v8::Handle<v8::Value> V8DataModel::getInvokers(v8::Local<v8::String> property, const v8::AccessorInfo& info) {
+ V8DataModel* dataModel = V8DOM::toClassPtr<V8DataModel>(info.Data());
+
+ dataModel->_invokers = v8::Persistent<v8::Object>::New(v8::Object::New());
+ //v8::Handle<v8::Object> ioProcessorObj = v8::Object::New();
+ std::map<std::string, Invoker> invokers = dataModel->_interpreter->getInvokers();
+ std::map<std::string, Invoker>::const_iterator invokerIter = invokers.begin();
+ while(invokerIter != invokers.end()) {
+ // std::cout << ioProcIter->first << std::endl;
+ dataModel->_invokers->Set(v8::String::New(invokerIter->first.c_str()),
+ dataModel->getDataAsValue(invokerIter->second.getDataModelVariables()));
+ invokerIter++;
+ }
+ return dataModel->_invokers;
+}
+
void V8DataModel::pushContext() {
_contexts.push_back(_contexts.back().New(_contexts.back()));
}
diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h
index 0dffa27..1672919 100644
--- a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h
+++ b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h
@@ -81,7 +81,9 @@ protected:
Arabica::DOM::V8DOM* _dom;
v8::Persistent<v8::Object> _ioProcessors;
+ v8::Persistent<v8::Object> _invokers;
static v8::Handle<v8::Value> getIOProcessors(v8::Local<v8::String> property, const v8::AccessorInfo& info);
+ static v8::Handle<v8::Value> getInvokers(v8::Local<v8::String> property, const v8::AccessorInfo& info);
static v8::Handle<v8::Value> getAttribute(v8::Local<v8::String> property, const v8::AccessorInfo& info);
static void setWithException(v8::Local<v8::String> property, v8::Local<v8::Value> value, const v8::AccessorInfo& info);
diff --git a/src/uscxml/plugins/element/respond/RespondElement.cpp b/src/uscxml/plugins/element/respond/RespondElement.cpp
index ae81fed..9da3002 100644
--- a/src/uscxml/plugins/element/respond/RespondElement.cpp
+++ b/src/uscxml/plugins/element/respond/RespondElement.cpp
@@ -98,7 +98,7 @@ void RespondElement::enterElement(const Arabica::DOM::Node<std::string>& node) {
size_t lastDot;
if ((lastDot = file.path().find_last_of(".")) != std::string::npos) {
std::string extension = file.path().substr(lastDot + 1);
- std::string mimeType = HTTPServer::mimeTypeForExtension(extension);
+ std::string mimeType = URL::getMimeType(extension);
if (mimeType.length() > 0) {
httpReply.headers["Content-Type"] = mimeType;
}
diff --git a/src/uscxml/plugins/invoker/CMakeLists.txt b/src/uscxml/plugins/invoker/CMakeLists.txt
index db0d61f..5f767c9 100644
--- a/src/uscxml/plugins/invoker/CMakeLists.txt
+++ b/src/uscxml/plugins/invoker/CMakeLists.txt
@@ -131,6 +131,27 @@ if (FFMPEG_FOUND)
endif()
+# instant messaging invoker
+
+if (LIBPURPLE_FOUND)
+ set(USCXML_INVOKERS "im ${USCXML_INVOKERS}")
+ file(GLOB_RECURSE LIBPURPLE_INVOKER
+ im/*.cpp
+ im/*.h
+ )
+ source_group("Invoker\\im" FILES ${LIBPURPLE_INVOKER})
+ if (BUILD_AS_PLUGINS)
+ add_library(
+ invoker_im SHARED
+ ${LIBPURPLE_INVOKER})
+ target_link_libraries(invoker_im uscxml)
+ set_target_properties(invoker_im PROPERTIES FOLDER "Plugin Invoker")
+ else()
+ list (APPEND USCXML_FILES ${LIBPURPLE_INVOKER})
+ endif()
+endif()
+
+
# calendar invoker
if (LIBICAL_FOUND)
diff --git a/src/uscxml/plugins/invoker/ffmpeg/FFMPEGInvoker.h b/src/uscxml/plugins/invoker/ffmpeg/FFMPEGInvoker.h
index e95b32e..ecce031 100644
--- a/src/uscxml/plugins/invoker/ffmpeg/FFMPEGInvoker.h
+++ b/src/uscxml/plugins/invoker/ffmpeg/FFMPEGInvoker.h
@@ -46,7 +46,8 @@ protected:
frame_count(0),
width(0),
height(0),
- sws_flags(SWS_BICUBIC) {}
+ sws_flags(SWS_BICUBIC),
+ sws_ctx(NULL) {}
virtual ~EncodingContext() {
if (sws_ctx)
diff --git a/src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.cpp b/src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.cpp
index 1292e3a..559e441 100644
--- a/src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.cpp
+++ b/src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.cpp
@@ -49,7 +49,27 @@ boost::shared_ptr<InvokerImpl> DirMonInvoker::create(InterpreterImpl* interprete
}
Data DirMonInvoker::getDataModelVariables() {
+ tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
+
Data data;
+ data.compound["dir"] = Data(_dir, Data::VERBATIM);
+
+ std::set<std::string>::iterator suffixIter = _suffixes.begin();
+ while(suffixIter != _suffixes.end()) {
+ data.compound["suffixes"].array.push_back(Data(*suffixIter, Data::VERBATIM));
+ suffixIter++;
+ }
+
+ std::map<std::string, struct stat> entries = _watcher->getAllEntries();
+ std::map<std::string, struct stat>::iterator entryIter = entries.begin();
+ while(entryIter != entries.end()) {
+ data.compound["file"].compound[entryIter->first].compound["mtime"] = toStr(entryIter->second.st_mtime);
+ data.compound["file"].compound[entryIter->first].compound["ctime"] = toStr(entryIter->second.st_mtime);
+ data.compound["file"].compound[entryIter->first].compound["atime"] = toStr(entryIter->second.st_mtime);
+ data.compound["file"].compound[entryIter->first].compound["size"] = toStr(entryIter->second.st_mtime);
+ entryIter++;
+ }
+
return data;
}
@@ -115,7 +135,10 @@ void DirMonInvoker::invoke(const InvokeRequest& req) {
void DirMonInvoker::run(void* instance) {
while(((DirMonInvoker*)instance)->_isRunning) {
- ((DirMonInvoker*)instance)->_watcher->updateEntries();
+ {
+ tthread::lock_guard<tthread::recursive_mutex> lock(((DirMonInvoker*)instance)->_mutex);
+ ((DirMonInvoker*)instance)->_watcher->updateEntries();
+ }
tthread::this_thread::sleep_for(tthread::chrono::milliseconds(20));
}
}
@@ -233,7 +256,7 @@ DirectoryWatch::~DirectoryWatch() {
}
}
-
+
void DirectoryWatch::reportAsDeleted() {
std::map<std::string, struct stat>::iterator fileIter = _knownEntries.begin();
while(fileIter != _knownEntries.end()) {
@@ -248,8 +271,8 @@ void DirectoryWatch::reportAsDeleted() {
monIter++;
}
}
- _knownEntries.erase(fileIter->first);
- fileIter++;
+ _knownEntries.erase(fileIter++);
+// fileIter++;
}
assert(_knownDirs.size() == 0);
assert(_knownEntries.size() == 0);
diff --git a/src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.h b/src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.h
index 59eee81..f5aa4bc 100644
--- a/src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.h
+++ b/src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.h
@@ -44,7 +44,7 @@ public:
std::map<std::string, struct stat> dirEntries = dirIter->second->getAllEntries();
std::map<std::string, struct stat>::iterator dirEntryIter = dirEntries.begin();
while(dirEntryIter != dirEntries.end()) {
- entries[dirIter->first + PATH_SEPERATOR + dirEntryIter->first] = dirEntryIter->second;
+ entries[dirIter->first + '/' + dirEntryIter->first] = dirEntryIter->second;
dirEntryIter++;
}
dirIter++;
diff --git a/src/uscxml/plugins/invoker/graphics/openscenegraph/converter/OSGConverter.cpp b/src/uscxml/plugins/invoker/graphics/openscenegraph/converter/OSGConverter.cpp
index 0e8430c..a6f303a 100644
--- a/src/uscxml/plugins/invoker/graphics/openscenegraph/converter/OSGConverter.cpp
+++ b/src/uscxml/plugins/invoker/graphics/openscenegraph/converter/OSGConverter.cpp
@@ -247,7 +247,7 @@ void OSGConverter::process(const SendRequest& req) {
osgViewer::ScreenCaptureHandler* captureHandler = new osgViewer::ScreenCaptureHandler(cOp, -1);
{
-// tthread::lock_guard<tthread::recursive_mutex> lock(_viewerMutex);
+ tthread::lock_guard<tthread::recursive_mutex> lock(_viewerMutex);
osgViewer::Viewer viewer;
osg::ref_ptr<osg::GraphicsContext> gc;
@@ -259,7 +259,9 @@ void OSGConverter::process(const SendRequest& req) {
osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits(ds);
traits->width = width;
traits->height = height;
+ // this fails with ubuntu in a VM in parallels
traits->pbuffer = true;
+
gc = osg::GraphicsContext::createGraphicsContext(traits.get());
if (!gc.valid()) {
@@ -267,6 +269,11 @@ void OSGConverter::process(const SendRequest& req) {
return;
}
+ if (!traits->width || !traits->height) {
+ LOG(ERROR) << "Traits returned with zero dimensions";
+ return;
+ }
+
GLenum pbuffer = gc->getTraits()->doubleBuffer ? GL_BACK : GL_FRONT;
viewer.setCameraManipulator(new osgGA::TrackballManipulator());
@@ -300,6 +307,11 @@ void OSGConverter::process(const SendRequest& req) {
void OSGConverter::reportSuccess(const SendRequest& req, const Data& content) {
Event event(req);
+
+ std::string format;
+ Event::getParam(req.params, "format", format);
+
+ event.data.compound["mimetype"] = Data(URL::getMimeType(format), Data::VERBATIM);
if (event.name.length() == 0)
event.name = "convert";
@@ -519,6 +531,10 @@ void OSGConverter::dumpMatrix(const osg::Matrix& m) {
void OSGConverter::NameRespectingWriteToFile::operator()(const osg::Image& image, const unsigned int context_id) {
+// std::cout << "NameRespectingWriteToFile" << std::endl;
+// std::cout << image.s() << std::endl;
+// std::cout << image.t() << std::endl;
+
// write to memory first
std::string format;
if (_req.params.find("format") != _req.params.end()) {
@@ -533,7 +549,9 @@ void OSGConverter::NameRespectingWriteToFile::operator()(const osg::Image& image
// osgDB got confused when we write to a stringstream
std::string tempFile = URL::getTmpFilename(format);
- osgDB::writeImageFile(image, tempFile, op);
+ if (!osgDB::writeImageFile(image, tempFile, op)) {
+ _converter->reportFailure(_req);
+ }
char* buffer = NULL;
size_t length = 0;
@@ -547,7 +565,9 @@ void OSGConverter::NameRespectingWriteToFile::operator()(const osg::Image& image
file.read(buffer, length);
}
- remove(tempFile.c_str());
+ std::cout << tempFile << std::endl;
+
+// remove(tempFile.c_str());
// osg::ref_ptr<osgDB::ReaderWriter> writerFormat = osgDB::Registry::instance()->getReaderWriterForExtension(format);
// if(!writerFormat.valid())
// _converter->reportFailure(_req);
diff --git a/src/uscxml/plugins/invoker/im/IMInvoker.cpp b/src/uscxml/plugins/invoker/im/IMInvoker.cpp
new file mode 100644
index 0000000..a7fd146
--- /dev/null
+++ b/src/uscxml/plugins/invoker/im/IMInvoker.cpp
@@ -0,0 +1,361 @@
+#include "IMInvoker.h"
+#include <glog/logging.h>
+
+#ifdef BUILD_AS_PLUGINS
+#include <Pluma/Connector.hpp>
+#endif
+
+namespace uscxml {
+
+#ifdef BUILD_AS_PLUGINS
+PLUMA_CONNECTOR
+bool connect(pluma::Host& host) {
+ host.add( new IMInvokerProvider() );
+ return true;
+}
+#endif
+
+Data IMInvoker::_pluginData;
+GHashTable* IMInvoker::_uiInfo = NULL;
+GRand* IMInvoker::_gRand = NULL;
+
+PurpleEventLoopUiOps IMInvoker::_uiEventLoopOps =
+{
+ purpleEventTimeoutAdd,
+ purpleEventTimeoutRemove,
+ purpleEventInputAdd,
+ purpleEventInputRemove,
+ purpleEventInputGetError,
+ purpleEventTimeoutAddSec,
+
+ /* padding */
+ NULL,
+ NULL,
+ NULL
+};
+
+PurpleAccountUiOps IMInvoker::_accountUIOps = {
+ accountNotifyAdded,
+ accountStatusChanged,
+ accountRequestAdd,
+ accountRequestAuthorize,
+ accountCloseRequest,
+ NULL,
+ NULL,
+ NULL
+};
+
+/*** Conversation uiops ***/
+static void
+null_write_conv(PurpleConversation *conv, const char *who, const char *alias,
+ const char *message, PurpleMessageFlags flags, time_t mtime)
+{
+ const char *name;
+ if (alias && *alias)
+ name = alias;
+ else if (who && *who)
+ name = who;
+ else
+ name = NULL;
+
+ printf("(%s) %s %s: %s\n", purple_conversation_get_name(conv),
+ purple_utf8_strftime("(%H:%M:%S)", localtime(&mtime)),
+ name, message);
+}
+
+static PurpleConversationUiOps null_conv_uiops =
+{
+ NULL, /* create_conversation */
+ NULL, /* destroy_conversation */
+ NULL, /* write_chat */
+ NULL, /* write_im */
+ null_write_conv, /* write_conv */
+ NULL, /* chat_add_users */
+ NULL, /* chat_rename_user */
+ NULL, /* chat_remove_users */
+ NULL, /* chat_update_user */
+ NULL, /* present */
+ NULL, /* has_focus */
+ NULL, /* custom_smiley_add */
+ NULL, /* custom_smiley_write */
+ NULL, /* custom_smiley_close */
+ NULL, /* send_confirm */
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+static void
+null_ui_init(void)
+{
+ /**
+ * This should initialize the UI components for all the modules. Here we
+ * just initialize the UI for conversations.
+ */
+ purple_conversations_set_ui_ops(&null_conv_uiops);
+}
+
+static PurpleCoreUiOps null_core_uiops =
+{
+ NULL,
+ NULL,
+ null_ui_init,
+ NULL,
+
+ /* padding */
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+DelayedEventQueue* IMInvoker::_eventQueue = NULL;
+
+void IMInvoker::initLibPurple(void *userdata, const std::string event) {
+ _uiInfo = g_hash_table_new(g_str_hash, g_str_equal);
+ _gRand = g_rand_new();
+
+ /* Set a custom user directory (optional) */
+ //purple_util_set_user_dir(CUSTOM_USER_DIRECTORY);
+
+ /* We do not want any debugging for now to keep the noise to a minimum. */
+ purple_debug_set_enabled(false);
+
+ purple_core_set_ui_ops(&null_core_uiops);
+// purple_eventloop_set_ui_ops(&glib_eventloops);
+ purple_eventloop_set_ui_ops(&_uiEventLoopOps);
+
+ purple_plugins_add_search_path("/usr/local/lib/purple-3");
+ // purple_plugins_probe(G_MODULE_SUFFIX);
+
+ if (!purple_core_init("uscxml")) {
+ LOG(ERROR) << "libpurple initialization failed." << std::endl;
+ return;
+ }
+
+ /* Load the preferences. */
+ purple_prefs_load();
+ purple_plugins_load_saved("/purple/uscxml/plugins/saved");
+
+ GList *l;
+ PurplePlugin *plugin;
+
+ for (l = purple_plugins_get_all(); l != NULL; l = l->next) {
+ plugin = (PurplePlugin *)l->data;
+
+ Data pluginData;
+ if (plugin->info->id) pluginData.compound["id"] = Data(plugin->info->id, Data::VERBATIM);
+ if (plugin->info->homepage) pluginData.compound["homepage"] = Data(plugin->info->homepage, Data::VERBATIM);
+ if (plugin->info->author) pluginData.compound["author"] = Data(plugin->info->author, Data::VERBATIM);
+ if (plugin->info->description) pluginData.compound["description"] = Data(plugin->info->description, Data::VERBATIM);
+ if (plugin->info->name) pluginData.compound["name"] = Data(plugin->info->name, Data::VERBATIM);
+ if (plugin->info->summary) pluginData.compound["summary"] = Data(plugin->info->summary, Data::VERBATIM);
+ if (plugin->info->version) pluginData.compound["version"] = Data(plugin->info->version, Data::VERBATIM);
+ if (plugin->info->major_version) pluginData.compound["majorVersion"] = Data(toStr(plugin->info->major_version), Data::VERBATIM);
+ if (plugin->info->minor_version) pluginData.compound["minorVersion"] = Data(toStr(plugin->info->minor_version), Data::VERBATIM);
+
+ if (plugin->info->type == PURPLE_PLUGIN_PROTOCOL)
+ _pluginData.compound["protocol"].compound[plugin->info->id] = pluginData;
+
+ }
+
+}
+
+void IMInvoker::send(void *userdata, const std::string event) {
+ EventContext* ctx = (EventContext*)userdata;
+ delete(ctx);
+}
+
+static void
+signed_on(PurpleConnection *gc, gpointer null)
+{
+ PurpleAccount *account = purple_connection_get_account(gc);
+ printf("Account connected: %s %s\n", purple_account_get_username(account), purple_account_get_protocol_id(account));
+}
+
+void IMInvoker::invoke(void *userdata, const std::string event) {
+ EventContext* ctx = (EventContext*)userdata;
+ IMInvoker* instance = ctx->instance;
+
+ std::string username;
+ Event::getParam(ctx->invokeReq.params, "username", username);
+ std::string protocolId;
+ Event::getParam(ctx->invokeReq.params, "protocol", protocolId);
+ std::string password;
+ Event::getParam(ctx->invokeReq.params, "password", password);
+
+ instance->_account = purple_account_new(username.c_str(), protocolId.c_str());
+ purple_account_set_password(instance->_account, password.c_str(), NULL, NULL);
+
+ purple_accounts_set_ui_ops(&_accountUIOps);
+
+ purple_account_set_enabled(instance->_account, "uscxml", true);
+
+ PurpleSavedStatus* status = purple_savedstatus_new(NULL, PURPLE_STATUS_AVAILABLE);
+ purple_savedstatus_activate(status);
+
+ int handle;
+ purple_signal_connect(purple_connections_get_handle(), "signed-on", &handle,
+ PURPLE_CALLBACK(signed_on), NULL);
+
+ delete(ctx);
+}
+
+IMInvoker::IMInvoker() {
+ _account = NULL;
+ if (!_eventQueue) {
+ _eventQueue = new DelayedEventQueue();
+ _eventQueue->addEvent("initLibPurple", IMInvoker::initLibPurple, 0, NULL);
+ _eventQueue->start();
+
+
+ }
+
+}
+
+IMInvoker::~IMInvoker() {
+ if (_account) {
+ purple_account_destroy(_account);
+ }
+};
+
+boost::shared_ptr<InvokerImpl> IMInvoker::create(InterpreterImpl* interpreter) {
+ boost::shared_ptr<IMInvoker> invoker = boost::shared_ptr<IMInvoker>(new IMInvoker());
+ return invoker;
+}
+
+Data IMInvoker::getDataModelVariables() {
+ return _pluginData;
+}
+
+void IMInvoker::send(const SendRequest& req) {
+ EventContext* ctx = new EventContext();
+ ctx->sendReq = req;
+ ctx->instance = this;
+ _eventQueue->addEvent(req.sendid, IMInvoker::invoke, 0, ctx);
+ return;
+}
+
+void IMInvoker::cancel(const std::string sendId) {
+}
+
+void IMInvoker::invoke(const InvokeRequest& req) {
+
+ EventContext* ctx = new EventContext();
+ ctx->invokeReq = req;
+ ctx->instance = this;
+ _eventQueue->addEvent(req.sendid, IMInvoker::invoke, 0, ctx);
+ return;
+}
+
+guint IMInvoker::purpleEventTimeoutAdd(guint interval, GSourceFunc function, gpointer data) {
+ PurpleEventContext* ctx = new PurpleEventContext();
+ ctx->function = function;
+ ctx->input = NULL;
+ ctx->data = data;
+ uintptr_t ptr = reinterpret_cast<uintptr_t>(ctx);
+
+ _eventQueue->addEvent(toStr(ptr), purpleCallback, interval, ctx);
+ return ptr;
+}
+
+gboolean IMInvoker::purpleEventTimeoutRemove(guint handle) {
+ _eventQueue->cancelEvent(toStr(handle));
+ return true;
+}
+
+guint IMInvoker::purpleEventTimeoutAddSec(guint interval, GSourceFunc function, gpointer data) {
+ return purpleEventTimeoutAdd(interval * 1000, function, data);
+}
+
+guint IMInvoker::purpleEventInputAdd(int fd, PurpleInputCondition cond, PurpleInputFunction func, gpointer data) {
+ PurpleEventContext* ctx = new PurpleEventContext();
+ ctx->function = NULL;
+ ctx->input = func;
+ ctx->inputFD = fd;
+ ctx->cond = cond;
+ ctx->data = data;
+
+ short opMask = 0;
+ if (cond & PURPLE_INPUT_READ)
+ opMask |= DelayedEventQueue::FD_READ;
+ if (cond & PURPLE_INPUT_WRITE)
+ opMask |= DelayedEventQueue::FD_WRITE;
+
+ guint eventId = g_rand_int(_gRand);
+ _eventQueue->addEvent(toStr(eventId), fd, opMask, purpleCallback, ctx, true);
+ return eventId;
+}
+
+gboolean IMInvoker::purpleEventInputRemove(guint handle) {
+ _eventQueue->cancelEvent(toStr(handle));
+ return true;
+}
+
+int IMInvoker::purpleEventInputGetError(int fd, int *error) {
+ std::cout << "purpleEventInputGetError" << std::endl;
+ return 0;
+}
+
+void IMInvoker::purpleCallback(void *userdata, const std::string event) {
+ PurpleEventContext* ctx = (PurpleEventContext*)userdata;
+ if (ctx->function) {
+ ctx->function(ctx->data);
+ delete ctx;
+ } else if(ctx->input) {
+ ctx->input(ctx->data, ctx->inputFD, ctx->cond);
+ }
+}
+
+void IMInvoker::purplePrefsInit(void) {}
+void IMInvoker::purpleDebugInit(void) {}
+void IMInvoker::purpleUIInit(void) {}
+void IMInvoker::purpleQuit(void) {}
+
+GHashTable* IMInvoker::purpleGetUIInfo(void) {
+ return _uiInfo;
+}
+
+void IMInvoker::accountNotifyAdded(PurpleAccount *account,
+ const char *remote_user,
+ const char *id,
+ const char *alias,
+ const char *message) {
+ std::cout << "accountNotifyAdded" << std::endl;
+}
+
+void IMInvoker::accountStatusChanged(PurpleAccount *account,
+ PurpleStatus *status) {
+ std::cout << "accountStatusChanged" << std::endl;
+
+}
+
+void IMInvoker::accountRequestAdd(PurpleAccount *account,
+ const char *remote_user,
+ const char *id,
+ const char *alias,
+ const char *message) {
+ std::cout << "accountRequestAdd" << std::endl;
+}
+
+void* IMInvoker::accountRequestAuthorize(PurpleAccount *account,
+ const char *remote_user,
+ const char *id,
+ const char *alias,
+ const char *message,
+ gboolean on_list,
+ PurpleAccountRequestAuthorizationCb authorize_cb,
+ PurpleAccountRequestAuthorizationCb deny_cb,
+ void *user_data) {
+ // always accept all requests
+ authorize_cb(message, user_data);
+ return user_data;
+}
+
+void IMInvoker::accountCloseRequest(void *ui_handle) {
+ std::cout << "accountCloseRequest" << std::endl;
+}
+
+
+} \ No newline at end of file
diff --git a/src/uscxml/plugins/invoker/im/IMInvoker.h b/src/uscxml/plugins/invoker/im/IMInvoker.h
new file mode 100644
index 0000000..fb02e46
--- /dev/null
+++ b/src/uscxml/plugins/invoker/im/IMInvoker.h
@@ -0,0 +1,117 @@
+#ifndef IMINVOKER_H_FNWG0XCQ
+#define IMINVOKER_H_FNWG0XCQ
+
+#include <uscxml/Interpreter.h>
+
+//extern "C" {
+#include <libpurple/purple.h>
+//}
+
+#ifdef BUILD_AS_PLUGINS
+#include "uscxml/plugins/Plugins.h"
+#endif
+
+namespace uscxml {
+
+class IMInvoker : public InvokerImpl {
+public:
+ struct EventContext {
+ InvokeRequest invokeReq;
+ SendRequest sendReq;
+ IMInvoker* instance;
+ };
+
+ IMInvoker();
+ virtual ~IMInvoker();
+ virtual boost::shared_ptr<InvokerImpl> create(InterpreterImpl* interpreter);
+
+ virtual std::set<std::string> getNames() {
+ std::set<std::string> names;
+ names.insert("im");
+ names.insert("instant-messaging");
+ names.insert("http://uscxml.tk.informatik.tu-darmstadt.de/#instant-messaging");
+ 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:
+ static bool _libPurpleIsInitialized;
+ static Data _pluginData;
+ static PurpleAccountUiOps _accountUIOps;
+ static PurpleEventLoopUiOps _uiEventLoopOps;
+ static PurpleCoreUiOps _uiCoreOps;
+ static GHashTable* _uiInfo;
+ static GRand* _gRand;
+
+ static DelayedEventQueue* _eventQueue;
+
+ // these are only being called from the delayed queue's thread
+ static void initLibPurple(void *userdata, const std::string event);
+ static void send(void *userdata, const std::string event);
+ static void invoke(void *userdata, const std::string event);
+
+ // libpurple ui operations
+ static guint purpleEventTimeoutAdd(guint interval, GSourceFunc function, gpointer data);
+ static gboolean purpleEventTimeoutRemove(guint handle);
+ static guint purpleEventInputAdd(int fd, PurpleInputCondition cond, PurpleInputFunction func, gpointer user_data);
+ static gboolean purpleEventInputRemove(guint handle);
+ static int purpleEventInputGetError(int fd, int *error);
+ static guint purpleEventTimeoutAddSec(guint interval, GSourceFunc function, gpointer data);
+
+ // callback contexts
+ struct PurpleEventContext {
+ PurpleInputFunction input;
+ PurpleInputCondition cond;
+ int inputFD;
+ GSourceFunc function;
+ gpointer data;
+ };
+ static void purpleCallback(void *userdata, const std::string event);
+
+ // libpurple core operations
+ static void purplePrefsInit(void);
+ static void purpleDebugInit(void);
+ static void purpleUIInit(void);
+ static void purpleQuit(void);
+ static GHashTable* purpleGetUIInfo(void);
+
+ // account operations
+ static void accountNotifyAdded(PurpleAccount *account,
+ const char *remote_user,
+ const char *id,
+ const char *alias,
+ const char *message);
+ static void accountStatusChanged(PurpleAccount *account,
+ PurpleStatus *status);
+ static void accountRequestAdd(PurpleAccount *account,
+ const char *remote_user,
+ const char *id,
+ const char *alias,
+ const char *message);
+ static void* accountRequestAuthorize(PurpleAccount *account,
+ const char *remote_user,
+ const char *id,
+ const char *alias,
+ const char *message,
+ gboolean on_list,
+ PurpleAccountRequestAuthorizationCb authorize_cb,
+ PurpleAccountRequestAuthorizationCb deny_cb,
+ void *user_data);
+ static void accountCloseRequest(void *ui_handle);
+
+
+ PurpleAccount* _account;
+};
+
+#ifdef BUILD_AS_PLUGINS
+PLUMA_INHERIT_PROVIDER(IMInvoker, InvokerImpl);
+#endif
+
+}
+
+
+#endif /* end of include guard: IMINVOKER_H_FNWG0XCQ */
diff --git a/src/uscxml/plugins/invoker/sample/SampleInvoker.cpp b/src/uscxml/plugins/invoker/sample/SampleInvoker.cpp
index 4d514ef..bb17370 100644
--- a/src/uscxml/plugins/invoker/sample/SampleInvoker.cpp
+++ b/src/uscxml/plugins/invoker/sample/SampleInvoker.cpp
@@ -23,7 +23,6 @@ SampleInvoker::~SampleInvoker() {
boost::shared_ptr<InvokerImpl> SampleInvoker::create(InterpreterImpl* interpreter) {
boost::shared_ptr<SampleInvoker> invoker = boost::shared_ptr<SampleInvoker>(new SampleInvoker());
- invoker->_interpreter = interpreter;
return invoker;
}