1 /*
2  * alias.c Handles command aliases for irc.c
3  *
4  * Written By Michael Sandrof
5  *
6  * Copyright (c) 1990 Michael Sandrof.
7  * Copyright (c) 1991, 1992 Troy Rollo.
8  * Copyright (c) 1992-2021 Matthew R. Green.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. The name of the author may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 #include "irc.h"
36 IRCII_RCSID("@(#)$eterna: alias.c,v 1.183 2021/02/27 08:02:14 mrg Exp $");
37 
38 #include "alias.h"
39 #include "dcc.h"
40 #include "status.h"
41 #include "edit.h"
42 #include "history.h"
43 #include "vars.h"
44 #include "ircaux.h"
45 #include "server.h"
46 #include "screen.h"
47 #include "window.h"
48 #include "input.h"
49 #include "names.h"
50 #include "server.h"
51 #include "output.h"
52 #include "names.h"
53 #include "parse.h"
54 #include "notify.h"
55 #include "ignore.h"
56 #include "exec.h"
57 #include "ircterm.h"
58 #include "numbers.h"
59 
60 #include <sys/stat.h>
61 
62 #ifdef HAVE_CRYPT_H
63 # include <crypt.h>
64 #endif
65 
66 /* Alias: structure of each alias entry */
67 struct	alias_stru
68 {
69 	u_char	*name;		/* name of alias */
70 	u_char	*stuff;		/* what the alias is */
71 	int	mark;		/* used to prevent recursive aliasing */
72 	int	global;		/* set if loaded from `global' */
73 	Alias	*next;		/* pointer to next alias in list */
74 };
75 
76 	int	parse_number(u_char **);
77 static	u_char	*next_unit(u_char *, u_char *, int *, int);
78 static	long	randm(long);
79 static	u_char	*lastop(u_char *);
80 static	u_char	*arg_number(int, int, u_char *);
81 static	Alias	*find_alias(Alias **, u_char *, int, int *);
82 static	void	insert_alias(Alias **, Alias *);
83 static	u_char	*alias_arg(u_char **, u_int *);
84 static	u_char	*find_inline(u_char *);
85 static	u_char	*built_in_alias(int);
86 static	void	expander_addition(u_char **, u_char *, int, u_char *);
87 static	u_char	*alias_special_char(u_char *, u_char **, u_char *, u_char *, u_char *, int *);
88 
89 static	u_char	*alias_detected(void);
90 static	u_char	*alias_sent_nick(void);
91 static	u_char	*alias_recv_nick(void);
92 static	u_char	*alias_msg_body(void);
93 static	u_char	*alias_joined_nick(void);
94 static	u_char	*alias_public_nick(void);
95 static	u_char	*alias_dollar(void);
96 static	u_char	*alias_channel(void);
97 static	u_char	*alias_server(void);
98 static	u_char	*alias_query_nick(void);
99 static	u_char	*alias_target(void);
100 static	u_char	*alias_nick(void);
101 static	u_char	*alias_invite(void);
102 static	u_char	*alias_cmdchar(void);
103 static	u_char	*alias_line(void);
104 static	u_char	*alias_away(void);
105 static	u_char	*alias_oper(void);
106 static	u_char	*alias_chanop(void);
107 static	u_char	*alias_modes(void);
108 static	u_char	*alias_time(void);
109 static	u_char	*alias_version(void);
110 static	u_char	*alias_currdir(void);
111 static	u_char	*alias_current_numeric(void);
112 static	u_char	*alias_server_version(void);
113 
114 typedef struct
115 {
116 	u_char	name;
117 	u_char	*(*func)(void);
118 }	BuiltIns;
119 
120 static	BuiltIns built_in[] =
121 {
122 	{ '.',		alias_sent_nick },
123 	{ ',',		alias_recv_nick },
124 	{ ':',		alias_joined_nick },
125 	{ ';',		alias_public_nick },
126 	{ '$',		alias_dollar },
127 	{ 'A',		alias_away },
128 	{ 'B',		alias_msg_body },
129 	{ 'C',		alias_channel },
130 	{ 'D',		alias_detected },
131 /*
132 	{ 'E' },
133 	{ 'F' },
134 	{ 'G' },
135 */
136 	{ 'H', 		alias_current_numeric },
137 	{ 'I',		alias_invite },
138 /*
139 	{ 'J' },
140 */
141 	{ 'K',		alias_cmdchar },
142 	{ 'L',		alias_line },
143 	{ 'M',		alias_modes },
144 	{ 'N',		alias_nick },
145 	{ 'O',		alias_oper },
146 	{ 'P',		alias_chanop },
147 	{ 'Q',		alias_query_nick },
148 	{ 'R',		alias_server_version },
149 	{ 'S',		alias_server },
150 	{ 'T',		alias_target },
151 	{ 'U',		alias_buffer },
152 	{ 'V',		alias_version },
153 	{ 'W',		alias_currdir },
154 /*
155 	{ 'X' },
156 	{ 'Y' },
157 */
158 	{ 'Z',		alias_time },
159 	{ '\0',		NULL }
160 };
161 
162 static	u_char	*function_left(u_char *);
163 static	u_char	*function_right(u_char *);
164 static	u_char	*function_mid(u_char *);
165 static	u_char	*function_rand(u_char *);
166 static	u_char	*function_srand(u_char *);
167 static	u_char	*function_time(u_char *);
168 static	u_char	*function_stime(u_char *);
169 static	u_char	*function_tdiff(u_char *);
170 static	u_char	*function_index(u_char *);
171 static	u_char	*function_rindex(u_char *);
172 static	u_char	*function_match(u_char *);
173 static	u_char	*function_rmatch(u_char *);
174 static	u_char	*function_userhost(u_char *);
175 static	u_char	*function_strip(u_char *);
176 static	u_char	*function_encode(u_char *);
177 static	u_char	*function_decode(u_char *);
178 static	u_char	*function_ischannel(u_char *);
179 static	u_char	*function_ischanop(u_char *);
180 #ifdef HAVE_CRYPT
181 static	u_char	*function_crypt(u_char *);
182 #endif /* HAVE_CRYPT */
183 static	u_char	*function_hasvoice(u_char *);
184 static	u_char	*function_dcclist(u_char *);
185 static	u_char	*function_chatpeers(u_char *);
186 static	u_char	*function_word(u_char *);
187 static	u_char	*function_querynick(u_char *);
188 static	u_char	*function_windows(u_char *);
189 static	u_char	*function_screens(u_char *);
190 static	u_char	*function_notify(u_char *);
191 static	u_char	*function_ignored(u_char *);
192 static	u_char	*function_winserver(u_char *);
193 static	u_char	*function_winservergroup(u_char *);
194 static	u_char	*function_winvisible(u_char *);
195 static	u_char	*function_winnum(u_char *);
196 static	u_char	*function_winnam(u_char *);
197 static	u_char	*function_winrows(u_char *);
198 static	u_char	*function_wincols(u_char *);
199 static	u_char	*function_connect(u_char *);
200 static	u_char	*function_listen(u_char *);
201 static	u_char	*function_toupper(u_char *);
202 static	u_char	*function_tolower(u_char *);
203 static	u_char	*function_channels(u_char *);
204 static	u_char	*function_servers(u_char *);
205 static	u_char	*function_servertype(u_char *);
206 static	u_char	*function_onchannel(u_char *);
207 static	u_char	*function_pid(u_char *);
208 static	u_char	*function_ppid(u_char *);
209 static	u_char	*function_idle(u_char *);
210 #ifdef HAVE_STRFTIME
211 static	u_char	*function_strftime(u_char *);
212 #endif /* HAVE_STRFTIME */
213 static	u_char	*function_urlencode(u_char *);
214 static	u_char	*function_shellfix(u_char *);
215 static	u_char	*function_filestat(u_char *);
216 
217 typedef struct
218 {
219 	u_char	*name;
220 	u_char	*(*func)(u_char *);
221 }	BuiltInFunctions;
222 
223 static BuiltInFunctions	built_in_functions[] =
224 {
225 	{ UP("LEFT"),		function_left },
226 	{ UP("RIGHT"),		function_right },
227 	{ UP("MID"),		function_mid },
228 	{ UP("RAND"),		function_rand },
229 	{ UP("SRAND"),		function_srand },
230 	{ UP("TIME"),		function_time },
231 	{ UP("TDIFF"),		function_tdiff },
232 	{ UP("STIME"),		function_stime },
233 	{ UP("INDEX"),		function_index },
234 	{ UP("RINDEX"),		function_rindex },
235 	{ UP("MATCH"),		function_match },
236 	{ UP("RMATCH"),		function_rmatch },
237 	{ UP("USERHOST"),	function_userhost },
238 	{ UP("STRIP"),		function_strip },
239 	{ UP("ENCODE"),		function_encode },
240 	{ UP("DECODE"),		function_decode },
241 	{ UP("ISCHANNEL"),	function_ischannel },
242 	{ UP("ISCHANOP"),	function_ischanop },
243 #ifdef HAVE_CRYPT
244 	{ UP("CRYPT"),		function_crypt },
245 #endif /* HAVE_CRYPT */
246 	{ UP("HASVOICE"),	function_hasvoice },
247 	{ UP("DCCLIST"),	function_dcclist },
248 	{ UP("CHATPEERS"),	function_chatpeers },
249 	{ UP("WORD"),		function_word },
250 	{ UP("WINNUM"),		function_winnum },
251 	{ UP("WINNAM"),		function_winnam },
252 	{ UP("WINVIS"),		function_winvisible },
253 	{ UP("WINROWS"),	function_winrows },
254 	{ UP("WINCOLS"),	function_wincols },
255 	{ UP("WINSERVER"),	function_winserver },
256 	{ UP("WINSERVERGROUP"),	function_winservergroup },
257 	{ UP("CONNECT"),	function_connect },
258 	{ UP("LISTEN"),		function_listen },
259 	{ UP("TOUPPER"),	function_toupper },
260 	{ UP("TOLOWER"),	function_tolower },
261 	{ UP("MYCHANNELS"),	function_channels },
262 	{ UP("MYSERVERS"),	function_servers },
263 	{ UP("SERVERTYPE"),	function_servertype },
264 	{ UP("CURPOS"),		function_curpos },
265 	{ UP("ONCHANNEL"),	function_onchannel },
266 	{ UP("PID"),		function_pid },
267 	{ UP("PPID"),		function_ppid },
268 	{ UP("CHANUSERS"),	function_chanusers },
269 #ifdef HAVE_STRFTIME
270 	{ UP("STRFTIME"),	function_strftime },
271 #endif /* HAVE_STRFTIME */
272 	{ UP("IDLE"),		function_idle },
273 	{ UP("QUERYNICK"),	function_querynick },
274 	{ UP("WINDOWS"),	function_windows },
275 	{ UP("SCREENS"),	function_screens },
276 	{ UP("NOTIFY"),		function_notify },
277 	{ UP("IGNORED"),	function_ignored },
278 	{ UP("URLENCODE"),	function_urlencode },
279 	{ UP("SHELLFIX"),	function_shellfix },
280 	{ UP("FILESTAT"),	function_filestat },
281 	{ UP(0),		NULL }
282 };
283 
284 /* alias_illegals: characters that are illegal in alias names */
285 static	u_char	alias_illegals[] = " #+-*/\\()={}[]<>!@$%^~`,?;:|'\"";
286 
287 static	Alias	*alias_list[] =
288 {
289 	NULL,
290 	NULL
291 };
292 
293 static	int	eval_args;
294 
295 /* function_stack and function_stkptr - hold the return values from functions */
296 static	u_char	* function_stack[128] =
297 {
298 	NULL
299 };
300 static	int	function_stkptr = 0;
301 
302 /*
303  * find_alias: looks up name in in alias list.  Returns the Alias	entry if
304  * found, or null if not found.   If do_unlink is set, the found entry is
305  * removed from the list as well.  If match is null, only perfect matches
306  * will return anything.  Otherwise, the number of matches will be returned.
307  */
308 static	Alias	*
find_alias(Alias ** list,u_char * name,int do_unlink,int * match)309 find_alias(Alias **list, u_char *name, int do_unlink, int *match)
310 {
311 	Alias	*tmp,
312 		*last = NULL;
313 	int	cmp;
314 	size_t	len;
315 	int	(*cmp_func)(const u_char *, const u_char *, size_t);
316 
317 	if (match)
318 	{
319 		*match = 0;
320 		cmp_func = my_strnicmp;
321 	}
322 	else
323 		cmp_func = (int (*)(const u_char *, const u_char *, size_t)) my_stricmp;
324 	if (name)
325 	{
326 		len = my_strlen(name);
327 		for (tmp = *list; tmp; tmp = tmp->next)
328 		{
329 			if ((cmp = cmp_func(name, tmp->name, len)) == 0)
330 			{
331 				if (do_unlink)
332 				{
333 					if (last)
334 						last->next = tmp->next;
335 					else
336 						*list = tmp->next;
337 				}
338 				if (match)
339 				{
340 					(*match)++;
341 					if (my_strlen(tmp->name) == len)
342 					{
343 						*match = 0;
344 						return (tmp);
345 					}
346 				}
347 				else
348 					return (tmp);
349 			}
350 			else if (cmp < 0)
351 				break;
352 			last = tmp;
353 		}
354 	}
355 	if (match && (*match == 1))
356 		return (last);
357 	else
358 		return (NULL);
359 }
360 
361 /*
362  * insert_alias: adds the given alias to the alias list.  The alias list is
363  * alphabetized by name
364  */
365 static	void
insert_alias(Alias ** list,Alias * nalias)366 insert_alias(Alias **list, Alias *nalias)
367 {
368 	Alias	*tmp,
369 		*last,
370 		*foo;
371 
372 	last = NULL;
373 	for (tmp = *list; tmp; tmp = tmp->next)
374 	{
375 		if (my_strcmp(nalias->name, tmp->name) < 0)
376 			break;
377 		last = tmp;
378 	}
379 	if (last)
380 	{
381 		foo = last->next;
382 		last->next = nalias;
383 		nalias->next = foo;
384 	}
385 	else
386 	{
387 		nalias->next = *list;
388 		*list = nalias;
389 	}
390 }
391 
392 /*
393  * add_alias: given the alias name and "stuff" that makes up the alias,
394  * add_alias() first checks to see if the alias name is already in use... if
395  * so, the old alias is replaced with the new one.  If the alias is not
396  * already in use, it is added.
397  */
398 void
add_alias(int type,u_char * name,u_char * stuff)399 add_alias(int type, u_char *name, u_char *stuff)
400 {
401 	Alias	*tmp;
402 	u_char	*ptr;
403 
404 	upper(name);
405 	if (type == COMMAND_ALIAS)
406 		say("Alias	%s added", name);
407 	else
408 	{
409 		if (!my_strcmp(name, "FUNCTION_RETURN"))
410 		{
411 			if (function_stack[function_stkptr])
412 				new_free(&function_stack[function_stkptr]);
413 			malloc_strcpy(&function_stack[function_stkptr], stuff);
414 			return;
415 		}
416 		if ((ptr = sindex(name, alias_illegals)) != NULL)
417 		{
418 			yell("Assign names may not contain '%c'", *ptr);
419 			return;
420 		}
421 		say("Assign %s added", name);
422 	}
423 	if ((tmp = find_alias(&(alias_list[type]), name, 1, NULL)) ==
424 			NULL)
425 	{
426 		tmp = new_malloc(sizeof *tmp);
427 		if (tmp == NULL)
428 		{
429 			yell("Couldn't allocate memory for new alias!");
430 			return;
431 		}
432 		tmp->name = NULL;
433 		tmp->stuff = NULL;
434 	}
435 	malloc_strcpy(&(tmp->name), name);
436 	malloc_strcpy(&(tmp->stuff), stuff);
437 	tmp->mark = 0;
438 	tmp->global = loading_global();
439 	insert_alias(&(alias_list[type]), tmp);
440 }
441 
442 /* alias_arg: a special version of next_arg for aliases */
443 static	u_char	*
alias_arg(u_char ** str,u_int * pos)444 alias_arg(u_char **str, u_int *pos)
445 {
446 	u_char	*ptr;
447 
448 	if (!*str)
449 		return NULL;
450 	*pos = 0;
451 	ptr = *str;
452 	while (' ' == *ptr)
453 	{
454 		ptr++;
455 		(*pos)++;
456 	}
457 	if (*ptr == '\0')
458 	{
459 		*str = empty_string();
460 		return (NULL);
461 	}
462 	if ((*str = sindex(ptr, UP(" "))) != NULL)
463 		*((*str)++) = '\0';
464 	else
465 		*str = empty_string();
466 	return (ptr);
467 }
468 
469 /* word_count: returns the number of words in the given string */
470 int
word_count(u_char * str)471 word_count(u_char *str)
472 {
473 	int	cnt = 0;
474 	u_char	*ptr;
475 
476 	while (1)
477 	{
478 		if ((ptr = sindex(str, UP("^ "))) != NULL)
479 		{
480 			cnt++;
481 			if ((str = sindex(ptr, UP(" "))) == NULL)
482 				return (cnt);
483 		}
484 		else
485 			return (cnt);
486 	}
487 }
488 
489 static	u_char	*
built_in_alias(int c)490 built_in_alias(int c)
491 {
492 	BuiltIns	*tmp;
493 	u_char	*ret = NULL;
494 
495 	for (tmp = built_in; tmp->name; tmp++)
496 		if ((u_char)c == tmp->name)
497 		{
498 			malloc_strcpy(&ret, tmp->func());
499 			break;
500 		}
501 	return (ret);
502 }
503 
504 /*
505  * find_inline: This simply looks up the given str.  It first checks to see
506  * if its a user variable and returns it if so.  If not, it checks to see if
507  * it's an IRC variable and returns it if so.  If not, it checks to see if
508  * its and environment variable and returns it if so.  If not, it returns
509  * null.  It mallocs the returned string
510  */
511 static	u_char	*
find_inline(u_char * str)512 find_inline(u_char *str)
513 {
514 	Alias	*nalias;
515 	u_char	*ret = NULL;
516 	u_char	*tmp;
517 
518 	if ((nalias = find_alias(&(alias_list[VAR_ALIAS]), str, 0, (int *) NULL))
519 			!= NULL)
520 	{
521 		malloc_strcpy(&ret, nalias->stuff);
522 		return (ret);
523 	}
524 	if ((my_strlen(str) == 1) && (ret = built_in_alias(*str)))
525 		return(ret);
526 	if ((ret = make_string_var(str)) != NULL)
527 		return (ret);
528 #ifdef DAEMON_UID
529 	if (getuid() == DAEMON_UID)
530 	malloc_strcpy(&ret, (getuid() != DAEMON_UID) && (tmp = my_getenv(str)) ?
531 				tmp : empty_string());
532 #else
533 	malloc_strcpy(&ret, (tmp = my_getenv(str)) ? tmp : empty_string());
534 #endif /* DAEMON_UID */
535 	return (ret);
536 }
537 
538 u_char	*
call_function(u_char * name,u_char * f_args,u_char * args,int * args_flag)539 call_function(u_char *name, u_char *f_args, u_char *args, int *args_flag)
540 {
541 	u_char	*tmp;
542 	u_char	*result = NULL;
543 	u_char	*sub_buffer = NULL;
544 	int	builtnum;
545 	u_char	*debug_copy = NULL;
546 	u_char	*cmd = NULL;
547 
548 	malloc_strcpy(&cmd, name);
549 	upper(cmd);
550 	tmp = expand_alias(NULL, f_args, args, args_flag, NULL);
551 	if (get_int_var(DEBUG_VAR) & DEBUG_FUNCTIONS)
552 		malloc_strcpy(&debug_copy, tmp);
553 	for (builtnum = 0; built_in_functions[builtnum].name != NULL &&
554 			my_strcmp(built_in_functions[builtnum].name, cmd);
555 			builtnum++)
556 		;
557 	new_free(&cmd);
558 	if (built_in_functions[builtnum].name)
559 		result = built_in_functions[builtnum].func(tmp);
560 	else
561 	{
562 		malloc_snprintf(&sub_buffer, "%s %s", name, tmp);
563 		function_stack[++function_stkptr] = NULL;
564 		parse_command(sub_buffer, 0, empty_string());
565 		new_free(&sub_buffer);
566 		eval_args=1;
567 		result = function_stack[function_stkptr];
568 		function_stack[function_stkptr] = NULL;
569 		if (!result)
570 			malloc_strcpy(&result, empty_string());
571 		function_stkptr--;
572 	}
573 	if (debug_copy)
574 	{
575 		yell("Function %s(%s) returned %s",
576 		    name, debug_copy, result);
577 		new_free(&debug_copy);
578 	}
579 	new_free(&tmp);
580 	return (result);
581 }
582 
583 
584 /* Given a pointer to an operator, find the last operator in the string */
585 static	u_char	*
lastop(u_char * ptr)586 lastop(u_char *ptr)
587 {
588 	while (ptr[1] && my_index("!=<>&^|#+/-*", ptr[1]))
589 		ptr++;
590 	return ptr;
591 }
592 
593 /* Convert foo[bar][baz] into foo.bar.baz. */
594 static	void
bracket_to_dot(u_char * ptr)595 bracket_to_dot(u_char *ptr)
596 {
597 	u_char	*left, *right;
598 
599 	while ((left = my_index(ptr, '[')) != NULL)
600 	{
601 		*left++ = '.';
602 		if ((right = matching_bracket(left, '[', ']')) == NULL)
603 			break;
604 
605 		/* can't use strcat here, overlapping strings */
606 		for (; right[0]; right++)
607 			right[0] = right[1];
608 	}
609 }
610 
611 #define	NU_EXPR	0
612 #define	NU_CONJ NU_EXPR
613 #define	NU_ASSN	1
614 #define	NU_COMP 2
615 #define	NU_ADD  3
616 #define	NU_MULT 4
617 #define	NU_UNIT 5
618 #define	NU_TERT 6
619 #define	NU_BITW 8
620 
621 static	u_char	*
next_unit(u_char * str,u_char * args,int * arg_flag,int stage)622 next_unit(u_char *str, u_char *args, int *arg_flag, int stage)
623 {
624 	u_char	*ptr,
625 		*ptr2,
626 		*right;
627 	int	got_sloshed = 0;
628 	u_char	*lastc;
629 	u_char	tmp[40];
630 	u_char	*result1 = NULL,
631 		*result2 = NULL;
632 	long	value1 = 0,
633 		value2,
634 		value3;
635 	u_char	op;
636 	int	display;
637 
638 	while (isspace(*str))
639 		++str;
640 	if (!*str)
641 	{
642 		malloc_strcpy(&result1, empty_string());
643 		return result1;
644 	}
645 	lastc = str+my_strlen(str)-1;
646 	while (isspace(*lastc))
647 		*lastc-- = '\0';
648 	if (stage == NU_UNIT && *lastc == ')' && *str == '(')
649 	{
650 		str++, *lastc-- = '\0';
651 		return next_unit(str, args, arg_flag, NU_EXPR);
652 	}
653 	if (!*str)
654 	{
655 		malloc_strcpy(&result1, empty_string());
656 		return result1;
657 	}
658 	for (ptr = str; *ptr; ptr++)
659 	{
660 		if (got_sloshed) /* Help! I'm drunk! */
661 		{
662 			got_sloshed = 0;
663 			continue;
664 		}
665 		switch (*ptr)
666 		{
667 		case '\\':
668 			got_sloshed = 1;
669 			continue;
670 		case '(':
671 			if (stage != NU_UNIT || ptr == str)
672 			{
673 				if (!(ptr2 = matching_bracket(ptr+1, '(', ')')))
674 					ptr = ptr+my_strlen(ptr)-1;
675 				else
676 					ptr = ptr2;
677 				break;
678 			}
679 			*ptr++ = '\0';
680 			right = ptr;
681 			ptr = matching_bracket(right, '(', ')');
682 			if (ptr)
683 				*ptr++ = '\0';
684 			result1 = call_function(str, right, args, arg_flag);
685 			if (ptr && *ptr)
686 			{
687 				malloc_strcat(&result1, ptr);
688 				result2 = next_unit(result1, args, arg_flag,
689 						stage);
690 				new_free(&result1);
691 				result1 = result2;
692 			}
693 			return result1;
694 		case '[':
695 			if (stage != NU_UNIT)
696 			{
697 				if (!(ptr2 = matching_bracket(ptr+1, '[', ']')))
698 					ptr = ptr+my_strlen(ptr)-1;
699 				else
700 					ptr = ptr2;
701 				break;
702 			}
703 			*ptr++ = '\0';
704 			right = ptr;
705 			ptr = matching_bracket(right, '[', ']');
706 			if (ptr)
707 				*ptr++ = '\0';
708 			result1 = expand_alias(NULL, right, args, arg_flag, NULL);
709 			if (*str)
710 			{
711 				malloc_snprintf(&result2, "%s.%s%s", str, result1,
712 						ptr ? CP(ptr) : "");
713 				new_free(&result1);
714 				if (ptr && *ptr)
715 				{
716 					result1 = next_unit(result2, args,
717 						arg_flag, stage);
718 				}
719 				else
720 				{
721 					result1 = find_inline(result2);
722 					if (!result1)
723 						malloc_strcpy(&result1,
724 							empty_string());
725 				}
726 				new_free(&result2);
727 			}
728 			else if (ptr && *ptr)
729 			{
730 				malloc_strcat(&result1, ptr);
731 				result2 = next_unit(result1, args, arg_flag,
732 					stage);
733 				new_free(&result1);
734 				result1 = result2;
735 			}
736 			return result1;
737 		case '-':
738 		case '+':
739 			if (*(ptr+1) == *(ptr))  /* index operator */
740 			{
741 				u_char *tptr;
742 				int r;
743 
744 				*ptr++ = '\0';
745 				if (ptr == str + 1)	/* Its a prefix */
746 					tptr = str + 2;
747 				else			/* Its a postfix */
748 					tptr = str;
749 			    	result1 = find_inline(tptr);
750 				if (!result1)
751 					malloc_strcpy(&result1, zero());
752 
753 				r = my_atoi(result1);
754 				if (*ptr == '+')
755 					r++;
756 				else
757 					r--;
758 				snprintf(CP(tmp), sizeof tmp, "%d", r);
759 				display = set_display_off();
760 				add_alias(VAR_ALIAS, tptr, tmp);
761 				set_display(display);
762 				/* A kludge?  Cheating?  Maybe.... */
763 				if (ptr == str + 1)
764 				{
765 					*(ptr-1) = ' ';
766 					*ptr = ' ';
767 				}
768 				else
769 				{
770 					if (*ptr == '+')
771 						*(ptr-1) = '-';
772 					else
773 						*(ptr-1) = '+';
774 					*ptr = '1';
775 				}
776 				ptr = str;
777 				new_free(&result1);
778 				break;
779 			}
780 			if (ptr == str) /* It's unary..... do nothing */
781 				break;
782 			if (stage != NU_ADD)
783 			{
784 				ptr = lastop(ptr);
785 				break;
786 			}
787 			op = *ptr;
788 			*ptr++ = '\0';
789 			result1 = next_unit(str, args, arg_flag, stage);
790 			result2 = next_unit(ptr, args, arg_flag, stage);
791 			value1 = my_atol(result1);
792 			value2 = my_atol(result2);
793 			new_free(&result1);
794 			new_free(&result2);
795 			if (op == '-')
796 				value3 = value1 - value2;
797 			else
798 				value3 = value1 + value2;
799 			snprintf(CP(tmp), sizeof tmp, "%ld", value3);
800 			malloc_strcpy(&result1, tmp);
801 			return result1;
802 		case '/':
803 		case '*':
804   		case '%':
805 			if (stage != NU_MULT)
806 			{
807 				ptr = lastop(ptr);
808 				break;
809 			}
810 			op = *ptr;
811 			*ptr++ = '\0';
812 			result1 = next_unit(str, args, arg_flag, stage);
813 			result2 = next_unit(ptr, args, arg_flag, stage);
814 			value1 = my_atol(result1);
815 			value2 = my_atol(result2);
816 			new_free(&result1);
817 			new_free(&result2);
818 			if (op == '/')
819 			{
820 				if (value2)
821 					value3 = value1 / value2;
822 				else
823 				{
824 					value3 = 0;
825 					say("Division by zero");
826 				}
827 			}
828 			else
829 			if (op == '*')
830 				value3 = value1 * value2;
831 			else
832 			{
833 				if (value2)
834 				    value3 = value1 % value2;
835 				else
836 				{
837 					value3 = 0;
838 					say("Mod by zero");
839 				}
840 			}
841 			snprintf(CP(tmp), sizeof tmp, "%ld", value3);
842 			malloc_strcpy(&result1, tmp);
843 			return result1;
844 		case '#':
845 			if (stage != NU_ADD || ptr[1] != '#')
846 			{
847 				ptr = lastop(ptr);
848 				break;
849 			}
850 			*ptr = '\0';
851 			ptr += 2;
852 			result1 = next_unit(str, args, arg_flag, stage);
853 			result2 = next_unit(ptr, args, arg_flag, stage);
854 			malloc_strcat(&result1, result2);
855 			new_free(&result2);
856 			return result1;
857 	/* Reworked - Jeremy Nelson, Feb 1994
858 	 * & or && should both be supported, each with different
859 	 * stages, same with || and ^^.  Also, they should be
860 	 * short-circuit as well.
861 	 */
862 		case '&':
863 			if (ptr[0] == ptr[1])
864 			{
865 				if (stage != NU_CONJ)
866 				{
867 					ptr = lastop(ptr);
868 					break;
869 				}
870 				*ptr = '\0';
871 				ptr += 2;
872 				result1 = next_unit(str, args, arg_flag, stage);
873 				value1 = my_atol(result1);
874 				if (value1)
875 				{
876 					result2 = next_unit(ptr, args, arg_flag, stage);
877 					value2 = my_atol(result2);
878 					value3 = value1 && value2;
879 				}
880 				else
881 					value3 = 0;
882 				new_free(&result1);
883 				new_free(&result2);
884 				tmp[0] = '0' + (value3?1:0);
885 				tmp[1] = '\0';
886 				malloc_strcpy(&result1, tmp);
887  				return result1;
888 			}
889 			else
890 			{
891 				if (stage != NU_BITW)
892 				{
893 					ptr = lastop(ptr);
894 					break;
895 				}
896 				*ptr = '\0';
897 				ptr += 1;
898 				result1 = next_unit(str, args, arg_flag, stage);
899 				result2 = next_unit(ptr, args, arg_flag, stage);
900 				value1 = my_atol(result1);
901 				value2 = my_atol(result2);
902 				new_free(&result1);
903 				new_free(&result2);
904 				value3 = value1 & value2;
905 				snprintf(CP(tmp), sizeof tmp, "%ld", value3);
906 				malloc_strcpy(&result1, tmp);
907  				return result1;
908 			}
909 		case '|':
910 			if (ptr[0] == ptr[1])
911 			{
912 				if (stage != NU_CONJ)
913 				{
914 					ptr = lastop(ptr);
915 					break;
916 				}
917 				*ptr = '\0';
918 				ptr += 2;
919 				result1 = next_unit(str, args, arg_flag, stage);
920 				value1 = my_atol(result1);
921 				if (!value1)
922 				{
923 					result2 = next_unit(ptr, args, arg_flag, stage);
924 					value2 = my_atol(result2);
925 					value3 = value1 | value2;
926 				}
927 				else
928 					value3 = 1;
929 				new_free(&result1);
930 				new_free(&result2);
931 				tmp[0] = '0' + (value3 ? 1 : 0);
932 				tmp[1] = '\0';
933 				malloc_strcpy(&result1, tmp);
934  				return result1;
935 			}
936 			else
937 			{
938 				if (stage != NU_BITW)
939 				{
940 					ptr = lastop(ptr);
941 					break;
942 				}
943 				*ptr = '\0';
944 				ptr += 1;
945 				result1 = next_unit(str, args, arg_flag, stage);
946 				result2 = next_unit(ptr, args, arg_flag, stage);
947 				value1 = my_atol(result1);
948 				value2 = my_atol(result2);
949 				new_free(&result1);
950 				new_free(&result2);
951 				value3 = value1 | value2;
952 				snprintf(CP(tmp), sizeof tmp, "%ld", value3);
953 				malloc_strcpy(&result1, tmp);
954  				return result1;
955 			}
956 		case '^':
957 			if (ptr[0] == ptr[1])
958 			{
959 				if (stage != NU_CONJ)
960 				{
961 					ptr = lastop(ptr);
962 					break;
963 				}
964 				*ptr = '\0';
965 				ptr += 2;
966 				result1 = next_unit(str, args, arg_flag, stage);
967 				result2 = next_unit(ptr, args, arg_flag, stage);
968 				value1 = my_atol(result1);
969 				value2 = my_atol(result2);
970 				value1 = value1?1:0;
971 				value2 = value2?1:0;
972 				value3 = value1 ^ value2;
973 				new_free(&result1);
974 				new_free(&result2);
975 				tmp[0] = '0' + (value3 ? 1 : 0);
976 				tmp[1] = '\0';
977 				malloc_strcpy(&result1, tmp);
978  				return result1;
979 			}
980 			else
981 			{
982 				if (stage != NU_BITW)
983 				{
984 					ptr = lastop(ptr);
985 					break;
986 				}
987 				*ptr = '\0';
988 				ptr += 1;
989 				result1 = next_unit(str, args, arg_flag, stage);
990 				result2 = next_unit(ptr, args, arg_flag, stage);
991 				value1 = my_atol(result1);
992 				value2 = my_atol(result2);
993 				new_free(&result1);
994 				new_free(&result2);
995 				value3 = value1 ^ value2;
996 				snprintf(CP(tmp), sizeof tmp, "%ld", value3);
997 				malloc_strcpy(&result1, tmp);
998  				return result1;
999 			}
1000 			case '?':
1001 			if (stage != NU_TERT)
1002 			{
1003 				ptr = lastop(ptr);
1004 				break;
1005 			}
1006 			*ptr++ = '\0';
1007 			result1 = next_unit(str, args, arg_flag, stage);
1008 			ptr2 = my_index(ptr, ':');
1009 			*ptr2++ = '\0';
1010 			right = result1;
1011 			value1 = parse_number(&right);
1012 			if (value1 == -1 && *right == '\0')
1013 				value1 = 0;
1014 			if (value1 == 0)
1015 				while (isspace(*right))
1016 					*(right++) = '\0';
1017 			if (value1 || *right)
1018 				result2 = next_unit(ptr, args, arg_flag, stage);
1019 			else
1020 				result2 = next_unit(ptr2, args, arg_flag, stage);
1021 			*(ptr2-1) = ':';
1022 			new_free(&result1);
1023 			return result2;
1024 		case '=':
1025 			if (ptr[1] != '=')
1026 			{
1027 				if (stage != NU_ASSN)
1028 				{
1029 					ptr = lastop(ptr);
1030 					break;
1031 				}
1032 				*ptr++ = '\0';
1033 				result1 = expand_alias(NULL, str,
1034 					args, arg_flag, NULL);
1035 				result2 = next_unit(ptr, args, arg_flag, stage);
1036 				display = set_display_off();
1037 				lastc = result1 + my_strlen(result1) - 1;
1038 				while (lastc > result1 && *lastc == ' ')
1039 					*lastc-- = '\0';
1040 				for (ptr = result1; *ptr == ' '; ptr++)
1041 					/* nothing */;
1042 				bracket_to_dot(ptr);
1043 				if (*ptr)
1044 					add_alias(VAR_ALIAS, ptr, result2);
1045 				else
1046 					yell("Invalid assignment expression");
1047 				set_display(display);
1048 				new_free(&result1);
1049 				return result2;
1050 			}
1051 			if (stage != NU_COMP)
1052 			{
1053 				ptr = lastop(ptr);
1054 				break;
1055 			}
1056 			*ptr = '\0';
1057 			ptr += 2;
1058 			result1 = next_unit(str, args, arg_flag, stage);
1059 			result2 = next_unit(ptr, args, arg_flag, stage);
1060 			if (!my_stricmp(result1, result2))
1061 				malloc_strcpy(&result1, one());
1062 			else
1063 				malloc_strcpy(&result1, zero());
1064 			new_free(&result2);
1065 			return result1;
1066 		case '>':
1067 		case '<':
1068 			if (stage != NU_COMP)
1069 			{
1070 				ptr = lastop(ptr);
1071 				break;
1072 			}
1073 			op = *ptr;
1074 			if (ptr[1] == '=')
1075 				value3 = 1, *ptr++ = '\0';
1076 			else
1077 				value3 = 0;
1078 			*ptr++ = '\0';
1079 			result1 = next_unit(str, args, arg_flag, stage);
1080 			result2 = next_unit(ptr, args, arg_flag, stage);
1081 			if (isdigit(*result1) && isdigit(*result2))
1082 			{
1083 				value1 = my_atol(result1);
1084 				value2 = my_atol(result2);
1085 				value1 = (value1 == value2) ? 0 : ((value1 <
1086 					value2) ? -1 : 1);
1087 			}
1088 			else
1089 				value1 = my_stricmp(result1, result2);
1090 			if (value1)
1091 			{
1092 				value2 = (value1 > 0) ? 1 : 0;
1093 				if (op == '<')
1094 					value2 = 1 - value2;
1095 			}
1096 			else
1097 				value2 = value3;
1098 			new_free(&result2);
1099 			snprintf(CP(tmp), sizeof tmp, "%ld", value2);
1100 			malloc_strcpy(&result1, tmp);
1101 			return result1;
1102 		case '~':
1103 			if (ptr == str)
1104 			{
1105 				if (stage != NU_BITW)
1106 					break;
1107 				result1 = next_unit(str+1, args, arg_flag,
1108 					stage);
1109 				if (isdigit(*result1))
1110 				{
1111 					value1 = my_atol(result1);
1112 					value2 = ~value1;
1113 				}
1114 				else
1115 					value2 = 0;
1116 				snprintf(CP(tmp), sizeof tmp, "%ld", value2);
1117 				malloc_strcpy(&result1, tmp);
1118 				return result1;
1119 			}
1120 			else
1121 			{
1122 				ptr = lastop(ptr);
1123 				break;
1124 			}
1125 		case '!':
1126 			if (ptr == str)
1127 			{
1128 				if (stage != NU_UNIT)
1129 					break;
1130 				result1 = next_unit(str+1, args, arg_flag,
1131 					stage);
1132 				if (isdigit(*result1))
1133 				{
1134 					value1 = my_atol(result1);
1135 					value2 = value1 ? 0 : 1;
1136 				}
1137 				else
1138 				{
1139 					value2 = ((*result1)?0:1);
1140 				}
1141 				snprintf(CP(tmp), sizeof tmp, "%ld", value2);
1142 				malloc_strcpy(&result1, tmp);
1143 				return result1;
1144 			}
1145 			if (stage != NU_COMP || ptr[1] != '=')
1146 			{
1147 				ptr = lastop(ptr);
1148 				break;
1149 			}
1150 			*ptr = '\0';
1151 			ptr += 2;
1152 			result1 = next_unit(str, args, arg_flag, stage);
1153 			result2 = next_unit(ptr, args, arg_flag, stage);
1154 			if (!my_stricmp(result1, result2))
1155 				malloc_strcpy(&result1, zero());
1156 			else
1157 				malloc_strcpy(&result1, one());
1158 			new_free(&result2);
1159 			return result1;
1160 			case ',':
1161 			/*
1162 			 * this utterly kludge code is needed (?) to get
1163 			 * around bugs introduced from hop's patches to
1164 			 * alias.c.  the $, variable stopped working
1165 			 * because of this.  -mrg, july 94.
1166 			 */
1167 			if (ptr == str || (ptr > str && ptr[-1] == '$'))
1168 				break;
1169 			if (stage != NU_EXPR)
1170 			{
1171 				ptr = lastop(ptr);
1172 				break;
1173 			}
1174 			*ptr++ = '\0';
1175 			result1 = next_unit(str, args, arg_flag, stage);
1176 			result2 = next_unit(ptr, args, arg_flag, stage);
1177 			new_free(&result1);
1178 			return result2;
1179 		}
1180 	}
1181 	if (stage != NU_UNIT)
1182 		return next_unit(str, args, arg_flag, stage+1);
1183 	if (isdigit(*str) || *str == '+' || *str == '-')
1184 		malloc_strcpy(&result1, str);
1185 	else
1186 	{
1187 		if (*str == '#' || *str=='@')
1188 			op = *str++;
1189 		else
1190 			op = '\0';
1191 		result1 = find_inline(str);
1192 		if (!result1)
1193 			malloc_strcpy(&result1, empty_string());
1194 		if (op)
1195 		{
1196 			if (op == '#')
1197 				value1 = word_count(result1);
1198 			else if (op == '@')
1199 				value1 = my_strlen(result1);
1200 			snprintf(CP(tmp), sizeof tmp, "%ld", value1);
1201 			malloc_strcpy(&result1, tmp);
1202 		}
1203 	}
1204 	return result1;
1205 }
1206 
1207 /*
1208  * parse_inline:  This evaluates user-variable expression.  I'll talk more
1209  * about this at some future date. The ^ function and some fixes by
1210  * troy@cbme.unsw.EDU.AU (Troy Rollo)
1211  */
1212 u_char	*
parse_inline(u_char * str,u_char * args,int * args_flag)1213 parse_inline(u_char *str, u_char *args, int *args_flag)
1214 {
1215 	return next_unit(str, args, args_flag, NU_EXPR);
1216 }
1217 
1218 /*
1219  * arg_number: Returns the argument 'num' from 'str', or, if 'num' is
1220  * negative, returns from argument 'num' to the end of 'str'.  You might be
1221  * wondering what's going on down there... here goes.  First we copy 'str' to
1222  * malloced space.  Then, using next_arg(), we strip out each argument ,
1223  * putting them in arg_list, and putting their position in the original
1224  * string in arg_list_pos.  Anyway, once parsing is done, the arguments are
1225  * returned directly from the arg_list array... or in the case of negative
1226  * 'num', the arg_list_pos is used to return the postion of the rest of the
1227  * args in the original string... got it?  Anyway, the bad points of the
1228  * routine:  1) Always parses out everything, even if only one arg is used.
1229  * 2) The malloced stuff remains around until arg_number is called with a
1230  * different string. Even then, some malloced stuff remains around.  This can
1231  * be fixed.
1232  */
1233 
1234 #define	LAST_ARG 8000
1235 
1236 static u_char *
arg_number(int lower_lim,int upper_lim,u_char * str)1237 arg_number(int lower_lim, int upper_lim, u_char *str)
1238 {
1239 	u_char	*ptr,
1240 		*arg,
1241 		c;
1242 	int	use_full = 0;
1243 	unsigned int	pos,
1244 		start_pos;
1245 	static	u_char	*last_args = NULL;
1246 	static	u_char	*last_range = NULL;
1247 	static	u_char	**arg_list = NULL;
1248 	static	unsigned int	*arg_list_pos = NULL;
1249 	static	unsigned int	*arg_list_end_pos = NULL;
1250 	static	int	arg_list_size;
1251 
1252 	if (eval_args)
1253 	{
1254 		int	arg_list_limit;
1255 
1256 		eval_args = 0;
1257 		new_free(&arg_list);
1258 		new_free(&arg_list_pos);
1259 		new_free(&arg_list_end_pos);
1260 		arg_list_size = 0;
1261 		arg_list_limit = 10;
1262 		arg_list = new_malloc(sizeof(*arg_list) * arg_list_limit);
1263 		arg_list_pos = new_malloc(sizeof(*arg_list_pos) * arg_list_limit);
1264 		arg_list_end_pos = new_malloc(sizeof(*arg_list_end_pos) * arg_list_limit);
1265 		malloc_strcpy(&last_args, str);
1266 		ptr = last_args;
1267 		pos = 0;
1268 		while ((arg = alias_arg(&ptr, &start_pos)) != NULL)
1269 		{
1270 			arg_list_pos[arg_list_size] = pos;
1271 			pos += start_pos + my_strlen(arg);
1272 			arg_list_end_pos[arg_list_size] = pos++;
1273 			arg_list[arg_list_size++] = arg;
1274 			if (arg_list_size == arg_list_limit)
1275 			{
1276 				arg_list_limit += 10;
1277 				arg_list = new_realloc(arg_list, sizeof(*arg_list) * arg_list_limit);
1278 				arg_list_pos = new_realloc(arg_list_pos, sizeof(*arg_list_pos) * arg_list_limit);
1279 				arg_list_end_pos = new_realloc(arg_list_end_pos, sizeof(*arg_list_end_pos) * arg_list_limit);
1280 			}
1281 		}
1282 	}
1283 	if (upper_lim == LAST_ARG && lower_lim == LAST_ARG)
1284 		upper_lim = lower_lim = arg_list_size - 1;
1285 	if (arg_list_size == 0)
1286 		return (empty_string());
1287 	if ((upper_lim >= arg_list_size) || (upper_lim < 0))
1288 	{
1289 		use_full = 1;
1290 		upper_lim = arg_list_size - 1;
1291 	}
1292 	if (upper_lim < lower_lim)
1293 		return (empty_string());
1294 	if (lower_lim >= arg_list_size)
1295 		lower_lim = arg_list_size - 1;
1296 	else if (lower_lim < 0)
1297 		lower_lim = 0;
1298 	if ((use_full == 0) && (lower_lim == upper_lim))
1299 		return (arg_list[lower_lim]);
1300 	c = *(str + arg_list_end_pos[upper_lim]);
1301 	*(str + arg_list_end_pos[upper_lim]) = '\0';
1302 	malloc_strcpy(&last_range, str + arg_list_pos[lower_lim]);
1303 	*(str + arg_list_end_pos[upper_lim]) = c;
1304 	return (last_range);
1305 }
1306 
1307 /*
1308  * parse_number: returns the next number found in a string and moves the
1309  * string pointer beyond that point	in the string.  Here's some examples:
1310  *
1311  * "123harhar"  returns 123 and str as "harhar"
1312  *
1313  * while:
1314  *
1315  * "hoohar"     returns -1  and str as "hoohar"
1316  */
1317 int
parse_number(u_char ** str)1318 parse_number(u_char **str)
1319 {
1320 	int	ret;
1321 	u_char	*ptr;
1322 
1323 	ptr = *str;
1324 	if (isdigit(*ptr))
1325 	{
1326 		ret = my_atoi(ptr);
1327 		for (; isdigit(*ptr); ptr++);
1328 		*str = ptr;
1329 	}
1330 	else
1331 		ret = -1;
1332 	return (ret);
1333 }
1334 
1335 /*
1336  * expander_addition: This handles string width formatting for irc variables
1337  * when [] is specified.
1338  */
1339 static	void
expander_addition(u_char ** buff,u_char * add,int length,u_char * quote_em)1340 expander_addition(u_char **buff, u_char *add, int length, u_char *quote_em)
1341 {
1342 	u_char	format[40],
1343 		*buffer = NULL,
1344 		*buffer2 = NULL;
1345 
1346 	if (length)
1347 	{
1348 		snprintf(CP(format), sizeof format, "%%%d.%ds", -length,
1349 			 length < 0 ? -length : length);
1350 		malloc_snprintf(&buffer, CP(format), add);
1351 		add = buffer;
1352 	}
1353 	if (quote_em)
1354 	{
1355 		buffer2 = double_quote(add, quote_em);
1356 		add = buffer2;
1357 	}
1358 
1359 	if (add && *add)
1360 		malloc_strcat(buff, add);
1361 
1362 	if (buffer)
1363 		new_free(&buffer);
1364 	if (buffer2)
1365 		new_free(&buffer2);
1366 }
1367 
1368 /* matching_bracket returns the next unescaped bracket of the given type */
1369 u_char	*
matching_bracket(u_char * string,int left,int right)1370 matching_bracket(u_char *string, int left, int right)
1371 {
1372 	int	bracket_count = 1;
1373 
1374 	while (*string && bracket_count)
1375 	{
1376 		if (*string == (u_char)left)
1377 			bracket_count++;
1378 		else if (*string == (u_char)right)
1379 		{
1380 			if (!--bracket_count)
1381 				return string;
1382 		}
1383 		else if (*string == '\\' && string[1])
1384 			string++;
1385 		string++;
1386 	}
1387 	return NULL;
1388 }
1389 
1390 
1391 /*
1392  * alias_special_char: Here we determin what to do with the character after
1393  * the $ in a line of text. The special characters are described more fulling
1394  * in the help/ALIAS file.  But they are all handled here. Paremeters are the
1395  * name of the alias (if applicable) to prevent deadly recursion, a
1396  * destination buffer (that we are malloc_str*ing) to which things are appended,
1397  * a ptr to the string (the first character of which is the special
1398  * character, the args to the alias, and a character indication what
1399  * characters in the string should be quoted with a backslash).  It returns a
1400  * pointer to the character right after the converted alias.
1401  *
1402  * The args_flag is set to 1 if any of the $n, $n-, $n-m, $-m, $*, or $()
1403  * is used in the alias.  Otherwise it is left unchanged.
1404  */
1405 static	u_char	*
alias_special_char(u_char * name,u_char ** lbuf,u_char * ptr,u_char * args,u_char * quote_em,int * args_flag)1406 alias_special_char(u_char *name, u_char **lbuf, u_char *ptr, u_char *args, u_char *quote_em, int *args_flag)
1407 {
1408 	u_char	*tmp,
1409 		c;
1410 	int	is_upper,
1411 		is_lower,
1412 		length;
1413 
1414 	length = 0;
1415 	if ((c = *ptr) == '[')
1416 	{
1417 		ptr++;
1418 		if ((tmp = my_index(ptr, ']')) != NULL)
1419 		{
1420 			*(tmp++) = '\0';
1421 			length = my_atoi(ptr);
1422 			ptr = tmp;
1423 			c = *ptr;
1424 		}
1425 		else
1426 		{
1427 			say("Missing %c", ']');
1428 			return (ptr);
1429 		}
1430 	}
1431 	tmp = ptr+1;
1432 	switch (c)
1433 	{
1434 	case '(':
1435 		{
1436 			u_char	*sub_buffer = NULL;
1437 
1438 			if ((ptr = matching_bracket(tmp, '(', ')')) ||
1439 			    (ptr = my_index(tmp, ')')))
1440 				*(ptr++) = '\0';
1441 			tmp = expand_alias(NULL, tmp, args, args_flag,
1442 				NULL);
1443 			malloc_strcpy(&sub_buffer, empty_string());
1444 			alias_special_char(NULL, &sub_buffer, tmp,
1445 				args, quote_em, args_flag);
1446 			expander_addition(lbuf, sub_buffer, length, quote_em);
1447 			new_free(&sub_buffer);
1448 			new_free(&tmp);
1449 			*args_flag = 1;
1450 		}
1451 		return (ptr);
1452 	case '!':
1453 		if ((ptr = my_index(tmp, '!')) != NULL)
1454 			*(ptr++) = '\0';
1455 		if ((tmp = do_history(tmp, empty_string())) != NULL)
1456 		{
1457 			expander_addition(lbuf, tmp, length, quote_em);
1458 			new_free(&tmp);
1459 		}
1460 		return (ptr);
1461 	case '{':
1462 		if ((ptr = my_index(tmp, '}')) != NULL)
1463 			*(ptr++) = '\0';
1464 		if ((tmp = parse_inline(tmp, args, args_flag)) != NULL)
1465 		{
1466 			expander_addition(lbuf, tmp, length, quote_em);
1467 			new_free(&tmp);
1468 		}
1469 		return (ptr);
1470 	case '*':
1471 		expander_addition(lbuf, args, length, quote_em);
1472 		*args_flag = 1;
1473 		return (ptr + 1);
1474 	default:
1475 		if (isdigit(c) || (c == '-') || c == '~')
1476 		{
1477 			*args_flag = 1;
1478 			if (*ptr == '~')
1479 			{
1480 				is_lower = is_upper = LAST_ARG;
1481 				ptr++;
1482 			}
1483 			else
1484 			{
1485 				is_lower = parse_number(&ptr);
1486 				if (*ptr == '-')
1487 				{
1488 					ptr++;
1489 					is_upper = parse_number(&ptr);
1490 				}
1491 				else
1492 					is_upper = is_lower;
1493 			}
1494 			expander_addition(lbuf, arg_number(is_lower, is_upper,
1495 				args), length, quote_em);
1496 			return (ptr ? ptr : empty_string());
1497 		}
1498 		else
1499 		{
1500 			u_char	*rest,
1501 				c2 = '\0';
1502 
1503 		/*
1504 		 * Why use ptr+1?  Cause try to maintain backward compatability
1505 		 * can be a pain in the butt.  Basically, we don't want any of
1506 		 * the illegal characters in the alias, except that things like
1507 		 * $* and $, were around first, so they must remain legal.  So
1508 		 * we skip the first char after the $.  Does this make sense?
1509 		 */
1510 			/* special case for $ */
1511 			if (*ptr == '$')
1512 			{
1513 				rest = ptr+1;
1514 				c2 = *rest;
1515 				*rest = '\0';
1516 			}
1517 			else if ((rest = sindex(ptr+1, alias_illegals)) != NULL)
1518 			{
1519 				if (isalpha(*ptr) || *ptr == '_')
1520 					while ((*rest == '[' ||
1521 					    *rest == '(') &&
1522 					    (tmp = matching_bracket(rest+1,
1523 					    (int)*rest, (int)(*rest == '[') ?
1524 					    ']' : ')')))
1525 						rest = tmp + 1;
1526 				c2 = *rest;
1527 				*rest = '\0';
1528 			}
1529 			if ((tmp = parse_inline(ptr, args, args_flag)) != NULL)
1530 			{
1531 				expander_addition(lbuf, tmp, length,
1532 					quote_em);
1533 				new_free(&tmp);
1534 			}
1535 			if (rest)
1536 				*rest = c2;
1537 			return(rest);
1538 		}
1539 	}
1540 	return NULL;
1541 }
1542 
1543 
1544 /*
1545  * expand_alias: Expands inline variables in the given string and returns the
1546  * expanded string in a new string which is malloced by expand_alias().
1547  *
1548  * Also unescapes anything that was quoted with a backslash
1549  *
1550  * Behaviour is modified by the following:
1551  *	Anything between brackets (...) {...} is left unmodified.
1552  *	If more_text is supplied, the text is broken up at
1553  *		semi-colons and returned one at a time. The unprocessed
1554  *		portion is written back into more_text.
1555  *	Backslash escapes are unescaped.
1556  */
1557 
1558 u_char	*
expand_alias(u_char * name,u_char * string,u_char * args,int * args_flag,u_char ** more_text)1559 expand_alias(u_char *name, u_char *string, u_char *args, int *args_flag, u_char **more_text)
1560 {
1561 	u_char	*lbuf = NULL,
1562 		*ptr,
1563 		*stuff = NULL,
1564 		*free_stuff;
1565 	u_char	*quote_em,
1566 		*quote_str = NULL;
1567 	u_char	ch;
1568 	int	quote_cnt = 0;
1569 	int	is_quote = 0;
1570 	void	(*str_cat)(u_char **, u_char *);
1571 
1572 	if (*string == '@' && more_text)
1573 	{
1574 		str_cat = malloc_strcat;
1575 		*args_flag = 1; /* Stop the @ command from auto appending */
1576 	}
1577 	else
1578 		str_cat = malloc_strcat_ue;
1579 	malloc_strcpy(&stuff, string);
1580 	free_stuff = stuff;
1581 	malloc_strcpy(&lbuf, empty_string());
1582 	eval_args = 1;
1583 	ptr = stuff;
1584 	if (more_text)
1585 		*more_text = NULL;
1586 	while (ptr && *ptr)
1587 	{
1588 		if (is_quote)
1589 		{
1590 			is_quote = 0;
1591 			++ptr;
1592 			continue;
1593 		}
1594 		switch(*ptr)
1595 		{
1596 		case '$':
1597 	/*
1598 	 * The test here ensures that if we are in the expression
1599 	 * evaluation command, we don't expand $. In this case we
1600 	 * are only coming here to do command separation at ';'s.
1601 	 * If more_text is not defined, and the first character is
1602 	 * '@', we have come here from [] in an expression.
1603 	 */
1604 			if (more_text && *string == '@')
1605 			{
1606 				ptr++;
1607 				break;
1608 			}
1609 			*(ptr++) = '\0';
1610 			(*str_cat)(&lbuf, stuff);
1611 			while (*ptr == '^')
1612 			{
1613 				ptr++;
1614 				if (quote_str)
1615 					quote_str = new_realloc(quote_str,
1616 						sizeof(*quote_str) *
1617 						(quote_cnt + 2));
1618 				else
1619 					quote_str = new_malloc(sizeof(*quote_str) *
1620 						(quote_cnt + 2));
1621 				quote_str[quote_cnt++] = *(ptr++);
1622 				quote_str[quote_cnt] = '\0';
1623 			}
1624 			quote_em = quote_str;
1625 			stuff = alias_special_char(name, &lbuf, ptr, args,
1626 				quote_em, args_flag);
1627 			if (stuff)
1628 				new_free(&quote_str);
1629 			quote_cnt = 0;
1630 			ptr = stuff;
1631 			break;
1632 		case ';':
1633 			if (!more_text)
1634 			{
1635 				ptr++;
1636 				break;
1637 			}
1638 			*more_text = string + (ptr - free_stuff) +1;
1639 			*ptr = '\0'; /* To terminate the loop */
1640 			break;
1641 		case '(':
1642 		case '{':
1643 			ch = *ptr;
1644 			*ptr = '\0';
1645 			(*str_cat)(&lbuf, stuff);
1646 			stuff = ptr;
1647 			*args_flag = 1;
1648 			if (!(ptr = matching_bracket(stuff + 1, (int)ch,
1649 					(int)(ch == '(') ?
1650 					')' : '}')))
1651 			{
1652 				yell("Unmatched %c", ch);
1653 				ptr = stuff + my_strlen(stuff+1)+1;
1654 			}
1655 			else
1656 				ptr++;
1657 			*stuff = ch;
1658 			ch = *ptr;
1659 			*ptr = '\0';
1660 			malloc_strcat(&lbuf, stuff);
1661 			stuff = ptr;
1662 			*ptr = ch;
1663 			break;
1664 		case '\\':
1665 			is_quote = 1;
1666 			ptr++;
1667 			break;
1668 		default:
1669 			ptr++;
1670 			break;
1671 		}
1672 	}
1673 	if (stuff)
1674 		(*str_cat)(&lbuf, stuff);
1675 	ptr = NULL;
1676 	new_free(&free_stuff);
1677 	ptr = lbuf;
1678 	if (get_int_var(DEBUG_VAR) & DEBUG_EXPANSIONS)
1679 		yell("Expanded [%s] to [%s]",
1680 			string, ptr);
1681 	return (ptr);
1682 }
1683 
1684 /*
1685  * get_alias: returns the alias matching 'name' as the function value. 'args'
1686  * are expanded as needed, etc.  If no matching alias is found, null is
1687  * returned, cnt is 0, and full_name is null.  If one matching alias is
1688  * found, it is retuned, with cnt set to 1 and full_name set to the full name
1689  * of the alias.  If more than 1 match are found, null is returned, cnt is
1690  * set to the number of matches, and fullname is null. NOTE: get_alias()
1691  * mallocs the space for the full_name, but returns the actual value of the
1692  * alias if found!
1693  */
1694 u_char	*
get_alias(int type,u_char * name,int * cnt,u_char ** full_name)1695 get_alias(int type, u_char *name, int *cnt, u_char **full_name)
1696 {
1697 	Alias	*tmp;
1698 
1699 	*full_name = NULL;
1700 	if ((name == NULL) || (*name == '\0'))
1701 	{
1702 		*cnt = 0;
1703 		return (NULL);
1704 	}
1705 	if ((tmp = find_alias(&(alias_list[type]), name, 0, cnt)) != NULL)
1706 	{
1707 		if (*cnt < 2)
1708 		{
1709 			malloc_strcpy(full_name, tmp->name);
1710 			return (tmp->stuff);
1711 		}
1712 	}
1713 	return (NULL);
1714 }
1715 
1716 /*
1717  * match_alias: this returns a list of alias names that match the given name.
1718  * This is used for command completion etc.  Note that the returned array is
1719  * malloced in this routine.  Use free_alias() to free.  Returns null if no
1720  * matches are found.
1721  */
1722 u_char	**
match_alias(u_char * name,int * cnt,int type)1723 match_alias(u_char *name, int *cnt, int type)
1724 {
1725 	Alias	*tmp;
1726 	u_char	**matches = NULL;
1727 	int	matches_size = 5;
1728 	size_t	len;
1729 	u_char	*last_match = NULL;
1730 	u_char	*dot;
1731 
1732 	len = my_strlen(name);
1733 	*cnt = 0;
1734 	matches = new_malloc(sizeof(*matches) * matches_size);
1735 	for (tmp = alias_list[type]; tmp; tmp = tmp->next)
1736 	{
1737 		if (my_strncmp(name, tmp->name, len) == 0)
1738 		{
1739 			if ((dot = my_index(tmp->name+len, '.')) != NULL)
1740 			{
1741 				if (type == COMMAND_ALIAS)
1742 					continue;
1743 				else
1744 				{
1745 					*dot = '\0';
1746 					if (last_match && !my_strcmp(last_match,
1747 							tmp->name))
1748 					{
1749 						*dot = '.';
1750 						continue;
1751 					}
1752 				}
1753 			}
1754 			matches[*cnt] = NULL;
1755 			malloc_strcpy(&(matches[*cnt]), tmp->name);
1756 			last_match = matches[*cnt];
1757 			if (dot)
1758 				*dot = '.';
1759 			if (++(*cnt) == matches_size)
1760 			{
1761 				matches_size += 5;
1762 				matches = new_realloc(matches, sizeof(*matches) * matches_size);
1763 			}
1764 		}
1765 		else if (*cnt)
1766 			break;
1767 	}
1768 	if (*cnt)
1769 	{
1770 		matches = new_realloc(matches, sizeof(*matches) * (*cnt + 1));
1771 		matches[*cnt] = NULL;
1772 	}
1773 	else
1774 		new_free(&matches);
1775 	return (matches);
1776 }
1777 
1778 void
free_alias(u_char ** aliases,int cnt)1779 free_alias(u_char **aliases, int cnt)
1780 {
1781 	for (; cnt--; )
1782 		new_free(&aliases[cnt]);
1783 	new_free(&aliases);
1784 }
1785 
1786 /* delete_alias: The alias name is removed from the alias list. */
1787 void
delete_alias(int type,u_char * name)1788 delete_alias(int type, u_char *name)
1789 {
1790 	Alias	*tmp;
1791 
1792 	upper(name);
1793 	if ((tmp = find_alias(&(alias_list[type]), name, 1, (int *) NULL))
1794 			!= NULL)
1795 	{
1796 		new_free(&(tmp->name));
1797 		new_free(&(tmp->stuff));
1798 		new_free(&tmp);
1799 		if (type == COMMAND_ALIAS)
1800 			say("Alias	%s removed", name);
1801 		else
1802 			say("Assign %s removed", name);
1803 	}
1804 	else
1805 		say("No such alias: %s", name);
1806 }
1807 
1808 /*
1809  * list_aliases: Lists all aliases matching 'name'.  If name is null, all
1810  * aliases are listed
1811  */
1812 void
list_aliases(int type,u_char * name)1813 list_aliases(int type, u_char *name)
1814 {
1815 	Alias	*tmp;
1816 	size_t	len;
1817 	int	lastlog_level;
1818 	size_t	DotLoc,
1819 		LastDotLoc = 0;
1820 	u_char	*LastStructName = NULL;
1821 	u_char	*s;
1822 
1823 	lastlog_level = message_from_level(LOG_CRAP);
1824 	if (type == COMMAND_ALIAS)
1825 		say("Aliases:");
1826 	else
1827 		say("Assigns:");
1828 	if (name)
1829 	{
1830 		upper(name);
1831 		len = my_strlen(name);
1832 	}
1833 	else
1834 		len = 0;
1835 	for (tmp = alias_list[type]; tmp; tmp = tmp->next)
1836 	{
1837 		if (!name || !my_strncmp(tmp->name, name, len))
1838 		{
1839 			s = my_index(tmp->name + len, '.');
1840 			if (!s)
1841 				say("\t%s\t%s", tmp->name, tmp->stuff);
1842 			else
1843 			{
1844 				DotLoc = s - tmp->name;
1845 				if (!LastStructName || (DotLoc != LastDotLoc) || my_strncmp(tmp->name, LastStructName, DotLoc))
1846 				{
1847 					say("\t%*.*s\t<Structure>", (int)DotLoc, (int)DotLoc, tmp->name);
1848 					LastStructName = tmp->name;
1849 					LastDotLoc = DotLoc;
1850 				}
1851 			}
1852 		}
1853 	}
1854 	(void)message_from_level(lastlog_level);
1855 }
1856 
1857 /*
1858  * mark_alias: sets the mark field of the given alias to 'flag', and returns
1859  * the previous value of the mark.  If the name is not found, -1 is returned.
1860  * This is used to prevent recursive aliases by marking and unmarking
1861  * aliases, and not reusing an alias that has previously been marked.  I'll
1862  * explain later
1863  */
1864 int
mark_alias(u_char * name,int flag)1865 mark_alias(u_char *name, int flag)
1866 {
1867 	int	old_mark;
1868 	Alias	*tmp;
1869 	int	match;
1870 
1871 	if ((tmp = find_alias(&(alias_list[COMMAND_ALIAS]), name, 0, &match))
1872 			!= NULL)
1873 	{
1874 		if (match < 2)
1875 		{
1876 			old_mark = tmp->mark;
1877 		/* New handling of recursion */
1878 			if (flag)
1879 			{
1880 				int	i;
1881 				/* Count recursion */
1882 
1883 				tmp->mark = tmp->mark + flag;
1884 				if ((i = get_int_var(MAX_RECURSIONS_VAR)) > 1)
1885 				{
1886 					if (tmp->mark > i)
1887 					{
1888 						tmp->mark = 0;
1889 						return(1); /* MAX exceeded. */
1890 					}
1891 					else return(0);
1892 				/* In recursion but it's ok */
1893 				}
1894 				else
1895 				{
1896 					if (tmp->mark > 1)
1897 					{
1898 						tmp->mark = 0;
1899 						return(1);
1900 				/* max of 1 here.. exceeded */
1901 					}
1902 					else return(0);
1903 				/* In recursion but it's ok */
1904 				}
1905 			}
1906 			else
1907 		/* Not in recursion at all */
1908 			{
1909 				tmp->mark = 0;
1910 				return(old_mark);
1911 			/* This one gets ignored anyway */
1912 			}
1913 		}
1914 	}
1915 	return (-1);
1916 }
1917 
1918 /*
1919  * execute_alias: After an alias has been identified and expanded, it is sent
1920  * here for proper execution.  This routine mainly prevents recursive
1921  * aliasing.  The name is the full name of the alias, and the alias is
1922  * already expanded alias (both of these parameters are returned by
1923  * get_alias())
1924  */
1925 void
execute_alias(u_char * alias_name,u_char * ealias,u_char * args)1926 execute_alias(u_char *alias_name, u_char *ealias, u_char *args)
1927 {
1928 	if (mark_alias(alias_name, 1))
1929 		say("Maximum recursion count exceeded in: %s", alias_name);
1930 	else
1931 	{
1932 		parse_line(alias_name, ealias, args, 0, 1, 0);
1933 		mark_alias(alias_name, 0);
1934 	}
1935 }
1936 
1937 /*
1938  * save_aliases: This will write all of the aliases to the FILE pointer fp in
1939  * such a way that they can be read back in using LOAD or the -l switch
1940  */
1941 void
save_aliases(FILE * fp,int do_all)1942 save_aliases(FILE *fp, int do_all)
1943 {
1944 	Alias	*tmp;
1945 
1946 	for (tmp = alias_list[VAR_ALIAS]; tmp; tmp = tmp->next)
1947 		if (!tmp->global || do_all)
1948 			fprintf(fp, "ASSIGN %s %s\n", tmp->name, tmp->stuff);
1949 	for (tmp = alias_list[COMMAND_ALIAS]; tmp; tmp = tmp->next)
1950 		if (!tmp->global || do_all)
1951 			fprintf(fp, "ALIAS %s %s\n", tmp->name, tmp->stuff);
1952 }
1953 
1954 /* The Built-In Alias expando functions */
1955 static	u_char	*
alias_line(void)1956 alias_line(void)
1957 {
1958 	return (get_input());
1959 }
1960 
1961 static	u_char	*
alias_time(void)1962 alias_time(void)
1963 {
1964 	static u_char timestr[16];
1965 	struct tm *tm;
1966 	time_t	t;
1967 
1968 	t = time(0);
1969 	tm = localtime(&t);
1970 
1971 	return format_clock(timestr, 16, tm->tm_hour, tm->tm_min);
1972 }
1973 
1974 static	u_char	*
alias_dollar(void)1975 alias_dollar(void)
1976 {
1977 	return UP("$");
1978 }
1979 
1980 static	u_char	*
alias_detected(void)1981 alias_detected(void)
1982 {
1983 	return get_last_notify_nick();
1984 }
1985 
1986 static	u_char	*
alias_nick(void)1987 alias_nick(void)
1988 {
1989 	const	int	from_server = get_from_server();
1990 
1991 	return from_server >= 0 ? server_get_nickname(from_server) : my_nickname();
1992 }
1993 
1994 static	u_char	*
alias_away(void)1995 alias_away(void)
1996 {
1997 	const	int	from_server = get_from_server();
1998 
1999 	return from_server >= 0 ? server_get_away(from_server) : empty_string();
2000 }
2001 
2002 static	u_char	*
alias_sent_nick(void)2003 alias_sent_nick(void)
2004 {
2005 	u_char *sent_nick = get_sent_nick();
2006 
2007 	return sent_nick ? sent_nick : empty_string();
2008 }
2009 
2010 static	u_char	*
alias_recv_nick(void)2011 alias_recv_nick(void)
2012 {
2013 	u_char *recv_nick = get_recv_nick();
2014 
2015 	return recv_nick ? recv_nick : empty_string();
2016 }
2017 
2018 static	u_char	*
alias_msg_body(void)2019 alias_msg_body(void)
2020 {
2021 	u_char *sent_body = get_sent_body();
2022 
2023 	return sent_body ? sent_body : empty_string();
2024 }
2025 
2026 static	u_char	*
alias_joined_nick(void)2027 alias_joined_nick(void)
2028 {
2029 	u_char *joined_nick = get_joined_nick();
2030 
2031 	return joined_nick ? joined_nick : empty_string();
2032 }
2033 
2034 static	u_char	*
alias_public_nick(void)2035 alias_public_nick(void)
2036 {
2037 	u_char *public_nick = get_public_nick();
2038 
2039 	return public_nick ? public_nick : empty_string();
2040 }
2041 
2042 static	u_char	*
alias_channel(void)2043 alias_channel(void)
2044 {
2045 	u_char	*tmp;
2046 
2047 	return (tmp = get_channel_by_refnum(0)) ? tmp : zero();
2048 }
2049 
2050 static	u_char	*
alias_server(void)2051 alias_server(void)
2052 {
2053 	u_char	*tmp;
2054 
2055 	if (parsing_server() != -1)
2056 		tmp = server_get_itsname(parsing_server());
2057 	else if (get_window_server(0) != -1)
2058 		tmp = server_get_itsname(get_window_server(0));
2059 	else
2060 		tmp = empty_string();
2061 	return tmp;
2062 }
2063 
2064 static	u_char	*
alias_query_nick(void)2065 alias_query_nick(void)
2066 {
2067 	u_char	*tmp;
2068 
2069 	return (tmp = query_nick()) ? tmp : empty_string();
2070 }
2071 
2072 static	u_char	*
alias_target(void)2073 alias_target(void)
2074 {
2075 	u_char	*tmp;
2076 
2077 	return (tmp = get_target_by_refnum(0)) ? tmp : empty_string();
2078 }
2079 
2080 static	u_char	*
alias_invite(void)2081 alias_invite(void)
2082 {
2083 	u_char	*invite_channel = get_invite_channel();
2084 
2085 	return invite_channel ? invite_channel : empty_string();
2086 }
2087 
2088 static	u_char	*
alias_cmdchar(void)2089 alias_cmdchar(void)
2090 {
2091 	static	u_char	thing[2];
2092 	u_char	*cmdchars;
2093 
2094 	if ((cmdchars = get_string_var(CMDCHARS_VAR)) == NULL)
2095 		cmdchars = UP(DEFAULT_CMDCHARS);
2096 	thing[0] = cmdchars[0];
2097 	thing[1] = '\0';
2098 	return (thing);
2099 }
2100 
2101 static	u_char	*
alias_oper(void)2102 alias_oper(void)
2103 {
2104 	const	int	from_server = get_from_server();
2105 
2106 	return (from_server >= 0 && server_get_operator(from_server)) ?
2107 	       get_string_var(STATUS_OPER_VAR) : empty_string();
2108 }
2109 
2110 static	u_char	*
alias_chanop(void)2111 alias_chanop(void)
2112 {
2113 	u_char	*tmp;
2114 	const	int	from_server = get_from_server();
2115 
2116 	return (from_server >= 0 &&
2117 		(tmp = get_channel_by_refnum(0)) &&
2118 		get_channel_oper(tmp, from_server)) ?
2119 	       UP("@") : empty_string();
2120 }
2121 
2122 static	u_char	*
alias_modes(void)2123 alias_modes(void)
2124 {
2125 	u_char	*tmp;
2126 	const	int	from_server = get_from_server();
2127 
2128 	return (from_server >= 0 &&
2129 		(tmp = get_channel_by_refnum(from_server))) ?
2130 	       get_channel_mode(tmp, from_server) : empty_string();
2131 }
2132 
2133 static	u_char	*
alias_version(void)2134 alias_version(void)
2135 {
2136 	return irc_version();
2137 }
2138 
2139 static	u_char	*
alias_currdir(void)2140 alias_currdir(void)
2141 {
2142 	static	u_char	dirbuf[1024];
2143 
2144 	if (getcwd(CP(dirbuf), 1024) == NULL)
2145 	{
2146 		dirbuf[0] = '.';
2147 		dirbuf[1] = '\0';
2148 	}
2149 	return (dirbuf);
2150 }
2151 
2152 static	u_char	*
alias_current_numeric(void)2153 alias_current_numeric(void)
2154 {
2155 	static	u_char	number[12];
2156 
2157 	snprintf(CP(number), sizeof number, "%03d", -current_numeric());
2158 	return (number);
2159 }
2160 
2161 static	u_char	*
alias_server_version(void)2162 alias_server_version(void)
2163 {
2164 	u_char	*s;
2165 	const	int	from_server = get_from_server();
2166 
2167 	return from_server >= 0 && (s = server_get_version_string(from_server)) ?
2168 		s : empty_string();
2169 }
2170 
2171 /*
2172  * alias: the /ALIAS command.  Calls the correct alias function depending on
2173  * the args
2174  */
2175 void
alias(u_char * command,u_char * args,u_char * subargs)2176 alias(u_char *command, u_char *args, u_char *subargs)
2177 {
2178 	u_char	*name,
2179 		*rest;
2180 	int	type;
2181 
2182 	type = *command - 48;	/*
2183 				 * A trick!  Yes, well, what the hell.  Note
2184 				 * the the command part of ALIAS is "0" and
2185 				 * the command part of ASSIGN is "1" in the
2186 				 * command array list
2187 				 */
2188 	if ((name = next_arg(args, &rest)) != NULL)
2189 	{
2190 		bracket_to_dot(name);
2191 		if (*rest)
2192 		{
2193 			if (*rest == '{')
2194 			{
2195 				u_char	*right_brace;
2196 
2197 				right_brace = matching_bracket(++rest, '{', '}');
2198 				if (!right_brace)
2199 				    say("Unmatched brace in ALIAS or ASSIGN");
2200 				else if (right_brace[1])
2201 				{
2202 					say("Junk after closing brace in ALIAS or ASSIGN");
2203 				}
2204 				else
2205 				{
2206 					*right_brace = '\0';
2207 					add_alias(type, name, rest);
2208 				}
2209 			}
2210 			else
2211 				add_alias(type, name, rest);
2212 		}
2213 		else
2214 		{
2215 			if (*name == '-')
2216 			{
2217 				if (*(name + 1))
2218 					delete_alias(type, name + 1);
2219 				else
2220 					say("You must specify an alias to be removed");
2221 			}
2222 			else
2223 				list_aliases(type, name);
2224 		}
2225 	}
2226 	else
2227 		list_aliases(type, NULL);
2228 }
2229 
2230 static u_char	*
function_left(u_char * input)2231 function_left(u_char *input)
2232 {
2233 	u_char	*result = NULL;
2234 	u_char	*count;
2235 	int	cvalue;
2236 
2237 	count = next_arg(input, &input);
2238 	if (count)
2239 		cvalue = my_atoi(count);
2240 	else
2241 		cvalue = 0;
2242 	if ((int) my_strlen(input) > cvalue)
2243 		input[cvalue] = '\0';
2244 	malloc_strcpy(&result, input);
2245 	return (result);
2246 }
2247 
2248 static u_char	*
function_right(u_char * input)2249 function_right(u_char *input)
2250 {
2251 	u_char	*result = NULL;
2252 	u_char	*count;
2253 	int	cvalue;
2254 	int	len;
2255 
2256 	count = next_arg(input, &input);
2257 	if (count)
2258 		cvalue = my_atoi(count);
2259 	else
2260 		cvalue = 0;
2261 	if ((len = (int) my_strlen(input)) > cvalue)
2262 		input += len - cvalue;
2263 	malloc_strcpy(&result, input);
2264 	return (result);
2265 }
2266 
2267 static u_char	*
function_mid(u_char * input)2268 function_mid(u_char *input)
2269 {
2270 	u_char	*result = NULL;
2271 	u_char	*mid_index;
2272 	int	ivalue;
2273 	u_char	*count;
2274 	int	cvalue;
2275 
2276 	mid_index = next_arg(input, &input);
2277 	if (mid_index)
2278 		ivalue = my_atoi(mid_index);
2279 	else
2280 		ivalue = 0;
2281 	count = next_arg(input, &input);
2282 	if (count)
2283 		cvalue = my_atoi(count);
2284 	else
2285 		cvalue = 0;
2286 	if (ivalue >= 0 && (int) my_strlen(input) > ivalue)
2287 		input += ivalue;
2288 	else
2289 		*input = '\0';
2290 	if (cvalue > 0 && (int) my_strlen(input) > cvalue)
2291 		input[cvalue] = '\0';
2292 	malloc_strcpy(&result, input);
2293 	return (result);
2294 }
2295 
2296 /* patch from Sarayan to make $rand() better */
2297 
2298 #define RAND_A 16807L
2299 #define RAND_M 2147483647L
2300 #define RAND_Q 127773L
2301 #define RAND_R 2836L
2302 
2303 static	long
randm(long l)2304 randm(long l)
2305 {
2306 	static	u_long	z = 0;
2307 	long	t;
2308 
2309 	if (!z)
2310 		z = (u_long) getuid();
2311 	if (!l)
2312 	{
2313 		t = RAND_A * (z % RAND_Q) - RAND_R * (z / RAND_Q);
2314 		if (t > 0)
2315 			z = t;
2316 		else
2317 			z = t + RAND_M;
2318 		return (z >> 8) | ((z & 255) << 23);
2319 	}
2320 	else
2321 	{
2322 		if (l < 0)
2323 			z = (u_long) getuid();
2324 		else
2325 			z = l;
2326 		return 0;
2327 	}
2328 }
2329 
2330 static u_char	*
function_rand(u_char * input)2331 function_rand(u_char *input)
2332 {
2333 	u_char	*result = NULL;
2334 	u_char	tmp[40];
2335 	long	tempin;
2336 
2337 	snprintf(CP(tmp), sizeof tmp, "%ld", (tempin = my_atol(input)) ? randm(0L) % tempin : 0);
2338 	malloc_strcpy(&result, tmp);
2339 	return (result);
2340 }
2341 
2342 static u_char	*
function_srand(u_char * input)2343 function_srand(u_char *input)
2344 {
2345 	u_char	*result = NULL;
2346 
2347 	if (input && *input)
2348 		(void) randm(my_atol(input));
2349 	else
2350 		(void) randm((long) time(NULL));
2351 	malloc_strcpy(&result, empty_string());
2352 	return (result);
2353 }
2354 
2355 static u_char	*
function_time(u_char * input)2356 function_time(u_char *input)
2357 {
2358 	u_char	*result = NULL;
2359 	time_t	ltime;
2360 	u_char	tmp[40];
2361 
2362 	(void) time(&ltime);
2363 	snprintf(CP(tmp), sizeof tmp, "%ld", (long)ltime);
2364 	malloc_strcpy(&result, tmp);
2365 	return (result);
2366 }
2367 
2368 static u_char	*
function_stime(u_char * input)2369 function_stime(u_char *input)
2370 {
2371 	u_char	*result = NULL;
2372 	time_t	ltime;
2373 
2374 	ltime = my_atol(input);
2375 	malloc_strcpy(&result, UP(ctime(&ltime)));
2376 	result[my_strlen(result) - 1] = '\0';
2377 	return (result);
2378 }
2379 
2380 static u_char	*
function_tdiff(u_char * input)2381 function_tdiff(u_char *input)
2382 {
2383 	u_char	*result = NULL;
2384 	time_t	ltime;
2385 	time_t	days,
2386 		hours,
2387 		minutes,
2388 		seconds;
2389 	u_char	tmp[80];
2390 	u_char	*tstr;
2391 
2392 	ltime = my_atol(input);
2393 	seconds = ltime % 60;
2394 	ltime = (ltime - seconds) / 60;
2395 	minutes = ltime%60;
2396 	ltime = (ltime - minutes) / 60;
2397 	hours = ltime % 24;
2398 	days = (ltime - hours) / 24;
2399 	tstr = tmp;
2400 	if (days)
2401 	{
2402 		snprintf(CP(tstr), sizeof(tmp) - (tstr - tmp), "%ld day%s ", (long) days, (days==1)?"":"s");
2403 		tstr += my_strlen(tstr);
2404 	}
2405 	if (hours)
2406 	{
2407 		snprintf(CP(tstr), sizeof(tmp) - (tstr - tmp), "%ld hour%s ", (long) hours, (hours==1)?"":"s");
2408 		tstr += my_strlen(tstr);
2409 	}
2410 	if (minutes)
2411 	{
2412 		snprintf(CP(tstr), sizeof(tmp) - (tstr - tmp), "%ld minute%s ", (long) minutes, (minutes==1)?"":"s");
2413 		tstr += my_strlen(tstr);
2414 	}
2415 	if (seconds || (!days && !hours && !minutes))
2416 	{
2417 		snprintf(CP(tstr), sizeof(tmp) - (tstr - tmp), "%ld second%s", (long) seconds, (seconds==1)?"":"s");
2418 		tstr += my_strlen(tstr);
2419 	}
2420 	malloc_strcpy(&result, tmp);
2421 	return (result);
2422 }
2423 
2424 static u_char	*
function_index(u_char * input)2425 function_index(u_char *input)
2426 {
2427 	u_char	*result = NULL;
2428 	u_char	*schars;
2429 	u_char	*iloc;
2430 	int	ival;
2431 	u_char	tmp[40];
2432 
2433 	schars = next_arg(input, &input);
2434 	iloc = (schars) ? sindex(input, schars) : NULL;
2435 	ival = (iloc) ? iloc - input : -1;
2436 	snprintf(CP(tmp), sizeof tmp, "%d", ival);
2437 	malloc_strcpy(&result, tmp);
2438 	return (result);
2439 }
2440 
2441 static u_char	*
function_rindex(u_char * input)2442 function_rindex(u_char *input)
2443 {
2444 	u_char	*result = NULL;
2445 	u_char	*schars;
2446 	u_char	*iloc;
2447 	int	ival;
2448 	u_char	tmp[40];
2449 
2450 	schars = next_arg(input, &input);
2451 	iloc = (schars) ? srindex(input, schars) : NULL;
2452 	ival = (iloc) ? iloc - input : -1;
2453 	snprintf(CP(tmp), sizeof tmp, "%d", ival);
2454 	malloc_strcpy(&result, tmp);
2455 	return (result);
2456 }
2457 
2458 static u_char	*
function_match(u_char * input)2459 function_match(u_char *input)
2460 {
2461 	u_char	*result = NULL;
2462 	u_char	*pattern;
2463 	u_char	*word;
2464 	int	current_match;
2465 	int	best_match = 0;
2466 	int	match = 0;
2467 	int	match_index = 0;
2468 	u_char	tmp[40];
2469 
2470 	if ((pattern = next_arg(input, &input)) != NULL)
2471 	{
2472 		while ((word = next_arg(input, &input)) != NULL)
2473 		{
2474 			match_index++;
2475 			if ((current_match = wild_match(pattern, word))
2476 					> best_match)
2477 			{
2478 				match = match_index;
2479 				best_match = current_match;
2480 			}
2481 		}
2482 	}
2483 	snprintf(CP(tmp), sizeof tmp, "%d", match);
2484 	malloc_strcpy(&result, tmp);
2485 	return (result);
2486 }
2487 
2488 static u_char	*
function_rmatch(u_char * input)2489 function_rmatch(u_char *input)
2490 {
2491 	u_char	*result = NULL;
2492 	u_char	*pattern;
2493 	u_char	*word;
2494 	int	current_match;
2495 	int	best_match = 0;
2496 	int	match = 0;
2497 	int	rmatch_index = 0;
2498 	u_char	tmp[40];
2499 
2500 	if ((pattern = next_arg(input, &input)) != NULL)
2501 	{
2502 		while ((word = next_arg(input, &input)) != NULL)
2503 		{
2504 			rmatch_index++;
2505 			if ((current_match = wild_match(word, pattern)) >
2506 					best_match)
2507 			{
2508 				match = rmatch_index;
2509 				best_match = current_match;
2510 			}
2511 		}
2512 	}
2513 	snprintf(CP(tmp), sizeof tmp, "%d", match);
2514 	malloc_strcpy(&result, tmp);
2515 	return (result);
2516 }
2517 
2518 static u_char	*
function_userhost(u_char * input)2519 function_userhost(u_char *input)
2520 {
2521 	u_char	*result = NULL;
2522 	u_char	*userhost = from_user_host();
2523 
2524 	malloc_strcpy(&result, userhost ? userhost : empty_string());
2525 	return (result);
2526 }
2527 
2528 static u_char	*
function_strip(u_char * input)2529 function_strip(u_char *input)
2530 {
2531 	u_char	tmpbuf[128], *result = NULL;
2532 	u_char	*retval = NULL;
2533 	u_char	*chars;
2534 	u_char	*cp, *dp;
2535 	size_t len = 0;
2536 
2537 	if ((chars = next_arg(input, &input)) && input)
2538 	{
2539 		len = my_strlen(input);
2540 		if (len > 127)
2541 			result = new_malloc(len + 1);
2542 		else
2543 			result = tmpbuf;
2544 
2545 		for (cp = input, dp = result; *cp; cp++)
2546 		{
2547 			if (!my_index(chars, *cp))
2548 				*dp++ = *cp;
2549 		}
2550 		*dp = '\0';
2551 	}
2552 	malloc_strcpy(&retval, result);
2553 	if (len > 127)
2554 		new_free(&result);	/* we could use this copy, but it might be extra-long */
2555 	return (retval);
2556 }
2557 
2558 static u_char	*
function_encode(u_char * input)2559 function_encode(u_char *input)
2560 {
2561 	u_char	*result;
2562 	u_char	*c;
2563 	int	i = 0;
2564 
2565 	result = new_malloc(my_strlen(input) * 2 + 1);
2566 	for (c = input; *c; c++)
2567 	{
2568 		result[i++] = (*c >> 4) + 0x41;
2569 		result[i++] = (*c & 0x0f) + 0x41;
2570 	}
2571 	result[i] = '\0';
2572 	return (result);
2573 }
2574 
2575 
2576 static u_char	*
function_decode(u_char * input)2577 function_decode(u_char *input)
2578 {
2579 	u_char	*result;
2580 	u_char	*c;
2581 	u_char	d, e;
2582 	int	i = 0;
2583 
2584 	c = input;
2585 	result = new_malloc(my_strlen(input) / 2 + 2);
2586 	while((d = *c) && (e = *(c+1)))
2587 	{
2588 		result[i] = ((d - 0x41) << 4) | (e - 0x41);
2589 		c += 2;
2590 		i++;
2591 	}
2592 	result[i] = '\0';
2593 	return (result);
2594 }
2595 
2596 static u_char	*
function_ischannel(u_char * input)2597 function_ischannel(u_char *input)
2598 {
2599 	u_char	*result = NULL;
2600 
2601 	malloc_strcpy(&result, is_channel(input) ? one() : zero());
2602 	return (result);
2603 }
2604 
2605 static u_char	*
function_ischanop(u_char * input)2606 function_ischanop(u_char *input)
2607 {
2608 	u_char	*result = NULL;
2609 	u_char	*nick;
2610 	u_char	*channel = NULL;
2611 
2612 	if (!(nick = next_arg(input, &channel)))
2613 		malloc_strcpy(&result, zero());
2614 	else
2615 		malloc_strcpy(&result, is_chanop(channel, nick) ? one() : zero());
2616 	return (result);
2617 }
2618 
2619 #ifdef HAVE_CRYPT
2620 static u_char *
function_crypt(u_char * input)2621 function_crypt(u_char *input)
2622 {
2623 	u_char	*result = NULL;
2624 	u_char	*salt;
2625 	u_char	*key = NULL;
2626 
2627 	if (!(salt = next_arg(input, &key)))
2628 		malloc_strcpy(&result, zero());
2629 	else
2630 		malloc_strcpy(&result, UP(crypt(CP(key), CP(salt))));
2631 	return (result);
2632 }
2633 #endif /* HAVE_CRYPT */
2634 
2635 static u_char *
function_hasvoice(u_char * input)2636 function_hasvoice(u_char *input)
2637 {
2638 	u_char	*result = NULL;
2639 	u_char	*nick;
2640 	u_char	*channel = NULL;
2641 
2642 	if (!(nick = next_arg(input, &channel)))
2643 		malloc_strcpy(&result, zero());
2644 	else
2645 		malloc_strcpy(&result, has_voice(channel, nick, get_from_server()) ? one() : zero());
2646 	return (result);
2647 }
2648 
2649 static u_char *
function_dcclist(u_char * nick)2650 function_dcclist(u_char *nick)
2651 {
2652 	if (!nick)
2653 	{
2654 		u_char *result;
2655 
2656 		malloc_strcpy(&result, zero());
2657 		return (result);
2658 	}
2659 
2660 	return dcc_list_func(nick);
2661 }
2662 
2663 static u_char *
function_chatpeers(u_char * dummy)2664 function_chatpeers(u_char *dummy)
2665 {
2666 	return dcc_chatpeers_func();
2667 }
2668 
2669 static u_char	*
function_word(u_char * input)2670 function_word(u_char *input)
2671 {
2672 	u_char	*result = NULL;
2673 	u_char	*count;
2674 	int	cvalue;
2675 	u_char	*word;
2676 
2677 	count = next_arg(input, &input);
2678 	if (count)
2679 		cvalue = my_atoi(count);
2680 	else
2681 		cvalue = 0;
2682 	if (cvalue < 0)
2683 		malloc_strcpy(&result, empty_string());
2684 	else
2685 	{
2686 		for (word = next_arg(input, &input); word && cvalue--;
2687 				word = next_arg(input, &input))
2688 			;
2689 		malloc_strcpy(&result, (word) ? word : empty_string());
2690 	}
2691 	return (result);
2692 }
2693 
2694 static u_char	*
function_querynick(u_char * input)2695 function_querynick(u_char *input)
2696 {
2697 	u_char	*result = NULL;
2698 	Window	*win;
2699 
2700 	if (input && isdigit(*input))
2701 		win = get_window_by_refnum((u_int)my_atoi(input));
2702 	else
2703 		win = curr_scr_win;
2704 	malloc_strcpy(&result, win ? window_get_query_nick(win) : UP("-1"));
2705 	return (result);
2706 }
2707 
2708 static u_char	*
function_windows(u_char * input)2709 function_windows(u_char *input)
2710 {
2711 	u_char	*result = NULL;
2712 	Win_Trav wt;
2713 	Window	*tmp;
2714 
2715 	malloc_strcat(&result, empty_string());
2716 	wt.init = 1;
2717 	while ((tmp = window_traverse(&wt)))
2718 	{
2719 		u_char *name = window_get_name(tmp);
2720 
2721 		if (name)
2722 		{
2723 			malloc_strcat(&result, name);
2724 			malloc_strcat(&result, UP(" "));
2725 		}
2726 		else
2727 		{
2728 			u_char buf[32];
2729 
2730 			snprintf(CP(buf), sizeof buf, "%u ", window_get_refnum(tmp));
2731 			malloc_strcat(&result, buf);
2732 		}
2733 	}
2734 
2735 	return (result);
2736 }
2737 
2738 static u_char	*
function_screens(u_char * input)2739 function_screens(u_char *input)
2740 {
2741 	Screen	*screen;
2742 	u_char	*result = NULL;
2743 	u_char buf[32];
2744 
2745 	malloc_strcat(&result, empty_string());
2746 	for (screen = screen_first(); screen; screen = screen_get_next(screen))
2747 	{
2748 		if (screen_get_alive(screen))
2749 		{
2750 			snprintf(CP(buf), sizeof buf, "%u ", screen_get_screennum(screen));
2751 			malloc_strcat(&result, buf);
2752 		}
2753 	}
2754 
2755 	return (result);
2756 }
2757 
2758 static u_char	*
function_notify(u_char * input)2759 function_notify(u_char *input)
2760 {
2761 	u_char	*result;
2762 
2763 	if (input && my_stricmp(input, UP("gone")) == 0)
2764 		result = get_notify_list(NOTIFY_LIST_GONE);
2765 	else if (input && my_stricmp(input, UP("all")) == 0)
2766 		result = get_notify_list(NOTIFY_LIST_ALL);
2767 	else
2768 		result = get_notify_list(NOTIFY_LIST_HERE);
2769 
2770 	return result;
2771 }
2772 
2773 /*
2774  * $ignored(nick!user@host type) with type from:
2775  *	ALL MSGS PUBLIC WALLS WALLOPS INVITES NOTICES NOTES CTCP CRAP
2776  * $ignored(nick):
2777  *	gives ignore's matching nick
2778  * $ignored():
2779  *	gives all
2780  */
2781 static u_char	*
function_ignored(u_char * input)2782 function_ignored(u_char *input)
2783 {
2784 	u_char	*result = NULL, *userhost, *nick;
2785 	int type;
2786 
2787 	if ((nick = next_arg(input, &input)) != NULL)
2788 	{
2789 		if (!input || !*input)
2790 			goto do_ignore_list;
2791 
2792 		type = get_ignore_type(input);
2793 		if (type == 0 || type == -1 || type == IGNORE_ALL)
2794 			goto do_zero;
2795 
2796 		if ((userhost = UP(my_index(nick, '!'))))
2797 			*userhost++ = 0;
2798 		switch (double_ignore(nick, userhost, type))
2799 		{
2800 		case DONT_IGNORE:
2801 			malloc_strcpy(&result, UP("dont"));
2802 			break;
2803 		case HIGHLIGHTED:
2804 			malloc_strcpy(&result, UP("highlighted"));
2805 			break;
2806 		case IGNORED:
2807 			malloc_strcpy(&result, UP("ignored"));
2808 			break;
2809 		default:
2810 			goto do_zero;
2811 		}
2812 	}
2813 	else
2814 do_ignore_list:
2815 		result = ignore_list_string(nick);
2816 	if (!result)
2817 do_zero:
2818 		malloc_strcpy(&result, zero());
2819 	return (result);
2820 }
2821 
2822 static u_char	*
function_winserver(u_char * input)2823 function_winserver(u_char *input)
2824 {
2825 	u_char	*result = NULL;
2826 	u_char	tmp[10];
2827 	Window	*win;
2828 
2829 	if (input && isdigit(*input))
2830 		win = get_window_by_refnum((u_int)my_atoi(input));
2831 	else
2832 		win = curr_scr_win;
2833 	snprintf(CP(tmp), sizeof tmp, "%d",
2834 		 win ? window_get_server(win) : -1);
2835 	malloc_strcpy(&result, tmp);
2836 	return (result);
2837 }
2838 
2839 static u_char	*
function_winservergroup(u_char * input)2840 function_winservergroup(u_char *input)
2841 {
2842 	u_char	*result = NULL;
2843 	u_char	tmp[10];
2844 	Window	*win;
2845 
2846 	if (input && isdigit(*input))
2847 		win = get_window_by_refnum((u_int)my_atoi(input));
2848 	else
2849 		win = curr_scr_win;
2850 	snprintf(CP(tmp), sizeof tmp, "%d",
2851 		 win ? window_get_server_group(win) : -1);
2852 	malloc_strcpy(&result, tmp);
2853 	return (result);
2854 }
2855 
2856 static u_char	*
function_winvisible(u_char * input)2857 function_winvisible(u_char *input)
2858 {
2859 	u_char	*result = NULL;
2860 	u_char	tmp[10];
2861 	Window	*win;
2862 
2863 	if (input && isdigit(*input))
2864 		win = get_window_by_refnum((u_int)my_atoi(input));
2865 	else
2866 		win = curr_scr_win;
2867 	snprintf(CP(tmp), sizeof tmp, "%d", win ? window_get_visible(win) : -1);
2868 	malloc_strcpy(&result, tmp);
2869 	return (result);
2870 }
2871 
2872 static u_char	*
function_winnum(u_char * input)2873 function_winnum(u_char *input)
2874 {
2875 	u_char	*result = NULL;
2876 	u_char	tmp[10];
2877 
2878 	snprintf(CP(tmp), sizeof tmp, "%d",
2879 		 curr_scr_win ? (int)window_get_refnum(curr_scr_win) : -1);
2880 	malloc_strcpy(&result, tmp);
2881 	return (result);
2882 }
2883 
2884 static u_char	*
function_winnam(u_char * input)2885 function_winnam(u_char *input)
2886 {
2887 	u_char	*result = NULL;
2888 	Window	*win;
2889 
2890 	if (input && isdigit(*input))
2891 		win = get_window_by_refnum((u_int)my_atoi(input));
2892 	else
2893 		win = curr_scr_win;
2894 	malloc_strcpy(&result, (win && window_get_name(win)) ?
2895 				window_get_name(win) : empty_string());
2896 	return (result);
2897 }
2898 
2899 /*
2900  * returns the current window's display (len) size counting for double
2901  * status bars, etc.. -Toasty
2902  */
2903 static u_char    *
function_winrows(u_char * input)2904 function_winrows(u_char *input)
2905 {
2906 	u_char	*result = NULL;
2907 
2908 	if (curr_scr_win)
2909 	{
2910 		u_char	tmp[10];
2911 
2912 		snprintf(CP(tmp), sizeof tmp, "%d",
2913 			 window_get_display_size(curr_scr_win));
2914 		malloc_strcpy(&result, tmp);
2915 	}
2916 	else
2917 		malloc_strcpy(&result, UP("-1"));
2918 	return (result);
2919 }
2920 
2921 /*
2922  * returns the current screen's (since all windows have the same
2923  * column/width) column value -Toasty
2924  */
2925 static u_char	*
function_wincols(u_char * input)2926 function_wincols(u_char *input)
2927 {
2928 	u_char	*result = NULL;
2929 
2930 	if (curr_scr_win)
2931 	{
2932 		u_char	tmp[10];
2933 
2934 		snprintf(CP(tmp), sizeof tmp, "%d", get_co());
2935 		malloc_strcpy(&result, tmp);
2936 	}
2937 	else
2938 		malloc_strcpy(&result, UP("-1"));
2939 	return (result);
2940 }
2941 
2942 static u_char	*
function_connect(u_char * input)2943 function_connect(u_char *input)
2944 {
2945 	u_char	*result = NULL;
2946 	u_char	*host;
2947 
2948 #ifdef DAEMON_UID
2949 	if (getuid() == DAEMON_UID)
2950 		put_it("You are not permitted to use CONNECT()");
2951 	else
2952 #endif /* DAEMON_ID */
2953 		if ((host = next_arg(input, &input)) != NULL)
2954 			result = dcc_raw_connect(host, (u_int) my_atoi(input));
2955 	return (result);
2956 }
2957 
2958 
2959 static u_char	*
function_listen(u_char * input)2960 function_listen(u_char *input)
2961 {
2962 	u_char	*result = NULL;
2963 
2964 #ifdef DAEMON_UID
2965 	if (getuid() == DAEMON_UID)
2966 		malloc_strcpy(&result, zero());
2967 	else
2968 #endif /* DAEMON_ID */
2969 		result = dcc_raw_listen((u_int) my_atoi(input));
2970 	return (result);
2971 }
2972 
2973 static u_char	*
function_toupper(u_char * input)2974 function_toupper(u_char *input)
2975 {
2976 	u_char	*new = NULL,
2977 		*ptr;
2978 
2979 	if (!input)
2980 		return empty_string();
2981 	malloc_strcpy(&new, input);
2982 	for (ptr = new; *ptr; ptr++)
2983 		*ptr = islower(*ptr) ? toupper(*ptr) : *ptr;
2984 	return new;
2985 }
2986 
2987 static u_char	*
function_tolower(u_char * input)2988 function_tolower(u_char *input)
2989 {
2990 	u_char	*new = NULL,
2991 		*ptr;
2992 
2993 	if (!input)
2994 		return empty_string();
2995 	malloc_strcpy(&new, input);
2996 	for (ptr = new; *ptr; ptr++)
2997 		*ptr = (isupper(*ptr)) ? tolower(*ptr) : *ptr;
2998 	return new;
2999 }
3000 
3001 static u_char	*
function_channels(u_char * input)3002 function_channels(u_char *input)
3003 {
3004 	Window	*window;
3005 
3006 	if (input)
3007 		window = isdigit(*input) ? get_window_by_refnum((u_int) my_atoi(input))
3008 					 : curr_scr_win;
3009 	else
3010 		window = curr_scr_win;
3011 
3012 	return create_channel_list(window);
3013 }
3014 
3015 static u_char	*
function_servers(u_char * input)3016 function_servers(u_char *input)
3017 {
3018 	return create_server_list();
3019 }
3020 
3021 static u_char	*
function_servertype(u_char * input)3022 function_servertype(u_char *input)
3023 {
3024 	int server;
3025 	u_char *s;
3026 	u_char *result = NULL;
3027 	const	int	from_server = get_from_server();
3028 
3029 	if (from_server < 0)
3030 		server = get_primary_server();
3031 	else
3032 		server = from_server;
3033 	if (server < 0)
3034 		s = empty_string();
3035 	else
3036 		switch (server_get_version(server)) {
3037 		case ServerICB:
3038 			s = UP("ICB");
3039 			break;
3040 		case Server2_6:
3041 			s = UP("IRC2.6");
3042 			break;
3043 		case Server2_7:
3044 			s = UP("IRC2.7");
3045 			break;
3046 		case Server2_8:
3047 			s = UP("IRC2.8");
3048 			break;
3049 		case Server2_9:
3050 			s = UP("IRC2.9");
3051 			break;
3052 		case Server2_10:
3053 			s = UP("IRC2.10");
3054 			break;
3055 		case Server2_11:
3056 			s = UP("IRC2.11");
3057 			break;
3058 		default:
3059 			s = UP("IRC unknown");
3060 			break;
3061 		}
3062 
3063 	malloc_strcpy(&result, s);
3064 	return (result);
3065 }
3066 
3067 static u_char	*
function_onchannel(u_char * input)3068 function_onchannel(u_char *input)
3069 {
3070 	u_char	*result = NULL;
3071 	u_char	*nick;
3072 	u_char	*channel = NULL;
3073 	const	int	from_server = get_from_server();
3074 
3075 	if (from_server < 0 || !(nick = next_arg(input, &channel)))
3076 		malloc_strcpy(&result, zero());
3077 	else
3078 		malloc_strcpy(&result,
3079 			is_on_channel(channel, from_server, nick) ? one() : zero());
3080 	return (result);
3081 }
3082 
3083 static u_char	*
function_pid(u_char * input)3084 function_pid(u_char *input)
3085 {
3086 	u_char	*result = NULL;
3087 	u_char	lbuf[32];	/* plenty big enough for %d */
3088 
3089 	snprintf(CP(lbuf), sizeof lbuf, "%d", (int) getpid());
3090 	malloc_strcpy(&result, lbuf);
3091 	return (result);
3092 }
3093 
3094 static u_char	*
function_ppid(u_char * input)3095 function_ppid(u_char *input)
3096 {
3097 	u_char	*result = NULL;
3098 	u_char	lbuf[32];	/* plenty big enough for %d */
3099 
3100 	snprintf(CP(lbuf), sizeof lbuf, "%d", (int) getppid());
3101 	malloc_strcpy(&result, lbuf);
3102 	return (result);
3103 }
3104 
3105 /*
3106  * idle() patch from scottr (scott.reynolds@plexus.com)
3107  */
3108 static u_char	*
function_idle(u_char * input)3109 function_idle(u_char *input)
3110 {
3111 	u_char	*result = NULL;
3112 	u_char	lbuf[20];
3113 
3114 	snprintf(CP(lbuf), sizeof lbuf, "%ld", (long)(time(0) - idle_time()));
3115 	malloc_strcpy(&result, lbuf);
3116 	return (result);
3117 }
3118 
3119 /*
3120  * strftime() patch from hari (markc@arbld.unimelb.edu.au)
3121  */
3122 #ifdef HAVE_STRFTIME
3123 static u_char	*
function_strftime(u_char * input)3124 function_strftime(u_char *input)
3125 {
3126 	u_char	result[128];
3127 	time_t	ltime;
3128 	u_char	*fmt = NULL;
3129 
3130 	ltime = my_atol(input);
3131 	fmt = input;
3132 	/* skip the time field */
3133 	while (isdigit(*fmt))
3134 		++fmt;
3135 	if (*fmt && *++fmt)
3136 	{
3137 		struct tm	*tm;
3138 
3139 		tm = localtime(&ltime);
3140 		if (strftime(CP(result), 128, CP(fmt), tm))
3141 		{
3142 			u_char	*s = NULL;
3143 
3144 			malloc_strcpy(&s, result);
3145 			return s;
3146 		}
3147 		else
3148 			return NULL;
3149 	}
3150 	else
3151 	{
3152 		return NULL;
3153 	}
3154 }
3155 #endif /* HAVE_STRFTIME */
3156 
3157 static u_char	*
function_urlencode(u_char * input)3158 function_urlencode(u_char *input)
3159 {
3160 	u_char	*result;
3161 	u_char	*c;
3162 	int	i = 0;
3163 
3164 	for (c = input; *c; c++)
3165 		if (*c == '+' || *c == '%' || *c == '&')
3166 			i += 3;
3167 		else
3168 			++i;
3169 
3170 	result = new_malloc(i + 1);
3171 
3172 	for (i = 0, c = input; *c; c++)
3173 	{
3174 		if (*c == ' ')
3175 			result[i++] = '+';
3176 		else if (*c == '+')
3177 		{
3178 			result[i++] = '%';
3179 			result[i++] = '2';
3180 			result[i++] = 'B';
3181 		}
3182 		else if (*c == '&')
3183 		{
3184 			result[i++] = '%';
3185 			result[i++] = '2';
3186 			result[i++] = '6';
3187 		}
3188 		else
3189 			result[i++] = *c;
3190 	}
3191 	result[i] = '\0';
3192 	return (result);
3193 }
3194 
3195 static u_char	*
function_shellfix(u_char * input)3196 function_shellfix(u_char *input)
3197 {
3198 	u_char	*result;
3199 	u_char	*c;
3200 	int	i = 2;
3201 
3202 	for (c = input; *c; c++)
3203 		if (*c == '\'')
3204 			i += 4;
3205 		else
3206 			++i;
3207 
3208 	result = new_malloc(i + 1);
3209 
3210 	i = 0;
3211 	result[i++] = '\'';
3212 	for (c = input; *c; c++)
3213 	{
3214 		if (*c == '\'')
3215 		{
3216 			result[i++] = '\'';
3217 			result[i++] = '\\';
3218 			result[i++] = '\'';
3219 			result[i++] = '\'';
3220 		}
3221 		else
3222 			result[i++] = *c;
3223 	}
3224 	result[i++] = '\'';
3225 	result[i] = '\0';
3226 	return (result);
3227 }
3228 
3229 static u_char	*
function_filestat(u_char * input)3230 function_filestat(u_char *input)
3231 {
3232 	struct	stat statbuf;
3233 	u_char	*result;
3234 	u_char	lbuf[40];   /* 40 should be enough */
3235 
3236 
3237 	if (stat(CP(input), &statbuf) == -1)
3238 		malloc_strcpy(&result, empty_string());
3239 	else
3240 	{
3241 		snprintf(CP(lbuf), sizeof lbuf, "%lu,%d,%d,%o,%s",
3242 		    (unsigned long)statbuf.st_size,
3243 		    (int)statbuf.st_uid,
3244 		    (int)statbuf.st_gid,
3245 		    statbuf.st_mode,
3246 		    input);
3247 		malloc_strcpy(&result, lbuf);
3248 	}
3249 	return (result);
3250 }
3251