You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
610 lines
17 KiB
610 lines
17 KiB
/* File: C:\WACKER\xfer\hpr_snd1.c (Created: 26-Jan-1994)
|
|
* created from HAWIN source file
|
|
* hpr_snd1.c -- Routines to provide HyperProtocol file send function in
|
|
* HyperACCESS.
|
|
*
|
|
* Copyright 1989,1994 by Hilgraeve Inc. -- Monroe, MI
|
|
* All rights reserved
|
|
*
|
|
* $Revision: 1 $
|
|
* $Date: 10/05/98 1:16p $
|
|
*/
|
|
|
|
#include <windows.h>
|
|
#include <stdlib.h>
|
|
#include <setjmp.h>
|
|
#include <time.h>
|
|
#include <term\res.h>
|
|
#include <sys\types.h>
|
|
#include <sys\utime.h>
|
|
|
|
#include <tdll\stdtyp.h>
|
|
#include <tdll\mc.h>
|
|
#include <tdll\load_res.h>
|
|
#include <tdll\xfer_msc.h>
|
|
#include <tdll\globals.h>
|
|
#include <tdll\file_io.h>
|
|
|
|
#if !defined(BYTE)
|
|
#define BYTE unsigned char
|
|
#endif
|
|
|
|
#include "itime.h"
|
|
#include "cmprs.h"
|
|
|
|
#include "xfr_dsp.h"
|
|
#include "xfr_todo.h"
|
|
#include "xfr_srvc.h"
|
|
|
|
#include "xfer.h"
|
|
#include "xfer.hh"
|
|
#include "xfer_tsc.h"
|
|
|
|
#include "hpr.h"
|
|
#include "hpr.hh"
|
|
#include "hpr_sd.hh"
|
|
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* hs_namecheck
|
|
*
|
|
* DESCRIPTION:
|
|
* This function is called to check the extension on a filename and to guess
|
|
* if it should be compressed or not.
|
|
*
|
|
* ARGUEMENTS:
|
|
* ft -- struct s_ftbl *, contains the name and gets the flag value
|
|
*
|
|
* RETURNS:
|
|
* Nothing, but may set flags in the structure passed as arguement
|
|
*/
|
|
void hs_namecheck(struct s_ftbl *ft)
|
|
{
|
|
BYTE *ptr;
|
|
|
|
if (strlen(ft->fname) < 5)
|
|
return;
|
|
|
|
ptr = ft->fname + strlen(ft->fname) - 4;
|
|
if (*ptr++ != '.')
|
|
return;
|
|
|
|
/* the extensions we are currently checking for are:
|
|
* ARC
|
|
* LZH
|
|
* PAK
|
|
* ZIP
|
|
* ZOO
|
|
*/
|
|
#if FALSE
|
|
/* TODO: replace with something else ANSI compatible */
|
|
if ((strnicmp(ptr, "ARC", 3) == 0) ||
|
|
(strnicmp(ptr, "LZH", 3) == 0) ||
|
|
(strnicmp(ptr, "PAK", 3) == 0) ||
|
|
(strnicmp(ptr, "ZIP", 3) == 0) ||
|
|
(strnicmp(ptr, "ZOO", 3) == 0))
|
|
bitset(ft->cntrl, FTC_DONT_CMPRS);
|
|
#endif
|
|
|
|
}
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* hs_filebreak
|
|
*
|
|
* DESCRIPTION:
|
|
* Handles changes to the currently open file. This routine is called whenever
|
|
* the data loading routine gets an EOF while attempting to load the next
|
|
* data character. This can happen when the program first starts or when
|
|
* a file is exhausted or when a file error is encountered. It can also
|
|
* occur artificially when, for example, a restart is requested to force
|
|
* a change in file or file position.
|
|
*
|
|
* ARGUMENTS:
|
|
* nfiles -- Total number of files expected to be sent during this transfer.
|
|
* This is only used in the initial (file 0) control message.
|
|
* nbytes -- Total number of bytes expected to be sent during this transfer.
|
|
* This is only used in the initial (file 0) control message.
|
|
*
|
|
* RETURNS:
|
|
* nothing
|
|
*/
|
|
void hs_filebreak(struct s_hc *hc, int nfiles, long nbytes)
|
|
{
|
|
BYTE str[90];
|
|
BYTE name_to_send[FNAME_LEN];
|
|
struct s_ftbl *ft;
|
|
|
|
/* we've either hit a real EOF, or the restart routine
|
|
has backed us up into an aborted file, or we're just
|
|
starting, or we've encountered a file error, or user cancelled.
|
|
*/
|
|
omsg_new(hc, 'C');
|
|
if (hc->datacnt > 0)
|
|
{
|
|
/* put partial block record in message */
|
|
wsprintf(str, "P%u,%u", hc->datacnt,
|
|
(hc->usecrc ? hc->h_crc : hc->h_checksum));
|
|
omsg_add(hc, str);
|
|
hc->datacnt = hc->h_crc = hc->h_checksum = 0;
|
|
}
|
|
|
|
if (hc->ucancel || hc->sc.rmtcancel)
|
|
{
|
|
hpr_id_get(hc, str);
|
|
omsg_add(hc, str);
|
|
omsg_add(hc, "X");
|
|
hs_waitack(hc);
|
|
}
|
|
|
|
if (hc->current_filen == 0)
|
|
{
|
|
/* just getting started or need to start over */
|
|
/* put 'V', 'B', 'D', 'N', and 'S' records in message */
|
|
hpr_id_get(hc, str); /* add 'V' field */
|
|
omsg_add(hc, str);
|
|
wsprintf(str, "B%d;D%d;N%u;S%lu", hc->blocksize,
|
|
(int)(hc->deadmantime / 10), nfiles, nbytes);
|
|
omsg_add(hc, str);
|
|
}
|
|
else
|
|
{
|
|
#if FALSE
|
|
/* TODO: put this back in later */
|
|
if (fio_error(hc->fhdl))
|
|
{
|
|
/* print error message on the screen */
|
|
hc->sc.hs_ftbl[hc->sc.ft_current].status = TSC_DISK_ERROR;
|
|
}
|
|
#endif
|
|
if (hc->sc.hs_ftbl[hc->sc.ft_current].status != TSC_OK)
|
|
{
|
|
strcpy(str, "A");
|
|
omsg_add(hc, str);
|
|
}
|
|
}
|
|
|
|
/* scan up the file table looking for first non-cancelled file or
|
|
* for top of table
|
|
*/
|
|
while (++hc->sc.ft_current <= hc->sc.ft_top
|
|
&& hc->sc.hs_ftbl[hc->sc.ft_current].status != TSC_OK)
|
|
{
|
|
xfer_name_to_send(hc->hSession,
|
|
hc->sc.hs_ftbl[hc->sc.ft_current].fname,
|
|
name_to_send);
|
|
wsprintf(str, "F%u,%s",
|
|
hc->current_filen = hc->sc.hs_ftbl[hc->sc.ft_current].filen,
|
|
name_to_send);
|
|
omsg_add(hc, str);
|
|
/* put size field in so rcvr can keep display accurate */
|
|
wsprintf(str, "s%lu", hc->sc.hs_ftbl[hc->sc.ft_current].flength);
|
|
omsg_add(hc, str);
|
|
omsg_send(hc, 1, hc->usecrc, FALSE);
|
|
/* now that we've started this file, tell receiver to abort it
|
|
* right away since its status is no longer TSC_OK
|
|
*/
|
|
omsg_new(hc, 'C');
|
|
strcpy(str, "A");
|
|
omsg_add(hc, str);
|
|
}
|
|
|
|
/* Now we should be ready for next file. We're either pointing at a
|
|
* normal file in the table to be restarted or we're at the top
|
|
* of the table and its time to open the next file
|
|
*/
|
|
hc->sc.hs_ptrgetc = hs_getc;
|
|
/* set pointer into table for speed */
|
|
ft = &hc->sc.hs_ftbl[hc->sc.ft_current];
|
|
if (hc->sc.ft_current <= hc->sc.ft_top)
|
|
{
|
|
/* try to reopen a file from the table */
|
|
hc->current_filen = ft->filen;
|
|
if (hc->fhdl != NULL && hc->sc.ft_current == hc->sc.ft_open)
|
|
{
|
|
/* file is already open */
|
|
fio_seek(hc->fhdl, 0, FIO_SEEK_SET);
|
|
}
|
|
else
|
|
{
|
|
/* reopen previously opened file */
|
|
if (hc->fhdl)
|
|
{
|
|
fio_close(hc->fhdl);
|
|
}
|
|
hc->fhdl = NULL;
|
|
hc->sc.ft_open = hc->sc.ft_current;
|
|
hc->current_filen = ft->filen;
|
|
hc->h_filebytes = hc->sc.bytes_sent = 0L;
|
|
hc->total_dsp = ft->dsp_bytes;
|
|
hc->total_thru = ft->thru_bytes;
|
|
if (xfer_opensendfile(hc->hSession, &hc->fhdl, ft->fname,
|
|
&ft->flength, NULL, NULL) != 0)
|
|
{
|
|
/* display error */
|
|
ft->status = TSC_CANT_OPEN;
|
|
hc->sc.hs_ptrgetc = hs_reteof;
|
|
hc->sc.ft_open = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
else if (xfer_nextfile(hc->hSession, name_to_send))
|
|
{
|
|
/* There are no more previously started files in the table to be
|
|
* restarted, but there is another brand new file to send
|
|
*/
|
|
if (hc->sc.ft_top >= hc->sc.ft_limit)
|
|
{
|
|
hsdsp_event(hc, HSE_FULL);
|
|
hsdsp_status(hc, HSS_WAITACK);
|
|
omsg_add(hc, "I");
|
|
omsg_send(hc, 1, hc->usecrc, FALSE);
|
|
omsg_new(hc, 'C');
|
|
HS_XMIT_FLUSH(hc);
|
|
while(hc->sc.ft_top >= hc->sc.ft_limit)
|
|
{
|
|
hs_background(hc); /* wait for space in table */
|
|
hs_logx(hc, FALSE);
|
|
}
|
|
hsdsp_event(hc, HSE_GOTACK);
|
|
hsdsp_status(hc, HSS_SENDING);
|
|
/* items may shift in hs_ftbl during hs_background */
|
|
ft = &hc->sc.hs_ftbl[hc->sc.ft_current];
|
|
}
|
|
|
|
/* open next file and install it in the table */
|
|
if (hc->fhdl)
|
|
{
|
|
fio_close(hc->fhdl);
|
|
}
|
|
hc->fhdl = NULL;
|
|
strcpy(ft->fname, name_to_send);
|
|
|
|
ft->filen = ++hc->current_filen;
|
|
ft->cntrl = 0;
|
|
ft->status = TSC_OK;
|
|
hs_namecheck(ft);
|
|
hc->total_dsp = ft->dsp_bytes =
|
|
hc->sc.hs_ftbl[hc->sc.ft_top].dsp_bytes +
|
|
hc->sc.hs_ftbl[hc->sc.ft_top].flength;
|
|
hc->total_thru = ft->thru_bytes =
|
|
hc->sc.hs_ftbl[hc->sc.ft_top].thru_bytes + hc->h_filebytes;
|
|
|
|
hc->sc.ft_top = hc->sc.ft_open = hc->sc.ft_current;
|
|
|
|
hc->h_filebytes = hc->sc.bytes_sent = 0;
|
|
if (xfer_opensendfile(hc->hSession, &hc->fhdl, ft->fname, &ft->flength,
|
|
NULL, NULL) != 0)
|
|
{
|
|
/* display error? */
|
|
hc->fhdl = NULL;
|
|
ft->status = TSC_CANT_OPEN;
|
|
hc->sc.ft_open = -1;
|
|
hc->sc.hs_ptrgetc = hs_reteof;
|
|
}
|
|
}
|
|
else /* no more files in table and no new files to send */
|
|
{
|
|
if (hc->fhdl)
|
|
{
|
|
fio_close(hc->fhdl);
|
|
}
|
|
hc->sc.ft_open = -1;
|
|
hc->fhdl = NULL;
|
|
--hc->sc.ft_current; /* don't point off top of table */
|
|
hsdsp_event(hc, HSE_DONE);
|
|
omsg_add(hc, "E");
|
|
hs_waitack(hc);
|
|
}
|
|
|
|
/* put file name and attribute records in message */
|
|
xfer_name_to_send(hc->hSession, ft->fname, name_to_send);
|
|
wsprintf(str, "F%d,%s", ft->filen, name_to_send);
|
|
omsg_add(hc, str);
|
|
wsprintf(str, "s%lu", ft->flength);
|
|
omsg_add(hc, str);
|
|
|
|
if (hc->fhdl)
|
|
{
|
|
unsigned long ftime;
|
|
struct tm *pT;
|
|
|
|
ftime = itimeGetFileTime(ft->fname);
|
|
ftime += itimeGetBasetime(); /* fudge for C 7 and later */
|
|
pT = localtime(&ftime);
|
|
wsprintf(str, "t%d,%d,%d,%d,%d,%d",
|
|
pT->tm_year + 1900,
|
|
pT->tm_mon,
|
|
pT->tm_mday,
|
|
pT->tm_hour,
|
|
pT->tm_min,
|
|
pT->tm_sec);
|
|
omsg_add(hc, str);
|
|
|
|
#if FALSE
|
|
if (hc->sc.rmt_compress && h_trycompress &&
|
|
!bittest(ft->cntrl, FTC_DONT_CMPRS) &&
|
|
ft->flength > CMPRS_MINSIZE &&
|
|
compress_start(&hc->sc.hs_ptrgetc, &h_filebytes, FALSE))
|
|
#endif
|
|
if (hc->sc.rmt_compress && hc->h_trycompress &&
|
|
!bittest(ft->cntrl, FTC_DONT_CMPRS) &&
|
|
ft->flength > CMPRS_MINSIZE &&
|
|
compress_start(&hc->sc.hs_ptrgetc, hc, &hc->h_filebytes, FALSE))
|
|
{
|
|
hsdsp_compress(hc, ON);
|
|
/* hsdsp_status(hc, HSS_SENDING); */
|
|
omsg_add(hc, "C");
|
|
bitset(ft->cntrl, FTC_COMPRESSED);
|
|
}
|
|
else
|
|
{
|
|
hsdsp_compress(hc, OFF);
|
|
bitclear(ft->cntrl, FTC_COMPRESSED);
|
|
}
|
|
}
|
|
omsg_send(hc, 1, hc->usecrc, FALSE);
|
|
|
|
HS_XMIT_FLUSH(hc);
|
|
hsdsp_newfile(hc, ft->filen, ft->fname, ft->flength);
|
|
hsdsp_progress(hc, 0);
|
|
}
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* hs_waitack
|
|
*
|
|
* DESCRIPTION:
|
|
* Called at the end of a transfer to wait for the final acknowldgement from
|
|
* receiver or until a restart message forces us to back up and retransmit
|
|
* some of the data. This routine never returns directly to its caller. It
|
|
* always exits by way of a longjmp either during a hs_background call if
|
|
* an 'END' or 'RESTART' message is received or at the end of the function
|
|
* if it times out without receiving either message.
|
|
*
|
|
* ARGUMENTS:
|
|
* none
|
|
*
|
|
* RETURNS:
|
|
* nothing (see DESCRIPTION)
|
|
*/
|
|
void hs_waitack(struct s_hc *hc)
|
|
{
|
|
long timer;
|
|
|
|
omsg_send(hc, 1, hc->usecrc, FALSE);
|
|
hc->sc.receiver_timedout = FALSE;
|
|
HS_XMIT_FLUSH(hc);
|
|
hsdsp_status(hc, HSS_WAITACK);
|
|
timer = startinterval();
|
|
|
|
|
|
/* wait for 60 seconds, until longjmp either restarts or ends transfer */
|
|
while (interval(timer) < FINAL_ACK_WAIT)
|
|
{
|
|
hs_background(hc);
|
|
if (hc->sc.receiver_timedout)
|
|
{
|
|
/* receiver must have missed our end of transfer message */
|
|
omsg_send(hc, 1, hc->usecrc, FALSE);
|
|
HS_XMIT_FLUSH(hc);
|
|
hc->sc.receiver_timedout = FALSE;
|
|
}
|
|
}
|
|
/* if we get here, we didn't get response from receiver for 60 seconds */
|
|
hsdsp_event(hc, HSE_NORESP);
|
|
longjmp(hc->sc.jb_bailout, TSC_NO_RESPONSE);
|
|
}
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* hs_decode_rmsg
|
|
*
|
|
* DESCRIPTION:
|
|
* Called by hs_rcvmsg when a complete message has been received. This routine
|
|
* parses and interprets the message either by recording information sent by
|
|
* the receiver or by altering the course of the transfer in response to an
|
|
* interruption message. There may be several fields in a message but note
|
|
* that certain messages transfer control elsewhere via a longjmp and thus
|
|
* prevent any subsequent fields from being scanned ('E', 'X', and 'R'
|
|
* messages specifically). All messages from the receiver to the sender are
|
|
* sent in printable characters.
|
|
*
|
|
* ARGUMENTS:
|
|
* data -- A string containing the messages to be interpreted. Each message
|
|
* is in the form of: 'T<data>;'
|
|
* where T is a single character message identifier and <data> is
|
|
* optional associated information.
|
|
*
|
|
* RETURNS:
|
|
* nothing
|
|
* (exits via a longjmp when certain interruption messages are received)
|
|
*/
|
|
void hs_decode_rmsg(struct s_hc *hc, BYTE *data)
|
|
{
|
|
BYTE *field;
|
|
int filenum;
|
|
int mnum;
|
|
int tval;
|
|
|
|
if (data[0] != 'c') /* this is the only kind we know about now but don't */
|
|
return; /* consider it an error if newer versions send */
|
|
/* other types */
|
|
|
|
mnum = unchar(data[2]);
|
|
field = strtok(&data[3], ";");
|
|
while (field != NULL)
|
|
{
|
|
switch(*field++)
|
|
{
|
|
case 'f': /* receiver has successfully received file fn */
|
|
hs_fileack(hc, atoi(field));
|
|
break;
|
|
case 'B': /* receiver is requesting a particular block size */
|
|
if (hc->current_filen == 0)
|
|
{
|
|
tval = atoi(field);
|
|
tval = max(tval, H_MINBLOCK);
|
|
hc->blocksize = min(hc->blocksize, tval);
|
|
}
|
|
break;
|
|
case 'D': /* receiver is requesting a particular deadman time */
|
|
tval = atoi(field);
|
|
tval = max(tval, H_MINDEADMAN);
|
|
hc->deadmantime = min(hc->deadmantime, tval * 10);
|
|
break;
|
|
case 'T': /* receiver is requesting check type */
|
|
hc->sc.rmtchkt = atoi(field);
|
|
break;
|
|
case 'C': /* receiver is agreeing to do compression */
|
|
if (!*field)
|
|
hc->sc.rmt_compress = TRUE;
|
|
break;
|
|
case 'E': /* receiver is acknowledging end of transfer */
|
|
hc->xfertime = interval(hc->xfertimer);
|
|
if (*field)
|
|
hs_fileack(hc, atoi(field));
|
|
hsdsp_event(hc, HSE_GOTACK);
|
|
if (!hc->ucancel && !hc->sc.rmtcancel)
|
|
longjmp(hc->sc.jb_bailout, TSC_COMPLETE);
|
|
else
|
|
longjmp(hc->sc.jb_bailout,
|
|
hc->ucancel ? TSC_USER_CANNED : TSC_RMT_CANNED);
|
|
break;
|
|
case 'X': /* receiver is requesting a cancellation of the xfer */
|
|
if (*field)
|
|
hs_fileack(hc, atoi(field));
|
|
hsdsp_event(hc, HSE_RMTCANCEL);
|
|
hc->sc.rmtcancel = TRUE;
|
|
hc->sc.hs_ptrgetc = hs_reteof;
|
|
break;
|
|
case 'A': /* receiver is aborting a single file */
|
|
hs_fileack(hc, filenum = atoi(field)); /* all earlier files ok */
|
|
|
|
/* If we're still sending the file being cancelled, mark it
|
|
* cancelled and set the character function pointer to hs_reteof
|
|
* to force a switch to the next file, if any.
|
|
* If we've already finished sending the file being cancelled,
|
|
* look it up in the file table and mark if cancelled so that
|
|
* if we're asked to back up into it, we won't bother resending
|
|
* it
|
|
*/
|
|
if (hc->current_filen == filenum)
|
|
{
|
|
hc->sc.hs_ftbl[hc->sc.ft_current].status = TSC_RMT_CANNED;
|
|
hc->sc.hs_ptrgetc = hs_reteof; /* force switch to next file */
|
|
}
|
|
else
|
|
{
|
|
/* we're no longer sending file being canned */
|
|
for (tval = hc->sc.ft_current; tval >= 0; --tval)
|
|
if (hc->sc.hs_ftbl[tval].filen == filenum)
|
|
hc->sc.hs_ftbl[tval].status = TSC_RMT_CANNED;
|
|
}
|
|
break;
|
|
|
|
case 'V':
|
|
tval = atoi(field);
|
|
field = strchr(field, ',');
|
|
|
|
/* if version restrictions were found, stop the transfer */
|
|
if (!hpr_id_check(hc, tval, ++field))
|
|
{
|
|
hsdsp_event(hc, HSE_RMTCANCEL);
|
|
hc->sc.rmtcancel = TRUE;
|
|
hc->sc.hs_ptrgetc = hs_reteof;
|
|
}
|
|
break;
|
|
|
|
case 'R': /* receiver is requesting a restart */
|
|
if (!hc->sc.started)
|
|
{
|
|
hsdsp_event(hc, HSE_GOTSTART);
|
|
hc->sc.started = TRUE;
|
|
}
|
|
else
|
|
{
|
|
hsdsp_event(hc, HSE_GOTRETRY);
|
|
hsdsp_retries(hc, ++hc->total_tries);
|
|
}
|
|
tval = atoi(strtok(field, ",")); /* get file number */
|
|
hs_fileack(hc, tval);
|
|
hs_dorestart(hc, tval, atoi(strtok(NULL, ",")), mnum, FALSE);
|
|
break;
|
|
|
|
case 't': /* receiver stopped receiving data */
|
|
hc->sc.receiver_timedout = TRUE;
|
|
break;
|
|
}
|
|
field = strtok(NULL, ";");
|
|
}
|
|
}
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* hs_fileack
|
|
*
|
|
* DESCRIPTION:
|
|
* Marks all transmitted files up to a specified file number as acknowledged,
|
|
* that is, as transmitted completely. This routine merely marks the files
|
|
* in the file table as complete; completed entries will be removed from the
|
|
* table later by hs_logx.
|
|
*
|
|
* ARGUMENTS:
|
|
* n -- The file number that the receiver considers current. All file numbers
|
|
* lower than this can be considered complete.
|
|
*
|
|
* RETURNS:
|
|
* nothing
|
|
*/
|
|
void hs_fileack(struct s_hc *hc, int n)
|
|
{
|
|
register int ix = 0;
|
|
|
|
while (ix <= hc->sc.ft_current)
|
|
{
|
|
if (ix <= hc->sc.ft_limit && hc->sc.hs_ftbl[ix].filen < n)
|
|
bitset(hc->sc.hs_ftbl[ix].cntrl, FTC_CONFIRMED);
|
|
++ix;
|
|
}
|
|
}
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* hs_logx
|
|
*
|
|
* DESCRIPTION:
|
|
* Logs either all acknowledged transfers or all transfers to the log file
|
|
* and removes their entries from the file table. Note that the values of
|
|
* hc->sc.ft_top, hc->sc.ft_current, and hc->sc.ft_open can change during this
|
|
* operation.
|
|
*
|
|
* ARGUMENTS:
|
|
* all -- if TRUE, log all regardless of confirmation
|
|
*
|
|
* RETURNS:
|
|
* nothing
|
|
*/
|
|
void hs_logx(struct s_hc *hc, int all)
|
|
{
|
|
struct s_ftbl *ftptr = &hc->sc.hs_ftbl[0];
|
|
|
|
while (hc->sc.ft_top >= 0 && (all ||
|
|
(hc->sc.ft_current > 1 && bittest(hc->sc.hs_ftbl[0].cntrl,FTC_CONFIRMED))))
|
|
{
|
|
if (ftptr->filen > 0)
|
|
{
|
|
if (ftptr->status == TSC_OK &&
|
|
!bittest(ftptr->cntrl,FTC_CONFIRMED))
|
|
ftptr->status = TSC_ERROR_LIMIT;
|
|
xfer_log_xfer(hc->hSession,
|
|
TRUE,
|
|
ftptr->fname,
|
|
NULL,
|
|
ftptr->status);
|
|
}
|
|
MemCopy((char *)&hc->sc.hs_ftbl[0], (char *)&hc->sc.hs_ftbl[1],
|
|
(unsigned)hc->sc.ft_top * sizeof(struct s_ftbl));
|
|
--hc->sc.ft_top;
|
|
--hc->sc.ft_current;
|
|
--hc->sc.ft_open;
|
|
}
|
|
}
|
|
|
|
/************************** end of hpr_snd1.c ************************/
|