about summary refs log tree commit diff stats
path: root/src/command
diff options
context:
space:
mode:
Diffstat (limited to 'src/command')
-rw-r--r--src/command/command.c589
-rw-r--r--src/command/command.h13
-rw-r--r--src/command/commands.c6
-rw-r--r--src/command/history.c81
-rw-r--r--src/command/history.h40
5 files changed, 340 insertions, 389 deletions
diff --git a/src/command/command.c b/src/command/command.c
index f18191bc..4a8c73e9 100644
--- a/src/command/command.c
+++ b/src/command/command.c
@@ -36,6 +36,7 @@
 #include <errno.h>
 #include <limits.h>
 #include <stdlib.h>
+#include <stdio.h>
 #include <string.h>
 
 #include <glib.h>
@@ -45,7 +46,6 @@
 #include "chat_session.h"
 #include "command/command.h"
 #include "command/commands.h"
-#include "command/history.h"
 #include "common.h"
 #include "config/accounts.h"
 #include "config/preferences.h"
@@ -70,35 +70,40 @@
 
 typedef char*(*autocompleter)(char*, int*);
 
-static void _cmd_complete_parameters(char *input, int *size);
-
-static char * _sub_autocomplete(char *input, int *size);
-static char * _notify_autocomplete(char *input, int *size);
-static char * _theme_autocomplete(char *input, int *size);
-static char * _autoaway_autocomplete(char *input, int *size);
-static char * _autoconnect_autocomplete(char *input, int *size);
-static char * _account_autocomplete(char *input, int *size);
-static char * _who_autocomplete(char *input, int *size);
-static char * _roster_autocomplete(char *input, int *size);
-static char * _group_autocomplete(char *input, int *size);
-static char * _bookmark_autocomplete(char *input, int *size);
-static char * _otr_autocomplete(char *input, int *size);
-static char * _connect_autocomplete(char *input, int *size);
-static char * _statuses_autocomplete(char *input, int *size);
-static char * _alias_autocomplete(char *input, int *size);
-static char * _join_autocomplete(char *input, int *size);
-static char * _log_autocomplete(char *input, int *size);
-static char * _form_autocomplete(char *input, int *size);
-static char * _form_field_autocomplete(char *input, int *size);
-static char * _occupants_autocomplete(char *input, int *size);
-static char * _kick_autocomplete(char *input, int *size);
-static char * _ban_autocomplete(char *input, int *size);
-static char * _affiliation_autocomplete(char *input, int *size);
-static char * _role_autocomplete(char *input, int *size);
-static char * _resource_autocomplete(char *input, int *size);
-static char * _titlebar_autocomplete(char *input, int *size);
-static char * _inpblock_autocomplete(char *input, int *size);
-static char * _strip_quotes_from_names(char *input, int *size);
+static gboolean _cmd_execute(const char * const command, const char * const inp);
+static gboolean _cmd_execute_default(const char * inp);
+static gboolean _cmd_execute_alias(const char * const inp, gboolean *ran);
+
+static char * _cmd_complete_parameters(const char * const input);
+
+static char * _strip_quotes_from_names(const char * const input);
+
+static char * _sub_autocomplete(const char * const input);
+static char * _notify_autocomplete(const char * const input);
+static char * _theme_autocomplete(const char * const input);
+static char * _autoaway_autocomplete(const char * const input);
+static char * _autoconnect_autocomplete(const char * const input);
+static char * _account_autocomplete(const char * const input);
+static char * _who_autocomplete(const char * const input);
+static char * _roster_autocomplete(const char * const input);
+static char * _group_autocomplete(const char * const input);
+static char * _bookmark_autocomplete(const char * const input);
+static char * _otr_autocomplete(const char * const input);
+static char * _connect_autocomplete(const char * const input);
+static char * _statuses_autocomplete(const char * const input);
+static char * _alias_autocomplete(const char * const input);
+static char * _join_autocomplete(const char * const input);
+static char * _log_autocomplete(const char * const input);
+static char * _form_autocomplete(const char * const input);
+static char * _form_field_autocomplete(const char * const input);
+static char * _occupants_autocomplete(const char * const input);
+static char * _kick_autocomplete(const char * const input);
+static char * _ban_autocomplete(const char * const input);
+static char * _affiliation_autocomplete(const char * const input);
+static char * _role_autocomplete(const char * const input);
+static char * _resource_autocomplete(const char * const input);
+static char * _titlebar_autocomplete(const char * const input);
+static char * _inpblock_autocomplete(const char * const input);
 
 GHashTable *commands = NULL;
 
@@ -613,7 +618,7 @@ static struct cmd_t command_defs[] =
         { "/wrap on|off", "Word wrapping.",
         { "/wrap on|off",
           "------------",
-          "Enable or disable word wrapping.",
+          "Enable or disable word wrapping in the main window.",
           NULL } } },
 
     { "/time",
@@ -1139,7 +1144,7 @@ cmd_init(void)
     autocomplete_add(help_ac, "basic");
     autocomplete_add(help_ac, "chatting");
     autocomplete_add(help_ac, "groupchat");
-    autocomplete_add(help_ac, "presence");
+    autocomplete_add(help_ac, "presences");
     autocomplete_add(help_ac, "contacts");
     autocomplete_add(help_ac, "service");
     autocomplete_add(help_ac, "settings");
@@ -1464,10 +1469,6 @@ cmd_init(void)
     autocomplete_add(time_ac, "seconds");
     autocomplete_add(time_ac, "off");
 
-    time_ac = autocomplete_new();
-    autocomplete_add(time_ac, "minutes");
-    autocomplete_add(time_ac, "seconds");
-
     resource_ac = autocomplete_new();
     autocomplete_add(resource_ac, "set");
     autocomplete_add(resource_ac, "off");
@@ -1477,8 +1478,6 @@ cmd_init(void)
     inpblock_ac = autocomplete_new();
     autocomplete_add(inpblock_ac, "timeout");
     autocomplete_add(inpblock_ac, "dynamic");
-
-    cmd_history_init();
 }
 
 void
@@ -1614,30 +1613,26 @@ cmd_alias_remove(char *value)
 }
 
 // Command autocompletion functions
-void
-cmd_autocomplete(char *input, int *size)
+char*
+cmd_autocomplete(const char * const input)
 {
     // autocomplete command
-    if ((strncmp(input, "/", 1) == 0) && (!str_contains(input, *size, ' '))) {
-        int i = 0;
+    if ((strncmp(input, "/", 1) == 0) && (!str_contains(input, strlen(input), ' '))) {
         char *found = NULL;
-        char inp_cpy[*size];
-        for(i = 0; i < *size; i++) {
-            inp_cpy[i] = input[i];
-        }
-        inp_cpy[i] = '\0';
-        found = autocomplete_complete(commands_ac, inp_cpy, TRUE);
+        found = autocomplete_complete(commands_ac, input, TRUE);
         if (found != NULL) {
-            char *auto_msg = strdup(found);
-            ui_replace_input(input, auto_msg, size);
-            free(auto_msg);
-            free(found);
+            return found;
         }
 
     // autocomplete parameters
     } else {
-        _cmd_complete_parameters(input, size);
+        char *found = _cmd_complete_parameters(input);
+        if (found) {
+            return found;
+        }
     }
+
+    return NULL;
 }
 
 void
@@ -1729,10 +1724,54 @@ cmd_reset_autocomplete()
     bookmark_autocomplete_reset();
 }
 
