home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_disks / 300-399 / ff330.lzh / XprKermit / kermitproto.w < prev    next >
Text File  |  1990-03-02  |  46KB  |  1,601 lines

  1. /*    
  2.  * A completely new C Kermit module.
  3.  *
  4.  * Based on code from Frank Da Cruz's excellent book, _Kermit: A File
  5.  * Transfer Protocol_, Digital Press, 1986.
  6.  *
  7.  * As this code is almost entirely from said book, it is certainly covered
  8.  * by that book's copyright.  Basically, this means the code is freely
  9.  * distributable, and can be used in a commercial program provided such
  10.  * use does not increase the program's cost to the purchaser beyond a small
  11.  * handling fee.
  12.  *
  13.  * Stephen Walton, swalton@solar.stanford.edu
  14.  * Dept. of Physics and Astronomy
  15.  * California State University, Northridge
  16.  * Northridge, CA 91330
  17.  *
  18.  *            ORGANIZATION
  19.  *
  20.  *  This file is in three pieces, and could probably be broken into
  21.  * two files.  Leading off are #DEFINE's and declarations of
  22.  * global and external variables.  Following are the unmodified sources
  23.  * from The Book.   Then are the z* file-handling routines written using
  24.  * standard Unix-style (almost ANSI C) file routines.
  25.  *
  26.  * I make no apologies for the organization; my primary goals were (1) to
  27.  * use the unmodified book source except for errors found by Lint, and
  28.  * (2) to allow this file to be plugged into an otherwise unmodified
  29.  * terminal program for the Commodore Amiga computer called VT100.  The
  30.  * comments starting with the string "/*lint" are for the Lint program
  31.  * of Gimpel Software, available for the Commodore Amiga and MS-DOS
  32.  * machines.  I highly recommend it.
  33.  *
  34.  * A few words about style herein.  Both "book Kermit" and the official
  35.  * C Kermit release make extensive use of global variables to set various
  36.  * options and keep track of what is going on.  I don't like this, but
  37.  * since example source code must be part of the Kermit specification,
  38.  * I chose to keep that organization.  There are several places where I
  39.  * I have tried to modularize things better.  First of all, everything
  40.  * which is not needed outside of this file is declared "static".  Second,
  41.  * I have kept the book Kermit code pretty much intact, except for some lint
  42.  * related things and one extra convention:  tmsg() appends characters to
  43.  * an existing status line, but tmsgl() is required to force that output to
  44.  * be seen.  Hence, I've changed the last in each series of tmsg() calls to
  45.  * tmsgl().
  46.  */
  47.  
  48.  
  49. /*
  50.  * Revision History--Versions 0 through 1 never left me.
  51.  *
  52.  * Version 0.5--Created and linted.
  53.  * Version 0.6--Added RESUME to handling of "unknown packets".
  54.  *          --Added proto() function to wrap around wart() for handling
  55.  *        of startup and cleanup functions.
  56.  *          --Changed handling of timeouts in input():  instead of an
  57.  *        error("Timeout") call, it puts the "Timeout" message in
  58.  *        the data field and pretends it read an 'E' packet.
  59.  * Version 0.7--Fixed a problem with rpsiz and MAXRP.  I had set rpsiz
  60.  *        to MAXRP in rpar() and was calling ttinl() with a max
  61.  *        argument of MAXRP, which resulted in truncated packets;
  62.  *        to wit, MAXRP+1 characters could come into ttinl counting
  63.  *        the eol.  Created defines DRPSIZ/DSPSIZ for default values
  64.  *        for rpsiz and spsiz, and increased MAXRP.
  65.  *          --Changed rcvpkt, sndpkt, and data so that they are pointers
  66.  *        instead of static arrays, and allocate and de-allocate
  67.  *        them in proto().
  68.  * Version 0.8--Added client support.  To make a Get
  69.  *        command, point the char *cmarg at the remote file
  70.  *        specification and set the start state to 'r'
  71.  *        (extern char start in the calling file).
  72.  * Version 0.9--Added long packet support.  This required adding an extern
  73.  *        int urpsiz which is set to the desired receive packet size
  74.  *        by the user interface.
  75.  *          --Since the above required using the capas, I also added the
  76.  *        code from C Kermit 4E(070) for negotiating window size
  77.  *        in rpar() and spar(). Of course, we don't do windows yet.
  78.  *          --Fixed a bug which is also part of C Kermit 4E(070).
  79.  *        If we tell the sender that we can receive a packet
  80.  *        of size MAXRP, the packet can contain as many as
  81.  *        MAXRP+5 characters, counting the EOL and extended
  82.  *        headers.  So rpack() must be able to handle somewhat
  83.  *        more characters than the actual maximum packet length.
  84.  *        I defined MAXRP here to be 1024, but only allow
  85.  *        rpsiz in proto() to be MAXRP-20.
  86.  * Version 0.95--Added code to gracefully abort transfer.  This works
  87.  *        via the cx and cz external variables and the state 'a'.
  88.  * Version 1.0--Unleashed upon the world.
  89.  * Version 1.1--Marco Papa (papa on BIX, papa@pollux.usc.edu on Internet)
  90.  *        added the code between the #ifdef XPRKERMIT...#endif
  91.  *        pairs, which turns this code into a routine which can
  92.  *        be used as an Amiga external file transfer protocol.
  93.  *        Upon getting it back from him, I fixed two lingering
  94.  *        bugs:  there was an "if (ebqflg & b8)" in encode()
  95.  *        which should be &&, and the first argument of encode()
  96.  *        needed to be declared as an int, not a char.
  97.  *          --Allow user to set bctr (block check to request) himself.
  98.  *          --If urpsiz is illegal, we set rpsiz to a legal value;  I also
  99.  *        set urpsiz to this as well, so the user knows what's up.
  100.  * Version 1.2--Added a typedef of CHAR to unsigned char to allow this code
  101.  *        to work with the latest version of Wart (V 1A(006) dated
  102.  *        12 January 1989.
  103.  * Version 1.3--21 December 1989
  104.  *        (1)  Added a tflush() call to the end of decode().  This
  105.  *        gives the user an opportunity to flush out the messages
  106.  *        from X packets, if the I/O is buffered.
  107.  *
  108.  * Version 1.4-- 5 January 1989
  109.  *         (1) Added the counters for characters on a per-file and
  110.  *        per-transaction basis.  Later, we can use the per-file
  111.  *        ones and a timer to figure out how long we have to go
  112.  *        on the current file.
  113.  *        (2) Started replacing tchar() calls with calls to the
  114.  *        screen() function, again a la C Kermit.  #define's for
  115.  *        the manifest constants for screen() are in kermitproto.h,
  116.  *         copied from C Kermit.
  117.  *        
  118.  */
  119.  
  120. #ifdef XPRKERMIT
  121. extern long calla(), callaa(), callad(), calladd(), calladda(), calldaa();
  122. extern long (*xupdate)(), (*xswrite)(), (*xfopen)(), (*xfclose)(), (*xfread)(),
  123.      (*xfwrite)(), (*xsread)(),  (*xchkabort)(), (*xffirst)(), (*xfnext)(),
  124.      (*xsflush)(), (*xfinfo)(), (*xgets)();
  125. extern long brkflag;
  126. #include "types.h"
  127. #include "xproto.h"
  128. #endif
  129.  
  130. /*
  131.  * Run this through the Wart preprocessor which comes with C Kermit.
  132.  */
  133.  
  134. #include "kermitproto.h"
  135.  
  136. /*
  137.  * Here are the variables which need to be set to startup values, and which
  138.  * also can be freely changed between protocol transfers.  At first I thought
  139.  * to declare them all "extern" in order to force definition elsewhere.
  140.  * On reflection, it makes sense to both declare them here and set them to
  141.  * their default startup values.  Thus they can be ignored outside of this
  142.  * module if you so desire.
  143.  *
  144.  * Note that the names are very systematic:  Names beginning with "r" have
  145.  * to do with values I use for received packets;  those beginning with "s"
  146.  * are values I use for sending packets.  Also note we set some, others are
  147.  * set for us.  I have made the ones we get in spar() static (local),
  148.  * and the ones we send in rpar() global.
  149.  *
  150.  * First the ints.
  151.  */
  152.  
  153. int    cx = 0,
  154.     cz = 0,        /* Flags for aborting transfers.  cx (control-X)*
  155.              * is set to 1 if an abort of the current file    *
  156.              * is desired, cz (control-Z) if an abort of    *
  157.              * an entire batch transfer is desired.        */
  158.     rpsiz = MAXRP,    /* Maximum packet size                */
  159.             /* Like most of the receive packet parameters,    *
  160.              * this one is actually set by the sender.  But    *
  161.              * since the sender has the option to not send    *
  162.              * these, we must initialize to "reasonable"    *
  163.              * defaults.                    */
  164.     bctr = 1,    /* Block check type to request.            */
  165.     limit = 5,    /* Retry limit on receive            */
  166.     warn = 0,    /* 1 for warn before overwriting files        */
  167.     rpadn = 0,    /* Number of pad characters I require.        */
  168.     rtimo = 10;    /* How long I want you to wait before you    *
  169.              * you time me out.                */
  170.  
  171. char    rmark = '\1',    /* Start of packet marker for receive        */
  172.     reol = '\r',    /* End of packet marker for receive        */
  173.     start = 0,    /* Start state                    */
  174.     sctlq = '#',    /* Control character quote character for send    */
  175.     rpadc = '\0';    /* Pad character I want you to use        */
  176.  
  177. /*
  178.  * Variables which MUST be set by the external interface.
  179.  */
  180. extern int
  181.     parity,        /* 0 for no parity--need for proper 8th-bit quote */
  182.     text,        /* Flag 1 for text file, 0 for binary file    */
  183.     urpsiz;        /* Maximum receive packet size user wants.    */
  184.  
  185. extern char
  186.     *cmarg;        /* Character string containing Kermit server cmd */
  187.  
  188. /*
  189.  * Variables having to do with the status of the file transfer.
  190.  */
  191. static long tfc,    /* File chararacters sent/received, total. */
  192.         ffc,    /*   "       "           "        , current file. */
  193.         tlci,    /* Comm line characters in, total. */
  194.         flci,    /*   "    "      "       ", current file. */
  195.         tlco,    /*   "    "      "       ", total. */
  196.         flco;    /*   "    "      "       ", current file. */
  197. /*
  198.  * In a fit of cleverness, here are some macro defines for variables we *
  199.  * aren't currently using. Only now we tell Lint to ignore constant    *
  200.  * Booleans!
  201.  */
  202.  
  203. /*lint -e506 */
  204.  
  205. #define local 1        /* Local mode flag--that is, I'm on your end    */
  206. #define server 0    /* We are never server                */
  207. #define delay 0        /* Time to delay before sending first packet    */
  208. #define xpkt 0        /* Send X packet instead of F?            */
  209.  
  210. /*
  211.  * This block of defines is strictly internal flags of various kinds.    *
  212.  * I hope to Grid that I've got them all.  Someday this will be cleaner *
  213.  */
  214. static int
  215.     spsiz = DSPSIZ,    /* Maximum send packet size            */
  216.     wsize = MAXWS,    /* Maximum window size                */
  217.     sndpkl,        /* Size of packet currently being attempted    */
  218.     filcnt,        /* Number of files transferred so far        */
  219.     bctu = 1,    /* Block check type to use            */
  220.     rqf,        /* Flag for 8th bit quote negotiations        */
  221.     ebq = '&',    /* 8th-bit prefix                */
  222.     ebqflg = 0,    /* 8th-bit quoting flag                */
  223.     xflag,        /* Output to screen for generic server commands    */
  224.     rq = 0,        /* Received 8bq bid                */
  225.     sq = 'Y',    /* Sent 8bq bid                    */
  226.     rpt = 0,    /* Repeat count                    */
  227.     rptq = '~',    /* Repeat prefix                */
  228.     rptflg = 0,    /* Repeat processing flag            */
  229.     capas = 10,    /* Final position of inbound capas mask        */
  230.     atcapr = 0,    /* Attribute capability requested        */
  231.     atcapu = 0,    /* Attribute capability used            */
  232.     swcapr = 0,    /* Sliding windows capability requested        */
  233.     swcapu = 0,    /* Sliding windows capability used        */
  234.     lpcapr = 0,    /* Long packets capability requested        */
  235.     lpcapu = 0,    /* Long packets capability used            */
  236.     rsn,        /* Received sequence number            */
  237.     seq = 0,    /* Current sequence number            */
  238.     maxsiz,        /* Maximum data size for packet            */
  239.     rln,        /* Length of received data field        */
  240.     size,        /* Current size of output packet data        */
  241.     osize,        /* Previous output packet data size        */
  242.     first = 0,    /* Some kind of lookahead flag            */
  243.     stimo = 5,    /* Timeout interval for me to use        */
  244.     spadn = 0;    /* Number of pad characters for me to use    */
  245.  
  246. #define atcapb 8    /* Attribute capability bit            */
  247. #define swcapb 4    /* Sliding windows capability bit        */
  248. #define lpcapb 2    /* Long packets capability bit            */
  249. #define closif zclosi    /* I use closif() to close the input file in    *
  250.              * case it needs to be more complex later, but    *
  251.              * for now it just calls the z routine.        */
  252.  
  253. static char
  254.     smark = '\1',    /* Start of packet marker for send        */
  255.     spadc = '\0',    /* Pad character to use on sending        */
  256.     seol = '\r',    /* End of packet marker for sending        */
  257.     rctlq = '#',    /* Control character quote char for receiving    */
  258.     filnam[50],    /* Current file name                */
  259.     ssc,        /* Start server command                */
  260.     *sndpkt,    /* Send packet.                    */
  261.     *rcvpkt,    /* Receieve packet.                */
  262.     *data,        /* Data to send/receive before encode/decode    */
  263.     *rdatap,    /* Pointer to null-terminated data field    */
  264.     *isp = NULL,    /* Pointer to characters in memory        */
  265.     *osp = NULL;    /* Output string pointer            */
  266.  
  267. /*
  268.  * Forward declarations.  Soon to be prototypes if the ANSI standard
  269.  * committee keeps its promises.
  270.  */
  271. int input(), spack(), ack();
  272. char *rpar();
  273.  
  274. /*
  275.  * External routines provided.
  276.  */
  277.  
  278. extern int ttinl(), ttol(), gnfile();
  279. #ifdef XPRKERMIT
  280. extern void ttflui(), tchar(), sleep();
  281. #else
  282. extern void ttflui(), tchar(), tmsg(), tmsgl(), sleep();
  283. #endif
  284. #define ERR(s) error(s); RESUME
  285. #define RESUME return
  286.  
  287. /*lint -save -e525 -e527    We don't care how Wart formats!        */
  288.  
  289. %states ssfil ssdat sseot
  290. %states srini srfil srdat
  291. %states sipkt srgen
  292. %%
  293.  
  294.  /* Start states */
  295.  
  296. s {                    /* - Start State - */
  297.     tinit();                /* Initialize transaction */
  298.     if (sinit('S') < 0) { ERR("sinit"); }    /* Build, send Send-Init. */
  299.     else {                /* If successful, */
  300.     filcnt = 0;            /* initialize file counter */
  301.     BEGIN ssfil;            /* and switch to ssfil state. */
  302.     }
  303. }
  304. v { tinit(); rinit(); BEGIN srini; }    /* - Receive - */
  305.  
  306. r {                    /* Get */
  307.     tinit(); ssc = 0;
  308.     if (sinit('I') < 0) { ERR("sinit"); }
  309.     else BEGIN sipkt;
  310. }
  311.  
  312. c {                    /* Host */
  313.     tinit(); ssc = 'C';
  314.     if (sinit('I') < 0) { ERR("sinit"); }
  315.     else BEGIN sipkt;
  316. }
  317.  
  318. g {                    /* Generic */
  319.     tinit(); ssc = 'G';
  320.     if (sinit('I') < 0) { ERR("sinit"); }
  321.     else BEGIN sipkt;
  322. }
  323.  
  324. a {                    /* Immediate protocol abort */
  325.     spack('E', seq, 21, "User aborted protocol");
  326.     closif();  closof(1);        /* Close files, deleting output */
  327.     RESUME;
  328. }
  329.  
  330. /* Dynamic states, sending file(s) */
  331.  
  332. <ssfil>Y {                /* - Send File State - */
  333.     if (filcnt++ == 0) spar(rdatap);    /* Set parameters if 1st time */
  334.     cx = 0;                /* Reset file interruption flag */
  335.     bctu = bctr;            /* Switch to negotiated block check */
  336.     resetc();                /* Reset global counters. */
  337. #ifdef XPRKERMIT
  338.     ST_Display_CRC(bctu);
  339. #endif
  340.     /* Is there a file to send in an uncancelled batch? */
  341.     if (!cz && gnfile(filnam, sizeof(filnam)) > 0) {
  342.     if (sfile() < 0) { ERR("sfile"); }    /* Yes, open it, send F packet */
  343.     else BEGIN ssdat;        /* and if no error, switch state. */
  344.     } else {                /* No (more) files to send */
  345.     if (seot() < 0) { ERR("seot"); }    /* so send B packet */
  346.     else BEGIN sseot;        /* and switch to sseot state. */
  347.     }
  348. }
  349. <ssdat>Y {                /* - Send Data State - */
  350.     int x;
  351.     if (rln == 1 && *rdatap == 'X')    /* Did ACK contain X as data? */
  352.     cx = 1;                /* Yes, set control-x flag. */
  353.     else if (rln == 1 && *rdatap == 'Z') /* Did ACK contain Z as data? */
  354.     cz = 1;                /* Yes set control-z flag. */
  355.     /* Check here for cancellation of transfer and data left to send. */
  356.     if (cx || cz || (x = sdata()) == 0) {
  357.     if (seof((cx | cz) ? "D" : "") < 0) {    /* If not, send Z packet. */
  358.         ERR("seof");
  359.     }
  360.     else BEGIN ssfil;        /* and go back to ssfil state. */
  361.     } else if (x < 0) { ERR("sdata"); }    /* Handle file i/o errors. */
  362. }
  363. <sseot>Y { RESUME; }            /* - Send B, done. */
  364.  
  365. /* Dynamic states, receiving file(s) */
  366.  
  367. <srini,srgen>S {
  368.     resetc();
  369.     spar(rdatap);
  370.     (void) ack1(rpar());
  371.     bctu = bctr;
  372.     BEGIN srfil;
  373. }
  374.  
  375. <srfil>B { (void) ack(); RESUME; }
  376.  
  377. <srfil>F { if (rcvfil() < 0) { ERR("rcvfil"); } else { (void) ack(); BEGIN srdat; } }
  378.  
  379. <srdat>D {
  380.    if (cx)
  381.     ack1("X");
  382.    else if (cz)
  383.     ack1("Z");
  384.    else {
  385.     if (decode() < 0) { ERR("decode"); } else (void) ack();
  386.    }
  387. }
  388.  
  389. <srdat>Z {
  390.     /* Discard output file if the sender tells us so. */
  391.     if (closof(cx || cz || (rln == 1 && *rdatap == 'D')) < 0) {
  392.     ERR("error closing file");
  393.     } else {
  394.     (void) ack(); BEGIN srfil;
  395.     }
  396. }
  397.  
  398. /* Dynamic states, server mode */
  399.  
  400. <sipkt>Y {            /* Got ACK for I packet */
  401.     spar(rdatap);        /* Set parameters from it */
  402.     start = 'E';        /* Force entry into next state */
  403. }
  404.  
  405. <sipkt>E {            /* Got E for I packet */
  406.     if (ssc) {
  407.     if (scmd(ssc,cmarg) < 0) { ERR("scmd"); }
  408.     else BEGIN srgen;
  409.     } else {
  410.     if (scmd('R',cmarg) < 0) { ERR("scmd"); }
  411.     else BEGIN srini;
  412.     }
  413. }
  414.  
  415. <srgen>Y { xflag = 1; decode(); RESUME; }
  416.  
  417. <srgen,srfil>X { xflag = 1; ack(); BEGIN srdat; }
  418.  
  419. /* Error state */
  420.  
  421. E { error(rdatap);
  422.     (void) closif();
  423.     (void) closof(1);        /* close files, discarding output */
  424.     RESUME; }
  425.     
  426. . { error("Unexpected packet type"); RESUME; }
  427.                 /* Handle unwanted packet types. */
  428. %%
  429.  
  430. /*lint -restore */
  431.  
  432. static
  433. int
  434. input() {                /* Return packets    */
  435.    int type, try;
  436.  
  437.     if (start != 0) {            /* Start state in effect? */
  438.     type = start;            /* Yes, call it a packet type, */
  439.     start = 0;            /* nullify the start state, */
  440.     return(type);            /* and return the type. */
  441.     }
  442.     type = rpack();            /* No start state, read a packet. */
  443.     for (try = 0; rsn != seq || strchr("TQN",type); try++) {
  444.     if (try > limit) {        /* If too mahy tries, */
  445.         strcpy(data, "Timed out");    /* give up */
  446.         rdatap = data;        /* Make up pretend 'E' packet */
  447.         return('E');        /* and return it */
  448.     }
  449.     if (type == 'N' && rsn == ((seq + 1) & 63)) {
  450.                     /* NAK for next packet */
  451.         return('Y');        /* is ACK for current. */
  452.     } else {            /* Otherwise, */
  453.         (void) resend();        /* resend previous packet. */
  454.     }
  455.     type = rpack();            /* Try to read response. */
  456.     }
  457.     ttflui();                /* Got a good one, clear buffer. */
  458.     return(type);            /* Return its type. */
  459. }
  460.  
  461. static
  462. nxtpkt() {
  463.     seq = (seq + 1) & 63;        /* Next packet number, mod 64 */
  464. }
  465.  
  466. /*  R E S E T C  --  Reset per-transaction character counters */
  467. resetc() {
  468.     tfc = tlci = tlco = 0;    /* Total file chars, line chars in & out */
  469. }
  470.  
  471. static
  472. tinit() {                /* Transaction initialization */
  473.     seq = 0;                /* Start off with packet 0 */
  474.     ebqflg = 0;                /* 8-bit quoting off */
  475.     sq = 'Y';                /* Normal 8-bit quote bid */
  476.     rqf = -1;                /* Flag other's bid not yet seen */
  477.     rptflg = 0;                /* No repeat counts by default */
  478.     bctu = 1;                /* Block check to use back to 1 */
  479.     xflag = 0;                /* Output normally to file */
  480.     osp = NULL;                /* ... */
  481.     *filnam = *sndpkt = *rcvpkt = '\0';  /* Clear string buffers */
  482. }
  483.  
  484. static
  485. error(s) char *s; {            /* Fatal error */
  486.     if (local) {            /* If in local mode */
  487.     screen(SCR_EM,0,0L,s);        /* Type message on console */
  488.     } else {                /* Otherwise, */
  489.     (void) spack('E',seq,strlen(s),s); /* Send in error packet. */
  490.     }
  491.     return;
  492. }
  493.  
  494. static
  495. ack() {
  496.     int x;                /* Empty acknowledgement */
  497.     x = spack('Y',seq,0,"");        /* Send the packet */
  498.     nxtpkt();                /* Increment the packet number */
  499.     return(x);
  500. }
  501.  
  502. static
  503. ack1(s) char *s; {
  504.     int x;                /* Acknowledgement with data */
  505.     x = spack('Y',seq,strlen(s),s);    /* Send the packet */
  506.     nxtpkt();                /* Increment packet number */
  507.     return(x);
  508. }
  509.  
  510. static
  511. nak() {                    /* Negative acknowledgement */
  512.     return(spack('N',seq,0,""));    /* Never has data! */
  513. }
  514.  
  515. /* Functions used by file sender. */
  516.  
  517. /* sinit()--start the transaction by filling in the initialization string
  518.  * and sending it in an S packet.
  519.  */
  520.  
  521. static
  522. sinit(c) char c; {
  523.     char *s;
  524.     s = rpar();
  525.     if (local == 0 && c == 'S' && server == 0) {
  526. #ifdef XPRKERMIT
  527.     ST_Display_String(STMsg,"Escape back to local system, RECEIVE command");
  528. #else
  529.     tmsgl("Escape back to local system, give RECEIVE command...");
  530. #endif
  531.     sleep(delay);
  532.     }
  533.     return(spack(c,seq,strlen(s),s));
  534. }
  535.  
  536. /*
  537.  * scmd() -- send a preformatted Kermit server command string.
  538.  */
  539. static
  540. scmd(t, s) char t, *s; {    /* Send a packet of the given type */
  541.     encstr(s);            /* Encode the command string */
  542.     spack(t,seq,size,data);
  543. }
  544.  
  545. /* rinit() -- do whatever is needed to initialize receive.  Now a no-op.
  546.  */
  547. static
  548. rinit()
  549. {
  550. }
  551.  
  552. /* sfile() -- open the file and send the File-Header packet.  Assumes that
  553.  * the global string pointer filnam references the file name.
  554.  */
  555.  
  556. static
  557. sfile() {
  558.     int x;
  559.     char pktnam[50];
  560.     if (zopeni(filnam) < 0)        /* Try to open file. */
  561.     return -1;
  562.     zltor(filnam,pktnam);        /* OK, convert name. */
  563.     x = encstr(pktnam);            /* Encode the result */
  564.     if (local) {            /* If in local mode, */
  565. #ifdef XPRKERMIT
  566.     ST_Display_String(STFile, pktnam);
  567.     ST_Display_String(STUplSize, filnam);
  568. #else
  569.     tmsg("Sending ");        /* let user know we're */
  570.     tmsg(filnam);            /* sending this file */
  571.     tmsg(" as ");            /* under */
  572.     tmsgl(pktnam);            /* this name */
  573. #endif
  574.     }
  575.     first = 1;                /* Flag beginning of file */
  576.     ffc = flci = flco = 0;        /* Zero per-file char count */
  577.     maxsiz = spsiz - (bctr + 3);    /* Maximum data length */
  578.     nxtpkt();                /* Increment packet number */
  579.     return(spack((xpkt ? 'X' : 'F'),seq,x,data)); /* Send packet */
  580. }
  581.  
  582. /* sdata() -- get next packet's worth of data */
  583.  
  584. static
  585. sdata() {
  586.     int x;
  587.     if ((x = getpkt(maxsiz)) == 0)    /* If no data left to send, */
  588.     return(0);            /* return EOF indication. */
  589.     nxtpkt();
  590.     return(spack('D',seq,x,data));    /* Send the data packet */
  591. }
  592.  
  593. /* seof -- close the input file and send a Z packet. */
  594.  
  595. static
  596. seof(s) char *s; {
  597.     if (closif() < 0)            /* Try to close the file. */
  598.     return -1;            /* On error, return failure. */
  599.     else {                /* Otherwise, */
  600. #ifdef XPRKERMIT
  601.     if (local) ST_Display_String(STMsg,"OK");
  602. #else
  603.     if (local) tmsgl("OK");        /* if local, reassure user. */
  604. #endif
  605.     nxtpkt();
  606.     return(spack('Z',seq,strlen(s),s));    /* Send Z packet */
  607.     }
  608. }
  609.  
  610. /* seot -- send B packet. */
  611.  
  612. static
  613. seot() {
  614.     nxtpkt();
  615. #ifdef XPRKERMIT
  616.     if (local) ST_Display_String(STMsg,"Done");
  617. #else
  618.     if (local) tmsgl("Done");
  619. #endif
  620.     return(spack('B',seq,0,""));
  621. }
  622.  
  623. static
  624. rcvfil() {                /* Receive a file */
  625.     char myname[50];
  626.  
  627.     ffc = flci = flco = 0;        /* Initialize per-file char count */
  628.     decstr(filnam);            /* Decode name */
  629.     zrtol(filnam,myname,warn);        /* Convert to local form. */
  630.     if (zopeno(myname) < 0)
  631.     return -1;
  632.     else {                /* File open OK, give message. */
  633.     if (local && !xflag) {
  634. #ifdef XPRKERMIT
  635.         ST_Display_String(STFile,myname);
  636.         ST_Display_CRC(bctu);
  637. #else
  638.         tmsg("Receiving "); tmsg(filnam); tmsg(" as "); tmsgl(myname);
  639. #endif
  640.     }
  641.     return 0;
  642.     }
  643. }
  644.  
  645. static
  646. closof(nokeep) int nokeep; {        /* Close output file, but */
  647.     if (xflag) return 0;        /* not if it's the screen. */
  648.     if (zcloso(nokeep) < 0)
  649.     return -1;
  650.     return 0;
  651. }
  652.  
  653. static
  654. spack(type,n,len,d) char type, *d; int n, len; {
  655.     int i = 0, j, k;
  656.     char *sohp;                /* Mark start of packet data. */
  657.  
  658.     for (i = 0; i < spadn; i++)
  659.     sndpkt[i] = spadc;        /* Do requested padding */
  660.     sohp = sndpkt + i;
  661.     sndpkt[i++] = smark;        /* Packet mark */
  662.     k = i++;                /* Remember this place */
  663.     sndpkt[i++] = tochar(n);        /* Sequence number */
  664.     sndpkt[i++] = type;            /* Packet type */
  665.     j = len + bctu;            /* True length */
  666.     if (j > 95) {            /* Long packet? */
  667.     sndpkt[k] = tochar(0);        /* Set LEN to 0 */
  668.     sndpkt[i++] = tochar(j / 95);    /* High part of length */
  669.     sndpkt[i++] = tochar(j % 95);    /* Low part of length */
  670.     sndpkt[i] = '\0';        /* Header checksum */
  671.     sndpkt[i++] = tochar(chk1(sndpkt+k));
  672.     } else
  673.     sndpkt[k] = tochar(j+2);    /* True length. */
  674.  
  675.     for (j = len; j > 0; j--) {        /* Data */
  676.     sndpkt[i++] = *d++;
  677.     }
  678.     sndpkt[i] = '\0';            /* Null terminate. */
  679.     switch (bctu) {
  680.     case 1:                /* Type 1 - 6 bit checksum */
  681.         sndpkt[i++] = tochar(chk1(sndpkt+k));
  682.         break;
  683.     case 2:                /* Type 2 - 12 bit checksum */
  684.         j = chksum(sndpkt+k);
  685.         sndpkt[i++] = tochar((j >> 6) & 077);
  686.         sndpkt[i++] = tochar(j & 077);
  687.         break;
  688.     case 3:                /* Type 3 - 16 bit CRC-CCITT */
  689.         j = chk3(sndpkt + k);
  690.         sndpkt[i++] = tochar((j >> 12) & 017);
  691.         sndpkt[i++] = tochar((j >> 6) & 077);
  692.         sndpkt[i++] = tochar(j & 077);
  693.         break;
  694.     }
  695.     sndpkt[i++] = seol;            /* End of line */
  696.     sndpkt[i] = '\0';            /* Null string-terminat    or. */
  697.     sndpkl = i;                /* Remember length. */
  698.     i = ttol(sndpkt,sndpkl);        /* Send the packet. */
  699.     tlco += sndpkl;            /* Count characters output. */
  700.     flco += sndpkl;
  701.     screen(SCR_PT, type, (long) n, sohp);
  702.     return(i);
  703. }
  704.  
  705. static
  706. resend() {
  707.     int x;
  708.     if (*sndpkt)
  709.     x = ttol(sndpkt,sndpkl);    /* Send previous packet */
  710.     else
  711.     x = nak();            /* or NAK if none */
  712.     if (local && !xflag) tchar('%');    /* Let the user know. */
  713.     return(x);
  714. }
  715.  
  716. chk1(packet) char *packet; {        /* Compute Kermit's */
  717.     int s, t;                /* 1-character block check. */
  718.     s = chksum(packet);            /* Get the arithmetic sum. */
  719.     t = (((s & 192) >> 6) + s) & 63;    /* Fold it into 6 bits. */
  720.     return(t);
  721. }
  722.  
  723. static
  724. chksum(p) char *p; {            /* Compute the checksum. */
  725.     unsigned m;
  726.     long s;
  727.  
  728.     m = (parity) ? 0177 : 0377;        /* Mask for parity bit.    */
  729.     s = 0;
  730.     for (; *p != '\0'; p++)        /* For each character, */
  731.     s += *p & m;            /* accumulate the sum, */
  732.     return(s & 07777);            /* and then return it. */
  733. }
  734.  
  735. /*
  736.  * rpack reads a packet and returns the packet type, or else Q if the
  737.  * packet was invalid, or T if a timeout occured.   Upon successful return,
  738.  * sets the global variables:
  739.  *    rsn    - the received sequence number
  740.  *    rln    - length of the received data field
  741.  *    rdatap    - a pointer to the null-terminated contents of the data field
  742.  */
  743. static
  744. rpack() {
  745.     int i, j, x, type, rlnpos;
  746.     char pbc[4];            /* Packet block check. */
  747.     char *sohp;                /* Start of packet data. */
  748.  
  749.     rsn = rln = -1;            /* In case of failure. */
  750.  
  751.     *rcvpkt = '\0';            /* Initialize receive buffer. */
  752.     j = ttinl(rcvpkt,MAXRP,reol,stimo); /* Try to get a "line". */
  753.     if (j < 0) return('T');        /* Timed out. */
  754.  
  755.     tlci += j;                /* Count received characters. */
  756.     flci += j;                /* On per-file basis. */
  757.     for (i = 0; rcvpkt[i] != rmark && (i < j); i++)    /* Find mark. */
  758.     ;
  759.     if (i == j) return('Q');        /* If no mark, bad packet. */
  760.     sohp = rcvpkt+i;
  761.  
  762.     rlnpos = ++i;            /* Got it, remember position. */
  763.     if ((j = unchar(rcvpkt[i++])) == 0) { /* Long packet? */
  764.         j = rlnpos + 5;            /* Yes, check header */
  765.         if (j > MAXRP) return('Q');    /* Be defensive. */
  766.         x = rcvpkt[j];            /* Remember header checksum */
  767.         rcvpkt[j] = '\0';
  768.         if (unchar(x) != chk1(rcvpkt+rlnpos))    /* Check header */
  769.         return('Q');
  770.     rcvpkt[j] = x;            /* Restore packet */
  771.     rln = unchar(rcvpkt[j-2]) * 95 + unchar(rcvpkt[j-1]) - bctu;
  772.     j = 3;
  773.     } else {
  774.     rln = j - bctu - 2;        /* Regular packet */
  775.     j = 0;                /* No extended header */
  776.     }
  777.     rsn = unchar(rcvpkt[i++]);        /* Sequence number. */
  778.     type = rcvpkt[i++];            /* Packet type */
  779.     i += j;                /* Skip extended header, if any */
  780.     rdatap = rcvpkt + i;        /* The data itself. */
  781.     j = rln + i;            /* Position of block check. */
  782.     if (j > MAXRP)
  783.     return('Q');            /* Be defensive! */
  784.     for (x = 0; x < bctu; x++)        /* Copy the block check. */
  785.     pbc[x] = rcvpkt[j+x];
  786.     rcvpkt[j] = '\0';
  787.     switch (bctu) {            /* Which block check type? */
  788.     case 1:
  789.         if (unchar(*pbc) != chk1(rcvpkt+rlnpos)) return('Q');
  790.         break;
  791.     case 2:
  792.         x = unchar(*pbc) << 6 | unchar(pbc[1]);
  793.         if (x != chksum(rcvpkt+rlnpos)) return('Q');
  794.     case 3:
  795.         x = unchar(*pbc) << 12 | unchar(pbc[1]) << 6 | unchar(pbc[2]);
  796.         if (x != chk3(rcvpkt+rlnpos)) return('Q');
  797.         break;
  798.     default:
  799.         error("Impossible block check type.");
  800.     }
  801.     screen(SCR_PT, type, (long) rsn, sohp);
  802.     return type;            /* Otherwise, return packet type */
  803. }
  804.  
  805. /*
  806.  * CHK3
  807.  * Calculate the 16-bit CRC of a null-terminated string using a
  808.  * byte-oriented tableless algorithm devised by Andy Lowry (Columbia
  809.  * University).  The magic number 010201 is derived from the CRC-CCITT
  810.  * polynomial x^16+x^12+x^5+1.
  811.  */
  812. static
  813. chk3(s) char *s; {
  814.     unsigned int c, q;
  815.     long crc = 0;
  816.  
  817.     while ((c = *s++) != '\0') {
  818.     if (parity) c &= 0177;
  819.     q = (crc ^ c) & 017;        /* Low order nybble */
  820.     crc = (crc >> 4) ^ (q * 010201);
  821.     q = (crc ^ (c >> 4)) & 017;    /* High order nybble */
  822.     crc = (crc >> 4) ^ (q * 010201);
  823.     }
  824.     return(crc);
  825. }
  826.  
  827. /*
  828.  * getpkt--Fill a packet to the maximum.  Result goes in local data array
  829.  * whose current length is indicated in global size.
  830.  */
  831. static
  832. getpkt(maxlen) int maxlen; {
  833.     int i, next;
  834.     static int c;
  835.     static char remain[6] = {'\0', '\0', '\0', '\0', '\0', '\0'};
  836.     void encode();
  837.     
  838.     if (first == 1) {            /* If first time thru... */
  839.     first = 0;            /* remember not to do this next time, */
  840.     remain[0] = '\0';        /* discard any old leftovers, */
  841.     c = gnchar();            /* get first character of file */
  842.     if (c < 0) {            /* watching out for null file */
  843.         first = -1;
  844.         return(size = 0);
  845.     }
  846.     } else if (first == -1) {        /* EOF from last time? */
  847.     return(size = 0);
  848.     }
  849.     
  850.  
  851. /* Copy any leftovers that didn't fit in the last packet. */
  852.  
  853.     for (size = 0; (data[size] = remain[size]) != '\0'; size++)
  854.     ;
  855.     *remain = '\0';
  856.  
  857. /* Get, encode, and deposit the next character. */
  858.  
  859.     rpt = 0;                /* Initialize repeat counter. */
  860.     
  861.     while (first > -1) {        /* Until end of file or string... */
  862.     next = gnchar();        /* Look ahead one character */
  863.     if (next < 0) first = -1;    /* If none, we're at EOF. */
  864.     osize = size;            /* Remember current size. */
  865.     encode(c, next);        /* Encode the character. */
  866.     c = next;            /* Old next char is now current. */
  867.     if (size == maxlen) return(size); /* If just at end, done. */
  868.     if (size > maxlen) {        /* Past end, must save some. */
  869.         for (i = 0; (remain[i] = data[osize+i]) != '\0'; i++)
  870.         ;
  871.         size = osize;
  872.         data[size] = '\0';
  873.         return(size);        /* Return size. */
  874.     }
  875.     }
  876.     return(size);            /* EOF, return size. */
  877. }
  878.  
  879. static
  880. gnchar() {
  881.    int c;
  882.  
  883.     if (isp) {                /* From string in memory */
  884.     return((c = *isp++) > 0 ? c : -1);
  885.     } else {
  886.     if ((c = zgetc(text)) > 0) {    /* or from a file. */
  887.         ffc++; tfc++;
  888.     }
  889.     return c;
  890.     }
  891. }
  892.  
  893. /*
  894.  * Encodes the character a into the global data array,
  895.  * and the global size is updated.
  896.  * Global sctlq is the control prefix for sending data.
  897.  *
  898.  * The first argument is spec'd as a char in the Kermit book but must
  899.  * actually be an int;  otherwise, it is sign extended and the comparison
  900.  * if (a == next) comes up TRUE if the last character in the file has the
  901.  * value 255 and the EOF flag (which is what next's value will be in this
  902.  * case) is -1.  This results in that last 255 not being sent.
  903.  */
  904. static void
  905. encode(a, next) int a; int next; {
  906.     int a7, b8;
  907.  
  908.     if (rptflg) {            /* Doing run-length encoding? */
  909.     if (a == next) {        /* Yes, got a run? */
  910.         if (++rpt < 94) {        /* Yes count. */
  911.         return;
  912.         } else if (rpt == 94) {    /* If at maximum */
  913.         data[size++] = rptq;    /* Emit prefix, */
  914.         data[size++] = tochar(rpt); /* and count, */
  915.         rpt = 0;        /* and reset counter. */
  916.         }
  917.     } else if (rpt == 1) {        /* Run broken, only two? */
  918.         rpt = 0;            /* Yes, do the character wice */
  919.         encode(a,-1);        /* by calling self recursively. */
  920.         if (size <= maxsiz) osize = size; /* Watch for boundary */
  921.         rpt = 0;            /* Call self second time. */
  922.         encode(a,-1);
  923.         return;
  924.     } else if (rpt > 1) {        /* Run broken, more than two? */
  925.         data[size++] = rptq;    /* Yes, emit prefix and count */
  926.         data[size++] = tochar(++rpt);
  927.         rpt = 0;            /* and reset counter. */
  928.     }
  929.     }
  930.     a7 = a & 127;            /* Isolate low 7 bits */
  931.     b8 = a & 128;            /* And "parity" bit */
  932.  
  933.     if (ebqflg && b8) {            /* If doing 8th-bit prefixing */
  934.     data[size++] = ebq;        /* and 8th bit on, insert prefix */
  935.     a = a7;                /* and clear the 8th bit. */
  936.     }
  937.     if (a7 < 32 || a7 == 127) {        /* If control character */
  938.     data[size++] = sctlq;        /* insert control quote */
  939.     a = ctl(a);            /* and make printable. */
  940.     } else if (a7 == sctlq)        /* If data is control prefix, */
  941.     data[size++] = sctlq;        /* prefix it. */
  942.     else if (ebqflg && a7 == ebq)    /* If doing 8th-bit prefixing, */
  943.     data[size++] = sctlq;        /* ditto for 8th-bit prefix. */
  944.     else if (rptflg && a7 == rptq)    /* If doing run-length encoding, */
  945.     data[size++] = sctlq;        /* ditto for repeat prefix. */
  946.  
  947.     data[size++] = a;            /* Finally, emit the character. */
  948.     data[size] = '\0';            /* Terminate string. */
  949. }
  950.  
  951. /*
  952.  * Decodes the data pointed to by the global pointer rdatap.
  953.  */
  954. static
  955. decode() {
  956.     int a, a7, b8;
  957.  
  958.     while ((a = *rdatap++) != '\0') {
  959.     rpt = 1;            /* Initialize repeat count. */
  960.     if (rptflg) {            /* Repeat processing? */
  961.         if (a == rptq) {        /* Yes, have repat prefix? */
  962.         rpt = unchar(*rdatap++); /* Yes, get count. */
  963.         a = *rdatap++;        /* and following character. */
  964.         }
  965.     }
  966.     b8 = 0;                /* Assume 8th bit not on. */
  967.     if (ebqflg) {            /* Doing 8th-bit prefixing? */
  968.         if (a == ebq) {        /* Yes, have 8th-bit prefix? */
  969.         b8 = 128;        /* Yes, remember bit 8 on */
  970.         a = *rdatap++;        /* and get following character. */
  971.         }
  972.     }
  973.     if (a == rctlq) {        /* Is it control prefix? */
  974.         a = *rdatap++;        /* Yes, get next character */
  975.         a7 = a & 127;        /* and its low 7 bits. */
  976.         if (a7 > 62 && a7 < 96)    /* Encoded control character? */
  977.             a = ctl(a);        /* Yes, controllify */
  978.     }
  979.     a |= b8;            /* OR in the 8th bit. */
  980.     for (; rpt > 0; rpt--) {
  981.         if (pnchar(a) < 0) return -1; /* Output the character. */
  982.         ffc++; tfc++;          /* Update character counts. */
  983.     }
  984.     }
  985.     tflush();                /* Flush out message (if xflag) */
  986.     return(0);
  987. }
  988.  
  989. static
  990. pnchar(c) int c; {            /* Put next character. */
  991.     if (xflag) {            /* To screen if desired. */
  992.     tchar(c);
  993.     return(1);
  994.     } else if (osp) {            /* Or to string in memory... */
  995.     *osp++ = c;
  996.     return(1);
  997.     } else return(zputc(c,text));    /* Otherwise to file. */
  998. }
  999.  
  1000. static
  1001. encstr(s) char *s; {            /* Fill a packet from the string */
  1002.     first = 1;                /* Start lookahead. */
  1003.     isp = s;                /* Set input string pointer */
  1004.     (void) getpkt(spsiz);        /* Fill a packet */
  1005.     isp = NULL;                /* Reset input string pointer */
  1006.     return(size);            /* Return data field length */
  1007. }
  1008.  
  1009. static
  1010. decstr(s) char *s; {            /* Decode packet data into a string */
  1011.     osp = s;                /* Set output string pointer */
  1012.     (void) decode();            /* Decode the string */
  1013.     *osp = '\0';            /* Terminate the string */
  1014.     osp = NULL;                /* Reset output string pointer */
  1015. }
  1016.  
  1017. static
  1018. spar(s) char *s; {            /* Set parameters */
  1019.     int x;
  1020.  
  1021.     s--;                /* Line up with field numbers. */
  1022.     
  1023.     /* Limit on size of outbound packets */
  1024.     x = (rln >= 1) ? unchar(s[1]) : 80;
  1025.     spsiz = (x < 10) ? 80 : x;
  1026.  
  1027.     /* Timeout on inbound packets */
  1028.     x = (rln >= 2) ? unchar(s[2]) : 5;
  1029.     stimo = (x < 0) ? 5 : x;
  1030.  
  1031.     
  1032.     /* Outbound padding */
  1033.     spadn = 0; spadc = '\0';
  1034.     if (rln >= 3) {
  1035.     spadn = unchar(s[3]);
  1036.     if (rln >= 4)
  1037.         spadc = ctl(s[4]);
  1038.     }
  1039.     
  1040.     /* Outbound packet terminator */
  1041.     seol = (rln >= 5) ? unchar(s[5]) : '\r';
  1042.     if (seol < 2 || seol > 31) seol = '\r';
  1043.     
  1044.     /* Control prefix */
  1045.     x = (rln >= 6) ? s[6] : '#';
  1046.     rctlq = ((x > 32 && x < 63) || (x > 95 && x < 127)) ? x : '#';
  1047.     
  1048.     /* 8th-bit quoting */
  1049.     rq = (rln >= 7) ? s[7] : 0;
  1050.     if (rq == 'Y') rqf = 1;
  1051.     else if ((rq > 32 && rq < 63) || (rq > 95 && rq < 127)) rqf = 2;
  1052.     else rqf = 0;
  1053.     
  1054.     switch (rqf) {
  1055.     case 0: ebqflg = 0; break;
  1056.     case 1: if (parity) { ebqflg = 1; ebq = '&'; } break;
  1057.     case 2: if (ebqflg = (ebq == sq || sq == 'Y')) ebq = rq;
  1058.     }
  1059.  
  1060.     /* Block check */
  1061.     x = 1;
  1062.     if (rln >= 8) {
  1063.     x = s[8] - '0';
  1064.     if (x < 1 || x > 3) x = 1;
  1065.     }
  1066.     bctr = x;
  1067.  
  1068.     /* Repeat prefix */
  1069.     if (rln >= 9) {
  1070.     rptq = s[9];
  1071.     rptflg = ((rptq > 32 && rptq < 63) || (rptq > 95 && rptq < 127));
  1072.     } else rptflg = 0;
  1073.  
  1074.     /* Capabilities */
  1075.     atcapu = lpcapu = swcapu = 0;    /* No capabilities by default    */
  1076.     if (rln >= 10) {
  1077.     x = unchar(s[10]);
  1078.     atcapu = (x & atcapb) && atcapr;    /* Attribute packets */
  1079.     lpcapu = (x & lpcapb) && lpcapr;    /* Long packets */
  1080.     swcapu = (x & swcapb) && swcapr;    /* Sliding windows */
  1081.     for (capas = 10; (unchar(s[capas]) & 1) && (rln >= capas); capas++)
  1082.         ;                    /* Skip to capas + 1 */
  1083.     }
  1084.  
  1085.     /* Long packets */
  1086.     if (lpcapu) {            /* Flag set above */
  1087.     if (rln > capas+2) {
  1088.         x = unchar(s[capas+2]) * 95 + unchar(s[capas+3]);
  1089.         spsiz = x > MAXSP ? MAXSP : x;
  1090.     }
  1091.     /* else a fatal error, but how do we terminate? */
  1092.     }
  1093.  
  1094.     /* Sliding windows */
  1095.     if (swcapu) {
  1096.     if (rln > capas+1) {
  1097.         x = unchar(s[capas+1]);
  1098.         wsize = x > MAXWS ? MAXWS : x;
  1099.     } else
  1100.         wsize = 1;
  1101.     }
  1102. }
  1103.  
  1104. /* Fill the array with my send-init parameters */
  1105.  
  1106. static char *
  1107. rpar() {
  1108.     data[1] = tochar(DRPSIZ);        /* Biggest packet I can receive */
  1109.     data[2] = tochar(rtimo);        /* When I want to be timed out */
  1110.     data[3] = tochar(rpadn);        /* How much padding I need */
  1111.     data[4] = ctl(rpadc);        /* Padding character I want */
  1112.     data[5] = tochar(reol);        /* End-of-Line character I want */
  1113.     data[6] = sctlq;            /* Control-Quote character I send */
  1114.     switch(rqf) {            /* 8th-bit prefix */
  1115.     case -1:
  1116.     case  1: if (parity) ebq = sq = '&'; break;
  1117.     case  0:
  1118.     case  2: break;
  1119.     }
  1120.     data[7] = sq;
  1121.     data[8] = bctr + '0';        /* Block Check Type */
  1122.     if (rptflg) data[9] = rptq; else data[9] = '~';
  1123.     data[10] = tochar(atcapr?atcapb:0 | lpcapr?lpcapb:0 | swcapr?swcapb:0);
  1124.     capas = 10;
  1125.     data[capas+1] = tochar(swcapr ? wsize : 0);    /* Window size */
  1126.     data[capas+2] = tochar(rpsiz / 95);    /* Long packet size */
  1127.     data[capas+3] = tochar(rpsiz % 95);    /* ... */
  1128.     data[capas+4] = '\0';
  1129.     return(data+1);            /* Return a pointer to the string */
  1130. }
  1131.  
  1132. /*
  1133.  * proto()--Kermit protocol entry point.  Set your start state and call
  1134.  * this, NOT wart().  Modified to set long packets capability on the
  1135.  * basis of the packet size set in the external user interface.
  1136.  */
  1137. void
  1138. proto()
  1139. {
  1140.     void *malloc();
  1141. #ifdef XPRKERMIT
  1142.     struct XPR_UPDATE xpru;
  1143.  
  1144.     xpru.xpru_protocol = "XPR-Kermit";
  1145.     xpru.xpru_updatemask = XPRU_PROTOCOL;
  1146.     calla(xupdate, &xpru);
  1147.     zclear();
  1148. #endif
  1149.     sndpkt = (char *) malloc((unsigned) (MAXSP+100));
  1150.     rcvpkt = (char *) malloc((unsigned) (MAXRP+200));
  1151.     data = (char *) malloc((unsigned) (MAXSP+4));
  1152.     if (urpsiz > 94) {                /* Long packets? */
  1153.     rpsiz = (urpsiz > MAXRP - 20 ? MAXRP - 20 : urpsiz);
  1154.     lpcapr = 1;                /* Request long packets */
  1155.     } else {                    /* No long packets */
  1156.     lpcapr = 0;
  1157.     if (urpsiz < 10)            /* Too small?    */
  1158.         rpsiz = 80;
  1159.     else
  1160.         rpsiz = DRPSIZ;
  1161.     }
  1162.     urpsiz = rpsiz;
  1163.     cx = cz = 0;                /* Haven't aborted yet */
  1164.     if (bctr < 1)
  1165.     bctr = 1;            /* Legal block check? */
  1166.     if (bctr > 3)
  1167.     bctr = 3;
  1168.     if (sndpkt == NULL || rcvpkt == NULL || data == NULL)
  1169. #ifdef XPRKERMIT
  1170.     ST_Display_String(STMsg,"Can't allocate memory");
  1171. #else
  1172.     tmsgl("Can't allocate memory for Kermit!!");
  1173. #endif
  1174.     else
  1175.     wart();
  1176.     if (sndpkt) free(sndpkt);
  1177.     if (rcvpkt) free(rcvpkt);
  1178.     if (data) free(data);
  1179. }
  1180.     
  1181. /*
  1182.  * That ends the system-independent Kermit modules.  What follows
  1183.  * are the system-dependent ones.
  1184.  */
  1185.  
  1186. /*
  1187.  * Now for the file routines.  I chose to use the z...() routines
  1188.  * written in terms of stdio.
  1189.  */
  1190. #ifndef XPRKERMIT
  1191. #include <stdio.h>
  1192. #else
  1193. typedef struct {
  1194.     int dummy;
  1195. } FILE;
  1196. #define EOF -1
  1197. #endif
  1198.  
  1199. static FILE *ifp = NULL, *ofp = NULL;
  1200.  
  1201. #ifdef XPRKERMIT
  1202. static 
  1203. zclear()
  1204. {
  1205.     ifp = NULL; ofp = NULL;
  1206. }
  1207. #endif
  1208.  
  1209. static
  1210. zopeni(name) char *name; {
  1211. #ifdef XPRKERMIT
  1212.     ifp = (FILE *) callaa(xfopen, name, "r");
  1213. #else
  1214.     ifp = fopen(name, "r");
  1215. #endif
  1216.     if (ifp == NULL)
  1217.     return -1;
  1218.     else
  1219.     return 0;
  1220. }
  1221.  
  1222. static
  1223. zopeno(name) char *name; {
  1224. #ifdef XPRKERMIT
  1225.     ofp = (FILE *) callaa(xfopen, name, "w");
  1226. #else
  1227.     ofp = fopen(name, "w");
  1228. #endif
  1229.     if (ofp == NULL)
  1230.     return -1;
  1231.     else
  1232.     return 0;
  1233. }
  1234.  
  1235. static
  1236. zclosi() {
  1237.     int x;
  1238.  
  1239.     if (ifp == NULL)
  1240.     return 0;
  1241. #ifdef XPRKERMIT
  1242.     x = calla(xfclose, ifp);
  1243. #else
  1244.     x = fclose(ifp);
  1245. #endif
  1246.     ifp = NULL;
  1247.     if (x < 0)
  1248.     return -1;
  1249.     else
  1250.     return 0;
  1251. }
  1252.  
  1253. static
  1254. zcloso(discard) int discard; {
  1255.     int x;
  1256.  
  1257.     if (ofp == NULL)
  1258.     return 0;
  1259. #ifdef XPRKERMIT
  1260.     x = calla(xfclose, ofp);
  1261. #else
  1262.     x = fclose(ofp);
  1263. #endif
  1264.     ofp = NULL;
  1265.     if (x < 0)
  1266.     return -1;
  1267. #if 0
  1268.     else if (discard)
  1269.     if (unlink(filnam) < 0)
  1270.         return -1;
  1271. #endif
  1272.     return 0;
  1273. }
  1274.  
  1275. #include <ctype.h>
  1276.  
  1277. extern int convert;        /* 0 for literal files, 1 for translate */
  1278.  
  1279. /* name from remote to local format */
  1280. static
  1281. zrtol(s1,s2,warn) char *s1, *s2; int warn; {
  1282.     strcpy(s2,s1);        /* for now */
  1283.     if (convert)
  1284.     while (*s2 != '\0') {
  1285.         if (isupper(*s2))
  1286.         *s2 = tolower(*s2);
  1287.         s2++;
  1288.     }
  1289. }
  1290.  
  1291. /* name from local to remote format */
  1292.  
  1293. static
  1294. zltor(s1,s2) char *s1, *s2; {
  1295. #ifdef XPRKERMIT
  1296.     char *EndPath();
  1297. #endif
  1298.     char dotseen = 0;
  1299.  
  1300.     if (!convert)
  1301.     strcpy(s2, s1);
  1302.     else {
  1303. #ifdef XPRKERMIT
  1304.     s1 = EndPath(s1);    /* strip dir/disk */
  1305. #endif
  1306.     while (*s1 != '\0') {
  1307.         if (islower(*s1))
  1308.         *s2 = toupper(*s1);
  1309.         else if (isalnum(*s1))
  1310.         *s2 = *s1;
  1311.         else if (*s1 == '.')
  1312.         if (!dotseen) {
  1313.             dotseen = 1;
  1314.             *s2 = *s1;
  1315.         } else
  1316.             *s2 = 'X';
  1317.         /* else a character we're not prepared to handle. */
  1318.         s1++; s2++;
  1319.         }
  1320.     *s2 = '\0';
  1321.     }
  1322. }
  1323.  
  1324. /*
  1325.  * System-dependent function to return next character from file.
  1326.  * If the text flag argument is nonzero, first convert to canonic form. 
  1327.  */
  1328. static
  1329. zgetc(text) {                /* Get next char from file. */
  1330. #define MAXREC 100            /* Size of record buffer. */
  1331.  
  1332.     static char recbuf[MAXREC + 1];    /* Big enough for MAXREC newlines */
  1333.     static char *rbp;            /* Buffer pointer */
  1334.     static int i = 0;            /* Buffer char counter */
  1335.     int c;
  1336.  
  1337.     if (i == 0) {            /* If the buffer is empty, */
  1338.                     /* read next line from file. */
  1339.     for (i = 0;
  1340.          i < MAXREC - 1 && (c = getc(ifp)) != EOF && c != '\n';
  1341.          i++)
  1342.         recbuf[i] = c;
  1343.     if (c == '\n') {        /* Got newline        */
  1344.         if (text) {            /* If in text mode    */
  1345.         recbuf[i++] = '\r';    /* Substitute CRLF    */
  1346.         }
  1347.         recbuf[i++] = c;
  1348.     }
  1349.     recbuf[i] = '\0';        /* Done, terminate buffer */
  1350.     if (i == 0) return -1;        /* If empty, indicate EOF */
  1351.     rbp = recbuf;            /* Remember position for next time */
  1352.     }
  1353.     i--;                /* Adjust the counter. */
  1354.     return(*rbp++ & 0377);        /* Return hext character */
  1355. }
  1356.  
  1357. static
  1358. zputc(c, text) int c, text; {        /* Put character in file. */
  1359.     unsigned int x;
  1360.  
  1361.     c &= 255;                /* Undo any sign extension */
  1362.     if (text && c == '\r')        /* If in text mode, */
  1363.         return 0;            /* eliminate carriage returns. */
  1364.     else {                /* Otherwise, */
  1365.     x = putc(c, ofp) & 255;        /* output the character. */
  1366.     if (c == 255) return 0;        /* Special handling for all 1's */
  1367.     return ((x != c) ? -1 : 0);    /* Normal return code. */
  1368.     }
  1369. }
  1370.  
  1371. #ifdef XPRKERMIT
  1372. int getc(ifp)
  1373. FILE *ifp;
  1374. {
  1375.     unsigned char buf;
  1376.     long status;
  1377.  
  1378.     status = calladda(xfread, &buf, 1L, 1L, ifp);
  1379.     if (status == 0) return (EOF);
  1380.     else return((int) buf);
  1381. }
  1382.  
  1383. putc(c, ofp)
  1384. int c;
  1385. FILE *ofp;
  1386. {
  1387.     int    status;
  1388.     char cl;
  1389.  
  1390.     cl = c;            /* useful ??? */
  1391.     status = calladda(xfwrite, &cl, 1L, 1L, ofp);
  1392.     if (status == 0) return (EOF);
  1393.     else return(c);
  1394. }
  1395.  
  1396. int ttol(s, n)
  1397. char *s;
  1398. int n;
  1399. {
  1400.     long status;
  1401.  
  1402.     status = callad(xswrite, s, (long) n);
  1403.     if (status == 0) return(n);
  1404.     else return(-1);
  1405. }
  1406.  
  1407. int ttinl(s, max, eol, timeout)
  1408. char *s;
  1409. int max, timeout, eol;
  1410. {
  1411.     int x = 0;
  1412.     char c;
  1413.  
  1414.     *s = '\0';
  1415.     /*
  1416.      * Willy Langeveld assures me that, since serial.device does its
  1417.      * own buffering, callling xsread once for each character isn't
  1418.      * going to take too long.
  1419.      */
  1420.     for (x = 0; x < max; x++) {
  1421.         if (calladd(xsread, &c, 1L, (long) (timeout * 1000000L)) < 0) {
  1422.             return -1;
  1423.         } else if ((s[x] = parity ? c & 127 : c) == eol) {
  1424.             break;
  1425.         } else if (xchkabort()) {
  1426.             cz = cx = brkflag = 1;
  1427.             break;
  1428.         }
  1429.     }
  1430.     s[x] = '\0';
  1431.     return(x);
  1432. #endif
  1433. }
  1434.  
  1435. void ttflui()
  1436. {
  1437.     xsflush();
  1438. }
  1439.  
  1440. void sleep(sec)
  1441. int sec;
  1442. {
  1443.     if (sec) TimeOut((long)sec);
  1444. }
  1445.  
  1446. #define MAXMESSAGE 50
  1447. static char message[MAXMESSAGE+1];
  1448. static int nmess = 0;
  1449. static long errors = 0, blocks = 0;
  1450.  
  1451. /*  screen(f,c,n,s)
  1452.       f - argument descriptor
  1453.       c - a character or small integer
  1454.       n - a long integer
  1455.       s - a string.
  1456.  Fill in this routine with the appropriate display update for the system.
  1457.  This version for XPR Kermit.
  1458. */
  1459.  
  1460. screen(f,c,n,s) int f; long n; char c; char *s; {
  1461.     struct XPR_UPDATE xpru;
  1462.  
  1463.     if (!local || xflag) return;
  1464.     switch (f) {
  1465.     case SCR_PT:            /* Packet Transferred. */
  1466.     if (c == 'Y') return;        /* Don't bother with ACK's. */
  1467.     xpru.xpru_packettype = c;
  1468.     xpru.xpru_blocksize = strlen(s);
  1469.     xpru.xpru_blocks = ++blocks;
  1470.     xpru.xpru_bytes = ffc;
  1471.     xpru.xpru_updatemask = XPRU_PACKETTYPE | XPRU_BLOCKSIZE |
  1472.         XPRU_BLOCKS | XPRU_BYTES;
  1473.     break;
  1474.     case SCR_EM:            /* Error message. */
  1475.     xpru.xpru_errormsg = s;
  1476.     xpru.xpru_updatemask = XPRU_ERRORMSG;
  1477.     break;
  1478.     default:
  1479.     return;
  1480.     }
  1481.     calla(xupdate, &xpru);
  1482. }
  1483.  
  1484. void tchar(c)
  1485. char c;
  1486. {
  1487.     struct XPR_UPDATE xpru;
  1488.  
  1489.     if (c == '%') {        /* retry */
  1490.         xpru.xpru_errors = ++errors;
  1491.         xpru.xpru_updatemask = XPRU_ERRORS;
  1492.     } else if (c == '#') { /* fake it */
  1493.         xpru.xpru_errors = errors = 0;
  1494.         xpru.xpru_blocks = blocks = 0;
  1495.         nmess = 0;            /* Make sure message empty. */
  1496.         xpru.xpru_updatemask = XPRU_BLOCKS | XPRU_ERRORS;
  1497.     } else {
  1498.         message[nmess++] = c;
  1499.         if (nmess >= MAXMESSAGE)
  1500.             tflush();
  1501.         return;
  1502.     }
  1503.     calla(xupdate, &xpru);
  1504. }
  1505.  
  1506. static
  1507. tflush()
  1508. {
  1509.     struct XPR_UPDATE xpru;
  1510.  
  1511.     if (nmess <= 0)
  1512.         return;
  1513.     message[nmess] = '\0';
  1514.     xpru.xpru_errormsg = message;
  1515.     xpru.xpru_updatemask = XPRU_ERRORMSG;
  1516.     calla(xupdate, &xpru);
  1517.     nmess = 0;
  1518. }
  1519.  
  1520. ST_Display_String(Item, S)
  1521. int Item;
  1522. char *S;
  1523. {
  1524.   struct XPR_UPDATE xpru;
  1525.  
  1526.   switch (Item) {
  1527.   case STMsg:
  1528.       xpru.xpru_msg = S;
  1529.     xpru.xpru_updatemask = XPRU_MSG; break;
  1530.   case STFile:
  1531.       xpru.xpru_filename = S;
  1532.     xpru.xpru_updatemask = XPRU_FILENAME; break;
  1533.   case STUplSize:
  1534.       xpru.xpru_filesize = callad(xfinfo, S, 1L);
  1535.     xpru.xpru_updatemask = XPRU_FILESIZE; break;
  1536.   default:
  1537.     return;
  1538.   }
  1539.   calla(xupdate, &xpru);
  1540. }
  1541.  
  1542. ST_Display_CRC(Item)
  1543. int Item;
  1544. {
  1545.   struct XPR_UPDATE xpru;
  1546.  
  1547.   switch (Item) {
  1548.   case 1:
  1549.       xpru.xpru_blockcheck = "Check-6"; break;
  1550.   case 2:
  1551.       xpru.xpru_blockcheck = "Check-12"; break;
  1552.   case 3:
  1553.       xpru.xpru_blockcheck = "CRC-16"; break;
  1554.   default:
  1555.     return;
  1556.   }
  1557.   xpru.xpru_updatemask = XPRU_BLOCKCHECK;
  1558.  
  1559.   calla(xupdate, &xpru);
  1560. }
  1561.  
  1562. extern char *p_pattern;
  1563.  
  1564. #define TRUE    1
  1565. #define FALSE    0
  1566.  
  1567. int gnfile(fname, len)
  1568. char *fname;
  1569. int len;    /* it is 50 */
  1570. {
  1571.     static firsttime = TRUE;
  1572.     char buffer[256];
  1573.     static long state;
  1574.  
  1575.     if (firsttime) {
  1576.         state = callaa(xffirst, buffer, p_pattern);
  1577.         if (state) firsttime = FALSE;
  1578.     } else {
  1579.         state = calldaa(xfnext, state, buffer, p_pattern);
  1580.         if (state == 0L) firsttime = TRUE;
  1581.     }
  1582.     if (state && strlen(buffer)<len) {
  1583.         strcpy(fname, buffer);
  1584.         return((int)state);
  1585.     } else    return(0);
  1586. }
  1587.  
  1588. char *EndPath(p)
  1589. char *p;
  1590. {
  1591.     char *q;
  1592.  
  1593.     q = p;
  1594.     while (*p != '\0') {
  1595.         if ((*p == '/') || (*p == ':'))
  1596.             q = p + 1;
  1597.         p++;
  1598.     }
  1599.     return(q);
  1600. }
  1601.