diff --git a/src/command/parser.c b/src/command/parser.c index af01ddcc..d7dfebab 100644 --- a/src/command/parser.c +++ b/src/command/parser.c @@ -201,8 +201,14 @@ parse_args_with_freetext(const char * const inp, int min, int max) in_quotes = TRUE; i++; } - token_start = ©[i]; - token_size++; + if (copy[i] == '"') { + token_start = ©[i+1]; + } else { + token_start = ©[i]; + } + if (copy[i] != '"') { + token_size++; + } } } else { if (in_quotes) { @@ -213,7 +219,9 @@ parse_args_with_freetext(const char * const inp, int min, int max) in_token = FALSE; in_quotes = FALSE; } else { - token_size++; + if (copy[i] != '"') { + token_size++; + } } } else { if ((!in_freetext && copy[i] == ' ') || copy[i] == '\0') { @@ -222,7 +230,9 @@ parse_args_with_freetext(const char * const inp, int min, int max) token_size = 0; in_token = FALSE; } else { - token_size++; + if (copy[i] != '"') { + token_size++; + } } } } diff --git a/src/config/theme.c b/src/config/theme.c index 5ca19969..1c0d176a 100644 --- a/src/config/theme.c +++ b/src/config/theme.c @@ -72,6 +72,8 @@ static struct colours_t { NCURSES_COLOR_T inputtext; NCURSES_COLOR_T timetext; NCURSES_COLOR_T splashtext; + NCURSES_COLOR_T subscribed; + NCURSES_COLOR_T unsubscribed; NCURSES_COLOR_T online; NCURSES_COLOR_T away; NCURSES_COLOR_T xa; @@ -220,6 +222,10 @@ theme_init_colours(void) // states init_pair(60, colour_prefs.typing, colour_prefs.bkgnd); init_pair(61, colour_prefs.gone, colour_prefs.bkgnd); + + // subscription status + init_pair(70, colour_prefs.subscribed, colour_prefs.bkgnd); + init_pair(71, colour_prefs.unsubscribed, colour_prefs.bkgnd); } static NCURSES_COLOR_T @@ -306,6 +312,14 @@ _load_colours(void) _set_colour(timetext_val, &colour_prefs.timetext, COLOR_WHITE); g_free(timetext_val); + gchar *subscribed_val = g_key_file_get_string(theme, "colours", "subscribed", NULL); + _set_colour(subscribed_val, &colour_prefs.subscribed, COLOR_GREEN); + g_free(subscribed_val); + + gchar *unsubscribed_val = g_key_file_get_string(theme, "colours", "unsubscribed", NULL); + _set_colour(unsubscribed_val, &colour_prefs.unsubscribed, COLOR_RED); + g_free(unsubscribed_val); + gchar *online_val = g_key_file_get_string(theme, "colours", "online", NULL); _set_colour(online_val, &colour_prefs.online, COLOR_GREEN); g_free(online_val); diff --git a/src/config/theme.h b/src/config/theme.h index d87b69f2..8878d7b2 100644 --- a/src/config/theme.h +++ b/src/config/theme.h @@ -55,6 +55,8 @@ #define COLOUR_XA COLOR_PAIR(55) #define COLOUR_TYPING COLOR_PAIR(60) #define COLOUR_GONE COLOR_PAIR(61) +#define COLOUR_SUBSCRIBED COLOR_PAIR(70) +#define COLOUR_UNSUBSCRIBED COLOR_PAIR(71) void theme_init(const char * const theme_name); void theme_init_colours(void); diff --git a/src/contact.c b/src/contact.c index bab3d89c..44cbd4b4 100644 --- a/src/contact.c +++ b/src/contact.c @@ -252,6 +252,20 @@ p_contact_subscription(const PContact contact) return contact->subscription; } +gboolean +p_contact_subscribed(const PContact contact) +{ + if (contact->subscription == NULL) { + return FALSE; + } else if (strcmp(contact->subscription, "to") == 0) { + return TRUE; + } else if (strcmp(contact->subscription, "both") == 0) { + return TRUE; + } else { + return FALSE; + } +} + Resource * p_contact_get_resource(const PContact contact, const char * const resource) { diff --git a/src/contact.h b/src/contact.h index cfd8b4d4..141587a0 100644 --- a/src/contact.h +++ b/src/contact.h @@ -53,5 +53,6 @@ Resource * p_contact_get_resource(const PContact contact, const char * const res void p_contact_set_groups(const PContact contact, GSList *groups); GSList * p_contact_groups(const PContact contact); gboolean p_contact_in_group(const PContact contact, const char * const group); +gboolean p_contact_subscribed(const PContact contact); #endif diff --git a/src/tools/autocomplete.c b/src/tools/autocomplete.c index e3829f7f..086dfabe 100644 --- a/src/tools/autocomplete.c +++ b/src/tools/autocomplete.c @@ -26,6 +26,8 @@ #include "autocomplete.h" +#include "ui/ui.h" + struct autocomplete_t { GSList *items; GSList *last_found; @@ -260,6 +262,84 @@ autocomplete_param_with_ac(char *input, int *size, char *command, return auto_msg; } +int +_count_tokens(char *string) +{ + int num_tokens = 0; + + cons_debug("String: %s", string); + + // if no quotes, use glib + if (g_strrstr(string, "\"") == NULL) { + cons_debug("NO QUOTES"); + gchar **tokens = g_strsplit(string, " ", 0); + num_tokens = g_strv_length(tokens); + g_strfreev(tokens); + + // else count tokens including quoted + } else { + cons_debug("QUOTES"); + int length = strlen(string); + int i = 0; + gboolean in_quotes = FALSE; + + // include first token + num_tokens++; + + for (i = 0; i < length; i++) { + if (string[i] == ' ') { + if (!in_quotes) { + num_tokens++; + } + } else if (string[i] == '"') { + if (in_quotes) { + in_quotes = FALSE; + } else { + in_quotes = TRUE; + } + } + } + } + + return num_tokens; +} + +char * +_get_start(char *string, int tokens) +{ + char *result_str = NULL; + int num_tokens = 0; + int length = strlen(string); + int i = 0; + gboolean in_quotes = FALSE; + GString *result = g_string_new(""); + + // include first token + num_tokens++; + + for (i = 0; i < length; i++) { + if (num_tokens < tokens) { + g_string_append_c(result, string[i]); + } + if (string[i] == ' ') { + if (!in_quotes) { + num_tokens++; + } + } else if (string[i] == '"') { + if (in_quotes) { + in_quotes = FALSE; + } else { + in_quotes = TRUE; + } + } + } + + result_str = result->str; + g_string_free(result, FALSE); + + return result_str; +} + char * autocomplete_param_no_with_func(char *input, int *size, char *command, int arg_number, autocomplete_func func) @@ -267,44 +347,35 @@ autocomplete_param_no_with_func(char *input, int *size, char *command, char *result = NULL; if (strncmp(input, command, strlen(command)) == 0 && (*size > strlen(command))) { int i = 0; - int quote_count = 0; char *found = NULL; GString *result_str = NULL; - // copy and null terminate input, count quotes + // copy and null terminate input gchar inp_cpy[*size]; for (i = 0; i < *size; i++) { - if (input[i] == '"') { - quote_count++; - } inp_cpy[i] = input[i]; } inp_cpy[i] = '\0'; g_strstrip(inp_cpy); - // count tokens - gchar **tokens = g_strsplit(inp_cpy, " ", 0); - int num_tokens = g_strv_length(tokens); + // count tokens properly + int num_tokens = _count_tokens(inp_cpy); + cons_debug("tokens: %d", num_tokens); - // if num tokens, or 2 quotes then candidate for autocompletion of last param - if (((num_tokens > arg_number - 1) && quote_count == 0) || quote_count == 2) { + // if correct number of tokens, then candidate for autocompletion of last param + if (num_tokens == arg_number) { - gchar *comp_str = NULL; + gchar *start_str = _get_start(inp_cpy, arg_number); + cons_debug("STARTSTR: %s", start_str); - // find start of autocompletion string - if (num_tokens > 3 && quote_count == 0) { - comp_str = g_strrstr(inp_cpy, tokens[arg_number - 1]); - } else { - comp_str = g_strrstr(inp_cpy, "\""); - comp_str = comp_str + 2; - } + gchar *comp_str = g_strdup(&inp_cpy[strlen(start_str)]); // autocomplete param if (comp_str != NULL) { found = func(comp_str); if (found != NULL) { result_str = g_string_new(""); - g_string_append(result_str, g_strndup(inp_cpy, strlen(inp_cpy) - strlen(comp_str))); + g_string_append(result_str, start_str); g_string_append(result_str, found); result = result_str->str; g_string_free(result_str, FALSE); diff --git a/src/ui/console.c b/src/ui/console.c index 67f3fa28..ee5ad221 100644 --- a/src/ui/console.c +++ b/src/ui/console.c @@ -43,6 +43,7 @@ static ProfWin* console; static void _cons_splash_logo(void); +void _show_roster_contacts(GSList *list, gboolean show_groups); ProfWin * cons_create(void) @@ -1307,17 +1308,9 @@ cons_navigation_help(void) } void -cons_show_roster_group(const char * const group, GSList *list) +_show_roster_contacts(GSList *list, gboolean show_groups) { GSList *curr = list; - cons_show(""); - - if (curr != NULL) { - cons_show("%s:", group); - } else { - cons_show("No group named %s exists.", group); - } - while(curr) { PContact contact = curr->data; @@ -1328,10 +1321,24 @@ cons_show_roster_group(const char * const group, GSList *list) title = g_string_append(title, strdup(p_contact_name(contact))); title = g_string_append(title, ")"); } - cons_show(title->str); + + const char *presence = p_contact_presence(contact); + win_print_time(console, '-'); + if (p_contact_subscribed(contact)) { + win_presence_colour_on(console, presence); + wprintw(console->win, "%s\n", title->str); + win_presence_colour_off(console, presence); + } else { + win_presence_colour_on(console, "offline"); + wprintw(console->win, "%s\n", title->str); + win_presence_colour_off(console, "offline"); + } + g_string_free(title, TRUE); - GString *sub = g_string_new(" Subscription : "); + win_print_time(console, '-'); + wprintw(console->win, " Subscription : "); + GString *sub = g_string_new(""); sub = g_string_append(sub, p_contact_subscription(contact)); if (p_contact_pending_out(contact)) { sub = g_string_append(sub, ", request sent"); @@ -1339,12 +1346,54 @@ cons_show_roster_group(const char * const group, GSList *list) if (presence_sub_request_exists(p_contact_barejid(contact))) { sub = g_string_append(sub, ", request received"); } - cons_show(sub->str); + if (p_contact_subscribed(contact)) { + wattron(console->win, COLOUR_SUBSCRIBED); + } else { + wattron(console->win, COLOUR_UNSUBSCRIBED); + } + wprintw(console->win, "%s\n", sub->str); + if (p_contact_subscribed(contact)) { + wattroff(console->win, COLOUR_SUBSCRIBED); + } else { + wattroff(console->win, COLOUR_UNSUBSCRIBED); + } + g_string_free(sub, TRUE); + if (show_groups) { + GSList *groups = p_contact_groups(contact); + if (groups != NULL) { + GString *groups_str = g_string_new(" Groups : "); + while (groups != NULL) { + g_string_append(groups_str, strdup(groups->data)); + if (g_slist_next(groups) != NULL) { + g_string_append(groups_str, ", "); + } + groups = g_slist_next(groups); + } + + cons_show(groups_str->str); + g_string_free(groups_str, TRUE); + } + } + curr = g_slist_next(curr); } +} + +void +cons_show_roster_group(const char * const group, GSList *list) +{ + cons_show(""); + + if (list != NULL) { + cons_show("%s:", group); + } else { + cons_show("No group named %s exists.", group); + } + + _show_roster_contacts(list, FALSE); ui_console_dirty(); cons_alert(); } @@ -1352,52 +1401,10 @@ cons_show_roster_group(const char * const group, GSList *list) void cons_show_roster(GSList *list) { - GSList *curr = list; cons_show(""); cons_show("Roster:"); - while(curr) { - - PContact contact = curr->data; - GString *title = g_string_new(" "); - title = g_string_append(title, p_contact_barejid(contact)); - if (p_contact_name(contact) != NULL) { - title = g_string_append(title, " ("); - title = g_string_append(title, strdup(p_contact_name(contact))); - title = g_string_append(title, ")"); - } - cons_show(title->str); - g_string_free(title, TRUE); - - GString *sub = g_string_new(" Subscription : "); - sub = g_string_append(sub, p_contact_subscription(contact)); - if (p_contact_pending_out(contact)) { - sub = g_string_append(sub, ", request sent"); - } - if (presence_sub_request_exists(p_contact_barejid(contact))) { - sub = g_string_append(sub, ", request received"); - } - cons_show(sub->str); - g_string_free(sub, TRUE); - - GSList *groups = p_contact_groups(contact); - if (groups != NULL) { - GString *groups_str = g_string_new(" Groups : "); - while (groups != NULL) { - g_string_append(groups_str, strdup(groups->data)); - if (g_slist_next(groups) != NULL) { - g_string_append(groups_str, ", "); - } - groups = g_slist_next(groups); - } - - cons_show(groups_str->str); - g_string_free(groups_str, TRUE); - } - - curr = g_slist_next(curr); - } - + _show_roster_contacts(list, TRUE); ui_console_dirty(); cons_alert(); } diff --git a/src/xmpp/roster.c b/src/xmpp/roster.c index f96a3f84..ed72d502 100644 --- a/src/xmpp/roster.c +++ b/src/xmpp/roster.c @@ -562,14 +562,16 @@ _roster_handle_push(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, // remove each fulljid PContact contact = roster_get_contact(barejid); - GList *resources = p_contact_get_available_resources(contact); - while (resources != NULL) { - GString *fulljid = g_string_new(strdup(barejid)); - g_string_append(fulljid, "/"); - g_string_append(fulljid, strdup(resources->data)); - autocomplete_remove(fulljid_ac, fulljid->str); - g_string_free(fulljid, TRUE); - resources = g_list_next(resources); + if (contact != NULL) { + GList *resources = p_contact_get_available_resources(contact); + while (resources != NULL) { + GString *fulljid = g_string_new(strdup(barejid)); + g_string_append(fulljid, "/"); + g_string_append(fulljid, strdup(resources->data)); + autocomplete_remove(fulljid_ac, fulljid->str); + g_string_free(fulljid, TRUE); + resources = g_list_next(resources); + } } // remove the contact