home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / COMM / MISC / SRC26_2.ZIP / SRC / KERMIT.C < prev    next >
Encoding:
C/C++ Source or Header  |  1990-07-12  |  39.5 KB  |  1,387 lines

  1. /*
  2.  * kermit.c: hterm kermit
  3.  *
  4.  * NO COPYRIGHT
  5.  *
  6.  * TODO:
  7.  *    receive transfer percentage
  8.  *
  9.  * 1.1 89/07/20 mnr ported by mnr@tkl.seiken.u-tokyo from unix kermit
  10.  * 1.2 89/07/20 Halca.Hirano add kermit panel, time out, user interface, etc.
  11.  *     ----- V2.3.-1 distributin ----
  12.  * 1.3 89/09/19 Halca.Hirano add user abort
  13.  *    fix incorrect transfer rate
  14.  *     ---- V2.4.0 distribution ----
  15.  * 1.4 89/10/22 Halca.Hirano
  16.  *    add 8bit prefix feature for 7bit line users.
  17.  * 1.5 89/10/26 Halca.Hirano
  18.  *    add long packet capability, but unusable yet.
  19.  * 1.6 89/12/01 Halca.Hirano
  20.  *    long packet is now available.
  21.  * 1.7 89/12/12 Halca.Hirano
  22.  *    move getnext() in file.c
  23.  *    all public functions are callable from comm. mode as well as from setup.
  24.  * 1.8 90/01/16 Halca.Hirano
  25.  *    get rid of bugs which make devide by 0 error
  26.  * 1.9 90/05/27 Halca.Hirano
  27.  *    BUG:
  28.  *        if pier kermit is normal kermit which is without long packet capability
  29.  *            and long packet mode
  30.  *        -> long packet request was sent
  31.  *    FIX:
  32.  *        -> request size which is requested by pier
  33.  * 2.1 90/06/18 Halca.Hirano
  34.  *    use only one packet buffer for sending and receiving
  35.  * 2.2 90/06/26 Halca.Hirano
  36.  *    fix receive packet size bug
  37.  *
  38.  * $Header: kermit.cv  1.15  90/07/04 18:01:14  hirano  Exp $
  39.  *
  40.  */
  41. /*
  42. ** Hterm kermit file transfer module
  43. **
  44. **    This module derived from UNIX KERMIT program.
  45. **    Original program has next HEADER.
  46. **    Columbia kermit is free ware!
  47. **
  48. */
  49.  
  50. /*
  51.  *  K e r m i t     File Transfer Utility
  52.  *
  53.  *  UNIX Kermit, Columbia University, 1981, 1982, 1983
  54.  *    Bill Catchings, Bob Cattani, Chris Maio, Frank da Cruz, Alan Crosswell
  55.  *
  56.  *  Also:   Jim Guyton, Rand Corporation
  57.  *        Walter Underwood, Ford Aerospace
  58.  *
  59.  *  usage:  kermit c [lbe line baud escapechar]        to connect
  60.  *        kermit s [d..iflb line baud] file ...    to send files
  61.  *        kermit r [d..iflb line baud]        to receive files
  62.  *
  63.  *  where   c=connect, s=send, r=receive,
  64.  *        d=debug, i=image mode, f=no filename conversion, l=tty line,
  65.  *        b=baud rate, e=escape char.
  66.  *
  67.  *  For remote Kermit, format is either:
  68.  *        kermit r                    to receive files
  69.  *  or        kermit s file ...                to send files
  70.  *
  71.  */
  72.  
  73. /*
  74.  *  Modification History:
  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 xprintMsg 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. #include "option.h"
  94. #ifdef KERMIT
  95.  
  96. #include    <stdio.h>        /* Standard UNIX definitions */
  97. #include    <setjmp.h>
  98. #if !defined(__TURBOC__) || __TURBOC__ >= 0x0200
  99. #include    <sys/types.h>
  100. #endif
  101. #include    <sys/stat.h>
  102. #include    <string.h>
  103. #include     "config.h"
  104. #include    "hterm.h"
  105. #include    "default.h"
  106. #include    "global.h"
  107.  
  108. /*
  109.  * Symbol Definitions 
  110.  */
  111. #define    MAX_LONG_PACKET_SIZE    1024    /* Maximum packet size */
  112. #define    MAX_SHORT_PACKET_SIZE    94    /* Maximum packet size */
  113.  
  114. #define MAX_TRY            10            /* Times to retry a packet */
  115. #define MY_QUOTE        '#'            /* Quote character I will use */
  116. #define MY_PAD            0            /* Number of padding characters I will need */
  117. #define MY_PAD_CHAR        0            /* Padding character I need (NULL) */
  118. #define MY_EOL            '\r'        /* End-Of-Line character I need */
  119. #define MY_8BIT_CHAR    '&'            /* 8bit prefix char        */
  120.  
  121. #define MY_TIME            10            /* Seconds after which I should be timed out */
  122. #define MAX_TIME        60            /* Maximum timeout interval */
  123. #define MIN_TIME        2            /* Minumum timeout interval */
  124.  
  125. #define LONG_PACKET_BIT    2            /* CAPAS field long packet bit    */
  126. #define SLIDING_WINDOW_BIT 4
  127. #define ATTRIBUTE_BIT    8
  128. #define CAPAS            10            /* capabilities field index    */
  129.  
  130. #define TRUE            -1            /* Boolean constants */
  131. #define FALSE            0
  132.  
  133. /* Macro Definitions */
  134. /*
  135.  * tochar: converts a control character to a printable one by adding a space.
  136.  *
  137.  * unchar: undoes tochar.
  138.  *
  139.  * ctl:       converts between control characters and printable characters by
  140.  *       toggling the control bit (ie. ^A becomes A and A becomes ^A).
  141.  */
  142. #define tochar(ch)        ((ch) + ' ')
  143. #define unchar(ch)      ((ch) - ' ')
  144. #define ctl(ch)            ((ch) ^ 64 )
  145.  
  146. /* Global Variables */
  147. static int    recflg = 0;                /* Now receiving, activate timer    */
  148.  
  149. static int    size;                    /* Size of present data */
  150. static int    rpsiz;                    /* Maximum receive packet size */
  151. static int    spsiz;                    /* Maximum send packet size */
  152. static int    pad;                    /* How much padding to send */
  153. static int    timint;                    /* Timeout for foreign host on sends */
  154. static int    n;                        /* Packet number */
  155. static int    numtry;                    /* Times this packet retried */
  156. static int    oldtry;                    /* Times previous packet retried */
  157. static int    slen;                    /* sent bytes             */
  158. static long    sendnum;                /* internal counter for print stat */
  159. static long    recnum;                    /* internal counter for print stat */
  160. static int    rlen;                    /* received bytes             */
  161. static int    totalRetry;                /* total retry counter thru transferring */
  162. static int    rateTimer;                /* a counter for transfer rate measurment */
  163. static long    bytes;                    /* bytes transferred        */
  164. static long    lastBytes;                /* bytes transferred for rate    */
  165. static long    bytesToSend;            /* bytes to send for percentage    */
  166. static int    bit8Prefix;                /* bit8 prefix char        */
  167. static int    bit8PrefixUsed;            /* bit8 prefix is used        */
  168. static int    bit8PrefixRequested;    /* bit8 prefix requested flag    */
  169. static int    sentBit8Prefix;            /* bit8 prefix my request    */
  170.  
  171. static char    state;                    /* Present state of the automaton */
  172. static char    padchar;                   /* Padding character to send */
  173. static char eol;                    /* End-Of-Line character to send */
  174. static char    quote;                       /* Quote character in incoming data */
  175. static char    *fileList;                /* List of files to be sent */
  176. static char    *filnam;                /* Current file name     */
  177. static char    *packet = XFerBuffer;    /* Packet buffer                     */
  178.     
  179. static FILE    *fp;                    /* File pointer for current disk file */
  180. static jmp_buf env;                    /* Environment ptr for timeout longjump */
  181. static char localFile[MAX_FILE_NAME] = DEFAULT_KERMIT_FILENAME;
  182. static int oldMode;                    /* caller's mode            */
  183.  
  184. static long LZERO = 0L;
  185. /*
  186.  * prototypes
  187.  */
  188. int sendsw(void);
  189. char sinit(void);
  190. char sfile(void);
  191. char sdata(void);
  192. char seof(void);
  193. char sbreak(void);
  194. int recsw(void);
  195. char rinit(void);
  196. char rfile(void);
  197. char rdata(void);
  198. int finishsw(void);
  199. char dofinish(void);
  200. int  doget(void);
  201. void tellAbort(void);
  202. void clkint(int v);
  203. int updateRetry(void);
  204. void spack(char, int, int, char *);
  205. int rpack(int *, int *, char *);
  206. int bufill(char []);
  207. int bufemp(char [], int);
  208. void spar(char []);
  209. void rpar(char [], int);
  210. void msgAbort(void);
  211. void kread(char *, int);
  212. void kwrite(char *, int);
  213. #define alarm(n) (kermitTimer = n * TICK_SEC)
  214. #define kwrite(buf,len) rowOutPortBuffer(buf, len)
  215.  
  216. int kbegin(msg)
  217. char *msg;
  218. {
  219.     oldMode = mode;
  220.     mode = M_SETUP;
  221.     if (oldMode == M_COMM)
  222.         showPage1();
  223.  
  224.     if (*msg && (emacs(msg, localFile, MAX_FILE_NAME, (E_HELP|E_FILE)) == ERR 
  225.             || localFile[0] == '\0')) {
  226.         if (oldMode == M_COMM)
  227.             showPage0();
  228.         mode = oldMode;
  229.         return(NO);
  230.     }
  231.     /*
  232.      *  Initialize these values and hope the first packet will get across OK 
  233.      */
  234.     eol = CR;            /* EOL for outgoing packets */
  235.     quote = '#';            /* Standard control-quote char "#" */
  236.     pad = 0;            /* No padding */
  237.     padchar = NULL;            /* Use null if any padding wanted */
  238.     rpsiz = xmodemLongP ? MAX_LONG_PACKET_SIZE : MAX_SHORT_PACKET_SIZE;
  239.     spsiz = xmodemLongP ? MAX_LONG_PACKET_SIZE : MAX_SHORT_PACKET_SIZE;
  240.     bit8Prefix = MY_8BIT_CHAR;    /* bit8 prefix char        */
  241.     bit8PrefixUsed = NO;        /* bit8 prefix is not used    */
  242.     bit8PrefixRequested = -1;    /* request unknown        */
  243.     sentBit8Prefix = 'Y';        /* bit8 prefix my request    */
  244.  
  245.     bytes = 0;
  246.     sendnum = LZERO;            /* internal counter for print stat */
  247.     recnum = LZERO;
  248.     totalRetry = 0;
  249.  
  250.     /*
  251.      * initial screen
  252.      */
  253.     xferPanel("kermit");
  254.     xprintMsg(X_PROTOCOL, "kermit", LZERO);
  255.     showHelp = 1;
  256.     downLoading = YES;
  257.     return(YES);
  258. }
  259.  
  260. void kend(msg, status)
  261. char *msg;
  262. int status;
  263. {
  264.     downLoading = NO;
  265.     if (fp)
  266.         fclose(fp);
  267.     bell();
  268.  
  269.     if (oldMode == M_COMM) {
  270.         showPage0();
  271.         putComment(msg, (status == FALSE) ? " failed" : " done");
  272.     }
  273.     mode = oldMode;
  274. }
  275.  
  276. void krec()
  277. {
  278.     int status;
  279.  
  280.     if (kbegin("") == NO)            /*Initialize variable    */
  281.         return;
  282.     xprintMsg(X_STATUS, "Receive", LZERO);
  283.     if ((status = recsw()) == FALSE)    /* Receive the file(s) */
  284.         xprintMsg(X_STATUS, "Receive failed", LZERO);
  285.     else                /* Report failure */
  286.         xprintMsg(X_STATUS, "Receive done", LZERO);
  287.     kend("rec", status);
  288. }
  289.  
  290. void ksend()
  291. {
  292.     int status;
  293.  
  294.     if (kbegin("Kermit send files: ") == NO)            /* Initialize variable    */
  295.         return;
  296.     fp = NULL;            /* Indicate no file open yet */
  297.  
  298.     fileList = localFile;
  299.     status = FALSE;
  300.     if (getNextFileName(1, &fileList, &filnam, NO) != NO) {    /* set first file name    */
  301.         xprintMsg(X_STATUS, "Send", LZERO);
  302.         if ((status  = sendsw()) == FALSE)        /* Send the file(s) */
  303.             xprintMsg(X_STATUS, "Send failed", LZERO);
  304.         else                    /*  or */
  305.             xprintMsg(X_STATUS, "Send done", LZERO);
  306.     } else {
  307.         sprintf(packet, "%s not found", localFile);
  308.         xprintMsg(X_ERROR, packet, LZERO);
  309.         bell();
  310.     }
  311.     kend("send", status);
  312. }
  313.  
  314. /*
  315. ** Issue 'finish' packette
  316. */
  317. void kfinish()
  318. {
  319.     int status;
  320.  
  321.     kbegin("");
  322.     xprintMsg(X_STATUS, "Finish remote server", LZERO);
  323.     if ((status = finishsw()) == FALSE)
  324.         xprintMsg(X_STATUS, "Finish failed", LZERO);
  325.     else
  326.         xprintMsg(X_STATUS, "Finish done", LZERO);
  327.     kend("finish", status);
  328. }
  329.  
  330. void kget()
  331. {
  332.     int status;
  333.     
  334.     if (kbegin("Kermit remote file: ") == NO)            /* Initialize variable    */
  335.         return;
  336.     fp = NULL;            /* Indicate no file open yet */
  337.     filnam = localFile;
  338.  
  339.     xprintMsg(X_STATUS, "Get", LZERO);
  340.     if ((status = doget()) == FALSE)        /* Send the file(s) */
  341.         xprintMsg(X_STATUS, "Get failed", LZERO);
  342.     else                    /*  or */
  343.         xprintMsg(X_STATUS, "Get Done", LZERO);
  344.     kend("get", status);
  345. }
  346.  
  347. /*
  348. **  sendsw()
  349.  *
  350.  *  Sendsw is the state table switcher for sending files.  It loops until
  351.  *  either it finishes, or an error is encountered.  The routines called
  352.  *  by sendsw are responsible for changing the state.
  353.  *
  354.  */
  355. static int sendsw()
  356. {
  357.     state = 'S';            /* Send initiate is the start state */
  358.     n = 0;                /* Initialize message number */
  359.     numtry = 0;                /* Say no tries yet */
  360.     totalRetry = 0;
  361.     while(TRUE) {                /* Do this as long as necessary */
  362.         switch(state) {
  363.             case 'S':    state = sinit();  break; /* Send-Init */
  364.             case 'F':    state = sfile();  break; /* Send-File */
  365.             case 'D':    state = sdata();  break; /* Send-Data */
  366.             case 'Z':    state = seof();      break; /* Send-End-of-File */
  367.             case 'B':    state = sbreak(); break; /* Send-Break */
  368.             case 'C':    return (TRUE);         /* Complete */
  369.             case 'A':    return (FALSE);         /* "Abort" */
  370.             default:    return (FALSE);         /* Unknown, fail */
  371.         }
  372.     }
  373. }
  374.  
  375. /*
  376. **  sinit()
  377.  *
  378.  *  Send Initiate: send this host's parameters and get other side's back.
  379.  */
  380. static char sinit()
  381. {
  382.     int num, len;            /* Packet number, length */
  383.  
  384.     if (updateRetry())
  385.         return('A');
  386.     spar(packet);            /* Fill up init info packet */
  387.  
  388.     flushInputBuffer();            /* Flush pending input */
  389.  
  390.     spack('S', n, strlen(packet), packet);        /* Send an S packet */
  391.     switch(rpack(&len, &num, packet)) {    /* What was the reply? */
  392.         case 'N':  
  393.             return(state);                /* NAK, try it again */
  394.         case 'Y':                        /* ACK */
  395.             if (n != num)                /* If wrong ACK, stay in S state */
  396.                 return(state);            /* and try again */
  397.             rpar(packet, len);            /* Get other side's init info */
  398.  
  399.             if (eol == 0) 
  400.                 eol = '\n';    /* Check and set defaults */
  401.             if (quote == 0) 
  402.                 quote = '#';
  403.  
  404.             numtry = 0;            /* Reset try counter */
  405.             n = (n+1)%64;        /* Bump packet count */
  406.             xprintMsg(X_PSIZE, NULL, (long)spsiz);
  407.             return('F');        /* OK, switch state to F */
  408.         case 'E':            /* Error packet received */
  409.             xprintMsg(X_ERROR, packet, LZERO);    /* print error msg    */
  410.             return('A');        /* abort */
  411.         case FALSE: 
  412.             return(state);    /* Receive failure, try again */
  413.         case 'Q':            /* aborted by user        */
  414.             msgAbort();
  415.             tellAbort();        /* send 'E' packet        */
  416.             return('A');
  417.         default:
  418.             return('A');        /* Anything else, just "abort" */
  419.     }
  420. }
  421.  
  422. /*
  423. **  sfile()
  424.  *
  425.  *  Send File Header.
  426.  */
  427. static char sfile()
  428. {
  429.     int num, len;            /* Packet number, length */
  430.     char *cp;                /* char pointer */
  431.     struct stat fileStat;
  432.  
  433.     if (updateRetry())
  434.         return('A');
  435.     
  436.     if (fp == NULL) {            /* If not already open, */
  437.         xprintMsg(X_FILENAME, filnam, LZERO);
  438.         if ((fp = fopen(filnam,"rb")) == NULL) {
  439.             sprintf(packet, "'%s' open failed", filnam);
  440.             xprintMsg(X_ERROR, packet, LZERO);
  441.             return('A');
  442.         }
  443.     }
  444.  
  445.     cp = strrchr(filnam, '/');
  446.     if (cp)
  447.         cp++;
  448.     else
  449.         cp = filnam;
  450.  
  451.     fstat(fileno(fp), &fileStat);
  452.     bytesToSend = fileStat.st_size;    /* set file size to send    */
  453.     xprintMsg(X_PERCENT, NULL, LZERO);
  454.     rateTimer = 4;                    /* sample per 4 packets */
  455.     timerValue = 30000;
  456.     lastBytes = 0;
  457.  
  458.     xprintMsg(X_FILENAME, cp, LZERO);    /* display file name        */
  459.     spack('F',n,strlen(cp),cp);        /* Send an F packet */
  460.     switch(rpack(&len,&num,packet))    { /* What was the reply? */
  461.         case 'N':            /* NAK, just stay in this state, */
  462.             num = (--num<0 ? 63:num);    /* unless it's NAK for next packet */
  463.             if (n != num)        /* which is just like an ACK for */ 
  464.                 return(state);        /* this packet so fall thru to... */
  465.         case 'Y':            /* ACK */
  466.             if (n != num) 
  467.                 return(state); /* If wrong ACK, stay in F state */
  468.             numtry = 0;            /* Reset try counter */
  469.             bytes = 0;
  470.             xprintMsg(X_KBYTES, NULL, (long)(bytes/1024));
  471.             xprintMsg(X_STATUS, "Sending", LZERO);
  472.             n = (n+1)%64;        /* Bump packet count */
  473.             size = bufill(packet);    /* Get first data from file */
  474.             return('D');        /* Switch state to D */
  475.         case 'E':            /* Error packet received */
  476.             xprintMsg(X_ERROR, packet, LZERO);/* print error msg    */
  477.             fclose(fp); 
  478.             fp = NULL;
  479.             return('A');        /* abort */
  480.         case FALSE: 
  481.             return(state);    /* Receive failure, stay in F state */
  482.         case 'Q':            /* aborted by user        */
  483.             fclose(fp); 
  484.             fp = NULL;
  485.             msgAbort();
  486.             tellAbort();        /* send 'E' packet        */
  487.             return('A');
  488.         default:   
  489.             return('A');    /* Something else, just "abort" */
  490.     }
  491. }
  492.  
  493.  
  494. /*
  495. **  sdata
  496.  *
  497.  *  Send File Data
  498.  */
  499. static char sdata()
  500. {
  501.     int num, len;            /* Packet number, length */
  502.  
  503.     if (updateRetry())
  504.         return('A'); /* If too many tries, give up */
  505.  
  506.     spack('D',n,size,packet);        /* Send a D packet */
  507.     switch(rpack(&len,&num, packet)) {    /* What was the reply? */
  508.         case 'N':            /* NAK, just stay in this state, */
  509.             num = (--num<0 ? 63:num);    /* unless it's NAK for next packet */
  510.             if (n != num)        /* which is just like an ACK for */
  511.                 return(state);        /* this packet so fall thru to... */
  512.         case 'Y':            /* ACK */
  513.             if (n != num)
  514.                 return(state); /* If wrong ACK, fail */
  515.             numtry = 0;            /* Reset try counter */
  516.             bytes += slen;
  517.             lastBytes += slen;
  518.             xprintMsg(X_KBYTES, NULL, (long)(bytes/1024));
  519.             if (bytesToSend)
  520.                 xprintMsg(X_PERCENT, NULL, (long)((bytes*100)/bytesToSend));
  521.             if (--rateTimer < 0) {
  522.                 xprintMsg(X_RATE, NULL, (long)((lastBytes*1000L)/(long)((long)(30000-timerValue)*TICK_INTERVAL)));
  523.                 timerValue = 30000;
  524.                 rateTimer = 4;
  525.                 lastBytes = 0;
  526.             }
  527.             n = (n+1)%64;        /* Bump packet count */
  528.             if ((size = bufill(packet)) == EOF) /* Get data from file */
  529.                 return('Z');        /* If EOF set state to that */
  530.             return('D');        /* Got data, stay in state D */
  531.         case 'E':            /* Error packet received */
  532.             xprintMsg(X_ERROR, packet, LZERO);    /* print error msg    */
  533.             fclose(fp); 
  534.             fp = NULL;
  535.             return('A');        /* abort */
  536.         case FALSE: 
  537.             return(state);    /* Receive failure, stay in D */
  538.         case 'Q':            /* aborted by user        */
  539.             fclose(fp); 
  540.             fp = NULL;
  541.             msgAbort();
  542.             tellAbort();        /* send 'E' packet        */
  543.             return('A');
  544.         default:
  545.             return('A');    /* Anything else, "abort" */
  546.     }
  547. }
  548.  
  549. /*
  550. **  seof()
  551.  *
  552.  *  Send End-Of-File.
  553.  */
  554. static char seof()
  555. {
  556.     int num, len;            /* Packet number, length */
  557.  
  558.     if (updateRetry())
  559.         return('A'); /* If too many tries, "abort" */
  560.  
  561.     spack('Z',n,0,packet);        /* Send a 'Z' packet */
  562.     switch(rpack(&len,&num,packet))    { /* What was the reply? */
  563.         case 'N':            /* NAK, just stay in this state, */
  564.             num = (--num<0 ? 63:num);    /* unless it's NAK for next packet, */
  565.             if (n != num)        /* which is just like an ACK for */
  566.                 return(state);        /* this packet so fall thru to... */
  567.         case 'Y':            /* ACK */
  568.             if (n != num) 
  569.                 return(state); /* If wrong ACK, hold out */
  570.             numtry = 0;            /* Reset try counter */
  571.             bytes += slen;
  572.             xprintMsg(X_KBYTES, NULL, (long)(bytes/1024));
  573.             if (bytesToSend)
  574.                 xprintMsg(X_PERCENT, NULL, (long)((bytes*100)/bytesToSend));
  575.             n = (n+1)%64;        /* and bump packet count */
  576.             fclose(fp);            /* Close the input file */
  577.             fp = NULL;            /* Set flag indicating no file open */ 
  578.             if (getNextFileName(0, &fileList, &filnam, NO) == NO)    /* No more files go? */
  579.                 return('B');        /* if not, break, EOT, all done */
  580.             return('F');        /* More files, switch state to F */
  581.         case 'E':            /* Error packet received */
  582.             fclose(fp); 
  583.             fp = NULL;
  584.             xprintMsg(X_ERROR, packet, LZERO);/* print error msg    */
  585.             return('A');        /* abort */
  586.         case FALSE: 
  587.             return(state);    /* Receive failure, stay in Z */
  588.         case 'Q':            /* aborted by user        */
  589.             fclose(fp); 
  590.             fp = NULL;
  591.             msgAbort();
  592.             tellAbort();        /* send 'E' packet        */
  593.             return('A');
  594.         default:
  595.             return('A');    /* Something else, "abort" */
  596.     }
  597. }
  598.  
  599. /*
  600. **  sbreak()
  601.  *
  602.  *  Send Break (EOT)
  603.  */
  604.  
  605. static char sbreak()
  606. {
  607.     int num, len;            /* Packet number, length */
  608.  
  609.     if (updateRetry())
  610.         return('A'); /* If too many tries "abort" */
  611.  
  612.     spack('B',n,0,packet);        /* Send a B packet */
  613.     switch (rpack(&len,&num,packet)) {    /* What was the reply? */
  614.         case 'N':            /* NAK, just stay in this state, */
  615.             num = (--num<0 ? 63:num);    /* unless NAK for previous packet, */
  616.             if (n != num)        /* which is just like an ACK for */
  617.                 return(state);        /* this packet so fall thru to... */
  618.         case 'Y':            /* ACK */
  619.             if (n != num) 
  620.                 return(state); /* If wrong ACK, fail */
  621.             numtry = 0;            /* Reset try counter */
  622.             n = (n+1)%64;        /* and bump packet count */
  623.             return('C');        /* Switch state to Complete */
  624.         case 'E':            /* Error packet received */
  625.             xprintMsg(X_ERROR, packet, LZERO);/* print error msg    */
  626.             return('A');        /* abort */
  627.         case FALSE: 
  628.             return(state);    /* Receive failure, stay in B */
  629.         case 'Q':            /* aborted by user        */
  630.             msgAbort();
  631.             tellAbort();        /* send 'E' packet        */
  632.             return('A');
  633.         default:    
  634.             return ('A');    /* Other, "abort" */
  635.    }
  636. }
  637.  
  638. /*
  639. **  recsw()
  640.  *
  641.  *  This is the state table switcher for receiving files.
  642.  */
  643.  
  644. static int recsw()
  645. {
  646.     char rinit(), rfile(), rdata();    /* Use these procedures */
  647.  
  648.     state = 'R';            /* Receive-Init is the start state */
  649.     n = 0;                /* Initialize message number */
  650.     numtry = 0;                /* Say no tries yet */
  651.     totalRetry = 0;
  652.  
  653.     while(TRUE) {
  654.         switch(state) {            /* Do until done */
  655.             case 'R':    state = rinit(); break; /* Receive-Init */
  656.             case 'F':    state = rfile(); break; /* Receive-File */
  657.             case 'D':    state = rdata(); break; /* Receive-Data */
  658.             case 'C':    return(TRUE);        /* Complete state */
  659.             case 'A':    return(FALSE);        /* "Abort" state */
  660.         }
  661.     }
  662. }
  663.  
  664.     
  665. /*
  666. **  rinit()
  667.  *
  668.  *  Receive Initialization
  669.  */
  670. static char rinit()
  671. {
  672.     int len, num;            /* Packet length, number */
  673.  
  674.     if (updateRetry())
  675.         return('A'); /* If too many tries, "abort" */
  676.  
  677.     switch(rpack(&len,&num,packet)) {    /* Get a packet */
  678.         case 'S':            /* Send-Init */
  679.             rpar(packet, len);        /* Get the other side's init data */
  680.             spar(packet);        /* Fill up packet with my init info */
  681.             spack('Y',n,strlen(packet),packet);    /* ACK with my parameters */
  682.             xprintMsg(X_PSIZE, NULL, (long)rpsiz);
  683.             oldtry = numtry;        /* Save old try count */
  684.             numtry = 0;            /* Start a new counter */
  685.             n = (n+1)%64;        /* Bump packet number, mod 64 */
  686.             return('F');        /* Enter File-Receive state */
  687.         case 'E':            /* Error packet received */
  688.             xprintMsg(X_ERROR, packet, LZERO);    /* print error msg    */
  689.             return('A');        /* abort */
  690.         case FALSE:            /* Didn't get packet */
  691.             spack('N',n,0,0);        /* Return a NAK */
  692.             return(state);        /* Keep trying */
  693.         case 'Q':            /* aborted by user        */
  694.             msgAbort();
  695.             tellAbort();        /* send 'E' packet        */
  696.             return('A');
  697.         default:     
  698.             return('A');    /* Some other packet type, "abort" */
  699.     }
  700. }
  701.  
  702.  
  703. /*
  704. **  rfile()
  705.  *
  706.  *  Receive File Header
  707.  */
  708. static char rfile()
  709. {
  710.     int num, len;            /* Packet number, length */
  711.  
  712.     if (updateRetry())
  713.         return('A'); /* "abort" if too many tries */
  714.  
  715.     switch(rpack(&len,&num,packet))    {/* Get a packet */
  716.         case 'S':            /* Send-Init, maybe our ACK lost */
  717.             if (oldtry++ > MAX_TRY) 
  718.                 return('A'); /* If too many tries "abort" */
  719.             if (num == ((n==0) ? 63:n-1)) { /* Previous packet, mod 64? */
  720.                                         /* Yes, ACK it again with  */
  721.                 spar(packet);        /* our Send-Init parameters */
  722.                 spack('Y',num,strlen(packet),packet);
  723.                 numtry = 0;        /* Reset try counter */
  724.                 return(state);        /* Stay in this state */
  725.             } else
  726.                 return('A');        /* Not previous packet, "abort" */
  727.         case 'Z':            /* End-Of-File */
  728.             if (oldtry++ > MAX_TRY) 
  729.                 return('A');
  730.             if (num == ((n==0) ? 63:n-1)) { /* Previous packet, mod 64? */
  731.                                             /* Yes, ACK it again. */
  732.                 spack('Y',num,0,0);
  733.                 numtry = 0;
  734.                 return(state);        /* Stay in this state */
  735.             } else
  736.                 return('A');        /* Not previous packet, "abort" */
  737.         case 'F':                    /* File Header (just what we want) */
  738.             if (num != n) 
  739.                 return('A');            /* The packet number must be right */
  740.             xprintMsg(X_FILENAME, packet, LZERO);
  741.             if ((fp=fopen(packet,"wb"))==NULL) { /* Try to open a new file */
  742.                 xprintMsg(X_ERROR, "File create failed", LZERO);
  743.                 /* send E packet to remote host? */
  744.                 return('A');
  745.             } else                        /* OK, give message */
  746.                 xprintMsg(X_STATUS, "Receiving", LZERO);
  747.  
  748.             xprintMsg(X_PERCENT, "", -1L);
  749.  
  750.             spack('Y',n,0,0);        /* Acknowledge the file header */
  751.             oldtry = numtry;        /* Reset try counters */
  752.             numtry = 0;            /* ... */
  753.             bytes = 0;            /* iniz number of transfer bytes*/
  754.             xprintMsg(X_KBYTES, NULL, (long)(bytes/1024));
  755.             rateTimer = 4;        /* sample per 4 packets */
  756.             timerValue = 30000;
  757.             lastBytes = 0;
  758.             n = (n+1)%64;        /* Bump packet number, mod 64 */
  759.             return('D');        /* Switch to Data state */
  760.         case 'B':            /* Break transmission (EOT) */
  761.             if (num != n) 
  762.                 return ('A'); /* Need right packet number here */
  763.             spack('Y',n,0,0);        /* Say OK */
  764.             return('C');        /* Go to complete state */
  765.         case 'E':            /* Error packet received */
  766.             if (fp)
  767.                 fclose(fp);
  768.             fp = NULL;
  769.             xprintMsg(X_ERROR, packet, LZERO);    /* print error msg    */
  770.             return('A');        /* abort */
  771.         case FALSE:            /* Didn't get packet */
  772.             spack('N',n,0,0);        /* Return a NAK */
  773.             return(state);        /* Keep trying */
  774.         case 'Q':            /* aborted by user        */
  775.             if (fp)
  776.                 fclose(fp);
  777.             fp = NULL;
  778.             msgAbort();
  779.             tellAbort();        /* send 'E' packet        */
  780.             return('A');
  781.         default:
  782.             return ('A');    /* Some other packet, "abort" */
  783.     }
  784. }
  785.  
  786.  
  787. /*
  788. **  rdata()
  789.  *
  790.  *  Receive Data
  791.  */
  792. static char rdata()
  793. {
  794.     int num, len;            /* Packet number, length */
  795.  
  796.     if (updateRetry())
  797.         return('A'); /* "abort" if too many tries */
  798.  
  799.     switch(rpack(&len,&num,packet))    { /* Get packet */
  800.         case 'D':            /* Got Data packet */
  801.             xprintMsg(X_PSIZE, NULL, (long)len);
  802.             if (num != n) {        /* if Not Right packet */
  803.                 if (oldtry++ > MAX_TRY)
  804.                     return('A');    /* If too many tries, abort */
  805.                 if (num == ((n==0) ? 63:n-1)) { /* Else check packet number */
  806.                                                 /* Previous packet again? */
  807.                     spack('Y',num,6,packet); /* Yes, re-ACK it */
  808.                     numtry = 0;        /* Reset try counter */
  809.                     return(state);    /* Don't write out data! */
  810.                 } else 
  811.                     return('A');    /* sorry, wrong number */
  812.             }
  813.             /* Got data with right packet number */
  814.             if (bufemp(packet,len)) {        /* Write the data to the file */
  815.                 xprintMsg(X_ERROR, "File write error", LZERO);
  816.                 tellAbort();
  817.                 return('A');
  818.             }
  819.             bytes += rlen;
  820.             lastBytes += rlen;
  821.             xprintMsg(X_KBYTES, NULL, (long)(bytes/1024));
  822.             if (--rateTimer < 0) {
  823.                 xprintMsg(X_RATE, NULL, (long)((lastBytes*1000L)/(long)((long)(30000-timerValue)*TICK_INTERVAL)));
  824.                 timerValue = 30000;
  825.                 rateTimer = 4;
  826.                 lastBytes = 0;
  827.             }
  828.             spack('Y',n,0,0);        /* Acknowledge the packet */
  829.             oldtry = numtry;        /* Reset the try counters */
  830.             numtry = 0;            /* ... */
  831.             n = (n+1)%64;        /* Bump packet number, mod 64 */
  832.             return('D');        /* Remain in data state */
  833.         case 'F':            /* Got a File Header */
  834.             if (oldtry++ > MAX_TRY)
  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.             } else
  842.                 return('A');        /* Not previous packet, "abort" */
  843.         case 'Z':            /* End-Of-File */
  844.             if (num != n) 
  845.                 return('A');    /* Must have right packet number */
  846.             spack('Y',n,0,0);        /* OK, ACK it. */
  847.             numtry = 0;
  848.             fclose(fp);            /* Close the file */
  849.             fp = NULL;
  850.             xprintMsg(X_PERCENT, "", 100L);
  851.             n = (n+1)%64;        /* Bump packet number */
  852.             return('F');        /* Go back to Receive File state */
  853.         case 'E':            /* Error packet received */
  854.             if (fp)
  855.                 fclose(fp);
  856.             fp = NULL;
  857.             xprintMsg(X_ERROR, packet, LZERO);    /* print error msg    */
  858.             return('A');        /* abort */
  859.         case FALSE:            /* Didn't get packet */
  860.             spack('N',n,0,0);        /* Return a NAK */
  861.             return(state);        /* Keep trying */
  862.         case 'Q':            /* aborted by user        */
  863.             if (fp)
  864.                 fclose(fp);
  865.             fp = NULL;
  866.             msgAbort();
  867.             tellAbort();    /* send 'E' packet        */
  868.             return('A');
  869.         default:     
  870.             return('A');    /* Some other packet, "abort" */
  871.     }
  872. }
  873.  
  874.  
  875. static int finishsw()
  876. {
  877.     char cinit(), dofinish();
  878.  
  879.     state = 'F';            /* Send initiate is the start state */
  880.     n = 0;                /* Initialize message number */
  881.     numtry = 0;                /* Say no tries yet */
  882.     while(TRUE) {                /* Do this as long as necessary */
  883.         switch(state) {
  884.             case 'F':    state = dofinish();  break; /* Do-finish */
  885.             case 'Y':   return (TRUE);         /* Complete */
  886.             case 'A':    return (FALSE);         /* "Abort" */
  887.             default:    return (FALSE);         /* Unknown, fail */
  888.         }
  889.     }
  890. }
  891.  
  892. static char dofinish()
  893. {
  894.     int num, len;            /* Packet number, length */
  895.     char finishCmd = 'F';
  896.  
  897.     if (updateRetry())
  898.         return('A'); /* If too many tries, give up */
  899.  
  900.  
  901.     flushInputBuffer();            /* Flush pending input */
  902.  
  903.     spack('G',n,2, &finishCmd);        /* Send an S packet */
  904.     switch(rpack(&len,&num,packet))    { /* What was the reply? */
  905.         case 'N':  
  906.             return(state);    /* NAK, try it again */
  907.         case 'Y':            /* ACK */
  908.             if (n != num)        /* If wrong ACK, stay in S state */
  909.                 return(state);        /* and try again */
  910.             numtry = 0;            /* Reset try counter */
  911.             n = (n+1)%64;        /* Bump packet count */
  912.             return('Y');        /* OK, switch state to F */
  913.         case 'E':            /* Error packet received */
  914.             xprintMsg(X_ERROR, packet, LZERO);    /* print error msg    */
  915.             return('A');        /* abort */
  916.         case FALSE: 
  917.             return(state);    /* Receive failure, try again */
  918.         case 'Q':            /* aborted by user        */
  919.             msgAbort();
  920.             tellAbort();        /* send 'E' packet        */
  921.             return('A');
  922.         default: 
  923.             return('A');        /* Anything else, just "abort" */
  924.     }
  925.  }
  926.  
  927. /*
  928. **  doget()
  929.  *
  930.  * Issue 'R' packet and then do recsw
  931.  */
  932.  
  933. static int doget()
  934. {
  935.     flushInputBuffer();                /* Flush pending input */
  936.     spack('R',n,strlen(filnam),filnam);    /* Send an R packet */
  937.     return (recsw());
  938. }
  939.  
  940. /*
  941.  *    KERMIT utilities.
  942.  */
  943.  
  944. static void tellAbort()
  945. {
  946.     char  *msg = "Aborted by user";
  947.     
  948.     spack('E', n, strlen(msg), msg);
  949. }
  950.  
  951. static void clkint(v)                /* Timer interrupt handler */
  952. int v;
  953. {
  954.     longjmp(env,v);            /* Tell rpack to give up */
  955. }
  956.  
  957. static int updateRetry()
  958. {
  959.     if (numtry++ > MAX_TRY) 
  960.         return(1);                 /* If too many tries, give up */
  961.     if (numtry > 1)
  962.         totalRetry++;
  963.     xprintMsg(X_RETRY, NULL, (long)totalRetry);
  964.     return(0);
  965. }
  966.  
  967. /*
  968. **  spack()
  969.  *
  970.  *  Send a Packet
  971.  */
  972. static void spack(type,num,len,data)
  973. char type;
  974. int num;
  975. int len;
  976. char *data;
  977. {
  978.     int i, len2;                    /* Character loop counter     */
  979.     register char chksum, chksum2;    /* Checksum, packet buffer     */
  980.     char *lenp;                    
  981.     register char *bufp;            /* Buffer pointer             */
  982.     char sendpkt[20];                /* header buffer            */
  983.  
  984.     /*
  985.      * send padding chars
  986.      */
  987.     for (i=1; i<=pad; i++) {
  988.         kwrite(&padchar, 1);        /* Issue any padding */
  989.     }
  990.  
  991.     /*
  992.      * build a header part and send it
  993.      */
  994.     bufp = sendpkt;                        /* Set up buffer pointer */
  995.     chksum = 0;
  996.     *bufp++ = SOH;                        /* Packet marker, ASCII 1 (SOH) */
  997.     lenp = bufp++;
  998.     *bufp++ = tochar(num);                /* Packet number             */
  999.     chksum += tochar(num);                /* Update checksum             */
  1000.     *bufp++ = type;                        /* Packet type                */
  1001.     chksum += type;                        /* Update checksum             */
  1002.     len2 = len + 1;                        /* len + checksum len        */
  1003.     if (len2 > 95) {                    /* if long packet            */
  1004.         *lenp++ = tochar(0);            /* zero length                */
  1005.         chksum += tochar(0);
  1006.         *bufp++ = tochar(len2 / 95);    /* high part                */
  1007.         chksum += tochar(len2 / 95);
  1008.         *bufp++ = tochar(len2 % 95);    /* low part                    */
  1009.         chksum += tochar(len2 % 95);
  1010.         chksum2 = (((chksum&0300)>>6)+chksum) & 077;
  1011.         *bufp++ = tochar(chksum2);
  1012.         chksum += tochar(chksum2);
  1013.     } else {
  1014.         *lenp = tochar(len2+2);        /* Send the character count         */
  1015.         chksum  += tochar(len2+2);    /* Initialize the checksum             */
  1016.     }
  1017.     kwrite(sendpkt, bufp-sendpkt);    /* send header                        */
  1018.     
  1019.     /*
  1020.      * calc check sum for the the data part then send the data part
  1021.      */
  1022.     for (i=0, bufp = data; i<len; i++)
  1023.         chksum += *bufp++;            /* Update checksum                     */
  1024.     kwrite(data, len);                /* send data                        */
  1025.  
  1026.     /*
  1027.      * build trailer part then send it
  1028.      */
  1029.     bufp = sendpkt;                    /* prepare trailer buffer            */
  1030.     chksum = (((chksum&0300)>>6)+chksum)&077; /* Compute final checksum */
  1031.     *bufp++ = tochar(chksum);        /* Put it in the packet             */
  1032.     *bufp = eol;                    /* Extra-packet line terminator     */
  1033.     kwrite(sendpkt,bufp-sendpkt+1);    /* Send the packet                     */
  1034.     xprintMsg(X_PSENT, NULL, (long)(sendnum++));    /* print sent packet num    */
  1035. }
  1036.  
  1037. /*
  1038. **  rpack()
  1039.  *
  1040.  *  Read a Packet
  1041.  */
  1042. static int rpack(len,num,data)
  1043. int *len;
  1044. int *num;                /* Packet length, number */
  1045. char *data;                /* Packet data */
  1046. {
  1047.     int    c;
  1048.     int i, done;            /* Data character number, loop exit */
  1049.     int len2;
  1050.     char t,                /* Current input character */
  1051.     type,                /* Packet type */
  1052.     cchksum,            /* Our (computed) checksum */
  1053.     rchksum;            /* Checksum received from other host */
  1054.  
  1055.     if ((c = setjmp(env)) == TRUE)
  1056.         return FALSE;            /* Timed out, fail         */
  1057.     else if (c == 'Q')
  1058.         return('Q');            /* aborted by user        */
  1059.     recflg = 1;
  1060.  
  1061.     if ((timint > MAX_TIME) || (timint < MIN_TIME)) 
  1062.         timint = MY_TIME;
  1063.     alarm(timint);
  1064.  
  1065.     do {
  1066.         kread(&t,1);
  1067.         t &= 0177;            /* Handle parity */
  1068.     } while (t != SOH);        /* Wait for packet header */
  1069.  
  1070.     done = FALSE;            /* Got SOH, init loop */
  1071.     while (!done) {            /* Loop to get a packet */
  1072.         kread(&t,1);        /* Get character */
  1073.         if (t == SOH) 
  1074.             continue;        /* Resynchronize if SOH */
  1075.         cchksum = t;            /* Start the checksum */
  1076.         len2 = unchar(t);        /* len2 = 0 if long packet    */
  1077.         if (len2)
  1078.             *len = len2 - 3;    /* data count        */
  1079.  
  1080.         kread(&t,1);            /* Get character */
  1081.         if (t == SOH) 
  1082.             continue;        /* Resynchronize if SOH */
  1083.         cchksum = cchksum + t;        /* Update checksum */
  1084.         *num = unchar(t);        /* Packet number */
  1085.  
  1086.         kread(&t,1);            /* Get character */
  1087.         if (t == SOH) 
  1088.             continue;        /* Resynchronize if SOH */
  1089.         cchksum = cchksum + t;        /* Update checksum */
  1090.         type = t;            /* Packet type */
  1091.  
  1092.         if (len2 == 0) {        /* long packet    */
  1093.             kread(&t, 1);
  1094.             cchksum += t;
  1095.             *len = unchar(t) * 95;
  1096.             kread(&t, 1);
  1097.             cchksum += t;
  1098.             *len += unchar(t);
  1099.             kread(&t, 1);        /* header check sum (ignored)    */
  1100.             cchksum += t;
  1101.             *len -= 1;        /* to real data        */
  1102.         }
  1103.     
  1104.         for (i = 0; i < *len; i++) {    /* The data itself, if any */
  1105.             kread(&t,1);        /* Get character */
  1106.             if (t == SOH) 
  1107.                 continue;    /* Resynch if SOH */
  1108.             cchksum = cchksum + t;    /* Update checksum */
  1109.             data[i] = t;        /* Put it in the data buffer */
  1110.         }
  1111.         data[*len] = 0;            /* Mark the end of the data */
  1112.  
  1113.         kread(&t,1);            /* Get last character (checksum) */
  1114.         rchksum = unchar(t);        /* Convert to numeric */
  1115.         kread(&t,1);        /* get EOL character and toss it */
  1116.         if (t == SOH) 
  1117.             continue;        /* Resynchronize if SOH */
  1118.         done = TRUE;            /* Got checksum, done */
  1119.     }
  1120.  
  1121.     recflg = 0;
  1122.                     /* Fold in bits 7,8 to compute */
  1123.     cchksum = (((cchksum&0300) >> 6)+cchksum)&077; /* final checksum */
  1124.  
  1125.     if (cchksum != rchksum) {
  1126.         return(FALSE);
  1127.     }
  1128.  
  1129.     xprintMsg(X_PRECV, NULL, (long)(recnum++));    /* print received packet num    */
  1130.  
  1131.     return(type);            /* All OK, return packet type */
  1132. }
  1133.  
  1134.  
  1135. /*
  1136. **  bufill()
  1137.  *
  1138.  *  Get a bufferful of data from the file that's being sent.
  1139.  *  Only control-quoting is done; 8-bit & repeat count prefixes are
  1140.  *  not handled.
  1141.  */
  1142.  
  1143. static bufill(buffer)
  1144. char buffer[];                /* Buffer */
  1145. {
  1146.     int i,                /* Loop index */
  1147.     t;                /* Char read from file */
  1148.     u_char t7;                /* 7-bit version of above */
  1149.  
  1150.     i = 0;                /* Init data buffer pointer */
  1151.     slen = 0;
  1152.     while((t = getc(fp)) != EOF) {    /* Get the next character */
  1153.         slen++;                /* inc send file length    */
  1154.         t7 = t & 0x7f;            /* Get low order 7 bits */
  1155.  
  1156.         if (bit8PrefixUsed && (t & 0x80)) {
  1157.             buffer[i++] = bit8Prefix;
  1158.             t = t7;
  1159.         }
  1160.         if (t7 < SPACE || t7 == DEL) {    /* Does this char require */
  1161.             buffer[i++] = quote;    /* Quote the character */
  1162.             t = ctl(t);
  1163.         }
  1164.         if (t7 == quote)
  1165.             buffer[i++] = quote;
  1166.         if (bit8PrefixUsed && (t7 == bit8Prefix))
  1167.             buffer[i++] = quote;
  1168.  
  1169.         buffer[i++] = t;        /* Deposit the character itself */
  1170.         buffer[i] = '\0';
  1171.         if (i >= spsiz-11)         /* 8 */
  1172.             return(i);    /* Check length */
  1173.     }
  1174.     if (i==0) 
  1175.         return(EOF);        /* Wind up here only on EOF */
  1176.     return(i);                /* Handle partial buffer */
  1177. }
  1178.  
  1179.  
  1180. /*
  1181. **    bufemp()
  1182.  *
  1183.  *  Put data from an incoming packet into a file.
  1184.  */
  1185. static bufemp(buffer,len)
  1186. char  buffer[];                /* Buffer */
  1187. int   len;                /* Length */
  1188. {
  1189.     int i;                /* Counter */
  1190.     char t;                /* Character holder */
  1191.     u_char b8, a7;
  1192.  
  1193.     rlen = 0;
  1194.     for (i=0; i<len; i++) {        /* Loop thru the data field */
  1195.         t = buffer[i];            /* Get character */
  1196.         b8 = 0;
  1197.         if (bit8PrefixUsed) {
  1198.             if (t == bit8Prefix) {
  1199.                 b8 = 0x80;
  1200.                 t = buffer[++i];
  1201.             }
  1202.         }
  1203.         if (t == quote) {            /* Control quote */
  1204.             t = buffer[++i];        /* Get the quoted character */
  1205.             a7 = (t & 0x7f);
  1206.             if ((a7 >= 0100 && a7 <= 0137) || a7 == '?')
  1207.                 t = ctl(t);        /* No, uncontrollify it */
  1208.         }
  1209.         t |= b8;
  1210.         if (putc(t, fp) == EOF) {
  1211.             return(ERR);
  1212.         }
  1213.         rlen++;
  1214.     }
  1215.     return(OK);
  1216. }
  1217.  
  1218.  
  1219. /*
  1220. ** spar()
  1221.  *
  1222.  * Fill the data array with my send-init parameters
  1223.  *
  1224.  */
  1225. static void spar(data)
  1226. char data[];
  1227. {
  1228.     /*
  1229.      * Biggest packet I can receive 
  1230.      *     send short one first, send long one later in capabilities
  1231.      *    short one may be used by dumb-kermit and long one may be used
  1232.      *    by c-kermit.
  1233.      */
  1234.     data[0] = tochar(MAX_SHORT_PACKET_SIZE);
  1235.  
  1236.     /*
  1237.      * other parameters
  1238.      */
  1239.     data[1] = tochar(MY_TIME);        /* When I want to be timed out */
  1240.     data[2] = tochar(MY_PAD);        /* How much padding I need */
  1241.     data[3] = ctl(MY_PAD_CHAR);        /* Padding character I want */
  1242.     data[4] = tochar(MY_EOL);        /* End-Of-Line character I want */
  1243.     data[5] = MY_QUOTE;            /* Control-Quote character I send */
  1244.     switch (bit8PrefixRequested) {
  1245.         case -1:     /* unknown */
  1246.         case 1:        /* 'Y' is requested */
  1247.              switch (paritybit) {
  1248.                 case NO_PAR_8:
  1249.                 case EV_PAR_8: break;
  1250.                 case NO_PAR_7:
  1251.                 case EV_PAR_7:
  1252.                 case SP_PAR_7: 
  1253.                     sentBit8Prefix = bit8Prefix = MY_8BIT_CHAR;
  1254.                     break;
  1255.             }
  1256.             break;
  1257.         case 0:        /* 'N' is requested    */
  1258.         case 2:     /* prefix char is requested    */
  1259.             break;
  1260.     }
  1261.     data[6] = sentBit8Prefix;
  1262.     data[7] = 1 + '0';        /* one char check sum    */
  1263.     data[8] = ' ';            /* No repeat prefix    */
  1264.     data[9] = '\0';
  1265.  
  1266.     if (xmodemLongP) {
  1267.         data[9] = tochar(LONG_PACKET_BIT);    /* CAPAS field    */
  1268.         data[CAPAS] = tochar(0);    /* No window sliding    */
  1269.         data[CAPAS+1] = tochar(rpsiz / 95);
  1270.         data[CAPAS+2] = tochar(rpsiz % 95);    /* long packet size    */
  1271.         data[CAPAS+3] = '\0';
  1272.     }
  1273. }
  1274.  
  1275.  
  1276. /*
  1277. ** rpar()
  1278.  *
  1279.  * Get the other host's send-init parameters
  1280.  *
  1281.  */
  1282.  
  1283. static void rpar(data, len)
  1284. char data[];
  1285. int len;        /* packet length    */
  1286. {
  1287.     int rq, x, capas;
  1288.  
  1289.     x = unchar(data[0]);    /* Maximum packet size other kermit can receive */
  1290.     if (x < spsiz) {
  1291.         spsiz = x;
  1292.         if (spsiz < 10 || (xmodemLongP == NO))
  1293.             spsiz = 80;
  1294.     }
  1295.     timint = unchar(data[1]);    /* When I should time out */
  1296.     pad = unchar(data[2]);        /* Number of pads to send */
  1297.     padchar = ctl(data[3]);        /* Padding character to send */
  1298.     eol = unchar(data[4]);        /* EOL character I must send */
  1299.     quote = data[5];        /* Incoming data quote character */
  1300.     /*
  1301.      * bit 8 prefix
  1302.      */
  1303.     rq = (len >= 7) ?  data[6] : 0;
  1304.         if (rq == 'Y') {
  1305.             bit8PrefixRequested = 1;
  1306.         switch (paritybit) {
  1307.             case NO_PAR_8:
  1308.             case EV_PAR_8: break;
  1309.             case NO_PAR_7:
  1310.             case EV_PAR_7:
  1311.             case SP_PAR_7: 
  1312.                 bit8PrefixUsed = YES;
  1313.                 bit8Prefix = '&';
  1314.                 break;
  1315.         }
  1316.     }else if ((rq > 32 && rq < 63) || (rq > 95 && rq < 127)) {
  1317.         bit8PrefixRequested = 2;
  1318.         bit8PrefixUsed = (bit8Prefix == sentBit8Prefix || sentBit8Prefix == 'Y');
  1319.         if (bit8PrefixUsed)
  1320.             bit8Prefix = rq;
  1321.     } else {
  1322.         bit8PrefixRequested = 0;
  1323.         bit8PrefixUsed = NO;
  1324.     }
  1325.     /*
  1326.      * block check 
  1327.      */
  1328.     if (len >= 8)
  1329.         ;
  1330.     /*
  1331.      * repeat prefix
  1332.      */
  1333.     if (len >= 9)
  1334.         ;
  1335.     /*
  1336.      * capabilities
  1337.      */
  1338.     if (len >= 10) {
  1339.         x = unchar(data[9]);
  1340.         for (capas = 10; (unchar(data[capas-1]) & 1) && (len >= capas); capas++)
  1341.             ;    /* skip other CAPAS field    */
  1342.     }
  1343.     /*
  1344.      * Maximum packet size other kermit can receive (long packet)
  1345.      */
  1346.     if ((x & LONG_PACKET_BIT) && len > capas+2) {
  1347.         x = unchar(data[capas+1]) * 95 + unchar(data[capas+2]);
  1348.         if (xmodemLongP)    /* long packet is requested by user    */
  1349.             spsiz = (x > MAX_LONG_PACKET_SIZE) ? MAX_LONG_PACKET_SIZE : x;
  1350.         else
  1351.             spsiz = (x > MAX_SHORT_PACKET_SIZE) ? MAX_SHORT_PACKET_SIZE : x;
  1352.         if (spsiz < 10)
  1353.             spsiz = 80;
  1354.     }
  1355. }
  1356.  
  1357.  
  1358. static void msgAbort()
  1359. {
  1360.     xprintMsg(X_ERROR, "Aborted by user", LZERO);
  1361. }
  1362.  
  1363. /*
  1364.  * basic I/O
  1365.  */
  1366. static void kread(buf, len)
  1367. char    *buf;
  1368. int    len;
  1369. {
  1370.     register int    c;
  1371.     register int    bp;
  1372.  
  1373.     for (bp = 0; bp < len; ) {
  1374.         if ((c = getSerial()) != -1) {
  1375.             buf[bp] = c & cMask;
  1376.             bp++;
  1377.         } else {
  1378.             if ((c = keyin()) != -1)
  1379.                 if (c == 0x1b)    /* ESC */
  1380.                     clkint('Q');
  1381.         }
  1382.         if (kermitTimer <= 0)
  1383.             clkint(TRUE);        /* time out    */
  1384.     }
  1385. }
  1386. #endif /* KERMIT */
  1387.