Annotation of sbbs/src/sbbs3/xmodem.c, revision 1.1.1.2

1.1       root        1: /* xmodem.c */
                      2: 
                      3: /* Synchronet X/YMODEM Functions */
                      4: 
1.1.1.2 ! root        5: /* $Id: xmodem.c,v 1.46 2010/03/09 03:53:09 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 2010 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: /* Standard headers */
                     39: #include <stdio.h>
                     40: #include <sys/stat.h>  /* struct stat */
                     41: #include <stdarg.h>            /* va_list */
                     42: 
                     43: /* smblib */
                     44: #include "crc16.h"
                     45: 
                     46: /* xpdev */
                     47: #include "genwrap.h"   /* YIELD */
                     48: #include "dirwrap.h"   /* getfname */
1.1.1.2 ! root       49: #include "filewrap.h"  /* fileoff_t */
1.1       root       50: 
                     51: /* sexyz */
                     52: #include "sexyz.h"
                     53: 
                     54: #define getcom(t)      xm->recv_byte(xm->cbdata,t)
                     55: #define putcom(ch)     xm->send_byte(xm->cbdata,ch,xm->send_timeout)
                     56: 
                     57: static int lprintf(xmodem_t* xm, int level, const char *fmt, ...)
                     58: {
                     59:        va_list argptr;
                     60:        char    sbuf[1024];
                     61: 
                     62:        if(xm->lputs==NULL)
                     63:                return(-1);
1.1.1.2 ! root       64:        if(xm->log_level != NULL)
        !            65:                if(level > *xm->log_level)
        !            66:                        return 0;
1.1       root       67: 
                     68:     va_start(argptr,fmt);
                     69:     vsnprintf(sbuf,sizeof(sbuf),fmt,argptr);
                     70:        sbuf[sizeof(sbuf)-1]=0;
                     71:     va_end(argptr);
                     72:     return(xm->lputs(xm->cbdata,level,sbuf));
                     73: }
                     74: 
                     75: static BOOL is_connected(xmodem_t* xm)
                     76: {
                     77:        if(xm->is_connected!=NULL)
                     78:                return(xm->is_connected(xm->cbdata));
                     79:        return(TRUE);
                     80: }
                     81: 
                     82: static BOOL is_cancelled(xmodem_t* xm)
                     83: {
                     84:        if(xm->is_cancelled!=NULL)
                     85:                return(xm->cancelled=xm->is_cancelled(xm->cbdata));
                     86:        return(xm->cancelled);
                     87: }
                     88: 
1.1.1.2 ! root       89: static void xmodem_flush(xmodem_t* xm)
        !            90: {
        !            91:        if(xm->flush!=NULL)
        !            92:                xm->flush(xm);
        !            93: }
        !            94: 
