/* * hook.c: Does those naughty hook functions. * * Written By Michael Sandrof * * Copyright(c) 1990 * * See the COPYRIGHT file, or do a HELP IRCII COPYRIGHT */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "irc.h" #include "hook.h" #include "vars.h" #include "ircaux.h" #include "expr.h" #include "list.h" #include "window.h" #include "server.h" #include "output.h" #include "commands.h" #include "parse.h" #include "fset.h" #include "misc.h" #include #define SILENT 0 #define QUIET 1 #define NORMAL 2 #define NOISY 3 /* * The various ON levels: SILENT means the DISPLAY will be OFF and it will * suppress the default action of the event, QUIET means the display will be * OFF but the default action will still take place, NORMAL means you will be * notified when an action takes place and the default action still occurs, * NOISY means you are notified when an action occur plus you see the action * in the display and the default actions still occurs */ static char *noise_level[] = { "SILENT", "QUIET", "NORMAL", "NOISY" }; #define HS_NOGENERIC 0x1000 #define HF_NORECURSE 0x0002 #define HF_GLOBAL 0x0004 int in_on_who = 0; NumericList *numeric_list = NULL; /* hook_functions: the list of all hook functions available */ HookFunc hook_functions[] = { {"ACTION", NULL, 3, 0, 0}, {"AR_PUBLIC", NULL, 3, 0, 0}, {"AR_PUBLIC_OTHER", NULL, 3, 0, 0}, {"AR_REPLY", NULL, 1, 0, 0}, {"BANS", NULL, 4, 0, 0}, {"BANS_HEADER", NULL, 4, 0, 0}, {"CHANNEL_NICK", NULL, 3, 0, 0}, {"CHANNEL_SIGNOFF", NULL, 3, 0, 0}, {"CHANNEL_STATS", NULL, 32, 0, 0}, {"CHANNEL_SWITCH", NULL, 1, 0, 0}, {"CHANNEL_SYNCH", NULL, 2, 0, 0}, {"CLONE_READ", NULL, 4, 0, 0}, {"CONNECT", NULL, 1, 0, 0}, {"CTCP", NULL, 4, 0, 0}, {"CTCP_REPLY", NULL, 3, 0, 0}, {"DCC_CHAT", NULL, 2, 0, 0}, {"DCC_CONNECT", NULL, 2, 0, 0}, {"DCC_ERROR", NULL, 6, 0, 0}, {"DCC_HEADER", NULL, 7, 0, 0}, {"DCC_LOST", NULL, 2, 0, 0}, {"DCC_POST", NULL, 7, 0, 0}, {"DCC_RAW", NULL, 3, 0, 0}, {"DCC_REQUEST", NULL, 4, 0, 0}, {"DCC_STAT", NULL, 7, 0, 0}, {"DCC_STATF", NULL, 7, 0, 0}, {"DCC_STATF1", NULL, 5, 0, 0}, {"DESYNC_MESSAGE", NULL, 2, 0, 0}, {"DISCONNECT", NULL, 1, 0, 0}, {"ENCRYPTED_NOTICE", NULL, 3, 0, 0}, {"ENCRYPTED_PRIVMSG", NULL, 3, 0, 0}, {"EXEC", NULL, 2, 0, 0}, {"EXEC_ERRORS", NULL, 2, 0, 0}, {"EXEC_EXIT", NULL, 3, 0, 0}, {"EXEC_PROMPT", NULL, 2, 0, 0}, {"EXIT", NULL, 1, 0, 0}, {"FLOOD", NULL, 3, 0, 0}, {"HELP", NULL, 2, 0, 0}, {"HELPSUBJECT", NULL, 2, 0, 0}, {"HELPTOPIC", NULL, 1, 0, 0}, {"HOOK", NULL, 1, 0, 0}, {"IDLE", NULL, 1, 0, 0}, {"INPUT", NULL, 1, 0, 0}, {"INVITE", NULL, 2, 0, 0}, {"JOIN", NULL, 3, 0, 0}, {"JOIN_ME", NULL, 1, 0, 0}, {"KICK", NULL, 3, 0, 0}, {"LEAVE", NULL, 2, 0, 0}, {"LIST", NULL, 3, 0, 0}, {"LLOOK_ADDED", NULL, 2, 0, 0}, {"LLOOK_JOIN", NULL, 2, 0, 0}, {"LLOOK_SPLIT", NULL, 2, 0, 0}, {"MODE", NULL, 3, 0, 0}, {"MODE_STRIPPED", NULL, 3, 0, 0}, {"MSG", NULL, 2, 0, 0}, {"MSG_GROUP", NULL, 3, 0, 0}, {"MSGLOG", NULL, 4, 0, 0}, {"NAMES", NULL, 2, 0, 0}, {"NICKNAME", NULL, 2, 0, 0}, {"NOTE", NULL, 3, 0, 0}, {"NOTICE", NULL, 2, 0, 0}, {"NOTIFY_SIGNOFF", NULL, 1, 0, 0}, {"NOTIFY_SIGNOFF_UH", NULL, 3, 0, 0}, {"NOTIFY_SIGNON", NULL, 1, 0, 0}, {"NOTIFY_SIGNON_UH", NULL, 3, 0, 0}, {"NSLOOKUP", NULL, 3, 0, 0}, {"ODD_SERVER_STUFF", NULL, 3, 0, 0}, {"PUBLIC", NULL, 3, 0, 0}, {"PUBLIC_MSG", NULL, 3, 0, 0}, {"PUBLIC_NOTICE", NULL, 3, 0, 0}, {"PUBLIC_OTHER", NULL, 3, 0, 0}, {"RAW_IRC", NULL, 1, 0, 0}, {"SAVEFILE", NULL, 2, 0, 0}, {"SAVEFILEPOST", NULL, 2, 0, 0}, {"SAVEFILEPRE", NULL, 2, 0, 0}, {"SEND_ACTION", NULL, 2, 0, HF_NORECURSE}, {"SEND_DCC_CHAT", NULL, 2, 0, HF_NORECURSE}, {"SEND_MSG", NULL, 2, 0, HF_NORECURSE}, {"SEND_NOTICE", NULL, 2, 0, HF_NORECURSE}, {"SEND_PUBLIC", NULL, 2, 0, HF_NORECURSE}, {"SEND_TO_SERVER", NULL, 3, 0, 0}, {"SERVER_NOTICE_FAKES", NULL, 3, 0, 0}, {"SERVER_NOTICE_FAKES_MYCHANNEL", NULL, 3, 0, 0}, {"SERVER_NOTICE_FOREIGN_KILL", NULL, 4, 0, 0}, {"SERVER_NOTICE_KILL", NULL, 4, 0, 0}, {"SERVER_NOTICE", NULL, 1, 0, 0}, {"SERVER_NOTICE_LOCAL_KILL", NULL, 4, 0, 0}, {"SERVER_NOTICE_SERVER_KILL", NULL, 4, 0, 0}, {"SET", NULL, 2, 0, 0}, {"SHOWIDLE_HEADER", NULL, 2, 0, 0}, {"SHOWIDLE", NULL, 4, 0, 0}, {"SIGNOFF", NULL, 1, 0, 0}, {"SILENCE", NULL, 2, 0, 0}, {"STAT", NULL, 5, 0, 0}, {"STAT_HEADER", NULL, 5, 0, 0}, {"STATUS_UPDATE", NULL, 2, 0, 0}, {"TIMER", NULL, 1, 0, 0}, {"TOPIC", NULL, 2, 0, 0}, {"USAGE", NULL, 2, 0, 0}, {"USERS", NULL, 7, 0, 0}, {"USERS_HEADER", NULL, 7, 0, 0}, {"USERS_SERVER", NULL, 2, 0, 0}, {"USERS_SERVER_HEADER", NULL, 2, 0, 0}, {"WALL", NULL, 2, 0, 0}, {"WALLOP", NULL, 3, 0, 0}, {"WHO", NULL, 6, 0, 0}, {"WHOLEFT", NULL, 6, 0, 0}, {"WHOLEFT_HEADER", NULL, 6, 0, 0}, {"WIDELIST", NULL, 1, 0, 0}, {"WINDOW", NULL, 2, 0, HF_NORECURSE}, {"WINDOW_KILL", NULL, 1, 0, 0}, {"YELL", NULL, 1, 0, 0} }; #if 0 static char *fill_it_out(char *str, int params) { char buffer[BIG_BUFFER_SIZE + 1]; char *arg, *free_ptr = NULL, *ptr; int i = 0; malloc_strcpy(&free_ptr, str); ptr = free_ptr; *buffer = (char) 0; while ((arg = next_arg(ptr, &ptr)) != NULL) { if (*buffer) strmcat(buffer, " ", BIG_BUFFER_SIZE); strmcat(buffer, arg, BIG_BUFFER_SIZE); if (++i == params) break; } for (; i < params; i++) strmcat(buffer, (i < params - 1) ? " %" : " *", BIG_BUFFER_SIZE); if (ptr && *ptr) { strmcat(buffer, " ", BIG_BUFFER_SIZE); strmcat(buffer, ptr, BIG_BUFFER_SIZE); } malloc_strcpy(&free_ptr, buffer); return (free_ptr); } #endif /* * This crap here is used so we can use the list manip stuff. Maybe * we should fix the problem instead of using nasty hacks like this. */ struct CmpInfoStruc { int ServerRequired; int SkipSerialNum; int SerialNumber; int Flags; } cmp_info; #define CIF_NOSERNUM 0x0001 #define CIF_SKIP 0x0002 int cmpinfodone = 0; /* * setup_struct and Add_Remove_Check are used by the list manipulation * functions for adding and removing hooks from the hook list. */ static void setup_struct(int ServReq, int SkipSer, int SerNum, int flags) { cmp_info.ServerRequired = ServReq; cmp_info.SkipSerialNum = SkipSer; cmp_info.SerialNumber = SerNum; cmp_info.Flags = flags; } static int Add_Remove_Check(Hook * Item, char *Name) { int comp; if (cmp_info.SerialNumber != Item->sernum) return (Item->sernum > cmp_info.SerialNumber) ? 1 : -1; if ((comp = my_stricmp(Item->nick, Name)) != 0) return comp; if (Item->server != cmp_info.ServerRequired) return (Item->server > cmp_info.ServerRequired) ? 1 : -1; return 0; } #if 0 static void add_numeric_hook(int numeric, char *nick, char *stuff, int noisy, int not, int server, int sernum, int flexible) { NumericList *entry; Hook *new; char buf[4]; sprintf(buf, "%3.3u", numeric); if ((entry = (NumericList *) find_in_list((struct list **) &numeric_list, buf, 0)) == NULL) { entry = (NumericList *) new_malloc(sizeof(NumericList)); memset(entry, 0, sizeof(NumericList)); malloc_strcpy(&(entry->name), buf); add_to_list((struct list **) &numeric_list, (struct list *) entry); } setup_struct((server == -1) ? -1 : (server & ~HS_NOGENERIC), sernum - 1, sernum, 0); if ((new = (Hook *) remove_from_list_ext((struct list **) &(entry->list), nick, (int (*)(struct list *, char *)) Add_Remove_Check)) != NULL) { new->not = 1; new_free(&(new->nick)); new_free(&(new->stuff)); new_free((char **) &new); } new = (Hook *) new_malloc(sizeof(Hook)); memset(new, 0, sizeof(Hook)); new->noisy = noisy; new->server = server; new->sernum = sernum; new->not = not; new->flexible = flexible; malloc_strcpy(&new->nick, nick); malloc_strcpy(&new->stuff, stuff); upper(new->nick); add_to_list_ext((struct list **) &(entry->list), (struct list *) new, (cmp_fn *) Add_Remove_Check); } #endif #if 0 /* * add_hook Given an index into the hook_functions array, this adds a new * entry to the list as specified by the rest of the parameters. The new * entry is added in alphabetical order (by nick). */ static void add_hook(int which, char *nick, char *stuff, int noisy, int not, int server, int sernum, int flexible) { Hook *new; if (which < 0) { add_numeric_hook(-which, nick, stuff, noisy, not, server, sernum, flexible); return; } setup_struct((server == -1) ? -1 : (server & ~HS_NOGENERIC), sernum - 1, sernum, 0); if ((new = (Hook *) remove_from_list_ext((struct list **) &(hook_functions[which].list), nick, (int (*)(struct list *, char *)) Add_Remove_Check)) != NULL) { new->not = 1; new_free(&(new->nick)); new_free(&(new->stuff)); new_free((char **) &new); } new = (Hook *) new_malloc(sizeof(Hook)); memset(new, 0, sizeof(Hook)); new->noisy = noisy; new->server = server; new->sernum = sernum; new->not = not; new->flexible = flexible; malloc_strcpy(&new->nick, nick); malloc_strcpy(&new->stuff, stuff); upper(new->nick); add_to_list_ext((struct list **) &(hook_functions[which].list), (struct list *) new, (cmp_fn *) Add_Remove_Check); } #endif /* show_hook shows a single hook */ extern void show_hook(Hook * list, char *name) { const char *hooks = get_fset_var(FORMAT_HOOK_FSET); char *text = NULL; if (list->stuff) text = stripansi(list->stuff); if (list->server != -1) { if (hooks) put_it("%s", convert_output_format(hooks, "%s %c %s %c %s %s %d Server %d %s", name, (list->flexible ? '\'' : '"'), list->nick, (list->flexible ? '\'' : '"'), (list->not ? "nothing" : text), noise_level[list->noisy], list->sernum, list->server & ~HS_NOGENERIC, (list->server & HS_NOGENERIC) ? " Exclusive" : empty_str)); else say("On %s from %c%s%c do %s [%s] <%d> (Server %d)%s", name, (list->flexible ? '\'' : '"'), list->nick, (list->flexible ? '\'' : '"'), (list->not ? "nothing" : text), noise_level[list->noisy], list->sernum, list->server & ~HS_NOGENERIC, (list->server & HS_NOGENERIC) ? " Exclusive" : empty_str); } else { if (hooks) put_it("%s", convert_output_format(hooks, "%s %c %s %c %s %s %d", name, (list->flexible ? '\'' : '"'), list->nick, (list->flexible ? '\'' : '"'), (list->not ? "nothing" : text), noise_level[list->noisy], list->sernum)); else say("On %s from %c%s%c do %s [%s] <%d>", name, (list->flexible ? '\'' : '"'), list->nick, (list->flexible ? '\'' : '"'), (list->not ? "nothing" : text), noise_level[list->noisy], list->sernum); } new_free(&text); } #if 0 /* * show_numeric_list: If numeric is 0, then all numeric lists are displayed. * If numeric is non-zero, then that particular list is displayed. The total * number of entries displayed is returned */ static int show_numeric_list(int numeric) { NumericList *tmp; Hook *list; char buf[4]; int cnt = 0; if (numeric) { sprintf(buf, "%3.3u", numeric); if ((tmp = (NumericList *) find_in_list((struct list **) &numeric_list, buf, 0)) != NULL) { for (list = tmp->list; list; list = list->next, cnt++) show_hook(list, tmp->name); } } else { for (tmp = numeric_list; tmp; tmp = tmp->next) { for (list = tmp->list; list; list = list->next, cnt++) show_hook(list, tmp->name); } } return (cnt); } /* * show_list: Displays the contents of the list specified by the index into * the hook_functions array. This function returns the number of entries in * the list displayed */ static int show_list(int which) { Hook *list; int cnt = 0; /* Less garbage when issueing /on without args. (lynx) */ for (list = hook_functions[which].list; list; list = list->next, cnt++) show_hook(list, hook_functions[which].name); return (cnt); } #endif /* * do_hook: This is what gets called whenever a MSG, INVITES, WALL, (you get * the idea) occurs. The nick is looked up in the appropriate list. If a * match is found, the stuff field from that entry in the list is treated as * if it were a command. First it gets expanded as though it were an alias * (with the args parameter used as the arguments to the alias). After it * gets expanded, it gets parsed as a command. This will return as its value * the value of the noisy field of the found entry, or -1 if not found. */ /* huh-huh.. this sucks.. im going to re-write it so that it works */ extern int do_hook(int which, char *format, ...) { Hook *tmp, **list; char buffer[BIG_BUFFER_SIZE * 10 + 1], *name = NULL; int RetVal = 1; unsigned int display; int i, old_in_on_who; Hook *hook_array[2048]; int hook_num = 0; static int hook_level = 0; hook_level++; *buffer = 0; if (format) { va_list args; va_start(args, format); vsnprintf(buffer, BIG_BUFFER_SIZE * 10, format, args); va_end(args); } if (which < 0) { NumericList *hook; char foo[10]; sprintf(foo, "%3.3u", -which); if ((hook = (NumericList *) find_in_list((struct list **) &numeric_list, foo, 0)) != NULL) { name = hook->name; list = &hook->list; } else list = NULL; } else { if (hook_functions[which].mark && (hook_functions[which].flags & HF_NORECURSE)) list = NULL; else { list = &(hook_functions[which].list); name = hook_functions[which].name; } } if (!list) return 1; if (which >= 0) hook_functions[which].mark++; /* not attached, so dont "fix" it */ { int currser = 0, oldser = 0; int currmatch = 0, oldmatch = 0; Hook *bestmatch = NULL; int nomorethisserial = 0; for (tmp = *list; tmp; tmp = tmp->next) { char *tmpnick = NULL; int sa; currser = tmp->sernum; if (currser != oldser) { /* new serial number */ oldser = currser; currmatch = oldmatch = nomorethisserial = 0; if (bestmatch) hook_array[hook_num++] = bestmatch; bestmatch = NULL; } if (nomorethisserial) continue; /* if there is a specific server hook and it doesnt match, then we make sure nothing from this serial number gets hooked */ if ((tmp->server != -1) && (tmp->server & HS_NOGENERIC) && (tmp->server != (from_server & HS_NOGENERIC))) { nomorethisserial = 1; bestmatch = NULL; continue; } if (tmp->flexible) tmpnick = expand_alias(tmp->nick, empty_str, &sa, NULL); else tmpnick = tmp->nick; currmatch = wild_match(tmpnick, buffer); if (currmatch > oldmatch) { oldmatch = currmatch; bestmatch = tmp; } if (tmp->flexible) new_free(&tmpnick); } if (bestmatch) hook_array[hook_num++] = bestmatch; } for (i = 0; i < hook_num; i++) { char *foo, *saved_who_from = NULL; int saved_who_level; if (!(tmp = hook_array[i])) { if (which >= 0) hook_functions[which].mark--; return RetVal; } if (tmp->not) continue; current_on_hook = which; if (tmp->noisy > QUIET) say("%s activated by %c%s%c", name, (tmp->flexible ? '\'' : '"'), buffer, (tmp->flexible ? '\'' : '"')); display = window_display; if (tmp->noisy < NOISY) window_display = 0; save_message_from(&saved_who_from, &saved_who_level); old_in_on_who = in_on_who; #ifdef ENFORCE_STRICTER_PROTOCOL if (which == WHO_LIST || (which <= -311 && which >= -318)) in_on_who = 1; #else in_on_who = 0; #endif if (!tmp->noisy && !tmp->sernum) RetVal = 0; if (tmp->stuff && *tmp->stuff) { char *name2 = alloca(strlen(name) + 1); strcpy(name2, name); foo = alloca(strlen(tmp->stuff) + 1); strcpy(foo, tmp->stuff); parse_line(name2, foo, buffer, 0, 0); } in_on_who = old_in_on_who; window_display = display; current_on_hook = -1; restore_message_from(saved_who_from, saved_who_level); } if (which >= 0) hook_functions[which].mark--; return RetVal; } static void remove_numeric_hook(int numeric, char *nick, int server, int sernum, int quiet) { NumericList *hook; Hook *tmp, *next; char buf[5]; sprintf(buf, "%3.3u", numeric); if ((hook = (NumericList *) find_in_list((struct list **) &numeric_list, buf, 0)) != NULL) { if (nick) { setup_struct((server == -1) ? -1 : (server & ~HS_NOGENERIC), sernum - 1, sernum, 0); if ((tmp = (Hook *) remove_from_list((struct list **) &(hook->list), nick)) != NULL) { if (!quiet) say("%c%s%c removed from %s list", (tmp->flexible ? '\'' : '"'), nick, (tmp->flexible ? '\'' : '"'), buf); tmp->not = 1; new_free(&(tmp->nick)); new_free(&(tmp->stuff)); new_free((char **) &tmp); if (hook->list == NULL) { if ((hook = (NumericList *) remove_from_list((struct list **) &numeric_list, buf)) != NULL) { new_free(&(hook->name)); new_free((char **) &hook); } } return; } } else { remove_from_list((struct list **) &numeric_list, buf); for (tmp = hook->list; tmp; tmp = next) { next = tmp->next; tmp->not = 1; new_free(&(tmp->nick)); new_free(&(tmp->stuff)); new_free((char **) &tmp); } hook->list = NULL; new_free((char **) &hook->name); new_free((char **) &hook); if (!quiet) say("The %s list is empty", buf); return; } } if (quiet) return; if (nick) say("\"%s\" is not on the %s list", nick, buf); else say("The %s list is empty", buf); } extern void flush_on_hooks(void) { int x; int old_display = window_display; window_display = 0; for (x = 1; x < 999; x++) remove_numeric_hook(x, NULL, 1, x, 1); for (x = 0; x < NUMBER_OF_LISTS; x++) remove_hook(x, NULL, 1, 0, 1); /* the 4th arg should be 0, not x */ window_display = old_display; } extern void remove_hook(int which, char *nick, int server, int sernum, int quiet) { Hook *tmp, *next; if (which < 0) { remove_numeric_hook(-which, nick, server, sernum, quiet); return; } if (nick) { setup_struct((server == -1) ? -1 : (server & ~HS_NOGENERIC), sernum - 1, sernum, 0); if ((tmp = (Hook *) remove_from_list_ext((struct list **) &(hook_functions[which].list), nick, (int (*)(struct list *, char *)) Add_Remove_Check)) != NULL) { if (!quiet) say("%c%s%c removed from %s list", (tmp->flexible ? '\'' : '"'), nick, (tmp->flexible ? '\'' : '"'), hook_functions[which].name); tmp->not = 1; new_free(&(tmp->nick)); new_free(&(tmp->stuff)); new_free((char **) &tmp); } else if (!quiet) say("\"%s\" is not on the %s list", nick, hook_functions[which].name); } else { Hook *prev = NULL; Hook *top = NULL; for (tmp = hook_functions[which].list; tmp; prev = tmp, tmp = next) { next = tmp->next; /* If given a non-zero sernum, then we clean out only those hooks that are at that level. */ if (sernum && tmp->sernum != sernum) { if (!top) top = tmp; continue; } if (prev) prev->next = tmp->next; tmp->not = 1; new_free(&(tmp->nick)); new_free(&(tmp->stuff)); new_free((char **) &tmp); } hook_functions[which].list = top; if (!quiet) { if (sernum) say("The %s <%d> list is empty", hook_functions[which].name, sernum); else say("The %s list is empty", hook_functions[which].name); } } } static void write_hook(FILE * fp, Hook * hook, char *name) { char *stuff = NULL; char flexi = '"'; if (hook->server != -1) return; if (hook->flexible) flexi = '\''; switch (hook->noisy) { case SILENT: stuff = "^"; break; case QUIET: stuff = "-"; break; case NORMAL: stuff = empty_str; break; case NOISY: stuff = "+"; break; } if (hook->sernum) fprintf(fp, "ON #%s%s %d", stuff, name, hook->sernum); else fprintf(fp, "ON %s%s", stuff, name); fprintf(fp, " %c%s%c %s\n", flexi, hook->nick, flexi, hook->stuff); } /* * save_hooks: for use by the SAVE command to write the hooks to a file so it * can be interpreted by the LOAD command */ extern void save_hooks(FILE * fp, int do_all) { Hook *list; NumericList *numeric; int which; for (which = 0; which < NUMBER_OF_LISTS; which++) { for (list = hook_functions[which].list; list; list = list->next) if (!list->global ||do_all) write_hook(fp, list, hook_functions[which].name); } for (numeric = numeric_list; numeric; numeric = numeric->next) { for (list = numeric->list; list; list = list->next) if (!list->global) write_hook(fp, list, numeric->name); } } #define INVALID_HOOKNUM -1001 /* * find_hook: returns the numerical value for a specified hook name */ int find_hook(char *name) { int which = INVALID_HOOKNUM, i, len, cnt; if (!(len = strlen(name))) { say("You must specify an event type!"); return INVALID_HOOKNUM; } upper(name); for (cnt = 0, i = 0; i < NUMBER_OF_LISTS; i++) { if (!strncmp(name, hook_functions[i].name, len)) { if (strlen(hook_functions[i].name) == len) { cnt = 1; which = i; break; } else { cnt++; which = i; } } else if (cnt) break; } if (cnt == 0) { if (is_number(name)) { which = my_atol(name); if ((which < 1) || (which > 999)) { say("Numerics must be between 001 and 999"); return INVALID_HOOKNUM; } which = -which; } else { say("No such ON function: %s", name); return INVALID_HOOKNUM; } } else if (cnt > 1) { say("Ambiguous ON function: %s", name); return INVALID_HOOKNUM; } return which; } /* * shook: the SHOOK command -- this probably doesnt belong here, * and shook is probably a stupid name */ BUILT_IN_COMMAND(shook) { int which; char *arg; if (!args || !*args) { userage(command, helparg); return; } arg = next_arg(args, &args); if ((which = find_hook(arg)) == INVALID_HOOKNUM) return; else do_hook(which, "%s", args); } /* on: The ON command */ BUILT_IN_COMMAND(oncmd) { #if 0 char *func, *nick, *serial; /* int noisy = NORMAL, not = 0, remove = 0, -not used */ int noisy, not, server, sernum, remove, which = 0; int flexible; char type; if ((func = next_arg(args, &args)) != NULL) { if (*func == '#') { if (!(serial = next_arg(args, &args))) { say("No serial number specified"); return; } sernum = my_atol(serial); func++; } else sernum = 0; switch (*func) { case '&': server = from_server; func++; break; case '@': server = from_server | HS_NOGENERIC; func++; break; default: server = -1; break; } switch (*func) { case '-': noisy = QUIET; func++; break; case '^': noisy = SILENT; func++; break; case '+': noisy = NOISY; func++; break; default: noisy = NORMAL; break; } if ((which = find_hook(func)) == INVALID_HOOKNUM) return; /* XXX This is bogus XXX */ if (which == INPUT_LIST && get_int_var(INPUT_PROTECTION_VAR)) { say("You cannot use /ON INPUT with INPUT_PROTECTION set"); say("Please read /HELP ON INPUT, and /HELP SET INPUT_PROTECTION"); return; } remove = 0; not = 0; switch (*args) { case '-': remove = 1; args++; break; case '^': not = 1; args++; break; } if ((nick = new_new_next_arg(args, &args, &type)) != NULL) { if (which < 0) nick = fill_it_out(nick, 1); else nick = fill_it_out(nick, hook_functions[which].params); if (type == '\'') flexible = 1; else flexible = 0; if (remove) { if (strlen(nick) == 0) say("No expression specified"); else remove_hook(which, nick, server, sernum, 0); } else /* Indent this bit back a couple of tabs - phone */ { if (not) args = empty_str; if (*nick) { char *exp; while (my_isspace(*args)) args++; if (*args == '{') { if (!(exp = next_expr(&args, '{'))) { say("Unmatched brace in ON"); new_free(&nick); return; } } else exp = args; add_hook(which, nick, exp, noisy, not, server, sernum, flexible); if (which < 0) say("On %3.3u from %c%s%c do %s [%s] <%d>", -which, type, nick, type, (not ? "nothing" : exp), noise_level[noisy], sernum); else say("On %s from %c%s%c do %s [%s] <%d>", hook_functions[which].name, type, nick, type, (not ? "nothing" : exp), noise_level[noisy], sernum); new_free(&nick); } } /* End of doovie intentation */ } else { if (remove) remove_hook(which, NULL, server, sernum, 0); else { /* the help files say that that an /on 0 shows all the numeric /ONs. Since the ACTION hook is "number 0", there is no * way to tell right here whether the user user specified an ACTION or a "show me it all". blah. ("feature" rmd from * helps) */ if (which < 0) { if (show_numeric_list(-which) == 0) say("The %3.3u list is empty.", -which); } else if (show_list(which) == 0) say("The %s list is empty.", hook_functions[which].name); } } } else { int total = 0; say("ON listings:"); for (which = 0; which < NUMBER_OF_LISTS; which++) total += show_list(which); total += show_numeric_list(0); if (total == 0) say("All ON lists are empty."); } #endif }