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