home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fred Fish Collection 1.5
/
ffcollection-1-5-1992-11.iso
/
ff_disks
/
500-599
/
ff589.lza
/
Term
/
TermSrc.lha
/
XPRQuickB
/
xprlib.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-09-02
|
16KB
|
647 lines
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* |_o_o|\\ Copyright (c) 1990 The Software Distillery. All Rights Reserved */
/* |. o.| || This program may not be distributed without the permission of */
/* | . | || the authors: BBS: (919) 382-8265 */
/* | o | || Dave Baker Alan Beale Jim Cooper */
/* | . |// Jay Denebeim Bruce Drake Gordon Keener */
/* ====== John Mainwaring Andy Mercier Jack Rouse */
/* John Toebes Mary Ellen Toebes Doug Walker Mike Whitcher */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "quickb.h"
#include <exec/memory.h>
static void miniterm(struct XPR_DATA *xd, char *startup);
static long setup_xd(struct XPR_IO *xio);
static void edit_opts(struct XPR_DATA *xd, char *buf);
static void set_optstr(struct XPR_DATA *xd, char *str);
/* protocol termination */
long __saveds __asm XProtocolCleanup(register __a0 struct XPR_IO *xio)
{
if (xio->xpr_data)
FreeMem(xio->xpr_data, (long)sizeof(struct XPR_DATA));
xio->xpr_data = 0;
return 1L;
}
/* protocol setup */
long __saveds __asm XProtocolSetup(register __a0 struct XPR_IO *xio)
{
struct XPR_DATA *xd;
char buf[256];
if (!setup_xd(xio)) return XPRS_FAILURE;
xd = (struct XPR_DATA *)xio->xpr_data;
if (xio->xpr_filename)
{
strcpy(buf, xio->xpr_filename);
set_optstr(xd, buf);
}
else
edit_opts(xd, buf);
return (xd->optAuto=='Y') ? XPRS_SUCCESS|XPRS_HOSTMON : XPRS_SUCCESS;
}
/* protocol send request */
long __saveds __asm XProtocolSend(register __a0 struct XPR_IO *xio)
{
if (!setup_xd(xio)) return 0L;
miniterm((struct XPR_DATA *)xio->xpr_data, "upl/proto:qb");
return 1L;
}
/* protocol receive request */
long __saveds __asm XProtocolReceive(register __a0 struct XPR_IO *xio)
{
if (!setup_xd(xio)) return 0L;
miniterm((struct XPR_DATA *)xio->xpr_data, "dow/proto:qb");
return 1L;
}
/* look for protocol initiation */
long __saveds __asm XProtocolHostMon(
register __a0 struct XPR_IO *xio,
register __a1 char *serbuff,
register __d0 long actual,
register __d1 long maxsize)
{
struct XPR_DATA *xd;
int c, lastc;
xd = (struct XPR_DATA *)xio->xpr_data;
if (!xd) return actual;
xd->nserbuf = actual;
xd->serbufp = serbuff;
while (--xd->nserbuf >= 0)
{
lastc = xd->cchar;
xd->cchar = c = *(xd->serbufp++) & 0x7F;
if (c == ENQ)
{
bp_ENQ(xd);
actual = 0;
}
else if (c == DLE)
{
bp_DLE(xd);
actual = 0;
}
else if (c == 'I' && lastc == 0x1B)
{
bp_ESC_I(xd);
actual = 0;
}
}
return actual;
}
long __saveds __asm XProtocolUserMon(
register __a0 struct XPR_IO *xio,
register __a1 char *serbuff,
register __d0 long actual,
register __d1 long maxsize)
{
return actual;
}
/* return failure */
static long Fail()
{
return 0L;
}
/* write an error message */
void errormsg(struct XPR_DATA *xd, char *msg)
{
xd->xpru.xpru_updatemask = XPRU_ERRORMSG;
xd->xpru.xpru_errormsg = msg;
(*xd->xpr_update)(&xd->xpru);
}
/* set up our data structures */
static long setup_xd(struct XPR_IO *xio)
{
struct XPR_UPDATE xpru;
register struct XPR_DATA *xd;
if (!xio->xpr_data)
{
if ((xio->xpr_data = AllocMem((long)sizeof(struct XPR_DATA),
MEMF_CLEAR)) == NULL)
{ /* no memory */
xpru.xpru_updatemask = XPRU_ERRORMSG;
xpru.xpru_errormsg = "Out of memory";
if (xio->xpr_update)
(*xio->xpr_update)(&xpru);
return 0L;
}
memset(xio->xpr_data, 0, sizeof(struct XPR_DATA));
xd = (struct XPR_DATA *)xio->xpr_data;
xd->xio = xio;
/* default options */
xd->maxiobuf = 16384; /* 16K buffer */
xd->optText = 'H'; /* use CompuServe suggestion */
xd->optOwrt = 'N'; /* use new file name */
xd->optAuto = 'Y'; /* activate automatically */
xd->optDelt = 'N'; /* don't delete after send */
xd->optKeep = (xio->xpr_extension >= 2L && xio->xpr_unlink)
? 'N'
: 'Y'; /* keep partial files */
}
else
xd = (struct XPR_DATA *)xio->xpr_data;
/* do some initialization */
xd->Done = xd->Aborting = FALSE;
xd->nserbuf = 0;
xd->iobuf = NULL;
xd->iobufn = 0;
/* following are optional */
xd->xpr_update = xio->xpr_update ? xio->xpr_update : Fail;
xd->xpr_chkabort = xio->xpr_chkabort ? xio->xpr_chkabort : Fail;
xd->xpr_chkmisc = xio->xpr_chkmisc ? xio->xpr_chkmisc : Fail;
xd->xpr_gets = xio->xpr_gets ? xio->xpr_gets : Fail;
xd->xpr_setserial = xio->xpr_setserial; /* NOTE! no default to fail */
xd->xpr_finfo = xio->xpr_finfo ? xio->xpr_finfo : Fail;
xd->xpr_options = (xio->xpr_extension >= 1L)
? xio->xpr_options : NULL;
xd->xpr_unlink = (xio->xpr_extension >= 2L)
? xio->xpr_unlink : NULL;
/* following are required */
if ((xd->xpr_fopen = xio->xpr_fopen) == NULL) goto lose;
if ((xd->xpr_fclose = xio->xpr_fclose) == NULL) goto lose;
if ((xd->xpr_fread = xio->xpr_fread) == NULL) goto lose;
if ((xd->xpr_fwrite = xio->xpr_fwrite) == NULL) goto lose;
if ((xd->xpr_sread = xio->xpr_sread) == NULL) goto lose;
if ((xd->xpr_swrite = xio->xpr_swrite) == NULL) goto lose;
return 1L;
lose:
errormsg(xd, "Insufficient XPR protocol support");
return 0L;
}
/* validate a boolean return value */
static int check_bool(struct XPR_DATA *xd, char *buf, char *which)
{
if (strcmp(buf, "ON") == 0)
buf[0] = 'Y';
else if (strcmp(buf, "OFF") == 0)
buf[0] = 'N';
return TRUE;
}
/* allow user to edit option string */
static void edit_opts(struct XPR_DATA *xd, char *buf)
{
char *p;
struct xpr_option *optptr[7];
struct xpr_option opt[7];
struct {
char Text[4];
char Owrt[4];
char Buff[8];
char Auto[4];
char Delt[4];
char Keep[4];
} optbuf;
register int i;
long status;
long l;
if (!xd->xpr_options)
{ /* format the current options */
p = buf;
*p++ = 'T'; *p++ = xd->optText; *p++ = ',';
*p++ = 'O'; *p++ = xd->optOwrt; *p++ = ',';
*p++ = 'B'; p += stcl_d(p, xd->maxiobuf >> 10); *p++ = ',';
*p++ = 'A'; *p++ = xd->optAuto; *p++ = ',';
*p++ = 'D'; *p++ = xd->optDelt; *p++ = ',';
*p++ = 'K'; *p++ = xd->optKeep; *p++ = '\0';
/* let the user edit it */
if ((*xd->xpr_gets)("Quick B options:", buf))
{ /* set the option string */
set_optstr(xd, buf);
}
return;
}
/* use the requester interface */
memset((char *)&optbuf, 0, sizeof(optbuf));
opt[0].xpro_description = "Quick B options:";
opt[0].xpro_type = XPRO_HEADER;
opt[0].xpro_value = NULL;
opt[0].xpro_length = 0;
optbuf.Text[0] = xd->optText;
opt[1].xpro_description = "Text mode (Y,N,H,C):";
opt[1].xpro_type = XPRO_STRING;
opt[1].xpro_value = optbuf.Text;
opt[1].xpro_length = sizeof(optbuf.Text);
optbuf.Owrt[0] = xd->optOwrt;
opt[2].xpro_description = "Overwrite mode (Y,N,S):";
opt[2].xpro_type = XPRO_STRING;
opt[2].xpro_value = optbuf.Owrt;
opt[2].xpro_length = sizeof(optbuf.Owrt);
stcl_d(optbuf.Buff, xd->maxiobuf >> 10);
opt[3].xpro_description = "I/O buffer size (KB):";
opt[3].xpro_type = XPRO_LONG;
opt[3].xpro_value = optbuf.Buff;
opt[3].xpro_length = sizeof(optbuf.Buff);
strcpy(optbuf.Auto, (xd->optAuto == 'Y') ? "yes" : "no");
opt[4].xpro_description = "Auto-activate transfers:";
opt[4].xpro_type = XPRO_BOOLEAN;
opt[4].xpro_value = optbuf.Auto;
opt[4].xpro_length = sizeof(optbuf.Auto);
strcpy(optbuf.Delt, (xd->optDelt == 'Y') ? "yes" : "no");
opt[5].xpro_description = "Delete after sending:";
opt[5].xpro_type = XPRO_BOOLEAN;
opt[5].xpro_value = optbuf.Delt;
opt[5].xpro_length = sizeof(optbuf.Delt);
strcpy(optbuf.Keep, (xd->optKeep == 'Y') ? "yes" : "no");
opt[6].xpro_description = "Keep partial files:";
opt[6].xpro_type = XPRO_BOOLEAN;
opt[6].xpro_value = optbuf.Keep;
opt[6].xpro_length = sizeof(optbuf.Keep);
/* prompt for options */
for (i = 0; i < 7; ++i)
optptr[i] = &opt[i];
status = (*xd->xpr_options)(7L, optptr);
if (status <= 0) return;
/* process options */
for (i = 1; i < 7; ++i)
{
if (!(status & (1 << i))) continue;
strupr(opt[i].xpro_value);
switch (i)
{
case 1: /* Text */
if (strchr("YNCH", optbuf.Text[0]))
xd->optText = optbuf.Text[0];
else
errormsg(xd, "Text option ignored");
break;
case 2: /* Overwrite */
if (strchr("YNS", optbuf.Owrt[0]))
xd->optOwrt = optbuf.Owrt[0];
else
errormsg(xd, "Overwrite option ignored");
break;
case 3: /* Buffer size */
stcd_l(optbuf.Buff, &l);
if (l < 0 || l > 0x7FFFFFFF >> 10)
errormsg(xd, "Buffer size ignored; out of range");
else
xd->maxiobuf = l << 10;
break;
case 4: /* Auto-Activate */
if (check_bool(xd, optbuf.Auto, "Auto-activate"))
xd->optAuto = optbuf.Auto[0];
break;
case 5: /* Delete after send */
if (check_bool(xd, optbuf.Delt, "Delete"))
{
if (optbuf.Delt[0] != 'Y' || xd->xpr_unlink)
xd->optDelt = optbuf.Delt[0];
else
errormsg(xd, "Delete option ignored; file deletion not available");
}
break;
case 6: /* Keep partial files */
if (check_bool(xd, optbuf.Keep, "Keep"))
{
if (optbuf.Keep[0] == 'Y' || xd->xpr_unlink)
xd->optKeep = optbuf.Keep[0];
else
errormsg(xd, "Keep option ignored; file deletion not available");
}
break;
}
}
return;
}
/* parse and merge option string with current settings */
static void set_optstr(struct XPR_DATA *xd, char *str)
{
long l;
/* convert to upper case for simpler parsing */
strupr(str);
for (;;)
{
str += strspn(str, " ,");
switch (*str++)
{
case 'T': /* text mode */
if (strchr("YNCH", *str))
xd->optText = *str;
else
errormsg(xd, "T option ignored; use TY, TN, TH, or TC");
break;
case 'O': /* overwrite */
if (strchr("YNS", *str))
xd->optOwrt = *str;
else
errormsg(xd, "O option ignored; use OY, ON, or OS");
break;
case 'B': /* buffer size */
str += stcd_l(str, &l);
if (l < 0 || l > 0x7FFFFFFF >> 10)
errormsg(xd, "Buffer size ignored; out of range");
else
xd->maxiobuf = l << 10;
break;
case 'A': /* auto-activate */
if (strchr("YN", *str))
xd->optAuto = *str;
else
errormsg(xd, "A option ignored; use AY or AN");
break;
case 'D': /* delete after send */
if (!strchr("YN", *str))
errormsg(xd, "D option ignored; use DY or DN");
else if (*str == 'Y' && !xd->xpr_unlink)
errormsg(xd, "DY option ignored; file deletion not available");
else
xd->optDelt = *str;
break;
case 'K': /* keep partial receives */
if (strchr("YN", *str))
xd->optKeep = *str;
else
errormsg(xd, "K option ignored; use KY or KN");
break;
default:
return;
}
/* skip rest of option */
str += strcspn(str, " ,");
}
}
void cputc(struct XPR_DATA *xd, int c)
{
char ch = c;
(*xd->xpr_swrite)(&ch, 1L);
}
/* called by cgetc macro to refill the buffer */
int cfilbuf(struct XPR_DATA *xd, long timeout)
{
long n;
n = (*xd->xpr_sread)(xd->serbuf, (long)MAX_SERBUF, 0L);
if (n <= 0)
n = (*xd->xpr_sread)(xd->serbuf, 1L, timeout);
if (n <= 0)
return -1;
xd->nserbuf = n-1;
xd->serbufp = &xd->serbuf[1];
return (int)xd->serbuf[0];
}
static void miniterm(struct XPR_DATA *xd, char *startup)
{
int c = -1;
int lastc;
char buf[256];
char prompt[1024];
char *p;
int i;
int to;
/* get the startup line */
strcpy(buf, startup);
if ((*xd->xpr_gets)("Startup line", buf))
{
for (p = buf; *p; ++p)
cputc(xd, *p);
cputc(xd, '\r');
}
xd->xpru.xpru_updatemask = XPRU_MSG;
xd->xpru.xpru_msg = "Entering protocol";
(*xd->xpr_update)(&xd->xpru);
i = 0;
to = 0;
do {
lastc = c;
c = cgetc(xd, 1000000L);
if (c < 0)
{ /* timed out */
if (++to == 10)
break;
if (to == 1 && i > 0)
{
prompt[i] = 0;
buf[0] = 0;
strcpy(buf, xd->xio->xpr_filename);
if ((*xd->xpr_gets)(prompt, buf))
{
for (p = buf; *p; ++p)
cputc(xd, *p);
cputc(xd, '\r');
}
i = 0;
}
}
else
{
to = 0;
if (c == ENQ)
bp_ENQ(xd);
else if (c == DLE)
bp_DLE(xd);
else if (c == 'I' && lastc == 0x1B)
bp_ESC_I(xd);
else if (c == '\n')
{
prompt[i] = 0;
xd->xpru.xpru_updatemask = XPRU_MSG;
xd->xpru.xpru_msg = prompt;
(*xd->xpr_update)(&xd->xpru);
i = 0;
}
else if (c != '\r' && i < sizeof(prompt)-1)
prompt[i++] = c;
}
if ((*xd->xpr_chkabort)())
xd->Aborting = TRUE;
} while (!xd->Done && !xd->Aborting);
xd->xpru.xpru_updatemask = XPRU_MSG;
xd->xpru.xpru_msg = "Timed out";
if (!xd->Done && !xd->Aborting)
(*xd->xpr_update)(&xd->xpru);
/* reset last character so HostMon isn't confused */
xd->cchar = -1;
}
/* open buffered file */
long bfopen(struct XPR_DATA *xd, char *filename, char *mode)
{
long file;
file = (*xd->xpr_fopen)(filename, mode);
if (!file) return file;
if (xd->maxiobuf)
{
xd->iobuf = AllocMem(xd->maxiobuf, 0L);
if (xd->iobuf == NULL)
errormsg(xd, "Not enough memory to buffer I/O");
}
if (!xd->iobuf || mode[0] == 'r')
{
xd->iobufn = 0; /* bytes available */
xd->writing = FALSE;
}
else
{
xd->iobufn = 0; /* bytes used */
xd->writing = TRUE;
}
xd->iobufp = xd->iobuf;
return file;
}
/* buffered file close */
long bfclose(struct XPR_DATA *xd, long file)
{
if (xd->writing && xd->iobufn)
(*xd->xpr_fwrite)(xd->iobuf, xd->iobufn, 1L, file);
if (xd->iobuf)
FreeMem(xd->iobuf, xd->maxiobuf);
xd->iobuf = NULL;
return (*xd->xpr_fclose)(file);
}
/* buffered file read */
long bfread(struct XPR_DATA *xd, char *buf, long len, long file)
{
register long n;
register long remain;
if (xd->iobuf == NULL)
return (*xd->xpr_fread)(buf, 1L, 1*len, file);
remain = len;
while (remain > 0)
{
if (xd->iobufn <= 0)
{ /* refill buffer */
xd->iobufn = (*xd->xpr_fread)(xd->iobuf, 1L,
xd->maxiobuf, file);
if (xd->iobufn <= 0)
return len - remain;
xd->iobufp = xd->iobuf;
}
n = min(xd->iobufn, remain);
memcpy(buf, xd->iobufp, (unsigned)n);
xd->iobufp += n;
xd->iobufn -= n;
buf += n;
remain -= n;
}
return len;
}
/* buffered file read, with optional text processing */
long xbfread(struct XPR_DATA *xd, char *buf, long len, long file)
{
unsigned char c;
long n;
if (!xd->TextMode)
return bfread(xd, buf, len, file);
for (n = 0; n < len; ++n)
{
if (xd->TextC >= 0)
{
buf[n] = xd->TextC;
xd->TextC = -1;
}
else if (bfread(xd, (char *)&c, 1L, file) != 1)
break;
else if (c == LF)
{
buf[n] = CR;
xd->TextC = LF;
}
else
buf[n] = c;
}
return n;
}
/* buffered file write */
long bfwrite(struct XPR_DATA *xd, char *buf, long len, long file)
{
register long n;
register long remain;
if (xd->iobuf == NULL)
return (*xd->xpr_fwrite)(buf, 1L, 1*len, file);
remain = len;
for (;;)
{
if (xd->iobufn >= xd->maxiobuf)
{ /* flush buffer */
n = (*xd->xpr_fwrite)(xd->iobuf, xd->iobufn, 1L, file);
if (n != 1)
return -1;
xd->iobufn = 0;
xd->iobufp = xd->iobuf;
}
if (remain <= 0) break;
n = xd->maxiobuf - xd->iobufn;
if (n > remain) n = remain;
memcpy(xd->iobufp, buf, (unsigned)n);
xd->iobufp += n;
xd->iobufn += n;
buf += n;
remain -= n;
}
return len;
}
/* buffered file write with optional text processing */
long xbfwrite(struct XPR_DATA *xd, char *buf, long len, long file)
{
register int i;
if (!xd->TextMode)
return bfwrite(xd, buf, len, file);
if (xd->TextC == CPMEOF)
return len;
for (i = 0; i < len; ++i)
{
if (xd->TextC == CR && buf[i] != LF)
{ /* carriage return not part of CR-LF */
if (bfwrite(xd, "\n", 1, file) != 1)
return i;
}
xd->TextC = buf[i];
if (buf[i] == CPMEOF)
break;
if (buf[i] != CR && bfwrite(xd, &buf[i], 1, file) != 1)
return i;
}
return len;
}