[alt.sources] xcomm 2.2, part 2 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:36 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 "'.phonelist'" '(301 characters)'
if test -f '.phonelist'
then
	echo shar: will not over-write existing file "'.phonelist'"
else
sed 's/^X//' << \SHAR_EOF > '.phonelist'
X 470-2548	Andover CNODE		BITS=8	BAUD=1200
X 687-0374	CompuServe		BITS=7	BAUD=1200, SCRIPT=compusrv.cmd
X 689-0186	BIX (Tymnet)		BITS=7	BAUD=1200
X 975-2273	Delphi (Telenet)	BITS=7	BAUD=1200
X1-441-2202	Allegro
X1-542-1796	CompuServe (Boston)	BITS=7	BAUD=1200
X1-603-888-8179	Opus (Nashua)		BITS=8	BAUD=1200
SHAR_EOF
if test 301 -ne "`wc -c < '.phonelist'`"
then
	echo shar: error transmitting "'.phonelist'" '(should have been 301 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'Makefile.pyr'" '(308 characters)'
if test -f 'Makefile.pyr'
then
	echo shar: will not over-write existing file "'Makefile.pyr'"
else
sed 's/^X//' << \SHAR_EOF > 'Makefile.pyr'
XCC		= /bin/att /bin/cc
XCFLAGS		= -O
XINSTLIB		= /usr/comm
X
XOBJS		= xcomm.o xcterm.o xcxmdm.o xcsubs.o xcport.o xccisb.o \
X		  xcscrpt.o
X
Xxcomm:  	$(OBJS)
X		$(CC) $(CFLAGS) $(OBJS) -o xcomm
X
Xclean:;		rm -f $(OBJS)
X
Xinstall:	xcomm
X		chmod u=rx,g=x,o=x xcomm
X		rm -f $(INSTLIB)/xcomm
X		ln xcomm $(INSTLIB)/xcomm
SHAR_EOF
if test 308 -ne "`wc -c < 'Makefile.pyr'`"
then
	echo shar: error transmitting "'Makefile.pyr'" '(should have been 308 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'Makefile.sun'" '(304 characters)'
if test -f 'Makefile.sun'
then
	echo shar: will not over-write existing file "'Makefile.sun'"
else
sed 's/^X//' << \SHAR_EOF > 'Makefile.sun'
XCC		= /usr/5bin/cc
XCFLAGS		= -O
XINSTLIB		= /usr/comm
X
XOBJS		= xcomm.o xcterm.o xcxmdm.o xcsubs.o xcport.o xccisb.o \
X		  xcscrpt.o
X
Xxcomm:  	$(OBJS)
X		$(CC) $(CFLAGS) $(OBJS) -o xcomm
X
Xclean:;		rm -f $(OBJS)
X
Xinstall:	xcomm
X		chmod u=rx,g=x,o=x xcomm
X		rm -f $(INSTLIB)/xcomm
X		ln xcomm $(INSTLIB)/xcomm
SHAR_EOF
if test 304 -ne "`wc -c < 'Makefile.sun'`"
then
	echo shar: error transmitting "'Makefile.sun'" '(should have been 304 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'compusrv.cmd'" '(1410 characters)'
if test -f 'compusrv.cmd'
then
	echo shar: will not over-write existing file "'compusrv.cmd'"
else
sed 's/^X//' << \SHAR_EOF > 'compusrv.cmd'
X# Ensure we are in 7-bit mode (high bit ignored), since CIS defaults to
X# seven-bit words (this ensures the waitfor commands will find what they
X# are looking for).
X
X    set 7bit on
X
X# The following IF condition tests to see if we are linked from a .phonelist
X# entry.  If not, we manually dial the local COMPUSERVE node:
X
X    if !linked
X	dial	687-0374	# Note anything past a full command is ignored
X    endif
X
X# Wait for a CONNECT message from the modem.  If we time out (20 seconds),
X# redial the number (it is probably busy).
X
Xconnect:
X    waitfor "CONNECT" 20
X    if !waitfor
X	redial
X	goto connect
X    endif
X
X# Pause a bit to let CIS catch up with us
X
X    pause 2
X
X# Transmit a Control-C (^C) to CompuServe, and then wait for the
X# prompt "User ID:".  If this is not seen in 10 seconds, we try again.
X
Xcis:
X    transmit "^C"
X    waitfor "User ID:"  10
X    if !waitfor
X	goto cis
X    endif
X
X# Transmit the user id string (remember the ^M at the end for ENTER)...
X
X    transmit "72236,3516^M"
X
X# Wait for CompuServe to ask for a password...
X
X    waitfor "Password:"
X
X# Transmit our password
X# (You don't think for a moment that this is my REAL password, do you?????)
X
X    transmit "YELLOW*BANANA^M"
X    
X# Wait for CompuServe header, and then transmit "G UNIXFORUM^M^O"
X# (The ^M is an ENTER, the ^O tells CompuServe to shut up until we
X# get there.)
X
X    waitfor "Compuserve"
X
X    transmit "G UNIXFORUM^M^O"
SHAR_EOF
if test 1410 -ne "`wc -c < 'compusrv.cmd'`"
then
	echo shar: error transmitting "'compusrv.cmd'" '(should have been 1410 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'install.doc'" '(5196 characters)'
if test -f 'install.doc'
then
	echo shar: will not over-write existing file "'install.doc'"
