home *** CD-ROM | disk | FTP | other *** search
- /*--------------------------------------------------------------------------*/
- /* */
- /* */
- /* ------------ Bit-Bucket Software, Co. */
- /* \ 10001101 / Writers and Distributors of */
- /* \ 011110 / Freely Available<tm> Software. */
- /* \ 1011 / */
- /* ------ */
- /* */
- /* (C) Copyright 1987-90, Bit Bucket Software Co., a Delaware Corporation. */
- /* */
- /* */
- /* BinkleyTerm Janus revision 0.31, 11- 2-89 */
- /* Full-duplex WaZOO file transfer protocol */
- /* */
- /* */
- /* For complete details of the licensing restrictions, please refer */
- /* to the License agreement, which is published in its entirety in */
- /* the MAKEFILE and BT.C, and also contained in the file LICENSE.240. */
- /* */
- /* USE OF THIS FILE IS SUBJECT TO THE RESTRICTIONS CONTAINED IN THE */
- /* BINKLEYTERM LICENSING AGREEMENT. IF YOU DO NOT FIND THE TEXT OF */
- /* THIS AGREEMENT IN ANY OF THE AFOREMENTIONED FILES, OR IF YOU DO */
- /* NOT HAVE THESE FILES, YOU SHOULD IMMEDIATELY CONTACT BIT BUCKET */
- /* SOFTWARE CO. AT ONE OF THE ADDRESSES LISTED BELOW. IN NO EVENT */
- /* SHOULD YOU PROCEED TO USE THIS FILE WITHOUT HAVING ACCEPTED THE */
- /* TERMS OF THE BINKLEYTERM LICENSING AGREEMENT, OR SUCH OTHER */
- /* AGREEMENT AS YOU ARE ABLE TO REACH WITH BIT BUCKET SOFTWARE, CO. */
- /* */
- /* */
- /* You can contact Bit Bucket Software Co. at any one of the following */
- /* addresses: */
- /* */
- /* Bit Bucket Software Co. FidoNet 1:104/501, 1:132/491, 1:141/491 */
- /* P.O. Box 460398 AlterNet 7:491/0 */
- /* Aurora, CO 80046 BBS-Net 86:2030/1 */
- /* Internet f491.n132.z1.fidonet.org */
- /* */
- /* Please feel free to contact us at any time to share your comments about */
- /* our software and/or licensing policies. */
- /* */
- /*--------------------------------------------------------------------------*/
-
- #define WAZOO_SECTION
- #include <sys\types.h>
- #include <sys\stat.h>
- #include <stdio.h>
- #include <stdarg.h>
- #include <fcntl.h>
- #include <ctype.h>
- #include <string.h>
- #include <time.h>
- #include <io.h>
- #include <conio.h>
- #include <stdlib.h>
-
- #ifdef __TURBOC__
- #include "tc_utime.h"
- #include <alloc.h>
- #else
- #include <sys/utime.h>
- #include <malloc.h>
- #endif
-
- #ifndef IBM_C
- extern int _fmode;
- #endif
-
- #include "com.h"
- #include "xfer.h"
- #include "zmodem.h"
- #include "keybd.h"
- #include "sbuf.h"
- #include "sched.h"
- #include "externs.h"
- #include "prototyp.h"
- #include "defines.h"
- #include "janus.h"
-
-
- /* Private routines */
- static void getfname(word);
- static void sendpkt(byte *,int,int);
- static void sendpkt32(byte *,int,int);
- static void txbyte(byte);
- static long procfname(void);
- static byte rcvpkt(void);
- static void rxclose(word);
- static void endbatch(void);
- static void j_message(word,char *,...);
- static void j_status(char *,...);
- static int j_error(byte *,byte *);
- static void update_y(void);
- static void long_set_timer(long *,word);
- static int long_time_gone(long *);
- static int rcvrawbyte(void);
- static int rxbyte(void);
- static void xfer_summary(char *,char *,long *,int);
- static void update_status(long *,long *,long,int *,int);
- static void through(long *,long *);
- static int get_filereq(byte);
- static int record_reqfile(char *);
- static byte get_reqname(byte);
- static void mark_done(char *);
-
-
-
- /* Private data. I know, proper software design says you shouldn't make data */
- /* global unless you really need to. In this case speed and code size make */
- /* it more important to avoid constantly pushing & popping arguments. */
-
- static byte *GenericError = "!%s";
- static byte *ReqTmp = "JANUSREQ.TMP";
- #ifdef OS_2
- static byte Upload_path[PATHLEN]; /* Dest. path of file being
- * received */
- #endif
- static char *Rxbuf; /* Address of packet reception buffer */
- static char *Txfname; /* Full path of file we're sending */
- static char *Rxfname; /* Full path of file we're receiving */
- static byte *Rxbufptr; /* Current position within packet reception buffer */
- static byte *Rxbufmax; /* Upper bound of packet reception buffer */
- static byte Do_after; /* What to do with file being sent when we're done */
- static byte WaitFlag; /* Tells rcvrawbyte() whether or not to wait */
- static byte SharedCap; /* Capability bits both sides have in common */
- static int Txfile; /* File handle of file we're sending */
- static int Rxfile; /* File handle of file we're receiving */
- static int ReqRecorded; /* Number of files obtained by this request */
- static word TimeoutSecs; /* How long to wait for various things */
- static word Rxblklen; /* Length of data in last data block packet recvd */
- static word Next_y; /* Number of next available line on screen */
- static word Tx_y; /* Line number of file transmission status display */
- static word Rx_y; /* Line number of file reception status display */
- static long Txlen; /* Total length of file we're sending */
- static long Rxlen; /* Total length of file we're receiving */
- static long Rxfiletime; /* Timestamp of file we're receiving */
- static long Diskavail; /* Bytes available in upload directory */
- static long TotalBytes; /* Total bytes xferred in this session */
- static long Txsttime; /* Time at which we started sending current file */
- static long Rxsttime; /* Time at which we started receiving current file */
-
-
- /*****************************************************************************/
- /* Super-duper neato-whizbang full-duplex streaming ACKless batch file */
- /* transfer protocol for use in WaZOO mail sessions */
- /*****************************************************************************/
- void Janus(void) {
- byte xstate; /* Current file transmission state */
- byte rstate; /* Current file reception state */
- byte pkttype; /* Type of packet last received */
- byte tx_inhibit; /* Flag to wait and send after done receiving */
- byte *holdname; /* Name of hold area */
- #ifdef OS_2
- byte *p; /* Temporary pointer */
- #endif
- byte fsent; /* Did we manage to send anything this session? */
- byte sending_req; /* Are we currently sending requested files? */
- byte attempting_req; /* Are we waiting for the sender to start our req? */
- byte req_started; /* Has the sender started servicing our request? */
- int txoldeta; /* Last transmission ETA displayed */
- int rxoldeta; /* Last reception ETA displayed */
- word blklen; /* Length of last data block sent */
- word txblklen; /* Size of data block to try to send this time */
- word txblkmax; /* Max size of data block to send at this speed */
- word goodneeded; /* # good bytes to send before upping txblklen */
- word goodbytes; /* Number of good bytes sent at this block size */
- word rpos_count; /* Number of RPOS packets sent at this position */
- long xmit_retry; /* Time to retransmit lost FNAMEPKT or EOF packet */
- long txpos; /* Current position within file we're sending */
- long lasttx; /* Position within file of last data block we sent */
- long starttime; /* Time at which we started this Janus session */
- long txstpos; /* Initial data position of file we're sending */
- long rxstpos; /* Initial data position of file we're receiving */
- long txoldpos; /* Last transmission file position displayed */
- long rxoldpos; /* Last reception file position displayed */
- long rpos_retry; /* Time at which to retry RPOS packet */
- long brain_dead; /* Time at which to give up on other computer */
- long rpos_sttime; /* Time at which we started current RPOS sequence */
- long last_rpostime; /* Timetag of last RPOS which we performed */
- long last_blkpos; /* File position of last out-of-sequence BLKPKT */
- FILE *reqfile; /* File handle for .REQ file */
-
-
- set_prior(3); /* Time Critical */
- XON_DISABLE();
- if (un_attended && fullscreen) {
- clear_filetransfer();
- sb_show();
- } else {
- set_xy(NULL);
- Next_y = locate_y;
- }
- Tx_y = Rx_y = 0;
- SharedCap = 0;
- TotalBytes = 0;
- time(&starttime);
-
- /*------------------------------------------------------------------------*/
- /* Allocate memory */
- /*------------------------------------------------------------------------*/
- Rxbuf = Txbuf + 4096 + 8;
- Txfname = Rxfname = NULL;
- if (!(Txfname = malloc(PATHLEN)) || !(Rxfname = malloc(PATHLEN))) {
- status_line(msgtxt[M_MEM_ERROR]);
- mdm_hangup();
- goto freemem;
- }
- Rxbufmax = Rxbuf + BUFMAX + 8;
-
- /*------------------------------------------------------------------------*/
- /* Initialize file transmission variables */
- /*------------------------------------------------------------------------*/
- tx_inhibit = FALSE;
- last_rpostime = xmit_retry = 0L;
- TimeoutSecs = (unsigned int)(40960 / cur_baud);
- if (TimeoutSecs < 10)
- TimeoutSecs = 10;
- long_set_timer(&brain_dead,120);
- txblkmax = cur_baud/300 * 128;
- if (txblkmax > BUFMAX)
- txblkmax = BUFMAX;
- txblklen = txblkmax;
- goodbytes = goodneeded = 0;
- Txfile = -1;
- sending_req = fsent = FALSE;
- xstate = XSENDFNAME;
- getfname(INITIAL_XFER);
-
- /*------------------------------------------------------------------------*/
- /* Initialize file reception variables */
- /*------------------------------------------------------------------------*/
- holdname = HoldAreaNameMunge(&called_addr);
- sprintf(Abortlog_name,"%s%s.Z\0",holdname,Hex_Addr_Str(&called_addr));
-
- /* Sorry, this don't cut in OS/2's zfree */
- #ifdef OS_2
- p = strchr(strcpy (Upload_path, CurrentNetFiles),'\0') - 1;
- while (p >= Upload_path && *p != '\\')
- --p;
- *(++p) = '\0';
- if ((Diskavail = zfree(Upload_path)) <= 0L)
- Diskavail = 0x7FFFFFF;
- #else
- Diskavail = (CurrentNetFiles[1] == ':') ? zfree(CurrentNetFiles) : 0x7FFFFFFF;
- #endif
- Rxbufptr = NULL;
- rpos_retry = rpos_count = 0;
- attempting_req = req_started = FALSE;
- rstate = RRCVFNAME;
-
- /*------------------------------------------------------------------------*/
- /* Send and/or receive stuff until we're done with both */
- /*------------------------------------------------------------------------*/
- do { /* while (xstate || rstate) */
-
- /*---------------------------------------------------------------------*/
- /* If nothing useful (i.e. sending or receiving good data block) has */
- /* happened within the last 2 minutes, give up in disgust */
- /*---------------------------------------------------------------------*/
- if (long_time_gone(&brain_dead)) {
- j_status(msgtxt[M_OTHER_DIED]); /* "He's dead, Jim." */
- goto giveup;
- }
-
- /*---------------------------------------------------------------------*/
- /* If we're tired of waiting for an ACK, try again */
- /*---------------------------------------------------------------------*/
- if (xmit_retry) {
- if (long_time_gone(&xmit_retry)) {
- j_message(Tx_y,msgtxt[M_TIMEOUT]);
- xmit_retry = 0L;
-
- switch (xstate) {
- case XRCVFNACK:
- xstate = XSENDFNAME;
- break;
- case XRCVFRNAKACK:
- xstate = XSENDFREQNAK;
- break;
- case XRCVEOFACK:
- errno = 0;
- lseek(Txfile, txpos=lasttx, SEEK_SET);
- if (j_error(msgtxt[M_SEEK_MSG],Txfname))
- goto giveup;
- xstate = XSENDBLK;
- break;
- }
- }
- }
-
- /*---------------------------------------------------------------------*/
- /* Transmit next part of file, if any */
- /*---------------------------------------------------------------------*/
- switch (xstate) {
- case XSENDBLK:
- if (tx_inhibit)
- break;
- *((long *)Txbuf) = lasttx = txpos;
- errno = 0;
- blklen = read(Txfile, Txbuf+sizeof(txpos), txblklen);
- if (j_error(msgtxt[M_READ_MSG],Txfname))
- goto giveup;
- txpos += blklen;
- sendpkt(Txbuf, sizeof(txpos)+blklen, BLKPKT);
- update_status(&txpos,&txoldpos,Txlen-txpos,&txoldeta,Tx_y);
- fsent = TRUE;
- if (txpos >= Txlen || blklen < txblklen) {
- long_set_timer(&xmit_retry,TimeoutSecs);
- xstate = XRCVEOFACK;
- } else
- long_set_timer(&brain_dead,120);
-
- if (txblklen < txblkmax && (goodbytes+=txblklen) >= goodneeded) {
- txblklen <<= 1;
- goodbytes = 0;
- }
- break;
-
- case XSENDFNAME:
- blklen = strchr( strchr(Txbuf,'\0')+1, '\0') - Txbuf + 1;
- Txbuf[blklen++] = OURCAP;
- sendpkt(Txbuf,blklen,FNAMEPKT);
- txoldpos = txoldeta = -1;
- long_set_timer(&xmit_retry,TimeoutSecs);
- xstate = XRCVFNACK;
- break;
-
- case XSENDFREQNAK:
- sendpkt(NULL,0,FREQNAKPKT);
- long_set_timer(&xmit_retry,TimeoutSecs);
- xstate = XRCVFRNAKACK;
- break;
- }
-
- /*---------------------------------------------------------------------*/
- /* Catch up on our reading; receive and handle all outstanding packets */
- /*---------------------------------------------------------------------*/
- while (pkttype = rcvpkt()) {
- if (pkttype != BADPKT)
- long_set_timer(&brain_dead,120);
- switch (pkttype) {
-
- /*---------------------------------------------------------------*/
- /* File data block or munged block */
- /*---------------------------------------------------------------*/
- case BADPKT:
- case BLKPKT:
- if (rstate == RRCVBLK) {
- if (pkttype == BADPKT || *((long *)Rxbuf) != Rxpos) {
- if (pkttype == BLKPKT) {
- if (*((long *)Rxbuf) < last_blkpos)
- rpos_retry = rpos_count = 0;
- last_blkpos = *((long *)Rxbuf);
- }
- if (long_time_gone(&rpos_retry)) {
- /* If we're the called machine, and we're trying
- to send stuff, and it seems to be screwing up
- our ability to receive stuff, maybe this
- connection just can't hack full-duplex. Try
- waiting till the sending system finishes before
- sending our stuff to it */
- if (rpos_count > 4) {
- if (xstate && !isOriginator && !tx_inhibit) {
- tx_inhibit = TRUE;
- j_status(msgtxt[M_GOING_ONE_WAY]);
- }
- rpos_count = 0;
- }
- if (++rpos_count == 1)
- time(&rpos_sttime);
- j_message(Rx_y,msgtxt[M_J_BAD_PACKET],Rxpos);
- *((long *)Rxbuf) = Rxpos;
- *((long *)(Rxbuf + sizeof(Rxpos))) = rpos_sttime;
- sendpkt(Rxbuf, sizeof(Rxpos)+sizeof(rpos_sttime), RPOSPKT);
- long_set_timer(&rpos_retry,TimeoutSecs/2);
- }
- } else {
- last_blkpos = Rxpos;
- rpos_retry = rpos_count = 0;
- errno = 0;
- write(Rxfile, Rxbuf+sizeof(Rxpos), Rxblklen -= sizeof(Rxpos));
- if (j_error(msgtxt[M_WRITE_MSG],Rxfname))
- goto giveup;
- Diskavail -= Rxblklen;
- Rxpos += Rxblklen;
- update_status(&Rxpos,&rxoldpos,Rxlen-Rxpos,&rxoldeta,Rx_y);
- if (Rxpos >= Rxlen) {
- rxclose(GOOD_XFER);
- Rxlen -= rxstpos;
- through(&Rxlen,&Rxsttime);
- j_status("%s-J%s %s",msgtxt[M_FILE_RECEIVED], (SharedCap&CANCRC32)?"/32":" ",Rxfname);
- update_files(0);
- rstate = RRCVFNAME;
- }
- }
- }
- if (rstate == RRCVFNAME)
- sendpkt(NULL,0,EOFACKPKT);
- break;
-
- /*---------------------------------------------------------------*/
- /* Name and other data for next file to receive */
- /*---------------------------------------------------------------*/
- case FNAMEPKT:
- if (rstate == RRCVFNAME)
- Rxpos = rxstpos = procfname();
- if (!Rxfname[0] && get_filereq(req_started)) {
- sendpkt(Rxbuf,strlen(Rxbuf)+2,FREQPKT);
- attempting_req = TRUE;
- req_started = FALSE;
- } else {
- if (attempting_req) {
- attempting_req = FALSE;
- req_started = TRUE;
- }
- *((long *)Rxbuf) = Rxpos;
- Rxbuf[sizeof(Rxpos)] = SharedCap;
- sendpkt(Rxbuf,sizeof(Rxpos)+1,FNACKPKT);
- rxoldpos = rxoldeta = -1;
- if (Rxpos > -1)
- rstate = (byte)((Rxfname[0]) ? RRCVBLK : RDONE);
- else
- j_status(msgtxt[M_REFUSING],Rxfname);
- if (!rstate)
- tx_inhibit = FALSE;
- if (!(xstate || rstate))
- goto breakout;
- }
- break;
-
- /*---------------------------------------------------------------*/
- /* ACK to filename packet we just sent */
- /*---------------------------------------------------------------*/
- case FNACKPKT:
- if (xstate == XRCVFNACK) {
- xmit_retry = 0L;
- if (Txfname[0]) {
- SharedCap = (Rxblklen > sizeof(long)) ? Rxbuf[sizeof(long)] : 0;
- if ((txpos = *((long *)Rxbuf)) > -1L) {
- if (txpos)
- status_line(msgtxt[M_SYNCHRONIZING],txpos);
- errno = 0;
- lseek(Txfile, txstpos = txpos, SEEK_SET);
- if (j_error(msgtxt[M_SEEK_MSG],Txfname))
- goto giveup;
- xstate = XSENDBLK;
- } else {
- j_status(msgtxt[M_REMOTE_REFUSED],Txfname);
- if (sending_req) {
- if (!(sending_req = get_reqname(FALSE)))
- getfname(GOOD_XFER);
- } else {
- Do_after = NOTHING_AFTER;
- getfname(GOOD_XFER);
- }
- xstate = XSENDFNAME;
- }
- } else {
- sent_mail = 1;
- xstate = XDONE;
- }
- }
- if (!(xstate || rstate))
- goto breakout;
- break;
-
- /*---------------------------------------------------------------*/
- /* Request to send more stuff rather than end batch just yet */
- /*---------------------------------------------------------------*/
- case FREQPKT:
- if (xstate == XRCVFNACK) {
- xmit_retry = 0L;
- SharedCap = *(strchr(Rxbuf,'\0')+1);
- if (CurrentReqLim > 0) {
- sprintf(Txbuf,request_template,CurrentNetFiles,
- Hex_Addr_Str (&(alias[0])));
- errno = 0;
- reqfile = fopen(Txbuf,"wt");
- j_error(msgtxt[M_OPEN_MSG],Txbuf);
- fputs(Rxbuf,reqfile);
- fputs("\n",reqfile);
- fclose(reqfile);
- unlink(ReqTmp);
- ReqRecorded = 0; /* counted by record_reqfile */
- respond_to_file_requests(0,record_reqfile);
- CurrentReqLim -= ReqRecorded;
- if (sending_req = get_reqname(TRUE))
- xstate = XSENDFNAME;
- else
- xstate = XSENDFREQNAK;
- } else
- xstate = XSENDFREQNAK;
- }
- break;
-
- /*---------------------------------------------------------------*/
- /* Our last file request didn't match anything; move on to next */
- /*---------------------------------------------------------------*/
- case FREQNAKPKT:
- attempting_req = FALSE;
- req_started = TRUE;
- sendpkt(NULL,0,FRNAKACKPKT);
- break;
-
- /*---------------------------------------------------------------*/
- /* ACK to no matching files for request error; try to end again */
- /*---------------------------------------------------------------*/
- case FRNAKACKPKT:
- if (xstate == XRCVFRNAKACK) {
- xmit_retry = 0L;
- getfname(GOOD_XFER);
- xstate = XSENDFNAME;
- }
- break;
-
- /*---------------------------------------------------------------*/
- /* ACK to last data block in file */
- /*---------------------------------------------------------------*/
- case EOFACKPKT:
- if (xstate == XRCVEOFACK || xstate == XRCVFNACK) {
- xmit_retry = 0L;
- if (xstate == XRCVEOFACK) {
- Txlen -= txstpos;
- through(&Txlen,&Txsttime);
- j_status("%s-J%s %s",msgtxt[M_FILE_SENT],(SharedCap&CANCRC32)?"/32":" ",Txfname);
- update_files(1);
- if (sending_req) {
- if (!(sending_req = get_reqname(FALSE)))
- getfname(GOOD_XFER);
- } else
- getfname(GOOD_XFER);
- }
- xstate = XSENDFNAME;
- }
- break;
-
- /*---------------------------------------------------------------*/
- /* Receiver says "let's try that again." */
- /*---------------------------------------------------------------*/
- case RPOSPKT:
- if (xstate == XSENDBLK || xstate == XRCVEOFACK) {
- if (*((long *)(Rxbuf+sizeof(txpos))) != last_rpostime) {
- last_rpostime = *((long *)(Rxbuf+sizeof(txpos)));
- xmit_retry = 0L;
- CLEAR_OUTBOUND();
- errno = 0;
- lseek(Txfile, txpos = lasttx = *((long *)Rxbuf), SEEK_SET);
- if (j_error(msgtxt[M_SEEK_MSG],Txfname))
- goto giveup;
- j_message(Tx_y,msgtxt[M_SYNCHRONIZING],txpos);
- txblklen >>= 2;
- if (txblklen < 64)
- txblklen = 64;
- goodbytes = 0;
- goodneeded += 1024;
- if (goodneeded > 8192)
- goodneeded = 8192;
- xstate = XSENDBLK;
- }
- }
- break;
-
- /*---------------------------------------------------------------*/
- /* Debris from end of previous Janus session; ignore it */
- /*---------------------------------------------------------------*/
- case HALTACKPKT:
- break;
-
- /*---------------------------------------------------------------*/
- /* Abort the transfer and quit */
- /*---------------------------------------------------------------*/
- default:
- j_status(msgtxt[M_UNKNOWN_PACKET],pkttype);
- /* fallthrough */
- case HALTPKT:
- giveup: j_status(msgtxt[M_SESSION_ABORT]);
- if (Txfname[0])
- getfname(ABORT_XFER);
- if (rstate == RRCVBLK) {
- TotalBytes += (Rxpos-rxstpos);
- rxclose(FAILED_XFER);
- }
- goto abortxfer;
-
- } /* switch (pkttype) */
- } /* while (pkttype) */
- } while (xstate || rstate);
-
- /*------------------------------------------------------------------------*/
- /* All done; make sure other end is also finished (one way or another) */
- /*------------------------------------------------------------------------*/
- breakout:
- if (!fsent) j_status(msgtxt[M_NOTHING_TO_SEND], Full_Addr_Str (&called_addr));
- abortxfer:
- through(&TotalBytes,&starttime);
- endbatch();
-
- /*------------------------------------------------------------------------*/
- /* Release allocated memory */
- /*------------------------------------------------------------------------*/
- freemem:
- if (Txfname)
- free(Txfname);
- if (Rxfname)
- free(Rxfname);
- flag_file (CLEAR_FLAG, &called_addr, 1);
- set_prior(4); /* Always High */
- }
-
-
-
- /*****************************************************************************/
- /* Get name and info for next file to be transmitted, if any, and build */
- /* FNAMEPKT. Packet contents as per ZModem filename info packet, to allow */
- /* use of same method of aborted-transfer recovery. If there are no more */
- /* files to be sent, build FNAMEPKT with null filename. Also open file and */
- /* set up for transmission. Set Txfname, Txfile, Txlen. Txbuf must not be */
- /* modified until FNACKPKT is received. */
- /*****************************************************************************/
- static void getfname(word xfer_flag) {
- static byte floflag, bad_xfers, outboundname[PATHLEN];
- static long floname_pos;
- static FILE *flofile;
- static int have_lock;
- char *holdname;
-
- register char *p;
- int i;
- long curr_pos;
- struct stat f;
-
- /*------------------------------------------------------------------------*/
- /* Initialize static variables on first call of the batch */
- /*------------------------------------------------------------------------*/
- if (xfer_flag == INITIAL_XFER) {
- floflag = outboundname[0] = '\0';
- flofile = NULL;
- have_lock = flag_file (TEST_AND_SET, &called_addr, 1);
-
- /*------------------------------------------------------------------------*/
- /* If we were already sending a file, close it and clean up */
- /*------------------------------------------------------------------------*/
- } else if (Txfile != -1) {
- errno = 0;
- close(Txfile);
- j_error(msgtxt[M_CLOSE_MSG],Txfname);
- Txfile = -1;
- /*---------------------------------------------------------------------*/
- /* If xfer completed, do post-xfer cleanup */
- /*---------------------------------------------------------------------*/
- if (xfer_flag == GOOD_XFER) {
- /*------------------------------------------------------------------*/
- /* Perform post-xfer file massaging if neccessary */
- /*------------------------------------------------------------------*/
- switch (Do_after) {
- case DELETE_AFTER:
- case SHOW_DELETE_AFTER:
- j_status(msgtxt[M_UNLINKING_MSG],Txfname);
- unlink(Txfname);
- j_error(msgtxt[M_UNLINK_MSG],Txfname);
- break;
- case TRUNC_AFTER:
- j_status(msgtxt[M_TRUNC_MSG],Txfname);
- Txfile = open(Txfname,O_TRUNC|O_RDWR,S_IREAD|S_IWRITE);
- if (Txfile != -1)
- errno = 0;
- j_error(msgtxt[M_TRUNC_MSG],Txfname);
- close(Txfile);
- Txfile = -1;
- }
- /*------------------------------------------------------------------*/
- /* If processing .?LO file, flag filename as sent (name[0] = '~') */
- /*------------------------------------------------------------------*/
- skipname:
- if (floflag) {
- curr_pos = ftell(flofile);
- j_error(msgtxt[M_SEEK_MSG],outboundname);
- fseek(flofile,floname_pos,SEEK_SET);
- j_error(msgtxt[M_SEEK_MSG],outboundname);
- fputc(Txfname[0] = '~',flofile);
- j_error(msgtxt[M_WRITE_MSG],outboundname);
- fseek(flofile,curr_pos,SEEK_SET);
- j_error(msgtxt[M_SEEK_MSG],outboundname);
- }
- } else {
- abort:
- ++bad_xfers;
- }
- }
-
- /*------------------------------------------------------------------------*/
- /* Find next file to be sent and build FNAMEPKT. If reading .FLO-type */
- /* file get next entry from it; otherwise check for next .OUT/.FLO file */
- /*------------------------------------------------------------------------*/
- if (have_lock)
- goto end_send;
-
- holdname = HoldAreaNameMunge(&called_addr);
- if (!floflag) {
- /*---------------------------------------------------------------------*/
- /* If first getfname() for this batch, init filename to .OUT */
- /*---------------------------------------------------------------------*/
- if (!outboundname[0]) {
- sprintf(outboundname,"%s%s.OUT",holdname,Hex_Addr_Str(&called_addr));
- *ext_flags = 'O';
- /*---------------------------------------------------------------------*/
- /* Increment outbound filename until match found or all checked */
- /* .OUT->.DUT->.CUT->.HUT->.FLO->.DLO->.CLO->.HLO->null name */
- /*---------------------------------------------------------------------*/
- } else {
- nxtout:
- p = strchr(outboundname,'\0') - 3;
- for (i = 0; i < NUM_FLAGS; ++i)
- if (ext_flags[i] == *p)
- break;
- if (i < NUM_FLAGS - 1) {
- *p = ext_flags[i+1];
- #ifndef JACK_DECKER
- if (isOriginator && *p == 'H')
- goto nxtout;
- #endif
- } else {
- /*---------------------------------------------------------------*/
- /* Finished ?,D,C,H sequence; wrap .OUT->.FLO, or .FLO->done */
- /*---------------------------------------------------------------*/
- if (!floflag) {
- *p++ = *ext_flags = 'F';
- *p++ = 'L';
- *p = 'O';
- ++floflag;
- } else
- end_send:
- outboundname[0] = Txfname[0] = Txbuf[0] = Txbuf[1] = floflag = '\0';
- }
- }
- /*---------------------------------------------------------------------*/
- /* Check potential outbound name; if file doesn't exist keep looking */
- /*---------------------------------------------------------------------*/
- if (outboundname[0]) {
- if (!dexists(outboundname))
- goto nxtout;
- if (floflag)
- goto rdflo;
- strcpy(Txfname,outboundname);
- /*------------------------------------------------------------------*/
- /* Start FNAMEPKT using .PKT alias */
- /*------------------------------------------------------------------*/
- invent_pkt_name(Txbuf);
- Do_after = DELETE_AFTER;
- }
- /*------------------------------------------------------------------------*/
- /* Read and process next entry from .?LO-type file */
- /*------------------------------------------------------------------------*/
- } else {
- rdflo:
- /*---------------------------------------------------------------------*/
- /* Open .?LO file for processing if neccessary */
- /*---------------------------------------------------------------------*/
- if (!flofile) {
- bad_xfers = 0;
- errno = 0;
- flofile = fopen(outboundname,"rb+");
- if (j_error(msgtxt[M_OPEN_MSG],outboundname))
- goto nxtout;
- }
- errno = 0;
- floname_pos = ftell(flofile);
- j_error(msgtxt[M_SEEK_MSG],outboundname);
- if (fgets(p = Txfname, PATHLEN, flofile)) {
- /*------------------------------------------------------------------*/
- /* Got an attached file name; check for handling flags, fix up name */
- /*------------------------------------------------------------------*/
- while (*p > ' ')
- ++p;
- *p = '\0';
- switch (Txfname[0]) {
- case '\0':
- case '~':
- case ';':
- goto rdflo;
- case TRUNC_AFTER:
- case DELETE_AFTER:
- case SHOW_DELETE_AFTER:
- Do_after = Txfname[0];
- strcpy(Txfname,Txfname+1);
- break;
- default:
- Do_after = NOTHING_AFTER;
- break;
- }
- /*------------------------------------------------------------------*/
- /* Start FNAMEPKT with simple filename */
- /*------------------------------------------------------------------*/
- while (p >= Txfname && *p != '\\' && *p != ':')
- --p;
- strcpy(Txbuf,++p);
- } else {
- /*------------------------------------------------------------------*/
- /* Finished reading this .?LO file; clean up and look for another */
- /*------------------------------------------------------------------*/
- errno = 0;
- fclose(flofile);
- j_error(msgtxt[M_CLOSE_MSG],outboundname);
- flofile = NULL;
- if (!bad_xfers) {
- unlink(outboundname);
- j_error(msgtxt[M_UNLINK_MSG],outboundname);
- }
- goto nxtout;
- }
- }
-
- /*------------------------------------------------------------------------*/
- /* If we managed to find a valid file to transmit, open it, finish */
- /* FNAMEPKT, and print nice message for the sysop. */
- /*------------------------------------------------------------------------*/
- if (Txfname[0]) {
- if (xfer_flag == ABORT_XFER)
- goto abort;
- j_status(msgtxt[M_SENDING],Txfname);
- errno = 0;
- Txfile = open(Txfname,O_RDONLY|O_BINARY);
- if (Txfile != -1)
- errno = 0;
- if (j_error(msgtxt[M_OPEN_MSG],Txfname))
- goto skipname;
-
- stat(Txfname,&f);
- sprintf(strchr(Txbuf,'\0')+1,"%lu %lo %o",Txlen = f.st_size,f.st_mtime,f.st_mode);
-
- p = strchr(Txfname,'\0');
- while (p >= Txfname && *p != ':' && *p != '\\')
- --p;
- if (!un_attended || !fullscreen)
- Tx_y = Next_y;
- else
- Tx_y = 1;
- xfer_summary(msgtxt[M_SEND],++p,&Txlen,Tx_y);
-
- time(&Txsttime);
- }
- }
-
-
- /*****************************************************************************/
- /* Build and send a packet of any type. */
- /* Packet structure is: PKTSTRT,contents,packet_type,PKTEND,crc */
- /* CRC is computed from contents and packet_type only; if PKTSTRT or PKTEND */
- /* get munged we'll never even find the CRC. */
- /*****************************************************************************/
- static void sendpkt(register byte *buf,int len,int type) {
- register word crc;
-
- if ((SharedCap & CANCRC32) && type != FNAMEPKT)
- sendpkt32(buf,len,type);
- else {
- BUFFER_BYTE(DLE);
- BUFFER_BYTE(PKTSTRTCHR ^ 0x40);
-
- crc = 0;
- while (--len >= 0) {
- txbyte(*buf);
- crc = xcrc(crc, ((word)(*buf++)) );
- }
-
- BUFFER_BYTE((byte)type);
- crc = xcrc(crc,type);
-
- BUFFER_BYTE(DLE);
- BUFFER_BYTE(PKTENDCHR ^ 0x40);
-
- txbyte((byte)(crc >> 8));
- txbyte((byte)(crc & 0xFF));
-
- UNBUFFER_BYTES();
- }
- }
-
-
- /*****************************************************************************/
- /* Build and send a packet using 32-bit CRC; same as sendpkt in other ways */
- /*****************************************************************************/
- static void sendpkt32(register byte *buf,register int len,int type) {
- unsigned long crc32;
-
- BUFFER_BYTE(DLE);
- BUFFER_BYTE(PKTSTRTCHR32 ^ 0x40);
-
- crc32 = 0xFFFFFFFF;
- while (--len >= 0) {
- txbyte(*buf);
- crc32 = Z_32UpdateCRC(((word)*buf),crc32);
- ++buf;
- }
-
- BUFFER_BYTE((byte)type);
- crc32 = Z_32UpdateCRC(type,crc32);
-
- BUFFER_BYTE(DLE);
- BUFFER_BYTE(PKTENDCHR ^ 0x40);
-
- txbyte((byte)(crc32 >> 24));
- txbyte((byte)((crc32 >> 16) & 0xFF));
- txbyte((byte)((crc32 >> 8) & 0xFF));
- txbyte((byte)(crc32 & 0xFF));
-
- UNBUFFER_BYTES();
- }
-
-
-
- /*****************************************************************************/
- /* Transmit cooked escaped byte(s) corresponding to raw input byte. Escape */
- /* DLE, XON, and XOFF using DLE prefix byte and ^ 0x40. Also escape */
- /* CR-after-'@' to avoid Telenet/PC-Pursuit problems. */
- /*****************************************************************************/
- static void txbyte(register byte c) {
- static byte lastsent;
-
- switch (c) {
- case CR:
- if (lastsent != '@')
- goto sendit;
- /* fallthrough */
- case DLE:
- case XON:
- case XOFF:
- BUFFER_BYTE(DLE);
- c ^= 0x40;
- /* fallthrough */
- default:
- sendit: BUFFER_BYTE(lastsent = c);
- }
- }
-
-
- /*****************************************************************************/
- /* Process FNAMEPKT of file to be received. Check for aborted-transfer */
- /* recovery and solve filename collisions. Check for enough disk space. */
- /* Return initial file data position to start receiving at, or -1 if error */
- /* detected to abort file reception. Set Rxfname, Rxlen, Rxfile. */
- /*****************************************************************************/
- static long procfname(void) {
- register byte *p;
- char linebuf[128], *fileinfo, *badfname;
- long filestart, bytes;
- FILE *abortlog;
- struct stat f;
- int i;
-
- /*------------------------------------------------------------------------*/
- /* Initialize for file reception */
- /*------------------------------------------------------------------------*/
- Rxfname[0] = Resume_WaZOO = 0;
-
- /*------------------------------------------------------------------------*/
- /* Save info on WaZOO transfer in case of abort */
- /*------------------------------------------------------------------------*/
- strcpy(Resume_name,fancy_str(Rxbuf));
- fileinfo = strchr(Rxbuf,'\0') + 1;
- p = strchr(fileinfo,'\0') + 1;
- SharedCap = (Rxblklen > p-Rxbuf) ? *p & OURCAP : 0;
-
- /*------------------------------------------------------------------------*/
- /* If this is a null FNAMEPKT, return OK immediately */
- /*------------------------------------------------------------------------*/
- if (!Rxbuf[0])
- return 0L;
-
- strcpy(linebuf,Rxbuf);
- strlwr(linebuf);
- p = check_netfile(linebuf);
- j_status("#%s %s %s",msgtxt[M_RECEIVING],(p) ? p : " ",Rxbuf);
-
- /*------------------------------------------------------------------------*/
- /* Extract and validate filesize */
- /*------------------------------------------------------------------------*/
- Rxlen = -1;
- Rxfiletime = 0;
- if (sscanf(fileinfo,"%ld %lo",&Rxlen,&Rxfiletime) < 1 || Rxlen < 0) {
- j_status(msgtxt[M_NO_LENGTH]);
- return -1L;
- }
- sprintf(Resume_info,"%ld %lo",Rxlen,Rxfiletime);
-
- /*------------------------------------------------------------------------*/
- /* Check if this is a failed WaZOO transfer which should be resumed */
- /*------------------------------------------------------------------------*/
- if (dexists(Abortlog_name)) {
- errno = 0;
- abortlog = fopen(Abortlog_name,read_ascii);
- if (!j_error(msgtxt[M_OPEN_MSG],Abortlog_name)) {
- while (!feof(abortlog)) {
- linebuf[0] = '\0';
- if (!fgets(p = linebuf,sizeof(linebuf),abortlog))
- break;
- while (*p >= ' ')
- ++p;
- *p = '\0';
- p = strchr(linebuf,' ');
- *p = '\0';
- if (!stricmp(linebuf,Resume_name)) {
- p = strchr( (badfname = ++p), ' ');
- *p = '\0';
- if (!stricmp(++p,Resume_info)) {
- ++Resume_WaZOO;
- break;
- }
- }
- }
- errno = 0;
- fclose(abortlog);
- j_error(msgtxt[M_CLOSE_MSG],Abortlog_name);
- }
- }
-
- /*------------------------------------------------------------------------*/
- /* Open either the old or a new file, as appropriate */
- /*------------------------------------------------------------------------*/
- p = strchr(strcpy(Rxfname,CurrentNetFiles),'\0');
- errno = 0;
- if (Resume_WaZOO) {
- strcpy(p,badfname);
- Rxfile = open(Rxfname,O_CREAT|O_RDWR|O_BINARY,S_IREAD|S_IWRITE);
- } else {
- strcpy(p,Rxbuf);
- /*---------------------------------------------------------------------*/
- /* If the file already exists: */
- /* 1) And the new file has the same time and size, skip it */
- /* 2) And OVERWRITE is turned on, delete the old copy */
- /* 3) Else create a unique file name in which to store new data */
- /*---------------------------------------------------------------------*/
- if (dexists(Rxfname)) {
- stat(Rxfname,&f);
- if (Rxlen == f.st_size && Rxfiletime == f.st_mtime) {
- j_status(msgtxt[M_ALREADY_HAVE],Rxfname);
- return -1L;
- }
- i = strlen(Rxfname) - 1;
- if ((!overwrite) || (is_arcmail(Rxfname,i))) {
- unique_name(Rxfname);
- j_status(msgtxt[M_RENAME_MSG],Rxfname);
- } else {
- unlink(Rxfname);
- j_error(msgtxt[M_UNLINK_MSG],Rxfname);
- }
- }
- Rxfile = open(Rxfname,O_CREAT|O_EXCL|O_RDWR|O_BINARY,S_IREAD|S_IWRITE);
- }
- if (Rxfile != -1)
- errno = 0;
- if (j_error(msgtxt[M_OPEN_MSG],Rxfname))
- return -1L;
-
- /*------------------------------------------------------------------------*/
- /* Determine initial file data position */
- /*------------------------------------------------------------------------*/
- if (Resume_WaZOO) {
- stat(Rxfname,&f);
- j_status(msgtxt[M_SYNCHRONIZING_OFFSET],filestart = f.st_size);
- p = Rxbuf;
- errno = 0;
- lseek(Rxfile,filestart,SEEK_SET);
- if (j_error(msgtxt[M_SEEK_MSG],Rxfname)) {
- close(Rxfile);
- return -1L;
- }
- } else
- filestart = 0L;
-
- /*------------------------------------------------------------------------*/
- /* Check for enough disk space */
- /*------------------------------------------------------------------------*/
- bytes = Rxlen - filestart + 10240;
- if (bytes > Diskavail) {
- j_status(msgtxt[M_OUT_OF_DISK_SPACE]);
- close(Rxfile);
- return -1L;
- }
-
- /*------------------------------------------------------------------------*/
- /* Print status message for the sysop */
- /*------------------------------------------------------------------------*/
- if (!un_attended || !fullscreen)
- Rx_y = Next_y;
- else
- Rx_y = 2;
- xfer_summary(msgtxt[M_RECV],p,&Rxlen,Rx_y);
-
- time(&Rxsttime);
-
- return filestart;
- }
-
-
- /*****************************************************************************/
- /* Receive, validate, and extract a packet if available. If a complete */
- /* packet hasn't been received yet, receive and store as much of the next */
- /* packet as possible. Each call to rcvpkt() will continue accumulating a */
- /* packet until a complete packet has been received or an error is detected. */
- /* Rxbuf must not be modified between calls to rcvpkt() if NOPKT is returned.*/
- /* Returns type of packet received, NOPKT, or BADPKT. Sets Rxblklen. */
- /*****************************************************************************/
- static byte rcvpkt() {
- static byte rxcrc32;
- static word crc;
- static unsigned long crc32;
- register byte *p;
- register int c;
- int i;
- unsigned long pktcrc;
-
- /*------------------------------------------------------------------------*/
- /* Abort transfer if operator pressed ESC */
- /*------------------------------------------------------------------------*/
-
- if (got_ESC()) {
- j_status(GenericError,msgtxt[M_KBD_MSG]);
- return HALTPKT;
- }
-
- /*------------------------------------------------------------------------*/
- /* If not accumulating packet yet, find start of next packet */
- /*------------------------------------------------------------------------*/
- WaitFlag = FALSE;
- if (!(p = Rxbufptr)) {
- do
- c = rxbyte();
- while (c >= 0 || c == PKTEND);
-
- switch (c) {
- case PKTSTRT:
- rxcrc32 = FALSE;
- p = Rxbuf;
- crc = 0;
- break;
- case PKTSTRT32:
- rxcrc32 = TRUE;
- p = Rxbuf;
- crc32 = 0xFFFFFFFF;
- break;
- case NOCARRIER:
- j_status(GenericError,&(msgtxt[M_NO_CARRIER][1]));
- return HALTPKT;
- default:
- return NOPKT;
- }
- }
-
- /*------------------------------------------------------------------------*/
- /* Accumulate packet data until we empty buffer or find packet delimiter */
- /*------------------------------------------------------------------------*/
- if (rxcrc32) {
- while ((c = rxbyte()) >= 0 && p < Rxbufmax) {
- *p++ = (byte)c;
- crc32 = Z_32UpdateCRC(c,crc32);
- }
- } else {
- while ((c = rxbyte()) >= 0 && p < Rxbufmax) {
- *p++ = (byte)c;
- crc = xcrc(crc,c);
- }
- }
-
- /*------------------------------------------------------------------------*/
- /* Handle whichever end-of-packet condition occurred */
- /*------------------------------------------------------------------------*/
- switch (c) {
- /*---------------------------------------------------------------------*/
- /* PKTEND found; verify valid CRC */
- /*---------------------------------------------------------------------*/
- case PKTEND:
- WaitFlag = TRUE;
- pktcrc = 0;
- for (i = (rxcrc32) ? 4 : 2; i; --i) {
- if ((c = rxbyte()) < 0)
- break;
- pktcrc = (pktcrc << 8) | c;
- }
- if (!i) {
- if ((rxcrc32 && pktcrc == crc32) || pktcrc == crc) {
- /*------------------------------------------------------------*/
- /* Good packet verified; compute packet data length and */
- /* return packet type */
- /*------------------------------------------------------------*/
- Rxbufptr = NULL;
- Rxblklen = --p - Rxbuf;
- return *p;
- }
- }
- /* fallthrough */
-
- /*---------------------------------------------------------------------*/
- /* Bad CRC, carrier lost, or buffer overflow from munged PKTEND */
- /*---------------------------------------------------------------------*/
- default:
- if (c == NOCARRIER) {
- j_status(GenericError,&(msgtxt[M_NO_CARRIER][1]));
- return HALTPKT;
- } else {
- Rxbufptr = NULL;
- return BADPKT;
- }
-
- /*---------------------------------------------------------------------*/
- /* Emptied buffer; save partial packet and let sender do something */
- /*---------------------------------------------------------------------*/
- case BUFEMPTY:
- Rxbufptr = p;
- return NOPKT;
-
- /*---------------------------------------------------------------------*/
- /* PKTEND was trashed; discard partial packet and prep for next one */
- /*---------------------------------------------------------------------*/
- case PKTSTRT:
- rxcrc32 = FALSE;
- Rxbufptr = Rxbuf;
- crc = 0;
- return BADPKT;
-
- case PKTSTRT32:
- rxcrc32 = TRUE;
- Rxbufptr = Rxbuf;
- crc32 = 0xFFFFFFFF;
- return BADPKT;
- }
- }
-
-
-
- /*****************************************************************************/
- /* Close file being received and perform post-reception aborted-transfer */
- /* recovery cleanup if neccessary. */
- /*****************************************************************************/
- static void rxclose(word xfer_flag) {
- register byte *p;
- byte namebuf[PATHLEN], linebuf[128], c;
- FILE *abortlog, *newlog;
- struct utimbuf utimes;
-
- /*------------------------------------------------------------------------*/
- /* Close file we've been receiving */
- /*------------------------------------------------------------------------*/
- errno = 0;
- close(Rxfile);
- j_error(msgtxt[M_CLOSE_MSG],Rxfname);
- if (Rxfiletime) {
- utimes.actime = Rxfiletime;
- utimes.modtime = Rxfiletime;
- utime(Rxfname,&utimes);
- }
-
- /*------------------------------------------------------------------------*/
- /* If we completed a previously-aborted transfer, kill log entry & rename */
- /*------------------------------------------------------------------------*/
- if (xfer_flag == GOOD_XFER && Resume_WaZOO) {
- abortlog = fopen(Abortlog_name,read_ascii);
- if (!j_error(msgtxt[M_OPEN_MSG],Abortlog_name)) {
- c = 0;
- strcpy(strchr(strcpy(namebuf,Abortlog_name),'\0')-1,"TMP");
- newlog = fopen(namebuf,write_ascii);
- if (!j_error(msgtxt[M_OPEN_MSG],namebuf)) {
- while (!feof(abortlog)) {
- linebuf[0] = '\0';
- if (!fgets(p = linebuf,sizeof(linebuf),abortlog))
- break;
- while (*p > ' ')
- ++p;
- *p = '\0';
- if (stricmp(linebuf,Resume_name)) {
- *p = ' ';
- fputs(linebuf,newlog);
- if (j_error(msgtxt[M_WRITE_MSG],namebuf))
- break;
- ++c;
- }
- }
- errno = 0;
- fclose(abortlog);
- j_error(msgtxt[M_CLOSE_MSG],Abortlog_name);
- fclose(newlog);
- j_error(msgtxt[M_CLOSE_MSG],namebuf);
- unlink(Abortlog_name);
- j_error(msgtxt[M_UNLINK_MSG],Abortlog_name);
- if (c) {
- if (!rename(namebuf,Abortlog_name))
- errno = 0;
- j_error(msgtxt[M_RENAME_MSG],namebuf);
- } else {
- unlink(namebuf);
- j_error(msgtxt[M_UNLINK_MSG],namebuf);
- }
- } else {
- fclose(abortlog);
- j_error(msgtxt[M_CLOSE_MSG],Abortlog_name);
- }
- }
- j_status(msgtxt[M_FINISHED_PART],Resume_name);
- unique_name(strcat(strcpy(namebuf,CurrentNetFiles),Resume_name));
- if (!rename(Rxfname,namebuf)) {
- errno = 0;
- strcpy(Rxfname,namebuf);
- } else
- j_error(msgtxt[M_RENAME_MSG],Rxfname);
- /*------------------------------------------------------------------------*/
- /* If transfer failed and was not an attempted resumption, log for later */
- /*------------------------------------------------------------------------*/
- } else if (xfer_flag == FAILED_XFER && !Resume_WaZOO) {
- j_status(msgtxt[M_SAVING_PART],Rxfname);
- unique_name(strcat(strcpy(namebuf,CurrentNetFiles),"BadWaZOO.001"));
- if (!rename(Rxfname,namebuf))
- errno = 0;
- j_error(msgtxt[M_RENAME_MSG],Rxfname);
-
- abortlog = fopen(Abortlog_name,"at");
- if (!j_error(msgtxt[M_OPEN_MSG],Abortlog_name)) {
- fprintf(abortlog,"%s %s %s\n",Resume_name,namebuf+strlen(CurrentNetFiles),Resume_info);
- j_error(msgtxt[M_WRITE_MSG],Abortlog_name);
- fclose(abortlog);
- j_error(msgtxt[M_CLOSE_MSG],Abortlog_name);
- } else {
- unlink(namebuf);
- j_error(msgtxt[M_UNLINK_MSG],namebuf);
- }
- }
- }
-
-
- /*****************************************************************************/
- /* Try REAL HARD to disengage batch session cleanly */
- /*****************************************************************************/
- static void endbatch(void) {
- register int done, timeouts;
- long timeval, brain_dead;
-
- /*------------------------------------------------------------------------*/
- /* Tell the other end to halt if it hasn't already */
- /*------------------------------------------------------------------------*/
- done = timeouts = 0;
- long_set_timer(&brain_dead,120);
- goto reject;
-
- /*------------------------------------------------------------------------*/
- /* Wait for the other end to acknowledge that it's halting */
- /*------------------------------------------------------------------------*/
- while (!done) {
- if (long_time_gone(&brain_dead))
- break;
-
- switch (rcvpkt()) {
- case NOPKT:
- case BADPKT:
- if (long_time_gone(&timeval)) {
- if (++timeouts > 2)
- ++done;
- else
- goto reject;
- }
- break;
-
- case HALTPKT:
- case HALTACKPKT:
- ++done;
- break;
-
- default:
- timeouts = 0;
- reject: sendpkt(NULL,0,HALTPKT);
- long_set_timer(&timeval,TimeoutSecs);
- break;
- }
- }
-
- /*------------------------------------------------------------------------*/
- /* Announce quite insistently that we're done now */
- /*------------------------------------------------------------------------*/
- for (done = 0; done < 10; ++done)
- sendpkt(NULL,0,HALTACKPKT);
-
- wait_for_clear();
- }
-
-
- /*****************************************************************************/
- /* Print a message in the message field of a transfer status line */
- /*****************************************************************************/
- static void j_message(word pos,char *va_alist,...)
- {
- va_list arg_ptr;
- int y, l;
-
- char buf[128];
- y = pos;
- va_start(arg_ptr, va_alist);
-
- if (!un_attended || !fullscreen)
- gotoxy(MSG_X,y);
- else
- sb_move(filewin,y,MSG_X);
-
-
- (void) vsprintf(buf,va_alist,arg_ptr);
-
- for (l = 25-strlen(buf); l > 0; --l)
- strcat(buf," ");
-
- if (!un_attended || !fullscreen) {
- cputs(buf);
- } else {
- sb_puts(filewin,buf);
- sb_show();
- }
-
- va_end(arg_ptr);
- }
-
-
- /*****************************************************************************/
- /* Print & log status message without messing up display */
- /*****************************************************************************/
- static void j_status(char *va_alist,...)
- {
- va_list arg_ptr;
-
- char buf[128];
- va_start(arg_ptr, va_alist);
-
- if (!un_attended || !fullscreen)
- gotoxy(1,Next_y-1);
-
- (void) vsprintf(buf,va_alist,arg_ptr);
-
- status_line(buf);
-
- if (!un_attended || !fullscreen)
- update_y();
-
- va_end(arg_ptr);
- }
-
-
- /*****************************************************************************/
- /* Print & log error message without messing up display */
- /*****************************************************************************/
- static int j_error(byte *msg,byte *fname) {
- register int e;
-
- if (e = errno) {
- if (!un_attended || !fullscreen)
- gotoxy(1,Next_y-1);
-
- got_error(msg,fname);
-
- if (!un_attended || !fullscreen)
- update_y();
- }
- return e;
- }
-
-
- /*****************************************************************************/
- /* Update screen position variables after printing a message */
- /*****************************************************************************/
- static void update_y() {
- set_xy(NULL); /* Bump cursor to next line after printing */
- if (locate_y == Next_y) { /* If we didn't go anywhere, screen scrolled; */
- if (Tx_y > 1) /* so decrement status line numbers */
- --Tx_y;
- if (Rx_y > 1)
- --Rx_y;
- } else Next_y = locate_y;
- }
-
-
- /*****************************************************************************/
- /* Compute future timehack for later reference */
- /*****************************************************************************/
- static void long_set_timer(long *Buffer,word Duration) {
- time(Buffer);
- *Buffer += (long)Duration;
- }
-
-
- /*****************************************************************************/
- /* Return TRUE if timehack has been passed, FALSE if not */
- /*****************************************************************************/
- static int long_time_gone(long *TimePtr) {
- return (time(NULL) > *TimePtr);
- }
-
-
- /*****************************************************************************/
- /* Receive cooked escaped byte translated to avoid various problems. */
- /* Returns raw byte, BUFEMPTY, PKTSTRT, PKTEND, or NOCARRIER. */
- /*****************************************************************************/
- static int rxbyte(void) {
- register int c, w;
-
- if ((c = rcvrawbyte()) == DLE) {
- w = WaitFlag++;
- if ((c = rcvrawbyte()) >= 0) {
- switch (c ^= 0x40) {
- case PKTSTRTCHR:
- c = PKTSTRT;
- break;
- case PKTSTRTCHR32:
- c = PKTSTRT32;
- break;
- case PKTENDCHR:
- c = PKTEND;
- break;
- }
- }
- WaitFlag = (byte)w;
- }
- return c;
- }
-
-
- /*****************************************************************************/
- /* Receive raw non-escaped byte. Returns byte, BUFEMPTY, or NOCARRIER. */
- /* If waitflag is true, will wait for a byte for Timeoutsecs; otherwise */
- /* will return BUFEMPTY if a byte isn't ready and waiting in inbound buffer. */
- /*****************************************************************************/
- static int rcvrawbyte(void) {
- register int c;
- long timeval;
-
- if ((c = PEEKBYTE()) >= 0)
- return MODEM_IN();
-
- if (!CARRIER)
- return NOCARRIER;
- if (!WaitFlag)
- return BUFEMPTY;
-
- timeval = time(NULL) + TimeoutSecs;
-
- while ((c = PEEKBYTE()) < 0) {
- if (!CARRIER)
- return NOCARRIER;
- if (time(NULL) > timeval)
- return BUFEMPTY;
- time_release();
- }
-
- return MODEM_IN();
- }
-
-
- /*****************************************************************************/
- /* Display start-of-transfer summary info */
- /*****************************************************************************/
- static void xfer_summary(char *xfertype,char *fname,long *len,int y) {
- char buf[128];
-
- if (!un_attended || !fullscreen)
- gotoxy(2,y);
- else
- sb_move(filewin,y,2);
-
- sprintf(buf,"%s %12.12s; 0/%8ldb,%4d min. ",
- xfertype, fname, *len, (int)((*len*10/cur_baud*100/JANUS_EFFICIENCY+59)/60));
-
- if (!un_attended || !fullscreen) {
- cputs(buf);
- cputs(local_CEOL);
- update_y();
- } else {
- sb_puts(filewin,buf);
- sb_show();
- }
- }
-
-
- /*****************************************************************************/
- /* Update any status line values which have changed */
- /*****************************************************************************/
- static void update_status(long *pos,long *oldpos,long left,int *oldeta,int y) {
- char buf[16];
- register int eta;
-
- elapse_time();
-
- if (*pos != *oldpos) {
- sprintf(buf,"%8ld",*oldpos = *pos);
- if (!un_attended || !fullscreen) {
- gotoxy(POS_X,y);
- cputs(buf);
- } else {
- sb_move(filewin,y,POS_X);
- sb_puts(filewin,buf);
- }
- }
-
- eta = (int)((left*10/cur_baud*100/JANUS_EFFICIENCY+59)/60);
- if (eta != *oldeta) {
- sprintf(buf,"%4d",*oldeta = eta);
- if (!un_attended || !fullscreen) {
- gotoxy(ETA_X,y);
- cputs(buf);
- } else {
- sb_move(filewin,y,ETA_X);
- sb_puts(filewin,buf);
- }
- }
-
- if (un_attended && fullscreen)
- sb_show();
- }
-
- /*****************************************************************************/
- /* Compute and print throughput */
- /*****************************************************************************/
- static void through(long *bytes,long *started) {
- static byte *scrn = "+CPS: %u (%lu bytes) Efficiency: %lu%%%%";
- unsigned long elapsed;
- register word cps;
-
- elapsed = time(NULL) - *started;
- cps = (elapsed) ? (word)(*bytes/elapsed) : 0;
- j_status(scrn, cps, *bytes, cps*1000L/cur_baud);
- TotalBytes += *bytes;
- }
-
-
- /*****************************************************************************/
- /* Get next file to request, if any */
- /*****************************************************************************/
- static int get_filereq(byte req_started) {
- byte reqname[PATHLEN], linebuf[128];
- register byte *p;
- int gotone = FALSE;
- FILE *reqfile;
-
- if (flag_file (TEST_AND_SET, &called_addr, 1))
- return FALSE;
-
- strcpy(reqname,Abortlog_name);
- strcpy(strchr(reqname,'Z'),"REQ");
-
- if (req_started)
- mark_done(reqname);
-
- if (dexists(reqname)) {
- if (!(remote_capabilities & WZ_FREQ))
- j_status(msgtxt[M_FREQ_DECLINED]);
- else if (!(SharedCap & CANFREQ))
- j_status(msgtxt[M_REMOTE_CANT_FREQ]);
- else {
- errno = 0;
- reqfile = fopen(reqname,read_ascii);
- if (!j_error(msgtxt[M_OPEN_MSG],reqname)) {
- while (!feof(reqfile)) {
- linebuf[0] = '\0';
- if (!fgets(p = linebuf,sizeof(linebuf),reqfile))
- break;
- while (*p >= ' ')
- ++p;
- *p = '\0';
- if (linebuf[0] != ';') {
- strcpy(Rxbuf,linebuf);
- *(strchr(Rxbuf,'\0')+1) = SharedCap;
- gotone = TRUE;
- break;
- }
- }
- fclose(reqfile);
- j_error(msgtxt[M_CLOSE_MSG],reqname);
- if (!gotone) {
- unlink(reqname);
- j_error(msgtxt[M_UNLINK_MSG],reqname);
- }
- }
- }
- }
-
- return gotone;
- }
-
-
- /*****************************************************************************/
- /* Record names of files to send in response to file request; callback */
- /* routine for respond_to_file_requests() */
- /*****************************************************************************/
- static int record_reqfile(char *fname) {
- FILE *tmpfile;
-
- errno = 0;
- tmpfile = fopen(ReqTmp,"at");
- if (!j_error(msgtxt[M_OPEN_MSG],ReqTmp)) {
- fputs(fname,tmpfile);
- j_error(msgtxt[M_WRITE_MSG],ReqTmp);
- fputs("\n",tmpfile);
- j_error(msgtxt[M_WRITE_MSG],ReqTmp);
- fclose(tmpfile);
- j_error(msgtxt[M_CLOSE_MSG],ReqTmp);
- ++ReqRecorded;
- return TRUE;
- }
- return FALSE;
- }
-
-
- /*****************************************************************************/
- /* Get next file which was requested, if any */
- /*****************************************************************************/
- static byte get_reqname(byte first_req) {
- register byte *p;
- byte gotone = FALSE;
- FILE *tmpfile;
- struct stat f;
-
- if (!first_req) {
- errno = 0;
- close(Txfile);
- j_error(msgtxt[M_CLOSE_MSG],Txfname);
- Txfile = -1;
- mark_done(ReqTmp);
- }
-
- if (dexists(ReqTmp)) {
- errno = 0;
- tmpfile = fopen(ReqTmp,read_ascii);
- if (!j_error(msgtxt[M_OPEN_MSG],ReqTmp)) {
- while (!feof(tmpfile)) {
- Txfname[0] = '\0';
- if (!fgets(p = Txfname,PATHLEN,tmpfile))
- break;
- while (*p >= ' ')
- ++p;
- *p = '\0';
- if (Txfname[0] != ';') {
- j_status(msgtxt[M_SENDING],Txfname);
- errno = 0;
- Txfile = open(Txfname,O_RDONLY|O_BINARY);
- if (Txfile != -1)
- errno = 0;
- if (j_error(msgtxt[M_OPEN_MSG],Txfname))
- continue;
- while (p >= Txfname && *p != '\\' && *p != ':')
- --p;
- strcpy(Txbuf,++p);
- stat(Txfname,&f);
- sprintf(strchr(Txbuf,'\0')+1,"%lu %lo %o",Txlen = f.st_size,f.st_mtime,f.st_mode);
- if (!un_attended || !fullscreen)
- Tx_y = Next_y;
- else
- Tx_y = 1;
- xfer_summary(msgtxt[M_SEND],p,&Txlen,Tx_y);
- time(&Txsttime);
- gotone = TRUE;
- break;
- }
- }
- fclose(tmpfile);
- j_error(msgtxt[M_CLOSE_MSG],ReqTmp);
- if (!gotone) {
- unlink(ReqTmp);
- j_error(msgtxt[M_UNLINK_MSG],ReqTmp);
- }
- }
- }
-
- return gotone;
- }
-
-
- /*****************************************************************************/
- /* Mark first unmarked line of file as done (comment it out) */
- /*****************************************************************************/
- static void mark_done(char *fname) {
- byte linebuf[128];
- FILE *fh;
- long pos;
-
- if (dexists(fname)) {
- errno = 0;
- fh = fopen(fname,"rb+");
- if (!j_error(msgtxt[M_OPEN_MSG],fname)) {
- while (!feof(fh)) {
- pos = ftell(fh);
- j_error(msgtxt[M_SEEK_MSG],fname);
- if (!fgets(linebuf,sizeof(linebuf),fh))
- break;
- if (linebuf[0] != ';') {
- fseek(fh,pos,SEEK_SET);
- j_error(msgtxt[M_SEEK_MSG],fname);
- fputc(';',fh);
- j_error(msgtxt[M_WRITE_MSG],fname);
- break;
- }
- }
- fclose(fh);
- j_error(msgtxt[M_CLOSE_MSG],fname);
- }
- }
- }