/* stuff for adding commands via Tcl on the fly */ #include #include #include #include "tcl.h" #include "eggdrop.h" /* types of commands */ #define CMD_MSG 0 #define CMD_DCC 1 #define CMD_FIL 2 #define CMD_PUB 3 extern Tcl_Interp *interp; extern int dcc_total; extern struct dcc_t dcc[]; /* extra commands are stored in Tcl hash tables (one hash table for each type of command: msg, dcc, etc) */ typedef struct { int flags_needed; char *func_name; } tcl_cmd_t; Tcl_HashTable H_msg, H_dcc, H_fil, H_pub; int hashtot=0; int expmem_tclhash() { return hashtot; } /* initialize hash tables */ init_hash() { Tcl_InitHashTable(&H_msg,TCL_STRING_KEYS); Tcl_InitHashTable(&H_dcc,TCL_STRING_KEYS); Tcl_InitHashTable(&H_fil,TCL_STRING_KEYS); Tcl_InitHashTable(&H_pub,TCL_STRING_KEYS); } /* fix a string so it can be passed to Tcl */ char *fixtclstr(s) char *s; { char *p,out[512]; int i=0; p=s; while (*p != 0) { switch(*p) { case ';': case '$': case '[': case ']': case '{': case '}': out[i++]='\\'; default: out[i++]=*p; } p++; } out[i]=0; return out; } /* add command (remove old one if necessary) */ int cmd_bind(typ,flags,cmd,proc) int typ,flags; char *cmd,*proc; { tcl_cmd_t *tt; int new; Tcl_HashEntry *he; Tcl_HashTable *ht; switch(typ) { case CMD_MSG: ht=&H_msg; break; case CMD_DCC: ht=&H_dcc; break; case CMD_FIL: ht=&H_fil; break; case CMD_PUB: ht=&H_pub; break; } if (proc[0]!='#') { /* not a bogus proc */ tt=(tcl_cmd_t *)nmalloc(sizeof(tcl_cmd_t)); hashtot+=sizeof(tcl_cmd_t); tt->flags_needed=flags; tt->func_name=(char *)nmalloc(strlen(proc)+1); hashtot+=strlen(proc)+1; strcpy(tt->func_name,proc); } else tt=NULL; he=Tcl_CreateHashEntry(ht,cmd,&new); if (!new) { /* remove old entry */ tcl_cmd_t *ttx=(tcl_cmd_t *)Tcl_GetHashValue(he); Tcl_DeleteHashEntry(he); hashtot-=(strlen(ttx->func_name)+1); hashtot-=sizeof(tcl_cmd_t); nfree(ttx->func_name); nfree(ttx); if (tt!=NULL) he=Tcl_CreateHashEntry(ht,cmd,&new); } if (tt!=NULL) Tcl_SetHashValue(he,tt); return 1; } /* check for tcl-bound msg command, return 1 if found */ /* msg: proc-name */ int check_tcl_msg(cmd,nick,uhost,hand,args) char *cmd,*nick,*uhost,*hand,*args; { Tcl_HashSearch srch; Tcl_HashEntry *he; int cnt=0; char *proc; tcl_cmd_t *tt; int i,ok,f=0; for (he=Tcl_FirstHashEntry(&H_msg,&srch); (he!=NULL) && (!f); he=Tcl_NextHashEntry(&srch)) { if (strncasecmp(cmd,Tcl_GetHashKey(&H_msg,he),strlen(cmd))==0) { tt=(tcl_cmd_t *)Tcl_GetHashValue(he); ok=1; for (i=1; i<=16384; i*=2) { if (tt->flags_needed & i) if (!match_attr_handle(hand,i)) ok=0; } if (ok) { cnt++; proc=tt->func_name; } if (ok) if (strcasecmp(cmd,Tcl_GetHashKey(&H_msg,he))==0) { cnt=1; f=1; /* perfect match */ } } } if (cnt>1) return 1; /* ambigious */ if (cnt==0) return 0; /* not found */ set_tcl_vars(); if (Tcl_VarEval(interp,proc," ",nick," ",uhost," ",hand," {",args,"}", NULL)==TCL_ERROR) { log(LOG_MISC,"Tcl error [%s]: %s",proc,interp->result); } else { get_tcl_vars(); if (atoi(interp->result)>0) log(LOG_CMDS,"(%s!%s) !%s! %s %s",nick,uhost,hand,cmd,args); } return 1; } /* check for tcl-bound dcc command, return 1 if found */ /* dcc: proc-name */ int check_tcl_dcc(cmd,idx,args) char *cmd,*args; int idx; { Tcl_HashSearch srch; Tcl_HashEntry *he; int cnt=0; char *proc; tcl_cmd_t *tt; int i,ok,f=0; char s[20]; for (he=Tcl_FirstHashEntry(&H_dcc,&srch); (he!=NULL) && (!f); he=Tcl_NextHashEntry(&srch)) { if (strncasecmp(cmd,Tcl_GetHashKey(&H_dcc,he),strlen(cmd))==0) { tt=(tcl_cmd_t *)Tcl_GetHashValue(he); ok=1; for (i=1; i<=16384; i*=2) { if (tt->flags_needed & i) if (!match_attr_handle(dcc[idx].nick,i)) ok=0; } if (ok) { cnt++; proc=tt->func_name; } if (ok) if (strcasecmp(cmd,Tcl_GetHashKey(&H_dcc,he))==0) { cnt=1; f=1; /* perfect match */ } } } if (cnt>1) { tprintf(dcc[idx].sock,"Ambigious command.\n"); return 1; } if (cnt==0) return 0; /* not found */ set_tcl_vars(); sprintf(s,"%d",idx); if (Tcl_VarEval(interp,proc," ",dcc[idx].nick," ",s," {",args,"}",NULL) ==TCL_ERROR) { log(LOG_MISC,"Tcl error [%s]: %s",proc,interp->result); } else { get_tcl_vars(); if (atoi(interp->result)>0) log(LOG_CMDS,"#%s# %s %s",dcc[idx].nick,cmd,args); } return 1; } /* check for tcl-bound file command, return 1 if found */ /* fil: proc-name */ int check_tcl_fil(cmd,idx,args) char *cmd,*args; int idx; { Tcl_HashSearch srch; Tcl_HashEntry *he; int cnt=0; char *proc; tcl_cmd_t *tt; int i,ok,f=0; char s[20]; for (he=Tcl_FirstHashEntry(&H_fil,&srch); (he!=NULL) && (!f); he=Tcl_NextHashEntry(&srch)) { if (strncasecmp(cmd,Tcl_GetHashKey(&H_fil,he),strlen(cmd))==0) { tt=(tcl_cmd_t *)Tcl_GetHashValue(he); ok=1; for (i=1; i<=16384; i*=2) { if (tt->flags_needed & i) if (!match_attr_handle(dcc[idx].nick,i)) ok=0; } if (ok) { cnt++; proc=tt->func_name; } if (ok) if (strcasecmp(cmd,Tcl_GetHashKey(&H_fil,he))==0) { cnt=1; f=1; /* perfect match */ } } } if (cnt>1) { tprintf(dcc[idx].sock,"Ambigious command.\n"); return 1; } if (cnt==0) return 0; /* not found */ set_tcl_vars(); sprintf(s,"%d",idx); if (Tcl_VarEval(interp,proc," ",dcc[idx].nick," ",s," {",args,"}") ==TCL_ERROR) { log(LOG_MISC,"Tcl error [%s]: %s",proc,interp->result); } else { get_tcl_vars(); if (atoi(interp->result)>0) log(LOG_CMDS,"#%s# files: %s %s",dcc[idx].nick,cmd,args); } return 1; } int check_tcl_pub(nick,from,msg) char *nick,*from,*msg; { char s[20],args[512],cmd[512],handle[21],host[161]; Tcl_HashSearch srch; Tcl_HashEntry *he; int i,ok,f=0; tcl_cmd_t *tt; char *proc; strcpy(args,msg); nsplit(cmd,args); sprintf(host,"%s!%s",nick,from); get_handle_by_host(handle,host); for (he=Tcl_FirstHashEntry(&H_pub,&srch); (he!=NULL) && (!f); he=Tcl_NextHashEntry(&srch)) { if (strcasecmp(cmd,Tcl_GetHashKey(&H_pub,he))==0) { tt=(tcl_cmd_t *)Tcl_GetHashValue(he); ok=1; for (i=1; i<=16384; i*=2) { if (tt->flags_needed & i) if (!match_attr_handle(handle,i)) ok=0; } if (ok) { f=1; proc=tt->func_name; } } } if (!f) return 0; /* not found */ set_tcl_vars(); if (Tcl_VarEval(interp,proc," ",nick," ",from," ",handle," {",args,"}", NULL)==TCL_ERROR) { log(LOG_MISC,"Tcl error [%s]: %s",proc,interp->result); } else { get_tcl_vars(); if (atoi(interp->result)>0) log(LOG_CMDS,"<<%s>> !%s! %s %s",nick,handle,cmd,args); } return 1; } void tell_binds(z) int z; { Tcl_HashEntry *he; Tcl_HashSearch srch; Tcl_HashTable *ht; int i,fnd=0; tcl_cmd_t *tt; char *proc,*typ,flg[20]; for (i=0; i<4; i++) { switch (i) { case 0: ht=&H_msg; typ="msg"; break; case 1: ht=&H_dcc; typ="dcc"; break; case 2: ht=&H_fil; typ="fil"; break; case 3: ht=&H_pub; typ="pub"; break; } for (he=Tcl_FirstHashEntry(ht,&srch); (he!=NULL); he=Tcl_NextHashEntry(&srch)) { if (!fnd) { tprintf(z,"Command bindings:\n"); fnd=1; tprintf(z," TYPE FLGS COMMAND BINDING (TCL)\n"); } tt=(tcl_cmd_t *)Tcl_GetHashValue(he); flags2str(tt->flags_needed,flg); tprintf(z," %s %-4s %-20s %s\n",typ,flg,Tcl_GetHashKey(&H_pub,he), tt->func_name); } } if (!fnd) tprintf(z,"No command bindings.\n"); }