summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--src/common/hexchat.h2
-rw-r--r--src/common/inbound.c52
-rw-r--r--src/common/inbound.h5
-rw-r--r--src/common/proto-irc.c52
-rw-r--r--src/common/server.c2
-rw-r--r--src/common/userlist.c42
-rw-r--r--src/common/userlist.h6
-rw-r--r--src/fe-gtk/menu.c7
8 files changed, 138 insertions, 30 deletions
diff --git a/src/common/hexchat.h b/src/common/hexchat.h
index 3e07ec4e..958228ff 100644
--- a/src/common/hexchat.h
+++ b/src/common/hexchat.h
@@ -593,6 +593,8 @@ typedef struct server
 	unsigned int have_uhnames:1;
 	unsigned int have_whox:1;		/* have undernet's WHOX features */
 	unsigned int have_idmsg:1;		/* freenode's IDENTIFY-MSG */
+	unsigned int have_accnotify:1; /* cap account-notify */
+	unsigned int have_extjoin:1;	/* cap extended-join */
 	unsigned int have_sasl:1;		/* SASL capability */
 	unsigned int have_except:1;	/* ban exemptions +e */
 	unsigned int have_invite:1;	/* invite exemptions +I */
diff --git a/src/common/inbound.c b/src/common/inbound.c
index 878a8759..47dd0678 100644
--- a/src/common/inbound.c
+++ b/src/common/inbound.c
@@ -137,7 +137,7 @@ static void
 inbound_make_idtext (server *serv, char *idtext, int max, int id)
 {
 	idtext[0] = 0;
-	if (serv->have_idmsg)
+	if (serv->have_idmsg || serv->have_accnotify)
 	{
 		if (id)
 		{
@@ -157,6 +157,7 @@ inbound_privmsg (server *serv, char *from, char *ip, char *text, int id)
 	session *sess;
 	struct User *user;
 	char idtext[64];
+	gboolean nodiag = FALSE;
 
 	sess = find_dialog (serv, from);
 
@@ -189,21 +190,24 @@ inbound_privmsg (server *serv, char *from, char *ip, char *text, int id)
 		return;
 	}
 
-	inbound_make_idtext (serv, idtext, sizeof (idtext), id);
-
 	sess = find_session_from_nick (from, serv);
 	if (!sess)
 	{
 		sess = serv->front_session;
-		EMIT_SIGNAL (XP_TE_PRIVMSG, sess, from, text, idtext, NULL, 0);
-		return;
+		nodiag = TRUE; /* We don't want it to look like a normal message in front sess */
 	}
-	
+
 	user = userlist_find (sess, from);
 	if (user)
+	{
 		user->lasttalk = time (0);
+		if (user->account)
+			id = TRUE;
+	}
+	
+	inbound_make_idtext (serv, idtext, sizeof (idtext), id);
 
-	if (sess->type == SESS_DIALOG)
+	if (sess->type == SESS_DIALOG && !nodiag)
 		EMIT_SIGNAL (XP_TE_DPRIVMSG, sess, from, text, idtext, NULL, 0);
 	else
 		EMIT_SIGNAL (XP_TE_PRIVMSG, sess, from, text, idtext, NULL, 0);
@@ -380,6 +384,8 @@ inbound_action (session *sess, char *chan, char *from, char *ip, char *text, int
 	{
 		nickchar[0] = user->prefix[0];
 		user->lasttalk = time (0);
+		if (user->account)
+			id = TRUE;
 	}
 
 	inbound_make_idtext (serv, idtext, sizeof (idtext), id);
@@ -436,6 +442,8 @@ inbound_chanmsg (server *serv, session *sess, char *chan, char *from, char *text
 	user = userlist_find (sess, from);
 	if (user)
 	{
+		if (user->account)
+			id = TRUE;
 		nickchar[0] = user->prefix[0];
 		user->lasttalk = time (0);
 	}
@@ -655,12 +663,12 @@ inbound_nameslist (server *serv, char *chan, char *names)
 		case 0:
 			name[pos] = 0;
 			if (pos != 0)
-				userlist_add (sess, name, 0);
+				userlist_add (sess, name, 0, NULL, NULL);
 			return;
 		case ' ':
 			name[pos] = 0;
 			pos = 0;
-			userlist_add (sess, name, 0);
+			userlist_add (sess, name, 0, NULL, NULL);
 			break;
 		default:
 			name[pos] = *names;
@@ -705,13 +713,13 @@ inbound_topicnew (server *serv, char *nick, char *chan, char *topic)
 }
 
 void
-inbound_join (server *serv, char *chan, char *user, char *ip)
+inbound_join (server *serv, char *chan, char *user, char *ip, char *account, char *realname)
 {
 	session *sess = find_channel (serv, chan);
 	if (sess)
 	{
 		EMIT_SIGNAL (XP_TE_JOIN, sess, user, chan, ip, NULL, 0);
-		userlist_add (sess, user, ip);
+		userlist_add (sess, user, ip, account, realname);
 	}
 }
 
@@ -784,6 +792,22 @@ inbound_quit (server *serv, char *nick, char *ip, char *reason)
 }
 
 void
+inbound_account (server *serv, char *nick, char *account)
+{
+	session *sess = NULL;
+	GSList *list;
+
+	list = sess_list;
+	while (list)
+	{
+		sess = list->data;
+		if (sess->server == serv)
+			userlist_set_account (sess, nick, account);
+		list = list->next;
+	}
+}
+
+void
 inbound_ping_reply (session *sess, char *timestring, char *from)
 {
 	unsigned long tim, nowtim, dif;
@@ -1252,7 +1276,7 @@ inbound_user_info_start (session *sess, char *nick)
 void
 inbound_user_info (session *sess, char *chan, char *user, char *host,
 						 char *servname, char *nick, char *realname,
-						 unsigned int away)
+						 char *account, unsigned int away)
 {
 	server *serv = sess->server;
 	session *who_sess;
@@ -1269,7 +1293,7 @@ inbound_user_info (session *sess, char *chan, char *user, char *host,
 	{
 		who_sess = find_channel (serv, chan);
 		if (who_sess)
-			userlist_add_hostname (who_sess, nick, uhost, realname, servname, away);
+			userlist_add_hostname (who_sess, nick, uhost, realname, servname, account, away);
 		else
 		{
 			if (serv->doing_dns && nick && host)
@@ -1284,7 +1308,7 @@ inbound_user_info (session *sess, char *chan, char *user, char *host,
 			sess = list->data;
 			if (sess->type == SESS_CHANNEL && sess->server == serv)
 			{
-				userlist_add_hostname (sess, nick, uhost, realname, servname, away);
+				userlist_add_hostname (sess, nick, uhost, realname, servname, account, away);
 			}
 		}
 	}
diff --git a/src/common/inbound.h b/src/common/inbound.h
index d77a9e53..e90ef8c3 100644
--- a/src/common/inbound.h
+++ b/src/common/inbound.h
@@ -23,6 +23,7 @@
 void inbound_next_nick (session *sess, char *nick);
 void inbound_uback (server *serv);
 void inbound_uaway (server *serv);
+void inbound_account (server *serv, char *nick, char *account);
 void inbound_part (server *serv, char *chan, char *user, char *ip, char *reason);
 void inbound_upart (server *serv, char *chan, char *ip, char *reason);
 void inbound_ukick (server *serv, char *chan, char *kicker, char *reason);
@@ -30,12 +31,12 @@ void inbound_kick (server *serv, char *chan, char *user, char *kicker, char *rea
 void inbound_notice (server *serv, char *to, char *nick, char *msg, char *ip, int id);
 void inbound_quit (server *serv, char *nick, char *ip, char *reason);
 void inbound_topicnew (server *serv, char *nick, char *chan, char *topic);
-void inbound_join (server *serv, char *chan, char *user, char *ip);
+void inbound_join (server *serv, char *chan, char *user, char *ip, char *account, char *realname);
 void inbound_ujoin (server *serv, char *chan, char *nick, char *ip);
 void inbound_topictime (server *serv, char *chan, char *nick, time_t stamp);
 void inbound_topic (server *serv, char *chan, char *topic_text);
 void inbound_user_info_start (session *sess, char *nick);
-void inbound_user_info (session *sess, char *chan, char *user, char *host, char *servname, char *nick, char *realname, unsigned int away);
+void inbound_user_info (session *sess, char *chan, char *user, char *host, char *servname, char *nick, char *realname, char *account, unsigned int away);
 void inbound_foundip (session *sess, char *ip);
 int inbound_banlist (session *sess, time_t stamp, char *chan, char *mask, char *banner, int is_exemption);
 void inbound_ping_reply (session *sess, char *timestring, char *from);
diff --git a/src/common/proto-irc.c b/src/common/proto-irc.c
index 906ee713..6eb7c58c 100644
--- a/src/common/proto-irc.c
+++ b/src/common/proto-irc.c
@@ -313,7 +313,10 @@ irc_join_info (server *serv, char *channel)
 static void
 irc_user_list (server *serv, char *channel)
 {
-	tcp_sendf (serv, "WHO %s\r\n", channel);
+	if (serv->have_whox)
+		tcp_sendf (serv, "WHO %s %%chtsunfra,152\r\n", channel);
+	else
+		tcp_sendf (serv, "WHO %s\r\n", channel);
 }
 
 /* userhost */
@@ -328,7 +331,7 @@ static void
 irc_away_status (server *serv, char *channel)
 {
 	if (serv->have_whox)
-		tcp_sendf (serv, "WHO %s %%ctnf,152\r\n", channel);
+		tcp_sendf (serv, "WHO %s %%chtsunfra,152\r\n", channel);
 	else
 		tcp_sendf (serv, "WHO %s\r\n", channel);
 }
@@ -560,7 +563,7 @@ process_numeric (session * sess, int n,
 		if (!serv->skip_next_whois)
 			EMIT_SIGNAL (XP_TE_WHOIS3, whois_sess, word[4], word_eol[5], NULL, NULL, 0);
 		else
-			inbound_user_info (sess, NULL, NULL, NULL, word[5], word[4], NULL, 0xff);
+			inbound_user_info (sess, NULL, NULL, NULL, word[5], word[4], NULL, NULL, 0xff);
 		break;
 
 	case 311:	/* WHOIS 1st line */
@@ -571,7 +574,7 @@ process_numeric (session * sess, int n,
 							 word[6], word_eol[8] + 1, 0);
 		else
 			inbound_user_info (sess, NULL, word[5], word[6], NULL, word[4],
-									 word_eol[8][0] == ':' ? word_eol[8] + 1 : word_eol[8], 0xff);
+									 word_eol[8][0] == ':' ? word_eol[8] + 1 : word_eol[8], NULL, 0xff);
 		break;
 
 	case 314:	/* WHOWAS */
@@ -716,7 +719,7 @@ process_numeric (session * sess, int n,
 				away = 1;
 
 			inbound_user_info (sess, word[4], word[5], word[6], word[7],
-									 word[8], word_eol[11], away);
+									 word[8], word_eol[11], word[10], away);
 
 			/* try to show only user initiated whos */
 			if (!who_sess || !who_sess->doing_who)
@@ -730,16 +733,17 @@ process_numeric (session * sess, int n,
 			unsigned int away = 0;
 			session *who_sess;
 
-			/* irc_away_status sends out a "152" */
+			/* irc_away_status and irc_user_list sends out a "152" */
 			if (!strcmp (word[4], "152"))
 			{
 				who_sess = find_channel (serv, word[5]);
 
-				if (*word[7] == 'G')
+				if (*word[10] == 'G')
 					away = 1;
 
-				/* :SanJose.CA.us.undernet.org 354 z1 152 #zed1 z1 H@ */
-				inbound_user_info (sess, word[5], 0, 0, 0, word[6], 0, away);
+				/* :server 354 yournick 152 #channel ~ident host servname nick H account :realname */
+				inbound_user_info (sess, word[5], word[6], word[7], word[8],
+									 word[9], word_eol[12], word[11], away);
 
 				/* try to show only user initiated whos */
 				if (!who_sess || !who_sess->doing_who)
@@ -965,13 +969,15 @@ process_named_msg (session *sess, char *type, char *word[], char *word_eol[])
 		case WORDL('J','O','I','N'):
 			{
 				char *chan = word[3];
+				char *account = word[4];
+				char *realname = word_eol[5] + 1;
 
 				if (*chan == ':')
 					chan++;
 				if (!serv->p_cmp (nick, serv->nick))
 					inbound_ujoin (serv, chan, nick, ip);
 				else
-					inbound_join (serv, chan, nick, ip);
+					inbound_join (serv, chan, nick, ip, account, realname);
 			}
 			return;
 
@@ -1047,6 +1053,11 @@ process_named_msg (session *sess, char *type, char *word[], char *word_eol[])
 		/* this should compile to a bunch of: CMP.L, JE ... nice & fast */
 		switch (t)
 		{
+
+		case WORDL('A','C','C','O'):
+			inbound_account (serv, nick, word[3]);
+			return;
+			
 		case WORDL('I','N','V','I'):
 			if (ignore_check (word[1], IG_INVI))
 				return;
@@ -1176,6 +1187,16 @@ process_named_msg (session *sess, char *type, char *word[], char *word_eol[])
 						serv->have_awaynotify = TRUE;
 					}
 
+					if (strstr (word_eol[5], "account-notify") != 0)
+					{
+						serv->have_accnotify = TRUE;
+					}
+					
+					if (strstr (word_eol[5], "extended-join") != 0)
+					{
+						serv->have_extjoin = TRUE;
+					}
+
 					if (strstr (word_eol[5], "sasl") != 0)
 					{
 						serv->have_sasl = TRUE;
@@ -1208,6 +1229,17 @@ process_named_msg (session *sess, char *type, char *word[], char *word_eol[])
 						want_cap ? strcat (buffer, " away-notify") : strcpy (buffer, "CAP REQ :away-notify");
 						want_cap = 1;
 					}
+					if (strstr (word_eol[5], "account-notify") != 0)
+					{
+						want_cap ? strcat (buffer, " account-notify") : strcpy (buffer, "CAP REQ :account-notify");
+						want_cap = 1;
+					}
+
+					if (strstr (word_eol[5], "extended-join") != 0)
+					{
+						want_cap ? strcat (buffer, " extended-join") : strcpy (buffer, "CAP REQ :extended-join");
+						want_cap = 1;
+					}
 					/* if the SASL password is set, request SASL auth */
 					if (strstr (word_eol[5], "sasl") != 0 && strlen (sess->server->saslpassword) != 0)
 					{
diff --git a/src/common/server.c b/src/common/server.c
index 9e07b5d5..f1de11fa 100644
--- a/src/common/server.c
+++ b/src/common/server.c
@@ -1888,6 +1888,8 @@ server_set_defaults (server *serv)
 	serv->have_uhnames = FALSE;
 	serv->have_whox = FALSE;
 	serv->have_idmsg = FALSE;
+	serv->have_accnotify = FALSE;
+	serv->have_extjoin = FALSE;
 	serv->have_sasl = FALSE;
 	serv->have_except = FALSE;
 	serv->have_invite = FALSE;
diff --git a/src/common/userlist.c b/src/common/userlist.c
index 868f8a38..17d9494d 100644
--- a/src/common/userlist.c
+++ b/src/common/userlist.c
@@ -113,9 +113,30 @@ userlist_set_away (struct session *sess, char *nick, unsigned int away)
 	}
 }
 
+void
+userlist_set_account (struct session *sess, char *nick, char *account)
+{
+	struct User *user;
+
+	user = userlist_find (sess, nick);
+	if (user)
+	{
+		if (user->account)
+			free (user->account);
+			
+		if (strcmp (account, "*") == 0)
+			user->account = NULL;
+		else
+			user->account = strdup (account);
+			
+		/* gui doesnt currently reflect login status, maybe later
+		fe_userlist_rehash (sess, user); */
+	}
+}
+
 int
 userlist_add_hostname (struct session *sess, char *nick, char *hostname,
-							  char *realname, char *servername, unsigned int away)
+							  char *realname, char *servername, char *account, unsigned int away)
 {
 	struct User *user;
 
@@ -128,6 +149,8 @@ userlist_add_hostname (struct session *sess, char *nick, char *hostname,
 			user->realname = strdup (realname);
 		if (!user->servername && servername)
 			user->servername = strdup (servername);
+		if (!user->account && account && strcmp (account, ":0") != 0 && strcmp (account, "0") != 0)
+			user->account = strdup (account);
 
 		if (away != 0xff)
 		{
@@ -155,6 +178,8 @@ free_user (struct User *user, gpointer data)
 		free (user->hostname);
 	if (user->servername)
 		free (user->servername);
+	if (user->account)
+		free (user->account);
 	free (user);
 
 	return TRUE;
@@ -358,7 +383,7 @@ userlist_remove_user (struct session *sess, struct User *user)
 }
 
 void
-userlist_add (struct session *sess, char *name, char *hostname)
+userlist_add (struct session *sess, char *name, char *hostname, char *account, char *realname)
 {
 	struct User *user;
 	int row, prefix_chars;
@@ -384,6 +409,15 @@ userlist_add (struct session *sess, char *name, char *hostname)
 	/* is it me? */
 	if (!sess->server->p_cmp (user->nick, sess->server->nick))
 		user->me = TRUE;
+	/* extended join info */
+	if (sess->server->have_extjoin)
+	{
+		if (account && strcmp (account, "*") != 0)
+			user->account = strdup (account);
+		if (realname)
+			user->realname = strdup (realname);
+	}
+
 	row = userlist_insertname (sess, user);
 
 	/* duplicate? some broken servers trigger this */
@@ -391,6 +425,10 @@ userlist_add (struct session *sess, char *name, char *hostname)
 	{
 		if (user->hostname)
 			free (user->hostname);
+		if (user->account)
+			free (user->account);
+		if (user->realname)
+			free (user->realname);
 		free (user);
 		return;
 	}
diff --git a/src/common/userlist.h b/src/common/userlist.h
index c1070670..777d61ea 100644
--- a/src/common/userlist.h
+++ b/src/common/userlist.h
@@ -28,6 +28,7 @@ struct User
 	char *hostname;
 	char *realname;
 	char *servername;
+	char *account;
 	time_t lasttalk;
 	unsigned int access;	/* axs bit field */
 	char prefix[2]; /* @ + % */
@@ -43,13 +44,14 @@ struct User
 
 int userlist_add_hostname (session *sess, char *nick,
 									char *hostname, char *realname,
-									char *servername, unsigned int away);
+									char *servername, char *account, unsigned int away);
 void userlist_set_away (session *sess, char *nick, unsigned int away);
+void userlist_set_account (session *sess, char *nick, char *account);
 struct User *userlist_find (session *sess, const char *name);
 struct User *userlist_find_global (server *serv, char *name);
 void userlist_clear (session *sess);
 void userlist_free (session *sess);
-void userlist_add (session *sess, char *name, char *hostname);
+void userlist_add (session *sess, char *name, char *hostname, char *account, char *realname);
 int userlist_remove (session *sess, char *name);
 void userlist_remove_user (session *sess, struct User *user);
 int userlist_change (session *sess, char *oldname, char *newname);
diff --git a/src/fe-gtk/menu.c b/src/fe-gtk/menu.c
index 74b1783f..fa7d5790 100644
--- a/src/fe-gtk/menu.c
+++ b/src/fe-gtk/menu.c
@@ -624,6 +624,13 @@ menu_create_nickinfo_menu (struct User *user, GtkWidget *submenu)
 	g_signal_connect (G_OBJECT (item), "activate",
 							G_CALLBACK (copy_to_clipboard_cb), 
 							user->hostname ? user->hostname : unknown);
+	
+	snprintf (buf, sizeof (buf), fmt, _("Account:"),
+				 user->account ? user->account : unknown);
+	item = menu_quick_item (0, buf, submenu, XCMENU_MARKUP, 0, 0);
+	g_signal_connect (G_OBJECT (item), "activate",
+							G_CALLBACK (copy_to_clipboard_cb), 
+							user->account ? user->account : unknown);
 
 	snprintf (buf, sizeof (buf), fmt, _("Country:"),
 				 user->hostname ? country(user->hostname) : unknown);