|
|
1.1 root 1: /* download.cpp */
2:
3: /* Synchronet file download routines */
4:
1.1.1.2 ! root 5: /* $Id: download.cpp,v 1.29 2004/11/06 00:56:47 rswindell Exp $ */
1.1 root 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: * *
1.1.1.2 ! root 11: * Copyright 2003 Rob Swindell - http://www.synchro.net/copyright.html *
1.1 root 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"
1.1.1.2 ! root 39: #include "telnet.h"
1.1 root 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;
1.1.1.2 ! root 57: if(!(cfg.dir[f->dir]->misc&DIR_NOSTAT)) {
! 58: logon_dlb+=length; /* Update 'this call' stats */
! 59: logon_dls++;
! 60: }
1.1 root 61: bprintf(text[FileNBytesSent],f->name,ultoac(length,tmp));
1.1.1.2 ! root 62: sprintf(str,"%s downloaded %s from %s %s"
! 63: ,useron.alias
! 64: ,f->name,cfg.lib[cfg.dir[f->dir]->lib]->sname
1.1 root 65: ,cfg.dir[f->dir]->sname);
66: logline("D-",str);
67: /****************************/
68: /* Update Downloader's Info */
69: /****************************/
70: useron.dls=(ushort)adjustuserrec(&cfg,useron.number,U_DLS,5,1);
71: useron.dlb=adjustuserrec(&cfg,useron.number,U_DLB,10,length);
1.1.1.2 ! root 72: if(!is_download_free(&cfg,f->dir,&useron))
1.1 root 73: subtract_cdt(&cfg,&useron,f->cdt);
74: /**************************/
75: /* Update Uploader's Info */
76: /**************************/
1.1.1.2 ! root 77: i=matchuser(&cfg,f->uler,TRUE /*sysop_alias*/);
1.1 root 78: uploader.number=i;
79: getuserdat(&cfg,&uploader);
80: if(i && i!=useron.number && uploader.firston<f->dateuled) {
81: l=f->cdt;
82: if(!(cfg.dir[f->dir]->misc&DIR_CDTDL)) /* Don't give credits on d/l */
83: l=0;
84: if(cfg.dir[f->dir]->misc&DIR_CDTMIN && cur_cps) { /* Give min instead of cdt */
85: mod=((ulong)(l*(cfg.dir[f->dir]->dn_pct/100.0))/cur_cps)/60;
86: adjustuserrec(&cfg,i,U_MIN,10,mod);
87: sprintf(tmp,"%lu minute",mod);
1.1.1.2 ! root 88: } else {
1.1 root 89: mod=(ulong)(l*(cfg.dir[f->dir]->dn_pct/100.0));
90: adjustuserrec(&cfg,i,U_CDT,10,mod);
91: ultoac(mod,tmp);
1.1.1.2 ! root 92: }
! 93: if(!(cfg.dir[f->dir]->misc&DIR_QUIET)) {
1.1 root 94: sprintf(str,text[DownloadUserMsg]
95: ,!strcmp(cfg.dir[f->dir]->code,"TEMP") ? temp_file : f->name
96: ,!strcmp(cfg.dir[f->dir]->code,"TEMP") ? text[Partially] : nulstr
1.1.1.2 ! root 97: ,useron.alias,tmp);
! 98: putsmsg(&cfg,i,str);
! 99: }
! 100: }
1.1 root 101: /*******************/
102: /* Update IXB File */
103: /*******************/
104: f->datedled=time(NULL);
105: sprintf(str,"%s%s.ixb",cfg.dir[f->dir]->data_dir,cfg.dir[f->dir]->code);
106: if((file=nopen(str,O_RDWR))==-1) {
107: errormsg(WHERE,ERR_OPEN,str,O_RDWR);
1.1.1.2 ! root 108: return;
! 109: }
1.1 root 110: length=filelength(file);
111: if(length%F_IXBSIZE) {
112: close(file);
113: errormsg(WHERE,ERR_LEN,str,length);
1.1.1.2 ! root 114: return;
! 115: }
1.1 root 116: strcpy(fname,f->name);
117: for(i=8;i<12;i++) /* Turn FILENAME.EXT into FILENAMEEXT */
118: fname[i]=fname[i+1];
119: for(l=0;l<(ulong)length;l+=F_IXBSIZE) {
120: read(file,str,F_IXBSIZE); /* Look for the filename in the IXB file */
121: str[11]=0;
1.1.1.2 ! root 122: if(!strcmp(fname,str))
! 123: break;
! 124: }
1.1 root 125: if(l>=(ulong)length) {
126: close(file);
127: errormsg(WHERE,ERR_CHK,f->name,0);
1.1.1.2 ! root 128: return;
! 129: }
1.1 root 130: lseek(file,l+18,SEEK_SET);
131: write(file,&f->datedled,4); /* Write the current time stamp for datedled */
132: close(file);
133: /*******************/
134: /* Update DAT File */
135: /*******************/
136: f->timesdled++;
137: putfiledat(&cfg,f);
138: /******************************************/
139: /* Update User to User index if necessary */
140: /******************************************/
141: if(f->dir==cfg.user_dir) {
142: rmuserxfers(&cfg,0,useron.number,f->name);
143: if(!getuserxfers(0,0,f->name)) { /* check if any ixt entries left */
1.1.1.2 ! root 144: remove(getfilepath(&cfg,f,str));
1.1 root 145: removefiledat(&cfg,f);
146: }
147: }
1.1.1.2 ! root 148:
! 149: user_event(EVENT_DOWNLOAD);
1.1 root 150: }
151:
152: /****************************************************************************/
153: /* This function is called when a file is unsuccessfully downloaded. */
154: /* It logs the tranfer time and checks for possible leech protocol use. */
155: /****************************************************************************/
156: void sbbs_t::notdownloaded(ulong size, time_t start, time_t end)
157: {
158: char str[256],tmp2[256];
159: char tmp[512];
160:
161: sprintf(str,"Estimated Time: %s Transfer Time: %s"
162: ,sectostr(cur_cps ? size/cur_cps : 0,tmp)
163: ,sectostr((uint)end-start,tmp2));
164: logline(nulstr,str);
165: if(cfg.leech_pct && cur_cps /* leech detection */
166: && end-start>=cfg.leech_sec
167: && end-start>=(double)(size/cur_cps)*(double)cfg.leech_pct/100.0) {
168: sprintf(str,"Possible use of leech protocol (leech=%u downloads=%u)"
169: ,useron.leech+1,useron.dls);
170: errorlog(str);
1.1.1.2 ! root 171: useron.leech=(uchar)adjustuserrec(&cfg,useron.number,U_LEECH,2,1);
! 172: }
1.1 root 173: }
174:
1.1.1.2 ! root 175: char* sbbs_t::protcmdline(prot_t* prot, enum XFER_TYPE type)
! 176: {
! 177: switch(type) {
! 178: case XFER_UPLOAD:
! 179: return(prot->ulcmd);
! 180: case XFER_DOWNLOAD:
! 181: return(prot->dlcmd);
! 182: case XFER_BATCH_UPLOAD:
! 183: return(prot->batulcmd);
! 184: case XFER_BATCH_DOWNLOAD:
! 185: return(prot->batdlcmd);
! 186: case XFER_BIDIR:
! 187: return(prot->bicmd);
! 188: }
! 189:
! 190: return("invalid transfer type");
! 191: }
1.1 root 192:
193: /****************************************************************************/
194: /* Handles start and stop routines for transfer protocols */
195: /****************************************************************************/
1.1.1.2 ! root 196: int sbbs_t::protocol(prot_t* prot, enum XFER_TYPE type
! 197: ,char *fpath, char *fspec, bool cd)
1.1 root 198: {
1.1.1.2 ! root 199: char protlog[256],*p;
! 200: char* cmdline;
1.1 root 201: char msg[256];
202: int i;
1.1.1.2 ! root 203: long ex_mode;
1.1 root 204: FILE* stream;
205:
206: sprintf(protlog,"%sPROTOCOL.LOG",cfg.node_dir);
207: remove(protlog); /* Deletes the protocol log */
208: if(useron.misc&AUTOHANG)
209: autohang=1;
210: else
211: autohang=yesno(text[HangUpAfterXferQ]);
1.1.1.2 ! root 212: if(sys_status&SS_ABORT || !online) { /* if ctrl-c or hangup */
1.1 root 213: autohang=0;
1.1.1.2 ! root 214: return(-1);
! 215: }
1.1 root 216: bputs(text[StartXferNow]);
217: RIOSYNC(0);
218: //lprintf("%s",cmdline);
219: if(cd)
220: p=cfg.temp_dir;
1.1.1.2 ! root 221: else
! 222: p=NULL;
! 223: cmdline=cmdstr(protcmdline(prot,type),fpath,fspec,NULL);
1.1 root 224: sprintf(msg,"Transferring %s",cmdline);
225: spymsg(msg);
1.1.1.2 ! root 226: sys_status|=SS_FILEXFER; /* disable spy during file xfer */
! 227: /* enable telnet binary transmission in both directions */
! 228: request_telnet_opt(TELNET_DO,TELNET_BINARY_TX);
! 229: request_telnet_opt(TELNET_WILL,TELNET_BINARY_TX);
! 230: ex_mode=0;
! 231: if(prot->misc&PROT_NATIVE)
! 232: ex_mode|=EX_NATIVE;
! 233: #ifdef __unix__ /* file xfer progs must use stdio on Unix */
! 234: ex_mode|=(EX_INR|EX_OUTR|EX_BIN);
! 235: #endif
! 236:
! 237: i=external(cmdline,ex_mode,p);
! 238: /* Got back to Text/NVT mode */
! 239: request_telnet_opt(TELNET_DONT,TELNET_BINARY_TX);
! 240: request_telnet_opt(TELNET_WONT,TELNET_BINARY_TX);
! 241:
1.1 root 242: sys_status&=~SS_FILEXFER;
243: if(online==ON_REMOTE)
244: rioctl(IOFB);
245:
246: // Save DSZLOG to logfile
247: if((stream=fnopen(NULL,protlog,O_RDONLY))!=NULL) {
248: while(!feof(stream) && !ferror(stream)) {
1.1.1.2 ! root 249: if(!fgets(protlog,sizeof(protlog),stream))
1.1 root 250: break;
251: truncsp(protlog);
252: logline(nulstr,protlog);
253: }
254: fclose(stream);
255: }
256:
257: CRLF;
258: if(autohang) sys_status|=SS_PAUSEOFF; /* Pause off after download */
259: return(i);
260: }
261:
262: /****************************************************************************/
263: /* Invokes the timed auto-hangup after transfer routine */
264: /****************************************************************************/
265: void sbbs_t::autohangup()
266: {
267: char a,c,k;
268: char tmp[512];
269:
270: if(online!=ON_REMOTE)
271: return;
272: SYNC;
273: sys_status&=~SS_PAUSEOFF; /* turn pause back on */
274: rioctl(IOFI);
275: if(!autohang) return;
276: lncntr=0;
277: bputs(text[Disconnecting]);
278: attr(GREEN);
279: outchar('[');
280: for(c=9,a=0;c>-1 && online && !a;c--) {
281: checkline();
282: attr(LIGHTGRAY|HIGH);
283: bputs(ultoa(c,tmp,10));
284: attr(GREEN);
285: outchar(']');
1.1.1.2 ! root 286: while((k=inkey(K_NONE,DELAY_AUTOHG))!=0 && online) {
1.1 root 287: if(toupper(k)=='H') {
288: c=0;
1.1.1.2 ! root 289: break;
! 290: }
1.1 root 291: if(toupper(k)=='A') {
292: a=1;
1.1.1.2 ! root 293: break;
! 294: }
! 295: }
1.1 root 296: if(!a) {
297: outchar(BS);
1.1.1.2 ! root 298: outchar(BS);
! 299: }
! 300: }
1.1 root 301: if(c==-1) {
302: bputs(text[Disconnected]);
1.1.1.2 ! root 303: hangup();
! 304: }
1.1 root 305: else
306: CRLF;
307: }
308:
1.1.1.2 ! root 309: bool sbbs_t::checkdszlog(file_t* f)
! 310: {
! 311: char path[MAX_PATH+1];
! 312: char str[MAX_PATH+128];
! 313: char fname[MAX_PATH+1];
! 314: char rpath[MAX_PATH+1];
! 315: char* p;
! 316: char* rname;
! 317: char code;
! 318: ulong bytes;
! 319: ulong dte;
! 320: ulong cps;
! 321: ulong errors;
! 322: ulong flows;
! 323: ulong block_size;
! 324: long serial_no;
! 325: FILE* fp;
! 326: bool success=false;
! 327:
! 328: sprintf(path,"%sPROTOCOL.LOG",cfg.node_dir);
! 329: if((fp=fopen(path,"r"))==NULL)
! 330: return(false);
! 331:
! 332: unpadfname(f->name,fname);
! 333:
! 334: /* Increase real path is different (long filename?) */
! 335: getfilepath(&cfg,f,rpath);
! 336: rname=getfname(rpath);
! 337:
! 338: while(!ferror(fp)) {
! 339: if(!fgets(str,sizeof(str),fp))
! 340: break;
! 341: sscanf(str,"%c %lu %lu bps %lu cps %lu errors %lu %lu %s %ld"
! 342: ,&code
! 343: ,&bytes
! 344: ,&dte
! 345: ,&cps
! 346: ,&errors
! 347: ,&flows
! 348: ,&block_size
! 349: ,path
! 350: ,&serial_no);
! 351: p=getfname(path); /* DSZ stores fullpath, BiModem doesn't */
! 352: if(stricmp(p,fname)==0 || stricmp(p,rname)==0) {
! 353: /* E for Error or L for Lost Carrier */
! 354: /* or only sent 0 bytes! */
! 355: if(code!='E' && code!='L' && bytes!=0)
! 356: success=true;
! 357: break;
! 358: }
! 359: }
! 360: fclose(fp);
! 361: return(success);
! 362: }
! 363:
! 364:
1.1 root 365: /****************************************************************************/
366: /* Checks dsz compatible log file for errors in transfer */
367: /* Returns 1 if the file in the struct file_t was successfuly transfered */
368: /****************************************************************************/
1.1.1.2 ! root 369: bool sbbs_t::checkprotresult(prot_t* prot, int error, file_t* f)
1.1 root 370: {
1.1.1.2 ! root 371: char str[512];
! 372: char tmp[128];
! 373: bool success;
1.1 root 374:
1.1.1.2 ! root 375: if(prot->misc&PROT_DSZLOG)
! 376: success=checkdszlog(f);
! 377: else
! 378: success=(error==0);
! 379:
! 380: if(!success) {
1.1 root 381: bprintf(text[FileNotSent],f->name);
382: if(f->dir<cfg.total_dirs)
1.1.1.2 ! root 383: sprintf(str,"%s attempted to download %s (%s) from %s %s"
! 384: ,useron.alias
! 385: ,f->name,ultoac(f->size,tmp)
1.1 root 386: ,cfg.lib[cfg.dir[f->dir]->lib]->sname,cfg.dir[f->dir]->sname);
387: else if(f->dir==cfg.total_dirs)
1.1.1.2 ! root 388: sprintf(str,"%s attempted to download QWK packet"
! 389: ,useron.alias);
1.1 root 390: else if(f->dir==cfg.total_dirs+1)
1.1.1.2 ! root 391: sprintf(str,"%s attempted to download attached file: %s"
! 392: ,useron.alias,f->name);
1.1 root 393: logline("D!",str);
1.1.1.2 ! root 394: return(false);
! 395: }
! 396: return(true);
1.1 root 397: }
398:
399:
400:
401: /************************************************************************/
402: /* Wait (for a limited period of time) for sequential dev to become */
403: /* available for file retrieval */
404: /************************************************************************/
405: void sbbs_t::seqwait(uint devnum)
406: {
407: char loop=0;
408: int i;
409: time_t start;
410: node_t node;
411:
412: if(!devnum)
413: return;
414: for(start=now=time(NULL);online && now-start<90;now=time(NULL)) {
415: if(msgabort()) /* max wait ^^^^ sec */
416: break;
1.1.1.2 ! root 417: getnodedat(cfg.node_num,&thisnode,true); /* open and lock this record */
1.1 root 418: for(i=1;i<=cfg.sys_nodes;i++) {
419: if(i==cfg.node_num) continue;
1.1.1.2 ! root 420: if(getnodedat(i,&node,true)==0) {
! 421: if((node.status==NODE_INUSE || node.status==NODE_QUIET)
! 422: && node.action==NODE_RFSD && node.aux==devnum) {
! 423: putnodedat(i,&node);
! 424: break;
! 425: }
! 426: putnodedat(i,&node);
! 427: }
! 428: }
1.1 root 429: if(i>cfg.sys_nodes) {
430: thisnode.action=NODE_RFSD;
431: thisnode.aux=devnum;
432: putnodedat(cfg.node_num,&thisnode); /* write devnum, unlock, and ret */
1.1.1.2 ! root 433: return;
! 434: }
1.1 root 435: putnodedat(cfg.node_num,&thisnode);
436: if(!loop)
437: bprintf(text[WaitingForDeviceN],devnum);
438: loop=1;
1.1.1.2 ! root 439: mswait(100);
! 440: }
1.1 root 441:
442: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.