home *** CD-ROM | disk | FTP | other *** search
/ High Voltage Shareware / high1.zip / high1 / DIR3 / KA9Q212.ZIP / RZ.C < prev    next >
C/C++ Source or Header  |  1993-07-16  |  35KB  |  1,512 lines

  1. /****************************************************************************
  2. *    Language     :    Turbo C 2.0                                                *
  3. *    Logfile        :    rz.c                                                    *
  4. *    Project        :    Comms library.                                            *
  5. *    Date         :    24 Jan 90                                                *
  6. *    Revision     :    1.1        GT    PC version.                                    *
  7. *    07 Mar 90    :    1.2        GT    Background transfer.                        *
  8. *    25 Oct 92    :    1.3        GT    KA9Q mods.                                    *
  9. *    30 Jan 93    :    1.4        GT    Fix KA9Q background transfer.                *
  10. *    20 Feb 93    :    1.5        GT    Bump HOWMANY to 2048.                        *
  11. *    21 Feb 93    :    1.6        GT    Allocate buffer on heap.                    *
  12. *    08 May 93    :    1.7        GT    Fix warnings.                                *
  13. *****************************************************************************
  14. *    Purpose        :    File receive driver.                                    *
  15. *****************************************************************************
  16. *                :    This module is based on the equivalent module in the    *
  17. *                :    31 Aug 87 version of rz/sz.                                *
  18. *    $Id: rz.c 1.5 93/07/16 11:49:53 ROOT_DOS Exp $
  19. ****************************************************************************/
  20.  
  21. #include    <io.h>
  22. #include    <fcntl.h>
  23. #include    <stdio.h>
  24. #include    <stdlib.h>
  25. #include    <signal.h>
  26. #include    <setjmp.h>
  27. #include    <ctype.h>
  28. #include    <time.h>
  29. #include    <string.h>
  30. #include    <process.h>
  31. #include    <sys/types.h>
  32. #include    <sys/stat.h>
  33. #include    <dos.h>
  34. #include    "zmodem.h"
  35. #include    "sz.h"
  36. #include    "rbsb.h"        /* most of the system dependent stuff here        */
  37. #include    "zm.h"
  38. #include    "global.h"
  39. #ifdef    DEBUGZ
  40. #include    "tty.h"
  41. #endif
  42.  
  43.  
  44. /*
  45.  * Max value for HOWMANY is 255.
  46.  *   A larger value reduces system overhead but may evoke kernel bugs.
  47.  *   133 corresponds to an XMODEM/CRC sector
  48.  */
  49.  
  50. #ifndef HOWMANY
  51. #define HOWMANY 2048            /* was 133                                        */
  52. #endif
  53.  
  54. #undef    RETRYMAX
  55. #define RETRYMAX    5
  56.  
  57. #define UNIXFILE 0x8000        /* the S_IFREG file mask bit for stat            */
  58. #define DEFBYTL 2000000000L    /* default rx file size                            */
  59. #define    CANBREAK
  60.  
  61. static int fout;
  62. static int Eofseen;            /* indicates cpm eof (^Z) has been received        */
  63.  
  64. int Readnum = HOWMANY;         /* Number of bytes to ask for in read () from
  65.                                  modem                                         */
  66.  
  67. static long Bytesleft;        /* number of bytes of incoming file left        */
  68. static long Modtime;        /* Unix style mod time for incoming file        */
  69. static short Filemode;        /* Unix style mode for incoming file            */
  70. static char Pathname[PATHLEN];
  71.  
  72. static int Batch = 0;
  73. static int MakeLCPathname = TRUE; /* make received pathname lower case        */
  74. static int Nflag = 0;        /* Don't really transfer files                    */
  75. static int Rxbinary = FALSE; /* receive all files in bin mode                */
  76. static int Rxascii = FALSE;    /* receive files in ascii (translate) mode        */
  77. static int Thisbinary;        /* current file is to be received in bin mode    */
  78. static int rz_blklen;        /* record length of received packets            */
  79. static char secbuf[KSIZE + 1];
  80. #if    0
  81. static char linbuf[HOWMANY];
  82. #endif
  83. static char *linbuf = 0;    /* -> receive buffer                            */
  84. int Lleft = 0;                /* number of characters in linbuf                */
  85. static int Filcnt = 0;        /* no of files transferred                        */
  86.  
  87. #if    0
  88. time_t timep[2];
  89. #endif
  90. static int nocommand = FALSE; /* TRUE - disallow remote commands            */
  91.  
  92. static int tryzhdrtype = ZRINIT; /* Header type to send corresponding to Last
  93.                                     rx close                                */
  94.  
  95.  
  96. /****************************************************************************
  97. *    Local prototypes.                                                        *
  98. ****************************************************************************/
  99.  
  100. #if    0
  101. static void bibi (int n);
  102. #endif
  103. static void chkinvok (char protocol);
  104. static void purgeline (void);
  105. static void uncaps (char *s);
  106. static int IsAnyLower (char *s);
  107. static void canit (void);
  108. static void report (int sct);
  109. static void checkpath (char *name);
  110. static int tryz (void);
  111. static int rzfiles (void);
  112. static int rzfile (void);
  113. static void zmputs (char *s);
  114. static int closeit (void);
  115. static void ackbibi (void);
  116. static int sys2 (char *s);
  117. static void exec2 (char *s);
  118. static long getfree (void);
  119. static int wcreceive (int argc, char **argp);
  120. static int wcrxpn (char *rpn);
  121. static int wcrx (void);
  122. static int wcgetsec (char *rxbuf, int maxtime);
  123. static int procheader (char *name);
  124. static int putsec (char *buf, int n);
  125.  
  126.                                
  127. /****************************************************************************
  128. *    getfree                                                                    *
  129. *    Routine to calculate the free bytes on the current file system.            *
  130. *    ~0 means many free bytes (unknown).                                        *
  131. ****************************************************************************/
  132.  
  133. static long getfree (void)
  134.     {
  135.     return (~0L);    /* many free bytes ... */
  136.     }    /* static long getfree (void) */
  137.  
  138.  
  139. #if    0
  140. /****************************************************************************
  141. *    bibi                                                                    *
  142. *    Called by signal interrupt or terminate to clean things up.                *
  143. ****************************************************************************/
  144. static void bibi (int n)
  145.     {
  146.     n = n;
  147.     if (_Zmodem)
  148.         {
  149. #ifdef    DEBUGZ
  150.         _tout ("\r\n\nbibi: calling zmputs (_Attn)\r\n");
  151. #endif
  152.         zmputs (_Attn);
  153.         }
  154.     
  155.     canit ();
  156.     _zperr_ ("Interrupted\n");
  157.     closeit ();
  158. #ifdef    DEBUGZ
  159.     _tout ("bibi: doing longjmp (_tohere, -1)\r\n");
  160. #endif
  161.     longjmp (_tohere, -1);
  162.     }    /* static void bibi (int n) */
  163. #endif
  164.  
  165.  
  166. /****************************************************************************
  167. *    _getfile                                                                *
  168. *    Receives file(s).  Returns 0 if successful.                                *
  169. ****************************************************************************/
  170.  
  171. int _getfile (int s, char protocol, char *options, char *filename,
  172.               void (*reporter) (int type, void *data))
  173.     {
  174.     char *cp;
  175.     int npats;
  176.     char **patts;
  177.     int exitcode = 0;
  178. #if    0
  179.     void (*sigint_sav) (int);
  180.     void (*sigterm_sav) (int);
  181. #endif
  182.  
  183.     /* Initialise global variables. */
  184.  
  185.     _z_socket = s;
  186.     Batch = 0;
  187.     _do_report = _zperr;
  188.     Filcnt = 0;
  189.     Lleft = 0;
  190.     MakeLCPathname = TRUE;
  191.     Nflag = 0;
  192.     nocommand = FALSE;
  193.     _Nozmodem = 0;
  194.     _Quiet = 0;
  195.     Readnum = HOWMANY;
  196.     Rxascii = FALSE;
  197.     Rxbinary = FALSE;
  198.     _Rxtimeout = 100;
  199.     _sending = FALSE;
  200.     tryzhdrtype = ZRINIT;
  201.     _Verbose = 0;
  202.     _Wcsmask = 0377;
  203.     _Zmodem = 0;
  204.     _Zrwindow = 1400;
  205.  
  206.     chkinvok (protocol);                    /* choose protocol                */
  207.     npats = 0;
  208.  
  209.     /* Parse options. */
  210.  
  211.     cp = options;
  212.     while (*cp != '\0')
  213.         {
  214.         switch (*cp++)
  215.             {
  216.             case '7':                        /* strip top bit                */
  217.                 _Wcsmask = 0177;
  218.  
  219.             case 'a':                        /* ASCII transfer                */
  220.                 Rxascii = TRUE;
  221.                 break;
  222.  
  223.             case 'b':                        /* binary transfer                */
  224.                 Rxbinary = TRUE;
  225.                 break;
  226.  
  227.             case 'c':                        /* XMODEM/CRC                    */
  228.                 _Crcflg = TRUE;
  229.                 break;
  230.  
  231.             case 'D':                        /* fake file transfer            */
  232.                 Nflag = TRUE;
  233.                 break;
  234.  
  235.             case 'i':                        /* disallow remote command        */
  236.                 nocommand = TRUE;
  237.                 break;
  238.                 
  239.             case 'e':                        /* escape ctl chars                */
  240.                 _Zctlesc = 1;
  241.                 break;
  242.  
  243.             case 'p':                        /* 'protect' option                */
  244.                 _Lzmanag = ZMPROT;
  245.                 break;
  246.  
  247.             case 'q':                        /* quiet                        */
  248.                 _Quiet = TRUE;
  249.                 _Verbose = 0;
  250.                 break;
  251.  
  252.             case 't':                        /* change timeout                */
  253.                 sscanf (cp, "%d", &_Rxtimeout);
  254.                 if (_Rxtimeout < 10 || _Rxtimeout > 1000)
  255.                     return (ERROR);
  256.  
  257.                 cp = _stbnb (cp);
  258.                 break;
  259.  
  260.             case 'w':                        /* window size                    */
  261.                 sscanf (cp, "%d", &_Zrwindow);
  262.                 cp = _stbnb (cp);
  263.                 break;
  264.  
  265.             case 'u':                        /* no lower case convert        */
  266.                 MakeLCPathname = FALSE;
  267.                 break;
  268.                 
  269.             case 'v':                        /* debug info                    */
  270.                 ++_Verbose;
  271.                 break;
  272.  
  273.             default:
  274.                 return (ERROR);
  275.             }    /* switch (*cp++) */
  276.             
  277.         }    /* while (*cp != '\0') */
  278.  
  279.     /* Get filename. */
  280.     
  281.     if (filename != NULL)
  282.         {
  283.         npats = 1;
  284.         patts = &filename;
  285.         }
  286.  
  287.     if (npats > 1)
  288.         return (ERROR);
  289.         
  290.     if (Batch && npats)
  291.         return (ERROR);
  292.  
  293.     /* Get reporter function */
  294.  
  295.     if (reporter != NULL)
  296.         _do_report = reporter;                /* user supplied fn                */
  297.  
  298. #if    0
  299.     if (_Verbose)
  300.         {
  301.         if ((_zperr_handle = open (LOGFILE,
  302.                                    O_CREAT | O_APPEND | O_WRONLY | O_TEXT,
  303.                                    S_IFREG | S_IWRITE)) == -1)
  304.             {
  305.             char buff[80];
  306.             
  307.             sprintf (buff, "Can't open log file %s: %s\n",
  308.                      LOGFILE, strerror (errno));
  309.             (*_do_report) (2, buff);
  310.             (*_do_report) (3, &Filcnt);        /* report no of files            */
  311.             return (ERROR);
  312.             }
  313.             
  314.         _do_report = _zperr;                /* use default reporter            */
  315.         }
  316. #endif
  317.  
  318.     if (!_Quiet)
  319.         {
  320.         if (_Verbose == 0)
  321.             _Verbose = 2;
  322.  
  323.         }
  324.  
  325. #if    0
  326.     if ((sigint_sav = signal (SIGINT, bibi)) == SIG_IGN)
  327.         signal (SIGINT, SIG_IGN);
  328.     else
  329.         signal (SIGINT, bibi);
  330.  
  331. #endif
  332.  
  333. #if    0
  334.     sigint_sav = signal (SIGINT, bibi);
  335.     sigterm_sav = signal (SIGTERM, bibi);
  336. #endif
  337.         
  338.     /* Set up escape routes. */
  339.  
  340.     if (setjmp (_tohere) != 0)
  341.         {
  342. #ifdef    DEBUGZ
  343.         _tout ("getfile: exiting via _tohere jump\r\n");
  344. #endif
  345.         (*_do_report) (3, &Filcnt);            /* report files transferred        */
  346. #if    0
  347.         signal (SIGINT, sigint_sav);
  348.         signal (SIGTERM, sigterm_sav);
  349.         (void) close (_zperr_handle);
  350. #endif
  351.         return (-2);                        /* user abort                    */
  352.         }
  353.  
  354.     if (setjmp (_nocarrier) != 0)
  355.         {
  356. #ifdef    DEBUGZ
  357.         _tout ("getfile: exiting via _nocarrier jump\r\n");
  358. #endif
  359.         (*_do_report) (3, &Filcnt);            /* report files transferred        */
  360. #if    0
  361.         signal (SIGINT, sigint_sav);
  362.         signal (SIGTERM, sigterm_sav);
  363.         (void) close (_zperr_handle);
  364. #endif
  365.         return (-3);                        /* lost carrier                    */
  366.         }
  367.  
  368.     /* Get the file(s). */
  369.     
  370.     if (wcreceive (npats, patts) == ERROR)
  371.         {
  372.         exitcode = 0200;
  373.         canit ();
  374.         }
  375.         
  376.     if (exitcode && !_Zmodem)            /* Bellow again with all thy might. */
  377.         canit ();
  378.         
  379.     if (!_Quiet)
  380.         _say ("\n");
  381.  
  382.     (*_do_report) (3, &Filcnt);            /* report files transferred            */
  383. #if    0
  384.     signal (SIGINT, sigint_sav);
  385.     signal (SIGTERM, sigterm_sav);
  386.     (void) close (_zperr_handle);
  387. #endif
  388.     return (exitcode);
  389.     }    /* int _getfile (int s, char protocol, char *options, char *filename,
  390.              void (*reporter) (int type, void *data)) */
  391.              
  392.  
  393. /****************************************************************************
  394. *    wcreceive                                                                *
  395. *    Let's receive something already.                                        *
  396. ****************************************************************************/
  397.  
  398. #if 0
  399. static char *rbmsg = "Ready to receive.\n"
  400.                      "To begin transfer, issue the send command "
  401.                      "to your modem program\r\n";
  402. #endif
  403.  
  404. static int wcreceive (int argc, char **argp)
  405.     {
  406.     int c;
  407.  
  408.     if (Batch || argc == 0)
  409.         {
  410.         /* ZMODEM / YMODEM BATCH */
  411.         
  412.         _Crcflg = (_Wcsmask == 0377);
  413. #if 0
  414.         if (!_Quiet)
  415.             _say (rbmsg);
  416.  
  417. #endif
  418.         
  419.         if ((c = tryz ()) != 0)
  420.             {
  421.             if (c == ZCOMPL)
  422.                 return OK;
  423.                 
  424.             if (c == ERROR)
  425.                 goto fubar;
  426.                 
  427.             c = rzfiles ();
  428.             if (c)
  429.                 goto fubar;
  430.                 
  431.             }    /* if ((c = tryz ()) != 0) */
  432.         else
  433.             {
  434.             for (;;)
  435.                 {
  436.                 if (wcrxpn (secbuf) == ERROR)
  437.                     goto fubar;
  438.                     
  439.                 if (secbuf[0] == 0)
  440.                     return OK;
  441.                     
  442.                 if (procheader (secbuf) == ERROR)
  443.                     goto fubar;
  444.                     
  445.                 if (wcrx () == ERROR)
  446.                     goto fubar;
  447.                     
  448.                 }    /* for (;;) */
  449.                 
  450.             }    /* else */
  451.             
  452.         }    /* if (Batch || argc == 0) */
  453.     else
  454.         {
  455.         /* XMODEM */
  456.         
  457.         Bytesleft = DEFBYTL;
  458.         Filemode = 0;
  459.         Modtime = 0L;
  460.  
  461.         procheader ("");
  462.         strcpy (Pathname, *argp);
  463.         checkpath (Pathname);
  464.         (*_do_report) (0, Pathname);
  465.         _say ("\nReady to receive %s\r\n", Pathname);
  466.         if ((fout = open (Pathname,
  467.                           O_CREAT | O_TRUNC | O_WRONLY | O_BINARY,
  468.                           S_IFREG | S_IWRITE)) == -1)
  469.             return ERROR;
  470.             
  471.         if (wcrx () == ERROR)
  472.             goto fubar;
  473.  
  474.         ++Filcnt;
  475.         }    /* else */
  476.         
  477.     return OK;
  478.  
  479.     /* Transfer failed - clean up. */
  480.     
  481. fubar:
  482.     canit ();
  483.     if (fout != -1)
  484.         close (fout);
  485.  
  486.     return ERROR;
  487.     }    /* static int wcreceive (int argc, char **argp) */
  488.     
  489.  
  490. /****************************************************************************
  491. *    wcrxpn                                                                    *
  492. *    Fetch a pathname from the other end as a C ctyle ASCIZ string.  Length    *
  493. *    is indeterminate as long as less than rz_blklen.  A null string         *
  494. *    represents no more files (YMODEM).                                        *
  495. ****************************************************************************/
  496.  
  497. static int wcrxpn (char *rpn)
  498.     {
  499.     int c;
  500.  
  501.     purgeline ();
  502.  
  503. et_tu:
  504.     _firstsec = TRUE;
  505.     Eofseen = FALSE;
  506.     _sendline (_Crcflg ? WANTCRC : NAK);
  507.     Lleft = 0;                            /* Do read next time ...             */
  508.     while ((c = wcgetsec (rpn, 100)) != 0)
  509.         {
  510.         if (c == WCEOT)
  511.             {
  512.             _zperr_ ("Pathname fetch returned %d", c);
  513.             _sendline (ACK);
  514.             Lleft = 0;                    /* Do read next time ...             */
  515.             _readline (1);
  516.             goto et_tu;
  517.             }
  518.  
  519.         return ERROR;
  520.         }    /* while ((c = wcgetsec (rpn, 100)) != 0) */
  521.         
  522.     _sendline (ACK);
  523.     return OK;
  524.     }    /* static int wcrxpn (char *rpn) */
  525.  
  526.  
  527. /****************************************************************************
  528. *    wcrx                                                                    *
  529. *    Adapted from CMODEM13.C, written by Jack M Wierda and Roderick W Hart.    *
  530. ****************************************************************************/
  531.  
  532. static int wcrx (void)
  533.     {
  534.     int sectnum, sectcurr;
  535.     char sendchar;
  536.     int cblklen;                        /* bytes to dump this block            */
  537.  
  538.     _firstsec = TRUE;
  539.     sectnum = 0;
  540.     Eofseen = FALSE;
  541.     sendchar = (char) (_Crcflg ? WANTCRC : NAK);
  542.  
  543.     for (;;)
  544.         {
  545.         _sendline (sendchar);            /* send it now, we're ready!        */
  546.         Lleft = 0;                        /* Do read next time ...            */
  547.         sectcurr = wcgetsec (secbuf, (sectnum & 0177) ? 50 : 130);
  548.         report (sectcurr);
  549.         if (sectcurr == (sectnum + 1 & _Wcsmask))
  550.             {
  551.             sectnum++;
  552.             cblklen = Bytesleft > rz_blklen ? rz_blklen : (int) Bytesleft;
  553.             if (putsec (secbuf, cblklen) == ERROR)
  554.                 return ERROR;
  555.  
  556.             if ((Bytesleft -= cblklen) < 0)
  557.                 Bytesleft = 0;
  558.  
  559.             sendchar = ACK;
  560.             }
  561.         else if (sectcurr == (sectnum & _Wcsmask))
  562.             {
  563.             _zperr_ ("Received dup Sector");
  564.             sendchar = ACK;
  565.             }
  566.         else if (sectcurr == WCEOT)
  567.             {
  568.             if (closeit ())
  569.                 return ERROR;
  570.  
  571.             _sendline (ACK);
  572.             Lleft = 0;                    /* Do read next time ...            */
  573.             return OK;
  574.             }
  575.         else if (sectcurr == ERROR)
  576.             return ERROR;
  577.         else
  578.             {
  579.             _zperr_ ("Sync Error");
  580.             return ERROR;
  581.             }
  582.  
  583.         }    /* for (;;) */
  584.         
  585.     }    /* static int wcrx (void) */
  586.     
  587.  
  588. /****************************************************************************
  589. *    wcgetsec                                                                *
  590. *    Fetches a Ward Christensen type sector.  Returns sector number             *
  591. *    encountered or ERROR if valid sector not received, or CAN CAN received    *
  592. *    or WCEOT if eot sector.  <maxtime> is timeout for first char, set to 4    *
  593. *    seconds thereafter.  NO ACK IS SENT IF SECTOR IS RECEIVED OK (Caller    *
  594. *    must do that when he is good and ready to get next sector).                *
  595. ****************************************************************************/
  596.  
  597. static int wcgetsec (char *rxbuf, int maxtime)
  598.     {
  599.     int checksum, wcj, firstch;
  600.     unsigned short oldcrc;
  601.     char *p;
  602.     int sectcurr;
  603.  
  604.     for (_Lastrx = _errors = 0; _errors < RETRYMAX; _errors++)
  605.         {
  606.         if ((firstch = _readline (maxtime)) == STX)
  607.             {
  608.             rz_blklen = KSIZE;
  609.             goto get2;
  610.             }
  611.  
  612.         if (firstch == SOH)
  613.             {
  614.             rz_blklen = SECSIZ;
  615.  
  616. get2:
  617.             sectcurr = _readline (1);
  618.             if ((sectcurr + (oldcrc = _readline (1))) == _Wcsmask)
  619.                 {
  620.                 oldcrc = checksum = 0;
  621.                 for (p = rxbuf, wcj = rz_blklen; --wcj >= 0;)
  622.                     {
  623.                     if ((firstch = _readline (1)) < 0)
  624.                         goto bilge;
  625.                         
  626.                     oldcrc = updcrc (firstch, oldcrc);
  627.                     checksum += (*p++ = (char) firstch);
  628.                     }
  629.                     
  630.                 if ((firstch = _readline (1)) < 0)
  631.                     goto bilge;
  632.                     
  633.                 if (_Crcflg)
  634.                     {
  635.                     oldcrc = updcrc (firstch, oldcrc);
  636.                     if ((firstch = _readline (1)) < 0)
  637.                         goto bilge;
  638.                         
  639.                     oldcrc = updcrc (firstch, oldcrc);
  640.                     if (oldcrc & 0xFFFF)
  641.                         _zperr_ ( "CRC");
  642.                     else
  643.                         {
  644.                         _firstsec = FALSE;
  645.                         return sectcurr;
  646.                         }
  647.  
  648.                     }    /* if (_Crcflg) */
  649.                 else if (((checksum - firstch) & _Wcsmask) == 0)
  650.                     {
  651.                     _firstsec = FALSE;
  652.                     return sectcurr;
  653.                     }
  654.                 else
  655.                     _zperr_ ( "Checksum");
  656.  
  657.                 }    /* if ((sectcurr + (oldcrc = _readline (1))) == _Wcsmask) */
  658.             else
  659.                 _zperr_ ("Sector number garbled");
  660.  
  661.             }    /* if (firstch == SOH) */
  662.         else if (firstch == EOT && Lleft == 0)    /* make sure eot really is
  663.                                                    eot and not just mixmash    */
  664.             return WCEOT;
  665.         else if (firstch == CAN)
  666.             {
  667.             if (_Lastrx == CAN)
  668.                 {
  669.                 _zperr_ ("Sender CANcelled");
  670.                 return ERROR;
  671.                 }
  672.             else
  673.                 {
  674.                 _Lastrx = CAN;
  675.                 continue;
  676.                 }
  677.  
  678.             }    /* else if (firstch == CAN) */
  679.         else if (firstch == ZTIMEOUT)
  680.             {
  681.             if (_firstsec)
  682.                 goto humbug;
  683.  
  684. bilge:
  685.             _zperr_ ( "TIMEOUT");
  686.             }
  687.         else
  688.             _zperr_ ( "Got 0%o sector header", firstch);
  689.  
  690. humbug:
  691.         _Lastrx = 0;
  692.         while (_readline (1) != ZTIMEOUT)
  693.             ;
  694.  
  695.         if (_firstsec)
  696.             {
  697.             _sendline (_Crcflg ? WANTCRC : NAK);
  698.             Lleft = 0;                    /* Do read next time ...            */
  699.             }
  700.         else
  701.             {
  702.             maxtime = 40;
  703.             _sendline (NAK);
  704.             Lleft = 0;                    /* Do read next time ...            */
  705.             }
  706.  
  707.         }    /* for (_Lastrx = _errors = 0; _errors < RETRYMAX; _errors++) */
  708.         
  709.     /* try to stop the bubble machine. */
  710.     
  711.     canit ();
  712.     return ERROR;
  713.     }    /* static int wcgetsec (char *rxbuf, int maxtime) */
  714.     
  715.  
  716. /****************************************************************************
  717. *    _readline                                                                *
  718. *    This version of _readline is reasonably well suited for reading many     *
  719. *    characters (except, currently, for the Regulus version!).  Timeout is    *
  720. *    in tenths of seconds.                                                    *
  721. ****************************************************************************/
  722.  
  723. int _readline (int timeout)
  724.     {
  725.     int n;
  726.     static char *cdq;            /* pointer for removing chars from linbuf    */
  727.     time_t start;                        /* start for timeout                */
  728.  
  729.     if (linbuf == 0)
  730.         linbuf = mallocw (HOWMANY);
  731.         
  732.     if (--Lleft >= 0)
  733.         {
  734.         if (_Verbose > 8)
  735.             {
  736.             _say ("%02x ", *cdq & 0377);
  737.             }
  738.  
  739.         return (*cdq++ & _Wcsmask);
  740.         }
  741.  
  742.     n = timeout / 10;
  743.     if (n < 2)
  744.         n = 3;        
  745.  
  746.     time (&start);
  747.     if (_Verbose > 5)
  748.         _vfile ("Calling read: alarm=%d  Readnum=%d ", n, Readnum);
  749.         
  750.     _no_carrier ();
  751.     while (1)
  752.         {
  753.         Lleft = _receive ((unsigned char *) (cdq = linbuf), Readnum);
  754.         if (Lleft != 0)
  755.             break;                        /* got something                    */
  756.  
  757.         if (time (NULL) >= start + n)
  758.             {
  759.             _zperr_ ("ZTIMEOUT");
  760.             return (ZTIMEOUT);
  761.             }
  762.  
  763.         }
  764.         
  765.     if (_Verbose > 5)
  766.         {
  767.         _say ("Read returned %d bytes\n", Lleft);
  768.         }
  769.  
  770.     if (Lleft < 1)
  771.         return ZTIMEOUT;
  772.  
  773.     --Lleft;
  774.     if (_Verbose > 8)
  775.         {
  776.         _say ("%02x ", *cdq & 0377);
  777.         }
  778.  
  779.     return (*cdq++ & _Wcsmask);
  780.     }    /* int _readline (int timeout) */
  781.  
  782.  
  783. /****************************************************************************
  784. *    purgeline                                                                *
  785. *    Purge the modem input queue of all characters.                            *
  786. ****************************************************************************/
  787.  
  788. static void purgeline (void)
  789.     {
  790.     unsigned char c;
  791.     
  792.     Lleft = 0;
  793.     while (_rdchk () > 0)
  794.         _receive (&c, 1);
  795.         
  796.     }    /* static void purgeline (void) */
  797.  
  798.  
  799. /****************************************************************************
  800. *    procheader                                                                *
  801. *    Process incoming file information header.                                *
  802. ****************************************************************************/
  803.  
  804. static int procheader (char *name)
  805.     {
  806.     int openmode;
  807.     char *p;
  808.  
  809.     /* set default parameters and overrides */
  810.  
  811.     (*_do_report) (0, name);
  812.     openmode = O_CREAT | O_TRUNC | O_WRONLY | O_BINARY;
  813.     Thisbinary = (!Rxascii) || Rxbinary;
  814.     if (_Lzmanag)
  815.         _zmanag = _Lzmanag;
  816.  
  817.     /* Process ZMODEM remote file management requests. */
  818.     
  819.     if (!Rxbinary && _zconv == ZCNL)    /* Remote ASCII override             */
  820.         Thisbinary = 0;
  821.         
  822.     if (_zconv == ZCBIN)                /* Remote Binary override             */
  823.         Thisbinary = TRUE;
  824.     else if (_zmanag == ZMAPND)
  825.         openmode = O_APPEND | O_WRONLY | O_BINARY;
  826.  
  827.     /* ZMPROT check for existing file */
  828.     
  829.     if (_zmanag == ZMPROT && (fout = open (name, O_RDONLY)) != -1)
  830.         {
  831.         close (fout);
  832.         return ERROR;
  833.         }
  834.  
  835.     Bytesleft = DEFBYTL;
  836.     Filemode = 0;
  837.     Modtime = 0L;
  838.  
  839.     p = name + 1 + strlen (name);
  840.     if (*p)
  841.         {
  842.         /* file coming from Unix or DOS system */
  843.  
  844.         sscanf (p, "%ld%lo%o", &Bytesleft, &Modtime, &Filemode);
  845.         if (Filemode & UNIXFILE)
  846.             ++Thisbinary;
  847.  
  848.         if (_Verbose)
  849.             {
  850.             _say ("Incoming: %s %ld %lo %o\n",
  851.                   name, Bytesleft, Modtime, Filemode);
  852.             }
  853.             
  854.         }    /* if (*p) */
  855.     else
  856.         {
  857.         /* File coming from CP/M system */
  858.         
  859.         for (p = name; *p; ++p)            /* change / to _                     */
  860.             if ( *p == '/')
  861.                 *p = '_';
  862.                 
  863.         if ( *--p == '.')                /* zap trailing period                 */
  864.             *p = 0;
  865.             
  866.         }    /* else */
  867.  
  868.     if (!_Zmodem && MakeLCPathname && !IsAnyLower (name))
  869.         uncaps (name);
  870.         
  871.     strcpy (Pathname, name);
  872.     if (_Verbose)
  873.         {
  874.         _say ("Receiving %s %s\n",
  875.               name, Thisbinary ? "BIN" : "ASCII");
  876.         }
  877.         
  878.     checkpath (name);
  879.     if (Nflag)
  880.         name = "nul";                    /* send to bit bucket                */
  881.  
  882.     if ((fout = open (name, openmode, S_IFREG | S_IWRITE)) == -1)
  883.         {
  884.         _vfile ("Can't open %s mode %x, %s\n",
  885.                 name, openmode, strerror (errno));
  886.         return ERROR;
  887.         }
  888.         
  889.     return OK;
  890.     }    /* static int procheader (char *name) */
  891.     
  892.  
  893. /****************************************************************************
  894. *    putsec                                                                    *
  895. *    Writes the <n> characters of <buf> to receive file fout.  If not in     *
  896. *    binary mode, carriage returns, and all characters starting with CPMEOF     *
  897. *    are discarded.                                                            *
  898. ****************************************************************************/
  899.  
  900. static int putsec (char *buf, int n)
  901.     {
  902.     char *p, *q;
  903.     char locbuf[KSIZE + 1];
  904.     int qcount;                            /* no of chars in local buffer        */
  905.     
  906.     if (Thisbinary)
  907.         {
  908.         write (fout, buf, n);
  909. #if    0
  910.         for (p = buf; --n >= 0;)
  911.             putc (*p++, fout);
  912.  
  913. #endif        
  914.         }
  915.     else
  916.         {
  917.         if (Eofseen)
  918.             return OK;
  919.  
  920.         q = locbuf;
  921.         qcount = 0;
  922.         for (p = buf; --n >= 0; ++p)
  923.             {
  924. #if    0
  925.             /* We'll keep CR under MesS-DOS. */
  926.             
  927.             if (*p == '\r')
  928.                 continue;
  929.  
  930. #endif
  931.             if (*p == CPMEOF)
  932.                 {
  933.                 Eofseen = TRUE;
  934.                 return OK;
  935.                 }
  936.  
  937.             *q++ = *p;                    /* put byte in write buffer            */
  938.             qcount++;
  939. #if    0
  940.             putc (*p ,fout);
  941. #endif
  942.             }    /* for (p = buf; --n >= 0; ++p) */
  943.  
  944.         if (qcount != 0)
  945.             write (fout, locbuf, qcount);
  946.             
  947.         }    /* else */
  948.         
  949.     return OK;
  950.     }    /* static int putsec (char *buf, int n) */
  951.     
  952.  
  953. /****************************************************************************
  954. *    uncaps                                                                    *
  955. *    Make string <s> lower case.                                                *
  956. ****************************************************************************/
  957.  
  958. static void uncaps (char *s)
  959.     {
  960.     for (; *s; ++s)
  961.         if (isupper (*s))
  962.             *s = tolower (*s);
  963.             
  964.     }    /* static void uncaps (char *s) */
  965.  
  966.  
  967. /****************************************************************************
  968. *    IsAnyLower                                                                *
  969. *    IsAnyLower returns TRUE if string s has lower case letters.                *
  970. ****************************************************************************/
  971.  
  972. static int IsAnyLower (char *s)
  973.     {
  974.     for (; *s; ++s)
  975.         if (islower (*s))
  976.             return TRUE;
  977.             
  978.     return FALSE;
  979.     }    /* static int IsAnyLower (char *s) */
  980.  
  981.  
  982. /****************************************************************************
  983. *    canit                                                                    *
  984. *    Send cancel string to get the other end to shut up.                        *
  985. ****************************************************************************/
  986.  
  987. static void canit (void)
  988.     {
  989. #ifdef    DEBUGZ
  990.     _tout ("canit: calling _canit ()\r\n");
  991. #endif
  992.     _canit ();
  993.     Lleft = 0;                            /* Do read next time ...             */
  994. #ifdef    DEBUGZ
  995.     _tout ("leaving canit ()\r\n");
  996. #endif
  997.     }    /* static void canit (void) */
  998.  
  999.  
  1000. /****************************************************************************
  1001. *    report                                                                    *
  1002. *    Print <sct>.                                                            *
  1003. ****************************************************************************/
  1004.  
  1005. static void report (int sct)
  1006.     {
  1007.     if (_Verbose > 1)
  1008.         _say ("%03d%c", sct, sct % 10 ? ' ' : '\r');
  1009.         
  1010.     }    /* static void report (int sct) */
  1011.  
  1012.  
  1013. /****************************************************************************
  1014. *    chkinvok                                                                *
  1015. *    Set chosen protocol.                                                    *
  1016. ****************************************************************************/
  1017.  
  1018. static void chkinvok (char protocol)
  1019.     {
  1020.     if (protocol == 'z')
  1021.         Batch = TRUE;
  1022.         
  1023.     if (protocol == 'y')
  1024.         Batch = _Nozmodem = TRUE;
  1025.         
  1026.     }    /* static void chkinvok (char protocol) */
  1027.     
  1028.  
  1029. /****************************************************************************
  1030. *    checkpath                                                                *
  1031. *    Totalitarian Communist pathname processing.                                *
  1032. ****************************************************************************/
  1033.  
  1034. static void checkpath (char *name)
  1035.     {
  1036.     /* No restrictions in this version. */
  1037.  
  1038.     name = name;                        /* silence compiler                    */
  1039.     }    /* static void checkpath (char *name) */
  1040.  
  1041.  
  1042. /****************************************************************************
  1043. *    tryz                                                                    *
  1044. *    Initialize for Zmodem receive attempt, try to activate Zmodem sender.    *
  1045. *    Handles ZSINIT frame.  Return ZFILE if Zmodem filename received, -1 on    *
  1046. *    error, ZCOMPL if transaction finished, else 0.                            *
  1047. ****************************************************************************/
  1048.  
  1049. static int tryz (void)
  1050.     {
  1051.     int c, n;
  1052.     int cmdzack1flg;
  1053.  
  1054.     if (_Nozmodem)                        /* Check for "rb" program name         */
  1055.         return 0;
  1056.         
  1057.     for (n = _Zmodem ? 15 : 5; --n >= 0;)
  1058.         {
  1059.         /* Set buffer length (0) and capability flags. */
  1060.         
  1061.         _stohdr (0L);
  1062. #ifdef CANBREAK
  1063.         _Txhdr[ZF0] = CANFC32 | CANFDX | CANOVIO | CANBRK;
  1064. #else
  1065.         _Txhdr[ZF0] = CANFC32 | CANFDX | CANOVIO;
  1066. #endif
  1067.         if (_Zctlesc)
  1068.             _Txhdr[ZF0] |= TESCCTL;
  1069.             
  1070.         _zshhdr (tryzhdrtype, _Txhdr);
  1071.         if (tryzhdrtype == ZSKIP)        /* Don't skip too far                 */
  1072.             tryzhdrtype = ZRINIT;        /* CAF 8-21-87                         */
  1073.             
  1074. again:
  1075.         switch (_zgethdr (_Rxhdr, 0))
  1076.             {
  1077.             case ZRQINIT:
  1078.                 continue;
  1079.  
  1080.             case ZEOF:
  1081.                 continue;
  1082.  
  1083.             case ZTIMEOUT:
  1084.                 continue;
  1085.  
  1086.             case ZFILE:
  1087.                 _zconv = _Rxhdr[ZF0];
  1088.                 _zmanag = _Rxhdr[ZF1];
  1089.                 _ztrans = _Rxhdr[ZF2];
  1090.                 tryzhdrtype = ZRINIT;
  1091.                 c = _zrdata (secbuf, KSIZE);
  1092.                 if (c == GOTCRCW)
  1093.                     return ZFILE;
  1094.  
  1095.                 _zshhdr (ZNAK, _Txhdr);
  1096.                 goto again;
  1097.  
  1098.             case ZSINIT:
  1099.                 _Zctlesc = TESCCTL & _Rxhdr[ZF0];
  1100.                 if (_zrdata (_Attn, ZATTNLEN) == GOTCRCW)
  1101.                     {
  1102.                     _zshhdr (ZACK, _Txhdr);
  1103.                     goto again;
  1104.                     }
  1105.  
  1106.                 _zshhdr (ZNAK, _Txhdr);
  1107.                 goto again;
  1108.  
  1109.             case ZFREECNT:
  1110.                 _stohdr (getfree ());
  1111.                 _zshhdr (ZACK, _Txhdr);
  1112.                 goto again;
  1113.  
  1114.             case ZCOMMAND:
  1115.                 cmdzack1flg = _Rxhdr[ZF0];
  1116.                 if (_zrdata (secbuf, KSIZE) == GOTCRCW)
  1117.                     {
  1118.                     if (cmdzack1flg & ZCACK1)
  1119.                         _stohdr (0L);
  1120.                     else
  1121.                         {
  1122.                         if (nocommand)
  1123.                             _stohdr (0L);    /* fake command ok                */
  1124.                         else
  1125.                             _stohdr ((long) sys2 (secbuf));
  1126.  
  1127.                         }
  1128.  
  1129.                     purgeline ();        /* dump impatient questions         */
  1130.                     do
  1131.                         {
  1132.                         _zshhdr (ZCOMPL, _Txhdr);
  1133.                         } while (++_errors < 20 && _zgethdr (_Rxhdr,1) != ZFIN);
  1134.                         
  1135.                     ackbibi ();
  1136.                     if (cmdzack1flg & ZCACK1)
  1137.                         if (nocommand)
  1138.                             longjmp (_tohere, -1);    /* don't do it            */
  1139.                         else
  1140.                             exec2 (secbuf);
  1141.  
  1142.                     return ZCOMPL;
  1143.                     }    /* if (_zrdata (secbuf, KSIZE) == GOTCRCW) */
  1144.                     
  1145.                 _zshhdr (ZNAK, _Txhdr);
  1146.                 goto again;
  1147.                 
  1148.             case ZCOMPL:
  1149.                 goto again;
  1150.  
  1151.             default:
  1152.                 continue;
  1153.  
  1154.             case ZFIN:
  1155.                 ackbibi ();
  1156.                 return ZCOMPL;
  1157.  
  1158.             case ZCAN:
  1159.                 return ERROR;
  1160.             }    /* switch (_zgethdr (_Rxhdr, 0)) */
  1161.             
  1162.         }    /* for (n = _Zmodem ? 15 : 5; --n >= 0;) */
  1163.         
  1164.     return 0;
  1165.     }    /* static int tryz (void) */
  1166.     
  1167.  
  1168. /****************************************************************************
  1169. *    rzfiles                                                                    *
  1170. *    Receive one or more files with the ZMODEM protocol.                        *
  1171. ****************************************************************************/
  1172.  
  1173. static int rzfiles (void)
  1174.     {
  1175.     int c;
  1176.  
  1177.     for (;;)
  1178.         {
  1179.         switch (c = rzfile ())
  1180.             {
  1181.             case ZEOF:
  1182.             case ZSKIP:
  1183.                 switch (tryz ())
  1184.                     {
  1185.                     case ZCOMPL:
  1186.                         return OK;
  1187.                         
  1188.                     default:
  1189.                         return ERROR;
  1190.  
  1191.                     case ZFILE:
  1192.                         break;
  1193.                     }
  1194.     
  1195.                 continue;
  1196.  
  1197.             default:
  1198.                 return c;
  1199.  
  1200.             case ERROR:
  1201.                 return ERROR;
  1202.             }    /* switch (c = rzfile ()) */
  1203.             
  1204.         }    /* for (;;) */
  1205.         
  1206.     }    /* static int rzfiles (void) */
  1207.     
  1208.  
  1209. /****************************************************************************
  1210. *    rzfile                                                                    *
  1211. *    Receive a file with ZMODEM protocol.  Assumes file name frame is in     *
  1212. *    secbuf.                                                                    *
  1213. ****************************************************************************/
  1214.  
  1215. static int rzfile (void)
  1216.     {
  1217.     int c, n;
  1218.     long rxbytes;
  1219.     int sent_zm = FALSE;                /* TRUE - sent ZMODEM string        */
  1220.     Eofseen = FALSE;
  1221.     if (procheader (secbuf) == ERROR)
  1222.         {
  1223.         return (tryzhdrtype = ZSKIP);
  1224.         }
  1225.         
  1226.     n = 20;
  1227.     rxbytes = 0l;
  1228.  
  1229.     for (;;)
  1230.         {
  1231.         _stohdr (rxbytes);
  1232.         _zshhdr (ZRPOS, _Txhdr);
  1233.  
  1234. nxthdr:
  1235.         switch (c = _zgethdr (_Rxhdr, 0))
  1236.             {
  1237.             default:
  1238.                 _vfile ("rzfile: _zgethdr returned %d", c);
  1239.                 return ERROR;
  1240.  
  1241.             case ZNAK:
  1242.             case ZTIMEOUT:
  1243.                 if ( --n < 0)
  1244.                     {
  1245.                     _vfile ("rzfile: _zgethdr returned %d", c);
  1246.                     return ERROR;
  1247.                     }
  1248.  
  1249.             case ZFILE:
  1250.                 _zrdata (secbuf, KSIZE);
  1251.                 continue;
  1252.  
  1253.             case ZEOF:
  1254.                 if (_rclhdr (_Rxhdr) != rxbytes)
  1255.                     {
  1256.                     /*
  1257.                      * Ignore eof if it's at wrong place - force
  1258.                      *  a timeout because the eof might have gone
  1259.                      *  out before we sent our zrpos.
  1260.                      */
  1261.  
  1262.                     _errors = 0;
  1263.                     goto nxthdr;
  1264.                     }
  1265.                     
  1266.                 if (closeit ())
  1267.                     {
  1268.                     tryzhdrtype = ZFERR;
  1269.                     _vfile ("rzfile: closeit returned <> 0");
  1270.                     return ERROR;
  1271.                     }
  1272.  
  1273.                 _vfile ("rzfile: normal EOF");
  1274.                 ++Filcnt;
  1275.                 return c;
  1276.  
  1277.             case ERROR:                    /* Too much garbage in header search
  1278.                                            error                             */
  1279.                 if (--n < 0)
  1280.                     {
  1281.                     _vfile ("rzfile: _zgethdr returned %d", c);
  1282.                     return ERROR;
  1283.                     }
  1284.  
  1285.                 zmputs (_Attn);
  1286.                 continue;
  1287.  
  1288.             case ZDATA:
  1289.                 if (_rclhdr (_Rxhdr) != rxbytes)
  1290.                     {
  1291.                     if ( --n < 0)
  1292.                         {
  1293.                         return ERROR;
  1294.                         }
  1295.  
  1296.                     zmputs (_Attn);
  1297.                     continue;
  1298.                     }
  1299.  
  1300. moredata:
  1301.                 if (_Verbose > 1)
  1302.                     {
  1303.                     (*_do_report) (1, &rxbytes);
  1304.                     if (!sent_zm)
  1305.                         {
  1306.                         sent_zm = TRUE;
  1307.                         _say ("ZMODEM%s", _Crc32 ? " CRC-32" : "");
  1308.                         }
  1309.                         
  1310.                     }
  1311.                              
  1312.                 switch (c = _zrdata (secbuf, KSIZE))
  1313.                     {
  1314.                     case ZCAN:
  1315.                         _vfile ("rzfile: _zgethdr returned %d", c);
  1316.                         return ERROR;
  1317.  
  1318.                     case ERROR:            /* CRC error                         */
  1319.                         if (--n < 0)
  1320.                             {
  1321.                             _vfile ("rzfile: _zgethdr returned %d", c);
  1322.                             return ERROR;
  1323.                             }
  1324.                             
  1325.                         zmputs (_Attn);
  1326.                         continue;
  1327.  
  1328.                     case ZTIMEOUT:
  1329.                         if (--n < 0)
  1330.                             {
  1331.                             _vfile ("rzfile: _zgethdr returned %d", c);
  1332.                             return ERROR;
  1333.                             }
  1334.                             
  1335.                         continue;
  1336.  
  1337.                     case GOTCRCW:
  1338.                         n = 20;
  1339.                         putsec (secbuf, _Rxcount);
  1340.                         rxbytes += _Rxcount;
  1341.                         _stohdr (rxbytes);
  1342.                         _zshhdr (ZACK, _Txhdr);
  1343.                         _sendline (XON);
  1344.                         goto nxthdr;
  1345.                         
  1346.                     case GOTCRCQ:
  1347.                         n = 20;
  1348.                         putsec (secbuf, _Rxcount);
  1349.                         rxbytes += _Rxcount;
  1350.                         _stohdr (rxbytes);
  1351.                         _zshhdr (ZACK, _Txhdr);
  1352.                         goto moredata;
  1353.  
  1354.                     case GOTCRCG:
  1355.                         n = 20;
  1356.                         putsec (secbuf, _Rxcount);
  1357.                         rxbytes += _Rxcount;
  1358.                         goto moredata;
  1359.  
  1360.                     case GOTCRCE:
  1361.                         n = 20;
  1362.                         putsec (secbuf, _Rxcount);
  1363.                         rxbytes += _Rxcount;
  1364.                         goto nxthdr;
  1365.                     }    /* switch (c = _zrdata (secbuf, KSIZE)) */
  1366.                     
  1367.             }    /* switch (c = _zgethdr (_Rxhdr, 0)) */
  1368.  
  1369.         }    /* for (;;) */
  1370.         
  1371.     }    /* static int rzfile (void) */
  1372.  
  1373.  
  1374. /****************************************************************************
  1375. *    zmputs                                                                    *
  1376. *    Send a string to the modem, processing for \336 (sleep 1 sec) and \335     *
  1377. *    (break signal).                                                            *
  1378. ****************************************************************************/
  1379.  
  1380. static void zmputs (char *s)
  1381.     {
  1382.     int c;
  1383.  
  1384.     while (*s)
  1385.         {
  1386.         switch (c = *s++)
  1387.             {
  1388.             case '\336':
  1389.                 sleep (1);
  1390.                 continue;
  1391.                 
  1392.             case '\335':
  1393.                 _sendbrk ();
  1394.                 continue;
  1395.                 
  1396.             default:
  1397.                 _sendline (c);
  1398.             }    /* switch (c = *s++) */
  1399.             
  1400.         }    /* while (*s) */
  1401.         
  1402.     }    /* static void zmputs (char *s) */
  1403.  
  1404.  
  1405. /****************************************************************************
  1406. *    closeit                                                                    *
  1407. *    Close the receive dataset, return OK or ERROR.                            *
  1408. ****************************************************************************/
  1409.  
  1410. static int closeit (void)
  1411.     {
  1412.     if (close (fout) == -1)
  1413.         {
  1414.         _zperr_ ("file close ERROR\n");
  1415.         return ERROR;
  1416.         }
  1417.         
  1418. #if    0
  1419.     /* Bit fancy for MesS-DOS, what? */
  1420.     
  1421.     if (Modtime)
  1422.         {
  1423.         timep[0] = time (NULL);
  1424.         timep[1] = Modtime;
  1425.         utime (Pathname, timep);
  1426.         }
  1427.  
  1428.     if (Filemode)
  1429.         chmod (Pathname, (07777 & Filemode));
  1430. #endif
  1431.  
  1432.     return OK;
  1433.     }    /* static int closeit (void) */
  1434.  
  1435.  
  1436. /****************************************************************************
  1437. *    ackbibi                                                                    *
  1438. *    Ack a ZFIN packet, let bygones be bygones.                                *
  1439. ****************************************************************************/
  1440.  
  1441. static void ackbibi (void)
  1442.     {
  1443.     int n;
  1444.  
  1445.     _vfile ("ackbibi:");
  1446.     Readnum = 1;
  1447.     _stohdr (0L);
  1448.     for (n = 3; --n >= 0;)
  1449.         {
  1450.         purgeline ();
  1451.         _zshhdr (ZFIN, _Txhdr);
  1452.         switch (_readline (100))
  1453.             {
  1454.             case 'O':
  1455.                 _readline (1);            /* Discard 2nd 'O'                    */
  1456.                 _vfile ("ackbibi complete");
  1457.                 return;
  1458.  
  1459.             case RCDO:
  1460.                 return;
  1461.  
  1462.             case ZTIMEOUT:
  1463.             default:
  1464.                 break;
  1465.             }    /* switch (_readline (100)) */
  1466.             
  1467.         }    /* for (n = 3; --n >= 0;) */
  1468.         
  1469.     }    /* static void ackbibi (void) */
  1470.     
  1471.  
  1472. /****************************************************************************
  1473. *    sys2                                                                    *
  1474. *    Strip leading ! if present, do shell escape.                            *
  1475. ****************************************************************************/
  1476.  
  1477. static int sys2 (char *s)
  1478.     {
  1479.     if (*s == '!')
  1480.         ++s;
  1481.         
  1482.     return system (s);
  1483.     }    /* static int sys2 (char *s) */
  1484.     
  1485.  
  1486. /****************************************************************************
  1487. *    exec2                                                                    *
  1488. *    Strip leading '!' if present and do an exec.                            *
  1489. ****************************************************************************/
  1490.  
  1491. static void exec2 (char *s)
  1492.     {
  1493.     char *comspec;                        /* -> command.com                    */
  1494.     int result;                            /* result of exec                    */
  1495.     
  1496. #ifdef    DEBUGZ
  1497.     _vfile ("exec2: exec %s\n", s);
  1498. #endif
  1499.     if (*s == '!')
  1500.         ++s;
  1501.  
  1502.     if ((comspec = getenv ("COMSPEC")) != NULL)
  1503.         result = execl (comspec, "command", "/c", s, NULL);
  1504.     else
  1505.         result = execl ("command", "command", "/c", s, NULL);
  1506.  
  1507.     if (result == -1)
  1508.         perror ("exec2");
  1509.         
  1510.     }    /* static void exec2 (char *s) */
  1511. /* End of rz.c */
  1512.