Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
BitchX
GitHub Repository: BitchX/BitchX1.3
Path: blob/master/source/hook.c
1069 views
1
/*
2
* hook.c: Does those naughty hook functions.
3
*
4
* Written By Michael Sandrof
5
* Rewritten by Jeremy Nelson and then rewritten to use
6
* hash'd lists by Colten Edwards
7
* Copyright(c) 1997
8
*/
9
10
#define __hook_c
11
#include "irc.h"
12
static char cvsrevision[] = "$Id: hook.c 36 2008-05-07 10:26:50Z keaston $";
13
CVS_REVISION(hook_c)
14
#include "struct.h"
15
16
#include "hook.h"
17
#include "vars.h"
18
#include "ircaux.h"
19
#include "if.h"
20
#include "alias.h"
21
#include "list.h"
22
#include "window.h"
23
#include "server.h"
24
#include "output.h"
25
#include "commands.h"
26
#include "parse.h"
27
#include "misc.h"
28
#include "stack.h"
29
#ifdef WANT_TCL
30
#include "tcl_bx.h"
31
#endif
32
#define MAIN_SOURCE
33
#include "modval.h"
34
35
#include <stdarg.h>
36
37
/*
38
* The various ON levels: SILENT means the DISPLAY will be OFF and it will
39
* suppress the default action of the event, QUIET means the display will be
40
* OFF but the default action will still take place, NORMAL means you will be
41
* notified when an action takes place and the default action still occurs,
42
* NOISY means you are notified when an action occur plus you see the action
43
* in the display and the default actions still occurs
44
*/
45
static char *noise_level[] = { "UNKNOWN", "SILENT", "QUIET", "NORMAL", "NOISY" };
46
47
#define HF_NORECURSE 0x0001
48
#define HF_DEBUG 0x0010
49
50
51
/*
52
* NumericList: a special list type to dynamically handle numeric hook
53
* requests
54
*/
55
typedef struct numericlist_stru
56
{
57
struct numericlist_stru *next;
58
int numeric;
59
char name[4];
60
Hook *list;
61
char *filename;
62
} NumericList;
63
64
NumericList *numeric_list = NULL;
65
66
#ifdef WANT_DLL
67
NumericList *dll_numeric_list = NULL;
68
#endif
69
70
/* hook_functions: the list of all hook functions available */
71
#define HOOK_COUNT (sizeof hook_functions / sizeof *hook_functions)
72
HookFunc hook_functions[] =
73
{
74
{ "ACTION", NULL, 3, 0, 0 },
75
{ "BANS", NULL, 4, 0, 0 },
76
{ "BANS_FOOTER", NULL, 2, 0, 0 },
77
{ "BANS_HEADER", NULL, 4, 0, 0 },
78
79
{ "CDCC_NOTE", NULL, 3, 0, 0 },
80
{ "CDCC_PACK", NULL, 7, 0, 0 },
81
{ "CDCC_POSTPACK", NULL, 8, 0, 0 },
82
{ "CDCC_PREPACK", NULL, 14, 0, 0 },
83
{ "CDCC_QUEUE", NULL, 5, 0, 0 },
84
{ "CDCC_QUEUEH", NULL, 3, 0, 0 },
85
{ "CDCC_SEND_NICK", NULL, 3, 0, 0 },
86
{ "CDCC_STATS", NULL, 1, 0, 0 },
87
88
{ "CHANOP", NULL, 1, 0, 0 },
89
{ "CHANNEL_NICK", NULL, 3, 0, 0 },
90
{ "CHANNEL_SIGNOFF", NULL, 3, 0, 0 },
91
{ "CHANNEL_STATS", NULL, 32, 0, 0 },
92
{ "CHANNEL_SWITCH", NULL, 1, 0, 0 },
93
{ "CHANNEL_SYNCH", NULL, 2, 0, 0 },
94
{ "CLONE", NULL, 2, 0, 0 },
95
{ "CONNECT", NULL, 1, 0, 0 },
96
{ "CTCP", NULL, 4, 0, 0 },
97
{ "CTCP_REPLY", NULL, 3, 0, 0 },
98
{ "DCC_CHAT", NULL, 2, 0, 0 },
99
{ "DCC_CONNECT", NULL, 2, 0, 0 },
100
{ "DCC_ERROR", NULL, 6, 0, 0 },
101
{ "DCC_HEADER", NULL, 7, 0, 0 },
102
{ "DCC_LOST", NULL, 2, 0, 0 },
103
{ "DCC_OFFER", NULL, 1, 0, 0 },
104
{ "DCC_POST", NULL, 7, 0, 0 },
105
{ "DCC_RAW", NULL, 3, 0, 0 },
106
{ "DCC_REQUEST", NULL, 4, 0, 0 },
107
{ "DCC_STAT", NULL, 7, 0, 0 },
108
{ "DCC_STATF", NULL, 7, 0, 0 },
109
{ "DCC_STATF1", NULL, 5, 0, 0 },
110
{ "DCC_TRANSFER_STAT", NULL, 13, 0, 0 },
111
{ "DCC_UPDATE", NULL, 1, 0, 0 },
112
{ "DEBUG", NULL, 1, 0, 0 },
113
{ "DESYNC_MESSAGE", NULL, 2, 0, 0 },
114
{ "DISCONNECT", NULL, 1, 0, 0 },
115
{ "EBANS", NULL, 4, 0, 0 },
116
{ "EBANS_FOOTER", NULL, 2, 0, 0 },
117
{ "EBANS_HEADER", NULL, 4, 0, 0 },
118
{ "ENCRYPTED_NOTICE", NULL, 3, 0, 0 },
119
{ "ENCRYPTED_PRIVMSG", NULL, 3, 0, 0 },
120
{ "EXEC", NULL, 2, 0, 0 },
121
{ "EXEC_ERRORS", NULL, 2, 0, 0 },
122
{ "EXEC_EXIT", NULL, 2, 0, 0 },
123
{ "EXEC_PROMPT", NULL, 2, 0, 0 },
124
{ "EXIT", NULL, 1, 0, 0 },
125
{ "FLOOD", NULL, 4, 0, 0 },
126
{ "FTP", NULL, 1, 0, 0 },
127
{ "HELP", NULL, 2, 0, 0 },
128
{ "HELPSUBJECT", NULL, 2, 0, 0 },
129
{ "HELPTOPIC", NULL, 1, 0, 0 },
130
{ "HOOK", NULL, 1, 0, 0 },
131
{ "IDLE", NULL, 1, 0, 0 },
132
{ "INPUT", NULL, 1, 0, 0 },
133
{ "INVITE", NULL, 2, 0, 0 },
134
{ "JOIN", NULL, 3, 0, 0 },
135
{ "JOIN_ME", NULL, 1, 0, 0 },
136
{ "KICK", NULL, 3, 0, 0 },
137
{ "LEAVE", NULL, 2, 0, 0 },
138
{ "LEAVE_ME", NULL, 1, 0, 0 },
139
{ "LIST", NULL, 3, 0, 0 },
140
{ "LLOOK_ADDED", NULL, 2, 0, 0 },
141
{ "LLOOK_JOIN", NULL, 2, 0, 0 },
142
{ "LLOOK_SPLIT", NULL, 2, 0, 0 },
143
{ "MAIL", NULL, 2, 0, 0 },
144
{ "MODE", NULL, 3, 0, 0 },
145
{ "MODE_STRIPPED", NULL, 3, 0, 0 },
146
{ "MODULE", NULL, 1, 0, 0 },
147
{ "MSG", NULL, 2, 0, 0 },
148
{ "MSG_GROUP", NULL, 3, 0, 0 },
149
{ "MSGLOG", NULL, 4, 0, 0 },
150
{ "NAMES", NULL, 2, 0, 0 },
151
{ "NETSPLIT", NULL, 1, 0, 0 },
152
{ "NICK_COMP", NULL, 1, 0, 0 },
153
{ "NICKNAME", NULL, 2, 0, 0 },
154
{ "NOTE", NULL, 3, 0, 0 },
155
{ "NOTICE", NULL, 2, 0, 0 },
156
{ "NOTIFY", NULL, 2, 0, 0 },
157
{ "NOTIFY_HEADER", NULL, 2, 0, 0 },
158
{ "NOTIFY_SIGNOFF", NULL, 1, 0, 0 },
159
{ "NOTIFY_SIGNON", NULL, 1, 0, 0 },
160
{ "NSLOOKUP", NULL, 3, 0, 0 },
161
{ "ODD_SERVER_STUFF", NULL, 3, 0, 0 },
162
{ "PASTE", NULL, 2, 0, 0 },
163
{ "PUBLIC", NULL, 3, 0, 0 },
164
{ "PUBLIC_AR", NULL, 3, 0, 0 },
165
{ "PUBLIC_MSG", NULL, 3, 0, 0 },
166
{ "PUBLIC_NOTICE", NULL, 3, 0, 0 },
167
{ "PUBLIC_OTHER", NULL, 3, 0, 0 },
168
{ "PUBLIC_OTHER_AR", NULL, 3, 0, 0 },
169
170
{ "RAW_IRC", NULL, 1, 0, 0 },
171
{ "REDIRECT", NULL, 2, 0, 0 },
172
{ "REPLY_AR", NULL, 1, 0, 0 },
173
{ "SAVEFILE", NULL, 2, 0, 0 },
174
{ "SAVEFILEPOST", NULL, 2, 0, 0 },
175
{ "SAVEFILEPRE", NULL, 2, 0, 0 },
176
{ "SEND_ACTION", NULL, 2, 0, HF_NORECURSE },
177
{ "SEND_CTCP", NULL, 3, 0, HF_NORECURSE },
178
{ "SEND_DCC_CHAT", NULL, 2, 0, HF_NORECURSE },
179
{ "SEND_MSG", NULL, 2, 0, HF_NORECURSE },
180
{ "SEND_NOTICE", NULL, 2, 0, HF_NORECURSE },
181
{ "SEND_PUBLIC", NULL, 2, 0, HF_NORECURSE },
182
{ "SEND_TO_SERVER", NULL, 3, 0, 0 },
183
{ "SERVER_NOTICE_FAKES",NULL, 3, 0, 0 },
184
{ "SERVER_NOTICE_FAKES_MYCHANNEL",NULL,3,0, 0 },
185
{ "SERVER_NOTICE_FOREIGN_KILL", NULL, 4, 0, 0 },
186
{ "SERVER_NOTICE_KILL", NULL, 4, 0, 0 },
187
{ "SERVER_NOTICE", NULL, 1, 0, 0 },
188
{ "SERVER_NOTICE_LOCAL_KILL",NULL,4, 0, 0 },
189
{ "SERVER_NOTICE_SERVER_KILL",NULL, 4, 0, 0 },
190
{ "SET", NULL, 2, 0, 0 },
191
{ "SHITLIST", NULL, 6, 0, 0 },
192
{ "SHITLIST_FOOTER", NULL, 1, 0, 0 },
193
{ "SHITLIST_HEADER", NULL, 6, 0, 0 },
194
{ "SHOWIDLE_FOOTER", NULL, 1, 0, 0 },
195
{ "SHOWIDLE_HEADER", NULL, 2, 0, 0 },
196
{ "SHOWIDLE", NULL, 4, 0, 0 },
197
{ "SIGNOFF", NULL, 1, 0, 0 },
198
{ "SILENCE", NULL, 2, 0, 0 },
199
{ "SOCKET", NULL, 3, 0, 0 },
200
{ "SOCKET_NOTIFY", NULL, 3, 0, 0 },
201
{ "STAT", NULL, 5, 0, 0 },
202
{ "STAT_FOOTER", NULL, 1, 0, 0 },
203
{ "STAT_HEADER", NULL, 5, 0, 0 },
204
{ "STATUS_UPDATE", NULL, 2, 0, 0 },
205
{ "SWITCH_CHANNELS", NULL, 3, 0, 0 },
206
{ "TIMER", NULL, 1, 0, 0 },
207
{ "TIMER_HOUR", NULL, 1, 0, 0 },
208
{ "TOPIC", NULL, 2, 0, 0 },
209
{ "URLGRAB", NULL, 1, 0, 0 },
210
{ "USAGE", NULL, 2, 0, 0 },
211
{ "USERLIST", NULL, 4, 0, 0 },
212
{ "USERLIST_FOOTER", NULL, 1, 0, 0 },
213
{ "USERLIST_HEADER", NULL, 5, 0, 0 },
214
{ "USERS", NULL, 5, 0, 0 },
215
{ "USERS_FOOTER", NULL, 1, 0, 0 },
216
{ "USERS_HEADER", NULL, 5, 0, 0 },
217
{ "USERS_IP", NULL, 3, 0, 0 },
218
{ "USERS_SERVER", NULL, 2, 0, 0 },
219
{ "USERS_SERVER_HEADER",NULL, 2, 0, 0 },
220
{ "WALL", NULL, 2, 0, 0 },
221
{ "WALLOP", NULL, 3, 0, 0 },
222
{ "WATCH", NULL, 3, 0, 0 },
223
{ "WHO", NULL, 6, 0, 0 },
224
{ "WHOLEFT", NULL, 6, 0, 0 },
225
{ "WHOLEFT_FOOTER", NULL, 1, 0, 0 },
226
{ "WHOLEFT_HEADER", NULL, 6, 0, 0 },
227
{ "WIDELIST", NULL, 1, 0, 0 },
228
{ "WINDOW", NULL, 2, 0, HF_NORECURSE },
229
{ "WINDOW_CREATE", NULL, 1, 0, 0 },
230
{ "WINDOW_FOCUS", NULL, 4, 0, 0 },
231
{ "WINDOW_KILL", NULL, 1, 0, 0 },
232
{ "WINDOW_SWAP", NULL, 1, 0, 0 },
233
{ "YELL", NULL, 1, 0, 0 }
234
};
235
236
void hook_add_to_list (Hook **list, Hook *item);
237
static Hook * hook_remove_from_list (Hook **list, char *item, int sernum);
238
static void add_numeric_list (NumericList *item);
239
static NumericList *find_numeric_list (int numeric);
240
static NumericList *remove_numeric_list (int numeric);
241
242
char *current_package(void) { return empty_string; }
243
244
/*
245
* name of the current hook that's running. a hook within a hook, might
246
* screw this up though.
247
*/
248
char hook_name[BIG_BUFFER_SIZE+1] = {0};
249
extern int last_function_call_level;
250
251
252
/*
253
* This converts a user-specified string of unknown composition and
254
* returns a string that contains at minimum "params" number of words
255
* in it. For any words that are forcibly added on, the last word will
256
* be a * (so it can match any number of words), and any previous words
257
* will be a % (so it forces the correct number of words to be caught.)
258
*/
259
static char * fill_it_out (char *str, int params)
260
{
261
char buffer[BIG_BUFFER_SIZE + 1];
262
char *arg,
263
*ptr;
264
int i = 0;
265
266
ptr = LOCAL_COPY(str);
267
*buffer = 0;
268
269
while ((arg = next_arg(ptr, &ptr)) != NULL)
270
{
271
if (*buffer)
272
strmcat(buffer, space, BIG_BUFFER_SIZE);
273
strmcat(buffer, arg, BIG_BUFFER_SIZE);
274
if (++i == params)
275
break;
276
}
277
278
for (; i < params; i++)
279
strmcat(buffer, (i < params-1) ? " %" : " *", BIG_BUFFER_SIZE);
280
281
if (*ptr)
282
{
283
strmcat(buffer, space, BIG_BUFFER_SIZE);
284
strmcat(buffer, ptr, BIG_BUFFER_SIZE);
285
}
286
return m_strdup(buffer);
287
}
288
289
290
#define INVALID_HOOKNUM -1001
291
292
/*
293
* find_hook: returns the numerical value for a specified hook name
294
*/
295
static int find_hook (char *name, int *first)
296
{
297
int which = INVALID_HOOKNUM, i, len, cnt;
298
299
if (first)
300
*first = -1;
301
302
if (!name || !(len = strlen(name)))
303
{
304
say("You must specify an event type!");
305
return INVALID_HOOKNUM;
306
}
307
308
upper(name);
309
310
for (cnt = 0, i = 0; i < NUMBER_OF_LISTS; i++)
311
{
312
if (!strncmp(name, hook_functions[i].name, len))
313
{
314
if (first && *first == -1)
315
*first = i;
316
317
if (strlen(hook_functions[i].name) == len)
318
{
319
cnt = 1;
320
which = i;
321
break;
322
}
323
else
324
{
325
cnt++;
326
which = i;
327
}
328
}
329
else if (cnt)
330
break;
331
}
332
333
if (cnt == 0)
334
{
335
if (is_number(name))
336
{
337
which = atol(name);
338
339
if ((which < 0) || (which > 999))
340
{
341
say("Numerics must be between 001 and 999");
342
return INVALID_HOOKNUM;
343
}
344
which = -which;
345
}
346
else
347
{
348
say("No such ON function: %s", name);
349
return INVALID_HOOKNUM;
350
}
351
}
352
else if (cnt > 1)
353
{
354
say("Ambiguous ON function: %s", name);
355
return INVALID_HOOKNUM;
356
}
357
358
return which;
359
}
360
361
362
363
364
/* * * * * ADDING A HOOK * * * * * */
365
/*
366
* This adds a numeric hook to the numeric hook list. The composition of that
367
* list is a linked list of "numeric holders" which simply indicate the
368
* numeric of that list, and a pointer to the actual list itself. The actual
369
* list itself is just a linked list of events sorted by serial number, then
370
* by "nick".
371
*/
372
static void add_numeric_hook (int numeric, char *nick, char *stuff, Noise noisy, int not, int sernum, int flexible)
373
{
374
NumericList *entry;
375
Hook *new;
376
377
if (!(entry = find_numeric_list(numeric)))
378
{
379
entry = (NumericList *) new_malloc(sizeof(NumericList));
380
entry->numeric = numeric;
381
sprintf(entry->name, "%3.3u", numeric);
382
entry->next = NULL;
383
entry->list = NULL;
384
add_numeric_list(entry);
385
}
386
387
if (!(new = hook_remove_from_list(&entry->list, nick, sernum)))
388
{
389
new = (Hook *)new_malloc(sizeof(Hook));
390
new->nick = NULL;
391
new->stuff = NULL;
392
}
393
394
malloc_strcpy(&new->nick, nick);
395
malloc_strcpy(&new->stuff, stuff);
396
new->noisy = noisy;
397
new->not = not;
398
new->sernum = sernum;
399
new->flexible = flexible;
400
new->global = loading_global;
401
malloc_strcpy(&new->filename, current_package());
402
new->next = NULL;
403
404
upper(new->nick);
405
hook_add_to_list(&entry->list, new);
406
}
407
408
#ifdef WANT_DLL
409
static void add_numeric_dll_hook (int numeric, Noise noise, int serial, char *nick, char *package, int (*func)(int, char *, char **))
410
{
411
NumericList *entry;
412
Hook *new;
413
414
if (!(entry = find_numeric_list(numeric)))
415
{
416
entry = (NumericList *) new_malloc(sizeof(NumericList));
417
entry->numeric = numeric;
418
sprintf(entry->name, "%3.3u", numeric);
419
entry->next = NULL;
420
entry->list = NULL;
421
add_numeric_list(entry);
422
}
423
new = (Hook *)new_malloc(sizeof(Hook));
424
malloc_strcpy(&new->nick, nick);
425
malloc_strcpy(&new->filename, package);
426
new->num_func = func;
427
new->noisy = noise;
428
new->sernum = serial;
429
upper(new->nick);
430
hook_add_to_list(&entry->list, new);
431
}
432
433
void add_dll_hook(int which, Noise noise, char *nick, char *package, int (*func1)(int, char *, char **), int (*func2)(char *, char *, char **))
434
{
435
Hook *new;
436
static int serial = 0;
437
serial++;
438
nick = fill_it_out(nick, which < 0 ? 1 : hook_functions[which].params);
439
if (which < 0)
440
{
441
add_numeric_dll_hook(which, noise, serial, nick, package, func1);
442
return;
443
}
444
new = (Hook *)new_malloc(sizeof(Hook));
445
malloc_strcpy(&new->nick, nick);
446
malloc_strcpy(&new->filename, package);
447
new->num_func = func1;
448
new->hook_func = func2;
449
new->noisy = noise;
450
new->sernum = serial;
451
upper(new->nick);
452
hook_add_to_list(&hook_functions[which].list, new);
453
}
454
#endif
455
456
/*
457
* add_hook: Given an index into the hook_functions array, this adds a new
458
* entry to the list as specified by the rest of the parameters. The new
459
* entry is added in alphabetical order (by nick).
460
*/
461
static void add_hook (int which, char *nick, char *stuff, Noise noisy, int not, int sernum, int flexible)
462
{
463
Hook *new;
464
465
if (which < 0)
466
{
467
add_numeric_hook(-which, nick, stuff, noisy,
468
not, sernum, flexible);
469
return;
470
}
471
472
if (!(new = hook_remove_from_list(&hook_functions[which].list, nick, sernum)))
473
{
474
new = (Hook *)new_malloc(sizeof(Hook));
475
new->nick = NULL;
476
new->stuff = NULL;
477
}
478
479
malloc_strcpy(&new->nick, nick);
480
malloc_strcpy(&new->stuff, stuff);
481
new->noisy = noisy;
482
new->not = not;
483
new->sernum = sernum;
484
new->flexible = flexible;
485
new->global = loading_global;
486
malloc_strcpy(&new->filename, current_package());
487
new->next = NULL;
488
489
upper(new->nick);
490
new->debug = (hook_functions[which].flags & HF_DEBUG) ? HF_DEBUG : 0;
491
hook_add_to_list(&hook_functions[which].list, new);
492
}
493
494
495
496
497
/* * * * * * REMOVING A HOOK * * * * * * * */
498
static void remove_numeric_hook (int numeric, char *nick, int sernum, int quiet)
499
{
500
NumericList *hook;
501
Hook *tmp,
502
*next;
503
504
if ((hook = find_numeric_list(numeric)))
505
{
506
if (nick)
507
{
508
if ((tmp = hook_remove_from_list(&hook->list, nick, sernum)))
509
{
510
if (!quiet)
511
{
512
say("%c%s%c removed from %d list",
513
(tmp->flexible?'\'':'"'), nick,
514
(tmp->flexible?'\'':'"'), numeric);
515
}
516
new_free(&(tmp->nick));
517
new_free(&tmp->filename);
518
new_free(&(tmp->stuff));
519
new_free((char **)&tmp);
520
521
if (!hook->list)
522
{
523
if ((hook = remove_numeric_list(numeric)))
524
new_free((char **)&hook);
525
}
526
return;
527
}
528
}
529
else
530
{
531
remove_numeric_list(numeric);
532
for (tmp = hook->list; tmp; tmp = next)
533
{
534
next = tmp->next;
535
tmp->not = 1;
536
new_free(&(tmp->nick));
537
new_free(&(tmp->stuff));
538
new_free(&tmp->filename);
539
new_free((char **)&tmp);
540
}
541
hook->list = NULL;
542
new_free((char **)&hook);
543
if (!quiet)
544
say("The %d list is empty", numeric);
545
return;
546
}
547
}
548
549
if (quiet)
550
return;
551
552
if (nick)
553
say("\"%s\" is not on the %d list", nick, numeric);
554
else
555
say("The %d list is empty", numeric);
556
}
557
558
559
static void remove_hook (int which, char *nick, int sernum, int quiet)
560
{
561
Hook *tmp,
562
*next;
563
564
if (which < 0)
565
{
566
remove_numeric_hook(-which, nick, sernum, quiet);
567
return;
568
}
569
if (nick)
570
{
571
if ((tmp = hook_remove_from_list(&hook_functions[which].list, nick, sernum)))
572
{
573
if (!quiet)
574
say("%c%s%c removed from %s list",
575
(tmp->flexible?'\'':'"'), nick,
576
(tmp->flexible?'\'':'"'),
577
hook_functions[which].name);
578
579
new_free(&(tmp->nick));
580
new_free(&(tmp->stuff));
581
new_free(&tmp->filename);
582
new_free((char **)&tmp); /* XXX why? */
583
}
584
else if (!quiet)
585
say("\"%s\" is not on the %s list", nick,
586
hook_functions[which].name);
587
}
588
else
589
{
590
Hook *prev = NULL;
591
Hook *top = NULL;
592
593
for (tmp = hook_functions[which].list; tmp; prev=tmp, tmp=next)
594
{
595
next = tmp->next;
596
597
/*
598
* If given a non-zero sernum, then we clean out
599
* only those hooks that are at that level.
600
*/
601
if (sernum && tmp->sernum != sernum)
602
{
603
if (!top)
604
top = tmp;
605
continue;
606
}
607
608
if (prev)
609
prev->next = tmp->next;
610
tmp->not = 1;
611
new_free(&(tmp->nick));
612
new_free(&(tmp->stuff));
613
new_free(&tmp->filename);
614
new_free((char **)&tmp);
615
}
616
hook_functions[which].list = top;
617
if (!quiet)
618
{
619
if (sernum)
620
say("The %s <%d> list is empty", hook_functions[which].name, sernum);
621
else
622
say("The %s list is empty", hook_functions[which].name);
623
}
624
}
625
}
626
627
/* Used to bulk-erase all of the currently scheduled ONs */
628
void flush_on_hooks (void)
629
{
630
int x;
631
int old_display = window_display;
632
633
window_display = 0;
634
for (x = 1; x < 999; x++)
635
remove_numeric_hook(x, NULL, x, 1);
636
for (x = 0; x < NUMBER_OF_LISTS; x++)
637
remove_hook(x, NULL, 0, 1);
638
window_display = old_display;
639
}
640
641
void unload_on_hooks (char *filename)
642
{
643
int x;
644
NumericList *tmp;
645
Hook *list, *next;
646
647
int old_display = window_display;
648
window_display = 0;
649
650
for (x = 1; x < 999; x++)
651
{
652
if ((tmp = find_numeric_list(x)))
653
{
654
for (list = tmp->list; list; list = next)
655
{
656
next = list->next;
657
if (!strcmp(list->filename, filename))
658
remove_numeric_hook(x, list->nick, list->sernum, 1);
659
}
660
}
661
}
662
663
for (x = 0; x < NUMBER_OF_LISTS; x++)
664
{
665
for (list = hook_functions[x].list; list; list = next)
666
{
667
next = list->next;
668
if (!strcmp(list->filename, filename))
669
remove_hook(x, list->nick, list->sernum, 1);
670
}
671
}
672
673
window_display = old_display;
674
}
675
676
void debug_hook(char *name, int x)
677
{
678
int cnt = 0, i;
679
680
for (cnt = 0, i = 0; i < NUMBER_OF_LISTS; i++)
681
{
682
if (!strcmp(name, hook_functions[i].name))
683
{
684
Hook *tmp;
685
if (x)
686
hook_functions[i].flags |= HF_DEBUG;
687
else
688
hook_functions[i].flags &= ~(HF_DEBUG);
689
for (tmp = hook_functions[i].list; tmp; tmp = tmp->next)
690
{
691
if (x)
692
tmp->debug |= HF_DEBUG;
693
else
694
tmp->debug &= ~(HF_DEBUG);
695
cnt++;
696
}
697
break;
698
}
699
}
700
701
if (cnt == 0)
702
{
703
int which;
704
if (is_number(name))
705
{
706
NumericList *tmp;
707
which = atol(name);
708
709
if ((which < 0) || (which > 999))
710
return;
711
712
if ((tmp = find_numeric_list(which)))
713
{
714
Hook *list;
715
for (list = tmp->list; list; list = list->next, cnt++)
716
{
717
if (x)
718
list->debug |= HF_DEBUG;
719
else
720
list->debug &= ~(HF_DEBUG);
721
cnt++;
722
}
723
}
724
}
725
}
726
}
727
728
729
/* * * * * * SHOWING A HOOK * * * * * * */
730
/* show_hook shows a single hook */
731
static void show_hook (Hook *list, char *name)
732
{
733
char *hooks = fget_string_var(FORMAT_HOOK_FSET);
734
if (hooks)
735
put_it("%s",
736
convert_output_format(hooks,
737
"%s %s %c %s %c %s %s %d",
738
list->filename[0] ? list->filename : "*",
739
name,
740
(list->flexible?'\'':'"'), list->nick,
741
(list->flexible?'\'':'"'),
742
(list->not ? "nothing" : list->stuff ? list->stuff:"DLL"),
743
noise_level[list->noisy],
744
list->sernum));
745
else
746
say("[%s] On %s from %c%s%c do %s [%s] <%d>",
747
list->filename[0] ? list->filename : "*",
748
name,
749
(list->flexible?'\'':'"'), list->nick,
750
(list->flexible?'\'':'"'),
751
(list->not ? "nothing" : list->stuff ? list->stuff:"DLL"),
752
noise_level[list->noisy],
753
list->sernum);
754
}
755
756
/*
757
* show_numeric_list: If numeric is 0, then all numeric lists are displayed.
758
* If numeric is non-zero, then that particular list is displayed. The total
759
* number of entries displayed is returned
760
*/
761
static int show_numeric_list (int numeric)
762
{
763
NumericList *tmp;
764
Hook *list;
765
char buf[4];
766
int cnt = 0;
767
768
if (numeric)
769
{
770
sprintf(buf, "%3.3u", numeric);
771
if ((tmp = find_numeric_list(numeric)))
772
{
773
for (list = tmp->list; list; list = list->next, cnt++)
774
show_hook(list, tmp->name);
775
}
776
}
777
else
778
{
779
for (tmp = numeric_list; tmp; tmp = tmp->next)
780
{
781
for (list = tmp->list; list; list = list->next, cnt++)
782
show_hook(list, tmp->name);
783
}
784
}
785
return (cnt);
786
}
787
788
/*
789
* show_list: Displays the contents of the list specified by the index into
790
* the hook_functions array. This function returns the number of entries in
791
* the list displayed
792
*/
793
static int show_list (int which)
794
{
795
Hook *list;
796
int cnt = 0;
797
798
/* Less garbage when issueing /on without args. (lynx) */
799
for (list = hook_functions[which].list; list; list = list->next, cnt++)
800
show_hook(list, hook_functions[which].name);
801
return (cnt);
802
}
803
804
805
806
/* * * * * * * * EXECUTING A HOOK * * * * * * */
807
#define NO_ACTION_TAKEN -1
808
#define SUPPRESS_DEFAULT 0
809
#define DONT_SUPPRESS_DEFAULT 1
810
#define RESULT_PENDING 2
811
#define RESULT_NEXT 3
812
813
/*
814
* do_hook: This is what gets called whenever a MSG, INVITES, WALL, (you get
815
* the idea) occurs. The nick is looked up in the appropriate list. If a
816
* match is found, the stuff field from that entry in the list is treated as
817
* if it were a command. First it gets expanded as though it were an alias
818
* (with the args parameter used as the arguments to the alias). After it
819
* gets expanded, it gets parsed as a command. This will return as its value
820
* the value of the noisy field of the found entry, or -1 if not found.
821
*/
822
823
int BX_do_hook (int which, char *format, ...)
824
{
825
Hook *tmp = NULL,
826
*next = NULL,
827
**list;
828
char buffer [BIG_BUFFER_SIZE * 10 + 1],
829
*name = NULL;
830
int retval = DONT_SUPPRESS_DEFAULT;
831
unsigned display = window_display;
832
int i;
833
Hook *hook_array [2048] = { 0 };
834
int hook_num = 0;
835
char *result = NULL;
836
int old_debug_count = debug_count;
837
838
#ifdef WANT_TCL
839
int tcl_ret = 0;
840
#endif
841
/*
842
* Figure out where the hooks are for the event type were asserting
843
*/
844
/* Numeric list */
845
if (which < 0)
846
{
847
NumericList *hook;
848
849
if ((hook = find_numeric_list(-which)))
850
{
851
name = hook->name;
852
list = &hook->list;
853
}
854
else
855
list = NULL;
856
}
857
858
/* Named list */
859
else if (which < HOOK_COUNT)
860
{
861
/*
862
* If we're already executing the type, and we're
863
* specifically not supposed to allow recursion, then
864
* dont allow recursion. ;-)
865
*/
866
if (hook_functions[which].mark &&
867
(hook_functions[which].flags & HF_NORECURSE))
868
list = NULL;
869
else
870
{
871
list = &(hook_functions[which].list);
872
name = hook_functions[which].name;
873
strncpy(hook_name, hook_functions[which].name, BIG_BUFFER_SIZE);
874
}
875
}
876
else /* invalid hook */
877
{
878
list = NULL;
879
}
880
881
/*
882
* Press the buffer using the specified format string and args
883
* We do this here so that we dont waste time doing the vsnprintf
884
* if we're not going to do any matching. So for types where the
885
* user has no hooks, its a cheapie call.
886
*/
887
if (format)
888
{
889
va_list args;
890
va_start (args, format);
891
vsnprintf(buffer, BIG_BUFFER_SIZE * 5, format, args);
892
va_end(args);
893
}
894
else
895
ircpanic("do_hook: format is NULL");
896
897
#ifdef WANT_TCL
898
if (tcl_interp)
899
tcl_ret = check_on_hook(which, format?buffer:NULL);
900
#endif
901
902
/*
903
* No hooks to look at? No problem. Drop out.
904
*/
905
if (!list)
906
{
907
*hook_name = 0;
908
return NO_ACTION_TAKEN;
909
}
910
911
/*
912
* Mark the event as being executed. This is used to suppress
913
* unwanted recursion in some /on's.
914
*/
915
if (which >= 0)
916
hook_functions[which].mark++;
917
918
919
/* not attached, so dont "fix" it */
920
{
921
int currser = 0,
922
oldser = INT_MIN,
923
currmatch = 0,
924
oldmatch = 0;
925
Hook * bestmatch = NULL;
926
927
/*
928
* Walk the list of hooks for this event
929
*/
930
for (tmp = *list; tmp; tmp = tmp->next)
931
{
932
char * tmpnick = NULL;
933
int sa;
934
935
/*
936
* save the current serial number
937
*/
938
currser = tmp->sernum;
939
940
/*
941
* Is this a different serial number than the
942
* last hook? If it is, then we save the previous
943
* serial number's best hook to the hook_array.
944
*/
945
if (currser != oldser)
946
{
947
oldser = currser;
948
currmatch = oldmatch = 0;
949
if (bestmatch)
950
hook_array[hook_num++] = bestmatch;
951
bestmatch = NULL;
952
}
953
954
/*
955
* If this is a flexible hook, expand the nick stuff
956
*/
957
if (tmp->flexible)
958
tmpnick = expand_alias(tmp->nick, empty_string,
959
&sa, NULL);
960
else
961
tmpnick = tmp->nick;
962
963
964
/*
965
* Check to see if the pattern matches the text
966
*/
967
currmatch = wild_match(tmpnick, buffer);
968
969
/*
970
* If it is the "best match" so far, then we mark
971
* its "value" and save a pointer to it.
972
*/
973
if (currmatch > oldmatch)
974
{
975
oldmatch = currmatch;
976
bestmatch = tmp;
977
}
978
979
/*
980
* Clean up after flexible hooks
981
*/
982
if (tmp->flexible)
983
new_free(&tmpnick);
984
}
985
986
/*
987
* Ok. we've walked the list. If the last hook had a best
988
* match, use that one too. =)
989
*/
990
if (bestmatch)
991
hook_array[hook_num++] = bestmatch;
992
}
993
994
995
/*
996
* Now we walk the list of collected hook events that are to be run
997
*/
998
for (i = 0; i < hook_num; i++)
999
{
1000
const char * saved_who_from;
1001
unsigned long saved_who_level;
1002
char * name_copy;
1003
char * stuff_copy;
1004
int old_alias_debug = alias_debug;
1005
char *result1 = NULL;
1006
1007
/*
1008
* This should never happen.
1009
*/
1010
if (!(tmp = hook_array[i]))
1011
ircpanic("hook_array[%d] is null", i);
1012
1013
/*
1014
* Check to see if this hook is supposed to supress the
1015
* default action for the event.
1016
*/
1017
1018
hook_next:
1019
if (tmp->noisy == SILENT && tmp->sernum == 0)
1020
retval = SUPPRESS_DEFAULT;
1021
else if (tmp->noisy == UNKNOWN && tmp->sernum == 0)
1022
retval = RESULT_PENDING;
1023
/*
1024
* If this is a negated event, or there isnt anything to be
1025
* executed, then we dont bother. Just go on to the next one
1026
*/
1027
if (tmp->not || !tmp->stuff || !*tmp->stuff)
1028
{
1029
if (!tmp->stuff)
1030
{
1031
if (tmp->hook_func)
1032
(tmp->hook_func)(name, buffer, NULL);
1033
else if (tmp->num_func)
1034
(tmp->num_func)(which, buffer, NULL);
1035
}
1036
continue;
1037
}
1038
/*
1039
* If this is a NORMAL or NOISY hook, then we tell the user
1040
* that we're going to execute the hook.
1041
*/
1042
if (tmp->noisy > QUIET)
1043
say("%s activated by %c%s%c",
1044
name, tmp->flexible ? '\'' : '"',
1045
buffer, tmp->flexible ? '\'' : '"');
1046
1047
if ((tmp->debug & HF_DEBUG) && (internal_debug & DEBUG_HOOK) && !in_debug_yell)
1048
{
1049
debugyell("ON %s activated [%s]", name, buffer);
1050
alias_debug++;
1051
}
1052
/*
1053
* Save some information that may be reset in the
1054
* execution, turn off the display if the user specified.
1055
*/
1056
save_display_target(&saved_who_from, &saved_who_level);
1057
if (tmp->noisy < NOISY)
1058
window_display = 0;
1059
1060
name_copy = LOCAL_COPY(name);
1061
stuff_copy = LOCAL_COPY(tmp->stuff);
1062
1063
if (tmp->noisy == UNKNOWN)
1064
result = parse_line_with_return(name_copy, stuff_copy, buffer, 0, 0);
1065
else
1066
{
1067
/*
1068
* Ok. Go and run the code. It is imperitive to note
1069
* that "tmp" may be deleted by the code executed here,
1070
* so it is absolutely forbidden to reference "tmp" after
1071
* this point.
1072
*/
1073
next = tmp->next;
1074
will_catch_return_exceptions++;
1075
result1 = parse_line_with_return(name_copy, stuff_copy, buffer, 0, 0);
1076
will_catch_return_exceptions--;
1077
return_exception = 0;
1078
}
1079
if (retval == RESULT_PENDING)
1080
{
1081
if (result && atol(result))
1082
retval = SUPPRESS_DEFAULT;
1083
else
1084
retval = DONT_SUPPRESS_DEFAULT;
1085
}
1086
new_free(&result);
1087
/*
1088
* Clean up the stuff that may have been mangled by the
1089
* execution.
1090
*/
1091
restore_display_target(saved_who_from, saved_who_level);
1092
if (result1 && *result1 && !my_stricmp(result1, "next"))
1093
{
1094
new_free(&result1);
1095
{
1096
if ((tmp = next))
1097
goto hook_next;
1098
else
1099
retval = RESULT_NEXT;
1100
}
1101
}
1102
new_free(&result1);
1103
alias_debug = old_alias_debug;
1104
window_display = display;
1105
}
1106
1107
/*
1108
* Mark the event as not currently being done here.
1109
*/
1110
if (which >= 0)
1111
hook_functions[which].mark--;
1112
1113
if (oper_command && *buffer)
1114
memset(buffer, 0, strlen(buffer)-1);
1115
/*
1116
* And return the user-specified suppression level
1117
*/
1118
if (old_debug_count == 1)
1119
debug_count = 1;
1120
*hook_name = 0;
1121
return retval;
1122
}
1123
1124
/*
1125
* shook: the SHOOK command -- this probably doesnt belong here,
1126
* and shook is probably a stupid name. It simply asserts a fake
1127
* hook event for a given type. Fraught with peril!
1128
*/
1129
BUILT_IN_COMMAND(shookcmd)
1130
{
1131
int which;
1132
char *arg = next_arg(args, &args);
1133
1134
if ((which = find_hook(arg, NULL)) == INVALID_HOOKNUM)
1135
return;
1136
else
1137
do_hook(which, "%s", args);
1138
}
1139
1140
1141
/* * * * * * SCHEDULING AN EVENT * * * * * * * */
1142
/*
1143
* The ON command:
1144
* Format: /ON [#][+-^]TYPE ['] [SERNUM] NICK ['] [{] STUFF [}]
1145
*
1146
* The "ON" command mainly takes three arguments. The first argument
1147
* is the "type" of callback that you want to schedule. This is either
1148
* a three digit number, of it is one of the strings so enumerated at the
1149
* top of this file in hook_list. The second argument is the "nick" or
1150
* "pattern" that is to be used to match against future events. If the
1151
* "nick" matches the text that is later passed to do_hook() with the given
1152
* "type", then the commands in "stuff" will be executed.
1153
*
1154
* If "nick" is enclosed in single quotes ('), then it is a "flexible"
1155
* pattern, and will be expanded before it is matched against the text
1156
* in do_hook. Otherwise, the string so specified is "static", and is
1157
* used as-is in do_hook().
1158
*
1159
* Within each type, there are at least 65,535 different "serial numbers",
1160
* (there actually are MAX_INT of them, but by convention, only 16 bit
1161
* serial numbers are used, from -32,768 to 32,767) which may be used to
1162
* schedule any number of events at the given serial number.
1163
*
1164
* Each time an assertion occurs for a given "type", at most one of the
1165
* scheduled events is executed for each of the distinct serial numbers that
1166
* are in use for that event. The event to be executed is the one at a
1167
* given serial number that "best" matches the text passed to do_hook().
1168
* While in theory, up to MAX_INT events could be executed for a given single
1169
* assertion, in practice, a hard limit of 2048 events per assertion is
1170
* enforced.
1171
*
1172
* The runtime behavior of the event being scheduled can be modified by
1173
* specifying a character at the beginning of the "type" argument. If you
1174
* want to schedule an event at a serial number, then the first character
1175
* must be a hash (#). The argument immediately FOLLOWING the "type"
1176
* argument, and immediately PRECEEDING the "nick" argument must be an
1177
* integer number, and is used for the serial number for this event.
1178
*
1179
* The "verbosity" of the event may also be modified by specifying at most
1180
* one of the following characters:
1181
* A caret (^) is the SILENT level, and indicates that the event is to
1182
* be executed with no output (window_display is turned off),
1183
* and the "default action" (whatever that is) for the event is
1184
* to be suppressed. The default action is actually only
1185
* suppressed if the SILENT level is specified for serial number
1186
* zero. This is the most common level used for overriding the
1187
* output of most /on's.
1188
* A minus (-) is the QUIET level, and is the same as the SILENT level,
1189
* except that the default action (whatever that is) is not to
1190
* be suppressed.
1191
* No character is the "normal" case, and is the same as the "minus"
1192
* level, with the addition that the client will inform you that
1193
* the event was executed. This is useful for debugging.
1194
* A plus (+) is the same as the "normal" (no character specified),
1195
* except that the output is not suppressed (window_display is
1196
* not changed.)
1197
*/
1198
BUILT_IN_COMMAND(oncmd)
1199
{
1200
char *func,
1201
*nick,
1202
*serial;
1203
Noise noisy = NORMAL;
1204
int not = 0,
1205
sernum = 0,
1206
remove = 0,
1207
which = INVALID_HOOKNUM;
1208
int flex = 0;
1209
char type;
1210
int first;
1211
1212
/*
1213
* Get the type of event to be scheduled
1214
*/
1215
if ((func = next_arg(args, &args)) != NULL)
1216
{
1217
/*
1218
* Check to see if this has a serial number.
1219
*/
1220
if (*func == '#')
1221
{
1222
if (!(serial = next_arg(args, &args)))
1223
{
1224
say("No serial number specified");
1225
return;
1226
}
1227
sernum = atol(serial);
1228
func++;
1229
}
1230
1231
/*
1232
* Get the verbosity level, if any.
1233
*/
1234
switch (*func)
1235
{
1236
case '?':
1237
noisy = UNKNOWN;
1238
func++;
1239
break;
1240
case '-':
1241
noisy = QUIET;
1242
func++;
1243
break;
1244
case '^':
1245
noisy = SILENT;
1246
func++;
1247
break;
1248
case '+':
1249
noisy = NOISY;
1250
func++;
1251
break;
1252
default:
1253
noisy = NORMAL;
1254
break;
1255
}
1256
1257
1258
/*
1259
* Check to see if the event type is valid
1260
*/
1261
if ((which = find_hook(func, &first)) == INVALID_HOOKNUM)
1262
{
1263
/*
1264
* Ok. So either the user specified an invalid type
1265
* or they specified an ambiguous type. Either way,
1266
* we're not going to be going anywhere. So we have
1267
* free reign to mangle 'args' at this point.
1268
*/
1269
1270
int len;
1271
1272
/*
1273
* If first is -1, then it was an unknown type.
1274
* An error has already been output, just return here
1275
*/
1276
if (first == -1)
1277
return;
1278
1279
/*
1280
* Otherwise, its an ambiguous type. If they were
1281
* trying to register the hook, then theyve already
1282
* gotten the error message, just return;
1283
*/
1284
if (new_new_next_arg(args, &args, &type))
1285
return;
1286
1287
/*
1288
* Ok. So they probably want a listing.
1289
*/
1290
say("ON listings:");
1291
len = strlen(func);
1292
while (!my_strnicmp(func, hook_functions[first].name, len))
1293
{
1294
show_list(first);
1295
first++;
1296
if (!hook_functions[first].name)
1297
break;
1298
}
1299
1300
return;
1301
}
1302
1303
/*
1304
* Check to see if this is a removal event or if this
1305
* is a negated event.
1306
*/
1307
switch (*args)
1308
{
1309
case '-':
1310
remove = 1;
1311
args++;
1312
break;
1313
case '^':
1314
not = 1;
1315
args++;
1316
break;
1317
}
1318
1319
/*
1320
* Grab the "nick"
1321
*/
1322
if ((nick = new_new_next_arg(args, &args, &type)))
1323
{
1324
char *exp;
1325
1326
/*
1327
* Pad it to the appropriate number of args
1328
*/
1329
if (which < 0)
1330
nick = fill_it_out(nick, 1);
1331
else
1332
nick = fill_it_out(nick, hook_functions[which].params);
1333
1334
/*
1335
* If nick is empty, something is very wrong.
1336
*/
1337
if (!*nick)
1338
{
1339
say("No expression specified");
1340
new_free(&nick);
1341
return;
1342
}
1343
1344
/*
1345
* If we're doing a removal, do the deed.
1346
*/
1347
if (remove)
1348
{
1349
remove_hook(which, nick, sernum, 0);
1350
new_free(&nick);
1351
return;
1352
}
1353
1354
/*
1355
* Take a note if its flexible or not.
1356
*/
1357
if (type == '\'')
1358
flex = 1;
1359
else
1360
flex = 0;
1361
1362
1363
/*
1364
* If this is a negative event, then we dont want
1365
* to take any action for it.
1366
*/
1367
if (not)
1368
args = empty_string;
1369
1370
1371
/*
1372
* Slurp up any whitespace after the nick
1373
*/
1374
while (my_isspace(*args))
1375
args++;
1376
1377
/*
1378
* Then slurp up the body ("text")
1379
*/
1380
if (*args == '{') /* } */
1381
{
1382
if (!(exp = next_expr(&args, '{'))) /* } */
1383
{
1384
say("Unmatched brace in ON");
1385
new_free(&nick);
1386
return;
1387
}
1388
}
1389
else
1390
exp = args;
1391
1392
/*
1393
* Schedule the event
1394
*/
1395
add_hook(which, nick, exp, noisy, not, sernum, flex);
1396
1397
/*
1398
* Tell the user that we're done.
1399
*/
1400
if (which < 0)
1401
say("On %3.3u from %c%s%c do %s [%s] <%d>",
1402
-which, type, nick, type,
1403
(not ? "nothing" : exp),
1404
noise_level[noisy], sernum);
1405
else
1406
say("On %s from %c%s%c do %s [%s] <%d>",
1407
hook_functions[which].name,
1408
type, nick, type,
1409
(not ? "nothing" : exp),
1410
noise_level[noisy], sernum);
1411
1412
/*
1413
* Clean up after the nick
1414
*/
1415
new_free(&nick);
1416
}
1417
1418
/*
1419
* No "nick" argument was specified. That means the user
1420
* either is deleting all of the events of a type, or it
1421
* wants to list all the events of a type.
1422
*/
1423
else
1424
{
1425
/*
1426
* if its a removal, do the deed
1427
*/
1428
if (remove)
1429
{
1430
remove_hook(which, NULL, sernum, 0);
1431
return;
1432
}
1433
1434
/*
1435
* The help files say that an "/on 0" shows all
1436
* of the numeric ONs. Since the ACTION hook is
1437
* number 0, we have to check to see if the first
1438
* character of "func" is a zero or not. If it is,
1439
* we output all of the numeric functions.
1440
*/
1441
if (*func == '0')
1442
{
1443
if (!show_numeric_list(0))
1444
say("All numeric ON lists are empty.");
1445
}
1446
else if (which < 0)
1447
{
1448
if (!show_numeric_list(-which))
1449
say("The %3.3u list is empty.", -which);
1450
}
1451
else if (!show_list(which))
1452
say("The %s list is empty.",
1453
hook_functions[which].name);
1454
}
1455
}
1456
1457
/*
1458
* No "Type" argument was specified. That means the user wants to
1459
* list all of the ONs currently scheduled.
1460
*/
1461
else
1462
{
1463
int total = 0;
1464
1465
say("ON listings:");
1466
1467
/*
1468
* Show the named events
1469
*/
1470
for (which = 0; which < NUMBER_OF_LISTS; which++)
1471
total += show_list(which);
1472
1473
/*
1474
* Show the numeric events
1475
*/
1476
total += show_numeric_list(0);
1477
1478
if (!total)
1479
say("All ON lists are empty.");
1480
}
1481
}
1482
1483
1484
/* * * * * * * * * * SAVING A HOOK * * * * * * * * * * */
1485
static void write_hook (FILE *fp, Hook *hook, char *name)
1486
{
1487
char *stuff = NULL;
1488
char flexi = '"';
1489
1490
if (hook->flexible)
1491
flexi = '\'';
1492
1493
switch (hook->noisy)
1494
{
1495
case SILENT:
1496
stuff = "^";
1497
break;
1498
case QUIET:
1499
stuff = "-";
1500
break;
1501
case NORMAL:
1502
stuff = empty_string;
1503
break;
1504
case NOISY:
1505
stuff = "+";
1506
break;
1507
case UNKNOWN:
1508
stuff = "?";
1509
break;
1510
}
1511
1512
if (hook->sernum)
1513
fprintf(fp, "ON #%s%s %d", stuff, name, hook->sernum);
1514
else
1515
fprintf(fp, "ON %s%s", stuff, name);
1516
1517
fprintf(fp, " %c%s%c {%s}\n", flexi, hook->nick, flexi, hook->stuff);
1518
}
1519
1520
/*
1521
* save_hooks: for use by the SAVE command to write the hooks to a file so it
1522
* can be interpreted by the LOAD command
1523
*/
1524
void save_hooks (FILE *fp, int do_all)
1525
{
1526
Hook *list;
1527
NumericList *numeric;
1528
int which;
1529
1530
for (which = 0; which < NUMBER_OF_LISTS; which++)
1531
{
1532
for (list = hook_functions[which].list; list; list = list->next)
1533
if (!list->global || do_all)
1534
write_hook(fp,list, hook_functions[which].name);
1535
}
1536
for (numeric = numeric_list; numeric; numeric = numeric->next)
1537
{
1538
for (list = numeric->list; list; list = list->next)
1539
if (!list->global)
1540
write_hook(fp, list, numeric->name);
1541
}
1542
}
1543
1544
1545
1546
/* * * * * * * * * * STACKING A HOOK * * * * * * * * */
1547
typedef struct onstacklist
1548
{
1549
int which;
1550
Hook *list;
1551
struct onstacklist *next;
1552
} OnStack;
1553
1554
static OnStack * on_stack = NULL;
1555
1556
void do_stack_on (int type, char *args)
1557
{
1558
int which;
1559
Hook *list;
1560
NumericList *nhook = NULL, *nptr;
1561
1562
if (!on_stack && (type == STACK_POP || type == STACK_LIST))
1563
{
1564
say("ON stack is empty!");
1565
return;
1566
}
1567
if (!args || !*args)
1568
{
1569
say("Missing event type for STACK ON");
1570
return;
1571
}
1572
1573
if ((which = find_hook(args, NULL)) == INVALID_HOOKNUM)
1574
return; /* Error message already outputted */
1575
1576
if (which < 0)
1577
{
1578
if ((nhook = find_numeric_list(-which)))
1579
list = nhook->list;
1580
else
1581
list = NULL;
1582
}
1583
else
1584
list = hook_functions[which].list;
1585
1586
1587
if (type == STACK_PUSH)
1588
{
1589
OnStack *new;
1590
new = (OnStack *) new_malloc(sizeof(OnStack));
1591
new->which = which;
1592
new->list = list;
1593
new->next = on_stack;
1594
on_stack = new;
1595
1596
if (which < 0)
1597
{
1598
if (nhook && numeric_list)
1599
remove_numeric_list(-which);
1600
}
1601
else
1602
hook_functions[which].list = NULL;
1603
1604
return;
1605
}
1606
1607
else if (type == STACK_POP)
1608
{
1609
OnStack *p, *tmp = (OnStack *) 0;
1610
1611
for (p = on_stack; p; tmp = p, p = p->next)
1612
{
1613
if (p->which == which)
1614
{
1615
if (p == on_stack)
1616
on_stack = p->next;
1617
else
1618
tmp->next = p->next;
1619
break;
1620
}
1621
}
1622
if (!p)
1623
{
1624
say("No %s on the stack", args);
1625
return;
1626
}
1627
1628
if ((which < 0 && nhook) ||
1629
(which >= 0 && hook_functions[which].list))
1630
remove_hook(which, NULL, 0, 1); /* free hooks */
1631
1632
if (which < 0)
1633
{
1634
/* look -- do we have any hooks already for this numeric? */
1635
if (!(nptr = find_numeric_list(-which)))
1636
{
1637
if (p->list) /* not just a placeholder? */
1638
{
1639
/* No. make a new list and put the stack on it */
1640
nptr = (NumericList *) new_malloc(sizeof(NumericList));
1641
nptr->list = p->list;
1642
nptr->next = NULL;
1643
nptr->numeric = -which;
1644
sprintf(nptr->name, "%3.3u", -which);
1645
add_numeric_list(nptr);
1646
}
1647
}
1648
else
1649
{
1650
remove_hook(which, NULL, 0, 1);
1651
nptr->list = p->list;
1652
}
1653
}
1654
else
1655
hook_functions[which].list = p->list;
1656
1657
new_free((char **)&p);
1658
return;
1659
}
1660
1661
else if (type == STACK_LIST)
1662
{
1663
int slevel = 0;
1664
OnStack *osptr;
1665
1666
for (osptr = on_stack; osptr; osptr = osptr->next)
1667
{
1668
if (osptr->which == which)
1669
{
1670
Hook *hptr;
1671
1672
slevel++;
1673
say("Level %d stack", slevel);
1674
for (hptr = osptr->list; hptr; hptr = hptr->next)
1675
show_hook(hptr, args);
1676
}
1677
}
1678
1679
if (!slevel)
1680
say("The STACK ON %s list is empty", args);
1681
return;
1682
}
1683
say("Unknown STACK ON type ??");
1684
}
1685
1686
1687
1688
/* List manips especially for on's. */
1689
void hook_add_to_list (Hook **list, Hook *item)
1690
{
1691
Hook *tmp, *last = NULL;
1692
1693
for (tmp = *list; tmp; last = tmp, tmp = tmp->next)
1694
{
1695
if (tmp->sernum < item->sernum)
1696
continue;
1697
else if ((tmp->sernum == item->sernum) && my_stricmp(tmp->nick, item->nick) < 0)
1698
continue;
1699
else
1700
break;
1701
}
1702
1703
if (last)
1704
{
1705
item->next = last->next;
1706
last->next = item;
1707
}
1708
else
1709
{
1710
item->next = *list;
1711
*list = item;
1712
}
1713
}
1714
1715
1716
static Hook *hook_remove_from_list (Hook **list, char *item, int sernum)
1717
{
1718
Hook *tmp, *last = NULL;
1719
1720
for (tmp = *list; tmp; last = tmp, tmp = tmp->next)
1721
{
1722
if ((tmp->sernum == sernum) && !my_stricmp(tmp->nick, item))
1723
{
1724
if (last)
1725
last->next = tmp->next;
1726
else
1727
*list = tmp->next;
1728
return tmp;
1729
}
1730
}
1731
return NULL;
1732
}
1733
1734
1735
static void add_numeric_list (NumericList *item)
1736
{
1737
NumericList *tmp, *last = NULL;
1738
1739
for (tmp = numeric_list; tmp; last = tmp, tmp = tmp->next)
1740
{
1741
if (tmp->numeric > item->numeric)
1742
break;
1743
}
1744
1745
if (last)
1746
{
1747
last->next = item;
1748
item->next = tmp;
1749
}
1750
else
1751
{
1752
item->next = numeric_list;
1753
numeric_list = item;
1754
}
1755
}
1756
1757
static NumericList *find_numeric_list (int numeric)
1758
{
1759
NumericList *tmp, *last = NULL;
1760
1761
for (tmp = numeric_list; tmp; last = tmp, tmp = tmp->next)
1762
{
1763
if (tmp->numeric == numeric)
1764
return tmp;
1765
}
1766
1767
return NULL;
1768
}
1769
1770
static NumericList *remove_numeric_list (int numeric)
1771
{
1772
NumericList *tmp, *last = NULL;
1773
1774
for (tmp = numeric_list; tmp; last = tmp, tmp = tmp->next)
1775
{
1776
if (tmp->numeric == numeric)
1777
break;
1778
}
1779
1780
if (tmp)
1781
{
1782
if (last)
1783
last->next = tmp->next;
1784
else
1785
numeric_list = numeric_list->next;
1786
}
1787
return tmp;
1788
}
1789
1790
#ifdef WANT_DLL
1791
#if 0
1792
static NumericList *remove_numeric_dll_list(int numeric)
1793
{
1794
NumericList *tmp, *last = NULL;
1795
1796
for (tmp = numeric_list; tmp; last = tmp, tmp = tmp->next)
1797
{
1798
if (tmp->numeric == numeric)
1799
break;
1800
}
1801
1802
if (last)
1803
last->next = tmp->next;
1804
else
1805
numeric_list = numeric_list->next;
1806
1807
return tmp;
1808
}
1809
1810
static Hook *remove_dll_hook_list(Hook **entry)
1811
{
1812
Hook *tmp, *last = NULL;
1813
1814
for (tmp = *list; tmp; last = tmp, tmp = tmp->next)
1815
{
1816
if (last)
1817
last->next = tmp->next;
1818
else
1819
*list = tmp->next;
1820
return tmp;
1821
}
1822
return NULL;
1823
}
1824
#endif
1825
1826
int remove_dll_hook(char *package)
1827
{
1828
NumericList *tmp;
1829
Hook *list, *next = NULL;
1830
int x, ret = 0;
1831
for (x = 1; x < 999; x++)
1832
{
1833
if ((tmp = find_numeric_list(x)))
1834
{
1835
for (list = tmp->list; list; list = next)
1836
{
1837
next = list->next;
1838
if (!my_stricmp(list->filename, package))
1839
{
1840
remove_numeric_hook(x, list->nick, list->sernum, 1);
1841
ret++;
1842
}
1843
}
1844
}
1845
}
1846
1847
for (x = 0; x < NUMBER_OF_LISTS; x++)
1848
{
1849
for (list = hook_functions[x].list; list; list = next)
1850
{
1851
next = list->next;
1852
if (!my_stricmp(list->filename, package))
1853
{
1854
remove_hook(x, list->nick, list->sernum, 1);
1855
ret++;
1856
}
1857
}
1858
}
1859
return ret;
1860
}
1861
1862
#endif
1863
1864