From b7dec705c324939712c9e6a7054a7d5a094911fa Mon Sep 17 00:00:00 2001 From: Jabber Developer Date: Sat, 11 Jul 2026 16:09:36 +0000 Subject: [PATCH] fix(autocomplete): guard history completion safely Prevent autocomplete crashes on asset failures when executing history subcommands without an active connection by validating the session state beforehand. Standardize JID resolution across command handlers to ensure consistent contact lookup behavior. Use auto_gchar gchar instead of GString for performance and readability purposes. --- src/command/cmd_ac.c | 98 ++++++++++++++++++++++---------------------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/src/command/cmd_ac.c b/src/command/cmd_ac.c index 6e91f057..abc5a295 100644 --- a/src/command/cmd_ac.c +++ b/src/command/cmd_ac.c @@ -1866,10 +1866,12 @@ _cmd_ac_complete_params(ProfWin* window, const char* const input, gboolean previ } gchar* history_jid_subcmds[] = { "/history verify", "/history export", "/history import" }; - for (size_t i = 0; i < ARRAY_SIZE(history_jid_subcmds); i++) { - result = autocomplete_param_with_func(input, history_jid_subcmds[i], roster_barejid_autocomplete, previous, NULL); - if (result) { - return result; + if (conn_status == JABBER_CONNECTED) { + for (size_t i = 0; i < ARRAY_SIZE(history_jid_subcmds); i++) { + result = autocomplete_param_with_func(input, history_jid_subcmds[i], roster_barejid_autocomplete, previous, NULL); + if (result) { + return result; + } } } @@ -2045,14 +2047,14 @@ _disco_autocomplete(ProfWin* window, const char* const input, gboolean previous) { char* result = NULL; result = autocomplete_param_with_ac(input, "/disco", disco_ac, TRUE, previous); - if (result) { - return result; - } + if (result) { + return result; + } result = _roster_jid_autocomplete(input, "/disco info", previous); - if (result) { - return result; - } + if (result) { + return result; + } result = _roster_jid_autocomplete(input, "/disco items", previous); return result; } @@ -3735,7 +3737,7 @@ _win_autocomplete(ProfWin* window, const char* const input, gboolean previous) } char* unquoted = strip_arg_quotes(input); - result = autocomplete_param_with_func(unquoted, "/win", roster_contact_autocomplete, previous, NULL); + result = _roster_jid_autocomplete(input, "/win", previous); free(unquoted); return result; } @@ -4070,13 +4072,13 @@ _invite_autocomplete(ProfWin* window, const char* const input, gboolean previous } result = _roster_jid_autocomplete(input, "/invite send", previous); - if (result) { - return result; - } + if (result) { + return result; + } - result = autocomplete_param_with_func(input, "/invite decline", muc_invites_find, previous, NULL); - if (result) { - return result; + result = autocomplete_param_with_func(input, "/invite decline", muc_invites_find, previous, NULL); + if (result) { + return result; } return NULL; @@ -4092,37 +4094,37 @@ _status_autocomplete(ProfWin* window, const char* const input, gboolean previous return result; } - // complete with: online, away etc. - result = autocomplete_param_with_ac(input, "/status set", account_status_ac, TRUE, previous); - if (result) { - return result; - } + // complete with: online, away etc. + result = autocomplete_param_with_ac(input, "/status set", account_status_ac, TRUE, previous); + if (result) { + return result; + } - // Remove quote character before and after names when doing autocomplete - char* unquoted = strip_arg_quotes(input); + // Remove quote character before and after names when doing autocomplete + char* unquoted = strip_arg_quotes(input); - // MUC completion with nicknames - if (window->type == WIN_MUC) { - ProfMucWin* mucwin = (ProfMucWin*)window; - assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); - Autocomplete nick_ac = muc_roster_ac(mucwin->roomjid); - if (nick_ac) { - result = autocomplete_param_with_ac(unquoted, "/status get", nick_ac, TRUE, previous); - if (result) { - free(unquoted); - return result; - } - } - // roster completion - } else { - result = _roster_jid_autocomplete(input, "/status get", previous); + // MUC completion with nicknames + if (window->type == WIN_MUC) { + ProfMucWin* mucwin = (ProfMucWin*)window; + assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); + Autocomplete nick_ac = muc_roster_ac(mucwin->roomjid); + if (nick_ac) { + result = autocomplete_param_with_ac(unquoted, "/status get", nick_ac, TRUE, previous); if (result) { free(unquoted); return result; } } + // roster completion + } else { + result = _roster_jid_autocomplete(input, "/status get", previous); + if (result) { + free(unquoted); + return result; + } + } - free(unquoted); + free(unquoted); return NULL; } @@ -4230,14 +4232,12 @@ _software_autocomplete(ProfWin* window, const char* const input, gboolean previo { char* result = NULL; - if (window->type == WIN_CHAT) { + if (window->type == WIN_CHAT && _is_connected()) { ProfChatWin* chatwin = (ProfChatWin*)window; assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); - GString* search_str = g_string_new("/software "); - g_string_append(search_str, chatwin->barejid); - result = autocomplete_param_with_func(search_str->str, "/software", roster_fulljid_autocomplete, previous, NULL); - g_string_free(search_str, TRUE); + auto_gchar gchar* search_str = g_strdup_printf("/software %s", chatwin->barejid); + result = autocomplete_param_with_func(search_str, "/software", roster_fulljid_autocomplete, previous, NULL); } else if (window->type == WIN_MUC) { ProfMucWin* mucwin = (ProfMucWin*)window; assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); @@ -4350,10 +4350,10 @@ _lastactivity_autocomplete(ProfWin* window, const char* const input, gboolean pr return result; } - result = autocomplete_param_with_func(input, "/lastactivity set", prefs_autocomplete_boolean_choice, previous, NULL); - if (result) { - return result; - } + result = autocomplete_param_with_func(input, "/lastactivity set", prefs_autocomplete_boolean_choice, previous, NULL); + if (result) { + return result; + } result = _roster_jid_autocomplete(input, "/lastactivity get", previous); return result;