SYSENTER/SYSCALL support
[minix.git] / commands / zmodem / zm.c
blob9e97b08e9df81bc64573deec50e83af2c0c5131e
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 lastsent; /* Last char we sent */
41 static 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(type, hdr)
77 int type;
78 register char *hdr;
80 register int n;
81 register unsigned short crc;
83 vfile("zsbhdr: %s %lx", frametypes[type+FTOFFSET], rclhdr(hdr));
84 if (type == ZDATA)
85 for (n = Znulls; --n >=0; )
86 xsendline(0);
88 xsendline(ZPAD); xsendline(ZDLE);
90 if (Crc32t=Txfcs32)
91 zsbh32(hdr, type);
92 else {
93 xsendline(ZBIN); zsendline(type); crc = updcrc(type, 0);
95 for (n=4; --n >= 0; ++hdr) {
96 zsendline(*hdr);
97 crc = updcrc((0377& *hdr), crc);
99 crc = updcrc(0,updcrc(0,crc));
100 zsendline(crc>>8);
101 zsendline(crc);
103 if (type != ZDATA)
104 flushmo();
108 /* Send ZMODEM binary header hdr of type type */
109 void zsbh32(hdr, type)
110 register char *hdr;
111 int type;
113 register int n;
114 register UNSL long crc;
116 xsendline(ZBIN32); zsendline(type);
117 crc = 0xFFFFFFFFL; crc = UPDC32(type, crc);
119 for (n=4; --n >= 0; ++hdr) {
120 crc = UPDC32((0377 & *hdr), crc);
121 zsendline(*hdr);
123 crc = ~crc;
124 for (n=4; --n >= 0;) {
125 zsendline((int)crc);
126 crc >>= 8;
130 /* Send ZMODEM HEX header hdr of type type */
131 void zshhdr(type, hdr)
132 int type;
133 register char *hdr;
135 register int n;
136 register unsigned short crc;
138 vfile("zshhdr: %s %lx", frametypes[type+FTOFFSET], rclhdr(hdr));
139 sendline(ZPAD); sendline(ZPAD); sendline(ZDLE); sendline(ZHEX);
140 zputhex(type);
141 Crc32t = 0;
143 crc = updcrc(type, 0);
144 for (n=4; --n >= 0; ++hdr) {
145 zputhex(*hdr); crc = updcrc((0377 & *hdr), crc);
147 crc = updcrc(0,updcrc(0,crc));
148 zputhex(crc>>8); zputhex(crc);
150 /* Make it printable on remote machine */
151 sendline(015); sendline(0212);
153 * Uncork the remote in case a fake XOFF has stopped data flow
155 if (type != ZFIN && type != ZACK)
156 sendline(021);
157 flushmo();
161 * Send binary array buf of length length, with ending ZDLE sequence frameend
163 static char *Zendnames[] = { "ZCRCE", "ZCRCG", "ZCRCQ", "ZCRCW"};
165 void zsdata(buf, length, frameend)
166 register char *buf;
167 int length;
168 int frameend;
170 register unsigned short crc;
172 vfile("zsdata: %d %s", length, Zendnames[(frameend-ZCRCE)&3]);
173 if (Crc32t)
174 zsda32(buf, length, frameend);
175 else {
176 crc = 0;
177 for (;--length >= 0; ++buf) {
178 zsendline(*buf); crc = updcrc((0377 & *buf), crc);
180 xsendline(ZDLE); xsendline(frameend);
181 crc = updcrc(frameend, crc);
183 crc = updcrc(0,updcrc(0,crc));
184 zsendline(crc>>8); zsendline(crc);
186 if (frameend == ZCRCW) {
187 xsendline(XON); flushmo();
191 void zsda32(buf, length, frameend)
192 register char *buf;
193 int length;
194 int frameend;
196 register int c;
197 register UNSL long crc;
199 crc = 0xFFFFFFFFL;
200 for (;--length >= 0; ++buf) {
201 c = *buf & 0377;
202 if (c & 0140)
203 xsendline(lastsent = c);
204 else
205 zsendline(c);
206 crc = UPDC32(c, crc);
208 xsendline(ZDLE); xsendline(frameend);
209 crc = UPDC32(frameend, crc);
211 crc = ~crc;
212 for (length=4; --length >= 0;) {
213 zsendline((int)crc); crc >>= 8;
218 * Receive array buf of max length with ending ZDLE sequence
219 * and CRC. Returns the ending character or error code.
220 * NB: On errors may store length+1 bytes!
222 int zrdata(buf, length)
223 register char *buf;
224 int length;
226 register int c;
227 register unsigned short crc;
228 register char *end;
229 register int d;
231 if (Rxframeind == ZBIN32)
232 return zrdat32(buf, length);
234 crc = Rxcount = 0; end = buf + length;
235 while (buf <= end) {
236 if ((c = zdlread()) & ~0377) {
237 crcfoo:
238 switch (c) {
239 case GOTCRCE:
240 case GOTCRCG:
241 case GOTCRCQ:
242 case GOTCRCW:
243 crc = updcrc((d=c)&0377, crc);
244 if ((c = zdlread()) & ~0377)
245 goto crcfoo;
246 crc = updcrc(c, crc);
247 if ((c = zdlread()) & ~0377)
248 goto crcfoo;
249 crc = updcrc(c, crc);
250 if (crc & 0xFFFF) {
251 zperr(badcrc);
252 return ERROR;
254 Rxcount = length - (end - buf);
255 vfile("zrdata: %d %s", Rxcount,
256 Zendnames[(d-GOTCRCE)&3]);
257 return d;
258 case GOTCAN:
259 zperr("Sender Canceled");
260 return ZCAN;
261 case TIMEOUT:
262 zperr("TIMEOUT");
263 return c;
264 default:
265 zperr("Bad data subpacket");
266 return c;
269 *buf++ = c;
270 crc = updcrc(c, crc);
272 zperr("Data subpacket too long");
273 return ERROR;
276 int zrdat32(buf, length)
277 register char *buf;
278 int length;
280 register int c;
281 register UNSL long crc;
282 register char *end;
283 register int d;
285 crc = 0xFFFFFFFFL; Rxcount = 0; end = buf + length;
286 while (buf <= end) {
287 if ((c = zdlread()) & ~0377) {
288 crcfoo:
289 switch (c) {
290 case GOTCRCE:
291 case GOTCRCG:
292 case GOTCRCQ:
293 case GOTCRCW:
294 d = c; c &= 0377;
295 crc = UPDC32(c, crc);
296 if ((c = zdlread()) & ~0377)
297 goto crcfoo;
298 crc = UPDC32(c, crc);
299 if ((c = zdlread()) & ~0377)
300 goto crcfoo;
301 crc = UPDC32(c, crc);
302 if ((c = zdlread()) & ~0377)
303 goto crcfoo;
304 crc = UPDC32(c, crc);
305 if ((c = zdlread()) & ~0377)
306 goto crcfoo;
307 crc = UPDC32(c, crc);
308 if (crc != 0xDEBB20E3) {
309 zperr(badcrc);
310 return ERROR;
312 Rxcount = length - (end - buf);
313 vfile("zrdat32: %d %s", Rxcount,
314 Zendnames[(d-GOTCRCE)&3]);
315 return d;
316 case GOTCAN:
317 zperr("Sender Canceled");
318 return ZCAN;
319 case TIMEOUT:
320 zperr("TIMEOUT");
321 return c;
322 default:
323 zperr("Bad data subpacket");
324 return c;
327 *buf++ = c;
328 crc = UPDC32(c, crc);
330 zperr("Data subpacket too long");
331 return ERROR;
336 * Read a ZMODEM header to hdr, either binary or hex.
337 * eflag controls local display of non zmodem characters:
338 * 0: no display
339 * 1: display printing characters only
340 * 2: display all non ZMODEM characters
341 * On success, set Zmodem to 1, set Rxpos and return type of header.
342 * Otherwise return negative on error.
343 * Return ERROR instantly if ZCRCW sequence, for fast error recovery.
345 int zgethdr(hdr, eflag)
346 char *hdr;
347 int eflag;
349 register int c, n, cancount;
351 n = Zrwindow + Baudrate; /* Max bytes before start of frame */
352 Rxframeind = Rxtype = 0;
354 startover:
355 cancount = 5;
356 again:
357 /* Return immediate ERROR if ZCRCW sequence seen */
358 switch (c = readline(Rxtimeout)) {
359 case RCDO:
360 case TIMEOUT:
361 goto fifi;
362 case CAN:
363 gotcan:
364 if (--cancount <= 0) {
365 c = ZCAN; goto fifi;
367 switch (c = readline(1)) {
368 case TIMEOUT:
369 goto again;
370 case ZCRCW:
371 c = ERROR;
372 /* **** FALL THRU TO **** */
373 case RCDO:
374 goto fifi;
375 default:
376 break;
377 case CAN:
378 if (--cancount <= 0) {
379 c = ZCAN; goto fifi;
381 goto again;
383 /* **** FALL THRU TO **** */
384 default:
385 agn2:
386 if ( --n == 0) {
387 zperr("Garbage count exceeded");
388 return(ERROR);
390 if (eflag && ((c &= 0177) & 0140))
391 bttyout(c);
392 else if (eflag > 1)
393 bttyout(c);
394 #ifdef UNIX
395 fflush(stderr);
396 #endif
397 goto startover;
398 case ZPAD|0200: /* This is what we want. */
399 Not8bit = c;
400 case ZPAD: /* This is what we want. */
401 break;
403 cancount = 5;
404 splat:
405 switch (c = noxrd7()) {
406 case ZPAD:
407 goto splat;
408 case RCDO:
409 case TIMEOUT:
410 goto fifi;
411 default:
412 goto agn2;
413 case ZDLE: /* This is what we want. */
414 break;
417 switch (c = noxrd7()) {
418 case RCDO:
419 case TIMEOUT:
420 goto fifi;
421 case ZBIN:
422 Rxframeind = ZBIN; Crc32 = FALSE;
423 c = zrbhdr(hdr);
424 break;
425 case ZBIN32:
426 Crc32 = Rxframeind = ZBIN32;
427 c = zrbhdr32(hdr);
428 break;
429 case ZHEX:
430 Rxframeind = ZHEX; Crc32 = FALSE;
431 c = zrhhdr(hdr);
432 break;
433 case CAN:
434 goto gotcan;
435 default:
436 goto agn2;
438 Rxpos = hdr[ZP3] & 0377;
439 Rxpos = (Rxpos<<8) + (hdr[ZP2] & 0377);
440 Rxpos = (Rxpos<<8) + (hdr[ZP1] & 0377);
441 Rxpos = (Rxpos<<8) + (hdr[ZP0] & 0377);
442 fifi:
443 switch (c) {
444 case GOTCAN:
445 c = ZCAN;
446 /* **** FALL THRU TO **** */
447 case ZNAK:
448 case ZCAN:
449 case ERROR:
450 case TIMEOUT:
451 case RCDO:
452 zperr("Got %s", frametypes[c+FTOFFSET]);
453 /* **** FALL THRU TO **** */
454 default:
455 if (c >= -3 && c <= FRTYPES)
456 vfile("zgethdr: %s %lx", frametypes[c+FTOFFSET], Rxpos);
457 else
458 vfile("zgethdr: %d %lx", c, Rxpos);
460 return c;
463 /* Receive a binary style header (type and position) */
464 int zrbhdr(hdr)
465 register char *hdr;
467 register int c, n;
468 register unsigned short crc;
470 if ((c = zdlread()) & ~0377)
471 return c;
472 Rxtype = c;
473 crc = updcrc(c, 0);
475 for (n=4; --n >= 0; ++hdr) {
476 if ((c = zdlread()) & ~0377)
477 return c;
478 crc = updcrc(c, crc);
479 *hdr = c;
481 if ((c = zdlread()) & ~0377)
482 return c;
483 crc = updcrc(c, crc);
484 if ((c = zdlread()) & ~0377)
485 return c;
486 crc = updcrc(c, crc);
487 if (crc & 0xFFFF) {
488 zperr(badcrc);
489 return ERROR;
491 #ifdef ZMODEM
492 Protocol = ZMODEM;
493 #endif
494 Zmodem = 1;
495 return Rxtype;
498 /* Receive a binary style header (type and position) with 32 bit FCS */
499 int zrbhdr32(hdr)
500 register char *hdr;
502 register int c, n;
503 register UNSL long crc;
505 if ((c = zdlread()) & ~0377)
506 return c;
507 Rxtype = c;
508 crc = 0xFFFFFFFFL; crc = UPDC32(c, crc);
509 #ifdef DEBUGZ
510 vfile("zrbhdr32 c=%X crc=%lX", c, crc);
511 #endif
513 for (n=4; --n >= 0; ++hdr) {
514 if ((c = zdlread()) & ~0377)
515 return c;
516 crc = UPDC32(c, crc);
517 *hdr = c;
518 #ifdef DEBUGZ
519 vfile("zrbhdr32 c=%X crc=%lX", c, crc);
520 #endif
522 for (n=4; --n >= 0;) {
523 if ((c = zdlread()) & ~0377)
524 return c;
525 crc = UPDC32(c, crc);
526 #ifdef DEBUGZ
527 vfile("zrbhdr32 c=%X crc=%lX", c, crc);
528 #endif
530 if (crc != 0xDEBB20E3) {
531 zperr(badcrc);
532 return ERROR;
534 #ifdef ZMODEM
535 Protocol = ZMODEM;
536 #endif
537 Zmodem = 1;
538 return Rxtype;
542 /* Receive a hex style header (type and position) */
543 int zrhhdr(hdr)
544 char *hdr;
546 register int c;
547 register unsigned short crc;
548 register int n;
550 if ((c = zgethex()) < 0)
551 return c;
552 Rxtype = c;
553 crc = updcrc(c, 0);
555 for (n=4; --n >= 0; ++hdr) {
556 if ((c = zgethex()) < 0)
557 return c;
558 crc = updcrc(c, crc);
559 *hdr = c;
561 if ((c = zgethex()) < 0)
562 return c;
563 crc = updcrc(c, crc);
564 if ((c = zgethex()) < 0)
565 return c;
566 crc = updcrc(c, crc);
567 if (crc & 0xFFFF) {
568 zperr(badcrc); return ERROR;
570 switch ( c = readline(1)) {
571 case 0215:
572 Not8bit = c;
573 /* **** FALL THRU TO **** */
574 case 015:
575 /* Throw away possible cr/lf */
576 switch (c = readline(1)) {
577 case 012:
578 Not8bit |= c;
581 #ifdef ZMODEM
582 Protocol = ZMODEM;
583 #endif
584 Zmodem = 1; return Rxtype;
587 /* Send a byte as two hex digits */
588 void zputhex(c)
589 register int c;
591 static char digits[] = "0123456789abcdef";
593 if (Verbose>8)
594 vfile("zputhex: %02X", c);
595 sendline(digits[(c&0xF0)>>4]);
596 sendline(digits[(c)&0xF]);
600 * Send character c with ZMODEM escape sequence encoding.
601 * Escape XON, XOFF. Escape CR following @ (Telenet net escape)
603 void zsendline(c)
604 int c;
607 /* Quick check for non control characters */
608 if (c & 0140)
609 xsendline(lastsent = c);
610 else {
611 switch (c &= 0377) {
612 case ZDLE:
613 xsendline(ZDLE);
614 xsendline (lastsent = (c ^= 0100));
615 break;
616 case 015:
617 case 0215:
618 if (!Zctlesc && (lastsent & 0177) != '@')
619 goto sendit;
620 /* **** FALL THRU TO **** */
621 case 020:
622 case 021:
623 case 023:
624 case 0220:
625 case 0221:
626 case 0223:
627 xsendline(ZDLE);
628 c ^= 0100;
629 sendit:
630 xsendline(lastsent = c);
631 break;
632 default:
633 if (Zctlesc && ! (c & 0140)) {
634 xsendline(ZDLE);
635 c ^= 0100;
637 xsendline(lastsent = c);
642 /* Decode two lower case hex digits into an 8 bit byte value */
643 int zgethex()
645 register int c;
647 c = zgeth1();
648 if (Verbose>8)
649 vfile("zgethex: %02X", c);
650 return c;
652 int zgeth1()
654 register int c, n;
656 if ((c = noxrd7()) < 0)
657 return c;
658 n = c - '0';
659 if (n > 9)
660 n -= ('a' - ':');
661 if (n & ~0xF)
662 return ERROR;
663 if ((c = noxrd7()) < 0)
664 return c;
665 c -= '0';
666 if (c > 9)
667 c -= ('a' - ':');
668 if (c & ~0xF)
669 return ERROR;
670 c += (n<<4);
671 return c;
675 * Read a byte, checking for ZMODEM escape encoding
676 * including CAN*5 which represents a quick abort
678 int zdlread()
680 register int c;
682 again:
683 /* Quick check for non control characters */
684 if ((c = readline(Rxtimeout)) & 0140)
685 return c;
686 switch (c) {
687 case ZDLE:
688 break;
689 case 023:
690 case 0223:
691 case 021:
692 case 0221:
693 goto again;
694 default:
695 if (Zctlesc && !(c & 0140)) {
696 goto again;
698 return c;
700 again2:
701 if ((c = readline(Rxtimeout)) < 0)
702 return c;
703 if (c == CAN && (c = readline(Rxtimeout)) < 0)
704 return c;
705 if (c == CAN && (c = readline(Rxtimeout)) < 0)
706 return c;
707 if (c == CAN && (c = readline(Rxtimeout)) < 0)
708 return c;
709 switch (c) {
710 case CAN:
711 return GOTCAN;
712 case ZCRCE:
713 case ZCRCG:
714 case ZCRCQ:
715 case ZCRCW:
716 return (c | GOTOR);
717 case ZRUB0:
718 return 0177;
719 case ZRUB1:
720 return 0377;
721 case 023:
722 case 0223:
723 case 021:
724 case 0221:
725 goto again2;
726 default:
727 if (Zctlesc && ! (c & 0140)) {
728 goto again2;
730 if ((c & 0140) == 0100)
731 return (c ^ 0100);
732 break;
734 if (Verbose>1)
735 zperr("Bad escape sequence %x", c);
736 return ERROR;
740 * Read a character from the modem line with timeout.
741 * Eat parity, XON and XOFF characters.
743 int noxrd7()
745 register int c;
747 for (;;) {
748 if ((c = readline(Rxtimeout)) < 0)
749 return c;
750 switch (c &= 0177) {
751 case XON:
752 case XOFF:
753 continue;
754 default:
755 if (Zctlesc && !(c & 0140))
756 continue;
757 case '\r':
758 case '\n':
759 case ZDLE:
760 return c;
765 /* Store long integer pos in Txhdr */
766 void stohdr(pos)
767 long pos;
769 Txhdr[ZP0] = pos;
770 Txhdr[ZP1] = pos>>8;
771 Txhdr[ZP2] = pos>>16;
772 Txhdr[ZP3] = pos>>24;
775 /* Recover a long integer from a header */
776 long
777 rclhdr(hdr)
778 register char *hdr;
780 register long l;
782 l = (hdr[ZP3] & 0377);
783 l = (l << 8) | (hdr[ZP2] & 0377);
784 l = (l << 8) | (hdr[ZP1] & 0377);
785 l = (l << 8) | (hdr[ZP0] & 0377);
786 return l;
789 /* End of zm.c */