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 %o %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
) && attempts
< RETRYMAX
);
730 if (attempts
== RETRYMAX
) {
731 zperr("No ACK on EOT");
738 * @param cseclen :data length of this sector to send
740 int wcputsec(char *buf
, int sectnum
, int cseclen
)
742 register int checksum
, wcj
;
748 firstch
=0; /* part of logic to detect CAN CAN */
751 fprintf(stderr
, "Sector %3d %2dk\n", Totsecs
, Totsecs
/8 );
753 fprintf(stderr
, "\rSector %3d %2dk ", Totsecs
, Totsecs
/8 );
754 for (attempts
=0; attempts
<= RETRYMAX
; attempts
++) {
756 sendline(cseclen
==1024?STX
:SOH
);
758 sendline(-sectnum
-1);
760 for (wcj
=cseclen
,cp
=buf
; --wcj
>=0; ) {
762 oldcrc
=updcrc((0377& *cp
), oldcrc
);
766 oldcrc
=updcrc(0,updcrc(0,oldcrc
));
767 sendline((int)oldcrc
>>8);
768 sendline((int)oldcrc
);
774 firstsec
= FALSE
; return OK
;
776 firstch
= readline(Rxtimeout
);
782 zperr("Cancelled"); return ERROR
;
786 zperr("Timeout on sector ACK"); continue;
791 zperr("NAK on sector"); continue;
794 Totsecs
+= (cseclen
>>7);
797 zperr("Got burst for sector ACK"); break;
799 zperr("Got %02x for sector ACK", firstch
); break;
803 if ((firstch
= readline(Rxtimeout
)) == TIMEOUT
)
805 if (firstch
== NAK
|| firstch
== WANTCRC
)
807 if (firstch
== CAN
&& Lastrx
== CAN
)
811 zperr("Retry Count Exceeded");
815 /* fill buf with count chars padding with ^Z for CPM */
816 int filbuf(char *buf
, int count
)
821 m
= read(fileno(in
), buf
, count
);
830 *buf
++ = 012; --m
; Lfseen
= 0;
832 while ((c
=getc(in
))!=EOF
) {
836 Lfseen
= TRUE
; break;
851 /* Fill buffer with blklen chars */
857 /* We assume request is within buffer, or just beyond */
858 txbuf
= Txb
+ (bytcnt
& TXBMASK
);
859 if (vpos
<= bytcnt
) {
860 n
= fread(txbuf
, 1, blklen
, in
);
866 if (vpos
>= (bytcnt
+blklen
))
868 /* May be a short block if crash recovery etc. */
870 return (vpos
- bytcnt
);
872 n
= fread(txbuf
, 1, blklen
, in
);
880 int fooseek(FILE *fptr
, long pos
, int whence
)
884 vfile("fooseek: pos =%lu vpos=%lu Canseek=%d", pos
, vpos
, Canseek
);
885 /* Seek offset < current buffer */
886 if (pos
< (vpos
-TXBSIZE
+1024)) {
889 vpos
= pos
& ~TXBMASK
;
892 if (fseek(fptr
, vpos
, 0))
895 else if (Canseek
== 0)
896 if (fseek(fptr
, vpos
= 0L, 0))
900 while (vpos
<= pos
) {
901 n
= fread(Txb
, 1, TXBSIZE
, fptr
);
903 vfile("n=%d vpos=%ld", n
, vpos
);
909 vfile("vpos=%ld", vpos
);
912 /* Seek offset > current buffer (crash recovery, etc.) */
915 if (fseek(fptr
, vpos
= (pos
& ~TXBMASK
), 0))
917 while (vpos
<= pos
) {
918 txbuf
= Txb
+ (vpos
& TXBMASK
);
919 m
= TXBSIZE
- (vpos
& TXBMASK
);
920 n
= fread(txbuf
, 1, m
, fptr
);
922 vfile("bo=%d n=%d vpos=%ld", txbuf
-Txb
, n
, vpos
);
930 /* Seek offset is within current buffer */
931 vfile("vpos=%ld", vpos
);
934 #define fseek fooseek
937 void vfile(const char *string
, ...)
941 va_start(args
, string
);
942 vfprintf(stderr
, string
, args
);
944 fprintf(stderr
, "\n");
957 * readline(timeout) reads character(s) from file descriptor 0
958 * timeout is in tenths of seconds
960 int readline(int timeout
)
966 if (setjmp(tohere
)) {
974 fprintf(stderr
, "Timeout=%d Calling alarm(%d) ", timeout
, c
);
976 signal(SIGALRM
, alrm
); alarm(c
);
977 c
=read(iofd
, byt
, 1);
980 fprintf(stderr
, "ret %x\n", byt
[0]);
983 return (byt
[0]&0377);
995 ioctl(iofd
, TCFLSH
, 0);
1002 /* send cancel string to get the other end to shut up */
1005 static char canistr
[] = {
1006 24,24,24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8,0
1010 raw_wbuf(strlen(canistr
), canistr
);
1023 void zperr(char *s
, char *p
, char *u
)
1027 fprintf(stderr
, "\nRetry %d: ", errors
);
1028 fprintf(stderr
, s
, p
, u
);
1029 fprintf(stderr
, "\n");
1033 * substr(string, token) searches for token in string s
1034 * returns pointer to token within string if found, NULL otherwise
1037 substr(char *s
, char *t
)
1039 register char *ss
,*tt
;
1040 /* search for first char of token */
1043 /* compare token with substring */
1044 for (ss
=s
,tt
=t
; ;) {
1050 return (char *)NULL
;
1055 " Send file(s) with ZMODEM Protocol",
1056 "Usage: sz [-2+abdefkLlNnquvwYy] [-] file ...",
1057 " sz [-2Ceqv] -c COMMAND",
1058 " \\ Force next option letter to upper case",
1060 "Send file(s) with ZMODEM/YMODEM/XMODEM Protocol",
1061 " (Y) = Option applies to YMODEM only",
1062 " (Z) = Option applies to ZMODEM only",
1063 "Usage: sz [-2+abdefkLlNnquvwYy] [-] file ...",
1064 " sz [-2Ceqv] -c COMMAND",
1065 " sb [-2adfkquv] [-] file ...",
1066 " sx [-2akquv] [-] file",
1069 " 2 Use 2 stop bits",
1071 " + Append to existing destination file (Z)",
1072 " a (ASCII) change NL to CR/LF",
1073 " b Binary file transfer override",
1074 " c send COMMAND (Z)",
1076 " d Change '.' to '/' in pathnames (Y/Z)",
1078 " e Escape all control characters (Z)",
1079 " f send Full pathname (Y/Z)",
1080 " i send COMMAND, ack Immediately (Z)",
1081 " k Send 1024 byte packets (Y)",
1082 " L N Limit subpacket length to N bytes (Z)",
1083 " l N Limit frame length to N bytes (l>=L) (Z)",
1084 " n send file if source newer (Z)",
1085 " N send file if source newer or longer (Z)",
1086 " o Use 16 bit CRC instead of 32 bit CRC (Z)",
1087 " p Protect existing destination file (Z)",
1088 " r Resume/Recover interrupted file transfer (Z)",
1089 " q Quiet (no progress reports)",
1091 " u Unlink file after transmission",
1093 " v Verbose - provide debugging information",
1094 " w N Window is N bytes (Z)",
1095 " Y Yes, overwrite existing file, skip if not present at rx (Z)",
1096 " y Yes, overwrite existing file (Z)",
1097 "- as pathname sends standard input as sPID.sz or environment ONAME",
1105 for (pp
=babble
; **pp
; ++pp
)
1106 fprintf(stderr
, "%s\n", *pp
);
1107 fprintf(stderr
, "%s for %s by Chuck Forsberg, Omen Technology INC\n",
1109 fprintf(stderr
, "\t\t\042The High Reliability Software\042\n");
1115 * Get the receiver's init parameters
1122 for (n
=10; --n
>=0; ) {
1124 switch (zgethdr(Rxhdr
, 1)) {
1125 case ZCHALLENGE
: /* Echo receiver's challenge numbr */
1127 zshhdr(ZACK
, Txhdr
);
1129 case ZCOMMAND
: /* They didn't see out ZRQINIT */
1131 zshhdr(ZRQINIT
, Txhdr
);
1134 Rxflags
= 0377 & Rxhdr
[ZF0
];
1135 Txfcs32
= (Wantfcs32
&& (Rxflags
& CANFC32
));
1136 Zctlesc
|= Rxflags
& TESCCTL
;
1137 Rxbuflen
= (0377 & Rxhdr
[ZP0
])+((0377 & Rxhdr
[ZP1
])<<8);
1138 if ( !(Rxflags
& CANFDX
))
1140 vfile("Rxbuflen=%d Tframlen=%d", Rxbuflen
, Tframlen
);
1142 signal(SIGINT
, SIG_IGN
);
1144 mode(2); /* Set cbreak, XON/XOFF, etc. */
1148 /* Use 1024 byte frames if no sample/interrupt */
1149 if (Rxbuflen
< 32 || Rxbuflen
> 1024) {
1151 vfile("Rxbuflen=%d", Rxbuflen
);
1155 /* Override to force shorter frame length */
1156 if (Rxbuflen
&& (Rxbuflen
>Tframlen
) && (Tframlen
>=32))
1157 Rxbuflen
= Tframlen
;
1158 if ( !Rxbuflen
&& (Tframlen
>=32) && (Tframlen
<=1024))
1159 Rxbuflen
= Tframlen
;
1160 vfile("Rxbuflen=%d", Rxbuflen
);
1163 /* If using a pipe for testing set lower buf len */
1165 if ((f
.st_mode
& S_IFMT
) != S_IFCHR
) {
1171 Txwindow
= TXBSIZE
- 1024;
1172 Txwspac
= TXBSIZE
/4;
1175 * If input is not a regular file, force ACK's to
1176 * prevent running beyond the buffer limits
1179 fstat(fileno(in
), &f
);
1180 if ((f
.st_mode
& S_IFMT
) != S_IFREG
) {
1183 Txwindow
= TXBSIZE
- 1024;
1184 Txwspac
= TXBSIZE
/4;
1190 /* Set initial subpacket length */
1191 if (blklen
< 1024) { /* Command line override? */
1194 if (Baudrate
> 1200)
1196 if (Baudrate
> 2400)
1199 if (Rxbuflen
&& blklen
>Rxbuflen
)
1201 if (blkopt
&& blklen
> blkopt
)
1203 vfile("Rxbuflen=%d blklen=%d", Rxbuflen
, blklen
);
1204 vfile("Txwindow = %u Txwspac = %d", Txwindow
, Txwspac
);
1206 return (sendzsinit());
1211 if (Rxhdr
[ZF0
] == ZCOMMAND
)
1214 zshhdr(ZNAK
, Txhdr
);
1221 /* Send send-init information */
1226 if (Myattn
[0] == '\0' && (!Zctlesc
|| (Rxflags
& TESCCTL
)))
1232 Txhdr
[ZF0
] |= TESCCTL
; zshhdr(ZSINIT
, Txhdr
);
1235 zsbhdr(ZSINIT
, Txhdr
);
1236 zsdata(Myattn
, 1+strlen(Myattn
), ZCRCW
);
1237 c
= zgethdr(Rxhdr
, 1);
1251 /* Send file name and related info */
1252 int zsendfile(char *buf
, int blen
)
1255 register UNSL
long crc
;
1258 Txhdr
[ZF0
] = Lzconv
; /* file conversion request */
1259 Txhdr
[ZF1
] = Lzmanag
; /* file management request */
1261 Txhdr
[ZF1
] |= ZMSKNOLOC
;
1262 Txhdr
[ZF2
] = Lztrans
; /* file transport request */
1264 zsbhdr(ZFILE
, Txhdr
);
1265 zsdata(buf
, blen
, ZCRCW
);
1267 c
= zgethdr(Rxhdr
, 1);
1270 while ((c
= readline(50)) > 0)
1274 /* **** FALL THRU TO **** */
1285 while (((c
= getc(in
)) != EOF
) && --Rxpos
)
1286 crc
= UPDC32(c
, crc
);
1288 clearerr(in
); /* Clear EOF */
1292 zsbhdr(ZCRC
, Txhdr
);
1295 fclose(in
); return c
;
1298 * Suppress zcrcw request otherwise triggered by
1301 if (Rxpos
&& fseek(in
, Rxpos
, 0))
1303 Lastsync
= (bytcnt
= Txpos
= Rxpos
) -1;
1304 return zsendfdata();
1309 /* Send the data in the file */
1312 register int c
, e
, n
;
1313 register int newcnt
;
1314 register long tcount
= 0;
1315 int junkcount
; /* Counts garbage chars received by TX */
1316 static int tleft
= 6; /* Counter for test mode */
1322 if (setjmp(intrjmp
)) {
1343 * If the reverse channel can be tested for data,
1344 * this logic may be used to detect error packets
1345 * sent by the receiver, in place of setjmp/longjmp
1346 * rdchk(fdes) returns non 0 if a character is available
1348 while (rdchk(iofd
)) {
1352 switch (readline(1))
1359 case XOFF
: /* Wait a while for an XON */
1368 signal(SIGINT
, onintr
);
1372 zsbhdr(ZDATA
, Txhdr
);
1375 * Special testing mode. This should force receiver to Attn,ZRPOS
1376 * many times. Each time the signal should be caught, causing the
1377 * file to be started over from the beginning.
1381 while (tcount
< 20000) {
1382 printf(qbf
); fflush(stdout
);
1383 tcount
+= strlen(qbf
);
1385 while (rdchk(iofd
)) {
1389 switch (readline(1))
1395 ioctl(iofd
, TCFLSH
, 1);
1398 case XOFF
: /* Wait for XON */
1405 signal(SIGINT
, SIG_IGN
); canit();
1406 sleep(3); purgeline(); mode(0);
1407 printf("\nsz: Tcount = %ld\n", tcount
);
1409 printf("ERROR: Interrupts Not Caught\n");
1419 else if (junkcount
> 3)
1421 else if (bytcnt
== Lastsync
)
1423 else if (Rxbuflen
&& (newcnt
-= n
) <= 0)
1425 else if (Txwindow
&& (Txwcnt
+= n
) >= Txwspac
) {
1426 Txwcnt
= 0; e
= ZCRCQ
;
1431 fprintf(stderr
, "\r%7ld ZMODEM%s ",
1432 Txpos
, Crc32t
?" CRC-32":"");
1433 zsdata(txbuf
, n
, e
);
1434 bytcnt
= Txpos
+= n
;
1439 * If the reverse channel can be tested for data,
1440 * this logic may be used to detect error packets
1441 * sent by the receiver, in place of setjmp/longjmp
1442 * rdchk(fdes) returns non 0 if a character is available
1445 while (rdchk(iofd
)) {
1449 switch (readline(1))
1458 ioctl(iofd
, TCFLSH
, 1);
1460 /* zcrce - dinna wanna starta ping-pong game */
1461 zsdata(txbuf
, 0, ZCRCE
);
1463 case XOFF
: /* Wait a while for an XON */
1470 #endif /* READCHECK */
1472 while ((tcount
= Txpos
- Lrxpos
) >= Txwindow
) {
1473 vfile("%ld window >= %u", tcount
, Txwindow
);
1475 zsdata(txbuf
, 0, e
= ZCRCQ
);
1479 ioctl(iofd
, TCFLSH
, 1);
1481 zsdata(txbuf
, 0, ZCRCE
);
1485 vfile("window = %ld", tcount
);
1489 signal(SIGINT
, SIG_IGN
);
1493 zsbhdr(ZEOF
, Txhdr
);
1494 switch (getinsync(0)) {
1512 * Respond to receiver's complaint, get back in sync with receiver
1514 int getinsync(int flag
)
1520 printf("\r\n\n\n***** Signal Caught *****\r\n");
1521 Rxpos
= 0; c
= ZRPOS
;
1523 c
= zgethdr(Rxhdr
, 0);
1531 /* ************************************* */
1532 /* If sending to a buffered modem, you */
1533 /* might send a break at this point to */
1534 /* dump the modem's buffer. */
1535 clearerr(in
); /* In case file EOF seen */
1536 if (fseek(in
, Rxpos
, 0))
1539 bytcnt
= Lrxpos
= Txpos
= Rxpos
;
1540 if (Lastsync
== Rxpos
) {
1541 if (++Beenhereb4
> 4)
1549 if (flag
|| Txpos
== Rxpos
)
1558 zsbhdr(ZNAK
, Txhdr
);
1565 /* Say "bibi" to the receiver, try to do it cleanly */
1569 stohdr(0L); /* CAF Was zsbhdr - minor change */
1570 zshhdr(ZFIN
, Txhdr
); /* to make debugging easier */
1571 switch (zgethdr(Rxhdr
, 0)) {
1573 sendline('O'); sendline('O'); flushmo();
1581 /* Local screen character display function */
1588 /* Send command and related info */
1589 int zsendcmd(char *buf
, int blen
)
1598 Txhdr
[ZF0
] = Cmdack1
;
1599 zsbhdr(ZCOMMAND
, Txhdr
);
1600 zsdata(buf
, blen
, ZCRCW
);
1602 Rxtimeout
= 100; /* Ten second wait for resp. */
1603 c
= zgethdr(Rxhdr
, 1);
1607 goto listen
; /* CAF 8-21-87 */
1610 if (++errors
> Cmdtries
)
1628 #ifdef vax11c /* YAMP :== Yet Another Missing Primitive */
1631 vfile("******** RZ *******");
1633 vfile("******** SZ *******");
1641 * If called as sb use YMODEM protocol
1643 void chkinvok(char *s
)
1660 if (s
[0]=='s' && s
[1]=='b') {
1661 Nozmodem
= TRUE
; blklen
=1024;
1663 if (s
[0]=='s' && s
[1]=='x') {
1669 void countem(int argc
, char **argv
)
1674 for (Totalleft
= 0, Filesleft
= 0; --argc
>=0; ++argv
) {
1677 fprintf(stderr
, "\nCountem: %03d %s ", argc
, *argv
);
1680 if (access(*argv
, 04) >= 0 && stat(*argv
, &f
) >= 0) {
1681 c
= f
.st_mode
& S_IFMT
;
1682 if (c
!= S_IFDIR
&& c
!= S_IFBLK
) {
1683 ++Filesleft
; Totalleft
+= f
.st_size
;
1687 fprintf(stderr
, " %lld", f
.st_size
);
1690 fprintf(stderr
, "\ncountem: Total %d %ld\n",
1691 Filesleft
, Totalleft
);
1694 void chartest(int m
)
1699 printf("\r\n\nCharacter Transparency Test Mode %d\r\n", m
);
1700 printf("If Pro-YAM/ZCOMM is not displaying ^M hit ALT-V NOW.\r\n");
1701 printf("Hit Enter.\021"); fflush(stdout
);
1704 for (n
= 0; n
< 256; ++n
) {
1707 printf("%02x ", n
); fflush(stdout
);
1708 sendline(n
); flushmo();
1709 printf(" "); fflush(stdout
);
1711 printf("Hit Enter.\021"); fflush(stdout
);
1713 printf("\r\n"); fflush(stdout
);
1716 printf("\021\r\nEnter Characters, echo is in hex.\r\n");
1717 printf("Hit SPACE or pause 40 seconds for exit.\r\n");
1719 while (n
!= TIMEOUT
&& n
!= ' ') {
1721 printf("%02x\r\n", n
);
1724 printf("\r\nMode %d character transparency test ends.\r\n", m
);