changeset 32793:b4c2802af7f8

Print unknown IRC numerics to channels if we can associate them. Basically, if they are of the form: <routing> <numeric> <...> <channel> <more> ... then we print <numeric>: <more> to <channel>. Thanks to marienz from Freenode for suggesting this. Fixes #15090
author Ethan Blanton <elb@pidgin.im>
date Sun, 06 May 2012 14:45:01 +0000
parents 670296a688dc
children a359399cc0ce
files ChangeLog libpurple/protocols/irc/msgs.c
diffstat 2 files changed, 72 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Sun May 06 06:05:11 2012 +0000
+++ b/ChangeLog	Sun May 06 14:45:01 2012 +0000
@@ -5,6 +5,8 @@
 	* Disable periodic WHO timer.  IRC channel user lists will no
 	  longer automatically display away status, but libpurple will be
 	  much kinder to the network.
+	* Print unknown numerics to channel windows if we can associate
+	  them.  Thanks to Marien Zwart. (#15090)
 
 version 2.10.3 (03/26/2012):
 	MSN:
--- a/libpurple/protocols/irc/msgs.c	Sun May 06 06:05:11 2012 +0000
+++ b/libpurple/protocols/irc/msgs.c	Sun May 06 14:45:01 2012 +0000
@@ -112,9 +112,78 @@
 		irc->timer = purple_timeout_add_seconds(45, (GSourceFunc)irc_blist_timeout, (gpointer)irc);
 }
 
+/* This function is ugly, but it's really an error handler. */
 void irc_msg_default(struct irc_conn *irc, const char *name, const char *from, char **args)
 {
-	char *clean;
+	int i;
+	const char *end, *cur, *numeric = NULL;
+	char *clean, *tmp, *convname;
+	PurpleConversation *convo;
+
+	for (cur = args[0], i = 0; i < 4; i++) {
+		end = strchr(cur, ' ');
+		if (end == NULL) {
+			goto undirected;
+		}
+		/* Check for 3-digit numeric in second position */
+		if (i == 1) {
+			if (end - cur != 3
+			    || !isdigit(cur[0]) || !isdigit(cur[1])
+			    || !isdigit(cur[2])) {
+				goto undirected;
+			}
+			/* Save the numeric for printing to the channel */
+			numeric = cur;
+		}
+		/* Don't advance cur if we're on the final iteration. */
+		if (i != 3) {
+			cur = end + 1;
+		}
+	}
+
+	/* At this point, cur is the beginning of the fourth position,
+	 * end is the following space, and there are remaining
+	 * arguments.  We'll check to see if this argument is a
+	 * currently active conversation (private message or channel,
+	 * either one), and print the numeric to that conversation if it
+	 * is. */
+
+	tmp = g_strndup(cur, end - cur);
+	convname = purple_utf8_salvage(tmp);
+	g_free(tmp);
+
+	/* Check for an existing conversation */
+	convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY,
+						      convname,
+						      irc->account);
+	g_free(convname);
+
+	if (convo == NULL) {
+		goto undirected;
+	}
+
+	/* end + 1 is the first argument past the target.  The initial
+	 * arguments we've skipped are routing info, numeric, recipient
+	 * (this account's nick, most likely), and target (this
+	 * channel).  If end + 1 is an ASCII :, skip it, because it's
+	 * meaningless in this context.  This won't catch all
+	 * :-arguments, but it'll catch the easy case. */
+	if (*++end == ':') {
+		end++;
+	}
+
+	/* We then print "numeric: remainder". */
+	clean = purple_utf8_salvage(end);
+	tmp = g_strdup_printf("%.3s: %s", numeric, clean);
+	g_free(clean);
+	purple_conversation_write(convo, "", tmp,
+				  PURPLE_MESSAGE_SYSTEM|PURPLE_MESSAGE_NO_LOG
+				  |PURPLE_MESSAGE_RAW|PURPLE_MESSAGE_NO_LINKIFY,
+				  time(NULL));
+	g_free(tmp);
+	return;
+
+  undirected:
 	/* This, too, should be escaped somehow (smarter) */
 	clean = purple_utf8_salvage(args[0]);
 	purple_debug(PURPLE_DEBUG_INFO, "irc", "Unrecognized message: %s\n", clean);