+/*
+ * Take a line of input and process it, return TRUE if profanity is to
+ * continue, FALSE otherwise
+ */
+gboolean
+cmd_process_input(char *inp)
+{
+    log_debug("Input received: %s", inp);
+    gboolean result = FALSE;
+    g_strstrip(inp);
+
+    // add line to history if something typed
+    if (strlen(inp) > 0) {
+        ui_inp_history_append(inp);
+    }
+
+    // just carry on if no input
+    if (strlen(inp) == 0) {
+        result = TRUE;
+
+    // handle command if input starts with a '/'
+    } else if (inp[0] == '/') {
+        char *inp_cpy = strdup(inp);
+        char *command = strtok(inp_cpy, " ");
+        result = _cmd_execute(command, inp);
+        free(inp_cpy);
+
+    // call a default handler if input didn't start with '/'
+    } else {
+        result = _cmd_execute_default(inp);
+    }
+
+    return result;
+}
+
 // Command execution
 
-gboolean
-cmd_execute(const char * const command, const char * const inp)
+void
+cmd_execute_connect(const char * const account)
+{
+    GString *command = g_string_new("/connect ");
+    g_string_append(command, account);
+    cmd_process_input(command->str);
+    g_string_free(command, TRUE);
+}
+
+static gboolean
+_cmd_execute(const char * const command, const char * const inp)
 {
     if (g_str_has_prefix(command, "/field") && ui_current_win_type() == WIN_MUC_CONFIG) {
         gboolean result = FALSE;
@@ -1766,17 +1805,17 @@ cmd_execute(const char * const command, const char * const inp)
         }
     } else {
         gboolean ran_alias = FALSE;
-        gboolean alias_result = cmd_execute_alias(inp, &ran_alias);
+        gboolean alias_result = _cmd_execute_alias(inp, &ran_alias);
         if (!ran_alias) {
-            return cmd_execute_default(inp);
+            return _cmd_execute_default(inp);
         } else {
             return alias_result;
         }
     }
 }
 
