/* * alias.c Handles command aliases for irc.c * * Written By Michael Sandrof * * Copyright(c) 1990 * * See the COPYRIGHT file, or do a HELP IRCII COPYRIGHT */ #ifndef lint static char rcsid[] = "@(#)$Id: alias.c,v 1.28 1994/10/15 23:11:03 mrg Stab $"; #endif #include "irc.h" #include "alias.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" extern char *dcc_raw_listen(); extern char *dcc_raw_connect(); extern void strmcat(); extern void strmcat_ue(); extern char *FromUserHost; extern int parse_number __P((char **)); static char *next_unit __P((char *, char *, int *, int)); static long randm(); static char *alias_detected(); static char *alias_sent_nick(); static char *alias_recv_nick(); static char *alias_msg_body(); static char *alias_joined_nick(); static char *alias_public_nick(); static char *alias_dollar(); static char *alias_channel(); static char *alias_server(); static char *alias_query_nick(); static char *alias_target(); static char *alias_nick(); static char *alias_invite(); static char *alias_cmdchar(); static char *alias_line(); static char *alias_away(); static char *alias_oper(); static char *alias_chanop(); static char *alias_modes(); static char *alias_buffer(); static char *alias_time(); static char *alias_version(); static char *alias_currdir(); static char *alias_current_numeric(); static char *alias_server_version(); typedef struct { char name; char *(*func)(); } 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 }, { (char) 0, NULL } }; char FAR command_line[BIG_BUFFER_SIZE+1] = ""; char *function_left __P((char *)); char *function_right __P((char *)); char *function_mid __P((char *)); char *function_rand __P((char *)); char *function_srand __P((char *)); char *function_time __P((char *)); char *function_stime __P((char *)); char *function_index __P((char *)); char *function_rindex __P((char *)); char *function_match __P((char *)); char *function_rmatch __P((char *)); char *function_userhost __P((char *)); char *function_strip __P((char *)); char *function_encode __P((unsigned char *)); char *function_decode __P((unsigned char *)); char *function_ischannel __P((char *)); char *function_ischanop __P((char *)); char *function_word __P((char *)); char *function_winnum __P((char *)); char *function_winnam __P((char *)); char *function_connect __P((char *)); char *function_listen __P((char *)); char *function_tdiff __P((char *)); char *function_toupper __P((char *)); char *function_tolower __P((char *)); char *function_channels __P((char *)); char *function_servers __P((char *)); char *function_curpos __P((char *)); char *function_onchannel __P((char *)); char *function_pid __P((char *)); char *function_ppid __P((char *)); char *function_chanusers __P((char *)); char *function_strftime __P((char *)); typedef struct { char *name; char *(*func)(); } BuiltInFunctions; static BuiltInFunctions FAR built_in_functions[] = { { "LEFT", function_left }, { "RIGHT", function_right }, { "MID", function_mid }, { "RAND", function_rand }, { "SRAND", function_srand }, { "TIME", function_time }, { "TDIFF", function_tdiff }, { "STIME", function_stime }, { "INDEX", function_index }, { "RINDEX", function_rindex }, { "MATCH", function_match }, { "RMATCH", function_rmatch }, { "USERHOST", function_userhost }, { "STRIP", function_strip }, { "ENCODE", function_encode }, { "DECODE", function_decode }, { "ISCHANNEL", function_ischannel }, { "ISCHANOP", function_ischanop }, { "WORD", function_word }, { "WINNUM", function_winnum }, { "WINNAM", function_winnam }, { "CONNECT", function_connect }, { "LISTEN", function_listen }, { "TOUPPER", function_toupper }, { "TOLOWER", function_tolower }, { "MYCHANNELS", function_channels }, { "MYSERVERS", function_servers }, { "CURPOS", function_curpos }, { "ONCHANNEL", function_onchannel }, { "PID", function_pid }, { "PPID", function_ppid }, { "CHANUSERS", function_chanusers }, { "STRFTIME", function_strftime }, { (char *) 0, NULL } }; /* alias_illegals: characters that are illegal in alias names */ char alias_illegals[] = " #+-*/\\()={}[]<>!@$%^~`,?;:|'\""; static Alias *alias_list[] = { (Alias *) 0, (Alias *) 0 }; /* alias_string: the thing that gets replaced by the $"..." construct */ static char *alias_string = (char *) 0; static int eval_args; /* function_stack and function_stkptr - hold the return values from functions */ static char * FAR function_stack[128] = { (char *) 0 }; static int function_stkptr = 0; extern char *MatchingBracket(); /* * find_alias: looks up name in in alias list. Returns the Alias entry if * found, or null if not found. If 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, unlink, match) Alias **list; char *name; int unlink; int *match; { Alias *tmp, *last = (Alias *) 0; int cmp, len; int (*cmp_func)(); if (match) { *match = 0; cmp_func = my_strnicmp; } else cmp_func = my_stricmp; if (name) { len = strlen(name); for (tmp = *list; tmp; tmp = tmp->next) { if ((cmp = cmp_func(name, tmp->name, len)) == 0) { if (unlink) { if (last) last->next = tmp->next; else *list = tmp->next; } if (match) { (*match)++; if (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, alias) Alias **list; Alias *alias; { Alias *tmp, *last, *foo; last = (Alias *) 0; for (tmp = *list; tmp; tmp = tmp->next) { if (strcmp(alias->name, tmp->name) < 0) break; last = tmp; } if (last) { foo = last->next; last->next = alias; alias->next = foo; } else { alias->next = *list; *list = alias; } } /* * 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; char *name, *stuff; { Alias *tmp; char *ptr; upper(name); if (type == COMMAND_ALIAS) say("Alias %s added", name); else { if (!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 = (char *) 0; tmp->stuff = (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 char * alias_arg(str, pos) char **str; u_int *pos; { char *ptr; if (!*str) return (char *) 0; *pos = 0; ptr = *str; while (' ' == *ptr) { ptr++; (*pos)++; } if (*ptr == '\0') { *str = empty_string; return ((char *) 0); } if ((*str = sindex(ptr, " ")) != 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) char *str; { int cnt = 0; char *ptr; while (1) { if ((ptr = sindex(str, "^ ")) != NULL) { cnt++; if ((str = sindex(ptr, " ")) == (char *) 0) return (cnt); } else return (cnt); } } static char * built_in_alias(c) char c; { BuiltIns *tmp; char *ret = (char *) 0; for(tmp = built_in;tmp->name;tmp++) if (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 char * find_inline(str) char *str; { Alias *alias; char *ret = NULL; char *tmp; if ((alias = find_alias(&(alias_list[VAR_ALIAS]), str, 0, (int *) NULL)) != NULL) { malloc_strcpy(&ret, alias->stuff); return (ret); } if ((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 = getenv(str)) ? tmp : empty_string); #else malloc_strcpy(&ret, (tmp = getenv(str)) ? tmp : empty_string); #endif /* DAEMON_UID */ return (ret); } static char * call_function(name, f_args, args, args_flag) char *name, *f_args, *args; int *args_flag; { char *tmp; char *result = (char *) 0; char *sub_buffer = (char *) 0; int builtnum; char *debug_copy = (char *) 0; tmp = expand_alias((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_stricmp(built_in_functions[builtnum].name, name); builtnum++) ; if (built_in_functions[builtnum].name) result = built_in_functions[builtnum].func(tmp); else { sub_buffer = new_malloc(strlen(name)+strlen(tmp)+2); strcpy(sub_buffer, name); strcat(sub_buffer, " "); strcat(sub_buffer, tmp); function_stack[++function_stkptr] = (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] = (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 */ char * lastop(ptr) 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 char * next_unit(str, args, arg_flag, stage) char *str, *args; int *arg_flag, stage; { char *ptr, *ptr2, *right; int got_sloshed = 0; char *lastc; char tmp[40]; char *result1 = (char *) 0, *result2 = (char *) 0; long value1 = 0, value2, value3; char op; int display; char *ArrayIndex, *EndIndex; while (isspace(*str)) ++str; if (!*str) { malloc_strcpy(&result1, empty_string); return result1; } lastc = str+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, '(', ')'))) ptr = ptr+strlen(ptr)-1; else ptr = ptr2; break; } *ptr++ = '\0'; right = ptr; ptr = MatchingBracket(right, LEFT_PAREN, 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, '[', ']'))) ptr = ptr+strlen(ptr)-1; else ptr = ptr2; break; } *ptr++ = '\0'; right = ptr; ptr = MatchingBracket(right, LEFT_BRACKET, RIGHT_BRACKET); if (ptr) *ptr++ = '\0'; result1 = expand_alias((char *) 0, right, args, arg_flag, NULL); if (*str) { result2 = new_malloc(strlen(str)+ (result1?strlen(result1):0)+ (ptr?strlen(ptr):0) + 2); strcpy(result2, str); strcat(result2, "."); strcat(result2, result1); new_free(&result1); if (ptr && *ptr) { 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 */ { 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,"0"); { /* This isnt supposed to be attached to the if, so dont "fix" it. */ int r; r = atoi(result1); if (*ptr == '+') r++; else r--; sprintf(tmp,"%ld",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 = atol(result1); value2 = atol(result2); new_free(&result1); new_free(&result2); if (op == '-') value3 = value1 - value2; else value3 = value1 + value2; sprintf(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 = atol(result1); value2 = 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(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 = atol(result1); if (value1) { result2 = next_unit(ptr, args, arg_flag, stage); value2 = 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 = atol(result1); value2 = atol(result2); new_free(&result1); new_free(&result2); value3 = value1 & value2; sprintf(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 = atol(result1); if (!value1) { result2 = next_unit(ptr, args, arg_flag, stage); value2 = 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 = atol(result1); value2 = atol(result2); new_free(&result1); new_free(&result2); value3 = value1 | value2; sprintf(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 = atol(result1); value2 = 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 = atol(result1); value2 = atol(result2); new_free(&result1); new_free(&result2); value3 = value1 ^ value2; sprintf(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 = index(ptr, ':'); *ptr2++ = '\0'; right = result1; value1 = parse_number(&right); if ((value1 == -1) && (*right == (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((char *) 0, str, args, arg_flag, NULL); result2 = next_unit(ptr, args, arg_flag, stage); display = window_display; window_display = 0; lastc = result1 + strlen(result1) - 1; while (lastc > result1 && *lastc == ' ') *lastc-- = '\0'; for (ptr = result1; *ptr == ' '; ptr++); while ((ArrayIndex = (char *) index(ptr, '[')) != NULL) { *ArrayIndex++='.'; if ((EndIndex = MatchingBracket(ArrayIndex, LEFT_BRACKET, RIGHT_BRACKET)) != NULL) { *EndIndex++='\0'; 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, "1"); else malloc_strcpy(&result1, "0"); 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 = atol(result1); value2 = 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(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 = atol(result1); value2 = ~value1; } else value2 = 0; sprintf(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 = atol(result1); value2 = value1 ? 0 : 1; } else { value2 = ((*result1)?0:1); } sprintf(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, "0"); else malloc_strcpy(&result1, "1"); 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 = strlen(result1); sprintf(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) */ char * parse_inline(str, args, args_flag) char *str; 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 extern char *arg_number(lower_lim, upper_lim, str) int lower_lim, upper_lim; char *str; { char *ptr, *arg, c; int use_full = 0; unsigned int pos, start_pos; static char *last_args = (char *) 0; static char *last_range = (char *) 0; static char **arg_list = (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 = (char **) new_malloc(sizeof(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 + 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 = (char **) new_realloc(arg_list, sizeof(char *) * arg_list_limit); arg_list_pos = (unsigned int *) new_realloc(arg_list_pos, sizeof(unsigned int) * arg_list_limit); arg_list_end_pos = (unsigned int *) new_realloc(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]) = (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) char **str; { int ret; char *ptr; ptr = *str; if (isdigit(*ptr)) { ret = atoi(ptr); for (; isdigit(*ptr); ptr++); *str = ptr; } else ret = -1; return (ret); } 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) char *buff, *add; int length; char *quote_em; { char format[40], *ptr; if (length) { sprintf(format, "%%%d.%ds", -length, (length < 0 ? -length : length)); sprintf(buffer, format, add); add = buffer; } if (quote_em) { ptr = double_quote(add, quote_em); strmcat(buff, ptr, BIG_BUFFER_SIZE); new_free(&ptr); } else if (buff) strmcat(buff, add, BIG_BUFFER_SIZE); } /* MatchingBracket returns the next unescaped bracket of the given type */ char * MatchingBracket(string, left, right) char *string; char left, right; { int bracket_count = 1; while (*string && bracket_count) { if (*string == left) bracket_count++; else if (*string == right) { if (!--bracket_count) return string; } else if (*string == '\\' && string[1]) string++; string++; } return (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 (of size BIG_BUFFER_SIZE) 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 char * alias_special_char(name, buffer, ptr, args, quote_em,args_flag) char *name; char *buffer; char *ptr; char *args; char *quote_em; int *args_flag; { char *tmp, c; int upper, lower, length; length = 0; if ((c = *ptr) == LEFT_BRACKET) { ptr++; if ((tmp = (char *) index(ptr, RIGHT_BRACKET)) != NULL) { *(tmp++) = (char) 0; length = atoi(ptr); ptr = tmp; c = *ptr; } else { say("Missing %c", RIGHT_BRACKET); return (ptr); } } tmp = ptr+1; switch (c) { case LEFT_PAREN: { define_big_buffer(sub_buffer); if ((ptr = MatchingBracket(tmp, LEFT_PAREN, RIGHT_PAREN)) || (ptr = (char *) index(tmp, RIGHT_PAREN))) *(ptr++) = (char) 0; tmp = expand_alias((char *) 0, tmp, args, args_flag, NULL); *sub_buffer = (char) 0; alias_special_char((char *) 0, sub_buffer, tmp, args, quote_em,args_flag); expander_addition(buffer, sub_buffer, length, quote_em); new_free(&tmp); *args_flag = 1; free_big_buffer(sub_buffer); } return (ptr); case '!': if ((ptr = (char *) index(tmp, '!')) != NULL) *(ptr++) = (char) 0; if ((tmp = do_history(tmp, empty_string)) != NULL) { expander_addition(buffer, tmp, length, quote_em); new_free(&tmp); } return (ptr); case LEFT_BRACE: if ((ptr = (char *) index(tmp, RIGHT_BRACE)) != NULL) *(ptr++) = (char) 0; if ((tmp = parse_inline(tmp, args, args_flag)) != NULL) { expander_addition(buffer, tmp, length, quote_em); new_free(&tmp); } return (ptr); case DOUBLE_QUOTE: if ((ptr = (char *) index(tmp, DOUBLE_QUOTE)) != NULL) *(ptr++) = (char) 0; alias_string = (char *) 0; if (irc_io(tmp, do_alias_string, use_input, 1)) { yell("Illegal recursive edit"); break; } expander_addition(buffer, alias_string, length, quote_em); new_free(&alias_string); return (ptr); case '*': expander_addition(buffer, args, length, quote_em); *args_flag = 1; return (ptr + 1); default: if (isdigit(c) || (c == '-') || c == '~') { *args_flag = 1; if (*ptr == '~') { lower = upper = LAST_ARG; ptr++; } else { lower = parse_number(&ptr); if (*ptr == '-') { ptr++; upper = parse_number(&ptr); } else upper = lower; } expander_addition(buffer, arg_number(lower, upper, args), length, quote_em); return (ptr ? ptr : empty_string); } else { char *rest, c = (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; c = *rest; *rest = (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, *rest, (*rest == LEFT_BRACKET) ? RIGHT_BRACKET: RIGHT_PAREN))) rest = tmp + 1; c = *rest; *rest = (char) 0; } if ((tmp = parse_inline(ptr, args, args_flag)) != NULL) { expander_addition(buffer, tmp, length, quote_em); new_free(&tmp); } if (rest) *rest = c; 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. */ char * expand_alias(name, string, args,args_flag, more_text) char *name, *string, *args; int *args_flag; char **more_text; { define_big_buffer(buffer); char *ptr, *stuff = (char *) 0, *free_stuff; char *quote_em, *quote_str = (char *) 0; char ch; int quote_cnt = 0; int is_quote = 0; void (*str_cat)(); if (*string == '@' && more_text) { str_cat = strmcat; *args_flag = 1; /* Stop the @ command from auto appending */ } else str_cat = strmcat_ue; malloc_strcpy(&stuff, string); free_stuff = stuff; *buffer = (char) 0; 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++) = (char) 0; (*str_cat)(buffer, stuff, BIG_BUFFER_SIZE); while (*ptr == '^') { ptr++; if (quote_str) quote_str = (char *) new_realloc(quote_str, sizeof(char) * (quote_cnt + 2)); else quote_str = (char *) new_malloc(sizeof(char) * (quote_cnt + 2)); quote_str[quote_cnt++] = *(ptr++); quote_str[quote_cnt] = (char) 0; } quote_em = quote_str; stuff = alias_special_char(name, buffer, ptr, args, 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'; (*str_cat)(buffer, stuff, BIG_BUFFER_SIZE); stuff = ptr; *args_flag = 1; if (!(ptr = MatchingBracket(stuff + 1, ch, (ch == LEFT_PAREN) ? RIGHT_PAREN : RIGHT_BRACE))) { yell("Unmatched %c", ch); ptr = stuff + strlen(stuff+1)+1; } else ptr++; *stuff = ch; ch = *ptr; *ptr = '\0'; strmcat(buffer, stuff, BIG_BUFFER_SIZE); stuff = ptr; *ptr = ch; break; case '\\': is_quote = 1; ptr++; break; default: ptr++; break; } } if (stuff) (*str_cat)(buffer, stuff, BIG_BUFFER_SIZE); ptr = (char *) 0; new_free(&free_stuff); malloc_strcpy(&ptr, buffer); if (get_int_var(DEBUG_VAR) & DEBUG_EXPANSIONS) yell("Expanded [%s] to [%s]", string, ptr); free_big_buffer(buffer); 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! */ char * get_alias(type, name, cnt, full_name) int type; char *name, **full_name; int *cnt; { Alias *tmp; *full_name = (char *) 0; if ((name == (char *) 0) || (*name == (char) 0)) { *cnt = 0; return ((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 ((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 */ char ** match_alias(name, cnt, type) char *name; int *cnt; int type; { Alias *tmp; char **matches = (char **) 0; int matches_size = 5; int len; char *last_match = (char *) 0; char *dot; len = strlen(name); *cnt = 0; matches = (char **) new_malloc(sizeof(char *) * matches_size); for (tmp = alias_list[type]; tmp; tmp = tmp->next) { if (strncmp(name, tmp->name, len) == 0) { if ((dot = (char *) index(tmp->name+len, '.')) != NULL) { if (type == COMMAND_ALIAS) continue; else { *dot = '\0'; if (last_match && !strcmp(last_match, tmp->name)) { *dot = '.'; continue; } } } matches[*cnt] = (char *) 0; malloc_strcpy(&(matches[*cnt]), tmp->name); last_match = matches[*cnt]; if (dot) *dot = '.'; if (++(*cnt) == matches_size) { matches_size += 5; matches = (char **) new_realloc(matches, sizeof(char *) * matches_size); } } else if (*cnt) break; } if (*cnt) { matches = (char **) new_realloc(matches, sizeof(char *) * (*cnt + 1)); matches[*cnt] = (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; 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; char *name; { Alias *tmp; int len; int DotLoc, LastDotLoc = 0; char *LastStructName = NULL; char *s; if (type == COMMAND_ALIAS) say("Aliases:"); else say("Assigns:"); if (name) { upper(name); len = strlen(name); } else len = 0; for (tmp = alias_list[type]; tmp; tmp = tmp->next) { if (!name || !strncmp(tmp->name, name, len)) { s = index(tmp->name + len, '.'); if (!s) say("\t%s\t%s", tmp->name, tmp->stuff); else { DotLoc = s - tmp->name; if (!LastStructName || (DotLoc != LastDotLoc) || strncmp(tmp->name, LastStructName, DotLoc)) { say("\t%*.*s\t", DotLoc, DotLoc, tmp->name); LastStructName = tmp->name; LastDotLoc = DotLoc; } } } } } /* * 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) 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, alias, args) char *alias_name, *alias, *args; { if (mark_alias(alias_name, 1)) say("Maximum recursion count exceeded in: %s", alias_name); else { parse_line(alias_name, alias, 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 char * alias_line() { return(get_input()); } static char * alias_buffer() { return cut_buffer; } static char * alias_time() { return(update_clock(GET_TIME)); } static char * alias_dollar() { return("$"); } static char * alias_detected() { return last_notify_nick; } static char * alias_nick() { return(get_server_nickname(curr_scr_win->server)); } static char * alias_away() { return server_list[curr_scr_win->server].away; } static char * alias_sent_nick() { return (sent_nick) ? sent_nick : empty_string; } static char * alias_recv_nick() { return (recv_nick) ? recv_nick : empty_string; } static char * alias_msg_body() { return (sent_body) ? sent_body : empty_string; } static char * alias_joined_nick() { return (joined_nick) ? joined_nick : empty_string; } static char * alias_public_nick() { return (public_nick) ? public_nick : empty_string; } static char * alias_channel() { char *tmp; return (tmp = get_channel_by_refnum(0)) ? tmp : "0"; } static 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 char * alias_query_nick() { char *tmp; return (tmp = query_nick()) ? tmp : empty_string; } static char * alias_target() { char *tmp; return (tmp = get_target_by_refnum(0)) ? tmp : empty_string; } static char * alias_invite() { return (invite_channel) ? invite_channel : empty_string; } static char * alias_cmdchar() { static char thing[2]; char *cmdchars; if ((cmdchars = get_string_var(CMDCHARS_VAR)) == (char *) 0) cmdchars = DEFAULT_CMDCHARS; thing[0] = cmdchars[0]; thing[1] = (char) 0; return(thing); } static char * alias_oper() { return get_server_operator(from_server) ? get_string_var(STATUS_OPER_VAR) : empty_string; } static char * alias_chanop() { char *tmp; return ((tmp = get_channel_by_refnum(0)) && get_channel_oper(tmp, from_server)) ? "@" : empty_string; } static char * alias_modes() { char *tmp; return (tmp = get_channel_by_refnum(0)) ? get_channel_mode(tmp, from_server) : empty_string; } /* * alias: the /ALIAS command. Calls the correct alias function depending on * the args */ void alias(command, args) char *command, *args; { char *name, *rest; int type; char *ArrayIndex; 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 = (char *) index(name, '[')) != NULL) { *ArrayIndex++ = '.'; if ((EndIndex = MatchingBracket(ArrayIndex, LEFT_BRACKET, RIGHT_BRACKET)) != NULL) { *EndIndex++ = '\0'; strcat(name, EndIndex); } else break; } if (*rest) { if (*rest == LEFT_BRACE) { char *ptr = MatchingBracket(++rest, LEFT_BRACE, 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, (char *) 0); } char * function_left(input) char *input; { char *result = (char *) 0; char *count; int cvalue; count = next_arg(input, &input); if (count) cvalue = atoi(count); else cvalue = 0; if (strlen(input) > cvalue) input[cvalue] = '\0'; malloc_strcpy(&result, input); return result; } char * function_right(input) char *input; { char *result = (char *) 0; char *count; int cvalue; count = next_arg(input, &input); if (count) cvalue = atoi(count); else cvalue = 0; if (strlen(input) > cvalue) input += strlen(input) - cvalue; malloc_strcpy(&result, input); return result; } char * function_mid(input) char *input; { char *result = (char *) 0; char *index; int ivalue; char *count; int cvalue; index = next_arg(input, &input); if (index) ivalue = atoi(index); else ivalue = 0; count = next_arg(input, &input); if (count) cvalue = atoi(count); else cvalue = 0; if (strlen(input) > ivalue) input += ivalue; else *input = (char) 0; if (strlen(input) > cvalue) input[cvalue] = (char) 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 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 else z = l; return 0; } } char * function_rand(input) char *input; { char *result = (char *) 0; char tmp[40]; long tempin; sprintf(tmp, "%ld", (tempin = atol(input)) ? randm(0L) % tempin : 0); malloc_strcpy(&result, tmp); return result; } char * function_srand(input) char *input; { char *result = (char *) 0; if (input && *input) (void) randm(atol(input)); else (void) randm((time_t) time(NULL)); malloc_strcpy(&result, empty_string); return result; } /*ARGSUSED*/ char * function_time(input) char *input; { char *result = (char *) 0; time_t ltime; char tmp[40]; (void) time(<ime); sprintf(tmp, "%ld", ltime); malloc_strcpy(&result, tmp); return result; } char * function_stime(input) char *input; { char *result = (char *) 0; time_t ltime; ltime = atol(input); malloc_strcpy(&result, ctime(<ime)); result[strlen(result) - 1] = (char) 0; return result; } char * function_tdiff(input) char *input; { char *result = (char *) 0; time_t ltime; time_t days, hours, minutes, seconds; char tmp[80]; char *tstr; ltime = 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(tstr, "%d day%s ", days, (days==1)?"":"s"); tstr += strlen(tstr); } if (hours) { sprintf(tstr, "%d hour%s ", hours, (hours==1)?"":"s"); tstr += strlen(tstr); } if (minutes) { sprintf(tstr, "%d minute%s ", minutes, (minutes==1)?"":"s"); tstr += strlen(tstr); } if (seconds || (!days && !hours && !minutes)) { sprintf(tstr, "%d second%s", seconds, (seconds==1)?"":"s"); tstr += strlen(tstr); } malloc_strcpy(&result, tmp); return result; } char * function_index(input) char *input; { char *result = (char *) 0; char *schars; char *iloc; int ival; char tmp[40]; schars = next_arg(input, &input); iloc = (schars) ? sindex(input, schars) : NULL; ival = (iloc) ? iloc - input : -1; sprintf(tmp, "%d", ival); malloc_strcpy(&result, tmp); return result; } char * function_rindex(input) char *input; { char *result = (char *) 0; char *schars; char *iloc, *liloc; int ival; char tmp[40]; schars = next_arg(input, &input); iloc = NULL; if (schars) { liloc = sindex(input, schars); while (liloc) liloc = sindex((iloc = liloc) + 1, schars); } ival = (iloc) ? iloc-input : -1; sprintf(tmp, "%d", ival); malloc_strcpy(&result, tmp); return result; } char * function_match(input) char *input; { char *result = (char *) 0; char *pattern; char *word; int current_match; int best_match = 0; int match = 0; int index = 0; char tmp[40]; if ((pattern = next_arg(input, &input)) != NULL) { while ((word = next_arg(input, &input)) != NULL) { index++; if ((current_match = wild_match(pattern, word)) > best_match) { match = index; best_match=current_match; } } } sprintf(tmp, "%d", match); malloc_strcpy(&result, tmp); return result; } char * function_rmatch(input) char *input; { char *result = (char *) 0; char *pattern; char *word; int current_match; int best_match = 0; int match = 0; int index = 0; char tmp[40]; if ((pattern = next_arg(input, &input)) != NULL) { while ((word = next_arg(input, &input)) != NULL) { index++; if ((current_match = wild_match(word, pattern)) > best_match) { match = index; best_match = current_match; } } } sprintf(tmp, "%d", match); malloc_strcpy(&result, tmp); return result; } /*ARGSUSED*/ char * function_userhost(input) char *input; { char *result = (char *) 0; malloc_strcpy(&result, FromUserHost ? FromUserHost : empty_string); return result; } char * function_strip(input) char *input; { static char FAR result[BIG_BUFFER_SIZE+1] = ""; char *retval = (char *) 0; char *chars; char *cp, *dp; if ((chars = next_arg(input, &input)) && input) { for (cp = input, dp = result; *cp; cp++) { if (!index(chars, *cp)) *dp++ = *cp; } *dp = '\0'; } malloc_strcpy(&retval, result); return retval; } char * function_encode(input) unsigned char *input; { static unsigned char FAR result[BIG_BUFFER_SIZE+1] = ""; char *retval = (char *) 0; unsigned char *c; int i = 0; for (c = input; *c; c++) { result[i++] = (*c >> 4) + 0x41; result[i++] = (*c & 0x0f) + 0x41; } result[i] = '\0'; malloc_strcpy(&retval, result); return retval; } char * function_decode(input) unsigned char *input; { static unsigned char FAR result[BIG_BUFFER_SIZE+1] = ""; char *retval = (char *) 0; unsigned char *c; unsigned char d,e; int i = 0; c = input; while((d = *c) && (e = *(c+1))) { result[i] = ((d - 0x41) << 4) | (e - 0x41); c += 2; i++; } result[i] = '\0'; malloc_strcpy(&retval, result); return retval; } char * function_ischannel(input) char *input; { char *result = (char *) 0; malloc_strcpy(&result, is_channel(input) ? "1" : "0"); return result; } char * function_ischanop(input) char *input; { char *result = (char *) 0; char *nick; char *channel = NULL; if (!(nick = next_arg(input, &channel))) malloc_strcpy(&result, "0"); else malloc_strcpy(&result, is_chanop(channel, nick) ? "1" : "0"); return result; } char * function_word(input) char *input; { char *result = (char *) 0; char *count; int cvalue; char *word; count = next_arg(input, &input); if (count) cvalue = 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; } char * function_winnum(input) char *input; { char *result = (char *) 0; char tmp[10]; if (curr_scr_win) sprintf(tmp, "%d", curr_scr_win->refnum); else strcpy(tmp, "-1"); malloc_strcpy(&result, tmp); return result; } char * function_winnam(input) char *input; { char *result = (char *) 0; malloc_strcpy(&result, (curr_scr_win && curr_scr_win->name) ? curr_scr_win->name : empty_string); return result; } char * function_connect(input) char *input; { char *result = (char *) 0; char *host; #ifdef DAEMON_UID if (getuid() == DAEMON_UID) put_it("You are not permitted to use CONNECT()"); else #endif if ((host = next_arg(input, &input)) != NULL) result = dcc_raw_connect(host, atoi(input)); return result; } char * function_listen(input) char *input; { char *result = (char *) 0; #ifdef DAEMON_UID if (getuid() == DAEMON_UID) malloc_strcpy(&result, "0"); else #endif result = dcc_raw_listen(atoi(input)); return result; } static char * alias_version(input) char *input; { char *result = (char *) 0; malloc_strcpy(&result, internal_version); return result; } static char * alias_currdir(input) char *input; { char *result = (char *) 0; getcwd(buffer, BIG_BUFFER_SIZE+1); /* is this more portable? *shrug*. i chose BIG_BUFFER_SIZE+1 because it's more readable -cgw- */ /* getcwd((char *)buffer, sizeof((char *)buffer)); */ malloc_strcpy(&result, buffer); return result; } static char * alias_current_numeric(input) char *input; { char *result = (char *) 0, number[4]; sprintf(number, "%03d", -current_numeric); malloc_strcpy(&result, number); return result; } static char * alias_server_version(input) char *input; { char *result = (char *) 0, *s; malloc_strcpy(&result, (s = server_list[curr_scr_win->server].version_string) ? s : empty_string); return result; } char * function_toupper(input) char *input; { char *new = (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; } char * function_tolower(input) char *input; { char *new = (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; } char * function_curpos(input) char *input; { char *new = (char *) 0, pos[4]; sprintf(pos, "%d", current_screen->buffer_pos); malloc_strcpy(&new, pos); return new; } char * function_channels(input) char *input; { Window *window; if (input) window = isdigit(*input) ? get_window_by_refnum(atoi(input)) : curr_scr_win; else window = curr_scr_win; return create_channel_list(window); } char * function_servers(input) char *input; { return create_server_list(); } char * function_onchannel(input) char *input; { char *result = (char *) 0; char *nick; char *channel = NULL; if (!(nick = next_arg(input, &channel))) malloc_strcpy(&result, "0"); else malloc_strcpy(&result, is_on_channel(channel, nick) ? "1" : "0"); return result; } char * function_pid(input) char *input; { char *result = (char *) 0; sprintf(buffer, "%d", (int) getpid()); malloc_strcpy(&result, buffer); return result; } char * function_ppid(input) char *input; { char *result = (char *) 0; sprintf(buffer, "%d", (int) getppid()); malloc_strcpy(&result, buffer); return result; } char * function_chanusers(input) char *input; { ChannelList *chan; NickList *nicks; char *result = (char *) 0; chan = lookup_channel(from_server, input, 0); if ((ChannelList *) 0 == chan) return (char *) 0; for (nicks = chan->nicks; nicks; nicks = nicks->next) { strcat(buffer, " "); strcat(buffer, nicks->nick); } malloc_strcpy(&result, buffer + 1); return result; } /* * strftime() patch from hari (markc@arbld.unimelb.edu.au) */ char * function_strftime(input) char *input; { char result[128]; time_t ltime; char *fmt = (char *) 0; ltime = atol(input); fmt = input; /* skip the time field */ while (isdigit(*fmt)) ++fmt; if (*fmt && *++fmt) { struct tm *tm; tm = localtime(<ime); if (strftime(result, 128, fmt, tm)) { char * s = (char *) 0; malloc_strcpy(&s, result); return s; } else return (char *) 0; } else { return (char *) 0; } }