1.1       root       95: static char *chr(uchar ch)
                     96: {
                     97:        static char str[25];
                     98: 
                     99:        switch(ch) {
                    100:                case SOH:       return("SOH");
                    101:                case STX:       return("STX");
                    102:                case ETX:       return("ETX");
                    103:                case EOT:       return("EOT");
                    104:                case ACK:       return("ACK");
                    105:                case NAK:       return("NAK");
                    106:                case CAN:       return("CAN");
                    107:        }
                    108:        if(ch>=' ' && ch<='~')
                    109:                sprintf(str,"'%c' (%02Xh)",ch,ch);
                    110:        else
                    111:                sprintf(str,"%u (%02Xh)",ch,ch);
                    112:        return(str); 
                    113: }
                    114: 
                    115: 
                    116: int xmodem_put_ack(xmodem_t* xm)
                    117: {
1.1.1.2 ! root      118:        int result;
        !           119: 
1.1       root      120:        while(getcom(0)!=NOINP && is_connected(xm))
                    121:                ;                               /* wait for any trailing data */
1.1.1.2 ! root      122:        result = putcom(ACK);
        !           123: 
        !           124:        xmodem_flush(xm);
        !           125: 
        !           126:        return result;
1.1       root      127: }
                    128: 
                    129: int xmodem_put_nak(xmodem_t* xm, unsigned block_num)
                    130: {
1.1.1.2 ! root      131:        int i,dump_count=0;
        !           132:        int     result;
        !           133: 
        !           134:        /* wait for any trailing data */
        !           135:        while((i=getcom(0))!=NOINP && is_connected(xm)) {
        !           136:                dump_count++;
        !           137:                lprintf(xm,LOG_DEBUG,"Block %u: Dumping byte: %02Xh"
        !           138:                        ,block_num, (BYTE)i);
        !           139:                SLEEP(1);
        !           140:        }
        !           141:        if(dump_count)
        !           142:                lprintf(xm,LOG_INFO,"Block %u: Dumped %u bytes"
        !           143:                        ,block_num, dump_count);
1.1       root      144: 
                    145:        if(block_num<=1) {
1.1.1.2 ! root      146:                if(*(xm->mode)&GMODE) {         /* G for X/Ymodem-G */
        !           147:                        lprintf(xm,LOG_INFO,"Block %u: Requesting mode: Streaming, 16-bit CRC", block_num);
        !           148:                        result = putcom('G');
1.1       root      149:                } else if(*(xm->mode)&CRC) {    /* C for CRC */
1.1.1.2 ! root      150:                        lprintf(xm,LOG_INFO,"Block %u: Requesting mode: 16-bit CRC", block_num);
        !           151:                        result = putcom('C');
1.1       root      152:                } else {                                /* NAK for checksum */
1.1.1.2 ! root      153:                        lprintf(xm,LOG_INFO,"Block %u: Requesting mode: 8-bit Checksum", block_num);
        !           154:                        result = putcom(NAK);
1.1       root      155:                }
1.1.1.2 ! root      156:        } else
        !           157:                result = putcom(NAK);
        !           158: 
        !           159:        xmodem_flush(xm);
        !           160: 
        !           161:        return result;
1.1       root      162: }
                    163: 
                    164: int xmodem_cancel(xmodem_t* xm)
                    165: {
                    166:        int i;
                    167:        int result;
                    168: 
                    169:        if(!is_cancelled(xm) && is_connected(xm)) {
                    170:                for(i=0;i<8 && is_connected(xm);i++)
                    171:                        if((result=putcom(CAN))!=0)
                    172:                                return result;
                    173:                for(i=0;i<10 && is_connected(xm);i++)
                    174:                        if((result=putcom('\b'))!=0)
                    175:                                return result;
                    176:                xm->cancelled=TRUE;
                    177:        }
                    178: 
1.1.1.2 ! root      179:        xmodem_flush(xm);
        !           180: 
        !           181:        return SUCCESS;
1.1       root      182: }
                    183: 
                    184: /****************************************************************************/
                    185: /* Return 0 on success                                                                                                         */
                    186: /****************************************************************************/
                    187: int xmodem_get_block(xmodem_t* xm, uchar* block, unsigned expected_block_num)
                    188: {
1.1.1.2 ! root      189:        uchar           block_num;                              /* Block number received in header      */
        !           190:        uchar           block_inv;
        !           191:        uchar           chksum,calc_chksum;
        !           192:        int                     i,eot=0,can=0;
        !           193:        uint            b,errors;
        !           194:        uint16_t        crc,calc_crc;
1.1       root      195: 
                    196:        for(errors=0;errors<=xm->max_errors && is_connected(xm);errors++) {
                    197: 
1.1.1.2 ! root      198:                i=getcom(expected_block_num<=1 ? 3 : 10);
1.1       root      199:                if(eot && i!=EOT && i!=NOINP)
                    200:                        eot=0;
                    201:                if(can && i!=CAN)
                    202:                        can=0;
                    203:                switch(i) {
1.1.1.2 ! root      204:                        case SOH: /* 128-byte blocks */
        !           205:                                xm->block_size=XMODEM_MIN_BLOCK_SIZE;
1.1       root      206:                                break;
1.1.1.2 ! root      207:                        case STX: /* 1024-byte blocks */
        !           208:                                if(xm->max_block_size < XMODEM_MAX_BLOCK_SIZE) {
        !           209:                                        lprintf(xm,LOG_WARNING,"Block %u: 1024-byte blocks not supported"
        !           210:                                                ,expected_block_num);
        !           211:                                        return FAILURE;
        !           212:                                }
        !           213:                                xm->block_size=XMODEM_MAX_BLOCK_SIZE;
1.1       root      214:                                break;
                    215:                        case EOT:
1.1.1.2 ! root      216:                                lprintf(xm,LOG_DEBUG,"Block %u: EOT received", expected_block_num);
1.1       root      217:                                if(/*((*xm->mode)&(YMODEM|GMODE))==YMODEM &&*/ !eot) {
                    218:                                        lprintf(xm,LOG_INFO,"NAKing first EOT");
                    219:                                        eot=1;  
                    220:                                        xmodem_put_nak(xm,expected_block_num); /* chuck's double EOT trick */
                    221:                                        continue; 
                    222:                                }
                    223:                                return(EOT);
                    224:                        case CAN:
                    225:                                if(!can) {                      /* must get two CANs in a row */
                    226:                                        can=1;
1.1.1.2 ! root      227:                                        lprintf(xm,LOG_WARNING,"Block %u: Received CAN  Expected SOH, STX, or EOT"
        !           228:                                                ,expected_block_num);
1.1       root      229:                                        continue; 
                    230:                                }
1.1.1.2 ! root      231:                                lprintf(xm,LOG_WARNING,"Block %u: Cancelled remotely", expected_block_num);
1.1       root      232:                                return(CAN);
                    233:                        default:
1.1.1.2 ! root      234:                                lprintf(xm,LOG_WARNING,"Block %u: Received %s  Expected SOH, STX, or EOT"
        !           235:                                        ,expected_block_num, chr((uchar)i));
1.1       root      236:                        case NOINP:     /* Nothing came in */
                    237:                                if(eot)
                    238:                                        return(EOT);
                    239:                                return(NOINP);
                    240:                }
                    241:                if((i=getcom(xm->byte_timeout))==NOINP)
                    242:                        break; 
                    243:                block_num=i;
                    244:                if((i=getcom(xm->byte_timeout))==NOINP)
                    245:                        break; 
                    246:                block_inv=i;
                    247:                calc_crc=calc_chksum=0;
                    248:                for(b=0;b<xm->block_size && is_connected(xm);b++) {
                    249:                        if((i=getcom(xm->byte_timeout))==NOINP)
                    250:                                break;
                    251:                        block[b]=i;
                    252:                        if((*xm->mode)&CRC)
                    253:                                calc_crc=ucrc16(block[b],calc_crc);
                    254:                        else
                    255:                                calc_chksum+=block[b]; 
                    256:                }
                    257: 
                    258:                if(b<xm->block_size)
                    259:                        break; 
                    260: 
                    261:                if((*xm->mode)&CRC) {
                    262:                        crc=getcom(xm->byte_timeout)<<8;
                    263:                        crc|=getcom(xm->byte_timeout); 
                    264:                }
                    265:                else
                    266:                        chksum=getcom(xm->byte_timeout);
                    267: 
                    268:                if(block_num!=(uchar)~block_inv) {
1.1.1.2 ! root      269:                        lprintf(xm,LOG_WARNING,"Block %u: Block number bit error (0x%02X vs 0x%02x)"
        !           270:                                ,expected_block_num, block_num,(uchar)~block_inv);
1.1       root      271:                        break; 
                    272:                }
                    273: 
                    274:                if((*xm->mode)&CRC) {
                    275:                        if(crc!=calc_crc) {
1.1.1.2 ! root      276:                                lprintf(xm,LOG_WARNING,"Block %u: CRC ERROR", block_num); 
1.1       root      277:                                break;
                    278:                        }
                    279:                }
                    280:                else    /* CHKSUM */
1.1.1.2 ! root      281:                {
1.1       root      282:                        if(chksum!=calc_chksum) {
1.1.1.2 ! root      283:                                lprintf(xm,LOG_WARNING,"Block %u: CHECKSUM ERROR", block_num); 
1.1       root      284:                                break;
                    285:                        }
                    286:                }
1.1.1.2 ! root      287: 
        !           288:                if(block_num!=(uchar)(expected_block_num&0xff)) {
        !           289:                        lprintf(xm,LOG_WARNING,"Block number error (%u received, expected %u)"
        !           290:                                ,block_num,expected_block_num&0xff);
        !           291:                        if((*xm->mode)&XMODEM && expected_block_num==1 && block_num==0)
        !           292:                                return(NOT_XMODEM);
        !           293:                        if(expected_block_num==0 && block_num==1)
        !           294:                                return(NOT_YMODEM);
        !           295:                        if(expected_block_num && block_num==(uchar)((expected_block_num-1)&0xff))
        !           296:                                continue;       /* silently discard repeated packets (ymodem.doc 7.3.2) */
        !           297:                        break; 
        !           298:                }
        !           299: 
        !           300:                return SUCCESS; /* Success */
1.1       root      301:        }
                    302: 
1.1.1.2 ! root      303:        return FAILURE;         /* Failure */
1.1       root      304: }
                    305: 
                    306: /*****************/
                    307: /* Sends a block */
                    308: /*****************/
                    309: int xmodem_put_block(xmodem_t* xm, uchar* block, unsigned block_size, unsigned block_num)
                    310: {
1.1.1.2 ! root      311:        int                     result;
        !           312:        uchar           ch,chksum;
        !           313:     uint               i;
        !           314:        uint16_t        crc;
1.1       root      315: 
1.1.1.2 ! root      316:        if(block_size==XMODEM_MIN_BLOCK_SIZE)
1.1       root      317:                result=putcom(SOH);
                    318:        else                    /* 1024 */
                    319:                result=putcom(STX);
                    320:        if(result!=0)
                    321:                return(result);
                    322:        ch=(uchar)(block_num&0xff);
                    323:        if((result=putcom(ch))!=0)
                    324:                return result;
                    325:        if((result=putcom((uchar)~ch))!=0)
                    326:                return result;
                    327:        chksum=0;
                    328:        crc=0;
                    329:        for(i=0;i<block_size && is_connected(xm);i++) {
                    330:                if((result=putcom(block[i]))!=0)
                    331:                        return result;
                    332:                if((*xm->mode)&CRC)
                    333:                        crc=ucrc16(block[i],crc);
                    334:                else
                    335:                        chksum+=block[i]; 
                    336:        }
                    337: 
                    338:        if((*xm->mode)&CRC) {
                    339:                if((result=     putcom((uchar)(crc >> 8)))!=0)
                    340:                        return result;
1.1.1.2 ! root      341:                result = putcom((uchar)(crc&0xff)); 
        !           342:        } else
        !           343:                result = putcom(chksum);
        !           344: 
        !           345:        xmodem_flush(xm);
        !           346: 
        !           347:        return result;
1.1       root      348: }
                    349: 
                    350: /************************************************************/
                    351: /* Gets an acknowledgement - usually after sending a block     */
