/* 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 */ /* 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=serverlist; int i; char s[121],s1[121],srv[121]; context; if (x==NULL) return; /* uh, no server list */ if (strcmp(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_prog_ban(chan->bans,s1,time(NULL),s); 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 "); 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"); printf("Go to IRC and: /msg %s hello\n",botname); 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])) tprintf(serv,"NICK %s\n",botname); 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; } }