Annotation of coherent/a/usr/src/local/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: 
                     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.