1.1.1.2 ! root      352: /* Returns ACK if ack received                                                         */
1.1       root      353: /************************************************************/
1.1.1.2 ! root      354: int xmodem_get_ack(xmodem_t* xm, unsigned tries, unsigned block_num)
1.1       root      355: {
1.1.1.2 ! root      356:        int i=NOINP,can=0;
1.1       root      357:        unsigned errors;
                    358: 
1.1.1.2 ! root      359:        for(errors=0;errors<tries && is_connected(xm);) {
1.1       root      360: 
1.1.1.2 ! root      361:                if((*xm->mode)&GMODE) {         /* Don't wait for ACK on X/Ymodem-G */
1.1       root      362:                        SLEEP(xm->g_delay);
                    363:                        if(getcom(0)==CAN) {
                    364:                                lprintf(xm,LOG_WARNING,"Block %u: !Cancelled remotely", block_num);
                    365:                                xmodem_cancel(xm);
1.1.1.2 ! root      366:                                return(CAN); 
1.1       root      367:                        }
1.1.1.2 ! root      368:                        return(ACK); 
1.1       root      369:                }
                    370: 
                    371:                i=getcom(xm->ack_timeout);
                    372:                if(can && i!=CAN)
                    373:                        can=0;
                    374:                if(i==ACK)
1.1.1.2 ! root      375:                        break;
1.1       root      376:                if(i==CAN) {
1.1.1.2 ! root      377:                        if(can) {       /* 2 CANs in a row */
1.1       root      378:                                lprintf(xm,LOG_WARNING,"Block %u: !Cancelled remotely", block_num);
                    379:                                xmodem_cancel(xm);
1.1.1.2 ! root      380:                                return(CAN); 
1.1       root      381:                        }
                    382:                        can=1; 
                    383:                }
                    384:                if(i!=NOINP) {
                    385:                        lprintf(xm,LOG_WARNING,"Block %u: !Received %s  Expected ACK"
                    386:                                ,block_num, chr((uchar)i));
                    387:                        if(i!=CAN)
1.1.1.2 ! root      388:                                return(i); 
        !           389:                }
        !           390:                if(i!=CAN)
        !           391:                        errors++;
1.1       root      392:        }
                    393: 
1.1.1.2 ! root      394:        return(i);
1.1       root      395: }
                    396: 
                    397: BOOL xmodem_get_mode(xmodem_t* xm)
                    398: {
                    399:        int                     i;
                    400:        unsigned        errors;
                    401:        unsigned        can;
                    402: 
                    403:        lprintf(xm,LOG_INFO,"Waiting for transfer mode request...");
                    404: 
                    405:        *(xm->mode)&=~(GMODE|CRC);
                    406:        for(errors=can=0;errors<=xm->max_errors && is_connected(xm);errors++) {
                    407:                i=getcom(xm->recv_timeout);
                    408:                if(can && i!=CAN)
                    409:                        can=0;
                    410:                switch(i) {
                    411:                        case NAK:               /* checksum */
                    412:                                lprintf(xm,LOG_INFO,"Receiver requested mode: 8-bit Checksum");
                    413:                                return(TRUE); 
                    414:                        case 'C':
                    415:                                lprintf(xm,LOG_INFO,"Receiver requested mode: 16-bit CRC");
1.1.1.2 ! root      416:                                if(!xm->crc_mode_supported)
        !           417:                                        continue;
1.1       root      418:                                *(xm->mode)|=CRC;
                    419:                                return(TRUE); 
                    420:                        case 'G':
                    421:                                lprintf(xm,LOG_INFO,"Receiver requested mode: Streaming, 16-bit CRC");
1.1.1.2 ! root      422:                                if(!xm->crc_mode_supported || !xm->g_mode_supported)
        !           423:                                        continue;
1.1       root      424:                                *(xm->mode)|=(GMODE|CRC);
                    425:                                return(TRUE); 
                    426:                        case CAN:
                    427:                                if(can) {
                    428:                                        lprintf(xm,LOG_WARNING,"Cancelled remotely");
                    429:                                        return(FALSE); 
                    430:                                }
                    431:                                can=1; 
                    432:                                break;
                    433:                        case NOINP:
                    434:                                break;
                    435:                        default:
                    436:                                lprintf(xm,LOG_WARNING,"Received %s  Expected NAK, C, or G"
                    437:                                        ,chr((uchar)i));
                    438:                                break;
                    439:                } 
                    440:        }
                    441: 
                    442:        lprintf(xm,LOG_ERR,"Failed to get transfer mode request from receiver");
                    443:        return(FALSE);
                    444: }
                    445: 
                    446: BOOL xmodem_put_eot(xmodem_t* xm)
                    447: {
                    448:        int ch;
                    449:        unsigned errors;
                    450:        unsigned cans=0;
                    451: 
                    452:        for(errors=0;errors<=xm->max_errors && is_connected(xm);errors++) {
                    453: 
                    454:                lprintf(xm,LOG_INFO,"Sending End-of-Text (EOT) indicator (%d)",errors+1);
                    455: 
                    456:                while((ch=getcom(0))!=NOINP && is_connected(xm))
                    457:                        lprintf(xm,LOG_INFO,"Throwing out received: %s",chr((uchar)ch));
                    458: 
                    459:                putcom(EOT);
1.1.1.2 ! root      460:                xmodem_flush(xm);
1.1       root      461:                if((ch=getcom(xm->recv_timeout))==NOINP)
                    462:                        continue;
                    463:                lprintf(xm,LOG_INFO,"Received %s",chr((uchar)ch)); 
                    464:                if(ch==ACK)
                    465:                        return(TRUE);
                    466:                if(ch==CAN && ++cans>1)
                    467:                        break;
                    468:                if(ch==NAK && errors==0 && (*(xm->mode)&(YMODEM|GMODE))==YMODEM) {
                    469:                        continue;  /* chuck's double EOT trick so don't complain */
                    470:                }
                    471:                lprintf(xm,LOG_WARNING,"Expected ACK");
                    472:        }
                    473:        return(FALSE);
                    474: }
                    475: 
