]> PatchyGit - patchyircd.git/commitdiff
add +beIq modes
authorEgor <egor@patchysicp.xyz>
Wed, 11 May 2022 17:05:35 +0000 (20:05 +0300)
committerEgor <egor@patchysicp.xyz>
Wed, 11 May 2022 17:05:35 +0000 (20:05 +0300)
common.h
glob.c [new file with mode: 0644]
irc.c
irc.h
ircfmt.c
ircfmt.h
net.c

index 0e4106b..46fca0b 100644 (file)
--- a/common.h
+++ b/common.h
@@ -28,6 +28,7 @@ struct client_data {
        char   *username;
        char   *realname;
        char   *hostname;
+       char   *nuh; // case-mapped nick!user@host
        char   *away;
        char   *nick_reg;
        char   *pass_reg;
@@ -54,9 +55,10 @@ struct channel {
        struct trie_node *v;
        int member_count;
        char dmode;
-       //char *ban_mask[20];
-       //char *exc_mask[20];
-       //char *iex_mask[20];
+       struct trie_node *listb;
+       struct trie_node *liste;
+       struct trie_node *listI;
+       struct trie_node *listq;
        char *chankey;
        int member_limit;
 };
diff --git a/glob.c b/glob.c
new file mode 100644 (file)
index 0000000..69a0248
--- /dev/null
+++ b/glob.c
@@ -0,0 +1,45 @@
+// https://research.swtch.com/glob
+int irc_glob(const char *key, const char *mask)
+{
+       const char *key2 = 0, *mask2 = 0;
+       while (*key || *mask) {
+               if (*mask) {
+                       switch (*mask) {
+                       case '\\':
+                               if (*key == *mask) {
+                                       key++, mask++;
+                                       if (!*mask)
+                                               continue;
+                                       if (*key == *mask) {
+                                               key++, mask++;
+                                               continue;
+                                       }
+                               }
+                               break;
+                       default:
+                               if (*key == *mask) {
+                                       key++, mask++;
+                                       continue;
+                               }
+                               break;
+                       case '?':
+                               if (*key) {
+                                       key++, mask++;
+                                       continue;
+                               }
+                               break;
+                       case '*':
+                               key2 = key2 + 1;
+                               mask2 = mask++;
+                               continue;
+                       }
+               }
+               if (key2 && *key2) {
+                       key = key2;
+                       mask = mask2;
+                       continue;
+               }
+               return 0;
+       }
+       return 1;
+}
diff --git a/irc.c b/irc.c
index f079b49..9a5c5eb 100644 (file)
--- a/irc.c
+++ b/irc.c
@@ -92,6 +92,18 @@ const char *format_umodes(struct client_data *cl) {
        *p++ = '\0';
        return umodes;
 }
+int match_list(struct client_data *cl, struct trie_node **list)
+{
+       struct trie_find *f = NULL;
+       if (trie_findfirst(&f, list) == 1)
+               do {
+                       if (irc_glob(cl->nuh, f->key)) {
+                               free(f);
+                               return 1;
+                       }
+               } while (trie_findnext(&f) == 1);
+       return 0;
+}
 int parsePacket(struct client_data *client) {
        char *source = NULL;
        char *command = NULL;
@@ -362,7 +374,13 @@ int processPacket(struct client_data *client, char *source, char *command, int a
                        struct channel *chan = findChannel(args[0]+is_modmsg);
                        if (!chan)
                                return err_nosuchchannel(client, args[0]), sendbuf(client), 0;
-                       // TODO: check bans
+                       if (match_list(client, &chan->listq))
+                               return err_cannotsendtochan(client, chan->name), sendbuf(client), 0;
+                       if (match_list(client, &chan->listb) && !match_list(client, &chan->liste))
+                               return err_cannotsendtochan(client, chan->name), sendbuf(client), 0;
+                       // TODO: actual invites
+                       if (chan->dmode & DMODE_INVITEONLY && !match_list(client, &chan->listI))
+                               return err_cannotsendtochan(client, chan->name), sendbuf(client), 0;
                        if (chan->dmode & DMODE_NOEXTERNAL && !trie_get(&chan->members, client->key))
                                return err_cannotsendtochan(client, chan->name), sendbuf(client), 0;
                        if (chan->dmode & DMODE_MODERATED && !trie_get(&chan->v, client->key) && !trie_get(&chan->o, client->key))
@@ -525,18 +543,44 @@ int processPacket(struct client_data *client, char *source, char *command, int a
                                if (!trie_get(&chan->o, client->key))
                                        return 0; // TODO: error
                                if (argc == 2) { // Type A channel modes
+                                       struct trie_find *f = NULL;
                                        if (!strcmp(args[1], "+b")) {
-                                               copy_strf(&databuf, ":%s 368 %s %s :End of channel ban list\n", hostname, client->nick, args[1]);
+                                               if (trie_findfirst(&f, &chan->listb) == 1)
+                                                       do {
+                                                               copy_strf(&databuf, ":%s 367 %s %s %s\n", hostname, client->nick, chan->name, f->key);
+                                                               sendbuf(client);
+                                                       } while(trie_findnext(&f) == 1);
+                                               copy_strf(&databuf, ":%s 368 %s %s :End of channel ban list\n", hostname, client->nick, chan->name);
                                                sendbuf(client);
                                                return 0;
                                        }
                                        if (!strcmp(args[1], "+e")) {
-                                               copy_strf(&databuf, ":%s 349 %s %s :End of channel exception list\n", hostname, client->nick, args[1]);
+                                               if (trie_findfirst(&f, &chan->liste) == 1)
+                                                       do {
+                                                               copy_strf(&databuf, ":%s 348 %s %s %s\n", hostname, client->nick, chan->name, f->key);
+                                                               sendbuf(client);
+                                                       } while(trie_findnext(&f) == 1);
+                                               copy_strf(&databuf, ":%s 349 %s %s :End of channel exception list\n", hostname, client->nick, chan->name);
                                                sendbuf(client);
                                                return 0;
                                        }
                                        if (!strcmp(args[1], "+I")) {
-                                               copy_strf(&databuf, ":%s 347 %s %s :End of Channel Invite Exception List\n", hostname, client->nick, args[1]);
+                                               if (trie_findfirst(&f, &chan->listI) == 1)
+                                                       do {
+                                                               copy_strf(&databuf, ":%s 346 %s %s %s\n", hostname, client->nick, chan->name, f->key);
+                                                               sendbuf(client);
+                                                       } while(trie_findnext(&f) == 1);
+                                               copy_strf(&databuf, ":%s 347 %s %s :End of Channel Invite Exception List\n", hostname, client->nick, chan->name);
+                                               sendbuf(client);
+                                               return 0;
+                                       }
+                                       if (!strcmp(args[1], "+q")) {
+                                               if (trie_findfirst(&f, &chan->listq) == 1)
+                                                       do {
+                                                               copy_strf(&databuf, ":%s 728 %s %s q %s\n", hostname, client->nick, chan->name, f->key);
+                                                               sendbuf(client);
+                                                       } while(trie_findnext(&f) == 1);
+                                               copy_strf(&databuf, ":%s 729 %s %s q :End of channel quiet list\n", hostname, client->nick, chan->name);
                                                sendbuf(client);
                                                return 0;
                                        }
@@ -548,6 +592,7 @@ int processPacket(struct client_data *client, char *source, char *command, int a
                                        case '-': is_plus = 0; break;
                                        default: goto unknown;
                                }
+                               struct trie_node **list;
                                char **argp = &args[2];
                                while (*p) {
                                        switch (*p) {
@@ -639,11 +684,35 @@ int processPacket(struct client_data *client, char *source, char *command, int a
                                                chanlog(), sendbuf_chan(chan);
                                                break;
                                        case 'b':
+                                               list = &chan->listb;
+                                               goto set_list;
                                        case 'e':
+                                               list = &chan->liste;
+                                               goto set_list;
                                        case 'I':
+                                               list = &chan->listI;
+                                               goto set_list;
+                                       case 'q':
+                                               list = &chan->listq;
+                                               goto set_list;
+                                       set_list: {
+                                               if(!*argp)
+                                                       break;
+                                               char *mask = *argp++;
+                                               if (strchr(mask, ' '))
+                                                       break; // TODO: error msg
+                                               stringlower(mask);
+                                               trie_set(list, mask, is_plus ? mask /* dummy */ : NULL, NULL);
+                                               char which[2] = {*p, 0};
+                                               copy_strf(&databuf, ":%s!%s@%s MODE %s %s%s %s\r\n",
+                                                               client->nick, client->username, client->hostname,
+                                                               chan->name, is_plus?"+":"-", which, mask);
+                                               // TODO: limit to ops
+                                               chanlog(), sendbuf_chan(chan);
                                                break;
+                                       }
                                        case 'v':
-                                       case 'o':
+                                       case 'o': {
                                                if(!*argp)
                                                        break;
                                                const char *nick = *argp++;
@@ -663,6 +732,7 @@ int processPacket(struct client_data *client, char *source, char *command, int a
                                                                chan->name, is_plus?"+":"-", which, cl->nick);
                                                sendbuf_chan(chan);
                                                break;
+                                       }
                                        default:
                                                goto unknown;
                                        }
@@ -938,6 +1008,11 @@ void setNick(struct client_data *client, char* nickname) {
        client->nick = mystrdup(nickname);
        if (!client->nick)
                abort();
+       client->nuh = malloc(strlen(client->nick) + strlen(client->username) + strlen(client->hostname) + 3);
+       if (!client->nuh)
+               abort();
+       sprintf(client->nuh, "%s!%s@%s", client->nick, client->username, client->hostname);
+       stringlower(client->nuh);
        client->key = mystrdup(key);
        if (!client->key)
                abort();
@@ -1010,10 +1085,11 @@ void channel_join(struct client_data *client, const char *channel, const char *c
                                return; // error 475
                        if (chan->member_limit != -1 && chan->member_count >= chan->member_limit)
                                return; // error 471
-                       // TODO: check ban
-                       // TODO: check ban exemption
-                       // TODO: check invite
-                       // TODO: check invite exemption
+                       if (match_list(client, &chan->listb) && !match_list(client, &chan->liste))
+                               return; // error 474
+                       // TODO: actual invites
+                       if (chan->dmode & DMODE_INVITEONLY && !match_list(client, &chan->listI))
+                               return; // error 474
                }
        }
        if (trie_set(&chan->members, client->key, client, NULL) == -1)
@@ -1053,6 +1129,10 @@ void channel_part(struct client_data *client, struct channel *chan, const char *
                trie_free(&chan->members);
                trie_free(&chan->o);
                trie_free(&chan->v);
+               trie_free(&chan->listb);
+               trie_free(&chan->liste);
+               trie_free(&chan->listI);
+               trie_free(&chan->listq);
                free(chan->chankey);
                free(chan);
        }
diff --git a/irc.h b/irc.h
index f9100b9..d75225f 100644 (file)
--- a/irc.h
+++ b/irc.h
@@ -19,4 +19,6 @@ void channel_join(struct client_data *client, const char *channel, const char *c
 void channel_part(struct client_data *client, struct channel *chan, const char *reason);
 extern struct dynarr databuf;
 
+// glob.c
+int irc_glob(const char *key, const char *mask);
 #endif
index ebf4a0a..6d6148f 100644 (file)
--- a/ircfmt.c
+++ b/ircfmt.c
@@ -100,11 +100,11 @@ void rpl_created(struct client_data *client) // 003
 }
 void rpl_myinfo(struct client_data *client) // 004
 {
-       copy_strf(&databuf, ":%s 004 %s PatchyIRCD 0.0.1 iworZ beIklPimnst\n", hostname, client->nick);
+       copy_strf(&databuf, ":%s 004 %s PatchyIRCD 0.0.1 iworZ beIqklPimnst\n", hostname, client->nick);
 }
 void rpl_isupport(struct client_data *client) // 005
 {
-       copy_strf(&databuf, ":%s 005 %s CASEMAPPING=ascii NICKLEN=%u EXCEPTS=e INVEX=I MAXTARGETS=1 CHANMODES=beI,k,l,Pimnst CHANTYPES=#& PREFIX=(ov)@+ STATUSMSG=@+ :are supported by this server\n", hostname, client->nick, MAX_NICKLEN-1);
+       copy_strf(&databuf, ":%s 005 %s CASEMAPPING=ascii NICKLEN=%u EXCEPTS=e INVEX=I MAXTARGETS=1 CHANMODES=beIq,k,l,Pimnst CHANTYPES=#& PREFIX=(ov)@+ STATUSMSG=@+ :are supported by this server\n", hostname, client->nick, MAX_NICKLEN-1);
 
 }
 #if 0
@@ -392,6 +392,8 @@ void err_notregistered(struct client_data *client) // 451
 // 705 RPL_HELPTXT
 // 706 RPL_ENDOFHELP
 // 723 ERR_NOPRIVS
+// 728 RPL_QUIETLIST
+// 729 RPL_ENDOFQUIETLIST
 // 900 RPL_LOGGEDIN
 // 901 RPL_LOGGEDOUT
 // 902 ERR_NICKLOCKED
index cb68b00..af2ee03 100644 (file)
--- a/ircfmt.h
+++ b/ircfmt.h
@@ -129,6 +129,8 @@ void err_notregistered(struct client_data *client); // 451
 // 705 RPL_HELPTXT
 // 706 RPL_ENDOFHELP
 // 723 ERR_NOPRIVS
+// 728 RPL_QUIETLIST
+// 729 RPL_ENDOFQUIETLIST
 // 900 RPL_LOGGEDIN
 // 901 RPL_LOGGEDOUT
 // 902 ERR_NICKLOCKED
diff --git a/net.c b/net.c
index d027f88..a534f3e 100644 (file)
--- a/net.c
+++ b/net.c
@@ -59,6 +59,7 @@ void killConnection(struct client_data *cl, bool byChoice) {
        free(cl->username);
        free(cl->realname);
        free(cl->hostname);
+       free(cl->nuh);
        free(cl->away);
        free(cl->nick_reg);
        if (cl->pass_reg)