]>
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;
56 DECLARE_MODULE_AV1(extb_extended
, _modinit
, _moddeinit
, NULL
, NULL
, NULL
, "$Revision: 1 $");
61 extban_table
['&'] = eb_and
;
62 extban_table
['|'] = eb_or
;
70 extban_table
['&'] = NULL
;
71 extban_table
['|'] = NULL
;
74 static int eb_or(const char *data
, struct Client
*client_p
,
75 struct Channel
*chptr
, long mode_type
)
77 return eb_combi(data
, client_p
, chptr
, mode_type
, FALSE
);
80 static int eb_and(const char *data
, struct Client
*client_p
,
81 struct Channel
*chptr
, long mode_type
)
83 return eb_combi(data
, client_p
, chptr
, mode_type
, TRUE
);
86 static int eb_combi(const char *data
, struct Client
*client_p
,
87 struct Channel
*chptr
, long mode_type
, int is_and
)
89 const char *p
, *banend
;
90 int have_result
= FALSE
;
91 int allowed_nodes
= 11;
94 if (recursion_depth
>= 5) {
95 DEBUG("combo invalid: recursion depth too high");
96 return EXTBAN_INVALID
;
99 if (EmptyString(data
)) {
100 DEBUG("combo invalid: empty data");
101 return EXTBAN_INVALID
;
104 datalen
= strlen(data
);
105 if (datalen
> BANLEN
) {
106 /* I'd be sad if this ever happened, but if it does we
107 * could overflow the buffer used below, so...
109 DEBUG("combo invalid: > BANLEN");
110 return EXTBAN_INVALID
;
112 banend
= data
+ datalen
;
114 if (data
[0] == '(') {
117 if (*banend
!= ')') {
118 DEBUG("combo invalid: starting but no closing paren");
119 return EXTBAN_INVALID
;
125 /* Empty combibans are invalid. */
127 DEBUG("combo invalid: no data (after removing parens)");
128 return EXTBAN_INVALID
;
131 /* Implementation note:
132 * I want it to be impossible to set a syntactically invalid combi-ban.
133 * (mismatched parens).
134 * That is: valid_extban should return false for those.
135 * Ideally we do not parse the entire ban when actually matching it:
136 * we can just short-circuit if we already know the ban is valid.
137 * Unfortunately there is no separate hook or mode_type for validation,
138 * so we always keep parsing even after we have determined a result.
143 while (--allowed_nodes
) {
145 char *child_data
, child_data_buf
[BANLEN
];
152 DEBUG("combo invalid: no data after ~");
157 f
= extban_table
[(unsigned char) *p
++];
159 DEBUG("combo invalid: non-existant child extban");
164 unsigned int parencount
= 0;
165 int escaped
= FALSE
, done
= FALSE
;
170 /* Possible optimization: we can skip the actual copy if
171 * we already have_result.
173 o
= child_data
= child_data_buf
;
177 DEBUG("combo invalid: EOD while in parens");
184 if (*p
!= '(' && *p
!= ')' && *p
!= '\\' && *p
!= ',')
199 DEBUG("combo invalid: negative parencount");
226 int child_result
= f(child_data
, client_p
, chptr
, mode_type
);
228 if (child_result
== EXTBAN_INVALID
) {
229 DEBUG("combo invalid: child invalid");
233 /* Convert child_result to a plain boolean result */
235 child_result
= child_result
== EXTBAN_NOMATCH
;
237 child_result
= child_result
== EXTBAN_MATCH
;
239 if (is_and
? !child_result
: child_result
)
247 DEBUG("combo invalid: no ',' after ban");
252 DEBUG("combo invalid: banend after ','");
257 /* at this point, *p should == banend */
259 DEBUG("combo invalid: more child extbans than allowed");
266 return have_result
? EXTBAN_NOMATCH
: EXTBAN_MATCH
;
268 return have_result
? EXTBAN_MATCH
: EXTBAN_NOMATCH
;