]>
jfr.im git - solanum.git/blob - extensions/extb_combi.c
2 * Extban that combines other extbans.
5 * $&:~a,m:*!*@gateway/web/cgi-irc*
6 * Which means: match unidentified webchat users.
7 * ("m" is another new extban type, which just does a normal match).
9 * More complicated example:
10 * $&:~a,|:(m:*!*@gateway/web/foo,m:*!*@gateway/web/bar)
11 * Which means: unidentified and using the foo or bar gateway.
15 * - Optional pair of parens around data.
17 * - component bans are separated by commas, but commas between
18 * matching pairs of parens are skipped.
20 * - Unbalanced parens are an error.
22 * - Parens, commas and backslashes can be escaped by backslashes.
24 * - A backslash before any character other than a paren or backslash
25 * is just a backslash (backslash and character are both used).
27 * - Non-existant extbans are invalid.
28 * This is primarily for consistency with non-combined bans:
29 * the ircd does not let you set +b $f unless the 'f' extban is loaded,
30 * so setting $&:f should be impossible too.
33 * - Backslashes double inside nested bans.
34 * Hopefully acceptable because they should be rare.
36 * - Is performance good enough?
37 * I suspect it is, but have done no load testing.
45 static const char extb_desc
[] = "Combination ($&, $|) extban types";
47 // #define MOD_DEBUG(s) sendto_realops_snomask(SNO_DEBUG, L_NETWIDE, (s))
49 #define RETURN_INVALID { recursion_depth--; return EXTBAN_INVALID; }
51 static int _modinit(void);
52 static void _moddeinit(void);
53 static int eb_or(const char *data
, struct Client
*client_p
, struct Channel
*chptr
, long mode_type
);
54 static int eb_and(const char *data
, struct Client
*client_p
, struct Channel
*chptr
, long mode_type
);
55 static int eb_combi(const char *data
, struct Client
*client_p
, struct Channel
*chptr
, long mode_type
, bool is_and
);
56 static int recursion_depth
= 0;
58 DECLARE_MODULE_AV2(extb_extended
, _modinit
, _moddeinit
, NULL
, NULL
, NULL
, NULL
, NULL
, extb_desc
);
63 extban_table
['&'] = eb_and
;
64 extban_table
['|'] = eb_or
;
72 extban_table
['&'] = NULL
;
73 extban_table
['|'] = NULL
;
76 static int eb_or(const char *data
, struct Client
*client_p
,
77 struct Channel
*chptr
, long mode_type
)
79 return eb_combi(data
, client_p
, chptr
, mode_type
, false);
82 static int eb_and(const char *data
, struct Client
*client_p
,
83 struct Channel
*chptr
, long mode_type
)
85 return eb_combi(data
, client_p
, chptr
, mode_type
, true);
88 static int eb_combi(const char *data
, struct Client
*client_p
,
89 struct Channel
*chptr
, long mode_type
, bool is_and
)
91 const char *p
, *banend
;
92 bool have_result
= false;
93 int allowed_nodes
= 11;
96 if (recursion_depth
>= 5) {
97 MOD_DEBUG("combo invalid: recursion depth too high");
98 return EXTBAN_INVALID
;
101 if (EmptyString(data
)) {
102 MOD_DEBUG("combo invalid: empty data");
103 return EXTBAN_INVALID
;
106 datalen
= strlen(data
);
107 if (datalen
> BANLEN
) {
108 /* I'd be sad if this ever happened, but if it does we
109 * could overflow the buffer used below, so...
111 MOD_DEBUG("combo invalid: > BANLEN");
112 return EXTBAN_INVALID
;
114 banend
= data
+ datalen
;
116 if (data
[0] == '(') {
119 if (*banend
!= ')') {
120 MOD_DEBUG("combo invalid: starting but no closing paren");
121 return EXTBAN_INVALID
;
127 /* Empty combibans are invalid. */
129 MOD_DEBUG("combo invalid: no data (after removing parens)");
130 return EXTBAN_INVALID
;
133 /* Implementation note:
134 * I want it to be impossible to set a syntactically invalid combi-ban.
135 * (mismatched parens).
136 * That is: valid_extban should return false for those.
137 * Ideally we do not parse the entire ban when actually matching it:
138 * we can just short-circuit if we already know the ban is valid.
139 * Unfortunately there is no separate hook or mode_type for validation,
140 * so we always keep parsing even after we have determined a result.
145 while (--allowed_nodes
) {
147 char *child_data
, child_data_buf
[BANLEN
];
154 MOD_DEBUG("combo invalid: no data after ~");
159 f
= extban_table
[(unsigned char) *p
++];
161 MOD_DEBUG("combo invalid: non-existant child extban");
166 unsigned int parencount
= 0;
167 bool escaped
= false, done
= false;
172 /* Possible optimization: we can skip the actual copy if
173 * we already have_result.
175 o
= child_data
= child_data_buf
;
179 MOD_DEBUG("combo invalid: EOD while in parens");
186 if (*p
!= '(' && *p
!= ')' && *p
!= '\\' && *p
!= ',')
201 MOD_DEBUG("combo invalid: negative parencount");
228 int child_result
= f(child_data
, client_p
, chptr
, mode_type
);
230 if (child_result
== EXTBAN_INVALID
) {
231 MOD_DEBUG("combo invalid: child invalid");
235 /* Convert child_result to a plain boolean result */
237 child_result
= child_result
== EXTBAN_NOMATCH
;
239 child_result
= child_result
== EXTBAN_MATCH
;
241 if (is_and
? !child_result
: child_result
)
249 MOD_DEBUG("combo invalid: no ',' after ban");
254 MOD_DEBUG("combo invalid: banend after ','");
259 /* at this point, *p should == banend */
261 MOD_DEBUG("combo invalid: more child extbans than allowed");
268 return have_result
? EXTBAN_NOMATCH
: EXTBAN_MATCH
;
270 return have_result
? EXTBAN_MATCH
: EXTBAN_NOMATCH
;