else
sed 's/^X//' << \SHAR_EOF > 'install.doc'
XXCOMM Installation
X
XTo compile:
X
X1.  Read xcomm.h and, if necessary, make any necessary changes.  The following 
X    #define's affect compilation:  
X
XCAPTFILE		"capture.log"
X
X    This is the default name given to the capture buffer in terminal mode
X    (and during script processing).
X
X
XPHFILE			".phonelist"
X
X    This is the default name given to the phone directory in terminal mode.
X
X
XSTARTUP			".xcomm"
X
X    This is the name of the startup script for XCOMM.  If this file is found
X    in your current or home directory, it will be executed immediately on
X    entrance into the XCOMM program.
X
X
XDRIBBLE			2
X
X    This is the default number of seconds to wait after transmitting a
X    newline when sending a file (using the <ESC> F command) in terminal
X    mode.
X
X
XPUT_TAKE		
X
X    If this entry is defined (any value), the puttake() function will be
X    included in the xcomm program.  This enables commands "%p" and "%t" in
X    command mode.  Place a start comment (/*) in front of this define if you
X    do not wish this code to be included.
X
X
XCIS_INIT		1
X
X    Default CIS mode on startup.  Basically, this is no longer necessary,
X    as the startup script can override this on entry to the program.  This
X    value should be 1 if CIS <ENQ> Transfer mode is desired; 0 if it is not
X    desired.
X
X
XHAVE_DUP2		1
X
X    dup2() used to be a standard part of Unix, but is not included with all
X    versions of Unix.  If your implementation does not have dup2() (or if
X    you are just not sure), define this as 0 and a functional equivalent
X    will be included in the source code.
X
X
XHAVE_STRSTR		0
X
X    The draft Ansi C standard specifies the "strstr" function to return the
X    position of a substring within a string.  This is NOT included in most
X    Unix systems, so I have written code to emulate it.
X
X
XHAVE_STRDUP		1
X
X    Not all systems support a strdup() function, which takes a char * arg,
X    and returns a second, identical string in newly-calloc'd space.  Xcomm
X    will use its own version of strdup() if this is set to 0.
X
X
XDTR_DROPS_CARRIER	1
X
X    On some (most?) modems, dropping the DTR signal will instruct the modem
X    to disconnect the phone line.  On most (some?) Unix systems, setting a
X    baud rate of 0 will drop carrier.
X
X    If either of these conditions do NOT apply to your setup, set this value
X    to 0 and an alternate hangup function will be used.  This alternate
X    function sends the Hayes ESCAPE sequence (+++), waits a few seconds, and
X    then sends the Hayes hangup command (ATH).
X
X
Xindex			strchr
Xrindex			strrchr
X
X    In the string(3) library on AT&T's Unix system, the functions "strchr"
X    and "strrchr" are used to find a character within a string.  On Berkley
X    and some Xenix systems, "index" and "rindex" are used (these are defined
X    this way in K & R, also).  The original XCOMM code used the index/rindex
X    functions, and this define helped make the program compile.
X
X    Note:  If your system does not support strchr and strrchr, define these
X	   functions oppositely:
X
X	   #define strchr  index
X	   #define strrchr rindex
X
X	   Since I tend to use the latter functions.  "The wonderful thing
X	   about standards is that there are SO many to choose from!"
X
X
X2.  Read the makefile.  You may wish to edit the INSTLIB reference to wherever 
X    your system stores user-created commands.  On some systems, /usr/bin is 
X    used, other systems have other standards.  On my system, I use /usr/comm.
X
X
X3.  Type "make" to compile xcomm.
X
X
X4.  Type "make install" to install as a permanent command.
X
X
X
XTo execute:
X
X    xcomm -l /dev/ttyNN
X
XWhere "/dev/ttyNN" is the device name that is used to access your modem.
X
XThe "-l /dev..." option may be defaulted by setting the environment variable
XMODEM.  This may be set by your login profile to the name of the device that
Xis used to access the modem.  In /bin/sh, use the following to set your
Xdevice to /dev/tty00:
X
X    set MODEM="/dev/tty00"; export MODEM
X
XIn "csh", this would be done as follows:
X	
X    setenv MODEM /dev/tty00
X
X
XImplementation:
X
XOn MY system, I install xcomm into its own directory (/usr/comm), and perform 
Xall uploads and downloads into this directory.  This helps keep production 
Xfiles from getting crashed.  I execute XCOMM from a shell script that changes
Xthe current directory to /usr/comm and executes the xcomm program there.
XThis keeps all uploads and downloads in that directory, keeping production
Xfiles from getting overwritten inadvertantly.  The file xcomm.sh included in
Xthe source distribution is the script that I use.
X
X
XNotes:
X
XXCOMM does not honor or set the LCK..tty files used by cu and uucp, so
Xthere may be some contention for the use of the modem.  If anybody would be
Xso kind as to write a routine that performs the lock, I will consider
Xplacing it into a future release.
X
X
XBUG REPORTS, FIXES, IDEAS, etc:
X
XI am very receptive to reasonable requests, suggestions, and bug reports.
XMy "electronic" addresses are listed below:
X
X	CompuServe		[72236,3516]
X	Delphi			LARRYG
X	Bix			LAR3RY
X	Andover CNode		larry gensch
X
X(The Andover CNode is a FIDO bulletin board that supports C programming
Xand can be reached at 617/470-2548 - 300/1200/2400 baud)
X
X
Xlarry gensch
SHAR_EOF
if test 5196 -ne "`wc -c < 'install.doc'`"
then
	echo shar: error transmitting "'install.doc'" '(should have been 5196 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'read.me'" '(1528 characters)'
if test -f 'read.me'
then
	echo shar: will not over-write existing file "'read.me'"
else
sed 's/^X//' << \SHAR_EOF > 'read.me'
XXCOMM 2.2:
X
XNew in this release...
X
X*   Modified XCOMM command line interface
X*   CIS "Quick B" Protocol support for faster up/downloads
X*   Brand new script processor with integration into the phonebook
X*   Some code cleanup
X*   Better "vanilla" Unix support (thanks to bug reports)
X
XRefer to "historical.doc" for a list of ALL new features.
X
XXCOMM is a PUBLIC DOMAIN (not shareware) communication program that works on 
XUnix System V.3.  It probably works on other Unix systems with no 
Xmodification, since no machine specific coding was done.  
X
XXCOMM is distributed in two bundles:
X
XXCM22DOC.SH	All documentation for XCOMM
XXCM22SRC.SH	All source code, header files, and makefile.
X
XThis README manifest file is included in both packages.
X
XContents of XCM22DOC.SH:
X
Xreadme		This manifest file
Xscript.doc	Quick reference to the XCOMM script language
Xxcomm.doc	Latest documentation for the XCOMM program
Xhistorical.doc	Historical information about versions 1.0 and 1.1
Xphonelist.doc	Documentation on using XCOMM's phonelist
X
X
XContents of XCM22SRC.SH:
X
Xreadme		This manifest file
Xinstall.doc	Quick installation notes
XMakefile	Make file for compiling XCOMM
Xxcomm.h		XCOMM's header file
Xxcomm.c		XCOMM main program
Xxccisb.c	XCOMM CIS-B/QuickB protocol module
Xxcport.c	XCOMM Terminal I/O module
Xxcscrpt.c	XCOMM Script processor
Xxcsubs.c	XCOMM's subroutines
Xxcterm.c	XCOMM Terminal mode module
Xxcxmdm.c	XCOMM XMODEM protocol module
Xcis.cmd		A sample XCOMM script file for logging onto CompuServe.
X.phonelist	A sample Phone List file
SHAR_EOF
if test 1528 -ne "`wc -c < 'read.me'`"
then
	echo shar: error transmitting "'read.me'" '(should have been 1528 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'xccisb.c'" '(23009 characters)'
if test -f 'xccisb.c'
then
	echo shar: will not over-write existing file "'xccisb.c'"
else
sed 's/^X//' << \SHAR_EOF > 'xccisb.c'
X/*
X    xccisb.c	CIS "B" Routines for XCOMM
X
X    The following code was modified from "BP.C", a "generic" B-protocol
X    handler available from CompuServe.
X
X*/
X/**
X * Copyright (c) 1985 by Steve Wilhite, Worthington, Ohio
X *
X * Permission is granted to use or distribute this software without any
X * restrictions as long as this entire copyright notice is included intact.
X * You may include it in any software product that you sell for profit.
X *
X * This software is distributed as is, and is not guaranteed to work on any
X * given hardware/software configuration.  Furthermore, no liability is
X * granted with this software.
X *
X * ABSTRACT:
X *
X *      The function, Transfer_File, implements error-free file transfer using
X *      CompuServe's "B" protocol.
X *
X *      It has been assumed that the start-of-packet sequence, DLE "B", has
X *      been detected and the next byte not received yet is the packet
X *      sequence number (an ASCII digit).
X *
X * AUTHOR: Steve Wilhite, CREATION DATE: 21-Jul-85
X *
X * REVISION HISTORY:
X *
X * 4 Dec 1987 -- larry gensch -- Supports QUICK-B Protocol 
X **/
X
X#include <stdio.h>
X#include <fcntl.h>
X#include <signal.h>
X#include <unistd.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <time.h>
X
X#include "xcomm.h"
X
Xextern FILE *tfp;		/* Generic tty pointer */
X
Xstatic int Abort_Flag = 0;	/* Equals 1 if user wants to abort */
Xstatic int Text_Mode = 0;	/* 1 = Convert /r/n to /n and back */
Xstatic int ACK_Count = 0;	/* Number of successful packets */
Xstatic int XMIT_Count = 0;	/* Number of successful packets */
Xstatic int NAK_Count = 0;	/* Number of consecutive NAKS */
Xstatic long io_count = 0L;	/* Number of bytes transferred */
Xstatic jmp_buf err_buf;		/* setjmp() buffer */
Xstatic int Last_Chr = 0;	/* Last char read from file */
Xstatic long start_time = 0L;	/* Start time of transfer */
Xstatic long bytes_sec = 0L;	/* Number of bytes transferred/sec */
X
Xstatic int Failure_Sent = 0;	/* CIS knows we aborted? */
X
X#define	Wants_To_Abort()	(Abort_Flag)
X#define MAX_WINDOW		2
X#define	min(a,b)		((a)<(b) ? (a) : (b))
X
X/*
X    The following define allows a hex transcript of the file transfer
X    to be generated.  Uncomment this define if you want the file XCOMM.LOG
X    generated.  (This really increases overhead, but handy for debugging!)
X*/
X
X/* #define CIS_B_DEBUG 	/* Uncomment if you want XCOMM.LOG generated */
X
X#define ETX     0x03
X#define ENQ     0x05
X#define DLE     0x10
X#define XON     0x11
X#define XOFF    0x13
X#define NAK     0x15
X
X#ifndef TRUE
X#define TRUE            1
X#define FALSE           0
X#endif
X
X#define Success         -1
X#define Failure         0
X
X#define MAX_PACKET      1024
X#define Max_Errors      10
X#define Max_Time        10
X#define WACK            ';'             /* wait acknowledge */
X
X/* Sender actions */
X
X#define S_Send_Packet   0
X#define S_Get_DLE       1
X#define S_Get_Num       2
X#define S_Get_Seq       3
X#define S_Get_Data      4
X#define S_Get_Checksum  5
X#define S_Timed_Out     6
X#define S_Send_NAK      7
X#define S_Got_NAK       8
X#define S_Got_ACK       9
X
X/* Receiver actions */
X
X#define R_Get_DLE       0
X#define R_Get_B         1
X#define R_Get_Seq       2
X#define R_Get_Data      3
X#define R_Get_Checksum  4
X#define R_Send_NAK      5
X#define R_Send_ACK      6
X#define R_Send_CTL      6
X
Xstatic int
XCh,
XChecksum,
XSeq_Num,
XR_Size,					/* Size of receiver buffer */
XXOFF_Flag,
XSeen_ETX;
X
Xstatic char S_Buffer[MAX_PACKET+1];	/* Sender buffer */
Xstatic char R_Buffer[MAX_PACKET+1];	/* Receiver buffer */
X
Xstatic int QBP_ws;
Xstatic int QBP_wr;
Xstatic int QBP_bs;
Xstatic int QBP_cm;
Xstatic int QBP_dq;
X
Xstatic int QBP_Active;			/* Signifies windowing in effect */
Xstatic unsigned QBP_Packet;		/* QB Packet Length */
Xstatic int QB_Out = 0;			/* Count of outstanding packets */
Xstatic int QB_Old = 0;			/* Oldest packet */
Xstatic int QB_Current = 0;		/* Current packet */
X
Xstatic struct QB_Hist {			/* Packet Send-ahead buffer */
X    int		block;			/* Block number */
X    int		size;			/* Size of the packet */
X    int		chk;			/* Checksum of packet */
X    char	seq;			/* Sequence number of packet */
X    char	buf[MAX_PACKET];	/* History buffer */
X} QB_Buf[MAX_WINDOW];	
X
X#ifdef CIS_B_DEBUG
Xstatic void xclog(dir, val)
X char dir;
X int val;
X{
X    static int cnt = 0;
X    static FILE *fp = NULL;
X    static int lastdir = 0;
X
X    if (fp == NULL) {
X	fp = fopen("xcomm.log", "w");
X	cnt = 0;
X	lastdir = dir;
X    }
X
X    if (dir == 0) {
X	fprintf(fp, "\n");
X	fclose(fp);
X	return;
X    }
X
X    if (++cnt > 20 || lastdir != dir) {
X	fprintf(fp, "\n");
X	cnt = 1;
X    }
X
X    if (lastdir != dir)
X	fprintf(fp, "\n");
X
X    fprintf(fp, "%c%1x%1x ", dir, val/16, val % 16);
X    lastdir = dir;
X}
X#else 
X#define xclog(dir,val)	/* */
X#endif
X
Xstatic long filelength(fp)
X FILE *fp;
X{
X    struct stat statbuf;
X
X    fstat(fileno(fp), &statbuf);
X
X    return statbuf.st_size;
X}
X
Xstatic Put_Msg(Text)
Xchar *Text;
X{
X    fprintf(tfp,"\r\n%s\r\n", Text);
X}
X
Xstatic char *status_msg = "%-7.7s Blk %5d  %7ld bytes %-30.30s\r";
X
Xstatic Show_ACK()
X{
X    ACK_Count++;
X    NAK_Count = 0;
X    fprintf(tfp,status_msg, "ACK", ACK_Count, io_count, " ");
X    fflush(tfp);
X}
X
Xstatic Show_XMIT(msg)
X char *msg;
X{
X    fprintf(tfp,status_msg, msg, QB_Buf[QB_Current].block, io_count, " ");
X    fflush(tfp);
X}
X
Xstatic Show_W_ACK()
X{
X    fprintf(tfp,status_msg, "ACK", QB_Buf[QB_Old].block, io_count, " ");
X    fflush(tfp);
X}
X
Xstatic Show_NAK(msg)
X{
X    char NAK_msg[8];
X
X    sprintf(NAK_msg, "NAK(%d)", NAK_Count++);
X    fprintf(tfp,status_msg, NAK_msg, ACK_Count, io_count, msg);
X    fflush(tfp);
X}
X
Xstatic Send_Byte(Ch)
X{
X    Ch &= 0xff;
X
X    sendbyte(Ch);
X    xclog('>', Ch);
X}
X
Xstatic Send_Masked_Byte(Ch)
X{
X    /* Mask any protocol or flow characters */
X
X    Ch &= 0xff;
X
X    if (Ch == ETX || Ch == ENQ || Ch == DLE || 
X	Ch == NAK || Ch == XON || Ch == XOFF)
X    {
X	Send_Byte(DLE);
X	Send_Byte(Ch + '@');
X    }
X    else Send_Byte(Ch);
X}
X
Xstatic Send_ACK()
X{
X    Send_Byte(DLE);
X    Send_Byte(Seq_Num + '0');
X}
X
Xstatic Read_Byte()
X{
X    if ((Ch = readbyte(Max_Time)) < 0 || Wants_To_Abort())
X	return Failure;
X    else {
X	xclog('<', Ch);
X	return Success;
X    }
X}
X
Xstatic Read_Masked_Byte()
X{
X    Seen_ETX = FALSE;
X    if (Read_Byte() == Failure) return Failure;
X
X    if (Ch == DLE) {
X	if (Read_Byte() == Failure)
X	    return Failure;
X	Ch -= '@';
X    } else if (Ch == ETX)
X	Seen_ETX = TRUE;
X
X    return Success;
X}
X
Xstatic unsigned short crctab[256] = {
X    0x0000,  0x1021,  0x2042,  0x3063,  0x4084,  0x50a5,  0x60c6,  0x70e7,
X    0x8108,  0x9129,  0xa14a,  0xb16b,  0xc18c,  0xd1ad,  0xe1ce,  0xf1ef,
X    0x1231,  0x0210,  0x3273,  0x2252,  0x52b5,  0x4294,  0x72f7,  0x62d6,
X    0x9339,  0x8318,  0xb37b,  0xa35a,  0xd3bd,  0xc39c,  0xf3ff,  0xe3de,
X    0x2462,  0x3443,  0x0420,  0x1401,  0x64e6,  0x74c7,  0x44a4,  0x5485,
X    0xa56a,  0xb54b,  0x8528,  0x9509,  0xe5ee,  0xf5cf,  0xc5ac,  0xd58d,
X    0x3653,  0x2672,  0x1611,  0x0630,  0x76d7,  0x66f6,  0x5695,  0x46b4,
X    0xb75b,  0xa77a,  0x9719,  0x8738,  0xf7df,  0xe7fe,  0xd79d,  0xc7bc,
X    0x48c4,  0x58e5,  0x6886,  0x78a7,  0x0840,  0x1861,  0x2802,  0x3823,
X    0xc9cc,  0xd9ed,  0xe98e,  0xf9af,  0x8948,  0x9969,  0xa90a,  0xb92b,
X    0x5af5,  0x4ad4,  0x7ab7,  0x6a96,  0x1a71,  0x0a50,  0x3a33,  0x2a12,
X    0xdbfd,  0xcbdc,  0xfbbf,  0xeb9e,  0x9b79,  0x8b58,  0xbb3b,  0xab1a,
X    0x6ca6,  0x7c87,  0x4ce4,  0x5cc5,  0x2c22,  0x3c03,  0x0c60,  0x1c41,
X    0xedae,  0xfd8f,  0xcdec,  0xddcd,  0xad2a,  0xbd0b,  0x8d68,  0x9d49,
X    0x7e97,  0x6eb6,  0x5ed5,  0x4ef4,  0x3e13,  0x2e32,  0x1e51,  0x0e70,
X    0xff9f,  0xefbe,  0xdfdd,  0xcffc,  0xbf1b,  0xaf3a,  0x9f59,  0x8f78,
X    0x9188,  0x81a9,  0xb1ca,  0xa1eb,  0xd10c,  0xc12d,  0xf14e,  0xe16f,
X    0x1080,  0x00a1,  0x30c2,  0x20e3,  0x5004,  0x4025,  0x7046,  0x6067,
X    0x83b9,  0x9398,  0xa3fb,  0xb3da,  0xc33d,  0xd31c,  0xe37f,  0xf35e,
X    0x02b1,  0x1290,  0x22f3,  0x32d2,  0x4235,  0x5214,  0x6277,  0x7256,
X    0xb5ea,  0xa5cb,  0x95a8,  0x8589,  0xf56e,  0xe54f,  0xd52c,  0xc50d,
X    0x34e2,  0x24c3,  0x14a0,  0x0481,  0x7466,  0x6447,  0x5424,  0x4405,
X    0xa7db,  0xb7fa,  0x8799,  0x97b8,  0xe75f,  0xf77e,  0xc71d,  0xd73c,
X    0x26d3,  0x36f2,  0x0691,  0x16b0,  0x6657,  0x7676,  0x4615,  0x5634,
X    0xd94c,  0xc96d,  0xf90e,  0xe92f,  0x99c8,  0x89e9,  0xb98a,  0xa9ab,
X    0x5844,  0x4865,  0x7806,  0x6827,  0x18c0,  0x08e1,  0x3882,  0x28a3,
X    0xcb7d,  0xdb5c,  0xeb3f,  0xfb1e,  0x8bf9,  0x9bd8,  0xabbb,  0xbb9a,
X    0x4a75,  0x5a54,  0x6a37,  0x7a16,  0x0af1,  0x1ad0,  0x2ab3,  0x3a92,
X    0xfd2e,  0xed0f,  0xdd6c,  0xcd4d,  0xbdaa,  0xad8b,  0x9de8,  0x8dc9,
X    0x7c26,  0x6c07,  0x5c64,  0x4c45,  0x3ca2,  0x2c83,  0x1ce0,  0x0cc1,
X    0xef1f,  0xff3e,  0xcf5d,  0xdf7c,  0xaf9b,  0xbfba,  0x8fd9,  0x9ff8,
X    0x6e17,  0x7e36,  0x4e55,  0x5e74,  0x2e93,  0x3eb2,  0x0ed1,  0x1ef0
X};
X
X#define updcrc(ch, crc) (crctab[((crc >> 8) ^ ch) & 0xff] ^ (crc << 8))
X
Xstatic Do_Checksum(Ch)
X unsigned Ch;
X{
X    if (QBP_cm == 0) {		/* Normal B Checksum */
X	Checksum <<= 1;
X	if (Checksum > 0xff)
X	    Checksum = (Checksum & 0xff) + 1;
X
X	Checksum += (Ch & 0xff);
X	if (Checksum > 0xff)
X	    Checksum = (Checksum & 0xff) + 1;
X    } else 			/* XMODEM CRC-16 */
X	Checksum = (updcrc(Ch & 0xff, Checksum) & 0xffff);
X				/* The 0xffff is due to the fact that my
X				   machine uses four-byte integers! */
X}
X
Xstatic int Read_Packet(Action)
Xint Action;
X{
X    int Next_Seq;
X    int Errors = 0;
X    char *msg = "Timeout";
X    int his_chk;
X    char mesag[30];
X
X    while (Errors < Max_Errors && !Wants_To_Abort())
X	switch (Action) {
X	case R_Get_DLE:
X	    if (Read_Byte() == Failure)
X		Action = R_Send_NAK;
X	    else if (Ch == DLE)
X		Action = R_Get_B;
X	    else if (Ch == ENQ)
X		Action = R_Send_ACK;
X	    break;
X
X	case R_Get_B:
X	    if (Read_Byte() == Failure)
X	        Action = R_Send_NAK;
X	    else if (Ch == 'B')
X		Action = R_Get_Seq;
X	    else
X		Action = R_Get_DLE;
X	    break;
X
X	case R_Get_Seq:
X	    if (Read_Byte() == Failure)
X		Action = R_Send_NAK;
X	    else {
X		Checksum = QBP_cm ? -1 : 0;
X		Next_Seq = Ch - '0';
X		Do_Checksum(Ch);
X		R_Size = 0;
X		Action = R_Get_Data;
X	    }
X
X	case R_Get_Data:
X	    if (Read_Masked_Byte() == Failure)
X		Action = R_Send_NAK;
X	    else if (Seen_ETX)
X		Action = R_Get_Checksum;
X	    else if (R_Size > QBP_Packet) {
X		msg = "Overrun";
X		Action = R_Send_NAK;
X	    } else {
X		R_Buffer[R_Size++] = Ch;
X		Do_Checksum(Ch);
X	    }
X
X	    break;
X
X	case R_Get_Checksum:
X	    Do_Checksum(ETX);
X
X	    if (Read_Masked_Byte() == Failure) {
X		Action = R_Send_NAK;
X		break;
X	    }
X
X	    if (QBP_cm) {
X		his_chk = Ch<<8;
X		if (Read_Masked_Byte() == Failure) {
X		    Action = R_Send_NAK;
X		    break;
X		}
X		his_chk |= Ch;
X	    } else
X		his_chk = Ch;
X
X	    if (Checksum != his_chk) {
X		sprintf(mesag, "Checksum %4x s/b %4x", his_chk, Checksum);
X		msg = mesag;
X		Action = R_Send_NAK;
X	    } else if (Next_Seq == Seq_Num)
X		Action = R_Send_ACK;
X	    else if (Next_Seq != (Seq_Num + 1) % 10) {
X		msg = "Bad Block";
X		Action = R_Send_NAK;
X	    } else {
X		Seq_Num = Next_Seq;
X		return Success;
X	    }
X
X	    break;
X
X	case R_Send_NAK:
X	    Errors++;
X	    Send_Byte(NAK);
X	    Show_NAK(msg);
X	    Action = R_Get_DLE;
X	    break;
X
X	case R_Send_ACK:
X	    Send_ACK();
X	    Action = R_Get_DLE;
X	    break;
X    }
X
X    return Failure;
X}
X
X#define Next_W(ind)	(ind++, ind %=QBP_ws)
X
Xstatic int Send_Window(Size)
X int Size;                      /* size of packet to send */
X{
X    int Action;
X    int I;
X    char *ptr;
X    struct QB_Hist *QB_Ptr;
X
X    if (QB_Out == QBP_ws) {
X	if (get_ACK() == Failure)
X	    return Failure;
X    }
X
X    QB_Ptr = &QB_Buf[QB_Current];
X
X    Seq_Num = (Seq_Num + 1) % 10;
X
X    Checksum = QBP_cm ? -1 : 0;
X    QB_Ptr->block = ++XMIT_Count;
X    QB_Ptr->seq = Seq_Num + '0';
X    Do_Checksum(Seq_Num + '0');
X
X    QB_Ptr->size = Size;
X    for (ptr = QB_Ptr->buf, I = 0; I < Size; I++) {
X	Do_Checksum(S_Buffer[I] + 0);
X	*ptr++ = S_Buffer[I];
X    }
X    Do_Checksum(ETX);
X    QB_Ptr->chk = Checksum;
X
X    Send_Buf(QB_Current);
X    QB_Out++;
X    Next_W(QB_Current);
X
X    return Success;
X}
X
XSend_Buf(Ind)
X{
X    char *ptr;
X    int i;
X
X    struct QB_Hist *QB_Ptr = &QB_Buf[Ind];
X
X    Show_XMIT(XMIT_Count == QB_Ptr->block?"Trans":"Retrans");
X
X    Send_Byte(DLE);
X    Send_Byte('B');
X    Send_Byte(QB_Ptr->seq);
X    for (ptr = QB_Ptr->buf, i = QB_Ptr->size; i > 0; i--)
X	Send_Masked_Byte(*ptr++);
X
X    Send_Byte(ETX);
X    if (QBP_cm)
X	Send_Masked_Byte(QB_Ptr->chk >> 8);
X
X    Send_Masked_Byte(QB_Ptr->chk & 0xff);
X
X}
X
Xget_ACK()
X{
X    int Action = S_Get_DLE;
X    int Errors = 0;
X    int hold, cnt;
X
X    Errors = 0;
X
X    while (QB_Out >= QBP_ws) {
X	if (Errors > Max_Errors || Wants_To_Abort())
X	    return Failure;
X
X	switch (Action) {
X	case S_Get_DLE:
X	    if (Read_Byte() == Failure) {
X		Action = S_Timed_Out;
X		break;
X	    }
X
X	    if (Ch == DLE) {
X		Action = S_Get_Num;
X		break;
X	    }
X
X	    if (Ch == NAK) {
X		Action = S_Got_NAK;
X		break;
X	    }
X
X	    break;
X
X	case S_Timed_Out:
X	    Errors++;
X	    Action = S_Get_DLE;
X	    break;
X
X	case S_Get_Num:
X	    if (Read_Byte() == Failure) {
X		Action = S_Timed_Out;
X		break;
X	    }
X
X	    if (Ch < '0' || Ch > '9') {
X		Errors++;
X		Action = S_Get_DLE;
X		break;
X	    }
X					/* Figure out which block was ACK'd */
X	    while (QB_Buf[QB_Old].seq != Ch && QB_Out > 0) {
X		QB_Out--;
X		Next_W(QB_Old);
X	    }
X
X	    if (QB_Buf[QB_Old].seq != Ch)
X		return Failure;		/* total loss of sync! */
X
X	    Show_W_ACK();
X	    Action = S_Get_DLE;
X	    break;
X
X	case S_Got_NAK:
X	    Show_NAK();
X
X	    QB_Current = QB_Old;	/* Reset currency point */
X	    for (cnt = 0; cnt < QB_Out; cnt++, Next_W(QB_Current)) {
X		if (Wants_To_Abort())
X		    return Failure;
X		Send_Buf(QB_Current);
X	    }
X
X	    Action = S_Get_DLE;
X	    break;
X	}
X    }
X
X    return Success;
X}
X
Xstatic int Send_Packet(Size)
Xint Size;                           /* size of packet to send */
X{
X    int Action, Next_Seq, RCV_Num, I, Errors, his_chk;
X    char *msg = "Timeout";
X    char mesag[30];
X
X    Next_Seq = (Seq_Num + 1) % 10;
X    Errors = 0;
X    Action = S_Send_Packet;
X
X    while (Errors < Max_Errors && !Wants_To_Abort())
X	switch (Action) {
X	case S_Send_Packet:
X	    Checksum = 0;
X	    Send_Byte(DLE);
X	    Send_Byte('B');
X	    Send_Byte(Next_Seq + '0');
X	    Do_Checksum(Next_Seq + '0');
X
X	    for (I = 0; I < Size; I++) {
X		Send_Masked_Byte(S_Buffer[I]);
X		Do_Checksum(S_Buffer[I] + 0);
X	    }
X
X	    Send_Byte(ETX);
X	    Do_Checksum(ETX);
X	    Send_Masked_Byte(Checksum & 0xff);
X	    Action = S_Get_DLE;
X	    break;
X
X	case S_Get_DLE:
X	    if (Read_Byte() == Failure)
X	        Action = S_Timed_Out;
X	    else if (Ch == DLE)
X		Action = S_Get_Num;
X	    else if (Ch == NAK) {
X		Errors++;
X		Action = S_Send_Packet;
X		Show_NAK("Unknown");
X	    }
X
X	    break;
X
X	case S_Get_Num:
X	    if (Read_Byte() == Failure) Action = S_Timed_Out;
X	    else if (Ch >= '0' && Ch <= '9')
X	    {
X		if (Ch == Seq_Num + '0')
X			Action = S_Get_DLE;
X		else if (Ch == Next_Seq + '0')
X		{
X			Seq_Num = Next_Seq;
X			return Success;
X		}
X		else if (Errors == 0) Action = S_Send_Packet;
X		else Action = S_Get_DLE;
X	    }
X	    else if (Ch == WACK)
X	    {
X		sleep(5);        /* Sleep for 5 seconds */
X		Action = S_Get_DLE;
X	    }
X	    else if (Ch == 'B') Action = S_Get_Seq;
X	    else Action = S_Get_DLE;
X	    break;
X
X	case S_Get_Seq:
X	/**
X	 * Start of a "B" protocol packet. The only packet that makes
X	 * any sense here is a failure packet.
X	 **/
X
X	    if (Read_Byte() == Failure)
X		Action = S_Send_NAK;
X	    else
X	    {
X		Checksum = 0;
X		RCV_Num = Ch - '0';
X		Do_Checksum(Ch);
X		I = 0;
X		Action = S_Get_Data;
X	    }
X
X	    break;
X
X	case S_Get_Data:
X	    if (Read_Masked_Byte() == Failure)
X		Action = S_Send_NAK;
X	    else if (Seen_ETX)
X		Action = S_Get_Checksum;
X	    else if (I > QBP_Packet) {
X		msg = "Overrun";
X		Action = S_Send_NAK;
X	    } else {
X		R_Buffer[I++] = Ch;
X		Do_Checksum(Ch);
X	    }
X
X	    break;
X
X	case S_Get_Checksum:
X	    Do_Checksum(ETX);
X
X	    if (Read_Masked_Byte() == Failure)
X		Action = S_Send_NAK;
X
X	    if (QBP_cm) {
X		his_chk = Ch<<8;
X		if (Read_Masked_Byte() == Failure) {
X		    Action = R_Send_NAK;
X		    break;
X		}
X		his_chk |= Ch;
X	    } else
X		his_chk = Ch;
X
X	    if (Checksum != his_chk) {
X		sprintf(mesag, "Checksum %4x s/b %4x", his_chk, Checksum);
X		msg = mesag;
X		Action = S_Send_NAK;
X	    }
X	    else if (RCV_Num != (Next_Seq + 1) % 10)
X	    {
X		msg = "Sequence";
X		Action = S_Send_NAK;
X	    }
X	    else
X	    {
X       /**
X	 * Assume the packet is failure packet. It makes no
X	 * difference since any other type of packet would be
X	 * invalid anyway. Return failure to caller.
X	 **/
X
X		Errors = Max_Errors;
X	    }
X
X	    break;
X
X	case S_Timed_Out:
X	    Errors++;
X	    Action = S_Get_DLE;
X	    break;
X
X	case S_Send_NAK:
X	    Errors++;
X	    Send_Byte(NAK);
X	    Action = S_Get_DLE;
X	    Show_NAK(msg);
X	    break;
X	}
X
X    return Failure;
X}
X
Xstatic Send_Failure()
X{
X    register i;
X
X    if (Failure_Sent++)
X	return;
X
X    Send_Byte(DLE);	/* Panic abort (usually works) */
X    Send_Byte(DLE);
X    Send_Byte(DLE);
X    Send_Byte(DLE);
X    Send_Byte(DLE);
X}
X
Xstatic int Receive_File(Name)
Xchar *Name;
X{
X    FILE *Data_File;
X    int exists = (access(Name, 0) == 0);
X
X    if (!mungmode && exists) {
X	Put_Msg("Transfer aborted due to file pre-existance.");
X	Send_Failure();
X	return Failure;
X    }
X
X    if ((Data_File = fopen(Name, "w")) == NULL) {
X	Put_Msg("Cannot create file");
X	Send_Failure();
X	return Failure;
X    }
X
X    if ((Data_File = fopen(Name, "w")) == NULL) {
X	Put_Msg("Cannot create file");
X	Send_Failure();
X	return Failure;
X    }
X
X    fprintf(tfp,"Receiving %s file %s\r\n", Text_Mode ? "Ascii":"Binary", Name);
X    Send_ACK();
X
X    for (;;)
X	if (Read_Packet(R_Get_DLE) == Success)
X	    switch (R_Buffer[0]) {
X	    case 'N':               /* Data packet */
X		if (Write(Data_File, &R_Buffer[1], R_Size - 1)) {
X		    Put_Msg("Disk write error");
X		    Send_Failure();
X		    fclose(Data_File);
X		    return Failure;
X		}
X
X		if (Wants_To_Abort()) {
X		    Send_Failure();
X		    fclose(Data_File);
X		    return Failure;
X		}
X
X		Send_ACK();
X		Show_ACK();
X		break;
X
X	    case 'T':               /* Transfer packet */
X		if (R_Buffer[1] == 'C') {
X		    Send_ACK();
X		    fclose(Data_File);
X		    return Success;
X		} else {
X		    Put_Msg("Unexpected packet type");
X		    Send_Failure();
X		    fclose(Data_File);
X		    return Failure;
X		}
X
X	    case 'F':               /* Failure packet */
X		Send_ACK();
X		fclose(Data_File);
X		return Failure;
X	    }
X    else {
X	fclose(Data_File);
X	return Failure;
X    }
X}
X
Xstatic int Send_File(Name)
Xchar *Name;
X{
X    FILE *Data_File;
X    int N;
X    long size;
X
X    if ((Data_File = fopen(Name, "r")) == NULL)
X    {
X	Put_Msg("Cannot access that file");
X	Send_Failure();
X	return Failure;
X    }
X
X    size = filelength(Data_File);
X
X    fprintf(tfp,"Transmitting %s file %s  (%ld bytes -- %ldK)\r\n",
X	    Text_Mode ? "Ascii":"Binary", Name, size, size / 1024);
X
X    do {
X	S_Buffer[0] = 'N';
X	N = Read(Data_File, &S_Buffer[1], QBP_Packet);
X
X	if (N > 0) {
X	    if (Send_Window(N + 1) == Failure) {
X		fclose(Data_File);
X		return Failure;
X	    }
X
X	    if (Wants_To_Abort()) {
X		Send_Failure();
X		fclose(Data_File);
X		return Failure;
X	    }
X	}
X    }    while (N > 0);
X
X    if (N == 0) {
X	fclose(Data_File);
X	S_Buffer[0] = 'T';
X	S_Buffer[1] = 'C';
X	if (Send_Window(2) == Failure)
X	    return Failure;
X	return get_ACK();
X    } else {
X	Put_Msg("Disk read error");
X	Send_Failure();
X	return Failure;
X    }
X}
X
Xstatic int Transfer_File()
X{
X    XOFF_Flag = FALSE;
X    Seq_Num = 0;
X
X    for (;;) {
X	if (Read_Packet(R_Get_DLE) == Success)
X	    switch (R_Buffer[0]) {
X	    case '+':			/* Get/Set QB Parameters */
X		Get_QB_Parms();
X		break;
X
X	    case 'T':			/* Transfer packet */
X		return do_transfer();
X		break;
X
X	    default:
X		Send_Failure();	/* Undefined packet */
X		return Failure;
X	    }
X	else
X	    return Failure;
X    }
X}
X
Xstatic int Get_QB_Parms()
X{
X    S_Buffer[0] = '+';
X    S_Buffer[1] = QBP_wr = min(1, R_Buffer[1]);
X    S_Buffer[2] = QBP_ws = min(MAX_WINDOW - 1, R_Buffer[2]);
X    S_Buffer[3] = QBP_bs = min(MAX_PACKET / 128, R_Buffer[3]);
X    S_Buffer[4] = min(1, R_Buffer[4]);
X    S_Buffer[5] = QBP_dq = 1;			/* Normal B Protocol Quoting */
X    
X    QBP_ws++;					/* Actual window size */
X
X    if (Send_Packet(6) != Success)
X	return Failure;
X
X    QBP_cm = S_Buffer[4];
X    QBP_Active = TRUE;
X    QBP_Packet = QBP_bs * 128;
X}
X
Xdo_transfer()
X{
X    int I, N;
X    char *Name;
X
X    /* Check data direction */
X
X    if (R_Buffer[1] != 'D' && R_Buffer[1] != 'U')
X    {
X	Send_Failure();      /* not implemented */
X	return Failure;
X    }
X
X    /* Check the file type */
X
X    if (R_Buffer[2] != 'A' && R_Buffer[2] != 'B')
X    {
X	Send_Failure();
X	return Failure;
X    }
X
X    /* Let CIS tell us if it is Ascii or not */
X
X    Text_Mode = (R_Buffer[2] == 'A');
X
X    /* Collect the file name */
X
X    Name = &R_Buffer[3];
X    Name[R_Size - 3] = '\0';
X
X    /* Do the transfer */
X
X    start_time = time(NULL);
X
X    if (R_Buffer[1] == 'U') 
X	return Send_File(Name);
X    else 
X	return Receive_File(Name);
X}
X
Xstatic Write(fp, buf, cnt)
X FILE *fp;
X char *buf;
X int cnt;
X{
X    for (; cnt-- > 0; buf++) {
X	io_count++;
X
X	if (Text_Mode && (*buf == '\r' && *(buf+1) == '\n'))
X	    continue;
X
X	if (putc(*buf, fp) == EOF)
X	    return -1;
X    }
X
X    return 0;
X}
X
Xstatic Read(fp, buf, max)
X FILE *fp;
X char *buf;
X int max;
X{
X    int c, cnt = 0;
X
X    while (max--)
X	switch (c = getc(fp)) {
X	case EOF:
X	    return cnt;
X
X	case '\n':
X	    if (Text_Mode && Last_Chr != '\r') {
X		ungetc(c, fp);
X		c = '\r';
X	    }
X	
X	default:
X	    Last_Chr = *buf++ = c;
X	    cnt++; io_count++;
X	    break;
X	}
X
X    return cnt;
X}
X
Xint B_Transfer(mode)
X{
X    int rc;
X    void newsigint();
X    long elapsed;
X
X    QBP_Active = FALSE;		/* Start in normal B Mode */
X    QBP_ws = 0;
X    QBP_wr = 0;
X    QBP_bs = 0;
X    QBP_cm = 0;
X    QBP_dq = 0;
X    QBP_Packet = 512;		/* Normal packet size maximum */
X
X    fprintf(tfp,"CIS QuickB Protocol Transfer\r\n");
X
X    Failure_Sent = Abort_Flag = Last_Chr = 0;
X    XMIT_Count = ACK_Count = NAK_Count = 0;
X    io_count = 0L;
X
X    signal(SIGINT, newsigint);
X    intdel(1);
X
X    if (setjmp(err_buf) == 0) {
X	xc_setxon(0);			/* turn off flow control */
X
X	Send_Byte(NAK);
X
X	if (startup() == Failure)
X	    Abort_Flag = 1;
X	else
X	    rc = Transfer_File();
X    }
X
X    if (Abort_Flag) {
X	Send_Failure();
X	purge();
X    }
X
X    if (Abort_Flag || rc == Failure)
X	fprintf(tfp,"\r\nFile Transfer aborted\r\n");
X    else
X	fprintf(tfp,"\r\nFile Transfer successful\r\n");
X
X    if (io_count) {
X	elapsed = time(NULL) - start_time;
X	if (elapsed > 0) {
X	    bytes_sec = io_count / start_time;
X	    fprintf(tfp,"Average %ld bytes/sec\r\n", bytes_sec);
X	}
X    }
X
X    xclog(0,0);
X
X    intdel(0);
X    signal(SIGINT, SIG_IGN);
X
X    return rc;
X}
X
Xstatic startup()
X{
X    int ch;
X
X    do {
X	Read_Byte();
X	if (Ch != ENQ)
X	    Send_Byte(NAK);
X	if (Wants_To_Abort())
X	    return Failure;
X    } while (Ch != ENQ);
X
X    Send_Byte(DLE); Send_Byte('+');	/* Quick B Indicator */
X    Send_Byte(DLE); Send_Byte('0');
X
X    return Success;
X}
X
Xstatic void newsigint()
X{
X    Abort_Flag = 1;
X
X    signal(SIGINT, SIG_IGN);
X
X    fprintf(tfp,"\r\nUser Abort...\r\n");
X}
SHAR_EOF
if test 23009 -ne "`wc -c < 'xccisb.c'`"
then
	echo shar: error transmitting "'xccisb.c'" '(should have been 23009 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'xcomm.c'" '(17910 characters)'
if test -f 'xcomm.c'
then
	echo shar: will not over-write existing file "'xcomm.c'"
else
sed 's/^X//' << \SHAR_EOF > 'xcomm.c'
X/*
X	xcomm		External (and XMODEM) Communications
X			By Eric E. Coe
X
X			Version 2.0 and above by larry gensch, ESQ
X
X   This program is in the public domain, and anyone can use it for
X   personal or non-profit use.  Feel free to study the code and borrow
X   from it (I borrowed from other programs to create it).
X
X   I am supporting versions 2.0 and higher of XCOMM.  Information (bug
X   fixes, requests, etc.) may be sent to any one of the following electronic
X   addresses:
X
X   CompuServe				[72236,3516]	UNIXFORUM
X   Delphi				LARRYG
X   Bix					lar3ry
X   Andover CNode (BBS) [617-470-2548]	larry gensch
X
X   -lar3ry gensch
X    programmer extraordinaire
X
X*/
X
X#define  VERSION   "2.2"
X
X/*
X		R E V I S I O N     H I S T O R Y
X
XVersion 2.2	larry gensch	12/8/87		Major code restructure
X    Reduced program and command options
X    Added SET command for setting various parameters
X    Added HANGUP command for disconnecting modem
X    Modified xccisb.c code to support CIS "Quick B" Protocol
X    Added xcscrpt.c code for processing script files
X    Added SCRIPT= parameter to phonebook processing (auto-logon scripts)
X    Added CIS parameter for CIS <ENQ> auto transfers
X    Added NL parameter for newline translation
X    Added HANGUP command from terminal mode
X    Added SCRIPT command from terminal mode
X
XVersion 2.1b	larry gensch	11/11/87	Bug Fix release
X    (no bugs in the code, just some portability fixes)
X    Changed "sigset" in xccisb to "signal"
X    Removed #include <setjmp.h> from xcxmdm
X
XVersion 2.1a	larry gensch	10/28/87	General Update
X    Added CIS "B" Protocol (c, ct commands)
X    Added BAUD= & BITS= parameters to phonelist file.
X    Switched some command letters
X    Revised command line parsing to use getopt()
X
XVersion 2.0	larry gensch	10/19/87	Revisions for System V.3
X    Basically version 1.1 with minor modifications
X
XVersion 1.1	Eric E Coe	7/21/85
X    Autodial for Hayes-compatible modem.
X    General rearranging of the code
X
XVersion 1.0	Eric E Coe	4/12/85
X    Program created
X*/
X
X#include <stdio.h>
X#include <signal.h>
X#include <ctype.h>
X#include <termio.h>
X
X#include "xcomm.h"
X
X/* globals */
X
Xjmp_buf erret;			/* non-local error return */
Xint mungmode = FALSE;		/* ok to overwrite files? */
Xint nlmode = TRUE;		/* Map newlines to carriage returns */
Xint stat_flag = FALSE;		/* Flag for status display */
X
X/* locals */
Xstruct termio newmode, oldmode, sigmode;
X
Xstatic int termflag = 0;
Xstatic int reterm = 0;
X
Xint tfd;
XFILE *tfp;
X
Xvoid s_cis(), s_script(), s_xmodem(), s_set(), s_term(), s_exit();
Xvoid s_shell(), s_help(), hangup();
X
X#ifdef PUT_TAKE
Xvoid puttake();
X#endif
X
X/*
X    Command table
X*/
X
Xstatic struct kw cmds[] = {
X	{ "c",		s_cis },
X	{ "g",		s_script },
X	{ "hangup",	hangup },
X	{ "rb",		s_xmodem },
X	{ "rt",		s_xmodem },
X	{ "sb",		s_xmodem },
X	{ "st",		s_xmodem },
X	{ "set",	s_set },
X	{ "t",		s_term },
X	{ "x",		s_exit },
X	{ "exit",	s_exit },
X	{ "!",		s_shell },
X	{ "!!",		s_shell },
X	{ "$",		s_shell },
X#ifdef PUT_TAKE
X	{ "%p",		puttake },
X	{ "%t",		puttake },
X#endif
X	{ "help",	s_help },
X	{ "?",		s_help },
X	{ NULL,		NULL }};
X
Xstatic char oldshell[WBSIZE];
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X    extern char *optarg;
X    extern int optind, opterr;
X
X    struct kw *ptr;
X    void catch();
X    int c;
X    char *script = NULL;
X
X    if ((tfp = fopen("/dev/tty", "r+")) == NULL) {
X	fprintf(stderr, "Cannot access local terminal!\n");
X	exit(1);
X    }
X
X    tfd = fileno(tfp);
X
X    ioctl(tfd, TCGETA, &oldmode);	/* get current console tty mode	*/
X    newmode = oldmode;                  /* copy (structure) to newmode  */
X
X    newmode.c_oflag = 0;
X    newmode.c_iflag &= ~(IXON | IXOFF);
X    newmode.c_lflag &= ~(ICANON | ISIG | ECHO);
X    newmode.c_cc[VMIN] = 1;
X    newmode.c_cc[VTIME] = 1;
X
X    sigmode = newmode;
X    sigmode.c_lflag |= ISIG;
X
X    nlmode = TRUE;
X
X    oldshell[0] = '\0';		/* set last command to blank    */
X    reterm = FALSE;		/* no direct jump into terminal mode */
X    if(setjmp(erret))		/* set error handler to exit    */
X        exit(0);		/* while parsing command line   */
X    signal(SIGINT, catch);	/* catch break & quit signals/keys */
X    signal(SIGQUIT, catch);
X
X    opterr = 0;				/* Disable getopt error messages */
X    while ((c = getopt(argc, argv, "g:l:t")) != -1)
X	switch (c) {
X	case 'l':			/* set modem port name          */
X	    mport(optarg);
X	    break;
X	case 'g':			/* Execute SCRIPT file		*/
X	    script = optarg;
X	    break;
X	case 't':			/* jump into terminal mode	*/
X	    reterm = TRUE;
X	    break;
X	default:			/* Bad command .. print help	*/
X	    usage();
X	    exit(1);
X	}
X
X    if(mopen() < 0) {			/* open modem port and configure */
X        fprintf(stderr, "Error in modem initialization routine.\r\n");
X        fprintf(stderr, "Check environment variable MODEM for modem port.\r\n");
X        exit(1);
X    }
X
X    setuid(getuid());			/* Return to being oneself. */
X
X    intdel(0);
X
X    do_startup();
X
X    status();       /* display all parameters */
X
X    fprintf(tfp, "Type \"help\" or ? for help\r\n");
X
X    for (;;) {
X        setjmp(erret);
X	ioctl(tfd, TCSETAW, &newmode);
X	eof_flag = 0;
X
X	if (script) {
X	    do_script(script);
X	    script = NULL;
X	    reterm = 1;
X	}
X
X	if (reterm) {
X	    reterm = 0;
X	    s_term();
X	    continue;
X	}
X
X	intdel(1);
X        fprintf(tfp, "\r\nXCOMM> ");	/* command prompt               */
X
X	getsome(line);
X	intdel(0);
X
X	fprintf(tfp, "\r\n");
X
X	getword();
X	if (word[0] == '\0')		/* If blank line... reprompt	*/
X	    continue;
X
X	for (ptr = cmds; ptr->keyword != NULL; ptr++) 
X	    if (strcmp(word, ptr->keyword) == 0)
X		break;
X
X	if (ptr->keyword)
X	    (*ptr->rtn)();
X	else 
X	    fprintf(tfp, "Unrecognized keyword: %s\r\n", word);
X    }
X
X}
X
Xstatic char *babble[] = {
X"Usage:  xcomm [-l device] [-t] [-g file]",
X"",
X"-l device      Use 'device' as the modem port (eg, -l /dev/tty00)",
X"-t             Enter terminal mode immediately",
X"-g file        Execute script file 'file' immediately",
X"",
XNULL };
X
Xusage()
X{
X    char **ptr;
X
X    for (ptr = babble; *ptr != NULL; ptr++)
X	fprintf(stderr, "%s\r\n", *ptr);
X}
X    
Xvoid s_script()
X{
X    getword();
X
X    if (word[0] == '\0') {
X	fprintf(tfp, "Script file not specified\r\n");
X	return;
X    }
X
X    do_script(word);
X    reterm = 1;
X}
X
Xvoid s_xmodem()
X{
X    char d = word[0];
X    char c = word[1];
X
X    getword();
X    if (word[0] == '\0')
X	fprintf(tfp, "No transfer file specified\r\n");
X    else if (d == 's')
X	xsend(c);
X    else
X	xreceive(c);
X
X    reterm = termflag;
X}
X
Xvoid s_exit()
X{
X    signal(SIGINT, SIG_IGN);
X    signal(SIGQUIT, SIG_IGN);
X
X    do_exit(0);
X}
X
Xvoid s_term()
X{
X    for (;;) {
X	terminal();
X	if (cismode != 2)
X	    return;
X	cismode = 1;
X	B_Transfer();
X    }
X}
X
Xvoid s_cis()
X{
X    B_Transfer();
X    reterm = termflag;
X}
X
Xvoid s_shell()
X{
X    char c = word[0];
X    char *ptr;
X    static char *shell = NULL;
X    char *getenv();
X    int child;
X
X    if (word[0] == word[1])
X	strcpy(wptr=word, oldshell);
X    else {
X	getword();
X	if (*wptr)
X	    strcpy(oldshell, wptr);
X    }
X	
X    if (!shell) {
X	shell = getenv("SHELL");
X	if (!shell)
X	    shell = "/bin/sh";
X    }
X
X    signal(SIGCLD, SIG_DFL);
X
X    ioctl(tfd, TCSETAW, &oldmode);
X
X    if ((child = forkem()) == 0) {
X	if (c == '$')	/* Attach modem to stdin, stdout */
X	    mattach();
X	if (word[0] == '\0')
X	    execl(shell, shell, "-i", (char *) NULL);
X	else
X	    execl(shell, shell, "-c", wptr, (char *) NULL);
X	fprintf(stderr, "Exec failed!");
X	exit(1);
X    }
X
X    signal(SIGINT, SIG_IGN);
X    signal(SIGQUIT, SIG_IGN);
X
X    while (wait((int *) 0) >= 0)
X	;
X
X    intdel(0);
X
X    strcpy(oldshell, wptr);
X
X    signal(SIGINT, catch);	/* catch break & quit signals/keys */
X    signal(SIGQUIT, catch);
X}
X
Xstatic char *cmdlist[] = {
X"XCOMM Command Summary",
X" ",
X"c               <-- Initiate CIS QuickB File Transfer (Upload and Download)",
X"g file          <-- Execute XCOMM Script file",
X"rb file         <-- XMODEM receive (binary mode)",
X"rt file         <-- XMODEM receive (Ascii mode)",
X"sb file...      <-- XMODEM send (binary mode)",
X"st file...      <-- XMODEM send (Ascii mode)",
X"set ...         <-- XCOMM Parameter set",
X"t               <-- Enter terminal emulation",
X"x               <-- Exit program",
X" ",
X"!               <-- Execute a local interactive shell",
X"! cmd           <-- Execute shell command string on the local system",
X"!!              <-- Re-execute the last shell command string",
X"$ cmd           <-- Shell command with stdin and stdout redirected to modem",
X"%p file         <-- Put file (transmit a file to a UNIX system)",
X"%t file         <-- Take file (receive a file from a UNIX system)",
X"?               <-- Print this help message",
X" ",
X" ",
X"",
X"SET Keywords:",
X" ",
X"set                     Display current XCOMM status",
X"set 7bit  on|off        Set/Reset 7-bit data mask (ignore high bits)",
X"set crc   on|off        Enable/Disable Xmodem CRC",
X"set term  on|off        Enable/Disable terminal mode after file transfer",
X"set cis   on|off        Set/Reset CIS <ENQ> mode (Auto up/download)",
X"set mung  on|off        Set/Reset file overwrite",
X"set nl    on|off        Set/Reset Terminal mode newline translation",
X"set purge on|off        Set/Reset bad phone line mode",
X"set xoff  on|off        Set/Reset XON/XOFF flow control",
X"set baud  <value>       Set baud rate to <value>",
X"set cfile name          Change name of capture file",
X"set pfile name          Change name of phonelist file",
XNULL };
X
Xvoid s_help()
X{
X    char **ptr = cmdlist;
X
X    for ( ; *ptr != NULL; ptr++)
X	if (**ptr)
X	    fprintf(tfp, "%s\r\n", *ptr);
X	else {
X	    fprintf(tfp, "PRESS ENTER: ");
X	    getsome(line);
X	    erasln();
X	}
X}
X
Xvoid s_set_7bit(), s_set_crc(), s_set_term(), s_set_cis(), s_set_mung();
Xvoid s_set_purge(), s_set_xoff(), s_set_baud(), s_set_cfile(), s_set_pfile();
Xvoid s_set_cr();
X
Xstatic struct kw setlist[] = {
X	{ "7bit",	s_set_7bit },
X	{ "crc",	s_set_crc },
X	{ "term",	s_set_term },
X	{ "nl",		s_set_cr },
X	{ "cis",	s_set_cis },
X	{ "mung",	s_set_mung },
X	{ "purge",	s_set_purge },
X	{ "xoff",	s_set_xoff },
X	{ "baud",	s_set_baud },
X	{ "cfile",	s_set_cfile },
X	{ "pfile",	s_set_pfile },
X	{ NULL,		NULL }};
X
Xvoid s_set()
X{
X    struct kw *ptr;
X
X    getword();
X
X    if (word[0] == '\0' && !scriptflag) {
X	status();
X	return;
X    } else if (word[0] == '\0') {
X	fprintf(tfp, "SET keyword requires an argument\r\n");
X	eof_flag++;
X	return;
X    }
X
X    lc_word(word);
X
X    for (ptr = setlist; ptr->keyword != NULL; ptr++)
X	if (strcmp(ptr->keyword, word) == 0) {
X	    (*ptr->rtn)();
X	    return;
X	}
X
X    fprintf(tfp, "Invalid SET keyword: %s\r\n", word);
X    eof_flag++;
X}
X
Xstatic char *statfmt = "%-8s %30s is %s\r\n";
X
Xvoid s_set_7bit()
X{
X    int val;
X
X    if (stat_flag) {
X	fprintf(tfp, statfmt, "7bit", "Seven-bit Mask",
X		bitmask==0x7f?"ON":"OFF");
X	return;
X    }
X
X    set_onoff(&val);
X    bitmask = val?0x7f:0xff;
X
X    if (!scriptflag)
X	fprintf(tfp, "<<%s-bit mask enabled>>\r\n", val?"Seven":"Eight");
X}
X
Xvoid s_set_crc()
X{
X    if (stat_flag) {
X	fprintf(tfp, statfmt, "crc", "Xmodem CRC",
X		crcheck?"ON":"OFF");
X	return;
X    }
X
X    set_onoff(&crcheck);
X
X    if (!scriptflag)
X	fprintf(tfp, "<<XMODEM %s enabled>>\r\n", 
X		crcheck?"CRC Check":"Checksum");
X}
X
Xvoid s_set_cr()
X{
X    if (stat_flag) {
X	fprintf(tfp, statfmt, "nl", "Terminal NL Translation",
X		nlmode?"ON":"OFF");
X	return;
X    }
X
X    set_onoff(&nlmode);
X
X    if (!scriptflag)
X	fprintf(tfp, "<<%s mode enabled>>\r\n", 
X		nlmode?"Newline translation":"Carriage return");
X}
X
Xvoid s_set_term()
X{
X    if (stat_flag) {
X	fprintf(tfp, statfmt, "term", "Auto Term Mode",
X		termflag?"ON":"OFF");
X	return;
X    }
X
X    set_onoff(&termflag);
X
X    if (!scriptflag)
X	fprintf(tfp, "<<File transfers return to %s mode>>\r\n",
X		termflag?"terminal":"command");
X}
X
Xvoid s_set_cis()
X{
X    if (stat_flag) {
X	fprintf(tfp, statfmt, "cis", "CIS <ENQ> Auto Download",
X		cismode?"ON":"OFF");
X	return;
X    }
X
X    set_onoff(&cismode);
X
X    if (!scriptflag)
X	fprintf(tfp, "<<CIS <ENQ> Auto Download is %s>>\r\n", 
X		cismode?"ON":"OFF");
X}
X
Xvoid s_set_mung()
X{
X    if (stat_flag) {
X	fprintf(tfp, statfmt, "mung", "File Overwrite", mungmode?"ON":"OFF");
X	return;
X    }
X
X    set_onoff(&mungmode);
X
X    if (!scriptflag)
X	fprintf(tfp, "<<File Overwrite is %s>>\r\n", mungmode?"ON":"OFF");
X}
X
Xvoid s_set_purge()
X{
X    if (stat_flag) {
X	fprintf(tfp, statfmt, "purge", "Bad Telephone line",
X		badline?"ON":"OFF");
X	return;
X    }
X
X    set_onoff(&badline);
X
X    if (!scriptflag)
X	fprintf(tfp,"<<Bad telephone line purging is %s\r\n",
X		badline?"ON":"OFF");
X}
X
Xvoid s_set_xoff()
X{
X    if (stat_flag) {
X	fprintf(tfp, statfmt, "xoff", "Terminal mode XON/XOFF",
X		flowflag?"ON":"OFF");
X	return;
X    }
X
X    set_onoff(&flowflag);
X    xc_setflow();
X
X    if (!scriptflag)
X	fprintf(tfp, "<<XON/XOFF Flow control is %s>>\r\n",flowflag?"ON":"OFF");
X}
X
Xset_onoff(flag)
X int *flag;
X{
X    char *strdup();
X    char *ptr = strdup(word);
X
X    getword();
X    lc_word(word);
X
X    if (strcmp(word, "on") == 0) {
X	*flag = 1;
X    } else if (strcmp(word, "off") == 0) {
X	*flag = 0;
X    } else {
X	fprintf(tfp, "Set '%s' value must be 'on' or 'off'.\r\n", ptr);
X	eof_flag++;
X    }
X    
X    if (ptr != NULL)
X	    free(ptr);
X}
X
Xvoid s_set_baud()
X{
X    if (stat_flag) {
X	char br[10];
X
X	sprintf(br, "%d", mbaud((char *) 0));
X	fprintf(tfp, statfmt, "baud", "Baud Rate", br);
X	return;
X    }
X
X    getword();
X    if (word[0] == '\0') {
X	fprintf(tfp, "Set Baud must have a baud rate.\r\n");
X	eof_flag++;
X	return;
X    }
X
X    if (mbaud(word)<0) {
X	fprintf(tfp, "Unsupported baud rate %s\r\n", word);
X	eof_flag++;
X    } else if (!scriptflag)
X	fprintf(tfp, "<<Baud rate set to %d>>\r\n", mbaud((char *) 0));
X}
X
Xvoid s_set_cfile()
X{
X    if (stat_flag) {
X	fprintf(tfp, statfmt, "cfile", "Capture file", captfile);
X	return;
X    }
X
X    getword();
X    if (word[0] == '\0') {
X	fprintf(tfp, "Set CFILE must have file name.\r\n");
X	eof_flag++;
X	return;
X    }
X
X    strcpy(captfile, word);
X
X    if (!scriptflag)
X	fprintf(tfp, "<<Capture file set to '%s'>>\r\n", captfile);
X}
X
Xvoid s_set_pfile()
X{
X    if (stat_flag) {
X	fprintf(tfp, statfmt, "pfile", "Phone number file", phonefile);
X	return;
X    }
X
X    getword();
X    if (word[0] == '\0') {
X	fprintf(tfp, "Set PFILE must have file name.\r\n");
X	eof_flag++;
X	return;
X    }
X
X    strcpy(phonefile, word);
X
X    if (!scriptflag)
X	fprintf(tfp, "<<Phone number file set to '%s'>>\r\n", phonefile);
X}
X
X#ifdef PUT_TAKE
X/*
X    Put and Take a file to/from a UNIX-type "cu" system.  Unfortunately,
X    the stty command is one of those commands that always gets changed
X    with different UNIX systems, so you will get (at least) a file full of
X    ^M on the take command for systems later than V7 or work-alikes.
X
X    Additionally, the Take command takes a bit too much!
X
X    Note:  This code was taken from the original XCOMM; I personally have
X	   not tested it.
X*/
X
Xvoid puttake()
X{
X    FILE *fp;
X    char wrkbuff[WBSIZE];
X    register int i;
X    char c = word[1];
X
X    getword();
X    if (word[0] == '\0') {
X        fprintf(tfp, "Must give a filename with the put and take options.\r\n");
X        return;
X    }
X
X    switch(c) {
X    case 'p':
X        if((fp = fopen(word, "r")) == NULL){
X            fprintf(tfp,"Can't read file '%s'.\r\n", word);
X            break;
X        }
X
X	fprintf(tfp,"Putting file '%s' to UNIX system.\r\n", word);
X        sprintf(wrkbuff, "stty -echo;cat >%s;stty echo\r\n", word);
X        sendstr(wrkbuff);       /* send command string to remote shell */
X        i = 0;
X        while((c = getc(fp)) != EOF){
X            if(++i > 64){       /* this prevents an overload on the */
X                i = 0;          /* receiver's input buffer (64=kludge) */
X                sleep(DRIBBLE);
X            }
X            send_mbyte(c);        /* send characters to cat command */
X        }
X        fclose(fp);
X        send_mbyte('D' - '@');    /* send a ^D to cat */
X        purge();                /* get rid of whatever was sent back */
X        break;
X
X    case 't':
X        if(!mungmode && !access(word, 0)){
X            fprintf(tfp,"Can't over write existing file '%s'.\r\n", word);
X            break;
X        }
X        if((fp = fopen(word, "w")) == NULL){
X            fprintf(tfp,"Can't write file '%s'.\r\n", word);
X            break;
X        }
X
X	fprintf(tfp,"Taking file '%s' from UNIX system.\r\n", word);
X        sprintf(wrkbuff, "stty -echo -onlcr tabs; sleep 3; cat %s; sleep 5; stty echo onlcr -tabs\n", word);
X        sendstr(wrkbuff);       /* send command string to remote shell */
X	sleep(2);		/* wait for remote system to consume command */
X        purge();                /* get rid of the echo */
X        while((c = read_mbyte(3)) != -1)  /* while more chars are being sent */
X            putc(c, fp);
X        fclose(fp);
X        break;
X
X    }
X}
X#endif /* PUT_TAKE */
X
X/*
X    Catch a signal and jump to main.  Reset signal and do a longjmp
X*/
X
Xvoid catch()
X{
X    fprintf(tfp,"\r\nXCOMM: Interrupt\r\n");
X
X    signal(SIGINT, catch);
X    signal(SIGQUIT, catch);
X    longjmp(erret, 1);
X}
X
X/*
X    Print the status of the program
X*/
X
Xstatus()
X{
X    struct kw *ptr;
X    void (*fct)() = NULL;
X
X    stat_flag = 1;
X
X    fprintf(tfp, "\fXCOMM Version %s  by larry gensch - modem port: %s\r\n\n", 
X	    VERSION, mport((char *) NULL));
X    fprintf(tfp, "Keyword              Description and Status\r\n");
X    fprintf(tfp, "-------  ----------------------------------------------\r\n");
X
X    for (ptr = setlist; ptr->keyword != NULL; ptr++)
X	if (ptr->rtn != fct) {
X	    fct = ptr->rtn;
X	    (*fct)();
X	}
X
X    fprintf(tfp, "\r\n");
X    stat_flag = 0;
X}
X
Xdo_exit(rc)
X{
X    unlock_tty();
X
X    fprintf(tfp, "\r\n");
X
X    ioctl(tfd, TCSETAW, &oldmode);
X    ioctl(tfd, TCFLSH, 2);
X
X    fclose(tfp);
X
X    exit(rc);
X}
X
Xdo_startup()
X{
X    char *home, *getenv();
X    char file[WBSIZE];
X
X    if (access(STARTUP, 0) == 0) 
X	strcpy(file, STARTUP);
X    else {
X	if ((home = getenv("HOME")) == NULL)
X	    return;
X	sprintf(file, "%s/%s", home, STARTUP);
X	if (access(file, 0))
X	    return;
X    }
X
X    linkflag = 2;
X    do_script(file);
X}
SHAR_EOF
if test 17910 -ne "`wc -c < 'xcomm.c'`"
then
	echo shar: error transmitting "'xcomm.c'" '(should have been 17910 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'xcomm.h'" '(2044 characters)'
