/*
Copyright (C) Magna Carta Software, Inc., 1990. All Rights Reserved.
C COMMUNICATIONS TOOLKIT
RXXFER.C -- ROUTINES TO HANDLE FILE RECEPTION.
*/
#define CCT_DEVELOPMENT
#include <comm.h>
#if (defined(MSC) || defined(__WATCOMC__) || defined(_INTELC32_))
#include <malloc.h>
#elif defined(__TURBOC__) || defined(__POWERC)
#include <alloc.h>
#endif
#include <limits.h>
#include <kermit.h>
#include <xmodem.h>
#include <cctz.h>
/*
MSC v6.0A bugs force sub-optimization of this file
To see the problem, try $(C_OPT) instead of $(C_OPTR) in small model
*/
#if defined(_MSC_VER)
#pragma optimize("e", off)
#endif
char *ftempname = "temp0001.$$$";
char fname[PATHLEN]; /* received file name from remote */
unsigned long fsize; /* received file size from remote */
unsigned long fdate; /* received file dtae from remote */
/*
C_FPUTC_ -- Add a byte to the receive buffer. If it is full, write it to
disk. The disk write resets the buffer pointer.
Return value:
0 -- Normal return;
DISK_FULL -- insufficient disk space for file;
*/
short c_fputc_(COMM_PORT *p, short ch)
{
short ret = 0;
XFER *x = p->x;
#if XDEBUG
if (ch == '\0')
fputc(ch, stdout);
#endif
*x->pb = (BYTE) ch;
x->pb++;
if (x->pb > x->high) ret = c_fwrite_(p, x);
return ((short) ret);
}
/*
C_FWRITE_ -- Write the received data in x->buf to disk.
If high level flow control is enabled, it is used.
Return value:
0 -- no error;
DISK_FULL -- insufficient disk space to write file;
*/
short c_fwrite_(COMM_PORT *p, XFER *x)
{
short save_rts, save_dtr, f_xoff = FALSE;
short ret = 0;
#if XDEBUG
printf("\nEntering c_fwrite");
#endif
/* IF FLOW CONTROL IS ASSERTED, TURN FLOW OFF */
if (p->flowctl & TX) {
if (p->flowctl & TXONXOFF) {
if (p->inhold & TXONXOFF) {
p->inhold &= ~TXONXOFF;
f_xoff = TRUE;
}
else c_putc(p, p->xoffchar);
}
if (p->flowctl & TRTS_CTS) {
save_rts = get_rts(p);
set_rts(p, LOW);
}
if (p->flowctl & TDTR_DSR) {
save_dtr = get_dtr(p);
set_dtr(p, LOW);
}
ms_pause(150); /* wait for flow control to take effect */
}
ret = x->pb - x->buf;
x->pb = x->buf;
ret = cct_file_write_(x->fh, x->buf, ret);
if (ret == EOF) {
if (x->error != NULL) x->error[-DISK_FULL - XERROR_OFFSET]++;
if (x->p_user != NULL) (*x->p_user)(p, DISK_FULL, 0L);
ret = DISK_FULL;
}
if (ret > 0) ret = 0;
/* IF FLOW CONTROL IS ASSERTED, TURN FLOW ON */
if (p->flowctl & TX) {
if (p->flowctl & TXONXOFF) {
if (f_xoff) p->inhold |= TXONXOFF;
else c_putc(p, p->xonchar);
}
if (p->flowctl & TRTS_CTS) set_rts(p, save_rts);
if (p->flowctl & TDTR_DSR) set_dtr(p, save_dtr);
}
return ((short) ret);
}
/*
C_CALLOC_ -- Allocate memory for file receive buffer.
Return value:
0 -- normal return (success);
-1 -- Insufficient memory for receive buffer;
*/
short c_calloc_(XFER *x, unsigned bufsize)
{
short ret = 0;
DWORD ramavail = memavail();
ramavail = (memavail() > (DWORD) UINT_MAX) ? (DWORD) UINT_MAX : ramavail;
if (ramavail < MIN_BUFFER_SIZE + HEADROOM) ret = EOF;
else {
/* ADJUST BUFSIZE TO > MIN. */
bufsize = (bufsize > MIN_BUFFER_SIZE) ? bufsize : MIN_BUFFER_SIZE;
/* ADJUST BUFSIZE FOR AVAILABLE RAM */
if (ramavail < bufsize + HEADROOM) bufsize = (unsigned) ramavail - HEADROOM;
x->pb = x->buf = (char *) memcalloc(bufsize, sizeof(char));
x->len = bufsize; /* file receive buffer length */
x->high = x->buf + bufsize - MIN_BUFFER_SIZE/2; /* file receive buffer highwater mark */
#if XDEBUG
printf("\nx->buf is %Fp, x->high is %Fp\n", x->buf, x->high);
printf("\nThe buffer length (difference) is %ld, x->len is %Fp\n", x->high - x->buf, x->len);
#endif
}
return (ret);
}
/*
FRECEIVE - Receive files from a communications port.
Return value:
0 -- normal return (success);
-1 -- Insufficient memory for receive buffer;
-2 -- unable to open file;
*/
short freceive(COMM_PORT *p, XFER *x, short protocol, unsigned bufsize, short (CDECL_ *progress)(struct comm_port *, short, DWORD))
{
short ret = 0, f_flow = FALSE;
WORD save_kbd_clear;
p->x = x;
x->num_files = 0;
if ((ret = c_calloc_(x, bufsize)) != 0) return (ret);
if (!ret) {
save_kbd_clear = kbd_clear;
kbd_clear = TRUE;
if (x->ibdelay == 0) x->ibdelay = XFER_IBDELAY; /* initialize interbyte delay */
if (x->retries == 0) x->retries = XFER_RETRIES; /* init. retries */
if (progress != NULL) x->p_user = progress; /* enable progress reports */
x->error = a_xfer_errors; /* enable error recording */
/* CHOOSE THE FILE TRANSFER PROTOCOL */
switch(protocol) {
case ASCII:
ret = rx_ascii_(p);
break;
case KERMIT:
if (x->k == NULL) k_init(p, x, NULL);
ret = k_rcv_(x->k);
break;
case XMODEM:
x->chk = checksum;
x->poll = NAK;
x->protocol = XMODEM;
ret = rx_xmodem_(p, x);
break;
case XMODEM_CRC:
x->chk = crc_ccitt;
x->poll = 'C';
x->protocol = XMODEM_CRC;
ret = rx_xmodem_(p, x);
break;
case YMODEM:
case XMODEM_1K:
x->chk = crc_ccitt;
x->poll = 'C';
x->protocol = XMODEM_1K;
ret = rx_xmodem_(p, x);
break;
case YMODEM_G:
x->chk = crc_ccitt;
x->poll = 'G';
x->protocol = YMODEM_G;
/* IF NO FORM OF FLOW CONTROL IS BEING ASSERTED, USE XONXOFF */
if (!(p->flowctl & TX)) {
set_tx_xlat(p, FLOWCTL, XONXOFF);
f_flow = TRUE;
}
ret = rx_xmodem_(p, x);
if (f_flow) p->flowctl &= ~XONXOFF;
break;
case ZMODEM:
if (p->ppb == NULL) z_init(p, CANFDX | CANOVIO | CANBRK | CANFC32, 0, 0);
ret = z_receive_(p);
break;
case FAST:
break;
default:
break;
}
}
ffreebuf_(x);
kbd_clear = save_kbd_clear;
return (ret);
}