From 255cc8416c6bd55c9d5acd16827529865789d460 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Wed, 6 Feb 2013 22:15:35 +0100 Subject: [PATCH] Revert "fix autoregistration" This reverts commit 393cf1cc03032c5938bcc57d54659b6aeb415aa3. --- backends/skype/main.cpp | 547 ++++++++++++++++++++++++++++++- include/transport/protocol.proto | 4 - src/usermanager.cpp | 4 +- 3 files changed, 536 insertions(+), 19 deletions(-) diff --git a/backends/skype/main.cpp b/backends/skype/main.cpp index 17c5ac6f..5d603d36 100644 --- a/backends/skype/main.cpp +++ b/backends/skype/main.cpp @@ -1,6 +1,4 @@ #include "glib.h" -#include -#include "sqlite3.h" #include #include "transport/config.h" @@ -22,15 +20,16 @@ #ifndef __FreeBSD__ #include "malloc.h" #endif +#include -#include "skype.h" +#include "sqlite3.h" DEFINE_LOGGER(logger, "backend"); using namespace Transport; -class SkypePlugin; +class SpectrumNetworkPlugin; #define GET_RESPONSE_DATA(RESP, DATA) ((RESP.find(std::string(DATA) + " ") != std::string::npos) ? RESP.substr(RESP.find(DATA) + strlen(DATA) + 1) : ""); #define GET_PROPERTY(VAR, OBJ, WHICH, PROP) std::string VAR = sk->send_command(std::string("GET ") + OBJ + " " + WHICH + " " + PROP); \ @@ -71,7 +70,7 @@ class SkypePlugin; LOG4CXX_ERROR(logger, NAME<< (sqlite3_errmsg(db) == NULL ? "" : sqlite3_errmsg(db)));\ } -SkypePlugin *np; +SpectrumNetworkPlugin *np; int m_sock; static int writeInput; @@ -98,14 +97,50 @@ static pbnetwork::StatusType getStatus(const std::string &st) { return status; } -class SkypePlugin : public NetworkPlugin { +class Skype { public: - SkypePlugin(Config *config, const std::string &host, int port) : NetworkPlugin() { + 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 m_groups; +}; + +class SpectrumNetworkPlugin : public NetworkPlugin { + public: + SpectrumNetworkPlugin(Config *config, const std::string &host, int port) : NetworkPlugin() { this->config = config; LOG4CXX_INFO(logger, "Starting the backend."); } - ~SkypePlugin() { + ~SpectrumNetworkPlugin() { for (std::map::iterator it = m_accounts.begin(); it != m_accounts.end(); it++) { delete (*it).first; } @@ -118,7 +153,7 @@ class SkypePlugin : public NetworkPlugin { } LOG4CXX_INFO(logger, "Creating account with name '" << name << "'"); - Skype *skype = new Skype(this, user, name, password); + Skype *skype = new Skype(user, name, password); m_sessions[user] = skype; m_accounts[skype] = user; @@ -356,6 +391,495 @@ class SkypePlugin : public NetworkPlugin { }; +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 = "\n" + "(time(NULL)) + ".0\">\n" + "\n" + "2\n" + "en\n" + "\n" + "\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 = "\n" + "(time(NULL)) + ".0\">\n" + "\n" + "\n" + "30000000\n" + "300000000\n" + "" + boost::lexical_cast(time(NULL)) + "\n" + "\n" + "\n" + "\n" + "\n" + "Spectrum\n" + "\n" + "\n" + "\n" + "\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 group_map; + std::string groups = send_command("SEARCH GROUPS CUSTOM"); + if (groups.find(' ') != std::string::npos) { + groups = groups.substr(groups.find(' ') + 1); + std::vector grps; + boost::split(grps, groups, boost::is_any_of(",")); + BOOST_FOREACH(std::string grp, grps) { + std::vector 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 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 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 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 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 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 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 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 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 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 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; @@ -444,7 +968,6 @@ int main(int argc, char **argv) { Logging::initBackendLogging(cfg); g_type_init(); - m_sock = create_socket(host.c_str(), port); @@ -455,9 +978,7 @@ int main(int argc, char **argv) { channel = g_io_channel_unix_new(m_sock); g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, cond, transportDataReceived, NULL, io_destroy); - dbus_threads_init_default(); - - np = new SkypePlugin(cfg, host, port); + np = new SpectrumNetworkPlugin(cfg, host, port); GMainLoop *m_loop; m_loop = g_main_loop_new(NULL, FALSE); diff --git a/include/transport/protocol.proto b/include/transport/protocol.proto index 4e47ea6a..796b656c 100644 --- a/include/transport/protocol.proto +++ b/include/transport/protocol.proto @@ -95,10 +95,6 @@ enum ParticipantFlag { 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 { diff --git a/src/usermanager.cpp b/src/usermanager.cpp index 2d9a5fbf..4a36eebf 100644 --- a/src/usermanager.cpp +++ b/src/usermanager.cpp @@ -252,8 +252,8 @@ void UserManager::handlePresence(Swift::Presence::ref presence) { // We allow auto_register feature in gateway-mode. This allows IRC user to register // the transport just by joining the room. if (!m_component->inServerMode()) { - if (!registered && (CONFIG_BOOL(m_component->getConfig(), "registration.auto_register") - /*!CONFIG_BOOL_DEFAULTED(m_component->getConfig(), "registration.needRegistration", true)*/)) { + if (!registered && (CONFIG_BOOL(m_component->getConfig(), "registration.auto_register") || + !CONFIG_BOOL_DEFAULTED(m_component->getConfig(), "registration.needRegistration", true))) { res.password = ""; res.jid = userkey;