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

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

unix.superglobalmegacorp.com

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