/* chanprog.c -- handles: rmspace() maintaining the server list revenge punishment timers, utimers telling the current programmed settings initializing a lot of stuff and loading the tcl scripts dprintf'ized, 1nov95 */ /* This file is part of the eggdrop source code copyright (c) 1997 Robey Pointer and is distributed according to the GNU general public license. For full details, read the top of 'main.c' or the file called COPYING that was distributed with this code. */ /* config file format changed 27jan94 (Tcl outdates that) */ #if HAVE_CONFIG_H #include #endif #include #include #include #include #include /* for mips */ #include "../lush.h" #include "eggdrop.h" #include "users.h" #include "chan.h" #include "proto.h" #include "tclegg.h" extern int serv; extern int shtime; extern int op_on_join; extern int telnet_port; extern int min_servs; extern int curserv; extern char botname[]; extern char origbotname[]; extern char botuser[]; extern char bothost[]; extern char botrealname[]; extern char botserver[]; extern char configfile[]; extern char dccdir[]; extern char dccin[]; extern char motdfile[]; extern char admin[]; extern char userfile[]; extern char helpdir[]; extern char initserver[]; extern char notify_new[]; extern char tempdir[]; extern char ctcp_version[]; extern char ctcp_finger[]; extern char ctcp_userinfo[]; extern char textdir[]; extern char owner[]; extern char firewall[]; extern int botserverport; extern int dcc_total; extern int use_stderr; extern int learn_users; extern int flood_thr; extern int flood_time; extern int flood_pub_thr; extern int flood_pub_time; extern int flood_join_thr; extern int flood_join_time; extern int flood_ctcp_thr; extern int flood_ctcp_time; extern int require_x; extern int share_users; extern int use_info; extern int passive; extern int strict_host; extern int noshare; extern int require_p; extern int isolate; extern int conmask; extern int default_flags; extern int keep_all_logs; extern int ban_time; extern int ignore_time; extern int make_userfile; extern int upload_to_cd; extern int dcc_limit; extern int never_give_up; extern int allow_new_telnets; extern int keepnick; extern int dcc_block; extern int dcc_maxsize; extern int dcc_users; extern int firewallport; extern int telnet_bots_only; extern struct dcc_t dcc[]; extern char *logfile[]; extern char *logchan[]; extern int logmask[]; extern char cx_file[]; extern int cx_line; extern struct userrec *userlist; extern char SBUF[]; extern struct chanset_t *chanset; extern Tcl_Interp *interp; /* used when rehash-ing */ char oldnick[NICKLEN]=""; /* where to store notes */ char notefile[121]; /* old-style queue, still used by server list */ struct eggqueue *serverlist=NULL; /* timers (minutely) and utimers (secondly) */ tcl_timer_t *timer=NULL,*utimer=NULL; /* next timer of any sort will have this number */ unsigned long timer_id=1; /* remove space characters from beginning and end of string */ /* (more efficent by Fred1) */ void rmspace(s) char *s; { #define whitespace(c) ( ((c)==32) || ((c)==9) || ((c)==13) || ((c)==10) ) char *p; /* wipe end of string */ for (p=s+strlen(s)-1; ((whitespace(*p))&&(p>=s)); p--); if (p!=s+strlen(s)-1) *(p+1)=0; for (p=s; ((whitespace(*p)) && (*p)); p++); if (p!=s) strcpy(s,p); } /* memory we should be using */ int expmem_chanprog() { int tot; struct eggqueue *s=serverlist; tcl_timer_t *t; tot=0; while (s!=NULL) { tot+=strlen(s->item)+1; tot+=sizeof(struct eggqueue); s=s->next; } t=timer; while (t!=NULL) { tot+=sizeof(tcl_timer_t); tot+=strlen(t->cmd)+1; t=t->next; } t=utimer; while (t!=NULL) { tot+=sizeof(tcl_timer_t); tot+=strlen(t->cmd)+1; t=t->next; } return tot; } /* add someone to a queue */ struct eggqueue *addq(ss,q) char *ss; struct eggqueue *q; { char s[512]; struct eggqueue *x,*z; char s1[121],*p; strcpy(s,ss); do { p=strchr(s,','); if (p!=NULL) { *p=0; p++; strcpy(s1,p); } else s1[0]=0; rmspace(s); rmspace(s1); x=(struct eggqueue *)nmalloc(sizeof(struct eggqueue)); x->next=NULL; x->item=(char *)nmalloc(strlen(s)+1); strcpy(x->item,s); if (q==NULL) q=x; else { z=q; while (z->next!=NULL) z=z->next; z->next=x; } s[0]=0; strcpy(s,s1); } while (s[0]); return q; } /* remove someone from a queue */ struct eggqueue *delq(s,q,ok) char *s; struct eggqueue *q; int *ok; { struct eggqueue *x,*ret,*old; x=q; ret=q; old=q; *ok=0; while (x!=NULL) { if (strcasecmp(x->item,s)==0) { if (x==ret) { ret=(x->next); nfree(x->item); nfree(x); x=ret; } else { old->next=x->next; nfree(x->item); nfree(x); x=old->next; } *ok=1; } else { old=x; x=x->next; } } return ret; } /* clear out a list */ void clearq(xx) struct eggqueue *xx; { struct eggqueue *x,*x1; x=xx; while (x!=NULL) { x1=x->next; nfree(x->item); nfree(x); x=x1; } } /* new server to the list */ void add_server(s) char *s; { serverlist=addq(s,serverlist); } /* set botserver to the next available server */ /* -> if (*ptr == -1) then jump to that particular server */ void next_server(ptr,serv,port,pass) int *ptr,*port; char *serv,*pass; { struct eggqueue *x=serverlist; int ok=1,i; char s[121]; context; if (x==NULL) return; /* -1 --> go to specified server */ if (*ptr == -1) { char sv[121]; int p; ok=0; i=0; while ((x!=NULL) && (!ok)) { strcpy(s,x->item); splitc(sv,s,':'); if (!sv[0]) { strcpy(sv,s); p=6667; } else { p=atoi(s); } if ((strcasecmp(sv,serv)==0) && (p==*port)) ok=1; else { x=x->next; i++; } } if (ok) { *ptr=i; return; } /* requested server is valid */ /* gotta add it : */ sprintf(s,"%s:%d",serv,*port); if (pass[0]) { strcat(s,":"); strcat(s,pass); } serverlist=addq(s,serverlist); *ptr=i; return; } /* find where i am and boogey */ i=(*ptr); while ((i>0) && (x!=NULL)) { x=x->next; i--; } if (x!=NULL) { x=x->next; (*ptr)++; } /* go to next server */ if (x==NULL) { x=serverlist; *ptr=0; } /* start over at the beginning */ pass[0]=0; strcpy(s,x->item); splitc(serv,s,':'); if (!serv[0]) { strcpy(serv,s); *port=6667; } else { char xs[121]; *port=atoi(s); splitc(xs,s,':'); if (xs[0]) strcpy(pass,s); } return; } /* 001: welcome to IRC (use it to fix the server name) */ void got001(from,msg) char *from,*msg; { struct eggqueue *x; int i; char s[121],s1[121],srv[121]; context; /* init-server */ if (initserver[0]) do_tcl("init-server",initserver); x=serverlist; if (x==NULL) return; /* uh, no server list */ if (strcasecmp(from,botserver)!=0) { putlog(LOG_MISC,"*","(%s is really %s; updating server list)", botserver,from); i=curserv; while ((i>0) && (x!=NULL)) { x=x->next; i--; } if (x==NULL) { putlog(LOG_MISC,"*","Invalid server list!"); return; } strcpy(s,x->item); splitc(srv,s,':'); if (!srv[0]) { strcpy(srv,s); strcpy(s,"6667"); } sprintf(s1,"%s:%s",from,s); nfree(x->item); x->item=(char *)nmalloc(strlen(s1)+1); strcpy(x->item,s1); strcpy(botserver,from); } } /* show server list, and point out which one the bot is on */ void tell_servers(idx) int idx; { struct eggqueue *x=serverlist; int i,sp; char s[141],sv[121]; context; if (x==NULL) { dprintf(idx,"No servers.\n"); return; } dprintf(idx,"My server list:\n"); i=0; while (x!=NULL) { strcpy(s,x->item); splitc(sv,s,':'); if (!sv[0]) { strcpy(sv,s); sp=6667; } else sp=atoi(s); sprintf(s," %s:%d",sv,sp); if (i==curserv) strcat(s," <- I am here."); dprintf(idx,"%s\n",s); x=x->next; i++; } } void wipe_serverlist() { if (serverlist==NULL) return; clearq(serverlist); serverlist=NULL; } /* revenge tactic: person did something bad */ /* if they're oplisted, remove them from the op list */ /* otherwise, deop them */ void take_revenge(chan,who,reason) struct chanset_t *chan; char *who; char *reason; { char nick[NICKLEN],s[UHOSTLEN],s1[UHOSTLEN],ct[81]; int i,atr; time_t tm; context; atr=get_attr_host(who); if (atr & USER_FRIEND) { putlog(LOG_MISC,"*","%s is a friend (%s)",who,reason); return; /* argh! */ } if (change_attr(who,'-',USER_OP)) { putlog(LOG_MISC,"*","No longer opping %s (%s)",who,reason); return; } if ((match_ban(who)) || (u_match_ban(chan->bans,who))) { /* what more can we do? */ return; } /* get current time into a string */ tm=time(NULL); strcpy(ct,ctime(&tm)); ct[10]=0; ct[16]=0; strcpy(ct,&ct[8]); strcpy(&ct[2],&ct[3]); strcpy(&ct[7],&ct[10]); if (atr & USER_DEOP) { /* this is out of control: BAN THEM */ putlog(LOG_MISC,"*","Now banning %s (%s)",who,reason); strcpy(s1,who); splitnick(nick,s1); maskhost(s1,s); strcpy(s1,"*!*"); strcat(s1,&s[2]); /* add extra * for ban */ sprintf(s,"(%s) %s",ct,reason); u_addban(chan->bans,s1,origbotname,s,time(NULL)+(60*ban_time)); return; } if (change_attr(who,'+',USER_DEOP)) { /* in the user list already, cool :) */ sprintf(s,"(%s) %s",ct,reason); putlog(LOG_MISC,"*","Now deopping %s (%s)",who,s); return; } strcpy(s1,who); splitnick(nick,s1); maskhost(s1,s); while (is_user(nick)) { if (strncmp(nick,"bad",3)==0) { i=atoi(&nick[3]); sprintf(nick,"bad%d",i+1); } else strcpy(nick,"bad1"); } userlist=adduser(userlist,nick,s,"-",USER_DEOP); sprintf(s,"(%s) %s (%s)",ct,reason,who); set_handle_comment(userlist,nick,s); putlog(LOG_MISC,"*","Now deopping %s (%s)",who,reason); } /* clear out the programming */ void clearprog() { context; clear_userlist(userlist); userlist=NULL; clearq(serverlist); serverlist=NULL; strcpy(oldnick,botname); } int logmodes(s) char *s; { int i; int res=0; for (i=0; iname); get_mode_protect(chan,s); if (s[0]) dprintf(idx," (forcing mode: %s)",s); s[0]=0; if (chan->stat&CHAN_CLEARBANS) strcat(s,"clear-bans "); if (chan->stat&CHAN_ENFORCEBANS) strcat(s,"enforce-bans "); if (chan->stat&CHAN_DYNAMICBANS) strcat(s,"dynamic-bans "); if (chan->stat&CHAN_NOUSERBANS) strcat(s,"forbid-user-bans "); if (chan->stat&CHAN_OPONJOIN) strcat(s,"op-on-join "); if (chan->stat&CHAN_BITCH) strcat(s,"bitch "); if (chan->stat&CHAN_GREET) strcat(s,"greet "); if (chan->stat&CHAN_PROTECTOPS) strcat(s,"protect-ops "); if (chan->stat&CHAN_LOGSTATUS) strcat(s,"log-status "); if (chan->stat&CHAN_REVENGE) strcat(s,"revenge "); if (chan->stat&CHAN_STOPNETHACK) strcat(s,"stopnethack "); if (chan->stat&CHAN_SECRET) strcat(s,"secret "); dprintf(idx,"\n Options: %s\n",s); s[0]=0; if (chan->need_op[0]) dprintf(idx," To get ops I do: %s\n",chan->need_op); if (chan->need_invite[0]) dprintf(idx," To get invited I do: %s\n",chan->need_invite); if (chan->idle_kick) dprintf(idx," Kicking idle users after %d min\n",chan->idle_kick); chan=chan->next; } #endif dprintf(idx,"Userfile: %s Motd: %s\n",userfile,motdfile); if (notefile[0]) dprintf(idx,"Notes can be stored, in: %s\n",notefile); else dprintf(idx,"Notes can not be stored.\n"); #ifndef NO_IRC if (dccdir[0]) { dprintf(idx,"DCC file path: %s",dccdir); if (upload_to_cd) dprintf(idx,"\n incoming: (go to the current dir)\n"); else if (dccin[0]) dprintf(idx,"\n incoming: %s\n",dccin); else dprintf(idx," (no uploads)\n"); dprintf(idx,"DCC block is %d, max concurrent d/ls is %d\n",dcc_block, dcc_limit); if (dcc_users) dprintf(idx," max users is %d\n",dcc_users); if ((upload_to_cd) || (dccin[0])) dprintf(idx,"DCC max file size: %dk\n",dcc_maxsize); } else dprintf(idx,"(No active file transfer path defined.)\n"); #endif if (telnet_port) dprintf(idx,"Listening at telnet port %d\n",telnet_port); #ifndef NO_IRC if (min_servs) dprintf(idx,"Requiring a net of at least %d server(s)\n",min_servs); if (initserver[0]) dprintf(idx,"On connect, I do: %s\n",initserver); dprintf(idx,"Flood is: %d msg/%ds, %d pub/%ds, %d join(nick)/%ds, %d ctcp/%ds\n", flood_thr,flood_time,flood_pub_thr,flood_pub_time,flood_join_thr, flood_join_time,flood_ctcp_thr,flood_ctcp_time); dprintf(idx,"Bans last %d mins, ignores last %d mins\n",ban_time, ignore_time); #endif dprintf(idx,"Help dir (%s), temp dir (%s), text dir (%s)\n",helpdir,tempdir, textdir); flags2str(default_flags,s); dprintf(idx,"New users get flags [%s], notify: %s\n",s,notify_new); #ifdef OWNER if (owner[0]) dprintf(idx,"Permanent owner(s): %s\n",owner); #endif for (i=0; ipw_name); } if (!readuserfile(userfile,&userlist)) { if (!make_userfile) fatal("USER FILE NOT FOUND! (try 'eggdrop -m' to make one)",0); printf("\n\nSTARTING BOT IN USERFILE CREATION MODE.\n"); #ifdef NO_IRC printf("Telnet to the bot and enter 'NEW' as your nickname.\n"); #else printf("Go to IRC and: /msg %s hello\n",botname); #endif printf("This will make the bot recognize you as the master.\n\n"); } else if (make_userfile) fatal("USERFILE ALREADY EXISTS (drop the '-m')",0); context; #ifndef NO_IRC if (serverlist==NULL) fatal("NO SERVER.",0); if (dccdir[0]) if (dccdir[strlen(dccdir)-1]!='/') strcat(dccdir,"/"); if (dccin[0]) if (dccin[strlen(dccin)-1]!='/') strcat(dccin,"/"); #else dccdir[0]=0; #endif if (helpdir[0]) if (helpdir[strlen(helpdir)-1]!='/') strcat(helpdir,"/"); if (tempdir[0]) if (tempdir[strlen(tempdir)-1]!='/') strcat(tempdir,"/"); if (textdir[0]) { if (textdir[strlen(textdir)-1]!='/') strcat(textdir,"/"); } else strcpy(textdir,helpdir); context; /* test tempdir: it's vital */ { FILE *f; char s[161]; sprintf(s,"%s.test.file",tempdir); f=fopen(s,"w"); if (f==NULL) fatal("CAN'T WRITE TO TEMP DIR.",0); fclose(f); unlink(s); } #ifdef NO_IRC /* sanity check */ if (telnet_bots_only) putlog(LOG_MISC,"*","* Drone mode (no user access; only bots)"); #endif reaffirm_owners(); } /* reload the user file from disk */ void reload() { FILE *f; context; f=fopen(userfile,"r"); if (f==NULL) { putlog(LOG_MISC,"*","Can't reload user file!"); return; } fclose(f); clear_userlist(userlist); userlist=NULL; if (!readuserfile(userfile,&userlist)) fatal("USER FILE IS MISSING!",0); context; reaffirm_owners(); } void rehash() { int old_tp=telnet_port; /* save old telnet port value */ struct chanset_t *chan; context; chan=chanset; while (chan!=NULL) { chan->stat |= CHANFLAGGED; /* flag will be cleared as the channels are re-added by the config file */ /* any still flagged afterwards will be removed */ chan=chan->next; } clearprog(); chanprog(); telnet_port=old_tp; #ifdef NO_IRC dccdir[0]=0; #else if ((strcasecmp(oldnick,botname)!=0) && (oldnick[0])) { /* change botname back, don't be premature */ strcpy(botname,oldnick); tprintf(serv,"NICK %s\n",origbotname); } if (initserver[0]) do_tcl("init-server",initserver); /* remove any extra channels */ chan=chanset; while (chan!=NULL) { if (chan->stat & CHANFLAGGED) { putlog(LOG_MISC,"*","No longer supporting channel %s",chan->name); if (serv>=0) mprintf(serv,"PART %s\n",chan->name); clear_channel(chan,0); freeuser(chan->bans); killchanset(chan->name); chan=chanset; } else chan=chan->next; } /* update stuff, as if we just got control of a channel again: */ chan=chanset; while (chan!=NULL) { recheck_channel(chan); chan=chan->next; } #endif } void get_first_server() { curserv=999; /* silly, no? */ } /* brief venture into timers */ /* add a timer */ unsigned long add_timer(stack,elapse,cmd,prev_id) tcl_timer_t **stack; int elapse; char *cmd; unsigned long prev_id; { tcl_timer_t *old=(*stack); *stack=(tcl_timer_t *)nmalloc(sizeof(tcl_timer_t)); (*stack)->next=old; (*stack)->mins=elapse; (*stack)->cmd=(char *)nmalloc(strlen(cmd)+1); strcpy((*stack)->cmd,cmd); /* if it's just being added back and already had an id, */ /* don't create a new one */ if (prev_id>0) (*stack)->id=prev_id; else (*stack)->id=timer_id++; return (*stack)->id; } /* remove a timer, by id */ int remove_timer(stack,id) tcl_timer_t **stack; unsigned long id; { tcl_timer_t *mark=*stack,*old; int ok=0; context; *stack=NULL; while (mark!=NULL) { if (mark->id != id) add_timer(stack,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 do_check_timers(stack) tcl_timer_t **stack; { tcl_timer_t *mark=*stack,*old; Tcl_DString ds; int argc,i; char **argv; context; /* new timers could be added by a Tcl script inside a current timer */ /* so i'll just clear out the timer list completely, and add any */ /* unexpired timers back on */ *stack=NULL; while (mark!=NULL) { mark->mins--; if (mark->mins == 0) { int code; set_tcl_vars(); Tcl_DStringInit(&ds); if (Tcl_SplitList(interp,mark->cmd,&argc,&argv) != TCL_OK) { putlog(LOG_MISC,"*","(Timer) Error for '%s': %s",mark->cmd, interp->result); } else { for (i=0; icmd); */ Tcl_DStringFree(&ds); if (code!=TCL_OK) putlog(LOG_MISC,"*","(Timer) Error for '%s': %s",mark->cmd, interp->result); } get_tcl_vars(); } else add_timer(stack,mark->mins,mark->cmd,mark->id); context; old=mark; mark=mark->next; nfree(old->cmd); nfree(old); } } void check_timers() { do_check_timers(&timer); } void check_utimers() { do_check_timers(&utimer); } /* return list of timers */ void list_timers(irp,stack) Tcl_Interp *irp; tcl_timer_t *stack; { tcl_timer_t *mark=stack; char mins[10],id[20],*argv[3],*x; while (mark!=NULL) { sprintf(mins,"%u",mark->mins); sprintf(id,"timer%lu",mark->id); argv[0]=mins; argv[1]=mark->cmd; argv[2]=id; x=Tcl_Merge(3,argv); Tcl_AppendElement(irp,x); n_free(x,"",0); mark=mark->next; } }