about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--Makefile.am2
-rw-r--r--src/command/cmd_autocomplete.c2917
-rw-r--r--src/command/cmd_autocomplete.h57
-rw-r--r--src/command/command.c2864
-rw-r--r--src/command/command.h12
-rw-r--r--src/command/commands.c13
-rw-r--r--src/plugins/callbacks.c6
-rw-r--r--src/ui/core.c7
-rw-r--r--src/ui/inputwin.c6
-rw-r--r--tests/unittests/test_cmd_alias.c3
10 files changed, 3010 insertions, 2877 deletions
diff --git a/Makefile.am b/Makefile.am
index 52ae369f..a9f7837a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -32,6 +32,7 @@ core_sources = \
 	src/ui/xmlwin.c \
 	src/command/command.h src/command/command.c \
 	src/command/commands.h src/command/commands.c \
+	src/command/cmd_autocomplete.h src/command/cmd_autocomplete.c \
 	src/tools/parser.c \
 	src/tools/parser.h \
 	src/tools/http_upload.c \
@@ -69,6 +70,7 @@ unittest_sources = \
 	src/pgp/gpg.h \
 	src/command/command.h src/command/command.c \
 	src/command/commands.h src/command/commands.c \
+	src/command/cmd_autocomplete.h src/command/cmd_autocomplete.c \
 	src/tools/parser.c \
 	src/tools/parser.h \
 	src/tools/p_sha1.h src/tools/p_sha1.c \
