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