summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorDiogo Sousa <diogogsousa@gmail.com>2013-06-22 00:13:36 +0100
committerDiogo Sousa <diogogsousa@gmail.com>2013-06-28 16:03:12 +0100
commit94186f7888d5a730e52e433a21698154dfcc4e2e (patch)
treec7ec4e195a92f0e81d130d1cfe47442e75a5637b
parentac5771377ea95287a99bfd5c8c99ec65e9bb069d (diff)
First step towards message tags extension support
(see http://ircv3.atheme.org/specification/message-tags-3.2).

In particular this commit implements a (very) dummy implementation
sketch of the server-time extension
(see http://ircv3.atheme.org/specification/message-tags-3.2 and #499).
-rw-r--r--src/common/inbound.c17
-rw-r--r--src/common/inbound.h5
-rw-r--r--src/common/outbound.c12
-rw-r--r--src/common/proto-irc.c83
-rw-r--r--src/common/proto-irc.h17
-rw-r--r--src/common/text.c24
-rw-r--r--src/common/text.h10
7 files changed, 136 insertions, 32 deletions
diff --git a/src/common/inbound.c b/src/common/inbound.c
index b1b739e5..55a4005c 100644
--- a/src/common/inbound.c
+++ b/src/common/inbound.c
@@ -158,6 +158,8 @@ inbound_privmsg (server *serv, char *from, char *ip, char *text, int id)
 	struct User *user;
 	char idtext[64];
 	gboolean nodiag = FALSE;
+	message_tags_data tags_data_ = MESSAGE_TAGS_DATA_INIT; /* TODO: this will be an argument */
+	const message_tags_data const *tags_data = &tags_data_;
 
 	sess = find_dialog (serv, from);
 
@@ -186,7 +188,7 @@ inbound_privmsg (server *serv, char *from, char *ip, char *text, int id)
 			}
 			set_topic (sess, ip, ip);
 		}
-		inbound_chanmsg (serv, NULL, NULL, from, text, FALSE, id);
+		inbound_chanmsg (serv, NULL, NULL, from, text, FALSE, id, tags_data);
 		return;
 	}
 
@@ -410,7 +412,9 @@ inbound_action (session *sess, char *chan, char *from, char *ip, char *text, int
 }
 
 void
-inbound_chanmsg (server *serv, session *sess, char *chan, char *from, char *text, char fromme, int id)
+inbound_chanmsg (server *serv, session *sess, char *chan, char *from, 
+		 char *text, char fromme, int id, 
+		 const message_tags_data const *tags_data)
 {
 	struct User *user;
 	int hilight = FALSE;
@@ -462,11 +466,14 @@ inbound_chanmsg (server *serv, session *sess, char *chan, char *from, char *text
 		hilight = TRUE;
 
 	if (sess->type == SESS_DIALOG)
-		EMIT_SIGNAL (XP_TE_DPRIVMSG, sess, from, text, idtext, NULL, 0);
+		EMIT_SIGNAL_TIMESTAMP (XP_TE_DPRIVMSG, sess, from, text, 
+				       idtext, NULL, 0, tags_data->timestamp);
 	else if (hilight)
-		EMIT_SIGNAL (XP_TE_HCHANMSG, sess, from, text, nickchar, idtext, 0);
+		EMIT_SIGNAL_TIMESTAMP (XP_TE_HCHANMSG, sess, from, text,
+				       nickchar, idtext, 0, tags_data->timestamp);
 	else
-		EMIT_SIGNAL (XP_TE_CHANMSG, sess, from, text, nickchar, idtext, 0);
+		EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANMSG, sess, from, text, 
+				       nickchar, idtext, 0, tags_data->timestamp);
 }
 
 void
diff --git a/src/common/inbound.h b/src/common/inbound.h
index 32368cc1..41a927a2 100644
--- a/src/common/inbound.h
+++ b/src/common/inbound.h
@@ -17,6 +17,8 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include "proto-irc.h"
+
 #ifndef HEXCHAT_INBOUND_H
 #define HEXCHAT_INBOUND_H
 
@@ -46,7 +48,8 @@ void inbound_away (server *serv, char *nick, char *msg);
 void inbound_away_notify (server *serv, char *nick, char *reason);
 void inbound_login_start (session *sess, char *nick, char *servname);
 void inbound_login_end (session *sess, char *text);
