Files
cproof/src/command/cmd_ac.c
Jabber Developer 02e679c277
All checks were successful
CI Code / Check spelling (push) Successful in 16s
CI Code / Check coding style (push) Successful in 30s
CI Code / Linux (debian) (push) Successful in 5m25s
CI Code / Linux (ubuntu) (push) Successful in 5m33s
CI Code / Code Coverage (push) Successful in 7m54s
CI Code / Linux (arch) (push) Successful in 12m7s
feat(autoping): autoping availability warning
## Introduced change

A new warning that notifies users when the connected XMPP server
advertises XEP-0199 (urn:xmpp:ping) support but the autoping feature
is disabled in settings. The warning can be toggled with
`/autoping warning on|off`.

The warning fires during the on-connect disco#info exchange, only for
responses from the server's own domain — responses from user JIDs or
subdomain services (e.g., conference servers) are excluded.

### Capabilities

- **On-connect detection**: Warning is emitted automatically when the
  server's disco#info response indicates `urn:xmpp:ping` support while
  autoping is disabled and the preference is enabled (default: on)
- **`/autoping warning on|off`**: Toggle the warning via the existing
  autoping command
- **Domain-scoped**: Only triggers for disco#info from the bound server
  domain; user JIDs and subdomain service JIDs are skipped
- **Case-insensitive domain matching**: Uses `g_ascii_strcasecmp` instead
  of `g_strcmp0` to handle case differences between the stanza `from`
  field and the bound domain
- **Display in settings**: Shown in both `/notify` and `/autoping`
  settings dumps, with consistent alignment and `(/autoping warning)`
  reference in each line
- **Autocomplete**: Dedicated `_autoping_autocomplete` function handles
  the `warning` subcommand with `on|off` completion

## Reasoning behind the change

Users connecting to servers that support XEP-0199 ping but have autoping
disabled may experience poorer connection stability. The warning draws
attention to this configuration mismatch without requiring users to read
documentation or dig into settings.

The warning is scoped to the server domain (not user JIDs or subdomain
services) because autoping is a connection-level feature — it only makes
sense in the context of the server's keepalive capabilities.

The warning preference defaults to `on` so users are informed by default,
but can be disabled with `/autoping warning off` if they prefer not to
see it.

## Implementation details

### Warning logic (`src/xmpp/iq.c`)

`_disco_autoping_warning_message()` is called from the on-connect
disco#info handler when the `from` field matches the bound domain. It
checks three conditions:

1. Server features contain `urn:xmpp:ping`
2. Autoping interval is 0 (disabled)
3. `PREF_AUTOPING_WARNING` is true

All three must be true for the warning to display.

### Domain matching

`g_ascii_strcasecmp(from, connection_get_domain())` is used instead of
`g_strcmp0` to handle case differences. This prevents the warning from
silently skipping if a server echoes the `from` field in a different
case than the bound domain.

### Command integration (`src/command/cmd_*.c`)

- `cmd_defs.c`: Added `/autoping warning on|off` syntax and argument
  description
- `cmd_funcs.c`: Added `warning` subcommand handler that calls
  `_cmd_set_boolean_preference` with `PREF_AUTOPING_WARNING`
- `cmd_ac.c`: Registered dedicated `_autoping_autocomplete` that handles
  the `warning` subcommand with `on|off` boolean completion

### Preference storage (`src/config/preferences.c`)

- Group: `PREF_GROUP_NOTIFICATIONS`
- Key: `autoping.warning`
- Default: `TRUE`

### Settings display (`src/ui/console.c`)

The autoping warning preference is shown in both `cons_notify_setting()`
and `cons_autoping_setting()` with consistent column alignment and a
`(/autoping warning)` reference in each line.

### Tests (`tests/functionaltests/test_autoping.c`)

Six functional tests cover all condition combinations:

| Test | Server ping | Autoping | Warning pref | Expected |
|---|---|---|---|---|
| `autoping_warning_shown_when_disabled` | yes | off | on | warning shown |
| `autoping_warning_not_shown_when_server_unsupported` | no | off | on | no warning |
| `autoping_warning_not_shown_when_autoping_enabled` | yes | on | on | no warning |
| `autoping_warning_not_shown_when_user_disabled` | yes | off | off | no warning |
| `autoping_warning_not_shown_for_user_jid` | yes (from user JID) | off | on | no warning |
| `autoping_warning_not_shown_for_subdomain_service` | yes (from subdomain) | off | on | no warning |

Co-authored-by: Jabber Developer2 <jabber.developer2@jabber.space>
2026-06-23 11:11:25 +00:00

4689 lines
159 KiB
C

