/*
* Modifications Copyright 1996, 1999, 2000, 2001, 2002, 2004 by Paul Mattes.
* Copyright Octover 1995 by Dick Altenbern.
* Based in part on code Copyright 1993, 1994, 1995 by Paul Mattes.
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose and without fee is hereby granted,
* provided that the above copyright notice appear in all copies and that
* both that copyright notice and this permission notice appear in
* supporting documentation.
*
* x3270, c3270, s3270 and tcl3270 are distributed in the hope that they will
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the file LICENSE
* for more details.
*/
/*
* tc_dft.c
* File transfer: DFT-style data processing functions
*/
#include "globals.h"
#if defined(X3270_FT) /*[*/
#include "appres.h"
#include "3270ds.h"
#include "ft_dft_ds.h"
#include "actionsc.h"
#include "kybdc.h"
#include "ft_dftc.h"
#include "ftc.h"
#include "tablesc.h"
#include "telnetc.h"
#include "trace_dsc.h"
#include "utilc.h"
#include <errno.h>
extern unsigned char aid;
/* Macros. */
#define OPEN_MSG "FT:MSG" /* Open request for message */
#define END_TRANSFER "TRANS03" /* Message for xfer complete */
#define DFT_MIN_BUF 256
#define DFT_MAX_BUF 32768
/* Typedefs. */
struct data_buffer {
char sf_length[2]; /* SF length = 0x0023 */
char sf_d0; /* 0xD0 */
char sf_request_type[2]; /* request type */
char compress_indic[2]; /* 0xc080 */
char begin_data; /* 0x61 */
char data_length[2]; /* Data Length in 3270 byte order+5 */
char data[256]; /* The actual data */
};
/* Globals. */
int dft_buffersize = 0; /* Buffer size (LIMIN, LIMOUT) */
/* Statics. */
static Boolean message_flag = False; /* Open Request for msg received */
static int eof;
static unsigned long recnum;
static char *abort_string = CN;
static unsigned char *dft_savebuf = NULL;
static int dft_savebuf_len = 0;
static int dft_savebuf_max = 0;
static void dft_abort(const char *s, unsigned short code);
static void dft_close_request(void);
static void dft_data_insert(struct data_buffer *data_bufr);
static void dft_get_request(void);
static void dft_insert_request(void);
static void dft_open_request(unsigned short len, unsigned char *cp);
static void dft_set_cur_req(void);
static int filter_len(char *s, register int len);
/* Process a Transfer Data structured field from the host. */
void
ft_dft_data(unsigned char *data, int length unused)
{
struct data_buffer *data_bufr = (struct data_buffer *)data;
unsigned short data_length, data_type;
unsigned char *cp;
if (ft_state == FT_NONE) {
trace_ds(" (no transfer in progress)\n");
return;
}
/* Get the length. */
cp = (unsigned char *)(data_bufr->sf_length);
GET16(data_length, cp);
/* Get the function type. */
cp = (unsigned char *)(data_bufr->sf_request_type);
GET16(data_type, cp);
/* Handle the requests */
switch (data_type) {
case TR_OPEN_REQ:
dft_open_request(data_length, cp);
break;
case TR_INSERT_REQ: /* Insert Request */
dft_insert_request();
break;
case TR_DATA_INSERT:
dft_data_insert(data_bufr);
break;
case TR_SET_CUR_REQ:
dft_set_cur_req();
break;
case TR_GET_REQ:
dft_get_request();
break;
case TR_CLOSE_REQ:
dft_close_request();
break;
default:
trace_ds(" Unsupported(0x%04x)\n", data_type);
break;
}
}
/* Process an Open request. */
static void
dft_open_request(unsigned short len, unsigned char *cp)
{
char *name = "?";
char namebuf[8];
char *s;
unsigned short recsz = 0;
if (len == 0x23) {
name = (char *)cp + 25;
} else if (len == 0x29) {
unsigned char *recszp;
recszp = cp + 27;
GET16(recsz, recszp);
name = (char *)cp + 31;
} else {
dft_abort(get_message("ftDftUknownOpen"), TR_OPEN_REQ);
return;
}
(void) memcpy(namebuf, name, 7);
namebuf[7] = '\0';
s = &namebuf[6];
while (s >= namebuf && *s == ' ') {
*s-- = '\0';
}
if (recsz) {
trace_ds(" Open('%s',recsz=%u)\n", namebuf, recsz);
} else {
trace_ds(" Open('%s')\n", namebuf);
}
if (!strcmp(namebuf, OPEN_MSG))
message_flag = True;
else {
message_flag = False;
ft_running(False);
}
eof = False;
recnum = 1;
/* Acknowledge the Open. */
trace_ds("> WriteStructuredField FileTransferData OpenAck\n");
obptr = obuf;
space3270out(6);
*obptr++ = AID_SF;
SET16(obptr, 5);
*obptr++ = SF_TRANSFER_DATA;
SET16(obptr, 9);
net_output();
}
/* Process an Insert request. */
static void
dft_insert_request(void)
{
trace_ds(" Insert\n");
/* Doesn't currently do anything. */
}
/* Process a Data Insert request. */
static void
dft_data_insert(struct data_buffer *data_bufr)
{
/* Received a data buffer, get the length and process it */
int my_length;
unsigned char *cp;
if (!message_flag && ft_state == FT_ABORT_WAIT) {
dft_abort(get_message("ftUserCancel"), TR_DATA_INSERT);
return;
}
cp = (unsigned char *) (data_bufr->data_length);
/* Get the data length in native format. */
GET16(my_length, cp);
/* Adjust for 5 extra count */
my_length -= 5;
trace_ds(" Data(rec=%lu) %d bytes\n", recnum, my_length);
/*
* First, check to see if we have message data or file data.
* Message data will result in a popup.
*/
if (message_flag) {
/* Data is from a message */
unsigned char *msgp;
unsigned char *dollarp;
/* Get storage to copy the message. */
msgp = (unsigned char *)Malloc(my_length + 1);
/* Copy the message. */
memcpy(msgp, data_bufr->data, my_length);
/* Null terminate the string. */
dollarp = (unsigned char *)memchr(msgp, '$', my_length);
if (dollarp != NULL)
*dollarp = '\0';
else
*(msgp + my_length) = '\0';
/* If transfer completed ok, use our msg. */
if (memcmp(msgp, END_TRANSFER, strlen(END_TRANSFER)) == 0) {
Free(msgp);
ft_complete((String)NULL);
} else if (ft_state == FT_ABORT_SENT && abort_string != CN) {
Free(msgp);
ft_complete(abort_string);
Replace(abort_string, CN);
} else {
ft_complete((char *)msgp);
Free(msgp);
}
} else if (my_length > 0) {
/* Write the data out to the file. */
int rv = 1;
if (ascii_flag && remap_flag) {
/* Filter. */
unsigned char *s = (unsigned char *)data_bufr->data;
unsigned len = my_length;
while (len--) {
*s = ft2asc[*s];
s++;
}
}
if (ascii_flag && cr_flag) {
char *s = (char *)data_bufr->data;
unsigned len = my_length;
/* Delete CRs and ^Zs. */
while (len) {
unsigned l = filter_len(s, len);
if (l) {
rv = fwrite(s, l, (size_t)1,
ft_local_file);
if (rv == 0)
break;
ft_length += l;
}
if (l < len)
l++;
s += l;
len -= l;
}
} else {
rv = fwrite((char *)data_bufr->data, my_length,
(size_t)1, ft_local_file);
ft_length += my_length;
}
if (!rv) {
/* write failed */
char *buf;
buf = xs_buffer("write(%s): %s", ft_local_filename,
strerror(errno));
dft_abort(buf, TR_DATA_INSERT);
Free(buf);
}
/* Add up amount transferred. */
ft_update_length();
}
/* Send an acknowledgement frame back. */
trace_ds("> WriteStructuredField FileTransferData DataAck(rec=%lu)\n", recnum);
obptr = obuf;
space3270out(12);
*obptr++ = AID_SF;
SET16(obptr, 11);
*obptr++ = SF_TRANSFER_DATA;
SET16(obptr, TR_NORMAL_REPLY);
SET16(obptr, TR_RECNUM_HDR);
SET32(obptr, recnum);
recnum++;
net_output();
}
/* Process a Set Cursor request. */
static void
dft_set_cur_req(void)
{
trace_ds(" SetCursor\n");
/* Currently doesn't do anything. */
}
/* Process a Get request. */
static void
dft_get_request(void)
{
int numbytes;
size_t numread;
size_t total_read = 0;
unsigned char *bufptr;
trace_ds(" Get\n");
if (!message_flag && ft_state == FT_ABORT_WAIT) {
dft_abort(get_message("ftUserCancel"), TR_GET_REQ);
return;
}
/* Read a buffer's worth. */
set_dft_buffersize();
space3270out(dft_buffersize);
numbytes = dft_buffersize - 27; /* always read 5 bytes less than we're allowed */
bufptr = obuf + 17;
while (!eof && numbytes) {
if (ascii_flag && cr_flag) {
int c;
/* Read one byte and do CR/LF translation. */
c = fgetc(ft_local_file);
if (c == EOF) {
break;
}
if (!ft_last_cr && c == '\n') {
*bufptr++ = '\r';
numbytes--;
total_read++;
}
if (numbytes) {
ft_last_cr = (c == '\r');
*bufptr++ = remap_flag? asc2ft[c]: c;
numbytes--;
total_read++;
} else {
ungetc(c, ft_local_file);
}
} else {
/* Binary read. */
numread = fread(bufptr, 1, numbytes, ft_local_file);
if (numread <= 0) {
break;
}
if (ascii_flag && remap_flag) {
unsigned char *s = bufptr;
int i = numread;
while (i) {
*s = asc2ft[*s];
s++;
i--;
}
}
bufptr += numread;
numbytes -= numread;
total_read += numread;
}
if (feof(ft_local_file) || ferror(ft_local_file)) {
break;
}
}
/* Check for read error. */
if (ferror(ft_local_file)) {
char *buf;
buf = xs_buffer("read(%s): %s", ft_local_filename,
strerror(errno));
dft_abort(buf, TR_GET_REQ);
Free(buf);
return;
}
/* Set up SF header for Data or EOF. */
obptr = obuf;
*obptr++ = AID_SF;
obptr += 2; /* skip SF length for now */
*obptr++ = SF_TRANSFER_DATA;
if (total_read) {
trace_ds("> WriteStructuredField FileTransferData Data(rec=%lu) %d bytes\n",
recnum, total_read);
SET16(obptr, TR_GET_REPLY);
SET16(obptr, TR_RECNUM_HDR);
SET32(obptr, recnum);
recnum++;
SET16(obptr, TR_NOT_COMPRESSED);
*obptr++ = TR_BEGIN_DATA;
SET16(obptr, total_read + 5);
obptr += total_read;
ft_length += total_read;
if (feof(ft_local_file)) {
eof = True;
}
} else {
trace_ds("> WriteStructuredField FileTransferData EOF\n");
*obptr++ = HIGH8(TR_GET_REQ);
*obptr++ = TR_ERROR_REPLY;
SET16(obptr, TR_ERROR_HDR);
SET16(obptr, TR_ERR_EOF);
eof = True;
}
/* Set the SF length. */
bufptr = obuf + 1;
SET16(bufptr, obptr - (obuf + 1));
/* Save the data. */
dft_savebuf_len = obptr - obuf;
if (dft_savebuf_len > dft_savebuf_max) {
dft_savebuf_max = dft_savebuf_len;
Replace(dft_savebuf, (unsigned char *)Malloc(dft_savebuf_max));
}
(void) memcpy(dft_savebuf, obuf, dft_savebuf_len);
aid = AID_SF;
/* Write the data. */
net_output();
ft_update_length();
}
/* Process a Close request. */
static void
dft_close_request(void)
{
/*
* Recieved a close request from the system.
* Return a close acknowledgement.
*/
trace_ds(" Close\n");
trace_ds("> WriteStructuredField FileTransferData CloseAck\n");
obptr = obuf;
space3270out(6);
*obptr++ = AID_SF;
SET16(obptr, 5); /* length */
*obptr++ = SF_TRANSFER_DATA;
SET16(obptr, TR_CLOSE_REPLY);
net_output();
}
/* Abort a transfer. */
static void
dft_abort(const char *s, unsigned short code)
{
Replace(abort_string, NewString(s));
trace_ds("> WriteStructuredField FileTransferData Error\n");
obptr = obuf;
space3270out(10);
*obptr++ = AID_SF;
SET16(obptr, 9); /* length */
*obptr++ = SF_TRANSFER_DATA;
*obptr++ = HIGH8(code);
*obptr++ = TR_ERROR_REPLY;
SET16(obptr, TR_ERROR_HDR);
SET16(obptr, TR_ERR_CMDFAIL);
net_output();
/* Update the pop-up and state. */
ft_aborting();
}
/* Returns the number of bytes in s, limited by len, that aren't CRs or ^Zs. */
static int
filter_len(char *s, register int len)
{
register char *t = s;
while (len && *t != '\r' && *t != 0x1a) {
len--;
t++;
}
return t - s;
}
/* Processes a Read Modified command when there is upload data pending. */
void
dft_read_modified(void)
{
if (dft_savebuf_len) {
trace_ds("> WriteStructuredField FileTransferData\n");
obptr = obuf;
space3270out(dft_savebuf_len);
memcpy(obptr, dft_savebuf, dft_savebuf_len);
obptr += dft_savebuf_len;
net_output();
}
}
/* Update the buffersize for generating a Query Reply. */
void
set_dft_buffersize(void)
{
if (dft_buffersize == 0) {
dft_buffersize = appres.dft_buffer_size;
if (dft_buffersize == 0)
dft_buffersize = DFT_BUF;
}
if (dft_buffersize > DFT_MAX_BUF)
dft_buffersize = DFT_MAX_BUF;
if (dft_buffersize < DFT_MIN_BUF)
dft_buffersize = DFT_MIN_BUF;
}
#endif /*]*/
syntax highlighted by Code2HTML, v. 0.9.1