diff options
Diffstat (limited to 'src')
139 files changed, 1111 insertions, 885 deletions
diff --git a/src/command/cmd_ac.c b/src/command/cmd_ac.c index f9d5a22a..58ad758a 100644 --- a/src/command/cmd_ac.c +++ b/src/command/cmd_ac.c @@ -1,7 +1,7 @@ /* * cmd_ac.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -582,6 +582,7 @@ cmd_ac_init(void) tls_property_ac = autocomplete_new(); autocomplete_add(tls_property_ac, "force"); autocomplete_add(tls_property_ac, "allow"); + autocomplete_add(tls_property_ac, "trust"); autocomplete_add(tls_property_ac, "legacy"); autocomplete_add(tls_property_ac, "disable"); @@ -664,7 +665,7 @@ cmd_ac_init(void) autocomplete_add(time_ac, "console"); autocomplete_add(time_ac, "chat"); autocomplete_add(time_ac, "muc"); - autocomplete_add(time_ac, "mucconfig"); + autocomplete_add(time_ac, "config"); autocomplete_add(time_ac, "private"); autocomplete_add(time_ac, "xml"); autocomplete_add(time_ac, "statusbar"); @@ -1107,8 +1108,8 @@ cmd_ac_reset(ProfWin *window) muc_jid_autocomplete_reset(mucwin->roomjid); } - if (window->type == WIN_MUC_CONFIG) { - ProfMucConfWin *confwin = (ProfMucConfWin*)window; + if (window->type == WIN_CONFIG) { + ProfConfWin *confwin = (ProfConfWin*)window; assert(confwin->memcheck == PROFCONFWIN_MEMCHECK); if (confwin->form) { form_reset_autocompleters(confwin->form); @@ -2349,13 +2350,13 @@ _inpblock_autocomplete(ProfWin *window, const char *const input, gboolean previo static char* _form_autocomplete(ProfWin *window, const char *const input, gboolean previous) { - if (window->type != WIN_MUC_CONFIG) { + if (window->type != WIN_CONFIG) { return NULL; } char *found = NULL; - ProfMucConfWin *confwin = (ProfMucConfWin*)window; + ProfConfWin *confwin = (ProfConfWin*)window; DataForm *form = confwin->form; if (form) { found = autocomplete_param_with_ac(input, "/form help", form->tag_ac, TRUE, previous); @@ -2375,13 +2376,13 @@ _form_autocomplete(ProfWin *window, const char *const input, gboolean previous) static char* _form_field_autocomplete(ProfWin *window, const char *const input, gboolean previous) { - if (window->type != WIN_MUC_CONFIG) { + if (window->type != WIN_CONFIG) { return NULL; } char *found = NULL; - ProfMucConfWin *confwin = (ProfMucConfWin*)window; + ProfConfWin *confwin = (ProfConfWin*)window; DataForm *form = confwin->form; if (form == NULL) { return NULL; @@ -2510,7 +2511,7 @@ _time_autocomplete(ProfWin *window, const char *const input, gboolean previous) return found; } - found = autocomplete_param_with_ac(input, "/time mucconfig", time_format_ac, TRUE, previous); + found = autocomplete_param_with_ac(input, "/time config", time_format_ac, TRUE, previous); if (found) { return found; } diff --git a/src/command/cmd_ac.h b/src/command/cmd_ac.h index d7b47eb5..cb9fdee2 100644 --- a/src/command/cmd_ac.h +++ b/src/command/cmd_ac.h @@ -1,7 +1,7 @@ /* * cmd_ac.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/command/cmd_defs.c b/src/command/cmd_defs.c index 418155c4..4447020b 100644 --- a/src/command/cmd_defs.c +++ b/src/command/cmd_defs.c @@ -1,7 +1,7 @@ /* * cmd_defs.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -158,7 +158,7 @@ static struct cmd_t command_defs[] = CMD_TAG_CONNECTION) CMD_SYN( "/connect [<account>]", - "/connect <account> [server <server>] [port <port>] [tls force|allow|legacy|disable]") + "/connect <account> [server <server>] [port <port>] [tls force|allow|trust|legacy|disable]") CMD_DESC( "Login to a chat service. " "If no account is specified, the default is used if one is configured. " @@ -169,6 +169,7 @@ static struct cmd_t command_defs[] = { "port <port>", "The port to use if different to the default (5222, or 5223 for SSL)." }, { "tls force", "Force TLS connection, and fail if one cannot be established, this is default behaviour." }, { "tls allow", "Use TLS for the connection if it is available." }, + { "tls trust", "Force TLS connection and trust server's certificate." }, { "tls legacy", "Use legacy TLS for the connection. It means server doesn't support STARTTLS and TLS is forced just after TCP connection is established." }, { "tls disable", "Disable TLS for the connection." }) CMD_EXAMPLES( @@ -383,7 +384,7 @@ static struct cmd_t command_defs[] = "/roster add someone@contacts.org", "/roster add someone@contacts.org Buddy", "/roster remove someone@contacts.org", - "/roster nick myfriend@chat.org My Friend", + "/roster nick myfriend@chat.org \"My Friend\"", "/roster clearnick kai@server.com", "/roster size 15") }, @@ -424,7 +425,7 @@ static struct cmd_t command_defs[] = "View, add to, and remove from roster groups. " "Passing no argument will list all roster groups.") CMD_ARGS( - { "show <group>", "List all roster items a group." }, + { "show <group>", "List all roster items in a group." }, { "add <group> <contact>", "Add a contact to a group." }, { "remove <group> <contact>", "Remove a contact from a group." }) CMD_EXAMPLES( @@ -1265,8 +1266,8 @@ static struct cmd_t command_defs[] = CMD_TAGS( CMD_TAG_UI) CMD_SYN( - "/time console|chat|muc|mucconfig|private|xml set <format>", - "/time console|chat|muc|mucconfig|private|xml off", + "/time console|chat|muc|config|private|xml set <format>", + "/time console|chat|muc|config|private|xml off", "/time statusbar set <format>", "/time statusbar off", "/time lastactivity set <format>") @@ -1283,8 +1284,8 @@ static struct cmd_t command_defs[] = { "chat off", "Do not show time in chat windows." }, { "muc set <format>", "Set time format for chat room windows." }, { "muc off", "Do not show time in chat room windows." }, - { "mucconfig set <format>", "Set time format for chat room config windows." }, - { "mucconfig off", "Do not show time in chat room config windows." }, + { "config set <format>", "Set time format for config windows." }, + { "config off", "Do not show time in config windows." }, { "private set <format>", "Set time format for private chat windows." }, { "private off", "Do not show time in private chat windows." }, { "xml set <format>", "Set time format for XML console window." }, @@ -1934,7 +1935,7 @@ static struct cmd_t command_defs[] = "/autoaway message away|xa <message>|off", "/autoaway check on|off") CMD_DESC( - "Manage autoway settings for idle time.") + "Manage autoaway settings for idle time.") CMD_ARGS( { "mode idle", "Sends idle time, status remains online." }, { "mode away", "Sends away and xa presence as well as idle time." }, @@ -2014,7 +2015,7 @@ static struct cmd_t command_defs[] = "/account set <account> otr <policy>", "/account set <account> pgpkeyid <pgpkeyid>", "/account set <account> startscript <script>", - "/account set <account> tls force|allow|legacy|disable", + "/account set <account> tls force|allow|trust|legacy|disable", "/account set <account> theme <theme>", "/account clear <account> password", "/account clear <account> eval_password", @@ -2054,6 +2055,7 @@ static struct cmd_t command_defs[] = { "set <account> startscript <script>", "Set the script to execute after connecting." }, { "set <account> tls force", "Force TLS connection, and fail if one cannot be established, this is default behaviour." }, { "set <account> tls allow", "Use TLS for the connection if it is available." }, + { "set <account> tls trust", "Force TLS connection and trust server's certificate." }, { "set <account> tls legacy", "Use legacy TLS for the connection. It means server doesn't support STARTTLS and TLS is forced just after TCP connection is established." }, { "set <account> tls disable", "Disable TLS for the connection." }, { "set <account> <theme>", "Set the UI theme for the account." }, @@ -2084,6 +2086,8 @@ static struct cmd_t command_defs[] = CMD_SUBFUNCS( { "sourcepath", cmd_plugins_sourcepath }, { "install", cmd_plugins_install }, + { "uninstall", cmd_plugins_uninstall }, + { "update", cmd_plugins_update }, { "load", cmd_plugins_load }, { "unload", cmd_plugins_unload }, { "reload", cmd_plugins_reload }, @@ -2095,6 +2099,8 @@ static struct cmd_t command_defs[] = "/plugins sourcepath set <path>", "/plugins sourcepath clear", "/plugins install [<path>]", + "/plugins uninstall [<plugin>]", + "/plugins update [<path>]", "/plugins unload [<plugin>]", "/plugins load [<plugin>]", "/plugins reload [<plugin>]", @@ -2105,6 +2111,8 @@ static struct cmd_t command_defs[] = { "sourcepath set <path>", "Set the default path to install plugins from, will be used if no arg is passed to /plugins install." }, { "sourcepath clear", "Clear the default plugins source path." }, { "install [<path>]", "Install a plugin, or all plugins found in a directory (recursive). Passing no argument will use the sourcepath if one is set." }, + { "uninstall [<plugin>]", "Uninstall a plugin." }, + { "update [<path>]", "Updates an installed plugin" }, { "load [<plugin>]", "Load a plugin that already exists in the plugin directory, passing no argument loads all found plugins." }, { "unload [<plugin>]", "Unload a loaded plugin, passing no argument will unload all plugins." }, { "reload [<plugin>]", "Reload a plugin, passing no argument will reload all plugins." }, @@ -2113,6 +2121,8 @@ static struct cmd_t command_defs[] = "/plugins sourcepath set /home/meee/projects/profanity-plugins", "/plugins install", "/plugins install /home/steveharris/Downloads/metal.py", + "/plugins update /home/steveharris/Downloads/metal.py", + "/plugins uninstall browser.py", "/plugins load browser.py", "/plugins unload say.py", "/plugins reload wikipedia.py") @@ -2298,6 +2308,26 @@ static struct cmd_t command_defs[] = CMD_EXAMPLES( "/export /path/to/output.csv", "/export ~/contacts.csv") + }, + + { "/cmd", + parse_args, 1, 3, NULL, + CMD_SUBFUNCS( + { "list", cmd_command_list }, + { "exec", cmd_command_exec }) + CMD_NOMAINFUNC + CMD_NOTAGS + CMD_SYN( + "/cmd list [<jid>]", + "/cmd exec <command> [<jid>]") + CMD_DESC( + "Execute ad hoc commands.") + CMD_ARGS( + { "list", "List supported ad hoc commands." }, + { "exec <command>", "Execute a command." }) + CMD_EXAMPLES( + "/cmd list", + "/cmd exec ping") } }; diff --git a/src/command/cmd_defs.h b/src/command/cmd_defs.h index d318e7ed..e6ce1053 100644 --- a/src/command/cmd_defs.h +++ b/src/command/cmd_defs.h @@ -1,7 +1,7 @@ /* * cmd_defs.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/command/cmd_funcs.c b/src/command/cmd_funcs.c index c8aa22b4..6cdd40fb 100644 --- a/src/command/cmd_funcs.c +++ b/src/command/cmd_funcs.c @@ -1,7 +1,7 @@ /* * cmd_funcs.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -70,6 +70,7 @@ #include "ui/ui.h" #include "ui/window_list.h" #include "xmpp/xmpp.h" +#include "xmpp/connection.h" #include "xmpp/contact.h" #include "xmpp/roster_list.h" #include "xmpp/jid.h" @@ -204,7 +205,7 @@ cmd_tls_trust(ProfWin *window, const char *const command, gchar **args) #ifdef HAVE_LIBMESODE jabber_conn_status_t conn_status = connection_get_status(); if (conn_status != JABBER_CONNECTED) { - cons_show("You are not currently connected."); + cons_show("You are currently not connected."); return TRUE; } if (!connection_is_secured()) { @@ -350,6 +351,7 @@ cmd_connect(ProfWin *window, const char *const command, gchar **args) if (tls_policy && (g_strcmp0(tls_policy, "force") != 0) && (g_strcmp0(tls_policy, "allow") != 0) && + (g_strcmp0(tls_policy, "trust") != 0) && (g_strcmp0(tls_policy, "disable") != 0) && (g_strcmp0(tls_policy, "legacy") != 0)) { cons_bad_cmd_usage(command); @@ -391,6 +393,14 @@ cmd_connect(ProfWin *window, const char *const command, gchar **args) // connect with account ProfAccount *account = accounts_get_account(lower); if (account) { + // override account options with connect options + if (altdomain != NULL) + account_set_server(account, altdomain); + if (port != 0) + account_set_port(account, port); + if (tls_policy != NULL) + account_set_tls_policy(account, tls_policy); + // use password if set if (account->password) { conn_status = cl_ev_connect_account(account); @@ -814,6 +824,7 @@ _account_set_tls(char *account_name, char *policy) { if ((g_strcmp0(policy, "force") != 0) && (g_strcmp0(policy, "allow") != 0) + && (g_strcmp0(policy, "trust") != 0) && (g_strcmp0(policy, "disable") != 0) && (g_strcmp0(policy, "legacy") != 0)) { cons_show("TLS policy must be one of: force, allow, legacy or disable."); @@ -3632,11 +3643,11 @@ cmd_decline(ProfWin *window, const char *const command, gchar **args) gboolean cmd_form_field(ProfWin *window, char *tag, gchar **args) { - if (window->type != WIN_MUC_CONFIG) { + if (window->type != WIN_CONFIG) { return TRUE; } - ProfMucConfWin *confwin = (ProfMucConfWin*)window; + ProfConfWin *confwin = (ProfConfWin*)window; DataForm *form = confwin->form; if (form) { if (!form_tag_exists(form, tag)) { @@ -3657,14 +3668,14 @@ cmd_form_field(ProfWin *window, char *tag, gchar **args) if (g_strcmp0(value, "on") == 0) { form_set_value(form, tag, "1"); win_println(window, THEME_DEFAULT, '-', "Field updated..."); - mucconfwin_show_form_field(confwin, form, tag); + confwin_show_form_field(confwin, form, tag); } else if (g_strcmp0(value, "off") == 0) { form_set_value(form, tag, "0"); win_println(window, THEME_DEFAULT, '-', "Field updated..."); - mucconfwin_show_form_field(confwin, form, tag); + confwin_show_form_field(confwin, form, tag); } else { win_println(window, THEME_DEFAULT, '-', "Invalid command, usage:"); - mucconfwin_field_help(confwin, tag); + confwin_field_help(confwin, tag); win_println(window, THEME_DEFAULT, '-', ""); } break; @@ -3675,24 +3686,24 @@ cmd_form_field(ProfWin *window, char *tag, gchar **args) value = args[0]; if (value == NULL) { win_println(window, THEME_DEFAULT, '-', "Invalid command, usage:"); - mucconfwin_field_help(confwin, tag); + confwin_field_help(confwin, tag); win_println(window, THEME_DEFAULT, '-', ""); } else { form_set_value(form, tag, value); win_println(window, THEME_DEFAULT, '-', "Field updated..."); - mucconfwin_show_form_field(confwin, form, tag); + confwin_show_form_field(confwin, form, tag); } break; case FIELD_LIST_SINGLE: value = args[0]; if ((value == NULL) || !form_field_contains_option(form, tag, value)) { win_println(window, THEME_DEFAULT, '-', "Invalid command, usage:"); - mucconfwin_field_help(confwin, tag); + confwin_field_help(confwin, tag); win_println(window, THEME_DEFAULT, '-', ""); } else { form_set_value(form, tag, value); win_println(window, THEME_DEFAULT, '-', "Field updated..."); - mucconfwin_show_form_field(confwin, form, tag); + confwin_show_form_field(confwin, form, tag); } break; @@ -3703,32 +3714,32 @@ cmd_form_field(ProfWin *window, char *tag, gchar **args) } if ((g_strcmp0(cmd, "add") != 0) && (g_strcmp0(cmd, "remove"))) { win_println(window, THEME_DEFAULT, '-', "Invalid command, usage:"); - mucconfwin_field_help(confwin, tag); + confwin_field_help(confwin, tag); win_println(window, THEME_DEFAULT, '-', ""); break; } if (value == NULL) { win_println(window, THEME_DEFAULT, '-', "Invalid command, usage:"); - mucconfwin_field_help(confwin, tag); + confwin_field_help(confwin, tag); win_println(window, THEME_DEFAULT, '-', ""); break; } if (g_strcmp0(cmd, "add") == 0) { form_add_value(form, tag, value); win_println(window, THEME_DEFAULT, '-', "Field updated..."); - mucconfwin_show_form_field(confwin, form, tag); + confwin_show_form_field(confwin, form, tag); break; } if (g_strcmp0(args[0], "remove") == 0) { if (!g_str_has_prefix(value, "val")) { win_println(window, THEME_DEFAULT, '-', "Invalid command, usage:"); - mucconfwin_field_help(confwin, tag); + confwin_field_help(confwin, tag); win_println(window, THEME_DEFAULT, '-', ""); break; } if (strlen(value) < 4) { win_println(window, THEME_DEFAULT, '-', "Invalid command, usage:"); - mucconfwin_field_help(confwin, tag); + confwin_field_help(confwin, tag); win_println(window, THEME_DEFAULT, '-', ""); break; } @@ -3736,7 +3747,7 @@ cmd_form_field(ProfWin *window, char *tag, gchar **args) int index = strtol(&value[3], NULL, 10); if ((index < 1) || (index > form_get_value_count(form, tag))) { win_println(window, THEME_DEFAULT, '-', "Invalid command, usage:"); - mucconfwin_field_help(confwin, tag); + confwin_field_help(confwin, tag); win_println(window, THEME_DEFAULT, '-', ""); break; } @@ -3744,7 +3755,7 @@ cmd_form_field(ProfWin *window, char *tag, gchar **args) removed = form_remove_text_multi_value(form, tag, index); if (removed) { win_println(window, THEME_DEFAULT, '-', "Field updated..."); - mucconfwin_show_form_field(confwin, form, tag); + confwin_show_form_field(confwin, form, tag); } else { win_println(window, THEME_DEFAULT, '-', "Could not remove %s from %s", value, tag); } @@ -3757,13 +3768,13 @@ cmd_form_field(ProfWin *window, char *tag, gchar **args) } if ((g_strcmp0(cmd, "add") != 0) && (g_strcmp0(cmd, "remove"))) { win_println(window, THEME_DEFAULT, '-', "Invalid command, usage:"); - mucconfwin_field_help(confwin, tag); + confwin_field_help(confwin, tag); win_println(window, THEME_DEFAULT, '-', ""); break; } if (value == NULL) { win_println(window, THEME_DEFAULT, '-', "Invalid command, usage:"); - mucconfwin_field_help(confwin, tag); + confwin_field_help(confwin, tag); win_println(window, THEME_DEFAULT, '-', ""); break; } @@ -3773,13 +3784,13 @@ cmd_form_field(ProfWin *window, char *tag, gchar **args) added = form_add_unique_value(form, tag, value); if (added) { win_println(window, THEME_DEFAULT, '-', "Field updated..."); - mucconfwin_show_form_field(confwin, form, tag); + confwin_show_form_field(confwin, form, tag); } else { win_println(window, THEME_DEFAULT, '-', "Value %s already selected for %s", value, tag); } } else { win_println(window, THEME_DEFAULT, '-', "Invalid command, usage:"); - mucconfwin_field_help(confwin, tag); + confwin_field_help(confwin, tag); win_println(window, THEME_DEFAULT, '-', ""); } break; @@ -3790,13 +3801,13 @@ cmd_form_field(ProfWin *window, char *tag, gchar **args) removed = form_remove_value(form, tag, value); if (removed) { win_println(window, THEME_DEFAULT, '-', "Field updated..."); - mucconfwin_show_form_field(confwin, form, tag); + confwin_show_form_field(confwin, form, tag); } else { win_println(window, THEME_DEFAULT, '-', "Value %s is not currently set for %s", value, tag); } } else { win_println(window, THEME_DEFAULT, '-', "Invalid command, usage:"); - mucconfwin_field_help(confwin, tag); + confwin_field_help(confwin, tag); win_println(window, THEME_DEFAULT, '-', ""); } } @@ -3808,13 +3819,13 @@ cmd_form_field(ProfWin *window, char *tag, gchar **args) } if ((g_strcmp0(cmd, "add") != 0) && (g_strcmp0(cmd, "remove"))) { win_println(window, THEME_DEFAULT, '-', "Invalid command, usage:"); - mucconfwin_field_help(confwin, tag); + confwin_field_help(confwin, tag); win_println(window, THEME_DEFAULT, '-', ""); break; } if (value == NULL) { win_println(window, THEME_DEFAULT, '-', "Invalid command, usage:"); - mucconfwin_field_help(confwin, tag); + confwin_field_help(confwin, tag); win_println(window, THEME_DEFAULT, '-', ""); break; } @@ -3822,7 +3833,7 @@ cmd_form_field(ProfWin *window, char *tag, gchar **args) added = form_add_unique_value(form, tag, value); if (added) { win_println(window, THEME_DEFAULT, '-', "Field updated..."); - mucconfwin_show_form_field(confwin, form, tag); + confwin_show_form_field(confwin, form, tag); } else { win_println(window, THEME_DEFAULT, '-', "JID %s already exists in %s", value, tag); } @@ -3832,7 +3843,7 @@ cmd_form_field(ProfWin *window, char *tag, gchar **args) removed = form_remove_value(form, tag, value); if (removed) { win_println(window, THEME_DEFAULT, '-', "Field updated..."); - mucconfwin_show_form_field(confwin, form, tag); + confwin_show_form_field(confwin, form, tag); } else { win_println(window, THEME_DEFAULT, '-', "Field %s does not contain %s", tag, value); } @@ -3857,7 +3868,7 @@ cmd_form(ProfWin *window, const char *const command, gchar **args) return TRUE; } - if (window->type != WIN_MUC_CONFIG) { + if (window->type != WIN_CONFIG) { cons_show("Command '/form' does not apply to this window."); return TRUE; } @@ -3870,20 +3881,20 @@ cmd_form(ProfWin *window, const char *const command, gchar **args) return TRUE; } - ProfMucConfWin *confwin = (ProfMucConfWin*)window; + ProfConfWin *confwin = (ProfConfWin*)window; assert(confwin->memcheck == PROFCONFWIN_MEMCHECK); if (g_strcmp0(args[0], "show") == 0) { - mucconfwin_show_form(confwin); + confwin_show_form(confwin); return TRUE; } if (g_strcmp0(args[0], "help") == 0) { char *tag = args[1]; if (tag) { - mucconfwin_field_help(confwin, tag); + confwin_field_help(confwin, tag); } else { - mucconfwin_form_help(confwin); + confwin_form_help(confwin); gchar **help_text = NULL; Command *command = cmd_get("/form"); @@ -3898,12 +3909,12 @@ cmd_form(ProfWin *window, const char *const command, gchar **args) return TRUE; } - if (g_strcmp0(args[0], "submit") == 0) { - iq_submit_room_config(confwin->roomjid, confwin->form); + if (g_strcmp0(args[0], "submit") == 0 && confwin->submit != NULL) { + confwin->submit(confwin); } - if (g_strcmp0(args[0], "cancel") == 0) { - iq_room_config_cancel(confwin->roomjid); + if (g_strcmp0(args[0], "cancel") == 0 && confwin->cancel != NULL) { + confwin->cancel(confwin); } if ((g_strcmp0(args[0], "submit") == 0) || (g_strcmp0(args[0], "cancel") == 0)) { @@ -4264,7 +4275,7 @@ cmd_room(ProfWin *window, const char *const command, gchar **args) } if (g_strcmp0(args[0], "config") == 0) { - ProfMucConfWin *confwin = wins_get_muc_conf(mucwin->roomjid); + ProfConfWin *confwin = wins_get_conf(mucwin->roomjid); if (confwin) { ui_focus_win((ProfWin*)confwin); @@ -5159,20 +5170,20 @@ cmd_time(ProfWin *window, const char *const command, gchar **args) cons_bad_cmd_usage(command); return TRUE; } - } else if (g_strcmp0(args[0], "mucconfig") == 0) { + } else if (g_strcmp0(args[0], "config") == 0) { if (args[1] == NULL) { - char *format = prefs_get_string(PREF_TIME_MUCCONFIG); - cons_show("MUC config time format: '%s'.", format); + char *format = prefs_get_string(PREF_TIME_CONFIG); + cons_show("config time format: '%s'.", format); prefs_free_string(format); return TRUE; } else if (g_strcmp0(args[1], "set") == 0 && args[2] != NULL) { - prefs_set_string(PREF_TIME_MUCCONFIG, args[2]); - cons_show("MUC config time format set to '%s'.", args[2]); + prefs_set_string(PREF_TIME_CONFIG, args[2]); + cons_show("config time format set to '%s'.", args[2]); wins_resize_all(); return TRUE; } else if (g_strcmp0(args[1], "off") == 0) { - prefs_set_string(PREF_TIME_MUCCONFIG, "off"); - cons_show("MUC config time display disabled."); + prefs_set_string(PREF_TIME_CONFIG, "off"); + cons_show("config time display disabled."); wins_resize_all(); return TRUE; } else { @@ -6616,15 +6627,16 @@ cmd_plugins_install(ProfWin *window, const char *const command, gchar **args) return TRUE; } + GString* error_message = g_string_new(NULL); gchar *plugin_name = g_path_get_basename(path); - gboolean result = plugins_install(plugin_name, path); + gboolean result = plugins_install(plugin_name, path, error_message); if (result) { cons_show("Plugin installed: %s", plugin_name); } else { - cons_show("Failed to install plugin: %s", plugin_name); + cons_show("Failed to install plugin: %s. %s", plugin_name, error_message->str); } g_free(plugin_name); - + g_string_free(error_message, TRUE); free(path); return TRUE; } @@ -6663,6 +6675,88 @@ cmd_plugins_install(ProfWin *window, const char *const command, gchar **args) } gboolean +cmd_plugins_update(ProfWin *window, const char *const command, gchar **args) +{ + char *path = args[1]; + if (path == NULL) { + char* sourcepath = prefs_get_string(PREF_PLUGINS_SOURCEPATH); + if (sourcepath) { + path = strdup(sourcepath); + prefs_free_string(sourcepath); + } else { + cons_show("Either a path must be provided or the sourcepath property must be set, see /help plugins"); + return TRUE; + } + } else if (path[0] == '~' && path[1] == '/') { + if (asprintf(&path, "%s/%s", getenv("HOME"), path+2) == -1) { + return TRUE; + } + } else { + path = strdup(path); + } + + if (access(path, R_OK) != 0) { + cons_show("File not found: %s", path); + free(path); + return TRUE; + } + + if (is_regular_file(path)) { + if (!g_str_has_suffix(path, ".py") && !g_str_has_suffix(path, ".so")) { + cons_show("Plugins must have one of the following extensions: '.py' '.so'"); + free(path); + return TRUE; + } + + GString* error_message = g_string_new(NULL); + gchar *plugin_name = g_path_get_basename(path); + if (plugins_unload(plugin_name)) { + if (plugins_uninstall(plugin_name)) { + if (plugins_install(plugin_name, path, error_message)) { + cons_show("Plugin installed: %s", plugin_name); + } else { + cons_show("Failed to install plugin: %s. %s", plugin_name, error_message->str); + } + } else { + cons_show("Failed to uninstall plugin: %s.", plugin_name); + } + } else { + cons_show("Failed to unload plugin: %s.", plugin_name); + } + g_free(plugin_name); + g_string_free(error_message, TRUE); + free(path); + return TRUE; + } + + if (is_dir(path)) { + free(path); + return FALSE; + } + + free(path); + cons_show("Argument must be a file or directory."); + return TRUE; +} + +gboolean +cmd_plugins_uninstall(ProfWin *window, const char *const command, gchar **args) +{ + if (args[1] == NULL) { + return FALSE; + } + + gboolean res = plugins_uninstall(args[1]); + if (res) { + cons_show("Uninstalled plugin: %s", args[1]); + } else { + cons_show("Failed to uninstall plugin: %s", args[1]); + } + + return TRUE; +} + +gboolean cmd_plugins_load(ProfWin *window, const char *const command, gchar **args) { if (args[1] == NULL) { @@ -7469,10 +7563,122 @@ cmd_encwarn(ProfWin *window, const char *const command, gchar **args) return TRUE; } +gboolean +cmd_command_list(ProfWin *window, const char *const command, gchar **args) +{ + jabber_conn_status_t conn_status = connection_get_status(); + + if (conn_status != JABBER_CONNECTED) { + cons_show("You are not currently connected."); + return TRUE; + } + + if (connection_supports(XMPP_FEATURE_COMMANDS) == FALSE) { + cons_show("Server does not support ad hoc commands."); + return TRUE; + } + + char *jid = args[1]; + if (jid == NULL) { + switch (window->type) { + case WIN_MUC: + { + ProfMucWin *mucwin = (ProfMucWin*)window; + assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); + jid = mucwin->roomjid; + break; + } + case WIN_CHAT: + { + ProfChatWin *chatwin = (ProfChatWin*)window; + assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); + jid = chatwin->barejid; + break; + } + case WIN_PRIVATE: + { + ProfPrivateWin *privatewin = (ProfPrivateWin*)window; + assert(privatewin->memcheck == PROFPRIVATEWIN_MEMCHECK); + jid = privatewin->fulljid; + break; + } + case WIN_CONSOLE: + { + jid = connection_get_domain(); + break; + } + default: + cons_show("Cannot send ad hoc commands."); + return TRUE; + } + } + + iq_command_list(jid); + + cons_show("List available ad hoc commands"); + return TRUE; +} + +gboolean +cmd_command_exec(ProfWin *window, const char *const command, gchar **args) +{ + jabber_conn_status_t conn_status = connection_get_status(); + + if (conn_status != JABBER_CONNECTED) { + cons_show("You are not currently connected."); + return TRUE; + } + + if (connection_supports(XMPP_FEATURE_COMMANDS) == FALSE) { + cons_show("Server does not support ad hoc commands."); + return TRUE; + } + + char *jid = args[2]; + if (jid == NULL) { + switch (window->type) { + case WIN_MUC: + { + ProfMucWin *mucwin = (ProfMucWin*)window; + assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); + jid = mucwin->roomjid; + break; + } + case WIN_CHAT: + { + ProfChatWin *chatwin = (ProfChatWin*)window; + assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); + jid = chatwin->barejid; + break; + } + case WIN_PRIVATE: + { + ProfPrivateWin *privatewin = (ProfPrivateWin*)window; + assert(privatewin->memcheck == PROFPRIVATEWIN_MEMCHECK); + jid = privatewin->fulljid; + break; + } + case WIN_CONSOLE: + { + jid = connection_get_domain(); + break; + } + default: + cons_show("Cannot send ad hoc commands."); + return TRUE; + } + } + + iq_command_exec(jid, args[1]); + + cons_show("Execute %s...", args[1]); + return TRUE; +} + static gboolean _cmd_execute(ProfWin *window, const char *const command, const char *const inp) { - if (g_str_has_prefix(command, "/field") && window->type == WIN_MUC_CONFIG) { + if (g_str_has_prefix(command, "/field") && window->type == WIN_CONFIG) { gboolean result = FALSE; gchar **args = parse_args_with_freetext(inp, 1, 2, &result); if (!result) { diff --git a/src/command/cmd_funcs.h b/src/command/cmd_funcs.h index 0bbf338e..89166ba1 100644 --- a/src/command/cmd_funcs.h +++ b/src/command/cmd_funcs.h @@ -1,7 +1,7 @@ /* * cmd_funcs.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -158,10 +158,14 @@ gboolean cmd_script(ProfWin *window, const char *const command, gchar **args); gboolean cmd_export(ProfWin *window, const char *const command, gchar **args); gboolean cmd_charset(ProfWin *window, const char *const command, gchar **args); gboolean cmd_console(ProfWin *window, const char *const command, gchar **args); +gboolean cmd_command_list(ProfWin *window, const char *const command, gchar **args); +gboolean cmd_command_exec(ProfWin *window, const char *const command, gchar **args); gboolean cmd_plugins(ProfWin *window, const char *const command, gchar **args); gboolean cmd_plugins_sourcepath(ProfWin *window, const char *const command, gchar **args); gboolean cmd_plugins_install(ProfWin *window, const char *const command, gchar **args); +gboolean cmd_plugins_update(ProfWin *window, const char *const command, gchar **args); +gboolean cmd_plugins_uninstall(ProfWin *window, const char *const command, gchar **args); gboolean cmd_plugins_load(ProfWin *window, const char *const command, gchar **args); gboolean cmd_plugins_unload(ProfWin *window, const char *const command, gchar **args); gboolean cmd_plugins_reload(ProfWin *window, const char *const command, gchar **args); diff --git a/src/common.c b/src/common.c index a3893c06..3e1b51b5 100644 --- a/src/common.c +++ b/src/common.c @@ -1,7 +1,7 @@ /* * common.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -46,6 +46,7 @@ #include <curl/curl.h> #include <curl/easy.h> #include <glib.h> +#include <gio/gio.h> #ifdef HAVE_NCURSESW_NCURSES_H #include <ncursesw/ncurses.h> @@ -55,7 +56,6 @@ #include "log.h" #include "common.h" -#include "tools/p_sha1.h" struct curl_data_t { @@ -63,8 +63,6 @@ struct curl_data_t size_t size; }; -static unsigned long unique_id = 0; - static size_t _data_callback(void *ptr, size_t size, size_t nmemb, void *data); gboolean @@ -107,28 +105,16 @@ mkdir_recursive(const char *dir) } gboolean -copy_file(const char *const sourcepath, const char *const targetpath) +copy_file(const char *const sourcepath, const char *const targetpath, const gboolean overwrite_existing) { - int ch; - FILE *source = fopen(sourcepath, "rb"); - if (source == NULL) { - return FALSE; - } - - FILE *target = fopen(targetpath, "wb"); - if (target == NULL) { - fclose(source); - return FALSE; - } - - while((ch = fgetc(source)) != EOF) { - fputc(ch, target); - } - - fclose(source); - fclose(target); - - return TRUE; + GFile *source = g_file_new_for_path(sourcepath); + GFile *dest = g_file_new_for_path(targetpath); + GError *error = NULL; + GFileCopyFlags flags = overwrite_existing ? G_FILE_COPY_OVERWRITE : G_FILE_COPY_NONE; + gboolean success = g_file_copy (source, dest, flags, NULL, NULL, NULL, &error); + g_object_unref(source); + g_object_unref(dest); + return success; } char* @@ -332,46 +318,6 @@ release_is_new(char *found_version) } } -char* -create_unique_id(char *prefix) -{ - char *result = NULL; - GString *result_str = g_string_new(""); - - unique_id++; - if (prefix) { - g_string_printf(result_str, "prof_%s_%lu", prefix, unique_id); - } else { - g_string_printf(result_str, "prof_%lu", unique_id); - } - result = result_str->str; - g_string_free(result_str, FALSE); - - return result; -} - -void -reset_unique_id(void) -{ - unique_id = 0; -} - -char* -p_sha1_hash(char *str) -{ - P_SHA1_CTX ctx; - uint8_t digest[20]; - uint8_t *input = (uint8_t*)malloc(strlen(str) + 1); - memcpy(input, str, strlen(str) + 1); - - P_SHA1_Init(&ctx); - P_SHA1_Update(&ctx, input, strlen(str)); - P_SHA1_Final(&ctx, digest); - - free(input); - return g_base64_encode(digest, sizeof(digest)); -} - static size_t _data_callback(void *ptr, size_t size, size_t nmemb, void *data) { diff --git a/src/common.h b/src/common.h index a53fdf9c..6d4ca39c 100644 --- a/src/common.h +++ b/src/common.h @@ -1,7 +1,7 @@ /* * common.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -82,7 +82,7 @@ typedef enum { gboolean create_dir(char *name); gboolean mkdir_recursive(const char *dir); -gboolean copy_file(const char *const src, const char *const target); +gboolean copy_file(const char *const src, const char *const target, const gboolean overwrite_existing); char* str_replace(const char *string, const char *substr, const char *replacement); int str_contains(const char str[], int size, char ch); gboolean strtoi_range(char *str, int *saveptr, int min, int max, char **err_msg); @@ -92,10 +92,6 @@ char* file_getline(FILE *stream); char* release_get_latest(void); gboolean release_is_new(char *found_version); -char* p_sha1_hash(char *str); -char* create_unique_id(char *prefix); -void reset_unique_id(void); - char* get_file_or_linked(char *loc, char *basedir); char* strip_arg_quotes(const char *const input); gboolean is_notify_enabled(void); diff --git a/src/config/account.c b/src/config/account.c index 705a5edf..93ba5078 100644 --- a/src/config/account.c +++ b/src/config/account.c @@ -1,7 +1,7 @@ /* * account.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -241,3 +241,20 @@ account_free(ProfAccount *account) g_list_free_full(account->otr_always, g_free); free(account); } + +void account_set_server(ProfAccount *account, const char *server) +{ + free(account->server); + account->server = strdup(server); +} + +void account_set_port(ProfAccount *account, int port) +{ + account->port = port; +} + +void account_set_tls_policy(ProfAccount *account, const char *tls_policy) +{ + free(account->tls_policy); + account->tls_policy = strdup(tls_policy); +} diff --git a/src/config/account.h b/src/config/account.h index 1262e518..68264c47 100644 --- a/src/config/account.h +++ b/src/config/account.h @@ -1,7 +1,7 @@ /* * account.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -77,5 +77,8 @@ ProfAccount* account_new(const gchar *const name, const gchar *const jid, char* account_create_connect_jid(ProfAccount *account); gboolean account_eval_password(ProfAccount *account); void account_free(ProfAccount *account); +void account_set_server(ProfAccount *account, const char *server); +void account_set_port(ProfAccount *account, int port); +void account_set_tls_policy(ProfAccount *account, const char *tls_policy); #endif diff --git a/src/config/accounts.c b/src/config/accounts.c index de898dd7..f53f53c9 100644 --- a/src/config/accounts.c +++ b/src/config/accounts.c @@ -1,7 +1,7 @@ /* * accounts.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -291,6 +291,7 @@ accounts_get_account(const char *const name) gchar *tls_policy = g_key_file_get_string(accounts, name, "tls.policy", NULL); if (tls_policy && ((g_strcmp0(tls_policy, "force") != 0) && (g_strcmp0(tls_policy, "allow") != 0) && + (g_strcmp0(tls_policy, "trust") != 0) && (g_strcmp0(tls_policy, "disable") != 0) && (g_strcmp0(tls_policy, "legacy") != 0))) { g_free(tls_policy); diff --git a/src/config/accounts.h b/src/config/accounts.h index c6a87c44..d41fb53e 100644 --- a/src/config/accounts.h +++ b/src/config/accounts.h @@ -1,7 +1,7 @@ /* * accounts.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/config/conflists.c b/src/config/conflists.c index 0d368757..e6416924 100644 --- a/src/config/conflists.c +++ b/src/config/conflists.c @@ -1,7 +1,7 @@ /* * conflists.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/config/conflists.h b/src/config/conflists.h index 0e46fb00..3b653834 100644 --- a/src/config/conflists.h +++ b/src/config/conflists.h @@ -1,7 +1,7 @@ /* * conflists.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/config/files.c b/src/config/files.c index e8de2edb..cd1c914f 100644 --- a/src/config/files.c +++ b/src/config/files.c @@ -1,7 +1,7 @@ /* * files.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/config/files.h b/src/config/files.h index 2eec9772..1d8d2890 100644 --- a/src/config/files.h +++ b/src/config/files.h @@ -1,7 +1,7 @@ /* * files.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/config/preferences.c b/src/config/preferences.c index e62c552c..265e11db 100644 --- a/src/config/preferences.c +++ b/src/config/preferences.c @@ -1,7 +1,7 @@ /* * preferences.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -123,7 +123,7 @@ prefs_load(void) g_key_file_set_string(prefs, PREF_GROUP_UI, "time.console", val); g_key_file_set_string(prefs, PREF_GROUP_UI, "time.chat", val); g_key_file_set_string(prefs, PREF_GROUP_UI, "time.muc", val); - g_key_file_set_string(prefs, PREF_GROUP_UI, "time.mucconfig", val); + g_key_file_set_string(prefs, PREF_GROUP_UI, "time.config", val); g_key_file_set_string(prefs, PREF_GROUP_UI, "time.private", val); g_key_file_set_string(prefs, PREF_GROUP_UI, "time.xmlconsole", val); g_key_file_remove_key(prefs, PREF_GROUP_UI, "time", NULL); @@ -1567,7 +1567,7 @@ _get_group(preference_t pref) case PREF_TIME_CONSOLE: case PREF_TIME_CHAT: case PREF_TIME_MUC: - case PREF_TIME_MUCCONFIG: + case PREF_TIME_CONFIG: case PREF_TIME_PRIVATE: case PREF_TIME_XMLCONSOLE: case PREF_TIME_STATUSBAR: @@ -1777,8 +1777,8 @@ _get_key(preference_t pref) return "time.chat"; case PREF_TIME_MUC: return "time.muc"; - case PREF_TIME_MUCCONFIG: - return "time.mucconfig"; + case PREF_TIME_CONFIG: + return "time.config"; case PREF_TIME_PRIVATE: return "time.private"; case PREF_TIME_XMLCONSOLE: @@ -1967,7 +1967,7 @@ _get_default_string(preference_t pref) return "%H:%M:%S"; case PREF_TIME_MUC: return "%H:%M:%S"; - case PREF_TIME_MUCCONFIG: + case PREF_TIME_CONFIG: return "%H:%M:%S"; case PREF_TIME_PRIVATE: return "%H:%M:%S"; diff --git a/src/config/preferences.h b/src/config/preferences.h index bafe4a1f..65dee327 100644 --- a/src/config/preferences.h +++ b/src/config/preferences.h @@ -1,7 +1,7 @@ /* * preferences.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -92,7 +92,7 @@ typedef enum { PREF_TIME_CONSOLE, PREF_TIME_CHAT, PREF_TIME_MUC, - PREF_TIME_MUCCONFIG, + PREF_TIME_CONFIG, PREF_TIME_PRIVATE, PREF_TIME_XMLCONSOLE, PREF_TIME_STATUSBAR, diff --git a/src/config/scripts.c b/src/config/scripts.c index 5980dcaa..aea914b4 100644 --- a/src/config/scripts.c +++ b/src/config/scripts.c @@ -1,7 +1,7 @@ /* * scripts.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/config/scripts.h b/src/config/scripts.h index 508a43c2..ef306c37 100644 --- a/src/config/scripts.h +++ b/src/config/scripts.h @@ -1,7 +1,7 @@ /* * scripts.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/config/theme.c b/src/config/theme.c index 13f9cc2b..a94cfb21 100644 --- a/src/config/theme.c +++ b/src/config/theme.c @@ -1,7 +1,7 @@ /* * theme.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -413,7 +413,7 @@ _load_preferences(void) _set_string_preference("time.console", PREF_TIME_CONSOLE); _set_string_preference("time.chat", PREF_TIME_CHAT); _set_string_preference("time.muc", PREF_TIME_MUC); - _set_string_preference("time.mucconfig", PREF_TIME_MUCCONFIG); + _set_string_preference("time.config", PREF_TIME_CONFIG); _set_string_preference("time.private", PREF_TIME_PRIVATE); _set_string_preference("time.xmlconsole", PREF_TIME_XMLCONSOLE); _set_string_preference("time.statusbar", PREF_TIME_STATUSBAR); diff --git a/src/config/theme.h b/src/config/theme.h index c1d9870e..69584b30 100644 --- a/src/config/theme.h +++ b/src/config/theme.h @@ -1,7 +1,7 @@ /* * theme.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/config/tlscerts.c b/src/config/tlscerts.c index 23f6575c..95a256b5 100644 --- a/src/config/tlscerts.c +++ b/src/config/tlscerts.c @@ -1,7 +1,7 @@ /* * tlscerts.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/config/tlscerts.h b/src/config/tlscerts.h index 2fd568ad..fcde7db0 100644 --- a/src/config/tlscerts.h +++ b/src/config/tlscerts.h @@ -1,7 +1,7 @@ /* * tlscerts.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/event/client_events.c b/src/event/client_events.c index 94f75ba5..3b6218ea 100644 --- a/src/event/client_events.c +++ b/src/event/client_events.c @@ -1,7 +1,7 @@ /* * client_events.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/event/client_events.h b/src/event/client_events.h index 098f2648..346cb8ff 100644 --- a/src/event/client_events.h +++ b/src/event/client_events.h @@ -1,7 +1,7 @@ /* * client_events.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/event/server_events.c b/src/event/server_events.c index b735c22f..5dfa652f 100644 --- a/src/event/server_events.c +++ b/src/event/server_events.c @@ -1,7 +1,7 @@ /* * server_events.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -896,8 +896,8 @@ sv_ev_muc_occupant_online(const char *const room, const char *const nick, const ProfMucWin *mucwin = wins_get_muc(room); if (mucwin) { mucwin_occupant_nick_change(mucwin, old_nick, nick); + wins_private_nick_change(mucwin->roomjid, old_nick, nick); } - wins_private_nick_change(mucwin->roomjid, old_nick, nick); free(old_nick); occupantswin_occupants(room); @@ -914,11 +914,13 @@ sv_ev_muc_occupant_online(const char *const room, const char *const nick, const } prefs_free_string(muc_status_pref); - Jid *jidp = jid_create_from_bare_and_resource(mucwin->roomjid, nick); - ProfPrivateWin *privwin = wins_get_private(jidp->fulljid); - jid_destroy(jidp); - if (privwin) { - privwin_occupant_online(privwin); + if (mucwin) { + Jid *jidp = jid_create_from_bare_and_resource(mucwin->roomjid, nick); + ProfPrivateWin *privwin = wins_get_private(jidp->fulljid); + jid_destroy(jidp); + if (privwin) { + privwin_occupant_online(privwin); + } } occupantswin_occupants(room); diff --git a/src/event/server_events.h b/src/event/server_events.h index bbbee8a2..cc261487 100644 --- a/src/event/server_events.h +++ b/src/event/server_events.h @@ -1,7 +1,7 @@ /* * server_events.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/log.c b/src/log.c index 78306c3c..0133a6cf 100644 --- a/src/log.c +++ b/src/log.c @@ -1,7 +1,7 @@ /* * log.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -228,7 +228,7 @@ _rotate_log_file(void) size_t len = strlen(log_file); char *log_file_new = malloc(len + 3); - strncpy(log_file_new, log_file, len); + memcpy(log_file_new, log_file, len); log_file_new[len] = '.'; log_file_new[len+1] = '1'; log_file_new[len+2] = 0; diff --git a/src/log.h b/src/log.h index a4c44ef6..43a34ca1 100644 --- a/src/log.h +++ b/src/log.h @@ -1,7 +1,7 @@ /* * log.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/main.c b/src/main.c index 91e17a9c..d2392a2b 100644 --- a/src/main.c +++ b/src/main.c @@ -1,7 +1,7 @@ /* * main.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/otr/otr.c b/src/otr/otr.c index e84f0ca2..47d5adf6 100644 --- a/src/otr/otr.c +++ b/src/otr/otr.c @@ -1,7 +1,7 @@ /* * otr.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/otr/otr.h b/src/otr/otr.h index 1ac99a75..b595df50 100644 --- a/src/otr/otr.h +++ b/src/otr/otr.h @@ -1,7 +1,7 @@ /* * otr.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/otr/otrlib.h b/src/otr/otrlib.h index ba1440c3..4add81b1 100644 --- a/src/otr/otrlib.h +++ b/src/otr/otrlib.h @@ -1,7 +1,7 @@ /* * otrlib.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/otr/otrlibv3.c b/src/otr/otrlibv3.c index c1328ecf..a2348c5c 100644 --- a/src/otr/otrlibv3.c +++ b/src/otr/otrlibv3.c @@ -1,7 +1,7 @@ /* * otrlibv3.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/otr/otrlibv4.c b/src/otr/otrlibv4.c index dfcb4529..176d9a42 100644 --- a/src/otr/otrlibv4.c +++ b/src/otr/otrlibv4.c @@ -1,7 +1,7 @@ /* * otrlibv4.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/pgp/gpg.c b/src/pgp/gpg.c index bfebe8bd..8d2c1eab 100644 --- a/src/pgp/gpg.c +++ b/src/pgp/gpg.c @@ -1,7 +1,7 @@ /* * gpg.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/pgp/gpg.h b/src/pgp/gpg.h index 4a7d27b1..580e108a 100644 --- a/src/pgp/gpg.h +++ b/src/pgp/gpg.h @@ -1,7 +1,7 @@ /* * gpg.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/plugins/api.c b/src/plugins/api.c index d30914dc..4d8434e1 100644 --- a/src/plugins/api.c +++ b/src/plugins/api.c @@ -1,7 +1,7 @@ /* * api.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/plugins/api.h b/src/plugins/api.h index 0f4881f0..0ba89f59 100644 --- a/src/plugins/api.h +++ b/src/plugins/api.h @@ -1,7 +1,7 @@ /* * api.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/plugins/autocompleters.c b/src/plugins/autocompleters.c index 040fcf4d..814253dd 100644 --- a/src/plugins/autocompleters.c +++ b/src/plugins/autocompleters.c @@ -1,7 +1,7 @@ /* * autocompleters.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/plugins/autocompleters.h b/src/plugins/autocompleters.h index edb076f4..dd811894 100644 --- a/src/plugins/autocompleters.h +++ b/src/plugins/autocompleters.h @@ -1,7 +1,7 @@ /* * autocompleters.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/plugins/c_api.c b/src/plugins/c_api.c index f3679d8f..3578d8f0 100644 --- a/src/plugins/c_api.c +++ b/src/plugins/c_api.c @@ -1,7 +1,7 @@ /* * c_api.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/plugins/c_api.h b/src/plugins/c_api.h index 8416ca20..dbce52e7 100644 --- a/src/plugins/c_api.h +++ b/src/plugins/c_api.h @@ -1,7 +1,7 @@ /* * c_api.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/plugins/c_plugins.c b/src/plugins/c_plugins.c index 44010e95..5a3b5957 100644 --- a/src/plugins/c_plugins.c +++ b/src/plugins/c_plugins.c @@ -1,7 +1,7 @@ /* * c_plugins.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/plugins/c_plugins.h b/src/plugins/c_plugins.h index 4098170a..a82e92cc 100644 --- a/src/plugins/c_plugins.h +++ b/src/plugins/c_plugins.h @@ -1,7 +1,7 @@ /* * c_plugins.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/plugins/callbacks.c b/src/plugins/callbacks.c index d197a44b..c2e79ff1 100644 --- a/src/plugins/callbacks.c +++ b/src/plugins/callbacks.c @@ -1,7 +1,7 @@ /* * callbacks.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/plugins/callbacks.h b/src/plugins/callbacks.h index 23edd8eb..783f073e 100644 --- a/src/plugins/callbacks.h +++ b/src/plugins/callbacks.h @@ -1,7 +1,7 @@ /* * callbacks.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/plugins/disco.c b/src/plugins/disco.c index a2889f9a..ae97a758 100644 --- a/src/plugins/disco.c +++ b/src/plugins/disco.c @@ -1,7 +1,7 @@ /* * disco.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/plugins/disco.h b/src/plugins/disco.h index 07c6a946..ab19e2a0 100644 --- a/src/plugins/disco.h +++ b/src/plugins/disco.h @@ -1,7 +1,7 @@ /* * disco.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/plugins/plugins.c b/src/plugins/plugins.c index 5ec90d0c..41885541 100644 --- a/src/plugins/plugins.c +++ b/src/plugins/plugins.c @@ -1,7 +1,7 @@ /* * plugins.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -34,6 +34,7 @@ #include <string.h> #include <stdlib.h> +#include <gio/gio.h> #include "log.h" #include "config.h" @@ -149,16 +150,19 @@ plugins_install_all(const char *const path) get_file_paths_recursive(path, &contents); GSList *curr = contents; + GString *error_message = NULL; while (curr) { + error_message = g_string_new(NULL); if (g_str_has_suffix(curr->data, ".py") || g_str_has_suffix(curr->data, ".so")) { gchar *plugin_name = g_path_get_basename(curr->data); - if (plugins_install(plugin_name, curr->data)) { + if (plugins_install(plugin_name, curr->data, error_message)) { result->installed = g_slist_append(result->installed, strdup(curr->data)); } else { result->failed = g_slist_append(result->failed, strdup(curr->data)); } } curr = g_slist_next(curr); + g_string_free(error_message, TRUE); } g_slist_free_full(contents, g_free); @@ -167,7 +171,25 @@ plugins_install_all(const char *const path) } gboolean -plugins_install(const char *const plugin_name, const char *const filename) +plugins_uninstall(const char *const plugin_name) +{ + plugins_unload(plugin_name); + char *plugins_dir = files_get_data_path(DIR_PLUGINS); + GString *target_path = g_string_new(plugins_dir); + free(plugins_dir); + g_string_append(target_path, "/"); + g_string_append(target_path, plugin_name); + GFile *file = g_file_new_for_path(target_path->str); + GError *error = NULL; + gboolean result = g_file_delete(file, NULL, &error); + g_object_unref(file); + g_error_free(error); + g_string_free(target_path, TRUE); + return result; +} + +gboolean +plugins_install(const char *const plugin_name, const char *const filename, GString *error_message) { char *plugins_dir = files_get_data_path(DIR_PLUGINS); GString *target_path = g_string_new(plugins_dir); @@ -175,18 +197,19 @@ plugins_install(const char *const plugin_name, const char *const filename) g_string_append(target_path, "/"); g_string_append(target_path, plugin_name); - ProfPlugin *plugin = g_hash_table_lookup(plugins, plugin_name); - if (plugin) { - plugins_unload(plugin_name); + if (g_file_test (target_path->str, G_FILE_TEST_EXISTS)) + { + log_info("Failed to install plugin: %s, file exists", plugin_name); + g_string_assign(error_message, "File exists"); + return FALSE; } - gboolean result = copy_file(filename, target_path->str); + gboolean result = copy_file(filename, target_path->str, false); g_string_free(target_path, TRUE); if (result) { result = plugins_load(plugin_name); } - return result; } diff --git a/src/plugins/plugins.h b/src/plugins/plugins.h index 16d6874a..4267cb22 100644 --- a/src/plugins/plugins.h +++ b/src/plugins/plugins.h @@ -1,7 +1,7 @@ /* * plugins.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -114,7 +114,9 @@ void plugins_shutdown(void); void plugins_free_install_result(PluginsInstallResult *result); -gboolean plugins_install(const char *const plugin_name, const char *const filename); +gboolean plugins_install(const char *const plugin_name, const char *const filename, GString * error_message); +gboolean plugins_uninstall(const char *const plugin_name); +gboolean plugins_update(const char *const plugin_name, const char *const filename, GString * error_message); PluginsInstallResult* plugins_install_all(const char *const path); gboolean plugins_load(const char *const name); GSList* plugins_load_all(void); diff --git a/src/plugins/profapi.c b/src/plugins/profapi.c index 11b9d154..53e175f9 100644 --- a/src/plugins/profapi.c +++ b/src/plugins/profapi.c @@ -1,7 +1,7 @@ /* * prof_api.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/plugins/profapi.h b/src/plugins/profapi.h index 48d9f189..68469b30 100644 --- a/src/plugins/profapi.h +++ b/src/plugins/profapi.h @@ -1,7 +1,7 @@ /* * prof_api.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/plugins/python_api.c b/src/plugins/python_api.c index 086ccbfb..99a96634 100644 --- a/src/plugins/python_api.c +++ b/src/plugins/python_api.c @@ -1,7 +1,7 @@ /* * python_api.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/plugins/python_api.h b/src/plugins/python_api.h index 8133c853..cf34c1e6 100644 --- a/src/plugins/python_api.h +++ b/src/plugins/python_api.h @@ -1,7 +1,7 @@ /* * python_api.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/plugins/python_plugins.c b/src/plugins/python_plugins.c index 6f7c2158..a6339793 100644 --- a/src/plugins/python_plugins.c +++ b/src/plugins/python_plugins.c @@ -1,7 +1,7 @@ /* * python_plugins.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/plugins/python_plugins.h b/src/plugins/python_plugins.h index 587d13d7..b5083ff0 100644 --- a/src/plugins/python_plugins.h +++ b/src/plugins/python_plugins.h @@ -1,7 +1,7 @@ /* * python_plugins.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/plugins/settings.c b/src/plugins/settings.c index e4286f22..6f4d37c5 100644 --- a/src/plugins/settings.c +++ b/src/plugins/settings.c @@ -1,7 +1,7 @@ /* * settings.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/plugins/settings.h b/src/plugins/settings.h index 3a81b2d1..cbff1bbf 100644 --- a/src/plugins/settings.h +++ b/src/plugins/settings.h @@ -1,7 +1,7 @@ /* * settings.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/plugins/themes.c b/src/plugins/themes.c index 85c26290..756a9793 100644 --- a/src/plugins/themes.c +++ b/src/plugins/themes.c @@ -1,7 +1,7 @@ /* * themes.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/plugins/themes.h b/src/plugins/themes.h index 4feb9f2e..470f7926 100644 --- a/src/plugins/themes.h +++ b/src/plugins/themes.h @@ -1,7 +1,7 @@ /* * themes.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/profanity.c b/src/profanity.c index 25bb5b42..1d4a2c35 100644 --- a/src/profanity.c +++ b/src/profanity.c @@ -1,7 +1,7 @@ /* * profanity.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/profanity.h b/src/profanity.h index 378eeddb..cf3040b5 100644 --- a/src/profanity.h +++ b/src/profanity.h @@ -1,7 +1,7 @@ /* * profanity.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/tools/autocomplete.c b/src/tools/autocomplete.c index 00f29fe0..79312e53 100644 --- a/src/tools/autocomplete.c +++ b/src/tools/autocomplete.c @@ -1,7 +1,7 @@ /* * autocomplete.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/tools/autocomplete.h b/src/tools/autocomplete.h index 64141b35..78bec44d 100644 --- a/src/tools/autocomplete.h +++ b/src/tools/autocomplete.h @@ -1,7 +1,7 @@ /* * autocomplete.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/tools/http_upload.c b/src/tools/http_upload.c index fc4c60f3..bebb7239 100644 --- a/src/tools/http_upload.c +++ b/src/tools/http_upload.c @@ -1,7 +1,7 @@ /* * http_upload.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/tools/http_upload.h b/src/tools/http_upload.h index 145207a4..7d61ea74 100644 --- a/src/tools/http_upload.h +++ b/src/tools/http_upload.h @@ -1,7 +1,7 @@ /* * http_upload.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/tools/p_sha1.c b/src/tools/p_sha1.c deleted file mode 100644 index 11adede3..00000000 --- a/src/tools/p_sha1.c +++ /dev/null @@ -1,403 +0,0 @@ -/** @file - * SHA-1 hash. - */ - -/* -SHA-1 in C -By Steve Reid <sreid@sea-to-sky.net> -100% Public Domain - ------------------ -Modified 7/98 -By James H. Brown <jbrown@burgoyne.com> -Still 100% Public Domain - -Corrected a problem which generated improper hash values on 16 bit machines -Routine SHA1Update changed from - void SHA1Update(P_SHA1_CTX* context, unsigned char* data, unsigned int -len) -to - void SHA1Update(P_SHA1_CTX* context, unsigned char* data, unsigned -long len) - -The 'len' parameter was declared an int which works fine on 32 bit machines. -However, on 16 bit machines an int is too small for the shifts being done -against -it. This caused the hash function to generate incorrect values if len was -greater than 8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update(). - -Since the file IO in main() reads 16K at a time, any file 8K or larger would -be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million -"a"s). - -I also changed the declaration of variables i & j in SHA1Update to -unsigned long from unsigned int for the same reason. - -These changes should make no difference to any 32 bit implementations since -an -int and a long are the same size in those environments. - --- -I also corrected a few compiler warnings generated by Borland C. -1. Added #include <process.h> for exit() prototype -2. Removed unused variable 'j' in SHA1Final -3. Changed exit(0) to return(0) at end of main. - -ALL changes I made can be located by searching for comments containing 'JHB' ------------------ -Modified 8/98 -By Steve Reid <sreid@sea-to-sky.net> -Still 100% public domain - -1- Removed #include <process.h> and used return() instead of exit() -2- Fixed overwriting of finalcount in SHA1Final() (discovered by Chris Hall) -3- Changed email address from steve@edmweb.com to sreid@sea-to-sky.net - ------------------ -Modified 4/01 -By Saul Kravitz <Saul.Kravitz@celera.com> -Still 100% PD -Modified to run on Compaq Alpha hardware. - ------------------ -Modified 07/2002 -By Ralph Giles <giles@artofcode.com> -Still 100% public domain -modified for use with stdint types, autoconf -code cleanup, removed attribution comments -switched SHA1Final() argument order for consistency -use SHA1_ prefix for public api -move public api to sha1.h -*/ - -/* -Test Vectors (from FIPS PUB 180-1) -"abc" - A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D -"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" - 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 -A million repetitions of "a" - 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F -*/ - -/* #define SHA1HANDSOFF */ - -#include <stdio.h> -#include <string.h> - -/* make sure the stdint.h types are available */ -#if defined(_MSC_VER) /* Microsoft Visual C++ */ - typedef signed char int8_t; - typedef short int int16_t; - typedef int int32_t; - typedef __int64 int64_t; - typedef unsigned char uint8_t; - typedef unsigned short int uint16_t; - typedef unsigned int uint32_t; - /* no uint64_t */ -#else -#include <stdint.h> -#endif - -#include "p_sha1.h" - -static uint32_t host_to_be(uint32_t i); -void P_SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]); - -#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) - -/* blk0() and blk() perform the initial expand. */ -/* I got the idea of expanding during the round function from SSLeay */ -#define blk0(i) (block->l[i] = host_to_be(block->l[i])) -#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ - ^block->l[(i+2)&15]^block->l[i&15],1)) - -/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ -#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); -#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); -#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); -#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); -#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); - - -#ifdef VERBOSE /* SAK */ -void SHAPrintContext(P_P_SHA1_CTX *context, char *msg){ - printf("%s (%d,%d) %x %x %x %x %x\n", - msg, - context->count[0], context->count[1], - context->state[0], - context->state[1], - context->state[2], - context->state[3], - context->state[4]); -} -#endif /* VERBOSE */ - -static uint32_t host_to_be(uint32_t i) -{ -#define le_to_be(i) ((rol((i),24) & 0xFF00FF00) | (rol((i),8) & 0x00FF00FF)) -#if defined(__BIG_ENDIAN__) || \ - (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \ - __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) - return i; -#elif defined(__LITTLE_ENDIAN__) || \ - (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \ - __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) - return le_to_be(i); -#else /* fallback to run-time check */ - static const union { - uint32_t u; - unsigned char c; - } check = {1}; - - return check.c ? le_to_be(i) : i; -#endif -} - -/* Hash a single 512-bit block. This is the core of the algorithm. */ -void P_SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]) -{ - uint32_t a, b, c, d, e; - typedef union { - uint8_t c[64]; - uint32_t l[16]; - } CHAR64LONG16; - CHAR64LONG16* block; - -#ifdef SHA1HANDSOFF - static uint8_t workspace[64]; - block = (CHAR64LONG16*)workspace; - memcpy(block, buffer, 64); -#else - block = (CHAR64LONG16*)buffer; -#endif - - /* Copy context->state[] to working vars */ - a = state[0]; - b = state[1]; - c = state[2]; - d = state[3]; - e = state[4]; - - /* 4 rounds of 20 operations each. Loop unrolled. */ - R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); - R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); - R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); - R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); - R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); - R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); - R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); - R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); - R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); - R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); - R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); - R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); - R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); - R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); - R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); - R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); - R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); - R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); - R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); - R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); - - /* Add the working vars back into context.state[] */ - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; - state[4] += e; - - /* Wipe variables */ - a = b = c = d = e = 0; -} - - -/* SHA1Init - Initialize new context */ -void P_SHA1_Init(P_SHA1_CTX* context) -{ - /* SHA1 initialization constants */ - context->state[0] = 0x67452301; - context->state[1] = 0xEFCDAB89; - context->state[2] = 0x98BADCFE; - context->state[3] = 0x10325476; - context->state[4] = 0xC3D2E1F0; - context->count[0] = context->count[1] = 0; -} - - -/* Run your data through this. */ -void P_SHA1_Update(P_SHA1_CTX* context, const uint8_t* data, const size_t len) -{ - size_t i, j; - -#ifdef VERBOSE - SHAPrintContext(context, "before"); -#endif - - j = (context->count[0] >> 3) & 63; - if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++; - context->count[1] += (len >> 29); - if ((j + len) > 63) { - memcpy(&context->buffer[j], data, (i = 64-j)); - P_SHA1_Transform(context->state, context->buffer); - for ( ; i + 63 < len; i += 64) { - P_SHA1_Transform(context->state, data + i); - } - j = 0; - } - else i = 0; - memcpy(&context->buffer[j], &data[i], len - i); - -#ifdef VERBOSE - SHAPrintContext(context, "after "); -#endif -} - - -/* Add padding and return the message digest. */ -void P_SHA1_Final(P_SHA1_CTX* context, uint8_t digest[P_SHA1_DIGEST_SIZE]) -{ - uint32_t i; - uint8_t finalcount[8]; - - for (i = 0; i < 8; i++) { - finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] - >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ - } - P_SHA1_Update(context, (uint8_t *)"\200", 1); - while ((context->count[0] & 504) != 448) { - P_SHA1_Update(context, (uint8_t *)"\0", 1); - } - P_SHA1_Update(context, finalcount, 8); /* Should cause a SHA1_Transform() */ - for (i = 0; i < P_SHA1_DIGEST_SIZE; i++) { - digest[i] = (uint8_t) - ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); - } - - /* Wipe variables */ - i = 0; - memset(context->buffer, 0, 64); - memset(context->state, 0, 20); - memset(context->count, 0, 8); - memset(finalcount, 0, 8); /* SWR */ - -#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite its own static vars */ - P_SHA1_Transform(context->state, context->buffer); -#endif -} - -/*************************************************************/ - -#if 0 -int main(int argc, char** argv) -{ -int i, j; -P_SHA1_CTX context; -unsigned char digest[P_SHA1_DIGEST_SIZE], buffer[16384]; -FILE* file; - - if (argc > 2) { - puts("Public domain SHA-1 implementation - by Steve Reid <sreid@sea-to-sky.net>"); - puts("Modified for 16 bit environments 7/98 - by James H. Brown <jbrown@burgoyne.com>"); /* JHB */ - puts("Produces the SHA-1 hash of a file, or stdin if no file is specified."); - return(0); - } - if (argc < 2) { - file = stdin; - } - else { - if (!(file = fopen(argv[1], "rb"))) { - fputs("Unable to open file.", stderr); - return(-1); - } - } - SHA1_Init(&context); - while (!feof(file)) { /* note: what if ferror(file) */ - i = fread(buffer, 1, 16384, file); - SHA1_Update(&context, buffer, i); - } - SHA1_Final(&context, digest); - fclose(file); - for (i = 0; i < P_SHA1_DIGEST_SIZE/4; i++) { - for (j = 0; j < 4; j++) { - printf("%02X", digest[i*4+j]); - } - putchar(' '); - } - putchar('\n'); - return(0); /* JHB */ -} -#endif - -/* self test */ - -#ifdef TEST - -static char *test_data[] = { - "abc", - "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", - "A million repetitions of 'a'"}; -static char *test_results[] = { - "A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D", - "84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1", - "34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F"}; - -void digest_to_hex(const uint8_t digest[P_SHA1_DIGEST_SIZE], char *output) -{ - int i,j; - char *c = output; - - for (i = 0; i < P_SHA1_DIGEST_SIZE/4; i++) { - for (j = 0; j < 4; j++) { - sprintf(c,"%02X", digest[i*4+j]); - c += 2; - } - sprintf(c, " "); - c += 1; - } - *(c - 1) = '\0'; -} - -int main(int argc, char** argv) -{ - int k; - P_SHA1_CTX context; - uint8_t digest[20]; - char output[80]; - - fprintf(stdout, "verifying SHA-1 implementation... "); - - for (k = 0; k < 2; k++){ - P_SHA1_Init(&context); - P_SHA1_Update(&context, (uint8_t*)test_data[k], strlen(test_data[k])); - P_SHA1_Final(&context, digest); - digest_to_hex(digest, output); - - if (strcmp(output, test_results[k])) { - fprintf(stdout, "FAIL\n"); - fprintf(stderr,"* hash of \"%s\" incorrect:\n", test_data[k]); - fprintf(stderr,"\t%s returned\n", output); - fprintf(stderr,"\t%s is correct\n", test_results[k]); - return (1); - } - } - /* million 'a' vector we feed separately */ - P_SHA1_Init(&context); - for (k = 0; k < 1000000; k++) - P_SHA1_Update(&context, (uint8_t*)"a", 1); - P_SHA1_Final(&context, digest); - digest_to_hex(digest, output); - if (strcmp(output, test_results[2])) { - fprintf(stdout, "FAIL\n"); - fprintf(stderr,"* hash of \"%s\" incorrect:\n", test_data[2]); - fprintf(stderr,"\t%s returned\n", output); - fprintf(stderr,"\t%s is correct\n", test_results[2]); - return (1); - } - - /* success */ - fprintf(stdout, "ok\n"); - return(0); -} -#endif /* TEST */ diff --git a/src/tools/p_sha1.h b/src/tools/p_sha1.h deleted file mode 100644 index 75443b01..00000000 --- a/src/tools/p_sha1.h +++ /dev/null @@ -1,31 +0,0 @@ -/* public api for steve reid's public domain SHA-1 implementation */ -/* this file is in the public domain */ - -/** @file - * SHA-1 hash API. - */ - -#ifndef __P_SHA1_H -#define __P_SHA1_H - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - uint32_t state[5]; - uint32_t count[2]; - uint8_t buffer[64]; -} P_SHA1_CTX; - -#define P_SHA1_DIGEST_SIZE 20 - -void P_SHA1_Init(P_SHA1_CTX* context); -void P_SHA1_Update(P_SHA1_CTX* context, const uint8_t* data, const size_t len); -void P_SHA1_Final(P_SHA1_CTX* context, uint8_t digest[P_SHA1_DIGEST_SIZE]); - -#ifdef __cplusplus -} -#endif - -#endif /* __P_SHA1_H */ diff --git a/src/tools/parser.c b/src/tools/parser.c index 74fef1e2..474a664e 100644 --- a/src/tools/parser.c +++ b/src/tools/parser.c @@ -1,7 +1,7 @@ /* * parser.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/tools/parser.h b/src/tools/parser.h index b099ce24..5d5c6028 100644 --- a/src/tools/parser.h +++ b/src/tools/parser.h @@ -1,7 +1,7 @@ /* * parser.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/tools/tinyurl.c b/src/tools/tinyurl.c index 36be4971..0750709f 100644 --- a/src/tools/tinyurl.c +++ b/src/tools/tinyurl.c @@ -1,7 +1,7 @@ /* * tinyurl.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/tools/tinyurl.h b/src/tools/tinyurl.h index 37e849c4..eb85f66f 100644 --- a/src/tools/tinyurl.h +++ b/src/tools/tinyurl.h @@ -1,7 +1,7 @@ /* * tinyurl.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/ui/buffer.c b/src/ui/buffer.c index 2d29ca65..b933ac8c 100644 --- a/src/ui/buffer.c +++ b/src/ui/buffer.c @@ -1,7 +1,7 @@ /* * buffer.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/ui/buffer.h b/src/ui/buffer.h index b16bcb51..243b003a 100644 --- a/src/ui/buffer.h +++ b/src/ui/buffer.h @@ -1,7 +1,7 @@ /* * buffer.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/ui/chatwin.c b/src/ui/chatwin.c index 31604db4..98431a60 100644 --- a/src/ui/chatwin.c +++ b/src/ui/chatwin.c @@ -1,7 +1,7 @@ /* * chatwin.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/ui/mucconfwin.c b/src/ui/confwin.c index 7a658a1e..042e0f8d 100644 --- a/src/ui/mucconfwin.c +++ b/src/ui/confwin.c @@ -1,7 +1,7 @@ /* - * mucconfwin.c + * confwin.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -40,10 +40,10 @@ #include "ui/win_types.h" #include "ui/window_list.h" -static void _mucconfwin_form_field(ProfWin *window, char *tag, FormField *field); +static void _confwin_form_field(ProfWin *window, char *tag, FormField *field); void -mucconfwin_show_form(ProfMucConfWin *confwin) +confwin_show_form(ProfConfWin *confwin) { ProfWin *window = (ProfWin*) confwin; if (confwin->form->title) { @@ -54,7 +54,7 @@ mucconfwin_show_form(ProfMucConfWin *confwin) } win_println(window, THEME_DEFAULT, '-', ""); - mucconfwin_form_help(confwin); + confwin_form_help(confwin); GSList *fields = confwin->form->fields; GSList *curr_field = fields; @@ -68,7 +68,7 @@ mucconfwin_show_form(ProfMucConfWin *confwin) } } else if (g_strcmp0(field->type, "hidden") != 0 && field->var) { char *tag = g_hash_table_lookup(confwin->form->var_to_tag, field->var); - _mucconfwin_form_field(window, tag, field); + _confwin_form_field(window, tag, field); } curr_field = g_slist_next(curr_field); @@ -76,35 +76,37 @@ mucconfwin_show_form(ProfMucConfWin *confwin) } void -mucconfwin_show_form_field(ProfMucConfWin *confwin, DataForm *form, char *tag) +confwin_show_form_field(ProfConfWin *confwin, DataForm *form, char *tag) { assert(confwin != NULL); FormField *field = form_get_field_by_tag(form, tag); ProfWin *window = (ProfWin*)confwin; - _mucconfwin_form_field(window, tag, field); + _confwin_form_field(window, tag, field); win_println(window, THEME_DEFAULT, '-', ""); } void -mucconfwin_handle_configuration(ProfMucConfWin *confwin, DataForm *form) +confwin_handle_configuration(ProfConfWin *confwin, DataForm *form) { assert(confwin != NULL); ProfWin *window = (ProfWin*)confwin; ui_focus_win(window); - mucconfwin_show_form(confwin); + confwin_show_form(confwin); win_println(window, THEME_DEFAULT, '-', ""); - win_println(window, THEME_DEFAULT, '-', "Use '/form submit' to save changes."); + if (confwin->submit != NULL) { + win_println(window, THEME_DEFAULT, '-', "Use '/form submit' to save changes."); + } win_println(window, THEME_DEFAULT, '-', "Use '/form cancel' to cancel changes."); win_println(window, THEME_DEFAULT, '-', "See '/form help' for more information."); win_println(window, THEME_DEFAULT, '-', ""); } void -mucconfwin_field_help(ProfMucConfWin *confwin, char *tag) +confwin_field_help(ProfConfWin *confwin, char *tag) { assert(confwin != NULL); @@ -187,7 +189,7 @@ mucconfwin_field_help(ProfMucConfWin *confwin, char *tag) } void -mucconfwin_form_help(ProfMucConfWin *confwin) +confwin_form_help(ProfConfWin *confwin) { assert(confwin != NULL); @@ -200,7 +202,7 @@ mucconfwin_form_help(ProfMucConfWin *confwin) } static void -_mucconfwin_form_field(ProfWin *window, char *tag, FormField *field) +_confwin_form_field(ProfWin *window, char *tag, FormField *field) { win_print(window, THEME_AWAY, '-', "[%s] ", tag); win_append(window, THEME_DEFAULT, "%s", field->label); @@ -258,7 +260,7 @@ _mucconfwin_form_field(ProfWin *window, char *tag, FormField *field) if (value == NULL) { win_appendln(window, THEME_OFFLINE, "FALSE"); } else { - if (g_strcmp0(value, "0") == 0) { + if (g_strcmp0(value, "0") == 0 || g_strcmp0(value, "false") == 0) { win_appendln(window, THEME_OFFLINE, "FALSE"); } else { win_appendln(window, THEME_ONLINE, "TRUE"); @@ -331,7 +333,7 @@ _mucconfwin_form_field(ProfWin *window, char *tag, FormField *field) } char* -mucconfwin_get_string(ProfMucConfWin *confwin) +confwin_get_string(ProfConfWin *confwin) { assert(confwin != NULL); diff --git a/src/ui/console.c b/src/ui/console.c index 9bead705..e5c12158 100644 --- a/src/ui/console.c +++ b/src/ui/console.c @@ -1,7 +1,7 @@ /* * console.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -1282,12 +1282,12 @@ cons_time_setting(void) cons_show("Time MUC (/time) : %s", pref_time_muc); prefs_free_string(pref_time_muc); - char *pref_time_mucconf = prefs_get_string(PREF_TIME_MUCCONFIG); - if (g_strcmp0(pref_time_mucconf, "off") == 0) - cons_show("Time MUC config (/time) : OFF"); + char *pref_time_conf = prefs_get_string(PREF_TIME_CONFIG); + if (g_strcmp0(pref_time_conf, "off") == 0) + cons_show("Time config (/time) : OFF"); else - cons_show("Time MUC config (/time) : %s", pref_time_mucconf); - prefs_free_string(pref_time_mucconf); + cons_show("Time config (/time) : %s", pref_time_conf); + prefs_free_string(pref_time_conf); char *pref_time_private = prefs_get_string(PREF_TIME_PRIVATE); if (g_strcmp0(pref_time_private, "off") == 0) @@ -2387,13 +2387,13 @@ _cons_splash_logo(void) ProfWin *console = wins_get_console(); win_println(console, THEME_DEFAULT, '-', "Welcome to"); - win_println(console, THEME_SPLASH, '-', " ___ _ "); - win_println(console, THEME_SPLASH, '-', " / __) (_)_ "); - win_println(console, THEME_SPLASH, '-', " ____ ____ ___ | |__ ____ ____ _| |_ _ _ "); - win_println(console, THEME_SPLASH, '-', "| _ \\ / ___) _ \\| __) _ | _ \\| | _) | | |"); - win_println(console, THEME_SPLASH, '-', "| | | | | | |_| | | ( ( | | | | | | |_| |_| |"); - win_println(console, THEME_SPLASH, '-', "| ||_/|_| \\___/|_| \\_||_|_| |_|_|\\___)__ |"); - win_println(console, THEME_SPLASH, '-', "|_| (____/ "); + win_println(console, THEME_SPLASH, '-', " ___ _ "); + win_println(console, THEME_SPLASH, '-', " / __) (_)_ "); + win_println(console, THEME_SPLASH, '-', " ____ ___ ___ | |__ ____ ____ _| |_ _ _ "); + win_println(console, THEME_SPLASH, '-', "| _ \\ / __) _ \\| __) _ | _ \\| | _) | | |"); + win_println(console, THEME_SPLASH, '-', "| | ) | | | (_) | | | ( | | | | | | |_| |_| |"); + win_println(console, THEME_SPLASH, '-', "| ||_/|_| \\___/|_| \\_||_|_| |_|_|\\___)__ |"); + win_println(console, THEME_SPLASH, '-', "|_| (____/ "); win_println(console, THEME_SPLASH, '-', ""); if (strcmp(PACKAGE_STATUS, "development") == 0) { diff --git a/src/ui/core.c b/src/ui/core.c index 5246d06a..3e141819 100644 --- a/src/ui/core.c +++ b/src/ui/core.c @@ -1,7 +1,7 @@ /* * core.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -632,8 +632,8 @@ ui_win_has_unsaved_form(int num) { ProfWin *window = wins_get_by_num(num); - if (window->type == WIN_MUC_CONFIG) { - ProfMucConfWin *confwin = (ProfMucConfWin*)window; + if (window->type == WIN_CONFIG) { + ProfConfWin *confwin = (ProfConfWin*)window; assert(confwin->memcheck == PROFCONFWIN_MEMCHECK); return confwin->form->modified; } else { @@ -651,13 +651,13 @@ ui_focus_win(ProfWin *window) } ProfWin *old_current = wins_get_current(); - if (old_current->type == WIN_MUC_CONFIG) { - ProfMucConfWin *confwin = (ProfMucConfWin*)old_current; + if (old_current->type == WIN_CONFIG) { + ProfConfWin *confwin = (ProfConfWin*)old_current; cmd_ac_remove_form_fields(confwin->form); } - if (window->type == WIN_MUC_CONFIG) { - ProfMucConfWin *confwin = (ProfMucConfWin*)window; + if (window->type == WIN_CONFIG) { + ProfConfWin *confwin = (ProfConfWin*)window; cmd_ac_add_form_fields(confwin->form); } @@ -681,8 +681,8 @@ void ui_close_win(int index) { ProfWin *window = wins_get_by_num(index); - if (window && window->type == WIN_MUC_CONFIG) { - ProfMucConfWin *confwin = (ProfMucConfWin*)window; + if (window && window->type == WIN_CONFIG) { + ProfConfWin *confwin = (ProfConfWin*)window; if (confwin->form) { cmd_ac_remove_form_fields(confwin->form); } @@ -1135,7 +1135,7 @@ ui_handle_room_config_submit_result(const char *const roomjid) GString *form_recipient = g_string_new(roomjid); g_string_append(form_recipient, " config"); - form_window = (ProfWin*) wins_get_muc_conf(form_recipient->str); + form_window = (ProfWin*) wins_get_conf(form_recipient->str); g_string_free(form_recipient, TRUE); if (form_window) { @@ -1167,7 +1167,7 @@ ui_handle_room_config_submit_result_error(const char *const roomjid, const char GString *form_recipient = g_string_new(roomjid); g_string_append(form_recipient, " config"); - form_window = (ProfWin*) wins_get_muc_conf(form_recipient->str); + form_window = (ProfWin*) wins_get_conf(form_recipient->str); g_string_free(form_recipient, TRUE); if (form_window) { diff --git a/src/ui/inputwin.c b/src/ui/inputwin.c index 654a4602..89d86faf 100644 --- a/src/ui/inputwin.c +++ b/src/ui/inputwin.c @@ -1,7 +1,7 @@ /* * inputwin.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -98,6 +98,7 @@ static void _inp_rl_linehandler(char *line); static int _inp_rl_tab_handler(int count, int key); static int _inp_rl_shift_tab_handler(int count, int key); static int _inp_rl_win_clear_handler(int count, int key); +static int _inp_rl_win_close_handler(int count, int key); static int _inp_rl_win_1_handler(int count, int key); static int _inp_rl_win_2_handler(int count, int key); static int _inp_rl_win_3_handler(int count, int key); @@ -387,6 +388,7 @@ _inp_rl_addfuncs(void) rl_add_funmap_entry("prof_subwin_pageup", _inp_rl_subwin_pageup_handler); rl_add_funmap_entry("prof_subwin_pagedown", _inp_rl_subwin_pagedown_handler); rl_add_funmap_entry("prof_win_clear", _inp_rl_win_clear_handler); + rl_add_funmap_entry("prof_win_close", _inp_rl_win_close_handler); } // Readline callbacks @@ -504,6 +506,15 @@ _inp_rl_win_clear_handler(int count, int key) } static int +_inp_rl_win_close_handler(int count, int key) +{ + ProfWin *win = wins_get_current(); + gchar* args = 0; + cmd_close(win, 0, &args); + return 0; +} + +static int _inp_rl_tab_handler(int count, int key) { if (rl_point != rl_end || !rl_line_buffer) { diff --git a/src/ui/inputwin.h b/src/ui/inputwin.h index db36cf70..af53694a 100644 --- a/src/ui/inputwin.h +++ b/src/ui/inputwin.h @@ -1,7 +1,7 @@ /* * inputwin.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/ui/mucwin.c b/src/ui/mucwin.c index f64a401e..fc13a9b1 100644 --- a/src/ui/mucwin.c +++ b/src/ui/mucwin.c @@ -1,7 +1,7 @@ /* * mucwin.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/ui/notifier.c b/src/ui/notifier.c index 452ae026..970d04eb 100644 --- a/src/ui/notifier.c +++ b/src/ui/notifier.c @@ -1,7 +1,7 @@ /* * notifier.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/ui/occupantswin.c b/src/ui/occupantswin.c index f6bb2197..ca507394 100644 --- a/src/ui/occupantswin.c +++ b/src/ui/occupantswin.c @@ -1,7 +1,7 @@ /* * occupantswin.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/ui/privwin.c b/src/ui/privwin.c index 8de59683..459c3e80 100644 --- a/src/ui/privwin.c +++ b/src/ui/privwin.c @@ -1,7 +1,7 @@ /* * privwin.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/ui/rosterwin.c b/src/ui/rosterwin.c index 3a38109d..89575e0d 100644 --- a/src/ui/rosterwin.c +++ b/src/ui/rosterwin.c @@ -1,7 +1,7 @@ /* * rosterwin.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/ui/screen.c b/src/ui/screen.c index 22548a75..dfb67ad9 100644 --- a/src/ui/screen.c +++ b/src/ui/screen.c @@ -1,7 +1,7 @@ /* * screen.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/ui/screen.h b/src/ui/screen.h index e382ab3e..f42cad46 100644 --- a/src/ui/screen.h +++ b/src/ui/screen.h @@ -1,7 +1,7 @@ /* * screen.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/ui/statusbar.c b/src/ui/statusbar.c index ac1d7498..d0ce7309 100644 --- a/src/ui/statusbar.c +++ b/src/ui/statusbar.c @@ -1,7 +1,7 @@ /* * statusbar.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -544,7 +544,7 @@ _display_name(StatusBarTab *tab) } else { fullname = strdup(tab->identifier); } - } else if (tab->window_type == WIN_MUC_CONFIG) { + } else if (tab->window_type == WIN_CONFIG) { char *pref = prefs_get_string(PREF_STATUSBAR_ROOM); GString *display_str = g_string_new(""); if (g_strcmp0("room", pref) == 0) { diff --git a/src/ui/statusbar.h b/src/ui/statusbar.h index de8b51cc..d97101e2 100644 --- a/src/ui/statusbar.h +++ b/src/ui/statusbar.h @@ -1,7 +1,7 @@ /* * statusbar.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/ui/titlebar.c b/src/ui/titlebar.c index 4f5383c2..f519fdd2 100644 --- a/src/ui/titlebar.c +++ b/src/ui/titlebar.c @@ -1,7 +1,7 @@ /* * titlebar.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/ui/titlebar.h b/src/ui/titlebar.h index 0aed4b2b..35c48040 100644 --- a/src/ui/titlebar.h +++ b/src/ui/titlebar.h @@ -1,7 +1,7 @@ /* * titlebar.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/ui/tray.c b/src/ui/tray.c index ecb0843b..4cdc2d2a 100644 --- a/src/ui/tray.c +++ b/src/ui/tray.c @@ -1,7 +1,7 @@ /* * tray.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/ui/tray.h b/src/ui/tray.h index c1e6ba77..b7b75fa9 100644 --- a/src/ui/tray.h +++ b/src/ui/tray.h @@ -1,7 +1,7 @@ /* * tray.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/ui/ui.h b/src/ui/ui.h index d344f855..ad5a1216 100644 --- a/src/ui/ui.h +++ b/src/ui/ui.h @@ -1,7 +1,7 @@ /* * ui.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -217,13 +217,13 @@ void privwin_room_kicked(ProfPrivateWin *privwin, const char *const actor, const void privwin_room_banned(ProfPrivateWin *privwin, const char *const actor, const char *const reason); void privwin_room_joined(ProfPrivateWin *privwin); -// MUC room config window -void mucconfwin_handle_configuration(ProfMucConfWin *confwin, DataForm *form); -void mucconfwin_show_form(ProfMucConfWin *confwin); -void mucconfwin_show_form_field(ProfMucConfWin *confwin, DataForm *form, char *tag); -void mucconfwin_form_help(ProfMucConfWin *confwin); -void mucconfwin_field_help(ProfMucConfWin *confwin, char *tag); -char* mucconfwin_get_string(ProfMucConfWin *confwin); +// config window +void confwin_handle_configuration(ProfConfWin *confwin, DataForm *form); +void confwin_show_form(ProfConfWin *confwin); +void confwin_show_form_field(ProfConfWin *confwin, DataForm *form, char *tag); +void confwin_form_help(ProfConfWin *confwin); +void confwin_field_help(ProfConfWin *confwin, char *tag); +char* confwin_get_string(ProfConfWin *confwin); // xml console void xmlwin_show(ProfXMLWin *xmlwin, const char *const msg); @@ -346,7 +346,7 @@ ProfWin* win_create_console(void); ProfWin* win_create_xmlconsole(void); ProfWin* win_create_chat(const char *const barejid); ProfWin* win_create_muc(const char *const roomjid); -ProfWin* win_create_muc_config(const char *const title, DataForm *form); +ProfWin* win_create_config(const char *const title, DataForm *form, ProfConfWinCallback submit, ProfConfWinCallback cancel, const void *userdata); ProfWin* win_create_private(const char *const fulljid); ProfWin* win_create_plugin(const char *const plugin_name, const char *const tag); void win_update_virtual(ProfWin *window); @@ -377,6 +377,11 @@ void win_show_info(ProfWin *window, PContact contact); void win_clear(ProfWin *window); char* win_get_tab_identifier(ProfWin *window); char* win_to_string(ProfWin *window); +void win_command_list_error(ProfWin *window, const char *const error); +void win_command_exec_error(ProfWin *window, const char *const command, const char *const error, ...); +void win_handle_command_list(ProfWin *window, GSList *cmds); +void win_handle_command_exec_status(ProfWin *window, const char *const type, const char *const value); +void win_handle_command_exec_result_note(ProfWin *window, const char *const type, const char *const value); // desktop notifications void notifier_initialise(void); diff --git a/src/ui/win_types.h b/src/ui/win_types.h index 7fa75b34..92618a36 100644 --- a/src/ui/win_types.h +++ b/src/ui/win_types.h @@ -1,7 +1,7 @@ /* * win_types.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -128,7 +128,7 @@ typedef enum { WIN_CONSOLE, WIN_CHAT, WIN_MUC, - WIN_MUC_CONFIG, + WIN_CONFIG, WIN_PRIVATE, WIN_XML, WIN_PLUGIN @@ -172,12 +172,18 @@ typedef struct prof_muc_win_t { char *message_char; } ProfMucWin; -typedef struct prof_mucconf_win_t { +typedef struct prof_conf_win_t ProfConfWin; +typedef void (*ProfConfWinCallback)(ProfConfWin *); + +struct prof_conf_win_t { ProfWin window; char *roomjid; DataForm *form; unsigned long memcheck; -} ProfMucConfWin; + ProfConfWinCallback submit; + ProfConfWinCallback cancel; + const void *userdata; +}; typedef struct prof_private_win_t { ProfWin window; diff --git a/src/ui/window.c b/src/ui/window.c index 5543707d..cc2c2062 100644 --- a/src/ui/window.c +++ b/src/ui/window.c @@ -1,7 +1,7 @@ /* * window.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -203,13 +203,16 @@ win_create_muc(const char *const roomjid) } ProfWin* -win_create_muc_config(const char *const roomjid, DataForm *form) +win_create_config(const char *const roomjid, DataForm *form, ProfConfWinCallback submit, ProfConfWinCallback cancel, const void *userdata) { - ProfMucConfWin *new_win = malloc(sizeof(ProfMucConfWin)); - new_win->window.type = WIN_MUC_CONFIG; + ProfConfWin *new_win = malloc(sizeof(ProfConfWin)); + new_win->window.type = WIN_CONFIG; new_win->window.layout = _win_create_simple_layout(); new_win->roomjid = strdup(roomjid); new_win->form = form; + new_win->submit = submit; + new_win->cancel = cancel; + new_win->userdata = userdata; new_win->memcheck = PROFCONFWIN_MEMCHECK; @@ -289,8 +292,8 @@ win_get_title(ProfWin *window) assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); return strdup(mucwin->roomjid); } - if (window->type == WIN_MUC_CONFIG) { - ProfMucConfWin *confwin = (ProfMucConfWin*) window; + if (window->type == WIN_CONFIG) { + ProfConfWin *confwin = (ProfConfWin*) window; assert(confwin->memcheck == PROFCONFWIN_MEMCHECK); GString *title = g_string_new(confwin->roomjid); g_string_append(title, " config"); @@ -338,10 +341,10 @@ win_get_tab_identifier(ProfWin *window) ProfMucWin *mucwin = (ProfMucWin*)window; return strdup(mucwin->roomjid); } - case WIN_MUC_CONFIG: + case WIN_CONFIG: { - ProfMucConfWin *mucconfwin = (ProfMucConfWin*)window; - return strdup(mucconfwin->roomjid); + ProfConfWin *confwin = (ProfConfWin*)window; + return strdup(confwin->roomjid); } case WIN_PRIVATE: { @@ -383,10 +386,10 @@ win_to_string(ProfWin *window) ProfMucWin *mucwin = (ProfMucWin*)window; return mucwin_get_string(mucwin); } - case WIN_MUC_CONFIG: + case WIN_CONFIG: { - ProfMucConfWin *mucconfwin = (ProfMucConfWin*)window; - return mucconfwin_get_string(mucconfwin); + ProfConfWin *confwin = (ProfConfWin*)window; + return confwin_get_string(confwin); } case WIN_PRIVATE: { @@ -491,11 +494,11 @@ win_free(ProfWin* window) free(mucwin->message_char); break; } - case WIN_MUC_CONFIG: + case WIN_CONFIG: { - ProfMucConfWin *mucconf = (ProfMucConfWin*)window; - free(mucconf->roomjid); - form_destroy(mucconf->form); + ProfConfWin *conf = (ProfConfWin*)window; + free(conf->roomjid); + form_destroy(conf->form); break; } case WIN_PRIVATE: @@ -1389,8 +1392,8 @@ _win_print(ProfWin *window, const char show_char, int pad_indent, GDateTime *tim case WIN_MUC: time_pref = prefs_get_string(PREF_TIME_MUC); break; - case WIN_MUC_CONFIG: - time_pref = prefs_get_string(PREF_TIME_MUCCONFIG); + case WIN_CONFIG: + time_pref = prefs_get_string(PREF_TIME_CONFIG); break; case WIN_PRIVATE: time_pref = prefs_get_string(PREF_TIME_PRIVATE); @@ -1724,3 +1727,60 @@ win_sub_newline_lazy(WINDOW *win) wmove(win, cury+1, 0); } } + +void +win_command_list_error(ProfWin *window, const char *const error) +{ + assert(window != NULL); + + win_println(window, THEME_ERROR, '!', "Error retrieving command list: %s", error); +} + +void +win_command_exec_error(ProfWin *window, const char *const command, const char *const error, ...) +{ + assert(window != NULL); + va_list arg; + va_start(arg, error); + GString *msg = g_string_new(NULL); + g_string_vprintf(msg, error, arg); + + win_println(window, THEME_ERROR, '!', "Error executing command %s: %s", command, msg->str); + + g_string_free(msg, TRUE); + va_end(arg); +} + +void +win_handle_command_list(ProfWin *window, GSList *cmds) +{ + assert(window != NULL); + + if (cmds) { + win_println(window, THEME_DEFAULT, '!', "Ad hoc commands:"); + GSList *curr_cmd = cmds; + while (curr_cmd) { + const char *cmd = curr_cmd->data; + win_println(window, THEME_DEFAULT, '!', " %s", cmd); + curr_cmd = g_slist_next(curr_cmd); + } + win_println(window, THEME_DEFAULT, '!', ""); + } else { + win_println(window, THEME_DEFAULT, '!', "No commands found"); + win_println(window, THEME_DEFAULT, '!', ""); + } +} + +void +win_handle_command_exec_status(ProfWin *window, const char *const command, const char *const value) +{ + assert(window != NULL); + win_println(window, THEME_DEFAULT, '!', "%s %s", command, value); +} + +void +win_handle_command_exec_result_note(ProfWin *window, const char *const type, const char *const value) +{ + assert(window != NULL); + win_println(window, THEME_DEFAULT, '!', value); +} diff --git a/src/ui/window.h b/src/ui/window.h index 62f737de..17ebd226 100644 --- a/src/ui/window.h +++ b/src/ui/window.h @@ -1,7 +1,7 @@ /* * window.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/ui/window_list.c b/src/ui/window_list.c index 798f4e41..5ce68d63 100644 --- a/src/ui/window_list.c +++ b/src/ui/window_list.c @@ -1,7 +1,7 @@ /* * window_list.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -139,16 +139,16 @@ wins_get_chat_unsubscribed(void) return result; } -ProfMucConfWin* -wins_get_muc_conf(const char *const roomjid) +ProfConfWin* +wins_get_conf(const char *const roomjid) { GList *values = g_hash_table_get_values(windows); GList *curr = values; while (curr) { ProfWin *window = curr->data; - if (window->type == WIN_MUC_CONFIG) { - ProfMucConfWin *confwin = (ProfMucConfWin*)window; + if (window->type == WIN_CONFIG) { + ProfConfWin *confwin = (ProfConfWin*)window; if (g_strcmp0(confwin->roomjid, roomjid) == 0) { g_list_free(values); return confwin; @@ -364,7 +364,7 @@ wins_get_by_num(int i) } ProfWin* -wins_get_by_string(char *str) +wins_get_by_string(const char *str) { if (g_strcmp0(str, "console") == 0) { ProfWin *conswin = wins_get_console(); @@ -584,7 +584,7 @@ wins_close_by_num(int i) autocomplete_remove(wins_close_ac, pluginwin->tag); break; } - case WIN_MUC_CONFIG: + case WIN_CONFIG: default: break; } @@ -657,12 +657,12 @@ wins_new_muc(const char *const roomjid) } ProfWin* -wins_new_muc_config(const char *const roomjid, DataForm *form) +wins_new_config(const char *const roomjid, DataForm *form, ProfConfWinCallback submit, ProfConfWinCallback cancel, const void *userdata) { GList *keys = g_hash_table_get_keys(windows); int result = _wins_get_next_available_num(keys); g_list_free(keys); - ProfWin *newwin = win_create_muc_config(roomjid, form); + ProfWin *newwin = win_create_config(roomjid, form, submit, cancel, userdata); g_hash_table_insert(windows, GINT_TO_POINTER(result), newwin); return newwin; } @@ -812,7 +812,7 @@ wins_get_prune_wins(void) ProfWin *window = curr->data; if (win_unread(window) == 0 && window->type != WIN_MUC && - window->type != WIN_MUC_CONFIG && + window->type != WIN_CONFIG && window->type != WIN_XML && window->type != WIN_CONSOLE) { result = g_slist_append(result, window); diff --git a/src/ui/window_list.h b/src/ui/window_list.h index 68e72739..6045d349 100644 --- a/src/ui/window_list.h +++ b/src/ui/window_list.h @@ -1,7 +1,7 @@ /* * window_list.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -42,7 +42,7 @@ void wins_init(void); ProfWin* wins_new_xmlconsole(void); ProfWin* wins_new_chat(const char *const barejid); ProfWin* wins_new_muc(const char *const roomjid); -ProfWin* wins_new_muc_config(const char *const roomjid, DataForm *form); +ProfWin* wins_new_config(const char *const roomjid, DataForm *form, ProfConfWinCallback submit, ProfConfWinCallback cancel, const void *userdata); ProfWin* wins_new_private(const char *const fulljid); ProfWin* wins_new_plugin(const char *const plugin_name, const char *const tag); @@ -56,7 +56,7 @@ ProfWin* wins_get_console(void); ProfChatWin* wins_get_chat(const char *const barejid); GList* wins_get_chat_unsubscribed(void); ProfMucWin* wins_get_muc(const char *const roomjid); -ProfMucConfWin* wins_get_muc_conf(const char *const roomjid); +ProfConfWin* wins_get_conf(const char *const roomjid); ProfPrivateWin* wins_get_private(const char *const fulljid); ProfPluginWin* wins_get_plugin(const char *const tag); ProfXMLWin* wins_get_xmlconsole(void); @@ -68,7 +68,7 @@ ProfWin* wins_get_current(void); void wins_set_current_by_num(int i); ProfWin* wins_get_by_num(int i); -ProfWin* wins_get_by_string(char *str); +ProfWin* wins_get_by_string(const char *str); ProfWin* wins_get_next(void); ProfWin* wins_get_previous(void); diff --git a/src/ui/xmlwin.c b/src/ui/xmlwin.c index c76e91cf..5aa19f7d 100644 --- a/src/ui/xmlwin.c +++ b/src/ui/xmlwin.c @@ -1,7 +1,7 @@ /* * xmlwin.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/xmpp/blocking.c b/src/xmpp/blocking.c index 5d1c52b2..d3c84f0d 100644 --- a/src/xmpp/blocking.c +++ b/src/xmpp/blocking.c @@ -1,7 +1,7 @@ /* * blocking.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -73,7 +73,7 @@ blocking_request(void) } blocked_ac = autocomplete_new(); - char *id = create_unique_id("blocked_list_request"); + char *id = connection_create_stanza_id("blocked_list_request"); iq_id_handler_add(id, _blocklist_result_handler, NULL, NULL); xmpp_ctx_t *ctx = connection_get_ctx(); @@ -115,7 +115,7 @@ blocked_add(char *jid) xmpp_ctx_t *ctx = connection_get_ctx(); - char *id = create_unique_id("block"); + char *id = connection_create_stanza_id("block"); xmpp_stanza_t *iq = xmpp_iq_new(ctx, STANZA_TYPE_SET, id); xmpp_stanza_t *block = xmpp_stanza_new(ctx); @@ -151,7 +151,7 @@ blocked_remove(char *jid) xmpp_ctx_t *ctx = connection_get_ctx(); - char *id = create_unique_id("unblock"); + char *id = connection_create_stanza_id("unblock"); xmpp_stanza_t *iq = xmpp_iq_new(ctx, STANZA_TYPE_SET, id); xmpp_stanza_t *block = xmpp_stanza_new(ctx); diff --git a/src/xmpp/blocking.h b/src/xmpp/blocking.h index 61acb631..7b3863f1 100644 --- a/src/xmpp/blocking.h +++ b/src/xmpp/blocking.h @@ -1,7 +1,7 @@ /* * blocking.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/xmpp/bookmark.c b/src/xmpp/bookmark.c index 65009224..99c17c1e 100644 --- a/src/xmpp/bookmark.c +++ b/src/xmpp/bookmark.c @@ -1,7 +1,7 @@ /* * bookmark.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -333,7 +333,7 @@ _send_bookmarks(void) { xmpp_ctx_t *ctx = connection_get_ctx(); - char *id = create_unique_id("bookmarks_update"); + char *id = connection_create_stanza_id("bookmarks_update"); xmpp_stanza_t *iq = xmpp_iq_new(ctx, STANZA_TYPE_SET, id); free(id); diff --git a/src/xmpp/bookmark.h b/src/xmpp/bookmark.h index f6c72c27..0823aee1 100644 --- a/src/xmpp/bookmark.h +++ b/src/xmpp/bookmark.h @@ -1,7 +1,7 @@ /* * bookmark.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/xmpp/capabilities.c b/src/xmpp/capabilities.c index 2152f869..8d66b25a 100644 --- a/src/xmpp/capabilities.c +++ b/src/xmpp/capabilities.c @@ -1,7 +1,7 @@ /* * capabilities.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/xmpp/capabilities.h b/src/xmpp/capabilities.h index 21ffe0b4..a4e25128 100644 --- a/src/xmpp/capabilities.h +++ b/src/xmpp/capabilities.h @@ -1,7 +1,7 @@ /* * capabilities.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/xmpp/chat_session.c b/src/xmpp/chat_session.c index 799a9c47..1b57068f 100644 --- a/src/xmpp/chat_session.c +++ b/src/xmpp/chat_session.c @@ -1,7 +1,7 @@ /* * chat_session.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/xmpp/chat_session.h b/src/xmpp/chat_session.h index d8de0330..564ee2b0 100644 --- a/src/xmpp/chat_session.h +++ b/src/xmpp/chat_session.h @@ -1,7 +1,7 @@ /* * chat_session.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/xmpp/chat_state.c b/src/xmpp/chat_state.c index 9659eb8b..da5c1342 100644 --- a/src/xmpp/chat_state.c +++ b/src/xmpp/chat_state.c @@ -1,7 +1,7 @@ /* * chat_state.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/xmpp/chat_state.h b/src/xmpp/chat_state.h index 51698cd1..f3d3adb0 100644 --- a/src/xmpp/chat_state.h +++ b/src/xmpp/chat_state.h @@ -1,7 +1,7 @@ /* * chat_state.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/xmpp/connection.c b/src/xmpp/connection.c index 6c5e7323..2adda46e 100644 --- a/src/xmpp/connection.c +++ b/src/xmpp/connection.c @@ -1,7 +1,7 @@ /* * connection.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -150,6 +150,9 @@ connection_connect(const char *const jid, const char *const passwd, const char * if (!tls_policy || (g_strcmp0(tls_policy, "force") == 0)) { xmpp_conn_set_flags(conn.xmpp_conn, XMPP_CONN_FLAG_MANDATORY_TLS); + } else if (g_strcmp0(tls_policy, "trust") == 0) { + xmpp_conn_set_flags(conn.xmpp_conn, XMPP_CONN_FLAG_MANDATORY_TLS); + xmpp_conn_set_flags(conn.xmpp_conn, XMPP_CONN_FLAG_TRUST_TLS); } else if (g_strcmp0(tls_policy, "disable") == 0) { xmpp_conn_set_flags(conn.xmpp_conn, XMPP_CONN_FLAG_DISABLE_TLS); } else if (g_strcmp0(tls_policy, "legacy") == 0) { @@ -393,6 +396,27 @@ connection_free_uuid(char *uuid) } char* +connection_create_stanza_id(char *prefix) +{ + char *result = NULL; + GString *result_str = g_string_new(""); + char *uuid = connection_create_uuid(); + + if (prefix) { + g_string_printf(result_str, "prof_%s_%s", prefix, uuid); + } else { + g_string_printf(result_str, "prof_%s", uuid); + } + + connection_free_uuid(uuid); + + result = result_str->str; + g_string_free(result_str, FALSE); + + return result; +} + +char* connection_get_domain(void) { return conn.domain; diff --git a/src/xmpp/connection.h b/src/xmpp/connection.h index b0ff7cec..170bc2bf 100644 --- a/src/xmpp/connection.h +++ b/src/xmpp/connection.h @@ -1,7 +1,7 @@ /* * connection.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -60,4 +60,6 @@ void connection_clear_data(void); void connection_add_available_resource(Resource *resource); void connection_remove_available_resource(const char *const resource); +char* connection_create_stanza_id(char *prefix); + #endif diff --git a/src/xmpp/contact.c b/src/xmpp/contact.c index a43372f3..49d0786c 100644 --- a/src/xmpp/contact.c +++ b/src/xmpp/contact.c @@ -1,7 +1,7 @@ /* * contact.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/xmpp/contact.h b/src/xmpp/contact.h index 170df2ca..d3b2dee3 100644 --- a/src/xmpp/contact.h +++ b/src/xmpp/contact.h @@ -1,7 +1,7 @@ /* * contact.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/xmpp/form.c b/src/xmpp/form.c index 6e26411a..d30eb0fc 100644 --- a/src/xmpp/form.c +++ b/src/xmpp/form.c @@ -1,7 +1,7 @@ /* * form.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/xmpp/form.h b/src/xmpp/form.h index 21314ce2..04af8f6b 100644 --- a/src/xmpp/form.h +++ b/src/xmpp/form.h @@ -1,7 +1,7 @@ /* * form.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/xmpp/iq.c b/src/xmpp/iq.c index 9bceb859..a77ef59b 100644 --- a/src/xmpp/iq.c +++ b/src/xmpp/iq.c @@ -1,7 +1,7 @@ /* * iq.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -88,6 +88,11 @@ typedef struct privilege_set_t { char *privilege; } ProfPrivilegeSet; +typedef struct command_config_data_t { + char *sessionid; + char *command; +} CommandConfigData; + static int _iq_handler(xmpp_conn_t *const conn, xmpp_stanza_t *const stanza, void *const userdata); static void _error_handler(xmpp_stanza_t *const stanza); @@ -120,6 +125,8 @@ static int _caps_response_for_jid_id_handler(xmpp_stanza_t *const stanza, void * static int _caps_response_legacy_id_handler(xmpp_stanza_t *const stanza, void *const userdata); static int _auto_pong_id_handler(xmpp_stanza_t *const stanza, void *const userdata); static int _room_list_id_handler(xmpp_stanza_t *const stanza, void *const userdata); +static int _command_list_result_handler(xmpp_stanza_t *const stanza, void *const userdata); +static int _command_exec_response_handler(xmpp_stanza_t *const stanza, void *const userdata); static void _iq_free_room_data(ProfRoomInfoData *roominfo); static void _iq_free_affiliation_set(ProfPrivilegeSet *affiliation_set); @@ -318,8 +325,8 @@ iq_room_list_request(gchar *conferencejid, gchar *filter) log_debug("Rooms request not cached for: %s", conferencejid); xmpp_ctx_t * const ctx = connection_get_ctx(); - char *id = create_unique_id("confreq"); - xmpp_stanza_t *iq = stanza_create_disco_items_iq(ctx, id, conferencejid); + char *id = connection_create_stanza_id("confreq"); + xmpp_stanza_t *iq = stanza_create_disco_items_iq(ctx, id, conferencejid, NULL); iq_id_handler_add(id, _room_list_id_handler, NULL, filter); @@ -363,7 +370,7 @@ iq_http_upload_request(HTTPUpload *upload) } xmpp_ctx_t * const ctx = connection_get_ctx(); - char *id = create_unique_id("http_upload_request"); + char *id = connection_create_stanza_id("http_upload_request"); xmpp_stanza_t *iq = stanza_create_http_upload_request(ctx, id, jid, upload); // TODO add free func iq_id_handler_add(id, _http_upload_response_id_handler, NULL, upload); @@ -379,7 +386,7 @@ void iq_disco_info_request(gchar *jid) { xmpp_ctx_t * const ctx = connection_get_ctx(); - char *id = create_unique_id("disco_info"); + char *id = connection_create_stanza_id("disco_info"); xmpp_stanza_t *iq = stanza_create_disco_info_iq(ctx, id, jid, NULL); iq_id_handler_add(id, _disco_info_response_id_handler, NULL, NULL); @@ -394,7 +401,7 @@ void iq_disco_info_request_onconnect(gchar *jid) { xmpp_ctx_t * const ctx = connection_get_ctx(); - char *id = create_unique_id("disco_info_onconnect"); + char *id = connection_create_stanza_id("disco_info_onconnect"); xmpp_stanza_t *iq = stanza_create_disco_info_iq(ctx, id, jid, NULL); iq_id_handler_add(id, _disco_info_response_id_handler_onconnect, NULL, NULL); @@ -409,7 +416,7 @@ void iq_last_activity_request(gchar *jid) { xmpp_ctx_t * const ctx = connection_get_ctx(); - char *id = create_unique_id("lastactivity"); + char *id = connection_create_stanza_id("lastactivity"); xmpp_stanza_t *iq = stanza_create_last_activity_iq(ctx, id, jid); iq_id_handler_add(id, _last_activity_response_id_handler, NULL, NULL); @@ -424,7 +431,7 @@ void iq_room_info_request(const char *const room, gboolean display_result) { xmpp_ctx_t * const ctx = connection_get_ctx(); - char *id = create_unique_id("room_disco_info"); + char *id = connection_create_stanza_id("room_disco_info"); xmpp_stanza_t *iq = stanza_create_disco_info_iq(ctx, id, room, NULL); ProfRoomInfoData *cb_data = malloc(sizeof(ProfRoomInfoData)); @@ -521,7 +528,7 @@ void iq_disco_items_request(gchar *jid) { xmpp_ctx_t * const ctx = connection_get_ctx(); - xmpp_stanza_t *iq = stanza_create_disco_items_iq(ctx, "discoitemsreq", jid); + xmpp_stanza_t *iq = stanza_create_disco_items_iq(ctx, "discoitemsreq", jid, NULL); iq_send_stanza(iq); xmpp_stanza_release(iq); } @@ -530,7 +537,7 @@ void iq_disco_items_request_onconnect(gchar *jid) { xmpp_ctx_t * const ctx = connection_get_ctx(); - xmpp_stanza_t *iq = stanza_create_disco_items_iq(ctx, "discoitemsreq_onconnect", jid); + xmpp_stanza_t *iq = stanza_create_disco_items_iq(ctx, "discoitemsreq_onconnect", jid, NULL); iq_send_stanza(iq); xmpp_stanza_release(iq); } @@ -584,10 +591,10 @@ iq_request_room_config_form(const char *const room_jid) } void -iq_submit_room_config(const char *const room, DataForm *form) +iq_submit_room_config(ProfConfWin *confwin) { xmpp_ctx_t * const ctx = connection_get_ctx(); - xmpp_stanza_t *iq = stanza_create_room_config_submit_iq(ctx, room, form); + xmpp_stanza_t *iq = stanza_create_room_config_submit_iq(ctx, confwin->roomjid, confwin->form); const char *id = xmpp_stanza_get_id(iq); iq_id_handler_add(id, _room_config_submit_id_handler, NULL, NULL); @@ -597,10 +604,10 @@ iq_submit_room_config(const char *const room, DataForm *form) } void -iq_room_config_cancel(const char *const room_jid) +iq_room_config_cancel(ProfConfWin *confwin) { xmpp_ctx_t * const ctx = connection_get_ctx(); - xmpp_stanza_t *iq = stanza_create_room_config_cancel_iq(ctx, room_jid); + xmpp_stanza_t *iq = stanza_create_room_config_cancel_iq(ctx, confwin->roomjid); iq_send_stanza(iq); xmpp_stanza_release(iq); } @@ -696,6 +703,62 @@ iq_send_ping(const char *const target) xmpp_stanza_release(iq); } +void +iq_command_list(const char *const target) +{ + xmpp_ctx_t * const ctx = connection_get_ctx(); + const char *id = connection_create_stanza_id("cmdlist"); + xmpp_stanza_t *iq = stanza_create_disco_items_iq(ctx, id, target, STANZA_NS_COMMAND); + + iq_id_handler_add(id, _command_list_result_handler, NULL, NULL); + + iq_send_stanza(iq); + xmpp_stanza_release(iq); +} + +void +iq_command_exec(const char *const target, const char *const command) +{ + xmpp_ctx_t * const ctx = connection_get_ctx(); + xmpp_stanza_t *iq = stanza_create_command_exec_iq(ctx, target, command); + const char *id = xmpp_stanza_get_id(iq); + + iq_id_handler_add(id, _command_exec_response_handler, free, strdup(command)); + + iq_send_stanza(iq); + xmpp_stanza_release(iq); +} + +void +iq_submit_command_config(ProfConfWin *confwin) +{ + xmpp_ctx_t * const ctx = connection_get_ctx(); + CommandConfigData *data = (CommandConfigData *)confwin->userdata; + xmpp_stanza_t *iq = stanza_create_command_config_submit_iq(ctx, confwin->roomjid, data->command, data->sessionid, confwin->form); + + const char *id = xmpp_stanza_get_id(iq); + iq_id_handler_add(id, _command_exec_response_handler, free, strdup(data->command)); + + iq_send_stanza(iq); + xmpp_stanza_release(iq); + free(data->sessionid); + free(data->command); + free(data); +} + +void +iq_cancel_command_config(ProfConfWin *confwin) +{ + xmpp_ctx_t * const ctx = connection_get_ctx(); + CommandConfigData *data = (CommandConfigData *)confwin->userdata; + xmpp_stanza_t *iq = stanza_create_room_config_cancel_iq(ctx, confwin->roomjid); + iq_send_stanza(iq); + xmpp_stanza_release(iq); + free(data->sessionid); + free(data->command); + free(data); +} + static void _error_handler(xmpp_stanza_t *const stanza) { @@ -1012,6 +1075,186 @@ _room_list_id_handler(xmpp_stanza_t *const stanza, void *const userdata) } static int +_command_list_result_handler(xmpp_stanza_t *const stanza, void *const userdata) +{ + const char *id = xmpp_stanza_get_id(stanza); + const char *type = xmpp_stanza_get_type(stanza); + char *from = strdup(xmpp_stanza_get_from(stanza)); + + if (id) { + log_debug("IQ command list result handler fired, id: %s.", id); + } else { + log_debug("IQ command list result handler fired."); + } + + // handle error responses + if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) { + char *error_message = stanza_get_error_message(stanza); + log_debug("Error retrieving command list for %s: %s", from, error_message); + ProfWin *win = wins_get_by_string(from); + if (win) { + win_command_list_error(win, error_message); + } + free(error_message); + free(from); + return 0; + } + + GSList *cmds = NULL; + + xmpp_stanza_t *query = xmpp_stanza_get_child_by_ns(stanza, XMPP_NS_DISCO_ITEMS); + if (query) { + xmpp_stanza_t *child = xmpp_stanza_get_children(query); + while (child) { + const char *name = xmpp_stanza_get_name(child); + if (g_strcmp0(name, "item") == 0) { + const char *node = xmpp_stanza_get_attribute(child, STANZA_ATTR_NODE); + if (node) { + cmds = g_slist_insert_sorted(cmds, (gpointer)node, (GCompareFunc)g_strcmp0); + } + } + child = xmpp_stanza_get_next(child); + } + } + + ProfWin *win = wins_get_by_string(from); + if (win == NULL) { + win = wins_get_console(); + } + + win_handle_command_list(win, cmds); + g_slist_free(cmds); + free(from); + + return 0; +} + +static int +_command_exec_response_handler(xmpp_stanza_t *const stanza, void *const userdata) +{ + const char *id = xmpp_stanza_get_id(stanza); + const char *type = xmpp_stanza_get_type(stanza); + const char *from = xmpp_stanza_get_from(stanza); + char *command = userdata; + + if (id) { + log_debug("IQ command exec response handler fired, id: %s.", id); + } else { + log_debug("IQ command exec response handler fired."); + } + + ProfWin *win = wins_get_by_string(from); + if (win == NULL) { + /* No more window associated with this command. + * Fallback to console. */ + win = wins_get_console(); + } + + // handle error responses + if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) { + char *error_message = stanza_get_error_message(stanza); + log_debug("Error executing command %s for %s: %s", command, from, error_message); + win_command_exec_error(win, command, error_message); + free(error_message); + return 0; + } + + xmpp_stanza_t *cmd = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_COMMAND); + if (!cmd) { + log_error("No command element for command response"); + win_command_exec_error(win, command, "Malformed command response"); + return 0; + } + + + const char *status = xmpp_stanza_get_attribute(cmd, STANZA_ATTR_STATUS); + if (g_strcmp0(status, "completed") == 0) { + win_handle_command_exec_status(win, command, "completed"); + xmpp_stanza_t *note = xmpp_stanza_get_child_by_name(cmd, "note"); + if (note) { + const char *type = xmpp_stanza_get_attribute(note, "type"); + const char *value = xmpp_stanza_get_text(note); + win_handle_command_exec_result_note(win, type, value); + } + xmpp_stanza_t *x = xmpp_stanza_get_child_by_ns(cmd, STANZA_NS_DATA); + if (x) { + xmpp_stanza_t *roster = xmpp_stanza_get_child_by_ns(x, XMPP_NS_ROSTER); + if (roster) { + /* Special handling of xep-0133 roster in response */ + GSList *list = NULL; + xmpp_stanza_t *child = xmpp_stanza_get_children(roster); + while (child) { + const char *barejid = xmpp_stanza_get_attribute(child, STANZA_ATTR_JID); + gchar *barejid_lower = g_utf8_strdown(barejid, -1); + const char *name = xmpp_stanza_get_attribute(child, STANZA_ATTR_NAME); + const char *sub = xmpp_stanza_get_attribute(child, STANZA_ATTR_SUBSCRIPTION); + const char *ask = xmpp_stanza_get_attribute(child, STANZA_ATTR_ASK); + + GSList *groups = NULL; + groups = roster_get_groups_from_item(child); + + gboolean pending_out = FALSE; + if (ask && (strcmp(ask, "subscribe") == 0)) { + pending_out = TRUE; + } + + PContact contact = p_contact_new(barejid_lower, name, groups, sub, NULL, pending_out); + list = g_slist_insert_sorted(list, contact, (GCompareFunc)roster_compare_name); + child = xmpp_stanza_get_next(child); + } + + cons_show_roster(list); + g_slist_free(list); + } else { + DataForm *form = form_create(x); + ProfConfWin *confwin = (ProfConfWin*)wins_new_config(from, form, NULL, NULL, NULL); + confwin_handle_configuration(confwin, form); + } + } + } else if (g_strcmp0(status, "executing") == 0) { + win_handle_command_exec_status(win, command, "executing"); + + /* Looking for a jabber:x:data type form */ + xmpp_stanza_t *x = xmpp_stanza_get_child_by_ns(cmd, STANZA_NS_DATA); + if (x == NULL) { + return 0; + } + + const char *form_type = xmpp_stanza_get_type(x); + if (g_strcmp0(form_type, "form") != 0) { + log_error("Unsupported payload in command response"); + win_command_exec_error(win, command, "Unsupported command response"); + return 0; + } + const char *sessionid = xmpp_stanza_get_attribute(cmd, "sessionid"); + + DataForm *form = form_create(x); + CommandConfigData *data = malloc(sizeof(CommandConfigData)); + if (sessionid == NULL) { + data->sessionid = NULL; + } else { + data->sessionid = strdup(sessionid); + } + data->command = command; + ProfConfWin *confwin = (ProfConfWin*)wins_new_config(from, form, iq_submit_command_config, iq_cancel_command_config, data); + confwin_handle_configuration(confwin, form); + } else if (g_strcmp0(status, "canceled") == 0) { + win_handle_command_exec_status(win, command, "canceled"); + xmpp_stanza_t *note = xmpp_stanza_get_child_by_name(cmd, "note"); + if (note) { + const char *type = xmpp_stanza_get_attribute(note, "type"); + const char *value = xmpp_stanza_get_text(note); + win_handle_command_exec_result_note(win, type, value); + } + } else { + log_error("Unsupported command status %s", status); + win_command_exec_error(win, command, "Malformed command response"); + } + + return 0; +} + +static int _enable_carbons_id_handler(xmpp_stanza_t *const stanza, void *const userdata) { const char *type = xmpp_stanza_get_type(stanza); @@ -1088,8 +1331,8 @@ _autoping_timed_send(xmpp_conn_t *const conn, void *const userdata) return 1; } - if (connection_supports(STANZA_NS_PING) == FALSE) { - log_warning("Server doesn't advertise %s feature, disabling autoping.", STANZA_NS_PING); + if (connection_supports(XMPP_FEATURE_PING) == FALSE) { + log_warning("Server doesn't advertise %s feature, disabling autoping.", XMPP_FEATURE_PING); prefs_set_autoping(0); cons_show_error("Server ping not supported, autoping disabled."); xmpp_conn_t *conn = connection_get_conn(); @@ -1540,8 +1783,8 @@ _room_config_id_handler(xmpp_stanza_t *const stanza, void *const userdata) } DataForm *form = form_create(x); - ProfMucConfWin *confwin = (ProfMucConfWin*)wins_new_muc_config(from, form); - mucconfwin_handle_configuration(confwin, form); + ProfConfWin *confwin = (ProfConfWin*)wins_new_config(from, form, iq_submit_room_config, iq_room_config_cancel, NULL); + confwin_handle_configuration(confwin, form); return 0; } diff --git a/src/xmpp/iq.h b/src/xmpp/iq.h index b06568b6..025d5e9f 100644 --- a/src/xmpp/iq.h +++ b/src/xmpp/iq.h @@ -1,7 +1,7 @@ /* * iq.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/xmpp/jid.c b/src/xmpp/jid.c index 0af54c72..51e1fa3c 100644 --- a/src/xmpp/jid.c +++ b/src/xmpp/jid.c @@ -1,7 +1,7 @@ /* * jid.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/xmpp/jid.h b/src/xmpp/jid.h index e4e4d272..fc0e388f 100644 --- a/src/xmpp/jid.h +++ b/src/xmpp/jid.h @@ -1,7 +1,7 @@ /* * jid.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/xmpp/message.c b/src/xmpp/message.c index 9f665892..6a2197f3 100644 --- a/src/xmpp/message.c +++ b/src/xmpp/message.c @@ -1,7 +1,7 @@ /* * message.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -139,7 +139,7 @@ message_send_chat(const char *const barejid, const char *const msg, const char * char *state = chat_session_get_state(barejid); char *jid = chat_session_get_jid(barejid); - char *id = create_unique_id("msg"); + char *id = connection_create_stanza_id("msg"); xmpp_stanza_t *message = xmpp_message_new(ctx, STANZA_TYPE_CHAT, jid, id); xmpp_message_set_body(message, msg); @@ -170,7 +170,7 @@ message_send_chat_pgp(const char *const barejid, const char *const msg, gboolean char *state = chat_session_get_state(barejid); char *jid = chat_session_get_jid(barejid); - char *id = create_unique_id("msg"); + char *id = connection_create_stanza_id("msg"); xmpp_stanza_t *message = NULL; #ifdef HAVE_LIBGPGME @@ -229,7 +229,7 @@ message_send_chat_otr(const char *const barejid, const char *const msg, gboolean char *state = chat_session_get_state(barejid); char *jid = chat_session_get_jid(barejid); - char *id = create_unique_id("msg"); + char *id = connection_create_stanza_id("msg"); xmpp_stanza_t *message = xmpp_message_new(ctx, STANZA_TYPE_CHAT, barejid, id); xmpp_message_set_body(message, msg); @@ -258,7 +258,7 @@ void message_send_private(const char *const fulljid, const char *const msg, const char *const oob_url) { xmpp_ctx_t * const ctx = connection_get_ctx(); - char *id = create_unique_id("prv"); + char *id = connection_create_stanza_id("prv"); xmpp_stanza_t *message = xmpp_message_new(ctx, STANZA_TYPE_CHAT, fulljid, id); xmpp_message_set_body(message, msg); @@ -277,7 +277,7 @@ void message_send_groupchat(const char *const roomjid, const char *const msg, const char *const oob_url) { xmpp_ctx_t * const ctx = connection_get_ctx(); - char *id = create_unique_id("muc"); + char *id = connection_create_stanza_id("muc"); xmpp_stanza_t *message = xmpp_message_new(ctx, STANZA_TYPE_GROUPCHAT, roomjid, id); xmpp_message_set_body(message, msg); @@ -584,7 +584,7 @@ _message_send_receipt(const char *const fulljid, const char *const message_id) { xmpp_ctx_t * const ctx = connection_get_ctx(); - char *id = create_unique_id("receipt"); + char *id = connection_create_stanza_id("receipt"); xmpp_stanza_t *message = xmpp_message_new(ctx, NULL, fulljid, id); free(id); diff --git a/src/xmpp/message.h b/src/xmpp/message.h index 47bb17ed..dee9be2d 100644 --- a/src/xmpp/message.h +++ b/src/xmpp/message.h @@ -1,7 +1,7 @@ /* * message.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/xmpp/muc.c b/src/xmpp/muc.c index 9f2f9f61..62a589d7 100644 --- a/src/xmpp/muc.c +++ b/src/xmpp/muc.c @@ -1,7 +1,7 @@ /* * muc.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/xmpp/muc.h b/src/xmpp/muc.h index e50e2a87..e0b035f2 100644 --- a/src/xmpp/muc.h +++ b/src/xmpp/muc.h @@ -1,7 +1,7 @@ /* * muc.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/xmpp/presence.c b/src/xmpp/presence.c index 8efb60e0..6d615de4 100644 --- a/src/xmpp/presence.c +++ b/src/xmpp/presence.c @@ -1,7 +1,7 @@ /* * presence.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -128,7 +128,7 @@ presence_subscription(const char *const jid, const jabber_subscr_t action) xmpp_ctx_t * const ctx = connection_get_ctx(); xmpp_stanza_t *presence = xmpp_presence_new(ctx); - char *id = create_unique_id("sub"); + char *id = connection_create_stanza_id("sub"); xmpp_stanza_set_id(presence, id); free(id); @@ -211,7 +211,7 @@ presence_send(const resource_presence_t presence_type, const int idle, char *sig xmpp_ctx_t * const ctx = connection_get_ctx(); xmpp_stanza_t *presence = xmpp_presence_new(ctx); - char *id = create_unique_id("presence"); + char *id = connection_create_stanza_id("presence"); xmpp_stanza_set_id(presence, id); free(id); @@ -579,7 +579,7 @@ _handle_caps(const char *const jid, XMPPCaps *caps) caps_map_jid_to_ver(jid, caps->ver); } else { log_info("Capabilities cache miss: %s, for %s, sending service discovery request", caps->ver, jid); - char *id = create_unique_id("caps"); + char *id = connection_create_stanza_id("caps"); iq_send_caps_request(jid, id, caps->node, caps->ver); free(id); } @@ -588,14 +588,14 @@ _handle_caps(const char *const jid, XMPPCaps *caps) // unsupported hash, xep-0115, associate with JID, no cache } else if (caps->hash) { log_info("Hash %s not supported: %s, sending service discovery request", caps->hash, jid); - char *id = create_unique_id("caps"); + char *id = connection_create_stanza_id("caps"); iq_send_caps_request_for_jid(jid, id, caps->node, caps->ver); free(id); // no hash, legacy caps, cache against node#ver } else if (caps->node && caps->ver) { log_info("No hash specified: %s, legacy request made for %s#%s", jid, caps->node, caps->ver); - char *id = create_unique_id("caps"); + char *id = connection_create_stanza_id("caps"); iq_send_caps_request_legacy(jid, id, caps->node, caps->ver); free(id); } else { diff --git a/src/xmpp/presence.h b/src/xmpp/presence.h index 6045f72c..cbdfd20b 100644 --- a/src/xmpp/presence.h +++ b/src/xmpp/presence.h @@ -1,7 +1,7 @@ /* * presence.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/xmpp/resource.c b/src/xmpp/resource.c index 734de3a0..fc6b503e 100644 --- a/src/xmpp/resource.c +++ b/src/xmpp/resource.c @@ -1,7 +1,7 @@ /* * resource.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/xmpp/resource.h b/src/xmpp/resource.h index 9376a51c..ef934c2b 100644 --- a/src/xmpp/resource.h +++ b/src/xmpp/resource.h @@ -1,7 +1,7 @@ /* * resource.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/xmpp/roster.c b/src/xmpp/roster.c index e7d9cfb2..9be154e7 100644 --- a/src/xmpp/roster.c +++ b/src/xmpp/roster.c @@ -1,7 +1,7 @@ /* * roster.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -75,9 +75,6 @@ static int _group_add_id_handler(xmpp_stanza_t *const stanza, void *const userda static int _group_remove_id_handler(xmpp_stanza_t *const stanza, void *const userdata); static void _free_group_data(GroupData *data); -// helper functions -GSList* _get_groups_from_item(xmpp_stanza_t *item); - void roster_request(void) { @@ -91,7 +88,7 @@ void roster_send_add_new(const char *const barejid, const char *const name) { xmpp_ctx_t * const ctx = connection_get_ctx(); - char *id = create_unique_id("roster"); + char *id = connection_create_stanza_id("roster"); xmpp_stanza_t *iq = stanza_create_roster_set(ctx, id, barejid, name, NULL); free(id); iq_send_stanza(iq); @@ -111,7 +108,7 @@ void roster_send_name_change(const char *const barejid, const char *const new_name, GSList *groups) { xmpp_ctx_t * const ctx = connection_get_ctx(); - char *id = create_unique_id("roster"); + char *id = connection_create_stanza_id("roster"); xmpp_stanza_t *iq = stanza_create_roster_set(ctx, id, barejid, new_name, groups); free(id); iq_send_stanza(iq); @@ -130,7 +127,7 @@ roster_send_add_to_group(const char *const group, PContact contact) new_groups = g_slist_append(new_groups, strdup(group)); // add an id handler to handle the response - char *unique_id = create_unique_id(NULL); + char *unique_id = connection_create_stanza_id(NULL); GroupData *data = malloc(sizeof(GroupData)); data->group = strdup(group); if (p_contact_name(contact)) { @@ -174,7 +171,7 @@ roster_send_remove_from_group(const char *const group, PContact contact) xmpp_ctx_t * const ctx = connection_get_ctx(); // add an id handler to handle the response - char *unique_id = create_unique_id(NULL); + char *unique_id = connection_create_stanza_id(NULL); GroupData *data = malloc(sizeof(GroupData)); data->group = strdup(group); if (p_contact_name(contact)) { @@ -254,7 +251,7 @@ roster_set_handler(xmpp_stanza_t *const stanza) pending_out = TRUE; } - GSList *groups = _get_groups_from_item(item); + GSList *groups = roster_get_groups_from_item(item); // update the local roster PContact contact = roster_get_contact(barejid_lower); @@ -301,7 +298,7 @@ roster_result_handler(xmpp_stanza_t *const stanza) pending_out = TRUE; } - GSList *groups = _get_groups_from_item(item); + GSList *groups = roster_get_groups_from_item(item); gboolean added = roster_add(barejid_lower, name, groups, sub, pending_out); if (!added) { @@ -318,7 +315,7 @@ roster_result_handler(xmpp_stanza_t *const stanza) } GSList* -_get_groups_from_item(xmpp_stanza_t *item) +roster_get_groups_from_item(xmpp_stanza_t *item) { GSList *groups = NULL; xmpp_stanza_t *group_element = xmpp_stanza_get_children(item); diff --git a/src/xmpp/roster.h b/src/xmpp/roster.h index 15614377..969044a4 100644 --- a/src/xmpp/roster.h +++ b/src/xmpp/roster.h @@ -1,7 +1,7 @@ /* * roster.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -38,5 +38,6 @@ void roster_request(void); void roster_set_handler(xmpp_stanza_t *const stanza); void roster_result_handler(xmpp_stanza_t *const stanza); +GSList* roster_get_groups_from_item(xmpp_stanza_t *const item); #endif diff --git a/src/xmpp/roster_list.c b/src/xmpp/roster_list.c index a2c5653d..5ebdc08f 100644 --- a/src/xmpp/roster_list.c +++ b/src/xmpp/roster_list.c @@ -1,7 +1,7 @@ /* * roster_list.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -73,8 +73,6 @@ static gboolean _key_equals(void *key1, void *key2); static gboolean _datetimes_equal(GDateTime *dt1, GDateTime *dt2); static void _replace_name(const char *const current_name, const char *const new_name, const char *const barejid); static void _add_name_and_barejid(const char *const name, const char *const barejid); -static gint _compare_name(PContact a, PContact b); -static gint _compare_presence(PContact a, PContact b); void roster_create(void) @@ -397,7 +395,7 @@ roster_get_contacts_by_presence(const char *const presence) while (g_hash_table_iter_next(&iter, &key, &value)) { PContact contact = (PContact)value; if (g_strcmp0(p_contact_presence(contact), presence) == 0) { - result = g_slist_insert_sorted(result, value, (GCompareFunc)_compare_name); + result = g_slist_insert_sorted(result, value, (GCompareFunc)roster_compare_name); } } @@ -417,9 +415,9 @@ roster_get_contacts(roster_ord_t order) GCompareFunc cmp_func; if (order == ROSTER_ORD_PRESENCE) { - cmp_func = (GCompareFunc) _compare_presence; + cmp_func = (GCompareFunc) roster_compare_presence; } else { - cmp_func = (GCompareFunc) _compare_name; + cmp_func = (GCompareFunc) roster_compare_name; } g_hash_table_iter_init(&iter, roster->contacts); @@ -444,7 +442,7 @@ roster_get_contacts_online(void) g_hash_table_iter_init(&iter, roster->contacts); while (g_hash_table_iter_next(&iter, &key, &value)) { if(strcmp(p_contact_presence(value), "offline")) - result = g_slist_insert_sorted(result, value, (GCompareFunc)_compare_name); + result = g_slist_insert_sorted(result, value, (GCompareFunc)roster_compare_name); } // return all contact structs @@ -499,9 +497,9 @@ roster_get_group(const char *const group, roster_ord_t order) GCompareFunc cmp_func; if (order == ROSTER_ORD_PRESENCE) { - cmp_func = (GCompareFunc) _compare_presence; + cmp_func = (GCompareFunc) roster_compare_presence; } else { - cmp_func = (GCompareFunc) _compare_name; + cmp_func = (GCompareFunc) roster_compare_name; } g_hash_table_iter_init(&iter, roster->contacts); @@ -605,8 +603,8 @@ _add_name_and_barejid(const char *const name, const char *const barejid) } } -static gint -_compare_name(PContact a, PContact b) +gint +roster_compare_name(PContact a, PContact b) { const char * utf8_str_a = NULL; const char * utf8_str_b = NULL; @@ -645,8 +643,8 @@ _get_presence_weight(const char *presence) } } -static gint -_compare_presence(PContact a, PContact b) +gint +roster_compare_presence(PContact a, PContact b) { const char *presence_a = p_contact_presence(a); const char *presence_b = p_contact_presence(b); @@ -663,6 +661,6 @@ _compare_presence(PContact a, PContact b) // otherwise order by name } else { - return _compare_name(a, b); + return roster_compare_name(a, b); } } diff --git a/src/xmpp/roster_list.h b/src/xmpp/roster_list.h index a0b01625..5120043c 100644 --- a/src/xmpp/roster_list.h +++ b/src/xmpp/roster_list.h @@ -1,7 +1,7 @@ /* * roster_list.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -70,5 +70,7 @@ char* roster_group_autocomplete(const char *const search_str, gboolean previous) char* roster_barejid_autocomplete(const char *const search_str, gboolean previous); GSList* roster_get_contacts_by_presence(const char *const presence); char* roster_get_msg_display_name(const char *const barejid, const char *const resource); +gint roster_compare_name(PContact a, PContact b); +gint roster_compare_presence(PContact a, PContact b); #endif diff --git a/src/xmpp/session.c b/src/xmpp/session.c index e06b03f1..de7fb7ac 100644 --- a/src/xmpp/session.c +++ b/src/xmpp/session.c @@ -1,7 +1,7 @@ /* * session.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/xmpp/session.h b/src/xmpp/session.h index a3413e9e..53200939 100644 --- a/src/xmpp/session.h +++ b/src/xmpp/session.h @@ -1,7 +1,7 @@ /* * session.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/xmpp/stanza.c b/src/xmpp/stanza.c index 2f690828..534ee06b 100644 --- a/src/xmpp/stanza.c +++ b/src/xmpp/stanza.c @@ -1,7 +1,7 @@ /* * stanza.c * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -45,6 +45,7 @@ #include <stdio.h> #include <libgen.h> #include <inttypes.h> +#include <assert.h> #include <glib.h> @@ -66,6 +67,7 @@ #include "xmpp/muc.h" static void _stanza_add_unique_id(xmpp_stanza_t *stanza, char *prefix); +static char* _stanza_create_sha1_hash(char *str); #if 0 xmpp_stanza_t* @@ -132,7 +134,7 @@ xmpp_stanza_t* stanza_create_bookmarks_pubsub_add(xmpp_ctx_t *ctx, const char *const jid, const gboolean autojoin, const char *const nick) { - char *id = create_unique_id("bookmark_add"); + char *id = connection_create_stanza_id("bookmark_add"); xmpp_stanza_t *stanza = xmpp_iq_new(ctx, STANZA_TYPE_SET, id); free(id); @@ -278,7 +280,7 @@ stanza_create_http_upload_request(xmpp_ctx_t *ctx, const char *const id, xmpp_stanza_t* stanza_enable_carbons(xmpp_ctx_t *ctx) { - char *id = create_unique_id("carbons"); + char *id = connection_create_stanza_id("carbons"); xmpp_stanza_t *iq = xmpp_iq_new(ctx, STANZA_TYPE_SET, id); free(id); @@ -295,7 +297,7 @@ stanza_enable_carbons(xmpp_ctx_t *ctx) xmpp_stanza_t* stanza_disable_carbons(xmpp_ctx_t *ctx) { - char *id = create_unique_id("carbons"); + char *id = connection_create_stanza_id("carbons"); xmpp_stanza_t *iq = xmpp_iq_new(ctx, STANZA_TYPE_SET, id); free(id); @@ -312,7 +314,7 @@ stanza_disable_carbons(xmpp_ctx_t *ctx) xmpp_stanza_t* stanza_create_chat_state(xmpp_ctx_t *ctx, const char *const fulljid, const char *const state) { - char *id = create_unique_id(NULL); + char *id = connection_create_stanza_id(NULL); xmpp_stanza_t *msg = xmpp_message_new(ctx, STANZA_TYPE_CHAT, fulljid, id); free(id); @@ -432,7 +434,7 @@ stanza_attach_x_oob_url(xmpp_ctx_t *ctx, xmpp_stanza_t *stanza, const char *cons xmpp_stanza_t* stanza_create_roster_remove_set(xmpp_ctx_t *ctx, const char *const barejid) { - char *id = create_unique_id("roster"); + char *id = connection_create_stanza_id("roster"); xmpp_stanza_t *iq = xmpp_iq_new(ctx, STANZA_TYPE_SET, id); free(id); @@ -498,7 +500,7 @@ xmpp_stanza_t* stanza_create_invite(xmpp_ctx_t *ctx, const char *const room, const char *const contact, const char *const reason, const char *const password) { - char *id = create_unique_id(NULL); + char *id = connection_create_stanza_id(NULL); xmpp_stanza_t *message = xmpp_message_new(ctx, NULL, contact, id); free(id); @@ -524,7 +526,7 @@ xmpp_stanza_t* stanza_create_mediated_invite(xmpp_ctx_t *ctx, const char *const room, const char *const contact, const char *const reason) { - char *id = create_unique_id(NULL); + char *id = connection_create_stanza_id(NULL); xmpp_stanza_t *message = xmpp_message_new(ctx, NULL, room, id); free(id); @@ -616,7 +618,7 @@ stanza_create_room_leave_presence(xmpp_ctx_t *ctx, const char *const room, xmpp_stanza_t* stanza_create_instant_room_request_iq(xmpp_ctx_t *ctx, const char *const room_jid) { - char *id = create_unique_id("room"); + char *id = connection_create_stanza_id("room"); xmpp_stanza_t *iq = xmpp_iq_new(ctx, STANZA_TYPE_SET, id); free(id); xmpp_stanza_set_to(iq, room_jid); @@ -642,7 +644,7 @@ stanza_create_instant_room_request_iq(xmpp_ctx_t *ctx, const char *const room_ji xmpp_stanza_t* stanza_create_instant_room_destroy_iq(xmpp_ctx_t *ctx, const char *const room_jid) { - char *id = create_unique_id("room"); + char *id = connection_create_stanza_id("room"); xmpp_stanza_t *iq = xmpp_iq_new(ctx, STANZA_TYPE_SET, id); free(id); xmpp_stanza_set_to(iq, room_jid); @@ -666,7 +668,7 @@ stanza_create_instant_room_destroy_iq(xmpp_ctx_t *ctx, const char *const room_ji xmpp_stanza_t* stanza_create_room_config_request_iq(xmpp_ctx_t *ctx, const char *const room_jid) { - char *id = create_unique_id("room"); + char *id = connection_create_stanza_id("room"); xmpp_stanza_t *iq = xmpp_iq_new(ctx, STANZA_TYPE_GET, id); free(id); xmpp_stanza_set_to(iq, room_jid); @@ -684,7 +686,7 @@ stanza_create_room_config_request_iq(xmpp_ctx_t *ctx, const char *const room_jid xmpp_stanza_t* stanza_create_room_config_cancel_iq(xmpp_ctx_t *ctx, const char *const room_jid) { - char *id = create_unique_id("room"); + char *id = connection_create_stanza_id("room"); xmpp_stanza_t *iq = xmpp_iq_new(ctx, STANZA_TYPE_SET, id); free(id); xmpp_stanza_set_to(iq, room_jid); @@ -710,7 +712,7 @@ stanza_create_room_config_cancel_iq(xmpp_ctx_t *ctx, const char *const room_jid) xmpp_stanza_t* stanza_create_room_affiliation_list_iq(xmpp_ctx_t *ctx, const char *const room, const char *const affiliation) { - char *id = create_unique_id("affiliation_get"); + char *id = connection_create_stanza_id("affiliation_get"); xmpp_stanza_t *iq = xmpp_iq_new(ctx, STANZA_TYPE_GET, id); free(id); xmpp_stanza_set_to(iq, room); @@ -734,7 +736,7 @@ stanza_create_room_affiliation_list_iq(xmpp_ctx_t *ctx, const char *const room, xmpp_stanza_t* stanza_create_room_role_list_iq(xmpp_ctx_t *ctx, const char *const room, const char *const role) { - char *id = create_unique_id("role_get"); + char *id = connection_create_stanza_id("role_get"); xmpp_stanza_t *iq = xmpp_iq_new(ctx, STANZA_TYPE_GET, id); free(id); xmpp_stanza_set_to(iq, room); @@ -759,7 +761,7 @@ xmpp_stanza_t* stanza_create_room_affiliation_set_iq(xmpp_ctx_t *ctx, const char *const room, const char *const jid, const char *const affiliation, const char *const reason) { - char *id = create_unique_id("affiliation_set"); + char *id = connection_create_stanza_id("affiliation_set"); xmpp_stanza_t *iq = xmpp_iq_new(ctx, STANZA_TYPE_SET, id); free(id); xmpp_stanza_set_to(iq, room); @@ -797,7 +799,7 @@ xmpp_stanza_t* stanza_create_room_role_set_iq(xmpp_ctx_t *const ctx, const char *const room, const char *const nick, const char *const role, const char *const reason) { - char *id = create_unique_id("role_set"); + char *id = connection_create_stanza_id("role_set"); xmpp_stanza_t *iq = xmpp_iq_new(ctx, STANZA_TYPE_SET, id); free(id); xmpp_stanza_set_to(iq, room); @@ -835,7 +837,7 @@ xmpp_stanza_t* stanza_create_room_kick_iq(xmpp_ctx_t *const ctx, const char *const room, const char *const nick, const char *const reason) { - char *id = create_unique_id("room_kick"); + char *id = connection_create_stanza_id("room_kick"); xmpp_stanza_t *iq = xmpp_iq_new(ctx, STANZA_TYPE_SET, id); free(id); xmpp_stanza_set_to(iq, room); @@ -872,7 +874,7 @@ stanza_create_room_kick_iq(xmpp_ctx_t *const ctx, const char *const room, const xmpp_stanza_t* stanza_create_software_version_iq(xmpp_ctx_t *ctx, const char *const fulljid) { - char *id = create_unique_id("sv"); + char *id = connection_create_stanza_id("sv"); xmpp_stanza_t *iq = xmpp_iq_new(ctx, STANZA_TYPE_GET, id); free(id); xmpp_stanza_set_to(iq, fulljid); @@ -924,7 +926,7 @@ stanza_create_disco_info_iq(xmpp_ctx_t *ctx, const char *const id, const char *c xmpp_stanza_t* stanza_create_disco_items_iq(xmpp_ctx_t *ctx, const char *const id, - const char *const jid) + const char *const jid, const char *const node) { xmpp_stanza_t *iq = xmpp_iq_new(ctx, STANZA_TYPE_GET, id); xmpp_stanza_set_to(iq, jid); @@ -932,6 +934,9 @@ stanza_create_disco_items_iq(xmpp_ctx_t *ctx, const char *const id, xmpp_stanza_t *query = xmpp_stanza_new(ctx); xmpp_stanza_set_name(query, STANZA_NAME_QUERY); xmpp_stanza_set_ns(query, XMPP_NS_DISCO_ITEMS); + if (node) { + xmpp_stanza_set_attribute(query, STANZA_ATTR_NODE, node); + } xmpp_stanza_add_child(iq, query); xmpp_stanza_release(query); @@ -958,7 +963,7 @@ stanza_create_last_activity_iq(xmpp_ctx_t *ctx, const char *const id, const char xmpp_stanza_t* stanza_create_room_config_submit_iq(xmpp_ctx_t *ctx, const char *const room, DataForm *form) { - char *id = create_unique_id("roomconf_submit"); + char *id = connection_create_stanza_id("roomconf_submit"); xmpp_stanza_t *iq = xmpp_iq_new(ctx, STANZA_TYPE_SET, id); free(id); xmpp_stanza_set_to(iq, room); @@ -1035,7 +1040,7 @@ stanza_contains_chat_state(xmpp_stanza_t *stanza) xmpp_stanza_t* stanza_create_ping_iq(xmpp_ctx_t *ctx, const char *const target) { - char *id = create_unique_id("ping"); + char *id = connection_create_stanza_id("ping"); xmpp_stanza_t *iq = xmpp_iq_new(ctx, STANZA_TYPE_GET, id); free(id); if (target) { @@ -1143,7 +1148,7 @@ stanza_create_caps_sha1_from_query(xmpp_stanza_t *const query) curr = g_slist_next(curr); } - char *result = p_sha1_hash(s->str); + char *result = _stanza_create_sha1_hash(s->str); g_string_free(s, TRUE); g_slist_free_full(identities, g_free); @@ -2038,10 +2043,74 @@ stanza_parse_presence(xmpp_stanza_t *stanza, int *err) return result; } +xmpp_stanza_t* +stanza_create_command_exec_iq(xmpp_ctx_t *ctx, const char *const target, + const char *const node) +{ + char *id = connection_create_stanza_id("cmdexec"); + xmpp_stanza_t *iq = xmpp_iq_new(ctx, STANZA_TYPE_SET, id); + free(id); + xmpp_stanza_set_to(iq, target); + + xmpp_stanza_t *command = xmpp_stanza_new(ctx); + xmpp_stanza_set_name(command, STANZA_NAME_COMMAND); + + xmpp_stanza_set_ns(command, STANZA_NS_COMMAND); + xmpp_stanza_set_attribute(command, "node", node); + xmpp_stanza_set_attribute(command, "action", "execute"); + + xmpp_stanza_add_child(iq, command); + xmpp_stanza_release(command); + + return iq; +} + +xmpp_stanza_t* +stanza_create_command_config_submit_iq(xmpp_ctx_t *ctx, const char *const room, + const char *const node, const char *const sessionid, DataForm *form) +{ + char *id = connection_create_stanza_id("commandconf_submit"); + xmpp_stanza_t *iq = xmpp_iq_new(ctx, STANZA_TYPE_SET, id); + free(id); + xmpp_stanza_set_to(iq, room); + + xmpp_stanza_t *command = xmpp_stanza_new(ctx); + xmpp_stanza_set_name(command, STANZA_NAME_COMMAND); + xmpp_stanza_set_ns(command, STANZA_NS_COMMAND); + xmpp_stanza_set_attribute(command, "node", node); + if (sessionid != NULL) { + xmpp_stanza_set_attribute(command, "sessionid", sessionid); + } + + xmpp_stanza_t *x = form_create_submission(form); + xmpp_stanza_add_child(command, x); + xmpp_stanza_release(x); + + xmpp_stanza_add_child(iq, command); + xmpp_stanza_release(command); + + return iq; +} + static void _stanza_add_unique_id(xmpp_stanza_t *stanza, char *prefix) { - char *id = create_unique_id(prefix); + char *id = connection_create_stanza_id(prefix); xmpp_stanza_set_id(stanza, id); free(id); } + +static char* +_stanza_create_sha1_hash(char *str) +{ + unsigned char *digest = (unsigned char*)malloc(XMPP_SHA1_DIGEST_SIZE); + assert(digest != NULL); + + xmpp_sha1_digest((unsigned char*)str, strlen(str), digest); + + char *b64 = g_base64_encode(digest, XMPP_SHA1_DIGEST_SIZE); + assert(b64 != NULL); + free(digest); + + return b64; +} diff --git a/src/xmpp/stanza.h b/src/xmpp/stanza.h index bd161616..d3c3c9dc 100644 --- a/src/xmpp/stanza.h +++ b/src/xmpp/stanza.h @@ -1,7 +1,7 @@ /* * stanza.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -99,6 +99,7 @@ #define STANZA_NAME_PUT "put" #define STANZA_NAME_GET "get" #define STANZA_NAME_URL "url" +#define STANZA_NAME_COMMAND "command" // error conditions #define STANZA_NAME_BAD_REQUEST "bad-request" @@ -156,6 +157,7 @@ #define STANZA_ATTR_REASON "reason" #define STANZA_ATTR_AUTOJOIN "autojoin" #define STANZA_ATTR_PASSWORD "password" +#define STANZA_ATTR_STATUS "status" #define STANZA_TEXT_AWAY "away" #define STANZA_TEXT_DND "dnd" @@ -186,6 +188,7 @@ #define STANZA_NS_HTTP_UPLOAD "urn:xmpp:http:upload" #define STANZA_NS_X_OOB "jabber:x:oob" #define STANZA_NS_BLOCKING "urn:xmpp:blocking" +#define STANZA_NS_COMMAND "http://jabber.org/protocol/commands" #define STANZA_DATAFORM_SOFTWARE "urn:xmpp:dataforms:softwareinfo" @@ -278,6 +281,9 @@ xmpp_stanza_t* stanza_create_room_subject_message(xmpp_ctx_t *ctx, const char *c xmpp_stanza_t* stanza_create_room_kick_iq(xmpp_ctx_t *const ctx, const char *const room, const char *const nick, const char *const reason); +xmpp_stanza_t* stanza_create_command_exec_iq(xmpp_ctx_t *ctx, const char *const target, const char *const node); +xmpp_stanza_t* stanza_create_command_config_submit_iq(xmpp_ctx_t *ctx, const char *const room, const char *const node, const char *const sessionid, DataForm *form); + int stanza_get_idle_time(xmpp_stanza_t *const stanza); void stanza_attach_priority(xmpp_ctx_t *const ctx, xmpp_stanza_t *const presence, const int pri); @@ -292,7 +298,7 @@ EntityCapabilities* stanza_create_caps_from_query_element(xmpp_stanza_t *query); const char* stanza_get_presence_string_from_type(resource_presence_t presence_type); xmpp_stanza_t* stanza_create_software_version_iq(xmpp_ctx_t *ctx, const char *const fulljid); -xmpp_stanza_t* stanza_create_disco_items_iq(xmpp_ctx_t *ctx, const char *const id, const char *const jid); +xmpp_stanza_t* stanza_create_disco_items_iq(xmpp_ctx_t *ctx, const char *const id, const char *const jid, const char *const node); char* stanza_get_status(xmpp_stanza_t *stanza, char *def); char* stanza_get_show(xmpp_stanza_t *stanza, char *def); diff --git a/src/xmpp/xmpp.h b/src/xmpp/xmpp.h index d4a29196..c9403090 100644 --- a/src/xmpp/xmpp.h +++ b/src/xmpp/xmpp.h @@ -1,7 +1,7 @@ /* * xmpp.h * - * Copyright (C) 2012 - 2018 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -60,6 +60,7 @@ #define XMPP_FEATURE_RECEIPTS "urn:xmpp:receipts" #define XMPP_FEATURE_LASTACTIVITY "jabber:iq:last" #define XMPP_FEATURE_MUC "http://jabber.org/protocol/muc" +#define XMPP_FEATURE_COMMANDS "http://jabber.org/protocol/commands" typedef enum { JABBER_CONNECTING, @@ -170,8 +171,8 @@ void iq_set_autoping(int seconds); void iq_confirm_instant_room(const char *const room_jid); void iq_destroy_room(const char *const room_jid); void iq_request_room_config_form(const char *const room_jid); -void iq_submit_room_config(const char *const room, DataForm *form); -void iq_room_config_cancel(const char *const room_jid); +void iq_submit_room_config(ProfConfWin *confwin); +void iq_room_config_cancel(ProfConfWin *confwin); void iq_send_ping(const char *const target); void iq_room_info_request(const char *const room, gboolean display_result); void iq_room_affiliation_list(const char *const room, char *affiliation); @@ -182,6 +183,8 @@ void iq_room_role_set(const char *const room, const char *const nick, char *role void iq_room_role_list(const char * const room, char *role); void iq_autoping_check(void); void iq_http_upload_request(HTTPUpload *upload); +void iq_command_list(const char *const target); +void iq_command_exec(const char *const target, const char *const command); EntityCapabilities* caps_lookup(const char *const jid); void caps_close(void); |