1 #define VERSION "sz 2.12 05-29-88"
2 #define PUBDIR "/usr/spool/uucppublic"
4 /*% cc -compat -M2 -Ox -K -i -DTXBSIZE=16384 -DNFGVMIN -DREADCHECK sz.c -lx -o sz; size sz
6 Following is used for testing, might not be reasonable for production
7 <-xtx-*> cc -Osal -DTXBSIZE=32768 -DSV sz.c -lx -o $B/sz; size $B/sz
9 ****************************************************************************
11 * sz.c By Chuck Forsberg, Omen Technology INC
13 ****************************************************************************
15 * Typical Unix/Xenix/Clone compiles:
17 * cc -O sz.c -o sz USG (SYS III/V) Unix
18 * cc -O -DSV sz.c -o sz Sys V Release 2 with non-blocking input
19 * Define to allow reverse channel checking
20 * cc -O -DV7 sz.c -o sz Unix Version 7, 2.8 - 4.3 BSD
22 * cc -O -K -i -DNFGVMIN -DREADCHECK sz.c -lx -o sz Classic Xenix
24 * ln sz sb **** All versions ****
25 * ln sz sx **** All versions ****
27 ****************************************************************************
29 * Typical VMS compile and install sequence:
31 * define LNK$LIBRARY SYS$LIBRARY:VAXCRTL.OLB
35 * sz :== $disk$user2:[username.subdir]sz.exe
37 * If you feel adventureous, remove the #define BADSYNC line
38 * immediately following the #ifdef vax11c line! Some VMS
39 * systems know how to fseek, some don't.
41 ****************************************************************************
44 * A program for Unix to send files and commands to computers running
45 * Professional-YAM, PowerCom, YAM, IMP, or programs supporting Y/XMODEM.
47 * Sz uses buffered I/O to greatly reduce CPU time compared to UMODEM.
49 * USG UNIX (3.0) ioctl conventions courtesy Jeff Martin
51 * 2.1x hacks to avoid VMS fseek() bogosity, allow input from pipe
52 * -DBADSEEK -DTXBSIZE=32768
53 * 2.x has mods for VMS flavor
55 * 1.34 implements tx backchannel garbage count and ZCRCW after ZRPOS
56 * in accordance with the 7-31-87 ZMODEM Protocol Description
60 #include <sys/types.h>
64 #define TXBSIZE 32768 /* Must be power of two, < MAXINT */
67 #define LOGFILE "szlog.tmp"
73 #define SS_NORMAL SS$_NORMAL
74 #define xsendline(c) sendline(c)
81 #define LOGFILE "/tmp/szlog"
83 #define sendline(c) putchar((c) & 0377)
84 #define xsendline(c) putchar(c)
106 /* Ward Christensen / CP/M parameters - Don't change these! */
108 #define CAN ('X'&037)
109 #define XOFF ('s'&037)
110 #define XON ('q'&037)
117 #define WANTCRC 0103 /* send C not NAK to get crc not checksum */
118 #define WANTG 0107 /* Send G not NAK to get nonstop batch xmsn */
125 int Zmodem
=0; /* ZMODEM protocol requested by receiver */
126 unsigned Baudrate
=2400; /* Default, should be set by first mode() call */
127 unsigned Txwindow
; /* Control the size of the transmitted window */
128 unsigned Txwspac
; /* Spacing between zcrcq requests */
129 unsigned Txwcnt
; /* Counter used to space ack requests */
130 long Lrxpos
; /* Receiver's last reported offset */
134 #include "vrzsz.c" /* most of the system dependent stuff here */
136 #include "rbsb.c" /* most of the system dependent stuff here */
144 * Attention string to be executed by receiver to interrupt streaming data
145 * when an error is detected. A pause (0336) may be needed before the
146 * ^C (03) or after it.
149 char Myattn
[] = { 0 };
152 char Myattn
[] = { 03, 0336, 0 };
154 char Myattn
[] = { 0 };
161 int Canseek
= 0; /* 1: Can seek 0: only rewind -1: neither (pipe) */
163 #define TXBSIZE 16384 /* Must be power of two, < MAXINT */
166 int Canseek
= 1; /* 1: Can seek 0: only rewind -1: neither (pipe) */
170 #define TXBMASK (TXBSIZE-1)
171 char Txb
[TXBSIZE
]; /* Circular buffer for file reads */
172 char *txbuf
= Txb
; /* Pointer to current file segment */
176 long vpos
= 0; /* Number of bytes read from file */
181 int Modem2
=0; /* XMODEM Protocol - don't send pathnames */
182 int Restricted
=0; /* restricted; no /.. or ../ in filenames */
183 int Quiet
=0; /* overrides logic that would otherwise set verbose */
184 int Ascii
=0; /* Add CR's for brain damaged programs */
185 int Fullname
=0; /* transmit full pathname */
186 int Unlinkafter
=0; /* Unlink file after it is sent */
187 int Dottoslash
=0; /* Change foo.bar.baz to foo/bar/baz */
189 int errcnt
=0; /* number of files unreadable */
190 int blklen
=128; /* length of transmitted records */
191 int Optiong
; /* Let it rip no wait for sector ACK's */
192 int Eofseen
; /* EOF seen on input set by zfilbuf */
193 int BEofseen
; /* EOF seen on input set by fooseek */
194 int Totsecs
; /* total number of sectors this file */
195 int Filcnt
=0; /* count of number of files opened */
197 unsigned Rxbuflen
= 16384; /* Receiver's max buffer length */
198 int Tframlen
= 0; /* Override for tx frame length */
199 int blkopt
=0; /* Override value for zmodem blklen */
202 int Wantfcs32
= TRUE
; /* want to send 32 bit FCS */
203 char Lzconv
; /* Local ZMODEM file conversion request */
204 char Lzmanag
; /* Local ZMODEM file management request */
207 char zconv
; /* ZMODEM file conversion request */
208 char zmanag
; /* ZMODEM file management request */
209 char ztrans
; /* ZMODEM file transport request */
210 int Command
; /* Send a command, then exit. */
211 char *Cmdstr
; /* Pointer to the command string */
213 int Cmdack1
; /* Rx ACKs command, then do it */
215 int Test
; /* 1= Force receiver to send Attn, etc with qbf. */
216 /* 2= Character transparency test */
217 char *qbf
="The quick brown fox jumped over the lazy dog's back 1234567890\r\n";
218 long Lastsync
; /* Last offset to which we got a ZRPOS */
219 int Beenhereb4
; /* How many times we've been ZRPOS'd same place */
221 jmp_buf tohere
; /* For the interrupt on RX timeout */
222 jmp_buf intrjmp
; /* For the interrupt on RX CAN */
224 void onintr(int sig
);
225 int main(int argc
, char *argv
[]);
226 int wcsend(int argc
, char *argp
[]);
227 int wcs(char *oname
);
228 int wctxpn(char *name
);
230 int wctx(long flen
);
231 int wcputsec(char *buf
, int sectnum
, int cseclen
);
232 int filbuf(char *buf
, int count
);
234 int fooseek(FILE *fptr
, long pos
, int whence
);
236 int readline(int timeout
);
238 void purgeline(void);
241 char *substr(char *s
, char *t
);
243 int getzrxinit(void);
244 int sendzsinit(void);
245 int zsendfile(char *buf
, int blen
);
246 int zsendfdata(void);
247 int getinsync(int flag
);
249 void bttyout(int c
);
250 int zsendcmd(char *buf
, int blen
);
251 void chkinvok(char *s
);
252 void countem(int argc
, char **argv
);
253 void chartest(int m
);
255 /* called by signal interrupt or terminate to clean things up */
258 canit(); fflush(stdout
); mode(0);
259 fprintf(stderr
, "sz: caught signal %d; exiting\n", n
);
263 fprintf(stderr
, "mode(2) in rbsb.c not implemented!!\n");
267 /* Called when ZMODEM gets an interrupt (^X) */
270 signal(SIGINT
, SIG_IGN
);
271 longjmp(intrjmp
, -1);
274 int Zctlesc
; /* Encode control characters */
275 int Nozmodem
= 0; /* If invoked as "sb" */
276 char *Progname
= "sz";
277 int Zrwindow
= 1400; /* RX window size (controls garbage count) */
281 int main(int argc
, char *argv
[])
287 static char xXbuf
[BUFSIZ
];
289 if ((cp
= getenv("ZNULLS")) && *cp
)
291 if ((cp
=getenv("SHELL")) && (substr(cp
, "rsh") || substr(cp
, "rksh")))
300 setbuf(stdout
, xXbuf
);
303 if (*cp
++ == '-' && *cp
) {
307 *cp
= toupper(*cp
); continue;
309 Lzmanag
= ZMAPND
; break;
312 Twostop
= TRUE
; break;
318 Lzconv
= ZCBIN
; break;
323 Cmdtries
= atoi(*++argv
);
327 /* **** FALL THROUGH TO **** */
337 /* **** FALL THROUGH TO **** */
339 Fullname
=TRUE
; break;
348 blkopt
= atoi(*++argv
);
349 if (blkopt
<24 || blkopt
>1024)
356 Tframlen
= atoi(*++argv
);
357 if (Tframlen
<32 || Tframlen
>1024)
361 Lzmanag
= ZMNEWL
; break;
363 Lzmanag
= ZMNEW
; break;
365 Wantfcs32
= FALSE
; break;
367 Lzmanag
= ZMPROT
; break;
371 Quiet
=TRUE
; Verbose
=0; break;
376 Rxtimeout
= atoi(*++argv
);
377 if (Rxtimeout
<10 || Rxtimeout
>1000)
382 chartest(1); chartest(2);
388 ++Unlinkafter
; break;
396 Txwindow
= atoi(*++argv
);
399 Txwindow
= (Txwindow
/64) * 64;
400 Txwspac
= Txwindow
/4;
402 || (!blkopt
&& Txwspac
< 1024))
409 /* **** FALLL THROUGH TO **** */
411 Lzmanag
= ZMCLOB
; break;
417 else if ( !npats
&& argc
>0) {
422 if ( !strcmp(*patts
, "-"))
428 if (npats
< 1 && !Command
&& !Test
)
431 if (freopen(LOGFILE
, "a", stderr
)==NULL
) {
432 printf("Can't open log file %s\n",LOGFILE
);
435 setbuf(stderr
, (char *)NULL
);
437 if (Fromcu
&& !Quiet
) {
441 vfile("%s %s for %s\n", Progname
, VERSION
, OS
);
445 if (signal(SIGINT
, bibi
) == SIG_IGN
) {
446 signal(SIGINT
, SIG_IGN
); signal(SIGKILL
, SIG_IGN
);
448 signal(SIGINT
, bibi
); signal(SIGKILL
, bibi
);
451 signal(SIGQUIT
, SIG_IGN
);
452 signal(SIGTERM
, bibi
);
456 printf("rz\r"); fflush(stdout
);
458 countem(npats
, patts
);
462 Txhdr
[ZF0
] = ZCOMMAND
;
463 zshhdr(ZRQINIT
, Txhdr
);
470 Exitcode
=0200; canit();
472 else if (zsendcmd(Cmdstr
, 1+strlen(Cmdstr
))) {
473 Exitcode
=0200; canit();
475 } else if (wcsend(npats
, patts
)==ERROR
) {
481 dm
= ((errcnt
!= 0) | Exitcode
);
490 int wcsend(int argc
, char *argp
[])
497 for (n
=0; n
<argc
; ++n
) {
499 if (wcs(argp
[n
])==ERROR
)
503 if (Filcnt
==0) { /* bitch if we couldn't open ANY files */
506 Cmdstr
= "echo \"sz: Can't open any requested files\"";
508 Exitcode
=0200; canit();
512 else if (zsendcmd(Cmdstr
, 1+strlen(Cmdstr
))) {
513 Exitcode
=0200; canit();
515 Exitcode
= 1; return OK
;
518 fprintf(stderr
,"\r\nCan't open any requested files.\r\n");
538 /* restrict pathnames to current tree or uucppublic */
539 if ( substr(name
, "../")
540 || (name
[0]== '/' && strncmp(name
, PUBDIR
, strlen(PUBDIR
))) ) {
542 fprintf(stderr
,"\r\nsz:\tSecurity Violation\r\n");
547 if ( !strcmp(oname
, "-")) {
548 if ((p
= getenv("ONAME")) && *p
)
551 sprintf(name
, "s%d.sz", getpid());
554 else if ((in
=fopen(oname
, "r"))==NULL
) {
556 return OK
; /* pass over it, there may be others */
558 BEofseen
= Eofseen
= 0; vpos
= 0;
559 /* Check for directory or block special files */
560 fstat(fileno(in
), &f
);
561 c
= f
.st_mode
& S_IFMT
;
562 if (c
== S_IFDIR
|| c
== S_IFBLK
) {
568 switch (wctxpn(name
)) {
574 if (!Zmodem
&& wctx(f
.st_size
)==ERROR
)
584 * generate and transmit pathname block consisting of
585 * pathname (null terminated),
586 * file length, mode time and file mode in octal
587 * as provided by the Unix fstat call.
588 * N.B.: modifies the passed name, may extend it!
590 int wctxpn(char *name
)
592 register char *p
, *q
;
597 if ((in
!=stdin
) && *name
&& fstat(fileno(in
), &f
)!= -1) {
598 fprintf(stderr
, "Sending %s, %lld blocks: ",
601 fprintf(stderr
, "Give your local XMODEM receive command now.\r\n");
604 zperr("Awaiting pathname nak for %s", *name
?name
:"<END>");
610 if (Dottoslash
) { /* change . to . */
611 for (p
=name
; *p
; ++p
) {
617 if (q
&& strlen(++q
) > 8) { /* If name>8 chars */
618 q
+= 8; /* make it .ext */
619 strcpy(name2
, q
); /* save excess of name */
621 strcpy(++q
, name2
); /* add it back */
625 for (p
=name
, q
=txbuf
; *p
; )
626 if ((*q
++ = *p
++) == '/' && !Fullname
)
630 while (q
< (txbuf
+ 1024))
632 if (!Ascii
&& (in
!=stdin
) && *name
&& fstat(fileno(in
), &f
)!= -1)
633 sprintf(p
, "%llu %llo %o 0 %d %ld", f
.st_size
, f
.st_mtime
,
634 f
.st_mode
, Filesleft
, Totalleft
);
635 Totalleft
-= f
.st_size
;
636 if (--Filesleft
<= 0)
641 /* force 1k blocks if name won't fit in 128 byte block */
644 else { /* A little goodie for IMP/KMD */
645 txbuf
[127] = (f
.st_size
+ 127) >>7;
646 txbuf
[126] = (f
.st_size
+ 127) >>15;
649 return zsendfile(txbuf
, 1+strlen(p
)+(p
-txbuf
));
650 if (wcputsec(txbuf
, 0, 128)==ERROR
)
657 register int firstch
;
661 switch (firstch
= readline(800)) {
665 Ascii
= 0; /* Receiver does the conversion */
668 zperr("Timeout on pathname");
672 mode(2); /* Set cbreak, XON/XOFF, etc. */
681 if ((firstch
= readline(20)) == CAN
&& Lastrx
== CAN
)
693 register int thisblklen
;
694 register int sectnum
, attempts
, firstch
;
697 charssent
= 0; firstsec
=TRUE
; thisblklen
= blklen
;
698 vfile("wctx:file length=%ld", flen
);
700 while ((firstch
=readline(Rxtimeout
))!=NAK
&& firstch
!= WANTCRC
701 && firstch
!= WANTG
&& firstch
!=TIMEOUT
&& firstch
!=CAN
)
704 zperr("Receiver CANcelled");
707 if (firstch
==WANTCRC
)
713 if (flen
<= (charssent
+ 896L))
715 if ( !filbuf(txbuf
, thisblklen
))
717 if (wcputsec(txbuf
, ++sectnum
, thisblklen
)==ERROR
)
719 charssent
+= thisblklen
;
729 while ((firstch
= readline(Rxtimeout
)) != ACK
&&
730 attempts
< RETRYMAX
);
731 if (attempts
== RETRYMAX
) {
732 zperr("No ACK on EOT");
739 * @param cseclen :data length of this sector to send
741 int wcputsec(char *buf
, int sectnum
, int cseclen
)
743 register int checksum
, wcj
;
749 firstch
=0; /* part of logic to detect CAN CAN */
752 fprintf(stderr
, "Sector %3d %2dk\n", Totsecs
, Totsecs
/8 );
754 fprintf(stderr
, "\rSector %3d %2dk ", Totsecs
, Totsecs
/8 );
755 for (attempts
=0; attempts
<= RETRYMAX
; attempts
++) {
757 sendline(cseclen
==1024?STX
:SOH
);
759 sendline(-sectnum
-1);
761 for (wcj
=cseclen
,cp
=buf
; --wcj
>=0; ) {
763 oldcrc
=updcrc((0377& *cp
), oldcrc
);
767 oldcrc
=updcrc(0,updcrc(0,oldcrc
));
768 sendline((int)oldcrc
>>8);
769 sendline((int)oldcrc
);
775 firstsec
= FALSE
; return OK
;
777 firstch
= readline(Rxtimeout
);
783 zperr("Cancelled"); return ERROR
;
787 zperr("Timeout on sector ACK"); continue;
792 zperr("NAK on sector"); continue;
795 Totsecs
+= (cseclen
>>7);
798 zperr("Got burst for sector ACK"); break;
800 zperr("Got %02x for sector ACK", firstch
); break;
804 if ((firstch
= readline(Rxtimeout
)) == TIMEOUT
)
806 if (firstch
== NAK
|| firstch
== WANTCRC
)
808 if (firstch
== CAN
&& Lastrx
== CAN
)
812 zperr("Retry Count Exceeded");
816 /* fill buf with count chars padding with ^Z for CPM */
817 int filbuf(char *buf
, int count
)
822 m
= read(fileno(in
), buf
, count
);
831 *buf
++ = 012; --m
; Lfseen
= 0;
833 while ((c
=getc(in
))!=EOF
) {
837 Lfseen
= TRUE
; break;
852 /* Fill buffer with blklen chars */
858 /* We assume request is within buffer, or just beyond */
859 txbuf
= Txb
+ (bytcnt
& TXBMASK
);
860 if (vpos
<= bytcnt
) {
861 n
= fread(txbuf
, 1, blklen
, in
);
867 if (vpos
>= (bytcnt
+blklen
))
869 /* May be a short block if crash recovery etc. */
871 return (vpos
- bytcnt
);
873 n
= fread(txbuf
, 1, blklen
, in
);
881 int fooseek(FILE *fptr
, long pos
, int whence
)
885 vfile("fooseek: pos =%lu vpos=%lu Canseek=%d", pos
, vpos
, Canseek
);
886 /* Seek offset < current buffer */
887 if (pos
< (vpos
-TXBSIZE
+1024)) {
890 vpos
= pos
& ~TXBMASK
;
893 if (fseek(fptr
, vpos
, 0))
896 else if (Canseek
== 0)
897 if (fseek(fptr
, vpos
= 0L, 0))
901 while (vpos
<= pos
) {
902 n
= fread(Txb
, 1, TXBSIZE
, fptr
);
904 vfile("n=%d vpos=%ld", n
, vpos
);
910 vfile("vpos=%ld", vpos
);
913 /* Seek offset > current buffer (crash recovery, etc.) */
916 if (fseek(fptr
, vpos
= (pos
& ~TXBMASK
), 0))
918 while (vpos
<= pos
) {
919 txbuf
= Txb
+ (vpos
& TXBMASK
);
920 m
= TXBSIZE
- (vpos
& TXBMASK
);
921 n
= fread(txbuf
, 1, m
, fptr
);
923 vfile("bo=%d n=%d vpos=%ld", txbuf
-Txb
, n
, vpos
);
931 /* Seek offset is within current buffer */
932 vfile("vpos=%ld", vpos
);
935 #define fseek fooseek
938 void vfile(const char *string
, ...)
942 va_start(args
, string
);
943 vfprintf(stderr
, string
, args
);
945 fprintf(stderr
, "\n");
958 * readline(timeout) reads character(s) from file descriptor 0
959 * timeout is in tenths of seconds
961 int readline(int timeout
)
967 if (setjmp(tohere
)) {
975 fprintf(stderr
, "Timeout=%d Calling alarm(%d) ", timeout
, c
);
977 signal(SIGALRM
, alrm
); alarm(c
);
978 c
=read(iofd
, byt
, 1);
981 fprintf(stderr
, "ret %x\n", byt
[0]);
984 return (byt
[0]&0377);
996 ioctl(iofd
, TCFLSH
, 0);
1003 /* send cancel string to get the other end to shut up */
1006 static char canistr
[] = {
1007 24,24,24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8,0
1011 raw_wbuf(strlen(canistr
), canistr
);
1014 printf("%s", canistr
);
1024 void zperr(char *s
, char *p
, char *u
)
1028 fprintf(stderr
, "\nRetry %d: ", errors
);
1029 fprintf(stderr
, s
, p
, u
);
1030 fprintf(stderr
, "\n");
1034 * substr(string, token) searches for token in string s
1035 * returns pointer to token within string if found, NULL otherwise
1038 substr(char *s
, char *t
)
1040 register char *ss
,*tt
;
1041 /* search for first char of token */
1044 /* compare token with substring */
1045 for (ss
=s
,tt
=t
; ;) {
1051 return (char *)NULL
;
1056 " Send file(s) with ZMODEM Protocol",
1057 "Usage: sz [-2+abdefkLlNnquvwYy] [-] file ...",
1058 " sz [-2Ceqv] -c COMMAND",
1059 " \\ Force next option letter to upper case",
1061 "Send file(s) with ZMODEM/YMODEM/XMODEM Protocol",
1062 " (Y) = Option applies to YMODEM only",
1063 " (Z) = Option applies to ZMODEM only",
1064 "Usage: sz [-2+abdefkLlNnquvwYy] [-] file ...",
1065 " sz [-2Ceqv] -c COMMAND",
1066 " sb [-2adfkquv] [-] file ...",
1067 " sx [-2akquv] [-] file",
1070 " 2 Use 2 stop bits",
1072 " + Append to existing destination file (Z)",
1073 " a (ASCII) change NL to CR/LF",
1074 " b Binary file transfer override",
1075 " c send COMMAND (Z)",
1077 " d Change '.' to '/' in pathnames (Y/Z)",
1079 " e Escape all control characters (Z)",
1080 " f send Full pathname (Y/Z)",
1081 " i send COMMAND, ack Immediately (Z)",
1082 " k Send 1024 byte packets (Y)",
1083 " L N Limit subpacket length to N bytes (Z)",
1084 " l N Limit frame length to N bytes (l>=L) (Z)",
1085 " n send file if source newer (Z)",
1086 " N send file if source newer or longer (Z)",
1087 " o Use 16 bit CRC instead of 32 bit CRC (Z)",
1088 " p Protect existing destination file (Z)",
1089 " r Resume/Recover interrupted file transfer (Z)",
1090 " q Quiet (no progress reports)",
1092 " u Unlink file after transmission",
1094 " v Verbose - provide debugging information",
1095 " w N Window is N bytes (Z)",
1096 " Y Yes, overwrite existing file, skip if not present at rx (Z)",
1097 " y Yes, overwrite existing file (Z)",
1098 "- as pathname sends standard input as sPID.sz or environment ONAME",
1106 for (pp
=babble
; **pp
; ++pp
)
1107 fprintf(stderr
, "%s\n", *pp
);
1108 fprintf(stderr
, "%s for %s by Chuck Forsberg, Omen Technology INC\n",
1110 fprintf(stderr
, "\t\t\042The High Reliability Software\042\n");
1116 * Get the receiver's init parameters
1123 for (n
=10; --n
>=0; ) {
1125 switch (zgethdr(Rxhdr
, 1)) {
1126 case ZCHALLENGE
: /* Echo receiver's challenge numbr */
1128 zshhdr(ZACK
, Txhdr
);
1130 case ZCOMMAND
: /* They didn't see out ZRQINIT */
1132 zshhdr(ZRQINIT
, Txhdr
);
1135 Rxflags
= 0377 & Rxhdr
[ZF0
];
1136 Txfcs32
= (Wantfcs32
&& (Rxflags
& CANFC32
));
1137 Zctlesc
|= Rxflags
& TESCCTL
;
1138 Rxbuflen
= (0377 & Rxhdr
[ZP0
])+((0377 & Rxhdr
[ZP1
])<<8);
1139 if ( !(Rxflags
& CANFDX
))
1141 vfile("Rxbuflen=%d Tframlen=%d", Rxbuflen
, Tframlen
);
1143 signal(SIGINT
, SIG_IGN
);
1145 mode(2); /* Set cbreak, XON/XOFF, etc. */
1149 /* Use 1024 byte frames if no sample/interrupt */
1150 if (Rxbuflen
< 32 || Rxbuflen
> 1024) {
1152 vfile("Rxbuflen=%d", Rxbuflen
);
1156 /* Override to force shorter frame length */
1157 if (Rxbuflen
&& (Rxbuflen
>Tframlen
) && (Tframlen
>=32))
1158 Rxbuflen
= Tframlen
;
1159 if ( !Rxbuflen
&& (Tframlen
>=32) && (Tframlen
<=1024))
1160 Rxbuflen
= Tframlen
;
1161 vfile("Rxbuflen=%d", Rxbuflen
);
1164 /* If using a pipe for testing set lower buf len */
1166 if ((f
.st_mode
& S_IFMT
) != S_IFCHR
) {
1172 Txwindow
= TXBSIZE
- 1024;
1173 Txwspac
= TXBSIZE
/4;
1176 * If input is not a regular file, force ACK's to
1177 * prevent running beyond the buffer limits
1180 fstat(fileno(in
), &f
);
1181 if ((f
.st_mode
& S_IFMT
) != S_IFREG
) {
1184 Txwindow
= TXBSIZE
- 1024;
1185 Txwspac
= TXBSIZE
/4;
1191 /* Set initial subpacket length */
1192 if (blklen
< 1024) { /* Command line override? */
1195 if (Baudrate
> 1200)
1197 if (Baudrate
> 2400)
1200 if (Rxbuflen
&& blklen
>Rxbuflen
)
1202 if (blkopt
&& blklen
> blkopt
)
1204 vfile("Rxbuflen=%d blklen=%d", Rxbuflen
, blklen
);
1205 vfile("Txwindow = %u Txwspac = %d", Txwindow
, Txwspac
);
1207 return (sendzsinit());
1212 if (Rxhdr
[ZF0
] == ZCOMMAND
)
1215 zshhdr(ZNAK
, Txhdr
);
1222 /* Send send-init information */
1227 if (Myattn
[0] == '\0' && (!Zctlesc
|| (Rxflags
& TESCCTL
)))
1233 Txhdr
[ZF0
] |= TESCCTL
; zshhdr(ZSINIT
, Txhdr
);
1236 zsbhdr(ZSINIT
, Txhdr
);
1237 zsdata(Myattn
, 1+strlen(Myattn
), ZCRCW
);
1238 c
= zgethdr(Rxhdr
, 1);
1252 /* Send file name and related info */
1253 int zsendfile(char *buf
, int blen
)
1256 register UNSL
long crc
;
1259 Txhdr
[ZF0
] = Lzconv
; /* file conversion request */
1260 Txhdr
[ZF1
] = Lzmanag
; /* file management request */
1262 Txhdr
[ZF1
] |= ZMSKNOLOC
;
1263 Txhdr
[ZF2
] = Lztrans
; /* file transport request */
1265 zsbhdr(ZFILE
, Txhdr
);
1266 zsdata(buf
, blen
, ZCRCW
);
1268 c
= zgethdr(Rxhdr
, 1);
1271 while ((c
= readline(50)) > 0)
1275 /* **** FALL THRU TO **** */
1286 while (((c
= getc(in
)) != EOF
) && --Rxpos
)
1287 crc
= UPDC32(c
, crc
);
1289 clearerr(in
); /* Clear EOF */
1293 zsbhdr(ZCRC
, Txhdr
);
1296 fclose(in
); return c
;
1299 * Suppress zcrcw request otherwise triggered by
1302 if (Rxpos
&& fseek(in
, Rxpos
, 0))
1304 Lastsync
= (bytcnt
= Txpos
= Rxpos
) -1;
1305 return zsendfdata();
1310 /* Send the data in the file */
1313 register int c
, e
, n
;
1314 register int newcnt
;
1315 register long tcount
= 0;
1316 int junkcount
; /* Counts garbage chars received by TX */
1317 static int tleft
= 6; /* Counter for test mode */
1323 if (setjmp(intrjmp
)) {
1344 * If the reverse channel can be tested for data,
1345 * this logic may be used to detect error packets
1346 * sent by the receiver, in place of setjmp/longjmp
1347 * rdchk(fdes) returns non 0 if a character is available
1349 while (rdchk(iofd
)) {
1353 switch (readline(1))
1360 case XOFF
: /* Wait a while for an XON */
1369 signal(SIGINT
, onintr
);
1373 zsbhdr(ZDATA
, Txhdr
);
1376 * Special testing mode. This should force receiver to Attn,ZRPOS
1377 * many times. Each time the signal should be caught, causing the
1378 * file to be started over from the beginning.
1382 while (tcount
< 20000) {
1383 printf("%s", qbf
); fflush(stdout
);
1384 tcount
+= strlen(qbf
);
1386 while (rdchk(iofd
)) {
1390 switch (readline(1))
1396 ioctl(iofd
, TCFLSH
, 1);
1399 case XOFF
: /* Wait for XON */
1406 signal(SIGINT
, SIG_IGN
); canit();
1407 sleep(3); purgeline(); mode(0);
1408 printf("\nsz: Tcount = %ld\n", tcount
);
1410 printf("ERROR: Interrupts Not Caught\n");
1420 else if (junkcount
> 3)
1422 else if (bytcnt
== Lastsync
)
1424 else if (Rxbuflen
&& (newcnt
-= n
) <= 0)
1426 else if (Txwindow
&& (Txwcnt
+= n
) >= Txwspac
) {
1427 Txwcnt
= 0; e
= ZCRCQ
;
1432 fprintf(stderr
, "\r%7ld ZMODEM%s ",
1433 Txpos
, Crc32t
?" CRC-32":"");
1434 zsdata(txbuf
, n
, e
);
1435 bytcnt
= Txpos
+= n
;
1440 * If the reverse channel can be tested for data,
1441 * this logic may be used to detect error packets
1442 * sent by the receiver, in place of setjmp/longjmp
1443 * rdchk(fdes) returns non 0 if a character is available
1446 while (rdchk(iofd
)) {
1450 switch (readline(1))
1459 ioctl(iofd
, TCFLSH
, 1);
1461 /* zcrce - dinna wanna starta ping-pong game */
1462 zsdata(txbuf
, 0, ZCRCE
);
1464 case XOFF
: /* Wait a while for an XON */
1471 #endif /* READCHECK */
1473 while ((tcount
= Txpos
- Lrxpos
) >= Txwindow
) {
1474 vfile("%ld window >= %u", tcount
, Txwindow
);
1476 zsdata(txbuf
, 0, e
= ZCRCQ
);
1480 ioctl(iofd
, TCFLSH
, 1);
1482 zsdata(txbuf
, 0, ZCRCE
);
1486 vfile("window = %ld", tcount
);
1490 signal(SIGINT
, SIG_IGN
);
1494 zsbhdr(ZEOF
, Txhdr
);
1495 switch (getinsync(0)) {
1513 * Respond to receiver's complaint, get back in sync with receiver
1515 int getinsync(int flag
)
1521 printf("\r\n\n\n***** Signal Caught *****\r\n");
1522 Rxpos
= 0; c
= ZRPOS
;
1524 c
= zgethdr(Rxhdr
, 0);
1532 /* ************************************* */
1533 /* If sending to a buffered modem, you */
1534 /* might send a break at this point to */
1535 /* dump the modem's buffer. */
1536 clearerr(in
); /* In case file EOF seen */
1537 if (fseek(in
, Rxpos
, 0))
1540 bytcnt
= Lrxpos
= Txpos
= Rxpos
;
1541 if (Lastsync
== Rxpos
) {
1542 if (++Beenhereb4
> 4)
1550 if (flag
|| Txpos
== Rxpos
)
1559 zsbhdr(ZNAK
, Txhdr
);
1566 /* Say "bibi" to the receiver, try to do it cleanly */
1570 stohdr(0L); /* CAF Was zsbhdr - minor change */
1571 zshhdr(ZFIN
, Txhdr
); /* to make debugging easier */
1572 switch (zgethdr(Rxhdr
, 0)) {
1574 sendline('O'); sendline('O'); flushmo();
1582 /* Local screen character display function */
1589 /* Send command and related info */
1590 int zsendcmd(char *buf
, int blen
)
1599 Txhdr
[ZF0
] = Cmdack1
;
1600 zsbhdr(ZCOMMAND
, Txhdr
);
1601 zsdata(buf
, blen
, ZCRCW
);
1603 Rxtimeout
= 100; /* Ten second wait for resp. */
1604 c
= zgethdr(Rxhdr
, 1);
1608 goto listen
; /* CAF 8-21-87 */
1611 if (++errors
> Cmdtries
)
1629 #ifdef vax11c /* YAMP :== Yet Another Missing Primitive */
1632 vfile("******** RZ *******");
1634 vfile("******** SZ *******");
1642 * If called as sb use YMODEM protocol
1644 void chkinvok(char *s
)
1661 if (s
[0]=='s' && s
[1]=='b') {
1662 Nozmodem
= TRUE
; blklen
=1024;
1664 if (s
[0]=='s' && s
[1]=='x') {
1670 void countem(int argc
, char **argv
)
1675 for (Totalleft
= 0, Filesleft
= 0; --argc
>=0; ++argv
) {
1678 fprintf(stderr
, "\nCountem: %03d %s ", argc
, *argv
);
1681 if (access(*argv
, 04) >= 0 && stat(*argv
, &f
) >= 0) {
1682 c
= f
.st_mode
& S_IFMT
;
1683 if (c
!= S_IFDIR
&& c
!= S_IFBLK
) {
1684 ++Filesleft
; Totalleft
+= f
.st_size
;
1688 fprintf(stderr
, " %lld", f
.st_size
);
1691 fprintf(stderr
, "\ncountem: Total %d %ld\n",
1692 Filesleft
, Totalleft
);
1695 void chartest(int m
)
1700 printf("\r\n\nCharacter Transparency Test Mode %d\r\n", m
);
1701 printf("If Pro-YAM/ZCOMM is not displaying ^M hit ALT-V NOW.\r\n");
1702 printf("Hit Enter.\021"); fflush(stdout
);
1705 for (n
= 0; n
< 256; ++n
) {
1708 printf("%02x ", n
); fflush(stdout
);
1709 sendline(n
); flushmo();
1710 printf(" "); fflush(stdout
);
1712 printf("Hit Enter.\021"); fflush(stdout
);
1714 printf("\r\n"); fflush(stdout
);
1717 printf("\021\r\nEnter Characters, echo is in hex.\r\n");
1718 printf("Hit SPACE or pause 40 seconds for exit.\r\n");
1720 while (n
!= TIMEOUT
&& n
!= ' ') {
1722 printf("%02x\r\n", n
);
1725 printf("\r\nMode %d character transparency test ends.\r\n", m
);