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