1 /*
2 * atheme-services: A collection of minimalist IRC services
3 * flags.c: Functions to convert a flags table into a bitmask.
4 *
5 * Copyright (c) 2005-2010 Atheme Project (http://www.atheme.org)
6 *
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
12 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
13 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
14 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
15 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
16 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
17 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
18 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
19 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
20 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
21 * POSSIBILITY OF SUCH DAMAGE.
22 */
23
24 #include "atheme.h"
25
26 #define FLAGS_ADD 0x1
27 #define FLAGS_DEL 0x2
28
29 unsigned int ca_all = CA_ALL_ALL;
30 unsigned int ca_all_enable = CA_ALL_ALL;
31
32 static char flags_buf[128];
33
34 struct flags_table chanacs_flags[256] = {
35 ['v'] = {CA_VOICE, 0, true, "voice"},
36 ['V'] = {CA_AUTOVOICE, 0, true, "autovoice"},
37 ['o'] = {CA_OP, 0, true, "op"},
38 ['O'] = {CA_AUTOOP, 0, true, "autoop"},
39 ['t'] = {CA_TOPIC, 0, true, "topic"},
40 ['s'] = {CA_SET, 0, true, "set"},
41 ['r'] = {CA_REMOVE, 0, true, "remove"},
42 ['i'] = {CA_INVITE, 0, true, "invite"},
43 ['R'] = {CA_RECOVER, 0, true, "recover"},
44 ['f'] = {CA_FLAGS, 0, true, "acl-change"},
45 ['h'] = {CA_HALFOP, 0, true, "halfop"},
46 ['H'] = {CA_AUTOHALFOP, 0, true, "autohalfop"},
47 ['A'] = {CA_ACLVIEW, 0, true, "acl-view"},
48 ['F'] = {CA_FOUNDER, 0, false, "founder"},
49 ['q'] = {CA_USEOWNER, 0, true, "owner"},
50 ['a'] = {CA_USEPROTECT, 0, true, "protect"},
51 ['b'] = {CA_AKICK, 0, false, "banned"},
52 ['e'] = {CA_EXEMPT, 0, true, "exempt"},
53 };
54
55 gflags_t mu_flags[] = {
56 { 'h', MU_HOLD },
57 { 'n', MU_NEVEROP },
58 { 'o', MU_NOOP },
59 { 'W', MU_WAITAUTH },
60 { 's', MU_HIDEMAIL },
61 { 'm', MU_NOMEMO },
62 { 'e', MU_EMAILMEMOS },
63 { 'C', MU_CRYPTPASS },
64 { 'b', MU_NOBURSTLOGIN },
65 { 'E', MU_ENFORCE },
66 { 'P', MU_USE_PRIVMSG },
67 { 'p', MU_PRIVATE },
68 { 'Q', MU_QUIETCHG },
69 { 'g', MU_NOGREET },
70 { 'r', MU_REGNOLIMIT },
71 { 'N', MU_NEVERGROUP },
72 { 'S', MU_NOPASSWORD },
73 { 0, 0 },
74 };
75
76 gflags_t mc_flags[] = {
77 { 'h', MC_HOLD },
78 { 'o', MC_NOOP },
79 { 'l', MC_LIMITFLAGS },
80 { 'z', MC_SECURE },
81 { 'v', MC_VERBOSE },
82 { 'r', MC_RESTRICTED },
83 { 'k', MC_KEEPTOPIC },
84 { 'e', MC_VERBOSE_OPS },
85 { 't', MC_TOPICLOCK },
86 { 'g', MC_GUARD },
87 { 'p', MC_PRIVATE },
88 { 'n', MC_NOSYNC },
89 { 'f', MC_ANTIFLOOD },
90 { 0, 0 },
91 };
92
93 gflags_t soper_flags[] = {
94 { 'c', SOPER_CONF },
95 { 0, 0 },
96 };
97
flags_associate(unsigned char flag,unsigned int restrictflags,bool def,const char * name)98 unsigned int flags_associate(unsigned char flag, unsigned int restrictflags, bool def, const char *name)
99 {
100 if (chanacs_flags[flag].value && chanacs_flags[flag].value != 0xFFFFFFFF)
101 return 0;
102
103 chanacs_flags[flag].value = flags_find_slot();
104 chanacs_flags[flag].restrictflags = restrictflags;
105 chanacs_flags[flag].def = def;
106 chanacs_flags[flag].name = name;
107
108 update_chanacs_flags();
109
110 return chanacs_flags[flag].value;
111 }
112
flags_clear(unsigned char flag)113 void flags_clear(unsigned char flag)
114 {
115 /* 0xFFFFFFFF = orphaned flag */
116 chanacs_flags[flag].value = 0xFFFFFFFF;
117 chanacs_flags[flag].restrictflags = 0;
118 chanacs_flags[flag].def = false;
119 chanacs_flags[flag].name = NULL;
120 }
121
flags_find_slot(void)122 unsigned int flags_find_slot(void)
123 {
124 unsigned int flag, i;
125 unsigned int all_flags = 0;
126
127 for (i = 0; i < ARRAY_SIZE(chanacs_flags); i++)
128 all_flags |= chanacs_flags[i].value;
129
130 for (flag = 1; flag && (all_flags & flag); flag <<= 1);
131
132 return flag;
133 }
134
135 /* Construct bitmasks to be added and removed
136 * Postcondition *addflags & *removeflags == 0
137 * -- jilles */
flags_make_bitmasks(const char * string,unsigned int * addflags,unsigned int * removeflags)138 void flags_make_bitmasks(const char *string, unsigned int *addflags, unsigned int *removeflags)
139 {
140 unsigned int flag;
141 bool shortflag = false;
142 int status = FLAGS_ADD;
143
144 *addflags = *removeflags = 0;
145 while (*string)
146 {
147 switch (*string)
148 {
149 case '+':
150 status = FLAGS_ADD;
151 break;
152
153 case '-':
154 status = FLAGS_DEL;
155 break;
156
157 case '=':
158 *addflags = 0;
159 *removeflags = 0xFFFFFFFF;
160 status = FLAGS_ADD;
161 break;
162
163 case '*':
164 if (status == FLAGS_ADD)
165 {
166 *addflags |= ca_all_enable;
167 *removeflags |= CA_AKICK;
168 }
169 else if (status == FLAGS_DEL)
170 {
171 *addflags = 0;
172 *removeflags = 0xFFFFFFFF;
173 }
174 break;
175
176 default:
177 if (!shortflag && (flag = xflag_lookup(string)) != 0x0)
178 {
179 if (status == FLAGS_ADD)
180 {
181 *addflags |= flag;
182 *removeflags &= ~flag;
183 }
184 else if (status == FLAGS_DEL)
185 {
186 *addflags &= ~flag;
187 *removeflags |= flag;
188 }
189
190 *addflags &= ca_all;
191 *removeflags &= ca_all;
192
193 return;
194 }
195 else if ((flag = chanacs_flags[(unsigned char)*string].value) != 0x0)
196 {
197 if (status == FLAGS_ADD)
198 {
199 *addflags |= flag;
200 *removeflags &= ~flag;
201 }
202 else if (status == FLAGS_DEL)
203 {
204 *addflags &= ~flag;
205 *removeflags |= flag;
206 }
207 }
208
209 shortflag = true;
210 }
211
212 string++;
213 }
214
215 *addflags &= ca_all;
216 *removeflags &= ca_all;
217
218 return;
219 }
220
flags_to_bitmask(const char * string,unsigned int flags)221 unsigned int flags_to_bitmask(const char *string, unsigned int flags)
222 {
223 unsigned int bitmask = (flags ? flags : 0x0);
224 int status = FLAGS_ADD;
225 unsigned int flag;
226
227 while (*string)
228 {
229 switch (*string)
230 {
231 case '+':
232 status = FLAGS_ADD;
233 break;
234
235 case '-':
236 status = FLAGS_DEL;
237 break;
238
239 case '=':
240 bitmask = 0;
241 status = FLAGS_ADD;
242 break;
243
244 case '*':
245 if (status == FLAGS_ADD)
246 bitmask |= CA_ALLPRIVS & ca_all_enable & ~CA_FOUNDER;
247 else if (status == FLAGS_DEL)
248 bitmask = 0;
249 break;
250
251 default:
252 if ((flag = chanacs_flags[(unsigned char) *string].value) != 0x0)
253 {
254 if (status == FLAGS_ADD)
255 bitmask |= flag;
256 else if (status == FLAGS_DEL)
257 bitmask &= ~flag;
258 }
259 }
260
261 string++;
262 }
263
264 return bitmask & ca_all;
265 }
266
bitmask_to_flags(unsigned int flags)267 char *bitmask_to_flags(unsigned int flags)
268 {
269 char *bptr;
270 unsigned int i = 0;
271
272 bptr = flags_buf;
273
274 *bptr++ = '+';
275
276 for (i = 0; i < ARRAY_SIZE(chanacs_flags); i++)
277 if (chanacs_flags[i].value & flags)
278 *bptr++ = (char) i;
279
280 *bptr++ = '\0';
281
282 return flags_buf;
283 }
284
bitmask_to_flags2(unsigned int addflags,unsigned int removeflags)285 char *bitmask_to_flags2(unsigned int addflags, unsigned int removeflags)
286 {
287 char *bptr;
288 unsigned int i = 0;
289
290 bptr = flags_buf;
291
292 if (removeflags)
293 {
294 *bptr++ = '-';
295 for (i = 0; i < ARRAY_SIZE(chanacs_flags); i++)
296 if (chanacs_flags[i].value & removeflags)
297 *bptr++ = (char) i;
298 }
299 if (addflags)
300 {
301 *bptr++ = '+';
302 for (i = 0; i < ARRAY_SIZE(chanacs_flags); i++)
303 if (chanacs_flags[i].value & addflags)
304 *bptr++ = (char) i;
305 }
306
307 *bptr++ = '\0';
308
309 return flags_buf;
310 }
311
312 /* flags a non-founder with +f and these flags is allowed to set -- jilles */
allow_flags(mychan_t * mc,unsigned int theirflags)313 unsigned int allow_flags(mychan_t *mc, unsigned int theirflags)
314 {
315 unsigned int flags;
316
317 flags = theirflags;
318 flags &= ~CA_AKICK;
319 if (flags & CA_REMOVE)
320 flags |= CA_AKICK;
321 if (flags & CA_OP)
322 flags |= CA_AUTOOP;
323 if (flags & CA_HALFOP)
324 flags |= CA_AUTOHALFOP;
325 if (flags & CA_VOICE)
326 flags |= CA_AUTOVOICE;
327 if (use_limitflags && mc->flags & MC_LIMITFLAGS)
328 {
329 if (!(theirflags & (CA_HIGHPRIVS & ~CA_FLAGS)))
330 flags &= CA_AKICK;
331 else if ((theirflags & CA_HIGHPRIVS) != CA_HIGHPRIVS)
332 flags &= ~CA_HIGHPRIVS;
333 }
334 return flags;
335 }
336
update_chanacs_flags(void)337 void update_chanacs_flags(void)
338 {
339 unsigned int i;
340
341 ca_all = ca_all_enable = 0;
342 for (i = 0; i < ARRAY_SIZE(chanacs_flags); i++)
343 {
344 ca_all |= chanacs_flags[i].value;
345 if (chanacs_flags[i].def == true)
346 ca_all_enable |= chanacs_flags[i].value;
347 }
348
349 if (ircd != NULL)
350 {
351 if (!ircd->uses_halfops)
352 ca_all &= ~(CA_HALFOP | CA_AUTOHALFOP);
353 if (!ircd->uses_protect)
354 ca_all &= ~CA_USEPROTECT;
355 if (!ircd->uses_owner)
356 ca_all &= ~CA_USEOWNER;
357 }
358 }
359
xflag_lookup(const char * name)360 unsigned int xflag_lookup(const char *name)
361 {
362 unsigned int i;
363
364 for (i = 0; i < ARRAY_SIZE(chanacs_flags); i++)
365 {
366 if (chanacs_flags[i].name == NULL)
367 continue;
368
369 if (!strcasecmp(chanacs_flags[i].name, name))
370 return chanacs_flags[i].value;
371 }
372
373 return 0;
374 }
375
xflag_apply(unsigned int in,const char * name)376 unsigned int xflag_apply(unsigned int in, const char *name)
377 {
378 unsigned int out, flag;
379 int status = FLAGS_ADD;
380
381 out = in;
382
383 switch (*name)
384 {
385 case '+':
386 status = FLAGS_ADD;
387 name++;
388 break;
389 case '-':
390 status = FLAGS_DEL;
391 name++;
392 break;
393 }
394
395 flag = xflag_lookup(name);
396
397 if (status == FLAGS_ADD)
398 out |= flag;
399 else
400 out &= ~flag;
401
402 return out;
403 }
404
xflag_tostr(unsigned int flags)405 const char *xflag_tostr(unsigned int flags)
406 {
407 unsigned int i;
408 static char buf[BUFSIZE];
409
410 *buf = '\0';
411
412 for (i = 0; i < ARRAY_SIZE(chanacs_flags); i++)
413 {
414 if (chanacs_flags[i].name == NULL)
415 continue;
416
417 if (!(flags & chanacs_flags[i].value))
418 continue;
419
420 if (*buf != '\0')
421 mowgli_strlcat(buf, ", ", sizeof buf);
422
423 mowgli_strlcat(buf, chanacs_flags[i].name, sizeof buf);
424 }
425
426 return buf;
427 }
428
gflags_tostr(gflags_t * gflags,unsigned int flags)429 char *gflags_tostr(gflags_t *gflags, unsigned int flags)
430 {
431 static char buf[257];
432 char *p = buf;
433 int i;
434 *p++ = '+';
435 for (i = 0; gflags[i].ch; i++)
436 if (flags & gflags[i].value)
437 *p++ = gflags[i].ch;
438 *p = '\0';
439 return buf;
440 }
441
gflag_fromchar(gflags_t * gflags,char f,unsigned int * res)442 static bool gflag_fromchar(gflags_t *gflags, char f, unsigned int *res)
443 {
444 int i;
445 if (f == '+') return true;
446 for (i = 0; gflags[i].ch; i++)
447 {
448 if (gflags[i].ch != f) continue;
449 *res |= gflags[i].value;
450 return true;
451 }
452 return false;
453 }
454
gflags_fromstr(gflags_t * gflags,const char * f,unsigned int * res)455 bool gflags_fromstr(gflags_t *gflags, const char *f, unsigned int *res)
456 {
457 *res = 0;
458 while (*f)
459 if (!gflag_fromchar(gflags, *f++, res))
460 return false;
461 return true;
462 }
463
464 /* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
465 * vim:ts=8
466 * vim:sw=8
467 * vim:noexpandtab
468 */
469