1.1.1.2 ! root      476: BOOL xmodem_send_file(xmodem_t* xm, const char* fname, FILE* fp, time_t* start, int64_t* sent)
1.1       root      477: {
                    478:        BOOL            success=FALSE;
1.1.1.2 ! root      479:        int64_t         sent_bytes=0;
        !           480:        char            block[XMODEM_MAX_BLOCK_SIZE];
1.1       root      481:        size_t          block_len;
                    482:        unsigned        block_num;
                    483:        size_t          i;
                    484:        size_t          rd;
                    485:        time_t          startfile;
                    486:        struct          stat st;
1.1.1.2 ! root      487:        BOOL            sent_header=FALSE;
1.1       root      488: 
                    489:        if(sent!=NULL)  
                    490:                *sent=0;
                    491: 
                    492:        if(start!=NULL)         
                    493:                *start=time(NULL);
                    494: 
                    495:        fstat(fileno(fp),&st);
                    496: 
                    497:        if(xm->total_files==0)
                    498:                xm->total_files=1;
                    499: 
                    500:        if(xm->total_bytes==0)
                    501:                xm->total_bytes=st.st_size;
                    502: 
                    503:        do {
                    504:        /* try */
                    505:                if(*(xm->mode)&YMODEM) {
                    506: 
                    507:                        if(!xmodem_get_mode(xm))
                    508:                                break;
                    509: 
                    510:                        memset(block,0,sizeof(block));
                    511:                        SAFECOPY(block,getfname(fname));
1.1.1.2 ! root      512:                        i=sprintf(block+strlen(block)+1,"%"PRIu64" %lo 0 0 %d %u"
        !           513:                                ,(uint64_t)st.st_size
1.1       root      514:                                ,st.st_mtime
                    515:                                ,xm->total_files-xm->sent_files
                    516:                                ,xm->total_bytes-xm->sent_bytes);
                    517:                        
1.1.1.2 ! root      518:                        lprintf(xm,LOG_INFO,"Sending YMODEM header block: '%s'",block+strlen(block)+1);
1.1       root      519:                        
                    520:                        block_len=strlen(block)+1+i;
                    521:                        for(xm->errors=0;xm->errors<=xm->max_errors && !is_cancelled(xm) && is_connected(xm);xm->errors++) {
1.1.1.2 ! root      522:                                xmodem_put_block(xm, block, block_len <=XMODEM_MIN_BLOCK_SIZE ? XMODEM_MIN_BLOCK_SIZE:XMODEM_MAX_BLOCK_SIZE, 0  /* block_num */);
        !           523:                                if((i=xmodem_get_ack(xm,/* tries: */1, /* block_num: */0)) == ACK) {
        !           524:                                        sent_header=TRUE;
1.1       root      525:                                        break; 
1.1.1.2 ! root      526:                                }
        !           527:                                if((i==NAK || i=='C' || i=='G')
        !           528:                                        && xm->fallback_to_xmodem && xm->errors+1 == xm->fallback_to_xmodem) {
        !           529:                                        lprintf(xm,LOG_NOTICE,"Falling back to XMODEM mode after %u attempts"
        !           530:                                                ,xm->fallback_to_xmodem);
        !           531:                                        *(xm->mode)&=~YMODEM;
        !           532:                                        break;
        !           533:                                }
1.1       root      534:                        }
1.1.1.2 ! root      535:                        if(xm->errors>xm->max_errors || is_cancelled(xm)) {
1.1       root      536:                                lprintf(xm,LOG_ERR,"Failed to send header block");
                    537:                                break;
                    538:                        }
                    539:                }
                    540: 
                    541:                if(!xmodem_get_mode(xm))
                    542:                        break;
                    543: 
                    544:                startfile=time(NULL);   /* reset time, don't count header block */
                    545:                if(start!=NULL)
                    546:                        *start=startfile;
                    547: 
                    548:                block_num=1;
                    549:                xm->errors=0;
1.1.1.2 ! root      550:                while(sent_bytes < st.st_size && xm->errors<=xm->max_errors && !is_cancelled(xm)
1.1       root      551:                        && is_connected(xm)) {
1.1.1.2 ! root      552:                        fseeko(fp,(off_t)sent_bytes,SEEK_SET);
1.1       root      553:                        memset(block,CPMEOF,xm->block_size);
1.1.1.2 ! root      554:                        if(!sent_header) {
        !           555:                                if(xm->block_size>XMODEM_MIN_BLOCK_SIZE) {
        !           556:                                        if((sent_bytes+xm->block_size) > st.st_size) {
        !           557:                                                if((sent_bytes+xm->block_size-XMODEM_MIN_BLOCK_SIZE) >= st.st_size) {
        !           558:                                                        lprintf(xm,LOG_INFO,"Falling back to 128-byte blocks for end of file");
        !           559:                                                        xm->block_size=XMODEM_MIN_BLOCK_SIZE;
        !           560:                                                }
        !           561:                                        }
        !           562:                                }
        !           563:                        }
1.1       root      564:                        if((rd=fread(block,1,xm->block_size,fp))!=xm->block_size 
1.1.1.2 ! root      565:                                && (sent_bytes + rd) != st.st_size) {
        !           566:                                lprintf(xm,LOG_ERR,"ERROR %d reading %u bytes at file offset %"PRId64
        !           567:                                        ,errno,xm->block_size,(int64_t)ftello(fp));
1.1       root      568:                                xm->errors++;
                    569:                                continue;
                    570:                        }
                    571:                        if(xm->progress!=NULL)
1.1.1.2 ! root      572:                                xm->progress(xm->cbdata,block_num,ftello(fp),st.st_size,startfile);
1.1       root      573:                        xmodem_put_block(xm, block, xm->block_size, block_num);
1.1.1.2 ! root      574:                        if(xmodem_get_ack(xm, /* tries: */5,block_num) != ACK) {
1.1       root      575:                                xm->errors++;
1.1.1.2 ! root      576:                                lprintf(xm,LOG_WARNING,"Block %u: Error #%d at offset %"PRId64
        !           577:                                        ,block_num, xm->errors,(int64_t)(ftello(fp)-xm->block_size));
        !           578:                                if(xm->errors==3 && block_num==1 && xm->block_size>XMODEM_MIN_BLOCK_SIZE) {
        !           579:                                        lprintf(xm,LOG_NOTICE,"Block %u: Falling back to 128-byte blocks", block_num);
        !           580:                                        xm->block_size=XMODEM_MIN_BLOCK_SIZE;
        !           581:                                }
1.1       root      582:                        } else {
                    583:                                block_num++; 
                    584:                                sent_bytes+=rd;
                    585:                        }
                    586:                }
1.1.1.2 ! root      587:                if(sent_bytes >= st.st_size && !is_cancelled(xm) && is_connected(xm)) {
1.1       root      588: 
                    589:        #if 0 /* !SINGLE_THREADED */
                    590:                        lprintf(LOG_DEBUG,"Waiting for output buffer to empty... ");
                    591:                        if(WaitForEvent(outbuf_empty,5000)!=WAIT_OBJECT_0)
                    592:                                lprintf(xm,LOG_WARNING,"FAILURE");
                    593:        #endif
                    594:                        if(xmodem_put_eot(xm))  /* end-of-text, wait for ACK */
                    595:                                success=TRUE;
                    596:                }
                    597:        } while(0);
                    598:        /* finally */
                    599: 
                    600:        if(!success)
                    601:                xmodem_cancel(xm);
                    602: 
                    603:        if(sent!=NULL)
                    604:                *sent=sent_bytes;
                    605: 
                    606:        return(success);
                    607: }
                    608: 
                    609: 
                    610: const char* xmodem_source(void)
                    611: {
                    612:        return(__FILE__);
                    613: }
                    614: 
                    615: char* xmodem_ver(char *buf)
                    616: {
1.1.1.2 ! root      617:        sscanf("$Revision: 1.46 $", "%*s %s", buf);
1.1       root      618: 
                    619:        return(buf);
                    620: }
                    621: 
                    622: void xmodem_init(xmodem_t* xm, void* cbdata, long* mode
                    623:                                ,int    (*lputs)(void*, int level, const char* str)
1.1.1.2 ! root      624:                                ,void   (*progress)(void* unused, unsigned block_num, int64_t offset, int64_t fsize, time_t t)
1.1       root      625:                                ,int    (*send_byte)(void*, uchar ch, unsigned timeout)
                    626:                                ,int    (*recv_byte)(void*, unsigned timeout)
                    627:                                ,BOOL   (*is_connected)(void*)
1.1.1.2 ! root      628:                                ,BOOL   (*is_cancelled)(void*)
        !           629:                                ,void   (*flush)(void*))
