/* main.c -- handles: changing nicknames when the desired nick is in use flood detection signal handling telnet code translation command line arguments connecting to a server (bot and helpbot) interpreting server responses (main loop) dprintf'ized, 15nov95 */ #if HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #ifdef STOP_UAC /* osf/1 complains a lot */ # include # define UAC_NOPRINT 0x00000001 /* Don't report unaligned fixups */ #endif /* some systems have a working sys/wait.h even though configure will */ /* decide it's not bsd compatable. oh well. */ #include "../lush.h" #include "eggdrop.h" #include "chan.h" #include "proto.h" /* number of seconds to wait between transmitting queued lines to the server */ /* lower this value at your own risk. ircd is known to start flood control */ /* at 512 bytes/2 seconds */ #define msgrate 2 /* If you're going to modify the following lines, please don't make up weird shit. Keep the "eggdrop" part and the version number, and add your own customized version info afterwards. That way we can still tell what your modifications were based on, and you don't look like an idiot (eg, "eggdrop eswk!" etc). Also please read the README file regarding your rights to distribute modified versions of this bot. */ char version[81]="Eggdrop v1.0i (c)1996 Robey Pointer"; char ver[41]="eggdrop v1.0i"; char egg_version[81]="1.0i 1090"; /* socket that the server is on */ int serv=(-1); /* run in the background? */ int backgrd=1; /* successful connect yet? */ int online=0; /* foreground: constantly display channel stats? */ int con_chan=0; /* foreground: use the terminal as a party line? */ int term_z=0; /* trying to connect to a server right now? */ time_t trying_server=0L; /* how lagged (in seconds) is the server? */ int server_lag=0; /* bot's username */ char botuser[21]; /* bot's real name field */ char botrealname[121]; /* our current host */ char bothost[121]; /* our server */ char botserver[121]; /* port # to connect to */ int botserverport=6667; /* name of the config file */ char configfile[121]="egg.config"; /* possible alternate nickname to use */ char altnick[10]=""; /* temporary thing for nick changes */ char newbotname[10]; /* current position in server list: */ int curserv=0; /* directory of help files (if used) */ char helpdir[121]; /* directory for text files that get dumped */ char textdir[121]=""; /* MSG flood */ int flood_thr=5; int flood_time=60; /* PUBLIC flood */ int flood_pub_thr=10; int flood_pub_time=60; /* JOIN flood */ int flood_join_thr=5; int flood_join_time=60; /* CTCP flood */ int flood_ctcp_thr=3; int flood_ctcp_time=60; /* what, if anything, to send to the server on connection */ char initserver[121]; /* never erase logfiles, no matter how old they are? */ int keep_all_logs=0; /* context storage for fatal crashes */ char cx_file[30]; int cx_line; /* unix-time that the bot loaded up */ time_t online_since; /* bot's user@host (refreshed whenever the bot joins a channel) */ /* may not be correct user@host BUT it's how the server sees it */ char botuserhost[121]; /* using bot in make-userfile mode? (first user to 'hello' becomes master) */ int make_userfile=0; /* never give up when connecting to servers? */ int never_give_up=0; /* permanent owner(s) of the bot */ char owner[121]=""; /* keep trying to regain my intended nickname? */ int keepnick=1; /* set when i send a CTCP AWAKE to myself, cleared when i get it */ int waiting_for_awake=0; /* name of the file for the pid to be stored in */ char pid_file[40]; /* how many minutes past the hour to save the userfile? */ int save_users_at=0; /* when (military time) to switch logfiles */ int switch_logfiles_at=300; /* static buffer used by various functions */ char SBUF[1024]; extern char botname[]; extern char origbotname[]; extern int dcc_total; extern struct dcc_t dcc[]; extern char dccdir[]; extern char dccin[]; extern int telnet_port; extern char admin[]; extern char notefile[]; extern char newserver[]; extern char newserverpass[]; extern int newserverport; extern int lastsock; extern char *logfile[]; extern char *logchan[]; extern int conmask; extern struct userrec *userlist; extern int cache_hit,cache_miss; extern char userfile[]; extern struct chanset_t *chanset; /* send stuff to stderr instead of logfiles? */ int use_stderr=1; void fatal(s,recoverable) char *s; int recoverable; { int i; putlog(LOG_MISC,"*","* %s",s); if (use_stderr) tprintf(STDERR,"* %s\n",s); if (serv>=0) killsock(serv); for (i=0; i (raw stuff from server), pull off who it's from & the code */ void parsemsg(in,from,code,params) char *in,*from,*code,*params; { char *p; from[0]=0; if (in[0]==':') { strcpy(in,&in[1]); p=strchr(in,' '); if (p==NULL) { from[0]=params[0]=0; strcpy(code,in); return; } strcpy(params,p+1); *p=0; strcpy(from,in); *p=' '; p++; strcpy(in,p); } p=strchr(in,' '); if (p==NULL) { strcpy(code,in); params[0]=0; return; } *p=0; strcpy(code,in); *p=' '; strcpy(params,p+1); } /* ping from server */ void gotpong(from,msg) char *from,*msg; { context; split(NULL,msg); fixcolon(msg); /* scrap server name */ waiting_for_awake=0; server_lag=time(NULL)-my_atoul(msg); } /* 432 : bad nickname */ void got432(from,msg) char *from,*msg; { context; putlog(LOG_MISC,"*","Server says my nickname is invalid."); putlog(LOG_MISC,"*","SWITCHING TO TEMPORARY NICK 'fucked' -- PLEASE FIX!"); strcpy(botname,"fucked"); newbotname[0]=0; tprintf(serv,"NICK fucked\n"); } /* 433 : nickname in use */ /* change nicks till we're acceptable or we give up */ void got433(from,msg) char *from,*msg; { char c,*oknicks="^-_\\[]`zqxjyc",*p; context; /* could be futile attempt to regain nick: */ if (newbotname[0]) { tprintf(serv,"NICK %s\n",newbotname); strcpy(botname,newbotname); newbotname[0]=0; return; } /* alternate nickname defined? */ if ((altnick[0]) && (strcasecmp(altnick,botname)!=0)) { strcpy(botname,altnick); } /* if alt nickname failed, drop thru to here */ else { c=botname[strlen(botname)-1]; p=strchr(oknicks,c); if (((c>='0') && (c<='9')) || (p!=NULL)) { if (p==NULL) { if (c=='9') botname[strlen(botname)-1]=oknicks[0]; else botname[strlen(botname)-1]=c+1; } else { p++; if (p==NULL) fatal("COULDN'T FIND A SUITABLE NICKNAME.",1); botname[strlen(botname)-1]=(*p); } } else { if (strlen(botname)==9) botname[strlen(botname)-1]='0'; else { botname[strlen(botname)+1]=0; botname[strlen(botname)]='0'; } } } putlog(LOG_MISC,"*","NICK IN USE: Trying '%s'",botname); tprintf(serv,"NICK %s\n",botname); } int lastmsgs[5]={ 0,0,0,0,0 }; char lastmsghost[5][81]={ "","","","","" }; time_t lastmsgtime[5]={ 0L,0L,0L,0L,0L }; /* do on NICK, PRIVMSG, and NOTICE -- and JOIN */ int detect_flood(from,chan,which,tochan) char *from; int which,tochan; struct chanset_t *chan; { char *p; time_t t; char h[UHOSTLEN],floodnick[NICKLEN],handle[10],ftype[10]; int thr=0,lapse=0; if (get_attr_host(from)&(USER_BOT|USER_MASTER|USER_FRIEND)) return 0; /* determine how many are necessary to make a flood */ switch(which) { case FLOOD_PRIVMSG: case FLOOD_NOTICE: if (tochan) { thr=flood_pub_thr; lapse=flood_pub_time; strcpy(ftype,"pub"); } else { thr=flood_thr; lapse=flood_time; strcpy(ftype,"msg"); } break; case FLOOD_JOIN: case FLOOD_NICK: thr=flood_join_thr; lapse=flood_join_time; if (which==FLOOD_JOIN) strcpy(ftype,"join"); else strcpy(ftype,"nick"); break; case FLOOD_CTCP: thr=flood_ctcp_thr; lapse=flood_ctcp_time; strcpy(ftype,"ctcp"); break; } if (thr==0) return 0; /* no flood protection */ /* okay, make sure i'm not flood-checking myself */ strcpy(h,from); splitnick(floodnick,h); if (newbotname[0]) { if (strcasecmp(floodnick,newbotname)==0) return 0; } else if (strcasecmp(floodnick,botname)==0) return 0; if (strcasecmp(h,botuserhost)==0) return 0; /* my user@host (?) */ p=strchr(from,'!'); if (p!=NULL) { p++; p=strchr(p,'@'); } if (p!=NULL) { p++; t=time(NULL); if (strcasecmp(lastmsghost[which],p)!=0) { /* new */ strcpy(lastmsghost[which],p); lastmsgtime[which]=t; lastmsgs[which]=0; return 0; } } if (p==NULL) return 0; /* uh... whatever. */ if (lastmsgtime[which] < t-lapse) { /* flood timer expired, reset it */ lastmsgtime[which]=t; lastmsgs[which]=0; return 0; } lastmsgs[which]++; if (lastmsgs[which]>=thr) { /* FLOOD */ /* reset counters */ lastmsgs[which]=0; lastmsgtime[which]=0; lastmsghost[which][0]=0; get_handle_by_host(handle,from); if (tochan) { if (check_tcl_flud(floodnick,from,handle,ftype,chan->name)) return 0; } else { if (check_tcl_flud(floodnick,from,handle,ftype,"*")) return 0; } if (((which==FLOOD_PRIVMSG) || (which==FLOOD_NOTICE)) && (!tochan)) { /* private msg */ sprintf(h,"*!*@%s",p); putlog(LOG_MISC,"*","Flood from @%s! Placing on ignore!",p); prog_ignore(h,time(NULL),origbotname); return 1; } else if (which==FLOOD_CTCP) { /* ctcp flood! */ sprintf(h,"*!*@%s",p); putlog(LOG_MISC,"*","CTCP flood from @%s! Placing on ignore!",p); prog_ignore(h,time(NULL),origbotname); return 1; } else if (which==FLOOD_JOIN) { /* join flood */ char sx[21]; sprintf(h,"*!*@%s",p); strcpy(sx,"join flood"); if (!isbanned(chan,h)) { add_mode(chan,'+','b',h); flush_mode(chan,QUICK); } if ((match_ban(from)) || (u_match_ban(chan->bans,from))) return 1; /* already banned */ putlog(LOG_MISC|LOG_JOIN,chan->name,"Join flood from @%s! Banning.",p); u_prog_ban(chan->bans,h,time(NULL),sx); if (!(chan->stat&CHAN_ENFORCEBANS)) kick_match_since(chan,h,lastmsgtime[which]); return 1; } else { /* flooding chan! either by public, notice, or nick */ p=strchr(from,'!'); if (p!=NULL) { putlog(LOG_MODES,chan->name,"Channel flood from %s -- kicking", from); *p=0; mprintf(serv,"KICK %s %s :flood\n",chan->name,from); *p='!'; return 1; } } } return 0; } void got_bus() { int x; time_t now=time(NULL); char s[80]; putlog(LOG_MISC,"*","* Last context: %s/%d",cx_file,cx_line); x=creat("DEBUG",0644); setsock(x,SOCK_NONSOCK); if (x<0) { putlog(LOG_MISC,"*","* Failed to write DEBUG"); } else { strcpy(s,ctime(&now)); tprintf(x,"Debug written %s",s); tprintf(x,"Context: %s/%d\n\n",cx_file,cx_line); tell_dcc(-x); tprintf(x,"\n"); debug_mem_to_dcc(-x); close(x); putlog(LOG_MISC,"*","* Wrote DEBUG"); } fatal("BUS ERROR -- CRASHING!",1); } void got_segv() { int x; time_t now=time(NULL); char s[80]; putlog(LOG_MISC,"*","* Last context: %s/%d",cx_file,cx_line); x=creat("DEBUG",0644); setsock(x,SOCK_NONSOCK); if (x<0) { putlog(LOG_MISC,"*","* Failed to write DEBUG"); } else { strcpy(s,ctime(&now)); tprintf(x,"Debug written %s",s); tprintf(x,"Context: %s/%d\n\n",cx_file,cx_line); tell_dcc(-x); tprintf(x,"\n"); debug_mem_to_dcc(-x); close(x); putlog(LOG_MISC,"*","* Wrote DEBUG"); } fatal("SEGMENT VIOLATION -- CRASHING!",1); } void got_fpe() { int x; time_t now=time(NULL); char s[80]; putlog(LOG_MISC,"*","* Last context: %s/%d",cx_file,cx_line); x=creat("DEBUG",0644); setsock(x,SOCK_NONSOCK); if (x<0) { putlog(LOG_MISC,"*","* Failed to write DEBUG"); } else { strcpy(s,ctime(&now)); tprintf(x,"Debug written %s",s); tprintf(x,"Context: %s/%d\n\n",cx_file,cx_line); tell_dcc(-x); tprintf(x,"\n"); debug_mem_to_dcc(-x); close(x); putlog(LOG_MISC,"*","* Wrote DEBUG"); } fatal("FLOATING POINT ERROR -- CRASHING!",1); } void got_term() { #ifdef DIE_ON_TERMHUP write_userfile(); tprintf(serv,"QUIT :terminate signal\n"); fatal("TERMINATE SIGNAL -- SIGNING OFF"); #else putlog(LOG_MISC,"*","RECEIVED TERMINATE SIGNAL (IGNORING)"); write_userfile(); return; #endif } void got_quit() { putlog(LOG_MISC,"*","RECEIVED QUIT SIGNAL (IGNORING)"); return; } void got_hup() { #ifdef DIE_ON_TERMHUP write_userfile(); tprintf(serv,"QUIT :hangup signal\n"); fatal("HANGUP SIGNAL -- SIGNING OFF"); #else putlog(LOG_MISC,"*","Received HUP signal: rehashing..."); rehash(); return; #endif } void got_alarm() { /* connection to a server was ended prematurely */ return; } void got_usr1() { int x,i; putlog(LOG_MISC,"*","* USER1 SIGNAL: Debugging sockets"); x=creat("DEBUG",0644); setsock(x,SOCK_NONSOCK); if (x<0) { putlog(LOG_MISC,"*","* Failed to write DEBUG"); return; } tell_dcc(-x); tprintf(x,"\n"); tprintf(x,"SERVER %s:%d, SOCK %d\n",botserver,botserverport,serv); if (fcntl(serv,F_GETFD,0)<0) { putlog(LOG_MISC,"*","* Server socket expired -- pfft"); killsock(serv); serv=(-1); } for (i=0; i= 251) && (*(p+1) <= 254)) { mark=3; if (!*(p+2)) mark=2; /* bogus */ } strcpy(p,p+mark); } } } void strip_telnet(sock,buf,len) int sock,*len; char *buf; { unsigned char *p=(unsigned char *)buf; int mark; while (*p != 0) { while ((*p != 255) && (*p != 0)) p++; /* search for IAC */ if (*p == 255) { p++; mark=2; if (!*p) mark=1; /* bogus */ if ((*p >= 251) && (*p <= 254)) { mark=3; if (!*(p+1)) mark=2; /* bogus */ } if (*p == 251) { /* WILL X -> response: DONT X */ /* except WILL ECHO which we just smile and ignore */ if (!(*(p+1) == 1)) { write(sock,"\377\376",2); write(sock,p+1,1); } } if (*p == 253) { /* DO X -> response: WONT X */ /* except DO ECHO which we just smile and ignore */ if (!(*(p+1) == 1)) { write(sock,"\377\374",2); write(sock,p+1,1); } } if (*p == 246) { /* "are you there?" */ /* response is: "hell yes!" */ write(sock,"\r\nHell, yes!\r\n",14); } /* anything else can probably be ignored */ p--; strcpy((char *)p,(char *)(p+mark)); /* wipe code from buffer */ *len = *len - mark; } } } void change_telnet_port() { int i,j,idx=(-1); /* find old entry if it exists */ for (i=0; i= MAXDCC) { putlog(LOG_MISC,"*","No more DCC slots available: can't open telnet port"); return; } idx=dcc_total; dcc[idx].addr=getmyip(); dcc[idx].type=DCC_TELNET; dcc[idx].u.other=NULL; strcpy(dcc[idx].nick,"(telnet)"); getmyhostname(dcc[idx].host); dcc_total++; } else { /* already an entry */ killsock(dcc[idx].sock); if (!telnet_port) { lostdcc(idx); putlog(LOG_MISC,"*","No longer listening at a telnet port."); return; } } j=telnet_port+20; i=(-1); while ((telnet_port=0) { dcc[idx].port=telnet_port; dcc[idx].sock=i; putlog(LOG_MISC,"*","Listening at telnet port %d",telnet_port); return; } putlog(LOG_MISC,"*","Couldn't find telnet port near %d.",telnet_port); telnet_port=0; lostdcc(idx); } void do_arg(s) char *s; { int i; if (s[0]=='-') for (i=1; i < strlen(s); i++) { if (s[i]=='n') backgrd=0; if (s[i]=='c') { con_chan=1; term_z=0; } if (s[i]=='t') { con_chan=0; term_z=1; } if (s[i]=='m') make_userfile=1; if (s[i]=='v') { printf("%s\n",version); exit(0); } if (s[i]=='h') { printf("\n%s\n\n",version); printf("Command line arguments:\n"); printf(" -h help\n"); printf(" -v print version and exit\n"); printf(" -n don't go into the background\n"); printf(" -c (with -n) display channel stats every 10 seconds\n"); printf(" -t (with -n) use terminal to simulate dcc-chat\n"); printf(" -m userfile creation mode\n"); printf(" optional config filename (default 'egg.config')\n"); printf("\n"); exit(0); } } else strcpy(configfile,s); } /* hook up to a server */ /* works a little differently now... async i/o is your friend */ void connect_server() { char s[121],pass[121]; static int oldserv=(-1); struct chanset_t *chan; context; waiting_for_awake=0; trying_server=time(NULL); empty_msgq(); if ((oldserv<0) || (never_give_up)) oldserv=curserv; /* start up the counter (always reset it if "never-give-up" is on) */ if (newserverport) { /* jump to specified server */ curserv=(-1); /* reset server list */ strcpy(botserver,newserver); botserverport=newserverport; strcpy(pass,newserverpass); newserver[0]=0; newserverport=0; newserverpass[0]=0; oldserv=(-1); } next_server(&curserv,botserver,&botserverport,pass); putlog(LOG_SERV,"*","Trying server %s:%d",botserver, botserverport); serv=open_telnet(botserver,botserverport); if (serv<0) { if (serv==(-2)) strcpy(s,"DNS lookup failed"); else neterror(s); putlog(LOG_SERV,"*","Failed connect to %s (%s)",botserver,s); if ((oldserv==curserv) && !(never_give_up)) fatal("NO SERVERS WILL ACCEPT MY CONNECTION.",1); } else { /* queue standard login */ tprintf(serv,"NICK %s\n",botname); if (pass[0]) tprintf(serv,"PASS %s\n",pass); tprintf(serv,"USER %s %s %s :%s\n",botuser,bothost,botserver,botrealname); chan=chanset; while (chan!=NULL) { mprintf(serv,"JOIN %s %s\n",chan->name,chan->key_prot); chan->stat&=~(CHANACTIVE|CHANPEND); chan=chan->next; } /* wait for async result now */ } } int main(argc,argv) int argc; char **argv; { int xx,i; char buf[520]; time_t now,then; struct tm *nowtm; FILE *f; char s[520]; struct sigaction sv; int modecnt=0; int timecnt=0,midnite=0,fivemin=0,hourly=0,miltime,switched=0,lastmin=99; #ifndef NO_IRC char from[121],code[520],msg[520]; struct chanset_t *chan; int j; #endif context; #ifdef STOP_UAC { int nvpair[2]; nvpair[0]=SSIN_UACPROC; nvpair[1]=UAC_NOPRINT; setsysinfo(SSI_NVPAIRS, (char *) nvpair, 1, NULL, 0); } #endif if (argc>1) for (i=1; itm_min; init_mem(); init_misc(); init_tand(); init_net(); init_blowfish(); init_tcl(); chanprog(); context; cache_miss=0; cache_hit=0; #ifdef NO_IRC strcat(ver," [limbo]"); #endif srandom((unsigned short int)time(NULL)); getmyhostname(bothost); sprintf(botuserhost,"%s@%s",botuser,bothost); /* wishful thinking */ get_first_server(); sprintf(pid_file,"pid.%s",origbotname); /* check for pre-existing eggdrop! */ f=fopen(pid_file,"r"); if (f!=NULL) { fgets(s,10,f); xx=atoi(s); kill(xx,SIGCHLD); /* meaningless kill to determine if pid is used */ if (errno!=ESRCH) { printf("I detect %s already running from this directory.\n",origbotname); printf("If this is incorrect, erase the '%s' file.\n\n",pid_file); exit(1); } } i=count_users(userlist); use_stderr=0; #ifndef NO_IRC j=0; chan=chanset; while (chan!=NULL) { j++; chan=chan->next; } #endif strcpy(s,ctime(&now)); s[strlen(s)-1]=0; strcpy(&s[11],&s[20]); putlog(LOG_ALL,"*",""); putlog(LOG_ALL,"*","--- Loading %s (%s)",ver,s); #ifdef NO_IRC putlog(LOG_ALL,"*","=== %s: in limbo, %d users.",botname,i); use_stderr=1; printf("%s: in limbo, %d users.\n",botname,i); #else putlog(LOG_ALL,"*","=== %s: %d channel%s, %d users.",botname,j,j==1?"":"s", i); use_stderr=1; printf("%s: %d channel%s, %d users.\n",botname,j,j==1?"":"s",i); #endif /* move into background? */ if (backgrd) { xx=fork(); if (xx==-1) fatal("CANNOT FORK PROCESS.",0); if (xx!=0) { FILE *fp; printf("Launched into the background (pid: %d)\n\n",xx); /* write pid to file */ unlink(pid_file); fp=fopen(pid_file,"w"); if (fp!=NULL) { fprintf(fp,"%u\n",xx); fclose(fp); } else printf("* Warning! Could not write %s file!\n",pid_file); #if HAVE_SETPGID setpgid(xx,xx); #endif exit(0); } } use_stderr=0; /* stop writing to stderr now */ if (backgrd) { /* ok, try to disassociate from controlling terminal */ /* (finger cross) */ #if HAVE_SETPGID setpgid(0,0); #endif /* close out stdin/out/err */ freopen("/dev/null","r",stdin); freopen("/dev/null","w",stdout); freopen("/dev/null","w",stderr); /* tcl wants those file handles kept open */ /* close(0); close(1); close(2); */ } /* terminal emulating dcc chat */ if ((!backgrd) && (term_z)) { int n=dcc_total; dcc[n].addr=getmyip(); dcc[n].port=0; dcc[n].sock=STDOUT; dcc[n].type=DCC_CHAT; set_chat(n); dcc[n].u.chat->away=NULL; dcc[n].u.chat->status=STAT_MASTER; dcc[n].u.chat->timer=time(NULL); dcc[n].u.chat->msgs_per_sec=0; dcc[n].u.chat->con_flags=conmask; dcc[n].u.chat->channel=0; strcpy(dcc[n].nick,"HQ"); strcpy(dcc[n].host,"local console"); setsock(STDOUT,0); /* entry in net table */ dprintf(n,"\n### ENTERING DCC CHAT SIMULATION ###\n\n"); dcc_total++; dcc_chatter(n); } #ifndef NO_IRC /* now connect to a server: */ newserver[0]=0; newserverport=0; connect_server(); #else /* initialize irc things so they won't bother us */ serv=(-1); dccdir[0]=0; strcpy(botname,origbotname); #endif then=time(NULL); online_since=time(NULL); auto_link_tandem(NULL); /* hurry and connect to tandem bots */ while(1) { context; now=time(NULL); if (now!=then) { /* once a second */ static int cnt=0; context; timecnt++; /* time to dequeue a msg? */ if (timecnt==msgrate) { deq_msg(); timecnt=0; } check_utimers(); /* secondly timers */ cnt++; if (cnt>=10) { /* every 10 seconds */ cnt=0; if ((con_chan) && (!backgrd)) { tprintf(STDOUT,"\033[2J\033[1;1H"); tell_verbose_status(DP_STDOUT,0); tell_mem_status_dcc(DP_STDOUT); } } if ((!online) && (now-online_since >= 60)) online=1; } nowtm=localtime(&now); then=now; if ((online) && (nowtm->tm_min != lastmin)) { /* once a minute */ context; lastmin=(lastmin+1)%60; #ifndef NO_IRC check_lonely_channels(); if (keepnick) { if (strcmp(botname,origbotname)!=0) { /* if i'm not using my intended nickname, try to recapture it */ strcpy(newbotname,botname); strcpy(botname,origbotname); tprintf(serv,"NICK %s\n",botname); waiting_for_awake=0; } else if (newbotname[0]) { newbotname[0]=0; waiting_for_awake=0; putlog(LOG_MISC,"*","Regained nickname '%s'. (?)",botname); } } check_idle_kick(); /* join any channels that aren't active or pending */ chan=chanset; while (chan!=NULL) { if (!(chan->stat&(CHANACTIVE|CHANPEND))) mprintf(serv,"JOIN %s\n",chan->name); chan=chan->next; } check_expired_splits(); check_expired_ignores(); check_expired_bans(); check_for_split(); /* am *I* split? */ check_expired_chanbans(); #endif /* ifndef NO_IRC */ check_expired_dcc(); check_expired_tbufs(); auto_link_tandem(NULL); /* attempt autolinks */ check_timers(); /* in case for some reason more than 1 min has passed: */ i=0; while (nowtm->tm_min!=lastmin) { /* timer drift, dammit */ check_timers(); i++; lastmin=(lastmin+1)%60; } if (i>1) putlog(LOG_MISC,"*","(!) timer drift -- spun %d minutes",i); } context; if (((int)(nowtm->tm_min/5)*5) == (nowtm->tm_min)) { /* 5 min */ if (!fivemin) { fivemin=1; #ifndef NO_IRC log_chans(); #ifdef CHECK_STONED if (waiting_for_awake) { /* uh oh! never got pong from last time, five minutes ago! */ /* server is probably stoned */ killsock(serv); serv=(-1); /* will reconnect about 50 lines down */ putlog(LOG_SERV,"*","Server got stoned; jumping..."); } else { /* check for server being stoned */ if ((serv>=0) && !trying_server) { tprintf(serv,"PING :%lu\n",(unsigned long)time(NULL)); waiting_for_awake=1; } } #endif /* CHECK_STONED */ #endif /* !NO_IRC */ check_botnet_pings(); } } else fivemin=0; context; miltime=(nowtm->tm_hour*100)+(nowtm->tm_min); if (miltime==0) { /* at midnight */ if (!midnite) { midnite=1; strcpy(s,ctime(&now)); s[strlen(s)-1]=0; strcpy(&s[11],&s[20]); putlog(LOG_MISC,"*","--- %s",s); } } else midnite=0; if (miltime==switch_logfiles_at) { if (!switched) { switched=1; putlog(LOG_MISC,"*","Backing up user file..."); strcpy(s,userfile); strcat(s,"~bak"); copyfile(userfile,s); expire_notes(); putlog(LOG_MISC,"*","Switching logfiles..."); for (i=0; itm_min==save_users_at) { /* hourly! */ if (!hourly) { hourly=1; write_userfile(); } } else hourly=0; #ifdef MODERN_TCL /* now Tcl has an event loop too, whee */ /* Tcl_DoOneEvent(TCL_DONT_WAIT); -breaks a lot */ #endif context; #ifndef NO_IRC if (serv<0) { clear_channels(); connect_server(); } context; #endif /* clean up sockets that were just left for dead */ for (i=0; i=0) { /* non-error */ context; #ifdef NO_IRC dcc_activity(xx,buf,i); #else if (xx!=serv) dcc_activity(xx,buf,i); else { /* SERVER ACTIVITY */ context; if (trying_server) { putlog(LOG_SERV,"*","Connected to %s",botserver); if (initserver[0]) do_tcl("init-server",initserver); trying_server=0L; waiting_for_awake=0; } strcpy(s,buf); parsemsg(buf,from,code,msg); fixfrom(from); #ifdef USE_CONSOLE_R if ((strcmp(code,"PRIVMSG")==0) || (strcmp(code,"NOTICE")==0)) { if (!match_ignore(from)) { putlog(LOG_RAW,"*","[@] %s",s); check_tcl_raw(s); } } else { putlog(LOG_RAW,"*","[@] %s",s); check_tcl_raw(s); } #endif if (strcmp(code,"PRIVMSG")==0) { if (!match_ignore(from)) gotmsg(from,msg); } else if (strcmp(code,"NOTICE")==0) { if (!match_ignore(from)) gotnotice(from,msg); } else if (strcmp(code,"MODE")==0) gotmode(from,msg); else if (strcmp(code,"JOIN")==0) gotjoin(from,msg); else if (strcmp(code,"PART")==0) gotpart(from,msg); else if (strcmp(code,"ERROR")==0) goterror(from,msg); else if (strcmp(code,"PONG")==0) gotpong(from,msg); else if (strcmp(code,"001")==0) got001(from,msg); else if (strcmp(code,"251")==0) got251(from,msg); else if (strcmp(code,"315")==0) got315(from,msg); else if (strcmp(code,"324")==0) got324(from,msg); else if (strcmp(code,"331")==0) got331(from,msg); else if (strcmp(code,"332")==0) got332(from,msg); else if (strcmp(code,"352")==0) got352(from,msg); else if (strcmp(code,"367")==0) got367(from,msg); else if (strcmp(code,"368")==0) got368(from,msg); else if (strcmp(code,"405")==0) got405(from,msg); else if (strcmp(code,"432")==0) got432(from,msg); else if (strcmp(code,"433")==0) got433(from,msg); else if (strcmp(code,"471")==0) got471(from,msg); else if (strcmp(code,"473")==0) got473(from,msg); else if (strcmp(code,"474")==0) got474(from,msg); else if (strcmp(code,"475")==0) got475(from,msg); else if (strcmp(code,"QUIT")==0) gotquit(from,msg); else if (strcmp(code,"NICK")==0) { gotnick(from,msg); detect_flood(from,NULL,FLOOD_NICK,1); } else if (strcmp(code,"KICK")==0) gotkick(from,msg); else if (strcmp(code,"INVITE")==0) gotinvite(from,msg); else if ((strcmp(code,"375")==0) || (strcmp(code,"376")==0) || (strcmp(code,"372")==0)) ; /* ignore motd */ else if (strcmp(code,"TOPIC")==0) gottopic(from,msg); else if (strcmp(code,"PING")==0) { fixcolon(msg); tprintf(serv,"PONG :%s\n",msg); } } /* in periods of high traffic (sockgets always returns info), only */ /* flush the stacked modes every 5th time -- in calmer times (when */ /* sockgets sometimes spends a whole second with no input) dump out */ /* any pending modes */ if (modecnt==4) flush_modes(); /* dump all mode changes */ modecnt=(modecnt+1)%5; #endif /* NO_IRC */ } else if (xx==-1) { /* EOF from someone */ context; #ifdef NO_IRC if ((i!=STDOUT) || backgrd) eof_dcc(i); else fatal("EOF ON TERMINAL",1); #else if (i==serv) { /* we lost this server, dammit */ putlog(LOG_SERV,"*","Disconnected from %s",botserver); clear_channels(); /* we're not on any channels any more */ killsock(serv); connect_server(); } else if ((i!=STDOUT) || backgrd) eof_dcc(i); else fatal("END OF FILE ON TERMINAL",1); #endif } else if ((xx==-2) && (errno!=EINTR)) { /* select() error */ context; putlog(LOG_MISC,"*","* Socket error #%d; recovering.",errno); #ifndef NO_IRC if (fcntl(serv,F_GETFD,0)==(-1)) { putlog(LOG_MISC,"*","Server socket expired -- pfft"); killsock(serv); serv=(-1); } #endif for (i=0; i