summaryrefslogtreecommitdiffstats
path: root/src/uscxml
diff options
context:
space:
mode:
Diffstat (limited to 'src/uscxml')
-rw-r--r--src/uscxml/Convenience.h33
-rw-r--r--src/uscxml/Factory.h26
-rw-r--r--src/uscxml/Message.cpp24
-rw-r--r--src/uscxml/Message.h16
-rw-r--r--src/uscxml/interpreter/InterpreterDraft6.cpp3
-rw-r--r--src/uscxml/plugins/datamodel/ecmascript/TypedArray.cpp28
-rw-r--r--src/uscxml/plugins/datamodel/ecmascript/TypedArray.h20
-rw-r--r--src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp62
-rw-r--r--src/uscxml/plugins/element/file/FileElement.cpp4
-rw-r--r--src/uscxml/plugins/element/respond/RespondElement.cpp2
-rw-r--r--src/uscxml/plugins/invoker/ffmpeg/FFMPEGInvoker.cpp12
-rw-r--r--src/uscxml/plugins/invoker/im/IMInvoker.cpp697
-rw-r--r--src/uscxml/plugins/invoker/im/IMInvoker.h179
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;
};