1.1       root      630: {
                    631:        memset(xm,0,sizeof(xmodem_t));
                    632: 
                    633:        /* Use sane default values */
                    634:        xm->send_timeout=10;            /* seconds */
                    635:        xm->recv_timeout=10;            /* seconds */
                    636:        xm->byte_timeout=3;                     /* seconds */
                    637:        xm->ack_timeout=10;                     /* seconds */
                    638: 
1.1.1.2 ! root      639:        xm->block_size=XMODEM_MAX_BLOCK_SIZE;
        !           640:        xm->max_block_size=XMODEM_MAX_BLOCK_SIZE;
1.1       root      641:        xm->max_errors=9;
                    642:        xm->g_delay=1;
                    643: 
                    644:        xm->cbdata=cbdata;
                    645:        xm->mode=mode;
1.1.1.2 ! root      646:        xm->g_mode_supported=TRUE;
        !           647:        xm->crc_mode_supported=TRUE;
1.1       root      648:        xm->lputs=lputs;
                    649:        xm->progress=progress;
                    650:        xm->send_byte=send_byte;
                    651:        xm->recv_byte=recv_byte;
                    652:        xm->is_connected=is_connected;
                    653:        xm->is_cancelled=is_cancelled;
1.1.1.2 ! root      654:        xm->flush=flush;
1.1       root      655: }

unix.superglobalmegacorp.com

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