/*
* cmd_ac.c
* vim: expandtab:ts=4:sts=4:sw=4
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
* Copyright (C) 2019 - 2026 Michael Vetter <jubalh@iodoru.org>
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <libgen.h>
#include <dirent.h>
#include <ctype.h>
#include "common.h"
#include "config/preferences.h"
#include "config/scripts.h"
#include "command/cmd_ac.h"
#include "command/cmd_funcs.h"
#include "tools/parser.h"
#include "plugins/plugins.h"
#include "ui/ui.h"
#include "ui/win_types.h"
#include "ui/window_list.h"
#include "xmpp/muc.h"
#include "xmpp/xmpp.h"
#include "xmpp/roster_list.h"
#include "ui/buffer.h"
#ifdef HAVE_LIBGPGME
#include "pgp/gpg.h"
#endif
#ifdef HAVE_OMEMO
#include "omemo/omemo.h"
#endif
#include "ai/ai_client.h"
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);
static char* _spellcheck_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _autoaway_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _autoping_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _autoconnect_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _account_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _who_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _roster_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _bookmark_autocomplete(ProfWin* window, const char* const input, gboolean previous);
#ifdef HAVE_LIBOTR
static char* _otr_autocomplete(ProfWin* window, const char* const input, gboolean previous);
#endif
#ifdef HAVE_LIBGPGME
static char* _pgp_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _ox_autocomplete(ProfWin* window, const char* const input, gboolean previous);
#endif
#ifdef HAVE_OMEMO
static char* _omemo_autocomplete(ProfWin* window, const char* const input, gboolean previous);
#endif
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);
static char* _log_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _form_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _form_field_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _occupants_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _kick_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _ban_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _affiliation_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _role_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _resource_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _wintitle_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _inpblock_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _time_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _receipts_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _reconnect_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _help_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _wins_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _tls_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _titlebar_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _script_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _subject_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _console_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _win_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _close_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _plugins_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _sendfile_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _blocked_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _tray_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _presence_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _rooms_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _statusbar_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _clear_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _invite_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _status_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _logging_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _privacy_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _color_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _avatar_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _correction_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static gchar* _correct_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _software_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _url_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _executable_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _lastactivity_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _intype_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _mood_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _strophe_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _stamp_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _adhoc_cmd_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _vcard_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _force_encryption_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _ai_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _script_autocomplete_func(const char* const prefix, gboolean previous, void* context);
static char* _cmd_ac_complete_params(ProfWin* window, const char* const input, gboolean previous);
static Autocomplete commands_ac;
static Autocomplete who_room_ac;
static Autocomplete who_roster_ac;
static Autocomplete help_ac;
static Autocomplete help_commands_ac;
static Autocomplete notify_ac;
static Autocomplete notify_chat_ac;
static Autocomplete notify_room_ac;
static Autocomplete notify_typing_ac;
static Autocomplete notify_mention_ac;
static Autocomplete notify_trigger_ac;
static Autocomplete prefs_ac;
static Autocomplete sub_ac;
static Autocomplete log_ac;
static Autocomplete log_level_ac;
static Autocomplete autoaway_ac;
static Autocomplete autoaway_mode_ac;
static Autocomplete autoaway_presence_ac;
static Autocomplete autoconnect_ac;
static Autocomplete wintitle_ac;
static Autocomplete theme_ac;
static Autocomplete theme_load_ac;
static Autocomplete spellcheck_ac;
static Autocomplete account_ac;
static Autocomplete account_set_ac;
static Autocomplete account_clear_ac;
static Autocomplete account_default_ac;
static Autocomplete account_status_ac;
static Autocomplete disco_ac;
static Autocomplete wins_ac;
static Autocomplete roster_ac;
static Autocomplete roster_show_ac;
static Autocomplete roster_by_ac;
static Autocomplete roster_count_ac;
static Autocomplete roster_order_ac;
static Autocomplete roster_header_ac;
static Autocomplete roster_contact_ac;
static Autocomplete roster_resource_ac;
static Autocomplete roster_presence_ac;
static Autocomplete roster_char_ac;
static Autocomplete roster_remove_all_ac;
static Autocomplete roster_room_ac;
static Autocomplete roster_room_title_ac;
static Autocomplete roster_room_position_ac;
static Autocomplete roster_room_by_ac;
static Autocomplete roster_room_order_ac;
static Autocomplete roster_unread_ac;
static Autocomplete roster_private_ac;
static Autocomplete group_ac;
static Autocomplete bookmark_ac;
static Autocomplete bookmark_property_ac;
static Autocomplete bookmark_ignore_ac;
#ifdef HAVE_LIBOTR
static Autocomplete otr_ac;
static Autocomplete otr_log_ac;
static Autocomplete otr_policy_ac;
#endif
#ifdef HAVE_OMEMO
static Autocomplete omemo_ac;
static Autocomplete omemo_log_ac;
static Autocomplete omemo_policy_ac;
static Autocomplete omemo_trustmode_ac;
#endif
static Autocomplete connect_property_ac;
static Autocomplete tls_property_ac;
static Autocomplete auth_property_ac;
static Autocomplete alias_ac;
static Autocomplete aliases_ac;
static Autocomplete join_property_ac;
static Autocomplete room_ac;
static Autocomplete rooms_all_ac;
static Autocomplete rooms_list_ac;
static Autocomplete rooms_cache_ac;
static Autocomplete affiliation_ac;
static Autocomplete role_ac;
static Autocomplete affiliation_cmd_ac;
static Autocomplete role_cmd_ac;
static Autocomplete subject_ac;
static Autocomplete form_ac;
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;
static Autocomplete inpblock_ac;
static Autocomplete receipts_ac;
static Autocomplete reconnect_ac;
#ifdef HAVE_LIBGPGME
static Autocomplete pgp_ac;
static Autocomplete pgp_log_ac;
static Autocomplete ox_ac;
static Autocomplete ox_log_ac;
#endif
static Autocomplete tls_ac;
static Autocomplete titlebar_ac;
static Autocomplete titlebar_room_ac;
static Autocomplete titlebar_room_title_ac;
static Autocomplete titlebar_show_ac;
static Autocomplete tls_certpath_ac;
static Autocomplete script_ac;
static Autocomplete script_show_ac;
static Autocomplete console_ac;
static Autocomplete console_msg_ac;
static Autocomplete autoping_ac;
static Autocomplete plugins_ac;
static Autocomplete plugins_load_ac;
static Autocomplete plugins_unload_ac;
static Autocomplete plugins_reload_ac;
static Autocomplete filepath_ac;
static Autocomplete blocked_ac;
static Autocomplete tray_ac;
static Autocomplete presence_ac;
static Autocomplete presence_setting_ac;
static Autocomplete winpos_ac;
static Autocomplete statusbar_ac;
static Autocomplete statusbar_self_ac;
static Autocomplete statusbar_chat_ac;
static Autocomplete statusbar_room_ac;
static Autocomplete statusbar_room_title_ac;
static Autocomplete statusbar_show_ac;
static Autocomplete statusbar_tabmode_ac;
static Autocomplete clear_ac;
static Autocomplete invite_ac;
static Autocomplete status_ac;
static Autocomplete status_state_ac;
static Autocomplete logging_ac;
static Autocomplete logging_group_ac;
static Autocomplete privacy_ac;
static Autocomplete privacy_log_ac;
static Autocomplete history_ac;
static Autocomplete history_switch_ac;
static Autocomplete color_ac;
static Autocomplete correction_ac;
static Autocomplete avatar_ac;
static Autocomplete ai_subcommands_ac;
static Autocomplete ai_set_subcommands_ac;
static Autocomplete ai_set_custom_subcommands_ac;
static Autocomplete ai_remove_subcommands_ac;
static Autocomplete url_ac;
static Autocomplete executable_ac;
static Autocomplete executable_param_ac;
static Autocomplete intype_ac;
static Autocomplete mood_ac;
static Autocomplete ai_models_ac;
static Autocomplete mood_type_ac;
static Autocomplete strophe_ac;
static Autocomplete strophe_sm_ac;
static Autocomplete strophe_verbosity_ac;
static Autocomplete stamp_ac;
static Autocomplete stamp_unset_ac;
static Autocomplete adhoc_cmd_ac;
static Autocomplete lastactivity_ac;
static Autocomplete vcard_ac;
static Autocomplete vcard_photo_ac;
static Autocomplete vcard_element_ac;
static Autocomplete vcard_set_ac;
static Autocomplete vcard_name_ac;
static Autocomplete vcard_set_param_ac;
static Autocomplete vcard_togglable_param_ac;
static Autocomplete vcard_address_type_ac;
static Autocomplete force_encryption_ac;
static Autocomplete force_encryption_policy_ac;
static char* last_filepath_input = NULL;
static Autocomplete* all_acs[] = {
&commands_ac,
&who_room_ac,
&who_roster_ac,
&help_ac,
&help_commands_ac,
&notify_ac,
&notify_chat_ac,
&notify_room_ac,
&notify_typing_ac,
&notify_mention_ac,
&notify_trigger_ac,
&prefs_ac,
&sub_ac,
&log_ac,
&log_level_ac,
&autoaway_ac,
&autoaway_mode_ac,
&autoaway_presence_ac,
&autoconnect_ac,
&wintitle_ac,
&theme_ac,
&spellcheck_ac,
&account_ac,
&account_set_ac,
&account_clear_ac,
&account_default_ac,
&account_status_ac,
&disco_ac,
&wins_ac,
&roster_ac,
&roster_show_ac,
&roster_by_ac,
&roster_count_ac,
&roster_order_ac,
&roster_header_ac,
&roster_contact_ac,
&roster_resource_ac,
&roster_presence_ac,
&roster_char_ac,
&roster_remove_all_ac,
&roster_room_ac,
&roster_room_title_ac,
&roster_room_position_ac,
&roster_room_by_ac,
&roster_room_order_ac,
&roster_unread_ac,
&roster_private_ac,
&group_ac,
&bookmark_ac,
&bookmark_property_ac,
&bookmark_ignore_ac,
#ifdef HAVE_LIBOTR
&otr_ac,
&otr_log_ac,
&otr_policy_ac,
#endif
#ifdef HAVE_OMEMO
&omemo_ac,
&omemo_log_ac,
&omemo_policy_ac,
&omemo_trustmode_ac,
#endif
&connect_property_ac,
&tls_property_ac,
&auth_property_ac,
&alias_ac,
&aliases_ac,
&join_property_ac,
&room_ac,
&rooms_all_ac,
&rooms_list_ac,
&rooms_cache_ac,
&affiliation_ac,
&role_ac,
&affiliation_cmd_ac,
&role_cmd_ac,
&subject_ac,
&form_ac,
&form_field_multi_ac,
&occupants_ac,
&occupants_default_ac,
&occupants_show_ac,
&occupants_header_ac,
&occupants_header_char_ac,
&occupants_char_ac,
&time_ac,
&time_format_ac,
&resource_ac,
&inpblock_ac,
&receipts_ac,
&reconnect_ac,
#ifdef HAVE_LIBGPGME
&pgp_ac,
&pgp_log_ac,
&ox_ac,
&ox_log_ac,
#endif
&tls_ac,
&titlebar_ac,
&titlebar_room_ac,
&titlebar_room_title_ac,
&titlebar_show_ac,
&tls_certpath_ac,
&script_ac,
&console_ac,
&console_msg_ac,
&autoping_ac,
&plugins_ac,
&filepath_ac,
&blocked_ac,
&tray_ac,
&presence_ac,
&presence_setting_ac,
&winpos_ac,
&statusbar_ac,
&statusbar_self_ac,
&statusbar_chat_ac,
&statusbar_room_ac,
&statusbar_room_title_ac,
&statusbar_show_ac,
&statusbar_tabmode_ac,
&clear_ac,
&invite_ac,
&status_ac,
&status_state_ac,
&logging_ac,
&logging_group_ac,
&privacy_ac,
&privacy_log_ac,
&history_ac,
&history_switch_ac,
&color_ac,
&correction_ac,
&avatar_ac,
&url_ac,
&executable_ac,
&executable_param_ac,
&intype_ac,
&mood_ac,
&mood_type_ac,
&strophe_ac,
&strophe_sm_ac,
&strophe_verbosity_ac,
&stamp_ac,
&stamp_unset_ac,
&adhoc_cmd_ac,
&lastactivity_ac,
&vcard_ac,
&vcard_photo_ac,
&vcard_element_ac,
&vcard_set_ac,
&vcard_name_ac,
&vcard_set_param_ac,
&vcard_togglable_param_ac,
&vcard_address_type_ac,
&force_encryption_ac,
&force_encryption_policy_ac,
&ai_subcommands_ac,
&ai_set_subcommands_ac,
&ai_set_custom_subcommands_ac,
&ai_remove_subcommands_ac,
&ai_models_ac
};
static GHashTable* ac_funcs = NULL;
/*!
* \brief Initialization of auto completion for commands.
*
* This function implements the auto completion for profanity's commands.
*
*/
void
cmd_ac_init(void)
{
size_t n;
for (n = 0; n < ARRAY_SIZE(all_acs); ++n) {
*(all_acs[n]) = autocomplete_new();
}
autocomplete_add(help_ac, "commands");
autocomplete_add(help_ac, "navigation");
autocomplete_add(help_ac, "search_all");
autocomplete_add(help_ac, "search_any");
autocomplete_add(help_commands_ac, "chat");
autocomplete_add(help_commands_ac, "groupchat");
autocomplete_add(help_commands_ac, "roster");
autocomplete_add(help_commands_ac, "presence");
autocomplete_add(help_commands_ac, "discovery");
autocomplete_add(help_commands_ac, "connection");
autocomplete_add(help_commands_ac, "ui");
autocomplete_add(help_commands_ac, "plugins");
autocomplete_add(prefs_ac, "ui");
autocomplete_add(prefs_ac, "desktop");
autocomplete_add(prefs_ac, "chat");
autocomplete_add(prefs_ac, "log");
autocomplete_add(prefs_ac, "conn");
autocomplete_add(prefs_ac, "presence");
#ifdef HAVE_LIBOTR
autocomplete_add(prefs_ac, "otr");
#endif
#ifdef HAVE_LIBGPGME
autocomplete_add(prefs_ac, "pgp");
autocomplete_add(prefs_ac, "ox");
#endif
#ifdef HAVE_OMEMO
autocomplete_add(prefs_ac, "omemo");
#endif
autocomplete_add(notify_ac, "chat");
autocomplete_add(notify_ac, "room");
autocomplete_add(notify_ac, "typing");
autocomplete_add(notify_ac, "remind");
autocomplete_add(notify_ac, "invite");
autocomplete_add(notify_ac, "sub");
autocomplete_add(notify_ac, "on");
autocomplete_add(notify_ac, "off");
autocomplete_add(notify_ac, "mention");
autocomplete_add(notify_ac, "trigger");
autocomplete_add(notify_ac, "reset");
autocomplete_add(notify_chat_ac, "on");
autocomplete_add(notify_chat_ac, "off");
autocomplete_add(notify_chat_ac, "current");
autocomplete_add(notify_chat_ac, "text");
autocomplete_add(notify_room_ac, "on");
autocomplete_add(notify_room_ac, "off");
autocomplete_add(notify_room_ac, "mention");
autocomplete_add(notify_room_ac, "offline");
autocomplete_add(notify_room_ac, "current");
autocomplete_add(notify_room_ac, "text");
autocomplete_add(notify_room_ac, "trigger");
autocomplete_add(notify_typing_ac, "on");
autocomplete_add(notify_typing_ac, "off");
autocomplete_add(notify_typing_ac, "current");
autocomplete_add(notify_mention_ac, "on");
autocomplete_add(notify_mention_ac, "off");
autocomplete_add(notify_mention_ac, "case_sensitive");
autocomplete_add(notify_mention_ac, "case_insensitive");
autocomplete_add(notify_mention_ac, "word_whole");
autocomplete_add(notify_mention_ac, "word_part");
autocomplete_add(notify_trigger_ac, "add");
autocomplete_add(notify_trigger_ac, "remove");
autocomplete_add(notify_trigger_ac, "list");
autocomplete_add(notify_trigger_ac, "on");
autocomplete_add(notify_trigger_ac, "off");
autocomplete_add(sub_ac, "request");
autocomplete_add(sub_ac, "allow");
autocomplete_add(sub_ac, "deny");
autocomplete_add(sub_ac, "show");
autocomplete_add(sub_ac, "sent");
autocomplete_add(sub_ac, "received");
autocomplete_add(wintitle_ac, "show");
autocomplete_add(wintitle_ac, "goodbye");
autocomplete_add(log_ac, "maxsize");
autocomplete_add(log_ac, "rotate");
autocomplete_add(log_ac, "shared");
autocomplete_add(log_ac, "where");
autocomplete_add(log_ac, "level");
autocomplete_add(log_level_ac, "WARN");
autocomplete_add(log_level_ac, "INFO");
autocomplete_add(log_level_ac, "DEBUG");
autocomplete_add(log_level_ac, "ERROR");
autocomplete_add(autoaway_ac, "mode");
autocomplete_add(autoaway_ac, "time");
autocomplete_add(autoaway_ac, "message");
autocomplete_add(autoaway_ac, "check");
autocomplete_add(autoaway_mode_ac, "away");
autocomplete_add(autoaway_mode_ac, "idle");
autocomplete_add(autoaway_mode_ac, "off");
autocomplete_add(autoaway_presence_ac, "away");
autocomplete_add(autoaway_presence_ac, "xa");
autocomplete_add(autoconnect_ac, "set");
autocomplete_add(autoconnect_ac, "off");
autocomplete_add(theme_ac, "load");
autocomplete_add(theme_ac, "full-load");
autocomplete_add(theme_ac, "list");
autocomplete_add(theme_ac, "colours");
autocomplete_add(theme_ac, "properties");
autocomplete_add(spellcheck_ac, "on");
autocomplete_add(spellcheck_ac, "off");
autocomplete_add(spellcheck_ac, "list");
autocomplete_add(spellcheck_ac, "lang");
autocomplete_add(disco_ac, "info");
autocomplete_add(disco_ac, "items");
autocomplete_add(account_ac, "list");
autocomplete_add(account_ac, "show");
autocomplete_add(account_ac, "add");
autocomplete_add(account_ac, "remove");
autocomplete_add(account_ac, "enable");
autocomplete_add(account_ac, "disable");
autocomplete_add(account_ac, "default");
autocomplete_add(account_ac, "rename");
autocomplete_add(account_ac, "set");
autocomplete_add(account_ac, "clear");
autocomplete_add(account_set_ac, "jid");
autocomplete_add(account_set_ac, "server");
autocomplete_add(account_set_ac, "port");
autocomplete_add(account_set_ac, "status");
autocomplete_add(account_set_ac, "online");
autocomplete_add(account_set_ac, "chat");
autocomplete_add(account_set_ac, "away");
autocomplete_add(account_set_ac, "xa");
autocomplete_add(account_set_ac, "dnd");
autocomplete_add(account_set_ac, "resource");
autocomplete_add(account_set_ac, "password");
autocomplete_add(account_set_ac, "eval_password");
autocomplete_add(account_set_ac, "muc");
autocomplete_add(account_set_ac, "nick");
autocomplete_add(account_set_ac, "otr");
autocomplete_add(account_set_ac, "pgpkeyid");
autocomplete_add(account_set_ac, "startscript");
autocomplete_add(account_set_ac, "clientid");
autocomplete_add(account_set_ac, "tls");
autocomplete_add(account_set_ac, "auth");
autocomplete_add(account_set_ac, "theme");
autocomplete_add(account_set_ac, "session_alarm");
autocomplete_add(account_clear_ac, "password");
autocomplete_add(account_clear_ac, "eval_password");
autocomplete_add(account_clear_ac, "server");
autocomplete_add(account_clear_ac, "port");
autocomplete_add(account_clear_ac, "otr");
autocomplete_add(account_clear_ac, "pgpkeyid");
autocomplete_add(account_clear_ac, "startscript");
autocomplete_add(account_clear_ac, "clientid");
autocomplete_add(account_clear_ac, "theme");
autocomplete_add(account_clear_ac, "muc");
autocomplete_add(account_clear_ac, "resource");
autocomplete_add(account_clear_ac, "session_alarm");
autocomplete_add(account_default_ac, "set");
autocomplete_add(account_default_ac, "off");
autocomplete_add(account_status_ac, "online");
autocomplete_add(account_status_ac, "chat");
autocomplete_add(account_status_ac, "away");
autocomplete_add(account_status_ac, "xa");
autocomplete_add(account_status_ac, "dnd");
autocomplete_add(account_status_ac, "last");
autocomplete_add(wins_ac, "unread");
autocomplete_add(wins_ac, "attention");
autocomplete_add(wins_ac, "prune");
autocomplete_add(wins_ac, "swap");
autocomplete_add(roster_ac, "add");
autocomplete_add(roster_ac, "online");
autocomplete_add(roster_ac, "nick");
autocomplete_add(roster_ac, "clearnick");
autocomplete_add(roster_ac, "remove");
autocomplete_add(roster_ac, "remove_all");
autocomplete_add(roster_ac, "show");
autocomplete_add(roster_ac, "hide");
autocomplete_add(roster_ac, "by");
autocomplete_add(roster_ac, "count");
autocomplete_add(roster_ac, "color");
autocomplete_add(roster_ac, "order");
autocomplete_add(roster_ac, "unread");
autocomplete_add(roster_ac, "room");
autocomplete_add(roster_ac, "size");
autocomplete_add(roster_ac, "wrap");
autocomplete_add(roster_ac, "header");
autocomplete_add(roster_ac, "contact");
autocomplete_add(roster_ac, "resource");
autocomplete_add(roster_ac, "presence");
autocomplete_add(roster_ac, "private");
autocomplete_add(roster_ac, "group");
autocomplete_add(roster_private_ac, "room");
autocomplete_add(roster_private_ac, "group");
autocomplete_add(roster_private_ac, "off");
autocomplete_add(roster_private_ac, "char");
autocomplete_add(roster_header_ac, "char");
autocomplete_add(roster_contact_ac, "char");
autocomplete_add(roster_contact_ac, "indent");
autocomplete_add(roster_resource_ac, "char");
autocomplete_add(roster_resource_ac, "indent");
autocomplete_add(roster_resource_ac, "join");
autocomplete_add(roster_presence_ac, "indent");
autocomplete_add(roster_char_ac, "none");
autocomplete_add(roster_show_ac, "offline");
autocomplete_add(roster_show_ac, "resource");
autocomplete_add(roster_show_ac, "presence");
autocomplete_add(roster_show_ac, "status");
autocomplete_add(roster_show_ac, "empty");
autocomplete_add(roster_show_ac, "priority");
autocomplete_add(roster_show_ac, "contacts");
autocomplete_add(roster_show_ac, "unsubscribed");
autocomplete_add(roster_show_ac, "rooms");
autocomplete_add(roster_by_ac, "group");
autocomplete_add(roster_by_ac, "presence");
autocomplete_add(roster_by_ac, "none");
autocomplete_add(roster_count_ac, "unread");
autocomplete_add(roster_count_ac, "items");
autocomplete_add(roster_count_ac, "off");
autocomplete_add(roster_count_ac, "zero");
autocomplete_add(roster_order_ac, "name");
autocomplete_add(roster_order_ac, "presence");
autocomplete_add(roster_unread_ac, "before");
autocomplete_add(roster_unread_ac, "after");
autocomplete_add(roster_unread_ac, "off");
autocomplete_add(roster_room_ac, "char");
autocomplete_add(roster_room_ac, "position");
autocomplete_add(roster_room_ac, "by");
autocomplete_add(roster_room_ac, "order");
autocomplete_add(roster_room_ac, "unread");
autocomplete_add(roster_room_ac, "private");
autocomplete_add(roster_room_ac, "title");
autocomplete_add(roster_room_by_ac, "service");
autocomplete_add(roster_room_by_ac, "none");
autocomplete_add(roster_room_title_ac, "bookmark");
autocomplete_add(roster_room_title_ac, "jid");
autocomplete_add(roster_room_title_ac, "localpart");
autocomplete_add(roster_room_title_ac, "name");
autocomplete_add(roster_room_order_ac, "name");
autocomplete_add(roster_room_order_ac, "unread");
autocomplete_add(roster_room_position_ac, "first");
autocomplete_add(roster_room_position_ac, "last");
autocomplete_add(roster_remove_all_ac, "contacts");
autocomplete_add(group_ac, "show");
autocomplete_add(group_ac, "add");
autocomplete_add(group_ac, "remove");
theme_load_ac = NULL;
plugins_load_ac = NULL;
plugins_unload_ac = NULL;
plugins_reload_ac = NULL;
autocomplete_add(who_roster_ac, "chat");
autocomplete_add(who_roster_ac, "online");
autocomplete_add(who_roster_ac, "away");
autocomplete_add(who_roster_ac, "xa");
autocomplete_add(who_roster_ac, "dnd");
autocomplete_add(who_roster_ac, "offline");
autocomplete_add(who_roster_ac, "available");
autocomplete_add(who_roster_ac, "unavailable");
autocomplete_add(who_roster_ac, "any");
autocomplete_add(who_room_ac, "chat");
autocomplete_add(who_room_ac, "online");
autocomplete_add(who_room_ac, "away");
autocomplete_add(who_room_ac, "xa");
autocomplete_add(who_room_ac, "dnd");
autocomplete_add(who_room_ac, "available");
autocomplete_add(who_room_ac, "unavailable");
autocomplete_add(who_room_ac, "moderator");
autocomplete_add(who_room_ac, "participant");
autocomplete_add(who_room_ac, "visitor");
autocomplete_add(who_room_ac, "owner");
autocomplete_add(who_room_ac, "admin");
autocomplete_add(who_room_ac, "member");
autocomplete_add(who_room_ac, "none");
autocomplete_add(bookmark_ac, "list");
autocomplete_add(bookmark_ac, "add");
autocomplete_add(bookmark_ac, "update");
autocomplete_add(bookmark_ac, "remove");
autocomplete_add(bookmark_ac, "join");
autocomplete_add(bookmark_ac, "invites");
autocomplete_add(bookmark_ac, "ignore");
autocomplete_add(bookmark_property_ac, "nick");
autocomplete_add(bookmark_property_ac, "password");
autocomplete_add(bookmark_property_ac, "autojoin");
autocomplete_add(bookmark_property_ac, "name");
autocomplete_add(bookmark_ignore_ac, "add");
autocomplete_add(bookmark_ignore_ac, "remove");
#ifdef HAVE_LIBOTR
autocomplete_add(otr_ac, "gen");
autocomplete_add(otr_ac, "start");
autocomplete_add(otr_ac, "end");
autocomplete_add(otr_ac, "myfp");
autocomplete_add(otr_ac, "theirfp");
autocomplete_add(otr_ac, "trust");
autocomplete_add(otr_ac, "untrust");
autocomplete_add(otr_ac, "secret");
autocomplete_add(otr_ac, "log");
autocomplete_add(otr_ac, "libver");
autocomplete_add(otr_ac, "policy");
autocomplete_add(otr_ac, "question");
autocomplete_add(otr_ac, "answer");
autocomplete_add(otr_ac, "char");
autocomplete_add(otr_ac, "sendfile");
autocomplete_add(otr_log_ac, "on");
autocomplete_add(otr_log_ac, "off");
autocomplete_add(otr_log_ac, "redact");
autocomplete_add(otr_policy_ac, "manual");
autocomplete_add(otr_policy_ac, "opportunistic");
autocomplete_add(otr_policy_ac, "always");
#endif
#ifdef HAVE_OMEMO
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");
autocomplete_add(omemo_ac, "trustmode");
autocomplete_add(omemo_ac, "char");
autocomplete_add(omemo_ac, "qrcode");
autocomplete_add(omemo_log_ac, "on");
autocomplete_add(omemo_log_ac, "off");
autocomplete_add(omemo_log_ac, "redact");
autocomplete_add(omemo_policy_ac, "manual");
autocomplete_add(omemo_policy_ac, "automatic");
autocomplete_add(omemo_policy_ac, "always");
// Autocomplete OMEMO trustmode
autocomplete_add(omemo_trustmode_ac, "manual");
autocomplete_add(omemo_trustmode_ac, "firstusage");
autocomplete_add(omemo_trustmode_ac, "blind");
#endif
autocomplete_add(connect_property_ac, "auth");
autocomplete_add(connect_property_ac, "server");
autocomplete_add(connect_property_ac, "port");
autocomplete_add(connect_property_ac, "tls");
autocomplete_add(tls_property_ac, "force");
autocomplete_add(tls_property_ac, "allow");
autocomplete_add(tls_property_ac, "trust");
autocomplete_add(tls_property_ac, "direct");
autocomplete_add(tls_property_ac, "disable");
autocomplete_add(tls_property_ac, "legacy");
autocomplete_add(auth_property_ac, "default");
autocomplete_add(auth_property_ac, "legacy");
autocomplete_add(join_property_ac, "nick");
autocomplete_add(join_property_ac, "password");
autocomplete_add(alias_ac, "add");
autocomplete_add(alias_ac, "remove");
autocomplete_add(alias_ac, "list");
autocomplete_add(room_ac, "accept");
autocomplete_add(room_ac, "destroy");
autocomplete_add(room_ac, "config");
autocomplete_add(rooms_all_ac, "service");
autocomplete_add(rooms_all_ac, "filter");
autocomplete_add(rooms_all_ac, "cache");
autocomplete_add(rooms_list_ac, "service");
autocomplete_add(rooms_list_ac, "filter");
autocomplete_add(rooms_cache_ac, "on");
autocomplete_add(rooms_cache_ac, "off");
autocomplete_add(rooms_cache_ac, "clear");
autocomplete_add(affiliation_ac, "owner");
autocomplete_add(affiliation_ac, "admin");
autocomplete_add(affiliation_ac, "member");
autocomplete_add(affiliation_ac, "none");
autocomplete_add(affiliation_ac, "outcast");
autocomplete_add(role_ac, "moderator");
autocomplete_add(role_ac, "participant");
autocomplete_add(role_ac, "visitor");
autocomplete_add(role_ac, "none");
autocomplete_add(affiliation_cmd_ac, "list");
autocomplete_add(affiliation_cmd_ac, "request");
autocomplete_add(affiliation_cmd_ac, "register");
autocomplete_add(affiliation_cmd_ac, "set");
autocomplete_add(role_cmd_ac, "list");
autocomplete_add(role_cmd_ac, "set");
autocomplete_add(subject_ac, "set");
autocomplete_add(subject_ac, "edit");
autocomplete_add(subject_ac, "editor");
autocomplete_add(subject_ac, "prepend");
autocomplete_add(subject_ac, "append");
autocomplete_add(subject_ac, "clear");
autocomplete_add(form_ac, "submit");
autocomplete_add(form_ac, "cancel");
autocomplete_add(form_ac, "show");
autocomplete_add(form_ac, "help");
autocomplete_add(form_field_multi_ac, "add");
autocomplete_add(form_field_multi_ac, "remove");
autocomplete_add(occupants_ac, "show");
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");
autocomplete_add(occupants_ac, "color");
autocomplete_add(occupants_default_ac, "show");
autocomplete_add(occupants_default_ac, "hide");
autocomplete_add(occupants_show_ac, "jid");
autocomplete_add(occupants_show_ac, "offline");
autocomplete_add(occupants_char_ac, "none");
autocomplete_add(occupants_header_ac, "char");
autocomplete_add(occupants_header_char_ac, "none");
autocomplete_add(time_ac, "console");
autocomplete_add(time_ac, "chat");
autocomplete_add(time_ac, "muc");
autocomplete_add(time_ac, "config");
autocomplete_add(time_ac, "private");
autocomplete_add(time_ac, "xml");
autocomplete_add(time_ac, "statusbar");
autocomplete_add(time_ac, "lastactivity");
autocomplete_add(time_ac, "all");
autocomplete_add(time_format_ac, "set");
autocomplete_add(time_format_ac, "off");
autocomplete_add(resource_ac, "set");
autocomplete_add(resource_ac, "off");
autocomplete_add(resource_ac, "title");
autocomplete_add(resource_ac, "message");
autocomplete_add(inpblock_ac, "timeout");
autocomplete_add(inpblock_ac, "dynamic");
autocomplete_add(receipts_ac, "send");
autocomplete_add(receipts_ac, "request");
autocomplete_add(reconnect_ac, "now");
#ifdef HAVE_LIBGPGME
autocomplete_add(pgp_ac, "keys");
autocomplete_add(pgp_ac, "contacts");
autocomplete_add(pgp_ac, "setkey");
autocomplete_add(pgp_ac, "libver");
autocomplete_add(pgp_ac, "start");
autocomplete_add(pgp_ac, "end");
autocomplete_add(pgp_ac, "log");
autocomplete_add(pgp_ac, "char");
autocomplete_add(pgp_ac, "sendfile");
autocomplete_add(pgp_ac, "sendpub");
autocomplete_add(pgp_ac, "autoimport");
autocomplete_add(pgp_log_ac, "on");
autocomplete_add(pgp_log_ac, "off");
autocomplete_add(pgp_log_ac, "redact");
autocomplete_add(ox_ac, "keys");
autocomplete_add(ox_ac, "contacts");
autocomplete_add(ox_ac, "start");
autocomplete_add(ox_ac, "end");
autocomplete_add(ox_ac, "log");
autocomplete_add(ox_ac, "char");
autocomplete_add(ox_ac, "announce");
autocomplete_add(ox_ac, "discover");
autocomplete_add(ox_ac, "request");
autocomplete_add(ox_log_ac, "on");
autocomplete_add(ox_log_ac, "off");
autocomplete_add(ox_log_ac, "redact");
#endif
autocomplete_add(tls_ac, "allow");
autocomplete_add(tls_ac, "always");
autocomplete_add(tls_ac, "deny");
autocomplete_add(tls_ac, "cert");
autocomplete_add(tls_ac, "trust");
autocomplete_add(tls_ac, "trusted");
autocomplete_add(tls_ac, "revoke");
autocomplete_add(tls_ac, "certpath");
autocomplete_add(titlebar_ac, "up");
autocomplete_add(titlebar_ac, "down");
autocomplete_add(titlebar_ac, "show");
autocomplete_add(titlebar_ac, "hide");
autocomplete_add(titlebar_ac, "room");
autocomplete_add(titlebar_room_ac, "title");
autocomplete_add(titlebar_room_title_ac, "bookmark");
autocomplete_add(titlebar_room_title_ac, "jid");
autocomplete_add(titlebar_room_title_ac, "localpart");
autocomplete_add(titlebar_room_title_ac, "name");
autocomplete_add(titlebar_show_ac, "tls");
autocomplete_add(titlebar_show_ac, "encwarn");
autocomplete_add(titlebar_show_ac, "resource");
autocomplete_add(titlebar_show_ac, "presence");
autocomplete_add(tls_certpath_ac, "set");
autocomplete_add(tls_certpath_ac, "clear");
autocomplete_add(tls_certpath_ac, "default");
autocomplete_add(script_ac, "run");
autocomplete_add(script_ac, "list");
autocomplete_add(script_ac, "show");
script_show_ac = NULL;
autocomplete_add(console_ac, "chat");
autocomplete_add(console_ac, "muc");
autocomplete_add(console_ac, "private");
autocomplete_add(console_msg_ac, "all");
autocomplete_add(console_msg_ac, "first");
autocomplete_add(console_msg_ac, "mention");
autocomplete_add(console_msg_ac, "none");
autocomplete_add(autoping_ac, "set");
autocomplete_add(autoping_ac, "timeout");
autocomplete_add(autoping_ac, "warning");
autocomplete_add(plugins_ac, "install");
autocomplete_add(plugins_ac, "update");
autocomplete_add(plugins_ac, "uninstall");
autocomplete_add(plugins_ac, "load");
autocomplete_add(plugins_ac, "unload");
autocomplete_add(plugins_ac, "reload");
autocomplete_add(plugins_ac, "python_version");
autocomplete_add(blocked_ac, "add");
autocomplete_add(blocked_ac, "remove");
autocomplete_add(blocked_ac, "report-abuse");
autocomplete_add(blocked_ac, "report-spam");
autocomplete_add(clear_ac, "persist_history");
autocomplete_add(tray_ac, "on");
autocomplete_add(tray_ac, "off");
autocomplete_add(tray_ac, "read");
autocomplete_add(tray_ac, "timer");
autocomplete_add(presence_ac, "titlebar");
autocomplete_add(presence_ac, "console");
autocomplete_add(presence_ac, "chat");
autocomplete_add(presence_ac, "room");
autocomplete_add(presence_setting_ac, "all");
autocomplete_add(presence_setting_ac, "online");
autocomplete_add(presence_setting_ac, "none");
autocomplete_add(winpos_ac, "up");
autocomplete_add(winpos_ac, "down");
autocomplete_add(statusbar_ac, "up");
autocomplete_add(statusbar_ac, "down");
autocomplete_add(statusbar_ac, "show");
autocomplete_add(statusbar_ac, "hide");
autocomplete_add(statusbar_ac, "maxtabs");
autocomplete_add(statusbar_ac, "tablen");
autocomplete_add(statusbar_ac, "tabmode");
autocomplete_add(statusbar_ac, "self");
autocomplete_add(statusbar_ac, "chat");
autocomplete_add(statusbar_ac, "room");
autocomplete_add(invite_ac, "send");
autocomplete_add(invite_ac, "list");
autocomplete_add(invite_ac, "decline");
autocomplete_add(statusbar_self_ac, "user");
autocomplete_add(statusbar_self_ac, "barejid");
autocomplete_add(statusbar_self_ac, "fulljid");
autocomplete_add(statusbar_self_ac, "off");
autocomplete_add(statusbar_chat_ac, "user");
autocomplete_add(statusbar_chat_ac, "jid");
autocomplete_add(statusbar_room_ac, "title");
autocomplete_add(statusbar_room_title_ac, "bookmark");
autocomplete_add(statusbar_room_title_ac, "jid");
autocomplete_add(statusbar_room_title_ac, "localpart");
autocomplete_add(statusbar_room_title_ac, "name");
autocomplete_add(statusbar_show_ac, "name");
autocomplete_add(statusbar_show_ac, "number");
autocomplete_add(statusbar_show_ac, "read");
autocomplete_add(statusbar_show_ac, "dbbackend");
autocomplete_add(statusbar_tabmode_ac, "actlist");
autocomplete_add(statusbar_tabmode_ac, "dynamic");
autocomplete_add(statusbar_tabmode_ac, "default");
autocomplete_add(status_ac, "set");
autocomplete_add(status_ac, "get");
autocomplete_add(status_state_ac, "online");
autocomplete_add(status_state_ac, "chat");
autocomplete_add(status_state_ac, "away");
autocomplete_add(status_state_ac, "xa");
autocomplete_add(status_state_ac, "dnd");
autocomplete_add(privacy_ac, "logging");
autocomplete_add(privacy_ac, "os");
autocomplete_add(privacy_log_ac, "on");
autocomplete_add(privacy_log_ac, "off");
autocomplete_add(privacy_log_ac, "redact");
autocomplete_add(privacy_log_ac, "flatfile");
autocomplete_add(history_ac, "on");
autocomplete_add(history_ac, "off");
autocomplete_add(history_ac, "backend");
autocomplete_add(history_ac, "switch");
autocomplete_add(history_ac, "verify");
autocomplete_add(history_ac, "export");
autocomplete_add(history_ac, "import");
autocomplete_add(history_switch_ac, "sqlite");
autocomplete_add(history_switch_ac, "flatfile");
autocomplete_add(logging_group_ac, "on");
autocomplete_add(logging_group_ac, "off");
autocomplete_add(logging_group_ac, "color");
autocomplete_add(color_ac, "on");
autocomplete_add(color_ac, "off");
autocomplete_add(color_ac, "redgreen");
autocomplete_add(color_ac, "blue");
autocomplete_add(color_ac, "own");
autocomplete_add(correction_ac, "on");
autocomplete_add(correction_ac, "off");
autocomplete_add(correction_ac, "char");
autocomplete_add_unsorted(ai_subcommands_ac, "set", FALSE);
autocomplete_add_unsorted(ai_subcommands_ac, "remove", FALSE);
autocomplete_add_unsorted(ai_subcommands_ac, "start", FALSE);
autocomplete_add_unsorted(ai_subcommands_ac, "clear", FALSE);
autocomplete_add_unsorted(ai_subcommands_ac, "providers", FALSE);
autocomplete_add_unsorted(ai_subcommands_ac, "switch", FALSE);
autocomplete_add_unsorted(ai_subcommands_ac, "models", FALSE);
autocomplete_add_unsorted(ai_set_subcommands_ac, "provider", FALSE);
autocomplete_add_unsorted(ai_set_subcommands_ac, "token", FALSE);
autocomplete_add_unsorted(ai_set_subcommands_ac, "default-model", FALSE);
autocomplete_add_unsorted(ai_set_subcommands_ac, "custom", FALSE);
autocomplete_add_unsorted(ai_set_custom_subcommands_ac, "tools", FALSE);
autocomplete_add_unsorted(ai_set_custom_subcommands_ac, "search", FALSE);
autocomplete_add_unsorted(ai_set_custom_subcommands_ac, "memory", FALSE);
autocomplete_add_unsorted(ai_set_custom_subcommands_ac, "plugins", FALSE);
autocomplete_add_unsorted(ai_remove_subcommands_ac, "provider", FALSE);
autocomplete_add(avatar_ac, "set");
autocomplete_add(avatar_ac, "disable");
autocomplete_add(avatar_ac, "get");
autocomplete_add(avatar_ac, "open");
autocomplete_add(url_ac, "open");
autocomplete_add(url_ac, "save");
autocomplete_add(executable_ac, "avatar");
autocomplete_add(executable_ac, "urlopen");
autocomplete_add(executable_ac, "urlsave");
autocomplete_add(executable_ac, "editor");
autocomplete_add(executable_ac, "vcard_photo");
autocomplete_add(executable_param_ac, "set");
autocomplete_add(executable_param_ac, "default");
autocomplete_add(intype_ac, "console");
autocomplete_add(intype_ac, "titlebar");
autocomplete_add(strophe_ac, "sm");
autocomplete_add(strophe_ac, "verbosity");
autocomplete_add(strophe_sm_ac, "on");
autocomplete_add(strophe_sm_ac, "no-resend");
autocomplete_add(strophe_sm_ac, "off");
autocomplete_add(strophe_verbosity_ac, "0");
autocomplete_add(strophe_verbosity_ac, "1");
autocomplete_add(strophe_verbosity_ac, "2");
autocomplete_add(strophe_verbosity_ac, "3");
autocomplete_add(stamp_ac, "outgoing");
autocomplete_add(stamp_ac, "incoming");
autocomplete_add(stamp_ac, "unset");
autocomplete_add(stamp_unset_ac, "outgoing");
autocomplete_add(stamp_unset_ac, "incoming");
autocomplete_add(mood_ac, "set");
autocomplete_add(mood_ac, "clear");
autocomplete_add(mood_ac, "on");
autocomplete_add(mood_ac, "off");
autocomplete_add(mood_type_ac, "afraid");
autocomplete_add(mood_type_ac, "amazed");
autocomplete_add(mood_type_ac, "angry");
autocomplete_add(mood_type_ac, "amorous");
autocomplete_add(mood_type_ac, "annoyed");
autocomplete_add(mood_type_ac, "anxious");
autocomplete_add(mood_type_ac, "aroused");
autocomplete_add(mood_type_ac, "ashamed");
autocomplete_add(mood_type_ac, "bored");
autocomplete_add(mood_type_ac, "brave");
autocomplete_add(mood_type_ac, "calm");
autocomplete_add(mood_type_ac, "cautious");
autocomplete_add(mood_type_ac, "cold");
autocomplete_add(mood_type_ac, "confident");
autocomplete_add(mood_type_ac, "confused");
autocomplete_add(mood_type_ac, "contemplative");
autocomplete_add(mood_type_ac, "contented");
autocomplete_add(mood_type_ac, "cranky");
autocomplete_add(mood_type_ac, "crazy");
autocomplete_add(mood_type_ac, "creative");
autocomplete_add(mood_type_ac, "curious");
autocomplete_add(mood_type_ac, "dejected");
autocomplete_add(mood_type_ac, "depressed");
autocomplete_add(mood_type_ac, "disappointed");
autocomplete_add(mood_type_ac, "disgusted");
autocomplete_add(mood_type_ac, "dismayed");
autocomplete_add(mood_type_ac, "distracted");
autocomplete_add(mood_type_ac, "embarrassed");
autocomplete_add(mood_type_ac, "envious");
autocomplete_add(mood_type_ac, "excited");
autocomplete_add(mood_type_ac, "flirtatious");
autocomplete_add(mood_type_ac, "frustrated");
autocomplete_add(mood_type_ac, "grumpy");
autocomplete_add(mood_type_ac, "guilty");
autocomplete_add(mood_type_ac, "happy");
autocomplete_add(mood_type_ac, "hopeful");
autocomplete_add(mood_type_ac, "hot");
autocomplete_add(mood_type_ac, "humbled");
autocomplete_add(mood_type_ac, "humiliated");
autocomplete_add(mood_type_ac, "hungry");
autocomplete_add(mood_type_ac, "hurt");
autocomplete_add(mood_type_ac, "impressed");
autocomplete_add(mood_type_ac, "in_awe");
autocomplete_add(mood_type_ac, "in_love");
autocomplete_add(mood_type_ac, "indignant");
autocomplete_add(mood_type_ac, "interested");
autocomplete_add(mood_type_ac, "intoxicated");
autocomplete_add(mood_type_ac, "invincible");
autocomplete_add(mood_type_ac, "jealous");
autocomplete_add(mood_type_ac, "lonely");
autocomplete_add(mood_type_ac, "lucky");
autocomplete_add(mood_type_ac, "mean");
autocomplete_add(mood_type_ac, "moody");
autocomplete_add(mood_type_ac, "nervous");
autocomplete_add(mood_type_ac, "neutral");
autocomplete_add(mood_type_ac, "offended");
autocomplete_add(mood_type_ac, "outraged");
autocomplete_add(mood_type_ac, "playful");
autocomplete_add(mood_type_ac, "proud");
autocomplete_add(mood_type_ac, "relaxed");
autocomplete_add(mood_type_ac, "relieved");
autocomplete_add(mood_type_ac, "remorseful");
autocomplete_add(mood_type_ac, "restless");
autocomplete_add(mood_type_ac, "sad");
autocomplete_add(mood_type_ac, "sarcastic");
autocomplete_add(mood_type_ac, "serious");
autocomplete_add(mood_type_ac, "shocked");
autocomplete_add(mood_type_ac, "shy");
autocomplete_add(mood_type_ac, "sick");
autocomplete_add(mood_type_ac, "sleepy");
autocomplete_add(mood_type_ac, "spontaneous");
autocomplete_add(mood_type_ac, "stressed");
autocomplete_add(mood_type_ac, "strong");
autocomplete_add(mood_type_ac, "surprised");
autocomplete_add(mood_type_ac, "thankful");
autocomplete_add(mood_type_ac, "thirsty");
autocomplete_add(mood_type_ac, "tired");
autocomplete_add(mood_type_ac, "undefined");
autocomplete_add(mood_type_ac, "weak");
autocomplete_add(mood_type_ac, "worried");
autocomplete_add(adhoc_cmd_ac, "list");
autocomplete_add(adhoc_cmd_ac, "exec");
autocomplete_add(lastactivity_ac, "set");
autocomplete_add(lastactivity_ac, "get");
autocomplete_add(vcard_ac, "get");
autocomplete_add(vcard_ac, "photo");
autocomplete_add(vcard_ac, "set");
autocomplete_add(vcard_ac, "add");
autocomplete_add(vcard_ac, "remove");
autocomplete_add(vcard_ac, "save");
autocomplete_add(vcard_photo_ac, "open");
autocomplete_add(vcard_photo_ac, "save");
autocomplete_add(vcard_element_ac, "nickname");
autocomplete_add(vcard_element_ac, "birthday");
autocomplete_add(vcard_element_ac, "address");
autocomplete_add(vcard_element_ac, "tel");
autocomplete_add(vcard_element_ac, "email");
autocomplete_add(vcard_element_ac, "jid");
autocomplete_add(vcard_element_ac, "title");
autocomplete_add(vcard_element_ac, "role");
autocomplete_add(vcard_element_ac, "note");
autocomplete_add(vcard_element_ac, "url");
autocomplete_add(vcard_set_ac, "fullname");
autocomplete_add(vcard_set_ac, "name");
autocomplete_add(vcard_name_ac, "family");
autocomplete_add(vcard_name_ac, "given");
autocomplete_add(vcard_name_ac, "middle");
autocomplete_add(vcard_name_ac, "prefix");
autocomplete_add(vcard_name_ac, "suffix");
autocomplete_add(vcard_set_param_ac, "pobox");
autocomplete_add(vcard_set_param_ac, "extaddr");
autocomplete_add(vcard_set_param_ac, "street");
autocomplete_add(vcard_set_param_ac, "locality");
autocomplete_add(vcard_set_param_ac, "region");
autocomplete_add(vcard_set_param_ac, "pocode");
autocomplete_add(vcard_set_param_ac, "country");
autocomplete_add(vcard_set_param_ac, "type");
autocomplete_add(vcard_set_param_ac, "home");
autocomplete_add(vcard_set_param_ac, "work");
autocomplete_add(vcard_set_param_ac, "voice");
autocomplete_add(vcard_set_param_ac, "fax");
autocomplete_add(vcard_set_param_ac, "pager");
autocomplete_add(vcard_set_param_ac, "msg");
autocomplete_add(vcard_set_param_ac, "cell");
autocomplete_add(vcard_set_param_ac, "video");
autocomplete_add(vcard_set_param_ac, "bbs");
autocomplete_add(vcard_set_param_ac, "modem");
autocomplete_add(vcard_set_param_ac, "isdn");
autocomplete_add(vcard_set_param_ac, "pcs");
autocomplete_add(vcard_set_param_ac, "preferred");
autocomplete_add(vcard_set_param_ac, "x400");
autocomplete_add(vcard_togglable_param_ac, "home");
autocomplete_add(vcard_togglable_param_ac, "work");
autocomplete_add(vcard_togglable_param_ac, "voice");
autocomplete_add(vcard_togglable_param_ac, "fax");
autocomplete_add(vcard_togglable_param_ac, "pager");
autocomplete_add(vcard_togglable_param_ac, "msg");
autocomplete_add(vcard_togglable_param_ac, "cell");
autocomplete_add(vcard_togglable_param_ac, "video");
autocomplete_add(vcard_togglable_param_ac, "bbs");
autocomplete_add(vcard_togglable_param_ac, "modem");
autocomplete_add(vcard_togglable_param_ac, "isdn");
autocomplete_add(vcard_togglable_param_ac, "pcs");
autocomplete_add(vcard_togglable_param_ac, "preferred");
autocomplete_add(vcard_togglable_param_ac, "x400");
autocomplete_add(vcard_address_type_ac, "domestic");
autocomplete_add(vcard_address_type_ac, "international");
autocomplete_add(force_encryption_ac, "on");
autocomplete_add(force_encryption_ac, "off");
autocomplete_add(force_encryption_ac, "policy");
autocomplete_add(force_encryption_policy_ac, "block");
autocomplete_add(force_encryption_policy_ac, "resend-to-confirm");
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, "/autoping", _autoping_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, "/privacy", _privacy_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, "/stamp", _stamp_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);
g_hash_table_insert(ac_funcs, "/force-encryption", _force_encryption_autocomplete);
g_hash_table_insert(ac_funcs, "/ai", _ai_autocomplete);
}
void
cmd_ac_add(const char* const value)
{
if (commands_ac == NULL) {
return;
}
autocomplete_add(commands_ac, value);
}
void
cmd_ac_add_help(const char* const value)
{
if (help_ac == NULL) {
return;
}
autocomplete_add(help_ac, value);
}
void
cmd_ac_add_cmd(const Command* command)
{
autocomplete_add(commands_ac, command->cmd);
autocomplete_add(help_ac, command->cmd + 1);
}
void
cmd_ac_add_alias(ProfAlias* alias)
{
GString* ac_alias = g_string_new("/");
g_string_append(ac_alias, alias->name);
autocomplete_add(commands_ac, ac_alias->str);
autocomplete_add(aliases_ac, alias->name);
g_string_free(ac_alias, TRUE);
}
void
cmd_ac_add_alias_value(char* value)
{
if (aliases_ac == NULL) {
return;
}
autocomplete_add(aliases_ac, value);
}
void
cmd_ac_remove_alias_value(char* value)
{
if (aliases_ac == NULL) {
return;
}
autocomplete_remove(aliases_ac, value);
}
void
cmd_ac_remove(const char* const value)
{
if (commands_ac == NULL) {
return;
}
autocomplete_remove(commands_ac, value);
}
void
cmd_ac_remove_help(const char* const value)
{
if (help_ac == NULL) {
return;
}
autocomplete_remove(help_ac, value);
}
gboolean
cmd_ac_exists(char* cmd)
{
if (commands_ac == NULL) {
return FALSE;
}
return autocomplete_contains(commands_ac, cmd);
}
void
cmd_ac_add_form_fields(DataForm* form)
{
if (form == NULL) {
return;
}
GList* fields = autocomplete_create_list(form->tag_ac);
GList* curr_field = fields;
while (curr_field) {
GString* field_str = g_string_new("/");
g_string_append(field_str, curr_field->data);
cmd_ac_add(field_str->str);
g_string_free(field_str, TRUE);
curr_field = g_list_next(curr_field);
}
g_list_free_full(fields, free);
}
void
cmd_ac_remove_form_fields(DataForm* form)
{
if (form == NULL) {
return;
}
GList* fields = autocomplete_create_list(form->tag_ac);
GList* curr_field = fields;
while (curr_field) {
GString* field_str = g_string_new("/");
g_string_append(field_str, curr_field->data);
cmd_ac_remove(field_str->str);
g_string_free(field_str, TRUE);
curr_field = g_list_next(curr_field);
}
g_list_free_full(fields, free);
}
char*
cmd_ac_complete(ProfWin* window, const char* const input, gboolean previous)
{
if (!input) {
return NULL;
}
char* found = NULL;
// autocomplete command
if ((strncmp(input, "/", 1) == 0) && (!strchr(input, ' '))) {
found = autocomplete_complete(commands_ac, input, TRUE, previous);
// autocomplete parameters
} else {
found = _cmd_ac_complete_params(window, input, previous);
}
return found;
}
void
cmd_ac_reset(ProfWin* window)
{
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status == JABBER_CONNECTED) {
roster_reset_search_attempts();
if (window->type == WIN_CHAT) {
ProfChatWin* chatwin = (ProfChatWin*)window;
assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
PContact contact = roster_get_contact(chatwin->barejid);
if (contact) {
p_contact_resource_ac_reset(contact);
}
}
}
muc_invites_reset_ac();
muc_confserver_reset_ac();
accounts_reset_all_search();
accounts_reset_enabled_search();
tlscerts_reset_ac();
prefs_reset_boolean_choice();
presence_reset_sub_request_search();
#ifdef HAVE_LIBGPGME
p_gpg_autocomplete_key_reset();
#endif
#ifdef HAVE_OMEMO
omemo_fingerprint_autocomplete_reset();
#endif
size_t n;
for (n = ARRAY_SIZE(all_acs); n > 0; --n) {
autocomplete_reset(*(all_acs[n - 1]));
}
if (theme_load_ac) {
autocomplete_free(theme_load_ac);
theme_load_ac = NULL;
}
if (plugins_load_ac) {
autocomplete_free(plugins_load_ac);
plugins_load_ac = NULL;
}
if (plugins_unload_ac) {
autocomplete_free(plugins_unload_ac);
plugins_unload_ac = NULL;
}
if (plugins_reload_ac) {
autocomplete_free(plugins_reload_ac);
plugins_reload_ac = NULL;
}
if (script_show_ac) {
autocomplete_free(script_show_ac);
script_show_ac = NULL;
}
if (window->type == WIN_MUC) {
ProfMucWin* mucwin = (ProfMucWin*)window;
assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
muc_autocomplete_reset(mucwin->roomjid);
muc_jid_autocomplete_reset(mucwin->roomjid);
}
if (window->type == WIN_CONFIG) {
ProfConfWin* confwin = (ProfConfWin*)window;
assert(confwin->memcheck == PROFCONFWIN_MEMCHECK);
if (confwin->form) {
form_reset_autocompleters(confwin->form);
}
}
bookmark_autocomplete_reset();
blocked_ac_reset();
prefs_reset_room_trigger_ac();
win_reset_search_attempts();
win_close_reset_search_attempts();
plugins_reset_autocomplete();
ai_providers_reset_ac();
}
void
cmd_ac_uninit(void)
{
size_t n;
for (n = ARRAY_SIZE(all_acs); n > 0; --n) {
autocomplete_free(*(all_acs[n - 1]));
}
autocomplete_free(theme_load_ac);
autocomplete_free(plugins_load_ac);
autocomplete_free(plugins_unload_ac);
autocomplete_free(plugins_reload_ac);
autocomplete_free(script_show_ac);
g_free(last_filepath_input);
last_filepath_input = NULL;
g_hash_table_destroy(ac_funcs);
ac_funcs = NULL;
}
static void
_filepath_item_free(gchar** ptr)
{
gchar* item = *ptr;
g_free(item);
}
char*
cmd_ac_complete_filepath(const char* const input, char* const startstr, gboolean previous)
{
// strip command
char* inpcp_ptr = (char*)input + strlen(startstr);
while (*inpcp_ptr == ' ') {
inpcp_ptr++;
}
auto_gchar gchar* inpcp = g_strdup(inpcp_ptr);
if (!inpcp) {
return NULL;
}
// strip quotes
if (inpcp[0] == '"') {
char* last_quote = strrchr(inpcp + 1, '"');
if (last_quote) {
*last_quote = '\0';
}
gchar* unquoted = g_strdup(inpcp + 1);
g_free(inpcp);
inpcp = unquoted;
}
auto_gchar gchar* expanded = get_expanded_path(inpcp);
if (!expanded) {
return NULL;
}
auto_gchar gchar* foofile = g_path_get_basename(expanded);
auto_gchar gchar* directory = g_path_get_dirname(expanded);
// If the input is already a known completion, don't update to allow cycling
if (last_filepath_input && (g_strcmp0(inpcp, last_filepath_input) == 0 || autocomplete_contains(filepath_ac, inpcp))) {
return autocomplete_param_with_ac(input, startstr, filepath_ac, TRUE, previous);
}
// If the input ends with a slash, the basename will be "." or "/"
// In that case, we are looking for all files in that directory
gboolean find_all = FALSE;
size_t inpcp_len = strlen(inpcp);
if (inpcp_len == 0 || inpcp[inpcp_len - 1] == '/') {
find_all = TRUE;
}
char* last_slash = strrchr(inpcp, '/');
auto_gchar gchar* user_dir_part = NULL;
if (last_slash) {
user_dir_part = g_strndup(inpcp, last_slash - inpcp + 1);
} else {
user_dir_part = g_strdup("");
}
GArray* files = g_array_new(TRUE, FALSE, sizeof(gchar*));
g_array_set_clear_func(files, (GDestroyNotify)_filepath_item_free);
DIR* d = opendir(directory);
if (d) {
struct dirent* dir;
while ((dir = readdir(d)) != NULL) {
if (strcmp(dir->d_name, ".") == 0 || strcmp(dir->d_name, "..") == 0) {
continue;
}
// check if it matches prefix
if (!find_all && !g_str_has_prefix(dir->d_name, foofile)) {
continue;
}
// only show hidden files on explicit request
if (dir->d_name[0] == '.' && (find_all || foofile[0] != '.')) {
continue;
}
gchar* acstring = g_strdup_printf("%s%s", user_dir_part, dir->d_name);
if (acstring) {
g_array_append_val(files, acstring);
}
}
closedir(d);
}
autocomplete_update(filepath_ac, (char**)files->data);
g_array_free(files, TRUE);
g_free(last_filepath_input);
last_filepath_input = g_strdup(inpcp);
return autocomplete_param_with_ac(input, startstr, filepath_ac, TRUE, previous);
}
static char*
_spellcheck_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;
result = autocomplete_param_with_ac(input, "/spellcheck", spellcheck_ac, TRUE, previous);
return result;
}
static char*
_cmd_ac_complete_params(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;
jabber_conn_status_t conn_status = connection_get_status();
// autocomplete boolean settings
gchar* boolean_choices[] = { "/beep", "/states", "/outtype", "/flash", "/splash",
"/vercheck", "/privileges", "/wrap",
"/carbons", "/slashguard", "/mam", "/silence" };
for (size_t i = 0; i < ARRAY_SIZE(boolean_choices); i++) {
result = autocomplete_param_with_func(input, boolean_choices[i], prefs_autocomplete_boolean_choice, previous, NULL);
if (result) {
return result;
}
}
result = autocomplete_param_with_ac(input, "/history switch", history_switch_ac, TRUE, previous);
if (result) {
return result;
}
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;
}
}
result = autocomplete_param_with_ac(input, "/history", history_ac, TRUE, previous);
if (result) {
return result;
}
result = _spellcheck_autocomplete(window, input, previous);
if (result) {
return result;
}
// autocomplete nickname in chat rooms
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) {
gchar* nick_choices[] = { "/msg", "/info", "/caps" };
// Remove quote character before and after names when doing autocomplete
char* unquoted = strip_arg_quotes(input);
for (size_t i = 0; i < ARRAY_SIZE(nick_choices); i++) {
result = autocomplete_param_with_ac(unquoted, nick_choices[i], nick_ac, TRUE, previous);
if (result) {
free(unquoted);
return result;
}
}
free(unquoted);
}
// otherwise autocomplete using roster
} else if (conn_status == JABBER_CONNECTED) {
gchar* contact_choices[] = { "/msg", "/info" };
// Remove quote character before and after names when doing autocomplete
char* unquoted = strip_arg_quotes(input);
for (size_t i = 0; i < ARRAY_SIZE(contact_choices); i++) {
result = autocomplete_param_with_func(unquoted, contact_choices[i], roster_contact_autocomplete, previous, NULL);
if (result) {
free(unquoted);
return result;
}
result = autocomplete_param_with_func(unquoted, contact_choices[i], roster_barejid_autocomplete, previous, NULL);
if (result) {
free(unquoted);
return result;
}
}
free(unquoted);
gchar* resource_choices[] = { "/caps", "/ping" };
for (size_t i = 0; i < ARRAY_SIZE(resource_choices); i++) {
result = autocomplete_param_with_func(input, resource_choices[i], roster_fulljid_autocomplete, previous, NULL);
if (result) {
return result;
}
}
}
gchar* invite_choices[] = { "/join" };
for (size_t i = 0; i < ARRAY_SIZE(invite_choices); i++) {
result = autocomplete_param_with_func(input, invite_choices[i], muc_invites_find, previous, NULL);
if (result) {
return result;
}
}
struct
{
gchar* cmd;
Autocomplete completer;
} ac_cmds[] = {
{ "/prefs", prefs_ac },
{ "/disco", disco_ac },
{ "/room", room_ac },
{ "/mainwin", winpos_ac },
{ "/inputwin", winpos_ac },
};
for (size_t 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;
}
}
size_t len = strlen(input);
char parsed[len + 1];
size_t i = 0;
while (i < len) {
if (input[i] == ' ') {
break;
} else {
parsed[i] = input[i];
}
i++;
}
parsed[i] = '\0';
char* (*ac_func)(ProfWin*, const char* const, gboolean) = (char* (*)(ProfWin*, const char* const, gboolean))g_hash_table_lookup(ac_funcs, parsed);
if (ac_func) {
result = ac_func(window, input, previous);
if (result) {
return result;
}
}
result = plugins_autocomplete(input, previous);
if (result) {
return result;
}
if (g_str_has_prefix(input, "/field")) {
result = _form_field_autocomplete(window, input, previous);
if (result) {
return result;
}
}
return NULL;
}
static char*
_sub_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;
result = autocomplete_param_with_func(input, "/sub allow", presence_sub_request_find, previous, NULL);
if (result) {
return result;
}
result = autocomplete_param_with_func(input, "/sub deny", presence_sub_request_find, previous, NULL);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/sub", sub_ac, TRUE, previous);
return result;
}
static char*
_tray_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;
result = autocomplete_param_with_func(input, "/tray read", prefs_autocomplete_boolean_choice, previous, NULL);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/tray", tray_ac, FALSE, previous);
return result;
}
static char*
_who_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;
if (window->type == WIN_MUC) {
result = autocomplete_param_with_ac(input, "/who", who_room_ac, TRUE, previous);
if (result) {
return result;
}
} else {
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status == JABBER_CONNECTED) {
gchar* group_commands[] = { "/who any", "/who online", "/who offline",
"/who chat", "/who away", "/who xa", "/who dnd", "/who available",
"/who unavailable" };
for (size_t i = 0; i < ARRAY_SIZE(group_commands); i++) {
result = autocomplete_param_with_func(input, group_commands[i], roster_group_autocomplete, previous, NULL);
if (result) {
return result;
}
}
}
result = autocomplete_param_with_ac(input, "/who", who_roster_ac, TRUE, previous);
}
return result;
}
static char*
_roster_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;
result = autocomplete_param_with_ac(input, "/roster room private char", roster_char_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/roster room private", roster_header_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/roster header char", roster_char_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/roster contact char", roster_char_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/roster room char", roster_char_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/roster private char", roster_char_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/roster resource char", roster_char_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_func(input, "/roster resource join", prefs_autocomplete_boolean_choice, previous, NULL);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/roster room position", roster_room_position_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/roster room by", roster_room_by_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/roster room order", roster_room_order_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/roster room unread", roster_unread_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/roster room title", roster_room_title_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_func(input, "/roster count zero", prefs_autocomplete_boolean_choice, previous, NULL);
if (result) {
return result;
}
result = autocomplete_param_with_func(input, "/roster color", prefs_autocomplete_boolean_choice, previous, NULL);
if (result) {
return result;
}
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status == JABBER_CONNECTED) {
result = autocomplete_param_with_func(input, "/roster nick", roster_barejid_autocomplete, previous, NULL);
if (result) {
return result;
}
result = autocomplete_param_with_func(input, "/roster clearnick", roster_barejid_autocomplete, previous, NULL);
if (result) {
return result;
}
result = autocomplete_param_with_func(input, "/roster remove", roster_contact_autocomplete, previous, NULL);
if (result) {
return result;
}
result = autocomplete_param_with_func(input, "/roster group show", roster_group_autocomplete, previous, NULL);
if (result) {
return result;
}
result = autocomplete_param_no_with_func(input, "/roster group add", 5, roster_contact_autocomplete, previous, NULL);
if (result) {
return result;
}
result = autocomplete_param_no_with_func(input, "/roster group remove", 5, roster_contact_autocomplete, previous, NULL);
if (result) {
return result;
}
result = autocomplete_param_with_func(input, "/roster group add", roster_group_autocomplete, previous, NULL);
if (result) {
return result;
}
result = autocomplete_param_with_func(input, "/roster group remove", roster_group_autocomplete, previous, NULL);
if (result) {
return result;
}
}
result = autocomplete_param_with_ac(input, "/roster remove_all", roster_remove_all_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/roster show", roster_show_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/roster hide", roster_show_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/roster by", roster_by_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/roster count", roster_count_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/roster order", roster_order_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/roster unread", roster_unread_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/roster room", roster_room_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_func(input, "/roster wrap", prefs_autocomplete_boolean_choice, previous, NULL);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/roster header", roster_header_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/roster contact", roster_contact_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/roster resource", roster_resource_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/roster presence", roster_presence_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/roster private", roster_private_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/roster group", group_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/roster", roster_ac, TRUE, previous);
if (result) {
return result;
}
return NULL;
}
static char*
_blocked_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;
result = autocomplete_param_with_func(input, "/blocked remove", blocked_ac_find, previous, NULL);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/blocked", blocked_ac, FALSE, previous);
if (result) {
return result;
}
return NULL;
}
static char*
_bookmark_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* found = NULL;
gboolean result;
auto_gcharv gchar** args = parse_args(input, 2, 8, &result);
if (result && ((strcmp(args[0], "add") == 0) || (strcmp(args[0], "update") == 0))) {
gboolean space_at_end = g_str_has_suffix(input, " ");
int num_args = g_strv_length(args);
if ((num_args == 2 && space_at_end) || (num_args == 3 && !space_at_end)) {
GString* beginning = g_string_new("/bookmark");
g_string_append_printf(beginning, " %s %s", args[0], args[1]);
found = autocomplete_param_with_ac(input, beginning->str, bookmark_property_ac, TRUE, previous);
g_string_free(beginning, TRUE);
if (found) {
return found;
}
}
if ((num_args == 3 && space_at_end && (g_strcmp0(args[2], "autojoin") == 0))
|| (num_args == 4 && (g_strcmp0(args[2], "autojoin") == 0) && !space_at_end)) {
GString* beginning = g_string_new("/bookmark");
g_string_append_printf(beginning, " %s %s %s", args[0], args[1], args[2]);
found = autocomplete_param_with_func(input, beginning->str, prefs_autocomplete_boolean_choice, previous, NULL);
g_string_free(beginning, TRUE);
if (found) {
return found;
}
}
if ((num_args == 4 && space_at_end) || (num_args == 5 && !space_at_end)) {
GString* beginning = g_string_new("/bookmark");
g_string_append_printf(beginning, " %s %s %s %s", args[0], args[1], args[2], args[3]);
found = autocomplete_param_with_ac(input, beginning->str, bookmark_property_ac, TRUE, previous);
g_string_free(beginning, TRUE);
if (found) {
return found;
}
}
if ((num_args == 5 && space_at_end && (g_strcmp0(args[4], "autojoin") == 0))
|| (num_args == 6 && (g_strcmp0(args[4], "autojoin") == 0) && !space_at_end)) {
GString* beginning = g_string_new("/bookmark");
g_string_append_printf(beginning, " %s %s %s %s %s", args[0], args[1], args[2], args[3], args[4]);
found = autocomplete_param_with_func(input, beginning->str, prefs_autocomplete_boolean_choice, previous, NULL);
g_string_free(beginning, TRUE);
if (found) {
return found;
}
}
if ((num_args == 6 && space_at_end) || (num_args == 7 && !space_at_end)) {
GString* beginning = g_string_new("/bookmark");
g_string_append_printf(beginning, " %s %s %s %s %s %s", args[0], args[1], args[2], args[3], args[4], args[5]);
found = autocomplete_param_with_ac(input, beginning->str, bookmark_property_ac, TRUE, previous);
g_string_free(beginning, TRUE);
if (found) {
return found;
}
}
if ((num_args == 7 && space_at_end && (g_strcmp0(args[6], "autojoin") == 0))
|| (num_args == 8 && (g_strcmp0(args[6], "autojoin") == 0) && !space_at_end)) {
GString* beginning = g_string_new("/bookmark");
g_string_append_printf(beginning, " %s %s %s %s %s %s %s", args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
found = autocomplete_param_with_func(input, beginning->str, prefs_autocomplete_boolean_choice, previous, NULL);
g_string_free(beginning, TRUE);
if (found) {
return found;
}
}
}
found = autocomplete_param_with_func(input, "/bookmark remove", bookmark_find, previous, NULL);
if (found) {
return found;
}
found = autocomplete_param_with_func(input, "/bookmark join", bookmark_find, previous, NULL);
if (found) {
return found;
}
found = autocomplete_param_with_func(input, "/bookmark update", bookmark_find, previous, NULL);
if (found) {
return found;
}
found = autocomplete_param_with_func(input, "/bookmark invites", prefs_autocomplete_boolean_choice, previous, NULL);
if (found) {
return found;
}
found = autocomplete_param_with_ac(input, "/bookmark ignore", bookmark_ignore_ac, TRUE, previous);
if (found) {
return found;
}
found = autocomplete_param_with_func(input, "/bookmark ignore add", bookmark_find, previous, NULL);
if (found) {
return found;
}
found = autocomplete_param_with_func(input, "/bookmark ignore remove", bookmark_find, previous, NULL);
if (found) {
return found;
}
found = autocomplete_param_with_func(input, "/bookmark list", bookmark_find, previous, NULL);
if (found) {
return found;
}
found = autocomplete_param_with_ac(input, "/bookmark", bookmark_ac, TRUE, previous);
return found;
}
static char*
_notify_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;
result = autocomplete_param_with_func(input, "/notify room trigger remove", prefs_autocomplete_room_trigger, previous, NULL);
if (result) {
return result;
}
gchar* boolean_choices1[] = { "/notify room current", "/notify chat current", "/notify typing current",
"/notify room text", "/notify chat text", "/notify room offline" };
for (size_t i = 0; i < ARRAY_SIZE(boolean_choices1); i++) {
result = autocomplete_param_with_func(input, boolean_choices1[i], prefs_autocomplete_boolean_choice, previous, NULL);
if (result) {
return result;
}
}
result = autocomplete_param_with_ac(input, "/notify room mention", notify_mention_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/notify room trigger", notify_trigger_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/notify room", notify_room_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/notify chat", notify_chat_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/notify typing", notify_typing_ac, TRUE, previous);
if (result) {
return result;
}
gchar* boolean_choices2[] = { "/notify invite", "/notify sub", "/notify mention", "/notify trigger" };
for (size_t i = 0; i < ARRAY_SIZE(boolean_choices2); i++) {
result = autocomplete_param_with_func(input, boolean_choices2[i], prefs_autocomplete_boolean_choice, previous, NULL);
if (result) {
return result;
}
}
result = autocomplete_param_with_ac(input, "/notify", notify_ac, TRUE, previous);
if (result) {
return result;
}
return NULL;
}
static char*
_autoaway_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;
result = autocomplete_param_with_ac(input, "/autoaway mode", autoaway_mode_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/autoaway time", autoaway_presence_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/autoaway message", autoaway_presence_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_func(input, "/autoaway check", prefs_autocomplete_boolean_choice, previous, NULL);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/autoaway", autoaway_ac, TRUE, previous);
if (result) {
return result;
}
return NULL;
}
static char*
_log_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;
result = autocomplete_param_with_func(input, "/log rotate", prefs_autocomplete_boolean_choice, previous, NULL);
if (result) {
return result;
}
result = autocomplete_param_with_func(input, "/log shared", prefs_autocomplete_boolean_choice, previous, NULL);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/log level", log_level_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/log", log_ac, TRUE, previous);
if (result) {
return result;
}
return NULL;
}
static char*
_autoconnect_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;
result = autocomplete_param_with_func(input, "/autoconnect set", accounts_find_enabled, previous, NULL);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/autoconnect", autoconnect_ac, TRUE, previous);
if (result) {
return result;
}
return NULL;
}
#ifdef HAVE_LIBOTR
static char*
_otr_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* found = NULL;
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status == JABBER_CONNECTED) {
found = autocomplete_param_with_func(input, "/otr start", roster_contact_autocomplete, previous, NULL);
if (found) {
return found;
}
}
found = autocomplete_param_with_ac(input, "/otr log", otr_log_ac, TRUE, previous);
if (found) {
return found;
}
// /otr policy always user@server.com
if (conn_status == JABBER_CONNECTED) {
gboolean result;
auto_gcharv gchar** args = parse_args(input, 2, 3, &result);
if (result && (strcmp(args[0], "policy") == 0)) {
GString* beginning = g_string_new("/otr ");
g_string_append(beginning, args[0]);
g_string_append(beginning, " ");
if (args[1]) {
g_string_append(beginning, args[1]);
}
found = autocomplete_param_with_func(input, beginning->str, roster_contact_autocomplete, previous, NULL);
g_string_free(beginning, TRUE);
if (found) {
return found;
}
}
}
found = autocomplete_param_with_ac(input, "/otr policy", otr_policy_ac, TRUE, previous);
if (found) {
return found;
}
found = autocomplete_param_with_func(input, "/otr sendfile", prefs_autocomplete_boolean_choice, previous, NULL);
if (found) {
return found;
}
found = autocomplete_param_with_ac(input, "/otr", otr_ac, TRUE, previous);
if (found) {
return found;
}
return NULL;
}
#endif
#ifdef HAVE_LIBGPGME
static char*
_pgp_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* found = NULL;
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status == JABBER_CONNECTED) {
found = autocomplete_param_with_func(input, "/pgp start", roster_contact_autocomplete, previous, NULL);
if (found) {
return found;
}
found = autocomplete_param_with_func(input, "/pgp sendpub", roster_contact_autocomplete, previous, NULL);
if (found) {
return found;
}
}
found = autocomplete_param_with_ac(input, "/pgp log", pgp_log_ac, TRUE, previous);
if (found) {
return found;
}
found = autocomplete_param_with_func(input, "/pgp sendfile", prefs_autocomplete_boolean_choice, previous, NULL);
if (found) {
return found;
}
found = autocomplete_param_with_func(input, "/pgp autoimport", prefs_autocomplete_boolean_choice, previous, NULL);
if (found) {
return found;
}
gboolean result;
auto_gcharv gchar** args = parse_args(input, 2, 3, &result);
if ((strncmp(input, "/pgp", 4) == 0) && (result == TRUE)) {
GString* beginning = g_string_new("/pgp ");
g_string_append(beginning, args[0]);
if (args[1]) {
g_string_append(beginning, " ");
g_string_append(beginning, args[1]);
}
found = autocomplete_param_with_func(input, beginning->str, p_gpg_autocomplete_key, previous, NULL);
g_string_free(beginning, TRUE);
if (found) {
return found;
}
}
if (conn_status == JABBER_CONNECTED) {
found = autocomplete_param_with_func(input, "/pgp setkey", roster_barejid_autocomplete, previous, NULL);
if (found) {
return found;
}
}
found = autocomplete_param_with_ac(input, "/pgp", pgp_ac, TRUE, previous);
if (found) {
return found;
}
return NULL;
}
static char*
_ox_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* found = NULL;
found = autocomplete_param_with_ac(input, "/ox", ox_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, "/ox start", roster_contact_autocomplete, previous, NULL);
if (found) {
return found;
}
found = autocomplete_param_with_func(input, "/ox discover", roster_barejid_autocomplete, previous, NULL);
if (found) {
return found;
}
found = autocomplete_param_with_func(input, "/ox setkey", roster_barejid_autocomplete, previous, NULL);
if (found) {
return found;
}
found = autocomplete_param_with_func(input, "/ox request", roster_barejid_autocomplete, previous, NULL);
if (found) {
return found;
}
}
found = autocomplete_param_with_ac(input, "/ox log", ox_log_ac, TRUE, previous);
if (found) {
return found;
}
if (strncmp(input, "/ox announce ", 13) == 0) {
return cmd_ac_complete_filepath(input, "/ox announce", previous);
}
return NULL;
}
#endif
#ifdef HAVE_OMEMO
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;
}
found = autocomplete_param_with_ac(input, "/omemo trustmode", omemo_trustmode_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, NULL);
if (found) {
return found;
}
found = autocomplete_param_with_func(input, "/omemo fingerprint", roster_contact_autocomplete, previous, NULL);
if (found) {
return found;
}
if (window->type == WIN_CHAT) {
ProfChatWin* chatwin = (ProfChatWin*)window;
assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
found = autocomplete_param_with_func(input, "/omemo trust", omemo_fingerprint_autocomplete, previous, chatwin->barejid);
if (found) {
return found;
}
} else {
found = autocomplete_param_with_func(input, "/omemo trust", roster_contact_autocomplete, previous, NULL);
if (found) {
return found;
}
int num_tokens = count_tokens(input);
if (num_tokens == 4) {
gboolean result;
auto_gcharv gchar** args = parse_args(input, 2, 3, &result);
if (result) {
auto_gchar gchar* jid = g_strdup(args[1]);
found = autocomplete_param_no_with_func(input, "/omemo trust", 4, omemo_fingerprint_autocomplete, previous, jid);
if (found) {
return found;
}
}
}
}
if (window->type == WIN_CHAT) {
ProfChatWin* chatwin = (ProfChatWin*)window;
assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
found = autocomplete_param_with_func(input, "/omemo untrust", omemo_fingerprint_autocomplete, previous, chatwin->barejid);
if (found) {
return found;
}
} else {
found = autocomplete_param_with_func(input, "/omemo untrust", roster_contact_autocomplete, previous, NULL);
if (found) {
return found;
}
int num_tokens = count_tokens(input);
if (num_tokens == 4) {
gboolean result;
auto_gcharv gchar** args = parse_args(input, 2, 3, &result);
if (result) {
auto_gchar gchar* jid = g_strdup(args[1]);
found = autocomplete_param_no_with_func(input, "/omemo untrust", 4, omemo_fingerprint_autocomplete, previous, jid);
if (found) {
return found;
}
}
}
}
}
found = autocomplete_param_with_ac(input, "/omemo", omemo_ac, TRUE, previous);
if (found) {
return found;
}
return NULL;
}
#endif
static char*
_plugins_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;
if (strncmp(input, "/plugins install ", 17) == 0) {
return cmd_ac_complete_filepath(input, "/plugins install", previous);
}
if (strncmp(input, "/plugins update ", 16) == 0) {
return cmd_ac_complete_filepath(input, "/plugins update", previous);
}
if (strncmp(input, "/plugins load ", 14) == 0) {
if (plugins_load_ac == NULL) {
plugins_load_ac = autocomplete_new();
GSList* plugins = plugins_unloaded_list();
GSList* curr = plugins;
while (curr) {
autocomplete_add(plugins_load_ac, curr->data);
curr = g_slist_next(curr);
}
g_slist_free_full(plugins, g_free);
}
result = autocomplete_param_with_ac(input, "/plugins load", plugins_load_ac, TRUE, previous);
if (result) {
return result;
}
}
if (strncmp(input, "/plugins reload ", 16) == 0) {
if (plugins_reload_ac == NULL) {
plugins_reload_ac = autocomplete_new();
GList* plugins = plugins_loaded_list();
GList* curr = plugins;
while (curr) {
autocomplete_add(plugins_reload_ac, curr->data);
curr = g_list_next(curr);
}
g_list_free(plugins);
}
result = autocomplete_param_with_ac(input, "/plugins reload", plugins_reload_ac, TRUE, previous);
if (result) {
return result;
}
}
if (strncmp(input, "/plugins unload ", 16) == 0) {
if (plugins_unload_ac == NULL) {
plugins_unload_ac = autocomplete_new();
GList* plugins = plugins_loaded_list();
GList* curr = plugins;
while (curr) {
autocomplete_add(plugins_unload_ac, curr->data);
curr = g_list_next(curr);
}
g_list_free(plugins);
}
result = autocomplete_param_with_ac(input, "/plugins unload", plugins_unload_ac, TRUE, previous);
if (result) {
return result;
}
}
result = autocomplete_param_with_ac(input, "/plugins", plugins_ac, TRUE, previous);
if (result) {
return result;
}
return NULL;
}
static char*
_theme_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;
if (strncmp(input, "/theme load ", 12) == 0) {
if (theme_load_ac == NULL) {
theme_load_ac = autocomplete_new();
GSList* themes = theme_list();
GSList* curr = themes;
while (curr) {
autocomplete_add(theme_load_ac, curr->data);
curr = g_slist_next(curr);
}
g_slist_free_full(themes, g_free);
autocomplete_add(theme_load_ac, "default");
}
result = autocomplete_param_with_ac(input, "/theme load", theme_load_ac, TRUE, previous);
if (result) {
return result;
}
}
if (strncmp(input, "/theme full-load ", 17) == 0) {
if (theme_load_ac == NULL) {
theme_load_ac = autocomplete_new();
GSList* themes = theme_list();
GSList* curr = themes;
while (curr) {
autocomplete_add(theme_load_ac, curr->data);
curr = g_slist_next(curr);
}
g_slist_free_full(themes, g_free);
autocomplete_add(theme_load_ac, "default");
}
result = autocomplete_param_with_ac(input, "/theme full-load", theme_load_ac, TRUE, previous);
if (result) {
return result;
}
}
result = autocomplete_param_with_ac(input, "/theme", theme_ac, TRUE, previous);
if (result) {
return result;
}
return NULL;
}
static char*
_script_autocomplete_func(const char* const prefix, gboolean previous, void* context)
{
if (script_show_ac == NULL) {
script_show_ac = autocomplete_new();
GSList* scripts = scripts_list();
GSList* curr = scripts;
while (curr) {
autocomplete_add(script_show_ac, curr->data);
curr = g_slist_next(curr);
}
g_slist_free_full(scripts, g_free);
}
return autocomplete_complete(script_show_ac, prefix, FALSE, previous);
}
static char*
_script_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;
if (strncmp(input, "/script show ", 13) == 0) {
result = autocomplete_param_with_func(input, "/script show", _script_autocomplete_func, previous, NULL);
if (result) {
return result;
}
}
if (strncmp(input, "/script run ", 12) == 0) {
result = autocomplete_param_with_func(input, "/script run", _script_autocomplete_func, previous, NULL);
if (result) {
return result;
}
}
result = autocomplete_param_with_ac(input, "/script", script_ac, TRUE, previous);
if (result) {
return result;
}
return NULL;
}
static char*
_resource_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* found = NULL;
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status == JABBER_CONNECTED && window->type == WIN_CHAT) {
ProfChatWin* chatwin = (ProfChatWin*)window;
assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
PContact contact = roster_get_contact(chatwin->barejid);
if (contact) {
Autocomplete ac = p_contact_resource_ac(contact);
found = autocomplete_param_with_ac(input, "/resource set", ac, FALSE, previous);
if (found) {
return found;
}
}
}
found = autocomplete_param_with_func(input, "/resource title", prefs_autocomplete_boolean_choice, previous, NULL);
if (found) {
return found;
}
found = autocomplete_param_with_func(input, "/resource message", prefs_autocomplete_boolean_choice, previous, NULL);
if (found) {
return found;
}
found = autocomplete_param_with_ac(input, "/resource", resource_ac, FALSE, previous);
if (found) {
return found;
}
return NULL;
}
static char*
_wintitle_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* found = NULL;
found = autocomplete_param_with_func(input, "/wintitle show", prefs_autocomplete_boolean_choice, previous, NULL);
if (found) {
return found;
}
found = autocomplete_param_with_func(input, "/wintitle goodbye", prefs_autocomplete_boolean_choice, previous, NULL);
if (found) {
return found;
}
found = autocomplete_param_with_ac(input, "/wintitle", wintitle_ac, FALSE, previous);
if (found) {
return found;
}
return NULL;
}
static char*
_inpblock_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* found = NULL;
found = autocomplete_param_with_func(input, "/inpblock dynamic", prefs_autocomplete_boolean_choice, previous, NULL);
if (found) {
return found;
}
found = autocomplete_param_with_ac(input, "/inpblock", inpblock_ac, FALSE, previous);
if (found) {
return found;
}
return NULL;
}
static char*
_form_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
if (window->type != WIN_CONFIG) {
return NULL;
}
char* found = NULL;
ProfConfWin* confwin = (ProfConfWin*)window;
DataForm* form = confwin->form;
if (form) {
found = autocomplete_param_with_ac(input, "/form help", form->tag_ac, TRUE, previous);
if (found) {
return found;
}
}
found = autocomplete_param_with_ac(input, "/form", form_ac, TRUE, previous);
if (found) {
return found;
}
return NULL;
}
static char*
_form_field_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
if (window->type != WIN_CONFIG) {
return NULL;
}
char* found = NULL;
ProfConfWin* confwin = (ProfConfWin*)window;
DataForm* form = confwin->form;
if (form == NULL) {
return NULL;
}
auto_gcharv gchar** split = g_strsplit(input, " ", 0);
if (g_strv_length(split) == 3) {
char* field_tag = split[0] + 1;
if (form_tag_exists(form, field_tag)) {
form_field_type_t field_type = form_get_field_type(form, field_tag);
Autocomplete value_ac = form_get_value_ac(form, field_tag);
GString* beginning = g_string_new(split[0]);
g_string_append(beginning, " ");
g_string_append(beginning, split[1]);
if (((g_strcmp0(split[1], "add") == 0) || (g_strcmp0(split[1], "remove") == 0))
&& field_type == FIELD_LIST_MULTI) {
found = autocomplete_param_with_ac(input, beginning->str, value_ac, TRUE, previous);
} else if ((g_strcmp0(split[1], "remove") == 0) && field_type == FIELD_TEXT_MULTI) {
found = autocomplete_param_with_ac(input, beginning->str, value_ac, TRUE, previous);
} else if ((g_strcmp0(split[1], "remove") == 0) && field_type == FIELD_JID_MULTI) {
found = autocomplete_param_with_ac(input, beginning->str, value_ac, TRUE, previous);
}
g_string_free(beginning, TRUE);
}
} else if (g_strv_length(split) == 2) {
char* field_tag = split[0] + 1;
if (form_tag_exists(form, field_tag)) {
form_field_type_t field_type = form_get_field_type(form, field_tag);
Autocomplete value_ac = form_get_value_ac(form, field_tag);
switch (field_type) {
case FIELD_BOOLEAN:
found = autocomplete_param_with_func(input, split[0], prefs_autocomplete_boolean_choice, previous, NULL);
break;
case FIELD_LIST_SINGLE:
found = autocomplete_param_with_ac(input, split[0], value_ac, TRUE, previous);
break;
case FIELD_LIST_MULTI:
case FIELD_JID_MULTI:
case FIELD_TEXT_MULTI:
found = autocomplete_param_with_ac(input, split[0], form_field_multi_ac, TRUE, previous);
break;
default:
break;
}
}
}
return found;
}
static char*
_occupants_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* found = NULL;
found = autocomplete_param_with_ac(input, "/occupants default show", occupants_show_ac, TRUE, previous);
if (found) {
return found;
}
found = autocomplete_param_with_ac(input, "/occupants char", occupants_char_ac, TRUE, previous);
if (found) {
return found;
}
found = autocomplete_param_with_func(input, "/occupants color", prefs_autocomplete_boolean_choice, previous, NULL);
if (found) {
return found;
}
found = autocomplete_param_with_ac(input, "/occupants default hide", occupants_show_ac, TRUE, previous);
if (found) {
return found;
}
found = autocomplete_param_with_ac(input, "/occupants default", occupants_default_ac, TRUE, previous);
if (found) {
return found;
}
found = autocomplete_param_with_ac(input, "/occupants show", occupants_show_ac, TRUE, previous);
if (found) {
return found;
}
found = autocomplete_param_with_ac(input, "/occupants hide", occupants_show_ac, TRUE, previous);
if (found) {
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, NULL);
if (found) {
return found;
}
found = autocomplete_param_with_ac(input, "/occupants", occupants_ac, TRUE, previous);
if (found) {
return found;
}
return NULL;
}
static char*
_time_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* found = NULL;
found = autocomplete_param_with_ac(input, "/time statusbar", time_format_ac, TRUE, previous);
if (found) {
return found;
}
found = autocomplete_param_with_ac(input, "/time lastactivity", time_format_ac, TRUE, previous);
if (found) {
return found;
}
found = autocomplete_param_with_ac(input, "/time console", time_format_ac, TRUE, previous);
if (found) {
return found;
}
found = autocomplete_param_with_ac(input, "/time chat", time_format_ac, TRUE, previous);
if (found) {
return found;
}
found = autocomplete_param_with_ac(input, "/time muc", time_format_ac, TRUE, previous);
if (found) {
return found;
}
found = autocomplete_param_with_ac(input, "/time config", time_format_ac, TRUE, previous);
if (found) {
return found;
}
found = autocomplete_param_with_ac(input, "/time private", time_format_ac, TRUE, previous);
if (found) {
return found;
}
found = autocomplete_param_with_ac(input, "/time xml", time_format_ac, TRUE, previous);
if (found) {
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;
}
return NULL;
}
static char*
_kick_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
if (window->type != WIN_MUC) {
return NULL;
}
ProfMucWin* mucwin = (ProfMucWin*)window;
assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
Autocomplete nick_ac = muc_roster_ac(mucwin->roomjid);
if (nick_ac == NULL) {
return NULL;
}
char* result = autocomplete_param_with_ac(input, "/kick", nick_ac, TRUE, previous);
return result;
}
static char*
_ban_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
if (window->type != WIN_MUC) {
return NULL;
}
ProfMucWin* mucwin = (ProfMucWin*)window;
assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
Autocomplete jid_ac = muc_roster_jid_ac(mucwin->roomjid);
if (jid_ac == NULL) {
return NULL;
}
char* result = autocomplete_param_with_ac(input, "/ban", jid_ac, TRUE, previous);
return result;
}
static char*
_affiliation_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;
if (window->type == WIN_MUC) {
ProfMucWin* mucwin = (ProfMucWin*)window;
assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
gboolean parse_result;
Autocomplete jid_ac = muc_roster_jid_ac(mucwin->roomjid);
auto_gcharv gchar** args = parse_args(input, 2, 3, &parse_result);
if ((strncmp(input, "/affiliation", 12) == 0) && (parse_result == TRUE)) {
GString* beginning = g_string_new("/affiliation ");
g_string_append(beginning, args[0]);
g_string_append(beginning, " ");
if (args[1]) {
g_string_append(beginning, args[1]);
}
result = autocomplete_param_with_ac(input, beginning->str, jid_ac, TRUE, previous);
g_string_free(beginning, TRUE);
if (result) {
return result;
}
}
}
result = autocomplete_param_with_ac(input, "/affiliation set", affiliation_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/affiliation list", affiliation_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/affiliation", affiliation_cmd_ac, TRUE, previous);
return result;
}
static char*
_role_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;
if (window->type == WIN_MUC) {
ProfMucWin* mucwin = (ProfMucWin*)window;
assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
gboolean parse_result;
Autocomplete nick_ac = muc_roster_ac(mucwin->roomjid);
auto_gcharv gchar** args = parse_args(input, 2, 3, &parse_result);
if ((strncmp(input, "/role", 5) == 0) && (parse_result == TRUE)) {
GString* beginning = g_string_new("/role ");
g_string_append(beginning, args[0]);
g_string_append(beginning, " ");
if (args[1]) {
g_string_append(beginning, args[1]);
}
result = autocomplete_param_with_ac(input, beginning->str, nick_ac, TRUE, previous);
g_string_free(beginning, TRUE);
if (result) {
return result;
}
}
}
result = autocomplete_param_with_ac(input, "/role set", role_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/role list", role_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/role", role_cmd_ac, TRUE, previous);
return result;
}
static char*
_wins_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;
result = autocomplete_param_with_ac(input, "/wins", wins_ac, TRUE, previous);
return result;
}
static char*
_tls_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;
result = autocomplete_param_with_func(input, "/tls revoke", tlscerts_complete, previous, NULL);
if (result) {
return result;
}
result = autocomplete_param_with_func(input, "/tls cert", tlscerts_complete, previous, NULL);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/tls certpath", tls_certpath_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/tls", tls_ac, TRUE, previous);
return result;
}
static char*
_titlebar_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;
result = autocomplete_param_with_ac(input, "/titlebar room title", titlebar_room_title_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/titlebar room", titlebar_room_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/titlebar show", titlebar_show_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/titlebar hide", titlebar_show_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/titlebar", titlebar_ac, TRUE, previous);
return result;
}
static char*
_receipts_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;
result = autocomplete_param_with_func(input, "/receipts send", prefs_autocomplete_boolean_choice, previous, NULL);
if (result) {
return result;
}
result = autocomplete_param_with_func(input, "/receipts request", prefs_autocomplete_boolean_choice, previous, NULL);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/receipts", receipts_ac, TRUE, previous);
return result;
}
static char*
_reconnect_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;
result = autocomplete_param_with_ac(input, "/reconnect", reconnect_ac, TRUE, previous);
return result;
}
static char*
_alias_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;
result = autocomplete_param_with_ac(input, "/alias remove", aliases_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/alias", alias_ac, TRUE, previous);
return result;
}
static char*
_connect_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* found = NULL;
gboolean result = FALSE;
auto_gcharv gchar** args = parse_args(input, 1, 9, &result);
if (result) {
gboolean space_at_end = g_str_has_suffix(input, " ");
int num_args = g_strv_length(args);
if ((num_args == 1 && space_at_end) || (num_args == 2 && !space_at_end)) {
GString* beginning = g_string_new("/connect");
g_string_append_printf(beginning, " %s", args[0]);
found = autocomplete_param_with_ac(input, beginning->str, connect_property_ac, TRUE, previous);
g_string_free(beginning, TRUE);
if (found) {
return found;
}
}
if ((num_args == 2 && space_at_end && (g_strcmp0(args[1], "tls") == 0))
|| (num_args == 3 && (g_strcmp0(args[1], "tls") == 0) && !space_at_end)) {
GString* beginning = g_string_new("/connect");
g_string_append_printf(beginning, " %s %s", args[0], args[1]);
found = autocomplete_param_with_ac(input, beginning->str, tls_property_ac, TRUE, previous);
g_string_free(beginning, TRUE);
if (found) {
return found;
}
}
if ((num_args == 3 && space_at_end) || (num_args == 4 && !space_at_end)) {
GString* beginning = g_string_new("/connect");
g_string_append_printf(beginning, " %s %s %s", args[0], args[1], args[2]);
found = autocomplete_param_with_ac(input, beginning->str, connect_property_ac, TRUE, previous);
g_string_free(beginning, TRUE);
if (found) {
return found;
}
}
if ((num_args == 4 && space_at_end && (g_strcmp0(args[3], "tls") == 0))
|| (num_args == 5 && (g_strcmp0(args[3], "tls") == 0) && !space_at_end)) {
GString* beginning = g_string_new("/connect");
g_string_append_printf(beginning, " %s %s %s %s", args[0], args[1], args[2], args[3]);
found = autocomplete_param_with_ac(input, beginning->str, tls_property_ac, TRUE, previous);
g_string_free(beginning, TRUE);
if (found) {
return found;
}
}
if ((num_args == 5 && space_at_end) || (num_args == 6 && !space_at_end)) {
GString* beginning = g_string_new("/connect");
g_string_append_printf(beginning, " %s %s %s %s %s", args[0], args[1], args[2], args[3], args[4]);
found = autocomplete_param_with_ac(input, beginning->str, connect_property_ac, TRUE, previous);
g_string_free(beginning, TRUE);
if (found) {
return found;
}
}
if ((num_args == 6 && space_at_end && (g_strcmp0(args[5], "tls") == 0))
|| (num_args == 7 && (g_strcmp0(args[5], "tls") == 0) && !space_at_end)) {
GString* beginning = g_string_new("/connect");
g_string_append_printf(beginning, " %s %s %s %s %s %s", args[0], args[1], args[2], args[3], args[4], args[5]);
found = autocomplete_param_with_ac(input, beginning->str, tls_property_ac, TRUE, previous);
g_string_free(beginning, TRUE);
if (found) {
return found;
}
}
if ((num_args == 7 && space_at_end) || (num_args == 8 && !space_at_end)) {
GString* beginning = g_string_new("/connect");
g_string_append_printf(beginning, " %s %s %s %s %s %s %s", args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
found = autocomplete_param_with_ac(input, beginning->str, connect_property_ac, TRUE, previous);
g_string_free(beginning, TRUE);
if (found) {
return found;
}
}
if ((num_args == 8 && space_at_end && (g_strcmp0(args[7], "tls") == 0))
|| (num_args == 9 && (g_strcmp0(args[7], "tls") == 0) && !space_at_end)) {
GString* beginning = g_string_new("/connect");
g_string_append_printf(beginning, " %s %s %s %s %s %s %s %s", args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]);
found = autocomplete_param_with_ac(input, beginning->str, tls_property_ac, TRUE, previous);
g_string_free(beginning, TRUE);
if (found) {
return found;
}
}
/* auth option */
if ((num_args == 2 && space_at_end && (g_strcmp0(args[1], "auth") == 0))
|| (num_args == 3 && (g_strcmp0(args[1], "auth") == 0) && !space_at_end)) {
GString* beginning = g_string_new("/connect");
g_string_append_printf(beginning, " %s %s", args[0], args[1]);
found = autocomplete_param_with_ac(input, beginning->str, auth_property_ac, TRUE, previous);
g_string_free(beginning, TRUE);
if (found) {
return found;
}
}
if ((num_args == 4 && space_at_end && (g_strcmp0(args[3], "auth") == 0))
|| (num_args == 5 && (g_strcmp0(args[3], "auth") == 0) && !space_at_end)) {
GString* beginning = g_string_new("/connect");
g_string_append_printf(beginning, " %s %s %s %s", args[0], args[1], args[2], args[3]);
found = autocomplete_param_with_ac(input, beginning->str, auth_property_ac, TRUE, previous);
g_string_free(beginning, TRUE);
if (found) {
return found;
}
}
if ((num_args == 6 && space_at_end && (g_strcmp0(args[5], "auth") == 0))
|| (num_args == 7 && (g_strcmp0(args[5], "auth") == 0) && !space_at_end)) {
GString* beginning = g_string_new("/connect");
g_string_append_printf(beginning, " %s %s %s %s %s %s", args[0], args[1], args[2], args[3], args[4], args[5]);
found = autocomplete_param_with_ac(input, beginning->str, auth_property_ac, TRUE, previous);
g_string_free(beginning, TRUE);
if (found) {
return found;
}
}
if ((num_args == 8 && space_at_end && (g_strcmp0(args[7], "auth") == 0))
|| (num_args == 9 && (g_strcmp0(args[7], "auth") == 0) && !space_at_end)) {
GString* beginning = g_string_new("/connect");
g_string_append_printf(beginning, " %s %s %s %s %s %s %s %s", args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]);
found = autocomplete_param_with_ac(input, beginning->str, auth_property_ac, TRUE, previous);
g_string_free(beginning, TRUE);
if (found) {
return found;
}
}
}
found = autocomplete_param_with_func(input, "/connect", accounts_find_enabled, previous, NULL);
if (found) {
return found;
}
return NULL;
}
static char*
_help_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;
result = autocomplete_param_with_ac(input, "/help commands", help_commands_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/help", help_ac, TRUE, previous);
return result;
}
static char*
_join_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* found = NULL;
gboolean result = FALSE;
auto_gcharv gchar** args = parse_args(input, 1, 5, &result);
if (result) {
gboolean space_at_end = g_str_has_suffix(input, " ");
int num_args = g_strv_length(args);
if ((num_args == 1 && space_at_end) || (num_args == 2 && !space_at_end)) {
GString* beginning = g_string_new("/join");
g_string_append_printf(beginning, " %s", args[0]);
found = autocomplete_param_with_ac(input, beginning->str, join_property_ac, TRUE, previous);
g_string_free(beginning, TRUE);
if (found) {
return found;
}
}
if ((num_args == 3 && space_at_end) || (num_args == 4 && !space_at_end)) {
GString* beginning = g_string_new("/join");
g_string_append_printf(beginning, " %s %s %s", args[0], args[1], args[2]);
found = autocomplete_param_with_ac(input, beginning->str, join_property_ac, TRUE, previous);
g_string_free(beginning, TRUE);
if (found) {
return found;
}
}
}
found = autocomplete_param_with_func(input, "/join", bookmark_find, previous, NULL);
return found;
}
static char*
_console_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;
result = autocomplete_param_with_ac(input, "/console chat", console_msg_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/console muc", console_msg_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/console private", console_msg_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/console", console_ac, TRUE, previous);
return result;
}
static char*
_win_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = autocomplete_param_with_func(input, "/win", win_autocomplete, previous, NULL);
if (result) {
return result;
}
char* unquoted = strip_arg_quotes(input);
result = autocomplete_param_with_func(unquoted, "/win", roster_contact_autocomplete, previous, NULL);
free(unquoted);
return result;
}
static char*
_close_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
return autocomplete_param_with_func(input, "/close", win_close_autocomplete, previous, NULL);
}
static char*
_sendfile_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
return cmd_ac_complete_filepath(input, "/sendfile", previous);
}
static char*
_subject_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;
if (window->type == WIN_MUC) {
if ((g_strcmp0(input, "/subject edit ") == 0)
|| (g_strcmp0(input, "/subject edit \"") == 0)) {
ProfMucWin* mucwin = (ProfMucWin*)window;
assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
char* subject = muc_subject(mucwin->roomjid);
if (subject) {
result = g_strdup_printf("/subject edit \"%s\"", subject);
}
}
}
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/subject", subject_ac, TRUE, previous);
return result;
}
static char*
_account_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* found = NULL;
gboolean result = FALSE;
auto_gcharv gchar** args = parse_args(input, 2, 4, &result);
if (result && (strcmp(args[0], "set") == 0)) {
gboolean space_at_end = g_str_has_suffix(input, " ");
int num_args = g_strv_length(args);
if ((num_args == 2 && space_at_end) || (num_args == 3 && !space_at_end)) {
GString* beginning = g_string_new("/account");
g_string_append_printf(beginning, " %s %s", args[0], args[1]);
found = autocomplete_param_with_ac(input, beginning->str, account_set_ac, TRUE, previous);
g_string_free(beginning, TRUE);
if (found) {
return found;
}
}
#ifdef HAVE_LIBOTR
if ((num_args == 3 && space_at_end && (g_strcmp0(args[2], "otr") == 0))
|| (num_args == 4 && (g_strcmp0(args[2], "otr") == 0) && !space_at_end)) {
GString* beginning = g_string_new("/account");
g_string_append_printf(beginning, " %s %s %s", args[0], args[1], args[2]);
found = autocomplete_param_with_ac(input, beginning->str, otr_policy_ac, TRUE, previous);
g_string_free(beginning, TRUE);
if (found) {
g_strfreev(args);
return found;
}
}
#endif
if ((num_args == 3 && space_at_end && (g_strcmp0(args[2], "status") == 0))
|| (num_args == 4 && (g_strcmp0(args[2], "status") == 0) && !space_at_end)) {
GString* beginning = g_string_new("/account");
g_string_append_printf(beginning, " %s %s %s", args[0], args[1], args[2]);
found = autocomplete_param_with_ac(input, beginning->str, account_status_ac, TRUE, previous);
g_string_free(beginning, TRUE);
if (found) {
return found;
}
}
if ((num_args == 3 && space_at_end && (g_strcmp0(args[2], "tls") == 0))
|| (num_args == 4 && (g_strcmp0(args[2], "tls") == 0) && !space_at_end)) {
GString* beginning = g_string_new("/account");
g_string_append_printf(beginning, " %s %s %s", args[0], args[1], args[2]);
found = autocomplete_param_with_ac(input, beginning->str, tls_property_ac, TRUE, previous);
g_string_free(beginning, TRUE);
if (found) {
return found;
}
}
if ((num_args == 3 && space_at_end && (g_strcmp0(args[2], "auth") == 0))
|| (num_args == 4 && (g_strcmp0(args[2], "auth") == 0) && !space_at_end)) {
GString* beginning = g_string_new("/account");
g_string_append_printf(beginning, " %s %s %s", args[0], args[1], args[2]);
found = autocomplete_param_with_ac(input, beginning->str, auth_property_ac, TRUE, previous);
g_string_free(beginning, TRUE);
if (found) {
return found;
}
}
if ((num_args == 3 && space_at_end && (g_strcmp0(args[2], "startscript") == 0))
|| (num_args == 4 && (g_strcmp0(args[2], "startscript") == 0) && !space_at_end)) {
GString* beginning = g_string_new("/account");
g_string_append_printf(beginning, " %s %s %s", args[0], args[1], args[2]);
found = autocomplete_param_with_func(input, beginning->str, _script_autocomplete_func, previous, NULL);
g_string_free(beginning, TRUE);
if (found) {
return found;
}
}
if ((num_args == 3 && space_at_end && (g_strcmp0(args[2], "theme") == 0))
|| (num_args == 4 && (g_strcmp0(args[2], "theme") == 0) && !space_at_end)) {
GString* beginning = g_string_new("/account");
g_string_append_printf(beginning, " %s %s %s", args[0], args[1], args[2]);
if (theme_load_ac == NULL) {
theme_load_ac = autocomplete_new();
GSList* themes = theme_list();
GSList* curr = themes;
while (curr) {
autocomplete_add(theme_load_ac, curr->data);
curr = g_slist_next(curr);
}
g_slist_free_full(themes, g_free);
autocomplete_add(theme_load_ac, "default");
}
found = autocomplete_param_with_ac(input, beginning->str, theme_load_ac, TRUE, previous);
g_string_free(beginning, TRUE);
if (found) {
return found;
}
}
#ifdef HAVE_LIBGPGME
if ((num_args == 3 && space_at_end && (g_strcmp0(args[2], "pgpkeyid") == 0))
|| (num_args == 4 && (g_strcmp0(args[2], "pgpkeyid") == 0) && !space_at_end)) {
GString* beginning = g_string_new("/account");
g_string_append_printf(beginning, " %s %s %s", args[0], args[1], args[2]);
found = autocomplete_param_with_func(input, beginning->str, p_gpg_autocomplete_key, previous, NULL);
g_string_free(beginning, TRUE);
if (found) {
return found;
}
}
#endif
}
if ((strncmp(input, "/account clear", 14) == 0) && (result == TRUE)) {
GString* beginning = g_string_new("/account clear ");
g_string_append(beginning, args[1]);
found = autocomplete_param_with_ac(input, beginning->str, account_clear_ac, TRUE, previous);
g_string_free(beginning, TRUE);
if (found) {
return found;
}
}
found = autocomplete_param_with_ac(input, "/account default", account_default_ac, TRUE, previous);
if (found) {
return found;
}
gchar* account_choice[] = { "/account set", "/account show", "/account enable",
"/account disable", "/account rename", "/account clear", "/account remove",
"/account default set" };
for (size_t i = 0; i < ARRAY_SIZE(account_choice); i++) {
found = autocomplete_param_with_func(input, account_choice[i], accounts_find_all, previous, NULL);
if (found) {
return found;
}
}
found = autocomplete_param_with_ac(input, "/account", account_ac, TRUE, previous);
return found;
}
static char*
_presence_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* found = NULL;
found = autocomplete_param_with_func(input, "/presence titlebar", prefs_autocomplete_boolean_choice, previous, NULL);
if (found) {
return found;
}
found = autocomplete_param_with_ac(input, "/presence console", presence_setting_ac, TRUE, previous);
if (found) {
return found;
}
found = autocomplete_param_with_ac(input, "/presence chat", presence_setting_ac, TRUE, previous);
if (found) {
return found;
}
found = autocomplete_param_with_ac(input, "/presence room", presence_setting_ac, TRUE, previous);
if (found) {
return found;
}
found = autocomplete_param_with_ac(input, "/presence", presence_ac, TRUE, previous);
return found;
}
static char*
_rooms_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* found = NULL;
gboolean result = FALSE;
auto_gcharv gchar** args = parse_args(input, 0, 4, &result);
if (result) {
gboolean space_at_end = g_str_has_suffix(input, " ");
int num_args = g_strv_length(args);
if (num_args <= 1) {
found = autocomplete_param_with_ac(input, "/rooms", rooms_all_ac, TRUE, previous);
if (found) {
return found;
}
}
if ((num_args == 1 && g_strcmp0(args[0], "service") == 0 && space_at_end) || (num_args == 2 && g_strcmp0(args[0], "service") == 0 && !space_at_end)) {
found = autocomplete_param_with_func(input, "/rooms service", muc_confserver_find, previous, NULL);
if (found) {
return found;
}
}
if ((num_args == 1 && g_strcmp0(args[0], "cache") == 0 && space_at_end) || (num_args == 2 && g_strcmp0(args[0], "cache") == 0 && !space_at_end)) {
found = autocomplete_param_with_ac(input, "/rooms cache", rooms_cache_ac, TRUE, previous);
if (found) {
return found;
}
}
if ((num_args == 2 && space_at_end) || (num_args == 3 && !space_at_end)) {
GString* beginning = g_string_new("/rooms");
g_string_append_printf(beginning, " %s %s", args[0], args[1]);
found = autocomplete_param_with_ac(input, beginning->str, rooms_list_ac, TRUE, previous);
g_string_free(beginning, TRUE);
if (found) {
return found;
}
}
if ((num_args == 3 && g_strcmp0(args[2], "service") == 0 && space_at_end) || (num_args == 4 && g_strcmp0(args[2], "service") == 0 && !space_at_end)) {
GString* beginning = g_string_new("/rooms");
g_string_append_printf(beginning, " %s %s %s", args[0], args[1], args[2]);
found = autocomplete_param_with_func(input, beginning->str, muc_confserver_find, previous, NULL);
g_string_free(beginning, TRUE);
if (found) {
return found;
}
}
if ((num_args >= 2) && g_strcmp0(args[0], "cache") == 0) {
return NULL;
}
}
return NULL;
}
static char*
_statusbar_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* found = NULL;
found = autocomplete_param_with_ac(input, "/statusbar", statusbar_ac, TRUE, previous);
if (found) {
return found;
}
found = autocomplete_param_with_ac(input, "/statusbar show", statusbar_show_ac, TRUE, previous);
if (found) {
return found;
}
found = autocomplete_param_with_ac(input, "/statusbar hide", statusbar_show_ac, TRUE, previous);
if (found) {
return found;
}
found = autocomplete_param_with_ac(input, "/statusbar self", statusbar_self_ac, TRUE, previous);
if (found) {
return found;
}
found = autocomplete_param_with_ac(input, "/statusbar chat", statusbar_chat_ac, TRUE, previous);
if (found) {
return found;
}
found = autocomplete_param_with_ac(input, "/statusbar tabmode", statusbar_tabmode_ac, TRUE, previous);
if (found) {
return found;
}
found = autocomplete_param_with_ac(input, "/statusbar room", statusbar_room_ac, TRUE, previous);
if (found) {
return found;
}
found = autocomplete_param_with_ac(input, "/statusbar room title", statusbar_room_title_ac, TRUE, previous);
return found;
}
static char*
_clear_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;
result = autocomplete_param_with_ac(input, "/clear", clear_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_func(input, "/clear persist_history", prefs_autocomplete_boolean_choice, previous, NULL);
return result;
}
static char*
_invite_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;
result = autocomplete_param_with_ac(input, "/invite", invite_ac, TRUE, previous);
if (result) {
return result;
}
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status == JABBER_CONNECTED) {
result = autocomplete_param_with_func(input, "/invite send", roster_contact_autocomplete, 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;
}
static char*
_status_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;
result = autocomplete_param_with_ac(input, "/status", status_ac, TRUE, previous);
if (result) {
return result;
}
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status == JABBER_CONNECTED) {
// 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);
// 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 = autocomplete_param_with_func(unquoted, "/status get", roster_contact_autocomplete, previous, NULL);
if (result) {
free(unquoted);
return result;
}
}
free(unquoted);
}
return NULL;
}
static char*
_privacy_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* found = NULL;
found = autocomplete_param_with_ac(input, "/privacy", privacy_ac, TRUE, previous);
if (found) {
return found;
}
found = autocomplete_param_with_ac(input, "/privacy logging", privacy_log_ac, TRUE, previous);
if (found) {
return found;
}
found = autocomplete_param_with_func(input, "/privacy os", prefs_autocomplete_boolean_choice, previous, NULL);
if (found) {
return found;
}
return found;
}
static char*
_logging_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;
result = autocomplete_param_with_ac(input, "/logging", logging_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/logging group", logging_group_ac, TRUE, previous);
return result;
}
static char*
_color_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;
result = autocomplete_param_with_func(input, "/color own", prefs_autocomplete_boolean_choice, previous, NULL);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/color", color_ac, TRUE, previous);
return result;
}
static char*
_avatar_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;
result = autocomplete_param_with_ac(input, "/avatar", avatar_ac, TRUE, previous);
if (result) {
return result;
}
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status == JABBER_CONNECTED) {
result = cmd_ac_complete_filepath(input, "/avatar set", previous);
if (result) {
return result;
}
result = autocomplete_param_with_func(input, "/avatar get", roster_barejid_autocomplete, previous, NULL);
if (result) {
return result;
}
result = autocomplete_param_with_func(input, "/avatar open", roster_barejid_autocomplete, previous, NULL);
if (result) {
return result;
}
}
return NULL;
}
static char*
_correction_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = autocomplete_param_with_ac(input, "/correction", correction_ac, TRUE, previous);
return result;
}
static gchar*
_correct_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
gchar* result = g_strdup_printf("/correct %s", win_get_last_sent_message(window));
return result;
}
static char*
_software_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;
if (window->type == WIN_CHAT) {
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);
} else 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(input, "/software", nick_ac, TRUE, previous);
if (result) {
return result;
}
}
} else {
result = autocomplete_param_with_func(input, "/software", roster_fulljid_autocomplete, previous, NULL);
if (result) {
return result;
}
}
return result;
}
static char*
_url_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;
result = autocomplete_param_with_ac(input, "/url", url_ac, TRUE, previous);
if (result) {
return result;
}
if (window->type == WIN_CHAT || window->type == WIN_MUC || window->type == WIN_PRIVATE) {
result = autocomplete_param_with_func(input, "/url open", wins_get_url, previous, window);
if (result) {
return result;
}
gboolean arg_result;
auto_gcharv gchar** args = parse_args(input, 1, 8, &arg_result);
gboolean space_at_end = g_str_has_suffix(input, " ");
int num_args = g_strv_length(args);
if (arg_result) {
if ((num_args == 1 && space_at_end) || (num_args == 2 && !space_at_end)) {
result = autocomplete_param_with_func(input, "/url save", wins_get_url, previous, window);
} else if ((num_args == 2 && space_at_end) || (num_args == 3 && !space_at_end)) {
auto_gchar gchar* cmd = g_strdup_printf("/url save %s", args[1]);
result = cmd_ac_complete_filepath(input, cmd, previous);
}
}
}
return result;
}
static char*
_executable_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;
result = autocomplete_param_with_ac(input, "/executable avatar", executable_param_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/executable urlopen", executable_param_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/executable urlsave", executable_param_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/executable vcard_photo", executable_param_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/executable editor", executable_param_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/executable", executable_ac, TRUE, previous);
return result;
}
static char*
_autoping_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;
result = autocomplete_param_with_ac(input, "/autoping", autoping_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_func(input, "/autoping warning", prefs_autocomplete_boolean_choice, previous, NULL);
return result;
}
static char*
_lastactivity_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;
result = autocomplete_param_with_ac(input, "/lastactivity", lastactivity_ac, TRUE, previous);
if (result) {
return result;
}
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status == JABBER_CONNECTED) {
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 get", roster_barejid_autocomplete, previous, NULL);
}
return result;
}
static char*
_intype_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;
result = autocomplete_param_with_func(input, "/intype console", prefs_autocomplete_boolean_choice, previous, NULL);
if (result) {
return result;
}
result = autocomplete_param_with_func(input, "/intype titlebar", prefs_autocomplete_boolean_choice, previous, NULL);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/intype", intype_ac, FALSE, previous);
return result;
}
static char*
_mood_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;
result = autocomplete_param_with_ac(input, "/mood", mood_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/mood set", mood_type_ac, FALSE, previous);
if (result) {
return result;
}
return result;
}
static char*
_strophe_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;
result = autocomplete_param_with_ac(input, "/strophe sm", strophe_sm_ac, FALSE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/strophe verbosity", strophe_verbosity_ac, FALSE, previous);
if (result) {
return result;
}
return autocomplete_param_with_ac(input, "/strophe", strophe_ac, FALSE, previous);
}
static char*
_stamp_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;
result = autocomplete_param_with_ac(input, "/stamp unset", stamp_unset_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/stamp", stamp_ac, TRUE, previous);
return result;
}
static char*
_adhoc_cmd_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;
result = autocomplete_param_with_ac(input, "/cmd", adhoc_cmd_ac, TRUE, previous);
return result;
}
static char*
_vcard_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;
gboolean parse_result = FALSE;
auto_gcharv gchar** args = parse_args(input, 0, 7, &parse_result);
if (parse_result && (g_strcmp0(args[0], "set") == 0)) {
gboolean space_at_end = g_str_has_suffix(input, " ");
int num_args = g_strv_length(args);
gboolean is_num = TRUE;
if (num_args >= 2) {
for (size_t i = 0; i < strlen(args[1]); i++) {
if (!isdigit((int)args[1][i])) {
is_num = FALSE;
break;
}
}
}
if ((num_args == 2 && space_at_end && is_num) || (num_args == 3 && !space_at_end && is_num)) {
GString* beginning = g_string_new("/vcard");
g_string_append_printf(beginning, " %s %s", args[0], args[1]);
result = autocomplete_param_with_ac(input, beginning->str, vcard_set_param_ac, TRUE, previous);
g_string_free(beginning, TRUE);
if (result) {
return result;
}
} else if ((num_args == 3 && space_at_end && is_num && (g_strcmp0(args[2], "type") == 0)) || (num_args == 4 && !space_at_end && is_num && (g_strcmp0(args[2], "type") == 0))) {
GString* beginning = g_string_new("/vcard");
g_string_append_printf(beginning, " %s %s %s", args[0], args[1], args[2]);
result = autocomplete_param_with_ac(input, beginning->str, vcard_address_type_ac, TRUE, previous);
g_string_free(beginning, TRUE);
if (result) {
return result;
}
} else if ((num_args == 3 && space_at_end && is_num && autocomplete_contains(vcard_togglable_param_ac, args[2])) || (num_args == 4 && !space_at_end && is_num && autocomplete_contains(vcard_togglable_param_ac, args[2]))) {
GString* beginning = g_string_new("/vcard");
g_string_append_printf(beginning, " %s %s %s", args[0], args[1], args[2]);
result = autocomplete_param_with_func(input, beginning->str, prefs_autocomplete_boolean_choice, previous, NULL);
g_string_free(beginning, TRUE);
if (result) {
return result;
}
} else {
result = autocomplete_param_with_ac(input, "/vcard set name", vcard_name_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/vcard set", vcard_set_ac, TRUE, previous);
if (result) {
return result;
}
}
}
result = autocomplete_param_with_ac(input, "/vcard add", vcard_element_ac, TRUE, previous);
if (result) {
return result;
}
if (window->type == WIN_MUC) {
char* unquoted = strip_arg_quotes(input);
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, "/vcard get", nick_ac, TRUE, previous);
if (result) {
free(unquoted);
return result;
}
result = autocomplete_param_with_ac(unquoted, "/vcard photo open", nick_ac, TRUE, previous);
if (result) {
free(unquoted);
return result;
}
result = autocomplete_param_with_ac(unquoted, "/vcard photo save", nick_ac, TRUE, previous);
if (result) {
free(unquoted);
return result;
}
}
free(unquoted);
} else {
char* unquoted = strip_arg_quotes(input);
result = autocomplete_param_with_func(unquoted, "/vcard get", roster_contact_autocomplete, previous, NULL);
if (result) {
free(unquoted);
return result;
}
result = autocomplete_param_with_func(unquoted, "/vcard photo open", roster_contact_autocomplete, previous, NULL);
if (result) {
free(unquoted);
return result;
}
result = autocomplete_param_with_func(unquoted, "/vcard photo save", roster_contact_autocomplete, previous, NULL);
if (result) {
free(unquoted);
return result;
}
free(unquoted);
}
result = autocomplete_param_with_ac(input, "/vcard photo", vcard_photo_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/vcard", vcard_ac, TRUE, previous);
if (result) {
return result;
}
return result;
}
static char*
_force_encryption_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;
result = autocomplete_param_with_ac(input, "/force-encryption policy", force_encryption_policy_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/force-encryption", force_encryption_ac, TRUE, previous);
return result;
}
/* Forward declaration */
static char* _ai_provider_and_model_autocomplete(ProfWin* window, const char* const input,
gboolean previous, const char* cmd);
static char*
_ai_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;
/* Parse once for reuse - /ai <subcommand> [<arg1>] [<arg2>] */
gboolean parse_result = FALSE;
auto_gcharv gchar** args = parse_args(input, 1, 4, &parse_result);
int num_args = g_strv_length(args);
/* Top-level /ai <subcommand> autocomplete (e.g., /ai s<tab> -> /ai set) */
result = autocomplete_param_with_func(input, "/ai set provider", ai_providers_find, previous, NULL);
if (result) {
return result;
}
// /ai set token <provider> <token> - autocomplete provider names
result = autocomplete_param_with_func(input, "/ai set token", ai_providers_find, previous, NULL);
if (result) {
return result;
}
// /ai set default-model <provider> <model> - autocomplete provider names
result = autocomplete_param_with_func(input, "/ai set default-model", ai_providers_find, previous, NULL);
if (result) {
return result;
}
// /ai set custom <provider> <setting> <value> - autocomplete provider names
result = autocomplete_param_with_func(input, "/ai set custom", ai_providers_find, previous, NULL);
if (result) {
return result;
}
// /ai set custom <provider> <setting> - autocomplete settings
/* args[0]="set", args[1]="custom", args[2]=provider (if typed), args[3]=setting (if typed) */
if (num_args == 3 && g_strcmp0(args[1], "custom") == 0) {
/* /ai set custom <provider> - check if provider is valid */
if (ai_get_provider(args[2])) {
/* Valid provider, try settings autocomplete */
result = autocomplete_param_with_ac(input, "/ai set custom ", ai_set_custom_subcommands_ac, TRUE, previous);
if (result) {
return result;
}
}
}
// /ai set <subcommand> - autocomplete subcommands
result = autocomplete_param_with_ac(input, "/ai set", ai_set_subcommands_ac, TRUE, previous);
if (result) {
return result;
}
// /ai remove provider <name> - autocomplete provider names
result = autocomplete_param_with_func(input, "/ai remove provider", ai_providers_find, previous, NULL);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/ai remove", ai_remove_subcommands_ac, TRUE, previous);
if (result) {
return result;
}
// /ai start <provider> <model> - autocomplete provider names and model names
result = _ai_provider_and_model_autocomplete(window, input, previous, "/ai start");
if (result) {
return result;
}
// /ai switch <provider> <model> - autocomplete provider names and model names
result = _ai_provider_and_model_autocomplete(window, input, previous, "/ai switch");
if (result) {
return result;
}
// /ai set default-model <provider> <model> - autocomplete provider names and model names
result = _ai_provider_and_model_autocomplete(window, input, previous, "/ai set default-model");
if (result) {
return result;
}
// /ai models <provider> - autocomplete provider names
result = autocomplete_param_with_func(input, "/ai models", ai_providers_find, previous, NULL);
if (result) {
return result;
}
// /ai clear - no autocomplete
// /ai providers - no autocomplete
result = autocomplete_param_with_ac(input, "/ai", ai_subcommands_ac, FALSE, previous);
return result;
}
/**
* Autocomplete provider names and model names for /ai <cmd> <provider> <model> patterns.
* First tries to autocomplete provider names, then model names if provider is valid.
* Uses static ai_models_ac to preserve cycling state (last_found) across calls.
* The cmd_prefix should NOT include trailing space (e.g., "/ai start" not "/ai start ").
*/
static char*
_ai_provider_and_model_autocomplete(ProfWin* window, const char* const input, gboolean previous, const char* cmd)
{
char* result;
/* First, try provider name autocomplete */
result = autocomplete_param_with_func(input, cmd, ai_providers_find, previous, NULL);
if (result) {
return result;
}
/* Provider was specified, try model name autocomplete */
/* Build the full command prefix with space */
auto_gchar gchar* cmd_prefix = g_strdup_printf("%s ", cmd);
if (!g_str_has_prefix(input, cmd_prefix)) {
return NULL;
}
/* Extract provider name from input (after cmd_prefix) */
auto_gchar gchar* rest = g_strdup(input + strlen(cmd_prefix));
char* space = strchr(rest, ' ');
if (space) {
*space = '\0';
}
/* Look up the provider by name and get its models */
AIProvider* prov = ai_get_provider(rest);
if (!prov || !prov->models) {
return NULL;
}
if (!ai_models_ac) {
ai_models_ac = autocomplete_new();
}
/* Convert GList* to char** for autocomplete_update */
int model_count = g_list_length(prov->models);
char** model_array = g_new0(char*, model_count + 1);
GList* curr = prov->models;
int i = 0;
while (curr) {
model_array[i++] = curr->data;
curr = g_list_next(curr);
}
autocomplete_update(ai_models_ac, model_array);
g_free(model_array);
auto_gchar gchar* full_prefix = g_strdup_printf("%s%s", cmd_prefix, rest);
result = autocomplete_param_with_ac(input, full_prefix, ai_models_ac, TRUE, previous);
return result;
}