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

unix.superglobalmegacorp.com

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