]> jfr.im git - solanum.git/blobdiff - extensions/filter.c
Merge pull request #302 from edk0/sasl-usercloak
[solanum.git] / extensions / filter.c
index 1268f45c61aac1f62c070ca136b05d1bb48f0824..36c3e28831b3132fb1fcbeab86a9e2f1afec946a 100644 (file)
 #include "stdinc.h"
 #include "channel.h"
 #include "client.h"
+#include "chmode.h"
 #include "match.h"
 #include "ircd.h"
 #include "numeric.h"
 #include "send.h"
-#include "s_serv.h"
 #include "s_newconf.h"
+#include "s_serv.h"
+#include "s_user.h"
 #include "msg.h"
 #include "parse.h"
 #include "modules.h"
 #define FILTER_USER     0
 #define FILTER_HOST     0
 
+#define FILTER_EXIT_MSG "Connection closed"
+
+static const char filter_desc[] = "Filter messages using a precompiled Hyperscan database";
+
 static void filter_msg_user(void *data);
 static void filter_msg_channel(void *data);
 static void on_client_exit(void *data);
@@ -79,6 +85,8 @@ enum filter_state {
 static enum filter_state state = FILTER_EMPTY;
 static char check_str[21] = "";
 
+static unsigned filter_chmode, filter_umode;
+
 mapi_hfn_list_av1 filter_hfnlist[] = {
        { "privmsg_user", (hookfn) filter_msg_user },
        { "privmsg_channel", (hookfn) filter_msg_channel },
@@ -92,9 +100,24 @@ struct Message setfilter_msgtab = {
        {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_setfilter, 2}, {mo_setfilter, 2}}
 };
 
+static int
+modinit(void)
+{
+       filter_umode = user_modes['u'] = find_umode_slot();
+       construct_umodebuf();
+       filter_chmode = cflag_add('u', chm_simple);
+       return 0;
+}
+
 static void
 moddeinit(void)
 {
+       if (filter_umode) {
+               user_modes['u'] = 0;
+               construct_umodebuf();
+       }
+       if (filter_chmode)
+               cflag_orphan('u');
        if (filter_scratch)
                hs_free_scratch(filter_scratch);
        if (filter_db)
@@ -106,7 +129,7 @@ moddeinit(void)
 
 mapi_clist_av1 filter_clist[] = { &setfilter_msgtab, NULL };
 
-DECLARE_MODULE_AV1(filter, NULL, moddeinit, filter_clist, NULL, filter_hfnlist, "0.3");
+DECLARE_MODULE_AV2(filter, modinit, moddeinit, filter_clist, NULL, filter_hfnlist, NULL, "0.4", filter_desc);
 
 static int
 setfilter(const char *check, const char *data, const char **error)
@@ -142,6 +165,28 @@ setfilter(const char *check, const char *data, const char **error)
                return 0;
        }
 
+       if (!strcasecmp(data, "drop")) {
+               if (!filter_db) {
+                       if (error) *error = "no database to drop";
+                       return -1;
+               }
+               hs_free_database(filter_db);
+               filter_db = 0;
+               return 0;
+       }
+
+       if (!strcasecmp(data, "abort")) {
+               if (state != FILTER_FILLING) {
+                       if (error) *error = "not filling";
+                       return -1;
+               }
+               state = filter_db ? FILTER_LOADED : FILTER_EMPTY;
+               rb_free(filter_data);
+               filter_data = 0;
+               filter_data_len = 0;
+               return 0;
+       }
+
        if (strcmp(check, check_str) != 0) {
                if (error) *error = "check strings don't match";
                return -1;
@@ -161,6 +206,7 @@ setfilter(const char *check, const char *data, const char **error)
                r = hs_alloc_scratch(db, &filter_scratch);
                if (r != HS_SUCCESS) {
                        if (error) *error = "couldn't allocate scratch";
+                       hs_free_database(db);
                        return -1;
                }
                if (filter_db) {
@@ -176,9 +222,16 @@ setfilter(const char *check, const char *data, const char **error)
                return 0;
        }
 
+       if (*data != '+') {
+               if (error) *error = "unknown command or data doesn't start with +";
+               return -1;
+       }
+
+       data += 1;
+
        if (state == FILTER_FILLING) {
                int dl;
-               unsigned char *d = rb_base64_decode(data, strlen(data), &dl);
+               unsigned char *d = rb_base64_decode((unsigned char *)data, strlen(data), &dl);
                if (!d) {
                        if (error) *error = "invalid data";
                        return -1;
@@ -331,6 +384,9 @@ filter_msg_user(void *data_)
        if (IsOper(s) || IsOper(data->target_p)) {
                return;
        }
+       if (data->target_p->umodes & filter_umode) {
+               return;
+       }
        char *text = strcpy(clean_buffer, data->text);
        strip_colour(text);
        strip_unprintable(text);
@@ -351,7 +407,7 @@ filter_msg_user(void *data_)
        }
        if (r & ACT_KILL) {
                data->approved = 1;
-               exit_client(NULL, s, s, "Excess flood");
+               exit_client(NULL, s, s, FILTER_EXIT_MSG);
        }
 }
 
@@ -369,6 +425,9 @@ filter_msg_channel(void *data_)
        if (IsOper(s)) {
                return;
        }
+       if (data->chptr->mode.mode & filter_chmode) {
+               return;
+       }
        char *text = strcpy(clean_buffer, data->text);
        strip_colour(text);
        strip_unprintable(text);
@@ -389,7 +448,7 @@ filter_msg_channel(void *data_)
        }
        if (r & ACT_KILL) {
                data->approved = 1;
-               exit_client(NULL, s, s, "Excess flood");
+               exit_client(NULL, s, s, FILTER_EXIT_MSG);
        }
 }