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