diff --git a/catgirl.1 b/catgirl.1 index fd8d40a..b1b72de 100644 --- a/catgirl.1 +++ b/catgirl.1 @@ -1,4 +1,4 @@ -.Dd February 19, 2020 +.Dd February 23, 2020 .Dt CATGIRL 1 .Os . @@ -242,16 +242,12 @@ can be typed .Bl -tag -width Ds .It Ic /away Op Ar message Set or clear your away status. -.It Ic /ban Op Ar mask ... -List or ban masks from the channel. .It Ic /cs Ar command Send a command to ChanServ. .It Ic /invite Ar nick Invite a user to the channel. .It Ic /join Ar channel Join a channel. -.It Ic /kick Ar nick Op Ar message -Kick a user from the channel. .It Ic /list Op Ar channel List channels. .It Ic /me Op Ar action @@ -276,8 +272,6 @@ Quit IRC. Send a raw IRC command. .It Ic /topic Op Ar topic Show or set the topic of the channel. -.It Ic /unban Ar mask ... -Unban masks from the channel. .It Ic /whois Ar nick Query information about a user. .El @@ -326,6 +320,30 @@ Switch to window by name. Switch to window by number. .El . +.Ss Operator Commands +.Bl -tag -width Ds +.It Ic /ban Op Ar mask ... +List or ban masks from the channel. +.It Ic /except Op Ar mask ... +List or add masks to the channel ban exception list. +.It Ic /invex Op Ar mask ... +List or add masks to the channel invite list. +.It Ic /kick Ar nick Op Ar message +Kick a user from the channel. +.It Ic /mode Oo Ar modes Oc Op Ar param ... +Show or set channel modes. +In the +.Sy +window, +show or set user modes. +.It Ic /unban Ar mask ... +Unban masks from the channel. +.It Ic /unexcept Ar mask ... +Remove masks from the channel ban exception list. +.It Ic /uninvex Ar mask ... +Remove masks from the channel invite list. +.El +. .Sh KEY BINDINGS The .Nm diff --git a/chat.h b/chat.h index e42cf7b..5b4e14c 100644 --- a/chat.h +++ b/chat.h @@ -176,6 +176,8 @@ static inline void utilPush(struct Util *util, const char *arg) { extern struct Replies { uint away; uint ban; + uint excepts; + uint invex; uint join; uint list; uint names; diff --git a/command.c b/command.c index 1d19a91..c2ebab7 100644 --- a/command.c +++ b/command.c @@ -143,14 +143,34 @@ static void commandKick(uint id, char *params) { } } +static void commandMode(uint id, char *params) { + if (id == Network) { + if (params) { + ircFormat("MODE %s %s\r\n", self.nick, params); + } else { + ircFormat("MODE %s\r\n", self.nick); + } + } else { + if (params) { + ircFormat("MODE %s %s\r\n", idNames[id], params); + } else { + ircFormat("MODE %s\r\n", idNames[id]); + } + } +} + +static void channelListMode(uint id, char pm, char l, char *params) { + int count = 1; + for (char *ch = params; *ch; ++ch) { + if (*ch == ' ') count++; + } + char modes[ParamCap - 2] = { l, l, l, l, l, l, l, l, l, l, l, l, l }; + ircFormat("MODE %s %c%.*s %s\r\n", idNames[id], pm, count, modes, params); +} + static void commandBan(uint id, char *params) { if (params) { - int count = 1; - for (char *ch = params; *ch; ++ch) { - if (*ch == ' ') count++; - } - char b[ParamCap - 2] = "bbbbbbbbbbbbb"; - ircFormat("MODE %s +%.*s %s\r\n", idNames[id], count, b, params); + channelListMode(id, '+', 'b', params); } else { ircFormat("MODE %s b\r\n", idNames[id]); replies.ban++; @@ -159,12 +179,35 @@ static void commandBan(uint id, char *params) { static void commandUnban(uint id, char *params) { if (!params) return; - int count = 1; - for (char *ch = params; *ch; ++ch) { - if (*ch == ' ') count++; + channelListMode(id, '-', 'b', params); +} + +static void commandExcept(uint id, char *params) { + if (params) { + channelListMode(id, '+', network.excepts, params); + } else { + ircFormat("MODE %s %c\r\n", idNames[id], network.excepts); + replies.excepts++; } - char b[ParamCap - 2] = "bbbbbbbbbbbbb"; - ircFormat("MODE %s -%.*s %s\r\n", idNames[id], count, b, params); +} + +static void commandUnexcept(uint id, char *params) { + if (!params) return; + channelListMode(id, '-', network.excepts, params); +} + +static void commandInvex(uint id, char *params) { + if (params) { + channelListMode(id, '+', network.invex, params); + } else { + ircFormat("MODE %s %c\r\n", idNames[id], network.invex); + replies.invex++; + } +} + +static void commandUninvex(uint id, char *params) { + if (!params) return; + channelListMode(id, '-', network.invex, params); } static void commandList(uint id, char *params) { @@ -293,13 +336,16 @@ static const struct Handler { { "/copy", .fn = commandCopy, .restricted = true }, { "/cs", .fn = commandCS }, { "/debug", .fn = commandDebug, .restricted = true }, + { "/except", .fn = commandExcept }, { "/exec", .fn = commandExec, .restricted = true }, { "/help", .fn = commandHelp }, + { "/invex", .fn = commandInvex }, { "/invite", .fn = commandInvite }, { "/join", .fn = commandJoin, .restricted = true }, { "/kick", .fn = commandKick }, { "/list", .fn = commandList }, { "/me", .fn = commandMe }, + { "/mode", .fn = commandMode }, { "/move", .fn = commandMove }, { "/msg", .fn = commandMsg, .restricted = true }, { "/names", .fn = commandNames }, @@ -313,6 +359,8 @@ static const struct Handler { { "/quote", .fn = commandQuote, .restricted = true }, { "/topic", .fn = commandTopic }, { "/unban", .fn = commandUnban }, + { "/unexcept", .fn = commandUnexcept }, + { "/uninvex", .fn = commandUninvex }, { "/whois", .fn = commandWhois }, { "/window", .fn = commandWindow }, }; diff --git a/handle.c b/handle.c index 2dc4654..f1fc75d 100644 --- a/handle.c +++ b/handle.c @@ -606,6 +606,50 @@ static void handleReplyEndOfBanList(struct Message *msg) { if (replies.ban) replies.ban--; } +static void onList(const char *list, struct Message *msg) { + uint id = idFor(msg->params[1]); + if (msg->params[3] && msg->params[4]) { + char since[sizeof("0000-00-00 00:00:00")]; + time_t time = strtol(msg->params[4], NULL, 10); + strftime(since, sizeof(since), "%F %T", localtime(&time)); + uiFormat( + id, Cold, tagTime(msg), + "On the \3%02d%s\3 %s list since %s by \3%02d%s\3: %s", + hash(msg->params[1]), msg->params[1], list, + since, completeColor(id, msg->params[3]), msg->params[3], + msg->params[2] + ); + } else { + uiFormat( + id, Cold, tagTime(msg), + "On the \3%02d%s\3 %s list: %s", + hash(msg->params[1]), msg->params[1], list, msg->params[2] + ); + } +} + +static void handleReplyExceptList(struct Message *msg) { + require(msg, false, 3); + if (!replies.excepts) return; + onList("except", msg); +} + +static void handleReplyEndOfExceptList(struct Message *msg) { + (void)msg; + if (replies.excepts) replies.excepts--; +} + +static void handleReplyInviteList(struct Message *msg) { + require(msg, false, 3); + if (!replies.invex) return; + onList("invite", msg); +} + +static void handleReplyEndOfInviteList(struct Message *msg) { + (void)msg; + if (replies.invex) replies.invex--; +} + static void handleReplyList(struct Message *msg) { require(msg, false, 4); if (!replies.list) return; @@ -881,6 +925,10 @@ static const struct Handler { { "331", handleReplyNoTopic }, { "332", handleReplyTopic }, { "341", handleReplyInviting }, + { "346", handleReplyInviteList }, + { "347", handleReplyEndOfInviteList }, + { "348", handleReplyExceptList }, + { "349", handleReplyEndOfExceptList }, { "353", handleReplyNames }, { "366", handleReplyEndOfNames }, { "367", handleReplyBanList },