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); } } @@ -783,6 +791,22 @@ inbound_quit (server *serv, char *nick, char *ip, char *reason) notify_set_offline (serv, nick, was_on_front_session); } +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) { @@ -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);