Annotation of sbbs/src/sbbs3/download.cpp, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.