diff --git a/src/command/cmd_autocomplete.c b/src/command/cmd_autocomplete.c
new file mode 100644
index 00000000..cce4855b
--- /dev/null
+++ b/src/command/cmd_autocomplete.c
@@ -0,0 +1,2917 @@
+/*
+ * cmd_autocomplete.c
+ *
+ * Copyright (C) 2012 - 2016 James Booth <boothj5@gmail.com>
+ *
+ * This file is part of Profanity.
+ *
+ * Profanity is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Profanity is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Profanity.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * In addition, as a special exception, the copyright holders give permission to
+ * link the code of portions of this program with the OpenSSL library under
+ * certain conditions as described in each individual source file, and
+ * distribute linked combinations including the two.
+ *
+ * You must obey the GNU General Public License in all respects for all of the
+ * code used other than OpenSSL. If you modify file(s) with this exception, you
+ * may extend this exception to your version of the file(s), but you are not
+ * obligated to do so. If you do not wish to do so, delete this exception
+ * statement from your version. If you delete this exception statement from all
+ * source files in the program, then also delete it here.
+ *
+ */
+
+#define _GNU_SOURCE 1
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <libgen.h>
+
+#include "common.h"
+#include "tools/parser.h"
+#include "ui/win_types.h"
+#include "command/commands.h"
+#include "config/preferences.h"
+#include "config/scripts.h"
+#include "muc.h"
+#include "xmpp/xmpp.h"
+#include "roster_list.h"
+#include "window_list.h"
+#include "plugins/plugins.h"
+#include "command/cmd_autocomplete.h"
+
+#ifdef HAVE_LIBGPGME
+#include "pgp/gpg.h"
+#endif
+
+static char* _sub_autocomplete(ProfWin *window, const char *const input);
+static char* _notify_autocomplete(ProfWin *window, const char *const input);
+static char* _theme_autocomplete(ProfWin *window, const char *const input);
+static char* _autoaway_autocomplete(ProfWin *window, const char *const input);
+static char* _autoconnect_autocomplete(ProfWin *window, const char *const input);
+static char* _account_autocomplete(ProfWin *window, const char *const input);
+static char* _who_autocomplete(ProfWin *window, const char *const input);
+static char* _roster_autocomplete(ProfWin *window, const char *const input);
+static char* _group_autocomplete(ProfWin *window, const char *const input);
+static char* _bookmark_autocomplete(ProfWin *window, const char *const input);
+static char* _otr_autocomplete(ProfWin *window, const char *const input);
+static char* _pgp_autocomplete(ProfWin *window, const char *const input);
+static char* _connect_autocomplete(ProfWin *window, const char *const input);
+static char* _statuses_autocomplete(ProfWin *window, const char *const input);
+static char* _alias_autocomplete(ProfWin *window, const char *const input);
+static char* _join_autocomplete(ProfWin *window, const char *const input);
+static char* _log_autocomplete(ProfWin *window, const char *const input);
+static char* _form_autocomplete(ProfWin *window, const char *const input);
+static char* _form_field_autocomplete(ProfWin *window, const char *const input);
+static char* _occupants_autocomplete(ProfWin *window, const char *const input);
+static char* _kick_autocomplete(ProfWin *window, const char *const input);
+static char* _ban_autocomplete(ProfWin *window, const char *const input);
+static char* _affiliation_autocomplete(ProfWin *window, const char *const input);
+static char* _role_autocomplete(ProfWin *window, const char *const input);
+static char* _resource_autocomplete(ProfWin *window, const char *const input);
+static char* _titlebar_autocomplete(ProfWin *window, const char *const input);
+static char* _inpblock_autocomplete(ProfWin *window, const char *const input);
+static char* _time_autocomplete(ProfWin *window, const char *const input);
+static char* _receipts_autocomplete(ProfWin *window, const char *const input);
+static char* _help_autocomplete(ProfWin *window, const char *const input);
+static char* _wins_autocomplete(ProfWin *window, const char *const input);
+static char* _tls_autocomplete(ProfWin *window, const char *const input);
+static char* _script_autocomplete(ProfWin *window, const char *const input);
+static char* _subject_autocomplete(ProfWin *window, const char *const input);
+static char* _console_autocomplete(ProfWin *window, const char *const input);
+static char* _win_autocomplete(ProfWin *window, const char *const input);
+static char* _close_autocomplete(ProfWin *window, const char *const input);
+static char* _plugins_autocomplete(ProfWin *window, const char *const input);
+static char* _sendfile_autocomplete(ProfWin *window, const char *const input);
+static char* _blocked_autocomplete(ProfWin *window, const char *const input);
+static char *_tray_autocomplete(ProfWin *window, const char *const input);
+
+static char* _script_autocomplete_func(const char *const prefix);
+
+static char* _cmd_ac_complete_params(ProfWin *window, const char *const input);
+
+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 autoaway_ac;
+static Autocomplete autoaway_mode_ac;
+static Autocomplete autoaway_presence_ac;
+static Autocomplete autoconnect_ac;
+static Autocomplete titlebar_ac;
+static Autocomplete theme_ac;
+static Autocomplete theme_load_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_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 otr_ac;
+static Autocomplete otr_log_ac;
+static Autocomplete otr_policy_ac;
+static Autocomplete connect_property_ac;
+static Autocomplete tls_property_ac;
+static Autocomplete statuses_ac;
+static Autocomplete statuses_setting_ac;
+static Autocomplete alias_ac;
+static Autocomplete aliases_ac;
+static Autocomplete join_property_ac;
+static Autocomplete room_ac;
+static Autocomplete affiliation_ac;
+static Autocomplete role_ac;
+static Autocomplete privilege_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 time_ac;
+static Autocomplete time_format_ac;
+static Autocomplete resource_ac;
+static Autocomplete inpblock_ac;
+static Autocomplete receipts_ac;
+static Autocomplete pgp_ac;
+static Autocomplete pgp_log_ac;
+static Autocomplete tls_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 sendfile_ac;
+static Autocomplete blocked_ac;
+static Autocomplete tray_ac;
+
+void
+cmd_ac_init(void)
+{
+    commands_ac = autocomplete_new();
+    aliases_ac = autocomplete_new();
+
+    help_ac = autocomplete_new();
+    autocomplete_add(help_ac, "commands");
+    autocomplete_add(help_ac, "navigation");
+
+    help_commands_ac = autocomplete_new();
+    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");
+
+    prefs_ac = autocomplete_new();
+    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");
+    autocomplete_add(prefs_ac, "otr");
+    autocomplete_add(prefs_ac, "pgp");
+
+    notify_ac = autocomplete_new();
+    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");
+
+    notify_chat_ac = autocomplete_new();
+    autocomplete_add(notify_chat_ac, "on");
+    autocomplete_add(notify_chat_ac, "off");
+    autocomplete_add(notify_chat_ac, "current");
+    autocomplete_add(notify_chat_ac, "text");
+
+    notify_room_ac = autocomplete_new();
+    autocomplete_add(notify_room_ac, "on");
+    autocomplete_add(notify_room_ac, "off");
+    autocomplete_add(notify_room_ac, "mention");
+    autocomplete_add(notify_room_ac, "current");
+    autocomplete_add(notify_room_ac, "text");
+    autocomplete_add(notify_room_ac, "trigger");
+
+    notify_typing_ac = autocomplete_new();
+    autocomplete_add(notify_typing_ac, "on");
+    autocomplete_add(notify_typing_ac, "off");
+    autocomplete_add(notify_typing_ac, "current");
+
+    notify_mention_ac = autocomplete_new();
+    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");
+
+    notify_trigger_ac = autocomplete_new();
+    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");
+
+    sub_ac = autocomplete_new();
+    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");
+
+    titlebar_ac = autocomplete_new();
+    autocomplete_add(titlebar_ac, "show");
+    autocomplete_add(titlebar_ac, "goodbye");
+
+    log_ac = autocomplete_new();
+    autocomplete_add(log_ac, "maxsize");
+    autocomplete_add(log_ac, "rotate");
+    autocomplete_add(log_ac, "shared");
+    autocomplete_add(log_ac, "where");
+
+    autoaway_ac = autocomplete_new();
+    autocomplete_add(autoaway_ac, "mode");
+    autocomplete_add(autoaway_ac, "time");
+    autocomplete_add(autoaway_ac, "message");
+    autocomplete_add(autoaway_ac, "check");
+
+    autoaway_mode_ac = autocomplete_new();
+    autocomplete_add(autoaway_mode_ac, "away");
+    autocomplete_add(autoaway_mode_ac, "idle");
+    autocomplete_add(autoaway_mode_ac, "off");
+
+    autoaway_presence_ac = autocomplete_new();
+    autocomplete_add(autoaway_presence_ac, "away");
+    autocomplete_add(autoaway_presence_ac, "xa");
+
+    autoconnect_ac = autocomplete_new();
+    autocomplete_add(autoconnect_ac, "set");
+    autocomplete_add(autoconnect_ac, "off");
+
+    theme_ac = autocomplete_new();
+    autocomplete_add(theme_ac, "load");
+    autocomplete_add(theme_ac, "list");
+    autocomplete_add(theme_ac, "colours");
+    autocomplete_add(theme_ac, "properties");
+
+    disco_ac = autocomplete_new();
+    autocomplete_add(disco_ac, "info");
+    autocomplete_add(disco_ac, "items");
+
+    account_ac = autocomplete_new();
+    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");
+
+    account_set_ac = autocomplete_new();
+    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, "tls");
+    autocomplete_add(account_set_ac, "theme");
+
+    account_clear_ac = autocomplete_new();
+    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, "theme");
+
+    account_default_ac = autocomplete_new();
+    autocomplete_add(account_default_ac, "set");
+    autocomplete_add(account_default_ac, "off");
+
+    account_status_ac = autocomplete_new();
+    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");
+
+    wins_ac = autocomplete_new();
+    autocomplete_add(wins_ac, "unread");
+    autocomplete_add(wins_ac, "prune");
+    autocomplete_add(wins_ac, "tidy");
+    autocomplete_add(wins_ac, "autotidy");
+    autocomplete_add(wins_ac, "swap");
+
+    roster_ac = autocomplete_new();
+    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, "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");
+
+    roster_private_ac = autocomplete_new();
+    autocomplete_add(roster_private_ac, "room");
+    autocomplete_add(roster_private_ac, "group");
+    autocomplete_add(roster_private_ac, "off");
+    autocomplete_add(roster_private_ac, "char");
+
+    roster_header_ac = autocomplete_new();
+    autocomplete_add(roster_header_ac, "char");
+
+    roster_contact_ac = autocomplete_new();
+    autocomplete_add(roster_contact_ac, "char");
+    autocomplete_add(roster_contact_ac, "indent");
+
+    roster_resource_ac = autocomplete_new();
+    autocomplete_add(roster_resource_ac, "char");
+    autocomplete_add(roster_resource_ac, "indent");
+    autocomplete_add(roster_resource_ac, "join");
+
+    roster_presence_ac = autocomplete_new();
+    autocomplete_add(roster_presence_ac, "indent");
+
+    roster_char_ac = autocomplete_new();
+    autocomplete_add(roster_char_ac, "none");
+
+    roster_show_ac = autocomplete_new();
+    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");
+
+    roster_by_ac = autocomplete_new();
+    autocomplete_add(roster_by_ac, "group");
+    autocomplete_add(roster_by_ac, "presence");
+    autocomplete_add(roster_by_ac, "none");
+
+    roster_count_ac = autocomplete_new();
+    autocomplete_add(roster_count_ac, "unread");
+    autocomplete_add(roster_count_ac, "items");
+    autocomplete_add(roster_count_ac, "off");
+    autocomplete_add(roster_count_ac, "zero");
+
+    roster_order_ac = autocomplete_new();
+    autocomplete_add(roster_order_ac, "name");
+    autocomplete_add(roster_order_ac, "presence");
+
+    roster_unread_ac = autocomplete_new();
+    autocomplete_add(roster_unread_ac, "before");
+    autocomplete_add(roster_unread_ac, "after");
+    autocomplete_add(roster_unread_ac, "off");
+
+    roster_room_ac = autocomplete_new();
+    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");
+
+    roster_room_by_ac = autocomplete_new();
+    autocomplete_add(roster_room_by_ac, "service");
+    autocomplete_add(roster_room_by_ac, "none");
+
+    roster_room_order_ac = autocomplete_new();
+    autocomplete_add(roster_room_order_ac, "name");
+    autocomplete_add(roster_room_order_ac, "unread");
+
+    roster_room_position_ac = autocomplete_new();
+    autocomplete_add(roster_room_position_ac, "first");
+    autocomplete_add(roster_room_position_ac, "last");
+
+    roster_remove_all_ac = autocomplete_new();
+    autocomplete_add(roster_remove_all_ac, "contacts");
+
+    group_ac = autocomplete_new();
+    autocomplete_add(group_ac, "show");
+    autocomplete_add(group_ac, "add");
+    autocomplete_add(group_ac, "remove");
+
+    theme_load_ac = NULL;
+    plugins_load_ac = NULL;
+
+    who_roster_ac = autocomplete_new();
+    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");
+
+    who_room_ac = autocomplete_new();
+    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");
+
+    bookmark_ac = autocomplete_new();
+    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");
+
+    bookmark_property_ac = autocomplete_new();
+    autocomplete_add(bookmark_property_ac, "nick");
+    autocomplete_add(bookmark_property_ac, "password");
+    autocomplete_add(bookmark_property_ac, "autojoin");
+
+    otr_ac = autocomplete_new();
+    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");
+
+    otr_log_ac = autocomplete_new();
+    autocomplete_add(otr_log_ac, "on");
+    autocomplete_add(otr_log_ac, "off");
+    autocomplete_add(otr_log_ac, "redact");
+
+    otr_policy_ac = autocomplete_new();
+    autocomplete_add(otr_policy_ac, "manual");
+    autocomplete_add(otr_policy_ac, "opportunistic");
+    autocomplete_add(otr_policy_ac, "always");
+
+    connect_property_ac = autocomplete_new();
+    autocomplete_add(connect_property_ac, "server");
+    autocomplete_add(connect_property_ac, "port");
+    autocomplete_add(connect_property_ac, "tls");
+
+    tls_property_ac = autocomplete_new();
+    autocomplete_add(tls_property_ac, "force");
+    autocomplete_add(tls_property_ac, "allow");
+    autocomplete_add(tls_property_ac, "disable");
+
+    join_property_ac = autocomplete_new();
+    autocomplete_add(join_property_ac, "nick");
+    autocomplete_add(join_property_ac, "password");
+
+    statuses_ac = autocomplete_new();
+    autocomplete_add(statuses_ac, "console");
+    autocomplete_add(statuses_ac, "chat");
+    autocomplete_add(statuses_ac, "muc");
+
+    statuses_setting_ac = autocomplete_new();
+    autocomplete_add(statuses_setting_ac, "all");
+    autocomplete_add(statuses_setting_ac, "online");
+    autocomplete_add(statuses_setting_ac, "none");
+
+    alias_ac = autocomplete_new();
+    autocomplete_add(alias_ac, "add");
+    autocomplete_add(alias_ac, "remove");
+    autocomplete_add(alias_ac, "list");
+
+    room_ac = autocomplete_new();
+    autocomplete_add(room_ac, "accept");
+    autocomplete_add(room_ac, "destroy");
+    autocomplete_add(room_ac, "config");
+
+    affiliation_ac = autocomplete_new();
+    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");
+
+    role_ac = autocomplete_new();
+    autocomplete_add(role_ac, "moderator");
+    autocomplete_add(role_ac, "participant");
+    autocomplete_add(role_ac, "visitor");
+    autocomplete_add(role_ac, "none");
+
+    privilege_cmd_ac = autocomplete_new();
+    autocomplete_add(privilege_cmd_ac, "list");
+    autocomplete_add(privilege_cmd_ac, "set");
+
+    subject_ac = autocomplete_new();
+    autocomplete_add(subject_ac, "set");
+    autocomplete_add(subject_ac, "edit");
+    autocomplete_add(subject_ac, "prepend");
+    autocomplete_add(subject_ac, "append");
+    autocomplete_add(subject_ac, "clear");
+
+    form_ac = autocomplete_new();
+    autocomplete_add(form_ac, "submit");
+    autocomplete_add(form_ac, "cancel");
+    autocomplete_add(form_ac, "show");
+    autocomplete_add(form_ac, "help");
+
+    form_field_multi_ac = autocomplete_new();
+    autocomplete_add(form_field_multi_ac, "add");
+    autocomplete_add(form_field_multi_ac, "remove");
+
+    occupants_ac = autocomplete_new();
+    autocomplete_add(occupants_ac, "show");
+    autocomplete_add(occupants_ac, "hide");
+    autocomplete_add(occupants_ac, "default");
+    autocomplete_add(occupants_ac, "size");
+
+    occupants_default_ac = autocomplete_new();
+    autocomplete_add(occupants_default_ac, "show");
+    autocomplete_add(occupants_default_ac, "hide");
+
+    occupants_show_ac = autocomplete_new();
+    autocomplete_add(occupants_show_ac, "jid");
+
+    time_ac = autocomplete_new();
+    autocomplete_add(time_ac, "console");
+    autocomplete_add(time_ac, "chat");
+    autocomplete_add(time_ac, "muc");
+    autocomplete_add(time_ac, "mucconfig");
+    autocomplete_add(time_ac, "private");
+    autocomplete_add(time_ac, "xml");
+    autocomplete_add(time_ac, "statusbar");
+    autocomplete_add(time_ac, "lastactivity");
+
+    time_format_ac = autocomplete_new();
+    autocomplete_add(time_format_ac, "set");
+    autocomplete_add(time_format_ac, "off");
+
+    resource_ac = autocomplete_new();
+    autocomplete_add(resource_ac, "set");
+    autocomplete_add(resource_ac, "off");
+    autocomplete_add(resource_ac, "title");
+    autocomplete_add(resource_ac, "message");
+
+    inpblock_ac = autocomplete_new();
+    autocomplete_add(inpblock_ac, "timeout");
+    autocomplete_add(inpblock_ac, "dynamic");
+
+    receipts_ac = autocomplete_new();
+    autocomplete_add(receipts_ac, "send");
+    autocomplete_add(receipts_ac, "request");
+
+    pgp_ac = autocomplete_new();
+    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");
+
+    pgp_log_ac = autocomplete_new();
+    autocomplete_add(pgp_log_ac, "on");
+    autocomplete_add(pgp_log_ac, "off");
+    autocomplete_add(pgp_log_ac, "redact");
+
+    tls_ac = autocomplete_new();
+    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(tls_ac, "show");
+
+    tls_certpath_ac = autocomplete_new();
+    autocomplete_add(tls_certpath_ac, "set");
+    autocomplete_add(tls_certpath_ac, "clear");
+
+    script_ac = autocomplete_new();
+    autocomplete_add(script_ac, "run");
+    autocomplete_add(script_ac, "list");
+    autocomplete_add(script_ac, "show");
+
+    script_show_ac = NULL;
+
+    console_ac = autocomplete_new();
+    autocomplete_add(console_ac, "chat");
+    autocomplete_add(console_ac, "muc");
+    autocomplete_add(console_ac, "private");
+
+    console_msg_ac = autocomplete_new();
+    autocomplete_add(console_msg_ac, "all");
+    autocomplete_add(console_msg_ac, "first");
+    autocomplete_add(console_msg_ac, "none");
+
+    autoping_ac = autocomplete_new();
+    autocomplete_add(autoping_ac, "set");
+    autocomplete_add(autoping_ac, "timeout");
+
+    plugins_ac = autocomplete_new();
+    autocomplete_add(plugins_ac, "load");
+
+    sendfile_ac = autocomplete_new();
+
+    blocked_ac = autocomplete_new();
+    autocomplete_add(blocked_ac, "add");
+    autocomplete_add(blocked_ac, "remove");
+
+    tray_ac = autocomplete_new();
+    autocomplete_add(tray_ac, "on");
+    autocomplete_add(tray_ac, "off");
+    autocomplete_add(tray_ac, "read");
+    autocomplete_add(tray_ac, "timer");
+}
+
+void
+cmd_ac_add(const char *const value)
+{
+    if (commands_ac) {
+        autocomplete_add(commands_ac, value);
+    }
+}
+
+void
+cmd_ac_add_help(const char *const value)
+{
+    if (help_ac) {
+        autocomplete_add(help_ac, value);
+    }
+}
+
+void
+cmd_ac_add_cmd(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) {
+        autocomplete_add(aliases_ac, value);
+    }
+}
+
+void
+cmd_ac_remove_alias_value(char *value)
+{
+    if (aliases_ac) {
+        autocomplete_remove(aliases_ac, value);
+    }
+}
+
+void
+cmd_ac_remove(const char *const value)
+{
+    if (commands_ac) {
+        autocomplete_remove(commands_ac, value);
+    }
+}
+
+gboolean
+cmd_ac_exists(char *cmd)
+{
+    if (commands_ac == NULL) {
+        return FALSE;
+    } else {
+        return autocomplete_contains(commands_ac, cmd);
+    }
+}
+
+void
+cmd_ac_add_form_fields(DataForm *form)
+{
+    if (form == NULL) {
+        return;
+    }
+
+    GSList *fields = autocomplete_create_list(form->tag_ac);
+    GSList *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_slist_next(curr_field);
+    }
+    g_slist_free_full(fields, free);
+}
+
+void
+cmd_ac_remove_form_fields(DataForm *form)
+{
+    if (form == NULL) {
+        return;
+    }
+
+    GSList *fields = autocomplete_create_list(form->tag_ac);
+    GSList *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_slist_next(curr_field);
+    }
+    g_slist_free_full(fields, free);
+}
+
+char*
+cmd_ac_complete(ProfWin *window, const char *const input)
+{
+    // autocomplete command
+    if ((strncmp(input, "/", 1) == 0) && (!str_contains(input, strlen(input), ' '))) {
+        char *found = NULL;
+        found = autocomplete_complete(commands_ac, input, TRUE);
+        if (found) {
+            return found;
+        }
+
+    // autocomplete parameters
+    } else {
+        char *found = _cmd_ac_complete_params(window, input);
+        if (found) {
+            return found;
+        }
+    }
+
+    return NULL;
+}
+
+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();
+    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
+    autocomplete_reset(help_ac);
+    autocomplete_reset(help_commands_ac);
+    autocomplete_reset(notify_ac);
+    autocomplete_reset(notify_chat_ac);
+    autocomplete_reset(notify_room_ac);
+    autocomplete_reset(notify_typing_ac);
+    autocomplete_reset(notify_mention_ac);
+    autocomplete_reset(notify_trigger_ac);
+    autocomplete_reset(sub_ac);
+    autocomplete_reset(sendfile_ac);
+
+    autocomplete_reset(who_room_ac);
+    autocomplete_reset(who_roster_ac);
+    autocomplete_reset(prefs_ac);
+    autocomplete_reset(log_ac);
+    autocomplete_reset(commands_ac);
+    autocomplete_reset(autoaway_ac);
+    autocomplete_reset(autoaway_mode_ac);
+    autocomplete_reset(autoaway_presence_ac);
+    autocomplete_reset(autoconnect_ac);
+    autocomplete_reset(theme_ac);
+    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;
+    }
+    autocomplete_reset(account_ac);
+    autocomplete_reset(account_set_ac);
+    autocomplete_reset(account_clear_ac);
+    autocomplete_reset(account_default_ac);
+    autocomplete_reset(account_status_ac);
+    autocomplete_reset(disco_ac);
+    autocomplete_reset(wins_ac);
+    autocomplete_reset(roster_ac);
+    autocomplete_reset(roster_header_ac);
+    autocomplete_reset(roster_contact_ac);
+    autocomplete_reset(roster_resource_ac);
+    autocomplete_reset(roster_presence_ac);
+    autocomplete_reset(roster_char_ac);
+    autocomplete_reset(roster_show_ac);
+    autocomplete_reset(roster_by_ac);
+    autocomplete_reset(roster_count_ac);
+    autocomplete_reset(roster_order_ac);
+    autocomplete_reset(roster_room_ac);
+    autocomplete_reset(roster_room_by_ac);
+    autocomplete_reset(roster_unread_ac);
+    autocomplete_reset(roster_room_position_ac);
+    autocomplete_reset(roster_room_order_ac);
+    autocomplete_reset(roster_remove_all_ac);
+    autocomplete_reset(roster_private_ac);
+    autocomplete_reset(group_ac);
+    autocomplete_reset(titlebar_ac);
+    autocomplete_reset(bookmark_ac);
+    autocomplete_reset(bookmark_property_ac);
+    autocomplete_reset(otr_ac);
+    autocomplete_reset(otr_log_ac);
+    autocomplete_reset(otr_policy_ac);
+    autocomplete_reset(connect_property_ac);
+    autocomplete_reset(tls_property_ac);
+    autocomplete_reset(statuses_ac);
+    autocomplete_reset(statuses_setting_ac);
+    autocomplete_reset(alias_ac);
+    autocomplete_reset(aliases_ac);
+    autocomplete_reset(join_property_ac);
+    autocomplete_reset(room_ac);
+    autocomplete_reset(affiliation_ac);
+    autocomplete_reset(role_ac);
+    autocomplete_reset(privilege_cmd_ac);
+    autocomplete_reset(subject_ac);
+    autocomplete_reset(form_ac);
+    autocomplete_reset(form_field_multi_ac);
+    autocomplete_reset(occupants_ac);
+    autocomplete_reset(occupants_default_ac);
+    autocomplete_reset(occupants_show_ac);
+    autocomplete_reset(time_ac);
+    autocomplete_reset(time_format_ac);
+    autocomplete_reset(resource_ac);
+    autocomplete_reset(inpblock_ac);
+    autocomplete_reset(receipts_ac);
+    autocomplete_reset(pgp_ac);
+    autocomplete_reset(pgp_log_ac);
+    autocomplete_reset(tls_ac);
+    autocomplete_reset(tls_certpath_ac);
+    autocomplete_reset(console_ac);
+    autocomplete_reset(console_msg_ac);
+    autocomplete_reset(autoping_ac);
+    autocomplete_reset(plugins_ac);
+    autocomplete_reset(blocked_ac);
+    autocomplete_reset(tray_ac);
+    autocomplete_reset(script_ac);
+    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_MUC_CONFIG) {
+        ProfMucConfWin *confwin = (ProfMucConfWin*)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();
+}
+
+void
+cmd_ac_uninit(void)
+{
+    autocomplete_free(commands_ac);
+    autocomplete_free(who_room_ac);
+    autocomplete_free(who_roster_ac);
+    autocomplete_free(help_ac);
+    autocomplete_free(help_commands_ac);
+    autocomplete_free(notify_ac);
+    autocomplete_free(notify_chat_ac);
+    autocomplete_free(notify_room_ac);
+    autocomplete_free(notify_typing_ac);
+    autocomplete_free(notify_mention_ac);
+    autocomplete_free(notify_trigger_ac);
+    autocomplete_free(sub_ac);
+    autocomplete_free(titlebar_ac);
+    autocomplete_free(log_ac);
+    autocomplete_free(prefs_ac);
+    autocomplete_free(autoaway_ac);
+    autocomplete_free(autoaway_mode_ac);
+    autocomplete_free(autoaway_presence_ac);
+    autocomplete_free(autoconnect_ac);
+    autocomplete_free(theme_ac);
+    autocomplete_free(theme_load_ac);
+    autocomplete_free(account_ac);
+    autocomplete_free(account_set_ac);
+    autocomplete_free(account_clear_ac);
+    autocomplete_free(account_default_ac);
+    autocomplete_free(account_status_ac);
+    autocomplete_free(disco_ac);
+    autocomplete_free(wins_ac);
+    autocomplete_free(roster_ac);
+    autocomplete_free(roster_header_ac);
+    autocomplete_free(roster_contact_ac);
+    autocomplete_free(roster_resource_ac);
+    autocomplete_free(roster_presence_ac);
+    autocomplete_free(roster_char_ac);
+    autocomplete_free(roster_show_ac);
+    autocomplete_free(roster_by_ac);
+    autocomplete_free(roster_count_ac);
+    autocomplete_free(roster_order_ac);
+    autocomplete_free(roster_room_ac);
+    autocomplete_free(roster_room_by_ac);
+    autocomplete_free(roster_unread_ac);
+    autocomplete_free(roster_room_position_ac);
+    autocomplete_free(roster_room_order_ac);
+    autocomplete_free(roster_remove_all_ac);
+    autocomplete_free(roster_private_ac);
+    autocomplete_free(group_ac);
+    autocomplete_free(bookmark_ac);
+    autocomplete_free(bookmark_property_ac);
+    autocomplete_free(otr_ac);
+    autocomplete_free(otr_log_ac);
+    autocomplete_free(otr_policy_ac);
+    autocomplete_free(connect_property_ac);
+    autocomplete_free(tls_property_ac);
+    autocomplete_free(statuses_ac);
+    autocomplete_free(statuses_setting_ac);
+    autocomplete_free(alias_ac);
+    autocomplete_free(aliases_ac);
+    autocomplete_free(join_property_ac);
+    autocomplete_free(room_ac);
+    autocomplete_free(affiliation_ac);
+    autocomplete_free(role_ac);
+    autocomplete_free(privilege_cmd_ac);
+    autocomplete_free(subject_ac);
+    autocomplete_free(form_ac);
+    autocomplete_free(form_field_multi_ac);
+    autocomplete_free(occupants_ac);
+    autocomplete_free(occupants_default_ac);
+    autocomplete_free(occupants_show_ac);
+    autocomplete_free(time_ac);
+    autocomplete_free(time_format_ac);
+    autocomplete_free(resource_ac);
+    autocomplete_free(inpblock_ac);
+    autocomplete_free(receipts_ac);
+    autocomplete_free(pgp_ac);
+    autocomplete_free(pgp_log_ac);
+    autocomplete_free(tls_ac);
+    autocomplete_free(tls_certpath_ac);
+    autocomplete_free(script_ac);
+    autocomplete_free(script_show_ac);
+    autocomplete_free(console_ac);
+    autocomplete_free(console_msg_ac);
+    autocomplete_free(autoping_ac);
+    autocomplete_free(plugins_ac);
+    autocomplete_free(plugins_load_ac);
+    autocomplete_free(sendfile_ac);
+    autocomplete_free(blocked_ac);
+    autocomplete_free(tray_ac);
+}
+
+static char*
+_cmd_ac_complete_params(ProfWin *window, const char *const input)
+{
+    int i;
+    char *result = NULL;
+
+    jabber_conn_status_t conn_status = connection_get_status();
+
+    // autocomplete boolean settings
+    gchar *boolean_choices[] = { "/beep", "/intype", "/states", "/outtype", "/flash", "/splash", "/chlog", "/grlog",
+        "/history", "/vercheck", "/privileges", "/presence", "/wrap", "/winstidy", "/carbons", "/encwarn",
+        "/lastactivity" };
+
+    for (i = 0; i < ARRAY_SIZE(boolean_choices); i++) {
+        result = autocomplete_param_with_func(input, boolean_choices[i], prefs_autocomplete_boolean_choice);
+        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", "/status", "/software" } ;
+
+            // Remove quote character before and after names when doing autocomplete
+            char *unquoted = strip_arg_quotes(input);
+            for (i = 0; i < ARRAY_SIZE(nick_choices); i++) {
+                result = autocomplete_param_with_ac(unquoted, nick_choices[i], nick_ac, TRUE);
+                if (result) {
+                    free(unquoted);
+                    return result;
+                }
+            }
+            free(unquoted);
+        }
+
+    // otherwise autocomplete using roster
+    } else if (conn_status == JABBER_CONNECTED) {
+        gchar *contact_choices[] = { "/msg", "/info", "/status" };
+        // Remove quote character before and after names when doing autocomplete
+        char *unquoted = strip_arg_quotes(input);
+        for (i = 0; i < ARRAY_SIZE(contact_choices); i++) {
+            result = autocomplete_param_with_func(unquoted, contact_choices[i], roster_contact_autocomplete);
+            if (result) {
+                free(unquoted);
+                return result;
+            }
+        }
+        free(unquoted);
+
+        gchar *resource_choices[] = { "/caps", "/software", "/ping" };
+        for (i = 0; i < ARRAY_SIZE(resource_choices); i++) {
+            result = autocomplete_param_with_func(input, resource_choices[i], roster_fulljid_autocomplete);
+            if (result) {
+                return result;
+            }
+        }
+    }
+
+    if (conn_status == JABBER_CONNECTED) {
+        result = autocomplete_param_with_func(input, "/invite", roster_contact_autocomplete);
+        if (result) {
+            return result;
+        }
+    }
+
+    gchar *invite_choices[] = { "/decline", "/join" };
+    for (i = 0; i < ARRAY_SIZE(invite_choices); i++) {
+        result = autocomplete_param_with_func(input, invite_choices[i], muc_invites_find);
+        if (result) {
+            return result;
+        }
+    }
+
+    gchar *cmds[] = { "/prefs", "/disco", "/room", "/autoping" };
+    Autocomplete completers[] = { prefs_ac, disco_ac, room_ac, autoping_ac };
+
+    for (i = 0; i < ARRAY_SIZE(cmds); i++) {
+        result = autocomplete_param_with_ac(input, cmds[i], completers[i], TRUE);
+        if (result) {
+            return result;
+        }
+    }
+
+    GHashTable *ac_funcs = g_hash_table_new(g_str_hash, g_str_equal);
+    g_hash_table_insert(ac_funcs, "/help",          _help_autocomplete);
+    g_hash_table_insert(ac_funcs, "/who",           _who_autocomplete);
+    g_hash_table_insert(ac_funcs, "/sub",           _sub_autocomplete);
+    g_hash_table_insert(ac_funcs, "/notify",        _notify_autocomplete);
+    g_hash_table_insert(ac_funcs, "/autoaway",      _autoaway_autocomplete);
+    g_hash_table_insert(ac_funcs, "/theme",         _theme_autocomplete);
+    g_hash_table_insert(ac_funcs, "/log",           _log_autocomplete);
+    g_hash_table_insert(ac_funcs, "/account",       _account_autocomplete);
+    g_hash_table_insert(ac_funcs, "/roster",        _roster_autocomplete);
+    g_hash_table_insert(ac_funcs, "/group",         _group_autocomplete);
+    g_hash_table_insert(ac_funcs, "/bookmark",      _bookmark_autocomplete);
+    g_hash_table_insert(ac_funcs, "/autoconnect",   _autoconnect_autocomplete);
+    g_hash_table_insert(ac_funcs, "/otr",           _otr_autocomplete);
+    g_hash_table_insert(ac_funcs, "/pgp",           _pgp_autocomplete);
+    g_hash_table_insert(ac_funcs, "/connect",       _connect_autocomplete);
+    g_hash_table_insert(ac_funcs, "/statuses",      _statuses_autocomplete);
+    g_hash_table_insert(ac_funcs, "/alias",         _alias_autocomplete);
+    g_hash_table_insert(ac_funcs, "/join",          _join_autocomplete);
+    g_hash_table_insert(ac_funcs, "/form",          _form_autocomplete);
+    g_hash_table_insert(ac_funcs, "/occupants",     _occupants_autocomplete);
+    g_hash_table_insert(ac_funcs, "/kick",          _kick_autocomplete);
+    g_hash_table_insert(ac_funcs, "/ban",           _ban_autocomplete);
+    g_hash_table_insert(ac_funcs, "/affiliation",   _affiliation_autocomplete);
+    g_hash_table_insert(ac_funcs, "/role",          _role_autocomplete);
+    g_hash_table_insert(ac_funcs, "/resource",      _resource_autocomplete);
+    g_hash_table_insert(ac_funcs, "/titlebar",      _titlebar_autocomplete);
+    g_hash_table_insert(ac_funcs, "/inpblock",      _inpblock_autocomplete);
+    g_hash_table_insert(ac_funcs, "/time",          _time_autocomplete);
+    g_hash_table_insert(ac_funcs, "/receipts",      _receipts_autocomplete);
+    g_hash_table_insert(ac_funcs, "/wins",          _wins_autocomplete);
+    g_hash_table_insert(ac_funcs, "/tls",           _tls_autocomplete);
+    g_hash_table_insert(ac_funcs, "/script",        _script_autocomplete);
+    g_hash_table_insert(ac_funcs, "/subject",       _subject_autocomplete);
+    g_hash_table_insert(ac_funcs, "/console",       _console_autocomplete);
+    g_hash_table_insert(ac_funcs, "/win",           _win_autocomplete);
+    g_hash_table_insert(ac_funcs, "/close",         _close_autocomplete);
+    g_hash_table_insert(ac_funcs, "/plugins",       _plugins_autocomplete);
+    g_hash_table_insert(ac_funcs, "/sendfile",      _sendfile_autocomplete);
+    g_hash_table_insert(ac_funcs, "/blocked",       _blocked_autocomplete);
+    g_hash_table_insert(ac_funcs, "/tray",          _tray_autocomplete);
+
+    int len = strlen(input);
+    char parsed[len+1];
+    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) = g_hash_table_lookup(ac_funcs, parsed);
+    if (ac_func) {
+        result = ac_func(window, input);
+        if (result) {
+            g_hash_table_destroy(ac_funcs);
+            return result;
+        }
+    }
+    g_hash_table_destroy(ac_funcs);
+
+    result = plugins_autocomplete(input);
+    if (result) {
+        return result;
+    }
+
+    if (g_str_has_prefix(input, "/field")) {
+        result = _form_field_autocomplete(window, input);
+        if (result) {
+            return result;
+        }
+    }
+
+    return NULL;
+}
+
+static char*
+_sub_autocomplete(ProfWin *window, const char *const input)
+{
+    char *result = NULL;
+    result = autocomplete_param_with_func(input, "/sub allow", presence_sub_request_find);
+    if (result) {
+        return result;
+    }
+    result = autocomplete_param_with_func(input, "/sub deny", presence_sub_request_find);
+    if (result) {
+        return result;
+    }
+    result = autocomplete_param_with_ac(input, "/sub", sub_ac, TRUE);
+    if (result) {
+        return result;
+    }
+
+    return NULL;
+}
+
+static char*
+_tray_autocomplete(ProfWin *window, const char *const input)
+{
+    char *result = NULL;
+    result = autocomplete_param_with_func(input, "/tray read", prefs_autocomplete_boolean_choice);
+    if (result) {
+        return result;
+    }
+
+    result = autocomplete_param_with_ac(input, "/tray", tray_ac, FALSE);
+    if (result) {
+        return result;
+    }
+
+    return NULL;
+}
+
+static char*
+_who_autocomplete(ProfWin *window, const char *const input)
+{
+    char *result = NULL;
+
+    if (window->type == WIN_MUC) {
+        result = autocomplete_param_with_ac(input, "/who", who_room_ac, TRUE);
+        if (result) {
+            return result;
+        }
+    } else {
+        jabber_conn_status_t conn_status = connection_get_status();
+        if (conn_status == JABBER_CONNECTED) {
+            int i = 0;
+            gchar *group_commands[] = { "/who any", "/who online", "/who offline",
+                "/who chat", "/who away", "/who xa", "/who dnd", "/who available",
+                "/who unavailable" };
+
+            for (i = 0; i < ARRAY_SIZE(group_commands); i++) {
+                result = autocomplete_param_with_func(input, group_commands[i], roster_group_autocomplete);
+                if (result) {
+                    return result;
+                }
+            }
+        }
+
+        result = autocomplete_param_with_ac(input, "/who", who_roster_ac, TRUE);
+        if (result) {
+            return result;
+        }
+    }
+
+    return result;
+}
+
+static char*
+_roster_autocomplete(ProfWin *window, const char *const input)
+{
+    char *result = NULL;
+    result = autocomplete_param_with_ac(input, "/roster room private char", roster_char_ac, TRUE);
+    if (result) {
+        return result;
+    }
+    result = autocomplete_param_with_ac(input, "/roster room private", roster_header_ac, TRUE);
+    if (result) {
+        return result;
+    }
+    result = autocomplete_param_with_ac(input, "/roster header char", roster_char_ac, TRUE);
+    if (result) {
+        return result;
+    }
+    result = autocomplete_param_with_ac(input, "/roster contact char", roster_char_ac, TRUE);
+    if (result) {
+        return result;
+    }
+    result = autocomplete_param_with_ac(input, "/roster room char", roster_char_ac, TRUE);
+    if (result) {
+        return result;
+    }
+    result = autocomplete_param_with_ac(input, "/roster private char", roster_char_ac, TRUE);
+    if (result) {
+        return result;
+    }
+    result = autocomplete_param_with_ac(input, "/roster resource char", roster_char_ac, TRUE);
+    if (result) {
+        return result;
+    }
+    result = autocomplete_param_with_func(input, "/roster resource join", prefs_autocomplete_boolean_choice);
+    if (result) {
+        return result;
+    }
+    result = autocomplete_param_with_ac(input, "/roster room position", roster_room_position_ac, TRUE);
+    if (result) {
+        return result;
+    }
+    result = autocomplete_param_with_ac(input, "/roster room by", roster_room_by_ac, TRUE);
+    if (result) {
+        return result;
+    }
+    result = autocomplete_param_with_ac(input, "/roster room order", roster_room_order_ac, TRUE);
+    if (result) {
+        return result;
+    }
+    result = autocomplete_param_with_ac(input, "/roster room unread", roster_unread_ac, TRUE);
+    if (result) {
+        return result;
+    }
+    result = autocomplete_param_with_func(input, "/roster count zero", prefs_autocomplete_boolean_choice);
+    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);
+        if (result) {
+            return result;
+        }
+        result = autocomplete_param_with_func(input, "/roster clearnick", roster_barejid_autocomplete);
+        if (result) {
+            return result;
+        }
+        result = autocomplete_param_with_func(input, "/roster remove", roster_barejid_autocomplete);
+        if (result) {
+            return result;
+        }
+    }
+
+    result = autocomplete_param_with_ac(input, "/roster remove_all", roster_remove_all_ac, TRUE);
+    if (result) {
+        return result;
+    }
+    result = autocomplete_param_with_ac(input, "/roster show", roster_show_ac, TRUE);
+    if (result) {
+        return result;
+    }
+    result = autocomplete_param_with_ac(input, "/roster hide", roster_show_ac, TRUE);
+    if (result) {
+        return result;
+    }
+    result = autocomplete_param_with_ac(input, "/roster by", roster_by_ac, TRUE);
+    if (result) {
+        return result;
+    }
+    result = autocomplete_param_with_ac(input, "/roster count", roster_count_ac, TRUE);
+    if (result) {
+        return result;
+    }
+    result = autocomplete_param_with_ac(input, "/roster order", roster_order_ac, TRUE);
+    if (result) {
+        return result;
+    }
+    result = autocomplete_param_with_ac(input, "/roster unread", roster_unread_ac, TRUE);
+    if (result) {
+        return result;
+    }
+    result = autocomplete_param_with_ac(input, "/roster room", roster_room_ac, TRUE);
+    if (result) {
+        return result;
+    }
+    result = autocomplete_param_with_func(input, "/roster wrap", prefs_autocomplete_boolean_choice);
+    if (result) {
+        return result;
+    }
+    result = autocomplete_param_with_ac(input, "/roster header", roster_header_ac, TRUE);
+    if (result) {
+        return result;
+    }
+    result = autocomplete_param_with_ac(input, "/roster contact", roster_contact_ac, TRUE);
+    if (result) {
+        return result;
+    }
+    result = autocomplete_param_with_ac(input, "/roster resource", roster_resource_ac, TRUE);
+    if (result) {
+        return result;
+    }
+    result = autocomplete_param_with_ac(input, "/roster presence", roster_presence_ac, TRUE);
+    if (result) {
+        return result;
+    }
+    result = autocomplete_param_with_ac(input, "/roster private", roster_private_ac, TRUE);
+    if (result) {
+        return result;
+    }
+    result = autocomplete_param_with_ac(input, "/roster", roster_ac, TRUE);
+    if (result) {
+        return result;
+    }
+
+    return NULL;
+}
+
+static char*
+_group_autocomplete(ProfWin *window, const char *const input)
+{
+    char *result = NULL;
+
+    jabber_conn_status_t conn_status = connection_get_status();
+
+    if (conn_status == JABBER_CONNECTED) {
+        result = autocomplete_param_with_func(input, "/group show", roster_group_autocomplete);
+        if (result) {
+            return result;
+        }
+        result = autocomplete_param_no_with_func(input, "/group add", 4, roster_contact_autocomplete);
+        if (result) {
+            return result;
+        }
+        result = autocomplete_param_no_with_func(input, "/group remove", 4, roster_contact_autocomplete);
+        if (result) {
+            return result;
+        }
+        result = autocomplete_param_with_func(input, "/group add", roster_group_autocomplete);
+        if (result) {
+            return result;
+        }
+        result = autocomplete_param_with_func(input, "/group remove", roster_group_autocomplete);
+        if (result) {
+            return result;
+        }
+    }
+
+    result = autocomplete_param_with_ac(input, "/group", group_ac, TRUE);
+    if (result) {
+        return result;
+    }
+
+    return NULL;
+}
+
+static char*
+_blocked_autocomplete(ProfWin *window, const char *const input)
+{
+    char *result = NULL;
+
+    result = autocomplete_param_with_func(input, "/blocked remove", blocked_ac_find);
+    if (result) {
+        return result;
+    }
+
+    result = autocomplete_param_with_ac(input, "/blocked", blocked_ac, FALSE);
+    if (result) {
+        return result;
+    }
+
+    return NULL;
+}
+
+
+static char*
+_bookmark_autocomplete(ProfWin *window, const char *const input)
+{
+    char *found = NULL;
+
+    gboolean result;
+    gchar **args = parse_args(input, 3, 8, &result);
+    gboolean handle_options = result && (g_strv_length(args) > 2);
+
+    if (handle_options && ((strcmp(args[0], "add") == 0) || (strcmp(args[0], "update") == 0)) ) {
+        GString *beginning = g_string_new("/bookmark");
+        gboolean autojoin = FALSE;
+        int num_args = g_strv_length(args);
+
+        g_string_append(beginning, " ");
+        g_string_append(beginning, args[0]);
+        g_string_append(beginning, " ");
+        g_string_append(beginning, args[1]);
+        if (num_args == 4 && g_strcmp0(args[2], "autojoin") == 0) {
+            g_string_append(beginning, " ");
+            g_string_append(beginning, args[2]);
+            autojoin = TRUE;
+        }
+
+        if (num_args > 4) {
+            g_string_append(beginning, " ");
+            g_string_append(beginning, args[2]);
+            g_string_append(beginning, " ");
+            g_string_append(beginning, args[3]);
+            if (num_args == 6 && g_strcmp0(args[4], "autojoin") == 0) {
+                g_string_append(beginning, " ");
+                g_string_append(beginning, args[4]);
+                autojoin = TRUE;
+            }
+        }
+
+        if (num_args > 6) {
+            g_string_append(beginning, " ");
+            g_string_append(beginning, args[4]);
+            g_string_append(beginning, " ");
+            g_string_append(beginning, args[5]);
+            if (num_args == 8 && g_strcmp0(args[6], "autojoin") == 0) {
+                g_string_append(beginning, " ");
+                g_string_append(beginning, args[6]);
+                autojoin = TRUE;
+            }
+        }
+
+        if (autojoin) {
+            found = autocomplete_param_with_func(input, beginning->str, prefs_autocomplete_boolean_choice);
+        } else {
+            found = autocomplete_param_with_ac(input, beginning->str, bookmark_property_ac, TRUE);
+        }
+        g_string_free(beginning, TRUE);
+        if (found) {
+            g_strfreev(args);
+            return found;
+        }
+    }
+
+    g_strfreev(args);
+
+    found = autocomplete_param_with_func(input, "/bookmark remove", bookmark_find);
+    if (found) {
+        return found;
+    }
+    found = autocomplete_param_with_func(input, "/bookmark join", bookmark_find);
+    if (found) {
+        return found;
+    }
+    found = autocomplete_param_with_func(input, "/bookmark update", bookmark_find);
+    if (found) {
+        return found;
+    }
+
+    found = autocomplete_param_with_ac(input, "/bookmark", bookmark_ac, TRUE);
+    return found;
+}
+
+static char*
+_notify_autocomplete(ProfWin *window, const char *const input)
+{
+    int i = 0;
+    char *result = NULL;
+
+    result = autocomplete_param_with_func(input, "/notify room trigger remove", prefs_autocomplete_room_trigger);
+    if (result) {
+        return result;
+    }
+
+    gchar *boolean_choices1[] = { "/notify room current", "/notify chat current", "/notify typing current",
+        "/notify room text", "/notify chat text" };
+    for (i = 0; i < ARRAY_SIZE(boolean_choices1); i++) {
+        result = autocomplete_param_with_func(input, boolean_choices1[i], prefs_autocomplete_boolean_choice);
+        if (result) {
+            return result;
+        }
+    }
+
+    result = autocomplete_param_with_ac(input, "/notify room mention", notify_mention_ac, TRUE);
+    if (result) {
+        return result;
+    }
+
+    result = autocomplete_param_with_ac(input, "/notify room trigger", notify_trigger_ac, TRUE);
+    if (result) {
+        return result;
+    }
+
+    result = autocomplete_param_with_ac(input, "/notify room", notify_room_ac, TRUE);
+    if (result) {
+        return result;
+    }
+
+    result = autocomplete_param_with_ac(input, "/notify chat", notify_chat_ac, TRUE);
+    if (result) {
+        return result;
+    }
+
+    result = autocomplete_param_with_ac(input, "/notify typing", notify_typing_ac, TRUE);
+    if (result) {
+        return result;
+    }
+
+    gchar *boolean_choices2[] = { "/notify invite", "/notify sub", "/notify mention", "/notify trigger"};
+    for (i = 0; i < ARRAY_SIZE(boolean_choices2); i++) {
+        result = autocomplete_param_with_func(input, boolean_choices2[i], prefs_autocomplete_boolean_choice);
+        if (result) {
+            return result;
+        }
+    }
+
+    result = autocomplete_param_with_ac(input, "/notify", notify_ac, TRUE);
+    if (result) {
+        return result;
+    }
+
+    return NULL;
+}
+
+static char*
+_autoaway_autocomplete(ProfWin *window, const char *const input)
+{
+    char *result = NULL;
+
+    result = autocomplete_param_with_ac(input, "/autoaway mode", autoaway_mode_ac, TRUE);
+    if (result) {
+        return result;
+    }
+
+    result = autocomplete_param_with_ac(input, "/autoaway time", autoaway_presence_ac, TRUE);
+    if (result) {
+        return result;
+    }
+
+    result = autocomplete_param_with_ac(input, "/autoaway message", autoaway_presence_ac, TRUE);
+    if (result) {
+        return result;
+    }
+
+    result = autocomplete_param_with_func(input, "/autoaway check", prefs_autocomplete_boolean_choice);
+    if (result) {
+        return result;
+    }
+    result = autocomplete_param_with_ac(input, "/autoaway", autoaway_ac, TRUE);
+    if (result) {
+        return result;
+    }
+
+    return NULL;
+}
+
+static char*
+_log_autocomplete(ProfWin *window, const char *const input)
+{
+    char *result = NULL;
+
+    result = autocomplete_param_with_func(input, "/log rotate",
+        prefs_autocomplete_boolean_choice);
+    if (result) {
+        return result;
+    }
+    result = autocomplete_param_with_func(input, "/log shared",
+        prefs_autocomplete_boolean_choice);
+    if (result) {
+        return result;
+    }
+    result = autocomplete_param_with_ac(input, "/log", log_ac, TRUE);
+    if (result) {
+        return result;
+    }
+
+    return NULL;
+}
+
+static char*
+_autoconnect_autocomplete(ProfWin *window, const char *const input)
+{
+    char *result = NULL;
+
+    result = autocomplete_param_with_func(input, "/autoconnect set", accounts_find_enabled);
+    if (result) {
+        return result;
+    }
+
+    result = autocomplete_param_with_ac(input, "/autoconnect", autoconnect_ac, TRUE);
+    if (result) {
+        return result;
+    }
+
+    return NULL;
+}
+
+static char*
+_otr_autocomplete(ProfWin *window, const char *const input)
+{
+    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);
+        if (found) {
+            return found;
+        }
+    }
+
+    found = autocomplete_param_with_ac(input, "/otr log", otr_log_ac, TRUE);
+    if (found) {
+        return found;
+    }
+
+    // /otr policy always user@server.com
+    if (conn_status == JABBER_CONNECTED) {
+        gboolean result;
+        gchar **args = parse_args(input, 3, 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, " ");
+            g_string_append(beginning, args[1]);
+
+            found = autocomplete_param_with_func(input, beginning->str, roster_contact_autocomplete);
+            g_string_free(beginning, TRUE);
+            if (found) {
+                g_strfreev(args);
+                return found;
+            }
+        }
+        g_strfreev(args);
+    }
+
+    found = autocomplete_param_with_ac(input, "/otr policy", otr_policy_ac, TRUE);
+    if (found) {
+        return found;
+    }
+
+    found = autocomplete_param_with_ac(input, "/otr", otr_ac, TRUE);
+    if (found) {
+        return found;
+    }
+
+    return NULL;
+}
+
+static char*
+_pgp_autocomplete(ProfWin *window, const char *const input)
+{
+    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);
+        if (found) {
+            return found;
+        }
+    }
+
+    found = autocomplete_param_with_ac(input, "/pgp log", pgp_log_ac, TRUE);
+    if (found) {
+        return found;
+    }
+
+#ifdef HAVE_LIBGPGME
+    gboolean result;
+    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);
+        g_string_free(beginning, TRUE);
+        if (found) {
+            g_strfreev(args);
+            return found;
+        }
+    }
+    g_strfreev(args);
+#endif
+
+    if (conn_status == JABBER_CONNECTED) {
+        found = autocomplete_param_with_func(input, "/pgp setkey", roster_barejid_autocomplete);
+        if (found) {
+            return found;
+        }
+    }
+
+    found = autocomplete_param_with_ac(input, "/pgp", pgp_ac, TRUE);
+    if (found) {
+        return found;
+    }
+
+    return NULL;
+}
+
+static char*
+_plugins_autocomplete(ProfWin *window, const char *const input)
+{
+    char *result = NULL;
+    if ((strncmp(input, "/plugins load ", 14) == 0) && (strlen(input) > 14)) {
+        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);
+        if (result) {
+            return result;
+        }
+    }
+    result = autocomplete_param_with_ac(input, "/plugins", plugins_ac, TRUE);
+    if (result) {
+        return result;
+    }
+
+    return NULL;
+}
+
+static char*
+_theme_autocomplete(ProfWin *window, const char *const input)
+{
+    char *result = NULL;
+    if ((strncmp(input, "/theme load ", 12) == 0) && (strlen(input) > 12)) {
+        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);
+        if (result) {
+            return result;
+        }
+    }
+    result = autocomplete_param_with_ac(input, "/theme", theme_ac, TRUE);
+    if (result) {
+        return result;
+    }
+
+    return NULL;
+}
+
+static char*
+_script_autocomplete_func(const char *const prefix)
+{
+    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);
+}
+
+
+static char*
+_script_autocomplete(ProfWin *window, const char *const input)
+{
+    char *result = NULL;
+    if ((strncmp(input, "/script show ", 13) == 0) && (strlen(input) > 13)) {
+        result = autocomplete_param_with_func(input, "/script show", _script_autocomplete_func);
+        if (result) {
+            return result;
+        }
+    }
+
+    if ((strncmp(input, "/script run ", 12) == 0) && (strlen(input) > 12)) {
+        result = autocomplete_param_with_func(input, "/script run", _script_autocomplete_func);
+        if (result) {
+            return result;
+        }
+    }
+
+    result = autocomplete_param_with_ac(input, "/script", script_ac, TRUE);
+    if (result) {
+        return result;
+    }
+
+    return NULL;
+}
+
+static char*
+_resource_autocomplete(ProfWin *window, const char *const input)
+{
+    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);
+            if (found) {
+                return found;
+            }
+        }
+    }
+
+    found = autocomplete_param_with_func(input, "/resource title", prefs_autocomplete_boolean_choice);
+    if (found) {
+        return found;
+    }
+
+    found = autocomplete_param_with_func(input, "/resource message", prefs_autocomplete_boolean_choice);
+    if (found) {
+        return found;
+    }
+
+    found = autocomplete_param_with_ac(input, "/resource", resource_ac, FALSE);
+    if (found) {
+        return found;
+    }
+
+    return NULL;
+}
+
+static char*
+_titlebar_autocomplete(ProfWin *window, const char *const input)
+{
+    char *found = NULL;
+
+    found = autocomplete_param_with_func(input, "/titlebar show", prefs_autocomplete_boolean_choice);
+    if (found) {
+        return found;
+    }
+
+    found = autocomplete_param_with_func(input, "/titlebar goodbye", prefs_autocomplete_boolean_choice);
+    if (found) {
+        return found;
+    }
+
+    found = autocomplete_param_with_ac(input, "/titlebar", titlebar_ac, FALSE);
+    if (found) {
+        return found;
+    }
+
+    return NULL;
+}
+
+static char*
+_inpblock_autocomplete(ProfWin *window, const char *const input)
+{
+    char *found = NULL;
+
+    found = autocomplete_param_with_func(input, "/inpblock dynamic", prefs_autocomplete_boolean_choice);
+    if (found) {
+        return found;
+    }
+
+    found = autocomplete_param_with_ac(input, "/inpblock", inpblock_ac, FALSE);
+    if (found) {
+        return found;
+    }
+
+    return NULL;
+}
+
+static char*
+_form_autocomplete(ProfWin *window, const char *const input)
+{
+    if (window->type != WIN_MUC_CONFIG) {
+        return NULL;
+    }
+
+    char *found = NULL;
+
+    ProfMucConfWin *confwin = (ProfMucConfWin*)window;
+    DataForm *form = confwin->form;
+    if (form) {
+        found = autocomplete_param_with_ac(input, "/form help", form->tag_ac, TRUE);
+        if (found) {
+            return found;
+        }
+    }
+
+    found = autocomplete_param_with_ac(input, "/form", form_ac, TRUE);
+    if (found) {
+        return found;
+    }
+
+    return NULL;
+}
+
+static char*
+_form_field_autocomplete(ProfWin *window, const char *const input)
+{
+    if (window->type != WIN_MUC_CONFIG) {
+        return NULL;
+    }
+
+    char *found = NULL;
+
+    ProfMucConfWin *confwin = (ProfMucConfWin*)window;
+    DataForm *form = confwin->form;
+    if (form == NULL) {
+        return NULL;
+    }
+
+    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);
+
+            } else if ((g_strcmp0(split[1], "remove") == 0) && field_type == FIELD_TEXT_MULTI) {
+                found = autocomplete_param_with_ac(input, beginning->str, value_ac, TRUE);
+
+            } else if ((g_strcmp0(split[1], "remove") == 0) && field_type == FIELD_JID_MULTI) {
+                found = autocomplete_param_with_ac(input, beginning->str, value_ac, TRUE);
+            }
+
+            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);
+                    break;
+                case FIELD_LIST_SINGLE:
+                    found = autocomplete_param_with_ac(input, split[0], value_ac, TRUE);
+                    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);
+                    break;
+                default:
+                    break;
+            }
+        }
+    }
+
+    g_strfreev(split);
+
+    return found;
+}
+
+static char*
+_occupants_autocomplete(ProfWin *window, const char *const input)
+{
+    char *found = NULL;
+
+    found = autocomplete_param_with_ac(input, "/occupants default show", occupants_show_ac, TRUE);
+    if (found) {
+        return found;
+    }
+
+    found = autocomplete_param_with_ac(input, "/occupants default hide", occupants_show_ac, TRUE);
+    if (found) {
+        return found;
+    }
+
+    found = autocomplete_param_with_ac(input, "/occupants default", occupants_default_ac, TRUE);
+    if (found) {
+        return found;
+    }
+
+    found = autocomplete_param_with_ac(input, "/occupants show", occupants_show_ac, TRUE);
+    if (found) {
+        return found;
+    }
+
+    found = autocomplete_param_with_ac(input, "/occupants hide", occupants_show_ac, TRUE);
+    if (found) {
+        return found;
+    }
+
+    found = autocomplete_param_with_ac(input, "/occupants", occupants_ac, TRUE);
+    if (found) {
+        return found;
+    }
+
+    return NULL;
+}
+
+static char*
+_time_autocomplete(ProfWin *window, const char *const input)
+{
+    char *found = NULL;
+
+    found = autocomplete_param_with_ac(input, "/time statusbar", time_format_ac, TRUE);
+    if (found) {
+        return found;
+    }
+
+    found = autocomplete_param_with_ac(input, "/time lastactivity", time_format_ac, TRUE);
+    if (found) {
+        return found;
+    }
+
+    found = autocomplete_param_with_ac(input, "/time console", time_format_ac, TRUE);
+    if (found) {
+        return found;
+    }
+
+    found = autocomplete_param_with_ac(input, "/time chat", time_format_ac, TRUE);
+    if (found) {
+        return found;
+    }
+
+    found = autocomplete_param_with_ac(input, "/time muc", time_format_ac, TRUE);
+    if (found) {
+        return found;
+    }
+
+    found = autocomplete_param_with_ac(input, "/time mucconfig", time_format_ac, TRUE);
+    if (found) {
+        return found;
+    }
+
+    found = autocomplete_param_with_ac(input, "/time private", time_format_ac, TRUE);
+    if (found) {
+        return found;
+    }
+
+    found = autocomplete_param_with_ac(input, "/time xml", time_format_ac, TRUE);
+    if (found) {
+        return found;
+    }
+
+    found = autocomplete_param_with_ac(input, "/time", time_ac, TRUE);
+    if (found) {
+        return found;
+    }
+
+    return NULL;
+}
+
+static char*
+_kick_autocomplete(ProfWin *window, const char *const input)
+{
+    char *result = NULL;
+
+    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, "/kick", nick_ac, TRUE);
+            if (result) {
+                return result;
+            }
+        }
+    }
+
+    return result;
+}
+
+static char*
+_ban_autocomplete(ProfWin *window, const char *const input)
+{
+    char *result = NULL;
+
+    if (window->type == WIN_MUC) {
+        ProfMucWin *mucwin = (ProfMucWin*)window;
+        assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
+        Autocomplete jid_ac = muc_roster_jid_ac(mucwin->roomjid);
+
+        if (jid_ac) {
+            result = autocomplete_param_with_ac(input, "/ban", jid_ac, TRUE);
+            if (result) {
+                return result;
+            }
+        }
+    }
+
+    return result;
+}
+
+static char*
+_affiliation_autocomplete(ProfWin *window, const char *const input)
+{
+    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);
+
+        gchar **args = parse_args(input, 3, 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, " ");
+            g_string_append(beginning, args[1]);
+
+            result = autocomplete_param_with_ac(input, beginning->str, jid_ac, TRUE);
+            g_string_free(beginning, TRUE);
+            if (result) {
+                g_strfreev(args);
+                return result;
+            }
+        }
+
+        g_strfreev(args);
+    }
+
+    result = autocomplete_param_with_ac(input, "/affiliation set", affiliation_ac, TRUE);
+    if (result) {
+        return result;
+    }
+
+    result = autocomplete_param_with_ac(input, "/affiliation list", affiliation_ac, TRUE);
+    if (result) {
+        return result;
+    }
+
+    result = autocomplete_param_with_ac(input, "/affiliation", privilege_cmd_ac, TRUE);
+    if (result) {
+        return result;
+    }
+
+    return result;
+}
+
+static char*
+_role_autocomplete(ProfWin *window, const char *const input)
+{
+    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);
+
+        gchar **args = parse_args(input, 3, 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, " ");
+            g_string_append(beginning, args[1]);
+
+            result = autocomplete_param_with_ac(input, beginning->str, nick_ac, TRUE);
+            g_string_free(beginning, TRUE);
+            if (result) {
+                g_strfreev(args);
+                return result;
+            }
+        }
+
+        g_strfreev(args);
+    }
+
+    result = autocomplete_param_with_ac(input, "/role set", role_ac, TRUE);
+    if (result) {
+        return result;
+    }
+
+    result = autocomplete_param_with_ac(input, "/role list", role_ac, TRUE);
+    if (result) {
+        return result;
+    }
+
+    result = autocomplete_param_with_ac(input, "/role", privilege_cmd_ac, TRUE);
+    if (result) {
+        return result;
+    }
+
+    return result;
+}
+
+static char*
+_statuses_autocomplete(ProfWin *window, const char *const input)
+{
+    char *result = NULL;
+
+    result = autocomplete_param_with_ac(input, "/statuses console", statuses_setting_ac, TRUE);
+    if (result) {
+        return result;
+    }
+
+    result = autocomplete_param_with_ac(input, "/statuses chat", statuses_setting_ac, TRUE);
+    if (result) {
+        return result;
+    }
+
+    result = autocomplete_param_with_ac(input, "/statuses muc", statuses_setting_ac, TRUE);
+    if (result) {
+        return result;
+    }
+
+    result = autocomplete_param_with_ac(input, "/statuses", statuses_ac, TRUE);
+    if (result) {
+        return result;
+    }
+
+    return NULL;
+}
+
+static char*
+_wins_autocomplete(ProfWin *window, const char *const input)
+{
+    char *result = NULL;
+
+    result = autocomplete_param_with_func(input, "/wins autotidy", prefs_autocomplete_boolean_choice);
+    if (result) {
+        return result;
+    }
+
+    result = autocomplete_param_with_ac(input, "/wins", wins_ac, TRUE);
+    if (result) {
+        return result;
+    }
+
+    return NULL;
+}
+
+static char*
+_tls_autocomplete(ProfWin *window, const char *const input)
+{
+    char *result = NULL;
+
+    result = autocomplete_param_with_func(input, "/tls revoke", tlscerts_complete);
+    if (result) {
+        return result;
+    }
+
+    result = autocomplete_param_with_func(input, "/tls cert", tlscerts_complete);
+    if (result) {
+        return result;
+    }
+
+    result = autocomplete_param_with_ac(input, "/tls certpath", tls_certpath_ac, TRUE);
+    if (result) {
+        return result;
+    }
+
+    result = autocomplete_param_with_func(input, "/tls show", prefs_autocomplete_boolean_choice);
+    if (result) {
+        return result;
+    }
+
+    result = autocomplete_param_with_ac(input, "/tls", tls_ac, TRUE);
+    if (result) {
+        return result;
+    }
+
+    return result;
+}
+
+static char*
+_receipts_autocomplete(ProfWin *window, const char *const input)
+{
+    char *result = NULL;
+
+    result = autocomplete_param_with_func(input, "/receipts send", prefs_autocomplete_boolean_choice);
+    if (result) {
+        return result;
+    }
+
+    result = autocomplete_param_with_func(input, "/receipts request", prefs_autocomplete_boolean_choice);
+    if (result) {
+        return result;
+    }
+
+    result = autocomplete_param_with_ac(input, "/receipts", receipts_ac, TRUE);
+    if (result) {
+        return result;
+    }
+
+    return NULL;
+}
+
+static char*
+_alias_autocomplete(ProfWin *window, const char *const input)
+{
+    char *result = NULL;
+
+    result = autocomplete_param_with_ac(input, "/alias remove", aliases_ac, TRUE);
+    if (result) {
+        return result;
+    }
+
+    result = autocomplete_param_with_ac(input, "/alias", alias_ac, TRUE);
+    if (result) {
+        return result;
+    }
+
+    return NULL;
+}
+
+static char*
+_connect_autocomplete(ProfWin *window, const char *const input)
+{
+    char *found = NULL;
+    gboolean result = FALSE;
+
+    gchar **args = parse_args(input, 2, 6, &result);
+
+    if ((strncmp(input, "/connect", 8) == 0) && (result == TRUE)) {
+        GString *beginning = g_string_new("/connect ");
+        g_string_append(beginning, args[0]);
+        if (args[1] && args[2]) {
+            g_string_append(beginning, " ");
+            g_string_append(beginning, args[1]);
+            g_string_append(beginning, " ");
+            g_string_append(beginning, args[2]);
+            if (args[3] && args[4]) {
+                g_string_append(beginning, " ");
+                g_string_append(beginning, args[3]);
+                g_string_append(beginning, " ");
+                g_string_append(beginning, args[4]);
+            }
+        }
+        found = autocomplete_param_with_ac(input, beginning->str, connect_property_ac, TRUE);
+        g_string_free(beginning, TRUE);
+        if (found) {
+            g_strfreev(args);
+            return found;
+        }
+    }
+
+    g_strfreev(args);
+
+    result = FALSE;
+    args = parse_args(input, 2, 7, &result);
+
+    if ((strncmp(input, "/connect", 8) == 0) && (result == TRUE)) {
+        GString *beginning = g_string_new("/connect ");
+        g_string_append(beginning, args[0]);
+        int curr = 0;
+        if (args[1]) {
+            g_string_append(beginning, " ");
+            g_string_append(beginning, args[1]);
+            curr = 1;
+            if (args[2] && args[3]) {
+                g_string_append(beginning, " ");
+                g_string_append(beginning, args[2]);
+                g_string_append(beginning, " ");
+                g_string_append(beginning, args[3]);
+                curr = 3;
+                if (args[4] && args[5]) {
+                    g_string_append(beginning, " ");
+                    g_string_append(beginning, args[4]);
+                    g_string_append(beginning, " ");
+                    g_string_append(beginning, args[5]);
+                    curr = 5;
+                }
+            }
+        }
+        if (curr != 0 && (g_strcmp0(args[curr], "tls") == 0)) {
+            found = autocomplete_param_with_ac(input, beginning->str, tls_property_ac, TRUE);
+            g_string_free(beginning, TRUE);
+            if (found) {
+                g_strfreev(args);
+                return found;
+            }
+        } else {
+            g_string_free(beginning, TRUE);
+        }
+    }
+
+    g_strfreev(args);
+
+    found = autocomplete_param_with_func(input, "/connect", accounts_find_enabled);
+    if (found) {
+        return found;
+    }
+
+    return NULL;
+}
+
+static char*
+_help_autocomplete(ProfWin *window, const char *const input)
+{
+    char *result = NULL;
+
+    result = autocomplete_param_with_ac(input, "/help commands", help_commands_ac, TRUE);
+    if (result) {
+        return result;
+    }
+
+    result = autocomplete_param_with_ac(input, "/help", help_ac, TRUE);
+    if (result) {
+        return result;
+    }
+
+    return NULL;
+}
+
+static char*
+_join_autocomplete(ProfWin *window, const char *const input)
+{
+    char *found = NULL;
+    gboolean result = FALSE;
+
+    found = autocomplete_param_with_func(input, "/join", bookmark_find);
+    if (found) {
+        return found;
+    }
+
+    gchar **args = parse_args(input, 2, 4, &result);
+
+    if ((strncmp(input, "/join", 5) == 0) && (result == TRUE)) {
+        GString *beginning = g_string_new("/join ");
+        g_string_append(beginning, args[0]);
+        if (args[1] && args[2]) {
+            g_string_append(beginning, " ");
+            g_string_append(beginning, args[1]);
+            g_string_append(beginning, " ");
+            g_string_append(beginning, args[2]);
+        }
+        found = autocomplete_param_with_ac(input, beginning->str, join_property_ac, TRUE);
+        g_string_free(beginning, TRUE);
+        if (found) {
+            g_strfreev(args);
+            return found;
+        }
+    }
+
+    g_strfreev(args);
+
+    return NULL;
+}
+
+static char*
+_console_autocomplete(ProfWin *window, const char *const input)
+{
+    char *result = NULL;
+
+    result = autocomplete_param_with_ac(input, "/console chat", console_msg_ac, TRUE);
+    if (result) {
+        return result;
+    }
+    result = autocomplete_param_with_ac(input, "/console muc", console_msg_ac, TRUE);
+    if (result) {
+        return result;
+    }
+    result = autocomplete_param_with_ac(input, "/console private", console_msg_ac, TRUE);
+    if (result) {
+        return result;
+    }
+
+    result = autocomplete_param_with_ac(input, "/console", console_ac, TRUE);
+    if (result) {
+        return result;
+    }
+
+    return NULL;
+}
+
+static char*
+_win_autocomplete(ProfWin *window, const char *const input)
+{
+    char *found = NULL;
+
+    found = autocomplete_param_with_func(input, "/win", win_autocomplete);
+    if (found) {
+        return found;
+    }
+
+    return NULL;
+}
+
+static char*
+_close_autocomplete(ProfWin *window, const char *const input)
+{
+    char *found = NULL;
+
+    found = autocomplete_param_with_func(input, "/close", win_close_autocomplete);
+    if (found) {
+        return found;
+    }
+
+    return NULL;
+}
+
+static char*
+_sendfile_autocomplete(ProfWin *window, const char *const input)
+{
+    static char* last_directory = NULL;
+
+    unsigned int output_off = 0;
+
+    char *result = NULL;
+    char *tmp;
+
+    // strip command
+    char *inpcp = (char*)input + 9;
+    while (*inpcp == ' ') {
+        inpcp++;
+    }
+
+    inpcp = strdup(inpcp);
+
+    // strip quotes
+    if (*inpcp == '"') {
+        tmp = strchr(inpcp+1, '"');
+        if (tmp) {
+            *tmp = '\0';
+        }
+        tmp = strdup(inpcp+1);
+        free(inpcp);
+        inpcp = tmp;
+    }
+
+    // expand ~ to $HOME
+    if (inpcp[0] == '~' && inpcp[1] == '/') {
+        if (asprintf(&tmp, "%s/%sfoo", getenv("HOME"), inpcp+2) == -1) {
+            return NULL;
+        }
+        output_off = strlen(getenv("HOME"))+1;
+    } else {
+        if (asprintf(&tmp, "%sfoo", inpcp) == -1) {
+            return NULL;
+        }
+    }
+    free(inpcp);
+    inpcp = tmp;
+
+    char* inpcp2 = strdup(inpcp);
+    char* foofile = strdup(basename(inpcp2));
+    char* directory = strdup(dirname(inpcp));
+    free(inpcp);
+    free(inpcp2);
+
+    if (!last_directory || strcmp(last_directory, directory) != 0) {
+        free(last_directory);
+        last_directory = directory;
+        autocomplete_reset(sendfile_ac);
+
+        struct dirent *dir;
+
+        DIR *d = opendir(directory);
+        if (d) {
+            while ((dir = readdir(d)) != NULL) {
+                if (strcmp(dir->d_name, ".") == 0) {
+                    continue;
+                } else if (strcmp(dir->d_name, "..") == 0) {
+                    continue;
+                } else if (*(dir->d_name) == '.' && *foofile != '.') {
+                    // only show hidden files on explicit request
+                    continue;
+                }
+                char * acstring;
+                if (output_off) {
+                    if (asprintf(&tmp, "%s/%s", directory, dir->d_name) == -1) {
+                        return NULL;
+                    }
+                    if (asprintf(&acstring, "~/%s", tmp+output_off) == -1) {
+                        return NULL;
+                    }
+                    free(tmp);
+                } else if (strcmp(directory, "/") == 0) {
+                    if (asprintf(&acstring, "/%s", dir->d_name) == -1) {
+                        return NULL;
+                    }
+                } else {
+                    if (asprintf(&acstring, "%s/%s", directory, dir->d_name) == -1) {
+                        return NULL;
+                    }
+                }
+                autocomplete_add(sendfile_ac, acstring);
+                free(acstring);
+            }
+            closedir(d);
+        }
+    } else {
+        free(foofile);
+        free(directory);
+    }
+
+    result = autocomplete_param_with_ac(input, "/sendfile", sendfile_ac, TRUE);
+    if (result) {
+        return result;
+    }
+
+    return NULL;
+}
+
+
+static char*
+_subject_autocomplete(ProfWin *window, const char *const input)
+{
+    char *result = NULL;
+
+    if (window->type == WIN_MUC) {
+        if ((g_strcmp0(input, "/subject e") == 0)
+                || (g_strcmp0(input, "/subject ed") == 0)
+                || (g_strcmp0(input, "/subject edi") == 0)
+                || (g_strcmp0(input, "/subject edit") == 0)
+                || (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) {
+                GString *result_str = g_string_new("/subject edit \"");
+                g_string_append(result_str, subject);
+                g_string_append(result_str, "\"");
+
+                result = result_str->str;
+                g_string_free(result_str, FALSE);
+            }
+        }
+    }
+    if (result) {
+        return result;
+    }
+
+    result = autocomplete_param_with_ac(input, "/subject", subject_ac, TRUE);
+    if (result) {
+        return result;
+    }
+
+    return NULL;
+}
+
+static char*
+_account_autocomplete(ProfWin *window, const char *const input)
+{
+    char *found = NULL;
+    gboolean result = FALSE;
+
+    gchar **args = parse_args(input, 3, 4, &result);
+
+    if ((strncmp(input, "/account set", 12) == 0) && (result == TRUE)) {
+        GString *beginning = g_string_new("/account set ");
+        g_string_append(beginning, args[1]);
+        if ((g_strv_length(args) > 3) && (g_strcmp0(args[2], "otr")) == 0) {
+            g_string_append(beginning, " ");
+            g_string_append(beginning, args[2]);
+            found = autocomplete_param_with_ac(input, beginning->str, otr_policy_ac, TRUE);
+            g_string_free(beginning, TRUE);
+            if (found) {
+                g_strfreev(args);
+                return found;
+            }
+        } else if ((g_strv_length(args) > 3) && (g_strcmp0(args[2], "status")) == 0) {
+            g_string_append(beginning, " ");
+            g_string_append(beginning, args[2]);
+            found = autocomplete_param_with_ac(input, beginning->str, account_status_ac, TRUE);
+            g_string_free(beginning, TRUE);
+            if (found) {
+                g_strfreev(args);
+                return found;
+            }
+        } else if ((g_strv_length(args) > 3) && (g_strcmp0(args[2], "tls")) == 0) {
+            g_string_append(beginning, " ");
+            g_string_append(beginning, args[2]);
+            found = autocomplete_param_with_ac(input, beginning->str, tls_property_ac, TRUE);
+            g_string_free(beginning, TRUE);
+            if (found) {
+                g_strfreev(args);
+                return found;
+            }
+        } else if ((g_strv_length(args) > 3) && (g_strcmp0(args[2], "startscript")) == 0) {
+            g_string_append(beginning, " ");
+            g_string_append(beginning, args[2]);
+            found = autocomplete_param_with_func(input, beginning->str, _script_autocomplete_func);
+            g_string_free(beginning, TRUE);
+            if (found) {
+                g_strfreev(args);
+                return found;
+            }
+        } else if ((g_strv_length(args) > 3) && (g_strcmp0(args[2], "theme")) == 0) {
+            g_string_append(beginning, " ");
+            g_string_append(beginning, 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);
+            g_string_free(beginning, TRUE);
+            if (found) {
+                return found;
+            }
+#ifdef HAVE_LIBGPGME
+        } else if ((g_strv_length(args) > 3) && (g_strcmp0(args[2], "pgpkeyid")) == 0) {
+            g_string_append(beginning, " ");
+            g_string_append(beginning, args[2]);
+            found = autocomplete_param_with_func(input, beginning->str, p_gpg_autocomplete_key);
+            g_string_free(beginning, TRUE);
+            if (found) {
+                g_strfreev(args);
+                return found;
+            }
+#endif
+        } else {
+            found = autocomplete_param_with_ac(input, beginning->str, account_set_ac, TRUE);
+            g_string_free(beginning, TRUE);
+            if (found) {
+                g_strfreev(args);
+                return found;
+            }
+        }
+    }
+
+    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);
+        g_string_free(beginning, TRUE);
+        if (found) {
+            g_strfreev(args);
+            return found;
+        }
+    }
+
+    g_strfreev(args);
+
+    found = autocomplete_param_with_ac(input, "/account default", account_default_ac, TRUE);
+    if(found){
+        return found;
+    }
+
+    int i = 0;
+    gchar *account_choice[] = { "/account set", "/account show", "/account enable",
+        "/account disable", "/account rename", "/account clear", "/account remove",
+        "/account default set" };
+
+    for (i = 0; i < ARRAY_SIZE(account_choice); i++) {
+        found = autocomplete_param_with_func(input, account_choice[i], accounts_find_all);
+        if (found) {
+            return found;
+        }
+    }
+
+    found = autocomplete_param_with_ac(input, "/account", account_ac, TRUE);
+    return found;
+}
diff --git a/src/command/cmd_autocomplete.h b/src/command/cmd_autocomplete.h
new file mode 100644
index 00000000..0d9e5f28
--- /dev/null
+++ b/src/command/cmd_autocomplete.h
@@ -0,0 +1,57 @@
+/*
+ * cmd_autocomplete.h
+ *
+ * Copyright (C) 2012 - 2016 James Booth <boothj5@gmail.com>
+ *
+ * This file is part of Profanity.
+ *
+ * Profanity is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Profanity is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Profanity.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * In addition, as a special exception, the copyright holders give permission to
+ * link the code of portions of this program with the OpenSSL library under
+ * certain conditions as described in each individual source file, and
+ * distribute linked combinations including the two.
+ *
+ * You must obey the GNU General Public License in all respects for all of the
+ * code used other than OpenSSL. If you modify file(s) with this exception, you
+ * may extend this exception to your version of the file(s), but you are not
+ * obligated to do so. If you do not wish to do so, delete this exception
+ * statement from your version. If you delete this exception statement from all
+ * source files in the program, then also delete it here.
+ *
+ */
+
+#include "config/preferences.h"
+#include "command/commands.h"
+
+void cmd_ac_init(void);
+void cmd_ac_uninit(void);
+
+void cmd_ac_add(const char *const value);
+void cmd_ac_add_help(const char *const value);
+void cmd_ac_add_cmd(Command *command);
+void cmd_ac_add_alias(ProfAlias *alias);
+void cmd_ac_add_alias_value(char *value);
+
+void cmd_ac_remove(const char *const value);
+void cmd_ac_remove_alias_value(char *value);
+
+gboolean cmd_ac_exists(char *cmd);
+
+void cmd_ac_add_form_fields(DataForm *form);
+void cmd_ac_remove_form_fields(DataForm *form);
+
+char* cmd_ac_complete(ProfWin *window, const char *const input);
+
+void cmd_ac_reset(ProfWin *window);
diff --git a/src/command/command.c b/src/command/command.c
index 7495506f..408b59a7 100644
--- a/src/command/command.c
+++ b/src/command/command.c
@@ -43,7 +43,6 @@
 #include <stdio.h>
 #include <string.h>
 #include <libgen.h>
