|
|
1.1 root 1: /* download.cpp */
2:
3: /* Synchronet file download routines */
4:
1.1.1.2 ! root 5: /* $Id: download.cpp,v 1.44 2011/09/21 03:10:53 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 2011 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"
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: {
1.1.1.2 ! root 47: char str[256],fname[13];
! 48: char tmp[512];
! 49: int i,file;
! 50: long mod;
! 51: long length;
! 52: ulong l;
! 53: user_t uploader;
1.1 root 54:
55: getfiledat(&cfg,f); /* Get current data - right after download */
56: if((length=f->size)<0L)
57: length=0L;
58: if(!(cfg.dir[f->dir]->misc&DIR_NOSTAT)) {
59: logon_dlb+=length; /* Update 'this call' stats */
60: logon_dls++;
61: }
62: bprintf(text[FileNBytesSent],f->name,ultoac(length,tmp));
63: sprintf(str,"%s downloaded %s from %s %s"
64: ,useron.alias
65: ,f->name,cfg.lib[cfg.dir[f->dir]->lib]->sname
66: ,cfg.dir[f->dir]->sname);
67: logline("D-",str);
68: /****************************/
69: /* Update Downloader's Info */
70: /****************************/
71: user_downloaded(&cfg, &useron, 1, length);
1.1.1.2 ! root 72: if(!is_download_free(&cfg,f->dir,&useron,&client))
1.1 root 73: subtract_cdt(&cfg,&useron,f->cdt);
74: /**************************/
75: /* Update Uploader's Info */
76: /**************************/
77: i=matchuser(&cfg,f->uler,TRUE /*sysop_alias*/);
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);
88: } else {
89: mod=(ulong)(l*(cfg.dir[f->dir]->dn_pct/100.0));
90: adjustuserrec(&cfg,i,U_CDT,10,mod);
91: ultoac(mod,tmp);
92: }
93: if(!(cfg.dir[f->dir]->misc&DIR_QUIET)) {
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
97: ,useron.alias,tmp);
98: putsmsg(&cfg,i,str);
99: }
100: }
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);
108: return;
109: }
1.1.1.2 ! root 110: length=(long)filelength(file);
1.1 root 111: if(length%F_IXBSIZE) {
112: close(file);
113: errormsg(WHERE,ERR_LEN,str,length);
114: return;
115: }
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(!stricmp(fname,str))
1.1 root 123: break;
124: }
125: if(l>=(ulong)length) {
126: close(file);
127: errormsg(WHERE,ERR_CHK,f->name,0);
128: return;
129: }
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 */
144: remove(getfilepath(&cfg,f,str));
145: removefiledat(&cfg,f);
146: }
147: }
148:
149: user_event(EVENT_DOWNLOAD);
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) {
1.1.1.2 ! root 168: lprintf(LOG_ERR, "Node %d Possible use of leech protocol (leech=%u downloads=%u)"
! 169: ,cfg.node_num, useron.leech+1,useron.dls);
1.1 root 170: useron.leech=(uchar)adjustuserrec(&cfg,useron.number,U_LEECH,2,1);
171: }
172: }
173:
1.1.1.2 ! root 174: const char* sbbs_t::protcmdline(prot_t* prot, enum XFER_TYPE type)
1.1 root 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)
1.1.1.2 ! root 208: autohang=true;
! 209: else if(text[HangUpAfterXferQ][0])
1.1 root 210: autohang=yesno(text[HangUpAfterXferQ]);
1.1.1.2 ! root 211: else
! 212: autohang=false;
1.1 root 213: if(sys_status&SS_ABORT || !online) { /* if ctrl-c or hangup */
1.1.1.2 ! root 214: autohang=false;
1.1 root 215: return(-1);
216: }
217: bputs(text[StartXferNow]);
218: if(cd)
219: p=cfg.temp_dir;
220: else
221: p=NULL;
222: cmdline=cmdstr(protcmdline(prot,type),fpath,fspec,NULL);
223: sprintf(msg,"Transferring %s",cmdline);
224: spymsg(msg);
225: sys_status|=SS_FILEXFER; /* disable spy during file xfer */
226: /* enable telnet binary transmission in both directions */
227: request_telnet_opt(TELNET_DO,TELNET_BINARY_TX);
228: request_telnet_opt(TELNET_WILL,TELNET_BINARY_TX);
229: ex_mode=0;
230: if(prot->misc&PROT_NATIVE)
231: ex_mode|=EX_NATIVE;
232: #ifdef __unix__ /* file xfer progs must use stdio on Unix */
233: if(!(prot->misc&PROT_SOCKET))
1.1.1.2 ! root 234: ex_mode|=(EX_STDIO|EX_BIN);
1.1 root 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:
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)) {
249: if(!fgets(protlog,sizeof(protlog),stream))
250: break;
251: truncsp(protlog);
1.1.1.2 ! root 252: logline(LOG_DEBUG,nulstr,protlog);
1.1 root 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(']');
286: while((k=inkey(K_NONE,DELAY_AUTOHG))!=0 && online) {
287: if(toupper(k)=='H') {
288: c=0;
289: break;
290: }
291: if(toupper(k)=='A') {
292: a=1;
293: break;
294: }
295: }
296: if(!a) {
297: outchar(BS);
298: outchar(BS);
299: }
300: }
301: if(c==-1) {
302: bputs(text[Disconnected]);
303: hangup();
304: }
305: else
306: CRLF;
307: }
308:
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: FILE* fp;
320: bool success=false;
321:
322: sprintf(path,"%sPROTOCOL.LOG",cfg.node_dir);
323: if((fp=fopen(path,"r"))==NULL)
324: return(false);
325:
326: unpadfname(f->name,fname);
327:
328: getfilepath(&cfg,f,rpath);
329: fexistcase(rpath); /* incase of long filename */
330: rname=getfname(rpath);
331:
332: while(!ferror(fp)) {
333: if(!fgets(str,sizeof(str),fp))
334: break;
335: if((p=strrchr(str,' '))!=NULL)
336: *p=0; /* we don't care about no stinking serial number */
337: p=str;
338: code=*p;
339: FIND_WHITESPACE(p); // Skip code
340: SKIP_WHITESPACE(p);
341: bytes=strtoul(p,NULL,10);
342: FIND_WHITESPACE(p); // Skip bytes
343: SKIP_WHITESPACE(p);
344: FIND_WHITESPACE(p); // Skip DTE rate
345: SKIP_WHITESPACE(p);
346: FIND_WHITESPACE(p); // Skip "bps" rate
347: SKIP_WHITESPACE(p);
348: FIND_WHITESPACE(p); // Skip CPS
349: SKIP_WHITESPACE(p);
350: FIND_WHITESPACE(p); // Skip "cps"
351: SKIP_WHITESPACE(p);
352: FIND_WHITESPACE(p); // Skip errors
353: SKIP_WHITESPACE(p);
354: FIND_WHITESPACE(p); // Skip "errors"
355: SKIP_WHITESPACE(p);
356: FIND_WHITESPACE(p); // Skip flows
357: SKIP_WHITESPACE(p);
358: FIND_WHITESPACE(p); // Skip block size
359: SKIP_WHITESPACE(p);
360: p=getfname(p); /* DSZ stores fullpath, BiModem doesn't */
361: if(stricmp(p,fname)==0 || stricmp(p,rname)==0) {
362: /* E for Error or L for Lost Carrier or s for Skipped */
363: /* or only sent 0 bytes! */
364: if(code!='E' && code!='L' && code!='s' && bytes!=0)
365: success=true;
366: break;
367: }
368: }
369: fclose(fp);
370: return(success);
371: }
372:
373:
374: /****************************************************************************/
375: /* Checks dsz compatible log file for errors in transfer */
376: /* Returns 1 if the file in the struct file_t was successfuly transfered */
377: /****************************************************************************/
378: bool sbbs_t::checkprotresult(prot_t* prot, int error, file_t* f)
379: {
380: char str[512];
381: char tmp[128];
382: bool success;
383:
384: if(prot->misc&PROT_DSZLOG)
385: success=checkdszlog(f);
386: else
387: success=(error==0);
388:
389: if(!success) {
390: bprintf(text[FileNotSent],f->name);
391: if(f->dir<cfg.total_dirs)
392: sprintf(str,"%s attempted to download %s (%s) from %s %s"
393: ,useron.alias
394: ,f->name,ultoac(f->size,tmp)
395: ,cfg.lib[cfg.dir[f->dir]->lib]->sname,cfg.dir[f->dir]->sname);
396: else if(f->dir==cfg.total_dirs)
397: sprintf(str,"%s attempted to download QWK packet"
398: ,useron.alias);
399: else if(f->dir==cfg.total_dirs+1)
400: sprintf(str,"%s attempted to download attached file: %s"
401: ,useron.alias,f->name);
1.1.1.2 ! root 402: logline(LOG_NOTICE,"D!",str);
1.1 root 403: return(false);
404: }
405: return(true);
406: }
407:
408:
409:
410: /************************************************************************/
411: /* Wait (for a limited period of time) for sequential dev to become */
412: /* available for file retrieval */
413: /************************************************************************/
414: void sbbs_t::seqwait(uint devnum)
415: {
416: char loop=0;
417: int i;
418: time_t start;
419: node_t node;
420:
421: if(!devnum)
422: return;
423: for(start=now=time(NULL);online && now-start<90;now=time(NULL)) {
424: if(msgabort()) /* max wait ^^^^ sec */
425: break;
426: getnodedat(cfg.node_num,&thisnode,true); /* open and lock this record */
427: for(i=1;i<=cfg.sys_nodes;i++) {
428: if(i==cfg.node_num) continue;
429: if(getnodedat(i,&node,true)==0) {
430: if((node.status==NODE_INUSE || node.status==NODE_QUIET)
431: && node.action==NODE_RFSD && node.aux==devnum) {
432: putnodedat(i,&node);
433: break;
434: }
435: putnodedat(i,&node);
436: }
437: }
438: if(i>cfg.sys_nodes) {
439: thisnode.action=NODE_RFSD;
440: thisnode.aux=devnum;
441: putnodedat(cfg.node_num,&thisnode); /* write devnum, unlock, and ret */
442: return;
443: }
444: putnodedat(cfg.node_num,&thisnode);
445: if(!loop)
446: bprintf(text[WaitingForDeviceN],devnum);
447: loop=1;
448: mswait(100);
449: }
450:
451: }
452:
453: bool sbbs_t::sendfile(char* fname, char prot)
454: {
455: char keys[128];
456: char ch;
457: size_t i;
458: bool result=false;
459:
460: if(prot)
461: ch=toupper(prot);
462: else {
463: xfer_prot_menu(XFER_DOWNLOAD);
464: mnemonics(text[ProtocolOrQuit]);
465: strcpy(keys,"Q");
466: for(i=0;i<cfg.total_prots;i++)
1.1.1.2 ! root 467: if(cfg.prot[i]->dlcmd[0] && chk_ar(cfg.prot[i]->ar,&useron,&client))
1.1 root 468: sprintf(keys+strlen(keys),"%c",cfg.prot[i]->mnemonic);
469:
470: ch=(char)getkeys(keys,0);
471:
472: if(ch=='Q' || sys_status&SS_ABORT)
473: return(false);
474: }
475: for(i=0;i<cfg.total_prots;i++)
1.1.1.2 ! root 476: if(cfg.prot[i]->mnemonic==ch && chk_ar(cfg.prot[i]->ar,&useron,&client))
1.1 root 477: break;
478: if(i<cfg.total_prots) {
479: if(protocol(cfg.prot[i],XFER_DOWNLOAD,fname,fname,false)==0)
480: result=true;
481: autohangup();
482: }
483:
484: return(result);
485: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.