[alt.sources] xcomm 2.2, part 3 of 3

karl@triceratops.cis.ohio-state.edu (Karl Kleinpaste) (09/28/88)

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	src
# This archive created: Tue Sep 27 17:13:53 1988
# By:	Karl Kleinpaste (OSU)
export PATH; PATH=/bin:$PATH
if test ! -d 'src'
then
	echo shar: creating directory "'src'"
	mkdir 'src'
fi
echo shar: entering directory "'src'"
cd 'src'
echo shar: extracting "'xcport.c'" '(9678 characters)'
if test -f 'xcport.c'
then
	echo shar: will not over-write existing file "'xcport.c'"
else
sed 's/^X//' << \SHAR_EOF > 'xcport.c'
X/*
X    Module:	xcport.c	XCOMM Modem Interface Routines
X
X    This code is purely public domain!
X*/
X
X#include <stdio.h>
X#include <signal.h>
X#include <fcntl.h>
X#include <termio.h>
X#include <string.h>
X#include <sys/types.h>
X#include <errno.h>
X
X#include "xcomm.h"
X
X/*
X    The dial() routine uses these two defines.
X
X    DIALSTR is a sprintf format string that assumes a HAYES-compatible
X    modem.
X
X    HAYSATT is the HAYES "attention" signal (used if DTR_DROPS_CARRIER
X    is not set to 1).
X
X    HAYSHUP is the HAYES "hangup" command (used if DTR_DROPS_CARRIER is not
X    set to 1).
X
X    MDELAY is the delay in the output because (on my modem) the command
X    would be ignored if sent at full speed.  Change for other setups.
X    (This setting is for U.S. Robotics Password Modem).
X*/
X
X#define DIALSTR "\rATDT %s\r"   /* format string for Hayes-type modem */
X#define HAYSATT "+++"		/* Hayes "attention" signal */
X#define	HAYSHUP	"ATH\r"		/* Hayes "hang up" command */
X#define MDELAY  20000           /* delay for output to modem itself */
X
X/* globals */
X
Xextern int tfp;			/* TTY file pointer */
Xint bitmask = 0xFF;             /* modem port i/o data mask */
Xint flowflag = 0;               /* modem port i/o data mask */
X
Xstatic int mfd = -1;            /* modem port file descriptor */
Xstatic struct termio pmode;	/* modem device control string */
Xstatic char port[NMSIZE];       /* modem port device file string */
Xstatic int baudrate = B1200;	/* baud rate */
X
Xint cpmode()
X{
X    pmode.c_iflag |= IGNBRK;
X
X    pmode.c_lflag = 0;
X#ifdef XCLUDE
X    pmode.c_lflag |= XCLUDE;
X#endif
X    pmode.c_oflag = 0;	/* Transparent output */
X
X    pmode.c_cflag = baudrate | CS8 | CREAD | CLOCAL;
X
X    pmode.c_cc[VMIN] = 1; 	/* This many chars satisfies reads */
X    pmode.c_cc[VTIME] = 1;	/* or in this many tenths of seconds */
X
X    xc_setflow();
X}
X
Xint xc_setxon(mode)
X{
X    cpmode();
X
X    if (mode) {
X	pmode.c_iflag |= IXON | IXOFF;
X	pmode.c_iflag &= ~IXANY;
X    } else
X	pmode.c_iflag &= ~(IXON | IXOFF | IXANY);
X
X    if(mfd != -1)
X	ioctl(mfd, TCSETAW, &pmode);
X}
X
Xint xc_flowtoggle()
X{
X    flowflag = 1 - flowflag;
X
X    xc_setflow();
X}
X
Xxc_setflow()
X{
X    if (flowflag) {
X	pmode.c_iflag |= IXON | IXOFF;
X	pmode.c_iflag &= ~IXANY;
X    } else
X	pmode.c_iflag &=~(IXON | IXOFF | IXANY);
X
X    if (mfd != -1)
X	ioctl(mfd, TCSETAW, &pmode);
X}
X
Xchar *mport(s)  /* get/set port string */
Xchar *s;
X{
X    if(s != NULL && mfd == -1)
X        strcpy(port, s);
X    return(port);
X}
X
X/* Get/set the baud rate of the modem port. If the port hasn't been opened yet,
X * just store in pmode for mopen() to use when it opens the port.
X */
Xint mbaud(s)
Xchar *s;
X{
X    cpmode();
X
X    if(s != NULL){
X        /* this gives a more limited, realistic range than in sgtty.h */
X        switch (atoi(s)) {
X        case  300: baudrate = B300;  break;
X        case 1200: baudrate = B1200; break;
X        case 2400: baudrate = B2400; break;
X        case 9600: baudrate = B9600; break;
X        default:   return(-1);
X        }
X	pmode.c_cflag &= ~CBAUD;
X	pmode.c_cflag |= baudrate;
X
X        if(mfd != -1)
X            ioctl(mfd, TCSETAW, &pmode);
X    }
X
X    switch(pmode.c_cflag & CBAUD){
X    case  B300: return(300);
X    case B1200: return(1200);
X    case B2400: return(2400);
X    case B9600: return(9600);
X    }
X
X    fprintf(tfp,"Impossible error in baud rate.\n");
X    return(0);
X}
X
X/*
X    The following routine is used to hang up the modem.  This is
X    accomplished by setting the baud rate to 0.  According to my
X    documentation on termio, setting the baud rate to zero will
X    result in DTR not being asserted.  This hangs up some (most?)
X    modems.  If not, the second part of the routine sends the Hayes
X    modem "escape" and then a hangup command.
X*/
X
Xvoid hangup()
X{
X    if (mfd == -1)
X	return;
X
X    fprintf(tfp,"<< HANGUP >>\r\n");
X    fflush(stdout);
X
X#if DTR_DROPS_CARRIER
X    pmode.c_cflag &= ~CBAUD;
X    pmode.c_cflag |= B0;	/* set baud 0 (drop DTR) */
X    ioctl(mfd, TCSETAW, &pmode);
X
X    sleep(1);			/* wait a minute */
X
X    pmode.c_cflag &= ~CBAUD;	/* reset baud rate */
X    pmode.c_cflag |= baudrate;
X    ioctl(mfd, TCSETAW, &pmode);
X#else	/* use Hayes command */
X    sleep(2);			/* Allow for "escape guard time" */
X    send_slowly(HAYSATT);	/* Send modem escape command */
X
X    sleep(3);			/* More "escape guard time" */
X    send_slowly(HAYSHUP);	/* Send hangup command */
X#endif
X}
X
X/* Opens the modem port and configures it. If the port string is
X * already defined it will use that as the modem port;  otherwise it
X * gets the environment variable MODEM. Returns 0 for success
X * or -1 on error.
X */
X
Xstatic int	  opened = 0;
X
Xint mopen()
X{
X    char *p, *getenv();
X    int oldflags;
X
X    cpmode();
X
X    if(port[0] == '\0'){
X        if((p = getenv("MODEM")) == NULL)
X            return(-1);
X        strcpy(port, p);
X    }
X
X    if (lock_tty()) {
X	fprintf(stderr, "Modem device is locked -- try later.\r\n");
X	return -1;
X    }
X
X    /* Need O_NDELAY to get the file open before we have carrier */
X    if((mfd = open(port, O_RDWR | O_NDELAY)) < 0) {
X	perror("mopen()");
X	unlock_tty();
X        return -1;
X	}
X
X    /* Now, we must reset the O_NDELAY mode so that read() works correctly */
X    if ( ((oldflags = fcntl(mfd, F_GETFL, 0)) == -1) ||
X	 (fcntl(mfd, F_SETFL, oldflags & ~O_NDELAY) == -1) ) {
X		perror("mopen can not reset O_NDELAY");
X		unlock_tty();
X		return -1;
X		}
X
X    ioctl(mfd, TCFLSH, 2);
X    ioctl(mfd, TCSETAW, &pmode);
X
X    opened++;
X
X    return(0);
X}
X
X#if !HAVE_DUP2		/* For those that do not have dup2()... */
Xint dup2(oldfd, newfd)
Xint oldfd, newfd;
X{
X        if (fcntl(oldfd, F_GETFL, 0) == -1)     /* Valid file descriptor? */
X                return (-1);                    /* No, return an error. */
X        close(newfd);                           /* Ensure newfd is closed */
X        return (fcntl(oldfd, F_DUPFD, newfd));  /* Dup oldfd into newfd */
X}
X#endif /* !HAVE_DUP2  Thanks to Bill Allie CIS: 76703,2061 */
X
X/* Attach standard input and output to the modem port. This only gets called
X * after a fork by the child process; which then exec's a program that uses
X * standard i/o for some data transfer protocol. (To put this here is actually
X * a kludge, but I wanted to keep the modem-specific stuff in a black box.)
X */
Xmattach()       /* attach standard i/o to port */
X{
X    dup2(mfd, 0);       /* close local stdin and connect to port */
X    dup2(mfd, 1);       /* close local stdout and connect to port */
X
X    close(mfd);         /* close the old port descriptor */
X}
X
Xint readbyte(seconds)
Xint seconds;
X{
X    return trminp(mfd, seconds);
X}
X
X/*
X    Read a byte using bitmask
X*/
X
Xread_mbyte(secs)
X{
X    int c;
X
X    return (c = readbyte(secs)) == -1 ? -1 : c & bitmask;
X}
X
X/* Output a byte to the modem port.
X * All data sent to the modem is output through this routine.
X */
Xsendbyte(ch)
Xint ch;
X{
X    char c = ch & 0xff;
X
X    write(mfd, &c, 1);
X}
X
Xsend_mbyte(ch)
X{
X    sendbyte(ch & bitmask);
X}
X
X/* Dial a phone number, using proper format and delay.
X */
X
Xstatic char *last_nbr = NULL;
Xchar *strdup();
X
Xdial(s)
Xchar *s;
X{
X    char buffer[WBSIZE];
X
X    if (last_nbr) 
X	free(last_nbr);
X
X    last_nbr = strdup(s);
X
X    sprintf(buffer, DIALSTR, s);
X    send_slowly(buffer);
X}
X
Xredial(last_nbr)
X char *last_nbr;
X{
X    char *s;
X
X    if (last_nbr == NULL) {
X	fprintf(tfp,"REDIAL FAILURE\r\n");
X	return 1;
X    }
X
X    s = strdup(last_nbr);
X    dial(s);
X    free(s);
X    return 0;
X}
X
Xsend_slowly(s)
X char *s;
X{
X    int i;
X
X/*
X    This busy-waiting, normally a bad idea on a multi-tasking system,
X    was used because sleep(1) is way too much of a delay.
X*/
X    while(*s){
X        send_mbyte(*s++);
X        for(i = 0; i < MDELAY; i++)
X            ;
X    }
X}
X
X/*
X    I have had requests to support the LCK..ttyxx files that CU and UUCP
X    tend to support.  I do not have any need for such code, and am not
X    exactly sure how the code should work.  I have therefore placed these
X    two entry points for some enterprising coder to code so that the lock
X    files may be created and destroyed.
X
X    lock_tty() returns non-zero if the lock file exists (prevents XCOMM from
X    running).
X
X    unlock_tty() deletes the lock file.
X
X    Simple, eh?
X*/
X
Xchar lckf[40] = "/usr/spool/locks/LCK..";
Xchar ltmp[40] = "/usr/spool/locks/LTMP.";
X
Xlock_tty()
X{
X    int pid, lckpid, lfd;
X    char pidstr[20];
X    char lckpidstr[20];
X    char *modemname;
X    extern int errno;
X
X    /*
X     * Get our PID, and initialize the filename strings.
X     */
X    pid = getpid();
X    sprintf(pidstr, "%d", pid);
X    modemname = strrchr(port, '/');
X    strcat(lckf, (modemname ? (modemname+1) : port));
X    strcat(ltmp, pidstr);
X
X    /*
X     * Create the LTMP.<pid> file and scribble our PID in it.
X     */
X    unlink(ltmp);
X    if ((lfd = creat(ltmp, 0444)) == -1) {
X	fprintf(stderr, "Can't creat(2) LTMP?\r\n");
X	return -1;
X    }
X    sprintf(pidstr, "%10d\n", pid);
X    write(lfd, pidstr, 11);
X    close(lfd);
X
X    /*
X     * Attempt to link directly - if it works, we're done.
X     */
X  relink:
X    if (link(ltmp, lckf) == 0) {
X	unlink(ltmp);
X        return 0;
X    }
X
X    /*
X     * Oh, bother, there's a LCK..* file already; we must
X     * now expend effort to learn if it's stale or not.
X     */
X    if ((lfd = open(lckf, O_RDONLY)) != -1) {
X	if (read(lfd, lckpidstr, 11) == 11) {
X	    lckpid = atol(lckpidstr);
X	    if (kill(lckpid, 0) == 0) {
X		fprintf(stderr, "%s locked by process %d.\r\n", port, lckpid);
X		unlink(ltmp);
X		return -1;
X	    }
X	}
X    }
X
X    /*
X     * The LCK..* file was stale.  Remove and retry.
X     */
X    if (unlink(lckf)) {
X	fprintf(stderr, "Can't unlink(2) stale LCK?\r\n");
X	unlink(ltmp);
X	return -1;
X    }
X    goto relink;
X    /*NOTREACHED*/
X}
X
Xunlock_tty()
X{
X    unlink(lckf);
X}
SHAR_EOF
if test 9678 -ne "`wc -c < 'xcport.c'`"
then
	echo shar: error transmitting "'xcport.c'" '(should have been 9678 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'xcscrpt.c'" '(7366 characters)'