-void inbound_chanmsg (server *serv, session *sess, char *chan, char *from, char *text, char fromme, int id);
+void inbound_chanmsg (server *serv, session *sess, char *chan, char *from, char *text, char fromme, int id,
+		      const message_tags_data const *tags_data);
 void clear_channel (session *sess);
 void set_topic (session *sess, char *topic, char *stripped_topic);
 void inbound_privmsg (server *serv, char *from, char *ip, char *text, int id);
diff --git a/src/common/outbound.c b/src/common/outbound.c
index 120bb241..d02c88a5 100644
--- a/src/common/outbound.c
+++ b/src/common/outbound.c
@@ -2755,7 +2755,7 @@ cmd_msg (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 				while ((split_text = split_up_text (sess, msg + offset, cmd_length, split_text)))
 				{
 					inbound_chanmsg (newsess->server, NULL, newsess->channel,
-										  newsess->server->nick, split_text, TRUE, FALSE);
+							 newsess->server->nick, split_text, TRUE, FALSE, 0);
 
 					if (*split_text)
 						offset += strlen(split_text);
@@ -2763,7 +2763,7 @@ cmd_msg (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 					g_free(split_text);
 				}
 				inbound_chanmsg (newsess->server, NULL, newsess->channel,
-									  newsess->server->nick, msg + offset, TRUE, FALSE);
+						 newsess->server->nick, msg + offset, TRUE, FALSE, 0);
 			}
 			else
 			{
@@ -3700,7 +3700,7 @@ cmd_wallchan (struct session *sess, char *tbuf, char *word[],
 			if (sess->type == SESS_CHANNEL)
 			{
 				inbound_chanmsg (sess->server, NULL, sess->channel,
-									  sess->server->nick, word_eol[2], TRUE, FALSE);
+						 sess->server->nick, word_eol[2], TRUE, FALSE, 0);
 				sess->server->p_message (sess->server, sess->channel, word_eol[2]);
 			}
 			list = list->next;
@@ -4396,7 +4396,7 @@ handle_say (session *sess, char *text, int check_spch)
 		if (dcc)
 		{
 			inbound_chanmsg (sess->server, NULL, sess->channel,
-								  sess->server->nick, text, TRUE, FALSE);
+					 sess->server->nick, text, TRUE, FALSE, 0);
 			set_topic (sess, net_ip (dcc->addr), net_ip (dcc->addr));
 			goto xit;
 		}
@@ -4411,7 +4411,7 @@ handle_say (session *sess, char *text, int check_spch)
 		while ((split_text = split_up_text (sess, text + offset, cmd_length, split_text)))
 		{
 			inbound_chanmsg (sess->server, sess, sess->channel, sess->server->nick,
-								  split_text, TRUE, FALSE);
+					 split_text, TRUE, FALSE, 0);
 			sess->server->p_message (sess->server, sess->channel, split_text);
 			
 			if (*split_text)
