1 /*
2 * levels.c - Sorting things by category -- Window/Lastlog, Ignore, and Floods
3 *
4 * Copyright (c) 1990 Michael Sandroff.
5 * Copyright (c) 1991, 1992 Troy Rollo.
6 * Copyright (c) 1992-1996 Matthew Green.
7 * Copyright 1993, 2005 EPIC Software Labs.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notices, the above paragraph (the one permitting redistribution),
17 * this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. The names of the author(s) may not be used to endorse or promote
20 * products derived from this software without specific prior written
21 * permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35 #include "irc.h"
36 #include "levels.h"
37 #include "ircaux.h"
38 #include "functions.h"
39 #include "output.h"
40
41 int LEVEL_NONE, LEVEL_CURRENT, LEVEL_OTHER;
42 int LEVEL_PUBLIC, LEVEL_MSG, LEVEL_NOTICE, LEVEL_WALL;
43 int LEVEL_WALLOP, LEVEL_OPNOTE, LEVEL_SNOTE, LEVEL_ACTION;
44 int LEVEL_DCC, LEVEL_CTCP, LEVEL_INVITE, LEVEL_JOIN;
45 int LEVEL_NICK, LEVEL_TOPIC, LEVEL_PART, LEVEL_QUIT;
46 int LEVEL_KICK, LEVEL_MODE, LEVEL_OPERWALL, LEVEL_SYSERR;
47 int LEVEL_USER1, LEVEL_USER2;
48 int LEVEL_USER3, LEVEL_USER4, LEVEL_USER5, LEVEL_USER6;
49 int LEVEL_USER7, LEVEL_USER8, LEVEL_USER9, LEVEL_USER10;
50 int LEVEL_ALL;
51
52 static Bucket *level_bucket = NULL;
53 static int next_level = 1;
54
init_levels(void)55 void init_levels (void)
56 {
57 level_bucket = new_bucket();
58 LEVEL_NONE = 0;
59 LEVEL_OTHER = add_new_level("OTHER");
60 add_new_level_alias(LEVEL_OTHER, "CRAP");
61 LEVEL_PUBLIC = add_new_level("PUBLICS");
62 LEVEL_MSG = add_new_level("MSGS");
63 LEVEL_NOTICE = add_new_level("NOTICES");
64 LEVEL_WALL = add_new_level("WALLS");
65 LEVEL_WALLOP = add_new_level("WALLOPS");
66 LEVEL_OPNOTE = add_new_level("OPNOTES");
67 LEVEL_SNOTE = add_new_level("SNOTES");
68 LEVEL_ACTION = add_new_level("ACTIONS");
69 LEVEL_DCC = add_new_level("DCCS");
70 LEVEL_CTCP = add_new_level("CTCPS");
71 LEVEL_INVITE = add_new_level("INVITES");
72 LEVEL_JOIN = add_new_level("JOINS");
73 LEVEL_NICK = add_new_level("NICKS");
74 LEVEL_TOPIC = add_new_level("TOPICS");
75 LEVEL_PART = add_new_level("PARTS");
76 LEVEL_QUIT = add_new_level("QUITS");
77 LEVEL_KICK = add_new_level("KICKS");
78 LEVEL_MODE = add_new_level("MODES");
79 LEVEL_OPERWALL = add_new_level("OPERWALL");
80 LEVEL_SYSERR = add_new_level("SYSERR");
81 LEVEL_USER1 = add_new_level("USER1");
82 LEVEL_USER2 = add_new_level("USER2");
83 LEVEL_USER3 = add_new_level("USER3");
84 LEVEL_USER4 = add_new_level("USER4");
85 LEVEL_USER5 = add_new_level("USER5");
86 LEVEL_USER6 = add_new_level("USER6");
87 LEVEL_USER7 = add_new_level("USER7");
88 LEVEL_USER8 = add_new_level("USER8");
89 LEVEL_USER9 = add_new_level("USER9");
90 LEVEL_USER10 = add_new_level("USER10");
91 LEVEL_ALL = 0x7FFFFFFF;
92 }
93
94 #define LEVELNAME(i) level_bucket->list[i].name
95 #define LEVELNUM(i) (*(int *)(level_bucket->list[i].stuff))
96
add_new_level(const char * name)97 int add_new_level (const char *name)
98 {
99 const char *name_copy;
100 int * levelnum;
101 int i;
102
103 if ((i = str_to_level(name)) != -1)
104 return i;
105
106 /* Don't allow overflow */
107 if (next_level >= BIT_MAXBIT)
108 return -1;
109
110 name_copy = malloc_strdup(name);
111 levelnum = new_malloc(sizeof(int));
112 *levelnum = next_level++;
113 add_to_bucket(level_bucket, name_copy, levelnum);
114 return *levelnum;
115 }
116
add_new_level_alias(int level,const char * name)117 int add_new_level_alias (int level, const char *name)
118 {
119 const char *name_copy;
120 int * levelnum;
121 int i;
122
123 if ((i = str_to_level(name)) != -1)
124 return i;
125
126 name_copy = malloc_strdup(name);
127 levelnum = new_malloc(sizeof(int));
128 *levelnum = level;
129 add_to_bucket(level_bucket, name_copy, levelnum);
130 return *levelnum;
131 }
132
get_all_levels(void)133 char * get_all_levels (void)
134 {
135 char *buffer = NULL;
136 size_t clue = 0;
137 int i;
138 int next = 1;
139
140 for (i = 0; i < level_bucket->numitems; i++)
141 {
142 /* This is done to skip aliases... */
143 if (LEVELNUM(i) == next)
144 {
145 malloc_strcat_word_c(&buffer, space, LEVELNAME(i), DWORD_NO, &clue);
146 next++;
147 }
148 }
149
150 return buffer;
151 }
152
mask_to_positive_str(const Mask * mask)153 static const char * mask_to_positive_str (const Mask *mask)
154 {
155 static char buffer[512];
156 int i;
157 int next = 1;
158
159 *buffer = 0;
160 for (i = 0; i < level_bucket->numitems; i++)
161 {
162 /* This is done to skip aliases... */
163 if (LEVELNUM(i) == next)
164 {
165 if (mask_isset(mask, next))
166 {
167 if (*buffer)
168 strlcat(buffer, " ", sizeof buffer);
169 strlcat(buffer, LEVELNAME(i), sizeof buffer);
170 }
171 next++;
172 }
173 }
174 return buffer;
175 }
176
mask_to_negative_str(const Mask * mask)177 static const char * mask_to_negative_str (const Mask *mask)
178 {
179 static char buffer[512];
180 int i;
181 int next = 1;
182
183 *buffer = 0;
184 strlcpy(buffer, "ALL", sizeof buffer);
185
186 for (i = 0; i < level_bucket->numitems; i++)
187 {
188 /* This is done to skip aliases... */
189 if (LEVELNUM(i) == next)
190 {
191 if (!mask_isset(mask, next))
192 {
193 if (*buffer)
194 strlcat(buffer, " -", sizeof buffer);
195 strlcat(buffer, LEVELNAME(i), sizeof buffer);
196 }
197 next++;
198 }
199 }
200 return buffer;
201 }
202
mask_to_str(const Mask * mask)203 const char * mask_to_str (const Mask *mask)
204 {
205 static char buffer[512]; /* this *should* be enough for this */
206 const char *str1, *str2;
207
208 if (mask_isall(mask))
209 {
210 strlcpy(buffer, "ALL", sizeof buffer);
211 return buffer;
212 }
213 if (mask_isnone(mask))
214 {
215 strlcpy(buffer, "NONE", sizeof buffer);
216 return buffer;
217 }
218
219 str1 = mask_to_positive_str(mask);
220 str2 = mask_to_negative_str(mask);
221 if (strlen(str1) <= strlen(str2))
222 return str1;
223 else
224 return str2;
225 }
226
str_to_mask(Mask * mask,const char * orig,char ** rejects)227 int str_to_mask (Mask *mask, const char *orig, char **rejects)
228 {
229 char *ptr,
230 *rest;
231 int len,
232 i,
233 neg;
234 int warn = 0;
235 char * str;
236 size_t cluep = 0;
237
238 mask_unsetall(mask);
239
240 if (!orig)
241 return 0; /* Whatever */
242
243 if (rejects == NULL || *rejects != NULL)
244 panic(1, "str_to_mask: rejects must be a pointer to null");
245
246 str = LOCAL_COPY(orig);
247 while ((str = next_arg(str, &rest)) != NULL)
248 {
249 while (str)
250 {
251 if ((ptr = strchr(str, ',')) != NULL)
252 *ptr++ = 0;
253 if ((len = strlen(str)) != 0)
254 {
255 if (my_strnicmp(str, "ALL", len) == 0)
256 mask_setall(mask);
257 else if (my_strnicmp(str, "NONE", len) == 0)
258 mask_unsetall(mask);
259 else
260 {
261 if (*str == '-')
262 {
263 str++, len--;
264 neg = 1;
265 }
266 else
267 neg = 0;
268
269 for (i = 0; i < level_bucket->numitems; i++)
270 {
271 if (!my_strnicmp(str, LEVELNAME(i), len))
272 {
273 if (neg)
274 mask_unset(mask, LEVELNUM(i));
275 else
276 mask_set(mask, LEVELNUM(i));
277 break;
278 }
279 }
280
281 if (i == level_bucket->numitems)
282 malloc_strcat_word_c(rejects, space, str,
283 DWORD_NO, &cluep);
284 }
285 }
286 str = ptr;
287 }
288 str = rest;
289 }
290
291 if (rejects && *rejects)
292 return -1;
293
294 return 0;
295 }
296
standard_level_warning(const char * who,char ** rejects)297 void standard_level_warning (const char *who, char **rejects)
298 {
299 if (rejects && *rejects)
300 {
301 char *s;
302
303 say("%s ignored the these unsupported levels: %s",
304 who, *rejects);
305 s = get_all_levels();
306 say("The valid levels are: %s", s);
307 new_free(&s);
308 new_free(rejects);
309 }
310 }
311
312
str_to_level(const char * orig)313 int str_to_level (const char *orig)
314 {
315 int i, len;
316
317 len = strlen(orig);
318 for (i = 0; i < level_bucket->numitems; i++)
319 if (!my_strnicmp(orig, LEVELNAME(i), len))
320 return LEVELNUM(i);
321
322 return -1;
323 }
324
level_to_str(int l)325 const char * level_to_str (int l)
326 {
327 int i;
328
329 if (l == LEVEL_NONE)
330 return "NONE";
331 else if (l == LEVEL_ALL)
332 return "ALL";
333 else
334 {
335 for (i = 0; i < level_bucket->numitems; i++)
336 if (l == LEVELNUM(i))
337 return LEVELNAME(i);
338 }
339
340 return empty_string;
341 }
342
343 /*
344 * $levelctl(LEVELS)
345 * $levelctl(ADD name)
346 * $levelctl(ALIAS old-name new-name)
347 * $levelctl(LOOKUP name-or-number)
348 * $levelctl(NORMALIZE string)
349 */
levelctl(char * input)350 char *levelctl (char *input)
351 {
352 char *listc, *retval;
353 const char *newlevel, *oldlevel;
354 int oldnum, newnum;
355
356 GET_FUNC_ARG(listc, input);
357 if (!my_strnicmp(listc, "LEVELS", 2)) {
358 retval = get_all_levels();
359 RETURN_MSTR(retval);
360 } else if (!my_strnicmp(listc, "ADD", 2)) {
361 GET_FUNC_ARG(newlevel, input);
362 newnum = add_new_level(newlevel);
363 RETURN_INT(newnum);
364 } else if (!my_strnicmp(listc, "ALIAS", 2)) {
365 GET_FUNC_ARG(oldlevel, input);
366 GET_FUNC_ARG(newlevel, input);
367 oldnum = str_to_level(oldlevel);
368 newnum = add_new_level_alias(oldnum, newlevel);
369 RETURN_INT(newnum);
370 } else if (!my_strnicmp(listc, "LOOKUP", 2)) {
371 GET_FUNC_ARG(newlevel, input);
372 if (is_number(newlevel)) {
373 oldnum = STR2INT(newlevel);
374 oldlevel = level_to_str(oldnum);
375 RETURN_STR(oldlevel);
376 } else {
377 oldnum = str_to_level(newlevel);
378 RETURN_INT(oldnum);
379 }
380 } else if (!my_strnicmp(listc, "NORMALIZE", 1)) {
381 Mask m;
382 const char *r;
383 char *err = NULL;
384
385 mask_unsetall(&m);
386 str_to_mask(&m, input, &err); /* Errors are ignored */
387 r = mask_to_str(&m);
388 RETURN_STR(r);
389 }
390
391 RETURN_EMPTY;
392 }
393
394