Commit 0a78acef authored by himselfv's avatar himselfv Committed by vitalyster

Carbons (#267)

Forward own messages from legacy network

* requires XEP-280/XEP-297 enabled client and XEP-0356 enabled server
* closes #265 
parent 69b41f9d
......@@ -45,6 +45,11 @@
DEFINE_LOGGER(logger_libpurple, "libpurple");
DEFINE_LOGGER(logger, "backend");
/* Additional PURPLE_MESSAGE_* flags as a hack to track the origin of the message. */
typedef enum {
PURPLE_MESSAGE_SPECTRUM2_ORIGINATED = 0x80000000,
} PurpleMessageSpectrum2Flags;
int main_socket;
static int writeInput;
bool firstPing = true;
......@@ -542,19 +547,19 @@ class SpectrumNetworkPlugin : public NetworkPlugin {
if (xhtml.empty()) {
gchar *_markup = purple_markup_escape_text_wrapped(message.c_str(), -1);
if (purple_conversation_get_type_wrapped(conv) == PURPLE_CONV_TYPE_IM) {
purple_conv_im_send_wrapped(PURPLE_CONV_IM_WRAPPED(conv), _markup);
purple_conv_im_send_with_flags_wrapped(PURPLE_CONV_IM_WRAPPED(conv), _markup, static_cast<PurpleMessageFlags>(PURPLE_MESSAGE_SPECTRUM2_ORIGINATED));
}
else if (purple_conversation_get_type_wrapped(conv) == PURPLE_CONV_TYPE_CHAT) {
purple_conv_chat_send_wrapped(PURPLE_CONV_CHAT_WRAPPED(conv), _markup);
purple_conv_chat_send_with_flags_wrapped(PURPLE_CONV_CHAT_WRAPPED(conv), _markup, static_cast<PurpleMessageFlags>(PURPLE_MESSAGE_SPECTRUM2_ORIGINATED));
}
g_free(_markup);
}
else {
if (purple_conversation_get_type_wrapped(conv) == PURPLE_CONV_TYPE_IM) {
purple_conv_im_send_wrapped(PURPLE_CONV_IM_WRAPPED(conv), xhtml.c_str());
purple_conv_im_send_with_flags_wrapped(PURPLE_CONV_IM_WRAPPED(conv), xhtml.c_str(), static_cast<PurpleMessageFlags>(PURPLE_MESSAGE_SPECTRUM2_ORIGINATED));
}
else if (purple_conversation_get_type_wrapped(conv) == PURPLE_CONV_TYPE_CHAT) {
purple_conv_chat_send_wrapped(PURPLE_CONV_CHAT_WRAPPED(conv), xhtml.c_str());
purple_conv_chat_send_with_flags_wrapped(PURPLE_CONV_CHAT_WRAPPED(conv), xhtml.c_str(), static_cast<PurpleMessageFlags>(PURPLE_MESSAGE_SPECTRUM2_ORIGINATED));
}
}
}
......@@ -1138,7 +1143,11 @@ static PurpleBlistUiOps blistUiOps =
NULL
};
static void conv_write_im(PurpleConversation *conv, const char *who, const char *msg, PurpleMessageFlags flags, time_t mtime);
static void conv_write(PurpleConversation *conv, const char *who, const char *alias, const char *msg, PurpleMessageFlags flags, time_t mtime) {
LOG4CXX_INFO(logger, "conv_write()");
if (flags & PURPLE_MESSAGE_SYSTEM && CONFIG_STRING(config, "service.protocol") == "prpl-telegram") {
PurpleAccount *account = purple_conversation_get_account_wrapped(conv);
......@@ -1194,6 +1203,10 @@ static void conv_write(PurpleConversation *conv, const char *who, const char *al
np->handleMessage(np->m_accounts[account], np->NameToLegacyName(account, conversationName), message_, who, xhtml_, timestamp);
}
}
else {
//Handle all non-special cases by just passing them to conv_write_im
conv_write_im(conv, who, msg, flags, mtime);
}
}
static char *calculate_data_hash(guchar *data, size_t len,
......@@ -1223,9 +1236,26 @@ static char *calculate_data_hash(guchar *data, size_t len,
}
static void conv_write_im(PurpleConversation *conv, const char *who, const char *msg, PurpleMessageFlags flags, time_t mtime) {
// Don't forwards our own messages.
if (purple_conversation_get_type_wrapped(conv) == PURPLE_CONV_TYPE_IM && (flags & PURPLE_MESSAGE_SEND || flags & PURPLE_MESSAGE_SYSTEM)) {
return;
LOG4CXX_INFO(logger, "conv_write_im()");
bool isCarbon = false;
if (purple_conversation_get_type_wrapped(conv) == PURPLE_CONV_TYPE_IM) {
//Don't forwards our own messages, but do forward messages "from=us" which originated elsewhere
//(such as carbons of our messages from other legacy network clients)
if (flags & PURPLE_MESSAGE_SPECTRUM2_ORIGINATED) {
LOG4CXX_INFO(logger, "conv_write_im(): ignoring a message generated by us");
return;
}
//If this is a carbon of a message from us, mark it as such
if(flags & PURPLE_MESSAGE_SEND)
isCarbon = true;
//Originally the transport had this filter too, I'm leaving it in for now:
if (flags & PURPLE_MESSAGE_SYSTEM) {
LOG4CXX_INFO(logger, "conv_write_im(): ignoring a system message");
return;
}
}
PurpleAccount *account = purple_conversation_get_account_wrapped(conv);
......@@ -1336,12 +1366,12 @@ static void conv_write_im(PurpleConversation *conv, const char *who, const char
w.erase((int) pos, w.length() - (int) pos);
}
LOG4CXX_INFO(logger, "Received message body='" << message_ << "' xhtml='" << xhtml_ << "' name='" << w << "'");
np->handleMessage(np->m_accounts[account], w, message_, n, xhtml_, timestamp);
np->handleMessage(np->m_accounts[account], w, message_, n, xhtml_, timestamp, false, false, isCarbon);
}
else {
std::string conversationName = purple_conversation_get_name_wrapped(conv);
LOG4CXX_INFO(logger, "Received message body='" << message_ << "' xhtml='" << xhtml_ << "' name='" << conversationName << "' " << who);
np->handleMessage(np->m_accounts[account], np->NameToLegacyName(account, conversationName), message_, who, xhtml_, timestamp);
np->handleMessage(np->m_accounts[account], np->NameToLegacyName(account, conversationName), message_, who, xhtml_, timestamp, false, false, isCarbon);
}
}
......
......@@ -74,7 +74,9 @@ purple_find_conversation_with_account_wrapped_fnc purple_find_conversation_with_
purple_conversation_new_wrapped_fnc purple_conversation_new_wrapped = NULL;
purple_conversation_get_type_wrapped_fnc purple_conversation_get_type_wrapped = NULL;
purple_conv_im_send_wrapped_fnc purple_conv_im_send_wrapped = NULL;
purple_conv_im_send_with_flags_wrapped_fnc purple_conv_im_send_with_flags_wrapped = NULL;
purple_conv_chat_send_wrapped_fnc purple_conv_chat_send_wrapped = NULL;
purple_conv_chat_send_with_flags_wrapped_fnc purple_conv_chat_send_with_flags_wrapped = NULL;
purple_conversation_destroy_wrapped_fnc purple_conversation_destroy_wrapped = NULL;
purple_conversation_get_account_wrapped_fnc purple_conversation_get_account_wrapped = NULL;
purple_conversation_get_name_wrapped_fnc purple_conversation_get_name_wrapped = NULL;
......@@ -441,10 +443,18 @@ bool resolvePurpleFunctions() {
if (!purple_conv_im_send_wrapped)
return false;
purple_conv_im_send_with_flags_wrapped = (purple_conv_im_send_with_flags_wrapped_fnc)GetProcAddress(f_hPurple, "purple_conv_im_send_with_flags");
if (!purple_conv_im_send_with_flags_wrapped)
return false;
purple_conv_chat_send_wrapped = (purple_conv_chat_send_wrapped_fnc)GetProcAddress(f_hPurple, "purple_conv_chat_send");
if (!purple_conv_chat_send_wrapped)
return false;
purple_conv_chat_send_with_flags_wrapped = (purple_conv_chat_send_with_flags_wrapped_fnc)GetProcAddress(f_hPurple, "purple_conv_chat_send_with_flags");
if (!purple_conv_chat_send_with_flags_wrapped)
return false;
purple_conversation_destroy_wrapped = (purple_conversation_destroy_wrapped_fnc)GetProcAddress(f_hPurple, "purple_conversation_destroy");
if (!purple_conversation_destroy_wrapped)
return false;
......
......@@ -236,9 +236,15 @@ extern purple_conversation_update_wrapped_func purple_conversation_update_wrappe
typedef void (_cdecl * purple_conv_im_send_wrapped_fnc)(PurpleConvIm *im, const char *message);
extern purple_conv_im_send_wrapped_fnc purple_conv_im_send_wrapped;
typedef void (_cdecl * purple_conv_im_send_with_flags_wrapped_fnc)(PurpleConvIm *im, const char *message, PurpleMessageFlags flags);
extern purple_conv_im_send_with_flags_wrapped_fnc purple_conv_im_send_with_flags_wrapped;
typedef void (_cdecl * purple_conv_chat_send_wrapped_fnc)(PurpleConvChat *chat, const char *message);
extern purple_conv_chat_send_wrapped_fnc purple_conv_chat_send_wrapped;
typedef void (_cdecl * purple_conv_chat_send_with_flags_wrapped_fnc)(PurpleConvChat *chat, const char *message, PurpleMessageFlags flags);
extern purple_conv_chat_send_with_flags_wrapped_fnc purple_conv_chat_send_with_flags_wrapped;
typedef void (_cdecl * purple_conversation_destroy_wrapped_fnc)(PurpleConversation *conv);
extern purple_conversation_destroy_wrapped_fnc purple_conversation_destroy_wrapped;
......@@ -543,7 +549,9 @@ extern wpurple_g_io_channel_win32_new_socket_wrapped_fnc wpurple_g_io_channel_wi
#define purple_conversation_set_data_wrapped purple_conversation_set_data
#define purple_conversation_update_wrapped purple_conversation_update
#define purple_conv_im_send_wrapped purple_conv_im_send
#define purple_conv_im_send_with_flags_wrapped purple_conv_im_send_with_flags
#define purple_conv_chat_send_wrapped purple_conv_chat_send
#define purple_conv_chat_send_with_flags_wrapped purple_conv_chat_send_with_flags
#define purple_conversation_destroy_wrapped purple_conversation_destroy
#define purple_conversation_get_account_wrapped purple_conversation_get_account
#define purple_conversation_get_name_wrapped purple_conversation_get_name
......
......@@ -181,6 +181,7 @@ Backend sends this payload when it receives new message from legacy network whic
|message|Plain text message|
|xhtml|Message formatted using XHTML-IM XEP if available|
|nickname| If the conversation is room, this is the nickname of user who sent the original message|
|carbon| If set, the message is a carbon copy of our own message sent in a different legacy network client. It should be treated as a message FROM us, not TO us|
h3. Type: TYPE_ATTENTION, Payload: ConversationMessage
......
/*
* Implements XEP-0334: Message Processing Hints
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#include <Swiften/Elements/HintPayload.h>
namespace Swift {
HintPayload::HintPayload(Type type)
: type_(type) {
}
}
/*
* Implements XEP-0334: Message Processing Hints
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#pragma once
#include <vector>
#include <string>
#include <boost/shared_ptr.hpp>
#include <Swiften/Elements/Payload.h>
#include "Swiften/SwiftenCompat.h"
namespace Swift {
class HintPayload : public Payload {
public:
typedef SWIFTEN_SHRPTR_NAMESPACE::shared_ptr<HintPayload> ref;
enum Type { NoPermanentStore, NoStore, NoCopy, Store };
public:
HintPayload(Type type = NoCopy);
void setType(Type type) { type_ = type; }
const Type getType() { return type_; }
private:
Type type_;
};
}
/*
* Implements Privilege tag for XEP-0356: Privileged Entity
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#include <Swiften/Elements/Privilege.h>
namespace Swift {
Privilege::Privilege() {
}
}
/*
* Implements Privilege tag for XEP-0356: Privileged Entity
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#pragma once
#include <vector>
#include <string>
#include <boost/shared_ptr.hpp>
#include <Swiften/Base/API.h>
#include <Swiften/Elements/Payload.h>
#include <Swiften/Version.h>
#if (SWIFTEN_VERSION >= 0x030000)
#define SWIFTEN_SUPPORTS_FORWARDED
#include <Swiften/Elements/Forwarded.h>
#endif
#include "Swiften/SwiftenCompat.h"
namespace Swift {
class Stanza;
class Privilege : public Payload {
public:
typedef SWIFTEN_SHRPTR_NAMESPACE::shared_ptr<Privilege> ref;
#ifdef SWIFTEN_SUPPORTS_FORWARDED
typedef Swift::Forwarded Forwarded;
#else
typedef Payload Forwarded;
#endif
public:
Privilege();
void setForwarded(SWIFTEN_SHRPTR_NAMESPACE::shared_ptr<Forwarded> forwarded) { forwarded_ = forwarded; }
const SWIFTEN_SHRPTR_NAMESPACE::shared_ptr<Forwarded>& getForwarded() const { return forwarded_; }
private:
SWIFTEN_SHRPTR_NAMESPACE::shared_ptr<Forwarded> forwarded_;
};
}
/*
* Implements XEP-0334: Message Processing Hints
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#include <Swiften/Parser/PayloadParsers/HintPayloadParser.h>
namespace Swift {
HintPayloadParser::HintPayloadParser() : level_(0) {
}
void HintPayloadParser::handleStartElement(const std::string& element, const std::string& /*ns*/, const AttributeMap& /*attributes*/) {
if (level_ == 0) {
HintPayload::Type type = HintPayload::NoCopy;
if (element == "no-permanent-store") {
type = HintPayload::NoPermanentStore;
} else if (element == "no-store") {
type = HintPayload::NoStore;
} else if (element == "no-copy") {
type = HintPayload::NoCopy;
} else if (element == "store") {
type = HintPayload::Store;
}
getPayloadInternal()->setType(type);
}
++level_;
}
void HintPayloadParser::handleEndElement(const std::string&, const std::string&) {
--level_;
}
void HintPayloadParser::handleCharacterData(const std::string&) {
}
}
/*
* Implements XEP-0334: Message Processing Hints
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#pragma once
#include <Swiften/Elements/HintPayload.h>
#include <Swiften/Parser/GenericPayloadParser.h>
namespace Swift {
class HintPayloadParser : public GenericPayloadParser<HintPayload> {
public:
HintPayloadParser();
virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes);
virtual void handleEndElement(const std::string& element, const std::string&);
virtual void handleCharacterData(const std::string& data);
private:
int level_;
};
}
/*
* Implements Privilege tag for XEP-0356: Privileged Entity
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#include <Swiften/Parser/PayloadParsers/PrivilegeParser.h>
#ifdef SWIFTEN_SUPPORTS_FORWARDED
#include <Swiften/Parser/PayloadParsers/ForwardedParser.h>
#else
#include <Swiften/Parser/PayloadParserFactoryCollection.h>
#include <Swiften/Parser/PayloadParserFactory.h>
#include <Swiften/Parser/UnknownPayloadParser.h>
#endif
namespace Swift {
PrivilegeParser::PrivilegeParser(PayloadParserFactoryCollection* factories) : factories_(factories), level_(TopLevel) {
}
void PrivilegeParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) {
if (level_ == PayloadLevel) {
if (element == "forwarded" && ns == "urn:xmpp:forward:0") {
#ifdef SWIFTEN_SUPPORTS_FORWARDED
childParser_ = SWIFTEN_SHRPTR_NAMESPACE::dynamic_pointer_cast<PayloadParser>(SWIFTEN_SHRPTR_NAMESPACE::make_shared<ForwardedParser>(factories_));
#else
PayloadParserFactory* parserFactory = factories_->getPayloadParserFactory(element, ns, attributes);
if (parserFactory) {
childParser_.reset(parserFactory->createPayloadParser());
}
else {
childParser_.reset(new UnknownPayloadParser());
}
#endif
};
}
if (childParser_) {
childParser_->handleStartElement(element, ns, attributes);
}
++level_;
}
void PrivilegeParser::handleEndElement(const std::string& element, const std::string& ns) {
--level_;
if (childParser_ && level_ >= PayloadLevel) {
childParser_->handleEndElement(element, ns);
}
if (childParser_ && level_ == PayloadLevel) {
getPayloadInternal()->setForwarded(SWIFTEN_SHRPTR_NAMESPACE::dynamic_pointer_cast<Privilege::Forwarded>(childParser_->getPayload()));
childParser_.reset();
}
}
void PrivilegeParser::handleCharacterData(const std::string& data) {
if (childParser_) {
childParser_->handleCharacterData(data);
}
}
}
/*
* Implements Privilege tag for XEP-0356: Privileged Entity
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#pragma once
#include <Swiften/Base/API.h>
#include <Swiften/Elements/Privilege.h>
#include <Swiften/Parser/GenericPayloadParser.h>
namespace Swift {
class PayloadParserFactoryCollection;
class PayloadParser;
class PrivilegeParser : public GenericPayloadParser<Privilege> {
public:
PrivilegeParser(PayloadParserFactoryCollection* factories);
virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes);
virtual void handleEndElement(const std::string& element, const std::string&);
virtual void handleCharacterData(const std::string& data);
enum Level {
TopLevel = 0,
PayloadLevel = 1
};
private:
PayloadParserFactoryCollection* factories_;
SWIFTEN_SHRPTR_NAMESPACE::shared_ptr<PayloadParser> childParser_;
int level_;
};
}
/*
* Implements XEP-0334: Message Processing Hints
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#include <string>
#include <Swiften/Serializer/PayloadSerializers/HintPayloadSerializer.h>
#include <boost/shared_ptr.hpp>
#include <Swiften/Serializer/XML/XMLTextNode.h>
#include <Swiften/Serializer/XML/XMLRawTextNode.h>
#include <Swiften/Serializer/XML/XMLElement.h>
namespace Swift {
HintPayloadSerializer::HintPayloadSerializer() : GenericPayloadSerializer<HintPayload>() {
}
std::string HintPayloadSerializer::serializePayload(SWIFTEN_SHRPTR_NAMESPACE::shared_ptr<HintPayload> hint) const {
std::string tagname = "";
switch(hint->getType()) {
case HintPayload::NoPermanentStore: tagname = "no-permanent-store"; break;
case HintPayload::NoStore: tagname = "no-store"; break;
case HintPayload::NoCopy: tagname = "no-copy"; break;
case HintPayload::Store: tagname = "store"; break;
}
return XMLElement(tagname, "urn:xmpp:hints").serialize();
}
}
/*
* Implements XEP-0334: Message Processing Hints
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#pragma once
#include <Swiften/Serializer/GenericPayloadSerializer.h>
#include <Swiften/Elements/HintPayload.h>
#include "Swiften/SwiftenCompat.h"
namespace Swift {
class HintPayloadSerializer : public GenericPayloadSerializer<HintPayload> {
public:
HintPayloadSerializer();
virtual std::string serializePayload(SWIFTEN_SHRPTR_NAMESPACE::shared_ptr<HintPayload>) const;
};
}
/*
* Implements Privilege tag for XEP-0356: Privileged Entity
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#include <Swiften/Serializer/PayloadSerializers/PrivilegeSerializer.h>
#include <boost/shared_ptr.hpp>
#include <Swiften/Serializer/XML/XMLTextNode.h>
#include <Swiften/Serializer/XML/XMLRawTextNode.h>
#include <Swiften/Serializer/XML/XMLElement.h>
#ifdef SWIFTEN_SUPPORTS_FORWARDED
#include <Swiften/Elements/Forwarded.h>
#include <Swiften/Serializer/PayloadSerializers/ForwardedSerializer.h>
#else
#include <Swiften/Serializer/PayloadSerializerCollection.h>
#endif
namespace Swift {
PrivilegeSerializer::PrivilegeSerializer(PayloadSerializerCollection* serializers) : GenericPayloadSerializer<Privilege>(), serializers_(serializers) {
}
PrivilegeSerializer::~PrivilegeSerializer() {
}
std::string PrivilegeSerializer::serializePayload(SWIFTEN_SHRPTR_NAMESPACE::shared_ptr<Privilege> payload) const {
if (!payload) {
return "";
}
XMLElement element("privilege", "urn:xmpp:privilege:1");
SWIFTEN_SHRPTR_NAMESPACE::shared_ptr<Privilege::Forwarded> forwarded(payload->getForwarded());
if (forwarded) {
std::string forwardedStr = "";
#ifdef SWIFTEN_SUPPORTS_FORWARDED
forwardedStr = ForwardedSerializer(serializers_).serialize(forwarded);
#else
PayloadSerializer* serializer = serializers_->getPayloadSerializer(payload);
if(serializer) {
forwardedStr = serializer->serialize(payload);
}
#endif
element.addNode(SWIFTEN_SHRPTR_NAMESPACE::make_shared<XMLRawTextNode>(forwardedStr));
}
return element.serialize();
}
}
/*
* Implements Privilege tag for XEP-0356: Privileged Entity
* Licensed under the Simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#pragma once
#include <Swiften/Serializer/GenericPayloadSerializer.h>
#include <Swiften/Elements/Privilege.h>
#include "Swiften/SwiftenCompat.h"
namespace Swift {
class PayloadSerializerCollection;
class PrivilegeSerializer : public GenericPayloadSerializer<Privilege> {
public:
PrivilegeSerializer(PayloadSerializerCollection* serializers);
virtual ~PrivilegeSerializer();
virtual std::string serializePayload(SWIFTEN_SHRPTR_NAMESPACE::shared_ptr<Privilege>) const;
private:
PayloadSerializerCollection* serializers_;
};
}
......@@ -51,3 +51,12 @@
#define SWIFTEN_SIGNAL_CONNECTION_NAMESPACE boost::signals
#define SWIFT_HOSTADDRESS(x) Swift::HostAddress(x)
#endif
#if (SWIFTEN_VERSION >= 0x030000)
//Swiften supports carbon Sent and Received tags as well as Forwarded tags inside those
#define SWIFTEN_SUPPORTS_CARBONS
//Swiften supports Forwarded tag
#define SWIFTEN_SUPPORTS_FORWARDED
//Privilege tag is implemented locally, but it makes little sense without forwarded tag
#define SWIFTEN_SUPPORTS_PRIVILEGE
#endif
\ No newline at end of file
......@@ -64,7 +64,17 @@ class Conversation {
/// \param message Message received from legacy network.
/// \param nickname For MUC conversation this is nickname of room participant who sent this message.
void handleMessage(SWIFTEN_SHRPTR_NAMESPACE::shared_ptr<Swift::Message> &message, const std::string &nickname = "");
void handleMessage(SWIFTEN_SHRPTR_NAMESPACE::shared_ptr<Swift::Message> &message, const std::string &nickname = "", const bool carbon = false);
//Generates a carbon <sent> wrapper <message> around the given payload and delivers it
void forwardAsCarbonSent(
const SWIFTEN_SHRPTR_NAMESPACE::shared_ptr<Swift::Message> &payload,
const Swift::JID& to);
//Generates a impersonation request <message> arount the given payload and delivers it
void forwardImpersonated(
SWIFTEN_SHRPTR_NAMESPACE::shared_ptr<Swift::Message> payload,
const Swift::JID& server);
void handleRawMessage(SWIFTEN_SHRPTR_NAMESPACE::shared_ptr<Swift::Message> &message);