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