Changeset - 79673211dd9c
[Not reviewed]
Merge
0 12 0
Vitaly Takmazov - 12 years ago 2013-02-06 21:55:48
vitalyster@gmail.com
Merge branch 'master' of https://github.com/hanzz/libtransport
11 files changed with 92 insertions and 558 deletions:
0 comments (0 inline, 0 general)
CMakeLists.txt
Show inline comments
 
@@ -106,13 +106,13 @@ if (NOT WIN32)
 
endif()
 

	
 
###### Database ######
 

	
 
# FIND SQLITE3
 
if (ENABLE_SQLITE3)
 
	if (NOT CMAKE_COMPILER_IS_GNUCXX)
 
	if (MSVC)
 
		ADD_SUBDIRECTORY(${CMAKE_SOURCE_DIR}/msvc-deps)
 
	else()
 
		if (WIN32)
 
			ADD_SUBDIRECTORY(${CMAKE_SOURCE_DIR}/msvc-deps/sqlite3)
 
		else()
 
			set(sqlite3_DIR "${CMAKE_SOURCE_DIR}/cmake_modules")
 
@@ -245,12 +245,22 @@ if(ENABLE_TESTS)
 
		set(CCPUNIT_LIBRARIES ${CPPUNIT_LIBRARY})
 
		set(CPPUNIT_FOUND 1)
 
		message(STATUS "Using cppunit: ${CPPUNIT_INCLUDE_DIR} ${CPPUNIT_LIBRARIES}")
 
	endif()
 
endif()
 

	
 
if (APPLE)
 
        FIND_LIBRARY(IOKIT_FRAMEWORK IOKit)
 
        FIND_LIBRARY(SECURITY_FRAMEWORK Security)
 
        FIND_LIBRARY(APPKIT_FRAMEWORK AppKit)
 
        FIND_LIBRARY(SYSTEMCONFIGURATION_FRAMEWORK SystemConfiguration)
 
        FIND_LIBRARY(SECURITYINTERFACE_FRAMEWORK SecurityInterface)
 
        MARK_AS_ADVANCED(IOKIT_FRAMEWORK APPKIT_FRAMEWORK SYSTEMCONFIGURATION_FRAMEWORK SECURITY_FRAMEWORK SECURITYINTERFACE_FRAMEWORK)
 
        SET (APPLE_FRAMEWORKS ${IOKIT_FRAMEWORK} ${APPKIT_FRAMEWORK} ${SYSTEMCONFIGURATION_FRAMEWORK} ${SECURITY_FRAMEWORK} ${SECURITYINTERFACE_FRAMEWORK})
 
endif()
 

	
 
message("  Supported features")
 
message("-----------------------")
 

	
 
if (SPECTRUM_VERSION)
 
	ADD_DEFINITIONS(-DSPECTRUM_VERSION="${SPECTRUM_VERSION}")
 
else (SPECTRUM_VERSION)
backends/skype/main.cpp
Show inline comments
 
#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"
 
@@ -17,22 +19,21 @@
 
#include "sys/wait.h"
 
#include "sys/signal.h"
 
// #include "valgrind/memcheck.h"
 
#ifndef __FreeBSD__
 
#include "malloc.h"
 
#endif
 
#include <dbus-1.0/dbus/dbus-glib-lowlevel.h>
 

	
 
#include "sqlite3.h"
 
#include "skype.h"
 

	
 

	
 
DEFINE_LOGGER(logger, "backend");
 

	
 
using namespace Transport;
 

	
 
class SpectrumNetworkPlugin;
 
class SkypePlugin;
 

	
 
#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);\
 
					}\
 
@@ -67,13 +68,13 @@ class SpectrumNetworkPlugin;
 
#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;
 
SkypePlugin *np;
 

	
 
int m_sock;
 
static int writeInput;
 

	
 
static std::string host;
 
static int port = 10000;
 
@@ -94,69 +95,33 @@ static pbnetwork::StatusType getStatus(const std::string &st) {
 
	else if (st == "AWAY") {
 
		status = pbnetwork::STATUS_AWAY;
 
	}
 
	return status;
 
}
 

	
 
