Improve the process for GNU tools
[minix3.git] / minix / commands / zmodem / zm.c
blob56ced1a65df9f2c69cf5d19f8a0754bf5e9a7a7d
1 /*
2 * Z M . C
3 * ZMODEM protocol primitives
4 * 05-09-88 Chuck Forsberg Omen Technology Inc
6 * Entry point Functions:
7 * zsbhdr(type, hdr) send binary header
8 * zshhdr(type, hdr) send hex header
9 * zgethdr(hdr, eflag) receive header - binary or hex
10 * zsdata(buf, len, frameend) send data
11 * zrdata(buf, len) receive data
12 * stohdr(pos) store position data in Txhdr
13 * long rclhdr(hdr) recover position offset from header
16 #ifndef CANFDX
17 #include "zmodem.h"
18 #endif
19 int Rxtimeout = 100; /* Tenths of seconds to wait for something */
21 #ifndef UNSL
22 #define UNSL
23 #endif
26 /* Globals used by ZMODEM functions */
27 int Rxframeind; /* ZBIN ZBIN32, or ZHEX type of frame received */
28 int Rxtype; /* Type of header received */
29 int Rxcount; /* Count of data bytes received */
30 char Rxhdr[4]; /* Received header */
31 char Txhdr[4]; /* Transmitted header */
32 long Rxpos; /* Received file position */
33 long Txpos; /* Transmitted file position */
34 int Txfcs32; /* TURE means send binary frames with 32 bit FCS */
35 int Crc32t; /* Display flag indicating 32 bit CRC being sent */
36 int Crc32; /* Display flag indicating 32 bit CRC being received */
37 int Znulls; /* Number of nulls to send at beginning of ZDATA hdr */
38 char Attn[ZATTNLEN+1]; /* Attention string rx sends to tx on err */
40 static int lastsent; /* Last char we sent */
41 static int Not8bit; /* Seven bits seen on header */
43 static char *frametypes[] = {
44 "Carrier Lost", /* -3 */
45 "TIMEOUT", /* -2 */
46 "ERROR", /* -1 */
47 #define FTOFFSET 3
48 "ZRQINIT",
49 "ZRINIT",
50 "ZSINIT",
51 "ZACK",
52 "ZFILE",
53 "ZSKIP",
54 "ZNAK",
55 "ZABORT",
56 "ZFIN",
57 "ZRPOS",
58 "ZDATA",
59 "ZEOF",
60 "ZFERR",
61 "ZCRC",
62 "ZCHALLENGE",
63 "ZCOMPL",
64 "ZCAN",
65 "ZFREECNT",
66 "ZCOMMAND",
67 "ZSTDERR",
68 "xxxxx"
69 #define FRTYPES 22 /* Total number of frame types in this array */
70 /* not including psuedo negative entries */
73 static char badcrc[] = "Bad CRC";
75 /* Send ZMODEM binary header hdr of type type */
76 void zsbhdr(int type, char *hdr)
78 register int n;
79 register unsigned short crc;
81 vfile("zsbhdr: %s %lx", frametypes[type+FTOFFSET], rclhdr(hdr));
82 if (type == ZDATA)
83 for (n = Znulls; --n >=0; )
84 xsendline(0);
86 xsendline(ZPAD); xsendline(ZDLE);
88 if ((Crc32t=Txfcs32))
89 zsbh32(hdr, type);
90 else {
91 xsendline(ZBIN); zsendline(type); crc = updcrc(type, 0);
93 for (n=4; --n >= 0; ++hdr) {
94 zsendline(*hdr);
95 crc = updcrc((0377& *hdr), crc);
97 crc = updcrc(0,updcrc(0,crc));
98 zsendline(crc>>8);
99 zsendline(crc);
101 if (type != ZDATA)
102 flushmo();
106 /* Send ZMODEM binary header hdr of type type */
107 void zsbh32(char *hdr, int type)
109 register int n;
110 register UNSL long crc;
112 xsendline(ZBIN32); zsendline(type);
113 crc = 0xFFFFFFFFL; crc = UPDC32(type, crc);
115 for (n=4; --n >= 0; ++hdr) {
116 crc = UPDC32((0377 & *hdr), crc);
117 zsendline(*hdr);
119 crc = ~crc;
120 for (n=4; --n >= 0;) {
121 zsendline((int)crc);
122 crc >>= 8;
126 /* Send ZMODEM HEX header hdr of type type */
127 void zshhdr(int type, char *hdr)
129 register int n;
130 register unsigned short crc;
132 vfile("zshhdr: %s %lx", frametypes[type+FTOFFSET], rclhdr(hdr));
133 sendline(ZPAD); sendline(ZPAD); sendline(ZDLE); sendline(ZHEX);
134 zputhex(type);
135 Crc32t = 0;
137 crc = updcrc(type, 0);
138 for (n=4; --n >= 0; ++hdr) {
139 zputhex(*hdr); crc = updcrc((0377 & *hdr), crc);
141 crc = updcrc(0,updcrc(0,crc));
142 zputhex(crc>>8); zputhex(crc);
144 /* Make it printable on remote machine */
145 sendline(015); sendline(0212);
147 * Uncork the remote in case a fake XOFF has stopped data flow
149 if (type != ZFIN && type != ZACK)
150 sendline(021);
151 flushmo();
155 * Send binary array buf of length length, with ending ZDLE sequence frameend
157 static char *Zendnames[] = { "ZCRCE", "ZCRCG", "ZCRCQ", "ZCRCW"};
159 void zsdata(char *buf, int length, int frameend)
161 register unsigned short crc;
163 vfile("zsdata: %d %s", length, Zendnames[(frameend-ZCRCE)&3]);
164 if (Crc32t)
165 zsda32(buf, length, frameend);
166 else {
167 crc = 0;
168 for (;--length >= 0; ++buf) {
169 zsendline(*buf); crc = updcrc((0377 & *buf), crc);
171 xsendline(ZDLE); xsendline(frameend);
172 crc = updcrc(frameend, crc);
174 crc = updcrc(0,updcrc(0,crc));
175 zsendline(crc>>8); zsendline(crc);
177 if (frameend == ZCRCW) {
178 xsendline(XON); flushmo();
182 void zsda32(char *buf, int length, int frameend)
184 register int c;
185 register UNSL long crc;
187 crc = 0xFFFFFFFFL;
188 for (;--length >= 0; ++buf) {
189 c = *buf & 0377;
190 if (c & 0140)
191 xsendline(lastsent = c);
192 else
193 zsendline(c);
194 crc = UPDC32(c, crc);
196 xsendline(ZDLE); xsendline(frameend);
197 crc = UPDC32(frameend, crc);
199 crc = ~crc;
200 for (length=4; --length >= 0;) {
201 zsendline((int)crc); crc >>= 8;
206 * Receive array buf of max length with ending ZDLE sequence
207 * and CRC. Returns the ending character or error code.
208 * NB: On errors may store length+1 bytes!
210 int zrdata(char *buf, int length)
212 register int c;
213 register unsigned short crc;
214 register char *end;
215 register int d;
217 if (Rxframeind == ZBIN32)
218 return zrdat32(buf, length);
220 crc = Rxcount = 0; end = buf + length;
221 while (buf <= end) {
222 if ((c = zdlread()) & ~0377) {
223 crcfoo:
224 switch (c) {
225 case GOTCRCE:
226 case GOTCRCG:
227 case GOTCRCQ:
228 case GOTCRCW:
229 crc = updcrc((((d=c))&0377), crc);
230 if ((c = zdlread()) & ~0377)
231 goto crcfoo;
232 crc = updcrc(c, crc);
233 if ((c = zdlread()) & ~0377)
234 goto crcfoo;
235 crc = updcrc(c, crc);
236 if (crc & 0xFFFF) {
237 zperr(badcrc);
238 return ERROR;
240 Rxcount = length - (end - buf);
241 vfile("zrdata: %d %s", Rxcount,
242 Zendnames[(d-GOTCRCE)&3]);
243 return d;
244 case GOTCAN:
245 zperr("Sender Canceled");
246 return ZCAN;
247 case TIMEOUT:
248 zperr("TIMEOUT");
249 return c;
250 default:
251 zperr("Bad data subpacket");
252 return c;
255 *buf++ = c;
256 crc = updcrc(c, crc);
258 zperr("Data subpacket too long");
259 return ERROR;
262 int zrdat32(char *buf, int length)
264 register int c;
265 register UNSL long crc;
266 register char *end;
267 register int d;
269 crc = 0xFFFFFFFFL; Rxcount = 0; end = buf + length;
270 while (buf <= end) {
271 if ((c = zdlread()) & ~0377) {
272 crcfoo:
273 switch (c) {
274 case GOTCRCE:
275 case GOTCRCG:
276 case GOTCRCQ:
277 case GOTCRCW:
278 d = c; c &= 0377;
279 crc = UPDC32(c, crc);
280 if ((c = zdlread()) & ~0377)
281 goto crcfoo;
282 crc = UPDC32(c, crc);
283 if ((c = zdlread()) & ~0377)
284 goto crcfoo;
285 crc = UPDC32(c, crc);
286 if ((c = zdlread()) & ~0377)
287 goto crcfoo;
288 crc = UPDC32(c, crc);
289 if ((c = zdlread()) & ~0377)
290 goto crcfoo;
291 crc = UPDC32(c, crc);
292 if (crc != 0xDEBB20E3) {
293 zperr(badcrc);
294 return ERROR;
296 Rxcount = length - (end - buf);
297 vfile("zrdat32: %d %s", Rxcount,
298 Zendnames[(d-GOTCRCE)&3]);
299 return d;
300 case GOTCAN:
301 zperr("Sender Canceled");
302 return ZCAN;
303 case TIMEOUT:
304 zperr("TIMEOUT");
305 return c;
306 default:
307 zperr("Bad data subpacket");
308 return c;
311 *buf++ = c;
312 crc = UPDC32(c, crc);
314 zperr("Data subpacket too long");
315 return ERROR;
320 * Read a ZMODEM header to hdr, either binary or hex.
321 * eflag controls local display of non zmodem characters:
322 * 0: no display
323 * 1: display printing characters only
324 * 2: display all non ZMODEM characters
325 * On success, set Zmodem to 1, set Rxpos and return type of header.
326 * Otherwise return negative on error.
327 * Return ERROR instantly if ZCRCW sequence, for fast error recovery.
329 int zgethdr(char *hdr, int eflag)
331 register int c, n, cancount;
333 n = Zrwindow + Baudrate; /* Max bytes before start of frame */
334 Rxframeind = Rxtype = 0;
336 startover:
337 cancount = 5;
338 again:
339 /* Return immediate ERROR if ZCRCW sequence seen */
340 switch (c = readline(Rxtimeout)) {
341 case RCDO:
342 case TIMEOUT:
343 goto fifi;
344 case CAN:
345 gotcan:
346 if (--cancount <= 0) {
347 c = ZCAN; goto fifi;
349 switch (c = readline(1)) {
350 case TIMEOUT:
351 goto again;
352 case ZCRCW:
353 c = ERROR;
354 /* **** FALL THRU TO **** */
355 case RCDO:
356 goto fifi;
357 default:
358 break;
359 case CAN:
360 if (--cancount <= 0) {
361 c = ZCAN; goto fifi;
363 goto again;
365 /* **** FALL THRU TO **** */
366 default:
367 agn2:
368 if ( --n == 0) {
369 zperr("Garbage count exceeded");
370 return(ERROR);
372 if (eflag && ((c &= 0177) & 0140))
373 bttyout(c);
374 else if (eflag > 1)
375 bttyout(c);
376 #ifdef UNIX
377 fflush(stderr);
378 #endif
379 goto startover;
380 case ZPAD|0200: /* This is what we want. */
381 Not8bit = c;
382 case ZPAD: /* This is what we want. */
383 break;
385 cancount = 5;
386 splat:
387 switch (c = noxrd7()) {
388 case ZPAD:
389 goto splat;
390 case RCDO:
391 case TIMEOUT:
392 goto fifi;
393 default:
394 goto agn2;
395 case ZDLE: /* This is what we want. */
396 break;
399 switch (c = noxrd7()) {
400 case RCDO:
401 case TIMEOUT:
402 goto fifi;
403 case ZBIN:
404 Rxframeind = ZBIN; Crc32 = FALSE;
405 c = zrbhdr(hdr);
406 break;
407 case ZBIN32:
408 Crc32 = Rxframeind = ZBIN32;
409 c = zrbhdr32(hdr);
410 break;
411 case ZHEX:
412 Rxframeind = ZHEX; Crc32 = FALSE;
413 c = zrhhdr(hdr);
414 break;
415 case CAN:
416 goto gotcan;
417 default:
418 goto agn2;
420 Rxpos = hdr[ZP3] & 0377;
421 Rxpos = (Rxpos<<8) + (hdr[ZP2] & 0377);
422 Rxpos = (Rxpos<<8) + (hdr[ZP1] & 0377);
423 Rxpos = (Rxpos<<8) + (hdr[ZP0] & 0377);
424 fifi:
425 switch (c) {
426 case GOTCAN:
427 c = ZCAN;
428 /* **** FALL THRU TO **** */
429 case ZNAK:
430 case ZCAN:
431 case ERROR:
432 case TIMEOUT:
433 case RCDO:
434 zperr("Got %s", frametypes[c+FTOFFSET]);
435 /* **** FALL THRU TO **** */
436 default:
437 if (c >= -3 && c <= FRTYPES)
438 vfile("zgethdr: %s %lx", frametypes[c+FTOFFSET], Rxpos);
439 else
440 vfile("zgethdr: %d %lx", c, Rxpos);
442 return c;
445 /* Receive a binary style header (type and position) */
446 int zrbhdr(char *hdr)
448 register int c, n;
449 register unsigned short crc;
451 if ((c = zdlread()) & ~0377)
452 return c;
453 Rxtype = c;
454 crc = updcrc(c, 0);
456 for (n=4; --n >= 0; ++hdr) {
457 if ((c = zdlread()) & ~0377)
458 return c;
459 crc = updcrc(c, crc);
460 *hdr = c;
462 if ((c = zdlread()) & ~0377)
463 return c;
464 crc = updcrc(c, crc);
465 if ((c = zdlread()) & ~0377)
466 return c;
467 crc = updcrc(c, crc);
468 if (crc & 0xFFFF) {
469 zperr(badcrc);
470 return ERROR;
472 #ifdef ZMODEM
473 Protocol = ZMODEM;
474 #endif
475 Zmodem = 1;
476 return Rxtype;
479 /* Receive a binary style header (type and position) with 32 bit FCS */
480 int zrbhdr32(char *hdr)
482 register int c, n;
483 register UNSL long crc;
485 if ((c = zdlread()) & ~0377)
486 return c;
487 Rxtype = c;
488 crc = 0xFFFFFFFFL; crc = UPDC32(c, crc);
489 #ifdef DEBUGZ
490 vfile("zrbhdr32 c=%X crc=%lX", c, crc);
491 #endif
493 for (n=4; --n >= 0; ++hdr) {
494 if ((c = zdlread()) & ~0377)
495 return c;
496 crc = UPDC32(c, crc);
497 *hdr = c;
498 #ifdef DEBUGZ
499 vfile("zrbhdr32 c=%X crc=%lX", c, crc);
500 #endif
502 for (n=4; --n >= 0;) {
503 if ((c = zdlread()) & ~0377)
504 return c;
505 crc = UPDC32(c, crc);
506 #ifdef DEBUGZ
507 vfile("zrbhdr32 c=%X crc=%lX", c, crc);
508 #endif
510 if (crc != 0xDEBB20E3) {
511 zperr(badcrc);
512 return ERROR;
514 #ifdef ZMODEM
515 Protocol = ZMODEM;
516 #endif
517 Zmodem = 1;
518 return Rxtype;
522 /* Receive a hex style header (type and position) */
523 int zrhhdr(char *hdr)
525 register int c;
526 register unsigned short crc;
527 register int n;
529 if ((c = zgethex()) < 0)
530 return c;
531 Rxtype = c;
532 crc = updcrc(c, 0);
534 for (n=4; --n >= 0; ++hdr) {
535 if ((c = zgethex()) < 0)
536 return c;
537 crc = updcrc(c, crc);
538 *hdr = c;
540 if ((c = zgethex()) < 0)
541 return c;
542 crc = updcrc(c, crc);
543 if ((c = zgethex()) < 0)
544 return c;
545 crc = updcrc(c, crc);
546 if (crc & 0xFFFF) {
547 zperr(badcrc); return ERROR;
549 switch ( c = readline(1)) {
550 case 0215:
551 Not8bit = c;
552 /* **** FALL THRU TO **** */
553 case 015:
554 /* Throw away possible cr/lf */
555 switch (c = readline(1)) {
556 case 012:
557 Not8bit |= c;
560 #ifdef ZMODEM
561 Protocol = ZMODEM;
562 #endif
563 Zmodem = 1; return Rxtype;
566 /* Send a byte as two hex digits */
567 void zputhex(int c)
569 static char digits[] = "0123456789abcdef";
571 if (Verbose>8)
572 vfile("zputhex: %02X", c);
573 sendline(digits[(c&0xF0)>>4]);
574 sendline(digits[(c)&0xF]);
578 * Send character c with ZMODEM escape sequence encoding.
579 * Escape XON, XOFF. Escape CR following @ (Telenet net escape)
581 void zsendline(int c)
584 /* Quick check for non control characters */
585 if (c & 0140)
586 xsendline(lastsent = c);
587 else {
588 switch (c &= 0377) {
589 case ZDLE:
590 xsendline(ZDLE);
591 xsendline (lastsent = (c ^= 0100));
592 break;
593 case 015:
594 case 0215:
595 if (!Zctlesc && (lastsent & 0177) != '@')
596 goto sendit;
597 /* **** FALL THRU TO **** */
598 case 020:
599 case 021:
600 case 023:
601 case 0220:
602 case 0221:
603 case 0223:
604 xsendline(ZDLE);
605 c ^= 0100;
606 sendit:
607 xsendline(lastsent = c);
608 break;
609 default:
610 if (Zctlesc && ! (c & 0140)) {
611 xsendline(ZDLE);
612 c ^= 0100;
614 xsendline(lastsent = c);
619 /* Decode two lower case hex digits into an 8 bit byte value */
620 int zgethex()
622 register int c;
624 c = zgeth1();
625 if (Verbose>8)
626 vfile("zgethex: %02X", c);
627 return c;
629 int zgeth1()
631 register int c, n;
633 if ((c = noxrd7()) < 0)
634 return c;
635 n = c - '0';
636 if (n > 9)
637 n -= ('a' - ':');
638 if (n & ~0xF)
639 return ERROR;
640 if ((c = noxrd7()) < 0)
641 return c;
642 c -= '0';
643 if (c > 9)
644 c -= ('a' - ':');
645 if (c & ~0xF)
646 return ERROR;
647 c += (n<<4);
648 return c;
652 * Read a byte, checking for ZMODEM escape encoding
653 * including CAN*5 which represents a quick abort
655 int zdlread()
657 register int c;
659 again:
660 /* Quick check for non control characters */
661 if ((c = readline(Rxtimeout)) & 0140)
662 return c;
663 switch (c) {
664 case ZDLE:
665 break;
666 case 023:
667 case 0223:
668 case 021:
669 case 0221:
670 goto again;
671 default:
672 if (Zctlesc && !(c & 0140)) {
673 goto again;
675 return c;
677 again2:
678 if ((c = readline(Rxtimeout)) < 0)
679 return c;
680 if (c == CAN && (c = readline(Rxtimeout)) < 0)
681 return c;
682 if (c == CAN && (c = readline(Rxtimeout)) < 0)
683 return c;
684 if (c == CAN && (c = readline(Rxtimeout)) < 0)
685 return c;
686 switch (c) {
687 case CAN:
688 return GOTCAN;
689 case ZCRCE:
690 case ZCRCG:
691 case ZCRCQ:
692 case ZCRCW:
693 return (c | GOTOR);
694 case ZRUB0:
695 return 0177;
696 case ZRUB1:
697 return 0377;
698 case 023:
699 case 0223:
700 case 021:
701 case 0221:
702 goto again2;
703 default:
704 if (Zctlesc && ! (c & 0140)) {
705 goto again2;
707 if ((c & 0140) == 0100)
708 return (c ^ 0100);
709 break;
711 if (Verbose>1)
712 zperr("Bad escape sequence %x", c);
713 return ERROR;
717 * Read a character from the modem line with timeout.
718 * Eat parity, XON and XOFF characters.
720 int noxrd7()
722 register int c;
724 for (;;) {
725 if ((c = readline(Rxtimeout)) < 0)
726 return c;
727 switch (c &= 0177) {
728 case XON:
729 case XOFF:
730 continue;
731 default:
732 if (Zctlesc && !(c & 0140))
733 continue;
734 case '\r':
735 case '\n':
736 case ZDLE:
737 return c;
742 /* Store long integer pos in Txhdr */
743 void stohdr(long pos)
745 Txhdr[ZP0] = pos;
746 Txhdr[ZP1] = pos>>8;
747 Txhdr[ZP2] = pos>>16;
748 Txhdr[ZP3] = pos>>24;
751 /* Recover a long integer from a header */
752 long
753 rclhdr(char *hdr)
755 register long l;
757 l = (hdr[ZP3] & 0377);
758 l = (l << 8) | (hdr[ZP2] & 0377);
759 l = (l << 8) | (hdr[ZP1] & 0377);
760 l = (l << 8) | (hdr[ZP0] & 0377);
761 return l;
764 /* End of zm.c */