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 / Vt100 / Src.lzh / Src / kermitproto.c < prev    next >
C/C++ Source or Header  |  1990-03-01  |  42KB  |  1,338 lines

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