class Skype {
 
class SkypePlugin : public NetworkPlugin {
 
	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() {
 
		SkypePlugin(Config *config, const std::string &host, int port) : NetworkPlugin() {
 
			this->config = config;
 
			LOG4CXX_INFO(logger, "Starting the backend.");
 
		}
 

	
 
		~SpectrumNetworkPlugin() {
 
		~SkypePlugin() {
 
			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);
 
			Skype *skype = new Skype(this, user, name, password);
 
			m_sessions[user] = skype;
 
			m_accounts[skype] = user;
 

	
 
			skype->login();
 
		}
 

	
 
@@ -388,501 +353,12 @@ class SpectrumNetworkPlugin : public NetworkPlugin {
 
		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;
 
	pid_t pid;
 

	
 
	do {
 
@@ -965,23 +441,26 @@ int main(int argc, char **argv) {
 
		return 1;
 
	}
 

	
 
	Logging::initBackendLogging(cfg);
 

	
 
	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);
 

	
 
	np = new SpectrumNetworkPlugin(cfg, host, port);
 
	dbus_threads_init_default();
 

	
 
	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);
backends/swiften/main.cpp
Show inline comments
 
@@ -14,15 +14,17 @@
 
#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;
 
@@ -186,15 +188,17 @@ class SwiftenPlugin : public NetworkPlugin {
 
				m_users.erase(user);
 
				m_mucs.erase(user);
 
			}
 

	
 
#ifndef WIN32
 
#ifndef __FreeBSD__
 
#ifndef __MACH__
 
			// force returning of memory chunks allocated by libxml2 to kernel
 
			malloc_trim(0);
 
#endif
 
#endif
 
#endif
 
		}
 

	
 
