1 /*
2 * hook.c: Does those naughty hook functions.
3 *
4 * Written By Michael Sandrof
5 *
6 * Copyright (c) 1990 Michael Sandrof.
7 * Copyright (c) 1991, 1992 Troy Rollo.
8 * Copyright (c) 1992-2000 Matthew R. Green.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 #include "irc.h"
36 IRCII_RCSID("@(#)$Id: hook.c,v 1.48 2000/04/04 13:49:40 mrg Exp $");
37
38 #include "hook.h"
39 #include "vars.h"
40 #include "ircaux.h"
41 #include "alias.h"
42 #include "list.h"
43 #include "window.h"
44 #include "server.h"
45 #include "output.h"
46 #include "edit.h"
47
48 #include "dma.h"
49
50 #ifdef INCLUDE_UNUSED_FUNCTIONS
51 static void flush_on_hooks _((void));
52 #endif /* INCLUDE_UNUSED_FUNCTIONS */
53 static u_char *fill_it_out _((u_char *, int));
54 static void setup_struct _((int, int, int, int));
55 static int Add_Remove_Check _((List *, u_char *));
56 static int Add_Remove_Check_List _((List *, List*));
57 static void add_numeric_hook _((int, u_char *, u_char *, int, int, int, int));
58 static void add_hook _((int, u_char *, u_char *, int, int, int, int));
59 static int show_numeric_list _((int));
60 static int show_list _((int));
61 static void remove_numeric_hook _((int, u_char *, int, int, int));
62 static void write_hook _((FILE *, Hook *, char *));
63
64 #define SILENT 0
65 #define QUIET 1
66 #define NORMAL 2
67 #define NOISY 3
68
69 /*
70 * The various ON levels: SILENT means the DISPLAY will be OFF and it will
71 * suppress the default action of the event, QUIET means the display will be
72 * OFF but the default action will still take place, NORMAL means you will be
73 * notified when an action takes place and the default action still occurs,
74 * NOISY means you are notified when an action occur plus you see the action
75 * in the display and the default actions still occurs
76 */
77 static char *noise_level[] = { "SILENT", "QUIET", "NORMAL", "NOISY" };
78
79 #define HS_NOGENERIC 0x1000
80 #define HF_LOOKONLY 0x0001
81 #define HF_NORECURSE 0x0002
82 #define HF_GLOBAL 0x0004
83
84 extern int load_depth;
85
86 int in_on_who = 0;
87
88 NumericList *numeric_list = (NumericList *) 0;
89 /* hook_functions: the list of all hook functions available */
90 HookFunc FAR hook_functions[] =
91 {
92 { "ACTION", (Hook *) 0, 3, 0, 0 },
93 { "CHANNEL_NICK", (Hook *) 0, 3, 0, 0 },
94 { "CHANNEL_SIGNOFF", (Hook *) 0, 3, 0, 0 },
95 { "CONNECT", (Hook *) 0, 1, 0, 0 },
96 { "CTCP", (Hook *) 0, 4, 0, 0 },
97 { "CTCP_REPLY", (Hook *) 0, 3, 0, 0 },
98 { "DCC_CHAT", (Hook *) 0, 2, 0, 0 },
99 { "DCC_CONNECT", (Hook *) 0, 2, 0, 0 },
100 { "DCC_ERROR", (Hook *) 0, 6, 0, 0 },
101 { "DCC_LOST", (Hook *) 0, 2, 0, 0 },
102 { "DCC_RAW", (Hook *) 0, 3, 0, 0 },
103 { "DCC_REQUEST", (Hook *) 0, 4, 0, 0 },
104 { "DISCONNECT", (Hook *) 0, 1, 0, 0 },
105 { "ENCRYPTED_NOTICE", (Hook *) 0, 3, 0, 0 },
106 { "ENCRYPTED_PRIVMSG", (Hook *) 0, 3, 0, 0 },
107 { "EXEC", (Hook *) 0, 2, 0, 0 },
108 { "EXEC_ERRORS", (Hook *) 0, 2, 0, 0 },
109 { "EXEC_EXIT", (Hook *) 0, 3, 0, 0 },
110 { "EXEC_PROMPT", (Hook *) 0, 2, 0, 0 },
111 { "EXIT", (Hook *) 0, 1, 0, 0 },
112 { "FLOOD", (Hook *) 0, 3, 0, 0 },
113 { "HELP", (Hook *) 0, 2, 0, 0 },
114 { "HOOK", (Hook *) 0, 1, 0, 0 },
115 #ifdef SUPPORT_ICB
116 { "ICB_STATUS", (Hook *) 0, 2, 0, 0 },
117 { "ICB_ERROR", (Hook *) 0, 1, 0, 0 },
118 #endif
119 { "IDLE", (Hook *) 0, 1, 0, 0 },
120 { "INPUT", (Hook *) 0, 1, 0, 0 },
121 { "INVITE", (Hook *) 0, 2, 0, 0 },
122 { "JOIN", (Hook *) 0, 3, 0, 0 },
123 { "KICK", (Hook *) 0, 3, 0, HF_LOOKONLY },
124 { "LEAVE", (Hook *) 0, 2, 0, 0 },
125 { "LIST", (Hook *) 0, 3, 0, HF_LOOKONLY },
126 { "MAIL", (Hook *) 0, 2, 0, 0 },
127 { "MODE", (Hook *) 0, 3, 0, 0 },
128 { "MSG", (Hook *) 0, 2, 0, 0 },
129 { "MSG_GROUP", (Hook *) 0, 3, 0, 0 },
130 { "NAMES", (Hook *) 0, 2, 0, HF_LOOKONLY },
131 { "NICKNAME", (Hook *) 0, 2, 0, 0 },
132 { "NOTE", (Hook *) 0, 10, 0, 0 },
133 { "NOTICE", (Hook *) 0, 2, 0, 0 },
134 { "NOTIFY_SIGNOFF", (Hook *) 0, 3, 0, 0 },
135 { "NOTIFY_SIGNON", (Hook *) 0, 4, 0, 0 },
136 { "PUBLIC", (Hook *) 0, 3, 0, 0 },
137 { "PUBLIC_MSG", (Hook *) 0, 3, 0, 0 },
138 { "PUBLIC_NOTICE", (Hook *) 0, 3, 0, 0 },
139 { "PUBLIC_OTHER", (Hook *) 0, 3, 0, 0 },
140 { "RAW_IRC", (Hook *) 0, 1, 0, 0 },
141 { "SEND_ACTION", (Hook *) 0, 2, 0, 0 },
142 { "SEND_DCC_CHAT", (Hook *) 0, 2, 0, 0 },
143 { "SEND_MSG", (Hook *) 0, 2, 0, 0 },
144 { "SEND_NOTICE", (Hook *) 0, 2, 0, 0 },
145 { "SEND_PUBLIC", (Hook *) 0, 2, 0, 0 },
146 { "SEND_TALK", (Hook *) 0, 2, 0, 0 },
147 { "SERVER_NOTICE", (Hook *) 0, 1, 0, 0 },
148 { "SIGNOFF", (Hook *) 0, 1, 0, 0 },
149 { "TALK", (Hook *) 0, 2, 0, 0 },
150 { "TIMER", (Hook *) 0, 1, 0, 0 },
151 { "TOPIC", (Hook *) 0, 2, 0, 0 },
152 { "WALL", (Hook *) 0, 2, 0, HF_LOOKONLY },
153 { "WALLOP", (Hook *) 0, 3, 0, HF_LOOKONLY },
154 { "WHO", (Hook *) 0, 6, 0, HF_LOOKONLY },
155 { "WIDELIST", (Hook *) 0, 1, 0, HF_LOOKONLY },
156 { "WINDOW", (Hook *) 0, 2, 0, HF_NORECURSE },
157 { "WINDOW_KILL", (Hook *) 0, 1, 0, 0 },
158 { "WINDOW_SWAP", (Hook *) 0, 2, 0, 0 }
159 };
160
161 static u_char *
fill_it_out(str,params)162 fill_it_out(str, params)
163 u_char *str;
164 int params;
165 {
166 u_char lbuf[BIG_BUFFER_SIZE + 1];
167 u_char *arg,
168 *free_ptr = (u_char *) 0,
169 *ptr;
170 int i = 0;
171
172 malloc_strcpy(&free_ptr, str);
173 ptr = free_ptr;
174 *lbuf = (u_char) 0;
175 while ((arg = next_arg(ptr, &ptr)) != NULL)
176 {
177 if (*lbuf)
178 my_strmcat(lbuf, " ", BIG_BUFFER_SIZE);
179 my_strmcat(lbuf, arg, BIG_BUFFER_SIZE);
180 if (++i == params)
181 break;
182 }
183 for (; i < params; i++)
184 my_strmcat(lbuf, (i < params-1) ? " %" : " *", BIG_BUFFER_SIZE);
185 if (*ptr)
186 {
187 my_strmcat(lbuf, " ", BIG_BUFFER_SIZE);
188 my_strmcat(lbuf, ptr, BIG_BUFFER_SIZE);
189 }
190 malloc_strcpy(&free_ptr, lbuf);
191 return (free_ptr);
192 }
193
194
195 /*
196 * A variety of comparison functions used by the hook routines follow.
197 */
198
199 struct CmpInfoStruc
200 {
201 int ServerRequired;
202 int SkipSerialNum;
203 int SerialNumber;
204 int Flags;
205 } cmp_info;
206
207 #define CIF_NOSERNUM 0x0001
208 #define CIF_SKIP 0x0002
209
210 int cmpinfodone = 0;
211
212 static void
setup_struct(ServReq,SkipSer,SerNum,flags)213 setup_struct(ServReq, SkipSer, SerNum, flags)
214 int ServReq;
215 int SkipSer;
216 int SerNum;
217 int flags;
218 {
219 cmp_info.ServerRequired = ServReq;
220 cmp_info.SkipSerialNum = SkipSer;
221 cmp_info.SerialNumber = SerNum;
222 cmp_info.Flags = flags;
223 }
224
225 static int
Add_Remove_Check(_Item,Name)226 Add_Remove_Check(_Item, Name)
227 List *_Item;
228 u_char *Name;
229 {
230 int comp;
231 Hook *Item = (Hook *)_Item;
232
233 if (cmp_info.SerialNumber != Item->sernum)
234 return (Item->sernum > cmp_info.SerialNumber) ? 1 : -1;
235 if ((comp = my_stricmp(Item->nick, Name)) != 0)
236 return comp;
237 if (Item->server != cmp_info.ServerRequired)
238 return (Item->server > cmp_info.ServerRequired) ? 1 : -1;
239 return 0;
240 }
241
242 static int
Add_Remove_Check_List(_Item,_Item2)243 Add_Remove_Check_List(_Item, _Item2)
244 List *_Item;
245 List *_Item2;
246 {
247 return Add_Remove_Check(_Item, _Item->name);
248 }
249
250 static void
add_numeric_hook(numeric,nick,stuff,noisy,not,server,sernum)251 add_numeric_hook(numeric, nick, stuff, noisy, not, server, sernum)
252 int numeric;
253 u_char *nick,
254 *stuff;
255 int noisy,
256 not;
257 int server,
258 sernum;
259 {
260 NumericList *entry;
261 Hook *new;
262 u_char buf[8];
263
264 snprintf(CP(buf), sizeof(buf)-1, "%3.3u", numeric);
265 buf[sizeof(buf)-1] = '\0';
266 if ((entry = (NumericList *) find_in_list((List **) &numeric_list, buf, 0)) ==
267 (NumericList *) 0)
268 {
269 entry = (NumericList *) new_malloc(sizeof(NumericList));
270 entry->name = (char *) 0;
271 entry->list = (Hook *) 0;
272 malloc_strcpy((u_char **) &(entry->name), buf);
273 add_to_list((List **) &numeric_list, (List *) entry);
274 }
275
276 setup_struct((server==-1) ? -1 : (server & ~HS_NOGENERIC), sernum-1, sernum, 0);
277 if ((new = (Hook *) remove_from_list_ext((List **) &(entry->list), nick, Add_Remove_Check)) != NULL)
278 {
279 new->not = 1;
280 new_free(&(new->nick));
281 new_free(&(new->stuff));
282 wait_new_free((u_char **) &new);
283 }
284 new = (Hook *) new_malloc(sizeof(Hook));
285 new->nick = (u_char *) 0;
286 new->noisy = noisy;
287 new->server = server;
288 new->sernum = sernum;
289 new->not = not;
290 new->global = loading_global;
291 new->stuff = (u_char *) 0;
292 malloc_strcpy(&new->nick, nick);
293 malloc_strcpy(&new->stuff, stuff);
294 upper(new->nick);
295 add_to_list_ext((List **) &(entry->list), (List *) new, Add_Remove_Check_List);
296 }
297
298 /*
299 * add_hook: Given an index into the hook_functions array, this adds a new
300 * entry to the list as specified by the rest of the parameters. The new
301 * entry is added in alphabetical order (by nick).
302 */
303 static void
add_hook(which,nick,stuff,noisy,not,server,sernum)304 add_hook(which, nick, stuff, noisy, not, server, sernum)
305 int which;
306 u_char *nick,
307 *stuff;
308 int noisy,
309 not;
310 int server,
311 sernum;
312 {
313 Hook *new;
314
315 if (which < 0)
316 {
317 add_numeric_hook(-which, nick, stuff, noisy, not, server,
318 sernum);
319 return;
320 }
321 setup_struct((server == -1) ? -1 : (server & ~HS_NOGENERIC), sernum-1, sernum, 0);
322 if ((new = (Hook *) remove_from_list_ext((List **) &(hook_functions[which].list), nick, Add_Remove_Check)) != NULL)
323 {
324 new->not = 1;
325 new_free(&(new->nick));
326 new_free(&(new->stuff));
327 wait_new_free((u_char **) &new);
328 }
329 new = (Hook *) new_malloc(sizeof(Hook));
330 new->nick = (u_char *) 0;
331 new->noisy = noisy;
332 new->server = server;
333 new->sernum = sernum;
334 new->not = not;
335 new->stuff = (u_char *) 0;
336 new->global = loading_global;
337 malloc_strcpy(&new->nick, nick);
338 malloc_strcpy(&new->stuff, stuff);
339 upper(new->nick);
340 add_to_list_ext((List **) &(hook_functions[which].list), (List *) new, Add_Remove_Check_List);
341 }
342
343 /* show_hook shows a single hook */
344 extern void
345 show_hook(list, name)
346 Hook *list;
347 char *name;
348 {
349 if (list->server != -1)
350 say("On %s from \"%s\" do %s [%s] <%d> (Server %d)%s",
351 name, list->nick,
352 (list->not ? (u_char *) "nothing" : list->stuff),
353 noise_level[list->noisy], list->sernum,
354 list->server&~HS_NOGENERIC,
355 (list->server&HS_NOGENERIC) ? (u_char *) " Exclusive" : empty_string);
356 else
357 say("On %s from \"%s\" do %s [%s] <%d>",
358 name, list->nick,
359 (list->not ? (u_char *) "nothing" : list->stuff),
360 noise_level[list->noisy],
361 list->sernum);
362 }
363
364 /*
365 * show_numeric_list: If numeric is 0, then all numeric lists are displayed.
366 * If numeric is non-zero, then that particular list is displayed. The total
367 * number of entries displayed is returned
368 */
369 static int
show_numeric_list(numeric)370 show_numeric_list(numeric)
371 int numeric;
372 {
373 NumericList *tmp;
374 Hook *list;
375 u_char buf[8];
376 int cnt = 0;
377
378 if (numeric)
379 {
380 snprintf(CP(buf), sizeof(buf)-1, "%3.3u", numeric);
381 buf[sizeof(buf)-1] = '\0';
382 if ((tmp = (NumericList *) find_in_list((List **) &numeric_list, buf, 0))
383 != NULL)
384 {
385 for (list = tmp->list; list; list = list->next, cnt++)
386 show_hook(list, tmp->name);
387 }
388 }
389 else
390 {
391 for (tmp = numeric_list; tmp; tmp = tmp->next)
392 {
393 for (list = tmp->list; list; list = list->next, cnt++)
394 show_hook(list, tmp->name);
395 }
396 }
397 return (cnt);
398 }
399
400 /*
401 * show_list: Displays the contents of the list specified by the index into
402 * the hook_functions array. This function returns the number of entries in
403 * the list displayed
404 */
405 static int
show_list(which)406 show_list(which)
407 int which;
408 {
409 Hook *list;
410 int cnt = 0;
411
412 /* Less garbage when issueing /on without args. (lynx) */
413 for (list = hook_functions[which].list; list; list = list->next, cnt++)
414 show_hook(list, hook_functions[which].name);
415 return (cnt);
416 }
417
418 /*
419 * do_hook: This is what gets called whenever a MSG, INVITES, WALL, (you get
420 * the idea) occurs. The nick is looked up in the appropriate list. If a
421 * match is found, the stuff field from that entry in the list is treated as
422 * if it were a command. First it gets expanded as though it were an alias
423 * (with the args parameter used as the arguments to the alias). After it
424 * gets expanded, it gets parsed as a command. This will return as its value
425 * the value of the noisy field of the found entry, or -1 if not found.
426 */
427 /* huh-huh.. this sucks.. im going to re-write it so that it works */
428 /*VARARGS*/
429 int
430 #ifdef HAVE_STDARG_H
do_hook(int which,char * format,...)431 do_hook(int which, char *format, ...)
432 {
433 va_list vl;
434 #else
435 do_hook(which, format, arg1, arg2, arg3, arg4, arg5, arg6)
436 int which;
437 char *format;
438 char *arg1,
439 *arg2,
440 *arg3,
441 *arg4,
442 *arg5,
443 *arg6;
444 {
445 #endif /* HAVE_STDARG_H */
446 Hook *tmp, **list;
447 u_char lbuf[(BIG_BUFFER_SIZE*4) + 1]; /* huge buffer ;) */
448 char *name = (char *) 0;
449 int RetVal = 1;
450 unsigned int display;
451 int i,
452 old_in_on_who;
453 Hook *hook_array[2048];
454 int hook_num = 0;
455 static int hook_level = 0;
456 size_t len;
457 u_char *foo;
458
459 hook_level++;
460 bzero(lbuf, sizeof(lbuf));
461
462 #ifdef HAVE_STDARG_H
463 va_start(vl, format);
464 vsnprintf(CP(lbuf), sizeof(lbuf)-1, format, vl);
465 va_end(vl);
466 #else
467 snprintf(CP(lbuf), sizeof(lbuf)-1, format, arg1, arg2, arg3, arg4, arg5, arg6);
468 #endif /* HAVE_STDARG_H */
469 if (which < 0)
470 {
471 NumericList *hook;
472 u_char buf[8];
473
474 snprintf(CP(buf), sizeof(buf)-1, "%3.3u", -which);
475 buf[sizeof(buf)-1] = '\0';
476 if ((hook = (NumericList *) find_in_list((List **) &numeric_list, buf, 0))
477 != NULL)
478 {
479 name = hook->name;
480 list = &hook->list;
481 }
482 else
483 list = (Hook **) 0;
484 }
485 else
486 {
487 if (hook_functions[which].mark && (hook_functions[which].flags & HF_NORECURSE))
488 list = (Hook **) 0;
489 else
490 {
491 list = &(hook_functions[which].list);
492 name = hook_functions[which].name;
493 }
494 }
495 if (!list)
496 return really_free(--hook_level), 1;
497
498 if (which >= 0)
499 hook_functions[which].mark++;
500 /* not attached, so dont "fix" it */
501 {
502 int currser = 0, oldser = 0;
503 int currmatch = 0, oldmatch = 0;
504 Hook *bestmatch = (Hook *) 0;
505 int nomorethisserial = 0;
506
507 for (tmp = *list;tmp;tmp = tmp->next)
508 {
509 currser = tmp->sernum;
510 if (currser != oldser) /* new serial number */
511 {
512 oldser = currser;
513 currmatch = oldmatch = nomorethisserial = 0;
514 if (bestmatch)
515 hook_array[hook_num++] = bestmatch;
516 bestmatch = (Hook *) 0;
517 }
518
519 if (nomorethisserial)
520 continue;
521 /* if there is a specific server
522 hook and it doesnt match, then
523 we make sure nothing from
524 this serial number gets hooked */
525 if ((tmp->server != -1) &&
526 (tmp->server & HS_NOGENERIC) &&
527 (tmp->server != (from_server & HS_NOGENERIC)))
528 {
529 nomorethisserial = 1;
530 bestmatch = (Hook *) 0;
531 continue;
532 }
533 currmatch = wild_match(tmp->nick,lbuf);
534 if (currmatch > oldmatch)
535 {
536 oldmatch = currmatch;
537 bestmatch = tmp;
538 }
539 }
540 if (bestmatch)
541 hook_array[hook_num++] = bestmatch;
542 }
543
544 for (i = 0; i < hook_num; i++)
545 {
546 tmp = hook_array[i];
547 if (!tmp)
548 {
549 if (which >= 0)
550 hook_functions[which].mark--;
551 return really_free(--hook_level), RetVal;
552 }
553 if (tmp->not)
554 continue;
555 send_text_flag = which;
556 if (tmp->noisy > QUIET)
557 say("%s activated by \"%s\"", name, lbuf);
558 display = window_display;
559 if (tmp->noisy < NOISY)
560 window_display = 0;
561
562 save_message_from();
563 old_in_on_who = in_on_who;
564 if (which == WHO_LIST || (which <= -311 && which >= -318))
565 in_on_who = 1;
566 len = my_strlen(tmp->stuff) + 1;
567 foo = new_malloc(len);
568 bcopy(tmp->stuff, foo, len);
569 parse_line((u_char *) 0, foo, lbuf, 0, 0, 1);
570 new_free(&foo);
571 in_on_who = old_in_on_who;
572 window_display = display;
573 send_text_flag = -1;
574 restore_message_from();
575 if (!tmp->noisy && !tmp->sernum)
576 RetVal = 0;
577 }
578 if (which >= 0)
579 hook_functions[which].mark--;
580 return really_free(--hook_level), RetVal;
581 }
582
583 static void
584 remove_numeric_hook(numeric, nick, server, sernum, quiet)
585 int numeric;
586 u_char *nick;
587 int server;
588 int sernum;
589 int quiet;
590 {
591 NumericList *hook;
592 Hook *tmp,
593 *next;
594 u_char buf[8];
595
596 snprintf(CP(buf), sizeof(buf)-1, "%3.3u", numeric);
597 buf[sizeof(buf)-1] = '\0';
598 if ((hook = (NumericList *) find_in_list((List **) &numeric_list, buf,0)) != NULL)
599 {
600 if (nick)
601 {
602 setup_struct((server == -1) ? -1 :
603 (server & ~HS_NOGENERIC), sernum - 1, sernum, 0);
604 if ((tmp = (Hook *) remove_from_list((List **) &(hook->list), nick)) != NULL)
605 {
606 if (!quiet)
607 say("\"%s\" removed from %s list", nick, buf);
608 tmp->not = 1;
609 new_free(&(tmp->nick));
610 new_free(&(tmp->stuff));
611 wait_new_free((u_char **) &tmp);
612 if (hook->list == (Hook *) 0)
613 {
614 if ((hook = (NumericList *) remove_from_list((List **) &numeric_list, buf)) != NULL)
615 {
616 new_free(&(hook->name));
617 new_free(&hook);
618 }
619 }
620 return;
621 }
622 }
623 else
624 {
625 for (tmp = hook->list; tmp; tmp = next)
626 {
627 next = tmp->next;
628 tmp->not = 1;
629 new_free(&(tmp->nick));
630 new_free(&(tmp->stuff));
631 wait_new_free((u_char **) &tmp);
632 }
633 hook->list = (Hook *) 0;
634 if (!quiet)
635 say("The %s list is empty", buf);
636 return;
637 }
638 }
639 if (quiet)
640 return;
641 if (nick)
642 say("\"%s\" is not on the %s list", nick, buf);
643 else
644 say("The %s list is empty", buf);
645 }
646
647 #ifdef INCLUDE_UNUSED_FUNCTIONS
648 static void
649 flush_on_hooks()
650 {
651 int x;
652 int old_display = window_display;
653
654 window_display = 0;
655 for (x = 100 ; x < 999; x++)
656 remove_numeric_hook(x, (u_char *) 0, 1, x, 0);
657 for (x = 0 ; x < NUMBER_OF_LISTS; x++)
658 remove_hook(x, (u_char *) 0, 1, x, 0);
659 window_display = old_display;
660 }
661 #endif /* INCLUDE_UNUSED_FUNCTIONS */
662
663 extern void
664 remove_hook(which, nick, server, sernum, quiet)
665 int which;
666 u_char *nick;
667 int server,
668 sernum,
669 quiet;
670 {
671 Hook *tmp,
672 *next;
673
674 if (which < 0)
675 {
676 remove_numeric_hook(-which, nick, server, sernum, quiet);
677 return;
678 }
679 if (nick)
680 {
681 setup_struct((server == -1) ? -1 : (server & ~HS_NOGENERIC),
682 sernum-1, sernum, 0);
683 if ((tmp = (Hook *) remove_from_list_ext((List **) &hook_functions[which].list, nick, Add_Remove_Check)) != NULL)
684 {
685 if (!quiet)
686 say("\"%s\" removed from %s list", nick, hook_functions[which].name);
687 tmp->not = 1;
688 new_free(&(tmp->nick));
689 new_free(&(tmp->stuff));
690 wait_new_free((u_char **) &tmp);
691 }
692 else if (!quiet)
693 say("\"%s\" is not on the %s list", nick, hook_functions[which].name);
694 }
695 else
696 {
697 for(tmp = hook_functions[which].list; tmp; tmp=next)
698 {
699 next = tmp->next;
700 tmp->not = 1;
701 new_free(&(tmp->nick));
702 new_free(&(tmp->stuff));
703 wait_new_free((u_char **) &tmp);
704 }
705 hook_functions[which].list = (Hook *) 0;
706 if (!quiet)
707 say("The %s list is empty", hook_functions[which].name);
708 }
709 }
710
711 /* on: The ON command */
712 /*ARGSUSED*/
713 void
714 on(command, args, subargs)
715 u_char *command,
716 *args,
717 *subargs;
718 {
719 u_char *func,
720 *nick,
721 *serial,
722 *cmd = (u_char *) 0;
723 /* int noisy = NORMAL, not = 0, do_remove = 0, -not used */
724 int noisy,
725 not,
726 server,
727 sernum,
728 do_remove,
729 which = 0,
730 cnt,
731 i;
732 size_t len;
733
734 if (get_int_var(NOVICE_VAR) && !load_depth)
735 {
736 yell("*** You may not type ON commands when you have the NOVICE");
737 yell("*** variable set to ON. Some ON commands may cause a");
738 yell("*** security breach on your machine, or enable another");
739 yell("*** user to control your IRC session. Read the help files");
740 yell("*** in /HELP ON before using ON");
741 return;
742 }
743 if ((func = next_arg(args, &args)) != NULL)
744 {
745 if (*func == '#')
746 {
747 if (!(serial = next_arg(args, &args)))
748 {
749 say("No serial number specified");
750 return;
751 }
752 sernum = my_atoi(serial);
753 func++;
754 }
755 else
756 sernum = 0;
757 switch (*func)
758 {
759 case '&':
760 server = from_server;
761 func++;
762 break;
763 case '@':
764 server = from_server|HS_NOGENERIC;
765 func++;
766 break;
767 default:
768 server = -1;
769 break;
770 }
771 switch (*func)
772 {
773 case '-':
774 noisy = QUIET;
775 func++;
776 break;
777 case '^':
778 noisy = SILENT;
779 func++;
780 break;
781 case '+':
782 noisy = NOISY;
783 func++;
784 break;
785 default:
786 noisy = NORMAL;
787 break;
788 }
789 if ((len = my_strlen(func)) == 0)
790 {
791 say("You must specify an event type!");
792 return;
793 }
794 malloc_strcpy(&cmd, func);
795 upper(cmd);
796 for (cnt = 0, i = 0; i < NUMBER_OF_LISTS; i++)
797 {
798 if (!my_strncmp(cmd, hook_functions[i].name, len))
799 {
800 if (my_strlen(hook_functions[i].name) == len)
801 {
802 cnt = 1;
803 which = i;
804 break;
805 }
806 else
807 {
808 cnt++;
809 which = i;
810 }
811 }
812 else if (cnt)
813 break;
814 }
815 if (cnt == 0)
816 {
817 if (is_number(cmd))
818 {
819 which = my_atoi(cmd);
820 if ((which < 0) || (which > 999))
821 {
822 say("Numerics must be between 001 and 999");
823 goto out;
824 }
825 which = -which;
826 }
827 else
828 {
829 say("No such ON function: %s", func);
830 goto out;
831 }
832 }
833 else if (cnt > 1)
834 {
835 say("Ambiguous ON function: %s", func);
836 goto out;
837 }
838 else
839 {
840 if (get_int_var(INPUT_PROTECTION_VAR) && !my_strnicmp(UP(hook_functions[which].name), UP("INPUT"), 5))
841 {
842 say("You cannot use /ON INPUT with INPUT_PROTECTION set");
843 say("Please read /HELP ON INPUT, and /HELP SET INPUT_PROTECTION");
844 goto out;
845 }
846 }
847 do_remove = 0;
848 not = 0;
849 switch (*args)
850 {
851 case '-':
852 do_remove = 1;
853 args++;
854 break;
855 case '^':
856 not = 1;
857 args++;
858 break;
859 }
860 if ((nick = new_next_arg(args, &args)) != NULL)
861 {
862 if (which < 0)
863 nick = fill_it_out(nick, 1);
864 else
865 nick = fill_it_out(nick,
866 hook_functions[which].params);
867 if (do_remove)
868 {
869 if (my_strlen(nick) == 0)
870 say("No expression specified");
871 else
872 remove_hook(which, nick, server,
873 sernum, 0);
874 }
875 else
876 {
877 if (not)
878 args = empty_string;
879 if (*nick)
880 {
881 if (*args == LEFT_BRACE)
882 {
883 u_char *ptr;
884
885 ptr = MatchingBracket(++args,
886 LEFT_BRACE, RIGHT_BRACE);
887 if (!ptr)
888 {
889 say("Unmatched brace in ON");
890 new_free(&nick);
891 goto out;
892 }
893 else if (ptr[1])
894 {
895 say("Junk after closing brace in ON");
896 new_free(&nick);
897 goto out;
898 }
899 else
900 *ptr = '\0';
901 }
902 add_hook(which, nick, args, noisy, not, server, sernum);
903 if (which < 0)
904 say("On %3.3u from \"%s\" do %s [%s] <%d>",
905 -which, nick, (not ? (u_char *) "nothing" : args),
906 noise_level[noisy], sernum);
907 else
908 say("On %s from \"%s\" do %s [%s] <%d>",
909 hook_functions[which].name, nick,
910 (not ? (u_char *) "nothing" : args),
911 noise_level[noisy], sernum);
912 }
913 }
914 new_free(&nick);
915 }
916 else
917 {
918 if (do_remove)
919 remove_hook(which, (u_char *) 0, server,
920 sernum, 0);
921 else
922 {
923 if (which < 0)
924 {
925 if (show_numeric_list(-which) == 0)
926 say("The %3.3u list is empty.",
927 -which);
928 }
929 else if (show_list(which) == 0)
930 say("The %s list is empty.",
931 hook_functions[which].name);
932 }
933 }
934 }
935 else
936 {
937 int total = 0;
938
939 say("ON listings:");
940 for (which = 0; which < NUMBER_OF_LISTS; which++)
941 total += show_list(which);
942 total += show_numeric_list(0);
943 if (total == 0)
944 say("All ON lists are empty.");
945 }
946 out:
947 new_free(&cmd);
948 }
949
950 static void
951 write_hook(fp, hook, name)
952 FILE *fp;
953 Hook *hook;
954 char *name;
955 {
956 char *stuff = (char *) 0;
957
958 if (hook->server!=-1)
959 return;
960 switch (hook->noisy)
961 {
962 case SILENT:
963 stuff = "^";
964 break;
965 case QUIET:
966 stuff = "-";
967 break;
968 case NORMAL:
969 stuff = CP(empty_string);
970 break;
971 case NOISY:
972 stuff = "+";
973 break;
974 }
975 if (hook->sernum)
976 fprintf(fp, "ON #%s%s %d \"%s\"", stuff, name, hook->sernum,
977 hook->nick);
978 else
979 fprintf(fp, "ON %s%s \"%s\"", stuff, name, hook->nick);
980 fprintf(fp, " %s\n", hook->stuff);
981 }
982
983 /*
984 * save_hooks: for use by the SAVE command to write the hooks to a file so it
985 * can be interpreted by the LOAD command
986 */
987 void
988 save_hooks(fp, do_all)
989 FILE *fp;
990 int do_all;
991 {
992 Hook *list;
993 NumericList *numeric;
994 int which;
995
996 for (which = 0; which < NUMBER_OF_LISTS; which++)
997 {
998 for (list = hook_functions[which].list; list; list = list->next)
999 if (!list->global || do_all)
1000 write_hook(fp,list, hook_functions[which].name);
1001 }
1002 for (numeric = numeric_list; numeric; numeric = numeric->next)
1003 {
1004 for (list = numeric->list; list; list = list->next)
1005 if (!list->global)
1006 write_hook(fp, list, numeric->name);
1007 }
1008 }
1009