diff options
Diffstat (limited to 'src/uscxml')
-rw-r--r-- | src/uscxml/Convenience.h | 33 | ||||
-rw-r--r-- | src/uscxml/Factory.h | 26 | ||||
-rw-r--r-- | src/uscxml/Message.cpp | 24 | ||||
-rw-r--r-- | src/uscxml/Message.h | 16 | ||||
-rw-r--r-- | src/uscxml/interpreter/InterpreterDraft6.cpp | 3 | ||||
-rw-r--r-- | src/uscxml/plugins/datamodel/ecmascript/TypedArray.cpp | 28 | ||||
-rw-r--r-- | src/uscxml/plugins/datamodel/ecmascript/TypedArray.h | 20 | ||||
-rw-r--r-- | src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp | 62 | ||||
-rw-r--r-- | src/uscxml/plugins/element/file/FileElement.cpp | 4 | ||||
-rw-r--r-- | src/uscxml/plugins/element/respond/RespondElement.cpp | 2 | ||||
-rw-r--r-- | src/uscxml/plugins/invoker/ffmpeg/FFMPEGInvoker.cpp | 12 | ||||
-rw-r--r-- | src/uscxml/plugins/invoker/im/IMInvoker.cpp | 697 | ||||
-rw-r--r-- | src/uscxml/plugins/invoker/im/IMInvoker.h | 179 |
13 files changed, 914 insertions, 192 deletions
diff --git a/src/uscxml/Convenience.h b/src/uscxml/Convenience.h new file mode 100644 index 0000000..ad45e2c --- /dev/null +++ b/src/uscxml/Convenience.h @@ -0,0 +1,33 @@ +#ifndef CONVENIENCE_H_LU7GZ6CB +#define CONVENIENCE_H_LU7GZ6CB + +namespace uscxml { + inline bool isnan(double x) { + return x != x; + } + + // see http://stackoverflow.com/questions/228005/alternative-to-itoa-for-converting-integer-to-string-c + template <typename T> std::string toStr(T tmp) { + std::ostringstream out; + out.precision(std::numeric_limits<double>::digits10 + 1); + out << tmp; + return out.str(); + } + + template <typename T> T strTo(std::string tmp) { + T output; + std::istringstream in(tmp); + in >> output; + return output; + } + + inline bool isNumeric( const char* pszInput, int nNumberBase) { + std::string base = ".-0123456789ABCDEF"; + std::string input = pszInput; + return (input.find_first_not_of(base.substr(0, nNumberBase + 2)) == std::string::npos); + } + +} + + +#endif /* end of include guard: CONVENIENCE_H_LU7GZ6CB */ diff --git a/src/uscxml/Factory.h b/src/uscxml/Factory.h index b815712..617e461 100644 --- a/src/uscxml/Factory.h +++ b/src/uscxml/Factory.h @@ -2,6 +2,7 @@ #define FACTORY_H_5WKLGPRB #include "uscxml/Message.h" +#include "uscxml/Convenience.h" #ifdef BUILD_AS_PLUGINS #include "Pluma/Pluma.hpp" @@ -14,31 +15,6 @@ namespace uscxml { -inline bool isnan(double x) { - return x != x; -} - -// see http://stackoverflow.com/questions/228005/alternative-to-itoa-for-converting-integer-to-string-c -template <typename T> std::string toStr(T tmp) { - std::ostringstream out; - out.precision(std::numeric_limits<double>::digits10 + 1); - out << tmp; - return out.str(); -} - -template <typename T> T strTo(std::string tmp) { - T output; - std::istringstream in(tmp); - in >> output; - return output; -} - -inline bool isNumeric( const char* pszInput, int nNumberBase) { - std::string base = ".-0123456789ABCDEF"; - std::string input = pszInput; - return (input.find_first_not_of(base.substr(0, nNumberBase + 2)) == std::string::npos); -} - class InterpreterImpl; class ExecutableContentImpl { diff --git a/src/uscxml/Message.cpp b/src/uscxml/Message.cpp index ef542d7..0a686d5 100644 --- a/src/uscxml/Message.cpp +++ b/src/uscxml/Message.cpp @@ -22,27 +22,27 @@ namespace uscxml { static int _dataIndentation = 1; Blob::~Blob() { - free(_data); + free(data); } -Blob::Blob(size_t size) { - _data = (char*)malloc(size); - memset(_data, 0, size); - _size = size; +Blob::Blob(size_t _size) { + data = (char*)malloc(_size); + memset(data, 0, _size); + size = _size; } -Blob::Blob(void* data, size_t size, bool adopt) { +Blob::Blob(void* _data, size_t _size, bool adopt) { if (adopt) { - _data = (char*)data; + data = (char*)_data; } else { - _data = (char*)malloc(size); - memcpy(_data, data, size); + data = (char*)malloc(_size); + memcpy(data, _data, _size); } - _size = size; + size = _size; } -Data::Data(const char* data, size_t size, bool adopt) { - binary = boost::shared_ptr<Blob>(new Blob((void*)data, size, adopt)); +Data::Data(const char* _data, size_t _size, bool adopt) { + binary = boost::shared_ptr<Blob>(new Blob((void*)_data, _size, adopt)); } Data::Data(const Arabica::DOM::Node<std::string>& dom) { diff --git a/src/uscxml/Message.h b/src/uscxml/Message.h index 9ae6ea1..bc92180 100644 --- a/src/uscxml/Message.h +++ b/src/uscxml/Message.h @@ -14,6 +14,8 @@ #include <boost/lexical_cast.hpp> #include <inttypes.h> +#include "uscxml/Convenience.h" + #define TAGNAME(elem) ((Arabica::DOM::Element<std::string>)elem).getTagName() #define LOCALNAME(elem) ((Arabica::DOM::Element<std::string>)elem).getLocalName() #define ATTR(elem, attr) ((Arabica::DOM::Element<std::string>)elem).getAttribute(attr) @@ -26,8 +28,9 @@ public: ~Blob(); Blob(size_t size); Blob(void* data, size_t size, bool adopt = false); - char* _data; - size_t _size; + char* data; + size_t size; + std::string mimetype; }; class Data { @@ -40,6 +43,15 @@ public: Data() : type(INTERPRETED) {} Data(const std::string& atom_, Type type_ = INTERPRETED) : atom(atom_), type(type_) {} Data(const char* data, size_t size, bool adopt); + Data(bool atom_) : type(INTERPRETED) { + if (atom_) { + atom = "true"; + } else { + atom = "false"; + } + } + template <typename T> Data(T value) : atom(toStr(value)), type(INTERPRETED) {} + explicit Data(const Arabica::DOM::Node<std::string>& dom); virtual ~Data() {} diff --git a/src/uscxml/interpreter/InterpreterDraft6.cpp b/src/uscxml/interpreter/InterpreterDraft6.cpp index 62c61e0..176bddf 100644 --- a/src/uscxml/interpreter/InterpreterDraft6.cpp +++ b/src/uscxml/interpreter/InterpreterDraft6.cpp @@ -56,8 +56,9 @@ void InterpreterDraft6::interpret() { for (unsigned int i = 0; i < dataElems.size(); i++) { // do not process data elements of nested documents from invokers if (!getAncestorElement(dataElems[i], _xmlNSPrefix + "invoke")) - if (dataElems[i].getNodeType() == Node_base::ELEMENT_NODE) + if (dataElems[i].getNodeType() == Node_base::ELEMENT_NODE) { initializeData(Element<std::string>(dataElems[i])); + } } } else if(_dataModel) { // initialize current data elements diff --git a/src/uscxml/plugins/datamodel/ecmascript/TypedArray.cpp b/src/uscxml/plugins/datamodel/ecmascript/TypedArray.cpp index d24639a..8d126e9 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/TypedArray.cpp +++ b/src/uscxml/plugins/datamodel/ecmascript/TypedArray.cpp @@ -4,14 +4,14 @@ #define DATAVIEW_TYPED_GET(type) \ type retVal;\ -if (index + _start + sizeof(type) > _buffer->_size)\ +if (index + _start + sizeof(type) > _buffer->size)\ return 0;\ -memcpy(&retVal, _buffer->_data + (_start + index), sizeof(type)); +memcpy(&retVal, _buffer->data + (_start + index), sizeof(type)); #define DATAVIEW_TYPED_SET(type) \ -if (index + _start + sizeof(type) > _buffer->_size)\ +if (index + _start + sizeof(type) > _buffer->size)\ return;\ -memcpy(_buffer->_data + (_start + index), &value, sizeof(type)); +memcpy(_buffer->data + (_start + index), &value, sizeof(type)); namespace uscxml { @@ -29,26 +29,26 @@ ArrayBuffer::ArrayBuffer(void* data, unsigned int size) { unsigned long ArrayBuffer::getByteLength() { if (!_buffer) return 0; - return _buffer->_size; + return _buffer->size; } ArrayBuffer ArrayBuffer::slice(long begin, long end) { if (!_buffer) { return ArrayBuffer(0); } - unsigned int realBegin = (begin + _buffer->_size) % _buffer->_size; - unsigned int realEnd = (end + _buffer->_size) % _buffer->_size; + unsigned int realBegin = (begin + _buffer->size) % _buffer->size; + unsigned int realEnd = (end + _buffer->size) % _buffer->size; if (realEnd < realBegin) { return ArrayBuffer(0); } ArrayBuffer arrBuffer(realEnd - realBegin); - memcpy(arrBuffer._buffer->_data, _buffer->_data + realBegin, realEnd - realBegin); + memcpy(arrBuffer._buffer->data, _buffer->data + realBegin, realEnd - realBegin); return arrBuffer; } ArrayBuffer ArrayBuffer::slice(long begin) { - return slice(begin, _buffer->_size); + return slice(begin, _buffer->size); } bool ArrayBuffer::isView(void*) { @@ -65,25 +65,25 @@ ArrayBuffer ArrayBufferView::getBuffer() { DataView::DataView(ArrayBuffer* buffer, unsigned long byteOffset, unsigned long byteLength) { _start = byteOffset; - if (_start > buffer->_buffer->_size) + if (_start > buffer->_buffer->size) return; _end = _start + byteLength; - if (_end > buffer->_buffer->_size) + if (_end > buffer->_buffer->size) return; _buffer = buffer->_buffer; } DataView::DataView(ArrayBuffer* buffer , unsigned long byteOffset) { _start = byteOffset; - _end = buffer->_buffer->_size; - if (_start > buffer->_buffer->_size) + _end = buffer->_buffer->size; + if (_start > buffer->_buffer->size) return; _buffer = buffer->_buffer; } DataView::DataView(ArrayBuffer* buffer) { _start = 0; - _end = (buffer->_buffer->_size); + _end = (buffer->_buffer->size); _buffer = buffer->_buffer; } diff --git a/src/uscxml/plugins/datamodel/ecmascript/TypedArray.h b/src/uscxml/plugins/datamodel/ecmascript/TypedArray.h index 5584721..460afd4 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/TypedArray.h +++ b/src/uscxml/plugins/datamodel/ecmascript/TypedArray.h @@ -199,7 +199,7 @@ public: _start = byteOffset / sizeof(S); _end = _start + length; - if (_end > buffer->_buffer->_size / sizeof(S)) + if (_end > buffer->_buffer->size / sizeof(S)) return; _buffer = buffer->_buffer; @@ -209,12 +209,12 @@ public: return; _start = byteOffset / sizeof(S); - _end = buffer->_buffer->_size / sizeof(S); + _end = buffer->_buffer->size / sizeof(S); _buffer = buffer->_buffer; } TypedArray(uscxml::ArrayBuffer* buffer) { _start = 0; - _end = (buffer->_buffer->_size) / sizeof(S); + _end = (buffer->_buffer->size) / sizeof(S); _buffer = buffer->_buffer; } @@ -225,7 +225,7 @@ public: _start = byteOffset / sizeof(S); _end = _start + length; - if (_end > buffer->_size / sizeof(S)) + if (_end > buffer->size / sizeof(S)) return; _buffer = buffer; @@ -271,7 +271,7 @@ public: if (index >= getLength()) return static_cast<T>(0); S retVal; - memcpy(&retVal, _buffer->_data + (_start + index) * sizeof(S), sizeof(S)); + memcpy(&retVal, _buffer->data + (_start + index) * sizeof(S), sizeof(S)); return retVal; } @@ -280,7 +280,7 @@ public: * Sets the element at the given numeric index to the given value. */ void set(unsigned long index, T value) { - memcpy(_buffer->_data + (_start + index) * sizeof(S), &value, sizeof(S)); + memcpy(_buffer->data + (_start + index) * sizeof(S), &value, sizeof(S)); } /** @@ -298,13 +298,13 @@ public: void set(TypedArray<T, S>* value, unsigned long offset) { if (!_buffer) return; - if (offset * sizeof(S) + value->getByteLength() > _buffer->_size) + if (offset * sizeof(S) + value->getByteLength() > _buffer->size) return; unsigned long otherOffset = value->_start * sizeof(S); // will this work if we use the same buffer? - memcpy(_buffer->_data + (_start + offset) * sizeof(S), value->_buffer->_data + otherOffset, value->getByteLength()); + memcpy(_buffer->data + (_start + offset) * sizeof(S), value->_buffer->data + otherOffset, value->getByteLength()); } void set(TypedArray<T, S>* value) { @@ -330,7 +330,7 @@ public: return; if (sizeof(T) == sizeof(S)) { - memcpy(_buffer->_data + offset, (void*)&data[0], data.size() * sizeof(S)); + memcpy(_buffer->data + offset, (void*)&data[0], data.size() * sizeof(S)); } else { S* buffer = (S*)malloc(data.size() * sizeof(S)); typename std::vector<T>::const_iterator dataIter = data.begin(); @@ -340,7 +340,7 @@ public: dataIter++; i++; } - memcpy(_buffer->_data + offset, buffer, data.size() * sizeof(S)); + memcpy(_buffer->data + offset, buffer, data.size() * sizeof(S)); free (buffer); } } diff --git a/src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp b/src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp index f863bb7..ee74a5f 100644 --- a/src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp +++ b/src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp @@ -204,6 +204,33 @@ void XPathDataModel::setEvent(const Event& event) { Data XPathDataModel::getStringAsData(const std::string& content) { Data data; + XPathValue<std::string> result = _xpath.evaluate_expr(content, _doc); + + std::stringstream ss; + + switch (result.type()) { + case ANY: + break; + case BOOL: + ss << result.asBool(); + break; + case NUMBER: + ss << result.asNumber(); + break; + case STRING: + ss << result.asString(); + break; + case NODE_SET: + NodeSet<std::string> ns = result.asNodeSet(); + for (int i = 0; i < ns.size(); i++) { + ss << ns[i]; + } + ss << result; + break; + } + + data.atom = ss.str(); + data.type = Data::VERBATIM; return data; } @@ -308,6 +335,7 @@ void XPathDataModel::eval(const Arabica::DOM::Element<std::string>& scriptElem, } bool XPathDataModel::isDeclared(const std::string& expr) { + return true; try { return _varResolver.isDeclared(expr) || evalAsBool(expr); } catch(...) { @@ -461,14 +489,13 @@ void XPathDataModel::init(const Element<std::string>& dataElem, Element<std::string> container = _doc.createElement("data"); container.setAttribute("id", location); + if (node) { - if (node) { - Node<std::string> data = node; - while (data) { - Node<std::string> dataClone = _doc.importNode(data, true); - container.appendChild(dataClone); - data = data.getNextSibling(); - } + Node<std::string> data = node; + while (data) { + Node<std::string> dataClone = _doc.importNode(data, true); + container.appendChild(dataClone); + data = data.getNextSibling(); } } else if (content.length() > 0) { Text<std::string> textNode = _doc.createTextNode(Interpreter::spaceNormalize(content)); @@ -497,8 +524,6 @@ void XPathDataModel::init(const Element<std::string>& dataElem, } catch (SyntaxException e) { throw Event("error.execution", Event::PLATFORM); } - } else { - LOG(ERROR) << "data element has no content"; } _datamodel.appendChild(container); @@ -740,7 +765,7 @@ NodeSetVariableResolver::resolveVariable(const std::string& namepaceUri, } void NodeSetVariableResolver::setVariable(const std::string& name, const NodeSet<std::string>& value) { -#if VERBOSE +#if 0 std::cout << std::endl << "Setting " << name << ":" << std::endl; for (int i = 0; i < value.size(); i++) { std::cout << value[i].getNodeType() << " | " << value[i] << std::endl; @@ -748,9 +773,26 @@ void NodeSetVariableResolver::setVariable(const std::string& name, const NodeSet std::cout << std::endl; #endif _variables[name] = value; +#if 0 + std::map<std::string, Arabica::XPath::NodeSet<std::string> >::iterator varIter = _variables.begin(); + while (varIter != _variables.end()) { + std::cout << varIter->first << ":" << std::endl; + for (int i = 0; i < varIter->second.size(); i++) { + std::cout << varIter->second[i].getNodeType() << " | " << varIter->second[i] << std::endl; + } + varIter++; + } +#endif } bool NodeSetVariableResolver::isDeclared(const std::string& name) { +#if 0 + std::map<std::string, Arabica::XPath::NodeSet<std::string> >::iterator varIter = _variables.begin(); + while (varIter != _variables.end()) { + std::cout << varIter->first << std::endl; + varIter++; + } +#endif return _variables.find(name) != _variables.end(); } diff --git a/src/uscxml/plugins/element/file/FileElement.cpp b/src/uscxml/plugins/element/file/FileElement.cpp index 2b48aba..e551ad7 100644 --- a/src/uscxml/plugins/element/file/FileElement.cpp +++ b/src/uscxml/plugins/element/file/FileElement.cpp @@ -78,8 +78,8 @@ void FileElement::enterElement(const Arabica::DOM::Node<std::string>& node) { } else { Data data = _interpreter->getDataModel().getStringAsData(ATTR(node, "contentexpr")); if (data.binary) { - content = data.binary->_data; - contentSize = data.binary->_size; + content = data.binary->data; + contentSize = data.binary->size; } else if (data.atom.length() > 0) { contentStr = data.atom; } diff --git a/src/uscxml/plugins/element/respond/RespondElement.cpp b/src/uscxml/plugins/element/respond/RespondElement.cpp index 9da3002..699a3a0 100644 --- a/src/uscxml/plugins/element/respond/RespondElement.cpp +++ b/src/uscxml/plugins/element/respond/RespondElement.cpp @@ -67,7 +67,7 @@ void RespondElement::enterElement(const Arabica::DOM::Node<std::string>& node) { if (contentData.atom.length() > 0) { httpReply.content = contentData.atom; } else if (contentData.binary) { - httpReply.content = std::string(contentData.binary->_data, contentData.binary->_size); + httpReply.content = std::string(contentData.binary->data, contentData.binary->size); } else { httpReply.content = Data::toJSON(contentData); } diff --git a/src/uscxml/plugins/invoker/ffmpeg/FFMPEGInvoker.cpp b/src/uscxml/plugins/invoker/ffmpeg/FFMPEGInvoker.cpp index e637f8b..36fcc1b 100644 --- a/src/uscxml/plugins/invoker/ffmpeg/FFMPEGInvoker.cpp +++ b/src/uscxml/plugins/invoker/ffmpeg/FFMPEGInvoker.cpp @@ -370,14 +370,14 @@ void FFMPEGInvoker::writeVideoFrame(EncodingContext* ctx, AVFormatContext *oc, A } uint32_t headerOffset = 0; - headerOffset += image->_data[10] << 0; - headerOffset += image->_data[11] << 8; - headerOffset += image->_data[12] << 16; - headerOffset += image->_data[13] << 24; + headerOffset += image->data[10] << 0; + headerOffset += image->data[11] << 8; + headerOffset += image->data[12] << 16; + headerOffset += image->data[13] << 24; // std::cout << headerOffset + (c->width * c->height) << " / " << image->_size << std::endl; - ret = avpicture_fill(&ctx->src_picture, (uint8_t*)(image->_data + headerOffset), BMP_FORMAT, c->width, c->height); + ret = avpicture_fill(&ctx->src_picture, (uint8_t*)(image->data + headerOffset), BMP_FORMAT, c->width, c->height); if (ret < 0) { fprintf(stderr, "Could not fill image from given bitmap\n"); @@ -386,7 +386,7 @@ void FFMPEGInvoker::writeVideoFrame(EncodingContext* ctx, AVFormatContext *oc, A (const uint8_t * const *)ctx->src_picture.data, ctx->src_picture.linesize, 0, c->height, ctx->dst_picture.data, ctx->dst_picture.linesize); } else { - avpicture_fill(&ctx->dst_picture, (uint8_t*)image->_data, c->pix_fmt, c->width, c->height); + avpicture_fill(&ctx->dst_picture, (uint8_t*)image->data, c->pix_fmt, c->width, c->height); } if (oc->oformat->flags & AVFMT_RAWPICTURE) { diff --git a/src/uscxml/plugins/invoker/im/IMInvoker.cpp b/src/uscxml/plugins/invoker/im/IMInvoker.cpp index a7fd146..cff9b5f 100644 --- a/src/uscxml/plugins/invoker/im/IMInvoker.cpp +++ b/src/uscxml/plugins/invoker/im/IMInvoker.cpp @@ -1,12 +1,22 @@ #include "IMInvoker.h" #include <glog/logging.h> +#include "uscxml/UUID.h" #ifdef BUILD_AS_PLUGINS #include <Pluma/Connector.hpp> #endif -namespace uscxml { +#define GET_INSTANCE_IN_CALLBACK(account) \ +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];\ + +namespace uscxml { + #ifdef BUILD_AS_PLUGINS PLUMA_CONNECTOR bool connect(pluma::Host& host) { @@ -25,16 +35,14 @@ PurpleEventLoopUiOps IMInvoker::_uiEventLoopOps = purpleEventTimeoutRemove, purpleEventInputAdd, purpleEventInputRemove, - purpleEventInputGetError, + NULL, //purpleEventInputGetError, purpleEventTimeoutAddSec, - - /* padding */ NULL, NULL, NULL }; -PurpleAccountUiOps IMInvoker::_accountUIOps = { +PurpleAccountUiOps IMInvoker::_uiAccountOps = { accountNotifyAdded, accountStatusChanged, accountRequestAdd, @@ -44,66 +52,139 @@ PurpleAccountUiOps IMInvoker::_accountUIOps = { 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 = +PurpleBlistUiOps IMInvoker::_uiBuddyOps = { + purpleNewList, + purpleNewNode, + purpleShow, + NULL, // purpleUpdate, + NULL, // purpleRemove, + NULL, // purpleDestroy, + NULL, // purpleSetVisible, + purpleRequestAddBuddy, + purpleRequestAddChat, + purpleRequestAddGroup, + NULL, // purpleSaveNode, + NULL, // purpleRemoveNode, + NULL, // purpleSaveAccount, +}; + +// file transfer +PurpleXferUiOps IMInvoker::_uiXferOps = { + purpleNewXfer, + purpleDestroy, + purpleAddXfer, + purpleUpdateProgress, + purpleCancelLocal, + purpleCancelRemote, + purpleWrite, + purpleRead, + purpleDataNotSent, + purpleAddThumbnail +}; + +// connection info +PurpleConnectionUiOps IMInvoker::_uiConnectOps = { + purpleConnectProgress, + purpleConnected, + purpleDisonnected, + purpleNotice, + purpleNetworkConnected, + purpleNetworkDisconnected, + purpleReportDisconnect, + NULL, + NULL, + NULL + +}; + +//libpurple conversation operations +PurpleConversationUiOps IMInvoker::_uiConvOps = { - 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, //purpleCreateConversation, + NULL, //purpleDestroyConversation, + NULL, //purpleWriteChat, + NULL, //purpleWriteIm, + purpleWriteConv, + NULL, //purpleChatRenameUser, + NULL, //purpleChatRemoveUsers, + NULL, //purpleChatUpdateUser, + NULL, //purplePresentConversation, + NULL, //purpleHasFocus, + NULL, //purpleCustomSmileyAdd, + NULL, //purpleCustomSmileyWrite, + NULL, //purpleCustomSmileyClose, + NULL, //purpleSendConfirm, 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); -} +PurpleNotifyUiOps IMInvoker::_uiNotifyOps = { + purpeNotifyMessage, + purpeNotifyEmail, + purpeNotifyEmails, + purpeNotifyFormatted, + purpeNotifySearchResults, + purpeNotifySearchResultsNewRows, + purpeNotifyUserInfo, + purpeNotifyURI, + purpeNotifyClose, + NULL, + NULL, + NULL, + NULL +}; -static PurpleCoreUiOps null_core_uiops = -{ +PurplePrivacyUiOps IMInvoker::_uiPrivacyOps = { + purplePermitAdded, + purplePermitRemoved, + purpleDebyAdded, + purpleDenyRemoved, + NULL, + NULL, NULL, + NULL +}; + +PurpleRequestFeature IMInvoker::_features; +PurpleRequestUiOps IMInvoker::_uiRequestOps = { + _features, + purpleRequestInput, + purpleRequestChoice, + purpleRequestAction, + purpleRequestWait, + purpleRequestWaitUpdate, + purpleRequestFields, + purpleRequestFile, + purpleRequestFolder, + purpleRequestClose, NULL, - null_ui_init, NULL, + NULL, + NULL +}; + +PurpleWhiteboardUiOps IMInvoker::_uiWhiteboardOps = { + purpleCreateWB, + purpleDestroyWB, + purpleSetDimensions, + purpleSetBrush, + purpleDrawPont, + purpleDrawLine, + purpleClearWB, + NULL, + NULL, + NULL, + NULL +}; - /* padding */ +PurpleCoreUiOps IMInvoker::_uiCoreOps = { + NULL, + NULL, + purpleUIInit, + NULL, NULL, NULL, NULL, @@ -112,8 +193,22 @@ static PurpleCoreUiOps null_core_uiops = DelayedEventQueue* IMInvoker::_eventQueue = NULL; +tthread::mutex IMInvoker::_initMutex; +tthread::condition_variable IMInvoker::_initCond; + +tthread::mutex IMInvoker::_accountMutex; +std::map<PurpleAccount*, IMInvoker*> IMInvoker::_accountInstances; + void IMInvoker::initLibPurple(void *userdata, const std::string event) { + _initMutex.lock(); + _uiInfo = g_hash_table_new(g_str_hash, g_str_equal); +// g_hash_table_insert(_uiInfo, "name", (char*)"uscxml"); +// g_hash_table_insert(_uiInfo, "version", "0.0.3"); +// g_hash_table_insert(_uiInfo, "website", "http://uscxml.tk.informatik.tu-darmstadt.de"); +// g_hash_table_insert(_uiInfo, "dev_website", "http://uscxml.tk.informatik.tu-darmstadt.de"); +// g_hash_table_insert(_uiInfo, "client_type", "pc"); + _gRand = g_rand_new(); /* Set a custom user directory (optional) */ @@ -122,7 +217,7 @@ void IMInvoker::initLibPurple(void *userdata, const std::string event) { /* 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_core_set_ui_ops(&_uiCoreOps); // purple_eventloop_set_ui_ops(&glib_eventloops); purple_eventloop_set_ui_ops(&_uiEventLoopOps); @@ -160,63 +255,222 @@ void IMInvoker::initLibPurple(void *userdata, const std::string event) { } + _initMutex.unlock(); + _initCond.notify_all(); + } -void IMInvoker::send(void *userdata, const std::string event) { - EventContext* ctx = (EventContext*)userdata; - delete(ctx); +void IMInvoker::buddyStatusChangedCB(PurpleBuddy *buddy, PurpleStatus *old, PurpleStatus *newstatus) { + PurpleAccount *account = purple_buddy_get_account(buddy); + GET_INSTANCE_IN_CALLBACK(account); + + std::string buddyName = purple_buddy_get_name(buddy); + inst->_dataModelVars.compound["buddies"].compound[buddyName] = buddyToData(buddy); } -static void -signed_on(PurpleConnection *gc, gpointer null) -{ +void IMInvoker::buddyIdleChangeCB(PurpleBuddy *buddy, gboolean old_idle, gboolean idle) { + PurpleAccount *account = purple_buddy_get_account(buddy); + GET_INSTANCE_IN_CALLBACK(account); +} + +void IMInvoker::buddyUpdateIdleCB() { +} + +void IMInvoker::buddyAddedCB(PurpleBuddy* buddy) { + PurpleAccount *account = purple_buddy_get_account(buddy); + GET_INSTANCE_IN_CALLBACK(account); +} + +void IMInvoker::buddyRemovedCB(PurpleBuddy* buddy) { + PurpleAccount *account = purple_buddy_get_account(buddy); + GET_INSTANCE_IN_CALLBACK(account); +} + +void IMInvoker::buddyCapsChangedCB(PurpleBuddy* buddy, PurpleMediaCaps newcaps, PurpleMediaCaps oldcaps) { + PurpleAccount *account = purple_buddy_get_account(buddy); + GET_INSTANCE_IN_CALLBACK(account); +} + +gboolean IMInvoker::jabberRcvdPresenceCB(PurpleConnection *gc, const char *type, const char *from, xmlnode *presence) { PurpleAccount *account = purple_connection_get_account(gc); - printf("Account connected: %s %s\n", purple_account_get_username(account), purple_account_get_protocol_id(account)); + GET_INSTANCE_IN_CALLBACK(account); } -void IMInvoker::invoke(void *userdata, const std::string event) { - EventContext* ctx = (EventContext*)userdata; - IMInvoker* instance = ctx->instance; +void IMInvoker::buddySignOnOffCB(PurpleBuddy *buddy) { + 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 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); + std::string buddyName = purple_buddy_get_name(buddy); + inst->_dataModelVars.compound["buddies"].compound[buddyName] = buddyToData(buddy); +} + +void IMInvoker::signedOnCB(PurpleConnection *gc, gpointer null) { + PurpleSavedStatus* status = purple_savedstatus_new(NULL, PURPLE_STATUS_AVAILABLE); + purple_savedstatus_activate(status); +} - 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); +Data IMInvoker::buddyToData(PurpleBuddy *buddy) { + Data data; + std::string buddyName = purple_buddy_get_name(buddy); - purple_account_set_enabled(instance->_account, "uscxml", true); + if (purple_buddy_get_name(buddy)) data.compound["name"] = Data(purple_buddy_get_name(buddy), Data::VERBATIM); + if (purple_buddy_get_alias(buddy)) data.compound["alias"] = Data(purple_buddy_get_alias(buddy), Data::VERBATIM); + if (purple_buddy_get_alias_only(buddy)) data.compound["aliasOnly"] = Data(purple_buddy_get_alias_only(buddy), Data::VERBATIM); + if (purple_buddy_get_server_alias(buddy)) data.compound["server"] = Data(purple_buddy_get_server_alias(buddy), Data::VERBATIM); - 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); + PurpleGroup* group = purple_buddy_get_group(buddy); + if (group) { + if (purple_group_get_name(group)) data.compound["group"] = Data(purple_group_get_name(group), Data::VERBATIM); + } - delete(ctx); + PurpleBuddyIcon* icon = purple_buddy_get_icon(buddy); + if (icon) { + size_t iconSize = 0; + gconstpointer iconData = purple_buddy_icon_get_data(icon, &iconSize); + data.compound["icon"] = Data((char*)iconData, iconSize, false); + } + + PurplePresence* presence = purple_buddy_get_presence(buddy); + + if (presence) { + GList *statusElem; + GList *statusList = purple_presence_get_statuses(presence); + PurpleStatus* status; + + 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); + + } + + } + std::cout << Data::toJSON(data); + return data; } +Data IMInvoker::purpleValueToData(PurpleValue* value) { + Data data; + switch (purple_value_get_type(value)) { + case PURPLE_TYPE_BOOLEAN: + if (purple_value_get_boolean(value)) + data = Data("true"); + data = Data("false"); + break; + 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: + Data(purple_value_get_char(value)); + break; + case PURPLE_TYPE_UCHAR: + Data(purple_value_get_uchar(value)); + break; + case PURPLE_TYPE_SHORT: + Data(purple_value_get_short(value)); + break; + case PURPLE_TYPE_USHORT: + Data(purple_value_get_ushort(value)); + break; + case PURPLE_TYPE_INT: + Data(purple_value_get_int(value)); + break; + case PURPLE_TYPE_UINT: + Data(purple_value_get_uint(value)); + break; + case PURPLE_TYPE_LONG: + Data(purple_value_get_long(value)); + break; + case PURPLE_TYPE_ULONG: + Data(purple_value_get_ulong(value)); + break; + case PURPLE_TYPE_INT64: + Data(purple_value_get_int64(value)); + break; + case PURPLE_TYPE_UINT64: + Data(purple_value_get_uint64(value)); + break; + case PURPLE_TYPE_OBJECT: + case PURPLE_TYPE_POINTER: + case PURPLE_TYPE_ENUM: + case PURPLE_TYPE_BOXED: + case PURPLE_TYPE_UNKNOWN: + case PURPLE_TYPE_SUBTYPE: + LOG(ERROR) << "purple thingy not supported"; + break; + } + return data; +} + IMInvoker::IMInvoker() { _account = NULL; if (!_eventQueue) { + tthread::lock_guard<tthread::mutex> lock(_initMutex); _eventQueue = new DelayedEventQueue(); _eventQueue->addEvent("initLibPurple", IMInvoker::initLibPurple, 0, NULL); _eventQueue->start(); - - + // make sure to have the shebang initialized when we leave + _initCond.wait(_initMutex); } } IMInvoker::~IMInvoker() { if (_account) { + _accountMutex.lock(); + _accountInstances.erase(_account); purple_account_destroy(_account); + _accountMutex.unlock(); } }; @@ -226,17 +480,62 @@ boost::shared_ptr<InvokerImpl> IMInvoker::create(InterpreterImpl* interpreter) { } Data IMInvoker::getDataModelVariables() { - return _pluginData; + tthread::lock_guard<tthread::mutex> lock(_accountMutex); + return _dataModelVars; } void IMInvoker::send(const SendRequest& req) { EventContext* ctx = new EventContext(); ctx->sendReq = req; ctx->instance = this; - _eventQueue->addEvent(req.sendid, IMInvoker::invoke, 0, ctx); + + std::string eventId = UUID::getUUID(); + _eventQueue->addEvent(eventId, IMInvoker::send, 0, ctx); return; } +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; + Event::getParam(ctx->sendReq.params, "receiver", receiver); + + Data data; + Event::getParam(ctx->sendReq.params, "data", data); + + // purple_conv_im_send + 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; + PurplePluginProtocolInfo *prpl_info; + + + if (gc) { + 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); + } + + } +#endif + } + } +#endif + delete(ctx); +} + void IMInvoker::cancel(const std::string sendId) { } @@ -249,6 +548,44 @@ void IMInvoker::invoke(const InvokeRequest& req) { return; } +void IMInvoker::invoke(void *userdata, const std::string event) { + _accountMutex.lock(); + + 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()); + _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(); +} + guint IMInvoker::purpleEventTimeoutAdd(guint interval, GSourceFunc function, gpointer data) { PurpleEventContext* ctx = new PurpleEventContext(); ctx->function = function; @@ -294,6 +631,7 @@ gboolean IMInvoker::purpleEventInputRemove(guint handle) { } int IMInvoker::purpleEventInputGetError(int fd, int *error) { + // unused std::cout << "purpleEventInputGetError" << std::endl; return 0; } @@ -310,7 +648,18 @@ void IMInvoker::purpleCallback(void *userdata, const std::string event) { void IMInvoker::purplePrefsInit(void) {} void IMInvoker::purpleDebugInit(void) {} -void IMInvoker::purpleUIInit(void) {} + +void IMInvoker::purpleUIInit(void) { + purple_accounts_set_ui_ops(&_uiAccountOps); + purple_xfers_set_ui_ops(&_uiXferOps); +// purple_blist_set_ui_ops(&_uiBuddyOps); +// purple_notify_set_ui_ops(&_uiNotifyOps); +// purple_privacy_set_ui_ops(&_uiPrivacyOps); +// purple_request_set_ui_ops(&_uiRequestOps); +// purple_connections_set_ui_ops(&_uiConnectOps); +// purple_whiteboard_set_ui_ops(&_uiWhiteboardOps); + purple_conversations_set_ui_ops(&_uiConvOps); +} void IMInvoker::purpleQuit(void) {} GHashTable* IMInvoker::purpleGetUIInfo(void) { @@ -357,5 +706,183 @@ void IMInvoker::accountCloseRequest(void *ui_handle) { std::cout << "accountCloseRequest" << std::endl; } +//libpurple conversation operations +void IMInvoker::purpleCreateConversation(PurpleConversation *conv) {} +void IMInvoker::purpleDestroyConversation(PurpleConversation *conv) {} +void IMInvoker::purpleWriteChat(PurpleConversation *conv, const char *who, const char *message, PurpleMessageFlags flags, time_t mtime) {} +void IMInvoker::purpleWriteIm(PurpleConversation *conv, const char *who, const char *message, PurpleMessageFlags flags, time_t mtime) {} +void IMInvoker::purpleWriteConv(PurpleConversation *conv, const char *name, const char *alias, const char *message, PurpleMessageFlags flags, time_t mtime) { + const char *who; + if (alias && *alias) + who = alias; + else if (name && *name) + who = name; + else + who = NULL; + + printf("(%s) %s %s: %s\n", purple_conversation_get_name(conv), + purple_utf8_strftime("(%H:%M:%S)", localtime(&mtime)), + who, message); +} +void IMInvoker::purpleChatAddUsers(PurpleConversation *conv, GList *cbuddies, gboolean new_arrivals) {} +void IMInvoker::purpleChatRenameUser(PurpleConversation *conv, const char *old_name, const char *new_name, const char *new_alias) {} +void IMInvoker::purpleChatRemoveUsers(PurpleConversation *conv, GList *users) {} +void IMInvoker::purpleChatUpdateUser(PurpleConversation *conv, const char *user) {} +void IMInvoker::purplePresentConversation(PurpleConversation *conv) {} +gboolean IMInvoker::purpleHasFocus(PurpleConversation *conv) { + return true; +} +gboolean IMInvoker::purpleCustomSmileyAdd(PurpleConversation *conv, const char *smile, gboolean remote) { + return true; +} +void IMInvoker::purpleCustomSmileyWrite(PurpleConversation *conv, const char *smile, const guchar *data, gsize size) {} +void IMInvoker::purpleCustomSmileyClose(PurpleConversation *conv, const char *smile) {} +void IMInvoker::purpleSendConfirm(PurpleConversation *conv, const char *message) {} + +// buddy operations +void IMInvoker::purpleNewList(PurpleBuddyList *list) { + std::cout << "purpleNewList" << std::endl; +} +void IMInvoker::purpleNewNode(PurpleBlistNode *node) { + std::cout << "purpleNewNode" << std::endl; +} +void IMInvoker::purpleShow(PurpleBuddyList *list) { + std::cout << "purpleShow" << std::endl; +} +void IMInvoker::purpleUpdate(PurpleBuddyList *list, PurpleBlistNode *node) { +} +void IMInvoker::purpleRemove(PurpleBuddyList *list, PurpleBlistNode *node) {} +void IMInvoker::purpleDestroy(PurpleBuddyList *list) {} +void IMInvoker::purpleSetVisible(PurpleBuddyList *list, gboolean show) {} +void IMInvoker::purpleRequestAddBuddy(PurpleAccount *account, const char *username, const char *group, const char *alias) { + std::cout << "purpleRequestAddBuddy" << std::endl; +} +void IMInvoker::purpleRequestAddChat(PurpleAccount *account, PurpleGroup *group, const char *alias, const char *name) { + std::cout << "purpleRequestAddChat" << std::endl; +} +void IMInvoker::purpleRequestAddGroup(void) { + std::cout << "purpleRequestAddGroup" << std::endl; +} +void IMInvoker::purpleSaveNode(PurpleBlistNode *node) {} +void IMInvoker::purpleRemoveNode(PurpleBlistNode *node) {} +void IMInvoker::purpleSaveAccount(PurpleAccount *account) {} + +// file transfer operations +void IMInvoker::purpleNewXfer(PurpleXfer *xfer) { + std::cout << "purpleNewXfer" << std::endl; +} +void IMInvoker::purpleDestroy(PurpleXfer *xfer) { + std::cout << "purpleDestroy" << std::endl; +} +void IMInvoker::purpleAddXfer(PurpleXfer *xfer) { + std::cout << "purpleAddXfer" << std::endl; +} +void IMInvoker::purpleUpdateProgress(PurpleXfer *xfer, double percent) { + std::cout << "purpleUpdateProgress" << std::endl; +} +void IMInvoker::purpleCancelLocal(PurpleXfer *xfer) { + std::cout << "purpleCancelLocal" << std::endl; +} +void IMInvoker::purpleCancelRemote(PurpleXfer *xfer) { + std::cout << "purpleCancelRemote" << std::endl; +} +gssize IMInvoker::purpleWrite(PurpleXfer *xfer, const guchar *buffer, gssize size) { + std::cout << "purpleWrite" << std::endl; +} +gssize IMInvoker::purpleRead(PurpleXfer *xfer, guchar **buffer, gssize size) { + std::cout << "purpleRead" << std::endl; +} +void IMInvoker::purpleDataNotSent(PurpleXfer *xfer, const guchar *buffer, gsize size) { + std::cout << "purpleDataNotSent" << std::endl; +} +void IMInvoker::purpleAddThumbnail(PurpleXfer *xfer, const gchar *formats) { + std::cout << "purpleAddThumbnail" << std::endl; +} + +// notification operations +void* IMInvoker::purpeNotifyMessage(PurpleNotifyMsgType type, const char *title, const char *primary, const char *secondary, PurpleRequestCommonParameters *cpar) { + return NULL; +} +void* IMInvoker::purpeNotifyEmail(PurpleConnection *gc, const char *subject, const char *from, const char *to, const char *url) { + return NULL; +} +void* IMInvoker::purpeNotifyEmails(PurpleConnection *gc, size_t count, gboolean detailed, const char **subjects, const char **froms, const char **tos, const char **urls) { + return NULL; +} +void* IMInvoker::purpeNotifyFormatted(const char *title, const char *primary, const char *secondary, const char *text) { + return NULL; +} +void* IMInvoker::purpeNotifySearchResults(PurpleConnection *gc, const char *title, const char *primary, const char *secondary, PurpleNotifySearchResults *results, gpointer user_data) { + return NULL; +} +void IMInvoker::purpeNotifySearchResultsNewRows(PurpleConnection *gc, PurpleNotifySearchResults *results, void *data) {} +void* IMInvoker::purpeNotifyUserInfo(PurpleConnection *gc, const char *who, PurpleNotifyUserInfo *user_info) { + return NULL; +} +void* IMInvoker::purpeNotifyURI(const char *uri) { + return NULL; +} +void IMInvoker::purpeNotifyClose(PurpleNotifyType type, void *ui_handle) {} + +// privacy ui operations +void IMInvoker::purplePermitAdded(PurpleAccount *account, const char *name) {} +void IMInvoker::purplePermitRemoved(PurpleAccount *account, const char *name) {} +void IMInvoker::purpleDebyAdded(PurpleAccount *account, const char *name) {} +void IMInvoker::purpleDenyRemoved(PurpleAccount *account, const char *name) {} + +// request ui operations +void* IMInvoker::purpleRequestInput(const char *title, const char *primary, + const char *secondary, const char *default_value, + 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) {} +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* 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) {} +void* IMInvoker::purpleRequestWait(const char *title, const char *primary, + const char *secondary, gboolean with_progress, + PurpleRequestCancelCb cancel_cb, + PurpleRequestCommonParameters *cpar, void *user_data) {} + +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) {} +void* IMInvoker::purpleRequestFile(const char *title, const char *filename, + gboolean savedialog, GCallback ok_cb, GCallback cancel_cb, + PurpleRequestCommonParameters *cpar, void *user_data) {} +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) {} + + +// connection ui operations +void IMInvoker::purpleConnectProgress(PurpleConnection *gc, const char *text, size_t step, size_t step_count) {} +void IMInvoker::purpleConnected(PurpleConnection *gc) {} +void IMInvoker::purpleDisonnected(PurpleConnection *gc) {} +void IMInvoker::purpleNotice(PurpleConnection *gc, const char *text) {} +void IMInvoker::purpleNetworkConnected(void) {} +void IMInvoker::purpleNetworkDisconnected(void) {} +void IMInvoker::purpleReportDisconnect(PurpleConnection *gc, PurpleConnectionError reason, const char *text) {} + +// whiteboard ui operations +void IMInvoker::purpleCreateWB(PurpleWhiteboard *wb) {} +void IMInvoker::purpleDestroyWB(PurpleWhiteboard *wb) {} +void IMInvoker::purpleSetDimensions(PurpleWhiteboard *wb, int width, int height) {} +void IMInvoker::purpleSetBrush(PurpleWhiteboard *wb, int size, int color) {} +void IMInvoker::purpleDrawPont(PurpleWhiteboard *wb, int x, int y, int color, int size) {} +void IMInvoker::purpleDrawLine(PurpleWhiteboard *wb, int x1, int y1, int x2, int y2, int color, int size) {} +void IMInvoker::purpleClearWB(PurpleWhiteboard *wb) {} + }
\ 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 fb02e46..b8a57f6 100644 --- a/src/uscxml/plugins/invoker/im/IMInvoker.h +++ b/src/uscxml/plugins/invoker/im/IMInvoker.h @@ -3,9 +3,9 @@ #include <uscxml/Interpreter.h> -//extern "C" { +extern "C" { #include <libpurple/purple.h> -//} +} #ifdef BUILD_AS_PLUGINS #include "uscxml/plugins/Plugins.h" @@ -41,14 +41,46 @@ public: protected: static bool _libPurpleIsInitialized; static Data _pluginData; - static PurpleAccountUiOps _accountUIOps; + + Data _dataModelVars; + + static Data buddyToData(PurpleBuddy *buddy); + static Data purpleValueToData(PurpleValue* value); + + static PurpleAccountUiOps _uiAccountOps; static PurpleEventLoopUiOps _uiEventLoopOps; static PurpleCoreUiOps _uiCoreOps; + static PurpleConversationUiOps _uiConvOps; + static PurpleBlistUiOps _uiBuddyOps; + static PurpleXferUiOps _uiXferOps; + static PurpleNotifyUiOps _uiNotifyOps; + static PurplePrivacyUiOps _uiPrivacyOps; + static PurpleRequestUiOps _uiRequestOps; + static PurpleConnectionUiOps _uiConnectOps; + static PurpleWhiteboardUiOps _uiWhiteboardOps; + + static PurpleRequestFeature _features; static GHashTable* _uiInfo; static GRand* _gRand; + static tthread::mutex _accountMutex; + static std::map<PurpleAccount*, IMInvoker*> _accountInstances; + static tthread::mutex _initMutex; + static tthread::condition_variable _initCond; static DelayedEventQueue* _eventQueue; + // 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 buddyAddedCB(PurpleBuddy* buddy); + static void buddyRemovedCB(PurpleBuddy* buddy); + 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 send(void *userdata, const std::string event); @@ -79,31 +111,130 @@ protected: static void purpleQuit(void); static GHashTable* purpleGetUIInfo(void); + //libpurple conversation operations + static void purpleCreateConversation(PurpleConversation *conv); + static void purpleDestroyConversation(PurpleConversation *conv); + static void purpleWriteChat(PurpleConversation *conv, const char *who, const char *message, PurpleMessageFlags flags, time_t mtime); + static void purpleWriteIm(PurpleConversation *conv, const char *who, const char *message, PurpleMessageFlags flags, time_t mtime); + static void purpleWriteConv(PurpleConversation *conv, const char *name, const char *alias, const char *message, PurpleMessageFlags flags, time_t mtime); + static void purpleChatAddUsers(PurpleConversation *conv, GList *cbuddies, gboolean new_arrivals); + static void purpleChatRenameUser(PurpleConversation *conv, const char *old_name, const char *new_name, const char *new_alias); + static void purpleChatRemoveUsers(PurpleConversation *conv, GList *users); + static void purpleChatUpdateUser(PurpleConversation *conv, const char *user); + static void purplePresentConversation(PurpleConversation *conv); + static gboolean purpleHasFocus(PurpleConversation *conv); + static gboolean purpleCustomSmileyAdd(PurpleConversation *conv, const char *smile, gboolean remote); + static void purpleCustomSmileyWrite(PurpleConversation *conv, const char *smile, const guchar *data, gsize size); + static void purpleCustomSmileyClose(PurpleConversation *conv, const char *smile); + static void purpleSendConfirm(PurpleConversation *conv, const char *message); + + // buddy operations + static void purpleNewList(PurpleBuddyList *list); + static void purpleNewNode(PurpleBlistNode *node); + static void purpleShow(PurpleBuddyList *list); + static void purpleUpdate(PurpleBuddyList *list, PurpleBlistNode *node); + static void purpleRemove(PurpleBuddyList *list, PurpleBlistNode *node); + static void purpleDestroy(PurpleBuddyList *list); + static void purpleSetVisible(PurpleBuddyList *list, gboolean show); + static void purpleRequestAddBuddy(PurpleAccount *account, const char *username, const char *group, const char *alias); + static void purpleRequestAddChat(PurpleAccount *account, PurpleGroup *group, const char *alias, const char *name); + static void purpleRequestAddGroup(void); + static void purpleSaveNode(PurpleBlistNode *node); + static void purpleRemoveNode(PurpleBlistNode *node); + static void purpleSaveAccount(PurpleAccount *account); + + // file transfer operations + static void purpleNewXfer(PurpleXfer *xfer); + static void purpleDestroy(PurpleXfer *xfer); + static void purpleAddXfer(PurpleXfer *xfer); + static void purpleUpdateProgress(PurpleXfer *xfer, double percent); + static void purpleCancelLocal(PurpleXfer *xfer); + static void purpleCancelRemote(PurpleXfer *xfer); + static gssize purpleWrite(PurpleXfer *xfer, const guchar *buffer, gssize size); + static gssize purpleRead(PurpleXfer *xfer, guchar **buffer, gssize size); + static void purpleDataNotSent(PurpleXfer *xfer, const guchar *buffer, gsize size); + static void purpleAddThumbnail(PurpleXfer *xfer, const gchar *formats); + + // notification operations + static void* purpeNotifyMessage(PurpleNotifyMsgType type, const char *title, const char *primary, const char *secondary, PurpleRequestCommonParameters *cpar); + static void* purpeNotifyEmail(PurpleConnection *gc, const char *subject, const char *from, const char *to, const char *url); + static void* purpeNotifyEmails(PurpleConnection *gc, size_t count, gboolean detailed, const char **subjects, const char **froms, const char **tos, const char **urls); + static void* purpeNotifyFormatted(const char *title, const char *primary, const char *secondary, const char *text); + static void* purpeNotifySearchResults(PurpleConnection *gc, const char *title, const char *primary, const char *secondary, PurpleNotifySearchResults *results, gpointer user_data); + static void purpeNotifySearchResultsNewRows(PurpleConnection *gc, PurpleNotifySearchResults *results, void *data); + static void* purpeNotifyUserInfo(PurpleConnection *gc, const char *who, PurpleNotifyUserInfo *user_info); + static void* purpeNotifyURI(const char *uri); + static void purpeNotifyClose(PurpleNotifyType type, void *ui_handle); + // 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 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); + // privacy ui operations + static void purplePermitAdded(PurpleAccount *account, const char *name); + static void purplePermitRemoved(PurpleAccount *account, const char *name); + static void purpleDebyAdded(PurpleAccount *account, const char *name); + static void purpleDenyRemoved(PurpleAccount *account, const char *name); + + // request ui operations + static void* purpleRequestInput(const char *title, const char *primary, + const char *secondary, const char *default_value, + 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); + static void* 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); + static void* 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); + static void* purpleRequestWait(const char *title, const char *primary, + const char *secondary, gboolean with_progress, + PurpleRequestCancelCb cancel_cb, + PurpleRequestCommonParameters *cpar, void *user_data); + + static void purpleRequestWaitUpdate(void *ui_handle, gboolean pulse, gfloat fraction); + static void* 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); + static void* purpleRequestFile(const char *title, const char *filename, + gboolean savedialog, GCallback ok_cb, GCallback cancel_cb, + PurpleRequestCommonParameters *cpar, void *user_data); + static void* purpleRequestFolder(const char *title, const char *dirname, + GCallback ok_cb, GCallback cancel_cb, + PurpleRequestCommonParameters *cpar, void *user_data); + static void purpleRequestClose(PurpleRequestType type, void *ui_handle); + + // connection ui operations + static void purpleConnectProgress(PurpleConnection *gc, const char *text, size_t step, size_t step_count); + static void purpleConnected(PurpleConnection *gc); + static void purpleDisonnected(PurpleConnection *gc); + static void purpleNotice(PurpleConnection *gc, const char *text); + static void purpleNetworkConnected(void); + static void purpleNetworkDisconnected(void); + static void purpleReportDisconnect(PurpleConnection *gc, PurpleConnectionError reason, const char *text); + + + // whiteboard ui operations + static void purpleCreateWB(PurpleWhiteboard *wb); + static void purpleDestroyWB(PurpleWhiteboard *wb); + static void purpleSetDimensions(PurpleWhiteboard *wb, int width, int height); + static void purpleSetBrush(PurpleWhiteboard *wb, int size, int color); + static void purpleDrawPont(PurpleWhiteboard *wb, int x, int y, int color, int size); + static void purpleDrawLine(PurpleWhiteboard *wb, int x1, int y1, int x2, int y2, int color, int size); + static void purpleClearWB(PurpleWhiteboard *wb); + + PurpleAccount* _account; }; |