@@ -4421,7 +4421,7 @@ handle_say (session *sess, char *text, int check_spch)
 		}
 
 		inbound_chanmsg (sess->server, sess, sess->channel, sess->server->nick,
-							  text + offset, TRUE, FALSE);
+				 text + offset, TRUE, FALSE, 0);
 		sess->server->p_message (sess->server, sess->channel, text + offset);
 	} else
 	{
diff --git a/src/common/proto-irc.c b/src/common/proto-irc.c
index ec4a36a3..1061b42c 100644
--- a/src/common/proto-irc.c
+++ b/src/common/proto-irc.c
@@ -29,6 +29,7 @@
 #endif
 
 #include "hexchat.h"
+#include "proto-irc.h"
 #include "ctcp.h"
 #include "fe.h"
 #include "ignore.h"
@@ -959,7 +960,8 @@ process_numeric (session * sess, int n,
 /* handle named messages that starts with a ':' */
 
 static void
-process_named_msg (session *sess, char *type, char *word[], char *word_eol[])
+process_named_msg (session *sess, char *type, char *word[], char *word_eol[],
+		   const message_tags_data const *tags_data)
 {
 	server *serv = sess->server;
 	char ip[128], nick[NICKLEN];
@@ -1173,7 +1175,7 @@ process_named_msg (session *sess, char *type, char *word[], char *word_eol[])
 						{
 							if (ignore_check (word[1], IG_CHAN))
 								return;
-							inbound_chanmsg (serv, NULL, to, nick, text, FALSE, id);
+							inbound_chanmsg (serv, NULL, to, nick, text, FALSE, id, tags_data);
 						} else
 						{
 							if (ignore_check (word[1], IG_PRIV))
@@ -1368,8 +1370,55 @@ process_named_servermsg (session *sess, char *buf, char *rawname, char *word_eol
 	EMIT_SIGNAL (XP_TE_SERVTEXT, sess, buf, sess->server->servername, rawname, NULL, 0);
 }
 
-/* irc_inline() - 1 single line received from serv */
+/* Handle time-server tags.
+ * 
+ * Sets timestamp to the correct time. This needs to take into account that
+ * time is in UTC, so we should convert it to our local time.
+ *
+ * See http://ircv3.atheme.org/extensions/server-time-3.2
+ */
+static void
+handle_message_tag_time (const char const *time, message_tags_data *tags_data)
+{
+	/* TODO, obviously :P */
+	tags_data->timestamp = 44332211;
+}
+
+/* Handle message tags.
+ *
+ * See http://ircv3.atheme.org/specification/message-tags-3.2 
+ */
+/* FIXME: we should ignore capabilities not enabled! */
+static void
+handle_message_tags (const char const *tags_str, message_tags_data *tags_data)
+{
+	char **tags;
+	int i;
+
+	/* FIXME We might want to avoid the allocation overhead here since 
+	 * this might be called for every message from the server.
+	 */
+	tags = g_strsplit (tags_str, ";", 0);
+
+	for (i=0; tags[i]; i++)
+	{
+		char *key = tags[i];
+		char *value = strchr (tags[i], '=');
+
+		if (!value)
+			continue;
+
+		*value = '\0';
+		value++;
+
+		if (!strcmp (key, "time"))
+			handle_message_tag_time (value, tags_data);
+	}
+	
+	g_strfreev (tags);
+}
 
+/* irc_inline() - 1 single line received from serv */
 static void
 irc_inline (server *serv, char *buf, int len)
 {
@@ -1379,8 +1428,7 @@ irc_inline (server *serv, char *buf, int len)
 	char *word_eol[PDIWORDS+1];
 	char pdibuf_static[522]; /* 1 line can potentially be 512*6 in utf8 */
 	char *pdibuf = pdibuf_static;
-
-	url_check_line (buf, len);
+	message_tags_data tags_data = MESSAGE_TAGS_DATA_INIT;
 
 	/* need more than 522? fall back to malloc */
 	if (len >= sizeof (pdibuf_static))
@@ -1392,11 +1440,27 @@ irc_inline (server *serv, char *buf, int len)
 	word[PDIWORDS] = NULL;
 	word_eol[PDIWORDS] = NULL;
 
-	if (buf[0] == ':')
+	if (*buf == '@')
 	{
-		/* split line into words and words_to_end_of_line */
-		process_data_init (pdibuf, buf, word, word_eol, FALSE, FALSE);
+		char *tags = buf + 1; /* skip the '@' */
+		char *sep = strchr (buf, ' ');
 
+		if (!sep)
+			goto xit;
+		
+		*sep = '\0';
+		buf = sep + 1;
+
+		handle_message_tags(tags, &tags_data);
+	}
+
+	url_check_line (buf, len);
+
+	/* split line into words and words_to_end_of_line */
+	process_data_init (pdibuf, buf, word, word_eol, FALSE, FALSE);
+
+	if (buf[0] == ':')
+	{
 		/* find a context for this message */
 		if (is_channel (serv, word[3]))
 		{
@@ -1417,7 +1481,6 @@ irc_inline (server *serv, char *buf, int len)
 
 	} else
 	{
-		process_data_init (pdibuf, buf, word, word_eol, FALSE, FALSE);
 		word[0] = type = word[1];
 		if (plugin_emit_server (sess, type, word, word_eol))
 			goto xit;
@@ -1439,7 +1502,7 @@ irc_inline (server *serv, char *buf, int len)
 		process_numeric (sess, atoi (word[2]), word, word_eol, text);
 	} else
 	{
-		process_named_msg (sess, type, word, word_eol);
+		process_named_msg (sess, type, word, word_eol, &tags_data);
 	}
 
 xit:
diff --git a/src/common/proto-irc.h b/src/common/proto-irc.h
index 2de9815c..7c8a483f 100644
--- a/src/common/proto-irc.h
+++ b/src/common/proto-irc.h
@@ -17,9 +17,26 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include <time.h>
+#include "hexchat.h"
+
 #ifndef HEXCHAT_PROTO_H
 #define HEXCHAT_PROTO_H
 
+#define MESSAGE_TAGS_DATA_INIT			\
+	{					\
+		.timestamp=(time_t)0,		\
+	}
+
+/* Message tag information that might be passed along with a server message
+ *
+ * See http://ircv3.atheme.org/specification/capability-negotiation-3.1
+ */
+typedef struct 
+{
+	time_t timestamp;
+} message_tags_data;
+
 void proto_fill_her_up (server *serv);
 
 #endif
diff --git a/src/common/text.c b/src/common/text.c
index f0a1dfb1..dc81feeb 100644
--- a/src/common/text.c
+++ b/src/common/text.c
@@ -865,8 +865,8 @@ text_validate (char **text, int *len)
 	return utf;
 }
 
-void
-PrintText (session *sess, char *text)
+static void
+PrintTextTimeStamp (session *sess, char *text, time_t timestamp)
 {
 	char *conv;
 
@@ -890,13 +890,19 @@ PrintText (session *sess, char *text)
 
 	log_write (sess, text);
 	scrollback_save (sess, text);
-	fe_print_text (sess, text, 0);
+	fe_print_text (sess, text, timestamp);
 
 	if (conv)
 		g_free (conv);
 }
 
 void
+PrintText (session *sess, char *text)
+{
+	PrintTextTimeStamp (sess, text, 0);
+}
+
+void
 PrintTextf (session *sess, char *format, ...)
 {
 	va_list args;
@@ -1836,12 +1842,13 @@ format_event (session *sess, int index, char **args, char *o, int sizeofo, unsig
 }
 
 static void
-display_event (session *sess, int event, char **args, unsigned int stripcolor_args)
+display_event (session *sess, int event, char **args, 
+	       unsigned int stripcolor_args, time_t timestamp)
 {
 	char o[4096];
 	format_event (sess, event, args, o, sizeof (o), stripcolor_args);
 	if (o[0])
-		PrintText (sess, o);
+		PrintTextTimeStamp (sess, o, timestamp);
 }
 
 int
@@ -2042,7 +2049,8 @@ text_color_of (char *name)
 /* called by EMIT_SIGNAL macro */
 
 void
-text_emit (int index, session *sess, char *a, char *b, char *c, char *d)
+text_emit (int index, session *sess, char *a, char *b, char *c, char *d,
+	   time_t timestamp)
 {
 	char *word[PDIWORDS];
 	int i;
@@ -2120,7 +2128,7 @@ text_emit (int index, session *sess, char *a, char *b, char *c, char *d)
 	}
 
 	sound_play_event (index);
-	display_event (sess, index, word, stripcolor_args);
+	display_event (sess, index, word, stripcolor_args, timestamp);
 }
 
 char *
@@ -2143,7 +2151,7 @@ text_emit_by_name (char *name, session *sess, char *a, char *b, char *c, char *d
 	i = pevent_find (name, &i);
 	if (i >= 0)
 	{
-		text_emit (i, sess, a, b, c, d);
+		text_emit (i, sess, a, b, c, d, 0);
 		return 1;
 	}
 
diff --git a/src/common/text.h b/src/common/text.h
index 52cc8ea9..dc5e5f72 100644
--- a/src/common/text.h
+++ b/src/common/text.h
@@ -17,12 +17,17 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include <time.h>
 #include "textenums.h"
 
 #ifndef HEXCHAT_TEXT_H
 #define HEXCHAT_TEXT_H
 
-#define EMIT_SIGNAL(i, sess, a, b, c, d, e) text_emit(i, sess, a, b, c, d)
+/* timestamp is non-zero if we are using server-time */
+#define EMIT_SIGNAL_TIMESTAMP(i, sess, a, b, c, d, e, timestamp) \
+	text_emit(i, sess, a, b, c, d, timestamp)
+#define EMIT_SIGNAL(i, sess, a, b, c, d, e) \
+	text_emit(i, sess, a, b, c, d, 0)
 
 struct text_event
 {
@@ -46,7 +51,8 @@ int pevt_build_string (const char *input, char **output, int *max_arg);
 int pevent_load (char *filename);
 void pevent_make_pntevts (void);
 int text_color_of (char *name);
-void text_emit (int index, session *sess, char *a, char *b, char *c, char *d);
+void text_emit (int index, session *sess, char *a, char *b, char *c, char *d,
+		time_t timestamp);
 int text_emit_by_name (char *name, session *sess, char *a, char *b, char *c, char *d);
 char *text_validate (char **text, int *len);
 int get_stamp_str (char *fmt, time_t tim, char **ret);