if test -f 'xcomm.h'
then
	echo shar: will not over-write existing file "'xcomm.h'"
else
sed 's/^X//' << \SHAR_EOF > 'xcomm.h'
X/*
X    XCOMM Global Definitions
X*/
X
X#define ENQ		0x05		/* CIS ENQ */
X
X#define ESCAPE_CHR	0x1b
X
X#define ENDCHAR        (('X' & 0x1f) + 128)	/* Exit terminal mode */
X#define TOGCHAR        (('T' & 0x1f) + 128)	/* Toggle capture buffer */
X#define DIVCHAR        (('F' & 0x1f) + 128)	/* Send file through modem */
X#define PSELECT        (('D' & 0x1f) + 128)	/* Dial from phonelist */
X#define HUPCHAR        (('H' & 0x1f) + 128)	/* Hang up modem */
X#define	SCRPCHR	       (('G' & 0x1f) + 128)	/* Execute script file */
X
X#define	CAPTFILE	"capture.log"	/* Default capture file */
X#define PHFILE		".phonelist"	/* Default phonelist file */
X#define STARTUP		".xcomm"	/* XCOMM Startup Script */
X#define DRIBBLE		2		/* Text "dribble" delay */
X#define PUT_TAKE			/* include put/take code */
X#define	CIS_INIT	1		/* cismode default 1=on/0=off */
X
X#define HAVE_DUP2	1		/* 0 if dup2() not available */
X#define	HAVE_STRSTR	0		/* We have to define strstr() */
X#define	HAVE_STRDUP	0		/* We have to define strdup() */
X
X#define	DTR_DROPS_CARRIER	1	/* Dropping DTR drops carrier */
X
X/*
X    Some Berkely and Xenix systems have index() and rindex() which are
X    functionally identical to the more standard strchr() and strrchr()
X    functions.  Drop these defines if your Unix does supports index and
X    rindex INSTEAD of strchr and strrchr.
X*/
X
X#define index           strchr		/* for SYSV */
X#define rindex          strrchr		/* for SYSV */
X
X/*
X    Other defines
X*/
X
X#ifndef TRUE
X#define TRUE    1
X#define FALSE   0
X#endif
X
X#define K       1024
X#define NMSIZE  256             /* file name buffer size */
X#define WBSIZE  256             /* input and working buffer size */
X
X/* globals */
X
X#include <setjmp.h>
X
Xextern jmp_buf erret;
Xextern int verbose, mungmode, bitmask, cbsiz, crcheck, badline, flowflag;
Xextern int cismode, linkflag, quote_flag, eof_flag, nlmode, scriptflag;
Xextern char captfile[NMSIZE], phonefile[NMSIZE], *mport();
Xextern char word[], *wptr, line[];
X
Xstruct kw {			/* Used by command parsing routines */
X    char *keyword;
X    void (*rtn)();
X};
SHAR_EOF
if test 2044 -ne "`wc -c < 'xcomm.h'`"
then
	echo shar: error transmitting "'xcomm.h'" '(should have been 2044 characters)'
fi
fi # end of overwriting check
echo shar: done with directory "'src'"
cd ..
#	End of shell archive
exit 0