sz.c

Go to the documentation of this file.
00001 #define VERSION "sz 2.12 05-29-88"
00002 #define PUBDIR "/usr/spool/uucppublic"
00003 
00004 /*% cc -compat -M2 -Ox -K -i -DTXBSIZE=16384  -DNFGVMIN -DREADCHECK sz.c -lx -o sz; size sz
00005 
00006         Following is used for testing, might not be reasonable for production
00007 <-xtx-*> cc -Osal -DTXBSIZE=32768  -DSV sz.c -lx -o $B/sz; size $B/sz
00008 
00009  ****************************************************************************
00010  *
00011  * sz.c By Chuck Forsberg,  Omen Technology INC
00012  *
00013  ****************************************************************************
00014  *
00015  * Typical Unix/Xenix/Clone compiles:
00016  *
00017  *      cc -O sz.c -o sz                USG (SYS III/V) Unix
00018  *      cc -O -DSV sz.c -o sz           Sys V Release 2 with non-blocking input
00019  *                                      Define to allow reverse channel checking
00020  *      cc -O -DV7  sz.c -o sz          Unix Version 7, 2.8 - 4.3 BSD
00021  *
00022  *      cc -O -K -i -DNFGVMIN -DREADCHECK sz.c -lx -o sz        Classic Xenix
00023  *
00024  *      ln sz sb                        **** All versions ****
00025  *      ln sz sx                        **** All versions ****
00026  *
00027  ****************************************************************************
00028  *
00029  * Typical VMS compile and install sequence:
00030  *
00031  *              define LNK$LIBRARY   SYS$LIBRARY:VAXCRTL.OLB
00032  *              cc sz.c
00033  *              cc vvmodem.c
00034  *              link sz,vvmodem
00035  *      sz :== $disk$user2:[username.subdir]sz.exe
00036  *
00037  *  If you feel adventureous, remove the #define BADSYNC line
00038  *  immediately following the #ifdef vax11c line!  Some VMS
00039  *  systems know how to fseek, some don't.
00040  *
00041  ****************************************************************************
00042  *
00043  *
00044  * A program for Unix to send files and commands to computers running
00045  *  Professional-YAM, PowerCom, YAM, IMP, or programs supporting Y/XMODEM.
00046  *
00047  *  Sz uses buffered I/O to greatly reduce CPU time compared to UMODEM.
00048  *
00049  *  USG UNIX (3.0) ioctl conventions courtesy Jeff Martin
00050  *
00051  *  2.1x hacks to avoid VMS fseek() bogosity, allow input from pipe
00052  *     -DBADSEEK -DTXBSIZE=32768  
00053  *  2.x has mods for VMS flavor
00054  *
00055  * 1.34 implements tx backchannel garbage count and ZCRCW after ZRPOS
00056  * in accordance with the 7-31-87 ZMODEM Protocol Description
00057  */
00058 
00059 
00060 #include <sys/types.h>
00061 
00062 #ifdef vax11c
00063 #define BADSEEK
00064 #define TXBSIZE 32768           /* Must be power of two, < MAXINT */
00065 #include <types.h>
00066 #include <stat.h>
00067 #define LOGFILE "szlog.tmp"
00068 #define OS "VMS"
00069 #define READCHECK
00070 #define BUFWRITE
00071 #define iofd
00072 extern int errno;
00073 #define SS_NORMAL SS$_NORMAL
00074 #define xsendline(c) sendline(c)
00075 
00076 
00077 #else   /* vax11c */
00078 
00079 
00080 #define SS_NORMAL 0
00081 #define LOGFILE "/tmp/szlog"
00082 
00083 #define sendline(c) putchar((c) & 0377)
00084 #define xsendline(c) putchar(c)
00085 
00086 #endif
00087 
00088 #include <signal.h>
00089 #include <setjmp.h>
00090 #include <ctype.h>
00091 #include <errno.h>
00092 #include <stdlib.h>
00093 #include <string.h>
00094 #include <stdlib.h>
00095 #include <unistd.h>
00096 #include <utime.h>
00097 #include <stdio.h>
00098 
00099 #define PATHLEN 256
00100 #define OK 0
00101 #define FALSE 0
00102 #define TRUE 1
00103 #undef ERROR
00104 #define ERROR (-1)
00105 /* Ward Christensen / CP/M parameters - Don't change these! */
00106 #define ENQ 005
00107 #define CAN ('X'&037)
00108 #define XOFF ('s'&037)
00109 #define XON ('q'&037)
00110 #define SOH 1
00111 #define STX 2
00112 #define EOT 4
00113 #define ACK 6
00114 #define NAK 025
00115 #define CPMEOF 032
00116 #define WANTCRC 0103    /* send C not NAK to get crc not checksum */
00117 #define WANTG 0107      /* Send G not NAK to get nonstop batch xmsn */
00118 #define TIMEOUT (-2)
00119 #define RCDO (-3)
00120 #define RETRYMAX 10
00121 
00122 
00123 #define HOWMANY 2
00124 int Zmodem=0;           /* ZMODEM protocol requested by receiver */
00125 unsigned Baudrate=2400; /* Default, should be set by first mode() call */
00126 unsigned Txwindow;      /* Control the size of the transmitted window */
00127 unsigned Txwspac;       /* Spacing between zcrcq requests */
00128 unsigned Txwcnt;        /* Counter used to space ack requests */
00129 long Lrxpos;            /* Receiver's last reported offset */
00130 int errors;
00131 
00132 #ifdef vax11c
00133 #include "vrzsz.c"      /* most of the system dependent stuff here */
00134 #else
00135 #include "rbsb.c"       /* most of the system dependent stuff here */
00136 #endif
00137 #include "crctab.c"
00138 
00139 int Filesleft;
00140 long Totalleft;
00141 
00142 /*
00143  * Attention string to be executed by receiver to interrupt streaming data
00144  *  when an error is detected.  A pause (0336) may be needed before the
00145  *  ^C (03) or after it.
00146  */
00147 #ifdef READCHECK
00148 char Myattn[] = { 0 };
00149 #else
00150 #ifdef USG
00151 char Myattn[] = { 03, 0336, 0 };
00152 #else
00153 char Myattn[] = { 0 };
00154 #endif
00155 #endif
00156 
00157 FILE *in;
00158 
00159 #ifdef BADSEEK
00160 int Canseek = 0;        /* 1: Can seek 0: only rewind -1: neither (pipe) */
00161 #ifndef TXBSIZE
00162 #define TXBSIZE 16384           /* Must be power of two, < MAXINT */
00163 #endif
00164 #else
00165 int Canseek = 1;        /* 1: Can seek 0: only rewind -1: neither (pipe) */
00166 #endif
00167 
00168 #ifdef TXBSIZE
00169 #define TXBMASK (TXBSIZE-1)
00170 char Txb[TXBSIZE];              /* Circular buffer for file reads */
00171 char *txbuf = Txb;              /* Pointer to current file segment */
00172 #else
00173 char txbuf[1024];
00174 #endif
00175 long vpos = 0;                  /* Number of bytes read from file */
00176 
00177 char Lastrx;
00178 char Crcflg;
00179 int Verbose=0;
00180 int Modem2=0;           /* XMODEM Protocol - don't send pathnames */
00181 int Restricted=0;       /* restricted; no /.. or ../ in filenames */
00182 int Quiet=0;            /* overrides logic that would otherwise set verbose */
00183 int Ascii=0;            /* Add CR's for brain damaged programs */
00184 int Fullname=0;         /* transmit full pathname */
00185 int Unlinkafter=0;      /* Unlink file after it is sent */
00186 int Dottoslash=0;       /* Change foo.bar.baz to foo/bar/baz */
00187 int firstsec;
00188 int errcnt=0;           /* number of files unreadable */
00189 int blklen=128;         /* length of transmitted records */
00190 int Optiong;            /* Let it rip no wait for sector ACK's */
00191 int Eofseen;            /* EOF seen on input set by zfilbuf */
00192 int BEofseen;           /* EOF seen on input set by fooseek */
00193 int Totsecs;            /* total number of sectors this file */
00194 int Filcnt=0;           /* count of number of files opened */
00195 int Lfseen=0;
00196 unsigned Rxbuflen = 16384;      /* Receiver's max buffer length */
00197 int Tframlen = 0;       /* Override for tx frame length */
00198 int blkopt=0;           /* Override value for zmodem blklen */
00199 int Rxflags = 0;
00200 long bytcnt;
00201 int Wantfcs32 = TRUE;   /* want to send 32 bit FCS */
00202 char Lzconv;    /* Local ZMODEM file conversion request */
00203 char Lzmanag;   /* Local ZMODEM file management request */
00204 int Lskipnocor;
00205 char Lztrans;
00206 char zconv;             /* ZMODEM file conversion request */
00207 char zmanag;            /* ZMODEM file management request */
00208 char ztrans;            /* ZMODEM file transport request */
00209 int Command;            /* Send a command, then exit. */
00210 char *Cmdstr;           /* Pointer to the command string */
00211 int Cmdtries = 11;
00212 int Cmdack1;            /* Rx ACKs command, then do it */
00213 int Exitcode = 0;
00214 int Test;               /* 1= Force receiver to send Attn, etc with qbf. */
00215                         /* 2= Character transparency test */
00216 char *qbf="The quick brown fox jumped over the lazy dog's back 1234567890\r\n";
00217 long Lastsync;          /* Last offset to which we got a ZRPOS */
00218 int Beenhereb4;         /* How many times we've been ZRPOS'd same place */
00219 
00220 jmp_buf tohere;         /* For the interrupt on RX timeout */
00221 jmp_buf intrjmp;        /* For the interrupt on RX CAN */
00222 
00223 _PROTOTYPE(void onintr , (int sig ));
00224 _PROTOTYPE(int main , (int argc , char *argv []));
00225 _PROTOTYPE(int wcsend , (int argc , char *argp []));
00226 _PROTOTYPE(int wcs , (char *oname ));
00227 _PROTOTYPE(int wctxpn , (char *name ));
00228 _PROTOTYPE(int getnak , (void));
00229 _PROTOTYPE(int wctx , (long flen ));
00230 _PROTOTYPE(int wcputsec , (char *buf , int sectnum , int cseclen ));
00231 _PROTOTYPE(int filbuf , (char *buf , int count ));
00232 _PROTOTYPE(int zfilbuf , (void));
00233 _PROTOTYPE(int fooseek , (FILE *fptr , long pos , int whence ));
00234 _PROTOTYPE(void alrm , (int sig ));
00235 _PROTOTYPE(int readline , (int timeout ));
00236 _PROTOTYPE(void flushmo , (void));
00237 _PROTOTYPE(void purgeline , (void));
00238 _PROTOTYPE(void canit , (void));
00239 void zperr();
00240 _PROTOTYPE(char *substr , (char *s , char *t ));
00241 _PROTOTYPE(int usage , (void));
00242 _PROTOTYPE(int getzrxinit , (void));
00243 _PROTOTYPE(int sendzsinit , (void));
00244 _PROTOTYPE(int zsendfile , (char *buf , int blen ));
00245 _PROTOTYPE(int zsendfdata , (void));
00246 _PROTOTYPE(int getinsync , (int flag ));
00247 _PROTOTYPE(void saybibi , (void));
00248 _PROTOTYPE(void bttyout , (int c ));
00249 _PROTOTYPE(int zsendcmd , (char *buf , int blen ));
00250 _PROTOTYPE(void chkinvok , (char *s ));
00251 _PROTOTYPE(void countem , (int argc , char **argv ));
00252 _PROTOTYPE(void chartest , (int m ));
00253 
00254 /* called by signal interrupt or terminate to clean things up */
00255 void bibi(n)
00256 int n;
00257 {
00258         canit(); fflush(stdout); mode(0);
00259         fprintf(stderr, "sz: caught signal %d; exiting\n", n);
00260         if (n == SIGQUIT)
00261                 abort();
00262         if (n == 99)
00263                 fprintf(stderr, "mode(2) in rbsb.c not implemented!!\n");
00264         cucheck();
00265         exit(128+n);
00266 }
00267 /* Called when ZMODEM gets an interrupt (^X) */
00268 void onintr(sig)
00269 int sig;
00270 {
00271         signal(SIGINT, SIG_IGN);
00272         longjmp(intrjmp, -1);
00273 }
00274 
00275 int Zctlesc;    /* Encode control characters */
00276 int Nozmodem = 0;       /* If invoked as "sb" */
00277 char *Progname = "sz";
00278 int Zrwindow = 1400;    /* RX window size (controls garbage count) */
00279 #include "zm.c"
00280 
00281 
00282 int main(argc, argv)
00283 int argc;
00284 char *argv[];
00285 {
00286         register char *cp;
00287         register npats;
00288         int dm;
00289         char **patts;
00290         static char xXbuf[BUFSIZ];
00291 
00292         if ((cp = getenv("ZNULLS")) && *cp)
00293                 Znulls = atoi(cp);
00294         if ((cp=getenv("SHELL")) && (substr(cp, "rsh") || substr(cp, "rksh")))
00295                 Restricted=TRUE;
00296         from_cu();
00297         chkinvok(argv[0]);
00298 
00299         Rxtimeout = 600;
00300         npats=0;
00301         if (argc<2)
00302                 usage();
00303         setbuf(stdout, xXbuf);          
00304         while (--argc) {
00305                 cp = *++argv;
00306                 if (*cp++ == '-' && *cp) {
00307                         while ( *cp) {
00308                                 switch(*cp++) {
00309                                 case '\\':
00310                                          *cp = toupper(*cp);  continue;
00311                                 case '+':
00312                                         Lzmanag = ZMAPND; break;
00313 #ifdef CSTOPB
00314                                 case '2':
00315                                         Twostop = TRUE; break;
00316 #endif
00317                                 case 'a':
00318                                         Lzconv = ZCNL;
00319                                         Ascii = TRUE; break;
00320                                 case 'b':
00321                                         Lzconv = ZCBIN; break;
00322                                 case 'C':
00323                                         if (--argc < 1) {
00324                                                 usage();
00325                                         }
00326                                         Cmdtries = atoi(*++argv);
00327                                         break;
00328                                 case 'i':
00329                                         Cmdack1 = ZCACK1;
00330                                         /* **** FALL THROUGH TO **** */
00331                                 case 'c':
00332                                         if (--argc != 1) {
00333                                                 usage();
00334                                         }
00335                                         Command = TRUE;
00336                                         Cmdstr = *++argv;
00337                                         break;
00338                                 case 'd':
00339                                         ++Dottoslash;
00340                                         /* **** FALL THROUGH TO **** */
00341                                 case 'f':
00342                                         Fullname=TRUE; break;
00343                                 case 'e':
00344                                         Zctlesc = 1; break;
00345                                 case 'k':
00346                                         blklen=1024; break;
00347                                 case 'L':
00348                                         if (--argc < 1) {
00349                                                 usage();
00350                                         }
00351                                         blkopt = atoi(*++argv);
00352                                         if (blkopt<24 || blkopt>1024)
00353                                                 usage();
00354                                         break;
00355                                 case 'l':
00356                                         if (--argc < 1) {
00357                                                 usage();
00358                                         }
00359                                         Tframlen = atoi(*++argv);
00360                                         if (Tframlen<32 || Tframlen>1024)
00361                                                 usage();
00362                                         break;
00363                                 case 'N':
00364                                         Lzmanag = ZMNEWL;  break;
00365                                 case 'n':
00366                                         Lzmanag = ZMNEW;  break;
00367                                 case 'o':
00368                                         Wantfcs32 = FALSE; break;
00369                                 case 'p':
00370                                         Lzmanag = ZMPROT;  break;
00371                                 case 'r':
00372                                         Lzconv = ZCRESUM;
00373                                 case 'q':
00374                                         Quiet=TRUE; Verbose=0; break;
00375                                 case 't':
00376                                         if (--argc < 1) {
00377                                                 usage();
00378                                         }
00379                                         Rxtimeout = atoi(*++argv);
00380                                         if (Rxtimeout<10 || Rxtimeout>1000)
00381                                                 usage();
00382                                         break;
00383                                 case 'T':
00384                                         if (++Test > 1) {
00385                                                 chartest(1); chartest(2);
00386                                                 mode(0);  exit(0);
00387                                         }
00388                                         break;
00389 #ifndef vax11c
00390                                 case 'u':
00391                                         ++Unlinkafter; break;
00392 #endif
00393                                 case 'v':
00394                                         ++Verbose; break;
00395                                 case 'w':
00396                                         if (--argc < 1) {
00397                                                 usage();
00398                                         }
00399                                         Txwindow = atoi(*++argv);
00400                                         if (Txwindow < 256)
00401                                                 Txwindow = 256;
00402                                         Txwindow = (Txwindow/64) * 64;
00403                                         Txwspac = Txwindow/4;
00404                                         if (blkopt > Txwspac
00405                                          || (!blkopt && Txwspac < 1024))
00406                                                 blkopt = Txwspac;
00407                                         break;
00408                                 case 'X':
00409                                         ++Modem2; break;
00410                                 case 'Y':
00411                                         Lskipnocor = TRUE;
00412                                         /* **** FALLL THROUGH TO **** */
00413                                 case 'y':
00414                                         Lzmanag = ZMCLOB; break;
00415                                 default:
00416                                         usage();
00417                                 }
00418                         }
00419                 }
00420                 else if ( !npats && argc>0) {
00421                         if (argv[0][0]) {
00422                                 npats=argc;
00423                                 patts=argv;
00424 #ifndef vax11c
00425                                 if ( !strcmp(*patts, "-"))
00426                                         iofd = 1;
00427 #endif
00428                         }
00429                 }
00430         }
00431         if (npats < 1 && !Command && !Test) 
00432                 usage();
00433         if (Verbose) {
00434                 if (freopen(LOGFILE, "a", stderr)==NULL) {
00435                         printf("Can't open log file %s\n",LOGFILE);
00436                         exit(0200);
00437                 }
00438                 setbuf(stderr, (char *)NULL);
00439         }
00440         if (Fromcu && !Quiet) {
00441                 if (Verbose == 0)
00442                         Verbose = 2;
00443         }
00444         vfile("%s %s for %s\n", Progname, VERSION, OS);
00445 
00446         mode(1);
00447 
00448         if (signal(SIGINT, bibi) == SIG_IGN) {
00449                 signal(SIGINT, SIG_IGN); signal(SIGKILL, SIG_IGN);
00450         } else {
00451                 signal(SIGINT, bibi); signal(SIGKILL, bibi);
00452         }
00453         if ( !Fromcu)
00454                 signal(SIGQUIT, SIG_IGN);
00455         signal(SIGTERM, bibi);
00456 
00457         if ( !Modem2) {
00458                 if (!Nozmodem) {
00459                         printf("rz\r");  fflush(stdout);
00460                 }
00461                 countem(npats, patts);
00462                 if (!Nozmodem) {
00463                         stohdr(0L);
00464                         if (Command)
00465                                 Txhdr[ZF0] = ZCOMMAND;
00466                         zshhdr(ZRQINIT, Txhdr);
00467                 }
00468         }
00469         fflush(stdout);
00470 
00471         if (Command) {
00472                 if (getzrxinit()) {
00473                         Exitcode=0200; canit();
00474                 }
00475                 else if (zsendcmd(Cmdstr, 1+strlen(Cmdstr))) {
00476                         Exitcode=0200; canit();
00477                 }
00478         } else if (wcsend(npats, patts)==ERROR) {
00479                 Exitcode=0200;
00480                 canit();
00481         }
00482         fflush(stdout);
00483         mode(0);
00484         dm = ((errcnt != 0) | Exitcode);
00485         if (dm) {
00486                 cucheck();  exit(dm);
00487         }
00488         putc('\n',stderr);
00489         exit(SS_NORMAL);
00490         /*NOTREACHED*/
00491 }
00492 
00493 int wcsend(argc, argp)
00494 int argc;
00495 char *argp[];
00496 {
00497         register int n;
00498 
00499         Crcflg=FALSE;
00500         firstsec=TRUE;
00501         bytcnt = -1;
00502         for (n=0; n<argc; ++n) {
00503                 Totsecs = 0;
00504                 if (wcs(argp[n])==ERROR)
00505                         return ERROR;
00506         }
00507         Totsecs = 0;
00508         if (Filcnt==0) {        /* bitch if we couldn't open ANY files */
00509                 if ( !Modem2) {
00510                         Command = TRUE;
00511                         Cmdstr = "echo \"sz: Can't open any requested files\"";
00512                         if (getnak()) {
00513                                 Exitcode=0200; canit();
00514                         }
00515                         if (!Zmodem)
00516                                 canit();
00517                         else if (zsendcmd(Cmdstr, 1+strlen(Cmdstr))) {
00518                                 Exitcode=0200; canit();
00519                         }
00520                         Exitcode = 1; return OK;
00521                 }
00522                 canit();
00523                 fprintf(stderr,"\r\nCan't open any requested files.\r\n");
00524                 return ERROR;
00525         }
00526         if (Zmodem)
00527                 saybibi();
00528         else if ( !Modem2)
00529                 wctxpn("");
00530         return OK;
00531 }
00532 
00533 int wcs(oname)
00534 char *oname;
00535 {
00536         register c;
00537         register char *p;
00538         struct stat f;
00539         char name[PATHLEN];
00540 
00541         strcpy(name, oname);
00542 
00543         if (Restricted) {
00544                 /* restrict pathnames to current tree or uucppublic */
00545                 if ( substr(name, "../")
00546                  || (name[0]== '/' && strncmp(name, PUBDIR, strlen(PUBDIR))) ) {
00547                         canit();
00548                         fprintf(stderr,"\r\nsz:\tSecurity Violation\r\n");
00549                         return ERROR;
00550                 }
00551         }
00552 
00553         if ( !strcmp(oname, "-")) {
00554                 if ((p = getenv("ONAME")) && *p)
00555                         strcpy(name, p);
00556                 else
00557                         sprintf(name, "s%d.sz", getpid());
00558                 in = stdin;
00559         }
00560         else if ((in=fopen(oname, "r"))==NULL) {
00561                 ++errcnt;
00562                 return OK;      /* pass over it, there may be others */
00563         }
00564         BEofseen = Eofseen = 0;  vpos = 0;
00565         /* Check for directory or block special files */
00566         fstat(fileno(in), &f);
00567         c = f.st_mode & S_IFMT;
00568         if (c == S_IFDIR || c == S_IFBLK) {
00569                 fclose(in);
00570                 return OK;
00571         }
00572 
00573         ++Filcnt;
00574         switch (wctxpn(name)) {
00575         case ERROR:
00576                 return ERROR;
00577         case ZSKIP:
00578                 return OK;
00579         }
00580         if (!Zmodem && wctx(f.st_size)==ERROR)
00581                 return ERROR;
00582 #ifndef vax11c
00583         if (Unlinkafter)
00584                 unlink(oname);
00585 #endif
00586         return 0;
00587 }
00588 
00589 /*
00590  * generate and transmit pathname block consisting of
00591  *  pathname (null terminated),
00592  *  file length, mode time and file mode in octal
00593  *  as provided by the Unix fstat call.
00594  *  N.B.: modifies the passed name, may extend it!
00595  */
00596 int wctxpn(name)
00597 char *name;
00598 {
00599         register char *p, *q;
00600         char name2[PATHLEN];
00601         struct stat f;
00602 
00603         if (Modem2) {
00604                 if ((in!=stdin) && *name && fstat(fileno(in), &f)!= -1) {
00605                         fprintf(stderr, "Sending %s, %ld blocks: ",
00606                           name, f.st_size>>7);
00607                 }
00608                 fprintf(stderr, "Give your local XMODEM receive command now.\r\n");
00609                 return OK;
00610         }
00611         zperr("Awaiting pathname nak for %s", *name?name:"<END>");
00612         if ( !Zmodem)
00613                 if (getnak())
00614                         return ERROR;
00615 
00616         q = (char *) 0;
00617         if (Dottoslash) {               /* change . to . */
00618                 for (p=name; *p; ++p) {
00619                         if (*p == '/')
00620                                 q = p;
00621                         else if (*p == '.')
00622                                 *(q=p) = '/';
00623                 }
00624                 if (q && strlen(++q) > 8) {     /* If name>8 chars */
00625                         q += 8;                 /*   make it .ext */
00626                         strcpy(name2, q);       /* save excess of name */
00627                         *q = '.';
00628                         strcpy(++q, name2);     /* add it back */
00629                 }
00630         }
00631 
00632         for (p=name, q=txbuf ; *p; )
00633                 if ((*q++ = *p++) == '/' && !Fullname)
00634                         q = txbuf;
00635         *q++ = 0;
00636         p=q;
00637         while (q < (txbuf + 1024))
00638                 *q++ = 0;
00639         if (!Ascii && (in!=stdin) && *name && fstat(fileno(in), &f)!= -1)
00640                 sprintf(p, "%lu %lo %o 0 %d %ld", f.st_size, f.st_mtime,
00641                   f.st_mode, Filesleft, Totalleft);
00642         Totalleft -= f.st_size;
00643         if (--Filesleft <= 0)
00644                 Totalleft = 0;
00645         if (Totalleft < 0)
00646                 Totalleft = 0;
00647 
00648         /* force 1k blocks if name won't fit in 128 byte block */
00649         if (txbuf[125])
00650                 blklen=1024;
00651         else {          /* A little goodie for IMP/KMD */
00652                 txbuf[127] = (f.st_size + 127) >>7;
00653                 txbuf[126] = (f.st_size + 127) >>15;
00654         }
00655         if (Zmodem)
00656                 return zsendfile(txbuf, 1+strlen(p)+(p-txbuf));
00657         if (wcputsec(txbuf, 0, 128)==ERROR)
00658                 return ERROR;
00659         return OK;
00660 }
00661 
00662 int getnak()
00663 {
00664         register firstch;
00665 
00666         Lastrx = 0;
00667         for (;;) {
00668                 switch (firstch = readline(800)) {
00669                 case ZPAD:
00670                         if (getzrxinit())
00671                                 return ERROR;
00672                         Ascii = 0;      /* Receiver does the conversion */
00673                         return FALSE;
00674                 case TIMEOUT:
00675                         zperr("Timeout on pathname");
00676                         return TRUE;
00677                 case WANTG:
00678 #ifdef MODE2OK
00679                         mode(2);        /* Set cbreak, XON/XOFF, etc. */
00680 #endif
00681                         Optiong = TRUE;
00682                         blklen=1024;
00683                 case WANTCRC:
00684                         Crcflg = TRUE;
00685                 case NAK:
00686                         return FALSE;
00687                 case CAN:
00688                         if ((firstch = readline(20)) == CAN && Lastrx == CAN)
00689                                 return TRUE;
00690                 default:
00691                         break;
00692                 }
00693                 Lastrx = firstch;
00694         }
00695 }
00696 
00697 
00698 int wctx(flen)
00699 long flen;
00700 {
00701         register int thisblklen;
00702         register int sectnum, attempts, firstch;
00703         long charssent;
00704 
00705         charssent = 0;  firstsec=TRUE;  thisblklen = blklen;
00706         vfile("wctx:file length=%ld", flen);
00707 
00708         while ((firstch=readline(Rxtimeout))!=NAK && firstch != WANTCRC
00709           && firstch != WANTG && firstch!=TIMEOUT && firstch!=CAN)
00710                 ;
00711         if (firstch==CAN) {
00712                 zperr("Receiver CANcelled");
00713                 return ERROR;
00714         }
00715         if (firstch==WANTCRC)
00716                 Crcflg=TRUE;
00717         if (firstch==WANTG)
00718                 Crcflg=TRUE;
00719         sectnum=0;
00720         for (;;) {
00721                 if (flen <= (charssent + 896L))
00722                         thisblklen = 128;
00723                 if ( !filbuf(txbuf, thisblklen))
00724                         break;
00725                 if (wcputsec(txbuf, ++sectnum, thisblklen)==ERROR)
00726                         return ERROR;
00727                 charssent += thisblklen;
00728         }
00729         fclose(in);
00730         attempts=0;
00731         do {
00732                 purgeline();
00733                 sendline(EOT);
00734                 fflush(stdout);
00735                 ++attempts;
00736         }
00737                 while ((firstch=(readline(Rxtimeout)) != ACK) && attempts < RETRYMAX);
00738         if (attempts == RETRYMAX) {
00739                 zperr("No ACK on EOT");
00740                 return ERROR;
00741         }
00742         else
00743                 return OK;
00744 }
00745 
00746 int wcputsec(buf, sectnum, cseclen)
00747 char *buf;
00748 int sectnum;
00749 int cseclen;    /* data length of this sector to send */
00750 {
00751         register checksum, wcj;
00752         register char *cp;
00753         unsigned oldcrc;
00754         int firstch;
00755         int attempts;
00756 
00757         firstch=0;      /* part of logic to detect CAN CAN */
00758 
00759         if (Verbose>2)
00760                 fprintf(stderr, "Sector %3d %2dk\n", Totsecs, Totsecs/8 );
00761         else if (Verbose>1)
00762                 fprintf(stderr, "\rSector %3d %2dk ", Totsecs, Totsecs/8 );
00763         for (attempts=0; attempts <= RETRYMAX; attempts++) {
00764                 Lastrx= firstch;
00765                 sendline(cseclen==1024?STX:SOH);
00766                 sendline(sectnum);
00767                 sendline(-sectnum -1);
00768                 oldcrc=checksum=0;
00769                 for (wcj=cseclen,cp=buf; --wcj>=0; ) {
00770                         sendline(*cp);
00771                         oldcrc=updcrc((0377& *cp), oldcrc);
00772                         checksum += *cp++;
00773                 }
00774                 if (Crcflg) {
00775                         oldcrc=updcrc(0,updcrc(0,oldcrc));
00776                         sendline((int)oldcrc>>8);
00777                         sendline((int)oldcrc);
00778                 }
00779                 else
00780                         sendline(checksum);
00781 
00782                 if (Optiong) {
00783                         firstsec = FALSE; return OK;
00784                 }
00785                 firstch = readline(Rxtimeout);
00786 gotnak:
00787                 switch (firstch) {
00788                 case CAN:
00789                         if(Lastrx == CAN) {
00790 cancan:
00791                                 zperr("Cancelled");  return ERROR;
00792                         }
00793                         break;
00794                 case TIMEOUT:
00795                         zperr("Timeout on sector ACK"); continue;
00796                 case WANTCRC:
00797                         if (firstsec)
00798                                 Crcflg = TRUE;
00799                 case NAK:
00800                         zperr("NAK on sector"); continue;
00801                 case ACK: 
00802                         firstsec=FALSE;
00803                         Totsecs += (cseclen>>7);
00804                         return OK;
00805                 case ERROR:
00806                         zperr("Got burst for sector ACK"); break;
00807                 default:
00808                         zperr("Got %02x for sector ACK", firstch); break;
00809                 }
00810                 for (;;) {
00811                         Lastrx = firstch;
00812                         if ((firstch = readline(Rxtimeout)) == TIMEOUT)
00813                                 break;
00814                         if (firstch == NAK || firstch == WANTCRC)
00815                                 goto gotnak;
00816                         if (firstch == CAN && Lastrx == CAN)
00817                                 goto cancan;
00818                 }
00819         }
00820         zperr("Retry Count Exceeded");
00821         return ERROR;
00822 }
00823 
00824 /* fill buf with count chars padding with ^Z for CPM */
00825 int filbuf(buf, count)
00826 register char *buf;
00827 int count;
00828 {
00829         register c, m;
00830 
00831         if ( !Ascii) {
00832                 m = read(fileno(in), buf, count);
00833                 if (m <= 0)
00834                         return 0;
00835                 while (m < count)
00836                         buf[m++] = 032;
00837                 return count;
00838         }
00839         m=count;
00840         if (Lfseen) {
00841                 *buf++ = 012; --m; Lfseen = 0;
00842         }
00843         while ((c=getc(in))!=EOF) {
00844                 if (c == 012) {
00845                         *buf++ = 015;
00846                         if (--m == 0) {
00847                                 Lfseen = TRUE; break;
00848                         }
00849                 }
00850                 *buf++ =c;
00851                 if (--m == 0)
00852                         break;
00853         }
00854         if (m==count)
00855                 return 0;
00856         else
00857                 while (--m>=0)
00858                         *buf++ = CPMEOF;
00859         return count;
00860 }
00861 
00862 /* Fill buffer with blklen chars */
00863 int zfilbuf()
00864 {
00865         int n;
00866 
00867 #ifdef TXBSIZE
00868         /* We assume request is within buffer, or just beyond */
00869         txbuf = Txb + (bytcnt & TXBMASK);
00870         if (vpos <= bytcnt) {
00871                 n = fread(txbuf, 1, blklen, in);
00872                 vpos += n;
00873                 if (n < blklen)
00874                         Eofseen = 1;
00875                 return n;
00876         }
00877         if (vpos >= (bytcnt+blklen))
00878                 return blklen;
00879         /* May be a short block if crash recovery etc. */
00880         Eofseen = BEofseen;
00881         return (vpos - bytcnt);
00882 #else
00883         n = fread(txbuf, 1, blklen, in);
00884         if (n < blklen)
00885                 Eofseen = 1;
00886         return n;
00887 #endif
00888 }
00889 
00890 #ifdef TXBSIZE
00891 int fooseek(fptr, pos, whence)
00892 FILE *fptr;
00893 long pos;
00894 {
00895         int m, n;
00896 
00897         vfile("fooseek: pos =%lu vpos=%lu Canseek=%d", pos, vpos, Canseek);
00898         /* Seek offset < current buffer */
00899         if (pos < (vpos -TXBSIZE +1024)) {
00900                 BEofseen = 0;
00901                 if (Canseek > 0) {
00902                         vpos = pos & ~TXBMASK;
00903                         if (vpos >= pos)
00904                                 vpos -= TXBSIZE;
00905                         if (fseek(fptr, vpos, 0))
00906                                 return 1;
00907                 }
00908                 else if (Canseek == 0)
00909                         if (fseek(fptr, vpos = 0L, 0))
00910                                 return 1;
00911                 else
00912                         return 1;
00913                 while (vpos <= pos) {
00914                         n = fread(Txb, 1, TXBSIZE, fptr);
00915                         vpos += n;
00916                         vfile("n=%d vpos=%ld", n, vpos);
00917                         if (n < TXBSIZE) {
00918                                 BEofseen = 1;
00919                                 break;
00920                         }
00921                 }
00922                 vfile("vpos=%ld", vpos);
00923                 return 0;
00924         }
00925         /* Seek offset > current buffer (crash recovery, etc.) */
00926         if (pos > vpos) {
00927                 if (Canseek)
00928                         if (fseek(fptr, vpos = (pos & ~TXBMASK), 0))
00929                                 return 1;
00930                 while (vpos <= pos) {
00931                         txbuf = Txb + (vpos & TXBMASK);
00932                         m = TXBSIZE - (vpos & TXBMASK);
00933                         n = fread(txbuf, 1, m, fptr);
00934                         vpos += n;
00935                         vfile("bo=%d n=%d vpos=%ld", txbuf-Txb, n, vpos);
00936                         if (m < n) {
00937                                 BEofseen = 1;
00938                                 break;
00939                         }
00940                 }
00941                 return 0;
00942         }
00943         /* Seek offset is within current buffer */
00944         vfile("vpos=%ld", vpos);
00945         return 0;
00946 }
00947 #define fseek fooseek
00948 #endif
00949 
00950 
00951 /* VARARGS1 */
00952 void vfile(f, a, b, c)
00953 register char *f,*a,*b,*c;
00954 {
00955         if (Verbose > 2) {
00956                 fprintf(stderr, f, a, b, c);
00957                 fprintf(stderr, "\n");
00958         }
00959 }
00960 
00961 
00962 void alrm(sig)
00963 int sig;
00964 {
00965         longjmp(tohere, -1);
00966 }
00967 
00968 
00969 #ifndef vax11c
00970 /*
00971  * readline(timeout) reads character(s) from file descriptor 0
00972  * timeout is in tenths of seconds
00973  */
00974 int readline(timeout)
00975 int timeout;
00976 {
00977         register int c;
00978         static char byt[1];
00979 
00980         fflush(stdout);
00981         if (setjmp(tohere)) {
00982                 zperr("TIMEOUT");
00983                 return TIMEOUT;
00984         }
00985         c = timeout/10;
00986         if (c<2)
00987                 c=2;
00988         if (Verbose>5) {
00989                 fprintf(stderr, "Timeout=%d Calling alarm(%d) ", timeout, c);
00990         }
00991         signal(SIGALRM, alrm); alarm(c);
00992         c=read(iofd, byt, 1);
00993         alarm(0);
00994         if (Verbose>5)
00995                 fprintf(stderr, "ret %x\n", byt[0]);
00996         if (c<1)
00997                 return TIMEOUT;
00998         return (byt[0]&0377);
00999 }
01000 
01001 void flushmo()
01002 {
01003         fflush(stdout);
01004 }
01005 
01006 
01007 void purgeline()
01008 {
01009 #ifdef USG
01010         ioctl(iofd, TCFLSH, 0);
01011 #else
01012         lseek(iofd, 0L, 2);
01013 #endif
01014 }
01015 #endif
01016 
01017 /* send cancel string to get the other end to shut up */
01018 void canit()
01019 {
01020         static char canistr[] = {
01021          24,24,24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8,0
01022         };
01023 
01024 #ifdef vax11c
01025         raw_wbuf(strlen(canistr), canistr);
01026         purgeline();
01027 #else
01028         printf(canistr);
01029         fflush(stdout);
01030 #endif
01031 }
01032 
01033 
01034 /*
01035  * Log an error
01036  */
01037 /*VARARGS1*/
01038 void zperr(s,p,u)
01039 char *s, *p, *u;
01040 {
01041         if (Verbose <= 0)
01042                 return;
01043         fprintf(stderr, "\nRetry %d: ", errors);
01044         fprintf(stderr, s, p, u);
01045         fprintf(stderr, "\n");
01046 }
01047 
01048 /*
01049  * substr(string, token) searches for token in string s
01050  * returns pointer to token within string if found, NULL otherwise
01051  */
01052 char *
01053 substr(s, t)
01054 register char *s,*t;
01055 {
01056         register char *ss,*tt;
01057         /* search for first char of token */
01058         for (ss=s; *s; s++)
01059                 if (*s == *t)
01060                         /* compare token with substring */
01061                         for (ss=s,tt=t; ;) {
01062                                 if (*tt == 0)
01063                                         return s;
01064                                 if (*ss++ != *tt++)
01065                                         break;
01066                         }
01067         return (char *)NULL;
01068 }
01069 
01070 char *babble[] = {
01071 #ifdef vax11c
01072         "       Send file(s) with ZMODEM Protocol",
01073         "Usage: sz [-2+abdefkLlNnquvwYy] [-] file ...",
01074         "       sz [-2Ceqv] -c COMMAND",
01075         "       \\ Force next option letter to upper case",
01076 #else
01077         "Send file(s) with ZMODEM/YMODEM/XMODEM Protocol",
01078         "       (Y) = Option applies to YMODEM only",
01079         "       (Z) = Option applies to ZMODEM only",
01080         "Usage: sz [-2+abdefkLlNnquvwYy] [-] file ...",
01081         "       sz [-2Ceqv] -c COMMAND",
01082         "       sb [-2adfkquv] [-] file ...",
01083         "       sx [-2akquv] [-] file",
01084 #endif
01085 #ifdef CSTOPB
01086         "       2 Use 2 stop bits",
01087 #endif
01088         "       + Append to existing destination file (Z)",
01089         "       a (ASCII) change NL to CR/LF",
01090         "       b Binary file transfer override",
01091         "       c send COMMAND (Z)",
01092 #ifndef vax11c
01093         "       d Change '.' to '/' in pathnames (Y/Z)",
01094 #endif
01095         "       e Escape all control characters (Z)",
01096         "       f send Full pathname (Y/Z)",
01097         "       i send COMMAND, ack Immediately (Z)",
01098         "       k Send 1024 byte packets (Y)",
01099         "       L N Limit subpacket length to N bytes (Z)",
01100         "       l N Limit frame length to N bytes (l>=L) (Z)",
01101         "       n send file if source newer (Z)",
01102         "       N send file if source newer or longer (Z)",
01103         "       o Use 16 bit CRC instead of 32 bit CRC (Z)",
01104         "       p Protect existing destination file (Z)",
01105         "       r Resume/Recover interrupted file transfer (Z)",
01106         "       q Quiet (no progress reports)",
01107 #ifndef vax11c
01108         "       u Unlink file after transmission",
01109 #endif
01110         "       v Verbose - provide debugging information",
01111         "       w N Window is N bytes (Z)",
01112         "       Y Yes, overwrite existing file, skip if not present at rx (Z)",
01113         "       y Yes, overwrite existing file (Z)",
01114         "- as pathname sends standard input as sPID.sz or environment ONAME",
01115         ""
01116 };
01117 
01118 int usage()
01119 {
01120         char **pp;
01121 
01122         for (pp=babble; **pp; ++pp)
01123                 fprintf(stderr, "%s\n", *pp);
01124         fprintf(stderr, "%s for %s by Chuck Forsberg, Omen Technology INC\n",
01125          VERSION, OS);
01126         fprintf(stderr, "\t\t\042The High Reliability Software\042\n");
01127         cucheck();
01128         exit(SS_NORMAL);
01129 }
01130 
01131 /*
01132  * Get the receiver's init parameters
01133  */
01134 int getzrxinit()
01135 {
01136         register n;
01137         struct stat f;
01138 
01139         for (n=10; --n>=0; ) {
01140                 
01141                 switch (zgethdr(Rxhdr, 1)) {
01142                 case ZCHALLENGE:        /* Echo receiver's challenge numbr */
01143                         stohdr(Rxpos);
01144                         zshhdr(ZACK, Txhdr);
01145                         continue;
01146                 case ZCOMMAND:          /* They didn't see out ZRQINIT */
01147                         stohdr(0L);
01148                         zshhdr(ZRQINIT, Txhdr);
01149                         continue;
01150                 case ZRINIT:
01151                         Rxflags = 0377 & Rxhdr[ZF0];
01152                         Txfcs32 = (Wantfcs32 && (Rxflags & CANFC32));
01153                         Zctlesc |= Rxflags & TESCCTL;
01154                         Rxbuflen = (0377 & Rxhdr[ZP0])+((0377 & Rxhdr[ZP1])<<8);
01155                         if ( !(Rxflags & CANFDX))
01156                                 Txwindow = 0;
01157                         vfile("Rxbuflen=%d Tframlen=%d", Rxbuflen, Tframlen);
01158                         if ( !Fromcu)
01159                                 signal(SIGINT, SIG_IGN);
01160 #ifdef MODE2OK
01161                         mode(2);        /* Set cbreak, XON/XOFF, etc. */
01162 #endif
01163 #ifndef READCHECK
01164 #ifndef USG
01165                         /* Use 1024 byte frames if no sample/interrupt */
01166                         if (Rxbuflen < 32 || Rxbuflen > 1024) {
01167                                 Rxbuflen = 1024;
01168                                 vfile("Rxbuflen=%d", Rxbuflen);
01169                         }
01170 #endif
01171 #endif
01172                         /* Override to force shorter frame length */
01173                         if (Rxbuflen && (Rxbuflen>Tframlen) && (Tframlen>=32))
01174                                 Rxbuflen = Tframlen;
01175                         if ( !Rxbuflen && (Tframlen>=32) && (Tframlen<=1024))
01176                                 Rxbuflen = Tframlen;
01177                         vfile("Rxbuflen=%d", Rxbuflen);
01178 
01179 #ifndef vax11c
01180                         /* If using a pipe for testing set lower buf len */
01181                         fstat(iofd, &f);
01182                         if ((f.st_mode & S_IFMT) != S_IFCHR) {
01183                                 Rxbuflen = 1024;
01184                         }
01185 #endif
01186 #ifdef BADSEEK
01187                         Canseek = 0;
01188                         Txwindow = TXBSIZE - 1024;
01189                         Txwspac = TXBSIZE/4;
01190 #endif
01191                         /*
01192                          * If input is not a regular file, force ACK's to
01193                          *  prevent running beyond the buffer limits
01194                          */
01195                         if ( !Command) {
01196                                 fstat(fileno(in), &f);
01197                                 if ((f.st_mode & S_IFMT) != S_IFREG) {
01198                                         Canseek = -1;
01199 #ifdef TXBSIZE
01200                                         Txwindow = TXBSIZE - 1024;
01201                                         Txwspac = TXBSIZE/4;
01202 #else
01203                                         return ERROR;
01204 #endif
01205                                 }
01206                         }
01207                         /* Set initial subpacket length */
01208                         if (blklen < 1024) {    /* Command line override? */
01209                                 if (Baudrate > 300)
01210                                         blklen = 256;
01211                                 if (Baudrate > 1200)
01212                                         blklen = 512;
01213                                 if (Baudrate > 2400)
01214                                         blklen = 1024;
01215                         }
01216                         if (Rxbuflen && blklen>Rxbuflen)
01217                                 blklen = Rxbuflen;
01218                         if (blkopt && blklen > blkopt)
01219                                 blklen = blkopt;
01220                         vfile("Rxbuflen=%d blklen=%d", Rxbuflen, blklen);
01221                         vfile("Txwindow = %u Txwspac = %d", Txwindow, Txwspac);
01222 
01223                         return (sendzsinit());
01224                 case ZCAN:
01225                 case TIMEOUT:
01226                         return ERROR;
01227                 case ZRQINIT:
01228                         if (Rxhdr[ZF0] == ZCOMMAND)
01229                                 continue;
01230                 default:
01231                         zshhdr(ZNAK, Txhdr);
01232                         continue;
01233                 }
01234         }
01235         return ERROR;
01236 }
01237 
01238 /* Send send-init information */
01239 int sendzsinit()
01240 {
01241         register c;
01242 
01243         if (Myattn[0] == '\0' && (!Zctlesc || (Rxflags & TESCCTL)))
01244                 return OK;
01245         errors = 0;
01246         for (;;) {
01247                 stohdr(0L);
01248                 if (Zctlesc) {
01249                         Txhdr[ZF0] |= TESCCTL; zshhdr(ZSINIT, Txhdr);
01250                 }
01251                 else
01252                         zsbhdr(ZSINIT, Txhdr);
01253                 zsdata(Myattn, 1+strlen(Myattn), ZCRCW);
01254                 c = zgethdr(Rxhdr, 1);
01255                 switch (c) {
01256                 case ZCAN:
01257                         return ERROR;
01258                 case ZACK:
01259                         return OK;
01260                 default:
01261                         if (++errors > 19)
01262                                 return ERROR;
01263                         continue;
01264                 }
01265         }
01266 }
01267 
01268 /* Send file name and related info */
01269 int zsendfile(buf, blen)
01270 char *buf;
01271 int blen;
01272 {
01273         register c;
01274         register UNSL long crc;
01275 
01276         for (;;) {
01277                 Txhdr[ZF0] = Lzconv;    /* file conversion request */
01278                 Txhdr[ZF1] = Lzmanag;   /* file management request */
01279                 if (Lskipnocor)
01280                         Txhdr[ZF1] |= ZMSKNOLOC;
01281                 Txhdr[ZF2] = Lztrans;   /* file transport request */
01282                 Txhdr[ZF3] = 0;
01283                 zsbhdr(ZFILE, Txhdr);
01284                 zsdata(buf, blen, ZCRCW);
01285 again:
01286                 c = zgethdr(Rxhdr, 1);
01287                 switch (c) {
01288                 case ZRINIT:
01289                         while ((c = readline(50)) > 0)
01290                                 if (c == ZPAD) {
01291                                         goto again;
01292                                 }
01293                         /* **** FALL THRU TO **** */
01294                 default:
01295                         continue;
01296                 case ZCAN:
01297                 case TIMEOUT:
01298                 case ZABORT:
01299                 case ZFIN:
01300                         return ERROR;
01301                 case ZCRC:
01302                         crc = 0xFFFFFFFFL;
01303                         if (Canseek >= 0) {
01304                                 while (((c = getc(in)) != EOF) && --Rxpos)
01305                                         crc = UPDC32(c, crc);
01306                                 crc = ~crc;
01307                                 clearerr(in);   /* Clear EOF */
01308                                 fseek(in, 0L, 0);
01309                         }
01310                         stohdr(crc);
01311                         zsbhdr(ZCRC, Txhdr);
01312                         goto again;
01313                 case ZSKIP:
01314                         fclose(in); return c;
01315                 case ZRPOS:
01316                         /*
01317                          * Suppress zcrcw request otherwise triggered by
01318                          * lastyunc==bytcnt
01319                          */
01320                         if (Rxpos && fseek(in, Rxpos, 0))
01321                                 return ERROR;
01322                         Lastsync = (bytcnt = Txpos = Rxpos) -1;
01323                         return zsendfdata();
01324                 }
01325         }
01326 }
01327 
01328 /* Send the data in the file */
01329 int zsendfdata()
01330 {
01331         register c, e, n;
01332         register int newcnt;
01333         register long tcount = 0;
01334         int junkcount;          /* Counts garbage chars received by TX */
01335         static int tleft = 6;   /* Counter for test mode */
01336 
01337         Lrxpos = 0;
01338         junkcount = 0;
01339         Beenhereb4 = FALSE;
01340 somemore:
01341         if (setjmp(intrjmp)) {
01342 waitack:
01343                 junkcount = 0;
01344                 c = getinsync(0);
01345 gotack:
01346                 switch (c) {
01347                 default:
01348                 case ZCAN:
01349                         fclose(in);
01350                         return ERROR;
01351                 case ZSKIP:
01352                         fclose(in);
01353                         return c;
01354                 case ZACK:
01355                 case ZRPOS:
01356                         break;
01357                 case ZRINIT:
01358                         return OK;
01359                 }
01360 #ifdef READCHECK
01361                 /*
01362                  * If the reverse channel can be tested for data,
01363                  *  this logic may be used to detect error packets
01364                  *  sent by the receiver, in place of setjmp/longjmp
01365                  *  rdchk(fdes) returns non 0 if a character is available
01366                  */
01367                 while (rdchk(iofd)) {
01368 #ifdef SV
01369                         switch (checked)
01370 #else
01371                         switch (readline(1))
01372 #endif
01373                         {
01374                         case CAN:
01375                         case ZPAD:
01376                                 c = getinsync(1);
01377                                 goto gotack;
01378                         case XOFF:              /* Wait a while for an XON */
01379                         case XOFF|0200:
01380                                 readline(100);
01381                         }
01382                 }
01383 #endif
01384         }
01385 
01386         if ( !Fromcu)
01387                 signal(SIGINT, onintr);
01388         newcnt = Rxbuflen;
01389         Txwcnt = 0;
01390         stohdr(Txpos);
01391         zsbhdr(ZDATA, Txhdr);
01392 
01393         /*
01394          * Special testing mode.  This should force receiver to Attn,ZRPOS
01395          *  many times.  Each time the signal should be caught, causing the
01396          *  file to be started over from the beginning.
01397          */
01398         if (Test) {
01399                 if ( --tleft)
01400                         while (tcount < 20000) {
01401                                 printf(qbf); fflush(stdout);
01402                                 tcount += strlen(qbf);
01403 #ifdef READCHECK
01404                                 while (rdchk(iofd)) {
01405 #ifdef SV
01406                                         switch (checked)
01407 #else
01408                                         switch (readline(1))
01409 #endif
01410                                         {
01411                                         case CAN:
01412                                         case ZPAD:
01413 #ifdef TCFLSH
01414                                                 ioctl(iofd, TCFLSH, 1);
01415 #endif
01416                                                 goto waitack;
01417                                         case XOFF:      /* Wait for XON */
01418                                         case XOFF|0200:
01419                                                 readline(100);
01420                                         }
01421                                 }
01422 #endif
01423                         }
01424                 signal(SIGINT, SIG_IGN); canit();
01425                 sleep(3); purgeline(); mode(0);
01426                 printf("\nsz: Tcount = %ld\n", tcount);
01427                 if (tleft) {
01428                         printf("ERROR: Interrupts Not Caught\n");
01429                         exit(1);
01430                 }
01431                 exit(SS_NORMAL);
01432         }
01433 
01434         do {
01435                 n = zfilbuf();
01436                 if (Eofseen)
01437                         e = ZCRCE;
01438                 else if (junkcount > 3)
01439                         e = ZCRCW;
01440                 else if (bytcnt == Lastsync)
01441                         e = ZCRCW;
01442                 else if (Rxbuflen && (newcnt -= n) <= 0)
01443                         e = ZCRCW;
01444                 else if (Txwindow && (Txwcnt += n) >= Txwspac) {
01445                         Txwcnt = 0;  e = ZCRCQ;
01446                 }
01447                 else
01448                         e = ZCRCG;
01449                 if (Verbose>1)
01450                         fprintf(stderr, "\r%7ld ZMODEM%s    ",
01451                           Txpos, Crc32t?" CRC-32":"");
01452                 zsdata(txbuf, n, e);
01453                 bytcnt = Txpos += n;
01454                 if (e == ZCRCW)
01455                         goto waitack;
01456 #ifdef READCHECK
01457                 /*
01458                  * If the reverse channel can be tested for data,
01459                  *  this logic may be used to detect error packets
01460                  *  sent by the receiver, in place of setjmp/longjmp
01461                  *  rdchk(fdes) returns non 0 if a character is available
01462                  */
01463                 fflush(stdout);
01464                 while (rdchk(iofd)) {
01465 #ifdef SV
01466                         switch (checked)
01467 #else
01468                         switch (readline(1))
01469 #endif
01470                         {
01471                         case CAN:
01472                         case ZPAD:
01473                                 c = getinsync(1);
01474                                 if (c == ZACK)
01475                                         break;
01476 #ifdef TCFLSH
01477                                 ioctl(iofd, TCFLSH, 1);
01478 #endif
01479                                 /* zcrce - dinna wanna starta ping-pong game */
01480                                 zsdata(txbuf, 0, ZCRCE);
01481                                 goto gotack;
01482                         case XOFF:              /* Wait a while for an XON */
01483                         case XOFF|0200:
01484                                 readline(100);
01485                         default:
01486                                 ++junkcount;
01487                         }
01488                 }
01489 #endif  /* READCHECK */
01490                 if (Txwindow) {
01491                         while ((tcount = Txpos - Lrxpos) >= Txwindow) {
01492                                 vfile("%ld window >= %u", tcount, Txwindow);
01493                                 if (e != ZCRCQ)
01494                                         zsdata(txbuf, 0, e = ZCRCQ);
01495                                 c = getinsync(1);
01496                                 if (c != ZACK) {
01497 #ifdef TCFLSH
01498                                         ioctl(iofd, TCFLSH, 1);
01499 #endif
01500                                         zsdata(txbuf, 0, ZCRCE);
01501                                         goto gotack;
01502                                 }
01503                         }
01504                         vfile("window = %ld", tcount);
01505                 }
01506         } while (!Eofseen);
01507         if ( !Fromcu)
01508                 signal(SIGINT, SIG_IGN);
01509 
01510         for (;;) {
01511                 stohdr(Txpos);
01512                 zsbhdr(ZEOF, Txhdr);
01513                 switch (getinsync(0)) {
01514                 case ZACK:
01515                         continue;
01516                 case ZRPOS:
01517                         goto somemore;
01518                 case ZRINIT:
01519                         return OK;
01520                 case ZSKIP:
01521                         fclose(in);
01522                         return c;
01523                 default:
01524                         fclose(in);
01525                         return ERROR;
01526                 }
01527         }
01528 }
01529 
01530 /*
01531  * Respond to receiver's complaint, get back in sync with receiver
01532  */
01533 int getinsync(flag)
01534 int flag;
01535 {
01536         register int c;
01537 
01538         for (;;) {
01539                 if (Test) {
01540                         printf("\r\n\n\n***** Signal Caught *****\r\n");
01541                         Rxpos = 0; c = ZRPOS;
01542                 } else
01543                         c = zgethdr(Rxhdr, 0);
01544                 switch (c) {
01545                 case ZCAN:
01546                 case ZABORT:
01547                 case ZFIN:
01548                 case TIMEOUT:
01549                         return ERROR;
01550                 case ZRPOS:
01551                         /* ************************************* */
01552                         /*  If sending to a buffered modem, you  */
01553                         /*   might send a break at this point to */
01554                         /*   dump the modem's buffer.            */
01555                         clearerr(in);   /* In case file EOF seen */
01556                         if (fseek(in, Rxpos, 0))
01557                                 return ERROR;
01558                         Eofseen = 0;
01559                         bytcnt = Lrxpos = Txpos = Rxpos;
01560                         if (Lastsync == Rxpos) {
01561                                 if (++Beenhereb4 > 4)
01562                                         if (blklen > 32)
01563                                                 blklen /= 2;
01564                         }
01565                         Lastsync = Rxpos;
01566                         return c;
01567                 case ZACK:
01568                         Lrxpos = Rxpos;
01569                         if (flag || Txpos == Rxpos)
01570                                 return ZACK;
01571                         continue;
01572                 case ZRINIT:
01573                 case ZSKIP:
01574                         fclose(in);
01575                         return c;
01576                 case ERROR:
01577                 default:
01578                         zsbhdr(ZNAK, Txhdr);
01579                         continue;
01580                 }
01581         }
01582 }
01583 
01584 
01585 /* Say "bibi" to the receiver, try to do it cleanly */
01586 void saybibi()
01587 {
01588         for (;;) {
01589                 stohdr(0L);             /* CAF Was zsbhdr - minor change */
01590                 zshhdr(ZFIN, Txhdr);    /*  to make debugging easier */
01591                 switch (zgethdr(Rxhdr, 0)) {
01592                 case ZFIN:
01593                         sendline('O'); sendline('O'); flushmo();
01594                 case ZCAN:
01595                 case TIMEOUT:
01596                         return;
01597                 }
01598         }
01599 }
01600 
01601 /* Local screen character display function */
01602 void bttyout(c)
01603 int c;
01604 {
01605         if (Verbose)
01606                 putc(c, stderr);
01607 }
01608 
01609 /* Send command and related info */
01610 int zsendcmd(buf, blen)
01611 char *buf;
01612 int blen;
01613 {
01614         register c;
01615         long cmdnum;
01616 
01617         cmdnum = getpid();
01618         errors = 0;
01619         for (;;) {
01620                 stohdr(cmdnum);
01621                 Txhdr[ZF0] = Cmdack1;
01622                 zsbhdr(ZCOMMAND, Txhdr);
01623                 zsdata(buf, blen, ZCRCW);
01624 listen:
01625                 Rxtimeout = 100;                /* Ten second wait for resp. */
01626                 c = zgethdr(Rxhdr, 1);
01627 
01628                 switch (c) {
01629                 case ZRINIT:
01630                         goto listen;    /* CAF 8-21-87 */
01631                 case ERROR:
01632                 case TIMEOUT:
01633                         if (++errors > Cmdtries)
01634                                 return ERROR;
01635                         continue;
01636                 case ZCAN:
01637                 case ZABORT:
01638                 case ZFIN:
01639                 case ZSKIP:
01640                 case ZRPOS:
01641                         return ERROR;
01642                 default:
01643                         if (++errors > 20)
01644                                 return ERROR;
01645                         continue;
01646                 case ZCOMPL:
01647                         Exitcode = Rxpos;
01648                         saybibi();
01649                         return OK;
01650                 case ZRQINIT:
01651 #ifdef vax11c           /* YAMP :== Yet Another Missing Primitive */
01652                         return ERROR;
01653 #else
01654                         vfile("******** RZ *******");
01655                         system("rz");
01656                         vfile("******** SZ *******");
01657                         goto listen;
01658 #endif
01659                 }
01660         }
01661 }
01662 
01663 /*
01664  * If called as sb use YMODEM protocol
01665  */
01666 void chkinvok(s)
01667 char *s;
01668 {
01669 #ifdef vax11c
01670         Progname = "sz";
01671 #else
01672         register char *p;
01673 
01674         p = s;
01675         while (*p == '-')
01676                 s = ++p;
01677         while (*p)
01678                 if (*p++ == '/')
01679                         s = p;
01680         if (*s == 'v') {
01681                 Verbose=1; ++s;
01682         }
01683         Progname = s;
01684         if (s[0]=='s' && s[1]=='b') {
01685                 Nozmodem = TRUE; blklen=1024;
01686         }
01687         if (s[0]=='s' && s[1]=='x') {
01688                 Modem2 = TRUE;
01689         }
01690 #endif
01691 }
01692 
01693 void countem(argc, argv)
01694 int argc;
01695 register char **argv;
01696 {
01697         register c;
01698         struct stat f;
01699 
01700         for (Totalleft = 0, Filesleft = 0; --argc >=0; ++argv) {
01701                 f.st_size = -1;
01702                 if (Verbose>2) {
01703                         fprintf(stderr, "\nCountem: %03d %s ", argc, *argv);
01704                         fflush(stderr);
01705                 }
01706                 if (access(*argv, 04) >= 0 && stat(*argv, &f) >= 0) {
01707                         c = f.st_mode & S_IFMT;
01708                         if (c != S_IFDIR && c != S_IFBLK) {
01709                                 ++Filesleft;  Totalleft += f.st_size;
01710                         }
01711                 }
01712                 if (Verbose>2)
01713                         fprintf(stderr, " %ld", f.st_size);
01714         }
01715         if (Verbose>2)
01716                 fprintf(stderr, "\ncountem: Total %d %ld\n",
01717                   Filesleft, Totalleft);
01718 }
01719 
01720 void chartest(m)
01721 int m;
01722 {
01723         register int n;
01724 
01725         mode(m);
01726         printf("\r\n\nCharacter Transparency Test Mode %d\r\n", m);
01727         printf("If Pro-YAM/ZCOMM is not displaying ^M hit ALT-V NOW.\r\n");
01728         printf("Hit Enter.\021");  fflush(stdout);
01729         readline(500);
01730 
01731         for (n = 0; n < 256; ++n) {
01732                 if (!(n%8))
01733                         printf("\r\n");
01734                 printf("%02x ", n);  fflush(stdout);
01735                 sendline(n);    flushmo();
01736                 printf("  ");  fflush(stdout);
01737                 if (n == 127) {
01738                         printf("Hit Enter.\021");  fflush(stdout);
01739                         readline(500);
01740                         printf("\r\n");  fflush(stdout);
01741                 }
01742         }
01743         printf("\021\r\nEnter Characters, echo is in hex.\r\n");
01744         printf("Hit SPACE or pause 40 seconds for exit.\r\n");
01745 
01746         while (n != TIMEOUT && n != ' ') {
01747                 n = readline(400);
01748                 printf("%02x\r\n", n);
01749                 fflush(stdout);
01750         }
01751         printf("\r\nMode %d character transparency test ends.\r\n", m);
01752         fflush(stdout);
01753 }
01754 
01755 /* End of sz.c */

Generated on Fri Apr 14 22:57:14 2006 for minix by  doxygen 1.4.6