AmendHub

Download:

jcs

/

wallops

/

amendments

/

88

irc: Implement /op, /deop, /voice, and /devoice


jcs made amendment 88 2 months ago
--- irc.c Wed Sep 11 16:25:38 2024 +++ irc.c Wed Sep 11 17:36:11 2024 @@ -45,8 +45,10 @@ void irc_remove_nick_from_channel(struct irc_channel * bool irc_nick_is_in_channel(struct irc_channel *channel, char *nick); void irc_change_user_nick(struct irc_channel *channel, struct irc_user *user, char *nick); -void irc_parse_channel_mode_change(struct irc_channel *channel, char *mode, +bool irc_parse_channel_mode_change(struct irc_channel *channel, char *mode, char *args); +void irc_do_mode_to_users(struct irc_connection *conn, char *channel_name, + char *mode, char *nicks); #define IRC_CAN_SEND(conn) ((conn)->send_pb.ioResult <= 0) @@ -643,13 +645,14 @@ irc_process_server(struct irc_connection *conn) "$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) { - 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); + bool others = irc_parse_channel_mode_change(channel, + msg.arg[1], msg.msg); + if (others) + /* + * 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; @@ -946,9 +949,22 @@ irc_process_server(struct irc_connection *conn) case 475: /* can't join channel */ chatter_printf(conn->chatter, conn, NULL, - "$B***$0 Cannot join $B%s$0$/: %s", + "$B***$0 Can't join $B%s$0$/: %s", msg.arg[1], msg.msg); return true; + case 481: + /* not oper */ + chatter_printf(conn->chatter, conn, NULL, + "$B***$0 You can't do that thing if you ain't got that " + "swing:$/: %s", + msg.msg); + return true; + case 482: + /* not op */ + chatter_printf(conn->chatter, conn, NULL, + "$B***$0 Can't do that on $B%s$0$/: %s", + msg.arg[1], msg.msg); + return true; case 502: /* error */ chatter_printf(conn->chatter, conn, NULL, @@ -1050,6 +1066,22 @@ irc_process_input(struct irc_connection *conn, struct arg0); return; } + if (strcasecmp(arg0, "deop") == 0) { + if (conn == NULL) + goto not_connected; + if (channel_name == NULL) + goto not_in_channel; + irc_do_mode_to_users(conn, channel_name, "-o", str); + return; + } + if (strcasecmp(arg0, "devoice") == 0) { + if (conn == NULL) + goto not_connected; + if (channel_name == NULL) + goto not_in_channel; + irc_do_mode_to_users(conn, channel_name, "-v", str); + return; + } if (strcasecmp(arg0, "disco") == 0 || strcasecmp(arg0, "discon") == 0 || strcasecmp(arg0, "disconnect") == 0) { @@ -1119,6 +1151,14 @@ irc_process_input(struct irc_connection *conn, struct irc_printf(conn, "NICK %s\r\n", str); return; } + if (strcasecmp(arg0, "op") == 0) { + if (conn == NULL) + goto not_connected; + if (channel_name == NULL) + goto not_in_channel; + irc_do_mode_to_users(conn, channel_name, "+o", str); + return; + } if (strcasecmp(arg0, "part") == 0) { if (conn == NULL) goto not_connected; @@ -1165,6 +1205,14 @@ irc_process_input(struct irc_connection *conn, struct (str ? str : "")); return; } + if (strcasecmp(arg0, "voice") == 0) { + if (conn == NULL) + goto not_connected; + if (channel_name == NULL) + goto not_in_channel; + irc_do_mode_to_users(conn, channel_name, "+v", str); + return; + } if (strcasecmp(arg0, "who") == 0) { if (conn == NULL) goto not_connected; @@ -1488,7 +1536,7 @@ irc_change_user_nick(struct irc_channel *channel, stru } } -void +bool irc_parse_channel_mode_change(struct irc_channel *channel, char *mode, char *args) { @@ -1497,6 +1545,7 @@ irc_parse_channel_mode_change(struct irc_channel *chan char *user; short n, j, flags; bool add = false; + bool others = false; len = strlen(mode); @@ -1546,7 +1595,48 @@ irc_parse_channel_mode_change(struct irc_channel *chan break; default: /* some other channel mode */ + others = true; break; + } + } + + return others; +} + +void +irc_do_mode_to_users(struct irc_connection *conn, char *channel_name, + char *mode, char *nicks) +{ +#define MAX_MODES_AT_ONCE 4 + /* assume we can only do 4 at a time */ + char modes[(2 * MAX_MODES_AT_ONCE) + 1]; + char mnicks[((member_size(struct irc_user, nick) + 1) * + MAX_MODES_AT_ONCE) + 1]; + char *nick; + short count; + + /* TODO: support +b by looking up user in nick table for hostmask */ + + modes[0] = '\0'; + mnicks[0] = '\0'; + count = 0; + + while (nicks != NULL) { + strlcat(modes, mode, sizeof(modes)); + + nick = strsep(&nicks, " "); + strlcat(mnicks, nick, sizeof(mnicks)); + count++; + + if (nicks != NULL && count != MAX_MODES_AT_ONCE) + strlcat(mnicks, " ", sizeof(mnicks)); + + if (nicks == NULL || count == 4) { + irc_printf(conn, "MODE %s %s %s\r\n", channel_name, modes, + mnicks); + mnicks[0] = '\0'; + modes[0] = '\0'; + count = 0; } } } \ No newline at end of file