/* dcc shtuff */ #include #include #include #include #include #include #include #include /* hpux needs for ntohl */ #include "eggdrop.h" /* dcc list */ struct dcc_t dcc[MAXDCC]; /* total dcc's */ int dcc_total=0; /* root dcc directory */ char dccdir[121]=""; /* directory to put incoming dcc's into */ char dccin[121]=""; /* temporary directory (default: current dir) */ char tempdir[121]=""; /* if non-zero, accept telnets at this port */ int telnet_port=0; /* file where the motd for dcc chat is stored */ char motdfile[121]="motd"; /* require 'p' access to get on the party line? */ int require_p=0; /* let all uploads go to the user's current directory? */ int upload_to_cd=0; extern int serv; extern char botname[]; extern char origbotname[]; extern char version[]; extern char ver[]; extern char botchan[]; extern int require_x; unsigned long getmyip(); extern char userfile[]; extern int isolate; extern char admin[]; extern int conmask; extern char os[]; extern char cx_file[]; extern int cx_line; extern struct userrec *userlist; int expmem_dcc() { int tot,i,j; tot=0; for (i=0; iaway!=NULL) tot+=strlen(dcc[i].u.chat->away)+1; } if ((j==DCC_FILES) || (j==DCC_FILES_PASS)) { tot+=sizeof(struct file_info)+sizeof(struct chat_info); if (dcc[i].u.file->chat->away!=NULL) tot+=strlen(dcc[i].u.file->chat-> away)+1; } if (j==DCC_EDIT) { tot+=sizeof(struct edit_info)+sizeof(struct chat_info); if (dcc[i].u.edit->chat->away!=NULL) tot+=strlen(dcc[i].u.edit->chat-> away)+1; } if ((j==DCC_SEND) || (j==DCC_GET) || (j==DCC_GET_PENDING)) tot+=sizeof(struct xfer_info); if ((j==DCC_TANDEM) || (j==DCC_TANDEM_NEW)) tot+=sizeof(struct tand_info); if ((j==DCC_RELAY) || (j==DCC_RELAYING)) { tot+=sizeof(struct relay_info)+sizeof(struct chat_info); if (dcc[i].u.relay->chat->away!=NULL) tot+=strlen(dcc[i].u.relay->chat-> away)+1; } if (j==DCC_FORK) { tot+=sizeof(struct fork_info); switch(dcc[i].u.fork->type) { case DCC_CHAT: tot+=sizeof(struct chat_info); break; case DCC_FILES: tot+=sizeof(struct file_info)+sizeof(struct chat_info); break; case DCC_SEND: tot+=sizeof(struct xfer_info); break; case DCC_TANDEM: tot+=sizeof(struct tand_info); break; case DCC_RELAY: tot+=sizeof(struct relay_info)+sizeof(struct chat_info); break; } } } return tot; } void chatout(va_alist) va_dcl { int i; va_list(va); char *format; char s[512]; va_start(va); format=va_arg(va,char *); vsprintf(s,format,va); for (i=0; ichannel==chan) tputs(dcc[i].sock,s); va_end(va); } void tandout(va_alist) va_dcl { int i; va_list va; char *format; char s[512]; va_start(va); format=va_arg(va,char *); vsprintf(s,format,va); for (i=0; istatus&STAT_SHARE) && (!(dcc[i].u.tand->status&STAT_GETTING)) && (!(dcc[i].u.tand->status&STAT_SENDING))) tputs(dcc[i].sock,s); q_resync(s); va_end(va); } void shareout_but(va_alist) va_dcl { int i,x; va_list va; char *format; char s[512]; va_start(va); x=va_arg(va,int); format=va_arg(va,char *); vsprintf(s,format,va); for (i=0; istatus&STAT_SHARE) && (!(dcc[i].u.tand->status&STAT_GETTING)) && (!(dcc[i].u.tand->status&STAT_SENDING))) tputs(dcc[i].sock,s); q_resync(s); va_end(va); } /* print to all but one */ void chatout_but(va_alist) va_dcl { int i,x; va_list va; char *format; char s[512]; va_start(va); x=va_arg(va,int); format=va_arg(va,char *); vsprintf(s,format,va); for (i=0; ichannel==chan) tputs(dcc[i].sock,s); va_end(va); } /* ditto for tandem bots */ void tandout_but(va_alist) va_dcl { int i,x; va_list va; char *format; char s[512]; va_start(va); x=va_arg(va,int); format=va_arg(va,char *); vsprintf(s,format,va); for (i=0; ichannel>=0)) || ((chan>=0) && (dcc[i].u.chat->channel==chan))) tprintf(z,"whom %s %s%c%s %s %s%s%s\n",nick,(dcc[i].u.chat->channel==0) &&(chan==(-1))?"+":"",dcc[i].u.chat->status&STAT_MASTER?'*': (dcc[i].u.chat->status&STAT_PARTY?'-':'@'),dcc[i].nick, origbotname,dcc[i].host,dcc[i].u.chat->away==NULL?"":" [AWAY]", now-dcc[i].u.chat->timer>300?" [idle]":""); } void answer_local_whom(z,chan) int z,chan; { int i; time_t now=time(NULL); if (chan==(-1)) tprintf(z,"Users across the bot network (+: party line)\n"); else if (chan>0) tprintf(z,"Users listening on channel %d:\n",chan); tprintf(z,"%-10s %-9s Host\n","Nick","Bot"); tprintf(z,"---------- --------- ------------------------------\n"); for (i=0; i=0) && (dcc[i].u.chat->channel==chan))) tprintf(z,"%c%-9s %c %-9s %s%s%s\n",dcc[i].u.chat->status&STAT_MASTER? '*':(dcc[i].u.chat->status&STAT_PARTY?' ':'@'),dcc[i].nick, (dcc[i].u.chat->channel==0)&&(chan==(-1))?'+':' ',origbotname, dcc[i].host,(dcc[i].u.chat->away!=NULL)?" [AWAY]":"", now-dcc[i].u.chat->timer>300?" [idle]":""); } if (isolate) tprintf(z,"This bot is isolated from any joint party line.\n"); } void tell_tandem_info(z,nick) int z; char *nick; { #ifdef TCL tprintf(z,"priv %s %s Channel: %s (%s under %s/Tcl)\n",origbotname,nick, botchan,ver,os); #else tprintf(z,"priv %s %s Channel: %s (%s under %s)\n",origbotname,nick,botchan, ver,os); #endif if (admin[0]) tprintf(z,"priv %s %s Admin: %s\n",origbotname,nick,admin); if (isolate) tprintf(z,"priv %s %s (I'm isolated from the joint party line.)\n", origbotname,nick); } void tell_tandem_who(z,nick,chan) int z; char *nick; int chan; { int i,k,ok=0; char s[121]; time_t tt; tt=time(NULL); tell_tandem_info(z,nick); if (!isolate) { if (chan==0) tprintf(z,"priv %s %s Party line members: (* = master, @ = op)\n", origbotname,nick); else tprintf(z,"priv %s %s People on channel %d: (* = master, @ = op)\n", origbotname,nick,chan); for (i=0; ichannel==chan) { sprintf(s,"| %c%-10s %s",dcc[i].u.chat->status&STAT_MASTER? '*':(dcc[i].u.chat->status&STAT_PARTY?' ':'@'),dcc[i].nick, dcc[i].host); if (tt - dcc[i].u.chat->timer > 300) { k=(tt-dcc[i].u.chat->timer)/60; if (k<60) sprintf(&s[strlen(s)]," (idle %dm)",k); else sprintf(&s[strlen(s)]," (idle %dh%dm)",k/60,k%60); } tprintf(z,"priv %s %s %s\n",origbotname,nick,s); if (dcc[i].u.chat->away!=NULL) tprintf(z,"priv %s %s | AWAY: %s\n",origbotname,nick, dcc[i].u.chat->away); } } for (i=0; i status&STAT_CALLED?"<-":"->",dcc[i].u.tand->status&STAT_SHARE? '+':' ',dcc[i].nick,dcc[i].u.tand->version); } ok=0; for (i=0; ichannel!=chan) { if (!ok) { ok=1; tprintf(z,"priv %s %s Other people on the bot:\n",origbotname, nick); } sprintf(s," %c%-10s %s",dcc[i].u.chat->status&STAT_MASTER?'*': (dcc[i].u.chat->status&STAT_PARTY?' ':'@'),dcc[i].nick, dcc[i].host); if (tt - dcc[i].u.chat->timer > 300) { k=(tt-dcc[i].u.chat->timer)/60; if (k<60) sprintf(&s[strlen(s)]," (idle %dm)",k); else sprintf(&s[strlen(s)]," (idle %dh%dm)",k/60,k%60); } tprintf(z,"priv %s %s |%s\n",origbotname,nick,s); if (dcc[i].u.chat->away!=NULL) tprintf(z,"priv %s %s | AWAY: %s\n",origbotname,nick, dcc[i].u.chat->away); } } void tell_who(z,chan) int z,chan; { int i,j,k,ok=0; char s[121]; time_t tt; for (j=0; dcc[j].sock!=z; j++); tt=time(NULL); if (chan==0) tprintf(z,"Party line members: (* = master, @ = op)\n"); else tprintf(z,"People on channel %d: (* = master, @ = op)\n",chan); for (i=0; ichannel==chan) { sprintf(s," %c%-10s %s",dcc[i].u.chat->status&STAT_MASTER?'*': (dcc[i].u.chat->status&STAT_PARTY?' ':'@'),dcc[i].nick, dcc[i].host); if (dcc[j].u.chat->status&STAT_MASTER) { if (dcc[i].u.chat->con_flags) sprintf(&s[strlen(s)]," (con:%s)",masktype(dcc[i].u.chat-> con_flags)); if (dcc[i].u.chat->status&STAT_TALK) strcat(s," (talk)"); } if (tt - dcc[i].u.chat->timer > 300) { k=(tt-dcc[i].u.chat->timer)/60; if (k<60) sprintf(&s[strlen(s)]," (idle %dm)",k); else sprintf(&s[strlen(s)]," (idle %dh%dm)",k/60,k%60); } tprintf(z,"%s\n",s); if (dcc[i].u.chat->away!=NULL) tprintf(z," AWAY: %s\n",dcc[i].u.chat->away); } for (i=0; itimer)); strcpy(s,&s[1]); s[9]=0; strcpy(s,&s[7]); s[2]=' '; strcpy(&s[7],&s[10]); s[12]=0; tprintf(z," %s%c%-10s (%s) %s\n",dcc[i].u.tand->status&STAT_CALLED? "<-":"->",dcc[i].u.tand->status&STAT_SHARE?'+':' ',dcc[i].nick, s,dcc[i].u.tand->version); } ok=0; for (i=0; ichannel!=chan) { if (!ok) { ok=1; tprintf(z,"Other people on the bot:\n"); } sprintf(s," %c%-10s ",dcc[i].u.chat->status&STAT_MASTER?'*': (dcc[i].u.chat->status&STAT_PARTY?' ':'@'),dcc[i].nick); if (dcc[j].u.chat->status&STAT_MASTER) { if (dcc[i].u.chat->channel<0) strcat(s,"(-OFF-) "); else if (dcc[i].u.chat->channel==0) strcat(s,"(party) "); else sprintf(&s[strlen(s)],"(%5d) ",dcc[i].u.chat->channel); } strcat(s,dcc[i].host); if (dcc[j].u.chat->status&STAT_MASTER) { if (dcc[i].u.chat->con_flags) sprintf(&s[strlen(s)]," (con:%s)",masktype(dcc[i].u.chat-> con_flags)); if (dcc[i].u.chat->status&STAT_TALK) strcat(s," (talk)"); } if (tt - dcc[i].u.chat->timer > 300) { k=(tt-dcc[i].u.chat->timer)/60; if (k<60) sprintf(&s[strlen(s)]," (idle %dm)",k); else sprintf(&s[strlen(s)]," (idle %dh%dm)",k/60,k%60); } tprintf(z,"%s\n",s); if (dcc[i].u.chat->away!=NULL) tprintf(z," AWAY: %s\n",dcc[i].u.chat->away); } } void dcc_chatter(z) int z; { int i,j; for (j=0; dcc[j].sock!=z; j++); tprintf(z,"Connected to %s, running %s\n",botname,version); show_motd(j); /* tell_who(z); */ tprintf(z,"Commands start with '.' (like '.quit' or '.help')\n"); tprintf(z,"Everything else goes out to the party line.\n\n"); chanout(dcc[j].u.chat->channel,"*** %s (%s) joined the party line.\n", dcc[j].nick,dcc[j].host); if (!isolate) tandout("chan %s %d %s joined the party line.\n",origbotname, dcc[j].u.chat->channel,dcc[j].nick); notes_read(dcc[j].nick,"",-1,z); } /* remove entry from dcc list */ void lostdcc(n) int n; { int i; switch(dcc[n].type) { case DCC_CHAT: case DCC_TELNET_ID: case DCC_CHAT_PASS: if (dcc[n].u.chat->away!=NULL) nfree(dcc[n].u.chat->away); nfree(dcc[n].u.chat); break; case DCC_FILES_PASS: case DCC_FILES: nfree(dcc[n].u.file->chat); nfree(dcc[n].u.file); break; case DCC_EDIT: nfree(dcc[n].u.edit->chat); nfree(dcc[n].u.edit); break; case DCC_SEND: case DCC_GET: case DCC_GET_PENDING: nfree(dcc[n].u.xfer); break; case DCC_TANDEM: case DCC_TANDEM_NEW: nfree(dcc[n].u.tand); break; case DCC_RELAY: case DCC_RELAYING: nfree(dcc[n].u.relay->chat); nfree(dcc[n].u.relay); break; case DCC_FORK: switch (dcc[n].u.fork->type) { case DCC_CHAT: nfree(dcc[n].u.fork->u.chat); break; case DCC_FILES: nfree(dcc[n].u.fork->u.file->chat); nfree(dcc[n].u.fork->u.file); break; case DCC_TANDEM: nfree(dcc[n].u.fork->u.tand); break; case DCC_RELAY: nfree(dcc[n].u.fork->u.relay->chat); nfree(dcc[n].u.fork->u.relay); break; case DCC_SEND: nfree(dcc[n].u.fork->u.xfer); break; } nfree(dcc[n].u.fork); break; } dcc_total--; for (i=n; i17) strcpy(s,&dcc[i].host[strlen(dcc[i].host)-17]); else strcpy(s,dcc[i].host); switch (dcc[i].type) { case DCC_CHAT: strcpy(x,"chat"); sprintf(other,"flags: %s/%d",stat_str(dcc[i].u.chat->status), dcc[i].u.chat->channel); break; case DCC_CHAT_PASS: strcpy(x,"pass"); sprintf(other,"waited %lus",now-dcc[i].u.chat->timer); break; case DCC_SEND: strcpy(x,"send"); sprintf(other,"%lu/%lu",dcc[i].u.xfer->sent,dcc[i].u.xfer->length); break; case DCC_GET: strcpy(x,"get"); sprintf(other,"%lu/%lu",dcc[i].u.xfer->sent,dcc[i].u.xfer->length); break; case DCC_GET_PENDING: strcpy(x,"getp"); sprintf(other,"waited %lus",now-dcc[i].u.xfer->pending); break; case DCC_TELNET: strcpy(x,"teln"); other[0]=0; break; case DCC_TELNET_ID: strcpy(x,"t-in"); sprintf(other,"waited %lus",now-dcc[i].u.chat->timer); break; case DCC_FILES: strcpy(x,"file"); sprintf(other,"flags: %s",stat_str(dcc[i].u.file->chat->status)); break; case DCC_EDIT: strcpy(x,"edit"); sprintf(other,"BROKEN"); break; case DCC_TANDEM: strcpy(x,"tand"); sprintf(other,"flags: %s",stat_str2(dcc[i].u.tand->status)); break; case DCC_TANDEM_NEW: strcpy(x,"tnd*"); sprintf(other,"waited %lus",now-dcc[i].u.tand->timer); break; case DCC_RELAY: strcpy(x,"rela"); sprintf(other,"-> sock %d",dcc[i].u.relay->sock); break; case DCC_RELAYING: strcpy(x,">rly"); sprintf(other,"-> sock %d",dcc[i].u.relay->sock); break; case DCC_FORK: strcpy(x,"fork"); switch(dcc[i].u.fork->type) { case DCC_CHAT: strcpy(other,"chat"); break; case DCC_FILES: strcpy(other,"file"); break; case DCC_TANDEM: strcpy(other,"tand"); break; case DCC_RELAY: strcpy(other,"rela"); break; case DCC_SEND: strcpy(other,"send"); break; } break; case DCC_FILES_PASS: strcpy(x,"fpas"); sprintf(other,"waited %lus",now-dcc[i].u.file->chat->timer); break; case DCC_LOST: strcpy(x,"LOST"); sprintf(other,"(zombie)"); break; default: sprintf(x,"?:%02d",dcc[i].type); sprintf(other,"!! ERROR !!"); break; } if (dcc[i].type==DCC_FORK) tprintf(z,"%2d (*) %08X %5d %-9s %-17s %-4s %s\n",i,dcc[i].addr, dcc[i].port,dcc[i].nick,s,x,other); else tprintf(z,"%2d %-4d %08X %5d %-9s %-17s %-4s %s\n",i,dcc[i].sock, dcc[i].addr,dcc[i].port,dcc[i].nick,s,x,other); if ((dcc[i].type==DCC_SEND) || (dcc[i].type==DCC_GET)) tprintf(z," Filename: %s\n",dcc[i].u.xfer->filename); if (dcc[i].type==DCC_FORK) tell_dcc_proc(z,i); } } /* mark someone on dcc chat as no longer away */ void not_away(idx,z) int idx,z; { int i; if (dcc[idx].u.chat->away==NULL) { tprintf(z,"You weren't away!\n"); return; } if (dcc[idx].u.chat->channel>=0) { chanout(dcc[idx].u.chat->channel,"*** %s is no longer away.\n", dcc[idx].nick); if (!isolate) tandout("chan %s %d %s is no longer away.\n",origbotname, dcc[idx].u.chat->channel,dcc[idx].nick); } tprintf(z,"You're not away any more.\n"); nfree(dcc[idx].u.chat->away); dcc[idx].u.chat->away=NULL; notes_read(dcc[idx].nick,"",-1,z); } void set_away(idx,z,s) int idx,z; char *s; { if (s==NULL) { not_away(idx,z); return; } if (!s[0]) { not_away(idx,z); return; } if (dcc[idx].u.chat->away!=NULL) nfree(dcc[idx].u.chat->away); dcc[idx].u.chat->away=(char *)nmalloc(strlen(s)+1); strcpy(dcc[idx].u.chat->away,s); if (dcc[idx].u.chat->channel>=0) { chanout(dcc[idx].u.chat->channel,"*** %s is now away: %s\n",dcc[idx].nick, s); if (!isolate) tandout("chan %s %d %s is now away: %s\n",origbotname, dcc[idx].u.chat->channel,dcc[idx].nick,s); } tprintf(z,"You are now away; notes will be stored.\n"); } void set_files(idx,z) int idx,z; { struct chat_info *ci; ci=dcc[idx].u.chat; dcc[idx].u.file=(struct file_info *)nmalloc(sizeof(struct file_info)); dcc[idx].u.file->chat=ci; } void set_tand(idx) int idx; { dcc[idx].u.tand=(struct tand_info *)nmalloc(sizeof(struct tand_info)); } void set_chat(idx) int idx; { dcc[idx].u.chat=(struct chat_info *)nmalloc(sizeof(struct chat_info)); } void set_xfer(idx) int idx; { dcc[idx].u.xfer=(struct xfer_info *)nmalloc(sizeof(struct xfer_info)); } void get_file_ptr(p) struct file_info **p; { (*p)=(struct file_info *)nmalloc(sizeof(struct file_info)); } void get_chat_ptr(p) struct chat_info **p; { (*p)=(struct chat_info *)nmalloc(sizeof(struct chat_info)); } void get_xfer_ptr(p) struct xfer_info **p; { (*p)=(struct xfer_info *)nmalloc(sizeof(struct xfer_info)); } void set_fork(idx) int idx; { void *hold; hold=dcc[idx].u.other; dcc[idx].u.fork=(struct fork_info *)nmalloc(sizeof(struct fork_info)); dcc[idx].u.fork->u.other=hold; dcc[idx].u.fork->type=dcc[idx].type; dcc[idx].type=DCC_FORK; } void set_relay(idx) int idx; { dcc[idx].u.relay=(struct relay_info *)nmalloc(sizeof(struct relay_info)); } void set_new_relay(idx) int idx; { set_relay(idx); dcc[idx].u.relay->chat=(struct chat_info *)nmalloc(sizeof(struct chat_info)); } /* make a password, 6-9 random letters and digits */ void makepass(s) char *s; { int i,j,k; i=6+(random()%4); for (j=0; j=dcc_total) return; if (dcc[idx].type==DCC_CHAT_PASS) { if (pass_match_by_handle(buf,dcc[idx].nick)) { if (get_attr_handle(dcc[idx].nick) & USER_TANDEM) { nfree(dcc[idx].u.chat); dcc[idx].u.tand=(struct tand_info *)nmalloc(sizeof(struct tand_info)); dcc[idx].type=DCC_TANDEM; dcc[idx].u.tand->status=STAT_CALLED; dcc[idx].u.tand->timer=time(NULL); dcc[idx].u.tand->version[0]=0; dcc[idx].u.tand->user=NULL; if (get_attr_handle(dcc[idx].nick) & BOT_LEAF) dcc[idx].u.tand->status|=STAT_LEAF; tprintf(z,"*hello!\n"); tprintf(z,"version %s %s\n",botchan,ver); tprintf(z,"thisbot %s\n",origbotname); stop_auto(dcc[idx].nick); log(LOG_TAND,"Linked to tandem-bot: %s",dcc[idx].nick); tandout_but(idx,"chat %s Linked to tandem-bot: %s\n",origbotname, dcc[idx].nick); tandout_but(idx,"nlinked %s %s\n",dcc[idx].nick,origbotname); dump_links(z); addbot(dcc[idx].nick,dcc[idx].nick); chatout("*** Linked to tandem-bot: %s\n",dcc[idx].nick); } else { dcc[idx].type=DCC_CHAT; dcc[idx].u.chat->status&=~STAT_CHAT; if (dcc[idx].u.chat->status&STAT_MASTER) dcc[idx].u.chat->con_flags=conmask; dcc_chatter(z); } } else { if (get_attr_handle(dcc[idx].nick) & USER_TANDEM) tprintf(z,"badpass\n"); else tprintf(z,"Authentification failed.\n"); log(LOG_MISC,"Bad password: DCC chat [%s]%s",dcc[idx].nick, dcc[idx].host); close(z); shutdown(z,2); lostdcc(idx); } } else if (dcc[idx].type==DCC_FILES_PASS) { if (pass_match_by_handle(buf,dcc[idx].nick)) { dcc[idx].type=DCC_FILES; log(LOG_MISC,"File system: [%s]%s/%d",dcc[idx].nick,dcc[idx].host, dcc[idx].port); welcome_to_files(idx,z); } else { tprintf(z,"Authentification failed.\n"); log(LOG_MISC,"Bad password: DCC chat [%s]%s",dcc[idx].nick, dcc[idx].host); close(z); shutdown(z,2); lostdcc(idx); } } #ifndef EXT_EDITOR else if (dcc[idx].type==DCC_EDIT) { got_cmd_edit(idx,z,buf); } #endif else if (dcc[idx].type==DCC_TANDEM_NEW) { if (strcasecmp(buf,"*hello!")==0) { dcc[idx].type=DCC_TANDEM; stop_auto(dcc[idx].nick); log(LOG_TAND,"Linked to tandem-bot: %s",dcc[idx].nick); tprintf(dcc[idx].sock,"version %s %s\n",botchan,ver); tprintf(dcc[idx].sock,"thisbot %s\n",origbotname); tandout_but(idx,"chat %s Linked to tandem-bot: %s\n",origbotname, dcc[idx].nick); tandout_but(idx,"nlinked %s %s\n",dcc[idx].nick,origbotname); dump_links(dcc[idx].sock); addbot(dcc[idx].nick,dcc[idx].nick); chatout("*** Linked to tandem-bot: %s\n",dcc[idx].nick); } if (strcasecmp(buf,"badpass")==0) { /* we entered the wrong password */ log(LOG_TAND,"Bad password on connect attempt to %s.",dcc[idx].nick); } if (strcasecmp(buf,"passreq")==0) { if (pass_match_by_handle("nopass",dcc[idx].nick)) { log(LOG_TAND,"Password required for connection to %s.",dcc[idx].nick); tprintf(z,"nopass\n"); } } /* ignore otherwise */ } else if (dcc[idx].type==DCC_TANDEM) { got_tandem(idx,z,buf); } else if (dcc[idx].type==DCC_CHAT) { if (!detect_dcc_flood(dcc[idx].u.chat,idx)) { if ((buf[0]=='.') || (dcc[idx].u.chat->channel<0)) { if (buf[0]=='.') strcpy(buf,&buf[1]); if (got_dcc_cmd(idx,z,buf)) { tprintf(z,"Thanks! Bye!\n"); log(LOG_MISC,"DCC connection closed (%s!%s)",dcc[idx].nick, dcc[idx].host); if (dcc[idx].u.chat->channel>=0) { chanout(dcc[idx].u.chat->channel,"*** %s left the party line.\n", dcc[idx].nick); if (!isolate) tandout("chan %s %d %s left the party line.\n",origbotname, dcc[idx].u.chat->channel,dcc[idx].nick); } if (dcc[idx].u.chat->status&STAT_TALK) if (!(dcc[idx].u.chat->status&STAT_TELNET)) tprintf(z,"/// KILL\n"); if (dcc[idx].sock!=STDOUT) { close(dcc[idx].sock); shutdown(dcc[idx].sock,2); lostdcc(idx); } else { tprintf(STDOUT,"\n### SIMULATION RESET\n\n"); dcc_chatter(STDOUT); } } } else if ((buf[0]=='/') && (buf[1]=='/') && (buf[2]=='/')) got_dcc_cmd(idx,z,buf); else if (buf[0]==',') { for (i=0; istatus&STAT_MASTER) tprintf(dcc[i].sock,"-%s- %s\n",dcc[idx].nick,&buf[1]); if (dcc[i].type==DCC_FILES) if (dcc[i].u.file->chat->status& STAT_MASTER) tprintf(dcc[i].sock,"-%s- %s\n",dcc[idx].nick,&buf[1]); } } else { if (dcc[idx].u.chat->away!=NULL) not_away(idx,z); /* (auto unmark away) */ for (i=0; ichannel==dcc[idx].u.chat->channel)) tprintf(dcc[i].sock,"<%s> %s\n",dcc[idx].nick,buf); if (!isolate) tandout("chan %s@%s %d %s\n",dcc[idx].nick,origbotname, dcc[idx].u.chat->channel,buf); } } } else if (dcc[idx].type==DCC_FILES) { if (!detect_dcc_flood(dcc[idx].u.file->chat,idx)) { if (buf[0]==',') { for (i=0; istatus&STAT_MASTER) tprintf(dcc[i].sock,"-%s- %s\n",dcc[idx].nick,&buf[1]); if (dcc[i].type==DCC_FILES) if (dcc[i].u.file->chat->status& STAT_MASTER) tprintf(dcc[i].sock,"-%s- %s\n",dcc[idx].nick,&buf[1]); } } else if (got_files_cmd(idx,z,buf)) { tprintf(z,"Thanks! Bye!\n"); log(LOG_MISC,"DCC user [%s]%s left file system",dcc[idx].nick, dcc[idx].host); set_handle_dccdir(userlist,dcc[idx].nick,dcc[idx].u.file->dir); if (dcc[idx].u.file->chat->status&STAT_CHAT) { struct chat_info *ci; tprintf(z,"Returning you to command mode...\n"); if (dcc[idx].u.file->chat->status&STAT_TALK) { tprintf(z,"/// PROMPT \n"); tprintf(z,"/// ECHO OFF\n"); } ci=dcc[idx].u.file->chat; nfree(dcc[idx].u.file); dcc[idx].u.chat=ci; if (dcc[idx].u.chat->channel>=0) { chanout(dcc[idx].u.chat->channel, "*** %s (%s) joined the party line\n",dcc[idx].nick, dcc[idx].host); if (!isolate) tandout("chan %s %d %s joined the party line.\n",origbotname, dcc[idx].u.chat->channel,dcc[idx].nick); } dcc[idx].u.chat->status&=(~STAT_CHAT); dcc[idx].type=DCC_CHAT; } else { tprintf(z,"Dropping connection now.\n"); log(LOG_CMDS,"Left files: [%s]%s/%d",dcc[idx].nick,dcc[idx].host, dcc[idx].port); if (dcc[idx].u.file->chat->status&STAT_TALK) if (!(dcc[idx].u.file->chat->status&STAT_TELNET)) tprintf(z,"/// KILL\n"); close(dcc[idx].sock); shutdown(dcc[idx].sock,2); lostdcc(idx); } } } } else if (dcc[idx].type==DCC_SEND) { sprintf(s,"%s%s",tempdir,dcc[idx].u.xfer->filename); f=fopen(s,"a"); if (f==NULL) { mprintf(serv,"NOTICE %s :Disk error.\n",dcc[idx].nick); log(LOG_MISC,"Disk error: dropping dcc send %s from %s!%s",dcc[idx]. u.xfer->filename,dcc[idx].nick,dcc[idx].host); sprintf(s,"%s%s",tempdir,dcc[idx].u.xfer->filename); unlink(s); close(dcc[idx].sock); shutdown(dcc[idx].sock,2); lostdcc(idx); } else { fwrite(buf,len,1,f); dcc[idx].u.xfer->sent+=len; netint=htonl(dcc[idx].u.xfer->sent); write(dcc[idx].sock,&netint,4); fclose(f); } } else if (dcc[idx].type==DCC_GET_PENDING) { unsigned long ip; i=answer(dcc[idx].sock,s,&ip); close(dcc[idx].sock); shutdown(dcc[idx].sock,2); dcc[idx].sock=i; dcc[idx].addr=ip; if (dcc[idx].sock==-1) { neterror(s); mprintf(serv,"NOTICE %s :Bad connection (%s)\n",dcc[idx].nick, s); log(LOG_MISC,"DCC bad connection: GET %s (%s!%s)",dcc[idx].u.xfer-> filename,dcc[idx].nick,dcc[idx].host); lostdcc(idx); } else { f=fopen(dcc[idx].u.xfer->filename,"r"); if (f==NULL) { close(dcc[idx].sock); shutdown(dcc[idx].sock,2); lostdcc(idx); } else { if (dcc[idx].u.xfer->length<512) dcc[idx].u.xfer->sent=dcc[idx].u.xfer->length; else dcc[idx].u.xfer->sent=512; dcc[idx].type=DCC_GET; bf=(char *)nmalloc(dcc[idx].u.xfer->sent+1); fread(bf,dcc[idx].u.xfer->sent,1,f); write(dcc[idx].sock,bf,dcc[idx].u.xfer->sent); nfree(bf); fclose(f); } } } else if (dcc[idx].type==DCC_GET) { if (dcc[idx].u.xfer->sofar) { memcpy(&dcc[idx].u.xfer->buf[dcc[idx].u.xfer->sofar],buf,len); memcpy(buf,dcc[idx].u.xfer->buf,dcc[idx].u.xfer->sofar+len); len+=dcc[idx].u.xfer->sofar; dcc[idx].u.xfer->sofar=0; } if (len<4) { /* not a full answer */ dcc[idx].u.xfer->sofar=len; memcpy(dcc[idx].u.xfer->buf,buf,len); } else { cmp=ntohl(*(unsigned long *)(buf)); dcc[idx].u.xfer->sofar=0; if (cmp==dcc[idx].u.xfer->sent) { f=fopen(dcc[idx].u.xfer->filename,"r"); if (f==NULL) { log(LOG_MISC,"DISK ERROR: Aborted dcc send %s to %s!%s", dcc[idx].u.xfer->filename,dcc[idx].nick,dcc[idx].host); close(dcc[idx].sock); shutdown(dcc[idx].sock,2); lostdcc(idx); } else if (dcc[idx].u.xfer->sent==dcc[idx].u.xfer->length) { close(dcc[idx].sock); shutdown(dcc[idx].sock,2); log(LOG_MISC,"Finished dcc send %s to %s!%s",dcc[idx].u.xfer-> filename,dcc[idx].nick,dcc[idx].host); wipe_tmp_file(idx); lostdcc(idx); fclose(f); /* was successful */ } else { fseek(f,dcc[idx].u.xfer->sent,0); l=512; if (dcc[idx].u.xfer->sent+512 > dcc[idx].u.xfer->length) l=dcc[idx].u.xfer->length - dcc[idx].u.xfer->sent; bf=(char *)nmalloc(l+1); fread(bf,l,1,f); write(dcc[idx].sock,bf,l); nfree(bf); dcc[idx].u.xfer->sent+=l; fclose(f); } } } } else if (dcc[idx].type==DCC_TELNET) { unsigned long ip; i=dcc_total; if (i+1>MAXDCC) { j=answer(dcc[idx].sock,s,&ip); if (j!=-1) { tprintf(j,"Sorry, too many connections already.\n"); close(j); shutdown(j,2); } } else { dcc[i].sock=answer(dcc[idx].sock,s,&ip); while ((dcc[i].sock==(-1)) && (errno==EAGAIN)) dcc[i].sock=answer(dcc[idx].sock,s,&ip); if (dcc[i].sock!=-1) { sprintf(dcc[i].host,"telnet!telnet@%s",s); if (match_ignore(dcc[i].host)) { tprintf(dcc[i].sock,"\nSorry, your site is being ignored.\n\n"); close(dcc[i].sock); shutdown(dcc[i].sock,2); } else { dcc[i].addr=ip; dcc[i].port=dcc[idx].port; sprintf(dcc[i].host,"telnet from %s",s); dcc[i].type=DCC_TELNET_ID; strcpy(dcc[i].nick,"???"); dcc[i].u.chat=(struct chat_info *)nmalloc(sizeof(struct chat_info)); dcc[i].u.chat->away=NULL; dcc[i].u.chat->status=STAT_TELNET; dcc[i].u.chat->timer=time(NULL); dcc[i].u.chat->msgs_per_sec=0; dcc[i].u.chat->con_flags=0; dcc[i].u.chat->channel=0; /* party line */ tprintf(dcc[i].sock,"\n\n%s (%s)\n\n",botname,version); tprintf(dcc[i].sock,"Identify yourself (nickname).\n"); dcc_total++; log(LOG_MISC,"TELNET connection: %s",s); } } else { neterror(s1); log(LOG_MISC,"Failed TELNET incoming (%s)",s1); } } } else if (dcc[idx].type==DCC_TELNET_ID) { int ok=0,atr=get_attr_handle(buf); if ((!require_p) || (!require_x)) if (atr & USER_OP) ok=1; if (atr & (USER_MASTER|USER_XFER|USER_TANDEM|USER_PARTY)) ok=1; if (!ok) { tprintf(dcc[idx].sock,"You don't have access.\n"); log(LOG_TAND,"Refused telnet from %s (invalid handle: %s)", dcc[idx].host,buf); close(dcc[idx].sock); shutdown(dcc[idx].sock,2); lostdcc(idx); } else if ((atr & USER_TANDEM) && (in_chain(buf))) { tprintf(dcc[idx].sock,"error Already connected.\n"); log(LOG_TAND,"Refused tandem connection from %s (duplicate)",buf); close(dcc[idx].sock); shutdown(dcc[idx].sock,2); lostdcc(idx); } else if (pass_match_by_handle("nopass",buf)) { if (atr & USER_TANDEM) { char ps[20]; makepass(ps); change_pass_by_handle(buf,ps); correct_handle(buf); strcpy(dcc[idx].nick,buf); nfree(dcc[idx].u.chat); dcc[idx].u.tand=(struct tand_info *)nmalloc(sizeof(struct tand_info)); dcc[idx].u.tand->status=STAT_CALLED; dcc[idx].u.tand->timer=time(NULL); dcc[idx].u.tand->version[0]=0; dcc[idx].u.tand->user=NULL; if (atr & BOT_LEAF) dcc[idx].u.tand->status|=BOT_LEAF; tprintf(dcc[idx].sock,"*hello!\n"); tprintf(dcc[idx].sock,"thisbot %s\n",origbotname); tprintf(dcc[idx].sock,"version %s %s\n",botchan,ver); tprintf(dcc[idx].sock,"handshake %s\n",ps); stop_auto(dcc[idx].nick); log(LOG_TAND,"Linked to tandem-bot: %s",dcc[idx].nick); tandout_but(idx,"nlinked %s %s\n",dcc[idx].nick,origbotname); tandout_but(idx,"chat %s Linked to tandem-bot: %s\n",origbotname, dcc[idx].nick); dump_links(dcc[idx].sock); addbot(dcc[idx].nick,dcc[idx].nick); chatout("*** Linked to tandem-bot: %s\n",dcc[idx].nick); dcc[idx].type=DCC_TANDEM; } else { tprintf(dcc[idx].sock,"Can't telnet until you have a password set.\n"); log(LOG_MISC,"Refused telnet from [%s]%s (no password)",buf, dcc[idx].host); close(dcc[idx].sock); shutdown(dcc[idx].sock,2); lostdcc(idx); } } else { int ok=0; dcc[idx].type=DCC_CHAT_PASS; dcc[idx].u.chat->timer=time(NULL); if (atr & USER_XFER) dcc[idx].u.chat->status|=STAT_XFER; if (atr & USER_MASTER) { dcc[idx].u.chat->status|=STAT_MASTER; ok=1; } else if (atr & USER_OP) { if (!require_p) ok=1; else if (atr & USER_PARTY) ok=1; } else if (atr & USER_PARTY) { ok=1; dcc[idx].u.chat->status|=STAT_PARTY; } if (atr & USER_TANDEM) ok=1; if (!ok) { struct file_info *fi; fi=(struct file_info *)nmalloc(sizeof(struct file_info)); fi->chat=dcc[idx].u.chat; dcc[idx].u.file=fi; dcc[idx].type=DCC_FILES_PASS; } correct_handle(buf); strcpy(dcc[idx].nick,buf); if (atr & USER_TANDEM) tprintf(dcc[idx].sock,"passreq\n"); else tprintf(dcc[idx].sock,"\nEnter your password.\n"); log(LOG_MISC,"Telnet -> DCC chat: [%s]%s",dcc[idx].nick,dcc[idx].host); } } else if (dcc[idx].type==DCC_RELAY) { if (!buf[0]) tprintf(dcc[idx].u.relay->sock," \n"); else tprintf(dcc[idx].u.relay->sock,"%s\n",buf); } else if (dcc[idx].type==DCC_RELAYING) { int j; if (strcasecmp(buf,"*BYE*")==0) { struct chat_info *ci; for (j=0; dcc[j].sock!=dcc[idx].u.relay->sock; j++); tprintf(dcc[idx].sock,"\n(Breaking connection to %s.)\n",dcc[j].nick); tprintf(dcc[idx].sock,"You are now back on %s.\n\n",origbotname); log(LOG_MISC,"Relay broken: %s -> %s",dcc[idx].nick,dcc[j].nick); if (dcc[idx].u.chat->channel>=0) { chanout(dcc[idx].u.chat->channel,"*** %s joined the party line.\n", dcc[idx].nick); if (!isolate) tandout("chan %s %d %s joined the party line.\n",origbotname, dcc[idx].u.chat->channel,dcc[idx].nick); } ci=dcc[idx].u.relay->chat; nfree(dcc[idx].u.relay); dcc[idx].u.chat=ci; dcc[idx].type=DCC_CHAT; notes_read(dcc[idx].nick,"",-1,dcc[idx].sock); close(dcc[j].sock); shutdown(dcc[j].sock,2); lostdcc(j); } else tprintf(dcc[idx].u.relay->sock,"%s\n",buf); } } /* eof from dcc goes here from I/O... */ void eof_dcc(z) int z; { int idx,i; char s[121]; context; for (idx=0; dcc[idx].sock!=z; idx++); if (idx>=dcc_total) { log(LOG_MISC,"(@) EOF socket %d, not a dcc socket, not anything.",z); return; } if ((dcc[idx].type==DCC_CHAT) || (dcc[idx].type==DCC_CHAT_PASS) || (dcc[idx].type==DCC_EDIT) || (dcc[idx].type==DCC_FILES) || (dcc[idx].type==DCC_FILES_PASS)) { #ifndef EXT_EDITOR if (dcc[idx].type==DCC_EDIT) leave_edit(idx,z); #endif if (dcc[idx].type==DCC_CHAT) dcc[idx].u.chat->con_flags=0; log(LOG_MISC,"Lost dcc connection to %s!%s/%d",dcc[idx].nick,dcc[idx].host, dcc[idx].port); if ((dcc[idx].type==DCC_CHAT) || (dcc[idx].type==DCC_EDIT)) { if (dcc[idx].u.chat->channel>=0) { chanout_but(idx,dcc[idx].u.chat->channel,"*** %s lost dcc link.\n", dcc[idx].nick); if (!isolate) tandout("chan %s %d %s lost dcc link.\n",origbotname, dcc[idx].u.chat->channel,dcc[idx].nick); } } close(z); shutdown(z,2); lostdcc(idx); } else if (dcc[idx].type==DCC_TANDEM) { log(LOG_TAND,"Lost tandem bot: %s",dcc[idx].nick,dcc[idx].port); tandout_but(idx,"chat %s Lost tandem bot: %s\n",origbotname,dcc[idx].nick); tandout_but(idx,"unlinked %s\n",dcc[idx].nick); rembot(dcc[idx].nick,dcc[idx].nick); unvia(idx,dcc[idx].nick); chatout("*** Lost tandem bot: %s\n",dcc[idx].nick); cancel_user_xfer(idx); close(z); shutdown(z,2); lostdcc(idx); } else if (dcc[idx].type==DCC_TANDEM_NEW) { log(LOG_TAND,"Lost tandem bot: %s",dcc[idx].nick,dcc[idx].port); close(z); shutdown(z,2); lostdcc(idx); } else if (dcc[idx].type==DCC_TELNET_ID) { log(LOG_MISC,"Lost telnet connection to %s/%d",dcc[idx].host, dcc[idx].port); close(z); shutdown(z,2); lostdcc(idx); } else if (dcc[idx].type==DCC_SEND) { if (dcc[idx].u.xfer->length==dcc[idx].u.xfer->sent) { int ok=0,j; char ofn[121],nfn[121]; /* success */ log(LOG_MISC,"Completed dcc send %s from %s!%s",dcc[idx].u.xfer-> filename,dcc[idx].nick,dcc[idx].host); /* move the file from /tmp */ sprintf(ofn,"cp %s%s %s%s",tempdir,dcc[idx].u.xfer->filename, dcc[idx].u.xfer->dir,dcc[idx].u.xfer->filename); system(ofn); sprintf(ofn,"%s%s",tempdir,dcc[idx].u.xfer->filename); unlink(ofn); /* ^ can't just mv cos /tmp may be on a different mount */ uploaded(dcc[idx].u.xfer->filename,dcc[idx].nick, dcc[idx].u.xfer->dir); for (j=0; j filename,dcc[idx].nick,dcc[idx].host,dcc[idx].u.xfer->sent, dcc[idx].u.xfer->length); sprintf(s,"%s%s",tempdir,dcc[idx].u.xfer->filename); unlink(s); close(z); shutdown(z,2); lostdcc(idx); } } else if ((dcc[idx].type==DCC_GET_PENDING) || (dcc[idx].type==DCC_GET)) { log(LOG_MISC,"Lost dcc get %s from %s!%s",dcc[idx].u.xfer->filename, dcc[idx].nick,dcc[idx].host); wipe_tmp_file(idx); close(z); shutdown(z,2); lostdcc(idx); } else if (dcc[idx].type==DCC_RELAY) { int j; struct chat_info *ci; for (j=0; dcc[j].sock!=dcc[idx].u.relay->sock; j++); log(LOG_MISC,"Ended relay link: %s -> %s",dcc[j].nick,dcc[idx].nick); tprintf(dcc[j].sock,"\n\n*** RELAY CONNECTION DROPPED.\n"); tprintf(dcc[j].sock,"You are now back on %s.\n",origbotname); if (dcc[j].u.chat->channel>=0) { chanout(dcc[j].u.chat->channel,"*** %s rejoined the party line.\n", dcc[j].nick); if (!isolate) tandout("chan %s %d %s rejoined the party line.\n",origbotname, dcc[j].u.chat->channel,dcc[j].nick); } ci=dcc[j].u.relay->chat; nfree(dcc[j].u.relay); dcc[j].u.chat=ci; dcc[j].type=DCC_CHAT; notes_read(dcc[j].nick,"",-1,dcc[j].sock); close(dcc[idx].sock); shutdown(dcc[idx].sock,2); lostdcc(idx); } else if (dcc[idx].type==DCC_RELAYING) { int j,x=dcc[idx].u.relay->sock; log(LOG_MISC,"Lost dcc connection to [%s]%s/%d",dcc[idx].nick, dcc[idx].host,dcc[idx].port); close(dcc[idx].sock); shutdown(dcc[idx].sock,2); lostdcc(idx); for (j=0; dcc[j].sock!=x; j++); log(LOG_MISC,"(Dropping relay link to %s)",dcc[j].nick); close(dcc[j].sock); shutdown(dcc[j].sock,2); lostdcc(j); /* drop connection to the bot */ } else { log(LOG_MISC,"*** ATTENTION: DEAD SOCKET (%d) OF TYPE %d UNTRAPPED", z,dcc[idx].type); close(z); shutdown(z,2); lostdcc(idx); } } void check_expired_dcc() { int i; time_t now; char xx[121],*p; now=time(NULL); for (i=0; ipending > 300) { strcpy(xx,dcc[i].u.xfer->filename); p=strrchr(xx,'/'); mprintf(serv,"NOTICE %s :Timeout on dcc send %s.\n",dcc[i].nick,p+1); log(LOG_MISC,"DCC timeout: GET %s (%s!%s)",dcc[i].u.xfer->filename, dcc[i].nick,dcc[i].host); wipe_tmp_file(i); close(dcc[i].sock); shutdown(dcc[i].sock,2); lostdcc(i); i--; } } else if (dcc[i].type==DCC_CHAT_PASS) { if (now-dcc[i].u.chat->timer > 180) { tprintf(dcc[i].sock,"Timeout.\n"); log(LOG_MISC,"Password timeout on dcc chat: [%s]%s",dcc[i].nick, dcc[i].host); close(dcc[i].sock); shutdown(dcc[i].sock,2); lostdcc(i); i--; } } else if (dcc[i].type==DCC_FILES_PASS) { if (now-dcc[i].u.file->chat->timer > 180) { tprintf(dcc[i].sock,"Timeout.\n"); log(LOG_MISC,"Password timeout on dcc chat: [%s]%s",dcc[i].nick, dcc[i].host); close(dcc[i].sock); shutdown(dcc[i].sock,2); lostdcc(i); i--; } } else if (dcc[i].type==DCC_TELNET_ID) { if (now-dcc[i].u.chat->timer > 180) { tprintf(dcc[i].sock,"Timeout.\n"); log(LOG_MISC,"Ident timeout on telnet: %s",dcc[i].host); close(dcc[i].sock); shutdown(dcc[i].sock,2); lostdcc(i); i--; } } else if (dcc[i].type==DCC_TANDEM_NEW) { if (now-dcc[i].u.tand->timer > 60) { log(LOG_MISC,"Timeout: Tandem link to %s at %s:%d",dcc[i].nick, dcc[i].host,dcc[i].port); close(dcc[i].sock); shutdown(dcc[i].sock,2); lostdcc(i); i--; } } } }