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

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