|
|
1.1 ! root 1: /* STP.C */ ! 2: ! 3: /* Developed 1990-1997 by Rob Swindell; PO Box 501, Yorba Linda, CA 92885 */ ! 4: ! 5: /* Synchronet Transfer Protocols */ ! 6: ! 7: #include <io.h> ! 8: #include <dos.h> ! 9: #include <dir.h> ! 10: #include <time.h> ! 11: #include <alloc.h> ! 12: #include <stdio.h> ! 13: #include <fcntl.h> ! 14: #include <errno.h> ! 15: #include <string.h> ! 16: #include <stdlib.h> ! 17: #include <stdarg.h> ! 18: #include <sys/stat.h> ! 19: ! 20: #define STP 1 ! 21: ! 22: #include "zmodem.h" ! 23: ! 24: #define MAXERRORS 10 ! 25: ! 26: #define ERROR -1 ! 27: /* Various Character/Ctrl-Code Definitions */ ! 28: #define SP 32 /* Space bar */ ! 29: #define ESC 27 /* ESC Char */ ! 30: #define CR 13 /* Carriage Return */ ! 31: #define FF 12 /* Form Feed */ ! 32: #define LF 10 /* Line Feed */ ! 33: #define TAB 9 /* Horizontal Tabulation */ ! 34: #define BS 8 /* Back Space */ ! 35: #define SOH 1 /* Start of header */ ! 36: #define STX 2 /* Start of text */ ! 37: #define ETX 3 /* End of text */ ! 38: #define EOT 4 /* End of transmission */ ! 39: #define ACK 6 /* Acknowledge */ ! 40: #define DLE 16 /* Data link escape */ ! 41: #define XON 17 /* Ctrl-Q - resume transmission */ ! 42: #define XOFF 19 /* Ctrl-S - pause transmission */ ! 43: #define NAK 21 /* Negative Acknowledge */ ! 44: #define CAN 24 /* Cancel */ ! 45: #define CPMEOF 26 /* CP/M End of file (^Z) */ ! 46: #define LOC_ABORT 0x2e03 /* Local abort key (^C) */ ! 47: ! 48: #define uchar unsigned char ! 49: #define uint unsigned int ! 50: #define ulong unsigned long ! 51: ! 52: #define SEND (1<<0) /* Sending file(s) */ ! 53: #define RECV (1<<1) /* Receiving file(s) */ ! 54: #define XMODEM (1<<2) /* Use Xmodem */ ! 55: #define YMODEM (1<<3) /* Use Ymodem */ ! 56: #define ZMODEM (1<<4) /* Use Zmodem */ ! 57: #define CRC (1<<5) /* Use CRC error correction */ ! 58: #define GMODE (1<<6) /* For Qmodem-G and Ymodem-G */ ! 59: #define DIR (1<<7) /* Directory specified to download to */ ! 60: #define DEBUG (1<<8) /* Debug output */ ! 61: #define OVERWRITE (1<<9) /* Overwrite receiving files */ ! 62: #define IGNORE_DCD (1<<10) /* Ignore DCD */ ! 63: #define ALARM (1<<11) /* Alarm when starting and stopping xfer */ ! 64: #define NO_LOCAL (1<<12) /* Don't check local keyboard */ ! 65: ! 66: /* Zmodem mode bits */ ! 67: #define CTRL_ESC (1<<0) /* Escape all control chars */ ! 68: #define VAR_HDRS (1<<1) /* Use variable headers */ ! 69: ! 70: #define LOOP_NOPEN 50 ! 71: ! 72: #define MAX_FNAMES 100 /* Up to 100 filenames */ ! 73: ! 74: /************************/ ! 75: /* Remote I/O Constants */ ! 76: /************************/ ! 77: ! 78: /* i/o mode and state flags */ ! 79: #define CTSCK 0x1000 /* check cts (mode only) */ ! 80: #define RTSCK 0x2000 /* check rts (mode only) */ ! 81: #define TXBOF 0x0800 /* transmit buffer overflow (outcom only) */ ! 82: #define ABORT 0x0400 /* check for ^C (mode), aborting (state) */ ! 83: #define PAUSE 0x0200 /* check for ^S (mode), pausing (state) */ ! 84: #define NOINP 0x0100 /* input buffer empty (incom only) */ ! 85: ! 86: /* status flags */ ! 87: #define DCD 0x80 /* DCD on */ ! 88: #define RI 0x40 /* Ring indicate */ ! 89: #define DSR 0x20 /* Dataset ready */ ! 90: #define CTS 0x10 /* CTS on */ ! 91: #define FERR 0x08 /* Frameing error */ ! 92: #define PERR 0x04 /* Parity error */ ! 93: #define OVRR 0x02 /* Overrun */ ! 94: #define RXLOST 0x01 /* Receive buffer overflow */ ! 95: ! 96: /* rioctl() arguments */ ! 97: /* returns mode or state flags in high 8 bits, status flags in low 8 bits */ ! 98: ! 99: /* the following return mode in high 8 bits */ ! 100: #define IOMODE 0 /* no operation */ ! 101: #define IOSM 1 /* i/o set mode flags */ ! 102: #define IOCM 2 /* i/o clear mode flags */ ! 103: ! 104: #define GVERS 0x007 /* get version */ ! 105: #define GUART 0x107 /* get uart */ ! 106: #define GIRQN 0x207 /* get IRQ number */ ! 107: #define GBAUD 0x307 /* get baud */ ! 108: ! 109: /* the following return state in high 8 bits */ ! 110: #define IOSTATE 4 /* no operation */ ! 111: #define IOSS 5 /* i/o set state flags */ ! 112: #define IOCS 6 /* i/o clear state flags */ ! 113: #define IOFB 0x308 /* i/o buffer flush */ ! 114: #define IOFI 0x208 /* input buffer flush */ ! 115: #define IOFO 0x108 /* output buffer flush */ ! 116: #define IOCE 9 /* i/o clear error flags */ ! 117: ! 118: #define TS_INT28 1 ! 119: #define TS_WINOS2 2 ! 120: #define TS_NODV 4 ! 121: ! 122: /* return count (16bit) */ ! 123: #define RXBC 0x000a /* get receive buffer count */ ! 124: #define RXBS 0x010a /* get receive buffer size */ ! 125: #define TXBC 0x000b /* get transmit buffer count */ ! 126: #define TXBS 0x010b /* get transmit buffer size */ ! 127: #define TXBF 0x020b /* get transmit buffer free space */ ! 128: #define TXSYNC 0x000c /* sync transmition (seconds<<8|0x0c) */ ! 129: #define IDLE 0x000d /* suspend communication routines */ ! 130: #define RESUME 0x010d /* return from suspended state */ ! 131: #define RLERC 0x000e /* read line error count and clear */ ! 132: #define CPTON 0x0110 /* set input translation flag for ctrl-p on */ ! 133: #define CPTOFF 0x0010 /* set input translation flag for ctrl-p off */ ! 134: #define GETCPT 0x8010 /* return the status of ctrl-p translation */ ! 135: #define MSR 0x0011 /* read modem status register */ ! 136: #define FIFOCTL 0x0012 /* FIFO UART control */ ! 137: #define TSTYPE 0x0013 /* Time-slice API type */ ! 138: #define GETTST 0x8013 /* Get Time-slice API type */ ! 139: ! 140: /* ivhctl() arguments */ ! 141: #define INT29R 1 /* copy int 29h output to remote */ ! 142: #define INT29L 2 /* Use _putlc for int 29h */ ! 143: #define INT16 0x10 /* return remote chars to int 16h calls */ ! 144: #define INTCLR 0 /* release int 16h, int 29h */ ! 145: ! 146: #define DCDHIGH (rioctl(IOSTATE)&DCD || mode&IGNORE_DCD) ! 147: ! 148: /**************/ ! 149: /* Prototypes */ ! 150: /**************/ ! 151: ! 152: /* LCLOLL.ASM */ ! 153: int lclini(int); ! 154: void lclxy(int,int); ! 155: int lclwx(void); ! 156: int lclwy(void); ! 157: int lclatr(int); ! 158: int lclaes(void); ! 159: void lputc(int); ! 160: long lputs(char far *); ! 161: uint lkbrd(int); ! 162: ! 163: /* RCIOLL.ASM */ ! 164: ! 165: int rioini(int com,int irq); /* initialize com,irq */ ! 166: int setbaud(int rate); /* set baud rate */ ! 167: int rioctl(int action); /* remote i/o control */ ! 168: int dtr(char onoff); /* set/reset dtr */ ! 169: int incom(void); /* receive character */ ! 170: int ivhctl(int intcode); /* local i/o redirection */ ! 171: ! 172: void riosync(); ! 173: void cancel(); ! 174: ! 175: extern mswtyp; ! 176: extern uint riobp; ! 177: ! 178: uint asmrev; ! 179: ! 180: /***************/ ! 181: /* Global Vars */ ! 182: /***************/ ! 183: long mode=0L; /* Program mode */ ! 184: long zmode=0L; /* Zmodem mode */ ! 185: uchar hdr_block_num; /* Block number received in header */ ! 186: uchar block[1024]; /* Block buffer */ ! 187: uint block_size; /* Block size (128 or 1024) */ ! 188: ulong block_num; /* Block number */ ! 189: ulong last_block_num; /* Last block number sent */ ! 190: uint flows=0; /* Number of flow controls */ ! 191: ! 192: /**************************************/ ! 193: /* Zmodem specific, from Chuck's RZSZ */ ! 194: /**************************************/ ! 195: char Txhdr[ZMAXHLEN]; /* Zmodem transmit header */ ! 196: char Rxhdr[ZMAXHLEN]; /* Zmodem receive header */ ! 197: char attn[ZATTNLEN]; /* Attention string for sender */ ! 198: char zconv; ! 199: char zmanag; ! 200: char ztrans; ! 201: int tryzhdrtype; ! 202: int Rxtimeout = 100; /* Tenths of seconds to wait for something */ ! 203: int Rxframeind; /* ZBIN ZBIN32, or ZHEX type of frame */ ! 204: int Rxtype; /* Type of header received */ ! 205: int Rxhlen; /* Length of header received */ ! 206: int Rxcount; /* Count of data bytes received */ ! 207: ! 208: /********/ ! 209: /* Code */ ! 210: /********/ ! 211: ! 212: int cbreakh() ! 213: { ! 214: return(1); ! 215: } ! 216: ! 217: /****************************************************************************/ ! 218: /* Performs printf() through local assembly routines */ ! 219: /****************************************************************************/ ! 220: int lprintf(char *fmat, ...) ! 221: { ! 222: va_list argptr; ! 223: char sbuf[2048]; ! 224: int chcount; ! 225: ! 226: va_start(argptr,fmat); ! 227: chcount=vsprintf(sbuf,fmat,argptr); ! 228: va_end(argptr); ! 229: lputs(sbuf); ! 230: return(chcount); ! 231: } ! 232: ! 233: void newline() ! 234: { ! 235: if(lclwx()>1) ! 236: lputs("\r\n"); ! 237: } ! 238: ! 239: /****************************************************************************/ ! 240: /* Network open function. Opens all files DENYALL and retries LOOP_NOPEN */ ! 241: /* number of times if the attempted file is already open or denying access */ ! 242: /* for some other reason. All files are opened in BINARY mode. */ ! 243: /****************************************************************************/ ! 244: int nopen(char *str, int access) ! 245: { ! 246: char count=0,logstr[256]; ! 247: int file,share; ! 248: ! 249: if(access==O_RDONLY) share=O_DENYWRITE; ! 250: else share=O_DENYALL; ! 251: while(((file=open(str,O_BINARY|share|access,S_IWRITE))==-1) ! 252: && errno==EACCES && count++<LOOP_NOPEN); ! 253: if(file==-1 && errno==EACCES) ! 254: lprintf("\7\r\nNOPEN: ACCESS DENIED\r\n\7"); ! 255: return(file); ! 256: } ! 257: ! 258: ! 259: /****************************************************************************/ ! 260: /* Converts an ASCII Hex string into an ulong */ ! 261: /****************************************************************************/ ! 262: ulong ahtoul(char *str) ! 263: { ! 264: ulong l,val=0; ! 265: ! 266: while((l=(*str++)|0x20)!=0x20) ! 267: val=(l&0xf)+(l>>6&1)*9+val*16; ! 268: return(val); ! 269: } ! 270: ! 271: /****************************************************************************/ ! 272: /* Checks the disk drive for the existence of a file. Returns 1 if it */ ! 273: /* exists, 0 if it doesn't. */ ! 274: /****************************************************************************/ ! 275: char fexist(char *filespec) ! 276: { ! 277: struct ffblk f; ! 278: ! 279: if(findfirst(filespec,&f,0)==NULL) ! 280: return(1); ! 281: return(0); ! 282: } ! 283: ! 284: /****************************************************************************/ ! 285: /* Truncates white-space chars off end of 'str' and terminates at first tab */ ! 286: /****************************************************************************/ ! 287: void truncsp(char *str) ! 288: { ! 289: char c; ! 290: ! 291: str[strcspn(str,"\t")]=0; ! 292: c=strlen(str); ! 293: while(c && str[c-1]<=SP) c--; ! 294: str[c]=0; ! 295: } ! 296: ! 297: /**************/ ! 298: /* Exit Point */ ! 299: /**************/ ! 300: void bail(int code) ! 301: { ! 302: ! 303: if(mode&ALARM) { ! 304: sound(2000); ! 305: mswait(500); ! 306: sound(1000); ! 307: mswait(500); ! 308: nosound(); } ! 309: riosync(); ! 310: rioini(0,0); /* uninstall com routines */ ! 311: newline(); ! 312: lprintf("Exiting - Error level: %d Flow restraint count: %u\r\n",code,flows); ! 313: fcloseall(); ! 314: exit(code); ! 315: } ! 316: ! 317: /************************************************************/ ! 318: /* Get a character from com port, time out after 10 seconds */ ! 319: /************************************************************/ ! 320: int getcom(char timeout) ! 321: { ! 322: uint i,ch; ! 323: time_t start; ! 324: ! 325: if((ch=incom())!=NOINP) ! 326: return(ch); ! 327: for(i=0;i<10000;i++) /* ten consecutive re-tries */ ! 328: if((ch=incom())!=NOINP) ! 329: return(ch); ! 330: flows++; ! 331: start=time(NULL); ! 332: while(time(NULL)-start<(long)timeout) { /* wait up to ten seconds */ ! 333: if((ch=incom())!=NOINP) ! 334: return(ch); ! 335: if(!DCDHIGH) { ! 336: newline(); ! 337: lprintf("No carrier\r\n"); ! 338: bail(1); } ! 339: mswait(0); ! 340: if(!(mode&NO_LOCAL) && lkbrd(0)==LOC_ABORT) { ! 341: newline(); ! 342: lprintf("Local abort\r\n"); ! 343: cancel(); ! 344: bail(1); } } ! 345: newline(); ! 346: lprintf("Input timeout\r\n"); ! 347: return(NOINP); ! 348: } ! 349: ! 350: /**********************************/ ! 351: /* Output a character to COM port */ ! 352: /**********************************/ ! 353: void putcom(uchar ch) ! 354: { ! 355: int i=0; ! 356: ! 357: while(outcom(ch)&TXBOF && i<180) { /* 10 sec delay */ ! 358: if(!i) lputc('F'); ! 359: if(!DCDHIGH) { ! 360: newline(); ! 361: lprintf("No carrier\r\n"); ! 362: bail(1); } ! 363: i++; ! 364: mswait(1); ! 365: if(!(mode&NO_LOCAL) && lkbrd(0)==LOC_ABORT) { ! 366: newline(); ! 367: lprintf("Local abort\r\n"); ! 368: bail(1); } } ! 369: if(i) { ! 370: lprintf("\b \b"); ! 371: flows++; ! 372: if(i==180) { ! 373: newline(); ! 374: lprintf("Output timeout\r\n"); ! 375: bail(1); } } ! 376: } ! 377: ! 378: void put_nak() ! 379: { ! 380: while(getcom(1)!=NOINP && (mode&NO_LOCAL || lkbrd(0)!=LOC_ABORT)) ! 381: ; /* wait for any trailing data */ ! 382: putcom(NAK); ! 383: } ! 384: ! 385: void cancel() ! 386: { ! 387: int i; ! 388: ! 389: for(i=0;i<10;i++) ! 390: putcom(CAN); ! 391: for(i=0;i<10;i++) ! 392: putcom(BS); ! 393: } ! 394: ! 395: /********************************/ ! 396: /* Update the CRC bytes */ ! 397: /********************************/ ! 398: /**** ! 399: void update_crc(uchar c, uchar *crc1, uchar *crc2) ! 400: { ! 401: int i, temp; ! 402: uchar carry, c_crc1, c_crc2; ! 403: ! 404: for (i=0; i < 8; i++) { ! 405: temp = c * 2; ! 406: c = temp; /* rotate left */ ! 407: carry = ((temp > 255) ? 1 : 0); ! 408: temp = (*crc2) * 2; ! 409: (*crc2) = temp; ! 410: (*crc2) |= carry; /* rotate with carry */ ! 411: c_crc2 = ((temp > 255) ? 1 : 0); ! 412: temp = (*crc1) * 2; ! 413: (*crc1) = temp; ! 414: (*crc1) |= c_crc2; ! 415: c_crc1 = ((temp > 255) ? 1 : 0); ! 416: if (c_crc1) { ! 417: (*crc2) ^= 0x21; ! 418: (*crc1) ^= 0x10; } } ! 419: } ! 420: ****/ ! 421: ! 422: void ucrc16(uchar ch, uint *rcrc) { ! 423: uint i, cy; ! 424: uchar nch=ch; ! 425: ! 426: for (i=0; i<8; i++) { ! 427: cy=*rcrc & 0x8000; ! 428: *rcrc<<=1; ! 429: if (nch & 0x80) *rcrc |= 1; ! 430: nch<<=1; ! 431: if (cy) *rcrc ^= 0x1021; } ! 432: } ! 433: ! 434: ! 435: char *chr(uchar ch) ! 436: { ! 437: static char str[25]; ! 438: ! 439: switch(ch) { ! 440: case SOH: ! 441: return("SOH"); ! 442: case STX: ! 443: return("STX"); ! 444: case ETX: ! 445: return("ETX"); ! 446: case EOT: ! 447: return("EOT"); ! 448: case ACK: ! 449: return("ACK"); ! 450: case NAK: ! 451: return("NAK"); ! 452: case CAN: ! 453: return("CAN"); ! 454: default: ! 455: sprintf(str,"%02Xh",ch); ! 456: return(str); } ! 457: } ! 458: ! 459: /****************************************************************/ ! 460: /* Gets the filename from the filename and optional path in buf */ ! 461: /****************************************************************/ ! 462: char *justfname(char *buf, char *out) ! 463: { ! 464: char *p1,*p2; ! 465: ! 466: if(mode&DEBUG) ! 467: lprintf("justfname: in: '%s'\r\n",buf); ! 468: p1=buf; ! 469: while(*p1) { ! 470: if((p2=strchr(p1,':'))!=NULL) { /* Remove path */ ! 471: p1=p2+1; ! 472: continue; } ! 473: if((p2=strchr(p1,'/'))!=NULL) { ! 474: p1=p2+1; ! 475: continue; } ! 476: if((p2=strchr(p1,'\\'))!=NULL) { ! 477: p1=p2+1; ! 478: continue; } ! 479: break; } ! 480: if(!*p1) { ! 481: lprintf("Invalid filename\r\n"); ! 482: strcpy(out,""); } ! 483: else ! 484: strcpy(out,p1); /* Use just the filename */ ! 485: if(mode&DEBUG) ! 486: lprintf("justfname: out: '%s'\r\n",out); ! 487: return(out); ! 488: } ! 489: ! 490: /****************************************************************************/ ! 491: /* Receive a X/Y/Zmodem block (sector) from COM port */ ! 492: /* hdrblock is 1 if attempting to get Ymodem header block, 0 if data block */ ! 493: /* Returns 0 if all went well, -1 on error or CAN, and EOT if EOT */ ! 494: /****************************************************************************/ ! 495: int get_block(int hdrblock) ! 496: { ! 497: uchar chksum,calc_chksum; ! 498: int i,b,errors,eot=0,can=0; ! 499: uint crc,calc_crc; ! 500: ! 501: for(errors=0;errors<MAXERRORS;errors++) { ! 502: i=getcom(10); ! 503: if(eot && i!=EOT) ! 504: eot=0; ! 505: if(can && i!=CAN) ! 506: can=0; ! 507: switch(i) { ! 508: case SOH: /* 128 byte blocks */ ! 509: block_size=128; ! 510: break; ! 511: case STX: /* 1024 byte blocks */ ! 512: block_size=1024; ! 513: break; ! 514: case EOT: ! 515: if((mode&(YMODEM|GMODE))==YMODEM && !eot) { ! 516: eot=1; ! 517: put_nak(); /* chuck's double EOT trick */ ! 518: continue; } ! 519: return(EOT); ! 520: case CAN: ! 521: newline(); ! 522: if(!can) { /* must get two CANs in a row */ ! 523: can=1; ! 524: lprintf("Received CAN Expected SOH, STX, or EOT\r\n"); ! 525: continue; } ! 526: lprintf("Cancelled remotely\r\n"); ! 527: return(-1); ! 528: case NOINP: /* Nothing came in */ ! 529: continue; ! 530: default: ! 531: newline(); ! 532: lprintf("Received %s Expected SOH, STX, or EOT\r\n",chr(i)); ! 533: if(hdrblock) /* Trying to get Ymodem header block */ ! 534: return(-1); ! 535: put_nak(); ! 536: continue; } ! 537: i=getcom(1); ! 538: if(i==NOINP) { ! 539: put_nak(); ! 540: continue; } ! 541: hdr_block_num=i; ! 542: i=getcom(1); ! 543: if(i==NOINP) { ! 544: put_nak(); ! 545: continue; } ! 546: if(hdr_block_num!=(uchar)~i) { ! 547: newline(); ! 548: lprintf("Block number error\r\n"); ! 549: put_nak(); ! 550: continue; } ! 551: calc_crc=calc_chksum=0; ! 552: for(b=0;b<block_size;b++) { ! 553: i=getcom(1); ! 554: if(i==NOINP) ! 555: break; ! 556: block[b]=i; ! 557: if(mode&CRC) ! 558: ucrc16(block[b],&calc_crc); ! 559: else ! 560: calc_chksum+=block[b]; } ! 561: ! 562: if(b<block_size) { ! 563: put_nak(); ! 564: continue; } ! 565: ! 566: if(mode&CRC) { ! 567: crc=getcom(1)<<8; ! 568: crc|=getcom(1); } ! 569: else ! 570: chksum=getcom(1); ! 571: ! 572: if(mode&CRC) { ! 573: ucrc16(0,&calc_crc); ! 574: ucrc16(0,&calc_crc); ! 575: if(crc==calc_crc) ! 576: break; ! 577: newline(); ! 578: lprintf("CRC error\r\n"); } ! 579: ! 580: else { /* CHKSUM */ ! 581: if(chksum==calc_chksum) ! 582: break; ! 583: newline(); ! 584: lprintf("Checksum error\r\n"); } ! 585: ! 586: if(mode&GMODE) { /* Don't bother sending a NAK. He's not listening */ ! 587: cancel(); ! 588: bail(1); } ! 589: put_nak(); } ! 590: ! 591: if(errors>=MAXERRORS) { ! 592: newline(); ! 593: lprintf("Too many errors\r\n"); ! 594: return(-1); } ! 595: return(0); ! 596: } ! 597: ! 598: /*****************/ ! 599: /* Sends a block */ ! 600: /*****************/ ! 601: void put_block() ! 602: { ! 603: uchar ch,chksum; ! 604: int i; ! 605: uint crc; ! 606: ! 607: if(block_size==128) ! 608: putcom(SOH); ! 609: else /* 1024 */ ! 610: putcom(STX); ! 611: ch=(block_num&0xff); ! 612: putcom(ch); ! 613: putcom(~ch); ! 614: chksum=crc=0; ! 615: for(i=0;i<block_size;i++) { ! 616: putcom(block[i]); ! 617: if(mode&CRC) ! 618: ucrc16(block[i],&crc); ! 619: else ! 620: chksum+=block[i]; } ! 621: ! 622: if(mode&CRC) { ! 623: ucrc16(0,&crc); ! 624: ucrc16(0,&crc); ! 625: putcom(crc>>8); ! 626: putcom(crc&0xff); } ! 627: else ! 628: putcom(chksum); ! 629: } ! 630: ! 631: /************************************************************/ ! 632: /* Gets an acknowledgement - usually after sending a block */ ! 633: /* Returns 1 if ack received, 0 otherwise. */ ! 634: /************************************************************/ ! 635: int get_ack() ! 636: { ! 637: int i,errors,can=0; ! 638: ! 639: for(errors=0;errors<MAXERRORS;errors++) { ! 640: ! 641: if(mode&GMODE) { /* Don't wait for ACK on Ymodem-G */ ! 642: if(incom()==CAN) { ! 643: newline(); ! 644: lprintf("Cancelled remotely\r\n"); ! 645: cancel(); ! 646: bail(1); } ! 647: return(1); } ! 648: ! 649: i=getcom(10); ! 650: if(can && i!=CAN) ! 651: can=0; ! 652: if(i==ACK) ! 653: return(1); ! 654: if(i==CAN) { ! 655: if(can) { ! 656: newline(); ! 657: lprintf("Cancelled remotely\r\n"); ! 658: cancel(); ! 659: bail(1); } ! 660: can=1; } ! 661: if(i!=NOINP) { ! 662: newline(); ! 663: lprintf("Received %s Expected ACK\r\n",chr(i)); ! 664: if(i!=CAN) ! 665: return(0); } } ! 666: ! 667: return(0); ! 668: } ! 669: ! 670: /****************************************************************************/ ! 671: /* Syncronizes the remote and local machines */ ! 672: /****************************************************************************/ ! 673: void riosync() ! 674: { ! 675: int i=0; ! 676: ! 677: while(rioctl(TXBC) && i<180) { /* 10 sec */ ! 678: if(!(mode&NO_LOCAL) && lkbrd(0)==LOC_ABORT) { ! 679: newline(); ! 680: lprintf("Local abort\r\n"); ! 681: cancel(); ! 682: break; } ! 683: if(!DCDHIGH) ! 684: break; ! 685: mswait(1); ! 686: i++; } ! 687: } ! 688: ! 689: /*********************************************************/ ! 690: /* Returns the number of blocks required to send n bytes */ ! 691: /*********************************************************/ ! 692: long blocks(long n) ! 693: { ! 694: long l; ! 695: ! 696: l=n/(long)block_size; ! 697: if(l*(long)block_size<n) ! 698: l++; ! 699: return(l); ! 700: } ! 701: ! 702: /****************************************/ ! 703: /* Zmodem specific functions start here */ ! 704: /****************************************/ ! 705: ! 706: /**********************************************/ ! 707: /* Output single byte as two hex ASCII digits */ ! 708: /**********************************************/ ! 709: void putzhex(uchar val) ! 710: { ! 711: char *digits="0123456789abcdef"; ! 712: ! 713: putcom(digits[(val&0xF0)>>4]); ! 714: putcom(digits[val&0xF]); ! 715: } ! 716: ! 717: /***********************/ ! 718: /* Output a hex header */ ! 719: /***********************/ ! 720: void putzhhdr(char type) ! 721: { ! 722: uint i,crc=0; ! 723: ! 724: putcom(ZPAD); ! 725: putcom(ZPAD); ! 726: putcom(ZDLE); ! 727: if(zmode&VAR_HDRS) { ! 728: putcom(ZVHEX); ! 729: putzhex(4); } ! 730: else ! 731: putcom(ZHEX); ! 732: putzhex(type); ! 733: ucrc16(type,&crc); ! 734: for(i=0;i<4;i++) { ! 735: putzhex(Txhdr[i]); ! 736: ucrc16(Txhdr[i],&crc); } ! 737: ucrc16(0,&crc); ! 738: ucrc16(0,&crc); ! 739: putzhex(crc>>8); ! 740: putzhex(crc&0xff); ! 741: putcom(CR); ! 742: putcom(LF); /* Chuck's RZ.C sends LF|0x80 for some unknown reason */ ! 743: if(type!=ZFIN && type!=ZACK) ! 744: putcom(XON); ! 745: } ! 746: ! 747: /****************************************************************************/ ! 748: /* Stores a long in the Zmodem transmit header (usually position offset) */ ! 749: /****************************************************************************/ ! 750: void ltohdr(long l) ! 751: { ! 752: ! 753: Txhdr[ZP0] = l; ! 754: Txhdr[ZP1] = l>>8; ! 755: Txhdr[ZP2] = l>>16; ! 756: Txhdr[ZP3] = l>>24; ! 757: } ! 758: ! 759: /****************************************************************************/ ! 760: /* Outputs single Zmodem character, escaping with ZDLE when appropriate */ ! 761: /****************************************************************************/ ! 762: void putzcom(uchar ch) ! 763: { ! 764: static lastsent; ! 765: ! 766: if(ch&0x60) /* not a control char */ ! 767: putcom(lastsent=ch); ! 768: else ! 769: switch(ch) { ! 770: case DLE: ! 771: case DLE|0x80: /* even if high-bit set */ ! 772: case XON: ! 773: case XON|0x80: ! 774: case XOFF: ! 775: case XOFF|0x80: ! 776: case ZDLE: ! 777: putcom(ZDLE); ! 778: ch^=0x40; ! 779: putcom(lastsent=ch); ! 780: break; ! 781: case CR: ! 782: case CR|0x80: ! 783: if(!(zmode&CTRL_ESC) && (lastsent&0x7f)!='@') ! 784: putcom(lastsent=ch); ! 785: else { ! 786: putcom(ZDLE); ! 787: ch^=0x40; ! 788: putcom(lastsent=ch); } ! 789: break; ! 790: default: ! 791: if(zmode&CTRL_ESC && !(ch&0x60)) { /* it's a ctrl char */ ! 792: putcom(ZDLE); ! 793: ch^=0x40; } ! 794: putcom(lastsent=ch); ! 795: break; } ! 796: } ! 797: ! 798: /* ! 799: * Read a byte, checking for ZMODEM escape encoding ! 800: * including CAN*5 which represents a quick abort ! 801: */ ! 802: int getzcom() ! 803: { ! 804: int i; ! 805: ! 806: while(1) { ! 807: /* Quick check for non control characters */ ! 808: if((i=getcom(Rxtimeout))&0x60) ! 809: return(i); ! 810: if(i==ZDLE) ! 811: break; ! 812: if((i&0x7f)==XOFF || (i&0x7f)==XON) ! 813: continue; ! 814: if(zmode&CTRL_ESC && !(i&0x60)) ! 815: continue; ! 816: return(i); } ! 817: ! 818: while(1) { /* Escaped characters */ ! 819: if((i=getcom(Rxtimeout))<0) ! 820: return(i); ! 821: if(i==CAN && (i=getcom(Rxtimeout))<0) ! 822: return(i); ! 823: if(i==CAN && (i=getcom(Rxtimeout))<0) ! 824: return(i); ! 825: if(i==CAN && (i=getcom(Rxtimeout))<0) ! 826: return(i); ! 827: switch (i) { ! 828: case CAN: ! 829: return(GOTCAN); ! 830: case ZCRCE: ! 831: case ZCRCG: ! 832: case ZCRCQ: ! 833: case ZCRCW: ! 834: return(i|GOTOR); ! 835: case ZRUB0: ! 836: return(0x7f); ! 837: case ZRUB1: ! 838: return(0xff); ! 839: case XON: ! 840: case XON|0x80: ! 841: case XOFF: ! 842: case XOFF|0x80: ! 843: continue; ! 844: default: ! 845: if (zmode&CTRL_ESC && !(i&0x60)) ! 846: continue; ! 847: if ((i&0x60)==0x40) ! 848: return(i^0x40); ! 849: break; } ! 850: break; } ! 851: return(ERROR); ! 852: } ! 853: ! 854: ! 855: ! 856: /* ! 857: * Read a character from the modem line with timeout. ! 858: * Eat parity, XON and XOFF characters. ! 859: */ ! 860: int getcom7() ! 861: { ! 862: int i; ! 863: ! 864: while(1) { ! 865: i=getcom(10); ! 866: switch(i) { ! 867: case XON: ! 868: case XOFF: ! 869: continue; ! 870: case CR: ! 871: case LF: ! 872: case NOINP: ! 873: case ZDLE: ! 874: return(i); ! 875: default: ! 876: if(!(i&0x60) && zmode&CTRL_ESC) ! 877: continue; ! 878: return(i); } } ! 879: } ! 880: ! 881: ! 882: #if 0 ! 883: ! 884: int getzhdr() ! 885: { ! 886: int done=0; ! 887: ! 888: while(!done) { ! 889: i=getcom(10); ! 890: switch(i) { ! 891: case NOINP: ! 892: done=1; ! 893: continue; ! 894: case XON: ! 895: case XON|0x80: ! 896: continue; ! 897: case ZPAD|0x80: ! 898: case ZPAD: ! 899: break; ! 900: case CAN: ! 901: cancount++; ! 902: if(cancount>=5) { ! 903: i=ZCAN; ! 904: done=1; ! 905: break; } ! 906: i=getcom(10); ! 907: switch(i) { ! 908: case NOINP: ! 909: continue; ! 910: case ZCRCW: ! 911: switch(getcom(10)) { ! 912: case NOINP: ! 913: i=ERROR ! 914: done=1; ! 915: break; ! 916: case RCDO: ! 917: done=1; ! 918: break; ! 919: default: ! 920: continue; } ! 921: break; ! 922: case RCDO: ! 923: done=1; ! 924: break; ! 925: case CAN: ! 926: cancount++; ! 927: if(cancount>=5) { ! 928: i=ZCAN; ! 929: done=1; ! 930: continue; ! 931: default: ! 932: break; } ! 933: continue; ! 934: default: ! 935: continue; } ! 936: ! 937: i=Rxframeind=getcom7(); ! 938: switch (i) { ! 939: case ZVBIN32: ! 940: if((Rxhlen=c=getzcom())<0) ! 941: goto fifi; ! 942: if(c>ZMAXHLEN) ! 943: goto agn2; ! 944: Crc32r=1; ! 945: c=zrbhd32(hdr); ! 946: break; ! 947: case ZBIN32: ! 948: if(zmode&VAR_HDRS) ! 949: goto agn2; ! 950: Crc32r=1; ! 951: c=zrbhd32(hdr); ! 952: break; ! 953: case ZVBINR32: ! 954: if((Rxhlen=c=getzcom())<0) ! 955: goto fifi; ! 956: if(c>ZMAXHLEN) ! 957: goto agn2; ! 958: Crc32r=2; ! 959: c=zrbhd32(hdr); ! 960: break; ! 961: case ZBINR32: ! 962: if(zmode&VAR_HDRS) ! 963: goto agn2; ! 964: Crc32r=2; ! 965: c=zrbhd32(hdr); ! 966: break; ! 967: case RCDO: ! 968: case TIMEOUT: ! 969: goto fifi; ! 970: case ZVBIN: ! 971: if((Rxhlen=c=getzcom())<0) ! 972: goto fifi; ! 973: if(c>ZMAXHLEN) ! 974: goto agn2; ! 975: Crc32r=0; ! 976: c=zrbhdr(hdr); ! 977: break; ! 978: case ZBIN: ! 979: if(zmode&VAR_HDRS) ! 980: goto agn2; ! 981: Crc32r=0; ! 982: c=zrbhdr(hdr); ! 983: break; ! 984: case ZVHEX: ! 985: if((Rxhlen=c=zgethex()) < 0) ! 986: goto fifi; ! 987: if(c>ZMAXHLEN) ! 988: goto agn2; ! 989: Crc32r=0; ! 990: c=zrhhdr(hdr); ! 991: break; ! 992: case ZHEX: ! 993: if(zmode&VAR_HDRS) ! 994: goto agn2; ! 995: Crc32r=0; ! 996: c=zrhhdr(hdr); ! 997: break; ! 998: case CAN: ! 999: goto gotcan; ! 1000: default: ! 1001: goto agn2; ! 1002: } ! 1003: ! 1004: ! 1005: ! 1006: /****************************************************************************/ ! 1007: /* Get the receiver's init parameters */ ! 1008: /****************************************************************************/ ! 1009: int getzrxinit() ! 1010: { ! 1011: int i; ! 1012: struct stat f; ! 1013: ! 1014: for(i=0;i<10;i++) { ! 1015: switch(zgethdr(Rxhdr,1)) { ! 1016: case ZCHALLENGE: /* Echo receiver's challenge numbr */ ! 1017: ltohdr(Rxpos); ! 1018: putzhhdr(ZACK); ! 1019: continue; ! 1020: case ZCOMMAND: /* They didn't see out ZRQINIT */ ! 1021: ltohdr(0L); ! 1022: putzhhdr(ZRQINIT); ! 1023: continue; ! 1024: case ZRINIT: ! 1025: Rxflags=Rxhdr[ZF0]&0x7f; ! 1026: if(Rxhdr[ZF1]&CANVHDR) ! 1027: zmode|=VAR_HDRS; ! 1028: Txfcs32 = (Wantfcs32 && (Rxflags & CANFC32)); ! 1029: Zctlesc |= Rxflags & TESCCTL; ! 1030: Rxbuflen = (0377 & Rxhdr[ZP0])+((0377 & Rxhdr[ZP1])<<8); ! 1031: if ( !(Rxflags & CANFDX)) ! 1032: Txwindow = 0; ! 1033: ! 1034: /* Override to force shorter frame length */ ! 1035: if (Rxbuflen && (Rxbuflen>Tframlen) && (Tframlen>=32)) ! 1036: Rxbuflen = Tframlen; ! 1037: if ( !Rxbuflen && (Tframlen>=32) && (Tframlen<=1024)) ! 1038: Rxbuflen = Tframlen; ! 1039: vfile("Rxbuflen=%d", Rxbuflen); ! 1040: ! 1041: /* ! 1042: * If input is not a regular file, force ACK's to ! 1043: * prevent running beyond the buffer limits ! 1044: */ ! 1045: if ( !Command) { ! 1046: fstat(fileno(in), &f); ! 1047: if ((f.st_mode & S_IFMT) != S_IFREG) { ! 1048: Canseek = -1; ! 1049: ef TXBSIZE ! 1050: Txwindow = TXBSIZE - 1024; ! 1051: Txwspac = TXBSIZE/4; ! 1052: e ! 1053: return ERROR; ! 1054: if ! 1055: } ! 1056: } ! 1057: ! 1058: /* Set initial subpacket length */ ! 1059: if (blklen < 1024) { /* Command line override? */ ! 1060: if (Effbaud > 300) ! 1061: blklen = 256; ! 1062: if (Effbaud > 1200) ! 1063: blklen = 512; ! 1064: if (Effbaud > 2400) ! 1065: blklen = 1024; ! 1066: } ! 1067: if (Rxbuflen && blklen>Rxbuflen) ! 1068: blklen = Rxbuflen; ! 1069: if (blkopt && blklen > blkopt) ! 1070: blklen = blkopt; ! 1071: vfile("Rxbuflen=%d blklen=%d", Rxbuflen, blklen); ! 1072: vfile("Txwindow = %u Txwspac = %d", Txwindow, Txwspac); ! 1073: ! 1074: ! 1075: if (Lztrans == ZTRLE && (Rxflags & CANRLE)) ! 1076: Txfcs32 = 2; ! 1077: else ! 1078: Lztrans = 0; ! 1079: ! 1080: return (sendzsinit()); ! 1081: case ZCAN: ! 1082: case TIMEOUT: ! 1083: return ERROR; ! 1084: case ZRQINIT: ! 1085: if (Rxhdr[ZF0] == ZCOMMAND) ! 1086: continue; ! 1087: default: ! 1088: putzhhdr(ZNAK); ! 1089: continue; } } ! 1090: return(ERROR); ! 1091: } ! 1092: ! 1093: ! 1094: getzdata(char *buf, int length) ! 1095: { ! 1096: int c,d; ! 1097: uint crc; ! 1098: char *end; ! 1099: ! 1100: switch (Crc32r) { ! 1101: case 1: ! 1102: return zrdat32(buf, length); ! 1103: case 2: ! 1104: return zrdatr32(buf, length); ! 1105: } ! 1106: ! 1107: crc = Rxcount = 0; end = buf + length; ! 1108: while (buf <= end) { ! 1109: if ((c = getzcom()) & ~0377) { ! 1110: crcfoo: ! 1111: switch (c) { ! 1112: case GOTCRCE: ! 1113: case GOTCRCG: ! 1114: case GOTCRCQ: ! 1115: case GOTCRCW: ! 1116: crc = updcrc((d=c)&0377, crc); ! 1117: if ((c = getzcom()) & ~0377) ! 1118: goto crcfoo; ! 1119: crc = updcrc(c, crc); ! 1120: if ((c = getzcom()) & ~0377) ! 1121: goto crcfoo; ! 1122: crc = updcrc(c, crc); ! 1123: if (crc & 0xFFFF) { ! 1124: zperr(badcrc); ! 1125: return ERROR; ! 1126: } ! 1127: Rxcount = length - (end - buf); ! 1128: #ifndef DSZ ! 1129: vfile("zrdata: %d %s", Rxcount, ! 1130: Zendnames[d-GOTCRCE&3]); ! 1131: #endif ! 1132: return d; ! 1133: case GOTCAN: ! 1134: zperr("Sender Canceled"); ! 1135: return ZCAN; ! 1136: case TIMEOUT: ! 1137: zperr("TIMEOUT"); ! 1138: return c; ! 1139: default: ! 1140: garbitch(); return c; ! 1141: } ! 1142: } ! 1143: *buf++ = c; ! 1144: crc = updcrc(c, crc); ! 1145: } ! 1146: #ifdef DSZ ! 1147: garbitch(); ! 1148: #else ! 1149: zperr("Data subpacket too long"); ! 1150: #endif ! 1151: return ERROR; ! 1152: } ! 1153: ! 1154: #endif ! 1155: ! 1156: /************************************************/ ! 1157: /* Dump the current blockm contents - for debug */ ! 1158: /************************************************/ ! 1159: void dump_block() ! 1160: { ! 1161: long l; ! 1162: ! 1163: for(l=0;l<block_size;l++) ! 1164: lprintf("%02X ",block[l]); ! 1165: lputs("\r\n"); ! 1166: } ! 1167: ! 1168: char *usage= ! 1169: "usage: STP <port> [chan] [opts] <cmd> [file | path | +list]\r\n\r\n" ! 1170: "where:\r\n\r\n" ! 1171: "port = COM port (1-4), D for DigiBoard, or UART I/O address (hex)\r\n" ! 1172: "chan = IRQ channel (2-15) or DigiBoard channel (4+)\r\n" ! 1173: "opts = b# to set DTE rate to #bps\r\n" ! 1174: " t# to set time-slice API type (default=1)\r\n" ! 1175: " o to overwrite files when receiving\r\n" ! 1176: " d to disable dropped carrier detection\r\n" ! 1177: " a to sound alarm at start and stop of transfer\r\n" ! 1178: " l to disable local keyboard (Ctrl-C) checking\r\n" ! 1179: "cmd = sx to send Xmodem rx to recv Xmodem\r\n" ! 1180: " sX to send Xmodem-1k rc to recv Xmodem-CRC\r\n" ! 1181: " sy to send Ymodem ry to recv Ymodem\r\n" ! 1182: " sY to send Ymodem-1k rg to recv Ymodem-G\r\n" ! 1183: " sz to send Zmodem rz to recv Zmodem\r\n" ! 1184: "file = filename to send or receive\r\n" ! 1185: "path = path to receive files into\r\n" ! 1186: "list = name of text file with list of filenames to send or receive\r\n"; ! 1187: ! 1188: /***************/ ! 1189: /* Entry Point */ ! 1190: /***************/ ! 1191: int main(int argc, char **argv) ! 1192: { ! 1193: char str[256],tmp[256],tmp2[256],irq,errors,*p,*p2,first_block ! 1194: ,*fname[MAX_FNAMES],fnames=0,fnum,success; ! 1195: int ch,i,j,k,file,last,total_files=0,sent_files=0,can; ! 1196: uint base=0,baud=0,cps; ! 1197: long b,l,m,file_bytes_left,serial_num; ! 1198: ulong file_bytes=0,total_bytes=0,sent_bytes=0; ! 1199: time_t t,startall,startfile,ftime; ! 1200: struct ffblk ff; ! 1201: struct ftime ft; ! 1202: struct date dosdate; ! 1203: struct time dostime; ! 1204: FILE *stream,*log=NULL; ! 1205: ! 1206: mswtyp=TS_INT28; /* default to int 28 only */ ! 1207: ! 1208: ctrlbrk(cbreakh); ! 1209: ! 1210: if((asmrev=*(&riobp-1))!=19) { ! 1211: printf("Wrong rciol.obj\n"); ! 1212: exit(1); } ! 1213: ! 1214: lclini(0xd<<8); ! 1215: ! 1216: lprintf("\r\nSynchronet Transfer Protocols v1.00" ! 1217: " Developed 1993-1997 Rob Swindell\r\n\r\n"); ! 1218: ! 1219: lputs("Command line: "); ! 1220: for(i=1;i<argc;i++) ! 1221: lprintf("%s ",argv[i]); ! 1222: lputs("\r\n"); ! 1223: ! 1224: if(argc<3) { ! 1225: lprintf(usage); ! 1226: exit(1); } ! 1227: ! 1228: i=1; ! 1229: ! 1230: base=ahtoul(argv[i]); ! 1231: if(base>4 && base<0x100) /* 'D' and 'FFFF' are the same */ ! 1232: base=0xffff; ! 1233: if(base!=0xffff && base<5) ! 1234: switch(atoi(argv[i])) { ! 1235: case 1: ! 1236: base=0x3f8; ! 1237: irq=4; ! 1238: break; ! 1239: case 2: ! 1240: base=0x2f8; ! 1241: irq=3; ! 1242: break; ! 1243: case 3: ! 1244: base=0x3e8; ! 1245: irq=4; ! 1246: break; ! 1247: case 4: ! 1248: base=0x2e8; ! 1249: irq=3; ! 1250: break; ! 1251: default: ! 1252: lprintf("Invalid COM Port (%s)\r\n",argv[1]); ! 1253: lprintf(usage); ! 1254: exit(1); } ! 1255: ! 1256: if(base>4 || isdigit(argv[i+1][0])) ! 1257: irq=atoi(argv[++i]); ! 1258: ! 1259: for(i++;i<argc;i++) { ! 1260: ! 1261: if(!(mode&(SEND|RECV))) { ! 1262: if(toupper(argv[i][0])=='S' || toupper(argv[i][0])=='R') { /* cmd */ ! 1263: if(toupper(argv[i][0])=='R') ! 1264: mode|=RECV; ! 1265: else ! 1266: mode|=SEND; ! 1267: ! 1268: block_size=1024; ! 1269: ! 1270: switch(argv[i][1]) { ! 1271: case 'c': ! 1272: case 'C': ! 1273: mode|=CRC; ! 1274: case 'x': ! 1275: block_size=128; ! 1276: case 'X': ! 1277: mode|=XMODEM; ! 1278: break; ! 1279: case 'y': ! 1280: block_size=128; ! 1281: case 'Y': ! 1282: mode|=(YMODEM|CRC); ! 1283: break; ! 1284: case 'g': ! 1285: case 'G': ! 1286: mode|=(YMODEM|CRC|GMODE); ! 1287: break; ! 1288: case 'z': ! 1289: case 'Z': ! 1290: mode|=(ZMODEM|CRC); ! 1291: break; ! 1292: default: ! 1293: lprintf("Unrecognized command '%s'\r\n\r\n",argv[i]); ! 1294: lprintf(usage); ! 1295: exit(1); } } ! 1296: ! 1297: else if(toupper(argv[i][0])=='B') ! 1298: baud=atoi(argv[i]+1); ! 1299: ! 1300: else if(toupper(argv[i][0])=='T') ! 1301: mswtyp=atoi(argv[i]+1); ! 1302: ! 1303: else if(toupper(argv[i][0])=='O') ! 1304: mode|=OVERWRITE; ! 1305: ! 1306: else if(toupper(argv[i][0])=='D') ! 1307: mode|=IGNORE_DCD; ! 1308: ! 1309: else if(toupper(argv[i][0])=='A') ! 1310: mode|=ALARM; ! 1311: ! 1312: else if(toupper(argv[i][0])=='L') ! 1313: mode|=NO_LOCAL; ! 1314: ! 1315: else if(argv[i][0]=='*') ! 1316: mode|=DEBUG; } ! 1317: ! 1318: else if(argv[i][0]=='+') { ! 1319: if(mode&DIR) { ! 1320: lprintf("Cannot specify both directory and filename\r\n"); ! 1321: exit(1); } ! 1322: sprintf(str,"%s",argv[i]+1); ! 1323: if((file=nopen(str,O_RDONLY))==-1 ! 1324: || (stream=fdopen(file,"rb"))==NULL) { ! 1325: lprintf("Error opening filelist %s\r\n",str); ! 1326: exit(1); } ! 1327: while(!feof(stream) && !ferror(stream) && fnames<MAX_FNAMES) { ! 1328: if(!fgets(str,128,stream)) ! 1329: break; ! 1330: truncsp(str); ! 1331: strupr(str); ! 1332: if((fname[fnames]=(char *)malloc(strlen(str)+1))==NULL) { ! 1333: lprintf("Error allocating memory for filename\r\n"); ! 1334: exit(1); } ! 1335: strcpy(fname[fnames++],str); } ! 1336: fclose(stream); } ! 1337: ! 1338: else if(mode&(SEND|RECV)){ ! 1339: if((fname[fnames]=(char *)malloc(128))==NULL) { ! 1340: lprintf("Error allocating memory for filename\r\n"); ! 1341: exit(1); } ! 1342: strcpy(fname[fnames],argv[i]); ! 1343: strupr(fname[fnames]); ! 1344: j=strlen(fname[fnames]); ! 1345: if(fname[fnames][j-1]=='\\' /* Ends in \ */ ! 1346: || !strcmp(fname[fnames]+1,":")) { /* Drive letter only */ ! 1347: /* || !findfirst(fname[fnames],&ff,FA_DIREC)) { is a directory */ ! 1348: if(mode&DIR) { ! 1349: lprintf("Only one directory can be specified\r\n"); ! 1350: exit(1); } ! 1351: if(fnames) { ! 1352: lprintf("Cannot specify both directory and filename\r\n"); ! 1353: exit(1); } ! 1354: if(mode&SEND) { ! 1355: lprintf("Cannot send directory '%s'\r\n",fname[fnames]); ! 1356: exit(1);} ! 1357: mode|=DIR; } ! 1358: fnames++; } } ! 1359: ! 1360: if(!(mode&(SEND|RECV))) { ! 1361: lprintf("No command specified\r\n"); ! 1362: lprintf(usage); ! 1363: exit(1); } ! 1364: ! 1365: if(mode&(SEND|XMODEM) && !fnames) { /* Sending with any or recv w/Xmodem */ ! 1366: lprintf("Must specify filename or filelist\r\n"); ! 1367: lprintf(usage); ! 1368: exit(1); } ! 1369: ! 1370: i=strlen(fname[0]); /* Make sure the directory ends in \ or : */ ! 1371: if(mode&DIR && fname[0][i-1]!='\\' && fname[0][i-1]!=':') ! 1372: strcat(fname[0],"\\"); ! 1373: ! 1374: i=rioini(base,irq); ! 1375: if(i) { ! 1376: lprintf("STP: Error (%d) initializing COM port base %x irq %d\r\n" ! 1377: ,i,base,irq); ! 1378: exit(1); } ! 1379: ! 1380: if(mode&ALARM) { ! 1381: sound(1000); ! 1382: mswait(500); ! 1383: sound(2000); ! 1384: mswait(500); ! 1385: nosound(); } ! 1386: ! 1387: if(baud) { ! 1388: i=setbaud(baud); ! 1389: if(i) { ! 1390: lprintf("STP: Error setting baud rate to %u\r\n",baud); ! 1391: bail(1); } } ! 1392: else ! 1393: baud=rioctl(GBAUD); ! 1394: ! 1395: rioctl(IOSM|CTSCK|RTSCK); ! 1396: ! 1397: rioctl(TSTYPE|mswtyp); /* set time-slice API type */ ! 1398: ! 1399: if(!DCDHIGH) { ! 1400: newline(); ! 1401: lprintf("No carrier\r\n"); ! 1402: bail(1); } ! 1403: ! 1404: p=getenv("DSZLOG"); ! 1405: if(p) { ! 1406: if((file=open(p,O_WRONLY|O_BINARY|O_CREAT,S_IWRITE|S_IREAD))==-1 ! 1407: || (log=fdopen(file,"wb"))==NULL) { ! 1408: lprintf("Error opening DSZLOG file '%s'\r\n",p); ! 1409: bail(1); } ! 1410: setvbuf(log,NULL,_IOFBF,16*1024); } ! 1411: ! 1412: startall=time(NULL); ! 1413: ! 1414: if(mode&RECV) { ! 1415: if(fnames>1) ! 1416: lprintf("Receiving %u files\r\n",fnames); ! 1417: fnum=0; ! 1418: while(1) { ! 1419: if(mode&XMODEM) { ! 1420: strcpy(str,fname[0]); ! 1421: file_bytes=file_bytes_left=0x7fffffff; ! 1422: serial_num=-1; } ! 1423: ! 1424: else if(mode&YMODEM) { ! 1425: lprintf("Fetching Ymodem header block\r\n"); ! 1426: for(errors=0;errors<MAXERRORS;errors++) { ! 1427: if(errors>3 && mode&CRC && !(mode&GMODE)) ! 1428: mode&=~CRC; ! 1429: if(mode&GMODE) /* G for Ymodem-G */ ! 1430: putcom('G'); ! 1431: else if(mode&CRC) /* C for CRC */ ! 1432: putcom('C'); ! 1433: else /* NAK for checksum */ ! 1434: putcom(NAK); ! 1435: for(i=60;i;i--) { ! 1436: if(rioctl(RXBC)) /* no chars in-bound */ ! 1437: break; ! 1438: mswait(100); } /* so wait */ ! 1439: ! 1440: if(!i) { /* none after 6 secs */ ! 1441: if(errors) ! 1442: lprintf("Ymodem header timeout (%d)\r\n",errors); ! 1443: continue; } ! 1444: if(!get_block(1)) { /* block received successfully */ ! 1445: putcom(ACK); ! 1446: break; } } ! 1447: if(errors==MAXERRORS) { ! 1448: lprintf("Error fetching Ymodem header block\r\n"); ! 1449: cancel(); ! 1450: bail(1); } ! 1451: if(!block[0]) { ! 1452: lputs("Received Ymodem termination block\r\n"); ! 1453: bail(0); } ! 1454: p=block+strlen(block)+1; ! 1455: sscanf(p,"%ld %lo %lo %lo %d %ld" ! 1456: ,&file_bytes /* file size (decimal) */ ! 1457: ,&ftime /* file time (octal unix format) */ ! 1458: ,&m /* file mode (not used) */ ! 1459: ,&serial_num /* program serial number */ ! 1460: ,&total_files /* remaining files to be sent */ ! 1461: ,&total_bytes /* remaining bytes to be sent */ ! 1462: ); ! 1463: if(!file_bytes) ! 1464: file_bytes=0x7fffffff; ! 1465: file_bytes_left=file_bytes; ! 1466: if(!total_files) ! 1467: total_files=fnames-fnum; ! 1468: if(!total_files) ! 1469: total_files=1; ! 1470: if(total_bytes<file_bytes) ! 1471: total_bytes=file_bytes; ! 1472: if(!serial_num) ! 1473: serial_num=-1; ! 1474: strupr(block); ! 1475: lprintf("Incoming filename: %.64s ",block); ! 1476: if(mode&DIR) ! 1477: sprintf(str,"%s%s",fname[0],justfname(block,tmp)); ! 1478: else { ! 1479: justfname(block,str); ! 1480: for(i=0;i<fnames;i++) { ! 1481: if(!fname[i][0]) /* name blank or already used */ ! 1482: continue; ! 1483: justfname(fname[i],tmp); ! 1484: if(!stricmp(tmp,str)) { ! 1485: strcpy(str,fname[i]); ! 1486: fname[i][0]=0; ! 1487: break; } } ! 1488: if(i==fnames) { /* Not found in list */ ! 1489: if(fnames) ! 1490: lputs(" - Not in receive list!"); ! 1491: if(!fnames || fnum>=fnames || !fname[fnum][0]) ! 1492: justfname(block,str); /* worst case */ ! 1493: else { ! 1494: strcpy(str,fname[fnum]); ! 1495: fname[fnum][0]=0; } } } ! 1496: lputs("\r\n"); } ! 1497: ! 1498: else { /* Zmodem */ ! 1499: #if 0 ! 1500: tryzhdrtype=ZRINIT; ! 1501: while(1) { ! 1502: Txhdr[ZF0]=(CANFC32|CANFDX|CANOVIO|CANRLE); ! 1503: /* add CANBRK if we can send break signal */ ! 1504: if(zmode&CTRL_ESC) ! 1505: Txhdr[ZF0]|=TESCCTL; ! 1506: Txhdr[ZF1]=CANVHDR; ! 1507: Txhdr[ZP0]=0; ! 1508: Txhdr[ZP1]=0; ! 1509: putzhhdr(tryzhdrtype); ! 1510: done=0; ! 1511: while(!done) { ! 1512: done=1; ! 1513: switch(getzhdr()) { ! 1514: case ZRQINIT: ! 1515: if(Rxhdr[ZF3]&0x80) ! 1516: zmode|=VAR_HDRS; /* we can var header */ ! 1517: break; ! 1518: case ZFILE: ! 1519: zconv=Rxhdr[ZF0]; ! 1520: zmanag=Rxhdr[ZF1]; ! 1521: ztrans=Rxhdr[ZF2]; ! 1522: if(Rxhdr[ZF3]&ZCANVHDR) ! 1523: zmode|=VAR_HDRS; ! 1524: tryzhdrtype=ZRINIT; ! 1525: if(getzdata(block, 1024)==GOTCRCW) { ! 1526: /* something */ ! 1527: done=1; } ! 1528: putzhhdr(ZNAK); ! 1529: done=0; ! 1530: break; ! 1531: case ZSINIT: ! 1532: if(Rxhdr[ZF0]&TESCCTL) ! 1533: zmode|=CTRL_ESC; ! 1534: if (getzdata(attn,ZATTNLEN)==GOTCRCW) { ! 1535: ltohdr(1L); ! 1536: putzhhdr(ZACK); } ! 1537: else ! 1538: putzhhdr(ZNAK); ! 1539: done=0; ! 1540: break; ! 1541: case ZFREECNT: ! 1542: ltohdr(0); /* should be free disk space */ ! 1543: putzhhdr(ZACK); ! 1544: done=0; ! 1545: break; ! 1546: case ZCOMMAND: ! 1547: /*** ! 1548: cmdzack1flg = Rxhdr[ZF0]; ! 1549: if(getzdata(block,1024)==GOTCRCW) { ! 1550: if (cmdzack1flg & ZCACK1) ! 1551: ltohdr(0L); ! 1552: else ! 1553: ltohdr((long)sys2(block)); ! 1554: purgeline(); /* dump impatient questions */ ! 1555: do { ! 1556: zshhdr(4,ZCOMPL, Txhdr); ! 1557: } ! 1558: while (++errors<20 && zgethdr(Rxhdr,1)!=ZFIN); ! 1559: ackbibi(); ! 1560: if (cmdzack1flg & ZCACK1) ! 1561: exec2(block); ! 1562: return ZCOMPL; ! 1563: } ! 1564: ***/ ! 1565: putzhhdr(ZNAK); ! 1566: done=0; ! 1567: break; ! 1568: case ZCOMPL: ! 1569: done=0; ! 1570: break; ! 1571: case ZFIN: ! 1572: ackbibi(); ! 1573: return ZCOMPL; ! 1574: case ZCAN: ! 1575: return ERROR; } } ! 1576: #endif ! 1577: } ! 1578: ! 1579: fnum++; ! 1580: ! 1581: if(!(mode&DIR) && fnames && fnum>fnames) { ! 1582: newline(); ! 1583: lprintf("Attempt to send more files than specified\r\n"); ! 1584: cancel(); ! 1585: break; } ! 1586: ! 1587: k=strlen(str); /* strip out control characters and high ASCII */ ! 1588: for(i=j=0;i<k;i++) ! 1589: if(str[i]>SP && (uchar)str[i]<0x7f) ! 1590: str[j++]=str[i]; ! 1591: str[j]=0; ! 1592: strupr(str); ! 1593: if(fexist(str) && !(mode&OVERWRITE)) { ! 1594: lprintf("%s already exists\r\n",str); ! 1595: cancel(); ! 1596: bail(1); } ! 1597: if((file=nopen(str,O_WRONLY|O_CREAT|O_TRUNC))==-1 ! 1598: || (stream=fdopen(file,"wb"))==NULL) { ! 1599: lprintf("Error creating %s\r\n",str); ! 1600: cancel(); ! 1601: bail(1); } ! 1602: setvbuf(stream,NULL,_IOFBF,8*1024); ! 1603: startfile=time(NULL); ! 1604: lprintf("Receiving %s (%lu bytes) via %s %s\r\n" ! 1605: ,str ! 1606: ,mode&XMODEM ? 0 : file_bytes ! 1607: ,mode&XMODEM ? "Xmodem" : mode&YMODEM ? mode&GMODE ? "Ymodem-G" ! 1608: : "Ymodem" :"Zmodem" ! 1609: ,mode&CRC ? "CRC-16":"Checksum"); ! 1610: ! 1611: errors=0; ! 1612: block_num=0; ! 1613: if(mode&GMODE) /* G for Ymodem-G */ ! 1614: putcom('G'); ! 1615: else if(mode&CRC) /* C for CRC */ ! 1616: putcom('C'); ! 1617: else /* NAK for checksum */ ! 1618: putcom(NAK); ! 1619: while(errors<MAXERRORS) { ! 1620: if(block_num && !(mode&GMODE)) ! 1621: putcom(ACK); ! 1622: i=get_block(0); /* returns 0 if block okay */ ! 1623: if(i==EOT) /* end of transfer */ ! 1624: break; ! 1625: if(i) { /* other error */ ! 1626: cancel(); ! 1627: bail(1); } ! 1628: if(file_bytes_left<=0L) { /* No more bytes to send */ ! 1629: newline(); ! 1630: lputs("Attempt to send more than header specified\r\n"); ! 1631: break; } ! 1632: if(hdr_block_num==((block_num+1)&0xff)) { /* correct block */ ! 1633: block_num++; ! 1634: if(file_bytes_left<block_size) { ! 1635: if(fwrite(block,1,file_bytes_left,stream) ! 1636: !=file_bytes_left) { ! 1637: newline(); ! 1638: lprintf("Error writing to file\r\n"); ! 1639: cancel(); ! 1640: bail(1); } } ! 1641: else { ! 1642: if(fwrite(block,1,block_size,stream) ! 1643: !=block_size) { ! 1644: newline(); ! 1645: lprintf("Error writing to file\r\n"); ! 1646: cancel(); ! 1647: bail(1); } } ! 1648: file_bytes_left-=block_size; } ! 1649: else { ! 1650: newline(); ! 1651: lprintf("Block number %u instead of %u\r\n" ! 1652: ,hdr_block_num,(block_num+1)&0xff); ! 1653: // dump_block(); ! 1654: errors++; } ! 1655: t=time(NULL)-startfile; ! 1656: if(!t) t=1; ! 1657: cps=(uint)((block_num*(long)block_size)/t); /* cps so far */ ! 1658: if(!cps) cps=1; ! 1659: l=file_bytes/cps; /* total transfer est time */ ! 1660: l-=t; /* now, it's est time left */ ! 1661: if(l<0) l=0; ! 1662: b=blocks(file_bytes); ! 1663: if(mode&YMODEM) ! 1664: lprintf("\rBlock (%lu%s): %lu/%lu Byte: %lu Time: %lu:%02lu " ! 1665: "Left: %lu:%02lu CPS: %u %lu%% " ! 1666: ,block_size%1024L ? block_size: block_size/1024L ! 1667: ,block_size%1024L ? "" : "k" ! 1668: ,block_num ! 1669: ,b ! 1670: ,block_num*(long)block_size ! 1671: ,t/60L ! 1672: ,t%60L ! 1673: ,l/60L ! 1674: ,l%60L ! 1675: ,cps ! 1676: ,(long)(((float)block_num/(float)b)*100.0) ! 1677: ); ! 1678: else /* Xmodem */ ! 1679: lprintf("\rBlock (%lu%s): %lu Byte: %lu Time: %lu:%02lu " ! 1680: "CPS: %u " ! 1681: ,block_size%1024L ? block_size: block_size/1024L ! 1682: ,block_size%1024L ? "" : "k" ! 1683: ,block_num ! 1684: ,block_num*(long)block_size ! 1685: ,t/60L ! 1686: ,t%60L ! 1687: ,cps ! 1688: ); ! 1689: } ! 1690: ! 1691: putcom(ACK); ! 1692: if(!(mode&XMODEM) && ftime) { ! 1693: unixtodos(ftime,&dosdate,&dostime); ! 1694: if(dosdate.da_year>=1980) { ! 1695: ft.ft_min=dostime.ti_min; ! 1696: ft.ft_hour=dostime.ti_hour; ! 1697: ft.ft_tsec=dostime.ti_sec/2; ! 1698: ft.ft_year=dosdate.da_year-1980; ! 1699: ft.ft_day=dosdate.da_day; ! 1700: ft.ft_month=dosdate.da_mon; ! 1701: setftime(file,&ft); } } ! 1702: fclose(stream); ! 1703: t=time(NULL)-startfile; ! 1704: if(!t) t=1; ! 1705: l=(block_num-1)*(long)block_size; ! 1706: if(l>file_bytes) ! 1707: l=file_bytes; ! 1708: newline(); ! 1709: lprintf("Successsful - Time: %lu:%02lu CPS: %lu\r\n" ! 1710: ,t/60,t%60,l/t); ! 1711: if(log) { ! 1712: fprintf(log,"%c %6lu %5u bps %4lu cps %3u errors %5u %4u " ! 1713: "%s %d\r\n" ! 1714: ,mode&ZMODEM ? 'Z' : 'R' ! 1715: ,l ! 1716: ,baud ! 1717: ,l/t ! 1718: ,errors ! 1719: ,flows ! 1720: ,block_size ! 1721: ,str ! 1722: ,serial_num); } ! 1723: if(mode&XMODEM) ! 1724: break; ! 1725: total_files--; ! 1726: total_bytes-=file_bytes; ! 1727: if(total_files>1 && total_bytes) ! 1728: lprintf("Remaining - Time: %lu:%02lu Files: %u Bytes: %lu\r\n" ! 1729: ,(total_bytes/cps)/60 ! 1730: ,(total_bytes/cps)%60 ! 1731: ,total_files ! 1732: ,total_bytes ! 1733: ); ! 1734: } ! 1735: bail(0); } ! 1736: ! 1737: /********/ ! 1738: /* SEND */ ! 1739: /********/ ! 1740: ! 1741: /****************************************************/ ! 1742: /* Search through all to find total files and bytes */ ! 1743: /****************************************************/ ! 1744: for(fnum=0;fnum<fnames;fnum++) { ! 1745: last=findfirst(fname[fnum],&ff,0); /* incase wildcards are used */ ! 1746: if(last) ! 1747: lprintf("%s not found\r\n",fname[fnum]); ! 1748: while(!last) { ! 1749: total_files++; ! 1750: total_bytes+=ff.ff_fsize; ! 1751: last=findnext(&ff); } } ! 1752: ! 1753: if(fnames>1) ! 1754: lprintf("Sending %u files (%lu bytes total)\r\n" ! 1755: ,total_files,total_bytes); ! 1756: ! 1757: rioctl(IOFB); ! 1758: ! 1759: /***********************************************/ ! 1760: /* Send every file matching names or filespecs */ ! 1761: /***********************************************/ ! 1762: for(fnum=0;fnum<fnames;fnum++) { ! 1763: last=findfirst(fname[fnum],&ff,0); ! 1764: while(!last) { ! 1765: if(mode&ZMODEM) { ! 1766: #if 0 ! 1767: putcom('r'); putcom('z'); putcom(CR); /* send rz\r */ ! 1768: ltohdr(0L); /* Zero the header */ ! 1769: putzhhdr(ZRQINIT); ! 1770: getzrxinit(); ! 1771: #endif ! 1772: } /* Zmodem */ ! 1773: else { ! 1774: mode&=~GMODE; ! 1775: flows=0; ! 1776: for(errors=can=0;errors<MAXERRORS;errors++) { ! 1777: i=getcom(10); ! 1778: if(can && i!=CAN) ! 1779: can=0; ! 1780: if(i==NAK) { /* csum */ ! 1781: mode&=~CRC; ! 1782: break; } ! 1783: if(i=='C') { ! 1784: mode|=CRC; ! 1785: break; } ! 1786: if(i=='G') { ! 1787: mode|=(GMODE|CRC); ! 1788: break; } ! 1789: if(i==CAN) { ! 1790: if(can) { ! 1791: newline(); ! 1792: lprintf("Cancelled remotely\r\n"); ! 1793: bail(1); } ! 1794: can=1; } ! 1795: rioctl(IOFB); /* flush buffers cause we have crap-o-la */ ! 1796: if(i!=NOINP) { ! 1797: newline(); ! 1798: lprintf("Received %s Expected NAK, C, or G\r\n" ! 1799: ,chr(i)); } } ! 1800: if(errors==MAXERRORS) { ! 1801: lprintf("Timeout starting transfer\r\n"); ! 1802: cancel(); ! 1803: bail(1); } } /* X/Ymodem */ ! 1804: ! 1805: strcpy(str,fname[fnum]); ! 1806: if(strchr(str,'*') || strchr(str,'?')) { /* wildcards used */ ! 1807: p=strrchr(str,'\\'); ! 1808: if(!p) ! 1809: p=strchr(str,':'); ! 1810: if(p) ! 1811: *(p+1)=NULL; ! 1812: else ! 1813: str[0]=0; ! 1814: strcat(str,ff.ff_name); } ! 1815: ! 1816: lprintf("Sending %s (%lu bytes) via %s %s\r\n" ! 1817: ,str,ff.ff_fsize ! 1818: ,mode&XMODEM ? "Xmodem" : mode&YMODEM ? mode&GMODE ? "Ymodem-G" ! 1819: : "Ymodem" :"Zmodem" ! 1820: ,mode&CRC ? "CRC-16":"Checksum"); ! 1821: ! 1822: if((file=nopen(str,O_RDONLY))==-1 ! 1823: || (stream=fdopen(file,"rb"))==NULL) { ! 1824: lprintf("Error opening %s for read\r\n",str); ! 1825: cancel(); ! 1826: bail(1); } ! 1827: setvbuf(stream,NULL,_IOFBF,8*1024); ! 1828: rioctl(IOFB); /* flush buffers cause extra 'G', 'C', or NAKs */ ! 1829: if(!(mode&XMODEM)) { ! 1830: getftime(file,&ft); ! 1831: dostime.ti_min=ft.ft_min; ! 1832: dostime.ti_hour=ft.ft_hour; ! 1833: dostime.ti_hund=0; ! 1834: dostime.ti_sec=ft.ft_tsec*2; ! 1835: dosdate.da_year=1980+ft.ft_year; ! 1836: dosdate.da_day=ft.ft_day; ! 1837: dosdate.da_mon=ft.ft_month; ! 1838: t=dostounix(&dosdate,&dostime); ! 1839: memset(block,NULL,128); ! 1840: strcpy(block,ff.ff_name); ! 1841: strlwr(block); ! 1842: sprintf(block+strlen(block)+1,"%lu %lo 0 0 %d %ld" ! 1843: ,ff.ff_fsize,t,total_files-sent_files,total_bytes-sent_bytes); ! 1844: /* ! 1845: lprintf("Sending Ymodem block '%s'\r\n",block+strlen(block)+1); ! 1846: */ ! 1847: block_num=0; ! 1848: i=block_size; ! 1849: block_size=128; /* Always use 128 for first block */ ! 1850: for(errors=0;errors<MAXERRORS;errors++) { ! 1851: put_block(); ! 1852: if(get_ack()) ! 1853: break; } ! 1854: if(errors==MAXERRORS) { ! 1855: newline(); ! 1856: lprintf("Failed to send header block\r\n"); ! 1857: cancel(); ! 1858: bail(1); } ! 1859: block_size=i; /* Restore block size */ ! 1860: mode&=~GMODE; ! 1861: for(errors=can=0;errors<MAXERRORS;errors++) { ! 1862: i=getcom(10); ! 1863: if(can && i!=CAN) ! 1864: can=0; ! 1865: if(i==NAK) { /* csum */ ! 1866: mode&=~CRC; ! 1867: break; } ! 1868: if(i=='C') { ! 1869: mode|=CRC; ! 1870: break; } ! 1871: if(i=='G') { ! 1872: mode|=(GMODE|CRC); ! 1873: break; } ! 1874: if(i==CAN) { ! 1875: if(can) { ! 1876: newline(); ! 1877: lprintf("Cancelled remotely\r\n"); ! 1878: bail(1); } ! 1879: can=1; } ! 1880: rioctl(IOFB); ! 1881: if(i!=NOINP) { ! 1882: newline(); ! 1883: lprintf("Received %s Expected NAK, C, or G\r\n" ! 1884: ,chr(i)); } } ! 1885: if(errors==MAXERRORS) { ! 1886: newline(); ! 1887: lprintf("Too many errors waiting for receiver\r\n"); ! 1888: cancel(); ! 1889: bail(1); } } ! 1890: last_block_num=block_num=1; ! 1891: startfile=time(NULL); ! 1892: errors=0; ! 1893: while((block_num-1)*(long)block_size<ff.ff_fsize && errors<MAXERRORS) { ! 1894: if(last_block_num==block_num) { /* block_num didn't increment */ ! 1895: fseek(stream,(block_num-1)*(long)block_size,SEEK_SET); ! 1896: i=fread(block,1,block_size,stream); ! 1897: while(i<block_size) ! 1898: block[i++]=CPMEOF; } ! 1899: last_block_num=block_num; ! 1900: put_block(); ! 1901: i=fread(block,1,block_size,stream); /* read next block from disk */ ! 1902: while(i<block_size) ! 1903: block[i++]=CPMEOF; ! 1904: t=time(NULL)-startfile; ! 1905: if(!t) t=1; /* t is time so far */ ! 1906: cps=(uint)((block_num*(long)block_size)/t); /* cps so far */ ! 1907: if(!cps) cps=1; ! 1908: l=ff.ff_fsize/cps; /* total transfer est time */ ! 1909: l-=t; /* now, it's est time left */ ! 1910: if(l<0) l=0; ! 1911: b=blocks(ff.ff_fsize); ! 1912: lprintf("\rBlock (%lu%s): %lu/%lu Byte: %lu " ! 1913: "Time: %lu:%02lu Left: %lu:%02lu CPS: %u %lu%% " ! 1914: ,block_size%1024L ? block_size: block_size/1024L ! 1915: ,block_size%1024L ? "" : "k" ! 1916: ,block_num ! 1917: ,b ! 1918: ,block_num*(long)block_size ! 1919: ,t/60L ! 1920: ,t%60L ! 1921: ,l/60L ! 1922: ,l%60L ! 1923: ,cps ! 1924: ,(long)(((float)block_num/(float)b)*100.0) ! 1925: ); ! 1926: if(!get_ack()) ! 1927: errors++; ! 1928: else ! 1929: block_num++; } ! 1930: fclose(stream); ! 1931: success=0; ! 1932: if((block_num-1)*(long)block_size>=ff.ff_fsize) { ! 1933: sent_files++; ! 1934: sent_bytes+=ff.ff_fsize; ! 1935: riosync(); ! 1936: lprintf("\n"); ! 1937: ! 1938: for(i=0;i<10;i++) { ! 1939: lprintf("\rSending EOT (%d)",i+1); ! 1940: rioctl(IOFI); ! 1941: putcom(EOT); ! 1942: ch=getcom(10); ! 1943: if(ch==ACK) ! 1944: break; ! 1945: if(ch==NAK && i==0 && (mode&(YMODEM|GMODE))==YMODEM) ! 1946: continue; /* chuck's double EOT trick so don't complain */ ! 1947: if(ch!=NOINP) { ! 1948: newline(); ! 1949: lprintf("Received %s Expected ACK\r\n" ! 1950: ,chr(ch)); } } ! 1951: if(i==3) ! 1952: lprintf("\rNo ACK on EOT \n"); ! 1953: t=time(NULL)-startfile; ! 1954: if(!t) t=1; ! 1955: lprintf("\rSuccesssful - Time: %lu:%02lu CPS: %lu\r\n" ! 1956: ,t/60,t%60,ff.ff_fsize/t); ! 1957: success=1; } ! 1958: else { ! 1959: newline(); ! 1960: lputs("Unsuccessful!\r\n"); ! 1961: t=time(NULL)-startfile; ! 1962: if(!t) t=1; } ! 1963: ! 1964: if(total_files>1 && total_files-sent_files>1) ! 1965: lprintf("Remaining - Time: %lu:%02lu Files: %u Bytes: %lu\r\n" ! 1966: ,((total_bytes-sent_bytes)/cps)/60 ! 1967: ,((total_bytes-sent_bytes)/cps)%60 ! 1968: ,total_files-sent_files ! 1969: ,total_bytes-sent_bytes ! 1970: ); ! 1971: if(log) { ! 1972: l=(block_num-1)*(long)block_size; ! 1973: if(l>ff.ff_fsize) ! 1974: l=ff.ff_fsize; ! 1975: fprintf(log,"%c %6lu %5u bps %4lu cps %3u errors %5u %4u " ! 1976: "%s -1\r\n" ! 1977: ,success ? (mode&ZMODEM ? 'z':'S') : 'E' ! 1978: ,l ! 1979: ,baud ! 1980: ,l/t ! 1981: ,errors ! 1982: ,flows ! 1983: ,block_size ! 1984: ,fname[fnum]); } ! 1985: ! 1986: last=findnext(&ff); } } ! 1987: if(mode&XMODEM) ! 1988: bail(0); ! 1989: mode&=~GMODE; ! 1990: i=getcom(10); ! 1991: if(i==NAK) ! 1992: mode&=~CRC; ! 1993: else if(i=='C') ! 1994: mode|=CRC; ! 1995: else if(i=='G') ! 1996: mode|=(GMODE|CRC); ! 1997: if(i!=NOINP && i!=NAK && i!='C' && i!='G') { ! 1998: newline(); ! 1999: lprintf("Received %s Expected NAK, C, or G\r\n",chr(i)); } ! 2000: else if(i!=NOINP) { ! 2001: block_num=0; ! 2002: block[0]=0; ! 2003: block_size=128; ! 2004: put_block(); ! 2005: if(!get_ack()) { ! 2006: newline(); ! 2007: lprintf("Failed to receive ACK after terminating block\r\n"); } } ! 2008: if(total_files>1) { ! 2009: t=time(NULL)-startall; ! 2010: if(!t) t=1; ! 2011: newline(); ! 2012: lprintf("Overall - Time %02lu:%02lu Bytes: %lu CPS: %lu\r\n" ! 2013: ,t/60,t%60,sent_bytes,sent_bytes/t); } ! 2014: bail(0); ! 2015: return(0); ! 2016: } ! 2017:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.