diff options
author | Stefan Radomski <radomski@tk.informatik.tu-darmstadt.de> | 2013-09-23 16:30:04 (GMT) |
---|---|---|
committer | Stefan Radomski <radomski@tk.informatik.tu-darmstadt.de> | 2013-09-23 16:30:04 (GMT) |
commit | be3c180fec71866a91b5f9297708d581bc1d6435 (patch) | |
tree | 830acee295b8456d1e629a0db6c3734f629074a3 /src/uscxml/plugins | |
parent | 8dde1311719b29c63efb379566916cb1aa9a7cd7 (diff) | |
download | uscxml-be3c180fec71866a91b5f9297708d581bc1d6435.zip uscxml-be3c180fec71866a91b5f9297708d581bc1d6435.tar.gz uscxml-be3c180fec71866a91b5f9297708d581bc1d6435.tar.bz2 |
Added instant messaging invoker
Diffstat (limited to 'src/uscxml/plugins')
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; } |