-gboolean
-cmd_execute_alias(const char * const inp, gboolean *ran)
+static gboolean
+_cmd_execute_alias(const char * const inp, gboolean *ran)
 {
     if (inp[0] != '/') {
         ran = FALSE;
@@ -1787,7 +1826,7 @@ cmd_execute_alias(const char * const inp, gboolean *ran)
         free(alias);
         if (value != NULL) {
             *ran = TRUE;
-            return process_input(value);
+            return cmd_process_input(value);
         } else {
             *ran = FALSE;
             return TRUE;
@@ -1795,8 +1834,8 @@ cmd_execute_alias(const char * const inp, gboolean *ran)
     }
 }
 
-gboolean
-cmd_execute_default(const char * inp)
+static gboolean
+_cmd_execute_default(const char * inp)
 {
     jabber_conn_status_t status = jabber_get_connection_status();
 
@@ -1905,8 +1944,8 @@ cmd_execute_default(const char * inp)
     return TRUE;
 }
 
-static void
-_cmd_complete_parameters(char *input, int *size)
+static char *
+_cmd_complete_parameters(const char * const input)
 {
     int i;
     char *result = NULL;
@@ -1917,12 +1956,9 @@ _cmd_complete_parameters(char *input, int *size)
         "/vercheck", "/privileges", "/presence", "/wrap" };
 
     for (i = 0; i < ARRAY_SIZE(boolean_choices); i++) {
-        result = autocomplete_param_with_func(input, size, boolean_choices[i],
-            prefs_autocomplete_boolean_choice);
-        if (result != NULL) {
-            ui_replace_input(input, result, size);
-            g_free(result);
-            return;
+        result = autocomplete_param_with_func(input, boolean_choices[i], prefs_autocomplete_boolean_choice);
+        if (result) {
+            return result;
         }
     }
 
@@ -1930,64 +1966,54 @@ _cmd_complete_parameters(char *input, int *size)
     if (ui_current_win_type() == WIN_MUC) {
         ProfMucWin *mucwin = wins_get_current_muc();
         Autocomplete nick_ac = muc_roster_ac(mucwin->roomjid);
-        if (nick_ac != NULL) {
+        if (nick_ac) {
             gchar *nick_choices[] = { "/msg", "/info", "/caps", "/status", "/software" } ;
 
             // Remove quote character before and after names when doing autocomplete
-            input = _strip_quotes_from_names(input, size);
+            char *unquoted = _strip_quotes_from_names(input);
             for (i = 0; i < ARRAY_SIZE(nick_choices); i++) {
-                result = autocomplete_param_with_ac(input, size, nick_choices[i],
-                    nick_ac, TRUE);
-                if (result != NULL) {
-                    ui_replace_input(input, result, size);
-                    g_free(result);
-                    return;
+                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 {
         gchar *contact_choices[] = { "/msg", "/info", "/status" };
         // Remove quote character before and after names when doing autocomplete
-        input = _strip_quotes_from_names(input, size);
+        char *unquoted = _strip_quotes_from_names(input);
         for (i = 0; i < ARRAY_SIZE(contact_choices); i++) {
-            result = autocomplete_param_with_func(input, size, contact_choices[i],
-                roster_contact_autocomplete);
-            if (result != NULL) {
-                ui_replace_input(input, result, size);
-                g_free(result);
-                return;
+            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, size, resource_choices[i],
-                roster_fulljid_autocomplete);
-            if (result != NULL) {
-                ui_replace_input(input, result, size);
-                g_free(result);
-                return;
+            result = autocomplete_param_with_func(input, resource_choices[i], roster_fulljid_autocomplete);
+            if (result) {
+                return result;
             }
         }
     }
 
-    result = autocomplete_param_with_func(input, size, "/invite", roster_contact_autocomplete);
-    if (result != NULL) {
-        ui_replace_input(input, result, size);
-        g_free(result);
-        return;
+    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, size, invite_choices[i],
-            muc_invites_find);
-        if (result != NULL) {
-            ui_replace_input(input, result, size);
-            g_free(result);
-            return;
+        result = autocomplete_param_with_func(input, invite_choices[i], muc_invites_find);
+        if (result) {
+            return result;
         }
     }
 
@@ -1995,11 +2021,9 @@ _cmd_complete_parameters(char *input, int *size)
     Autocomplete completers[] = { help_ac, prefs_ac, disco_ac, close_ac, wins_ac, subject_ac, room_ac, time_ac };
 
     for (i = 0; i < ARRAY_SIZE(cmds); i++) {
-        result = autocomplete_param_with_ac(input, size, cmds[i], completers[i], TRUE);
-        if (result != NULL) {
-            ui_replace_input(input, result, size);
-            g_free(result);
-            return;
+        result = autocomplete_param_with_ac(input, cmds[i], completers[i], TRUE);
+        if (result) {
+            return result;
         }
     }
 
@@ -2030,9 +2054,10 @@ _cmd_complete_parameters(char *input, int *size)
     g_hash_table_insert(ac_funcs, "/titlebar",      _titlebar_autocomplete);
     g_hash_table_insert(ac_funcs, "/inpblock",      _inpblock_autocomplete);
 
-    char parsed[*size+1];
+    int len = strlen(input);
+    char parsed[len+1];
     i = 0;
-    while (i < *size) {
+    while (i < len) {
         if (input[i] == ' ') {
             break;
         } else {
@@ -2042,44 +2067,39 @@ _cmd_complete_parameters(char *input, int *size)
     }
     parsed[i] = '\0';
 
-    char * (*ac_func)(char *, int *) = g_hash_table_lookup(ac_funcs, parsed);
+    char * (*ac_func)(const char * const) = g_hash_table_lookup(ac_funcs, parsed);
     if (ac_func != NULL) {
-        result = ac_func(input, size);
-        if (result != NULL) {
-            ui_replace_input(input, result, size);
-            g_free(result);
+        result = ac_func(input);
+        if (result) {
             g_hash_table_destroy(ac_funcs);
-            return;
+            return result;
         }
     }
     g_hash_table_destroy(ac_funcs);
 
-    input[*size] = '\0';
     if (g_str_has_prefix(input, "/field")) {
-        result = _form_field_autocomplete(input, size);
-        if (result != NULL) {
-            ui_replace_input(input, result, size);
-            g_free(result);
-            return;
+        result = _form_field_autocomplete(input);
+        if (result) {
+            return result;
         }
     }
 
-    return;
+    return NULL;
 }
 
 static char *
-_sub_autocomplete(char *input, int *size)
+_sub_autocomplete(const char * const input)
 {
     char *result = NULL;
-    result = autocomplete_param_with_func(input, size, "/sub allow", presence_sub_request_find);
+    result = autocomplete_param_with_func(input, "/sub allow", presence_sub_request_find);
     if (result != NULL) {
         return result;
     }
-    result = autocomplete_param_with_func(input, size, "/sub deny", presence_sub_request_find);
+    result = autocomplete_param_with_func(input, "/sub deny", presence_sub_request_find);
     if (result != NULL) {
         return result;
     }
-    result = autocomplete_param_with_ac(input, size, "/sub", sub_ac, TRUE);
+    result = autocomplete_param_with_ac(input, "/sub", sub_ac, TRUE);
     if (result != NULL) {
         return result;
     }
@@ -2088,13 +2108,13 @@ _sub_autocomplete(char *input, int *size)
 }
 
 static char *
-_who_autocomplete(char *input, int *size)
+_who_autocomplete(const char * const input)
 {
     char *result = NULL;
     win_type_t win_type = ui_current_win_type();
 
     if (win_type == WIN_MUC) {
-        result = autocomplete_param_with_ac(input, size, "/who", who_room_ac, TRUE);
+        result = autocomplete_param_with_ac(input, "/who", who_room_ac, TRUE);
         if (result != NULL) {
             return result;
         }
@@ -2105,13 +2125,13 @@ _who_autocomplete(char *input, int *size)
             "/who unavailable" };
 
         for (i = 0; i < ARRAY_SIZE(group_commands); i++) {
-            result = autocomplete_param_with_func(input, size, group_commands[i], roster_group_autocomplete);
+            result = autocomplete_param_with_func(input, group_commands[i], roster_group_autocomplete);
             if (result != NULL) {
                 return result;
             }
         }
 
-        result = autocomplete_param_with_ac(input, size, "/who", who_roster_ac, TRUE);
+        result = autocomplete_param_with_ac(input, "/who", who_roster_ac, TRUE);
         if (result != NULL) {
             return result;
         }
@@ -2121,34 +2141,34 @@ _who_autocomplete(char *input, int *size)
 }
 
 static char *
-_roster_autocomplete(char *input, int *size)
+_roster_autocomplete(const char * const input)
 {
     char *result = NULL;
-    result = autocomplete_param_with_func(input, size, "/roster nick", roster_barejid_autocomplete);
+    result = autocomplete_param_with_func(input, "/roster nick", roster_barejid_autocomplete);
     if (result != NULL) {
         return result;
     }
-    result = autocomplete_param_with_func(input, size, "/roster clearnick", roster_barejid_autocomplete);
+    result = autocomplete_param_with_func(input, "/roster clearnick", roster_barejid_autocomplete);
     if (result != NULL) {
         return result;
     }
-    result = autocomplete_param_with_func(input, size, "/roster remove", roster_barejid_autocomplete);
+    result = autocomplete_param_with_func(input, "/roster remove", roster_barejid_autocomplete);
     if (result != NULL) {
         return result;
     }
-    result = autocomplete_param_with_ac(input, size, "/roster show", roster_option_ac, TRUE);
+    result = autocomplete_param_with_ac(input, "/roster show", roster_option_ac, TRUE);
     if (result != NULL) {
         return result;
     }
-    result = autocomplete_param_with_ac(input, size, "/roster hide", roster_option_ac, TRUE);
+    result = autocomplete_param_with_ac(input, "/roster hide", roster_option_ac, TRUE);
     if (result != NULL) {
         return result;
     }
-    result = autocomplete_param_with_ac(input, size, "/roster by", roster_by_ac, TRUE);
+    result = autocomplete_param_with_ac(input, "/roster by", roster_by_ac, TRUE);
     if (result != NULL) {
         return result;
     }
-    result = autocomplete_param_with_ac(input, size, "/roster", roster_ac, TRUE);
+    result = autocomplete_param_with_ac(input, "/roster", roster_ac, TRUE);
     if (result != NULL) {
         return result;
     }
@@ -2157,31 +2177,31 @@ _roster_autocomplete(char *input, int *size)
 }
 
 static char *
-_group_autocomplete(char *input, int *size)
+_group_autocomplete(const char * const input)
 {
     char *result = NULL;
-    result = autocomplete_param_with_func(input, size, "/group show", roster_group_autocomplete);
+    result = autocomplete_param_with_func(input, "/group show", roster_group_autocomplete);
     if (result != NULL) {
         return result;
     }
 
-    result = autocomplete_param_no_with_func(input, size, "/group add", 4, roster_contact_autocomplete);
+    result = autocomplete_param_no_with_func(input, "/group add", 4, roster_contact_autocomplete);
     if (result != NULL) {
         return result;
     }
-    result = autocomplete_param_no_with_func(input, size, "/group remove", 4, roster_contact_autocomplete);
+    result = autocomplete_param_no_with_func(input, "/group remove", 4, roster_contact_autocomplete);
     if (result != NULL) {
         return result;
     }
-    result = autocomplete_param_with_func(input, size, "/group add", roster_group_autocomplete);
+    result = autocomplete_param_with_func(input, "/group add", roster_group_autocomplete);
     if (result != NULL) {
         return result;
     }
-    result = autocomplete_param_with_func(input, size, "/group remove", roster_group_autocomplete);
+    result = autocomplete_param_with_func(input, "/group remove", roster_group_autocomplete);
     if (result != NULL) {
         return result;
     }
-    result = autocomplete_param_with_ac(input, size, "/group", group_ac, TRUE);
+    result = autocomplete_param_with_ac(input, "/group", group_ac, TRUE);
     if (result != NULL) {
         return result;
     }
@@ -2190,7 +2210,7 @@ _group_autocomplete(char *input, int *size)
 }
 
 static char *
-_bookmark_autocomplete(char *input, int *size)
+_bookmark_autocomplete(const char * const input)
 {
     char *found = NULL;
 
@@ -2238,9 +2258,9 @@ _bookmark_autocomplete(char *input, int *size)
         }
 
         if (autojoin) {
-            found = autocomplete_param_with_func(input, size, beginning->str, prefs_autocomplete_boolean_choice);
+            found = autocomplete_param_with_func(input, beginning->str, prefs_autocomplete_boolean_choice);
         } else {
-            found = autocomplete_param_with_ac(input, size, beginning->str, bookmark_property_ac, TRUE);
+            found = autocomplete_param_with_ac(input, beginning->str, bookmark_property_ac, TRUE);
         }
         g_string_free(beginning, TRUE);
         if (found != NULL) {
@@ -2251,79 +2271,79 @@ _bookmark_autocomplete(char *input, int *size)
 
     g_strfreev(args);
 
-    found = autocomplete_param_with_func(input, size, "/bookmark remove", bookmark_find);
+    found = autocomplete_param_with_func(input, "/bookmark remove", bookmark_find);
     if (found != NULL) {
         return found;
     }
-    found = autocomplete_param_with_func(input, size, "/bookmark join", bookmark_find);
+    found = autocomplete_param_with_func(input, "/bookmark join", bookmark_find);
     if (found != NULL) {
         return found;
     }
-    found = autocomplete_param_with_func(input, size, "/bookmark update", bookmark_find);
+    found = autocomplete_param_with_func(input, "/bookmark update", bookmark_find);
     if (found != NULL) {
         return found;
     }
 
-    found = autocomplete_param_with_ac(input, size, "/bookmark", bookmark_ac, TRUE);
+    found = autocomplete_param_with_ac(input, "/bookmark", bookmark_ac, TRUE);
     return found;
 }
 
 static char *
-_notify_autocomplete(char *input, int *size)
+_notify_autocomplete(const char * const input)
 {
     int i = 0;
     char *result = NULL;
 
-    result = autocomplete_param_with_func(input, size, "/notify room current", prefs_autocomplete_boolean_choice);
+    result = autocomplete_param_with_func(input, "/notify room current", prefs_autocomplete_boolean_choice);
     if (result != NULL) {
         return result;
     }
 
-    result = autocomplete_param_with_func(input, size, "/notify message current", prefs_autocomplete_boolean_choice);
+    result = autocomplete_param_with_func(input, "/notify message current", prefs_autocomplete_boolean_choice);
     if (result != NULL) {
         return result;
     }
 
-    result = autocomplete_param_with_func(input, size, "/notify typing current", prefs_autocomplete_boolean_choice);
+    result = autocomplete_param_with_func(input, "/notify typing current", prefs_autocomplete_boolean_choice);
     if (result != NULL) {
         return result;
     }
 
-    result = autocomplete_param_with_func(input, size, "/notify room text", prefs_autocomplete_boolean_choice);
+    result = autocomplete_param_with_func(input, "/notify room text", prefs_autocomplete_boolean_choice);
     if (result != NULL) {
         return result;
     }
 
-    result = autocomplete_param_with_func(input, size, "/notify message text", prefs_autocomplete_boolean_choice);
+    result = autocomplete_param_with_func(input, "/notify message text", prefs_autocomplete_boolean_choice);
     if (result != NULL) {
         return result;
     }
 
-    result = autocomplete_param_with_ac(input, size, "/notify room", notify_room_ac, TRUE);
+    result = autocomplete_param_with_ac(input, "/notify room", notify_room_ac, TRUE);
     if (result != NULL) {
         return result;
     }
 
-    result = autocomplete_param_with_ac(input, size, "/notify message", notify_message_ac, TRUE);
+    result = autocomplete_param_with_ac(input, "/notify message", notify_message_ac, TRUE);
     if (result != NULL) {
         return result;
     }
 
-    result = autocomplete_param_with_ac(input, size, "/notify typing", notify_typing_ac, TRUE);
+    result = autocomplete_param_with_ac(input, "/notify typing", notify_typing_ac, TRUE);
     if (result != NULL) {
         return result;
     }
 
     gchar *boolean_choices[] = { "/notify invite", "/notify sub" };
     for (i = 0; i < ARRAY_SIZE(boolean_choices); i++) {
-        result = autocomplete_param_with_func(input, size, boolean_choices[i],
+        result = autocomplete_param_with_func(input, boolean_choices[i],
             prefs_autocomplete_boolean_choice);
         if (result != NULL) {
             return result;
         }
     }
 
-    result = autocomplete_param_with_ac(input, size, "/notify", notify_ac, TRUE);
+    result = autocomplete_param_with_ac(input, "/notify", notify_ac, TRUE);
     if (result != NULL) {
         return result;
     }
@@ -2332,20 +2352,20 @@ _notify_autocomplete(char *input, int *size)
 }
 
 static char *
-_autoaway_autocomplete(char *input, int *size)
+_autoaway_autocomplete(const char * const input)
 {
     char *result = NULL;
 
-    result = autocomplete_param_with_ac(input, size, "/autoaway mode", autoaway_mode_ac, TRUE);
+    result = autocomplete_param_with_ac(input, "/autoaway mode", autoaway_mode_ac, TRUE);
     if (result != NULL) {
         return result;
     }
-    result = autocomplete_param_with_func(input, size, "/autoaway check",
+    result = autocomplete_param_with_func(input, "/autoaway check",
         prefs_autocomplete_boolean_choice);
     if (result != NULL) {
         return result;
     }
-    result = autocomplete_param_with_ac(input, size, "/autoaway", autoaway_ac, TRUE);
+    result = autocomplete_param_with_ac(input, "/autoaway", autoaway_ac, TRUE);
     if (result != NULL) {
         return result;
     }
@@ -2354,21 +2374,21 @@ _autoaway_autocomplete(char *input, int *size)
 }
 
 static char *
-_log_autocomplete(char *input, int *size)
+_log_autocomplete(const char * const input)
 {
     char *result = NULL;
 
-    result = autocomplete_param_with_func(input, size, "/log rotate",
+    result = autocomplete_param_with_func(input, "/log rotate",
         prefs_autocomplete_boolean_choice);
     if (result != NULL) {
         return result;
     }
-    result = autocomplete_param_with_func(input, size, "/log shared",
+    result = autocomplete_param_with_func(input, "/log shared",
         prefs_autocomplete_boolean_choice);
     if (result != NULL) {
         return result;
     }
-    result = autocomplete_param_with_ac(input, size, "/log", log_ac, TRUE);
+    result = autocomplete_param_with_ac(input, "/log", log_ac, TRUE);
     if (result != NULL) {
         return result;
     }
@@ -2377,16 +2397,16 @@ _log_autocomplete(char *input, int *size)
 }
 
 static char *
-_autoconnect_autocomplete(char *input, int *size)
+_autoconnect_autocomplete(const char * const input)
 {
     char *result = NULL;
 
-    result = autocomplete_param_with_func(input, size, "/autoconnect set", accounts_find_enabled);
+    result = autocomplete_param_with_func(input, "/autoconnect set", accounts_find_enabled);
     if (result != NULL) {
         return result;
     }
 
-    result = autocomplete_param_with_ac(input, size, "/autoconnect", autoconnect_ac, TRUE);
+    result = autocomplete_param_with_ac(input, "/autoconnect", autoconnect_ac, TRUE);
     if (result != NULL) {
         return result;
     }
@@ -2395,16 +2415,16 @@ _autoconnect_autocomplete(char *input, int *size)
 }
 
 static char *
-_otr_autocomplete(char *input, int *size)
+_otr_autocomplete(const char * const input)
 {
     char *found = NULL;
 
-    found = autocomplete_param_with_func(input, size, "/otr start", roster_contact_autocomplete);
+    found = autocomplete_param_with_func(input, "/otr start", roster_contact_autocomplete);
     if (found != NULL) {
         return found;
     }
 
-    found = autocomplete_param_with_ac(input, size, "/otr log", otr_log_ac, TRUE);
+    found = autocomplete_param_with_ac(input, "/otr log", otr_log_ac, TRUE);
     if (found != NULL) {
         return found;
     }
@@ -2418,7 +2438,7 @@ _otr_autocomplete(char *input, int *size)
         g_string_append(beginning, " ");
         g_string_append(beginning, args[1]);
 
-        found = autocomplete_param_with_func(input, size, beginning->str, roster_contact_autocomplete);
+        found = autocomplete_param_with_func(input, beginning->str, roster_contact_autocomplete);
         g_string_free(beginning, TRUE);
         if (found != NULL) {
             g_strfreev(args);
@@ -2428,18 +2448,18 @@ _otr_autocomplete(char *input, int *size)
 
     g_strfreev(args);
 
-    found = autocomplete_param_with_ac(input, size, "/otr policy", otr_policy_ac, TRUE);
+    found = autocomplete_param_with_ac(input, "/otr policy", otr_policy_ac, TRUE);
     if (found != NULL) {
         return found;
     }
 
-    found = autocomplete_param_with_func(input, size, "/otr warn",
+    found = autocomplete_param_with_func(input, "/otr warn",
         prefs_autocomplete_boolean_choice);
     if (found != NULL) {
         return found;
     }
 
-    found = autocomplete_param_with_ac(input, size, "/otr", otr_ac, TRUE);
+    found = autocomplete_param_with_ac(input, "/otr", otr_ac, TRUE);
     if (found != NULL) {
         return found;
     }
@@ -2448,10 +2468,10 @@ _otr_autocomplete(char *input, int *size)
 }
 
 static char *
-_theme_autocomplete(char *input, int *size)
+_theme_autocomplete(const char * const input)
 {
     char *result = NULL;
-    if ((strncmp(input, "/theme set ", 11) == 0) && (*size > 11)) {
+    if ((strncmp(input, "/theme set ", 11) == 0) && (strlen(input) > 11)) {
         if (theme_load_ac == NULL) {
             theme_load_ac = autocomplete_new();
             GSList *themes = theme_list();
@@ -2462,12 +2482,12 @@ _theme_autocomplete(char *input, int *size)
             g_slist_free(themes);
             autocomplete_add(theme_load_ac, "default");
         }
-        result = autocomplete_param_with_ac(input, size, "/theme set", theme_load_ac, TRUE);
+        result = autocomplete_param_with_ac(input, "/theme set", theme_load_ac, TRUE);
         if (result != NULL) {
             return result;
         }
     }
-    result = autocomplete_param_with_ac(input, size, "/theme", theme_ac, TRUE);
+    result = autocomplete_param_with_ac(input, "/theme", theme_ac, TRUE);
     if (result != NULL) {
         return result;
     }
@@ -2476,7 +2496,7 @@ _theme_autocomplete(char *input, int *size)
 }
 
 static char *
-_resource_autocomplete(char *input, int *size)
+_resource_autocomplete(const char * const input)
 {
     char *found = NULL;
 
@@ -2486,24 +2506,24 @@ _resource_autocomplete(char *input, int *size)
         PContact contact = roster_get_contact(chatwin->barejid);
         if (contact) {
             Autocomplete ac = p_contact_resource_ac(contact);
-            found = autocomplete_param_with_ac(input, size, "/resource set", ac, FALSE);
+            found = autocomplete_param_with_ac(input, "/resource set", ac, FALSE);
             if (found != NULL) {
                 return found;
             }
         }
     }
 
-    found = autocomplete_param_with_func(input, size, "/resource title", prefs_autocomplete_boolean_choice);
+    found = autocomplete_param_with_func(input, "/resource title", prefs_autocomplete_boolean_choice);
     if (found != NULL) {
         return found;
     }
 
-    found = autocomplete_param_with_func(input, size, "/resource message", prefs_autocomplete_boolean_choice);
+    found = autocomplete_param_with_func(input, "/resource message", prefs_autocomplete_boolean_choice);
     if (found != NULL) {
         return found;
     }
 
-    found = autocomplete_param_with_ac(input, size, "/resource", resource_ac, FALSE);
+    found = autocomplete_param_with_ac(input, "/resource", resource_ac, FALSE);
     if (found != NULL) {
         return found;
     }
@@ -2512,21 +2532,21 @@ _resource_autocomplete(char *input, int *size)
 }
 
 static char *
-_titlebar_autocomplete(char *input, int *size)
+_titlebar_autocomplete(const char * const input)
 {
     char *found = NULL;
 
-    found = autocomplete_param_with_func(input, size, "/titlebar show", prefs_autocomplete_boolean_choice);
+    found = autocomplete_param_with_func(input, "/titlebar show", prefs_autocomplete_boolean_choice);
     if (found != NULL) {
         return found;
     }
 
-    found = autocomplete_param_with_func(input, size, "/titlebar goodbye", prefs_autocomplete_boolean_choice);
+    found = autocomplete_param_with_func(input, "/titlebar goodbye", prefs_autocomplete_boolean_choice);
     if (found != NULL) {
         return found;
     }
 
-    found = autocomplete_param_with_ac(input, size, "/titlebar", titlebar_ac, FALSE);
+    found = autocomplete_param_with_ac(input, "/titlebar", titlebar_ac, FALSE);
     if (found != NULL) {
         return found;
     }
@@ -2535,16 +2555,16 @@ _titlebar_autocomplete(char *input, int *size)
 }
 
 static char *
-_inpblock_autocomplete(char *input, int *size)
+_inpblock_autocomplete(const char * const input)
 {
     char *found = NULL;
 
-    found = autocomplete_param_with_func(input, size, "/inpblock dynamic", prefs_autocomplete_boolean_choice);
+    found = autocomplete_param_with_func(input, "/inpblock dynamic", prefs_autocomplete_boolean_choice);
     if (found != NULL) {
         return found;
     }
 
-    found = autocomplete_param_with_ac(input, size, "/inpblock", inpblock_ac, FALSE);
+    found = autocomplete_param_with_ac(input, "/inpblock", inpblock_ac, FALSE);
     if (found != NULL) {
         return found;
     }
@@ -2553,7 +2573,7 @@ _inpblock_autocomplete(char *input, int *size)
 }
 
 static char *
-_form_autocomplete(char *input, int *size)
+_form_autocomplete(const char * const input)
 {
     ProfWin *current = wins_get_current();
     if (current->type != WIN_MUC_CONFIG) {
@@ -2565,13 +2585,13 @@ _form_autocomplete(char *input, int *size)
     ProfMucConfWin *confwin = (ProfMucConfWin*)current;
     DataForm *form = confwin->form;
     if (form) {
-        found = autocomplete_param_with_ac(input, size, "/form help", form->tag_ac, TRUE);
+        found = autocomplete_param_with_ac(input, "/form help", form->tag_ac, TRUE);
         if (found != NULL) {
             return found;
         }
     }
 
-    found = autocomplete_param_with_ac(input, size, "/form", form_ac, TRUE);
+    found = autocomplete_param_with_ac(input, "/form", form_ac, TRUE);
     if (found != NULL) {
         return found;
     }
@@ -2580,7 +2600,7 @@ _form_autocomplete(char *input, int *size)
 }
 
 static char *
-_form_field_autocomplete(char *input, int *size)
+_form_field_autocomplete(const char * const input)
 {
     ProfWin *current = wins_get_current();
     if (current->type != WIN_MUC_CONFIG) {
@@ -2595,7 +2615,6 @@ _form_field_autocomplete(char *input, int *size)
         return NULL;
     }
 
-    input[*size] = '\0';
     gchar **split = g_strsplit(input, " ", 0);
 
     if (g_strv_length(split) == 3) {
@@ -2609,13 +2628,13 @@ _form_field_autocomplete(char *input, int *size)
 
             if (((g_strcmp0(split[1], "add") == 0) || (g_strcmp0(split[1], "remove") == 0))
                     && field_type == FIELD_LIST_MULTI) {
-                found = autocomplete_param_with_ac(input, size, beginning->str, value_ac, TRUE);
+                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, size, beginning->str, value_ac, TRUE);
+                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, size, beginning->str, value_ac, TRUE);
+                found = autocomplete_param_with_ac(input, beginning->str, value_ac, TRUE);
             }
 
             g_string_free(beginning, TRUE);
@@ -2630,15 +2649,15 @@ _form_field_autocomplete(char *input, int *size)
             switch (field_type)
             {
                 case FIELD_BOOLEAN:
-                    found = autocomplete_param_with_func(input, size, split[0], prefs_autocomplete_boolean_choice);
+                    found = autocomplete_param_with_func(input, split[0], prefs_autocomplete_boolean_choice);
                     break;
                 case FIELD_LIST_SINGLE:
-                    found = autocomplete_param_with_ac(input, size, split[0], value_ac, TRUE);
+                    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, size, split[0], form_field_multi_ac, TRUE);
+                    found = autocomplete_param_with_ac(input, split[0], form_field_multi_ac, TRUE);
                     break;
                 default:
                     break;
@@ -2652,16 +2671,16 @@ _form_field_autocomplete(char *input, int *size)
 }
 
 static char *
-_occupants_autocomplete(char *input, int *size)
+_occupants_autocomplete(const char * const input)
 {
     char *found = NULL;
 
-    found = autocomplete_param_with_ac(input, size, "/occupants default", occupants_default_ac, TRUE);
+    found = autocomplete_param_with_ac(input, "/occupants default", occupants_default_ac, TRUE);
     if (found != NULL) {
         return found;
     }
 
-    found = autocomplete_param_with_ac(input, size, "/occupants", occupants_ac, TRUE);
+    found = autocomplete_param_with_ac(input, "/occupants", occupants_ac, TRUE);
     if (found != NULL) {
         return found;
     }
@@ -2670,7 +2689,7 @@ _occupants_autocomplete(char *input, int *size)
 }
 
 static char *
-_kick_autocomplete(char *input, int *size)
+_kick_autocomplete(const char * const input)
 {
     char *result = NULL;
 
@@ -2679,7 +2698,7 @@ _kick_autocomplete(char *input, int *size)
         Autocomplete nick_ac = muc_roster_ac(mucwin->roomjid);
 
         if (nick_ac != NULL) {
-            result = autocomplete_param_with_ac(input, size, "/kick", nick_ac, TRUE);
+            result = autocomplete_param_with_ac(input, "/kick", nick_ac, TRUE);
             if (result != NULL) {
                 return result;
             }
@@ -2690,7 +2709,7 @@ _kick_autocomplete(char *input, int *size)
 }
 
 static char *
-_ban_autocomplete(char *input, int *size)
+_ban_autocomplete(const char * const input)
 {
     char *result = NULL;
 
@@ -2699,7 +2718,7 @@ _ban_autocomplete(char *input, int *size)
         Autocomplete jid_ac = muc_roster_jid_ac(mucwin->roomjid);
 
         if (jid_ac != NULL) {
-            result = autocomplete_param_with_ac(input, size, "/ban", jid_ac, TRUE);
+            result = autocomplete_param_with_ac(input, "/ban", jid_ac, TRUE);
             if (result != NULL) {
                 return result;
             }
@@ -2710,7 +2729,7 @@ _ban_autocomplete(char *input, int *size)
 }
 
 static char *
-_affiliation_autocomplete(char *input, int *size)
+_affiliation_autocomplete(const char * const input)
 {
     char *result = NULL;
 
@@ -2719,7 +2738,6 @@ _affiliation_autocomplete(char *input, int *size)
         gboolean parse_result;
         Autocomplete jid_ac = muc_roster_jid_ac(mucwin->roomjid);
 
-        input[*size] = '\0';
         gchar **args = parse_args(input, 3, 3, &parse_result);
 
         if ((strncmp(input, "/affiliation", 12) == 0) && (parse_result == TRUE)) {
@@ -2728,7 +2746,7 @@ _affiliation_autocomplete(char *input, int *size)
             g_string_append(beginning, " ");
             g_string_append(beginning, args[1]);
 
-            result = autocomplete_param_with_ac(input, size, beginning->str, jid_ac, TRUE);
+            result = autocomplete_param_with_ac(input, beginning->str, jid_ac, TRUE);
             g_string_free(beginning, TRUE);
             if (result != NULL) {
                 g_strfreev(args);
@@ -2739,17 +2757,17 @@ _affiliation_autocomplete(char *input, int *size)
         g_strfreev(args);
     }
 
-    result = autocomplete_param_with_ac(input, size, "/affiliation set", affiliation_ac, TRUE);
+    result = autocomplete_param_with_ac(input, "/affiliation set", affiliation_ac, TRUE);
     if (result != NULL) {
         return result;
     }
 
-    result = autocomplete_param_with_ac(input, size, "/affiliation list", affiliation_ac, TRUE);
+    result = autocomplete_param_with_ac(input, "/affiliation list", affiliation_ac, TRUE);
     if (result != NULL) {
         return result;
     }
 
-    result = autocomplete_param_with_ac(input, size, "/affiliation", privilege_cmd_ac, TRUE);
+    result = autocomplete_param_with_ac(input, "/affiliation", privilege_cmd_ac, TRUE);
     if (result != NULL) {
         return result;
     }
@@ -2758,7 +2776,7 @@ _affiliation_autocomplete(char *input, int *size)
 }
 
 static char *
-_role_autocomplete(char *input, int *size)
+_role_autocomplete(const char * const input)
 {
     char *result = NULL;
 
@@ -2767,7 +2785,6 @@ _role_autocomplete(char *input, int *size)
         gboolean parse_result;
         Autocomplete nick_ac = muc_roster_ac(mucwin->roomjid);
 
-        input[*size] = '\0';
         gchar **args = parse_args(input, 3, 3, &parse_result);
 
         if ((strncmp(input, "/role", 5) == 0) && (parse_result == TRUE)) {
@@ -2776,7 +2793,7 @@ _role_autocomplete(char *input, int *size)
             g_string_append(beginning, " ");
             g_string_append(beginning, args[1]);
 
-            result = autocomplete_param_with_ac(input, size, beginning->str, nick_ac, TRUE);
+            result = autocomplete_param_with_ac(input, beginning->str, nick_ac, TRUE);
             g_string_free(beginning, TRUE);
             if (result != NULL) {
                 g_strfreev(args);
@@ -2787,17 +2804,17 @@ _role_autocomplete(char *input, int *size)
         g_strfreev(args);
     }
 
-    result = autocomplete_param_with_ac(input, size, "/role set", role_ac, TRUE);
+    result = autocomplete_param_with_ac(input, "/role set", role_ac, TRUE);
     if (result != NULL) {
         return result;
     }
 
-    result = autocomplete_param_with_ac(input, size, "/role list", role_ac, TRUE);
+    result = autocomplete_param_with_ac(input, "/role list", role_ac, TRUE);
     if (result != NULL) {
         return result;
     }
 
-    result = autocomplete_param_with_ac(input, size, "/role", privilege_cmd_ac, TRUE);
+    result = autocomplete_param_with_ac(input, "/role", privilege_cmd_ac, TRUE);
     if (result != NULL) {
         return result;
     }
@@ -2806,26 +2823,26 @@ _role_autocomplete(char *input, int *size)
 }
 
 static char *
-_statuses_autocomplete(char *input, int *size)
+_statuses_autocomplete(const char * const input)
 {
     char *result = NULL;
 
-    result = autocomplete_param_with_ac(input, size, "/statuses console", statuses_setting_ac, TRUE);
+    result = autocomplete_param_with_ac(input, "/statuses console", statuses_setting_ac, TRUE);
     if (result != NULL) {
         return result;
     }
 
-    result = autocomplete_param_with_ac(input, size, "/statuses chat", statuses_setting_ac, TRUE);
+    result = autocomplete_param_with_ac(input, "/statuses chat", statuses_setting_ac, TRUE);
     if (result != NULL) {
         return result;
     }
 
-    result = autocomplete_param_with_ac(input, size, "/statuses muc", statuses_setting_ac, TRUE);
+    result = autocomplete_param_with_ac(input, "/statuses muc", statuses_setting_ac, TRUE);
     if (result != NULL) {
         return result;
     }
 
-    result = autocomplete_param_with_ac(input, size, "/statuses", statuses_ac, TRUE);
+    result = autocomplete_param_with_ac(input, "/statuses", statuses_ac, TRUE);
     if (result != NULL) {
         return result;
     }
@@ -2834,16 +2851,16 @@ _statuses_autocomplete(char *input, int *size)
 }
 
 static char *
-_alias_autocomplete(char *input, int *size)
+_alias_autocomplete(const char * const input)
 {
     char *result = NULL;
 
-    result = autocomplete_param_with_ac(input, size, "/alias remove", aliases_ac, TRUE);
+    result = autocomplete_param_with_ac(input, "/alias remove", aliases_ac, TRUE);
     if (result != NULL) {
         return result;
     }
 
-    result = autocomplete_param_with_ac(input, size, "/alias", alias_ac, TRUE);
+    result = autocomplete_param_with_ac(input, "/alias", alias_ac, TRUE);
     if (result != NULL) {
         return result;
     }
@@ -2852,12 +2869,11 @@ _alias_autocomplete(char *input, int *size)
 }
 
 static char *
-_connect_autocomplete(char *input, int *size)
+_connect_autocomplete(const char * const input)
 {
     char *found = NULL;
     gboolean result = FALSE;
 
-    input[*size] = '\0';
     gchar **args = parse_args(input, 2, 4, &result);
 
     if ((strncmp(input, "/connect", 8) == 0) && (result == TRUE)) {
@@ -2869,7 +2885,7 @@ _connect_autocomplete(char *input, int *size)
             g_string_append(beginning, " ");
             g_string_append(beginning, args[2]);
         }
-        found = autocomplete_param_with_ac(input, size, beginning->str, connect_property_ac, TRUE);
+        found = autocomplete_param_with_ac(input, beginning->str, connect_property_ac, TRUE);
         g_string_free(beginning, TRUE);
         if (found != NULL) {
             g_strfreev(args);
@@ -2879,7 +2895,7 @@ _connect_autocomplete(char *input, int *size)
 
     g_strfreev(args);
 
-    found = autocomplete_param_with_func(input, size, "/connect", accounts_find_enabled);
+    found = autocomplete_param_with_func(input, "/connect", accounts_find_enabled);
     if (found != NULL) {
         return found;
     }
@@ -2888,14 +2904,12 @@ _connect_autocomplete(char *input, int *size)
 }
 
 static char *
-_join_autocomplete(char *input, int *size)
+_join_autocomplete(const char * const input)
 {
     char *found = NULL;
     gboolean result = FALSE;
 
-    input[*size] = '\0';
-
-    found = autocomplete_param_with_func(input, size, "/join", bookmark_find);
+    found = autocomplete_param_with_func(input, "/join", bookmark_find);
     if (found != NULL) {
         return found;
     }
@@ -2911,7 +2925,7 @@ _join_autocomplete(char *input, int *size)
             g_string_append(beginning, " ");
             g_string_append(beginning, args[2]);
         }
-        found = autocomplete_param_with_ac(input, size, beginning->str, join_property_ac, TRUE);
+        found = autocomplete_param_with_ac(input, beginning->str, join_property_ac, TRUE);
         g_string_free(beginning, TRUE);
         if (found != NULL) {
             g_strfreev(args);
@@ -2925,12 +2939,11 @@ _join_autocomplete(char *input, int *size)
 }
 
 static char *
-_account_autocomplete(char *input, int *size)
+_account_autocomplete(const char * const input)
 {
     char *found = NULL;
     gboolean result = FALSE;
 
-    input[*size] = '\0';
     gchar **args = parse_args(input, 3, 4, &result);
 
     if ((strncmp(input, "/account set", 12) == 0) && (result == TRUE)) {
@@ -2939,14 +2952,14 @@ _account_autocomplete(char *input, int *size)
         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, size, beginning->str, otr_policy_ac, TRUE);
+            found = autocomplete_param_with_ac(input, beginning->str, otr_policy_ac, TRUE);
             g_string_free(beginning, TRUE);
             if (found != NULL) {
                 g_strfreev(args);
                 return found;
             }
         } else {
-            found = autocomplete_param_with_ac(input, size, beginning->str, account_set_ac, TRUE);
+            found = autocomplete_param_with_ac(input, beginning->str, account_set_ac, TRUE);
             g_string_free(beginning, TRUE);
             if (found != NULL) {
                 g_strfreev(args);
@@ -2958,7 +2971,7 @@ _account_autocomplete(char *input, int *size)
     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, size, beginning->str, account_clear_ac, TRUE);
+        found = autocomplete_param_with_ac(input, beginning->str, account_clear_ac, TRUE);
         g_string_free(beginning, TRUE);
         if (found != NULL) {
             g_strfreev(args);
@@ -2968,7 +2981,7 @@ _account_autocomplete(char *input, int *size)
 
     g_strfreev(args);
 
-    found = autocomplete_param_with_ac(input, size, "/account default", account_default_ac, TRUE);
+    found = autocomplete_param_with_ac(input, "/account default", account_default_ac, TRUE);
     if(found){
         return found;
     }
@@ -2979,31 +2992,85 @@ _account_autocomplete(char *input, int *size)
         "/account default set" };
 
     for (i = 0; i < ARRAY_SIZE(account_choice); i++) {
-        found = autocomplete_param_with_func(input, size, account_choice[i],
-            accounts_find_all);
+        found = autocomplete_param_with_func(input, account_choice[i], accounts_find_all);
         if (found != NULL) {
             return found;
         }
     }
 
-    found = autocomplete_param_with_ac(input, size, "/account", account_ac, TRUE);
+    found = autocomplete_param_with_ac(input, "/account", account_ac, TRUE);
     return found;
 }
 
+static int
+_cmp_command(Command *cmd1, Command *cmd2)
+{
+    return g_strcmp0(cmd1->cmd, cmd2->cmd);
+}
+
+void
+command_docgen(void)
+{
+    GList *cmds = NULL;
+    unsigned int i;
+    for (i = 0; i < ARRAY_SIZE(command_defs); i++) {
+        Command *pcmd = command_defs+i;
+        cmds = g_list_insert_sorted(cmds, pcmd, (GCompareFunc)_cmp_command);
+    }
+
+    FILE *toc_fragment = fopen("toc_fragment.html", "w");
+    FILE *main_fragment = fopen("main_fragment.html", "w");
+
+    fputs("<ul><li><ul><li>\n", toc_fragment);
+    fputs("<hr>\n", main_fragment);
+
+    GList *curr = cmds;
+    while (curr) {
+        Command *pcmd = curr->data;
+
+        fprintf(toc_fragment, "<a href=\"#%s\">%s</a>,\n", &pcmd->cmd[1], pcmd->cmd);
+
+        fprintf(main_fragment, "<a name=\"%s\"></a>\n", &pcmd->cmd[1]);
+        fprintf(main_fragment, "<h4>%s</h4>\n", pcmd->cmd);
+        fputs("<p>Usage:</p>\n", main_fragment);
+        fprintf(main_fragment, "<p><pre><code>%s</code></pre></p>\n", pcmd->help.usage);
+
+        fputs("<p>Details:</p>\n", main_fragment);
+        fputs("<p><pre><code>", main_fragment);
+        int i = 2;
+        while (pcmd->help.long_help[i] != NULL) {
+            fprintf(main_fragment, "%s\n", pcmd->help.long_help[i++]);
+        }
+        fputs("</code></pre></p>\n<a href=\"#top\"><h5>back to top</h5></a><br><hr>\n", main_fragment);
+        fputs("\n", main_fragment);
+
+        curr = g_list_next(curr);
+    }
+
+    fputs("</ul></ul>\n", toc_fragment);
+
+    fclose(toc_fragment);
+    fclose(main_fragment);
+    g_list_free(cmds);
+}
+
 static char *
-_strip_quotes_from_names(char *input, int *size) {
+_strip_quotes_from_names(const char * const input) {
+    char *unquoted = strdup(input);
+
     // Remove starting quote if it exists
-    if(strchr(input, '"') != NULL) {
-        if(strchr(input, ' ') + 1 == strchr(input, '"')) {
-            memmove(strchr(input, '"'), strchr(input, '"')+1, strchr(input, '\0') - strchr(input, '"'));
+    if(strchr(unquoted, '"') != NULL) {
+        if(strchr(unquoted, ' ') + 1 == strchr(unquoted, '"')) {
+            memmove(strchr(unquoted, '"'), strchr(unquoted, '"')+1, strchr(unquoted, '\0') - strchr(unquoted, '"'));
         }
     }
 
     // Remove ending quote if it exists
-    if(strchr(input, '"') != NULL) {
-        if(strchr(input, '\0') - 1 == strchr(input, '"')) {
-            memmove(strchr(input, '"'), strchr(input, '"')+1, strchr(input, '\0') - strchr(input, '"'));
+    if(strchr(unquoted, '"') != NULL) {
+        if(strchr(unquoted, '\0') - 1 == strchr(unquoted, '"')) {
+            memmove(strchr(unquoted, '"'), strchr(unquoted, '"')+1, strchr(unquoted, '\0') - strchr(unquoted, '"'));
         }
     }
-    return input;
+
+    return unquoted;
 }
diff --git a/src/command/command.h b/src/command/command.h
index 13cf2d00..8be1143f 100644
--- a/src/command/command.h
+++ b/src/command/command.h
@@ -44,7 +44,7 @@ GHashTable *commands;
 void cmd_init(void);
 void cmd_uninit(void);
 
-void cmd_autocomplete(char *input, int *size);
+char* cmd_autocomplete(const char * const input);
 void cmd_reset_autocomplete(void);
 void cmd_autocomplete_add(char *value);
 void cmd_autocomplete_remove(char *value);
@@ -53,9 +53,8 @@ void cmd_autocomplete_remove_form_fields(DataForm *form);
 void cmd_alias_add(char *value);
 void cmd_alias_remove(char *value);
 
-gboolean cmd_execute(const char * const command, const char * const inp);
-gboolean cmd_execute_alias(const char * const inp, gboolean *ran);
-gboolean cmd_execute_default(const char * const inp);
+gboolean cmd_process_input(char *inp);
+void cmd_execute_connect(const char * const account);
 
 gboolean cmd_exists(char *cmd);
 
@@ -64,7 +63,9 @@ GSList * cmd_get_settings_help(void);
 GSList * cmd_get_presence_help(void);
 
 void cmd_history_append(char *inp);
-char *cmd_history_previous(char *inp, int *size);
-char *cmd_history_next(char *inp, int *size);
+char *cmd_history_previous(char *inp);
+char *cmd_history_next(char *inp);
+
+void command_docgen(void);
 
 #endif
diff --git a/src/command/commands.c b/src/command/commands.c
index 75a4f6cf..2059c982 100644
--- a/src/command/commands.c
+++ b/src/command/commands.c
@@ -154,6 +154,10 @@ cmd_connect(gchar **args, struct cmd_help_t help)
                         cons_show("Error evaluating password, see logs for details.");
                         return TRUE;
                     }
+                    // strip trailing newline
+                    if (g_str_has_suffix(account->password, "\n")) {
+                        account->password[strlen(account->password)-1] = '\0';
+                    }
                 } else {
                     log_error("popen failed when running eval_password.");
                     cons_show("Error evaluating password, see logs for details.");
@@ -710,7 +714,7 @@ cmd_help(gchar **args, struct cmd_help_t help)
             "/rooms", "/tiny", "/who", "/nick", "/privileges", "/info", "/occupants" };
         _cmd_show_filtered_help("Groupchat commands", filter, ARRAY_SIZE(filter));
 
-    } else if (strcmp(args[0], "presence") == 0) {
+    } else if (strcmp(args[0], "presences") == 0) {
         gchar *filter[] = { "/autoaway", "/away", "/chat", "/dnd",
             "/online", "/priority", "/account", "/status", "/statuses", "/who",
             "/xa" };
diff --git a/src/command/history.c b/src/command/history.c
deleted file mode 100644
index 92846246..00000000
--- a/src/command/history.c
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * history.c
- *
- * Copyright (C) 2012 - 2014 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 "tools/history.h"
-
-#define MAX_HISTORY 100
-
-static History history;
-
-void _stringify_input(char *inp, int size, char *string);
-
-void
-cmd_history_init(void)
-{
-    history = history_new(MAX_HISTORY);
-}
-
-void
-cmd_history_append(char *inp)
-{
-    history_append(history, inp);
-}
-
-char *
-cmd_history_previous(char *inp, int *size)
-{
-    char inp_str[*size + 1];
-    _stringify_input(inp, *size, inp_str);
-
-    return history_previous(history, inp_str);
-}
-
-char *
-cmd_history_next(char *inp, int *size)
-{
-    char inp_str[*size + 1];
-    _stringify_input(inp, *size, inp_str);
-
-    return history_next(history, inp_str);
-}
-
-void
-_stringify_input(char *inp, int size, char *string)
-{
-    int i;
-    for (i = 0; i < size; i++) {
-        string[i] = inp[i];
-    }
-    string[size] = '\0';
-}
diff --git a/src/command/history.h b/src/command/history.h
deleted file mode 100644
index f2d7c26b..00000000
--- a/src/command/history.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * history.h
- *
- * Copyright (C) 2012 - 2014 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.
- *
- */
-
-#ifndef COMMAND_HISTORY_H
-#define COMMAND_HISTORY_H
-
-void cmd_history_init(void);
-
-#endif