-
 #include <dirent.h>
 #include <sys/types.h>
 
@@ -52,6 +51,7 @@
 #include "chat_session.h"
 #include "command/command.h"
 #include "command/commands.h"
+#include "command/cmd_autocomplete.h"
 #include "common.h"
 #include "config/accounts.h"
 #include "config/preferences.h"
@@ -64,12 +64,6 @@
 #include "log.h"
 #include "muc.h"
 #include "plugins/plugins.h"
-#ifdef HAVE_LIBOTR
-#include "otr/otr.h"
-#endif
-#ifdef HAVE_LIBGPGME
-#include "pgp/gpg.h"
-#endif
 #include "profanity.h"
 #include "tools/autocomplete.h"
 #include "tools/parser.h"
@@ -78,55 +72,13 @@
 #include "ui/ui.h"
 #include "window_list.h"
 
-static gboolean _cmd_execute(ProfWin *window, const char *const command, const char *const inp);
-
-static char* _cmd_complete_parameters(ProfWin *window, const char *const input);
-
-static char* _script_autocomplete_func(const char *const prefix);
-
-static char* _sub_autocomplete(ProfWin *window, const char *const input);
-static char* _notify_autocomplete(ProfWin *window, const char *const input);
-static char* _theme_autocomplete(ProfWin *window, const char *const input);
-static char* _autoaway_autocomplete(ProfWin *window, const char *const input);
-static char* _autoconnect_autocomplete(ProfWin *window, const char *const input);
-static char* _account_autocomplete(ProfWin *window, const char *const input);
-static char* _who_autocomplete(ProfWin *window, const char *const input);
-static char* _roster_autocomplete(ProfWin *window, const char *const input);
-static char* _group_autocomplete(ProfWin *window, const char *const input);
-static char* _bookmark_autocomplete(ProfWin *window, const char *const input);
-static char* _otr_autocomplete(ProfWin *window, const char *const input);
-static char* _pgp_autocomplete(ProfWin *window, const char *const input);
-static char* _connect_autocomplete(ProfWin *window, const char *const input);
-static char* _statuses_autocomplete(ProfWin *window, const char *const input);
-static char* _alias_autocomplete(ProfWin *window, const char *const input);
-static char* _join_autocomplete(ProfWin *window, const char *const input);
-static char* _log_autocomplete(ProfWin *window, const char *const input);
-static char* _form_autocomplete(ProfWin *window, const char *const input);
-static char* _form_field_autocomplete(ProfWin *window, const char *const input);
-static char* _occupants_autocomplete(ProfWin *window, const char *const input);
-static char* _kick_autocomplete(ProfWin *window, const char *const input);
-static char* _ban_autocomplete(ProfWin *window, const char *const input);
-static char* _affiliation_autocomplete(ProfWin *window, const char *const input);
-static char* _role_autocomplete(ProfWin *window, const char *const input);
-static char* _resource_autocomplete(ProfWin *window, const char *const input);
-static char* _titlebar_autocomplete(ProfWin *window, const char *const input);
-static char* _inpblock_autocomplete(ProfWin *window, const char *const input);
-static char* _time_autocomplete(ProfWin *window, const char *const input);
-static char* _receipts_autocomplete(ProfWin *window, const char *const input);
-static char* _help_autocomplete(ProfWin *window, const char *const input);
-static char* _wins_autocomplete(ProfWin *window, const char *const input);
-static char* _tls_autocomplete(ProfWin *window, const char *const input);
-static char* _script_autocomplete(ProfWin *window, const char *const input);
-static char* _subject_autocomplete(ProfWin *window, const char *const input);
-static char* _console_autocomplete(ProfWin *window, const char *const input);
-static char* _win_autocomplete(ProfWin *window, const char *const input);
-static char* _close_autocomplete(ProfWin *window, const char *const input);
-static char* _plugins_autocomplete(ProfWin *window, const char *const input);
-static char* _sendfile_autocomplete(ProfWin *window, const char *const input);
-static char* _blocked_autocomplete(ProfWin *window, const char *const input);
-static char *_tray_autocomplete(ProfWin *window, const char *const input);
+#ifdef HAVE_LIBOTR
+#include "otr/otr.h"
+#endif
 
