diff -ru xchat-2.8.6/src/common/ctcp.c xchat-2.8.6/src/common/ctcp.c --- xchat-2.8.6/src/common/ctcp.c 2008-02-05 12:02:47.000000000 +0200 +++ xchat-2.8.6/src/common/ctcp.c 2008-09-13 20:17:43.000000000 +0300 @@ -149,11 +149,11 @@ if (!chansess) chansess = sess; - EMIT_SIGNAL (XP_TE_CTCPSNDC, chansess, word[5], + EMIT_SIGNAL (XP_TE_CTCPSNDC, chansess, word[5], /* XXX unsafe_name? */ nick, to, NULL, 0); } else { - EMIT_SIGNAL (XP_TE_CTCPSND, sess->server->front_session, word[5], + EMIT_SIGNAL (XP_TE_CTCPSND, sess->server->front_session, word[5], /* XXX unsafe_name? */ nick, NULL, NULL, 0); } @@ -182,6 +182,7 @@ chansess = find_channel (sess->server, to); if (!chansess) chansess = sess; + /* FIXME it's a channel, but do we need to unsafe_name it? */ EMIT_SIGNAL (XP_TE_CTCPGENC, chansess, msg, nick, to, NULL, 0); } } diff -ru xchat-2.8.6/src/common/inbound.c xchat-2.8.6/src/common/inbound.c --- xchat-2.8.6/src/common/inbound.c 2008-03-19 06:28:03.000000000 +0200 +++ xchat-2.8.6/src/common/inbound.c 2008-09-13 20:27:09.000000000 +0300 @@ -513,6 +513,7 @@ inbound_ujoin (server *serv, char *chan, char *nick, char *ip) { session *sess; + char uchan[CHANLEN]; /* already joined? probably a bnc */ sess = find_channel (serv, chan); @@ -548,7 +549,8 @@ /* sends a MODE */ serv->p_join_info (sess->server, chan); - EMIT_SIGNAL (XP_TE_UJOIN, sess, nick, chan, ip, NULL, 0); + rfc_unsafe_chan (uchan, chan, CHANLEN); + EMIT_SIGNAL (XP_TE_UJOIN, sess, nick, uchan, ip, NULL, 0); if (prefs.userhost) { @@ -564,7 +566,9 @@ session *sess = find_channel (serv, chan); if (sess) { - EMIT_SIGNAL (XP_TE_UKICK, sess, serv->nick, chan, kicker, reason, 0); + char uchan[CHANLEN]; + rfc_unsafe_chan (uchan, chan, CHANLEN); + EMIT_SIGNAL (XP_TE_UKICK, sess, serv->nick, uchan, kicker, reason, 0); clear_channel (sess); if (prefs.autorejoin) { @@ -580,11 +584,13 @@ session *sess = find_channel (serv, chan); if (sess) { + char uchan[CHANLEN]; + rfc_unsafe_chan (uchan, chan, CHANLEN); if (*reason) - EMIT_SIGNAL (XP_TE_UPARTREASON, sess, serv->nick, ip, chan, reason, + EMIT_SIGNAL (XP_TE_UPARTREASON, sess, serv->nick, ip, uchan, reason, 0); else - EMIT_SIGNAL (XP_TE_UPART, sess, serv->nick, ip, chan, NULL, 0); + EMIT_SIGNAL (XP_TE_UPART, sess, serv->nick, ip, uchan, NULL, 0); clear_channel (sess); } } @@ -594,17 +600,19 @@ { session *sess; char name[NICKLEN]; + char uchan[CHANLEN]; int pos = 0; sess = find_channel (serv, chan); + rfc_unsafe_chan (uchan, chan, CHANLEN); if (!sess) { - EMIT_SIGNAL (XP_TE_USERSONCHAN, serv->server_session, chan, names, NULL, + EMIT_SIGNAL (XP_TE_USERSONCHAN, serv->server_session, uchan, names, NULL, NULL, 0); return; } if (!sess->ignore_names) - EMIT_SIGNAL (XP_TE_USERSONCHAN, sess, chan, names, NULL, NULL, 0); + EMIT_SIGNAL (XP_TE_USERSONCHAN, sess, uchan, names, NULL, NULL, 0); if (sess->end_of_names) { @@ -640,6 +648,7 @@ { session *sess = find_channel (serv, chan); char *stripped_topic; + char uchan[CHANLEN]; if (sess) { @@ -649,7 +658,8 @@ } else sess = serv->server_session; - EMIT_SIGNAL (XP_TE_TOPIC, sess, chan, topic_text, NULL, NULL, 0); + rfc_unsafe_chan (uchan, chan, CHANLEN); + EMIT_SIGNAL (XP_TE_TOPIC, sess, uchan, topic_text, NULL, NULL, 0); } void @@ -661,10 +671,12 @@ sess = find_channel (serv, chan); if (sess) { + char uchan[CHANLEN]; stripped_topic = strip_color (topic, -1, STRIP_ALL); set_topic (sess, topic, stripped_topic); g_free (stripped_topic); - EMIT_SIGNAL (XP_TE_NEWTOPIC, sess, nick, topic, chan, NULL, 0); + rfc_unsafe_chan (uchan, chan, CHANLEN); + EMIT_SIGNAL (XP_TE_NEWTOPIC, sess, nick, topic, uchan, NULL, 0); } } @@ -674,7 +686,9 @@ session *sess = find_channel (serv, chan); if (sess) { - EMIT_SIGNAL (XP_TE_JOIN, sess, user, chan, ip, NULL, 0); + char uchan[CHANLEN]; + rfc_unsafe_chan (uchan, chan, CHANLEN); + EMIT_SIGNAL (XP_TE_JOIN, sess, user, uchan, ip, NULL, 0); userlist_add (sess, user, ip); } } @@ -685,7 +699,9 @@ session *sess = find_channel (serv, chan); if (sess) { - EMIT_SIGNAL (XP_TE_KICK, sess, kicker, user, chan, reason, 0); + char uchan[CHANLEN]; + rfc_unsafe_chan (uchan, chan, CHANLEN); + EMIT_SIGNAL (XP_TE_KICK, sess, kicker, user, uchan, reason, 0); userlist_remove (sess, user); } } @@ -696,10 +712,12 @@ session *sess = find_channel (serv, chan); if (sess) { + char uchan[CHANLEN]; + rfc_unsafe_chan (uchan, chan, CHANLEN); if (*reason) - EMIT_SIGNAL (XP_TE_PARTREASON, sess, user, ip, chan, reason, 0); + EMIT_SIGNAL (XP_TE_PARTREASON, sess, user, ip, uchan, reason, 0); else - EMIT_SIGNAL (XP_TE_PART, sess, user, ip, chan, NULL, 0); + EMIT_SIGNAL (XP_TE_PART, sess, user, ip, uchan, NULL, 0); userlist_remove (sess, user); } } @@ -708,13 +726,15 @@ inbound_topictime (server *serv, char *chan, char *nick, time_t stamp) { char *tim = ctime (&stamp); + char uchan[CHANLEN]; session *sess = find_channel (serv, chan); if (!sess) sess = serv->server_session; tim[24] = 0; /* get rid of the \n */ - EMIT_SIGNAL (XP_TE_TOPICDATE, sess, chan, nick, tim, NULL, 0); + rfc_unsafe_chan (uchan, chan, CHANLEN); + EMIT_SIGNAL (XP_TE_TOPICDATE, sess, uchan, nick, tim, NULL, 0); } void @@ -1231,12 +1251,14 @@ if (!fe_is_banwindow (sess)) { + char uchan[CHANLEN]; nowindow: /* let proto-irc.c do the 'goto def' for exemptions */ if (is_exemption) return FALSE; - EMIT_SIGNAL (XP_TE_BANLIST, sess, chan, mask, banner, time_str, 0); + rfc_unsafe_chan (uchan, chan, CHANLEN); + EMIT_SIGNAL (XP_TE_BANLIST, sess, uchan, mask, banner, time_str, 0); return TRUE; } diff -ru xchat-2.8.6/src/common/proto-irc.c xchat-2.8.6/src/common/proto-irc.c --- xchat-2.8.6/src/common/proto-irc.c 2008-04-02 07:32:15.000000000 +0300 +++ xchat-2.8.6/src/common/proto-irc.c 2008-09-13 20:23:43.000000000 +0300 @@ -422,9 +422,11 @@ channel_date (session *sess, char *chan, char *timestr) { time_t timestamp = (time_t) atol (timestr); + char uchan[CHANLEN]; char *tim = ctime (×tamp); tim[24] = 0; /* get rid of the \n */ - EMIT_SIGNAL (XP_TE_CHANDATE, sess, chan, tim, NULL, NULL, 0); + rfc_unsafe_chan (uchan, chan, CHANLEN); + EMIT_SIGNAL (XP_TE_CHANDATE, sess, uchan, tim, NULL, NULL, 0); } static void @@ -434,6 +436,7 @@ server *serv = sess->server; /* show whois is the server tab */ session *whois_sess = serv->server_session; + char uchan[CHANLEN]; /* unless this setting is on */ if (prefs.irc_whois_front) @@ -598,9 +601,11 @@ case 313: case 319: + /* FIXME: Is this really necessary? */ + rfc_unsafe_chan (uchan, word_eol[5] + 1, CHANLEN); if (!serv->skip_next_whois) EMIT_SIGNAL (XP_TE_WHOIS2, whois_sess, word[4], - word_eol[5] + 1, NULL, NULL, 0); + uchan, NULL, NULL, 0); break; case 307: /* dalnet version */ @@ -640,8 +645,11 @@ if (sess->ignore_mode) sess->ignore_mode = FALSE; else - EMIT_SIGNAL (XP_TE_CHANMODES, sess, word[4], word_eol[5], + { + rfc_unsafe_chan (uchan, word_eol[5], CHANLEN); + EMIT_SIGNAL (XP_TE_CHANMODES, sess, word[4], uchan, NULL, NULL, 0); + } fe_update_mode_buttons (sess, 't', '-'); fe_update_mode_buttons (sess, 'n', '-'); fe_update_mode_buttons (sess, 's', '-'); @@ -686,7 +694,8 @@ #endif case 341: /* INVITE ACK */ - EMIT_SIGNAL (XP_TE_UINVITE, sess, word[4], word[5], serv->servername, + rfc_unsafe_chan (uchan, word[5], CHANLEN); + EMIT_SIGNAL (XP_TE_UINVITE, sess, word[4], uchan, serv->servername, NULL, 0); break; @@ -828,19 +837,23 @@ break; case 471: - EMIT_SIGNAL (XP_TE_USERLIMIT, sess, word[4], NULL, NULL, NULL, 0); + rfc_unsafe_chan (uchan, word[4], CHANLEN); + EMIT_SIGNAL (XP_TE_USERLIMIT, sess, uchan, NULL, NULL, NULL, 0); break; case 473: - EMIT_SIGNAL (XP_TE_INVITE, sess, word[4], NULL, NULL, NULL, 0); + rfc_unsafe_chan (uchan, word[4], CHANLEN); + EMIT_SIGNAL (XP_TE_INVITE, sess, uchan, NULL, NULL, NULL, 0); break; case 474: - EMIT_SIGNAL (XP_TE_BANNED, sess, word[4], NULL, NULL, NULL, 0); + rfc_unsafe_chan (uchan, word[4], CHANLEN); + EMIT_SIGNAL (XP_TE_BANNED, sess, uchan, NULL, NULL, NULL, 0); break; case 475: - EMIT_SIGNAL (XP_TE_KEYWORD, sess, word[4], NULL, NULL, NULL, 0); + rfc_unsafe_chan (uchan, word[4], CHANLEN); + EMIT_SIGNAL (XP_TE_KEYWORD, sess, uchan, NULL, NULL, NULL, 0); break; case 601: @@ -990,6 +1003,7 @@ else if (len >= 5) { guint32 t; + char uchan[CHANLEN]; t = WORDL((guint8)type[0], (guint8)type[1], (guint8)type[2], (guint8)type[3]); /* this should compile to a bunch of: CMP.L, JE ... nice & fast */ @@ -1000,11 +1014,16 @@ return; if (word[4][0] == ':') + { + rfc_unsafe_chan (uchan, word[4] + 1, CHANLEN); EMIT_SIGNAL (XP_TE_INVITED, sess, word[4] + 1, nick, serv->servername, NULL, 0); - else + } else + { + rfc_unsafe_chan (uchan, word[4], CHANLEN); EMIT_SIGNAL (XP_TE_INVITED, sess, word[4], nick, serv->servername, NULL, 0); + } return; diff -ru xchat-2.8.6/src/common/text.c xchat-2.8.6/src/common/text.c --- xchat-2.8.6/src/common/text.c 2008-03-28 04:20:04.000000000 +0200 +++ xchat-2.8.6/src/common/text.c 2008-09-13 20:17:43.000000000 +0300 @@ -372,10 +372,12 @@ static char * log_create_filename (char *channame) { + char unsafe[CHANLEN]; char *tmp, *ret; int mbl; - ret = tmp = strdup (channame); + rfc_unsafe_chan (unsafe, channame, CHANLEN); + ret = tmp = strdup (unsafe); while (*tmp) { mbl = g_utf8_skip[((unsigned char *)tmp)[0]]; diff -ru xchat-2.8.6/src/common/util.c xchat-2.8.6/src/common/util.c --- xchat-2.8.6/src/common/util.c 2008-09-13 20:17:15.000000000 +0300 +++ xchat-2.8.6/src/common/util.c 2008-09-13 20:17:43.000000000 +0300 @@ -1450,6 +1450,18 @@ 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff };*/ +void +rfc_unsafe_chan (char *dst, char *src, int len) +{ + if (src[0] != '!' || strlen (src) < 7) + safe_strcpy (dst, src, len); + else + { + dst[0] = '!'; + safe_strcpy (dst + 1, src + 6, len - 6); + } +} + /*static int rename_utf8 (char *oldname, char *newname) { diff -ru xchat-2.8.6/src/common/util.h xchat-2.8.6/src/common/util.h --- xchat-2.8.6/src/common/util.h 2008-09-13 20:17:15.000000000 +0300 +++ xchat-2.8.6/src/common/util.h 2008-09-13 20:17:43.000000000 +0300 @@ -27,6 +27,7 @@ int rfc_casecmp (const char *, const char *); int rfc_ncasecmp (char *, char *, int); int hal_casecomp ( char *s1, char *s2); +void rfc_unsafe_chan (char *dst, char *src, int len); int buf_get_line (char *, char **, int *, int len); char *nocasestrstr (const char *text, const char *tofind); char *country (char *); diff -ru xchat-2.8.6/src/fe-gtk/banlist.c xchat-2.8.6/src/fe-gtk/banlist.c --- xchat-2.8.6/src/fe-gtk/banlist.c 2008-02-05 12:02:50.000000000 +0200 +++ xchat-2.8.6/src/fe-gtk/banlist.c 2008-09-13 20:17:43.000000000 +0300 @@ -40,6 +40,7 @@ #include "../common/fe.h" #include "../common/modes.h" #include "../common/outbound.h" +#include "../common/util.h" #include "../common/xchatc.h" #include "gtkutil.h" #include "maingui.h" @@ -125,11 +126,13 @@ if (sess->server->connected) { GtkListStore *store; + char uchan[CHANLEN]; gtk_widget_set_sensitive (sess->res->banlist_butRefresh, FALSE); + rfc_unsafe_chan (uchan, sess->channel, CHANLEN); snprintf (tbuf, sizeof tbuf, "XChat: Ban List (%s, %s)", - sess->channel, sess->server->servername); + uchan, sess->server->servername); mg_set_title (sess->res->banlist_window, tbuf); store = get_store (sess); @@ -272,10 +275,12 @@ banlist_clear (GtkWidget * wid, struct session *sess) { GtkWidget *dialog; + char uchan[CHANLEN]; + rfc_unsafe_chan (uchan, sess->channel, CHANLEN); dialog = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_OK_CANCEL, - _("Are you sure you want to remove all bans in %s?"), sess->channel); + _("Are you sure you want to remove all bans in %s?"), uchan); g_signal_connect (G_OBJECT (dialog), "response", G_CALLBACK (banlist_clear_cb), sess); gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE); diff -ru xchat-2.8.6/src/fe-gtk/maingui.c xchat-2.8.6/src/fe-gtk/maingui.c --- xchat-2.8.6/src/fe-gtk/maingui.c 2008-04-01 11:53:41.000000000 +0300 +++ xchat-2.8.6/src/fe-gtk/maingui.c 2008-09-13 20:20:30.000000000 +0300 @@ -55,6 +55,7 @@ #include "../common/plugin.h" #include "../common/modes.h" #include "../common/url.h" +#include "../common/util.h" #include "fe-gtk.h" #include "banlist.h" #include "gtkutil.h" @@ -489,6 +490,7 @@ fe_set_title (session *sess) { char tbuf[512]; + char uchan[CHANLEN]; int type; if (sess->gui->is_tab && sess != current_tab) @@ -510,17 +512,18 @@ sess->server->nick, server_get_network (sess->server, TRUE)); break; case SESS_CHANNEL: + rfc_unsafe_chan (uchan, sess->channel, CHANLEN); /* don't display keys in the titlebar */ if ((!(prefs.gui_tweaks & 16)) && has_key (sess->current_modes)) snprintf (tbuf, sizeof (tbuf), DISPLAY_NAME": %s @ %s / %s", sess->server->nick, server_get_network (sess->server, TRUE), - sess->channel); + uchan); else snprintf (tbuf, sizeof (tbuf), DISPLAY_NAME": %s @ %s / %s (%s)", sess->server->nick, server_get_network (sess->server, TRUE), - sess->channel, sess->current_modes ? sess->current_modes : ""); + uchan, sess->current_modes ? sess->current_modes : ""); if (prefs.gui_tweaks & 1) snprintf (tbuf + strlen (tbuf), 9, " (%d)", sess->total); break; @@ -790,7 +793,9 @@ case SESS_CHANNEL: if (sess->topic) { - text = g_strdup_printf (_("Topic for %s is: %s"), sess->channel, + char uchan[CHANLEN]; + rfc_unsafe_chan (uchan, sess->channel, CHANLEN); + text = g_strdup_printf (_("Topic for %s is: %s"), uchan, sess->topic); add_tip (sess->gui->topic_entry, text); g_free (text); @@ -1632,7 +1637,10 @@ if (sess) { - char *name = g_markup_escape_text (sess->channel[0] ? sess->channel : _(""), -1); + char uchan[CHANLEN]; + char *name; + rfc_unsafe_chan (uchan, sess->channel[0] ? sess->channel : _(""), CHANLEN); + name = g_markup_escape_text (uchan, -1); snprintf (buf, sizeof (buf), "%s", name); g_free (name); @@ -1661,6 +1669,7 @@ mg_detach_tab_cb, ch); mg_create_icon_item (_("_Close"), GTK_STOCK_CLOSE, menu, mg_destroy_tab_cb, ch); + /* FIXME what is this menu? */ if (sess && tabmenu_list) menu_create (menu, tabmenu_list, sess->channel, FALSE); menu_add_plugin_items (menu, "\x4$TAB", sess->channel); @@ -2906,6 +2915,7 @@ } /* compare two tabs (for tab sorting function) */ +/* TODO: Thanks to rfc_unsafe_chan sorting is unnecessarily expensive */ static int mg_tabs_compare (session *a, session *b) @@ -2920,7 +2930,14 @@ if (a->type != SESS_CHANNEL && b->type == SESS_CHANNEL) return 1; - return strcasecmp (a->channel, b->channel); + if (a->type == SESS_CHANNEL) + { + char achan[CHANLEN], bchan[CHANLEN]; + rfc_unsafe_chan (achan, a->channel, CHANLEN); + rfc_unsafe_chan (bchan, b->channel, CHANLEN); + return strcasecmp (achan, bchan); + } else + return strcasecmp (a->channel, b->channel); } static void @@ -3236,16 +3253,16 @@ { if (sess->waitchannel[0]) { + tbuf[0] = '('; + rfc_unsafe_chan (tbuf + 1, sess->waitchannel, CHANLEN); if (prefs.truncchans > 2 && g_utf8_strlen (sess->waitchannel, -1) > prefs.truncchans) { /* truncate long channel names */ - tbuf[0] = '('; - strcpy (tbuf + 1, sess->waitchannel); g_utf8_offset_to_pointer(tbuf, prefs.truncchans)[0] = 0; strcat (tbuf, "..)"); } else { - sprintf (tbuf, "(%s)", sess->waitchannel); + strcat (tbuf, ")"); } } else @@ -3370,7 +3387,11 @@ fe_set_channel (session *sess) { if (sess->res->tab != NULL) - chan_rename (sess->res->tab, sess->channel, prefs.truncchans); + { + char uchan[CHANLEN]; + rfc_unsafe_chan (uchan, sess->channel, CHANLEN); + chan_rename (sess->res->tab, uchan, prefs.truncchans); + } } void