if test -f 'xcscrpt.c'
then
	echo shar: will not over-write existing file "'xcscrpt.c'"
else
sed 's/^X//' << \SHAR_EOF > 'xcscrpt.c'
X/*
X    Program	xcscrpt.c	Script handler for xcomm
X    Author	larry gensch, ESQ  December 4, 1987
X
X    This code is released to the public domain
X*/
X
X#include <stdio.h>
X#include <time.h>
X#include <ctype.h>
X#include <signal.h>
X
X#include "xcomm.h"
X
X#define	MAX_PATH	256
X#define	MAX_LINE	128
X
Xextern char *getenv();
Xextern FILE *tfp;
X
Xstatic FILE *script_file, *cf;
Xstatic int waitfor_time = 0;
Xstatic int tty_flag = 1;
Xstatic int echo_flag = 0;
Xstatic int if_flag = 0;
Xstatic int waitflag = 0;
Xstatic int captflag = 0;
Xstatic jmp_buf here;
X
Xstatic void k_waitfor(), k_transmit(), k_pause(), k_exit(), k_quit();
Xstatic void k_if(), k_goto(), k_else(), k_endif(), k_redial();
Xstatic void k_dial(), s_set(), hangup(), k_echo(), k_tty(), k_capture();
X
X/* globals */
X
Xint linkflag = 0;
Xint scriptflag = 0;
X
Xstatic struct kw kw[] = {
X	{ "waitfor",    k_waitfor },
X	{ "transmit",	k_transmit },
X	{ "pause",	k_pause },
X	{ "exit",	k_exit },
X	{ "if",		k_if },
X	{ "else",	k_else },
X	{ "endif",	k_endif },
X	{ "hangup",	hangup },
X	{ "goto",	k_goto },
X	{ "dial",	k_dial },
X	{ "redial",	k_redial },
X	{ "quit",	k_quit },
X	{ "set",	s_set },
X	{ "echo",	k_echo },
X	{ "capture",	k_capture },
X	{ "tty",	k_tty },
X	{ NULL,		NULL }};
X
Xstatic void newsigint();
X
Xdo_script(file)
X char *file;
X{
X    int quiet = 0;
X
X    if (open_script(file)) {
X	fprintf(tfp, "Cannot find script file %s\r\n", file);
X	return;
X    }
X
X    if (linkflag == 2) {
X	quiet = 1;
X	linkflag = 0;
X    }
X
X    if (!quiet)
X	fprintf(tfp, "<<< RUNNING SCRIPT >>>\r\n");
X
X    if_flag = 0;
X    echo_flag = 0;
X    captflag = 0;
X    tty_flag = 1;
X    scriptflag = 1;
X
X    if (setjmp(here) == 0) {
X	signal(SIGINT, newsigint);
X	intdel(1);
X
X	for (eof_flag = 0; !eof_flag; )
X	    get_line();
X    }
X
X    fclose(script_file);
X    if (captflag)
X	fclose(cf);
X
X    if (!quiet)
X	fprintf(tfp, "<< SCRIPT COMPLETE >>\r\n");
X
X    linkflag = 0;
X    scriptflag = 0;
X
X    signal(SIGINT, SIG_IGN);
X    intdel(0);
X
X    return;
X}
X
Xstatic void newsigint()
X{
X    signal(SIGINT, SIG_IGN);
X
X    eof_flag = 1;
X    fprintf(tfp, "\r\nUser Abort...\r\n");
X    longjmp(here);
X}
X
Xstatic char path[MAX_PATH];
X
Xstatic open_script(file)
X char *file;
X{
X    char *home;
X
X    eof_flag = 0;
X
X    if (script_file = fopen(file, "r"))
X	return 0;
X    
X    if ((home = getenv("HOME")) == NULL)
X	return 1;
X
X    sprintf(path, "%s/%s", home, file);
X
X    if (script_file = fopen(path, "r"))
X	return 0;
X
X    return 1;
X}
X    
Xstatic char wf[MAX_LINE];
X
Xstatic get_line()
X{
X    int i;
X
X    getline(script_file);
X
X    if (eof_flag)
X	return;
X
X    getword();
X    lc_word(word);
X
X    if (echo_flag) {
X	if (strcmp(word, "transmit"))
X	    fprintf(tfp, "%s\r\n", line);
X	else
X	    fprintf(tfp, "TRANSMIT...\r\n");
X    }
X	
X    if (word[0] == '\0')		/* Ignore blank lines */
X	return;
X    if (word[0] == '#')			/* Ignore comments */
X	return;
X
X    if (word[strlen(word) - 1] == ':')	/* Ignore labels */
X	return;
X
X    if (if_flag == -1) {
X	if (strcmp(word, "else") && strcmp(word, "endif"))
X	    return;
X    }
X
X    for (i = 0; kw[i].keyword != NULL; i++)
X	if (strcmp(kw[i].keyword, word) == 0) {
X	    (*kw[i].rtn)();
X	    return;
X	}
X
X    fprintf(tfp, "UNDEFINED COMMAND: \"%s\"\r\n", word);
X    eof_flag = 1;
X    return;
X}
X
Xstatic void k_waitfor()
X{
X    long t;
X    int c;
X    char *ptr = wf;
X
X    quote_flag = 1;
X    getword();
X    quote_flag = 0;
X    if (eof_flag)
X	return;
X
X    if (word[0] == '\0') {
X	fprintf(tfp, "No argument to WAITFOR command\r\n");
X	eof_flag = 1;
X	return;
X    }
X
X    strcpy(wf, word);
X    lc_word(wf);
X
X    getword();
X    if (eof_flag)
X	return;
X
X    if (word[0])
X	waitfor_time = atoi(word);
X    else
X	waitfor_time = 30;
X
X    t = time(NULL) + waitfor_time;
X
X    while (t != time(NULL) && !eof_flag) {
X	if ((c = read_mbyte(1)) == -1)
X	    continue;
X
X	if (cismode && c == ENQ) {
X	    fprintf(tfp,"B transfer in middle of script\r\n");
X	    cismode = 1;
X	    B_Transfer();
X
X	    t = time(NULL) + waitfor_time;
X
X	    if ((c = read_mbyte(1)) == -1)
X	      continue;
X	}
X
X	if (tty_flag)
X	    fputc(c, tfp);
X
X	if (captflag)
X	    fputc(c, cf);
X
X	if (tolower(c) != *ptr) {
X	    ptr = wf;
X	    continue;
X	}
X
X	if (*++ptr == '\0') {
X	    waitflag = 1;
X	    return;
X	}
X    }
X
X    waitflag = 0;
X}
X
Xstatic void k_transmit()
X{
X    char *ptr;
X
X    quote_flag = 1;
X    getword();
X    quote_flag = 0;
X    if (eof_flag)
X	return;
X
X    if (word[0] == '\0') {
X	fprintf(tfp, "No argument to TRANSMIT command\r\n");
X	eof_flag = 1;
X	return;
X    }
X
X    send_slowly(word);
X}
X
Xstatic void k_pause()
X{
X    int pause_time;
X
X    getword();
X    if (eof_flag)
X	return;
X
X    if (word[0] == '\0')
X	pause_time = 5;
X    else
X	pause_time = atoi(word);
X
X    sleep(pause_time);
X}
X
Xstatic void k_quit()
X{
X    do_exit(0);		/* Terminate XCOMM */
X}
X
Xstatic void k_exit()
X{
X    eof_flag = 1;
X}
X
Xstatic char label[WBSIZE];
X
Xstatic void k_goto()
X{
X    int found = 0, i;
X
X    getword();
X    if (word[0] == '\0') {
X	fprintf(tfp, "No argument for GOTO: %s\r\n", line);
X	eof_flag++;
X	return;
X    }
X
X    strcpy(label, word);
X    lc_word(label);
X
X    rewind(script_file);
X    while (!found) {
X	getline(script_file);
X	if (eof_flag)
X	    break;
X
X	getword();
X	if (word[0] == '\0' || word[0] == '#')
X	    continue;
X
X	if (word[i = (strlen(word)-1)] != ':')
X	    continue;
X
X	word[i] = '\0';
X
X	lc_word(word);
X	found = (strcmp(word, label) == 0);
X    }
X
X    if (eof_flag) {
X	fprintf(tfp, "Label %s not found\r\n", label);
X	eof_flag++;
X	return;
X    }
X
X    if_flag = 0;			/* reset IF flag */
X}
X
Xstatic if_negate = 0;
X
Xstatic void k_if()
X{
X    char *ptr;
X
X    if (if_flag) {
X	fprintf(tfp, "Nested IF statements not allowed\r\n");
X	eof_flag++;
X	return;
X    }
X
X    if_negate = 0;
X    getword();
X    if (word[0] == '\0') {
X	fprintf(tfp, "No condition on IF statement\r\n");
X	eof_flag++;
X	return;
X    }
X
X    lc_word(word);
X    if (strcmp(word, "not") == 0) {
X	if_negate = 1;
X	getword();
X	if (word[0] == '\0') {
X	    fprintf(tfp, "No condition on IF statement\r\n");
X	    eof_flag++;
X	    return;
X	}
X    }
X
X    if (word[0] == '!') {
X	if_negate = 1;
X	ptr = word + 1;
X    } else
X	ptr = word;
X
X    if (strcmp(ptr, "waitfor") == 0) {
X	if_flag = if_test(waitflag);
X	return;
X    }
X
X    if (strcmp(ptr, "linked") == 0) {
X	if_flag = if_test(linkflag);
X	return;
X    }
X
X    fprintf(tfp, "Undefined IF condition %s\r\n", ptr);
X    eof_flag++;
X    return;
X}
X
Xstatic if_test(cond)
X int cond;
X{
X    if (if_negate)
X	cond = !cond;
X
X    if (cond)
X	return 1;
X    else
X	return -1;
X}
X
Xstatic void k_else()
X{
X    if (!if_flag) {
X	fprintf(tfp, "ELSE not within IF\r\n");
X	eof_flag++;
X	return;
X    }
X
X    if_flag = -if_flag;
X}
X
Xstatic void k_endif()
X{
X    if (!if_flag) {
X	fprintf(tfp, "ENDIF not wihtin IF\r\n");
X	eof_flag++;
X	return;
X    }
X
X    if_flag = 0;
X}
X
Xstatic void k_dial()
X{
X    getword();
X
X    if (word[0] == '\0') {
X	fprintf(tfp, "DIAL command must have an argument\r\n");
X	eof_flag++;
X	return;
X    }
X
X    dial(word);
X}
X
Xstatic void k_redial()
X{
X    if (redial()) {
X	eof_flag++;
X	return;
X    }
X}
X
Xstatic void k_echo()
X{
X    set_onoff(&echo_flag);
X    return;
X}
X
Xstatic void k_capture()
X{
X    int val = captflag;
X
X    set_onoff(&captflag);
X    if (eof_flag)
X	return;
X
X    if (val == captflag)
X	return;
X	
X    if (captflag == 0)
X	fclose(cf);
X    else {
X	if ((cf = fopen(captfile, "a")) == NULL) {
X	    fprintf(tfp, "Cannot open capture file %s\r\n");
X	    eof_flag++;
X	    return;
X	}
X    }
X}
X
Xstatic void k_tty()
X{
X    set_onoff(&tty_flag);
X    return;
X}
X
SHAR_EOF
if test 7366 -ne "`wc -c < 'xcscrpt.c'`"
then
	echo shar: error transmitting "'xcscrpt.c'" '(should have been 7366 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'xcsubs.c'" '(4386 characters)'
