]>
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 // #define DEBUG(s) sendto_realops_snomask(SNO_DEBUG, L_NETWIDE, (s))
47 #define RETURN_INVALID { recursion_depth--; return EXTBAN_INVALID; }
49 static int _modinit(void);
50 static void _moddeinit(void);
51 static int eb_or(const char *data
, struct Client
*client_p
, struct Channel
*chptr
, long mode_type
);
52 static int eb_and(const char *data
, struct Client
*client_p
, struct Channel
*chptr
, long mode_type
);
53 static int eb_combi(const char *data
, struct Client
*client_p
, struct Channel
*chptr
, long mode_type
, int is_and
);
54 static int recursion_depth
= 0;
55 static const char extb_desc
[] = "Combination ($&, $|) extban types";
57 DECLARE_MODULE_AV2(extb_extended
, _modinit
, _moddeinit
, NULL
, NULL
, NULL
, NULL
, NULL
, extb_desc
);
62 extban_table
['&'] = eb_and
;
63 extban_table
['|'] = eb_or
;
71 extban_table
['&'] = NULL
;
72 extban_table
['|'] = NULL
;
75 static int eb_or(const char *data
, struct Client
*client_p
,
76 struct Channel
*chptr
, long mode_type
)
78 return eb_combi(data
, client_p
, chptr
, mode_type
, FALSE
);
81 static int eb_and(const char *data
, struct Client
*client_p
,
82 struct Channel
*chptr
, long mode_type
)
84 return eb_combi(data
, client_p
, chptr
, mode_type
, TRUE
);
87 static int eb_combi(const char *data
, struct Client
*client_p
,
88 struct Channel
*chptr
, long mode_type
, int is_and
)
90 const char *p
, *banend
;
91 int have_result
= FALSE
;
92 int allowed_nodes
= 11;
95 if (recursion_depth
>= 5) {
96 DEBUG("combo invalid: recursion depth too high");
97 return EXTBAN_INVALID
;
100 if (EmptyString(data
)) {
101 DEBUG("combo invalid: empty data");
102 return EXTBAN_INVALID
;
105 datalen
= strlen(data
);
106 if (datalen
> BANLEN
) {
107 /* I'd be sad if this ever happened, but if it does we
108 * could overflow the buffer used below, so...
110 DEBUG("combo invalid: > BANLEN");
111 return EXTBAN_INVALID
;
113 banend
= data
+ datalen
;
115 if (data
[0] == '(') {
118 if (*banend
!= ')') {
119 DEBUG("combo invalid: starting but no closing paren");
120 return EXTBAN_INVALID
;
126 /* Empty combibans are invalid. */
128 DEBUG("combo invalid: no data (after removing parens)");
129 return EXTBAN_INVALID
;
132 /* Implementation note:
133 * I want it to be impossible to set a syntactically invalid combi-ban.
134 * (mismatched parens).
135 * That is: valid_extban should return false for those.
136 * Ideally we do not parse the entire ban when actually matching it:
137 * we can just short-circuit if we already know the ban is valid.
138 * Unfortunately there is no separate hook or mode_type for validation,
139 * so we always keep parsing even after we have determined a result.
144 while (--allowed_nodes
) {
146 char *child_data
, child_data_buf
[BANLEN
];
153 DEBUG("combo invalid: no data after ~");
158 f
= extban_table
[(unsigned char) *p
++];
160 DEBUG("combo invalid: non-existant child extban");
165 unsigned int parencount
= 0;
166 int escaped
= FALSE
, done
= FALSE
;
171 /* Possible optimization: we can skip the actual copy if
172 * we already have_result.
174 o
= child_data
= child_data_buf
;
178 DEBUG("combo invalid: EOD while in parens");
185 if (*p
!= '(' && *p
!= ')' && *p
!= '\\' && *p
!= ',')
200 DEBUG("combo invalid: negative parencount");
227 int child_result
= f(child_data
, client_p
, chptr
, mode_type
);
229 if (child_result
== EXTBAN_INVALID
) {
230 DEBUG("combo invalid: child invalid");
234 /* Convert child_result to a plain boolean result */
236 child_result
= child_result
== EXTBAN_NOMATCH
;
238 child_result
= child_result
== EXTBAN_MATCH
;
240 if (is_and
? !child_result
: child_result
)
248 DEBUG("combo invalid: no ',' after ban");
253 DEBUG("combo invalid: banend after ','");
258 /* at this point, *p should == banend */
260 DEBUG("combo invalid: more child extbans than allowed");
267 return have_result
? EXTBAN_NOMATCH
: EXTBAN_MATCH
;
269 return have_result
? EXTBAN_MATCH
: EXTBAN_NOMATCH
;