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 / xprkermit.c < prev    next >
C/C++ Source or Header  |  1990-03-02  |  24KB  |  887 lines

  1. /** xprkermit.c
  2. *
  3. *   These are the protocol transfer routines for a simple Kermit upload/dnload
  4. *
  5. *   Version 0.9--by Marco Papa.
  6. *
  7. *   Version 1.0--updated by Stephen Walton.
  8. *    Added several more user selections to XPRotocolSetup():
  9. *    bctr (block check type to request), limit (retry-limit), and
  10. *    rtimo (timeout for me).  "Real" C Kermit makes many of the
  11. *    things declared as local to kermitproto.w user-settable,
  12. *    such as the send packet size.
  13. *    Also fixed several problems in kermitproto.w.
  14. *
  15. *   Version 1.5--more features
  16. *    Extensive changes.
  17. *    (1) Created a SetupVars variable to hold setting-up information
  18. *    in the XPR_IO structure.  This will allow re-entrancy when and if
  19. *    it comes.  Right now, it mainly gives a way to set up defaults with
  20. *    one assignment.
  21. *    (2) Added the generic Kermit server functions FINISH, BYE, and CD.
  22. *    (3) Added the ability to set options and execute the server functions
  23. *    from a setup string (sent as IO->xpr_filename to XPRotocolSetup()).
  24. *
  25. *    This code is copyright 1990 by Stephen Walton and Marco Papa.  It may
  26. *    be freely distributed in its original or in modified form, provided
  27. *    this copyright notice is kept intact.  It may not be sold for profit,
  28. *    but may be included as part of a commercial program provided that
  29. *    said inclusion does not increase the cost of that program beyond a
  30. *    modest handling fee.
  31. **/
  32. #include <exec/exec.h>
  33. #include <functions.h>
  34. #include <stdio.h>
  35.  
  36. /*
  37.  * xproto.h is the include file given in Appendix B.
  38.  */
  39.  
  40. #include "xproto.h"
  41. #include "xprkermit.h"
  42. #include "kermitproto.h"
  43.  
  44. /*
  45.  * The following two strings must exist.
  46.  */
  47. char            XPRname[] = "xprkermit.library";
  48. char            XPRid[] = "xprkermit 1.5 (9 December 1989)\r\n";
  49. UWORD           XPRrevision = 5;
  50.  
  51. long            atol();
  52. /*
  53.  * The callxx...() routines are described later. They provide the assembler
  54.  * interface from the XPR library to the call-back routines.
  55.  */
  56. long
  57. calla(), callaa(), callad(), calladd(), calladda(), calldaa(),
  58. callda(), calld();
  59.  
  60. /* IMPORTANT: this makes it non-reentrant !!!! */
  61. long            (*xupdate) (), (*xswrite) (), (*xfopen) (), (*xfclose) (), (*xfread) (),
  62.                 (*xsread) (), (*xchkabort) (), (*xfnext) (), (*xffirst) (), (*xsflush) (),
  63.                 (*xfwrite) (), (*xgets) (), (*xfinfo) ();
  64.  
  65. /*
  66.  * External and forward declarations.
  67.  */
  68.  
  69. char           *malloc(), *strcpy(), *index();
  70. void            ioerr(), XPRLong();
  71. SetupVars      *setup();
  72. extern char     start;
  73.  
  74. /*
  75.  * The flags for the kermitproto.w module.
  76.  */
  77. char           *p_pattern;    /* wildcard pattern */
  78. int             parity;        /* parity on? 0 for no parity--need for
  79.                  * proper 8th-bit quote */
  80. int             text;        /* Text or binary mode? Flag 1 for text file,
  81.                  * 0 for binary file     */
  82. int             convert;    /* Convert file names to lower case? 0 for
  83.                  * literal files (no), 1 for translate (yes) */
  84. int             urpsiz;        /* Kermit maximum packet size. Maximum
  85.                  * receive packet size user wants.     */
  86. char           *cmarg;        /* Character string containing Kermit server
  87.                  * cmd */
  88.  
  89. extern int      bctr;        /* Block check type to request. */
  90. extern int      limit;        /* Retry limit.  May increase on very noisy
  91.                  * lines. */
  92. extern int      rtimo;        /* Timeout to request. */
  93.  
  94. int             getfile;    /* Host server. 0 = Receive (no) ; 1 = Get
  95.                  * (yes) */
  96. long            brkflag;
  97.  
  98. static SetupVars Defaults = {
  99.     {""},            /* No default file name. */
  100.     0,                /* Parity defaults to off. */
  101.     1,                /* Text file defaults to on. */
  102.     1,                /* Convert file names by default. */
  103.     94,                /* Default maximum packet length. */
  104.     1,                /* Default block check type. */
  105.     5,                /* Retry limit */
  106.     10,                /* Timeout (seconds) */
  107.     0,                /* Host is server?  No by default. */
  108. };
  109.  
  110. /**
  111. *
  112. *   Send a file
  113. *
  114. **/
  115. long
  116. XProtocolSend(IO)
  117.     struct XPR_IO  *IO;
  118. {
  119.     struct XPR_UPDATE xpru;
  120.     SetupVars      *sv;
  121.  
  122.     brkflag = 0;
  123.  
  124.     if ((sv = setup(IO)) == NULL)
  125.     return 0L;        /* Initialize parameters. */
  126.     /*
  127.      * Read the text/binary set using xpr_finfo if present.  Else use the
  128.      * value chosen in XPRotocolSetup.
  129.      */
  130.     if (xfinfo) {
  131.     /*
  132.      * Use feature that calling xpr_finfo with a zero-length filename
  133.      * returns setting of internal comm program Text/Binary flag.
  134.      */
  135.     text = (callad(xfinfo, IO->xpr_filename, 2L) == 1 ? 0 : 1);
  136.     }
  137.     /*
  138.      * Start the transfer. See 3.8 for a discussion on how to implement
  139.      * xupdate.
  140.      */
  141.     tchar('#');
  142.  
  143.     /*
  144.      * Copy filename, and put pointer in external Kermit variable.
  145.      */
  146.     strcpy(sv->FileName, IO->xpr_filename);
  147.     p_pattern = sv->FileName;
  148.     /*
  149.      * */
  150.     start = 's';
  151.     proto();
  152.  
  153.     /*
  154.      * If we got here through chkabort() say Aborted.
  155.      */
  156.     xpru.xpru_updatemask = XPRU_MSG;
  157.     if (brkflag)
  158.     xpru.xpru_msg = "Aborted";
  159.     else
  160.     xpru.xpru_msg = "Done";
  161.     (void) calla(xupdate, &xpru);
  162.     if (brkflag)
  163.     return (0L);
  164.     else
  165.     return (1L);
  166. }
  167.  
  168.  
  169. /**
  170. *
  171. *   Receive a file.
  172. *
  173. **/
  174. long
  175. XProtocolReceive(IO)
  176.     struct XPR_IO  *IO;
  177. {
  178.     struct XPR_UPDATE xpru;
  179.     long            status;
  180.     SetupVars      *sv;
  181.  
  182.  
  183.     brkflag = 0;
  184.  
  185.     if ((sv = setup(IO)) == NULL)
  186.     return 0L;            /* Initialize parameters. */
  187.     /*
  188.      * Read the text/binary set using xpr_finfo if present.  Else use the
  189.      * value chosen in XPRotocolSetup.
  190.      */
  191.     if (xfinfo) {
  192.     /*
  193.      * Use feature th at calling xpr_finfo with a zero-length filename
  194.      * returns setting of internal comm program Text/Binary flag.
  195.      */
  196.     text = (callad(xfinfo, "", 2L) == 1 ? 0 : 1);
  197.     }
  198.     /*
  199.      * Start the transfer. See 3.8 for a discussion on how to implement
  200.      * xupdate.
  201.      */
  202.     tchar('#');
  203.  
  204.     /*
  205.      * */
  206.     if (getfile) {
  207.     /*
  208.      * Copy filename, and put pointer in external Kermit variable.
  209.      */
  210.     cmarg = sv->FileName;
  211.     start = 'r';
  212.     status = callaa(xgets, "Host Filename", cmarg);
  213.     if (!status)
  214.         return (0L);
  215.     } else
  216.     start = 'v';
  217.     proto();
  218.  
  219.     /*
  220.      * If we got here through chkabort() say Aborted.
  221.      */
  222.     xpru.xpru_updatemask = XPRU_MSG;
  223.     if (brkflag)
  224.     xpru.xpru_msg = "Aborted";
  225.     else
  226.     xpru.xpru_msg = "Done";
  227.     (void) calla(xupdate, &xpru);
  228.     if (brkflag)
  229.     return (0L);
  230.     else
  231.     return (1L);
  232. }
  233.  
  234. /*
  235.  * Perform a generic Kermit server command.
  236.  */
  237. static
  238. DoGeneric(IO, s)
  239.     struct XPR_IO  *IO;
  240.     char           *s;
  241. {
  242.     SetupVars *sv;
  243.  
  244.     if ((sv = setup(IO)) == NULL)
  245.     return 0;            /* Set up transfer characteristics. */
  246.     brkflag = 0;
  247.     start = 'g';
  248.     cmarg = s;
  249.     proto();
  250.     if (brkflag)
  251.     return (0);
  252.     else
  253.     return (1);
  254. }
  255.  
  256. /*
  257.  * Execute a Kermit FINISH command.
  258.  */
  259. static
  260. KermitFinish(IO)
  261.     struct XPR_IO  *IO;
  262. {
  263.     return (DoGeneric(IO, "F"));
  264. }
  265.  
  266. /*
  267.  * Execute a Kermit BYE command.
  268.  */
  269. static
  270. KermitBye(IO)
  271.     struct XPR_IO  *IO;
  272. {
  273.     return (DoGeneric(IO, "L"));
  274. }
  275.  
  276. /*
  277.  * Change directory on remote server.  We need to return an error if the CD
  278.  * fails on the remote end.
  279.  */
  280. static
  281. KermitCd(IO, dir)
  282.     struct XPR_IO  *IO;
  283.     char           *dir;
  284. {
  285.     char            CdCommand[100];
  286.     int             retval;
  287.  
  288.     CdCommand[0] = 'C';
  289.     CdCommand[1] = tochar(strlen(dir));
  290.     strcpy(CdCommand + 2, dir);
  291.     retval = DoGeneric(IO, CdCommand);
  292.     return retval;
  293. }
  294.  
  295. #if AZTEC_C
  296. /*
  297.  * Case-independent string comparison for Aztec C. Modification of the
  298.  * strcmp() routine from Henry Spencer's portable string library.  Depends on
  299.  * a toupper() function (as opposed to macro).
  300.  */
  301.  
  302. int                /* <0 for <, 0 for ==, >0 for > */
  303. stricmp(s1, s2)
  304.     char           *s1;
  305.     char           *s2;
  306. {
  307.     register char  *scan1;
  308.     register char  *scan2;
  309.  
  310.     scan1 = s1;
  311.     scan2 = s2;
  312.     while (*scan1 != '\0' && toupper(*scan1) == toupper(*scan2)) {
  313.     scan1++;
  314.     scan2++;
  315.     }
  316.  
  317.     /*
  318.      * The following case analysis is necessary so that characters which look
  319.      * negative collate low against normal characters but high against the
  320.      * end-of-string NUL.
  321.      */
  322.     if (*scan1 == '\0' && *scan2 == '\0')
  323.     return (0);
  324.     else if (*scan1 == '\0')
  325.     return (-1);
  326.     else if (*scan2 == '\0')
  327.     return (1);
  328.     else
  329.     return (toupper(*scan1) - toupper(*scan2));
  330. }
  331.  
  332. #endif
  333.  
  334. /**
  335. *
  336. *   Setup
  337. *
  338. * First, a general-purpose comparison for either of the two possible returns
  339. * indicating a Yes push on a Boolean gadget.
  340. **/
  341.  
  342. #define XprBoolTrue(s) ((stricmp(s, "yes") == 0) || (stricmp(s, "on") == 0))
  343.  
  344. /*
  345.  * Then, a small set of code to initialize a string based on a value.
  346.  */
  347.  
  348. #define XprSet(value, string) (value ? \
  349.    (void) strcpy(string, YesString) : \
  350.    (void) strcpy(string, NoString)) \
  351.  
  352. static char     YesString[] = "yes";
  353. static char     NoString[] = "no";
  354.  
  355. /*
  356.  * If Setup() succeeds, flag same.  Also, we don't need a file requester
  357.  * on receive.
  358.  */
  359. #define SUCCESS (XPRS_SUCCESS | XPRS_NORECREQ)
  360.  
  361. long
  362. XProtocolSetup(IO)
  363.     struct XPR_IO  *IO;
  364. {
  365.     long            (*xupdate) (), (*xgets) (), (*xoptions) (), (*xfinfo) ();
  366.     struct XPR_UPDATE xpru;
  367. #define NOPTS 8
  368.     struct xpr_option opt[NOPTS], *popt[NOPTS];
  369. #define MAXSTRING 6
  370.     char            ValueStrings[NOPTS][MAXSTRING];
  371.     long            status;
  372.     int             i, j;
  373.     char            buf[256];
  374.     SetupVars      *sv, tempvar;
  375.  
  376.     if ((xupdate = IO->xpr_update) == NULL)
  377.     return (XPRS_FAILURE);
  378.     if ((xgets = IO->xpr_gets) == NULL)
  379.     return (XPRS_FAILURE);
  380.  
  381.     /*
  382.      * Allocate memory for file name buffer and options if first call. Copy
  383.      * defaults into it and then merge in user changes.
  384.      */
  385.     if ((sv = (SetupVars *) IO->xpr_data) == NULL) {
  386.     if ((sv = (SetupVars *) malloc((unsigned) sizeof(SetupVars))) == NULL)
  387.         return XPRS_FAILURE;
  388.     *sv = Defaults;
  389.     IO->xpr_data = (long *) sv;
  390.     }
  391.     tempvar = *sv;
  392.     /*
  393.      * In order to use xpr_options, we must have all of the three conditions
  394.      * which follow true.  Otherwise, either IO->xpr_filename is non-NULL, in
  395.      * which case we assume it contains a setup string, or there is no
  396.      * xpr_options, in which case we use xpr_gets to retrieve a setup string.
  397.      */
  398.     if (IO->xpr_filename == NULL &&
  399.     IO->xpr_extension >= 1 &&
  400.     (xoptions = IO->xpr_options) != NULL) {
  401.  
  402.     /*
  403.      * I use a counter, i, here, so that I can stick in more options
  404.      * without needing to change a lot of numbers.  I can also skip
  405.      * options dynamically, as in Text below.
  406.      */
  407. #if 1
  408.     i = 0;
  409.     /* Announce us. */
  410.     opt[i].xpro_description = "Kermit Commands 1.5";
  411.     opt[i].xpro_type = XPRO_HEADER;
  412.     opt[i].xpro_value = NULL;
  413.     opt[i].xpro_length = 0;
  414.     i++;
  415.     /*
  416.      * First, do the Kermit server command items.
  417.      */
  418.     opt[i].xpro_description = "Kermit FINISH";
  419.     opt[i].xpro_type = XPRO_COMMAND;
  420.     opt[i].xpro_value = NULL;
  421.     opt[i].xpro_length = 0;
  422.     i++;
  423.     opt[i].xpro_description = "Kermit BYE";
  424.     opt[i].xpro_type = XPRO_COMMAND;
  425.     opt[i].xpro_value = NULL;
  426.     opt[i].xpro_length = 0;
  427.     i++;
  428.     opt[i].xpro_description = "Kermit CD";
  429.     opt[i].xpro_type = XPRO_COMMPAR;
  430.     buf[0] = '\0';
  431.     opt[i].xpro_value = buf;        /* Use buf to hold dir name. */
  432.     opt[i].xpro_length = sizeof(buf) - 1;
  433.     i++;
  434.     opt[i].xpro_description = "Kermit Options";
  435.     opt[i].xpro_type = XPRO_COMMAND;
  436.     opt[i].xpro_value = NULL;
  437.     opt[i].xpro_length = 0;
  438.     i++;
  439.     /* show requester after loading pointers */
  440.     for (j = 0; j < i; j++)
  441.         popt[j] = &opt[j];
  442.     status = callda(xoptions, (long) i, popt);
  443.     /* check returned value */
  444.     if (status == -1L)
  445.         return XPRS_FAILURE;
  446.     /* Check returned value to see what we are to do. */
  447.     i = 1;
  448.     if (status & (1L << i))
  449.         return (KermitFinish(IO) ? SUCCESS : XPRS_FAILURE);
  450.     i++;
  451.     if (status & (1L << i))
  452.         return (KermitBye(IO) ? SUCCESS : XPRS_FAILURE);
  453.     i++;
  454.     if (status & (1L << i))
  455.         return (KermitCd(IO, opt[i].xpro_value) ? SUCCESS : XPRS_FAILURE);
  456. #endif
  457.     /* If we get to this point, we are to set options. */
  458.     i = 0;            /* Start over. */
  459.     opt[i].xpro_description = "Kermit Options 1.5";
  460.     opt[i].xpro_type = XPRO_HEADER;
  461.     opt[i].xpro_value = NULL;
  462.     opt[i].xpro_length = 0;
  463.     i++;
  464.     /* Convert filename */
  465.     opt[i].xpro_description = "Convert Filename";
  466.     opt[i].xpro_type = XPRO_BOOLEAN;
  467.     XprSet(tempvar.ConvertFlag, ValueStrings[i]);
  468.     opt[i].xpro_value = ValueStrings[i];
  469.     opt[i].xpro_length = MAXSTRING;
  470.     i++;
  471.     /* host is server */
  472.     opt[i].xpro_description = "Host Server";
  473.     opt[i].xpro_type = XPRO_BOOLEAN;
  474.     XprSet(tempvar.GetFlag, ValueStrings[i]);
  475.     opt[i].xpro_value = ValueStrings[i];
  476.     opt[i].xpro_length = MAXSTRING;
  477.     i++;
  478.     /*
  479.      * file type -- only show this if xpr_finfo not present, or returns
  480.      * error when we try to get the file type.
  481.      */
  482.     if ((xfinfo = IO->xpr_finfo) == NULL ||
  483.         (tempvar.TextFlag = (callad(xfinfo, "", 2L))) == 0) {
  484.         tempvar.TextFlag = -1;    /* Flag xfinfo failed. */
  485.         opt[i].xpro_description = "Text File";
  486.         opt[i].xpro_type = XPRO_BOOLEAN;
  487.         XprSet(tempvar.TextFlag, ValueStrings[i]);
  488.         opt[i].xpro_value = ValueStrings[i];
  489.         opt[i].xpro_length = MAXSTRING;
  490.         i++;
  491.     } else
  492.         /*
  493.          * Switch to 0 for binary, 1 for text; xpr_finfo returns 1 for
  494.          * binary, 2 for text.
  495.          */
  496.         tempvar.TextFlag -= 1;
  497.     /* Packet size */
  498.     opt[i].xpro_description = "Packet Size";
  499.     opt[i].xpro_type = XPRO_LONG;
  500.     (void) sprintf(ValueStrings[i], "%-d", tempvar.MaxPacket);
  501.     opt[i].xpro_value = ValueStrings[i];
  502.     opt[i].xpro_length = MAXSTRING;
  503.     i++;
  504.     /* Block Check type */
  505.     opt[i].xpro_description = "Block Check (1, 2, 3)";
  506.     opt[i].xpro_type = XPRO_LONG;
  507.     (void) sprintf(ValueStrings[i], "%-d", tempvar.BlockCheckType);
  508.     opt[i].xpro_value = ValueStrings[i];
  509.     opt[i].xpro_length = MAXSTRING;
  510.     i++;
  511.     /* Retry Limit */
  512.     opt[i].xpro_description = "Maximum Retries";
  513.     opt[i].xpro_type = XPRO_LONG;
  514.     (void) sprintf(ValueStrings[i], "%-d", tempvar.RetryLimit);
  515.     opt[i].xpro_value = ValueStrings[i];
  516.     opt[i].xpro_length = MAXSTRING;
  517.     i++;
  518.     /* Timeout */
  519.     opt[i].xpro_description = "Timeout (seconds)";
  520.     opt[i].xpro_type = XPRO_LONG;
  521.     (void) sprintf(ValueStrings[i], "%-d", tempvar.Timeout);
  522.     opt[i].xpro_value = ValueStrings[i];
  523.     opt[i].xpro_length = MAXSTRING;
  524.     i++;
  525.     /* show requester after loading pointers */
  526.     for (j = 0; j < i; j++)
  527.         popt[j] = &opt[j];
  528.     /* show requester */
  529.     status = callda(xoptions, (long) i, popt);
  530.     /* check returned value */
  531.     if (status == -1L)
  532.         return XPRS_FAILURE;
  533.     i = 1;            /* Skip header         */
  534.     if (status & (1L << i))
  535.         tempvar.ConvertFlag = XprBoolTrue(opt[i].xpro_value) ? 1 : 0;
  536.     i++;
  537.     if (status & (1L << i))
  538.         tempvar.GetFlag = XprBoolTrue(opt[i].xpro_value) ? 1 : 0;
  539.     i++;
  540.     if (xfinfo == NULL || tempvar.TextFlag == -1) {
  541.         if (status & (1L << i))
  542.         tempvar.TextFlag = XprBoolTrue(opt[i].xpro_value) ? 1 : 0;
  543.         i++;
  544.     }
  545.     if (status & (1L << i))
  546.         tempvar.MaxPacket = atoi(opt[i].xpro_value);
  547.     i++;
  548.     if (status & (1L << i))
  549.         tempvar.BlockCheckType = atoi(opt[i].xpro_value);
  550.     i++;
  551.     if (status & (1L << i))
  552.         tempvar.RetryLimit = atoi(opt[i].xpro_value);
  553.     i++;
  554.     if (status & (1L << i))
  555.         tempvar.Timeout = atoi(opt[i].xpro_value);
  556.     } else {
  557.     if (IO->xpr_filename != NULL)
  558.         strcpy(buf, IO->xpr_filename);    /* Save setup string */
  559.     else {            /* Prompt for command/options string */
  560.         sprintf(buf, "OC%c,G%c,T%c,P%d,B%d,R%d,O%d", tempvar.ConvertFlag ? 'Y' : 'N',
  561.             tempvar.GetFlag ? 'Y' : 'N', tempvar.TextFlag ? 'Y' : 'N', tempvar.MaxPacket,
  562.            tempvar.BlockCheckType, tempvar.RetryLimit, tempvar.Timeout);
  563.         if (callaa(xgets, "Kermit Options", buf) == 0)
  564.         return XPRS_FAILURE;    /* Failed to set up? */
  565.     }
  566.     switch (buf[0]) {
  567.     case 'F':
  568.         return (KermitFinish(IO) ? SUCCESS : XPRS_FAILURE);
  569.     case 'B':
  570.         return (KermitBye(IO) ? SUCCESS : XPRS_FAILURE);
  571.     case 'C':
  572.         return (KermitCd(IO, buf + 1) ? SUCCESS : XPRS_FAILURE);
  573.     case 'O':
  574.         if (SetupFromString(IO, buf, &tempvar) == 0)
  575.         return XPRS_FAILURE;
  576.         break;
  577.     case '\0':
  578.         break;
  579.     default:
  580.         ioerr(IO, "Unrecognized XPR Kermit setup string");
  581.         break;
  582.     }
  583.     }
  584.     *sv = tempvar;        /* Copy setups into safe place. */
  585.     /*
  586.      * Return success and inform caller that we don't need a requester for
  587.      * receive.
  588.      */
  589.     return SUCCESS;
  590. }
  591.  
  592. static char Delimiters[] = " \t\r\n,";
  593.  
  594. SetupFromString(IO, s, sv)
  595.     struct XPR_IO  *IO;
  596.     char           *s;
  597.     SetupVars      *sv;
  598. {
  599.     char           *p, *strtok();
  600.     char            errbuf[50];
  601.  
  602.     if (*s != 'O')
  603.     return 0;        /* Options string must start with O. */
  604.     s++;            /* Skip leading O. */
  605.     /*
  606.      * Hunt for options with strtok.  We allow whitespace and commas to
  607.      * separate options.
  608.      */
  609.     for (p = strtok(s, Delimiters); p != NULL; p = strtok(NULL, Delimiters)) {
  610.     switch (*p++) {                /* Auto-increment to option */
  611.     case 'C':                /* Case conversion. */    
  612.         if (*p == 'Y' || *p == 'N')
  613.         sv->ConvertFlag = (*p == 'Y');
  614.         else
  615.         ioerr(IO, "Illegal C option format (must be Y or N)");
  616.         break;
  617.     case 'G':                /* Get files (Host server) */
  618.         if (*p == 'Y' || *p == 'N')
  619.         sv->GetFlag = (*p == 'Y');
  620.         else
  621.         ioerr(IO, "Illegal G option format (must be Y or N)");
  622.         break;
  623.     case 'T':                /* Text file */
  624.         if (*p == 'Y' || *p == 'N')
  625.         sv->TextFlag = (*p == 'Y');
  626.         else
  627.         ioerr(IO, "Illegal T option format (must be Y or N)");
  628.         break;
  629.     case 'P':                /* Maximum packet length */
  630.         sv->MaxPacket = atoi(p);
  631.         break;
  632.     case 'B':                /* Block check type. */
  633.         sv->BlockCheckType = atoi(p);
  634.         break;
  635.     case 'R':                /* Retry limit */
  636.         sv->RetryLimit = atoi(p);
  637.         break;
  638.     case 'O':                /* Timeout */
  639.         sv->Timeout = atoi(p);
  640.         break;
  641.     default:
  642.         sprintf(errbuf, "Illegal XPR Kermit option: %c", p[-1]);
  643.         ioerr(IO, errbuf);
  644.         break;
  645.     }
  646.     }
  647.     return 1;
  648. }
  649.  
  650. /**
  651. *
  652. *   Cleanup
  653. *
  654. **/
  655. long
  656. XProtocolCleanup(IO)
  657.     struct XPR_IO  *IO;
  658. {
  659.     if (IO->xpr_data)
  660.     free(IO->xpr_data);
  661.     IO->xpr_data = NULL;
  662.  
  663.     return (1L);
  664. }
  665.  
  666. int
  667. XPRParity(IO)
  668.     struct XPR_IO  *IO;
  669. {
  670.     long            (*xsetserial) ();
  671.     struct XPR_UPDATE xpru;
  672.     long            status;
  673.  
  674.     /* check out parity */
  675.     if (xsetserial = IO->xpr_setserial) {
  676.     status = calld(xsetserial, -1L);
  677.     if (status & 0x00000001L)
  678.         return 1;
  679.     else
  680.         return 0;
  681.     } else
  682.     return 0;        /* Assume no parity if can't tell. */
  683. }
  684.  
  685. void
  686. XPRLong(IO, i)
  687.     struct XPR_IO  *IO;
  688.     long            i;
  689. {
  690.     long            (*xupdate) ();
  691.     struct XPR_UPDATE xpru;
  692.     char            locbuf[80];
  693.  
  694.     if ((xupdate = IO->xpr_update) == NULL)
  695.     return;
  696.     /* debug: show long value */
  697.     xpru.xpru_updatemask = XPRU_MSG;
  698.     sprintf(locbuf, "%lx", i);
  699.     xpru.xpru_msg = &locbuf[0];
  700.     calla(xupdate, &xpru);
  701. }
  702.  
  703. /*
  704.  * Copy setup variables into the local copies.  If there are none, then
  705.  * simply copy the defaults.
  706.  */
  707. static SetupVars *
  708. setup(IO)
  709.     struct XPR_IO  *IO;
  710. {
  711.     register SetupVars *Current;
  712.  
  713.     /*
  714.      * These are the call-backs we need. If any of them isn't provided, quit.
  715.      * Could do some error reporting if at least xupdate is there.
  716.      */
  717.     if ((xupdate = IO->xpr_update) == NULL)
  718.     return (0L);
  719.     if ((xswrite = IO->xpr_swrite) == NULL)
  720.     return (0L);
  721.     if ((xfopen = IO->xpr_fopen) == NULL)
  722.     return (0L);
  723.     if ((xfclose = IO->xpr_fclose) == NULL)
  724.     return (0L);
  725.     if ((xfread = IO->xpr_fread) == NULL)
  726.     return (0L);
  727.     if ((xsread = IO->xpr_sread) == NULL)
  728.     return (0L);
  729.     if ((xchkabort = IO->xpr_chkabort) == NULL)
  730.     return (0L);
  731.     if ((xfnext = IO->xpr_fnext) == NULL)
  732.     return (0L);
  733.     if ((xffirst = IO->xpr_ffirst) == NULL)
  734.     return (0L);
  735.     if ((xsflush = IO->xpr_sflush) == NULL)
  736.     return (0L);
  737.     if ((xfwrite = IO->xpr_fwrite) == NULL)
  738.     return (0L);
  739.     if ((xgets = IO->xpr_gets) == NULL)
  740.     return (0L);
  741.     xfinfo = IO->xpr_finfo;
  742.  
  743.     if (IO->xpr_data == NULL) {
  744.     if ((IO->xpr_data = (long *) malloc((unsigned) sizeof(SetupVars)))
  745.             == NULL) {
  746.         ioerr(IO, "Out of memory!");
  747.         return NULL;
  748.     }
  749.     Current = (SetupVars *) IO->xpr_data;
  750.     *Current = Defaults;
  751.     } else
  752.     Current = (SetupVars *) IO->xpr_data;
  753.     parity = Current->ParityFlag = XPRParity(IO);
  754.     text = Current->TextFlag;
  755.     convert = Current->ConvertFlag;
  756.     urpsiz = Current->MaxPacket;
  757.     bctr = Current->BlockCheckType;
  758.     limit = Current->RetryLimit;
  759.     rtimo = Current->Timeout;
  760.     getfile = Current->GetFlag;
  761.     return Current;
  762. }
  763.  
  764. /*
  765.  * Have the comm program display an error message for us, using a temporary
  766.  * XPR_UPDATE structure; used to display errors before Vars gets allocated
  767.  */
  768. void
  769. ioerr(IO, msg)
  770.     struct XPR_IO  *IO;
  771.     char           *msg;
  772. {
  773.     struct XPR_UPDATE xpru;
  774.     long            (*xupdate) ();
  775.  
  776.     if (xupdate = IO->xpr_update) {
  777.     xpru.xpru_updatemask = XPRU_ERRORMSG;
  778.     xpru.xpru_errormsg = msg;
  779.     (void) calla(xupdate, &xpru);
  780.     }
  781. }
  782.  
  783. #if AZTEC_C
  784. /*
  785.  * Simple, re-entrant versions of malloc() and free to replace the ones in
  786.  * the Aztec C libraries.  The only reason to use these instead of AllocMem()
  787.  * is that these remember the size of the stuff allocated.
  788.  */
  789.  
  790. char *malloc(n)
  791. unsigned n;
  792. {
  793.     long *p;
  794.  
  795.     if ((p = AllocMem((long) n + sizeof(long), MEMF_PUBLIC | MEMF_CLEAR)) == NULL)
  796.     return NULL;
  797.     p[0] = n;
  798.     return ((char *) &p[1]);
  799. }
  800.  
  801. free(p)
  802. char *p;
  803. {
  804.     long *s = (long *) p;
  805.  
  806.     FreeMem(&s[-1], s[-1]);
  807.     return 1;
  808. }
  809. #endif
  810. /**
  811. *
  812. *   The following functions setup the proper registers for the call-back 
  813. *   functions.
  814. *
  815. **/
  816. #ifndef _lint
  817.  
  818. #asm
  819.         public _callad
  820. _callad:
  821.         movea.l 8(sp),a0                ; Second argument goes in a0
  822.         move.l  12(sp),d0               ; Third  argument goes in d0
  823. /*
  824. *   Now this is a trick to avoid using another register.
  825. *   Charlie taught me this...
  826. */
  827.         move.l  4(sp),-(sp)             ; First  argument is function
  828.         rts
  829.  
  830.         public  _calladda
  831. _calladda:
  832.         movea.l 8(sp),a0                ; Second argument goes in a0
  833.         move.l  12(sp),d0               ; Third  argument goes in d0
  834.         move.l  16(sp),d1               ; Fourth argument goes in d1
  835.         movea.l 20(sp),a1               ; Fifth  argument goes in a1
  836.         move.l  4(sp),-(sp)             ; First  argument is function
  837.         rts
  838.  
  839.         public  _calldaa
  840. _calldaa:
  841.         move.l  8(sp),d0                ; Second  argument goes in d0
  842.         movea.l 12(sp),a0               ; Third argument goes in a0
  843.         movea.l 16(sp),a1               ; Fourth argument goes in a1
  844.         move.l  4(sp),-(sp)             ; First  argument is function
  845.         rts
  846.  
  847.         public  _calla
  848. _calla:
  849.         movea.l 8(sp),a0                ; Second argument goes in a0
  850.         move.l  4(sp),-(sp)             ; First  argument is function
  851.         rts
  852.  
  853.         public  _calld
  854. _calld:
  855.         move.l  8(sp),d0                ; Second argument goes in d0
  856.         move.l  4(sp),-(sp)             ; First  argument is function
  857.         rts
  858.  
  859.         public  _callaa
  860. _callaa:
  861.         movea.l 8(sp),a0                ; Second argument goes in a0
  862.         movea.l 12(sp),a1               ; Third  argument goes in a1
  863.         move.l  4(sp),-(sp)             ; First  argument is function
  864.         rts
  865.  
  866.         public  _callda
  867. _callda:
  868.         move.l  8(sp),d0                ; Second argument goes in d0
  869.         movea.l 12(sp),a0               ; Third  argument goes in a0
  870.         move.l  4(sp),-(sp)             ; First  argument is function
  871.         rts
  872.  
  873.         public  _calladd
  874. _calladd:
  875.         movea.l  8(sp),a0               ; Second argument goes in a0
  876.         move.l  12(sp),d0               ; Third  argument goes in d0
  877.         move.l  16(sp),d1               ; Fourth argument goes in d1
  878.         move.l  4(sp),-(sp)             ; First  argument is function
  879.         rts
  880.  
  881. #endasm
  882. /*
  883. *   Could have added any other functions needed for other call-backs.
  884. *   Could have written a fancier single one... Could've...
  885. */
  886. #endif
  887.