| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202 |
- /*
- * 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 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(H_dcc, C_dcc);
- Context;
- }
- void kill_bind(void)
- {
- tcl_bind_list_t *tl, *tl_next;
- rem_builtins(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;
- Context;
- 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;
- Context;
- 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];
- Context;
- 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++) {
- /* add H_dcc cmds to cmds[] :: add to the help system.. */
- if (tl == H_dcc) {
- cmds[cmdi].name = cc[i].name;
- 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);
- }
- }
- /* 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);
- }
- }
|