/*
* 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 <stdarg.h>
#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
}
syntax highlighted by Code2HTML, v. 0.9.1