Remove old skype backend

This commit is contained in:
Jan Kaluza 2016-02-08 13:33:12 +01:00
parent 43f871a93f
commit b628deb2d8
11 changed files with 3 additions and 1415 deletions

View file

@ -213,11 +213,6 @@ endif()
set(event_DIR "${CMAKE_SOURCE_DIR}/cmake_modules")
find_package(event)
if (NOT WIN32 AND ENABLE_SKYPE)
set(dbus_DIR "${CMAKE_SOURCE_DIR}/cmake_modules")
find_package(dbus)
endif()
####### Miscallanous ######
@ -373,16 +368,6 @@ if (PROTOBUF_FOUND)
else()
message("SMSTools3 plugin : no (user disabled)")
endif()
if(${LIBDBUSGLIB_FOUND})
message("Skype plugin : yes")
include_directories(${LIBDBUSGLIB_INCLUDE_DIRS})
else()
if(ENABLE_SKYPE)
message("Skype plugin : no (install dbus-glib-devel)")
else(ENABLE_SKYPE)
message("Skype plugin : no (user disabled)")
endif()
endif()
else()
message("Frotz plugin : no (does not run on Win32)")
message("SMSTools3 plugin : no (does not run on Win32)")

View file

@ -38,6 +38,9 @@ Version 2.0.2 (2016-02-xx):
Swiften backend:
* Swiften backend works as before the frontends introduction.
Skype backend:
* The old skype backend has been removed. Use purple-skypeweb instead.
Web interface:
* Allow setting "port" and "base_location" in the config file.
* Allow maintaining joined rooms in the Web interface for the Slack

View file

@ -22,8 +22,5 @@ if (PROTOBUF_FOUND)
if(ENABLE_FROTZ)
ADD_SUBDIRECTORY(frotz)
endif()
if (${LIBDBUSGLIB_FOUND})
ADD_SUBDIRECTORY(skype)
endif()
endif()
endif()

View file

@ -1,9 +0,0 @@
cmake_minimum_required(VERSION 2.6)
FILE(GLOB SRC *.cpp)
ADD_EXECUTABLE(spectrum2_skype_backend ${SRC})
target_link_libraries(spectrum2_skype_backend ${GLIB2_LIBRARIES} ${EVENT_LIBRARIES} transport pthread ${LIBDBUSGLIB_LIBRARIES})
INSTALL(TARGETS spectrum2_skype_backend RUNTIME DESTINATION bin)

View file

@ -1,93 +0,0 @@
#include "glib.h"
#include <dbus-1.0/dbus/dbus-glib-lowlevel.h>
#include "sqlite3.h"
#include <iostream>
#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
#include "skype.h"
#include "skypeplugin.h"
DEFINE_LOGGER(logger, "backend");
using namespace Transport;
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);
}
}
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);
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) {
std::cerr << error;
return 1;
}
Logging::initBackendLogging(cfg);
g_type_init();
g_set_printerr_handler(log_glib_error);
dbus_threads_init_default();
SkypePlugin *np = new SkypePlugin(cfg, host, port);
GMainLoop *m_loop;
m_loop = g_main_loop_new(NULL, FALSE);
if (m_loop) {
g_main_loop_run(m_loop);
}
return 0;
}

View file

@ -1,600 +0,0 @@
/**
* 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 "skypedb.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 skype_check_missedmessages(gpointer data) {
Skype *skype = (Skype *) data;
skype->send_command("SEARCH MISSEDCHATMESSAGES");
return TRUE;
}
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;
}
m_db = createSkypeDirectory();
bool spawned = spawnSkype(m_db);
if (!spawned) {
m_np->handleDisconnected(m_user, pbnetwork::CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE, "Error spawning the Skype instance.");
return;
}
m_db += "/" + getUsername() + "/main.db";
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);
g_timeout_add_seconds(10, skype_check_missedmessages, 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;
}
}
}
// Try to load skype buddies from database, if it fails
// fallback to old method.
if (!SkypeDB::loadBuddies(m_np, m_db, m_user, group_map)) {
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");
GET_PROPERTY(display_alias, "USER", cmd[1], "DISPLAYNAME");
if (display_alias != "") alias = display_alias;
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] == "MESSAGES") || (cmd[0] == "CHATMESSAGES")) {
std::string msgs = GET_RESPONSE_DATA(message, "CHATMESSAGES");
std::vector<std::string> data;
boost::split(data, msgs, boost::is_any_of(","));
BOOST_FOREACH(std::string str, data) {
boost::trim(str);
if (!str.empty()) {
std::string re = send_command("GET CHATMESSAGE " + str + " STATUS");
handleSkypeMessage(re);
}
}
}
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()) {
send_command("SET CHATMESSAGE " + cmd[1] + " SEEN");
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;
}

View file

@ -1,92 +0,0 @@
/**
* 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;
std::string m_db;
};

View file

@ -1,170 +0,0 @@
/**
* 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/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
#include "skypeplugin.h"
// 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);
if (size > 0) {
const void *data = sqlite3_column_blob(stmt, 0);
photo = std::string((const char *)data + 1, size - 1);
ret = true;
} else {
ret = false;
}
}
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 create prepared statement");
LOG4CXX_ERROR(logger, (sqlite3_errmsg(db) == NULL ? "" : sqlite3_errmsg(db)));
}
sqlite3_close(db);
}
return ret;
}
bool loadBuddies(SkypePlugin *np, const std::string &db_path, std::string &user, std::map<std::string, std::string> &group_map) {
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;
// aliases, fullname,
PREP_STMT(stmt, "select skypename, displayname, mood_text from Contacts;");
if (stmt) {
BEGIN(stmt);
int ret2;
while((ret2 = sqlite3_step(stmt)) == SQLITE_ROW) {
const char *d;
d = (const char *) sqlite3_column_text(stmt, 0);
if (!d) {
continue;
}
ret = true;
std::string buddy = d;
d = (const char *) sqlite3_column_text(stmt, 1);
std::string alias = d ? d : buddy;
d = (const char *) sqlite3_column_text(stmt, 2);
std::string mood_text = d ? d : "";
std::vector<std::string> groups;
if (group_map.find(buddy) != group_map.end()) {
groups.push_back(group_map[buddy]);
}
np->handleBuddyChanged(user, buddy, alias, groups, pbnetwork::STATUS_NONE, mood_text);
}
if (ret2 != SQLITE_DONE) {
FINALIZE_STMT(stmt);
ret = false;
}
}
else {
LOG4CXX_ERROR(logger, "Can't create prepared statement");
LOG4CXX_ERROR(logger, (sqlite3_errmsg(db) == NULL ? "" : sqlite3_errmsg(db)));
}
sqlite3_close(db);
}
return ret;
}
}

View file

@ -1,35 +0,0 @@
/**
* 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>
class SkypePlugin;
namespace SkypeDB {
bool getAvatar(const std::string &db, const std::string &name, std::string &avatar);
bool loadBuddies(SkypePlugin *np, const std::string &db, std::string &user, std::map<std::string, std::string> &group_map);
}

View file

@ -1,324 +0,0 @@
/**
* 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/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) {
}

View file

@ -1,74 +0,0 @@
/**
* 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;
};