Skype backend
This commit is contained in:
parent
3fd77c64ac
commit
c643e5b81d
8 changed files with 1227 additions and 0 deletions
|
@ -9,6 +9,7 @@ if (PROTOBUF_FOUND)
|
|||
|
||||
if (NOT WIN32)
|
||||
ADD_SUBDIRECTORY(frotz)
|
||||
ADD_SUBDIRECTORY(skype)
|
||||
endif()
|
||||
|
||||
endif()
|
||||
|
|
13
backends/skype/CMakeLists.txt
Normal file
13
backends/skype/CMakeLists.txt
Normal file
|
@ -0,0 +1,13 @@
|
|||
cmake_minimum_required(VERSION 2.6)
|
||||
FILE(GLOB SRC *.cpp)
|
||||
|
||||
include_directories(/usr/include/dbus-1.0/)
|
||||
include_directories(/usr/lib/dbus-1.0/include/)
|
||||
include_directories(/usr/lib64/dbus-1.0/include/)
|
||||
|
||||
ADD_EXECUTABLE(spectrum2_skype_backend ${SRC})
|
||||
|
||||
target_link_libraries(spectrum2_skype_backend ${GLIB2_LIBRARIES} ${EVENT_LIBRARIES} transport pthread dbus-glib-1 dbus-1 gobject-2.0 transport-plugin)
|
||||
|
||||
INSTALL(TARGETS spectrum2_skype_backend RUNTIME DESTINATION bin)
|
||||
|
248
backends/skype/geventloop.cpp
Normal file
248
backends/skype/geventloop.cpp
Normal file
|
@ -0,0 +1,248 @@
|
|||
/**
|
||||
* XMPP - libpurple transport
|
||||
*
|
||||
* Copyright (C) 2009, Jan Kaluza <hanzz@soc.pidgin.im>
|
||||
*
|
||||
* 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 "geventloop.h"
|
||||
#ifdef _WIN32
|
||||
#include "win32/win32dep.h"
|
||||
#endif
|
||||
#ifdef WITH_LIBEVENT
|
||||
#include "event.h"
|
||||
#endif
|
||||
|
||||
typedef struct _PurpleIOClosure {
|
||||
PurpleInputFunction function;
|
||||
guint result;
|
||||
gpointer data;
|
||||
#ifdef WITH_LIBEVENT
|
||||
GSourceFunc function2;
|
||||
struct timeval timeout;
|
||||
struct event evfifo;
|
||||
#endif
|
||||
} PurpleIOClosure;
|
||||
|
||||
static gboolean io_invoke(GIOChannel *source,
|
||||
GIOCondition condition,
|
||||
gpointer data)
|
||||
{
|
||||
PurpleIOClosure *closure = (PurpleIOClosure* )data;
|
||||
PurpleInputCondition purple_cond = (PurpleInputCondition)0;
|
||||
|
||||
int tmp = 0;
|
||||
if (condition & READ_COND)
|
||||
{
|
||||
tmp |= PURPLE_INPUT_READ;
|
||||
purple_cond = (PurpleInputCondition)tmp;
|
||||
}
|
||||
if (condition & WRITE_COND)
|
||||
{
|
||||
tmp |= PURPLE_INPUT_WRITE;
|
||||
purple_cond = (PurpleInputCondition)tmp;
|
||||
}
|
||||
|
||||
closure->function(closure->data, g_io_channel_unix_get_fd(source), purple_cond);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void io_destroy(gpointer data)
|
||||
{
|
||||
g_free(data);
|
||||
}
|
||||
|
||||
static guint input_add(gint fd,
|
||||
PurpleInputCondition condition,
|
||||
PurpleInputFunction function,
|
||||
gpointer data)
|
||||
{
|
||||
PurpleIOClosure *closure = g_new0(PurpleIOClosure, 1);
|
||||
GIOChannel *channel;
|
||||
GIOCondition cond = (GIOCondition)0;
|
||||
closure->function = function;
|
||||
closure->data = data;
|
||||
|
||||
int tmp = 0;
|
||||
if (condition & PURPLE_INPUT_READ)
|
||||
{
|
||||
tmp |= READ_COND;
|
||||
cond = (GIOCondition)tmp;
|
||||
}
|
||||
if (condition & PURPLE_INPUT_WRITE)
|
||||
{
|
||||
tmp |= WRITE_COND;
|
||||
cond = (GIOCondition)tmp;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
channel = wpurple_g_io_channel_win32_new_socket(fd);
|
||||
#else
|
||||
channel = g_io_channel_unix_new(fd);
|
||||
#endif
|
||||
closure->result = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, cond,
|
||||
io_invoke, closure, io_destroy);
|
||||
|
||||
g_io_channel_unref(channel);
|
||||
return closure->result;
|
||||
}
|
||||
|
||||
static PurpleEventLoopUiOps eventLoopOps =
|
||||
{
|
||||
g_timeout_add,
|
||||
g_source_remove,
|
||||
input_add,
|
||||
g_source_remove,
|
||||
NULL,
|
||||
#if GLIB_CHECK_VERSION(2,14,0)
|
||||
g_timeout_add_seconds,
|
||||
#else
|
||||
NULL,
|
||||
#endif
|
||||
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
#ifdef WITH_LIBEVENT
|
||||
|
||||
static GHashTable *events = NULL;
|
||||
static unsigned long id = 0;
|
||||
|
||||
static void event_io_destroy(gpointer data)
|
||||
{
|
||||
PurpleIOClosure *closure = (PurpleIOClosure* )data;
|
||||
event_del(&closure->evfifo);
|
||||
g_free(data);
|
||||
}
|
||||
|
||||
static void event_io_invoke(int fd, short event, void *data)
|
||||
{
|
||||
PurpleIOClosure *closure = (PurpleIOClosure* )data;
|
||||
PurpleInputCondition purple_cond = (PurpleInputCondition)0;
|
||||
int tmp = 0;
|
||||
if (event & EV_READ)
|
||||
{
|
||||
tmp |= PURPLE_INPUT_READ;
|
||||
purple_cond = (PurpleInputCondition)tmp;
|
||||
}
|
||||
if (event & EV_WRITE)
|
||||
{
|
||||
tmp |= PURPLE_INPUT_WRITE;
|
||||
purple_cond = (PurpleInputCondition)tmp;
|
||||
}
|
||||
if (event & EV_TIMEOUT)
|
||||
{
|
||||
// tmp |= PURPLE_INPUT_WRITE;
|
||||
// purple_cond = (PurpleInputCondition)tmp;
|
||||
if (closure->function2(closure->data))
|
||||
evtimer_add(&closure->evfifo, &closure->timeout);
|
||||
// else
|
||||
// event_io_destroy(data);
|
||||
return;
|
||||
}
|
||||
|
||||
closure->function(closure->data, fd, purple_cond);
|
||||
}
|
||||
|
||||
static gboolean event_input_remove(guint handle)
|
||||
{
|
||||
PurpleIOClosure *closure = (PurpleIOClosure *) g_hash_table_lookup(events, &handle);
|
||||
if (closure)
|
||||
event_io_destroy(closure);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static guint event_input_add(gint fd,
|
||||
PurpleInputCondition condition,
|
||||
PurpleInputFunction function,
|
||||
gpointer data)
|
||||
{
|
||||
PurpleIOClosure *closure = g_new0(PurpleIOClosure, 1);
|
||||
GIOChannel *channel;
|
||||
GIOCondition cond = (GIOCondition)0;
|
||||
closure->function = function;
|
||||
closure->data = data;
|
||||
|
||||
int tmp = EV_PERSIST;
|
||||
if (condition & PURPLE_INPUT_READ)
|
||||
{
|
||||
tmp |= EV_READ;
|
||||
}
|
||||
if (condition & PURPLE_INPUT_WRITE)
|
||||
{
|
||||
tmp |= EV_WRITE;
|
||||
}
|
||||
|
||||
event_set(&closure->evfifo, fd, tmp, event_io_invoke, closure);
|
||||
event_add(&closure->evfifo, NULL);
|
||||
|
||||
int *f = (int *) g_malloc(sizeof(int));
|
||||
*f = id;
|
||||
id++;
|
||||
g_hash_table_replace(events, f, closure);
|
||||
|
||||
return *f;
|
||||
}
|
||||
|
||||
static guint event_timeout_add (guint interval, GSourceFunc function, gpointer data) {
|
||||
struct timeval timeout;
|
||||
PurpleIOClosure *closure = g_new0(PurpleIOClosure, 1);
|
||||
closure->function2 = function;
|
||||
closure->data = data;
|
||||
|
||||
timeout.tv_sec = interval/1000;
|
||||
timeout.tv_usec = (interval%1000)*1000;
|
||||
evtimer_set(&closure->evfifo, event_io_invoke, closure);
|
||||
evtimer_add(&closure->evfifo, &timeout);
|
||||
closure->timeout = timeout;
|
||||
|
||||
guint *f = (guint *) g_malloc(sizeof(guint));
|
||||
*f = id;
|
||||
id++;
|
||||
g_hash_table_replace(events, f, closure);
|
||||
return *f;
|
||||
}
|
||||
|
||||
static PurpleEventLoopUiOps libEventLoopOps =
|
||||
{
|
||||
event_timeout_add,
|
||||
event_input_remove,
|
||||
event_input_add,
|
||||
event_input_remove,
|
||||
NULL,
|
||||
// #if GLIB_CHECK_VERSION(2,14,0)
|
||||
// g_timeout_add_seconds,
|
||||
// #else
|
||||
NULL,
|
||||
// #endif
|
||||
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
#endif /* WITH_LIBEVENT*/
|
||||
|
||||
PurpleEventLoopUiOps * getEventLoopUiOps(void){
|
||||
return &eventLoopOps;
|
||||
#ifdef WITH_LIBEVENT
|
||||
events = g_hash_table_new_full(g_int_hash, g_int_equal, g_free, NULL);
|
||||
return &libEventLoopOps;
|
||||
#endif
|
||||
}
|
33
backends/skype/geventloop.h
Normal file
33
backends/skype/geventloop.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
/**
|
||||
* XMPP - libpurple transport
|
||||
*
|
||||
* Copyright (C) 2009, Jan Kaluza <hanzz@soc.pidgin.im>
|
||||
*
|
||||
* 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 _HI_EVENTLOOP_H
|
||||
#define _HI_EVENTLOOP_H
|
||||
|
||||
#include <glib.h>
|
||||
#include "purple.h"
|
||||
#include "eventloop.h"
|
||||
|
||||
#define READ_COND (G_IO_IN | G_IO_HUP | G_IO_ERR)
|
||||
#define WRITE_COND (G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL)
|
||||
|
||||
PurpleEventLoopUiOps * getEventLoopUiOps(void);
|
||||
|
||||
#endif
|
791
backends/skype/main.cpp
Normal file
791
backends/skype/main.cpp
Normal file
|
@ -0,0 +1,791 @@
|
|||
#include "glib.h"
|
||||
#include <iostream>
|
||||
|
||||
#include "transport/config.h"
|
||||
#include "transport/transport.h"
|
||||
#include "transport/usermanager.h"
|
||||
#include "transport/logger.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 "spectrumeventloop.h"
|
||||
#include <boost/filesystem.hpp>
|
||||
#include "geventloop.h"
|
||||
#include "log4cxx/logger.h"
|
||||
#include "log4cxx/consoleappender.h"
|
||||
#include "log4cxx/patternlayout.h"
|
||||
#include "log4cxx/propertyconfigurator.h"
|
||||
#include "log4cxx/helpers/properties.h"
|
||||
#include "log4cxx/helpers/fileinputstream.h"
|
||||
#include "sys/wait.h"
|
||||
#include "sys/signal.h"
|
||||
// #include "valgrind/memcheck.h"
|
||||
#include "malloc.h"
|
||||
#include <dbus-1.0/dbus/dbus-glib-lowlevel.h>
|
||||
|
||||
|
||||
using namespace log4cxx;
|
||||
|
||||
static LoggerPtr logger = Logger::getLogger("backend");
|
||||
|
||||
using namespace Transport;
|
||||
|
||||
class SpectrumNetworkPlugin;
|
||||
|
||||
|
||||
SpectrumNetworkPlugin *np;
|
||||
|
||||
static gboolean nodaemon = FALSE;
|
||||
static gchar *logfile = NULL;
|
||||
static gchar *lock_file = NULL;
|
||||
static gchar *host = NULL;
|
||||
static int port = 10000;
|
||||
static gboolean ver = FALSE;
|
||||
static gboolean list_purple_settings = FALSE;
|
||||
|
||||
int m_sock;
|
||||
static int writeInput;
|
||||
|
||||
static GOptionEntry options_entries[] = {
|
||||
{ "nodaemon", 'n', 0, G_OPTION_ARG_NONE, &nodaemon, "Disable background daemon mode", NULL },
|
||||
{ "logfile", 'l', 0, G_OPTION_ARG_STRING, &logfile, "Set file to log", NULL },
|
||||
{ "pidfile", 'p', 0, G_OPTION_ARG_STRING, &lock_file, "File where to write transport PID", NULL },
|
||||
{ "version", 'v', 0, G_OPTION_ARG_NONE, &ver, "Shows Spectrum version", NULL },
|
||||
{ "list-purple-settings", 's', 0, G_OPTION_ARG_NONE, &list_purple_settings, "Lists purple settings which can be used in config file", NULL },
|
||||
{ "host", 'h', 0, G_OPTION_ARG_STRING, &host, "Host to connect to", NULL },
|
||||
{ "port", 'p', 0, G_OPTION_ARG_INT, &port, "Port to connect to", NULL },
|
||||
{ NULL, 0, 0, G_OPTION_ARG_NONE, NULL, "", NULL }
|
||||
};
|
||||
|
||||
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() { 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;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_username;
|
||||
std::string m_password;
|
||||
GPid m_pid;
|
||||
DBusGConnection *m_connection;
|
||||
DBusGProxy *m_proxy;
|
||||
std::string m_user;
|
||||
};
|
||||
|
||||
class SpectrumNetworkPlugin : public NetworkPlugin {
|
||||
public:
|
||||
SpectrumNetworkPlugin(Config *config, const std::string &host, int port) : NetworkPlugin() {
|
||||
this->config = config;
|
||||
}
|
||||
|
||||
~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;
|
||||
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 handleLogoutRequest(const std::string &user, const std::string &legacyName) {
|
||||
Skype *skype = m_sessions[user];
|
||||
if (skype) {
|
||||
skype->logout();
|
||||
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 handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml) {
|
||||
Skype *skype = m_sessions[user];
|
||||
if (skype) {
|
||||
skype->send_command("MESSAGE " + legacyName + " " + message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void handleVCardRequest(const std::string &user, const std::string &legacyName, unsigned int id) {
|
||||
Skype *skype = m_sessions[user];
|
||||
if (skype) {
|
||||
std::string name = legacyName;
|
||||
if (name.find("skype.") == 0) {
|
||||
name = name.substr(6);
|
||||
}
|
||||
std::string photo;
|
||||
gchar *filename = NULL;
|
||||
gchar *new_filename = NULL;
|
||||
gchar *image_data = NULL;
|
||||
gsize image_data_len = 0;
|
||||
gchar *ret;
|
||||
int fh;
|
||||
GError *error;
|
||||
const gchar *userfiles[] = {"user256", "user1024", "user4096", "user16384", "user32768", "user65536",
|
||||
"profile256", "profile1024", "profile4096", "profile16384", "profile32768",
|
||||
NULL};
|
||||
char *username = g_strdup_printf("\x03\x10%s", name.c_str());
|
||||
for (fh = 0; userfiles[fh]; fh++) {
|
||||
filename = g_strconcat("/tmp/skype/", skype->getUsername().c_str(), "/", skype->getUsername().c_str(), "/", userfiles[fh], ".dbb", NULL);
|
||||
std::cout << "getting filename:" << filename << "\n";
|
||||
if (g_file_get_contents(filename, &image_data, &image_data_len, NULL))
|
||||
{
|
||||
std::cout << "got\n";
|
||||
char *start = (char *)memmem(image_data, image_data_len, username, strlen(username)+1);
|
||||
if (start != NULL)
|
||||
{
|
||||
char *next = image_data;
|
||||
char *last = next;
|
||||
//find last index of l33l
|
||||
while ((next = (char *)memmem(next+4, start-next-4, "l33l", 4)))
|
||||
{
|
||||
last = next;
|
||||
}
|
||||
start = last;
|
||||
if (start != NULL)
|
||||
{
|
||||
char *img_start;
|
||||
//find end of l33l block
|
||||
char *end = (char *)memmem(start+4, image_data+image_data_len-start-4, "l33l", 4);
|
||||
if (!end) end = image_data+image_data_len;
|
||||
|
||||
//look for start of JPEG block
|
||||
img_start = (char *)memmem(start, end-start, "\xFF\xD8", 2);
|
||||
if (img_start)
|
||||
{
|
||||
//look for end of JPEG block
|
||||
char *img_end = (char *)memmem(img_start, end-img_start, "\xFF\xD9", 2);
|
||||
if (img_end)
|
||||
{
|
||||
image_data_len = img_end - img_start + 2;
|
||||
photo = std::string(img_start, image_data_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
g_free(image_data);
|
||||
}
|
||||
g_free(filename);
|
||||
}
|
||||
g_free(username);
|
||||
|
||||
std::string alias = "";
|
||||
std::cout << skype->getUsername() << " " << name << "\n";
|
||||
if (skype->getUsername() == name) {
|
||||
alias = skype->send_command("GET PROFILE FULLNAME");
|
||||
alias = alias.substr(17);
|
||||
}
|
||||
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 handleBuddyRemovedRequest(const std::string &user, const std::string &buddyName, const std::vector<std::string> &groups) {
|
||||
}
|
||||
|
||||
void handleBuddyUpdatedRequest(const std::string &user, const std::string &buddyName, const std::string &alias, const std::vector<std::string> &groups) {
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void Skype::login() {
|
||||
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);
|
||||
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;
|
||||
int fd_output;
|
||||
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,
|
||||
NULL /*error*/);
|
||||
std::string login_data = std::string(m_username + " " + m_password + "\n");
|
||||
LOG4CXX_INFO(logger, m_username << ": Login data=" << login_data);
|
||||
write(fd, login_data.c_str(), login_data.size());
|
||||
close(fd);
|
||||
|
||||
fcntl (fd_output, F_SETFL, O_NONBLOCK);
|
||||
|
||||
free(db);
|
||||
|
||||
sleep(2);
|
||||
|
||||
GError *error = NULL;
|
||||
DBusObjectPathVTable vtable;
|
||||
|
||||
//Initialise threading
|
||||
dbus_threads_init_default();
|
||||
|
||||
if (m_connection == NULL)
|
||||
{
|
||||
m_connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
|
||||
if (m_connection == NULL && error != NULL)
|
||||
{
|
||||
LOG4CXX_INFO(logger, m_username << ": DBUS Error: " << error->message);
|
||||
g_error_free(error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_proxy == 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);
|
||||
g_error_free(error);
|
||||
}
|
||||
|
||||
vtable.message_function = &skype_notify_handler;
|
||||
dbus_connection_register_object_path(dbus_g_connection_get_connection(m_connection), "/com/Skype/Client", &vtable, this);
|
||||
}
|
||||
|
||||
int counter = 0;
|
||||
std::string re = "CONNSTATUS OFFLINE";
|
||||
while (re == "CONNSTATUS OFFLINE" || re.empty()) {
|
||||
sleep(1);
|
||||
gchar buffer[1024];
|
||||
int bytes_read;
|
||||
bytes_read = read (fd_output, buffer, 1023);
|
||||
if (bytes_read > 0) {
|
||||
buffer[bytes_read] = 0;
|
||||
np->handleDisconnected(m_user, 0, buffer);
|
||||
close(fd_output);
|
||||
logout();
|
||||
return;
|
||||
}
|
||||
re = send_command("NAME Spectrum");
|
||||
if (counter++ > 15)
|
||||
break;
|
||||
}
|
||||
|
||||
close(fd_output);
|
||||
|
||||
if (send_command("PROTOCOL 7") != "PROTOCOL 7") {
|
||||
np->handleDisconnected(m_user, 0, "Skype is not ready");
|
||||
logout();
|
||||
return;
|
||||
}
|
||||
|
||||
np->handleConnected(m_user);
|
||||
|
||||
std::map<std::string, std::string> group_map;
|
||||
std::string groups = send_command("SEARCH GROUPS CUSTOM");
|
||||
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");
|
||||
boost::split(data, name, boost::is_any_of(" "));
|
||||
name = name.substr(name.find("DISPLAYNAME") + 12);
|
||||
|
||||
std::string users = send_command("GET GROUP " + data[1] + " USERS");
|
||||
users = name.substr(name.find("USERS") + 6);
|
||||
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] != '\0'; i+=8)
|
||||
{
|
||||
std::string buddy = full_friends_list[i];
|
||||
|
||||
if (buddy[0] == ',') {
|
||||
buddy.erase(buddy.begin());
|
||||
}
|
||||
std::cout << "BUDDY '" << buddy << "'\n";
|
||||
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];
|
||||
i++;
|
||||
}
|
||||
|
||||
std::vector<std::string> groups;
|
||||
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");
|
||||
}
|
||||
|
||||
void Skype::logout() {
|
||||
if (m_pid != 0) {
|
||||
send_command("SET USERSTATUS INVISIBLE");
|
||||
send_command("SET USERSTATUS OFFLINE");
|
||||
sleep(2);
|
||||
g_object_unref(m_proxy);
|
||||
LOG4CXX_INFO(logger, m_username << ": Killing Skype instance");
|
||||
kill((int) m_pid, SIGTERM);
|
||||
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];
|
||||
|
||||
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);
|
||||
} else {
|
||||
LOG4CXX_INFO(logger, m_username << ": DBUS no response");
|
||||
}
|
||||
|
||||
}
|
||||
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]);
|
||||
std::string mood_text = sk->send_command("GET USER " + cmd[1] + " MOOD_TEXT");
|
||||
mood_text = mood_text.substr(mood_text.find("MOOD_TEXT") + 10);
|
||||
|
||||
std::string alias = sk->send_command("GET USER " + cmd[1] + " FULLNAME");
|
||||
alias = alias.substr(alias.find("FULLNAME") + 9);
|
||||
|
||||
std::vector<std::string> groups;
|
||||
np->handleBuddyChanged(sk->getUser(), cmd[1], alias, groups, status, mood_text);
|
||||
}
|
||||
}
|
||||
else if (cmd[2] == "MOOD_TEXT") {
|
||||
std::string st = sk->send_command("GET USER " + cmd[1] + " ONLINESTATUS");
|
||||
st = st.substr(st.find("ONLINESTATUS") + 13);
|
||||
pbnetwork::StatusType status = getStatus(st);
|
||||
|
||||
std::string mood_text = message.substr(message.find("MOOD_TEXT") + 10);
|
||||
|
||||
std::vector<std::string> groups;
|
||||
np->handleBuddyChanged(sk->getUser(), cmd[1], "", groups, status, mood_text);
|
||||
}
|
||||
else if (cmd[2] == "BUDDYSTATUS" && cmd[3] == "3") {
|
||||
std::string st = sk->send_command("GET USER " + cmd[1] + " ONLINESTATUS");
|
||||
st = st.substr(st.find("ONLINESTATUS") + 13);
|
||||
pbnetwork::StatusType status = getStatus(st);
|
||||
|
||||
std::string mood_text = message.substr(message.find("MOOD_TEXT") + 10);
|
||||
|
||||
std::vector<std::string> groups;
|
||||
np->handleBuddyChanged(sk->getUser(), cmd[1], "", groups, status, mood_text);
|
||||
}
|
||||
}
|
||||
else if (cmd[0] == "CHATMESSAGE") {
|
||||
if (cmd[3] == "RECEIVED") {
|
||||
std::string body = sk->send_command("GET CHATMESSAGE " + cmd[1] + " BODY");
|
||||
body = body.substr(body.find("BODY") + 5);
|
||||
|
||||
std::string chatname = sk->send_command("GET CHATMESSAGE " + cmd[1] + " CHATNAME");
|
||||
size_t start = chatname.find("$") + 1;
|
||||
size_t len = chatname.find(";") - start;
|
||||
std::string from = chatname.substr(start, len);
|
||||
|
||||
std::string from_handle = sk->send_command("GET CHATMESSAGE " + cmd[1] + " FROM_HANDLE");
|
||||
from_handle = from_handle.substr(from_handle.find("FROM_HANDLE") + 12);
|
||||
|
||||
// if (from_handle != sk->getUsername()) {
|
||||
from = from_handle;
|
||||
// }
|
||||
if (from_handle == sk->getUsername())
|
||||
return;
|
||||
|
||||
np->handleMessage(sk->getUser(), from, body);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
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 int create_socket(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
|
||||
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");
|
||||
exit(errno);
|
||||
}
|
||||
std::string d = std::string(buffer, n);
|
||||
np->handleDataRead(d);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void io_destroy(gpointer data) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
GError *error = NULL;
|
||||
GOptionContext *context;
|
||||
context = g_option_context_new("config_file_name or profile name");
|
||||
g_option_context_add_main_entries(context, options_entries, "");
|
||||
if (!g_option_context_parse (context, &argc, &argv, &error)) {
|
||||
std::cout << "option parsing failed: " << error->message << "\n";
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ver) {
|
||||
// std::cout << VERSION << "\n";
|
||||
std::cout << "verze\n";
|
||||
g_option_context_free(context);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (argc != 2) {
|
||||
#ifdef WIN32
|
||||
std::cout << "Usage: spectrum.exe <configuration_file.cfg>\n";
|
||||
#else
|
||||
|
||||
#if GLIB_CHECK_VERSION(2,14,0)
|
||||
std::cout << g_option_context_get_help(context, FALSE, NULL);
|
||||
#else
|
||||
std::cout << "Usage: spectrum <configuration_file.cfg>\n";
|
||||
std::cout << "See \"man spectrum\" for more info.\n";
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
#ifndef WIN32
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
if (signal(SIGCHLD, spectrum_sigchld_handler) == SIG_ERR) {
|
||||
std::cout << "SIGCHLD handler can't be set\n";
|
||||
g_option_context_free(context);
|
||||
return -1;
|
||||
}
|
||||
//
|
||||
// if (signal(SIGINT, spectrum_sigint_handler) == SIG_ERR) {
|
||||
// std::cout << "SIGINT handler can't be set\n";
|
||||
// g_option_context_free(context);
|
||||
// return -1;
|
||||
// }
|
||||
//
|
||||
// if (signal(SIGTERM, spectrum_sigterm_handler) == SIG_ERR) {
|
||||
// std::cout << "SIGTERM handler can't be set\n";
|
||||
// g_option_context_free(context);
|
||||
// return -1;
|
||||
// }
|
||||
//
|
||||
// struct sigaction sa;
|
||||
// memset(&sa, 0, sizeof(sa));
|
||||
// sa.sa_handler = spectrum_sighup_handler;
|
||||
// if (sigaction(SIGHUP, &sa, NULL)) {
|
||||
// std::cout << "SIGHUP handler can't be set\n";
|
||||
// g_option_context_free(context);
|
||||
// return -1;
|
||||
// }
|
||||
#endif
|
||||
Config config;
|
||||
if (!config.load(argv[1])) {
|
||||
std::cout << "Can't open " << argv[1] << " configuration file.\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (CONFIG_STRING(&config, "logging.backend_config").empty()) {
|
||||
LoggerPtr root = log4cxx::Logger::getRootLogger();
|
||||
root->addAppender(new ConsoleAppender(new PatternLayout("%d %-5p %c: %m%n")));
|
||||
}
|
||||
else {
|
||||
log4cxx::helpers::Properties p;
|
||||
log4cxx::helpers::FileInputStream *istream = new log4cxx::helpers::FileInputStream(CONFIG_STRING(&config, "logging.backend_config"));
|
||||
|
||||
p.load(istream);
|
||||
p.setProperty("pid", boost::lexical_cast<std::string>(getpid()));
|
||||
log4cxx::PropertyConfigurator::configure(p);
|
||||
}
|
||||
|
||||
// initPurple(config);
|
||||
|
||||
g_type_init();
|
||||
|
||||
m_sock = create_socket(host, port);
|
||||
|
||||
|
||||
GIOChannel *channel;
|
||||
GIOCondition cond = (GIOCondition) READ_COND;
|
||||
channel = g_io_channel_unix_new(m_sock);
|
||||
g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, cond, transportDataReceived, NULL, io_destroy);
|
||||
|
||||
np = new SpectrumNetworkPlugin(&config, host, port);
|
||||
|
||||
GMainLoop *m_loop;
|
||||
m_loop = g_main_loop_new(NULL, FALSE);
|
||||
|
||||
if (m_loop) {
|
||||
g_main_loop_run(m_loop);
|
||||
}
|
||||
}
|
||||
|
||||
g_option_context_free(context);
|
||||
}
|
90
backends/skype/spectrumeventloop.cpp
Normal file
90
backends/skype/spectrumeventloop.cpp
Normal file
|
@ -0,0 +1,90 @@
|
|||
/**
|
||||
* XMPP - libpurple transport
|
||||
*
|
||||
* Copyright (C) 2009, Jan Kaluza <hanzz@soc.pidgin.im>
|
||||
*
|
||||
* 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 "spectrumeventloop.h"
|
||||
#include "glib.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#ifdef WITH_LIBEVENT
|
||||
#include <event.h>
|
||||
#endif
|
||||
|
||||
|
||||
using namespace Swift;
|
||||
|
||||
// Fires the event's callback and frees the event
|
||||
static gboolean processEvent(void *data) {
|
||||
Event *ev = (Event *) data;
|
||||
ev->callback();
|
||||
delete ev;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
SpectrumEventLoop::SpectrumEventLoop() : m_isRunning(false) {
|
||||
m_loop = NULL;
|
||||
if (true) {
|
||||
m_loop = g_main_loop_new(NULL, FALSE);
|
||||
}
|
||||
#ifdef WITH_LIBEVENT
|
||||
else {
|
||||
/*struct event_base *base = (struct event_base *)*/
|
||||
event_init();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
SpectrumEventLoop::~SpectrumEventLoop() {
|
||||
stop();
|
||||
}
|
||||
|
||||
void SpectrumEventLoop::run() {
|
||||
m_isRunning = true;
|
||||
if (m_loop) {
|
||||
g_main_loop_run(m_loop);
|
||||
}
|
||||
#ifdef WITH_LIBEVENT
|
||||
else {
|
||||
event_loop(0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void SpectrumEventLoop::stop() {
|
||||
std::cout << "stopped loop\n";
|
||||
if (!m_isRunning)
|
||||
return;
|
||||
if (m_loop) {
|
||||
g_main_loop_quit(m_loop);
|
||||
g_main_loop_unref(m_loop);
|
||||
m_loop = NULL;
|
||||
}
|
||||
#ifdef WITH_LIBEVENT
|
||||
else {
|
||||
event_loopexit(NULL);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void SpectrumEventLoop::post(const Event& event) {
|
||||
// pass copy of event to main thread
|
||||
Event *ev = new Event(event.owner, event.callback);
|
||||
g_timeout_add(0, processEvent, ev);
|
||||
}
|
49
backends/skype/spectrumeventloop.h
Normal file
49
backends/skype/spectrumeventloop.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
/**
|
||||
* XMPP - libpurple transport
|
||||
*
|
||||
* Copyright (C) 2009, Jan Kaluza <hanzz@soc.pidgin.im>
|
||||
*
|
||||
* 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 SPECTRUM_EVENT_LOOP_H
|
||||
#define SPECTRUM_EVENT_LOOP_H
|
||||
|
||||
#include <vector>
|
||||
#include "Swiften/EventLoop/EventLoop.h"
|
||||
#include "glib.h"
|
||||
|
||||
// Event loop implementation for Spectrum
|
||||
class SpectrumEventLoop : public Swift::EventLoop {
|
||||
public:
|
||||
// Creates event loop according to CONFIG().eventloop settings.
|
||||
SpectrumEventLoop();
|
||||
~SpectrumEventLoop();
|
||||
|
||||
// Executes the eventloop.
|
||||
void run();
|
||||
|
||||
// Stops tht eventloop.
|
||||
void stop();
|
||||
|
||||
// Posts new Swift::Event to main thread.
|
||||
virtual void post(const Swift::Event& event);
|
||||
|
||||
private:
|
||||
bool m_isRunning;
|
||||
GMainLoop *m_loop;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -40,6 +40,8 @@ users_per_backend=10
|
|||
# Full path to backend binary.
|
||||
backend=/usr/bin/spectrum2_libpurple_backend
|
||||
#backend=/usr/bin/spectrum2_libircclient-qt_backend
|
||||
# For skype:
|
||||
#backend=/usr/bin/setsid /usr/bin/xvfb-run -n BACKEND_ID -s "-screen 0 10x10x8" -f /tmp/x-skype-gw /usr/bin/spectrum2_skype_backend
|
||||
|
||||
# Libpurple protocol-id for spectrum_libpurple_backend
|
||||
protocol=prpl-jabber
|
||||
|
|
Loading…
Add table
Reference in a new issue