diff options
author | TingPing <tingping@tingping.se> | 2014-12-09 03:16:35 -0500 |
---|---|---|
committer | TingPing <tingping@tingping.se> | 2014-12-09 05:30:35 -0500 |
commit | fda692d250dbb65f1305ad054d4c7e61b5d67756 (patch) | |
tree | e6e3d8c3e15f33a2bfc7fa42976e5d8c0ef40018 /src/fe-gtk | |
parent | 99a1fff5908c67b534aa26c0e6e47b2d09c368a5 (diff) |
Fix various unsafe string handling in fkeys
Also removes the 2048 input byte limit And fixes utf8 completion chars in some cases
Diffstat (limited to 'src/fe-gtk')
-rw-r--r-- | src/fe-gtk/fkeys.c | 74 |
1 files changed, 44 insertions, 30 deletions
diff --git a/src/fe-gtk/fkeys.c b/src/fe-gtk/fkeys.c index 2f020311..e27866ee 100644 --- a/src/fe-gtk/fkeys.c +++ b/src/fe-gtk/fkeys.c @@ -1409,9 +1409,6 @@ key_action_tab_clean(void) } } -/* Used in the followig completers */ -#define COMP_BUF 2048 - /* For use in sorting the user list for completion */ static int talked_recent_cmp (struct User *a, struct User *b) @@ -1425,16 +1422,31 @@ talked_recent_cmp (struct User *a, struct User *b) return 0; } +#define COMP_BUF 2048 + +static inline glong +len_to_offset (const char *str, glong len) +{ + return g_utf8_pointer_to_offset (str, str + len); +} + +static inline glong +offset_to_len (const char *str, glong offset) +{ + return g_utf8_offset_to_pointer (str, offset) - str; +} + static int key_action_tab_comp (GtkWidget *t, GdkEventKey *entry, char *d1, char *d2, struct session *sess) { int len = 0, elen = 0, i = 0, cursor_pos, ent_start = 0, comp = 0, found = 0, prefix_len, skip_len = 0, is_nick, is_cmd = 0; - char buf[COMP_BUF], ent[CHANLEN], *postfix = NULL, *result, *ch; + char ent[CHANLEN], *postfix = NULL, *result, *ch; GList *list = NULL, *tmp_list = NULL; const char *text; GCompletion *gcomp = NULL; + GString *buf; /* force the IM Context to reset */ SPELL_ENTRY_SET_EDITABLE (t, FALSE); @@ -1448,8 +1460,6 @@ key_action_tab_comp (GtkWidget *t, GdkEventKey *entry, char *d1, char *d2, cursor_pos = SPELL_ENTRY_GET_POS (t); - buf[0] = 0; /* make sure we don't get garbage in the buffer */ - /* handle "nick: " or "nick " or "#channel "*/ ch = g_utf8_find_prev_char(text, g_utf8_offset_to_pointer(text,cursor_pos)); if (ch && ch[0] == ' ') @@ -1609,40 +1619,42 @@ key_action_tab_comp (GtkWidget *t, GdkEventKey *entry, char *d1, char *d2, /* bash style completion */ if (g_list_next(list) != NULL) { + buf = g_string_sized_new (MAX(COMP_BUF, len + NICKLEN)); if (strlen (result) > elen) /* the largest common prefix is larger than nick, change the data */ { if (prefix_len) - g_utf8_strncpy (buf, text, prefix_len); - strncat (buf, result, COMP_BUF - prefix_len); - cursor_pos = strlen (buf); + g_string_append_len (buf, text, offset_to_len (text, prefix_len)); + g_string_append (buf, result); + cursor_pos = buf->len; g_free(result); if (postfix) { - strcat (buf, " "); - strncat (buf, postfix, COMP_BUF - cursor_pos -1); + g_string_append_c (buf, ' '); + g_string_append (buf, postfix); } - SPELL_ENTRY_SET_TEXT (t, buf); - SPELL_ENTRY_SET_POS (t, g_utf8_pointer_to_offset(buf, buf + cursor_pos)); - buf[0] = 0; + SPELL_ENTRY_SET_TEXT (t, buf->str); + SPELL_ENTRY_SET_POS (t, len_to_offset (buf->str, cursor_pos)); + g_string_erase (buf, 0, -1); } else g_free(result); + while (list) { - len = strlen (buf); /* current buffer */ + len = buf->len; elen = strlen (list->data); /* next item to add */ if (len + elen + 2 >= COMP_BUF) /* +2 is space + null */ { - PrintText (sess, buf); - buf[0] = 0; - len = 0; + PrintText (sess, buf->str); + g_string_erase (buf, 0, -1); } - strcpy (buf + len, (char *) list->data); - strcpy (buf + len + elen, " "); + g_string_append (buf, (char*)list->data); + g_string_append_c (buf, ' '); list = list->next; } - PrintText (sess, buf); + PrintText (sess, buf->str); g_completion_free(gcomp); + g_string_free (buf, TRUE); return 2; } /* Only one matching entry */ @@ -1654,17 +1666,19 @@ key_action_tab_comp (GtkWidget *t, GdkEventKey *entry, char *d1, char *d2, if(result) { + buf = g_string_sized_new (len + NICKLEN); if (prefix_len) - g_utf8_strncpy(buf, text, prefix_len); - strncat (buf, result, COMP_BUF - (prefix_len + 3)); /* make sure nicksuffix and space fits */ + g_string_append_len (buf, text, offset_to_len (text, prefix_len)); + g_string_append (buf, result); if(!prefix_len && is_nick) - strcat (buf, &prefs.hex_completion_suffix[0]); - strcat (buf, " "); - cursor_pos = strlen (buf); + g_string_append_unichar (buf, g_utf8_get_char_validated ((const char*)&prefs.hex_completion_suffix, -1)); + g_string_append_c (buf, ' '); + cursor_pos = buf->len; if (postfix) - strncat (buf, postfix, COMP_BUF - cursor_pos - 2); - SPELL_ENTRY_SET_TEXT (t, buf); - SPELL_ENTRY_SET_POS (t, g_utf8_pointer_to_offset(buf, buf + cursor_pos)); + g_string_append (buf, postfix); + SPELL_ENTRY_SET_TEXT (t, buf->str); + SPELL_ENTRY_SET_POS (t, len_to_offset (buf->str, cursor_pos)); + g_string_free (buf, TRUE); } if (gcomp) g_completion_free(gcomp); @@ -1796,7 +1810,7 @@ replace_handle (GtkWidget *t) snprintf (word, sizeof (word), "%s", pop->cmd); else snprintf (word, sizeof (word), "%s%s", pop->cmd, postfix); - strcat (outbuf, word); + g_strlcat (outbuf, word, sizeof(outbuf)); SPELL_ENTRY_SET_TEXT (t, outbuf); SPELL_ENTRY_SET_POS (t, -1); return; |