]> PatchyGit - patchyircd.git/commitdiff
add MONITOR and extended-monitor
authorEgor <egor@patchysicp.xyz>
Fri, 27 Oct 2023 20:14:20 +0000 (23:14 +0300)
committerEgor <egor@patchysicp.xyz>
Fri, 27 Oct 2023 20:14:20 +0000 (23:14 +0300)
src/admin.c
src/common.h
src/irc.c
src/irc.h
src/ircfmt.c
src/ircfmt.h
src/net.c

index 568e048..431d699 100644 (file)
@@ -146,6 +146,7 @@ static int client_index(lua_State *L)
        integer_getter(cl, regstate);
        map_getter(cl, channels, MAPTYPE_CHANNEL);
        map_getter(cl, invites, MAPTYPE_CHANNEL);
+       map_getter(cl, monitor, MAPTYPE_STRINGSET);
        integer_getter(cl, cookie);
        integer_getter(cl, signon);
        integer_getter(cl, lastactivity);
index 0b8e1fc..31d6707 100644 (file)
@@ -26,6 +26,7 @@ struct tls;
 #define CAP_EXTENDEDJOIN 4
 #define CAP_AWAYNOTIFY 8
 #define CAP_INVITENOTIFY 16
+#define CAP_EXTENDEDMONITOR 32
 struct client_data {
        SOCKET FD;
        struct tls *cctx;
@@ -50,6 +51,7 @@ struct client_data {
        char   regstate;
        map_t  channels;
        map_t  invites;
+       map_t  monitor;
        int    cookie;
        time_t signon;
        time_t lastactivity;
index 4184026..f790f82 100644 (file)
--- a/src/irc.c
+++ b/src/irc.c
@@ -52,6 +52,21 @@ void sendbuf_list_sans_self_caps(struct client_data *client, map_t *ls, int cook
 void sendbuf_list_sans_self(struct client_data *client, map_t *ls, int cookie) {
        sendbuf_list_sans_self_caps(client, ls, cookie, 0, 0);
 }
+void sendbuf_monitor(const char *nick, int cookie, int positive, int negative)
+{
+       struct client_data *cl;
+       map_foreach(&client_map, 0, &cl)
+               if (map_get(&cl->monitor, nick)) {
+                       if (cookie) {
+                               if (cookie != cl->cookie)
+                                       cl->cookie = cookie;
+                               else
+                                       continue;
+                       }
+                       if (!(~cl->caps & positive) && !(cl->caps & negative))
+                               sendbuf(cl);
+               }
+}
 int get_cookie() {
        static int cookie = 0;
        if (++cookie == 0) {
@@ -63,11 +78,12 @@ int get_cookie() {
        }
        return cookie;
 }
-void sendbuf_visible_caps(struct client_data *client, int positive, int negative) {
+int sendbuf_visible_caps(struct client_data *client, int positive, int negative) {
        int cookie = get_cookie();
        struct channel *chan;
        map_foreach(&client->channels, 0, &chan)
                sendbuf_list_sans_self_caps(client, &chan->members, cookie, positive, negative);
+       return cookie;
 }
 void sendbuf_visible(struct client_data *client) {
        sendbuf_visible_caps(client, 0, 0);
@@ -184,6 +200,7 @@ int processPacket(struct client_data *client, char *source, char *command, int a
                        { "extended-join", CAP_EXTENDEDJOIN },
                        { "away-notify", CAP_AWAYNOTIFY },
                        { "invite-notify", CAP_INVITENOTIFY },
+                       { "extended-monitor", CAP_EXTENDEDMONITOR },
                        { 0, 0 }
                };
 
@@ -1043,7 +1060,77 @@ int processPacket(struct client_data *client, char *source, char *command, int a
                        rpl_unaway(client), sendbuf(client);
                }
                msg_away(client);
-               sendbuf_visible_caps(client, CAP_AWAYNOTIFY, 0);
+               int cookie = sendbuf_visible_caps(client, CAP_AWAYNOTIFY, 0);
+               sendbuf_monitor(client->key, cookie, CAP_AWAYNOTIFY|CAP_EXTENDEDMONITOR, 0);
+       } else if(strcmp(command, "MONITOR") == 0) {
+               if (!is_registered(client))
+                       return err_notregistered(client), sendbuf(client), 0;
+               if (argc == 0)
+                       return err_needmoreparams(client, command), sendbuf(client), 0;
+               if (!args[0][0] || args[0][1])
+                       return err_needmoreparams(client, command), sendbuf(client), 0; /* FIXME: wrong error */
+               switch (args[0][0]) {
+               case '+': {
+                       if (argc < 2)
+                               return err_needmoreparams(client, command), sendbuf(client), 0;
+                       if (strchr(args[1], ' '))
+                               return err_needmoreparams(client, command), sendbuf(client), 0; /* FIXME: wrong error */
+                       stringlower(args[1]);
+                       char *p = args[1];
+                       do {
+                               char *nick = p;
+                               if ((p = strchr(nick, ',')))
+                                       *p++ = '\0';
+                               /* TODO: rpl_monlistfull */
+                               if (map_set(&client->monitor, nick, /* dummy */ nick, 0) == -1)
+                                       abort();
+                               struct client_data *cl = map_get(&client_map, nick);
+                               if (cl)
+                                       rpl_mononline(client, cl), sendbuf(client);
+                               else
+                                       rpl_monoffline(client, nick), sendbuf(client);
+                       } while (p);
+                       break;
+               }
+               case '-': {
+                       if (argc < 2)
+                               return err_needmoreparams(client, command), sendbuf(client), 0;
+                       if (strchr(args[1], ' '))
+                               return err_needmoreparams(client, command), sendbuf(client), 0; /* FIXME: wrong error */
+                       stringlower(args[1]);
+                       char *p = args[1];
+                       do {
+                               char *nick = p;
+                               if ((p = strchr(nick, ',')))
+                                       *p++ = '\0';
+                               map_unset(&client->monitor, nick, 0);
+                       } while (p);
+                       break;
+               }
+               case 'C':
+                       map_free(&client->monitor);
+                       break;
+               case 'L': {
+                       const char *key;
+                       map_foreach(&client->monitor, &key, 0)
+                               rpl_monlist(client, key), sendbuf(client);
+                       rpl_endofmonlist(client), sendbuf(client);
+                       break;
+               }
+               case 'S': {
+                       const char *key;
+                       map_foreach(&client->monitor, &key, 0) {
+                               struct client_data *cl = map_get(&client_map, key);
+                               if (cl)
+                                       rpl_mononline(client, cl), sendbuf(client);
+                               else
+                                       rpl_monoffline(client, key), sendbuf(client);
+                       }
+                       break;
+               }
+               default:
+                       return err_needmoreparams(client, command), sendbuf(client), 0; /* FIXME: wrong error */
+               }
 #ifdef HAS_LUA
        } else if(strcmp(command, "LUA") == 0) {
                if (argc < 1)
@@ -1173,6 +1260,7 @@ void setNick(struct client_data *client, char* nickname) {
                msg_nick(client, nickname);
                sendbuf(client);
                sendbuf_visible(client);
+               rpl_monoffline(0, client->key), sendbuf_monitor(client->key, 0, 0, 0);
                map_unset(&client_map, client->key, NULL);
                struct channel *chan;
                map_foreach(&client->channels, 0, &chan) {
@@ -1206,6 +1294,7 @@ void setNick(struct client_data *client, char* nickname) {
                abort();
        if (map_set(&client_map, client->key, client, 0) == -1)
                abort();
+       rpl_mononline(0, client), sendbuf_monitor(client->key, 0, 0, 0);
 
        return;
 }
index 29bd8c0..93b2cf8 100644 (file)
--- a/src/irc.h
+++ b/src/irc.h
@@ -6,6 +6,7 @@
 #include "util.h"
 
 #define is_registered(cl) ((cl)->regstate == REG_REGISTERED)
+void sendbuf_monitor(const char *nick, int cookie, int positive, int negative);
 int parsePacket(struct client_data *client);
 int processPacket(struct client_data *client, char *source, char *command, int argc, char *args[]);
 void newUser(struct client_data *client);
index 202267e..25a89c7 100644 (file)
@@ -133,7 +133,7 @@ void rpl_myinfo(struct client_data *client) // 004
 }
 void rpl_isupport(struct client_data *client) // 005
 {
-       copy_strf(&databuf, ":%s 005 %s NETWORK=PatchyIRC CASEMAPPING=ascii NICKLEN=%u EXCEPTS=e INVEX=I MAXTARGETS=1 CHANMODES=beIqw,k,l,Pimnst CHANTYPES=#& PREFIX=(ov)@+ STATUSMSG=@+ BOT=B WHOX :are supported by this server\r\n", hostname, client->nick, MAX_NICKLEN-1);
+       copy_strf(&databuf, ":%s 005 %s NETWORK=PatchyIRC CASEMAPPING=ascii NICKLEN=%u EXCEPTS=e INVEX=I MAXTARGETS=1 CHANMODES=beIqw,k,l,Pimnst CHANTYPES=#& PREFIX=(ov)@+ STATUSMSG=@+ BOT=B WHOX MONITOR :are supported by this server\r\n", hostname, client->nick, MAX_NICKLEN-1);
 
 }
 #if 0
@@ -685,6 +685,28 @@ void rpl_endofquietlist(struct client_data *client, struct channel *chan) // 729
 {
        copy_strf(&databuf, ":%s 729 %s %s q :End of channel quiet list\r\n", hostname, client->nick, chan->name);
 }
+void rpl_mononline(struct client_data *client, struct client_data *cl) // 730
+{
+       copy_strf(&databuf, ":%s 730 %s :%s!%s@%s\r\n", hostname, client ? client->nick : "*", cl->nick, cl->username, cl->hostname);
+}
+void rpl_monoffline(struct client_data *client, const char *nick) // 731
+{
+       copy_strf(&databuf, ":%s 731 %s :%s\r\n", hostname, client ? client->nick : "*", nick);
+}
+void rpl_monlist(struct client_data *client, const char *nick) // 732
+{
+       copy_strf(&databuf, ":%s 732 %s :%s\r\n", hostname, client->nick, nick);
+}
+void rpl_endofmonlist(struct client_data *client) // 733
+{
+       copy_strf(&databuf, ":%s 733 %s :End of MONITOR list\r\n", hostname, client->nick);
+}
+#if 0
+void rpl_monlistfull(struct client_data *client, int limit, const char *targets) // 734
+{
+       copy_strf(&databuf, ":%s 734 %s %d %s :Monitor list is full.\r\n", hostname, client->nick, limit, targets);
+}
+#endif
 // 900 RPL_LOGGEDIN
 // 901 RPL_LOGGEDOUT
 // 902 ERR_NICKLOCKED
index f4ab13f..b39a76b 100644 (file)
@@ -138,6 +138,11 @@ void rpl_endofhelp(struct client_data *client); // 706
 // 723 ERR_NOPRIVS
 void rpl_quietlist(struct client_data *client, struct channel *chan, const char *mask); // 728
 void rpl_endofquietlist(struct client_data *client, struct channel *chan); // 729
+void rpl_mononline(struct client_data *client, struct client_data *cl); // 730
+void rpl_monoffline(struct client_data *client, const char *nick); // 731
+void rpl_monlist(struct client_data *client, const char *nick); // 732
+void rpl_endofmonlist(struct client_data *client); // 733
+void rpl_monlistfull(struct client_data *client, int limit, const char *targets); // 734
 // 900 RPL_LOGGEDIN
 // 901 RPL_LOGGEDOUT
 // 902 ERR_NICKLOCKED
index 3e51cf4..02aa036 100644 (file)
--- a/src/net.c
+++ b/src/net.c
@@ -69,12 +69,14 @@ void killConnection(struct client_data *cl, int byChoice)
        /* Remove from client_map and get rid of the pending invites */
        if (cl->key) {
                map_unset(&client_map, cl->key, NULL);
+               rpl_monoffline(0, cl->key), sendbuf_monitor(cl->key, 0, 0, 0);
                struct channel *chan;
                map_foreach(&cl->invites, 0, &chan)
                        map_unset(&chan->invitees, cl->key, NULL);
        }
        map_free(&cl->channels);
        map_free(&cl->invites);
+       map_free(&cl->monitor);
        killConnectionPart2(cl);
 }
 void killConnectionPart2(struct client_data *cl)