| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242 |
- /*
- * tclhash.c -- handles:
- * bind and unbind
- * checking and triggering the various in-bot bindings
- * listing current bindings
- * adding/removing new binding tables
- * (non-Tcl) procedure lookups for msg/dcc/file commands
- * (Tcl) binding internal procedures to msg/dcc/file commands
- *
- */
- #include "main.h"
- #include "chan.h"
- #include "users.h"
- #include "match.c"
- extern Tcl_Interp *interp;
- extern struct dcc_t *dcc;
- extern struct userrec *userlist;
- extern int dcc_total;
- extern time_t now;
- extern mycmds cmds[];
- extern int cmdi;
- extern char dcc_prefix[];
- p_tcl_bind_list bind_table_list;
- p_tcl_bind_list H_chat, H_act, H_bcst, H_chon, H_chof,
- H_load, H_unld, H_link, H_disc, H_dcc, H_chjn, H_chpt,
- H_bot, H_time, H_nkch, H_away, H_note, H_filt, H_event;
- static int builtin_2char();
- static int builtin_3char();
- static int builtin_5int();
- static int builtin_char();
- static int builtin_chpt();
- static int builtin_chjn();
- static int builtin_idxchar();
- static int builtin_charidx();
- static int builtin_chat();
- static int builtin_dcc();
- /* Allocate and initialise a chunk of memory.
- */
- static inline void *n_malloc_null(int size, const char *file, int line)
- {
- #ifdef DEBUG_MEM
- # define nmalloc_null(size) n_malloc_null(size, __FILE__, __LINE__)
- void *ptr = n_malloc(size, file, line);
- #else
- # define nmalloc_null(size) n_malloc_null(size, NULL, 0)
- void *ptr = nmalloc(size);
- #endif
- egg_memset(ptr, 0, size);
- return ptr;
- }
- /* Delete trigger/command.
- */
- static inline void tcl_cmd_delete(tcl_cmd_t *tc)
- {
- nfree(tc->func_name);
- nfree(tc);
- }
- /* Delete bind and its elements.
- */
- static inline void tcl_bind_mask_delete(tcl_bind_mask_t *tm)
- {
- tcl_cmd_t *tc, *tc_next;
- for (tc = tm->first; tc; tc = tc_next) {
- tc_next = tc->next;
- tcl_cmd_delete(tc);
- }
- nfree(tm->mask);
- nfree(tm);
- }
- /* Delete bind list and its elements.
- */
- static inline void tcl_bind_list_delete(tcl_bind_list_t *tl)
- {
- tcl_bind_mask_t *tm, *tm_next;
- for (tm = tl->first; tm; tm = tm_next) {
- tm_next = tm->next;
- tcl_bind_mask_delete(tm);
- }
- nfree(tl);
- }
- inline void garbage_collect_tclhash(void)
- {
- tcl_bind_list_t *tl, *tl_next, *tl_prev;
- tcl_bind_mask_t *tm, *tm_next, *tm_prev;
- tcl_cmd_t *tc, *tc_next, *tc_prev;
- for (tl = bind_table_list, tl_prev = NULL; tl; tl = tl_next) {
- tl_next = tl->next;
- if (tl->flags & HT_DELETED) {
- if (tl_prev)
- tl_prev->next = tl->next;
- else
- bind_table_list = tl->next;
- tcl_bind_list_delete(tl);
- } else {
- for (tm = tl->first, tm_prev = NULL; tm; tm = tm_next) {
- tm_next = tm->next;
- if (!(tm->flags & TBM_DELETED)) {
- for (tc = tm->first, tc_prev = NULL; tc; tc = tc_next) {
- tc_next = tc->next;
- if (tc->attributes & TC_DELETED) {
- if (tc_prev)
- tc_prev->next = tc->next;
- else
- tm->first = tc->next;
- tcl_cmd_delete(tc);
- } else
- tc_prev = tc;
- }
- }
- /* Delete the bind when it's marked as deleted or
- when it's empty. */
- if ((tm->flags & TBM_DELETED) || tm->first == NULL) {
- if (tm_prev)
- tm_prev->next = tm->next;
- else
- tl->first = tm_next;
- tcl_bind_mask_delete(tm);
- } else
- tm_prev = tm;
- }
- tl_prev = tl;
- }
- }
- }
- static inline int tcl_cmd_expmem(tcl_cmd_t *tc)
- {
- int tot;
- tot = sizeof(*tc);
- if (tc->func_name)
- tot += strlen(tc->func_name) + 1;
- return tot;
- }
- static inline int tcl_bind_mask_expmem(tcl_bind_mask_t *tm)
- {
- int tot = 0;
- tcl_cmd_t *tc;
- for (tc = tm->first; tc; tc = tc->next)
- tot += tcl_cmd_expmem(tc);
- if (tm->mask)
- tot += strlen(tm->mask) + 1;
- tot += sizeof(*tm);
- return tot;
- }
- static inline int tcl_bind_list_expmem(tcl_bind_list_t *tl)
- {
- int tot = 0;
- tcl_bind_mask_t *tm;
- for (tm = tl->first; tm; tm = tm->next)
- tot += tcl_bind_mask_expmem(tm);
- tot += sizeof(*tl);
- return tot;
- }
- int expmem_tclhash(void)
- {
- int tot = 0;
- tcl_bind_list_t *tl;
- for (tl = bind_table_list; tl; tl = tl->next)
- tot += tcl_bind_list_expmem(tl);
- return tot;
- }
- extern dcc_cmd_t C_dcc[];
- static int tcl_bind();
- static cd_tcl_cmd cd_cmd_table[] = {
- {"bind", tcl_bind, (void *)0},
- {"unbind", tcl_bind, (void *)1},
- {0}
- };
- void init_bind(void)
- {
- bind_table_list = NULL;
- Context;
- add_cd_tcl_cmds(cd_cmd_table);
- H_unld = add_bind_table("unld", HT_STACKABLE, builtin_char);
- H_time = add_bind_table("time", HT_STACKABLE, builtin_5int);
- H_note = add_bind_table("note", 0, builtin_3char);
- H_nkch = add_bind_table("nkch", HT_STACKABLE, builtin_2char);
- H_load = add_bind_table("load", HT_STACKABLE, builtin_char);
- H_link = add_bind_table("link", HT_STACKABLE, builtin_2char);
- H_filt = add_bind_table("filt", HT_STACKABLE, builtin_idxchar);
- H_disc = add_bind_table("disc", HT_STACKABLE, builtin_char);
- H_dcc = add_bind_table("dcc", 0, builtin_dcc);
- H_chpt = add_bind_table("chpt", HT_STACKABLE, builtin_chpt);
- H_chon = add_bind_table("chon", HT_STACKABLE, builtin_charidx);
- H_chof = add_bind_table("chof", HT_STACKABLE, builtin_charidx);
- H_chjn = add_bind_table("chjn", HT_STACKABLE, builtin_chjn);
- H_chat = add_bind_table("chat", HT_STACKABLE, builtin_chat);
- H_bot = add_bind_table("bot", 0, builtin_3char);
- H_bcst = add_bind_table("bcst", HT_STACKABLE, builtin_chat);
- H_away = add_bind_table("away", HT_STACKABLE, builtin_chat);
- H_act = add_bind_table("act", HT_STACKABLE, builtin_chat);
- H_event = add_bind_table("evnt", HT_STACKABLE, builtin_char);
- add_builtins_dcc(H_dcc, C_dcc);
- Context;
- }
- void kill_bind(void)
- {
- tcl_bind_list_t *tl, *tl_next;
- rem_builtins_dcc(H_dcc, C_dcc);
- for (tl = bind_table_list; tl; tl = tl_next) {
- tl_next = tl->next;
- if (!(tl->flags |= HT_DELETED))
- putlog(LOG_DEBUG, "*", "De-Allocated bind table %s", tl->name);
- tcl_bind_list_delete(tl);
- }
- bind_table_list = NULL;
- }
- tcl_bind_list_t *add_bind_table(const char *nme, int flg, Function func)
- {
- tcl_bind_list_t *tl, *tl_prev;
- int v;
- /* Do not allow coders to use bind table names longer than
- 4 characters. */
- Assert(strlen(nme) <= 4);
- for (tl = bind_table_list, tl_prev = NULL; tl; tl_prev = tl, tl = tl->next) {
- if (tl->flags & HT_DELETED)
- continue;
- v = egg_strcasecmp(tl->name, nme);
- if (!v)
- return tl; /* Duplicate, just return old value. */
- if (v > 0)
- break; /* New. Insert at start of list. */
- }
- tl = nmalloc_null(sizeof(tcl_bind_list_t));
- strcpy(tl->name, nme);
- tl->flags = flg;
- tl->func = func;
- if (tl_prev) {
- tl->next = tl_prev->next;
- tl_prev->next = tl;
- } else {
- tl->next = bind_table_list;
- bind_table_list = tl;
- }
- putlog(LOG_DEBUG, "*", "Allocated bind table %s (flags %d)", nme, flg);
- return tl;
- }
- void del_bind_table(tcl_bind_list_t *tl_which)
- {
- tcl_bind_list_t *tl;
- for (tl = bind_table_list; tl; tl = tl->next) {
- if (tl->flags & HT_DELETED)
- continue;
- if (tl == tl_which) {
- tl->flags |= HT_DELETED;
- putlog(LOG_DEBUG, "*", "De-Allocated bind table %s", tl->name);
- return;
- }
- }
- putlog(LOG_DEBUG, "*", "??? Tried to delete not listed bind table ???");
- }
- tcl_bind_list_t *find_bind_table(const char *nme)
- {
- tcl_bind_list_t *tl;
- int v;
- for (tl = bind_table_list; tl; tl = tl->next) {
- if (tl->flags & HT_DELETED)
- continue;
- v = egg_strcasecmp(tl->name, nme);
- if (!v)
- return tl;
- if (v > 0)
- return NULL;
- }
- return NULL;
- }
- static void dump_bind_tables(Tcl_Interp *irp)
- {
- tcl_bind_list_t *tl;
- u_8bit_t i;
- for (tl = bind_table_list, i = 0; tl; tl = tl->next) {
- if (tl->flags & HT_DELETED)
- continue;
- if (i)
- Tcl_AppendResult(irp, ", ", NULL);
- else
- i = 1;
- Tcl_AppendResult(irp, tl->name, NULL);
- }
- }
- static int unbind_bind_entry(tcl_bind_list_t *tl, const char *flags,
- const char *cmd, const char *proc)
- {
- tcl_bind_mask_t *tm;
- /* Search for matching bind in bind list. */
- for (tm = tl->first; tm; tm = tm->next) {
- if (tm->flags & TBM_DELETED)
- continue;
- if (!strcmp(cmd, tm->mask))
- break; /* Found it! fall out! */
- }
- if (tm) {
- tcl_cmd_t *tc;
- /* Search for matching proc in bind. */
- for (tc = tm->first; tc; tc = tc->next) {
- if (tc->attributes & TC_DELETED)
- continue;
- if (!egg_strcasecmp(tc->func_name, proc)) {
- /* Erase proc regardless of flags. */
- tc->attributes |= TC_DELETED;
- return 1; /* Match. */
- }
- }
- }
- return 0; /* No match. */
- }
- /* Add command (remove old one if necessary)
- */
- static int bind_bind_entry(tcl_bind_list_t *tl, const char *flags,
- const char *cmd, const char *proc)
- {
- tcl_cmd_t *tc;
- tcl_bind_mask_t *tm, *tm_last;
- Context;
- /* Search for matching bind in bind list. */
- for (tm = tl->first, tm_last = NULL; tm; tm_last = tm, tm = tm->next) {
- if (tm->flags & TBM_DELETED)
- continue;
- if (!strcmp(cmd, tm->mask))
- break; /* Found it! fall out! */
- }
- /* Create bind if it doesn't exist yet. */
- if (!tm) {
- tm = nmalloc_null(sizeof(tcl_bind_mask_t));
- tm->mask = nmalloc(strlen(cmd) + 1);
- strcpy(tm->mask, cmd);
- /* Link into linked list of binds. */
- tm->next = tl->first;
- tl->first = tm;
- }
- /* Proc already defined? If so, replace. */
- for (tc = tm->first; tc; tc = tc->next) {
- if (tc->attributes & TC_DELETED)
- continue;
- if (!egg_strcasecmp(tc->func_name, proc)) {
- tc->flags.match = FR_GLOBAL | FR_CHAN;
- break_down_flags(flags, &(tc->flags), NULL);
- return 1;
- }
- }
- /* If this bind list is not stackable, remove the
- old entry from this bind. */
- if (!(tl->flags & HT_STACKABLE)) {
- for (tc = tm->first; tc; tc = tc->next) {
- if (tc->attributes & TC_DELETED)
- continue;
- /* NOTE: We assume there's only one not-yet-deleted
- entry. */
- tc->attributes |= TC_DELETED;
- break;
- }
- }
- tc = nmalloc_null(sizeof(tcl_cmd_t));
- tc->flags.match = FR_GLOBAL | FR_CHAN;
- break_down_flags(flags, &(tc->flags), NULL);
- tc->func_name = nmalloc(strlen(proc) + 1);
- strcpy(tc->func_name, proc);
- /* Link into linked list of the bind's command list. */
- tc->next = tm->first;
- tm->first = tc;
- return 1;
- }
- static int tcl_getbinds(tcl_bind_list_t *tl_kind, const char *name)
- {
- tcl_bind_mask_t *tm;
- for (tm = tl_kind->first; tm; tm = tm->next) {
- if (tm->flags & TBM_DELETED)
- continue;
- if (!egg_strcasecmp(tm->mask, name)) {
- tcl_cmd_t *tc;
- for (tc = tm->first; tc; tc = tc->next) {
- if (tc->attributes & TC_DELETED)
- continue;
- Tcl_AppendElement(interp, tc->func_name);
- }
- break;
- }
- }
- return TCL_OK;
- }
- static int tcl_bind STDVAR
- {
- tcl_bind_list_t *tl;
- /* Note: `cd' defines what tcl_bind is supposed do: 0 stands for
- bind and 1 stands for unbind. */
- if ((long int) cd == 1)
- BADARGS(5, 5, " type flags cmd/mask procname");
- else
- BADARGS(4, 5, " type flags cmd/mask ?procname?");
- tl = find_bind_table(argv[1]);
- if (!tl) {
- Tcl_AppendResult(irp, "bad type, should be one of: ", NULL);
- dump_bind_tables(irp);
- return TCL_ERROR;
- }
- if ((long int) cd == 1) {
- if (!unbind_bind_entry(tl, argv[2], argv[3], argv[4])) {
- /* Don't error if trying to re-unbind a builtin */
- if (argv[4][0] != '*' || argv[4][4] != ':' ||
- strcmp(argv[3], &argv[4][5]) || strncmp(argv[1], &argv[4][1], 3)) {
- Tcl_AppendResult(irp, "no such binding", NULL);
- return TCL_ERROR;
- }
- }
- } else {
- if (argc == 4)
- return tcl_getbinds(tl, argv[3]);
- bind_bind_entry(tl, argv[2], argv[3], argv[4]);
- }
- Tcl_AppendResult(irp, argv[3], NULL);
- return TCL_OK;
- }
- int check_validity(char *nme, Function func)
- {
- char *p;
- tcl_bind_list_t *tl;
- if (*nme != '*')
- return 0;
- p = strchr(nme + 1, ':');
- if (p == NULL)
- return 0;
- *p = 0;
- tl = find_bind_table(nme + 1);
- *p = ':';
- if (!tl)
- return 0;
- if (tl->func != func)
- return 0;
- return 1;
- }
- static int builtin_3char STDVAR
- {
- Function F = (Function) cd;
- BADARGS(4, 4, " from to args");
- CHECKVALIDITY(builtin_3char);
- F(argv[1], argv[2], argv[3]);
- return TCL_OK;
- }
- static int builtin_2char STDVAR
- {
- Function F = (Function) cd;
- BADARGS(3, 3, " nick msg");
- CHECKVALIDITY(builtin_2char);
- F(argv[1], argv[2]);
- return TCL_OK;
- }
- static int builtin_5int STDVAR
- {
- Function F = (Function) cd;
- BADARGS(6, 6, " min hrs dom mon year");
- CHECKVALIDITY(builtin_5int);
- F(atoi(argv[1]), atoi(argv[2]), atoi(argv[3]), atoi(argv[4]), atoi(argv[5]));
- return TCL_OK;
- }
- static int builtin_char STDVAR
- {
- Function F = (Function) cd;
- BADARGS(2, 2, " handle");
- CHECKVALIDITY(builtin_char);
- F(argv[1]);
- return TCL_OK;
- }
- static int builtin_chpt STDVAR
- {
- Function F = (Function) cd;
- BADARGS(3, 3, " bot nick sock");
- CHECKVALIDITY(builtin_chpt);
- F(argv[1], argv[2], atoi(argv[3]));
- return TCL_OK;
- }
- static int builtin_chjn STDVAR
- {
- Function F = (Function) cd;
- BADARGS(6, 6, " bot nick chan# flag&sock host");
- CHECKVALIDITY(builtin_chjn);
- F(argv[1], argv[2], atoi(argv[3]), argv[4][0],
- argv[4][0] ? atoi(argv[4] + 1) : 0, argv[5]);
- return TCL_OK;
- }
- static int builtin_idxchar STDVAR
- {
- Function F = (Function) cd;
- int idx;
- char *r;
- BADARGS(3, 3, " idx args");
- CHECKVALIDITY(builtin_idxchar);
- if (atoi(argv[1]) < 0) { /* this is a remote-simul idx */
- idx = atoi(argv[1]) * -1;
- } else {
- idx = findidx(atoi(argv[1]));
- }
- if (idx < 0) {
- Tcl_AppendResult(irp, "invalid idx", NULL);
- return TCL_ERROR;
- }
- r = (((char *(*)()) F) (idx, argv[2]));
- Tcl_ResetResult(irp);
- Tcl_AppendResult(irp, r, NULL);
- return TCL_OK;
- }
- int findanyidx(register int z)
- {
- register int j;
- for (j = 0; j < dcc_total; j++)
- if (dcc[j].sock == z)
- return j;
- return -1;
- }
- static int builtin_charidx STDVAR
- {
- Function F = (Function) cd;
- int idx;
- BADARGS(3, 3, " handle idx");
- CHECKVALIDITY(builtin_charidx);
- idx = findanyidx(atoi(argv[2]));
- if (idx < 0) {
- Tcl_AppendResult(irp, "invalid idx", NULL);
- return TCL_ERROR;
- }
- Tcl_AppendResult(irp, int_to_base10(F(argv[1], idx)), NULL);
- return TCL_OK;
- }
- static int builtin_chat STDVAR
- {
- Function F = (Function) cd;
- int ch;
- BADARGS(4, 4, " handle idx text");
- CHECKVALIDITY(builtin_chat);
- ch = atoi(argv[2]);
- F(argv[1], ch, argv[3]);
- return TCL_OK;
- }
- static int builtin_dcc STDVAR
- {
- int idx;
- Function F = (Function) cd;
- BADARGS(4, 4, " hand idx param");
- if (atoi(argv[2]) < 0) { /* this is a remote-simul idx */
- idx = atoi(argv[2]) * -1;
- } else {
- idx = findidx(atoi(argv[2]));
- }
- if (idx < 0) {
- Tcl_AppendResult(irp, "invalid idx", NULL);
- return TCL_ERROR;
- }
- if (F == NULL) {
- Tcl_AppendResult(irp, "break", NULL);
- return TCL_OK;
- }
- /* Check if it's a password change, if so, don't show the password. We
- * don't need pretty formats here, as it's only for debugging purposes.
- */
- debug4(STR("tcl: builtin dcc call: %s %s %s %s"), argv[0], argv[1], argv[2],
- (!strcmp(argv[0] + 5, "newpass") ||
- !strcmp(argv[0] + 5, "chpass")) ? "[something]" : argv[3]);
- (F) (dcc[idx].user, idx, argv[3]);
- Tcl_ResetResult(irp);
- Tcl_AppendResult(irp, "0", NULL);
- return TCL_OK;
- }
- /* trigger (execute) a proc */
- static int trigger_bind(const char *proc, const char *param)
- {
- int x;
- /* We now try to debug the Tcl_VarEval() call below by remembering both
- * the called proc name and it's parameters. This should render us a bit
- * less helpless when we see context dumps.
- */
- {
- const char *msg = "Tcl proc: %s, param: %s";
- char *buf;
- Context;
- buf = nmalloc(strlen(msg) + (proc ? strlen(proc) : 6)
- + (param ? strlen(param) : 6) + 1);
- sprintf(buf, msg, proc ? proc : "<null>", param ? param : "<null>");
- ContextNote(buf);
- nfree(buf);
- }
- x = Tcl_VarEval(interp, proc, param, NULL);
- Context;
- if (x == TCL_ERROR) {
- if (strlen(interp->result) > 400)
- interp->result[400] = 0;
- putlog(LOG_MISC, "*", "Tcl error [%s]: %s", proc, interp->result);
- return BIND_EXECUTED;
- } else {
- if (!strcmp(interp->result, "break"))
- return BIND_EXEC_BRK;
- return (atoi(interp->result) > 0) ? BIND_EXEC_LOG : BIND_EXECUTED;
- }
- }
- int check_tcl_bind(tcl_bind_list_t *tl, const char *match,
- struct flag_record *atr, const char *param, int match_type)
- {
- tcl_bind_mask_t *tm, *tm_last = NULL, *tm_p = NULL;
- int cnt = 0;
- char *proc = NULL, *fullmatch = NULL;
- tcl_cmd_t *tc, *htc = NULL;
- int finish = 0, atrok, x, ok;
- for (tm = tl->first; tm && !finish; tm_last = tm, tm = tm->next) {
- if (tm->flags & TBM_DELETED)
- continue;
- /* Find out whether this bind matches the mask or provides
- the the requested atcributes, depending on the specified
- requirements. */
- switch (match_type & 0x03) {
- case MATCH_PARTIAL:
- ok = !egg_strncasecmp(match, tm->mask, strlen(match));
- break;
- case MATCH_EXACT:
- ok = !egg_strcasecmp(match, tm->mask);
- break;
- case MATCH_CASE:
- ok = !strcmp(match, tm->mask);
- break;
- case MATCH_MASK:
- ok = wild_match_per((unsigned char *) tm->mask, (unsigned char *) match);
- break;
- default:
- ok = 0;
- }
- if (!ok)
- continue; /* This bind does not match. */
- if (match_type & BIND_STACKABLE) {
- /* Could be multiple commands/triggers. */
- for (tc = tm->first; tc; tc = tc->next) {
- if (match_type & BIND_USE_ATTR) {
- /* Check whether the provided flags suffice for
- this command/trigger. */
- if (match_type & BIND_HAS_BUILTINS)
- atrok = flagrec_ok(&tc->flags, atr);
- else
- atrok = flagrec_eq(&tc->flags, atr);
- } else
- atrok = 1;
- if (atrok) {
- cnt++;
- tc->hits++;
- tm_p = tm_last;
- Tcl_SetVar(interp, "lastbind", (char *) tm->mask, TCL_GLOBAL_ONLY);
- x = trigger_bind(tc->func_name, param);
- Context;
- if (match_type & BIND_ALTER_ARGS) {
- if (interp->result == NULL || !interp->result[0])
- return x;
- } else if ((match_type & BIND_WANTRET) && x == BIND_EXEC_LOG)
- return x;
- }
- }
- /* Apart from MATCH_MASK, currently no match type allows us to match
- against more than one bind. So if this isn't MATCH_MASK then exit
- the loop now. */
- /* This will suffice until we have stackable partials. */
- if ((match_type & 3) != MATCH_MASK)
- finish = 1;
- } else {
- /* Search for valid entry. */
- for (tc = tm->first; tc; tc = tc->next)
- if (!(tc->attributes & TC_DELETED))
- break;
- if (tc) {
- /* Check whether the provided flags suffice for this
- command/trigger. */
- if (match_type & BIND_USE_ATTR) {
- if (match_type & BIND_HAS_BUILTINS)
- atrok = flagrec_ok(&tc->flags, atr);
- else
- atrok = flagrec_eq(&tc->flags, atr);
- } else
- atrok = 1;
- if (atrok) {
- cnt++;
- /* Remember information about this bind and its only
- command/trigger. */
- proc = tc->func_name;
- fullmatch = tm->mask;
- htc = tc;
- tm_p = tm_last;
- /* Either this is a non-partial match, which means we
- only want to execute _one_ bind ... */
- if ((match_type & 3) != MATCH_PARTIAL ||
- /* ... or this is happens to be an exact match. */
- !egg_strcasecmp(match, tm->mask))
- cnt = finish = 1;
- }
- }
- }
- }
- if (!cnt)
- return BIND_NOMATCH;
- if ((match_type & 0x03) == MATCH_MASK ||
- (match_type & 0x03) == MATCH_CASE)
- return BIND_EXECUTED;
- /* Now that we have found at least one bind, we can update the
- preferred entries information. */
- if (htc)
- htc->hits++;
- if (tm_p) {
- /* Move mask to front of bind's mask list. */
- tm = tm_p->next;
- tm_p->next = tm->next; /* Unlink mask from list. */
- tm->next = tl->first; /* Readd mask to front of list. */
- tl->first = tm;
- }
- if (cnt > 1)
- return BIND_AMBIGUOUS;
- Tcl_SetVar(interp, "lastbind", (char *) fullmatch, TCL_GLOBAL_ONLY);
- Context;
- return trigger_bind(proc, param);
- }
- /* Check for tcl-bound dcc command, return 1 if found
- * dcc: proc-name <handle> <sock> <args...>
- */
- int check_tcl_dcc(char *cmd, int idx, char *args)
- {
- struct tcl_bind_mask_b *hm;
- struct flag_record fr = {FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0};
- int x;
- #ifdef S_DCCPASS
- int found = 0;
- #endif
- char s[11];
- get_user_flagrec(dcc[idx].user, &fr, dcc[idx].u.chat->con_chan);
- if (dcc[idx].simul) {
- egg_snprintf(s, sizeof s, "-%d", idx);
- } else {
- egg_snprintf(s, sizeof s, "%ld", dcc[idx].sock);
- }
- #ifdef S_DCCPASS
- for (hm = H_dcc->first; hm; hm = hm->next) {
- if (!egg_strcasecmp(cmd, hm->mask)) {
- found = 1;
- break;
- }
- }
- if (found) {
- if (has_cmd_pass(cmd)) {
- char *p,
- work[1024],
- pass[128];
- p = strchr(args, ' ');
- if (p)
- *p = 0;
- strncpy0(pass, args, sizeof(pass));
- if (check_cmd_pass(cmd, pass)) {
- if (p)
- *p = ' ';
- strncpy0(work, args, sizeof(work));
- p = work;
- newsplit(&p);
- strcpy(args, p);
- } else {
- dprintf(idx, "Invalid command password. Use %scommand password arguments\n", dcc_prefix);
- putlog(LOG_MISC, "*", "%s attempted %s%s with missing or incorrect command password", dcc[idx].nick, dcc_prefix, cmd);
- return 0;
- }
- }
- }
- #endif
- Tcl_SetVar(interp, "_dcc1", (char *) dcc[idx].nick, 0);
- Tcl_SetVar(interp, "_dcc2", (char *) s, 0);
- Tcl_SetVar(interp, "_dcc3", (char *) args, 0);
- x = check_tcl_bind(H_dcc, cmd, &fr, " $_dcc1 $_dcc2 $_dcc3",
- MATCH_PARTIAL | BIND_USE_ATTR | BIND_HAS_BUILTINS);
- if (x == BIND_AMBIGUOUS) {
- dprintf(idx, MISC_AMBIGUOUS);
- return 0;
- }
- if (x == BIND_NOMATCH) {
- dprintf(idx, "What? You need '%shelp'\n", dcc_prefix);
- return 0;
- }
- if (x == BIND_EXEC_BRK)
- return 1; /* quit */
- if (x == BIND_EXEC_LOG)
- putlog(LOG_CMDS, "*", "#%s# %s %s", dcc[idx].nick, cmd, args);
- return 0;
- }
- void check_tcl_bot(const char *nick, const char *code, const char *param)
- {
- Tcl_SetVar(interp, "_bot1", (char *) nick, 0);
- Tcl_SetVar(interp, "_bot2", (char *) code, 0);
- Tcl_SetVar(interp, "_bot3", (char *) param, 0);
- check_tcl_bind(H_bot, code, 0, " $_bot1 $_bot2 $_bot3", MATCH_EXACT);
- }
- void check_tcl_chonof(char *hand, int sock, tcl_bind_list_t *tl)
- {
- struct flag_record fr = {FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0};
- char s[11];
- struct userrec *u;
- u = get_user_by_handle(userlist, hand);
- touch_laston(u, "partyline", now);
- get_user_flagrec(u, &fr, NULL);
- Tcl_SetVar(interp, "_chonof1", (char *) hand, 0);
- egg_snprintf(s, sizeof s, "%d", sock);
- Tcl_SetVar(interp, "_chonof2", (char *) s, 0);
- check_tcl_bind(tl, hand, &fr, " $_chonof1 $_chonof2", MATCH_MASK |
- BIND_USE_ATTR | BIND_STACKABLE | BIND_WANTRET);
- }
- void check_tcl_chatactbcst(const char *from, int chan, const char *text,
- tcl_bind_list_t *tl)
- {
- char s[11];
- egg_snprintf(s, sizeof s, "%d", chan);
- Tcl_SetVar(interp, "_cab1", (char *) from, 0);
- Tcl_SetVar(interp, "_cab2", (char *) s, 0);
- Tcl_SetVar(interp, "_cab3", (char *) text, 0);
- check_tcl_bind(tl, text, 0, " $_cab1 $_cab2 $_cab3",
- MATCH_MASK | BIND_STACKABLE);
- }
- void check_tcl_nkch(const char *ohand, const char *nhand)
- {
- Tcl_SetVar(interp, "_nkch1", (char *) ohand, 0);
- Tcl_SetVar(interp, "_nkch2", (char *) nhand, 0);
- check_tcl_bind(H_nkch, ohand, 0, " $_nkch1 $_nkch2",
- MATCH_MASK | BIND_STACKABLE);
- }
- void check_tcl_link(const char *bot, const char *via)
- {
- Tcl_SetVar(interp, "_link1", (char *) bot, 0);
- Tcl_SetVar(interp, "_link2", (char *) via, 0);
- check_tcl_bind(H_link, bot, 0, " $_link1 $_link2",
- MATCH_MASK | BIND_STACKABLE);
- }
- void check_tcl_disc(const char *bot)
- {
- Tcl_SetVar(interp, "_disc1", (char *) bot, 0);
- check_tcl_bind(H_disc, bot, 0, " $_disc1", MATCH_MASK | BIND_STACKABLE);
- }
- void check_tcl_loadunld(const char *mod, tcl_bind_list_t *tl)
- {
- Tcl_SetVar(interp, "_lu1", (char *) mod, 0);
- check_tcl_bind(tl, mod, 0, " $_lu1", MATCH_MASK | BIND_STACKABLE);
- }
- const char *check_tcl_filt(int idx, const char *text)
- {
- char s[11];
- int x;
- struct flag_record fr = {FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0};
- egg_snprintf(s, sizeof s, "%ld", dcc[idx].sock);
- get_user_flagrec(dcc[idx].user, &fr, dcc[idx].u.chat->con_chan);
- Tcl_SetVar(interp, "_filt1", (char *) s, 0);
- Tcl_SetVar(interp, "_filt2", (char *) text, 0);
- x = check_tcl_bind(H_filt, text, &fr, " $_filt1 $_filt2",
- MATCH_MASK | BIND_USE_ATTR | BIND_STACKABLE |
- BIND_WANTRET | BIND_ALTER_ARGS);
- if (x == BIND_EXECUTED || x == BIND_EXEC_LOG) {
- if (interp->result == NULL || !interp->result[0])
- return "";
- else
- return interp->result;
- } else
- return text;
- }
- int check_tcl_note(const char *from, const char *to, const char *text)
- {
- int x;
- Tcl_SetVar(interp, "_note1", (char *) from, 0);
- Tcl_SetVar(interp, "_note2", (char *) to, 0);
- Tcl_SetVar(interp, "_note3", (char *) text, 0);
- x = check_tcl_bind(H_note, to, 0, " $_note1 $_note2 $_note3", MATCH_EXACT);
- return (x == BIND_MATCHED || x == BIND_EXECUTED || x == BIND_EXEC_LOG);
- }
- void check_tcl_listen(const char *cmd, int idx)
- {
- char s[11];
- int x;
- egg_snprintf(s, sizeof s, "%d", idx);
- Tcl_SetVar(interp, "_n", (char *) s, 0);
- x = Tcl_VarEval(interp, cmd, " $_n", NULL);
- if (x == TCL_ERROR)
- putlog(LOG_MISC, "*", "error on listen: %s", interp->result);
- }
- void check_tcl_chjn(const char *bot, const char *nick, int chan,
- const char type, int sock, const char *host)
- {
- struct flag_record fr = {FR_GLOBAL, 0, 0, 0, 0, 0};
- char s[11], t[2], u[11];
- t[0] = type;
- t[1] = 0;
- switch (type) {
- case '^':
- fr.global = USER_ADMIN;
- break;
- case '*':
- fr.global = USER_OWNER;
- break;
- case '+':
- fr.global = USER_MASTER;
- break;
- case '@':
- fr.global = USER_OP;
- break;
- }
- egg_snprintf(s, sizeof s, "%d", chan);
- egg_snprintf(u, sizeof u, "%d", sock);
- Tcl_SetVar(interp, "_chjn1", (char *) bot, 0);
- Tcl_SetVar(interp, "_chjn2", (char *) nick, 0);
- Tcl_SetVar(interp, "_chjn3", (char *) s, 0);
- Tcl_SetVar(interp, "_chjn4", (char *) t, 0);
- Tcl_SetVar(interp, "_chjn5", (char *) u, 0);
- Tcl_SetVar(interp, "_chjn6", (char *) host, 0);
- check_tcl_bind(H_chjn, s, &fr,
- " $_chjn1 $_chjn2 $_chjn3 $_chjn4 $_chjn5 $_chjn6",
- MATCH_MASK | BIND_STACKABLE);
- }
- void check_tcl_chpt(const char *bot, const char *hand, int sock, int chan)
- {
- char u[11], v[11];
- egg_snprintf(u, sizeof u, "%d", sock);
- egg_snprintf(v, sizeof v, "%d", chan);
- Tcl_SetVar(interp, "_chpt1", (char *) bot, 0);
- Tcl_SetVar(interp, "_chpt2", (char *) hand, 0);
- Tcl_SetVar(interp, "_chpt3", (char *) u, 0);
- Tcl_SetVar(interp, "_chpt4", (char *) v, 0);
- check_tcl_bind(H_chpt, v, 0, " $_chpt1 $_chpt2 $_chpt3 $_chpt4",
- MATCH_MASK | BIND_STACKABLE);
- }
- void check_tcl_away(const char *bot, int idx, const char *msg)
- {
- char u[11];
- egg_snprintf(u, sizeof u, "%d", idx);
- Tcl_SetVar(interp, "_away1", (char *) bot, 0);
- Tcl_SetVar(interp, "_away2", (char *) u, 0);
- Tcl_SetVar(interp, "_away3", msg ? (char *) msg : "", 0);
- check_tcl_bind(H_away, bot, 0, " $_away1 $_away2 $_away3",
- MATCH_MASK | BIND_STACKABLE);
- }
- void check_tcl_time(struct tm *tm)
- {
- char y[18];
- egg_snprintf(y, sizeof y, "%02d", tm->tm_min);
- Tcl_SetVar(interp, "_time1", (char *) y, 0);
- egg_snprintf(y, sizeof y, "%02d", tm->tm_hour);
- Tcl_SetVar(interp, "_time2", (char *) y, 0);
- egg_snprintf(y, sizeof y, "%02d", tm->tm_mday);
- Tcl_SetVar(interp, "_time3", (char *) y, 0);
- egg_snprintf(y, sizeof y, "%02d", tm->tm_mon);
- Tcl_SetVar(interp, "_time4", (char *) y, 0);
- egg_snprintf(y, sizeof y, "%04d", tm->tm_year + 1900);
- Tcl_SetVar(interp, "_time5", (char *) y, 0);
- egg_snprintf(y, sizeof y, "%02d %02d %02d %02d %04d", tm->tm_min, tm->tm_hour,
- tm->tm_mday, tm->tm_mon, tm->tm_year + 1900);
- check_tcl_bind(H_time, y, 0,
- " $_time1 $_time2 $_time3 $_time4 $_time5",
- MATCH_MASK | BIND_STACKABLE);
- }
- void check_tcl_event(const char *event)
- {
- Tcl_SetVar(interp, "_event1", (char *) event, 0);
- check_tcl_bind(H_event, event, 0, " $_event1", MATCH_EXACT | BIND_STACKABLE);
- }
- void tell_binds(int idx, char *par)
- {
- tcl_bind_list_t *tl, *tl_kind;
- tcl_bind_mask_t *tm;
- int fnd = 0, showall = 0, patmatc = 0;
- tcl_cmd_t *tc;
- char *name, *proc, *s, flg[100];
- if (par[0])
- name = newsplit(&par);
- else
- name = NULL;
- if (par[0])
- s = newsplit(&par);
- else
- s = NULL;
- if (name)
- tl_kind = find_bind_table(name);
- else
- tl_kind = NULL;
- if ((name && name[0] && !egg_strcasecmp(name, "all")) || (s && s[0] && !egg_strcasecmp(s, "all")))
- showall = 1;
- if (tl_kind == NULL && name && name[0] && egg_strcasecmp(name, "all"))
- patmatc = 1;
- dprintf(idx, MISC_CMDBINDS);
- dprintf(idx, " TYPE FLGS COMMAND HITS BINDING (TCL)\n");
- for (tl = tl_kind ? tl_kind : bind_table_list; tl;
- tl = tl_kind ? 0 : tl->next) {
- if (tl->flags & HT_DELETED)
- continue;
- for (tm = tl->first; tm; tm = tm->next) {
- if (tm->flags & TBM_DELETED)
- continue;
- for (tc = tm->first; tc; tc = tc->next) {
- if (tc->attributes & TC_DELETED)
- continue;
- proc = tc->func_name;
- build_flags(flg, &(tc->flags), NULL);
- if (showall || proc[0] != '*') {
- int ok = 0;
- if (patmatc == 1) {
- if (wild_match_per(name, tl->name) ||
- wild_match_per(name, tm->mask) ||
- wild_match_per(name, tc->func_name))
- ok = 1;
- } else
- ok = 1;
- if (ok) {
- dprintf(idx, " %-4s %-8s %-20s %4d %s\n", tl->name, flg, tm->mask,
- tc->hits, tc->func_name);
- fnd = 1;
- }
- }
- }
- }
- }
- if (!fnd) {
- if (patmatc)
- dprintf(idx, "No command bindings found that match %s\n", name);
- else if (tl_kind)
- dprintf(idx, "No command bindings for type: %s.\n", name);
- else
- dprintf(idx, "No command bindings exist.\n");
- }
- }
- /* Bring the default msg/dcc/fil commands into the Tcl interpreter */
- void add_builtins(tcl_bind_list_t *tl, cmd_t *cc)
- {
- int k, i;
- char p[1024], *l;
- cd_tcl_cmd table[2];
- table[0].name = p;
- table[0].callback = tl->func;
- table[1].name = NULL;
- for (i = 0; cc[i].name; i++) {
- egg_snprintf(p, sizeof p, "*%s:%s", tl->name,
- cc[i].funcname ? cc[i].funcname : cc[i].name);
- l = (char *) nmalloc(Tcl_ScanElement(p, &k));
- Tcl_ConvertElement(p, l, k | TCL_DONT_USE_BRACES);
- table[0].cdata = (void *)cc[i].func;
- add_cd_tcl_cmds(table);
- bind_bind_entry(tl, cc[i].flags, cc[i].name, l);
- nfree(l);
- }
- }
- void add_builtins_dcc(tcl_bind_list_t *tl, dcc_cmd_t * cc)
- {
- int k, i;
- char p[1024], *l;
- cd_tcl_cmd table[2];
- table[0].name = p;
- table[0].callback = tl->func;
- table[1].name = NULL;
- for (i = 0; cc[i].name; i++) {
- //lets add to the help system..
- cmds[cmdi].name = cc[i].name;
- cmds[cmdi].usage = cc[i].usage;
- cmds[cmdi].desc = cc[i].desc;
- cmds[cmdi].flags.match = FR_GLOBAL | FR_CHAN;
- break_down_flags(cc[i].flags, &(cmds[cmdi].flags), NULL);
- cmdi++;
- egg_snprintf(p, sizeof p, "*%s:%s", tl->name,
- cc[i].funcname ? cc[i].funcname : cc[i].name);
- l = (char *) nmalloc(Tcl_ScanElement(p, &k));
- Tcl_ConvertElement(p, l, k | TCL_DONT_USE_BRACES);
- table[0].cdata = (void *)cc[i].func;
- add_cd_tcl_cmds(table);
- bind_bind_entry(tl, cc[i].flags, cc[i].name, l);
- nfree(l);
- }
- /*
- int i;
- for (i = 0; cc[i].name; i++) {
- bind_bind_entry(table, cc[i].flags, cc[i].name, "");
- }
- */
- }
- void rem_builtins_dcc(tcl_bind_list_t *table, dcc_cmd_t *cc)
- {
- int i;
- for (i = 0; cc[i].name; i++) {
- unbind_bind_entry(table, cc[i].flags, cc[i].name, "");
- }
- }
- /* Remove the default msg/dcc/fil commands from the Tcl interpreter */
- void rem_builtins(tcl_bind_list_t *table, cmd_t *cc)
- {
- int k, i;
- char p[1024], *l;
- for (i = 0; cc[i].name; i++) {
- egg_snprintf(p, sizeof p, "*%s:%s", table->name,
- cc[i].funcname ? cc[i].funcname : cc[i].name);
- l = (char *) nmalloc(Tcl_ScanElement(p, &k));
- Tcl_ConvertElement(p, l, k | TCL_DONT_USE_BRACES);
- Tcl_DeleteCommand(interp, p);
- unbind_bind_entry(table, cc[i].flags, cc[i].name, l);
- nfree(l);
- }
- }
|