		void handleSwiftConnected(const std::string &user) {
 
			LOG4CXX_INFO(logger, user << ": Connected to XMPP server.");
 
			handleConnected(user);
 
@@ -217,12 +221,16 @@ class SwiftenPlugin : public NetworkPlugin {
 
		void handleSwiftPresenceChanged(const std::string &user, Swift::Presence::ref presence) {
 
			boost::shared_ptr<Swift::Client> client = m_users[user];
 
			if (client->getMUCRegistry()->isMUC(presence->getFrom().toBare())) {
 
				return;
 
			}
 

	
 
			if (presence->getPayload<Swift::MUCUserPayload>() != NULL || presence->getPayload<Swift::MUCPayload>() != NULL) {
 
				return;
 
			}
 

	
 
			LOG4CXX_INFO(logger, user << ": " << presence->getFrom().toBare().toString() << " presence changed");
 

	
 
			std::string message = presence->getStatus();
 
			std::string photo = "";
 

	
 
			boost::shared_ptr<Swift::VCardUpdate> update = presence->getPayload<Swift::VCardUpdate>();
 
@@ -296,13 +304,12 @@ class SwiftenPlugin : public NetworkPlugin {
 
// 				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();
 
				m_mucs.erase(user);
 
				m_users.erase(user);
 
			}
 
		}
 

	
 
		void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &msg, const std::string &xhtml = "", const std::string &id = "") {
 
			LOG4CXX_INFO(logger, "Sending message from " << user << " to " << legacyName << ".");
 
			boost::shared_ptr<Swift::Client> client = m_users[user];
 
@@ -311,13 +318,13 @@ class SwiftenPlugin : public NetworkPlugin {
 
				message->setTo(Swift::JID(legacyName));
 
				message->setFrom(client->getJID());
 
				message->setBody(msg);
 
				if (client->getMUCRegistry()->isMUC(legacyName)) {
 
					message->setType(Swift::Message::Groupchat);
 
					boost::shared_ptr<MUCController> muc = m_mucs[user][legacyName];
 
					handleMessage(user, legacyName, msg, muc->getNickname(), xhtml);
 
// 					handleMessage(user, legacyName, msg, muc->getNickname(), xhtml);
 
				}
 

	
 
				client->sendMessage(message);
 
			}
 
		}
 

	
include/transport/memoryusage.h
Show inline comments
 
@@ -21,15 +21,13 @@
 
#pragma once
 

	
 
#include <vector>
 

	
 
#ifndef WIN32
 
#include "signal.h"
 
#else 
 
#define pid_t void*
 
#endif
 

	
 
namespace Transport {
 

	
 
#ifndef WIN32
 
	void process_mem_usage(double& shared, double& resident_set, pid_t pid = 0);
 
#endif
 

	
 
}
include/transport/protocol.proto
Show inline comments
 
@@ -92,12 +92,16 @@ enum ParticipantFlag {
 
	PARTICIPANT_FLAG_MODERATOR = 1;
 
	PARTICIPANT_FLAG_CONFLICT = 2;
 
	PARTICIPANT_FLAG_BANNED = 4;
 
	PARTICIPANT_FLAG_NOT_AUTHORIZED = 8;
 
	PARTICIPANT_FLAG_ME = 16;
 
	PARTICIPANT_FLAG_KICKED = 32;
 
	PARTICIPANT_FLAG_VISITOR = 64;
 
	PARTICIPANT_FLAG_MEMBER = 128;
 
	PARTICIPANT_FLAG_ADMIN = 256;
 
	PARTICIPANT_FLAG_OWNER = 512;
 
}
 

	
 
message Participant {
 
	required string userName = 1;
 
	required string room = 2;
 
	required string nickname = 3;
spectrum/src/main.cpp
Show inline comments
 
@@ -25,14 +25,16 @@
 
#include "sys/stat.h"
 
#include <pwd.h>
 
#include <grp.h>
 
#include <sys/resource.h>
 
#include "libgen.h"
 
#ifndef __FreeBSD__
 
#ifndef __MACH__
 
#include <malloc.h>
 
#endif
 
#endif
 
#else
 
#include <process.h>
 
#define getpid _getpid
 
#include "win32/ServiceWrapper.h"
 
#endif
 
#include <sys/stat.h>
 
@@ -305,16 +307,18 @@ int main(int argc, char **argv)
 
	GetModuleFileNameA(NULL, szFilePath, sizeof(szFilePath));
 
	std::string exe_file(szFilePath);					
 
#endif	
 
	setlocale(LC_ALL, "");
 
#ifndef WIN32
 
#ifndef __FreeBSD__
 
#ifndef __MACH__
 
	mallopt(M_CHECK_ACTION, 2);
 
	mallopt(M_PERTURB, 0xb);
 
#endif
 
#endif
 
#endif
 

	
 
#ifndef WIN32
 
	if (signal(SIGINT, spectrum_sigint_handler) == SIG_ERR) {
 
		std::cout << "SIGINT handler can't be set\n";
 
		return -1;
 
	}
spectrum_manager/src/CMakeLists.txt
Show inline comments
 
@@ -4,13 +4,16 @@ FILE(GLOB SRC *.cpp *.c)
 
ADD_EXECUTABLE(spectrum2_manager ${SRC} ../../src/config.cpp ../../src/util.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../include/transport/protocol.pb.cc)
 

	
 
ADD_DEPENDENCIES(spectrum2_manager pb)
 
SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_SOURCE_DIR}/../../include/transport/protocol.pb.cc PROPERTIES GENERATED 1)
 

	
 
target_link_libraries(spectrum2_manager ${SWIFTEN_LIBRARY} ${PROTOBUF_LIBRARIES})
 
 

	
 
if(APPLE)
 
target_link_libraries(spectrum2_manager ${APPLE_FRAMEWORKS})
 
endif()
 
INSTALL(TARGETS spectrum2_manager RUNTIME DESTINATION bin)
 
 
INSTALL(FILES
 
	spectrum_manager.cfg
 
	DESTINATION /etc/spectrum2
 
	)
src/CMakeLists.txt
Show inline comments
 
cmake_minimum_required(VERSION 2.6)
 
FILE(GLOB SRC *.cpp *.h)
 
FILE(GLOB_RECURSE SWIFTEN_SRC ../include/Swiften/*.cpp)
 

	
 
# Build without openssl on msvc
 
if (CMAKE_COMPILER_IS_GNUCXX)
 
if (NOT MSVC)
 
	string(REGEX REPLACE "[^;]+;?/Schannel/[^;]+;?" "" SWIFTEN_SRC "${SWIFTEN_SRC}") 
 
else()
 
	string(REGEX REPLACE "[^;]+;?/OpenSSL/[^;]+;?" "" SWIFTEN_SRC "${SWIFTEN_SRC}") 
 
endif()
 

	
 
FILE(GLOB HEADERS ../include/transport/*.h)
 
@@ -44,19 +44,22 @@ endif(PROTOBUF_FOUND)
 
		ADD_DEFINITIONS(-fPIC)
 
	endif()
 
# endif()
 

	
 
if (WIN32)
 
	include_directories("${CMAKE_SOURCE_DIR}/msvc-deps/sqlite3")
 
	TARGET_LINK_LIBRARIES(transport transport-plugin sqlite3 ${PQXX_LIBRARY} ${PQ_LIBRARY} ${MYSQL_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES} ${PROTOBUF_LIBRARY})
 
	TARGET_LINK_LIBRARIES(transport transport-plugin sqlite3 ${PQXX_LIBRARY} ${PQ_LIBRARY} ${MYSQL_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES} ${PROTOBUF_LIBRARY} psapi.lib)
 
else()
 
	TARGET_LINK_LIBRARIES(transport transport-plugin ${PQXX_LIBRARY} ${PQ_LIBRARY} ${SQLITE3_LIBRARIES} ${MYSQL_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES} ${POPT_LIBRARY} ${PROTOBUF_LIBRARY})
 
endif()
 

	
 
SET_TARGET_PROPERTIES(transport PROPERTIES
 
      VERSION ${TRANSPORT_VERSION} SOVERSION ${TRANSPORT_VERSION}
 
)
 
if (APPLE)
 
	TARGET_LINK_LIBRARIES(transport ${APPLE_FRAMEWORKS})
 
endif()
 

	
 
INSTALL(TARGETS transport LIBRARY DESTINATION ${LIB_INSTALL_DIR} ARCHIVE DESTINATION ${LIB_INSTALL_DIR} COMPONENT libraries)
 

	
 
#CONFIGURE_FILE(transport.pc.in "${CMAKE_CURRENT_BINARY_DIR}/transport.pc")
 
#INSTALL(FILES "${CMAKE_CURRENT_BINARY_DIR}/transport.pc" DESTINATION lib/pkgconfig)
src/admininterface.cpp
Show inline comments
 
@@ -133,43 +133,35 @@ void AdminInterface::handleQuery(Swift::Message::ref message) {
 
		int backends = m_server->getBackendCount();
 
		message->setBody(boost::lexical_cast<std::string>(backends));
 
	}
 
	else if (message->getBody() == "res_memory") {
 
		double shared = 0;
 
		double rss = 0;
 
#ifndef WIN32
 
		process_mem_usage(shared, rss);
 
#endif
 

	
 
		const std::list <NetworkPluginServer::Backend *> &backends = m_server->getBackends();
 
		BOOST_FOREACH(NetworkPluginServer::Backend * backend, backends) {
 
			rss += backend->res;
 
		}
 

	
 
		message->setBody(boost::lexical_cast<std::string>(rss));
 
	}
 
	else if (message->getBody() == "shr_memory") {
 
		double shared = 0;
 
		double rss = 0;
 
#ifndef WIN32
 
		process_mem_usage(shared, rss);
 
#endif
 

	
 
		const std::list <NetworkPluginServer::Backend *> &backends = m_server->getBackends();
 
		BOOST_FOREACH(NetworkPluginServer::Backend * backend, backends) {
 
			shared += backend->shared;
 
		}
 

	
 
		message->setBody(boost::lexical_cast<std::string>(shared));
 
	}
 
	else if (message->getBody() == "used_memory") {
 
		double shared = 0;
 
		double rss = 0;
 
#ifndef WIN32
 
		process_mem_usage(shared, rss);
 
#endif
 
		rss -= shared;
 

	
 
		const std::list <NetworkPluginServer::Backend *> &backends = m_server->getBackends();
 
		BOOST_FOREACH(NetworkPluginServer::Backend * backend, backends) {
 
			rss += backend->res - backend->shared;
 
		}
src/memoryusage.cpp
Show inline comments
 
@@ -25,26 +25,47 @@
 
#include <sstream>
 
#include <fstream>
 
#include <algorithm>
 
#include <boost/lexical_cast.hpp>
 
#ifndef WIN32
 
#include <sys/param.h>
 
#else 
 
#include <windows.h>
 
#include <psapi.h>
 
#endif
 
#ifdef BSD
 
#ifdef __MACH__
 
#include <mach/mach.h>
 
#elif BSD
 
#include <sys/types.h>
 
#include <sys/sysctl.h>
 
#include <sys/param.h>
 
#include <sys/sysctl.h>
 
#include <sys/user.h>
 

	
 
#endif
 

	
 
namespace Transport {
 

	
 
#ifndef WIN32
 
#ifdef BSD
 
#ifdef __MACH__
 

	
 
void process_mem_usage(double& vm_usage, double& resident_set, pid_t pid) {
 

	
 
	struct task_basic_info t_info;
 
	mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;
 

	
 
	if (KERN_SUCCESS != task_info(mach_task_self(),
 
                              TASK_BASIC_INFO, (task_info_t)&t_info, 
 
                              &t_info_count)) {
 
		vm_usage = 0;
 
		resident_set = 0;
 
    		return;
 
	}
 
	vm_usage = t_info.virtual_size;
 
	resident_set = t_info.resident_size;
 
}
 
#elif BSD
 
void process_mem_usage(double& vm_usage, double& resident_set, pid_t pid) {
 
	int mib[4];
 
	size_t size;
 
	mib[0] = CTL_KERN;
 
	mib[1] = KERN_PROC;
 
	mib[2] = KERN_PROC_PID;
 
@@ -117,9 +138,18 @@ void process_mem_usage(double& shared, double& resident_set, pid_t pid) {
 

	
 
	long page_size_kb = sysconf(_SC_PAGE_SIZE) / 1024; // in case x86-64 is configured to use 2MB pages
 
	shared     = shared_ * page_size_kb;
 
	resident_set = rss * page_size_kb;
 
}
 
#endif /* else BSD */
 
#else
 
#define PSAPI_VERSION 1
 
#define pid_t void*
 
	void process_mem_usage(double& shared, double& resident_set, pid_t pid) {
 
		PROCESS_MEMORY_COUNTERS_EX pmc;
 
		GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc));
 
