/[cvs]/eggdrop1.9/src/tclhash.c
ViewVC logotype

Annotation of /eggdrop1.9/src/tclhash.c

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.75 - (hide annotations) (download) (as text)
Thu Oct 10 04:41:59 2002 UTC (17 years, 1 month ago) by stdarg
Branch: MAIN
CVS Tags: HEAD
Changes since 1.74: +1 -1 lines
File MIME type: text/x-chdr
FILE REMOVED
* Moved bind tables to libeggdrop

1 guppy 1.26 /*
2 tothwolf 1.66 * tclhash.c --
3 guppy 1.26 *
4 tothwolf 1.66 * bind and unbind
5     * checking and triggering the various in-bot bindings
6     * listing current bindings
7     * adding/removing new binding tables
8     * (non-Tcl) procedure lookups for msg/dcc/file commands
9     * (Tcl) binding internal procedures to msg/dcc/file commands
10 segfault 1.1 */
11 guppy 1.26 /*
12     * Copyright (C) 1997 Robey Pointer
13 wcc 1.60 * Copyright (C) 1999, 2000, 2001, 2002 Eggheads Development Team
14 guppy 1.26 *
15 fabian 1.5 * This program is free software; you can redistribute it and/or
16     * modify it under the terms of the GNU General Public License
17     * as published by the Free Software Foundation; either version 2
18     * of the License, or (at your option) any later version.
19 guppy 1.26 *
20 fabian 1.5 * This program is distributed in the hope that it will be useful,
21     * but WITHOUT ANY WARRANTY; without even the implied warranty of
22     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23     * GNU General Public License for more details.
24 guppy 1.26 *
25 fabian 1.5 * You should have received a copy of the GNU General Public License
26     * along with this program; if not, write to the Free Software
27     * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28 segfault 1.1 */
29 tothwolf 1.66
30     #ifndef lint
31 stdarg 1.75 static const char rcsid[] = "$Id: tclhash.c,v 1.74 2002/09/20 02:06:25 stdarg Exp $";
32 tothwolf 1.66 #endif
33 segfault 1.1
34     #include "main.h"
35     #include "chan.h"
36     #include "users.h"
37 ite 1.59 #include "logfile.h"
38 wingman 1.65 #include "cmdt.h" /* cmd_t */
39     #include "userrec.h" /* touch_laston */
40     #include "match.h" /* wild_match_per */
41     #include "tclhash.h" /* prototypes */
42 segfault 1.1
43 stdarg 1.71 extern struct dcc_t *dcc;
44     extern int dcc_total;
45 fabian 1.10
46 stdarg 1.71 /* The head of the bind table linked list. */
47 stdarg 1.36 static bind_table_t *bind_table_list_head = NULL;
48 stdarg 1.31
49 stdarg 1.71 /* Garbage collection stuff. */
50 stdarg 1.69 static int check_bind_executing = 0;
51     static int already_scheduled = 0;
52     static void bind_table_really_del(bind_table_t *table);
53     static void bind_entry_really_del(bind_table_t *table, bind_entry_t *entry);
54    
55 stdarg 1.57 /* Prototypes for the commands we create in this file. */
56 stdarg 1.69 static int script_bind(char *table_name, char *flags, char *mask, script_callback_t *callback);
57     static int script_unbind(char *table_name, char *flags, char *mask, char *name);
58     static int script_rebind(char *table_name, char *flags, char *mask, char *command, char *newflags, char *newmask);
59 stdarg 1.57 static int script_binds(script_var_t *retval, char *tablename);
60 stdarg 1.46
61 stdarg 1.57 static script_command_t tclhash_script_cmds[] = {
62 stdarg 1.64 {"", "binds", script_binds, NULL, 0, "s", "?bind-table?", 0, SCRIPT_PASS_RETVAL | SCRIPT_VAR_ARGS},
63 stdarg 1.57 {"", "bind", script_bind, NULL, 4, "sssc", "table flags mask command", SCRIPT_INTEGER, 0},
64 stdarg 1.69 {"", "unbind", script_unbind, NULL, 4, "ssss", "table flags mask command", SCRIPT_INTEGER, 0},
65     {"", "rebind", script_rebind, NULL, 6, "ssssss", "table flags mask command newflags newmask", SCRIPT_INTEGER, 0},
66 stdarg 1.55 {0}
67 stdarg 1.46 };
68 stdarg 1.35
69 stdarg 1.45 void binds_init(void)
70 stdarg 1.35 {
71     bind_table_list_head = NULL;
72 stdarg 1.67 script_create_commands(tclhash_script_cmds);
73 segfault 1.1 }
74    
75 stdarg 1.69 static int internal_bind_cleanup()
76     {
77     bind_table_t *table, *next_table;
78     bind_entry_t *entry, *next_entry;
79    
80     for (table = bind_table_list_head; table; table = next_table) {
81     next_table = table->next;
82     if (table->flags & BIND_DELETED) {
83     bind_table_really_del(table);
84     continue;
85     }
86     for (entry = table->entries; entry; entry = next_entry) {
87     next_entry = entry->next;
88     if (entry->flags & BIND_DELETED) bind_entry_really_del(table, entry);
89     }
90     }
91     already_scheduled = 0;
92     return(0);
93     }
94    
95     static void schedule_bind_cleanup()
96     {
97     egg_timeval_t when;
98    
99     if (already_scheduled) return;
100     already_scheduled = 1;
101    
102     when.sec = 0;
103     when.usec = 0;
104     timer_create(&when, internal_bind_cleanup);
105     }
106    
107 stdarg 1.68 void kill_binds(void)
108 stdarg 1.31 {
109 stdarg 1.68 while (bind_table_list_head) bind_table_del(bind_table_list_head);
110 stdarg 1.31 }
111    
112 stdarg 1.68 bind_table_t *bind_table_add(const char *name, int nargs, const char *syntax, int match_type, int flags)
113 stdarg 1.30 {
114     bind_table_t *table;
115    
116 stdarg 1.31 for (table = bind_table_list_head; table; table = table->next) {
117 stdarg 1.72 if (!strcmp(table->name, name)) break;
118 stdarg 1.30 }
119 stdarg 1.72
120     /* If it doesn't exist, create it. */
121     if (!table) {
122     table = (bind_table_t *)calloc(1, sizeof(*table));
123     table->name = strdup(name);
124     table->next = bind_table_list_head;
125     bind_table_list_head = table;
126     }
127     else if (!(table->flags & BIND_FAKE)) return(table);
128    
129 stdarg 1.36 table->nargs = nargs;
130 stdarg 1.72 if (syntax) table->syntax = strdup(syntax);
131 stdarg 1.36 table->match_type = match_type;
132 stdarg 1.30 table->flags = flags;
133     return(table);
134     }
135    
136 stdarg 1.68 void bind_table_del(bind_table_t *table)
137 stdarg 1.30 {
138     bind_table_t *cur, *prev;
139    
140     for (prev = NULL, cur = bind_table_list_head; cur; prev = cur, cur = cur->next) {
141     if (!strcmp(table->name, cur->name)) break;
142     }
143    
144     /* If it's found, remove it from the list. */
145     if (cur) {
146     if (prev) prev->next = cur->next;
147     else bind_table_list_head = cur->next;
148     }
149    
150     /* Now delete it. */
151 stdarg 1.69 if (check_bind_executing) {
152     table->flags |= BIND_DELETED;
153     schedule_bind_cleanup();
154     }
155     else {
156     bind_table_really_del(table);
157     }
158     }
159    
160     static void bind_table_really_del(bind_table_t *table)
161     {
162     bind_entry_t *entry, *next;
163    
164 tothwolf 1.40 free(table->name);
165 stdarg 1.69 for (entry = table->entries; entry; entry = next) {
166     next = entry->next;
167     free(entry->function_name);
168     free(entry->mask);
169     free(entry);
170 stdarg 1.30 }
171 stdarg 1.69 free(table);
172 stdarg 1.30 }
173    
174 stdarg 1.69 bind_table_t *bind_table_lookup(const char *name)
175 stdarg 1.30 {
176     bind_table_t *table;
177    
178     for (table = bind_table_list_head; table; table = table->next) {
179 stdarg 1.69 if (!(table->flags & BIND_DELETED) && !strcmp(table->name, name)) break;
180 stdarg 1.30 }
181 stdarg 1.36 return(table);
182 stdarg 1.30 }
183    
184 stdarg 1.72 bind_table_t *bind_table_lookup_or_fake(const char *name)
185     {
186     bind_table_t *table;
187    
188     table = bind_table_lookup(name);
189     if (!table) table = bind_table_add(name, 0, NULL, 0, BIND_FAKE);
190     return(table);
191     }
192    
193 stdarg 1.69 /* Look up a bind entry based on either function name or id. */
194     bind_entry_t *bind_entry_lookup(bind_table_t *table, int id, const char *mask, const char *function_name)
195 stdarg 1.30 {
196 stdarg 1.69 bind_entry_t *entry;
197 stdarg 1.30
198 stdarg 1.69 for (entry = table->entries; entry; entry = entry->next) {
199     if (entry->flags & BIND_DELETED) continue;
200     if (entry->id == id || (!strcmp(entry->mask, mask) && !strcmp(entry->function_name, function_name))) break;
201 stdarg 1.30 }
202 stdarg 1.69 return(entry);
203     }
204    
205     int bind_entry_del(bind_table_t *table, int id, const char *mask, const char *function_name, void *cdata)
206     {
207     bind_entry_t *entry;
208    
209     entry = bind_entry_lookup(table, id, mask, function_name);
210     if (!entry) return(-1);
211 stdarg 1.31
212 stdarg 1.69 if (cdata) *(void **)cdata = entry->client_data;
213    
214     /* Delete it. */
215     if (check_bind_executing) {
216     entry->flags |= BIND_DELETED;
217     schedule_bind_cleanup();
218 stdarg 1.31 }
219 stdarg 1.69 else bind_entry_really_del(table, entry);
220     return(0);
221     }
222 stdarg 1.31
223 stdarg 1.69 static void bind_entry_really_del(bind_table_t *table, bind_entry_t *entry)
224     {
225     if (entry->next) entry->next->prev = entry->prev;
226     if (entry->prev) entry->prev->next = entry->next;
227     else table->entries = entry->next;
228 tothwolf 1.40 free(entry->function_name);
229 stdarg 1.69 free(entry->mask);
230     memset(entry, 0, sizeof(*entry));
231 tothwolf 1.40 free(entry);
232 stdarg 1.69 }
233    
234     /* Modify a bind entry's flags and mask. */
235     int bind_entry_modify(bind_table_t *table, int id, const char *mask, const char *function_name, const char *newflags, const char *newmask)
236     {
237     bind_entry_t *entry;
238    
239     entry = bind_entry_lookup(table, id, mask, function_name);
240     if (!entry) return(-1);
241    
242     /* Modify it. */
243     free(entry->mask);
244     entry->mask = strdup(newmask);
245     entry->user_flags.match = FR_GLOBAL | FR_CHAN;
246     break_down_flags(newflags, &(entry->user_flags), NULL);
247 stdarg 1.31
248 stdarg 1.30 return(0);
249 segfault 1.1 }
250    
251 stdarg 1.68 int bind_entry_add(bind_table_t *table, const char *flags, const char *mask, const char *function_name, int bind_flags, Function callback, void *client_data)
252 stdarg 1.31 {
253 stdarg 1.69 bind_entry_t *entry, *old_entry;
254    
255     old_entry = bind_entry_lookup(table, -1, mask, function_name);
256 stdarg 1.31
257 stdarg 1.69 if (old_entry) {
258     if (table->flags & BIND_STACKABLE) {
259     entry = (bind_entry_t *)calloc(1, sizeof(*entry));
260     entry->prev = old_entry;
261     entry->next = old_entry->next;
262     old_entry->next = entry;
263     if (entry->next) entry->next->prev = entry;
264     }
265     else {
266     entry = old_entry;
267     free(entry->function_name);
268     free(entry->mask);
269 stdarg 1.33 }
270 stdarg 1.31 }
271 stdarg 1.33 else {
272 stdarg 1.69 for (old_entry = table->entries; old_entry && old_entry->next; old_entry = old_entry->next) {
273     ; /* empty loop */
274     }
275     entry = (bind_entry_t *)calloc(1, sizeof(*entry));
276     if (old_entry) old_entry->next = entry;
277     else table->entries = entry;
278     entry->prev = old_entry;
279 stdarg 1.33 }
280    
281 stdarg 1.69 entry->mask = strdup(mask);
282 ite 1.58 entry->function_name = strdup(function_name);
283 stdarg 1.33 entry->callback = callback;
284     entry->client_data = client_data;
285 stdarg 1.69 entry->flags = bind_flags;
286 stdarg 1.33
287     entry->user_flags.match = FR_GLOBAL | FR_CHAN;
288     break_down_flags(flags, &(entry->user_flags), NULL);
289    
290 stdarg 1.32 return(0);
291 segfault 1.1 }
292    
293 stdarg 1.46 static int script_bind(char *table_name, char *flags, char *mask, script_callback_t *callback)
294 stdarg 1.35 {
295 stdarg 1.46 bind_table_t *table;
296 stdarg 1.39 int retval;
297    
298 stdarg 1.69 table = bind_table_lookup(table_name);
299 stdarg 1.46 if (!table) return(1);
300    
301 ite 1.58 callback->syntax = strdup(table->syntax);
302 stdarg 1.68 retval = bind_entry_add(table, flags, mask, callback->name, BIND_WANTS_CD, callback->callback, callback);
303 stdarg 1.39 return(retval);
304 stdarg 1.35 }
305    
306 stdarg 1.46 static int script_unbind(char *table_name, char *flags, char *mask, char *name)
307 stdarg 1.35 {
308     bind_table_t *table;
309 stdarg 1.46 script_callback_t *callback;
310     int retval;
311 stdarg 1.35
312 stdarg 1.69 table = bind_table_lookup(table_name);
313 stdarg 1.46 if (!table) return(1);
314 stdarg 1.35
315 stdarg 1.69 retval = bind_entry_del(table, -1, mask, name, &callback);
316 ite 1.61 if (callback) callback->del(callback);
317 stdarg 1.46 return(retval);
318 segfault 1.1 }
319    
320 stdarg 1.69 static int script_rebind(char *table_name, char *flags, char *mask, char *command, char *newflags, char *newmask)
321     {
322     bind_table_t *table;
323    
324     table = bind_table_lookup(table_name);
325     if (!table) return(-1);
326     return bind_entry_modify(table, -1, mask, command, newflags, newmask);
327     }
328    
329 fabian 1.18 int findanyidx(register int z)
330 segfault 1.1 {
331 fabian 1.18 register int j;
332 segfault 1.1
333     for (j = 0; j < dcc_total; j++)
334 stdarg 1.63 if (dcc[j].type && dcc[j].sock == z)
335 segfault 1.1 return j;
336     return -1;
337     }
338    
339 stdarg 1.69 /* Returns a list of binds in a given table, or the list of bind tables. */
340 stdarg 1.57 static int script_binds(script_var_t *retval, char *tablename)
341     {
342     bind_table_t *table;
343     bind_entry_t *entry;
344 stdarg 1.69 script_var_t *sublist, *func, *flags, *mask, *nhits;
345 stdarg 1.57 char flagbuf[128];
346    
347     retval->type = SCRIPT_ARRAY | SCRIPT_FREE | SCRIPT_VAR;
348     retval->len = 0;
349     retval->value = NULL;
350    
351 stdarg 1.64 /* No table name? Then return the list of tables. */
352     if (!tablename) {
353     for (table = bind_table_list_head; table; table = table->next) {
354 stdarg 1.69 if (table->flags & BIND_DELETED) return(0);
355 stdarg 1.64 script_list_append(retval, script_string(table->name, -1));
356     }
357     return(0);
358     }
359    
360 stdarg 1.69 table = bind_table_lookup(tablename);
361     if (!table) return(0);
362    
363     for (entry = table->entries; entry; entry = entry->next) {
364     if (entry->flags & BIND_DELETED) continue;
365    
366     mask = script_string(entry->mask, -1);
367     build_flags(flagbuf, &entry->user_flags, NULL);
368     flags = script_copy_string(flagbuf, -1);
369     nhits = script_int(entry->nhits);
370     func = script_string(entry->function_name, -1);
371     sublist = script_list(4, flags, mask, nhits, func);
372     script_list_append(retval, sublist);
373 stdarg 1.64 }
374 stdarg 1.69 return(0);
375     }
376 stdarg 1.57
377 stdarg 1.69 /* Execute a bind entry with the given argument list. */
378     static int bind_entry_exec(bind_table_t *table, bind_entry_t *entry, void **al)
379     {
380     bind_entry_t *prev;
381    
382     /* Give this entry a hit. */
383     entry->nhits++;
384    
385     /* Search for the last entry that isn't deleted. */
386     for (prev = entry->prev; prev; prev = prev->prev) {
387     if (!(prev->flags & BIND_DELETED) && (prev->nhits >= entry->nhits)) break;
388     }
389    
390     /* See if this entry is more popular than the preceding one. */
391     if (entry->prev != prev) {
392     /* Remove entry. */
393     if (entry->prev) entry->prev->next = entry->next;
394     else table->entries = entry->next;
395     if (entry->next) entry->next->prev = entry->prev;
396    
397     /* Re-add in correct position. */
398     if (prev) {
399     entry->next = prev->next;
400     if (prev->next) prev->next->prev = entry;
401     prev->next = entry;
402     }
403     else {
404     entry->next = table->entries;
405     table->entries = entry;
406 stdarg 1.57 }
407 stdarg 1.69 entry->prev = prev;
408     if (entry->next) entry->next->prev = entry;
409 stdarg 1.57 }
410 stdarg 1.69
411     /* Does the callback want client data? */
412     if (entry->flags & BIND_WANTS_CD) {
413     *al = entry->client_data;
414     }
415     else al++;
416    
417     return entry->callback(al[0], al[1], al[2], al[3], al[4], al[5], al[6], al[7], al[8], al[9]);
418 stdarg 1.57 }
419    
420 stdarg 1.69 int check_bind(bind_table_t *table, const char *match, struct flag_record *flags, ...)
421 stdarg 1.33 {
422 stdarg 1.69 void *args[11];
423     bind_entry_t *entry, *next;
424     int i, cmp, retval;
425     va_list ap;
426 stdarg 1.33
427 stdarg 1.69 check_bind_executing++;
428 stdarg 1.33
429 stdarg 1.69 va_start(ap, flags);
430     for (i = 1; i <= table->nargs; i++) {
431     args[i] = va_arg(ap, void *);
432     }
433     va_end(ap);
434 stdarg 1.36
435 stdarg 1.37 /* Default return value is 0 */
436 stdarg 1.69 retval = 0;
437 stdarg 1.37
438 stdarg 1.69 /* If it's a partial bind, we have to find the closest match. */
439     if (table->match_type & MATCH_PARTIAL) {
440 stdarg 1.70 int matchlen, masklen, tie;
441     bind_entry_t *winner;
442 stdarg 1.69
443 stdarg 1.70 matchlen = strlen(match);
444 stdarg 1.69 tie = 0;
445 stdarg 1.70 winner = NULL;
446 stdarg 1.69 for (entry = table->entries; entry; entry = entry->next) {
447     if (entry->flags & BIND_DELETED) continue;
448 stdarg 1.73 if (table->flags & BIND_USE_ATTR) {
449     if (table->flags & BIND_STRICT_ATTR) cmp = flagrec_eq(&entry->user_flags, flags);
450     else cmp = flagrec_ok(&entry->user_flags, flags);
451     if (!cmp) continue;
452     }
453 stdarg 1.70 masklen = strlen(entry->mask);
454     if (!strncasecmp(match, entry->mask, masklen < matchlen ? masklen : matchlen)) {
455     winner = entry;
456     if (masklen == matchlen) break;
457     else if (tie) return(-1);
458     else tie = 1;
459 stdarg 1.69 }
460 stdarg 1.33 }
461 stdarg 1.70 if (winner) retval = bind_entry_exec(table, winner, args);
462 stdarg 1.69 else retval = -1;
463     check_bind_executing--;
464     return(retval);
465     }
466    
467     for (entry = table->entries; entry; entry = next) {
468     next = entry->next;
469     if (entry->flags & BIND_DELETED) continue;
470    
471     if (table->match_type & MATCH_MASK) {
472     cmp = !wild_match_per((unsigned char *)entry->mask, (unsigned char *)match);
473 stdarg 1.33 }
474     else {
475 stdarg 1.69 if (table->match_type & MATCH_CASE) cmp = strcmp(entry->mask, match);
476     else cmp = strcasecmp(entry->mask, match);
477 stdarg 1.33 }
478     if (cmp) continue; /* Doesn't match. */
479 stdarg 1.34
480 stdarg 1.69 /* Check flags. */
481     if (table->flags & BIND_USE_ATTR) {
482     if (table->flags & BIND_STRICT_ATTR) cmp = flagrec_eq(&entry->user_flags, flags);
483     else cmp = flagrec_ok(&entry->user_flags, flags);
484     if (!cmp) continue;
485     }
486 stdarg 1.37
487 stdarg 1.69 retval = bind_entry_exec(table, entry, args);
488     if ((table->flags & BIND_BREAKABLE) && (retval & BIND_RET_BREAK)) {
489     check_bind_executing--;
490     return(retval);
491 stdarg 1.34 }
492 stdarg 1.33 }
493 stdarg 1.69 check_bind_executing--;
494     return(retval);
495 segfault 1.1 }
496    
497 stdarg 1.68 void add_builtins(const char *table_name, cmd_t *cmds)
498 stdarg 1.36 {
499     char name[50];
500 stdarg 1.68 bind_table_t *table;
501    
502 stdarg 1.72 table = bind_table_lookup_or_fake(table_name);
503 stdarg 1.36
504     for (; cmds->name; cmds++) {
505     snprintf(name, 50, "*%s:%s", table->name, cmds->funcname ? cmds->funcname : cmds->name);
506 stdarg 1.68 bind_entry_add(table, cmds->flags, cmds->name, name, 0, cmds->func, NULL);
507 stdarg 1.36 }
508     }
509    
510 stdarg 1.68 void rem_builtins(const char *table_name, cmd_t *cmds)
511 stdarg 1.36 {
512     char name[50];
513 stdarg 1.68 bind_table_t *table;
514    
515 stdarg 1.69 table = bind_table_lookup(table_name);
516 stdarg 1.68 if (!table) return;
517 stdarg 1.36
518     for (; cmds->name; cmds++) {
519     sprintf(name, "*%s:%s", table->name, cmds->funcname ? cmds->funcname : cmds->name);
520 stdarg 1.69 bind_entry_del(table, -1, cmds->name, name, NULL);
521 stdarg 1.36 }
522 segfault 1.1 }

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23