if test -f 'xcsubs.c'
then
	echo shar: will not over-write existing file "'xcsubs.c'"
else
sed 's/^X//' << \SHAR_EOF > 'xcsubs.c'
X/*
X    Module:	xcsubs.c	XCOMM Subroutines
X
X    Revisions:
X
X    2.2		lg	Now uses /dev/tty instead of stdin/stdout
X    2.2		lg	Added command parser
X*/
X
X#include <stdio.h>
X#include <ctype.h>
X#include <signal.h>
X#include <termio.h>
X
X#include "xcomm.h"
X
Xextern struct termio newmode, sigmode;
Xextern FILE *tfp;	/* Local terminal */
Xextern int tfd;		/* Local terminal */
X
Xchar line[WBSIZE];	/* Input line */
Xchar word[WBSIZE];	/* Parsed word */
Xchar *wptr, *lptr;	/* Word and line pointers */
Xint quote_flag = 0;	/* Indicates special processing during parse */
Xint eof_flag = 0;	/* Indicates EOF during getline() processing */
X
Xsendstr(p)              /* send a string to the port */
Xregister char *p;
X{
X    while(*p)
X        send_mbyte(*p++);
X}
X
X/* Do the fork call, packaging the error return so that the caller
X * need not have code for it.
X */
X
Xforkem()
X{
X    int i;
X
X    if((i = fork()) < 0){
X        fprintf(tfp,"XCOMM: Fork failed");
X        longjmp(erret, 1);
X    }
X    return(i);
X}
X
X
X/* Convert uppercase characters to lowercase, (without
X * mangling non-uppercase characters), in a portable manner.
X */
Xmklow(c)
Xint c;
X{
X    if(isupper(c))
X        return(tolower(c));
X    return(c);
X}
X
X/* This is an string input routine to be used
X * when the raw terminal mode is in effect.
X */
Xgetsome(s)
Xchar *s;
X{
X    int c, i;
X
X    if (s == line) {
X	lptr = line;
X	memset(line, 0, WBSIZE);
X    }
X
X    i = 0;
X    while((c = coninp()) != '\r' && c != '\n') {
X        if(c == '\b'){
X            if(i > 0){
X                i--;
X                fprintf(tfp,"\b \b");
X            } else
X                putc(7, tfp);
X            continue;
X        }
X        s[i++] = c;
X        putc(c, tfp);
X    }
X    s[i] = '\0';
X    putc(' ', tfp);
X}
X
X/*
X    Erase current line without moving downwards
X*/
X
Xerasln()
X{
X    int i;
X
X    putc('\r', tfp);
X    for(i = 0; i < 79; i++)
X        putc(' ', tfp);
X    putc('\r', tfp);
X}
X
X/* 
X    Throw away all input characters until no more are sent.
X*/
X
Xpurge()
X{
X    while(readbyte(1) != -1)
X        ;
X}
X
X/*
X    Parse the "line" array for a word
X*/
X
Xgetword()
X{
X    char *ptr = word;
X    char quote = '\0';
X    int bflag = 0, qflag = 0;
X    int c;
X
X    *ptr = '\0';
X    if (eof_flag || *lptr == '\0')
X	return;
X
X    while (isspace(*lptr))
X	lptr++;
X
X    wptr = lptr;
X
X    if (*lptr == '\0')
X	return;
X
X    if (*lptr == '\'' || *lptr == '\"')
X	quote = *lptr++;
X    else
X	quote = '\0';
X
X    for (; *lptr != '\0'; lptr++) {
X	if (quote) {
X	    if (*lptr == '\0') {
X		word[0] = '\0';
X		fprintf(tfp, "Unmatched quote: %s\r\n", line);
X		eof_flag = 1;
X		return;
X	    }
X	    if (*lptr == quote)
X		break;
X	} else if (!qflag && isspace(*lptr))
X	    break;
X
X	if (bflag)
X	    *ptr++ = *lptr & 0x1f;
X	else if (qflag)
X	    *ptr++ = *lptr;
X	else if (quote_flag && *lptr == '^')
X	    bflag = 1;
X	else if (quote_flag && *lptr == '\\')
X	    qflag = 1;
X	else
X	    *ptr++ = *lptr;
X    }
X
X    lptr++;
X    *ptr = '\0';
X}
X
X/*
X    Make the specified word all lower case
X*/
X
Xlc_word(ptr)
X char *ptr;
X{
X    while (*ptr) {
X	*ptr = mklow(*ptr);
X	ptr++;
X    }
X}
X
X/*
X    Input a line from the specified file
X*/
X
Xgetline(fp)
X FILE *fp;
X{
X    int l;
X
X    memset(line, 0, WBSIZE);
X
X    if ((fgets((lptr=line), WBSIZE, fp)) == NULL) {
X	eof_flag = 1;
X	line[0] = '\0';
X    }
X
X    l = strlen(line);		/* Purge newline if found */
X    if (l--) {
X	if (line[l] == '\n')
X	    line[l] = '\0';
X    }
X}
X
X/*
X    trminp() is used as a single-character terminal input routine
X*/
X
Xstatic alrm() {}  /* do nothing */
X
Xint trminp(fd, seconds)
X int fd, seconds;
X{
X    static char rxbuf[BUFSIZ], *p;      /* BUFSIZ is defined in stdio.h */
X    static int count = 0;
X
X    if(count > 0){
X        count--;
X        return(*p++ & 0xff);
X    }
X    if(seconds > 0){
X        signal(SIGALRM, alrm);
X        alarm((unsigned)seconds);
X    }
X    if((count  = read(fd, p = rxbuf, BUFSIZ)) < 1)
X        return(-1);
X    if(seconds > 0)
X        alarm(0);
X    count--;
X    return(*p++ & 0xff);
X}
X
X/*
X    coninp() gets a single character from the local terminal
X*/
X
Xconinp()
X{
X    int c;
X
X    fflush(tfp);
X
X    while ((c = trminp(tfd, 0)) == -1)
X	;
X
X    return c;
X}
X
Xintdel(flag)
X{
X    if (flag)
X	ioctl(tfd, TCSETAW, &sigmode);
X    else
X	ioctl(tfd, TCSETAW, &newmode);
X}
X
X#if	!HAVE_STRDUP
Xchar *
Xstrdup(s)
Xchar *s;
X{
X    extern char *calloc(), *strcpy();
X    char *r = calloc(1, strlen(s)+1);
X
X    return(strcpy(r, s));
X}
X#endif /* !HAVE_STRDUP */
SHAR_EOF
if test 4386 -ne "`wc -c < 'xcsubs.c'`"
then
	echo shar: error transmitting "'xcsubs.c'" '(should have been 4386 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'xcterm.c'" '(8607 characters)'