		shared =  (double)pmc.PrivateUsage;
 
		resident_set = (double)pmc.WorkingSetSize;
 
	}
 
#endif /* WIN32 */
 

	
 
}
src/usermanager.cpp
Show inline comments
 
@@ -30,15 +30,17 @@
 
#include "storageresponder.h"
 

	
 
#include "Swiften/Server/ServerStanzaChannel.h"
 
#include "Swiften/Elements/StreamError.h"
 
#include "Swiften/Elements/MUCPayload.h"
 
#include "Swiften/Elements/ChatState.h"
 
#ifndef __FreeBSD__
 
#ifndef __FreeBSD__ 
 
#ifndef __MACH__
 
#include "malloc.h"
 
#endif
 
#endif
 
// #include "valgrind/memcheck.h"
 

	
 
namespace Transport {
 

	
 
DEFINE_LOGGER(logger, "UserManager");
 

	
 
@@ -127,15 +129,17 @@ void UserManager::removeUser(User *user, bool onUserBehalf) {
 
	}
 

	
 
	onUserDestroyed(user);
 
	delete user;
 
#ifndef WIN32
 
#ifndef __FreeBSD__
 
#ifndef __MACH__
 
	malloc_trim(0);
 
#endif
 
#endif
 
#endif
 
// 	VALGRIND_DO_LEAK_CHECK;
 
}
 

	
 
