source: trunk/minix/commands/zmodem/zm.c@ 9

Last change on this file since 9 was 9, checked in by Mattia Monga, 13 years ago

Minix 3.1.2a

File size: 14.8 KB
Line 
1/*
2 * Z M . C
3 * ZMODEM protocol primitives
4 * 05-09-88 Chuck Forsberg Omen Technology Inc
5 *
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
14 */
15
16#ifndef CANFDX
17#include "zmodem.h"
18#endif
19int Rxtimeout = 100; /* Tenths of seconds to wait for something */
20
21#ifndef UNSL
22#define UNSL
23#endif
24
25
26/* Globals used by ZMODEM functions */
27int Rxframeind; /* ZBIN ZBIN32, or ZHEX type of frame received */
28int Rxtype; /* Type of header received */
29int Rxcount; /* Count of data bytes received */
30char Rxhdr[4]; /* Received header */
31char Txhdr[4]; /* Transmitted header */
32long Rxpos; /* Received file position */
33long Txpos; /* Transmitted file position */
34int Txfcs32; /* TURE means send binary frames with 32 bit FCS */
35int Crc32t; /* Display flag indicating 32 bit CRC being sent */
36int Crc32; /* Display flag indicating 32 bit CRC being received */
37int Znulls; /* Number of nulls to send at beginning of ZDATA hdr */
38char Attn[ZATTNLEN+1]; /* Attention string rx sends to tx on err */
39
40static lastsent; /* Last char we sent */
41static Not8bit; /* Seven bits seen on header */
42
43static 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 */
71};
72
73static char badcrc[] = "Bad CRC";
74
75/* Send ZMODEM binary header hdr of type type */
76void zsbhdr(type, hdr)
77int type;
78register char *hdr;
79{
80 register int n;
81 register unsigned short crc;
82
83 vfile("zsbhdr: %s %lx", frametypes[type+FTOFFSET], rclhdr(hdr));
84 if (type == ZDATA)
85 for (n = Znulls; --n >=0; )
86 xsendline(0);
87
88 xsendline(ZPAD); xsendline(ZDLE);
89
90 if (Crc32t=Txfcs32)
91 zsbh32(hdr, type);
92 else {
93 xsendline(ZBIN); zsendline(type); crc = updcrc(type, 0);
94
95 for (n=4; --n >= 0; ++hdr) {
96 zsendline(*hdr);
97 crc = updcrc((0377& *hdr), crc);
98 }
99 crc = updcrc(0,updcrc(0,crc));
100 zsendline(crc>>8);
101 zsendline(crc);
102 }
103 if (type != ZDATA)
104 flushmo();
105}
106
107
108/* Send ZMODEM binary header hdr of type type */
109void zsbh32(hdr, type)
110register char *hdr;
111int type;
112{
113 register int n;
114 register UNSL long crc;
115
116 xsendline(ZBIN32); zsendline(type);
117 crc = 0xFFFFFFFFL; crc = UPDC32(type, crc);
118
119 for (n=4; --n >= 0; ++hdr) {
120 crc = UPDC32((0377 & *hdr), crc);
121 zsendline(*hdr);
122 }
123 crc = ~crc;
124 for (n=4; --n >= 0;) {
125 zsendline((int)crc);
126 crc >>= 8;
127 }
128}
129
130/* Send ZMODEM HEX header hdr of type type */
131void zshhdr(type, hdr)
132int type;
133register char *hdr;
134{
135 register int n;
136 register unsigned short crc;
137
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;
142
143 crc = updcrc(type, 0);
144 for (n=4; --n >= 0; ++hdr) {
145 zputhex(*hdr); crc = updcrc((0377 & *hdr), crc);
146 }
147 crc = updcrc(0,updcrc(0,crc));
148 zputhex(crc>>8); zputhex(crc);
149
150 /* Make it printable on remote machine */
151 sendline(015); sendline(0212);
152 /*
153 * Uncork the remote in case a fake XOFF has stopped data flow
154 */
155 if (type != ZFIN && type != ZACK)
156 sendline(021);
157 flushmo();
158}
159
160/*
161 * Send binary array buf of length length, with ending ZDLE sequence frameend
162 */
163static char *Zendnames[] = { "ZCRCE", "ZCRCG", "ZCRCQ", "ZCRCW"};
164
165void zsdata(buf, length, frameend)
166register char *buf;
167int length;
168int frameend;
169{
170 register unsigned short crc;
171
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);
179 }
180 xsendline(ZDLE); xsendline(frameend);
181 crc = updcrc(frameend, crc);
182
183 crc = updcrc(0,updcrc(0,crc));
184 zsendline(crc>>8); zsendline(crc);
185 }
186 if (frameend == ZCRCW) {
187 xsendline(XON); flushmo();
188 }
189}
190
191void zsda32(buf, length, frameend)
192register char *buf;
193int length;
194int frameend;
195{
196 register int c;
197 register UNSL long crc;
198
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);
207 }
208 xsendline(ZDLE); xsendline(frameend);
209 crc = UPDC32(frameend, crc);
210
211 crc = ~crc;
212 for (length=4; --length >= 0;) {
213 zsendline((int)crc); crc >>= 8;
214 }
215}
216
217/*
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!
221 */
222int zrdata(buf, length)
223register char *buf;
224int length;
225{
226 register int c;
227 register unsigned short crc;
228 register char *end;
229 register int d;
230
231 if (Rxframeind == ZBIN32)
232 return zrdat32(buf, length);
233
234 crc = Rxcount = 0; end = buf + length;
235 while (buf <= end) {
236 if ((c = zdlread()) & ~0377) {
237crcfoo:
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;
253 }
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;
267 }
268 }
269 *buf++ = c;
270 crc = updcrc(c, crc);
271 }
272 zperr("Data subpacket too long");
273 return ERROR;
274}
275
276int zrdat32(buf, length)
277register char *buf;
278int length;
279{
280 register int c;
281 register UNSL long crc;
282 register char *end;
283 register int d;
284
285 crc = 0xFFFFFFFFL; Rxcount = 0; end = buf + length;
286 while (buf <= end) {
287 if ((c = zdlread()) & ~0377) {
288crcfoo:
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;
311 }
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;
325 }
326 }
327 *buf++ = c;
328 crc = UPDC32(c, crc);
329 }
330 zperr("Data subpacket too long");
331 return ERROR;
332}
333
334
335/*
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.
344 */
345int zgethdr(hdr, eflag)
346char *hdr;
347int eflag;
348{
349 register int c, n, cancount;
350
351 n = Zrwindow + Baudrate; /* Max bytes before start of frame */
352 Rxframeind = Rxtype = 0;
353
354startover:
355 cancount = 5;
356again:
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:
363gotcan:
364 if (--cancount <= 0) {
365 c = ZCAN; goto fifi;
366 }
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;
380 }
381 goto again;
382 }
383 /* **** FALL THRU TO **** */
384 default:
385agn2:
386 if ( --n == 0) {
387 zperr("Garbage count exceeded");
388 return(ERROR);
389 }
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;
402 }
403 cancount = 5;
404splat:
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;
415 }
416
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;
437 }
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);
442fifi:
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);
459 }
460 return c;
461}
462
463/* Receive a binary style header (type and position) */
464int zrbhdr(hdr)
465register char *hdr;
466{
467 register int c, n;
468 register unsigned short crc;
469
470 if ((c = zdlread()) & ~0377)
471 return c;
472 Rxtype = c;
473 crc = updcrc(c, 0);
474
475 for (n=4; --n >= 0; ++hdr) {
476 if ((c = zdlread()) & ~0377)
477 return c;
478 crc = updcrc(c, crc);
479 *hdr = c;
480 }
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;
490 }
491#ifdef ZMODEM
492 Protocol = ZMODEM;
493#endif
494 Zmodem = 1;
495 return Rxtype;
496}
497
498/* Receive a binary style header (type and position) with 32 bit FCS */
499int zrbhdr32(hdr)
500register char *hdr;
501{
502 register int c, n;
503 register UNSL long crc;
504
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
512
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
521 }
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
529 }
530 if (crc != 0xDEBB20E3) {
531 zperr(badcrc);
532 return ERROR;
533 }
534#ifdef ZMODEM
535 Protocol = ZMODEM;
536#endif
537 Zmodem = 1;
538 return Rxtype;
539}
540
541
542/* Receive a hex style header (type and position) */
543int zrhhdr(hdr)
544char *hdr;
545{
546 register int c;
547 register unsigned short crc;
548 register int n;
549
550 if ((c = zgethex()) < 0)
551 return c;
552 Rxtype = c;
553 crc = updcrc(c, 0);
554
555 for (n=4; --n >= 0; ++hdr) {
556 if ((c = zgethex()) < 0)
557 return c;
558 crc = updcrc(c, crc);
559 *hdr = c;
560 }
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;
569 }
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;
579 }
580 }
581#ifdef ZMODEM
582 Protocol = ZMODEM;
583#endif
584 Zmodem = 1; return Rxtype;
585}
586
587/* Send a byte as two hex digits */
588void zputhex(c)
589register int c;
590{
591 static char digits[] = "0123456789abcdef";
592
593 if (Verbose>8)
594 vfile("zputhex: %02X", c);
595 sendline(digits[(c&0xF0)>>4]);
596 sendline(digits[(c)&0xF]);
597}
598
599/*
600 * Send character c with ZMODEM escape sequence encoding.
601 * Escape XON, XOFF. Escape CR following @ (Telenet net escape)
602 */
603void zsendline(c)
604int c;
605{
606
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;
636 }
637 xsendline(lastsent = c);
638 }
639 }
640}
641
642/* Decode two lower case hex digits into an 8 bit byte value */
643int zgethex()
644{
645 register int c;
646
647 c = zgeth1();
648 if (Verbose>8)
649 vfile("zgethex: %02X", c);
650 return c;
651}
652int zgeth1()
653{
654 register int c, n;
655
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;
672}
673
674/*
675 * Read a byte, checking for ZMODEM escape encoding
676 * including CAN*5 which represents a quick abort
677 */
678int zdlread()
679{
680 register int c;
681
682again:
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;
697 }
698 return c;
699 }
700again2:
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;
729 }
730 if ((c & 0140) == 0100)
731 return (c ^ 0100);
732 break;
733 }
734 if (Verbose>1)
735 zperr("Bad escape sequence %x", c);
736 return ERROR;
737}
738
739/*
740 * Read a character from the modem line with timeout.
741 * Eat parity, XON and XOFF characters.
742 */
743int noxrd7()
744{
745 register int c;
746
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;
761 }
762 }
763}
764
765/* Store long integer pos in Txhdr */
766void stohdr(pos)
767long pos;
768{
769 Txhdr[ZP0] = pos;
770 Txhdr[ZP1] = pos>>8;
771 Txhdr[ZP2] = pos>>16;
772 Txhdr[ZP3] = pos>>24;
773}
774
775/* Recover a long integer from a header */
776long
777rclhdr(hdr)
778register char *hdr;
779{
780 register long l;
781
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;
787}
788
789/* End of zm.c */
Note: See TracBrowser for help on using the repository browser.