diff options
author | Michael Catanzaro <mcatanzaro@gnome.org> | 2020-09-24 07:03:10 -0500 |
---|---|---|
committer | Alexander Akulich <akulichalexander@gmail.com> | 2020-11-01 01:12:41 +0300 |
commit | 6967ca8e1f8d8f7948a430fea0bf159e126042be (patch) | |
tree | 76ed6f56dd5ac1d17f4515b7eee3225577d1e135 | |
parent | 3f04a0d60fdc653bffd6919cb374a8d496771a8e (diff) | |
download | telepathy-idle-6967ca8e1f8d8f7948a430fea0bf159e126042be.tar.gz |
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
-rw-r--r-- | src/idle-parser.c | 26 |
1 files 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) { |