/* this file is only used if you are linking in Tcl */ #include #include #include "tcl.h" #include "eggdrop.h" #include "chan.h" #define CMD_MSG 0 #define CMD_DCC 1 #define CMD_FIL 2 #define CMD_PUB 3 /* 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, periodic_save, use_info, passive, strict_host, require_p, isolate, keep_all_logs, raw_files, perm_bans, clearbans, chan_updates, use_stderr, upload_to_cd; extern int telnet_port, botserverport, min_servs, helpserverport, default_flags, conmask; 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[], gainops[], userfile[], helpbot[], helpserver[], helpdir[], initserver[], chankey[], notify_new[], notefile[], curchan[], botuserhost[], tempdir[]; extern char cx_file[]; extern int cx_line; extern struct chan_t channel; extern int online; struct queue { char *item; struct queue *next; }; extern struct queue *serverlist; extern struct dcc_t dcc[]; extern int dcc_total; Tcl_Interp *Tcl_CreateInterp(); char *ismember(); char *masktype(); int expmem_tcl() { int i,tot=0; for (i=0; i(nh))) { \ Tcl_AppendResult(irp,"wrong # args: should be \"",argv[0], \ (example),"\"",NULL); \ return TCL_ERROR; \ } int tcl_logfile STDVAR { int i,ok=0; char s[151]; 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 tcl_putdcc STDVAR { int i; BADARGS(3,3," dccIdent text"); i=atoi(argv[1]); if ((i<0) || (i>=dcc_total)) { Tcl_AppendResult(interp,"dccIdent out of range",NULL); return TCL_ERROR; } tprintf(dcc[i].sock,"%s\n",argv[2]); return TCL_OK; } int tcl_putlog STDVAR { int mode=(int)cd; BADARGS(2,2," text"); log(mode,"%s",argv[1]); return TCL_OK; } int tcl_countusers STDVAR { char s[40]; BADARGS(1,1,""); sprintf(s,"%d",count_users()); Tcl_AppendResult(irp,s,NULL); return TCL_OK; } int tcl_validuser STDVAR { BADARGS(2,2," handle"); if (is_user(argv[1])) Tcl_AppendResult(irp,"1",NULL); else Tcl_AppendResult(irp,"0",NULL); return TCL_OK; } int tcl_finduser STDVAR { char s[20]; BADARGS(2,2," nick!user@host"); get_handle_by_host(s,argv[1]); Tcl_AppendResult(irp,s,NULL); return TCL_OK; } int tcl_passwdOk STDVAR { BADARGS(3,3," handle passwd"); if (pass_match_by_handle(argv[2],argv[1])) Tcl_AppendResult(irp,"1",NULL); else Tcl_AppendResult(irp,"0",NULL); return TCL_OK; } int tcl_chattr STDVAR { int f,i,pos=1; char s[20]; BADARGS(2,3," handle ?changes?"); if (!is_user(argv[1])) { Tcl_AppendResult(irp,"*",NULL); return TCL_OK; } if (argc==3) { /* make changes */ for (i=0; iresult); 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; int i; struct queue *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) char *var,*val; { char *s; s=Tcl_GetVar(interp,var,TCL_GLOBAL_ONLY); if (s!=NULL) { if (strlen(s)>119) log(LOG_MISC,"Tcl variable %s is too long!",var); else strcpy(val,s); } } void tcl_setstr(var,val) char *var,*val; { Tcl_SetVar(interp,var,val,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(); Tcl_DeleteCommand(interp,"exec"); /* 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,"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,"chattr",tcl_chattr,NULL,NULL); Tcl_CreateCommand(interp,"matchattr",tcl_matchattr,NULL,NULL); Tcl_CreateCommand(interp,"botisop",tcl_botisop,NULL,NULL); Tcl_CreateCommand(interp,"onchan",tcl_onchan,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,"chanlist",tcl_chanlist,NULL,NULL); Tcl_CreateCommand(interp,"bind",tcl_bind,NULL,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,"addhost",tcl_addhost,NULL,NULL); Tcl_CreateCommand(interp,"delhost",tcl_delhost,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("periodic-save",periodic_save); 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); /* 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); /* 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("gain-ops",gainops); tcl_setstr("init-server",initserver); tcl_setstr("notefile",notefile); tcl_setstr("helpbot",helpbot); tcl_setstr("helpdir",helpdir); tcl_setstr("tempdir",tempdir); tcl_setstr("channel-key",chankey); tcl_setstr("notify-newusers",notify_new); /* 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("periodic-save",&periodic_save); 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); /* 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); /* strings */ tcl_str("nick",origbotname); tcl_str("username",botuser); tcl_str("realname",botrealname); tcl_str("home-channel",botchan); tcl_str("userfile",userfile); tcl_str("dcc-path",dccdir); if (dccdir[0]) if (dccdir[strlen(dccdir)-1]!='/') strcat(dccdir,"/"); tcl_str("dcc-incoming",dccin); if (dccin[0]) if (dccin[strlen(dccin)-1]!='/') strcat(dccin,"/"); tcl_str("motd",motdfile); tcl_str("admin",admin); tcl_str("gain-ops",gainops); tcl_str("init-server",initserver); tcl_str("notefile",notefile); if (helpbot[0]) had_helpbot=1; tcl_str("helpbot",helpbot); if ((had_helpbot) && (!helpbot[0])) { log(LOG_MISC,"Killing the helpbot."); close(helpsock); shutdown(helpsock,2); 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 */ } tcl_str("helpdir",helpdir); if (helpdir[0]) if (helpdir[strlen(helpdir)-1]!='/') strcat(helpdir,"/"); tcl_str("tempdir",tempdir); if (tempdir[0]) if (tempdir[strlen(tempdir)-1]!='/') strcat(tempdir,"/"); tcl_str("channel-key",chankey); tcl_str("notify-newusers",notify_new); /* weird ones */ s[0]=0; tcl_str("console",s); if (s[0]) conmask=logmodes(s); else conmask=LOG_MODES|LOG_MISC|LOG_CMDS; s[0]=0; tcl_str("chanmode",s); set_mode_protect(s); s[0]=0; tcl_str("default-flags",s); default_flags=str2flags(s); } /* evaluate a Tcl command, send output to a dcc user */ int cmd_tcl(idx,z,msg) int idx,z; char *msg; { int code; context; set_tcl_vars(); code=Tcl_Eval(interp,msg); if (code==TCL_OK) tprintf(z,"Tcl: %s\n",interp->result); else tprintf(z,"Tcl error: %s\n",interp->result); /* refresh internal vars */ get_tcl_vars(); } /* perform a 'set' command */ int cmd_set(idx,z,msg) int idx,z; 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); code=Tcl_Eval(interp,s); if (code==TCL_OK) { if (strchr(msg,' ')==NULL) tprintf(z,"currently: %s\n",interp->result); else tprintf(z,"Ok, set.\n"); } else tprintf(z,"Error: %s\n",interp->result); get_tcl_vars(); } /* read and interpret the configfile given */ /* return 1 if everything was okay */ int readtclprog(fname) char *fname; { int code; context; set_tcl_vars(); 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",interp->result); } else { log(LOG_MISC,"Tcl error in file '%s':",fname); log(LOG_MISC,"%s",interp->result); } return 0; } /* refresh internal variables */ get_tcl_vars(); return 1; }