|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.