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

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

unix.superglobalmegacorp.com

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