|
|
1.1 ! root 1: /* download.cpp */ ! 2: ! 3: /* Synchronet file download routines */ ! 4: ! 5: /* $Id: download.cpp,v 1.36 2006/06/18 05:08:13 rswindell Exp $ */ ! 6: ! 7: /**************************************************************************** ! 8: * @format.tab-size 4 (Plain Text/Source Code File Header) * ! 9: * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) * ! 10: * * ! 11: * Copyright 2006 Rob Swindell - http://www.synchro.net/copyright.html * ! 12: * * ! 13: * This program is free software; you can redistribute it and/or * ! 14: * modify it under the terms of the GNU General Public License * ! 15: * as published by the Free Software Foundation; either version 2 * ! 16: * of the License, or (at your option) any later version. * ! 17: * See the GNU General Public License for more details: gpl.txt or * ! 18: * http://www.fsf.org/copyleft/gpl.html * ! 19: * * ! 20: * Anonymous FTP access to the most recent released source is available at * ! 21: * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net * ! 22: * * ! 23: * Anonymous CVS access to the development source and modification history * ! 24: * is available at cvs.synchro.net:/cvsroot/sbbs, example: * ! 25: * cvs -d :pserver:[email protected]:/cvsroot/sbbs login * ! 26: * (just hit return, no password is necessary) * ! 27: * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src * ! 28: * * ! 29: * For Synchronet coding style and modification guidelines, see * ! 30: * http://www.synchro.net/source.html * ! 31: * * ! 32: * You are encouraged to submit any modifications (preferably in Unix diff * ! 33: * format) via e-mail to [email protected] * ! 34: * * ! 35: * Note: If this box doesn't appear square, then you need to fix your tabs. * ! 36: ****************************************************************************/ ! 37: ! 38: #include "sbbs.h" ! 39: #include "telnet.h" ! 40: ! 41: /****************************************************************************/ ! 42: /* Updates downloader, uploader and downloaded file data */ ! 43: /* Must have offset, dir and name fields filled prior to call. */ ! 44: /****************************************************************************/ ! 45: void sbbs_t::downloadfile(file_t* f) ! 46: { ! 47: char str[256],fname[13]; ! 48: char tmp[512]; ! 49: int i,file; ! 50: long length,mod; ! 51: ulong l; ! 52: user_t uploader; ! 53: ! 54: getfiledat(&cfg,f); /* Get current data - right after download */ ! 55: if((length=f->size)<0L) ! 56: length=0L; ! 57: if(!(cfg.dir[f->dir]->misc&DIR_NOSTAT)) { ! 58: logon_dlb+=length; /* Update 'this call' stats */ ! 59: logon_dls++; ! 60: } ! 61: bprintf(text[FileNBytesSent],f->name,ultoac(length,tmp)); ! 62: sprintf(str,"%s downloaded %s from %s %s" ! 63: ,useron.alias ! 64: ,f->name,cfg.lib[cfg.dir[f->dir]->lib]->sname ! 65: ,cfg.dir[f->dir]->sname); ! 66: logline("D-",str); ! 67: /****************************/ ! 68: /* Update Downloader's Info */ ! 69: /****************************/ ! 70: user_downloaded(&cfg, &useron, 1, length); ! 71: if(!is_download_free(&cfg,f->dir,&useron)) ! 72: subtract_cdt(&cfg,&useron,f->cdt); ! 73: /**************************/ ! 74: /* Update Uploader's Info */ ! 75: /**************************/ ! 76: i=matchuser(&cfg,f->uler,TRUE /*sysop_alias*/); ! 77: uploader.number=i; ! 78: getuserdat(&cfg,&uploader); ! 79: if(i && i!=useron.number && uploader.firston<f->dateuled) { ! 80: l=f->cdt; ! 81: if(!(cfg.dir[f->dir]->misc&DIR_CDTDL)) /* Don't give credits on d/l */ ! 82: l=0; ! 83: if(cfg.dir[f->dir]->misc&DIR_CDTMIN && cur_cps) { /* Give min instead of cdt */ ! 84: mod=((ulong)(l*(cfg.dir[f->dir]->dn_pct/100.0))/cur_cps)/60; ! 85: adjustuserrec(&cfg,i,U_MIN,10,mod); ! 86: sprintf(tmp,"%lu minute",mod); ! 87: } else { ! 88: mod=(ulong)(l*(cfg.dir[f->dir]->dn_pct/100.0)); ! 89: adjustuserrec(&cfg,i,U_CDT,10,mod); ! 90: ultoac(mod,tmp); ! 91: } ! 92: if(!(cfg.dir[f->dir]->misc&DIR_QUIET)) { ! 93: sprintf(str,text[DownloadUserMsg] ! 94: ,!strcmp(cfg.dir[f->dir]->code,"TEMP") ? temp_file : f->name ! 95: ,!strcmp(cfg.dir[f->dir]->code,"TEMP") ? text[Partially] : nulstr ! 96: ,useron.alias,tmp); ! 97: putsmsg(&cfg,i,str); ! 98: } ! 99: } ! 100: /*******************/ ! 101: /* Update IXB File */ ! 102: /*******************/ ! 103: f->datedled=time(NULL); ! 104: sprintf(str,"%s%s.ixb",cfg.dir[f->dir]->data_dir,cfg.dir[f->dir]->code); ! 105: if((file=nopen(str,O_RDWR))==-1) { ! 106: errormsg(WHERE,ERR_OPEN,str,O_RDWR); ! 107: return; ! 108: } ! 109: length=filelength(file); ! 110: if(length%F_IXBSIZE) { ! 111: close(file); ! 112: errormsg(WHERE,ERR_LEN,str,length); ! 113: return; ! 114: } ! 115: strcpy(fname,f->name); ! 116: for(i=8;i<12;i++) /* Turn FILENAME.EXT into FILENAMEEXT */ ! 117: fname[i]=fname[i+1]; ! 118: for(l=0;l<(ulong)length;l+=F_IXBSIZE) { ! 119: read(file,str,F_IXBSIZE); /* Look for the filename in the IXB file */ ! 120: str[11]=0; ! 121: if(!strcmp(fname,str)) ! 122: break; ! 123: } ! 124: if(l>=(ulong)length) { ! 125: close(file); ! 126: errormsg(WHERE,ERR_CHK,f->name,0); ! 127: return; ! 128: } ! 129: lseek(file,l+18,SEEK_SET); ! 130: write(file,&f->datedled,4); /* Write the current time stamp for datedled */ ! 131: close(file); ! 132: /*******************/ ! 133: /* Update DAT File */ ! 134: /*******************/ ! 135: f->timesdled++; ! 136: putfiledat(&cfg,f); ! 137: /******************************************/ ! 138: /* Update User to User index if necessary */ ! 139: /******************************************/ ! 140: if(f->dir==cfg.user_dir) { ! 141: rmuserxfers(&cfg,0,useron.number,f->name); ! 142: if(!getuserxfers(0,0,f->name)) { /* check if any ixt entries left */ ! 143: remove(getfilepath(&cfg,f,str)); ! 144: removefiledat(&cfg,f); ! 145: } ! 146: } ! 147: ! 148: user_event(EVENT_DOWNLOAD); ! 149: } ! 150: ! 151: /****************************************************************************/ ! 152: /* This function is called when a file is unsuccessfully downloaded. */ ! 153: /* It logs the tranfer time and checks for possible leech protocol use. */ ! 154: /****************************************************************************/ ! 155: void sbbs_t::notdownloaded(ulong size, time_t start, time_t end) ! 156: { ! 157: char str[256],tmp2[256]; ! 158: char tmp[512]; ! 159: ! 160: sprintf(str,"Estimated Time: %s Transfer Time: %s" ! 161: ,sectostr(cur_cps ? size/cur_cps : 0,tmp) ! 162: ,sectostr((uint)end-start,tmp2)); ! 163: logline(nulstr,str); ! 164: if(cfg.leech_pct && cur_cps /* leech detection */ ! 165: && end-start>=cfg.leech_sec ! 166: && end-start>=(double)(size/cur_cps)*(double)cfg.leech_pct/100.0) { ! 167: sprintf(str,"Possible use of leech protocol (leech=%u downloads=%u)" ! 168: ,useron.leech+1,useron.dls); ! 169: errorlog(str); ! 170: useron.leech=(uchar)adjustuserrec(&cfg,useron.number,U_LEECH,2,1); ! 171: } ! 172: } ! 173: ! 174: char* sbbs_t::protcmdline(prot_t* prot, enum XFER_TYPE type) ! 175: { ! 176: switch(type) { ! 177: case XFER_UPLOAD: ! 178: return(prot->ulcmd); ! 179: case XFER_DOWNLOAD: ! 180: return(prot->dlcmd); ! 181: case XFER_BATCH_UPLOAD: ! 182: return(prot->batulcmd); ! 183: case XFER_BATCH_DOWNLOAD: ! 184: return(prot->batdlcmd); ! 185: case XFER_BIDIR: ! 186: return(prot->bicmd); ! 187: } ! 188: ! 189: return("invalid transfer type"); ! 190: } ! 191: ! 192: /****************************************************************************/ ! 193: /* Handles start and stop routines for transfer protocols */ ! 194: /****************************************************************************/ ! 195: int sbbs_t::protocol(prot_t* prot, enum XFER_TYPE type ! 196: ,char *fpath, char *fspec, bool cd) ! 197: { ! 198: char protlog[256],*p; ! 199: char* cmdline; ! 200: char msg[256]; ! 201: int i; ! 202: long ex_mode; ! 203: FILE* stream; ! 204: ! 205: sprintf(protlog,"%sPROTOCOL.LOG",cfg.node_dir); ! 206: remove(protlog); /* Deletes the protocol log */ ! 207: if(useron.misc&AUTOHANG) ! 208: autohang=1; ! 209: else ! 210: autohang=yesno(text[HangUpAfterXferQ]); ! 211: if(sys_status&SS_ABORT || !online) { /* if ctrl-c or hangup */ ! 212: autohang=0; ! 213: return(-1); ! 214: } ! 215: bputs(text[StartXferNow]); ! 216: if(cd) ! 217: p=cfg.temp_dir; ! 218: else ! 219: p=NULL; ! 220: cmdline=cmdstr(protcmdline(prot,type),fpath,fspec,NULL); ! 221: sprintf(msg,"Transferring %s",cmdline); ! 222: spymsg(msg); ! 223: sys_status|=SS_FILEXFER; /* disable spy during file xfer */ ! 224: /* enable telnet binary transmission in both directions */ ! 225: request_telnet_opt(TELNET_DO,TELNET_BINARY_TX); ! 226: request_telnet_opt(TELNET_WILL,TELNET_BINARY_TX); ! 227: ex_mode=0; ! 228: if(prot->misc&PROT_NATIVE) ! 229: ex_mode|=EX_NATIVE; ! 230: #ifdef __unix__ /* file xfer progs must use stdio on Unix */ ! 231: if(!(prot->misc&PROT_SOCKET)) ! 232: ex_mode|=(EX_INR|EX_OUTR|EX_BIN); ! 233: #endif ! 234: ! 235: i=external(cmdline,ex_mode,p); ! 236: /* Got back to Text/NVT mode */ ! 237: request_telnet_opt(TELNET_DONT,TELNET_BINARY_TX); ! 238: request_telnet_opt(TELNET_WONT,TELNET_BINARY_TX); ! 239: ! 240: sys_status&=~SS_FILEXFER; ! 241: if(online==ON_REMOTE) ! 242: rioctl(IOFB); ! 243: ! 244: // Save DSZLOG to logfile ! 245: if((stream=fnopen(NULL,protlog,O_RDONLY))!=NULL) { ! 246: while(!feof(stream) && !ferror(stream)) { ! 247: if(!fgets(protlog,sizeof(protlog),stream)) ! 248: break; ! 249: truncsp(protlog); ! 250: logline(nulstr,protlog); ! 251: } ! 252: fclose(stream); ! 253: } ! 254: ! 255: CRLF; ! 256: if(autohang) sys_status|=SS_PAUSEOFF; /* Pause off after download */ ! 257: return(i); ! 258: } ! 259: ! 260: /****************************************************************************/ ! 261: /* Invokes the timed auto-hangup after transfer routine */ ! 262: /****************************************************************************/ ! 263: void sbbs_t::autohangup() ! 264: { ! 265: char a,c,k; ! 266: char tmp[512]; ! 267: ! 268: if(online!=ON_REMOTE) ! 269: return; ! 270: SYNC; ! 271: sys_status&=~SS_PAUSEOFF; /* turn pause back on */ ! 272: rioctl(IOFI); ! 273: if(!autohang) return; ! 274: lncntr=0; ! 275: bputs(text[Disconnecting]); ! 276: attr(GREEN); ! 277: outchar('['); ! 278: for(c=9,a=0;c>-1 && online && !a;c--) { ! 279: checkline(); ! 280: attr(LIGHTGRAY|HIGH); ! 281: bputs(ultoa(c,tmp,10)); ! 282: attr(GREEN); ! 283: outchar(']'); ! 284: while((k=inkey(K_NONE,DELAY_AUTOHG))!=0 && online) { ! 285: if(toupper(k)=='H') { ! 286: c=0; ! 287: break; ! 288: } ! 289: if(toupper(k)=='A') { ! 290: a=1; ! 291: break; ! 292: } ! 293: } ! 294: if(!a) { ! 295: outchar(BS); ! 296: outchar(BS); ! 297: } ! 298: } ! 299: if(c==-1) { ! 300: bputs(text[Disconnected]); ! 301: hangup(); ! 302: } ! 303: else ! 304: CRLF; ! 305: } ! 306: ! 307: bool sbbs_t::checkdszlog(file_t* f) ! 308: { ! 309: char path[MAX_PATH+1]; ! 310: char str[MAX_PATH+128]; ! 311: char fname[MAX_PATH+1]; ! 312: char rpath[MAX_PATH+1]; ! 313: char* p; ! 314: char* rname; ! 315: char code; ! 316: ulong bytes; ! 317: FILE* fp; ! 318: bool success=false; ! 319: ! 320: sprintf(path,"%sPROTOCOL.LOG",cfg.node_dir); ! 321: if((fp=fopen(path,"r"))==NULL) ! 322: return(false); ! 323: ! 324: unpadfname(f->name,fname); ! 325: ! 326: getfilepath(&cfg,f,rpath); ! 327: fexistcase(rpath); /* incase of long filename */ ! 328: rname=getfname(rpath); ! 329: ! 330: while(!ferror(fp)) { ! 331: if(!fgets(str,sizeof(str),fp)) ! 332: break; ! 333: if((p=strrchr(str,' '))!=NULL) ! 334: *p=0; /* we don't care about no stinking serial number */ ! 335: p=str; ! 336: code=*p; ! 337: FIND_WHITESPACE(p); // Skip code ! 338: SKIP_WHITESPACE(p); ! 339: bytes=strtoul(p,NULL,10); ! 340: FIND_WHITESPACE(p); // Skip bytes ! 341: SKIP_WHITESPACE(p); ! 342: FIND_WHITESPACE(p); // Skip DTE rate ! 343: SKIP_WHITESPACE(p); ! 344: FIND_WHITESPACE(p); // Skip "bps" rate ! 345: SKIP_WHITESPACE(p); ! 346: FIND_WHITESPACE(p); // Skip CPS ! 347: SKIP_WHITESPACE(p); ! 348: FIND_WHITESPACE(p); // Skip "cps" ! 349: SKIP_WHITESPACE(p); ! 350: FIND_WHITESPACE(p); // Skip errors ! 351: SKIP_WHITESPACE(p); ! 352: FIND_WHITESPACE(p); // Skip "errors" ! 353: SKIP_WHITESPACE(p); ! 354: FIND_WHITESPACE(p); // Skip flows ! 355: SKIP_WHITESPACE(p); ! 356: FIND_WHITESPACE(p); // Skip block size ! 357: SKIP_WHITESPACE(p); ! 358: p=getfname(p); /* DSZ stores fullpath, BiModem doesn't */ ! 359: if(stricmp(p,fname)==0 || stricmp(p,rname)==0) { ! 360: /* E for Error or L for Lost Carrier or s for Skipped */ ! 361: /* or only sent 0 bytes! */ ! 362: if(code!='E' && code!='L' && code!='s' && bytes!=0) ! 363: success=true; ! 364: break; ! 365: } ! 366: } ! 367: fclose(fp); ! 368: return(success); ! 369: } ! 370: ! 371: ! 372: /****************************************************************************/ ! 373: /* Checks dsz compatible log file for errors in transfer */ ! 374: /* Returns 1 if the file in the struct file_t was successfuly transfered */ ! 375: /****************************************************************************/ ! 376: bool sbbs_t::checkprotresult(prot_t* prot, int error, file_t* f) ! 377: { ! 378: char str[512]; ! 379: char tmp[128]; ! 380: bool success; ! 381: ! 382: if(prot->misc&PROT_DSZLOG) ! 383: success=checkdszlog(f); ! 384: else ! 385: success=(error==0); ! 386: ! 387: if(!success) { ! 388: bprintf(text[FileNotSent],f->name); ! 389: if(f->dir<cfg.total_dirs) ! 390: sprintf(str,"%s attempted to download %s (%s) from %s %s" ! 391: ,useron.alias ! 392: ,f->name,ultoac(f->size,tmp) ! 393: ,cfg.lib[cfg.dir[f->dir]->lib]->sname,cfg.dir[f->dir]->sname); ! 394: else if(f->dir==cfg.total_dirs) ! 395: sprintf(str,"%s attempted to download QWK packet" ! 396: ,useron.alias); ! 397: else if(f->dir==cfg.total_dirs+1) ! 398: sprintf(str,"%s attempted to download attached file: %s" ! 399: ,useron.alias,f->name); ! 400: logline("D!",str); ! 401: return(false); ! 402: } ! 403: return(true); ! 404: } ! 405: ! 406: ! 407: ! 408: /************************************************************************/ ! 409: /* Wait (for a limited period of time) for sequential dev to become */ ! 410: /* available for file retrieval */ ! 411: /************************************************************************/ ! 412: void sbbs_t::seqwait(uint devnum) ! 413: { ! 414: char loop=0; ! 415: int i; ! 416: time_t start; ! 417: node_t node; ! 418: ! 419: if(!devnum) ! 420: return; ! 421: for(start=now=time(NULL);online && now-start<90;now=time(NULL)) { ! 422: if(msgabort()) /* max wait ^^^^ sec */ ! 423: break; ! 424: getnodedat(cfg.node_num,&thisnode,true); /* open and lock this record */ ! 425: for(i=1;i<=cfg.sys_nodes;i++) { ! 426: if(i==cfg.node_num) continue; ! 427: if(getnodedat(i,&node,true)==0) { ! 428: if((node.status==NODE_INUSE || node.status==NODE_QUIET) ! 429: && node.action==NODE_RFSD && node.aux==devnum) { ! 430: putnodedat(i,&node); ! 431: break; ! 432: } ! 433: putnodedat(i,&node); ! 434: } ! 435: } ! 436: if(i>cfg.sys_nodes) { ! 437: thisnode.action=NODE_RFSD; ! 438: thisnode.aux=devnum; ! 439: putnodedat(cfg.node_num,&thisnode); /* write devnum, unlock, and ret */ ! 440: return; ! 441: } ! 442: putnodedat(cfg.node_num,&thisnode); ! 443: if(!loop) ! 444: bprintf(text[WaitingForDeviceN],devnum); ! 445: loop=1; ! 446: mswait(100); ! 447: } ! 448: ! 449: } ! 450: ! 451: bool sbbs_t::sendfile(char* fname, char prot) ! 452: { ! 453: char keys[128]; ! 454: char ch; ! 455: size_t i; ! 456: bool result=false; ! 457: ! 458: if(prot) ! 459: ch=toupper(prot); ! 460: else { ! 461: xfer_prot_menu(XFER_DOWNLOAD); ! 462: mnemonics(text[ProtocolOrQuit]); ! 463: strcpy(keys,"Q"); ! 464: for(i=0;i<cfg.total_prots;i++) ! 465: if(cfg.prot[i]->dlcmd[0] && chk_ar(cfg.prot[i]->ar,&useron)) ! 466: sprintf(keys+strlen(keys),"%c",cfg.prot[i]->mnemonic); ! 467: ! 468: ch=(char)getkeys(keys,0); ! 469: ! 470: if(ch=='Q' || sys_status&SS_ABORT) ! 471: return(false); ! 472: } ! 473: for(i=0;i<cfg.total_prots;i++) ! 474: if(cfg.prot[i]->mnemonic==ch && chk_ar(cfg.prot[i]->ar,&useron)) ! 475: break; ! 476: if(i<cfg.total_prots) { ! 477: if(protocol(cfg.prot[i],XFER_DOWNLOAD,fname,fname,false)==0) ! 478: result=true; ! 479: autohangup(); ! 480: } ! 481: ! 482: return(result); ! 483: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.