if test -f 'xcterm.c'
then
	echo shar: will not over-write existing file "'xcterm.c'"
else
sed 's/^X//' << \SHAR_EOF > 'xcterm.c'
X/* xcterm.c             XCOMM terminal mode
X */
X
X#include <stdio.h>
X#include <ctype.h>
X#include <signal.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X
X#include "xcomm.h"
X
X/* globals */
Xchar captfile[NMSIZE]  = CAPTFILE;	/* capture file's name */
Xchar phonefile[NMSIZE] = PHFILE;	/* phone number file's name */
X
Xint cismode = CIS_INIT;			/* Respond to CIS "ENQ" */
Xextern FILE *tfp;			/* Local terminal pointer */
X
X/* locals */
X
Xstatic FILE *cfp;			/* capture file pointer */
Xstatic int ctop;			/* index top of capture buffer */
Xstatic int child_pid = 0;		/* ID of child process */
Xstatic int capture = FALSE;		/* are we capturing or not ? */
Xstatic char *cbuffp = NULL;		/* capture buffer pointer */
Xstatic jmp_buf  rtm;
X
X/* forward declarations */
Xvoid toggle(), cleanup(), newbmask(), cisbmode();
X
Xstatic int script_flag = 0;
Xstatic char *script_file;
Xstatic char script_buf[100];
X
Xterminal()
X{
X    int c;
X
Xreterm:
X    setjmp(rtm);
X
X    if (cismode > 1)
X	return;
X
X    script_flag = 0;		/* reset scripting flag */
X
X    fprintf(tfp,"Entering Terminal Mode\r\n");
X    /* split into read and write processes */
X    if((child_pid = forkem()) == 0){
X	/* child, read proc: read from port and write to tty */
X        cfp = NULL;
X        signal(SIGALRM, toggle);
X        signal(SIGTERM, cleanup);
X        signal(SIGUSR1, newbmask);
X        while(1){
X            while((c = read_mbyte(0)) == -1)
X                ;
X	    if (cismode && c == ENQ) {
X		cismode = 2;
X		cleanup();
X	    }
X            fputc(c, tfp);
X	    fflush(tfp);
X            if(capture && c != '\r')
X		fputc(c, cfp);
X        }
X	/*NOTREACHED*/
X    }
X    /* parent, write proc: read from tty and write to port */
X    signal(SIGCLD, cisbmode);
X
X    do {
X        switch(c = getconchr()) {
X        case TOGCHAR:		/* signal child to toggle buffer */
X	    kill(child_pid, SIGALRM);
X	    break;
X
X        case DIVCHAR:		/* divert a file through modem port */
X	    divert();
X	    break;
X
X	case SCRPCHR:		/* execute a script file */
X	    if (get_script())
X		break;
X	    script_flag = 1;
X	    goto fillicide;
X
X        case PSELECT:		/* select and dial a phone number */
X	    pselect();
X	    if (!script_flag) 
X		break;
X
X        case ENDCHAR:		/* signal child to cleanup and exit */
Xfillicide:
X	    c = ENDCHAR;
X	    signal(SIGCLD, SIG_IGN);
X	    kill(child_pid, SIGTERM);
X	    break;
X
X	case HUPCHAR:		/* Hangup */
X	    hangup();
X	    break;
X
X	case '\n':		/* See if NL translation in effect */
X	    if (nlmode)
X		c = '\r';
X
X        default:		/* just send the character to the port */
X	    send_mbyte(c);
X	    break;
X        }
X    } while(c != ENDCHAR);
X
X    while(wait((int *) 0) >= 0)		/* wait for the read process to die */
X        ;
X
X    if (script_flag) {
X	do_script(script_file);
X	goto reterm;
X    }
X
X    fprintf(tfp,"\r\nLeaving Terminal Mode\r\n");
X}
X
Xstatic void cisbmode()
X{
X    cismode = 2;
X    signal(SIGCLD, SIG_IGN);
X
X    longjmp(rtm);
X}
X
X/* The next three functions are only run by the port read process (child).
X * They handle the capture buffer.
X *
X * toggle capture status
X */
Xstatic void toggle()
X{
X    char *malloc();
X
X    if(capture) {
X	fclose(cfp);
X        capture = FALSE;
X	fprintf(tfp, "\r\n<<CAPTURE BUFF CLOSED>>\r\n");
X    } else {
X	if ((cfp = fopen(captfile, "a")) == NULL) {
X	    fprintf(tfp,"\r\n<<CAN'T OPEN CAPTURE FILE>\r\n");
X	} else {
X	    capture = TRUE;
X	    fprintf(tfp,"\r\n<<CAPTURE BUFF OPEN>>\r\n");
X	}
X    }
X
X    signal(SIGALRM, toggle);	/* set signal for next toggle */
X}
X
X/* cleanup, flush and exit
X */
Xstatic void cleanup()
X{
X    if(capture){
X        fclose(cfp);
X	fprintf(tfp,"\r\n<<CAPTURE BUFF SAVED>>\r\n");
X    }
X
X    if (cismode == 2)
X	fprintf(tfp,"\r\n<<FILE TRANSFER REQUEST>>\r\n");
X
X    fflush(tfp);
X    exit(0);
X}
X
Xstatic void newbmask()
X{
X    if (bitmask == 0xff)
X	bitmask = 0x7f;
X    else
X	bitmask = 0xff;
X    
X    if (child_pid)
X	kill(child_pid, SIGUSR1);
X    else
X	fprintf(tfp,"<<SET TO %d BIT MASK>>\r\n", bitmask == 0xff ? 8 : 7);
X}
X
Xstatic FILE *openfile(name)
X char *name;
X{
X    FILE *fp;
X    char *home, fullname[NMSIZE];
X
X    if (fp = fopen(name, "r"))
X	return fp;
X
X    if (home = (char *) getenv("HOME")) {
X	sprintf(fullname, "%s/%s", home, name);
X	return fopen(fullname, "r");
X    } else
X	return NULL;
X}
X
X/*
X    Select a script file.  If the file exists, execute it, otherwise
X    exit with a non-zero return.
X*/
X
Xget_script()
X{
X    fprintf(tfp,"\r\nEnter script file: ");
X    getsome(script_buf);
X    if (script_buf[0] == '\0') {
X	fprintf(tfp,"\r\n<<ABORTED>>\r\n");
X	return 1;
X    }
X    if (access(script_buf, 04)) {
X	fprintf(tfp," <<- NOT FOUND\r\n");
X	return 1;
X    }
X    fprintf(tfp, "\r\n");
X    linkflag = FALSE;
X    script_file = script_buf;
X    return 0;
X}
X
X/* pselect() and divert() are used by the port write process (parent).
X * They produce other sources of input for the port than the keayboard.
X *
X * Select phone number and dial it. (Hayes - type modem)
X * Phone number is stored in a file, one number per line, with the phone
X * number first, followed by some space and then any comments.
X * VERSION 2.1 - If line contains BAUD=nnnn, the baud rate will be changed
X *		 to nnn.  If lines contains BITS=7 or BITS=8, the bitmask
X *		 will be changed to the specified value.
X * VERSION 2.2 - If line contains SCRIPT=nnnnn, the designated script file
X *		 will be started.
X */
Xpselect()
X{
X    FILE *fp;
X    char buffer[WBSIZE + 1];
X    int c, i;
X
X    if ((fp = openfile(phonefile)) == NULL) {
X	fprintf(tfp,"Phonelist file '%s' not in current or home directory\r\n",
X		phonefile);
X	return;
X    }
X
X    fprintf(tfp,"Type D-Dial   X-Exit  Any other key for next line.\r\n");
X    do {
X        if(fgets(buffer, WBSIZE, fp) == NULL){
X            rewind(fp);
X            if(fgets(buffer, WBSIZE, fp) == NULL){
X                fprintf(tfp,"Empty phonelist file!\r\n");
X                return;
X            }
X        }
X        erasln();
X        for(i = 0; i < WBSIZE && (c = buffer[i]) != '\n'; i++)
X            fputc(c, tfp);
X        fputc('\r', tfp);
X    } while((c = mklow(getc(tfp))) != 'd' && c != 'x');
X    erasln();
X    fclose(fp);
X    if(c == 'd')
X	dialbuf(buffer);
X}
X
X#if	!HAVE_STRSTR
X/*
X    Find first occurance of str2 in str1 and return a pointer to it
X*/
X
Xchar *strstr(str1, str2)
X char *str1, *str2;
X{
X    char *Sptr, *Tptr;
X    int len = strlen(str1) - strlen(str2) + 1;
X
X    if (*str2)
X	for (; len > 0; len--, str1++) {
X	    if (*str1 != *str2)
X		continue;
X
X	    for (Sptr = str1, Tptr = str2; *Tptr != '\0'; Sptr++, Tptr++)
X		if (*Sptr != *Tptr)
X		    break;
X	    
X	    if (*Tptr == '\0')
X		return str1;
X	}
X
X    return NULL;
X}
X#endif
X
Xdialbuf(buf)
X char *buf;
X{
X    char *nbr, *ptr, *ptr1, c;
X
X    if (ptr = strstr(buf, "BAUD=")) {
X	ptr += 5;
X	if (mbaud(ptr) == -1) 
X	    fprintf(tfp,"Invalid BAUD= value\r\n");
X	else
X	    fprintf(tfp,"<<SET TO %d BAUD>>\r\n", mbaud(NULL));
X    }
X
X    if (ptr = strstr(buf, "BITS=")) {
X	ptr += 5;
X	switch (*ptr) {
X	case '7':
X	    if (bitmask == 0xff)
X		newbmask();
X	    break;
X	case '8':
X	    if (bitmask == 0x7f)
X		newbmask();
X	    break;
X	default:
X	    fprintf(tfp,"Invalid BITS= value\r\n");
X	}
X    }
X
X    while (isspace(*buf) && *buf)
X	    buf++;
X
X    if (!(*buf))
X	    return;
X
X    for (nbr = buf; !isspace(*buf) && *buf; buf++)
X	    ;
X    
X    c = *buf;
X    *buf = '\0';
X    dial (nbr);
X
X    *buf = c;
X    if (ptr = strstr(buf, "SCRIPT=")) {
X	ptr += 7;
X	ptr1 = ptr;
X	while (!isspace(*ptr1) && *ptr1 != '\0')
X	    ptr1++;
X	*ptr1 = '\0';
X	script_file = ptr;
X	script_flag = 1;
X	linkflag = TRUE;
X    }
X}
X
X/* Divert file into input stream, with optional delay after each newline.
X */
Xdivert()
X{
X    FILE *fp;
X    char buffer[NMSIZE];
X    int c, i;
X
X    fprintf(tfp,"\r\nFile? ");
X    getsome(buffer);
X    if((fp = fopen(buffer, "r")) == NULL){
X        fprintf(tfp,"\r\nCan't open %s for input\r\n", buffer);
X        return;
X    }
X    fprintf(tfp,"\r\nThe default delay of %d can be ", DRIBBLE);
X    fprintf(tfp,"changed by typing the new delay after the 'y'\r\n");
X    fprintf(tfp,"Delay after every newline (y/n)? ");
X
X    getsome(buffer);
X    fprintf(tfp,"\r\n");
X
X    i = 0;
X    if(mklow(buffer[0]) == 'y' && (i = atoi(buffer + 1)) == 0)
X        i = DRIBBLE;
X    while((c = getc(fp)) != EOF)
X        if(c != '\n')
X            send_mbyte(c);
X        else {
X            send_mbyte('\r');
X            if(i)
X                sleep((unsigned) i);
X        }
X    fclose(fp);
X}
X
Xgetconchr()
X{
X    int c, tc;
X
X    if ((c = coninp()) == ESCAPE_CHR) {
X	switch (c = ((tc = coninp()) & 0x1f) + 128) {
X	case ENDCHAR:
X	case TOGCHAR:
X	case DIVCHAR:
X	case PSELECT:
X	case HUPCHAR:
X	case SCRPCHR:
X	    break;
X
X	default:
X	    c = tc;
X	}
X    }
X    return c;
X}
X
SHAR_EOF
if test 8607 -ne "`wc -c < 'xcterm.c'`"
then
	echo shar: error transmitting "'xcterm.c'" '(should have been 8607 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'xcxmdm.c'" '(12344 characters)'
