Blob Blame History Raw
From 0be57b4f449ce9289734f630873391ef1831dd3c Mon Sep 17 00:00:00 2001
From: Michael Catanzaro <mcatanzaro@gnome.org>
Date: Thu, 24 Sep 2020 07:03:10 -0500
Subject: [PATCH] Properly handle long IRC messages

IRC messages are delimited by CRLF. When the string passed to
idle_parser_receive() doesn't end in \r or \n, the remaining parts get
stashed away to be used to form a message on the next call to
idle_parser_receive(). But telepathy-idle improperly assumes that the
next call to idle_parser_receive() will definitely contain \r or \n,
i.e. it assumes that an IRC message cannot be split between three calls
to idle_parser_receive(). That assumption is wrong.

Fixes polari#147
---
 src/idle-parser.c | 26 +++++++++++++++++++++-----
 1 file changed, 21 insertions(+), 5 deletions(-)

diff --git a/src/idle-parser.c b/src/idle-parser.c
index 159e6cc..71ca8b1 100644
--- a/src/idle-parser.c
+++ b/src/idle-parser.c
@@ -151,6 +151,7 @@ struct _IdleParserPrivate {
 
 	/* continuation line buffer */
 	gchar split_buf[IRC_MSG_MAXLEN + 3];
+	guint split_buf_used;
 
 	/* message handlers */
 	GSList *handlers[IDLE_PARSER_LAST_MESSAGE_CODE];
@@ -226,6 +227,13 @@ strnlen(const char *msg, size_t maxlen)
 }
 #endif
 
+static void clear_split_buf(IdleParser *parser) {
+	IdleParserPrivate *priv = IDLE_PARSER_GET_PRIVATE(parser);
+
+	memset(priv->split_buf, '\0', IRC_MSG_MAXLEN + 3);
+	priv->split_buf_used = 0;
+}
+
 void idle_parser_receive(IdleParser *parser, const gchar *msg) {
 	IdleParserPrivate *priv = IDLE_PARSER_GET_PRIVATE(parser);
 	guint i;
@@ -245,7 +253,7 @@ void idle_parser_receive(IdleParser *parser, const gchar *msg) {
 				if ((lasti == 0) && (priv->split_buf[0] != '\0')) {
 					g_strlcpy(g_stpcpy(concat_buf, priv->split_buf), msg, i + 1);
 					tmp = concat_buf;
-					memset(priv->split_buf, '\0', IRC_MSG_MAXLEN + 3);
+					clear_split_buf(parser);
 				} else {
 					tmp = g_strndup(msg + lasti, i - lasti);
 				}
@@ -264,10 +272,18 @@ void idle_parser_receive(IdleParser *parser, const gchar *msg) {
 		}
 	}
 
-	if (!line_ends)
-		g_strlcpy(priv->split_buf, msg + lasti, (IRC_MSG_MAXLEN + 3) - lasti);
-	else
-		memset(priv->split_buf, '\0', IRC_MSG_MAXLEN + 3);
+	if (!line_ends) {
+		len = strlen(msg + lasti);
+		if (len > (IRC_MSG_MAXLEN + 3) - priv->split_buf_used - 1) {
+			IDLE_DEBUG("Discarding content that exceeds maximum message length: \"%s\"", msg + lasti);
+			clear_split_buf(parser);
+		} else {
+			g_strlcpy(priv->split_buf + priv->split_buf_used, msg + lasti, (IRC_MSG_MAXLEN + 3) - priv->split_buf_used);
+			priv->split_buf_used += len;
+		}
+	} else {
+		clear_split_buf(parser);
+	}
 }
 
 void idle_parser_add_handler(IdleParser *parser, IdleParserMessageCode code, IdleParserMessageHandler handler, gpointer user_data) {
-- 
GitLab