Merge branch 'master' of https://github.com/hanzz/libtransport
This commit is contained in:
commit
19a3b041f5
37 changed files with 2301 additions and 1031 deletions
|
@ -9,6 +9,7 @@ if (PROTOBUF_FOUND)
|
|||
|
||||
if (ENABLE_SWIFTEN)
|
||||
ADD_SUBDIRECTORY(swiften)
|
||||
ADD_SUBDIRECTORY(swiften_raw)
|
||||
endif()
|
||||
|
||||
ADD_SUBDIRECTORY(template)
|
||||
|
|
|
@ -1,3 +1,23 @@
|
|||
/**
|
||||
* XMPP - libpurple transport
|
||||
*
|
||||
* Copyright (C) 2013, 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 "ircnetworkplugin.h"
|
||||
#include <IrcCommand>
|
||||
#include <IrcMessage>
|
||||
|
@ -53,12 +73,13 @@ void IRCNetworkPlugin::readData() {
|
|||
m_firstPing = false;
|
||||
// Users can join the network without registering if we allow
|
||||
// one user to connect multiple IRC networks.
|
||||
NetworkPlugin::PluginConfig cfg;
|
||||
if (m_servers.empty()) {
|
||||
NetworkPlugin::PluginConfig cfg;
|
||||
cfg.setNeedRegistration(false);
|
||||
cfg.setSupportMUC(true);
|
||||
sendConfig(cfg);
|
||||
}
|
||||
cfg.setSupportMUC(true);
|
||||
cfg.disableJIDEscaping();
|
||||
sendConfig(cfg);
|
||||
}
|
||||
|
||||
std::string d = std::string(m_socket->readAll().data(), availableBytes);
|
||||
|
@ -94,7 +115,7 @@ MyIrcSession *IRCNetworkPlugin::createSession(const std::string &user, const std
|
|||
|
||||
void IRCNetworkPlugin::handleLoginRequest(const std::string &user, const std::string &legacyName, const std::string &password) {
|
||||
if (!m_servers.empty()) {
|
||||
// legacy name is users nickname
|
||||
// legacy name is user's nickname
|
||||
if (m_sessions[user] != NULL) {
|
||||
LOG4CXX_WARN(logger, user << ": Already logged in.");
|
||||
return;
|
||||
|
@ -153,6 +174,13 @@ void IRCNetworkPlugin::handleMessageSendRequest(const std::string &user, const s
|
|||
}
|
||||
|
||||
std::string target = getTargetName(legacyName);
|
||||
// We are sending PM message. On XMPP side, user is sending PM using the particular channel,
|
||||
// for example #room@irc.freenode.org/hanzz. On IRC side, we are forwarding this message
|
||||
// just to "hanzz". Therefore we have to somewhere store, that message from "hanzz" should
|
||||
// be mapped to #room@irc.freenode.org/hanzz.
|
||||
if (legacyName.find("/") != std::string::npos) {
|
||||
m_sessions[session]->addPM(target, legacyName.substr(0, legacyName.find("@")));
|
||||
}
|
||||
|
||||
LOG4CXX_INFO(logger, user << ": Session name: " << session << ", message to " << target);
|
||||
|
||||
|
|
|
@ -1,3 +1,22 @@
|
|||
/**
|
||||
* XMPP - libpurple transport
|
||||
*
|
||||
* Copyright (C) 2013, 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
|
||||
|
||||
|
|
|
@ -1,11 +1,21 @@
|
|||
/*
|
||||
* Copyright (C) 2008-2009 J-P Nurmi jpnurmi@gmail.com
|
||||
/**
|
||||
* XMPP - libpurple transport
|
||||
*
|
||||
* This example is free, and not covered by LGPL license. There is no
|
||||
* restriction applied to their modification, redistribution, using and so on.
|
||||
* You can study them, modify them, use them in your own program - either
|
||||
* completely or partially. By using it you may give me some credits in your
|
||||
* program, but you don't have to.
|
||||
* Copyright (C) 2013, 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 "transport/config.h"
|
||||
|
|
|
@ -1,11 +1,21 @@
|
|||
/*
|
||||
* Copyright (C) 2008-2009 J-P Nurmi jpnurmi@gmail.com
|
||||
/**
|
||||
* XMPP - libpurple transport
|
||||
*
|
||||
* This example is free, and not covered by LGPL license. There is no
|
||||
* restriction applied to their modification, redistribution, using and so on.
|
||||
* You can study them, modify them, use them in your own program - either
|
||||
* completely or partially. By using it you may give me some credits in your
|
||||
* program, but you don't have to.
|
||||
* Copyright (C) 2013, 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 "session.h"
|
||||
|
@ -70,7 +80,31 @@ void MyIrcSession::on_connected() {
|
|||
}
|
||||
|
||||
void MyIrcSession::on_socketError(QAbstractSocket::SocketError error) {
|
||||
on_disconnected();
|
||||
std::string reason;
|
||||
switch(error) {
|
||||
case QAbstractSocket::ConnectionRefusedError: reason = "The connection was refused by the peer (or timed out)."; break;
|
||||
case QAbstractSocket::RemoteHostClosedError: reason = "The remote host closed the connection."; break;
|
||||
case QAbstractSocket::HostNotFoundError: reason = "The host address was not found."; break;
|
||||
case QAbstractSocket::SocketAccessError: reason = "The socket operation failed because the application lacked the required privileges."; break;
|
||||
case QAbstractSocket::SocketResourceError: reason = "The local system ran out of resources."; break;
|
||||
case QAbstractSocket::SocketTimeoutError: reason = "The socket operation timed out."; break;
|
||||
case QAbstractSocket::DatagramTooLargeError: reason = "The datagram was larger than the operating system's limit."; break;
|
||||
case QAbstractSocket::NetworkError: reason = "An error occurred with the network."; break;
|
||||
case QAbstractSocket::SslHandshakeFailedError: reason = "The SSL/TLS handshake failed, so the connection was closed"; break;
|
||||
case QAbstractSocket::UnknownSocketError: reason = "An unidentified error occurred."; break;
|
||||
default: reason= "Unknown error."; break;
|
||||
};
|
||||
|
||||
if (!suffix.empty()) {
|
||||
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_ROOM_NOT_FOUND, pbnetwork::STATUS_NONE, reason);
|
||||
}
|
||||
}
|
||||
else {
|
||||
np->handleDisconnected(user, 0, reason);
|
||||
np->tryNextServer();
|
||||
}
|
||||
m_connected = false;
|
||||
}
|
||||
|
||||
void MyIrcSession::on_disconnected() {
|
||||
|
@ -96,9 +130,8 @@ bool MyIrcSession::correctNickname(std::string &nickname) {
|
|||
|
||||
void MyIrcSession::on_joined(IrcMessage *message) {
|
||||
IrcJoinMessage *m = (IrcJoinMessage *) message;
|
||||
bool op = 0;
|
||||
std::string nickname = TO_UTF8(m->sender().name());
|
||||
op = correctNickname(nickname);
|
||||
bool op = correctNickname(nickname);
|
||||
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 +140,8 @@ void MyIrcSession::on_joined(IrcMessage *message) {
|
|||
|
||||
void MyIrcSession::on_parted(IrcMessage *message) {
|
||||
IrcPartMessage *m = (IrcPartMessage *) message;
|
||||
bool op = 0;
|
||||
std::string nickname = TO_UTF8(m->sender().name());
|
||||
op = correctNickname(nickname);
|
||||
bool op = correctNickname(nickname);
|
||||
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()));
|
||||
|
@ -117,13 +149,13 @@ void MyIrcSession::on_parted(IrcMessage *message) {
|
|||
|
||||
void MyIrcSession::on_quit(IrcMessage *message) {
|
||||
IrcQuitMessage *m = (IrcQuitMessage *) message;
|
||||
std::string nickname = TO_UTF8(m->sender().name());
|
||||
bool op = correctNickname(nickname);
|
||||
|
||||
for(AutoJoinMap::iterator it = m_autoJoin.begin(); it != m_autoJoin.end(); it++) {
|
||||
bool op = 0;
|
||||
std::string nickname = TO_UTF8(m->sender().name());
|
||||
if (!hasIRCBuddy(it->second->getChannel(), nickname)) {
|
||||
continue;
|
||||
}
|
||||
op = correctNickname(nickname);
|
||||
removeIRCBuddy(it->second->getChannel(), nickname);
|
||||
LOG4CXX_INFO(logger, user << ": " << nickname << " quit " << it->second->getChannel() + suffix);
|
||||
np->handleParticipantChanged(user, nickname, it->second->getChannel() + suffix, op, pbnetwork::STATUS_NONE, TO_UTF8(m->reason()));
|
||||
|
@ -132,9 +164,10 @@ void MyIrcSession::on_quit(IrcMessage *message) {
|
|||
|
||||
void MyIrcSession::on_nickChanged(IrcMessage *message) {
|
||||
IrcNickMessage *m = (IrcNickMessage *) message;
|
||||
std::string nickname = TO_UTF8(m->sender().name());
|
||||
correctNickname(nickname);
|
||||
|
||||
for(AutoJoinMap::iterator it = m_autoJoin.begin(); it != m_autoJoin.end(); it++) {
|
||||
std::string nickname = TO_UTF8(m->sender().name());
|
||||
if (!hasIRCBuddy(it->second->getChannel(), nickname)) {
|
||||
continue;
|
||||
}
|
||||
|
@ -152,20 +185,23 @@ void MyIrcSession::on_modeChanged(IrcMessage *message) {
|
|||
std::string mode = TO_UTF8(m->mode());
|
||||
if (nickname.empty())
|
||||
return;
|
||||
LOG4CXX_INFO(logger, user << ": " << nickname << " changed mode to " << mode);
|
||||
for(AutoJoinMap::iterator it = m_autoJoin.begin(); it != m_autoJoin.end(); it++) {
|
||||
if (!hasIRCBuddy(it->second->getChannel(), nickname)) {
|
||||
continue;
|
||||
}
|
||||
IRCBuddy &buddy = getIRCBuddy(it->second->getChannel(), nickname);
|
||||
if (mode == "+o") {
|
||||
buddy.setOp(true);
|
||||
}
|
||||
else {
|
||||
buddy.setOp(false);
|
||||
}
|
||||
np->handleParticipantChanged(user, nickname, it->second->getChannel() + suffix,(int) buddy.isOp(), pbnetwork::STATUS_ONLINE, "");
|
||||
|
||||
correctNickname(nickname);
|
||||
|
||||
if (!hasIRCBuddy(TO_UTF8(m->target().toLower()), nickname)) {
|
||||
return;
|
||||
}
|
||||
IRCBuddy &buddy = getIRCBuddy(TO_UTF8(m->target().toLower()), nickname);
|
||||
if (mode == "+o") {
|
||||
buddy.setOp(true);
|
||||
}
|
||||
else {
|
||||
buddy.setOp(false);
|
||||
}
|
||||
|
||||
np->handleParticipantChanged(user, nickname, TO_UTF8(m->target().toLower()) + suffix,(int) buddy.isOp(), pbnetwork::STATUS_ONLINE, "");
|
||||
|
||||
LOG4CXX_INFO(logger, user << ": " << nickname << " changed mode to " << mode << " in " << TO_UTF8(m->target().toLower()));
|
||||
}
|
||||
|
||||
void MyIrcSession::on_topicChanged(IrcMessage *message) {
|
||||
|
@ -203,8 +239,22 @@ void MyIrcSession::on_messageReceived(IrcMessage *message) {
|
|||
else {
|
||||
std::string nickname = TO_UTF8(m->sender().name());
|
||||
correctNickname(nickname);
|
||||
LOG4CXX_INFO(logger, nickname + suffix);
|
||||
np->handleMessage(user, nickname + suffix, TO_UTF8(msg));
|
||||
if (m_pms.find(nickname) != m_pms.end()) {
|
||||
if (hasIRCBuddy(m_pms[nickname], nickname)) {
|
||||
LOG4CXX_INFO(logger, nickname);
|
||||
np->handleMessage(user, m_pms[nickname] + suffix, TO_UTF8(msg), nickname, "", "", false, true);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
nickname = nickname + suffix;
|
||||
}
|
||||
}
|
||||
else {
|
||||
nickname = nickname + suffix;
|
||||
}
|
||||
|
||||
LOG4CXX_INFO(logger, nickname);
|
||||
np->handleMessage(user, nickname, TO_UTF8(msg));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -313,8 +363,6 @@ void MyIrcSession::on_numericMessageReceived(IrcMessage *message) {
|
|||
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;
|
||||
}
|
||||
|
||||
void MyIrcSession::awayTimeout() {
|
||||
|
|
|
@ -1,11 +1,21 @@
|
|||
/*
|
||||
* Copyright (C) 2008-2009 J-P Nurmi jpnurmi@gmail.com
|
||||
/**
|
||||
* XMPP - libpurple transport
|
||||
*
|
||||
* This example is free, and not covered by LGPL license. There is no
|
||||
* restriction applied to their modification, redistribution, using and so on.
|
||||
* You can study them, modify them, use them in your own program - either
|
||||
* completely or partially. By using it you may give me some credits in your
|
||||
* program, but you don't have to.
|
||||
* Copyright (C) 2013, 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
|
||||
*/
|
||||
|
||||
#ifndef SESSION_H
|
||||
|
@ -69,8 +79,6 @@ public:
|
|||
|
||||
MyIrcSession(const std::string &user, IRCNetworkPlugin *np, const std::string &suffix = "", QObject* parent = 0);
|
||||
virtual ~MyIrcSession();
|
||||
std::string suffix;
|
||||
int rooms;
|
||||
|
||||
void addAutoJoinChannel(const std::string &channel, const std::string &password) {
|
||||
m_autoJoin[channel] = boost::make_shared<AutoJoinChannel>(channel, password, 12 + m_autoJoin.size());
|
||||
|
@ -81,6 +89,14 @@ public:
|
|||
removeIRCBuddies(channel);
|
||||
}
|
||||
|
||||
// We are sending PM message. On XMPP side, user is sending PM using the particular channel,
|
||||
// for example #room@irc.freenode.org/hanzz. On IRC side, we are forwarding this message
|
||||
// just to "hanzz". Therefore we have to somewhere store, that message from "hanzz" should
|
||||
// be mapped to #room@irc.freenode.org/hanzz.
|
||||
void addPM(const std::string &name, const std::string &room) {
|
||||
m_pms[name] = room;
|
||||
}
|
||||
|
||||
void setIdentify(const std::string &identify) {
|
||||
m_identify = identify;
|
||||
}
|
||||
|
@ -116,6 +132,9 @@ public:
|
|||
void on_messageReceived(IrcMessage *message);
|
||||
void on_numericMessageReceived(IrcMessage *message);
|
||||
|
||||
std::string suffix;
|
||||
int rooms;
|
||||
|
||||
protected Q_SLOTS:
|
||||
void on_connected();
|
||||
void on_disconnected();
|
||||
|
@ -133,6 +152,7 @@ protected:
|
|||
bool m_connected;
|
||||
std::list<std::string> m_rooms;
|
||||
std::list<std::string> m_names;
|
||||
std::map<std::string, std::string> m_pms;
|
||||
IRCBuddyMap m_buddies;
|
||||
QTimer *m_awayTimer;
|
||||
};
|
||||
|
|
|
@ -91,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) {
|
||||
|
@ -357,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);
|
||||
|
@ -806,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]);
|
||||
|
||||
|
@ -881,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
|
||||
};
|
||||
|
||||
|
|
|
@ -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,866 +22,15 @@
|
|||
#ifndef __FreeBSD__
|
||||
#include "malloc.h"
|
||||
#endif
|
||||
#include <dbus-1.0/dbus/dbus-glib-lowlevel.h>
|
||||
|
||||
#include "sqlite3.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="";\
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 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)));\
|
||||
}
|
||||
|
||||
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;
|
||||
std::map<std::string, std::string> m_groups;
|
||||
};
|
||||
|
||||
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");
|
||||
skype->send_command("SET USER " + buddyName + " ISAUTHORIZED FALSE");
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (photo.empty()) {
|
||||
sqlite3 *db;
|
||||
std::string db_path = std::string("/tmp/skype/") + skype->getUsername() + "/" + skype->getUsername() + "/main.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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
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();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
else if(cmd[2] == "RECEIVEDAUTHREQUEST") {
|
||||
np->handleAuthorization(sk->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 = sk->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);
|
||||
// np->handleBuddyChanged(sk->getUser(), u, alias, groups, status, mood_text);
|
||||
// }
|
||||
// }
|
||||
if (cmd[2] == "NROFUSERS" && cmd[3] != "0") {
|
||||
GET_PROPERTY(grp, "GROUP", cmd[1], "DISPLAYNAME");
|
||||
std::string users = sk->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);
|
||||
np->handleBuddyChanged(sk->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 == 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;
|
||||
|
@ -896,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) {
|
||||
|
@ -969,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);
|
||||
|
@ -987,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);
|
||||
|
||||
}
|
||||
|
325
backends/skype/skypeplugin.cpp
Normal file
325
backends/skype/skypeplugin.cpp
Normal file
|
@ -0,0 +1,325 @@
|
|||
/**
|
||||
* 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
|
||||
|
||||
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();
|
||||
google::protobuf::ShutdownProtobufLibrary();
|
||||
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();
|
||||
google::protobuf::ShutdownProtobufLibrary();
|
||||
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();
|
||||
google::protobuf::ShutdownProtobufLibrary();
|
||||
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();
|
||||
google::protobuf::ShutdownProtobufLibrary();
|
||||
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;
|
||||
|
||||
};
|
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,
|
||||
|
|
|
@ -40,7 +40,8 @@ class Conversation {
|
|||
PARTICIPANT_FLAG_BANNED = 4,
|
||||
PARTICIPANT_FLAG_NOT_AUTHORIZED = 8,
|
||||
PARTICIPANT_FLAG_ME = 16,
|
||||
PARTICIPANT_FLAG_KICKED = 32
|
||||
PARTICIPANT_FLAG_KICKED = 32,
|
||||
PARTICIPANT_FLAG_ROOM_NOT_FOUD = 64
|
||||
} ParticipantFlag;
|
||||
|
||||
typedef struct _Participant {
|
||||
|
@ -70,6 +71,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.
|
||||
|
|
|
@ -65,6 +65,8 @@ class LocalBuddy : public Buddy {
|
|||
std::string m_statusMessage;
|
||||
std::string m_iconHash;
|
||||
Swift::StatusShow m_status;
|
||||
|
||||
friend class NetworkPluginServer;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -39,18 +39,23 @@ class NetworkPlugin {
|
|||
|
||||
class PluginConfig {
|
||||
public:
|
||||
PluginConfig() : m_needPassword(true), m_needRegistration(false), m_supportMUC(false) {}
|
||||
PluginConfig() : m_needPassword(true), m_needRegistration(false), m_supportMUC(false), m_rawXML(false),
|
||||
m_disableJIDEscaping(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; }
|
||||
void disableJIDEscaping() { m_disableJIDEscaping = true; }
|
||||
|
||||
private:
|
||||
bool m_needPassword;
|
||||
bool m_needRegistration;
|
||||
bool m_supportMUC;
|
||||
bool m_rawXML;
|
||||
bool m_disableJIDEscaping;
|
||||
std::vector<std::string> m_extraFields;
|
||||
|
||||
friend class NetworkPlugin;
|
||||
|
@ -67,6 +72,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")
|
||||
|
@ -245,6 +252,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); }
|
||||
|
|
|
@ -28,6 +28,11 @@
|
|||
#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"
|
||||
|
||||
|
@ -47,7 +52,7 @@ class DummyReadBytestream;
|
|||
class AdminInterface;
|
||||
class DiscoItemsResponder;
|
||||
|
||||
class NetworkPluginServer {
|
||||
class NetworkPluginServer : Swift::XMPPParserClient {
|
||||
public:
|
||||
struct Backend {
|
||||
int pongReceived;
|
||||
|
@ -116,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);
|
||||
|
@ -149,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;
|
||||
|
@ -171,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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -95,6 +95,7 @@ enum ParticipantFlag {
|
|||
PARTICIPANT_FLAG_NOT_AUTHORIZED = 8;
|
||||
PARTICIPANT_FLAG_ME = 16;
|
||||
PARTICIPANT_FLAG_KICKED = 32;
|
||||
PARTICIPANT_FLAG_ROOM_NOT_FOUND = 64;
|
||||
}
|
||||
|
||||
message Participant {
|
||||
|
@ -180,6 +181,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;
|
||||
|
|
|
@ -30,9 +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"
|
||||
|
@ -52,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.
|
||||
|
||||
|
@ -151,6 +153,8 @@ namespace Transport {
|
|||
/// \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::IQ>)> onRawIQReceived;
|
||||
|
||||
private:
|
||||
void handleConnected();
|
||||
void handleConnectionError(const Swift::ComponentError &error);
|
||||
|
@ -162,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;
|
||||
|
@ -181,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;
|
||||
|
|
|
@ -133,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;
|
||||
|
|
|
@ -73,6 +73,9 @@ void NetworkPlugin::sendConfig(const PluginConfig &cfg) {
|
|||
|
||||
data += "[features]\n";
|
||||
data += std::string("muc=") + (cfg.m_supportMUC ? "1" : "0") + "\n";
|
||||
data += std::string("rawxml=") + (cfg.m_rawXML ? "1" : "0") + "\n";
|
||||
data += std::string("disable_jid_escaping=") + (cfg.m_disableJIDEscaping ? "1" : "0") + "\n";
|
||||
|
||||
|
||||
pbnetwork::BackendConfig m;
|
||||
m.set_config(data);
|
||||
|
@ -85,6 +88,12 @@ void NetworkPlugin::sendConfig(const PluginConfig &cfg) {
|
|||
send(message);
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -647,6 +656,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;
|
||||
}
|
||||
|
|
|
@ -103,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) {
|
||||
|
|
|
@ -315,6 +315,8 @@ void Config::updateBackendConfig(const std::string &backendConfig) {
|
|||
("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), "")
|
||||
("features.disable_jid_escaping", value<bool>()->default_value(false), "")
|
||||
;
|
||||
|
||||
std::stringstream ifs(backendConfig);
|
||||
|
@ -324,6 +326,12 @@ void Config::updateBackendConfig(const std::string &backendConfig) {
|
|||
notify(m_backendConfig);
|
||||
|
||||
onBackendConfigUpdated();
|
||||
|
||||
if (CONFIG_BOOL_DEFAULTED(this, "features.disable_jid_escaping", false)) {
|
||||
Variables::iterator it(m_variables.find("service.jid_escaping"));
|
||||
boost::program_options::variable_value& vx(it->second);
|
||||
vx.value() = false;
|
||||
}
|
||||
}
|
||||
|
||||
Config *Config::createFromArgs(int argc, char **argv, std::string &error, std::string &host, int &port) {
|
||||
|
|
|
@ -39,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() {
|
||||
|
@ -82,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);
|
||||
|
@ -137,20 +182,6 @@ void Conversation::handleMessage(boost::shared_ptr<Swift::Message> &message, con
|
|||
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;
|
||||
|
@ -164,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) {
|
||||
|
@ -246,7 +257,14 @@ Swift::Presence::ref Conversation::generatePresence(const std::string &nick, int
|
|||
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)));
|
||||
presence->addPayload(boost::shared_ptr<Swift::Payload>(new Swift::ErrorPayload(Swift::ErrorPayload::NotAuthorized, Swift::ErrorPayload::Auth, statusMessage)));
|
||||
return presence;
|
||||
}
|
||||
else if (flag & PARTICIPANT_FLAG_ROOM_NOT_FOUD) {
|
||||
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::ItemNotFound, Swift::ErrorPayload::Cancel, statusMessage)));
|
||||
return presence;
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -269,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();
|
||||
|
@ -987,6 +992,145 @@ 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();
|
||||
NetworkConversation *conv = (NetworkConversation *) user->getConversationManager()->getConversation(originalJID.toBare());
|
||||
|
||||
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 (conv && conv->isMUC()) {
|
||||
if (name.find_last_of("@") != std::string::npos) {
|
||||
name.replace(name.find_last_of("@"), 1, "%");
|
||||
}
|
||||
}
|
||||
else {
|
||||
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) {
|
||||
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());
|
||||
}
|
||||
else {
|
||||
Swift::Presence::ref highest = m_component->getPresenceOracle()->getHighestPriorityPresence(user->getJID());
|
||||
iq->setTo(highest->getFrom());
|
||||
}
|
||||
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());
|
||||
|
@ -1098,6 +1242,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;
|
||||
}
|
||||
|
@ -1267,6 +1414,7 @@ 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));
|
||||
|
||||
|
@ -1374,6 +1522,7 @@ 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));
|
||||
|
||||
|
@ -1406,6 +1555,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;
|
||||
|
|
|
@ -295,12 +295,12 @@ bool PQXXBackend::getBuddies(long id, std::list<BuddyInfo> &roster) {
|
|||
BuddyInfo b;
|
||||
std::string group;
|
||||
|
||||
b.id = r[0][0].as<long>();
|
||||
b.legacyName = r[0][1].as<std::string>();
|
||||
b.subscription = r[0][2].as<std::string>();
|
||||
b.alias = r[0][3].as<std::string>();
|
||||
group = r[0][4].as<std::string>();
|
||||
b.flags = r[0][5].as<long>();
|
||||
b.id = (*it)[0].as<long>();
|
||||
b.legacyName = (*it)[1].as<std::string>();
|
||||
b.subscription = (*it)[2].as<std::string>();
|
||||
b.alias = (*it)[3].as<std::string>();
|
||||
group = (*it)[4].as<std::string>();
|
||||
b.flags = (*it)[5].as<long>();
|
||||
|
||||
if (!group.empty()) {
|
||||
b.groups = StorageBackend::deserializeGroups(group);
|
||||
|
@ -317,10 +317,10 @@ bool PQXXBackend::getBuddies(long id, std::list<BuddyInfo> &roster) {
|
|||
std::string key;
|
||||
std::string val;
|
||||
|
||||
buddy_id = r[0][0].as<long>();
|
||||
var.type = r[0][1].as<long>();
|
||||
key = r[0][2].as<std::string>();
|
||||
val = r[0][3].as<std::string>();
|
||||
buddy_id = (*it)[0].as<long>();
|
||||
var.type = (*it)[1].as<long>();
|
||||
key = (*it)[2].as<std::string>();
|
||||
val = (*it)[3].as<std::string>();
|
||||
switch (var.type) {
|
||||
case TYPE_BOOLEAN:
|
||||
var.b = atoi(val.c_str());
|
||||
|
|
|
@ -26,6 +26,7 @@ class ConfigTest : public CPPUNIT_NS :: TestFixture{
|
|||
CPPUNIT_TEST_SUITE(ConfigTest);
|
||||
CPPUNIT_TEST(setStringTwice);
|
||||
CPPUNIT_TEST(updateBackendConfig);
|
||||
CPPUNIT_TEST(updateBackendConfigJIDEscaping);
|
||||
CPPUNIT_TEST(unregisteredList);
|
||||
CPPUNIT_TEST(unregisteredString);
|
||||
CPPUNIT_TEST(unregisteredListAsString);
|
||||
|
@ -57,6 +58,16 @@ class ConfigTest : public CPPUNIT_NS :: TestFixture{
|
|||
CPPUNIT_ASSERT_EQUAL(false, CONFIG_BOOL(&cfg, "registration.needPassword"));
|
||||
}
|
||||
|
||||
void updateBackendConfigJIDEscaping() {
|
||||
Config cfg;
|
||||
std::istringstream ifs("service.jids = irc.freenode.org\n");
|
||||
cfg.load(ifs);
|
||||
CPPUNIT_ASSERT_EQUAL(true, CONFIG_BOOL(&cfg, "service.jid_escaping"));
|
||||
|
||||
cfg.updateBackendConfig("[features]\ndisable_jid_escaping=1\n");
|
||||
CPPUNIT_ASSERT_EQUAL(false, CONFIG_BOOL(&cfg, "service.jid_escaping"));
|
||||
}
|
||||
|
||||
void unregisteredList() {
|
||||
Config cfg;
|
||||
std::istringstream ifs("service.irc_server = irc.freenode.org\nservice.irc_server=localhost\n");
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -52,6 +52,9 @@
|
|||
#include "Swiften/Parser/PayloadParsers/InvisibleParser.h"
|
||||
#include "Swiften/Serializer/PayloadSerializers/InvisibleSerializer.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"));
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -243,6 +243,7 @@ void User::handlePresence(Swift::Presence::ref presence, bool forceJoin) {
|
|||
|
||||
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) {
|
||||
|
@ -284,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;
|
||||
|
@ -311,6 +313,7 @@ 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;
|
||||
|
|
Loading…
Add table
Reference in a new issue