home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 2 BBS / 02-BBS.zip / BSRC_250.LZH / JANUS.C < prev    next >
C/C++ Source or Header  |  1991-09-15  |  79KB  |  2,091 lines

  1. /*--------------------------------------------------------------------------*/
  2. /*                                                                          */
  3. /*                                                                          */
  4. /*      ------------         Bit-Bucket Software, Co.                       */
  5. /*      \ 10001101 /         Writers and Distributors of                    */
  6. /*       \ 011110 /          Freely Available<tm> Software.                 */
  7. /*        \ 1011 /                                                          */
  8. /*         ------                                                           */
  9. /*                                                                          */
  10. /*  (C) Copyright 1987-91, Bit Bucket Software Co., a Delaware Corporation. */
  11. /*                                                                          */
  12. /*                                                                          */
  13. /*                  BinkleyTerm Janus revision 0.31, 11- 2-89               */
  14. /*                   Full-duplex WaZOO file transfer protocol               */
  15. /*                                                                          */
  16. /*                                                                          */
  17. /*    For complete  details  of the licensing restrictions, please refer    */
  18. /*    to the License  agreement,  which  is published in its entirety in    */
  19. /*    the MAKEFILE and BT.C, and also contained in the file LICENSE.250.    */
  20. /*                                                                          */
  21. /*    USE  OF THIS FILE IS SUBJECT TO THE  RESTRICTIONS CONTAINED IN THE    */
  22. /*    BINKLEYTERM  LICENSING  AGREEMENT.  IF YOU DO NOT FIND THE TEXT OF    */
  23. /*    THIS  AGREEMENT IN ANY OF THE  AFOREMENTIONED FILES,  OR IF YOU DO    */
  24. /*    NOT HAVE THESE FILES,  YOU  SHOULD  IMMEDIATELY CONTACT BIT BUCKET    */
  25. /*    SOFTWARE CO.  AT ONE OF THE  ADDRESSES  LISTED BELOW.  IN NO EVENT    */
  26. /*    SHOULD YOU  PROCEED TO USE THIS FILE  WITHOUT HAVING  ACCEPTED THE    */
  27. /*    TERMS  OF  THE  BINKLEYTERM  LICENSING  AGREEMENT,  OR  SUCH OTHER    */
  28. /*    AGREEMENT AS YOU ARE ABLE TO REACH WITH BIT BUCKET SOFTWARE, CO.      */
  29. /*                                                                          */
  30. /*                                                                          */
  31. /* You can contact Bit Bucket Software Co. at any one of the following      */
  32. /* addresses:                                                               */
  33. /*                                                                          */
  34. /* Bit Bucket Software Co.        FidoNet  1:104/501, 1:343/491             */
  35. /* P.O. Box 460398                AlterNet 7:491/0                          */
  36. /* Aurora, CO 80046               BBS-Net  86:2030/1                        */
  37. /*                                Internet f491.n343.z1.fidonet.org         */
  38. /*                                                                          */
  39. /* Please feel free to contact us at any time to share your comments about  */
  40. /* our software and/or licensing policies.                                  */
  41. /*                                                                          */
  42. /*--------------------------------------------------------------------------*/
  43.  
  44. /* Include this file before any other includes or defines! */
  45.  
  46. #include "includes.h"
  47.  
  48. #include "janus.h"
  49.  
  50.  
  51. /* Private routines */
  52. void getfname (word);
  53. void sendpkt (byte *, int, int);
  54. void sendpkt32 (byte *, int, int);
  55. void txbyte (byte);
  56. long procfname (void);
  57. byte rcvpkt (void);
  58. void rxclose (word);
  59. void endbatch (void);
  60. void j_message (word, char *,...);
  61. void j_status (char *,...);
  62. void j_msgend (word);
  63. int  j_error (char *, char *);
  64. void update_y (void);
  65. void long_set_timer (long *, word);
  66. int  long_time_gone (long *);
  67. int  rcvrawbyte (void);
  68. int  rxbyte (void);
  69. void xfer_summary (char *, char *, long *, int);
  70. void update_status (long *, long *, long, int *, int);
  71. void through (long *, long *);
  72. int  get_filereq (byte);
  73. int  record_reqfile (char *);
  74. int  timeof_reqfile (long);
  75. byte get_reqname (byte);
  76. void mark_done (char *);
  77.  
  78.  
  79.  
  80. /* Private data. I know, proper software design says you shouldn't make data */
  81. /* global unless you really need to.  In this case speed and code size make  */
  82. /* it more important to avoid constantly pushing & popping arguments.        */
  83.  
  84. static char *GenericError = "!%s";
  85. static char *ReqTmp = "JANUSREQ.TMP";
  86. static char *Rxbuf;       /* Address of packet reception buffer              */
  87. static char *Txfname;     /* Full path of file we're sending                 */
  88. static char *Rxfname;     /* Full path of file we're receiving               */
  89. static byte *Rxbufptr;    /* Current position within packet reception buffer */
  90. static byte *Rxbufmax;    /* Upper bound of packet reception buffer          */
  91. static byte  Do_after;    /* What to do with file being sent when we're done */
  92. static byte  WaitFlag;    /* Tells rcvrawbyte() whether or not to wait       */
  93. static byte  SharedCap;   /* Capability bits both sides have in common       */
  94. static int   Txfile;      /* File handle of file we're sending               */
  95. static int   Rxfile;      /* File handle of file we're receiving             */
  96. static int   ReqRecorded; /* Number of files obtained by this request        */
  97. static word  TimeoutSecs; /* How long to wait for various things             */
  98. static int   Rxblklen;    /* Length of data in last data block packet recvd  */
  99. static int   Next_y;      /* Number of next available line on screen         */
  100. static int   Tx_y;        /* Line number of file transmission status display */
  101. static int   Rx_y;        /* Line number of file reception status display    */
  102. static long  Txlen;       /* Total length of file we're sending              */
  103. static long  Rxlen;       /* Total length of file we're receiving            */
  104. static long  Rxfiletime;  /* Timestamp of file we're receiving               */
  105. static long  Diskavail;   /* Bytes available in upload directory             */
  106. static long  TotalBytes;  /* Total bytes xferred in this session             */
  107. static long  Txsttime;    /* Time at which we started sending current file   */
  108. static long  Rxsttime;    /* Time at which we started receiving current file */
  109.  
  110.  
  111. /*****************************************************************************/
  112. /* Super-duper neato-whizbang full-duplex streaming ACKless batch file       */
  113. /* transfer protocol for use in WaZOO mail sessions                          */
  114. /*****************************************************************************/
  115. void Janus (void)
  116. {
  117.    byte  xstate;          /* Current file transmission state                 */
  118.    byte  rstate;          /* Current file reception state                    */
  119.    byte  pkttype;         /* Type of packet last received                    */
  120.    byte  tx_inhibit;      /* Flag to wait and send after done receiving      */
  121.    char *holdname;        /* Name of hold area                               */
  122.    byte  fsent;           /* Did we manage to send anything this session?    */
  123.    byte  sending_req;     /* Are we currently sending requested files?       */
  124.    byte  attempting_req;  /* Are we waiting for the sender to start our req? */
  125.    byte  req_started;     /* Has the sender started servicing our request?   */
  126.    int   txoldeta;        /* Last transmission ETA displayed                 */
  127.    int   rxoldeta;        /* Last reception ETA displayed                    */
  128.    word  blklen;          /* Length of last data block sent                  */
  129.    word  txblklen;        /* Size of data block to try to send this time     */
  130.    word  txblkmax;        /* Max size of data block to send at this speed    */
  131.    word  goodneeded;      /* # good bytes to send before upping txblklen     */
  132.    word  goodbytes;       /* Number of good bytes sent at this block size    */
  133.    word  rpos_count;      /* Number of RPOS packets sent at this position    */
  134.    long  xmit_retry;      /* Time to retransmit lost FNAMEPKT or EOF packet  */
  135.    long  txpos;           /* Current position within file we're sending      */
  136.    long  lasttx;          /* Position within file of last data block we sent */
  137.    long  starttime;       /* Time at which we started this Janus session     */
  138.    long  txstpos;         /* Initial data position of file we're sending     */
  139.    long  rxstpos;         /* Initial data position of file we're receiving   */
  140.    long  txoldpos;        /* Last transmission file position displayed       */
  141.    long  rxoldpos;        /* Last reception file position displayed          */
  142.    long  rpos_retry;      /* Time at which to retry RPOS packet              */
  143.    long  brain_dead;      /* Time at which to give up on other computer      */
  144.    long  rpos_sttime;     /* Time at which we started current RPOS sequence  */
  145.    long  last_rpostime;   /* Timetag of last RPOS which we performed         */
  146.    long  last_blkpos;     /* File position of last out-of-sequence BLKPKT    */
  147.    FILE *reqfile;         /* File handle for .REQ file                       */
  148.  
  149.  
  150.    set_prior (3);                               /* Time Critical             */
  151.    XON_DISABLE ();
  152.    if (un_attended && fullscreen)
  153.       {
  154.       clear_filetransfer ();
  155.       sb_show ();
  156.       }
  157.    else
  158.       {
  159.       set_xy (NULL);
  160.       Next_y = locate_y;
  161.       }
  162.    Tx_y = Rx_y = 0;
  163.    SharedCap = 0;
  164.    TotalBytes = 0;
  165.    (void) time ((time_t *) &starttime);
  166.  
  167.    /*------------------------------------------------------------------------*/
  168.    /* Allocate memory                                                        */
  169.    /*------------------------------------------------------------------------*/
  170.    Rxbuf = (char *) Txbuf + 4096 + 8;
  171.    Txfname = Rxfname = NULL;
  172.    if (((Txfname = malloc (PATHLEN)) == NULL)
  173.        || ((Rxfname = malloc (PATHLEN)) == NULL))
  174.       {
  175.       status_line (MSG_TXT (M_MEM_ERROR));
  176.       mdm_hangup ();
  177.       goto freemem;
  178.       }
  179.    Rxbufmax = (byte *) (Rxbuf + BUFMAX + 8);
  180.  
  181.    /*------------------------------------------------------------------------*/
  182.    /* Initialize file transmission variables                                 */
  183.    /*------------------------------------------------------------------------*/
  184.    tx_inhibit = FALSE;
  185.    last_rpostime = last_blkpos = lasttx = txstpos = rxstpos = xmit_retry = 0L;
  186.    TimeoutSecs = (unsigned int) (40960 / cur_baud.rate_value);
  187.    if (TimeoutSecs < 30)
  188.       TimeoutSecs = 30;
  189.    long_set_timer (&brain_dead, 120);
  190.    txblkmax = cur_baud.rate_value / 300 * 128;
  191.    if (txblkmax > BUFMAX)
  192.       txblkmax = BUFMAX;
  193.    txblklen = txblkmax;
  194.    goodbytes = goodneeded = 0;
  195.    Txfile = -1;
  196.    sending_req = fsent = FALSE;
  197.    xstate = XSENDFNAME;
  198.    getfname (INITIAL_XFER);
  199.  
  200.    /*------------------------------------------------------------------------*/
  201.    /* Initialize file reception variables                                    */
  202.    /*------------------------------------------------------------------------*/
  203.    holdname = HoldAreaNameMunge (&called_addr);
  204.    (void) sprintf (Abortlog_name, "%s%s.Z\0", holdname, Hex_Addr_Str (&called_addr));
  205.  
  206.    if ((Diskavail = zfree (CURRENT.sc_Inbound)) <= 0L)
  207.       Diskavail = 0x7FFFFFF;
  208.  
  209.    Rxbufptr = NULL;
  210.    rpos_retry = rpos_count = 0;
  211.    attempting_req = req_started = FALSE;
  212.    rstate = RRCVFNAME;
  213.  
  214.    /*------------------------------------------------------------------------*/
  215.    /* Send and/or receive stuff until we're done with both                   */
  216.    /*------------------------------------------------------------------------*/
  217.    do
  218.       {                                         /* while (xstate || rstate)  */
  219.  
  220.       /*---------------------------------------------------------------------*/
  221.       /* If nothing useful (i.e. sending or receiving good data block) has   */
  222.       /* happened within the last 2 minutes, give up in disgust              */
  223.       /*---------------------------------------------------------------------*/
  224.       if (long_time_gone (&brain_dead))
  225.          {
  226.          j_status (MSG_TXT (M_OTHER_DIED));     /* "He's dead, Jim." */
  227.          goto giveup;
  228.          }
  229.  
  230.       /*---------------------------------------------------------------------*/
  231.       /* If we're tired of waiting for an ACK, try again                     */
  232.       /*---------------------------------------------------------------------*/
  233.       if (xmit_retry)
  234.          {
  235.          if (long_time_gone (&xmit_retry))
  236.             {
  237.             j_message (Tx_y, MSG_TXT (M_TIMEOUT));
  238.             xmit_retry = 0L;
  239.  
  240.             switch (xstate)
  241.                {
  242.                case XRCVFNACK:
  243.                   xstate = XSENDFNAME;
  244.                   break;
  245.                case XRCVFRNAKACK:
  246.                   xstate = XSENDFREQNAK;
  247.                   break;
  248.                case XRCVEOFACK:
  249.                   errno = 0;
  250.                   if (lseek (Txfile, txpos = lasttx, SEEK_SET) == -1L)
  251.                      {
  252.                      (void) j_error (MSG_TXT (M_SEEK_MSG), Txfname);
  253.                      goto giveup;
  254.                      }
  255.                   xstate = XSENDBLK;
  256.                   break;
  257.                }
  258.             }
  259.          }
  260.  
  261.       /*---------------------------------------------------------------------*/
  262.       /* Transmit next part of file, if any                                  */
  263.       /*---------------------------------------------------------------------*/
  264.       switch (xstate)
  265.          {
  266.          case XSENDBLK:
  267.             if (tx_inhibit)
  268.                break;
  269.             *((long *) Txbuf) = lasttx = txpos;
  270.             errno = 0;
  271.             blklen = read (Txfile, Txbuf + sizeof (txpos), txblklen);
  272.             if (j_error (MSG_TXT (M_READ_MSG), Txfname))
  273.                goto giveup;
  274.             txpos += blklen;
  275.             sendpkt (Txbuf, sizeof (txpos) + blklen, BLKPKT);
  276.             update_status (&txpos, &txoldpos, Txlen - txpos, &txoldeta, Tx_y);
  277.             fsent = TRUE;
  278.             if (txpos >= Txlen || blklen < txblklen)
  279.                {
  280.                long_set_timer (&xmit_retry, TimeoutSecs);
  281.                xstate = XRCVEOFACK;
  282.                }
  283.             else
  284.                long_set_timer (&brain_dead, 120);
  285.  
  286.             if (txblklen < txblkmax && (goodbytes += txblklen) >= goodneeded)
  287.                {
  288.                txblklen <<= 1;
  289.                goodbytes = 0;
  290.                }
  291.             break;
  292.  
  293.          case XSENDFNAME:
  294.             blklen = (int) (strchr (strchr ((char *) Txbuf, '\0') + 1, '\0') - (char *) Txbuf) + 1;
  295.             Txbuf[blklen++] = OURCAP;
  296.             sendpkt (Txbuf, blklen, FNAMEPKT);
  297.             txoldpos = txoldeta = -1;
  298.             long_set_timer (&xmit_retry, TimeoutSecs);
  299.             xstate = XRCVFNACK;
  300.             break;
  301.  
  302.          case XSENDFREQNAK:
  303.             sendpkt (NULL, 0, FREQNAKPKT);
  304.             long_set_timer (&xmit_retry, TimeoutSecs);
  305.             xstate = XRCVFRNAKACK;
  306.             break;
  307.          }
  308.  
  309.       /*---------------------------------------------------------------------*/
  310.       /* Catch up on our reading; receive and handle all outstanding packets */
  311.       /*---------------------------------------------------------------------*/
  312.       while ((pkttype = rcvpkt ()) != 0)
  313.          {
  314.          if (pkttype != BADPKT)
  315.             long_set_timer (&brain_dead, 120);
  316.          switch (pkttype)
  317.             {
  318.  
  319.             /*---------------------------------------------------------------*/
  320.             /* File data block or munged block                               */
  321.             /*---------------------------------------------------------------*/
  322.             case BADPKT:
  323.             case BLKPKT:
  324.                if (rstate == RRCVBLK)
  325.                   {
  326.                   if (pkttype == BADPKT || *((long *) Rxbuf) != Rxpos)
  327.                      {
  328.                      if (pkttype == BLKPKT)
  329.                         {
  330.                         if (*((long *) Rxbuf) < last_blkpos)
  331.                            rpos_retry = rpos_count = 0;
  332.                         last_blkpos = *((long *) Rxbuf);
  333.                         }
  334.                      if (long_time_gone (&rpos_retry))
  335.                         {
  336.  
  337.                         /*---------------------------------------------------*/
  338.                         /* If we're the called machine, and we're trying to  */
  339.                         /* send stuff, and it seems to be screwing up our    */
  340.                         /* ability to receive stuff, maybe this connection   */
  341.                         /* just can't hack full-duplex.  Try waiting till    */
  342.                         /* the sending system finishes before sending our    */
  343.                         /* stuff to it                                       */
  344.                         /*---------------------------------------------------*/
  345.                         if (rpos_count > 4)
  346.                            {
  347.                            if (xstate && !isOriginator && !tx_inhibit)
  348.                               {
  349.                               tx_inhibit = TRUE;
  350.                               j_status (MSG_TXT (M_GOING_ONE_WAY));
  351.                               }
  352.                            rpos_count = 0;
  353.                            }
  354.                         if (++rpos_count == 1)
  355.                            (void) time ((time_t *) &rpos_sttime);
  356.                         j_message (Rx_y, MSG_TXT (M_J_BAD_PACKET), Rxpos);
  357.                         *((long *) Rxbuf) = Rxpos;
  358.                         *((long *) (Rxbuf + sizeof (Rxpos))) = rpos_sttime;
  359.                         sendpkt ((byte *) Rxbuf, sizeof (Rxpos) + sizeof (rpos_sttime), RPOSPKT);
  360.                         long_set_timer (&rpos_retry, TimeoutSecs / 2);
  361.                         }
  362.                      }
  363.                   else
  364.                      {
  365.                      last_blkpos = Rxpos;
  366.                      rpos_retry = rpos_count = 0;
  367.                      errno = 0;
  368.                      (void) write (Rxfile, Rxbuf + sizeof (Rxpos), Rxblklen -= sizeof (Rxpos));
  369.                      if (j_error (MSG_TXT (M_WRITE_MSG), Rxfname))
  370.                         goto giveup;
  371.                      Diskavail -= Rxblklen;
  372.                      Rxpos += Rxblklen;
  373.                      update_status (&Rxpos, &rxoldpos, Rxlen - Rxpos, &rxoldeta, Rx_y);
  374.                      if (Rxpos >= Rxlen)
  375.                         {
  376.                         rxclose (GOOD_XFER);
  377.                         Rxlen -= rxstpos;
  378.                         through (&Rxlen, &Rxsttime);
  379.                         j_status ("%s-J%s %s", MSG_TXT (M_FILE_RECEIVED), (SharedCap & CANCRC32) ? "/32" : " ", Rxfname);
  380.                         j_msgend (Rx_y);
  381.                         update_files (0);
  382.                         rstate = RRCVFNAME;
  383.                         }
  384.                      }
  385.                   }
  386.                if (rstate == RRCVFNAME)
  387.                   sendpkt (NULL, 0, EOFACKPKT);
  388.                break;
  389.  
  390.             /*---------------------------------------------------------------*/
  391.             /* Name and other data for next file to receive                  */
  392.             /*---------------------------------------------------------------*/
  393.             case FNAMEPKT:
  394.                if (rstate == RRCVFNAME)
  395.                   Rxpos = rxstpos = procfname ();
  396.                if (!Rxfname[0] && get_filereq (req_started))
  397.                   {
  398.                   sendpkt ((byte *) Rxbuf, strlen (Rxbuf) + 2, FREQPKT);
  399.                   attempting_req = TRUE;
  400.                   req_started = FALSE;
  401.                   }
  402.                else
  403.                   {
  404.                   if (attempting_req)
  405.                      {
  406.                      attempting_req = FALSE;
  407.                      req_started = TRUE;
  408.                      }
  409.                   *((long *) Rxbuf) = Rxpos;
  410.                   Rxbuf[sizeof (Rxpos)] = (char) SharedCap;
  411.                   sendpkt ((byte *) Rxbuf, sizeof (Rxpos) + 1, FNACKPKT);
  412.                   rxoldpos = rxoldeta = -1;
  413.                   if (Rxpos > -1)
  414.                      rstate = (byte) ((Rxfname[0]) ? RRCVBLK : RDONE);
  415.                   else
  416.                      j_status (MSG_TXT (M_REFUSING), Rxfname);
  417.                   if (!rstate)
  418.                      tx_inhibit = FALSE;
  419.                   if (!(xstate || rstate))
  420.                      goto breakout;
  421.                   }
  422.                break;
  423.  
  424.             /*---------------------------------------------------------------*/
  425.             /* ACK to filename packet we just sent                           */
  426.             /*---------------------------------------------------------------*/
  427.             case FNACKPKT:
  428.                if (xstate == XRCVFNACK)
  429.                   {
  430.                   xmit_retry = 0L;
  431.                   if (Txfname[0])
  432.                      {
  433.                      SharedCap = (byte) ((Rxblklen > sizeof (long)) ? Rxbuf[sizeof (long)] : 0);
  434.                      if ((txpos = *((long *) Rxbuf)) > -1L)
  435.                         {
  436.                         if (txpos)
  437.                            status_line (MSG_TXT (M_SYNCHRONIZING), txpos);
  438.                         errno = 0;
  439.                         if (lseek (Txfile, txstpos = txpos, SEEK_SET) == -1L)
  440.                            {
  441.                            (void) j_error (MSG_TXT (M_SEEK_MSG), Txfname);
  442.                            goto giveup;
  443.                            }
  444.                         xstate = XSENDBLK;
  445.                         }
  446.                      else
  447.                         {
  448.                         j_status (MSG_TXT (M_REMOTE_REFUSED), Txfname);
  449.                         if (sending_req)
  450.                            {
  451.                            if (!(sending_req = get_reqname (FALSE)))
  452.                               getfname (GOOD_XFER);
  453.                            }
  454.                         else
  455.                            {
  456.                            Do_after = NOTHING_AFTER;
  457.                            getfname (GOOD_XFER);
  458.                            }
  459.                         xstate = XSENDFNAME;
  460.                         }
  461.                      }
  462.                   else
  463.                      {
  464.                      sent_mail = 1;
  465.                      xstate = XDONE;
  466.                      }
  467.                   }
  468.                if (!(xstate || rstate))
  469.                   goto breakout;
  470.                break;
  471.  
  472.             /*---------------------------------------------------------------*/
  473.             /* Request to send more stuff rather than end batch just yet     */
  474.             /*---------------------------------------------------------------*/
  475.             case FREQPKT:
  476.                if (xstate == XRCVFNACK)
  477.                   {
  478.                   xmit_retry = 0L;
  479.                   SharedCap = *(strchr (Rxbuf, '\0') + 1);
  480.                   (void) sprintf ((char *) Txbuf, request_template, CURRENT.sc_Inbound,
  481.                                   Hex_Addr_Str (&(alias[0])));
  482.                   errno = 0;
  483.                   reqfile = fopen ((char *) Txbuf, "wt");
  484.                   if (reqfile != (FILE *) NULL)
  485.                      errno = 0;
  486.                   (void) j_error (MSG_TXT (M_OPEN_MSG), (char *) Txbuf);
  487.                   (void) fputs (Rxbuf, reqfile);
  488.                   (void) fputs ("\n", reqfile);
  489.                   (void) fclose (reqfile);
  490.                   (void) unlink (ReqTmp);
  491.                   ReqRecorded = 0;              /* counted by record_reqfile */
  492.                   (void) respond_to_file_requests (0, record_reqfile, timeof_reqfile);
  493.                   CURRENT.rq_Limit -= ReqRecorded;
  494.                   if ((sending_req = get_reqname (TRUE)) != 0)
  495.                      xstate = XSENDFNAME;
  496.                   else
  497.                      xstate = XSENDFREQNAK;
  498.                   }
  499.                break;
  500.  
  501.             /*---------------------------------------------------------------*/
  502.             /* Our last file request didn't match anything; move on to next  */
  503.             /*---------------------------------------------------------------*/
  504.             case FREQNAKPKT:
  505.                attempting_req = FALSE;
  506.                req_started = TRUE;
  507.                sendpkt (NULL, 0, FRNAKACKPKT);
  508.                break;
  509.  
  510.             /*---------------------------------------------------------------*/
  511.             /* ACK to no matching files for request error; try to end again  */
  512.             /*---------------------------------------------------------------*/
  513.             case FRNAKACKPKT:
  514.                if (xstate == XRCVFRNAKACK)
  515.                   {
  516.                   xmit_retry = 0L;
  517.                   getfname (GOOD_XFER);
  518.                   xstate = XSENDFNAME;
  519.                   }
  520.                break;
  521.  
  522.             /*---------------------------------------------------------------*/
  523.             /* ACK to last data block in file                                */
  524.             /*---------------------------------------------------------------*/
  525.             case EOFACKPKT:
  526.                if (xstate == XRCVEOFACK || xstate == XRCVFNACK)
  527.                   {
  528.                   xmit_retry = 0L;
  529.                   if (xstate == XRCVEOFACK)
  530.                      {
  531.                      Txlen -= txstpos;
  532.                      through (&Txlen, &Txsttime);
  533.                      j_status ("%s-J%s %s", MSG_TXT (M_FILE_SENT), (SharedCap & CANCRC32) ? "/32" : " ", Txfname);
  534.                      j_msgend (Tx_y);
  535.                      update_files (1);
  536.                      if (sending_req)
  537.                         {
  538.                         if (!(sending_req = get_reqname (FALSE)))
  539.                            getfname (GOOD_XFER);
  540.                         }
  541.                      else
  542.                         getfname (GOOD_XFER);
  543.                      }
  544.                   xstate = XSENDFNAME;
  545.                   }
  546.                break;
  547.  
  548.             /*---------------------------------------------------------------*/
  549.             /* Receiver says "let's try that again."                         */
  550.             /*---------------------------------------------------------------*/
  551.             case RPOSPKT:
  552.                if (xstate == XSENDBLK || xstate == XRCVEOFACK)
  553.                   {
  554.                   if (*((long *) (Rxbuf + sizeof (txpos))) != last_rpostime)
  555.                      {
  556.                      last_rpostime = *((long *) (Rxbuf + sizeof (txpos)));
  557.                      xmit_retry = 0L;
  558.                      CLEAR_OUTBOUND ();
  559.                      errno = 0;
  560.                      if (lseek (Txfile, txpos = lasttx = *((long *) Rxbuf), SEEK_SET) == -1L)
  561.                         {
  562.                         (void) j_error (MSG_TXT (M_SEEK_MSG), Txfname);
  563.                         goto giveup;
  564.                         }
  565.                      j_status (MSG_TXT (M_SYNCHRONIZING), txpos);
  566.                      txblklen >>= 2;
  567.                      if (txblklen < 64)
  568.                         txblklen = 64;
  569.                      goodbytes = 0;
  570.                      goodneeded += 1024;
  571.                      if (goodneeded > 8192)
  572.                         goodneeded = 8192;
  573.                      xstate = XSENDBLK;
  574.                      }
  575.                   }
  576.                break;
  577.  
  578.             /*---------------------------------------------------------------*/
  579.             /* Debris from end of previous Janus session; ignore it          */
  580.             /*---------------------------------------------------------------*/
  581.             case HALTACKPKT:
  582.                break;
  583.  
  584.             /*---------------------------------------------------------------*/
  585.             /* Abort the transfer and quit                                   */
  586.             /*---------------------------------------------------------------*/
  587.             default:
  588.                j_status (MSG_TXT (M_UNKNOWN_PACKET), pkttype);
  589.                /* fallthrough */
  590.             case HALTPKT:
  591. giveup:
  592.                j_status (MSG_TXT (M_SESSION_ABORT));
  593.                if (Txfname[0])
  594.                   getfname (ABORT_XFER);
  595.                if (rstate == RRCVBLK)
  596.                   {
  597.                   TotalBytes += (Rxpos - rxstpos);
  598.                   rxclose (FAILED_XFER);
  599.                   }
  600.                goto abortxfer;
  601.  
  602.             }                                   /* switch (pkttype)  */
  603.          }                                      /* while (pkttype)   */
  604.       } while (xstate || rstate);
  605.  
  606.    /*------------------------------------------------------------------------*/
  607.    /* All done; make sure other end is also finished (one way or another)    */
  608.    /*------------------------------------------------------------------------*/
  609. breakout:
  610.    if (!fsent)
  611.       j_status (MSG_TXT (M_NOTHING_TO_SEND), Full_Addr_Str (&called_addr));
  612. abortxfer:
  613.    through (&TotalBytes, &starttime);
  614.    endbatch ();
  615.  
  616.    /*------------------------------------------------------------------------*/
  617.    /* Release allocated memory                                               */
  618.    /*------------------------------------------------------------------------*/
  619. freemem:
  620.    if (Txfname)
  621.       free (Txfname);
  622.    if (Rxfname)
  623.       free (Rxfname);
  624.    set_prior (4);                               /* Always High                                     */
  625. }
  626.  
  627.  
  628.  
  629. /*****************************************************************************/
  630. /* Get name and info for next file to be transmitted, if any, and build      */
  631. /* FNAMEPKT.  Packet contents as per ZModem filename info packet, to allow   */
  632. /* use of same method of aborted-transfer recovery.  If there are no more    */
  633. /* files to be sent, build FNAMEPKT with null filename.  Also open file and  */
  634. /* set up for transmission.  Set Txfname, Txfile, Txlen.  Txbuf must not be  */
  635. /* modified until FNACKPKT is received.                                      */
  636. /*****************************************************************************/
  637. void getfname (word xfer_flag)
  638. {
  639.    static byte    floflag, bad_xfers;
  640.    static char    outboundname[PATHLEN];
  641.    static long    floname_pos;
  642.    static FILE   *flofile;
  643.    char          *holdname;
  644.  
  645.    register char *p;
  646.    int            i;
  647.    long           curr_pos;
  648.    struct stat    f;
  649.  
  650.    /*------------------------------------------------------------------------*/
  651.    /* Initialize static variables on first call of the batch                 */
  652.    /*------------------------------------------------------------------------*/
  653.    if (xfer_flag == INITIAL_XFER)
  654.       {
  655.       floflag = outboundname[0] = '\0';
  656.       flofile = NULL;
  657.       }
  658.    else
  659.    /*------------------------------------------------------------------------*/
  660.    /* If we were already sending a file, close it and clean up               */
  661.    /*------------------------------------------------------------------------*/
  662.    if (Txfile != -1)
  663.       {
  664.       errno = 0;
  665.       (void) close (Txfile);
  666.       Txfile = -1;
  667.       /*---------------------------------------------------------------------*/
  668.       /* If xfer completed, do post-xfer cleanup                             */
  669.       /*---------------------------------------------------------------------*/
  670.       if (xfer_flag == GOOD_XFER)
  671.          {
  672.          /*------------------------------------------------------------------*/
  673.          /* Perform post-xfer file massaging if neccessary                   */
  674.          /*------------------------------------------------------------------*/
  675.          switch (Do_after)
  676.             {
  677.             case DELETE_AFTER:
  678.             case SHOW_DELETE_AFTER:
  679.                j_status (MSG_TXT (M_UNLINKING_MSG), Txfname);
  680.                (void) unlink (Txfname);
  681.                break;
  682.             case TRUNC_AFTER:
  683.                j_status (MSG_TXT (M_TRUNC_MSG), Txfname);
  684.                Txfile = open (Txfname, O_TRUNC | O_RDWR, S_IREAD | S_IWRITE);
  685.                if (Txfile != -1)
  686.                   errno = 0;
  687.                (void) j_error (MSG_TXT (M_TRUNC_MSG), Txfname);
  688.                (void) close (Txfile);
  689.                Txfile = -1;
  690.             }
  691.          /*------------------------------------------------------------------*/
  692.          /* If processing .?LO file, flag filename as sent (name[0] = '~')   */
  693.          /*------------------------------------------------------------------*/
  694.    skipname:
  695.          if (floflag)
  696.             {
  697.             curr_pos = ftell (flofile);
  698.             if (curr_pos == -1L)
  699.                (void) j_error (MSG_TXT (M_SEEK_MSG), outboundname);
  700.             if (fseek (flofile, floname_pos, SEEK_SET) == -1L)
  701.                (void) j_error (MSG_TXT (M_SEEK_MSG), outboundname);
  702.             if (fputc (Txfname[0] = '~', flofile) != EOF)
  703.                errno = 0;
  704.             (void) j_error (MSG_TXT (M_WRITE_MSG), outboundname);
  705.             if (fseek (flofile, curr_pos, SEEK_SET) == -1L)
  706.                (void) j_error (MSG_TXT (M_SEEK_MSG), outboundname);
  707.             }
  708.          }
  709.       else
  710.          {
  711.    abort:
  712.          ++bad_xfers;
  713.          }
  714.       }
  715.  
  716.    /*------------------------------------------------------------------------*/
  717.    /* Find next file to be sent and build FNAMEPKT.  If reading .FLO-type    */
  718.    /* file get next entry from it; otherwise check for next .OUT/.FLO file   */
  719.    /*------------------------------------------------------------------------*/
  720.  
  721.    holdname = HoldAreaNameMunge (&called_addr);
  722.    if (!floflag)
  723.       {
  724.       /*---------------------------------------------------------------------*/
  725.       /* If first getfname() for this batch, init filename to .OUT           */
  726.       /*---------------------------------------------------------------------*/
  727.       if (!outboundname[0])
  728.          {
  729.          (void) sprintf (outboundname, "%s%s.OUT", holdname, Hex_Addr_Str (&called_addr));
  730.          *ext_flags = 'O';
  731.          }
  732.       /*---------------------------------------------------------------------*/
  733.       /* Increment outbound filename until match found or all checked        */
  734.       /* .OUT->.DUT->.CUT->.HUT->.FLO->.DLO->.CLO->.HLO->null name           */
  735.       /*---------------------------------------------------------------------*/
  736.       else
  737.          {
  738.    nxtout:
  739.          p = strchr (outboundname, '\0') - 3;
  740.          for (i = 0; i < NUM_FLAGS; ++i)
  741.             if (ext_flags[i] == *p)
  742.                break;
  743.          if (i < NUM_FLAGS - 1)
  744.             {
  745.             *p = ext_flags[i + 1];
  746. #ifndef JACK_DECKER
  747.             if (isOriginator && *p == 'H')
  748.                goto nxtout;
  749. #endif
  750.             }
  751.          else
  752.             {
  753.             /*---------------------------------------------------------------*/
  754.             /* Finished ?,D,C,H sequence; wrap .OUT->.FLO, or .FLO->done     */
  755.             /*---------------------------------------------------------------*/
  756.             if (!floflag)
  757.                {
  758.                *p++ = *ext_flags = 'F';
  759.                *p++ = 'L';
  760.                *p = 'O';
  761.                ++floflag;
  762.                }
  763.             else
  764.                outboundname[0] = Txfname[0] = Txbuf[0] = Txbuf[1] = floflag = '\0';
  765.             }
  766.          }
  767.       /*---------------------------------------------------------------------*/
  768.       /* Check potential outbound name; if file doesn't exist keep looking   */
  769.       /*---------------------------------------------------------------------*/
  770.       if (outboundname[0])
  771.          {
  772.          if (!dexists (outboundname))
  773.             goto nxtout;
  774.          if (floflag)
  775.             goto rdflo;
  776.          (void) strcpy (Txfname, outboundname);
  777.          /*------------------------------------------------------------------*/
  778.          /* Start FNAMEPKT using .PKT alias                                  */
  779.          /*------------------------------------------------------------------*/
  780.          invent_pkt_name ((char *) Txbuf);
  781.          Do_after = DELETE_AFTER;
  782.          }
  783.       /*---------------------------------------------------------------------*/
  784.       /* Read and process next entry from .?LO-type file                     */
  785.       /*---------------------------------------------------------------------*/
  786.       }
  787.    else
  788.       {
  789. rdflo:
  790.       /*---------------------------------------------------------------------*/
  791.       /* Open .?LO file for processing if neccessary                         */
  792.       /*---------------------------------------------------------------------*/
  793.       if (!flofile)
  794.          {
  795.          bad_xfers = 0;
  796.          errno = 0;
  797.          flofile = share_fopen (outboundname, "rb+", DENY_WRITE);
  798.          if (flofile == (FILE *) NULL)
  799.             {
  800.             j_error (MSG_TXT (M_OPEN_MSG), outboundname);
  801.             goto nxtout;
  802.             }
  803.          }
  804.       errno = 0;
  805.       floname_pos = ftell (flofile);
  806.       if (floname_pos == -1L)
  807.          (void) j_error (MSG_TXT (M_SEEK_MSG), outboundname);
  808.       if (fgets (p = Txfname, PATHLEN, flofile))
  809.          {
  810.          /*------------------------------------------------------------------*/
  811.          /* Got an attached file name; check for handling flags, fix up name */
  812.          /*------------------------------------------------------------------*/
  813.          while (*p > ' ')
  814.             ++p;
  815.          *p = '\0';
  816.          switch (Txfname[0])
  817.             {
  818.             case '\0':
  819.             case '~':
  820.             case ';':
  821.                goto rdflo;
  822.             case TRUNC_AFTER:
  823.             case DELETE_AFTER:
  824.             case SHOW_DELETE_AFTER:
  825.                Do_after = Txfname[0];
  826.                (void) strcpy (Txfname, Txfname + 1);
  827.                break;
  828.             default:
  829.                Do_after = NOTHING_AFTER;
  830.                break;
  831.             }
  832.          /*------------------------------------------------------------------*/
  833.          /* Start FNAMEPKT with simple filename                              */
  834.          /*------------------------------------------------------------------*/
  835.          while (p >= Txfname && *p != '\\' && *p != ':')
  836.             --p;
  837.          (void) strcpy ((char *) Txbuf, ++p);
  838.          }
  839.       else
  840.          {
  841.          /*------------------------------------------------------------------*/
  842.          /* Finished reading this .?LO file; clean up and look for another   */
  843.          /*------------------------------------------------------------------*/
  844.          errno = 0;
  845.          (void) fclose (flofile);
  846.          flofile = NULL;
  847.          if (!bad_xfers)
  848.             {
  849.             (void) unlink (outboundname);
  850.             }
  851.          goto nxtout;
  852.          }
  853.       }
  854.  
  855.    /*------------------------------------------------------------------------*/
  856.    /* If we managed to find a valid file to transmit, open it, finish        */
  857.    /* FNAMEPKT, and print nice message for the sysop.                        */
  858.    /*------------------------------------------------------------------------*/
  859.    if (Txfname[0])
  860.       {
  861.       if (xfer_flag == ABORT_XFER)
  862.          goto abort;
  863.       j_status (MSG_TXT (M_SENDING), Txfname);
  864.       errno = 0;
  865.       Txfile = share_open (Txfname, O_RDONLY | O_BINARY, DENY_WRITE);
  866.       if (Txfile != -1)
  867.          errno = 0;
  868.       if (j_error (MSG_TXT (M_OPEN_MSG), Txfname))
  869.          goto skipname;
  870.  
  871.  
  872.       if (isatty (Txfile))                      /* Check for character devices     */
  873.          {
  874.          (void) close (Txfile);                 /* return errors if it is the case */
  875.          errno = 1;
  876.          (void) j_error (MSG_TXT (M_DEVICE_MSG), Txfname);
  877.          goto skipname;
  878.          }
  879.  
  880.       (void) stat (Txfname, &f);
  881.       (void) sprintf (strchr ((char *) Txbuf, '\0') + 1, "%lu %lo %o", Txlen = f.st_size, f.st_mtime, f.st_mode);
  882.  
  883.       p = strchr (Txfname, '\0');
  884.       while (p >= Txfname && *p != ':' && *p != '\\')
  885.          --p;
  886.       if (!un_attended || !fullscreen)
  887.          Tx_y = Next_y;
  888.       else
  889.          Tx_y = 1;
  890.       xfer_summary (MSG_TXT (M_SEND), ++p, &Txlen, Tx_y);
  891.  
  892.       (void) time ((time_t *) &Txsttime);
  893.       }
  894. }
  895.  
  896.  
  897. /*****************************************************************************/
  898. /* Build and send a packet of any type.                                      */
  899. /* Packet structure is: PKTSTRT,contents,packet_type,PKTEND,crc              */
  900. /* CRC is computed from contents and packet_type only; if PKTSTRT or PKTEND  */
  901. /* get munged we'll never even find the CRC.                                 */
  902. /*****************************************************************************/
  903. void sendpkt (register byte * buf, int len, int type)
  904. {
  905.    register word crc;
  906.  
  907.    if ((SharedCap & CANCRC32) && type != FNAMEPKT)
  908.       sendpkt32 (buf, len, type);
  909.    else
  910.       {
  911.       BUFFER_BYTE (DLE);
  912.       BUFFER_BYTE (PKTSTRTCHR ^ 0x40);
  913.  
  914.       crc = 0;
  915.       while (--len >= 0)
  916.          {
  917.          txbyte (*buf);
  918.          crc = xcrc (crc, ((word) (*buf++)));
  919.          }
  920.  
  921.       BUFFER_BYTE ((byte) type);
  922.       crc = xcrc (crc, type);
  923.  
  924.       BUFFER_BYTE (DLE);
  925.       BUFFER_BYTE (PKTENDCHR ^ 0x40);
  926.  
  927.       txbyte ((byte) (crc >> 8));
  928.       txbyte ((byte) (crc & 0xFF));
  929.  
  930.       UNBUFFER_BYTES ();
  931.       }
  932. }
  933.  
  934.  
  935. /*****************************************************************************/
  936. /* Build and send a packet using 32-bit CRC; same as sendpkt in other ways   */
  937. /*****************************************************************************/
  938. void sendpkt32 (register byte * buf, register int len, int type)
  939. {
  940.    unsigned long crc32;
  941.  
  942.    BUFFER_BYTE (DLE);
  943.    BUFFER_BYTE (PKTSTRTCHR32 ^ 0x40);
  944.  
  945.    crc32 = 0xFFFFFFFF;
  946.    while (--len >= 0)
  947.       {
  948.       txbyte (*buf);
  949.       crc32 = Z_32UpdateCRC (((word) * buf), crc32);
  950.       ++buf;
  951.       }
  952.  
  953.    BUFFER_BYTE ((byte) type);
  954.    crc32 = Z_32UpdateCRC (type, crc32);
  955.  
  956.    BUFFER_BYTE (DLE);
  957.    BUFFER_BYTE (PKTENDCHR ^ 0x40);
  958.  
  959.    txbyte ((byte) (crc32 >> 24));
  960.    txbyte ((byte) ((crc32 >> 16) & 0xFF));
  961.    txbyte ((byte) ((crc32 >> 8) & 0xFF));
  962.    txbyte ((byte) (crc32 & 0xFF));
  963.  
  964.    UNBUFFER_BYTES ();
  965. }
  966.  
  967.  
  968.  
  969. /*****************************************************************************/
  970. /* Transmit cooked escaped byte(s) corresponding to raw input byte.  Escape  */
  971. /* DLE, XON, and XOFF using DLE prefix byte and ^ 0x40. Also escape          */
  972. /* CR-after-'@' to avoid Telenet/PC-Pursuit problems.                        */
  973. /*****************************************************************************/
  974. void txbyte (register byte c)
  975. {
  976.    static byte lastsent;
  977.  
  978.    switch (c)
  979.       {
  980.       case CR:
  981.          if (lastsent != '@')
  982.             goto sendit;
  983.          /* fallthrough */
  984.       case DLE:
  985.       case XON:
  986.       case XOFF:
  987.          BUFFER_BYTE (DLE);
  988.          c ^= 0x40;
  989.          /* fallthrough */
  990.       default:
  991.    sendit:BUFFER_BYTE (lastsent = c);
  992.       }
  993. }
  994.  
  995.  
  996. /*****************************************************************************/
  997. /* Process FNAMEPKT of file to be received.  Check for aborted-transfer      */
  998. /* recovery and solve filename collisions.    Check for enough disk space.   */
  999. /* Return initial file data position to start receiving at, or -1 if error   */
  1000. /* detected to abort file reception.  Set Rxfname, Rxlen, Rxfile.            */
  1001. /*****************************************************************************/
  1002. long procfname (void)
  1003. {
  1004.    register char *p;
  1005.    char           linebuf[128], *fileinfo, *badfname;
  1006.    long           filestart, bytes;
  1007.    FILE          *abortlog;
  1008.    struct stat    f;
  1009.    int            i;
  1010.  
  1011.    /*------------------------------------------------------------------------*/
  1012.    /* Initialize for file reception                                          */
  1013.    /*------------------------------------------------------------------------*/
  1014.    badfname = NULL;
  1015.    Rxfname[0] = Resume_WaZOO = 0;
  1016.  
  1017.    /*------------------------------------------------------------------------*/
  1018.    /* Save info on WaZOO transfer in case of abort                           */
  1019.    /*------------------------------------------------------------------------*/
  1020.    (void) strcpy (Resume_name, fancy_str (Rxbuf));
  1021.    fileinfo = strchr (Rxbuf, '\0') + 1;
  1022.    p = strchr (fileinfo, '\0') + 1;
  1023.    SharedCap = (byte) ((Rxblklen > p - Rxbuf) ? *p & OURCAP : 0);
  1024.  
  1025.    /*------------------------------------------------------------------------*/
  1026.    /* If this is a null FNAMEPKT, return OK immediately                      */
  1027.    /*------------------------------------------------------------------------*/
  1028.    if (!Rxbuf[0])
  1029.       return 0L;
  1030.  
  1031.    (void) strcpy (linebuf, Rxbuf);
  1032.    (void) strlwr (linebuf);
  1033.    p = check_netfile (linebuf);
  1034.    j_status ("#%s %s %s", MSG_TXT (M_RECEIVING), (p) ? p : " ", Rxbuf);
  1035.  
  1036.    /*------------------------------------------------------------------------*/
  1037.    /* Extract and validate filesize                                          */
  1038.    /*------------------------------------------------------------------------*/
  1039.    Rxlen = -1;
  1040.    Rxfiletime = 0;
  1041.    if (sscanf (fileinfo, "%ld %lo", &Rxlen, &Rxfiletime) < 1 || Rxlen < 0)
  1042.       {
  1043.       j_status (MSG_TXT (M_NO_LENGTH));
  1044.       return -1L;
  1045.       }
  1046.    (void) sprintf (Resume_info, "%ld %lo", Rxlen, Rxfiletime);
  1047.  
  1048.    /*------------------------------------------------------------------------*/
  1049.    /* Check if this is a failed WaZOO transfer which should be resumed       */
  1050.    /*------------------------------------------------------------------------*/
  1051.    if (dexists (Abortlog_name))
  1052.       {
  1053.       errno = 0;
  1054.       abortlog = fopen (Abortlog_name, read_ascii);
  1055.       if (abortlog != (FILE *) NULL)
  1056.          errno = 0;
  1057.       if (!j_error (MSG_TXT (M_OPEN_MSG), Abortlog_name))
  1058.          {
  1059.          while (!feof (abortlog))
  1060.             {
  1061.             linebuf[0] = '\0';
  1062.             if (!fgets (p = linebuf, sizeof (linebuf), abortlog))
  1063.                break;
  1064.             while (*p >= ' ')
  1065.                ++p;
  1066.             *p = '\0';
  1067.             p = strchr (linebuf, ' ');
  1068.             *p = '\0';
  1069.             if (!stricmp (linebuf, Resume_name))
  1070.                {
  1071.                p = strchr ((badfname = ++p), ' ');
  1072.                *p = '\0';
  1073.                if (!stricmp (++p, Resume_info))
  1074.                   {
  1075.                   ++Resume_WaZOO;
  1076.                   break;
  1077.                   }
  1078.                }
  1079.             }
  1080.          errno = 0;
  1081.          (void) fclose (abortlog);
  1082.          }
  1083.       }
  1084.  
  1085.    /*------------------------------------------------------------------------*/
  1086.    /* Open either the old or a new file, as appropriate                      */
  1087.    /*------------------------------------------------------------------------*/
  1088.    p = strchr (strcpy (Rxfname, CURRENT.sc_Inbound), '\0');
  1089.    errno = 0;
  1090.    if (Resume_WaZOO)
  1091.       {
  1092.       (void) strcpy (p, badfname);
  1093.       Rxfile = open (Rxfname, O_CREAT | O_RDWR | O_BINARY, S_IREAD | S_IWRITE);
  1094.       }
  1095.    else
  1096.       {
  1097.       (void) strcpy (p, Rxbuf);
  1098.       /*---------------------------------------------------------------------*/
  1099.       /* If the file already exists:                                         */
  1100.       /* 1) And the new file has the same time and size, skip it             */
  1101.       /* 2) And OVERWRITE is turned on, delete the old copy                  */
  1102.       /* 3) Else create a unique file name in which to store new data        */
  1103.       /*---------------------------------------------------------------------*/
  1104.       if (dexists (Rxfname))
  1105.          {
  1106.          (void) stat (Rxfname, &f);
  1107.          if (Rxlen == f.st_size && Rxfiletime == f.st_mtime)
  1108.             {
  1109.             j_status (MSG_TXT (M_ALREADY_HAVE), Rxfname);
  1110.             return -1L;
  1111.             }
  1112.          i = strlen (Rxfname) - 1;
  1113.          if ((!overwrite) || (is_arcmail (Rxfname, i)))
  1114.             {
  1115.             unique_name (Rxfname);
  1116.             j_status (MSG_TXT (M_RENAME_MSG), Rxfname);
  1117.             }
  1118.          else
  1119.             {
  1120.             (void) unlink (Rxfname);
  1121.             }
  1122.          }
  1123.       Rxfile = open (Rxfname, O_CREAT | O_EXCL | O_RDWR | O_BINARY, S_IREAD | S_IWRITE);
  1124.       }
  1125.    if (Rxfile != -1)
  1126.       errno = 0;
  1127.    if (j_error (MSG_TXT (M_OPEN_MSG), Rxfname))
  1128.       return -1L;
  1129.  
  1130.  
  1131.    if (isatty (Rxfile))                         /* Check for character devices     */
  1132.       {
  1133.       (void) close (Rxfile);                    /* Return errors if it is the case */
  1134.       errno = 1;
  1135.       (void) j_error (MSG_TXT (M_DEVICE_MSG), Rxfname);
  1136.       return -1L;
  1137.       }
  1138.  
  1139.  
  1140.    /*------------------------------------------------------------------------*/
  1141.    /* Determine initial file data position                                   */
  1142.    /*------------------------------------------------------------------------*/
  1143.    if (Resume_WaZOO)
  1144.       {
  1145.       (void) stat (Rxfname, &f);
  1146.       j_status (MSG_TXT (M_SYNCHRONIZING_OFFSET), filestart = f.st_size);
  1147.       p = Rxbuf;
  1148.       errno = 0;
  1149.       if (lseek (Rxfile, filestart, SEEK_SET) == -1L)
  1150.          {
  1151.          (void) j_error (MSG_TXT (M_SEEK_MSG), Rxfname);
  1152.          (void) close (Rxfile);
  1153.          return -1L;
  1154.          }
  1155.       }
  1156.    else
  1157.       filestart = 0L;
  1158.  
  1159.    /*------------------------------------------------------------------------*/
  1160.    /* Check for enough disk space                                            */
  1161.    /*------------------------------------------------------------------------*/
  1162.    bytes = Rxlen - filestart + 10240;
  1163.    if (bytes > Diskavail)
  1164.       {
  1165.       j_status (MSG_TXT (M_OUT_OF_DISK_SPACE));
  1166.       (void) close (Rxfile);
  1167.       return -1L;
  1168.       }
  1169.  
  1170.    /*------------------------------------------------------------------------*/
  1171.    /* Print status message for the sysop                                     */
  1172.    /*------------------------------------------------------------------------*/
  1173.    if (!un_attended || !fullscreen)
  1174.       Rx_y = Next_y;
  1175.    else
  1176.       Rx_y = 2;
  1177.    xfer_summary (MSG_TXT (M_RECV), p, &Rxlen, Rx_y);
  1178.  
  1179.    (void) time ((time_t *) &Rxsttime);
  1180.  
  1181.    return filestart;
  1182. }
  1183.  
  1184.  
  1185. /*****************************************************************************/
  1186. /* Receive, validate, and extract a packet if available.  If a complete      */
  1187. /* packet hasn't been received yet, receive and store as much of the next    */
  1188. /* packet as possible.    Each call to rcvpkt() will continue accumulating a */
  1189. /* packet until a complete packet has been received or an error is detected. */
  1190. /* Rxbuf must not be modified between calls to rcvpkt() if NOPKT is returned.*/
  1191. /* Returns type of packet received, NOPKT, or BADPKT.  Sets Rxblklen.        */
  1192. /*****************************************************************************/
  1193. byte rcvpkt ()
  1194. {
  1195.    static byte     rxcrc32;
  1196.    static word     crc;
  1197.    static unsigned long crc32;
  1198.    register byte  *p;
  1199.    register int    c;
  1200.    int             i;
  1201.    unsigned long   pktcrc;
  1202.  
  1203.    /*------------------------------------------------------------------------*/
  1204.    /* Abort transfer if operator pressed ESC                                 */
  1205.    /*------------------------------------------------------------------------*/
  1206.  
  1207.    if (got_ESC ())
  1208.       {
  1209.       j_status (GenericError, MSG_TXT (M_KBD_MSG));
  1210.       return HALTPKT;
  1211.       }
  1212.  
  1213.    /*------------------------------------------------------------------------*/
  1214.    /* If not accumulating packet yet, find start of next packet              */
  1215.    /*------------------------------------------------------------------------*/
  1216.    WaitFlag = FALSE;
  1217.    p = Rxbufptr;
  1218.    if (!p)
  1219.       {
  1220.       do
  1221.          c = rxbyte ();
  1222.       while (c >= 0 || c == PKTEND);
  1223.  
  1224.       switch (c)
  1225.          {
  1226.          case PKTSTRT:
  1227.             rxcrc32 = FALSE;
  1228.             p = (byte *) Rxbuf;
  1229.             crc = 0;
  1230.             break;
  1231.          case PKTSTRT32:
  1232.             rxcrc32 = TRUE;
  1233.             p = (byte *) Rxbuf;
  1234.             crc32 = 0xFFFFFFFF;
  1235.             break;
  1236.          case NOCARRIER:
  1237.             j_status (GenericError, &(MSG_TXT (M_NO_CARRIER)[1]));
  1238.             return HALTPKT;
  1239.          default:
  1240.             return NOPKT;
  1241.          }
  1242.       }
  1243.  
  1244.    /*------------------------------------------------------------------------*/
  1245.    /* Accumulate packet data until we empty buffer or find packet delimiter  */
  1246.    /*------------------------------------------------------------------------*/
  1247.    if (rxcrc32)
  1248.       {
  1249.       while ((c = rxbyte ()) >= 0 && p < Rxbufmax)
  1250.          {
  1251.          *p++ = (byte) c;
  1252.          crc32 = Z_32UpdateCRC (c, crc32);
  1253.          }
  1254.       }
  1255.    else
  1256.       {
  1257.       while ((c = rxbyte ()) >= 0 && p < Rxbufmax)
  1258.          {
  1259.          *p++ = (byte) c;
  1260.          crc = xcrc (crc, c);
  1261.          }
  1262.       }
  1263.  
  1264.    /*------------------------------------------------------------------------*/
  1265.    /* Handle whichever end-of-packet condition occurred                      */
  1266.    /*------------------------------------------------------------------------*/
  1267.    switch (c)
  1268.       {
  1269.       /*---------------------------------------------------------------------*/
  1270.       /* PKTEND found; verify valid CRC                                      */
  1271.       /*---------------------------------------------------------------------*/
  1272.       case PKTEND:
  1273.          WaitFlag = TRUE;
  1274.          pktcrc = 0;
  1275.          for (i = (rxcrc32) ? 4 : 2; i; --i)
  1276.             {
  1277.             if ((c = rxbyte ()) < 0)
  1278.                break;
  1279.             pktcrc = (pktcrc << 8) | c;
  1280.             }
  1281.          if (!i)
  1282.             {
  1283.             if ((rxcrc32 && pktcrc == crc32) || pktcrc == crc)
  1284.                {
  1285.                /*------------------------------------------------------------*/
  1286.                /* Good packet verified; compute packet data length and       */
  1287.                /* return packet type                                         */
  1288.                /*------------------------------------------------------------*/
  1289.                Rxbufptr = NULL;
  1290.                Rxblklen = (int) (--p - (byte *) Rxbuf);
  1291.                return *p;
  1292.                }
  1293.             }
  1294.          /* fallthrough */
  1295.  
  1296.       /*---------------------------------------------------------------------*/
  1297.       /* Bad CRC, carrier lost, or buffer overflow from munged PKTEND        */
  1298.       /*---------------------------------------------------------------------*/
  1299.       default:
  1300.          if (c == NOCARRIER)
  1301.             {
  1302.             j_status (GenericError, &(MSG_TXT (M_NO_CARRIER)[1]));
  1303.             return HALTPKT;
  1304.             }
  1305.          else
  1306.             {
  1307.             Rxbufptr = NULL;
  1308.             return BADPKT;
  1309.             }
  1310.  
  1311.       /*---------------------------------------------------------------------*/
  1312.       /* Emptied buffer; save partial packet and let sender do something     */
  1313.       /*---------------------------------------------------------------------*/
  1314.       case BUFEMPTY:
  1315.          time_release ();  /* Also give other tasks a chance */
  1316.          Rxbufptr = p;
  1317.          return NOPKT;
  1318.  
  1319.       /*---------------------------------------------------------------------*/
  1320.       /* PKTEND was trashed; discard partial packet and prep for next one    */
  1321.       /*---------------------------------------------------------------------*/
  1322.       case PKTSTRT:
  1323.          rxcrc32 = FALSE;
  1324.          Rxbufptr = (byte *) Rxbuf;
  1325.          crc = 0;
  1326.          return BADPKT;
  1327.  
  1328.       case PKTSTRT32:
  1329.          rxcrc32 = TRUE;
  1330.          Rxbufptr = (byte *) Rxbuf;
  1331.          crc32 = 0xFFFFFFFF;
  1332.          return BADPKT;
  1333.       }
  1334. }
  1335.  
  1336.  
  1337.  
  1338. /*****************************************************************************/
  1339. /* Close file being received and perform post-reception aborted-transfer     */
  1340. /* recovery cleanup if neccessary.                                           */
  1341. /*****************************************************************************/
  1342. void rxclose (word xfer_flag)
  1343. {
  1344.    register char *p;
  1345.    char           namebuf[PATHLEN], linebuf[128];
  1346.    byte           c;
  1347.    FILE          *abortlog, *newlog;
  1348.    struct utimbuf utimes;
  1349.  
  1350.    /*------------------------------------------------------------------------*/
  1351.    /* Close file we've been receiving                                        */
  1352.    /*------------------------------------------------------------------------*/
  1353.    errno = 0;
  1354.    (void) close (Rxfile);
  1355.    if (Rxfiletime)
  1356.       {
  1357.       utimes.UT_ACTIME = Rxfiletime;
  1358.       utimes.modtime = Rxfiletime;
  1359.       (void) utime (Rxfname, (UTIMBUF *) &utimes);
  1360.       }
  1361.  
  1362.    /*------------------------------------------------------------------------*/
  1363.    /* If we completed a previously-aborted transfer, kill log entry & rename */
  1364.    /*------------------------------------------------------------------------*/
  1365.    if (xfer_flag == GOOD_XFER && Resume_WaZOO)
  1366.       {
  1367.       abortlog = fopen (Abortlog_name, read_ascii);
  1368.       if (abortlog != (FILE *) NULL)
  1369.          errno = 0;
  1370.       if (!j_error (MSG_TXT (M_OPEN_MSG), Abortlog_name))
  1371.          {
  1372.          c = 0;
  1373.          (void) strcpy (strchr (strcpy (namebuf, Abortlog_name), '\0') - 1, "TMP");
  1374.          newlog = fopen (namebuf, write_ascii);
  1375.          if (newlog != (FILE *) NULL)
  1376.             errno = 0;
  1377.          if (!j_error (MSG_TXT (M_OPEN_MSG), namebuf))
  1378.             {
  1379.             while (!feof (abortlog))
  1380.                {
  1381.                linebuf[0] = '\0';
  1382.                if (!fgets (p = linebuf, sizeof (linebuf), abortlog))
  1383.                   break;
  1384.                while (*p > ' ')
  1385.                   ++p;
  1386.                *p = '\0';
  1387.                if (stricmp (linebuf, Resume_name))
  1388.                   {
  1389.                   *p = ' ';
  1390.                   (void) fputs (linebuf, newlog);
  1391.                   if (j_error (MSG_TXT (M_WRITE_MSG), namebuf))
  1392.                      break;
  1393.                   ++c;
  1394.                   }
  1395.                }
  1396.             errno = 0;
  1397.             (void) fclose (abortlog);
  1398.             (void) fclose (newlog);
  1399.             (void) unlink (Abortlog_name);
  1400.             if (c)
  1401.                {
  1402.                if (!rename (namebuf, Abortlog_name))
  1403.                   errno = 0;
  1404.                (void) j_error (MSG_TXT (M_RENAME_MSG), namebuf);
  1405.                }
  1406.             else
  1407.                {
  1408.                (void) unlink (namebuf);
  1409.                }
  1410.             }
  1411.          else
  1412.             {
  1413.             (void) fclose (abortlog);
  1414.             }
  1415.          }
  1416.       j_status (MSG_TXT (M_FINISHED_PART), Resume_name);
  1417.       unique_name (strcat (strcpy (namebuf, CURRENT.sc_Inbound), Resume_name));
  1418.       if (!rename (Rxfname, namebuf))
  1419.          {
  1420.          errno = 0;
  1421.          (void) strcpy (Rxfname, namebuf);
  1422.          }
  1423.       else
  1424.          (void) j_error (MSG_TXT (M_RENAME_MSG), Rxfname);
  1425.       /*------------------------------------------------------------------------*/
  1426.       /* If transfer failed and was not an attempted resumption, log for later  */
  1427.       /*------------------------------------------------------------------------*/
  1428.       }
  1429.    else
  1430.    if (xfer_flag == FAILED_XFER && !Resume_WaZOO)
  1431.       {
  1432.       j_status (MSG_TXT (M_SAVING_PART), Rxfname);
  1433.       unique_name (strcat (strcpy (namebuf, CURRENT.sc_Inbound), "BadWaZOO.001"));
  1434.       if (!rename (Rxfname, namebuf))
  1435.          errno = 0;
  1436.       (void) j_error (MSG_TXT (M_RENAME_MSG), Rxfname);
  1437.  
  1438.       abortlog = fopen (Abortlog_name, "at");
  1439.       if (abortlog != (FILE *) NULL)
  1440.          errno = 0;
  1441.       if (!j_error (MSG_TXT (M_OPEN_MSG), Abortlog_name))
  1442.          {
  1443.          (void) fprintf (abortlog, "%s %s %s\n", Resume_name, namebuf + strlen (CURRENT.sc_Inbound), Resume_info);
  1444.          (void) j_error (MSG_TXT (M_WRITE_MSG), Abortlog_name);
  1445.          (void) fclose (abortlog);
  1446.          }
  1447.       else
  1448.          {
  1449.          (void) unlink (namebuf);
  1450.          }
  1451.       }
  1452. }
  1453.  
  1454.  
  1455. /*****************************************************************************/
  1456. /* Try REAL HARD to disengage batch session cleanly                          */
  1457. /*****************************************************************************/
  1458. void endbatch (void)
  1459. {
  1460.    register int done, timeouts;
  1461.    long         timeval, brain_dead;
  1462.  
  1463.    /*------------------------------------------------------------------------*/
  1464.    /* Tell the other end to halt if it hasn't already                        */
  1465.    /*------------------------------------------------------------------------*/
  1466.    done = timeouts = 0;
  1467.    long_set_timer (&brain_dead, 120);
  1468.    sendpkt (NULL, 0, HALTPKT);
  1469.    long_set_timer (&timeval, TimeoutSecs);
  1470.  
  1471.    /*------------------------------------------------------------------------*/
  1472.    /* Wait for the other end to acknowledge that it's halting                */
  1473.    /*------------------------------------------------------------------------*/
  1474.    while (!done)
  1475.       {
  1476.       if (long_time_gone (&brain_dead))
  1477.          break;
  1478.  
  1479.       switch (rcvpkt ())
  1480.          {
  1481.          case NOPKT:
  1482.          case BADPKT:
  1483.             if (long_time_gone (&timeval))
  1484.                {
  1485.                if (++timeouts > 2)
  1486.                   ++done;
  1487.                else
  1488.                   goto reject;
  1489.                }
  1490.             break;
  1491.  
  1492.          case HALTPKT:
  1493.          case HALTACKPKT:
  1494.             ++done;
  1495.             break;
  1496.  
  1497.          default:
  1498.             timeouts = 0;
  1499.       reject:sendpkt (NULL, 0, HALTPKT);
  1500.             long_set_timer (&timeval, TimeoutSecs);
  1501.             break;
  1502.          }
  1503.       }
  1504.  
  1505.    /*------------------------------------------------------------------------*/
  1506.    /* Announce quite insistently that we're done now                         */
  1507.    /*------------------------------------------------------------------------*/
  1508.    for (done = 0; done < 10; ++done)
  1509.       sendpkt (NULL, 0, HALTACKPKT);
  1510.  
  1511.    wait_for_clear ();
  1512. }
  1513.  
  1514.  
  1515. /*****************************************************************************/
  1516. /* Print a message in the message field of a transfer status line            */
  1517. /*****************************************************************************/
  1518. void j_message (word pos, char *va_alist,...)
  1519. {
  1520.    va_list arg_ptr;
  1521.    int     y, l;
  1522.  
  1523. #ifdef MILQ
  1524.    int     Ln = FILE_LN_1;
  1525.  
  1526. #endif
  1527.  
  1528.    char    buf[128];
  1529.  
  1530.    y = pos;
  1531.    va_start (arg_ptr, va_alist);
  1532.  
  1533. #ifndef MILQ
  1534.    if (!un_attended || !fullscreen)
  1535.       gotoxy (MSG_X, y);
  1536.    else
  1537.       sb_move (file_hWnd, y, MSG_X);
  1538. #endif
  1539.  
  1540.    (void) vsprintf (buf, va_alist, arg_ptr);
  1541.  
  1542.    for (l = 25 - strlen (buf); l > 0; --l)
  1543.       (void) strcat (buf, " ");
  1544.  
  1545. #ifdef MILQ
  1546.    if (un_attended)
  1547.       {
  1548.       if (2 == y)
  1549.          Ln = FILE_LN_2;
  1550.       FlLnModeSet (Ln, 0);
  1551.       sb_puts (GetDlgItem (file_hWnd, Ln + GD_STATUS), buf);
  1552. #else
  1553.    if (!un_attended || !fullscreen)
  1554.       {
  1555.       (void) cputs (buf);
  1556.       }
  1557.    else
  1558.       {
  1559.       sb_puts (file_hWnd, buf);
  1560. #endif
  1561.       sb_show ();
  1562.       }
  1563.  
  1564.    va_end (arg_ptr);
  1565. }
  1566.  
  1567.  
  1568. /*****************************************************************************/
  1569. /* Clear out a line in the log status display                                */
  1570. /*****************************************************************************/
  1571.  
  1572. void j_msgend (word pos)
  1573. {
  1574.  
  1575.    if (un_attended && fullscreen)
  1576.       {
  1577.       sb_move (file_hWnd, pos, 2);
  1578. #ifndef MILQ
  1579.       /* 72 blanks */
  1580.       sb_puts (file_hWnd, "                                                                        ");
  1581. #else
  1582.       sb_puts (GetDlgItem (file_hWnd, FILE_LN_2), "");
  1583. #endif
  1584.       sb_show ();
  1585.       }
  1586. }
  1587.  
  1588.  
  1589. /*****************************************************************************/
  1590. /* Print & log status message without messing up display                     */
  1591. /*****************************************************************************/
  1592. void j_status (char *va_alist,...)
  1593. {
  1594.    va_list arg_ptr;
  1595.  
  1596.    char    buf[128];
  1597.  
  1598.    va_start (arg_ptr, va_alist);
  1599.  
  1600. #ifndef MILQ
  1601.    if (!un_attended || !fullscreen)
  1602.       gotoxy (1, Next_y - 1);
  1603. #endif
  1604.  
  1605.    (void) vsprintf (buf, va_alist, arg_ptr);
  1606.  
  1607.    status_line (buf);
  1608.  
  1609.    if (!un_attended || !fullscreen)
  1610.       update_y ();
  1611.  
  1612.    va_end (arg_ptr);
  1613. }
  1614.  
  1615.  
  1616. /*****************************************************************************/
  1617. /* Print & log error message without messing up display                      */
  1618. /*****************************************************************************/
  1619. int j_error (char *msg, char *fname)
  1620. {
  1621.    register int e;
  1622.  
  1623.    if ((e = (int) errno) != 0)
  1624.       {
  1625.  
  1626. #ifndef MILQ
  1627.       if (!un_attended || !fullscreen)
  1628.          gotoxy (1, Next_y - 1);
  1629. #endif
  1630.  
  1631.       (void) got_error (msg, fname);
  1632.  
  1633.       if (!un_attended || !fullscreen)
  1634.          update_y ();
  1635.       }
  1636.    return e;
  1637. }
  1638.  
  1639.  
  1640. /*****************************************************************************/
  1641. /* Update screen position variables after printing a message                 */
  1642. /*****************************************************************************/
  1643. void update_y ()
  1644. {
  1645.  
  1646.    set_xy (NULL);               /* Bump cursor to next line after printing   */
  1647.    if (locate_y == Next_y)
  1648.       {                         /* If we didn't go anywhere, screen scrolled;*/
  1649.       if (Tx_y > 1)             /* so decrement status line numbers          */
  1650.          --Tx_y;
  1651.       if (Rx_y > 1)
  1652.          --Rx_y;
  1653.       }
  1654.    else
  1655.       Next_y = locate_y;
  1656. }
  1657.  
  1658.  
  1659. /*****************************************************************************/
  1660. /* Compute future timehack for later reference                               */
  1661. /*****************************************************************************/
  1662. void long_set_timer (long *Buffer, word Duration)
  1663. {
  1664.  
  1665.    (void) time ((time_t *) Buffer);
  1666.    *Buffer += (long) Duration;
  1667. }
  1668.  
  1669.  
  1670. /*****************************************************************************/
  1671. /* Return TRUE if timehack has been passed, FALSE if not                     */
  1672. /*****************************************************************************/
  1673. int long_time_gone (long *TimePtr)
  1674. {
  1675.  
  1676.    return (time (NULL) > *TimePtr);
  1677. }
  1678.  
  1679.  
  1680. /*****************************************************************************/
  1681. /* Receive cooked escaped byte translated to avoid various problems.         */
  1682. /* Returns raw byte, BUFEMPTY, PKTSTRT, PKTEND, or NOCARRIER.                */
  1683. /*****************************************************************************/
  1684. int rxbyte (void)
  1685. {
  1686.    register int c, w;
  1687.  
  1688.    if ((c = rcvrawbyte ()) == DLE)
  1689.       {
  1690.       w = WaitFlag++;
  1691.       if ((c = rcvrawbyte ()) >= 0)
  1692.          {
  1693.          switch (c ^= 0x40)
  1694.             {
  1695.             case PKTSTRTCHR:
  1696.                c = PKTSTRT;
  1697.                break;
  1698.             case PKTSTRTCHR32:
  1699.                c = PKTSTRT32;
  1700.                break;
  1701.             case PKTENDCHR:
  1702.                c = PKTEND;
  1703.                break;
  1704.             }
  1705.          }
  1706.       WaitFlag = (byte) w;
  1707.       }
  1708.    return c;
  1709. }
  1710.  
  1711.  
  1712. /*****************************************************************************/
  1713. /* Receive raw non-escaped byte.  Returns byte, BUFEMPTY, or NOCARRIER.      */
  1714. /* If waitflag is true, will wait for a byte for Timeoutsecs; otherwise      */
  1715. /* will return BUFEMPTY if a byte isn't ready and waiting in inbound buffer. */
  1716. /*****************************************************************************/
  1717. int rcvrawbyte (void)
  1718. {
  1719.    long timeval;
  1720.  
  1721.    if ((int) PEEKBYTE () >= 0)
  1722.       return MODEM_IN ();
  1723.  
  1724.    if (!CARRIER)
  1725.       return NOCARRIER;
  1726.    if (!WaitFlag)
  1727.       return BUFEMPTY;
  1728.  
  1729.    timeval = time (NULL) + TimeoutSecs;
  1730.  
  1731.    while ((int) PEEKBYTE () < 0)
  1732.       {
  1733.       if (!CARRIER)
  1734.          return NOCARRIER;
  1735.       if (time (NULL) > timeval)
  1736.          return BUFEMPTY;
  1737.       time_release ();
  1738.       }
  1739.  
  1740.    return MODEM_IN ();
  1741. }
  1742.  
  1743.  
  1744. /*****************************************************************************/
  1745. /* Display start-of-transfer summary info                                    */
  1746. /*****************************************************************************/
  1747. void xfer_summary (char *xfertype, char *fname, long *len, int y)
  1748. {
  1749.    char buf[128];
  1750.  
  1751. #ifdef MILQ
  1752.    int  FlLn = FILE_LN_1;
  1753.  
  1754.    if (2 == y)
  1755.       FlLn = FILE_LN_2;
  1756.    FlLnModeSet (FlLn, 1);
  1757. #endif
  1758.  
  1759. #ifndef MILQ
  1760.    if (!un_attended || !fullscreen)
  1761.       gotoxy (2, y);
  1762.    else
  1763.       sb_move (file_hWnd, y, 2);
  1764.  
  1765.    (void) sprintf (buf, "%s %12.12s;        0/%8ldb,%4d min.                       ",
  1766.                    xfertype, fname, *len, (int) ((*len * 10 / cur_baud.rate_value * 100 / JANUS_EFFICIENCY + 59) / 60));
  1767. #endif
  1768.  
  1769.    if (!un_attended || !fullscreen)
  1770.       {
  1771. #ifndef MILQ
  1772.       (void) cputs (buf);
  1773.       (void) cputs (local_CEOL);
  1774. #endif
  1775.       update_y ();
  1776.       }
  1777.    else
  1778.       {
  1779. #ifndef MILQ
  1780.       sb_puts (file_hWnd, buf);
  1781. #else
  1782.       (void) sprintf (buf, "%s %12.12s",
  1783.                       xfertype, fname);
  1784.       sb_puts (GetDlgItem (file_hWnd, FlLn), buf);
  1785.       sb_puts (GetDlgItem (file_hWnd, FlLn + GD_TOTAL), "       0");
  1786.       sb_puts (GetDlgItem (file_hWnd, FlLn + GD_STATUS), "");
  1787.       (void) sprintf (buf, "%8ld", *len);
  1788.       sb_puts (GetDlgItem (file_hWnd, FlLn + GD_SIZE), buf);
  1789. #endif
  1790.       sb_show ();
  1791.       }
  1792. }
  1793.  
  1794.  
  1795. /*****************************************************************************/
  1796. /* Update any status line values which have changed                          */
  1797. /*****************************************************************************/
  1798. void            update_status (long *pos, long *oldpos, long left, int *oldeta, int y)
  1799. {
  1800.    char         buf[16];
  1801.    register int eta;
  1802.  
  1803. #ifdef MILQ
  1804.    int          Ln = FILE_LN_1;
  1805.  
  1806.    if (2 == y)
  1807.       Ln = FILE_LN_2;
  1808.    FlLnModeSet (Ln, 1);
  1809. #endif
  1810.  
  1811.    elapse_time ();
  1812.  
  1813.    if (*pos != *oldpos)
  1814.       {
  1815.       (void) sprintf (buf, "%8ld", *oldpos = *pos);
  1816. #ifndef MILQ
  1817.       if (!un_attended || !fullscreen)
  1818.          {
  1819.          gotoxy (POS_X, y);
  1820.          (void) cputs (buf);
  1821.          }
  1822.       else
  1823.          {
  1824.          sb_move (file_hWnd, y, POS_X);
  1825.          sb_puts (file_hWnd, buf);
  1826.          }
  1827. #else
  1828.       sb_puts (GetDlgItem (file_hWnd, Ln + GD_TOTAL), buf);
  1829. #endif
  1830.       }
  1831.  
  1832.    eta = (int) ((left * 10 / cur_baud.rate_value * 100 / JANUS_EFFICIENCY + 59) / 60);
  1833.    if (eta != *oldeta)
  1834.       {
  1835.       (void) sprintf (buf, "%4d Min", *oldeta = eta);
  1836.  
  1837. #ifndef MILQ
  1838.       if (!un_attended || !fullscreen)
  1839.          {
  1840.          gotoxy (ETA_X, y);
  1841.          (void) cputs (buf);
  1842.          }
  1843.       else
  1844.          {
  1845.          sb_move (file_hWnd, y, ETA_X);
  1846.          sb_puts (file_hWnd, buf);
  1847.          }
  1848. #else
  1849.       sb_puts (GetDlgItem (file_hWnd, Ln + GD_DTTM), buf);
  1850. #endif
  1851.       }
  1852.  
  1853.    if (un_attended && fullscreen)
  1854.       sb_show ();
  1855. }
  1856.  
  1857. /*****************************************************************************/
  1858. /* Compute and print throughput                                              */
  1859. /*****************************************************************************/
  1860. void through (long *bytes, long *started)
  1861. {
  1862.    static char   *scrn = "+CPS: %u (%lu bytes)  Efficiency: %lu%%%%";
  1863.    unsigned long  elapsed;
  1864.    register word  cps;
  1865.  
  1866.    elapsed = time (NULL) - *started;
  1867.    cps = (elapsed) ? (word) (*bytes / elapsed) : 0;
  1868.    j_status (scrn, cps, *bytes, cps * 1000L / cur_baud.rate_value);
  1869.    TotalBytes += *bytes;
  1870. }
  1871.  
  1872.  
  1873. /*****************************************************************************/
  1874. /* Get next file to request, if any                                          */
  1875. /*****************************************************************************/
  1876. int get_filereq (byte req_started)
  1877. {
  1878.    char           reqname[PATHLEN], linebuf[128];
  1879.    register char *p;
  1880.    int            gotone = FALSE;
  1881.    FILE          *reqfile;
  1882.  
  1883.    (void) strcpy (reqname, Abortlog_name);
  1884.    (void) strcpy (strchr (reqname, 'Z'), "REQ");
  1885.  
  1886.    if (req_started)
  1887.       mark_done (reqname);
  1888.  
  1889.    if (dexists (reqname))
  1890.       {
  1891.       if (!(remote_capabilities & WZ_FREQ))
  1892.          j_status (MSG_TXT (M_FREQ_DECLINED));
  1893.       else
  1894.       if (!(SharedCap & CANFREQ))
  1895.          j_status (MSG_TXT (M_REMOTE_CANT_FREQ));
  1896.       else
  1897.          {
  1898.          errno = 0;
  1899.          reqfile = fopen (reqname, read_ascii);
  1900.          if (reqfile != (FILE *) NULL)
  1901.             errno = 0;
  1902.          if (!j_error (MSG_TXT (M_OPEN_MSG), reqname))
  1903.             {
  1904.             while (!feof (reqfile))
  1905.                {
  1906.                linebuf[0] = '\0';
  1907.                if (!fgets (p = linebuf, sizeof (linebuf), reqfile))
  1908.                   break;
  1909.                while (*p >= ' ')
  1910.                   ++p;
  1911.                *p = '\0';
  1912.                if (linebuf[0] != ';')
  1913.                   {
  1914.                   (void) strcpy (Rxbuf, linebuf);
  1915.                   *(strchr (Rxbuf, '\0') + 1) = SharedCap;
  1916.                   gotone = TRUE;
  1917.                   break;
  1918.                   }
  1919.                }
  1920.             errno = 0;
  1921.             (void) fclose (reqfile);
  1922.             if (!gotone)
  1923.                {
  1924.                (void) unlink (reqname);
  1925.                }
  1926.             }
  1927.          }
  1928.       }
  1929.  
  1930.    return gotone;
  1931. }
  1932.  
  1933.  
  1934. /*****************************************************************************/
  1935. /* Record names of files to send in response to file request; callback       */
  1936. /* routine for respond_to_file_requests()                                    */
  1937. /*****************************************************************************/
  1938. int record_reqfile (char *fname)
  1939. {
  1940.    FILE *tmpfile;
  1941.  
  1942.    errno = 0;
  1943.    tmpfile = fopen (ReqTmp, "at");
  1944.    if (tmpfile != (FILE *) NULL)
  1945.       errno = 0;
  1946.    if (!j_error (MSG_TXT (M_OPEN_MSG), ReqTmp))
  1947.       {
  1948.       (void) fputs (fname, tmpfile);
  1949.       (void) j_error (MSG_TXT (M_WRITE_MSG), ReqTmp);
  1950.       (void) fputs ("\n", tmpfile);
  1951.       (void) j_error (MSG_TXT (M_WRITE_MSG), ReqTmp);
  1952.       (void) fclose (tmpfile);
  1953.       ++ReqRecorded;
  1954.       return TRUE;
  1955.       }
  1956.    return FALSE;
  1957. }
  1958.  
  1959. /*****************************************************************************/
  1960. /* Estimate transfer time for requested file(s); callback                    */
  1961. /* routine for respond_to_file_requests()                                    */
  1962. /*****************************************************************************/
  1963. int timeof_reqfile (long filesize)
  1964. {
  1965.    int i;
  1966.  
  1967.    i = (int) (filesize * 10 / cur_baud.rate_value * 100 / JANUS_EFFICIENCY);
  1968.  
  1969.    /*
  1970.     * Since actual transfers don't occur while in file request code, we have to "reverse engineer" the testing for end-time. 
  1971.     */
  1972.  
  1973.    if (CURRENT.time_Limit != 0)
  1974.       {
  1975.       if (((long) time (NULL) + i - freq_accum.time) > CURRENT.time_Limit)
  1976.          return i;
  1977.       freq_accum.time -= i;                     /* Add time to (now-start) interval */
  1978.       return 0;
  1979.       }
  1980.    return i;
  1981. }
  1982.  
  1983. /*****************************************************************************/
  1984. /* Get next file which was requested, if any                                 */
  1985. /*****************************************************************************/
  1986. byte get_reqname (byte first_req)
  1987. {
  1988.    register char *p;
  1989.    byte           gotone = FALSE;
  1990.    FILE          *tmpfile;
  1991.    struct stat    f;
  1992.  
  1993.    if (!first_req)
  1994.       {
  1995.       errno = 0;
  1996.       (void) close (Txfile);
  1997.       Txfile = -1;
  1998.       mark_done (ReqTmp);
  1999.       }
  2000.  
  2001.    if (dexists (ReqTmp))
  2002.       {
  2003.       errno = 0;
  2004.       tmpfile = fopen (ReqTmp, read_ascii);
  2005.       if (tmpfile != (FILE *) NULL)
  2006.          errno = 0;
  2007.       if (!j_error (MSG_TXT (M_OPEN_MSG), ReqTmp))
  2008.          {
  2009.          while (!feof (tmpfile))
  2010.             {
  2011.             Txfname[0] = '\0';
  2012.             if (!fgets (p = Txfname, PATHLEN, tmpfile))
  2013.                break;
  2014.             while (*p >= ' ')
  2015.                ++p;
  2016.             *p = '\0';
  2017.             if (Txfname[0] != ';')
  2018.                {
  2019.                j_status (MSG_TXT (M_SENDING), Txfname);
  2020.                errno = 0;
  2021.                Txfile = share_open (Txfname, O_RDONLY | O_BINARY, DENY_WRITE);
  2022.                if (Txfile != -1)
  2023.                   errno = 0;
  2024.                if (j_error (MSG_TXT (M_OPEN_MSG), Txfname))
  2025.                   continue;
  2026.                while (p >= Txfname && *p != '\\' && *p != ':')
  2027.                   --p;
  2028.                (void) strcpy ((char *) Txbuf, ++p);
  2029.                (void) stat (Txfname, &f);
  2030.                (void) sprintf (strchr ((char *) Txbuf, '\0') + 1, "%lu %lo %o", Txlen = f.st_size, f.st_mtime, f.st_mode);
  2031.                if (!un_attended || !fullscreen)
  2032.                   Tx_y = Next_y;
  2033.                else
  2034.                   Tx_y = 1;
  2035.                xfer_summary (MSG_TXT (M_SEND), p, &Txlen, Tx_y);
  2036.                (void) time ((time_t *) &Txsttime);
  2037.                gotone = TRUE;
  2038.                break;
  2039.                }
  2040.             }
  2041.          (void) fclose (tmpfile);
  2042.          if (!gotone)
  2043.             {
  2044.             (void) unlink (ReqTmp);
  2045.             }
  2046.          }
  2047.       }
  2048.  
  2049.    return gotone;
  2050. }
  2051.  
  2052.  
  2053. /*****************************************************************************/
  2054. /* Mark first unmarked line of file as done (comment it out)                 */
  2055. /*****************************************************************************/
  2056. void mark_done (char *fname)
  2057. {
  2058.    char  linebuf[128];
  2059.    FILE *fh;
  2060.    long  pos;
  2061.  
  2062.    if (dexists (fname))
  2063.       {
  2064.       errno = 0;
  2065.       fh = fopen (fname, "rb+");
  2066.       if (fh != (FILE *) NULL)
  2067.          errno = 0;
  2068.       if (!j_error (MSG_TXT (M_OPEN_MSG), fname))
  2069.          {
  2070.          while (!feof (fh))
  2071.             {
  2072.             pos = ftell (fh);
  2073.             if (pos == -1L)
  2074.                (void) j_error (MSG_TXT (M_SEEK_MSG), fname);
  2075.             if (!fgets (linebuf, sizeof (linebuf), fh))
  2076.                break;
  2077.             if (linebuf[0] != ';')
  2078.                {
  2079.                if (fseek (fh, pos, SEEK_SET) == -1L)
  2080.                   (void) j_error (MSG_TXT (M_SEEK_MSG), fname);
  2081.                (void) fputc (';', fh);
  2082.                (void) j_error (MSG_TXT (M_WRITE_MSG), fname);
  2083.                break;
  2084.                }
  2085.             }
  2086.          (void) fclose (fh);
  2087.          }
  2088.       }
  2089. }
  2090.  
  2091.