diff --git a/backends/libpurple/main.cpp b/backends/libpurple/main.cpp index ce8ad051..39c53627 100644 --- a/backends/libpurple/main.cpp +++ b/backends/libpurple/main.cpp @@ -1,3 +1,5 @@ +#include "utils.h" + #include "glib.h" #include "purple.h" #include @@ -12,25 +14,7 @@ #include "log4cxx/helpers/properties.h" #include "log4cxx/helpers/fileinputstream.h" #include "log4cxx/helpers/transcoder.h" -#ifndef WIN32 -#include "sys/wait.h" -#include "sys/signal.h" -#include -#include -#include -#include -#include -#include -#include "sys/socket.h" -#include -#include -#include -#else -#include -#define getpid _getpid -#define ssize_t SSIZE_T -#include "win32/win32dep.h" -#endif + // #include "valgrind/memcheck.h" #include "malloc.h" #include @@ -44,7 +28,7 @@ using namespace log4cxx; static LoggerPtr logger_libpurple = log4cxx::Logger::getLogger("libpurple"); static LoggerPtr logger = log4cxx::Logger::getLogger("backend"); -int m_sock; +int main_socket; static int writeInput; using namespace Transport; @@ -107,13 +91,8 @@ static std::string KEYFILE_STRING(const std::string &cat, const std::string &key #define KEYFILE_BOOL(CAT, KEY) g_key_file_get_boolean(keyfile, CAT, KEY, 0) -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; struct FTData { unsigned long id; @@ -122,121 +101,12 @@ struct FTData { }; 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 } }; static void *notify_user_info(PurpleConnection *gc, const char *who, PurpleNotifyUserInfo *user_info); -static GHashTable *ui_info = NULL; - -static GHashTable *spectrum_ui_get_info(void) -{ - if(NULL == ui_info) { - ui_info = g_hash_table_new(g_str_hash, g_str_equal); - - g_hash_table_insert(ui_info, g_strdup("name"), g_strdup("Spectrum")); - g_hash_table_insert(ui_info, g_strdup("version"), g_strdup("0.5")); - g_hash_table_insert(ui_info, g_strdup("website"), g_strdup("http://spectrum.im")); - g_hash_table_insert(ui_info, g_strdup("dev_website"), g_strdup("http://spectrum.im")); - g_hash_table_insert(ui_info, g_strdup("client_type"), g_strdup("pc")); - - /* - * This is the client key for "Pidgin." It is owned by the AIM - * account "markdoliner." Please don't use this key for other - * applications. You can either not specify a client key, in - * which case the default "libpurple" key will be used, or you - * can register for your own client key at - * http://developer.aim.com/manageKeys.jsp - */ - g_hash_table_insert(ui_info, g_strdup("prpl-aim-clientkey"), g_strdup("ma1cSASNCKFtrdv9")); - g_hash_table_insert(ui_info, g_strdup("prpl-icq-clientkey"), g_strdup("ma1cSASNCKFtrdv9")); - - /* - * This is the distid for Pidgin, given to us by AOL. Please - * don't use this for other applications. You can just not - * specify a distid and libpurple will use a default. - */ - g_hash_table_insert(ui_info, g_strdup("prpl-aim-distid"), GINT_TO_POINTER(1550)); - g_hash_table_insert(ui_info, g_strdup("prpl-icq-distid"), GINT_TO_POINTER(1550)); - } - - return ui_info; -} - -static gboolean -badchar(char c) -{ - switch (c) { - case ' ': - case ',': - case '\0': - case '\n': - case '\r': - case '<': - case '>': - case '"': - return TRUE; - default: - return FALSE; - } -} - -static gboolean -badentity(const char *c) -{ - if (!g_ascii_strncasecmp(c, "<", 4) || - !g_ascii_strncasecmp(c, ">", 4) || - !g_ascii_strncasecmp(c, """, 6)) { - return TRUE; - } - return FALSE; -} - -static const char * -process_link(GString *ret, - const char *start, const char *c, - int matchlen, - const char *urlprefix, - int inside_paren) -{ - char *url_buf; - const char *t; - - for (t = c;; t++) { - if (!badchar(*t) && !badentity(t)) - continue; - - if (t - c == matchlen) - break; - - if (*t == ',' && *(t + 1) != ' ') { - continue; - } - - if (t > start && *(t - 1) == '.') - t--; - if (t > start && *(t - 1) == ')' && inside_paren > 0) - t--; - - url_buf = g_strndup(c, t - c); -// tmpurlbuf = purple_unescape_html(url_buf); -// std::cout << url_buf << "\n"; - g_string_append_printf(ret, "%s", - urlprefix, - url_buf, url_buf); -// g_free(tmpurlbuf); - g_free(url_buf); - return t; - } - - return c; -} static gboolean ft_ui_ready(void *data) { PurpleXfer *xfer = (PurpleXfer *) data; @@ -246,184 +116,6 @@ static gboolean ft_ui_ready(void *data) { return FALSE; } -static char * -spectrum_markup_linkify(const char *text) -{ - const char *c, *t, *q = NULL; - char *tmpurlbuf, *url_buf; - gunichar g; - gboolean inside_html = FALSE; - int inside_paren = 0; - GString *ret; - - if (text == NULL) - return NULL; - - ret = g_string_new(""); - - c = text; - while (*c) { - - if(*c == '(' && !inside_html) { - inside_paren++; - ret = g_string_append_c(ret, *c); - c++; - } - - if(inside_html) { - if(*c == '>') { - inside_html = FALSE; - } else if(!q && (*c == '\"' || *c == '\'')) { - q = c; - } else if(q) { - if(*c == *q) - q = NULL; - } - } else if(*c == '<') { - inside_html = TRUE; - if (!g_ascii_strncasecmp(c, "", 3)) { - inside_html = FALSE; - break; - } - ret = g_string_append_c(ret, *c); - c++; - if (!(*c)) - break; - } - } - } else if (!g_ascii_strncasecmp(c, "http://", 7)) { - c = process_link(ret, text, c, 7, "", inside_paren); - } else if (!g_ascii_strncasecmp(c, "https://", 8)) { - c = process_link(ret, text, c, 8, "", inside_paren); - } else if (!g_ascii_strncasecmp(c, "ftp://", 6)) { - c = process_link(ret, text, c, 6, "", inside_paren); - } else if (!g_ascii_strncasecmp(c, "sftp://", 7)) { - c = process_link(ret, text, c, 7, "", inside_paren); - } else if (!g_ascii_strncasecmp(c, "file://", 7)) { - c = process_link(ret, text, c, 7, "", inside_paren); - } else if (!g_ascii_strncasecmp(c, "www.", 4) && c[4] != '.' && (c == text || badchar(c[-1]) || badentity(c-1))) { - c = process_link(ret, text, c, 4, "http://", inside_paren); - } else if (!g_ascii_strncasecmp(c, "ftp.", 4) && c[4] != '.' && (c == text || badchar(c[-1]) || badentity(c-1))) { - c = process_link(ret, text, c, 4, "ftp://", inside_paren); - } else if (!g_ascii_strncasecmp(c, "xmpp:", 5) && (c == text || badchar(c[-1]) || badentity(c-1))) { - c = process_link(ret, text, c, 5, "", inside_paren); - } else if (!g_ascii_strncasecmp(c, "mailto:", 7)) { - t = c; - while (1) { - if (badchar(*t) || badentity(t)) { - const char *d; - if (t - c == 7) { - break; - } - if (t > text && *(t - 1) == '.') - t--; - if ((d = strstr(c + 7, "?")) != NULL && d < t) - url_buf = g_strndup(c + 7, d - c - 7); - else - url_buf = g_strndup(c + 7, t - c - 7); - if (!purple_email_is_valid(url_buf)) { - g_free(url_buf); - break; - } - g_free(url_buf); - url_buf = g_strndup(c, t - c); -// tmpurlbuf = purple_unescape_html(url_buf); - g_string_append_printf(ret, "%s", - url_buf, url_buf); - g_free(url_buf); -// g_free(tmpurlbuf); - c = t; - break; - } - t++; - } - } else if (c != text && (*c == '@')) { - int flag; - GString *gurl_buf = NULL; - const char illegal_chars[] = "!@#$%^&*()[]{}/|\\<>\":;\r\n \0"; - - if (strchr(illegal_chars,*(c - 1)) || strchr(illegal_chars, *(c + 1))) - flag = 0; - else { - flag = 1; - gurl_buf = g_string_new(""); - } - - t = c; - while (flag) { - /* iterate backwards grabbing the local part of an email address */ - g = g_utf8_get_char(t); - if (badchar(*t) || (g >= 127) || (*t == '(') || - ((*t == ';') && ((t > (text+2) && (!g_ascii_strncasecmp(t - 3, "<", 4) || - !g_ascii_strncasecmp(t - 3, ">", 4))) || - (t > (text+4) && (!g_ascii_strncasecmp(t - 5, """, 6)))))) { - /* local part will already be part of ret, strip it out */ - ret = g_string_truncate(ret, ret->len - (c - t)); - ret = g_string_append_unichar(ret, g); - break; - } else { - g_string_prepend_unichar(gurl_buf, g); - t = g_utf8_find_prev_char(text, t); - if (t < text) { - ret = g_string_assign(ret, ""); - break; - } - } - } - - t = g_utf8_find_next_char(c, NULL); - - while (flag) { - /* iterate forwards grabbing the domain part of an email address */ - g = g_utf8_get_char(t); - if (badchar(*t) || (g >= 127) || (*t == ')') || badentity(t)) { - char *d; - - url_buf = g_string_free(gurl_buf, FALSE); - - /* strip off trailing periods */ - if (strlen(url_buf) > 0) { - for (d = url_buf + strlen(url_buf) - 1; *d == '.'; d--, t--) - *d = '\0'; - } - - tmpurlbuf = purple_unescape_html(url_buf); - if (purple_email_is_valid(tmpurlbuf)) { - g_string_append_printf(ret, "%s", - url_buf, url_buf); - } else { - g_string_append(ret, url_buf); - } - g_free(url_buf); - g_free(tmpurlbuf); - c = t; - - break; - } else { - g_string_append_unichar(gurl_buf, g); - t = g_utf8_find_next_char(t, NULL); - } - } - } - - if(*c == ')' && !inside_html) { - inside_paren--; - ret = g_string_append_c(ret, *c); - c++; - } - - if (*c == 0) - break; - - ret = g_string_append_c(ret, *c); - c++; - - } - return g_string_free(ret, FALSE); -} - struct authRequest { PurpleAccountRequestAuthorizationCb authorize_cb; PurpleAccountRequestAuthorizationCb deny_cb; @@ -509,13 +201,13 @@ static std::string getAlias(PurpleBuddy *m_buddy) { class SpectrumNetworkPlugin : public NetworkPlugin { public: - SpectrumNetworkPlugin(const std::string &host, int port) : NetworkPlugin() { + SpectrumNetworkPlugin() : NetworkPlugin() { } void handleExitRequest() { LOG4CXX_INFO(logger, "Exiting..."); - exit(1); + exit(0); } void getProtocolAndName(const std::string &legacyName, std::string &name, std::string &protocol) { @@ -597,7 +289,7 @@ class SpectrumNetworkPlugin : public NetworkPlugin { void handleLoginRequest(const std::string &user, const std::string &legacyName, const std::string &password) { PurpleAccount *account = NULL; - + std::string name; std::string protocol; getProtocolAndName(legacyName, name, protocol); @@ -614,7 +306,6 @@ class SpectrumNetworkPlugin : public NetworkPlugin { return; } - if (purple_accounts_find(name.c_str(), protocol.c_str()) != NULL) { LOG4CXX_INFO(logger, "Using previously created account with name '" << name.c_str() << "' and protocol '" << protocol << "'"); account = purple_accounts_find(name.c_str(), protocol.c_str()); @@ -637,11 +328,13 @@ class SpectrumNetworkPlugin : public NetworkPlugin { setDefaultAccountOptions(account); + // Enable account + privacy lists purple_account_set_enabled(account, "spectrum", TRUE); if (KEYFILE_BOOL("service", "enable_privacy_lists")) { purple_account_set_privacy_type(account, PURPLE_PRIVACY_DENY_USERS); } + // Set the status const PurpleStatusType *status_type = purple_account_get_status_type_with_primitive(account, PURPLE_STATUS_AVAILABLE); if (status_type != NULL) { purple_account_set_status(account, purple_status_type_get_id(status_type), TRUE, NULL); @@ -661,50 +354,6 @@ class SpectrumNetworkPlugin : public NetworkPlugin { m_accounts.erase(account); purple_accounts_delete(account); -// -// // Remove conversations. -// // This has to be called before m_account->ui_data = NULL;, because it uses -// // ui_data to call SpectrumMessageHandler::purpleConversationDestroyed() callback. -// GList *iter; -// for (iter = purple_get_conversations(); iter; ) { -// PurpleConversation *conv = (PurpleConversation*) iter->data; -// iter = iter->next; -// if (purple_conversation_get_account(conv) == account) -// purple_conversation_destroy(conv); -// } -// -// g_free(account->ui_data); -// account->ui_data = NULL; -// m_accounts.erase(account); -// -// purple_notify_close_with_handle(account); -// purple_request_close_with_handle(account); -// -// purple_accounts_remove(account); -// -// GSList *buddies = purple_find_buddies(account, NULL); -// while(buddies) { -// PurpleBuddy *b = (PurpleBuddy *) buddies->data; -// purple_blist_remove_buddy(b); -// buddies = g_slist_delete_link(buddies, buddies); -// } -// -// /* Remove any open conversation for this account */ -// for (GList *it = purple_get_conversations(); it; ) { -// PurpleConversation *conv = (PurpleConversation *) it->data; -// it = it->next; -// if (purple_conversation_get_account(conv) == account) -// purple_conversation_destroy(conv); -// } -// -// /* Remove this account's pounces */ -// // purple_pounce_destroy_all_by_account(account); -// -// /* This will cause the deletion of an old buddy icon. */ -// purple_buddy_icons_set_account_icon(account, NULL, 0); -// -// purple_account_destroy(account); - // force returning of memory chunks allocated by libxml2 to kernel #ifndef WIN32 malloc_trim(0); #endif @@ -1002,9 +651,9 @@ class SpectrumNetworkPlugin : public NetworkPlugin { } void sendData(const std::string &string) { - write(m_sock, string.c_str(), string.size()); + write(main_socket, string.c_str(), string.size()); if (writeInput == 0) - writeInput = purple_input_add(m_sock, PURPLE_INPUT_WRITE, &transportDataReceived, NULL); + writeInput = purple_input_add(main_socket, PURPLE_INPUT_WRITE, &transportDataReceived, NULL); } void readyForData() { @@ -1864,9 +1513,8 @@ static bool initPurple() { remove("./accounts.xml"); remove("./blist.xml"); -// if (m_configuration.logAreas & LOG_AREA_PURPLE) - purple_debug_set_ui_ops(&debugUiOps); - purple_debug_set_verbose(true); + purple_debug_set_ui_ops(&debugUiOps); + purple_debug_set_verbose(true); purple_core_set_ui_ops(&coreUiOps); if (KEYFILE_STRING("service", "eventloop") == "libev") { @@ -1930,50 +1578,7 @@ static bool initPurple() { } return ret; } -#ifndef WIN32 -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); - } -} -#endif - -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 void transportDataReceived(gpointer data, gint source, PurpleInputCondition cond) { if (cond & PURPLE_INPUT_READ) { @@ -2002,17 +1607,10 @@ int main(int argc, char **argv) { 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"; + std::cerr << "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"; @@ -2036,27 +1634,6 @@ int main(int argc, char **argv) { 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 keyfile = g_key_file_new (); if (!g_key_file_load_from_file (keyfile, argv[1], (GKeyFileFlags) 0, 0)) { @@ -2091,12 +1668,11 @@ int main(int argc, char **argv) { initPurple(); - m_sock = create_socket(host, port); - - purple_input_add(m_sock, PURPLE_INPUT_READ, &transportDataReceived, NULL); + main_socket = create_socket(host, port); + purple_input_add(main_socket, PURPLE_INPUT_READ, &transportDataReceived, NULL); purple_timeout_add_seconds(30, pingTimeout, NULL); - np = new SpectrumNetworkPlugin(host, port); + np = new SpectrumNetworkPlugin(); bool libev = KEYFILE_STRING("service", "eventloop") == "libev"; GMainLoop *m_loop; diff --git a/backends/libpurple/utils.cpp b/backends/libpurple/utils.cpp new file mode 100644 index 00000000..417ad67d --- /dev/null +++ b/backends/libpurple/utils.cpp @@ -0,0 +1,129 @@ +/** + * libtransport -- C++ library for easy XMPP Transports development + * + * 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 + */ + +#include "utils.h" + +#include "glib.h" +#include "purple.h" +#include +#include + +#include "errno.h" + +#ifndef WIN32 +#include "sys/wait.h" +#include "sys/signal.h" +#include +#include +#include +#include +#include +#include +#include "sys/socket.h" +#include +#include +#include +#else +#include +#define getpid _getpid +#define ssize_t SSIZE_T +#include "win32/win32dep.h" +#endif + +static GHashTable *ui_info = NULL; + +GHashTable *spectrum_ui_get_info(void) +{ + if(NULL == ui_info) { + ui_info = g_hash_table_new(g_str_hash, g_str_equal); + + g_hash_table_insert(ui_info, g_strdup("name"), g_strdup("Spectrum")); + g_hash_table_insert(ui_info, g_strdup("version"), g_strdup("0.5")); + g_hash_table_insert(ui_info, g_strdup("website"), g_strdup("http://spectrum.im")); + g_hash_table_insert(ui_info, g_strdup("dev_website"), g_strdup("http://spectrum.im")); + g_hash_table_insert(ui_info, g_strdup("client_type"), g_strdup("pc")); + + /* + * This is the client key for "Pidgin." It is owned by the AIM + * account "markdoliner." Please don't use this key for other + * applications. You can either not specify a client key, in + * which case the default "libpurple" key will be used, or you + * can register for your own client key at + * http://developer.aim.com/manageKeys.jsp + */ + g_hash_table_insert(ui_info, g_strdup("prpl-aim-clientkey"), g_strdup("ma1cSASNCKFtrdv9")); + g_hash_table_insert(ui_info, g_strdup("prpl-icq-clientkey"), g_strdup("ma1cSASNCKFtrdv9")); + + /* + * This is the distid for Pidgin, given to us by AOL. Please + * don't use this for other applications. You can just not + * specify a distid and libpurple will use a default. + */ + g_hash_table_insert(ui_info, g_strdup("prpl-aim-distid"), GINT_TO_POINTER(1550)); + g_hash_table_insert(ui_info, g_strdup("prpl-icq-distid"), GINT_TO_POINTER(1550)); + } + + return ui_info; +} + +#ifndef WIN32 +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); + } +} +#endif + +int create_socket(char *host, int portno) { + struct sockaddr_in serv_addr; + + int main_socket = 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(main_socket, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { + close(main_socket); + main_socket = 0; + } + + int flags = fcntl(main_socket, F_GETFL); + flags |= O_NONBLOCK; + fcntl(main_socket, F_SETFL, flags); + return main_socket; +} diff --git a/backends/libpurple/utils.h b/backends/libpurple/utils.h new file mode 100644 index 00000000..2055b6c1 --- /dev/null +++ b/backends/libpurple/utils.h @@ -0,0 +1,30 @@ +/** + * libtransport -- C++ library for easy XMPP Transports development + * + * 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 "purple.h" + +#ifndef WIN32 +void spectrum_sigchld_handler(int sig); +#endif + +int create_socket(char *host, int portno); +GHashTable *spectrum_ui_get_info(void); \ No newline at end of file