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