From af6f468cb738ec77dc2cac82d5c91b5847279346 Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Fri, 31 Mar 2023 12:30:12 +0200 Subject: [PATCH 1/4] fix memory leak `found` was leaked before This was somehow missed in e9aaba938b4f1b62b5f9018583a82ed7e7180977 Signed-off-by: Steffen Jaeckel --- src/tools/autocomplete.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/tools/autocomplete.c b/src/tools/autocomplete.c index 227b79e0..27532081 100644 --- a/src/tools/autocomplete.c +++ b/src/tools/autocomplete.c @@ -314,11 +314,8 @@ autocomplete_complete(Autocomplete ac, const gchar* search_str, gboolean quote, static char* _autocomplete_param_common(const char* const input, char* command, autocomplete_func func, Autocomplete ac, gboolean quote, gboolean previous, void* context) { - char* command_cpy; - char* result = NULL; int len; - - command_cpy = g_strdup_printf("%s ", command); + auto_char char* command_cpy = g_strdup_printf("%s ", command); if (!command_cpy) { return NULL; } @@ -327,8 +324,11 @@ _autocomplete_param_common(const char* const input, char* command, autocomplete_ if (strncmp(input, command_cpy, len) == 0) { int inp_len = strlen(input); - char prefix[inp_len]; - char* found; + auto_char char* found = NULL; + auto_char char* prefix = malloc(inp_len + 1); + if (!prefix) { + return NULL; + } for (int i = len; i < inp_len; i++) { prefix[i - len] = input[i]; @@ -343,12 +343,11 @@ _autocomplete_param_common(const char* const input, char* command, autocomplete_ } if (found) { - result = g_strdup_printf("%s%s", command_cpy, found); + return g_strdup_printf("%s%s", command_cpy, found); } } - free(command_cpy); - return result; + return NULL; } char* From 0242576d7c00e529f8fefc2c30d7415b13595c95 Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Fri, 31 Mar 2023 12:31:19 +0200 Subject: [PATCH 2/4] only create hashtable once Before this change the same hashtable was re-created each time one used the auto-completion feature. Signed-off-by: Steffen Jaeckel --- src/command/cmd_ac.c | 146 ++++++++++++++++++++++--------------------- 1 file changed, 74 insertions(+), 72 deletions(-) diff --git a/src/command/cmd_ac.c b/src/command/cmd_ac.c index 8654a07b..c986be5e 100644 --- a/src/command/cmd_ac.c +++ b/src/command/cmd_ac.c @@ -294,6 +294,8 @@ static Autocomplete vcard_togglable_param_ac; static Autocomplete vcard_toggle_ac; static Autocomplete vcard_address_type_ac; +static GHashTable* ac_funcs = NULL; + /*! * \brief Initialization of auto completion for commands. * @@ -1297,6 +1299,78 @@ cmd_ac_init(void) vcard_address_type_ac = autocomplete_new(); autocomplete_add(vcard_address_type_ac, "domestic"); autocomplete_add(vcard_address_type_ac, "international"); + + if (ac_funcs != NULL) + g_hash_table_destroy(ac_funcs); + ac_funcs = g_hash_table_new(g_str_hash, g_str_equal); + g_hash_table_insert(ac_funcs, "/account", _account_autocomplete); + g_hash_table_insert(ac_funcs, "/affiliation", _affiliation_autocomplete); + g_hash_table_insert(ac_funcs, "/alias", _alias_autocomplete); + g_hash_table_insert(ac_funcs, "/autoaway", _autoaway_autocomplete); + g_hash_table_insert(ac_funcs, "/autoconnect", _autoconnect_autocomplete); + g_hash_table_insert(ac_funcs, "/avatar", _avatar_autocomplete); + g_hash_table_insert(ac_funcs, "/ban", _ban_autocomplete); + g_hash_table_insert(ac_funcs, "/blocked", _blocked_autocomplete); + g_hash_table_insert(ac_funcs, "/bookmark", _bookmark_autocomplete); + g_hash_table_insert(ac_funcs, "/clear", _clear_autocomplete); + g_hash_table_insert(ac_funcs, "/close", _close_autocomplete); + g_hash_table_insert(ac_funcs, "/cmd", _adhoc_cmd_autocomplete); + g_hash_table_insert(ac_funcs, "/color", _color_autocomplete); + g_hash_table_insert(ac_funcs, "/connect", _connect_autocomplete); + g_hash_table_insert(ac_funcs, "/console", _console_autocomplete); + g_hash_table_insert(ac_funcs, "/correct", _correct_autocomplete); + g_hash_table_insert(ac_funcs, "/correction", _correction_autocomplete); + g_hash_table_insert(ac_funcs, "/executable", _executable_autocomplete); + g_hash_table_insert(ac_funcs, "/form", _form_autocomplete); + g_hash_table_insert(ac_funcs, "/help", _help_autocomplete); + g_hash_table_insert(ac_funcs, "/inpblock", _inpblock_autocomplete); + g_hash_table_insert(ac_funcs, "/intype", _intype_autocomplete); + g_hash_table_insert(ac_funcs, "/invite", _invite_autocomplete); + g_hash_table_insert(ac_funcs, "/join", _join_autocomplete); + g_hash_table_insert(ac_funcs, "/kick", _kick_autocomplete); + g_hash_table_insert(ac_funcs, "/lastactivity", _lastactivity_autocomplete); + g_hash_table_insert(ac_funcs, "/log", _log_autocomplete); + g_hash_table_insert(ac_funcs, "/logging", _logging_autocomplete); + g_hash_table_insert(ac_funcs, "/mood", _mood_autocomplete); + g_hash_table_insert(ac_funcs, "/notify", _notify_autocomplete); + g_hash_table_insert(ac_funcs, "/occupants", _occupants_autocomplete); +#ifdef HAVE_OMEMO + g_hash_table_insert(ac_funcs, "/omemo", _omemo_autocomplete); +#endif +#ifdef HAVE_LIBOTR + g_hash_table_insert(ac_funcs, "/otr", _otr_autocomplete); +#endif +#ifdef HAVE_LIBGPGME + g_hash_table_insert(ac_funcs, "/ox", _ox_autocomplete); + g_hash_table_insert(ac_funcs, "/pgp", _pgp_autocomplete); +#endif + g_hash_table_insert(ac_funcs, "/plugins", _plugins_autocomplete); + g_hash_table_insert(ac_funcs, "/presence", _presence_autocomplete); + g_hash_table_insert(ac_funcs, "/receipts", _receipts_autocomplete); + g_hash_table_insert(ac_funcs, "/reconnect", _reconnect_autocomplete); + g_hash_table_insert(ac_funcs, "/resource", _resource_autocomplete); + g_hash_table_insert(ac_funcs, "/role", _role_autocomplete); + g_hash_table_insert(ac_funcs, "/rooms", _rooms_autocomplete); + g_hash_table_insert(ac_funcs, "/roster", _roster_autocomplete); + g_hash_table_insert(ac_funcs, "/script", _script_autocomplete); + g_hash_table_insert(ac_funcs, "/sendfile", _sendfile_autocomplete); + g_hash_table_insert(ac_funcs, "/software", _software_autocomplete); + g_hash_table_insert(ac_funcs, "/status", _status_autocomplete); + g_hash_table_insert(ac_funcs, "/statusbar", _statusbar_autocomplete); + g_hash_table_insert(ac_funcs, "/strophe", _strophe_autocomplete); + g_hash_table_insert(ac_funcs, "/sub", _sub_autocomplete); + g_hash_table_insert(ac_funcs, "/subject", _subject_autocomplete); + g_hash_table_insert(ac_funcs, "/theme", _theme_autocomplete); + g_hash_table_insert(ac_funcs, "/time", _time_autocomplete); + g_hash_table_insert(ac_funcs, "/titlebar", _titlebar_autocomplete); + g_hash_table_insert(ac_funcs, "/tls", _tls_autocomplete); + g_hash_table_insert(ac_funcs, "/tray", _tray_autocomplete); + g_hash_table_insert(ac_funcs, "/url", _url_autocomplete); + g_hash_table_insert(ac_funcs, "/vcard", _vcard_autocomplete); + g_hash_table_insert(ac_funcs, "/who", _who_autocomplete); + g_hash_table_insert(ac_funcs, "/win", _win_autocomplete); + g_hash_table_insert(ac_funcs, "/wins", _wins_autocomplete); + g_hash_table_insert(ac_funcs, "/wintitle", _wintitle_autocomplete); } void @@ -2019,76 +2093,6 @@ _cmd_ac_complete_params(ProfWin* window, const char* const input, gboolean previ } } - GHashTable* ac_funcs = g_hash_table_new(g_str_hash, g_str_equal); - g_hash_table_insert(ac_funcs, "/help", _help_autocomplete); - g_hash_table_insert(ac_funcs, "/who", _who_autocomplete); - g_hash_table_insert(ac_funcs, "/sub", _sub_autocomplete); - g_hash_table_insert(ac_funcs, "/notify", _notify_autocomplete); - g_hash_table_insert(ac_funcs, "/autoaway", _autoaway_autocomplete); - g_hash_table_insert(ac_funcs, "/theme", _theme_autocomplete); - g_hash_table_insert(ac_funcs, "/log", _log_autocomplete); - g_hash_table_insert(ac_funcs, "/account", _account_autocomplete); - g_hash_table_insert(ac_funcs, "/roster", _roster_autocomplete); - g_hash_table_insert(ac_funcs, "/bookmark", _bookmark_autocomplete); - g_hash_table_insert(ac_funcs, "/autoconnect", _autoconnect_autocomplete); -#ifdef HAVE_LIBOTR - g_hash_table_insert(ac_funcs, "/otr", _otr_autocomplete); -#endif -#ifdef HAVE_LIBGPGME - g_hash_table_insert(ac_funcs, "/pgp", _pgp_autocomplete); - g_hash_table_insert(ac_funcs, "/ox", _ox_autocomplete); -#endif -#ifdef HAVE_OMEMO - g_hash_table_insert(ac_funcs, "/omemo", _omemo_autocomplete); -#endif - 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); - g_hash_table_insert(ac_funcs, "/form", _form_autocomplete); - g_hash_table_insert(ac_funcs, "/occupants", _occupants_autocomplete); - g_hash_table_insert(ac_funcs, "/kick", _kick_autocomplete); - g_hash_table_insert(ac_funcs, "/ban", _ban_autocomplete); - g_hash_table_insert(ac_funcs, "/affiliation", _affiliation_autocomplete); - g_hash_table_insert(ac_funcs, "/role", _role_autocomplete); - g_hash_table_insert(ac_funcs, "/resource", _resource_autocomplete); - g_hash_table_insert(ac_funcs, "/wintitle", _wintitle_autocomplete); - g_hash_table_insert(ac_funcs, "/inpblock", _inpblock_autocomplete); - g_hash_table_insert(ac_funcs, "/time", _time_autocomplete); - g_hash_table_insert(ac_funcs, "/receipts", _receipts_autocomplete); - g_hash_table_insert(ac_funcs, "/reconnect", _reconnect_autocomplete); - g_hash_table_insert(ac_funcs, "/wins", _wins_autocomplete); - g_hash_table_insert(ac_funcs, "/tls", _tls_autocomplete); - g_hash_table_insert(ac_funcs, "/titlebar", _titlebar_autocomplete); - g_hash_table_insert(ac_funcs, "/script", _script_autocomplete); - g_hash_table_insert(ac_funcs, "/subject", _subject_autocomplete); - g_hash_table_insert(ac_funcs, "/console", _console_autocomplete); - g_hash_table_insert(ac_funcs, "/win", _win_autocomplete); - g_hash_table_insert(ac_funcs, "/close", _close_autocomplete); - g_hash_table_insert(ac_funcs, "/plugins", _plugins_autocomplete); - g_hash_table_insert(ac_funcs, "/sendfile", _sendfile_autocomplete); - g_hash_table_insert(ac_funcs, "/blocked", _blocked_autocomplete); - g_hash_table_insert(ac_funcs, "/tray", _tray_autocomplete); - g_hash_table_insert(ac_funcs, "/presence", _presence_autocomplete); - g_hash_table_insert(ac_funcs, "/rooms", _rooms_autocomplete); - g_hash_table_insert(ac_funcs, "/statusbar", _statusbar_autocomplete); - g_hash_table_insert(ac_funcs, "/clear", _clear_autocomplete); - g_hash_table_insert(ac_funcs, "/invite", _invite_autocomplete); - g_hash_table_insert(ac_funcs, "/status", _status_autocomplete); - g_hash_table_insert(ac_funcs, "/logging", _logging_autocomplete); - g_hash_table_insert(ac_funcs, "/color", _color_autocomplete); - g_hash_table_insert(ac_funcs, "/avatar", _avatar_autocomplete); - g_hash_table_insert(ac_funcs, "/correction", _correction_autocomplete); - g_hash_table_insert(ac_funcs, "/correct", _correct_autocomplete); - g_hash_table_insert(ac_funcs, "/software", _software_autocomplete); - g_hash_table_insert(ac_funcs, "/url", _url_autocomplete); - g_hash_table_insert(ac_funcs, "/executable", _executable_autocomplete); - g_hash_table_insert(ac_funcs, "/lastactivity", _lastactivity_autocomplete); - g_hash_table_insert(ac_funcs, "/intype", _intype_autocomplete); - g_hash_table_insert(ac_funcs, "/mood", _mood_autocomplete); - g_hash_table_insert(ac_funcs, "/strophe", _strophe_autocomplete); - g_hash_table_insert(ac_funcs, "/cmd", _adhoc_cmd_autocomplete); - g_hash_table_insert(ac_funcs, "/vcard", _vcard_autocomplete); - int len = strlen(input); char parsed[len + 1]; int i = 0; @@ -2106,11 +2110,9 @@ _cmd_ac_complete_params(ProfWin* window, const char* const input, gboolean previ if (ac_func) { result = ac_func(window, input, previous); if (result) { - g_hash_table_destroy(ac_funcs); return result; } } - g_hash_table_destroy(ac_funcs); result = plugins_autocomplete(input, previous); if (result) { From 74415ae71d287d097a7adadea34cb8662735b530 Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Sun, 2 Apr 2023 14:39:54 +0200 Subject: [PATCH 3/4] refactor into array of a `struct` ...instead of having two separate arrays. Signed-off-by: Steffen Jaeckel --- src/command/cmd_ac.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/command/cmd_ac.c b/src/command/cmd_ac.c index c986be5e..0cc4a170 100644 --- a/src/command/cmd_ac.c +++ b/src/command/cmd_ac.c @@ -2083,11 +2083,21 @@ _cmd_ac_complete_params(ProfWin* window, const char* const input, gboolean previ } } - gchar* cmds[] = { "/prefs", "/disco", "/room", "/autoping", "/mainwin", "/inputwin" }; - Autocomplete completers[] = { prefs_ac, disco_ac, room_ac, autoping_ac, winpos_ac, winpos_ac }; + struct + { + gchar* cmd; + Autocomplete completer; + } ac_cmds[] = { + { "/prefs", prefs_ac }, + { "/disco", disco_ac }, + { "/room", room_ac }, + { "/autoping", autoping_ac }, + { "/mainwin", winpos_ac }, + { "/inputwin", winpos_ac }, + }; - for (int i = 0; i < ARRAY_SIZE(cmds); i++) { - result = autocomplete_param_with_ac(input, cmds[i], completers[i], TRUE, previous); + for (int i = 0; i < ARRAY_SIZE(ac_cmds); i++) { + result = autocomplete_param_with_ac(input, ac_cmds[i].cmd, ac_cmds[i].completer, TRUE, previous); if (result) { return result; } From 7271898541f217b24ce13010ca494c7b74d49ad6 Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Mon, 3 Apr 2023 15:54:33 +0200 Subject: [PATCH 4/4] fix display of a "list type" in a form if there's no value assigned yet It is possible, that a server sends a form with a field as follows, which has no (default) value assigned. ``` ``` This patch fixes profanity to show that list. Before this patch profanity showed nothing. I stumbled over this while running the `/room config` command inside a newly created muc on the `sure.im` XMPP server. Signed-off-by: Steffen Jaeckel --- src/ui/confwin.c | 48 +++++++++++++++++++++--------------------------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/src/ui/confwin.c b/src/ui/confwin.c index d74c6d86..85abe748 100644 --- a/src/ui/confwin.c +++ b/src/ui/confwin.c @@ -215,8 +215,8 @@ _confwin_form_field(ProfWin* window, char* tag, FormField* field) win_append(window, THEME_DEFAULT, ": "); } - GSList* values = field->values; - GSList* curr_value = values; + GSList* curr_value = field->values; + GSList* curr_option; switch (field->type_t) { case FIELD_HIDDEN: @@ -272,36 +272,30 @@ _confwin_form_field(ProfWin* window, char* tag, FormField* field) } break; case FIELD_LIST_SINGLE: - if (curr_value) { - win_newline(window); - char* value = curr_value->data; - GSList* options = field->options; - GSList* curr_option = options; - while (curr_option) { - FormOption* option = curr_option->data; - if (g_strcmp0(option->value, value) == 0) { - win_println(window, THEME_ONLINE, "-", " [%s] %s", option->value, option->label); - } else { - win_println(window, THEME_OFFLINE, "-", " [%s] %s", option->value, option->label); - } - curr_option = g_slist_next(curr_option); + win_newline(window); + char* value = curr_value ? curr_value->data : NULL; + curr_option = field->options; + while (curr_option) { + FormOption* option = curr_option->data; + if (g_strcmp0(option->value, value) == 0) { + win_println(window, THEME_ONLINE, "-", " [%s] %s", option->value, option->label); + } else { + win_println(window, THEME_OFFLINE, "-", " [%s] %s", option->value, option->label); } + curr_option = g_slist_next(curr_option); } break; case FIELD_LIST_MULTI: - if (curr_value) { - win_newline(window); - GSList* options = field->options; - GSList* curr_option = options; - while (curr_option) { - FormOption* option = curr_option->data; - if (g_slist_find_custom(curr_value, option->value, (GCompareFunc)g_strcmp0)) { - win_println(window, THEME_ONLINE, "-", " [%s] %s", option->value, option->label); - } else { - win_println(window, THEME_OFFLINE, "-", " [%s] %s", option->value, option->label); - } - curr_option = g_slist_next(curr_option); + win_newline(window); + curr_option = field->options; + while (curr_option) { + FormOption* option = curr_option->data; + if (g_slist_find_custom(curr_value, option->value, (GCompareFunc)g_strcmp0)) { + win_println(window, THEME_ONLINE, "-", " [%s] %s", option->value, option->label); + } else { + win_println(window, THEME_OFFLINE, "-", " [%s] %s", option->value, option->label); } + curr_option = g_slist_next(curr_option); } break; case FIELD_JID_SINGLE: