📄 rz.c
字号:
lseek(iofd, 0L, 2);#endif}/* * Update CRC CRC-16 used by XMODEM/CRC, YMODEM, and ZMODEM. * Note: Final result must be masked with 0xFFFF before testing * More efficient table driven routines exist. */unsigned shortupdcrc(c, crc)register c;register unsigned crc;{ register count; for (count=8; --count>=0;) { if (crc & 0x8000) { crc <<= 1; crc += (((c<<=1) & 0400) != 0); crc ^= 0x1021; } else { crc <<= 1; crc += (((c<<=1) & 0400) != 0); } } return crc; }/* * Process incoming file information header */procheader(name)char *name;{ register char *openmode, *p, **pp; /* set default parameters */ openmode = "w"; Thisbinary=Rxbinary; /* * Process ZMODEM remote file management requests */ if (zconv == ZCNL) /* Remote ASCII override */ Thisbinary = 0; if (zconv == ZCBIN) /* Remote Binary override */ ++Thisbinary; else if (zmanag == ZMAPND) openmode = "a"; Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L; p = name + 1 + strlen(name); if (*p) { /* file coming from Unix or DOS system */ sscanf(p, "%ld%lo%o", &Bytesleft, &Modtime, &Filemode); if (Filemode & UNIXFILE) ++Thisbinary; if (Verbose) { fprintf(stderr, "Incoming: %s %ld %lo %o\n", name, Bytesleft, Modtime, Filemode); } } else { /* File coming from CP/M system */ for (p=name; *p; ++p) /* change / to _ */ if ( *p == '/') *p = '_'; if ( *--p == '.') /* zap trailing period */ *p = 0; } /* scan for extensions that signify a binary file */ if (p=substr(name, ".")) for (pp=Extensions; **pp; ++pp) if (strcmp(p, *pp)==0) { Thisbinary=TRUE; break; } /* scan for files which should be appended */ if ( !Thisbinary && (substr(name, ".TXT") || substr(name, ".txt") || substr(name, ".MSG"))) openmode = "a"; if (MakeLCPathname && !IsAnyLower(name)) uncaps(name); if (Topipe) { sprintf(Pathname, "%s %s", Progname+2, name); if (Verbose) fprintf(stderr, "Topipe: %s %s\n", Pathname, Thisbinary?"BIN":"ASCII"); if ((fout=popen(Pathname, "w")) == NULL) return ERROR; } else { strcpy(Pathname, name); if (Verbose) { fprintf(stderr, "Receiving %s %s %s\n", name, Thisbinary?"BIN":"ASCII", openmode); } checkpath(name); if (Nflag) name = "/dev/null"; if ((fout=fopen(name, openmode)) == NULL) return ERROR; } return OK;}/* Make string s lower case */uncaps(s)register char *s;{ for ( ; *s; ++s) if (isupper(*s)) *s = tolower(*s);}/* * IsAnyLower returns TRUE if string s has lower case letters. */IsAnyLower(s)register char *s;{ for ( ; *s; ++s) if (islower(*s)) return TRUE; return FALSE;}/* * Putsec writes the n characters of buf to receive file fout. * If not in binary mode, carriage returns, and all characters * starting with CPMEOF are discarded. */putsec(buf, n)char *buf;register n;{ register char *p; if (Thisbinary) { for (p=buf; --n>=0; ) putc( *p++, fout); } else { if (Eofseen) return OK; for (p=buf; --n>=0; ++p ) { if ( *p == '\r') continue; if (*p == CPMEOF) { Eofseen=TRUE; return OK; } putc(*p ,fout); } } return OK;}/* * Send a character to modem. Small is beautiful. */sendline(c){ char d; d = c; if (Verbose>4) fprintf(stderr, "Sendline: %x\n", c); write(1, &d, 1);}xsendline(c){ sendline(c);}flushmo() {}/* * substr(string, token) searches for token in string s * returns pointer to token within string if found, NULL otherwise */char *substr(s, t)register char *s,*t;{ register char *ss,*tt; /* search for first char of token */ for (ss=s; *s; s++) if (*s == *t) /* compare token with substring */ for (ss=s,tt=t; ;) { if (*tt == 0) return s; if (*ss++ != *tt++) break; } return NULL;}/* * Log an error *//*VARARGS1*/log(s,p,u)char *s, *p, *u;{ if (!Verbose) return; fprintf(stderr, "error %d: ", errors); fprintf(stderr, s, p, u);}/* send cancel string to get the other end to shut up */canit(){ static char canistr[] = { ZPAD,ZPAD,24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8,0 }; printf(canistr); Lleft=0; /* Do read next time ... */ fflush(stdout);}/* * Return 1 iff stdout and stderr are different devices * indicating this program operating with a modem on a * different line */fromcu(){ struct stat a, b; fstat(1, &a); fstat(2, &b); return (a.st_rdev != b.st_rdev);}report(sct)int sct;{ if (Verbose>1) fprintf(stderr,"%03d%c",sct,sct%10? ' ' : '\r');}/* * If called as [-][dir/../]vrzCOMMAND set Verbose to 1 * If called as [-][dir/../]rzCOMMAND set the pipe flag * If called as rb use YMODEM protocol */chkinvok(s)char *s;{ register char *p; p = s; while (*p == '-') s = ++p; while (*p) if (*p++ == '/') s = p; if (*s == 'v') { Verbose=1; ++s; } Progname = s; if (s[0]=='r' && s[1]=='b') Nozmodem = TRUE; if (s[2] && s[0]=='r' && s[1]=='b') Topipe=TRUE; if (s[2] && s[0]=='r' && s[1]=='z') Topipe=TRUE;}/* * Totalitarian Communist pathname processing */checkpath(name)char *name;{ if (Restricted) { if (fopen(name, "r") != NULL) { canit(); fprintf(stderr, "\r\nrz: %s exists\n", name); bibi(); } /* restrict pathnames to current tree or uucppublic */ if ( substr(name, "../") || (name[0]== '/' && strncmp(name, PUBDIR, strlen(PUBDIR))) ) { canit(); fprintf(stderr,"\r\nrz:\tSecurity Violation\r\n"); bibi(); } }}/* * Initialize for Zmodem receive attempt, try to activate Zmodem sender * Handles ZSINIT frame * Return ZFILE if Zmodem filename received, -1 on error, * ZCOMPL if transaction finished, else 0 */tryz(){ register c, n; register cmdzack1flg; if (Nozmodem) /* Check for "rb" program name */ return 0; Rxtimeout = 100; for (n=5; --n>=0; ) { /* Set buffer length (0) and capability flags */ stohdr(0L); Txhdr[ZF0] = CANFDX|CANOVIO|CANBRK; zshhdr(Badclose?ZFERR:ZRINIT, Txhdr);again: switch (zgethdr(Rxhdr, 0)) { case ZRQINIT: continue; case ZEOF: continue; case TIMEOUT: continue; case ZFILE: zconv = Rxhdr[ZF0]; zmanag = Rxhdr[ZF1]; ztrans = Rxhdr[ZF2]; Badclose = FALSE; if (zrbdata(secbuf, KSIZE) == GOTCRCW) return ZFILE; zshhdr(ZNAK, Txhdr); case ZSINIT: if (zrbdata(Attn, ZATTNLEN) == GOTCRCW) { zshhdr(ZACK, Txhdr); goto again; } zshhdr(ZNAK, Txhdr); continue; case ZFREECNT: stohdr(getfree()); zshhdr(ZACK, Txhdr); goto again; case ZCOMMAND: cmdzack1flg = Rxhdr[ZF0]; if (zrbdata(secbuf, KSIZE) == GOTCRCW) { if (cmdzack1flg & ZCACK1) stohdr(0L); else stohdr((long)sys2(secbuf)); purgeline(); /* dump impatient questions */ do { zshhdr(ZCOMPL, Txhdr); } while (++errors<10 && zgethdr(Rxhdr,1) != ZFIN); ackbibi(); if (cmdzack1flg & ZCACK1) exec2(secbuf); return ZCOMPL; } zshhdr(ZNAK, Txhdr); goto again; case ZCOMPL: goto again; default: continue; case ZFIN: ackbibi(); return ZCOMPL; case ZCAN: return ERROR; } } return 0;}/* * Receive 1 or more files with ZMODEM protocol */rzfiles(){ register c; for (;;) { switch (c = rzfile()) { case ZEOF: case ZSKIP: switch (tryz()) { case ZCOMPL: return OK; default: return ERROR; case ZFILE: break; } continue; default: return c; case ERROR: return ERROR; } }}/* * Receive a file with ZMODEM protocol * Assumes file name frame is in secbuf */rzfile(){ register c, n; long rxbytes; Eofseen=FALSE; if (procheader(secbuf) == ERROR) { zshhdr(ZSKIP, Txhdr); return ZSKIP; } n = 10; rxbytes = 0l; for (;;) { stohdr(rxbytes); zshhdr(ZRPOS, Txhdr);nxthdr: switch (c = zgethdr(Rxhdr, 0)) { default: vfile("rzfile: zgethdr returned %d", c); return ERROR; case ZNAK: case TIMEOUT: if ( --n < 0) { vfile("rzfile: zgethdr returned %d", c); return ERROR; } case ZFILE: continue; case ZEOF: if (rclhdr(Rxhdr) != rxbytes) { continue; } if (closeit()) { Badclose = TRUE; vfile("rzfile: closeit returned <> 0"); return ERROR; } vfile("rzfile: normal EOF"); return c; case ERROR: /* Too much garbage in header search error */ if ( --n < 0) { vfile("rzfile: zgethdr returned %d", c); return ERROR; } zmputs(Attn); continue; case ZDATA: n = 10; if (rclhdr(Rxhdr) != rxbytes) { zmputs(Attn); continue; }moredata: switch (c = zrbdata(secbuf, KSIZE)) { case ZCAN: vfile("rzfile: zgethdr returned %d", c); return ERROR; case ERROR: /* CRC error */ if ( --n < 0) { vfile("rzfile: zgethdr returned %d", c); return ERROR; } zmputs(Attn); continue; case TIMEOUT: if ( --n < 0) { vfile("rzfile: zgethdr returned %d", c); return ERROR; } continue; case GOTCRCW: putsec(secbuf, Rxcount); rxbytes += Rxcount; stohdr(rxbytes); zshhdr(ZACK, Txhdr); goto nxthdr; case GOTCRCQ: putsec(secbuf, Rxcount); rxbytes += Rxcount; stohdr(rxbytes); zshhdr(ZACK, Txhdr); goto moredata; case GOTCRCG: putsec(secbuf, Rxcount); rxbytes += Rxcount; goto moredata; case GOTCRCE: putsec(secbuf, Rxcount); rxbytes += Rxcount; goto nxthdr; } } }}/* * Send a string to the modem, processing for \336 (sleep 1 sec) * and \335 (break signal) */zmputs(s)char *s;{ register c; while (*s) { switch (c = *s++) { case '\336': sleep(1); continue; case '\335': sendbrk(); continue; default: sendline(c); } }}/* * Close the receive dataset, return OK or ERROR */closeit(){ if (Topipe) { if (pclose(fout)) { return ERROR; } return OK; } if (fclose(fout)==ERROR) { fprintf(stderr, "file close ERROR\n"); return ERROR; } if (Modtime) { timep[0] = time(NULL); timep[1] = Modtime; utime(Pathname, timep); } if (Filemode) chmod(Pathname, (07777 & Filemode)); return OK;}/* * Ack a ZFIN packet, let byegones be byegones */ackbibi(){ register n; vfile("ackbibi:"); Readnum = 1; stohdr(0L); for (n=4; --n>=0; ) { zshhdr(ZFIN, Txhdr); for (;;) { switch (readline(100)) { case 'O': readline(1); /* Discard 2nd 'O' */ /* ***** FALL THRU TO ***** */ case TIMEOUT: vfile("ackbibi complete"); return; default: break; } } }}/* * Local console output simulation */bttyout(c){ if (Verbose || fromcu) putc(c, stderr);}/* * Strip leading ! if present, do shell escape. */sys2(s)register char *s;{ if (*s == '!') ++s; return system(s);}/* * Strip leading ! if present, do exec. */exec2(s)register char *s;{ if (*s == '!') ++s; mode(0); execl("/bin/sh", "sh", "-c", s);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -