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

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

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


Revision 1.75 - (show annotations) (download) (as text)
Thu Oct 10 04:41:59 2002 UTC (17 years, 2 months 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 /*
2 * tclhash.c --
3 *
4 * 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 */
11 /*
12 * Copyright (C) 1997 Robey Pointer
13 * Copyright (C) 1999, 2000, 2001, 2002 Eggheads Development Team
14 *
15 * 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 *
20 * 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 *
25 * 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 */
29
30 #ifndef lint
31 static const char rcsid[] = "$Id: tclhash.c,v 1.74 2002/09/20 02:06:25 stdarg Exp $";
32 #endif
33
34 #include "main.h"
35 #include "chan.h"
36 #include "users.h"
37 #include "logfile.h"
38 #include "cmdt.h" /* cmd_t */
39 #include "userrec.h" /* touch_laston */
40 #include "match.h" /* wild_match_per */
41 #include "tclhash.h" /* prototypes */
42
43 extern struct dcc_t *dcc;
44 extern int dcc_total;
45
46 /* The head of the bind table linked list. */
47 static bind_table_t *bind_table_list_head = NULL;
48
49 /* Garbage collection stuff. */
50 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 /* Prototypes for the commands we create in this file. */
56 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 static int script_binds(script_var_t *retval, char *tablename);
60
61 static script_command_t tclhash_script_cmds[] = {
62 {"", "binds", script_binds, NULL, 0, "s", "?bind-table?", 0, SCRIPT_PASS_RETVAL | SCRIPT_VAR_ARGS},
63 {"", "bind", script_bind, NULL, 4, "sssc", "table flags mask command", SCRIPT_INTEGER, 0},
64 {"", "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 {0}
67 };
68
69 void binds_init(void)
70 {
71 bind_table_list_head = NULL;
72 script_create_commands(tclhash_script_cmds);
73 }
74
75 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 void kill_binds(void)
108 {
109 while (bind_table_list_head) bind_table_del(bind_table_list_head);
110 }
111
112 bind_table_t *bind_table_add(const char *name, int nargs, const char *syntax, int match_type, int flags)
113 {
114 bind_table_t *table;
115
116 for (table = bind_table_list_head; table; table = table->next) {
117 if (!strcmp(table->name, name)) break;
118 }
119
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 table->nargs = nargs;
130 if (syntax) table->syntax = strdup(syntax);
131 table->match_type = match_type;
132 table->flags = flags;
133 return(table);
134 }
135
136 void bind_table_del(bind_table_t *table)
137 {
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 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 free(table->name);
165 for (entry = table->entries; entry; entry = next) {
166 next = entry->next;
167 free(entry->function_name);
168 free(entry->mask);
169 free(entry);
170 }
171 free(table);
172 }
173
174 bind_table_t *bind_table_lookup(const char *name)
175 {
176 bind_table_t *table;
177
178 for (table = bind_table_list_head; table; table = table->next) {
179 if (!(table->flags & BIND_DELETED) && !strcmp(table->name, name)) break;
180 }
181 return(table);
182 }
183
184 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 /* 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 {
196 bind_entry_t *entry;
197
198 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 }
202 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
212 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 }
219 else bind_entry_really_del(table, entry);
220 return(0);
221 }
222
223 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 free(entry->function_name);
229 free(entry->mask);
230 memset(entry, 0, sizeof(*entry));
231 free(entry);
232 }
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
248 return(0);
249 }
250
251 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 {
253 bind_entry_t *entry, *old_entry;
254
255 old_entry = bind_entry_lookup(table, -1, mask, function_name);
256
257 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 }
270 }
271 else {
272 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 }
280
281 entry->mask = strdup(mask);
282 entry->function_name = strdup(function_name);
283 entry->callback = callback;
284 entry->client_data = client_data;
285 entry->flags = bind_flags;
286
287 entry->user_flags.match = FR_GLOBAL | FR_CHAN;
288 break_down_flags(flags, &(entry->user_flags), NULL);
289
290 return(0);
291 }
292
293 static int script_bind(char *table_name, char *flags, char *mask, script_callback_t *callback)
294 {
295 bind_table_t *table;
296 int retval;
297
298 table = bind_table_lookup(table_name);
299 if (!table) return(1);
300
301 callback->syntax = strdup(table->syntax);
302 retval = bind_entry_add(table, flags, mask, callback->name, BIND_WANTS_CD, callback->callback, callback);
303 return(retval);
304 }
305
306 static int script_unbind(char *table_name, char *flags, char *mask, char *name)
307 {
308 bind_table_t *table;
309 script_callback_t *callback;
310 int retval;
311
312 table = bind_table_lookup(table_name);
313 if (!table) return(1);
314
315 retval = bind_entry_del(table, -1, mask, name, &callback);
316 if (callback) callback->del(callback);
317 return(retval);
318 }
319
320 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 int findanyidx(register int z)
330 {
331 register int j;
332
333 for (j = 0; j < dcc_total; j++)
334 if (dcc[j].type && dcc[j].sock == z)
335 return j;
336 return -1;
337 }
338
339 /* Returns a list of binds in a given table, or the list of bind tables. */
340 static int script_binds(script_var_t *retval, char *tablename)
341 {
342 bind_table_t *table;
343 bind_entry_t *entry;
344 script_var_t *sublist, *func, *flags, *mask, *nhits;
345 char flagbuf[128];
346
347 retval->type = SCRIPT_ARRAY | SCRIPT_FREE | SCRIPT_VAR;
348 retval->len = 0;
349 retval->value = NULL;
350
351 /* No table name? Then return the list of tables. */
352 if (!tablename) {
353 for (table = bind_table_list_head; table; table = table->next) {
354 if (table->flags & BIND_DELETED) return(0);
355 script_list_append(retval, script_string(table->name, -1));
356 }
357 return(0);
358 }
359
360 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 }
374 return(0);
375 }
376
377 /* 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 }
407 entry->prev = prev;
408 if (entry->next) entry->next->prev = entry;
409 }
410
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 }
419
420 int check_bind(bind_table_t *table, const char *match, struct flag_record *flags, ...)
421 {
422 void *args[11];
423 bind_entry_t *entry, *next;
424 int i, cmp, retval;
425 va_list ap;
426
427 check_bind_executing++;
428
429 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
435 /* Default return value is 0 */
436 retval = 0;
437
438 /* If it's a partial bind, we have to find the closest match. */
439 if (table->match_type & MATCH_PARTIAL) {
440 int matchlen, masklen, tie;
441 bind_entry_t *winner;
442
443 matchlen = strlen(match);
444 tie = 0;
445 winner = NULL;
446 for (entry = table->entries; entry; entry = entry->next) {
447 if (entry->flags & BIND_DELETED) continue;
448 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 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 }
460 }
461 if (winner) retval = bind_entry_exec(table, winner, args);
462 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 }
474 else {
475 if (table->match_type & MATCH_CASE) cmp = strcmp(entry->mask, match);
476 else cmp = strcasecmp(entry->mask, match);
477 }
478 if (cmp) continue; /* Doesn't match. */
479
480 /* 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
487 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 }
492 }
493 check_bind_executing--;
494 return(retval);
495 }
496
497 void add_builtins(const char *table_name, cmd_t *cmds)
498 {
499 char name[50];
500 bind_table_t *table;
501
502 table = bind_table_lookup_or_fake(table_name);
503
504 for (; cmds->name; cmds++) {
505 snprintf(name, 50, "*%s:%s", table->name, cmds->funcname ? cmds->funcname : cmds->name);
506 bind_entry_add(table, cmds->flags, cmds->name, name, 0, cmds->func, NULL);
507 }
508 }
509
510 void rem_builtins(const char *table_name, cmd_t *cmds)
511 {
512 char name[50];
513 bind_table_t *table;
514
515 table = bind_table_lookup(table_name);
516 if (!table) return;
517
518 for (; cmds->name; cmds++) {
519 sprintf(name, "*%s:%s", table->name, cmds->funcname ? cmds->funcname : cmds->name);
520 bind_entry_del(table, -1, cmds->name, name, NULL);
521 }
522 }

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23