Annotation of coherent/a/usr/src/local/kermit.c, revision 1.1

1.1     ! root        1: /*
        !             2:  *  K e r m i t         File Transfer Utility
        !             3:  *
        !             4:  *  UNIX Kermit, Columbia University, 1981, 1982, 1983
        !             5:  *     Bill Catchings, Bob Cattani, Chris Maio, Frank da Cruz, Alan Crosswell
        !             6:  *
        !             7:  *  Also:   Jim Guyton, Rand Corporation
        !             8:  *         Walter Underwood, Ford Aerospace
        !             9:  *         Lauren Weinstein
        !            10:  *
        !            11:  *  usage:  kermit c|C [lbe line baud escapechar]      to connect
        !            12:  *         kermit s [d..iflbht line baud] file ...     to send files
        !            13:  *         kermit r [d..iflbht line baud]              to receive files
        !            14:  *
        !            15:  *  where   c|C=connect, s=send, r=receive,
        !            16:  *         d=debug, i=image mode, f=no filename conversion, l=tty line,
        !            17:  *         b=baud rate, e=escape char, h=host (server) mode, t=tymnet mode.
        !            18:  *
        !            19:  *  For remote Kermit, format is either:
        !            20:  *         kermit r                                    to receive files
        !            21:  *  or     kermit s file ...                           to send files
        !            22:  *
        !            23:  */
        !            24: 
        !            25: /*
        !            26:  *  Modification History:
        !            27:  *
        !            28:  *  Oct. 17 Included fixes from Alan Crosswell (CUCCA) for IBM_UTS:
        !            29:  *         - Changed MYEOL character from \n to \r.
        !            30:  *         - Change char to int in bufill so getc would return -1 on
        !            31:  *           EOF instead of 255 (-1 truncated to 8 bits)
        !            32:  *         - Added read() in rpack to eat the EOL character
        !            33:  *         - Added fflush() call in printmsg to force the output
        !            34:  *         NOTE: The last three changes are not conditionally compiled
        !            35:  *               since they should work equally well on any system.
        !            36:  *
        !            37:  *         Changed Berkeley 4.x conditional compilation flag from
        !            38:  *             UNIX4X to UCB4X.
        !            39:  *         Added support for error packets and cleaned up the printing
        !            40:  *             routines.
        !            41:  *  Nov. 5, 1983 (Lauren Weinstein) 
        !            42:  *          Changed "write(0..." to "write(1..." in escape char code. 
        !            43:  *         Changed escape char processing to send the escape char to
        !            44:  *             the remote system if entered twice in a row.
        !            45:  *         Added support for the "Coherent" OS.            
        !            46:  *         Changed the "UCB4X" conditional to "UNIXL" to more correctly
        !            47:  *             indicate its broader meaning.
        !            48:  *         Added explicit "host" (server) flag ("-h") option.
        !            49:  *         Misc. code cleanups.
        !            50:  *  Jan. 21, 1984 (Lauren Weinstein) 
        !            51:  *         Added "suspend" (no hangup) command (^s) for Coherent.
        !            52:  *         Added default tty line/speed settings for Coherent.
        !            53:  *         Added Tymnet mode option ("-t").
        !            54:  *  Apr. 6, 1984 (Lauren Weinstein)    
        !            55:  *         Misc. code cleanups.
        !            56:  *  June 4, 1984 (Lauren Weinstein)
        !            57:  *         Added ability to pass the first line of data to send over the
        !            58:  *         connection via the command line (after the "-C" option flag). 
        !            59:  */
        !            60: 
        !            61: #include <stdio.h>         /* Standard UNIX definitions */
        !            62: 
        !            63: /* Conditional compilation for different machines/operating systems */
        !            64: /* One and only one of the following lines should be 1 */
        !            65: 
        !            66: #define UNIXL      1       /* Various UNIX and UNIX look-alikes */
        !            67: #define TOPS_20            0       /* TOPS-20 */
        !            68: #define IBM_UTS            0       /* Amdahl UTS on IBM systems */
        !            69: #define VAX_VMS            0       /* VAX/VMS (not yet implemented) */
        !            70: 
        !            71: /* Conditional compilation for the different Unix and Unix-like variants */
        !            72: /* 0 means don't compile it, nonzero means do */
        !            73: 
        !            74: #if UNIXL
        !            75: #define V6_LIBS            0       /* Use retrofit libraries */
        !            76: #define NO_FIONREAD 1      /* Don't use ioctl for flushinput() */
        !            77: #define NO_TANDEM   0      /* Don't use TANDEM line discipline (xon/xoff) */
        !            78: #define MULTIREAD   1 /*++1++*/
        !            79:                        /* True for multiple byte read/write in -c mode */
        !            80: #define COHERENT    1      /* True for Coherent OS */
        !            81: #define LOCK_LINE   1       /* Lock the line when in local mode */
        !            82: #endif
        !            83: 
        !            84: #if IBM_UTS
        !            85: #define V6_LIBS            0       /* Use retrofit libraries */
        !            86: #define NO_FIONREAD 1      /* Don't use ioctl for flushinput() */
        !            87: #define NO_TANDEM   1      /* Don't use TANDEM line discipline (xon/xoff) */
        !            88: #define MULTIREAD   0      /* True for multiple byte read/write in -c mode */
        !            89: #endif
        !            90: 
        !            91: #if V6_LIBS
        !            92: #include <retrofit/sgtty.h>
        !            93: #include <retrofit/signal.h>
        !            94: #include <retrofit/setjmp.h>
        !            95: #else
        !            96: #include <sgtty.h>
        !            97: #include <signal.h>
        !            98: #include <setjmp.h>
        !            99: #endif
        !           100: 
        !           101: #if NO_TANDEM
        !           102: #define TANDEM     0       /* define it to be nothing if it's unsupported */
        !           103: #endif
        !           104: 
        !           105: #if COHERENT
        !           106: #define DEFLINE            "/dev/modem"    /* default tty comm line */
        !           107: #define DEFSPEED    9600         /* default tty speed */       
        !           108: #endif
        !           109: 
        !           110: /* Symbol Definitions */
        !           111: 
        !           112: #define MAXPACKSIZ  94     /* Maximum packet size */
        !           113: #define SOH        1       /* Start of header */
        !           114: #define CR         13      /* ASCII Carriage Return */
        !           115: #define SP         32      /* ASCII space */
        !           116: #define DEL        127     /* Delete (rubout) */
        !           117: #define ESCCHR     '^'     /* Default escape character for CONNECT */
        !           118: 
        !           119: #define MAXTRY     20      /* Times to retry a packet */
        !           120: #define MYQUOTE            '#'     /* Quote character I will use */
        !           121: #define MYPAD      0       /* Number of padding characters I will need */
        !           122: #define MYPCHAR            0       /* Padding character I need (NUL) */
        !           123: #define NUL        '\0'
        !           124: #if IBM_UTS
        !           125: #define MYEOL      '\r'    /* End-Of-Line character for UTS systems */
        !           126: #else
        !           127: #define MYEOL      '\n'    /* End-Of-Line character I need */
        !           128: #endif
        !           129: 
        !           130: #define MYTIME     10      /* (10) Seconds after which I should be timed out */
        !           131: #define MAXTIM     60      /* (60) Maximum timeout interval */
        !           132: #define MINTIM     2       /* (2) Minumum timeout interval */
        !           133: 
        !           134: #define TRUE       -1      /* Boolean constants */
        !           135: #define FALSE      0
        !           136: 
        !           137: 
        !           138: /* Macro Definitions */
        !           139: 
        !           140: /*
        !           141:  * tochar: converts a control character to a printable one by adding a space.
        !           142:  *
        !           143:  * unchar: undoes tochar.
        !           144:  *
        !           145:  * ctl:           converts between control characters and printable characters by
        !           146:  *        toggling the control bit (ie. ^A becomes A and A becomes ^A).
        !           147:  */
        !           148: #define tochar(ch)  ((ch) + ' ')
        !           149: #define unchar(ch)  ((ch) - ' ')
        !           150: #define ctl(ch)            ((ch) ^ 64 )
        !           151: 
        !           152: 
        !           153: /* Global Variables */
        !           154: 
        !           155: int    size,               /* Size of present data */
        !           156:        rpsiz,              /* Maximum receive packet size */
        !           157:        spsiz,              /* Maximum send packet size */
        !           158:        pad,                /* How much padding to send */
        !           159:        timint,             /* Timeout for foreign host on sends */
        !           160:        n,                  /* Packet number */
        !           161:        numtry,             /* Times this packet retried */
        !           162:        oldtry,             /* Times previous packet retried */
        !           163:        ttyfd,              /* File descriptor of tty for I/O, 0 if remote */
        !           164:        remote,             /* -1 means we're a remote kermit */
        !           165:        image,              /* -1 means 8-bit mode */
        !           166:        debug,              /* indicates level of debugging output (0=none) */
        !           167:        filnamcnv,          /* -1 means do file name case conversions */
        !           168:        filecount,          /* Number of files left to send */
        !           169:         tflg;              /* Flag for Tymnet mode */
        !           170:        logflg;             /* Log connect transactions */
        !           171:        loglastch;          /* last log character for cr elim */
        !           172: 
        !           173: char   state,              /* Present state of the automaton */
        !           174:        padchar,            /* Padding character to send */
        !           175:        eol,                /* End-Of-Line character to send */
        !           176:        escchr,             /* Connect command escape character */
        !           177:        quote,              /* Quote character in incoming data */
        !           178:        **filelist,         /* List of files to be sent */
        !           179:        *filnam,            /* Current file name */
        !           180:        *ttyline,           /* Pointer to tty line */
        !           181:        ttynbuff[128];      /* Name buffer for tty line */
        !           182:        inbuff[128];        /* remote data input buffer */
        !           183:        recpkt[MAXPACKSIZ], /* Receive packet buffer */
        !           184:        packet[MAXPACKSIZ]; /* Packet buffer */
        !           185:        ldata[1024];        /* First line of data to send over connection */ 
        !           186: 
        !           187: FILE   *fp,                /* File pointer for current disk file */
        !           188:        *log;               /* File pointer for Logfile */
        !           189: int    logfd;              /* File descriptor for Logfile */
        !           190: 
        !           191: jmp_buf env;               /* Environment ptr for timeout longjump */
        !           192: 
        !           193: 
        !           194: /*
        !           195:  *  m a i n
        !           196:  *
        !           197:  *  Main routine - parse command and options, set up the
        !           198:  *  tty lines, and dispatch to the appropriate routine.
        !           199:  */
        !           200: 
        !           201: main(argc,argv)
        !           202: int argc;                          /* Character pointers to and count of */
        !           203: char **argv;                           /* command line arguments */
        !           204: {
        !           205:     char *cp;                          /* char pointer */
        !           206:     int speed,                         /* speed of assigned tty, */
        !           207:        cflg, rflg, sflg;               /* flags for CONNECT, RECEIVE, SEND */
        !           208:     int hflg;                          /* flag for HOST (server) mode */
        !           209:     struct sgttyb
        !           210:        rawmode,                        /* Controlling tty raw mode */
        !           211:        cookedmode,                     /* Controlling tty cooked mode */
        !           212:        ttymode;                        /* mode of tty line in LINE option */
        !           213: 
        !           214:     if (argc < 2) usage();             /* Make sure there's a command line */
        !           215: 
        !           216:     cp = *++argv; argv++; argc -= 2;   /* Set up pointers to args */
        !           217: 
        !           218: /*  Initialize these values and hope the first packet will get across OK */
        !           219: 
        !           220:     eol = CR;                          /* EOL for outgoing packets */
        !           221:     quote = '#';                       /* Standard control-quote char "#" */
        !           222:     pad = 0;                           /* No padding */
        !           223:     padchar = NUL;                     /* Use null if any padding wanted */
        !           224: 
        !           225:     speed = hflg = cflg = logflg = sflg = 0;    /* Turn off all parse flags */
        !           226:     loglastch = -1;
        !           227:     rflg = tflg = 0;
        !           228:     ttyline = 0;                       /* Default is remote mode */
        !           229: 
        !           230: #if UNIXL                              /* Default to 7-bit masking, CRLF */
        !           231:     image = FALSE;                     /* translation and filename case */
        !           232:     filnamcnv = TRUE;                  /* conversion for UNIX systems */
        !           233: #if COHERENT
        !           234:     ttyline = DEFLINE;                 /* set default tty line */
        !           235:     speed = DEFSPEED;                  /* set default tty speed */
        !           236: #endif   
        !           237: #else
        !           238:     image = TRUE;                      /* Default to no processing for */
        !           239:     filnamcnv = FALSE;                 /* non-UNIX-type systems        */
        !           240: #endif
        !           241: 
        !           242:     escchr = ESCCHR;                   /* Default escape character */
        !           243:  
        !           244:     while ((*cp) != NUL)               /* Parse characters in first arg */
        !           245:        switch (*cp++)
        !           246:        {
        !           247:            case 'c':                   /* c/C = Connect command */
        !           248:            case 'C':
        !           249:                cflg++;
        !           250:                if (*(cp-1) == 'C' && argc--)  /* "C" command? */
        !           251:                   strcpy(ldata, *argv++);   /* get starting data line */
        !           252:                break;
        !           253:            case 's': sflg++; break;    /* S = Send command */
        !           254:            case 'r': rflg++; break;    /* R = Receive command */
        !           255:            case 'h': hflg++; break;    /* H = Host (server) mode */
        !           256:            case 't': tflg++; break;    /* T = Tymnet mode */
        !           257:            case 'd':                   /* D = Increment debug mode count */
        !           258:                debug++; break;
        !           259:                
        !           260:            case 'f':
        !           261:                filnamcnv = FALSE;      /* F = don't do case conversion */
        !           262:                break;                  /*     on filenames */
        !           263: 
        !           264:            case 'i':                   /* I = Image (8-bit) mode */
        !           265:                image = TRUE; break;    /* (this is default for non-UNIX) */
        !           266: 
        !           267:            case 'l':                   /* L = specify tty line to use */
        !           268:                if (argc--) ttyline = *argv++;
        !           269:                else usage(); 
        !           270:                if (debug) printf("Line to remote host is %s\n", ttyline); 
        !           271:                break;
        !           272:                
        !           273:            case 'L':                   /* write to log file */
        !           274:                logflg++; break;
        !           275:                
        !           276:            case 'e':                   /* E = specify escape char */
        !           277:                if (argc--) escchr = **argv++;
        !           278:                else usage();
        !           279:                if (debug) printf("Escape char is \"%c\"\n",escchr);
        !           280:                break;
        !           281:                
        !           282:            case 'b':                   /* B = specify baud rate */
        !           283: #if UNIXL
        !           284:                if (argc--) speed = atoi(*argv++);
        !           285:                else usage();
        !           286:                if (debug) printf("Line speed to remote host is %d\n",speed);
        !           287:                break;
        !           288: #else
        !           289:                printmsg("Speed setting not implemented.");
        !           290:                exit(1);
        !           291: #endif
        !           292:        }
        !           293: 
        !           294: /* Done parsing */
        !           295: 
        !           296:     if ((cflg+sflg+rflg) != 1)         /* Only one command allowed */
        !           297:        usage();
        !           298: 
        !           299:     if (!hflg)  /* local mode if "hflg" is FALSE */
        !           300:     {  
        !           301:         ttyfd = open(ttyline,2);       /* Open the tty line */
        !           302:         if (ttyfd < 0) {
        !           303:           printmsg("Cannot open %s", ttyline);
        !           304:           exit(1);
        !           305:         }
        !           306: #if LOCK_LINE          /* Set exclusive-use mode on line */
        !           307:        if (ioctl(ttyfd,TIOCEXCL,0) != 0)
        !           308:        {
        !           309:            printmsg("Cannot lock %s", ttyline);
        !           310:            exit(1);
        !           311:        }
        !           312: #endif
        !           313:         remote = FALSE;                        /* Indicate we're in local mode */
        !           314:     }
        !           315:     else                               /* No LINE specified so we operate */
        !           316:     {                                  /* in remote mode (ie. controlling */
        !           317:        ttyfd = 0;                      /* tty is the communications line) */
        !           318:        remote = TRUE;
        !           319:     }
        !           320:     
        !           321: 
        !           322: /* Put the proper tty into the correct mode */
        !           323: 
        !           324:     if (remote)                                /* If remote, use controlling tty */
        !           325:     {
        !           326:        gtty(0,&cookedmode);            /* Save current mode so we can */
        !           327:        gtty(0,&rawmode);               /* restore it later */
        !           328:        rawmode.sg_flags |= (RAW|TANDEM);
        !           329:        rawmode.sg_flags &= ~(ECHO|CRMOD);
        !           330:        stty(0,&rawmode);               /* Put tty in raw mode */
        !           331:     }
        !           332:     else                               /* Local, use assigned line */
        !           333:     {
        !           334:        gtty(ttyfd,&ttymode);
        !           335:        ttymode.sg_flags |= (RAW|TANDEM);
        !           336:        ttymode.sg_flags &= ~(ECHO|CRMOD);
        !           337: 
        !           338: #if UNIXL                              /* Speed changing for UNIX only */
        !           339:        if (speed)                      /* User specified a speed? */
        !           340:        {
        !           341:            switch(speed)               /* Get internal system code */
        !           342:            {
        !           343:                case 110: speed = B110; break;
        !           344:                case 150: speed = B150; break;
        !           345:                case 300: speed = B300; break;
        !           346:                case 1200: speed = B1200; break;
        !           347:                case 2400: speed = B2400; break;
        !           348:                case 4800: speed = B4800; break;
        !           349:                case 9600: speed = B9600; break; 
        !           350:                case 19200: speed = B19200; break;
        !           351: 
        !           352:                default:
        !           353:                    printmsg("Bad line speed.");
        !           354:                    exit(1);
        !           355:            }
        !           356:            ttymode.sg_ispeed = speed;
        !           357:            ttymode.sg_ospeed = speed;
        !           358:        }
        !           359: #endif /* UNIXL */
        !           360: 
        !           361:        stty(ttyfd,&ttymode);           /* Put asg'd tty in raw mode */
        !           362:     }  
        !           363: 
        !           364: 
        !           365: /* All set up, now execute the command that was given. */
        !           366: 
        !           367:     if (debug)
        !           368:     {
        !           369:        printf("Debugging level = %d\n\n",debug);
        !           370: 
        !           371:        if (cflg) printf("Connect command\n\n");
        !           372:        if (sflg) printf("Send command\n\n");
        !           373:        if (rflg) printf("Receive command\n\n");
        !           374:        if (logflg) printf("Logging connect transactions\n\n");
        !           375:     }
        !           376:   
        !           377:     if (cflg) connect();               /* Connect command */
        !           378: 
        !           379:     if (sflg)                          /* Send command */ 
        !           380:     {
        !           381:        if (argc--) filnam = *argv++;   /* Get file to send */
        !           382:        else
        !           383:        {   if (remote)
        !           384:                stty(0,&cookedmode);    /* Restore controlling tty's modes */
        !           385:            usage();                    /* and give error */
        !           386:        }
        !           387:        fp = NULL;                      /* Indicate no file open yet */
        !           388:        filelist = argv;                /* Set up the rest of the file list */
        !           389:        filecount = argc;               /* Number of files left to send */
        !           390:        if (sendsw() == FALSE)          /* Send the file(s) */
        !           391:            printmsg("Send failed.");   /* Report failure */
        !           392:        else                            /*  or */
        !           393:            printmsg("done.");          /* success */
        !           394:     }
        !           395: 
        !           396:     if (rflg)                          /* Receive command */
        !           397:     {
        !           398:        if (recsw() == FALSE)           /* Receive the file(s) */
        !           399:            printmsg("Receive failed.");
        !           400:        else                            /* Report failure */
        !           401:            printmsg("done.");          /* or success */
        !           402:     }
        !           403: 
        !           404:     if (remote) stty(0,&cookedmode);   /* Restore controlling tty's modes */
        !           405:     exit(0);
        !           406: }
        !           407: 
        !           408: 
        !           409: /*
        !           410:  *  s e n d s w
        !           411:  *
        !           412:  *  Sendsw is the state table switcher for sending files.  It loops until
        !           413:  *  either it finishes, or an error is encountered.  The routines called
        !           414:  *  by sendsw are responsible for changing the state.
        !           415:  *
        !           416:  */
        !           417: 
        !           418: sendsw()
        !           419: {
        !           420:     char sinit(), sfile(), sdata(), seof(), sbreak();
        !           421: 
        !           422:     state = 'S';                       /* Send initiate is the start state */
        !           423:     n = 0;                             /* Initialize message number */
        !           424:     numtry = 0;                                /* Say no tries yet */
        !           425:     while(TRUE)                                /* Do this as long as necessary */
        !           426:     {
        !           427:        if (debug) printf("sendsw state: %c\n",state);
        !           428:        switch(state)
        !           429:        {
        !           430:            case 'S':   state = sinit();  break; /* Send-Init */
        !           431:            case 'F':   state = sfile();  break; /* Send-File */
        !           432:            case 'D':   state = sdata();  break; /* Send-Data */
        !           433:            case 'Z':   state = seof();   break; /* Send-End-of-File */
        !           434:            case 'B':   state = sbreak(); break; /* Send-Break */
        !           435:            case 'C':   return (TRUE);           /* Complete */
        !           436:            case 'A':   return (FALSE);          /* "Abort" */
        !           437:            default:    return (FALSE);          /* Unknown, fail */
        !           438:        }
        !           439:     }
        !           440: }
        !           441: 
        !           442: 
        !           443: /*
        !           444:  *  s i n i t
        !           445:  *
        !           446:  *  Send Initiate: send this host's parameters and get other side's back.
        !           447:  */
        !           448: 
        !           449: char sinit()
        !           450: {
        !           451:     int num, len;                      /* Packet number, length */
        !           452: 
        !           453:     if (numtry++ > MAXTRY) return('A'); /* If too many tries, give up */
        !           454:     spar(packet);                      /* Fill up init info packet */
        !           455: 
        !           456:     flushinput();                      /* Flush pending input */
        !           457: 
        !           458:     spack('S',n,6,packet);             /* Send an S packet */
        !           459:     switch(rpack(&len,&num,recpkt))    /* What was the reply? */
        !           460:     {
        !           461:        case 'N':  return(state);       /* NAK, try it again */
        !           462: 
        !           463:        case 'Y':                       /* ACK */
        !           464:            if (n != num)               /* If wrong ACK, stay in S state */
        !           465:                return(state);          /* and try again */
        !           466:            rpar(recpkt);               /* Get other side's init info */
        !           467: 
        !           468:            if (eol == 0) eol = '\n';   /* Check and set defaults */
        !           469:            if (quote == 0) quote = '#';
        !           470: 
        !           471:            numtry = 0;                 /* Reset try counter */
        !           472:            n = (n+1)%64;               /* Bump packet count */
        !           473:            return('F');                /* OK, switch state to F */
        !           474: 
        !           475:        case 'E':                       /* Error packet received */
        !           476:            prerrpkt(recpkt);           /* Print it out and */
        !           477:            return('A');                /* abort */
        !           478: 
        !           479:        case FALSE: return(state);      /* Receive failure, try again */
        !           480: 
        !           481:        default: return('A');           /* Anything else, just "abort" */
        !           482:    }
        !           483:  }
        !           484: 
        !           485: 
        !           486: /*
        !           487:  *  s f i l e
        !           488:  *
        !           489:  *  Send File Header.
        !           490:  */
        !           491: 
        !           492: char sfile()
        !           493: {
        !           494:     int num, len;                      /* Packet number, length */
        !           495:     char filnam1[50],                  /* Converted file name */
        !           496:        *newfilnam,                     /* Pointer to file name to send */
        !           497:        *cp;                            /* char pointer */
        !           498: 
        !           499:     if (numtry++ > MAXTRY) return('A'); /* If too many tries, give up */
        !           500:     
        !           501:     if (fp == NULL)                    /* If not already open, */
        !           502:     {  if (debug) printf("   Opening %s for sending.\n",filnam);
        !           503:        fp = fopen(filnam,"r");         /* open the file to be sent */
        !           504:        if (fp == NULL)                 /* If bad file pointer, give up */
        !           505:        {
        !           506:            error("Cannot open file %s",filnam);
        !           507:            return('A');
        !           508:        }
        !           509:     }
        !           510: 
        !           511:     strcpy(filnam1, filnam);           /* Copy file name */
        !           512:     newfilnam = cp = filnam1;
        !           513:     while (*cp != '\0')                        /* Strip off all leading directory */
        !           514:        if (*cp++ == '/')               /* names (ie. up to the last /). */
        !           515:            newfilnam = cp;
        !           516: 
        !           517:     if (filnamcnv)                     /* Convert lower case to upper  */
        !           518:        for (cp = newfilnam; *cp != '\0'; cp++)
        !           519:            if (*cp >= 'a' && *cp <= 'z')
        !           520:                *cp ^= 040;
        !           521: 
        !           522:     len = cp - newfilnam;              /* Compute length of new filename */
        !           523: 
        !           524:     printmsg("Sending %s as %s",filnam,newfilnam);
        !           525: 
        !           526:     spack('F',n,len,newfilnam);                /* Send an F packet */
        !           527:     switch(rpack(&len,&num,recpkt))    /* What was the reply? */
        !           528:     {                  
        !           529:        case 'N':                       /* NAK, just stay in this state, */
        !           530:            num = (--num<0 ? 63:num);   /* unless it's NAK for next packet */
        !           531:            if (n != num)               /* which is just like an ACK for */ 
        !           532:                return(state);          /* this packet so fall thru to... */
        !           533: 
        !           534:        case 'Y':                       /* ACK */
        !           535:            if (n != num) return(state); /* If wrong ACK, stay in F state */
        !           536:            numtry = 0;                 /* Reset try counter */
        !           537:            n = (n+1)%64;               /* Bump packet count */
        !           538:            size = bufill(packet);      /* Get first data from file */
        !           539:            return('D');                /* Switch state to D */
        !           540: 
        !           541:        case 'E':                       /* Error packet received */
        !           542:            prerrpkt(recpkt);           /* Print it out and */
        !           543:            return('A');                /* abort */
        !           544: 
        !           545:        case FALSE: return(state);      /* Receive failure, stay in F state */
        !           546: 
        !           547:        default:    return('A');        /* Something else, just "abort" */
        !           548:     }
        !           549: }
        !           550: 
        !           551: 
        !           552: /*
        !           553:  *  s d a t a
        !           554:  *
        !           555:  *  Send File Data
        !           556:  */
        !           557: 
        !           558: char sdata()
        !           559: {
        !           560:     int num, len;                      /* Packet number, length */
        !           561: 
        !           562:     if (numtry++ > MAXTRY) return('A'); /* If too many tries, give up */
        !           563:     spack('D',n,size,packet);          /* Send a D packet */
        !           564:     switch(rpack(&len,&num,recpkt))    /* What was the reply? */
        !           565:     {              
        !           566:        case 'N':                       /* NAK, just stay in this state, */
        !           567:            num = (--num<0 ? 63:num);   /* unless it's NAK for next packet */
        !           568:            if (n != num)               /* which is just like an ACK for */
        !           569:                return(state);          /* this packet so fall thru to... */
        !           570:                
        !           571:        case 'Y':                       /* ACK */
        !           572:            if (n != num) return(state); /* If wrong ACK, fail */
        !           573:            numtry = 0;                 /* Reset try counter */
        !           574:            n = (n+1)%64;               /* Bump packet count */
        !           575:            if ((size = bufill(packet)) == EOF) /* Get data from file */
        !           576:                return('Z');            /* If EOF set state to that */
        !           577:            return('D');                /* Got data, stay in state D */
        !           578: 
        !           579:        case 'E':                       /* Error packet received */
        !           580:            prerrpkt(recpkt);           /* Print it out and */
        !           581:            return('A');                /* abort */
        !           582: 
        !           583:        case FALSE: return(state);      /* Receive failure, stay in D */
        !           584: 
        !           585:        default:    return('A');        /* Anything else, "abort" */
        !           586:     }
        !           587: }
        !           588: 
        !           589: 
        !           590: /*
        !           591:  *  s e o f
        !           592:  *
        !           593:  *  Send End-Of-File.
        !           594:  */
        !           595: 
        !           596: char seof()
        !           597: {
        !           598:     int num, len;                      /* Packet number, length */
        !           599:     if (numtry++ > MAXTRY) return('A'); /* If too many tries, "abort" */
        !           600: 
        !           601:     spack('Z',n,0,packet);             /* Send a 'Z' packet */
        !           602:     switch(rpack(&len,&num,recpkt))    /* What was the reply? */
        !           603:     {
        !           604:        case 'N':                       /* NAK, just stay in this state, */
        !           605:            num = (--num<0 ? 63:num);   /* unless it's NAK for next packet, */
        !           606:            if (n != num)               /* which is just like an ACK for */
        !           607:                return(state);          /* this packet so fall thru to... */
        !           608: 
        !           609:        case 'Y':                       /* ACK */
        !           610:            if (n != num) return(state); /* If wrong ACK, hold out */
        !           611:            numtry = 0;                 /* Reset try counter */
        !           612:            n = (n+1)%64;               /* and bump packet count */
        !           613:            if (debug) printf("   Closing input file %s, ",filnam);
        !           614:            fclose(fp);                 /* Close the input file */
        !           615:            fp = NULL;                  /* Set flag indicating no file open */ 
        !           616: 
        !           617:            if (debug) printf("looking for next file...\n");
        !           618:            if (gnxtfl() == FALSE)      /* No more files go? */
        !           619:                return('B');            /* if not, break, EOT, all done */
        !           620:            if (debug) printf("   New file is %s\n",filnam);
        !           621:            return('F');                /* More files, switch state to F */
        !           622: 
        !           623:        case 'E':                       /* Error packet received */
        !           624:            prerrpkt(recpkt);           /* Print it out and */
        !           625:            return('A');                /* abort */
        !           626: 
        !           627:        case FALSE: return(state);      /* Receive failure, stay in Z */
        !           628: 
        !           629:        default:    return('A');        /* Something else, "abort" */
        !           630:     }
        !           631: }
        !           632: 
        !           633: 
        !           634: /*
        !           635:  *  s b r e a k
        !           636:  *
        !           637:  *  Send Break (EOT)
        !           638:  */
        !           639: 
        !           640: char sbreak()
        !           641: {
        !           642:     int num, len;                      /* Packet number, length */
        !           643:     if (numtry++ > MAXTRY) return('A'); /* If too many tries "abort" */
        !           644: 
        !           645:     spack('B',n,0,packet);             /* Send a B packet */
        !           646:     switch (rpack(&len,&num,recpkt))   /* What was the reply? */
        !           647:     {
        !           648:        case 'N':                       /* NAK, just stay in this state, */
        !           649:            num = (--num<0 ? 63:num);   /* unless NAK for previous packet, */
        !           650:            if (n != num)               /* which is just like an ACK for */
        !           651:                return(state);          /* this packet so fall thru to... */
        !           652: 
        !           653:        case 'Y':                       /* ACK */
        !           654:            if (n != num) return(state); /* If wrong ACK, fail */
        !           655:            numtry = 0;                 /* Reset try counter */
        !           656:            n = (n+1)%64;               /* and bump packet count */
        !           657:            return('C');                /* Switch state to Complete */
        !           658: 
        !           659:        case 'E':                       /* Error packet received */
        !           660:            prerrpkt(recpkt);           /* Print it out and */
        !           661:            return('A');                /* abort */
        !           662: 
        !           663:        case FALSE: return(state);      /* Receive failure, stay in B */
        !           664: 
        !           665:        default:    return ('A');       /* Other, "abort" */
        !           666:    }
        !           667: }
        !           668: 
        !           669: 
        !           670: /*
        !           671:  *  r e c s w
        !           672:  *
        !           673:  *  This is the state table switcher for receiving files.
        !           674:  */
        !           675: 
        !           676: recsw()
        !           677: {
        !           678:     char rinit(), rfile(), rdata();    /* Use these procedures */
        !           679: 
        !           680:     state = 'R';                       /* Receive-Init is the start state */
        !           681:     n = 0;                             /* Initialize message number */
        !           682:     numtry = 0;                                /* Say no tries yet */
        !           683: 
        !           684:     while(TRUE)
        !           685:     {
        !           686:        if (debug) printf(" recsw state: %c\n",state);
        !           687:        switch(state)                   /* Do until done */
        !           688:        {
        !           689:            case 'R':   state = rinit(); break; /* Receive-Init */
        !           690:            case 'F':   state = rfile(); break; /* Receive-File */
        !           691:            case 'D':   state = rdata(); break; /* Receive-Data */
        !           692:            case 'C':   return(TRUE);           /* Complete state */
        !           693:            case 'A':   return(FALSE);          /* "Abort" state */
        !           694:        }
        !           695:     }
        !           696: }
        !           697: 
        !           698:     
        !           699: /*
        !           700:  *  r i n i t
        !           701:  *
        !           702:  *  Receive Initialization
        !           703:  */
        !           704:   
        !           705: char rinit()
        !           706: {
        !           707:     int len, num;                      /* Packet length, number */
        !           708: 
        !           709:     if (numtry++ > MAXTRY) return('A'); /* If too many tries, "abort" */
        !           710: 
        !           711:     switch(rpack(&len,&num,packet))    /* Get a packet */
        !           712:     {
        !           713:        case 'S':                       /* Send-Init */
        !           714:            rpar(packet);               /* Get the other side's init data */
        !           715:            spar(packet);               /* Fill up packet with my init info */
        !           716:            spack('Y',n,6,packet);      /* ACK with my parameters */
        !           717:            oldtry = numtry;            /* Save old try count */
        !           718:            numtry = 0;                 /* Start a new counter */
        !           719:            n = (n+1)%64;               /* Bump packet number, mod 64 */
        !           720:            return('F');                /* Enter File-Receive state */
        !           721: 
        !           722:        case 'E':                       /* Error packet received */
        !           723:            prerrpkt(recpkt);           /* Print it out and */
        !           724:            return('A');                /* abort */
        !           725: 
        !           726:        case FALSE:                     /* Didn't get packet */
        !           727:            spack('N',n,0,0);           /* Return a NAK */
        !           728:            return(state);              /* Keep trying */
        !           729: 
        !           730:        default:     return('A');       /* Some other packet type, "abort" */
        !           731:     }
        !           732: }
        !           733: 
        !           734: 
        !           735: /*
        !           736:  *  r f i l e
        !           737:  *
        !           738:  *  Receive File Header
        !           739:  */
        !           740: 
        !           741: char rfile()
        !           742: {
        !           743:     int num, len;                      /* Packet number, length */
        !           744:     char filnam1[50];                  /* Holds the converted file name */
        !           745: 
        !           746:     if (numtry++ > MAXTRY) return('A'); /* "abort" if too many tries */
        !           747: 
        !           748:     switch(rpack(&len,&num,packet))    /* Get a packet */
        !           749:     {
        !           750:        case 'S':                       /* Send-Init, maybe our ACK lost */
        !           751:            if (oldtry++ > MAXTRY) return('A'); /* If too many tries abort */
        !           752:            if (num == ((n==0) ? 63:n-1)) /* Previous packet, mod 64? */
        !           753:            {                           /* Yes, ACK it again with  */
        !           754:                spar(packet);           /* our Send-Init parameters */
        !           755:                spack('Y',num,6,packet);
        !           756:                numtry = 0;             /* Reset try counter */
        !           757:                return(state);          /* Stay in this state */
        !           758:            }
        !           759:            else return('A');           /* Not previous packet, "abort" */
        !           760: 
        !           761:        case 'Z':                       /* End-Of-File */
        !           762:            if (oldtry++ > MAXTRY) return('A');
        !           763:            if (num == ((n==0) ? 63:n-1)) /* Previous packet, mod 64? */
        !           764:            {                           /* Yes, ACK it again. */
        !           765:                spack('Y',num,0,0);
        !           766:                numtry = 0;
        !           767:                return(state);          /* Stay in this state */
        !           768:            }
        !           769:            else return('A');           /* Not previous packet, "abort" */
        !           770: 
        !           771:        case 'F':                       /* File Header (just what we want) */
        !           772:            if (num != n) return('A');  /* The packet number must be right */
        !           773:            strcpy(filnam1, packet);    /* Copy the file name */
        !           774: 
        !           775:            if (filnamcnv)              /* Convert upper case to lower */
        !           776:                for (filnam=filnam1; *filnam != '\0'; filnam++)
        !           777:                    if (*filnam >= 'A' && *filnam <= 'Z')
        !           778:                        *filnam |= 040;
        !           779: 
        !           780:            if ((fp=fopen(filnam1,"w"))==NULL) /* Try to open a new file */
        !           781:            {
        !           782:                error("Cannot create %s",filnam1); /* Give up if can't */
        !           783:                return('A');
        !           784:            }
        !           785:            else                        /* OK, give message */
        !           786:                printmsg("Receiving %s as %s",packet,filnam1);
        !           787: 
        !           788:            spack('Y',n,0,0);           /* Acknowledge the file header */
        !           789:            oldtry = numtry;            /* Reset try counters */
        !           790:            numtry = 0;                 /* ... */
        !           791:            n = (n+1)%64;               /* Bump packet number, mod 64 */
        !           792:            return('D');                /* Switch to Data state */
        !           793: 
        !           794:        case 'B':                       /* Break transmission (EOT) */
        !           795:            if (num != n) return ('A'); /* Need right packet number here */
        !           796:            spack('Y',n,0,0);           /* Say OK */
        !           797:            return('C');                /* Go to complete state */
        !           798: 
        !           799:        case 'E':                       /* Error packet received */
        !           800:            prerrpkt(recpkt);           /* Print it out and */
        !           801:            return('A');                /* abort */
        !           802: 
        !           803:        case FALSE:                     /* Didn't get packet */
        !           804:            spack('N',n,0,0);           /* Return a NAK */
        !           805:            return(state);              /* Keep trying */
        !           806: 
        !           807:        default:    return ('A');       /* Some other packet, "abort" */
        !           808:     }
        !           809: }
        !           810: 
        !           811: 
        !           812: /*
        !           813:  *  r d a t a
        !           814:  *
        !           815:  *  Receive Data
        !           816:  */
        !           817: 
        !           818: char rdata()
        !           819: {
        !           820:     int num, len;                      /* Packet number, length */
        !           821:     if (numtry++ > MAXTRY) return('A'); /* "abort" if too many tries */
        !           822: 
        !           823:     if (tflg)
        !           824:        sleep(1);                       /* Delay for Tymnet */
        !           825: 
        !           826:     switch(rpack(&len,&num,packet))    /* Get packet */
        !           827:     {
        !           828:        case 'D':                       /* Got Data packet */
        !           829:            if (num != n)               /* Right packet? */
        !           830:            {                           /* No */
        !           831:                if (oldtry++ > MAXTRY)
        !           832:                   return('A'); /* If too many tries, abort */
        !           833:                if (num == ((n==0) ? 63:n-1)) /* Else check packet number */
        !           834:                {                       /* Previous packet again? */
        !           835:                    spack('Y',num,6,packet); /* Yes, re-ACK it */
        !           836:                    numtry = 0;         /* Reset try counter */
        !           837:                    return(state);      /* Don't write out data! */
        !           838:                }
        !           839:                else
        !           840:                   return('A'); /* sorry, wrong number */
        !           841:            }
        !           842:            /* Got data with right packet number */
        !           843:            bufemp(packet,len);         /* Write the data to the file */
        !           844:            spack('Y',n,0,0);           /* Acknowledge the packet */
        !           845:            oldtry = numtry;            /* Reset the try counters */
        !           846:            numtry = 0;                 /* ... */
        !           847:            n = (n+1)%64;               /* Bump packet number, mod 64 */
        !           848:            return('D');                /* Remain in data state */
        !           849: 
        !           850:        case 'F':                       /* Got a File Header */
        !           851:            if (oldtry++ > MAXTRY)
        !           852:                return('A');            /* If too many tries, "abort" */
        !           853:            if (num == ((n==0) ? 63:n-1)) /* Else check packet number */
        !           854:            {                           /* It was the previous one */
        !           855:                spack('Y',num,0,0);     /* ACK it again */
        !           856:                numtry = 0;             /* Reset try counter */
        !           857:                return(state);          /* Stay in Data state */
        !           858:            }
        !           859:            else
        !           860:                return('A');            /* Not previous packet, "abort" */
        !           861: 
        !           862:        case 'Z':                       /* End-Of-File */
        !           863:            if (num != n) return('A');  /* Must have right packet number */
        !           864:            spack('Y',n,0,0);           /* OK, ACK it. */
        !           865:            fclose(fp);                 /* Close the file */
        !           866:            n = (n+1)%64;               /* Bump packet number */
        !           867:            return('F');                /* Go back to Receive File state */
        !           868: 
        !           869:        case 'E':                       /* Error packet received */
        !           870:            prerrpkt(recpkt);           /* Print it out and */
        !           871:            return('A');                /* abort */
        !           872: 
        !           873:        case FALSE:                     /* Didn't get packet */
        !           874:            spack('N',n,0,0);           /* Return a NAK */
        !           875:            return(state);              /* Keep trying */
        !           876: 
        !           877:        default:
        !           878:            return('A');                /* Some other packet, "abort" */
        !           879:        
        !           880:     }
        !           881: }
        !           882: 
        !           883: /*
        !           884:  *  c o n n e c t
        !           885:  *
        !           886:  *  Establish a virtual terminal connection with the remote host, over an
        !           887:  *  assigned tty line. 
        !           888:  */
        !           889: 
        !           890: connect()
        !           891: {
        !           892:     int pid,                           /* Holds process id of child */
        !           893:         connected;                     /* TRUE if connection open */
        !           894:     int        closemode = FALSE;              /* TRUE if we closed connection */
        !           895:     register char *p;  
        !           896:     register int count;
        !           897:     char filetoread [25];
        !           898:     char       * ofp;
        !           899:     int rcount;
        !           900:     char bel = '\07',
        !           901:        c;
        !           902:     static char *heremsg = "\r\nYes, I'm still here... ^r version\r\n";
        !           903:     struct sgttyb
        !           904:        rawmode,                        /* Controlling tty raw mode */
        !           905:        cookedmode;                     /* Controlling tty cooked mode */
        !           906: 
        !           907:     if (remote)                                /* Nothing to connect to in remote */
        !           908:     {                                  /* mode, so just return */
        !           909:        printmsg("No line specified for connection.");
        !           910:        return;
        !           911:     }
        !           912: 
        !           913:     gtty(0,&cookedmode);               /* Save current mode so we can */
        !           914:     gtty(0,&rawmode);                  /* restore it later */
        !           915:     rawmode.sg_flags |= (RAW|TANDEM);
        !           916:     rawmode.sg_flags &= ~(ECHO|CRMOD);
        !           917:     stty(0,&rawmode);                  /* Put tty in raw mode */
        !           918: 
        !           919:        if (logflg) {
        !           920:                if ((logfd = open ("Log", 2)) == -1) {
        !           921:                        if ((logfd = creat ("Log", 0644)) == -1) {
        !           922:                                printmsg ("Cannot open log file\n");
        !           923:                                stty(0, &cookedmode);   /* Restore tty mode */
        !           924:                                return(-1);
        !           925:                        }
        !           926:                }
        !           927:                if ((lseek (logfd, 0L, 2) == -1)) {
        !           928:                        printmsg ("Cannot seek to end of log file\n");
        !           929:                        stty(0, &cookedmode);           /* Restore tty mode */
        !           930:                        return (-1);
        !           931:                }
        !           932:        }
        !           933: 
        !           934:     pid = fork();          /* Start fork to get typeout from remote host */
        !           935: 
        !           936:     if (pid)                       /* Parent: send type-in to remote host */
        !           937:     {
        !           938:        printmsg("connected...\r");
        !           939:        connected = TRUE;               /* Put us in "connect mode" */
        !           940:        
        !           941:        if (*ldata)                     /* initial data line to send? */
        !           942:        {  write(ttyfd, ldata, strlen(ldata));  
        !           943:           write(ttyfd, "\r", 1);       /* ending <CR> */
        !           944:        }
        !           945: 
        !           946:        while (connected)
        !           947:        {
        !           948:            read(0,&c,1);               /* Get a character */
        !           949:            if ((c&0177) == escchr)     /* Check for escape character */
        !           950:            {
        !           951:                read(0,&c,1);
        !           952:                if ((c&0177) == escchr)
        !           953:                    write(ttyfd,&c,1);
        !           954:                else
        !           955:                switch (c&0177)
        !           956:                {
        !           957:                    case 'c':   /* close connection */
        !           958:                    case 'C':
        !           959:                        closemode = TRUE;  /* we're closing connection */
        !           960: #if COHERENT  
        !           961:                        ioctl(ttyfd, TIOCHPCL);  /* set hangup on modem */
        !           962: 
        !           963:                    case 's':   /* suspend connection */
        !           964:                    case 'S':           
        !           965: #endif
        !           966:                        connected = FALSE;
        !           967:                        write(1,"\r\n",2);
        !           968:                        break;                  
        !           969: 
        !           970:                    case 'r': /* read a file and send it */
        !           971:                        ofp = filetoread;
        !           972:                        write (0, "File to send: ", strlen("File to send: "));
        !           973:                        read(0, &c, 1);
        !           974:                        while (c != '\r') {
        !           975:                                write(0, &c, 1);
        !           976:                                *ofp++ = c;
        !           977:                                read(0, &c, 1);
        !           978:                        }
        !           979:                        *ofp++ = '\0';
        !           980:                        write(0,"\r\n",2);
        !           981:                        fp = fopen (filetoread,"r");
        !           982: 
        !           983:                        if (fp == NULL) {
        !           984:                            error("Cannot open file %s\r\n",filetoread);
        !           985:                        } else { 
        !           986:                                while((c = getc(fp)) != EOF) {
        !           987:                                        if (c == '\n')
        !           988:                                                c = '\r';
        !           989:                                        write(ttyfd, &c, 1);
        !           990:                                }
        !           991:                                fclose(fp);
        !           992:                        }
        !           993:                        fp = NULL;
        !           994:                        break;                  
        !           995: 
        !           996:                    case 'h':
        !           997:                    case 'H':
        !           998:                        write(1,heremsg, strlen(heremsg));
        !           999:                        break;
        !          1000:                    
        !          1001:                    default:
        !          1002:                        write(1,"\7",1);  /* bell */
        !          1003:                        break;
        !          1004:                }
        !          1005:            }
        !          1006:            else
        !          1007:            {                           /* If not escape charater, */
        !          1008:                write(ttyfd,&c,1);      /* write it out */
        !          1009:                c = NUL;                /* Nullify it (why?) */
        !          1010:            }
        !          1011:        }
        !          1012:        kill(pid,9);                    /* Done, kill the child */
        !          1013:        wait(0);                        /* and bury him */
        !          1014:        stty(0,&cookedmode);            /* Restore tty mode */
        !          1015:        printmsg(closemode ? "disconnected." : "suspended.");
        !          1016:        return;                         /* Done */
        !          1017:     }
        !          1018:     else                 /* Child does the reading from the remote host */
        !          1019:     {
        !          1020:        for(;;)                         /* Do this forever */
        !          1021:        {
        !          1022: #if MULTIREAD
        !          1023:            count = rcount = read(ttyfd, inbuff, 128);  /* read chars */
        !          1024: #else
        !          1025:            count = read(ttyfd, inbuff, 1);  /* read one char */
        !          1026: #endif
        !          1027: #if COHERENT
        !          1028:            for (p = inbuff; count--; p++)
        !          1029:               *p &= 0177;              /* strip parity for IBM display */
        !          1030: #endif     
        !          1031: #if MULTIREAD
        !          1032:                write(1, inbuff, rcount);       /* write chars */
        !          1033:                if (logflg) {
        !          1034:                        p = inbuff;
        !          1035:                        for (count = rcount; count--; p++) {
        !          1036:                                if (*p != '\r')
        !          1037:                                        write (logfd, p, 1);
        !          1038:                        }
        !          1039:                }
        !          1040: #else
        !          1041:                write(1, inbuff, 1);        /* write char */ 
        !          1042: 
        !          1043:                if (logflg) 
        !          1044:                        if (inbuff [0] != '\r');
        !          1045:                                write (logfd, inbuff, 1); /* log chars */
        !          1046: #endif
        !          1047:        }
        !          1048:     }
        !          1049: }
        !          1050: 
        !          1051: /*
        !          1052:  *     KERMIT utilities.
        !          1053:  */
        !          1054: 
        !          1055: clkint()                               /* Timer interrupt handler */
        !          1056: {
        !          1057:     longjmp(env, TRUE);                        /* Tell rpack to give up */
        !          1058: }
        !          1059: 
        !          1060: 
        !          1061: /*
        !          1062:  *  s p a c k
        !          1063:  *
        !          1064:  *  Send a Packet
        !          1065:  */
        !          1066: 
        !          1067: spack(type,num,len,data)
        !          1068: char type, *data;
        !          1069: int num, len;
        !          1070: {
        !          1071:     int i;                             /* Character loop counter */
        !          1072:     char chksum, buffer[100];          /* Checksum, packet buffer */
        !          1073:     register char *bufp;               /* Buffer pointer */
        !          1074: 
        !          1075:     if (debug>1)                       /* Display outgoing packet */
        !          1076:     {
        !          1077:        if (data != NULL)
        !          1078:            data[len] = '\0';           /* Null-terminate data to print it */
        !          1079:        printf("  spack type: %c\n",type);
        !          1080:        printf("         num:  %d\n",num);
        !          1081:        printf("         len:  %d\n",len);
        !          1082:        if (data != NULL)
        !          1083:            printf("        data: \"%s\"\n",data);
        !          1084:     }
        !          1085:   
        !          1086:     bufp = buffer;                     /* Set up buffer pointer */
        !          1087:     for (i=1; i<=pad; i++) write(ttyfd,&padchar,1); /* Issue any padding */
        !          1088: 
        !          1089:     *bufp++ = SOH;                     /* Packet marker, ASCII 1 (SOH) */
        !          1090:     *bufp++ = tochar(len+3);           /* Send the character count */
        !          1091:     chksum  = tochar(len+3);           /* Initialize the checksum */
        !          1092:     *bufp++ = tochar(num);             /* Packet number */
        !          1093:     chksum += tochar(num);             /* Update checksum */
        !          1094:     *bufp++ = type;                    /* Packet type */
        !          1095:     chksum += type;                    /* Update checksum */
        !          1096: 
        !          1097:     for (i=0; i<len; i++)              /* Loop for all data characters */
        !          1098:     {
        !          1099:        *bufp++ = data[i];              /* Get a character */
        !          1100:        chksum += data[i];              /* Update checksum */
        !          1101:     }
        !          1102:     chksum = (((chksum&0300) >> 6)+chksum)&077; /* Compute final checksum */
        !          1103:     *bufp++ = tochar(chksum);          /* Put it in the packet */
        !          1104:     *bufp = eol;                       /* Extra-packet line terminator */
        !          1105:     write(ttyfd, buffer,bufp-buffer+1); /* Send the packet */
        !          1106: }
        !          1107: 
        !          1108: /*
        !          1109:  *  r p a c k
        !          1110:  *
        !          1111:  *  Read a Packet
        !          1112:  */
        !          1113: 
        !          1114: rpack(len,num,data)
        !          1115: int *len, *num;                                /* Packet length, number */
        !          1116: char *data;                            /* Packet data */
        !          1117: {
        !          1118:     int i, done;                       /* Data character number, loop exit */
        !          1119:     char t,                            /* Current input character */
        !          1120:        type,                           /* Packet type */
        !          1121:        cchksum,                        /* Our (computed) checksum */
        !          1122:        rchksum;                        /* Checksum received from other host */
        !          1123: 
        !          1124: #if UNIXL                              /* TOPS-20 can't handle timeouts... */
        !          1125:     if (setjmp(env)) return FALSE;     /* Timed out, fail */
        !          1126:     signal(SIGALRM,clkint);            /* Setup the timeout */
        !          1127:     if ((timint > MAXTIM) || (timint < MINTIM)) timint = MYTIME;
        !          1128:     alarm(timint);
        !          1129: #endif /* UNIXL */
        !          1130: 
        !          1131:     while (t != SOH)                   /* Wait for packet header */
        !          1132:     {
        !          1133:        read(ttyfd,&t,1);
        !          1134:        t &= 0177;                      /* Handle parity */
        !          1135:     }
        !          1136: 
        !          1137:     done = FALSE;                      /* Got SOH, init loop */
        !          1138:     while (!done)                      /* Loop to get a packet */
        !          1139:     {
        !          1140:        read(ttyfd,&t,1);               /* Get character */
        !          1141:        if (!image) t &= 0177;          /* Handle parity */
        !          1142:        if (t == SOH) continue;         /* Resynchronize if SOH */
        !          1143:        cchksum = t;                    /* Start the checksum */
        !          1144:        *len = unchar(t)-3;             /* Character count */
        !          1145: 
        !          1146:        read(ttyfd,&t,1);               /* Get character */
        !          1147:        if (!image) t &= 0177;          /* Handle parity */
        !          1148:        if (t == SOH) continue;         /* Resynchronize if SOH */
        !          1149:        cchksum = cchksum + t;          /* Update checksum */
        !          1150:        *num = unchar(t);               /* Packet number */
        !          1151: 
        !          1152:        read(ttyfd,&t,1);               /* Get character */
        !          1153:        if (!image) t &= 0177;          /* Handle parity */
        !          1154:        if (t == SOH) continue;         /* Resynchronize if SOH */
        !          1155:        cchksum = cchksum + t;          /* Update checksum */
        !          1156:        type = t;                       /* Packet type */
        !          1157: 
        !          1158:        for (i=0; i<*len; i++)          /* The data itself, if any */
        !          1159:        {                               /* Loop for character count */
        !          1160:            read(ttyfd,&t,1);           /* Get character */
        !          1161:            if (!image) t &= 0177;      /* Handle parity */
        !          1162:            if (t == SOH) continue;     /* Resynch if SOH */
        !          1163:            cchksum = cchksum + t;      /* Update checksum */
        !          1164:            data[i] = t;                /* Put it in the data buffer */
        !          1165:        }
        !          1166:        data[*len] = 0;                 /* Mark the end of the data */
        !          1167: 
        !          1168:        read(ttyfd,&t,1);               /* Get last character (checksum) */
        !          1169:        rchksum = unchar(t);            /* Convert to numeric */
        !          1170:        read(ttyfd,&t,1);               /* get EOL character and toss it */
        !          1171:        if (!image) t &= 0177;          /* Handle parity */
        !          1172:        if (t == SOH) continue;         /* Resynchronize if SOH */
        !          1173:        done = TRUE;                    /* Got checksum, done */
        !          1174:     }
        !          1175: 
        !          1176: #if UNIXL
        !          1177:     alarm(0);                          /* Disable the timer interrupt */
        !          1178: #endif
        !          1179: 
        !          1180:     if (debug>1)                       /* Display incoming packet */
        !          1181:     {
        !          1182:        if (data != NULL)
        !          1183:            data[*len] = '\0';          /* Null-terminate data to print it */
        !          1184:        printf("  rpack type: %c\n",type);
        !          1185:        printf("         num:  %d\n",*num);
        !          1186:        printf("         len:  %d\n",*len);
        !          1187:        if (data != NULL)
        !          1188:            printf("        data: \"%s\"\n",data);
        !          1189:     }
        !          1190:                                        /* Fold in bits 7,8 to compute */
        !          1191:     cchksum = (((cchksum&0300) >> 6)+cchksum)&077; /* final checksum */
        !          1192: 
        !          1193:     if (cchksum != rchksum) return(FALSE);
        !          1194: 
        !          1195:     return(type);                      /* All OK, return packet type */
        !          1196: }
        !          1197: 
        !          1198: 
        !          1199: /*
        !          1200:  *  b u f i l l
        !          1201:  *
        !          1202:  *  Get a bufferful of data from the file that's being sent.
        !          1203:  *  Only control-quoting is done; 8-bit & repeat count prefixes are
        !          1204:  *  not handled.
        !          1205:  */
        !          1206: 
        !          1207: bufill(buffer)
        !          1208: char buffer[];                         /* Buffer */
        !          1209: {
        !          1210:     int i,                             /* Loop index */
        !          1211:        t;                              /* Char read from file */
        !          1212:     char t7;                           /* 7-bit version of above */
        !          1213: 
        !          1214:     i = 0;                             /* Init data buffer pointer */
        !          1215:     while((t = getc(fp)) != EOF)       /* Get the next character */
        !          1216:     {
        !          1217:        t7 = t & 0177;                  /* Get low order 7 bits */
        !          1218: 
        !          1219:        if (t7 < SP || t7==DEL || t7==quote) /* Does this char require */
        !          1220:        {                                   /* special handling? */
        !          1221:            if (t=='\n' && !image)
        !          1222:            {                           /* Do LF->CRLF mapping if !image */
        !          1223:                buffer[i++] = quote;
        !          1224:                buffer[i++] = ctl('\r');
        !          1225:            }
        !          1226:            buffer[i++] = quote;        /* Quote the character */
        !          1227:            if (t7 != quote)
        !          1228:            {
        !          1229:                t = ctl(t);             /* and uncontrolify */
        !          1230:                t7 = ctl(t7);
        !          1231:            }
        !          1232:        }
        !          1233:        if (image)
        !          1234:            buffer[i++] = t;            /* Deposit the character itself */
        !          1235:        else
        !          1236:            buffer[i++] = t7;
        !          1237: 
        !          1238:        if (i >= spsiz-8) return(i);    /* Check length */
        !          1239:     }
        !          1240:     if (i==0) return(EOF);             /* Wind up here only on EOF */
        !          1241:     return(i);                         /* Handle partial buffer */
        !          1242: }
        !          1243: 
        !          1244: 
        !          1245: /*
        !          1246:  *     b u f e m p
        !          1247:  *
        !          1248:  *  Put data from an incoming packet into a file.
        !          1249:  */
        !          1250: 
        !          1251: bufemp(buffer,len)
        !          1252: char  buffer[];                                /* Buffer */
        !          1253: int   len;                             /* Length */
        !          1254: {
        !          1255:     int i;                             /* Counter */
        !          1256:     char t;                            /* Character holder */
        !          1257: 
        !          1258:     for (i=0; i<len; i++)              /* Loop thru the data field */
        !          1259:     {
        !          1260:        t = buffer[i];                  /* Get character */
        !          1261:        if (t == MYQUOTE)               /* Control quote? */
        !          1262:        {                               /* Yes */
        !          1263:            t = buffer[++i];            /* Get the quoted character */
        !          1264:            if ((t & 0177) != MYQUOTE)  /* Low order bits match quote char? */
        !          1265:                t = ctl(t);             /* No, uncontrollify it */
        !          1266:        }
        !          1267:        if (t==CR && !image)            /* Don't pass CR if in image mode */
        !          1268:            continue;
        !          1269: 
        !          1270:        putc(t,fp);
        !          1271:     }
        !          1272: }
        !          1273: 
        !          1274: 
        !          1275: /*
        !          1276:  *  g n x t f l
        !          1277:  *
        !          1278:  *  Get next file in a file group
        !          1279:  */
        !          1280: 
        !          1281: gnxtfl()
        !          1282: {
        !          1283:     if (debug) printf("          gnxtfl: filelist = \"%s\"\n",*filelist);
        !          1284:     filnam = *(filelist++);
        !          1285:     if (filecount-- == 0) return FALSE; /* If no more, fail */
        !          1286:     else return TRUE;                  /* else succeed */
        !          1287: }
        !          1288: 
        !          1289: 
        !          1290: /*
        !          1291:  *  s p a r
        !          1292:  *
        !          1293:  *  Fill the data array with my send-init parameters
        !          1294:  *
        !          1295:  */
        !          1296: 
        !          1297: spar(data)
        !          1298: char data[];
        !          1299: {
        !          1300:     data[0] = tochar(MAXPACKSIZ);         /* Biggest packet I can receive */
        !          1301:     data[1] = tochar(MYTIME);          /* When I want to be timed out */
        !          1302:     data[2] = tochar(MYPAD);           /* How much padding I need */
        !          1303:     data[3] = ctl(MYPCHAR);            /* Padding character I want */
        !          1304:     data[4] = tochar(MYEOL);           /* End-Of-Line character I want */
        !          1305:     data[5] = MYQUOTE;                 /* Control-Quote character I send */
        !          1306: }
        !          1307: 
        !          1308: 
        !          1309: /*  r p a r
        !          1310:  *
        !          1311:  *  Get the other host's send-init parameters
        !          1312:  *
        !          1313:  */
        !          1314: 
        !          1315: rpar(data)
        !          1316: char data[];
        !          1317: {
        !          1318:     spsiz = unchar(data[0]);           /* Maximum send packet size */
        !          1319:     timint = unchar(data[1]);          /* When I should time out */
        !          1320:     pad = unchar(data[2]);             /* Number of pads to send */
        !          1321:     padchar = ctl(data[3]);            /* Padding character to send */
        !          1322:     eol = unchar(data[4]);             /* EOL character I must send */
        !          1323:     quote = data[5];                   /* Incoming data quote character */
        !          1324: }
        !          1325:  
        !          1326: 
        !          1327: /*
        !          1328:  *  f l u s h i n p u t
        !          1329:  *
        !          1330:  *  Dump all pending input to clear stacked up NACK's.
        !          1331:  *  (Implemented only for Berkeley Unix at this time).
        !          1332:  */
        !          1333: 
        !          1334: #if UNIXL&(~NO_FIONREAD)
        !          1335: flushinput()
        !          1336: {
        !          1337: #if COHERENT
        !          1338:     int count;                         /* Number of bytes ready to read */
        !          1339: #else
        !          1340:     long int count;                    /* Number of bytes ready to read */
        !          1341: #endif
        !          1342:     long int i;                                /* Number of bytes to read in loop */
        !          1343: 
        !          1344: #if COHERENT
        !          1345:     ioctl(ttyfd, TIOCQUERY, &count);   /* See how many bytes pending read */
        !          1346: #else
        !          1347:     ioctl(ttyfd, FIONREAD, &count);    /* See how many bytes pending read */
        !          1348: #endif
        !          1349: 
        !          1350:     if (!count) return;                        /* If zero, then no input to flush */
        !          1351: 
        !          1352:     while (count)                      /* Loop till all are flushed */
        !          1353:     {
        !          1354:        i = (count<sizeof(recpkt)) ?    /* Read min of count and size of */
        !          1355:            count : sizeof(recpkt);     /*  the read buffer */
        !          1356:        read(ttyfd, recpkt, i);         /* Read a bunch */
        !          1357:        count -= i;                     /* Subtract from amount to read */
        !          1358:     }
        !          1359: }
        !          1360: #else
        !          1361: flushinput()           /* Null version */
        !          1362: {}
        !          1363: #endif /* UNIXL&(~FIONREAD) */
        !          1364: 
        !          1365: 
        !          1366: /*
        !          1367:  *  Kermit printing routines:
        !          1368:  *
        !          1369:  *  usage - print command line options showing proper syntax
        !          1370:  *  printmsg - like printf with "Kermit: " prepended
        !          1371:  *  error - like printmsg if local kermit; sends a error packet if remote
        !          1372:  *  prerrpkt - print contents of error packet received from remote host
        !          1373:  */
        !          1374: 
        !          1375: /*
        !          1376:  *  u s a g e 
        !          1377:  *
        !          1378:  *  Print summary of usage info and quit
        !          1379:  */
        !          1380: 
        !          1381: usage()
        !          1382: {
        !          1383: #if UNIXL
        !          1384:     printf("Usage: kermit c|C [lbe line baud esc.char]  (connect mode)\n");
        !          1385:     printf("or:           kermit s[diflbht line baud] file ...  (send mode)\n");
        !          1386:     printf("or:           kermit r[diflbht line baud]           (receive mode)\n");
        !          1387: #else
        !          1388:     printf("Usage: kermit c|C [le line esc.char]        (connect mode)\n");
        !          1389:     printf("or:           kermit s[diflht line] file ...        (send mode)\n");
        !          1390:     printf("or:           kermit r[diflht line]                 (receive mode)\n");
        !          1391: #endif
        !          1392:     exit(1);
        !          1393: }
        !          1394: 
        !          1395: /*
        !          1396:  *  p r i n t m s g
        !          1397:  *
        !          1398:  *  Print message on standard output if not remote.
        !          1399:  */
        !          1400: 
        !          1401: /*VARARGS1*/
        !          1402: printmsg(fmt, a1, a2, a3, a4, a5)
        !          1403: char *fmt;
        !          1404: {
        !          1405:     if (!remote)
        !          1406:     {
        !          1407:        printf("kermit: ");
        !          1408:        printf(fmt,a1,a2,a3,a4,a5);
        !          1409:        printf("\n");
        !          1410:        fflush(stdout);                 /* force output (UTS needs it) */
        !          1411:     }
        !          1412: }
        !          1413: 
        !          1414: /*
        !          1415:  *  e r r o r
        !          1416:  *
        !          1417:  *  Print error message.
        !          1418:  *
        !          1419:  *  If local, print error message with printmsg.
        !          1420:  *  If remote, send an error packet with the message.
        !          1421:  */
        !          1422: 
        !          1423: /*VARARGS1*/
        !          1424: error(fmt, a1, a2, a3, a4, a5)
        !          1425: char *fmt;
        !          1426: {
        !          1427:     char msg[80];
        !          1428:     int len;
        !          1429: 
        !          1430:     if (remote)
        !          1431:     {
        !          1432:        sprintf(msg,fmt,a1,a2,a3,a4,a5); /* Make it a string */
        !          1433:        len = strlen(msg);
        !          1434:        spack('E',n,len,msg);           /* Send the error packet */
        !          1435:     }
        !          1436:     else
        !          1437:        printmsg(fmt, a1, a2, a3, a4, a5);
        !          1438: 
        !          1439:     return;
        !          1440: }
        !          1441: 
        !          1442: /*
        !          1443:  *  p r e r r p k t
        !          1444:  *
        !          1445:  *  Print contents of error packet received from remote host.
        !          1446:  */
        !          1447: prerrpkt(msg)
        !          1448: char *msg;
        !          1449: {
        !          1450:     printf("kermit: aborting with following error from remote host:\n%s\n",
        !          1451:        msg);
        !          1452: }
        !          1453: 

unix.superglobalmegacorp.com

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