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

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