From ad7461beec95887be5fd7f6450944f3dcdea8387 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Tue, 4 Sep 2012 10:28:11 +0200 Subject: [PATCH] Pass command the same command line options as we have in main instance to backend instances --- backends/frotz/main.cpp | 50 ++++---- backends/libcommuni/main.cpp | 51 ++++---- backends/libpurple/main.cpp | 230 +++++++++++++++-------------------- backends/libpurple/utils.cpp | 2 +- backends/libpurple/utils.h | 2 +- backends/libyahoo2/main.cpp | 39 ++++-- backends/smstools3/main.cpp | 50 ++++---- backends/swiften/main.cpp | 39 ++++-- backends/template/main.cpp | 39 ++++-- backends/twitter/main.cpp | 39 ++++-- include/transport/util.h | 4 + spectrum/src/sample.cfg | 3 +- src/networkpluginserver.cpp | 59 +++++---- src/util.cpp | 33 +++++ 14 files changed, 358 insertions(+), 282 deletions(-) diff --git a/backends/frotz/main.cpp b/backends/frotz/main.cpp index c626becc..1e8b2f65 100644 --- a/backends/frotz/main.cpp +++ b/backends/frotz/main.cpp @@ -339,46 +339,48 @@ int main (int argc, char* argv[]) { return -1; } - boost::program_options::options_description desc("Usage: spectrum [OPTIONS] \nAllowed options"); + std::string configFile; + boost::program_options::variables_map vm; + boost::program_options::options_description desc("Usage: spectrum \nAllowed options"); desc.add_options() - ("host,h", value(&host), "host") - ("port,p", value(&port), "port") + ("help", "help") + ("host,h", boost::program_options::value(&host)->default_value(""), "Host to connect to") + ("port,p", boost::program_options::value(&port)->default_value(10000), "Port to connect to") + ("config", boost::program_options::value(&configFile)->default_value(""), "Config file") ; + try { - boost::program_options::variables_map vm; - boost::program_options::store(boost::program_options::parse_command_line(argc, argv, desc), vm); + boost::program_options::positional_options_description p; + p.add("config", -1); + boost::program_options::store(boost::program_options::command_line_parser(argc, argv). + options(desc).positional(p).allow_unregistered().run(), vm); boost::program_options::notify(vm); + + if(vm.count("help")) + { + std::cout << desc << "\n"; + return 1; + } + + if(vm.count("config") == 0) { + std::cout << desc << "\n"; + return 1; + } } catch (std::runtime_error& e) { std::cout << desc << "\n"; - exit(1); + return 1; } catch (...) { std::cout << desc << "\n"; - exit(1); - } - - - if (argc < 5) { return 1; } -// QStringList channels; -// for (int i = 3; i < argc; ++i) -// { -// channels.append(argv[i]); -// } -// -// MyIrcSession session; -// session.setNick(argv[2]); -// session.setAutoJoinChannels(channels); -// session.connectToServer(argv[1], 6667); - - Config config; - if (!config.load(argv[5])) { + Config config(argc, argv); + if (!config.load(configFile)) { std::cerr << "Can't open " << argv[1] << " configuration file.\n"; return 1; } diff --git a/backends/libcommuni/main.cpp b/backends/libcommuni/main.cpp index cab69429..c059714c 100644 --- a/backends/libcommuni/main.cpp +++ b/backends/libcommuni/main.cpp @@ -28,47 +28,48 @@ int main (int argc, char* argv[]) { int port; - boost::program_options::options_description desc("Usage: spectrum [OPTIONS] \nAllowed options"); + std::string configFile; + boost::program_options::variables_map vm; + boost::program_options::options_description desc("Usage: spectrum \nAllowed options"); desc.add_options() - ("host,h", value(&host), "host") - ("port,p", value(&port), "port") + ("help", "help") + ("host,h", boost::program_options::value(&host)->default_value(""), "Host to connect to") + ("port,p", boost::program_options::value(&port)->default_value(10000), "Port to connect to") + ("config", boost::program_options::value(&configFile)->default_value(""), "Config file") ; + try { - boost::program_options::variables_map vm; - boost::program_options::store(boost::program_options::parse_command_line(argc, argv, desc), vm); + boost::program_options::positional_options_description p; + p.add("config", -1); + boost::program_options::store(boost::program_options::command_line_parser(argc, argv). + options(desc).positional(p).allow_unregistered().run(), vm); boost::program_options::notify(vm); + + if(vm.count("help")) + { + std::cout << desc << "\n"; + return 1; + } + + if(vm.count("config") == 0) { + std::cout << desc << "\n"; + return 1; + } } catch (std::runtime_error& e) { std::cout << desc << "\n"; - exit(1); + return 1; } catch (...) { std::cout << desc << "\n"; - exit(1); - } - - - if (argc < 5) { - qDebug("Usage: %s ", argv[0]); return 1; } -// QStringList channels; -// for (int i = 3; i < argc; ++i) -// { -// channels.append(argv[i]); -// } -// -// MyIrcSession session; -// session.setNick(argv[2]); -// session.setAutoJoinChannels(channels); -// session.connectToServer(argv[1], 6667); - - Config config; - if (!config.load(argv[5])) { + Config config(argc, argv); + if (!config.load(configFile)) { std::cerr << "Can't open " << argv[1] << " configuration file.\n"; return 1; } diff --git a/backends/libpurple/main.cpp b/backends/libpurple/main.cpp index 17bfc14b..c3d1d911 100644 --- a/backends/libpurple/main.cpp +++ b/backends/libpurple/main.cpp @@ -15,6 +15,7 @@ #include "malloc.h" #include #include "errno.h" +#include #ifdef WITH_LIBEVENT #include @@ -69,48 +70,10 @@ static void transportDataReceived(gpointer data, gint source, PurpleInputConditi class SpectrumNetworkPlugin; -GKeyFile *keyfile; +boost::shared_ptr config; SpectrumNetworkPlugin *np; -static std::string replaceAll( - std::string result, - const std::string& replaceWhat, - const std::string& replaceWithWhat) -{ - while(1) - { - const int pos = result.find(replaceWhat); - if (pos==-1) break; - result.replace(pos,replaceWhat.size(),replaceWithWhat); - } - return result; -} - -static std::string KEYFILE_STRING(const std::string &cat, const std::string &key, const std::string &def = "") { - gchar *str = g_key_file_get_string(keyfile, cat.c_str(), key.c_str(), 0); - if (!str) { - return def; - } - std::string ret(str); - g_free(str); - - if (ret.find("#") != std::string::npos) { - ret = ret.substr(0, ret.find("#")); - while(*(ret.end() - 1) == ' ') { - ret.erase(ret.end() - 1); - } - } - - if (ret.find("$jid") != std::string::npos) { - std::string jid = KEYFILE_STRING("service", "jid"); - ret = replaceAll(ret, "$jid", jid); - } - return ret; -} - -#define KEYFILE_BOOL(CAT, KEY) g_key_file_get_boolean(keyfile, CAT, KEY, 0) - -static gchar *host = NULL; +static std::string host; static int port = 10000; struct FTData { @@ -119,12 +82,6 @@ struct FTData { bool paused; }; -static GOptionEntry options_entries[] = { - { "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 gboolean ft_ui_ready(void *data) { @@ -231,7 +188,7 @@ class SpectrumNetworkPlugin : public NetworkPlugin { void getProtocolAndName(const std::string &legacyName, std::string &name, std::string &protocol) { name = legacyName; - protocol = KEYFILE_STRING("service", "protocol"); + protocol = CONFIG_STRING(config, "service.protocol"); if (protocol == "any") { protocol = name.substr(0, name.find(".")); name = name.substr(name.find(".") + 1); @@ -242,13 +199,13 @@ class SpectrumNetworkPlugin : public NetworkPlugin { char* contents; gsize length; gboolean ret = false; - if (!KEYFILE_STRING("backend", "avatars_directory").empty()) { - std::string f = KEYFILE_STRING("backend", "avatars_directory") + "/" + legacyName; + if (!CONFIG_STRING(config, "backend.avatars_directory").empty()) { + std::string f = CONFIG_STRING(config, "backend.avatars_directory") + "/" + legacyName; ret = g_file_get_contents (f.c_str(), &contents, &length, NULL); } - if (!KEYFILE_STRING("backend", "default_avatar").empty() && !ret) { - ret = g_file_get_contents (KEYFILE_STRING("backend", "default_avatar").c_str(), + if (!CONFIG_STRING(config, "backend.default_avatar").empty() && !ret) { + ret = g_file_get_contents (CONFIG_STRING(config, "backend.default_avatar").c_str(), &contents, &length, NULL); } @@ -259,13 +216,16 @@ class SpectrumNetworkPlugin : public NetworkPlugin { void setDefaultAccountOptions(PurpleAccount *account) { int i = 0; - gchar **keys = g_key_file_get_keys (keyfile, "purple", NULL, NULL); - while (keys && keys[i] != NULL) { - std::string key = keys[i]; + Config::SectionValuesCont purpleConfigValues = config->getSectionValues("purple"); - if (key == "fb_api_key" || key == "fb_api_secret") { + BOOST_FOREACH ( const Config::SectionValuesCont::value_type & keyItem, purpleConfigValues ) + { + std::string key = keyItem.first; + std::string strippedKey = boost::erase_first_copy(key, "purple."); + + if (strippedKey == "fb_api_key" || strippedKey == "fb_api_secret") { purple_account_set_bool(account, "auth_fb", TRUE); - } + } PurplePlugin *plugin = purple_find_prpl(purple_account_get_protocol_id(account)); PurplePluginProtocolInfo *prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(plugin); @@ -274,23 +234,23 @@ class SpectrumNetworkPlugin : public NetworkPlugin { PurpleAccountOption *option = (PurpleAccountOption *) l->data; PurplePrefType type = purple_account_option_get_type(option); std::string key2(purple_account_option_get_setting(option)); - if (key != key2) { + if (strippedKey != key2) { continue; } found = true; switch (type) { case PURPLE_PREF_BOOLEAN: - purple_account_set_bool(account, key.c_str(), fromString(KEYFILE_STRING("purple", key))); + purple_account_set_bool(account, strippedKey.c_str(), fromString(keyItem.second.as())); break; case PURPLE_PREF_INT: - purple_account_set_int(account, key.c_str(), fromString(KEYFILE_STRING("purple", key))); + purple_account_set_int(account, strippedKey.c_str(), fromString(keyItem.second.as())); break; case PURPLE_PREF_STRING: case PURPLE_PREF_STRING_LIST: - purple_account_set_string(account, key.c_str(), KEYFILE_STRING("purple", key).c_str()); + purple_account_set_string(account, strippedKey.c_str(), keyItem.second.as().c_str()); break; default: continue; @@ -299,11 +259,10 @@ class SpectrumNetworkPlugin : public NetworkPlugin { } if (!found) { - purple_account_set_string(account, key.c_str(), KEYFILE_STRING("purple", key).c_str()); + purple_account_set_string(account, strippedKey.c_str(), keyItem.second.as().c_str()); } i++; } - g_strfreev (keys); char* contents; gsize length; @@ -313,7 +272,7 @@ class SpectrumNetworkPlugin : public NetworkPlugin { } - if (KEYFILE_STRING("service", "protocol") == "prpl-novell") { + if (CONFIG_STRING(config, "service.protocol") == "prpl-novell") { std::string username(purple_account_get_username(account)); std::vector u = split(username, '@'); purple_account_set_username(account, (const char*) u.front().c_str()); @@ -372,7 +331,7 @@ class SpectrumNetworkPlugin : public NetworkPlugin { // Enable account + privacy lists purple_account_set_enabled(account, "spectrum", TRUE); - if (KEYFILE_BOOL("service", "enable_privacy_lists")) { + if (CONFIG_BOOL(config, "service.enable_privacy_lists")) { purple_account_set_privacy_type(account, PURPLE_PRIVACY_DENY_USERS); } @@ -493,12 +452,12 @@ class SpectrumNetworkPlugin : public NetworkPlugin { PurpleAccount *account = m_sessions[user]; if (account) { std::string name = legacyName; - if (KEYFILE_STRING("service", "protocol") == "any" && legacyName.find("prpl-") == 0) { + if (CONFIG_STRING(config, "service.protocol") == "any" && legacyName.find("prpl-") == 0) { name = name.substr(name.find(".") + 1); } m_vcards[user + name] = id; - if (KEYFILE_BOOL("backend", "no_vcard_fetch") && name != purple_account_get_username(account)) { + if (CONFIG_BOOL(config, "backend.no_vcard_fetch") && name != purple_account_get_username(account)) { PurpleNotifyUserInfo *user_info = purple_notify_user_info_new(); notify_user_info(purple_account_get_connection(account), name.c_str(), user_info); purple_notify_user_info_destroy(user_info); @@ -580,7 +539,7 @@ class SpectrumNetworkPlugin : public NetworkPlugin { } void handleBuddyBlockToggled(const std::string &user, const std::string &buddyName, bool blocked) { - if (KEYFILE_BOOL("service", "enable_privacy_lists")) { + if (CONFIG_BOOL(config, "service.enable_privacy_lists")) { PurpleAccount *account = m_sessions[user]; if (account) { if (blocked) { @@ -848,7 +807,7 @@ static void buddyListNewNode(PurpleBlistNode *node) { PurplePluginProtocolInfo *prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl); bool blocked = false; - if (KEYFILE_BOOL("service", "enable_privacy_lists")) { + if (CONFIG_BOOL(config, "service.enable_privacy_lists")) { if (prpl_info && prpl_info->tooltip_text) { PurpleNotifyUserInfo *user_info = purple_notify_user_info_new(); prpl_info->tooltip_text(buddy, user_info, true); @@ -1578,13 +1537,13 @@ static bool initPurple() { purple_debug_set_verbose(true); purple_core_set_ui_ops(&coreUiOps); - if (KEYFILE_STRING("service", "eventloop") == "libev") { + if (CONFIG_STRING_DEFAULTED(config, "service.eventloop", "") == "libev") { LOG4CXX_INFO(logger, "Will use libev based event loop"); } else { LOG4CXX_INFO(logger, "Will use glib based event loop"); } - purple_eventloop_set_ui_ops(getEventLoopUiOps(KEYFILE_STRING("service", "eventloop") == "libev")); + purple_eventloop_set_ui_ops(getEventLoopUiOps(CONFIG_STRING_DEFAULTED(config, "service.eventloop", "") == "libev")); ret = purple_core_init("spectrum"); if (ret) { @@ -1670,30 +1629,6 @@ static void transportDataReceived(gpointer data, gint source, PurpleInputConditi } 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::cerr << "option parsing failed: " << error->message << "\n"; - return -1; - } - - 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 mallopt(M_CHECK_ACTION, 2); mallopt(M_PERTURB, 0xb); @@ -1702,53 +1637,84 @@ int main(int argc, char **argv) { if (signal(SIGCHLD, spectrum_sigchld_handler) == SIG_ERR) { std::cout << "SIGCHLD 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)) { - std::cout << "Can't open " << argv[1] << " configuration file.\n"; + + std::string configFile; + boost::program_options::variables_map vm; + boost::program_options::options_description desc("Usage: spectrum \nAllowed options"); + desc.add_options() + ("help", "help") + ("host,h", boost::program_options::value(&host)->default_value(""), "Host to connect to") + ("port,p", boost::program_options::value(&port)->default_value(10000), "Port to connect to") + ("config", boost::program_options::value(&configFile)->default_value(""), "Config file") + ; + + try + { + boost::program_options::positional_options_description p; + p.add("config", -1); + boost::program_options::store(boost::program_options::command_line_parser(argc, argv). + options(desc).positional(p).allow_unregistered().run(), vm); + boost::program_options::notify(vm); + + if(vm.count("help")) + { + std::cout << desc << "\n"; return 1; } - Config config; - if (!config.load(argv[1])) { - std::cerr << "Can't open " << argv[1] << " configuration file.\n"; + if(vm.count("config") == 0) { + std::cout << desc << "\n"; return 1; } - Logging::initBackendLogging(&config); - - initPurple(); - - 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(); - bool libev = KEYFILE_STRING("service", "eventloop") == "libev"; - - GMainLoop *m_loop; -#ifdef WITH_LIBEVENT - if (!libev) { - m_loop = g_main_loop_new(NULL, FALSE); - } - else { - event_init(); - } -#endif - m_loop = g_main_loop_new(NULL, FALSE); - - if (m_loop) { - g_main_loop_run(m_loop); - } -#ifdef WITH_LIBEVENT - else { - event_loop(0); - } -#endif + } + catch (std::runtime_error& e) + { + std::cout << desc << "\n"; + return 1; + } + catch (...) + { + std::cout << desc << "\n"; + return 1; } - g_option_context_free(context); + config = boost::make_shared(argc, argv); + if (!config->load(vm["config"].as())) { + std::cerr << "Can't load configuration file.\n"; + return 1; + } + + Logging::initBackendLogging(config.get()); + initPurple(); + + main_socket = create_socket(host.c_str(), port); + purple_input_add(main_socket, PURPLE_INPUT_READ, &transportDataReceived, NULL); + purple_timeout_add_seconds(30, pingTimeout, NULL); + + np = new SpectrumNetworkPlugin(); + bool libev = CONFIG_STRING_DEFAULTED(config, "service.eventloop", "") == "libev"; + + GMainLoop *m_loop; +#ifdef WITH_LIBEVENT + if (!libev) { + m_loop = g_main_loop_new(NULL, FALSE); + } + else { + event_init(); + } +#endif + m_loop = g_main_loop_new(NULL, FALSE); + if (m_loop) { + g_main_loop_run(m_loop); + } +#ifdef WITH_LIBEVENT + else { + event_loop(0); + } +#endif + return 0; } diff --git a/backends/libpurple/utils.cpp b/backends/libpurple/utils.cpp index a4ddf44b..de76e642 100644 --- a/backends/libpurple/utils.cpp +++ b/backends/libpurple/utils.cpp @@ -125,7 +125,7 @@ void spectrum_sigchld_handler(int sig) } #endif -int create_socket(char *host, int portno) { +int create_socket(const char *host, int portno) { struct sockaddr_in serv_addr; int main_socket = socket(AF_INET, SOCK_STREAM, 0); diff --git a/backends/libpurple/utils.h b/backends/libpurple/utils.h index 72d513a4..956b86f6 100644 --- a/backends/libpurple/utils.h +++ b/backends/libpurple/utils.h @@ -27,7 +27,7 @@ void spectrum_sigchld_handler(int sig); #endif -int create_socket(char *host, int portno); +int create_socket(const char *host, int portno); GHashTable *spectrum_ui_get_info(void); void execute_purple_plugin_action(PurpleConnection *gc, const std::string &name); diff --git a/backends/libyahoo2/main.cpp b/backends/libyahoo2/main.cpp index 21eb3316..d7937424 100644 --- a/backends/libyahoo2/main.cpp +++ b/backends/libyahoo2/main.cpp @@ -741,35 +741,48 @@ int main (int argc, char* argv[]) { } #endif - boost::program_options::options_description desc("Usage: spectrum [OPTIONS] \nAllowed options"); + std::string configFile; + boost::program_options::variables_map vm; + boost::program_options::options_description desc("Usage: spectrum \nAllowed options"); desc.add_options() - ("host,h", value(&host), "host") - ("port,p", value(&port), "port") + ("help", "help") + ("host,h", boost::program_options::value(&host)->default_value(""), "Host to connect to") + ("port,p", boost::program_options::value(&port)->default_value(10000), "Port to connect to") + ("config", boost::program_options::value(&configFile)->default_value(""), "Config file") ; + try { - boost::program_options::variables_map vm; - boost::program_options::store(boost::program_options::parse_command_line(argc, argv, desc), vm); + boost::program_options::positional_options_description p; + p.add("config", -1); + boost::program_options::store(boost::program_options::command_line_parser(argc, argv). + options(desc).positional(p).allow_unregistered().run(), vm); boost::program_options::notify(vm); + + if(vm.count("help")) + { + std::cout << desc << "\n"; + return 1; + } + + if(vm.count("config") == 0) { + std::cout << desc << "\n"; + return 1; + } } catch (std::runtime_error& e) { std::cout << desc << "\n"; - exit(1); + return 1; } catch (...) { std::cout << desc << "\n"; - exit(1); - } - - - if (argc < 5) { return 1; } - Config config; - if (!config.load(argv[5])) { + Config config(argc, argv); + if (!config.load(configFile)) { std::cerr << "Can't open " << argv[1] << " configuration file.\n"; return 1; } diff --git a/backends/smstools3/main.cpp b/backends/smstools3/main.cpp index 32799348..16b172ad 100644 --- a/backends/smstools3/main.cpp +++ b/backends/smstools3/main.cpp @@ -260,46 +260,48 @@ int main (int argc, char* argv[]) { return -1; } - boost::program_options::options_description desc("Usage: spectrum [OPTIONS] \nAllowed options"); + std::string configFile; + boost::program_options::variables_map vm; + boost::program_options::options_description desc("Usage: spectrum \nAllowed options"); desc.add_options() - ("host,h", value(&host), "host") - ("port,p", value(&port), "port") + ("help", "help") + ("host,h", boost::program_options::value(&host)->default_value(""), "Host to connect to") + ("port,p", boost::program_options::value(&port)->default_value(10000), "Port to connect to") + ("config", boost::program_options::value(&configFile)->default_value(""), "Config file") ; + try { - boost::program_options::variables_map vm; - boost::program_options::store(boost::program_options::parse_command_line(argc, argv, desc), vm); + boost::program_options::positional_options_description p; + p.add("config", -1); + boost::program_options::store(boost::program_options::command_line_parser(argc, argv). + options(desc).positional(p).allow_unregistered().run(), vm); boost::program_options::notify(vm); + + if(vm.count("help")) + { + std::cout << desc << "\n"; + return 1; + } + + if(vm.count("config") == 0) { + std::cout << desc << "\n"; + return 1; + } } catch (std::runtime_error& e) { std::cout << desc << "\n"; - exit(1); + return 1; } catch (...) { std::cout << desc << "\n"; - exit(1); - } - - - if (argc < 5) { return 1; } -// QStringList channels; -// for (int i = 3; i < argc; ++i) -// { -// channels.append(argv[i]); -// } -// -// MyIrcSession session; -// session.setNick(argv[2]); -// session.setAutoJoinChannels(channels); -// session.connectToServer(argv[1], 6667); - - Config config; - if (!config.load(argv[5])) { + Config config(argc, argv); + if (!config.load(configFile)) { std::cerr << "Can't open " << argv[1] << " configuration file.\n"; return 1; } diff --git a/backends/swiften/main.cpp b/backends/swiften/main.cpp index a9e3bf36..65b3fe4f 100644 --- a/backends/swiften/main.cpp +++ b/backends/swiften/main.cpp @@ -264,35 +264,48 @@ int main (int argc, char* argv[]) { } #endif - boost::program_options::options_description desc("Usage: spectrum [OPTIONS] \nAllowed options"); + std::string configFile; + boost::program_options::variables_map vm; + boost::program_options::options_description desc("Usage: spectrum \nAllowed options"); desc.add_options() - ("host,h", value(&host), "host") - ("port,p", value(&port), "port") + ("help", "help") + ("host,h", boost::program_options::value(&host)->default_value(""), "Host to connect to") + ("port,p", boost::program_options::value(&port)->default_value(10000), "Port to connect to") + ("config", boost::program_options::value(&configFile)->default_value(""), "Config file") ; + try { - boost::program_options::variables_map vm; - boost::program_options::store(boost::program_options::parse_command_line(argc, argv, desc), vm); + boost::program_options::positional_options_description p; + p.add("config", -1); + boost::program_options::store(boost::program_options::command_line_parser(argc, argv). + options(desc).positional(p).allow_unregistered().run(), vm); boost::program_options::notify(vm); + + if(vm.count("help")) + { + std::cout << desc << "\n"; + return 1; + } + + if(vm.count("config") == 0) { + std::cout << desc << "\n"; + return 1; + } } catch (std::runtime_error& e) { std::cout << desc << "\n"; - exit(1); + return 1; } catch (...) { std::cout << desc << "\n"; - exit(1); - } - - - if (argc < 5) { return 1; } - Config config; - if (!config.load(argv[5])) { + Config config(argc, argv); + if (!config.load(configFile)) { std::cerr << "Can't open " << argv[1] << " configuration file.\n"; return 1; } diff --git a/backends/template/main.cpp b/backends/template/main.cpp index bc7bc011..730ece10 100644 --- a/backends/template/main.cpp +++ b/backends/template/main.cpp @@ -113,35 +113,48 @@ int main (int argc, char* argv[]) { return -1; } #endif - boost::program_options::options_description desc("Usage: spectrum [OPTIONS] \nAllowed options"); + std::string configFile; + boost::program_options::variables_map vm; + boost::program_options::options_description desc("Usage: spectrum \nAllowed options"); desc.add_options() - ("host,h", value(&host), "host") - ("port,p", value(&port), "port") + ("help", "help") + ("host,h", boost::program_options::value(&host)->default_value(""), "Host to connect to") + ("port,p", boost::program_options::value(&port)->default_value(10000), "Port to connect to") + ("config", boost::program_options::value(&configFile)->default_value(""), "Config file") ; + try { - boost::program_options::variables_map vm; - boost::program_options::store(boost::program_options::parse_command_line(argc, argv, desc), vm); + boost::program_options::positional_options_description p; + p.add("config", -1); + boost::program_options::store(boost::program_options::command_line_parser(argc, argv). + options(desc).positional(p).allow_unregistered().run(), vm); boost::program_options::notify(vm); + + if(vm.count("help")) + { + std::cout << desc << "\n"; + return 1; + } + + if(vm.count("config") == 0) { + std::cout << desc << "\n"; + return 1; + } } catch (std::runtime_error& e) { std::cout << desc << "\n"; - exit(1); + return 1; } catch (...) { std::cout << desc << "\n"; - exit(1); - } - - - if (argc < 5) { return 1; } - Config config; - if (!config.load(argv[5])) { + Config config(argc, argv); + if (!config.load(configFile)) { std::cerr << "Can't open " << argv[1] << " configuration file.\n"; return 1; } diff --git a/backends/twitter/main.cpp b/backends/twitter/main.cpp index cf387fd7..b3404d82 100644 --- a/backends/twitter/main.cpp +++ b/backends/twitter/main.cpp @@ -27,35 +27,48 @@ int main (int argc, char* argv[]) { return -1; } - boost::program_options::options_description desc("Usage: spectrum [OPTIONS] \nAllowed options"); + std::string configFile; + boost::program_options::variables_map vm; + boost::program_options::options_description desc("Usage: spectrum \nAllowed options"); desc.add_options() - ("host,h", value(&host), "host") - ("port,p", value(&port), "port") + ("help", "help") + ("host,h", boost::program_options::value(&host)->default_value(""), "Host to connect to") + ("port,p", boost::program_options::value(&port)->default_value(10000), "Port to connect to") + ("config", boost::program_options::value(&configFile)->default_value(""), "Config file") ; + try { - boost::program_options::variables_map vm; - boost::program_options::store(boost::program_options::parse_command_line(argc, argv, desc), vm); + boost::program_options::positional_options_description p; + p.add("config", -1); + boost::program_options::store(boost::program_options::command_line_parser(argc, argv). + options(desc).positional(p).allow_unregistered().run(), vm); boost::program_options::notify(vm); + + if(vm.count("help")) + { + std::cout << desc << "\n"; + return 1; + } + + if(vm.count("config") == 0) { + std::cout << desc << "\n"; + return 1; + } } catch (std::runtime_error& e) { std::cout << desc << "\n"; - exit(1); + return 1; } catch (...) { std::cout << desc << "\n"; - exit(1); - } - - - if (argc < 5) { return 1; } - Config config; - if (!config.load(argv[5])) { + Config config(argc, argv); + if (!config.load(configFile)) { std::cerr << "Can't open " << argv[1] << " configuration file.\n"; return 1; } diff --git a/include/transport/util.h b/include/transport/util.h index d79a555f..3301ad90 100644 --- a/include/transport/util.h +++ b/include/transport/util.h @@ -42,6 +42,10 @@ std::vector deserializeGroups(std::string &groups); int getRandomPort(const std::string &s); +#ifdef _WIN32 + std::wstring utf8ToUtf16(const std::string& str); +#endif + } } diff --git a/spectrum/src/sample.cfg b/spectrum/src/sample.cfg index 03eba8b3..2cebc3d2 100644 --- a/spectrum/src/sample.cfg +++ b/spectrum/src/sample.cfg @@ -14,7 +14,8 @@ admin_password=test #cert_password=test #password to that certificate if any users_per_backend=10 #backend=../..//backends/swiften/spectrum2_swiften_backend -backend=../../backends/twitter/spectrum2_twitter_backend +#backend=../../backends/twitter/spectrum2_twitter_backend +backend=/home/hanzz/code/libtransport/backends/libpurple/spectrum2_libpurple_backend protocol=prpl-jabber #protocol=prpl-msn #protocol=any diff --git a/src/networkpluginserver.cpp b/src/networkpluginserver.cpp index 82ede6e8..b86090b6 100644 --- a/src/networkpluginserver.cpp +++ b/src/networkpluginserver.cpp @@ -43,6 +43,7 @@ #include "Swiften/Elements/InvisiblePayload.h" #include "Swiften/Elements/SpectrumErrorPayload.h" #include "transport/protocol.pb.h" +#include "transport/util.h" #include "utf8.h" @@ -58,6 +59,8 @@ #include "popt.h" #endif +using namespace Transport::Util; + namespace Transport { static unsigned long backend_id; @@ -122,16 +125,24 @@ class NetworkFactory : public Factory { wrap.SerializeToString(&MESSAGE); // Executes new backend -static unsigned long exec_(std::string path, const char *host, const char *port, const char *config) { - std::string original_path = path; +static unsigned long exec_(const std::string& exePath, const char *host, const char *port, const char *cmdlineArgs) { // BACKEND_ID is replaced with unique ID. The ID is increasing for every backend. - boost::replace_all(path, "BACKEND_ID", boost::lexical_cast(backend_id++)); - - // Add host and port. - path += std::string(" --host ") + host + " --port " + port + " " + config; - LOG4CXX_INFO(logger, "Starting new backend " << path); + std::string finalExePath = boost::replace_all_copy(exePath, "BACKEND_ID", boost::lexical_cast(backend_id++)); #ifdef _WIN32 + // Add host and port. + std::ostringstream fullCmdLine; + fullCmdLine << "\"" << finalExePath << "\" --host " << host << " --port " << port; + + if (cmdlineArgs) + fullCmdLine << " " << cmdlineArgs; + + LOG4CXX_INFO(logger, "Starting new backend " << fullCmdLine.str()); + + // We must provide a non-const buffer to CreateProcess below + std::vector rawCommandLineArgs( fullCmdLine.str().size() + 1 ); + wcscpy_s(&rawCommandLineArgs[0], rawCommandLineArgs.size(), utf8ToUtf16(fullCmdLine.str()).c_str()); + STARTUPINFO si; PROCESS_INFORMATION pi; @@ -139,26 +150,30 @@ static unsigned long exec_(std::string path, const char *host, const char *port, si.cb=sizeof (si); if (! CreateProcess( - NULL, - (LPSTR)path.c_str(), // command line - 0, // process attributes - 0, // thread attributes - 0, // inherit handles - 0, // creation flags - 0, // environment - 0, // cwd - &si, - &pi - ) + utf8ToUtf16(finalExePath).c_str(), + &rawCommandLineArgs[0], + 0, // process attributes + 0, // thread attributes + 0, // inherit handles + 0, // creation flags + 0, // environment + 0, // cwd + &si, + &pi + ) ) { LOG4CXX_ERROR(logger, "Could not start process"); } return 0; #else + // Add host and port. + finalExePath += std::string(" --host ") + host + " --port " + port + " " + cmdlineArgs; + LOG4CXX_INFO(logger, "Starting new backend " << finalExePath); + // Create array of char * from string using -lpopt library - char *p = (char *) malloc(path.size() + 1); - strcpy(p, path.c_str()); + char *p = (char *) malloc(finalExePath.size() + 1); + strcpy(p, finalExePath.c_str()); int argc; char **argv; poptParseArgvString(p, &argc, (const char ***) &argv); @@ -269,7 +284,7 @@ NetworkPluginServer::NetworkPluginServer(Component *component, Config *config, U LOG4CXX_INFO(logger, "Listening on host " << CONFIG_STRING(m_config, "service.backend_host") << " port " << CONFIG_STRING(m_config, "service.backend_port")); while (true) { - unsigned long pid = exec_(CONFIG_STRING(m_config, "service.backend"), CONFIG_STRING(m_config, "service.backend_host").c_str(), CONFIG_STRING(m_config, "service.backend_port").c_str(), m_config->getConfigFile().c_str()); + unsigned long pid = exec_(CONFIG_STRING(m_config, "service.backend"), CONFIG_STRING(m_config, "service.backend_host").c_str(), CONFIG_STRING(m_config, "service.backend_port").c_str(), m_config->getCommandLineArgs().c_str()); LOG4CXX_INFO(logger, "Tried to spawn first backend with pid " << pid); LOG4CXX_INFO(logger, "Backend should now connect to Spectrum2 instance. Spectrum2 won't accept any connection before backend connects"); @@ -1509,7 +1524,7 @@ NetworkPluginServer::Backend *NetworkPluginServer::getFreeClient(bool acceptUser if (c == NULL && !m_startingBackend) { m_isNextLongRun = longRun; m_startingBackend = true; - exec_(CONFIG_STRING(m_config, "service.backend"), CONFIG_STRING(m_config, "service.backend_host").c_str(), CONFIG_STRING(m_config, "service.backend_port").c_str(), m_config->getConfigFile().c_str()); + exec_(CONFIG_STRING(m_config, "service.backend"), CONFIG_STRING(m_config, "service.backend_host").c_str(), CONFIG_STRING(m_config, "service.backend_port").c_str(), m_config->getCommandLineArgs().c_str()); } return c; diff --git a/src/util.cpp b/src/util.cpp index 315726cb..7589f213 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -25,6 +25,7 @@ #include #include #include +#include using namespace boost::filesystem; @@ -137,6 +138,38 @@ int getRandomPort(const std::string &s) { return 30000 + rand() % 10000; } +#ifdef _WIN32 +std::wstring utf8ToUtf16(const std::string& str) +{ + try + { + if (str.empty()) + return L""; + + // First request the size of the required UTF-16 buffer + int numRequiredBytes = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), boost::numeric_cast(str.size()), NULL, 0); + if (!numRequiredBytes) + return L""; + + // Allocate memory for the UTF-16 string + std::vector utf16Str(numRequiredBytes); + + int numConverted = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), boost::numeric_cast(str.size()), &utf16Str[0], numRequiredBytes); + if (!numConverted) + return L""; + + std::wstring wstr(&utf16Str[0], numConverted); + return wstr; + } + catch (...) + { + // I don't believe libtransport is exception-safe so we'll just return an empty string instead + return L""; + } +} +#endif // _WIN32 + + } }