/* Copyright (C) Magna Carta Software, Inc. 1990, 1991. All Rights Reserved. C TELECOMM TOOLKIT v1.0 TXXFER.C -- File send routines. */ #define CCT_DEVELOPMENT #if (defined(CCTW) || defined(_WINDOWS)) #include #endif #include #include #include #include #include #include #include #if (defined(MSC) || defined(__WATCOMC__) || defined(_INTELC32_)) #include #elif defined(__TURBOC__) || defined(__POWERC) #include #endif #define issent(a) ((a->f_status) & F_SENT) /* C_FPEEKC_ -- "Peek at the next byte from the send buffer or, if it is empty, refill it from the file on disk. Keep MIN_BUFFER_SIZE characters from the last refill in the buffer in case of required resends. Return value: Normal return -- the next character in the buffer; No more characters -- EOF; This does not work in TC v2.0 or TC++ small model: if (x->pb < x->buf + x->len) ch = (BYTE) *x->pb++; ** */ short c_fpeekc_(XFER *x) { char *pfbuf, *oldbuf; short ch = 0; unsigned i = 0; unsigned count = 0; /* AT START OF FILE -- LOAD BUFFER */ if (x->f_pos == 1) { if ((x->fh = cct_file_open_(x->fspec, O_RDONLY | O_BINARY)) == 0) return (NO_FILE); count = cct_file_read_(x->fh, x->buf, x->len); if (count > 0) { x->pb = x->buf; x->f_pos = FALSE; } else ch = EOF; } if (ch != EOF) { if ((unsigned) (x->pb - x->buf) < x->len) ch = (BYTE) *x->pb; else if (x->origin == RAM) ch = EOF; /* SENDING FROM RAM */ else { /* SENDING FROM DISK */ if (x->f_pos == EOF) ch = EOF; else { pfbuf = x->buf; oldbuf = x->pb - (MIN_BUFFER_SIZE/2); for (i=0; i< MIN_BUFFER_SIZE/2; i++) *pfbuf++ = *oldbuf++; x->len -= MIN_BUFFER_SIZE/2; count = cct_file_read_(x->fh, pfbuf, x->len); if (count > 0) { x->len = i + count; x->pb = &x->buf[MIN_BUFFER_SIZE/2]; ch = (BYTE) *x->pb; } else ch = x->f_pos = EOF; /* EOF flag set here */ } } } return (ch); } /* C_FGETC_ -- Get a byte from the send buffer or, if it is empty, refill it from the file on disk. Keep MIN_BUFFER_SIZE characters from the last refill in the buffer in case of required resends. Return value: Normal return -- the next character in the buffer; No more characters -- EOF; This does not work in TC v2.0 or TC++ small model: if (x->pb < x->buf + x->len) ch = (BYTE) *x->pb++; ** */ short c_fgetc_(XFER *x) { short ch; ch = c_fpeekc_(x); x->pb++; return (ch); } /* FUNLOAD -- Free memory allocated for the file transfer buffer. Close the file specified by 'fname'. Unload its XFER_FILE structure from RAM. Return code: 0 -- Success -1 -- Unable to close file; -2 -- XFER_FILE is NULL; */ short funload(XFER *x, const char *fname) { short ret = 0; if (x->xf == NULL) ret = EOF; if (!ret) { ffreebuf_(x); /* free memory used by the buffer */ ret = cct_file_close_(x->fh); /* close the file/stream */ if (!ret) ret = funqueue(x, fname); } return (ret); } /* FMAKEBUF_ -- Called from fsend(). Finds the next file to send. Creates a buffer. Return value: 0 -- normal return (success). 'n' indicates number of files sent; NO_FILE -- no files queued to send; EOF -- unable to read file; NO_RAM -- insufficient memory for file transfer buffer (less than MIN_BUFFER_SIZE) */ short fmakebuf_(XFER *x, WORD len) { XFER_FILE *xf; DWORD ramavail; unsigned buflen; short ret; if (x == NULL || x->xf == NULL) return (NO_FILE); if (x->buf != NULL) funload(x, NULL); /* previous file still around! */ xf = x->xf; /* WADDLE FORWARD TO THE FIRST UNSENT FILE */ while (xf->next != NULL && issent(xf) == TRUE) xf = xf->next; if (issent(xf) == TRUE) return (NO_FILE); x->fspec = xf->fspec; x->xf_current = xf; /* COMPLETE FILE INFORMATION IN STRUCTURE */ ret = cct_file_stat_(xf->fspec, &x->stat); if (ret == EOF) return (EOF); /* GET AVAILABLE MEMORY */ ramavail = memavail() - HEADROOM; /* IF INSUFFICIENT RAM, RETURN WITH ERROR */ if (ramavail < MIN_BUFFER_SIZE) return (NO_RAM); /* SET BUFFER SIZE */ if (len > MIN_BUFFER_SIZE) buflen = (len < (unsigned) ramavail) ? len : (unsigned) ramavail; else buflen = (unsigned) ramavail; if (x->stat.st_size < (off_t) buflen) { /* SEND THE WHOLE FILE FROM RAM */ if ((x->buf = memcalloc((size_t) x->stat.st_size, sizeof(char))) == NULL) return (NO_RAM); x->len = (unsigned) x->stat.st_size; x->origin = RAM; } else { /* NOT ENOUGH ROOM TO MOVE WHOLE FILE TO RAM -- MOVE PART OF IT */ if ((x->buf = memcalloc(buflen, sizeof(char))) == NULL) return (NO_RAM); x->len = buflen; x->origin = DISK; } /* SET FLAG TO INDICATE START OF FILE */ x->f_pos = 1; return (0); } /* FSEND -- Sends all files queued with fqueue(). Return value: >=0 -- normal return (success). 'n' indicates number of files sent; -1 -- No files queued (XFER_FILE structure is null); -2 -- No files queued (XFER_FILE structure is null); -3 -- unable to open file; -4 -- Insufficient memory for file fransfer buffer (less than MIN_BUFFER_SIZE) -5 -- file length does not match number of bytes read; -6 -- file transfer started OK -- still in progress under TX interrupts; */ short fsend(COMM_PORT *p, XFER *x, short protocol, unsigned len, short (CDECL_ *progress)(struct comm_port *, short, DWORD)) { short ret = 0; WORD save_kbd_clear; char sxlat[XLAT_SIZE]; p->x = x; x->maxlen = x->len = len; if (x->ibdelay == 0) x->ibdelay = 10000; /* initialize interbyte delay */ x->p_user = progress; /* enable progress reports */ x->error = a_xfer_errors; /* enable error recording */ save_kbd_clear = kbd_clear; kbd_clear = TRUE; save_xlat(p, sxlat); p->rx_xlat = ON; p->tx_xlat = ON; /* CHOOSE THE FILE TRANSFER PROTOCOL */ x->protocol = protocol; switch(protocol) { case ASCII: ret = ascii_send_(p, x, len, progress); break; case KERMIT: if (x->k == NULL) k_init(p, x, NULL); ret = k_send_(x->k, x, len, progress); break; case XMODEM: case XMODEM_CRC: case XMODEM_1K: case YMODEM: case YMODEM_G: ret = x_tx_(p, x, protocol, len, progress); break; case ZMODEM: if (p->ppb == NULL) z_init(p, CANFDX | CANOVIO | CANBRK | CANFC32, 0, 0); z_send_(p); break; default: break; } ret = (ret < 0) ? EOF : ret; /* FILE TRANSFER COMPLETED -- CLEAN UP */ if (!p->f_txbusy) { ll_delete_list(x->xf); ffreebuf_(x); } rest_xlat(p, sxlat); kbd_clear = save_kbd_clear; return (ret); }