-GHashTable *commands = NULL;
+#ifdef HAVE_LIBGPGME
+#include "pgp/gpg.h"
+#endif
 
 #define CMD_TAG_CHAT        "chat"
 #define CMD_TAG_GROUPCHAT   "groupchat"
@@ -151,6 +103,10 @@ GHashTable *commands = NULL;
 #define CMD_NOEXAMPLES      { NULL } }
 #define CMD_EXAMPLES(...)   { __VA_ARGS__, NULL } }
 
+static gboolean _cmd_execute(ProfWin *window, const char *const command, const char *const inp);
+
+GHashTable *commands = NULL;
+
 /*
  * Command list
  */
@@ -2218,93 +2174,6 @@ static struct cmd_t command_defs[] =
     },
 };
 
-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 autoaway_ac;
-static Autocomplete autoaway_mode_ac;
-static Autocomplete autoaway_presence_ac;
-static Autocomplete autoconnect_ac;
-static Autocomplete titlebar_ac;
-static Autocomplete theme_ac;
-static Autocomplete theme_load_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_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 otr_ac;
-static Autocomplete otr_log_ac;
-static Autocomplete otr_policy_ac;
-static Autocomplete connect_property_ac;
-static Autocomplete tls_property_ac;
-static Autocomplete statuses_ac;
-static Autocomplete statuses_setting_ac;
-static Autocomplete alias_ac;
-static Autocomplete aliases_ac;
-static Autocomplete join_property_ac;
-static Autocomplete room_ac;
-static Autocomplete affiliation_ac;
-static Autocomplete role_ac;
-static Autocomplete privilege_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 time_ac;
-static Autocomplete time_format_ac;
-static Autocomplete resource_ac;
-static Autocomplete inpblock_ac;
-static Autocomplete receipts_ac;
-static Autocomplete pgp_ac;
-static Autocomplete pgp_log_ac;
-static Autocomplete tls_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 sendfile_ac;
-static Autocomplete blocked_ac;
-static Autocomplete tray_ac;
 
 /*
  * Initialise command autocompleter and history
@@ -2314,12 +2183,7 @@ cmd_init(void)
 {
     log_info("Initialising commands");
 
-    commands_ac = autocomplete_new();
-    aliases_ac = autocomplete_new();
-
-    help_ac = autocomplete_new();
-    autocomplete_add(help_ac, "commands");
-    autocomplete_add(help_ac, "navigation");
+    cmd_ac_init();
 
     // load command defs into hash table
     commands = g_hash_table_new(g_str_hash, g_str_equal);
@@ -2331,8 +2195,7 @@ cmd_init(void)
         g_hash_table_insert(commands, pcmd->cmd, pcmd);
 
         // add to commands and help autocompleters
-        autocomplete_add(commands_ac, pcmd->cmd);
-        autocomplete_add(help_ac, pcmd->cmd+1);
+        cmd_ac_add_cmd(pcmd);
     }
 
     // load aliases
@@ -2340,887 +2203,16 @@ cmd_init(void)
     GList *curr = aliases;
     while (curr) {
         ProfAlias *alias = curr->data;
-        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);
+        cmd_ac_add_alias(alias);
         curr = g_list_next(curr);
     }
     prefs_free_aliases(aliases);
-
-    help_commands_ac = autocomplete_new();
-    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");
-
-    prefs_ac = autocomplete_new();
-    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");
-    autocomplete_add(prefs_ac, "otr");
-    autocomplete_add(prefs_ac, "pgp");
-
-    notify_ac = autocomplete_new();
-    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");
-
-    notify_chat_ac = autocomplete_new();
-    autocomplete_add(notify_chat_ac, "on");
-    autocomplete_add(notify_chat_ac, "off");
-    autocomplete_add(notify_chat_ac, "current");
-    autocomplete_add(notify_chat_ac, "text");
-
-    notify_room_ac = autocomplete_new();
-    autocomplete_add(notify_room_ac, "on");
-    autocomplete_add(notify_room_ac, "off");
-    autocomplete_add(notify_room_ac, "mention");
-    autocomplete_add(notify_room_ac, "current");
-    autocomplete_add(notify_room_ac, "text");
-    autocomplete_add(notify_room_ac, "trigger");
-
-    notify_typing_ac = autocomplete_new();
-    autocomplete_add(notify_typing_ac, "on");
-    autocomplete_add(notify_typing_ac, "off");
-    autocomplete_add(notify_typing_ac, "current");
-
-    notify_mention_ac = autocomplete_new();
-    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");
-
-    notify_trigger_ac = autocomplete_new();
-    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");
-
-    sub_ac = autocomplete_new();
-    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");
-
-    titlebar_ac = autocomplete_new();
-    autocomplete_add(titlebar_ac, "show");
-    autocomplete_add(titlebar_ac, "goodbye");
-
-    log_ac = autocomplete_new();
-    autocomplete_add(log_ac, "maxsize");
-    autocomplete_add(log_ac, "rotate");
-    autocomplete_add(log_ac, "shared");
-    autocomplete_add(log_ac, "where");
-
-    autoaway_ac = autocomplete_new();
-    autocomplete_add(autoaway_ac, "mode");
-    autocomplete_add(autoaway_ac, "time");
-    autocomplete_add(autoaway_ac, "message");
-    autocomplete_add(autoaway_ac, "check");
-
-    autoaway_mode_ac = autocomplete_new();
-    autocomplete_add(autoaway_mode_ac, "away");
-    autocomplete_add(autoaway_mode_ac, "idle");
-    autocomplete_add(autoaway_mode_ac, "off");
-
-    autoaway_presence_ac = autocomplete_new();
-    autocomplete_add(autoaway_presence_ac, "away");
-    autocomplete_add(autoaway_presence_ac, "xa");
-
-    autoconnect_ac = autocomplete_new();
-    autocomplete_add(autoconnect_ac, "set");
-    autocomplete_add(autoconnect_ac, "off");
-
-    theme_ac = autocomplete_new();
-    autocomplete_add(theme_ac, "load");
-    autocomplete_add(theme_ac, "list");
-    autocomplete_add(theme_ac, "colours");
-    autocomplete_add(theme_ac, "properties");
-
-    disco_ac = autocomplete_new();
-    autocomplete_add(disco_ac, "info");
-    autocomplete_add(disco_ac, "items");
-
-    account_ac = autocomplete_new();
-    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");
-
-    account_set_ac = autocomplete_new();
-    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, "tls");
-    autocomplete_add(account_set_ac, "theme");
-
-    account_clear_ac = autocomplete_new();
-    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, "theme");
-
-    account_default_ac = autocomplete_new();
-    autocomplete_add(account_default_ac, "set");
-    autocomplete_add(account_default_ac, "off");
-
-    account_status_ac = autocomplete_new();
-    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");
-
-    wins_ac = autocomplete_new();
-    autocomplete_add(wins_ac, "unread");
-    autocomplete_add(wins_ac, "prune");
-    autocomplete_add(wins_ac, "tidy");
-    autocomplete_add(wins_ac, "autotidy");
-    autocomplete_add(wins_ac, "swap");
-
-    roster_ac = autocomplete_new();
-    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, "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");
-
-    roster_private_ac = autocomplete_new();
-    autocomplete_add(roster_private_ac, "room");
-    autocomplete_add(roster_private_ac, "group");
-    autocomplete_add(roster_private_ac, "off");
-    autocomplete_add(roster_private_ac, "char");
-
-    roster_header_ac = autocomplete_new();
-    autocomplete_add(roster_header_ac, "char");
-
-    roster_contact_ac = autocomplete_new();
-    autocomplete_add(roster_contact_ac, "char");
-    autocomplete_add(roster_contact_ac, "indent");
-
-    roster_resource_ac = autocomplete_new();
-    autocomplete_add(roster_resource_ac, "char");
-    autocomplete_add(roster_resource_ac, "indent");
-    autocomplete_add(roster_resource_ac, "join");
-
-    roster_presence_ac = autocomplete_new();
-    autocomplete_add(roster_presence_ac, "indent");
-
-    roster_char_ac = autocomplete_new();
-    autocomplete_add(roster_char_ac, "none");
-
-    roster_show_ac = autocomplete_new();
-    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");
-
-    roster_by_ac = autocomplete_new();
-    autocomplete_add(roster_by_ac, "group");
-    autocomplete_add(roster_by_ac, "presence");
-    autocomplete_add(roster_by_ac, "none");
-
-    roster_count_ac = autocomplete_new();
-    autocomplete_add(roster_count_ac, "unread");
-    autocomplete_add(roster_count_ac, "items");
-    autocomplete_add(roster_count_ac, "off");
-    autocomplete_add(roster_count_ac, "zero");
-
-    roster_order_ac = autocomplete_new();
-    autocomplete_add(roster_order_ac, "name");
-    autocomplete_add(roster_order_ac, "presence");
-
-    roster_unread_ac = autocomplete_new();
-    autocomplete_add(roster_unread_ac, "before");
-    autocomplete_add(roster_unread_ac, "after");
-    autocomplete_add(roster_unread_ac, "off");
-
-    roster_room_ac = autocomplete_new();
-    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");
-
-    roster_room_by_ac = autocomplete_new();
-    autocomplete_add(roster_room_by_ac, "service");
-    autocomplete_add(roster_room_by_ac, "none");
-
-    roster_room_order_ac = autocomplete_new();
-    autocomplete_add(roster_room_order_ac, "name");
-    autocomplete_add(roster_room_order_ac, "unread");
-
-    roster_room_position_ac = autocomplete_new();
-    autocomplete_add(roster_room_position_ac, "first");
-    autocomplete_add(roster_room_position_ac, "last");
-
-    roster_remove_all_ac = autocomplete_new();
-    autocomplete_add(roster_remove_all_ac, "contacts");
-
-    group_ac = autocomplete_new();
-    autocomplete_add(group_ac, "show");
-    autocomplete_add(group_ac, "add");
-    autocomplete_add(group_ac, "remove");
-
-    theme_load_ac = NULL;
-    plugins_load_ac = NULL;
-
-    who_roster_ac = autocomplete_new();
-    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");
-
-    who_room_ac = autocomplete_new();
-    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");
-
-    bookmark_ac = autocomplete_new();
-    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");
-
-    bookmark_property_ac = autocomplete_new();
-    autocomplete_add(bookmark_property_ac, "nick");
-    autocomplete_add(bookmark_property_ac, "password");
-    autocomplete_add(bookmark_property_ac, "autojoin");
-
-    otr_ac = autocomplete_new();
-    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");
-
-    otr_log_ac = autocomplete_new();
-    autocomplete_add(otr_log_ac, "on");
-    autocomplete_add(otr_log_ac, "off");
-    autocomplete_add(otr_log_ac, "redact");
-
-    otr_policy_ac = autocomplete_new();
-    autocomplete_add(otr_policy_ac, "manual");
-    autocomplete_add(otr_policy_ac, "opportunistic");
-    autocomplete_add(otr_policy_ac, "always");
-
-    connect_property_ac = autocomplete_new();
-    autocomplete_add(connect_property_ac, "server");
-    autocomplete_add(connect_property_ac, "port");
-    autocomplete_add(connect_property_ac, "tls");
-
-    tls_property_ac = autocomplete_new();
-    autocomplete_add(tls_property_ac, "force");
-    autocomplete_add(tls_property_ac, "allow");
-    autocomplete_add(tls_property_ac, "disable");
-
-    join_property_ac = autocomplete_new();
-    autocomplete_add(join_property_ac, "nick");
-    autocomplete_add(join_property_ac, "password");
-
-    statuses_ac = autocomplete_new();
-    autocomplete_add(statuses_ac, "console");
-    autocomplete_add(statuses_ac, "chat");
-    autocomplete_add(statuses_ac, "muc");
-
-    statuses_setting_ac = autocomplete_new();
-    autocomplete_add(statuses_setting_ac, "all");
-    autocomplete_add(statuses_setting_ac, "online");
-    autocomplete_add(statuses_setting_ac, "none");
-
-    alias_ac = autocomplete_new();
-    autocomplete_add(alias_ac, "add");
-    autocomplete_add(alias_ac, "remove");
-    autocomplete_add(alias_ac, "list");
-
-    room_ac = autocomplete_new();
-    autocomplete_add(room_ac, "accept");
-    autocomplete_add(room_ac, "destroy");
-    autocomplete_add(room_ac, "config");
-
-    affiliation_ac = autocomplete_new();
-    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");
-
-    role_ac = autocomplete_new();
-    autocomplete_add(role_ac, "moderator");
-    autocomplete_add(role_ac, "participant");
-    autocomplete_add(role_ac, "visitor");
-    autocomplete_add(role_ac, "none");
-
-    privilege_cmd_ac = autocomplete_new();
-    autocomplete_add(privilege_cmd_ac, "list");
-    autocomplete_add(privilege_cmd_ac, "set");
-
-    subject_ac = autocomplete_new();
-    autocomplete_add(subject_ac, "set");
-    autocomplete_add(subject_ac, "edit");
-    autocomplete_add(subject_ac, "prepend");
-    autocomplete_add(subject_ac, "append");
-    autocomplete_add(subject_ac, "clear");
-
-    form_ac = autocomplete_new();
-    autocomplete_add(form_ac, "submit");
-    autocomplete_add(form_ac, "cancel");
-    autocomplete_add(form_ac, "show");
-    autocomplete_add(form_ac, "help");
-
-    form_field_multi_ac = autocomplete_new();
-    autocomplete_add(form_field_multi_ac, "add");
-    autocomplete_add(form_field_multi_ac, "remove");
-
-    occupants_ac = autocomplete_new();
-    autocomplete_add(occupants_ac, "show");
-    autocomplete_add(occupants_ac, "hide");
-    autocomplete_add(occupants_ac, "default");
-    autocomplete_add(occupants_ac, "size");
-
-    occupants_default_ac = autocomplete_new();
-    autocomplete_add(occupants_default_ac, "show");
-    autocomplete_add(occupants_default_ac, "hide");
-
-    occupants_show_ac = autocomplete_new();
-    autocomplete_add(occupants_show_ac, "jid");
-
-    time_ac = autocomplete_new();
-    autocomplete_add(time_ac, "console");
-    autocomplete_add(time_ac, "chat");
-    autocomplete_add(time_ac, "muc");
-    autocomplete_add(time_ac, "mucconfig");
-    autocomplete_add(time_ac, "private");
-    autocomplete_add(time_ac, "xml");
-    autocomplete_add(time_ac, "statusbar");
-    autocomplete_add(time_ac, "lastactivity");
-
-    time_format_ac = autocomplete_new();
-    autocomplete_add(time_format_ac, "set");
-    autocomplete_add(time_format_ac, "off");
-
-    resource_ac = autocomplete_new();
-    autocomplete_add(resource_ac, "set");
-    autocomplete_add(resource_ac, "off");
-    autocomplete_add(resource_ac, "title");
-    autocomplete_add(resource_ac, "message");
-
-    inpblock_ac = autocomplete_new();
-    autocomplete_add(inpblock_ac, "timeout");
-    autocomplete_add(inpblock_ac, "dynamic");
-
-    receipts_ac = autocomplete_new();
-    autocomplete_add(receipts_ac, "send");
-    autocomplete_add(receipts_ac, "request");
-
-    pgp_ac = autocomplete_new();
-    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");
-
-    pgp_log_ac = autocomplete_new();
-    autocomplete_add(pgp_log_ac, "on");
-    autocomplete_add(pgp_log_ac, "off");
-    autocomplete_add(pgp_log_ac, "redact");
-
-    tls_ac = autocomplete_new();
-    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(tls_ac, "show");
-
-    tls_certpath_ac = autocomplete_new();
-    autocomplete_add(tls_certpath_ac, "set");
-    autocomplete_add(tls_certpath_ac, "clear");
-
-    script_ac = autocomplete_new();
-    autocomplete_add(script_ac, "run");
-    autocomplete_add(script_ac, "list");
-    autocomplete_add(script_ac, "show");
-
-    script_show_ac = NULL;
-
-    console_ac = autocomplete_new();
-    autocomplete_add(console_ac, "chat");
-    autocomplete_add(console_ac, "muc");
-    autocomplete_add(console_ac, "private");
-
-    console_msg_ac = autocomplete_new();
-    autocomplete_add(console_msg_ac, "all");
-    autocomplete_add(console_msg_ac, "first");
-    autocomplete_add(console_msg_ac, "none");
-
-    autoping_ac = autocomplete_new();
-    autocomplete_add(autoping_ac, "set");
-    autocomplete_add(autoping_ac, "timeout");
-
-    plugins_ac = autocomplete_new();
-    autocomplete_add(plugins_ac, "load");
-
-    sendfile_ac = autocomplete_new();
-
-    blocked_ac = autocomplete_new();
-    autocomplete_add(blocked_ac, "add");
-    autocomplete_add(blocked_ac, "remove");
-
-    tray_ac = autocomplete_new();
-    autocomplete_add(tray_ac, "on");
-    autocomplete_add(tray_ac, "off");
-    autocomplete_add(tray_ac, "read");
-    autocomplete_add(tray_ac, "timer");
 }
 
 void
 cmd_uninit(void)
 {
-    autocomplete_free(commands_ac);
-    autocomplete_free(who_room_ac);
-    autocomplete_free(who_roster_ac);
-    autocomplete_free(help_ac);
-    autocomplete_free(help_commands_ac);
-    autocomplete_free(notify_ac);
-    autocomplete_free(notify_chat_ac);
-    autocomplete_free(notify_room_ac);
-    autocomplete_free(notify_typing_ac);
-    autocomplete_free(notify_mention_ac);
-    autocomplete_free(notify_trigger_ac);
-    autocomplete_free(sub_ac);
-    autocomplete_free(titlebar_ac);
-    autocomplete_free(log_ac);
-    autocomplete_free(prefs_ac);
-    autocomplete_free(autoaway_ac);
-    autocomplete_free(autoaway_mode_ac);
-    autocomplete_free(autoaway_presence_ac);
-    autocomplete_free(autoconnect_ac);
-    autocomplete_free(theme_ac);
-    autocomplete_free(theme_load_ac);
-    autocomplete_free(account_ac);
-    autocomplete_free(account_set_ac);
-    autocomplete_free(account_clear_ac);
-    autocomplete_free(account_default_ac);
-    autocomplete_free(account_status_ac);
-    autocomplete_free(disco_ac);
-    autocomplete_free(wins_ac);
-    autocomplete_free(roster_ac);
-    autocomplete_free(roster_header_ac);
-    autocomplete_free(roster_contact_ac);
-    autocomplete_free(roster_resource_ac);
-    autocomplete_free(roster_presence_ac);
-    autocomplete_free(roster_char_ac);
-    autocomplete_free(roster_show_ac);
-    autocomplete_free(roster_by_ac);
-    autocomplete_free(roster_count_ac);
-    autocomplete_free(roster_order_ac);
-    autocomplete_free(roster_room_ac);
-    autocomplete_free(roster_room_by_ac);
-    autocomplete_free(roster_unread_ac);
-    autocomplete_free(roster_room_position_ac);
-    autocomplete_free(roster_room_order_ac);
-    autocomplete_free(roster_remove_all_ac);
-    autocomplete_free(roster_private_ac);
-    autocomplete_free(group_ac);
-    autocomplete_free(bookmark_ac);
-    autocomplete_free(bookmark_property_ac);
-    autocomplete_free(otr_ac);
-    autocomplete_free(otr_log_ac);
-    autocomplete_free(otr_policy_ac);
-    autocomplete_free(connect_property_ac);
-    autocomplete_free(tls_property_ac);
-    autocomplete_free(statuses_ac);
-    autocomplete_free(statuses_setting_ac);
-    autocomplete_free(alias_ac);
-    autocomplete_free(aliases_ac);
-    autocomplete_free(join_property_ac);
-    autocomplete_free(room_ac);
-    autocomplete_free(affiliation_ac);
-    autocomplete_free(role_ac);
-    autocomplete_free(privilege_cmd_ac);
-    autocomplete_free(subject_ac);
-    autocomplete_free(form_ac);
-    autocomplete_free(form_field_multi_ac);
-    autocomplete_free(occupants_ac);
-    autocomplete_free(occupants_default_ac);
-    autocomplete_free(occupants_show_ac);
-    autocomplete_free(time_ac);
-    autocomplete_free(time_format_ac);
-    autocomplete_free(resource_ac);
-    autocomplete_free(inpblock_ac);
-    autocomplete_free(receipts_ac);
-    autocomplete_free(pgp_ac);
-    autocomplete_free(pgp_log_ac);
-    autocomplete_free(tls_ac);
-    autocomplete_free(tls_certpath_ac);
-    autocomplete_free(script_ac);
-    autocomplete_free(script_show_ac);
-    autocomplete_free(console_ac);
-    autocomplete_free(console_msg_ac);
-    autocomplete_free(autoping_ac);
-    autocomplete_free(plugins_ac);
-    autocomplete_free(plugins_load_ac);
-    autocomplete_free(sendfile_ac);
-    autocomplete_free(blocked_ac);
-    autocomplete_free(tray_ac);
-}
-
-gboolean
-cmd_exists(char *cmd)
-{
-    if (commands_ac == NULL) {
-        return FALSE;
-    } else {
-        return autocomplete_contains(commands_ac, cmd);
-    }
-}
-
-void
-cmd_autocomplete_add(const char *const value)
-{
-    if (commands_ac) {
-        autocomplete_add(commands_ac, value);
-    }
-}
-
-void
-cmd_help_autocomplete_add(const char *const value)
-{
-    if (help_ac) {
-        autocomplete_add(help_ac, value);
-    }
-}
-
-void
-cmd_autocomplete_add_form_fields(DataForm *form)
-{
-    if (form == NULL) {
-        return;
-    }
-
-    GSList *fields = autocomplete_create_list(form->tag_ac);
-    GSList *curr_field = fields;
-    while (curr_field) {
-        GString *field_str = g_string_new("/");
-        g_string_append(field_str, curr_field->data);
-        cmd_autocomplete_add(field_str->str);
-        g_string_free(field_str, TRUE);
-        curr_field = g_slist_next(curr_field);
-    }
-    g_slist_free_full(fields, free);
-}
-
-void
-cmd_autocomplete_remove_form_fields(DataForm *form)
-{
-    if (form == NULL) {
-        return;
-    }
-
-    GSList *fields = autocomplete_create_list(form->tag_ac);
-    GSList *curr_field = fields;
-    while (curr_field) {
-        GString *field_str = g_string_new("/");
-        g_string_append(field_str, curr_field->data);
-        cmd_autocomplete_remove(field_str->str);
-        g_string_free(field_str, TRUE);
-        curr_field = g_slist_next(curr_field);
-    }
-    g_slist_free_full(fields, free);
-}
-
-void
-cmd_autocomplete_remove(const char *const value)
-{
-    if (commands_ac) {
-        autocomplete_remove(commands_ac, value);
-    }
-}
-
-void
-cmd_alias_add(char *value)
-{
-    if (aliases_ac) {
-        autocomplete_add(aliases_ac, value);
-    }
-}
-
-void
-cmd_alias_remove(char *value)
-{
-    if (aliases_ac) {
-        autocomplete_remove(aliases_ac, value);
-    }
-}
-
-// Command autocompletion functions
-char*
-cmd_autocomplete(ProfWin *window, const char *const input)
-{
-    // autocomplete command
-    if ((strncmp(input, "/", 1) == 0) && (!str_contains(input, strlen(input), ' '))) {
-        char *found = NULL;
-        found = autocomplete_complete(commands_ac, input, TRUE);
-        if (found) {
-            return found;
-        }
-
-    // autocomplete parameters
-    } else {
-        char *found = _cmd_complete_parameters(window, input);
-        if (found) {
-            return found;
-        }
-    }
-
-    return NULL;
-}
-
-void
-cmd_reset_autocomplete(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();
-    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
-    autocomplete_reset(help_ac);
-    autocomplete_reset(help_commands_ac);
-    autocomplete_reset(notify_ac);
-    autocomplete_reset(notify_chat_ac);
-    autocomplete_reset(notify_room_ac);
-    autocomplete_reset(notify_typing_ac);
-    autocomplete_reset(notify_mention_ac);
-    autocomplete_reset(notify_trigger_ac);
-    autocomplete_reset(sub_ac);
-    autocomplete_reset(sendfile_ac);
-
-    autocomplete_reset(who_room_ac);
-    autocomplete_reset(who_roster_ac);
-    autocomplete_reset(prefs_ac);
-    autocomplete_reset(log_ac);
-    autocomplete_reset(commands_ac);
-    autocomplete_reset(autoaway_ac);
-    autocomplete_reset(autoaway_mode_ac);
-    autocomplete_reset(autoaway_presence_ac);
-    autocomplete_reset(autoconnect_ac);
-    autocomplete_reset(theme_ac);
-    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;
-    }
-    autocomplete_reset(account_ac);
-    autocomplete_reset(account_set_ac);
-    autocomplete_reset(account_clear_ac);
-    autocomplete_reset(account_default_ac);
-    autocomplete_reset(account_status_ac);
-    autocomplete_reset(disco_ac);
-    autocomplete_reset(wins_ac);
-    autocomplete_reset(roster_ac);
-    autocomplete_reset(roster_header_ac);
-    autocomplete_reset(roster_contact_ac);
-    autocomplete_reset(roster_resource_ac);
-    autocomplete_reset(roster_presence_ac);
-    autocomplete_reset(roster_char_ac);
-    autocomplete_reset(roster_show_ac);
-    autocomplete_reset(roster_by_ac);
-    autocomplete_reset(roster_count_ac);
-    autocomplete_reset(roster_order_ac);
-    autocomplete_reset(roster_room_ac);
-    autocomplete_reset(roster_room_by_ac);
-    autocomplete_reset(roster_unread_ac);
-    autocomplete_reset(roster_room_position_ac);
-    autocomplete_reset(roster_room_order_ac);
-    autocomplete_reset(roster_remove_all_ac);
-    autocomplete_reset(roster_private_ac);
-    autocomplete_reset(group_ac);
-    autocomplete_reset(titlebar_ac);
-    autocomplete_reset(bookmark_ac);
-    autocomplete_reset(bookmark_property_ac);
-    autocomplete_reset(otr_ac);
-    autocomplete_reset(otr_log_ac);
-    autocomplete_reset(otr_policy_ac);
-    autocomplete_reset(connect_property_ac);
-    autocomplete_reset(tls_property_ac);
-    autocomplete_reset(statuses_ac);
-    autocomplete_reset(statuses_setting_ac);
-    autocomplete_reset(alias_ac);
-    autocomplete_reset(aliases_ac);
-    autocomplete_reset(join_property_ac);
-    autocomplete_reset(room_ac);
-    autocomplete_reset(affiliation_ac);
-    autocomplete_reset(role_ac);
-    autocomplete_reset(privilege_cmd_ac);
-    autocomplete_reset(subject_ac);
-    autocomplete_reset(form_ac);
-    autocomplete_reset(form_field_multi_ac);
-    autocomplete_reset(occupants_ac);
-    autocomplete_reset(occupants_default_ac);
-    autocomplete_reset(occupants_show_ac);
-    autocomplete_reset(time_ac);
-    autocomplete_reset(time_format_ac);
-    autocomplete_reset(resource_ac);
-    autocomplete_reset(inpblock_ac);
-    autocomplete_reset(receipts_ac);
-    autocomplete_reset(pgp_ac);
-    autocomplete_reset(pgp_log_ac);
-    autocomplete_reset(tls_ac);
-    autocomplete_reset(tls_certpath_ac);
-    autocomplete_reset(console_ac);
-    autocomplete_reset(console_msg_ac);
-    autocomplete_reset(autoping_ac);
-    autocomplete_reset(plugins_ac);
-    autocomplete_reset(blocked_ac);
-    autocomplete_reset(tray_ac);
-    autocomplete_reset(script_ac);
-    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_MUC_CONFIG) {
-        ProfMucConfWin *confwin = (ProfMucConfWin*)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();
+    cmd_ac_uninit();
 }
 
 gboolean
@@ -3361,1832 +2353,6 @@ _cmd_execute(ProfWin *window, const char *const command, const char *const inp)
     }
 }
 
-static char*
-_cmd_complete_parameters(ProfWin *window, const char *const input)
-{
-    int i;
-    char *result = NULL;
-
-    jabber_conn_status_t conn_status = connection_get_status();
-
-    // autocomplete boolean settings
-    gchar *boolean_choices[] = { "/beep", "/intype", "/states", "/outtype", "/flash", "/splash", "/chlog", "/grlog",
-        "/history", "/vercheck", "/privileges", "/presence", "/wrap", "/winstidy", "/carbons", "/encwarn",
-        "/lastactivity" };
-
-    for (i = 0; i < ARRAY_SIZE(boolean_choices); i++) {
-        result = autocomplete_param_with_func(input, boolean_choices[i], prefs_autocomplete_boolean_choice);
-        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", "/status", "/software" } ;
-
-            // Remove quote character before and after names when doing autocomplete
-            char *unquoted = strip_arg_quotes(input);
-            for (i = 0; i < ARRAY_SIZE(nick_choices); i++) {
-                result = autocomplete_param_with_ac(unquoted, nick_choices[i], nick_ac, TRUE);
-                if (result) {
-                    free(unquoted);
-                    return result;
-                }
-            }
-            free(unquoted);
-        }
-
-    // otherwise autocomplete using roster
-    } else if (conn_status == JABBER_CONNECTED) {
-        gchar *contact_choices[] = { "/msg", "/info", "/status" };
-        // Remove quote character before and after names when doing autocomplete
-        char *unquoted = strip_arg_quotes(input);
-        for (i = 0; i < ARRAY_SIZE(contact_choices); i++) {
-            result = autocomplete_param_with_func(unquoted, contact_choices[i], roster_contact_autocomplete);
-            if (result) {
-                free(unquoted);
-                return result;
-            }
-        }
-        free(unquoted);
-
-        gchar *resource_choices[] = { "/caps", "/software", "/ping" };
-        for (i = 0; i < ARRAY_SIZE(resource_choices); i++) {
-            result = autocomplete_param_with_func(input, resource_choices[i], roster_fulljid_autocomplete);
-            if (result) {
-                return result;
-            }
-        }
-    }
-
-    if (conn_status == JABBER_CONNECTED) {
-        result = autocomplete_param_with_func(input, "/invite", roster_contact_autocomplete);
-        if (result) {
-            return result;
-        }
-    }
-
-    gchar *invite_choices[] = { "/decline", "/join" };
-    for (i = 0; i < ARRAY_SIZE(invite_choices); i++) {
-        result = autocomplete_param_with_func(input, invite_choices[i], muc_invites_find);
-        if (result) {
-            return result;
-        }
-    }
-
-    gchar *cmds[] = { "/prefs", "/disco", "/room", "/autoping" };
-    Autocomplete completers[] = { prefs_ac, disco_ac, room_ac, autoping_ac };
-
-    for (i = 0; i < ARRAY_SIZE(cmds); i++) {
-        result = autocomplete_param_with_ac(input, cmds[i], completers[i], TRUE);
-        if (result) {
-            return result;
-        }
-    }
-
-    GHashTable *ac_funcs = g_hash_table_new(g_str_hash, g_str_equal);
-    g_hash_table_insert(ac_funcs, "/help",          _help_autocomplete);
-    g_hash_table_insert(ac_funcs, "/who",           _who_autocomplete);
-    g_hash_table_insert(ac_funcs, "/sub",           _sub_autocomplete);
-    g_hash_table_insert(ac_funcs, "/notify",        _notify_autocomplete);
-    g_hash_table_insert(ac_funcs, "/autoaway",      _autoaway_autocomplete);
-    g_hash_table_insert(ac_funcs, "/theme",         _theme_autocomplete);
-    g_hash_table_insert(ac_funcs, "/log",           _log_autocomplete);
-    g_hash_table_insert(ac_funcs, "/account",       _account_autocomplete);
-    g_hash_table_insert(ac_funcs, "/roster",        _roster_autocomplete);
-    g_hash_table_insert(ac_funcs, "/group",         _group_autocomplete);
-    g_hash_table_insert(ac_funcs, "/bookmark",      _bookmark_autocomplete);
-    g_hash_table_insert(ac_funcs, "/autoconnect",   _autoconnect_autocomplete);
-    g_hash_table_insert(ac_funcs, "/otr",           _otr_autocomplete);
-    g_hash_table_insert(ac_funcs, "/pgp",           _pgp_autocomplete);
-    g_hash_table_insert(ac_funcs, "/connect",       _connect_autocomplete);
-    g_hash_table_insert(ac_funcs, "/statuses",      _statuses_autocomplete);
-    g_hash_table_insert(ac_funcs, "/alias",         _alias_autocomplete);
-    g_hash_table_insert(ac_funcs, "/join",          _join_autocomplete);
-    g_hash_table_insert(ac_funcs, "/form",          _form_autocomplete);
-    g_hash_table_insert(ac_funcs, "/occupants",     _occupants_autocomplete);
-    g_hash_table_insert(ac_funcs, "/kick",          _kick_autocomplete);
-    g_hash_table_insert(ac_funcs, "/ban",           _ban_autocomplete);
-    g_hash_table_insert(ac_funcs, "/affiliation",   _affiliation_autocomplete);
-    g_hash_table_insert(ac_funcs, "/role",          _role_autocomplete);
-    g_hash_table_insert(ac_funcs, "/resource",      _resource_autocomplete);
-    g_hash_table_insert(ac_funcs, "/titlebar",      _titlebar_autocomplete);
-    g_hash_table_insert(ac_funcs, "/inpblock",      _inpblock_autocomplete);
-    g_hash_table_insert(ac_funcs, "/time",          _time_autocomplete);
-    g_hash_table_insert(ac_funcs, "/receipts",      _receipts_autocomplete);
-    g_hash_table_insert(ac_funcs, "/wins",          _wins_autocomplete);
-    g_hash_table_insert(ac_funcs, "/tls",           _tls_autocomplete);
-    g_hash_table_insert(ac_funcs, "/script",        _script_autocomplete);
-    g_hash_table_insert(ac_funcs, "/subject",       _subject_autocomplete);
-    g_hash_table_insert(ac_funcs, "/console",       _console_autocomplete);
-    g_hash_table_insert(ac_funcs, "/win",           _win_autocomplete);
-    g_hash_table_insert(ac_funcs, "/close",         _close_autocomplete);
-    g_hash_table_insert(ac_funcs, "/plugins",       _plugins_autocomplete);
-    g_hash_table_insert(ac_funcs, "/sendfile",      _sendfile_autocomplete);
-    g_hash_table_insert(ac_funcs, "/blocked",       _blocked_autocomplete);
-    g_hash_table_insert(ac_funcs, "/tray",          _tray_autocomplete);
-
-    int len = strlen(input);
-    char parsed[len+1];
-    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) = g_hash_table_lookup(ac_funcs, parsed);
-    if (ac_func) {
-        result = ac_func(window, input);
-        if (result) {
-            g_hash_table_destroy(ac_funcs);
-            return result;
-        }
-    }
-    g_hash_table_destroy(ac_funcs);
-
-    result = plugins_autocomplete(input);
-    if (result) {
-        return result;
-    }
-
-    if (g_str_has_prefix(input, "/field")) {
-        result = _form_field_autocomplete(window, input);
-        if (result) {
-            return result;
-        }
-    }
-
-    return NULL;
-}
-
-static char*
-_sub_autocomplete(ProfWin *window, const char *const input)
-{
-    char *result = NULL;
-    result = autocomplete_param_with_func(input, "/sub allow", presence_sub_request_find);
-    if (result) {
-        return result;
-    }
-    result = autocomplete_param_with_func(input, "/sub deny", presence_sub_request_find);
-    if (result) {
-        return result;
-    }
-    result = autocomplete_param_with_ac(input, "/sub", sub_ac, TRUE);
-    if (result) {
-        return result;
-    }
-
-    return NULL;
-}
-
-static char*
-_tray_autocomplete(ProfWin *window, const char *const input)
-{
-    char *result = NULL;
-    result = autocomplete_param_with_func(input, "/tray read", prefs_autocomplete_boolean_choice);
-    if (result) {
-        return result;
-    }
-
-    result = autocomplete_param_with_ac(input, "/tray", tray_ac, FALSE);
-    if (result) {
-        return result;
-    }
-
-    return NULL;
-}
-
-static char*
-_who_autocomplete(ProfWin *window, const char *const input)
-{
-    char *result = NULL;
-
-    if (window->type == WIN_MUC) {
-        result = autocomplete_param_with_ac(input, "/who", who_room_ac, TRUE);
-        if (result) {
-            return result;
-        }
-    } else {
-        jabber_conn_status_t conn_status = connection_get_status();
-        if (conn_status == JABBER_CONNECTED) {
-            int i = 0;
-            gchar *group_commands[] = { "/who any", "/who online", "/who offline",
-                "/who chat", "/who away", "/who xa", "/who dnd", "/who available",
-                "/who unavailable" };
-
-            for (i = 0; i < ARRAY_SIZE(group_commands); i++) {
-                result = autocomplete_param_with_func(input, group_commands[i], roster_group_autocomplete);
-                if (result) {
-                    return result;
-                }
-            }
-        }
-
-        result = autocomplete_param_with_ac(input, "/who", who_roster_ac, TRUE);
-        if (result) {
-            return result;
-        }
-    }
-
-    return result;
-}
-
-static char*
-_roster_autocomplete(ProfWin *window, const char *const input)
-{
-    char *result = NULL;
-    result = autocomplete_param_with_ac(input, "/roster room private char", roster_char_ac, TRUE);
-    if (result) {
-        return result;
-    }
-    result = autocomplete_param_with_ac(input, "/roster room private", roster_header_ac, TRUE);
-    if (result) {
-        return result;
-    }
-    result = autocomplete_param_with_ac(input, "/roster header char", roster_char_ac, TRUE);
-    if (result) {
-        return result;
-    }
-    result = autocomplete_param_with_ac(input, "/roster contact char", roster_char_ac, TRUE);
-    if (result) {
-        return result;
-    }
-    result = autocomplete_param_with_ac(input, "/roster room char", roster_char_ac, TRUE);
-    if (result) {
-        return result;
-    }
-    result = autocomplete_param_with_ac(input, "/roster private char", roster_char_ac, TRUE);
-    if (result) {
-        return result;
-    }
-    result = autocomplete_param_with_ac(input, "/roster resource char", roster_char_ac, TRUE);
-    if (result) {
-        return result;
-    }
-    result = autocomplete_param_with_func(input, "/roster resource join", prefs_autocomplete_boolean_choice);
-    if (result) {
-        return result;
-    }
-    result = autocomplete_param_with_ac(input, "/roster room position", roster_room_position_ac, TRUE);
-    if (result) {
-        return result;
-    }
-    result = autocomplete_param_with_ac(input, "/roster room by", roster_room_by_ac, TRUE);
-    if (result) {
-        return result;
-    }
-    result = autocomplete_param_with_ac(input, "/roster room order", roster_room_order_ac, TRUE);
-    if (result) {
-        return result;
-    }
-    result = autocomplete_param_with_ac(input, "/roster room unread", roster_unread_ac, TRUE);
-    if (result) {
-        return result;
-    }
-    result = autocomplete_param_with_func(input, "/roster count zero", prefs_autocomplete_boolean_choice);
-    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);
-        if (result) {
-            return result;
-        }
-        result = autocomplete_param_with_func(input, "/roster clearnick", roster_barejid_autocomplete);
-        if (result) {
-            return result;
-        }
-        result = autocomplete_param_with_func(input, "/roster remove", roster_barejid_autocomplete);
-        if (result) {
-            return result;
-        }
-    }
-
-    result = autocomplete_param_with_ac(input, "/roster remove_all", roster_remove_all_ac, TRUE);
-    if (result) {
-        return result;
-    }
-    result = autocomplete_param_with_ac(input, "/roster show", roster_show_ac, TRUE);
-    if (result) {
-        return result;
-    }
-    result = autocomplete_param_with_ac(input, "/roster hide", roster_show_ac, TRUE);
-    if (result) {
-        return result;
-    }
-    result = autocomplete_param_with_ac(input, "/roster by", roster_by_ac, TRUE);
-    if (result) {
-        return result;
-    }
-    result = autocomplete_param_with_ac(input, "/roster count", roster_count_ac, TRUE);
-    if (result) {
-        return result;
-    }
-    result = autocomplete_param_with_ac(input, "/roster order", roster_order_ac, TRUE);
-    if (result) {
-        return result;
-    }
-    result = autocomplete_param_with_ac(input, "/roster unread", roster_unread_ac, TRUE);
-    if (result) {
-        return result;
-    }
-    result = autocomplete_param_with_ac(input, "/roster room", roster_room_ac, TRUE);
-    if (result) {
-        return result;
-    }
-    result = autocomplete_param_with_func(input, "/roster wrap", prefs_autocomplete_boolean_choice);
-    if (result) {
-        return result;
-    }
-    result = autocomplete_param_with_ac(input, "/roster header", roster_header_ac, TRUE);
-    if (result) {
-        return result;
-    }
-    result = autocomplete_param_with_ac(input, "/roster contact", roster_contact_ac, TRUE);
-    if (result) {
-        return result;
-    }
-    result = autocomplete_param_with_ac(input, "/roster resource", roster_resource_ac, TRUE);
-    if (result) {
-        return result;
-    }
-    result = autocomplete_param_with_ac(input, "/roster presence", roster_presence_ac, TRUE);
-    if (result) {
-        return result;
-    }
-    result = autocomplete_param_with_ac(input, "/roster private", roster_private_ac, TRUE);
-    if (result) {
-        return result;
-    }
-    result = autocomplete_param_with_ac(input, "/roster", roster_ac, TRUE);
-    if (result) {
-        return result;
-    }
-
-    return NULL;
-}
-
-static char*
-_group_autocomplete(ProfWin *window, const char *const input)
-{
-    char *result = NULL;
-
-    jabber_conn_status_t conn_status = connection_get_status();
-
-    if (conn_status == JABBER_CONNECTED) {
-        result = autocomplete_param_with_func(input, "/group show", roster_group_autocomplete);
-        if (result) {
-            return result;
-        }
-        result = autocomplete_param_no_with_func(input, "/group add", 4, roster_contact_autocomplete);
-        if (result) {
-            return result;
-        }
-        result = autocomplete_param_no_with_func(input, "/group remove", 4, roster_contact_autocomplete);
-        if (result) {
-            return result;
-        }
-        result = autocomplete_param_with_func(input, "/group add", roster_group_autocomplete);
-        if (result) {
-            return result;
-        }
-        result = autocomplete_param_with_func(input, "/group remove", roster_group_autocomplete);
-        if (result) {
-            return result;
-        }
-    }
-
-    result = autocomplete_param_with_ac(input, "/group", group_ac, TRUE);
-    if (result) {
-        return result;
-    }
-
-    return NULL;
-}
-
-static char*
-_blocked_autocomplete(ProfWin *window, const char *const input)
-{
-    char *result = NULL;
-
-    result = autocomplete_param_with_func(input, "/blocked remove", blocked_ac_find);
-    if (result) {
-        return result;
-    }
-
-    result = autocomplete_param_with_ac(input, "/blocked", blocked_ac, FALSE);
-    if (result) {
-        return result;
-    }
-
-    return NULL;
-}
-
-
-static char*
-_bookmark_autocomplete(ProfWin *window, const char *const input)
-{
-    char *found = NULL;
-
-    gboolean result;
-    gchar **args = parse_args(input, 3, 8, &result);
-    gboolean handle_options = result && (g_strv_length(args) > 2);
-
-    if (handle_options && ((strcmp(args[0], "add") == 0) || (strcmp(args[0], "update") == 0)) ) {
-        GString *beginning = g_string_new("/bookmark");
-        gboolean autojoin = FALSE;
-        int num_args = g_strv_length(args);
-
-        g_string_append(beginning, " ");
-        g_string_append(beginning, args[0]);
-        g_string_append(beginning, " ");
-        g_string_append(beginning, args[1]);
-        if (num_args == 4 && g_strcmp0(args[2], "autojoin") == 0) {
-            g_string_append(beginning, " ");
-            g_string_append(beginning, args[2]);
-            autojoin = TRUE;
-        }
-
-        if (num_args > 4) {
-            g_string_append(beginning, " ");
-            g_string_append(beginning, args[2]);
-            g_string_append(beginning, " ");
-            g_string_append(beginning, args[3]);
-            if (num_args == 6 && g_strcmp0(args[4], "autojoin") == 0) {
-                g_string_append(beginning, " ");
-                g_string_append(beginning, args[4]);
-                autojoin = TRUE;
-            }
-        }
-
-        if (num_args > 6) {
-            g_string_append(beginning, " ");
-            g_string_append(beginning, args[4]);
-            g_string_append(beginning, " ");
-            g_string_append(beginning, args[5]);
-            if (num_args == 8 && g_strcmp0(args[6], "autojoin") == 0) {
-                g_string_append(beginning, " ");
-                g_string_append(beginning, args[6]);
-                autojoin = TRUE;
-            }
-        }
-
-        if (autojoin) {
-            found = autocomplete_param_with_func(input, beginning->str, prefs_autocomplete_boolean_choice);
-        } else {
-            found = autocomplete_param_with_ac(input, beginning->str, bookmark_property_ac, TRUE);
-        }
-        g_string_free(beginning, TRUE);
-        if (found) {
-            g_strfreev(args);
-            return found;
-        }
-    }
-
-    g_strfreev(args);
-
-    found = autocomplete_param_with_func(input, "/bookmark remove", bookmark_find);
-    if (found) {
-        return found;
-    }
-    found = autocomplete_param_with_func(input, "/bookmark join", bookmark_find);
-    if (found) {
-        return found;
-    }
-    found = autocomplete_param_with_func(input, "/bookmark update", bookmark_find);
-    if (found) {
-        return found;
-    }
-
-    found = autocomplete_param_with_ac(input, "/bookmark", bookmark_ac, TRUE);
-    return found;
-}
-
-static char*
-_notify_autocomplete(ProfWin *window, const char *const input)
-{
-    int i = 0;
-    char *result = NULL;
-
-    result = autocomplete_param_with_func(input, "/notify room trigger remove", prefs_autocomplete_room_trigger);
-    if (result) {
-        return result;
-    }
-
-    gchar *boolean_choices1[] = { "/notify room current", "/notify chat current", "/notify typing current",
-        "/notify room text", "/notify chat text" };
-    for (i = 0; i < ARRAY_SIZE(boolean_choices1); i++) {
-        result = autocomplete_param_with_func(input, boolean_choices1[i], prefs_autocomplete_boolean_choice);
-        if (result) {
-            return result;
-        }
-    }
-
-    result = autocomplete_param_with_ac(input, "/notify room mention", notify_mention_ac, TRUE);
-    if (result) {
-        return result;
-    }
-
-    result = autocomplete_param_with_ac(input, "/notify room trigger", notify_trigger_ac, TRUE);
-    if (result) {
-        return result;
-    }
-
-    result = autocomplete_param_with_ac(input, "/notify room", notify_room_ac, TRUE);
-    if (result) {
-        return result;
-    }
-
-    result = autocomplete_param_with_ac(input, "/notify chat", notify_chat_ac, TRUE);
-    if (result) {
-        return result;
-    }
-
-    result = autocomplete_param_with_ac(input, "/notify typing", notify_typing_ac, TRUE);
-    if (result) {
-        return result;
-    }
-
-    gchar *boolean_choices2[] = { "/notify invite", "/notify sub", "/notify mention", "/notify trigger"};
-    for (i = 0; i < ARRAY_SIZE(boolean_choices2); i++) {
-        result = autocomplete_param_with_func(input, boolean_choices2[i], prefs_autocomplete_boolean_choice);
-        if (result) {
-            return result;
-        }
-    }
-
-    result = autocomplete_param_with_ac(input, "/notify", notify_ac, TRUE);
-    if (result) {
-        return result;
-    }
-
-    return NULL;
-}
-
-static char*
-_autoaway_autocomplete(ProfWin *window, const char *const input)
-{
-    char *result = NULL;
-
-    result = autocomplete_param_with_ac(input, "/autoaway mode", autoaway_mode_ac, TRUE);
-    if (result) {
-        return result;
-    }
-
-    result = autocomplete_param_with_ac(input, "/autoaway time", autoaway_presence_ac, TRUE);
-    if (result) {
-        return result;
-    }
-
-    result = autocomplete_param_with_ac(input, "/autoaway message", autoaway_presence_ac, TRUE);
-    if (result) {
-        return result;
-    }
-
-    result = autocomplete_param_with_func(input, "/autoaway check", prefs_autocomplete_boolean_choice);
-    if (result) {
-        return result;
-    }
-    result = autocomplete_param_with_ac(input, "/autoaway", autoaway_ac, TRUE);
-    if (result) {
-        return result;
-    }
-
-    return NULL;
-}
-
-static char*
-_log_autocomplete(ProfWin *window, const char *const input)
-{
-    char *result = NULL;
-
-    result = autocomplete_param_with_func(input, "/log rotate",
-        prefs_autocomplete_boolean_choice);
-    if (result) {
-        return result;
-    }
-    result = autocomplete_param_with_func(input, "/log shared",
-        prefs_autocomplete_boolean_choice);
-    if (result) {
-        return result;
-    }
-    result = autocomplete_param_with_ac(input, "/log", log_ac, TRUE);
-    if (result) {
-        return result;
-    }
-
-    return NULL;
-}
-
-static char*
-_autoconnect_autocomplete(ProfWin *window, const char *const input)
-{
-    char *result = NULL;
-
-    result = autocomplete_param_with_func(input, "/autoconnect set", accounts_find_enabled);
-    if (result) {
-        return result;
-    }
-
-    result = autocomplete_param_with_ac(input, "/autoconnect", autoconnect_ac, TRUE);
-    if (result) {
-        return result;
-    }
-
-    return NULL;
-}
-
-static char*
-_otr_autocomplete(ProfWin *window, const char *const input)
-{
-    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);
-        if (found) {
-            return found;
-        }
-    }
-
-    found = autocomplete_param_with_ac(input, "/otr log", otr_log_ac, TRUE);
-    if (found) {
-        return found;
-    }
-
-    // /otr policy always user@server.com
-    if (conn_status == JABBER_CONNECTED) {
-        gboolean result;
-        gchar **args = parse_args(input, 3, 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, " ");
-            g_string_append(beginning, args[1]);
-
-            found = autocomplete_param_with_func(input, beginning->str, roster_contact_autocomplete);
-            g_string_free(beginning, TRUE);
-            if (found) {
-                g_strfreev(args);
-                return found;
-            }
-        }
-        g_strfreev(args);
-    }
-
-    found = autocomplete_param_with_ac(input, "/otr policy", otr_policy_ac, TRUE);
-    if (found) {
-        return found;
-    }
-
-    found = autocomplete_param_with_ac(input, "/otr", otr_ac, TRUE);
-    if (found) {
-        return found;
-    }
-
-    return NULL;
-}
-
-static char*
-_pgp_autocomplete(ProfWin *window, const char *const input)
-{
-    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);
-        if (found) {
-            return found;
-        }
-    }
-
-    found = autocomplete_param_with_ac(input, "/pgp log", pgp_log_ac, TRUE);
-    if (found) {
-        return found;
-    }
-
-#ifdef HAVE_LIBGPGME
-    gboolean result;
-    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);
-        g_string_free(beginning, TRUE);
-        if (found) {
-            g_strfreev(args);
-            return found;
-        }
-    }
-    g_strfreev(args);
-#endif
-
-    if (conn_status == JABBER_CONNECTED) {
-        found = autocomplete_param_with_func(input, "/pgp setkey", roster_barejid_autocomplete);
-        if (found) {
-            return found;
-        }
-    }
-
-    found = autocomplete_param_with_ac(input, "/pgp", pgp_ac, TRUE);
-    if (found) {
-        return found;
-    }
-
-    return NULL;
-}
-
-static char*
-_plugins_autocomplete(ProfWin *window, const char *const input)
-{
-    char *result = NULL;
-    if ((strncmp(input, "/plugins load ", 14) == 0) && (strlen(input) > 14)) {
-        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);
-        if (result) {
-            return result;
-        }
-    }
-    result = autocomplete_param_with_ac(input, "/plugins", plugins_ac, TRUE);
-    if (result) {
-        return result;
-    }
-
-    return NULL;
-}
-
-static char*
-_theme_autocomplete(ProfWin *window, const char *const input)
-{
-    char *result = NULL;
-    if ((strncmp(input, "/theme load ", 12) == 0) && (strlen(input) > 12)) {
-        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);
-        if (result) {
-            return result;
-        }
-    }
-    result = autocomplete_param_with_ac(input, "/theme", theme_ac, TRUE);
-    if (result) {
-        return result;
-    }
-
-    return NULL;
-}
-
-static char*
-_script_autocomplete_func(const char *const prefix)
-{
-    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);
-}
-
-
-static char*
-_script_autocomplete(ProfWin *window, const char *const input)
-{
-    char *result = NULL;
-    if ((strncmp(input, "/script show ", 13) == 0) && (strlen(input) > 13)) {
-        result = autocomplete_param_with_func(input, "/script show", _script_autocomplete_func);
-        if (result) {
-            return result;
-        }
-    }
-
-    if ((strncmp(input, "/script run ", 12) == 0) && (strlen(input) > 12)) {
-        result = autocomplete_param_with_func(input, "/script run", _script_autocomplete_func);
-        if (result) {
-            return result;
-        }
-    }
-
-    result = autocomplete_param_with_ac(input, "/script", script_ac, TRUE);
-    if (result) {
-        return result;
-    }
-
-    return NULL;
-}
-
-static char*
-_resource_autocomplete(ProfWin *window, const char *const input)
-{
-    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);
-            if (found) {
-                return found;
-            }
-        }
-    }
-
-    found = autocomplete_param_with_func(input, "/resource title", prefs_autocomplete_boolean_choice);
-    if (found) {
-        return found;
-    }
-
-    found = autocomplete_param_with_func(input, "/resource message", prefs_autocomplete_boolean_choice);
-    if (found) {
-        return found;
-    }
-
-    found = autocomplete_param_with_ac(input, "/resource", resource_ac, FALSE);
-    if (found) {
-        return found;
-    }
-
-    return NULL;
-}
-
-static char*
-_titlebar_autocomplete(ProfWin *window, const char *const input)
-{
-    char *found = NULL;
-
-    found = autocomplete_param_with_func(input, "/titlebar show", prefs_autocomplete_boolean_choice);
-    if (found) {
-        return found;
-    }
-
-    found = autocomplete_param_with_func(input, "/titlebar goodbye", prefs_autocomplete_boolean_choice);
-    if (found) {
-        return found;
-    }
-
-    found = autocomplete_param_with_ac(input, "/titlebar", titlebar_ac, FALSE);
-    if (found) {
-        return found;
-    }
-
-    return NULL;
-}
-
-static char*
-_inpblock_autocomplete(ProfWin *window, const char *const input)
-{
-    char *found = NULL;
-
-    found = autocomplete_param_with_func(input, "/inpblock dynamic", prefs_autocomplete_boolean_choice);
-    if (found) {
-        return found;
-    }
-
-    found = autocomplete_param_with_ac(input, "/inpblock", inpblock_ac, FALSE);
-    if (found) {
-        return found;
-    }
-
-    return NULL;
-}
-
-static char*
-_form_autocomplete(ProfWin *window, const char *const input)
-{
-    if (window->type != WIN_MUC_CONFIG) {
-        return NULL;
-    }
-
-    char *found = NULL;
-
-    ProfMucConfWin *confwin = (ProfMucConfWin*)window;
-    DataForm *form = confwin->form;
-    if (form) {
-        found = autocomplete_param_with_ac(input, "/form help", form->tag_ac, TRUE);
-        if (found) {
-            return found;
-        }
-    }
-
-    found = autocomplete_param_with_ac(input, "/form", form_ac, TRUE);
-    if (found) {
-        return found;
-    }
-
-    return NULL;
-}
-
-static char*
-_form_field_autocomplete(ProfWin *window, const char *const input)
-{
-    if (window->type != WIN_MUC_CONFIG) {
-        return NULL;
-    }
-
-    char *found = NULL;
-
-    ProfMucConfWin *confwin = (ProfMucConfWin*)window;
-    DataForm *form = confwin->form;
-    if (form == NULL) {
-        return NULL;
-    }
-
-    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);
-
-            } else if ((g_strcmp0(split[1], "remove") == 0) && field_type == FIELD_TEXT_MULTI) {
-                found = autocomplete_param_with_ac(input, beginning->str, value_ac, TRUE);
-
-            } else if ((g_strcmp0(split[1], "remove") == 0) && field_type == FIELD_JID_MULTI) {
-                found = autocomplete_param_with_ac(input, beginning->str, value_ac, TRUE);
-            }
-
-            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);
-                    break;
-                case FIELD_LIST_SINGLE:
-                    found = autocomplete_param_with_ac(input, split[0], value_ac, TRUE);
-                    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);
-                    break;
-                default:
-                    break;
-            }
-        }
-    }
-
-    g_strfreev(split);
-
-    return found;
-}
-
-static char*
-_occupants_autocomplete(ProfWin *window, const char *const input)
-{
-    char *found = NULL;
-
-    found = autocomplete_param_with_ac(input, "/occupants default show", occupants_show_ac, TRUE);
-    if (found) {
-        return found;
-    }
-
-    found = autocomplete_param_with_ac(input, "/occupants default hide", occupants_show_ac, TRUE);
-    if (found) {
-        return found;
-    }
-
-    found = autocomplete_param_with_ac(input, "/occupants default", occupants_default_ac, TRUE);
-    if (found) {
-        return found;
-    }
-
-    found = autocomplete_param_with_ac(input, "/occupants show", occupants_show_ac, TRUE);
-    if (found) {
-        return found;
-    }
-
-    found = autocomplete_param_with_ac(input, "/occupants hide", occupants_show_ac, TRUE);
-    if (found) {
-        return found;
-    }
-
-    found = autocomplete_param_with_ac(input, "/occupants", occupants_ac, TRUE);
-    if (found) {
-        return found;
-    }
-
-    return NULL;
-}
-
-static char*
-_time_autocomplete(ProfWin *window, const char *const input)
-{
-    char *found = NULL;
-
-    found = autocomplete_param_with_ac(input, "/time statusbar", time_format_ac, TRUE);
-    if (found) {
-        return found;
-    }
-
-    found = autocomplete_param_with_ac(input, "/time lastactivity", time_format_ac, TRUE);
-    if (found) {
-        return found;
-    }
-
-    found = autocomplete_param_with_ac(input, "/time console", time_format_ac, TRUE);
-    if (found) {
-        return found;
-    }
-
-    found = autocomplete_param_with_ac(input, "/time chat", time_format_ac, TRUE);
-    if (found) {
-        return found;
-    }
-
-    found = autocomplete_param_with_ac(input, "/time muc", time_format_ac, TRUE);
-    if (found) {
-        return found;
-    }
-
-    found = autocomplete_param_with_ac(input, "/time mucconfig", time_format_ac, TRUE);
-    if (found) {
-        return found;
-    }
-
-    found = autocomplete_param_with_ac(input, "/time private", time_format_ac, TRUE);
-    if (found) {
-        return found;
-    }
-
-    found = autocomplete_param_with_ac(input, "/time xml", time_format_ac, TRUE);
-    if (found) {
-        return found;
-    }
-
-    found = autocomplete_param_with_ac(input, "/time", time_ac, TRUE);
-    if (found) {
-        return found;
-    }
-
-    return NULL;
-}
-
-static char*
-_kick_autocomplete(ProfWin *window, const char *const input)
-{
-    char *result = NULL;
-
-    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, "/kick", nick_ac, TRUE);
-            if (result) {
-                return result;
-            }
-        }
-    }
-
-    return result;
-}
-
-static char*
-_ban_autocomplete(ProfWin *window, const char *const input)
-{
-    char *result = NULL;
-
-    if (window->type == WIN_MUC) {
-        ProfMucWin *mucwin = (ProfMucWin*)window;
-        assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
-        Autocomplete jid_ac = muc_roster_jid_ac(mucwin->roomjid);
-
-        if (jid_ac) {
-            result = autocomplete_param_with_ac(input, "/ban", jid_ac, TRUE);
-            if (result) {
-                return result;
-            }
-        }
-    }
-
-    return result;
-}
-
-static char*
-_affiliation_autocomplete(ProfWin *window, const char *const input)
-{
-    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);
-
-        gchar **args = parse_args(input, 3, 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, " ");
-            g_string_append(beginning, args[1]);
-
-            result = autocomplete_param_with_ac(input, beginning->str, jid_ac, TRUE);
-            g_string_free(beginning, TRUE);
-            if (result) {
-                g_strfreev(args);
-                return result;
-            }
-        }
-
-        g_strfreev(args);
-    }
-
-    result = autocomplete_param_with_ac(input, "/affiliation set", affiliation_ac, TRUE);
-    if (result) {
-        return result;
-    }
-
-    result = autocomplete_param_with_ac(input, "/affiliation list", affiliation_ac, TRUE);
-    if (result) {
-        return result;
-    }
-
-    result = autocomplete_param_with_ac(input, "/affiliation", privilege_cmd_ac, TRUE);
-    if (result) {
-        return result;
-    }
-
-    return result;
-}
-
-static char*
-_role_autocomplete(ProfWin *window, const char *const input)
-{
-    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);
-
-        gchar **args = parse_args(input, 3, 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, " ");
-            g_string_append(beginning, args[1]);
-
-            result = autocomplete_param_with_ac(input, beginning->str, nick_ac, TRUE);
-            g_string_free(beginning, TRUE);
-            if (result) {
-                g_strfreev(args);
-                return result;
-            }
-        }
-
-        g_strfreev(args);
-    }
-
-    result = autocomplete_param_with_ac(input, "/role set", role_ac, TRUE);
-    if (result) {
-        return result;
-    }
-
-    result = autocomplete_param_with_ac(input, "/role list", role_ac, TRUE);
-    if (result) {
-        return result;
-    }
-
-    result = autocomplete_param_with_ac(input, "/role", privilege_cmd_ac, TRUE);
-    if (result) {
-        return result;
-    }
-
-    return result;
-}
-
-static char*
-_statuses_autocomplete(ProfWin *window, const char *const input)
-{
-    char *result = NULL;
-
-    result = autocomplete_param_with_ac(input, "/statuses console", statuses_setting_ac, TRUE);
-    if (result) {
-        return result;
-    }
-
-    result = autocomplete_param_with_ac(input, "/statuses chat", statuses_setting_ac, TRUE);
-    if (result) {
-        return result;
-    }
-
-    result = autocomplete_param_with_ac(input, "/statuses muc", statuses_setting_ac, TRUE);
-    if (result) {
-        return result;
-    }
-
-    result = autocomplete_param_with_ac(input, "/statuses", statuses_ac, TRUE);
-    if (result) {
-        return result;
-    }
-
-    return NULL;
-}
-
-static char*
-_wins_autocomplete(ProfWin *window, const char *const input)
-{
-    char *result = NULL;
-
-    result = autocomplete_param_with_func(input, "/wins autotidy", prefs_autocomplete_boolean_choice);
-    if (result) {
-        return result;
-    }
-
-    result = autocomplete_param_with_ac(input, "/wins", wins_ac, TRUE);
-    if (result) {
-        return result;
-    }
-
-    return NULL;
-}
-
-static char*
-_tls_autocomplete(ProfWin *window, const char *const input)
-{
-    char *result = NULL;
-
-    result = autocomplete_param_with_func(input, "/tls revoke", tlscerts_complete);
-    if (result) {
-        return result;
-    }
-
-    result = autocomplete_param_with_func(input, "/tls cert", tlscerts_complete);
-    if (result) {
-        return result;
-    }
-
-    result = autocomplete_param_with_ac(input, "/tls certpath", tls_certpath_ac, TRUE);
-    if (result) {
-        return result;
-    }
-
-    result = autocomplete_param_with_func(input, "/tls show", prefs_autocomplete_boolean_choice);
-    if (result) {
-        return result;
-    }
-
-    result = autocomplete_param_with_ac(input, "/tls", tls_ac, TRUE);
-    if (result) {
-        return result;
-    }
-
-    return result;
-}
-
-static char*
-_receipts_autocomplete(ProfWin *window, const char *const input)
-{
-    char *result = NULL;
-
-    result = autocomplete_param_with_func(input, "/receipts send", prefs_autocomplete_boolean_choice);
-    if (result) {
-        return result;
-    }
-
-    result = autocomplete_param_with_func(input, "/receipts request", prefs_autocomplete_boolean_choice);
-    if (result) {
-        return result;
-    }
-
-    result = autocomplete_param_with_ac(input, "/receipts", receipts_ac, TRUE);
-    if (result) {
-        return result;
-    }
-
-    return NULL;
-}
-
-static char*
-_alias_autocomplete(ProfWin *window, const char *const input)
-{
-    char *result = NULL;
-
-    result = autocomplete_param_with_ac(input, "/alias remove", aliases_ac, TRUE);
-    if (result) {
-        return result;
-    }
-
-    result = autocomplete_param_with_ac(input, "/alias", alias_ac, TRUE);
-    if (result) {
-        return result;
-    }
-
-    return NULL;
-}
-
-static char*
-_connect_autocomplete(ProfWin *window, const char *const input)
-{
-    char *found = NULL;
-    gboolean result = FALSE;
-
-    gchar **args = parse_args(input, 2, 6, &result);
-
-    if ((strncmp(input, "/connect", 8) == 0) && (result == TRUE)) {
-        GString *beginning = g_string_new("/connect ");
-        g_string_append(beginning, args[0]);
-        if (args[1] && args[2]) {
-            g_string_append(beginning, " ");
-            g_string_append(beginning, args[1]);
-            g_string_append(beginning, " ");
-            g_string_append(beginning, args[2]);
-            if (args[3] && args[4]) {
-                g_string_append(beginning, " ");
-                g_string_append(beginning, args[3]);
-                g_string_append(beginning, " ");
-                g_string_append(beginning, args[4]);
-            }
-        }
-        found = autocomplete_param_with_ac(input, beginning->str, connect_property_ac, TRUE);
-        g_string_free(beginning, TRUE);
-        if (found) {
-            g_strfreev(args);
-            return found;
-        }
-    }
-
-    g_strfreev(args);
-
-    result = FALSE;
-    args = parse_args(input, 2, 7, &result);
-
-    if ((strncmp(input, "/connect", 8) == 0) && (result == TRUE)) {
-        GString *beginning = g_string_new("/connect ");
-        g_string_append(beginning, args[0]);
-        int curr = 0;
-        if (args[1]) {
-            g_string_append(beginning, " ");
-            g_string_append(beginning, args[1]);
-            curr = 1;
-            if (args[2] && args[3]) {
-                g_string_append(beginning, " ");
-                g_string_append(beginning, args[2]);
-                g_string_append(beginning, " ");
-                g_string_append(beginning, args[3]);
-                curr = 3;
-                if (args[4] && args[5]) {
-                    g_string_append(beginning, " ");
-                    g_string_append(beginning, args[4]);
-                    g_string_append(beginning, " ");
-                    g_string_append(beginning, args[5]);
-                    curr = 5;
-                }
-            }
-        }
-        if (curr != 0 && (g_strcmp0(args[curr], "tls") == 0)) {
-            found = autocomplete_param_with_ac(input, beginning->str, tls_property_ac, TRUE);
-            g_string_free(beginning, TRUE);
-            if (found) {
-                g_strfreev(args);
-                return found;
-            }
-        } else {
-            g_string_free(beginning, TRUE);
-        }
-    }
-
-    g_strfreev(args);
-
-    found = autocomplete_param_with_func(input, "/connect", accounts_find_enabled);
-    if (found) {
-        return found;
-    }
-
-    return NULL;
-}
-
-static char*
-_help_autocomplete(ProfWin *window, const char *const input)
-{
-    char *result = NULL;
-
-    result = autocomplete_param_with_ac(input, "/help commands", help_commands_ac, TRUE);
-    if (result) {
-        return result;
-    }
-
-    result = autocomplete_param_with_ac(input, "/help", help_ac, TRUE);
-    if (result) {
-        return result;
-    }
-
-    return NULL;
-}
-
-static char*
-_join_autocomplete(ProfWin *window, const char *const input)
-{
-    char *found = NULL;
-    gboolean result = FALSE;
-
-    found = autocomplete_param_with_func(input, "/join", bookmark_find);
-    if (found) {
-        return found;
-    }
-
-    gchar **args = parse_args(input, 2, 4, &result);
-
-    if ((strncmp(input, "/join", 5) == 0) && (result == TRUE)) {
-        GString *beginning = g_string_new("/join ");
-        g_string_append(beginning, args[0]);
-        if (args[1] && args[2]) {
-            g_string_append(beginning, " ");
-            g_string_append(beginning, args[1]);
-            g_string_append(beginning, " ");
-            g_string_append(beginning, args[2]);
-        }
-        found = autocomplete_param_with_ac(input, beginning->str, join_property_ac, TRUE);
-        g_string_free(beginning, TRUE);
-        if (found) {
-            g_strfreev(args);
-            return found;
-        }
-    }
-
-    g_strfreev(args);
-
-    return NULL;
-}
-
-static char*
-_console_autocomplete(ProfWin *window, const char *const input)
-{
-    char *result = NULL;
-
-    result = autocomplete_param_with_ac(input, "/console chat", console_msg_ac, TRUE);
-    if (result) {
-        return result;
-    }
-    result = autocomplete_param_with_ac(input, "/console muc", console_msg_ac, TRUE);
-    if (result) {
-        return result;
-    }
-    result = autocomplete_param_with_ac(input, "/console private", console_msg_ac, TRUE);
-    if (result) {
-        return result;
-    }
-
-    result = autocomplete_param_with_ac(input, "/console", console_ac, TRUE);
-    if (result) {
-        return result;
-    }
-
-    return NULL;
-}
-
-static char*
-_win_autocomplete(ProfWin *window, const char *const input)
-{
-    char *found = NULL;
-
-    found = autocomplete_param_with_func(input, "/win", win_autocomplete);
-    if (found) {
-        return found;
-    }
-
-    return NULL;
-}
-
-static char*
-_close_autocomplete(ProfWin *window, const char *const input)
-{
-    char *found = NULL;
-
-    found = autocomplete_param_with_func(input, "/close", win_close_autocomplete);
-    if (found) {
-        return found;
-    }
-
-    return NULL;
-}
-
-static char*
-_sendfile_autocomplete(ProfWin *window, const char *const input)
-{
-    static char* last_directory = NULL;
-
-    unsigned int output_off = 0;
-
-    char *result = NULL;
-    char *tmp;
-
-    // strip command
-    char *inpcp = (char*)input + 9;
-    while (*inpcp == ' ') {
-        inpcp++;
-    }
-
-    inpcp = strdup(inpcp);
-
-    // strip quotes
-    if (*inpcp == '"') {
-        tmp = strchr(inpcp+1, '"');
-        if (tmp) {
-            *tmp = '\0';
-        }
-        tmp = strdup(inpcp+1);
-        free(inpcp);
-        inpcp = tmp;
-    }
-
-    // expand ~ to $HOME
-    if (inpcp[0] == '~' && inpcp[1] == '/') {
-        if (asprintf(&tmp, "%s/%sfoo", getenv("HOME"), inpcp+2) == -1) {
-            return NULL;
-        }
-        output_off = strlen(getenv("HOME"))+1;
-    } else {
-        if (asprintf(&tmp, "%sfoo", inpcp) == -1) {
-            return NULL;
-        }
-    }
-    free(inpcp);
-    inpcp = tmp;
-
-    char* inpcp2 = strdup(inpcp);
-    char* foofile = strdup(basename(inpcp2));
-    char* directory = strdup(dirname(inpcp));
-    free(inpcp);
-    free(inpcp2);
-
-    if (!last_directory || strcmp(last_directory, directory) != 0) {
-        free(last_directory);
-        last_directory = directory;
-        autocomplete_reset(sendfile_ac);
-
-        struct dirent *dir;
-
-        DIR *d = opendir(directory);
-        if (d) {
-            while ((dir = readdir(d)) != NULL) {
-                if (strcmp(dir->d_name, ".") == 0) {
-                    continue;
-                } else if (strcmp(dir->d_name, "..") == 0) {
-                    continue;
-                } else if (*(dir->d_name) == '.' && *foofile != '.') {
-                    // only show hidden files on explicit request
-                    continue;
-                }
-                char * acstring;
-                if (output_off) {
-                    if (asprintf(&tmp, "%s/%s", directory, dir->d_name) == -1) {
-                        return NULL;
-                    }
-                    if (asprintf(&acstring, "~/%s", tmp+output_off) == -1) {
-                        return NULL;
-                    }
-                    free(tmp);
-                } else if (strcmp(directory, "/") == 0) {
-                    if (asprintf(&acstring, "/%s", dir->d_name) == -1) {
-                        return NULL;
-                    }
-                } else {
-                    if (asprintf(&acstring, "%s/%s", directory, dir->d_name) == -1) {
-                        return NULL;
-                    }
-                }
-                autocomplete_add(sendfile_ac, acstring);
-                free(acstring);
-            }
-            closedir(d);
-        }
-    } else {
-        free(foofile);
-        free(directory);
-    }
-
-    result = autocomplete_param_with_ac(input, "/sendfile", sendfile_ac, TRUE);
-    if (result) {
-        return result;
-    }
-
-    return NULL;
-}
-
-
-static char*
-_subject_autocomplete(ProfWin *window, const char *const input)
-{
-    char *result = NULL;
-
-    if (window->type == WIN_MUC) {
-        if ((g_strcmp0(input, "/subject e") == 0)
-                || (g_strcmp0(input, "/subject ed") == 0)
-                || (g_strcmp0(input, "/subject edi") == 0)
-                || (g_strcmp0(input, "/subject edit") == 0)
-                || (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) {
-                GString *result_str = g_string_new("/subject edit \"");
-                g_string_append(result_str, subject);
-                g_string_append(result_str, "\"");
-
-                result = result_str->str;
-                g_string_free(result_str, FALSE);
-            }
-        }
-    }
-    if (result) {
-        return result;
-    }
-
-    result = autocomplete_param_with_ac(input, "/subject", subject_ac, TRUE);
-    if (result) {
-        return result;
-    }
-
-    return NULL;
-}
-
-static char*
-_account_autocomplete(ProfWin *window, const char *const input)
-{
-    char *found = NULL;
-    gboolean result = FALSE;
-
-    gchar **args = parse_args(input, 3, 4, &result);
-
-    if ((strncmp(input, "/account set", 12) == 0) && (result == TRUE)) {
-        GString *beginning = g_string_new("/account set ");
-        g_string_append(beginning, args[1]);
-        if ((g_strv_length(args) > 3) && (g_strcmp0(args[2], "otr")) == 0) {
-            g_string_append(beginning, " ");
-            g_string_append(beginning, args[2]);
-            found = autocomplete_param_with_ac(input, beginning->str, otr_policy_ac, TRUE);
-            g_string_free(beginning, TRUE);
-            if (found) {
-                g_strfreev(args);
-                return found;
-            }
-        } else if ((g_strv_length(args) > 3) && (g_strcmp0(args[2], "status")) == 0) {
-            g_string_append(beginning, " ");
-            g_string_append(beginning, args[2]);
-            found = autocomplete_param_with_ac(input, beginning->str, account_status_ac, TRUE);
-            g_string_free(beginning, TRUE);
-            if (found) {
-                g_strfreev(args);
-                return found;
-            }
-        } else if ((g_strv_length(args) > 3) && (g_strcmp0(args[2], "tls")) == 0) {
-            g_string_append(beginning, " ");
-            g_string_append(beginning, args[2]);
-            found = autocomplete_param_with_ac(input, beginning->str, tls_property_ac, TRUE);
-            g_string_free(beginning, TRUE);
-            if (found) {
-                g_strfreev(args);
-                return found;
-            }
-        } else if ((g_strv_length(args) > 3) && (g_strcmp0(args[2], "startscript")) == 0) {
-            g_string_append(beginning, " ");
-            g_string_append(beginning, args[2]);
-            found = autocomplete_param_with_func(input, beginning->str, _script_autocomplete_func);
-            g_string_free(beginning, TRUE);
-            if (found) {
-                g_strfreev(args);
-                return found;
-            }
-        } else if ((g_strv_length(args) > 3) && (g_strcmp0(args[2], "theme")) == 0) {
-            g_string_append(beginning, " ");
-            g_string_append(beginning, 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);
-            g_string_free(beginning, TRUE);
-            if (found) {
-                return found;
-            }
-#ifdef HAVE_LIBGPGME
-        } else if ((g_strv_length(args) > 3) && (g_strcmp0(args[2], "pgpkeyid")) == 0) {
-            g_string_append(beginning, " ");
-            g_string_append(beginning, args[2]);
-            found = autocomplete_param_with_func(input, beginning->str, p_gpg_autocomplete_key);
-            g_string_free(beginning, TRUE);
-            if (found) {
-                g_strfreev(args);
-                return found;
-            }
-#endif
-        } else {
-            found = autocomplete_param_with_ac(input, beginning->str, account_set_ac, TRUE);
-            g_string_free(beginning, TRUE);
-            if (found) {
-                g_strfreev(args);
-                return found;
-            }
-        }
-    }
-
-    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);
-        g_string_free(beginning, TRUE);
-        if (found) {
-            g_strfreev(args);
-            return found;
-        }
-    }
-
-    g_strfreev(args);
-
-    found = autocomplete_param_with_ac(input, "/account default", account_default_ac, TRUE);
-    if(found){
-        return found;
-    }
-
-    int i = 0;
-    gchar *account_choice[] = { "/account set", "/account show", "/account enable",
-        "/account disable", "/account rename", "/account clear", "/account remove",
-        "/account default set" };
-
-    for (i = 0; i < ARRAY_SIZE(account_choice); i++) {
-        found = autocomplete_param_with_func(input, account_choice[i], accounts_find_all);
-        if (found) {
-            return found;
-        }
-    }
-
-    found = autocomplete_param_with_ac(input, "/account", account_ac, TRUE);
-    return found;
-}
-
 static int
 _cmp_command(Command *cmd1, Command *cmd2)
 {
diff --git a/src/command/command.h b/src/command/command.h
index 34beee86..4764ea4d 100644
--- a/src/command/command.h
+++ b/src/command/command.h
@@ -44,24 +44,12 @@ GHashTable *commands;
 void cmd_init(void);
 void cmd_uninit(void);
 
-char* cmd_autocomplete(ProfWin *window, const char *const input);
-void cmd_reset_autocomplete(ProfWin *window);
-void cmd_help_autocomplete_add(const char *const value);
-void cmd_autocomplete_add(const char *const value);
-void cmd_autocomplete_remove(const char *const value);
-void cmd_autocomplete_add_form_fields(DataForm *form);
-void cmd_autocomplete_remove_form_fields(DataForm *form);
-void cmd_alias_add(char *value);
-void cmd_alias_remove(char *value);
-
 gboolean cmd_valid_tag(const char *const str);
 gboolean cmd_has_tag(Command *pcmd, const char *const tag);
 
 gboolean cmd_process_input(ProfWin *window, char *inp);
 void cmd_execute_connect(ProfWin *window, const char *const account);
 
-gboolean cmd_exists(char *cmd);
-
 GSList* cmd_get_basic_help(void);
 GSList* cmd_get_settings_help(void);
 GSList* cmd_get_presence_help(void);
diff --git a/src/command/commands.c b/src/command/commands.c
index 177c56bb..d4df39b8 100644
--- a/src/command/commands.c
+++ b/src/command/commands.c
@@ -52,6 +52,7 @@
 #include "chat_session.h"
 #include "command/commands.h"
 #include "command/command.h"
+#include "command/cmd_autocomplete.h"
 #include "common.h"
 #include "config/accounts.h"
 #include "config/account.h"
@@ -3882,7 +3883,7 @@ cmd_form(ProfWin *window, const char *const command, gchar **args)
 
     if ((g_strcmp0(args[0], "submit") == 0) || (g_strcmp0(args[0], "cancel") == 0)) {
         if (confwin->form) {
-            cmd_autocomplete_remove_form_fields(confwin->form);
+            cmd_ac_remove_form_fields(confwin->form);
         }
 
         int num = wins_get_num(window);
@@ -4627,14 +4628,14 @@ cmd_alias(ProfWin *window, const char *const command, gchar **args)
                 cons_bad_cmd_usage(command);
                 g_string_free(ac_value, TRUE);
                 return TRUE;
-            } else if (cmd_exists(ac_value->str)) {
+            } else if (cmd_ac_exists(ac_value->str)) {
                 cons_show("Command or alias '%s' already exists.", ac_value->str);
                 g_string_free(ac_value, TRUE);
                 return TRUE;
             } else {
                 prefs_add_alias(alias_p, value);
-                cmd_autocomplete_add(ac_value->str);
-                cmd_alias_add(alias_p);
+                cmd_ac_add(ac_value->str);
+                cmd_ac_add_alias_value(alias_p);
                 cons_show("Command alias added %s -> %s", ac_value->str, value);
                 g_string_free(ac_value, TRUE);
                 return TRUE;
@@ -4655,8 +4656,8 @@ cmd_alias(ProfWin *window, const char *const command, gchar **args)
             } else {
                 GString *ac_value = g_string_new("/");
                 g_string_append(ac_value, alias);
-                cmd_autocomplete_remove(ac_value->str);
-                cmd_alias_remove(alias);
+                cmd_ac_remove(ac_value->str);
+                cmd_ac_remove_alias_value(alias);
                 g_string_free(ac_value, TRUE);
                 cons_show("Command alias removed -> /%s", alias);
             }
diff --git a/src/plugins/callbacks.c b/src/plugins/callbacks.c
index eaca342a..ad09abef 100644
--- a/src/plugins/callbacks.c
+++ b/src/plugins/callbacks.c
@@ -36,6 +36,7 @@
 #include <stdlib.h>
 
 #include "command/command.h"
+#include "command/cmd_autocomplete.h"
 #include "plugins/callbacks.h"
 #include "plugins/plugins.h"
 #include "tools/autocomplete.h"
@@ -72,9 +73,8 @@ void
 callbacks_add_command(PluginCommand *command)
 {
     p_commands = g_slist_append(p_commands, command);
-    cmd_autocomplete_add(command->command_name);
-    cmd_help_autocomplete_add(&command->command_name[1]);
-
+    cmd_ac_add(command->command_name);
+    cmd_ac_add_help(&command->command_name[1]);
 }
 
 void
diff --git a/src/ui/core.c b/src/ui/core.c
index 0b761274..4397044b 100644
--- a/src/ui/core.c
+++ b/src/ui/core.c
@@ -56,6 +56,7 @@
 
 #include "chat_session.h"
 #include "command/command.h"
+#include "command/cmd_autocomplete.h"
 #include "common.h"
 #include "config/preferences.h"
 #include "config/theme.h"
@@ -651,12 +652,12 @@ ui_focus_win(ProfWin *window)
     ProfWin *old_current = wins_get_current();
     if (old_current->type == WIN_MUC_CONFIG) {
         ProfMucConfWin *confwin = (ProfMucConfWin*)old_current;
-        cmd_autocomplete_remove_form_fields(confwin->form);
+        cmd_ac_remove_form_fields(confwin->form);
     }
 
     if (window->type == WIN_MUC_CONFIG) {
         ProfMucConfWin *confwin = (ProfMucConfWin*)window;
-        cmd_autocomplete_add_form_fields(confwin->form);
+        cmd_ac_add_form_fields(confwin->form);
     }
 
     int i = wins_get_num(window);
@@ -679,7 +680,7 @@ ui_close_win(int index)
     if (window && window->type == WIN_MUC_CONFIG) {
         ProfMucConfWin *confwin = (ProfMucConfWin*)window;
         if (confwin->form) {
-            cmd_autocomplete_remove_form_fields(confwin->form);
+            cmd_ac_remove_form_fields(confwin->form);
         }
     }
 
diff --git a/src/ui/inputwin.c b/src/ui/inputwin.c
index 2c7eae34..72f65271 100644
--- a/src/ui/inputwin.c
+++ b/src/ui/inputwin.c
@@ -53,7 +53,7 @@
 #include <ncurses.h>
 #endif
 
-#include "command/command.h"
+#include "command/cmd_autocomplete.h"
 #include "common.h"
 #include "config/accounts.h"
 #include "config/preferences.h"
@@ -452,7 +452,7 @@ _inp_rl_getc(FILE *stream)
     int ch = rl_getc(stream);
     if (_inp_printable(ch)) {
         ProfWin *window = wins_get_current();
-        cmd_reset_autocomplete(window);
+        cmd_ac_reset(window);
     }
     return ch;
 }
@@ -482,7 +482,7 @@ _inp_rl_tab_handler(int count, int key)
         }
     } else if (strncmp(rl_line_buffer, "/", 1) == 0) {
         ProfWin *window = wins_get_current();
-        char *result = cmd_autocomplete(window, rl_line_buffer);
+        char *result = cmd_ac_complete(window, rl_line_buffer);
         if (result) {
             rl_replace_line(result, 1);
             rl_point = rl_end;
diff --git a/tests/unittests/test_cmd_alias.c b/tests/unittests/test_cmd_alias.c
index fd8f824f..8957f558 100644
--- a/tests/unittests/test_cmd_alias.c
+++ b/tests/unittests/test_cmd_alias.c
@@ -15,6 +15,7 @@
 
 #include "command/command.h"
 #include "command/commands.h"
+#include "command/cmd_autocomplete.h"
 
 #define CMD_ALIAS "/alias"
 
@@ -77,7 +78,7 @@ void cmd_alias_add_shows_message_when_exists(void **state)
 
     cmd_init();
     prefs_add_alias("hc", "/help commands");
-    cmd_autocomplete_add("/hc");
+    cmd_ac_add("/hc");
 
     expect_cons_show("Command or alias '/hc' already exists.");