Annotation of researchv10no/cmd/spitbol/cint/rbsb.sh, revision 1.1.1.1

1.1       root        1: #      This is a shell archive.
                      2: #      Remove everything above and including the cut line.
                      3: #      Then run the rest of the file through sh.
                      4: -----cut here-----cut here-----cut here-----cut here-----
                      5: #!/bin/sh
                      6: # shar:        Shell Archiver
                      7: #      Run the following text with /bin/sh to create:
                      8: #      rb.1
                      9: #      rb.c
                     10: #      rbsb.c
                     11: #      sb.1
                     12: #      sb.c
                     13: #      undos.1
                     14: #      undos.c
                     15: # This archive created: Fri Jan 10 12:33:41 1986
                     16: cat << \SHAR_EOF > rb.1
                     17: '\" Revision Level 
                     18: '\" Last Delta     12-16-85
                     19: .TH RB 1 OMEN
                     20: .SH NAME
                     21: rb \- YMODEM batch file receive
                     22: .SH SYNOPSIS
                     23: .B rb
                     24: [
                     25: .B \-bquv
                     26: ]
                     27: .PP
                     28: .B rb
                     29: [
                     30: .B \-bcquv
                     31: ]
                     32: .B file
                     33: .PP
                     34: .B [-][v]rbCOMMAND
                     35: .SH DESCRIPTION
                     36: .B Rb
                     37: receives 0 or more files in batch mode.
                     38: Iff
                     39: .B file
                     40: is speficied,
                     41: a single file is received in XMODEM single file mode.
                     42: 
                     43: Normally, the file contents are converted to
                     44: .SM Unix
                     45: conventions by stripping carriage returns and all characters
                     46: beginning with Control Z (CP/M end of file).
                     47: If the raw pathname ends in
                     48: ".A",
                     49: ".ARC",
                     50: ".CCC",
                     51: ".CL",
                     52: ".CMD",
                     53: ".COM",
                     54: ".CRL",
                     55: ".DAT",
                     56: ".DIR",
                     57: ".EXE",
                     58: ".O",
                     59: ".OBJ",
                     60: ".OVL",
                     61: ".PAG",
                     62: ".REL",
                     63: ".SAV",
                     64: ".SUB",
                     65: ".SWP",
                     66: ".SYS",
                     67: ".TAR",
                     68: ".UTL",
                     69: ".a",
                     70: ".o",
                     71: ".tar",
                     72: or if the first sector contains
                     73: data that suggest a binary file
                     74: (parity bits or characters in the range 000 to 006 before the first ^Z),
                     75: or if the file mode is transmitted and the 0100000 bit is set,
                     76: that file will be received in binary mode anyway.
                     77: 
                     78: Otherwise,
                     79: if the raw pathname ends in .MSG, or .TXT, any existing file will
                     80: be appended to rather than replaced.
                     81: 
                     82: Normally, each file name is converted to lower case
                     83: unless it contains one or more lower case letters.
                     84: 
                     85: Rb works with either standard 128 byte sectors or
                     86: 1024 byte sectors
                     87: (YAM
                     88: .B k
                     89: option).
                     90: The user should determine experimentally
                     91: the conditions under which use of 1k blocks
                     92: actually improves throughput without causing
                     93: problems.
                     94: 
                     95: If extended file information (file length, etc.)
                     96: is received,
                     97: the file length controls the number of bytes written to
                     98: the output dataset,
                     99: and the modify time and file mode
                    100: (iff non zero)
                    101: are set accordingly.
                    102: 
                    103: If no extended file information is received,
                    104: slashes in the pathname are changed to underscore,
                    105: and any trailing period in the pathname is eliminated.
                    106: 
                    107: If rb is invoked with stdout and stderr to different datasets,
                    108: Verbose is set to 2, causing frame by frame progress reports
                    109: to stderr.
                    110: This may be disabled with the
                    111: .B q
                    112: option.
                    113: 
                    114: If the SHELL environment variable includes
                    115: .I "rsh"
                    116: or
                    117: .I "rksh"
                    118: (restricted shell),
                    119: rb will not accept pathnames containing referenced to absolute paths
                    120: or to a parent directory, will not receive to an existing file, and
                    121: removes any files received in error.
                    122: 
                    123: .PP
                    124: The meanings of the available options are:
                    125: .PP
                    126: .PD 0
                    127: .TP
                    128: .B b
                    129: transfer all files in binary
                    130: (tell it like it is)
                    131: mode.
                    132: This option disables any append mode special processing.
                    133: .TP
                    134: .B c
                    135: Request 16 bit cyclic redundancy check
                    136: (8 bit checksum default).
                    137: .TP
                    138: .B q
                    139: Quiet suppresses verbosity.
                    140: .TP
                    141: .B v
                    142: .IR Verbose
                    143: causes a list of file
                    144: names to be appended to
                    145: /tmp/rblog .
                    146: More v's generate more output.
                    147: .TP
                    148: .B u
                    149: Retain upper case letters in file names unconditionally.
                    150: .PD
                    151: .SH EXAMPLES
                    152: (
                    153: .SM Unix
                    154: command)
                    155: .RS
                    156: $rb
                    157: .br
                    158: rb: ready C
                    159: .br
                    160: .RE
                    161: (Pro-YAM command)
                    162: .RS
                    163: <F1>
                    164: .br
                    165: >>>c: sbt *.h *.c
                    166: .br
                    167: .RE
                    168: .SH SEE ALSO
                    169: YMODEM.DOC,
                    170: IMP(CP/M),
                    171: ncu(1),
                    172: Professional-YAM manual,
                    173: sb(omen),
                    174: usq(omen),
                    175: undos(omen)
                    176: 
                    177: Compile time options for various operating systems are described in the
                    178: program source file.
                    179: .SH NOTES
                    180: If rb is invoked as
                    181: .B rbCOMMAND
                    182: (with an optional leading \- as generated by login(1)),
                    183: rb will pipe each received file to ``COMMAND filename''
                    184: (filename is the name of the transmitted file)
                    185: with the file contents as standard input.
                    186: A typical usage for this form is rbrmail which calls rmail
                    187: to post mail.
                    188: On some
                    189: .SM Unix
                    190: systems, the login directory must contain
                    191: COMMAND as login sets SHELL=rsh which disallows absolute
                    192: pathnames.
                    193: If invoked with a leading ``v'' rb will report progress to LOGFILE.
                    194: The following entry works for
                    195: .SM Unix
                    196: 3.0.
                    197:        rbrmail::5:1::/bin:/usr/local/rbrmail
                    198: .PP
                    199: The following (in a shell script)
                    200: may be used to fetch file(s) from a remote computer connected to /dev/tty7
                    201: once sb has been started on the remote.
                    202:        rb -v >/dev/tty7 </dev/tty7
                    203: .SH BUGS
                    204: Pathnames are restricted to 127 characters.
                    205: 
                    206: In XMODEM single file mode, the pathname given on the command line
                    207: is still processed as described above.
                    208: 
                    209: The CR/LF to NL translation merely deletes CR\'s;
                    210: undos(omen) performs a more intelligent translation.
                    211: .SH "VMS VERSION"
                    212: Some of the #includes with file names enclosed with angle brackets <>
                    213: may need to have the angle brackets removed, or vice versa.
                    214: 
                    215: The VMS version does not set binary mode according to the incoming
                    216: file type.
                    217: Non binary file processing consists of stripping all characters beginning
                    218: with CPMEOF (^Z).
                    219: 
                    220: The VMS version does not set the file time.
                    221: 
                    222: VMS occaisonally loses incoming characters, resulting in retries
                    223: and degradation of throughput.
                    224: 
                    225: There may be unknown interactions between the VMS C standard i/o
                    226: package and RMS.
                    227: 
                    228: The VMS version does not support invocation as
                    229: .B rbCOMMAND .
                    230: SHAR_EOF
                    231: cat << \SHAR_EOF > rb.c
                    232: #define VERSION "2.17 12-07-85"
                    233: #define PUBDIR "/usr/spool/uucppublic"
                    234: 
                    235: /*% cc -DUSG -DNFGVMIN -O -K % -o rb
                    236:  *
                    237:  * rb.c By Chuck Forsberg
                    238:  *
                    239:  *  USG UNIX (3.0) ioctl conventions courtesy  Jeff Martin
                    240:  *     cc -O -DV7  rb.c -o rb          Unix V7, BSD 2.8 - 4.2
                    241:  *     cc -O -DUSG rb.c -o rb          USG (3.0) Unix
                    242:  *     cc -o rb.c                      Regulus
                    243:  *             (Don't try this on Unix, you'll clobber the source!)
                    244:  *  Unix is a trademark of Western Electric Company
                    245:  *
                    246:  *  Regulus conventions 1-10-83 CAF
                    247:  *
                    248:  *  Some systems (Venix, Coherent, Regulus) do not support tty raw mode
                    249:  *  read(2) the same way as Unix. ONEREAD must be defined to force one
                    250:  *  character reads for these systems. Added 7-01-84 CAF
                    251:  *
                    252:  *  Alarm signal handling changed to work with 4.2 BSD 7-15-84 CAF 
                    253:  *
                    254:  *  NFGVMIN Added 1-13-85 CAF for PC-AT Xenix systems where c_cc[VMIN]
                    255:  *  doesn't seem to work (even though it compiles without error!).
                    256:  *
                    257:  * A program for Unix which can receive
                    258:  *  files from computers running YAM or MODEM.
                    259:  *  rb uses Unix System III buffered input to reduce CPU time.
                    260:  *  If no filename is given, YAM batch mode is assumed.
                    261:  *
                    262:  * Iff the program is invoked by rbCOMMAND, output is piped to 
                    263:  * "COMMAND filename"
                    264:  *
                    265:  *  Supports the CRC option or regular checksum.
                    266:  *  Received pathnames containing no lowercase letters will be changed to lower
                    267:  *  case unless -u option is given.
                    268:  *
                    269:  *  Unless the -b (binary) option is given, \r is discarded and
                    270:  *  ^Z (which is also discarded) acts as end of file.
                    271:  *
                    272:  *  Any slashes in the pathname are changed to underscore.
                    273:  *  If the raw pathname ends in .MSG or .TXT, any existing file will
                    274:  *  be appended to rather than replaced. Trailing periods are eliminated.
                    275:  *
                    276:  *  If the raw pathname ends in any of the extensions in Extensions,
                    277:  *   or .?Q* (squeezed file), or if the first sector contains binary-like
                    278:  *   data (parity bits or characters in the range 0 to 6 before ^Z is seen),
                    279:  *   or if the transmitted file mode has the 0100000 but set,
                    280:  *   that file will be received in binary mode anyway.
                    281:  *
                    282:  *
                    283:  * A log of activities is appended to LOGFILE with the -v option
                    284:  * If stdout and stderr refer to different devices, progress is displayed to
                    285:  * stderr.
                    286:  *
                    287:  * rb is derived from yam2.c and sb.c
                    288:  */
                    289: #define LOGFILE "/tmp/rblog"
                    290: 
                    291: #include <stdio.h>
                    292: #include <signal.h>
                    293: #include <setjmp.h>
                    294: #include <ctype.h>
                    295: FILE *popen();
                    296: 
                    297: #define OK 0
                    298: #define FALSE 0
                    299: #define TRUE 1
                    300: #define ERROR (-1)
                    301: 
                    302: #define HOWMANY 133
                    303: #include "rbsb.c"      /* most of the system dependent stuff here */
                    304: 
                    305: char *substr();
                    306: FILE *fout;
                    307: 
                    308: char *Extensions[] = {
                    309: ".A",
                    310: ".ARC",
                    311: ".CCC",
                    312: ".CL",
                    313: ".CMD",
                    314: ".COM",
                    315: ".CRL",
                    316: ".DAT",
                    317: ".DIR",
                    318: ".EXE",
                    319: ".O",
                    320: ".OBJ",
                    321: ".OVL",
                    322: ".PAG",
                    323: ".REL",
                    324: ".SAV",
                    325: ".SUB",
                    326: ".SWP",
                    327: ".SYS",
                    328: ".TAR",
                    329: ".UTL",
                    330: ".a",
                    331: ".o",
                    332: ".tar",
                    333: ""
                    334: };
                    335: 
                    336: /* Ward Christensen / CP/M parameters - Don't change these! */
                    337: #define ENQ 005
                    338: #define CAN ('X'&037)
                    339: #define XOFF ('s'&037)
                    340: #define XON ('q'&037)
                    341: #define SOH 1
                    342: #define STX 2
                    343: #define EOT 4
                    344: #define ACK 6
                    345: #define NAK 025
                    346: #define CPMEOF 032
                    347: #define WANTCRC 0103   /* send C not NAK to get crc not checksum */
                    348: #define TIMEOUT (-2)
                    349: #define ERRORMAX 5
                    350: #define RETRYMAX 5
                    351: #define WCEOT (-10)
                    352: #define SECSIZ 128     /* cp/m's Magic Number record size */
                    353: #define PATHLEN 257    /* ready for 4.2 bsd ? */
                    354: #define KSIZE 1024     /* record size with k option */
                    355: #define UNIXFILE 0x8000        /* happens to the the S_IFREG file mask bit for stat */
                    356: 
                    357: int Lastrx;
                    358: int Crcflg;
                    359: int Firstsec;
                    360: int Eofseen;           /* indicates cpm eof (^Z) has been received */
                    361: int totblocks;         /* total number of blocks received */
                    362: int errors;
                    363: int Restricted=0;      /* restricted; no /.. or ../ in filenames */
                    364: 
                    365: #define DEFBYTL 2000000000L    /* default rx file size */
                    366: long Bytesleft;                /* number of bytes of incoming file left */
                    367: long Modtime;          /* Unix style mod time for incoming file */
                    368: short Filemode;                /* Unix style mode for incoming file */
                    369: char Pathname[PATHLEN];
                    370: char *Progname;                /* the name by which we were called */
                    371: 
                    372: int Batch=0;
                    373: int Wcsmask=0377;
                    374: int Topipe=0;
                    375: int MakeLCPathname=TRUE;       /* make received pathname lower case */
                    376: int Verbose=0;
                    377: int Quiet=0;           /* overrides logic that would otherwise set verbose */
                    378: int Rxbinary=FALSE;    /* receive all files in bin mode */
                    379: int Thisbinary;                /* current file is to be received in bin mode */
                    380: int Blklen;            /* record length of received packets */
                    381: char secbuf[KSIZE];
                    382: char linbuf[KSIZE];
                    383: int Lleft=0;           /* number of characters in linbuf */
                    384: 
                    385: jmp_buf tohere;                /* For the interrupt on RX timeout */
                    386: 
                    387: unsigned short updcrc();
                    388: 
                    389: alrm()
                    390: {
                    391:        longjmp(tohere, -1);
                    392: }
                    393: 
                    394: /* called by signal interrupt or terminate to clean things up */
                    395: bibi(n)
                    396: {
                    397:        canit(); mode(0);
                    398:        fprintf(stderr, "sb: caught signal %d; exiting", n);
                    399:        exit(128+n);
                    400: }
                    401: 
                    402: main(argc, argv)
                    403: char *argv[];
                    404: {
                    405:        register char *cp;
                    406:        register npats;
                    407:        char *virgin, **patts;
                    408:        char *getenv();
                    409:        int exitcode;
                    410: 
                    411:        setbuf(stderr, NULL);
                    412:        if ((cp=getenv("SHELL")) && (substr(cp, "rsh") || substr(cp, "rsh")))
                    413:                Restricted=TRUE;
                    414: 
                    415:        chkinvok(virgin=argv[0]);       /* if called as [-]rbCOMMAND set flag */
                    416:        npats = 0;
                    417:        while (--argc) {
                    418:                cp = *++argv;
                    419:                if (*cp == '-') {
                    420:                        while( *++cp) {
                    421:                                switch(*cp) {
                    422:                                case '1':
                    423:                                        iofd = 1; break;
                    424:                                case '7':
                    425:                                        Wcsmask = 0177;
                    426:                                case 'b':
                    427:                                        Rxbinary=TRUE; break;
                    428:                                case 'k':
                    429:                                case 'c':
                    430:                                        Crcflg=TRUE; break;
                    431:                                case 'q':
                    432:                                        Quiet=TRUE; Verbose=0; break;
                    433:                                case 'u':
                    434:                                        MakeLCPathname=FALSE; break;
                    435:                                case 'v':
                    436:                                        ++Verbose; break;
                    437:                                default:
                    438:                                        usage();
                    439:                                }
                    440:                        }
                    441:                }
                    442:                else if ( !npats && argc>0) {
                    443:                        if (argv[0][0]) {
                    444:                                npats=argc;
                    445:                                patts=argv;
                    446:                        }
                    447:                }
                    448:        }
                    449:        if (npats > 1)
                    450:                usage();
                    451:        if (Verbose) {
                    452:                if (freopen(LOGFILE, "a", stderr)==NULL) {
                    453:                        printf("Can't open log file %s\n",LOGFILE);
                    454:                        exit(0200);
                    455:                }
                    456:                setbuf(stderr, NULL);
                    457:                fprintf(stderr, "argv[0]=%s Progname=%s\n", virgin, Progname);
                    458:        }
                    459:        if (fromcu() && !Quiet) {
                    460:                if (Verbose == 0)
                    461:                        Verbose = 2;
                    462:        }
                    463:        mode(1);
                    464:        if (signal(SIGINT, bibi) == SIG_IGN) {
                    465:                signal(SIGINT, SIG_IGN); signal(SIGKILL, SIG_IGN);
                    466:        }
                    467:        else {
                    468:                signal(SIGINT, bibi); signal(SIGKILL, bibi);
                    469:        }
                    470:        if (wcreceive(npats, patts)==ERROR) {
                    471:                exitcode=0200;
                    472:                canit();
                    473:        }
                    474:        mode(0);
                    475:        if (exitcode != 0)      /* bellow again with all thy might. */
                    476:                canit();
                    477: #ifdef REGULUS
                    478:        else
                    479:                printf("\6\6\6\6\6\n"); /* Regulus doesn't wait ... */
                    480: #endif
                    481:        exit(exitcode);
                    482: }
                    483: 
                    484: 
                    485: usage()
                    486: {
                    487:        fprintf(stderr,"%s %s by Chuck Forsberg\n", Progname, VERSION);
                    488:        fprintf(stderr,"Usage:  rb [-17buv]\n\tor rb [-1bcuv] file\n");
                    489:        exit(1);
                    490: }
                    491: 
                    492: wcreceive(argc, argp)
                    493: char **argp;
                    494: {
                    495:        if (Batch || argc==0) {
                    496:                Crcflg=(Wcsmask==0377);
                    497:                fprintf(stderr, "rb: ready ");
                    498:                for (;;) {
                    499:                        totblocks=0;
                    500:                        if (wcrxpn(secbuf)== ERROR)
                    501:                                goto fubar;
                    502:                        if (secbuf[0]==0)
                    503:                                return OK;
                    504:                        if (procheader(secbuf) == ERROR)
                    505:                                goto fubar;
                    506:                        if (wcrx()==ERROR)
                    507:                                goto fubar;
                    508:                }
                    509:        } else {
                    510:                totblocks=0; Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
                    511: 
                    512:                strcpy(Pathname, *argp);
                    513:                checkpath(Pathname);
                    514:                fprintf(stderr, "\nrb: ready to receive %s ", Pathname);
                    515:                if ((fout=fopen(Pathname, "w")) == NULL)
                    516:                        return ERROR;
                    517:                if (wcrx()==ERROR)
                    518:                        goto fubar;
                    519:        }
                    520:        return OK;
                    521: fubar:
                    522:        canit();
                    523:        if (Topipe && fout) {
                    524:                pclose(fout);  return ERROR;
                    525:        }
                    526:        if (fout)
                    527:                fclose(fout);
                    528:        if (Restricted) {
                    529:                unlink(Pathname);
                    530:                fprintf(stderr, "\r\nrb: %s removed.\r\n", Pathname);
                    531:        }
                    532:        return ERROR;
                    533: }
                    534: 
                    535: 
                    536: /*
                    537:  * Fetch a pathname from the other end as a C ctyle ASCIZ string.
                    538:  * Length is indeterminate as long as less than Blklen
                    539:  * a null string represents no more files
                    540:  */
                    541: wcrxpn(rpn)
                    542: char *rpn;     /* receive a pathname */
                    543: {
                    544:        register c;
                    545: 
                    546: #ifdef NFGVMIN
                    547:        readline(1);
                    548: #else
                    549:        purgeline();
                    550: #endif
                    551: 
                    552: et_tu:
                    553:        Firstsec=TRUE;
                    554:        sendline(Crcflg?WANTCRC:NAK);
                    555:        while ((c = wcgetsec(rpn, 100)) != 0) {
                    556:                log( "Pathname fetch returned %d\n", c);
                    557:                if (c == WCEOT) {
                    558:                        sendline(ACK); readline(1); goto et_tu;
                    559:                }
                    560:                return ERROR;
                    561:        }
                    562:        sendline(ACK);
                    563:        return OK;
                    564: }
                    565: 
                    566: /*
                    567:  * Adapted from CMODEM13.C, written by
                    568:  * Jack M. Wierda and Roderick W. Hart
                    569:  */
                    570: 
                    571: wcrx()
                    572: {
                    573:        register int sectnum, sectcurr;
                    574:        register char sendchar;
                    575:        register char *p;
                    576:        int cblklen;                    /* bytes to dump this block */
                    577:        time_t timep[2];
                    578: 
                    579:        Firstsec=TRUE;sectnum=0; Eofseen=FALSE;
                    580:        sendchar=Crcflg?WANTCRC:NAK;
                    581: 
                    582:        for (;;) {
                    583:                sendline(sendchar);     /* send it now, we're ready! */
                    584:                sectcurr=wcgetsec(secbuf, (sectnum&0177)?50:130);
                    585:                report(sectcurr);
                    586:                if (sectcurr==(sectnum+1 &Wcsmask)) {
                    587: 
                    588:                        if (sectnum==0 && !Thisbinary)
                    589:                                for (p=secbuf,sectcurr=Blklen;
                    590:                                  *p != 032 && --sectcurr>=0; ++p)
                    591:                                        if (*p < 07 || (*p & 0200)) {
                    592:                                                Thisbinary++;
                    593:                                                if (Verbose)
                    594:                                                        fprintf(stderr, "Changed to BIN\n");
                    595:                                                break;
                    596:                                        }
                    597:                        sectnum++;
                    598:                        cblklen = Bytesleft>Blklen ? Blklen:Bytesleft;
                    599:                        if (putsec(secbuf, cblklen)==ERROR)
                    600:                                return ERROR;
                    601:                        if ((Bytesleft-=cblklen) < 0)
                    602:                                Bytesleft = 0;
                    603:                        sendchar=ACK;
                    604:                }
                    605:                else if (sectcurr==(sectnum&Wcsmask)) {
                    606:                        log( "Received dup Sector\n");
                    607:                        sendchar=ACK;
                    608:                }
                    609:                else if (sectcurr==WCEOT) {
                    610:                        if (Topipe) {
                    611:                                if (pclose(fout)!=ERROR) {
                    612:                                        sendline(ACK);
                    613:                                        return OK;
                    614:                                }
                    615:                                canit(); return ERROR;
                    616:                        }
                    617:                        if (fclose(fout)==ERROR) {
                    618:                                canit();
                    619:                                fprintf(stderr, "file close ERROR\n");
                    620:                                return ERROR;
                    621:                        }
                    622:                        if (Modtime) {
                    623:                                timep[0] = time(NULL);
                    624:                                timep[1] = Modtime;
                    625:                                utime(Pathname, timep);
                    626:                        }
                    627:                        if (Filemode)
                    628:                                chmod(Pathname, (07777 & Filemode));
                    629:                        sendline(ACK);
                    630:                        return OK;
                    631:                }
                    632:                else if (sectcurr==ERROR)
                    633:                        return ERROR;
                    634:                else {
                    635:                        log( "Sync Error\n");
                    636:                        return ERROR;
                    637:                }
                    638:        }
                    639: }
                    640: 
                    641: /*
                    642:  * wcgetsec fetches a Ward Christensen type sector.
                    643:  * Returns sector number encountered or ERROR if valid sector not received,
                    644:  * or CAN CAN received
                    645:  * or WCEOT if eot sector
                    646:  * time is timeout for first char, set to 4 seconds thereafter
                    647:  ***************** NO ACK IS SENT IF SECTOR IS RECEIVED OK **************
                    648:  *    (Caller must do that when he is good and ready to get next sector)
                    649:  */
                    650: 
                    651: wcgetsec(rxbuf, maxtime)
                    652: char *rxbuf;
                    653: int maxtime;
                    654: {
                    655:        register checksum, wcj, firstch;
                    656:        register unsigned short oldcrc;
                    657:        register char *p;
                    658:        int sectcurr;
                    659: 
                    660:        for (Lastrx=errors=0; errors<RETRYMAX; errors++) {
                    661: 
                    662:                if ((firstch=readline(maxtime))==STX) {
                    663:                        Blklen=KSIZE; goto get2;
                    664:                }
                    665:                if (firstch==SOH) {
                    666:                        Blklen=SECSIZ;
                    667: get2:
                    668:                        sectcurr=readline(1);
                    669:                        if ((sectcurr+(oldcrc=readline(1)))==Wcsmask) {
                    670:                                oldcrc=checksum=0;
                    671:                                for (p=rxbuf,wcj=Blklen; --wcj>=0; ) {
                    672:                                        if ((firstch=readline(1)) < 0)
                    673:                                                goto bilge;
                    674:                                        oldcrc=updcrc(firstch, oldcrc);
                    675:                                        checksum += (*p++ = firstch);
                    676:                                }
                    677:                                if ((firstch=readline(1)) < 0)
                    678:                                        goto bilge;
                    679:                                if (Crcflg) {
                    680:                                        oldcrc=updcrc(firstch, oldcrc);
                    681:                                        if ((firstch=readline(1)) < 0)
                    682:                                                goto bilge;
                    683:                                        oldcrc=updcrc(firstch, oldcrc);
                    684:                                        if (oldcrc)
                    685:                                                log("CRC=0%o\n", oldcrc);
                    686:                                        else {
                    687:                                                Firstsec=FALSE;
                    688:                                                return sectcurr;
                    689:                                        }
                    690:                                }
                    691:                                else if (((checksum-firstch)&Wcsmask)==0) {
                    692:                                        Firstsec=FALSE;
                    693:                                        return sectcurr;
                    694:                                }
                    695:                                else
                    696:                                        log( "Checksum Error\n");
                    697:                        }
                    698:                        else
                    699:                                log("Sector number garbled 0%o 0%o\n",
                    700:                                 sectcurr, oldcrc);
                    701:                }
                    702:                /* make sure eot really is eot and not just mixmash */
                    703: #ifdef NFGVMIN
                    704:                else if (firstch==EOT && readline(1)==TIMEOUT)
                    705:                        return WCEOT;
                    706: #else
                    707:                else if (firstch==EOT && Lleft==0)
                    708:                        return WCEOT;
                    709: #endif
                    710:                else if (firstch==CAN) {
                    711:                        if (Lastrx==CAN) {
                    712:                                log( "Sender CANcelled\n");
                    713:                                return ERROR;
                    714:                        } else {
                    715:                                Lastrx=CAN;
                    716:                                continue;
                    717:                        }
                    718:                }
                    719:                else if (firstch==TIMEOUT) {
                    720:                        if (Firstsec)
                    721:                                goto humbug;
                    722: bilge:
                    723:                        log( "Timeout\n");
                    724:                }
                    725:                else
                    726:                        log( "Got 0%o sector header\n", firstch);
                    727: 
                    728: humbug:
                    729:                Lastrx=0;
                    730:                while(readline(1)!=TIMEOUT)
                    731:                        ;
                    732:                if (Firstsec)
                    733:                        sendline(Crcflg?WANTCRC:NAK);
                    734:                else {
                    735:                        maxtime=40; sendline(NAK);
                    736:                }
                    737:        }
                    738:        /* try to stop the bubble machine. */
                    739:        canit();
                    740:        return ERROR;
                    741: }
                    742: 
                    743: /*
                    744:  * This version of readline is reasoably well suited for
                    745:  * reading many characters.
                    746:  *  (except, currently, for the Regulus version!)
                    747:  *
                    748:  * timeout is in tenths of seconds
                    749:  */
                    750: readline(timeout)
                    751: int timeout;
                    752: {
                    753:        register n;
                    754:        static char *cdq;       /* pointer for removing chars from linbuf */
                    755: 
                    756:        if (--Lleft >= 0) {
                    757:                if (Verbose > 8) {
                    758:                        fprintf(stderr, "%02x ", *cdq&0377);
                    759:                }
                    760:                return (*cdq++ & Wcsmask);
                    761:        }
                    762:        n = timeout/10;
                    763:        if (n < 2)
                    764:                n = 3;
                    765:        if (Verbose > 3)
                    766:                fprintf(stderr, "Calling read: n=%d ", n);
                    767:        if (setjmp(tohere)) {
                    768: #ifdef TIOCFLUSH
                    769: /*             ioctl(iofd, TIOCFLUSH, 0); */
                    770: #endif
                    771:                Lleft = 0;
                    772:                if (Verbose>1)
                    773:                        fprintf(stderr, "Readline:TIMEOUT\n");
                    774:                return TIMEOUT;
                    775:        }
                    776:        signal(SIGALRM, alrm); alarm(n);
                    777: #ifdef ONEREAD
                    778:        /* Sorry, Regulus and some others don't work right in raw mode! */
                    779:        Lleft=read(iofd, cdq=linbuf, 1);
                    780: #else
                    781:        Lleft=read(iofd, cdq=linbuf, KSIZE);
                    782: #endif
                    783:        alarm(0);
                    784:        if (Verbose > 3) {
                    785:                fprintf(stderr, "Read returned %d bytes\n", Lleft);
                    786:        }
                    787:        if (Lleft < 1)
                    788:                return TIMEOUT;
                    789:        --Lleft;
                    790:        if (Verbose > 8) {
                    791:                fprintf(stderr, "%02x ", *cdq&0377);
                    792:        }
                    793:        return (*cdq++ & Wcsmask);
                    794: }
                    795: 
                    796: 
                    797: 
                    798: 
                    799: purgeline()
                    800: {
                    801:        Lleft = 0;
                    802: #ifdef USG
                    803:        ioctl(iofd, TCFLSH, 0);
                    804: #else
                    805:        lseek(iofd, 0L, 2);
                    806: #endif
                    807: }
                    808: 
                    809: /* update CRC */
                    810: unsigned short
                    811: updcrc(c, crc)
                    812: register c;
                    813: register unsigned crc;
                    814: {
                    815:        register count;
                    816: 
                    817:        for (count=8; --count>=0;) {
                    818:                if (crc & 0x8000) {
                    819:                        crc <<= 1;
                    820:                        crc += (((c<<=1) & 0400)  !=  0);
                    821:                        crc ^= 0x1021;
                    822:                }
                    823:                else {
                    824:                        crc <<= 1;
                    825:                        crc += (((c<<=1) & 0400)  !=  0);
                    826:                }
                    827:        }
                    828:        return crc;     
                    829: }
                    830: 
                    831: /*
                    832:  * process incoming header
                    833:  */
                    834: procheader(name)
                    835: char *name;
                    836: {
                    837:        register char *openmode, *p, **pp;
                    838: 
                    839:        /* set default parameters */
                    840:        openmode = "w"; Thisbinary=Rxbinary;
                    841:        Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
                    842: 
                    843:        p = name + 1 + strlen(name);
                    844:        if (*p) {       /* file coming from Unix or DOS system */
                    845:                sscanf(p, "%ld%lo%o", &Bytesleft, &Modtime, &Filemode);
                    846:                if (Filemode & UNIXFILE)
                    847:                        ++Thisbinary;
                    848:                if (Verbose) {
                    849:                        fprintf(stderr,  "Incoming: %s %ld %lo %o\n",
                    850:                          name, Bytesleft, Modtime, Filemode);
                    851:                }
                    852:        }
                    853:        else {          /* File coming from CP/M system */
                    854:                for (p=name; *p; ++p)           /* change / to _ */
                    855:                        if ( *p == '/')
                    856:                                *p = '_';
                    857: 
                    858:                if ( *--p == '.')               /* zap trailing period */
                    859:                        *p = 0;
                    860:        }
                    861: 
                    862:        /* scan for extensions that signify a binary file */
                    863:        if (p=substr(name, "."))
                    864:                for (pp=Extensions; **pp; ++pp)
                    865:                        if (strcmp(p, *pp)==0) {
                    866:                                Thisbinary=TRUE; break;
                    867:                        }
                    868: 
                    869:        /* scan for files which should be appended */
                    870:        if ( !Thisbinary
                    871:          && (substr(name, ".TXT")
                    872:          || substr(name, ".txt")
                    873:          || substr(name, ".MSG")))
                    874:                openmode = "a";
                    875:        if (MakeLCPathname && !IsAnyLower(name))
                    876:                uncaps(name);
                    877:        if (Topipe) {
                    878:                sprintf(Pathname, "%s %s", Progname+2, name);
                    879:                if (Verbose)
                    880:                        fprintf(stderr,  "Topipe: %s %s\n",
                    881:                          Pathname, Thisbinary?"BIN":"ASCII");
                    882:                if ((fout=popen(Pathname, "w")) == NULL)
                    883:                        return ERROR;
                    884:        } else {
                    885:                strcpy(Pathname, name);
                    886:                if (Verbose) {
                    887:                        fprintf(stderr,  "Receiving %s %s %s\n",
                    888:                          name, Thisbinary?"BIN":"ASCII", openmode);
                    889:                }
                    890:                checkpath(name);
                    891:                if ((fout=fopen(name, openmode)) == NULL)
                    892:                        return ERROR;
                    893:        }
                    894:        return OK;
                    895: }
                    896: 
                    897: /* make string s lower case */
                    898: uncaps(s)
                    899: register char *s;
                    900: {
                    901:        for ( ; *s; ++s)
                    902:                if (isupper(*s))
                    903:                        *s = tolower(*s);
                    904: }
                    905: 
                    906: 
                    907: /*
                    908:  * IsAnyLower returns TRUE if string s has lower case letters.
                    909:  */
                    910: IsAnyLower(s)
                    911: register char *s;
                    912: {
                    913:        for ( ; *s; ++s)
                    914:                if (islower(*s))
                    915:                        return TRUE;
                    916:        return FALSE;
                    917: }
                    918: /*
                    919:  * putsec writes the n characters of buf to receive file fout.
                    920:  *  If not in binary mode, carriage returns, and all characters
                    921:  *  starting with CPMEOF are discarded.
                    922:  */
                    923: putsec(buf, n)
                    924: char *buf;
                    925: register n;
                    926: {
                    927:        register char *p;
                    928: 
                    929:        ++totblocks;
                    930:        if (Thisbinary)
                    931:        {
                    932:                for (p=buf; --n>=0; )
                    933:                        putc( *p++, fout);
                    934:        }
                    935:        else {
                    936:                if (Eofseen)
                    937:                        return OK;
                    938:                for (p=buf; --n>=0; ++p ) {
                    939:                        if ( *p == '\r')
                    940:                                continue;
                    941:                        if (*p == CPMEOF) {
                    942:                                Eofseen=TRUE; return OK;
                    943:                        }
                    944:                        putc(*p ,fout);
                    945:                }
                    946:        }
                    947:        return OK;
                    948: }
                    949: sendline(c)
                    950: {
                    951:        char d;
                    952: 
                    953:        d = c;
                    954:        if (Verbose>2)
                    955:                fprintf(stderr, "Sendline: %x\n", c);
                    956:        write(1, &d, 1);
                    957:        Lleft=0;        /* Do read next time ... */
                    958: }
                    959: 
                    960: 
                    961: /*
                    962:  * substr(string, token) searches for token in string s
                    963:  * returns pointer to token within string if found, NULL otherwise
                    964:  */
                    965: char *
                    966: substr(s, t)
                    967: register char *s,*t;
                    968: {
                    969:        register char *ss,*tt;
                    970:        /* search for first char of token */
                    971:        for (ss=s; *s; s++)
                    972:                if (*s == *t)
                    973:                        /* compare token with substring */
                    974:                        for (ss=s,tt=t; ;) {
                    975:                                if (*tt == 0)
                    976:                                        return s;
                    977:                                if (*ss++ != *tt++)
                    978:                                        break;
                    979:                        }
                    980:        return NULL;
                    981: }
                    982: 
                    983: /*VARARGS1*/
                    984: log(s,p,u)
                    985: char *s, *p, *u;
                    986: {
                    987:        if (!Verbose)
                    988:                return;
                    989:        fprintf(stderr, "error %d: ", errors);
                    990:        fprintf(stderr, s, p, u);
                    991: }
                    992: 
                    993: /* send 10 CAN's to try to get the other end to shut up */
                    994: canit()
                    995: {
                    996:        register n;
                    997:        for (n=10; --n>=0; )
                    998:                sendline(CAN);
                    999: }
                   1000: 
                   1001: #ifdef REGULUS
                   1002: /*
                   1003:  * copies count bytes from s to d
                   1004:  * (No structure assignment in Regulus C compiler)
                   1005:  */
                   1006: 
                   1007: movmem(s, d, count)
                   1008: register char *s, *d;
                   1009: register count;
                   1010: {
                   1011:        while (--count >= 0)
                   1012:                *d++ = *s++;
                   1013: }
                   1014: #endif
                   1015: 
                   1016: /*
                   1017:  * return 1 iff stdout and stderr are different devices
                   1018:  *  indicating this program operating with a modem on a
                   1019:  *  different line
                   1020:  */
                   1021: fromcu()
                   1022: {
                   1023:        struct stat a, b;
                   1024:        fstat(1, &a); fstat(2, &b);
                   1025:        return (a.st_rdev != b.st_rdev);
                   1026: }
                   1027: 
                   1028: report(sct)
                   1029: int sct;
                   1030: {
                   1031:        if (Verbose>1)
                   1032:                fprintf(stderr,"%03d%c",sct,sct%10? ' ' : '\r');
                   1033: }
                   1034: 
                   1035: /*
                   1036:  * if called as [-][dir/../]vrbCOMMAND set Verbose to 1
                   1037:  * if called as [-][dir/../]rbCOMMAND set the pipe flag
                   1038:  */
                   1039: chkinvok(s)
                   1040: char *s;
                   1041: {
                   1042:        register char *p;
                   1043: 
                   1044:        p = s;
                   1045:        while (*p == '-')
                   1046:                s = ++p;
                   1047:        while (*p)
                   1048:                if (*p++ == '/')
                   1049:                        s = p;
                   1050:        if (*s == 'v') {
                   1051:                Verbose=1; ++s;
                   1052:        }
                   1053:        Progname = s;
                   1054:        if (s[2] && s[0]=='r' && s[1]=='b')
                   1055:                Topipe=TRUE;
                   1056: }
                   1057: 
                   1058: checkpath(name)
                   1059: char *name;
                   1060: {
                   1061:        if (Restricted) {
                   1062:                if (fopen(name, "r") != NULL) {
                   1063:                        canit();
                   1064:                        fprintf(stderr, "\r\nrb: %s exists\n", name);
                   1065:                        bibi();
                   1066:                }
                   1067:                /* restrict pathnames to current tree or uucppublic */
                   1068:                if ( substr(name, "../")
                   1069:                 || (name[0]== '/' && strncmp(name, PUBDIR, strlen(PUBDIR))) ) {
                   1070:                        canit();
                   1071:                        fprintf(stderr,"\r\nrb:\tSecurity Violation\r\n");
                   1072:                        bibi();
                   1073:                }
                   1074:        }
                   1075: }
                   1076: 
                   1077: SHAR_EOF
                   1078: cat << \SHAR_EOF > rbsb.c
                   1079: /* -rev 09-13-85
                   1080:  * mode function and most of the rest of the system dependent
                   1081:  * stuff for rb.c and sb.c   This file is #included so the includer
                   1082:  * can set parameters such as HOWMANY.
                   1083:  */
                   1084: 
                   1085: #ifdef USG
                   1086: #include <sys/types.h>
                   1087: #include <sys/stat.h>
                   1088: #include <termio.h>
                   1089: #include <sys/ioctl.h>
                   1090: #define OS "USG"
                   1091: #endif
                   1092: 
                   1093: #ifdef V7
                   1094: #include <sys/types.h>
                   1095: #include <sys/stat.h>
                   1096: #include <sgtty.h>
                   1097: #define OS "V7"
                   1098: #endif
                   1099: 
                   1100: #ifndef OS
                   1101: #include <termio.h>
                   1102: #include <sys/ioctl.h>
                   1103: #include <stat.h>
                   1104: #define REGULUS
                   1105: #define ONEREAD
                   1106: #define OS "REGULUS"
                   1107: #define void int
                   1108: #define time_t long
                   1109: #endif
                   1110: 
                   1111: 
                   1112: #ifdef ICANON
                   1113: struct termio oldtty, tty;
                   1114: #else
                   1115: struct sgttyb oldtty, tty;
                   1116: struct tchars oldtch, tch;
                   1117: #endif
                   1118: 
                   1119: int iofd = 0;          /* File descriptor for ioctls & reads */
                   1120: 
                   1121: /*
                   1122:  * mode(n)
                   1123:  *  2: set a cbreak, XON/XOFF control mode if using Pro-YAM's -g option
                   1124:  *  1: save old tty stat, set raw mode 
                   1125:  *  0: restore original tty mode
                   1126:  */
                   1127: mode(n)
                   1128: {
                   1129:        static did0 = FALSE;
                   1130: 
                   1131:        switch(n) {
                   1132: #ifdef USG
                   1133:        case 2: /* Cbreak mode used by sb when -g detected */
                   1134:                if(!did0)
                   1135:                        (void) ioctl(iofd, TCGETA, &oldtty);
                   1136:                tty = oldtty;
                   1137: 
                   1138:                tty.c_iflag = BRKINT|IXON;
                   1139: 
                   1140:                tty.c_oflag = 0;        /* Transparent output */
                   1141: 
                   1142:                tty.c_cflag &= ~PARENB; /* Disable parity */
                   1143:                tty.c_cflag |= CS8;     /* Set character size = 8 */
                   1144: 
                   1145: #ifdef XCLUDE
                   1146:                tty.c_lflag = XCLUDE | ISIG;
                   1147: #else
                   1148:                tty.c_lflag = ISIG;
                   1149: #endif
                   1150: 
                   1151:                tty.c_cc[VINTR] = 030;  /* Interrupt on CANCEL */
                   1152:                tty.c_cc[VMIN] = 1;
                   1153: 
                   1154:                (void) ioctl(iofd, TCSETAW, &tty);
                   1155:                did0 = TRUE;
                   1156:                return OK;
                   1157:        case 1:
                   1158:                if(!did0)
                   1159:                        (void) ioctl(iofd, TCGETA, &oldtty);
                   1160:                tty = oldtty;
                   1161: 
                   1162:                tty.c_iflag = IGNBRK;
                   1163: 
                   1164:                 /* No echo, crlf mapping, INTR, QUIT, delays, no erase/kill */
                   1165:                tty.c_lflag &= ~(ECHO | ICANON | ISIG);
                   1166: #ifdef XCLUDE
                   1167:                tty.c_lflag |= XCLUDE;
                   1168: #endif
                   1169: 
                   1170:                tty.c_oflag = 0;        /* Transparent output */
                   1171: 
                   1172:                tty.c_cflag &= ~PARENB; /* Leave baud rate alone, disable parity */
                   1173:                tty.c_cflag |= CS8;     /* Set character size = 8 */
                   1174:                tty.c_cc[VMIN] = HOWMANY; /* Satisfy reads when this many chars in */
                   1175:                tty.c_cc[VTIME] = 1;    /* ... or in this many tenths of seconds */
                   1176:                (void) ioctl(iofd, TCSETAW, &tty);
                   1177:                did0 = TRUE;
                   1178:                return OK;
                   1179: #endif
                   1180: #ifdef V7
                   1181:        case 2:
                   1182:                if(!did0) {
                   1183:                        ioctl(iofd, TIOCEXCL, 0);
                   1184:                        ioctl(iofd, TIOCGETP, &oldtty);
                   1185:                        ioctl(iofd, TIOCGETC, &oldtch);
                   1186:                }
                   1187:                tty = oldtty;
                   1188:                tch = oldtch;
                   1189:                tch.t_intrc = 030;
                   1190:                tty.sg_flags |= CBREAK;
                   1191:                tty.sg_flags &= ~ECHO;
                   1192:                ioctl(iofd, TIOCSETP, &tty);
                   1193:                ioctl(iofd, TIOCSETC, &tch);
                   1194:                did0 = TRUE;
                   1195:                return OK;
                   1196:        case 1:
                   1197:                if(!did0) {
                   1198:                        ioctl(iofd, TIOCEXCL, 0);
                   1199:                        ioctl(iofd, TIOCGETP, &oldtty);
                   1200:                        ioctl(iofd, TIOCGETC, &oldtch);
                   1201:                }
                   1202:                tty = oldtty;
                   1203:                tty.sg_flags |= RAW;
                   1204:                tty.sg_flags &= ~ECHO;
                   1205:                ioctl(iofd, TIOCSETP, &tty);
                   1206:                did0 = TRUE;
                   1207:                return OK;
                   1208: #endif
                   1209: #ifdef REGULUS
                   1210:        case 2:
                   1211:                return ERROR;
                   1212:        case 1:
                   1213:                if(!did0) {
                   1214:                        ioctl(iofd, TCGETA, &oldtty);
                   1215:                }
                   1216:                tty = oldtty;
                   1217: 
                   1218:                tty.c_lflag = 0;
                   1219:                tty.c_iflag = IGNBRK;
                   1220:                tty.c_oflag = 0;        /* Transparent output */
                   1221: 
                   1222:                tty.c_cflag &= ~PARENB; /* Leave baud rate alone, disable parity */
                   1223:                tty.c_cflag |= CS8;     /* Set character size = 8 */
                   1224:                tty.c_cc[VMIN] = HOWMANY; /* Satisfy reads when this many chars in */
                   1225:                tty.c_cc[VTIME] = 1;    /* ... or in this many tenths of seconds */
                   1226:                ioctl(iofd, TCSETA, &tty);
                   1227:                did0 = TRUE;
                   1228:                return OK;
                   1229: #endif
                   1230: #ifdef REGULUS10
                   1231:                if(!did0) {
                   1232:                        ioctl(iofd, TIOCGETP, &oldtty);
                   1233:                }
                   1234:                /* Sorry, No structure assignment in Regulus  C */
                   1235:                movmem( (char *)&oldtty, (char *)&tty, sizeof(tty));
                   1236:                tty.sg_flags |= (EIGHTBIT|RAW);
                   1237:                tty.sg_flags &= ~ECHO;
                   1238:                tty.sg_ledit &= ~LEDIT;
                   1239:                ioctl(iofd, TIOCSETP, &tty);
                   1240:                did0 = TRUE;
                   1241:                return OK;
                   1242: #endif
                   1243:        case 0:
                   1244:                if(!did0)
                   1245:                        return ERROR;
                   1246: #ifdef USG
                   1247:                (void) ioctl(iofd, TCSBRK, 1);  /* Wait for output to drain */
                   1248:                (void) ioctl(iofd, TCFLSH, 1);  /* Flush input queue */
                   1249:                (void) ioctl(iofd, TCSETAW, &oldtty);   /* Restore original modes */
                   1250:                (void) ioctl(iofd, TCXONC,1);   /* Restart output */
                   1251: #endif
                   1252: #ifdef V7
                   1253:                ioctl(iofd, TIOCSETP, &oldtty);
                   1254:                ioctl(iofd, TIOCSETC, &oldtch);
                   1255:                ioctl(iofd, TIOCNXCL, 0);
                   1256: #endif
                   1257: #ifdef REGULUS
                   1258:                ioctl(iofd, TCSETAW, &oldtty);  /* Restore original modes */
                   1259: #endif
                   1260: #ifdef REGULUS10
                   1261:                ioctl(iofd, TIOCSETP, &oldtty);
                   1262: #endif
                   1263:                return OK;
                   1264:        default:
                   1265:                return ERROR;
                   1266:        }
                   1267: }
                   1268: 
                   1269: SHAR_EOF
                   1270: cat << \SHAR_EOF > sb.1
                   1271: '\" Revision Level 
                   1272: '\" Last Delta     12-07-85
                   1273: .TH SB 1 OMEN
                   1274: .SH NAME
                   1275: sb \- send files in batch mode
                   1276: .SH SYNOPSIS
                   1277: .B sb
                   1278: [
                   1279: .B \-1dfkquv
                   1280: ]
                   1281: .B file ...
                   1282: .br
                   1283: .B "sb -X"
                   1284: [
                   1285: .B \-1kquv
                   1286: ]
                   1287: .B file
                   1288: .SH DESCRIPTION
                   1289: .B Sb
                   1290: sends one or more files with YMODEM batch protocol.
                   1291: Normally, only the file name part of the pathname is transmitted.
                   1292: On
                   1293: .SM Unix
                   1294: systems, additional information about the file is transmitted.
                   1295: If the receiving program uses this information,
                   1296: the transmitted file length controls the exact number of bytes written to
                   1297: the output dataset,
                   1298: and the modify time and file mode
                   1299: are set accordingly.
                   1300: 
                   1301: With the
                   1302: .B -X
                   1303: flag,
                   1304: .B sb
                   1305: sends a single file using XMODEM protocol.
                   1306: The received file name must be supplied by the user.
                   1307: 
                   1308: If sb is invoked with stdout and stderr to different datasets,
                   1309: Verbose is set to 2, causing frame by frame progress reports
                   1310: to stderr.
                   1311: This may be disabled with the
                   1312: .B q
                   1313: option.
                   1314: 
                   1315: Iff sb is invoked with $SHELL set and iff that variable contains the
                   1316: string
                   1317: .I "rsh"
                   1318: or
                   1319: .I "rksh"
                   1320: (restricted shell), sb operates in restricted mode.
                   1321: Restricted mode restricts pathnames to the current directory and
                   1322: PUBDIR (conventionally, /usr/spool/uucppublic) and/or subdirectories
                   1323: thereof.
                   1324: 
                   1325: Sb supports YMODEM
                   1326: .B g
                   1327: mode by switching to "cbreak" tty mode with XON/XOFF folow control
                   1328: and the interrupt character set to CAN.
                   1329: The YMODEM
                   1330: .B g
                   1331: mode
                   1332: (Pro-YAM
                   1333: .B g
                   1334: option)
                   1335: increases throughput over error free channels
                   1336: (direct connection, X.PC, etc.)
                   1337: by not acknowledging each transmitted sector.
                   1338: .PP
                   1339: The meanings of the available options are:
                   1340: .PP
                   1341: .PD 0
                   1342: .TP
                   1343: .B 1
                   1344: Use file descriptor 1 for ioctls and reads.
                   1345: By default, file descriptor 0 is used.
                   1346: .TP
                   1347: .B X
                   1348: (XMODEM protocol)
                   1349: Send a single file without the filename packet.
                   1350: .TP
                   1351: .B d
                   1352: Change all instances of "." to "/" in the transmitted pathname.
                   1353: Thus, C.omenB0000 (which is unacceptable to MSDOS or CP/M)
                   1354: is transmitted as C/omenB0000.
                   1355: If the resultant filename has more than 8 characters in the stem,
                   1356: a "." in inserted to allow a total of eleven.
                   1357: .TP
                   1358: .B f
                   1359: Send Full pathnname.
                   1360: Normally directory prefices are stripped from the transmitted
                   1361: filename.
                   1362: .TP
                   1363: .B k
                   1364: Send files using 1024 byte blocks
                   1365: rather than the default 128 byte blocks.
                   1366: The user should determine experimentally
                   1367: the conditions under which use of 1k blocks
                   1368: actually improves throughput without causing
                   1369: problems.
                   1370: .TP
                   1371: .B q
                   1372: Quiet suppresses verbosity.
                   1373: .TP
                   1374: .B u
                   1375: Unlink the file after successful transmission.
                   1376: .TP
                   1377: .B v
                   1378: .IR Verbose
                   1379: causes a list of file
                   1380: names to be appended to
                   1381: /tmp/sblog .
                   1382: More v's generate more output.
                   1383: .PD
                   1384: .SH EXAMPLES
                   1385: (Unix command)
                   1386: .RS
                   1387: sb -k *.c
                   1388: .br
                   1389: .RE
                   1390: (Pro-YAM command)
                   1391: .RS
                   1392: <F3>
                   1393: .br
                   1394: .RE
                   1395: (8-bit YAM Commands)
                   1396: .br
                   1397: .RS
                   1398: ^E
                   1399: .br
                   1400: >>>c: rt -y
                   1401: .br
                   1402: .RE
                   1403: .SH SEE ALSO
                   1404: rb(omen),
                   1405: YMODEM.DOC,
                   1406: Professional-YAM manual,
                   1407: IMP(CP/M),
                   1408: ncu(1),
                   1409: sq(omen),
                   1410: todos(omen),
                   1411: tocpm(omen),
                   1412: tomac(omen)
                   1413: 
                   1414: Compile time options for various operating systems are described in the
                   1415: program source file.
                   1416: .SH BUGS
                   1417: On VMS,
                   1418: some of the #includes with file names enclosed with angle brackets <>
                   1419: may need to have the angle brackets removed, or vice versa.
                   1420: 
                   1421: The VMS version does not transmit the file date.
                   1422: 
                   1423: The VMS version does not recognize Pro-YAM\'s
                   1424: .B g
                   1425: option (YMODEM-g protocol).
                   1426: 
                   1427: The VMS version calculates the file length by counting the bytes therin.
                   1428: 
                   1429: When VMS is lightly loaded, the response time may be too quick for MODEM7
                   1430: unless the MODEM7
                   1431: .B "q"
                   1432: modifier is used.
                   1433: 
                   1434: There may be unknown interactions between the VMS C standard i/o
                   1435: package and RMS.
                   1436: SHAR_EOF
                   1437: cat << \SHAR_EOF > sb.c
                   1438: #define VERSION "sb 2.24 01-04-86"
                   1439: #define PUBDIR "/usr/spool/uucppublic"
                   1440: 
                   1441: /*% cc -K -O -DUSG sb.c -o sb
                   1442: 
                   1443:  * sb.c By Chuck Forsberg
                   1444:  *
                   1445:  *  USG UNIX (3.0) ioctl conventions courtesy  Jeff Martin
                   1446:  *     cc -O -DV7  sb.c -o sb          Unix version 7, 2.8 - 4.3 BSD
                   1447:  *     cc -O -DUSG sb.c -o sb          USG (3.0) Unix
                   1448:  *  ******* Some systems (Venix, Coherent, Regulus) do not *******
                   1449:  *  ******* support tty raw mode read(2) identically to    *******
                   1450:  *  ******* Unix. ONEREAD must be defined to force one     *******
                   1451:  *  ******* character reads for these systems.            *******
                   1452:  *
                   1453:  * A small program for Unix which can send 1 or more
                   1454:  * files in Batch mode to computers running YAM. (Use "rb" in YAM.)
                   1455:  * Supports the CRC option or regular checksum.
                   1456:  * Exit status is 0 for all transfers completed successfully,
                   1457:  * 1 for 1 or more unreadable files or'd with 200 for incomplete file xfer.
                   1458:  *
                   1459:  * accepts -k option for 1kb record length.
                   1460:  *
                   1461:  * sb is derived from yam2.c
                   1462:  * Uses buffered i/o to reduce the CPU time compared to UMODEM.
                   1463:  */
                   1464: 
                   1465: #define LOGFILE "/tmp/sblog"
                   1466: 
                   1467: #include <stdio.h>
                   1468: #include <signal.h>
                   1469: #include <setjmp.h>
                   1470: #include <ctype.h>
                   1471: 
                   1472: #define PATHLEN 256
                   1473: #define OK 0
                   1474: #define FALSE 0
                   1475: #define TRUE 1
                   1476: #define ERROR (-1)
                   1477: 
                   1478: #define HOWMANY 2
                   1479: #include "rbsb.c"      /* most of the system dependent stuff here */
                   1480: 
                   1481: FILE *in;
                   1482: 
                   1483: /* Ward Christensen / CP/M parameters - Don't change these! */
                   1484: #define ENQ 005
                   1485: #define CAN ('X'&037)
                   1486: #define XOFF ('s'&037)
                   1487: #define XON ('q'&037)
                   1488: #define SOH 1
                   1489: #define STX 2
                   1490: #define EOT 4
                   1491: #define ACK 6
                   1492: #define NAK 025
                   1493: #define CPMEOF 032
                   1494: #define WANTCRC 0103   /* send C not NAK to get crc not checksum */
                   1495: #define WANTG 0107     /* Send G not NAK to get nonstop batch xmsn */
                   1496: #define TIMEOUT (-2)
                   1497: #define RETRYMAX 10
                   1498: #define SECSIZ 128     /* cp/m's Magic Number record size */
                   1499: #define KSIZE 1024
                   1500: 
                   1501: char Lastrx;
                   1502: char Crcflg;
                   1503: int Wcsmask=0377;
                   1504: int Verbose=0;
                   1505: int Modem=0;           /* MODEM - don't send pathnames */
                   1506: int Restricted=0;      /* restricted; no /.. or ../ in filenames */
                   1507: int Quiet=0;           /* overrides logic that would otherwise set verbose */
                   1508: int Fullname=0;                /* transmit full pathname */
                   1509: int Unlinkafter=0;     /* Unlink file after it is sent */
                   1510: int Dottoslash=0;      /* Change foo.bar.baz to foo/bar/baz */
                   1511: int firstsec;
                   1512: int errcnt=0;          /* number of files unreadable */
                   1513: int blklen=SECSIZ;     /* length of transmitted records */
                   1514: int Optiong;           /* Let it rip no wait for sector ACK's */
                   1515: int Noeofseen;
                   1516: int Totsecs;           /* total number of sectors this file */
                   1517: char txbuf[KSIZE];
                   1518: int Filcnt=0;          /* count of number of files opened */
                   1519: 
                   1520: jmp_buf tohere;                /* For the interrupt on RX timeout */
                   1521: 
                   1522: unsigned updcrc();
                   1523: char *substr(), *getenv();
                   1524: 
                   1525: /* called by signal interrupt or terminate to clean things up */
                   1526: bibi(n)
                   1527: {
                   1528:        canit(); fflush(stdout); mode(0);
                   1529:        fprintf(stderr, "sb: caught signal %d; exiting\n", n);
                   1530:        if (n == SIGQUIT)
                   1531:                abort();
                   1532:        exit(128+n);
                   1533: }
                   1534: 
                   1535: #ifdef REGULUS
                   1536: sendline(c)
                   1537: {
                   1538:        static char d[2];
                   1539: 
                   1540:        d[0] = c&Wcsmask;
                   1541:        write(1, d, 1);
                   1542: }
                   1543: #else
                   1544: #define sendline(c) putchar(c & Wcsmask)
                   1545: #endif
                   1546: 
                   1547: main(argc, argv)
                   1548: char *argv[];
                   1549: {
                   1550:        register char *cp;
                   1551:        register npats;
                   1552:        int agcnt; char **agcv;
                   1553:        char **patts;
                   1554:        int exitcode;
                   1555: #ifndef REGULUS
                   1556:        static char xXbuf[BUFSIZ];
                   1557: #endif
                   1558: 
                   1559:        if ((cp=getenv("SHELL")) && (substr(cp, "rsh") || substr(cp, "rsh")))
                   1560:                Restricted=TRUE;
                   1561: 
                   1562:        npats=0;
                   1563:        if (argc<2)
                   1564:                usage();
                   1565: #ifndef REGULUS
                   1566:        setbuf(stdout, xXbuf);          
                   1567: #endif
                   1568:        while (--argc) {
                   1569:                cp = *++argv;
                   1570:                if (*cp++ == '-' && *cp) {
                   1571:                        while ( *cp) {
                   1572:                                switch(*cp++) {
                   1573:                                case '1':
                   1574:                                        iofd = 1; break;
                   1575:                                case '7':
                   1576:                                        Wcsmask=0177; break;
                   1577:                                case 'd':
                   1578:                                        ++Dottoslash;
                   1579:                                        /* **** FALL THROUGH TO **** */
                   1580:                                case 'f':
                   1581:                                        Fullname=TRUE; break;
                   1582:                                case 'k':
                   1583:                                        blklen=KSIZE; break;
                   1584:                                case 'q':
                   1585:                                        Quiet=TRUE; Verbose=0; break;
                   1586:                                case 'u':
                   1587:                                        ++Unlinkafter; break;
                   1588:                                case 'v':
                   1589:                                        ++Verbose; break;
                   1590:                                case 'X':
                   1591:                                        ++Modem; break;
                   1592:                                default:
                   1593:                                        usage();
                   1594:                                }
                   1595:                        }
                   1596:                }
                   1597:                else if ( !npats && argc>0) {
                   1598:                        if (argv[0][0]) {
                   1599:                                npats=argc;
                   1600:                                patts=argv;
                   1601:                                if ( !strcmp(*patts, "-"))
                   1602:                                        iofd = 1;
                   1603:                        }
                   1604:                }
                   1605:        }
                   1606:        if (npats < 1) 
                   1607:                usage();
                   1608:        if (Verbose) {
                   1609:                if (freopen(LOGFILE, "a", stderr)==NULL) {
                   1610:                        printf("Can't open log file %s\n",LOGFILE);
                   1611:                        exit(0200);
                   1612:                }
                   1613:                setbuf(stderr, NULL);
                   1614:        }
                   1615:        if (fromcu() && !Quiet) {
                   1616:                if (Verbose == 0)
                   1617:                        Verbose = 2;
                   1618:        }
                   1619:        if (Verbose != 1) {
                   1620:                fprintf(stderr, "sb: %d file%s requested:\r\n",
                   1621:                 npats, npats>1?"s":"");
                   1622:                for ( agcnt=npats, agcv=patts; --agcnt>=0; ) {
                   1623:                        fprintf(stderr, "%s ", *agcv++);
                   1624:                }
                   1625:        }
                   1626: 
                   1627:        mode(1);
                   1628:        if (signal(SIGINT, bibi) == SIG_IGN) {
                   1629:                signal(SIGINT, SIG_IGN); signal(SIGKILL, SIG_IGN);
                   1630:        }
                   1631:        else {
                   1632:                signal(SIGINT, bibi); signal(SIGKILL, bibi);
                   1633:                signal(SIGQUIT, bibi);
                   1634:        }
                   1635: 
                   1636:        if (wcsend(npats, patts)==ERROR) {
                   1637:                exitcode=0200;
                   1638:                canit();
                   1639:        }
                   1640:        fflush(stdout);
                   1641:        mode(0);
                   1642:        exit((errcnt != 0) | exitcode);
                   1643: }
                   1644: 
                   1645: wcsend(argc, argp)
                   1646: char *argp[];
                   1647: {
                   1648:        register n;
                   1649: 
                   1650:        Crcflg=FALSE;
                   1651:        firstsec=TRUE;
                   1652:        for (n=0; n<argc; ++n) {
                   1653:                Totsecs = 0;
                   1654:                if (wcs(argp[n])==ERROR)
                   1655:                        goto fubar;
                   1656:        }
                   1657:        Totsecs = 0;
                   1658:        if (Filcnt==0) {        /* bitch if we couldn't open ANY files */
                   1659:                fprintf(stderr,"\r\nCan't open any requested files.\n");
                   1660:                return ERROR;
                   1661:        }
                   1662:        else if (wctxpn("")==ERROR)
                   1663:                goto fubar;
                   1664:        return OK;
                   1665: fubar:
                   1666:        canit(); return ERROR;
                   1667: }
                   1668: 
                   1669: wcs(oname)
                   1670: char *oname;
                   1671: {
                   1672:        register c;
                   1673:        register char *p;
                   1674:        struct stat f;
                   1675:        char name[PATHLEN];
                   1676: 
                   1677:        strcpy(name, oname);
                   1678: 
                   1679:        if (Restricted) {
                   1680:                /* restrict pathnames to current tree or uucppublic */
                   1681:                if ( substr(name, "../")
                   1682:                 || (name[0]== '/' && strncmp(name, PUBDIR, strlen(PUBDIR))) ) {
                   1683:                        canit();
                   1684:                        fprintf(stderr,"\r\nsb:\tSecurity Violation\r\n");
                   1685:                        return ERROR;
                   1686:                }
                   1687:        }
                   1688: 
                   1689:        if ( !strcmp(oname, "-")) {
                   1690:                sprintf(name, "s%d.sb", getpid());
                   1691:                in = stdin;
                   1692:        }
                   1693:        else if ((in=fopen(oname, "r"))==NULL) {
                   1694:                ++errcnt;
                   1695:                return OK;      /* pass over it, there may be others */
                   1696:        }
                   1697:        ++Noeofseen;
                   1698:        /* Check for directory or block special files */
                   1699: #ifndef REGULUS                /* This doesn't seem to work on Regulus */
                   1700:        fstat(fileno(in), &f);
                   1701:        c = f.st_mode & S_IFMT;
                   1702:        if (c == S_IFDIR || c == S_IFBLK) {
                   1703:                fclose(in);
                   1704:                return OK;
                   1705:        }
                   1706: #endif
                   1707:        ++Filcnt;
                   1708:        if (wctxpn(name)== ERROR)
                   1709:                return ERROR;
                   1710:        if (wctx()==ERROR)
                   1711:                return ERROR;
                   1712:        if (Unlinkafter)
                   1713:                unlink(oname);
                   1714:        return 0;
                   1715: }
                   1716: 
                   1717: /*
                   1718:  * generate and transmit pathname block consisting of
                   1719:  *  pathname (null terminated),
                   1720:  *  file length, mode time and file mode in octal
                   1721:  *  as provided by the Unix fstat call.
                   1722:  *  N.B.: modifies the passed name, may extend it!
                   1723:  */
                   1724: wctxpn(name)
                   1725: char *name;
                   1726: {
                   1727:        register firstch;
                   1728:        register char *p, *q;
                   1729:        char name2[PATHLEN];
                   1730:        struct stat f;
                   1731: 
                   1732:        if (Modem)
                   1733:                return OK;
                   1734:        logent("\r\nAwaiting pathname nak for %s\r\n", *name?name:"<END>");
                   1735:        if (getnak())
                   1736:                return ERROR;
                   1737: 
                   1738:        q = (char *) 0;
                   1739:        if (Dottoslash) {               /* change . to . */
                   1740:                for (p=name; *p; ++p) {
                   1741:                        if (*p == '/')
                   1742:                                q = p;
                   1743:                        else if (*p == '.')
                   1744:                                *(q=p) = '/';
                   1745:                }
                   1746:                if (q && strlen(++q) > 8) {     /* If name>8 chars */
                   1747:                        q += 8;                 /*   make it .ext */
                   1748:                        strcpy(name2, q);       /* save excess of name */
                   1749:                        *q = '.';
                   1750:                        strcpy(++q, name2);     /* add it back */
                   1751:                }
                   1752:        }
                   1753: 
                   1754:        for (p=name, q=txbuf ; *p; )
                   1755:                if ((*q++ = *p++) == '/' && !Fullname)
                   1756:                        q = txbuf;
                   1757:        *q++ = 0;
                   1758:        p=q;
                   1759:        while (q < (txbuf + KSIZE))
                   1760:                *q++ = 0;
                   1761:        if (in == stdin)
                   1762:                strcpy(p, "1999999999");
                   1763: #ifndef REGULUS                /* This doesn't seem to work on Regulus */
                   1764:        else if (*name && fstat(fileno(in), &f)!= -1)
                   1765:                sprintf(p, "%lu %lo %o", f.st_size, f.st_mtime, f.st_mode);
                   1766: #endif
                   1767:        /* force 1k blocks if name won't fit in 128 byte block */
                   1768:        if (txbuf[125])
                   1769:                blklen=KSIZE;
                   1770:        else {          /* A little goodie for IMP/KMD */
                   1771:                txbuf[127] = f.st_size >>7;
                   1772:                txbuf[126] = f.st_size >>15;
                   1773:        }
                   1774:        if (wcputsec(txbuf, 0, SECSIZ)==ERROR)
                   1775:                return ERROR;
                   1776:        return OK;
                   1777: }
                   1778: 
                   1779: getnak()
                   1780: {
                   1781:        register firstch;
                   1782: 
                   1783:        Lastrx = 0;
                   1784:        for (;;) {
                   1785:                switch (firstch = readock(800,2)) {
                   1786:                case TIMEOUT:
                   1787:                        logent("Timeout on pathname\n");
                   1788:                        return TRUE;
                   1789:                case WANTG:
                   1790:                        mode(2);        /* Set cbreak, XON/XOFF, etc. */
                   1791:                        Optiong = TRUE;
                   1792:                        blklen=KSIZE;
                   1793:                case WANTCRC:
                   1794:                        Crcflg = TRUE;
                   1795:                case NAK:
                   1796:                        return FALSE;
                   1797:                case CAN:
                   1798:                        if (Lastrx == CAN)
                   1799:                                return TRUE;
                   1800:                default:
                   1801:                        break;
                   1802:                }
                   1803:                Lastrx = firstch;
                   1804:        }
                   1805: }
                   1806: 
                   1807: 
                   1808: wctx()
                   1809: {
                   1810:        register int sectnum, attempts, firstch;
                   1811: 
                   1812:        firstsec=TRUE;
                   1813: 
                   1814:        while ((firstch=readock(400, 2))!=NAK && firstch != WANTCRC
                   1815:          && firstch != WANTG && firstch!=TIMEOUT && firstch!=CAN)
                   1816:                ;
                   1817:        if (firstch==CAN) {
                   1818:                logent("Receiver CANcelled\n");
                   1819:                return ERROR;
                   1820:        }
                   1821:        if (firstch==WANTCRC)
                   1822:                Crcflg=TRUE;
                   1823:        if (firstch==WANTG)
                   1824:                Crcflg=TRUE;
                   1825:        sectnum=1;
                   1826:        while (filbuf(txbuf, blklen)) {
                   1827:                if (wcputsec(txbuf, sectnum, blklen)==ERROR) {
                   1828:                        return ERROR;
                   1829:                } else
                   1830:                        sectnum++;
                   1831:        }
                   1832:        if (Verbose>1)
                   1833:                fprintf(stderr, " Closing ");
                   1834:        fclose(in);
                   1835:        attempts=0;
                   1836:        do {
                   1837:                logent(" EOT ");
                   1838:                purgeline();
                   1839:                sendline(EOT);
                   1840:                fflush(stdout);
                   1841:                ++attempts;
                   1842:        }
                   1843:                while ((firstch=(readock(100, 2)) != ACK) && attempts < RETRYMAX);
                   1844:        if (attempts == RETRYMAX) {
                   1845:                logent("No ACK on EOT\n");
                   1846:                return ERROR;
                   1847:        }
                   1848:        else
                   1849:                return OK;
                   1850: }
                   1851: 
                   1852: wcputsec(buf, sectnum, cseclen)
                   1853: char *buf;
                   1854: int sectnum;
                   1855: int cseclen;   /* data length of this sector to send */
                   1856: {
                   1857:        register checksum, wcj;
                   1858:        register char *cp;
                   1859:        unsigned oldcrc;
                   1860:        int firstch;
                   1861:        int attempts;
                   1862: 
                   1863:        firstch=0;      /* part of logic to detect CAN CAN */
                   1864: 
                   1865:        if (Verbose>1)
                   1866:                fprintf(stderr, "\rSector %3d %2dk ", Totsecs, Totsecs/8 );
                   1867:        for (attempts=0; attempts <= RETRYMAX; attempts++) {
                   1868:                Lastrx= firstch;
                   1869:                sendline(cseclen==KSIZE?STX:SOH);
                   1870:                sendline(sectnum);
                   1871:                sendline(-sectnum -1);
                   1872:                oldcrc=checksum=0;
                   1873:                for (wcj=cseclen,cp=buf; --wcj>=0; ) {
                   1874:                        sendline(*cp);
                   1875:                        oldcrc=updcrc(*cp, oldcrc);
                   1876:                        checksum += *cp++;
                   1877:                }
                   1878:                if (Crcflg) {
                   1879:                        oldcrc=updcrc(0,updcrc(0,oldcrc));
                   1880:                        sendline((int)oldcrc>>8);
                   1881:                        sendline((int)oldcrc);
                   1882:                }
                   1883:                else
                   1884:                        sendline(checksum);
                   1885: 
                   1886:                if (Optiong) {
                   1887:                        firstsec = FALSE; return OK;
                   1888:                }
                   1889:                firstch = readock(400, (Noeofseen&&sectnum) ? 2:1);
                   1890: gotnak:
                   1891:                switch (firstch) {
                   1892:                case CAN:
                   1893:                        if(Lastrx == CAN) {
                   1894: cancan:
                   1895:                                logent("Cancelled\n");  return ERROR;
                   1896:                        }
                   1897:                        break;
                   1898:                case TIMEOUT:
                   1899:                        logent("Timeout on sector ACK\n"); continue;
                   1900:                case WANTCRC:
                   1901:                        if (firstsec)
                   1902:                                Crcflg = TRUE;
                   1903:                case NAK:
                   1904:                        logent("NAK on sector\n"); continue;
                   1905:                case ACK: 
                   1906:                        firstsec=FALSE;
                   1907:                        Totsecs += (cseclen>>7);
                   1908:                        return OK;
                   1909:                case ERROR:
                   1910:                        logent("Got burst for sector ACK\n"); break;
                   1911:                default:
                   1912:                        logent("Got %02x for sector ACK\n", firstch); break;
                   1913:                }
                   1914:                for (;;) {
                   1915:                        Lastrx = firstch;
                   1916:                        if ((firstch = readock(400, 2)) == TIMEOUT)
                   1917:                                break;
                   1918:                        if (firstch == NAK || firstch == WANTCRC)
                   1919:                                goto gotnak;
                   1920:                        if (firstch == CAN && Lastrx == CAN)
                   1921:                                goto cancan;
                   1922:                }
                   1923:        }
                   1924:        logent("Retry Count Exceeded\n");
                   1925:        return ERROR;
                   1926: }
                   1927: 
                   1928: 
                   1929: /* fill buf with count chars padding with ^Z for CPM */
                   1930: filbuf(buf, count)
                   1931: register char *buf;
                   1932: {
                   1933:        register c, m;
                   1934:        static lfseen=0;
                   1935: 
                   1936:        m=count;
                   1937:        while ((c=getc(in))!=EOF) {
                   1938:                *buf++ =c;
                   1939:                if (--m == 0)
                   1940:                        break;
                   1941:        }
                   1942:        if (m==count)
                   1943:                return (Noeofseen=0);
                   1944:        else
                   1945:                while (--m>=0)
                   1946:                        *buf++ = CPMEOF;
                   1947:        return count;
                   1948: }
                   1949: 
                   1950: 
                   1951: alrm()
                   1952: {
                   1953:        longjmp(tohere, -1);
                   1954: }
                   1955: 
                   1956: 
                   1957: /*
                   1958:  * readock(timeout, count) reads character(s) from file descriptor 0
                   1959:  *  (1 <= count <= 3)
                   1960:  * it attempts to read count characters. If it gets more than one,
                   1961:  * it is an error unless all are CAN
                   1962:  * (otherwise, only normal response is ACK, CAN, or C)
                   1963:  *  Only looks for one if Optiong, which signifies cbreak, not raw input
                   1964:  *
                   1965:  * timeout is in tenths of seconds
                   1966:  */
                   1967: readock(timeout, count)
                   1968: {
                   1969:        register int c;
                   1970:        static char byt[5];
                   1971: 
                   1972:        if (Optiong)
                   1973:                count = 1;      /* Special hack for cbreak */
                   1974: 
                   1975:        fflush(stdout);
                   1976:        if (setjmp(tohere)) {
                   1977:                logent("TIMEOUT\n");
                   1978:                return TIMEOUT;
                   1979:        }
                   1980:        c = timeout/10;
                   1981:        if (c<2)
                   1982:                c=2;
                   1983:        if (Verbose>3) {
                   1984:                fprintf(stderr, "Timeout=%d Calling alarm(%d) ", timeout, c);
                   1985:                byt[1] = 0;
                   1986:        }
                   1987:        signal(SIGALRM, alrm); alarm(c);
                   1988: #ifdef ONEREAD
                   1989:        c=read(iofd, byt, 1);           /* regulus raw read is unique */
                   1990: #else
                   1991:        c=read(iofd, byt, count);
                   1992: #endif
                   1993:        alarm(0);
                   1994:        if (Verbose>5)
                   1995:                fprintf(stderr, "ret cnt=%d %x %x\n", c, byt[0], byt[1]);
                   1996:        if (c<1)
                   1997:                return TIMEOUT;
                   1998:        if (c==1)
                   1999:                return (byt[0]&0377);
                   2000:        else
                   2001:                while (c)
                   2002:                        if (byt[--c] != CAN)
                   2003:                                return ERROR;
                   2004:        return CAN;
                   2005: }
                   2006: 
                   2007: purgeline()
                   2008: {
                   2009: #ifdef USG
                   2010:        ioctl(iofd, TCFLSH, 0);
                   2011: #else
                   2012:        lseek(iofd, 0L, 2);
                   2013: #endif
                   2014: }
                   2015: 
                   2016: /* update CRC */
                   2017: unsigned updcrc(c, crc)
                   2018: register c;
                   2019: register unsigned crc;
                   2020: {
                   2021:        register count;
                   2022: 
                   2023:        for (count=8; --count>=0;) {
                   2024:                if (crc & 0x8000) {
                   2025:                        crc <<= 1;
                   2026:                        crc += (((c<<=1) & 0400)  !=  0);
                   2027:                        crc ^= 0x1021;
                   2028:                }
                   2029:                else {
                   2030:                        crc <<= 1;
                   2031:                        crc += (((c<<=1) & 0400)  !=  0);
                   2032:                }
                   2033:        }
                   2034:        return crc;     
                   2035: }
                   2036: 
                   2037: /* send 10 CAN's to try to get the other end to shut up */
                   2038: canit()
                   2039: {
                   2040:        register n;
                   2041:        for (n=10; --n>=0; )
                   2042:                sendline(CAN);
                   2043: }
                   2044: 
                   2045: #ifdef REGULUS
                   2046: /*
                   2047:  * copies count bytes from s to d
                   2048:  * (No structure assignment in Regulus C compiler)
                   2049:  */
                   2050: movmem(s, d, count)
                   2051: register char *s, *d;
                   2052: register count;
                   2053: {
                   2054:        while (--count >= 0)
                   2055:                *d++ = *s++;
                   2056: }
                   2057: #endif
                   2058: 
                   2059: /*VARARGS1*/
                   2060: logent(a, b, c)
                   2061: char *a, *b, *c;
                   2062: {
                   2063:        if(Verbose)
                   2064:                fprintf(stderr, a, b, c);
                   2065: }
                   2066: 
                   2067: /*
                   2068:  * return 1 iff stdout and stderr are different devices
                   2069:  *  indicating this program operating with a modem on a
                   2070:  *  different line
                   2071:  */
                   2072: fromcu()
                   2073: {
                   2074:        struct stat a, b;
                   2075:        fstat(1, &a); fstat(2, &b);
                   2076:        return (a.st_rdev != b.st_rdev);
                   2077: }
                   2078: 
                   2079: /*
                   2080:  * substr(string, token) searches for token in string s
                   2081:  * returns pointer to token within string if found, NULL otherwise
                   2082:  */
                   2083: char *
                   2084: substr(s, t)
                   2085: register char *s,*t;
                   2086: {
                   2087:        register char *ss,*tt;
                   2088:        /* search for first char of token */
                   2089:        for (ss=s; *s; s++)
                   2090:                if (*s == *t)
                   2091:                        /* compare token with substring */
                   2092:                        for (ss=s,tt=t; ;) {
                   2093:                                if (*tt == 0)
                   2094:                                        return s;
                   2095:                                if (*ss++ != *tt++)
                   2096:                                        break;
                   2097:                        }
                   2098:        return NULL;
                   2099: }
                   2100: 
                   2101: usage()
                   2102: {
                   2103:        fprintf(stderr,"%s by Chuck Forsberg\n", VERSION);
                   2104:        fprintf(stderr,"Usage: sb [-17dfkquvX] [-] file ...\n");
                   2105:        fprintf(stderr,"        1 Use stdout for all modem i/o\n");
                   2106:        fprintf(stderr,"        7 Use 7 bits only\n");
                   2107:        fprintf(stderr,"        d Change '.' to '/' in pathnames\n");
                   2108:        fprintf(stderr,"        f Send full pathname\n");
                   2109:        fprintf(stderr,"        k Send 1024 byte packets\n");
                   2110:        fprintf(stderr,"        q Quiet (no progress reports)\n");
                   2111:        fprintf(stderr,"        u Unlink file after transmission\n");
                   2112:        fprintf(stderr,"        v Verbose - give more information\n");
                   2113:        fprintf(stderr,"        X XMODEM protocol - send no pathnames\n");
                   2114:        fprintf(stderr,"- as pathname sends standard input, filename=sPID.sb, requires -1 flag\n");
                   2115:        exit(1);
                   2116: }
                   2117: SHAR_EOF
                   2118: cat << \SHAR_EOF > undos.1
                   2119: .TH UNDOS 1 OMEN
                   2120: .SH NAME
                   2121: undos,tounix,todos,tocpm,tomac,unmac \- Change file format for target operating system
                   2122: .SH SYNOPSIS
                   2123: .B undos
                   2124: [
                   2125: .B -s
                   2126: ]
                   2127: file ...
                   2128: .br
                   2129: .B tounix
                   2130: [
                   2131: .B -s
                   2132: ]
                   2133: file ...
                   2134: .br
                   2135: .B todos
                   2136: [
                   2137: .B -s
                   2138: ]
                   2139: file ...
                   2140: .br
                   2141: .B tocpm
                   2142: [
                   2143: .B -s
                   2144: ]
                   2145: file ...
                   2146: .br
                   2147: .B unmac
                   2148: [
                   2149: .B -s
                   2150: ]
                   2151: file ...
                   2152: .br
                   2153: .B tomac
                   2154: [
                   2155: .B -s
                   2156: ]
                   2157: file ...
                   2158: .SH DESCRIPTION
                   2159: .B Undos
                   2160: and
                   2161: .B tounix
                   2162: convert DOS or CP/M format source files to Unix format by deleting
                   2163: carriage returns preceding linefeeds and eliminating characters
                   2164: starting with CPMEOF (^Z).
                   2165: .PP
                   2166: .B Todos
                   2167: converts Unix format source files to DOS format by adding a carriage return
                   2168: (if not already present) before each linefeed,
                   2169: and eliminates characters
                   2170: starting with CPMEOF (^Z).
                   2171: .B Tocpm
                   2172: additionally appends CPMEOF (^Z) characters to the resulting file
                   2173: to make the file length a multiple of the 128 byte CP/M record length.
                   2174: 
                   2175: Any combination of
                   2176: .B undos, todos,
                   2177: or
                   2178: .B tocpm
                   2179: (without flags)
                   2180: may be applied to a proper ASCII
                   2181: file without destroying information.
                   2182: Lone carriage returns used to force overprinting are not translated
                   2183: to CR/LF pairs.
                   2184: 
                   2185: .B Unmac
                   2186: converts files with lines terminated only by carriage return
                   2187: to Unix format.
                   2188: .B Unmac
                   2189: should only be used to translate files whose lines are terminated
                   2190: by lone carriage returns.
                   2191: 
                   2192: .B Tomac
                   2193: converts Unix format files to Macintosh format
                   2194: (lines terminated by carriage return only).
                   2195: 
                   2196: The optional flag
                   2197: .B -s
                   2198: Strips the parity bit on all characters
                   2199: and discards all resulting characters with values less than 7.
                   2200: 
                   2201: The access and modification times of the modified files are set
                   2202: to those of the original files.
                   2203: .SH DIAGNOSTICS
                   2204: Refuses to translate files in which "binary" characters (less than 7
                   2205: or greater than 127) are seen before CPMEOF.
                   2206: Refuses to translate files
                   2207: with ultra long lines.
                   2208: Refuses to translate special files.
                   2209: .SH NOTES
                   2210: Should be executed with the current directory in the same filesystem
                   2211: as the target files for minimum disk i/o.
                   2212: .SH BUGS
                   2213: Does not detect short files without linefeeds.
                   2214: .B Unmac
                   2215: and
                   2216: .B tomac
                   2217: cannot handle files with CR-only overprinting.
                   2218: (Files whose lines end with CR only violate the ASCII code!).
                   2219: .SH SEE ALSO
                   2220: lar(1), yam(1), sq(1), usq(1), rb(omen), sb(omen)
                   2221: SHAR_EOF
                   2222: cat << \SHAR_EOF > undos.c
                   2223: /*% cc -O -K % -o undos
                   2224:  *
                   2225:  * Undos - change DOS format files to Unix, etc.
                   2226:  */
                   2227: char ID[] =
                   2228:  "Undos Rev 12-07-85 (C)Copyright Omen Technology Inc All Rights Reserved\n";
                   2229: /*
                   2230:  * This program and documentation may be copied, used, or modified
                   2231:  *  by Professional-YAM and POWERCOMM licensees provided these notices are
                   2232:  * not removed.  Others may use this program for non-profit purposes only.
                   2233:  */
                   2234: 
                   2235: #include <stdio.h>
                   2236: #include <sys/types.h>
                   2237: #include <sys/stat.h>
                   2238: 
                   2239: #define LL 1024
                   2240: #define SUB 032
                   2241: 
                   2242: char Lbuf[LL];
                   2243: char *Progname;
                   2244: int Todos = 0;
                   2245: int Tocpm = 0;
                   2246: int Tomac = 0;
                   2247: int Unmac = 0;
                   2248: int Strip = 0;
                   2249: 
                   2250: main(argc, argv)
                   2251: char **argv;
                   2252: {
                   2253:        Progname = *argv;
                   2254:        if (! strcmp(Progname, "tocpm"))
                   2255:                Todos = Tocpm = 1;
                   2256:        if (! strcmp(Progname, "todos"))
                   2257:                Todos = 1;
                   2258:        if (! strcmp(Progname, "unmac"))
                   2259:                Unmac = 1;
                   2260:        if (! strcmp(Progname, "tomac"))
                   2261:                Tomac = 1;
                   2262: 
                   2263:        if (! strcmp(argv[1], "-s")) {
                   2264:                ++Strip; --argc; ++argv;
                   2265:        }
                   2266: 
                   2267: 
                   2268:        if (argc<2 || *argv[1]== '-')
                   2269:                usage();
                   2270:        while (--argc >= 1)
                   2271:                chngfmt(*++argv);
                   2272:        exit(0);
                   2273: }
                   2274: usage()
                   2275: {
                   2276:        fprintf(stderr, ID);
                   2277:        fprintf(stderr, "Usage: {undos|tounix|todos|tocpm|unmac} [-s] file ...\n");
                   2278:        fprintf(stderr, "       -s Strip parity bit, ignore bytes < 007\n");
                   2279:        exit(1);
                   2280: }
                   2281: 
                   2282: 
                   2283: chngfmt(name)
                   2284: char *name;
                   2285: {
                   2286:        register c;
                   2287:        register char *p;
                   2288:        register n;
                   2289:        register long fpos;
                   2290:        struct stat st;
                   2291:        FILE *fin, *fout;
                   2292:        int linno = 0;
                   2293:        long ftell();
                   2294:        char *mktemp();
                   2295:        char outnam[64];
                   2296: 
                   2297:        if (stat(name, &st)) {
                   2298:                xperror(name); return;
                   2299:        }
                   2300:        if ((st.st_mode & S_IFMT) != S_IFREG) {
                   2301:                fprintf(stderr, "%s: %s is not a regular file\n", Progname, name);
                   2302:                return;
                   2303:        }
                   2304:        if ((fin = fopen(name, "r")) == NULL) {
                   2305:                xperror(name); return;
                   2306:        }
                   2307:        strcpy(outnam, "undosXXXXXX");
                   2308:        mktemp(outnam);
                   2309:        if ((fout = fopen(outnam, "w")) == NULL) {
                   2310:                xperror(outnam); exit(1);
                   2311:        }
                   2312: 
                   2313:        for (;;) {
                   2314:                ++linno;
                   2315:                for (p=Lbuf, n=LL; --n>0; ) {
                   2316: ignore:
                   2317:                        if ((c = getc(fin)) == EOF)
                   2318:                                break;
                   2319:                        if ( !c)
                   2320:                                goto ignore;
                   2321:                        if (c < '\7' || (c & 0200)) {
                   2322:                                if (Strip) {
                   2323:                                        if ((c &= 0177) < 7)
                   2324:                                                goto ignore;
                   2325:                                } else
                   2326:                                        goto thisbin; 
                   2327:                        }
                   2328:                        if (c == SUB)
                   2329:                                break;
                   2330:                        if (c == '\r' && Unmac)
                   2331:                                c = '\n';
                   2332:                        *p++ = c;
                   2333:                        if (c == '\n')
                   2334:                                break;
                   2335:                }
                   2336:                *p = '\0';
                   2337: 
                   2338:                if (n == 0) {
                   2339:        thisbin:
                   2340:                        if (n) {
                   2341:                                fprintf(stderr, "%s: %s is a binary file", Progname, name);
                   2342:                                fprintf(stderr, " line=%d char =%2X\n", linno, c);
                   2343:                        } else
                   2344:                                fprintf(stderr, "%s: %s has no linefeeds: try unmac?\n", Progname, name);
                   2345:                        fclose(fout);
                   2346:                        unlink(outnam);
                   2347:                        return;
                   2348:                }
                   2349: 
                   2350:                if (Todos) {
                   2351:                        if (*--p == '\n' && p[-1] != '\r') {
                   2352:                                *p++ = '\r'; *p++ = '\n'; *p = 0;
                   2353:                        }
                   2354:                } else if (Tomac) {
                   2355:                        if (*--p == '\n') {
                   2356:                                if (p[-1] == '\r')
                   2357:                                        --p;
                   2358:                                *p++ = '\r'; *p = 0;
                   2359:                        }
                   2360:                } else {
                   2361:                        if (*--p == '\n' && *--p == '\r') {
                   2362:                                *p++ = '\n'; *p = 0;
                   2363:                        }
                   2364:                }
                   2365:                if (fputs(Lbuf, fout) == EOF) {
                   2366:                        xperror(outnam); exit(1);
                   2367:                }
                   2368:                switch (c) {
                   2369:                case EOF:
                   2370:                        if (ferror(fin)) {
                   2371:                                xperror(name); exit(0200);
                   2372:                        }
                   2373:                case SUB:
                   2374:                        if (Tocpm) {
                   2375:                                fpos = ftell(fout);
                   2376:                                do {
                   2377:                                        putc(SUB, fout);
                   2378:                                } while (++fpos & 127);
                   2379:                        }
                   2380:                        fclose(fout); fclose(fin);
                   2381:                        if (st.st_nlink > 1) 
                   2382:                                sprintf(Lbuf, "cp %s %s", outnam, name);
                   2383:                        else
                   2384:                                sprintf(Lbuf, "mv %s %s", outnam, name);
                   2385:                        system(Lbuf);
                   2386:                        utime(name, (struct utimbuf *) &st.st_atime);
                   2387:                        if (st.st_nlink > 1) 
                   2388:                                unlink(outnam);
                   2389:                        return;
                   2390:                }
                   2391:        }
                   2392: }
                   2393: 
                   2394: xperror(s)
                   2395: char *s;
                   2396: {
                   2397:        register char *p;
                   2398:        extern int sys_nerr;
                   2399:        extern char *sys_errlist[];
                   2400:        extern errno;
                   2401: 
                   2402:        if (errno >= sys_nerr)
                   2403:                p = "Gloryovsky: a New Error!";
                   2404:        else
                   2405:                p = sys_errlist[errno];
                   2406:        fprintf(stderr, "%s: %s: %s\n", Progname, s, p);
                   2407: }
                   2408: SHAR_EOF
                   2409: #      End of shell archive
                   2410: exit 0

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.