AmendHub

Download:

jcs

/

wallops

/

amendments

/

81

irc: Try to detect channel name at start of commands, various fixes

If the user types "/topic #channel blah", detect "#channel" and use
that as the channel name rather than the current tab channel.
 
Also fix up some things around channel mode handling, especially when
using +k since there's a space in it between the mode and key.

jcs made amendment 81 2 months ago
--- irc.c Tue Sep 10 22:53:39 2024 +++ irc.c Wed Sep 11 09:58:59 2024 @@ -557,7 +557,7 @@ irc_process_server(struct irc_connection *conn) } if (!(settings.ignores & IGNORE_QUITS)) chatter_printf(conn->chatter, conn, msg.arg[0], - "$B*** %s$0 was kicked from $B%s$0 by $B%s%0:$/ %s", + "$B*** %s$0 was kicked from $B%s$0 by $B%s$0:$/ %s", msg.arg[0], msg.arg[1], user->nick, msg.msg); return true; } @@ -605,13 +605,24 @@ irc_process_server(struct irc_connection *conn) strlcat(msg.msg, " ", sizeof(msg.msg)); strlcat(msg.msg, msg.arg[5], sizeof(msg.msg)); } + + if (channel && channel->mode[0] == '\0') + /* probably initial mode on join, wait for 324 */ + return true; + chatter_printf(conn->chatter, conn, channel ? channel->name : NULL, - "$B***$0 Mode change ($B%s %s$0) on $B%s$0 by $B%s%0", + "$B***$0 Mode change ($B%s %s$0) on $B%s$0 by $B%s$0", msg.arg[1], msg.msg, msg.arg[0], user->nick); - if (channel) + if (channel) { irc_parse_channel_mode_change(channel, msg.arg[1], msg.msg); + /* + * To simplify parsing mode changes like "+ik blah", + * just ask for the full mode now to get a 324 + */ + irc_printf(conn, "MODE %s\r\n", channel->name); + } } return true; } @@ -691,6 +702,16 @@ irc_process_server(struct irc_connection *conn) } return true; } + if (strcmp(msg.cmd, "TOPIC") == 0) { + user = irc_parse_user(msg.source); + chatter_printf(conn->chatter, conn, msg.arg[0], + "$B***$0 Topic for $B%s$0 changed by $B%s$0:$/ %s", + msg.arg[0], user->nick, msg.msg); + if ((channel = irc_find_channel(conn, msg.arg[0]))) + strlcpy(channel->topic, msg.msg, sizeof(channel->topic)); + return true; + } + goto unknown; } @@ -767,12 +788,27 @@ irc_process_server(struct irc_connection *conn) msg.msg); return true; case 324: - /* channel mode */ + /* channel mode, concatenate args */ + msg.msg[0] = '\0'; + if (msg.arg[2][0] != '\0') + strlcat(msg.msg, msg.arg[2], sizeof(msg.msg)); + if (msg.arg[3][0] != '\0') { + strlcat(msg.msg, " ", sizeof(msg.msg)); + strlcat(msg.msg, msg.arg[3], sizeof(msg.msg)); + } + if (msg.arg[4][0] != '\0') { + strlcat(msg.msg, " ", sizeof(msg.msg)); + strlcat(msg.msg, msg.arg[4], sizeof(msg.msg)); + } + if (msg.arg[5][0] != '\0') { + strlcat(msg.msg, " ", sizeof(msg.msg)); + strlcat(msg.msg, msg.arg[5], sizeof(msg.msg)); + } chatter_printf(conn->chatter, conn, msg.arg[1], "$B***$0 Mode for $B%s$0:$/ %s", - msg.arg[1], msg.arg[2]); + msg.arg[1], msg.msg); if ((channel = irc_find_channel(conn, msg.arg[1]))) { - strlcpy(channel->mode, msg.arg[2], sizeof(channel->topic)); + strlcpy(channel->mode, msg.msg, sizeof(channel->mode)); if (channel->chatter) channel->chatter->need_tab_bar_redraw = true; } @@ -789,6 +825,14 @@ irc_process_server(struct irc_connection *conn) "$B*** |$0 Account:$/ %s %s", msg.msg, msg.arg[2]); return true; + case 331: + /* no TOPIC */ + chatter_printf(conn->chatter, conn, msg.arg[1], + "$B***$0 No topic is set for $B%s$0", + msg.arg[1]); + if ((channel = irc_find_channel(conn, msg.arg[1]))) + channel->topic[0] = '\0'; + return true; case 332: /* TOPIC */ chatter_printf(conn->chatter, conn, msg.arg[1], @@ -917,7 +961,7 @@ void irc_process_input(struct irc_connection *conn, struct irc_channel *channel, char *query_nick, char *str) { - char *arg0, *arg1; + char *arg0, *arg1, *channel_name; size_t n; if (conn == NULL || conn->state < IRC_STATE_CONNECTED) @@ -941,9 +985,28 @@ irc_process_input(struct irc_connection *conn, struct /* skip / */ str++; - - arg0 = strsep(&str, " "); + arg0 = strsep(&str, " "); + + /* special case: send as-is */ + if (strcasecmp(arg0, "quote") == 0 || strcasecmp(arg0, "raw") == 0) { + if (conn == NULL) + goto not_connected; + if (str == NULL) + goto not_enough_params; + irc_printf(conn, "%s\r\n", str); + return; + } + + if (str && (str[0] == '#' || str[0] == '&')) + /* channel specified */ + channel_name = strsep(&str, " "); + else if (channel) + /* use channel of current tab */ + channel_name = channel->name; + else + channel_name = NULL; + if (strcasecmp(arg0, "clear") == 0) { chatter_clear_messages(conn->chatter, conn->chatter->current_tab); return; @@ -969,17 +1032,18 @@ irc_process_input(struct irc_connection *conn, struct if (strcasecmp(arg0, "join") == 0) { if (conn == NULL) goto not_connected; - if (str == NULL) + if (channel_name == NULL) goto not_enough_params; /* * If we're already in this channel, we won't get any response * from the server to switch channels. */ - if ((channel = irc_find_channel(conn, str))) + if ((channel = irc_find_channel(conn, channel_name))) /* this won't actually create, it'll just switch for us */ - irc_create_channel(conn, str); + irc_create_channel(conn, channel_name); else - irc_printf(conn, "JOIN %s\r\n", str); + irc_printf(conn, "JOIN %s%s%s\r\n", channel_name, + (str ? " " : ""), (str ? str : "")); return; } if (strcasecmp(arg0, "me") == 0) { @@ -1000,13 +1064,10 @@ irc_process_input(struct irc_connection *conn, struct if (strcasecmp(arg0, "mode") == 0) { if (conn == NULL) goto not_connected; - if (channel) { - if (str) - irc_printf(conn, "MODE %s %s\r\n", channel->name, str); - else - irc_printf(conn, "MODE %s\r\n", channel->name); - } else + if (channel_name == NULL) goto not_in_channel; + irc_printf(conn, "MODE %s%s%s\r\n", channel_name, (str ? " " : ""), + (str ? str : "")); return; } if (strcasecmp(arg0, "msg") == 0) { @@ -1032,12 +1093,10 @@ irc_process_input(struct irc_connection *conn, struct if (strcasecmp(arg0, "part") == 0) { if (conn == NULL) goto not_connected; - if (str == NULL && channel) - irc_printf(conn, "PART %s\r\n", channel->name); - else if (str) - irc_printf(conn, "PART %s\r\n", str); - else + if (channel_name == NULL) goto not_in_channel; + irc_printf(conn, "PART %s%s%s\r\n", channel_name, + (str ? " :" : ""), (str ? str : "")); return; } if (strcasecmp(arg0, "query") == 0) { @@ -1059,43 +1118,30 @@ irc_process_input(struct irc_connection *conn, struct ExitToShell(); return; } - if (strcasecmp(arg0, "quote") == 0) { - if (conn == NULL) - goto not_connected; - if (str == NULL) - goto not_enough_params; - irc_printf(conn, "%s\r\n", str); - return; - } if (strcasecmp(arg0, "topic") == 0) { if (conn == NULL) goto not_connected; - if (str && channel) - irc_printf(conn, "TOPIC %s: %s\r\n", channel->name, str); - else if (channel) - irc_printf(conn, "TOPIC %s\r\n", channel->name); - else + if (channel_name == NULL) goto not_in_channel; + if (str) + irc_printf(conn, "TOPIC %s :%s\r\n", channel_name, str); + else + irc_printf(conn, "TOPIC %s\r\n", channel_name); return; } if (strcasecmp(arg0, "umode") == 0) { if (conn == NULL) goto not_connected; - if (str) - irc_printf(conn, "MODE %s %s\r\n", conn->nick, str); - else - irc_printf(conn, "MODE %s\r\n", conn->nick); + irc_printf(conn, "MODE %s%s%s\r\n", conn->nick, (str ? " :" : ""), + (str ? str : "")); return; } if (strcasecmp(arg0, "who") == 0) { if (conn == NULL) goto not_connected; - if (str == NULL && channel) - irc_printf(conn, "WHO %s\r\n", channel->name); - else if (str) - irc_printf(conn, "WHO %s\r\n", str); - else + if (channel_name == NULL) goto not_in_channel; + irc_printf(conn, "WHO %s\r\n", channel_name); return; } if (strcasecmp(arg0, "whois") == 0) { @@ -1177,13 +1223,18 @@ irc_dealloc_channel(struct irc_channel *channel) struct chatter *chatter = channel->chatter; struct chatter_tab *tab; - if ((tab = chatter_find_tab(chatter, conn, channel->name))) + if ((tab = chatter_find_tab(chatter, conn, channel->name))) { + /* clear channel first so close_tab doesn't try to part */ + tab->channel = NULL; chatter_close_tab(chatter, tab); + } if (channel->nicks) xfree(&channel->nicks); SLIST_REMOVE(&conn->channels_list, channel, irc_channel, list); + + xfree(&channel); } void