00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #include "main.h"
00032 #include "chan.h"
00033 #include "users.h"
00034
00035 extern Tcl_Interp *interp;
00036 extern struct dcc_t *dcc;
00037 extern struct userrec *userlist;
00038 extern int dcc_total;
00039 extern time_t now;
00040
00041 p_tcl_bind_list bind_table_list;
00042 p_tcl_bind_list H_chat, H_act, H_bcst, H_chon, H_chof, H_load, H_unld, H_link,
00043 H_disc, H_dcc, H_chjn, H_chpt, H_bot, H_time, H_nkch, H_away,
00044 H_note, H_filt, H_event, H_cron, H_log = NULL;
00045
00046 static int builtin_2char();
00047 static int builtin_3char();
00048 static int builtin_5int();
00049 static int builtin_cron();
00050 static int builtin_char();
00051 static int builtin_chpt();
00052 static int builtin_chjn();
00053 static int builtin_idxchar();
00054 static int builtin_charidx();
00055 static int builtin_chat();
00056 static int builtin_dcc();
00057 static int builtin_log();
00058
00059
00060
00061
00062 static inline void *n_malloc_null(int size, const char *file, int line)
00063 {
00064 #ifdef DEBUG_MEM
00065 # define nmalloc_null(size) n_malloc_null(size, __FILE__, __LINE__)
00066 void *ptr = n_malloc(size, file, line);
00067 #else
00068 # define nmalloc_null(size) n_malloc_null(size, NULL, 0)
00069 void *ptr = nmalloc(size);
00070 #endif
00071
00072 egg_memset(ptr, 0, size);
00073 return ptr;
00074 }
00075
00076
00077
00078
00079 static inline void tcl_cmd_delete(tcl_cmd_t *tc)
00080 {
00081 nfree(tc->func_name);
00082 nfree(tc);
00083 }
00084
00085
00086
00087 static inline void tcl_bind_mask_delete(tcl_bind_mask_t *tm)
00088 {
00089 tcl_cmd_t *tc, *tc_next;
00090
00091 for (tc = tm->first; tc; tc = tc_next) {
00092 tc_next = tc->next;
00093 tcl_cmd_delete(tc);
00094 }
00095 nfree(tm->mask);
00096 nfree(tm);
00097 }
00098
00099
00100
00101 static inline void tcl_bind_list_delete(tcl_bind_list_t *tl)
00102 {
00103 tcl_bind_mask_t *tm, *tm_next;
00104
00105 for (tm = tl->first; tm; tm = tm_next) {
00106 tm_next = tm->next;
00107 tcl_bind_mask_delete(tm);
00108 }
00109 nfree(tl);
00110 }
00111
00112 inline void garbage_collect_tclhash(void)
00113 {
00114 tcl_bind_list_t *tl, *tl_next, *tl_prev;
00115 tcl_bind_mask_t *tm, *tm_next, *tm_prev;
00116 tcl_cmd_t *tc, *tc_next, *tc_prev;
00117
00118 for (tl = bind_table_list, tl_prev = NULL; tl; tl = tl_next) {
00119 tl_next = tl->next;
00120
00121 if (tl->flags & HT_DELETED) {
00122 if (tl_prev)
00123 tl_prev->next = tl->next;
00124 else
00125 bind_table_list = tl->next;
00126 tcl_bind_list_delete(tl);
00127 } else {
00128 for (tm = tl->first, tm_prev = NULL; tm; tm = tm_next) {
00129 tm_next = tm->next;
00130
00131 if (!(tm->flags & TBM_DELETED)) {
00132 for (tc = tm->first, tc_prev = NULL; tc; tc = tc_next) {
00133 tc_next = tc->next;
00134
00135 if (tc->attributes & TC_DELETED) {
00136 if (tc_prev)
00137 tc_prev->next = tc->next;
00138 else
00139 tm->first = tc->next;
00140 tcl_cmd_delete(tc);
00141 } else
00142 tc_prev = tc;
00143 }
00144 }
00145
00146
00147 if ((tm->flags & TBM_DELETED) || tm->first == NULL) {
00148 if (tm_prev)
00149 tm_prev->next = tm->next;
00150 else
00151 tl->first = tm_next;
00152 tcl_bind_mask_delete(tm);
00153 } else
00154 tm_prev = tm;
00155 }
00156 tl_prev = tl;
00157 }
00158 }
00159 }
00160
00161 static inline int tcl_cmd_expmem(tcl_cmd_t *tc)
00162 {
00163 int tot;
00164
00165 tot = sizeof(*tc);
00166 if (tc->func_name)
00167 tot += strlen(tc->func_name) + 1;
00168 return tot;
00169 }
00170
00171 static inline int tcl_bind_mask_expmem(tcl_bind_mask_t *tm)
00172 {
00173 int tot = 0;
00174 tcl_cmd_t *tc;
00175
00176 for (tc = tm->first; tc; tc = tc->next)
00177 tot += tcl_cmd_expmem(tc);
00178 if (tm->mask)
00179 tot += strlen(tm->mask) + 1;
00180 tot += sizeof(*tm);
00181 return tot;
00182 }
00183
00184 static inline int tcl_bind_list_expmem(tcl_bind_list_t *tl)
00185 {
00186 int tot = 0;
00187 tcl_bind_mask_t *tm;
00188
00189 for (tm = tl->first; tm; tm = tm->next)
00190 tot += tcl_bind_mask_expmem(tm);
00191 tot += sizeof(*tl);
00192 return tot;
00193 }
00194
00195 int expmem_tclhash(void)
00196 {
00197 int tot = 0;
00198 tcl_bind_list_t *tl;
00199
00200 for (tl = bind_table_list; tl; tl = tl->next)
00201 tot += tcl_bind_list_expmem(tl);
00202 return tot;
00203 }
00204
00205
00206 extern cmd_t C_dcc[];
00207 static int tcl_bind();
00208
00209 static cd_tcl_cmd cd_cmd_table[] = {
00210 {"bind", tcl_bind, (void *) 0},
00211 {"unbind", tcl_bind, (void *) 1},
00212 {0}
00213 };
00214
00215 void init_bind(void)
00216 {
00217 bind_table_list = NULL;
00218 Context;
00219 add_cd_tcl_cmds(cd_cmd_table);
00220 H_unld = add_bind_table("unld", HT_STACKABLE, builtin_char);
00221 H_time = add_bind_table("time", HT_STACKABLE, builtin_5int);
00222 H_cron = add_bind_table("cron", HT_STACKABLE, builtin_cron);
00223 H_note = add_bind_table("note", 0, builtin_3char);
00224 H_nkch = add_bind_table("nkch", HT_STACKABLE, builtin_2char);
00225 H_load = add_bind_table("load", HT_STACKABLE, builtin_char);
00226 H_link = add_bind_table("link", HT_STACKABLE, builtin_2char);
00227 H_filt = add_bind_table("filt", HT_STACKABLE, builtin_idxchar);
00228 H_disc = add_bind_table("disc", HT_STACKABLE, builtin_char);
00229 H_dcc = add_bind_table("dcc", 0, builtin_dcc);
00230 H_chpt = add_bind_table("chpt", HT_STACKABLE, builtin_chpt);
00231 H_chon = add_bind_table("chon", HT_STACKABLE, builtin_charidx);
00232 H_chof = add_bind_table("chof", HT_STACKABLE, builtin_charidx);
00233 H_chjn = add_bind_table("chjn", HT_STACKABLE, builtin_chjn);
00234 H_chat = add_bind_table("chat", HT_STACKABLE, builtin_chat);
00235 H_bot = add_bind_table("bot", 0, builtin_3char);
00236 H_bcst = add_bind_table("bcst", HT_STACKABLE, builtin_chat);
00237 H_away = add_bind_table("away", HT_STACKABLE, builtin_chat);
00238 H_act = add_bind_table("act", HT_STACKABLE, builtin_chat);
00239 H_event = add_bind_table("evnt", HT_STACKABLE, builtin_char);
00240 H_log = add_bind_table("log", HT_STACKABLE, builtin_log);
00241 add_builtins(H_dcc, C_dcc);
00242 Context;
00243 }
00244
00245 void kill_bind(void)
00246 {
00247 tcl_bind_list_t *tl, *tl_next;
00248
00249 rem_builtins(H_dcc, C_dcc);
00250 for (tl = bind_table_list; tl; tl = tl_next) {
00251 tl_next = tl->next;
00252
00253 if (!(tl->flags |= HT_DELETED))
00254 putlog(LOG_DEBUG, "*", "De-Allocated bind table %s", tl->name);
00255 tcl_bind_list_delete(tl);
00256 }
00257 H_log = NULL;
00258 bind_table_list = NULL;
00259 }
00260
00261 tcl_bind_list_t *add_bind_table(const char *nme, int flg, IntFunc func)
00262 {
00263 tcl_bind_list_t *tl, *tl_prev;
00264 int v;
00265
00266
00267
00268 Assert(strlen(nme) <= 4);
00269
00270 for (tl = bind_table_list, tl_prev = NULL; tl; tl_prev = tl, tl = tl->next) {
00271 if (tl->flags & HT_DELETED)
00272 continue;
00273 v = egg_strcasecmp(tl->name, nme);
00274 if (!v)
00275 return tl;
00276 if (v > 0)
00277 break;
00278 }
00279
00280 tl = nmalloc_null(sizeof *tl);
00281 strcpy(tl->name, nme);
00282 tl->flags = flg;
00283 tl->func = func;
00284
00285 if (tl_prev) {
00286 tl->next = tl_prev->next;
00287 tl_prev->next = tl;
00288 } else {
00289 tl->next = bind_table_list;
00290 bind_table_list = tl;
00291 }
00292
00293 putlog(LOG_DEBUG, "*", "Allocated bind table %s (flags %d)", nme, flg);
00294 return tl;
00295 }
00296
00297 void del_bind_table(tcl_bind_list_t *tl_which)
00298 {
00299 tcl_bind_list_t *tl;
00300
00301 for (tl = bind_table_list; tl; tl = tl->next) {
00302 if (tl->flags & HT_DELETED)
00303 continue;
00304 if (tl == tl_which) {
00305 tl->flags |= HT_DELETED;
00306 putlog(LOG_DEBUG, "*", "De-Allocated bind table %s", tl->name);
00307 return;
00308 }
00309 }
00310 putlog(LOG_DEBUG, "*", "??? Tried to delete not listed bind table ???");
00311 }
00312
00313 tcl_bind_list_t *find_bind_table(const char *nme)
00314 {
00315 tcl_bind_list_t *tl;
00316 int v;
00317
00318 for (tl = bind_table_list; tl; tl = tl->next) {
00319 if (tl->flags & HT_DELETED)
00320 continue;
00321 v = egg_strcasecmp(tl->name, nme);
00322 if (!v)
00323 return tl;
00324 if (v > 0)
00325 return NULL;
00326 }
00327 return NULL;
00328 }
00329
00330 static void dump_bind_tables(Tcl_Interp *irp)
00331 {
00332 tcl_bind_list_t *tl;
00333 u_8bit_t i;
00334
00335 for (tl = bind_table_list, i = 0; tl; tl = tl->next) {
00336 if (tl->flags & HT_DELETED)
00337 continue;
00338 if (i)
00339 Tcl_AppendResult(irp, ", ", NULL);
00340 else
00341 i = 1;
00342 Tcl_AppendResult(irp, tl->name, NULL);
00343 }
00344 }
00345
00346 static int unbind_bind_entry(tcl_bind_list_t *tl, const char *flags,
00347 const char *cmd, const char *proc)
00348 {
00349 tcl_bind_mask_t *tm;
00350
00351
00352 for (tm = tl->first; tm; tm = tm->next) {
00353 if (tm->flags & TBM_DELETED)
00354 continue;
00355 if (!strcmp(cmd, tm->mask))
00356 break;
00357 }
00358
00359 if (tm) {
00360 tcl_cmd_t *tc;
00361
00362
00363 for (tc = tm->first; tc; tc = tc->next) {
00364 if (tc->attributes & TC_DELETED)
00365 continue;
00366 if (!egg_strcasecmp(tc->func_name, proc)) {
00367
00368 tc->attributes |= TC_DELETED;
00369 return 1;
00370 }
00371 }
00372 }
00373 return 0;
00374 }
00375
00376
00377
00378 static int bind_bind_entry(tcl_bind_list_t *tl, const char *flags,
00379 const char *cmd, const char *proc)
00380 {
00381 tcl_cmd_t *tc;
00382 tcl_bind_mask_t *tm;
00383
00384
00385 for (tm = tl->first; tm; tm = tm->next) {
00386 if (tm->flags & TBM_DELETED)
00387 continue;
00388 if (!strcmp(cmd, tm->mask))
00389 break;
00390 }
00391
00392
00393 if (!tm) {
00394 tm = nmalloc_null(sizeof *tm);
00395 tm->mask = nmalloc(strlen(cmd) + 1);
00396 strcpy(tm->mask, cmd);
00397
00398
00399 tm->next = tl->first;
00400 tl->first = tm;
00401 }
00402
00403
00404 for (tc = tm->first; tc; tc = tc->next) {
00405 if (tc->attributes & TC_DELETED)
00406 continue;
00407 if (!egg_strcasecmp(tc->func_name, proc)) {
00408 tc->flags.match = FR_GLOBAL | FR_CHAN;
00409 break_down_flags(flags, &(tc->flags), NULL);
00410 return 1;
00411 }
00412 }
00413
00414
00415
00416 if (!(tl->flags & HT_STACKABLE)) {
00417 for (tc = tm->first; tc; tc = tc->next) {
00418 if (tc->attributes & TC_DELETED)
00419 continue;
00420
00421 tc->attributes |= TC_DELETED;
00422 break;
00423 }
00424 }
00425
00426 tc = nmalloc_null(sizeof *tc);
00427 tc->flags.match = FR_GLOBAL | FR_CHAN;
00428 break_down_flags(flags, &(tc->flags), NULL);
00429 tc->func_name = nmalloc(strlen(proc) + 1);
00430 strcpy(tc->func_name, proc);
00431
00432
00433 tc->next = tm->first;
00434 tm->first = tc;
00435
00436 return 1;
00437 }
00438
00439 static int tcl_getbinds(tcl_bind_list_t *tl_kind, const char *name)
00440 {
00441 tcl_bind_mask_t *tm;
00442
00443 for (tm = tl_kind->first; tm; tm = tm->next) {
00444 if (tm->flags & TBM_DELETED)
00445 continue;
00446 if (!egg_strcasecmp(tm->mask, name)) {
00447 tcl_cmd_t *tc;
00448
00449 for (tc = tm->first; tc; tc = tc->next) {
00450 if (tc->attributes & TC_DELETED)
00451 continue;
00452 Tcl_AppendElement(interp, tc->func_name);
00453 }
00454 break;
00455 }
00456 }
00457 return TCL_OK;
00458 }
00459
00460 static int tcl_bind STDVAR
00461 {
00462 tcl_bind_list_t *tl;
00463
00464
00465 if ((long int) cd == 1)
00466 BADARGS(5, 5, " type flags cmd/mask procname");
00467
00468 else
00469 BADARGS(4, 5, " type flags cmd/mask ?procname?");
00470
00471 tl = find_bind_table(argv[1]);
00472 if (!tl) {
00473 Tcl_AppendResult(irp, "bad type, should be one of: ", NULL);
00474 dump_bind_tables(irp);
00475 return TCL_ERROR;
00476 }
00477 if ((long int) cd == 1) {
00478 if (!unbind_bind_entry(tl, argv[2], argv[3], argv[4])) {
00479
00480 if (argv[4][0] != '*' || argv[4][4] != ':' ||
00481 strcmp(argv[3], &argv[4][5]) || strncmp(argv[1], &argv[4][1], 3)) {
00482 Tcl_AppendResult(irp, "no such binding", NULL);
00483 return TCL_ERROR;
00484 }
00485 }
00486 } else {
00487 if (argc == 4)
00488 return tcl_getbinds(tl, argv[3]);
00489 bind_bind_entry(tl, argv[2], argv[3], argv[4]);
00490 }
00491 Tcl_AppendResult(irp, argv[3], NULL);
00492 return TCL_OK;
00493 }
00494
00495 int check_validity(char *nme, IntFunc func)
00496 {
00497 char *p;
00498 tcl_bind_list_t *tl;
00499
00500 if (*nme != '*')
00501 return 0;
00502 p = strchr(nme + 1, ':');
00503 if (p == NULL)
00504 return 0;
00505 *p = 0;
00506 tl = find_bind_table(nme + 1);
00507 *p = ':';
00508 if (!tl)
00509 return 0;
00510 if (tl->func != func)
00511 return 0;
00512 return 1;
00513 }
00514
00515 static int builtin_3char STDVAR
00516 {
00517 Function F = (Function) cd;
00518
00519 BADARGS(4, 4, " from to args");
00520
00521 CHECKVALIDITY(builtin_3char);
00522 F(argv[1], argv[2], argv[3]);
00523 return TCL_OK;
00524 }
00525
00526 static int builtin_2char STDVAR
00527 {
00528 Function F = (Function) cd;
00529
00530 BADARGS(3, 3, " nick msg");
00531
00532 CHECKVALIDITY(builtin_2char);
00533 F(argv[1], argv[2]);
00534 return TCL_OK;
00535 }
00536
00537 static int builtin_5int STDVAR
00538 {
00539 Function F = (Function) cd;
00540
00541 BADARGS(6, 6, " min hrs dom mon year");
00542
00543 CHECKVALIDITY(builtin_5int);
00544 F(atoi(argv[1]), atoi(argv[2]), atoi(argv[3]), atoi(argv[4]), atoi(argv[5]));
00545 return TCL_OK;
00546 }
00547
00548 static int builtin_cron STDVAR
00549 {
00550 Function F = (Function) cd;
00551
00552 BADARGS(6, 6, " min hrs dom mon weekday");
00553
00554 CHECKVALIDITY(builtin_cron);
00555 F(atoi(argv[1]), atoi(argv[2]), atoi(argv[3]), atoi(argv[4]), atoi(argv[5]));
00556 return TCL_OK;
00557 }
00558
00559 static int builtin_char STDVAR
00560 {
00561 Function F = (Function) cd;
00562
00563 BADARGS(2, 2, " handle");
00564
00565 CHECKVALIDITY(builtin_char);
00566 F(argv[1]);
00567 return TCL_OK;
00568 }
00569
00570 static int builtin_chpt STDVAR
00571 {
00572 Function F = (Function) cd;
00573
00574 BADARGS(3, 3, " bot nick sock");
00575
00576 CHECKVALIDITY(builtin_chpt);
00577 F(argv[1], argv[2], atoi(argv[3]));
00578 return TCL_OK;
00579 }
00580
00581 static int builtin_chjn STDVAR
00582 {
00583 Function F = (Function) cd;
00584
00585 BADARGS(6, 6, " bot nick chan# flag&sock host");
00586
00587 CHECKVALIDITY(builtin_chjn);
00588 F(argv[1], argv[2], atoi(argv[3]), argv[4][0],
00589 argv[4][0] ? atoi(argv[4] + 1) : 0, argv[5]);
00590 return TCL_OK;
00591 }
00592
00593 static int builtin_idxchar STDVAR
00594 {
00595 Function F = (Function) cd;
00596 int idx;
00597 char *r;
00598
00599 BADARGS(3, 3, " idx args");
00600
00601 CHECKVALIDITY(builtin_idxchar);
00602 idx = findidx(atoi(argv[1]));
00603 if (idx < 0) {
00604 Tcl_AppendResult(irp, "invalid idx", NULL);
00605 return TCL_ERROR;
00606 }
00607 r = (((char *(*)()) F) (idx, argv[2]));
00608
00609 Tcl_ResetResult(irp);
00610 Tcl_AppendResult(irp, r, NULL);
00611 return TCL_OK;
00612 }
00613
00614 static int builtin_charidx STDVAR
00615 {
00616 Function F = (Function) cd;
00617 int idx;
00618
00619 BADARGS(3, 3, " handle idx");
00620
00621 CHECKVALIDITY(builtin_charidx);
00622 idx = findanyidx(atoi(argv[2]));
00623 if (idx < 0) {
00624 Tcl_AppendResult(irp, "invalid idx", NULL);
00625 return TCL_ERROR;
00626 }
00627 Tcl_AppendResult(irp, int_to_base10(F(argv[1], idx)), NULL);
00628
00629 return TCL_OK;
00630 }
00631
00632 static int builtin_chat STDVAR
00633 {
00634 Function F = (Function) cd;
00635 int ch;
00636
00637 BADARGS(4, 4, " handle idx text");
00638
00639 CHECKVALIDITY(builtin_chat);
00640 ch = atoi(argv[2]);
00641 F(argv[1], ch, argv[3]);
00642 return TCL_OK;
00643 }
00644
00645 static int builtin_dcc STDVAR
00646 {
00647 int idx;
00648 Function F = (Function) cd;
00649
00650 BADARGS(4, 4, " hand idx param");
00651
00652 CHECKVALIDITY(builtin_dcc);
00653 idx = findidx(atoi(argv[2]));
00654 if (idx < 0) {
00655 Tcl_AppendResult(irp, "invalid idx", NULL);
00656 return TCL_ERROR;
00657 }
00658
00659
00660
00661
00662 if (F == CMD_LEAVE) {
00663 Tcl_AppendResult(irp, "break", NULL);
00664 return TCL_OK;
00665 }
00666
00667
00668
00669
00670 debug4("tcl: builtin dcc call: %s %s %s %s", argv[0], argv[1], argv[2],
00671 (!strcmp(argv[0] + 5, "newpass") || !strcmp(argv[0] + 5, "chpass")) ?
00672 "[something]" : argv[3]);
00673 F(dcc[idx].user, idx, argv[3]);
00674 Tcl_ResetResult(irp);
00675 Tcl_AppendResult(irp, "0", NULL);
00676 return TCL_OK;
00677 }
00678
00679 static int builtin_log STDVAR
00680 {
00681 Function F = (Function) cd;
00682
00683 BADARGS(3, 3, " lvl chan msg");
00684
00685 CHECKVALIDITY(builtin_log);
00686 F(argv[1], argv[2], argv[3]);
00687 return TCL_OK;
00688 }
00689
00690
00691
00692
00693
00694 static inline int trigger_bind(const char *proc, const char *param,
00695 char *mask)
00696 {
00697 int x;
00698 #ifdef DEBUG_CONTEXT
00699 const char *msg = "Tcl proc: %s, param: %s";
00700 char *buf;
00701
00702
00703
00704
00705
00706 Context;
00707 buf = nmalloc(strlen(msg) + (proc ? strlen(proc) : 6)
00708 + (param ? strlen(param) : 6) + 1);
00709 sprintf(buf, msg, proc ? proc : "<null>", param ? param : "<null>");
00710 ContextNote(buf);
00711 nfree(buf);
00712 #endif
00713
00714
00715
00716
00717
00718 Tcl_SetVar(interp, "lastbind", (char *) mask, TCL_GLOBAL_ONLY);
00719
00720 x = Tcl_VarEval(interp, proc, param, NULL);
00721 Context;
00722
00723 if (x == TCL_ERROR) {
00724
00725 putlog(LOG_MISC, "*", "Tcl error [%s]: %.*s", proc, 400, tcl_resultstring());
00726
00727 return BIND_EXECUTED;
00728 }
00729
00730
00731
00732
00733 if (!strcmp(tcl_resultstring(), "break"))
00734 return BIND_QUIT;
00735
00736 return (tcl_resultint() > 0) ? BIND_EXEC_LOG : BIND_EXECUTED;
00737 }
00738
00739
00740
00741
00742
00743
00744
00745 static inline int check_bind_match(const char *match, char *mask,
00746 int match_type)
00747 {
00748 switch (match_type & 0x07) {
00749 case MATCH_PARTIAL:
00750 return (!egg_strncasecmp(match, mask, strlen(match)));
00751 break;
00752 case MATCH_EXACT:
00753 return (!egg_strcasecmp(match, mask));
00754 break;
00755 case MATCH_CASE:
00756 return (!strcmp(match, mask));
00757 break;
00758 case MATCH_MASK:
00759 return (wild_match_per(mask, match));
00760 break;
00761 case MATCH_MODE:
00762 return (wild_match_partial_case(mask, match));
00763 break;
00764 case MATCH_CRON:
00765 return (cron_match(mask, match));
00766 break;
00767 default:
00768
00769 break;
00770 }
00771 return 0;
00772 }
00773
00774
00775
00776
00777
00778
00779 static inline int check_bind_flags(struct flag_record *flags,
00780 struct flag_record *atr, int match_type)
00781 {
00782 if (match_type & BIND_USE_ATTR) {
00783 if (match_type & BIND_HAS_BUILTINS)
00784 return (flagrec_ok(flags, atr));
00785 else
00786 return (flagrec_eq(flags, atr));
00787 } else
00788 return 1;
00789 return 0;
00790 }
00791
00792
00793
00794 int check_tcl_bind(tcl_bind_list_t *tl, const char *match,
00795 struct flag_record *atr, const char *param, int match_type)
00796 {
00797 int x, result = 0, cnt = 0, finish = 0;
00798 char *proc = NULL, *mask = NULL;
00799 tcl_bind_mask_t *tm, *tm_last = NULL, *tm_p = NULL;
00800 tcl_cmd_t *tc, *htc = NULL;
00801
00802 for (tm = tl->first; tm && !finish; tm_last = tm, tm = tm->next) {
00803
00804 if (tm->flags & TBM_DELETED)
00805 continue;
00806
00807 if (!check_bind_match(match, tm->mask, match_type))
00808 continue;
00809
00810 for (tc = tm->first; tc; tc = tc->next) {
00811
00812
00813 if (!(tc->attributes & TC_DELETED)) {
00814
00815
00816 if (check_bind_flags(&tc->flags, atr, match_type)) {
00817 cnt++;
00818 tm_p = tm_last;
00819
00820
00821 if (!(match_type & BIND_STACKABLE)) {
00822
00823
00824 proc = tc->func_name;
00825 mask = tm->mask;
00826 htc = tc;
00827
00828
00829
00830
00831 if ((match_type & 0x07) != MATCH_PARTIAL ||
00832
00833 !egg_strcasecmp(match, tm->mask)) {
00834 cnt = 1;
00835 finish = 1;
00836 }
00837
00838
00839 break;
00840 }
00841
00842
00843
00844
00845
00846
00847
00848
00849
00850
00851
00852 tc->hits++;
00853
00854 x = trigger_bind(tc->func_name, param, tm->mask);
00855
00856 if ((tl->flags & HT_DELETED) || (tm->flags & TBM_DELETED)) {
00857
00858 return x;
00859 } else if (match_type & BIND_ALTER_ARGS) {
00860 if (tcl_resultempty())
00861 return x;
00862 } else if ((match_type & BIND_STACKRET) && x == BIND_EXEC_LOG) {
00863
00864
00865
00866
00867 if (!result)
00868 result = x;
00869 continue;
00870 } else if ((match_type & BIND_WANTRET) && x == BIND_EXEC_LOG) {
00871
00872 return x;
00873 }
00874 }
00875 }
00876 }
00877 }
00878
00879 if (!cnt)
00880 return BIND_NOMATCH;
00881
00882
00883
00884
00885 if (result)
00886 return result;
00887
00888 if ((match_type & 0x07) == MATCH_MASK || (match_type & 0x07) == MATCH_CASE)
00889 return BIND_EXECUTED;
00890
00891
00892 if (htc)
00893 htc->hits++;
00894
00895
00896
00897
00898 if (tm_p && tm_p->next) {
00899 tm = tm_p->next;
00900 tm_p->next = tm->next;
00901 tm->next = tl->first;
00902 tl->first = tm;
00903 }
00904
00905 if (cnt > 1)
00906 return BIND_AMBIGUOUS;
00907
00908 return trigger_bind(proc, param, mask);
00909 }
00910
00911
00912
00913
00914
00915 int check_tcl_dcc(const char *cmd, int idx, const char *args)
00916 {
00917 struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 };
00918 int x;
00919 char s[11];
00920
00921 get_user_flagrec(dcc[idx].user, &fr, dcc[idx].u.chat->con_chan);
00922 egg_snprintf(s, sizeof s, "%ld", dcc[idx].sock);
00923 Tcl_SetVar(interp, "_dcc1", (char *) dcc[idx].nick, 0);
00924 Tcl_SetVar(interp, "_dcc2", (char *) s, 0);
00925 Tcl_SetVar(interp, "_dcc3", (char *) args, 0);
00926 x = check_tcl_bind(H_dcc, cmd, &fr, " $_dcc1 $_dcc2 $_dcc3",
00927 MATCH_PARTIAL | BIND_USE_ATTR | BIND_HAS_BUILTINS);
00928 if (x == BIND_AMBIGUOUS) {
00929 dprintf(idx, MISC_AMBIGUOUS);
00930 return 0;
00931 }
00932 if (x == BIND_NOMATCH) {
00933 dprintf(idx, MISC_NOSUCHCMD);
00934 return 0;
00935 }
00936
00937
00938 if (x == BIND_QUIT)
00939 return 1;
00940
00941 if (x == BIND_EXEC_LOG)
00942 putlog(LOG_CMDS, "*", "#%s# %s %s", dcc[idx].nick, cmd, args);
00943 return 0;
00944 }
00945
00946 void check_tcl_bot(const char *nick, const char *code, const char *param)
00947 {
00948 Tcl_SetVar(interp, "_bot1", (char *) nick, 0);
00949 Tcl_SetVar(interp, "_bot2", (char *) code, 0);
00950 Tcl_SetVar(interp, "_bot3", (char *) param, 0);
00951 check_tcl_bind(H_bot, code, 0, " $_bot1 $_bot2 $_bot3", MATCH_EXACT);
00952 }
00953
00954 void check_tcl_chonof(char *hand, int sock, tcl_bind_list_t *tl)
00955 {
00956 struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 };
00957 char s[11];
00958 struct userrec *u;
00959
00960 u = get_user_by_handle(userlist, hand);
00961 touch_laston(u, "partyline", now);
00962 get_user_flagrec(u, &fr, NULL);
00963 Tcl_SetVar(interp, "_chonof1", (char *) hand, 0);
00964 egg_snprintf(s, sizeof s, "%d", sock);
00965 Tcl_SetVar(interp, "_chonof2", (char *) s, 0);
00966 check_tcl_bind(tl, hand, &fr, " $_chonof1 $_chonof2", MATCH_MASK |
00967 BIND_USE_ATTR | BIND_STACKABLE | BIND_WANTRET);
00968 }
00969
00970 void check_tcl_chatactbcst(const char *from, int chan, const char *text,
00971 tcl_bind_list_t *tl)
00972 {
00973 char s[11];
00974
00975 egg_snprintf(s, sizeof s, "%d", chan);
00976 Tcl_SetVar(interp, "_cab1", (char *) from, 0);
00977 Tcl_SetVar(interp, "_cab2", (char *) s, 0);
00978 Tcl_SetVar(interp, "_cab3", (char *) text, 0);
00979 check_tcl_bind(tl, text, 0, " $_cab1 $_cab2 $_cab3",
00980 MATCH_MASK | BIND_STACKABLE);
00981 }
00982
00983 void check_tcl_nkch(const char *ohand, const char *nhand)
00984 {
00985 Tcl_SetVar(interp, "_nkch1", (char *) ohand, 0);
00986 Tcl_SetVar(interp, "_nkch2", (char *) nhand, 0);
00987 check_tcl_bind(H_nkch, ohand, 0, " $_nkch1 $_nkch2",
00988 MATCH_MASK | BIND_STACKABLE);
00989 }
00990
00991 void check_tcl_link(const char *bot, const char *via)
00992 {
00993 Tcl_SetVar(interp, "_link1", (char *) bot, 0);
00994 Tcl_SetVar(interp, "_link2", (char *) via, 0);
00995 check_tcl_bind(H_link, bot, 0, " $_link1 $_link2",
00996 MATCH_MASK | BIND_STACKABLE);
00997 }
00998
00999 void check_tcl_disc(const char *bot)
01000 {
01001 Tcl_SetVar(interp, "_disc1", (char *) bot, 0);
01002 check_tcl_bind(H_disc, bot, 0, " $_disc1", MATCH_MASK | BIND_STACKABLE);
01003 }
01004
01005 void check_tcl_loadunld(const char *mod, tcl_bind_list_t *tl)
01006 {
01007 Tcl_SetVar(interp, "_lu1", (char *) mod, 0);
01008 check_tcl_bind(tl, mod, 0, " $_lu1", MATCH_MASK | BIND_STACKABLE);
01009 }
01010
01011 const char *check_tcl_filt(int idx, const char *text)
01012 {
01013 char s[11];
01014 int x;
01015 struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 };
01016
01017 egg_snprintf(s, sizeof s, "%ld", dcc[idx].sock);
01018 get_user_flagrec(dcc[idx].user, &fr, dcc[idx].u.chat->con_chan);
01019 Tcl_SetVar(interp, "_filt1", (char *) s, 0);
01020 Tcl_SetVar(interp, "_filt2", (char *) text, 0);
01021 x = check_tcl_bind(H_filt, text, &fr, " $_filt1 $_filt2",
01022 MATCH_MASK | BIND_USE_ATTR | BIND_STACKABLE |
01023 BIND_WANTRET | BIND_ALTER_ARGS);
01024 if (x == BIND_EXECUTED || x == BIND_EXEC_LOG) {
01025 if (tcl_resultempty())
01026 return "";
01027 else
01028 return tcl_resultstring();
01029 } else
01030 return text;
01031 }
01032
01033 int check_tcl_note(const char *from, const char *to, const char *text)
01034 {
01035 int x;
01036
01037 Tcl_SetVar(interp, "_note1", (char *) from, 0);
01038 Tcl_SetVar(interp, "_note2", (char *) to, 0);
01039 Tcl_SetVar(interp, "_note3", (char *) text, 0);
01040
01041 x = check_tcl_bind(H_note, to, 0, " $_note1 $_note2 $_note3",
01042 MATCH_MASK | BIND_STACKABLE | BIND_WANTRET);
01043
01044 return (x == BIND_EXEC_LOG);
01045 }
01046
01047 void check_tcl_listen(const char *cmd, int idx)
01048 {
01049 char s[11];
01050 int x;
01051
01052 egg_snprintf(s, sizeof s, "%d", idx);
01053 Tcl_SetVar(interp, "_n", (char *) s, 0);
01054 x = Tcl_VarEval(interp, cmd, " $_n", NULL);
01055 if (x == TCL_ERROR)
01056 putlog(LOG_MISC, "*", "error on listen: %s", tcl_resultstring());
01057 }
01058
01059 void check_tcl_chjn(const char *bot, const char *nick, int chan,
01060 const char type, int sock, const char *host)
01061 {
01062 struct flag_record fr = { FR_GLOBAL, 0, 0, 0, 0, 0 };
01063 char s[11], t[2], u[11];
01064
01065 t[0] = type;
01066 t[1] = 0;
01067 switch (type) {
01068 case '*':
01069 fr.global = USER_OWNER;
01070
01071 break;
01072 case '+':
01073 fr.global = USER_MASTER;
01074
01075 break;
01076 case '@':
01077 fr.global = USER_OP;
01078
01079 break;
01080 case '^':
01081 fr.global = USER_HALFOP;
01082
01083 break;
01084 case '%':
01085 fr.global = USER_BOTMAST;
01086 }
01087 egg_snprintf(s, sizeof s, "%d", chan);
01088 egg_snprintf(u, sizeof u, "%d", sock);
01089 Tcl_SetVar(interp, "_chjn1", (char *) bot, 0);
01090 Tcl_SetVar(interp, "_chjn2", (char *) nick, 0);
01091 Tcl_SetVar(interp, "_chjn3", (char *) s, 0);
01092 Tcl_SetVar(interp, "_chjn4", (char *) t, 0);
01093 Tcl_SetVar(interp, "_chjn5", (char *) u, 0);
01094 Tcl_SetVar(interp, "_chjn6", (char *) host, 0);
01095 check_tcl_bind(H_chjn, s, &fr,
01096 " $_chjn1 $_chjn2 $_chjn3 $_chjn4 $_chjn5 $_chjn6",
01097 MATCH_MASK | BIND_STACKABLE);
01098 }
01099
01100 void check_tcl_chpt(const char *bot, const char *hand, int sock, int chan)
01101 {
01102 char u[11], v[11];
01103
01104 egg_snprintf(u, sizeof u, "%d", sock);
01105 egg_snprintf(v, sizeof v, "%d", chan);
01106 Tcl_SetVar(interp, "_chpt1", (char *) bot, 0);
01107 Tcl_SetVar(interp, "_chpt2", (char *) hand, 0);
01108 Tcl_SetVar(interp, "_chpt3", (char *) u, 0);
01109 Tcl_SetVar(interp, "_chpt4", (char *) v, 0);
01110 check_tcl_bind(H_chpt, v, 0, " $_chpt1 $_chpt2 $_chpt3 $_chpt4",
01111 MATCH_MASK | BIND_STACKABLE);
01112 }
01113
01114 void check_tcl_away(const char *bot, int idx, const char *msg)
01115 {
01116 char u[11];
01117
01118 egg_snprintf(u, sizeof u, "%d", idx);
01119 Tcl_SetVar(interp, "_away1", (char *) bot, 0);
01120 Tcl_SetVar(interp, "_away2", (char *) u, 0);
01121 Tcl_SetVar(interp, "_away3", msg ? (char *) msg : "", 0);
01122 check_tcl_bind(H_away, bot, 0, " $_away1 $_away2 $_away3",
01123 MATCH_MASK | BIND_STACKABLE);
01124 }
01125
01126 void check_tcl_time(struct tm *tm)
01127 {
01128 char y[18];
01129
01130 egg_snprintf(y, sizeof y, "%02d", tm->tm_min);
01131 Tcl_SetVar(interp, "_time1", (char *) y, 0);
01132 egg_snprintf(y, sizeof y, "%02d", tm->tm_hour);
01133 Tcl_SetVar(interp, "_time2", (char *) y, 0);
01134 egg_snprintf(y, sizeof y, "%02d", tm->tm_mday);
01135 Tcl_SetVar(interp, "_time3", (char *) y, 0);
01136 egg_snprintf(y, sizeof y, "%02d", tm->tm_mon);
01137 Tcl_SetVar(interp, "_time4", (char *) y, 0);
01138 egg_snprintf(y, sizeof y, "%04d", tm->tm_year + 1900);
01139 Tcl_SetVar(interp, "_time5", (char *) y, 0);
01140 egg_snprintf(y, sizeof y, "%02d %02d %02d %02d %04d", tm->tm_min, tm->tm_hour,
01141 tm->tm_mday, tm->tm_mon, tm->tm_year + 1900);
01142 check_tcl_bind(H_time, y, 0,
01143 " $_time1 $_time2 $_time3 $_time4 $_time5",
01144 MATCH_MASK | BIND_STACKABLE);
01145 }
01146
01147 void check_tcl_cron(struct tm *tm)
01148 {
01149 char y[15];
01150
01151 egg_snprintf(y, sizeof y, "%02d", tm->tm_min);
01152 Tcl_SetVar(interp, "_cron1", (char *) y, 0);
01153 egg_snprintf(y, sizeof y, "%02d", tm->tm_hour);
01154 Tcl_SetVar(interp, "_cron2", (char *) y, 0);
01155 egg_snprintf(y, sizeof y, "%02d", tm->tm_mday);
01156 Tcl_SetVar(interp, "_cron3", (char *) y, 0);
01157 egg_snprintf(y, sizeof y, "%02d", tm->tm_mon + 1);
01158 Tcl_SetVar(interp, "_cron4", (char *) y, 0);
01159 egg_snprintf(y, sizeof y, "%02d", tm->tm_wday);
01160 Tcl_SetVar(interp, "_cron5", (char *) y, 0);
01161 egg_snprintf(y, sizeof y, "%02d %02d %02d %02d %02d", tm->tm_min, tm->tm_hour,
01162 tm->tm_mday, tm->tm_mon + 1, tm->tm_wday);
01163 check_tcl_bind(H_cron, y, 0,
01164 " $_cron1 $_cron2 $_cron3 $_cron4 $_cron5",
01165 MATCH_CRON | BIND_STACKABLE);
01166 }
01167
01168 void check_tcl_event(const char *event)
01169 {
01170 Tcl_SetVar(interp, "_event1", (char *) event, 0);
01171 check_tcl_bind(H_event, event, 0, " $_event1", MATCH_EXACT | BIND_STACKABLE);
01172 }
01173
01174 void check_tcl_log(int lv, char *chan, char *msg)
01175 {
01176 char mask[512];
01177
01178 snprintf(mask, sizeof mask, "%s %s", chan, msg);
01179 Tcl_SetVar(interp, "_log1", masktype(lv), 0);
01180 Tcl_SetVar(interp, "_log2", chan, 0);
01181 Tcl_SetVar(interp, "_log3", msg, 0);
01182 check_tcl_bind(H_log, mask, 0, " $_log1 $_log2 $_log3",
01183 MATCH_MASK | BIND_STACKABLE);
01184 }
01185
01186 void tell_binds(int idx, char *par)
01187 {
01188 tcl_bind_list_t *tl, *tl_kind;
01189 tcl_bind_mask_t *tm;
01190 int fnd = 0, showall = 0, patmatc = 0;
01191 tcl_cmd_t *tc;
01192 char *name, *proc, *s, flg[100];
01193
01194 if (par[0])
01195 name = newsplit(&par);
01196 else
01197 name = NULL;
01198 if (par[0])
01199 s = newsplit(&par);
01200 else
01201 s = NULL;
01202
01203 if (name)
01204 tl_kind = find_bind_table(name);
01205 else
01206 tl_kind = NULL;
01207
01208 if ((name && name[0] && !egg_strcasecmp(name, "all")) ||
01209 (s && s[0] && !egg_strcasecmp(s, "all")))
01210 showall = 1;
01211 if (tl_kind == NULL && name && name[0] && egg_strcasecmp(name, "all"))
01212 patmatc = 1;
01213
01214 dprintf(idx, MISC_CMDBINDS);
01215 dprintf(idx, " TYPE FLAGS COMMAND HITS BINDING (TCL)\n");
01216
01217 for (tl = tl_kind ? tl_kind : bind_table_list; tl;
01218 tl = tl_kind ? 0 : tl->next) {
01219 if (tl->flags & HT_DELETED)
01220 continue;
01221 for (tm = tl->first; tm; tm = tm->next) {
01222 if (tm->flags & TBM_DELETED)
01223 continue;
01224 for (tc = tm->first; tc; tc = tc->next) {
01225 if (tc->attributes & TC_DELETED)
01226 continue;
01227 proc = tc->func_name;
01228 build_flags(flg, &(tc->flags), NULL);
01229 if (showall || proc[0] != '*') {
01230 int ok = 0;
01231
01232 if (patmatc == 1) {
01233 if (wild_match_per(name, tl->name) ||
01234 wild_match_per(name, tm->mask) ||
01235 wild_match_per(name, tc->func_name))
01236 ok = 1;
01237 } else
01238 ok = 1;
01239
01240 if (ok) {
01241 dprintf(idx, " %-4s %-8s %-20s %4d %s\n", tl->name, flg, tm->mask,
01242 tc->hits, tc->func_name);
01243 fnd = 1;
01244 }
01245 }
01246 }
01247 }
01248 }
01249 if (!fnd) {
01250 if (patmatc)
01251 dprintf(idx, "No command bindings found that match %s\n", name);
01252 else if (tl_kind)
01253 dprintf(idx, "No command bindings for type: %s.\n", name);
01254 else
01255 dprintf(idx, "No command bindings exist.\n");
01256 }
01257 }
01258
01259
01260 void add_builtins(tcl_bind_list_t *tl, cmd_t *cc)
01261 {
01262 int k, i;
01263 char p[1024], *l;
01264 cd_tcl_cmd table[2];
01265
01266 table[0].name = p;
01267 table[0].callback = tl->func;
01268 table[1].name = NULL;
01269 for (i = 0; cc[i].name; i++) {
01270 egg_snprintf(p, sizeof p, "*%s:%s", tl->name,
01271 cc[i].funcname ? cc[i].funcname : cc[i].name);
01272 l = nmalloc(Tcl_ScanElement(p, &k) + 1);
01273 Tcl_ConvertElement(p, l, k | TCL_DONT_USE_BRACES);
01274 table[0].cdata = (void *) cc[i].func;
01275 add_cd_tcl_cmds(table);
01276 bind_bind_entry(tl, cc[i].flags, cc[i].name, l);
01277 nfree(l);
01278 }
01279 }
01280
01281
01282 void rem_builtins(tcl_bind_list_t *table, cmd_t *cc)
01283 {
01284 int k, i;
01285 char p[1024], *l;
01286
01287 for (i = 0; cc[i].name; i++) {
01288 egg_snprintf(p, sizeof p, "*%s:%s", table->name,
01289 cc[i].funcname ? cc[i].funcname : cc[i].name);
01290 l = nmalloc(Tcl_ScanElement(p, &k) + 1);
01291 Tcl_ConvertElement(p, l, k | TCL_DONT_USE_BRACES);
01292 Tcl_DeleteCommand(interp, p);
01293 unbind_bind_entry(table, cc[i].flags, cc[i].name, l);
01294 nfree(l);
01295 }
01296 }