diff options
Diffstat (limited to 'src')
34 files changed, 797 insertions, 832 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 diff --git a/src/common.c b/src/common.c index ffd12899..7638da31 100644 --- a/src/common.c +++ b/src/common.c @@ -191,7 +191,7 @@ str_replace(const char *string, const char *substr, } int -str_contains(char str[], int size, char ch) +str_contains(const char str[], int size, char ch) { int i; for (i = 0; i < size; i++) { @@ -202,6 +202,28 @@ str_contains(char str[], int size, char ch) return 0; } +int +utf8_display_len(const char * const str) +{ + if (!str) { + return 0; + } + + int len = 0; + gchar *curr = g_utf8_offset_to_pointer(str, 0); + while (*curr != '\0') { + gunichar curru = g_utf8_get_char(curr); + if (g_unichar_iswide(curru)) { + len += 2; + } else { + len ++; + } + curr = g_utf8_next_char(curr); + } + + return len; +} + char * prof_getline(FILE *stream) { diff --git a/src/common.h b/src/common.h index 55451dea..26d4a99a 100644 --- a/src/common.h +++ b/src/common.h @@ -103,7 +103,8 @@ gboolean create_dir(char *name); gboolean mkdir_recursive(const char *dir); char * str_replace(const char *string, const char *substr, const char *replacement); -int str_contains(char str[], int size, char ch); +int str_contains(const char str[], int size, char ch); +int utf8_display_len(const char * const str); char * prof_getline(FILE *stream); char* release_get_latest(void); gboolean release_is_new(char *found_version); diff --git a/src/config/accounts.c b/src/config/accounts.c index d86fe3af..4d4d47d0 100644 --- a/src/config/accounts.c +++ b/src/config/accounts.c @@ -117,13 +117,13 @@ accounts_close(void) } char * -accounts_find_enabled(char *prefix) +accounts_find_enabled(const char * const prefix) { return autocomplete_complete(enabled_ac, prefix, TRUE); } char * -accounts_find_all(char *prefix) +accounts_find_all(const char * const prefix) { return autocomplete_complete(all_ac, prefix, TRUE); } diff --git a/src/config/accounts.h b/src/config/accounts.h index a1dda018..cbbe88e6 100644 --- a/src/config/accounts.h +++ b/src/config/accounts.h @@ -43,8 +43,8 @@ void accounts_load(void); void accounts_close(void); -char * accounts_find_all(char *prefix); -char * accounts_find_enabled(char *prefix); +char * accounts_find_all(const char * const prefix); +char * accounts_find_enabled(const char * const prefix); void accounts_reset_all_search(void); void accounts_reset_enabled_search(void); void accounts_add(const char *jid, const char *altdomain, const int port); diff --git a/src/config/preferences.c b/src/config/preferences.c index 5b683426..67f12b18 100644 --- a/src/config/preferences.c +++ b/src/config/preferences.c @@ -154,7 +154,7 @@ prefs_close(void) } char * -prefs_autocomplete_boolean_choice(char *prefix) +prefs_autocomplete_boolean_choice(const char * const prefix) { return autocomplete_complete(boolean_choice_ac, prefix, TRUE); } diff --git a/src/config/preferences.h b/src/config/preferences.h index 9590eb64..68286f09 100644 --- a/src/config/preferences.h +++ b/src/config/preferences.h @@ -114,7 +114,7 @@ void prefs_close(void); char * prefs_find_login(char *prefix); void prefs_reset_login_search(void); -char * prefs_autocomplete_boolean_choice(char *prefix); +char * prefs_autocomplete_boolean_choice(const char * const prefix); void prefs_reset_boolean_choice(void); gint prefs_get_gone(void); diff --git a/src/config/theme.c b/src/config/theme.c index 6d3c5938..a5dbd0dd 100644 --- a/src/config/theme.c +++ b/src/config/theme.c @@ -592,7 +592,7 @@ theme_attrs(theme_item_t attrs) case THEME_BLACK_BOLD: result = COLOR_PAIR(52); break; case THEME_MAGENTA: result = COLOR_PAIR(53); break; case THEME_MAGENTA_BOLD: result = COLOR_PAIR(53); break; - default: break; + default: break; } if (g_hash_table_lookup(bold_items, GINT_TO_POINTER(attrs))) { diff --git a/src/contact.c b/src/contact.c index f16f1679..943be374 100644 --- a/src/contact.c +++ b/src/contact.c @@ -381,7 +381,7 @@ void p_contact_set_presence(const PContact contact, Resource *resource) { g_hash_table_replace(contact->available_resources, strdup(resource->name), resource); - autocomplete_add(contact->resource_ac, strdup(resource->name)); + autocomplete_add(contact->resource_ac, resource->name); } void diff --git a/src/main.c b/src/main.c index f3b6a17f..7ee5affe 100644 --- a/src/main.c +++ b/src/main.c @@ -40,13 +40,7 @@ #endif #include "profanity.h" - -#ifdef HAVE_LIBOTR -#include "otr/otr.h" -#endif -#include "xmpp/xmpp.h" - -#include "ui/ui.h" +#include "command/command.h" static gboolean disable_tls = FALSE; static gboolean version = FALSE; @@ -56,6 +50,11 @@ static char *account_name = NULL; int main(int argc, char **argv) { + if (argc == 2 && g_strcmp0(argv[1], "docgen") == 0 && g_strcmp0(PACKAGE_STATUS, "development") == 0) { + command_docgen(); + return 0; + } + static GOptionEntry entries[] = { { "version", 'v', 0, G_OPTION_ARG_NONE, &version, "Show version information", NULL }, diff --git a/src/muc.c b/src/muc.c index 74e0d66e..f50f3879 100644 --- a/src/muc.c +++ b/src/muc.c @@ -141,7 +141,7 @@ muc_invites_reset_ac(void) } char * -muc_invites_find(char *search_str) +muc_invites_find(const char * const search_str) { return autocomplete_complete(invite_ac, search_str, TRUE); } @@ -632,8 +632,8 @@ muc_roster_nick_change_complete(const char * const room, return NULL; } -void -muc_autocomplete(char *input, int *size) +char * +muc_autocomplete(const char * const input) { win_type_t wintype = ui_current_win_type(); if (wintype == WIN_MUC) { @@ -641,8 +641,7 @@ muc_autocomplete(char *input, int *size) ChatRoom *chat_room = g_hash_table_lookup(rooms, mucwin->roomjid); if (chat_room && chat_room->nick_ac) { - input[*size] = '\0'; - char *search_str = NULL; + const char * search_str = NULL; gchar *last_space = g_strrstr(input, " "); if (!last_space) { @@ -664,12 +663,15 @@ muc_autocomplete(char *input, int *size) if (!last_space || (*(last_space+1) == '\0')) { g_string_append(replace_with, ": "); } - ui_replace_input(input, replace_with->str, size); - g_string_free(replace_with, TRUE); g_free(result); + result = replace_with->str; + g_string_free(replace_with, FALSE); + return result; } } } + + return NULL; } void diff --git a/src/muc.h b/src/muc.h index 3f4ea876..01f8b44b 100644 --- a/src/muc.h +++ b/src/muc.h @@ -114,7 +114,7 @@ gint muc_invites_count(void); GSList* muc_invites(void); gboolean muc_invites_contain(const char * const room); void muc_invites_reset_ac(void); -char* muc_invites_find(char *search_str); +char* muc_invites_find(const char * const search_str); void muc_invites_clear(void); void muc_set_subject(const char * const room, const char * const subject); @@ -123,7 +123,7 @@ char* muc_subject(const char * const room); void muc_pending_broadcasts_add(const char * const room, const char * const message); GList * muc_pending_broadcasts(const char * const room); -void muc_autocomplete(char *input, int *size); +char* muc_autocomplete(const char * const input); void muc_autocomplete_reset(const char * const room); gboolean muc_requires_config(const char * const room); diff --git a/src/profanity.c b/src/profanity.c index b28eae20..13297124 100644 --- a/src/profanity.c +++ b/src/profanity.c @@ -64,10 +64,11 @@ #include "ui/ui.h" #include "ui/windows.h" -static void _handle_idle_time(void); +static void _check_autoaway(void); static void _init(const int disable_tls, char *log_level); static void _shutdown(void); static void _create_directories(void); +static void _connect_default(const char * const account); static gboolean idle = FALSE; @@ -75,62 +76,29 @@ void prof_run(const int disable_tls, char *log_level, char *account_name) { _init(disable_tls, log_level); - log_info("Starting main event loop"); - ui_input_nonblocking(TRUE); - GTimer *timer = g_timer_new(); - gboolean cmd_result = TRUE; - jabber_conn_status_t conn_status = jabber_get_connection_status(); - - char inp[INP_WIN_MAX]; - int size = 0; - - char *pref_connect_account = prefs_get_string(PREF_CONNECT_ACCOUNT); - if (account_name != NULL) { - char *cmd = "/connect"; - snprintf(inp, sizeof(inp), "%s %s", cmd, account_name); - process_input(inp); - } else if (pref_connect_account != NULL) { - char *cmd = "/connect"; - snprintf(inp, sizeof(inp), "%s %s", cmd, pref_connect_account); - process_input(inp); - } - prefs_free_string(pref_connect_account); + _connect_default(account_name); ui_update(); - while(cmd_result == TRUE) { - wint_t ch = ERR; - int result; - size = 0; - - while(ch != '\n') { - conn_status = jabber_get_connection_status(); - if (conn_status == JABBER_CONNECTED) { - _handle_idle_time(); - } - - gdouble elapsed = g_timer_elapsed(timer, NULL); - - gint remind_period = prefs_get_notify_remind(); - if (remind_period > 0 && elapsed >= remind_period) { - notify_remind(); - g_timer_start(timer); - } + char *line = NULL; + gboolean cmd_result = TRUE; - ch = ui_get_char(inp, &size, &result); + log_info("Starting main event loop"); - ui_handle_special_keys(&ch, result); + while(cmd_result) { + while(!line) { + _check_autoaway(); + line = ui_readline(); #ifdef HAVE_LIBOTR otr_poll(); #endif + notify_remind(); jabber_process_events(); ui_update(); } - - inp[size++] = '\0'; - cmd_result = process_input(inp); + cmd_result = cmd_process_input(line); + ui_input_clear(); + FREE_SET_NULL(line); } - - g_timer_destroy(timer); } void @@ -166,57 +134,38 @@ prof_handle_activity(void) } } -/* - * Take a line of input and process it, return TRUE if profanity is to - * continue, FALSE otherwise - */ -gboolean -process_input(char *inp) +static void +_connect_default(const char * const account) { - log_debug("Input received: %s", inp); - gboolean result = FALSE; - g_strstrip(inp); - - // add line to history if something typed - if (strlen(inp) > 0) { - cmd_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 '/' + if (account) { + cmd_execute_connect(account); } else { - result = cmd_execute_default(inp); + char *pref_connect_account = prefs_get_string(PREF_CONNECT_ACCOUNT); + if (pref_connect_account) { + cmd_execute_connect(pref_connect_account); + prefs_free_string(pref_connect_account); + } } - - ui_input_clear(); - roster_reset_search_attempts(); - - return result; } static void -_handle_idle_time() +_check_autoaway() { + jabber_conn_status_t conn_status = jabber_get_connection_status(); + if (conn_status != JABBER_CONNECTED) { + return; + } + gint prefs_time = prefs_get_autoaway_time() * 60000; - resource_presence_t current_presence = accounts_get_last_presence(jabber_get_account_name()); unsigned long idle_ms = ui_get_idle_time(); char *pref_autoaway_mode = prefs_get_string(PREF_AUTOAWAY_MODE); - char *pref_autoaway_message = prefs_get_string(PREF_AUTOAWAY_MESSAGE); if (!idle) { + resource_presence_t current_presence = accounts_get_last_presence(jabber_get_account_name()); if ((current_presence == RESOURCE_ONLINE) || (current_presence == RESOURCE_CHAT)) { if (idle_ms >= prefs_time) { idle = TRUE; + char *pref_autoaway_message = prefs_get_string(PREF_AUTOAWAY_MESSAGE); // handle away mode if (strcmp(pref_autoaway_mode, "away") == 0) { @@ -227,6 +176,8 @@ _handle_idle_time() } else if (strcmp(pref_autoaway_mode, "idle") == 0) { presence_update(RESOURCE_ONLINE, pref_autoaway_message, idle_ms / 1000); } + + prefs_free_string(pref_autoaway_message); } } @@ -246,8 +197,8 @@ _handle_idle_time() } } } + prefs_free_string(pref_autoaway_mode); - prefs_free_string(pref_autoaway_message); } static void @@ -287,6 +238,7 @@ _init(const int disable_tls, char *log_level) otr_init(); #endif atexit(_shutdown); + ui_input_nonblocking(TRUE); } static void diff --git a/src/roster_list.c b/src/roster_list.c index 2d01d205..44d05ff0 100644 --- a/src/roster_list.c +++ b/src/roster_list.c @@ -344,13 +344,13 @@ roster_has_pending_subscriptions(void) } char * -roster_contact_autocomplete(char *search_str) +roster_contact_autocomplete(const char * const search_str) { return autocomplete_complete(name_ac, search_str, TRUE); } char * -roster_fulljid_autocomplete(char *search_str) +roster_fulljid_autocomplete(const char * const search_str) { return autocomplete_complete(fulljid_ac, search_str, TRUE); } @@ -406,13 +406,13 @@ roster_get_groups(void) } char * -roster_group_autocomplete(char *search_str) +roster_group_autocomplete(const char * const search_str) { return autocomplete_complete(groups_ac, search_str, TRUE); } char * -roster_barejid_autocomplete(char *search_str) +roster_barejid_autocomplete(const char * const search_str) { return autocomplete_complete(barejid_ac, search_str, TRUE); } diff --git a/src/roster_list.h b/src/roster_list.h index 7743ece6..e193085b 100644 --- a/src/roster_list.h +++ b/src/roster_list.h @@ -59,12 +59,12 @@ char * roster_barejid_from_name(const char * const name); GSList * roster_get_contacts(void); GSList * roster_get_contacts_online(void); gboolean roster_has_pending_subscriptions(void); -char * roster_contact_autocomplete(char *search_str); -char * roster_fulljid_autocomplete(char *search_str); +char * roster_contact_autocomplete(const char * const search_str); +char * roster_fulljid_autocomplete(const char * const search_str); GSList * roster_get_group(const char * const group); GSList * roster_get_groups(void); -char * roster_group_autocomplete(char *search_str); -char * roster_barejid_autocomplete(char *search_str); +char * roster_group_autocomplete(const char * const search_str); +char * roster_barejid_autocomplete(const char * const search_str); GSList * roster_get_contacts_by_presence(const char * const presence); GSList * roster_get_nogroup(void); diff --git a/src/tools/autocomplete.c b/src/tools/autocomplete.c index 486fd2ba..2623c828 100644 --- a/src/tools/autocomplete.c +++ b/src/tools/autocomplete.c @@ -169,7 +169,7 @@ autocomplete_contains(Autocomplete ac, const char *value) } gchar * -autocomplete_complete(Autocomplete ac, gchar *search_str, gboolean quote) +autocomplete_complete(Autocomplete ac, const gchar *search_str, gboolean quote) { gchar *found = NULL; @@ -216,8 +216,7 @@ autocomplete_complete(Autocomplete ac, gchar *search_str, gboolean quote) } char * -autocomplete_param_with_func(char *input, int *size, char *command, - autocomplete_func func) +autocomplete_param_with_func(const char * const input, char *command, autocomplete_func func) { GString *auto_msg = NULL; char *result = NULL; @@ -225,15 +224,16 @@ autocomplete_param_with_func(char *input, int *size, char *command, sprintf(command_cpy, "%s ", command); int len = strlen(command_cpy); - if ((strncmp(input, command_cpy, len) == 0) && (*size > len)) { + if ((strncmp(input, command_cpy, len) == 0) && (strlen(input) > len)) { int i; - char inp_cpy[*size]; - for(i = len; i < *size; i++) { - inp_cpy[i-len] = input[i]; + int inp_len = strlen(input); + char prefix[inp_len]; + for(i = len; i < inp_len; i++) { + prefix[i-len] = input[i]; } - inp_cpy[(*size) - len] = '\0'; + prefix[inp_len - len] = '\0'; - char *found = func(inp_cpy); + char *found = func(prefix); if (found) { auto_msg = g_string_new(command_cpy); g_string_append(auto_msg, found); @@ -247,23 +247,23 @@ autocomplete_param_with_func(char *input, int *size, char *command, } char * -autocomplete_param_with_ac(char *input, int *size, char *command, - Autocomplete ac, gboolean quote) +autocomplete_param_with_ac(const char * const input, char *command, Autocomplete ac, gboolean quote) { GString *auto_msg = NULL; char *result = NULL; char *command_cpy = malloc(strlen(command) + 2); sprintf(command_cpy, "%s ", command); int len = strlen(command_cpy); - if ((strncmp(input, command_cpy, len) == 0) && (*size > len)) { + int inp_len = strlen(input); + if ((strncmp(input, command_cpy, len) == 0) && (strlen(input) > len)) { int i; - char inp_cpy[*size]; - for(i = len; i < *size; i++) { - inp_cpy[i-len] = input[i]; + char prefix[inp_len]; + for(i = len; i < inp_len; i++) { + prefix[i-len] = input[i]; } - inp_cpy[(*size) - len] = '\0'; + prefix[inp_len - len] = '\0'; - char *found = autocomplete_complete(ac, inp_cpy, quote); + char *found = autocomplete_complete(ac, prefix, quote); if (found) { auto_msg = g_string_new(command_cpy); g_string_append(auto_msg, found); @@ -278,28 +278,18 @@ autocomplete_param_with_ac(char *input, int *size, char *command, } char * -autocomplete_param_no_with_func(char *input, int *size, char *command, - int arg_number, autocomplete_func func) +autocomplete_param_no_with_func(const char * const input, char *command, int arg_number, autocomplete_func func) { - if (strncmp(input, command, strlen(command)) == 0 && (*size > strlen(command))) { - int i = 0; + if (strncmp(input, command, strlen(command)) == 0 && (strlen(input) > strlen(command))) { GString *result_str = NULL; - // copy and null terminate input - gchar inp_cpy[*size]; - for (i = 0; i < *size; i++) { - inp_cpy[i] = input[i]; - } - inp_cpy[i] = '\0'; - g_strstrip(inp_cpy); - // count tokens properly - int num_tokens = count_tokens(inp_cpy); + int num_tokens = count_tokens(input); // if correct number of tokens, then candidate for autocompletion of last param if (num_tokens == arg_number) { - gchar *start_str = get_start(inp_cpy, arg_number); - gchar *comp_str = g_strdup(&inp_cpy[strlen(start_str)]); + gchar *start_str = get_start(input, arg_number); + gchar *comp_str = g_strdup(&input[strlen(start_str)]); // autocomplete param if (comp_str) { diff --git a/src/tools/autocomplete.h b/src/tools/autocomplete.h index a029b7ef..70cd8f30 100644 --- a/src/tools/autocomplete.h +++ b/src/tools/autocomplete.h @@ -37,7 +37,7 @@ #include <glib.h> -typedef char*(*autocomplete_func)(char *); +typedef char*(*autocomplete_func)(const char * const); typedef struct autocomplete_t *Autocomplete; // allocate new autocompleter with no items @@ -53,18 +53,18 @@ void autocomplete_add(Autocomplete ac, const char *item); void autocomplete_remove(Autocomplete ac, const char * const item); // find the next item prefixed with search string -gchar * autocomplete_complete(Autocomplete ac, gchar *search_str, gboolean quote); +gchar * autocomplete_complete(Autocomplete ac, const gchar *search_str, gboolean quote); GSList * autocomplete_create_list(Autocomplete ac); gint autocomplete_length(Autocomplete ac); -char * autocomplete_param_with_func(char *input, int *size, char *command, +char * autocomplete_param_with_func(const char * const input, char *command, autocomplete_func func); -char * autocomplete_param_with_ac(char *input, int *size, char *command, +char * autocomplete_param_with_ac(const char * const input, char *command, Autocomplete ac, gboolean quote); -char * autocomplete_param_no_with_func(char *input, int *size, char *command, +char * autocomplete_param_no_with_func(const char * const input, char *command, int arg_number, autocomplete_func func); void autocomplete_reset(Autocomplete ac); diff --git a/src/tools/parser.c b/src/tools/parser.c index ae149155..e91b227d 100644 --- a/src/tools/parser.c +++ b/src/tools/parser.c @@ -316,7 +316,7 @@ parse_args_with_freetext(const char * const inp, int min, int max, gboolean *res } int -count_tokens(char *string) +count_tokens(const char * const string) { int length = g_utf8_strlen(string, -1); gboolean in_quotes = FALSE; @@ -347,7 +347,7 @@ count_tokens(char *string) } char * -get_start(char *string, int tokens) +get_start(const char * const string, int tokens) { GString *result = g_string_new(""); int length = g_utf8_strlen(string, -1); diff --git a/src/tools/parser.h b/src/tools/parser.h index 7ecef3fc..eeb97df3 100644 --- a/src/tools/parser.h +++ b/src/tools/parser.h @@ -39,8 +39,8 @@ gchar** parse_args(const char * const inp, int min, int max, gboolean *result); gchar** parse_args_with_freetext(const char * const inp, int min, int max, gboolean *result); -int count_tokens(char *string); -char* get_start(char *string, int tokens); +int count_tokens(const char * const string); +char* get_start(const char * const string, int tokens); GHashTable* parse_options(gchar **args, gchar **keys, gboolean *res); void options_destroy(GHashTable *options); diff --git a/src/ui/console.c b/src/ui/console.c index dd50d6d3..cdf5d1b8 100644 --- a/src/ui/console.c +++ b/src/ui/console.c @@ -1402,7 +1402,7 @@ cons_help(void) cons_show("/help basic - List basic commands for getting started."); cons_show("/help chatting - List chat commands."); cons_show("/help groupchat - List groupchat commands."); - cons_show("/help presence - List commands to change presence."); + cons_show("/help presences - List commands to change presence."); cons_show("/help contacts - List commands for manipulating your roster."); cons_show("/help service - List service discovery commands."); cons_show("/help settings - List commands for changing settings."); diff --git a/src/ui/core.c b/src/ui/core.c index e0f46f6e..85d5748a 100644 --- a/src/ui/core.c +++ b/src/ui/core.c @@ -74,14 +74,15 @@ static char *win_title; +static int inp_size; + #ifdef HAVE_LIBXSS static Display *display; #endif static GTimer *ui_idle_time; -static void _win_handle_switch(const wint_t * const ch); -static void _win_handle_page(const wint_t * const ch, const int result); +static void _win_handle_switch(const wint_t ch); static void _win_show_history(int win_index, const char * const contact); static void _ui_draw_term_title(void); @@ -103,11 +104,13 @@ ui_init(void) status_bar_active(1); create_input_window(); wins_init(); + notifier_initialise(); cons_about(); #ifdef HAVE_LIBXSS display = XOpenDisplay(0); #endif ui_idle_time = g_timer_new(); + inp_size = 0; ProfWin *window = wins_get_current(); win_update_virtual(window); } @@ -174,30 +177,42 @@ ui_close(void) endwin(); } -wint_t -ui_get_char(char *input, int *size, int *result) +char* +ui_readline(void) { - wint_t ch = inp_get_char(input, size, result); - if (ch != ERR && *result != ERR) { + int key_type; + wint_t ch; + + char *line = inp_read(&key_type, &ch); + _win_handle_switch(ch); + + ProfWin *current = wins_get_current(); + win_handle_page(current, ch, key_type); + + if (ch == KEY_RESIZE) { + ui_resize(); + } + + if (ch != ERR && key_type != ERR) { ui_reset_idle_time(); ui_input_nonblocking(TRUE); } else { ui_input_nonblocking(FALSE); } - return ch; + return line; } void -ui_input_clear(void) +ui_inp_history_append(char *inp) { - inp_win_reset(); + inp_history_append(inp); } void -ui_replace_input(char *input, const char * const new_input, int *size) +ui_input_clear(void) { - inp_replace_input(input, new_input, size); + inp_win_reset(); } void @@ -702,16 +717,6 @@ ui_disconnected(void) } void -ui_handle_special_keys(const wint_t * const ch, const int result) -{ - _win_handle_switch(ch); - _win_handle_page(ch, result); - if (*ch == KEY_RESIZE) { - ui_resize(); - } -} - -void ui_close_connected_win(int index) { ProfWin *window = wins_get_by_num(index); @@ -1413,8 +1418,8 @@ ui_outgoing_chat_msg(const char * const from, const char * const barejid, // create new window if (window == NULL) { window = wins_new_chat(barejid); - ProfChatWin *chatwin = (ProfChatWin*)window; #ifdef HAVE_LIBOTR + ProfChatWin *chatwin = (ProfChatWin*)window; if (otr_is_secure(barejid)) { chatwin->is_otr = TRUE; } @@ -2935,143 +2940,32 @@ ui_hide_roster(void) } static void -_win_handle_switch(const wint_t * const ch) +_win_handle_switch(const wint_t ch) { - if (*ch == KEY_F(1)) { + if (ch == KEY_F(1)) { ui_switch_win(1); - } else if (*ch == KEY_F(2)) { + } else if (ch == KEY_F(2)) { ui_switch_win(2); - } else if (*ch == KEY_F(3)) { + } else if (ch == KEY_F(3)) { ui_switch_win(3); - } else if (*ch == KEY_F(4)) { + } else if (ch == KEY_F(4)) { ui_switch_win(4); - } else if (*ch == KEY_F(5)) { + } else if (ch == KEY_F(5)) { ui_switch_win(5); - } else if (*ch == KEY_F(6)) { + } else if (ch == KEY_F(6)) { ui_switch_win(6); - } else if (*ch == KEY_F(7)) { + } else if (ch == KEY_F(7)) { ui_switch_win(7); - } else if (*ch == KEY_F(8)) { + } else if (ch == KEY_F(8)) { ui_switch_win(8); - } else if (*ch == KEY_F(9)) { + } else if (ch == KEY_F(9)) { ui_switch_win(9); - } else if (*ch == KEY_F(10)) { + } else if (ch == KEY_F(10)) { ui_switch_win(0); } } static void -_win_handle_page(const wint_t * const ch, const int result) -{ - ProfWin *current = wins_get_current(); - int rows = getmaxy(stdscr); - int y = getcury(current->layout->win); - - int page_space = rows - 4; - int *page_start = &(current->layout->y_pos); - - if (prefs_get_boolean(PREF_MOUSE)) { - MEVENT mouse_event; - - if (*ch == KEY_MOUSE) { - if (getmouse(&mouse_event) == OK) { - -#ifdef PLATFORM_CYGWIN - if (mouse_event.bstate & BUTTON5_PRESSED) { // mouse wheel down -#else - if (mouse_event.bstate & BUTTON2_PRESSED) { // mouse wheel down -#endif - *page_start += 4; - - // only got half a screen, show full screen - if ((y - (*page_start)) < page_space) - *page_start = y - page_space; - - // went past end, show full screen - else if (*page_start >= y) - *page_start = y - page_space; - - current->layout->paged = 1; - win_update_virtual(current); - } else if (mouse_event.bstate & BUTTON4_PRESSED) { // mouse wheel up - *page_start -= 4; - - // went past beginning, show first page - if (*page_start < 0) - *page_start = 0; - - current->layout->paged = 1; - win_update_virtual(current); - } - } - } - } - - // page up - if (*ch == KEY_PPAGE) { - *page_start -= page_space; - - // went past beginning, show first page - if (*page_start < 0) - *page_start = 0; - - current->layout->paged = 1; - win_update_virtual(current); - - // page down - } else if (*ch == KEY_NPAGE) { - *page_start += page_space; - - // only got half a screen, show full screen - if ((y - (*page_start)) < page_space) - *page_start = y - page_space; - - // went past end, show full screen - else if (*page_start >= y) - *page_start = y - page_space - 1; - - current->layout->paged = 1; - win_update_virtual(current); - } - - // switch off page if last line and space line visible - if ((y) - *page_start == page_space) { - current->layout->paged = 0; - } - - if (current->layout->type == LAYOUT_SPLIT) { - ProfLayoutSplit *split_layout = (ProfLayoutSplit*)current->layout; - int sub_y = getcury(split_layout->subwin); - int *sub_y_pos = &(split_layout->sub_y_pos); - - // alt up arrow - if ((result == KEY_CODE_YES) && ((*ch == 565) || (*ch == 337))) { - *sub_y_pos -= page_space; - - // went past beginning, show first page - if (*sub_y_pos < 0) - *sub_y_pos = 0; - - win_update_virtual(current); - - // alt down arrow - } else if ((result == KEY_CODE_YES) && ((*ch == 524) || (*ch == 336))) { - *sub_y_pos += page_space; - - // only got half a screen, show full screen - if ((sub_y- (*sub_y_pos)) < page_space) - *sub_y_pos = sub_y - page_space; - - // went past end, show full screen - else if (*sub_y_pos >= sub_y) - *sub_y_pos = sub_y - page_space - 1; - - win_update_virtual(current); - } - } -} - -static void _win_show_history(int win_index, const char * const contact) { ProfWin *window = wins_get_by_num(win_index); diff --git a/src/ui/inputwin.c b/src/ui/inputwin.c index a6877a86..85ddc79a 100644 --- a/src/ui/inputwin.c +++ b/src/ui/inputwin.c @@ -50,6 +50,7 @@ #include "config/accounts.h" #include "config/preferences.h" #include "config/theme.h" +#include "tools/history.h" #include "log.h" #include "muc.h" #include "profanity.h" @@ -72,17 +73,25 @@ #define KEY_CTRL_U 0025 #define KEY_CTRL_W 0027 +#define MAX_HISTORY 100 +#define INP_WIN_MAX 1000 + static WINDOW *inp_win; +static History history; + +static char input[INP_WIN_MAX]; +static int input_len_bytes; + static int pad_start = 0; static int rows, cols; -static int _handle_edit(int result, const wint_t ch, char *input, int *size); -static int _handle_alt_key(char *input, int *size, int key); -static void _handle_backspace(int display_size, int inp_x, int *size, char *input); +static int _handle_edit(int key_type, const wint_t ch); +static int _handle_alt_key(int key); +static void _handle_backspace(void); static int _printable(const wint_t ch); static void _clear_input(void); -static void _go_to_end(int display_size); -static void _delete_previous_word(char *input, int *size); +static void _go_to_end(void); +static void _delete_previous_word(void); void create_input_window(void) @@ -98,6 +107,7 @@ create_input_window(void) keypad(inp_win, TRUE); wmove(inp_win, 0, 0); _inp_win_update_virtual(); + history = history_new(MAX_HISTORY); } void @@ -131,38 +141,34 @@ inp_block(void) wtimeout(inp_win, -1); } -wint_t -inp_get_char(char *input, int *size, int *result) +char * +inp_read(int *key_type, wint_t *ch) { - wint_t ch; - int display_size = 0; - - if (*size != 0) { - display_size = g_utf8_strlen(input, *size); - } + int display_size = utf8_display_len(input); // echo off, and get some more input noecho(); - *result = wget_wch(inp_win, &ch); + *key_type = wget_wch(inp_win, ch); gboolean in_command = FALSE; if ((display_size > 0 && input[0] == '/') || - (display_size == 0 && ch == '/')) { + (display_size == 0 && *ch == '/')) { in_command = TRUE; } - if (*result == ERR) { + if (*key_type == ERR) { prof_handle_idle(); } - if ((*result != ERR) && (*result != KEY_CODE_YES) && !in_command && _printable(ch)) { + if ((*key_type != ERR) && (*key_type != KEY_CODE_YES) && !in_command && _printable(*ch)) { prof_handle_activity(); } // if it wasn't an arrow key etc - if (!_handle_edit(*result, ch, input, size)) { - if (_printable(ch) && *result != KEY_CODE_YES) { - if (*size >= INP_WIN_MAX) { - return ERR; + if (!_handle_edit(*key_type, *ch)) { + if (_printable(*ch) && *key_type != KEY_CODE_YES) { + if (input_len_bytes >= INP_WIN_MAX) { + *ch = ERR; + return NULL; } int inp_x = getcurx(inp_win); @@ -170,11 +176,11 @@ inp_get_char(char *input, int *size, int *result) // handle insert if not at end of input if (inp_x < display_size) { char bytes[MB_CUR_MAX]; - size_t utf_len = wcrtomb(bytes, ch, NULL); + size_t utf_len = wcrtomb(bytes, *ch, NULL); char *next_ch = g_utf8_offset_to_pointer(input, inp_x); char *offset; - for (offset = &input[*size - 1]; offset >= next_ch; offset--) { + for (offset = &input[input_len_bytes - 1]; offset >= next_ch; offset--) { *(offset + utf_len) = *offset; } int i; @@ -182,8 +188,8 @@ inp_get_char(char *input, int *size, int *result) *(next_ch + i) = bytes[i]; } - *size += utf_len; - input[*size] = '\0'; + input_len_bytes += utf_len; + input[input_len_bytes] = '\0'; waddstr(inp_win, next_ch); wmove(inp_win, 0, inp_x + 1); @@ -195,15 +201,15 @@ inp_get_char(char *input, int *size, int *result) // otherwise just append } else { char bytes[MB_CUR_MAX+1]; - size_t utf_len = wcrtomb(bytes, ch, NULL); + size_t utf_len = wcrtomb(bytes, *ch, NULL); // wcrtomb can return (size_t) -1 if (utf_len < MB_CUR_MAX) { int i; for (i = 0 ; i < utf_len; i++) { - input[(*size)++] = bytes[i]; + input[input_len_bytes++] = bytes[i]; } - input[*size] = '\0'; + input[input_len_bytes] = '\0'; bytes[utf_len] = '\0'; waddstr(inp_win, bytes); @@ -225,7 +231,13 @@ inp_get_char(char *input, int *size, int *result) echo(); - return ch; + if (*ch == '\n') { + input[input_len_bytes] = '\0'; + input_len_bytes = 0; + return strdup(input); + } else { + return NULL; + } } void @@ -248,16 +260,14 @@ inp_put_back(void) } void -inp_replace_input(char *input, const char * const new_input, int *size) +inp_replace_input(const char * const new_input) { - int display_size; strncpy(input, new_input, INP_WIN_MAX); - *size = strlen(input); - display_size = g_utf8_strlen(input, *size); + input_len_bytes = strlen(input); inp_win_reset(); - input[*size] = '\0'; + input[input_len_bytes] = '\0'; waddstr(inp_win, input); - _go_to_end(display_size); + _go_to_end(); } void @@ -268,6 +278,12 @@ inp_win_reset(void) _inp_win_update_virtual(); } +void +inp_history_append(char *inp) +{ + history_append(history, inp); +} + static void _clear_input(void) { @@ -281,23 +297,17 @@ _clear_input(void) * return 0 if it wasn't */ static int -_handle_edit(int result, const wint_t ch, char *input, int *size) +_handle_edit(int key_type, const wint_t ch) { char *prev = NULL; char *next = NULL; - int inp_x = 0; + int inp_x = getcurx(inp_win); int next_ch; - int display_size = 0; - - if (*size != 0) { - display_size = g_utf8_strlen(input, *size); - } - - inp_x = getcurx(inp_win); + int display_size = utf8_display_len(input); // CTRL-LEFT - if ((result == KEY_CODE_YES) && (ch == 547 || ch == 545 || ch == 544 || ch == 540 || ch == 539) && (inp_x > 0)) { - input[*size] = '\0'; + if ((key_type == KEY_CODE_YES) && (ch == 547 || ch == 545 || ch == 544 || ch == 540 || ch == 539) && (inp_x > 0)) { + input[input_len_bytes] = '\0'; gchar *curr_ch = g_utf8_offset_to_pointer(input, inp_x); curr_ch = g_utf8_find_prev_char(input, curr_ch); gchar *prev_ch; @@ -346,8 +356,8 @@ _handle_edit(int result, const wint_t ch, char *input, int *size) return 1; // CTRL-RIGHT - } else if ((result == KEY_CODE_YES) && (ch == 562 || ch == 560 || ch == 555 || ch == 559 || ch == 554) && (inp_x < display_size)) { - input[*size] = '\0'; + } else if ((key_type == KEY_CODE_YES) && (ch == 562 || ch == 560 || ch == 555 || ch == 559 || ch == 554) && (inp_x < display_size)) { + input[input_len_bytes] = '\0'; gchar *curr_ch = g_utf8_offset_to_pointer(input, inp_x); gchar *next_ch = g_utf8_find_next_char(curr_ch, NULL); gunichar curr_uni; @@ -389,12 +399,12 @@ _handle_edit(int result, const wint_t ch, char *input, int *size) return 1; // ALT-LEFT - } else if ((result == KEY_CODE_YES) && (ch == 537 || ch == 542)) { + } else if ((key_type == KEY_CODE_YES) && (ch == 537 || ch == 542)) { ui_previous_win(); return 1; // ALT-RIGHT - } else if ((result == KEY_CODE_YES) && (ch == 552 || ch == 557)) { + } else if ((key_type == KEY_CODE_YES) && (ch == 552 || ch == 557)) { ui_next_win(); return 1; @@ -406,34 +416,34 @@ _handle_edit(int result, const wint_t ch, char *input, int *size) // check for ALT-key next_ch = wgetch(inp_win); if (next_ch != ERR) { - return _handle_alt_key(input, size, next_ch); + return _handle_alt_key(next_ch); } else { - *size = 0; + input_len_bytes = 0; inp_win_reset(); return 1; } case 127: - _handle_backspace(display_size, inp_x, size, input); + _handle_backspace(); return 1; case KEY_BACKSPACE: - if (result != KEY_CODE_YES) { + if (key_type != KEY_CODE_YES) { return 0; } - _handle_backspace(display_size, inp_x, size, input); + _handle_backspace(); return 1; case KEY_DC: // DEL - if (result != KEY_CODE_YES) { + if (key_type != KEY_CODE_YES) { return 0; } case KEY_CTRL_D: if (inp_x == display_size-1) { gchar *start = g_utf8_substring(input, 0, inp_x); - for (*size = 0; *size < strlen(start); (*size)++) { - input[*size] = start[*size]; + for (input_len_bytes = 0; input_len_bytes < strlen(start); input_len_bytes++) { + input[input_len_bytes] = start[input_len_bytes]; } - input[*size] = '\0'; + input[input_len_bytes] = '\0'; g_free(start); @@ -441,14 +451,14 @@ _handle_edit(int result, const wint_t ch, char *input, int *size) waddstr(inp_win, input); } else if (inp_x < display_size-1) { gchar *start = g_utf8_substring(input, 0, inp_x); - gchar *end = g_utf8_substring(input, inp_x+1, *size); + gchar *end = g_utf8_substring(input, inp_x+1, input_len_bytes); GString *new = g_string_new(start); g_string_append(new, end); - for (*size = 0; *size < strlen(new->str); (*size)++) { - input[*size] = new->str[*size]; + for (input_len_bytes = 0; input_len_bytes < strlen(new->str); input_len_bytes++) { + input[input_len_bytes] = new->str[input_len_bytes]; } - input[*size] = '\0'; + input[input_len_bytes] = '\0'; g_free(start); g_free(end); @@ -461,7 +471,7 @@ _handle_edit(int result, const wint_t ch, char *input, int *size) return 1; case KEY_LEFT: - if (result != KEY_CODE_YES) { + if (key_type != KEY_CODE_YES) { return 0; } case KEY_CTRL_B: @@ -477,7 +487,7 @@ _handle_edit(int result, const wint_t ch, char *input, int *size) return 1; case KEY_RIGHT: - if (result != KEY_CODE_YES) { + if (key_type != KEY_CODE_YES) { return 0; } case KEY_CTRL_F: @@ -493,33 +503,35 @@ _handle_edit(int result, const wint_t ch, char *input, int *size) return 1; case KEY_UP: - if (result != KEY_CODE_YES) { + if (key_type != KEY_CODE_YES) { return 0; } case KEY_CTRL_P: - prev = cmd_history_previous(input, size); + input[input_len_bytes] = '\0'; + prev = history_previous(history, input); if (prev) { - inp_replace_input(input, prev, size); + inp_replace_input(prev); } return 1; case KEY_DOWN: - if (result != KEY_CODE_YES) { + if (key_type != KEY_CODE_YES) { return 0; } case KEY_CTRL_N: - next = cmd_history_next(input, size); + input[input_len_bytes] = '\0'; + next = history_next(history, input); if (next) { - inp_replace_input(input, next, size); - } else if (*size != 0) { - input[*size] = '\0'; - cmd_history_append(input); - inp_replace_input(input, "", size); + inp_replace_input(next); + } else if (input_len_bytes != 0) { + input[input_len_bytes] = '\0'; + history_append(history, input); + inp_replace_input(""); } return 1; case KEY_HOME: - if (result != KEY_CODE_YES) { + if (key_type != KEY_CODE_YES) { return 0; } case KEY_CTRL_A: @@ -529,31 +541,40 @@ _handle_edit(int result, const wint_t ch, char *input, int *size) return 1; case KEY_END: - if (result != KEY_CODE_YES) { + if (key_type != KEY_CODE_YES) { return 0; } case KEY_CTRL_E: - _go_to_end(display_size); + _go_to_end(); return 1; case 9: // tab - if (*size != 0) { + if (input_len_bytes != 0) { + input[input_len_bytes] = '\0'; if ((strncmp(input, "/", 1) != 0) && (ui_current_win_type() == WIN_MUC)) { - muc_autocomplete(input, size); + char *result = muc_autocomplete(input); + if (result) { + inp_replace_input(result); + free(result); + } } else if (strncmp(input, "/", 1) == 0) { - cmd_autocomplete(input, size); + char *result = cmd_autocomplete(input); + if (result) { + inp_replace_input(result); + free(result); + } } } return 1; case KEY_CTRL_W: - _delete_previous_word(input, size); + _delete_previous_word(); return 1; break; case KEY_CTRL_U: while (getcurx(inp_win) > 0) { - _delete_previous_word(input, size); + _delete_previous_word(); } return 1; break; @@ -565,18 +586,20 @@ _handle_edit(int result, const wint_t ch, char *input, int *size) } static void -_handle_backspace(int display_size, int inp_x, int *size, char *input) +_handle_backspace(void) { + int inp_x = getcurx(inp_win); + int display_size = utf8_display_len(input); roster_reset_search_attempts(); if (display_size > 0) { // if at end, delete last char if (inp_x >= display_size) { gchar *start = g_utf8_substring(input, 0, inp_x-1); - for (*size = 0; *size < strlen(start); (*size)++) { - input[*size] = start[*size]; + for (input_len_bytes = 0; input_len_bytes < strlen(start); input_len_bytes++) { + input[input_len_bytes] = start[input_len_bytes]; } - input[*size] = '\0'; + input[input_len_bytes] = '\0'; g_free(start); @@ -587,14 +610,14 @@ _handle_backspace(int display_size, int inp_x, int *size, char *input) // if in middle, delete and shift chars left } else if (inp_x > 0 && inp_x < display_size) { gchar *start = g_utf8_substring(input, 0, inp_x - 1); - gchar *end = g_utf8_substring(input, inp_x, *size); + gchar *end = g_utf8_substring(input, inp_x, input_len_bytes); GString *new = g_string_new(start); g_string_append(new, end); - for (*size = 0; *size < strlen(new->str); (*size)++) { - input[*size] = new->str[*size]; + for (input_len_bytes = 0; input_len_bytes < strlen(new->str); input_len_bytes++) { + input[input_len_bytes] = new->str[input_len_bytes]; } - input[*size] = '\0'; + input[input_len_bytes] = '\0'; g_free(start); g_free(end); @@ -619,7 +642,7 @@ _handle_backspace(int display_size, int inp_x, int *size, char *input) } static int -_handle_alt_key(char *input, int *size, int key) +_handle_alt_key(int key) { switch (key) { @@ -661,7 +684,7 @@ _handle_alt_key(char *input, int *size, int key) break; case 263: case 127: - _delete_previous_word(input, size); + _delete_previous_word(); break; default: break; @@ -670,12 +693,12 @@ _handle_alt_key(char *input, int *size, int key) } static void -_delete_previous_word(char *input, int *size) +_delete_previous_word(void) { int end_del = getcurx(inp_win); int start_del = end_del; - input[*size] = '\0'; + input[input_len_bytes] = '\0'; gchar *curr_ch = g_utf8_offset_to_pointer(input, end_del); curr_ch = g_utf8_find_prev_char(input, curr_ch); gchar *prev_ch; @@ -721,8 +744,8 @@ _delete_previous_word(char *input, int *size) input[strlen(start_string)+i] = end_string[i]; } - *size = strlen(start_string)+i; - input[*size] = '\0'; + input_len_bytes = strlen(start_string)+i; + input[input_len_bytes] = '\0'; _clear_input(); waddstr(inp_win, input); @@ -740,8 +763,9 @@ _delete_previous_word(char *input, int *size) } static void -_go_to_end(int display_size) +_go_to_end(void) { + int display_size = utf8_display_len(input); wmove(inp_win, 0, display_size); if (display_size > cols-2) { pad_start = display_size - cols + 1; diff --git a/src/ui/inputwin.h b/src/ui/inputwin.h index b5a26c10..39fde720 100644 --- a/src/ui/inputwin.h +++ b/src/ui/inputwin.h @@ -36,13 +36,14 @@ #define UI_INPUTWIN_H void create_input_window(void); -wint_t inp_get_char(char *input, int *size, int *result); +char* inp_read(int *key_type, wint_t *ch); void inp_win_reset(void); void inp_win_resize(void); void inp_put_back(void); void inp_non_block(gint); void inp_block(void); void inp_get_password(char *passwd); -void inp_replace_input(char *input, const char * const new_input, int *size); +void inp_replace_input(const char * const new_input); +void inp_history_append(char *inp); #endif diff --git a/src/ui/notifier.c b/src/ui/notifier.c index ff93443f..7ca8f705 100644 --- a/src/ui/notifier.c +++ b/src/ui/notifier.c @@ -48,10 +48,19 @@ #include "log.h" #include "muc.h" #include "ui/ui.h" +#include "config/preferences.h" static void _notify(const char * const message, int timeout, const char * const category); +static GTimer *remind_timer; + +void +notifier_initialise(void) +{ + remind_timer = g_timer_new(); +} + void notifier_uninit(void) { @@ -60,6 +69,7 @@ notifier_uninit(void) notify_uninit(); } #endif + g_timer_destroy(remind_timer); } void @@ -128,46 +138,52 @@ notify_subscription(const char * const from) void notify_remind(void) { - gint unread = ui_unread(); - gint open = muc_invites_count(); - gint subs = presence_sub_request_count(); + gdouble elapsed = g_timer_elapsed(remind_timer, NULL); + gint remind_period = prefs_get_notify_remind(); + if (remind_period > 0 && elapsed >= remind_period) { + gint unread = ui_unread(); + gint open = muc_invites_count(); + gint subs = presence_sub_request_count(); - GString *text = g_string_new(""); + GString *text = g_string_new(""); - if (unread > 0) { - if (unread == 1) { - g_string_append(text, "1 unread message"); - } else { - g_string_append_printf(text, "%d unread messages", unread); - } - - } - if (open > 0) { if (unread > 0) { - g_string_append(text, "\n"); + if (unread == 1) { + g_string_append(text, "1 unread message"); + } else { + g_string_append_printf(text, "%d unread messages", unread); + } + } - if (open == 1) { - g_string_append(text, "1 room invite"); - } else { - g_string_append_printf(text, "%d room invites", open); + if (open > 0) { + if (unread > 0) { + g_string_append(text, "\n"); + } + if (open == 1) { + g_string_append(text, "1 room invite"); + } else { + g_string_append_printf(text, "%d room invites", open); + } } - } - if (subs > 0) { - if ((unread > 0) || (open > 0)) { - g_string_append(text, "\n"); + if (subs > 0) { + if ((unread > 0) || (open > 0)) { + g_string_append(text, "\n"); + } + if (subs == 1) { + g_string_append(text, "1 subscription request"); + } else { + g_string_append_printf(text, "%d subscription requests", subs); + } } - if (subs == 1) { - g_string_append(text, "1 subscription request"); - } else { - g_string_append_printf(text, "%d subscription requests", subs); + + if ((unread > 0) || (open > 0) || (subs > 0)) { + _notify(text->str, 5000, "Incoming message"); } - } - if ((unread > 0) || (open > 0) || (subs > 0)) { - _notify(text->str, 5000, "Incoming message"); - } + g_string_free(text, TRUE); - g_string_free(text, TRUE); + g_timer_start(remind_timer); + } } static void diff --git a/src/ui/ui.h b/src/ui/ui.h index e28914ff..99e73b4a 100644 --- a/src/ui/ui.h +++ b/src/ui/ui.h @@ -51,8 +51,6 @@ #include "ui/window.h" #include "xmpp/xmpp.h" -#define INP_WIN_MAX 1000 - // ui startup and control void ui_init(void); void ui_load_colours(void); @@ -61,7 +59,6 @@ void ui_close(void); void ui_redraw(void); void ui_resize(void); GSList* ui_get_chat_recipients(void); -void ui_handle_special_keys(const wint_t * const ch, const int result); gboolean ui_switch_win(const int i); void ui_next_win(void); void ui_previous_win(void); @@ -230,10 +227,9 @@ void ui_update_presence(const resource_presence_t resource_presence, void ui_about(void); void ui_statusbar_new(const int win); -wint_t ui_get_char(char *input, int *size, int *result); +char * ui_readline(void); void ui_input_clear(void); void ui_input_nonblocking(gboolean); -void ui_replace_input(char *input, const char * const new_input, int *size); void ui_invalid_command_usage(const char * const usage, void (*setting_func)(void)); @@ -243,6 +239,8 @@ void ui_open_xmlconsole_win(void); gboolean ui_win_has_unsaved_form(int num); +void ui_inp_history_append(char *inp); + // console window actions void cons_show(const char * const msg, ...); void cons_about(void); @@ -330,6 +328,7 @@ void rosterwin_roster(void); void occupantswin_occupants(const char * const room); // desktop notifier actions +void notifier_initialise(void); void notifier_uninit(void); void notify_typing(const char * const handle); diff --git a/src/ui/window.c b/src/ui/window.c index 3a45ab01..54f1b99f 100644 --- a/src/ui/window.c +++ b/src/ui/window.c @@ -330,6 +330,7 @@ win_free(ProfWin* window) buffer_free(window->layout->buffer); delwin(window->layout->win); } + free(window->layout); if (window->type == WIN_CHAT) { ProfChatWin *chatwin = (ProfChatWin*)window; @@ -358,6 +359,116 @@ win_free(ProfWin* window) } void +win_handle_page(ProfWin *window, const wint_t ch, const int result) +{ + int rows = getmaxy(stdscr); + int y = getcury(window->layout->win); + + int page_space = rows - 4; + int *page_start = &(window->layout->y_pos); + + if (prefs_get_boolean(PREF_MOUSE)) { + MEVENT mouse_event; + + if (ch == KEY_MOUSE) { + if (getmouse(&mouse_event) == OK) { + +#ifdef PLATFORM_CYGWIN + if (mouse_event.bstate & BUTTON5_PRESSED) { // mouse wheel down +#else + if (mouse_event.bstate & BUTTON2_PRESSED) { // mouse wheel down +#endif + *page_start += 4; + + // only got half a screen, show full screen + if ((y - (*page_start)) < page_space) + *page_start = y - page_space; + + // went past end, show full screen + else if (*page_start >= y) + *page_start = y - page_space; + + window->layout->paged = 1; + win_update_virtual(window); + } else if (mouse_event.bstate & BUTTON4_PRESSED) { // mouse wheel up + *page_start -= 4; + + // went past beginning, show first page + if (*page_start < 0) + *page_start = 0; + + window->layout->paged = 1; + win_update_virtual(window); + } + } + } + } + + // page up + if (ch == KEY_PPAGE) { + *page_start -= page_space; + + // went past beginning, show first page + if (*page_start < 0) + *page_start = 0; + + window->layout->paged = 1; + win_update_virtual(window); + + // page down + } else if (ch == KEY_NPAGE) { + *page_start += page_space; + + // only got half a screen, show full screen + if ((y - (*page_start)) < page_space) + *page_start = y - page_space; + + // went past end, show full screen + else if (*page_start >= y) + *page_start = y - page_space - 1; + + window->layout->paged = 1; + win_update_virtual(window); + } + + // switch off page if last line and space line visible + if ((y) - *page_start == page_space) { + window->layout->paged = 0; + } + + if (window->layout->type == LAYOUT_SPLIT) { + ProfLayoutSplit *split_layout = (ProfLayoutSplit*)window->layout; + int sub_y = getcury(split_layout->subwin); + int *sub_y_pos = &(split_layout->sub_y_pos); + + // alt up arrow + if ((result == KEY_CODE_YES) && ((ch == 565) || (ch == 337))) { + *sub_y_pos -= page_space; + + // went past beginning, show first page + if (*sub_y_pos < 0) + *sub_y_pos = 0; + + win_update_virtual(window); + + // alt down arrow + } else if ((result == KEY_CODE_YES) && ((ch == 524) || (ch == 336))) { + *sub_y_pos += page_space; + + // only got half a screen, show full screen + if ((sub_y- (*sub_y_pos)) < page_space) + *sub_y_pos = sub_y - page_space; + + // went past end, show full screen + else if (*sub_y_pos >= sub_y) + *sub_y_pos = sub_y - page_space - 1; + + win_update_virtual(window); + } + } +} + +void win_update_virtual(ProfWin *window) { int rows, cols; diff --git a/src/ui/window.h b/src/ui/window.h index b6bd0298..fd10a1d7 100644 --- a/src/ui/window.h +++ b/src/ui/window.h @@ -37,6 +37,8 @@ #include "config.h" +#include <wchar.h> + #ifdef HAVE_NCURSESW_NCURSES_H #include <ncursesw/ncurses.h> #elif HAVE_NCURSES_H @@ -176,6 +178,7 @@ void win_show_subwin(ProfWin *window); int win_roster_cols(void); int win_occpuants_cols(void); void win_printline_nowrap(WINDOW *win, char *msg); +void win_handle_page(ProfWin *current, const wint_t ch, const int result); int win_unread(ProfWin *window); gboolean win_has_active_subwin(ProfWin *window); diff --git a/src/xmpp/bookmark.c b/src/xmpp/bookmark.c index ddc6e300..94adabea 100644 --- a/src/xmpp/bookmark.c +++ b/src/xmpp/bookmark.c @@ -220,7 +220,7 @@ bookmark_get_list(void) } char * -bookmark_find(char *search_str) +bookmark_find(const char * const search_str) { return autocomplete_complete(bookmark_ac, search_str, TRUE); } diff --git a/src/xmpp/presence.c b/src/xmpp/presence.c index 1b3e7fc7..65384a0d 100644 --- a/src/xmpp/presence.c +++ b/src/xmpp/presence.c @@ -158,7 +158,7 @@ presence_clear_sub_requests(void) } char * -presence_sub_request_find(char * search_str) +presence_sub_request_find(const char * const search_str) { return autocomplete_complete(sub_requests_ac, search_str, TRUE); } diff --git a/src/xmpp/xmpp.h b/src/xmpp/xmpp.h index 161eebdf..a004a4bf 100644 --- a/src/xmpp/xmpp.h +++ b/src/xmpp/xmpp.h @@ -163,7 +163,7 @@ void presence_subscription(const char * const jid, const jabber_subscr_t action) GSList* presence_get_subscription_requests(void); gint presence_sub_request_count(void); void presence_reset_sub_request_search(void); -char * presence_sub_request_find(char * search_str); +char * presence_sub_request_find(const char * const search_str); void presence_join_room(char *room, char *nick, char * passwd); void presence_change_room_nick(const char * const room, const char * const nick); void presence_leave_chat_room(const char * const room_jid); @@ -208,7 +208,7 @@ gboolean bookmark_update(const char *jid, const char *nick, const char *password gboolean bookmark_remove(const char *jid); gboolean bookmark_join(const char *jid); const GList * bookmark_get_list(void); -char * bookmark_find(char *search_str); +char * bookmark_find(const char * const search_str); void bookmark_autocomplete_reset(void); void roster_send_name_change(const char * const barejid, const char * const new_name, GSList *groups); |