if test -f 'xcxmdm.c'
then
	echo shar: will not over-write existing file "'xcxmdm.c'"
else
sed 's/^X//' << \SHAR_EOF > 'xcxmdm.c'
X/*
X    Module:	xcxmdm.c	XMODEM Protocol Module
X
X    This source code is purely public domain
X*/
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <signal.h>
X
X#include "xcomm.h"
X
X#define SOH     001     /* ^A */
X#define EOT     004     /* ^D */
X#define ACK     006     /* ^F */
X#define NAK     025     /* ^U */
X#define CAN     030     /* ^X */
X#define CPMEOF  032     /* ^Z */
X#define WANTCRC 'C'
X#define OK       0
X#define TIMEOUT  -1     /* -1 is returned by readbyte() upon timeout */
X#define ERROR    -2
X#define WCEOT    -3
X#define RETRYMAX 10
X#define SECSIZ  128
X
X/* globals */
Xint
X        badline         = FALSE,        /* bad telephone line?          */
X        crcheck         = TRUE;         /* CRC check enabled?           */
X
Xextern FILE *tfp;			/* TTY File pointer */
X
X/* locals */
Xstatic FILE
X        *xfp;                           /* buffered file pointer        */
Xstatic int
X        firstsec,                       /* first sector of file or not? */
X        textmode        = TRUE;         /* Text translations enabled?   */
Xstatic char wcbuff[SECSIZ];             /* Ward Christensen sector buffer */
Xstatic unsigned short updcrc();
X
Xstatic void newsigint();		/* Our SIGINT handler */
Xstatic int  save_crc;			/* Saved crcheck value */
Xstatic jmp_buf our_env;
X
Xxreceive(c)
X int c;
X{
X    if (word[0] == '\0') {
X	fprintf(tfp,"No file name specified for XMODEM receive\r\n");
X	return;
X    }
X
X    xc_setxon(0);				/* turn off XON/XOFF */
X    save_crc = crcheck;
X    signal(SIGINT, newsigint);			/* Install our handler */
X
X    if (!setmode(c)) {
X	if (setjmp (our_env) == 0) {
X	    crcheck = 0xff;
X	    do_xreceive(word);
X	}
X    }
X
X    signal(SIGINT, SIG_IGN);			/* Reinstall old handler */
X    crcheck = save_crc;
X    restmode();
X}
X
Xxsend(c)
X int c;
X{
X    if (word[0] == '\0') {
X	fprintf(tfp,"No file name specified for XMODEM send\r\n");
X	return;
X    }
X
X    xc_setxon(0);				/* turn off XON/XOFF */
X    save_crc = crcheck;
X    signal(SIGINT, newsigint);			/* Install our handler */
X
X    if (!setmode(c)) {
X	if (setjmp (our_env) == 0) {
X	    crcheck = 0xff;
X	    do_xsend(word);
X	}
X    }
X
X    signal(SIGINT, SIG_IGN);			/* Reinstall old handler */
X    crcheck = save_crc;
X    restmode();
X}
X
Xstatic void newsigint()
X{
X    fprintf(tfp,"\r\nUser abort\r\n");
X    signal(SIGINT, SIG_IGN);	/* Ignore subsequent DEL's */
X    canit();			/* Abort the transmission */
X    longjmp(our_env, 0);
X}
X
Xstatic restmode()
X{
X    intdel(0);
X
X    xc_setflow();				/* restore XON/XOFF */
X}
X
Xstatic do_xreceive(p)
X char *p;
X{
X    long bytes, ftime;
X    short fmode;
X    char *ctime();
X
X    fprintf(tfp,"XCOMM: Ready to receive single file %s\r\n", p);
X    if (wcrx(p) == ERROR)
X	canit();
X    return;
X}
X
Xdo_xsend(p)
X char *p;
X{
X    if (wctx(p) == ERROR) {
X	fprintf(tfp,"Error transmitting file %s\r\n", p);
X	return;
X    }
X}
X
X/*
X    Receive a file using XMODEM protocol
X*/
X
Xstatic wcrx(name)
Xchar *name;
X{
X    register int sectnum, sectcurr, sendchar, eofseen;
X
X    if (!mungmode && !access(name, 0)) {
X        canit();
X	fprintf(tfp,"Receive of %s aborted due to pre-exsistence.\r\n");
X        return(ERROR);
X    }
X
X    if ((xfp = fopen(name, "w")) == NULL) {
X        canit();
X	fprintf(tfp,"Receive of %s aborted due to inabilty to open.\r\n");
X        return(ERROR);
X    }
X    firstsec = TRUE;
X    eofseen = FALSE;
X    sectnum = 0;
X    sendchar = crcheck ? WANTCRC : NAK;
X    fprintf(tfp,"Sync...\r\n");
X
X    while(TRUE) {
X        if (badline)
X            purge();
X        sendbyte(sendchar);
X        sectcurr = wcgetsec(6);
X        if (sectcurr == ((sectnum + 1) & 0xff)) {
X            sectnum++;
X	    putsec();
X	    fprintf(tfp,"Received sector #%d             \r", sectnum);
X	    fflush(tfp);
X
X            sendchar = ACK;
X            continue;
X        }
X
X        if (sectcurr == (sectnum & 0xff)) {
X	    fprintf(tfp,"Received duplicate sector #%d   \r", sectnum);
X	    fflush(tfp);
X            sendchar = ACK;
X            continue;
X        }
X
X	fprintf(tfp, "\r\n");
X        fclose(xfp);
X
X        if (sectcurr == WCEOT) {
X	    fprintf(tfp,"File recived OK\r\n");
X            sendbyte(ACK);
X            return(OK);
X        }
X
X        if (sectcurr == ERROR)
X            return(ERROR);
X
X	fprintf(tfp,"Sync error ... expected %d(%d), got %d\r\n",
X		    (sectnum + 1) & 0xff, sectnum, sectcurr);
X        return(ERROR);
X    }
X}
X
X/*
X    Transmit a file using XMODEM protocol
X*/
X
Xstatic wctx(name)
Xchar *name;
X{
X    register int sectnum, eoflg, c, attempts;
X
X    if ((xfp = fopen(name, "r")) == NULL) {
X	fprintf(tfp,"Can't open file %s for reading.\r\n", name);
X        return(ERROR);
X    }
X    firstsec = TRUE;
X    attempts = 0;
X    fprintf(tfp,"Sync...\r\n");
X
X    while((c = readbyte(30)) != NAK && c != WANTCRC && c != CAN)
X        if (c == TIMEOUT && ++attempts > RETRYMAX) {
X	    fprintf(tfp,"Receiver not responding.\r\n");
X            fclose(xfp);
X            return(ERROR);
X        }
X    if (c == CAN) {
X	fprintf(tfp,"Receiver CANcelled.\r\n");
X        fclose(xfp);
X        return(ERROR);
X    }
X    crcheck = (c == WANTCRC);
X    fprintf(tfp,"%s error checking requested.\r\n",
X		crcheck ? "CRC check" : "Checksum");
X    sectnum = 1;
X
X    do {
X        eoflg = getsec();
X	fprintf(tfp,"Transmitting sector #%d\r", sectnum);
X	fflush(tfp);
X
X        if (wcputsec(sectnum) == ERROR) {
X            fclose(xfp);
X            return(ERROR);
X        }
X        sectnum++;
X    } while(eoflg);
X
X    fprintf(tfp, "\r\n");
X    fclose(xfp);
X    attempts = 0;
X    sendbyte(EOT);
X    while(readbyte(5) != ACK && attempts++ < RETRYMAX)
X        sendbyte(EOT);
X    if (attempts >= RETRYMAX) {
X	fprintf(tfp,"Receiver not responding to completion.\r\n");
X        return(ERROR);
X    }
X
X    fprintf(tfp,"Transmission complete.\r\n");
X    return(OK);
X}
X
X/*
X    wcgetsec() inputs an XMODEM "sector".
X    This routine returns the sector number encountered, or ERROR if a valid
X    sector is not received or CAN received; or WCEOT if EOT sector.
X
X    Maxtime is the timeout for the first character, set to 6 seconds for
X    retries.  No ACK is sent if the sector is received ok.  This must be
X    done by the caller when it is ready to receive the next sector.
X*/
X
Xstatic wcgetsec(maxtime)
Xint maxtime;
X{
X    register checksum, j, c;
X    register unsigned short oldcrc;
X    int sectcurr, sectcomp, attempts;
X
X    for(attempts = 0; attempts < RETRYMAX; attempts++) {
X        do {
X            c = readbyte(maxtime);
X        } while(c != SOH && c != EOT && c != CAN && c != TIMEOUT);
X
X        switch(c) {
X        case SOH:
X            sectcurr = readbyte(3);
X            sectcomp = readbyte(3);
X            if ((sectcurr + sectcomp) == 0xff) {
X                oldcrc = checksum = 0;
X                for(j = 0; j < SECSIZ; j++) {
X                    if ((c = readbyte(3)) < 0)
X                        goto timeout;
X                    wcbuff[j] = c;
X                    if (crcheck)
X                        oldcrc = updcrc(c, oldcrc);
X                    else
X                        checksum += c;
X                }
X                if ((c = readbyte(3)) < 0)
X                    goto timeout;
X                if (crcheck) {
X                    oldcrc = updcrc(c, oldcrc);
X                    if ((c = readbyte(3)) < 0)
X                        goto timeout;
X                    if (updcrc(c, oldcrc)) {
X			fprintf(tfp,"\r\nCRC error\r\n");
X                        break;
X                    }
X                }
X                else if (((checksum - c) & 0xff) != 0) {
X		    fprintf(tfp,"\r\nChecksum error\r\n");
X                    break;
X                }
X                firstsec = FALSE;
X                return(sectcurr);
X            }
X            else 
X                fprintf(tfp,"\r\nSector number garbled 0%03o 0%03o\r\n",
X			sectcurr, sectcomp);
X            break;
X        case EOT:
X            if (readbyte(3) == TIMEOUT)
X                return(WCEOT);
X            break;
X        case CAN:
X	    fprintf(tfp,"\r\nSender CANcelled.\r\n");
X            return(ERROR);
X        case TIMEOUT:
X            if (firstsec)
X                break;
Xtimeout:
X	    fprintf(tfp,"\r\nTimeout\r\n");
X            break;
X        }
X	fprintf(tfp,"\r\nTrying again on ths sector.\r\n");
X        purge();
X        if (firstsec)
X            sendbyte(crcheck ? WANTCRC : NAK);
X        else {
X            maxtime = 6;
X            sendbyte(NAK);
X        }
X    }
X    fprintf(tfp,"\r\nRetry count exceeded.\r\n");
X    canit();
X    return(ERROR);
X}
X
X/* wcputsec outputs a Ward Christensen type sector.
X * it returns OK or ERROR
X */
Xstatic wcputsec(sectnum)
Xint sectnum;
X{
X    register checksum, j, c, attempts;
X    register unsigned short oldcrc;
X
X    oldcrc = checksum = 0;
X    for(j = 0; j < SECSIZ; j++) {
X        c = wcbuff[j];
X        oldcrc = updcrc(c, oldcrc);
X        checksum += c;
X    }
X    oldcrc = updcrc(0, updcrc(0, oldcrc));
X
X    for(attempts = 0; attempts < RETRYMAX; attempts++) {
X        sendbyte(SOH);
X        sendbyte(sectnum);
X        sendbyte(-sectnum - 1);
X        for(j = 0; j < SECSIZ; j++)
X            sendbyte(wcbuff[j]);
X        if (badline)
X            purge();
X        if (crcheck) {
X            sendbyte((int) (oldcrc >> 8));
X            sendbyte((int) oldcrc);
X        }
X        else
X            sendbyte(checksum);
X        switch(c = readbyte(10)) {
X        case CAN:
X	    fprintf(tfp,"\r\nReceiver CANcelled.\r\n");
X            return(ERROR);
X        case ACK:
X            firstsec = FALSE;
X            return(OK);
X        case NAK:
X	    fprintf(tfp,"\r\nGot a NAK on sector acknowledge.\r\n");
X            break;
X        case TIMEOUT:
X	    fprintf(tfp,"\r\nTimeout on sector acknowledge.\r\n");
X            break;
X        default:
X	    fprintf(tfp,"\r\nGot 0%03o for sector acknowledge.\r\n", c);
X            do {
X                if ((c = readbyte(3)) == CAN) {
X		    fprintf(tfp,"\r\nReceiver CANcelled.\r\n");
X                    return(ERROR);
X                }
X            } while(c != TIMEOUT);
X            if (firstsec)
X                crcheck = (c == WANTCRC);
X            break;
X        }
X    }
X    fprintf(tfp,"\r\nRetry count exceeded.\r\n");
X    return(ERROR);
X}
X
X/* update the cyclic redundantcy check value
X */
Xstatic unsigned short updcrc(c, crc)
Xregister c;
Xregister unsigned crc;
X{
X    register int i;
X
X    for(i = 0; i < 8; i++) {
X        if (crc & 0x8000) {
X            crc <<= 1;
X            crc += (((c <<= 1) & 0400) != 0);
X            crc ^= 0x1021;
X        }
X        else {
X            crc <<= 1;
X            crc += (((c <<= 1) & 0400) != 0);
X        }
X    }
X    return(crc);
X}
X
Xstatic zerobuff()
X{
X    register int i;
X
X    for(i = 0; i < SECSIZ; i++)
X        wcbuff[i] = '\0';
X}
X
X/* send 10 CAN's to try to get the other end to shut up */
Xstatic canit()
X{
X    register int i;
X
X    for(i = 0; i < 20; i++)
X        sendbyte(CAN);
X}
X
Xstatic setmode(c)
Xint c;
X{
X    intdel(1);
X
X    switch(mklow(c)) {
X    case 't':
X        textmode = TRUE;
X        break;
X    case 'b':
X        textmode = FALSE;
X    case ' ':
X        break;
X
X    default:
X        return(1);
X    }
X
X    fprintf(tfp,"%s file transfer mode.\r\n", textmode ? "Text" : "Binary");
X
X    return(0);
X}
X
X/* fill the CP/M sector buffer from the UNIX file
X * do text adjustments if necessary
X * return 1 if more sectors are to be read, or 0 if this is the last
X */
Xstatic getsec()
X{
X    register int i, c;
X
X    i = 0;
X    while(i < SECSIZ && (c = getc(xfp)) != EOF) {
X        if (textmode && c == '\n') {
X            wcbuff[i++] = '\r';
X            if (i >= SECSIZ) {          /* handle a newline on the last byte */
X                ungetc(c, xfp);         /* of the sector                     */
X                return(1);
X            }
X        }
X        wcbuff[i++] = c;
X    }
X    /* make sure that an extra blank sector is not sent */
X    if (c != EOF && (c = getc(xfp)) != EOF) {
X        ungetc(c, xfp);
X        return(1);
X    }
X    /* fill up the last sector with ^Z's if text mode or 0's if binary mode */
X    while(i < SECSIZ)
X        wcbuff[i++] = textmode ? CPMEOF : '\0';
X    return(0);
X}
X
X/* Put received WC sector into a UNIX file
X * using text translations in nessesary.
X */
X
Xstatic putsec()
X{
X    register int i, c;
X
X    for(i = 0; i < SECSIZ; i++) {
X        c = wcbuff[i];
X        if (textmode) {
X            if (c == CPMEOF)
X                return(1);
X            if (c == '\r')
X                continue;
X        }
X        putc(c, xfp);
X    }
X    return(0);
X}
X
SHAR_EOF
if test 12344 -ne "`wc -c < 'xcxmdm.c'`"
then
	echo shar: error transmitting "'xcxmdm.c'" '(should have been 12344 characters)'
fi
fi # end of overwriting check
echo shar: done with directory "'src'"
cd ..
#	End of shell archive
exit 0