Merge branch 'master' of https://github.com/hanzz/libtransport
This commit is contained in:
commit
ea970de471
97 changed files with 2910 additions and 1160 deletions
|
@ -29,7 +29,7 @@ option(ENABLE_TWITTER "Build Twitter plugin" ON)
|
|||
option(ENABLE_YAHOO2 "Build Libyahoo2 plugin" ON)
|
||||
|
||||
option(ENABLE_DOCS "Build Docs" ON)
|
||||
option(ENABLE_LOG "Build with logging using Log4cxx" ON)
|
||||
# option(ENABLE_LOG "Build with logging using Log4cxx" ON)
|
||||
option(ENABLE_TESTS "Build Tests using CppUnit" OFF)
|
||||
|
||||
MACRO(LIST_CONTAINS var value)
|
||||
|
@ -109,7 +109,7 @@ endif()
|
|||
|
||||
# FIND SQLITE3
|
||||
if (ENABLE_SQLITE3)
|
||||
if (NOT CMAKE_COMPILER_IS_GNUCXX)
|
||||
if (MSVC)
|
||||
ADD_SUBDIRECTORY(${CMAKE_SOURCE_DIR}/msvc-deps)
|
||||
else()
|
||||
if (WIN32)
|
||||
|
@ -225,7 +225,7 @@ if(ENABLE_DOCS)
|
|||
find_package(Doxygen)
|
||||
endif()
|
||||
|
||||
if(ENABLE_LOG)
|
||||
# if(ENABLE_LOG)
|
||||
if(LOG4CXX_INCLUDE_DIR AND LOG4CXX_LIBRARY)
|
||||
set(LOG4CXX_LIBRARIES ${LOG4CXX_LIBRARY})
|
||||
set(LOG4CXX_FOUND 1)
|
||||
|
@ -234,7 +234,7 @@ if(ENABLE_LOG)
|
|||
set(log4cxx_DIR "${CMAKE_SOURCE_DIR}/cmake_modules")
|
||||
find_package(log4cxx)
|
||||
endif()
|
||||
endif()
|
||||
# endif()
|
||||
|
||||
# FIND CPPUNIT
|
||||
if(ENABLE_TESTS)
|
||||
|
@ -248,6 +248,16 @@ if(ENABLE_TESTS)
|
|||
endif()
|
||||
endif()
|
||||
|
||||
if (APPLE)
|
||||
FIND_LIBRARY(IOKIT_FRAMEWORK IOKit)
|
||||
FIND_LIBRARY(SECURITY_FRAMEWORK Security)
|
||||
FIND_LIBRARY(APPKIT_FRAMEWORK AppKit)
|
||||
FIND_LIBRARY(SYSTEMCONFIGURATION_FRAMEWORK SystemConfiguration)
|
||||
FIND_LIBRARY(SECURITYINTERFACE_FRAMEWORK SecurityInterface)
|
||||
MARK_AS_ADVANCED(IOKIT_FRAMEWORK APPKIT_FRAMEWORK SYSTEMCONFIGURATION_FRAMEWORK SECURITY_FRAMEWORK SECURITYINTERFACE_FRAMEWORK)
|
||||
SET (APPLE_FRAMEWORKS ${IOKIT_FRAMEWORK} ${APPKIT_FRAMEWORK} ${SYSTEMCONFIGURATION_FRAMEWORK} ${SECURITY_FRAMEWORK} ${SECURITYINTERFACE_FRAMEWORK})
|
||||
endif()
|
||||
|
||||
message(" Supported features")
|
||||
message("-----------------------")
|
||||
|
||||
|
@ -423,10 +433,10 @@ if (LOG4CXX_FOUND)
|
|||
ADD_DEFINITIONS(-DWITH_LOG4CXX)
|
||||
else()
|
||||
set(LOG4CXX_LIBRARIES "")
|
||||
if(ENABLE_LOG)
|
||||
if (WIN32)
|
||||
message("Log4cxx : no (install log4cxx-devel)")
|
||||
else(ENABLE_LOG)
|
||||
message("Log4cxx : no (user disabled)")
|
||||
else()
|
||||
message(FATAL_ERROR "Log4cxx : no (install log4cxx-devel)")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ if (PROTOBUF_FOUND)
|
|||
|
||||
if (ENABLE_SWIFTEN)
|
||||
ADD_SUBDIRECTORY(swiften)
|
||||
ADD_SUBDIRECTORY(swiften_raw)
|
||||
endif()
|
||||
|
||||
ADD_SUBDIRECTORY(template)
|
||||
|
|
|
@ -56,6 +56,7 @@ void IRCNetworkPlugin::readData() {
|
|||
if (m_servers.empty()) {
|
||||
NetworkPlugin::PluginConfig cfg;
|
||||
cfg.setNeedRegistration(false);
|
||||
cfg.setSupportMUC(true);
|
||||
sendConfig(cfg);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,10 +33,10 @@ int main (int argc, char* argv[]) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
QCoreApplication app(argc, argv);
|
||||
|
||||
Logging::initBackendLogging(cfg);
|
||||
|
||||
QCoreApplication app(argc, argv);
|
||||
|
||||
Swift::QtEventLoop eventLoop;
|
||||
|
||||
|
||||
|
|
|
@ -86,6 +86,9 @@ bool MyIrcSession::correctNickname(std::string &nickname) {
|
|||
switch(nickname.at(0)) {
|
||||
case '@': nickname = nickname.substr(1); flags = 1; break;
|
||||
case '+': nickname = nickname.substr(1); break;
|
||||
case '~': nickname = nickname.substr(1); break;
|
||||
case '&': nickname = nickname.substr(1); break;
|
||||
case '%': nickname = nickname.substr(1); break;
|
||||
default: break;
|
||||
}
|
||||
return flags;
|
||||
|
@ -96,9 +99,9 @@ void MyIrcSession::on_joined(IrcMessage *message) {
|
|||
bool op = 0;
|
||||
std::string nickname = TO_UTF8(m->sender().name());
|
||||
op = correctNickname(nickname);
|
||||
getIRCBuddy(TO_UTF8(m->channel()), nickname).setOp(op);
|
||||
np->handleParticipantChanged(user, nickname, TO_UTF8(m->channel()) + suffix, op, pbnetwork::STATUS_ONLINE);
|
||||
LOG4CXX_INFO(logger, user << ": " << nickname << " joined " << TO_UTF8(m->channel()) + suffix);
|
||||
getIRCBuddy(TO_UTF8(m->channel().toLower()), nickname).setOp(op);
|
||||
np->handleParticipantChanged(user, nickname, TO_UTF8(m->channel().toLower()) + suffix, op, pbnetwork::STATUS_ONLINE);
|
||||
LOG4CXX_INFO(logger, user << ": " << nickname << " joined " << TO_UTF8(m->channel().toLower()) + suffix);
|
||||
}
|
||||
|
||||
|
||||
|
@ -107,9 +110,9 @@ void MyIrcSession::on_parted(IrcMessage *message) {
|
|||
bool op = 0;
|
||||
std::string nickname = TO_UTF8(m->sender().name());
|
||||
op = correctNickname(nickname);
|
||||
removeIRCBuddy(TO_UTF8(m->channel()), nickname);
|
||||
LOG4CXX_INFO(logger, user << ": " << nickname << " parted " << TO_UTF8(m->channel()) + suffix);
|
||||
np->handleParticipantChanged(user, nickname, TO_UTF8(m->channel()) + suffix, op, pbnetwork::STATUS_NONE, TO_UTF8(m->reason()));
|
||||
removeIRCBuddy(TO_UTF8(m->channel().toLower()), nickname);
|
||||
LOG4CXX_INFO(logger, user << ": " << nickname << " parted " << TO_UTF8(m->channel().toLower()) + suffix);
|
||||
np->handleParticipantChanged(user, nickname, TO_UTF8(m->channel().toLower()) + suffix, op, pbnetwork::STATUS_NONE, TO_UTF8(m->reason()));
|
||||
}
|
||||
|
||||
void MyIrcSession::on_quit(IrcMessage *message) {
|
||||
|
@ -172,7 +175,7 @@ void MyIrcSession::on_topicChanged(IrcMessage *message) {
|
|||
correctNickname(nickname);
|
||||
|
||||
LOG4CXX_INFO(logger, user << ": " << nickname << " topic changed to " << TO_UTF8(m->topic()));
|
||||
np->handleSubject(user, TO_UTF8(m->channel()) + suffix, TO_UTF8(m->topic()), nickname);
|
||||
np->handleSubject(user, TO_UTF8(m->channel().toLower()) + suffix, TO_UTF8(m->topic()), nickname);
|
||||
}
|
||||
|
||||
void MyIrcSession::on_messageReceived(IrcMessage *message) {
|
||||
|
@ -190,7 +193,7 @@ void MyIrcSession::on_messageReceived(IrcMessage *message) {
|
|||
msg = QString("/me ") + msg;
|
||||
}
|
||||
|
||||
std::string target = TO_UTF8(m->target());
|
||||
std::string target = TO_UTF8(m->target().toLower());
|
||||
LOG4CXX_INFO(logger, user << ": Message from " << target);
|
||||
if (target.find("#") == 0) {
|
||||
std::string nickname = TO_UTF8(m->sender().name());
|
||||
|
@ -229,10 +232,10 @@ void MyIrcSession::on_numericMessageReceived(IrcMessage *message) {
|
|||
if (nick.find("/") != std::string::npos) {
|
||||
nick = nick.substr(0, nick.find("/"));
|
||||
}
|
||||
np->handleSubject(user, TO_UTF8(parameters[1]) + suffix, m_topicData, nick);
|
||||
np->handleSubject(user, TO_UTF8(parameters[1].toLower()) + suffix, m_topicData, nick);
|
||||
break;
|
||||
case 352: {
|
||||
channel = parameters[1];
|
||||
channel = parameters[1].toLower();
|
||||
nick = TO_UTF8(parameters[5]);
|
||||
IRCBuddy &buddy = getIRCBuddy(TO_UTF8(channel), nick);
|
||||
|
||||
|
@ -249,7 +252,7 @@ void MyIrcSession::on_numericMessageReceived(IrcMessage *message) {
|
|||
break;
|
||||
}
|
||||
case 353:
|
||||
channel = parameters[2];
|
||||
channel = parameters[2].toLower();
|
||||
members = parameters[3].split(" ");
|
||||
|
||||
LOG4CXX_INFO(logger, user << ": Received members for " << TO_UTF8(channel) << suffix);
|
||||
|
@ -265,13 +268,33 @@ void MyIrcSession::on_numericMessageReceived(IrcMessage *message) {
|
|||
break;
|
||||
case 366:
|
||||
// ask /who to get away states
|
||||
channel = parameters[1];
|
||||
channel = parameters[1].toLower();
|
||||
LOG4CXX_INFO(logger, user << "Asking /who for channel " << TO_UTF8(channel));
|
||||
sendCommand(IrcCommand::createWho(channel));
|
||||
break;
|
||||
case 432:
|
||||
np->handleDisconnected(user, pbnetwork::CONNECTION_ERROR_INVALID_USERNAME, "Erroneous Nickname");
|
||||
break;
|
||||
case 433:
|
||||
for(AutoJoinMap::iterator it = m_autoJoin.begin(); it != m_autoJoin.end(); it++) {
|
||||
np->handleParticipantChanged(user, TO_UTF8(nickName()), it->second->getChannel() + suffix, pbnetwork::PARTICIPANT_FLAG_CONFLICT);
|
||||
}
|
||||
if (suffix.empty()) {
|
||||
np->handleDisconnected(user, pbnetwork::CONNECTION_ERROR_INVALID_USERNAME, "Nickname is already in use");
|
||||
}
|
||||
break;
|
||||
case 436:
|
||||
for(AutoJoinMap::iterator it = m_autoJoin.begin(); it != m_autoJoin.end(); it++) {
|
||||
np->handleParticipantChanged(user, TO_UTF8(nickName()), it->second->getChannel() + suffix, pbnetwork::PARTICIPANT_FLAG_CONFLICT);
|
||||
}
|
||||
np->handleDisconnected(user, pbnetwork::CONNECTION_ERROR_INVALID_USERNAME, "Nickname collision KILL");
|
||||
case 464:
|
||||
for(AutoJoinMap::iterator it = m_autoJoin.begin(); it != m_autoJoin.end(); it++) {
|
||||
np->handleParticipantChanged(user, TO_UTF8(nickName()), it->second->getChannel() + suffix, pbnetwork::PARTICIPANT_FLAG_NOT_AUTHORIZED);
|
||||
}
|
||||
if (suffix.empty()) {
|
||||
np->handleDisconnected(user, pbnetwork::CONNECTION_ERROR_INVALID_USERNAME, "Password incorrect");
|
||||
}
|
||||
case 321:
|
||||
m_rooms.clear();
|
||||
m_names.clear();
|
||||
|
@ -287,6 +310,10 @@ void MyIrcSession::on_numericMessageReceived(IrcMessage *message) {
|
|||
break;
|
||||
}
|
||||
|
||||
if (m->code() >= 400 && m->code() < 500) {
|
||||
LOG4CXX_INFO(logger, user << ": Error message received: " << message->toData().data());
|
||||
}
|
||||
|
||||
//qDebug() << "numeric message received:" << receiver() << origin << code << params;
|
||||
}
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@ DEFINE_LOGGER(logger, "backend");
|
|||
|
||||
int main_socket;
|
||||
static int writeInput;
|
||||
bool firstPing = true;
|
||||
|
||||
using namespace Transport;
|
||||
|
||||
|
@ -90,6 +91,14 @@ struct FTData {
|
|||
bool paused;
|
||||
};
|
||||
|
||||
struct NodeCache {
|
||||
PurpleAccount *account;
|
||||
std::map<PurpleBlistNode *, int> nodes;
|
||||
int timer;
|
||||
};
|
||||
|
||||
bool caching = true;
|
||||
|
||||
static void *notify_user_info(PurpleConnection *gc, const char *who, PurpleNotifyUserInfo *user_info);
|
||||
|
||||
static gboolean ft_ui_ready(void *data) {
|
||||
|
@ -356,6 +365,12 @@ class SpectrumNetworkPlugin : public NetworkPlugin {
|
|||
void handleLogoutRequest(const std::string &user, const std::string &legacyName) {
|
||||
PurpleAccount *account = m_sessions[user];
|
||||
if (account) {
|
||||
if (account->ui_data) {
|
||||
NodeCache *cache = (NodeCache *) account->ui_data;
|
||||
purple_timeout_remove_wrapped(cache->timer);
|
||||
delete cache;
|
||||
account->ui_data = NULL;
|
||||
}
|
||||
if (purple_account_get_int_wrapped(account, "version", 0) != 0) {
|
||||
std::string data = stringOf(purple_account_get_int_wrapped(account, "version", 0));
|
||||
g_file_set_contents ("gfire.cfg", data.c_str(), data.size(), NULL);
|
||||
|
@ -549,6 +564,7 @@ class SpectrumNetworkPlugin : public NetworkPlugin {
|
|||
}
|
||||
purple_blist_add_buddy_wrapped(buddy, NULL, group ,NULL);
|
||||
purple_account_add_buddy_wrapped(account, buddy);
|
||||
LOG4CXX_INFO(logger, "Adding new buddy " << buddyName.c_str() << " to legacy network roster");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -804,12 +820,56 @@ static std::vector<std::string> getGroups(PurpleBuddy *m_buddy) {
|
|||
return groups;
|
||||
}
|
||||
|
||||
static void buddyListNewNode(PurpleBlistNode *node) {
|
||||
void buddyListNewNode(PurpleBlistNode *node);
|
||||
|
||||
static gboolean new_node_cache(void *data) {
|
||||
NodeCache *cache = (NodeCache *) data;
|
||||
caching = false;
|
||||
for (std::map<PurpleBlistNode *, int>::const_iterator it = cache->nodes.begin(); it != cache->nodes.end(); it++) {
|
||||
buddyListNewNode(it->first);
|
||||
}
|
||||
caching = true;
|
||||
|
||||
cache->account->ui_data = NULL;
|
||||
delete cache;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void buddyNodeRemoved(PurpleBuddyList *list, PurpleBlistNode *node) {
|
||||
if (!PURPLE_BLIST_NODE_IS_BUDDY_WRAPPED(node))
|
||||
return;
|
||||
PurpleBuddy *buddy = (PurpleBuddy *) node;
|
||||
PurpleAccount *account = purple_buddy_get_account_wrapped(buddy);
|
||||
|
||||
if (!account->ui_data) {
|
||||
return;
|
||||
}
|
||||
|
||||
NodeCache *cache = (NodeCache *) account->ui_data;
|
||||
cache->nodes.erase(node);
|
||||
}
|
||||
|
||||
void buddyListNewNode(PurpleBlistNode *node) {
|
||||
if (!PURPLE_BLIST_NODE_IS_BUDDY_WRAPPED(node))
|
||||
return;
|
||||
PurpleBuddy *buddy = (PurpleBuddy *) node;
|
||||
PurpleAccount *account = purple_buddy_get_account_wrapped(buddy);
|
||||
|
||||
if (caching) {
|
||||
if (!account->ui_data) {
|
||||
NodeCache *cache = new NodeCache;
|
||||
cache->account = account;
|
||||
cache->timer = purple_timeout_add_wrapped(400, new_node_cache, cache);
|
||||
account->ui_data = (void *) cache;
|
||||
}
|
||||
|
||||
NodeCache *cache = (NodeCache *) account->ui_data;
|
||||
cache->nodes[node] = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
std::vector<std::string> groups = getGroups(buddy);
|
||||
LOG4CXX_INFO(logger, "Buddy updated " << np->m_accounts[account] << " " << purple_buddy_get_name_wrapped(buddy) << " " << getAlias(buddy) << " group (" << groups.size() << ")=" << groups[0]);
|
||||
|
||||
|
@ -879,21 +939,35 @@ static void NodeRemoved(PurpleBlistNode *node, void *data) {
|
|||
// PurpleBuddy *buddy = (PurpleBuddy *) node;
|
||||
}
|
||||
|
||||
static void buddyListSaveNode(PurpleBlistNode *node) {
|
||||
if (!PURPLE_BLIST_NODE_IS_BUDDY(node))
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
static void buddyListSaveAccount(PurpleAccount *account) {
|
||||
}
|
||||
|
||||
static void buddyListRemoveNode(PurpleBlistNode *node) {
|
||||
if (!PURPLE_BLIST_NODE_IS_BUDDY(node))
|
||||
return;
|
||||
}
|
||||
|
||||
static PurpleBlistUiOps blistUiOps =
|
||||
{
|
||||
NULL,
|
||||
buddyListNewNode,
|
||||
NULL,
|
||||
buddyListUpdate,
|
||||
NULL, //NodeRemoved,
|
||||
buddyNodeRemoved,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL, // buddyListAddBuddy,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL, //buddyListSaveNode,
|
||||
NULL, //buddyListRemoveNode,
|
||||
NULL, //buddyListSaveAccount,
|
||||
buddyListSaveNode,
|
||||
buddyListRemoveNode,
|
||||
buddyListSaveAccount,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
@ -908,10 +982,6 @@ static void conv_write_im(PurpleConversation *conv, const char *who, const char
|
|||
// std::string msg = striped;
|
||||
// g_free(striped);
|
||||
|
||||
std::string w = purple_normalize_wrapped(account, who);
|
||||
size_t pos = w.find("/");
|
||||
if (pos != std::string::npos)
|
||||
w.erase((int) pos, w.length() - (int) pos);
|
||||
|
||||
// Escape HTML characters.
|
||||
char *newline = purple_strdup_withhtml_wrapped(msg);
|
||||
|
@ -948,11 +1018,15 @@ static void conv_write_im(PurpleConversation *conv, const char *who, const char
|
|||
// LOG4CXX_INFO(logger, "Received message body='" << message_ << "' xhtml='" << xhtml_ << "'");
|
||||
|
||||
if (purple_conversation_get_type_wrapped(conv) == PURPLE_CONV_TYPE_IM) {
|
||||
std::string w = purple_normalize_wrapped(account, who);
|
||||
size_t pos = w.find("/");
|
||||
if (pos != std::string::npos)
|
||||
w.erase((int) pos, w.length() - (int) pos);
|
||||
np->handleMessage(np->m_accounts[account], w, message_, "", xhtml_, timestamp);
|
||||
}
|
||||
else {
|
||||
LOG4CXX_INFO(logger, "Received message body='" << message_ << "' name='" << purple_conversation_get_name_wrapped(conv) << "' " << w);
|
||||
np->handleMessage(np->m_accounts[account], purple_conversation_get_name_wrapped(conv), message_, w, xhtml_, timestamp);
|
||||
LOG4CXX_INFO(logger, "Received message body='" << message_ << "' name='" << purple_conversation_get_name_wrapped(conv) << "' " << who);
|
||||
np->handleMessage(np->m_accounts[account], purple_conversation_get_name_wrapped(conv), message_, who, xhtml_, timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1099,7 +1173,7 @@ static void *notify_user_info(PurpleConnection *gc, const char *who, PurpleNotif
|
|||
else if (label=="Nickname" || label == "Nick") {
|
||||
nickname = purple_notify_user_info_entry_get_value_wrapped(vcardEntry);
|
||||
}
|
||||
else if (label=="Full Name") {
|
||||
else if (label=="Full Name" || label == "Display name") {
|
||||
fullName = purple_notify_user_info_entry_get_value_wrapped(vcardEntry);
|
||||
}
|
||||
else {
|
||||
|
@ -1655,6 +1729,14 @@ static void transportDataReceived(gpointer data, gint source, PurpleInputConditi
|
|||
exit(errno);
|
||||
}
|
||||
std::string d = std::string(buffer, n);
|
||||
|
||||
if (firstPing) {
|
||||
firstPing = false;
|
||||
NetworkPlugin::PluginConfig cfg;
|
||||
cfg.setSupportMUC(true);
|
||||
np->sendConfig(cfg);
|
||||
}
|
||||
|
||||
np->handleDataRead(d);
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
#include "glib.h"
|
||||
#include <dbus-1.0/dbus/dbus-glib-lowlevel.h>
|
||||
#include "sqlite3.h"
|
||||
#include <iostream>
|
||||
|
||||
#include "transport/config.h"
|
||||
|
@ -20,758 +22,15 @@
|
|||
#ifndef __FreeBSD__
|
||||
#include "malloc.h"
|
||||
#endif
|
||||
#include <dbus-1.0/dbus/dbus-glib-lowlevel.h>
|
||||
|
||||
#include "skype.h"
|
||||
#include "skypeplugin.h"
|
||||
|
||||
|
||||
DEFINE_LOGGER(logger, "backend");
|
||||
|
||||
using namespace Transport;
|
||||
|
||||
class SpectrumNetworkPlugin;
|
||||
|
||||
#define GET_RESPONSE_DATA(RESP, DATA) ((RESP.find(std::string(DATA) + " ") != std::string::npos) ? RESP.substr(RESP.find(DATA) + strlen(DATA) + 1) : "");
|
||||
#define GET_PROPERTY(VAR, OBJ, WHICH, PROP) std::string VAR = sk->send_command(std::string("GET ") + OBJ + " " + WHICH + " " + PROP); \
|
||||
try {\
|
||||
VAR = GET_RESPONSE_DATA(VAR, PROP);\
|
||||
}\
|
||||
catch (std::out_of_range& oor) {\
|
||||
VAR="";\
|
||||
}
|
||||
|
||||
|
||||
|
||||
SpectrumNetworkPlugin *np;
|
||||
|
||||
int m_sock;
|
||||
static int writeInput;
|
||||
|
||||
static std::string host;
|
||||
static int port = 10000;
|
||||
|
||||
DBusHandlerResult skype_notify_handler(DBusConnection *connection, DBusMessage *message, gpointer user_data);
|
||||
|
||||
static pbnetwork::StatusType getStatus(const std::string &st) {
|
||||
pbnetwork::StatusType status = pbnetwork::STATUS_ONLINE;
|
||||
if (st == "SKYPEOUT" || st == "OFFLINE") {
|
||||
status = pbnetwork::STATUS_NONE;
|
||||
}
|
||||
else if (st == "DND") {
|
||||
status = pbnetwork::STATUS_DND;
|
||||
}
|
||||
else if (st == "NA") {
|
||||
status = pbnetwork::STATUS_XA;
|
||||
}
|
||||
else if (st == "AWAY") {
|
||||
status = pbnetwork::STATUS_AWAY;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
class Skype {
|
||||
public:
|
||||
Skype(const std::string &user, const std::string &username, const std::string &password);
|
||||
~Skype() { LOG4CXX_INFO(logger, "Skype instance desctuctor"); logout(); }
|
||||
void login();
|
||||
void logout();
|
||||
std::string send_command(const std::string &message);
|
||||
|
||||
const std::string &getUser() {
|
||||
return m_user;
|
||||
}
|
||||
|
||||
const std::string &getUsername() {
|
||||
return m_username;
|
||||
}
|
||||
|
||||
bool createDBusProxy();
|
||||
bool loadSkypeBuddies();
|
||||
|
||||
int getPid() {
|
||||
return (int) m_pid;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_username;
|
||||
std::string m_password;
|
||||
GPid m_pid;
|
||||
DBusGConnection *m_connection;
|
||||
DBusGProxy *m_proxy;
|
||||
std::string m_user;
|
||||
int m_timer;
|
||||
int m_counter;
|
||||
int fd_output;
|
||||
};
|
||||
|
||||
class SpectrumNetworkPlugin : public NetworkPlugin {
|
||||
public:
|
||||
SpectrumNetworkPlugin(Config *config, const std::string &host, int port) : NetworkPlugin() {
|
||||
this->config = config;
|
||||
LOG4CXX_INFO(logger, "Starting the backend.");
|
||||
}
|
||||
|
||||
~SpectrumNetworkPlugin() {
|
||||
for (std::map<Skype *, std::string>::iterator it = m_accounts.begin(); it != m_accounts.end(); it++) {
|
||||
delete (*it).first;
|
||||
}
|
||||
}
|
||||
|
||||
void handleLoginRequest(const std::string &user, const std::string &legacyName, const std::string &password) {
|
||||
std::string name = legacyName;
|
||||
if (name.find("skype.") == 0 || name.find("prpl-skype.") == 0) {
|
||||
name = name.substr(name.find(".") + 1);
|
||||
}
|
||||
LOG4CXX_INFO(logger, "Creating account with name '" << name << "'");
|
||||
|
||||
Skype *skype = new Skype(user, name, password);
|
||||
m_sessions[user] = skype;
|
||||
m_accounts[skype] = user;
|
||||
|
||||
skype->login();
|
||||
}
|
||||
|
||||
void handleMemoryUsage(double &res, double &shared) {
|
||||
res = 0;
|
||||
shared = 0;
|
||||
for(std::map<std::string, Skype *>::const_iterator it = m_sessions.begin(); it != m_sessions.end(); it++) {
|
||||
Skype *skype = it->second;
|
||||
if (skype) {
|
||||
double r;
|
||||
double s;
|
||||
process_mem_usage(s, r, skype->getPid());
|
||||
res += r;
|
||||
shared += s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void handleLogoutRequest(const std::string &user, const std::string &legacyName) {
|
||||
Skype *skype = m_sessions[user];
|
||||
if (skype) {
|
||||
LOG4CXX_INFO(logger, "User wants to logout, logging out");
|
||||
skype->logout();
|
||||
Logging::shutdownLogging();
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void handleStatusChangeRequest(const std::string &user, int status, const std::string &statusMessage) {
|
||||
Skype *skype = m_sessions[user];
|
||||
if (!skype)
|
||||
return;
|
||||
|
||||
std::string st;
|
||||
switch(status) {
|
||||
case Swift::StatusShow::Away: {
|
||||
st = "AWAY";
|
||||
break;
|
||||
}
|
||||
case Swift::StatusShow::DND: {
|
||||
st = "DND";
|
||||
break;
|
||||
}
|
||||
case Swift::StatusShow::XA: {
|
||||
st = "NA";
|
||||
break;
|
||||
}
|
||||
case Swift::StatusShow::None: {
|
||||
break;
|
||||
}
|
||||
case pbnetwork::STATUS_INVISIBLE:
|
||||
st = "INVISIBLE";
|
||||
break;
|
||||
default:
|
||||
st = "ONLINE";
|
||||
break;
|
||||
}
|
||||
skype->send_command("SET USERSTATUS " + st);
|
||||
|
||||
if (!statusMessage.empty()) {
|
||||
skype->send_command("SET PROFILE MOOD_TEXT " + statusMessage);
|
||||
}
|
||||
}
|
||||
|
||||
void handleBuddyUpdatedRequest(const std::string &user, const std::string &buddyName, const std::string &alias, const std::vector<std::string> &groups) {
|
||||
Skype *skype = m_sessions[user];
|
||||
if (skype) {
|
||||
skype->send_command("SET USER " + buddyName + " BUDDYSTATUS 2 Please authorize me");
|
||||
skype->send_command("SET USER " + buddyName + " ISAUTHORIZED TRUE");
|
||||
}
|
||||
}
|
||||
|
||||
void handleBuddyRemovedRequest(const std::string &user, const std::string &buddyName, const std::vector<std::string> &groups) {
|
||||
Skype *skype = m_sessions[user];
|
||||
if (skype) {
|
||||
skype->send_command("SET USER " + buddyName + " BUDDYSTATUS 1");
|
||||
}
|
||||
}
|
||||
|
||||
void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml = "", const std::string &id = "") {
|
||||
Skype *skype = m_sessions[user];
|
||||
if (skype) {
|
||||
skype->send_command("MESSAGE " + legacyName + " " + message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void handleVCardRequest(const std::string &user, const std::string &legacyName, unsigned int id) {
|
||||
Skype *skype = m_sessions[user];
|
||||
if (skype) {
|
||||
std::string name = legacyName;
|
||||
if (name.find("skype.") == 0) {
|
||||
name = name.substr(6);
|
||||
}
|
||||
std::string photo;
|
||||
gchar *filename = NULL;
|
||||
gchar *new_filename = NULL;
|
||||
gchar *image_data = NULL;
|
||||
gsize image_data_len = 0;
|
||||
gchar *ret;
|
||||
int fh;
|
||||
GError *error;
|
||||
const gchar *userfiles[] = {"user256", "user1024", "user4096", "user16384", "user32768", "user65536",
|
||||
"profile256", "profile1024", "profile4096", "profile16384", "profile32768",
|
||||
NULL};
|
||||
char *username = g_strdup_printf("\x03\x10%s", name.c_str());
|
||||
for (fh = 0; userfiles[fh]; fh++) {
|
||||
filename = g_strconcat("/tmp/skype/", skype->getUsername().c_str(), "/", skype->getUsername().c_str(), "/", userfiles[fh], ".dbb", NULL);
|
||||
std::cout << "getting filename:" << filename << "\n";
|
||||
if (g_file_get_contents(filename, &image_data, &image_data_len, NULL))
|
||||
{
|
||||
std::cout << "got\n";
|
||||
char *start = (char *)memmem(image_data, image_data_len, username, strlen(username)+1);
|
||||
if (start != NULL)
|
||||
{
|
||||
char *next = image_data;
|
||||
char *last = next;
|
||||
//find last index of l33l
|
||||
while ((next = (char *)memmem(next+4, start-next-4, "l33l", 4)))
|
||||
{
|
||||
last = next;
|
||||
}
|
||||
start = last;
|
||||
if (start != NULL)
|
||||
{
|
||||
char *img_start;
|
||||
//find end of l33l block
|
||||
char *end = (char *)memmem(start+4, image_data+image_data_len-start-4, "l33l", 4);
|
||||
if (!end) end = image_data+image_data_len;
|
||||
|
||||
//look for start of JPEG block
|
||||
img_start = (char *)memmem(start, end-start, "\xFF\xD8", 2);
|
||||
if (img_start)
|
||||
{
|
||||
//look for end of JPEG block
|
||||
char *img_end = (char *)memmem(img_start, end-img_start, "\xFF\xD9", 2);
|
||||
if (img_end)
|
||||
{
|
||||
image_data_len = img_end - img_start + 2;
|
||||
photo = std::string(img_start, image_data_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
g_free(image_data);
|
||||
}
|
||||
g_free(filename);
|
||||
}
|
||||
g_free(username);
|
||||
|
||||
std::string alias = "";
|
||||
std::cout << skype->getUsername() << " " << name << "\n";
|
||||
if (skype->getUsername() == name) {
|
||||
alias = skype->send_command("GET PROFILE FULLNAME");
|
||||
alias = GET_RESPONSE_DATA(alias, "FULLNAME")
|
||||
}
|
||||
handleVCard(user, id, legacyName, "", alias, photo);
|
||||
}
|
||||
}
|
||||
|
||||
void sendData(const std::string &string) {
|
||||
write(m_sock, string.c_str(), string.size());
|
||||
// if (writeInput == 0)
|
||||
// writeInput = purple_input_add(m_sock, PURPLE_INPUT_WRITE, &transportDataReceived, NULL);
|
||||
}
|
||||
|
||||
void handleVCardUpdatedRequest(const std::string &user, const std::string &p, const std::string &nickname) {
|
||||
}
|
||||
|
||||
void handleBuddyBlockToggled(const std::string &user, const std::string &buddyName, bool blocked) {
|
||||
|
||||
}
|
||||
|
||||
void handleTypingRequest(const std::string &user, const std::string &buddyName) {
|
||||
|
||||
}
|
||||
|
||||
void handleTypedRequest(const std::string &user, const std::string &buddyName) {
|
||||
|
||||
}
|
||||
|
||||
void handleStoppedTypingRequest(const std::string &user, const std::string &buddyName) {
|
||||
|
||||
}
|
||||
|
||||
void handleAttentionRequest(const std::string &user, const std::string &buddyName, const std::string &message) {
|
||||
|
||||
}
|
||||
|
||||
std::map<std::string, Skype *> m_sessions;
|
||||
std::map<Skype *, std::string> m_accounts;
|
||||
std::map<std::string, unsigned int> m_vcards;
|
||||
Config *config;
|
||||
|
||||
};
|
||||
|
||||
|
||||
Skype::Skype(const std::string &user, const std::string &username, const std::string &password) {
|
||||
m_username = username;
|
||||
m_user = user;
|
||||
m_password = password;
|
||||
m_pid = 0;
|
||||
m_connection = 0;
|
||||
m_proxy = 0;
|
||||
m_timer = -1;
|
||||
m_counter = 0;
|
||||
}
|
||||
|
||||
|
||||
static gboolean load_skype_buddies(gpointer data) {
|
||||
Skype *skype = (Skype *) data;
|
||||
return skype->loadSkypeBuddies();
|
||||
}
|
||||
|
||||
bool Skype::createDBusProxy() {
|
||||
if (m_proxy == NULL) {
|
||||
LOG4CXX_INFO(logger, "Creating DBus proxy for com.Skype.Api.");
|
||||
m_counter++;
|
||||
|
||||
GError *error = NULL;
|
||||
m_proxy = dbus_g_proxy_new_for_name_owner (m_connection, "com.Skype.API", "/com/Skype", "com.Skype.API", &error);
|
||||
if (m_proxy == NULL && error != NULL) {
|
||||
LOG4CXX_INFO(logger, m_username << ":" << error->message);
|
||||
|
||||
if (m_counter == 15) {
|
||||
LOG4CXX_ERROR(logger, "Logging out, proxy couldn't be created: " << error->message);
|
||||
np->handleDisconnected(m_user, pbnetwork::CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE, error->message);
|
||||
logout();
|
||||
g_error_free(error);
|
||||
return FALSE;
|
||||
}
|
||||
g_error_free(error);
|
||||
}
|
||||
|
||||
if (m_proxy) {
|
||||
LOG4CXX_INFO(logger, "Proxy created.");
|
||||
DBusObjectPathVTable vtable;
|
||||
vtable.message_function = &skype_notify_handler;
|
||||
dbus_connection_register_object_path(dbus_g_connection_get_connection(m_connection), "/com/Skype/Client", &vtable, this);
|
||||
|
||||
m_counter = 0;
|
||||
m_timer = g_timeout_add_seconds(1, load_skype_buddies, this);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean create_dbus_proxy(gpointer data) {
|
||||
Skype *skype = (Skype *) data;
|
||||
return skype->createDBusProxy();
|
||||
}
|
||||
|
||||
void Skype::login() {
|
||||
if (m_username.find("..") == 0 || m_username.find("/") != std::string::npos) {
|
||||
np->handleDisconnected(m_user, pbnetwork::CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE, "Invalid username");
|
||||
return;
|
||||
}
|
||||
boost::filesystem::remove_all(std::string("/tmp/skype/") + m_username);
|
||||
|
||||
boost::filesystem::path path(std::string("/tmp/skype/") + m_username);
|
||||
if (!boost::filesystem::exists(path)) {
|
||||
boost::filesystem::create_directories(path);
|
||||
boost::filesystem::path path2(std::string("/tmp/skype/") + m_username + "/" + m_username );
|
||||
boost::filesystem::create_directories(path2);
|
||||
}
|
||||
|
||||
std::string shared_xml = "<?xml version=\"1.0\"?>\n"
|
||||
"<config version=\"1.0\" serial=\"28\" timestamp=\"" + boost::lexical_cast<std::string>(time(NULL)) + ".0\">\n"
|
||||
"<UI>\n"
|
||||
"<Installed>2</Installed>\n"
|
||||
"<Language>en</Language>\n"
|
||||
"</UI>\n"
|
||||
"</config>\n";
|
||||
g_file_set_contents(std::string(std::string("/tmp/skype/") + m_username + "/shared.xml").c_str(), shared_xml.c_str(), -1, NULL);
|
||||
|
||||
std::string config_xml = "<?xml version=\"1.0\"?>\n"
|
||||
"<config version=\"1.0\" serial=\"7\" timestamp=\"" + boost::lexical_cast<std::string>(time(NULL)) + ".0\">\n"
|
||||
"<Lib>\n"
|
||||
"<Account>\n"
|
||||
"<IdleTimeForAway>30000000</IdleTimeForAway>\n"
|
||||
"<IdleTimeForNA>300000000</IdleTimeForNA>\n"
|
||||
"<LastUsed>" + boost::lexical_cast<std::string>(time(NULL)) + "</LastUsed>\n"
|
||||
"</Account>\n"
|
||||
"</Lib>\n"
|
||||
"<UI>\n"
|
||||
"<API>\n"
|
||||
"<Authorizations>Spectrum</Authorizations>\n"
|
||||
"<BlockedPrograms></BlockedPrograms>\n"
|
||||
"</API>\n"
|
||||
"</UI>\n"
|
||||
"</config>\n";
|
||||
g_file_set_contents(std::string(std::string("/tmp/skype/") + m_username + "/" + m_username +"/config.xml").c_str(), config_xml.c_str(), -1, NULL);
|
||||
|
||||
sleep(1);
|
||||
std::string db_path = std::string("/tmp/skype/") + m_username;
|
||||
char *db = (char *) malloc(db_path.size() + 1);
|
||||
strcpy(db, db_path.c_str());
|
||||
LOG4CXX_INFO(logger, m_username << ": Spawning new Skype instance dbpath=" << db);
|
||||
gchar* argv[6] = {"skype", "--disable-cleanlooks", "--pipelogin", "--dbpath", db, 0};
|
||||
|
||||
int fd;
|
||||
GError *error = NULL;
|
||||
bool spawned = g_spawn_async_with_pipes(NULL,
|
||||
argv,
|
||||
NULL /*envp*/,
|
||||
G_SPAWN_SEARCH_PATH,
|
||||
NULL /*child_setup*/,
|
||||
NULL /*user_data*/,
|
||||
&m_pid /*child_pid*/,
|
||||
&fd,
|
||||
NULL,
|
||||
&fd_output,
|
||||
&error);
|
||||
|
||||
if (!spawned) {
|
||||
LOG4CXX_ERROR(logger, "Error spawning the Skype instance: " << error->message)
|
||||
np->handleDisconnected(m_user, pbnetwork::CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE, "Error spawning the Skype instance.");
|
||||
return;
|
||||
}
|
||||
|
||||
std::string login_data = std::string(m_username + " " + m_password + "\n");
|
||||
LOG4CXX_INFO(logger, m_username << ": Login data=" << m_username);
|
||||
write(fd, login_data.c_str(), login_data.size());
|
||||
close(fd);
|
||||
|
||||
fcntl (fd_output, F_SETFL, O_NONBLOCK);
|
||||
|
||||
free(db);
|
||||
|
||||
//Initialise threading
|
||||
dbus_threads_init_default();
|
||||
|
||||
if (m_connection == NULL)
|
||||
{
|
||||
LOG4CXX_INFO(logger, "Creating DBUS connection.");
|
||||
GError *error = NULL;
|
||||
m_connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
|
||||
if (m_connection == NULL && error != NULL)
|
||||
{
|
||||
LOG4CXX_INFO(logger, m_username << ": Creating DBUS Connection error: " << error->message);
|
||||
g_error_free(error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
sleep(1);
|
||||
m_timer = g_timeout_add_seconds(1, create_dbus_proxy, this);
|
||||
}
|
||||
|
||||
bool Skype::loadSkypeBuddies() {
|
||||
// std::string re = "CONNSTATUS OFFLINE";
|
||||
// while (re == "CONNSTATUS OFFLINE" || re.empty()) {
|
||||
// sleep(1);
|
||||
|
||||
gchar buffer[1024];
|
||||
int bytes_read = read(fd_output, buffer, 1023);
|
||||
if (bytes_read > 0) {
|
||||
buffer[bytes_read] = 0;
|
||||
std::string b(buffer);
|
||||
LOG4CXX_WARN(logger, "Skype wrote this on stdout '" << b << "'");
|
||||
if (b.find("Incorrect Password") != std::string::npos) {
|
||||
LOG4CXX_INFO(logger, "Incorrect password, logging out")
|
||||
np->handleDisconnected(m_user, pbnetwork::CONNECTION_ERROR_AUTHENTICATION_FAILED, "Incorrect password");
|
||||
close(fd_output);
|
||||
logout();
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
std::string re = send_command("NAME Spectrum");
|
||||
if (m_counter++ > 15) {
|
||||
LOG4CXX_ERROR(logger, "Logging out, because we tried to connect the Skype over DBUS 15 times without success");
|
||||
np->handleDisconnected(m_user, pbnetwork::CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE, "Skype is not ready. This issue have been logged and admins will check it and try to fix it soon.");
|
||||
close(fd_output);
|
||||
logout();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (re.empty() || re == "CONNSTATUS OFFLINE" || re == "ERROR 68") {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
close(fd_output);
|
||||
|
||||
if (send_command("PROTOCOL 7") != "PROTOCOL 7") {
|
||||
LOG4CXX_ERROR(logger, "PROTOCOL 7 failed, logging out");
|
||||
np->handleDisconnected(m_user, pbnetwork::CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE, "Skype is not ready. This issue have been logged and admins will check it and try to fix it soon.");
|
||||
logout();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
np->handleConnected(m_user);
|
||||
|
||||
std::map<std::string, std::string> group_map;
|
||||
std::string groups = send_command("SEARCH GROUPS CUSTOM");
|
||||
if (groups.find(' ') != std::string::npos) {
|
||||
groups = groups.substr(groups.find(' ') + 1);
|
||||
std::vector<std::string> grps;
|
||||
boost::split(grps, groups, boost::is_any_of(","));
|
||||
BOOST_FOREACH(std::string grp, grps) {
|
||||
std::vector<std::string> data;
|
||||
std::string name = send_command("GET GROUP " + grp + " DISPLAYNAME");
|
||||
|
||||
if (name.find("ERROR") == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
boost::split(data, name, boost::is_any_of(" "));
|
||||
name = GET_RESPONSE_DATA(name, "DISPLAYNAME");
|
||||
|
||||
std::string users = send_command("GET GROUP " + data[1] + " USERS");
|
||||
try {
|
||||
users = GET_RESPONSE_DATA(users, "USERS");
|
||||
}
|
||||
catch (std::out_of_range& oor) {
|
||||
continue;
|
||||
}
|
||||
boost::split(data, users, boost::is_any_of(","));
|
||||
BOOST_FOREACH(std::string u, data) {
|
||||
group_map[u] = grp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string friends = send_command("GET AUTH_CONTACTS_PROFILES");
|
||||
|
||||
char **full_friends_list = g_strsplit((strchr(friends.c_str(), ' ')+1), ";", 0);
|
||||
if (full_friends_list && full_friends_list[0])
|
||||
{
|
||||
//in the format of: username;full name;phone;office phone;mobile phone;
|
||||
// online status;friendly name;voicemail;mood
|
||||
// (comma-seperated lines, usernames can have comma's)
|
||||
|
||||
for (int i=0; full_friends_list[i] && full_friends_list[i+1] && *full_friends_list[i] != '\0'; i+=8)
|
||||
{
|
||||
std::string buddy = full_friends_list[i];
|
||||
|
||||
if (buddy[0] == ',') {
|
||||
buddy.erase(buddy.begin());
|
||||
}
|
||||
|
||||
if (buddy.rfind(",") != std::string::npos) {
|
||||
buddy = buddy.substr(buddy.rfind(","));
|
||||
}
|
||||
|
||||
if (buddy[0] == ',') {
|
||||
buddy.erase(buddy.begin());
|
||||
}
|
||||
|
||||
LOG4CXX_INFO(logger, "Got buddy " << buddy);
|
||||
std::string st = full_friends_list[i + 5];
|
||||
|
||||
pbnetwork::StatusType status = getStatus(st);
|
||||
|
||||
std::string alias = full_friends_list[i + 6];
|
||||
|
||||
std::string mood_text = "";
|
||||
if (full_friends_list[i + 8] && *full_friends_list[i + 8] != '\0' && *full_friends_list[i + 8] != ',') {
|
||||
mood_text = full_friends_list[i + 8];
|
||||
}
|
||||
|
||||
std::vector<std::string> groups;
|
||||
if (group_map.find(buddy) != group_map.end()) {
|
||||
groups.push_back(group_map[buddy]);
|
||||
}
|
||||
np->handleBuddyChanged(m_user, buddy, alias, groups, status, mood_text);
|
||||
}
|
||||
}
|
||||
g_strfreev(full_friends_list);
|
||||
|
||||
send_command("SET AUTOAWAY OFF");
|
||||
send_command("SET USERSTATUS ONLINE");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void Skype::logout() {
|
||||
if (m_pid != 0) {
|
||||
send_command("SET USERSTATUS INVISIBLE");
|
||||
send_command("SET USERSTATUS OFFLINE");
|
||||
sleep(2);
|
||||
g_object_unref(m_proxy);
|
||||
LOG4CXX_INFO(logger, m_username << ": Terminating Skype instance (SIGTERM)");
|
||||
kill((int) m_pid, SIGTERM);
|
||||
// Give skype a chance
|
||||
sleep(2);
|
||||
LOG4CXX_INFO(logger, m_username << ": Killing Skype instance (SIGKILL)");
|
||||
kill((int) m_pid, SIGKILL);
|
||||
m_pid = 0;
|
||||
}
|
||||
}
|
||||
|
||||
std::string Skype::send_command(const std::string &message) {
|
||||
GError *error = NULL;
|
||||
gchar *str = NULL;
|
||||
// int message_num;
|
||||
// gchar error_return[30];
|
||||
|
||||
LOG4CXX_INFO(logger, "Sending: '" << message << "'");
|
||||
if (!dbus_g_proxy_call (m_proxy, "Invoke", &error, G_TYPE_STRING, message.c_str(), G_TYPE_INVALID,
|
||||
G_TYPE_STRING, &str, G_TYPE_INVALID))
|
||||
{
|
||||
if (error && error->message)
|
||||
{
|
||||
LOG4CXX_INFO(logger, m_username << ": DBUS Error: " << error->message);
|
||||
g_error_free(error);
|
||||
return "";
|
||||
} else {
|
||||
LOG4CXX_INFO(logger, m_username << ": DBUS no response");
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
||||
if (str != NULL)
|
||||
{
|
||||
LOG4CXX_INFO(logger, m_username << ": DBUS:'" << str << "'");
|
||||
}
|
||||
return str ? std::string(str) : std::string();
|
||||
}
|
||||
|
||||
static void handle_skype_message(std::string &message, Skype *sk) {
|
||||
std::vector<std::string> cmd;
|
||||
boost::split(cmd, message, boost::is_any_of(" "));
|
||||
|
||||
if (cmd[0] == "USER") {
|
||||
if (cmd[1] == sk->getUsername()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmd[2] == "ONLINESTATUS") {
|
||||
if (cmd[3] == "SKYPEOUT" || cmd[3] == "UNKNOWN") {
|
||||
return;
|
||||
}
|
||||
else {
|
||||
pbnetwork::StatusType status = getStatus(cmd[3]);
|
||||
GET_PROPERTY(mood_text, "USER", cmd[1], "MOOD_TEXT");
|
||||
GET_PROPERTY(alias, "USER", cmd[1], "FULLNAME");
|
||||
|
||||
std::vector<std::string> groups;
|
||||
np->handleBuddyChanged(sk->getUser(), cmd[1], alias, groups, status, mood_text);
|
||||
}
|
||||
}
|
||||
else if (cmd[2] == "MOOD_TEXT") {
|
||||
GET_PROPERTY(st, "USER", cmd[1], "ONLINESTATUS");
|
||||
pbnetwork::StatusType status = getStatus(st);
|
||||
|
||||
std::string mood_text = GET_RESPONSE_DATA(message, "MOOD_TEXT");
|
||||
|
||||
std::vector<std::string> groups;
|
||||
np->handleBuddyChanged(sk->getUser(), cmd[1], "", groups, status, mood_text);
|
||||
}
|
||||
else if (cmd[2] == "BUDDYSTATUS" && cmd[3] == "3") {
|
||||
GET_PROPERTY(mood_text, "USER", cmd[1], "MOOD_TEXT");
|
||||
GET_PROPERTY(st, "USER", cmd[1], "ONLINESTATUS");
|
||||
pbnetwork::StatusType status = getStatus(st);
|
||||
|
||||
std::vector<std::string> groups;
|
||||
np->handleBuddyChanged(sk->getUser(), cmd[1], "", groups, status, mood_text);
|
||||
}
|
||||
else if (cmd[2] == "FULLNAME") {
|
||||
GET_PROPERTY(alias, "USER", cmd[1], "FULLNAME");
|
||||
GET_PROPERTY(mood_text, "USER", cmd[1], "MOOD_TEXT");
|
||||
GET_PROPERTY(st, "USER", cmd[1], "ONLINESTATUS");
|
||||
pbnetwork::StatusType status = getStatus(st);
|
||||
|
||||
std::vector<std::string> groups;
|
||||
np->handleBuddyChanged(sk->getUser(), cmd[1], alias, groups, status, mood_text);
|
||||
}
|
||||
//TODO: handle RECEIVEDAUTHREQUEST and reply it with:
|
||||
// void
|
||||
// skype_auth_allow(gpointer sender)
|
||||
// {
|
||||
// skype_send_message("SET USER %s ISAUTHORIZED TRUE", sender);
|
||||
// g_free(sender);
|
||||
// }
|
||||
//
|
||||
// void
|
||||
// skype_auth_deny(gpointer sender)
|
||||
// {
|
||||
// skype_send_message("SET USER %s ISAUTHORIZED FALSE", sender);
|
||||
// g_free(sender);
|
||||
// }
|
||||
}
|
||||
else if (cmd[0] == "CHATMESSAGE") {
|
||||
if (cmd[3] == "RECEIVED") {
|
||||
GET_PROPERTY(body, "CHATMESSAGE", cmd[1], "BODY");
|
||||
GET_PROPERTY(from_handle, "CHATMESSAGE", cmd[1], "FROM_HANDLE");
|
||||
|
||||
if (from_handle == sk->getUsername())
|
||||
return;
|
||||
|
||||
np->handleMessage(sk->getUser(), from_handle, body);
|
||||
|
||||
sk->send_command("SET CHATMESSAGE " + cmd[1] + " SEEN");
|
||||
}
|
||||
}
|
||||
else if (cmd[0] == "CALL") {
|
||||
// CALL 884 STATUS RINGING
|
||||
if (cmd[2] == "STATUS") {
|
||||
if (cmd[3] == "RINGING" || cmd[3] == "MISSED") {
|
||||
// handle only incoming calls
|
||||
GET_PROPERTY(type, "CALL", cmd[1], "TYPE");
|
||||
if (type.find("INCOMING") != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
GET_PROPERTY(from, "CALL", cmd[1], "PARTNER_HANDLE");
|
||||
GET_PROPERTY(dispname, "CALL", cmd[1], "PARTNER_DISPNAME");
|
||||
|
||||
if (cmd[3] == "RINGING") {
|
||||
np->handleMessage(sk->getUser(), from, "User " + dispname + " is calling you.");
|
||||
}
|
||||
else {
|
||||
np->handleMessage(sk->getUser(), from, "You have missed call from user " + dispname + ".");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DBusHandlerResult skype_notify_handler(DBusConnection *connection, DBusMessage *message, gpointer user_data) {
|
||||
DBusMessageIter iterator;
|
||||
gchar *message_temp;
|
||||
DBusMessage *temp_message;
|
||||
|
||||
temp_message = dbus_message_ref(message);
|
||||
dbus_message_iter_init(temp_message, &iterator);
|
||||
if (dbus_message_iter_get_arg_type(&iterator) != DBUS_TYPE_STRING)
|
||||
{
|
||||
dbus_message_unref(message);
|
||||
return (DBusHandlerResult) FALSE;
|
||||
}
|
||||
|
||||
do {
|
||||
dbus_message_iter_get_basic(&iterator, &message_temp);
|
||||
std::string m(message_temp);
|
||||
LOG4CXX_INFO(logger,"DBUS message: " << m);
|
||||
handle_skype_message(m, (Skype *) user_data);
|
||||
} while(dbus_message_iter_has_next(&iterator) && dbus_message_iter_next(&iterator));
|
||||
|
||||
dbus_message_unref(message);
|
||||
|
||||
return DBUS_HANDLER_RESULT_HANDLED;
|
||||
}
|
||||
|
||||
static void spectrum_sigchld_handler(int sig)
|
||||
{
|
||||
int status;
|
||||
|
@ -788,68 +47,24 @@ static void spectrum_sigchld_handler(int sig)
|
|||
}
|
||||
}
|
||||
|
||||
static int create_socket(const char *host, int portno) {
|
||||
struct sockaddr_in serv_addr;
|
||||
|
||||
int m_sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
memset((char *) &serv_addr, 0, sizeof(serv_addr));
|
||||
serv_addr.sin_family = AF_INET;
|
||||
serv_addr.sin_port = htons(portno);
|
||||
|
||||
hostent *hos; // Resolve name
|
||||
if ((hos = gethostbyname(host)) == NULL) {
|
||||
// strerror() will not work for gethostbyname() and hstrerror()
|
||||
// is supposedly obsolete
|
||||
Logging::shutdownLogging();
|
||||
exit(1);
|
||||
}
|
||||
serv_addr.sin_addr.s_addr = *((unsigned long *) hos->h_addr_list[0]);
|
||||
|
||||
if (connect(m_sock, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
|
||||
close(m_sock);
|
||||
m_sock = 0;
|
||||
}
|
||||
|
||||
int flags = fcntl(m_sock, F_GETFL);
|
||||
flags |= O_NONBLOCK;
|
||||
fcntl(m_sock, F_SETFL, flags);
|
||||
return m_sock;
|
||||
}
|
||||
|
||||
|
||||
static gboolean transportDataReceived(GIOChannel *source, GIOCondition condition, gpointer data) {
|
||||
char buffer[65535];
|
||||
char *ptr = buffer;
|
||||
ssize_t n = read(m_sock, ptr, sizeof(buffer));
|
||||
if (n <= 0) {
|
||||
LOG4CXX_INFO(logger, "Diconnecting from spectrum2 server");
|
||||
Logging::shutdownLogging();
|
||||
exit(errno);
|
||||
}
|
||||
std::string d = std::string(buffer, n);
|
||||
np->handleDataRead(d);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void io_destroy(gpointer data) {
|
||||
Logging::shutdownLogging();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void log_glib_error(const gchar *string) {
|
||||
LOG4CXX_ERROR(logger, "GLIB ERROR:" << string);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
#ifndef WIN32
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
if (signal(SIGCHLD, spectrum_sigchld_handler) == SIG_ERR) {
|
||||
std::cout << "SIGCHLD handler can't be set\n";
|
||||
return -1;
|
||||
}
|
||||
if (signal(SIGCHLD, spectrum_sigchld_handler) == SIG_ERR) {
|
||||
std::cout << "SIGCHLD handler can't be set\n";
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
std::string host;
|
||||
int port = 10000;
|
||||
|
||||
|
||||
std::string error;
|
||||
Config *cfg = Config::createFromArgs(argc, argv, error, host, port);
|
||||
if (cfg == NULL) {
|
||||
|
@ -861,16 +76,11 @@ int main(int argc, char **argv) {
|
|||
|
||||
g_type_init();
|
||||
|
||||
m_sock = create_socket(host.c_str(), port);
|
||||
|
||||
g_set_printerr_handler(log_glib_error);
|
||||
|
||||
GIOChannel *channel;
|
||||
GIOCondition cond = (GIOCondition) G_IO_IN;
|
||||
channel = g_io_channel_unix_new(m_sock);
|
||||
g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, cond, transportDataReceived, NULL, io_destroy);
|
||||
dbus_threads_init_default();
|
||||
|
||||
np = new SpectrumNetworkPlugin(cfg, host, port);
|
||||
SkypePlugin *np = new SkypePlugin(cfg, host, port);
|
||||
|
||||
GMainLoop *m_loop;
|
||||
m_loop = g_main_loop_new(NULL, FALSE);
|
||||
|
@ -879,4 +89,5 @@ int main(int argc, char **argv) {
|
|||
g_main_loop_run(m_loop);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
570
backends/skype/skype.cpp
Normal file
570
backends/skype/skype.cpp
Normal file
|
@ -0,0 +1,570 @@
|
|||
/**
|
||||
* libtransport -- C++ library for easy XMPP Transports development
|
||||
*
|
||||
* Copyright (C) 2011, Jan Kaluza <hanzz.k@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
|
||||
*/
|
||||
|
||||
#include "skype.h"
|
||||
#include "skypeplugin.h"
|
||||
|
||||
#include "transport/config.h"
|
||||
#include "transport/logging.h"
|
||||
#include "transport/transport.h"
|
||||
#include "transport/usermanager.h"
|
||||
#include "transport/memoryusage.h"
|
||||
#include "transport/sqlite3backend.h"
|
||||
#include "transport/userregistration.h"
|
||||
#include "transport/user.h"
|
||||
#include "transport/storagebackend.h"
|
||||
#include "transport/rostermanager.h"
|
||||
#include "transport/conversation.h"
|
||||
#include "transport/networkplugin.h"
|
||||
#include <boost/filesystem.hpp>
|
||||
#include "sys/wait.h"
|
||||
#include "sys/signal.h"
|
||||
// #include "valgrind/memcheck.h"
|
||||
#ifndef __FreeBSD__
|
||||
#include "malloc.h"
|
||||
#endif
|
||||
|
||||
|
||||
DEFINE_LOGGER(logger, "Skype");
|
||||
|
||||
Skype::Skype(SkypePlugin *np, const std::string &user, const std::string &username, const std::string &password) {
|
||||
m_username = username;
|
||||
m_user = user;
|
||||
m_password = password;
|
||||
m_pid = 0;
|
||||
m_connection = 0;
|
||||
m_proxy = 0;
|
||||
m_timer = -1;
|
||||
m_counter = 0;
|
||||
m_np = np;
|
||||
}
|
||||
|
||||
static gboolean load_skype_buddies(gpointer data) {
|
||||
Skype *skype = (Skype *) data;
|
||||
return skype->loadSkypeBuddies();
|
||||
}
|
||||
|
||||
static gboolean create_dbus_proxy(gpointer data) {
|
||||
Skype *skype = (Skype *) data;
|
||||
return skype->createDBusProxy();
|
||||
}
|
||||
|
||||
static pbnetwork::StatusType getStatus(const std::string &st) {
|
||||
pbnetwork::StatusType status = pbnetwork::STATUS_ONLINE;
|
||||
if (st == "SKYPEOUT" || st == "OFFLINE") {
|
||||
status = pbnetwork::STATUS_NONE;
|
||||
}
|
||||
else if (st == "DND") {
|
||||
status = pbnetwork::STATUS_DND;
|
||||
}
|
||||
else if (st == "NA") {
|
||||
status = pbnetwork::STATUS_XA;
|
||||
}
|
||||
else if (st == "AWAY") {
|
||||
status = pbnetwork::STATUS_AWAY;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
DBusHandlerResult skype_notify_handler(DBusConnection *connection, DBusMessage *message, gpointer data) {
|
||||
Skype *skype = (Skype *) data;
|
||||
return skype->dbusMessageReceived(connection, message);
|
||||
}
|
||||
|
||||
void Skype::login() {
|
||||
// Do not allow usernames with unsecure symbols
|
||||
if (m_username.find("..") == 0 || m_username.find("/") != std::string::npos) {
|
||||
m_np->handleDisconnected(m_user, pbnetwork::CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE, "Invalid username");
|
||||
return;
|
||||
}
|
||||
|
||||
std::string db_path = createSkypeDirectory();
|
||||
|
||||
bool spawned = spawnSkype(db_path);
|
||||
if (!spawned) {
|
||||
m_np->handleDisconnected(m_user, pbnetwork::CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE, "Error spawning the Skype instance.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (m_connection == NULL) {
|
||||
LOG4CXX_INFO(logger, "Creating DBUS connection.");
|
||||
GError *error = NULL;
|
||||
m_connection = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
|
||||
if (m_connection == NULL && error != NULL)
|
||||
{
|
||||
LOG4CXX_INFO(logger, m_username << ": Creating DBUS Connection error: " << error->message);
|
||||
g_error_free(error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_timer = g_timeout_add_seconds(1, create_dbus_proxy, this);
|
||||
}
|
||||
|
||||
bool Skype::createDBusProxy() {
|
||||
if (m_proxy == NULL) {
|
||||
LOG4CXX_INFO(logger, "Creating DBus proxy for com.Skype.Api.");
|
||||
m_counter++;
|
||||
|
||||
GError *error = NULL;
|
||||
m_proxy = dbus_g_proxy_new_for_name_owner(m_connection, "com.Skype.API", "/com/Skype", "com.Skype.API", &error);
|
||||
if (m_proxy == NULL && error != NULL) {
|
||||
LOG4CXX_INFO(logger, m_username << ":" << error->message);
|
||||
|
||||
if (m_counter == 15) {
|
||||
LOG4CXX_ERROR(logger, "Logging out, proxy couldn't be created: " << error->message);
|
||||
m_np->handleDisconnected(m_user, pbnetwork::CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE, error->message);
|
||||
logout();
|
||||
g_error_free(error);
|
||||
return FALSE;
|
||||
}
|
||||
g_error_free(error);
|
||||
}
|
||||
|
||||
if (m_proxy) {
|
||||
LOG4CXX_INFO(logger, "Proxy created.");
|
||||
DBusObjectPathVTable vtable;
|
||||
vtable.message_function = &skype_notify_handler;
|
||||
dbus_connection_register_object_path(dbus_g_connection_get_connection(m_connection), "/com/Skype/Client", &vtable, this);
|
||||
|
||||
m_counter = 0;
|
||||
m_timer = g_timeout_add_seconds(1, load_skype_buddies, this);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool Skype::loadSkypeBuddies() {
|
||||
// std::string re = "CONNSTATUS OFFLINE";
|
||||
// while (re == "CONNSTATUS OFFLINE" || re.empty()) {
|
||||
// sleep(1);
|
||||
|
||||
gchar buffer[1024];
|
||||
int bytes_read = read(fd_output, buffer, 1023);
|
||||
if (bytes_read > 0) {
|
||||
buffer[bytes_read] = 0;
|
||||
std::string b(buffer);
|
||||
LOG4CXX_WARN(logger, "Skype wrote this on stdout '" << b << "'");
|
||||
if (b.find("Incorrect Password") != std::string::npos) {
|
||||
LOG4CXX_INFO(logger, "Incorrect password, logging out")
|
||||
m_np->handleDisconnected(m_user, pbnetwork::CONNECTION_ERROR_AUTHENTICATION_FAILED, "Incorrect password");
|
||||
close(fd_output);
|
||||
logout();
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
std::string re = send_command("NAME Spectrum");
|
||||
if (m_counter++ > 15) {
|
||||
LOG4CXX_ERROR(logger, "Logging out, because we tried to connect the Skype over DBUS 15 times without success");
|
||||
m_np->handleDisconnected(m_user, pbnetwork::CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE, "Skype is not ready. This issue have been logged and admins will check it and try to fix it soon.");
|
||||
close(fd_output);
|
||||
logout();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (re.empty() || re == "CONNSTATUS OFFLINE" || re == "ERROR 68") {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
close(fd_output);
|
||||
|
||||
if (send_command("PROTOCOL 7") != "PROTOCOL 7") {
|
||||
LOG4CXX_ERROR(logger, "PROTOCOL 7 failed, logging out");
|
||||
m_np->handleDisconnected(m_user, pbnetwork::CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE, "Skype is not ready. This issue have been logged and admins will check it and try to fix it soon.");
|
||||
logout();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
m_np->handleConnected(m_user);
|
||||
|
||||
std::map<std::string, std::string> group_map;
|
||||
std::string groups = send_command("SEARCH GROUPS CUSTOM");
|
||||
if (groups.find(' ') != std::string::npos) {
|
||||
groups = groups.substr(groups.find(' ') + 1);
|
||||
std::vector<std::string> grps;
|
||||
boost::split(grps, groups, boost::is_any_of(","));
|
||||
BOOST_FOREACH(std::string grp, grps) {
|
||||
std::vector<std::string> data;
|
||||
std::string name = send_command("GET GROUP " + grp + " DISPLAYNAME");
|
||||
|
||||
if (name.find("ERROR") == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
boost::split(data, name, boost::is_any_of(" "));
|
||||
name = GET_RESPONSE_DATA(name, "DISPLAYNAME");
|
||||
|
||||
std::string users = send_command("GET GROUP " + data[1] + " USERS");
|
||||
try {
|
||||
users = GET_RESPONSE_DATA(users, "USERS");
|
||||
}
|
||||
catch (std::out_of_range& oor) {
|
||||
continue;
|
||||
}
|
||||
boost::split(data, users, boost::is_any_of(","));
|
||||
BOOST_FOREACH(std::string u, data) {
|
||||
group_map[u] = grp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string friends = send_command("GET AUTH_CONTACTS_PROFILES");
|
||||
|
||||
char **full_friends_list = g_strsplit((strchr(friends.c_str(), ' ')+1), ";", 0);
|
||||
if (full_friends_list && full_friends_list[0])
|
||||
{
|
||||
//in the format of: username;full name;phone;office phone;mobile phone;
|
||||
// online status;friendly name;voicemail;mood
|
||||
// (comma-seperated lines, usernames can have comma's)
|
||||
|
||||
for (int i=0; full_friends_list[i] && full_friends_list[i+1] && *full_friends_list[i] != '\0'; i+=8)
|
||||
{
|
||||
std::string buddy = full_friends_list[i];
|
||||
|
||||
if (buddy[0] == ',') {
|
||||
buddy.erase(buddy.begin());
|
||||
}
|
||||
|
||||
if (buddy.rfind(",") != std::string::npos) {
|
||||
buddy = buddy.substr(buddy.rfind(","));
|
||||
}
|
||||
|
||||
if (buddy[0] == ',') {
|
||||
buddy.erase(buddy.begin());
|
||||
}
|
||||
|
||||
LOG4CXX_INFO(logger, "Got buddy " << buddy);
|
||||
std::string st = full_friends_list[i + 5];
|
||||
|
||||
pbnetwork::StatusType status = getStatus(st);
|
||||
|
||||
std::string alias = full_friends_list[i + 6];
|
||||
|
||||
std::string mood_text = "";
|
||||
if (full_friends_list[i + 8] && *full_friends_list[i + 8] != '\0' && *full_friends_list[i + 8] != ',') {
|
||||
mood_text = full_friends_list[i + 8];
|
||||
}
|
||||
|
||||
std::vector<std::string> groups;
|
||||
if (group_map.find(buddy) != group_map.end()) {
|
||||
groups.push_back(group_map[buddy]);
|
||||
}
|
||||
m_np->handleBuddyChanged(m_user, buddy, alias, groups, status, mood_text);
|
||||
}
|
||||
}
|
||||
g_strfreev(full_friends_list);
|
||||
|
||||
send_command("SET AUTOAWAY OFF");
|
||||
send_command("SET USERSTATUS ONLINE");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void Skype::logout() {
|
||||
if (m_pid != 0) {
|
||||
if (m_proxy) {
|
||||
send_command("SET USERSTATUS INVISIBLE");
|
||||
send_command("SET USERSTATUS OFFLINE");
|
||||
sleep(2);
|
||||
g_object_unref(m_proxy);
|
||||
}
|
||||
LOG4CXX_INFO(logger, m_username << ": Terminating Skype instance (SIGTERM)");
|
||||
kill((int) m_pid, SIGTERM);
|
||||
// Give skype a chance
|
||||
sleep(2);
|
||||
LOG4CXX_INFO(logger, m_username << ": Killing Skype instance (SIGKILL)");
|
||||
kill((int) m_pid, SIGKILL);
|
||||
m_pid = 0;
|
||||
}
|
||||
}
|
||||
|
||||
std::string Skype::send_command(const std::string &message) {
|
||||
GError *error = NULL;
|
||||
gchar *str = NULL;
|
||||
// int message_num;
|
||||
// gchar error_return[30];
|
||||
|
||||
LOG4CXX_INFO(logger, "Sending: '" << message << "'");
|
||||
if (!dbus_g_proxy_call (m_proxy, "Invoke", &error, G_TYPE_STRING, message.c_str(), G_TYPE_INVALID,
|
||||
G_TYPE_STRING, &str, G_TYPE_INVALID))
|
||||
{
|
||||
if (error && error->message)
|
||||
{
|
||||
LOG4CXX_INFO(logger, m_username << ": DBUS Error: " << error->message);
|
||||
g_error_free(error);
|
||||
return "";
|
||||
} else {
|
||||
LOG4CXX_INFO(logger, m_username << ": DBUS no response");
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
||||
if (str != NULL)
|
||||
{
|
||||
LOG4CXX_INFO(logger, m_username << ": DBUS:'" << str << "'");
|
||||
}
|
||||
return str ? std::string(str) : std::string();
|
||||
}
|
||||
|
||||
void Skype::handleSkypeMessage(std::string &message) {
|
||||
std::vector<std::string> cmd;
|
||||
boost::split(cmd, message, boost::is_any_of(" "));
|
||||
|
||||
if (cmd[0] == "USER") {
|
||||
if (cmd[1] == getUsername()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmd[2] == "ONLINESTATUS") {
|
||||
if (cmd[3] == "SKYPEOUT" || cmd[3] == "UNKNOWN") {
|
||||
return;
|
||||
}
|
||||
else {
|
||||
pbnetwork::StatusType status = getStatus(cmd[3]);
|
||||
GET_PROPERTY(mood_text, "USER", cmd[1], "MOOD_TEXT");
|
||||
GET_PROPERTY(alias, "USER", cmd[1], "FULLNAME");
|
||||
|
||||
std::vector<std::string> groups;
|
||||
m_np->handleBuddyChanged(getUser(), cmd[1], alias, groups, status, mood_text);
|
||||
}
|
||||
}
|
||||
else if (cmd[2] == "MOOD_TEXT") {
|
||||
GET_PROPERTY(st, "USER", cmd[1], "ONLINESTATUS");
|
||||
pbnetwork::StatusType status = getStatus(st);
|
||||
|
||||
std::string mood_text = GET_RESPONSE_DATA(message, "MOOD_TEXT");
|
||||
|
||||
std::vector<std::string> groups;
|
||||
m_np->handleBuddyChanged(getUser(), cmd[1], "", groups, status, mood_text);
|
||||
}
|
||||
else if (cmd[2] == "BUDDYSTATUS" && cmd[3] == "3") {
|
||||
GET_PROPERTY(mood_text, "USER", cmd[1], "MOOD_TEXT");
|
||||
GET_PROPERTY(st, "USER", cmd[1], "ONLINESTATUS");
|
||||
pbnetwork::StatusType status = getStatus(st);
|
||||
|
||||
std::vector<std::string> groups;
|
||||
m_np->handleBuddyChanged(getUser(), cmd[1], "", groups, status, mood_text);
|
||||
}
|
||||
else if (cmd[2] == "FULLNAME") {
|
||||
GET_PROPERTY(alias, "USER", cmd[1], "FULLNAME");
|
||||
GET_PROPERTY(mood_text, "USER", cmd[1], "MOOD_TEXT");
|
||||
GET_PROPERTY(st, "USER", cmd[1], "ONLINESTATUS");
|
||||
pbnetwork::StatusType status = getStatus(st);
|
||||
|
||||
std::vector<std::string> groups;
|
||||
m_np->handleBuddyChanged(getUser(), cmd[1], alias, groups, status, mood_text);
|
||||
}
|
||||
else if(cmd[2] == "RECEIVEDAUTHREQUEST") {
|
||||
m_np->handleAuthorization(getUser(), cmd[1]);
|
||||
}
|
||||
}
|
||||
else if (cmd[0] == "GROUP") {
|
||||
// if (cmd[2] == "DISPLAYNAME") {
|
||||
// //GROUP 810 DISPLAYNAME My Friends
|
||||
// std::string grp = GET_RESPONSE_DATA(message, "DISPLAYNAME");
|
||||
// std::string users = send_command("GET GROUP " + cmd[1] + " USERS");
|
||||
// try {
|
||||
// users = GET_RESPONSE_DATA(users, "USERS");
|
||||
// }
|
||||
// catch (std::out_of_range& oor) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// std::vector<std::string> data;
|
||||
// boost::split(data, users, boost::is_any_of(","));
|
||||
// BOOST_FOREACH(std::string u, data) {
|
||||
// GET_PROPERTY(alias, "USER", u, "FULLNAME");
|
||||
// GET_PROPERTY(mood_text, "USER", u, "MOOD_TEXT");
|
||||
// GET_PROPERTY(st, "USER", u, "ONLINESTATUS");
|
||||
// pbnetwork::StatusType status = getStatus(st);
|
||||
//
|
||||
// std::vector<std::string> groups;
|
||||
// groups.push_back(grp);
|
||||
// m_np->handleBuddyChanged(getUser(), u, alias, groups, status, mood_text);
|
||||
// }
|
||||
// }
|
||||
if (cmd[2] == "NROFUSERS" && cmd[3] != "0") {
|
||||
GET_PROPERTY(grp, "GROUP", cmd[1], "DISPLAYNAME");
|
||||
std::string users = send_command("GET GROUP " + cmd[1] + " USERS");
|
||||
try {
|
||||
users = GET_RESPONSE_DATA(users, "USERS");
|
||||
}
|
||||
catch (std::out_of_range& oor) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::string> data;
|
||||
boost::split(data, users, boost::is_any_of(","));
|
||||
BOOST_FOREACH(std::string u, data) {
|
||||
GET_PROPERTY(alias, "USER", u, "FULLNAME");
|
||||
GET_PROPERTY(mood_text, "USER", u, "MOOD_TEXT");
|
||||
GET_PROPERTY(st, "USER", u, "ONLINESTATUS");
|
||||
pbnetwork::StatusType status = getStatus(st);
|
||||
|
||||
std::vector<std::string> groups;
|
||||
groups.push_back(grp);
|
||||
m_np->handleBuddyChanged(getUser(), u, alias, groups, status, mood_text);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (cmd[0] == "CHATMESSAGE") {
|
||||
if (cmd[3] == "RECEIVED") {
|
||||
GET_PROPERTY(body, "CHATMESSAGE", cmd[1], "BODY");
|
||||
GET_PROPERTY(from_handle, "CHATMESSAGE", cmd[1], "FROM_HANDLE");
|
||||
|
||||
if (from_handle == getUsername())
|
||||
return;
|
||||
|
||||
m_np->handleMessage(getUser(), from_handle, body);
|
||||
|
||||
send_command("SET CHATMESSAGE " + cmd[1] + " SEEN");
|
||||
}
|
||||
}
|
||||
else if (cmd[0] == "CALL") {
|
||||
// CALL 884 STATUS RINGING
|
||||
if (cmd[2] == "STATUS") {
|
||||
if (cmd[3] == "RINGING" || cmd[3] == "MISSED") {
|
||||
// handle only incoming calls
|
||||
GET_PROPERTY(type, "CALL", cmd[1], "TYPE");
|
||||
if (type.find("INCOMING") != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
GET_PROPERTY(from, "CALL", cmd[1], "PARTNER_HANDLE");
|
||||
GET_PROPERTY(dispname, "CALL", cmd[1], "PARTNER_DISPNAME");
|
||||
|
||||
if (cmd[3] == "RINGING") {
|
||||
m_np->handleMessage(getUser(), from, "User " + dispname + " is calling you.");
|
||||
}
|
||||
else {
|
||||
m_np->handleMessage(getUser(), from, "You have missed call from user " + dispname + ".");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DBusHandlerResult Skype::dbusMessageReceived(DBusConnection *connection, DBusMessage *message) {
|
||||
DBusMessageIter iterator;
|
||||
gchar *message_temp;
|
||||
DBusMessage *temp_message;
|
||||
|
||||
temp_message = dbus_message_ref(message);
|
||||
dbus_message_iter_init(temp_message, &iterator);
|
||||
if (dbus_message_iter_get_arg_type(&iterator) != DBUS_TYPE_STRING)
|
||||
{
|
||||
dbus_message_unref(message);
|
||||
return (DBusHandlerResult) FALSE;
|
||||
}
|
||||
|
||||
do {
|
||||
dbus_message_iter_get_basic(&iterator, &message_temp);
|
||||
std::string m(message_temp);
|
||||
LOG4CXX_INFO(logger,"DBUS message: " << m);
|
||||
handleSkypeMessage(m);
|
||||
} while(dbus_message_iter_has_next(&iterator) && dbus_message_iter_next(&iterator));
|
||||
|
||||
dbus_message_unref(message);
|
||||
|
||||
return DBUS_HANDLER_RESULT_HANDLED;
|
||||
}
|
||||
|
||||
std::string Skype::createSkypeDirectory() {
|
||||
std::string tmpdir = std::string("/tmp/skype/") + m_username;
|
||||
|
||||
// This should not be needed anymore...
|
||||
// boost::filesystem::remove_all(std::string("/tmp/skype/") + m_username);
|
||||
|
||||
boost::filesystem::path path(tmpdir);
|
||||
if (!boost::filesystem::exists(path)) {
|
||||
boost::filesystem::create_directories(path);
|
||||
boost::filesystem::path path2(tmpdir + "/" + m_username );
|
||||
boost::filesystem::create_directories(path2);
|
||||
}
|
||||
|
||||
std::string shared_xml = "<?xml version=\"1.0\"?>\n"
|
||||
"<config version=\"1.0\" serial=\"28\" timestamp=\"" + boost::lexical_cast<std::string>(time(NULL)) + ".0\">\n"
|
||||
"<UI>\n"
|
||||
"<Installed>2</Installed>\n"
|
||||
"<Language>en</Language>\n"
|
||||
"</UI>\n"
|
||||
"</config>\n";
|
||||
g_file_set_contents(std::string(tmpdir + "/shared.xml").c_str(), shared_xml.c_str(), -1, NULL);
|
||||
|
||||
std::string config_xml = "<?xml version=\"1.0\"?>\n"
|
||||
"<config version=\"1.0\" serial=\"7\" timestamp=\"" + boost::lexical_cast<std::string>(time(NULL)) + ".0\">\n"
|
||||
"<Lib>\n"
|
||||
"<Account>\n"
|
||||
"<IdleTimeForAway>30000000</IdleTimeForAway>\n"
|
||||
"<IdleTimeForNA>300000000</IdleTimeForNA>\n"
|
||||
"<LastUsed>" + boost::lexical_cast<std::string>(time(NULL)) + "</LastUsed>\n"
|
||||
"</Account>\n"
|
||||
"</Lib>\n"
|
||||
"<UI>\n"
|
||||
"<API>\n"
|
||||
"<Authorizations>Spectrum</Authorizations>\n"
|
||||
"<BlockedPrograms></BlockedPrograms>\n"
|
||||
"</API>\n"
|
||||
"</UI>\n"
|
||||
"</config>\n";
|
||||
g_file_set_contents(std::string(tmpdir + "/" + m_username +"/config.xml").c_str(), config_xml.c_str(), -1, NULL);
|
||||
|
||||
return tmpdir;
|
||||
}
|
||||
|
||||
bool Skype::spawnSkype(const std::string &db_path) {
|
||||
char *db = (char *) malloc(db_path.size() + 1);
|
||||
strcpy(db, db_path.c_str());
|
||||
LOG4CXX_INFO(logger, m_username << ": Spawning new Skype instance dbpath=" << db);
|
||||
gchar* argv[6] = {"skype", "--disable-cleanlooks", "--pipelogin", "--dbpath", db, 0};
|
||||
|
||||
int fd;
|
||||
GError *error = NULL;
|
||||
bool spawned = g_spawn_async_with_pipes(NULL,
|
||||
argv,
|
||||
NULL /*envp*/,
|
||||
G_SPAWN_SEARCH_PATH,
|
||||
NULL /*child_setup*/,
|
||||
NULL /*user_data*/,
|
||||
&m_pid /*child_pid*/,
|
||||
&fd,
|
||||
NULL,
|
||||
&fd_output,
|
||||
&error);
|
||||
|
||||
if (!spawned) {
|
||||
LOG4CXX_ERROR(logger, "Error spawning the Skype instance: " << error->message)
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string login_data = std::string(m_username + " " + m_password + "\n");
|
||||
LOG4CXX_INFO(logger, m_username << ": Login data=" << m_username);
|
||||
write(fd, login_data.c_str(), login_data.size());
|
||||
close(fd);
|
||||
|
||||
fcntl (fd_output, F_SETFL, O_NONBLOCK);
|
||||
|
||||
free(db);
|
||||
|
||||
return true;
|
||||
}
|
91
backends/skype/skype.h
Normal file
91
backends/skype/skype.h
Normal file
|
@ -0,0 +1,91 @@
|
|||
/**
|
||||
* libtransport -- C++ library for easy XMPP Transports development
|
||||
*
|
||||
* Copyright (C) 2011, Jan Kaluza <hanzz.k@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "glib.h"
|
||||
#include <dbus-1.0/dbus/dbus-glib-lowlevel.h>
|
||||
#include "sqlite3.h"
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
|
||||
#define GET_RESPONSE_DATA(RESP, DATA) ((RESP.find(std::string(DATA) + " ") != std::string::npos) ? RESP.substr(RESP.find(DATA) + strlen(DATA) + 1) : "");
|
||||
#define GET_PROPERTY(VAR, OBJ, WHICH, PROP) std::string VAR = send_command(std::string("GET ") + OBJ + " " + WHICH + " " + PROP); \
|
||||
try {\
|
||||
VAR = GET_RESPONSE_DATA(VAR, PROP);\
|
||||
}\
|
||||
catch (std::out_of_range& oor) {\
|
||||
VAR="";\
|
||||
}
|
||||
|
||||
class SkypePlugin;
|
||||
|
||||
class Skype {
|
||||
public:
|
||||
Skype(SkypePlugin *np, const std::string &user, const std::string &username, const std::string &password);
|
||||
|
||||
virtual ~Skype() {
|
||||
logout();
|
||||
}
|
||||
|
||||
void login();
|
||||
|
||||
void logout();
|
||||
|
||||
std::string send_command(const std::string &message);
|
||||
|
||||
const std::string &getUser() {
|
||||
return m_user;
|
||||
}
|
||||
|
||||
const std::string &getUsername() {
|
||||
return m_username;
|
||||
}
|
||||
|
||||
int getPid() {
|
||||
return (int) m_pid;
|
||||
}
|
||||
|
||||
public: // but do not use them, should be used only internally
|
||||
bool createDBusProxy();
|
||||
|
||||
bool loadSkypeBuddies();
|
||||
|
||||
void handleSkypeMessage(std::string &message);
|
||||
|
||||
DBusHandlerResult dbusMessageReceived(DBusConnection *connection, DBusMessage *message);
|
||||
|
||||
private:
|
||||
std::string createSkypeDirectory();
|
||||
bool spawnSkype(const std::string &db_path);
|
||||
|
||||
std::string m_username;
|
||||
std::string m_password;
|
||||
GPid m_pid;
|
||||
DBusGConnection *m_connection;
|
||||
DBusGProxy *m_proxy;
|
||||
std::string m_user;
|
||||
int m_timer;
|
||||
int m_counter;
|
||||
int fd_output;
|
||||
std::map<std::string, std::string> m_groups;
|
||||
SkypePlugin *m_np;
|
||||
};
|
||||
|
115
backends/skype/skypedb.cpp
Normal file
115
backends/skype/skypedb.cpp
Normal file
|
@ -0,0 +1,115 @@
|
|||
/**
|
||||
* libtransport -- C++ library for easy XMPP Transports development
|
||||
*
|
||||
* Copyright (C) 2011, Jan Kaluza <hanzz.k@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
|
||||
*/
|
||||
|
||||
#include "skypedb.h"
|
||||
|
||||
#include "transport/config.h"
|
||||
#include "transport/logging.h"
|
||||
#include "transport/transport.h"
|
||||
#include "transport/usermanager.h"
|
||||
#include "transport/memoryusage.h"
|
||||
#include "transport/sqlite3backend.h"
|
||||
#include "transport/userregistration.h"
|
||||
#include "transport/user.h"
|
||||
#include "transport/storagebackend.h"
|
||||
#include "transport/rostermanager.h"
|
||||
#include "transport/conversation.h"
|
||||
#include "transport/networkplugin.h"
|
||||
#include <boost/filesystem.hpp>
|
||||
#include "sys/wait.h"
|
||||
#include "sys/signal.h"
|
||||
// #include "valgrind/memcheck.h"
|
||||
#ifndef __FreeBSD__
|
||||
#include "malloc.h"
|
||||
#endif
|
||||
|
||||
// Prepare the SQL statement
|
||||
#define PREP_STMT(sql, str) \
|
||||
if(sqlite3_prepare_v2(db, std::string(str).c_str(), -1, &sql, NULL)) { \
|
||||
LOG4CXX_ERROR(logger, str<< (sqlite3_errmsg(db) == NULL ? "" : sqlite3_errmsg(db))); \
|
||||
sql = NULL; \
|
||||
}
|
||||
|
||||
// Finalize the prepared statement
|
||||
#define FINALIZE_STMT(prep) \
|
||||
if(prep != NULL) { \
|
||||
sqlite3_finalize(prep); \
|
||||
}
|
||||
|
||||
#define BEGIN(STATEMENT) sqlite3_reset(STATEMENT);\
|
||||
int STATEMENT##_id = 1;\
|
||||
int STATEMENT##_id_get = 0;\
|
||||
(void)STATEMENT##_id_get;
|
||||
|
||||
#define BIND_INT(STATEMENT, VARIABLE) sqlite3_bind_int(STATEMENT, STATEMENT##_id++, VARIABLE)
|
||||
#define BIND_STR(STATEMENT, VARIABLE) sqlite3_bind_text(STATEMENT, STATEMENT##_id++, VARIABLE.c_str(), -1, SQLITE_STATIC)
|
||||
#define RESET_GET_COUNTER(STATEMENT) STATEMENT##_id_get = 0;
|
||||
#define GET_INT(STATEMENT) sqlite3_column_int(STATEMENT, STATEMENT##_id_get++)
|
||||
#define GET_STR(STATEMENT) (const char *) sqlite3_column_text(STATEMENT, STATEMENT##_id_get++)
|
||||
#define GET_BLOB(STATEMENT) (const void *) sqlite3_column_blob(STATEMENT, STATEMENT##_id_get++)
|
||||
#define EXECUTE_STATEMENT(STATEMENT, NAME) if(sqlite3_step(STATEMENT) != SQLITE_DONE) {\
|
||||
LOG4CXX_ERROR(logger, NAME<< (sqlite3_errmsg(db) == NULL ? "" : sqlite3_errmsg(db)));\
|
||||
}
|
||||
|
||||
using namespace Transport;
|
||||
|
||||
DEFINE_LOGGER(logger, "SkypeDB");
|
||||
|
||||
namespace SkypeDB {
|
||||
|
||||
bool getAvatar(const std::string &db_path, const std::string &name, std::string &photo) {
|
||||
bool ret = false;
|
||||
sqlite3 *db;
|
||||
LOG4CXX_INFO(logger, "Opening database " << db_path);
|
||||
if (sqlite3_open(db_path.c_str(), &db)) {
|
||||
sqlite3_close(db);
|
||||
LOG4CXX_ERROR(logger, "Can't open database");
|
||||
}
|
||||
else {
|
||||
sqlite3_stmt *stmt;
|
||||
PREP_STMT(stmt, "SELECT avatar_image FROM Contacts WHERE skypename=?");
|
||||
if (stmt) {
|
||||
BEGIN(stmt);
|
||||
BIND_STR(stmt, name);
|
||||
if(sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
int size = sqlite3_column_bytes(stmt, 0);
|
||||
const void *data = sqlite3_column_blob(stmt, 0);
|
||||
photo = std::string((const char *)data + 1, size - 1);
|
||||
ret = true;
|
||||
}
|
||||
else {
|
||||
LOG4CXX_ERROR(logger, (sqlite3_errmsg(db) == NULL ? "" : sqlite3_errmsg(db)));
|
||||
}
|
||||
|
||||
int ret;
|
||||
while((ret = sqlite3_step(stmt)) == SQLITE_ROW) {
|
||||
}
|
||||
FINALIZE_STMT(stmt);
|
||||
}
|
||||
else {
|
||||
LOG4CXX_ERROR(logger, "Can't created prepared statement");
|
||||
LOG4CXX_ERROR(logger, (sqlite3_errmsg(db) == NULL ? "" : sqlite3_errmsg(db)));
|
||||
}
|
||||
sqlite3_close(db);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
33
backends/skype/skypedb.h
Normal file
33
backends/skype/skypedb.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
/**
|
||||
* libtransport -- C++ library for easy XMPP Transports development
|
||||
*
|
||||
* Copyright (C) 2011, Jan Kaluza <hanzz.k@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "glib.h"
|
||||
#include <dbus-1.0/dbus/dbus-glib-lowlevel.h>
|
||||
#include "sqlite3.h"
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
|
||||
namespace SkypeDB {
|
||||
bool getAvatar(const std::string &db, const std::string &name, std::string &avatar);
|
||||
|
||||
}
|
||||
|
349
backends/skype/skypeplugin.cpp
Normal file
349
backends/skype/skypeplugin.cpp
Normal file
|
@ -0,0 +1,349 @@
|
|||
/**
|
||||
* libtransport -- C++ library for easy XMPP Transports development
|
||||
*
|
||||
* Copyright (C) 2011, Jan Kaluza <hanzz.k@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
|
||||
*/
|
||||
|
||||
#include "skypeplugin.h"
|
||||
#include "skype.h"
|
||||
#include "skypedb.h"
|
||||
|
||||
#include "transport/config.h"
|
||||
#include "transport/logging.h"
|
||||
#include "transport/transport.h"
|
||||
#include "transport/usermanager.h"
|
||||
#include "transport/memoryusage.h"
|
||||
#include "transport/sqlite3backend.h"
|
||||
#include "transport/userregistration.h"
|
||||
#include "transport/user.h"
|
||||
#include "transport/storagebackend.h"
|
||||
#include "transport/rostermanager.h"
|
||||
#include "transport/conversation.h"
|
||||
#include "transport/networkplugin.h"
|
||||
#include <boost/filesystem.hpp>
|
||||
#include "sys/wait.h"
|
||||
#include "sys/signal.h"
|
||||
// #include "valgrind/memcheck.h"
|
||||
#ifndef __FreeBSD__
|
||||
#include "malloc.h"
|
||||
#endif
|
||||
|
||||
// Prepare the SQL statement
|
||||
#define PREP_STMT(sql, str) \
|
||||
if(sqlite3_prepare_v2(db, std::string(str).c_str(), -1, &sql, NULL)) { \
|
||||
LOG4CXX_ERROR(logger, str<< (sqlite3_errmsg(db) == NULL ? "" : sqlite3_errmsg(db))); \
|
||||
sql = NULL; \
|
||||
}
|
||||
|
||||
// Finalize the prepared statement
|
||||
#define FINALIZE_STMT(prep) \
|
||||
if(prep != NULL) { \
|
||||
sqlite3_finalize(prep); \
|
||||
}
|
||||
|
||||
#define BEGIN(STATEMENT) sqlite3_reset(STATEMENT);\
|
||||
int STATEMENT##_id = 1;\
|
||||
int STATEMENT##_id_get = 0;\
|
||||
(void)STATEMENT##_id_get;
|
||||
|
||||
#define BIND_INT(STATEMENT, VARIABLE) sqlite3_bind_int(STATEMENT, STATEMENT##_id++, VARIABLE)
|
||||
#define BIND_STR(STATEMENT, VARIABLE) sqlite3_bind_text(STATEMENT, STATEMENT##_id++, VARIABLE.c_str(), -1, SQLITE_STATIC)
|
||||
#define RESET_GET_COUNTER(STATEMENT) STATEMENT##_id_get = 0;
|
||||
#define GET_INT(STATEMENT) sqlite3_column_int(STATEMENT, STATEMENT##_id_get++)
|
||||
#define GET_STR(STATEMENT) (const char *) sqlite3_column_text(STATEMENT, STATEMENT##_id_get++)
|
||||
#define GET_BLOB(STATEMENT) (const void *) sqlite3_column_blob(STATEMENT, STATEMENT##_id_get++)
|
||||
#define EXECUTE_STATEMENT(STATEMENT, NAME) if(sqlite3_step(STATEMENT) != SQLITE_DONE) {\
|
||||
LOG4CXX_ERROR(logger, NAME<< (sqlite3_errmsg(db) == NULL ? "" : sqlite3_errmsg(db)));\
|
||||
}
|
||||
|
||||
using namespace Transport;
|
||||
|
||||
DEFINE_LOGGER(logger, "SkypePlugin");
|
||||
|
||||
static int m_sock;
|
||||
|
||||
static gboolean transportDataReceived(GIOChannel *source, GIOCondition condition, gpointer data) {
|
||||
SkypePlugin *np = (SkypePlugin *) data;
|
||||
char buffer[65535];
|
||||
char *ptr = buffer;
|
||||
ssize_t n = read(m_sock, ptr, sizeof(buffer));
|
||||
if (n <= 0) {
|
||||
LOG4CXX_INFO(logger, "Diconnecting from spectrum2 server");
|
||||
Logging::shutdownLogging();
|
||||
exit(errno);
|
||||
}
|
||||
std::string d = std::string(buffer, n);
|
||||
np->handleDataRead(d);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int create_socket(const char *host, int portno) {
|
||||
struct sockaddr_in serv_addr;
|
||||
|
||||
int m_sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
memset((char *) &serv_addr, 0, sizeof(serv_addr));
|
||||
serv_addr.sin_family = AF_INET;
|
||||
serv_addr.sin_port = htons(portno);
|
||||
|
||||
hostent *hos; // Resolve name
|
||||
if ((hos = gethostbyname(host)) == NULL) {
|
||||
// strerror() will not work for gethostbyname() and hstrerror()
|
||||
// is supposedly obsolete
|
||||
Logging::shutdownLogging();
|
||||
exit(1);
|
||||
}
|
||||
serv_addr.sin_addr.s_addr = *((unsigned long *) hos->h_addr_list[0]);
|
||||
|
||||
if (connect(m_sock, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
|
||||
close(m_sock);
|
||||
m_sock = 0;
|
||||
}
|
||||
|
||||
int flags = fcntl(m_sock, F_GETFL);
|
||||
flags |= O_NONBLOCK;
|
||||
fcntl(m_sock, F_SETFL, flags);
|
||||
return m_sock;
|
||||
}
|
||||
|
||||
static void io_destroy(gpointer data) {
|
||||
Logging::shutdownLogging();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
SkypePlugin::SkypePlugin(Config *config, const std::string &host, int port) : NetworkPlugin() {
|
||||
this->config = config;
|
||||
LOG4CXX_INFO(logger, "Starting the backend.");
|
||||
|
||||
m_sock = create_socket(host.c_str(), port);
|
||||
GIOChannel *channel;
|
||||
GIOCondition cond = (GIOCondition) G_IO_IN;
|
||||
channel = g_io_channel_unix_new(m_sock);
|
||||
g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, cond, transportDataReceived, this, io_destroy);
|
||||
}
|
||||
|
||||
SkypePlugin::~SkypePlugin() {
|
||||
for (std::map<Skype *, std::string>::iterator it = m_accounts.begin(); it != m_accounts.end(); it++) {
|
||||
delete (*it).first;
|
||||
}
|
||||
}
|
||||
|
||||
void SkypePlugin::handleLoginRequest(const std::string &user, const std::string &legacyName, const std::string &password) {
|
||||
std::string name = legacyName;
|
||||
if (name.find("skype.") == 0 || name.find("prpl-skype.") == 0) {
|
||||
name = name.substr(name.find(".") + 1);
|
||||
}
|
||||
LOG4CXX_INFO(logger, "Creating account with name '" << name << "'");
|
||||
|
||||
Skype *skype = new Skype(this, user, name, password);
|
||||
m_sessions[user] = skype;
|
||||
m_accounts[skype] = user;
|
||||
|
||||
skype->login();
|
||||
}
|
||||
|
||||
void SkypePlugin::handleMemoryUsage(double &res, double &shared) {
|
||||
res = 0;
|
||||
shared = 0;
|
||||
for(std::map<std::string, Skype *>::const_iterator it = m_sessions.begin(); it != m_sessions.end(); it++) {
|
||||
Skype *skype = it->second;
|
||||
if (skype) {
|
||||
double r;
|
||||
double s;
|
||||
process_mem_usage(s, r, skype->getPid());
|
||||
res += r;
|
||||
shared += s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SkypePlugin::handleLogoutRequest(const std::string &user, const std::string &legacyName) {
|
||||
Skype *skype = m_sessions[user];
|
||||
if (skype) {
|
||||
LOG4CXX_INFO(logger, "User wants to logout, logging out");
|
||||
skype->logout();
|
||||
Logging::shutdownLogging();
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void SkypePlugin::handleStatusChangeRequest(const std::string &user, int status, const std::string &statusMessage) {
|
||||
Skype *skype = m_sessions[user];
|
||||
if (!skype)
|
||||
return;
|
||||
|
||||
std::string st;
|
||||
switch(status) {
|
||||
case Swift::StatusShow::Away: {
|
||||
st = "AWAY";
|
||||
break;
|
||||
}
|
||||
case Swift::StatusShow::DND: {
|
||||
st = "DND";
|
||||
break;
|
||||
}
|
||||
case Swift::StatusShow::XA: {
|
||||
st = "NA";
|
||||
break;
|
||||
}
|
||||
case Swift::StatusShow::None: {
|
||||
break;
|
||||
}
|
||||
case pbnetwork::STATUS_INVISIBLE:
|
||||
st = "INVISIBLE";
|
||||
break;
|
||||
default:
|
||||
st = "ONLINE";
|
||||
break;
|
||||
}
|
||||
skype->send_command("SET USERSTATUS " + st);
|
||||
|
||||
if (!statusMessage.empty()) {
|
||||
skype->send_command("SET PROFILE MOOD_TEXT " + statusMessage);
|
||||
}
|
||||
}
|
||||
|
||||
void SkypePlugin::handleBuddyUpdatedRequest(const std::string &user, const std::string &buddyName, const std::string &alias, const std::vector<std::string> &groups) {
|
||||
Skype *skype = m_sessions[user];
|
||||
if (skype) {
|
||||
skype->send_command("SET USER " + buddyName + " BUDDYSTATUS 2 Please authorize me");
|
||||
skype->send_command("SET USER " + buddyName + " ISAUTHORIZED TRUE");
|
||||
}
|
||||
}
|
||||
|
||||
void SkypePlugin::handleBuddyRemovedRequest(const std::string &user, const std::string &buddyName, const std::vector<std::string> &groups) {
|
||||
Skype *skype = m_sessions[user];
|
||||
if (skype) {
|
||||
skype->send_command("SET USER " + buddyName + " BUDDYSTATUS 1");
|
||||
skype->send_command("SET USER " + buddyName + " ISAUTHORIZED FALSE");
|
||||
}
|
||||
}
|
||||
|
||||
void SkypePlugin::handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml, const std::string &id) {
|
||||
Skype *skype = m_sessions[user];
|
||||
if (skype) {
|
||||
skype->send_command("MESSAGE " + legacyName + " " + message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SkypePlugin::handleVCardRequest(const std::string &user, const std::string &legacyName, unsigned int id) {
|
||||
Skype *skype = m_sessions[user];
|
||||
if (skype) {
|
||||
std::string name = legacyName;
|
||||
if (name.find("skype.") == 0) {
|
||||
name = name.substr(6);
|
||||
}
|
||||
std::string photo;
|
||||
gchar *filename = NULL;
|
||||
gchar *new_filename = NULL;
|
||||
gchar *image_data = NULL;
|
||||
gsize image_data_len = 0;
|
||||
gchar *ret;
|
||||
int fh;
|
||||
GError *error;
|
||||
const gchar *userfiles[] = {"user256", "user1024", "user4096", "user16384", "user32768", "user65536",
|
||||
"profile256", "profile1024", "profile4096", "profile16384", "profile32768",
|
||||
NULL};
|
||||
char *username = g_strdup_printf("\x03\x10%s", name.c_str());
|
||||
for (fh = 0; userfiles[fh]; fh++) {
|
||||
filename = g_strconcat("/tmp/skype/", skype->getUsername().c_str(), "/", skype->getUsername().c_str(), "/", userfiles[fh], ".dbb", NULL);
|
||||
std::cout << "getting filename:" << filename << "\n";
|
||||
if (g_file_get_contents(filename, &image_data, &image_data_len, NULL))
|
||||
{
|
||||
std::cout << "got\n";
|
||||
char *start = (char *)memmem(image_data, image_data_len, username, strlen(username)+1);
|
||||
if (start != NULL)
|
||||
{
|
||||
char *next = image_data;
|
||||
char *last = next;
|
||||
//find last index of l33l
|
||||
while ((next = (char *)memmem(next+4, start-next-4, "l33l", 4)))
|
||||
{
|
||||
last = next;
|
||||
}
|
||||
start = last;
|
||||
if (start != NULL)
|
||||
{
|
||||
char *img_start;
|
||||
//find end of l33l block
|
||||
char *end = (char *)memmem(start+4, image_data+image_data_len-start-4, "l33l", 4);
|
||||
if (!end) end = image_data+image_data_len;
|
||||
|
||||
//look for start of JPEG block
|
||||
img_start = (char *)memmem(start, end-start, "\xFF\xD8", 2);
|
||||
if (img_start)
|
||||
{
|
||||
//look for end of JPEG block
|
||||
char *img_end = (char *)memmem(img_start, end-img_start, "\xFF\xD9", 2);
|
||||
if (img_end)
|
||||
{
|
||||
image_data_len = img_end - img_start + 2;
|
||||
photo = std::string(img_start, image_data_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
g_free(image_data);
|
||||
}
|
||||
g_free(filename);
|
||||
}
|
||||
g_free(username);
|
||||
|
||||
if (photo.empty()) {
|
||||
std::string db_path = std::string("/tmp/skype/") + skype->getUsername() + "/" + skype->getUsername() + "/main.db";
|
||||
SkypeDB::getAvatar(db_path, name, photo);
|
||||
}
|
||||
|
||||
std::string alias;
|
||||
std::cout << skype->getUsername() << " " << name << "\n";
|
||||
if (skype->getUsername() == name) {
|
||||
alias = skype->send_command("GET PROFILE FULLNAME");
|
||||
alias = GET_RESPONSE_DATA(alias, "FULLNAME")
|
||||
}
|
||||
handleVCard(user, id, legacyName, "", alias, photo);
|
||||
}
|
||||
}
|
||||
|
||||
void SkypePlugin::sendData(const std::string &string) {
|
||||
write(m_sock, string.c_str(), string.size());
|
||||
// if (writeInput == 0)
|
||||
// writeInput = purple_input_add(m_sock, PURPLE_INPUT_WRITE, &transportDataReceived, NULL);
|
||||
}
|
||||
|
||||
void SkypePlugin::handleVCardUpdatedRequest(const std::string &user, const std::string &p, const std::string &nickname) {
|
||||
}
|
||||
|
||||
void SkypePlugin::handleBuddyBlockToggled(const std::string &user, const std::string &buddyName, bool blocked) {
|
||||
|
||||
}
|
||||
|
||||
void SkypePlugin::handleTypingRequest(const std::string &user, const std::string &buddyName) {
|
||||
|
||||
}
|
||||
|
||||
void SkypePlugin::handleTypedRequest(const std::string &user, const std::string &buddyName) {
|
||||
|
||||
}
|
||||
|
||||
void SkypePlugin::handleStoppedTypingRequest(const std::string &user, const std::string &buddyName) {
|
||||
|
||||
}
|
||||
|
||||
void SkypePlugin::handleAttentionRequest(const std::string &user, const std::string &buddyName, const std::string &message) {
|
||||
|
||||
}
|
||||
|
74
backends/skype/skypeplugin.h
Normal file
74
backends/skype/skypeplugin.h
Normal file
|
@ -0,0 +1,74 @@
|
|||
/**
|
||||
* libtransport -- C++ library for easy XMPP Transports development
|
||||
*
|
||||
* Copyright (C) 2011, Jan Kaluza <hanzz.k@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "glib.h"
|
||||
#include <dbus-1.0/dbus/dbus-glib-lowlevel.h>
|
||||
#include "sqlite3.h"
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include "transport/networkplugin.h"
|
||||
#include "transport/config.h"
|
||||
|
||||
class Skype;
|
||||
|
||||
class SkypePlugin : public Transport::NetworkPlugin {
|
||||
public:
|
||||
SkypePlugin(Transport::Config *config, const std::string &host, int port);
|
||||
|
||||
virtual ~SkypePlugin();
|
||||
|
||||
void handleLoginRequest(const std::string &user, const std::string &legacyName, const std::string &password);
|
||||
|
||||
void handleMemoryUsage(double &res, double &shared);
|
||||
|
||||
void handleLogoutRequest(const std::string &user, const std::string &legacyName);
|
||||
|
||||
void handleStatusChangeRequest(const std::string &user, int status, const std::string &statusMessage);
|
||||
|
||||
void handleBuddyUpdatedRequest(const std::string &user, const std::string &buddyName, const std::string &alias, const std::vector<std::string> &groups);
|
||||
|
||||
void handleBuddyRemovedRequest(const std::string &user, const std::string &buddyName, const std::vector<std::string> &groups);
|
||||
|
||||
void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml = "", const std::string &id = "");
|
||||
|
||||
void handleVCardRequest(const std::string &user, const std::string &legacyName, unsigned int id);
|
||||
|
||||
void sendData(const std::string &string);
|
||||
|
||||
void handleVCardUpdatedRequest(const std::string &user, const std::string &p, const std::string &nickname);
|
||||
|
||||
void handleBuddyBlockToggled(const std::string &user, const std::string &buddyName, bool blocked);
|
||||
|
||||
void handleTypingRequest(const std::string &user, const std::string &buddyName);
|
||||
|
||||
void handleTypedRequest(const std::string &user, const std::string &buddyName);
|
||||
|
||||
void handleStoppedTypingRequest(const std::string &user, const std::string &buddyName);
|
||||
|
||||
void handleAttentionRequest(const std::string &user, const std::string &buddyName, const std::string &message);
|
||||
|
||||
std::map<std::string, Skype *> m_sessions;
|
||||
std::map<Skype *, std::string> m_accounts;
|
||||
std::map<std::string, unsigned int> m_vcards;
|
||||
Transport::Config *config;
|
||||
|
||||
};
|
|
@ -3,6 +3,8 @@
|
|||
#include "transport/networkplugin.h"
|
||||
#include "transport/logging.h"
|
||||
|
||||
#include "boost/date_time/posix_time/posix_time.hpp"
|
||||
|
||||
// Swiften
|
||||
#include "Swiften/Swiften.h"
|
||||
|
||||
|
@ -15,9 +17,11 @@
|
|||
#endif
|
||||
|
||||
#ifndef __FreeBSD__
|
||||
#ifndef __MACH__
|
||||
// malloc_trim
|
||||
#include "malloc.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Boost
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
@ -32,7 +36,83 @@ Swift::SimpleEventLoop *loop_;
|
|||
|
||||
// Plugins
|
||||
class SwiftenPlugin;
|
||||
SwiftenPlugin *np = NULL;
|
||||
NetworkPlugin *np = NULL;
|
||||
|
||||
class MUCController {
|
||||
public:
|
||||
MUCController(const std::string &user, boost::shared_ptr<Swift::Client> client, const std::string &room, const std::string &nickname, const std::string &password) {
|
||||
m_user = user;
|
||||
m_room = room;
|
||||
muc = client->getMUCManager()->createMUC(room);
|
||||
if (!password.empty()) {
|
||||
muc->setPassword(password);
|
||||
}
|
||||
|
||||
muc->onJoinComplete.connect(boost::bind(&MUCController::handleJoinComplete, this, _1));
|
||||
muc->onJoinFailed.connect(boost::bind(&MUCController::handleJoinFailed, this, _1));
|
||||
muc->onOccupantJoined.connect(boost::bind(&MUCController::handleOccupantJoined, this, _1));
|
||||
muc->onOccupantPresenceChange.connect(boost::bind(&MUCController::handleOccupantPresenceChange, this, _1));
|
||||
muc->onOccupantLeft.connect(boost::bind(&MUCController::handleOccupantLeft, this, _1, _2, _3));
|
||||
muc->onOccupantRoleChanged.connect(boost::bind(&MUCController::handleOccupantRoleChanged, this, _1, _2, _3));
|
||||
muc->onOccupantAffiliationChanged.connect(boost::bind(&MUCController::handleOccupantAffiliationChanged, this, _1, _2, _3));
|
||||
|
||||
muc->joinAs(nickname);
|
||||
}
|
||||
|
||||
virtual ~MUCController() {
|
||||
muc->onJoinComplete.disconnect(boost::bind(&MUCController::handleJoinComplete, this, _1));
|
||||
muc->onJoinFailed.disconnect(boost::bind(&MUCController::handleJoinFailed, this, _1));
|
||||
muc->onOccupantJoined.disconnect(boost::bind(&MUCController::handleOccupantJoined, this, _1));
|
||||
muc->onOccupantPresenceChange.disconnect(boost::bind(&MUCController::handleOccupantPresenceChange, this, _1));
|
||||
muc->onOccupantLeft.disconnect(boost::bind(&MUCController::handleOccupantLeft, this, _1, _2, _3));
|
||||
muc->onOccupantRoleChanged.disconnect(boost::bind(&MUCController::handleOccupantRoleChanged, this, _1, _2, _3));
|
||||
muc->onOccupantAffiliationChanged.disconnect(boost::bind(&MUCController::handleOccupantAffiliationChanged, this, _1, _2, _3));
|
||||
}
|
||||
|
||||
const std::string &getNickname() {
|
||||
//return muc->getCurrentNick();
|
||||
return m_nick;
|
||||
}
|
||||
|
||||
void handleOccupantJoined(const Swift::MUCOccupant& occupant) {
|
||||
np->handleParticipantChanged(m_user, occupant.getNick(), m_room, occupant.getRole() == Swift::MUCOccupant::Moderator, pbnetwork::STATUS_ONLINE);
|
||||
}
|
||||
|
||||
void handleOccupantLeft(const Swift::MUCOccupant& occupant, Swift::MUC::LeavingType type, const std::string& reason) {
|
||||
np->handleParticipantChanged(m_user, occupant.getNick(), m_room, occupant.getRole() == Swift::MUCOccupant::Moderator, pbnetwork::STATUS_NONE);
|
||||
}
|
||||
|
||||
void handleOccupantPresenceChange(boost::shared_ptr<Swift::Presence> presence) {
|
||||
const Swift::MUCOccupant& occupant = muc->getOccupant(presence->getFrom().getResource());
|
||||
np->handleParticipantChanged(m_user, presence->getFrom().getResource(), m_room, (int) occupant.getRole() == Swift::MUCOccupant::Moderator, (pbnetwork::StatusType) presence->getShow(), presence->getStatus());
|
||||
}
|
||||
|
||||
void handleOccupantRoleChanged(const std::string& nick, const Swift::MUCOccupant& occupant, const Swift::MUCOccupant::Role& oldRole) {
|
||||
|
||||
}
|
||||
|
||||
void handleOccupantAffiliationChanged(const std::string& nick, const Swift::MUCOccupant::Affiliation& affiliation, const Swift::MUCOccupant::Affiliation& oldAffiliation) {
|
||||
// np->handleParticipantChanged(m_user, occupant->getNick(), m_room, (int) occupant.getRole() == Swift::MUCOccupant::Moderator, pbnetwork::STATUS_ONLINE);
|
||||
}
|
||||
|
||||
void handleJoinComplete(const std::string& nick) {
|
||||
m_nick = nick;
|
||||
}
|
||||
|
||||
void handleJoinFailed(boost::shared_ptr<Swift::ErrorPayload> error) {
|
||||
|
||||
}
|
||||
|
||||
void part() {
|
||||
muc->part();
|
||||
}
|
||||
|
||||
private:
|
||||
Swift::MUC::ref muc;
|
||||
std::string m_user;
|
||||
std::string m_room;
|
||||
std::string m_nick;
|
||||
};
|
||||
|
||||
class SwiftenPlugin : public NetworkPlugin {
|
||||
public:
|
||||
|
@ -106,13 +186,16 @@ class SwiftenPlugin : public NetworkPlugin {
|
|||
client->onDisconnected.disconnect(boost::bind(&SwiftenPlugin::handleSwiftDisconnected, this, user, _1));
|
||||
client->onMessageReceived.disconnect(boost::bind(&SwiftenPlugin::handleSwiftMessageReceived, this, user, _1));
|
||||
m_users.erase(user);
|
||||
m_mucs.erase(user);
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
#ifndef __FreeBSD__
|
||||
#ifndef __MACH__
|
||||
// force returning of memory chunks allocated by libxml2 to kernel
|
||||
malloc_trim(0);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -136,6 +219,15 @@ class SwiftenPlugin : public NetworkPlugin {
|
|||
}
|
||||
|
||||
void handleSwiftPresenceChanged(const std::string &user, Swift::Presence::ref presence) {
|
||||
boost::shared_ptr<Swift::Client> client = m_users[user];
|
||||
if (client->getMUCRegistry()->isMUC(presence->getFrom().toBare())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (presence->getPayload<Swift::MUCUserPayload>() != NULL || presence->getPayload<Swift::MUCPayload>() != NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOG4CXX_INFO(logger, user << ": " << presence->getFrom().toBare().toString() << " presence changed");
|
||||
|
||||
std::string message = presence->getStatus();
|
||||
|
@ -160,7 +252,22 @@ class SwiftenPlugin : public NetworkPlugin {
|
|||
std::string body = message->getBody();
|
||||
boost::shared_ptr<Swift::Client> client = m_users[user];
|
||||
if (client) {
|
||||
handleMessage(user, message->getFrom().toBare().toString(), body, "", "");
|
||||
if (message->getType() == Swift::Message::Groupchat) {
|
||||
boost::shared_ptr<Swift::Delay> delay = message->getPayload<Swift::Delay>();
|
||||
std::string timestamp = "";
|
||||
if (delay) {
|
||||
timestamp = boost::posix_time::to_iso_string(delay->getStamp());
|
||||
}
|
||||
handleMessage(user, message->getFrom().toBare().toString(), body, message->getFrom().getResource(), "", timestamp);
|
||||
}
|
||||
else {
|
||||
if (client->getMUCRegistry()->isMUC(message->getFrom().toBare())) {
|
||||
handleMessage(user, message->getFrom().toBare().toString(), body, message->getFrom().getResource(), "", "", false, true);
|
||||
}
|
||||
else {
|
||||
handleMessage(user, message->getFrom().toBare().toString(), body, "", "");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -199,6 +306,7 @@ class SwiftenPlugin : public NetworkPlugin {
|
|||
client->getRoster()->onInitialRosterPopulated.disconnect(boost::bind(&SwiftenPlugin::handleSwiftRosterReceived, this, user));
|
||||
client->getPresenceOracle()->onPresenceChange.disconnect(boost::bind(&SwiftenPlugin::handleSwiftPresenceChanged, this, user, _1));
|
||||
client->disconnect();
|
||||
m_mucs.erase(user);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -210,6 +318,11 @@ class SwiftenPlugin : public NetworkPlugin {
|
|||
message->setTo(Swift::JID(legacyName));
|
||||
message->setFrom(client->getJID());
|
||||
message->setBody(msg);
|
||||
if (client->getMUCRegistry()->isMUC(legacyName)) {
|
||||
message->setType(Swift::Message::Groupchat);
|
||||
boost::shared_ptr<MUCController> muc = m_mucs[user][legacyName];
|
||||
// handleMessage(user, legacyName, msg, muc->getNickname(), xhtml);
|
||||
}
|
||||
|
||||
client->sendMessage(message);
|
||||
}
|
||||
|
@ -226,17 +339,81 @@ class SwiftenPlugin : public NetworkPlugin {
|
|||
}
|
||||
|
||||
void handleBuddyUpdatedRequest(const std::string &user, const std::string &buddyName, const std::string &alias, const std::vector<std::string> &groups) {
|
||||
LOG4CXX_INFO(logger, user << ": Added/Updated buddy " << buddyName << ".");
|
||||
// handleBuddyChanged(user, buddyName, alias, groups, pbnetwork::STATUS_ONLINE);
|
||||
boost::shared_ptr<Swift::Client> client = m_users[user];
|
||||
if (client) {
|
||||
LOG4CXX_INFO(logger, user << ": Added/Updated buddy " << buddyName << ".");
|
||||
if (!client->getRoster()->containsJID(buddyName)) {
|
||||
Swift::RosterItemPayload item;
|
||||
item.setName(alias);
|
||||
item.setJID(buddyName);
|
||||
item.setGroups(groups);
|
||||
boost::shared_ptr<Swift::RosterPayload> roster(new Swift::RosterPayload());
|
||||
roster->addItem(item);
|
||||
Swift::SetRosterRequest::ref request = Swift::SetRosterRequest::create(roster, client->getIQRouter());
|
||||
// request->onResponse.connect(boost::bind(&RosterController::handleRosterSetError, this, _1, roster));
|
||||
request->send();
|
||||
client->getSubscriptionManager()->requestSubscription(buddyName);
|
||||
}
|
||||
else {
|
||||
Swift::JID contact(buddyName);
|
||||
Swift::RosterItemPayload item(contact, alias, client->getRoster()->getSubscriptionStateForJID(contact));
|
||||
item.setGroups(groups);
|
||||
boost::shared_ptr<Swift::RosterPayload> roster(new Swift::RosterPayload());
|
||||
roster->addItem(item);
|
||||
Swift::SetRosterRequest::ref request = Swift::SetRosterRequest::create(roster, client->getIQRouter());
|
||||
// request->onResponse.connect(boost::bind(&RosterController::handleRosterSetError, this, _1, roster));
|
||||
request->send();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void handleBuddyRemovedRequest(const std::string &user, const std::string &buddyName, const std::vector<std::string> &groups) {
|
||||
boost::shared_ptr<Swift::Client> client = m_users[user];
|
||||
if (client) {
|
||||
Swift::RosterItemPayload item(buddyName, "", Swift::RosterItemPayload::Remove);
|
||||
boost::shared_ptr<Swift::RosterPayload> roster(new Swift::RosterPayload());
|
||||
roster->addItem(item);
|
||||
Swift::SetRosterRequest::ref request = Swift::SetRosterRequest::create(roster, client->getIQRouter());
|
||||
// request->onResponse.connect(boost::bind(&RosterController::handleRosterSetError, this, _1, roster));
|
||||
request->send();
|
||||
}
|
||||
}
|
||||
|
||||
void handleJoinRoomRequest(const std::string &user, const std::string &room, const std::string &nickname, const std::string &password) {
|
||||
boost::shared_ptr<Swift::Client> client = m_users[user];
|
||||
if (client) {
|
||||
if (client->getMUCRegistry()->isMUC(room)) {
|
||||
return;
|
||||
}
|
||||
|
||||
boost::shared_ptr<MUCController> muc = boost::shared_ptr<MUCController>( new MUCController(user, client, room, nickname, password));
|
||||
m_mucs[user][room] = muc;
|
||||
}
|
||||
}
|
||||
|
||||
void handleLeaveRoomRequest(const std::string &user, const std::string &room) {
|
||||
boost::shared_ptr<Swift::Client> client = m_users[user];
|
||||
if (client) {
|
||||
if (!client->getMUCRegistry()->isMUC(room)) {
|
||||
return;
|
||||
}
|
||||
|
||||
boost::shared_ptr<MUCController> muc = m_mucs[user][room];
|
||||
if (!muc) {
|
||||
m_mucs[user].erase(room);
|
||||
return;
|
||||
}
|
||||
|
||||
muc->part();
|
||||
m_mucs[user].erase(room);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Config *config;
|
||||
std::map<std::string, boost::shared_ptr<Swift::Client> > m_users;
|
||||
std::map<std::string, std::map<std::string, boost::shared_ptr<MUCController> > > m_mucs;
|
||||
};
|
||||
|
||||
#ifndef WIN32
|
||||
|
|
14
backends/swiften_raw/CMakeLists.txt
Normal file
14
backends/swiften_raw/CMakeLists.txt
Normal file
|
@ -0,0 +1,14 @@
|
|||
cmake_minimum_required(VERSION 2.6)
|
||||
|
||||
FILE(GLOB SRC *.cpp)
|
||||
|
||||
ADD_EXECUTABLE(spectrum2_swiften_raw_backend ${SRC})
|
||||
|
||||
IF (NOT WIN32)
|
||||
target_link_libraries(spectrum2_swiften_raw_backend transport pthread ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES})
|
||||
else()
|
||||
target_link_libraries(spectrum2_swiften_raw_backend transport ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES})
|
||||
endif()
|
||||
|
||||
INSTALL(TARGETS spectrum2_swiften_raw_backend RUNTIME DESTINATION bin)
|
||||
|
427
backends/swiften_raw/main.cpp
Normal file
427
backends/swiften_raw/main.cpp
Normal file
|
@ -0,0 +1,427 @@
|
|||
// Transport includes
|
||||
#include "transport/config.h"
|
||||
#include "transport/networkplugin.h"
|
||||
#include "transport/logging.h"
|
||||
|
||||
#include "boost/date_time/posix_time/posix_time.hpp"
|
||||
|
||||
// Swiften
|
||||
#include "Swiften/Swiften.h"
|
||||
|
||||
#ifndef WIN32
|
||||
// for signal handler
|
||||
#include "unistd.h"
|
||||
#include "signal.h"
|
||||
#include "sys/wait.h"
|
||||
#include "sys/signal.h"
|
||||
#endif
|
||||
|
||||
#ifndef __FreeBSD__
|
||||
#ifndef __MACH__
|
||||
// malloc_trim
|
||||
#include "malloc.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Boost
|
||||
#include <boost/algorithm/string.hpp>
|
||||
using namespace boost::filesystem;
|
||||
using namespace boost::program_options;
|
||||
using namespace Transport;
|
||||
|
||||
DEFINE_LOGGER(logger, "Swiften");
|
||||
DEFINE_LOGGER(logger_xml, "backend.xml");
|
||||
|
||||
// eventloop
|
||||
Swift::SimpleEventLoop *loop_;
|
||||
|
||||
// Plugins
|
||||
class SwiftenPlugin;
|
||||
NetworkPlugin *np = NULL;
|
||||
Swift::XMPPSerializer *serializer;
|
||||
|
||||
class ForwardIQHandler : public Swift::IQHandler {
|
||||
public:
|
||||
std::map <std::string, std::string> m_id2resource;
|
||||
|
||||
ForwardIQHandler(NetworkPlugin *np, const std::string &user) {
|
||||
m_np = np;
|
||||
m_user = user;
|
||||
}
|
||||
|
||||
bool handleIQ(boost::shared_ptr<Swift::IQ> iq) {
|
||||
if (iq->getPayload<Swift::RosterPayload>() != NULL) {
|
||||
return false;
|
||||
}
|
||||
if (iq->getType() == Swift::IQ::Get) {
|
||||
m_id2resource[iq->getID()] = iq->getFrom().getResource();
|
||||
}
|
||||
|
||||
iq->setTo(m_user);
|
||||
std::string xml = safeByteArrayToString(serializer->serializeElement(iq));
|
||||
m_np->sendRawXML(xml);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
NetworkPlugin *m_np;
|
||||
std::string m_user;
|
||||
|
||||
};
|
||||
|
||||
class SwiftenPlugin : public NetworkPlugin, Swift::XMPPParserClient {
|
||||
public:
|
||||
Swift::BoostNetworkFactories *m_factories;
|
||||
Swift::BoostIOServiceThread m_boostIOServiceThread;
|
||||
boost::shared_ptr<Swift::Connection> m_conn;
|
||||
bool m_firstPing;
|
||||
|
||||
Swift::FullPayloadSerializerCollection collection;
|
||||
Swift::XMPPParser *m_xmppParser;
|
||||
Swift::FullPayloadParserFactoryCollection m_collection2;
|
||||
|
||||
SwiftenPlugin(Config *config, Swift::SimpleEventLoop *loop, const std::string &host, int port) : NetworkPlugin() {
|
||||
this->config = config;
|
||||
m_firstPing = true;
|
||||
m_factories = new Swift::BoostNetworkFactories(loop);
|
||||
m_conn = m_factories->getConnectionFactory()->createConnection();
|
||||
m_conn->onDataRead.connect(boost::bind(&SwiftenPlugin::_handleDataRead, this, _1));
|
||||
m_conn->connect(Swift::HostAddressPort(Swift::HostAddress(host), port));
|
||||
|
||||
serializer = new Swift::XMPPSerializer(&collection, Swift::ClientStreamType);
|
||||
m_xmppParser = new Swift::XMPPParser(this, &m_collection2, m_factories->getXMLParserFactory());
|
||||
m_xmppParser->parse("<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='localhost' version='1.0'>");
|
||||
|
||||
LOG4CXX_INFO(logger, "Starting the plugin.");
|
||||
}
|
||||
|
||||
// NetworkPlugin uses this method to send the data to networkplugin server
|
||||
void sendData(const std::string &string) {
|
||||
m_conn->write(Swift::createSafeByteArray(string));
|
||||
}
|
||||
|
||||
// This method has to call handleDataRead with all received data from network plugin server
|
||||
void _handleDataRead(boost::shared_ptr<Swift::SafeByteArray> data) {
|
||||
if (m_firstPing) {
|
||||
m_firstPing = false;
|
||||
NetworkPlugin::PluginConfig cfg;
|
||||
cfg.setRawXML(true);
|
||||
sendConfig(cfg);
|
||||
}
|
||||
std::string d(data->begin(), data->end());
|
||||
handleDataRead(d);
|
||||
}
|
||||
|
||||
void handleStreamStart(const Swift::ProtocolHeader&) {}
|
||||
|
||||
void handleElement(boost::shared_ptr<Swift::Element> element) {
|
||||
boost::shared_ptr<Swift::Stanza> stanza = boost::dynamic_pointer_cast<Swift::Stanza>(element);
|
||||
if (!stanza) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string user = stanza->getFrom().toBare();
|
||||
|
||||
boost::shared_ptr<Swift::Client> client = m_users[user];
|
||||
if (!client)
|
||||
return;
|
||||
|
||||
stanza->setFrom(client->getJID());
|
||||
|
||||
boost::shared_ptr<Swift::Message> message = boost::dynamic_pointer_cast<Swift::Message>(stanza);
|
||||
if (message) {
|
||||
client->sendMessage(message);
|
||||
return;
|
||||
}
|
||||
|
||||
boost::shared_ptr<Swift::Presence> presence = boost::dynamic_pointer_cast<Swift::Presence>(stanza);
|
||||
if (presence) {
|
||||
client->sendPresence(presence);
|
||||
return;
|
||||
}
|
||||
|
||||
boost::shared_ptr<Swift::IQ> iq = boost::dynamic_pointer_cast<Swift::IQ>(stanza);
|
||||
if (iq) {
|
||||
if (m_handlers[user]->m_id2resource.find(stanza->getID()) != m_handlers[user]->m_id2resource.end()) {
|
||||
iq->setTo(Swift::JID(iq->getTo().getNode(), iq->getTo().getDomain(), m_handlers[user]->m_id2resource[stanza->getID()]));
|
||||
m_handlers[user]->m_id2resource.erase(stanza->getID());
|
||||
}
|
||||
client->getIQRouter()->sendIQ(iq);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void handleStreamEnd() {}
|
||||
|
||||
void handleRawXML(const std::string &xml) {
|
||||
m_xmppParser->parse(xml);
|
||||
}
|
||||
|
||||
void handleSwiftDisconnected(const std::string &user, const boost::optional<Swift::ClientError> &error) {
|
||||
std::string message = "";
|
||||
bool reconnect = false;
|
||||
if (error) {
|
||||
switch(error->getType()) {
|
||||
case Swift::ClientError::UnknownError: message = ("Unknown Error"); reconnect = true; break;
|
||||
case Swift::ClientError::DomainNameResolveError: message = ("Unable to find server"); break;
|
||||
case Swift::ClientError::ConnectionError: message = ("Error connecting to server"); break;
|
||||
case Swift::ClientError::ConnectionReadError: message = ("Error while receiving server data"); reconnect = true; break;
|
||||
case Swift::ClientError::ConnectionWriteError: message = ("Error while sending data to the server"); reconnect = true; break;
|
||||
case Swift::ClientError::XMLError: message = ("Error parsing server data"); reconnect = true; break;
|
||||
case Swift::ClientError::AuthenticationFailedError: message = ("Login/password invalid"); break;
|
||||
case Swift::ClientError::CompressionFailedError: message = ("Error while compressing stream"); break;
|
||||
case Swift::ClientError::ServerVerificationFailedError: message = ("Server verification failed"); break;
|
||||
case Swift::ClientError::NoSupportedAuthMechanismsError: message = ("Authentication mechanisms not supported"); break;
|
||||
case Swift::ClientError::UnexpectedElementError: message = ("Unexpected response"); break;
|
||||
case Swift::ClientError::ResourceBindError: message = ("Error binding resource"); break;
|
||||
case Swift::ClientError::SessionStartError: message = ("Error starting session"); break;
|
||||
case Swift::ClientError::StreamError: message = ("Stream error"); break;
|
||||
case Swift::ClientError::TLSError: message = ("Encryption error"); break;
|
||||
case Swift::ClientError::ClientCertificateLoadError: message = ("Error loading certificate (Invalid password?)"); break;
|
||||
case Swift::ClientError::ClientCertificateError: message = ("Certificate not authorized"); break;
|
||||
|
||||
case Swift::ClientError::UnknownCertificateError: message = ("Unknown certificate"); break;
|
||||
case Swift::ClientError::CertificateExpiredError: message = ("Certificate has expired"); break;
|
||||
case Swift::ClientError::CertificateNotYetValidError: message = ("Certificate is not yet valid"); break;
|
||||
case Swift::ClientError::CertificateSelfSignedError: message = ("Certificate is self-signed"); break;
|
||||
case Swift::ClientError::CertificateRejectedError: message = ("Certificate has been rejected"); break;
|
||||
case Swift::ClientError::CertificateUntrustedError: message = ("Certificate is not trusted"); break;
|
||||
case Swift::ClientError::InvalidCertificatePurposeError: message = ("Certificate cannot be used for encrypting your connection"); break;
|
||||
case Swift::ClientError::CertificatePathLengthExceededError: message = ("Certificate path length constraint exceeded"); break;
|
||||
case Swift::ClientError::InvalidCertificateSignatureError: message = ("Invalid certificate signature"); break;
|
||||
case Swift::ClientError::InvalidCAError: message = ("Invalid Certificate Authority"); break;
|
||||
case Swift::ClientError::InvalidServerIdentityError: message = ("Certificate does not match the host identity"); break;
|
||||
}
|
||||
}
|
||||
LOG4CXX_INFO(logger, user << ": Disconnected " << message);
|
||||
handleDisconnected(user, reconnect ? 0 : 3, message);
|
||||
|
||||
boost::shared_ptr<Swift::Client> client = m_users[user];
|
||||
if (client) {
|
||||
client->onConnected.disconnect(boost::bind(&SwiftenPlugin::handleSwiftConnected, this, user));
|
||||
client->onDisconnected.disconnect(boost::bind(&SwiftenPlugin::handleSwiftDisconnected, this, user, _1));
|
||||
client->onMessageReceived.disconnect(boost::bind(&SwiftenPlugin::handleSwiftMessageReceived, this, user, _1));
|
||||
m_users.erase(user);
|
||||
m_handlers.erase(user);
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
#ifndef __FreeBSD__
|
||||
#ifndef __MACH__
|
||||
// force returning of memory chunks allocated by libxml2 to kernel
|
||||
malloc_trim(0);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void handleSwiftConnected(const std::string &user) {
|
||||
LOG4CXX_INFO(logger, user << ": Connected to XMPP server.");
|
||||
handleConnected(user);
|
||||
m_users[user]->requestRoster();
|
||||
Swift::Presence::ref response = Swift::Presence::create();
|
||||
response->setFrom(m_users[user]->getJID());
|
||||
m_users[user]->sendPresence(response);
|
||||
}
|
||||
|
||||
void handleSwiftRosterReceived(const std::string &user) {
|
||||
Swift::PresenceOracle *oracle = m_users[user]->getPresenceOracle();
|
||||
BOOST_FOREACH(const Swift::XMPPRosterItem &item, m_users[user]->getRoster()->getItems()) {
|
||||
Swift::Presence::ref lastPresence = oracle->getLastPresence(item.getJID());
|
||||
pbnetwork::StatusType status = lastPresence ? ((pbnetwork::StatusType) lastPresence->getShow()) : pbnetwork::STATUS_NONE;
|
||||
handleBuddyChanged(user, item.getJID().toBare().toString(),
|
||||
item.getName(), item.getGroups(), status);
|
||||
}
|
||||
}
|
||||
|
||||
void handleSwiftPresenceChanged(const std::string &user, Swift::Presence::ref presence) {
|
||||
// boost::shared_ptr<Swift::Client> client = m_users[user];
|
||||
// if (client->getMUCRegistry()->isMUC(presence->getFrom().toBare())) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// if (presence->getPayload<Swift::MUCUserPayload>() != NULL || presence->getPayload<Swift::MUCPayload>() != NULL) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// LOG4CXX_INFO(logger, user << ": " << presence->getFrom().toBare().toString() << " presence changed");
|
||||
//
|
||||
// std::string message = presence->getStatus();
|
||||
// std::string photo = "";
|
||||
//
|
||||
// boost::shared_ptr<Swift::VCardUpdate> update = presence->getPayload<Swift::VCardUpdate>();
|
||||
// if (update) {
|
||||
// photo = update->getPhotoHash();
|
||||
// }
|
||||
//
|
||||
// boost::optional<Swift::XMPPRosterItem> item = m_users[user]->getRoster()->getItem(presence->getFrom());
|
||||
// if (item) {
|
||||
// handleBuddyChanged(user, presence->getFrom().toBare().toString(), item->getName(), item->getGroups(), (pbnetwork::StatusType) presence->getShow(), message, photo);
|
||||
// }
|
||||
// else {
|
||||
// std::vector<std::string> groups;
|
||||
// handleBuddyChanged(user, presence->getFrom().toBare().toString(), presence->getFrom().toBare(), groups, (pbnetwork::StatusType) presence->getShow(), message, photo);
|
||||
// }
|
||||
presence->setTo(user);
|
||||
std::string xml = safeByteArrayToString(serializer->serializeElement(presence));
|
||||
sendRawXML(xml);
|
||||
}
|
||||
|
||||
void handleSwiftMessageReceived(const std::string &user, Swift::Message::ref message) {
|
||||
message->setTo(user);
|
||||
std::string xml = safeByteArrayToString(serializer->serializeElement(message));
|
||||
sendRawXML(xml);
|
||||
}
|
||||
|
||||
void handleSwiftenDataRead(const Swift::SafeByteArray &data) {
|
||||
std::string d = safeByteArrayToString(data);
|
||||
if (!boost::starts_with(d, "<auth")) {
|
||||
LOG4CXX_INFO(logger_xml, "XML IN " << d);
|
||||
}
|
||||
}
|
||||
|
||||
void handleSwiftenDataWritten(const Swift::SafeByteArray &data) {
|
||||
LOG4CXX_INFO(logger_xml, "XML OUT " << safeByteArrayToString(data));
|
||||
}
|
||||
|
||||
void handleLoginRequest(const std::string &user, const std::string &legacyName, const std::string &password) {
|
||||
LOG4CXX_INFO(logger, user << ": connecting as " << legacyName);
|
||||
boost::shared_ptr<Swift::Client> client = boost::make_shared<Swift::Client>(Swift::JID(legacyName), password, m_factories);
|
||||
m_users[user] = client;
|
||||
client->setAlwaysTrustCertificates();
|
||||
client->onConnected.connect(boost::bind(&SwiftenPlugin::handleSwiftConnected, this, user));
|
||||
client->onDisconnected.connect(boost::bind(&SwiftenPlugin::handleSwiftDisconnected, this, user, _1));
|
||||
client->onMessageReceived.connect(boost::bind(&SwiftenPlugin::handleSwiftMessageReceived, this, user, _1));
|
||||
client->getRoster()->onInitialRosterPopulated.connect(boost::bind(&SwiftenPlugin::handleSwiftRosterReceived, this, user));
|
||||
client->getPresenceOracle()->onPresenceChange.connect(boost::bind(&SwiftenPlugin::handleSwiftPresenceChanged, this, user, _1));
|
||||
client->onDataRead.connect(boost::bind(&SwiftenPlugin::handleSwiftenDataRead, this, _1));
|
||||
client->onDataWritten.connect(boost::bind(&SwiftenPlugin::handleSwiftenDataWritten, this, _1));
|
||||
Swift::ClientOptions opt;
|
||||
opt.allowPLAINWithoutTLS = true;
|
||||
client->connect(opt);
|
||||
|
||||
boost::shared_ptr<ForwardIQHandler> handler = boost::make_shared<ForwardIQHandler>(this, user);
|
||||
client->getIQRouter()->addHandler(handler);
|
||||
m_handlers[user] = handler;
|
||||
}
|
||||
|
||||
void handleLogoutRequest(const std::string &user, const std::string &legacyName) {
|
||||
boost::shared_ptr<Swift::Client> client = m_users[user];
|
||||
if (client) {
|
||||
client->onConnected.disconnect(boost::bind(&SwiftenPlugin::handleSwiftConnected, this, user));
|
||||
// client->onDisconnected.disconnect(boost::bind(&SwiftenPlugin::handleSwiftDisconnected, this, user, _1));
|
||||
client->onMessageReceived.disconnect(boost::bind(&SwiftenPlugin::handleSwiftMessageReceived, this, user, _1));
|
||||
client->getRoster()->onInitialRosterPopulated.disconnect(boost::bind(&SwiftenPlugin::handleSwiftRosterReceived, this, user));
|
||||
client->getPresenceOracle()->onPresenceChange.disconnect(boost::bind(&SwiftenPlugin::handleSwiftPresenceChanged, this, user, _1));
|
||||
client->disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &msg, const std::string &xhtml = "", const std::string &id = "") {
|
||||
}
|
||||
|
||||
void handleVCardRequest(const std::string &user, const std::string &legacyName, unsigned int id) {
|
||||
}
|
||||
|
||||
void handleBuddyUpdatedRequest(const std::string &user, const std::string &buddyName, const std::string &alias, const std::vector<std::string> &groups) {
|
||||
boost::shared_ptr<Swift::Client> client = m_users[user];
|
||||
if (client) {
|
||||
LOG4CXX_INFO(logger, user << ": Added/Updated buddy " << buddyName << ".");
|
||||
if (!client->getRoster()->containsJID(buddyName) || client->getRoster()->getSubscriptionStateForJID(buddyName) != Swift::RosterItemPayload::Both) {
|
||||
Swift::RosterItemPayload item;
|
||||
item.setName(alias);
|
||||
item.setJID(buddyName);
|
||||
item.setGroups(groups);
|
||||
boost::shared_ptr<Swift::RosterPayload> roster(new Swift::RosterPayload());
|
||||
roster->addItem(item);
|
||||
Swift::SetRosterRequest::ref request = Swift::SetRosterRequest::create(roster, client->getIQRouter());
|
||||
// request->onResponse.connect(boost::bind(&RosterController::handleRosterSetError, this, _1, roster));
|
||||
request->send();
|
||||
client->getSubscriptionManager()->requestSubscription(buddyName);
|
||||
}
|
||||
else {
|
||||
Swift::JID contact(buddyName);
|
||||
Swift::RosterItemPayload item(contact, alias, client->getRoster()->getSubscriptionStateForJID(contact));
|
||||
item.setGroups(groups);
|
||||
boost::shared_ptr<Swift::RosterPayload> roster(new Swift::RosterPayload());
|
||||
roster->addItem(item);
|
||||
Swift::SetRosterRequest::ref request = Swift::SetRosterRequest::create(roster, client->getIQRouter());
|
||||
// request->onResponse.connect(boost::bind(&RosterController::handleRosterSetError, this, _1, roster));
|
||||
request->send();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void handleBuddyRemovedRequest(const std::string &user, const std::string &buddyName, const std::vector<std::string> &groups) {
|
||||
boost::shared_ptr<Swift::Client> client = m_users[user];
|
||||
if (client) {
|
||||
Swift::RosterItemPayload item(buddyName, "", Swift::RosterItemPayload::Remove);
|
||||
boost::shared_ptr<Swift::RosterPayload> roster(new Swift::RosterPayload());
|
||||
roster->addItem(item);
|
||||
Swift::SetRosterRequest::ref request = Swift::SetRosterRequest::create(roster, client->getIQRouter());
|
||||
// request->onResponse.connect(boost::bind(&RosterController::handleRosterSetError, this, _1, roster));
|
||||
request->send();
|
||||
}
|
||||
}
|
||||
|
||||
void handleJoinRoomRequest(const std::string &user, const std::string &room, const std::string &nickname, const std::string &password) {
|
||||
|
||||
}
|
||||
|
||||
void handleLeaveRoomRequest(const std::string &user, const std::string &room) {
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
Config *config;
|
||||
std::map<std::string, boost::shared_ptr<Swift::Client> > m_users;
|
||||
std::map<std::string, boost::shared_ptr<ForwardIQHandler> > m_handlers;
|
||||
};
|
||||
|
||||
#ifndef WIN32
|
||||
static void spectrum_sigchld_handler(int sig)
|
||||
{
|
||||
int status;
|
||||
pid_t pid;
|
||||
|
||||
do {
|
||||
pid = waitpid(-1, &status, WNOHANG);
|
||||
} while (pid != 0 && pid != (pid_t)-1);
|
||||
|
||||
if ((pid == (pid_t) - 1) && (errno != ECHILD)) {
|
||||
char errmsg[BUFSIZ];
|
||||
snprintf(errmsg, BUFSIZ, "Warning: waitpid() returned %d", pid);
|
||||
perror(errmsg);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int main (int argc, char* argv[]) {
|
||||
std::string host;
|
||||
int port;
|
||||
|
||||
#ifndef WIN32
|
||||
if (signal(SIGCHLD, spectrum_sigchld_handler) == SIG_ERR) {
|
||||
std::cout << "SIGCHLD handler can't be set\n";
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
std::string error;
|
||||
Config *cfg = Config::createFromArgs(argc, argv, error, host, port);
|
||||
if (cfg == NULL) {
|
||||
std::cerr << error;
|
||||
return 1;
|
||||
}
|
||||
|
||||
Logging::initBackendLogging(cfg);
|
||||
|
||||
Swift::SimpleEventLoop eventLoop;
|
||||
loop_ = &eventLoop;
|
||||
np = new SwiftenPlugin(cfg, &eventLoop, host, port);
|
||||
loop_->run();
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -3,16 +3,21 @@ DEFINE_LOGGER(logger, "HelpMessageRequest")
|
|||
void HelpMessageRequest::run()
|
||||
{
|
||||
helpMsg = helpMsg
|
||||
+ "\n******************************HELP************************************\n"
|
||||
+ "#status <your status> ==> Update your status\n"
|
||||
+ "You will receive tweets of people you follow from this contact."
|
||||
+ "Following commands can be used to manage your Twitter account:"
|
||||
+ "#timeline [username] ==> Retrieve <username>'s timeline; Default - own timeline\n"
|
||||
+ "#status <your status> ==> Update your status\n"
|
||||
+ "@<username> <message> ==> Send a directed message to the user <username>\n"
|
||||
+ "#retweet <unique_tweet_id> ==> Retweet the tweet having id <unique_tweet_id> \n"
|
||||
+ "#follow <username> ==> Follow user <username>\n"
|
||||
+ "#unfollow <username> ==> Stop Following user <username>\n"
|
||||
+ "#mode [012] ==> Switch mode to 0(single), 1(multiple) or 2(chatroom)\n"
|
||||
+ "#mode [01] ==> Switch mode to 0(single), 1(multiple). See below\n"
|
||||
+ "#help ==> Print this help message\n"
|
||||
+ "************************************************************************\n";
|
||||
+ "************************************************************************\n"
|
||||
+ "There are 3 ways how to use the gateway:\n"
|
||||
+ "Mode 0 - There is twitter.com contact in your roster and all Twitter messages are forwaded using this contact.\n"
|
||||
+ "Mode 1 - Same as Mode 0, but the people you follow are displayed in your roster. You will receive/send directed messages using those contacts.\n"
|
||||
+ "Joining the #twitter@" + jid + " room - You can join mentioned room and see people you follow there as well as the tweets they post. Private messages in that room are mapped to Twitter direct messages.";
|
||||
}
|
||||
|
||||
void HelpMessageRequest::finalize()
|
||||
|
|
|
@ -14,13 +14,15 @@ using namespace Transport;
|
|||
class HelpMessageRequest : public Thread
|
||||
{
|
||||
std::string user;
|
||||
std::string jid;
|
||||
std::string helpMsg;
|
||||
boost::function<void (std::string &, std::string &)> callBack;
|
||||
|
||||
public:
|
||||
HelpMessageRequest(const std::string &_user, boost::function<void (std::string &, std::string &)> cb) {
|
||||
HelpMessageRequest(const std::string &_user, const std::string &jid, boost::function<void (std::string &, std::string &)> cb) {
|
||||
user = _user;
|
||||
callBack = cb;
|
||||
this->jid = jid;
|
||||
}
|
||||
|
||||
void run();
|
||||
|
|
|
@ -39,6 +39,7 @@ void PINExchangeProcess::finalize()
|
|||
}
|
||||
np->pinExchangeComplete(user, OAuthAccessTokenKey, OAuthAccessTokenSecret);
|
||||
np->handleMessage(user, "twitter.com", "PIN is OK. You are now authorized.");
|
||||
np->handleMessage(user, "twitter.com", "Send '#help' (without the quotes) to see how to use this transport.");
|
||||
LOG4CXX_INFO(logger, user << ": Sent PIN " << data << " and obtained Access Token");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -156,10 +156,13 @@ void TwitterPlugin::handleLoginRequest(const std::string &user, const std::strin
|
|||
// User logging out
|
||||
void TwitterPlugin::handleLogoutRequest(const std::string &user, const std::string &legacyName)
|
||||
{
|
||||
if(onlineUsers.count(user)) {
|
||||
if (userdb.count(user)) {
|
||||
delete userdb[user].sessions;
|
||||
userdb[user].sessions = NULL;
|
||||
userdb[user].connectionState = DISCONNECTED;
|
||||
}
|
||||
|
||||
if(onlineUsers.count(user)) {
|
||||
onlineUsers.erase(user);
|
||||
}
|
||||
}
|
||||
|
@ -212,7 +215,7 @@ void TwitterPlugin::handleMessageSendRequest(const std::string &user, const std:
|
|||
if(cmd == "#pin")
|
||||
tp->runAsThread(new PINExchangeProcess(np, userdb[user].sessions, user, data));
|
||||
else if(cmd == "#help")
|
||||
tp->runAsThread(new HelpMessageRequest(user, boost::bind(&TwitterPlugin::helpMessageResponse, this, _1, _2)));
|
||||
tp->runAsThread(new HelpMessageRequest(user, CONFIG_STRING(config, "service.jid"), boost::bind(&TwitterPlugin::helpMessageResponse, this, _1, _2)));
|
||||
else if(cmd[0] == '@') {
|
||||
std::string username = cmd.substr(1);
|
||||
tp->runAsThread(new DirectMessageRequest(userdb[user].sessions, user, username, data,
|
||||
|
@ -274,7 +277,7 @@ void TwitterPlugin::handleMessageSendRequest(const std::string &user, const std:
|
|||
}
|
||||
|
||||
else {
|
||||
std::string buddy;
|
||||
std::string buddy = legacyName;
|
||||
if(userdb[user].twitterMode == CHATROOM) buddy = legacyName.substr(legacyName.find("/") + 1);
|
||||
if(legacyName != "twitter") {
|
||||
tp->runAsThread(new DirectMessageRequest(userdb[user].sessions, user, buddy, message,
|
||||
|
|
|
@ -38,6 +38,7 @@ Server::Server(
|
|||
NetworkFactories* networkFactories,
|
||||
UserRegistry *userRegistry,
|
||||
const JID& jid,
|
||||
const std::string &address,
|
||||
int port) :
|
||||
userRegistry_(userRegistry),
|
||||
port_(port),
|
||||
|
@ -45,7 +46,8 @@ Server::Server(
|
|||
networkFactories_(networkFactories),
|
||||
stopping(false),
|
||||
selfJID(jid),
|
||||
stanzaChannel_(){
|
||||
stanzaChannel_(),
|
||||
address_(address){
|
||||
stanzaChannel_ = new ServerStanzaChannel();
|
||||
iqRouter_ = new IQRouter(stanzaChannel_);
|
||||
tlsFactory = NULL;
|
||||
|
@ -63,7 +65,12 @@ void Server::start() {
|
|||
if (serverFromClientConnectionServer) {
|
||||
return;
|
||||
}
|
||||
serverFromClientConnectionServer = networkFactories_->getConnectionServerFactory()->createConnectionServer(port_);
|
||||
if (address_ == "0.0.0.0") {
|
||||
serverFromClientConnectionServer = networkFactories_->getConnectionServerFactory()->createConnectionServer(port_);
|
||||
}
|
||||
else {
|
||||
serverFromClientConnectionServer = networkFactories_->getConnectionServerFactory()->createConnectionServer(Swift::HostAddress(address_), port_);
|
||||
}
|
||||
serverFromClientConnectionServerSignalConnections.push_back(
|
||||
serverFromClientConnectionServer->onNewConnection.connect(
|
||||
boost::bind(&Server::handleNewClientConnection, this, _1)));
|
||||
|
|
|
@ -35,7 +35,7 @@ namespace Swift {
|
|||
|
||||
class Server : public Entity {
|
||||
public:
|
||||
Server(EventLoop* eventLoop, NetworkFactories* networkFactories, UserRegistry *userRegistry, const JID& jid, int port);
|
||||
Server(EventLoop* eventLoop, NetworkFactories* networkFactories, UserRegistry *userRegistry, const JID& jid, const std::string &address, int port);
|
||||
~Server();
|
||||
|
||||
void start();
|
||||
|
@ -86,5 +86,6 @@ namespace Swift {
|
|||
TLSServerContextFactory *tlsFactory;
|
||||
CertificateWithKey::ref cert;
|
||||
PlatformXMLParserFactory *parserFactory_;
|
||||
std::string address_;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -23,7 +23,10 @@
|
|||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include "Swiften/Swiften.h"
|
||||
#include <time.h>
|
||||
|
||||
#include "Swiften/Elements/FormField.h"
|
||||
#include "Swiften/Elements/Command.h"
|
||||
|
||||
namespace Transport {
|
||||
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#include <algorithm>
|
||||
#include <map>
|
||||
#include "transport/adhoccommand.h"
|
||||
#include "Swiften/Swiften.h"
|
||||
|
||||
namespace Transport {
|
||||
|
||||
|
|
|
@ -23,7 +23,10 @@
|
|||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include "Swiften/Swiften.h"
|
||||
|
||||
#include "Swiften/Queries/Responder.h"
|
||||
#include "Swiften/Elements/Command.h"
|
||||
#include "Swiften/Network/Timer.h"
|
||||
|
||||
namespace Transport {
|
||||
|
||||
|
|
|
@ -22,7 +22,8 @@
|
|||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include "Swiften/Swiften.h"
|
||||
|
||||
#include "Swiften/Elements/Message.h"
|
||||
|
||||
namespace Transport {
|
||||
|
||||
|
|
|
@ -23,8 +23,8 @@
|
|||
#include <string>
|
||||
#include <algorithm>
|
||||
#include "transport/transport.h"
|
||||
#include "Swiften/Elements/VCard.h"
|
||||
|
||||
#include "Swiften/Swiften.h"
|
||||
|
||||
namespace Transport {
|
||||
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#include <algorithm>
|
||||
#include "transport/transport.h"
|
||||
|
||||
#include "Swiften/Swiften.h"
|
||||
#include "Swiften/Elements/Message.h"
|
||||
|
||||
namespace Transport {
|
||||
|
@ -34,15 +33,22 @@ class ConversationManager;
|
|||
/// Represents one XMPP-Legacy network conversation.
|
||||
class Conversation {
|
||||
public:
|
||||
typedef enum {
|
||||
PARTICIPANT_FLAG_NONE = 0,
|
||||
PARTICIPANT_FLAG_MODERATOR = 1,
|
||||
PARTICIPANT_FLAG_CONFLICT = 2,
|
||||
PARTICIPANT_FLAG_BANNED = 4,
|
||||
PARTICIPANT_FLAG_NOT_AUTHORIZED = 8,
|
||||
PARTICIPANT_FLAG_ME = 16,
|
||||
PARTICIPANT_FLAG_KICKED = 32
|
||||
} ParticipantFlag;
|
||||
|
||||
typedef struct _Participant {
|
||||
int flag;
|
||||
ParticipantFlag flag;
|
||||
int status;
|
||||
std::string statusMessage;
|
||||
} Participant;
|
||||
|
||||
/// Type of participants in MUC rooms.
|
||||
enum ParticipantFlag {None, Moderator};
|
||||
|
||||
/// Creates new conversation.
|
||||
|
||||
/// \param conversationManager ConversationManager associated with this Conversation.
|
||||
|
@ -64,6 +70,8 @@ class Conversation {
|
|||
/// \param nickname For MUC conversation this is nickname of room participant who sent this message.
|
||||
void handleMessage(boost::shared_ptr<Swift::Message> &message, const std::string &nickname = "");
|
||||
|
||||
void handleRawMessage(boost::shared_ptr<Swift::Message> &message);
|
||||
|
||||
/// Handles participant change in MUC.
|
||||
|
||||
/// \param nickname Nickname of participant which changed.
|
||||
|
@ -71,7 +79,7 @@ class Conversation {
|
|||
/// \param status Current status of this participant.
|
||||
/// \param statusMessage Current status message of this participant.
|
||||
/// \param newname If participant was renamed, this variable contains his new name.
|
||||
void handleParticipantChanged(const std::string &nickname, int flag, int status = Swift::StatusShow::None, const std::string &statusMessage = "", const std::string &newname = "");
|
||||
void handleParticipantChanged(const std::string &nickname, ParticipantFlag flag, int status = Swift::StatusShow::None, const std::string &statusMessage = "", const std::string &newname = "");
|
||||
|
||||
/// Sets XMPP user nickname in MUC rooms.
|
||||
|
||||
|
|
|
@ -23,7 +23,8 @@
|
|||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include "Swiften/Swiften.h"
|
||||
|
||||
#include "Swiften/Elements/Message.h"
|
||||
|
||||
namespace Transport {
|
||||
|
||||
|
|
|
@ -21,9 +21,9 @@
|
|||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "Swiften/Swiften.h"
|
||||
#include "Swiften/Queries/GetResponder.h"
|
||||
#include "Swiften/Elements/DiscoItems.h"
|
||||
#include "Swiften/Elements/CapsInfo.h"
|
||||
|
||||
namespace Transport {
|
||||
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#include <algorithm>
|
||||
#include "transport/transport.h"
|
||||
|
||||
#include "Swiften/Swiften.h"
|
||||
#include "Swiften/Elements/Message.h"
|
||||
#include "transport/conversation.h"
|
||||
#include "transport/buddy.h"
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "Swiften/Swiften.h"
|
||||
#include "Swiften/Queries/Responder.h"
|
||||
#include "Swiften/Elements/GatewayPayload.h"
|
||||
|
||||
|
|
|
@ -65,6 +65,8 @@ class LocalBuddy : public Buddy {
|
|||
std::string m_statusMessage;
|
||||
std::string m_iconHash;
|
||||
Swift::StatusShow m_status;
|
||||
|
||||
friend class NetworkPluginServer;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -22,7 +22,8 @@
|
|||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include "Swiften/Swiften.h"
|
||||
|
||||
#include "Swiften/FileTransfer/ReadBytestream.h"
|
||||
|
||||
namespace Transport {
|
||||
|
||||
|
|
|
@ -24,12 +24,10 @@
|
|||
|
||||
#ifndef WIN32
|
||||
#include "signal.h"
|
||||
#else
|
||||
#define pid_t void*
|
||||
#endif
|
||||
|
||||
namespace Transport {
|
||||
|
||||
#ifndef WIN32
|
||||
void process_mem_usage(double& shared, double& resident_set, pid_t pid = 0);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include "Swiften/Swiften.h"
|
||||
#include "transport/storagebackend.h"
|
||||
#include "transport/config.h"
|
||||
#include "mysql.h"
|
||||
|
|
|
@ -39,16 +39,20 @@ class NetworkPlugin {
|
|||
|
||||
class PluginConfig {
|
||||
public:
|
||||
PluginConfig() : m_needPassword(true), m_needRegistration(false) {}
|
||||
PluginConfig() : m_needPassword(true), m_needRegistration(false), m_supportMUC(false), m_rawXML(false) {}
|
||||
virtual ~PluginConfig() {}
|
||||
|
||||
void setNeedRegistration(bool needRegistration = false) { m_needRegistration = needRegistration; }
|
||||
void setNeedPassword(bool needPassword = true) { m_needPassword = needPassword; }
|
||||
void setSupportMUC(bool supportMUC = true) { m_supportMUC = supportMUC; }
|
||||
void setExtraFields(const std::vector<std::string> &fields) { m_extraFields = fields; }
|
||||
void setRawXML(bool rawXML = false) { m_rawXML = rawXML; }
|
||||
|
||||
private:
|
||||
bool m_needPassword;
|
||||
bool m_needRegistration;
|
||||
bool m_supportMUC;
|
||||
bool m_rawXML;
|
||||
std::vector<std::string> m_extraFields;
|
||||
|
||||
friend class NetworkPlugin;
|
||||
|
@ -65,6 +69,8 @@ class NetworkPlugin {
|
|||
|
||||
void sendConfig(const PluginConfig &cfg);
|
||||
|
||||
void sendRawXML(std::string &xml);
|
||||
|
||||
/// Call this function when legacy network buddy changed.
|
||||
/// \param user XMPP JID of user for which this event occurs. You can get it from NetworkPlugin::handleLoginRequest(). (eg. "user%gmail.com@xmpp.domain.tld")
|
||||
/// \param buddyName Name of legacy network buddy. (eg. "user2@gmail.com")
|
||||
|
@ -111,7 +117,7 @@ class NetworkPlugin {
|
|||
/// \param message Plain text message.
|
||||
/// \param nickname Nickname of buddy in room. Empty if it's normal chat message.
|
||||
/// \param xhtml XHTML message.
|
||||
void handleMessage(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &nickname = "", const std::string &xhtml = "", const std::string ×tamp = "", bool headline = false);
|
||||
void handleMessage(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &nickname = "", const std::string &xhtml = "", const std::string ×tamp = "", bool headline = false, bool pm = false);
|
||||
|
||||
void handleMessageAck(const std::string &user, const std::string &legacyName, const std::string &id);
|
||||
|
||||
|
@ -243,6 +249,8 @@ class NetworkPlugin {
|
|||
virtual void handleFTPauseRequest(unsigned long ftID) {}
|
||||
virtual void handleFTContinueRequest(unsigned long ftID) {}
|
||||
|
||||
virtual void handleRawXML(const std::string &xml) {}
|
||||
|
||||
virtual void handleMemoryUsage(double &res, double &shared) {res = 0; shared = 0;}
|
||||
|
||||
virtual void handleExitRequest() { exit(1); }
|
||||
|
|
|
@ -21,11 +21,18 @@
|
|||
#pragma once
|
||||
|
||||
#include <time.h>
|
||||
#include "Swiften/Swiften.h"
|
||||
#include "Swiften/Presence/PresenceOracle.h"
|
||||
#include "Swiften/Disco/EntityCapsManager.h"
|
||||
#include "Swiften/Network/BoostConnectionServer.h"
|
||||
#include "Swiften/Network/Connection.h"
|
||||
#include "Swiften/Elements/ChatState.h"
|
||||
#include "Swiften/Elements/RosterItemPayload.h"
|
||||
#include "Swiften/Elements/VCard.h"
|
||||
#include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h"
|
||||
#include "Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h"
|
||||
#include "Swiften/Parser/XMPPParser.h"
|
||||
#include "Swiften/Parser/XMPPParserClient.h"
|
||||
#include "Swiften/Serializer/XMPPSerializer.h"
|
||||
#include "storagebackend.h"
|
||||
#include "transport/filetransfermanager.h"
|
||||
|
||||
|
@ -45,7 +52,7 @@ class DummyReadBytestream;
|
|||
class AdminInterface;
|
||||
class DiscoItemsResponder;
|
||||
|
||||
class NetworkPluginServer {
|
||||
class NetworkPluginServer : Swift::XMPPParserClient {
|
||||
public:
|
||||
struct Backend {
|
||||
int pongReceived;
|
||||
|
@ -114,6 +121,7 @@ class NetworkPluginServer {
|
|||
void handleQueryPayload(Backend *b, const std::string &payload);
|
||||
void handleBackendConfigPayload(const std::string &payload);
|
||||
void handleRoomListPayload(const std::string &payload);
|
||||
void handleRawXML(const std::string &xml);
|
||||
|
||||
void handleUserCreated(User *user);
|
||||
void handleRoomJoined(User *user, const Swift::JID &who, const std::string &room, const std::string &nickname, const std::string &password);
|
||||
|
@ -125,6 +133,8 @@ class NetworkPluginServer {
|
|||
void handleBuddyUpdated(Buddy *buddy, const Swift::RosterItemPayload &item);
|
||||
void handleBuddyRemoved(Buddy *buddy);
|
||||
void handleBuddyAdded(Buddy *buddy, const Swift::RosterItemPayload &item);
|
||||
void handleUserBuddyAdded(User *user, Buddy *buddy);
|
||||
void handleUserBuddyRemoved(User *user, Buddy *buddy);
|
||||
|
||||
void handleBlockToggled(Buddy *buddy);
|
||||
|
||||
|
@ -145,6 +155,14 @@ class NetworkPluginServer {
|
|||
Backend *getFreeClient(bool acceptUsers = true, bool longRun = false, bool check = false);
|
||||
void connectWaitingUsers();
|
||||
void loginDelayFinished();
|
||||
void handleRawIQReceived(boost::shared_ptr<Swift::IQ> iq);
|
||||
void handleRawPresenceReceived(boost::shared_ptr<Swift::Presence> presence);
|
||||
|
||||
void handleStreamStart(const Swift::ProtocolHeader&) {}
|
||||
|
||||
void handleElement(boost::shared_ptr<Swift::Element> element);
|
||||
|
||||
void handleStreamEnd() {}
|
||||
|
||||
UserManager *m_userManager;
|
||||
VCardResponder *m_vcardResponder;
|
||||
|
@ -167,6 +185,11 @@ class NetworkPluginServer {
|
|||
bool m_startingBackend;
|
||||
DiscoItemsResponder *m_discoItemsResponder;
|
||||
time_t m_lastLogin;
|
||||
Swift::XMPPParser *m_xmppParser;
|
||||
Swift::FullPayloadParserFactoryCollection m_collection;
|
||||
Swift::XMPPSerializer *m_serializer;
|
||||
Swift::FullPayloadSerializerCollection m_collection2;
|
||||
std::map <std::string, std::string> m_id2resource;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include "Swiften/Swiften.h"
|
||||
#include "transport/storagebackend.h"
|
||||
#include "transport/config.h"
|
||||
#include <pqxx/pqxx>
|
||||
|
|
|
@ -72,6 +72,7 @@ message ConversationMessage {
|
|||
optional string timestamp = 6;
|
||||
optional bool headline = 7;
|
||||
optional string id = 8;
|
||||
optional bool pm = 9;
|
||||
}
|
||||
|
||||
message Room {
|
||||
|
@ -86,6 +87,16 @@ message RoomList {
|
|||
repeated string name = 2;
|
||||
}
|
||||
|
||||
enum ParticipantFlag {
|
||||
PARTICIPANT_FLAG_NONE = 0;
|
||||
PARTICIPANT_FLAG_MODERATOR = 1;
|
||||
PARTICIPANT_FLAG_CONFLICT = 2;
|
||||
PARTICIPANT_FLAG_BANNED = 4;
|
||||
PARTICIPANT_FLAG_NOT_AUTHORIZED = 8;
|
||||
PARTICIPANT_FLAG_ME = 16;
|
||||
PARTICIPANT_FLAG_KICKED = 32;
|
||||
}
|
||||
|
||||
message Participant {
|
||||
required string userName = 1;
|
||||
required string room = 2;
|
||||
|
@ -169,6 +180,7 @@ message WrapperMessage {
|
|||
TYPE_QUERY = 31;
|
||||
TYPE_ROOM_LIST = 32;
|
||||
TYPE_CONV_MESSAGE_ACK = 33;
|
||||
TYPE_RAW_XML = 34;
|
||||
}
|
||||
required Type type = 1;
|
||||
optional bytes payload = 2;
|
||||
|
|
|
@ -25,8 +25,12 @@
|
|||
#include <map>
|
||||
#include <boost/pool/pool_alloc.hpp>
|
||||
#include <boost/pool/object_pool.hpp>
|
||||
#include "Swiften/Swiften.h"
|
||||
// #include "rosterstorage.h"
|
||||
#include "Swiften/Elements/RosterPayload.h"
|
||||
#include "Swiften/Queries/GenericRequest.h"
|
||||
#include "Swiften/Roster/SetRosterRequest.h"
|
||||
#include "Swiften/Elements/Presence.h"
|
||||
#include "Swiften/Network/Timer.h"
|
||||
|
||||
namespace Transport {
|
||||
|
||||
|
|
|
@ -21,10 +21,11 @@
|
|||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "Swiften/Swiften.h"
|
||||
#include "Swiften/Queries/Responder.h"
|
||||
#include "Swiften/Elements/RosterPayload.h"
|
||||
|
||||
#include <boost/signal.hpp>
|
||||
|
||||
namespace Transport {
|
||||
|
||||
class UserManager;
|
||||
|
|
|
@ -22,7 +22,9 @@
|
|||
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include "Swiften/Swiften.h"
|
||||
#include <map>
|
||||
|
||||
#include "Swiften/Network/Timer.h"
|
||||
|
||||
namespace Transport {
|
||||
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include "Swiften/Swiften.h"
|
||||
#include "transport/adhoccommand.h"
|
||||
#include "transport/adhoccommandfactory.h"
|
||||
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include "Swiften/Swiften.h"
|
||||
#include "transport/storagebackend.h"
|
||||
#include "transport/config.h"
|
||||
#include "sqlite3.h"
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "Swiften/Swiften.h"
|
||||
#include "Swiften/Queries/SetResponder.h"
|
||||
#include "Swiften/Elements/StatsPayload.h"
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#include <queue>
|
||||
#include <iostream>
|
||||
#include "transport/logging.h"
|
||||
#include "Swiften/Swiften.h"
|
||||
#include "Swiften/EventLoop/EventLoop.h"
|
||||
|
||||
|
||||
/*
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "Swiften/Swiften.h"
|
||||
#include "Swiften/Server/Server.h"
|
||||
#include "Swiften/Disco/GetDiscoInfoRequest.h"
|
||||
#include "Swiften/Disco/EntityCapsManager.h"
|
||||
|
@ -31,7 +30,11 @@
|
|||
#include "Swiften/Network/BoostIOServiceThread.h"
|
||||
#include "Swiften/Server/UserRegistry.h"
|
||||
#include "Swiften/Base/SafeByteArray.h"
|
||||
#include "Swiften/Queries/IQHandler.h"
|
||||
#include "Swiften/Jingle/JingleSessionManager.h"
|
||||
#include "Swiften/Component/ComponentError.h"
|
||||
#include "Swiften/Component/Component.h"
|
||||
#include "Swiften/Queries/IQHandler.h"
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
#include "transport/config.h"
|
||||
|
@ -40,12 +43,6 @@
|
|||
#include <Swiften/Network/BoostConnectionServer.h>
|
||||
|
||||
namespace Transport {
|
||||
// typedef enum { CLIENT_FEATURE_ROSTERX = 2,
|
||||
// CLIENT_FEATURE_XHTML_IM = 4,
|
||||
// CLIENT_FEATURE_FILETRANSFER = 8,
|
||||
// CLIENT_FEATURE_CHATSTATES = 16
|
||||
// } SpectrumImportantFeatures;
|
||||
//
|
||||
class StorageBackend;
|
||||
class Factory;
|
||||
class UserRegistry;
|
||||
|
@ -57,7 +54,7 @@ namespace Transport {
|
|||
///
|
||||
/// In server mode it represents Jabber server to which users can connect and use
|
||||
/// it as transport.
|
||||
class Component {
|
||||
class Component : Swift::IQHandler {
|
||||
public:
|
||||
/// Creates new Component instance.
|
||||
|
||||
|
@ -68,7 +65,9 @@ namespace Transport {
|
|||
/// - service.server
|
||||
/// - service.port
|
||||
/// - service.server_mode
|
||||
/// \param factories Swift::NetworkFactories.
|
||||
/// \param factory Transport Abstract factory used to create basic transport structures.
|
||||
/// \param userRegistery UserRegistry class instance. It's needed only when running transport in server-mode.
|
||||
Component(Swift::EventLoop *loop, Swift::NetworkFactories *factories, Config *config, Factory *factory, Transport::UserRegistry *userRegistry = NULL);
|
||||
|
||||
/// Component destructor.
|
||||
|
@ -96,9 +95,13 @@ namespace Transport {
|
|||
/// \return True if the component is in server mode.
|
||||
bool inServerMode() { return m_server != NULL; }
|
||||
|
||||
/// Connects the Jabber server.
|
||||
|
||||
/// Starts the Component.
|
||||
|
||||
/// In server-mode, it starts listening on particular port for new client connections.
|
||||
/// In gateway-mode, it connects the XMPP server.
|
||||
void start();
|
||||
|
||||
/// Stops the component.
|
||||
void stop();
|
||||
|
||||
/// Returns Jabber ID of this transport.
|
||||
|
@ -139,13 +142,18 @@ namespace Transport {
|
|||
/// This signal is emitted when presence from XMPP user is received.
|
||||
|
||||
/// It's emitted only for presences addressed to transport itself
|
||||
/// (for example to="j2j.domain.tld").
|
||||
/// \param presence presence data
|
||||
/// (for example to="j2j.domain.tld") and for presences comming to
|
||||
/// MUC (for example to="#chat%irc.freenode.org@irc.domain.tld")
|
||||
/// \param presence Presence.
|
||||
boost::signal<void (Swift::Presence::ref presence)> onUserPresenceReceived;
|
||||
|
||||
/// Component class asks the XMPP clients automatically for their capabilities.
|
||||
/// This signal is emitted when capabilities have been received or changed.
|
||||
/// \param jid JID of the client for which we received capabilities
|
||||
/// \param info disco#info with response.
|
||||
boost::signal<void (const Swift::JID& jid, boost::shared_ptr<Swift::DiscoInfo> info)> onUserDiscoInfoReceived;
|
||||
|
||||
// boost::signal<void (boost::shared_ptr<Swift::DiscoInfo> info, Swift::ErrorPayload::ref error, const Swift::JID& jid)> onDiscoInfoResponse;
|
||||
boost::signal<void (boost::shared_ptr<Swift::IQ>)> onRawIQReceived;
|
||||
|
||||
private:
|
||||
void handleConnected();
|
||||
|
@ -158,6 +166,9 @@ namespace Transport {
|
|||
void handleDiscoInfoResponse(boost::shared_ptr<Swift::DiscoInfo> info, Swift::ErrorPayload::ref error, const Swift::JID& jid);
|
||||
void handleCapsChanged(const Swift::JID& jid);
|
||||
|
||||
void handleBackendConfigChanged();
|
||||
bool handleIQ(boost::shared_ptr<Swift::IQ>);
|
||||
|
||||
Swift::NetworkFactories *m_factories;
|
||||
Swift::Component *m_component;
|
||||
Swift::Server *m_server;
|
||||
|
@ -177,6 +188,7 @@ namespace Transport {
|
|||
Swift::JID m_jid;
|
||||
Factory *m_factory;
|
||||
Swift::EventLoop *m_loop;
|
||||
bool m_rawXML;
|
||||
|
||||
friend class User;
|
||||
friend class UserRegistration;
|
||||
|
|
|
@ -21,12 +21,13 @@
|
|||
#pragma once
|
||||
|
||||
#include <time.h>
|
||||
#include "Swiften/Swiften.h"
|
||||
#include "Swiften/Disco/EntityCapsManager.h"
|
||||
#include "Swiften/Disco/EntityCapsProvider.h"
|
||||
#include "storagebackend.h"
|
||||
#include <Swiften/FileTransfer/OutgoingFileTransfer.h>
|
||||
#include "Swiften/Elements/SpectrumErrorPayload.h"
|
||||
#include "Swiften/Network/Timer.h"
|
||||
#include "Swiften/Network/Connection.h"
|
||||
|
||||
namespace Transport {
|
||||
|
||||
|
@ -132,6 +133,7 @@ class User : public Swift::EntityCapsProvider {
|
|||
|
||||
boost::signal<void ()> onReadyToConnect;
|
||||
boost::signal<void (Swift::Presence::ref presence)> onPresenceChanged;
|
||||
boost::signal<void (Swift::Presence::ref presence)> onRawPresenceReceived;
|
||||
boost::signal<void (const Swift::JID &who, const std::string &room, const std::string &nickname, const std::string &password)> onRoomJoined;
|
||||
boost::signal<void (const std::string &room)> onRoomLeft;
|
||||
boost::signal<void ()> onDisconnected;
|
||||
|
|
|
@ -22,8 +22,12 @@
|
|||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include "Swiften/Swiften.h"
|
||||
#include "transport/userregistry.h"
|
||||
#include "Swiften/Elements/Message.h"
|
||||
#include "Swiften/Elements/Presence.h"
|
||||
#include "Swiften/Disco/EntityCapsProvider.h"
|
||||
#include "Swiften/Elements/DiscoInfo.h"
|
||||
#include "Swiften/Network/Timer.h"
|
||||
|
||||
namespace Transport {
|
||||
|
||||
|
@ -133,6 +137,7 @@ class UserManager : public Swift::EntityCapsProvider {
|
|||
void handleProbePresence(Swift::Presence::ref presence);
|
||||
void handleErrorPresence(Swift::Presence::ref presence);
|
||||
void handleSubscription(Swift::Presence::ref presence);
|
||||
void handleMUCPresence(Swift::Presence::ref presence);
|
||||
void handleRemoveTimeout(const std::string jid, User *user, bool reconnect);
|
||||
void handleDiscoInfo(const Swift::JID& jid, boost::shared_ptr<Swift::DiscoInfo> info);
|
||||
void addUser(User *user);
|
||||
|
|
|
@ -20,9 +20,10 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "Swiften/Swiften.h"
|
||||
#include "Swiften/Queries/Responder.h"
|
||||
#include "Swiften/Elements/InBandRegistrationPayload.h"
|
||||
#include "Swiften/Elements/RosterPayload.h"
|
||||
#include <boost/signal.hpp>
|
||||
|
||||
namespace Transport {
|
||||
|
||||
|
|
|
@ -22,8 +22,10 @@
|
|||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include "Swiften/Swiften.h"
|
||||
#include "Swiften/Server/UserRegistry.h"
|
||||
#include "Swiften/Network/NetworkFactories.h"
|
||||
#include "Swiften/Network/Timer.h"
|
||||
#include "Swiften/Network/TimerFactory.h"
|
||||
#include "transport/config.h"
|
||||
|
||||
namespace Transport {
|
||||
|
|
|
@ -23,7 +23,8 @@
|
|||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include "Swiften/Swiften.h"
|
||||
|
||||
#include "Swiften/Network/Timer.h"
|
||||
|
||||
namespace Transport {
|
||||
|
||||
|
|
|
@ -21,9 +21,11 @@
|
|||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "Swiften/Swiften.h"
|
||||
#include "Swiften/Queries/Responder.h"
|
||||
#include "Swiften/Elements/VCard.h"
|
||||
#include "Swiften/Network/NetworkFactories.h"
|
||||
#include "Swiften/Network/Timer.h"
|
||||
#include <boost/signal.hpp>
|
||||
|
||||
namespace Transport {
|
||||
|
||||
|
|
|
@ -21,10 +21,9 @@
|
|||
# You have to configure the plugin to run as user and group "spectrum".
|
||||
#
|
||||
# By default, the plugin monitors all instances configured in a config-file
|
||||
# in /etc/spectrum. If you use a different directory, you can specify the
|
||||
# environment-variable "base". If you do not want to monitor all instances,
|
||||
# you can give an explicit listing of the corresponding configuration files
|
||||
# with the environment variable "cfgs".
|
||||
# in /etc/spectrum2/transports. If you do not want to monitor all instances,
|
||||
# you can give an explicit listing of the corresponding instances
|
||||
# with the environment variable "jids".
|
||||
#
|
||||
# Here is an example of a configuration. Note again that you can ommit both
|
||||
# env.cfgs and env.base:
|
||||
|
@ -32,8 +31,7 @@
|
|||
# [spectrum_*]
|
||||
# user spectrum
|
||||
# group spectrum
|
||||
# env.cfgs xmpp.example.com.cfg,irc.example.com.cfg
|
||||
# env.base /etc/spectrum
|
||||
# env.jids xmpp.example.com,irc.example.com
|
||||
#
|
||||
# Author:
|
||||
# Mathias Ertl <mati@fsinf.at>
|
||||
|
@ -94,9 +92,16 @@ def handle_field( string ):
|
|||
# get runtime variables
|
||||
suffix = sys.argv[0].partition('_')[2]
|
||||
verbose = os.environ.get( 'verbose' )
|
||||
proc = Popen(['spectrum2_manager', 'list'], stdout=PIPE, stderr=PIPE)
|
||||
out, err = proc.communicate()
|
||||
jids = out.split('\n')[:-1]
|
||||
|
||||
jids = []
|
||||
|
||||
base = os.environ.get( 'base', '/etc/spectrum' )
|
||||
if 'jids' in os.environ.keys():
|
||||
jids = os.environ.get( 'jids' ).split(',')
|
||||
else:
|
||||
proc = Popen(['spectrum2_manager', 'list'], stdout=PIPE, stderr=PIPE)
|
||||
out, err = proc.communicate()
|
||||
jids = out.split('\n')[:-1]
|
||||
|
||||
# set variables based on wildcard
|
||||
if suffix == 'uptime':
|
||||
|
|
|
@ -71,6 +71,10 @@ void NetworkPlugin::sendConfig(const PluginConfig &cfg) {
|
|||
data += std::string("extraField=") + (*it) + "\n";
|
||||
}
|
||||
|
||||
data += "[features]\n";
|
||||
data += std::string("muc=") + (cfg.m_supportMUC ? "1" : "0") + "\n";
|
||||
data += std::string("rawxml=") + (cfg.m_rawXML ? "1" : "0") + "\n";
|
||||
|
||||
pbnetwork::BackendConfig m;
|
||||
m.set_config(data);
|
||||
|
||||
|
@ -82,7 +86,13 @@ void NetworkPlugin::sendConfig(const PluginConfig &cfg) {
|
|||
send(message);
|
||||
}
|
||||
|
||||
void NetworkPlugin::handleMessage(const std::string &user, const std::string &legacyName, const std::string &msg, const std::string &nickname, const std::string &xhtml, const std::string ×tamp, bool headline) {
|
||||
void NetworkPlugin::sendRawXML(std::string &xml) {
|
||||
WRAP(xml, pbnetwork::WrapperMessage_Type_TYPE_RAW_XML);
|
||||
|
||||
send(xml);
|
||||
}
|
||||
|
||||
void NetworkPlugin::handleMessage(const std::string &user, const std::string &legacyName, const std::string &msg, const std::string &nickname, const std::string &xhtml, const std::string ×tamp, bool headline, bool pm) {
|
||||
pbnetwork::ConversationMessage m;
|
||||
m.set_username(user);
|
||||
m.set_buddyname(legacyName);
|
||||
|
@ -91,6 +101,7 @@ void NetworkPlugin::handleMessage(const std::string &user, const std::string &le
|
|||
m.set_xhtml(xhtml);
|
||||
m.set_timestamp(timestamp);
|
||||
m.set_headline(headline);
|
||||
m.set_pm(pm);
|
||||
|
||||
std::string message;
|
||||
m.SerializeToString(&message);
|
||||
|
@ -643,6 +654,9 @@ void NetworkPlugin::handleDataRead(std::string &data) {
|
|||
case pbnetwork::WrapperMessage_Type_TYPE_EXIT:
|
||||
handleExitRequest();
|
||||
break;
|
||||
case pbnetwork::WrapperMessage_Type_TYPE_RAW_XML:
|
||||
handleRawXML(wrapper.payload());
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "transport/adhocmanager.h"
|
||||
#include "transport/settingsadhoccommand.h"
|
||||
#include "Swiften/EventLoop/SimpleEventLoop.h"
|
||||
#include "Swiften/Network/BoostNetworkFactories.h"
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#ifndef WIN32
|
||||
|
@ -27,8 +28,10 @@
|
|||
#include <sys/resource.h>
|
||||
#include "libgen.h"
|
||||
#ifndef __FreeBSD__
|
||||
#ifndef __MACH__
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
#include <process.h>
|
||||
#define getpid _getpid
|
||||
|
@ -307,10 +310,12 @@ int main(int argc, char **argv)
|
|||
setlocale(LC_ALL, "");
|
||||
#ifndef WIN32
|
||||
#ifndef __FreeBSD__
|
||||
#ifndef __MACH__
|
||||
mallopt(M_CHECK_ACTION, 2);
|
||||
mallopt(M_PERTURB, 0xb);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef WIN32
|
||||
if (signal(SIGINT, spectrum_sigint_handler) == SIG_ERR) {
|
||||
|
|
|
@ -13,15 +13,15 @@ admin_password=test
|
|||
#cert=server.pfx #patch to PKCS#12 certificate
|
||||
#cert_password=test #password to that certificate if any
|
||||
users_per_backend=10
|
||||
backend=../..//backends/swiften/spectrum2_swiften_backend
|
||||
#backend=../..//backends/swiften/spectrum2_swiften_backend
|
||||
#backend=../../backends/twitter/spectrum2_twitter_backend
|
||||
#backend=/home/hanzz/code/libtransport/backends/libcommuni/spectrum2_libcommuni_backend
|
||||
backend=/home/hanzz/code/libtransport/backends/libcommuni/spectrum2_libcommuni_backend
|
||||
protocol=prpl-jabber
|
||||
#protocol=prpl-msn
|
||||
#protocol=any
|
||||
#protocol=prpl-icq
|
||||
working_dir=./
|
||||
portfile=$jid.port
|
||||
portfile=./$jid.port
|
||||
irc_server=irc.freenode.org
|
||||
|
||||
[backend]
|
||||
|
|
|
@ -14,7 +14,7 @@ jid = localhost
|
|||
password = secret
|
||||
|
||||
# XMPP server to which Spectrum connects in gateway mode.
|
||||
# In server mode, this option is ignored.
|
||||
# To bind to all ipv4 interfaces, use server=0.0.0.0
|
||||
server = 127.0.0.1
|
||||
|
||||
# XMPP server port.
|
||||
|
@ -41,7 +41,7 @@ users_per_backend=10
|
|||
backend=/usr/bin/spectrum2_libpurple_backend
|
||||
#backend=/usr/bin/spectrum2_libcommuni_backend
|
||||
# For skype:
|
||||
#backend=/usr/bin/xvfb-run -n BACKEND_ID -s "-screen 0 10x10x8" -f /tmp/x-skype-gw /usr/bin/spectrum2_skype_backend
|
||||
#backend=/usr/bin/xvfb-run -a -s "-screen 0 10x10x8" -f /tmp/x-skype-gw /usr/bin/spectrum2_skype_backend
|
||||
|
||||
# Libpurple protocol-id for spectrum_libpurple_backend
|
||||
protocol=prpl-jabber
|
||||
|
|
|
@ -7,7 +7,10 @@ ADD_DEPENDENCIES(spectrum2_manager pb)
|
|||
SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_SOURCE_DIR}/../../include/transport/protocol.pb.cc PROPERTIES GENERATED 1)
|
||||
|
||||
target_link_libraries(spectrum2_manager ${SWIFTEN_LIBRARY} ${PROTOBUF_LIBRARIES})
|
||||
|
||||
|
||||
if(APPLE)
|
||||
target_link_libraries(spectrum2_manager ${APPLE_FRAMEWORKS})
|
||||
endif()
|
||||
INSTALL(TARGETS spectrum2_manager RUNTIME DESTINATION bin)
|
||||
|
||||
INSTALL(FILES
|
||||
|
|
|
@ -138,6 +138,9 @@ int main(int argc, char **argv)
|
|||
else if (command[0] == "list") {
|
||||
std::vector<std::string> list = show_list(&config);
|
||||
}
|
||||
else if (command[0] == "restart") {
|
||||
return restart_instances(&config);
|
||||
}
|
||||
else if (command[0] == "server") {
|
||||
Server server(&config);
|
||||
if (server.start() == false) {
|
||||
|
|
|
@ -3,7 +3,7 @@ FILE(GLOB SRC *.cpp *.h)
|
|||
FILE(GLOB_RECURSE SWIFTEN_SRC ../include/Swiften/*.cpp)
|
||||
|
||||
# Build without openssl on msvc
|
||||
if (CMAKE_COMPILER_IS_GNUCXX)
|
||||
if (NOT MSVC)
|
||||
string(REGEX REPLACE "[^;]+;?/Schannel/[^;]+;?" "" SWIFTEN_SRC "${SWIFTEN_SRC}")
|
||||
else()
|
||||
string(REGEX REPLACE "[^;]+;?/OpenSSL/[^;]+;?" "" SWIFTEN_SRC "${SWIFTEN_SRC}")
|
||||
|
@ -47,7 +47,7 @@ endif(PROTOBUF_FOUND)
|
|||
|
||||
if (WIN32)
|
||||
include_directories("${CMAKE_SOURCE_DIR}/msvc-deps/sqlite3")
|
||||
TARGET_LINK_LIBRARIES(transport transport-plugin sqlite3 ${PQXX_LIBRARY} ${PQ_LIBRARY} ${MYSQL_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES} ${PROTOBUF_LIBRARY})
|
||||
TARGET_LINK_LIBRARIES(transport transport-plugin sqlite3 ${PQXX_LIBRARY} ${PQ_LIBRARY} ${MYSQL_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES} ${PROTOBUF_LIBRARY} psapi.lib)
|
||||
else()
|
||||
TARGET_LINK_LIBRARIES(transport transport-plugin ${PQXX_LIBRARY} ${PQ_LIBRARY} ${SQLITE3_LIBRARIES} ${MYSQL_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES} ${POPT_LIBRARY} ${PROTOBUF_LIBRARY})
|
||||
endif()
|
||||
|
@ -55,6 +55,9 @@ endif()
|
|||
SET_TARGET_PROPERTIES(transport PROPERTIES
|
||||
VERSION ${TRANSPORT_VERSION} SOVERSION ${TRANSPORT_VERSION}
|
||||
)
|
||||
if (APPLE)
|
||||
TARGET_LINK_LIBRARIES(transport ${APPLE_FRAMEWORKS})
|
||||
endif()
|
||||
|
||||
INSTALL(TARGETS transport LIBRARY DESTINATION ${LIB_INSTALL_DIR} ARCHIVE DESTINATION ${LIB_INSTALL_DIR} COMPONENT libraries)
|
||||
|
||||
|
|
|
@ -136,10 +136,7 @@ void AdminInterface::handleQuery(Swift::Message::ref message) {
|
|||
else if (message->getBody() == "res_memory") {
|
||||
double shared = 0;
|
||||
double rss = 0;
|
||||
#ifndef WIN32
|
||||
process_mem_usage(shared, rss);
|
||||
#endif
|
||||
|
||||
const std::list <NetworkPluginServer::Backend *> &backends = m_server->getBackends();
|
||||
BOOST_FOREACH(NetworkPluginServer::Backend * backend, backends) {
|
||||
rss += backend->res;
|
||||
|
@ -150,10 +147,7 @@ void AdminInterface::handleQuery(Swift::Message::ref message) {
|
|||
else if (message->getBody() == "shr_memory") {
|
||||
double shared = 0;
|
||||
double rss = 0;
|
||||
#ifndef WIN32
|
||||
process_mem_usage(shared, rss);
|
||||
#endif
|
||||
|
||||
const std::list <NetworkPluginServer::Backend *> &backends = m_server->getBackends();
|
||||
BOOST_FOREACH(NetworkPluginServer::Backend * backend, backends) {
|
||||
shared += backend->shared;
|
||||
|
@ -164,9 +158,7 @@ void AdminInterface::handleQuery(Swift::Message::ref message) {
|
|||
else if (message->getBody() == "used_memory") {
|
||||
double shared = 0;
|
||||
double rss = 0;
|
||||
#ifndef WIN32
|
||||
process_mem_usage(shared, rss);
|
||||
#endif
|
||||
rss -= shared;
|
||||
|
||||
const std::list <NetworkPluginServer::Backend *> &backends = m_server->getBackends();
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#include <boost/bind.hpp>
|
||||
#include "Swiften/Queries/IQRouter.h"
|
||||
#include "transport/BlockPayload.h"
|
||||
#include "Swiften/Swiften.h"
|
||||
#include "transport/usermanager.h"
|
||||
#include "transport/user.h"
|
||||
#include "transport/buddy.h"
|
||||
|
|
|
@ -21,9 +21,9 @@
|
|||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "Swiften/Swiften.h"
|
||||
#include "Swiften/Queries/SetResponder.h"
|
||||
#include "transport/BlockPayload.h"
|
||||
#include <boost/signal.hpp>
|
||||
|
||||
namespace Transport {
|
||||
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
#include "transport/usermanager.h"
|
||||
#include "transport/discoitemsresponder.h"
|
||||
|
||||
#include "Swiften/Elements/VCardUpdate.h"
|
||||
|
||||
namespace Transport {
|
||||
|
||||
Buddy::Buddy(RosterManager *rosterManager, long id, BuddyFlag flags) : m_id(id), m_flags(flags), m_rosterManager(rosterManager),
|
||||
|
@ -101,15 +103,19 @@ Swift::Presence::ref Buddy::generatePresenceStanza(int features, bool only_new)
|
|||
}
|
||||
|
||||
Swift::Presence::ref presence = Swift::Presence::create();
|
||||
presence->setFrom(m_jid);
|
||||
presence->setTo(m_rosterManager->getUser()->getJID().toBare());
|
||||
presence->setType(Swift::Presence::Available);
|
||||
|
||||
if (!statusMessage.empty())
|
||||
presence->setStatus(statusMessage);
|
||||
|
||||
if (s.getType() == Swift::StatusShow::None)
|
||||
if (s.getType() == Swift::StatusShow::None) {
|
||||
presence->setType(Swift::Presence::Unavailable);
|
||||
presence->setFrom(Swift::JID(m_jid.getNode(), m_jid.getDomain()));
|
||||
}
|
||||
else {
|
||||
presence->setFrom(m_jid);
|
||||
}
|
||||
presence->setShow(s.getType());
|
||||
|
||||
if (presence->getType() != Swift::Presence::Unavailable) {
|
||||
|
|
|
@ -314,6 +314,8 @@ void Config::updateBackendConfig(const std::string &backendConfig) {
|
|||
("registration.needRegistration", value<bool>()->default_value(false), "")
|
||||
("registration.extraField", value<std::vector<std::string> >()->multitoken(), "")
|
||||
("features.receipts", value<bool>()->default_value(false), "")
|
||||
("features.muc", value<bool>()->default_value(false), "")
|
||||
("features.rawxml", value<bool>()->default_value(false), "")
|
||||
;
|
||||
|
||||
std::stringstream ifs(backendConfig);
|
||||
|
|
|
@ -26,6 +26,12 @@
|
|||
#include "transport/buddy.h"
|
||||
#include "transport/rostermanager.h"
|
||||
|
||||
#include "Swiften/Elements/MUCItem.h"
|
||||
#include "Swiften/Elements/MUCOccupant.h"
|
||||
#include "Swiften/Elements/MUCUserPayload.h"
|
||||
#include "Swiften/Elements/Delay.h"
|
||||
#include "Swiften/Elements/MUCPayload.h"
|
||||
|
||||
namespace Transport {
|
||||
|
||||
Conversation::Conversation(ConversationManager *conversationManager, const std::string &legacyName, bool isMUC) : m_conversationManager(conversationManager) {
|
||||
|
@ -33,6 +39,10 @@ Conversation::Conversation(ConversationManager *conversationManager, const std::
|
|||
m_muc = isMUC;
|
||||
m_jid = m_conversationManager->getUser()->getJID().toBare();
|
||||
m_sentInitialPresence = false;
|
||||
|
||||
if (CONFIG_BOOL_DEFAULTED(conversationManager->getComponent()->getConfig(), "features.rawxml", false)) {
|
||||
m_sentInitialPresence = true;
|
||||
}
|
||||
}
|
||||
|
||||
Conversation::~Conversation() {
|
||||
|
@ -76,6 +86,47 @@ void Conversation::setRoom(const std::string &room) {
|
|||
m_legacyName = m_room + "/" + m_legacyName;
|
||||
}
|
||||
|
||||
void Conversation::handleRawMessage(boost::shared_ptr<Swift::Message> &message) {
|
||||
if (message->getType() != Swift::Message::Groupchat) {
|
||||
if (m_conversationManager->getComponent()->inServerMode() && m_conversationManager->getUser()->shouldCacheMessages()) {
|
||||
boost::posix_time::ptime timestamp = boost::posix_time::second_clock::universal_time();
|
||||
boost::shared_ptr<Swift::Delay> delay(boost::make_shared<Swift::Delay>());
|
||||
delay->setStamp(timestamp);
|
||||
message->addPayload(delay);
|
||||
m_cachedMessages.push_back(message);
|
||||
if (m_cachedMessages.size() > 100) {
|
||||
m_cachedMessages.pop_front();
|
||||
}
|
||||
}
|
||||
else {
|
||||
m_conversationManager->getComponent()->getStanzaChannel()->sendMessage(message);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (m_jids.empty()) {
|
||||
boost::posix_time::ptime timestamp = boost::posix_time::second_clock::universal_time();
|
||||
boost::shared_ptr<Swift::Delay> delay(boost::make_shared<Swift::Delay>());
|
||||
delay->setStamp(timestamp);
|
||||
message->addPayload(delay);
|
||||
m_cachedMessages.push_back(message);
|
||||
if (m_cachedMessages.size() > 100) {
|
||||
m_cachedMessages.pop_front();
|
||||
}
|
||||
}
|
||||
else {
|
||||
BOOST_FOREACH(const Swift::JID &jid, m_jids) {
|
||||
message->setTo(jid);
|
||||
// Subject has to be sent after our own presence (the one with code 110)
|
||||
if (!message->getSubject().empty() && m_sentInitialPresence == false) {
|
||||
m_subject = message;
|
||||
return;
|
||||
}
|
||||
m_conversationManager->getComponent()->getStanzaChannel()->sendMessage(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Conversation::handleMessage(boost::shared_ptr<Swift::Message> &message, const std::string &nickname) {
|
||||
if (m_muc) {
|
||||
message->setType(Swift::Message::Groupchat);
|
||||
|
@ -124,23 +175,13 @@ void Conversation::handleMessage(boost::shared_ptr<Swift::Message> &message, con
|
|||
message->setFrom(Swift::JID(n, m_conversationManager->getComponent()->getJID().toBare(), "user"));
|
||||
}
|
||||
else {
|
||||
message->setFrom(Swift::JID(m_room, m_conversationManager->getComponent()->getJID().toBare(), n));
|
||||
std::string legacyName = m_room;
|
||||
if (legacyName.find_last_of("@") != std::string::npos) {
|
||||
legacyName.replace(legacyName.find_last_of("@"), 1, "%"); // OK
|
||||
}
|
||||
message->setFrom(Swift::JID(legacyName, m_conversationManager->getComponent()->getJID().toBare(), n));
|
||||
}
|
||||
}
|
||||
|
||||
if (m_conversationManager->getComponent()->inServerMode() && m_conversationManager->getUser()->shouldCacheMessages()) {
|
||||
boost::posix_time::ptime timestamp = boost::posix_time::second_clock::universal_time();
|
||||
boost::shared_ptr<Swift::Delay> delay(boost::make_shared<Swift::Delay>());
|
||||
delay->setStamp(timestamp);
|
||||
message->addPayload(delay);
|
||||
m_cachedMessages.push_back(message);
|
||||
if (m_cachedMessages.size() > 100) {
|
||||
m_cachedMessages.pop_front();
|
||||
}
|
||||
}
|
||||
else {
|
||||
m_conversationManager->getComponent()->getStanzaChannel()->sendMessage(message);
|
||||
}
|
||||
}
|
||||
else {
|
||||
std::string legacyName = m_legacyName;
|
||||
|
@ -154,29 +195,9 @@ void Conversation::handleMessage(boost::shared_ptr<Swift::Message> &message, con
|
|||
}
|
||||
|
||||
message->setFrom(Swift::JID(legacyName, m_conversationManager->getComponent()->getJID().toBare(), n));
|
||||
|
||||
if (m_jids.empty()) {
|
||||
boost::posix_time::ptime timestamp = boost::posix_time::second_clock::universal_time();
|
||||
boost::shared_ptr<Swift::Delay> delay(boost::make_shared<Swift::Delay>());
|
||||
delay->setStamp(timestamp);
|
||||
message->addPayload(delay);
|
||||
m_cachedMessages.push_back(message);
|
||||
if (m_cachedMessages.size() > 100) {
|
||||
m_cachedMessages.pop_front();
|
||||
}
|
||||
}
|
||||
else {
|
||||
BOOST_FOREACH(const Swift::JID &jid, m_jids) {
|
||||
message->setTo(jid);
|
||||
// Subject has to be sent after our own presence (the one with code 110)
|
||||
if (!message->getSubject().empty() && m_sentInitialPresence == false) {
|
||||
m_subject = message;
|
||||
return;
|
||||
}
|
||||
m_conversationManager->getComponent()->getStanzaChannel()->sendMessage(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handleRawMessage(message);
|
||||
}
|
||||
|
||||
void Conversation::sendParticipants(const Swift::JID &to) {
|
||||
|
@ -225,19 +246,35 @@ Swift::Presence::ref Conversation::generatePresence(const std::string &nick, int
|
|||
|
||||
Swift::MUCUserPayload *p = new Swift::MUCUserPayload ();
|
||||
if (m_nickname == nickname) {
|
||||
Swift::MUCUserPayload::StatusCode c;
|
||||
c.code = 110;
|
||||
p->addStatusCode(c);
|
||||
m_sentInitialPresence = true;
|
||||
if (flag & PARTICIPANT_FLAG_CONFLICT) {
|
||||
delete p;
|
||||
presence->setType(Swift::Presence::Error);
|
||||
presence->addPayload(boost::shared_ptr<Swift::Payload>(new Swift::MUCPayload()));
|
||||
presence->addPayload(boost::shared_ptr<Swift::Payload>(new Swift::ErrorPayload(Swift::ErrorPayload::Conflict)));
|
||||
return presence;
|
||||
}
|
||||
else if (flag & PARTICIPANT_FLAG_NOT_AUTHORIZED) {
|
||||
delete p;
|
||||
presence->setType(Swift::Presence::Error);
|
||||
presence->addPayload(boost::shared_ptr<Swift::Payload>(new Swift::MUCPayload()));
|
||||
presence->addPayload(boost::shared_ptr<Swift::Payload>(new Swift::ErrorPayload(Swift::ErrorPayload::NotAuthorized, Swift::ErrorPayload::Auth)));
|
||||
return presence;
|
||||
}
|
||||
else {
|
||||
Swift::MUCUserPayload::StatusCode c;
|
||||
c.code = 110;
|
||||
p->addStatusCode(c);
|
||||
m_sentInitialPresence = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Swift::MUCItem item;
|
||||
|
||||
item.affiliation = Swift::MUCOccupant::Member;
|
||||
item.role = Swift::MUCOccupant::Participant;
|
||||
|
||||
if (flag & Moderator) {
|
||||
if (flag & PARTICIPANT_FLAG_MODERATOR) {
|
||||
item.affiliation = Swift::MUCOccupant::Admin;
|
||||
item.role = Swift::MUCOccupant::Moderator;
|
||||
}
|
||||
|
@ -249,13 +286,13 @@ Swift::Presence::ref Conversation::generatePresence(const std::string &nick, int
|
|||
p->addStatusCode(c);
|
||||
presence->setType(Swift::Presence::Unavailable);
|
||||
}
|
||||
|
||||
|
||||
p->addItem(item);
|
||||
presence->addPayload(boost::shared_ptr<Swift::Payload>(p));
|
||||
return presence;
|
||||
}
|
||||
|
||||
void Conversation::handleParticipantChanged(const std::string &nick, int flag, int status, const std::string &statusMessage, const std::string &newname) {
|
||||
void Conversation::handleParticipantChanged(const std::string &nick, Conversation::ParticipantFlag flag, int status, const std::string &statusMessage, const std::string &newname) {
|
||||
Swift::Presence::ref presence = generatePresence(nick, flag, status, statusMessage, newname);
|
||||
|
||||
if (presence->getType() == Swift::Presence::Unavailable) {
|
||||
|
|
|
@ -26,9 +26,9 @@
|
|||
#include "Swiften/Disco/DiscoInfoResponder.h"
|
||||
#include "Swiften/Queries/IQRouter.h"
|
||||
#include "Swiften/Elements/DiscoInfo.h"
|
||||
#include "Swiften/Swiften.h"
|
||||
#include "transport/config.h"
|
||||
#include "transport/logging.h"
|
||||
#include "Swiften/Disco/CapsInfoGenerator.h"
|
||||
|
||||
using namespace Swift;
|
||||
using namespace boost;
|
||||
|
@ -39,28 +39,31 @@ namespace Transport {
|
|||
|
||||
DiscoInfoResponder::DiscoInfoResponder(Swift::IQRouter *router, Config *config) : Swift::GetResponder<DiscoInfo>(router) {
|
||||
m_config = config;
|
||||
m_config->onBackendConfigUpdated.connect(boost::bind(&DiscoInfoResponder::updateBuddyFeatures, this));
|
||||
m_config->onBackendConfigUpdated.connect(boost::bind(&DiscoInfoResponder::updateFeatures, this));
|
||||
m_buddyInfo = NULL;
|
||||
m_transportInfo.addIdentity(DiscoInfo::Identity(CONFIG_STRING(m_config, "identity.name"),
|
||||
CONFIG_STRING(m_config, "identity.category"),
|
||||
CONFIG_STRING(m_config, "identity.type")));
|
||||
|
||||
std::list<std::string> features;
|
||||
features.push_back("jabber:iq:register");
|
||||
features.push_back("jabber:iq:gateway");
|
||||
features.push_back("jabber:iq:private");
|
||||
features.push_back("http://jabber.org/protocol/disco#info");
|
||||
features.push_back("http://jabber.org/protocol/commands");
|
||||
setTransportFeatures(features);
|
||||
|
||||
updateBuddyFeatures();
|
||||
updateFeatures();
|
||||
}
|
||||
|
||||
DiscoInfoResponder::~DiscoInfoResponder() {
|
||||
delete m_buddyInfo;
|
||||
}
|
||||
|
||||
void DiscoInfoResponder::updateBuddyFeatures() {
|
||||
void DiscoInfoResponder::updateFeatures() {
|
||||
std::list<std::string> features2;
|
||||
features2.push_back("jabber:iq:register");
|
||||
features2.push_back("jabber:iq:gateway");
|
||||
features2.push_back("jabber:iq:private");
|
||||
features2.push_back("http://jabber.org/protocol/disco#info");
|
||||
features2.push_back("http://jabber.org/protocol/commands");
|
||||
if (CONFIG_BOOL_DEFAULTED(m_config, "features.muc", false)) {
|
||||
features2.push_back("http://jabber.org/protocol/muc");
|
||||
}
|
||||
setTransportFeatures(features2);
|
||||
|
||||
std::list<std::string> features;
|
||||
features.push_back("http://jabber.org/protocol/disco#items");
|
||||
features.push_back("http://jabber.org/protocol/disco#info");
|
||||
|
|
|
@ -21,7 +21,8 @@
|
|||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "Swiften/Swiften.h"
|
||||
#include <list>
|
||||
#include <boost/signal.hpp>
|
||||
#include "Swiften/Queries/GetResponder.h"
|
||||
#include "Swiften/Elements/DiscoInfo.h"
|
||||
#include "Swiften/Elements/CapsInfo.h"
|
||||
|
@ -51,7 +52,7 @@ class DiscoInfoResponder : public Swift::GetResponder<Swift::DiscoInfo> {
|
|||
|
||||
private:
|
||||
virtual bool handleGetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr<Swift::DiscoInfo> payload);
|
||||
void updateBuddyFeatures();
|
||||
void updateFeatures();
|
||||
|
||||
Swift::DiscoInfo m_transportInfo;
|
||||
Swift::DiscoInfo *m_buddyInfo;
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#include <iostream>
|
||||
#include <boost/bind.hpp>
|
||||
#include "Swiften/Queries/IQRouter.h"
|
||||
#include "Swiften/Swiften.h"
|
||||
#include "transport/transport.h"
|
||||
#include "transport/logging.h"
|
||||
#include "discoinforesponder.h"
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "transport/user.h"
|
||||
#include "transport/buddy.h"
|
||||
#include "transport/logging.h"
|
||||
#include "Swiften/Network/ConnectionServerFactory.h"
|
||||
|
||||
namespace Transport {
|
||||
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#include <boost/bind.hpp>
|
||||
#include "Swiften/Queries/IQRouter.h"
|
||||
#include "Swiften/Elements/RawXMLPayload.h"
|
||||
#include "Swiften/Swiften.h"
|
||||
#include "transport/usermanager.h"
|
||||
#include "transport/user.h"
|
||||
#include "transport/transport.h"
|
||||
|
@ -53,7 +52,14 @@ bool GatewayResponder::handleGetRequest(const Swift::JID& from, const Swift::JID
|
|||
|
||||
bool GatewayResponder::handleSetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr<Swift::GatewayPayload> payload) {
|
||||
std::string prompt = payload->getPrompt();
|
||||
|
||||
std::string escaped = Swift::JID::getEscapedNode(prompt);
|
||||
if (!CONFIG_BOOL_DEFAULTED(m_userManager->getComponent()->getConfig(), "service.jid_escaping", true)) {
|
||||
escaped = prompt;
|
||||
if (escaped.find_last_of("@") != std::string::npos) {
|
||||
escaped.replace(escaped.find_last_of("@"), 1, "%");
|
||||
}
|
||||
}
|
||||
// This code is here to workaround Gajim (and probably other clients bug too) bug
|
||||
// https://trac.gajim.org/ticket/7277
|
||||
if (prompt.find("\\40") != std::string::npos) {
|
||||
|
|
|
@ -136,30 +136,38 @@ static void initLogging(Config *config, std::string key, bool only_create_dir =
|
|||
p.setProperty("id", id);
|
||||
#endif
|
||||
|
||||
std::string dir;
|
||||
std::vector<std::string> dirs;
|
||||
BOOST_FOREACH(const log4cxx::LogString &prop, p.propertyNames()) {
|
||||
// if (boost::ends_with(prop, ".File")) {
|
||||
if (boost::ends_with(prop, ".File")) {
|
||||
std::string dir;
|
||||
log4cxx::helpers::Transcoder::encode(p.get(prop), dir);
|
||||
boost::replace_all(dir, "${jid}", jid);
|
||||
boost::replace_all(dir, "${pid}", pid);
|
||||
boost::replace_all(dir, "${id}", id);
|
||||
break;
|
||||
// }
|
||||
dirs.push_back(dir);
|
||||
}
|
||||
}
|
||||
mode_t old_cmask;
|
||||
if (!dir.empty()) {
|
||||
// create directories
|
||||
// create directories
|
||||
#ifndef WIN32
|
||||
old_cmask = umask(0007);
|
||||
old_cmask = umask(0007);
|
||||
#endif
|
||||
try {
|
||||
Transport::Util::createDirectories(config, boost::filesystem::path(dir).parent_path());
|
||||
}
|
||||
catch (const boost::filesystem::filesystem_error &e) {
|
||||
std::cerr << "Can't create logging directory directory " << boost::filesystem::path(dir).parent_path().string() << ": " << e.what() << ".\n";
|
||||
|
||||
BOOST_FOREACH(std::string &dir, dirs) {
|
||||
if (!dir.empty()) {
|
||||
try {
|
||||
Transport::Util::createDirectories(config, boost::filesystem::path(dir).parent_path());
|
||||
}
|
||||
catch (const boost::filesystem::filesystem_error &e) {
|
||||
std::cerr << "Can't create logging directory directory " << boost::filesystem::path(dir).parent_path().string() << ": " << e.what() << ".\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
umask(old_cmask);
|
||||
#endif
|
||||
|
||||
if (only_create_dir) {
|
||||
return;
|
||||
}
|
||||
|
@ -168,24 +176,20 @@ static void initLogging(Config *config, std::string key, bool only_create_dir =
|
|||
|
||||
// Change owner of main log file
|
||||
#ifndef WIN32
|
||||
if (!CONFIG_STRING(config, "service.group").empty() && !CONFIG_STRING(config, "service.user").empty()) {
|
||||
struct group *gr;
|
||||
if ((gr = getgrnam(CONFIG_STRING(config, "service.group").c_str())) == NULL) {
|
||||
std::cerr << "Invalid service.group name " << CONFIG_STRING(config, "service.group") << "\n";
|
||||
BOOST_FOREACH(std::string &dir, dirs) {
|
||||
if (!CONFIG_STRING(config, "service.group").empty() && !CONFIG_STRING(config, "service.user").empty()) {
|
||||
struct group *gr;
|
||||
if ((gr = getgrnam(CONFIG_STRING(config, "service.group").c_str())) == NULL) {
|
||||
std::cerr << "Invalid service.group name " << CONFIG_STRING(config, "service.group") << "\n";
|
||||
}
|
||||
struct passwd *pw;
|
||||
if ((pw = getpwnam(CONFIG_STRING(config, "service.user").c_str())) == NULL) {
|
||||
std::cerr << "Invalid service.user name " << CONFIG_STRING(config, "service.user") << "\n";
|
||||
}
|
||||
chown(dir.c_str(), pw->pw_uid, gr->gr_gid);
|
||||
}
|
||||
struct passwd *pw;
|
||||
if ((pw = getpwnam(CONFIG_STRING(config, "service.user").c_str())) == NULL) {
|
||||
std::cerr << "Invalid service.user name " << CONFIG_STRING(config, "service.user") << "\n";
|
||||
}
|
||||
chown(dir.c_str(), pw->pw_uid, gr->gr_gid);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef WIN32
|
||||
if (!dir.empty()) {
|
||||
umask(old_cmask);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,20 +28,41 @@
|
|||
#include <boost/lexical_cast.hpp>
|
||||
#ifndef WIN32
|
||||
#include <sys/param.h>
|
||||
#else
|
||||
#include <windows.h>
|
||||
#include <psapi.h>
|
||||
#endif
|
||||
#ifdef BSD
|
||||
#ifdef __MACH__
|
||||
#include <mach/mach.h>
|
||||
#elif BSD
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/user.h>
|
||||
|
||||
#endif
|
||||
|
||||
namespace Transport {
|
||||
|
||||
#ifndef WIN32
|
||||
#ifdef BSD
|
||||
#ifdef __MACH__
|
||||
|
||||
void process_mem_usage(double& vm_usage, double& resident_set, pid_t pid) {
|
||||
|
||||
struct task_basic_info t_info;
|
||||
mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;
|
||||
|
||||
if (KERN_SUCCESS != task_info(mach_task_self(),
|
||||
TASK_BASIC_INFO, (task_info_t)&t_info,
|
||||
&t_info_count)) {
|
||||
vm_usage = 0;
|
||||
resident_set = 0;
|
||||
return;
|
||||
}
|
||||
vm_usage = t_info.virtual_size;
|
||||
resident_set = t_info.resident_size;
|
||||
}
|
||||
#elif BSD
|
||||
void process_mem_usage(double& vm_usage, double& resident_set, pid_t pid) {
|
||||
int mib[4];
|
||||
size_t size;
|
||||
|
@ -120,6 +141,15 @@ void process_mem_usage(double& shared, double& resident_set, pid_t pid) {
|
|||
resident_set = rss * page_size_kb;
|
||||
}
|
||||
#endif /* else BSD */
|
||||
#else
|
||||
#define PSAPI_VERSION 1
|
||||
#define pid_t void*
|
||||
void process_mem_usage(double& shared, double& resident_set, pid_t pid) {
|
||||
PROCESS_MEMORY_COUNTERS_EX pmc;
|
||||
GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc));
|
||||
shared = (double)pmc.PrivateUsage;
|
||||
resident_set = (double)pmc.WorkingSetSize;
|
||||
}
|
||||
#endif /* WIN32 */
|
||||
|
||||
}
|
||||
|
|
|
@ -34,18 +34,24 @@
|
|||
#include "transport/logging.h"
|
||||
#include "transport/admininterface.h"
|
||||
#include "blockresponder.h"
|
||||
#include "Swiften/Swiften.h"
|
||||
#include "Swiften/Server/ServerStanzaChannel.h"
|
||||
#include "Swiften/Elements/StreamError.h"
|
||||
#include "Swiften/Network/BoostConnectionServer.h"
|
||||
#include "Swiften/Network/ConnectionServerFactory.h"
|
||||
#include "Swiften/Elements/AttentionPayload.h"
|
||||
#include "Swiften/Elements/XHTMLIMPayload.h"
|
||||
#include "Swiften/Elements/Delay.h"
|
||||
#include "Swiften/Elements/DeliveryReceipt.h"
|
||||
#include "Swiften/Elements/DeliveryReceiptRequest.h"
|
||||
#include "Swiften/Elements/InvisiblePayload.h"
|
||||
#include "Swiften/Elements/SpectrumErrorPayload.h"
|
||||
#include "transport/protocol.pb.h"
|
||||
#include "transport/util.h"
|
||||
#include "transport/discoitemsresponder.h"
|
||||
|
||||
#include "boost/date_time/posix_time/posix_time.hpp"
|
||||
#include "boost/signal.hpp"
|
||||
|
||||
#include "utf8.h"
|
||||
|
||||
#include <Swiften/FileTransfer/ReadBytestream.h>
|
||||
|
@ -263,11 +269,16 @@ NetworkPluginServer::NetworkPluginServer(Component *component, Config *config, U
|
|||
m_adminInterface = NULL;
|
||||
m_startingBackend = false;
|
||||
m_lastLogin = 0;
|
||||
m_xmppParser = new Swift::XMPPParser(this, &m_collection, component->getNetworkFactories()->getXMLParserFactory());
|
||||
m_xmppParser->parse("<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='localhost' version='1.0'>");
|
||||
m_serializer = new Swift::XMPPSerializer(&m_collection2, Swift::ClientStreamType);
|
||||
m_discoItemsResponder = discoItemsResponder;
|
||||
m_component->m_factory = new NetworkFactory(this);
|
||||
m_userManager->onUserCreated.connect(boost::bind(&NetworkPluginServer::handleUserCreated, this, _1));
|
||||
m_userManager->onUserDestroyed.connect(boost::bind(&NetworkPluginServer::handleUserDestroyed, this, _1));
|
||||
|
||||
m_component->onRawIQReceived.connect(boost::bind(&NetworkPluginServer::handleRawIQReceived, this, _1));
|
||||
|
||||
m_pingTimer = component->getNetworkFactories()->getTimerFactory()->createTimer(20000);
|
||||
m_pingTimer->onTick.connect(boost::bind(&NetworkPluginServer::pingTimeout, this));
|
||||
m_pingTimer->start();
|
||||
|
@ -346,6 +357,10 @@ void NetworkPluginServer::start() {
|
|||
}
|
||||
else {
|
||||
LOG4CXX_ERROR(logger, "Backend can not be started, exit_code=" << WEXITSTATUS(status) << ", possible error: " << strerror(WEXITSTATUS(status)));
|
||||
if (WEXITSTATUS(status) == ENOENT) {
|
||||
LOG4CXX_ERROR(logger, "This usually means the path to backend executable defined in config file as '[service] backend=\"...\"' is wrong or the executable does not exists.");
|
||||
}
|
||||
|
||||
}
|
||||
LOG4CXX_ERROR(logger, "Check backend log for more details");
|
||||
continue;
|
||||
|
@ -619,7 +634,7 @@ void NetworkPluginServer::handleParticipantChangedPayload(const std::string &dat
|
|||
return;
|
||||
}
|
||||
|
||||
conv->handleParticipantChanged(payload.nickname(), payload.flag(), payload.status(), payload.statusmessage(), payload.newname());
|
||||
conv->handleParticipantChanged(payload.nickname(), (Conversation::ParticipantFlag) payload.flag(), payload.status(), payload.statusmessage(), payload.newname());
|
||||
}
|
||||
|
||||
void NetworkPluginServer::handleRoomChangedPayload(const std::string &data) {
|
||||
|
@ -680,7 +695,6 @@ void NetworkPluginServer::handleConvMessagePayload(const std::string &data, bool
|
|||
msg->addPayload(delay);
|
||||
}
|
||||
|
||||
|
||||
NetworkConversation *conv = (NetworkConversation *) user->getConversationManager()->getConversation(payload.buddyname());
|
||||
|
||||
// We can't create Conversation for payload with nickname, because this means the message is from room,
|
||||
|
@ -689,6 +703,19 @@ void NetworkPluginServer::handleConvMessagePayload(const std::string &data, bool
|
|||
return;
|
||||
}
|
||||
|
||||
if (conv && payload.pm()) {
|
||||
conv = (NetworkConversation *) user->getConversationManager()->getConversation(payload.buddyname() + "/" + payload.nickname());
|
||||
if (!conv) {
|
||||
conv = new NetworkConversation(user->getConversationManager(), payload.nickname());
|
||||
std::string name = payload.buddyname();
|
||||
conv->setRoom(name);
|
||||
conv->setNickname(payload.buddyname() + "/" + payload.nickname());
|
||||
|
||||
user->getConversationManager()->addConversation(conv);
|
||||
conv->onMessageToSend.connect(boost::bind(&NetworkPluginServer::handleMessageReceived, this, _1, _2));
|
||||
}
|
||||
}
|
||||
|
||||
// Create new Conversation if it does not exist
|
||||
if (!conv) {
|
||||
conv = new NetworkConversation(user->getConversationManager(), payload.buddyname());
|
||||
|
@ -965,6 +992,133 @@ void NetworkPluginServer::handleRoomListPayload(const std::string &data) {
|
|||
}
|
||||
}
|
||||
|
||||
void NetworkPluginServer::handleElement(boost::shared_ptr<Swift::Element> element) {
|
||||
boost::shared_ptr<Swift::Stanza> stanza = boost::dynamic_pointer_cast<Swift::Stanza>(element);
|
||||
if (!stanza) {
|
||||
return;
|
||||
}
|
||||
|
||||
User *user = m_userManager->getUser(stanza->getTo().toBare());
|
||||
if (!user)
|
||||
return;
|
||||
|
||||
Swift::JID originalJID = stanza->getFrom();
|
||||
LocalBuddy *buddy = (LocalBuddy *) user->getRosterManager()->getBuddy(stanza->getFrom().toBare());
|
||||
if (buddy) {
|
||||
const Swift::JID &jid = buddy->getJID();
|
||||
if (stanza->getFrom().getResource().empty()) {
|
||||
stanza->setFrom(Swift::JID(jid.getNode(), jid.getDomain()));
|
||||
}
|
||||
else {
|
||||
stanza->setFrom(Swift::JID(jid.getNode(), jid.getDomain(), stanza->getFrom().getResource()));
|
||||
}
|
||||
}
|
||||
else {
|
||||
std::string name = stanza->getFrom().toBare();
|
||||
if (CONFIG_BOOL_DEFAULTED(m_config, "service.jid_escaping", true)) {
|
||||
name = Swift::JID::getEscapedNode(name);
|
||||
}
|
||||
else {
|
||||
if (name.find_last_of("@") != std::string::npos) {
|
||||
name.replace(name.find_last_of("@"), 1, "%");
|
||||
}
|
||||
}
|
||||
if (stanza->getFrom().getResource().empty()) {
|
||||
stanza->setFrom(Swift::JID(name, m_component->getJID().toString()));
|
||||
}
|
||||
else {
|
||||
stanza->setFrom(Swift::JID(name, m_component->getJID().toString(), stanza->getFrom().getResource()));
|
||||
}
|
||||
}
|
||||
|
||||
boost::shared_ptr<Swift::Message> message = boost::dynamic_pointer_cast<Swift::Message>(stanza);
|
||||
if (message) {
|
||||
NetworkConversation *conv = (NetworkConversation *) user->getConversationManager()->getConversation(originalJID.toBare());
|
||||
if (conv) {
|
||||
conv->handleRawMessage(message);
|
||||
return;
|
||||
}
|
||||
|
||||
m_component->getStanzaChannel()->sendMessage(message);
|
||||
return;
|
||||
}
|
||||
|
||||
boost::shared_ptr<Swift::Presence> presence = boost::dynamic_pointer_cast<Swift::Presence>(stanza);
|
||||
if (presence) {
|
||||
m_component->getStanzaChannel()->sendPresence(presence);
|
||||
if (buddy) {
|
||||
buddy->m_statusMessage = presence->getStatus();
|
||||
buddy->m_status = Swift::StatusShow(presence->getShow());
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
boost::shared_ptr<Swift::IQ> iq = boost::dynamic_pointer_cast<Swift::IQ>(stanza);
|
||||
if (iq) {
|
||||
if (m_id2resource.find(stanza->getTo().toBare().toString() + stanza->getID()) != m_id2resource.end()) {
|
||||
iq->setTo(Swift::JID(iq->getTo().getNode(), iq->getTo().getDomain(), m_id2resource[stanza->getTo().toBare().toString() + stanza->getID()]));
|
||||
m_id2resource.erase(stanza->getTo().toBare().toString() + stanza->getID());
|
||||
}
|
||||
m_component->getIQRouter()->sendIQ(iq);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkPluginServer::handleRawXML(const std::string &xml) {
|
||||
m_xmppParser->parse(xml);
|
||||
}
|
||||
|
||||
void NetworkPluginServer::handleRawPresenceReceived(boost::shared_ptr<Swift::Presence> presence) {
|
||||
User *user = m_userManager->getUser(presence->getFrom().toBare());
|
||||
if (!user)
|
||||
return;
|
||||
|
||||
Backend *c = (Backend *) user->getData();
|
||||
if (!c) {
|
||||
return;
|
||||
}
|
||||
|
||||
Swift::JID legacyname = Swift::JID(Buddy::JIDToLegacyName(presence->getTo()));
|
||||
if (!presence->getTo().getResource().empty()) {
|
||||
presence->setTo(Swift::JID(legacyname.getNode(), legacyname.getDomain(), presence->getTo().getResource()));
|
||||
}
|
||||
else {
|
||||
presence->setTo(Swift::JID(legacyname.getNode(), legacyname.getDomain()));
|
||||
}
|
||||
|
||||
std::string xml = safeByteArrayToString(m_serializer->serializeElement(presence));
|
||||
WRAP(xml, pbnetwork::WrapperMessage_Type_TYPE_RAW_XML);
|
||||
send(c->connection, xml);
|
||||
}
|
||||
|
||||
void NetworkPluginServer::handleRawIQReceived(boost::shared_ptr<Swift::IQ> iq) {
|
||||
User *user = m_userManager->getUser(iq->getFrom().toBare());
|
||||
if (!user)
|
||||
return;
|
||||
|
||||
Backend *c = (Backend *) user->getData();
|
||||
if (!c) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (iq->getType() == Swift::IQ::Get) {
|
||||
m_id2resource[iq->getFrom().toBare().toString() + iq->getID()] = iq->getFrom().getResource();
|
||||
}
|
||||
|
||||
Swift::JID legacyname = Swift::JID(Buddy::JIDToLegacyName(iq->getTo()));
|
||||
if (!iq->getTo().getResource().empty()) {
|
||||
iq->setTo(Swift::JID(legacyname.getNode(), legacyname.getDomain(), iq->getTo().getResource()));
|
||||
}
|
||||
else {
|
||||
iq->setTo(Swift::JID(legacyname.getNode(), legacyname.getDomain()));
|
||||
}
|
||||
|
||||
std::string xml = safeByteArrayToString(m_serializer->serializeElement(iq));
|
||||
WRAP(xml, pbnetwork::WrapperMessage_Type_TYPE_RAW_XML);
|
||||
send(c->connection, xml);
|
||||
}
|
||||
|
||||
void NetworkPluginServer::handleDataRead(Backend *c, boost::shared_ptr<Swift::SafeByteArray> data) {
|
||||
// Append data to buffer
|
||||
c->data.insert(c->data.end(), data->begin(), data->end());
|
||||
|
@ -1076,6 +1230,9 @@ void NetworkPluginServer::handleDataRead(Backend *c, boost::shared_ptr<Swift::Sa
|
|||
case pbnetwork::WrapperMessage_Type_TYPE_CONV_MESSAGE_ACK:
|
||||
handleConvMessageAckPayload(wrapper.payload());
|
||||
break;
|
||||
case pbnetwork::WrapperMessage_Type_TYPE_RAW_XML:
|
||||
handleRawXML(wrapper.payload());
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
@ -1245,8 +1402,12 @@ void NetworkPluginServer::handleUserCreated(User *user) {
|
|||
// Don't forget to disconnect these in handleUserDestroyed!!!
|
||||
user->onReadyToConnect.connect(boost::bind(&NetworkPluginServer::handleUserReadyToConnect, this, user));
|
||||
user->onPresenceChanged.connect(boost::bind(&NetworkPluginServer::handleUserPresenceChanged, this, user, _1));
|
||||
user->onRawPresenceReceived.connect(boost::bind(&NetworkPluginServer::handleRawPresenceReceived, this, _1));
|
||||
user->onRoomJoined.connect(boost::bind(&NetworkPluginServer::handleRoomJoined, this, user, _1, _2, _3, _4));
|
||||
user->onRoomLeft.connect(boost::bind(&NetworkPluginServer::handleRoomLeft, this, user, _1));
|
||||
|
||||
user->getRosterManager()->onBuddyAdded.connect(boost::bind(&NetworkPluginServer::handleUserBuddyAdded, this, user, _1));
|
||||
user->getRosterManager()->onBuddyRemoved.connect(boost::bind(&NetworkPluginServer::handleUserBuddyRemoved, this, user, _1));
|
||||
}
|
||||
|
||||
void NetworkPluginServer::handleUserReadyToConnect(User *user) {
|
||||
|
@ -1349,9 +1510,13 @@ void NetworkPluginServer::handleUserDestroyed(User *user) {
|
|||
|
||||
user->onReadyToConnect.disconnect(boost::bind(&NetworkPluginServer::handleUserReadyToConnect, this, user));
|
||||
user->onPresenceChanged.disconnect(boost::bind(&NetworkPluginServer::handleUserPresenceChanged, this, user, _1));
|
||||
user->onRawPresenceReceived.disconnect(boost::bind(&NetworkPluginServer::handleRawPresenceReceived, this, _1));
|
||||
user->onRoomJoined.disconnect(boost::bind(&NetworkPluginServer::handleRoomJoined, this, user, _1, _2, _3, _4));
|
||||
user->onRoomLeft.disconnect(boost::bind(&NetworkPluginServer::handleRoomLeft, this, user, _1));
|
||||
|
||||
user->getRosterManager()->onBuddyAdded.disconnect(boost::bind(&NetworkPluginServer::handleUserBuddyAdded, this, user, _1));
|
||||
user->getRosterManager()->onBuddyRemoved.disconnect(boost::bind(&NetworkPluginServer::handleUserBuddyRemoved, this, user, _1));
|
||||
|
||||
pbnetwork::Logout logout;
|
||||
logout.set_user(user->getJID().toBare());
|
||||
logout.set_legacyname(userInfo.uin);
|
||||
|
@ -1378,6 +1543,25 @@ void NetworkPluginServer::handleUserDestroyed(User *user) {
|
|||
|
||||
void NetworkPluginServer::handleMessageReceived(NetworkConversation *conv, boost::shared_ptr<Swift::Message> &msg) {
|
||||
conv->getConversationManager()->getUser()->updateLastActivity();
|
||||
|
||||
if (CONFIG_BOOL_DEFAULTED(m_config, "features.rawxml", false)) {
|
||||
Backend *c = (Backend *) conv->getConversationManager()->getUser()->getData();
|
||||
if (!c) {
|
||||
return;
|
||||
}
|
||||
Swift::JID legacyname = Swift::JID(Buddy::JIDToLegacyName(msg->getTo()));
|
||||
if (!msg->getTo().getResource().empty()) {
|
||||
msg->setTo(Swift::JID(legacyname.getNode(), legacyname.getDomain(), msg->getTo().getResource()));
|
||||
}
|
||||
else {
|
||||
msg->setTo(Swift::JID(legacyname.getNode(), legacyname.getDomain()));
|
||||
}
|
||||
std::string xml = safeByteArrayToString(m_serializer->serializeElement(msg));
|
||||
WRAP(xml, pbnetwork::WrapperMessage_Type_TYPE_RAW_XML);
|
||||
send(c->connection, xml);
|
||||
return;
|
||||
}
|
||||
|
||||
boost::shared_ptr<Swift::ChatState> statePayload = msg->getPayload<Swift::ChatState>();
|
||||
if (statePayload) {
|
||||
pbnetwork::WrapperMessage_Type type = pbnetwork::WrapperMessage_Type_TYPE_BUDDY_CHANGED;
|
||||
|
@ -1532,6 +1716,32 @@ void NetworkPluginServer::handleBuddyAdded(Buddy *buddy, const Swift::RosterItem
|
|||
handleBuddyUpdated(buddy, item);
|
||||
}
|
||||
|
||||
void NetworkPluginServer::handleUserBuddyAdded(User *user, Buddy *b) {
|
||||
pbnetwork::Buddy buddy;
|
||||
buddy.set_username(user->getJID().toBare());
|
||||
buddy.set_buddyname(b->getName());
|
||||
buddy.set_alias(b->getAlias());
|
||||
BOOST_FOREACH(const std::string &g, b->getGroups()) {
|
||||
buddy.add_group(g);
|
||||
}
|
||||
buddy.set_status(pbnetwork::STATUS_NONE);
|
||||
|
||||
std::string message;
|
||||
buddy.SerializeToString(&message);
|
||||
|
||||
WRAP(message, pbnetwork::WrapperMessage_Type_TYPE_BUDDY_CHANGED);
|
||||
|
||||
Backend *c = (Backend *) user->getData();
|
||||
if (!c) {
|
||||
return;
|
||||
}
|
||||
send(c->connection, message);
|
||||
}
|
||||
|
||||
void NetworkPluginServer::handleUserBuddyRemoved(User *user, Buddy *b) {
|
||||
handleBuddyRemoved(b);
|
||||
}
|
||||
|
||||
void NetworkPluginServer::handleBlockToggled(Buddy *b) {
|
||||
User *user = b->getRosterManager()->getUser();
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
*/
|
||||
|
||||
#include "transport/presenceoracle.h"
|
||||
#include "Swiften/Swiften.h"
|
||||
#include "Swiften/Elements/MUCPayload.h"
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
|
@ -52,9 +52,8 @@ void PresenceOracle::clearPresences(const Swift::JID& bareJID) {
|
|||
|
||||
void PresenceOracle::handleIncomingPresence(Presence::ref presence) {
|
||||
// ignore presences for some contact, we're checking only presences for the transport itself here.
|
||||
bool isMUC = presence->getPayload<MUCPayload>() != NULL || *presence->getTo().getNode().c_str() == '#';
|
||||
// filter out login/logout presence spam
|
||||
if (!presence->getTo().getNode().empty() && isMUC == false)
|
||||
if (!presence->getTo().getNode().empty())
|
||||
return;
|
||||
|
||||
JID bareJID(presence->getFrom().toBare());
|
||||
|
@ -62,29 +61,27 @@ void PresenceOracle::handleIncomingPresence(Presence::ref presence) {
|
|||
}
|
||||
else {
|
||||
Presence::ref passedPresence = presence;
|
||||
if (!isMUC) {
|
||||
if (presence->getType() == Presence::Unsubscribe || presence->getType() == Presence::Unsubscribed) {
|
||||
/* 3921bis says that we don't follow up with an unavailable, so simulate this ourselves */
|
||||
passedPresence = Presence::ref(new Presence());
|
||||
passedPresence->setType(Presence::Unavailable);
|
||||
passedPresence->setFrom(bareJID);
|
||||
passedPresence->setStatus(presence->getStatus());
|
||||
}
|
||||
std::map<JID, boost::shared_ptr<Presence> > jidMap = entries_[bareJID];
|
||||
if (passedPresence->getFrom().isBare() && presence->getType() == Presence::Unavailable) {
|
||||
/* Have a bare-JID only presence of offline */
|
||||
jidMap.clear();
|
||||
} else if (passedPresence->getType() == Presence::Available) {
|
||||
/* Don't have a bare-JID only offline presence once there are available presences */
|
||||
jidMap.erase(bareJID);
|
||||
}
|
||||
if (passedPresence->getType() == Presence::Unavailable && jidMap.size() > 1) {
|
||||
jidMap.erase(passedPresence->getFrom());
|
||||
} else {
|
||||
jidMap[passedPresence->getFrom()] = passedPresence;
|
||||
}
|
||||
entries_[bareJID] = jidMap;
|
||||
if (presence->getType() == Presence::Unsubscribe || presence->getType() == Presence::Unsubscribed) {
|
||||
/* 3921bis says that we don't follow up with an unavailable, so simulate this ourselves */
|
||||
passedPresence = Presence::ref(new Presence());
|
||||
passedPresence->setType(Presence::Unavailable);
|
||||
passedPresence->setFrom(bareJID);
|
||||
passedPresence->setStatus(presence->getStatus());
|
||||
}
|
||||
std::map<JID, boost::shared_ptr<Presence> > jidMap = entries_[bareJID];
|
||||
if (passedPresence->getFrom().isBare() && presence->getType() == Presence::Unavailable) {
|
||||
/* Have a bare-JID only presence of offline */
|
||||
jidMap.clear();
|
||||
} else if (passedPresence->getType() == Presence::Available) {
|
||||
/* Don't have a bare-JID only offline presence once there are available presences */
|
||||
jidMap.erase(bareJID);
|
||||
}
|
||||
if (passedPresence->getType() == Presence::Unavailable && jidMap.size() > 1) {
|
||||
jidMap.erase(passedPresence->getFrom());
|
||||
} else {
|
||||
jidMap[passedPresence->getFrom()] = passedPresence;
|
||||
}
|
||||
entries_[bareJID] = jidMap;
|
||||
onPresenceChange(passedPresence);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,10 @@
|
|||
#include "Swiften/Elements/RosterPayload.h"
|
||||
#include "Swiften/Elements/RosterItemPayload.h"
|
||||
#include "Swiften/Elements/RosterItemExchangePayload.h"
|
||||
#include "Swiften/Elements/Nickname.h"
|
||||
#include "Swiften/Queries/IQRouter.h"
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/make_shared.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <iterator>
|
||||
|
@ -151,12 +154,7 @@ void RosterManager::sendBuddyRosterPush(Buddy *buddy) {
|
|||
Swift::RosterPayload::ref payload = Swift::RosterPayload::ref(new Swift::RosterPayload());
|
||||
Swift::RosterItemPayload item;
|
||||
item.setJID(buddy->getJID().toBare());
|
||||
if (buddy->getAlias().empty()) {
|
||||
item.setName(buddy->getJID().toBare().toString());
|
||||
}
|
||||
else {
|
||||
item.setName(buddy->getAlias());
|
||||
}
|
||||
item.setName(buddy->getAlias());
|
||||
item.setGroups(buddy->getGroups());
|
||||
item.setSubscription(Swift::RosterItemPayload::Both);
|
||||
|
||||
|
@ -280,6 +278,15 @@ void RosterManager::handleRemoteRosterResponse(boost::shared_ptr<Swift::RosterPa
|
|||
|
||||
LOG4CXX_INFO(logger, m_user->getJID().toString() << ": This server supports remote roster protoXEP");
|
||||
m_supportRemoteRoster = true;
|
||||
|
||||
//If we receive empty RosterPayload on login (not register) initiate full RosterPush
|
||||
if(!m_buddies.empty() && payload->getItems().empty()){
|
||||
LOG4CXX_INFO(logger, "Received empty Roster upon login. Pushing full Roster.");
|
||||
for(std::map<std::string, Buddy *, std::less<std::string>, boost::pool_allocator< std::pair<std::string, Buddy *> > >::const_iterator c_it = m_buddies.begin();
|
||||
c_it != m_buddies.end(); c_it++) {
|
||||
sendBuddyRosterPush(c_it->second);
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
BOOST_FOREACH(const Swift::RosterItemPayload &item, payload->getItems()) {
|
||||
|
@ -490,6 +497,7 @@ void RosterManager::handleSubscription(Swift::Presence::ref presence) {
|
|||
buddy = m_component->getFactory()->createBuddy(this, buddyInfo);
|
||||
setBuddy(buddy);
|
||||
onBuddyAdded(buddy);
|
||||
LOG4CXX_INFO(logger, m_user->getJID().toString() << ": Subscription received for new buddy " << buddyInfo.legacyName << " => adding to legacy network");
|
||||
response->setType(Swift::Presence::Subscribed);
|
||||
break;
|
||||
case Swift::Presence::Unsubscribe:
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#include <iostream>
|
||||
#include <boost/bind.hpp>
|
||||
#include "Swiften/Queries/IQRouter.h"
|
||||
#include "Swiften/Swiften.h"
|
||||
#include "transport/user.h"
|
||||
#include "transport/usermanager.h"
|
||||
#include "transport/rostermanager.h"
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
#include "transport/storagebackend.h"
|
||||
#include "transport/logging.h"
|
||||
|
||||
#include "Swiften/Network/NetworkFactories.h"
|
||||
|
||||
DEFINE_LOGGER(logger, "RosterStorage");
|
||||
|
||||
namespace Transport {
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
#define RESET_GET_COUNTER(STATEMENT) STATEMENT##_id_get = 0;
|
||||
#define GET_INT(STATEMENT) sqlite3_column_int(STATEMENT, STATEMENT##_id_get++)
|
||||
#define GET_STR(STATEMENT) (const char *) sqlite3_column_text(STATEMENT, STATEMENT##_id_get++)
|
||||
#define GET_BLOB(STATEMENT) (const void *) sqlite3_column_blob(STATEMENT, STATEMENT##_id_get++)
|
||||
#define EXECUTE_STATEMENT(STATEMENT, NAME) if(sqlite3_step(STATEMENT) != SQLITE_DONE) {\
|
||||
LOG4CXX_ERROR(logger, NAME<< (sqlite3_errmsg(m_db) == NULL ? "" : sqlite3_errmsg(m_db)));\
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#include <boost/bind.hpp>
|
||||
#include "Swiften/Queries/IQRouter.h"
|
||||
#include "transport/BlockPayload.h"
|
||||
#include "Swiften/Swiften.h"
|
||||
#include "transport/usermanager.h"
|
||||
#include "transport/user.h"
|
||||
#include "transport/buddy.h"
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
#include "transport/sqlite3backend.h"
|
||||
#include "transport/mysqlbackend.h"
|
||||
#include "transport/pqxxbackend.h"
|
||||
#include "Swiften/StringCodecs/Base64.h"
|
||||
|
||||
#include "Swiften/Swiften.h"
|
||||
|
||||
namespace Transport {
|
||||
|
||||
|
|
|
@ -24,7 +24,9 @@
|
|||
#include <boost/bind.hpp>
|
||||
#include "Swiften/Queries/IQRouter.h"
|
||||
#include "Swiften/Elements/RawXMLPayload.h"
|
||||
#include "Swiften/Swiften.h"
|
||||
#include "Swiften/Elements/Storage.h"
|
||||
#include "Swiften/Elements/Storage.h"
|
||||
#include "Swiften/Serializer/PayloadSerializers/StorageSerializer.h"
|
||||
#include "transport/usermanager.h"
|
||||
#include "transport/user.h"
|
||||
#include "transport/logging.h"
|
||||
|
|
|
@ -21,9 +21,9 @@
|
|||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "Swiften/Swiften.h"
|
||||
#include "Swiften/Queries/Responder.h"
|
||||
#include "Swiften/Elements/RosterPayload.h"
|
||||
#include "Swiften/Elements/PrivateStorage.h"
|
||||
|
||||
namespace Transport {
|
||||
|
||||
|
|
|
@ -35,6 +35,8 @@ class ConversationManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTe
|
|||
CPPUNIT_TEST(handleParticipantChangedTwoResources);
|
||||
CPPUNIT_TEST(handlePMFromXMPP);
|
||||
CPPUNIT_TEST(handleGroupchatRemoved);
|
||||
CPPUNIT_TEST(handleNicknameConflict);
|
||||
CPPUNIT_TEST(handleNotAuthorized);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
|
@ -115,7 +117,7 @@ class ConversationManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTe
|
|||
CPPUNIT_ASSERT_EQUAL(0, (int) received.size());
|
||||
|
||||
// this user presence - status code 110
|
||||
conv->handleParticipantChanged("nickname", 1, Swift::StatusShow::Away, "my status message");
|
||||
conv->handleParticipantChanged("nickname", Conversation::PARTICIPANT_FLAG_MODERATOR, Swift::StatusShow::Away, "my status message");
|
||||
loop->processEvents();
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(2, (int) received.size());
|
||||
|
@ -343,17 +345,17 @@ class ConversationManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTe
|
|||
injectPresence(response);
|
||||
loop->processEvents();
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(4, (int) received.size());
|
||||
CPPUNIT_ASSERT_EQUAL(3, (int) received.size());
|
||||
CPPUNIT_ASSERT(dynamic_cast<Swift::Message *>(getStanza(received[1])));
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("hi there!"), dynamic_cast<Swift::Message *>(getStanza(received[1]))->getBody());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("user@localhost/resource"), dynamic_cast<Swift::Message *>(getStanza(received[1]))->getTo().toString());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("#room@localhost/anotheruser"), dynamic_cast<Swift::Message *>(getStanza(received[1]))->getFrom().toString());
|
||||
|
||||
CPPUNIT_ASSERT(dynamic_cast<Swift::Message *>(getStanza(received[2])));
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("hi there!"), dynamic_cast<Swift::Message *>(getStanza(received[2]))->getBody());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("hi there2!"), dynamic_cast<Swift::Message *>(getStanza(received[2]))->getBody());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("user@localhost/resource"), dynamic_cast<Swift::Message *>(getStanza(received[2]))->getTo().toString());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("#room@localhost/anotheruser"), dynamic_cast<Swift::Message *>(getStanza(received[2]))->getFrom().toString());
|
||||
|
||||
CPPUNIT_ASSERT(dynamic_cast<Swift::Message *>(getStanza(received[3])));
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("hi there2!"), dynamic_cast<Swift::Message *>(getStanza(received[3]))->getBody());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("user@localhost/resource"), dynamic_cast<Swift::Message *>(getStanza(received[3]))->getTo().toString());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("#room@localhost/anotheruser"), dynamic_cast<Swift::Message *>(getStanza(received[3]))->getFrom().toString());
|
||||
|
||||
}
|
||||
|
||||
void handleGroupchatMessagesBouncerLeave() {
|
||||
|
@ -408,17 +410,17 @@ class ConversationManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTe
|
|||
injectPresence(response);
|
||||
loop->processEvents();
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(4, (int) received.size());
|
||||
CPPUNIT_ASSERT_EQUAL(3, (int) received.size());
|
||||
CPPUNIT_ASSERT(dynamic_cast<Swift::Message *>(getStanza(received[1])));
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("hi there!"), dynamic_cast<Swift::Message *>(getStanza(received[1]))->getBody());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("user@localhost/resource"), dynamic_cast<Swift::Message *>(getStanza(received[1]))->getTo().toString());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("#room@localhost/anotheruser"), dynamic_cast<Swift::Message *>(getStanza(received[1]))->getFrom().toString());
|
||||
|
||||
CPPUNIT_ASSERT(dynamic_cast<Swift::Message *>(getStanza(received[2])));
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("hi there!"), dynamic_cast<Swift::Message *>(getStanza(received[2]))->getBody());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("hi there2!"), dynamic_cast<Swift::Message *>(getStanza(received[2]))->getBody());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("user@localhost/resource"), dynamic_cast<Swift::Message *>(getStanza(received[2]))->getTo().toString());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("#room@localhost/anotheruser"), dynamic_cast<Swift::Message *>(getStanza(received[2]))->getFrom().toString());
|
||||
|
||||
CPPUNIT_ASSERT(dynamic_cast<Swift::Message *>(getStanza(received[3])));
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("hi there2!"), dynamic_cast<Swift::Message *>(getStanza(received[3]))->getBody());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("user@localhost/resource"), dynamic_cast<Swift::Message *>(getStanza(received[3]))->getTo().toString());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("#room@localhost/anotheruser"), dynamic_cast<Swift::Message *>(getStanza(received[3]))->getFrom().toString());
|
||||
|
||||
}
|
||||
|
||||
void handleGroupchatMessagesTwoResources() {
|
||||
|
@ -472,7 +474,7 @@ class ConversationManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTe
|
|||
conv->addJID("user@localhost/resource");
|
||||
|
||||
// normal presence
|
||||
conv->handleParticipantChanged("anotheruser", 0, Swift::StatusShow::Away, "my status message");
|
||||
conv->handleParticipantChanged("anotheruser", Conversation::PARTICIPANT_FLAG_NONE, Swift::StatusShow::Away, "my status message");
|
||||
loop->processEvents();
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(1, (int) received.size());
|
||||
|
@ -487,7 +489,7 @@ class ConversationManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTe
|
|||
received.clear();
|
||||
|
||||
// this user presence - status code 110
|
||||
conv->handleParticipantChanged("nickname", 1, Swift::StatusShow::Away, "my status message");
|
||||
conv->handleParticipantChanged("nickname", Conversation::PARTICIPANT_FLAG_MODERATOR, Swift::StatusShow::Away, "my status message");
|
||||
loop->processEvents();
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(1, (int) received.size());
|
||||
|
@ -503,7 +505,7 @@ class ConversationManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTe
|
|||
received.clear();
|
||||
|
||||
// renamed - status code 303
|
||||
conv->handleParticipantChanged("anotheruser", 1, Swift::StatusShow::Away, "my status message", "hanzz");
|
||||
conv->handleParticipantChanged("anotheruser", Conversation::PARTICIPANT_FLAG_MODERATOR, Swift::StatusShow::Away, "my status message", "hanzz");
|
||||
loop->processEvents();
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(2, (int) received.size());
|
||||
|
@ -530,7 +532,7 @@ class ConversationManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTe
|
|||
conv->addJID("user@localhost/resource2");
|
||||
|
||||
// normal presence
|
||||
conv->handleParticipantChanged("anotheruser", 0, Swift::StatusShow::Away, "my status message");
|
||||
conv->handleParticipantChanged("anotheruser", Conversation::PARTICIPANT_FLAG_NONE, Swift::StatusShow::Away, "my status message");
|
||||
loop->processEvents();
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(1, (int) received2.size());
|
||||
|
@ -551,7 +553,7 @@ class ConversationManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTe
|
|||
conv->setNickname("nickname");
|
||||
conv->setJID("user@localhost/resource");
|
||||
|
||||
conv->handleParticipantChanged("anotheruser", 0, Swift::StatusShow::Away, "my status message");
|
||||
conv->handleParticipantChanged("anotheruser", Conversation::PARTICIPANT_FLAG_NONE, Swift::StatusShow::Away, "my status message");
|
||||
loop->processEvents();
|
||||
|
||||
received.clear();
|
||||
|
@ -593,6 +595,44 @@ class ConversationManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTe
|
|||
CPPUNIT_ASSERT_EQUAL(332, getStanza(received[0])->getPayload<Swift::MUCUserPayload>()->getStatusCodes()[0].code);
|
||||
}
|
||||
|
||||
void handleNicknameConflict() {
|
||||
User *user = userManager->getUser("user@localhost");
|
||||
TestingConversation *conv = new TestingConversation(user->getConversationManager(), "#room", true);
|
||||
|
||||
conv->onMessageToSend.connect(boost::bind(&ConversationManagerTest::handleMessageReceived, this, _1, _2));
|
||||
conv->setNickname("nickname");
|
||||
conv->addJID("user@localhost/resource");
|
||||
|
||||
// normal presence
|
||||
conv->handleParticipantChanged("nickname", Conversation::PARTICIPANT_FLAG_CONFLICT, Swift::StatusShow::Away, "my status message");
|
||||
loop->processEvents();
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(1, (int) received.size());
|
||||
CPPUNIT_ASSERT(dynamic_cast<Swift::Presence *>(getStanza(received[0])));
|
||||
CPPUNIT_ASSERT_EQUAL(Swift::Presence::Error, dynamic_cast<Swift::Presence *>(getStanza(received[0]))->getType());
|
||||
CPPUNIT_ASSERT(getStanza(received[0])->getPayload<Swift::ErrorPayload>());
|
||||
CPPUNIT_ASSERT_EQUAL(Swift::ErrorPayload::Conflict, getStanza(received[0])->getPayload<Swift::ErrorPayload>()->getCondition());
|
||||
}
|
||||
|
||||
void handleNotAuthorized() {
|
||||
User *user = userManager->getUser("user@localhost");
|
||||
TestingConversation *conv = new TestingConversation(user->getConversationManager(), "#room", true);
|
||||
|
||||
conv->onMessageToSend.connect(boost::bind(&ConversationManagerTest::handleMessageReceived, this, _1, _2));
|
||||
conv->setNickname("nickname");
|
||||
conv->addJID("user@localhost/resource");
|
||||
|
||||
// normal presence
|
||||
conv->handleParticipantChanged("nickname", Conversation::PARTICIPANT_FLAG_NOT_AUTHORIZED, Swift::StatusShow::Away, "my status message");
|
||||
loop->processEvents();
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(1, (int) received.size());
|
||||
CPPUNIT_ASSERT(dynamic_cast<Swift::Presence *>(getStanza(received[0])));
|
||||
CPPUNIT_ASSERT_EQUAL(Swift::Presence::Error, dynamic_cast<Swift::Presence *>(getStanza(received[0]))->getType());
|
||||
CPPUNIT_ASSERT(getStanza(received[0])->getPayload<Swift::ErrorPayload>());
|
||||
CPPUNIT_ASSERT_EQUAL(Swift::ErrorPayload::NotAuthorized, getStanza(received[0])->getPayload<Swift::ErrorPayload>()->getCondition());
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION (ConversationManagerTest);
|
||||
|
|
|
@ -53,6 +53,7 @@ class NetworkPluginServerTest : public CPPUNIT_NS :: TestFixture, public BasicTe
|
|||
CPPUNIT_TEST(handleBuddyChangedPayloadUserContactInRoster);
|
||||
CPPUNIT_TEST(handleMessageHeadline);
|
||||
CPPUNIT_TEST(handleConvMessageAckPayload);
|
||||
CPPUNIT_TEST(handleRawXML);
|
||||
|
||||
CPPUNIT_TEST(benchmarkHandleBuddyChangedPayload);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
@ -196,6 +197,17 @@ class NetworkPluginServerTest : public CPPUNIT_NS :: TestFixture, public BasicTe
|
|||
CPPUNIT_ASSERT_EQUAL(0, (int) received.size());
|
||||
}
|
||||
|
||||
void handleRawXML() {
|
||||
User *user = userManager->getUser("user@localhost");
|
||||
|
||||
std::string xml = "<presence from='buddy1@domain.tld' to='user@localhost'/>";
|
||||
|
||||
serv->handleRawXML(xml);
|
||||
CPPUNIT_ASSERT_EQUAL(1, (int) received.size());
|
||||
CPPUNIT_ASSERT(dynamic_cast<Swift::Presence *>(getStanza(received[0])));
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("buddy1\\40domain.tld@localhost"), dynamic_cast<Swift::Presence *>(getStanza(received[0]))->getFrom().toString());
|
||||
}
|
||||
|
||||
void handleMessageHeadline() {
|
||||
User *user = userManager->getUser("user@localhost");
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ using namespace Transport;
|
|||
class RosterManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTest {
|
||||
CPPUNIT_TEST_SUITE(RosterManagerTest);
|
||||
CPPUNIT_TEST(setBuddy);
|
||||
CPPUNIT_TEST(setBuddyNoAlias);
|
||||
CPPUNIT_TEST(sendCurrentPresences);
|
||||
CPPUNIT_TEST(sendUnavailablePresences);
|
||||
CPPUNIT_TEST(sendCurrentPresence);
|
||||
|
@ -72,6 +73,25 @@ class RosterManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTest {
|
|||
|
||||
}
|
||||
|
||||
void setBuddyNoAlias() {
|
||||
User *user = userManager->getUser("user@localhost");
|
||||
CPPUNIT_ASSERT(user);
|
||||
|
||||
std::vector<std::string> grp;
|
||||
grp.push_back("group1");
|
||||
LocalBuddy *buddy = new LocalBuddy(user->getRosterManager(), -1, "buddy1", "", grp, BUDDY_JID_ESCAPING);
|
||||
user->getRosterManager()->setBuddy(buddy);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(1, (int) received.size());
|
||||
|
||||
Swift::RosterPayload::ref payload1 = getStanza(received[0])->getPayload<Swift::RosterPayload>();
|
||||
CPPUNIT_ASSERT(payload1);
|
||||
CPPUNIT_ASSERT_EQUAL(1, (int) payload1->getItems().size());
|
||||
Swift::RosterItemPayload item = payload1->getItems()[0];
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("buddy1"), Buddy::JIDToLegacyName(item.getJID()));
|
||||
CPPUNIT_ASSERT_EQUAL(std::string(""), item.getName());
|
||||
}
|
||||
|
||||
void setBuddy() {
|
||||
add2Buddies();
|
||||
CPPUNIT_ASSERT_EQUAL(4, (int) received.size());
|
||||
|
|
|
@ -125,7 +125,7 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest {
|
|||
User *user = userManager->getUser("user@localhost");
|
||||
|
||||
Swift::Presence::ref response = Swift::Presence::create();
|
||||
response->setTo("#room@localhost/hanzz");
|
||||
response->setTo("room@localhost/hanzz");
|
||||
response->setFrom("user@localhost/resource");
|
||||
|
||||
Swift::MUCPayload *payload = new Swift::MUCPayload();
|
||||
|
@ -134,11 +134,8 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest {
|
|||
injectPresence(response);
|
||||
loop->processEvents();
|
||||
|
||||
// no presence received in server mode, just disco#info
|
||||
CPPUNIT_ASSERT_EQUAL(1, (int) received.size());
|
||||
CPPUNIT_ASSERT(getStanza(received[0])->getPayload<Swift::DiscoInfo>());
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("#room"), room);
|
||||
CPPUNIT_ASSERT_EQUAL(0, (int) received.size());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("room"), room);
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("hanzz"), roomNickname);
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("password"), roomPassword);
|
||||
|
||||
|
@ -147,7 +144,7 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest {
|
|||
roomPassword = "";
|
||||
|
||||
// simulate that backend joined the room
|
||||
TestingConversation *conv = new TestingConversation(user->getConversationManager(), "#room", true);
|
||||
TestingConversation *conv = new TestingConversation(user->getConversationManager(), "room", true);
|
||||
conv->addJID("user@localhost/resource");
|
||||
user->getConversationManager()->addConversation(conv);
|
||||
|
||||
|
@ -156,8 +153,7 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest {
|
|||
loop->processEvents();
|
||||
|
||||
// no presence received in server mode, just disco#info
|
||||
CPPUNIT_ASSERT_EQUAL(1, (int) received.size());
|
||||
CPPUNIT_ASSERT(getStanza(received[0])->getPayload<Swift::DiscoInfo>());
|
||||
CPPUNIT_ASSERT_EQUAL(0, (int) received.size());
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(std::string(""), room);
|
||||
CPPUNIT_ASSERT_EQUAL(std::string(""), roomNickname);
|
||||
|
@ -169,14 +165,14 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest {
|
|||
User *user = userManager->getUser("user@localhost");
|
||||
|
||||
// Add 1 participant
|
||||
Conversation *conv = user->getConversationManager()->getConversation("#room");
|
||||
conv->handleParticipantChanged("anotheruser", 0, Swift::StatusShow::Away, "my status message");
|
||||
Conversation *conv = user->getConversationManager()->getConversation("room");
|
||||
conv->handleParticipantChanged("anotheruser", Conversation::PARTICIPANT_FLAG_NONE, Swift::StatusShow::Away, "my status message");
|
||||
|
||||
// Connect 2nd resource
|
||||
connectSecondResource();
|
||||
received2.clear();
|
||||
Swift::Presence::ref response = Swift::Presence::create();
|
||||
response->setTo("#room@localhost/hanzz");
|
||||
response->setTo("room@localhost/hanzz");
|
||||
response->setFrom("user@localhost/resource2");
|
||||
|
||||
Swift::MUCPayload *payload = new Swift::MUCPayload();
|
||||
|
@ -189,19 +185,20 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest {
|
|||
CPPUNIT_ASSERT_EQUAL(std::string(""), roomNickname);
|
||||
CPPUNIT_ASSERT_EQUAL(std::string(""), roomPassword);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(2, (int) received2.size());
|
||||
CPPUNIT_ASSERT(dynamic_cast<Swift::Presence *>(getStanza(received2[1])));
|
||||
CPPUNIT_ASSERT_EQUAL(Swift::StatusShow::Away, dynamic_cast<Swift::Presence *>(getStanza(received2[1]))->getShow());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("user@localhost/resource2"), dynamic_cast<Swift::Presence *>(getStanza(received2[1]))->getTo().toString());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("#room@localhost/anotheruser"), dynamic_cast<Swift::Presence *>(getStanza(received2[1]))->getFrom().toString());
|
||||
CPPUNIT_ASSERT(getStanza(received2[1])->getPayload<Swift::MUCUserPayload>());
|
||||
CPPUNIT_ASSERT_EQUAL(Swift::MUCOccupant::Member, *getStanza(received2[1])->getPayload<Swift::MUCUserPayload>()->getItems()[0].affiliation);
|
||||
CPPUNIT_ASSERT_EQUAL(Swift::MUCOccupant::Participant, *getStanza(received2[1])->getPayload<Swift::MUCUserPayload>()->getItems()[0].role);
|
||||
CPPUNIT_ASSERT_EQUAL(1, (int) received2.size());
|
||||
CPPUNIT_ASSERT(dynamic_cast<Swift::Presence *>(getStanza(received2[0])));
|
||||
CPPUNIT_ASSERT_EQUAL(Swift::StatusShow::Away, dynamic_cast<Swift::Presence *>(getStanza(received2[0]))->getShow());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("user@localhost/resource2"), dynamic_cast<Swift::Presence *>(getStanza(received2[0]))->getTo().toString());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("room@localhost/anotheruser"), dynamic_cast<Swift::Presence *>(getStanza(received2[0]))->getFrom().toString());
|
||||
CPPUNIT_ASSERT(getStanza(received2[0])->getPayload<Swift::MUCUserPayload>());
|
||||
CPPUNIT_ASSERT_EQUAL(Swift::MUCOccupant::Member, *getStanza(received2[0])->getPayload<Swift::MUCUserPayload>()->getItems()[0].affiliation);
|
||||
CPPUNIT_ASSERT_EQUAL(Swift::MUCOccupant::Participant, *getStanza(received2[0])->getPayload<Swift::MUCUserPayload>()->getItems()[0].role);
|
||||
}
|
||||
|
||||
void handlePresenceLeaveRoom() {
|
||||
received.clear();
|
||||
Swift::Presence::ref response = Swift::Presence::create();
|
||||
response->setTo("#room@localhost/hanzz");
|
||||
response->setTo("room@localhost/hanzz");
|
||||
response->setFrom("user@localhost/resource");
|
||||
response->setType(Swift::Presence::Unavailable);
|
||||
|
||||
|
@ -213,9 +210,9 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest {
|
|||
|
||||
CPPUNIT_ASSERT_EQUAL(0, (int) received.size());
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("#room"), room);
|
||||
CPPUNIT_ASSERT_EQUAL(std::string(""), roomNickname);
|
||||
CPPUNIT_ASSERT_EQUAL(std::string(""), roomPassword);
|
||||
// CPPUNIT_ASSERT_EQUAL(std::string("room"), room);
|
||||
// CPPUNIT_ASSERT_EQUAL(std::string(""), roomNickname);
|
||||
// CPPUNIT_ASSERT_EQUAL(std::string(""), roomPassword);
|
||||
}
|
||||
|
||||
void handlePresenceLeaveRoomTwoResources() {
|
||||
|
@ -224,7 +221,7 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest {
|
|||
|
||||
// User is still connected from resource2, so he should not leave the room
|
||||
Swift::Presence::ref response = Swift::Presence::create();
|
||||
response->setTo("#room@localhost/hanzz");
|
||||
response->setTo("room@localhost/hanzz");
|
||||
response->setFrom("user@localhost/resource");
|
||||
response->setType(Swift::Presence::Unavailable);
|
||||
|
||||
|
@ -243,7 +240,7 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest {
|
|||
// disconnect also from resource
|
||||
// User is still connected from resource2, so he should not leave the room
|
||||
response = Swift::Presence::create();
|
||||
response->setTo("#room@localhost/hanzz");
|
||||
response->setTo("room@localhost/hanzz");
|
||||
response->setFrom("user@localhost/resource2");
|
||||
response->setType(Swift::Presence::Unavailable);
|
||||
|
||||
|
@ -255,7 +252,7 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest {
|
|||
|
||||
CPPUNIT_ASSERT_EQUAL(0, (int) received.size());
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("#room"), room);
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("room"), room);
|
||||
CPPUNIT_ASSERT_EQUAL(std::string(""), roomNickname);
|
||||
CPPUNIT_ASSERT_EQUAL(std::string(""), roomPassword);
|
||||
}
|
||||
|
@ -278,7 +275,7 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest {
|
|||
CPPUNIT_ASSERT_EQUAL(std::string(""), roomNickname);
|
||||
CPPUNIT_ASSERT_EQUAL(std::string(""), roomPassword);
|
||||
|
||||
Conversation *conv = user->getConversationManager()->getConversation("#room");
|
||||
Conversation *conv = user->getConversationManager()->getConversation("room");
|
||||
CPPUNIT_ASSERT_EQUAL(1, (int) conv->getJIDs().size());
|
||||
CPPUNIT_ASSERT_EQUAL(Swift::JID("user@localhost/resource2"), conv->getJIDs().front());
|
||||
}
|
||||
|
@ -287,7 +284,7 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest {
|
|||
User *user = userManager->getUser("user@localhost");
|
||||
user->addUserSetting("stay_connected", "1");
|
||||
Swift::Presence::ref response = Swift::Presence::create();
|
||||
response->setTo("#room@localhost/hanzz");
|
||||
response->setTo("room@localhost/hanzz");
|
||||
response->setFrom("user@localhost/resource");
|
||||
response->setType(Swift::Presence::Unavailable);
|
||||
|
||||
|
@ -312,7 +309,7 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest {
|
|||
|
||||
// User is still connected from resource2, so he should not leave the room
|
||||
Swift::Presence::ref response = Swift::Presence::create();
|
||||
response->setTo("#room@localhost/hanzz");
|
||||
response->setTo("room@localhost/hanzz");
|
||||
response->setFrom("user@localhost/resource");
|
||||
response->setType(Swift::Presence::Unavailable);
|
||||
|
||||
|
@ -332,7 +329,7 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest {
|
|||
// disconnect also from resource
|
||||
// User is still connected from resource2, so he should not leave the room
|
||||
response = Swift::Presence::create();
|
||||
response->setTo("#room@localhost/hanzz");
|
||||
response->setTo("room@localhost/hanzz");
|
||||
response->setFrom("user@localhost/resource2");
|
||||
response->setType(Swift::Presence::Unavailable);
|
||||
|
||||
|
@ -368,7 +365,7 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest {
|
|||
CPPUNIT_ASSERT_EQUAL(std::string(""), roomNickname);
|
||||
CPPUNIT_ASSERT_EQUAL(std::string(""), roomPassword);
|
||||
|
||||
Conversation *conv = user->getConversationManager()->getConversation("#room");
|
||||
Conversation *conv = user->getConversationManager()->getConversation("room");
|
||||
CPPUNIT_ASSERT_EQUAL(1, (int) conv->getJIDs().size());
|
||||
CPPUNIT_ASSERT_EQUAL(Swift::JID("user@localhost/resource2"), conv->getJIDs().front());
|
||||
}
|
||||
|
@ -377,12 +374,12 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest {
|
|||
User *user = userManager->getUser("user@localhost");
|
||||
handlePresenceJoinRoom();
|
||||
|
||||
CPPUNIT_ASSERT(user->getConversationManager()->getConversation("#room"));
|
||||
CPPUNIT_ASSERT(user->getConversationManager()->getConversation("room"));
|
||||
|
||||
received.clear();
|
||||
handlePresenceLeaveRoom();
|
||||
|
||||
CPPUNIT_ASSERT(!user->getConversationManager()->getConversation("#room"));
|
||||
CPPUNIT_ASSERT(!user->getConversationManager()->getConversation("room"));
|
||||
}
|
||||
|
||||
void handleDisconnected() {
|
||||
|
@ -427,7 +424,7 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest {
|
|||
user->setConnected(false);
|
||||
|
||||
Swift::Presence::ref response = Swift::Presence::create();
|
||||
response->setTo("#room@localhost/hanzz");
|
||||
response->setTo("room@localhost/hanzz");
|
||||
response->setFrom("user@localhost/resource");
|
||||
|
||||
Swift::MUCPayload *payload = new Swift::MUCPayload();
|
||||
|
@ -436,16 +433,13 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest {
|
|||
injectPresence(response);
|
||||
loop->processEvents();
|
||||
|
||||
// no presence received in server mode, just disco#info
|
||||
CPPUNIT_ASSERT_EQUAL(1, (int) received.size());
|
||||
CPPUNIT_ASSERT(getStanza(received[0])->getPayload<Swift::DiscoInfo>());
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(0, (int) received.size());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string(""), room);
|
||||
CPPUNIT_ASSERT_EQUAL(std::string(""), roomNickname);
|
||||
CPPUNIT_ASSERT_EQUAL(std::string(""), roomPassword);
|
||||
|
||||
user->setConnected(true);
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("#room"), room);
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("room"), room);
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("hanzz"), roomNickname);
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("password"), roomPassword);
|
||||
}
|
||||
|
@ -460,7 +454,7 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest {
|
|||
received.clear();
|
||||
user->setConnected(true);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("#room"), room);
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("room"), room);
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("hanzz"), roomNickname);
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("password"), roomPassword);
|
||||
CPPUNIT_ASSERT_EQUAL(0, (int) received.size());
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#include <Swiften/Server/Server.h>
|
||||
#include <Swiften/Network/DummyNetworkFactories.h>
|
||||
#include <Swiften/Network/DummyConnectionServer.h>
|
||||
#include <Swiften/Network/ConnectionFactory.h>
|
||||
#include <Swiften/Network/DummyTimerFactory.h>
|
||||
|
||||
using namespace Transport;
|
||||
|
||||
|
@ -34,7 +36,7 @@ class UserRegistryTest : public CPPUNIT_NS :: TestFixture {
|
|||
userRegistry->onConnectUser.connect(bind(&UserRegistryTest::handleConnectUser, this, _1));
|
||||
userRegistry->onDisconnectUser.connect(bind(&UserRegistryTest::handleDisconnectUser, this, _1));
|
||||
|
||||
server = new Swift::Server(loop, factories, userRegistry, "localhost", 5222);
|
||||
server = new Swift::Server(loop, factories, userRegistry, "localhost", "0.0.0.0", 5222);
|
||||
server->start();
|
||||
connectionServer = server->getConnectionServer();
|
||||
|
||||
|
|
|
@ -51,7 +51,10 @@
|
|||
#include "transport/BlockSerializer.h"
|
||||
#include "Swiften/Parser/PayloadParsers/InvisibleParser.h"
|
||||
#include "Swiften/Serializer/PayloadSerializers/InvisibleSerializer.h"
|
||||
#include "Swiften/Swiften.h"
|
||||
#include "Swiften/Parser/GenericPayloadParserFactory.h"
|
||||
#include "Swiften/Queries/IQRouter.h"
|
||||
#include "Swiften/Elements/RosterPayload.h"
|
||||
#include "Swiften/Elements/InBandRegistrationPayload.h"
|
||||
|
||||
using namespace Swift;
|
||||
using namespace boost;
|
||||
|
@ -67,9 +70,11 @@ Component::Component(Swift::EventLoop *loop, Swift::NetworkFactories *factories,
|
|||
m_server = NULL;
|
||||
m_reconnectCount = 0;
|
||||
m_config = config;
|
||||
m_config->onBackendConfigUpdated.connect(boost::bind(&Component::handleBackendConfigChanged, this));
|
||||
m_factory = factory;
|
||||
m_loop = loop;
|
||||
m_userRegistry = userRegistry;
|
||||
m_rawXML = false;
|
||||
|
||||
m_jid = Swift::JID(CONFIG_STRING(m_config, "service.jid"));
|
||||
|
||||
|
@ -80,7 +85,7 @@ Component::Component(Swift::EventLoop *loop, Swift::NetworkFactories *factories,
|
|||
|
||||
if (CONFIG_BOOL(m_config, "service.server_mode")) {
|
||||
LOG4CXX_INFO(logger, "Creating component in server mode on port " << CONFIG_INT(m_config, "service.port"));
|
||||
m_server = new Swift::Server(loop, m_factories, m_userRegistry, m_jid, CONFIG_INT(m_config, "service.port"));
|
||||
m_server = new Swift::Server(loop, m_factories, m_userRegistry, m_jid, CONFIG_STRING(m_config, "service.server"), CONFIG_INT(m_config, "service.port"));
|
||||
if (!CONFIG_STRING(m_config, "service.cert").empty()) {
|
||||
#ifndef _WIN32
|
||||
//TODO: fix
|
||||
|
@ -177,6 +182,30 @@ Component::~Component() {
|
|||
}
|
||||
}
|
||||
|
||||
bool Component::handleIQ(boost::shared_ptr<Swift::IQ> iq) {
|
||||
if (!m_rawXML) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (iq->getPayload<Swift::RosterPayload>() != NULL) { return false; }
|
||||
if (iq->getPayload<Swift::InBandRegistrationPayload>() != NULL) { return false; }
|
||||
if (iq->getPayload<Swift::StatsPayload>() != NULL) { return false; }
|
||||
|
||||
if (iq->getTo().getNode().empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
onRawIQReceived(iq);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Component::handleBackendConfigChanged() {
|
||||
if (!m_rawXML && CONFIG_BOOL_DEFAULTED(m_config, "features.rawxml", false)) {
|
||||
m_rawXML = true;
|
||||
m_iqRouter->addHandler(this);
|
||||
}
|
||||
}
|
||||
|
||||
Swift::StanzaChannel *Component::getStanzaChannel() {
|
||||
return m_stanzaChannel;
|
||||
}
|
||||
|
@ -275,9 +304,8 @@ void Component::handleDataWritten(const Swift::SafeByteArray &data) {
|
|||
}
|
||||
|
||||
void Component::handlePresence(Swift::Presence::ref presence) {
|
||||
bool isMUC = presence->getPayload<MUCPayload>() != NULL || *presence->getTo().getNode().c_str() == '#';
|
||||
// filter out login/logout presence spam
|
||||
if (!presence->getTo().getNode().empty() && isMUC == false)
|
||||
if (!presence->getTo().getNode().empty())
|
||||
return;
|
||||
|
||||
// filter out bad presences
|
||||
|
|
41
src/user.cpp
41
src/user.cpp
|
@ -26,7 +26,6 @@
|
|||
#include "transport/conversationmanager.h"
|
||||
#include "transport/presenceoracle.h"
|
||||
#include "transport/logging.h"
|
||||
#include "Swiften/Swiften.h"
|
||||
#include "Swiften/Server/ServerStanzaChannel.h"
|
||||
#include "Swiften/Elements/StreamError.h"
|
||||
#include "Swiften/Elements/MUCPayload.h"
|
||||
|
@ -195,11 +194,6 @@ void User::setCacheMessages(bool cacheMessages) {
|
|||
}
|
||||
|
||||
void User::handlePresence(Swift::Presence::ref presence, bool forceJoin) {
|
||||
|
||||
int currentResourcesCount = m_presenceOracle->getAllPresence(m_jid).size();
|
||||
|
||||
m_conversationManager->resetResources();
|
||||
|
||||
LOG4CXX_INFO(logger, "PRESENCE " << presence->getFrom().toString() << " " << presence->getTo().toString());
|
||||
if (!m_connected) {
|
||||
// we are not connected to legacy network, so we should do it when disco#info arrive :)
|
||||
|
@ -231,8 +225,9 @@ void User::handlePresence(Swift::Presence::ref presence, bool forceJoin) {
|
|||
}
|
||||
}
|
||||
|
||||
bool isMUC = presence->getPayload<Swift::MUCPayload>() != NULL || *presence->getTo().getNode().c_str() == '#';
|
||||
if (isMUC) {
|
||||
|
||||
if (!presence->getTo().getNode().empty()) {
|
||||
bool isMUC = presence->getPayload<Swift::MUCPayload>() != NULL || *presence->getTo().getNode().c_str() == '#';
|
||||
if (presence->getType() == Swift::Presence::Unavailable) {
|
||||
std::string room = Buddy::JIDToLegacyName(presence->getTo());
|
||||
Conversation *conv = m_conversationManager->getConversation(room);
|
||||
|
@ -242,9 +237,13 @@ void User::handlePresence(Swift::Presence::ref presence, bool forceJoin) {
|
|||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
|
||||
if (getUserSetting("stay_connected") != "1") {
|
||||
LOG4CXX_INFO(logger, m_jid.toString() << ": Going to left room " << room);
|
||||
onRawPresenceReceived(presence);
|
||||
onRoomLeft(room);
|
||||
|
||||
BOOST_FOREACH(Swift::Presence::ref &p, m_joinedRooms) {
|
||||
|
@ -260,7 +259,7 @@ void User::handlePresence(Swift::Presence::ref presence, bool forceJoin) {
|
|||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
else if (isMUC) {
|
||||
// force connection to legacy network to let backend to handle auto-join on connect.
|
||||
if (!m_readyForConnect) {
|
||||
LOG4CXX_INFO(logger, m_jid.toString() << ": Ready to be connected to legacy network");
|
||||
|
@ -286,6 +285,7 @@ void User::handlePresence(Swift::Presence::ref presence, bool forceJoin) {
|
|||
}
|
||||
|
||||
if (forceJoin) {
|
||||
onRawPresenceReceived(presence);
|
||||
onRoomJoined(presence->getFrom(), room, presence->getTo().getResource(), password);
|
||||
}
|
||||
return;
|
||||
|
@ -313,13 +313,34 @@ void User::handlePresence(Swift::Presence::ref presence, bool forceJoin) {
|
|||
conv->setNickname(presence->getTo().getResource());
|
||||
conv->addJID(presence->getFrom());
|
||||
|
||||
onRawPresenceReceived(presence);
|
||||
onRoomJoined(presence->getFrom(), room, presence->getTo().getResource(), password);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
int currentResourcesCount = m_presenceOracle->getAllPresence(m_jid).size();
|
||||
|
||||
m_conversationManager->resetResources();
|
||||
|
||||
|
||||
if (presence->getType() == Swift::Presence::Unavailable) {
|
||||
m_conversationManager->removeJID(presence->getFrom());
|
||||
|
||||
std::string presences;
|
||||
std::vector<Swift::Presence::ref> ps = m_presenceOracle->getAllPresence(m_jid);
|
||||
BOOST_FOREACH(Swift::Presence::ref p, ps) {
|
||||
if (p != presence) {
|
||||
presences += p->getFrom().toString() + " ";
|
||||
}
|
||||
};
|
||||
|
||||
if (!presences.empty()) {
|
||||
LOG4CXX_INFO(logger, m_jid.toString() << ": User is still connected from following clients: " << presences);
|
||||
}
|
||||
else {
|
||||
LOG4CXX_INFO(logger, m_jid.toString() << ": Last client disconnected");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -29,12 +29,15 @@
|
|||
#include "transport/discoitemsresponder.h"
|
||||
#include "storageresponder.h"
|
||||
|
||||
#include "Swiften/Swiften.h"
|
||||
#include "Swiften/Server/ServerStanzaChannel.h"
|
||||
#include "Swiften/Elements/StreamError.h"
|
||||
#ifndef __FreeBSD__
|
||||
#include "Swiften/Elements/MUCPayload.h"
|
||||
#include "Swiften/Elements/ChatState.h"
|
||||
#ifndef __FreeBSD__
|
||||
#ifndef __MACH__
|
||||
#include "malloc.h"
|
||||
#endif
|
||||
#endif
|
||||
// #include "valgrind/memcheck.h"
|
||||
|
||||
namespace Transport {
|
||||
|
@ -129,9 +132,11 @@ void UserManager::removeUser(User *user, bool onUserBehalf) {
|
|||
delete user;
|
||||
#ifndef WIN32
|
||||
#ifndef __FreeBSD__
|
||||
#ifndef __MACH__
|
||||
malloc_trim(0);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
// VALGRIND_DO_LEAK_CHECK;
|
||||
}
|
||||
|
||||
|
@ -229,7 +234,7 @@ void UserManager::handlePresence(Swift::Presence::ref presence) {
|
|||
res.password = "";
|
||||
res.uin = presence->getFrom().getNode();
|
||||
res.jid = userkey;
|
||||
if (res.uin.find_last_of("%") != std::string::npos) { // OK
|
||||
while (res.uin.find_last_of("%") != std::string::npos) { // OK
|
||||
res.uin.replace(res.uin.find_last_of("%"), 1, "@"); // OK
|
||||
}
|
||||
if (m_storageBackend) {
|
||||
|
@ -247,8 +252,8 @@ void UserManager::handlePresence(Swift::Presence::ref presence) {
|
|||
// We allow auto_register feature in gateway-mode. This allows IRC user to register
|
||||
// the transport just by joining the room.
|
||||
if (!m_component->inServerMode()) {
|
||||
if (!registered && (CONFIG_BOOL(m_component->getConfig(), "registration.auto_register") ||
|
||||
!CONFIG_BOOL_DEFAULTED(m_component->getConfig(), "registration.needRegistration", true))) {
|
||||
if (!registered && (CONFIG_BOOL(m_component->getConfig(), "registration.auto_register")
|
||||
/*!CONFIG_BOOL_DEFAULTED(m_component->getConfig(), "registration.needRegistration", true)*/)) {
|
||||
res.password = "";
|
||||
res.jid = userkey;
|
||||
|
||||
|
@ -399,6 +404,7 @@ void UserManager::handleGeneralPresenceReceived(Swift::Presence::ref presence) {
|
|||
break;
|
||||
case Swift::Presence::Available:
|
||||
case Swift::Presence::Unavailable:
|
||||
handleMUCPresence(presence);
|
||||
break;
|
||||
case Swift::Presence::Probe:
|
||||
handleProbePresence(presence);
|
||||
|
@ -411,6 +417,24 @@ void UserManager::handleGeneralPresenceReceived(Swift::Presence::ref presence) {
|
|||
};
|
||||
}
|
||||
|
||||
void UserManager::handleMUCPresence(Swift::Presence::ref presence) {
|
||||
// Don't let RosterManager to handle presences for us
|
||||
if (presence->getTo().getNode().empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (presence->getType() == Swift::Presence::Available) {
|
||||
handlePresence(presence);
|
||||
}
|
||||
else if (presence->getType() == Swift::Presence::Unavailable) {
|
||||
std::string userkey = presence->getFrom().toBare().toString();
|
||||
User *user = getUser(userkey);
|
||||
if (user) {
|
||||
user->handlePresence(presence);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UserManager::handleProbePresence(Swift::Presence::ref presence) {
|
||||
// Don't let RosterManager to handle presences for us
|
||||
if (presence->getTo().getNode().empty()) {
|
||||
|
|
|
@ -26,6 +26,9 @@
|
|||
#include "transport/user.h"
|
||||
#include "transport/logging.h"
|
||||
#include "Swiften/Elements/ErrorPayload.h"
|
||||
#include "Swiften/EventLoop/SimpleEventLoop.h"
|
||||
#include "Swiften/Network/BoostNetworkFactories.h"
|
||||
#include "Swiften/Client/Client.h"
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include "Swiften/Swiften.h"
|
||||
#include "Swiften/Server/UserRegistry.h"
|
||||
#include "transport/userregistry.h"
|
||||
#include "transport/logging.h"
|
||||
|
@ -79,9 +78,6 @@ void UserRegistry::stopLogin(const Swift::JID& user, Swift::ServerFromClientSess
|
|||
LOG4CXX_WARN(logger, key << ": Stopping login process (user probably disconnected while logging in), but this is not active session");
|
||||
}
|
||||
}
|
||||
else {
|
||||
LOG4CXX_WARN(logger, key << ": Stopping login process (user probably disconnected while logging in) for invalid user");
|
||||
}
|
||||
|
||||
// ::removeLater can be called only by libtransport, not by Swift and libtransport
|
||||
// takes care about user disconnecting itself, so don't call our signal.
|
||||
|
@ -96,21 +92,15 @@ void UserRegistry::onPasswordValid(const Swift::JID &user) {
|
|||
users[key].session->handlePasswordValid();
|
||||
users.erase(key);
|
||||
}
|
||||
else {
|
||||
LOG4CXX_INFO(logger, key << ": onPasswordValid called for invalid user");
|
||||
}
|
||||
}
|
||||
|
||||
void UserRegistry::onPasswordInvalid(const Swift::JID &user, const std::string &error) {
|
||||
std::string key = user.toBare().toString();
|
||||
if (users.find(key) != users.end()) {
|
||||
LOG4CXX_INFO(logger, key << ": Password is invalid");
|
||||
LOG4CXX_INFO(logger, key << ": Password is invalid or there was an error when connecting the legacy network");
|
||||
users[key].session->handlePasswordInvalid(error);
|
||||
users.erase(key);
|
||||
}
|
||||
else {
|
||||
LOG4CXX_INFO(logger, key << ": onPasswordInvalid called for invalid user");
|
||||
}
|
||||
}
|
||||
|
||||
void UserRegistry::handleRemoveTimeout(const Swift::JID &user) {
|
||||
|
|
|
@ -23,11 +23,12 @@
|
|||
#include <iostream>
|
||||
#include <boost/bind.hpp>
|
||||
#include "Swiften/Queries/IQRouter.h"
|
||||
#include "Swiften/Swiften.h"
|
||||
#include "transport/storagebackend.h"
|
||||
#include "transport/transport.h"
|
||||
#include "transport/logging.h"
|
||||
|
||||
#include "Swiften/Network/NetworkFactories.h"
|
||||
|
||||
using namespace Swift;
|
||||
using namespace boost;
|
||||
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#include <iostream>
|
||||
#include <boost/bind.hpp>
|
||||
#include "Swiften/Queries/IQRouter.h"
|
||||
#include "Swiften/Swiften.h"
|
||||
#include "transport/user.h"
|
||||
#include "transport/usermanager.h"
|
||||
#include "transport/rostermanager.h"
|
||||
|
|
Loading…
Add table
Reference in a new issue