home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / honeywellgcosc / hgker.c < prev    next >
C/C++ Source or Header  |  2020-01-01  |  47KB  |  1,309 lines

  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.  *          Server Mode and Honeywell H66 & DPS8 added   by
  10.  *          Terry Carlin, Honeywell inc.
  11.  *
  12.  *
  13.  *  For remote Kermit, format is either:
  14.  *          kermit r                                    to receive files
  15.  *  or      kermit s file ...                           to send files
  16.  *
  17.  *  or      kermit sv                                   server mode
  18.  *
  19.  *  or      kermit rc                                   receive into
  20.  *                                                      working directory
  21.  *
  22.  *  or       kermit svc                                 server mode using
  23.  *                                                      working directory
  24.  */
  25.  
  26.  
  27.  
  28.  
  29. /*
  30.  *  Modification History:
  31.  *
  32.  *          - Changed MYEOL character from \n to \r.
  33.  *          - Change char to int in bufill so getc would return -1 on
  34.  *            EOF instead of 255 (-1 truncated to 8 bits)
  35.  *          - Added read() in rpack to eat the EOL character
  36.  *          - Added fflush() call in printmsg to force the output
  37.  *          NOTE: The last three changes are not conditionally compiled
  38.  *                since they should work equally well on any system.
  39.  *
  40.  *          Added support for error packets and cleaned up the printing
  41.  *              routines.
  42.  *          Added support for Honeyewll running GCOS.
  43.  *          Added simple server mode
  44.  */
  45.  
  46. #include <stdio.h>          /* Standard UNIX definitions */
  47. #include <fildes.h>
  48. #include <fcntl.h>
  49. #include <signal.h>
  50. /* Symbol Definitions */
  51.  
  52. #define MAXPACKSIZ  94      /* Maximum packet size */
  53. #define SOH         1       /* Start of header */
  54. #define CR          13      /* ASCII Carriage Return */
  55. #define SP          32      /* ASCII space */
  56. #define DEL         127     /* Delete (rubout) */
  57. #define ESCCHR      '^'     /* Default escape character for CONNECT */
  58.  
  59. #define MAXTRY      10      /* Times to retry a packet */
  60. #define MYQUOTE     '#'     /* Quote character I will use */
  61. #define MYPAD       0       /* Number of padding characters I will need */
  62. #define MYPCHAR     0       /* Padding character I need (NULL) */
  63.  
  64. #define MYEOL       '\r'    /* End-Of-Line character for UTS systems */
  65.  
  66. #define MYTIME      10      /* Seconds after which I should be timed out */
  67. #define MAXTIM      60      /* Maximum timeout interval */
  68. #define MINTIM      2       /* Minumum timeout interval */
  69.  
  70. #define TRUE        -1      /* Boolean constants */
  71. #define FALSE       0
  72.  
  73.  
  74. /* Macro Definitions */
  75.  
  76. /*
  77.  * tochar: converts a control character to a printable one by adding a space.
  78.  *
  79.  * unchar: undoes tochar.
  80.  *
  81.  * ctl:    converts between control characters and printable characters by
  82.  *         toggling the control bit (ie. ^A becomes A and A becomes ^A).
  83.  */
  84. #define tochar(ch)  ((ch) + ' ')
  85. #define unchar(ch)  ((ch) - ' ')
  86. #define ctl(ch)     ((ch) ^ 64 )
  87.  
  88.  
  89. /* Global Variables */
  90.  
  91.  
  92.  
  93.  
  94. int     size,               /* Size of present data */
  95.         tmpfil,             /* User wanted temp file for output */
  96.         cflg,                    /* cwd flag */
  97.         rpsiz,              /* Maximum receive packet size */
  98.         spsiz,              /* Maximum send packet size */
  99.         pad,                /* How much padding to send */
  100.         timint,             /* Timeout for foreign host on sends */
  101.         n,                  /* Packet number */
  102.         numtry,             /* Times this packet retried */
  103.         oldtry,             /* Times previous packet retried */
  104.         ttyfd,              /* File descriptor of tty for I/O, 0 if remote */
  105.         remote,             /* -1 means we're a remote kermit */
  106.         image,              /* -1 means 8-bit mode */
  107.         debug,              /* indicates level of debugging output (0=none) */
  108.         cnvfilnam,          /* -1 means do file name case conversions */
  109.         filecount,          /* Number of files left to send */
  110.         state,              /* Present state of the automaton */
  111.         padchar,            /* Padding character to send */
  112.         eol,                /* End-Of-Line character to send */
  113.         escchr,             /* Connect command escape character */
  114.         quote;              /* Quote character in incoming data */
  115. char    **filelist,         /* List of files to be sent */
  116.         *filnam,            /* Current file name */
  117.         recpkt[MAXPACKSIZ], /* Receive packet buffer */
  118.         packet[MAXPACKSIZ]; /* Packet buffer */
  119. char working_directory[40] = "/";
  120. FILE    *fp,                /* File pointer for current disk file */
  121.         *fddebug,           /* File for debugging output */
  122.         *log;               /* File pointer for Logfile */
  123.  
  124. /*
  125.  *  m a i n
  126.  *
  127.  *  Main routine - parse command and options, set up the
  128.  *  tty lines, and dispatch to the appropriate routine.
  129.  */
  130.  
  131. main(argc,argv)
  132. int argc;                           /* Character pointers to and count of */
  133. char **argv;                            /* command line arguments */
  134. {
  135.     char *ttyname,                      /* tty name for LINE argument */
  136.         *cp;                            /* char pointer */
  137.      char savefile[60];          /* work area for filename and cwd */
  138.         int rflg, sflg;               /* flags for RECEIVE, SEND */
  139.         int svflg;                   /* server mode */
  140.         int cmd;                      /* for parser */
  141.  extern int dobreak();                /* just need its address */
  142.     if (argc < 2) usage();              /* Make sure there's a command line */
  143.  
  144.     cp = *++argv; argv++; argc -= 2;    /* Set up pointers to args */
  145.  
  146.     printf("Kermit-GCOS V3.0\n");
  147.  
  148.  
  149. /*  Initialize these values and hope the first packet will get across OK */
  150.  
  151.     eol = CR;                           /* EOL for outgoing packets */
  152.     quote = '#';                        /* Standard control-quote char "#" */
  153.     pad = 0;                            /* No padding */
  154.     padchar = NULL;                     /* Use null if any padding wanted */
  155.  
  156. cflg = 0;   sflg = rflg = svflg = 0;     /* Turn off all parse flags */
  157.     ttyname = 0;                        /* Default is remote mode */
  158.     tmpfil = FALSE;                     /* Create perm files as default */
  159.     image = FALSE;                      /* translation and filename case */
  160.     cnvfilnam = TRUE;                   /* conversion for UNIX systems */
  161.  
  162.     while ((*cp) != NULL)               /* Parse characters in first */
  163.         {
  164.         cmd = *cp++;
  165.         if (isupper(cmd))
  166.             cmd = tolower(cmd);
  167.         switch (cmd)
  168.         {
  169.             case 's':                   /* S = Send command */
  170.                       sflg++;
  171.                       break;
  172.  
  173.             case 'r':                   /* R = Receive command */
  174.                       rflg++;
  175.                       break;
  176.             case 'v':    /*     server mode        */
  177.                      if (sflg)
  178.                          {
  179.                          sflg = 0;
  180.                          svflg++;
  181.                          }
  182.                      else
  183.                          printf("Unknown mode\n");
  184.                      break;
  185.  
  186.             case 'c':                  /* Change working directory */
  187.                     printf("cwd: Enter working directory ");
  188.                     gets(working_directory);
  189.                     strcat(working_directory, "/");
  190.                     cflg++;
  191.                     break;
  192.             case 'd':                   /* D = Increment debug mode count */
  193.                 if (!debug)
  194.                      if ((fddebug = fopen("kermit.d", "w")) == NULL)
  195.                         {
  196.                         printf("Could not open kermit.d\n");
  197.                         exit(1);
  198.                         }
  199.                 debug++; break;
  200.  
  201.             case 'f':
  202.                 cnvfilnam = FALSE;      /* F = don't do case conversion */
  203.                 break;                  /*     on filenames */
  204.  
  205.             case 't':                   /* wants uploaded file to be temp */
  206.                 tmpfil++;
  207.                 working_directory[0] = '\0'; /* null out string */
  208.                 break;
  209.  
  210.  
  211.         }
  212.     }
  213.  
  214. /* Done parsing */
  215.  
  216.     if ((sflg+rflg+svflg) != 1)          /* Only one command allowed */
  217.         usage();
  218.  
  219.      if ((tmpfil + cflg) > 1)
  220.          {
  221.          printf("Can't have working directory and temporary files\n");
  222.          exit();
  223.          }
  224.  
  225.        ttyfd = 0;        /* communications line */
  226.         remote = TRUE;
  227.  
  228. /* Put the proper tty into the correct mode */
  229.  
  230.      system("LINE 160");         /* change line length to 160 chars */
  231.  
  232. /* Set up tty break vectors */
  233.      signal( _SIGBRK, dobreak);
  234.  
  235.  
  236. /* All set up, now execute the command that was given. */
  237.  
  238.     if (debug)
  239.     {
  240.         dbprint("Debugging level = %d\n\n",debug);
  241.  
  242.         if (sflg) dbprint("Send command\n\n");
  243.         if (rflg) dbprint("Receive command\n\n");
  244.         if (svflg) dbprint("Server mode\n");
  245.     }
  246.  
  247.     if (svflg)
  248.          servsw();
  249.  
  250.  
  251.     if (sflg)                           /* Send command */
  252.     {
  253.         if (argc--) filnam = *argv++;   /* Get file to send */
  254.         else
  255.         {
  256.             usage();                    /* and give error */
  257.         }
  258.         if (cflg)                     /* see if working directory set */
  259.             {
  260.             strcpy(savefile, working_directory);
  261.             strcat(savefile, filnam);
  262.             filnam = savefile;
  263.             }
  264.         fp = NULL;                      /* Indicate no file open yet */
  265.         filelist = argv;                /* Set up the rest of the file list */
  266.         filecount = argc;               /* Number of files left to send */
  267.         state = 'S';                    /* Set up initial state */
  268.         printf("Sending file\n");
  269.          if (sendsw(sflg) == FALSE)   /* Send the file(s) */
  270.             printmsg("Send failed.");   /* Report failure */
  271.         else                            /*  or */
  272.             printmsg("done.");          /* success */
  273.     }
  274.  
  275.  
  276.  
  277.  
  278.     if (rflg)                           /* Receive command */
  279.     {
  280.         state = 'R';                     /* Set up initial state */
  281.          printf("Ready to receive file\n");
  282.         if (recsw() == FALSE)           /* Receive the file(s) */
  283.             printmsg("Receive failed.");
  284.         else                            /* Report failure */
  285.             printmsg("done.");          /* or success */
  286.     }
  287.    if (debug)
  288.       fclose(fddebug);
  289. }
  290.  
  291.  
  292.  /*
  293.   * Servsw is the state table switcher for Server mode.  It will call
  294.   * sendsw() and recsw() to to the real work.
  295.   */
  296.  servsw()
  297.  {
  298.  int num, len, i;
  299.  int pkttype;    /* packet type */
  300.  char savename[60], *cptr;
  301.  printf("Server mode\n");
  302.  while(TRUE)
  303.    {
  304.    n = numtry = 0;
  305.   switch((pkttype = rpack(&len, &num, recpkt)))
  306.       {
  307.       case 'I':        /* Info packet */
  308.               rpar(recpkt);
  309.               spar(packet);
  310.               spack('Y',n,6,packet);
  311.               break;
  312.       case 'S':
  313.               rpar(recpkt);
  314.               spar(packet);
  315.               spack('Y',n,6,packet);
  316.               n = (n + 1) % 64;
  317.               state = 'F';
  318.               recsw();    /* go do the file receive */
  319.               break;
  320.       case 'R':
  321.               if (cflg)     /* do cwd if there */
  322.                   {
  323.                   strcpy(savename,working_directory);
  324.                   strcat(savename, recpkt);
  325.                   }
  326.               else
  327.                   strcpy(savename, recpkt); /* save away filename */
  328.               filnam = savename;
  329.              fp = NULL;
  330.              filecount = 0;
  331.               state = 'S';              /* do send now */
  332.               sendsw(FALSE);       /* send the file they want */
  333.               break;
  334.       case 'G':        /* Generic Kermit command */
  335.               switch(recpkt[0])    /* Command is in first char */
  336.                    {
  337.                    case 'L':       /* logoff kermit and system */
  338.                            spack('Y',n,0,0);
  339.                            if (debug)
  340.                                 fclose(fddebug);
  341.                            system("LOGOFF");   /* logoff */
  342.                            break;  /* never get here but ??? */
  343.                    case 'F':       /* finish kermit return to tss */
  344.                           spack('Y',n,0,0);
  345.                            return(TRUE);
  346.                    case 'C':       /*  Change working directory */
  347.                           spack('Y',n,0,0);
  348.                           len = unchar(recpkt[1]);
  349.                           cptr = working_directory;
  350.                           for (i=2;len;i++,len--)
  351.                             *cptr++ = recpkt[i];
  352.                           *cptr++ = '/';
  353.                           *cptr = '\0';
  354.                           break;
  355.                    default:
  356.                           error("Unemplemented Generic kermit command");
  357.                           break;
  358.                     }
  359.                break;
  360.       case 'N':      /* NAK, ignore */
  361.               break;
  362.       default:
  363.               if (debug)
  364.                    dbprint("Unknown packet type %c\n", pkttype);
  365.               error("Unknown packet type");
  366.       }
  367.    }
  368. }
  369. /*
  370.  *  s e n d s w
  371.  *
  372.  *  Sendsw is the state table switcher for sending files.  It loops until
  373.  *  either it finishes, or an error is encountered.  The routines called
  374.  *  by sendsw are responsible for changing the state.
  375.  *
  376.  */
  377.  
  378. sendsw(sflg)
  379. int sflg;         /* need to know if comming in from send or serv */
  380. {
  381.  
  382.     if (sflg)    /* if in send mode then */
  383.     sleep(10);              /* give user a chance to start receive */
  384.     n = 0;                              /* Initialize message number */
  385.     numtry = 0;                         /* Say no tries yet */
  386.     while(TRUE)                         /* Do this as long as necessary */
  387.     {
  388.         if (debug) dbprint("sendsw state: %c\n",state);
  389.         switch(state)
  390.         {
  391.             case 'S':   state = sinit();  break; /* Send-Init */
  392.             case 'F':   state = sfile();  break; /* Send-File */
  393.             case 'D':   state = sdata();  break; /* Send-Data */
  394.             case 'Z':   state = seof();   break; /* Send-End-of-File */
  395.             case 'B':   state = sbreak(); break; /* Send-Break */
  396.             case 'C':   return (TRUE);           /* Complete */
  397.             case 'A':   return (FALSE);          /* "Abort" */
  398.             default:    return (FALSE);          /* Unknown, fail */
  399.         }
  400.     }
  401. }
  402.  
  403.  
  404. /*
  405.  *  s i n i t
  406.  *
  407.  *  Send Initiate: send this host's parameters and get other side's back.
  408.  */
  409.  
  410. sinit()
  411. {
  412.     int num, len;                       /* Packet number, length */
  413.  
  414.  
  415.  
  416.  
  417.     if (numtry++ > MAXTRY) return('A'); /* If too many tries, give up */
  418.     spar(packet);                       /* Fill up init info packet */
  419.  
  420.  
  421.     spack('S',n,6,packet);              /* Send an S packet */
  422.     switch(rpack(&len,&num,recpkt))     /* What was the reply? */
  423.     {
  424.         case 'N':  return(state);       /* NAK, try it again */
  425.  
  426.         case 'Y':                       /* ACK */
  427.             if (n != num)               /* If wrong ACK, stay in S state */
  428.                 return(state);          /* and try again */
  429.             rpar(recpkt);               /* Get other side's init info */
  430.  
  431.             if (eol == 0) eol = '\n';   /* Check and set defaults */
  432.             if (quote == 0) quote = '#';
  433.  
  434.             numtry = 0;                 /* Reset try counter */
  435.             n = (n+1)%64;               /* Bump packet count */
  436.             return('F');                /* OK, switch state to F */
  437.  
  438.         case 'E':                       /* Error packet received */
  439.             prerrpkt(recpkt);           /* Print it out and */
  440.             return('A');                /* abort */
  441.  
  442.         case FALSE: return(state);      /* Receive failure, try again */
  443.  
  444.         default: return('A');           /* Anything else, just "abort" */
  445.    }
  446.  }
  447.  
  448.  
  449. /*
  450.  *  s f i l e
  451.  *
  452.  *  Send File Header.
  453.  */
  454.  
  455. sfile()
  456. {
  457.     int num, len;                       /* Packet number, length */
  458.     char filnam1[50],                   /* Converted file name */
  459.         *newfilnam,                     /* Pointer to file name to send */
  460.         *cp;                            /* char pointer */
  461.  
  462.     if (numtry++ > MAXTRY) return('A'); /* If too many tries, give up */
  463.  
  464.  
  465.  
  466.  
  467.     if (fp == NULL)                     /* If not already open, */
  468.     {   if (debug) dbprint("   Opening %s for sending.\n",filnam);
  469.         fp = fopen(filnam,"r");         /* open the file to be sent */
  470.         if (fp == NULL)                 /* If bad file pointer, give up */
  471.         {
  472.             error("Cannot open file %s",filnam);
  473.             return('A');
  474.         }
  475.     }
  476.  
  477.     strcpy(filnam1, filnam);            /* Copy file name */
  478.     newfilnam = cp = filnam1;
  479.     while (*cp != '\0')                 /* Strip off all leading directory */
  480.         if (*cp++ == '/')               /* names (ie. up to the last /). */
  481.             newfilnam = cp;
  482.  
  483.     if (cnvfilnam)                      /* Convert lower case to upper  */
  484.         for (cp = newfilnam; *cp != '\0'; cp++)
  485.             if (*cp >= 'a' && *cp <= 'z')
  486.                 *cp ^= 040;
  487.  
  488.     len = cp - newfilnam;               /* Compute length of new filename */
  489.  
  490.     printmsg("Sending %s as %s",filnam,newfilnam);
  491.  
  492.     spack('F',n,len,newfilnam);         /* Send an F packet */
  493.     switch(rpack(&len,&num,recpkt))     /* What was the reply? */
  494.     {
  495.         case 'N':                       /* NAK, just stay in this state, */
  496.             num = (--num<0 ? 63:num);   /* unless it's NAK for next packet */
  497.             if (n != num)               /* which is just like an ACK for */
  498.                 return(state);          /* this packet so fall thru to... */
  499.  
  500.         case 'Y':                       /* ACK */
  501.             if (n != num) return(state); /* If wrong ACK, stay in F state */
  502.             numtry = 0;                 /* Reset try counter */
  503.             n = (n+1)%64;               /* Bump packet count */
  504.             size = bufill(packet);      /* Get first data from file */
  505.             return('D');                /* Switch state to D */
  506.  
  507.         case 'E':                       /* Error packet received */
  508.             prerrpkt(recpkt);           /* Print it out and */
  509.             return('A');                /* abort */
  510.  
  511.         case FALSE: return(state);      /* Receive failure, stay in F state */
  512.  
  513.         default:    return('A');        /* Something else, just "abort" */
  514.     }
  515. }
  516.  
  517.  
  518.  
  519.  
  520. /*
  521.  *  s d a t a
  522.  *
  523.  *  Send File Data
  524.  */
  525.  
  526. sdata()
  527. {
  528.     int num, len;                       /* Packet number, length */
  529.  
  530.     if (numtry++ > MAXTRY) return('A'); /* If too many tries, give up */
  531.  
  532.     spack('D',n,size,packet);           /* Send a D packet */
  533.     switch(rpack(&len,&num,recpkt))     /* What was the reply? */
  534.     {
  535.         case 'N':                       /* NAK, just stay in this state, */
  536.             num = (--num<0 ? 63:num);   /* unless it's NAK for next packet */
  537.             if (n != num)               /* which is just like an ACK for */
  538.                 return(state);          /* this packet so fall thru to... */
  539.  
  540.         case 'Y':                       /* ACK */
  541.             if (n != num) return(state); /* If wrong ACK, fail */
  542.             numtry = 0;                 /* Reset try counter */
  543.             n = (n+1)%64;               /* Bump packet count */
  544.             if ((size = bufill(packet)) == EOF) /* Get data from file */
  545.                 return('Z');            /* If EOF set state to that */
  546.             return('D');                /* Got data, stay in state D */
  547.  
  548.         case 'E':                       /* Error packet received */
  549.             prerrpkt(recpkt);           /* Print it out and */
  550.             return('A');                /* abort */
  551.  
  552.         case FALSE: return(state);      /* Receive failure, stay in D */
  553.  
  554.         default:    return('A');        /* Anything else, "abort" */
  555.     }
  556. }
  557.  
  558.  
  559. /*
  560.  *  s e o f
  561.  *
  562.  *  Send End-Of-File.
  563.  */
  564.  
  565. seof()
  566. {
  567.     int num, len;                       /* Packet number, length */
  568.     if (numtry++ > MAXTRY) return('A'); /* If too many tries, "abort" */
  569.  
  570.  
  571.  
  572.  
  573.     spack('Z',n,0,packet);              /* Send a 'Z' packet */
  574.     switch(rpack(&len,&num,recpkt))     /* What was the reply? */
  575.     {
  576.         case 'N':                       /* NAK, just stay in this state, */
  577.             num = (--num<0 ? 63:num);   /* unless it's NAK for next packet, */
  578.             if (n != num)               /* which is just like an ACK for */
  579.                 return(state);          /* this packet so fall thru to... */
  580.  
  581.         case 'Y':                       /* ACK */
  582.             if (n != num) return(state); /* If wrong ACK, hold out */
  583.             numtry = 0;                 /* Reset try counter */
  584.             n = (n+1)%64;               /* and bump packet count */
  585.             if (debug) dbprint("   Closing input file %s, ",filnam);
  586.             fclose(fp);                 /* Close the input file */
  587.             fp = NULL;                  /* Set flag indicating no file open */
  588.  
  589.             if (debug) dbprint("looking for next file...\n");
  590.             if (gnxtfl() == FALSE)      /* No more files go? */
  591.                 return('B');            /* if not, break, EOT, all done */
  592.             if (debug) dbprint("   New file is %s\n",filnam);
  593.             return('F');                /* More files, switch state to F */
  594.  
  595.         case 'E':                       /* Error packet received */
  596.             prerrpkt(recpkt);           /* Print it out and */
  597.             return('A');                /* abort */
  598.  
  599.         case FALSE: return(state);      /* Receive failure, stay in Z */
  600.  
  601.         default:    return('A');        /* Something else, "abort" */
  602.     }
  603. }
  604.  
  605.  
  606. /*
  607.  *  s b r e a k
  608.  *
  609.  *  Send Break (EOT)
  610.  */
  611.  
  612. sbreak()
  613. {
  614.     int num, len;                       /* Packet number, length */
  615.     if (numtry++ > MAXTRY) return('A'); /* If too many tries "abort" */
  616.  
  617.     spack('B',n,0,packet);              /* Send a B packet */
  618.     switch (rpack(&len,&num,recpkt))    /* What was the reply? */
  619.     {
  620.         case 'N':                       /* NAK, just stay in this state, */
  621.             num = (--num<0 ? 63:num);   /* unless NAK for previous packet, */
  622.             if (n != num)               /* which is just like an ACK for */
  623.                 return(state);          /* this packet so fall thru to... */
  624.  
  625.  
  626.  
  627.  
  628.         case 'Y':                       /* ACK */
  629.             if (n != num) return(state); /* If wrong ACK, fail */
  630.             numtry = 0;                 /* Reset try counter */
  631.             n = (n+1)%64;               /* and bump packet count */
  632.             return('C');                /* Switch state to Complete */
  633.  
  634.         case 'E':                       /* Error packet received */
  635.             prerrpkt(recpkt);           /* Print it out and */
  636.             return('A');                /* abort */
  637.  
  638.         case FALSE: return(state);      /* Receive failure, stay in B */
  639.  
  640.         default:    return ('A');       /* Other, "abort" */
  641.    }
  642. }
  643.  
  644.  
  645. /*
  646.  *  r e c s w
  647.  *
  648.  *  This is the state table switcher for receiving files.
  649.  */
  650.  
  651. recsw()
  652. {
  653.  
  654.     if (state == 'R')
  655.     n = 0;                              /* Initialize message number */
  656.     numtry = 0;                         /* Say no tries yet */
  657.  
  658.     while(TRUE)
  659.     {
  660.         if (debug) dbprint(" recsw state: %c\n",state);
  661.         switch(state)                   /* Do until done */
  662.         {
  663.             case 'R':   state = rinit(); break; /* Receive-Init */
  664.             case 'F':   state = rfile(); break; /* Receive-File */
  665.             case 'D':   state = rdata(); break; /* Receive-Data */
  666.             case 'C':   return(TRUE);           /* Complete state */
  667.             case 'A':   return(FALSE);          /* "Abort" state */
  668.         }
  669.     }
  670. }
  671.  
  672.  
  673. /*
  674.  *  r i n i t
  675.  *
  676.  *  Receive Initialization
  677.  */
  678.  
  679. rinit()
  680. {
  681.     int len, num;                       /* Packet length, number */
  682.  
  683.  
  684.  
  685.  
  686.     if (numtry++ > MAXTRY) return('A'); /* If too many tries, "abort" */
  687.  
  688.     switch(rpack(&len,&num,packet))     /* Get a packet */
  689.     {
  690.         case 'S':                       /* Send-Init */
  691.             rpar(packet);               /* Get the other side's init data */
  692.             spar(packet);               /* Fill up packet with my init info */
  693.             spack('Y',n,6,packet);      /* ACK with my parameters */
  694.             oldtry = numtry;            /* Save old try count */
  695.             numtry = 0;                 /* Start a new counter */
  696.             n = (n+1)%64;               /* Bump packet number, mod 64 */
  697.             return('F');                /* Enter File-Receive state */
  698.  
  699.         case 'E':                       /* Error packet received */
  700.             prerrpkt(recpkt);           /* Print it out and */
  701.             return('A');                /* abort */
  702.  
  703.         case FALSE:                     /* Didn't get packet */
  704.             spack('N',n,0,0);           /* Return a NAK */
  705.             return(state);              /* Keep trying */
  706.  
  707.         default:     return('A');       /* Some other packet type, "abort" */
  708.     }
  709. }
  710.  
  711.  
  712. /*
  713.  *  r f i l e
  714.  *
  715.  *  Receive File Header
  716.  */
  717.  
  718. rfile()
  719. {
  720.     int num, len;                       /* Packet number, length */
  721.     char filnam1[50];                   /* Holds the converted file name */
  722.  
  723.     if (numtry++ > MAXTRY) return('A'); /* "abort" if too many tries */
  724.  
  725.     switch(rpack(&len,&num,packet))     /* Get a packet */
  726.     {
  727.         case 'S':                       /* Send-Init, maybe our ACK lost */
  728.             if (oldtry++ > MAXTRY) return('A'); /* If too many tries "abort" */
  729.             if (num == ((n==0) ? 63:n-1)) /* Previous packet, mod 64? */
  730.             {                           /* Yes, ACK it again with  */
  731.                 spar(packet);           /* our Send-Init parameters */
  732.                 spack('Y',num,6,packet);
  733.                 numtry = 0;             /* Reset try counter */
  734.                 return(state);          /* Stay in this state */
  735.             }
  736.             else return('A');           /* Not previous packet, "abort" */
  737.  
  738.  
  739.  
  740.  
  741.         case 'Z':                       /* End-Of-File */
  742.             if (oldtry++ > MAXTRY) return('A');
  743.             if (num == ((n==0) ? 63:n-1)) /* Previous packet, mod 64? */
  744.             {                           /* Yes, ACK it again. */
  745.                 spack('Y',num,0,0);
  746.                 numtry = 0;
  747.                 return(state);          /* Stay in this state */
  748.             }
  749.             else return('A');           /* Not previous packet, "abort" */
  750.  
  751.         case 'F':                       /* File Header (just what we want) */
  752.             if (num != n) return('A');  /* The packet number must be right */
  753.             if (!tmpfil)          /* fix up to make quick access perm file*/
  754.                   {
  755.                   strcpy(filnam1, working_directory);
  756.                   }
  757.             else
  758.                   filnam1[0] = '\0';
  759.             strcat(filnam1, packet);    /* Copy the file name */
  760.             if (!tmpfil)
  761.            /* file names can only be 8 chars */
  762.                 filnam1[(strlen(working_directory) + 8)] = '\0'; 
  763.             else
  764.                 filnam1[8] = '\0';
  765.             if ((fp=fopen(filnam1,"w"))==NULL) /* Try to open a new file */
  766.             {
  767.                 error("Cannot create %s",filnam1); /* Give up if can't */
  768.                 return('A');
  769.             }
  770.             else                        /* OK, give message */
  771.                 printmsg("Receiving %s as %s",packet,filnam1);
  772.  
  773.             spack('Y',n,0,0);           /* Acknowledge the file header */
  774.             oldtry = numtry;            /* Reset try counters */
  775.             numtry = 0;                 /* ... */
  776.             n = (n+1)%64;               /* Bump packet number, mod 64 */
  777.             return('D');                /* Switch to Data state */
  778.  
  779.         case 'B':                       /* Break transmission (EOT) */
  780.             if (num != n) return ('A'); /* Need right packet number here */
  781.             spack('Y',n,0,0);           /* Say OK */
  782.             return('C');                /* Go to complete state */
  783.  
  784.         case 'E':                       /* Error packet received */
  785.             prerrpkt(recpkt);           /* Print it out and */
  786.             return('A');                /* abort */
  787.  
  788.         case FALSE:                     /* Didn't get packet */
  789.             spack('N',n,0,0);           /* Return a NAK */
  790.             return(state);              /* Keep trying */
  791.  
  792.         default:    return ('A');       /* Some other packet, "abort" */
  793.     }
  794. }
  795.  
  796.  
  797.  
  798.  
  799. /*
  800.  *  r d a t a
  801.  *
  802.  *  Receive Data
  803.  */
  804.  
  805. rdata()
  806. {
  807.     int num, len;                       /* Packet number, length */
  808.     if (numtry++ > MAXTRY) return('A'); /* "abort" if too many tries */
  809.  
  810.     switch(rpack(&len,&num,packet))     /* Get packet */
  811.     {
  812.         case 'D':                       /* Got Data packet */
  813.             if (num != n)               /* Right packet? */
  814.             {                           /* No */
  815.                 if (oldtry++ > MAXTRY)
  816.                     return('A');        /* If too many tries, abort */
  817.                 if (num == ((n==0) ? 63:n-1)) /* Else check packet number */
  818.                 {                       /* Previous packet again? */
  819.                     spack('Y',num,6,packet); /* Yes, re-ACK it */
  820.                     numtry = 0;         /* Reset try counter */
  821.                     return(state);      /* Don't write out data! */
  822.                 }
  823.                 else return('A');       /* sorry, wrong number */
  824.             }
  825.             /* Got data with right packet number */
  826.             bufemp(packet,len);         /* Write the data to the file */
  827.             spack('Y',n,0,0);           /* Acknowledge the packet */
  828.             oldtry = numtry;            /* Reset the try counters */
  829.             numtry = 0;                 /* ... */
  830.             n = (n+1)%64;               /* Bump packet number, mod 64 */
  831.             return('D');                /* Remain in data state */
  832.  
  833.         case 'F':                       /* Got a File Header */
  834.             if (oldtry++ > MAXTRY)
  835.                 return('A');            /* If too many tries, "abort" */
  836.             if (num == ((n==0) ? 63:n-1)) /* Else check packet number */
  837.             {                           /* It was the previous one */
  838.                 spack('Y',num,0,0);     /* ACK it again */
  839.                 numtry = 0;             /* Reset try counter */
  840.                 return(state);          /* Stay in Data state */
  841.             }
  842.             else return('A');           /* Not previous packet, "abort" */
  843.  
  844.         case 'Z':                       /* End-Of-File */
  845.             if (num != n) return('A');  /* Must have right packet number */
  846.             spack('Y',n,0,0);           /* OK, ACK it. */
  847.             fclose(fp);                 /* Close the file */
  848.             n = (n+1)%64;               /* Bump packet number */
  849.             return('F');                /* Go back to Receive File state */
  850.  
  851.         case 'E':                       /* Error packet received */
  852.             prerrpkt(recpkt);           /* Print it out and */
  853.             return('A');                /* abort */
  854.  
  855.  
  856.  
  857.  
  858.         case FALSE:                     /* Didn't get packet */
  859.             spack('N',n,0,0);           /* Return a NAK */
  860.             return(state);              /* Keep trying */
  861.  
  862.         default:     return('A');       /* Some other packet, "abort" */
  863.     }
  864. }
  865.  
  866. /*
  867.  *      KERMIT utilities.
  868.  */
  869.  
  870. /*
  871.  *  s p a c k
  872.  *
  873.  *  Send a Packet
  874.  */
  875.  
  876. spack(type,num,len,data)
  877. char  *data;
  878. int num, len, type;
  879. {
  880.     int i,chksum;                       /* Character loop counter */
  881.     char  buffer[100];           /* Checksum, packet buffer */
  882.     register char *bufp;                /* Buffer pointer */
  883.  
  884.     if (debug>1)                        /* Display outgoing packet */
  885.     {
  886.         if (data != NULL)
  887.             data[len] = '\0';           /* Null-terminate data to print it */
  888.         dbprint("  spack type: %c\n",type);
  889.         dbprint("         num:  %d\n",num);
  890.         dbprint("         len:  %d\n",len);
  891.         if (data != NULL)
  892.             dbprint("        data: \"%s\"\n",data);
  893.     }
  894.  
  895.     bufp = buffer;                      /* Set up buffer pointer */
  896.     for (i=1; i<=pad; i++) putchar(padchar); /* Issue any padding */
  897.  
  898.     *bufp++ = SOH;                      /* Packet marker, ASCII 1 (SOH) */
  899.     *bufp++ = tochar(len+3);            /* Send the character count */
  900.     chksum  = tochar(len+3);            /* Initialize the checksum */
  901.     *bufp++ = tochar(num);              /* Packet number */
  902.     chksum += tochar(num);              /* Update checksum */
  903.     *bufp++ = type;                     /* Packet type */
  904.     chksum += type;                     /* Update checksum */
  905.  
  906.  
  907.  
  908.  
  909.     for (i=0; i<len; i++)               /* Loop for all data characters */
  910.     {
  911.         *bufp++ = data[i];              /* Get a character */
  912.         chksum += data[i];              /* Update checksum */
  913.     }
  914.     chksum = (((chksum&0300) >> 6)+chksum)&077; /* Compute final checksum */
  915.     *bufp++ = tochar(chksum);           /* Put it in the packet */
  916.     *bufp++ = eol;                        /* Extra-packet line terminator */
  917.     *bufp = '\0';                       /* make it a string */
  918.     write(1, buffer, bufp-buffer+1); /* Send the packet */
  919. }
  920.  
  921. /*
  922.  *  r p a c k
  923.  *
  924.  *  Read a Packet
  925.  */
  926.  
  927. rpack(len,num,data)
  928. int *len, *num;                         /* Packet length, number */
  929. char *data;                             /* Packet data */
  930. {
  931.     int i, done;                        /* Data character number, loop exit */
  932.     char t,                             /* Current input character */
  933.         type,                           /* Packet type */
  934.         cchksum,                        /* Our (computed) checksum */
  935.         rchksum;                        /* Checksum received from other host */
  936.  
  937.     while (t != SOH)                    /* Wait for packet header */
  938.     {
  939.         t = getchar();
  940.         t &= 0177;                      /* Handle parity */
  941.     }
  942.  
  943.     done = FALSE;                       /* Got SOH, init loop */
  944.     while (!done)                       /* Loop to get a packet */
  945.     {
  946.         t = getchar();               /* Get character */
  947.         if (!image) t &= 0177;          /* Handle parity */
  948.         if (t == SOH) continue;         /* Resynchronize if SOH */
  949.         cchksum = t;                    /* Start the checksum */
  950.         *len = unchar(t)-3;             /* Character count */
  951.  
  952.         t = getchar();               /* Get character */
  953.         if (!image) t &= 0177;          /* Handle parity */
  954.         if (t == SOH) continue;         /* Resynchronize if SOH */
  955.         cchksum = cchksum + t;          /* Update checksum */
  956.         *num = unchar(t);               /* Packet number */
  957.  
  958.  
  959.  
  960.  
  961.         t = getchar();               /* Get character */
  962.         if (!image) t &= 0177;          /* Handle parity */
  963.         if (t == SOH) continue;         /* Resynchronize if SOH */
  964.         cchksum = cchksum + t;          /* Update checksum */
  965.         type = t;                       /* Packet type */
  966.  
  967.         for (i=0; i<*len; i++)          /* The data itself, if any */
  968.         {                               /* Loop for character count */
  969.             t = getchar();           /* Get character */
  970.             if (!image) t &= 0177;      /* Handle parity */
  971.             if (t == SOH) continue;     /* Resynch if SOH */
  972.             cchksum = cchksum + t;      /* Update checksum */
  973.             data[i] = t;                /* Put it in the data buffer */
  974.         }
  975.         data[*len] = 0;                 /* Mark the end of the data */
  976.  
  977.         t = getchar();               /* Get last character (checksum) */
  978.         rchksum = unchar(t);            /* Convert to numeric */
  979.         t = getchar();               /* get EOL character and toss it */
  980.         if (!image) t &= 0177;          /* Handle parity */
  981.         if (t == SOH) continue;         /* Resynchronize if SOH */
  982.         done = TRUE;                    /* Got checksum, done */
  983.     }
  984.  
  985.  
  986.     if (debug>1)                        /* Display incoming packet */
  987.     {
  988.         if (data != NULL)
  989.             data[*len] = '\0';          /* Null-terminate data to print it */
  990.         dbprint("  rpack type: %c\n",type);
  991.         dbprint("         num:  %d\n",*num);
  992.         dbprint("         len:  %d\n",*len);
  993.         if (data != NULL)
  994.             dbprint("        data: \"%s\"\n",data);
  995.     }
  996.                                         /* Fold in bits 7,8 to compute */
  997.     cchksum = (((cchksum&0300) >> 6)+cchksum)&077; /* final checksum */
  998.  
  999.     if (cchksum != rchksum) return(FALSE);
  1000.  
  1001.     return(type);                       /* All OK, return packet type */
  1002. }
  1003.  
  1004.  
  1005. /*
  1006.  *  b u f i l l
  1007.  *
  1008.  *  Get a bufferful of data from the file that's being sent.
  1009.  *  Only control-quoting is done; 8-bit & repeat count prefixes are
  1010.  *  not handled.
  1011.  */
  1012.  
  1013.  
  1014.  
  1015.  
  1016. bufill(buffer)
  1017. char buffer[];                          /* Buffer */
  1018. {
  1019.     int i,                              /* Loop index */
  1020.         t;                              /* Char read from file */
  1021.     char t7;                            /* 7-bit version of above */
  1022.  
  1023.     i = 0;                              /* Init data buffer pointer */
  1024.     while((t = getc(fp)) != EOF)        /* Get the next character */
  1025.     {
  1026.         t7 = t & 0177;                  /* Get low order 7 bits */
  1027.  
  1028.         if (t7 < SP || t7==DEL || t7==quote) /* Does this char require */
  1029.         {                                   /* special handling? */
  1030.             if (t=='\n' && !image)
  1031.             {                           /* Do LF->CRLF mapping if !image */
  1032.                 buffer[i++] = quote;
  1033.                 buffer[i++] = ctl('\r');
  1034.             }
  1035.             buffer[i++] = quote;        /* Quote the character */
  1036.             if (t7 != quote)
  1037.             {
  1038.                 t = ctl(t);             /* and uncontrolify */
  1039.                 t7 = ctl(t7);
  1040.             }
  1041.         }
  1042.         if (image)
  1043.             buffer[i++] = t;            /* Deposit the character itself */
  1044.         else
  1045.             buffer[i++] = t7;
  1046.  
  1047.         if (i >= spsiz-8) return(i);    /* Check length */
  1048.     }
  1049.     if (i==0) return(EOF);              /* Wind up here only on EOF */
  1050.     return(i);                          /* Handle partial buffer */
  1051. }
  1052.  
  1053.  
  1054. /*
  1055.  *      b u f e m p
  1056.  *
  1057.  *  Put data from an incoming packet into a file.
  1058.  */
  1059.  
  1060. bufemp(buffer,len)
  1061. char  buffer[];                         /* Buffer */
  1062. int   len;                              /* Length */
  1063. {
  1064.     int i;                              /* Counter */
  1065.     char t;                             /* Character holder */
  1066.  
  1067.  
  1068.  
  1069.  
  1070.     for (i=0; i<len; i++)               /* Loop thru the data field */
  1071.     {
  1072.         t = buffer[i];                  /* Get character */
  1073.         if (t == MYQUOTE)               /* Control quote? */
  1074.         {                               /* Yes */
  1075.             t = buffer[++i];            /* Get the quoted character */
  1076.             if ((t & 0177) != MYQUOTE)  /* Low order bits match quote char? */
  1077.                 t = ctl(t);             /* No, uncontrollify it */
  1078.         }
  1079.         if (t==CR && !image)            /* Don't pass CR if in image mode */
  1080.             continue;
  1081.  
  1082.         putc(t,fp);
  1083.     }
  1084. }
  1085.  
  1086.  
  1087. /*
  1088.  *  g n x t f l
  1089.  *
  1090.  *  Get next file in a file group
  1091.  */
  1092.  
  1093. gnxtfl()
  1094. {
  1095.  static char savename[60];
  1096.     if (filecount-- <= 0)
  1097.          return(FALSE);
  1098.     if (debug)
  1099.          dbprint("    gnxtfl: filecount = %d\n", filecount);
  1100.     if (debug) dbprint("   gnxtfl: filelist = \"%s\"\n",*filelist);
  1101.     filnam = *(filelist++);
  1102.     if (cflg)     /* want cwd processing ? */
  1103.         {
  1104.         strcpy(savename, working_directory);
  1105.         strcat(savename, filnam);
  1106.         filnam = savename;
  1107.         }
  1108.     return(TRUE);
  1109. }
  1110.  
  1111.  
  1112. /*
  1113.  *  s p a r
  1114.  *
  1115.  *  Fill the data array with my send-init parameters
  1116.  *
  1117.  */
  1118.  
  1119. spar(data)
  1120. char data[];
  1121. {
  1122.     data[0] = tochar(MAXPACKSIZ);          /* Biggest packet I can receive */
  1123.     data[1] = tochar(MYTIME);           /* When I want to be timed out */
  1124.     data[2] = tochar(MYPAD);            /* How much padding I need */
  1125.     data[3] = ctl(MYPCHAR);             /* Padding character I want */
  1126.     data[4] = tochar(MYEOL);            /* End-Of-Line character I want */
  1127.     data[5] = MYQUOTE;                  /* Control-Quote character I send */
  1128. }
  1129.  
  1130.  
  1131.  
  1132.  
  1133. /*  r p a r
  1134.  *
  1135.  *  Get the other host's send-init parameters
  1136.  *
  1137.  */
  1138.  
  1139. rpar(data)
  1140. char data[];
  1141. {
  1142.     spsiz = unchar(data[0]);            /* Maximum send packet size */
  1143.     timint = unchar(data[1]);           /* When I should time out */
  1144.     pad = unchar(data[2]);              /* Number of pads to send */
  1145.     padchar = ctl(data[3]);             /* Padding character to send */
  1146.     eol = unchar(data[4]);              /* EOL character I must send */
  1147.     quote = data[5];                    /* Incoming data quote character */
  1148. }
  1149.  
  1150.  
  1151. /*
  1152.  *  Kermit printing routines:
  1153.  *
  1154.  *  usage - print command line options showing proper syntax
  1155.  *  printmsg -  like printf with "Kermit: " prepended
  1156.  *  error - like printmsg if local kermit; sends a error packet if remote
  1157.  *  prerrpkt - print contents of error packet received from remote host
  1158.  */
  1159.  
  1160. /*
  1161.  *  u s a g e
  1162.  *
  1163.  *  Print summary of usage info and quit
  1164.  */
  1165.  
  1166. usage()
  1167. {
  1168.     printf("Usage:    kermit s[d] file ...          (send mode)\n");
  1169.     printf("   or:    kermit r[dt]                  (receive mode)\n");
  1170.     printf("   or:    kermit sv                     (server mode)\n");
  1171.     printf("   or:    kermit sc file ...            (cwd & send)\n");
  1172.     printf("   or:    kermit rc                     (cwd & receive)\n");
  1173.     printf("   or:    kermit svc                    (cwd & server)\n");
  1174.     exit(1);
  1175. }
  1176.  
  1177. /*
  1178.  *  p r i n t m s g
  1179.  *
  1180.  *  Print message on standard output if not remote.
  1181.  */
  1182.  
  1183. /*VARARGS1*/
  1184. printmsg(fmt, a1, a2, a3, a4, a5)
  1185. char *fmt;
  1186. {
  1187.     if (!remote)
  1188.     {
  1189.         printf("Kermit-GCOS: ");
  1190.         printf(fmt,a1,a2,a3,a4,a5);
  1191.         printf("\n");
  1192.         fflush(stdout);                 /* force output (UTS needs it) */
  1193.     }
  1194.    if (debug)
  1195.        dbprint(fmt, a1, a2, a3, a4, a5);
  1196. }
  1197.  
  1198.  
  1199.  
  1200.  
  1201. /*
  1202.  *  e r r o r
  1203.  *
  1204.  *  Print error message.
  1205.  *
  1206.  *  If local, print error message with printmsg.
  1207.  *  If remote, send an error packet with the message.
  1208.  */
  1209. static char prefmt[80] = "Kermit-GCOS:";
  1210. /*VARARGS1*/
  1211. error(fmt, a1, a2, a3, a4, a5)
  1212. char *fmt;
  1213. {
  1214.     char msg[80];
  1215.     int len;
  1216.     strcpy(&prefmt[12], fmt);
  1217.     if (remote)
  1218.     {
  1219.         sprintf(msg,prefmt,a1,a2,a3,a4,a5); /* Make it a string */
  1220.         len = strlen(msg);
  1221.         spack('E',n,len,msg);           /* Send the error packet */
  1222.     }
  1223.     else
  1224.         printmsg(prefmt, a1, a2, a3, a4, a5);
  1225.  
  1226.     return;
  1227. }
  1228.  
  1229. /*
  1230.  *  p r e r r p k t
  1231.  *
  1232.  *  Print contents of error packet received from remote host.
  1233.  */
  1234. prerrpkt(msg)
  1235. char *msg;
  1236. {
  1237.     printf("Kermit aborting with following error from remote host:\n%s\n",
  1238.             msg);
  1239.     return;
  1240. }
  1241.  
  1242.  
  1243. dbprint(fmt,arg1,arg2,arg3,arg4,arg5,arg6)
  1244. char *fmt;
  1245. {
  1246.    fprintf(fddebug,fmt,arg1,arg2,arg3,arg4,arg5,arg6);
  1247. }
  1248. /* Handle tty breaks comming from micro */
  1249. dobreak()
  1250. {
  1251.      fprintf(stderr, "*break*%c\n",007);
  1252.      if (debug)
  1253.          fclose(fddebug);
  1254.      exit();
  1255. }
  1256. /* the following is a datanet-8 model required for kermit-gcos to run */
  1257. /*                                                                    */
  1258. /* The TTY BREAK is disabled and a control-Y substituted for a break  */
  1259. /* the Backspace is used for character delete and the @ sign is passed*/
  1260. /* as data                                                            */
  1261. /*
  1262. MODEL PCTRAN  ASY -ASCI                                                &
  1263.                   -LINE 250                                            &
  1264.                   -LTSZ 256                                            &
  1265.                   -SY96                                                &
  1266.                   -STOP 1:2                                            &
  1267.                   -OVSZ 2048                                           &
  1268.                   -MCOL X'20'                                          &
  1269.                   -MLIN X'20'                                          &
  1270.                   -TYPE 23                                             &
  1271.                   -FILL X'00' 0                                        &
  1272.                   -BRK ATT1                                            &
  1273.                   -ATT0 X'17'                                          &
  1274.                   -ATT1 X'19'                                          &
  1275.                   -ATT2 X'1A'                                          &
  1276. -INEFF  X'00' IGN   0     0     *               *                      &
  1277. -INEFF  X'02' FUN   0     0     *               *                      &
  1278. -CR     X'03' FUN   0     0     X'0A':X'0D' X'0A':X'0D'                &
  1279. -MTROFF X'04' FUN   3     0     *               X'04'                  &
  1280. -INEFF  X'05' IGN   0     0     *               *                      &
  1281. -INEFF  X'06' IGN   0     0     *               *                      &
  1282. -INEFF  X'07' NOR   0     0     *               *                      &
  1283. -BAKSP  X'08' ANN   0     0     *               *                      &
  1284. -HT     X'09' NOR   0     0     *               *                      &
  1285. -LF     X'0A' FUN   0     0     X'0D'           X'0D':X'0A'            &
  1286. -VT     X'0B' FUN   0     0     *               *                      &
  1287. -CR     X'0D' FUN   0     0     X'0D':X'0A'     X'0D':X'0A'            &
  1288. -INEFF  X'0E' NOR   0     0     *               *                      &
  1289. -INEFF  X'0F' NOR   0     0     *               *                      &
  1290. -RPTL   X'10' FUN   0     0     *               *                      &
  1291. -INEFF  X'11' NOR   0     0     *               *                      &
  1292. -INEFF  X'12' NOR   0     0     *               *                      &
  1293. -INEFF  X'13' NOR   0     0     *               *                      &
  1294. -INEFF  X'14' NOR   0     0     *               *                      &
  1295. -ETX    X'15' FUN   0     0     *               *                      &
  1296. -INEFF  X'16' FUN   0     0     *               *                      &
  1297. -EFLIN  X'18' FUN   0     0     X'20':X'44':X'45':X'4C':X'0D':X'0A'    &
  1298. -INEFF  X'1B' NOR   0     0     *               *                      &
  1299. -INEFF  X'1C' FUN   0     0     *               *                      &
  1300. -INEFF  X'1D' FUN   0     0     *               *                      &
  1301. -INEFF  X'1E' FUN   0     0     *               *                      &
  1302. -INEFF  X'1F' FUN   0     0     *               *                      &
  1303.  *
  1304.  */
  1305. /* If the site has NPS, it must be configured to allow SOH (001),*
  1306.  * and all printable characters to pass thru as data.  It is     *
  1307.  * a good idea to configure the control-Y key for a break key.   *
  1308.  */
  1309.