diff --git a/CMakeLists.txt b/CMakeLists.txt index ff164dfa..a90840c2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,11 +9,19 @@ find_package(cppunit) set(sqlite3_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") find_package(sqlite3) +set(purple_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") +find_package(purple REQUIRED) + +set(glib_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") +find_package(glib REQUIRED) + +set(event_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") +find_package(event) + find_package(Doxygen) message("Supported features") message("------------------") - if (SQLITE3_FOUND) ADD_DEFINITIONS(-DWITH_SQLITE) include_directories(SQLITE3_INCLUDE_DIR) @@ -47,9 +55,14 @@ SET(TRANSPORT_VERSION 2.0) SET(PROJECT_VERSION 2.0) include_directories(include) +include_directories(${PURPLE_INCLUDE_DIR}) +include_directories(${EVENT_INCLUDE_DIRS}) +include_directories(${GLIB2_INCLUDE_DIR}) + ADD_SUBDIRECTORY(src) ADD_SUBDIRECTORY(include) ADD_SUBDIRECTORY(examples) +ADD_SUBDIRECTORY(spectrum) if(DOXYGEN_FOUND) message("Docs : yes") diff --git a/spectrum/CMakeLists.txt b/spectrum/CMakeLists.txt new file mode 100644 index 00000000..4b7537b5 --- /dev/null +++ b/spectrum/CMakeLists.txt @@ -0,0 +1 @@ +ADD_SUBDIRECTORY(src) diff --git a/spectrum/src/CMakeLists.txt b/spectrum/src/CMakeLists.txt new file mode 100644 index 00000000..4d267d79 --- /dev/null +++ b/spectrum/src/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 2.6) +FILE(GLOB SRC *.cpp) + +ADD_EXECUTABLE(spectrum ${SRC}) + +target_link_libraries(spectrum ${PURPLE_LIBRARY} ${GLIB2_LIBRARIES} ${EVENT_LIBRARIES} transport) + diff --git a/spectrum/src/geventloop.cpp b/spectrum/src/geventloop.cpp new file mode 100644 index 00000000..d1ceb445 --- /dev/null +++ b/spectrum/src/geventloop.cpp @@ -0,0 +1,249 @@ +/** + * XMPP - libpurple transport + * + * Copyright (C) 2009, Jan Kaluza + * + * 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 + std::cout << "EPOLL\n"; + events = g_hash_table_new_full(g_int_hash, g_int_equal, g_free, NULL); + return &libEventLoopOps; +#endif +} diff --git a/spectrum/src/geventloop.h b/spectrum/src/geventloop.h new file mode 100644 index 00000000..3febd65e --- /dev/null +++ b/spectrum/src/geventloop.h @@ -0,0 +1,33 @@ +/** + * XMPP - libpurple transport + * + * Copyright (C) 2009, Jan Kaluza + * + * 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 +#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 diff --git a/spectrum/src/main.cpp b/spectrum/src/main.cpp new file mode 100644 index 00000000..aff0d4fe --- /dev/null +++ b/spectrum/src/main.cpp @@ -0,0 +1,201 @@ +#include "glib.h" +#include "purple.h" +#include + +#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 "spectrumeventloop.h" +#include "geventloop.h" + + + +using namespace Transport; + +static gboolean nodaemon = FALSE; +static gchar *logfile = NULL; +static gchar *lock_file = NULL; +static gboolean ver = FALSE; +static gboolean upgrade_db = FALSE; +static gboolean check_db_version = FALSE; +static gboolean list_purple_settings = FALSE; + +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 }, + { "upgrade-db", 'u', 0, G_OPTION_ARG_NONE, &upgrade_db, "Upgrades Spectrum database", NULL }, + { "check-db-GlooxMessageHandler::version", 'c', 0, G_OPTION_ARG_NONE, &check_db_version, "Checks Spectrum database version", NULL }, + { NULL, 0, 0, G_OPTION_ARG_NONE, NULL, "", NULL } +}; + +static void transport_core_ui_init(void) +{ +// purple_blist_set_ui_ops(&blistUiOps); +// purple_accounts_set_ui_ops(&accountUiOps); +// purple_notify_set_ui_ops(¬ifyUiOps); +// purple_request_set_ui_ops(&requestUiOps); +// purple_xfers_set_ui_ops(getXferUiOps()); +// purple_connections_set_ui_ops(&conn_ui_ops); +// purple_conversations_set_ui_ops(&conversation_ui_ops); +// #ifndef WIN32 +// purple_dnsquery_set_ui_ops(getDNSUiOps()); +// #endif +} + +static PurpleCoreUiOps coreUiOps = +{ + NULL, +// debug_init, + NULL, + transport_core_ui_init, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +static bool initPurple(Config &cfg) { + bool ret; + + purple_util_set_user_dir("./"); + +// if (m_configuration.logAreas & LOG_AREA_PURPLE) +// purple_debug_set_ui_ops(&debugUiOps); + + purple_core_set_ui_ops(&coreUiOps); + purple_eventloop_set_ui_ops(getEventLoopUiOps()); + + ret = purple_core_init("spectrum"); + if (ret) { + static int conversation_handle; + static int conn_handle; + static int blist_handle; + + purple_set_blist(purple_blist_new()); + purple_blist_load(); + + purple_prefs_load(); + + /* Good default preferences */ + /* The combination of these two settings mean that libpurple will never + * (of its own accord) set all the user accounts idle. + */ + purple_prefs_set_bool("/purple/away/away_when_idle", false); + /* + * This must be set to something not "none" for idle reporting to work + * for, e.g., the OSCAR prpl. We don't implement the UI ops, so this is + * okay for now. + */ + purple_prefs_set_string("/purple/away/idle_reporting", "system"); + + /* Disable all logging */ + purple_prefs_set_bool("/purple/logging/log_ims", false); + purple_prefs_set_bool("/purple/logging/log_chats", false); + purple_prefs_set_bool("/purple/logging/log_system", false); + + +// purple_signal_connect(purple_conversations_get_handle(), "received-im-msg", &conversation_handle, PURPLE_CALLBACK(newMessageReceived), NULL); +// purple_signal_connect(purple_conversations_get_handle(), "buddy-typing", &conversation_handle, PURPLE_CALLBACK(buddyTyping), NULL); +// purple_signal_connect(purple_conversations_get_handle(), "buddy-typed", &conversation_handle, PURPLE_CALLBACK(buddyTyped), NULL); +// purple_signal_connect(purple_conversations_get_handle(), "buddy-typing-stopped", &conversation_handle, PURPLE_CALLBACK(buddyTypingStopped), NULL); +// purple_signal_connect(purple_connections_get_handle(), "signed-on", &conn_handle,PURPLE_CALLBACK(signed_on), NULL); +// purple_signal_connect(purple_blist_get_handle(), "buddy-removed", &blist_handle,PURPLE_CALLBACK(buddyRemoved), NULL); +// purple_signal_connect(purple_blist_get_handle(), "buddy-signed-on", &blist_handle,PURPLE_CALLBACK(buddySignedOn), NULL); +// purple_signal_connect(purple_blist_get_handle(), "buddy-signed-off", &blist_handle,PURPLE_CALLBACK(buddySignedOff), NULL); +// purple_signal_connect(purple_blist_get_handle(), "buddy-status-changed", &blist_handle,PURPLE_CALLBACK(buddyStatusChanged), NULL); +// purple_signal_connect(purple_blist_get_handle(), "blist-node-removed", &blist_handle,PURPLE_CALLBACK(NodeRemoved), NULL); +// purple_signal_connect(purple_conversations_get_handle(), "chat-topic-changed", &conversation_handle, PURPLE_CALLBACK(conv_chat_topic_changed), NULL); +// +// purple_commands_init(); + + } + return ret; +} + +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 \n"; +#else + +#if GLIB_CHECK_VERSION(2,14,0) + std::cout << g_option_context_get_help(context, FALSE, NULL); +#else + std::cout << "Usage: spectrum \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 sample.cfg configuration file.\n"; + return 1; + } + + initPurple(config); + + SpectrumEventLoop eventLoop; + Component transport(&eventLoop, &config); + Logger logger(&transport); + transport.connect(); + + eventLoop.run(); + } + + g_option_context_free(context); +} diff --git a/spectrum/src/sample.cfg b/spectrum/src/sample.cfg new file mode 100644 index 00000000..fc90fdf8 --- /dev/null +++ b/spectrum/src/sample.cfg @@ -0,0 +1,9 @@ +[service] +jid = icq.localhost +password = secret +server = 127.0.0.1 +port = 8888 + +[database] +database = test.sql +prefix=icq diff --git a/spectrum/src/spectrum.cpp b/spectrum/src/spectrum.cpp new file mode 100644 index 00000000..52e6965e --- /dev/null +++ b/spectrum/src/spectrum.cpp @@ -0,0 +1,15 @@ +#include "spectrum.h" +#include "transport/config.h" +#include "transport/transport.h" +#include "transport/usermanager.h" +#include "transport/logger.h" +#include "transport/sqlite3backend.h" +#include "transport/userregistration.h" + +Spectrum::Spectrum(const std::string &config) { + +} + +Spectrum::~Spectrum() { + +} diff --git a/spectrum/src/spectrum.h b/spectrum/src/spectrum.h new file mode 100644 index 00000000..2f09ec6b --- /dev/null +++ b/spectrum/src/spectrum.h @@ -0,0 +1,33 @@ +/** + * XMPP - libpurple transport + * + * Copyright (C) 2011, Jan Kaluza + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ + +#pragma once +#include "transport/transport.h" + +using namespace Transport; + +class Spectrum { + public: + Spectrum(const std::string &config); + ~Spectrum(); + + private: + Component *m_component; +}; diff --git a/spectrum/src/spectrumeventloop.cpp b/spectrum/src/spectrumeventloop.cpp new file mode 100644 index 00000000..6d59695b --- /dev/null +++ b/spectrum/src/spectrumeventloop.cpp @@ -0,0 +1,89 @@ +/** + * XMPP - libpurple transport + * + * Copyright (C) 2009, Jan Kaluza + * + * 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 "purple.h" + +#include + +#ifdef WITH_LIBEVENT +#include +#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() { + 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); + purple_timeout_add(0, processEvent, ev); +} diff --git a/spectrum/src/spectrumeventloop.h b/spectrum/src/spectrumeventloop.h new file mode 100644 index 00000000..7e811c89 --- /dev/null +++ b/spectrum/src/spectrumeventloop.h @@ -0,0 +1,49 @@ +/** + * XMPP - libpurple transport + * + * Copyright (C) 2009, Jan Kaluza + * + * 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 +#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