void UserManager::removeAllUsers(bool onUserBehalf) {
 
	while(m_users.begin() != m_users.end()) {
 
		removeUser((*m_users.begin()).second, onUserBehalf);
 
@@ -245,14 +249,14 @@ void UserManager::handlePresence(Swift::Presence::ref presence) {
 
			res.password = m_userRegistry->getUserPassword(userkey);
 
		}
 

	
 
		// We allow auto_register feature in gateway-mode. This allows IRC user to register
 
		// the transport just by joining the room.
 
		if (!m_component->inServerMode()) {
 
			if (!registered && (CONFIG_BOOL(m_component->getConfig(), "registration.auto_register") ||
 
				!CONFIG_BOOL_DEFAULTED(m_component->getConfig(), "registration.needRegistration", true))) {
 
			if (!registered && (CONFIG_BOOL(m_component->getConfig(), "registration.auto_register")
 
				/*!CONFIG_BOOL_DEFAULTED(m_component->getConfig(), "registration.needRegistration", true)*/)) {
 
				res.password = "";
 
				res.jid = userkey;
 

	
 
				bool isMUC = presence->getPayload<Swift::MUCPayload>() != NULL || *presence->getTo().getNode().c_str() == '#';
 
				if (isMUC) {
 
					res.uin = presence->getTo().getResource();
0 comments (0 inline, 0 general)