|
|
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.