Metropoli BBS
VIEWER: rxxfer.c MODE: TEXT (ASCII)
/*
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);
}
[ RETURN TO DIRECTORY ]