/* * alias.c Handles command aliases for irc.c * * Written By Michael Sandrof * * Copyright (c) 1990 Michael Sandrof. * Copyright (c) 1991, 1992 Troy Rollo. * Copyright (c) 1992-2000 Matthew R. Green. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "irc.h" IRCII_RCSID("@(#)$Id: alias.c,v 1.91 2000/07/18 17:12:17 mrg Exp $"); #include "alias.h" #include "dcc.h" #include "status.h" #include "edit.h" #include "history.h" #include "vars.h" #include "ircaux.h" #include "server.h" #include "screen.h" #include "window.h" #include "input.h" #include "names.h" #include "server.h" #include "output.h" #include "names.h" #include "parse.h" /* * define this to use the old way of managing allocations * inside the guts of alias handling (static buffers, not * malloc & realloc'ed ones). */ #undef USE_OLD_ALIAS_ALLOC extern int parse_number _((u_char **)); static u_char *next_unit _((u_char *, u_char *, int *, int)); static long randm _((long)); static u_char *lastop _((u_char *)); static u_char *arg_number _((int, int, u_char *)); static void do_alias_string _((void)); static Alias *find_alias _((Alias **, u_char *, int, int *)); static void insert_alias _((Alias **, Alias *)); static u_char *alias_arg _((u_char **, u_int *)); static u_char *find_inline _((u_char *)); static u_char *built_in_alias _((int)); static u_char *call_function _((u_char *, u_char *, u_char *, int *)); #ifndef USE_OLD_ALIAS_ALLOC static void expander_addition _((u_char **, u_char *, int, u_char *)); static u_char *alias_special_char _((u_char *, u_char **, u_char *, u_char *, u_char *, int *)); #else /* USE_OLD_ALIAS_ALLOC */ static void expander_addition _((u_char *, u_char *, int, u_char *)); static u_char *alias_special_char _((u_char *, u_char *, u_char *, u_char *, u_char *, int *)); #endif /* USE_OLD_ALIAS_ALLOC */ static u_char *alias_detected _((void)); static u_char *alias_sent_nick _((void)); static u_char *alias_recv_nick _((void)); static u_char *alias_msg_body _((void)); static u_char *alias_joined_nick _((void)); static u_char *alias_public_nick _((void)); static u_char *alias_dollar _((void)); static u_char *alias_channel _((void)); static u_char *alias_server _((void)); static u_char *alias_query_nick _((void)); static u_char *alias_target _((void)); static u_char *alias_nick _((void)); static u_char *alias_invite _((void)); static u_char *alias_cmdchar _((void)); static u_char *alias_line _((void)); static u_char *alias_away _((void)); static u_char *alias_oper _((void)); static u_char *alias_chanop _((void)); static u_char *alias_modes _((void)); static u_char *alias_buffer _((void)); static u_char *alias_time _((void)); static u_char *alias_version _((void)); static u_char *alias_currdir _((void)); static u_char *alias_current_numeric _((void)); static u_char *alias_server_version _((void)); typedef struct { u_char name; u_char *(*func) _((void)); } BuiltIns; static FAR BuiltIns built_in[] = { { '.', alias_sent_nick }, { ',', alias_recv_nick }, { ':', alias_joined_nick }, { ';', alias_public_nick }, { '$', alias_dollar }, { 'A', alias_away }, { 'B', alias_msg_body }, { 'C', alias_channel }, { 'D', alias_detected }, /* { 'E' }, { 'F' }, { 'G' }, */ { 'H', alias_current_numeric }, { 'I', alias_invite }, /* { 'J' }, */ { 'K', alias_cmdchar }, { 'L', alias_line }, { 'M', alias_modes }, { 'N', alias_nick }, { 'O', alias_oper }, { 'P', alias_chanop }, { 'Q', alias_query_nick }, { 'R', alias_server_version }, { 'S', alias_server }, { 'T', alias_target }, { 'U', alias_buffer }, { 'V', alias_version }, { 'W', alias_currdir }, /* { 'X' }, { 'Y' }, */ { 'Z', alias_time }, { (u_char) 0, NULL } }; u_char *command_line = (u_char *) 0; u_char *function_left _((u_char *)); u_char *function_right _((u_char *)); u_char *function_mid _((u_char *)); u_char *function_rand _((u_char *)); u_char *function_srand _((u_char *)); u_char *function_time _((u_char *)); u_char *function_stime _((u_char *)); u_char *function_index _((u_char *)); u_char *function_rindex _((u_char *)); u_char *function_match _((u_char *)); u_char *function_rmatch _((u_char *)); u_char *function_userhost _((u_char *)); u_char *function_strip _((u_char *)); u_char *function_encode _((u_char *)); u_char *function_decode _((u_char *)); u_char *function_ischannel _((u_char *)); u_char *function_ischanop _((u_char *)); #ifdef HAVE_CRYPT u_char *function_crypt _((u_char *)); #endif /* HAVE_CRYPT */ u_char *function_hasvoice _((u_char *)); u_char *function_dcclist _((u_char *)); u_char *function_chatpeers _((u_char *)); u_char *function_word _((u_char *)); u_char *function_winnum _((u_char *)); u_char *function_winnam _((u_char *)); u_char *function_winrows _((u_char *)); u_char *function_wincols _((u_char *)); u_char *function_winvisible _((u_char *)); u_char *function_winserver _((u_char *)); u_char *function_winservergroup _((u_char *)); u_char *function_connect _((u_char *)); u_char *function_listen _((u_char *)); u_char *function_tdiff _((u_char *)); u_char *function_toupper _((u_char *)); u_char *function_tolower _((u_char *)); u_char *function_channels _((u_char *)); u_char *function_servers _((u_char *)); u_char *function_servertype _((u_char *)); u_char *function_curpos _((u_char *)); u_char *function_onchannel _((u_char *)); u_char *function_pid _((u_char *)); u_char *function_ppid _((u_char *)); u_char *function_chanusers _((u_char *)); u_char *function_idle _((u_char *)); u_char *function_querynick _((u_char *)); #ifdef HAVE_STRFTIME u_char *function_strftime _((u_char *)); #endif /* HAVE_STRFTIME */ typedef struct { u_char *name; u_char *(*func) _((u_char *)); } BuiltInFunctions; static BuiltInFunctions FAR built_in_functions[] = { { UP("LEFT"), function_left }, { UP("RIGHT"), function_right }, { UP("MID"), function_mid }, { UP("RAND"), function_rand }, { UP("SRAND"), function_srand }, { UP("TIME"), function_time }, { UP("TDIFF"), function_tdiff }, { UP("STIME"), function_stime }, { UP("INDEX"), function_index }, { UP("RINDEX"), function_rindex }, { UP("MATCH"), function_match }, { UP("RMATCH"), function_rmatch }, { UP("USERHOST"), function_userhost }, { UP("STRIP"), function_strip }, { UP("ENCODE"), function_encode }, { UP("DECODE"), function_decode }, { UP("ISCHANNEL"), function_ischannel }, { UP("ISCHANOP"), function_ischanop }, #ifdef HAVE_CRYPT { UP("CRYPT"), function_crypt }, #endif /* HAVE_CRYPT */ { UP("HASVOICE"), function_hasvoice }, { UP("DCCLIST"), function_dcclist }, { UP("CHATPEERS"), function_chatpeers }, { UP("WORD"), function_word }, { UP("WINNUM"), function_winnum }, { UP("WINNAM"), function_winnam }, { UP("WINVIS"), function_winvisible }, { UP("WINROWS"), function_winrows }, { UP("WINCOLS"), function_wincols }, { UP("WINSERVER"), function_winserver }, { UP("WINSERVERGROUP"), function_winservergroup }, { UP("CONNECT"), function_connect }, { UP("LISTEN"), function_listen }, { UP("TOUPPER"), function_toupper }, { UP("TOLOWER"), function_tolower }, { UP("MYCHANNELS"), function_channels }, { UP("MYSERVERS"), function_servers }, { UP("SERVERTYPE"), function_servertype }, { UP("CURPOS"), function_curpos }, { UP("ONCHANNEL"), function_onchannel }, { UP("PID"), function_pid }, { UP("PPID"), function_ppid }, { UP("CHANUSERS"), function_chanusers }, #ifdef HAVE_STRFTIME { UP("STRFTIME"), function_strftime }, #endif /* HAVE_STRFTIME */ { UP("IDLE"), function_idle }, { UP("QUERYNICK"), function_querynick }, { UP(0), NULL } }; /* alias_illegals: characters that are illegal in alias names */ u_char alias_illegals[] = " #+-*/\\()={}[]<>!@$%^~`,?;:|'\""; static Alias *alias_list[] = { (Alias *) 0, (Alias *) 0 }; /* alias_string: the thing that gets replaced by the $"..." construct */ static u_char *alias_string = (u_char *) 0; static int eval_args; /* function_stack and function_stkptr - hold the return values from functions */ static u_char * FAR function_stack[128] = { (u_char *) 0 }; static int function_stkptr = 0; /* * find_alias: looks up name in in alias list. Returns the Alias entry if * found, or null if not found. If do_unlink is set, the found entry is * removed from the list as well. If match is null, only perfect matches * will return anything. Otherwise, the number of matches will be returned. */ static Alias * find_alias(list, name, do_unlink, match) Alias **list; u_char *name; int do_unlink; int *match; { Alias *tmp, *last = (Alias *) 0; int cmp; size_t len; int (*cmp_func) _((u_char *, u_char *, size_t)); if (match) { *match = 0; cmp_func = my_strnicmp; } else cmp_func = (int (*) _((u_char *, u_char *, size_t))) my_stricmp; if (name) { len = my_strlen(name); for (tmp = *list; tmp; tmp = tmp->next) { if ((cmp = cmp_func(name, tmp->name, len)) == 0) { if (do_unlink) { if (last) last->next = tmp->next; else *list = tmp->next; } if (match) { (*match)++; if (my_strlen(tmp->name) == len) { *match = 0; return (tmp); } } else return (tmp); } else if (cmp < 0) break; last = tmp; } } if (match && (*match == 1)) return (last); else return ((Alias *) 0); } /* * insert_alias: adds the given alias to the alias list. The alias list is * alphabetized by name */ static void insert_alias(list, nalias) Alias **list; Alias *nalias; { Alias *tmp, *last, *foo; last = (Alias *) 0; for (tmp = *list; tmp; tmp = tmp->next) { if (my_strcmp(nalias->name, tmp->name) < 0) break; last = tmp; } if (last) { foo = last->next; last->next = nalias; nalias->next = foo; } else { nalias->next = *list; *list = nalias; } } /* * add_alias: given the alias name and "stuff" that makes up the alias, * add_alias() first checks to see if the alias name is already in use... if * so, the old alias is replaced with the new one. If the alias is not * already in use, it is added. */ void add_alias(type, name, stuff) int type; u_char *name, *stuff; { Alias *tmp; u_char *ptr; upper(name); if (type == COMMAND_ALIAS) say("Alias %s added", name); else { if (!my_strcmp(name, "FUNCTION_RETURN")) { if (function_stack[function_stkptr]) new_free(&function_stack[function_stkptr]); malloc_strcpy(&function_stack[function_stkptr], stuff); return; } if ((ptr = sindex(name, alias_illegals)) != NULL) { yell("Assign names may not contain '%c'", *ptr); return; } say("Assign %s added", name); } if ((tmp = find_alias(&(alias_list[type]), name, 1, (int *) 0)) == (Alias *) 0) { tmp = (Alias *) new_malloc(sizeof(Alias)); if (tmp == (Alias *) 0) { yell("Couldn't allocate memory for new alias!"); return; } tmp->name = (u_char *) 0; tmp->stuff = (u_char *) 0; } malloc_strcpy(&(tmp->name), name); malloc_strcpy(&(tmp->stuff), stuff); tmp->mark = 0; tmp->global = loading_global; insert_alias(&(alias_list[type]), tmp); } /* alias_arg: a special version of next_arg for aliases */ static u_char * alias_arg(str, pos) u_char **str; u_int *pos; { u_char *ptr; if (!*str) return (u_char *) 0; *pos = 0; ptr = *str; while (' ' == *ptr) { ptr++; (*pos)++; } if (*ptr == '\0') { *str = empty_string; return ((u_char *) 0); } if ((*str = sindex(ptr, UP(" "))) != NULL) *((*str)++) = '\0'; else *str = empty_string; return (ptr); } /* word_count: returns the number of words in the given string */ extern int word_count(str) u_char *str; { int cnt = 0; u_char *ptr; while (1) { if ((ptr = sindex(str, UP("^ "))) != NULL) { cnt++; if ((str = sindex(ptr, UP(" "))) == (u_char *) 0) return (cnt); } else return (cnt); } } static u_char * built_in_alias(c) int c; { BuiltIns *tmp; u_char *ret = (u_char *) 0; for (tmp = built_in; tmp->name; tmp++) if ((u_char)c == tmp->name) { malloc_strcpy(&ret, tmp->func()); break; } return (ret); } /* * find_inline: This simply looks up the given str. It first checks to see * if its a user variable and returns it if so. If not, it checks to see if * it's an IRC variable and returns it if so. If not, it checks to see if * its and environment variable and returns it if so. If not, it returns * null. It mallocs the returned string */ static u_char * find_inline(str) u_char *str; { Alias *nalias; u_char *ret = NULL; u_char *tmp; if ((nalias = find_alias(&(alias_list[VAR_ALIAS]), str, 0, (int *) NULL)) != NULL) { malloc_strcpy(&ret, nalias->stuff); return (ret); } if ((my_strlen(str) == 1) && (ret = built_in_alias(*str))) return(ret); if ((ret = make_string_var(str)) != NULL) return (ret); #ifdef DAEMON_UID if (getuid() == DAEMON_UID) malloc_strcpy(&ret, (getuid() != DAEMON_UID) && (tmp = my_getenv(str)) ? tmp : empty_string); #else malloc_strcpy(&ret, (tmp = my_getenv(str)) ? tmp : empty_string); #endif /* DAEMON_UID */ return (ret); } static u_char * call_function(name, f_args, args, args_flag) u_char *name, *f_args, *args; int *args_flag; { u_char *tmp; u_char *result = (u_char *) 0; u_char *sub_buffer = (u_char *) 0; int builtnum; u_char *debug_copy = (u_char *) 0; u_char *cmd = (u_char *) 0; malloc_strcpy(&cmd, name); upper(cmd); tmp = expand_alias((u_char *) 0, f_args, args, args_flag, NULL); if (get_int_var(DEBUG_VAR) & DEBUG_FUNCTIONS) malloc_strcpy(&debug_copy, tmp); for (builtnum = 0; built_in_functions[builtnum].name != NULL && my_strcmp(built_in_functions[builtnum].name, cmd); builtnum++) ; new_free(&cmd); if (built_in_functions[builtnum].name) result = built_in_functions[builtnum].func(tmp); else { sub_buffer = new_malloc(my_strlen(name)+my_strlen(tmp)+2); my_strcpy(sub_buffer, name); my_strcat(sub_buffer, " "); my_strcat(sub_buffer, tmp); function_stack[++function_stkptr] = (u_char *) 0; parse_command(sub_buffer, 0, empty_string); new_free(&sub_buffer); eval_args=1; result = function_stack[function_stkptr]; function_stack[function_stkptr] = (u_char *) 0; if (!result) malloc_strcpy(&result, empty_string); function_stkptr--; } if (debug_copy) { yell("Function %s(%s) returned %s", name, debug_copy, result); new_free(&debug_copy); } new_free(&tmp); return (result); } /* Given a pointer to an operator, find the last operator in the string */ static u_char * lastop(ptr) u_char *ptr; { while (ptr[1] && index("!=<>&^|#+/-*", ptr[1])) ptr++; return ptr; } #define NU_EXPR 0 #define NU_CONJ NU_EXPR #define NU_ASSN 1 #define NU_COMP 2 #define NU_ADD 3 #define NU_MULT 4 #define NU_UNIT 5 #define NU_TERT 6 #define NU_BITW 8 static u_char * next_unit(str, args, arg_flag, stage) u_char *str, *args; int *arg_flag, stage; { u_char *ptr, *ptr2, *right; int got_sloshed = 0; u_char *lastc; u_char tmp[40]; u_char *result1 = (u_char *) 0, *result2 = (u_char *) 0; long value1 = 0, value2, value3; u_char op; int display; u_char *ArrayIndex, *EndIndex; while (isspace(*str)) ++str; if (!*str) { malloc_strcpy(&result1, empty_string); return result1; } lastc = str+my_strlen(str)-1; while (isspace(*lastc)) *lastc-- = '\0'; if (stage == NU_UNIT && *lastc == ')' && *str == '(') { str++, *lastc-- = '\0'; return next_unit(str, args, arg_flag, NU_EXPR); } if (!*str) { malloc_strcpy(&result1, empty_string); return result1; } for (ptr = str; *ptr; ptr++) { if (got_sloshed) /* Help! I'm drunk! */ { got_sloshed = 0; continue; } switch(*ptr) { case '\\': got_sloshed = 1; continue; case '(': if (stage != NU_UNIT || ptr == str) { if (!(ptr2 = MatchingBracket(ptr+1, (int)'(', (int)')'))) ptr = ptr+my_strlen(ptr)-1; else ptr = ptr2; break; } *ptr++ = '\0'; right = ptr; ptr = MatchingBracket(right, (int)LEFT_PAREN, (int)RIGHT_PAREN); if (ptr) *ptr++ = '\0'; result1 = call_function(str, right, args, arg_flag); if (ptr && *ptr) { malloc_strcat(&result1, ptr); result2 = next_unit(result1, args, arg_flag, stage); new_free(&result1); result1 = result2; } return result1; case '[': if (stage != NU_UNIT) { if (!(ptr2 = MatchingBracket(ptr+1, (int)'[', (int)']'))) ptr = ptr+my_strlen(ptr)-1; else ptr = ptr2; break; } *ptr++ = '\0'; right = ptr; ptr = MatchingBracket(right, (int)LEFT_BRACKET, (int)RIGHT_BRACKET); if (ptr) *ptr++ = '\0'; result1 = expand_alias((u_char *) 0, right, args, arg_flag, NULL); if (*str) { result2 = new_malloc(my_strlen(str)+ (result1?my_strlen(result1):0)+ (ptr?my_strlen(ptr):0) + 2); my_strcpy(result2, str); my_strcat(result2, "."); my_strcat(result2, result1); new_free(&result1); if (ptr && *ptr) { my_strcat(result2, ptr); result1 = next_unit(result2, args, arg_flag, stage); } else { result1 = find_inline(result2); if (!result1) malloc_strcpy(&result1, empty_string); } new_free(&result2); } else if (ptr && *ptr) { malloc_strcat(&result1, ptr); result2 = next_unit(result1, args, arg_flag, stage); new_free(&result1); result1 = result2; } return result1; case '-': case '+': if (*(ptr+1) == *(ptr)) /* index operator */ { u_char *tptr; *ptr++ = '\0'; if (ptr == str + 1) /* Its a prefix */ { tptr = str + 2; } else /* Its a postfix */ { tptr = str; } result1 = find_inline(tptr); if (!result1) malloc_strcpy(&result1, zero); { /* This isnt supposed to be attached to the if, so dont "fix" it. */ int r; r = my_atoi(result1); if (*ptr == '+') r++; else r--; sprintf(CP(tmp), "%d", r); display = window_display; window_display = 0; add_alias(VAR_ALIAS,tptr,tmp); window_display = display; } /* A kludge? Cheating? Maybe.... */ if (ptr == str + 1) { *(ptr-1) = ' '; *ptr = ' '; } else { if (*ptr == '+') *(ptr-1) = '-'; else *(ptr-1) = '+'; *ptr = '1'; } ptr = str; new_free(&result1); break; } if (ptr == str) /* It's unary..... do nothing */ break; if (stage != NU_ADD) { ptr = lastop(ptr); break; } op = *ptr; *ptr++ = '\0'; result1 = next_unit(str, args, arg_flag, stage); result2 = next_unit(ptr, args, arg_flag, stage); value1 = my_atol(result1); value2 = my_atol(result2); new_free(&result1); new_free(&result2); if (op == '-') value3 = value1 - value2; else value3 = value1 + value2; sprintf(CP(tmp), "%ld", value3); malloc_strcpy(&result1, tmp); return result1; case '/': case '*': case '%': if (stage != NU_MULT) { ptr = lastop(ptr); break; } op = *ptr; *ptr++ = '\0'; result1 = next_unit(str, args, arg_flag, stage); result2 = next_unit(ptr, args, arg_flag, stage); value1 = my_atol(result1); value2 = my_atol(result2); new_free(&result1); new_free(&result2); if (op == '/') { if (value2) value3 = value1 / value2; else { value3 = 0; say("Division by zero"); } } else if (op == '*') value3 = value1 * value2; else { if (value2) value3 = value1 % value2; else { value3 = 0; say("Mod by zero"); } } sprintf(CP(tmp), "%ld", value3); malloc_strcpy(&result1, tmp); return result1; case '#': if (stage != NU_ADD || ptr[1] != '#') { ptr = lastop(ptr); break; } *ptr = '\0'; ptr += 2; result1 = next_unit(str, args, arg_flag, stage); result2 = next_unit(ptr, args, arg_flag, stage); malloc_strcat(&result1, result2); new_free(&result2); return result1; /* Reworked - Jeremy Nelson, Feb 1994 * & or && should both be supported, each with different * stages, same with || and ^^. Also, they should be * short-circuit as well. */ case '&': if (ptr[0] == ptr[1]) { if (stage != NU_CONJ) { ptr = lastop(ptr); break; } *ptr = '\0'; ptr += 2; result1 = next_unit(str, args, arg_flag, stage); value1 = my_atol(result1); if (value1) { result2 = next_unit(ptr, args, arg_flag, stage); value2 = my_atol(result2); value3 = value1 && value2; } else value3 = 0; new_free(&result1); new_free(&result2); tmp[0] = '0' + (value3?1:0); tmp[1] = '\0'; malloc_strcpy(&result1, tmp); return result1; } else { if (stage != NU_BITW) { ptr = lastop(ptr); break; } *ptr = '\0'; ptr += 1; result1 = next_unit(str, args, arg_flag, stage); result2 = next_unit(ptr, args, arg_flag, stage); value1 = my_atol(result1); value2 = my_atol(result2); new_free(&result1); new_free(&result2); value3 = value1 & value2; sprintf(CP(tmp), "%ld",value3); malloc_strcpy(&result1, tmp); return result1; } case '|': if (ptr[0] == ptr[1]) { if (stage != NU_CONJ) { ptr = lastop(ptr); break; } *ptr = '\0'; ptr += 2; result1 = next_unit(str, args, arg_flag, stage); value1 = my_atol(result1); if (!value1) { result2 = next_unit(ptr, args, arg_flag, stage); value2 = my_atol(result2); value3 = value1 || value2; } else value3 = 1; new_free(&result1); new_free(&result2); tmp[0] = '0' + (value3 ? 1 : 0); tmp[1] = '\0'; malloc_strcpy(&result1, tmp); return result1; } else { if (stage != NU_BITW) { ptr = lastop(ptr); break; } *ptr = '\0'; ptr += 1; result1 = next_unit(str, args, arg_flag, stage); result2 = next_unit(ptr, args, arg_flag, stage); value1 = my_atol(result1); value2 = my_atol(result2); new_free(&result1); new_free(&result2); value3 = value1 | value2; sprintf(CP(tmp), "%ld",value3); malloc_strcpy(&result1, tmp); return result1; } case '^': if (ptr[0] == ptr[1]) { if (stage != NU_CONJ) { ptr = lastop(ptr); break; } *ptr = '\0'; ptr += 2; result1 = next_unit(str, args, arg_flag, stage); result2 = next_unit(ptr, args, arg_flag, stage); value1 = my_atol(result1); value2 = my_atol(result2); value1 = value1?1:0; value2 = value2?1:0; value3 = value1 ^ value2; new_free(&result1); new_free(&result2); tmp[0] = '0' + (value3 ? 1 : 0); tmp[1] = '\0'; malloc_strcpy(&result1, tmp); return result1; } else { if (stage != NU_BITW) { ptr = lastop(ptr); break; } *ptr = '\0'; ptr += 1; result1 = next_unit(str, args, arg_flag, stage); result2 = next_unit(ptr, args, arg_flag, stage); value1 = my_atol(result1); value2 = my_atol(result2); new_free(&result1); new_free(&result2); value3 = value1 ^ value2; sprintf(CP(tmp), "%ld",value3); malloc_strcpy(&result1, tmp); return result1; } case '?': if (stage != NU_TERT) { ptr = lastop(ptr); break; } *ptr++ = '\0'; result1 = next_unit(str, args, arg_flag, stage); ptr2 = my_index(ptr, ':'); *ptr2++ = '\0'; right = result1; value1 = parse_number(&right); if ((value1 == -1) && (*right == (u_char) 0)) value1 = 0; if ( value1 == 0 ) while (isspace(*right)) *(right++) = '\0'; if ( value1 || *right ) result2 = next_unit(ptr, args, arg_flag, stage); else result2 = next_unit(ptr2, args, arg_flag, stage); *(ptr2-1) = ':'; new_free(&result1); return result2; case '=': if (ptr[1] != '=') { if (stage != NU_ASSN) { ptr = lastop(ptr); break; } *ptr++ = '\0'; result1 = expand_alias((u_char *) 0, str, args, arg_flag, NULL); result2 = next_unit(ptr, args, arg_flag, stage); display = window_display; window_display = 0; lastc = result1 + my_strlen(result1) - 1; while (lastc > result1 && *lastc == ' ') *lastc-- = '\0'; for (ptr = result1; *ptr == ' '; ptr++); while ((ArrayIndex = my_index(ptr, '[')) != NULL) { *ArrayIndex++='.'; if ((EndIndex = MatchingBracket(ArrayIndex, (int)LEFT_BRACKET, (int)RIGHT_BRACKET)) != NULL) { *EndIndex++='\0'; my_strcat(ptr, EndIndex); } else break; } if (*ptr) add_alias(VAR_ALIAS, ptr, result2); else yell("Invalid assignment expression"); window_display = display; new_free(&result1); return result2; } if (stage != NU_COMP) { ptr = lastop(ptr); break; } *ptr = '\0'; ptr += 2; result1 = next_unit(str, args, arg_flag, stage); result2 = next_unit(ptr, args, arg_flag, stage); if (!my_stricmp(result1, result2)) malloc_strcpy(&result1, one); else malloc_strcpy(&result1, zero); new_free(&result2); return result1; case '>': case '<': if (stage != NU_COMP) { ptr = lastop(ptr); break; } op = *ptr; if (ptr[1] == '=') value3 = 1, *ptr++ = '\0'; else value3 = 0; *ptr++ = '\0'; result1 = next_unit(str, args, arg_flag, stage); result2 = next_unit(ptr, args, arg_flag, stage); if (isdigit(*result1) && isdigit(*result2)) { value1 = my_atol(result1); value2 = my_atol(result2); value1 = (value1 == value2) ? 0 : ((value1 < value2) ? -1 : 1); } else value1 = my_stricmp(result1, result2); if (value1) { value2 = (value1 > 0) ? 1 : 0; if (op == '<') value2 = 1 - value2; } else value2 = value3; new_free(&result2); sprintf(CP(tmp), "%ld", value2); malloc_strcpy(&result1, tmp); return result1; case '~': if (ptr == str) { if (stage != NU_BITW) break; result1 = next_unit(str+1, args, arg_flag, stage); if (isdigit(*result1)) { value1 = my_atol(result1); value2 = ~value1; } else value2 = 0; sprintf(CP(tmp), "%ld", value2); malloc_strcpy(&result1, tmp); return result1; } else { ptr = lastop(ptr); break; } case '!': if (ptr == str) { if (stage != NU_UNIT) break; result1 = next_unit(str+1, args, arg_flag, stage); if (isdigit(*result1)) { value1 = my_atol(result1); value2 = value1 ? 0 : 1; } else { value2 = ((*result1)?0:1); } sprintf(CP(tmp), "%ld", value2); malloc_strcpy(&result1, tmp); return result1; } if (stage != NU_COMP || ptr[1] != '=') { ptr = lastop(ptr); break; } *ptr = '\0'; ptr += 2; result1 = next_unit(str, args, arg_flag, stage); result2 = next_unit(ptr, args, arg_flag, stage); if (!my_stricmp(result1, result2)) malloc_strcpy(&result1, zero); else malloc_strcpy(&result1, one); new_free(&result2); return result1; case ',': /* * this utterly kludge code is needed (?) to get * around bugs introduced from hop's patches to * alias.c. the $, variable stopped working * because of this. -mrg, july 94. */ if (ptr == str || (ptr > str && ptr[-1] == '$')) break; if (stage != NU_EXPR) { ptr = lastop(ptr); break; } *ptr++ = '\0'; result1 = next_unit(str, args, arg_flag, stage); result2 = next_unit(ptr, args, arg_flag, stage); new_free(&result1); return result2; } } if (stage != NU_UNIT) return next_unit(str, args, arg_flag, stage+1); if (isdigit(*str) || *str == '+' || *str == '-') malloc_strcpy(&result1, str); else { if (*str == '#' || *str=='@') op = *str++; else op = '\0'; result1 = find_inline(str); if (!result1) malloc_strcpy(&result1, empty_string); if (op) { if (op == '#') value1 = word_count(result1); else if (op == '@') value1 = my_strlen(result1); sprintf(CP(tmp), "%ld", value1); malloc_strcpy(&result1, tmp); } } return result1; } /* * parse_inline: This evaluates user-variable expression. I'll talk more * about this at some future date. The ^ function and some fixes by * troy@cbme.unsw.EDU.AU (Troy Rollo) */ u_char * parse_inline(str, args, args_flag) u_char *str; u_char *args; int *args_flag; { return next_unit(str, args, args_flag, NU_EXPR); } /* * arg_number: Returns the argument 'num' from 'str', or, if 'num' is * negative, returns from argument 'num' to the end of 'str'. You might be * wondering what's going on down there... here goes. First we copy 'str' to * malloced space. Then, using next_arg(), we strip out each argument , * putting them in arg_list, and putting their position in the original * string in arg_list_pos. Anyway, once parsing is done, the arguments are * returned directly from the arg_list array... or in the case of negative * 'num', the arg_list_pos is used to return the postion of the rest of the * args in the original string... got it? Anyway, the bad points of the * routine: 1) Always parses out everything, even if only one arg is used. * 2) The malloced stuff remains around until arg_number is called with a * different string. Even then, some malloced stuff remains around. This can * be fixed. */ #define LAST_ARG 8000 static u_char * arg_number(lower_lim, upper_lim, str) int lower_lim, upper_lim; u_char *str; { u_char *ptr, *arg, c; int use_full = 0; unsigned int pos, start_pos; static u_char *last_args = (u_char *) 0; static u_char *last_range = (u_char *) 0; static u_char **arg_list = (u_char **) 0; static unsigned int *arg_list_pos = (unsigned int *) 0; static unsigned int *arg_list_end_pos = (unsigned int *) 0; static int arg_list_size; if (eval_args) { int arg_list_limit; eval_args = 0; new_free(&arg_list); new_free(&arg_list_pos); new_free(&arg_list_end_pos); arg_list_size = 0; arg_list_limit = 10; arg_list = (u_char **) new_malloc(sizeof(u_char *) * arg_list_limit); arg_list_pos = (unsigned int *) new_malloc(sizeof(unsigned int) * arg_list_limit); arg_list_end_pos = (unsigned int *) new_malloc(sizeof(unsigned int) * arg_list_limit); malloc_strcpy(&last_args, str); ptr = last_args; pos = 0; while ((arg = alias_arg(&ptr, &start_pos)) != NULL) { arg_list_pos[arg_list_size] = pos; pos += start_pos + my_strlen(arg); arg_list_end_pos[arg_list_size] = pos++; arg_list[arg_list_size++] = arg; if (arg_list_size == arg_list_limit) { arg_list_limit += 10; arg_list = (u_char **) new_realloc((u_char *) arg_list, sizeof(u_char *) * arg_list_limit); arg_list_pos = (unsigned int *) new_realloc(UP(arg_list_pos), sizeof(unsigned int) * arg_list_limit); arg_list_end_pos = (unsigned int *) new_realloc(UP(arg_list_end_pos), sizeof(unsigned int) * arg_list_limit); } } } if (upper_lim == LAST_ARG && lower_lim == LAST_ARG) upper_lim = lower_lim = arg_list_size - 1; if (arg_list_size == 0) return (empty_string); if ((upper_lim >= arg_list_size) || (upper_lim < 0)) { use_full = 1; upper_lim = arg_list_size - 1; } if (upper_lim < lower_lim) return (empty_string); if (lower_lim >= arg_list_size) lower_lim = arg_list_size - 1; else if (lower_lim < 0) lower_lim = 0; if ((use_full == 0) && (lower_lim == upper_lim)) return (arg_list[lower_lim]); c = *(str + arg_list_end_pos[upper_lim]); *(str + arg_list_end_pos[upper_lim]) = (u_char) 0; malloc_strcpy(&last_range, str + arg_list_pos[lower_lim]); *(str + arg_list_end_pos[upper_lim]) = c; return (last_range); } /* * parse_number: returns the next number found in a string and moves the * string pointer beyond that point in the string. Here's some examples: * * "123harhar" returns 123 and str as "harhar" * * while: * * "hoohar" returns -1 and str as "hoohar" */ extern int parse_number(str) u_char **str; { int ret; u_char *ptr; ptr = *str; if (isdigit(*ptr)) { ret = my_atoi(ptr); for (; isdigit(*ptr); ptr++); *str = ptr; } else ret = -1; return (ret); } static void do_alias_string() { malloc_strcpy(&alias_string, get_input()); irc_io_loop = 0; } /* * expander_addition: This handles string width formatting for irc variables * when [] is specified. */ static void expander_addition(buff, add, length, quote_em) #ifndef USE_OLD_ALIAS_ALLOC u_char **buff, #else /* USE_OLD_ALIAS_ALLOC */ u_char *buff, #endif /* USE_OLD_ALIAS_ALLOC */ *add; int length; u_char *quote_em; { u_char format[40], buffer[BIG_BUFFER_SIZE], *ptr; if (length) { sprintf(CP(format), "%%%d.%ds", -length, (length < 0 ? -length : length)); sprintf(CP(buffer), CP(format), add); add = buffer; } if (quote_em) { ptr = double_quote(add, quote_em); #ifndef USE_OLD_ALIAS_ALLOC malloc_strcat(buff, ptr); #else /* USE_OLD_ALIAS_ALLOC */ strmcat(buff, ptr, BIG_BUFFER_SIZE); #endif /* USE_OLD_ALIAS_ALLOC */ new_free(&ptr); } #ifndef USE_OLD_ALIAS_ALLOC else if (add && *add) malloc_strcat(buff, add); #else /* USE_OLD_ALIAS_ALLOC */ else if (buff) strmcat(buff, add, BIG_BUFFER_SIZE); #endif /* USE_OLD_ALIAS_ALLOC */ } /* MatchingBracket returns the next unescaped bracket of the given type */ u_char * MatchingBracket(string, left, right) u_char *string; int left; int right; { int bracket_count = 1; while (*string && bracket_count) { if (*string == (u_char)left) bracket_count++; else if (*string == (u_char)right) { if (!--bracket_count) return string; } else if (*string == '\\' && string[1]) string++; string++; } return (u_char *) 0; } /* * alias_special_char: Here we determin what to do with the character after * the $ in a line of text. The special characters are described more fulling * in the help/ALIAS file. But they are all handled here. Paremeters are the * name of the alias (if applicable) to prevent deadly recursion, a * destination buffer (that we are malloc_str*ing) to which things are appended, * a ptr to the string (the first character of which is the special * character, the args to the alias, and a character indication what * characters in the string should be quoted with a backslash). It returns a * pointer to the character right after the converted alias. The args_flag is set to 1 if any of the $n, $n-, $n-m, $-m, $*, or $() is used in the alias. Otherwise it is left unchanged. */ /*ARGSUSED*/ static u_char * alias_special_char(name, lbuf, ptr, args, quote_em,args_flag) u_char *name; #ifndef USE_OLD_ALIAS_ALLOC u_char **lbuf; #else /* USE_OLD_ALIAS_ALLOC */ u_char *lbuf; #endif /* USE_OLD_ALIAS_ALLOC */ u_char *ptr; u_char *args; u_char *quote_em; int *args_flag; { u_char *tmp, c; int is_upper, is_lower, length; length = 0; if ((c = *ptr) == LEFT_BRACKET) { ptr++; if ((tmp = my_index(ptr, RIGHT_BRACKET)) != NULL) { *(tmp++) = (u_char) 0; length = my_atoi(ptr); #ifdef USE_OLD_ALIAS_ALLOC /* XXX hack to avoid core dumps */ if (length > ((BIG_BUFFER_SIZE * 5) / 3)) length = ((BIG_BUFFER_SIZE * 5) / 3); #endif /* USE_OLD_ALIAS_ALLOC */ ptr = tmp; c = *ptr; } else { say("Missing %c", RIGHT_BRACKET); return (ptr); } } tmp = ptr+1; switch (c) { case LEFT_PAREN: { #ifndef USE_OLD_ALIAS_ALLOC u_char *sub_buffer = (u_char *) 0; #else /* USE_OLD_ALIAS_ALLOC */ u_char sub_buffer[BIG_BUFFER_SIZE+1]; #endif /* USE_OLD_ALIAS_ALLOC */ if ((ptr = MatchingBracket(tmp, (int)LEFT_PAREN, (int)RIGHT_PAREN)) || (ptr = my_index(tmp, RIGHT_PAREN))) *(ptr++) = (u_char) 0; tmp = expand_alias((u_char *) 0, tmp, args, args_flag, NULL); #ifndef USE_OLD_ALIAS_ALLOC malloc_strcpy(&sub_buffer, empty_string); alias_special_char((u_char *) 0, &sub_buffer, tmp, #else /* USE_OLD_ALIAS_ALLOC */ *sub_buffer = (u_char) 0; alias_special_char((u_char *) 0, sub_buffer, tmp, #endif /* USE_OLD_ALIAS_ALLOC */ args, quote_em,args_flag); expander_addition(lbuf, sub_buffer, length, quote_em); #ifndef USE_OLD_ALIAS_ALLOC new_free(&sub_buffer); #endif /* not USE_OLD_ALIAS_ALLOC */ new_free(&tmp); *args_flag = 1; } return (ptr); case '!': if ((ptr = my_index(tmp, '!')) != NULL) *(ptr++) = (u_char) 0; if ((tmp = do_history(tmp, empty_string)) != NULL) { expander_addition(lbuf, tmp, length, quote_em); new_free(&tmp); } return (ptr); case LEFT_BRACE: if ((ptr = my_index(tmp, RIGHT_BRACE)) != NULL) *(ptr++) = (u_char) 0; if ((tmp = parse_inline(tmp, args, args_flag)) != NULL) { expander_addition(lbuf, tmp, length, quote_em); new_free(&tmp); } return (ptr); case DOUBLE_QUOTE: if ((ptr = my_index(tmp, DOUBLE_QUOTE)) != NULL) *(ptr++) = (u_char) 0; alias_string = (u_char *) 0; /* XXX - the cast in the following is an ugly hack! */ if (irc_io(tmp, (void (*) _((u_int, u_char *))) do_alias_string, use_input, 1)) { yell("Illegal recursive edit"); break; } expander_addition(lbuf, alias_string, length, quote_em); new_free(&alias_string); return (ptr); case '*': expander_addition(lbuf, args, length, quote_em); *args_flag = 1; return (ptr + 1); default: if (isdigit(c) || (c == '-') || c == '~') { *args_flag = 1; if (*ptr == '~') { is_lower = is_upper = LAST_ARG; ptr++; } else { is_lower = parse_number(&ptr); if (*ptr == '-') { ptr++; is_upper = parse_number(&ptr); } else is_upper = is_lower; } expander_addition(lbuf, arg_number(is_lower, is_upper, args), length, quote_em); return (ptr ? ptr : empty_string); } else { u_char *rest, c2 = (u_char) 0; /* * Why use ptr+1? Cause try to maintain backward compatability * can be a pain in the butt. Basically, we don't want any of * the illegal characters in the alias, except that things like * $* and $, were around first, so they must remain legal. So * we skip the first char after the $. Does this make sense? */ /* special case for $ */ if (*ptr == '$') { rest = ptr+1; c2 = *rest; *rest = (u_char) 0; } else if ((rest = sindex(ptr+1, alias_illegals)) != NULL) { if (isalpha(*ptr) || *ptr == '_') while ((*rest == LEFT_BRACKET || *rest == LEFT_PAREN) && (tmp = MatchingBracket(rest+1, (int)*rest, (int)(*rest == LEFT_BRACKET) ? RIGHT_BRACKET : RIGHT_PAREN))) rest = tmp + 1; c2 = *rest; *rest = (u_char) 0; } if ((tmp = parse_inline(ptr, args, args_flag)) != NULL) { expander_addition(lbuf, tmp, length, quote_em); new_free(&tmp); } if (rest) *rest = c2; return(rest); } } return NULL; } /* * expand_alias: Expands inline variables in the given string and returns the * expanded string in a new string which is malloced by expand_alias(). * * Also unescapes anything that was quoted with a backslash * * Behaviour is modified by the following: * Anything between brackets (...) {...} is left unmodified. * If more_text is supplied, the text is broken up at * semi-colons and returned one at a time. The unprocessed * portion is written back into more_text. * Backslash escapes are unescaped. */ u_char * expand_alias(name, string, args, args_flag, more_text) u_char *name, *string, *args; int *args_flag; u_char **more_text; { #ifndef USE_OLD_ALIAS_ALLOC u_char *lbuf = (u_char *) 0, #else /* USE_OLD_ALIAS_ALLOC */ u_char lbuf[BIG_BUFFER_SIZE + 1], #endif /* USE_OLD_ALIAS_ALLOC */ *ptr, *stuff = (u_char *) 0, *free_stuff; u_char *quote_em, *quote_str = (u_char *) 0; u_char ch; int quote_cnt = 0; int is_quote = 0; #ifndef USE_OLD_ALIAS_ALLOC void (*str_cat) _((u_char **, u_char *)); #else /* USE_OLD_ALIAS_ALLOC */ void (*str_cat) _((u_char *, u_char *, size_t)); #endif /* USE_OLD_ALIAS_ALLOC */ if (*string == '@' && more_text) { #ifndef USE_OLD_ALIAS_ALLOC str_cat = malloc_strcat; #else /* USE_OLD_ALIAS_ALLOC */ str_cat = strmcat; #endif /* USE_OLD_ALIAS_ALLOC */ *args_flag = 1; /* Stop the @ command from auto appending */ } else #ifndef USE_OLD_ALIAS_ALLOC str_cat = malloc_strcat_ue; #else /* USE_OLD_ALIAS_ALLOC */ str_cat = strmcat_ue; #endif /* USE_OLD_ALIAS_ALLOC */ malloc_strcpy(&stuff, string); free_stuff = stuff; #ifndef USE_OLD_ALIAS_ALLOC malloc_strcpy(&lbuf, empty_string); #else /* USE_OLD_ALIAS_ALLOC */ *lbuf = (u_char) 0; #endif /* USE_OLD_ALIAS_ALLOC */ eval_args = 1; ptr = stuff; if (more_text) *more_text = NULL; while (ptr && *ptr) { if (is_quote) { is_quote = 0; ++ptr; continue; } switch(*ptr) { case '$': /* * The test here ensures that if we are in the expression * evaluation command, we don't expand $. In this case we * are only coming here to do command separation at ';'s. * If more_text is not defined, and the first character is * '@', we have come here from [] in an expression. */ if (more_text && *string == '@') { ptr++; break; } *(ptr++) = (u_char) 0; #ifndef USE_OLD_ALIAS_ALLOC (*str_cat)(&lbuf, stuff); #else /* USE_OLD_ALIAS_ALLOC */ (*str_cat)(lbuf, stuff, BIG_BUFFER_SIZE); #endif /* USE_OLD_ALIAS_ALLOC */ while (*ptr == '^') { ptr++; if (quote_str) quote_str = (u_char *) new_realloc(quote_str, sizeof(u_char) * (quote_cnt + 2)); else quote_str = (u_char *) new_malloc(sizeof(u_char) * (quote_cnt + 2)); quote_str[quote_cnt++] = *(ptr++); quote_str[quote_cnt] = (u_char) 0; } quote_em = quote_str; #ifndef USE_OLD_ALIAS_ALLOC stuff = alias_special_char(name, &lbuf, ptr, args, #else /* USE_OLD_ALIAS_ALLOC */ stuff = alias_special_char(name, lbuf, ptr, args, #endif /* USE_OLD_ALIAS_ALLOC */ quote_em, args_flag); if (stuff) new_free("e_str); quote_cnt = 0; ptr = stuff; break; case ';': if (!more_text) { ptr++; break; } *more_text = string + (ptr - free_stuff) +1; *ptr = '\0'; /* To terminate the loop */ break; case LEFT_PAREN: case LEFT_BRACE: ch = *ptr; *ptr = '\0'; #ifndef USE_OLD_ALIAS_ALLOC (*str_cat)(&lbuf, stuff); #else /* USE_OLD_ALIAS_ALLOC */ (*str_cat)(lbuf, stuff, BIG_BUFFER_SIZE); #endif /* USE_OLD_ALIAS_ALLOC */ stuff = ptr; *args_flag = 1; if (!(ptr = MatchingBracket(stuff + 1, (int)ch, (int)(ch == LEFT_PAREN) ? RIGHT_PAREN : RIGHT_BRACE))) { yell("Unmatched %c", ch); ptr = stuff + my_strlen(stuff+1)+1; } else ptr++; *stuff = ch; ch = *ptr; *ptr = '\0'; #ifndef USE_OLD_ALIAS_ALLOC malloc_strcat(&lbuf, stuff); #else /* USE_OLD_ALIAS_ALLOC */ strmcat(lbuf, stuff, BIG_BUFFER_SIZE); #endif /* USE_OLD_ALIAS_ALLOC */ stuff = ptr; *ptr = ch; break; case '\\': is_quote = 1; ptr++; break; default: ptr++; break; } } if (stuff) #ifndef USE_OLD_ALIAS_ALLOC (*str_cat)(&lbuf, stuff); #else /* USE_OLD_ALIAS_ALLOC */ (*str_cat)(lbuf, stuff, BIG_BUFFER_SIZE); #endif /* USE_OLD_ALIAS_ALLOC */ ptr = (u_char *) 0; new_free(&free_stuff); #ifndef USE_OLD_ALIAS_ALLOC ptr = lbuf; #else /* USE_OLD_ALIAS_ALLOC */ malloc_strcpy(&ptr, lbuf); #endif /* USE_OLD_ALIAS_ALLOC */ if (get_int_var(DEBUG_VAR) & DEBUG_EXPANSIONS) yell("Expanded [%s] to [%s]", string, ptr); return (ptr); } /* * get_alias: returns the alias matching 'name' as the function value. 'args' * are expanded as needed, etc. If no matching alias is found, null is * returned, cnt is 0, and full_name is null. If one matching alias is * found, it is retuned, with cnt set to 1 and full_name set to the full name * of the alias. If more than 1 match are found, null is returned, cnt is * set to the number of matches, and fullname is null. NOTE: get_alias() * mallocs the space for the full_name, but returns the actual value of the * alias if found! */ u_char * get_alias(type, name, cnt, full_name) int type; u_char *name, **full_name; int *cnt; { Alias *tmp; *full_name = (u_char *) 0; if ((name == (u_char *) 0) || (*name == (u_char) 0)) { *cnt = 0; return ((u_char *) 0); } if ((tmp = find_alias(&(alias_list[type]), name, 0, cnt)) != NULL) { if (*cnt < 2) { malloc_strcpy(full_name, tmp->name); return (tmp->stuff); } } return ((u_char *) 0); } /* * match_alias: this returns a list of alias names that match the given name. * This is used for command completion etc. Note that the returned array is * malloced in this routine. Returns null if no matches are found */ u_char ** match_alias(name, cnt, type) u_char *name; int *cnt; int type; { Alias *tmp; u_char **matches = (u_char **) 0; int matches_size = 5; size_t len; u_char *last_match = (u_char *) 0; u_char *dot; len = my_strlen(name); *cnt = 0; matches = (u_char **) new_malloc(sizeof(u_char *) * matches_size); for (tmp = alias_list[type]; tmp; tmp = tmp->next) { if (my_strncmp(name, tmp->name, len) == 0) { if ((dot = my_index(tmp->name+len, '.')) != NULL) { if (type == COMMAND_ALIAS) continue; else { *dot = '\0'; if (last_match && !my_strcmp(last_match, tmp->name)) { *dot = '.'; continue; } } } matches[*cnt] = (u_char *) 0; malloc_strcpy(&(matches[*cnt]), tmp->name); last_match = matches[*cnt]; if (dot) *dot = '.'; if (++(*cnt) == matches_size) { matches_size += 5; matches = (u_char **) new_realloc(UP(matches), sizeof(u_char *) * matches_size); } } else if (*cnt) break; } if (*cnt) { matches = (u_char **) new_realloc(UP(matches), sizeof(u_char *) * (*cnt + 1)); matches[*cnt] = (u_char *) 0; } else new_free(&matches); return (matches); } /* delete_alias: The alias name is removed from the alias list. */ void delete_alias(type, name) int type; u_char *name; { Alias *tmp; upper(name); if ((tmp = find_alias(&(alias_list[type]), name, 1, (int *) NULL)) != NULL) { new_free(&(tmp->name)); new_free(&(tmp->stuff)); new_free(&tmp); if (type == COMMAND_ALIAS) say("Alias %s removed", name); else say("Assign %s removed", name); } else say("No such alias: %s", name); } /* * list_aliases: Lists all aliases matching 'name'. If name is null, all * aliases are listed */ void list_aliases(type, name) int type; u_char *name; { Alias *tmp; size_t len; int lastlog_level; size_t DotLoc, LastDotLoc = 0; u_char *LastStructName = NULL; u_char *s; lastlog_level = message_from_level(LOG_CRAP); if (type == COMMAND_ALIAS) say("Aliases:"); else say("Assigns:"); if (name) { upper(name); len = my_strlen(name); } else len = 0; for (tmp = alias_list[type]; tmp; tmp = tmp->next) { if (!name || !my_strncmp(tmp->name, name, len)) { s = my_index(tmp->name + len, '.'); if (!s) say("\t%s\t%s", tmp->name, tmp->stuff); else { DotLoc = s - tmp->name; if (!LastStructName || (DotLoc != LastDotLoc) || my_strncmp(tmp->name, LastStructName, DotLoc)) { say("\t%*.*s\t", DotLoc, DotLoc, tmp->name); LastStructName = tmp->name; LastDotLoc = DotLoc; } } } } (void)message_from_level(lastlog_level); } /* * mark_alias: sets the mark field of the given alias to 'flag', and returns * the previous value of the mark. If the name is not found, -1 is returned. * This is used to prevent recursive aliases by marking and unmarking * aliases, and not reusing an alias that has previously been marked. I'll * explain later */ int mark_alias(name, flag) u_char *name; int flag; { int old_mark; Alias *tmp; int match; if ((tmp = find_alias(&(alias_list[COMMAND_ALIAS]), name, 0, &match)) != NULL) { if (match < 2) { old_mark = tmp->mark; /* New handling of recursion */ if (flag) { int i; /* Count recursion */ tmp->mark = tmp->mark + flag; if ((i = get_int_var(MAX_RECURSIONS_VAR)) > 1) { if (tmp->mark > i) { tmp->mark = 0; return(1); /* MAX exceeded. */ } else return(0); /* In recursion but it's ok */ } else { if (tmp->mark > 1) { tmp->mark = 0; return(1); /* max of 1 here.. exceeded */ } else return(0); /* In recursion but it's ok */ } } else /* Not in recursion at all */ { tmp->mark = 0; return(old_mark); /* This one gets ignored anyway */ } } } return (-1); } /* * execute_alias: After an alias has been identified and expanded, it is sent * here for proper execution. This routine mainly prevents recursive * aliasing. The name is the full name of the alias, and the alias is * already expanded alias (both of these parameters are returned by * get_alias()) */ void execute_alias(alias_name, ealias, args) u_char *alias_name, *ealias, *args; { if (mark_alias(alias_name, 1)) say("Maximum recursion count exceeded in: %s", alias_name); else { parse_line(alias_name, ealias, args, 0,1); mark_alias(alias_name, 0); } } /* * save_aliases: This will write all of the aliases to the FILE pointer fp in * such a way that they can be read back in using LOAD or the -l switch */ void save_aliases(fp, do_all) FILE *fp; int do_all; { Alias *tmp; for (tmp = alias_list[VAR_ALIAS]; tmp; tmp = tmp->next) if (!tmp->global || do_all) fprintf(fp, "ASSIGN %s %s\n", tmp->name, tmp->stuff); for (tmp = alias_list[COMMAND_ALIAS]; tmp; tmp = tmp->next) if (!tmp->global || do_all) fprintf(fp, "ALIAS %s %s\n", tmp->name, tmp->stuff); } /* The Built-In Alias expando functions */ static u_char * alias_line() { return (get_input()); } static u_char * alias_buffer() { return (cut_buffer); } static u_char * alias_time() { static u_char timestr[16]; return (update_clock(timestr, 16, GET_TIME)); } static u_char * alias_dollar() { return (UP("$")); } static u_char * alias_detected() { return (last_notify_nick); } static u_char * alias_nick() { return ((from_server >= 0) ? get_server_nickname(from_server) : nickname); } static u_char * alias_away() { return ((from_server >= 0) ? server_list[from_server].away : empty_string); } static u_char * alias_sent_nick() { return (sent_nick) ? sent_nick : empty_string; } static u_char * alias_recv_nick() { return (recv_nick) ? recv_nick : empty_string; } static u_char * alias_msg_body() { return (sent_body) ? sent_body : empty_string; } static u_char * alias_joined_nick() { return (joined_nick) ? joined_nick : empty_string; } static u_char * alias_public_nick() { return (public_nick) ? public_nick : empty_string; } static u_char * alias_channel() { u_char *tmp; return ((tmp = get_channel_by_refnum(0)) ? tmp : zero); } static u_char * alias_server() { return ((parsing_server_index != -1) ? get_server_itsname(parsing_server_index) : (get_window_server(0) != -1) ? get_server_itsname(get_window_server(0)) : empty_string); } static u_char * alias_query_nick() { u_char *tmp; return ((tmp = query_nick()) ? tmp : empty_string); } static u_char * alias_target() { u_char *tmp; return ((tmp = get_target_by_refnum(0)) ? tmp : empty_string); } static u_char * alias_invite() { return ((invite_channel) ? invite_channel : empty_string); } static u_char * alias_cmdchar() { static u_char thing[2]; u_char *cmdchars; if ((cmdchars = get_string_var(CMDCHARS_VAR)) == (u_char *) 0) cmdchars = UP(DEFAULT_CMDCHARS); thing[0] = cmdchars[0]; thing[1] = (u_char) 0; return (thing); } static u_char * alias_oper() { return ((from_server >= 0 && get_server_operator(from_server)) ? get_string_var(STATUS_OPER_VAR) : empty_string); } static u_char * alias_chanop() { u_char *tmp; return ((from_server >= 0 && (tmp = get_channel_by_refnum(0)) && get_channel_oper(tmp, from_server)) ? UP("@") : empty_string); } static u_char * alias_modes() { u_char *tmp; return ((from_server >= 0 && (tmp = get_channel_by_refnum(0))) ? get_channel_mode(tmp, from_server) : empty_string); } static u_char * alias_version() { return (internal_version); } static u_char * alias_currdir() { static u_char dirbuf[1024]; getcwd(CP(dirbuf), 1024+1); return (dirbuf); } static u_char * alias_current_numeric() { static u_char number[4]; sprintf(CP(number), "%03d", -current_numeric); return (number); } static u_char * alias_server_version() { u_char *s; return ((curr_scr_win->server >= 0 && (s = server_list[curr_scr_win->server].version_string)) ? s : empty_string); } /* * alias: the /ALIAS command. Calls the correct alias function depending on * the args */ void alias(command, args, subargs) u_char *command, *args, *subargs; { u_char *name, *rest; int type; u_char *ArrayIndex; u_char *EndIndex; type = *command - 48; /* * A trick! Yes, well, what the hell. Note * the the command part of ALIAS is "0" and * the command part of ASSIGN is "1" in the * command array list */ if ((name = next_arg(args, &rest)) != NULL) { while ((ArrayIndex = my_index(name, '[')) != NULL) { *ArrayIndex++ = '.'; if ((EndIndex = MatchingBracket(ArrayIndex, (int)LEFT_BRACKET, (int)RIGHT_BRACKET)) != NULL) { *EndIndex++ = '\0'; my_strcat(name, EndIndex); } else break; } if (*rest) { if (*rest == LEFT_BRACE) { u_char *ptr; ptr = MatchingBracket(++rest, (int)LEFT_BRACE, (int)RIGHT_BRACE); if (!ptr) say("Unmatched brace in ALIAS or ASSIGN"); else if (ptr[1]) { say("Junk after closing brace in ALIAS or ASSIGN"); } else { *ptr = '\0'; add_alias(type, name, rest); } } else add_alias(type, name, rest); } else { if (*name == '-') { if (*(name + 1)) delete_alias(type, name + 1); else say("You must specify an alias to be removed"); } else list_aliases(type, name); } } else list_aliases(type, (u_char *) 0); } u_char * function_left(input) u_char *input; { u_char *result = (u_char *) 0; u_char *count; int cvalue; count = next_arg(input, &input); if (count) cvalue = my_atoi(count); else cvalue = 0; if ((int) my_strlen(input) > cvalue) input[cvalue] = '\0'; malloc_strcpy(&result, input); return (result); } u_char * function_right(input) u_char *input; { u_char *result = (u_char *) 0; u_char *count; int cvalue; int len; count = next_arg(input, &input); if (count) cvalue = my_atoi(count); else cvalue = 0; if ((len = (int) my_strlen(input)) > cvalue) input += len - cvalue; malloc_strcpy(&result, input); return (result); } u_char * function_mid(input) u_char *input; { u_char *result = (u_char *) 0; u_char *mid_index; int ivalue; u_char *count; int cvalue; mid_index = next_arg(input, &input); if (mid_index) ivalue = my_atoi(mid_index); else ivalue = 0; count = next_arg(input, &input); if (count) cvalue = my_atoi(count); else cvalue = 0; if ((int) my_strlen(input) > ivalue) input += ivalue; else *input = '\0'; if ((int) my_strlen(input) > cvalue) input[cvalue] = '\0'; malloc_strcpy(&result, input); return (result); } /* patch from Sarayan to make $rand() better */ #define RAND_A 16807L #define RAND_M 2147483647L #define RAND_Q 127773L #define RAND_R 2836L static long randm(l) long l; { static u_long z = 0; long t; #ifndef __MSDOS__ if (!z) z = (u_long) getuid(); #endif /* __MSDOS__ */ if (!l) { t = RAND_A * (z % RAND_Q) - RAND_R * (z / RAND_Q); if (t > 0) z = t; else z = t + RAND_M; return (z >> 8) | ((z & 255) << 23); } else { if (l < 0) #ifdef __MSDOS__ z = 0; #else z = (u_long) getuid(); #endif /* __MSDOS__ */ else z = l; return 0; } } u_char * function_rand(input) u_char *input; { u_char *result = (u_char *) 0; u_char tmp[40]; long tempin; #ifdef _Windows sprintf(CP(tmp), "%ld", random(my_atol(input))); #else sprintf(CP(tmp), "%ld", (tempin = my_atol(input)) ? randm(0L) % tempin : 0); #endif /* _Windows */ malloc_strcpy(&result, tmp); return (result); } u_char * function_srand(input) u_char *input; { u_char *result = (u_char *) 0; if (input && *input) (void) randm(my_atol(input)); else (void) randm((long) time(NULL)); malloc_strcpy(&result, empty_string); return (result); } /*ARGSUSED*/ u_char * function_time(input) u_char *input; { u_char *result = (u_char *) 0; time_t ltime; u_char tmp[40]; (void) time(<ime); sprintf(CP(tmp), "%ld", (long)ltime); malloc_strcpy(&result, tmp); return (result); } u_char * function_stime(input) u_char *input; { u_char *result = (u_char *) 0; time_t ltime; ltime = my_atol(input); malloc_strcpy(&result, UP(ctime(<ime))); result[my_strlen(result) - 1] = (u_char) 0; return (result); } u_char * function_tdiff(input) u_char *input; { u_char *result = (u_char *) 0; time_t ltime; time_t days, hours, minutes, seconds; u_char tmp[80]; u_char *tstr; ltime = my_atol(input); seconds = ltime % 60; ltime = (ltime - seconds) / 60; minutes = ltime%60; ltime = (ltime - minutes) / 60; hours = ltime % 24; days = (ltime - hours) / 24; tstr = tmp; if (days) { sprintf(CP(tstr), "%ld day%s ", (long) days, (days==1)?"":"s"); tstr += my_strlen(tstr); } if (hours) { sprintf(CP(tstr), "%ld hour%s ", (long) hours, (hours==1)?"":"s"); tstr += my_strlen(tstr); } if (minutes) { sprintf(CP(tstr), "%ld minute%s ", (long) minutes, (minutes==1)?"":"s"); tstr += my_strlen(tstr); } if (seconds || (!days && !hours && !minutes)) { sprintf(CP(tstr), "%ld second%s", (long) seconds, (seconds==1)?"":"s"); tstr += my_strlen(tstr); } malloc_strcpy(&result, tmp); return (result); } u_char * function_index(input) u_char *input; { u_char *result = (u_char *) 0; u_char *schars; u_char *iloc; int ival; u_char tmp[40]; schars = next_arg(input, &input); iloc = (schars) ? sindex(input, schars) : NULL; ival = (iloc) ? iloc - input : -1; sprintf(CP(tmp), "%d", ival); malloc_strcpy(&result, tmp); return (result); } u_char * function_rindex(input) u_char *input; { u_char *result = (u_char *) 0; u_char *schars; u_char *iloc; int ival; u_char tmp[40]; schars = next_arg(input, &input); iloc = (schars) ? srindex(input, schars) : NULL; ival = (iloc) ? iloc - input : -1; sprintf(CP(tmp), "%d", ival); malloc_strcpy(&result, tmp); return (result); } u_char * function_match(input) u_char *input; { u_char *result = (u_char *) 0; u_char *pattern; u_char *word; int current_match; int best_match = 0; int match = 0; int match_index = 0; u_char tmp[40]; if ((pattern = next_arg(input, &input)) != NULL) { while ((word = next_arg(input, &input)) != NULL) { match_index++; if ((current_match = wild_match(pattern, word)) > best_match) { match = match_index; best_match = current_match; } } } sprintf(CP(tmp), "%d", match); malloc_strcpy(&result, tmp); return (result); } u_char * function_rmatch(input) u_char *input; { u_char *result = (u_char *) 0; u_char *pattern; u_char *word; int current_match; int best_match = 0; int match = 0; int rmatch_index = 0; u_char tmp[40]; if ((pattern = next_arg(input, &input)) != NULL) { while ((word = next_arg(input, &input)) != NULL) { rmatch_index++; if ((current_match = wild_match(word, pattern)) > best_match) { match = rmatch_index; best_match = current_match; } } } sprintf(CP(tmp), "%d", match); malloc_strcpy(&result, tmp); return (result); } /*ARGSUSED*/ u_char * function_userhost(input) u_char *input; { u_char *result = (u_char *) 0; malloc_strcpy(&result, FromUserHost ? FromUserHost : empty_string); return (result); } u_char * function_strip(input) u_char *input; { u_char tmpbuf[128], *result; u_char *retval = (u_char *) 0; u_char *chars; u_char *cp, *dp; size_t len = 0; if ((chars = next_arg(input, &input)) && input) { len = my_strlen(input); if (len > 127) result = (u_char *) new_malloc(len + 1); else result = tmpbuf; for (cp = input, dp = result; *cp; cp++) { if (!my_index(chars, *cp)) *dp++ = *cp; } *dp = '\0'; } malloc_strcpy(&retval, result); if (len > 127) new_free(&result); /* we could use this copy, but it might be extra-long */ return (retval); } u_char * function_encode(input) u_char *input; { u_char *result; u_char *c; int i = 0; result = (u_char *) new_malloc(my_strlen(input) * 2 + 1); for (c = input; *c; c++) { result[i++] = (*c >> 4) + 0x41; result[i++] = (*c & 0x0f) + 0x41; } result[i] = '\0'; return (result); } u_char * function_decode(input) u_char *input; { u_char *result; u_char *c; u_char d,e; int i = 0; c = input; result = (u_char *) new_malloc(my_strlen(input) / 2 + 2); while((d = *c) && (e = *(c+1))) { result[i] = ((d - 0x41) << 4) | (e - 0x41); c += 2; i++; } result[i] = '\0'; return (result); } u_char * function_ischannel(input) u_char *input; { u_char *result = (u_char *) 0; malloc_strcpy(&result, is_channel(input) ? one : zero); return (result); } u_char * function_ischanop(input) u_char *input; { u_char *result = (u_char *) 0; u_char *nick; u_char *channel = NULL; if (!(nick = next_arg(input, &channel))) malloc_strcpy(&result, zero); else malloc_strcpy(&result, is_chanop(channel, nick) ? one : zero); return (result); } #ifdef HAVE_CRYPT #if 0 extern char *crypt(const char *key, const char *salt); #endif u_char * function_crypt(input) u_char *input; { u_char *result = (u_char *) 0; u_char *salt; u_char *key = NULL; if (!(salt = next_arg(input, &key))) malloc_strcpy(&result, zero); else malloc_strcpy(&result, UP(crypt(key, salt))); return (result); } #endif /* HAVE_CRYPT */ u_char * function_hasvoice(input) u_char *input; { u_char *result = (u_char *) 0; u_char *nick; u_char *channel = NULL; if (!(nick = next_arg(input, &channel))) malloc_strcpy(&result, zero); else malloc_strcpy(&result, has_voice(channel, nick) ? one : zero); return (result); } u_char * function_dcclist(Nick) u_char *Nick; { u_char *result; DCC_list *Client; size_t len = 0; int i; if (!Nick) { malloc_strcpy(&result, zero); return (result); } for (i = 0, Client = ClientList; Client != NULL; Client = Client->next) if (!my_stricmp(Nick, Client->user)) len += 3; result = (u_char *) new_malloc(len + 1); for (i = 0, Client = ClientList; Client != NULL; Client = Client->next) if (!my_stricmp(Nick, Client->user)) { int b = Client->flags; int a = (b & DCC_TYPES); result[i++] = (a == DCC_CHAT) ? 'C' /* CHAT */ : (a == DCC_FILEOFFER) ? 'S' /* SEND */ : (a == DCC_FILEREAD) ? 'G' /* GET */ : (a == DCC_TALK) ? 'T' /* TALK */ : (a == DCC_SUMMON) ? 'U' /* SUMMON */ : (a == DCC_RAW_LISTEN) ? 'L' /* RAW_LISTEN */ : (a == DCC_RAW) ? 'R' /* RAW */ : 'x'; result[i++] = (b & DCC_DELETE) ? 'C' /* CLOSED */ : (b & DCC_ACTIVE) ? 'A' /* ACTIVE */ : (b & DCC_WAIT) ? 'W' /* WAITING */ : (b & DCC_OFFER) ? 'O' /* OFFERED */ : 'x'; result[i++] = ' '; } result[i] = '\0'; return (result); } u_char * function_chatpeers(dummy) u_char *dummy; { u_char *result; DCC_list *Client; int notfirst = 0; size_t len = 0; /* calculate size */ for (Client = ClientList; Client != NULL; Client = Client->next) if ((Client->flags & (DCC_CHAT|DCC_ACTIVE)) == (DCC_CHAT|DCC_ACTIVE)) len += (my_strlen(Client->user) + 1); result = (u_char *) new_malloc(len); *result = '\0'; for (Client = ClientList; Client != NULL; Client = Client->next) if ((Client->flags & (DCC_CHAT|DCC_ACTIVE)) == (DCC_CHAT|DCC_ACTIVE)) { if (notfirst) my_strcat(result, ","); else notfirst = 1; my_strcat(result, Client->user); } return (result); } u_char * function_word(input) u_char *input; { u_char *result = (u_char *) 0; u_char *count; int cvalue; u_char *word; count = next_arg(input, &input); if (count) cvalue = my_atoi(count); else cvalue = 0; if (cvalue < 0) malloc_strcpy(&result, empty_string); else { for (word = next_arg(input, &input); word && cvalue--; word = next_arg(input, &input)) ; malloc_strcpy(&result, (word) ? word : empty_string); } return (result); } u_char * function_querynick(input) u_char *input; { u_char *result = (u_char *) 0; Window *win; if (input && isdigit(*input)) win = get_window_by_refnum((u_int)my_atoi(input)); else win = curr_scr_win; malloc_strcpy(&result, win ? win->query_nick : UP("-1")); return (result); } u_char * function_winserver(input) u_char *input; { u_char *result = (u_char *) 0; u_char tmp[10]; Window *win; if (input && isdigit(*input)) win = get_window_by_refnum((u_int)my_atoi(input)); else win = curr_scr_win; sprintf(CP(tmp), "%d", win ? win->server : -1); malloc_strcpy(&result, tmp); return (result); } u_char * function_winservergroup(input) u_char *input; { u_char *result = (u_char *) 0; u_char tmp[10]; Window *win; if (input && isdigit(*input)) win = get_window_by_refnum((u_int)my_atoi(input)); else win = curr_scr_win; sprintf(CP(tmp), "%d", win ? win->server_group : -1); malloc_strcpy(&result, tmp); return (result); } u_char * function_winvisible(input) u_char *input; { u_char *result = (u_char *) 0; u_char tmp[10]; Window *win; if (input && isdigit(*input)) win = get_window_by_refnum((u_int)my_atoi(input)); else win = curr_scr_win; sprintf(CP(tmp), "%d", win ? win->visible : -1); malloc_strcpy(&result, tmp); return (result); } u_char * function_winnum(input) u_char *input; { u_char *result = (u_char *) 0; u_char tmp[10]; sprintf(CP(tmp), "%d", curr_scr_win ? (int)curr_scr_win->refnum : -1); malloc_strcpy(&result, tmp); return (result); } u_char * function_winnam(input) u_char *input; { u_char *result = (u_char *) 0; Window *win; if (input && isdigit(*input)) win = get_window_by_refnum((u_int)my_atoi(input)); else win = curr_scr_win; malloc_strcpy(&result, (win && win->name) ? win->name : empty_string); return (result); } /* * returns the current window's display (len) size counting for double * status bars, etc.. -Toasty */ u_char * function_winrows(input) u_char *input; { u_char *result = (u_char *) 0; if (curr_scr_win) { u_char tmp[10]; sprintf(CP(tmp), "%d", curr_scr_win->display_size); malloc_strcpy(&result, tmp); } else malloc_strcpy(&result, UP("-1")); return (result); } /* * returns the current screen's (since all windows have the same * column/width) column value -Toasty */ u_char * function_wincols(input) u_char *input; { u_char *result = (u_char *) 0; if (curr_scr_win) { u_char tmp[10]; sprintf(CP(tmp), "%d", current_screen->co); malloc_strcpy(&result, tmp); } else malloc_strcpy(&result, UP("-1")); return (result); } u_char * function_connect(input) u_char *input; { u_char *result = (u_char *) 0; u_char *host; #ifdef DAEMON_UID if (getuid() == DAEMON_UID) put_it("You are not permitted to use CONNECT()"); else #endif /* DAEMON_ID */ if ((host = next_arg(input, &input)) != NULL) result = dcc_raw_connect(host, (u_int) my_atoi(input)); return (result); } u_char * function_listen(input) u_char *input; { u_char *result = (u_char *) 0; #ifdef DAEMON_UID if (getuid() == DAEMON_UID) malloc_strcpy(&result, zero); else #endif /* DAEMON_ID */ result = dcc_raw_listen((u_int) my_atoi(input)); return (result); } u_char * function_toupper(input) u_char *input; { u_char *new = (u_char *) 0, *ptr; if (!input) return empty_string; malloc_strcpy(&new, input); for (ptr = new; *ptr; ptr++) *ptr = islower(*ptr) ? toupper(*ptr) : *ptr; return new; } u_char * function_tolower(input) u_char *input; { u_char *new = (u_char *) 0, *ptr; if (!input) return empty_string; malloc_strcpy(&new, input); for (ptr = new; *ptr; ptr++) *ptr = (isupper(*ptr)) ? tolower(*ptr) : *ptr; return new; } u_char * function_curpos(input) u_char *input; { u_char *new = (u_char *) 0, pos[4]; sprintf(CP(pos), "%d", current_screen->buffer_pos); malloc_strcpy(&new, pos); return new; } u_char * function_channels(input) u_char *input; { Window *window; if (input) window = isdigit(*input) ? get_window_by_refnum((u_int) my_atoi(input)) : curr_scr_win; else window = curr_scr_win; return create_channel_list(window); } u_char * function_servers(input) u_char *input; { return create_server_list(); } u_char * function_servertype(input) u_char *input; { int server; u_char *s; u_char *result = NULL; if (from_server < 0) server = primary_server; else server = from_server; if (server < 0) s = empty_string; else switch (server_list[server].version) { case ServerICB: s = UP("ICB"); break; case Server2_5: s = UP("IRC2.5"); break; case Server2_6: s = UP("IRC2.6"); break; case Server2_7: s = UP("IRC2.7"); break; case Server2_8: s = UP("IRC2.8"); break; case Server2_9: s = UP("IRC2.9"); break; case Server2_10: s = UP("IRC2.10"); break; case Server2_11: s = UP("IRC2.11"); break; } malloc_strcpy(&result, s); return (result); } u_char * function_onchannel(input) u_char *input; { u_char *result = (u_char *) 0; u_char *nick; u_char *channel = NULL; if (from_server < 0 || !(nick = next_arg(input, &channel))) malloc_strcpy(&result, zero); else malloc_strcpy(&result, is_on_channel(channel, from_server, nick) ? one : zero); return (result); } u_char * function_pid(input) u_char *input; { u_char *result = (u_char *) 0; u_char lbuf[32]; /* plenty big enough for %d */ sprintf(CP(lbuf), "%d", (int) getpid()); malloc_strcpy(&result, lbuf); return (result); } u_char * function_ppid(input) u_char *input; { u_char *result = (u_char *) 0; u_char lbuf[32]; /* plenty big enough for %d */ sprintf(CP(lbuf), "%d", (int) getppid()); malloc_strcpy(&result, lbuf); return (result); } u_char * function_chanusers(input) u_char *input; { ChannelList *chan; NickList *nicks; u_char *result = (u_char *) 0; int len = 0; int notfirst = 0; chan = lookup_channel(input, from_server, CHAN_NOUNLINK); if ((ChannelList *) 0 == chan) return (u_char *) 0; for (nicks = chan->nicks; nicks; nicks = nicks->next) len += (my_strlen(nicks->nick) + 1); result = (u_char *) new_malloc(len + 1); *result = '\0'; for (nicks = chan->nicks; nicks; nicks = nicks->next) { if (notfirst) my_strcat(result, " "); else notfirst = 1; my_strcat(result, nicks->nick); } return (result); } /* * strftime() patch from hari (markc@arbld.unimelb.edu.au) */ #ifdef HAVE_STRFTIME u_char * function_strftime(input) u_char *input; { u_char result[128]; time_t ltime; u_char *fmt = (u_char *) 0; ltime = my_atol(input); fmt = input; /* skip the time field */ while (isdigit(*fmt)) ++fmt; if (*fmt && *++fmt) { struct tm *tm; tm = localtime(<ime); if (strftime(CP(result), 128, CP(fmt), tm)) { u_char *s = (u_char *) 0; malloc_strcpy(&s, result); return s; } else return (u_char *) 0; } else { return (u_char *) 0; } } #endif /* HAVE_STRFTIME */ /* * idle() patch from scottr (scott.reynolds@plexus.com) */ u_char * function_idle(input) u_char *input; { u_char *result = (u_char *) 0; u_char lbuf[20]; sprintf(CP(lbuf), "%ld", (long)(time(0) - idle_time)); malloc_strcpy(&result, lbuf); return (result); } .