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

  1. /****************************************************************************
  2. *    Language     :    Turbo C 2.0                                                *
  3. *    Logfile        :    sz.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    Mods for KA9Q.                                *
  9. *    30 Jan 93    :    1.4        GT    Fix KA9Q background working.                *
  10. *    21 Feb 93    :    1.5        GT    Fix reporting.                                *
  11. *    08 May 93    :    1.6        GT    Fix warnings.                                *
  12. *****************************************************************************
  13. *    Purpose        :    File send driver.                                        *
  14. *****************************************************************************
  15. *                :    This module is based on the equivalent module in the    *
  16. *                :    31 Aug 87 version of rz/sz.                                *
  17. *    $Id: sz.c 1.4 93/07/16 11:51:01 ROOT_DOS Exp $
  18. ****************************************************************************/
  19.  
  20. #include    <io.h>
  21. #include    <fcntl.h>
  22. #include    <stdio.h>
  23. #include    <stdlib.h>
  24. #include    <signal.h>
  25. #include    <setjmp.h>
  26. #include    <ctype.h>
  27. #include    <stdarg.h>
  28. #include    <time.h>
  29. #include    <process.h>
  30. #include    <string.h>
  31. #include    <io.h>
  32. #include    <sys/types.h>
  33. #include    <sys/stat.h>
  34. #include    <dos.h>
  35. #include    "socket.h"
  36. #include    "proc.h"
  37.  
  38. /* kludge for krappy Microsoft */
  39.  
  40. #ifndef    S_IFBLK
  41. #define    S_IFBLK        0x3000
  42. #endif
  43.  
  44. #include    "zmodem.h"
  45. #include    "sz.h"
  46. #include    "rbsb.h"            /* most of the system dependent stuff here    */
  47. #include    "zm.h"
  48. #ifdef    DEBUGZ
  49. #include    "tty.h"
  50. #endif
  51.  
  52.  
  53. #define HOWMANY        2048
  54. #define    NO_DCD        1
  55.  
  56. /****************************************************************************
  57. *    Local prototypes.                                                        *
  58. ****************************************************************************/
  59.  
  60. #if    0
  61. static void bibi (int n);
  62. #endif
  63. static void chkinvok (char protocol);
  64. static int readline (int n);
  65. static void purgeline (void);
  66. #if    0
  67. static void onintr (void);
  68. #endif
  69. static int wcsend (int argc, char **argp);
  70. static int wcs (char *oname);
  71. static int wctxpn (char *name);
  72. static int getnak (void);
  73. static int wctx (long flen);
  74. static int wcputsec (char *buf, int sectnum, int cseclen);
  75. static int filbuf (char *buf, int count);
  76. static int zfilbuf (char *buf, int count);
  77. static int readock (int timeout, int count);
  78. static int getzrxinit (void);
  79. static int sendzsinit (void);
  80. static int zsendfile (char *buf, int blen);
  81. static int zsendfdata (void);
  82. static int getinsync (int flag);
  83. static void saybibi (void);
  84. static int zsendcmd (char *buf, int blen);
  85.  
  86.  
  87. /****************************************************************************
  88. *    Global data.                                                            *
  89. ****************************************************************************/
  90.  
  91. int _Zmodem = 0;                /* ZMODEM protocol requested                */
  92. unsigned _Baud_z = 19200;
  93. static unsigned Txwindow;        /* Control the size of the transmitted window */
  94. static unsigned Txwspac;        /* Spacing between zcrcq requests            */
  95. static unsigned Txwcnt;            /* Counter used to space ack requests        */
  96. static long Lrxpos;                /* Receiver's last reported offset            */
  97. int _errors;
  98. int _sending;                    /* TRUE - sending a file.                    */
  99. int _zperr_handle;                /* -> log file                                */
  100.  
  101. /*
  102.  * Attention string to be executed by receiver to interrupt streaming data
  103.  *  when an error is detected.  A pause (0336) may be needed before the
  104.  *  ^C (03) or after it.
  105.  */
  106.  
  107. static char Myattn[] = { 0 };
  108.  
  109. static int in;
  110.  
  111. int _Lastrx;                                /* was char                        */
  112. int _Crcflg;                                /* was char                        */
  113. int _Wcsmask = 0377;
  114.  
  115. /* Command line option flags */
  116.  
  117. int _Verbose = 0;
  118. static int Modem2 = 0;            /* XMODEM Protocol - don't send pathnames    */
  119. int _Quiet = 0;                    /* overrides logic that would otherwise set
  120.                                    verbose                                    */
  121. static int Ascii = 0;            /* Add CR's for brain damaged programs        */
  122. static int Fullname = 0;        /* transmit full pathname                    */
  123. static int Unlinkafter = 0;        /* Unlink file after it is sent                */
  124.  
  125. static int Dottoslash = 0;        /* Change foo.bar.baz to foo/bar/baz        */
  126. int _firstsec;
  127. static int errcnt = 0;            /* number of files unreadable                */
  128. static int blklen = SECSIZ;        /* length of transmitted records            */
  129. static int Optiong;                /* Let it rip no wait for sector ACK's        */
  130. static int Noeofseen;
  131. static int Totsecs;                /* total number of sectors this file        */
  132. static char txbuf[KSIZE];
  133. static int Filcnt = 0;            /* count of number of files opened            */
  134. static int Lfseen = 0;
  135. static unsigned Rxbuflen = 16384;    /* Receiver's max buffer length            */
  136. static int Tframlen = 0;        /* Override for tx frame length                */
  137. static int blkopt = 0;            /* Override value for zmodem blklen            */
  138. static int Rxflags = 0;
  139. static long bytcnt;
  140. static int Wantfcs32 = TRUE;    /* want to send 32 bit FCS                    */
  141. static char Lzconv;                /* Local ZMODEM file conversion request        */
  142. char _Lzmanag;                    /* Local ZMODEM file management request        */
  143. static int Lskipnocor;
  144. static char Lztrans;
  145. char _zconv;                    /* ZMODEM file conversion request            */
  146. char _zmanag;                    /* ZMODEM file management request            */
  147. char _ztrans;                    /* ZMODEM file transport request            */
  148. static int Command;                /* Send a command, then exit.                */
  149. static char Cmdstr[256];        /* Command string                            */
  150. static int Cmdtries = 11;
  151. static int Cmdack1;                /* Rx ACKs command, then do it                */
  152. static int Exitcode;
  153. static int Testattn;            /* Force receiver to send Attn, etc with qbf. */
  154. static char *qbf = "The quick brown fox jumped over the lazy dog's back "
  155.                    "1234567890\r\n";
  156. static long Lastread;            /* Beginning offset of last buffer read        */
  157. static int Lastn;                /* Count of last buffer read or -1            */
  158. static int Dontread;            /* Don't read the buffer, it's still there    */
  159. static long Lastsync;            /* Last offset to which we got a ZRPOS        */
  160. static int Beenhereb4;            /* How many times we've been ZRPOS'd same
  161.                                    place                                    */
  162.  
  163. jmp_buf _tohere;                    /* For user abort.                            */
  164. static jmp_buf intrjmp;            /* For the interrupt on RX CAN.                */
  165. jmp_buf _nocarrier;                /* For carrier dropped.                        */
  166.  
  167. int _Zctlesc;                    /* Encode control characters                */
  168. int _Nozmodem = 0;                /* If invoked as "sb"                        */
  169. int _Zrwindow = 1400;            /* RX window size (controls garbage count)    */
  170. void (*_do_report) (int type, void *data) = _zperr;
  171.                                 /* -> progress report fn                    */
  172.  
  173. extern int Lleft;                /* number of chars in read buffer            */
  174. extern int Readnum;                /* how many bytes to read                    */
  175.  
  176.  
  177. #if    0
  178. /****************************************************************************
  179. *    bibi                                                                    *
  180. *    Called by signal interrupt or terminate to clean things up.                *
  181. ****************************************************************************/
  182.  
  183. static void bibi (int n)
  184.     {
  185.     n = n;
  186.     _canit ();
  187.     _zperr_ ("Interrupted\n");
  188.     longjmp (_tohere, -1);
  189.     }    /* static void bibi (int n) */
  190.  
  191.  
  192. /****************************************************************************
  193. *    onintr                                                                    *
  194. *    Called when Zmodem gets an interrupt (^X).                                *
  195. ****************************************************************************/
  196.  
  197. static void onintr (void)
  198.     {
  199. #if    0
  200.     signal (SIGINT, SIG_IGN);
  201. #endif
  202.     longjmp (intrjmp, -1);
  203.     }    /* static void onintr (void) */
  204. #endif
  205.  
  206.  
  207. /****************************************************************************
  208. *    _no_carrier                                                                *
  209. *    Tests to see if CD still present, exits if not.                            *
  210. ****************************************************************************/
  211.  
  212. void _no_carrier (void)
  213.     {
  214. #if    !defined (NO_DCD)
  215.     if ((modemstat () & 0x80) == 0)
  216.         {
  217.         _zperr_ ("No carrier\n");
  218.         longjmp (_nocarrier, -1);
  219.         }
  220.  
  221. #endif
  222.     }    /* void _no_carrier (void) */
  223.     
  224.  
  225. /****************************************************************************
  226. *    _sendline and _xsendline                                                *
  227. *    Send a character to remote.                                                *
  228. ****************************************************************************/
  229.  
  230. void _sendline (int c)
  231.     {
  232.     if (_sending)
  233.         c &= _Wcsmask;
  234.  
  235.     _xsendline (c);
  236.     }    /* void _sendline (int c) */
  237.  
  238.  
  239. void _xsendline (int c)
  240.     {
  241. #ifdef    DEBUGZ
  242.     if (_Verbose > 6)
  243.         _vfile ("_xsendline: %x\n", c);
  244. #endif
  245.  
  246.     while (_send ((unsigned char *) &c, 1) != 1)
  247.         _no_carrier ();
  248.         
  249.     }    /* void _xsendline (int c) */
  250.     
  251.  
  252. /****************************************************************************
  253. *    _flushmo                                                                *
  254. *    Flush the ouput channel.                                                *
  255. ****************************************************************************/
  256.  
  257. void _flushmo (void)
  258.     {
  259.     _flush ();
  260.     }    /* void _flushmo (void) */
  261.  
  262.  
  263. /****************************************************************************
  264. *    _sendfile                                                                *
  265. *    Send file(s).  Returns 0 if successful.                                    *
  266. ****************************************************************************/
  267.  
  268. int _sendfile (int s, char protocol, char *options, char *filenames[],
  269.                void (*reporter) (int type, void *data))
  270.     {
  271.     char *cp;
  272.     int npats;
  273.     int agcnt;
  274.     char **agcv;
  275.     char **patts;
  276.     int i;                                    /* loop counter                    */
  277. #if    0
  278.     void (*sigint_sav) (int);
  279.     void (*sigterm_sav) (int);
  280. #endif
  281.     
  282.     /* Initialise global variables */
  283.  
  284.     _z_socket = s;
  285.     Lleft = 0;
  286.     Readnum = HOWMANY;
  287.     Ascii = 0;
  288.     blklen = SECSIZ;
  289.     blkopt = 0;
  290.     Cmdtries = 11;
  291.     Command = FALSE;
  292.     _do_report = _zperr;
  293.     Dottoslash = 0;
  294.     errcnt = 0;
  295.     Exitcode = 0;
  296.     Filcnt = 0;
  297.     Fullname = 0;
  298.     Lfseen = 0;
  299.     Modem2 = 0;
  300.     _Nozmodem = 0;
  301.     _Quiet = 0;
  302.     Rxbuflen = 16384;
  303.     Rxflags = 0;
  304.     _sending = TRUE;
  305.     Tframlen = 0;
  306.     Unlinkafter = 0;
  307.     Wantfcs32 = TRUE;
  308.     _Wcsmask = 0377;
  309.     _Verbose = 0;
  310.     _Zmodem = 0;
  311.     _Zrwindow = 1400;
  312.  
  313.     /* See if null padding required */
  314.     
  315.     if (((cp = getenv ("ZNULLS")) != NULL) && *cp)
  316.         _Znulls = atoi (cp);
  317.     
  318.     chkinvok (protocol);                    /* select protocol                */
  319.     _Rxtimeout = 600;
  320.     npats = 0;
  321.  
  322.     /* Parse options. */
  323.     
  324.     cp = options;
  325.     while (*cp != '\0')
  326.         {
  327.         switch (*cp++)
  328.             {
  329.             case '+':                        /* append file                    */
  330.                 _Lzmanag = ZMAPND;
  331.                 break;
  332.  
  333.             case '7':                        /* strip top bit                */
  334.                 _Wcsmask = 0177;
  335.                 break;
  336.  
  337.             case 'a':                        /* NL -> CRNL conversion        */
  338.                 Lzconv = ZCNL;
  339.                 Ascii = TRUE;
  340.                 break;
  341.  
  342.             case 'b':                        /* binary file                    */
  343.                 Lzconv = ZCBIN;
  344.                 break;
  345.  
  346.             case 'i':                        /* command, no wait                */
  347.                 Cmdack1 = ZCACK1;
  348.  
  349.                 /* **** FALL THROUGH TO **** */
  350.  
  351.             case 'c':                        /* command, wait                */
  352.                 if (*cp != '#')                /* command delimiter?            */
  353.                     return (ERROR);            /* invalid parameter            */
  354.  
  355.                 Command = TRUE;
  356.                 for (i = 0; i < sizeof (Cmdstr); i++)
  357.                     {
  358.                     if (*++cp == '#')
  359.                         break;                /* end of command                */
  360.                         
  361.                     Cmdstr[i] = *cp;
  362.                     }
  363.  
  364.                 Cmdstr[i] = '\0';
  365.                 cp++;
  366.                 break;
  367.                 
  368.             case 'd':                        /* . -> /                        */
  369.                 ++Dottoslash;
  370.                 
  371.                 /* **** FALL THROUGH TO **** */
  372.  
  373.             case 'f':                        /* full pathnames                */
  374.                 Fullname = TRUE;
  375.                 break;
  376.             
  377.             case 'e':                        /* escape ctl chars                */
  378.                 _Zctlesc = 1;
  379.                 break;
  380.  
  381.             case 'k':                        /* YMODEM 1k                    */
  382.                 blklen = KSIZE;
  383.                 break;
  384.  
  385.             case 'L':                        /* limit subpacket length        */
  386.                 sscanf (cp, "%d", &blkopt);
  387.                 if (blkopt < 24 || blkopt > 1024)
  388.                     return (ERROR);            /* bad length                    */
  389.  
  390.                 cp = _stbnb (cp);            /* skip whitespace                */
  391.                 break;
  392.                 
  393.             case 'l':                        /* limit frame length            */
  394.                 sscanf (cp, "%d", &Tframlen);
  395.                 if (Tframlen < 32 || Tframlen > 1024)
  396.                     return (ERROR);
  397.  
  398.                 cp = _stbnb (cp);
  399.                 break;
  400.                 
  401.             case 'N':                        /* source newer or longer        */
  402.                 _Lzmanag = ZMNEWL;
  403.                 break;
  404.                 
  405.             case 'n':                        /* source newer                    */
  406.                 _Lzmanag = ZMNEW;
  407.                 break;
  408.                 
  409.             case 'o':                        /* 16 bit CRC                    */
  410.                 Wantfcs32 = FALSE;
  411.                 break;
  412.  
  413.             case 'p':                        /* no target overwrite            */
  414.                 _Lzmanag = ZMPROT;
  415.                 break;
  416.  
  417.             case 'r':                        /* resume file transfer            */
  418.                 Lzconv = ZCRESUM;
  419.                 break;
  420.  
  421.             case 'q':                        /* quiet                        */
  422.                 _Quiet = TRUE;
  423.                 _Verbose = 0;
  424.                 break;
  425.  
  426.             case 't':                        /* change timeout                */
  427.                 sscanf (cp, "%d", &_Rxtimeout);
  428.                 if (_Rxtimeout < 10 || _Rxtimeout > 1000)
  429.                     return (ERROR);
  430.  
  431.                 cp = _stbnb (cp);
  432.                 break;
  433.  
  434.             case 'T':                        /* test attention mode            */
  435.                 Testattn = TRUE;
  436.                 break;
  437.  
  438.             case 'u':                        /* erase after send                */
  439.                 ++Unlinkafter;
  440.                 break;
  441.                 
  442.             case 'v':                        /* debugging info                */
  443.                 ++_Verbose;
  444.                 break;
  445.                 
  446.             case 'w':                        /* window size                    */
  447.                 sscanf (cp, "%d", &Txwindow);
  448.                 if (Txwindow < 256)
  449.                     Txwindow = 256;
  450.                     
  451.                 Txwindow = (Txwindow / 64) * 64;
  452.                 Txwspac = Txwindow / 4;
  453.                 if (blkopt > Txwspac || (!blkopt && Txwspac < 1024))
  454.                     blkopt = Txwspac;
  455.                     
  456.                 cp = _stbnb (cp);
  457.                 break;
  458.                 
  459.             case 'X':                        /* use XMODEM                    */
  460.                 ++Modem2;
  461.                 break;
  462.                 
  463.             case 'Y':                        /* overwrite target only if
  464.                                                present                        */
  465.                 Lskipnocor = TRUE;
  466.  
  467.                 /* **** FALL THROUGH TO **** */
  468.  
  469.             case 'y':                        /* overwrite target always        */
  470.                 _Lzmanag = ZMCLOB;
  471.                 break;
  472.  
  473.             default:
  474.                 return (ERROR);
  475.             }    /* switch (*cp++) */
  476.  
  477.         }    /* while (*cp != '\0') */
  478.  
  479.     /* parse filenames */
  480.  
  481.     patts = filenames;
  482.     while (**patts != '\0')
  483.         {
  484.         npats++;                            /* bump filename count            */
  485.         patts++;                            /* try next string                */
  486.         }
  487.  
  488.     patts = filenames;
  489.     if (npats < 1 && !Command) 
  490.         return (ERROR);                        /* no filenames                    */
  491.  
  492.     /* Get reporter function */
  493.  
  494.     if (reporter != NULL)
  495.         _do_report = reporter;                /* user supplied fn                */
  496.  
  497. #if    0
  498.     if (_Verbose)
  499.         {
  500.         if ((_zperr_handle = open (LOGFILE,
  501.                                    O_CREAT | O_APPEND | O_WRONLY | O_TEXT,
  502.                                    S_IFREG | S_IWRITE)) == -1)
  503.             {
  504.             char buff[80];
  505.             
  506.             sprintf (buff, "Can't open log file %s: %s\n",
  507.                      LOGFILE, strerror (errno));
  508.             (*_do_report) (2, buff);
  509.             (*_do_report) (3, &Filcnt);        /* report no of files            */
  510.         
  511.             return (ERROR);
  512.             }
  513.  
  514.         _do_report = _zperr;                /* use default reporter            */
  515.         }
  516. #endif
  517.     
  518.     if (!_Quiet)
  519.         {
  520.         if (_Verbose == 0)
  521.             _Verbose = 2;
  522.             
  523.         }
  524.  
  525. #if    0
  526.     if ((sigint_sav = signal (SIGINT, bibi)) == SIG_IGN)
  527.         signal (SIGINT, SIG_IGN);
  528.     else
  529.         signal (SIGINT, bibi);
  530.  
  531. #endif
  532.  
  533. #if    0
  534.     sigint_sav = signal (SIGINT, bibi);
  535.     sigterm_sav = signal (SIGTERM, bibi);
  536. #endif
  537.         
  538.     /* Organise escape routes. */
  539.  
  540.     if (setjmp (_tohere) != 0)
  541.         {
  542.         (*_do_report) (3, &Filcnt);            /* report no of files            */
  543. #if    0
  544.         signal (SIGINT, sigint_sav);
  545.         signal (SIGTERM, sigterm_sav);
  546.         (void) close (_zperr_handle);
  547. #endif
  548.         return (-2);                        /* user abort                    */
  549.         }
  550.  
  551.     if (setjmp (_nocarrier) != 0)
  552.         {
  553.         (*_do_report) (3, &Filcnt);            /* report no of files            */
  554. #if    0
  555.         signal (SIGINT, sigint_sav);
  556.         signal (SIGTERM, sigterm_sav);
  557.         (void) close (_zperr_handle);
  558. #endif
  559.         return (-3);                        /* lost carrier                    */
  560.         }
  561.  
  562.     if (!Modem2)
  563.         {
  564. #if    0
  565.         if (!_Nozmodem)
  566.             {
  567.             printf ("rz\r");
  568.             }
  569. #endif
  570.  
  571.         if (!Command && !_Quiet && _Verbose != 1)
  572.             {
  573.             _say ("%d file%s requested:\r\n",
  574.                      npats, npats > 1 ? "s" : "");
  575.             for (agcnt = npats, agcv = patts; --agcnt >= 0;)
  576.                 {
  577.                 _say ("%s ", *agcv++);
  578.                 }
  579.                 
  580.             _say ("\r\n");
  581.             _say ("\r\n\bSending in Batch Mode\r\n");
  582.             }
  583.             
  584.         if (!_Nozmodem)
  585.             {
  586.             _stohdr (0L);
  587.             if (Command)
  588.                 _Txhdr[ZF0] = ZCOMMAND;
  589.  
  590.             _zshhdr (ZRQINIT, _Txhdr);
  591.             }
  592.  
  593.         }    /* if (!Modem2) */
  594.         
  595.     if (Command)
  596.         {
  597.         if (getzrxinit ())
  598.             {
  599.             Exitcode = -2;
  600.             _canit ();
  601.             }
  602.         else if (zsendcmd (Cmdstr, 1 + strlen (Cmdstr)))
  603.             {
  604.             Exitcode = -2;
  605.             _canit ();
  606.             }
  607.             
  608.         }
  609.     else if (wcsend (npats, patts) == ERROR)
  610.         {
  611.         Exitcode = -2;
  612.         _canit ();
  613.         }
  614.         
  615.     if (!_Quiet)
  616.         _say ("\n");
  617.  
  618.     (*_do_report) (3, &Filcnt);            /* report no of files            */
  619. #if    0
  620.     signal (SIGINT, sigint_sav);
  621.     signal (SIGTERM, sigterm_sav);
  622.     (void) close (_zperr_handle);
  623. #endif
  624.     return (Exitcode);
  625.     }    /* int _sendfile (int s, char protocol, char *options,
  626.                           char *filenames[],
  627.                           void (*reporter) (int type, void *data)) */
  628.  
  629.  
  630. /****************************************************************************
  631. *    _stbnb                                                                    *
  632. *    Skip to blank then skip to nonblank.                                    *
  633. ****************************************************************************/
  634.  
  635. char *_stbnb (char *cp)
  636.     {
  637.     /* skip to blank */
  638.  
  639.     while (!isspace (*cp))
  640.         cp++;
  641.         
  642.     /* skip to nonblank */
  643.  
  644.     while (isspace (*cp))
  645.         cp++;
  646.  
  647.     return (cp);
  648.     }    /* char *_stbnb (char *cp) */
  649.  
  650.  
  651. /****************************************************************************
  652. *    wcsend                                                                    *
  653. *    Send <argc> strings (<argp>) to remote.                                    *
  654. ****************************************************************************/
  655.  
  656. static int wcsend (int argc, char **argp)
  657.     {
  658.     int n;
  659.  
  660.     _Crcflg = FALSE;
  661.     _firstsec = TRUE;
  662.     bytcnt = -1;
  663.     for (n = 0; n < argc; ++n)
  664.         {
  665.         Totsecs = 0;
  666.         if (wcs (argp[n]) == ERROR)
  667.             return ERROR;
  668.             
  669.         }
  670.         
  671.     Totsecs = 0;
  672.     if (Filcnt == 0)
  673.         {
  674.         /* bitch if we couldn't open ANY files */
  675.         
  676. #if    0
  677.         if (1)
  678. #endif
  679.             {
  680.             Command = TRUE;
  681.             strcpy (Cmdstr, "echo Can't open any requested files");
  682.             if (getnak ())
  683.                 {
  684.                 Exitcode = -2;
  685.                 _canit ();
  686.                 }
  687.                 
  688.             if (!_Zmodem)
  689.                 _canit ();
  690.             else if (zsendcmd (Cmdstr, 1 + strlen (Cmdstr)))
  691.                 {
  692.                 Exitcode = -2;
  693.                 _canit ();
  694.                 }
  695.                 
  696.             Exitcode = -2;
  697.             return OK;
  698.             }
  699.             
  700. #if    0                                    /* unreachable                        */
  701.         _canit ();
  702.         _say ("\r\nCan't open any requested files.\r\n");
  703.         return ERROR;
  704. #endif
  705.         }    /* if (Filcnt == 0) */
  706.         
  707.     if (_Zmodem)
  708.         saybibi ();
  709.     else if (!Modem2)
  710.         wctxpn ("");
  711.         
  712.     return OK;
  713.     }    /* static int wcsend (int argc, char **argp) */
  714.  
  715.  
  716. /****************************************************************************
  717. *    wcs                                                                        *
  718. *    Send file <oname> to remote.                                            *
  719. ****************************************************************************/
  720.  
  721. static int wcs (char *oname)
  722.     {
  723.     int c;
  724.     struct stat f;
  725.     char name[PATHLEN];
  726.  
  727.     strcpy (name, oname);
  728.     if ((in = open (oname, O_RDONLY | O_BINARY)) == -1)
  729.         {
  730.         if (_Verbose > 2)
  731.             {
  732.             _say ("Couldn't open %s\r\n", oname);
  733.             }
  734.             
  735.         ++errcnt;
  736.         return OK;    /* pass over it, there may be others */
  737.         }
  738.         
  739.     ++Noeofseen;
  740.     Lastread = 0;
  741.     Lastn = -1;
  742.     Dontread = FALSE;
  743.     
  744.     /* Check for directory or block special files */
  745.     
  746.     fstat (in, &f);
  747.     c = f.st_mode & S_IFMT;
  748.     if (c == S_IFDIR || c == S_IFBLK)
  749.         {
  750.         close (in);
  751.         return OK;
  752.         }
  753.  
  754.     ++Filcnt;
  755.     switch (wctxpn (name))
  756.         {
  757.         case ERROR:
  758.             return ERROR;
  759.             
  760.         case ZSKIP:
  761.             return OK;
  762.         }
  763.         
  764.     if (!_Zmodem && wctx (f.st_size) == ERROR)
  765.         return ERROR;
  766.         
  767.     if (Unlinkafter)
  768.         unlink (oname);
  769.         
  770.     return 0;
  771.     }    /* static int wcs (char *oname) */
  772.     
  773.  
  774. /****************************************************************************
  775. *    wctxpn                                                                    *
  776. *    Generate and transmit pathname block consisting of pathname (null         *
  777. *    terminated), file length, mode time and file mode in octal as provided     *
  778. *    by the fstat call.                                                        *
  779. *    N.B.: modifies the passed name, may extend it!                            *
  780. ****************************************************************************/
  781.  
  782. static int wctxpn (char *name)
  783.     {
  784.     char *p, *q;
  785.     char name2[PATHLEN];
  786.     struct stat f;
  787.  
  788.     (*_do_report) (0, name);
  789.     if (Modem2)
  790.         {
  791.         if (*name && (fstat (in, &f) != -1))
  792.             {
  793.             _say ("Sending %s, %ld blocks: ", name, f.st_size >> 7);
  794.             }
  795.  
  796.         _say ("Give your local XMODEM receive command now.\r\n");
  797.         return OK;
  798.         }
  799.  
  800.     _vfile ("Awaiting pathname nak for %s", *name ? name : "<END>");
  801.     if (!_Zmodem)
  802.         if (getnak ())
  803.             return ERROR;
  804.             
  805.     q = (char *) 0;
  806.     if (Dottoslash)
  807.         {
  808.         /* change . to . */
  809.         for (p = name; *p; ++p)
  810.             {
  811.             if (*p == '/')
  812.                 q = p;
  813.             else if (*p == '.')
  814.                 *(q = p) = '/';
  815.                 
  816.             }
  817.             
  818.         if (q && strlen (++q) > 8)
  819.             {
  820.             /* If name > 8 chars */
  821.             q += 8;                            /*   make it .ext                 */
  822.             strcpy (name2, q);                /* save excess of name             */
  823.             *q = '.';
  824.             strcpy (++q, name2);            /* add it back                     */
  825.             }
  826.             
  827.         }    /* if (Dottoslash) */
  828.  
  829.     for (p = name, q = txbuf; *p;)
  830.         if ((*q++ = *p++) == '\\' && !Fullname)
  831.             q = txbuf;
  832.             
  833.     *q++ = 0;
  834.     p = q;
  835.     while (q < (txbuf + KSIZE))
  836.         *q++ = 0;
  837.  
  838.     if (!Ascii && *name && fstat (in, &f) != -1)
  839.         sprintf (p, "%lu %lo %o", f.st_size, f.st_mtime, f.st_mode);
  840.         
  841.     /* force 1k blocks if name won't fit in 128 byte block */
  842.  
  843.     if (txbuf[125])
  844.         blklen = KSIZE;
  845.     else
  846.         {
  847.         /* A little goodie for IMP/KMD */
  848.         
  849.         if (_Zmodem)
  850.             blklen = SECSIZ;
  851.             
  852.         txbuf[127] = (char) ((f.st_size + 127) >> 7);
  853.         txbuf[126] = (char) ((f.st_size + 127) >> 15);
  854.         }
  855.         
  856.     if (_Zmodem)
  857.         return zsendfile (txbuf, (int) (1 + strlen (p) + (p - txbuf)));
  858.         
  859.     if (wcputsec (txbuf, 0, SECSIZ) == ERROR)
  860.         return ERROR;
  861.         
  862.     return OK;
  863.     }    /* static int wctxpn (char *name) */
  864.  
  865.  
  866. /****************************************************************************
  867. *    getnak                                                                    *
  868. *    Returns FALSE if NAK or ZPAD received.                                    *
  869. ****************************************************************************/
  870.  
  871. static int getnak (void)
  872.     {
  873.     int firstch;
  874.  
  875.     _Lastrx = 0;
  876.     for (;;)
  877.         {
  878.         switch (firstch = readock (800, 1))
  879.             {
  880.             case ZPAD:
  881.                 if (getzrxinit ())
  882.                     return ERROR;
  883.  
  884.                 Ascii = 0;
  885.                 return FALSE;
  886.                 
  887.             case ZTIMEOUT:
  888.                 _zperr_ ("Timeout on pathname");
  889.                 return TRUE;
  890.                 
  891.             case WANTG:
  892.                 Optiong = TRUE;
  893.                 blklen=KSIZE;
  894.                 
  895.             case WANTCRC:
  896.                 _Crcflg = TRUE;
  897.                 
  898.             case NAK:
  899.                 return FALSE;
  900.  
  901.             case CAN:
  902.                 if ((firstch = readock (20, 1)) == CAN && _Lastrx == CAN)
  903.                     return TRUE;
  904.                     
  905.             default:
  906.                 break;
  907.             }    /* switch (firstch = readock (800, 1)) */
  908.             
  909.         _Lastrx = firstch;
  910.         }    /* for (;;) */
  911.         
  912.     }    /* static int getnak (void) */
  913.     
  914.  
  915. /****************************************************************************
  916. *    wctx                                                                    *
  917. *    Send <flen> bytes (in blocks) using XMODEM or YMODEM.                    *
  918. ****************************************************************************/
  919.  
  920. static int wctx (long flen)
  921.     {
  922.     int thisblklen;
  923.     int sectnum, attempts, firstch;
  924.     long charssent;
  925.  
  926.     charssent = 0;
  927.     _firstsec = TRUE;
  928.     thisblklen = blklen;
  929.     _vfile ("wctx:file length = %ld", flen);
  930.  
  931.     while ((firstch = readock (_Rxtimeout, 2)) != NAK &&
  932.            firstch != WANTCRC &&
  933.            firstch != WANTG &&
  934.            firstch != ZTIMEOUT &&
  935.            firstch != CAN)
  936.         ;
  937.         
  938.     if (firstch == CAN)
  939.         {
  940.         _zperr_ ("Receiver CANcelled");
  941.         return ERROR;
  942.         }
  943.         
  944.     if (firstch == WANTCRC)
  945.         _Crcflg = TRUE;
  946.         
  947.     if (firstch == WANTG)
  948.         _Crcflg = TRUE;
  949.  
  950.     sectnum = 0;
  951.     for (;;)
  952.         {
  953.         if (flen <= (charssent + 896L))
  954.             thisblklen = 128;
  955.  
  956.         if (!filbuf (txbuf, thisblklen))
  957.             break;
  958.             
  959.         if (wcputsec (txbuf, ++sectnum, thisblklen) == ERROR)
  960.             return ERROR;
  961.             
  962.         charssent += thisblklen;
  963.         }
  964.  
  965.     close (in);
  966.     attempts = 0;
  967.     do
  968.         {
  969.         purgeline ();
  970.         _sendline (EOT);
  971.         ++attempts;
  972.         firstch = (readock (_Rxtimeout, 1));
  973.         } while (firstch != ACK && attempts < RETRYMAX);
  974.                  
  975.     if (attempts == RETRYMAX)
  976.         {
  977.         _zperr_ ("No ACK on EOT");
  978.         return ERROR;
  979.         }
  980.     else
  981.         return OK;
  982.  
  983.     }    /* static int wctx (long flen) */
  984.  
  985.  
  986. /****************************************************************************
  987. *    wcputsec                                                                *
  988. *    Send block <sectnum> of length <cseclen> using XMODEM or YMODEM.        *
  989. ****************************************************************************/
  990.  
  991. static int wcputsec (char *buf, int sectnum, int cseclen)
  992.     {
  993.     int checksum, wcj;
  994.     char *cp;
  995.     unsigned oldcrc;
  996.     int firstch;
  997.     int attempts;
  998.  
  999.     firstch = 0;                        /* part of logic to detect CAN CAN    */
  1000.  
  1001.     _vfile ("Sector %3d %2dk\n", Totsecs, Totsecs / 8 );
  1002.     if (_Verbose > 1)
  1003.         _say ("\rSector %3d %2dk ", Totsecs, Totsecs / 8 );
  1004.  
  1005.     for (attempts = 0; attempts <= RETRYMAX; attempts++)
  1006.         {
  1007.         _Lastrx = firstch;
  1008.         _sendline (cseclen == KSIZE ? STX : SOH);
  1009.         _sendline (sectnum);
  1010.         _sendline (- sectnum - 1);
  1011.         oldcrc = checksum = 0;
  1012.         for (wcj = cseclen, cp = buf; --wcj >= 0;)
  1013.             {
  1014.             _sendline (*cp);
  1015.             oldcrc = updcrc ((0377 & *cp), oldcrc);
  1016.             checksum += *cp++;
  1017.             }
  1018.             
  1019.         if (_Crcflg)
  1020.             {
  1021.             oldcrc = updcrc (0, updcrc (0, oldcrc));
  1022.             _sendline ((int) oldcrc >> 8);
  1023.             _sendline ((int) oldcrc);
  1024.             }
  1025.         else
  1026.             _sendline (checksum);
  1027.  
  1028.         if (Optiong)
  1029.             {
  1030.             _firstsec = FALSE;
  1031.             return OK;
  1032.             }
  1033.  
  1034.         firstch = readock (_Rxtimeout, (Noeofseen && sectnum) ? 2 : 1);
  1035.  
  1036. gotnak:
  1037.         switch (firstch)
  1038.             {
  1039.             case CAN:
  1040.                 if (_Lastrx == CAN)
  1041.                     {
  1042. cancan:
  1043.                     _zperr_ ("Cancelled");
  1044.                     return ERROR;
  1045.                     }
  1046.  
  1047.                 break;
  1048.  
  1049.             case ZTIMEOUT:
  1050.                 _zperr_ ("Timeout on sector ACK");
  1051.                 continue;
  1052.  
  1053.             case WANTCRC:
  1054.                 if (_firstsec)
  1055.                     _Crcflg = TRUE;
  1056.  
  1057.             case NAK:
  1058.                 _zperr_ ("NAK on sector");
  1059.                 continue;
  1060.  
  1061.             case ACK: 
  1062.                 _firstsec = FALSE;
  1063.                 Totsecs += (cseclen >> 7);
  1064.                 return OK;
  1065.  
  1066.             case ERROR:
  1067.                 _zperr_ ("Got burst for sector ACK");
  1068.                 break;
  1069.  
  1070.             default:
  1071.                 _zperr_ ("Got %02x for sector ACK", firstch);
  1072.                 break;
  1073.             }    /* switch (firstch) */
  1074.             
  1075.         for (;;)
  1076.             {
  1077.             _Lastrx = firstch;
  1078.             if ((firstch = readock (_Rxtimeout, 2)) == ZTIMEOUT)
  1079.                 break;
  1080.  
  1081.             if (firstch == NAK || firstch == WANTCRC)
  1082.                 goto gotnak;
  1083.  
  1084.             if (firstch == CAN && _Lastrx == CAN)
  1085.                 goto cancan;
  1086.  
  1087.             }
  1088.  
  1089.         }    /* for (attempts = 0; attempts <= RETRYMAX; attempts++) */
  1090.         
  1091.     _zperr_ ("Retry Count Exceeded");
  1092.     return ERROR;
  1093.     }    /* static int wcputsec (char *buf, int sectnum, int cseclen) */
  1094.     
  1095.  
  1096. /****************************************************************************
  1097. *    filbuf                                                                    *
  1098. *    Fill <buf> with <count> chars padding with ^Z for CPM.                    *
  1099. ****************************************************************************/
  1100.  
  1101. static int filbuf (char *buf, int count)
  1102.     {
  1103.     int c, m;
  1104.     char locbuf[BUFSIZ];                /* local read buffer                */
  1105.     char *q;                            /* -> read buffer                    */
  1106.     int rcount;                            /* no of chars read                    */
  1107.     
  1108.     if (!Ascii)
  1109.         {
  1110.         m = read (in, buf, count);
  1111.         if (m <= 0)
  1112.             return 0;
  1113.             
  1114.         while (m < count)
  1115.             buf[m++] = 032;
  1116.             
  1117.         return count;
  1118.         }
  1119.         
  1120.     m = count;
  1121.     if (Lfseen)
  1122.         {
  1123.         *buf++ = 012;
  1124.         --m;
  1125.         Lfseen = 0;
  1126.         }
  1127.         
  1128. #if    0
  1129.     while ((c = getc (in)) != EOF)
  1130. #endif
  1131.     while ((rcount = read (in, locbuf, sizeof (locbuf))) != -1)
  1132.         {
  1133.         q = locbuf;
  1134.         while (rcount-- != 0)
  1135.             {
  1136.             c = *q++;
  1137.             if (c == 012)
  1138.                 {
  1139.                 *buf++ = 015;
  1140.                 if (--m == 0)
  1141.                     {
  1142.                     Lfseen = TRUE;
  1143.                     break;
  1144.                     }
  1145.  
  1146.                 }
  1147.  
  1148.             *buf++ = (char) c;
  1149.             if (--m == 0)
  1150.                 break;
  1151.  
  1152.             }    /* while (rcount-- != 0) */
  1153.  
  1154.         if (m == 0)
  1155.             break;
  1156.  
  1157.         }    /* while ((rcount = read (in, locbuf, sizeof (locbuf)) != -1) */
  1158.  
  1159.     if (m == count)
  1160.         return 0;
  1161.     else
  1162.         while (--m >= 0)
  1163.             *buf++ = CPMEOF;
  1164.  
  1165.     return count;
  1166.     }    /* static int filbuf (char *buf, int count) */
  1167.     
  1168.  
  1169. /****************************************************************************
  1170. *    zfilbuf                                                                    *
  1171. *    Fill <buf> with <count> chars.                                            *
  1172. ****************************************************************************/
  1173.  
  1174. static int zfilbuf (char *buf, int count)
  1175.     {
  1176.     if (eof (in))
  1177.         return (0);
  1178.         
  1179.     return (read (in, buf, count));
  1180. #if    0
  1181.     int c, m;
  1182.  
  1183.     m = count;
  1184.     while ((c = getc (in)) != EOF)
  1185.         {
  1186.         *buf++ = c;
  1187.         if (--m == 0)
  1188.             break;
  1189.  
  1190.         }
  1191.  
  1192.     return (count - m);
  1193. #endif
  1194.     }    /* static int zfilbuf (char *buf, int count) */
  1195.     
  1196.  
  1197. /****************************************************************************
  1198. *    _vfile                                                                    *
  1199. *    Print debugging message.                                                *
  1200. ****************************************************************************/
  1201.  
  1202. void _vfile (char *f, ...)
  1203.     {
  1204.     va_list parms;                            /* -> variable arguments        */
  1205.     char buf[128];                            /* for text                        */
  1206.     
  1207.     va_start (parms, f);
  1208.     if (_Verbose > 2)
  1209.         {
  1210.         vsprintf (buf, f, parms);
  1211.         strcat (buf, "\n");
  1212.         (*_do_report) (2, buf);                /* call reporter function        */
  1213.         }
  1214.  
  1215.     va_end (parms);
  1216.     }    /* void _vfile (char *f, ...) */
  1217.  
  1218.  
  1219. /****************************************************************************
  1220. *    _say                                                                    *
  1221. *    Report something unconditionally.                                        *
  1222. ****************************************************************************/
  1223.  
  1224. void _say (char *f, ...)
  1225.     {
  1226.     va_list parms;                            /* -> variable arguments        */
  1227.     char buf[128];                            /* for text                        */
  1228.     
  1229.     va_start (parms, f);
  1230.     vsprintf (buf, f, parms);
  1231.     (*_do_report) (2, buf);                    /* call reporter function        */
  1232.     va_end (parms);
  1233.     }    /* void say (char *f, ...) */
  1234.  
  1235.  
  1236. /****************************************************************************
  1237. *    readock                                                                    *
  1238. *    Reads character(s) from receive channel.  It attempts to read count     *
  1239. *    characters (1 <= <count> <= 3).  If it gets more than one, it is an     *
  1240. *    error unless all are CAN (otherwise, only normal response is ACK, CAN    *
  1241. *    or C).  Only looks for one if Optiong, which signifies cbreak, not raw     *
  1242. *    input.  <timeout> is in tenths of seconds.                                *
  1243. ****************************************************************************/
  1244.  
  1245. static int readock (int timeout, int count)
  1246.     {
  1247.     int c, t;
  1248.     static unsigned char byt[5];
  1249.     time_t start;                            /* start time for timeout        */
  1250.     
  1251.     if (Optiong)
  1252.         count = 1;                            /* Special hack for cbreak         */
  1253.  
  1254.     t = timeout / 10;
  1255.     if (t < 2)
  1256.         t = 2;
  1257.  
  1258.     time (&start);
  1259.     if (_Verbose > 5)
  1260.         {
  1261.         _say ("Timeout=%d Calling alarm (%d) ", timeout, t);
  1262.         byt[1] = 0;
  1263.         }
  1264.  
  1265.     _no_carrier ();
  1266.     while (1)
  1267.         {
  1268.         c = _receive (byt, count);
  1269.         if (c != 0)
  1270.             break;                            /* got something                */
  1271.  
  1272.         if (time (NULL) >= start + t)
  1273.             {
  1274.             _zperr_ ("TIMEOUT");
  1275.             return ZTIMEOUT;
  1276.             }
  1277.  
  1278.         }
  1279.         
  1280.     if (_Verbose > 5)
  1281.         _say ("ret cnt=%d %x %x\n", c, byt[0], byt[1]);
  1282.         
  1283.     if (c < 1)
  1284.         return ZTIMEOUT;
  1285.  
  1286.     if (c == 1)
  1287.         return (byt[0] & 0377);
  1288.     else
  1289.         while (c)
  1290.             if (byt[--c] != CAN)
  1291.                 return ERROR;
  1292.                 
  1293.     return CAN;
  1294.     }    /* static int readock (int timeout, int count) */
  1295.  
  1296.     
  1297. /****************************************************************************
  1298. *    readline                                                                *
  1299. *    Receive one control character with timeout.                                *
  1300. ****************************************************************************/
  1301.  
  1302. static int readline (int n)
  1303.     {
  1304.     return (readock (n, 1));
  1305.     }    /* static int readline (int n) */
  1306.     
  1307.  
  1308. /****************************************************************************
  1309. *    purgeline                                                                *
  1310. *    Flush input buffer.                                                        *
  1311. ****************************************************************************/
  1312.  
  1313. static void purgeline (void)
  1314.     {
  1315.     unsigned char c;
  1316.  
  1317.     while (_rdchk () > 0)
  1318.         _receive (&c, 1);
  1319.         
  1320. #if    0
  1321.     while (_receive (&c, 1) > 0)
  1322.         ;
  1323. #endif
  1324.         
  1325.     }    /* static void purgeline (void) */
  1326.  
  1327.  
  1328. /****************************************************************************
  1329. *    _canit                                                                     *
  1330. *    Send cancel string to get the other end to shut up.                        *
  1331. ****************************************************************************/
  1332.  
  1333. void _canit (void)
  1334.     {
  1335.     int result;
  1336.     int count = 0;
  1337. #ifdef    DEBUGZ
  1338.     char buf[128];
  1339. #endif
  1340.  
  1341.     static unsigned char canistr[] = { 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
  1342.                                        8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0 };
  1343.  
  1344.     _flushmo ();
  1345.     while (count != strlen ((char *) canistr))
  1346.         {
  1347.         while ((result = _send (canistr + count,
  1348.                                 strlen ((char *) canistr) - count)) == 0)
  1349.             ;
  1350.  
  1351.         count += result;
  1352. #ifdef    DEBUGZ
  1353.         sprintf (buf, "_canit: count = %d\r\n", count);
  1354.         _tout (buf);
  1355. #endif
  1356.         }
  1357.  
  1358.     _flushmo ();
  1359.     }    /* void _canit (void) */
  1360.  
  1361.  
  1362. /****************************************************************************
  1363. *    _zperr_                                                                    *
  1364. *    Log an error.                                                            *
  1365. ****************************************************************************/
  1366.  
  1367. void _zperr_ (char *s, ...)
  1368.     {
  1369.     va_list parms;
  1370.     char buf0[128];                            /* for report string            */
  1371.     char buf1[128];
  1372.     char buf2[128];
  1373.     
  1374.     if (_Verbose <= 0)
  1375.         return;
  1376.  
  1377.     va_start (parms, s);
  1378.     sprintf (buf1, "Retry %d: ", _errors);
  1379.     vsprintf (buf2, s, parms);
  1380.     sprintf (buf0, "%s%s\n", buf1, buf2);
  1381.     (*_do_report) (2, buf0);                /* call reporter function        */
  1382.     va_end (parms);
  1383.     }    /* void _zperr_ (char *s, ...) */
  1384.  
  1385.  
  1386. /****************************************************************************
  1387. *    _zperr                                                                    *
  1388. *    Default progress report function.                                        *
  1389. ****************************************************************************/
  1390.  
  1391. void _zperr (int type, void *data)
  1392.     {
  1393.     switch (type)
  1394.         {
  1395.         case 0:                                /* filename                        */
  1396.             tprintf ("FILE: %s\n", data);
  1397.             break;
  1398.  
  1399.         case 1:                                /* bytes transferred            */
  1400.             tprintf ("\r%7ld ", *((long *) data));
  1401.             break;
  1402.  
  1403.         case 2:                                /* other text                    */
  1404.             tprintf ("%s", data);
  1405.             break;
  1406.  
  1407.         case 3:                                /* end of transfer                */
  1408.             tprintf ("%5d files transferred\n", *((int *) data));
  1409.             break;
  1410.             
  1411.         default:
  1412.             return;
  1413.         }    /* switch (type) */
  1414.  
  1415.     }    /* void _zperr (int type, void *data) */
  1416.     
  1417.  
  1418. /****************************************************************************
  1419. *    _substr                                                                    *
  1420. *    Searches for <token> in string <s>.  Returns pointer to token within     *
  1421. *    string if found, NULL otherwise.                                        *
  1422. ****************************************************************************/
  1423.  
  1424. char *_substr (char *s, char *t)
  1425.     {
  1426.     char *ss,*tt;
  1427.     
  1428.     /* search for first char of token */
  1429.     
  1430.     for (ss = s; *s; s++)
  1431.         {
  1432.         if (*s == *t)
  1433.             {
  1434.             /* compare token with substring */
  1435.             
  1436.             for (ss = s, tt = t;;)
  1437.                 {
  1438.                 if (*tt == 0)
  1439.                     return s;
  1440.                     
  1441.                 if (*ss++ != *tt++)
  1442.                     break;
  1443.                     
  1444.                 }
  1445.  
  1446.             }    /* if (*s == *t) */
  1447.  
  1448.         }    /* for (ss = s; *s; s++) */
  1449.         
  1450.     return NULL;
  1451.     }    /* char *_substr (char *s, char *t) */
  1452.  
  1453.  
  1454. /****************************************************************************
  1455. *    getzrxinit                                                                *
  1456. *    Get the receiver's init parameters.                                        *
  1457. ****************************************************************************/
  1458.  
  1459. static int getzrxinit (void)
  1460.     {
  1461.     int n;
  1462.     struct stat f;
  1463.  
  1464.     for (n = 10; --n >= 0;)
  1465.         {
  1466.         switch (_zgethdr (_Rxhdr, 1))
  1467.             {
  1468.             case ZCHALLENGE:     /* Echo receiver's challenge numbr */
  1469.                 _stohdr (_Rxpos);
  1470.                 _zshhdr (ZACK, _Txhdr);
  1471.                 continue;
  1472.                 
  1473.             case ZCOMMAND:             /* They didn't see out ZRQINIT */
  1474.                 _stohdr (0L);
  1475.                 _zshhdr (ZRQINIT, _Txhdr);
  1476.                 continue;
  1477.                 
  1478.             case ZRINIT:
  1479.                 Rxflags = 0377 & _Rxhdr[ZF0];
  1480.                 _Txfcs32 = (Wantfcs32 && (Rxflags & CANFC32));
  1481.                 _Zctlesc |= Rxflags & TESCCTL;
  1482.                 Rxbuflen = (0377 & _Rxhdr[ZP0]) + ((0377 & _Rxhdr[ZP1]) << 8);
  1483.                 _vfile ("Rxbuflen=%d Tframlen=%d", Rxbuflen, Tframlen);
  1484. #if    0
  1485.                 signal (SIGINT, SIG_IGN);
  1486. #endif
  1487.  
  1488.                 /* Override to force shorter frame length */
  1489.     
  1490.                 if (Rxbuflen && (Rxbuflen > Tframlen) && (Tframlen >= 32))
  1491.                     Rxbuflen = Tframlen;
  1492.  
  1493.                 if (!Rxbuflen && (Tframlen >= 32) && (Tframlen <= 1024))
  1494.                     Rxbuflen = Tframlen;
  1495.  
  1496.                 _vfile ("Rxbuflen=%d", Rxbuflen);
  1497.  
  1498.                 /*
  1499.                  * If input is not a regular file, force ACK's each 1024
  1500.                  *  (A smarter strategey could be used here ...)
  1501.                  */
  1502.  
  1503.                 fstat (in, &f);
  1504.                 if (((f.st_mode & S_IFMT) != S_IFREG) &&
  1505.                     (Rxbuflen == 0 || Rxbuflen > 1024))
  1506.                     Rxbuflen = 1024;
  1507.  
  1508.                 _vfile ("Rxbuflen=%d", Rxbuflen);
  1509.  
  1510.                 return (sendzsinit ());
  1511.  
  1512.             case ZCAN:
  1513.             case ZTIMEOUT:
  1514.                 return ERROR;
  1515.  
  1516.             case ZRQINIT:
  1517.                 if (_Rxhdr[ZF0] == ZCOMMAND)
  1518.                     continue;
  1519.  
  1520.             default:
  1521.                 _zshhdr (ZNAK, _Txhdr);
  1522.                 continue;
  1523.             }    /* switch (_zgethdr (_Rxhdr, 1)) */
  1524.             
  1525.         }    /* for (n = 10; --n >= 0;) */
  1526.         
  1527.     return ERROR;
  1528.     }    /* static int getzrxinit (void) */
  1529.     
  1530.  
  1531. /****************************************************************************
  1532. *    sendzsinit                                                                *
  1533. *    Send send-init information.                                                *
  1534. ****************************************************************************/
  1535.  
  1536. static int sendzsinit (void)
  1537.     {
  1538.     int c;
  1539.  
  1540.     if (Myattn[0] == '\0' && (!_Zctlesc || (Rxflags & TESCCTL)))
  1541.         return OK;
  1542.         
  1543.     _errors = 0;
  1544.     for (;;)
  1545.         {
  1546.         _stohdr (0L);
  1547.         if (_Zctlesc)
  1548.             {
  1549.             _Txhdr[ZF0] |= TESCCTL;
  1550.             _zshhdr (ZSINIT, _Txhdr);
  1551.             }
  1552.         else
  1553.             _zsbhdr (ZSINIT, _Txhdr);
  1554.             
  1555.         _zsdata (Myattn, 1 + strlen (Myattn), ZCRCW);
  1556.         c = _zgethdr (_Rxhdr, 1);
  1557.         switch (c)
  1558.             {
  1559.             case ZCAN:
  1560.                 return ERROR;
  1561.  
  1562.             case ZACK:
  1563.                 return OK;
  1564.  
  1565.             default:
  1566.                 if (++_errors > 19)
  1567.                     return ERROR;
  1568.  
  1569.                 continue;
  1570.             }    /* switch (c) */
  1571.             
  1572.         }    /* for (;;) */
  1573.         
  1574.     }    /* static int sendzsinit (void) */
  1575.     
  1576.  
  1577. /****************************************************************************
  1578. *    zsendfile                                                                *
  1579. *    Send file name and related info.                                        *
  1580. ****************************************************************************/
  1581.  
  1582. static int zsendfile (char *buf, int blen)
  1583.     {
  1584.     int c;
  1585.  
  1586.     for (;;)
  1587.         {
  1588.         _Txhdr[ZF0] = Lzconv;                /* file conversion request */
  1589.         _Txhdr[ZF1] = _Lzmanag;                /* file management request */
  1590.         if (Lskipnocor)
  1591.             _Txhdr[ZF1] |= ZMSKNOLOC;
  1592.             
  1593.         _Txhdr[ZF2] = Lztrans;                /* file transport request */
  1594.         _Txhdr[ZF3] = 0;
  1595.         _zsbhdr (ZFILE, _Txhdr);
  1596.         _zsdata (buf, blen, ZCRCW);
  1597.  
  1598. again:
  1599.         c = _zgethdr (_Rxhdr, 1);
  1600.         switch (c)
  1601.             {
  1602.             case ZRINIT:
  1603.                 while ((c = readline (50)) > 0)
  1604.                     if (c == ZPAD)
  1605.                         {
  1606.                         goto again;
  1607.                         }
  1608.                         
  1609.                 /* **** FALL THRU TO **** */
  1610.  
  1611.             default:
  1612.                 continue;
  1613.  
  1614.             case ZCAN:
  1615.             case ZTIMEOUT:
  1616.             case ZABORT:
  1617.             case ZFIN:
  1618.                 return ERROR;
  1619.  
  1620.             case ZSKIP:
  1621.                 close (in);
  1622.                 return c;
  1623.                 
  1624.             case ZRPOS:
  1625.                 /*
  1626.                  * Suppress zcrcw request otherwise triggered by
  1627.                  * lastyunc==bytcnt
  1628.                  */
  1629.  
  1630.                 Lastsync = (bytcnt = _Txpos = _Rxpos) - 1;
  1631.                 lseek (in, _Rxpos, 0);
  1632.                 Dontread = FALSE;
  1633.                 return zsendfdata ();
  1634.             }    /* switch (c) */
  1635.             
  1636.         }    /* for (;;) */
  1637.         
  1638.     }    /* static int zsendfile (char *buf, int blen) */
  1639.     
  1640.  
  1641. /****************************************************************************
  1642. *    zsendfdata                                                                *
  1643. *    Send the data in the file.                                                *
  1644. ****************************************************************************/
  1645.  
  1646. static int zsendfdata (void)
  1647.     {
  1648.     int c, e, n;
  1649.     int newcnt;
  1650.     long tcount = 0;
  1651.     int junkcount;                    /* Counts garbage chars received by TX    */
  1652.     static int tleft = 6;            /* Counter for test mode                */
  1653.     int sent_zm = FALSE;            /* TRUE - sent ZMODEM string            */
  1654.     if (_Baud_z > 300)
  1655.         blklen = 256;
  1656.         
  1657.     if (_Baud_z > 1200)
  1658.         blklen = 512;
  1659.         
  1660.     if (_Baud_z > 2400)
  1661.         blklen = KSIZE;
  1662.         
  1663.     if (Rxbuflen && blklen > Rxbuflen)
  1664.         blklen = Rxbuflen;
  1665.         
  1666.     if (blkopt && blklen > blkopt)
  1667.         blklen = blkopt;
  1668.         
  1669.     _vfile ("Rxbuflen=%d blklen=%d", Rxbuflen, blklen);
  1670.     _vfile ("Txwindow = %u Txwspac = %d", Txwindow, Txwspac);
  1671.     Lrxpos = 0;
  1672.     junkcount = 0;
  1673.     Beenhereb4 = FALSE;
  1674.     
  1675. somemore:
  1676.     if (setjmp (intrjmp))
  1677.         {
  1678. waitack:
  1679.         junkcount = 0;
  1680.         c = getinsync (0);
  1681.  
  1682. gotack:
  1683.         switch (c)
  1684.             {
  1685.             default:
  1686.             case ZCAN:
  1687.                 close (in);
  1688.                 return ERROR;
  1689.  
  1690.             case ZSKIP:
  1691.                 close (in);
  1692.                 return c;
  1693.  
  1694.             case ZACK:
  1695.             case ZRPOS:
  1696.                 break;
  1697.  
  1698.             case ZRINIT:
  1699.                 return OK;
  1700.             }    /* switch (c) */
  1701.             
  1702.         /*
  1703.          * If the reverse channel can be tested for data,
  1704.          *  this logic may be used to detect error packets
  1705.          *  sent by the receiver, in place of setjmp/longjmp
  1706.          *  _rdchk () returns non 0 if a character is available
  1707.          */
  1708.  
  1709.         while (_rdchk ())
  1710.             {
  1711.             switch (readline (1))
  1712.                 {
  1713.                 case CAN:
  1714.                 case ZPAD:
  1715.                     c = getinsync (1);
  1716.                     goto gotack;
  1717.  
  1718.                 case XOFF:                /* Wait a while for an XON             */
  1719.                 case XOFF | 0200:
  1720.                     readline(100);
  1721.                 }    /* switch (readline (1)) */
  1722.                 
  1723.             }    /* while (_rdchk ()) */
  1724.             
  1725.         }    /* if (setjmp (intrjmp)) */
  1726.  
  1727. #if    0
  1728.     signal (SIGINT, onintr);
  1729. #endif
  1730.     newcnt = Rxbuflen;
  1731.     Txwcnt = 0;
  1732.     _stohdr (_Txpos);
  1733.     _zsbhdr (ZDATA, _Txhdr);
  1734.  
  1735.     /*
  1736.      * Special testing mode.  This should force receiver to Attn,ZRPOS
  1737.      *  many times.  Each time the signal should be caught, causing the
  1738.      *  file to be started over from the beginning.
  1739.      */
  1740.      
  1741.     if (Testattn)
  1742.         {
  1743.         if (--tleft)
  1744.             while (tcount < 20000)
  1745.                 {
  1746.                 _send ((unsigned char *) qbf, strlen (qbf));
  1747.                 tcount += strlen (qbf);
  1748.                 while (_rdchk ())
  1749.                     {
  1750.                     switch (readline (1))
  1751.                         {
  1752.                         case CAN:
  1753.                         case ZPAD:
  1754.                             goto waitack;
  1755.  
  1756.                         case XOFF:        /* Wait for XON                     */
  1757.                         case XOFF | 0200:
  1758.                             readline (100);
  1759.                         }    /* switch (readline (1)) */
  1760.                         
  1761.                     }    /* while (_rdchk ()) */
  1762.                     
  1763.                 }    /* while (tcount < 20000) */
  1764.                 
  1765. #if    0
  1766.         signal (SIGINT, SIG_IGN);
  1767. #endif
  1768.         _canit ();
  1769.         sleep (3);
  1770.         purgeline ();
  1771.         printf ("\nTcount = %ld\n", tcount);
  1772.         if (tleft)
  1773.             {
  1774.             printf ("ERROR: Interrupts Not Caught\n");
  1775.             return (ERROR);
  1776.             }
  1777.             
  1778.         return (0);
  1779.         }    /* if (Testattn) */
  1780.         
  1781.     do
  1782.         {
  1783.         if (Dontread)
  1784.             {
  1785.             n = Lastn;
  1786.             }
  1787.         else
  1788.             {
  1789.             n = zfilbuf (txbuf, blklen);
  1790.             Lastread = _Txpos;
  1791.             Lastn = n;
  1792.             }
  1793.  
  1794.         Dontread = FALSE;
  1795.         if (n < blklen)
  1796.             e = ZCRCE;
  1797.         else if (junkcount > 3)
  1798.             e = ZCRCW;
  1799.         else if (bytcnt == Lastsync)
  1800.             e = ZCRCW;
  1801.         else if (Rxbuflen && (newcnt -= n) <= 0)
  1802.             e = ZCRCW;
  1803.         else if (Txwindow && (Txwcnt += n) >= Txwspac)
  1804.             {
  1805.             Txwcnt = 0;
  1806.             e = ZCRCQ;
  1807.             }
  1808.         else
  1809.             e = ZCRCG;
  1810.             
  1811.         if (_Verbose > 1)
  1812.             {
  1813.             (*_do_report) (1, &_Txpos);
  1814.             if (!sent_zm)
  1815.                 {
  1816.                 sent_zm = TRUE;
  1817.                 _say ("ZMODEM%s", _Crc32t ? " CRC-32" : "");
  1818.                 }
  1819.                 
  1820.             }
  1821.                      
  1822.         _zsdata (txbuf, n, e);
  1823.         bytcnt = _Txpos += n;
  1824.         if (e == ZCRCW)
  1825.             goto waitack;
  1826.  
  1827.         /*
  1828.          * If the reverse channel can be tested for data,
  1829.          *  this logic may be used to detect error packets
  1830.          *  sent by the receiver, in place of setjmp/longjmp
  1831.          *  _rdchk () returns non 0 if a character is available
  1832.          */
  1833.          
  1834.         while (_rdchk ())
  1835.             {
  1836.             switch (readline (1))
  1837.                 {
  1838.                 case CAN:
  1839.                 case ZPAD:
  1840.                     c = getinsync (1);
  1841.                     if (c == ZACK)
  1842.                         break;
  1843.  
  1844.                     /* zcrce - dinna wanna starta ping-pong game */
  1845.  
  1846.                     _zsdata (txbuf, 0, ZCRCE);
  1847.                     goto gotack;
  1848.  
  1849.                 case XOFF:                /* Wait a while for an XON             */
  1850.                 case XOFF | 0200:
  1851.                     readline (100);
  1852.  
  1853.                 default:
  1854.                     ++junkcount;
  1855.                 }    /* switch (readline (1)) */
  1856.                 
  1857.             }    /* while (_rdchk ()) */
  1858.             
  1859.         if (Txwindow)
  1860.             {
  1861.             while ((tcount = _Txpos - Lrxpos) >= Txwindow)
  1862.                 {
  1863.                 _vfile ("%ld window >= %u", tcount, Txwindow);
  1864.                 if (e != ZCRCQ)
  1865.                     _zsdata (txbuf, 0, e = ZCRCQ);
  1866.                     
  1867.                 c = getinsync (1);
  1868.                 if (c != ZACK)
  1869.                     {
  1870.                     _zsdata (txbuf, 0, ZCRCE);
  1871.                     goto gotack;
  1872.                     }
  1873.                 }
  1874.  
  1875.             _vfile ("window = %ld", tcount);
  1876.             }
  1877.  
  1878.         } while (n == blklen);
  1879.  
  1880. #if    0
  1881.     signal (SIGINT, SIG_IGN);
  1882. #endif
  1883.  
  1884.     for (;;)
  1885.         {
  1886.         _stohdr (_Txpos);
  1887.         _zsbhdr (ZEOF, _Txhdr);
  1888.         switch (getinsync (0))
  1889.             {
  1890.             case ZACK:
  1891.                 continue;
  1892.  
  1893.             case ZRPOS:
  1894.                 goto somemore;
  1895.  
  1896.             case ZRINIT:
  1897.                 return OK;
  1898.  
  1899.             case ZSKIP:
  1900.                 close (in);
  1901.                 return c;
  1902.  
  1903.             default:
  1904.                 close (in);
  1905.                 return ERROR;
  1906.             }    /* switch (getinsync (0)) */
  1907.             
  1908.         }    /* for (;;) */
  1909.         
  1910.     }    /* static int zsendfdata (void) */
  1911.     
  1912.  
  1913. /****************************************************************************
  1914. *    getinsync                                                                *
  1915. *    Respond to receiver's complaint, get back in sync with receiver.        *
  1916. ****************************************************************************/
  1917.  
  1918. static int getinsync (int flag)
  1919.     {
  1920.     int c;
  1921.  
  1922.     for (;;)
  1923.         {
  1924.         if (Testattn)
  1925.             {
  1926.             printf ("\r\n\n\n***** Signal Caught *****\r\n");
  1927.             _Rxpos = 0;
  1928.             c = ZRPOS;
  1929.             }
  1930.         else
  1931.             c = _zgethdr (_Rxhdr, 0);
  1932.             
  1933.         switch (c)
  1934.             {
  1935.             case ZCAN:
  1936.             case ZABORT:
  1937.             case ZFIN:
  1938.             case ZTIMEOUT:
  1939.                 return ERROR;
  1940.  
  1941.             case ZRPOS:
  1942.                 /* ************************************* */
  1943.                 /*    If sending to a modem buffer, you     */
  1944.                 /*     might send a break at this point to */
  1945.                 /*     dump the modem's buffer.             */
  1946.  
  1947.                 if (Lastn >= 0 && Lastread == _Rxpos)
  1948.                     {
  1949.                     Dontread = TRUE;
  1950.                     }
  1951.                 else
  1952.                     {
  1953. #if    0
  1954.                     clearerr (in);           /* In case file EOF seen */
  1955. #endif
  1956.                     lseek (in, _Rxpos, 0);
  1957.                     }
  1958.  
  1959.                 bytcnt = Lrxpos = _Txpos = _Rxpos;
  1960.                 if (Lastsync == _Rxpos)
  1961.                     {
  1962.                     if (++Beenhereb4 > 4)
  1963.                         if (blklen > 256)
  1964.                             blklen /= 2;
  1965.  
  1966.                     }
  1967.  
  1968.                 Lastsync = _Rxpos;
  1969.                 return c;
  1970.  
  1971.             case ZACK:
  1972.                 Lrxpos = _Rxpos;
  1973.                 if (flag || _Txpos == _Rxpos)
  1974.                     return ZACK;
  1975.  
  1976.                 continue;
  1977.  
  1978.             case ZRINIT:
  1979.             case ZSKIP:
  1980.                 close (in);
  1981.                 return c;
  1982.  
  1983.             case ERROR:
  1984.             default:
  1985.                 _zsbhdr (ZNAK, _Txhdr);
  1986.                 continue;
  1987.             }    /* switch (c) */
  1988.             
  1989.         }    /* for (;;) */
  1990.         
  1991.     }    /* static int getinsync (int flag) */
  1992.     
  1993.  
  1994. /****************************************************************************
  1995. *    saybibi                                                                    *
  1996. *    Say "bibi" to the receiver, try to do it cleanly.                        *
  1997. ****************************************************************************/
  1998.  
  1999. static void saybibi (void)
  2000.     {
  2001.     for (;;)
  2002.         {
  2003.         _stohdr (0L);                      /* CAF Was _zsbhdr - minor change */
  2004.         _zshhdr (ZFIN, _Txhdr);                /*    to make debugging easier */
  2005.         switch (_zgethdr (_Rxhdr, 0))
  2006.             {
  2007.             case ZFIN:
  2008.                 _sendline ('O');
  2009.                 _sendline ('O');
  2010.                 _flushmo ();
  2011.                 
  2012.             case ZCAN:
  2013.             case ZTIMEOUT:
  2014.                 return;
  2015.             }
  2016.  
  2017.         }
  2018.  
  2019.     }    /* static void saybibi (void) */
  2020.  
  2021.  
  2022. /****************************************************************************
  2023. *    _bttyout                                                                *
  2024. *    Local screen character display function.                                *
  2025. ****************************************************************************/
  2026.     
  2027. void _bttyout (int c)
  2028.     {
  2029.     char str[2];                        /* for making string                */
  2030.     
  2031.     if (_Verbose)
  2032.         {
  2033.         str[0] = (char) c;
  2034.         str[1] = '\0';
  2035.         _say (str);
  2036.         }
  2037.         
  2038.     }    /* void _bttyout (int c) */
  2039.  
  2040.  
  2041. /****************************************************************************
  2042. *    zsendcmd                                                                *
  2043. *    Send command and related info.                                            *
  2044. ****************************************************************************/
  2045.  
  2046. static int zsendcmd (char *buf, int blen)
  2047.     {
  2048.     int c;
  2049.     long cmdnum;
  2050.  
  2051.     cmdnum = getpid ();
  2052.     _errors = 0;
  2053.     for (;;)
  2054.         {
  2055.         _stohdr (cmdnum);
  2056.         _Txhdr[ZF0] = (char) Cmdack1;
  2057.         _zsbhdr (ZCOMMAND, _Txhdr);
  2058.         _zsdata (buf, blen, ZCRCW);
  2059.  
  2060. listen:
  2061.         _Rxtimeout = 100;                   /* Ten second wait for resp. */
  2062.         c = _zgethdr (_Rxhdr, 1);
  2063.  
  2064.         switch (c)
  2065.             {
  2066.             case ZRINIT:
  2067.                 goto listen;    /* CAF 8-21-87 */
  2068.  
  2069.             case ERROR:
  2070.             case ZTIMEOUT:
  2071.                 if (++_errors > Cmdtries)
  2072.                     return ERROR;
  2073.  
  2074.                 continue;
  2075.  
  2076.             case ZCAN:
  2077.             case ZABORT:
  2078.             case ZFIN:
  2079.             case ZSKIP:
  2080.             case ZRPOS:
  2081.                 return ERROR;
  2082.  
  2083.             default:
  2084.                 if (++_errors > 20)
  2085.                     return ERROR;
  2086.  
  2087.                 continue;
  2088.  
  2089.             case ZCOMPL:
  2090.                 Exitcode = (int) _Rxpos;
  2091.                 saybibi ();
  2092.                 return OK;
  2093.             }    /* switch (c) */
  2094.             
  2095.         }    /* for (;;) */
  2096.         
  2097.     }    /* static int zsendcmd (char *buf, int blen) */
  2098.     
  2099.  
  2100. /****************************************************************************
  2101. *    chkinvok                                                                *
  2102. *    Set chosen protocol.                                                    *
  2103. ****************************************************************************/
  2104.  
  2105. static void chkinvok (char protocol)
  2106.     {
  2107.     if (protocol == 'y')
  2108.         {
  2109.         _Nozmodem = TRUE;
  2110.         blklen = KSIZE;
  2111.         }
  2112.         
  2113.     if (protocol == 'x')
  2114.         {
  2115.         Modem2 = TRUE;
  2116.         }
  2117.  
  2118.     }    /* static void chkinvok (char protocol) */
  2119. /* End of sz.c */
  2120.