diff options
Diffstat (limited to 'src/command')
-rw-r--r-- | src/command/cmd_ac.c | 246 | ||||
-rw-r--r-- | src/command/cmd_defs.c | 125 | ||||
-rw-r--r-- | src/command/cmd_defs.h | 1 | ||||
-rw-r--r-- | src/command/cmd_funcs.c | 756 | ||||
-rw-r--r-- | src/command/cmd_funcs.h | 14 |
5 files changed, 1047 insertions, 95 deletions
diff --git a/src/command/cmd_ac.c b/src/command/cmd_ac.c index 58ad758a..5abee8be 100644 --- a/src/command/cmd_ac.c +++ b/src/command/cmd_ac.c @@ -2,6 +2,7 @@ * cmd_ac.c * * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> + * Copyright (C) 2019 Michael Vetter <jubalh@iodoru.org> * * This file is part of Profanity. * @@ -57,6 +58,10 @@ #include "pgp/gpg.h" #endif +#ifdef HAVE_OMEMO +#include "omemo/omemo.h" +#endif + static char* _sub_autocomplete(ProfWin *window, const char *const input, gboolean previous); static char* _notify_autocomplete(ProfWin *window, const char *const input, gboolean previous); static char* _theme_autocomplete(ProfWin *window, const char *const input, gboolean previous); @@ -69,6 +74,7 @@ static char* _group_autocomplete(ProfWin *window, const char *const input, gbool static char* _bookmark_autocomplete(ProfWin *window, const char *const input, gboolean previous); static char* _otr_autocomplete(ProfWin *window, const char *const input, gboolean previous); static char* _pgp_autocomplete(ProfWin *window, const char *const input, gboolean previous); +static char* _omemo_autocomplete(ProfWin *window, const char *const input, gboolean previous); static char* _connect_autocomplete(ProfWin *window, const char *const input, gboolean previous); static char* _alias_autocomplete(ProfWin *window, const char *const input, gboolean previous); static char* _join_autocomplete(ProfWin *window, const char *const input, gboolean previous); @@ -157,6 +163,9 @@ static Autocomplete bookmark_property_ac; static Autocomplete otr_ac; static Autocomplete otr_log_ac; static Autocomplete otr_policy_ac; +static Autocomplete omemo_ac; +static Autocomplete omemo_log_ac; +static Autocomplete omemo_policy_ac; static Autocomplete connect_property_ac; static Autocomplete tls_property_ac; static Autocomplete alias_ac; @@ -175,6 +184,9 @@ static Autocomplete form_field_multi_ac; static Autocomplete occupants_ac; static Autocomplete occupants_default_ac; static Autocomplete occupants_show_ac; +static Autocomplete occupants_header_ac; +static Autocomplete occupants_header_char_ac; +static Autocomplete occupants_char_ac; static Autocomplete time_ac; static Autocomplete time_format_ac; static Autocomplete resource_ac; @@ -237,6 +249,7 @@ cmd_ac_init(void) autocomplete_add(prefs_ac, "presence"); autocomplete_add(prefs_ac, "otr"); autocomplete_add(prefs_ac, "pgp"); + autocomplete_add(prefs_ac, "omemo"); notify_ac = autocomplete_new(); autocomplete_add(notify_ac, "chat"); @@ -574,6 +587,27 @@ cmd_ac_init(void) autocomplete_add(otr_policy_ac, "opportunistic"); autocomplete_add(otr_policy_ac, "always"); + omemo_ac = autocomplete_new(); + autocomplete_add(omemo_ac, "gen"); + autocomplete_add(omemo_ac, "log"); + autocomplete_add(omemo_ac, "start"); + autocomplete_add(omemo_ac, "end"); + autocomplete_add(omemo_ac, "trust"); + autocomplete_add(omemo_ac, "untrust"); + autocomplete_add(omemo_ac, "fingerprint"); + autocomplete_add(omemo_ac, "clear_device_list"); + autocomplete_add(omemo_ac, "policy"); + + omemo_log_ac = autocomplete_new(); + autocomplete_add(omemo_log_ac, "on"); + autocomplete_add(omemo_log_ac, "off"); + autocomplete_add(omemo_log_ac, "redact"); + + omemo_policy_ac = autocomplete_new(); + autocomplete_add(omemo_policy_ac, "manual"); + autocomplete_add(omemo_policy_ac, "automatic"); + autocomplete_add(omemo_policy_ac, "always"); + connect_property_ac = autocomplete_new(); autocomplete_add(connect_property_ac, "server"); autocomplete_add(connect_property_ac, "port"); @@ -653,6 +687,10 @@ cmd_ac_init(void) autocomplete_add(occupants_ac, "hide"); autocomplete_add(occupants_ac, "default"); autocomplete_add(occupants_ac, "size"); + autocomplete_add(occupants_ac, "indent"); + autocomplete_add(occupants_ac, "header"); + autocomplete_add(occupants_ac, "wrap"); + autocomplete_add(occupants_ac, "char"); occupants_default_ac = autocomplete_new(); autocomplete_add(occupants_default_ac, "show"); @@ -661,6 +699,15 @@ cmd_ac_init(void) occupants_show_ac = autocomplete_new(); autocomplete_add(occupants_show_ac, "jid"); + occupants_char_ac = autocomplete_new(); + autocomplete_add(occupants_char_ac, "none"); + + occupants_header_ac = autocomplete_new(); + autocomplete_add(occupants_header_ac, "char"); + + occupants_header_char_ac = autocomplete_new(); + autocomplete_add(occupants_header_char_ac, "none"); + time_ac = autocomplete_new(); autocomplete_add(time_ac, "console"); autocomplete_add(time_ac, "chat"); @@ -670,6 +717,7 @@ cmd_ac_init(void) autocomplete_add(time_ac, "xml"); autocomplete_add(time_ac, "statusbar"); autocomplete_add(time_ac, "lastactivity"); + autocomplete_add(time_ac, "all"); time_format_ac = autocomplete_new(); autocomplete_add(time_format_ac, "set"); @@ -983,6 +1031,9 @@ cmd_ac_reset(ProfWin *window) #ifdef HAVE_LIBGPGME p_gpg_autocomplete_key_reset(); #endif +#ifdef HAVE_OMEMO + omemo_fingerprint_autocomplete_reset(); +#endif autocomplete_reset(help_ac); autocomplete_reset(help_commands_ac); autocomplete_reset(notify_ac); @@ -1052,6 +1103,9 @@ cmd_ac_reset(ProfWin *window) autocomplete_reset(otr_ac); autocomplete_reset(otr_log_ac); autocomplete_reset(otr_policy_ac); + autocomplete_reset(omemo_ac); + autocomplete_reset(omemo_log_ac); + autocomplete_reset(omemo_policy_ac); autocomplete_reset(connect_property_ac); autocomplete_reset(tls_property_ac); autocomplete_reset(alias_ac); @@ -1068,8 +1122,11 @@ cmd_ac_reset(ProfWin *window) autocomplete_reset(form_ac); autocomplete_reset(form_field_multi_ac); autocomplete_reset(occupants_ac); + autocomplete_reset(occupants_char_ac); autocomplete_reset(occupants_default_ac); autocomplete_reset(occupants_show_ac); + autocomplete_reset(occupants_header_ac); + autocomplete_reset(occupants_header_char_ac); autocomplete_reset(time_ac); autocomplete_reset(time_format_ac); autocomplete_reset(resource_ac); @@ -1179,6 +1236,9 @@ cmd_ac_uninit(void) autocomplete_free(otr_ac); autocomplete_free(otr_log_ac); autocomplete_free(otr_policy_ac); + autocomplete_free(omemo_ac); + autocomplete_free(omemo_log_ac); + autocomplete_free(omemo_policy_ac); autocomplete_free(connect_property_ac); autocomplete_free(tls_property_ac); autocomplete_free(alias_ac); @@ -1195,8 +1255,10 @@ cmd_ac_uninit(void) autocomplete_free(form_ac); autocomplete_free(form_field_multi_ac); autocomplete_free(occupants_ac); + autocomplete_free(occupants_char_ac); autocomplete_free(occupants_default_ac); autocomplete_free(occupants_show_ac); + autocomplete_free(occupants_header_ac); autocomplete_free(time_ac); autocomplete_free(time_format_ac); autocomplete_free(resource_ac); @@ -1228,11 +1290,15 @@ cmd_ac_uninit(void) autocomplete_free(statusbar_show_ac); } +static void +_filepath_item_free(char **ptr) { + char *item = *ptr; + free(item); +} + char* cmd_ac_complete_filepath(const char *const input, char *const startstr, gboolean previous) { - static char* last_directory = NULL; - unsigned int output_off = 0; char *result = NULL; @@ -1260,11 +1326,13 @@ cmd_ac_complete_filepath(const char *const input, char *const startstr, gboolean // expand ~ to $HOME if (inpcp[0] == '~' && inpcp[1] == '/') { if (asprintf(&tmp, "%s/%sfoo", getenv("HOME"), inpcp+2) == -1) { + free(inpcp); return NULL; } output_off = strlen(getenv("HOME"))+1; } else { if (asprintf(&tmp, "%sfoo", inpcp) == -1) { + free(inpcp); return NULL; } } @@ -1277,56 +1345,61 @@ cmd_ac_complete_filepath(const char *const input, char *const startstr, gboolean free(inpcp); free(inpcp2); - if (!last_directory || strcmp(last_directory, directory) != 0) { - free(last_directory); - last_directory = directory; - autocomplete_reset(filepath_ac); - - struct dirent *dir; - - DIR *d = opendir(directory); - if (d) { - while ((dir = readdir(d)) != NULL) { - if (strcmp(dir->d_name, ".") == 0) { - continue; - } else if (strcmp(dir->d_name, "..") == 0) { - continue; - } else if (*(dir->d_name) == '.' && *foofile != '.') { - // only show hidden files on explicit request - continue; + struct dirent *dir; + GArray *files = g_array_new(TRUE, FALSE, sizeof(char *)); + g_array_set_clear_func(files, (GDestroyNotify)_filepath_item_free); + + DIR *d = opendir(directory); + if (d) { + while ((dir = readdir(d)) != NULL) { + if (strcmp(dir->d_name, ".") == 0) { + continue; + } else if (strcmp(dir->d_name, "..") == 0) { + continue; + } else if (*(dir->d_name) == '.' && *foofile != '.') { + // only show hidden files on explicit request + continue; + } + + char *acstring; + if (output_off) { + if (asprintf(&tmp, "%s/%s", directory, dir->d_name) == -1) { + free(directory); + free(foofile); + return NULL; + } + if (asprintf(&acstring, "~/%s", tmp+output_off) == -1) { + free(directory); + free(foofile); + return NULL; + } + free(tmp); + } else if (strcmp(directory, "/") == 0) { + if (asprintf(&acstring, "/%s", dir->d_name) == -1) { + free(directory); + free(foofile); + return NULL; } - char * acstring; - if (output_off) { - if (asprintf(&tmp, "%s/%s", directory, dir->d_name) == -1) { - free(foofile); - return NULL; - } - if (asprintf(&acstring, "~/%s", tmp+output_off) == -1) { - free(foofile); - return NULL; - } - free(tmp); - } else if (strcmp(directory, "/") == 0) { - if (asprintf(&acstring, "/%s", dir->d_name) == -1) { - free(foofile); - return NULL; - } - } else { - if (asprintf(&acstring, "%s/%s", directory, dir->d_name) == -1) { - free(foofile); - return NULL; - } + } else { + if (asprintf(&acstring, "%s/%s", directory, dir->d_name) == -1) { + free(directory); + free(foofile); + return NULL; } - autocomplete_add(filepath_ac, acstring); - free(acstring); } - closedir(d); + + char *acstring_cpy = strdup(acstring); + g_array_append_val(files, acstring_cpy); + free(acstring); } - } else { - free(directory); + closedir(d); } + free(directory); free(foofile); + autocomplete_update(filepath_ac, (char **)files->data); + g_array_free(files, TRUE); + result = autocomplete_param_with_ac(input, startstr, filepath_ac, TRUE, previous); if (result) { return result; @@ -1438,6 +1511,7 @@ _cmd_ac_complete_params(ProfWin *window, const char *const input, gboolean previ g_hash_table_insert(ac_funcs, "/autoconnect", _autoconnect_autocomplete); g_hash_table_insert(ac_funcs, "/otr", _otr_autocomplete); g_hash_table_insert(ac_funcs, "/pgp", _pgp_autocomplete); + g_hash_table_insert(ac_funcs, "/omemo", _omemo_autocomplete); g_hash_table_insert(ac_funcs, "/connect", _connect_autocomplete); g_hash_table_insert(ac_funcs, "/alias", _alias_autocomplete); g_hash_table_insert(ac_funcs, "/join", _join_autocomplete); @@ -2118,6 +2192,63 @@ _pgp_autocomplete(ProfWin *window, const char *const input, gboolean previous) } static char* +_omemo_autocomplete(ProfWin *window, const char *const input, gboolean previous) +{ + char *found = NULL; + + found = autocomplete_param_with_ac(input, "/omemo log", omemo_log_ac, TRUE, previous); + if (found) { + return found; + } + + found = autocomplete_param_with_ac(input, "/omemo policy", omemo_policy_ac, TRUE, previous); + if (found) { + return found; + } + + jabber_conn_status_t conn_status = connection_get_status(); + + if (conn_status == JABBER_CONNECTED) { + found = autocomplete_param_with_func(input, "/omemo start", roster_contact_autocomplete, previous); + if (found) { + return found; + } + + found = autocomplete_param_with_func(input, "/omemo fingerprint", roster_contact_autocomplete, previous); + if (found) { + return found; + } + + +#ifdef HAVE_OMEMO + if (window->type == WIN_CHAT) { + found = autocomplete_param_with_func(input, "/omemo trust", omemo_fingerprint_autocomplete, previous); + if (found) { + return found; + } + } else { + found = autocomplete_param_with_func(input, "/omemo trust", roster_contact_autocomplete, previous); + if (found) { + return found; + } + + found = autocomplete_param_no_with_func(input, "/omemo trust", 4, omemo_fingerprint_autocomplete, previous); + if (found) { + return found; + } + } +#endif + } + + found = autocomplete_param_with_ac(input, "/omemo", omemo_ac, TRUE, previous); + if (found) { + return found; + } + + return NULL; +} + +static char* _plugins_autocomplete(ProfWin *window, const char *const input, gboolean previous) { char *result = NULL; @@ -2453,6 +2584,11 @@ _occupants_autocomplete(ProfWin *window, const char *const input, gboolean previ return found; } + found = autocomplete_param_with_ac(input, "/occupants char", occupants_char_ac, TRUE, previous); + if (found) { + return found; + } + found = autocomplete_param_with_ac(input, "/occupants default hide", occupants_show_ac, TRUE, previous); if (found) { return found; @@ -2473,6 +2609,21 @@ _occupants_autocomplete(ProfWin *window, const char *const input, gboolean previ return found; } + found = autocomplete_param_with_ac(input, "/occupants header char", roster_char_ac, TRUE, previous); + if (found) { + return found; + } + + found = autocomplete_param_with_ac(input, "/occupants header", occupants_header_ac, TRUE, previous); + if (found) { + return found; + } + + found = autocomplete_param_with_func(input, "/occupants wrap", prefs_autocomplete_boolean_choice, previous); + if (found) { + return found; + } + found = autocomplete_param_with_ac(input, "/occupants", occupants_ac, TRUE, previous); if (found) { return found; @@ -2526,6 +2677,11 @@ _time_autocomplete(ProfWin *window, const char *const input, gboolean previous) return found; } + found = autocomplete_param_with_ac(input, "/time all", time_format_ac, TRUE, previous); + if (found) { + return found; + } + found = autocomplete_param_with_ac(input, "/time", time_ac, TRUE, previous); if (found) { return found; diff --git a/src/command/cmd_defs.c b/src/command/cmd_defs.c index 4447020b..e7ece238 100644 --- a/src/command/cmd_defs.c +++ b/src/command/cmd_defs.c @@ -2,6 +2,7 @@ * cmd_defs.c * * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> + * Copyright (C) 2019 Michael Vetter <jubalh@iodoru.org> * * This file is part of Profanity. * @@ -372,7 +373,7 @@ static struct cmd_t command_defs[] = { "resource indent <indent>", "Indent resource line by <indent> spaces (0 to 10)." }, { "resource join on|off", "Join resource with previous line when only one available resource." }, { "presence indent <indent>", "Indent presence line by <indent> spaces (-1 to 10), a value of -1 will show presence on the previous line." }, - { "size <precent>", "Percentage of the screen taken up by the roster (1-99)." }, + { "size <percent>", "Percentage of the screen taken up by the roster (1-99)." }, { "wrap on|off", "Enable or disable line wrapping in roster panel." }, { "add <jid> [<nick>]", "Add a new item to the roster." }, { "remove <jid>", "Removes an item from the roster." }, @@ -401,12 +402,14 @@ static struct cmd_t command_defs[] = "/blocked add [<jid>]", "/blocked remove <jid>") CMD_DESC( - "Manage blocked users, calling with no arguments shows the current list of blocked users.") + "Manage blocked users (XEP-0191), calling with no arguments shows the current list of blocked users." + "To blog a certain user in a MUC use the following as jid: room@conference.example.org/spammy-user") CMD_ARGS( { "add [<jid>]", "Block the specified Jabber ID. If in a chat window and no jid is specified, the current recipient will be blocked." }, { "remove <jid>", "Remove the specified Jabber ID from the blocked list." }) CMD_EXAMPLES( - "/blocked add spammer@spam.org") + "/blocked add spammer@spam.org", + "/blocked add profanity@rooms.dismail.de/spammy-user") }, { "/group", @@ -570,10 +573,10 @@ static struct cmd_t command_defs[] = { "password <password>", "Password if the room requires one." }) CMD_EXAMPLES( "/join", - "/join jdev@conference.jabber.org", - "/join jdev@conference.jabber.org nick mynick", + "/join profanity@rooms.dismail.de", + "/join profanity@rooms.dismail.de nick mynick", "/join private@conference.jabber.org nick mynick password mypassword", - "/join jdev") + "/join mychannel") }, { "/leave", @@ -752,18 +755,28 @@ static struct cmd_t command_defs[] = CMD_TAG_UI) CMD_SYN( "/occupants show|hide [jid]", + "/occupants char <char>|none", "/occupants default show|hide [jid]", - "/occupants size [<percent>]") + "/occupants size [<percent>]", + "/occupants indent <indent>", + "/occupants header char <char>|none", + "/occupants wrap on|off") CMD_DESC( "Show or hide room occupants, and occupants panel display settings.") CMD_ARGS( { "show", "Show the occupants panel in current room." }, + { "char <char>", "Prefix occupants with specified character." }, + { "char none", "Remove occupants character prefix." }, { "hide", "Hide the occupants panel in current room." }, { "show jid", "Show jid in the occupants panel in current room." }, { "hide jid", "Hide jid in the occupants panel in current room." }, { "default show|hide", "Whether occupants are shown by default in new rooms." }, { "default show|hide jid", "Whether occupants jids are shown by default in new rooms." }, - { "size <percent>", "Percentage of the screen taken by the occupants list in rooms (1-99)." }) + { "size <percent>", "Percentage of the screen taken by the occupants list in rooms (1-99)." }, + { "indent <indent>", "Indent contact line by <indent> spaces (0 to 10)." }, + { "header char <char>", "Prefix occupants headers with specified character." }, + { "header char none", "Remove occupants header character prefix." }, + { "wrap on|off", "Enable or disable line wrapping in occupants panel." }) CMD_NOEXAMPLES }, @@ -1027,7 +1040,7 @@ static struct cmd_t command_defs[] = CMD_ARGS( { "<url>", "The url to make tiny." }) CMD_EXAMPLES( - "Example: /tiny http://www.profanity.im") + "Example: /tiny https://profanity-im.github.io/") }, { "/who", @@ -1266,8 +1279,8 @@ static struct cmd_t command_defs[] = CMD_TAGS( CMD_TAG_UI) CMD_SYN( - "/time console|chat|muc|config|private|xml set <format>", - "/time console|chat|muc|config|private|xml off", + "/time all|console|chat|muc|config|private|xml set <format>", + "/time all|console|chat|muc|config|private|xml off", "/time statusbar set <format>", "/time statusbar off", "/time lastactivity set <format>") @@ -1292,13 +1305,16 @@ static struct cmd_t command_defs[] = { "xml off", "Do not show time in XML console window." }, { "statusbar set <format>", "Change time format in statusbar." }, { "statusbar off", "Do not show time in status bar." }, - { "lastactivity set <format>", "Change time format for last activity." }) + { "lastactivity set <format>", "Change time format for last activity." }, + { "all set <format>", "Set time for: console, chat, muc, config, private and xml windows." }, + { "all off", "Do not show time for: console, chat, muc, config, private and xml windows." }) CMD_EXAMPLES( "/time console set %H:%M:%S", "/time chat set \"%d-%m-%y %H:%M:%S\"", "/time xml off", "/time statusbar set %H:%M", - "/time lastactivity set \"%d-%m-%y %H:%M:%S\"") + "/time lastactivity set \"%d-%m-%y %H:%M:%S\"", + "/time all set \"%d-%m-%y %H:%M:%S\"") }, { "/inpblock", @@ -2134,7 +2150,7 @@ static struct cmd_t command_defs[] = CMD_MAINFUNC(cmd_prefs) CMD_NOTAGS CMD_SYN( - "/prefs [ui|desktop|chat|log|conn|presence|otr|pgp]") + "/prefs [ui|desktop|chat|log|conn|presence|otr|pgp|omemo]") CMD_DESC( "Show preferences for different areas of functionality. " "Passing no arguments shows all preferences.") @@ -2146,7 +2162,8 @@ static struct cmd_t command_defs[] = { "conn", "Connection handling preferences." }, { "presence", "Chat presence preferences." }, { "otr", "Off The Record preferences." }, - { "pgp", "OpenPGP preferences." }) + { "pgp", "OpenPGP preferences." }, + { "omemo", "OMEMO preferences." }) CMD_NOEXAMPLES }, @@ -2328,7 +2345,82 @@ static struct cmd_t command_defs[] = CMD_EXAMPLES( "/cmd list", "/cmd exec ping") - } + }, + + { "/omemo", + parse_args, 1, 3, NULL, + CMD_SUBFUNCS( + { "gen", cmd_omemo_gen }, + { "log", cmd_omemo_log }, + { "start", cmd_omemo_start }, + { "end", cmd_omemo_end }, + { "trust", cmd_omemo_trust }, + { "untrust", cmd_omemo_untrust }, + { "fingerprint", cmd_omemo_fingerprint }, + { "char", cmd_omemo_char }, + { "policy", cmd_omemo_policy }, + { "clear_device_list", cmd_omemo_clear_device_list }) + CMD_NOMAINFUNC + CMD_TAGS( + CMD_TAG_CHAT, + CMD_TAG_UI) + CMD_SYN( + "/omemo gen", + "/omemo log on|off|redact", + "/omemo start [<contact>]", + "/omemo trust [<contact>] <fingerprint>", + "/omemo end", + "/omemo fingerprint [<contact>]", + "/omemo char <char>", + "/omemo policy manual|automatic|always", + "/omemo clear_device_list") + CMD_DESC( + "OMEMO commands to manage keys, and perform encryption during chat sessions.") + CMD_ARGS( + { "gen", "Generate OMEMO crytographic materials for current account." }, + { "start [<contact>]", "Start an OMEMO session with contact, or current recipient if omitted." }, + { "end", "End the current OMEMO session." }, + { "log on|off", "Enable or disable plaintext logging of OMEMO encrypted messages." }, + { "log redact", "Log OMEMO encrypted messages, but replace the contents with [redacted]. This is the default." }, + { "fingerprint [<contact>]", "Show contact fingerprints, or current recipient if omitted." }, + { "char <char>", "Set the character to be displayed next to OMEMO encrypted messages." }, + { "policy manual", "Set the global OMEMO policy to manual, OMEMO sessions must be started manually." }, + { "policy automatic", "Set the global OMEMO policy to opportunistic, an OMEMO session will be attempted upon starting a conversation." }, + { "policy always", "Set the global OMEMO policy to always, an error will be displayed if an OMEMO session cannot be initiated upon starting a conversation." }, + { "clear_device_list", "Clear your own device list on server side. Each client will reannounce itself when connected back."}) + CMD_EXAMPLES( + "/omemo gen", + "/omemo start buddy@buddychat.org", + "/omemo trust c4f9c875-144d7a3b-0c4a05b6-ca3be51a-a037f329-0bd3ae62-07f99719-55559d2a", + "/omemo untrust buddy@buddychat.org c4f9c875-144d7a3b-0c4a05b6-ca3be51a-a037f329-0bd3ae62-07f99719-55559d2a", + "/omemo char *") + }, + + { "/save", + parse_args, 0, 0, NULL, + CMD_NOSUBFUNCS + CMD_MAINFUNC(cmd_save) + CMD_NOTAGS + CMD_SYN( + "/save") + CMD_DESC( + "Save preferences to configuration file.") + CMD_NOARGS + CMD_NOEXAMPLES + }, + + { "/reload", + parse_args, 0, 0, NULL, + CMD_NOSUBFUNCS + CMD_MAINFUNC(cmd_reload) + CMD_NOTAGS + CMD_SYN( + "/reload") + CMD_DESC( + "Reload preferences from configuration file.") + CMD_NOARGS + CMD_NOEXAMPLES + }, }; static GHashTable *search_index; @@ -2363,7 +2455,6 @@ _cmd_index(Command *cmd) { g_string_free(index_source, TRUE); GString *index = g_string_new(""); - i = 0; for (i = 0; i < g_strv_length(tokens); i++) { index = g_string_append(index, tokens[i]); index = g_string_append(index, " "); diff --git a/src/command/cmd_defs.h b/src/command/cmd_defs.h index e6ce1053..fb3a12c4 100644 --- a/src/command/cmd_defs.h +++ b/src/command/cmd_defs.h @@ -2,6 +2,7 @@ * cmd_defs.h * * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> + * Copyright (C) 2019 Michael Vetter <jubalh@iodoru.org> * * This file is part of Profanity. * diff --git a/src/command/cmd_funcs.c b/src/command/cmd_funcs.c index 82d8dccc..afec87fe 100644 --- a/src/command/cmd_funcs.c +++ b/src/command/cmd_funcs.c @@ -2,6 +2,7 @@ * cmd_funcs.c * * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> + * Copyright (C) 2019 Michael Vetter <jubalh@iodoru.org> * * This file is part of Profanity. * @@ -85,6 +86,11 @@ #include "pgp/gpg.h" #endif +#ifdef HAVE_OMEMO +#include "omemo/omemo.h" +#include "xmpp/omemo.h" +#endif + #ifdef HAVE_GTK #include "ui/tray.h" #endif @@ -387,6 +393,7 @@ cmd_connect(ProfWin *window, const char *const command, gchar **args) } char *jid; + user = strdup(user); g_free(def); // connect with account @@ -413,8 +420,8 @@ cmd_connect(ProfWin *window, const char *const command, gchar **args) account->password = NULL; } else { cons_show("Error evaluating password, see logs for details."); - g_free(user); account_free(account); + free(user); return TRUE; } @@ -444,6 +451,7 @@ cmd_connect(ProfWin *window, const char *const command, gchar **args) options_destroy(options); free(jid); + free(user); return TRUE; } @@ -1673,6 +1681,10 @@ cmd_prefs(ProfWin *window, const char *const command, gchar **args) cons_show(""); cons_show_pgp_prefs(); cons_show(""); + } else if (strcmp(args[0], "omemo") == 0) { + cons_show(""); + cons_show_omemo_prefs(); + cons_show(""); } else { cons_bad_cmd_usage(command); } @@ -2140,17 +2152,67 @@ cmd_msg(ProfWin *window, const char *const command, gchar **args) } ui_focus_win((ProfWin*)chatwin); +#ifdef HAVE_OMEMO +#ifndef HAVE_LIBOTR + if (omemo_automatic_start(barejid)) { + omemo_start_session(barejid); + chatwin->is_omemo = TRUE; + } + + if (msg) { + cl_ev_send_msg(chatwin, msg, NULL); + } + + return TRUE; +#endif +#endif + +#ifdef HAVE_OMEMO +#ifdef HAVE_LIBOTR + if (omemo_automatic_start(barejid) && otr_is_secure(barejid)) { + win_println(window, THEME_DEFAULT, '!', "Chat could be either OMEMO or OTR encrypted. Use '/omemo start %s' or '/otr start %s' to start a session.", usr, usr); + return TRUE; + } else if (omemo_automatic_start(barejid)) { + omemo_start_session(barejid); + chatwin->is_omemo = TRUE; + } + if (msg) { cl_ev_send_msg(chatwin, msg, NULL); } else { + if (otr_is_secure(barejid)) { + chatwin_otr_secured(chatwin, otr_is_trusted(barejid)); + } + } + + return TRUE; +#endif +#endif + +#ifndef HAVE_OMEMO #ifdef HAVE_LIBOTR + if (msg) { + cl_ev_send_msg(chatwin, msg, NULL); + } else { if (otr_is_secure(barejid)) { chatwin_otr_secured(chatwin, otr_is_trusted(barejid)); } + } + + return TRUE; +#endif #endif + +#ifndef HAVE_OMEMO +#ifndef HAVE_LIBOTR + if (msg) { + cl_ev_send_msg(chatwin, msg, NULL); } return TRUE; +#endif +#endif + } } @@ -3154,6 +3216,16 @@ cmd_resource(ProfWin *window, const char *const command, gchar **args) } } +static void +_cmd_status_show_status(char* usr) +{ + char *usr_jid = roster_barejid_from_name(usr); + if (usr_jid == NULL) { + usr_jid = usr; + } + cons_show_status(usr_jid); +} + gboolean cmd_status(ProfWin *window, const char *const command, gchar **args) { @@ -3184,7 +3256,7 @@ cmd_status(ProfWin *window, const char *const command, gchar **args) break; case WIN_CHAT: if (usr) { - win_println(window, THEME_DEFAULT, '-', "No parameter required when in chat."); + _cmd_status_show_status(usr); } else { ProfChatWin *chatwin = (ProfChatWin*)window; assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); @@ -3198,7 +3270,7 @@ cmd_status(ProfWin *window, const char *const command, gchar **args) break; case WIN_PRIVATE: if (usr) { - win_println(window, THEME_DEFAULT, '-', "No parameter required when in chat."); + _cmd_status_show_status(usr); } else { ProfPrivateWin *privatewin = (ProfPrivateWin*)window; assert(privatewin->memcheck == PROFPRIVATEWIN_MEMCHECK); @@ -3214,11 +3286,7 @@ cmd_status(ProfWin *window, const char *const command, gchar **args) break; case WIN_CONSOLE: if (usr) { - char *usr_jid = roster_barejid_from_name(usr); - if (usr_jid == NULL) { - usr_jid = usr; - } - cons_show_status(usr_jid); + _cmd_status_show_status(usr); } else { cons_bad_cmd_usage(command); } @@ -3230,6 +3298,21 @@ cmd_status(ProfWin *window, const char *const command, gchar **args) return TRUE; } +static void +_cmd_info_show_contact(char *usr) +{ + char *usr_jid = roster_barejid_from_name(usr); + if (usr_jid == NULL) { + usr_jid = usr; + } + PContact pcontact = roster_get_contact(usr_jid); + if (pcontact) { + cons_show_info(pcontact); + } else { + cons_show("No such contact \"%s\" in roster.", usr); + } +} + gboolean cmd_info(ProfWin *window, const char *const command, gchar **args) { @@ -3264,7 +3347,7 @@ cmd_info(ProfWin *window, const char *const command, gchar **args) break; case WIN_CHAT: if (usr) { - win_println(window, THEME_DEFAULT, '-', "No parameter required when in chat."); + _cmd_info_show_contact(usr); } else { ProfChatWin *chatwin = (ProfChatWin*)window; assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); @@ -3278,7 +3361,7 @@ cmd_info(ProfWin *window, const char *const command, gchar **args) break; case WIN_PRIVATE: if (usr) { - win_println(window, THEME_DEFAULT, '-', "No parameter required when in chat."); + _cmd_info_show_contact(usr); } else { ProfPrivateWin *privatewin = (ProfPrivateWin*)window; assert(privatewin->memcheck == PROFPRIVATEWIN_MEMCHECK); @@ -3294,16 +3377,7 @@ cmd_info(ProfWin *window, const char *const command, gchar **args) break; case WIN_CONSOLE: if (usr) { - char *usr_jid = roster_barejid_from_name(usr); - if (usr_jid == NULL) { - usr_jid = usr; - } - PContact pcontact = roster_get_contact(usr_jid); - if (pcontact) { - cons_show_info(pcontact); - } else { - cons_show("No such contact \"%s\" in roster.", usr); - } + _cmd_info_show_contact(usr); } else { cons_bad_cmd_usage(command); } @@ -4247,12 +4321,6 @@ cmd_room(ProfWin *window, const char *const command, gchar **args) ProfMucWin *mucwin = (ProfMucWin*)window; assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); - int num = wins_get_num(window); - - int ui_index = num; - if (ui_index == 10) { - ui_index = 0; - } if (g_strcmp0(args[0], "accept") == 0) { gboolean requires_config = muc_requires_config(mucwin->roomjid); @@ -4310,6 +4378,55 @@ cmd_occupants(ProfWin *window, const char *const command, gchar **args) } } + if (g_strcmp0(args[0], "indent") == 0) { + if (!args[1]) { + cons_bad_cmd_usage(command); + return TRUE; + } else { + int intval = 0; + char *err_msg = NULL; + gboolean res = strtoi_range(args[1], &intval, 0, 10, &err_msg); + if (res) { + prefs_set_occupants_indent(intval); + cons_show("Occupants indent set to: %d", intval); + + occupantswin_occupants_all(); + } else { + cons_show(err_msg); + free(err_msg); + } + return TRUE; + } + } + + if (g_strcmp0(args[0], "wrap") == 0) { + if (!args[1]) { + cons_bad_cmd_usage(command); + return TRUE; + } else { + _cmd_set_boolean_preference(args[1], command, "Occupants panel line wrap", PREF_OCCUPANTS_WRAP); + occupantswin_occupants_all(); + return TRUE; + } + } + + if (g_strcmp0(args[0], "char") == 0) { + if (!args[1]) { + cons_bad_cmd_usage(command); + } else if (g_strcmp0(args[1], "none") == 0) { + prefs_clear_occupants_char(); + cons_show("Occupants char removed."); + + occupantswin_occupants_all(); + } else { + prefs_set_occupants_char(args[1][0]); + cons_show("Occupants char set to %c.", args[1][0]); + + occupantswin_occupants_all(); + } + return TRUE; + } + if (g_strcmp0(args[0], "default") == 0) { if (g_strcmp0(args[1], "show") == 0) { if (g_strcmp0(args[2], "jid") == 0) { @@ -4335,6 +4452,28 @@ cmd_occupants(ProfWin *window, const char *const command, gchar **args) } } + // header settings + if (g_strcmp0(args[0], "header") == 0) { + if (g_strcmp0(args[1], "char") == 0) { + if (!args[2]) { + cons_bad_cmd_usage(command); + } else if (g_strcmp0(args[2], "none") == 0) { + prefs_clear_occupants_header_char(); + cons_show("Occupants header char removed."); + + occupantswin_occupants_all(); + } else { + prefs_set_occupants_header_char(args[2][0]); + cons_show("Occupants header char set to %c.", args[2][0]); + + occupantswin_occupants_all(); + } + } else { + cons_bad_cmd_usage(command); + } + return TRUE; + } + jabber_conn_status_t conn_status = connection_get_status(); if (conn_status != JABBER_CONNECTED) { cons_show("You are not currently connected."); @@ -5228,6 +5367,44 @@ cmd_time(ProfWin *window, const char *const command, gchar **args) cons_bad_cmd_usage(command); return TRUE; } + } else if (g_strcmp0(args[0], "all") == 0) { + if (args[1] == NULL) { + cons_time_setting(); + return TRUE; + } else if (g_strcmp0(args[1], "set") == 0 && args[2] != NULL) { + prefs_set_string(PREF_TIME_CONSOLE, args[2]); + cons_show("Console time format set to '%s'.", args[2]); + prefs_set_string(PREF_TIME_CHAT, args[2]); + cons_show("Chat time format set to '%s'.", args[2]); + prefs_set_string(PREF_TIME_MUC, args[2]); + cons_show("MUC 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]); + prefs_set_string(PREF_TIME_PRIVATE, args[2]); + cons_show("Private chat time format set to '%s'.", args[2]); + prefs_set_string(PREF_TIME_XMLCONSOLE, args[2]); + cons_show("XML Console 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_CONSOLE, "off"); + cons_show("Console time display disabled."); + prefs_set_string(PREF_TIME_CHAT, "off"); + cons_show("Chat time display disabled."); + prefs_set_string(PREF_TIME_MUC, "off"); + cons_show("MUC time display disabled."); + prefs_set_string(PREF_TIME_CONFIG, "off"); + cons_show("config time display disabled."); + prefs_set_string(PREF_TIME_PRIVATE, "off"); + cons_show("config time display disabled."); + prefs_set_string(PREF_TIME_XMLCONSOLE, "off"); + cons_show("XML Console time display disabled."); + ui_redraw(); + return TRUE; + } else { + cons_bad_cmd_usage(command); + return TRUE; + } } else { cons_bad_cmd_usage(command); return TRUE; @@ -5237,6 +5414,10 @@ cmd_time(ProfWin *window, const char *const command, gchar **args) gboolean cmd_states(ProfWin *window, const char *const command, gchar **args) { + if (args[0] == NULL) { + return FALSE; + } + _cmd_set_boolean_preference(args[0], command, "Sending chat states", PREF_STATES); // if disabled, disable outtype and gone @@ -5270,6 +5451,10 @@ cmd_wintitle(ProfWin *window, const char *const command, gchar **args) gboolean cmd_outtype(ProfWin *window, const char *const command, gchar **args) { + if (args[0] == NULL) { + return FALSE; + } + _cmd_set_boolean_preference(args[0], command, "Sending typing notifications", PREF_OUTTYPE); // if enabled, enable states @@ -6424,17 +6609,29 @@ cmd_autoconnect(ProfWin *window, const char *const command, gchar **args) prefs_set_string(PREF_CONNECT_ACCOUNT, NULL); cons_show("Autoconnect account disabled."); } else if (strcmp(args[0], "set") == 0) { - prefs_set_string(PREF_CONNECT_ACCOUNT, args[1]); - cons_show("Autoconnect account set to: %s.", args[1]); + if (args[1] == NULL || strlen(args[1]) == 0) { + cons_bad_cmd_usage(command); + } else { + if (accounts_account_exists(args[1])) { + prefs_set_string(PREF_CONNECT_ACCOUNT, args[1]); + cons_show("Autoconnect account set to: %s.", args[1]); + } else { + cons_show_error("Account '%s' does not exist.", args[1]); + } + } } else { cons_bad_cmd_usage(command); } - return true; + return TRUE; } gboolean cmd_chlog(ProfWin *window, const char *const command, gchar **args) { + if (args[0] == NULL) { + return FALSE; + } + _cmd_set_boolean_preference(args[0], command, "Chat logging", PREF_CHLOG); // if set to off, disable history @@ -6456,6 +6653,10 @@ cmd_grlog(ProfWin *window, const char *const command, gchar **args) gboolean cmd_history(ProfWin *window, const char *const command, gchar **args) { + if (args[0] == NULL) { + return FALSE; + } + _cmd_set_boolean_preference(args[0], command, "Chat history", PREF_HISTORY); // if set to on, set chlog @@ -6469,6 +6670,10 @@ cmd_history(ProfWin *window, const char *const command, gchar **args) gboolean cmd_carbons(ProfWin *window, const char *const command, gchar **args) { + if (args[0] == NULL) { + return FALSE; + } + _cmd_set_boolean_preference(args[0], command, "Message carbons preference", PREF_CARBONS); jabber_conn_status_t conn_status = connection_get_status(); @@ -6579,11 +6784,13 @@ cmd_plugins_sourcepath(ProfWin *window, const char *const command, gchar **args) if (!is_dir(path)) { cons_show("Plugins sourcepath must be a directory."); + free(path); return TRUE; } cons_show("Setting plugins sourcepath: %s", path); prefs_set_string(PREF_PLUGINS_SOURCEPATH, path); + free(path); return TRUE; } @@ -6661,6 +6868,8 @@ cmd_plugins_install(ProfWin *window, const char *const command, gchar **args) } else { cons_show("Argument must be a file or directory."); } + + free(path); return TRUE; } @@ -6765,12 +6974,14 @@ cmd_plugins_load(ProfWin *window, const char *const command, gchar **args) return TRUE; } - gboolean res = plugins_load(args[1]); + GString* error_message = g_string_new(NULL); + gboolean res = plugins_load(args[1], error_message); if (res) { cons_show("Loaded plugin: %s", args[1]); } else { - cons_show("Failed to load plugin: %s", args[1]); + cons_show("Failed to load plugin: %s. %s", args[1], error_message->str); } + g_string_free(error_message, TRUE); return TRUE; } @@ -6807,12 +7018,14 @@ cmd_plugins_reload(ProfWin *window, const char *const command, gchar **args) return TRUE; } - gboolean res = plugins_reload(args[1]); + GString* error_message = g_string_new(NULL); + gboolean res = plugins_reload(args[1], error_message); if (res) { cons_show("Reloaded plugin: %s", args[1]); } else { - cons_show("Failed to reload plugin: %s", args[1]); + cons_show("Failed to reload plugin: %s, %s", args[1], error_message); } + g_string_free(error_message, TRUE); return TRUE; } @@ -7295,6 +7508,11 @@ cmd_otr_start(ProfWin *window, const char *const command, gchar **args) return TRUE; } + if (chatwin->is_omemo) { + win_println(window, THEME_DEFAULT, '!', "You must disable OMEMO before starting an OTR session."); + return TRUE; + } + if (chatwin->is_otr) { win_println(window, THEME_DEFAULT, '!', "You are already in an OTR session."); return TRUE; @@ -7624,6 +7842,11 @@ cmd_command_exec(ProfWin *window, const char *const command, gchar **args) return TRUE; } + if (args[1] == NULL) { + cons_bad_cmd_usage(command); + return TRUE; + } + char *jid = args[2]; if (jid == NULL) { switch (window->type) { @@ -7863,3 +8086,470 @@ _cmd_set_boolean_preference(gchar *arg, const char *const command, g_string_free(enabled, TRUE); g_string_free(disabled, TRUE); } + +gboolean +cmd_omemo_gen(ProfWin *window, const char *const command, gchar **args) +{ +#ifdef HAVE_OMEMO + if (connection_get_status() != JABBER_CONNECTED) { + cons_show("You must be connected with an account to initialize OMEMO."); + return TRUE; + } + + if (omemo_loaded()) { + cons_show("OMEMO crytographic materials have already been generated."); + return TRUE; + } + + cons_show("Generating OMEMO crytographic materials, it may take a while..."); + ui_update(); + ProfAccount *account = accounts_get_account(session_get_account_name()); + omemo_generate_crypto_materials(account); + cons_show("OMEMO crytographic materials generated."); + return TRUE; +#else + cons_show("This version of Profanity has not been built with OMEMO support enabled"); + return TRUE; +#endif +} + +gboolean +cmd_omemo_start(ProfWin *window, const char *const command, gchar **args) +{ +#ifdef HAVE_OMEMO + if (connection_get_status() != JABBER_CONNECTED) { + cons_show("You must be connected with an account to load OMEMO information."); + return TRUE; + } + + if (!omemo_loaded()) { + win_println(window, THEME_DEFAULT, '!', "You have not generated or loaded a cryptographic materials, use '/omemo gen'"); + return TRUE; + } + + ProfChatWin *chatwin = NULL; + + // recipient supplied + if (args[1]) { + char *contact = args[1]; + char *barejid = roster_barejid_from_name(contact); + if (barejid == NULL) { + barejid = contact; + } + + chatwin = wins_get_chat(barejid); + if (!chatwin) { + chatwin = chatwin_new(barejid); + } + ui_focus_win((ProfWin*)chatwin); + } else { + if (window->type == WIN_CHAT) { + chatwin = (ProfChatWin*)window; + assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); + } + } + + if (chatwin) { + if (chatwin->pgp_send) { + win_println((ProfWin*)chatwin, THEME_DEFAULT, '!', "You must disable PGP encryption before starting an OMEMO session."); + return TRUE; + } + + if (chatwin->is_otr) { + win_println((ProfWin*)chatwin, THEME_DEFAULT, '!', "You must disable OTR encryption before starting an OMEMO session."); + return TRUE; + } + + if (chatwin->is_omemo) { + win_println((ProfWin*)chatwin, THEME_DEFAULT, '!', "You are already in an OMEMO session."); + return TRUE; + } + + accounts_add_omemo_state(session_get_account_name(), chatwin->barejid, TRUE); + omemo_start_session(chatwin->barejid); + chatwin->is_omemo = TRUE; + } else if (window->type == WIN_MUC) { + ProfMucWin *mucwin = (ProfMucWin*)window; + assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); + + if (muc_anonymity_type(mucwin->roomjid) == MUC_ANONYMITY_TYPE_NONANONYMOUS) { + accounts_add_omemo_state(session_get_account_name(), mucwin->roomjid, TRUE); + omemo_start_muc_sessions(mucwin->roomjid); + mucwin->is_omemo = TRUE; + } else { + win_println(window, THEME_DEFAULT, '!', "MUC must be non-anonymous (i.e. be configured to present real jid to anyone) in order to support OMEMO."); + } + } else { + win_println(window, THEME_DEFAULT, '-', "You must be in a regular chat window to start an OMEMO session."); + } + + return TRUE; +#else + cons_show("This version of Profanity has not been built with OMEMO support enabled"); + return TRUE; +#endif +} + +gboolean +cmd_omemo_char(ProfWin *window, const char *const command, gchar **args) +{ +#ifdef HAVE_OMEMO + if (args[1] == NULL) { + cons_bad_cmd_usage(command); + } else if (strlen(args[1]) != 1) { + cons_bad_cmd_usage(command); + } else { + prefs_set_omemo_char(args[1][0]); + cons_show("OMEMO char set to %c.", args[1][0]); + } + return TRUE; +#else + cons_show("This version of Profanity has not been built with OMEMO support enabled"); + return TRUE; +#endif +} + +gboolean +cmd_omemo_log(ProfWin *window, const char *const command, gchar **args) +{ +#ifdef HAVE_OMEMO + char *choice = args[1]; + if (g_strcmp0(choice, "on") == 0) { + prefs_set_string(PREF_OMEMO_LOG, "on"); + cons_show("OMEMO messages will be logged as plaintext."); + if (!prefs_get_boolean(PREF_CHLOG)) { + cons_show("Chat logging is currently disabled, use '/chlog on' to enable."); + } + } else if (g_strcmp0(choice, "off") == 0) { + prefs_set_string(PREF_OMEMO_LOG, "off"); + cons_show("OMEMO message logging disabled."); + } else if (g_strcmp0(choice, "redact") == 0) { + prefs_set_string(PREF_OMEMO_LOG, "redact"); + cons_show("OMEMO messages will be logged as '[redacted]'."); + if (!prefs_get_boolean(PREF_CHLOG)) { + cons_show("Chat logging is currently disabled, use '/chlog on' to enable."); + } + } else { + cons_bad_cmd_usage(command); + } + return TRUE; +#else + cons_show("This version of Profanity has not been built with OMEMO support enabled"); + return TRUE; +#endif +} + +gboolean +cmd_omemo_end(ProfWin *window, const char *const command, gchar **args) +{ +#ifdef HAVE_OMEMO + if (connection_get_status() != JABBER_CONNECTED) { + cons_show("You must be connected with an account to load OMEMO information."); + return TRUE; + } + + if (window->type == WIN_CHAT) { + ProfChatWin *chatwin = (ProfChatWin*)window; + assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); + + if (!chatwin->is_omemo) { + win_println(window, THEME_DEFAULT, '!', "You are not currently in an OMEMO session."); + return TRUE; + } + + chatwin->is_omemo = FALSE; + accounts_add_omemo_state(session_get_account_name(), chatwin->barejid, FALSE); + } else if (window->type == WIN_MUC) { + ProfMucWin *mucwin = (ProfMucWin*)window; + assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); + + if (!mucwin->is_omemo) { + win_println(window, THEME_DEFAULT, '!', "You are not currently in an OMEMO session."); + return TRUE; + } + + mucwin->is_omemo = FALSE; + accounts_add_omemo_state(session_get_account_name(), mucwin->roomjid, FALSE); + } else { + win_println(window, THEME_DEFAULT, '-', "You must be in a regular chat window to start an OMEMO session."); + return TRUE; + } + + return TRUE; +#else + cons_show("This version of Profanity has not been built with OMEMO support enabled"); + return TRUE; +#endif +} + +gboolean +cmd_omemo_fingerprint(ProfWin *window, const char *const command, gchar **args) +{ +#ifdef HAVE_OMEMO + if (connection_get_status() != JABBER_CONNECTED) { + cons_show("You must be connected with an account to load OMEMO information."); + return TRUE; + } + + if (!omemo_loaded()) { + win_println(window, THEME_DEFAULT, '!', "You have not generated or loaded a cryptographic materials, use '/omemo gen'"); + return TRUE; + } + + Jid *jid; + if (!args[1]) { + if (window->type == WIN_CONSOLE) { + char *fingerprint = omemo_own_fingerprint(TRUE); + cons_show("Your OMEMO fingerprint: %s", fingerprint); + free(fingerprint); + jid = jid_create(connection_get_fulljid()); + } else if (window->type == WIN_CHAT) { + ProfChatWin *chatwin = (ProfChatWin*)window; + jid = jid_create(chatwin->barejid); + } else { + win_println(window, THEME_DEFAULT, '-', "You must be in a regular chat window to print fingerprint without providing the contact."); + return TRUE; + } + } else { + char *barejid = roster_barejid_from_name(args[1]); + if (barejid) { + jid = jid_create(barejid); + } else { + jid = jid_create(args[1]); + if (!jid) { + cons_show("%s is not a valid jid", args[1]); + return TRUE; + } + } + } + + GList *fingerprints = omemo_known_device_identities(jid->barejid); + GList *fingerprint; + + if (!fingerprints) { + win_println(window, THEME_DEFAULT, '-', "There is no known fingerprints for %s", jid->barejid); + return TRUE; + } + + for (fingerprint = fingerprints; fingerprint != NULL; fingerprint = fingerprint->next) { + char *formatted_fingerprint = omemo_format_fingerprint(fingerprint->data); + gboolean trusted = omemo_is_trusted_identity(jid->barejid, fingerprint->data); + + win_println(window, THEME_DEFAULT, '-', "%s's OMEMO fingerprint: %s%s", jid->barejid, formatted_fingerprint, trusted ? " (trusted)" : ""); + + free(formatted_fingerprint); + } + + g_list_free(fingerprints); + + win_println(window, THEME_DEFAULT, '-', "You can trust it with '/omemo trust <fingerprint>'"); + win_println(window, THEME_DEFAULT, '-', "You can untrust it with '/omemo untrust <fingerprint>'"); + + return TRUE; +#else + cons_show("This version of Profanity has not been built with OMEMO support enabled"); + return TRUE; +#endif +} + +gboolean +cmd_omemo_trust(ProfWin *window, const char *const command, gchar **args) +{ +#ifdef HAVE_OMEMO + if (connection_get_status() != JABBER_CONNECTED) { + cons_show("You must be connected with an account to load OMEMO information."); + return TRUE; + } + + if (!args[1]) { + cons_bad_cmd_usage(command); + return TRUE; + } + + if (!omemo_loaded()) { + win_println(window, THEME_DEFAULT, '!', "You have not generated or loaded a cryptographic materials, use '/omemo gen'"); + return TRUE; + } + + char *fingerprint; + char *barejid; + + /* Contact not provided */ + if (!args[2]) { + fingerprint = args[1]; + + if (window->type != WIN_CHAT) { + win_println(window, THEME_DEFAULT, '-', "You must be in a regular chat window to trust a device without providing the contact."); + return TRUE; + } + + ProfChatWin *chatwin = (ProfChatWin*)window; + assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); + barejid = chatwin->barejid; + } else { + fingerprint = args[2]; + char *contact = args[1]; + barejid = roster_barejid_from_name(contact); + if (barejid == NULL) { + barejid = contact; + } + } + + omemo_trust(barejid, fingerprint); + + char *unformatted_fingerprint = malloc(strlen(fingerprint)); + int i; + int j; + for (i = 0, j = 0; fingerprint[i] != '\0'; i++) { + if (!g_ascii_isxdigit(fingerprint[i])) { + continue; + } + unformatted_fingerprint[j++] = fingerprint[i]; + } + + unformatted_fingerprint[j] = '\0'; + gboolean trusted = omemo_is_trusted_identity(barejid, unformatted_fingerprint); + + win_println(window, THEME_DEFAULT, '-', "%s's OMEMO fingerprint: %s%s", barejid, fingerprint, trusted ? " (trusted)" : ""); + + free(unformatted_fingerprint); + + return TRUE; +#else + cons_show("This version of Profanity has not been built with OMEMO support enabled"); + return TRUE; +#endif +} + +gboolean +cmd_omemo_untrust(ProfWin *window, const char *const command, gchar **args) +{ +#ifdef HAVE_OMEMO + if (connection_get_status() != JABBER_CONNECTED) { + cons_show("You must be connected with an account to load OMEMO information."); + return TRUE; + } + + if (!args[1]) { + cons_bad_cmd_usage(command); + return TRUE; + } + + if (!omemo_loaded()) { + win_println(window, THEME_DEFAULT, '!', "You have not generated or loaded a cryptographic materials, use '/omemo gen'"); + return TRUE; + } + + char *fingerprint; + char *barejid; + + /* Contact not provided */ + if (!args[2]) { + fingerprint = args[1]; + + if (window->type != WIN_CHAT) { + win_println(window, THEME_DEFAULT, '-', "You must be in a regular chat window to trust a device without providing the contact."); + return TRUE; + } + + ProfChatWin *chatwin = (ProfChatWin*)window; + assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); + barejid = chatwin->barejid; + } else { + fingerprint = args[2]; + char *contact = args[1]; + barejid = roster_barejid_from_name(contact); + if (barejid == NULL) { + barejid = contact; + } + } + + omemo_untrust(barejid, fingerprint); + + char *unformatted_fingerprint = malloc(strlen(fingerprint)); + int i; + int j; + for (i = 0, j = 0; fingerprint[i] != '\0'; i++) { + if (!g_ascii_isxdigit(fingerprint[i])) { + continue; + } + unformatted_fingerprint[j++] = fingerprint[i]; + } + + unformatted_fingerprint[j] = '\0'; + gboolean trusted = omemo_is_trusted_identity(barejid, unformatted_fingerprint); + + win_println(window, THEME_DEFAULT, '-', "%s's OMEMO fingerprint: %s%s", barejid, fingerprint, trusted ? " (trusted)" : ""); + + free(unformatted_fingerprint); + + return TRUE; +#else + cons_show("This version of Profanity has not been built with OMEMO support enabled"); + return TRUE; +#endif +} + +gboolean +cmd_omemo_clear_device_list(ProfWin *window, const char *const command, gchar **args) +{ +#ifdef HAVE_OMEMO + if (connection_get_status() != JABBER_CONNECTED) { + cons_show("You must be connected with an account to initialize OMEMO."); + return TRUE; + } + + omemo_devicelist_publish(NULL); + cons_show("Cleared OMEMO device list"); + return TRUE; +#else + cons_show("This version of Profanity has not been built with OMEMO support enabled"); + return TRUE; +#endif +} + +gboolean +cmd_omemo_policy(ProfWin *window, const char *const command, gchar **args) +{ +#ifdef HAVE_OMEMO + if (args[1] == NULL) { + char *policy = prefs_get_string(PREF_OMEMO_POLICY); + cons_show("OMEMO policy is now set to: %s", policy); + prefs_free_string(policy); + return TRUE; + } + + char *choice = args[1]; + if ((g_strcmp0(choice, "manual") != 0) && + (g_strcmp0(choice, "automatic") != 0) && + (g_strcmp0(choice, "always") != 0)) { + cons_show("OMEMO policy can be set to: manual, automatic or always."); + return TRUE; + } + + prefs_set_string(PREF_OMEMO_POLICY, choice); + cons_show("OMEMO policy is now set to: %s", choice); + return TRUE; +#else + cons_show("This version of Profanity has not been built with OMEMO support enabled"); + return TRUE; +#endif +} + +gboolean +cmd_save(ProfWin *window, const char *const command, gchar **args) +{ + log_info("Saving preferences to configuration file"); + cons_show("Saving preferences."); + prefs_save(); + return TRUE; +} + +gboolean +cmd_reload(ProfWin *window, const char *const command, gchar **args) +{ + log_info("Reloading preferences"); + cons_show("Reloading preferences."); + prefs_reload(); + return TRUE; +} diff --git a/src/command/cmd_funcs.h b/src/command/cmd_funcs.h index 89166ba1..9102e1e1 100644 --- a/src/command/cmd_funcs.h +++ b/src/command/cmd_funcs.h @@ -2,6 +2,7 @@ * cmd_funcs.h * * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> + * Copyright (C) 2019 Michael Vetter <jubalh@iodoru.org> * * This file is part of Profanity. * @@ -214,4 +215,17 @@ gboolean cmd_wins_swap(ProfWin *window, const char *const command, gchar **args) gboolean cmd_form_field(ProfWin *window, char *tag, gchar **args); +gboolean cmd_omemo_gen(ProfWin *window, const char *const command, gchar **args); +gboolean cmd_omemo_char(ProfWin *window, const char *const command, gchar **args); +gboolean cmd_omemo_log(ProfWin *window, const char *const command, gchar **args); +gboolean cmd_omemo_start(ProfWin *window, const char *const command, gchar **args); +gboolean cmd_omemo_end(ProfWin *window, const char *const command, gchar **args); +gboolean cmd_omemo_fingerprint(ProfWin *window, const char *const command, gchar **args); +gboolean cmd_omemo_trust(ProfWin *window, const char *const command, gchar **args); +gboolean cmd_omemo_untrust(ProfWin *window, const char *const command, gchar **args); +gboolean cmd_omemo_policy(ProfWin *window, const char *const command, gchar **args); +gboolean cmd_omemo_clear_device_list(ProfWin *window, const char *const command, gchar **args); + +gboolean cmd_save(ProfWin *window, const char *const command, gchar **args); +gboolean cmd_reload(ProfWin *window, const char *const command, gchar **args); #endif |