/*
* hook.c: Does those naughty hook functions.
*
* Written By Michael Sandrof
*
* Copyright (c) 1990 Michael Sandrof.
* Copyright (c) 1991, 1992 Troy Rollo.
* Copyright (c) 1992-2003 Matthew R. Green.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: hook.c,v 1.15 2003/01/08 20:00:54 f Exp $
*/
#include "irc.h"
#include "hook.h"
#include "vars.h"
#include "ircaux.h"
#include "alias.h"
#include "list.h"
#include "window.h"
#include "server.h"
#include "output.h"
#include "edit.h"
#include "buffer.h"
#ifdef INCLUDE_UNUSED_FUNCTIONS
static void flush_on_hooks _((void));
#endif /* INCLUDE_UNUSED_FUNCTIONS */
static char *fill_it_out _((char *, int));
static void setup_struct _((int, int, int, int));
static int Add_Remove_Check _((List *, char *));
static int Add_Remove_Check_List _((List *, List*));
static void add_numeric_hook _((int, char *, char *, int, int, int, int));
static void add_hook _((int, char *, char *, int, int, int, int));
static int show_numeric_list _((int));
static int show_list _((int));
static void remove_numeric_hook _((int, char *, int, int, int));
static void write_hook _((FILE *, Hook *, char *));
#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_LOOKONLY 0x0001
#define HF_NORECURSE 0x0002
#define HF_GLOBAL 0x0004
extern int load_depth;
int in_on_who = 0;
NumericList *numeric_list = (NumericList *) 0;
/* hook_functions: the list of all hook functions available */
HookFunc FAR hook_functions[] =
{
{ "ACTION", (Hook *) 0, 3, 0, 0 },
/**************************** PATCHED by Flier ******************************/
{ "CDCC_PLIST", (Hook *) 0, 5, 0, 0 },
{ "CDCC_PLIST_FOOTER", (Hook *) 0, 4, 0, 0 },
{ "CDCC_PLIST_HEADER", (Hook *) 0, 3, 0, 0 },
/****************************************************************************/
{ "CHANNEL_NICK", (Hook *) 0, 3, 0, 0 },
{ "CHANNEL_SIGNOFF", (Hook *) 0, 3, 0, 0 },
/**************************** PATCHED by Flier ******************************/
{ "CHANNEL_SYNCH", (Hook *) 0, 2, 0, 0 },
{ "CHANNEL_WALLOP", (Hook *) 0, 3, 0, 0 },
/****************************************************************************/
{ "CONNECT", (Hook *) 0, 1, 0, 0 },
{ "CTCP", (Hook *) 0, 4, 0, 0 },
{ "CTCP_REPLY", (Hook *) 0, 3, 0, 0 },
{ "DCC_CHAT", (Hook *) 0, 2, 0, 0 },
{ "DCC_CONNECT", (Hook *) 0, 2, 0, 0 },
{ "DCC_ERROR", (Hook *) 0, 6, 0, 0 },
/**************************** PATCHED by Flier ******************************/
{ "DCC_LIST", (Hook *) 0, 8, 0, 0 },
{ "DCC_LIST_FOOTER", (Hook *) 0, 1, 0, 0 },
{ "DCC_LIST_HEADER", (Hook *) 0, 1, 0, 0 },
/****************************************************************************/
{ "DCC_LOST", (Hook *) 0, 2, 0, 0 },
{ "DCC_RAW", (Hook *) 0, 3, 0, 0 },
{ "DCC_REQUEST", (Hook *) 0, 4, 0, 0 },
{ "DISCONNECT", (Hook *) 0, 1, 0, 0 },
{ "ENCRYPTED_NOTICE", (Hook *) 0, 3, 0, 0 },
{ "ENCRYPTED_PRIVMSG", (Hook *) 0, 3, 0, 0 },
{ "EXEC", (Hook *) 0, 2, 0, 0 },
{ "EXEC_ERRORS", (Hook *) 0, 2, 0, 0 },
{ "EXEC_EXIT", (Hook *) 0, 3, 0, 0 },
{ "EXEC_PROMPT", (Hook *) 0, 2, 0, 0 },
{ "EXIT", (Hook *) 0, 1, 0, 0 },
{ "FLOOD", (Hook *) 0, 3, 0, 0 },
{ "HELP", (Hook *) 0, 2, 0, 0 },
{ "HOOK", (Hook *) 0, 1, 0, 0 },
{ "IDLE", (Hook *) 0, 1, 0, 0 },
{ "INPUT", (Hook *) 0, 1, 0, 0 },
{ "INVITE", (Hook *) 0, 2, 0, 0 },
{ "JOIN", (Hook *) 0, 3, 0, 0 },
/**************************** PATCHED by Flier ******************************/
{ "JOIN_ME", (Hook *) 0, 1, 0, 0 },
/****************************************************************************/
{ "KICK", (Hook *) 0, 3, 0, HF_LOOKONLY },
{ "LEAVE", (Hook *) 0, 2, 0, 0 },
{ "LIST", (Hook *) 0, 3, 0, HF_LOOKONLY },
{ "MAIL", (Hook *) 0, 2, 0, 0 },
{ "MODE", (Hook *) 0, 3, 0, 0 },
{ "MSG", (Hook *) 0, 2, 0, 0 },
{ "MSG_GROUP", (Hook *) 0, 3, 0, 0 },
{ "NAMES", (Hook *) 0, 2, 0, HF_LOOKONLY },
{ "NICKNAME", (Hook *) 0, 2, 0, 0 },
{ "NOTE", (Hook *) 0, 10, 0, 0 },
{ "NOTICE", (Hook *) 0, 2, 0, 0 },
{ "NOTIFY_SIGNOFF", (Hook *) 0, 1, 0, 0 },
/**************************** Patched by Flier ******************************/
{ "NOTIFY_SIGNOFF_UH", (Hook *) 0, 3, 0, 0 },
/****************************************************************************/
{ "NOTIFY_SIGNON", (Hook *) 0, 1, 0, 0 },
/**************************** PATCHED by Flier ******************************/
{ "NOTIFY_SIGNON_UH", (Hook *) 0, 3, 0, 0 },
/****************************************************************************/
{ "PUBLIC", (Hook *) 0, 3, 0, 0 },
{ "PUBLIC_MSG", (Hook *) 0, 3, 0, 0 },
{ "PUBLIC_NOTICE", (Hook *) 0, 3, 0, 0 },
{ "PUBLIC_OTHER", (Hook *) 0, 3, 0, 0 },
{ "RAW_IRC", (Hook *) 0, 1, 0, 0 },
{ "RAW_SEND", (Hook *) 0, 1, 0, 0 },
{ "SEND_ACTION", (Hook *) 0, 2, 0, 0 },
/**************************** PATCHED by Flier ******************************/
{ "SEND_CTCP", (Hook *) 0, 3, 0, 0 },
/****************************************************************************/
{ "SEND_DCC_CHAT", (Hook *) 0, 2, 0, 0 },
{ "SEND_MSG", (Hook *) 0, 2, 0, 0 },
{ "SEND_NOTICE", (Hook *) 0, 2, 0, 0 },
{ "SEND_PUBLIC", (Hook *) 0, 2, 0, 0 },
{ "SERVER_NOTICE", (Hook *) 0, 1, 0, 0 },
{ "SIGNOFF", (Hook *) 0, 1, 0, 0 },
{ "TIMER", (Hook *) 0, 1, 0, 0 },
{ "TOPIC", (Hook *) 0, 2, 0, 0 },
{ "WALL", (Hook *) 0, 2, 0, HF_LOOKONLY },
{ "WALLOP", (Hook *) 0, 3, 0, HF_LOOKONLY },
{ "WHO", (Hook *) 0, 6, 0, HF_LOOKONLY },
{ "WIDELIST", (Hook *) 0, 1, 0, HF_LOOKONLY },
{ "WINDOW", (Hook *) 0, 2, 0, HF_NORECURSE },
{ "WINDOW_KILL", (Hook *) 0, 1, 0, 0 },
{ "WINDOW_SWAP", (Hook *) 0, 2, 0, 0 }
};
static char *
fill_it_out(str, params)
char *str;
int params;
{
char lbuf[BIG_BUFFER_SIZE + 1];
char *arg,
*free_ptr = (char *) 0,
*ptr;
int i = 0;
malloc_strcpy(&free_ptr, str);
ptr = free_ptr;
*lbuf = (char) 0;
while ((arg = next_arg(ptr, &ptr)) != NULL)
{
if (*lbuf)
strmcat(lbuf, " ", BIG_BUFFER_SIZE);
strmcat(lbuf, arg, BIG_BUFFER_SIZE);
if (++i == params)
break;
}
for (; i < params; i++)
strmcat(lbuf, (i < params-1) ? " %" : " *", BIG_BUFFER_SIZE);
if (*ptr)
{
strmcat(lbuf, " ", BIG_BUFFER_SIZE);
strmcat(lbuf, ptr, BIG_BUFFER_SIZE);
}
malloc_strcpy(&free_ptr, lbuf);
return (free_ptr);
}
/*
* A variety of comparison functions used by the hook routines follow.
*/
struct CmpInfoStruc
{
int ServerRequired;
int SkipSerialNum;
int SerialNumber;
int Flags;
} cmp_info;
#define CIF_NOSERNUM 0x0001
#define CIF_SKIP 0x0002
int cmpinfodone = 0;
static void
setup_struct(ServReq, SkipSer, SerNum, flags)
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(_Item, Name)
List *_Item;
char *Name;
{
int comp;
Hook *Item = (Hook *)_Item;
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;
}
static int
Add_Remove_Check_List(_Item, _Item2)
List *_Item;
List *_Item2;
{
return Add_Remove_Check(_Item, _Item->name);
}
static void
add_numeric_hook(numeric, nick, stuff, noisy, not, server, sernum)
int numeric;
char *nick,
*stuff;
int noisy,
not;
int server,
sernum;
{
NumericList *entry;
Hook *new;
char buf[4];
snprintf(buf, sizeof buf, "%3.3u", numeric);
if ((entry = (NumericList *) find_in_list((List **) &numeric_list, buf, 0)) ==
(NumericList *) 0)
{
entry = (NumericList *) new_malloc(sizeof(NumericList));
entry->name = (char *) 0;
entry->list = (Hook *) 0;
malloc_strcpy(&(entry->name), buf);
add_to_list((List **) &numeric_list, (List *) entry);
}
setup_struct((server==-1) ? -1 : (server & ~HS_NOGENERIC), sernum-1, sernum, 0);
if ((new = (Hook *) remove_from_list_ext((List **) &(entry->list), nick, Add_Remove_Check)) != NULL)
{
new->not = 1;
new_free(&(new->nick));
new_free(&(new->stuff));
wait_new_free((char **) &new);
}
new = (Hook *) new_malloc(sizeof(Hook));
new->nick = (char *) 0;
new->noisy = noisy;
new->server = server;
new->sernum = sernum;
new->not = not;
new->global = loading_global;
new->stuff = (char *) 0;
malloc_strcpy(&new->nick, nick);
malloc_strcpy(&new->stuff, stuff);
upper(new->nick);
add_to_list_ext((List **) &(entry->list), (List *) new, Add_Remove_Check_List);
}
/*
* 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(which, nick, stuff, noisy, not, server, sernum)
int which;
char *nick,
*stuff;
int noisy,
not;
int server,
sernum;
{
Hook *new;
if (which < 0)
{
add_numeric_hook(-which, nick, stuff, noisy, not, server,
sernum);
return;
}
setup_struct((server == -1) ? -1 : (server & ~HS_NOGENERIC), sernum-1, sernum, 0);
if ((new = (Hook *) remove_from_list_ext((List **) &(hook_functions[which].list), nick, Add_Remove_Check)) != NULL)
{
new->not = 1;
new_free(&(new->nick));
new_free(&(new->stuff));
wait_new_free((char **) &new);
}
new = (Hook *) new_malloc(sizeof(Hook));
new->nick = (char *) 0;
new->noisy = noisy;
new->server = server;
new->sernum = sernum;
new->not = not;
new->stuff = (char *) 0;
new->global = loading_global;
malloc_strcpy(&new->nick, nick);
malloc_strcpy(&new->stuff, stuff);
upper(new->nick);
add_to_list_ext((List **) &(hook_functions[which].list), (List *) new, Add_Remove_Check_List);
}
/* show_hook shows a single hook */
extern void
show_hook(list, name)
Hook *list;
char *name;
{
if (list->server != -1)
say("On %s from \"%s\" do %s [%s] <%d> (Server %d)%s",
name, list->nick,
(list->not ? "nothing" : list->stuff),
noise_level[list->noisy], list->sernum,
list->server&~HS_NOGENERIC,
(list->server&HS_NOGENERIC) ? " Exclusive" : empty_string);
else
say("On %s from \"%s\" do %s [%s] <%d>",
name, list->nick,
(list->not ? "nothing" : list->stuff),
noise_level[list->noisy],
list->sernum);
}
/*
* 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(numeric)
int numeric;
{
NumericList *tmp;
Hook *list;
char buf[4];
int cnt = 0;
if (numeric)
{
snprintf(buf, sizeof buf, "%3.3u", numeric);
if ((tmp = (NumericList *) find_in_list((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(which)
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);
}
/*
* 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 */
/*VARARGS*/
int
#ifdef HAVE_STDARG_H
do_hook(int which, char *format, ...)
{
va_list vl;
#else
/**************************** Patched by Flier ******************************/
/*do_hook(which, format, arg1, arg2, arg3, arg4, arg5, arg6)*/
do_hook(which, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)
/****************************************************************************/
int which;
char *format;
char *arg1,
*arg2,
*arg3,
*arg4,
*arg5,
/**************************** Patched by Flier ******************************/
/**arg6;*/
*arg6,
*arg7,
*arg8,
*arg9;
/****************************************************************************/
{
#endif
Hook *tmp, **list;
char *name = (char *) 0;
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;
size_t len;
char *foo;
#ifdef NEED_PUTBUF_DECLARED
/* make this buffer *much* bigger than needed */
u_char putbuf[2*BIG_BUFFER_SIZE + 1] = "";
#endif
PUTBUF_INIT
hook_level++;
#ifdef HAVE_STDARG_H
va_start(vl, format);
PUTBUF_SPRINTF(format, vl);
va_end(vl);
#else
/**************************** Patched by Flier ******************************/
/*snprintf(CP(putbuf), sizeof putbuf, format, arg1, arg2, arg3, arg4, arg5, arg6);*/
snprintf(putbuf, sizeof putbuf, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
/****************************************************************************/
#endif
if (which < 0)
{
NumericList *hook;
char buf[4];
snprintf(buf, sizeof buf, "%3.3u", -which);
if ((hook = (NumericList *) find_in_list((List **) &numeric_list, buf, 0))
!= NULL)
{
name = hook->name;
list = &hook->list;
}
else
list = (Hook **) 0;
}
else
{
if (hook_functions[which].mark && (hook_functions[which].flags & HF_NORECURSE))
list = (Hook **) 0;
else
{
list = &(hook_functions[which].list);
name = hook_functions[which].name;
}
}
if (!list)
{
RetVal = 1;
goto out;
}
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 = (Hook *) 0;
int nomorethisserial = 0;
for (tmp = *list;tmp;tmp = tmp->next)
{
currser = tmp->sernum;
if (currser != oldser) /* new serial number */
{
oldser = currser;
currmatch = oldmatch = nomorethisserial = 0;
if (bestmatch)
hook_array[hook_num++] = bestmatch;
bestmatch = (Hook *) 0;
}
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 = (Hook *) 0;
continue;
}
currmatch = wild_match(tmp->nick, putbuf);
if (currmatch > oldmatch)
{
oldmatch = currmatch;
bestmatch = tmp;
}
}
if (bestmatch)
hook_array[hook_num++] = bestmatch;
}
for (i = 0; i < hook_num; i++)
{
tmp = hook_array[i];
if (!tmp)
{
if (which >= 0)
hook_functions[which].mark--;
goto out;
}
if (tmp->not)
continue;
send_text_flag = which;
if (tmp->noisy > QUIET)
say("%s activated by \"%s\"", name, putbuf);
display = window_display;
if (tmp->noisy < NOISY)
window_display = 0;
save_message_from();
old_in_on_who = in_on_who;
if (which == WHO_LIST || (which <= -311 && which >= -318))
in_on_who = 1;
len = strlen(tmp->stuff) + 1;
foo = new_malloc(len);
bcopy(tmp->stuff, foo, len);
parse_line((char *) 0, foo, putbuf, 0, 0, 1);
new_free(&foo);
in_on_who = old_in_on_who;
window_display = display;
send_text_flag = -1;
restore_message_from();
if (!tmp->noisy && !tmp->sernum)
RetVal = 0;
}
if (which >= 0)
hook_functions[which].mark--;
out:
PUTBUF_END
return really_free(--hook_level), RetVal;
}
static void
remove_numeric_hook(numeric, nick, server, sernum, quiet)
int numeric;
char *nick;
int server;
int sernum;
int quiet;
{
NumericList *hook;
Hook *tmp,
*next;
char buf[4];
snprintf(buf, sizeof buf, "%3.3u", numeric);
if ((hook = (NumericList *) find_in_list((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((List **) &(hook->list), nick)) != NULL)
{
if (!quiet)
say("\"%s\" removed from %s list", nick, buf);
tmp->not = 1;
new_free(&(tmp->nick));
new_free(&(tmp->stuff));
wait_new_free((char **) &tmp);
if (hook->list == (Hook *) 0)
{
if ((hook = (NumericList *) remove_from_list((List **) &numeric_list, buf)) != NULL)
{
new_free(&(hook->name));
new_free(&hook);
}
}
return;
}
}
else
{
for (tmp = hook->list; tmp; tmp = next)
{
next = tmp->next;
tmp->not = 1;
new_free(&(tmp->nick));
new_free(&(tmp->stuff));
wait_new_free((char **) &tmp);
}
hook->list = (Hook *) 0;
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);
}
#ifdef INCLUDE_UNUSED_FUNCTIONS
static void
flush_on_hooks()
{
int x;
int old_display = window_display;
window_display = 0;
for (x = 100 ; x < 999; x++)
remove_numeric_hook(x, (char *) 0, 1, x, 0);
for (x = 0 ; x < NUMBER_OF_LISTS; x++)
remove_hook(x, (char *) 0, 1, x, 0);
window_display = old_display;
}
#endif /* INCLUDE_UNUSED_FUNCTIONS */
extern void
remove_hook(which, nick, server, sernum, quiet)
int which;
char *nick;
int server,
sernum,
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((List **) &hook_functions[which].list, nick, Add_Remove_Check)) != NULL)
{
if (!quiet)
say("\"%s\" removed from %s list", nick, hook_functions[which].name);
tmp->not = 1;
new_free(&(tmp->nick));
new_free(&(tmp->stuff));
wait_new_free((char **) &tmp);
}
else if (!quiet)
say("\"%s\" is not on the %s list", nick, hook_functions[which].name);
}
else
{
for(tmp = hook_functions[which].list; tmp; tmp=next)
{
next = tmp->next;
tmp->not = 1;
new_free(&(tmp->nick));
new_free(&(tmp->stuff));
wait_new_free((char **) &tmp);
}
hook_functions[which].list = (Hook *) 0;
if (!quiet)
say("The %s list is empty", hook_functions[which].name);
}
}
/* on: The ON command */
/*ARGSUSED*/
void
on(command, args, subargs)
char *command,
*args,
*subargs;
{
char *func,
*nick,
*serial,
*cmd = (char *) 0;
/* int noisy = NORMAL, not = 0, do_remove = 0, -not used */
int noisy,
not,
server,
sernum,
do_remove,
which = 0,
cnt,
i,
ambiguous = 0;
size_t len;
if (get_int_var(NOVICE_VAR) && !load_depth)
{
yell("*** You may not type ON commands when you have the NOVICE");
yell("*** variable set to ON. Some ON commands may cause a");
yell("*** security breach on your machine, or enable another");
yell("*** user to control your IRC session. Read the help files");
yell("*** in /HELP ON before using ON");
return;
}
if ((func = next_arg(args, &args)) != NULL)
{
if (*func == '#')
{
if (!(serial = next_arg(args, &args)))
{
say("No serial number specified");
return;
}
sernum = atoi(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 ((len = strlen(func)) == 0)
{
say("You must specify an event type!");
return;
}
malloc_strcpy(&cmd, func);
upper(cmd);
for (cnt = 0, i = 0; i < NUMBER_OF_LISTS; i++)
{
if (!strncmp(cmd, 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(cmd))
{
which = atoi(cmd);
if ((which < 0) || (which > 999))
{
say("Numerics must be between 001 and 999");
goto out;
}
which = -which;
}
else
{
say("No such ON function: %s", func);
goto out;
}
}
else if (cnt > 1)
ambiguous = 1;
else
{
if (get_int_var(INPUT_PROTECTION_VAR) && !my_strnicmp(hook_functions[which].name, "INPUT", 5))
{
say("You cannot use /ON INPUT with INPUT_PROTECTION set");
say("Please read /HELP ON INPUT, and /HELP SET INPUT_PROTECTION");
goto out;
}
}
do_remove = 0;
not = 0;
switch (*args)
{
case '-':
do_remove = 1;
args++;
break;
case '^':
not = 1;
args++;
break;
}
if ((nick = new_next_arg(args, &args)) != NULL)
{
if (ambiguous)
{
say("Ambiguous ON function: %s", func);
goto out;
}
if (which < 0)
nick = fill_it_out(nick, 1);
else
nick = fill_it_out(nick,
hook_functions[which].params);
if (do_remove)
{
if (strlen(nick) == 0)
say("No expression specified");
else
remove_hook(which, nick, server,
sernum, 0);
}
else
{
if (not)
args = empty_string;
if (*nick)
{
if (*args == LEFT_BRACE)
{
char *ptr;
ptr = MatchingBracket(++args,
LEFT_BRACE, RIGHT_BRACE);
if (!ptr)
{
say("Unmatched brace in ON");
new_free(&nick);
goto out;
}
else if (ptr[1])
{
say("Junk after closing brace in ON");
new_free(&nick);
goto out;
}
else
*ptr = '\0';
}
add_hook(which, nick, args, noisy, not, server, sernum);
if (which < 0)
say("On %3.3u from \"%s\" do %s [%s] <%d>",
-which, nick, (not ? "nothing" : args),
noise_level[noisy], sernum);
else
say("On %s from \"%s\" do %s [%s] <%d>",
hook_functions[which].name, nick,
(not ? "nothing" : args),
noise_level[noisy], sernum);
}
}
new_free(&nick);
}
else
{
if (do_remove)
{
if (ambiguous)
{
say("Ambiguous ON function: %s", func);
goto out;
}
remove_hook(which, (char *) 0, server,
sernum, 0);
}
else
{
if (which < 0)
{
if (show_numeric_list(-which) == 0)
say("The %3.3u list is empty.",
-which);
}
else if (ambiguous)
{
for (i = 0; i < NUMBER_OF_LISTS; i++)
if (!strncmp(cmd,
hook_functions[i].name, len))
(void)show_list(i);
}
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.");
}
out:
new_free(&cmd);
}
static void
write_hook(fp, hook, name)
FILE *fp;
Hook *hook;
char *name;
{
char *stuff = (char *) 0;
if (hook->server!=-1)
return;
switch (hook->noisy)
{
case SILENT:
stuff = "^";
break;
case QUIET:
stuff = "-";
break;
case NORMAL:
stuff = empty_string;
break;
case NOISY:
stuff = "+";
break;
}
if (hook->sernum)
fprintf(fp, "ON #%s%s %d \"%s\"", stuff, name, hook->sernum,
hook->nick);
else
fprintf(fp, "ON %s%s \"%s\"", stuff, name, hook->nick);
fprintf(fp, " %s\n", 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
*/
void
save_hooks(fp, do_all)
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);
}
}
/**************************** Patched by Flier ******************************/
void DumpOn() {
int i;
Hook *tmp;
Hook *tmpdel;
NumericList *hook;
NumericList *hookdel;
for (i=0;i<NUMBER_OF_LISTS;i++) {
for (tmp=hook_functions[i].list;tmp;) {
tmpdel=tmp;
tmp=tmp->next;
tmpdel->not=1;
new_free(&(tmpdel->nick));
new_free(&(tmpdel->stuff));
wait_new_free((char **) &tmpdel);
}
hook_functions[i].list=(Hook *) 0;
}
for (hook=numeric_list;hook;) {
hookdel=hook;
hook=hook->next;
for(tmp=hookdel->list;tmp;) {
tmpdel=tmp;
tmp=tmp->next;
tmpdel->not = 1;
new_free(&(tmpdel->nick));
new_free(&(tmpdel->stuff));
wait_new_free((char **) &tmpdel);
}
hookdel->list=(Hook *) 0;
}
}
/****************************************************************************/
syntax highlighted by Code2HTML, v. 0.9.1