summary refs log tree commit diff stats
path: root/src/fe-gtk
diff options
context:
space:
mode:
authorTingPing <tingping@tingping.se>2014-12-09 03:16:35 -0500
committerTingPing <tingping@tingping.se>2014-12-09 05:30:35 -0500
commitfda692d250dbb65f1305ad054d4c7e61b5d67756 (patch)
treee6e3d8c3e15f33a2bfc7fa42976e5d8c0ef40018 /src/fe-gtk
parent99a1fff5908c67b534aa26c0e6e47b2d09c368a5 (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.c74
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;