/* this file is only used if you are linking in Tcl */ #if HAVE_CONFIG_H #include #endif #include #include #include #include #include "../lush.h" #include "users.h" #include "eggdrop.h" #include "chan.h" #include "proto.h" #include "tclegg.h" /* eggdrop always uses the same interpreter */ Tcl_Interp *interp; extern int curserv, helpserv, serv, helpsock; extern int shtime, op_on_join, revenge, greet, learn_users, require_x, enforce_bans, share_users, use_info, passive, strict_host, require_p, isolate, keep_all_logs, raw_files, perm_bans, clearbans, chan_updates, use_stderr, upload_to_cd, bitch, never_give_up, protect_ops, allow_new_telnets, forbid_bans, keepnick; extern int telnet_port, botserverport, min_servs, helpserverport, default_flags, conmask, newserverport, idle_kick, dcc_block, dcc_limit, dcc_maxsize, dcc_users; extern char *logfile[]; extern int logmask[]; extern int flood_thr, flood_pub_thr, flood_join_thr, ban_time, ignore_time; extern char botname[], origbotname[], botuser[], botrealname[], botserver[], botchan[], dccdir[], dccin[], motdfile[], admin[], userfile[], helpbot[], helpserver[], helpdir[], initserver[], chankey[], notify_new[], notefile[], curchan[], botuserhost[], tempdir[], newserver[], textdir[], ctcp_version[], ctcp_finger[], ctcp_userinfo[], owner[], newserverpass[], need_op[], need_invite[]; extern char flag1, flag2, flag3, flag4, flag5, flag6, flag7, flag8, flag9, flag0; extern char cx_file[]; extern int cx_line; extern struct chan_t channel; extern int online; extern struct userrec *userlist; extern struct eggqueue *serverlist; extern struct dcc_t dcc[]; extern int dcc_total; /* initialize to no timers */ tcl_timer_t *timer=NULL; /* next timer will have this number */ unsigned long timer_id=1; /* prototypes for tcl */ Tcl_Interp *Tcl_CreateInterp(); void set_tcl_vars(); void get_tcl_vars(); int expmem_tcl() { int i,tot=0; tcl_timer_t *t=timer; for (i=0; icmd)+1; t=t->next; } return tot; } /***********************************************************************/ /* brief venture into timers */ /* add a timer */ unsigned long add_timer(mins,cmd,prev_id) int mins; char *cmd; unsigned long prev_id; { tcl_timer_t *old=timer; timer=(tcl_timer_t *)nmalloc(sizeof(tcl_timer_t)); timer->next=old; timer->mins=mins; timer->cmd=(char *)nmalloc(strlen(cmd)+1); strcpy(timer->cmd,cmd); /* if it's just being added back and already had an id, don't */ /* create a new one */ if (prev_id>0) timer->id=prev_id; else timer->id=timer_id++; return timer->id; } /* remove a timer, by id */ int remove_timer(id) unsigned long id; { tcl_timer_t *mark=timer,*old; int ok=0; context; timer=NULL; while (mark!=NULL) { if (mark->id != id) add_timer(mark->mins,mark->cmd,mark->id); else ok++; old=mark; mark=mark->next; nfree(old->cmd); nfree(old); } return ok; } /* check timers, execute the ones that have expired */ void check_timers() { tcl_timer_t *mark=timer,*old; context; /* new timers could be added by a Tcl script inside a current timer */ /* so we just clear out the timer list completely, and any unexpired */ /* timers, we'll just add back */ timer=NULL; while (mark!=NULL) { mark->mins--; if (mark->mins == 0) { int code; set_tcl_vars(); code=Tcl_Eval(interp,mark->cmd); if (code!=TCL_OK) log(LOG_MISC,"(Timer) Error for '%s': %s",mark->cmd,interp->result); get_tcl_vars(); } else add_timer(mark->mins,mark->cmd,mark->id); context; old=mark; mark=mark->next; nfree(old->cmd); nfree(old); } } /* return list of timers */ void list_timers(irp) Tcl_Interp *irp; { tcl_timer_t *mark=timer; char s[512]; while (mark!=NULL) { sprintf(s,"%u %s timer%lu",mark->mins,mark->cmd,mark->id); Tcl_AppendElement(irp,s); mark=mark->next; } } /***********************************************************************/ #define STDVAR (cd,irp,argc,argv) \ ClientData cd; Tcl_Interp *irp; int argc; char *argv[]; #define BADARGS(nl,nh,example) \ if ((argc<(nl)) || (argc>(nh))) { \ Tcl_AppendResult(irp,"wrong # args: should be \"",argv[0], \ (example),"\"",NULL); \ return TCL_ERROR; \ } int tcl_logfile STDVAR { int i,lmask; char s[151],*lfile; BADARGS(1,3," ??logModes? logFile?"); if (argc==1) { /* they just want a list of the logfiles and modes */ for (i=0; inick[0]) { Tcl_AppendElement(irp,m->nick); m=m->next; } return TCL_OK; } int tcl_putserv STDVAR { BADARGS(2,2," text"); mprintf(serv,"%s\n",argv[1]); return TCL_OK; } int tcl_puthelp STDVAR { BADARGS(2,2," text"); if (helpbot[0]) hprintf(helpsock,"%s\n",argv[1]); else mprintf(serv,"%s\n",argv[1]); return TCL_OK; } int findidx(z) int z; { int j; for (j=0; j510) argv[2][510]=0; /* restrict length of cmd */ if (got_dcc_cmd(idx,argv[2])) { dcc_activity(dcc[idx].sock,".quit",5); } return TCL_OK; } int tcl_addhost STDVAR { BADARGS(3,3," handle hostmask"); addhost_by_handle(argv[1],argv[2]); return TCL_OK; } int tcl_delhost STDVAR { BADARGS(3,3," handle hostmask"); if (delhost_by_handle(argv[1],argv[2])) { Tcl_AppendResult(irp,"1",NULL); return TCL_OK; } Tcl_AppendResult(irp,"0",NULL); return TCL_OK; } int tcl_timer STDVAR { unsigned long x; char s[41]; BADARGS(3,3," minutes command"); if (atoi(argv[1]) <= 0) { Tcl_AppendResult(irp,"time value must be positive, nonzero",NULL); return TCL_ERROR; } if (argv[2][0]!='#') { x=add_timer(atoi(argv[1]),argv[2],0L); sprintf(s,"timer%lu",x); Tcl_AppendResult(irp,s,NULL); } return TCL_OK; } int tcl_killtimer STDVAR { BADARGS(2,2," timerID"); if (strncmp(argv[1],"timer",5)!=0) { Tcl_AppendResult(irp,"argument is not a timerID",NULL); return TCL_ERROR; } if (remove_timer(atol(&argv[1][5]))) return TCL_OK; Tcl_AppendResult(irp,"invalid timerID",NULL); return TCL_ERROR; } int tcl_unixtime STDVAR { char s[20]; time_t t; BADARGS(1,1,""); t=time(NULL); sprintf(s,"%lu",(unsigned long)t); Tcl_AppendResult(irp,s,NULL); return TCL_OK; } int tcl_time STDVAR { char s[81]; time_t t; BADARGS(1,1,""); t=time(NULL); strcpy(s,ctime(&t)); strcpy(s,&s[11]); s[5]=0; Tcl_AppendResult(irp,s,NULL); return TCL_OK; } int tcl_date STDVAR { char s[81]; time_t t; BADARGS(1,1,""); t=time(NULL); strcpy(s,ctime(&t)); s[10]=s[24]=0; strcpy(s,&s[8]); strcpy(&s[8],&s[20]); strcpy(&s[2],&s[3]); Tcl_AppendResult(irp,s,NULL); return TCL_OK; } int tcl_getinfo STDVAR { char s[161]; BADARGS(2,2," handle"); get_handle_info(argv[1],s); Tcl_AppendResult(irp,s,NULL); return TCL_OK; } int tcl_getdccdir STDVAR { char s[161]; BADARGS(2,2," handle"); get_handle_dccdir(argv[1],s); Tcl_AppendResult(irp,s,NULL); return TCL_OK; } int tcl_getcomment STDVAR { char s[161]; BADARGS(2,2," handle"); get_handle_comment(argv[1],s); Tcl_AppendResult(irp,s,NULL); return TCL_OK; } int tcl_getemail STDVAR { char s[161]; BADARGS(2,2," handle"); get_handle_email(argv[1],s); Tcl_AppendResult(irp,s,NULL); return TCL_OK; } int tcl_getxtra STDVAR { char s[513]; BADARGS(2,2," handle"); get_handle_xtra(argv[1],s); Tcl_AppendResult(irp,s,NULL); return TCL_OK; } int tcl_setinfo STDVAR { BADARGS(3,3," handle info"); set_handle_info(userlist,argv[1],argv[2]); return TCL_OK; } int tcl_setdccdir STDVAR { BADARGS(3,3," handle dccdir"); set_handle_dccdir(userlist,argv[1],argv[2]); return TCL_OK; } int tcl_setcomment STDVAR { BADARGS(3,3," handle comment"); set_handle_comment(userlist,argv[1],argv[2]); return TCL_OK; } int tcl_setemail STDVAR { BADARGS(3,3," handle email"); set_handle_email(userlist,argv[1],argv[2]); return TCL_OK; } int tcl_setxtra STDVAR { BADARGS(3,3," handle xtra"); set_handle_xtra(userlist,argv[1],argv[2]); return TCL_OK; } int tcl_delban STDVAR { BADARGS(2,2," ban"); if (unprog_ban(argv[1])>0) Tcl_AppendResult(irp,"1",NULL); else Tcl_AppendResult(irp,"0",NULL); return TCL_OK; } int tcl_isban STDVAR { BADARGS(2,2," ban"); if (equals_ban(argv[1])) Tcl_AppendResult(irp,"1",NULL); else Tcl_AppendResult(irp,"0",NULL); return TCL_OK; } int tcl_ispermban STDVAR { BADARGS(2,2," ban"); if (equals_ban(argv[1])==2) Tcl_AppendResult(irp,"1",NULL); else Tcl_AppendResult(irp,"0",NULL); return TCL_OK; } int tcl_matchban STDVAR { BADARGS(2,2," user!nick@host"); if (match_ban(argv[1])) Tcl_AppendResult(irp,"1",NULL); else Tcl_AppendResult(irp,"0",NULL); return TCL_OK; } int tcl_addban STDVAR { time_t t=time(NULL); char ban[161]; BADARGS(2,3," ban ?comment?"); if (strlen(argv[1])>160) argv[1][160]=0; strcpy(ban,argv[1]); if (argc==2) { /* no comment */ prog_ban(ban,t,""); if (me_op()) { add_mode('+','b',argv[1]); recheck_channel(); } } else { if (strlen(argv[2])>70) argv[2][70]=0; prog_ban(ban,t,argv[2]); if (me_op()) { add_mode('+','b',argv[1]); recheck_channel(); } } return TCL_OK; } int tcl_addpermban STDVAR { char ban[161]; BADARGS(2,3," ban ?comment?"); if (strlen(argv[1])>160) argv[1][160]=0; strcpy(ban,argv[1]); if (argc==2) prog_ban(ban,0L,""); else { if (strlen(argv[2])>70) argv[2][70]=0; prog_ban(ban,0L,argv[2]); } if (me_op()) { add_mode('+','b',ban); recheck_channel(); } return TCL_OK; } int tcl_getlaston STDVAR { char s[21]; time_t t; BADARGS(2,2," handle"); get_handle_laston(argv[1],&t); sprintf(s,"%lu",t); Tcl_AppendResult(irp,s,NULL); return TCL_OK; } int tcl_timers STDVAR { BADARGS(1,1,""); list_timers(irp); return TCL_OK; } int tcl_jump STDVAR { BADARGS(1,4," ?server? ?port? ?pass?"); if (argc>=2) { strcpy(newserver,argv[1]); if (argc>=3) newserverport=atoi(argv[2]); else newserverport=6667; if (argc==4) strcpy(newserverpass,argv[3]); } tprintf(serv,"QUIT :jumping\n"); sleep(1); close(serv); serv=(-1); return TCL_OK; } int tcl_ctime STDVAR { time_t tt; char s[81]; BADARGS(2,2," unixtime"); tt=(time_t)atol(argv[1]); strcpy(s,ctime(&tt)); s[strlen(s)-1]=0; Tcl_AppendResult(irp,s,NULL); return TCL_OK; } int tcl_myip STDVAR { char s[21]; BADARGS(1,1,""); sprintf(s,"%lu",getmyip()); Tcl_AppendResult(irp,s,NULL); return TCL_OK; } int tcl_dccsend STDVAR { char s[5],sys[512],*nfn; int i; FILE *f; BADARGS(3,3," filename ircnick"); f=fopen(argv[1],"r"); if (f==NULL) { /* file not found */ Tcl_AppendResult(irp,"3",NULL); return TCL_OK; } fclose(f); nfn=strrchr(argv[1],'/'); if (nfn==NULL) nfn=argv[1]; else nfn++; if (at_limit(argv[2])) { /* queue that mother */ if (nfn==argv[1]) queue_file("*",nfn,"(script)",argv[2]); else { nfn--; *nfn=0; nfn++; sprintf(sys,"*%s",argv[1]); queue_file(sys,nfn,"(script)",argv[2]); } Tcl_AppendResult(irp,"4",NULL); return TCL_OK; } sprintf(sys,"%s%s",tempdir,nfn); /* new filename, in /tmp */ copyfile(argv[1],sys); i=raw_dcc_send(sys,argv[2],"*",argv[1]); sprintf(s,"%d",i); Tcl_AppendResult(irp,s,NULL); return TCL_OK; } /*int tcl_rehash STDVAR { BADARGS(1,1,""); rehash(); return TCL_OK; }*/ int tcl_rand STDVAR { unsigned long x; char s[41]; BADARGS(2,2," limit"); x=random()%(atol(argv[1])); sprintf(s,"%lu",x); Tcl_AppendResult(irp,s,NULL); return TCL_OK; } int tcl_dccbroadcast STDVAR { char msg[401]; BADARGS(2,2," message"); strncpy(msg,argv[1],400); msg[400]=0; chatout("*** %s\n",msg); tandout("chat %s %s\n",origbotname,msg); return TCL_OK; } int tcl_hand2idx STDVAR { int i; char s[10]; BADARGS(2,2," nickname"); for (i=0; iu.chat->channel); else sprintf(s,"%d",dcc[idx].u.chat->channel); Tcl_AppendResult(irp,s,NULL); return TCL_OK; } int tcl_setchan STDVAR { int idx,i,chan; BADARGS(3,3," idx channel"); i=atoi(argv[1]); idx=findidx(i); if (idx<0) { Tcl_AppendResult(irp,"invalid idx",NULL); return TCL_ERROR; } if ((dcc[idx].type!=DCC_CHAT) && (dcc[idx].type!=DCC_SCRIPT)) { Tcl_AppendResult(irp,"invalid idx",NULL); return TCL_ERROR; } if ((argv[2][0]<'0') || (argv[2][0]>'9')) { chan=get_assoc(argv[2]); if (chan<0) { Tcl_AppendResult(irp,"channel name is invalid",NULL); return TCL_ERROR; } } else chan=atoi(argv[2]); if ((chan<-1) || (chan>99999)) { Tcl_AppendResult(irp,"channel out of range; must be -1 thru 99999",NULL); return TCL_ERROR; } if (dcc[idx].type==DCC_SCRIPT) dcc[idx].u.script->u.chat->channel=chan; else dcc[idx].u.chat->channel=chan; return TCL_OK; } int tcl_dccputchan STDVAR { int chan; char msg[401]; BADARGS(3,3," channel message"); chan=atoi(argv[1]); if ((chan<0) || (chan>99999)) { Tcl_AppendResult(irp,"channel out of range; must be 0 thru 99999",NULL); return TCL_ERROR; } strncpy(msg,argv[2],400); msg[400]=0; chanout2(chan,"%s\n",argv[2]); return TCL_OK; } int tcl_console STDVAR { int i,j,pls; BADARGS(2,3," idx ?console-modes?"); j=atoi(argv[1]); i=findidx(j); if (i<0) { Tcl_AppendResult(irp,"invalid idx",NULL); return TCL_ERROR; } if (dcc[i].type!=DCC_CHAT) { Tcl_AppendResult(irp,"invalid idx",NULL); return TCL_ERROR; } if (argc==3) { pls=1; if ((argv[2][0]!='+') && (argv[2][0]!='-')) dcc[i].u.chat->con_flags=0; for (j=0; jcon_flags|=logmodes(s); else dcc[i].u.chat->con_flags&=~logmodes(s); } } } Tcl_AppendResult(irp,masktype(dcc[i].u.chat->con_flags),NULL); return TCL_OK; } int tcl_control STDVAR { int idx,i; BADARGS(3,3," idx command"); i=atoi(argv[1]); idx=findidx(i); if (idx<0) { Tcl_AppendResult(irp,"invalid idx",NULL); return TCL_ERROR; } if ((dcc[idx].type==DCC_CHAT) && (dcc[idx].u.chat->channel >= 0)) chanout2_but(idx,dcc[idx].u.chat->channel,"%s has gone.\n",dcc[idx].nick); set_script(idx); strncpy(dcc[idx].u.script->command,argv[2],120); dcc[idx].u.script->command[119]=0; return TCL_OK; } int tcl_killdcc STDVAR { int idx,i; BADARGS(2,2," idx"); i=atoi(argv[1]); idx=findidx(i); if (idx<0) { Tcl_AppendResult(irp,"invalid idx",NULL); return TCL_ERROR; } close(dcc[idx].sock); lostdcc(idx); return TCL_OK; } int tcl_putbot STDVAR { int i; char msg[401]; BADARGS(3,3," botnick message"); i=nextbot(argv[1]); if (i<0) { Tcl_AppendResult(irp,"bot is not in the chain",NULL); return TCL_ERROR; } strncpy(msg,argv[2],400); msg[400]=0; tprintf(dcc[i].sock,"zapf %s %s %s\n",origbotname,argv[1],msg); return TCL_OK; } int tcl_putallbots STDVAR { char msg[401]; BADARGS(2,2," message"); strncpy(msg,argv[1],400); msg[400]=0; tandout("zapf-broad %s %s\n",origbotname,msg); return TCL_OK; } int tcl_getchanidle STDVAR { memberlist *m=channel.member; time_t now=time(NULL); BADARGS(2,2," nickname"); while (m->nick[0]) { if (strcasecmp(m->nick,argv[1])==0) { char s[20]; int x; x=(now-(m->last))/60; sprintf(s,"%d",x); Tcl_AppendResult(irp,s,NULL); return TCL_OK; } m=m->next; } Tcl_AppendResult(irp,"0",NULL); return TCL_OK; } int tcl_idx2hand STDVAR { int i,idx; BADARGS(2,2," idx"); i=atoi(argv[1]); idx=findidx(i); if (idx<0) { Tcl_AppendResult(irp,"invalid idx",NULL); return TCL_ERROR; } Tcl_AppendResult(irp,dcc[idx].nick,NULL); return TCL_OK; } int tcl_userlist STDVAR { struct userrec *u=userlist; int f=0; BADARGS(1,2," ?flags?"); if (argc==2) f=str2flags(argv[1]); while (u!=NULL) { if ((u->flags & f)==f) Tcl_AppendElement(interp,u->handle); u=u->next; } return TCL_OK; } int tcl_sendnote STDVAR { char s[5]; BADARGS(4,4," from to message"); if (strlen(argv[1])>20) argv[1][20]=0; if (strlen(argv[2])>20) argv[2][20]=0; sprintf(s,"%d",add_note(argv[2],argv[1],argv[3],-1,0)); Tcl_AppendResult(irp,s,NULL); return TCL_OK; } int tcl_save STDVAR { write_userfile(); return TCL_OK; } int tcl_bots STDVAR { int i; BADARGS(1,1,""); for (i=0; iban[0]) { Tcl_AppendElement(irp,b->ban); b=b->next; } return TCL_OK; } /**********************************************************************/ /* called when some script tries to change flag1..flag7 */ /* (possible that the new value will be invalid, so we ignore the change) */ char *tcl_chflag(cdata,irp,name1,name2,flags) ClientData cdata; Tcl_Interp *irp; char *name1,*name2; int flags; { char s[2],*p; p=Tcl_GetVar(irp,name1,TCL_GLOBAL_ONLY); if (p==NULL) return NULL; s[0]=(*p); s[1]=0; switch ((int)cdata) { case 1: if ( !(str2flags(s) & ~USER_FLAG1) || (!(str2flags(s) & ~USER_FELLOW)) ) flag1=s[0]; else s[0]=flag1; break; case 2: if ( !(str2flags(s) & ~USER_FLAG2) || (!(str2flags(s) & ~USER_UNBAN)) ) flag2=s[0]; else s[0]=flag2; break; case 3: if (!(str2flags(s) & ~USER_FLAG3)) flag3=s[0]; else s[0]=flag3; break; case 4: if (!(str2flags(s) & ~USER_FLAG4)) flag4=s[0]; else s[0]=flag4; break; case 5: if (!(str2flags(s) & ~USER_FLAG5)) flag5=s[0]; else s[0]=flag5; break; case 6: if (!(str2flags(s) & ~USER_FLAG6)) flag6=s[0]; else s[0]=flag6; break; case 7: if (!(str2flags(s) & ~USER_FLAG7)) flag7=s[0]; else s[0]=flag7; break; case 8: if (!(str2flags(s) & ~USER_FLAG8)) flag8=s[0]; else s[0]=flag8; break; case 9: if (!(str2flags(s) & ~USER_FLAG9)) flag9=s[0]; else s[0]=flag9; break; case 0: if (!(str2flags(s) & ~USER_FLAG0)) flag0=s[0]; else s[0]=flag0; break; } Tcl_SetVar(irp,name1,s,TCL_GLOBAL_ONLY); return NULL; } /* parse the 'servers' variable */ /* save and re-set the values of curserv and helpserv */ void get_tcl_servers() { int i,lc,code; char **list; char *serv; wipe_serverlist(); serv=Tcl_GetVar(interp,"servers",TCL_GLOBAL_ONLY); if (serv==NULL) { curserv=0; helpserv=0; return; } code=Tcl_SplitList(interp,serv,&lc,&list); if (code==TCL_ERROR) { log(LOG_MISC,"Tcl error parsing server list:"); log(LOG_MISC,"%s",interp->result); return; } for (i=0; i' */ curserv=(-1); helpserv=(-1); if (botserver[0]) next_server(&curserv,botserver,&botserverport,""); if (helpserver[0]) next_server(&helpserv,helpserver,&helpserverport,""); } /* weird, weird, weird... */ void set_tcl_servers() { Tcl_DString ds; char *slist; struct eggqueue *q; Tcl_DStringInit(&ds); q=serverlist; while (q!=NULL) { Tcl_DStringAppendElement(&ds,q->item); q=q->next; } slist=Tcl_DStringValue(&ds); Tcl_SetVar(interp,"servers",slist,TCL_GLOBAL_ONLY); Tcl_DStringFree(&ds); } void tcl_bool(var,val) char *var; int *val; { char *s; s=Tcl_GetVar(interp,var,TCL_GLOBAL_ONLY); if (s!=NULL) { if (Tcl_ExprBoolean(interp,s,val)==TCL_ERROR) { log(LOG_MISC,"Tcl error evaluating %s:",var); log(LOG_MISC,"%s",interp->result); } } } void tcl_setbool(var,val) char *var; int val; { char s[2]; s[1]=0; s[0]=(val?'1':'0'); Tcl_SetVar(interp,var,s,TCL_GLOBAL_ONLY); } void tcl_int(var,val) char *var; int *val; { char *s; long l; s=Tcl_GetVar(interp,var,TCL_GLOBAL_ONLY); if (s!=NULL) { if (Tcl_ExprLong(interp,s,&l)==TCL_ERROR) { log(LOG_MISC,"Tcl error evaluating %s:",var); log(LOG_MISC,"%s",interp->result); } } *val=(int)l; } void tcl_setint(var,val) char *var; int val; { char s[40]; sprintf(s,"%d",val); Tcl_SetVar(interp,var,s,TCL_GLOBAL_ONLY); } void tcl_str(var,val,max) char *var,*val; int max; { char *s; s=Tcl_GetVar(interp,var,TCL_GLOBAL_ONLY); if (s!=NULL) { if (strlen(s)>max) s[max]=0; strcpy(val,s); } } void tcl_setstr(var,val) char *var,*val; { Tcl_SetVar(interp,var,val,TCL_GLOBAL_ONLY); } void tcl_char(var,val) char *var,*val; { char *s; s=Tcl_GetVar(interp,var,TCL_GLOBAL_ONLY); if (s!=NULL) *val=s[0]; } void tcl_setchar(var,val) char *var,val; { char s[2]; s[0]=val; s[1]=0; Tcl_SetVar(interp,var,s,TCL_GLOBAL_ONLY); } /* not going through Tcl's crazy main() system (what on earth was he smoking?!) so we gotta initialize the Tcl interpreter */ void init_tcl() { /* initialize the interpreter */ interp=Tcl_CreateInterp(); Tcl_Init(interp); init_hash(); init_builtins(); /* see note (1) at the bottom of this file */ /* Tcl_DeleteCommand(interp,"exec"); */ /* put traces on the 5 flag variables */ tcl_setchar("flag1",flag1); tcl_setchar("flag2",flag2); tcl_setchar("flag3",flag3); tcl_setchar("flag4",flag4); tcl_setchar("flag5",flag5); tcl_setchar("flag6",flag6); tcl_setchar("flag7",flag7); tcl_setchar("flag8",flag8); tcl_setchar("flag9",flag9); tcl_setchar("flag0",flag0); Tcl_TraceVar(interp,"flag1",TCL_TRACE_WRITES,tcl_chflag,(ClientData)1); Tcl_TraceVar(interp,"flag2",TCL_TRACE_WRITES,tcl_chflag,(ClientData)2); Tcl_TraceVar(interp,"flag3",TCL_TRACE_WRITES,tcl_chflag,(ClientData)3); Tcl_TraceVar(interp,"flag4",TCL_TRACE_WRITES,tcl_chflag,(ClientData)4); Tcl_TraceVar(interp,"flag5",TCL_TRACE_WRITES,tcl_chflag,(ClientData)5); Tcl_TraceVar(interp,"flag6",TCL_TRACE_WRITES,tcl_chflag,(ClientData)6); Tcl_TraceVar(interp,"flag7",TCL_TRACE_WRITES,tcl_chflag,(ClientData)7); Tcl_TraceVar(interp,"flag8",TCL_TRACE_WRITES,tcl_chflag,(ClientData)8); Tcl_TraceVar(interp,"flag9",TCL_TRACE_WRITES,tcl_chflag,(ClientData)9); Tcl_TraceVar(interp,"flag0",TCL_TRACE_WRITES,tcl_chflag,(ClientData)0); /* add new commands */ Tcl_CreateCommand(interp,"logfile",tcl_logfile,NULL,NULL); Tcl_CreateCommand(interp,"putserv",tcl_putserv,NULL,NULL); Tcl_CreateCommand(interp,"puthelp",tcl_puthelp,NULL,NULL); Tcl_CreateCommand(interp,"putdcc",tcl_putdcc,NULL,NULL); Tcl_CreateCommand(interp,"puterror",tcl_putlog, (ClientData)(LOG_MISC|LOG_CHAN),NULL); Tcl_CreateCommand(interp,"putlog",tcl_putlog,(ClientData)LOG_MISC,NULL); Tcl_CreateCommand(interp,"putcmdlog",tcl_putlog,(ClientData)LOG_CMDS,NULL); Tcl_CreateCommand(interp,"putxferlog",tcl_putlog,(ClientData)LOG_FILES,NULL); Tcl_CreateCommand(interp,"countusers",tcl_countusers,NULL,NULL); Tcl_CreateCommand(interp,"validuser",tcl_validuser,NULL,NULL); Tcl_CreateCommand(interp,"finduser",tcl_finduser,NULL,NULL); Tcl_CreateCommand(interp,"passwdOk",tcl_passwdOk,NULL,NULL); Tcl_CreateCommand(interp,"passwdok",tcl_passwdOk,NULL,NULL); Tcl_CreateCommand(interp,"chattr",tcl_chattr,NULL,NULL); Tcl_CreateCommand(interp,"matchattr",tcl_matchattr,NULL,NULL); Tcl_CreateCommand(interp,"botisop",tcl_botisop,NULL,NULL); Tcl_CreateCommand(interp,"isop",tcl_isop,NULL,NULL); Tcl_CreateCommand(interp,"onchan",tcl_onchan,NULL,NULL); Tcl_CreateCommand(interp,"handonchan",tcl_handonchan,NULL,NULL); Tcl_CreateCommand(interp,"ischanban",tcl_ischanban,NULL,NULL); Tcl_CreateCommand(interp,"getchanhost",tcl_getchanhost,NULL,NULL); Tcl_CreateCommand(interp,"onchanSplit",tcl_onchanSplit,NULL,NULL); Tcl_CreateCommand(interp,"onchansplit",tcl_onchanSplit,NULL,NULL); Tcl_CreateCommand(interp,"chanlist",tcl_chanlist,NULL,NULL); Tcl_CreateCommand(interp,"bind",tcl_bind,(ClientData)0,NULL); Tcl_CreateCommand(interp,"unbind",tcl_bind,(ClientData)1,NULL); Tcl_CreateCommand(interp,"adduser",tcl_adduser,NULL,NULL); Tcl_CreateCommand(interp,"maskhost",tcl_maskhost,NULL,NULL); Tcl_CreateCommand(interp,"dccSimul",tcl_dccsimul,NULL,NULL); Tcl_CreateCommand(interp,"dccsimul",tcl_dccsimul,NULL,NULL); Tcl_CreateCommand(interp,"addhost",tcl_addhost,NULL,NULL); Tcl_CreateCommand(interp,"delhost",tcl_delhost,NULL,NULL); Tcl_CreateCommand(interp,"timer",tcl_timer,NULL,NULL); Tcl_CreateCommand(interp,"killtimer",tcl_killtimer,NULL,NULL); Tcl_CreateCommand(interp,"unixtime",tcl_unixtime,NULL,NULL); Tcl_CreateCommand(interp,"time",tcl_time,NULL,NULL); Tcl_CreateCommand(interp,"date",tcl_date,NULL,NULL); Tcl_CreateCommand(interp,"getinfo",tcl_getinfo,NULL,NULL); Tcl_CreateCommand(interp,"getdccdir",tcl_getdccdir,NULL,NULL); Tcl_CreateCommand(interp,"getcomment",tcl_getcomment,NULL,NULL); Tcl_CreateCommand(interp,"getemail",tcl_getemail,NULL,NULL); Tcl_CreateCommand(interp,"getxtra",tcl_getxtra,NULL,NULL); Tcl_CreateCommand(interp,"setinfo",tcl_setinfo,NULL,NULL); Tcl_CreateCommand(interp,"setdccdir",tcl_setdccdir,NULL,NULL); Tcl_CreateCommand(interp,"setcomment",tcl_setcomment,NULL,NULL); Tcl_CreateCommand(interp,"setemail",tcl_setemail,NULL,NULL); Tcl_CreateCommand(interp,"setxtra",tcl_setxtra,NULL,NULL); Tcl_CreateCommand(interp,"delban",tcl_delban,NULL,NULL); Tcl_CreateCommand(interp,"isban",tcl_isban,NULL,NULL); Tcl_CreateCommand(interp,"ispermban",tcl_ispermban,NULL,NULL); Tcl_CreateCommand(interp,"matchban",tcl_matchban,NULL,NULL); Tcl_CreateCommand(interp,"addban",tcl_addban,NULL,NULL); Tcl_CreateCommand(interp,"addpermban",tcl_addpermban,NULL,NULL); Tcl_CreateCommand(interp,"getlaston",tcl_getlaston,NULL,NULL); Tcl_CreateCommand(interp,"timers",tcl_timers,NULL,NULL); Tcl_CreateCommand(interp,"jump",tcl_jump,NULL,NULL); Tcl_CreateCommand(interp,"ctime",tcl_ctime,NULL,NULL); Tcl_CreateCommand(interp,"myip",tcl_myip,NULL,NULL); Tcl_CreateCommand(interp,"dccsend",tcl_dccsend,NULL,NULL); /* Tcl_CreateCommand(interp,"rehash",tcl_rehash,NULL,NULL); */ Tcl_CreateCommand(interp,"rand",tcl_rand,NULL,NULL); Tcl_CreateCommand(interp,"dccbroadcast",tcl_dccbroadcast,NULL,NULL); Tcl_CreateCommand(interp,"hand2idx",tcl_hand2idx,NULL,NULL); Tcl_CreateCommand(interp,"getidx",tcl_hand2idx,NULL,NULL); Tcl_CreateCommand(interp,"idx2hand",tcl_idx2hand,NULL,NULL); Tcl_CreateCommand(interp,"getchan",tcl_getchan,NULL,NULL); Tcl_CreateCommand(interp,"setchan",tcl_setchan,NULL,NULL); Tcl_CreateCommand(interp,"dccputchan",tcl_dccputchan,NULL,NULL); Tcl_CreateCommand(interp,"console",tcl_console,NULL,NULL); Tcl_CreateCommand(interp,"control",tcl_control,NULL,NULL); Tcl_CreateCommand(interp,"putbot",tcl_putbot,NULL,NULL); Tcl_CreateCommand(interp,"putallbots",tcl_putallbots,NULL,NULL); Tcl_CreateCommand(interp,"getchanidle",tcl_getchanidle,NULL,NULL); Tcl_CreateCommand(interp,"killdcc",tcl_killdcc,NULL,NULL); Tcl_CreateCommand(interp,"userlist",tcl_userlist,NULL,NULL); Tcl_CreateCommand(interp,"sendnote",tcl_sendnote,NULL,NULL); Tcl_CreateCommand(interp,"save",tcl_save,NULL,NULL); Tcl_CreateCommand(interp,"bots",tcl_bots,NULL,NULL); Tcl_CreateCommand(interp,"chanbans",tcl_chanbans,NULL,NULL); } /* set Tcl variables to match eggdrop internal variables */ void set_tcl_vars() { char s[121]; set_tcl_servers(); /* on/off variables */ tcl_setbool("log-time",shtime); tcl_setbool("clear-bans",clearbans); tcl_setbool("op-on-join",op_on_join); tcl_setbool("revenge",revenge); tcl_setbool("greet",greet); tcl_setbool("learn-users",learn_users); tcl_setbool("require-x",require_x); tcl_setbool("require-p",require_p); tcl_setbool("enforce-bans",enforce_bans); tcl_setbool("use-info",use_info); tcl_setbool("share-users",share_users); tcl_setbool("passive",passive); tcl_setbool("strict-host",strict_host); tcl_setbool("isolate",isolate); tcl_setbool("keep-all-logs",keep_all_logs); tcl_setbool("chan-updates",chan_updates); tcl_setbool("raw-files",raw_files); tcl_setbool("perm-bans",perm_bans); tcl_setbool("upload-to-cd",upload_to_cd); tcl_setbool("bitch",bitch); tcl_setbool("never-give-up",never_give_up); tcl_setbool("protect-ops",protect_ops); tcl_setbool("open-telnets",allow_new_telnets); tcl_setbool("forbid-bans",forbid_bans); tcl_setbool("keep-nick",keepnick); /* numbers */ tcl_setint("telnet",telnet_port); tcl_setint("servlimit",min_servs); tcl_setint("flood-msg",flood_thr); tcl_setint("flood-chan",flood_pub_thr); tcl_setint("flood-join",flood_join_thr); tcl_setint("ban-time",ban_time); tcl_setint("ignore-time",ignore_time); tcl_setint("dcc-limit",dcc_limit); tcl_setint("dcc-block",dcc_block); tcl_setint("idle-kick",idle_kick); tcl_setint("dcc-maxsize",dcc_maxsize); tcl_setint("dcc-users",dcc_users); /* strings */ tcl_setstr("nick",origbotname); tcl_setstr("username",botuser); tcl_setstr("realname",botrealname); tcl_setstr("home-channel",botchan); tcl_setstr("userfile",userfile); tcl_setstr("dcc-path",dccdir); tcl_setstr("dcc-incoming",dccin); tcl_setstr("motd",motdfile); tcl_setstr("admin",admin); tcl_setstr("init-server",initserver); tcl_setstr("notefile",notefile); tcl_setstr("helpbot",helpbot); tcl_setstr("helpdir",helpdir); tcl_setstr("tempdir",tempdir); tcl_setstr("textdir",textdir); tcl_setstr("channel-key",chankey); tcl_setstr("notify-newusers",notify_new); tcl_setstr("ctcp-version",ctcp_version); tcl_setstr("ctcp-finger",ctcp_finger); tcl_setstr("ctcp-userinfo",ctcp_userinfo); tcl_setstr("owner",owner); tcl_setstr("need-op",need_op); tcl_setstr("need-invite",need_invite); /* weird */ strcpy(s,masktype(conmask)); tcl_setstr("console",s); get_mode_protect(s); tcl_setstr("chanmode",s); flags2str(default_flags,s); tcl_setstr("default-flags",s); /* variables that we won't re-read... only for convenience of scripts */ tcl_setstr("channel",curchan); tcl_setstr("botnick",botname); sprintf(s,"%s:%d",botserver,botserverport); tcl_setstr("server",s); sprintf(s,"%s!%s",botname,botuserhost); tcl_setstr("botname",s); /* cos we have to: */ tcl_setstr("tcl_interactive","0"); } /* set eggdrop internal variables to match Tcl variables */ void get_tcl_vars() { char s[120]; int had_helpbot=0,oldisol; get_tcl_servers(); /* on/off variables: */ tcl_bool("log-time",&shtime); tcl_bool("clear-bans",&clearbans); tcl_bool("op-on-join",&op_on_join); tcl_bool("revenge",&revenge); tcl_bool("greet",&greet); tcl_bool("learn-users",&learn_users); tcl_bool("require-x",&require_x); tcl_bool("require-p",&require_p); tcl_bool("enforce-bans",&enforce_bans); tcl_bool("use-info",&use_info); tcl_bool("share-users",&share_users); tcl_bool("passive",&passive); tcl_bool("strict-host",&strict_host); oldisol=isolate; tcl_bool("isolate",&isolate); if ((isolate) && (!oldisol) && (online)) { /* suddenly isolating now */ chatout("*** Party line is now isolated.\n"); tandout("chat %s Isolating my party line.\n",origbotname); } if ((!isolate) && (oldisol) && (online)) { chatout("*** Party line is now open.\n"); tandout("chat %s Merging my party line.\n",origbotname); } tcl_bool("keep-all-logs",&keep_all_logs); tcl_bool("chan-updates",&chan_updates); tcl_bool("raw-files",&raw_files); tcl_bool("perm-bans",&perm_bans); tcl_bool("upload-to-cd",&upload_to_cd); tcl_bool("bitch",&bitch); tcl_bool("never-give-up",&never_give_up); tcl_bool("protect-ops",&protect_ops); tcl_bool("open-telnets",&allow_new_telnets); tcl_bool("forbid-bans",&forbid_bans); tcl_bool("keep-nick",&keepnick); /* numbers */ tcl_int("telnet",&telnet_port); tcl_int("servlimit",&min_servs); tcl_int("flood-msg",&flood_thr); tcl_int("flood-chan",&flood_pub_thr); tcl_int("flood-join",&flood_join_thr); tcl_int("ban-time",&ban_time); tcl_int("ignore-time",&ignore_time); tcl_int("dcc-limit",&dcc_limit); tcl_int("dcc-block",&dcc_block); tcl_int("idle-kick",&idle_kick); tcl_int("dcc-maxsize",&dcc_maxsize); tcl_int("dcc-users",&dcc_users); /* strings */ tcl_str("nick",origbotname,9); tcl_str("username",botuser,10); tcl_str("realname",botrealname,80); tcl_str("home-channel",botchan,80); tcl_str("userfile",userfile,120); tcl_str("dcc-path",dccdir,120); if (dccdir[0]) if (dccdir[strlen(dccdir)-1]!='/') strcat(dccdir,"/"); tcl_str("dcc-incoming",dccin,120); if (dccin[0]) if (dccin[strlen(dccin)-1]!='/') strcat(dccin,"/"); tcl_str("motd",motdfile,120); tcl_str("admin",admin,120); tcl_str("init-server",initserver,120); tcl_str("notefile",notefile,120); if (helpbot[0]) had_helpbot=1; tcl_str("helpbot",helpbot,10); if ((had_helpbot) && (!helpbot[0])) { log(LOG_MISC,"Killing the helpbot."); close(helpsock); helpsock=(-1); } if ((!had_helpbot) && (helpbot[0])) { if (online) log(LOG_MISC,"Spawning helpbot: %s",helpbot); helpsock=(-1); /* bot will find out that socket is bad, and connect */ } /* nick for helpbot probably changed */ if ((had_helpbot) && (helpbot[0])) hprintf(helpsock,"NICK %s\n",helpbot); tcl_str("helpdir",helpdir,120); if (helpdir[0]) if (helpdir[strlen(helpdir)-1]!='/') strcat(helpdir,"/"); tcl_str("tempdir",tempdir,120); if (tempdir[0]) if (tempdir[strlen(tempdir)-1]!='/') strcat(tempdir,"/"); tcl_str("textdir",textdir,120); if (textdir[0]) { if (textdir[strlen(textdir)-1]!='/') strcat(textdir,"/"); } else strcpy(textdir,helpdir); tcl_str("channel-key",chankey,120); tcl_str("notify-newusers",notify_new,120); tcl_str("ctcp-version",ctcp_version,120); tcl_str("ctcp-finger",ctcp_finger,120); tcl_str("ctcp-userinfo",ctcp_userinfo,120); tcl_str("owner",owner,120); tcl_str("need-op",need_op,120); tcl_str("need-invite",need_invite,120); /* weird ones */ s[0]=0; tcl_str("console",s,20); if (s[0]) conmask=logmodes(s); else conmask=LOG_MODES|LOG_MISC|LOG_CMDS; s[0]=0; tcl_str("chanmode",s,80); set_mode_protect(s); s[0]=0; tcl_str("default-flags",s,20); default_flags=str2flags(s); } /* evaluate a Tcl command, send output to a dcc user */ void cmd_tcl(idx,msg) int idx; char *msg; { int code; char *p; context; set_tcl_vars(); code=Tcl_Eval(interp,msg); if (code==TCL_OK) { p=interp->result; while (strlen(p)>500) { char *q=p+500; while ((*q!=' ') && (q!=p)) q--; if (q==p) q=p+500; /* ^ 1 char will get squashed because there was no space -- too bad */ *q=0; dprintf(idx,"TCL: %s\n",p); p=q+1; } dprintf(idx,"TCL: %s\n",p); } else dprintf(idx,"TCL error: %s\n",interp->result); /* refresh internal vars */ get_tcl_vars(); } /* perform a 'set' command */ void cmd_set(idx,msg) int idx; char *msg; { int code; char s[512]; context; log(LOG_CMDS,"#%s# set %s",dcc[idx].nick,msg); set_tcl_vars(); strcpy(s,"set "); strcat(s,msg); if (!msg[0]) { char *q; strcpy(s,"info globals"); Tcl_Eval(interp,s); q=interp->result; while (strlen(q)>500) { char *p=q+500; while ((*p != ' ') && (p > q)) p--; if (p == q) p=q+500; *p=0; dprintf(idx,"global vars: %s\n",q); q=p+1; } dprintf(idx,"global vars: %s\n",q); } code=Tcl_Eval(interp,s); if (code==TCL_OK) { if (strchr(msg,' ')==NULL) dprintf(idx,"currently: %s\n",interp->result); else dprintf(idx,"Ok, set.\n"); } else dprintf(idx,"Error: %s\n",interp->result); get_tcl_vars(); } void do_tcl(whatzit,script) char *whatzit,*script; { int code; set_tcl_vars(); code=Tcl_Eval(interp,script); if (code!=TCL_OK) { log(LOG_MISC,"Tcl error in script for '%s':",whatzit); log(LOG_MISC,"%s",interp->result); } get_tcl_vars(); } /* read and interpret the configfile given */ /* return 1 if everything was okay */ int readtclprog(fname) char *fname; { int code; FILE *f; set_tcl_vars(); f=fopen(fname,"r"); if (f==NULL) return 0; fclose(f); code=Tcl_EvalFile(interp,fname); if (code!=TCL_OK) { if (use_stderr) { tprintf(STDERR,"Tcl error in file '%s':\n",fname); tprintf(STDERR,"%s\n",Tcl_GetVar(interp,"errorInfo",TCL_GLOBAL_ONLY)); } else { log(LOG_MISC,"Tcl error in file '%s':",fname); log(LOG_MISC,"%s\n",Tcl_GetVar(interp,"errorInfo",TCL_GLOBAL_ONLY)); } /* try to go on anyway (shrug) */ } /* refresh internal variables */ get_tcl_vars(); return 1; } /* note (1): the tcl 'exec' command is no longer removed, since it is assumed that the tcl command will be left at its default flag requirement, ie: only owners can do tcl commands directly. also, removing the 'exec' command doesn't block up all holes -- tcl allows you to open a "pipe" which really just executes a shell command and redirects output. so you were never truly safe anyway. gee. */