[unix-pc.sources] Pcomm

egray@fthood.UUCP (03/13/88)

Hello netlanders!

This is "pcomm"...  the long-awaited replacement for my "mdm" program.

Pcomm is a public domain telecommunication program for Unix designed to
operate similar to the popular MSDOS program, ProComm.  ProComm (TM) is
copyrighted by Datastorm Technologies Inc.

The source code is quite large... (about 300k total) and is broken down
into 6 parts for easier mailing.  Because of it's size, I'm posting half
the code on one day, and the other half the next.

The program has a minor quirk which may be irritating to some...  In order
to get pop-up windows to work while communicating with another system, the
program has to keep a duplicate copy of what it thinks is on the screen.
This "virtual screen" is only used to repaint the background during the 
transition from the terminal mode to the command mode.  The problem is
that the virtual screen currently doesn't "understand" escape sequences.
For example, when the screen is repainted, instead of clearing the screen,
the string "^[[2J" will appear.  Since the virtual screen is ONLY USED in
the command mode, the quirk doesn't detract from the usefulness of the
program (in my humble opinion).  No bug reports on this, please... I'm
working on it!

There is a shell archive, "Unixpc.shar" (included in the distribution)
that contains the files specific to the AT&T Unix PC 7300.

Have fun...

Emmet P. Gray				US Army, HQ III Corps & Fort Hood
...!ihnp4!uiucuxc!fthood!egray		Attn: AFZF-DE-ENV
					Directorate of Engineering & Housing
					Environmental Management Office
					Fort Hood, TX 76544-5057

-----------------------------------------------------------------------------
#! /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:
#	Readme
#	Release.notes
#	Doc
#	Pcomm.1
#	Pcomm.dial_dir
#	Pcomm.modem
#	Pcomm.param
# This archive created: Fri Mar 11 07:34:59 1988
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'Readme'" '(7859 characters)'
if test -f 'Readme'
then
	echo shar: "will not over-write existing file 'Readme'"
else
sed 's/^X//' << \SHAR_EOF > 'Readme'
X
X				  Pcomm
X		      A Unix Telecommunication Program
X
XRequirements:
X
X	Pcomm will not run on terminals with a screen size of less than
X	80 columns by 24 lines or on terminals that lack cursor movement
X	capabilities.  For terminals without arrow keys, use the letter
X	"U" in place of "up arrow" and the letter "N" in place of 
X	"down arrow".
X
X	Running Pcomm from a dialup line at 1200 baud will be make the
X	windows incredibly slow.
X
XPortability:
X
X	This program was written with AT&T System V in mind.  It makes
X	use of System V specific routines such as those in termio(7).
X	There is currently no port to Berkeley or v7 Unix.
X
X	This program can make use of the newer curses(3) routines from
X	SVR2.  There is a compile-time definition OLDCURSES for compatibility
X	with older flavors of curses(3).  None of the functionality is
X	lost using older curses, only some of the whistles and bells.
X
X	Included in the distribution package is a shell script named
X	"Unixpc.shar" that contains the Makefile specific for the AT&T
X	Unix PC 7300.
X
X	Pcomm makes use of the bold, blinking and standout video attributes.
X	My concept of "standout" and "reverse" might be different than
X	yours (I like "standout" to be a brighter version of "reverse").
X	Check your terminfo database... 
X
X	Flavors of curses without the keypad() function won't be able to
X	recognize arrow keys on the terminal, so users will have to
X	substitute the letters described above for the arrow keys.
X
XThings to do:
X
X	There are many pre-processor definitions located in the source
X	code that alter the way pcomm works, or gives the location of other
X	files.  The following list shows the location and default settings
X	of these definitions:
X
X	LOG_CALLS	Should pcomm keep a log of all phone calls?  The
X			default in admin.c is no (#undef).  If defined,
X			the path to the log file is in LOGFILE.
X	
X	LIMIT_LD	Should access to long distance dialing be limited
X			to privileged users?  The default in admin.c is
X			no (#undef).  If defined, the group to check is in
X			GRPNAME.
X
X	LPRINT		This is the pretty line print program.  (This is not
X			the name of the device).  The default in d_print.c
X			is "/usr/bin/lprint".
X
X	MAX_PASS	The maximum number of dialing attempts before we
X			give up.  The default in di_win.c is 25.
X
X	DEFAULT		The directory containing the default support files.
X			It is not intended that users have write permission
X			on these files.  The default in init.c is
X			"/usr/local/lib/pcomm".
X		
X	LPR		The generic line printer program.  (This is not the
X			name of the device).  The default in input.c is
X			"/usr/bin/lpr".
X
X	LOCKDIR		The location of the UUCP lock files.  The default
X			in port.c is "/usr/spool/uucp".  (HoneyDanBer UUCP
X			normally uses /usr/spool/locks).
X
X	ASCII_PID	Should the pid (process ID) in the UUCP lock file
X			be ASCII encoded?  The default in port.c is no
X			(#undef). (HoneyDanBer UUCP normally uses ASCII pids).
X
X	NUM_DIR		The maximum slots in the dialing directory.  The
X			default in dial_dir.h is 100.
X
X	NUM_QUEUE	The maximum slots in the dialing queue.  The default
X			in dial_dir.h is 10.
X
X	NOPROMOTE	Should missing video attributes be promoted to
X			standout?  The default in misc.h is no (#undef).
X
X	NUM_TTY		The maximum number of ttys used for dialout.  The
X			default in modem.h is 10.
X
X	NUM_MODEM	The maximum number of different types of modems used
X			for dialout.  The default in modem.h is 10.
X
X	MAX_ERRORS 	The maximum number of errors for a single block
X			before we give up on a file transfer.  The default
X			in xmodem.h is 10.
X
X	The compile-time definition SGID is specific to my system, but
X	others might find it useful.  On my system, all programs that 
X	access the dialout modems, are set-group-id to "uucp".  (This is
X	because normal users don't have write permission to the devices,
X	the lock directory, or the phone.call logfile).  The use of
X	SGID will assure that the real group id is restored during shell
X	escapes, open()s, etc.  The access(2) routine is used to determine
X	read and write permissions prior to opening files.
X
X	The distribution package contains three sample support files named
X	"Pcomm.dial_dir", "Pcomm.modem", and "Pcomm.param".  These files
X	should be renamed to change the upper case "P" to a lower case
X	"p" and copied into the directory given in the DEFAULT definition
X	described above.
X
XDocumentation:
X
X	The reference documentation file, "Doc" is designed to run thru
X	the Unix "pr" command before being sent to the printer.  For example:
X
X	pr -h "          Pcomm Reference Manual              " | lpr
X
X	The file "Pcomm.1" is a nroff manual page suitable for copying
X	into /usr/man/man1.
X
XSetup:
X
X	Before pcomm can be used properly, the tty/modem database must be
X	configured to match your system.  The "pcomm.modem" file should
X	be edited by the "TTY Setup" and "Modem Setup" menus.
X
X	The shell archive "Unixpc.shar" contains the Pcomm.modem file
X	specific to the AT&T Unix PC 7300.  (Its codes are NOT intuitive)
X
XWhere similarities end:
X
X	When pcomm is first executed, it hasn't yet selected a communications
X	port to use, so characters typed at the blank screen are ignored.
X	To get a port without pcomm doing the dialing, select an empty
X	entry in the dialing directory, or use the manual dial option with
X	the phone number set to a single space character.  The second field
X	in the status line will show what tty port is currently in use.
X
X	Since all printing goes through the Unix print spooler, the printer
X	logging feature will not output characters as they appear on the
X	screen.  Printing will actually start when the print logging is
X	toggled off (and the complete print job is sent to the spool).
X
X	Pcomm doesn't emulate any terminals... Whatever terminal you're on
X	is what the remote system sees.
X
X	Pcomm doesn't have a script language or command interpreter.  The
X	index field of the dialing directory is used instead to act as a
X	shortcut into the dialing directory from the "-f" command line
X	option.  The index field is also used to specify a particular tty
X	to be used (as opposed to searching the list of ttys for the first
X	free one).  This feature must be used on direct connections with
X	other machines.  For example, if tty12 is a hard-wired port to
X	"System A", then the dialing directory entry for "System A" would
X	have "tty12" in the index field.
X
XKnown limitations:
X
X	The keyboard macro feature is not implemented at this time.
X
X	The true screen contents are lost when the "hot key" is pressed.
X	Pcomm attempts to compensate (rather poorly) by repainting a
X	virtual screen of what it thinks the true screen should look like.
X	Escape sequences in the virtual screen image will be ignored when
X	the background is repainted.  For example, if you're on a vt100 
X	and you recieve a ^[[2J to clear the screen, the screen *will* be
X	cleared... but when the screen is repainted, it will contain the
X	characters ^[, [, 2, J (instead of performing the function).
X
X	The disp_tty() routine in s_tty.c currently does not support a
X	NUM_TTY definition of greater than 10.
X
X	For some strange reason, the first keystroke is "lost" after a
X	file transfer is complete or after starting data logging.
X
XFuture directions:
X
X	The virtual screen routines need a lot of work.  The most commonly
X	used escape sequences (known to terminfo) will be processed.
X
X 	I plan to have an option at compile time to have the virtual screen
X	buffer held on disk (v7) or in shared memory (SVR2).
X	
X	The input routine is designed so it could be a standalone program
X	that gets called from pcomm.  I plan to have an option at compile
X	time to have input() compiled into pcomm or as a separate program.
X
X
XEmmet P. Gray				US Army, HQ III Corps & Fort Hood
X...!ihnp4!uiucuxc!fthood!egray		Attn: AFZF-DE-ENV
X					Directorate of Engineering & Housing
X					Environmental Management Office
X					Fort Hood, TX 76544-5057
SHAR_EOF
if test 7859 -ne "`wc -c < 'Readme'`"
then
	echo shar: "error transmitting 'Readme'" '(should have been 7859 characters)'
fi
fi
echo shar: "extracting 'Release.notes'" '(853 characters)'
if test -f 'Release.notes'
then
	echo shar: "will not over-write existing file 'Release.notes'"
else
sed 's/^X//' << \SHAR_EOF > 'Release.notes'
X
X			     Pcomm  version 1.0
X
XThings that have changed:
X
X	I've added a bunch of parameters to the pcomm.param and pcomm.modem
X	files, so the files used with the beta release won't work with the
X	1.0 release.
X
X	Pcomm will attempt to determine if the modem has synchronized at
X	a baud rate different that what is expected, and make changes to
X	the line settings as appropriate.
X
X	The quit and interrupt signals are now ignored.
X	
X	All of the file transfer protocols are now functional.
X
X	The directory search order used to find the support files has been
X	changed slightly
X
XThings left to do:
X
X	Work on the virtual screen routines.
X
XHave fun...
X
XEmmet P. Gray				US Army, HQ III Corps & Fort Hood
X...!ihnp4!uiucuxc!fthood!egray		Attn: AFZF-DE-ENV
X					Directorate of Engineering & Housing
X					Environmental Management Office
X					Fort Hood, TX 76544-5057
SHAR_EOF
if test 853 -ne "`wc -c < 'Release.notes'`"
then
	echo shar: "error transmitting 'Release.notes'" '(should have been 853 characters)'
fi
fi
echo shar: "extracting 'Doc'" '(32879 characters)'
if test -f 'Doc'
then
	echo shar: "will not over-write existing file 'Doc'"
else
sed 's/^X//' << \SHAR_EOF > 'Doc'
X
X
X
X
X
X
X
X
X
X
X		  PPPPPP    CCCC    OOOO    MM   MM   MM   MM
X		  P    P   C       O    O   M M M M   M M M M
X		  PPPPPP   C       O    O   M  M  M   M  M  M
X		  P	   C       O    O   M     M   M     M
X		  P	    CCCC    OOOO    M     M   M     M
X
X
X
X
X
X
X
X
X			    Pcomm Reference Manual
X
X				 version 1.0
X
X
X
X
X				  written by
X
X				 Emmet P. Gray
X			...!ihnp4!uiucuxc!fthood!egray
X
X
X
X
X
X
X	Pcomm is a public domain telecommunications program for Unix that
X	is designed to operate similar to the MSDOS program, ProComm.
X	ProComm (TM) is copyrighted by Datastorm Technologies, Inc.  This
X	is a completely new program and contains no ProComm source code.
X	This is not a Datastorm product.
X
X
X			      Table of Contents
X
X
X		   1. INTRODUCTION .................... 3
X		   1.1 Requirements ................... 3
X		   1.2 Support files .................. 3
X
X		   2. RUNNING PCOMM ................... 4
X		   2.1 Hot key ........................ 4
X		   2.2 Status line .................... 4
X		   2.3 Help screen .................... 5
X		   2.4 Exit pcomm ..................... 5
X
X		   3. SETUP SCREENS ................... 6
X		   3.1 Prompting ...................... 6
X		   3.2 TTY setup ...................... 7
X		   3.3 Modem setup .................... 8
X		   3.4 Terminal setup ................. 9
X		   3.5 General setup .................. 10
X		   3.6 ASCII transfer setup ........... 11
X
X		   4. MAJOR FUNCTIONS ................. 13
X		   4.1 Dialing directory .............. 13
X		   4.2 Redial ......................... 15
X		   4.3 Keyboard macros ................ 15
X		   4.4 Line settings .................. 15
X		   4.5 Exit pcomm ..................... 16
X		   4.6 Unix gateway ................... 16
X
X		   5. UTILITY FUNCTIONS ............... 17
X		   5.1 Program information ............ 17
X		   5.2 Setup screen ................... 17
X		   5.3 Change directory ............... 17
X		   5.4 Clear screen ................... 17
X		   5.5 Toggle duplex .................. 17
X		   5.6 Hangup the phone ............... 17
X		   5.7 Printer logging ................ 18
X		   5.8 Toggle CR - CR/LF .............. 18
X		   5.9 Break .......................... 18
X
X		   6. FILE FUNCTIONS .................. 19
X		   6.1 Send files ..................... 19
X		   6.2 Receive files .................. 20
X		   6.3 Directory ...................... 20
X		   6.4 Screen dump .................... 21
X		   6.5 Start data logging ............. 21
X		   6.6 Toggle logging ................. 21
X
X		   7. DIALING WINDOW .................. 22
X
X1. INTRODUCTION
X
X	Pcomm is a public domain, menu driven, telecommunication program
X	designed to provide the same "ease of use" as similar programs
X	available in MSDOS.  Some of its features are:
X
X		o+ Large dialing directory
X		o+ Automatic redial feature
X		o+ Supports several file transfer protocols
X		o+ Data logging (log of the terminal session)
X		o+ Printer logging
X		o+ Screen dump
X		o+ User customization
X
X	Pcomm does not emulate any particular terminal.  Whatever terminal
X	you're on, is what the remote system "sees".
X
X1.1 Requirements
X
X	Pcomm will not run on terminals with a screen size of less than
X	80 columns by 24 lines or on terminals that lack cursor movement
X	capabilities.  For terminals without arrow keys, use the letter "U"
X	in place of "up arrow" and the letter "N" in place of "down arrow".
X
X1.2 Support files
X
X	Pcomm uses three support files, namely:
X
X		pcomm.dial_dir	the dialing directory
X		pcomm.modem	the modem/tty database
X		pcomm.param	the start-up default parameters
X
X	There is a default directory (typically "/usr/local/lib/pcomm")
X	where the "standard" support files live.  Since the average user 
X	would not have write permission on these files, it's assumed that
X	you'll copy these standard files to your own directory and edit
X	them to suit your needs.
X
X	Pcomm can use the environmental variable "PCOMM" to search for
X	these "private" support files.  If used, the variable must contain
X	the path to the directory containing the files.
X
X	The following directories are searched to find the support files:
X
X		o+ directory given with the "-d" option
X		o+ directory in the PCOMM environmental variable
X		o+ the current working directory
X		o+ the global default directory
X
X2. RUNNING PCOMM
X
X	Pcomm has the following command line syntax.
X
X		pcomm [-d directory] [-f index]
X
X	The "-d" option allows you to specify an additional path to be used
X	when searching for the pcomm support files.
X
X	The "-f" option is used to specify automatic dialing of an entry in
X	the dialing directory.  The "index" field in the dialing directory
X	(described later) is checked against the string given on the command
X	line.  If a match is found, that entry is automatically dialed.
X
X2.1 Hot key
X
X	Pcomm uses a "hot key" to precede each command.  (The value of the
X	hot key is a user tunable parameter, but for the purpose of this
X	document we'll assume the hot key is defined as control-A).
X
X	The hot key is used to put pcomm in the command mode.  For example,
X	to get the help screen, you'd type control-A (to get to the command
X	mode) then the number 0 (to display the help screen).  When a command
X	is completed, pcomm returns to the terminal mode.
X
X	NOTE:  While in the command mode, the communications with the remote
X	system is temporarily suspended.
X
X2.2 Status line
X
X	Whenever pcomm is in the command mode (or is not currently connected
X	to a remote) a status line is displayed at the bottom of the screen.
X	A typical status line might look like this:
X
X+-----------------------------------------------------------------------------+
X|  ^A-0 HELP   | No TTY | FDX |  1200 E71 | LOG OFF | PTR OFF | CR    | CR    |
X+-----------------------------------------------------------------------------+
X
X	The eight fields of the status line are:
X
X		o+ help screen command (or a temporary message)
X		o+ name of the tty device in use
X		o+ duplex mode (FDX = full duplex, HDX = half duplex)
X		o+ current line settings
X		o+ status of data logging option
X		o+ status of printer logging option
X		o+ incoming CR translation
X		o+ outgoing CR translation
X
X
X2.3 Help screen
X
X	The help screen gives a brief review of all the available commands.
X	To access the help screen type ^A and '0' (zero).  The typical help
X	screen would look like this:
X
X+-----------------------------------------------------------------------------+
X|			     P C O M M     H E L P			      |
X|-----------------------------------------------------------------------------|
X|									      |
X|       Major Functions        Utility Functions	 File Functions       |
X|									      |
X| Dialing Directory .  ^A-D  Program Info .....  ^A-I  Send files ....  ^A-up |
X| Auto Redial .......  ^A-R  Setup Screen .....  ^A-S  Receive files .  ^A-dn |
X| Keyboard Macros ...  ^A-M  Change Directory .  ^A-B  Directory .....  ^A-F  |
X| Line Settings .....  ^A-P  Clear Screen .....  ^A-C  Screen Dump ...  ^A-G  |
X| Exit Pcomm ........  ^A-X  Toggle Duplex ....  ^A-E  Start Data Log.  ^A-1  |
X| Unix Gateway ......  ^A-4  Hangup Phone .....  ^A-H  Toggle Log ....  ^A-2  |
X|			     Printer On/Off ...  ^A-L			      |
X|			     Toggle CR/CR-LF ..  ^A-3			      |
X|			     Break Key ........  ^A-7			      |
X|									      |
X+-------------------------- Press any key to continue ------------------------+
X
X2.4 Exit pcomm
X
X	To exit pcomm, you'd type ^A and 'x' to access the exit window.
X
X	+-- Exit -----------------------+
X	|				|
X	|   Exit to Unix? (y/n): _	|
X	|				|
X	+-------------------------------+
X
X	To exit, you'd press the letter 'y' (carriage return not required).
X
X3. SETUP SCREENS
X
X	Pcomm allows you to change many of the default parameters.  The setup
X	screen is accessed by typing ^A and 's'.  The following screen is
X	typical and shows the sub-menu choices:
X
X	----------------------- Setup Menu ----------------------------
X
X				1) TTY Setup
X				2) Modem Setup
X				3) Terminal Setup
X				4) General Setup
X				5) ASCII Transfer Setup
X				S) Save setup to disk
X
X	---------------------------------------------------------------
X	OPTION ==> _				      Press ESC to exit
X	
X	To select one of the sub-menu choices, you'd type the number (or
X	letter) at the "OPTION ==>" prompt.  To exit from a sub-menu and
X	return to this setup menu screen, you'd press the escape key.
X
X	Changes made affect the current pcomm session only.  To make the
X	changes become the default, you'd select the 's' option.
X
X3.1 Prompting
X
X	There are several different types of prompts used in the setup
X	screens.  The prompts use the bottom two lines on the display for
X	user input and to give more information on what is being asked.
X	Pcomm will beep at any illegal input.  The escape key 'ESC' will
X	abort any prompt.  The prompt types are:
X
X		o+ Character prompt.  Asks you to input a single character.
X
X		o+ String prompt.  Asks you to input a word or group of
X		characters.
X
X		o+ Numeric prompt.  Asks you for a number.
X
X		o+ Menu prompt.  Shows a selection and allows you to to
X		choose the current selection by pressing the carriage return
X		or change the selection by pressing the space bar.
X
X3.2 TTY setup
X
X	The TTY setup screen contains the list of devices (ports) that pcomm
X	is allowed to use, and what is attached to each port.  A typical TTY
X	setup screen might look like this:
X
X	------------------------- TTY Setup ---------------------------
X
X		TTY name	Modem name	Maximum baud
X
X		1) tty10	HAYES		1200
X		2) tty11	HAYES		2400
X		3) tty12	DIRECT		9600
X		4)				0
X		5)				0
X		6)				0
X		7)				0
X		8)				0
X		9)				0
X		10)			        0
X
X		11) Add a TTY entry
X		12) Delete a TTY entry
X
X	---------------------------------------------------------------
X	OPTION ==> _				    Press ESC to return
X
X	You may edit an entry by typing the entry number at the prompt.
X	To add an entry, you'd type '11' at the prompt, etc.
X
X	The tty setup fields are:
X
X		1) The tty name.  This is the name of the serial port that
X		pcomm will be allowed to use.  Notice that the path component
X		of the name, "/dev/" is not used.
X
X		2) The modem name.  This a keyword that is used later to link
X		the modem database with the tty database.  The name could be
X		any combination of letters or numbers (both upper and lower
X		case).
X
X	NOTE:  All hard-wired ports (ports without modems attached)
X	*must* use the word "DIRECT" for the modem name.
X
X		3) The maximum baud rate is highest rating of the modem (or
X		the connected baud rate of hard-wired ports).  The baud rate
X		is selected from a "menu prompt".
X
X3.3 Modem setup
X
X	The modem setup contains the commands to make the modem dial, hangup
X	the phone, etc.  A typical modem setup screen might look like this:
X
X	-------------------------- Modem Setup --------------------------
X
X		1) Modem name ............. HAYES
X
X		2) Modem init string ...... ATS7=45S11=70!
X		3) Dialing command ........ ATDT
X		4) Dialing cmd suffix ..... !
X		5) Hangup string .......... ~~+++~~ATH0!
X		6) 300 baud connect ....... CONNECT!
X		7) 1200 baud connect ...... CONNECT 1200
X		8) 2400 baud connect ...... CONNECT 2400
X		9) 4800 baud connect ......
X		10) 9600 baud connect .....
X		11) 19200 baud connect ....
X		12) No connect string 1 ... BUSY
X		13) No connect string 2 ... VOICE
X		14) No connect string 3 ... NO CARRIER
X		15) No connect string 4 ...
X
X	---------------------------------------------------------------
X	OPTION ==> _				    Press ESC to return
X
X	The fields of the modem setup are:
X
X		1) Modem name.  This is the keyword that links the modem
X		database with the tty database.  A menu prompt is used to
X		select the modem name (and the remaining parameters that go
X		with it).
X
X		2) Modem initialization string.  This is sent to the modem
X		whenever the port is selected.  Consult your modem manual for
X		the codes to be used.  Notice the use of the "!" character,
X		this is the "character synonym" for the carriage return.
X
X	NOTE: See section 3.5 for the complete list of character synonyms.
X
X		3) Dialing command.  The first part of the command to make
X		the modem dial.  It is assumed that the phone number will
X		immediately follow.
X
X		4) Dialing command suffix.  The last part of the command to
X		make the modem dial.  Typically this would be the carriage
X		return "character synonym".
X
X		5) Hangup string.  The command to make the modem hangup the
X		phone.  The character synonym for a 1 second pause is the
X		tilde "~" character.
X
X		6-11) Connect strings.  The return message when the modem is
X		connected to the remote.  If different messages are returned
X		depending on which baud rate is selected, they should be
X		specified.
X
X	NOTE: If two connect strings are similar, (one is contained entirely
X	in another) then it is possible that the return code from the modem
X	will not match the correct connect string.  To prevent this from
X	happening, use the command synonym for the carriage return to
X	terminate the shorter connect string.
X
X		12-15) No connect strings.  The messages returned by the
X		modem when no connection is made.
X
X3.4 Terminal setup
X
X	The terminal setup allows you to define the hot key and the mapping
X	of the end-of-line characters.  A typical terminal setup menu would
X	look like this:
X
X	---------------------- Terminal Setup --------------------------
X
X			1) Hot key ................ 1
X			2) ASCII version of hot ... ^A
X
X			3) Duplex ................. FULL
X			4) Flow control ........... XON/XOFF
X			5) CR translation (in) .... CR
X			6) CR translation (out) ... CR
X
X	---------------------------------------------------------------
X	OPTION ==> _				    Press ESC to return
X
X	The fields in the terminal setup are:
X
X		1) Hot key.  This is the decimal code for the user definable
X		hot key.  Consult an ASCII/decimal conversion chart for the
X		decimal values of other characters.
X
X		2) ASCII version of hot key.  This is the printable version
X		of the hot key used by pcomm in the help screen and status
X		line.
X
X		3) Duplex.  A menu prompt is shown to select between FULL
X		duplex and HALF duplex.  In the half duplex mode, characters
X		sent to the remote system are also sent to the the screen.
X		(The duplex mode can also be change "on the fly" by the
X		^A-E command.)
X
X	NOTE: Due to a technical limitation in pcomm, data logging and
X	print logging will not work correctly in the half duplex mode.
X
X		4) Flow control.  A menu prompt is shown to select between
X		XON/XOFF flow control and NONE.  The flow control selected
X		here is only used during the terminal session, not during
X		file transfers.
X
X		5-6) CR translations.  The end-of-line characters for both
X		incoming and outgoing carriage returns can be altered to suit
X		the remote system's needs.  A menu prompt provides the
X		following choices:
X	
X			o+ CR (no translation)
X			o+ CR/NL translate CR to CR/NL
X
X		The incoming CR translation can also be changed "on the fly"
X		with the ^A-3 command.
X
X3.5 General setup
X
X	The general setup allows you to define the character synonyms and
X	the default files used by the screen dump and other features.  A
X	typical general setup screen might look like this:
X
X	------------------------ General Setup -----------------------
X
X			1) Default log file ....... pcomm.log
X			2) Screen dump file ....... pcomm.dump
X
X			3) Strip high bit  ........ YES
X
X			4) Pause character ........ ~
X			5) CR character ........... !
X			6) CTRL character ......... ^
X			7) ESC character .......... |
X
X			8) Aborted downloads ...... KEEP
X
X			9) Connect delay time ..... 35
X			10) Pause between redials . 5
X
X	---------------------------------------------------------------
X	OPTION ==> _				    Press ESC to return
X
X	The general setup fields are:
X
X		1) Default log file.  The file name to be used as the default
X		when the data logging is actived (^A-1).  You can override
X		this default at run time.
X
X		2) Screen dump file.  The file name to be used for the screen
X		dump command (^A-G).
X
X		3) Strip high bit.  Should pcomm strip the eighth bit on
X		incoming and outgoing characters?  A menu prompts allows you
X		to select YES or NO.  This feature is not used during file
X		transfers.
X
X		4-7) Character synonyms.  These are symbols that pcomm uses
X		to translate special characters to the their real values
X		prior to sending them to the modem.  Synonyms are useful for
X		terminals and editors that balk at special characters.
X
X		8) Aborted downloads.  When a download aborts (fails), should
X		the partially completed file be kept?  The menu prompt allows
X		"KEEP" or "DELETE".
X
X		9) Connect delay time.  The number of seconds pcomm will wait
X		for the modem to return a status code.
X
X		10) Pause between retries.  The number of seconds to wait
X		before pcomm tries to call the number again.
X
X3.6 ASCII transfer setup
X
X	This setup screen allows you to select options to be used for ASCII
X	uploads and download.  A typical ASCII transfer setup would look
X	like this:
X
X	---------------------- ASCII Transfer Setup ---------------------
X
X				ASCII UPLOAD
X
X			1) Echo locally ........... NO
X			2) Expand blank lines ..... NO
X			3) CR delay (ms) .......... 0
X			4) Pace the output ........ NO
X			5) CR translation ......... NONE
X			6) LF translation ......... NONE
X
X				ASCII DOWNLOAD
X
X			7) Transfer timeout ....... 5
X			8) CR translation ......... STRIP
X			9) LF translation ......... NONE
X
X	---------------------------------------------------------------
X	OPTION ==> _				    Press ESC to return
X
X	The fields are:
X
X		1) Echo locally.  This is similar to the duplex option in
X		that it copies outgoing characters to the screen.  The options
X		are YES and NO.
X
X		2) Expand blank lines.  Should a blank line (NL alone) be
X		expanded to a space and NL?  Some BBS systems use a blank
X		line to signal the end of a ASCII upload.  The options are
X		YES and NO.
X
X		3) CR delay.  The delay in milliseconds to be used when
X		sending a CR.  The menu prompt limits the choice to 0, 100,
X		or 150.
X
X		4) Pace output.  Should each character sent be delayed?  Very
X		old BBS systems may require this.  The choice is YES or NO.
X
X		5) CR translation.  The menu prompt provides the following
X		choices for upload translations:
X
X			o+ NONE (no translation)
X			o+ ADD NL translate CR to CR/NL.
X			o+ STRIP remove the CR character
X
X		6) LF translation. Same as above except the choices are:
X		
X			o+ NONE (no translation)
X			o+ ADD CR translate NL to CR/NL.
X			o+ STRIP remove the NL character
X
X		7) Transfer timeout.  The number of seconds to be used to
X		determine the end of an ASCII download.  You can halt the
X		transfer before the timer goes off by hitting the ESC key.
X
X		8-9) Same as 5) and 6) above, except for downloading.
X
X4. MAJOR FUNCTIONS
X
X	When pcomm is invoked without the "-f" command line option, you are
X	placed in the terminal mode with a blank screen and a status line.
X	However, since pcomm hasn't yet selected a serial port to use,
X	characters typed at the blank screen are ignored.
X
X	Normally the first command you'd use is ^A-D to bring up the dialing
X	directory menu.
X
X4.1 Dialing directory
X
X	To dial another system, you'd type ^A-D to access the dialing
X	directory menu, then enter the entry number at the prompt.
X
X	The entry number could be preceded by a special long distance dialing
X	code such as "#5" in lieu of "5" alone.  Long distance codes could
X	contain access numbers such as those that MCI and Sprint require.
X
X	A typical dialing directory would look like this:
X
X+----------------------------------------------------------------------------+
X|			D I A L I N G	D I R E C T O R Y		     |
X|----------------------------------------------------------------------------|
X|	  Name		     Number	   Baud P D S Dpx  Index/tty         |
X|  1- Abbey Road	1 (512) 590-6036   2400-N-8-1  F		     |
X|  2- Tel-Med-Com		526-8686   1200-E-7-1  F		     |
X|  3- C Board		1 (619) 722-8724   2400-N-8-1  F		     |
X|  4- Crest		1 (213) 471-2518   2400-N-8-1  F  crest		     |
X|  5- Last Chance	1 (219) 762-8411   2400-E-7-1  F		     |
X|  6- Killer		1 (214) 827-1994   1200-E-7-1  F		     |
X|  7- System A (direct)			   9600-N-8-1  F  tty12		     |
X|  8-					   1200-E-7-1  F		     |
X|  9-					   1200-E-7-1  F		     |
X| 10-					   1200-E-7-1  F		     |
X|									     |
X|   ==> _	R Revise	M Manual Dialing	Entry to Dial	     |
X|		P LD Codes	D Delete Entry		<cr> Scroll Down     |
X|		up/dn Page	L Print Entries		ESC Exit	     |
X|									     |
X|   LD Codes Active: @ #						     |
X|									     |
X+----------------------------------------------------------------------------+
X
X	The fields of the dialing directory are:
X
X		o+ Name.  The name of the remote system.
X
X		o+ Number.  The telephone number to the remote system.
X
X	NOTE: The "(", ")", "-", and space character are for just for looks,
X	they don't get sent to the modem.
X
X		o+ Line settings.  The communications settings to be used
X		when dialing that entry.  The range of values are:
X
X			Baud	Parity	   Data bits  Stop bits
X
X			300	N - none	7	1
X			1200	E - even	8	2
X			2400	O - odd
X			4800
X			9600
X			19200
X
X		o+ Duplex.  The duplex mode.  Either "F" for full or "H"
X		for half.
X
X		o+ Index.  The string to be used to select this entry with
X		the "-f" command line option.  This field is also used to
X		specify a particular tty for the entry.
X
X	NOTE:  On all hard-wired ports, the index field must be set to the
X	name of the port.  For example, if tty12 is a hard-wired port to
X	"System A", then the dialing directory entry for "System A" would
X	have "tty12" in the index field.
X
X	The commands at the dialing directory prompt are:
X
X		R) Revise (or add) a dialing directory entry or long distance
X		dialing code.  Prompts you to save the changes to disk.
X
X		P) Print (display) the long distance dialing codes.
X
X		up/dn) Scroll the dialing directory up or down 10 lines.
X		Use the up and down arrow keys to access this feature.
X
X		M) Manual dial. Prompts you for a phone number rather than
X		using a number already in the dialing directory.
X
X		D) Delete an entry or a range of entries.  Prompts you to
X		save the changes to disk.
X
X		L) Print.  Send the dialing directory to the printer
X		or a file of your choice.
X
X		1-100) Entry number.  Dial the phone for that entry number.
X
X	NOTE:  To access the port directly without dialing (perhaps to send

X	the dial codes yourself), select an empty entry or enter a single
X	space character at the manual dial option.
X
X		<cr> Carriage return.  Scroll the dialing directory down one
X		line.
X
X4.2 Redial
X
X	The redial feature is a misnomer, it really is a queuing system that
X	allows pcomm to dial several numbers in a cycle until one of them
X	answers.
X
X	When you invoke the redial command with ^A-R, you are prompted for a
X	list of dialing directory numbers.  (You may also prepend a long
X	distance code to the entry number).
X
X     +-- Redial Queue --------------------------------------------------+
X     |								    	|
X     |   Directory Entry Number(s): _					|
X     |									|
X     |			(CR for previous numbers)			|
X     +------------------------------------------------------------------+
X
X	To redial the previous number, press a carriage return alone at
X	the prompt.
X
X4.3 Keyboard macros.
X
X	Keyboard macros are not supported at this time.
X
X4.4 Line settings.
X
X	The line settings menu is invoked by ^A-P.  A typical line settings
X	menu would look like this:
X
X		+-----------------------------------------------+
X		|		Line Settings			|
X		|-----------------------------------------------|
X		|						|
X		|	Current Settings:  1200,E,7,1		|
X		|						|
X		|    1)     300,E,7,1	7)	 300,N,8,1	|
X		|    2)    1200,E,7,1	8)	1200,N,8,1	|
X		|    3)    2400,E,7,1	9)	2400,N,8,1	|
X		|    4)    4800,E,7,1	10)	4800,N,8,1	|
X		|    5)    9600,E,7,1	11)	9600,N,8,1	|
X		|    6)   19200,E,7,1	12)    19200,N,8,1	|
X		|						|
X		|   Parity	Data Bits	Stop Bits	|
X		|   13) Odd	14) 7 bits	16) 1 bit	|
X		|		15) 8 bits	17) 2 bits	|
X		|						|
X		|   18) Save Changes	YOUR CHOICE: _		|
X		|						|
X		+------------- Press ESC to return -------------+
X
X	After dialing a remote, the line settings in the dialing directory
X	entry are automatically used.  Therefore the line settings menu is
X	used to adjust the values or to select the default parameters.  You
X	can make the current setting the default by selecting the "Save
X	Changes" option.
X
X	The current settings are also displayed in the status line.
X
X	NOTE: During file transfers, certain parameters (namely the data
X	bits and parity) will be temporarily promoted.
X
X4.5 Exit pcomm
X
X	To exit pcomm, you'd type ^A-X.
X
X4.6 Unix gateway.
X
X	To temporarily suspend pcomm and spawn a Unix shell, you'd type
X	^A-4.  To return to pcomm, you'd exit the shell normally, typically
X	with "^D" or "exit".
X
X5. UTILITY FUNCTIONS
X
X	The following commands perform secondary functions.
X
X5.1 Program information
X
X	To display the opening information screen, you'd type ^A-I.  Press
X	any key to return to the terminal mode.
X
X5.2 Setup screen
X
X	The setup screens are described in detail in section 3 of this manual.
X
X5.3 Change directory
X
X	To change the current working directory while still inside pcomm,
X	you'd type ^A-B.  A screen similar to the following would appear:
X
X	+-- Change directory -------------------------------------------+
X	|								|
X	|   Current directory: /usr/egray				|
X	|   New directory: _						|
X	|								|
X	+---------------------------------------------------------------+
X
X	Abbrievations known to the shell are acceptable, for example the
X	"~" character would be translated to the home directory in the csh
X	or ksh shell.
X
X5.4 Clear screen.
X
X	To clear the local screen and home the cursor, you'd type ^A-C.
X
X	NOTE:  The remote system may not "know" the screen has been cleared,
X	and may make assumptions about the screen that are incorrect.
X	
X5.5 Toggle Duplex.
X
X	The ^A-E command changes the duplex mode from FULL to HALF, or from
X	HALF to FULL.  The status line shows the current settings.
X
X5.6 Hangup the phone.
X
X	To hangup the phone, you'd type ^A-H.  The word "disconnecting" will
X	briefly show in the status line.
X
X	NOTE: The hangup string is sent to the modem and then the DTR is
X	dropped on the line.
X
X5.7 Printer logging.
X
X	The ^A-L command toggles the printer logging on or off.  The current
X	settings are displayed in the status line.
X
X	NOTE: Since all printing goes to the normal Unix print spool program,
X	the characters will not print on the printer as they appear on the
X	screen.  The printing will actually begin when the printer logging
X	is turned *off* and the complete print job is sent to the spool.
X
X5.8 Toggle CR - CR/LF.
X
X	The ^A-3 command toggles the incoming line termination characters
X	between CR and CR/LF.  The status line show the current settings (in
X	the next to the last field).
X
X5.9 Break.
X
X	A ^A-7 sends a modem break to the remote system.  The word "break"
X	is (very) briefly displayed on the status line.
X
X	NOTE: This not the same as the break key on the keyboard (we don't
X	want to send a break to the local system, we want to sent it to
X	the *remote*).
X
X6. FILE FUNCTIONS
X
X	One of the most important features of a telecommunication program is
X	the ability to transfer files.  The following file transfer protocols
X	are implemented at this time:
X
X	protocol	packet		error		multiple
X	name		size		detection	files?
X	---------	--------	------------	-----
X	
X	xmodem		128		checksum/CRC	no
X	xmodem-1k	128/1024	checksum/CRC	no
X	modem7		128		checksum	yes*1
X	ymodem		128/1024	CRC		yes*2
X	ymodem-g	128/1024	none*3		yes
X	ASCII		none		none		no
X
X	Notes:	1 CP/M style file name
X		2 MSDOS style file name and file size
X		3 Not needed!
X
X6.1 Send files.
X
X	To send a file to the remote, you'd first instruct the remote system
X	to receive the file, then type ^A-"up arrow".  The following screen
X	would appear:
X
X					+----- Upload -----+
X					|		   |
X					|  1) xmodem       |
X					|  2) xmodem-1k    |
X					|  3) modem7       |
X					|  4) ymodem       |
X					|  5) ymodem-g     |
X					|  6) ASCII	   |
X					|		   |
X					|		   |
X					|		   |
X					|  ESC to Abort    |
X					|		   |
X					|  Protocol: _     |
X					+------------------+
X
X	You'd then select the type of protocol at the prompt, and another
X	window similar to this would appear:
X
X	+-- Send xmodem ------------------------------------------------+
X	|								|
X	|								|
X	|   Enter filename: _						|
X	|								|
X	|								|
X	+---------------------------------------------------------------+
X
X	Now you'd type in the file name or names you'd like to send.
X	Wildcards known to the shell are acceptable.
X
X	Now the file transfer actually begins.  A status screen similar to
X	the following is displayed during the transfer:
X
X				+-------------- Uploading --------------+
X				|					|
X				|	     Protocol: xmodem		|
X				|	    File name: main.c		|
X				|	    File size: 4420		|
X				|  Error check method: CRC		|
X				|   Est transfer time: 0:00:50		|
X				|	  Block count: 5		|
X				|    Percent complete: 11.2%		|
X				|   Bytes transferred: 640		|
X				|   Errors this block: 0		|
X				|   Total error count: 0		|
X				|	 Last message: NONE		|
X				|					|
X				+---------- Press ESC to abort ---------+
X
X	As the transfer progresses, the "block count", "percent complete",
X	and "bytes transferred" fields will be continuously updated.  If
X	errors occur the "errors this block" and "total error count" fields
X	will be updated and the "last message" field will contain a message
X	about the error.
X
X	At the end of the transfer, pcomm will beep and return to the terminal
X	mode.  If an error occurred and the transfer was aborted, you will be
X	prompted to acknowledge the error by pressing a key before returning
X	to the terminal mode.
X
X6.2 Receive files
X
X	To receive a file (or group of files) from a remote system, you'd
X	instruct the remote system first, then type ^A-"down arrow".
X	Receiving a file is basically the same as sending a file.
X
X	NOTE: Some systems do not pad the end of the file with control-Z's
X	and therefore files might grow in length when received.
X
X	NOTE: Due to a technical limitation of pcomm, characters received
X	during an ASCII download will not reappear on the screen when you
X	return to the terminal mode.
X
X6.3 Directory
X
X	To obtain a listing of a directory on the local system while still
X	running pcomm, you'd type ^A-F.  The following screen would appear:
X
X	+-- List Directory ---------------------------------------------+
X	|								|
X	|   Current directory: /usr/egray				|
X	|   File spec (wildcards allowed): _				|
X	|								|
X	+---------------------------------------------------------------+
X
X	Abbrievations know to the shell are valid.
X
X	NOTE: Since we're really doing a popen() to the "ls" command,
X	additional command line options are also valid.
X
X6.4 Screen dump
X
X	To dump the contents of the current screen (minus any windows showing)
X	you'd type ^A-G.  The contents of the screen are written to the file
X	specified in the general setup for this purpose.  If the file already
X	exists, the screen contents are appended to the file.  The message
X	"screen dump" will briefly appear in the status line.
X
X6.5 Start Data log
X
X	To start the data logging, or change the file used for data logging,
X	you'd type ^A-1.  The following screen would appear:
X
X	+-- Start Data Logging -----------------------------------------+
X	|								|
X	|   Default log file: pcomm.log					|
X	|   New log file: _						|
X	|								|
X	+---------------------------------------------------------------+
X
X	To keep the default file, just press a carriage return at the prompt,
X	otherwise, enter a new file name.
X
X	The status of the logging is shown in the status line.
X
X6.6 Toggle Logging
X
X	To temporarily suspend data logging or to start it again without
X	being prompted for the file name, you'd type ^A-2.
X
X	The status lines shows the current settings.
X
X7.  DIALING WINDOW
X
X	While pcomm is dialing another system, a screen similar to the
X	following is shown:
X
X	+--------------------------------------------------------------------+
X	|		  D I A L I N G	       W I N D O W		     |
X	+--------------------------------------------------------------------+
X	|								     |
X	|		      System name: C Board			     |
X	|		      Pass number: 1				     |
X	|	     Elapse time this try: 4				     |
X	|	    Time at start of dial: 14:53:36			     |
X	|	Time at start of this try: 14:53:37			     |
X	|	       Connect delay time: 35				     |
X	|	      Pause between tries: 5				     |
X	|			Index/tty:				     |
X	|	       Result of last try:				     |
X	|								     |
X	|  SPACE: Recycle    DEL: Remove from queue   E: Change delay times  |
X	|								     |
X	+------------------------ Press ESC to abort ------------------------+
X
X	The options available during the dialing are:
X
X		SPACE) Press the space bar to stop the dialing of the current
X		entry and go on to the next entry in the queue.  If there is
X		only one entry in the queue, then that number is immediately
X		redialed.
X
X		DEL) Press the DEL key to remove the current number from the
X		queue.
X
X		E) Press the letter "E" to change the connect delay time, or
X		the pause between retries.  You will be prompted to save the
X		changes to disk.
echo shar: "36 control characters may be missing from 'Doc'"
SHAR_EOF
if test 32879 -ne "`wc -c < 'Doc'`"
then
	echo shar: "error transmitting 'Doc'" '(should have been 32879 characters)'
fi
fi
echo shar: "extracting 'Pcomm.1'" '(6287 characters)'
if test -f 'Pcomm.1'
then
	echo shar: "will not over-write existing file 'Pcomm.1'"
else
sed 's/^X//' << \SHAR_EOF > 'Pcomm.1'
X.TH PCOMM 1 local
X.SH NAME
Xpcomm \- a telecommunication program
X.SH SYNOPSIS
X.B pcomm
X[
X.B -d directory
X]
X[
X.B -f index
X]
X.SH DESCRIPTION
X.I Pcomm
Xis a telecommunication program designed to operate similar to the
Xpopular MSDOS program, ProComm.  ProComm (TM) is copyrighted by Datastorm
XTechnologies, Inc.
X.PP
XThe '-d' command line option allows the user to specify an additional
Xpath to be used when searching for the pcomm support files.
X.PP
XThe '-f' command line option is used to specify automatic dialing of an
Xentry in the dialing directory.  The 'index' field in the dialing directory
Xis checked against the string given in the command line option.  If a
Xmatch is found, that entry is automatically dialed.
X.PP
XWhenever
X.I pcomm
Xis in the command mode, a status line is displayed at the bottom of the
Xscreen.  The eight fields of the status line are:
X.PP
X.RS 5
X.nf
Xo+ help screen command
Xo+ tty name in use
Xo+ current line settings
Xo+ the duplex mode
Xo+ status of data logging
Xo+ status of printer
Xo+ incoming CR translation
Xo+ outgoing CR translation
X.fi
X.RE
X.SH COMMANDS
XThe following commands are accessible by pressing a user definable 'hot
Xkey' and the command letter.  The default 'hot key' is control-A.
X.TP
X.B ^A-0
XDisplays a summary of the available commands.
X.TP
X.B ^A-D
XDisplays the dialing directory.  From this screen, the directory
Xcan be scrolled up or down 10 lines by pressing the up or down
Xarrow keys respectively.  To select an entry to dial, just enter 
Xthe entry number at the prompt.  The following sub-commands are
Xalso available:
X.RS 5
X.TP
X.B R
XRevise or add an entry.  Prompts for entry number or long distance code
Xto revise.
X.TP
X.B D
XDelete a dialing directory entry or a range of entries.
X.TP
X.B P
XDisplay the current long distance dialing codes.
X.TP
X.B L
XSend the dialing directory to the line printer.
X.TP
X.B M
XManual dial.  Prompts for a phone number.
X.RE
X.TP
X.B ^A-R
XAutomatic redial of selected dialing directory entries.  Prompts the
Xuser for a list of directory entries to be placed in the queue.
X.TP
X.B ^A-M
XAllows the user to maintain a list of keyboard macros assigned to
Xspecific keys.  When pressed, the string assigned to that key is sent
Xto the remote system.
X.TP
X.B ^A-P
XAdjust the current communication line settings.  Displays a menu of 
Xbaud rate, parity, data bit, and stop bit choices.  Allows the new choice
Xto be saved and become the default.  The current line settings are
Xshown on the status line.
X.TP
X.B ^A-X
XExit 
X.I pcomm.
X.TP
X.B ^A-4
XSpawn a Unix shell while still communicating with the remote system.
XUses the 'native' shell as described in the SHELL environmental
Xvariable.
X.TP
X.B ^A-I
XDisplays the program information screen.
X.TP
X.B ^A-S
XDisplays a choice of setup screens.  The following sub-menus are
Xavailable:
X.RS 5 
X.TP
X.B 1
XTTY Setup.  Allows for the assignment of modem names to the ttys 
Xused for dialing.
X.TP
X.B 2
XModem Setup.  Prompts for the dialing instructions for the modem
Xnames specified in the TTY setup.
X.TP
X.B 3
XTerminal Setup.  This screen contains the 'hot key' definition and
Xcarriage return / line feed translations.
X.TP
X.B 4
XGeneral Setup.  Prompts for default log file name and the set of
Xcommand character translations.
X.TP
X.B 5
XASCII Setup.  Additional character translations allowed during ASCII
Xfile transfers.
X.TP
X.B S
XSave the changes to disk.
X.RE
X.TP
X.B ^A-B
XChanges the current working directory.
X.TP
X.B ^A-C
XClears the local screen.
X.TP
X.B ^A-E
XToggles between full duplex and half duplex mode.  The status line
Xshows the current duplex mode.
X.TP
X.B ^A-H
XHang up the phone.  Disconnects the phone, but remains in 
X.I pcomm.
X.TP
X.B ^A-L
XToggles the printer on and off.  Since the printer is accessed through
Xthe normal Unix spool program, the output is not sent to the printer
Xuntil 
X.B after
Xthis feature is turned off.
X.TP
X.B ^A-3
XToggle the line termination characters between the carriage return and
Xthe carriage return line feed pair.  This affects the terminal session
Xonly, not the file transfers.  The current settings are shown in the
Xstatus line.
X.TP
X.B ^A-7
XSend a modem break.  This is
X.B not
Xthe same as the break key on the keyboard.
X.TP
X.B ^A-up
XDisplays a menu of file transfer protocols to be used to send files 
Xto a remote system.
X.TP
X.B ^A-dn
XDisplays file transfer protocols to be used to receive files from a
Xremote system.
X.TP
X.B ^A-F
XDisplays the contents of a Unix directory.
X.TP
X.B ^A-G
XDump the contents of the screen to a specified file.  Escape
Xsequences and special characters will not be represented accurately
Xin the file.
X.TP
X.B ^A-1
XBegin data logging.  Prompts the user for the name of the file that
Xwill be used to collect a complete record of the terminal session.
X.TP
X.B ^A-2
XToggles the data logging option without prompting for a new file
Xname.  The status line shows the current data logging mode.
X.SH CONFIGURATION
X.I Pcomm
Xmust have access to the terminfo or termcap data for the terminal
Xbeing used.  The minimum capabilities include a screen size of at
Xleast 80 columns by 24 lines and cursor movement capabilities.
XRunning
X.I pcomm
Xfrom terminals at relatively slow speeds (i.e.: 1200 baud) will cause
Xthe windows to appear sluggish.
X.PP
XTerminals that don't have arrow keys or systems without the newer
Xversions of curses(3) will require the user to substitute the
Xletter 'U' for 'up arrow' and 'N' for 'down arrow'.
X.PP
XThere are three pcomm support files that contain information such as
Xthe default parameters, the modem/tty database, and dialing directory
Xentries.  The following directories are searched to find these files:
X.PP
X.RS 5
X.nf
Xo+ directory given with the '-d' option
Xo+ directory in the PCOMM environmental variable
Xo+ current directory
Xo+ default library directory
X.fi
X.RE
X.PP
XThe 'index' field in the dialing directory serves two purposes.
XThe first use is to act as a short cut into the dialing directory with
Xthe '-f' command line option.  The second use is to specify a tty name
Xfor a given entry.  If the 'index' is a valid device name, that
Xdevice is used instead of searching the tty database for a free port.
X.SH FILES
X.nf
Xpcomm.dial_dir        the dialing directory
Xpcomm.modem           the modem/tty database
Xpcomm.param           the start-up default parameters
X.fi
X.SH SEE ALSO
Xxmodem(1), mdm(1)
echo shar: "12 control characters may be missing from 'Pcomm.1'"
SHAR_EOF
if test 6287 -ne "`wc -c < 'Pcomm.1'`"
then
	echo shar: "error transmitting 'Pcomm.1'" '(should have been 6287 characters)'
fi
fi
echo shar: "extracting 'Pcomm.dial_dir'" '(319 characters)'
if test -f 'Pcomm.dial_dir'
then
	echo shar: "will not over-write existing file 'Pcomm.dial_dir'"
else
sed 's/^X//' << \SHAR_EOF > 'Pcomm.dial_dir'
XDIR_1=Abbey Road;1 (512) 590-6036;2400-N-8-1;F;
XDIR_2=Tel-Med-Com;526-8686;1200-E-7-1;F;
XDIR_3=C Board;1 (619) 722-8724;2400-N-8-1;F;
XDIR_4=Crest;1 (213) 471-2518;2400-N-8-1;F;crest
XDIR_5=Last Chance;1 (219) 762-8411;2400-E-7-1;F;
XDIR_6=Killer;1 (214) 827-1994;1200-E-7-1;F;
XDIR_7=System A (direct);;9600-E-7-1;F;tty12
SHAR_EOF
if test 319 -ne "`wc -c < 'Pcomm.dial_dir'`"
then
	echo shar: "error transmitting 'Pcomm.dial_dir'" '(should have been 319 characters)'
fi
fi
echo shar: "extracting 'Pcomm.modem'" '(248 characters)'
if test -f 'Pcomm.modem'
then
	echo shar: "will not over-write existing file 'Pcomm.modem'"
else
sed 's/^X//' << \SHAR_EOF > 'Pcomm.modem'
XTTY_1=tty10;HAYES;1200
XTTY_2=tty11;HAYES;2400
XTTY_3=tty12;DIRECT;9600
XMODEM_1a=HAYES;ATS7=45S11=70!;ATDT;!;~~+++~~ATH0!
XMODEM_1b=CONNECT!;CONNECT 1200;CONNECT 2400;;;
XMODEM_1c=BUSY;VOICE;NO CARRIER;
XMODEM_2a=DIRECT;;;;
XMODEM_2b=;;;;;
XMODEM_2c=;;;;
SHAR_EOF
if test 248 -ne "`wc -c < 'Pcomm.modem'`"
then
	echo shar: "error transmitting 'Pcomm.modem'" '(should have been 248 characters)'
fi
fi
echo shar: "extracting 'Pcomm.param'" '(362 characters)'
if test -f 'Pcomm.param'
then
	echo shar: "will not over-write existing file 'Pcomm.param'"
else
sed 's/^X//' << \SHAR_EOF > 'Pcomm.param'
XD_BAUD=1200
XD_PARITY=E
XD_DBITS=7
XD_SBITS=1
XHOT=1
XASCII_HOT=^A
XD_DUPLEX=FULL
XFLOW=XON/XOFF
XCR_IN=CR
XCR_OUT=CR
XLOGFILE=pcomm.log
XDUMPFILE=pcomm.dump
XSTRIP=YES
XPAUSE_CHAR=~
XCR_CHAR=!
XCTRL_CHAR=^
XESC_CHAR=|
XABORT=KEEP
XCDELAY=35
XPAUSE=5
XLECHO=NO
XEXPAND=NO
XCR_DELAY=0
XPACE=NO
XCR_UP=NONE
XLF_UP=NONE
XTIMER=5
XCR_DN=STRIP
XLF_DN=NONE
XLD_PLUS=
XLD_MINUS=
XLD_AT=8,
XLD_POUND=9
SHAR_EOF
if test 362 -ne "`wc -c < 'Pcomm.param'`"
then
	echo shar: "error transmitting 'Pcomm.param'" '(should have been 362 characters)'
fi
fi
exit 0
#	End of shell archive

egray@fthood.UUCP (03/13/88)

This is part 2 (of 6) to the Pcomm version 1.0 distribution.

Emmet P. Gray				US Army, HQ III Corps & Fort Hood
...!ihnp4!uiucuxc!fthood!egray		Attn: AFZF-DE-ENV
					Directorate of Engineering & Housing
					Environmental Management Office
					Fort Hood, TX 76544-5057

-------------------------------------------------------------------------------
#! /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:
#	Makefile
#	Unixpc.shar
#	dial_dir.h
#	misc.h
#	modem.h
#	param.h
#	status.h
#	xmodem.h
#	admin.c
#	chg_dir.c
#	curses.c
#	d_delete.c
#	d_lib.c
#	d_manual.c
#	d_menu.c
# This archive created: Fri Mar 11 07:35:04 1988
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'Makefile'" '(3099 characters)'
if test -f 'Makefile'
then
	echo shar: "will not over-write existing file 'Makefile'"
else
sed 's/^X//' << \SHAR_EOF > 'Makefile'
X#				PCOMM
X#			for a generic Unix box
X#
X# valid compile time definitions (CFLAGS) are:
X#
X# OLDCURSES	use termcap (in lieu of terminfo) for curses
X# UNIXPC	use AT&T Unix PC 7300/3b1 specific routines
X# SGID		retore the real group id before doing anything dangerous
X#
X# for systems without getcwd(3) or getopt(3)
X#
X#GETCWD = getcwd.o
X#GETOPT = getopt.o
X
XCC = cc -O
XCFLAGS =
X#CURSES = -lcurses -ltermlib
XCURSES = -lcurses
XLDFLAGS =
XSHAR = shar -a
X
XOBJECTS = $(GETCWD) $(GETOPT) admin.o chg_dir.o curses.o d_delete.o d_lib.o \
X	d_manual.o d_menu.o d_print.o d_prompt.o d_revise.o data_log.o \
X	di_delay.o di_win.o dial.o expand.o help.o info.o init.o input.o \
X	line_set.o list_dir.o ls_menu.o m_lib.o main.o n_shell.o p_lib.o \
X	pexit.o port.o redial.o s_axfer.o s_gen.o s_menu.o s_modem.o \
X	s_prompt.o s_term.o s_tty.o screen.o st_line.o strings.o terminal.o \
X	x_ascii.o x_batch.o x_menu.o x_rcv.o x_send.o x_win.o xmodem.o
X
Xpcomm:	$(OBJECTS)
X	$(CC) $(LDFLAGS) $(OBJECTS) -o pcomm $(CURSES)
X
Xlint:
X	lint $(CFLAGS) *.c
X
Xshar:
X	$(SHAR) Readme Release.notes Doc Pcomm.1 Pcomm.dial_dir Pcomm.modem \
X	Pcomm.param > pcomm_sh.1
X	$(SHAR) Makefile dial_dir.h misc.h modem.h param.h status.h xmodem.h \
X	admin.c chg_dir.c curses.c d_delete.c d_lib.c d_manual.c d_menu.c \
X	d_print.c > pcomm_sh.2
X	$(SHAR) d_prompt.c d_revise.c data_log.c di_delay.c di_win.c dial.c \
X	expand.c getcwd.c getopt.c help.c info.c init.c input.c > pcomm_sh.3
X	$(SHAR) line_set.c list_dir.c ls_menu.c m_lib.c main.c n_shell.c \
X	p_lib.c pexit.c port.c redial.c s_axfer.c s_gen.c > pcomm_sh.4
X	$(SHAR) s_menu.c s_modem.c s_prompt.c s_term.c s_tty.c screen.c \
X	st_line.c strings.c terminal.c x_ascii.c x_batch.c > pcomm_sh.5
X	$(SHAR) x_menu.c x_rcv.c x_send.c x_win.c xmodem.c > pcomm_sh.6
X
Xadmin.o:	dial_dir.h param.h
Xchg_dir.o:	misc.h
Xcurses.o:	misc.h
Xd_delete.o:	dial_dir.h misc.h param.h
Xd_lib.o:	dial_dir.h param.h status.h
Xd_manual.o:	dial_dir.h
Xd_menu.o:	dial_dir.h misc.h param.h
Xd_print.o:	dial_dir.h misc.h
Xd_prompt.o:	dial_dir.h misc.h
Xd_revise.o:	dial_dir.h misc.h param.h
Xdata_log.o:	misc.h param.h status.h
Xdi_delay.o:	misc.h param.h
Xdi_win.o:	dial_dir.h misc.h modem.h param.h status.h
Xdial.o:		dial_dir.h modem.h param.h status.h
Xhelp.o:		misc.h
Xinit.o:		misc.h status.h
Xline_set.o:	dial_dir.h param.h status.h
Xlist_dir.o:	misc.h
Xls_menu.o:	dial_dir.h misc.h param.h
Xm_lib.o:	modem.h status.h
Xmain.o:		dial_dir.h modem.h param.h status.h
Xp_lib.o:	param.h status.h
Xpexit.o:	dial_dir.h misc.h param.h status.h
Xport.o:		dial_dir.h modem.h status.h
Xredial.o:	dial_dir.h misc.h
Xs_axfer.o:	misc.h param.h
Xs_gen.o:	misc.h param.h
Xs_menu.o:	misc.h
Xs_modem.o:	misc.h modem.h
Xs_prompt.o:	misc.h
Xs_term.o:	misc.h param.h
Xs_tty.o:	misc.h modem.h status.h
Xscreen.o:	param.h status.h
Xst_line.o:	dial_dir.h misc.h modem.h param.h status.h
Xterminal.o:	dial_dir.h modem.h param.h status.h
Xx_ascii.o:	param.h status.h
Xx_batch.o:	misc.h xmodem.h
Xx_menu.o:	misc.h xmodem.h
Xx_rcv.o:	dial_dir.h misc.h xmodem.h
Xx_send.o:	dial_dir.h misc.h status.h xmodem.h
Xx_win.o:	dial_dir.h misc.h status.h xmodem.h
Xxmodem.o:	param.h status.h xmodem.h
SHAR_EOF
if test 3099 -ne "`wc -c < 'Makefile'`"
then
	echo shar: "error transmitting 'Makefile'" '(should have been 3099 characters)'
fi
fi
echo shar: "extracting 'Unixpc.shar'" '(5713 characters)'
if test -f 'Unixpc.shar'
then
	echo shar: "will not over-write existing file 'Unixpc.shar'"
else
sed 's/^X//' << \SHAR_EOF > 'Unixpc.shar'
X#! /bin/sh
X# This is a shell archive, meaning:
X# 1. Remove everything above the #! /bin/sh line.
X# 2. Save the resulting text in a file.
X# 3. Execute the file with /bin/sh (not csh) to create:
X#	Ifile.sh
X#	Makefile
X#	Pcomm.modem
X# This archive created: Fri Mar 11 07:34:54 1988
Xexport PATH; PATH=/bin:/usr/bin:$PATH
Xecho shar: "extracting 'Ifile.sh'" '(705 characters)'
Xif test -f 'Ifile.sh'
Xthen
X	echo shar: "will not over-write existing file 'Ifile.sh'"
Xelse
Xsed 's/^X//' << \SHAR_EOF > 'Ifile.sh'
XXex - $1 << EOF
XX1,\$s/^PC/xPC/
XX1,\$s/^BC/xBC/
XX1,\$s/^UP/xUP/
XX1,\$s/^ospeed/xospeed/
XX1,\$s/^LINES/xLINES/
XX1,\$s/^COLS/xCOLS/
XX1,\$s/^tgetflag/xtgetflag/
XX1,\$s/^tgetent/xtgetent/
XX1,\$s/^tgetstr/xtgetstr/
XX1,\$s/^tgetnum/xtgetnum/
XX1,\$s/^tgoto/xtgoto/
XX1,\$s/^tputs/xtputs/
XX1,\$s/^wrefresh/xwrefresh/
XX1,\$s/^initscr/xinitscr/
XX1,\$s/^cbreak/xcbreak/
XX1,\$s/^nl/xnl/
XX1,\$s/^flushinp/xflushinp/
XX1,\$s/^noecho/xnoecho/
XX1,\$s/^savetty/xsavetty/
XX1,\$s/^resetty/xresetty/
XX1,\$s/^echo/xecho/
XX1,\$s/^nocbreak/xnocbreak/
XX1,\$s/^nonl/xnonl/
XX1,\$s/^keypad/xkeypad/
XX1,\$s/^endwin/xendwin/
XX1,\$s/^printw/xprintw/
XX1,\$s/^fixterm/xfixterm/
XX1,\$s/^resetterm/xresetterm/
XX1,\$s/^setterm/xsetterm/
XX1,\$s/^baudrate/xbaudrate/
XXw
XXq
XXEOF
XSHAR_EOF
Xif test 705 -ne "`wc -c < 'Ifile.sh'`"
Xthen
X	echo shar: "error transmitting 'Ifile.sh'" '(should have been 705 characters)'
Xfi
Xfi
Xecho shar: "extracting 'Makefile'" '(3372 characters)'
Xif test -f 'Makefile'
Xthen
X	echo shar: "will not over-write existing file 'Makefile'"
Xelse
Xsed 's/^X//' << \SHAR_EOF > 'Makefile'
XX#				Pcomm
XX#			for AT&T Unix PC 7300/3b1
XX#
XX# valid compile time definitions (CFLAGS) are:
XX#
XX# OLDCURSES	use termcap (in lieu of terminfo) for curses
XX# UNIXPC	use AT&T Unix PC 7300/3b1 specific routines
XX# SGID		retore the real group id before doing anything dangerous
XX#
XX# for systems without getcwd(3) or getopt(3)
XX#
XX#GETCWD = getcwd.o
XX#GETOPT = getopt.o
XX
XXCC = cc -O
XXCFLAGS = -DUNIXPC
XXCURSES = -lcurses
XXLD = ld -s
XXSHAR = shar -a
XXSTARTUP = /lib/crt0s.o
XXSHAREDLIB = shlib_c.ifile
XX
XXOBJECTS = $(GETCWD) $(GETOPT) admin.o chg_dir.o curses.o d_delete.o d_lib.o \
XX	d_manual.o d_menu.o d_print.o d_prompt.o d_revise.o data_log.o \
XX	di_delay.o di_win.o dial.o expand.o help.o info.o init.o input.o \
XX	line_set.o list_dir.o ls_menu.o m_lib.o main.o n_shell.o p_lib.o \
XX	pexit.o port.o redial.o s_axfer.o s_gen.o s_menu.o s_modem.o \
XX	s_prompt.o s_term.o s_tty.o screen.o st_line.o strings.o terminal.o \
XX	x_ascii.o x_batch.o x_menu.o x_rcv.o x_send.o x_win.o xmodem.o
XX
XXOTHERS = setvbuf.o doprnt.o
XX
XXpcomm:	$(OBJECTS) $(OTHERS) $(SHAREDLIB)
XX	$(LD) $(OBJECTS) $(OTHERS) $(CURSES) $(STARTUP) $(SHAREDLIB) -o pcomm
XX
XXlint:
XX	lint $(CFLAGS) *.c
XX
XXshar:
XX	$(SHAR) Readme Release.notes Doc Pcomm.1 Pcomm.dial_dir Pcomm.modem \
XX	Pcomm.param Ifile.sh > pcomm_sh.1
XX	$(SHAR) Makefile dial_dir.h misc.h modem.h param.h status.h xmodem.h \
XX	admin.c chg_dir.c curses.c d_delete.c d_lib.c d_manual.c d_menu.c \
XX	d_print.c > pcomm_sh.2
XX	$(SHAR) d_prompt.c d_revise.c data_log.c di_delay.c di_win.c dial.c \
XX	expand.c getcwd.c getopt.c help.c info.c init.c input.c > pcomm_sh.3
XX	$(SHAR) line_set.c list_dir.c ls_menu.c m_lib.c main.c n_shell.c \
XX	p_lib.c pexit.c port.c redial.c s_axfer.c s_gen.c > pcomm_sh.4
XX	$(SHAR) s_menu.c s_modem.c s_prompt.c s_term.c s_tty.c screen.c \
XX	st_line.c strings.c terminal.c x_ascii.c x_batch.c > pcomm_sh.5
XX	$(SHAR) x_menu.c x_rcv.c x_send.c x_win.c xmodem.c > pcomm_sh.6
XX
XXsetvbuf.o:
XX	ar x /lib/libc.a setvbuf.o
XX
XXdoprnt.o:
XX	ar x /lib/libc.a doprnt.o
XX
XXshlib_c.ifile:
XX	cp /lib/shlib.ifile shlib_c.ifile
XX	sh Ifile.sh shlib_c.ifile
XX
XXadmin.o:	dial_dir.h param.h
XXchg_dir.o:	misc.h
XXcurses.o:	misc.h
XXd_delete.o:	dial_dir.h misc.h param.h
XXd_lib.o:	dial_dir.h param.h status.h
XXd_manual.o:	dial_dir.h
XXd_menu.o:	dial_dir.h misc.h param.h
XXd_print.o:	dial_dir.h misc.h
XXd_prompt.o:	dial_dir.h misc.h
XXd_revise.o:	dial_dir.h misc.h param.h
XXdata_log.o:	misc.h param.h status.h
XXdi_delay.o:	misc.h param.h
XXdi_win.o:	dial_dir.h misc.h modem.h param.h status.h
XXdial.o:		dial_dir.h modem.h param.h status.h
XXhelp.o:		misc.h
XXinit.o:		misc.h status.h
XXline_set.o:	dial_dir.h param.h status.h
XXlist_dir.o:	misc.h
XXls_menu.o:	dial_dir.h misc.h param.h
XXm_lib.o:	modem.h status.h
XXmain.o:		dial_dir.h modem.h param.h status.h
XXp_lib.o:	param.h status.h
XXpexit.o:	dial_dir.h misc.h param.h status.h
XXport.o:		dial_dir.h modem.h status.h
XXredial.o:	dial_dir.h misc.h
XXs_axfer.o:	misc.h param.h
XXs_gen.o:	misc.h param.h
XXs_menu.o:	misc.h
XXs_modem.o:	misc.h modem.h
XXs_prompt.o:	misc.h
XXs_term.o:	misc.h param.h
XXs_tty.o:	misc.h modem.h status.h
XXscreen.o:	param.h status.h
XXst_line.o:	dial_dir.h misc.h modem.h param.h status.h
XXterminal.o:	dial_dir.h modem.h param.h status.h
XXx_ascii.o:	param.h status.h
XXx_batch.o:	misc.h xmodem.h
XXx_menu.o:	misc.h xmodem.h
XXx_rcv.o:	dial_dir.h misc.h xmodem.h
XXx_send.o:	dial_dir.h misc.h status.h xmodem.h
XXx_win.o:	dial_dir.h misc.h status.h xmodem.h
XXxmodem.o:	param.h status.h xmodem.h
XSHAR_EOF
Xif test 3372 -ne "`wc -c < 'Makefile'`"
Xthen
X	echo shar: "error transmitting 'Makefile'" '(should have been 3372 characters)'
Xfi
Xfi
Xecho shar: "extracting 'Pcomm.modem'" '(154 characters)'
Xif test -f 'Pcomm.modem'
Xthen
X	echo shar: "will not over-write existing file 'Pcomm.modem'"
Xelse
Xsed 's/^X//' << \SHAR_EOF > 'Pcomm.modem'
XXTTY_1=ph1;OBM;1200
XXTTY_2=tty000;DIRECT;19200
XXMODEM_1a=OBM;;%;@;
XXMODEM_1b=CONNECT;CONNECT;;;;
XXMODEM_1c=;;;
XXMODEM_2a=DIRECT;;;;
XXMODEM_2b=;;;;;
XXMODEM_2c=;;;
XSHAR_EOF
Xif test 154 -ne "`wc -c < 'Pcomm.modem'`"
Xthen
X	echo shar: "error transmitting 'Pcomm.modem'" '(should have been 154 characters)'
Xfi
Xfi
Xexit 0
X#	End of shell archive
SHAR_EOF
if test 5713 -ne "`wc -c < 'Unixpc.shar'`"
then
	echo shar: "error transmitting 'Unixpc.shar'" '(should have been 5713 characters)'
fi
fi
echo shar: "extracting 'dial_dir.h'" '(815 characters)'
if test -f 'dial_dir.h'
then
	echo shar: "will not over-write existing file 'dial_dir.h'"
else
sed 's/^X//' << \SHAR_EOF > 'dial_dir.h'
X/*
X * The dialing directory structure.  The first eight elements are
X * contained in the pcomm.dial_dir file.
X */
X
X#define NUM_DIR		100
X#define NUM_QUEUE	10
X
Xstruct DIAL_DIR {
X	char	*name[NUM_DIR+1];	/* name of system being called */
X	char	*number[NUM_DIR+1];	/* phone number */
X	int	baud[NUM_DIR+1];	/* baud rate */
X	char	parity[NUM_DIR+1];	/* parity */
X	int	dbits[NUM_DIR+1];	/* data bits */
X	int	sbits[NUM_DIR+1];	/* stop bits */
X	char	duplex[NUM_DIR+1];	/* duplex (F = full, H = half) */
X	char 	*index[NUM_DIR+1];	/* command line index (or tty) */
X
X	int	d_entries;		/* number of entries in the file */
X	int	d_cur;			/* the current entry */
X	int	q_num[NUM_QUEUE];	/* entry numbers in the queue */
X	char	q_ld[NUM_QUEUE];	/* LD codes in the queue */
X};
X
X#ifndef MAIN
Xextern struct DIAL_DIR *dir;
X#endif /* MAIN */
SHAR_EOF
if test 815 -ne "`wc -c < 'dial_dir.h'`"
then
	echo shar: "error transmitting 'dial_dir.h'" '(should have been 815 characters)'
fi
fi
echo shar: "extracting 'misc.h'" '(1031 characters)'
if test -f 'misc.h'
then
	echo shar: "will not over-write existing file 'misc.h'"
else
sed 's/^X//' << \SHAR_EOF > 'misc.h'
X/*
X * Definitions to support the home-grown curses functions and to make the
X * old curses routines happy
X */
X
X#define NOPROMOTE
X
X#define mvwattrstr(w,y,x,a,s)	(wmove(w,y,x)==ERR?ERR:wattrstr(w,a,s))
X#define mvwattrch(w,y,x,a,c)	(wmove(w,y,x)==ERR?ERR:wattrch(w,a,c))
X#define mvwattrnum(w,y,x,a,n)	(wmove(w,y,x)==ERR?ERR:wattrnum(w,a,n))
X#define mvattrstr(y,x,a,s)	(wmove(stdscr,y,x)==ERR?ERR:wattrstr(stdscr,a,s))
X#define mvattrch(y,x,a,c)	(wmove(stdscr,y,x)==ERR?ERR:wattrch(stdscr,a,c))
X#define mvattrnum(y,x,a,n)	(wmove(stdscr,y,x)==ERR?ERR:wattrnum(stdscr,a,n))
X#define attrstr(a,s)		wattrstr(stdscr,a,s)
X#define attrch(a,c)		wattrch(stdscr,a,c)
X#define attrnum(a,n)		wattrnum(stdscr,a,n)
X
X#ifdef OLDCURSES
X#ifdef NOPROMOTE
X#define A_BOLD		0
X#define A_BLINK		0
X#define A_REVERSE	1
X#define A_DIM		0
X#define A_STANDOUT	1
X#define A_UNDERLINE	0
X#else /* NOPROMOTE */
X#define A_BOLD		1
X#define A_BLINK		1
X#define A_REVERSE	1
X#define A_DIM		1
X#define A_STANDOUT	1
X#define A_UNDERLINE	1
X#endif /* NOPROMOTE */
X#endif /* OLDCURSES */
SHAR_EOF
if test 1031 -ne "`wc -c < 'misc.h'`"
then
	echo shar: "error transmitting 'misc.h'" '(should have been 1031 characters)'
fi
fi
echo shar: "extracting 'modem.h'" '(1417 characters)'
if test -f 'modem.h'
then
	echo shar: "will not over-write existing file 'modem.h'"
else
sed 's/^X//' << \SHAR_EOF > 'modem.h'
X/*
X * The modem and tty databases.  The first 3 elements make up the tty
X * database, the next 15 make up the modem database.  A "tname" in common
X * with a "mname" link the two together.
X */
X
X#define NUM_TTY		10
X#define NUM_MODEM	10
X
Xstruct MODEM {
X	char 	*tty[NUM_TTY];		/* tty names */
X	char	*tname[NUM_TTY];	/* modem name */
X	int	mbaud[NUM_TTY];		/* maximum baud rate */
X
X	char	*mname[NUM_MODEM];	/* modem name (matches tname above) */
X	char	*init[NUM_MODEM];	/* initialization */
X	char	*dial[NUM_MODEM];	/* dial command */
X	char	*suffix[NUM_MODEM];	/* dialing command suffix */
X	char	*hangup[NUM_MODEM];	/* hang up the modem */
X	char	*con_3[NUM_MODEM];	/* 300 baud connect message */
X	char	*con_12[NUM_MODEM];	/* 1200 baud connect message */
X	char	*con_24[NUM_MODEM];	/* 2400 baud connect message */
X	char	*con_48[NUM_MODEM];	/* 4800 baud connect message */
X	char	*con_96[NUM_MODEM];	/* 9600 baud connect message */
X	char	*con_192[NUM_MODEM];	/* 19200 baud connect message */
X	char	*no_con1[NUM_MODEM];	/* no connect #1 */
X	char	*no_con2[NUM_MODEM];	/* no connect #2 */
X	char	*no_con3[NUM_MODEM];	/* no connect #3 */
X	char	*no_con4[NUM_MODEM];	/* no connect #4 */
X
X	int	t_entries;		/* number of tty entries */
X	int	m_entries;		/* number of modem entries */
X	int	t_cur;			/* current tty entry number */
X	int	m_cur;			/* current modem entry number */
X};
X
X#ifndef MAIN
Xextern struct MODEM *modem;
X#endif /* MAIN */
SHAR_EOF
if test 1417 -ne "`wc -c < 'modem.h'`"
then
	echo shar: "error transmitting 'modem.h'" '(should have been 1417 characters)'
fi
fi
echo shar: "extracting 'param.h'" '(2262 characters)'
if test -f 'param.h'
then
	echo shar: "will not over-write existing file 'param.h'"
else
sed 's/^X//' << \SHAR_EOF > 'param.h'
X/*
X * The standard pcomm parameters.  Everything can be altered by using one
X * of pcomm's menus.  Although editing by hand is not encouraged, the
X * pcomm.param file is just an ASCII file.
X */
X
X#define MAX_CDELAY	120
X#define MIN_CDELAY	10
X#define MAX_PAUSE	120
X#define MIN_PAUSE	1
X#define MAX_TIMER	20
X#define MIN_TIMER	2
X
X#define NUM_PARAM	33
X#define LINE_SET	0
X#define TERM_SETUP	4
X#define GEN_SETUP	10
X#define DELAY_TIMES	18
X#define ASCII_SETUP	20
X#define LD_CODES	29
X
Xstruct PARAM {
X				/* 0-3 used in line_set_menu() */
X	int	d_baud;			/* default baud rate */
X	char	d_parity;		/* default parity */
X	int	d_dbits;		/* default data bits */
X	int 	d_sbits;		/* default stop bits */
X
X				/* 4-9 used in term_setup() */
X	int	hot;			/* the decimal code for the hot key */
X	char 	*ascii_hot;		/* ascii representation of hot key */
X	char 	*d_duplex;		/* default duplex */
X	char	*flow;			/* flow control */
X	char	*cr_in;			/* send as carriage return */
X	char	*cr_out;		/* receive carriage return as */
X
X				/* 10-17 used in gen_setup() */
X	char	*logfile;		/* default log file */
X	char	*dumpfile;		/* default screen dump file */
X	char	*strip;			/* strip high bit (translate table) */
X	char	pause_char;		/* pause char synonym */
X	char 	cr_char;		/* carriage return char synonym */
X	char 	ctrl_char;		/* ctrl char synonym */
X	char 	esc_char;		/* escape char synonym */
X	char 	*abort;			/* destination of aborted downloads */
X
X				/* 18-19 used in gen_setup() & delay_times() */
X	int	cdelay;			/* connect delay time */
X	int	pause;			/* pause between dialing attempts */
X
X				/* 20-27 used in ascii_xfer_setup() */
X	char	*lecho;			/* echo locally ? */
X	char	*expand;		/* expand blank lines? */
X	int	cr_delay;		/* carriage return delay (ms) */
X	char	*pace;			/* pace the output ? */
X	char	*cr_up;			/* send carriage return as */
X	char	*lf_up;			/* send line feed as */
X	int	timer;			/* Transfer timeout */
X	char	*cr_dn;			/* receive carriage return as */
X	char	*lf_dn;			/* receive line feed as */
X
X				/* 28-31 used in d_revise() */
X	char	*ld_plus;		/* + long distance code */
X	char	*ld_minus;		/* - long distance code */
X	char	*ld_at;			/* @ long distance code */
X	char	*ld_pound;		/* # long distance code */
X};
X
X#ifndef MAIN
Xextern struct PARAM *param;
X#endif /* MAIN */
SHAR_EOF
if test 2262 -ne "`wc -c < 'param.h'`"
then
	echo shar: "error transmitting 'param.h'" '(should have been 2262 characters)'
fi
fi
echo shar: "extracting 'status.h'" '(631 characters)'
if test -f 'status.h'
then
	echo shar: "will not over-write existing file 'status.h'"
else
sed 's/^X//' << \SHAR_EOF > 'status.h'
X/*
X * The location of the support files, status flags, and other various
X * changeable things.
X */
X
Xstruct STATUS {
X	char	*p_path;		/* pcomm.param file */
X	char	*d_path;		/* pcomm.dial_dir file */
X	char	*m_path;		/* pcomm.modem file */
X	char	*lock_path;		/* UUCP lock file */
X	char	*vs_path;		/* virtual screen file */
X	char	*log_path;		/* data logging file */
X	int	fd;			/* file descriptor for tty */
X	int	log;			/* status of log option */
X	int	print;			/* status of print option */
X	int	msg;			/* the 'msg' status */
X	int	pid;			/* the pid of the child process */
X};
X
X#ifndef MAIN
Xextern struct STATUS *status;
X#endif /* MAIN */
SHAR_EOF
if test 631 -ne "`wc -c < 'status.h'`"
then
	echo shar: "error transmitting 'status.h'" '(should have been 631 characters)'
fi
fi
echo shar: "extracting 'xmodem.h'" '(373 characters)'
if test -f 'xmodem.h'
then
	echo shar: "will not over-write existing file 'xmodem.h'"
else
sed 's/^X//' << \SHAR_EOF > 'xmodem.h'
X/*
X * Definitions for the xmodem stuff.
X */
X
X#define MAX_ERRORS 	10
X
X#define SOH		1
X#define STX		2
X#define EOT		4
X#define ACK		6
X#define NAK		21
X#define CAN		24
X#define CTRLZ		26
X
X#define PROTOCOLS	6
X#define XMODEM		0
X#define XMODEM_1k	1
X#define MODEM7		2
X#define YMODEM		3
X#define YMODEM_G	4
X#define XASCII		5
X
X#define ABORT		(-1)
X#define ERROR		(-2)
X#define CANCEL		(-3)
SHAR_EOF
if test 373 -ne "`wc -c < 'xmodem.h'`"
then
	echo shar: "error transmitting 'xmodem.h'" '(should have been 373 characters)'
fi
fi
echo shar: "extracting 'admin.c'" '(2871 characters)'
if test -f 'admin.c'
then
	echo shar: "will not over-write existing file 'admin.c'"
else
sed 's/^X//' << \SHAR_EOF > 'admin.c'
X/*
X * Perform administrative functions.  Check to see if the user has
X * permission to make long distance calls, and record all phone calls
X * made by pcomm.
X */
X
X#undef LOG_CALLS
X#undef LIMIT_LD
X
X#define LOGFILE "/usr/adm/phone.calls"
X#define GRPNAME "uucp"
X
X#include <stdio.h>
X#include <grp.h>
X#include "dial_dir.h"
X#include "param.h"
X
X/*
X * Make a log of all calls made by pcomm.  The argument is the index
X * into the queue.
X */
X
Xint
Xlog_calls(i)
Xint i;
X{
X#ifdef LOG_CALLS
X	FILE *fp;
X	char *number, *build_num(), *date, *ctime(), *getlogin();
X	long now, time();
X	void error_win();
X					/* build the complete phone number */
X	number = build_num(i);
X					/* build date and time */
X	time(&now);
X	date = ctime(&now);
X	date[10] = NULL;
X	date[16] = NULL;
X
X	if (!(fp = fopen(LOGFILE, "a+")))
X		error_win(1, "Can't open phone log file", "Contact your system administrator");
X
X	fprintf(fp, "pcomm: %s called %s at %s on %s\n", getlogin(), number, &date[11], date);
X	fclose(fp);
X#endif /* LOG_CALLS */
X	return (0);
X}
X
X/*
X * Check to see if long distance (toll) call is authorized.  The argument
X * is the index into the queue.
X */
X
Xint
Xlimit_ld(i)
Xint i;
X{
X#ifdef LIMIT_LD
X	char *number, *build_num(), *name, *getlogin();
X	struct group *getgrnam(), *grpbuf;
X
X					/* if no group, don't bother */
X	grpbuf = getgrnam(GRPNAME);
X	if (!grpbuf || !*grpbuf->gr_mem)
X		return(0);
X					/* are you in the group? */
X	name = getlogin();
X	for (; *grpbuf->gr_mem != NULL; grpbuf->gr_mem++) {
X		if (!strcmp(*grpbuf->gr_mem, name))
X			return(0);
X	}
X					/* numbers only... */
X	number = build_num(i);
X
X	/*
X	 * Very site specific!!!  We use a '9' to get an outside line,
X	 * so any 9 followed by a 1 is a toll call (except for 1-800
X	 * numbers).
X	 */
X	if (!strncmp(number, "91", 2) && strncmp(number, "91800", 5)) {
X		error_win(0, "You are not authorized to place long distance \(toll\) calls", NULL);
X		return(1);
X	}
X
X	if (*number == NULL) {
X		error_win(0, "You are not authorized direct access to the line", "Use the automatic dialing feature");
X		return(1);
X	}
X#endif /* LIMIT_LD */
X	return(0);
X}
X
X#ifdef LOG_CALLS || LIMIT_LD
X/*
X * Put together the complete phone number but strip out the extraneous
X * characters.
X */
X
Xchar *
Xbuild_num(i)
Xint i;
X{
X	int j;
X	char *t, temp[40], *strcpy(), *strcat();
X	static char ans[40];
X
X	temp[0] = NULL;
X					/* add LD codes ? */
X	switch (dir->q_ld[i]) {
X		case 0:
X			break;
X		case '+':
X			strcpy(temp, param->ld_plus);
X			break;
X		case '-':
X			strcpy(temp, param->ld_minus);
X			break;
X		case '@':
X			strcpy(temp, param->ld_at);
X			break;
X		case '#':
X			strcpy(temp, param->ld_pound);
X			break;
X	}
X					/* add the number */
X	strcat(temp, dir->number[dir->q_num[i]]);
X
X					/* copy only digits */
X	j = 0;
X	t = temp;
X	while (*t) {
X		if (*t >= '0' && *t <= '9')
X			ans[j++] = *t;
X		t++;
X	}
X	ans[j] = NULL;
X
X	return(ans);
X}
X#endif /* LOG_CALLS || LIMIT_LD */
SHAR_EOF
if test 2871 -ne "`wc -c < 'admin.c'`"
then
	echo shar: "error transmitting 'admin.c'" '(should have been 2871 characters)'
fi
fi
echo shar: "extracting 'chg_dir.c'" '(1363 characters)'
if test -f 'chg_dir.c'
then
	echo shar: "will not over-write existing file 'chg_dir.c'"
else
sed 's/^X//' << \SHAR_EOF > 'chg_dir.c'
X/*
X * Open a window to prompt for a new directory.  Checks to see if the
X * directory exists, but doesn't move to there (yet).  Returns the path
X * to the new directory, or NULL if you chickened out.
X */
X
X#include <curses.h>
X#include "misc.h"
X
Xchar *
Xchange_dir(fd)
Xint fd;
X{
X	WINDOW *ch_win, *newwin();
X	int got_it;
X	char *ans, *dir, *expand(), *cwd, *getcwd(), cwdbuf[200];
X	char *get_str();
X	void free_ptr();
X
X	cwd = getcwd(cwdbuf, 200);
X
X	ch_win = newwin(6, 70, 5, 5);
X
X	mvwprintw(ch_win, 2, 4, "Current directory: %s", cwd);
X	mvwaddstr(ch_win, 3, 4, "New directory: ");
X	box(ch_win, '|', '-');
X
X	mvwattrstr(ch_win, 0, 3, A_BOLD, " Change directory ");
X	wmove(ch_win, 3, 19);
X	wrefresh(ch_win);
X					/* get the answer */
X	got_it = 0;
X	while ((ans = get_str(ch_win, 60, NULL, " 	")) != NULL) {
X		if (*ans == NULL)
X			break;
X					/* expand the input */
X		dir = expand(ans);
X					/* if it exists */
X		if (!access(dir, 1)) {
X			got_it++;
X			break;
X		}
X		beep();
X		mvwattrstr(ch_win, 4, 15, A_BOLD, "No such directory or no access permission");
X		wrefresh(ch_win);
X		wait_key(ch_win, 3);
X					/* cleanup the mess */
X		clear_line(ch_win, 3, 19, 1);
X		clear_line(ch_win, 4, 14, 1);
X		wmove(ch_win, 3, 19);
X		wrefresh(ch_win);
X		free_ptr(dir);
X	}
X	if (fd == -1) {
X		werase(ch_win);
X		wrefresh(ch_win);
X	}
X	delwin(ch_win);
X	if (got_it)
X		return(dir);
X	return(NULL);
X}
SHAR_EOF
if test 1363 -ne "`wc -c < 'chg_dir.c'`"
then
	echo shar: "error transmitting 'chg_dir.c'" '(should have been 1363 characters)'
fi
fi
echo shar: "extracting 'curses.c'" '(7649 characters)'
if test -f 'curses.c'
then
	echo shar: "will not over-write existing file 'curses.c'"
else
sed 's/^X//' << \SHAR_EOF > 'curses.c'
X/*
X * Miscellaneous curses routines.
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include <signal.h>
X#include <setjmp.h>
X#ifdef OLDCURSES
X#include <fcntl.h>
X#else /* OLDCURSES */
X#include <term.h>
X#endif /* OLDCURSES */
X#include "misc.h"
X
X/*
X * Get a string from a window.  Similar to wgetstr(), except we limit
X * the length, return a NULL (not pointer to NULL) on ESC key, beep
X * at any character in 'disallow' string, and beep at any character not
X * in 'allow'. (It doesn't make sense to use both 'allow' and 'disallow'
X * at the same time)
X */
X
Xchar *
Xget_str(win, num, allow, disallow)
XWINDOW *win;
Xint num;
Xchar *allow, *disallow;
X{
X	int count, x, y;
X	char ans, *strchr();
X	static char buf[80];
X
X	count = 0;
X	while ((ans = wgetch(win)) != '\r') {
X					/* do our own backspace */
X		if (ans == 8) {
X			if (!count) {
X				beep();
X				continue;
X			}
X			count--;
X			buf[count] = NULL;
X			getyx(win, y, x);
X			x--;
X			wmove(win, y, x);
X			waddch(win, ' ');
X			wmove(win, y, x);
X			wrefresh(win);
X			continue;
X		}
X					/* an ESC anywhere in the string */
X		if (ans == 27)
X			return(NULL);
X
X					/* illegal character ? */
X		if (disallow != NULL && strchr(disallow, ans)) {
X			beep();
X			continue;
X		}
X		if (allow != NULL && !strchr(allow, ans)) {
X			beep();
X			continue;
X		}
X					/* exceeded the max ? */
X		if (count == num) {
X			beep();
X			continue;
X		}
X
X		buf[count] = ans;
X		waddch(win, ans);
X		wrefresh(win);
X		count++;
X	}
X	buf[count] = NULL;
X	return(buf);
X}
X
X/*
X * Get a number from a window.  We limit the length and return a -1
X * on ESC key.
X */
X
Xint
Xget_num(win, num)
XWINDOW *win;
Xint num;
X{
X	int count, x, y, number;
X	char ans, buf[80];
X
X	count = 0;
X	while ((ans = wgetch(win)) != '\r') {
X					/* do our own backspace */
X		if (ans == 8) {
X			if (!count) {
X				beep();
X				continue;
X			}
X			count--;
X			buf[count] = NULL;
X			getyx(win, y, x);
X			x--;
X			wmove(win, y, x);
X			waddch(win, ' ');
X			wmove(win, y, x);
X			wrefresh(win);
X			continue;
X		}
X					/* an ESC anywhere in the string */
X		if (ans == 27)
X			return(-1);
X					/* only digits are allowed */
X		if (ans < '0' || ans > '9') {
X			beep();
X			continue;
X		}
X					/* exceeded the max ? */
X		if (count == num) {
X			beep();
X			continue;
X		}
X
X		buf[count] = ans;
X		waddch(win, ans);
X		wrefresh(win);
X		count++;
X	}
X	buf[count] = NULL;
X	number = atoi(buf);
X	return(number);
X}
X
X/*
X * Change video attributes while printing a string.  The use of the
X * pre-processor definition NOPROMOTE (located in misc.h) means that
X * strings will be printed without any special video attribute if the
X * requested capability doesn't exist.
X */
X
Xwattrstr(win, attr, str)
XWINDOW *win;
Xint attr;
Xchar *str;
X{
X	int do_it;
X					/* if nothing, do nothing */
X	if (str == NULL || *str == NULL)
X		return(0);
X
X#ifdef OLDCURSES
X	if (attr)
X		wstandout(win);
X	waddstr(win, str);
X	if (attr)
X		wstandend(win);
X#else /* OLDCURSES */
X#ifdef NOPROMOTE
X					/* does the capability exist ? */
X	do_it = 0;
X	if ((attr & A_STANDOUT) && enter_standout_mode)
X		do_it++;
X	if ((attr & A_UNDERLINE) && enter_underline_mode)
X		do_it++;
X	if ((attr & A_REVERSE) && (enter_reverse_mode || enter_standout_mode))
X		do_it++;
X	if ((attr & A_BLINK) && enter_blink_mode)
X		do_it++;
X	if ((attr & A_BOLD) && enter_bold_mode)
X		do_it++;
X	if ((attr & A_DIM) && enter_dim_mode)
X		do_it++;
X#else /* NOPROMOTE */
X	do_it = 1;
X#endif /* NOPROMOTE */
X
X	if (do_it)
X		wattron(win, attr);
X					/* print the string */
X	waddstr(win, str);
X	if (do_it)
X		wattroff(win, attr);
X#endif /* OLDCURSES */
X	return(0);
X}
X
X/*
X * Change video attributes while printing a character.
X */
X
Xwattrch(win, attr, c)
XWINDOW *win;
Xint attr;
Xchar c;
X{
X	int do_it;
X
X	if (c == NULL)
X		return(0);
X#ifdef OLDCURSES
X	if (attr)
X		wstandout(win);
X	waddch(win, c);
X	if (attr)
X		wstandend(win);
X#else /* OLDCURSES */
X#ifdef NOPROMOTE
X					/* does the capability exist ? */
X	do_it = 0;
X	if ((attr & A_STANDOUT) && enter_standout_mode)
X		do_it++;
X	if ((attr & A_UNDERLINE) && enter_underline_mode)
X		do_it++;
X	if ((attr & A_REVERSE) && (enter_reverse_mode || enter_standout_mode))
X		do_it++;
X	if ((attr & A_BLINK) && enter_blink_mode)
X		do_it++;
X	if ((attr & A_BOLD) && enter_bold_mode)
X		do_it++;
X	if ((attr & A_DIM) && enter_dim_mode)
X		do_it++;
X#else /* NOPROMOTE */
X	do_it = 1;
X#endif /* NOPROMOTE */
X
X	if (do_it)
X		wattron(win, attr);
X					/* print the character */
X	waddch(win, c);
X	if (do_it)
X		wattroff(win, attr);
X#endif /* OLDCURSES */
X	return(0);
X}
X
X
X/*
X * Change video attributes while printing a number.
X */
X
Xwattrnum(win, attr, num)
XWINDOW *win;
Xint attr, num;
X{
X	int do_it;
X	char buf[20];
X
X	sprintf(buf, "%d", num);
X
X#ifdef OLDCURSES
X	if (attr)
X		wstandout(win);
X	waddstr(win, buf);
X	if (attr)
X		wstandend(win);
X#else /* OLDCURSES */
X#ifdef NOPROMOTE
X					/* does the capability exist ? */
X	do_it = 0;
X	if ((attr & A_STANDOUT) && enter_standout_mode)
X		do_it++;
X	if ((attr & A_UNDERLINE) && enter_underline_mode)
X		do_it++;
X	if ((attr & A_REVERSE) && (enter_reverse_mode || enter_standout_mode))
X		do_it++;
X	if ((attr & A_BLINK) && enter_blink_mode)
X		do_it++;
X	if ((attr & A_BOLD) && enter_bold_mode)
X		do_it++;
X	if ((attr & A_DIM) && enter_dim_mode)
X		do_it++;
X#else /* NOPROMOTE */
X	do_it = 1;
X#endif /* NOPROMOTE */
X
X	if (do_it)
X		wattron(win, attr);
X					/* print the character */
X	waddstr(win, buf);
X	if (do_it)
X		wattroff(win, attr);
X#endif /* OLDCURSES */
X	return(0);
X}
X
X/*
X * Prompt for a Yes or No answer.  Echo the single key input as words.
X * Handle the funny cursor movement problems with magic cookie terminals.
X * Returns a 1 on yes.
X */
X
Xint
Xyes_prompt(win, y, x, attr, str)
XWINDOW *win;
Xint y, x, attr;
Xchar *str;
X{
X	int save, ret_code;
X	char new_str[80], *strcpy(), *strcat();
X					/* build and display the prompt */
X	strcpy(new_str, str);
X	strcat(new_str, "? (y/n):");
X	mvwattrstr(win, y, x, attr, new_str);
X	wmove(win, y, strlen(new_str)+x+2);
X	wrefresh(win);
X
X	ret_code = 0;
X	save = wgetch(win);
X	if (save == 'y' || save == 'Y') {
X		waddstr(win, "Yes");
X		ret_code = 1;
X	}
X	else
X		waddstr(win, "No");
X
X	wrefresh(win);
X	return(ret_code);
X}
X
X/*
X * Handy routine for clear-to-end-of-line.  Fixes up the box if requested.
X */
X
Xint
Xclear_line(win, y, x, re_box)
XWINDOW *win;
Xint y, x, re_box;
X{
X	if (wmove(win, y, x) == ERR)
X		return(ERR);
X
X	wclrtoeol(win);
X
X	if (re_box) {
X		mvwaddch(win, y, win->_maxx-1, '|');
X		wmove(win, y, x);
X	}
X	return(0);
X}
X
X/*
X * Wait for a key or time out.  Returns a -1 on timeout.
X */
X
Xjmp_buf wk_jmp;
X
Xint
Xwait_key(win, sec)
XWINDOW *win;
Xunsigned int sec;
X{
X	int c, force_wk();
X	unsigned int alarm();
X
X	signal(SIGALRM, force_wk);
X	if (setjmp(wk_jmp))
X		return(-1);
X	alarm(sec);
X	c = wgetch(win);
X	alarm(0);
X	return(c);
X}
Xint
Xforce_wk(dummy)
Xint dummy;
X{
X	void longjmp();
X
X	longjmp(wk_jmp, 1);
X}
X
X/*
X * Here are some routines that are probably missing from the older
X * flavors of curses(3)
X */
X
X#ifdef OLDCURSES
X/*
X * Make the terminal bell go off
X */
X
Xint
Xbeep()
X{
X	fputc(7, stderr);
X	return(0);
X}
X
X/*
X * Fix the stdin so that a read is satisfied immediately.  When read()
X * is called it returns the character in the queue, or an error if no
X * key was pressed.  The window argument is not used!
X */
X
Xint
Xnodelay(win, flag)
XWINDOW *win;
Xint flag;
X{
X	if (flag)
X		fcntl(0, F_SETFL, fcntl(0, F_GETFL, 0) | O_NDELAY);
X	else
X		fcntl(0, F_SETFL, fcntl(0, F_GETFL, 0) & ~O_NDELAY);
X	return(0);
X}
X
X/*
X * Take the terminal out of the "curses mode"
X */
X
Xint
Xresetterm()
X{
X	resetty();
X	return(0);
X}
X
X/*
X * Put the terminal back into the "curses mode"
X */
X
Xint
Xmyputchar(c)
Xchar c;
X{
X	putchar(c);
X}
Xint
Xfixterm()
X{
X	tputs(TI, 1, myputchar);
X	tputs(VS, 1, myputchar);
X	nonl();
X	crmode();
X	noecho();
X	return(0);
X}
X#endif /* OLDCURSES */
SHAR_EOF
if test 7649 -ne "`wc -c < 'curses.c'`"
then
	echo shar: "error transmitting 'curses.c'" '(should have been 7649 characters)'
fi
fi
echo shar: "extracting 'd_delete.c'" '(1987 characters)'
if test -f 'd_delete.c'
then
	echo shar: "will not over-write existing file 'd_delete.c'"
else
sed 's/^X//' << \SHAR_EOF > 'd_delete.c'
X/*
X * The delete option of the dialing directory.  Prompts for saving
X * changes to disk. A return code of 1 means that entries were deleted.
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include "dial_dir.h"
X#include "misc.h"
X#include "param.h"
X
Xint
Xdelete()
X{
X	WINDOW *d_win, *newwin();
X	int i, first, last;
X	void free_ptr();
X	extern char *null_ptr;
X	
X	d_win = newwin(6, 32, 10, 15);
X
X	mvwaddstr(d_win, 2, 2, "Delete entry:     thru:");
X	box(d_win, '|', '-');
X	wmove(d_win, 2, 16);
X	wrefresh(d_win);
X					/* get the first of the range */
X	while ((first = get_num(d_win, 3)) != -1) {
X		if (first > 0 && first <= NUM_DIR)
X			break;
X		mvwaddstr(d_win, 2, 16, "   ");
X		wmove(d_win, 2, 16);
X		beep();
X		wrefresh(d_win);
X	}
X	if (first == -1) {
X		delwin(d_win);
X		return(0);
X	}
X					/* get the last of the range */
X	wmove(d_win, 2, 26);
X	wrefresh(d_win);
X	while ((last = get_num(d_win, 3)) != -1) {
X		if ((first <= last && last <= NUM_DIR) || last == 0)
X			break;
X		mvwaddstr(d_win, 2, 26, "   ");
X		wmove(d_win, 2, 26);
X		beep();
X		wrefresh(d_win);
X	}
X	if (last == -1) {
X		delwin(d_win);
X		return(0);
X	}
X					/* if "last" omitted, echo "first" */
X	if (!last) {
X		last = first;
X		mvwprintw(d_win, 2, 26, "%d", first);
X		wrefresh(d_win);
X	}
X					/* save to disk? */
X	if (yes_prompt(d_win, 3, 2, A_BOLD, "Are you sure")) {
X					/* delete from the physical file */
X		if (del_dir(first, last)) {
X			touchwin(d_win);
X			wrefresh(d_win);
X		}
X		/*
X		 * We don't really care if del_dir() fails because we still
X		 * change the version in memory.
X		 */
X		for (i=first; i<=last; i++) {
X			free_ptr(dir->name[i]);
X			free_ptr(dir->number[i]);
X			free_ptr(dir->index[i]);
X			dir->name[i] = null_ptr;
X			dir->number[i] = null_ptr;
X			dir->baud[i] = param->d_baud;
X			dir->parity[i] = param->d_parity;
X			dir->dbits[i] = param->d_dbits;
X			dir->sbits[i] = param->d_sbits;
X			dir->duplex[i] = *param->d_duplex;
X			dir->index[i] = null_ptr;
X		}
X		delwin(d_win);
X		return(1);
X	}
X	delwin(d_win);
X	return(0);
X}
SHAR_EOF
if test 1987 -ne "`wc -c < 'd_delete.c'`"
then
	echo shar: "error transmitting 'd_delete.c'" '(should have been 1987 characters)'
fi
fi
echo shar: "extracting 'd_lib.c'" '(6469 characters)'
if test -f 'd_lib.c'
then
	echo shar: "will not over-write existing file 'd_lib.c'"
else
sed 's/^X//' << \SHAR_EOF > 'd_lib.c'
X/*
X * Routines to manipulate the dialing directory file pcomm.dial_dir
X */
X
X#include <stdio.h>
X#include "dial_dir.h"
X#include "param.h"
X#include "status.h"
X
X/*
X * Read the dialing directory.  Returns a pointer to a static area
X * containing the DIAL_DIR structure.  All of the entries are created
X * reguardless of the number of physical entries in the file.  Element
X * number zero is reserved for the "manual" entry.  All errors are fatal.
X */
X
Xstruct DIAL_DIR *
Xread_dir()
X{
X	FILE *fp;
X	int i, j, oops;
X	char *strdup(), buf[80], *temp_token, *str, *str_tok(), token[20];
X	char message[80], *sep;
X	static struct DIAL_DIR d;
X	void error_win();
X	extern char *null_ptr;
X
X	if (!(fp = fopen(status->d_path, "r"))) {
X		sprintf(buf, "'%s' for read", status->d_path);
X		error_win(1, "Can't open dialing directory file", buf);
X	}
X
X	sep = ";;---;;\n";
X	i = 0;
X	oops = 0;
X	while (fgets(buf, 80, fp) != NULL) {
X		i++;
X		if (i > NUM_DIR)
X			break;
X					/* get the token */
X		if (!(temp_token = str_tok(buf, '='))) {
X			sprintf(message, "is missing a token at line %d", i);
X			oops++;
X			break;
X		}
X		/*
X		 * Parse the rest of the line.  This is similar to using
X		 * the "real" strtok() function, but my version returns
X		 * a null pointer if the parameter is missing.  Note the
X		 * array of field separators.
X		 */
X		for (j=0; j<8; j++) {
X			if (!(str = str_tok((char *) NULL, sep[j]))) {
X				sprintf(message, "is missing a parameter at line %d", i);
X				oops++;
X				break;
X			}
X			switch(j) {
X				case 0:
X					d.name[i] = strdup(str);
X					break;
X				case 1:
X					d.number[i] = strdup(str);
X					break;
X				case 2:
X					d.baud[i] = atoi(str);
X					break;
X				case 3:
X					d.parity[i] = *str;
X					break;
X				case 4:
X					d.dbits[i] = atoi(str);
X					break;
X				case 5:
X					d.sbits[i] = atoi(str);
X					break;
X				case 6:
X					d.duplex[i] = *str;
X					break;
X				case 7:
X					d.index[i] = strdup(str);
X					break;
X			}
X		}
X		if (oops)
X			break;
X					/* sanity checking */
X		sprintf(token, "DIR_%d", i);
X		if (strcmp(temp_token, token)) {
X			sprintf(message, "is corrupted at line %d", i);
X			oops++;
X			break;
X		}
X	}
X	fclose(fp);
X
X	if (oops) {
X		sprintf(buf, "Directory file '%s'", status->d_path);
X		error_win(1, buf, message);
X	}
X	d.d_entries = i;
X					/* fill in the rest with defaults */
X	i++;
X	for (; i<=NUM_DIR; i++) {
X		d.name[i] = null_ptr;
X		d.number[i] = null_ptr;
X		d.baud[i] = param->d_baud;
X		d.parity[i] = param->d_parity;
X		d.dbits[i] = param->d_dbits;
X		d.sbits[i] = param->d_sbits;
X		d.duplex[i] = *param->d_duplex;
X		d.index[i] = null_ptr;
X	}
X					/* create an empty "manual" entry */
X	d.name[0] = null_ptr;
X	d.number[0] = null_ptr;
X	d.baud[0] = param->d_baud;
X	d.parity[0] = param->d_parity;
X	d.dbits[0] = param->d_dbits;
X	d.sbits[0] = param->d_sbits;
X	d.duplex[0] = *param->d_duplex;
X	d.index[0] = null_ptr;
X					/* create an empty queue */
X	for (i=0; i<NUM_QUEUE; i++) {
X		d.q_ld[i] = NULL;
X		d.q_num[i] = -1;
X	}
X					/* the startup d_cur is 0 */
X	d.d_cur = 0;
X	return(&d);
X}
X
X/*
X * Update a dialing directory entry.  Update only the one entry asked for,
X * not the entire image in memory.  If the new entry is beyond the end of
X * the physical file, then fill in the holes, and update "dir->d_entries".
X * A return code of 1 means a non-fatal error.
X */
X
Xint
Xupdate_dir(entry)
Xint entry;
X{
X	FILE *fp_in, *fp_out;
X	char *temp[NUM_DIR+1], buf[80], *strdup();
X	int i;
X	void error_win(), free_ptr();
X
X					/* open for read */
X	if (!(fp_in = fopen(status->d_path, "r"))) {
X		sprintf(buf, "'%s' for read", status->d_path);
X		error_win(1, "Can't open dialing directory file", buf);
X	}
X					/* read in a temporary version */
X	i = 0;
X	while (fgets(buf, 80, fp_in) != NULL)
X		temp[++i] = strdup(buf);
X	
X	fclose(fp_in);
X					/* alter only 1 entry */
X	sprintf(buf, "DIR_%d=%s;%s;%d-%c-%d-%d;%c;%s\n", entry,
X	 dir->name[entry], dir->number[entry], dir->baud[entry],
X	 dir->parity[entry], dir->dbits[entry], dir->sbits[entry],
X	 dir->duplex[entry], dir->index[entry]);
X
X	if (entry <= dir->d_entries)
X		free_ptr(temp[entry]);
X	temp[entry] = strdup(buf);
X					/* fill in holes if beyond end */
X	if (entry > dir->d_entries+1) {
X		for (i=dir->d_entries+1; i<entry; i++) {
X			sprintf(buf, "DIR_%d=;;%d-%c-%d-%d;%c;\n", i,
X			 param->d_baud, param->d_parity, param->d_dbits,
X			 param->d_sbits, *param->d_duplex);
X			temp[i] = strdup(buf);
X		}
X	}
X					/* update "dir->d_entries" */
X	if (entry > dir->d_entries)
X		dir->d_entries = entry;
X
X					/* open for read */
X	if (!(fp_out = fopen(status->d_path, "w"))) {
X		for (i=1; i<=dir->d_entries; i++)
X			free_ptr(temp[i]);
X		sprintf(buf, "'%s'", status->d_path);
X		error_win(0, "No write permission on directory file", buf);
X		return(1);
X	}
X					/* put it back */
X	for (i=1; i<=dir->d_entries; i++) {
X		fputs(temp[i], fp_out);
X		free_ptr(temp[i]);
X	}
X
X	fclose(fp_out);
X	return(0);
X}
X
X/*
X * Delete a range of dialing directory entries.  Actually, just copies
X * default (empty) entries in place of deleted entries.  However, it will
X * shrink the file if deletions occur at the physical EOF.  A return code
X * of 1 means a non-fatal error.
X */
X
Xint
Xdel_dir(first, last)
Xint first, last;
X{
X	FILE *fp_in, *fp_out;
X	int i;
X	char *temp[NUM_DIR+1], buf[80], *strdup();
X	void error_win(), free_ptr();
X					/* sanity checking */
X	if (first > dir->d_entries)
X		return(0);
X	if (last > dir->d_entries)
X		last = dir->d_entries;
X
X					/* open for read */
X	if (!(fp_in = fopen(status->d_path, "r"))) {
X		sprintf(buf, "'%s' for read", status->d_path);	
X		error_win(1, "Can't open dialing directory file", buf);
X	}
X					/* read in a temporary version */
X	i = 0;
X	while (fgets(buf, 80, fp_in) != NULL)
X		temp[++i] = strdup(buf);
X
X	fclose(fp_in);
X					/* delete the range of values */
X	for (i=first; i<=last; i++) {
X		sprintf(buf, "DIR_%d=;;%d-%c-%d-%d;%c;\n", i, param->d_baud,
X		 param->d_parity, param->d_dbits, param->d_sbits,
X		 *param->d_duplex);
X		free_ptr(temp[i]);
X		temp[i] = strdup(buf);
X	}
X					/* shrink the file? */
X	if (last >= dir->d_entries) {
X		for (i=first; i<=last; i++)
X			free_ptr(temp[i]);
X		dir->d_entries = first-1;
X	}
X					/* open for write */
X	if (!(fp_out = fopen(status->d_path, "w"))) {
X		for (i=1; i<=dir->d_entries; i++)
X			free_ptr(temp[i]);
X		sprintf(buf, "'%s'", status->d_path);
X		error_win(0, "No write permission on dialing directory file", buf);
X		return(1);
X	}
X					/* put it all back */
X	for (i=1; i<=dir->d_entries; i++) {
X		fputs(temp[i], fp_out);
X		free_ptr(temp[i]);
X	}
X
X	fclose(fp_out);
X	return(0);
X}
SHAR_EOF
if test 6469 -ne "`wc -c < 'd_lib.c'`"
then
	echo shar: "error transmitting 'd_lib.c'" '(should have been 6469 characters)'
fi
fi
echo shar: "extracting 'd_manual.c'" '(1757 characters)'
if test -f 'd_manual.c'
then
	echo shar: "will not over-write existing file 'd_manual.c'"
else
sed 's/^X//' << \SHAR_EOF > 'd_manual.c'
X/*
X * The manual dial option of the dialing directory.  A return code of
X * 1 means we're ready to dial.  Dialing directory entry 0 is reserved
X * for the manual dial option.  No sanity checking is done on the input.
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include "dial_dir.h"
X
Xint
Xmanual()
X{
X	WINDOW *m_win, *newwin();
X	char *number, *strdup(), *get_str(), ld_code, *strchr();
X	void fix_xmc(), free_ptr();
X	extern int xmc;
X	
X	m_win = newwin(5, 50, 0, 20);
X
X	box(m_win, '|', '-');
X	mvwaddstr(m_win, 2, 3, "Phone Number: ");
X	wrefresh(m_win);
X					/* get a phone number */
X	if ((number = get_str(m_win, 30, NULL, NULL)) == NULL) {
X		werase(m_win);
X		wrefresh(m_win);
X		delwin(m_win);
X		if (xmc > 0)
X			fix_xmc();
X		return(0);
X	}
X					/* is first char an LD code ? */
X	ld_code = NULL;
X	if (strchr("+-@#", *number)) {
X		ld_code = *number;
X		number++;
X	}
X					/* put it in the queue */
X	dir->q_ld[0] = ld_code;
X	dir->q_num[0] = 0;
X					/* end of queue marker */
X	dir->q_num[1] = -1;
X	dir->d_cur = 0;
X					/* build the entry zero */
X	free_ptr(dir->name[0]);
X	free_ptr(dir->number[0]);
X	dir->name[0] = strdup(number);
X	dir->number[0] = strdup(number);
X					/* it overlaps dm_win, so erase it */
X	werase(m_win);
X	wrefresh(m_win);
X	delwin(m_win);
X	if (xmc > 0)
X		fix_xmc();
X	return(1);
X}
X
X/*
X * Clear the end of the physical screen where the magic cookie got shifted
X * Geez, I hate magic cookie terminals...  Wyse, are you listening?
X */
X
Xvoid
Xfix_xmc()
X{
X	WINDOW *cl_win, *newwin();
X
X	/*
X	 * Since the cookie got shifted off the window, we have to
X	 * create a new window to cover where the cookie ended up.
X	 */
X	cl_win = newwin(1, 2, 4, 78);
X					/* have to touch, otherwise nothing! */
X	touchwin(cl_win);
X	wrefresh(cl_win);
X	delwin(cl_win);
X	
X	return;
X}
SHAR_EOF
if test 1757 -ne "`wc -c < 'd_manual.c'`"
then
	echo shar: "error transmitting 'd_manual.c'" '(should have been 1757 characters)'
fi
fi
echo shar: "extracting 'd_menu.c'" '(6870 characters)'
if test -f 'd_menu.c'
then
	echo shar: "will not over-write existing file 'd_menu.c'"
else
sed 's/^X//' << \SHAR_EOF > 'd_menu.c'
X/*
X * Routines for the dialing directory menu.
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include "dial_dir.h"
X#include "misc.h"
X#include "param.h"
X
X/*
X * Display the dialing directory and prompt for options.  A return code of
X * 1 means we're ready to dial.
X */
X
Xint
Xdial_menu()
X{
X	WINDOW *dm_win, *newwin();
X	char buf[5], ld_code;
X	int ans, start, current, needs_repair, count, x, y, i, ret_code;
X	void scroll_dir(), active_ld(), disp_ld(), print_dir();
X	extern int xmc;
X
X	dm_win = newwin(22, 78, 1, 1);
X	mvwattrstr(dm_win, 1, 20, A_BOLD, "D I A L I N G       D I R E C T O R Y");
X	waddstr(dm_win, "\n-----------------------------------------------------------------------------\n");
X	wattrstr(dm_win, A_STANDOUT, "           Name                   Number        Baud P D S Dpx  Index/tty    ");
X					/* show the first 10 entries */
X	scroll_dir(dm_win, 1);
X
X	mvwaddstr(dm_win, 15, 4, "==>");
X	mvwattrch(dm_win, 15, 14, A_BOLD, 'R');
X	waddstr(dm_win, " Revise");
X	mvwattrch(dm_win, 15, 32, A_BOLD, 'M');
X	waddstr(dm_win, " Manual Dialing");
X	mvwaddstr(dm_win, 15, 55, "Entry to Dial");
X
X	mvwattrch(dm_win, 16, 14, A_BOLD, 'P');
X	waddstr(dm_win, " LD Codes");
X	mvwattrch(dm_win, 16, 32, A_BOLD, 'D');
X	waddstr(dm_win, " Delete Entry");
X	mvwattrstr(dm_win, 16, 55, A_BOLD, "<cr>");
X	waddstr(dm_win, " Scroll Down");
X
X	mvwattrstr(dm_win, 17, 14, A_BOLD, "up/dn");
X	waddstr(dm_win, " Page");
X	mvwattrch(dm_win, 17, 32, A_BOLD, 'L');
X	waddstr(dm_win, " Print Entries");
X	mvwattrstr(dm_win, 17, 55, A_BOLD, "ESC");
X	waddstr(dm_win, " Exit");
X
X	mvwaddstr(dm_win, 19, 4, "LD Codes Active:");
X					/* show which LD codes are active */
X	active_ld(dm_win);
X
X	box(dm_win, '|', '-');
X	y = 15;
X	x = 8;
X	wmove(dm_win, 15, 8);
X	wrefresh(dm_win);
X#ifndef OLDCURSES
X	keypad(dm_win, 1);
X#endif /* OLDCURSES */
X					/* prompt for options */
X	current = 1;
X	count = 0;
X	ld_code = NULL;
X	ret_code = 0;
X	do {
X		needs_repair = 0;
X		ans = wgetch(dm_win);
X					/* get an entry number */
X		if (ans >= '0' && ans <= '9') {
X			if (count > 2) {
X				beep();
X				continue;
X			}
X			buf[count] = ans;
X			waddch(dm_win, ans);
X			wrefresh(dm_win);
X			count++;
X			continue;
X		}
X		switch (ans) {
X			case 8:		/* do our own backspace */
X				if (!count) {
X					beep();
X					break;
X				}
X				count--;
X				if (!count)
X					ld_code = NULL;
X				buf[count] = NULL;
X				getyx(dm_win, y, x);
X				x--;
X				wmove(dm_win, y, x);
X				waddch(dm_win, ' ');
X				wmove(dm_win, y, x);
X				wrefresh(dm_win);
X				break;
X#ifndef OLDCURSES
X			case KEY_UP:
X#endif /* OLDCURSES */
X			case 'u':
X			case 'U':	/* up arrow key */
X				if (current == 1) {
X					beep();
X					break;
X				}
X				start = current - 10;
X				if (start < 1)
X					start = 1;
X				current = start;
X				scroll_dir(dm_win, start);
X				break;
X#ifndef OLDCURSES
X			case KEY_DOWN:
X			case '\n':
X#endif /* OLDCURSES */
X			case 'n':
X			case 'N':	/* down arrow key */
X				if (current == NUM_DIR-9) {
X					beep();
X					break;
X				}
X				start = current + 10;
X				if (start > NUM_DIR-9)
X					start = NUM_DIR-9;
X				current = start;
X				scroll_dir(dm_win, start);
X				break;	
X			case '\r':	/* <CR> key */
X				if (!count) {
X					if (current == NUM_DIR-9) {
X						beep();
X						break;
X					}
X					current++;
X					if (current > NUM_DIR-9)
X						current = NUM_DIR-9;
X					scroll_dir(dm_win, current);
X				}
X				/*
X				 * The CR is used for the scroll-down-one-line
X				 * function, and to terminate numeric input.
X				 */
X				else {
X					buf[count] = NULL;
X					i = atoi(buf);
X					if (!i || i > NUM_DIR) {
X						beep();
X						mvwaddstr(dm_win, 15, 8, "   ");
X						x = 8;
X						count = 0;
X						break;
X					}
X					dir->q_ld[0] = ld_code;
X					dir->q_num[0] = i;
X					dir->d_cur = i;
X
X					/* end of queue marker */
X					dir->q_num[1] = -1;
X					
X					ret_code = 1;
X					break;
X				}
X				break;	
X			case 'r':
X			case 'R':	/* revise */
X				if (revise()) {
X					active_ld(dm_win);
X					scroll_dir(dm_win, current);
X				}
X				touchwin(dm_win);
X				break;
X			case 'p':	/* display LD codes */
X			case 'P':
X				disp_ld();
X				touchwin(dm_win);
X				needs_repair = 1;
X				break;
X			case 'd':
X			case 'D':	/* delete a range of entries */
X				if (delete())
X					scroll_dir(dm_win, current);
X				touchwin(dm_win);
X				break;
X			case 'm':
X			case 'M':	/* manual dial */
X				if (manual()) {
X					ret_code = 1;
X					break;
X				}
X				touchwin(dm_win);
X				needs_repair = 1;
X				break;
X			case 'l':
X			case 'L':	/* print the entries */
X				print_dir();
X				touchwin(dm_win);
X				needs_repair = 1;
X				break;
X			case '+':	/* LD codes */
X			case '-':
X			case '@':
X			case '#':
X				waddch(dm_win, ans);
X				wrefresh(dm_win);
X				ld_code = ans;
X				continue;
X			case 27:	/* ESC key (exit) */
X				break;
X			default:
X				beep();
X		}
X		if (ret_code)
X			break;
X					/* magic cookie terminal ? */
X		if (xmc > 0 && needs_repair) {
X			clear_line(dm_win, 1, 0, 0);
X			clear_line(dm_win, 3, 0, 0);
X			wrefresh(dm_win);
X			mvwattrstr(dm_win, 1, 20, A_BOLD, "D I A L I N G       D I R E C T O R Y");
X			mvwattrstr(dm_win, 3, 0, A_STANDOUT, "           Name                   Number        Baud P D S Dpx  Index/tty    ");
X			box(dm_win, '|', '-');
X		}
X		wmove(dm_win, y, x);
X		wrefresh(dm_win);
X	} while (ans != 27);
X
X	werase(dm_win);
X	wrefresh(dm_win);
X	delwin(dm_win);
X	return(ret_code);
X}
X
X/*
X * Scroll the dialing directory.  Actually, we're not doing a real scroll
X * function on the screen, we're just repainting 10 lines.
X */
X
Xvoid
Xscroll_dir(win, start)
XWINDOW *win;
Xint start;
X{
X	int i;
X
X	wmove(win, 4, 0);
X	for (i=start; i<start+10; i++)
X		wprintw(win,
X		 "%4d- %-20.20s %18.18s  %5d-%c-%d-%d  %c  %-14.14s\n", i,
X		 dir->name[i], dir->number[i], dir->baud[i], dir->parity[i],
X		 dir->dbits[i], dir->sbits[i], dir->duplex[i], dir->index[i]);
X	box(win, '|', '-');
X	return;
X}
X
X/*
X * Display the Long Distance codes.  Press any key to continue.
X */
X
Xvoid
Xdisp_ld()
X{
X	WINDOW *ld_win, *newwin();
X
X	ld_win = newwin(12, 30, 0, 0);
X	mvwaddstr(ld_win, 1, 5, "Long Distance Codes\n");
X	waddstr(ld_win, "------------------------------");
X	mvwprintw(ld_win, 3, 2, "+ %-20.20s", param->ld_plus);
X	mvwprintw(ld_win, 5, 2, "- %-20.20s", param->ld_minus);
X	mvwprintw(ld_win, 7, 2, "@ %-20.20s", param->ld_at);
X	mvwprintw(ld_win, 9, 2, "# %-20.20s", param->ld_pound);
X	box(ld_win, '|', '-');
X
X	mvwaddstr(ld_win, 11, 8, " Press any key ");
X	wmove(ld_win, 11, 29);
X	wrefresh(ld_win);
X	wgetch(ld_win);
X					/* it overlaps, so erase it */
X	werase(ld_win);
X	wrefresh(ld_win);
X	delwin(ld_win);
X	return;
X}
X
X/*
X * Display which of the Long Distance codes are active.
X */
X
Xvoid
Xactive_ld(win)
XWINDOW *win;
X{
X	mvwaddstr(win, 19, 21, "        ");
X	wmove(win, 19, 21);
X					/* a NULL pointer means not active */
X	if (*param->ld_plus != NULL)
X		waddstr(win, "+ ");
X	if (*param->ld_minus != NULL)
X		waddstr(win, "- ");
X	if (*param->ld_at != NULL)
X		waddstr(win, "@ ");
X	if (*param->ld_pound != NULL)
X		waddstr(win, "# ");
X	return;
X}
SHAR_EOF
if test 6870 -ne "`wc -c < 'd_menu.c'`"
then
	echo shar: "error transmitting 'd_menu.c'" '(should have been 6870 characters)'
fi
fi
exit 0
#	End of shell archive

egray@fthood.UUCP (03/13/88)

This is part 3 (of 6) to the Pcomm version 1.0 distribution.

Emmet P. Gray				US Army, HQ III Corps & Fort Hood
...!ihnp4!uiucuxc!fthood!egray		Attn: AFZF-DE-ENV
					Directorate of Engineering & Housing
					Environmental Management Office
					Fort Hood, TX 76544-5057

-------------------------------------------------------------------------------
#! /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:
#	d_print.c
#	d_prompt.c
#	d_revise.c
#	data_log.c
#	di_delay.c
#	di_win.c
#	dial.c
#	expand.c
#	getcwd.c
#	getopt.c
#	help.c
#	info.c
#	init.c
# This archive created: Fri Mar 11 07:35:10 1988
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'd_print.c'" '(3497 characters)'
if test -f 'd_print.c'
then
	echo shar: "will not over-write existing file 'd_print.c'"
else
sed 's/^X//' << \SHAR_EOF > 'd_print.c'
X/*
X * The print option of the dialing directory.  A carriage return will
X * send the dialing directory to the print spool program, otherwise the
X * selected file will be used.
X */
X
X#define LPRINT "/usr/bin/lprint"
X
X#include <stdio.h>
X#include <curses.h>
X#include "dial_dir.h"
X#include "misc.h"
X
Xvoid
Xprint_dir()
X{
X	FILE *fp, *popen();
X	WINDOW *p_win, *newwin();
X	char *file, *get_str_erase(), buf[80];
X	int is_printer, i, can;
X	void error_win();
X	unsigned int sleep();
X	
X	p_win = newwin(5, 54, 0, 26);
X
X	mvwaddstr(p_win, 2, 3, "Print to: (printer)");
X	box(p_win, '|', '-');
X	wmove(p_win, 2, 13);
X	wrefresh(p_win);
X
X	/*
X	 * This is a special version of get_str() that looks at the
X	 * first character to see if it should erase the default answer
X	 * already on the screen.
X	 */
X	if ((file = get_str_erase(p_win, 40)) == NULL) {
X					/* erase because it overlaps dm_win */
X		werase(p_win);
X		wrefresh(p_win);
X		delwin(p_win);
X		return;
X	}
X	is_printer = 0;
X					/* the default (printer) */
X	if (*file == NULL) {
X		if (!(fp = popen(LPRINT, "w"))) {
X			sprintf(buf, "'%s'", LPRINT);
X			error_win(0, "Can't open printer device", buf);
X			werase(p_win);
X			wrefresh(p_win);
X			delwin(p_win);
X			return;
X		}
X		is_printer = 1;
X	}
X					/* the requested file */
X	else {
X		/*
X		 * Check to see if the file already exists (and if we
X		 * have write permission too).  Currently only allows
X		 * you to bail out or overwrite the file.
X		 */
X		if (!(can = can_write(file))) {
X			sprintf(buf, "'%s'", file);
X			error_win(0, "No write permission on file", buf);
X			werase(p_win);
X			wrefresh(p_win);
X			delwin(p_win);
X			return;
X		}
X		if (can == 2) {
X			werase(p_win);
X			mvwprintw(p_win, 2, 3, "File '%s' already exists!", file);
X			beep();
X			box(p_win, '|', '-');
X			if (!yes_prompt(p_win, 3, 3, A_BOLD, "Overwrite")) {
X				werase(p_win);
X				wrefresh(p_win);
X				delwin(p_win);
X				return;
X			}
X		}
X			
X		fp = fopen(file, "w");
X	}
X	
X	werase(p_win);
X	mvwaddstr(p_win, 2, 13, "Printing pcomm directory");
X	box(p_win, '|', '-');
X	wrefresh(p_win);
X
X	/*
X	 * Only prints up to the end of the physical file, not the entire
X	 * structure.  I gave some thought about not printing empty entries,
X	 * but...
X	 */
X	for (i=1; i<=dir->d_entries; i++)
X		fprintf(fp, "%4d- %-20.20s %18.18s  %5d-%c-%d-%d  %c  %-14.14s\n",
X		 i, dir->name[i], dir->number[i], dir->baud[i], dir->parity[i],
X		 dir->dbits[i], dir->sbits[i], dir->duplex[i], dir->index[i]);
X
X	if (is_printer)
X		pclose(fp);
X	else {
X					/* a dramatic delay... */
X		sleep(1);
X		fclose(fp);
X	}
X
X	werase(p_win);
X	wrefresh(p_win);
X	delwin(p_win);
X	return;
X}
X
X/*
X * Get a string from a window but erase the line first.
X */
X
Xchar *
Xget_str_erase(win, num)
XWINDOW *win;
Xint num;
X{
X	int count, x, y, done_it;
X	char ans;
X	static char buf[80];
X
X	done_it = 0;
X	count = 0;
X	while ((ans = wgetch(win)) != '\r') {
X					/* do our own backspace */
X		if (ans == 8) {
X			if (!count) {
X				beep();
X				continue;
X			}
X			count--;
X			buf[count] = NULL;
X			getyx(win, y, x);
X			x--;
X			wmove(win, y, x);
X			waddch(win, ' ');
X			wmove(win, y, x);
X			wrefresh(win);
X			continue;
X		}
X					/* exceeded the max ? */
X		if (count == num) {
X			beep();
X			continue;
X		}
X					/* an ESC anywhere in the string */
X		if (ans == 27)
X			return(NULL);
X					/* erase the default answer */
X		if (!done_it) {
X			waddstr(win, "         ");
X			wmove(win, 2, 13);
X			wrefresh(win);
X			done_it = 1;
X		}
X
X		buf[count] = ans;
X		waddch(win, ans);
X		wrefresh(win);
X		count++;
X	}
X	buf[count] = NULL;
X	return(buf);
X}
SHAR_EOF
if test 3497 -ne "`wc -c < 'd_print.c'`"
then
	echo shar: "error transmitting 'd_print.c'" '(should have been 3497 characters)'
fi
fi
echo shar: "extracting 'd_prompt.c'" '(5941 characters)'
if test -f 'd_prompt.c'
then
	echo shar: "will not over-write existing file 'd_prompt.c'"
else
sed 's/^X//' << \SHAR_EOF > 'd_prompt.c'
X/*
X * Prompt for directory entry changes.  Copies the original values in
X * case you change your mind half way thru.  A return code of 1 means
X * the entry was changed.
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include "dial_dir.h"
X#include "misc.h"
X
Xint
Xprompt_lib(win, i)
XWINDOW *win;
Xint i;
X{
X	int n, baud, dbits, sbits, spot;
X	static int valid_baud[6] = {300, 1200, 2400, 4800, 9600, 19200};
X	static char *valid_parity[3] = {"Even", "Odd", "None"};
X	char *ans, *get_str(), c, temp, *name, *number, *index, parity;
X	char duplex, *strdup(), buf[40];
X	void free_ptr();
X	extern int xmc;
X	extern char *null_ptr;
X					/* make copies */
X	name = strdup(dir->name[i]);
X	number = strdup(dir->number[i]);
X	baud = dir->baud[i];
X	parity = dir->parity[i];
X	dbits = dir->dbits[i];
X	sbits = dir->sbits[i];
X	duplex = dir->duplex[i];
X	index = strdup(dir->index[i]);
X					/* display original values */
X	werase(win);
X	mvwprintw(win, 2, 5, "%-20.20s %18.18s  %5d-%c-%d-%d  %c  %-14.14s\n",
X	 dir->name[i], dir->number[i], dir->baud[i], dir->parity[i],
X	 dir->dbits[i], dir->sbits[i], dir->duplex[i], dir->index[i]);
X	box(win, '|', '-');
X
X					/* prompt for name */
X	mvwaddstr(win, 4, 4, "Name: ");
X	wrefresh(win);
X
X	if ((ans = get_str(win, 20, NULL, ";")) == NULL)
X		return(0);
X	if (*ans != NULL) {
X		if (!strcmp(ans, " "))
X			name = null_ptr;
X		else
X			name = strdup(ans);
X		mvwaddstr(win, 2, 5, "                    ");
X		wrefresh(win);
X		mvwattrstr(win, 2, 5, A_BOLD, name);
X	}
X					/* prompt for number */
X	clear_line(win, 4, 4, 1);
X	waddstr(win, "Number: ");
X	wrefresh(win);
X
X	if ((ans = get_str(win, 18, NULL, ";")) == NULL)
X		return(0);
X	if (*ans != NULL) {
X		if (!strcmp(ans, " "))
X			number = null_ptr;
X		else
X			number = strdup(ans);
X		mvwaddstr(win, 2, 26, "                  ");
X		wrefresh(win);
X		/*
X		 * Should be right justified, but we don't wanna to have
X		 * the attribute turned on for blanks.
X		 */
X		spot = 26 + 18 - strlen(number);
X		mvwattrstr(win, 2, spot, A_BOLD, number);
X	}
X					/* template for next few */
X	clear_line(win, 4, 4, 1);
X	mvwaddstr(win, 4, 31, "(Any key to change, <CR> to accept)");
X
X	/*
X	 * These next few prompts display a series of choices and allow
X	 * the user to hit a return to accept the currently showing
X	 * value.  The first value displayed is always the current value.
X	 */
X					/* choose from baud menu */
X	for (n=0; n<6; n++) {
X		if (valid_baud[n] == baud)
X			break;
X	}
X	mvwprintw(win, 4, 4, "Baud: %-5d", valid_baud[n]);
X	wmove(win, 4, 10);
X	wrefresh(win);
X
X	while ((c = wgetch(win)) != '\r') {
X		if (c == 27)
X			return(0);
X		n = (n == 5) ? 0 : n+1;
X		mvwprintw(win, 4, 4, "Baud: %-5d", valid_baud[n]);
X		wmove(win, 4, 10);
X		wrefresh(win);
X	}
X	if (baud != valid_baud[n]) {
X		baud = valid_baud[n];
X		sprintf(buf, "%5d", baud);
X		if (xmc > 0) {
X			sprintf(buf, "%5d-%c-%d-%d", baud, parity, dbits, sbits);
X			mvwaddstr(win, 2, 46, "           ");
X			wrefresh(win);
X		}
X		mvwattrstr(win, 2, 46, A_BOLD, buf);
X	}
X					/* choose from parity menu */
X	for (n=0; n<3; n++) {
X		if (*valid_parity[n] == parity)
X			break;
X	}
X	mvwprintw(win, 4, 4, "Parity: %-5.5s", valid_parity[n]);
X	wmove(win, 4, 12);
X	wrefresh(win);
X
X	while ((c = wgetch(win)) != '\r') {
X		if (c == 27)
X			return(0);
X		n = (n == 2) ? 0 : n+1;
X		mvwprintw(win, 4, 4, "Parity: %-5.5s", valid_parity[n]);
X		wmove(win, 4, 12);
X		wrefresh(win);
X	}
X	if (parity != *valid_parity[n]) {
X		parity = *valid_parity[n];
X		if (xmc > 0) {
X			sprintf(buf, "%5d-%c-%d-%d", baud, parity, dbits, sbits);
X			mvwaddstr(win, 2, 46, "           ");
X			wrefresh(win);
X			mvwattrstr(win, 2, 46, A_BOLD, buf);
X		}
X		else
X			mvwattrch(win, 2, 52, A_BOLD, parity);
X	}
X					/* choose from data bits menu */
X	n = dbits;
X	mvwprintw(win, 4, 4, "Data Bits: %d    ", n);
X	wmove(win, 4, 15);
X	wrefresh(win);
X
X	while ((c = wgetch(win)) != '\r') {
X		if (c == 27)
X			return(0);
X		n = (n == 8) ? 7 : 8;
X		mvwprintw(win, 4, 4, "Data Bits: %d    ", n);
X		wmove(win, 4, 15);
X		wrefresh(win);
X	}
X	if (dbits != n) {
X		dbits = n;
X		if (xmc > 0) {
X			sprintf(buf, "%5d-%c-%d-%d", baud, parity, dbits, sbits);
X			mvwaddstr(win, 2, 46, "           ");
X			wrefresh(win);
X			mvwattrstr(win, 2, 46, A_BOLD, buf);
X		}
X		else
X			mvwattrnum(win, 2, 54, A_BOLD, dbits);
X	}
X					/* choose from stop bits menu */
X	n = sbits;
X	mvwprintw(win, 4, 4, "Stop Bits: %d    ", n);
X	wmove(win, 4, 15);
X	wrefresh(win);
X
X	while ((c = wgetch(win)) != '\r') {
X		if (c == 27)
X			return(0);
X		n = (n == 2) ? 1 : 2;
X		mvwprintw(win, 4, 4, "Stop Bits: %d    ", n);
X		wmove(win, 4, 15);
X		wrefresh(win);
X	}
X	if (sbits != n) {
X		sbits = n;
X		if (xmc > 0) {
X			sprintf(buf, "%5d-%c-%d-%d", baud, parity, dbits, sbits);
X			mvwaddstr(win, 2, 46, "           ");
X			wrefresh(win);
X			mvwattrstr(win, 2, 46, A_BOLD, buf);
X		}
X		else
X			mvwattrnum(win, 2, 56, A_BOLD, sbits);
X	}
X					/* choose from duplex menu */
X	temp = duplex;
X	mvwprintw(win, 4, 4, "Duplex: %c    ", temp);
X	wmove(win, 4, 12);
X	wrefresh(win);
X
X	while ((c = wgetch(win)) != '\r') {
X		if (c == 27)
X			return(0);
X		temp = (temp == 'F') ? 'H' : 'F';
X		mvwprintw(win, 4, 4, "Duplex: %c    ", temp);
X		wmove(win, 4, 12);
X		wrefresh(win);
X	}
X	if (duplex != temp) {
X		duplex = temp;
X		mvwattrch(win, 2, 59, A_BOLD, duplex);
X	}
X					/* prompt for command line index */
X	clear_line(win, 4, 4, 1);
X	waddstr(win, "Command line index (or tty): ");
X	wrefresh(win);
X
X	if ((ans = get_str(win, 14, NULL, ";")) == NULL)
X		return(0);
X	if (*ans != NULL) {
X		if (!strcmp(ans, " "))
X			index = null_ptr;
X		else
X			index = strdup(ans);
X		mvwattrstr(win, 2, 62, A_BOLD, index);
X	}
X					/* store 'em for real */
X	free_ptr(dir->name[i]);
X	free_ptr(dir->number[i]);
X	free_ptr(dir->index[i]);
X
X	dir->name[i] = strdup(name);
X	dir->number[i] = strdup(number);
X	dir->baud[i] = baud;
X	dir->parity[i] = parity;
X	dir->dbits[i] = dbits;
X	dir->sbits[i] = sbits;
X	dir->duplex[i] = duplex;
X	dir->index[i] = strdup(index);
X
X	free_ptr(name);
X	free_ptr(number);
X	free_ptr(index);
X	return(1);
X}
SHAR_EOF
if test 5941 -ne "`wc -c < 'd_prompt.c'`"
then
	echo shar: "error transmitting 'd_prompt.c'" '(should have been 5941 characters)'
fi
fi
echo shar: "extracting 'd_revise.c'" '(3971 characters)'
if test -f 'd_revise.c'
then
	echo shar: "will not over-write existing file 'd_revise.c'"
else
sed 's/^X//' << \SHAR_EOF > 'd_revise.c'
X/*
X * The revise option of the dialing directory.  A return code of 1 means
X * that something was updated.  Prompts for saving changes to disk.
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include "dial_dir.h"
X#include "misc.h"
X#include "param.h"
X
Xint
Xrevise()
X{
X	WINDOW *r_win, *newwin();
X	int count, dir_flag, param_flag, num, x, y, save;
X	char ans, buf[40], *ld, *prompt_ld(), *strdup();
X	void free_ptr();
X	
X	r_win = newwin(7, 77, 7, 2);
X
X	mvwaddstr(r_win, 3, 6, "Entry to revise?");
X	mvwaddstr(r_win, 3, 35, "(Entry Number, +, -, @, #)");
X	box(r_win, '|', '-');
X	wmove(r_win, 3, 23);
X	wrefresh(r_win);
X
X	dir_flag = 0;
X	param_flag = 0;
X	count = 0;
X
X	/*
X	 * Can't use my home-grown get_str() and get_num() functions
X	 * here, because we are prompting for an entry number or a
X	 * long distance code.  This routine echoes numbers only.
X	 */
X	while ((ans = wgetch(r_win)) != 27) {
X		if (ans >= '0' && ans <= '9') {
X			if (count == 3) {
X				beep();
X				continue;
X			}
X			buf[count] = ans;
X			waddch(r_win, ans);
X			wrefresh(r_win);
X			count++;
X			continue;
X		}
X					/* terminating <CR> */
X		if (ans == '\r') {
X			if (!count) {
X				beep();
X				continue;
X			}
X			buf[count] = NULL;
X			num = atoi(buf);
X					/* valid range of numbers? */
X			if (num == 0 || num > NUM_DIR) {
X				beep();
X				mvwaddstr(r_win, 3, 23, "   ");
X				wmove(r_win, 3, 23);
X				wrefresh(r_win);
X				count = 0;
X				continue;
X			}
X					/* prompt for that entry */
X			if (prompt_lib(r_win, num)) {
X				dir_flag++;
X				break;
X			}
X			delwin(r_win);
X			return(0);
X		}
X					/* do our own backspace */
X		if (ans == 8) {
X			if (!count) {
X				beep();
X				continue;
X			}
X			count--;
X			buf[count] = NULL;
X			getyx(r_win, y, x);
X			x--;
X			wmove(r_win, y, x);
X			waddch(r_win, ' ');
X			wmove(r_win, y, x);
X			wrefresh(r_win);
X			continue;
X		}
X					/* non-number after number is error */
X		if (count) {
X			beep();
X			continue;
X		}
X					/* prompt for LD codes */
X		switch (ans) {
X			case '+':
X				if ((ld = prompt_ld(r_win, param->ld_plus, ans)) != NULL) {
X					free_ptr(param->ld_plus);
X					param->ld_plus = strdup(ld);
X					param_flag++;
X				}
X				break;
X			case '-':
X				if ((ld = prompt_ld(r_win, param->ld_minus, ans)) != NULL) {
X					free_ptr(param->ld_minus);
X					param->ld_minus = strdup(ld);
X					param_flag++;
X				}
X				break;
X			case '@':
X				if ((ld = prompt_ld(r_win, param->ld_at, ans)) != NULL) {
X					free_ptr(param->ld_at);
X					param->ld_at = strdup(ld);
X					param_flag++;
X				}
X				break;
X			case '#':
X				if ((ld = prompt_ld(r_win, param->ld_pound, ans)) != NULL) {
X					free_ptr(param->ld_pound);
X					param->ld_pound = strdup(ld);
X					param_flag++;
X				}
X				break;
X			default:
X				beep();
X				continue;
X		}
X		break;
X	}
X					/* if nothing changed */
X	if (!param_flag && !dir_flag) {
X		delwin(r_win);
X		return(0);
X	}
X					/* save to disk ? */
X	clear_line(r_win, 4, 4, 1);
X	if (dir_flag) {
X		sprintf(buf, "Save entry %d to disk", num);
X		save = yes_prompt(r_win, 4, 4, A_BOLD, buf);
X	}
X	else
X		save = yes_prompt(r_win, 4, 4, A_BOLD, "Save to disk");
X
X					/* update the files */
X	if (save && dir_flag) {
X		if (update_dir(num)) {
X			touchwin(r_win);
X			wrefresh(r_win);
X		}
X	}
X	if (save && param_flag) {
X		if (update_param()) {
X			touchwin(r_win);
X			wrefresh(r_win);
X		}
X	}
X	delwin(r_win);
X	return(1);
X}
X
X/*
X * Prompt for long distance code changes.  If new string is a space,
X * change it to a null pointer.  Returns the new value or NULL on escape.
X */
X
Xchar *
Xprompt_ld(win, current_ld, name)
XWINDOW *win;
Xchar *current_ld, name;
X{
X	char *ans, *get_str();
X	extern char *null_ptr;
X
X	werase(win);
X	mvwprintw(win, 2, 4, "%-20.20s", current_ld);
X	mvwprintw(win, 4, 4, "New LD code for %c: ", name);
X	box(win, '|', '-');
X	wrefresh(win);
X
X	if ((ans = get_str(win, 20, NULL, NULL)) == NULL)
X		return(NULL);
X					/* if space, change to NULL pointer */
X	if (!strcmp(ans, " "))
X		ans = null_ptr;
X					/* display new value */
X	clear_line(win, 2, 4, 1);
X	wattrstr(win, A_BOLD, ans);
X
X	return(ans);
X}
SHAR_EOF
if test 3971 -ne "`wc -c < 'd_revise.c'`"
then
	echo shar: "error transmitting 'd_revise.c'" '(should have been 3971 characters)'
fi
fi
echo shar: "extracting 'data_log.c'" '(1840 characters)'
if test -f 'data_log.c'
then
	echo shar: "will not over-write existing file 'data_log.c'"
else
sed 's/^X//' << \SHAR_EOF > 'data_log.c'
X/*
X * Open a window to prompt for a path name to be used for the data logging
X * feature.  Turns on the data logging by killing the input routine and
X * restarting it.  A return code of 1 means we need to restart the input
X * routine.
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include "misc.h"
X#include "param.h"
X#include "status.h"
X
Xint
Xdata_logging(fd)
Xint fd;
X{
X	int ret_code;
X	WINDOW *dl_win, *newwin();
X	char *ans, *path, *expand(), *get_str(), *strdup();
X	void input_off(), free_ptr();
X	extern char *null_ptr;
X
X	dl_win = newwin(6, 70, 5, 5);
X
X	mvwprintw(dl_win, 2, 4, "Default log file: %s", param->logfile);
X	mvwaddstr(dl_win, 3, 4, "New log file: ");
X	box(dl_win, '|', '-');
X
X	mvwattrstr(dl_win, 0, 3, A_BOLD, " Start Data Logging ");
X	wmove(dl_win, 3, 18);
X	wrefresh(dl_win);
X					/* get the path */
X	ret_code = 0;
X	path = null_ptr;
X	while ((ans = get_str(dl_win, 60, NULL, " 	")) != NULL) {
X					/* give 'em the default */
X		if (*ans == NULL)
X			path = strdup(param->logfile);
X		else
X			path = expand(ans);
X
X					/* test write permission */
X		if (can_write(path)) {
X			ret_code++;
X			break;
X		}
X
X		beep();
X		mvwattrstr(dl_win, 4, 24, A_BOLD, "No write permission");
X		wrefresh(dl_win);
X		wait_key(dl_win, 3);
X					/* cleanup the mess */
X		clear_line(dl_win, 3, 18, 1);
X		clear_line(dl_win, 4, 24, 1);
X		wmove(dl_win, 3, 18);
X		wrefresh(dl_win);
X	}
X	if (ret_code) {
X		/*
X		 * Killing and then restarting the input routine is the
X		 * only way to change the name of the file that the input
X		 * routines uses.  It also assures that the 'status->log'
X		 * flag is in sync with the flag in the input routine.
X		 */
X		input_off();
X		status->log = 1;
X		free_ptr(status->log_path);
X		status->log_path = strdup(path);
X	}
X	if (fd == -1) {
X		werase(dl_win);
X		wrefresh(dl_win);
X	}
X	delwin(dl_win);
X
X	free_ptr(path);
X	return(ret_code);
X}
SHAR_EOF
if test 1840 -ne "`wc -c < 'data_log.c'`"
then
	echo shar: "error transmitting 'data_log.c'" '(should have been 1840 characters)'
fi
fi
echo shar: "extracting 'di_delay.c'" '(1941 characters)'
if test -f 'di_delay.c'
then
	echo shar: "will not over-write existing file 'di_delay.c'"
else
sed 's/^X//' << \SHAR_EOF > 'di_delay.c'
X/*
X * Prompt for new delay times during a dialing session.  Also, prompts
X * if changes should be saved to disk.  Dialing is suspended during
X * this routine.
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include "misc.h"
X#include "param.h"
X
Xvoid
Xdelay_times()
X{
X	WINDOW *dt_win, *newwin();
X	int cdelay, pause;
X
X	dt_win = newwin(9, 45, 7, 15);
X
X	mvwprintw(dt_win, 2, 4, "Current carrier delay time: %d", param->cdelay);
X	mvwprintw(dt_win, 3, 4, "Current pause between redials: %d", param->pause);
X	mvwaddstr(dt_win, 5, 4, "New carrier delay: ");
X	mvwaddstr(dt_win, 6, 4, "New pause time: ");
X	box(dt_win, '|', '-');
X
X	mvwattrstr(dt_win, 0, 3, A_BOLD, " Change delay times ");
X	wmove(dt_win, 5, 23);
X	wrefresh(dt_win);
X					/* get the cdelay number */
X	if ((cdelay = get_num(dt_win, 3)) == -1) {
X		delwin(dt_win);
X		return;
X	}
X					/* give 'em the current settings */
X	if (!cdelay) {
X		cdelay = param->cdelay;
X		wprintw(dt_win, "%-3d", cdelay);
X	}
X	else {
X					/* some reasonable limit */
X		if (cdelay > MAX_CDELAY || cdelay < MIN_CDELAY) {
X			beep();
X			if (cdelay > MAX_CDELAY)
X				cdelay = MAX_CDELAY;
X			else
X				cdelay = MIN_CDELAY;
X			mvwprintw(dt_win, 5, 23, "%-3d", cdelay);
X		}
X	}
X					/* get the pause number */
X	wmove(dt_win, 6, 20);
X	wrefresh(dt_win);
X	if ((pause = get_num(dt_win, 3)) == -1) {
X		delwin(dt_win);
X		return;
X	}
X					/* give 'em the current settings */
X	if (!pause) {
X		pause = param->pause;
X		wprintw(dt_win, "%-3d", pause);
X	}
X	else {
X					/* some reasonable limit */
X		if (pause > MAX_PAUSE || pause < MIN_PAUSE) {
X			beep();
X			if (pause > MAX_PAUSE)
X				pause = MAX_PAUSE;
X			else
X				pause = MIN_PAUSE;
X			mvwprintw(dt_win, 6, 20, "%-3d", pause);
X		}
X	}
X					/* set 'em */
X	param->cdelay = cdelay;
X	param->pause = pause;
X					/* save 'em to disk ? */
X	if (yes_prompt(dt_win, 7, 12, A_BOLD, "Save to disk")) {
X		if (update_param()) {
X			touchwin(dt_win);
X			wrefresh(dt_win);
X		}
X	}
X
X	delwin(dt_win);
X	return;
X}
SHAR_EOF
if test 1941 -ne "`wc -c < 'di_delay.c'`"
then
	echo shar: "error transmitting 'di_delay.c'" '(should have been 1941 characters)'
fi
fi
echo shar: "extracting 'di_win.c'" '(9254 characters)'
if test -f 'di_win.c'
then
	echo shar: "will not over-write existing file 'di_win.c'"
else
sed 's/^X//' << \SHAR_EOF > 'di_win.c'
X/*
X * The dialing window routines.
X */
X
X#define MAX_PASS 25
X
X#include <stdio.h>
X#include <curses.h>
X#include <signal.h>
X#include <setjmp.h>
X#include "dial_dir.h"
X#include "misc.h"
X#include "modem.h"
X#include "param.h"
X#include "status.h"
X
X/*
X * The dialing window.  Its job is to kill the input routine, get a port,
X * cycle thru the entries in the queue, while interpreting both the
X * user's requests and the modem's responses.  A return code of 1 means
X * we're ready to fire up the input mode.
X */
X
Xint
Xdial_win()
X{
X	WINDOW *di_win, *newwin();
X	int i, j, ans, want_out, pass, tic, baud, modem_sync;
X	long now, time();
X	char *tbuf, *ctime(), *str, cr=13, *monitor_dial();
X	void disp_queue(), send_str(), dial_it(), delay_times(), input_off();
X	void error_win(), status_line(), line_set(), hang_up();
X	extern int rc_index;
X	unsigned int sleep();
X					/* are we already talking? */
X	input_off();
X	hang_up(1);
X
X	if (get_port())
X		return(0);
X	/*
X	 * If the phone number is a NULL, then either we are on a
X	 * direct line, or you want to do the dialing yourself.
X	 */
X	if (*dir->number[dir->q_num[0]] == NULL) {
X					/* check LD permission */
X		if (limit_ld(0))
X			return(0);
X					/* can't talk directly to OBM */
X		if (!strcmp(modem->mname[modem->m_cur], "OBM")) {
X			error_win(0, "Can't access the line directly.", "Use the automatic dialing feature");
X			return(0);
X		}
X		unlink(status->vs_path);
X		touchwin(stdscr);
X		clear();
X		printw("Connected to %s at %d baud...\n", modem->tty[modem->t_cur], dir->baud[dir->d_cur]);
X		refresh();
X		return(1);
X	}
X
X	di_win = newwin(17, 70, 3, 5);
X					/* the basic window */
X	mvwattrstr(di_win, 1, 20, A_BOLD, "D I A L I N G       W I N D O W");
X	mvwaddstr(di_win, 2, 0, "---------------------------------------------------------------------");
X	mvwaddstr(di_win, 4, 23, "System name:");
X	mvwaddstr(di_win, 5, 23, "Pass number:");
X	mvwaddstr(di_win, 6, 14, "Elapse time this try:");
X	mvwaddstr(di_win, 7, 13, "Time at start of dial:");
X	mvwaddstr(di_win, 8, 9, "Time at start of this try:");
X	mvwaddstr(di_win, 9, 16, "Connect delay time:");
X	mvwaddstr(di_win, 10, 15, "Pause between tries:");
X	mvwaddstr(di_win, 11, 25, "Index/tty:");
X	mvwaddstr(di_win, 12, 16, "Result of last try:");
X
X	mvwaddstr(di_win, 14, 3, "SPACE: Recycle");
X	mvwaddstr(di_win, 14, 21, "DEL: Remove from queue");
X	mvwaddstr(di_win, 14, 46, "E: Change delay times");
X
X					/* the start time */
X	time(&now);
X	tbuf = ctime(&now);
X	tbuf[19] = NULL;
X	mvwaddstr(di_win, 7, 36, &tbuf[11]);
X
X	mvwprintw(di_win, 9, 36, "%-4d", param->cdelay);
X	mvwprintw(di_win, 10, 36, "%-4d", param->pause);
X
X	box(di_win, '|', '-');
X	mvwaddstr(di_win, 16, 25, " Press ESC to abort ");
X
X	pass = 0;
X	i = 0;
X	want_out = 0;
X	while (!want_out && pass <= MAX_PASS) {
X		ans = -1;
X		pass++;
X					/* update the d_cur variable */
X		dir->d_cur = dir->q_num[i];
X					/* check LD permission */
X		if (limit_ld(i))
X			return(0);
X					/* get a port */
X		if (get_port())
X			return(0);
X					/* can the modem sync baud rates ? */
X		modem_sync = can_sync();
X					/* fill in the window */
X		disp_queue(di_win, dir->d_cur, pass);
X
X		/*
X		 * The actual dial routine. The 'i' is the index into the
X		 * queue, not the entry number.  Returns immediately without
X		 * waiting for a carrier.
X		 */
X		dial_it(i);
X		ioctl(status->fd, TCFLSH, 0);
X
X		/*
X		 * Here we do a time-slice between reading the result codes
X		 * from the modem and reading the keyboard.  The one second
X		 * granularity won't be too accurate, but who cares?
X		 */
X		tic = 0;
X		rc_index = 0;
X		while (tic < param->cdelay) {
X			if (!(str = monitor_dial())) {
X				mvwprintw(di_win, 6, 36, "%-4d", ++tic);
X				wrefresh(di_win);
X			}
X			else {
X				/*
X				 * A return code that converts to an number
X				 * that is less than 300 is probably an error
X				 * message.
X				 */
X				baud = atoi(str);
X				if (baud < 300) {
X					mvwprintw(di_win, 12, 36, "%-20.20s", str);
X					wmove(di_win, 12, 36);
X					wrefresh(di_win);
X					break;
X				}
X					/* we're connected */
X				beep();
X				clear_line(di_win, 12, 36, 1);
X				wattrstr(di_win, A_BLINK, "CONNECTED");
X				wmove(di_win, 12, 36);
X				wrefresh(di_win);
X				wait_key(di_win, 2);
X				delwin(di_win);
X
X				/*
X				 * Did the modem sync at a different baud
X				 * rate than what we expected?
X				 */
X				if (modem_sync) {
X					if (dir->baud[dir->d_cur] != baud) {
X						dir->baud[dir->d_cur] = baud;
X						line_set();
X					}
X				}
X
X				unlink(status->vs_path);
X				touchwin(stdscr);
X				clear();
X				printw("Connected to %s at %d baud...\n",
X				 dir->name[dir->d_cur], dir->baud[dir->d_cur]);
X				refresh();
X
X					/* log the call */
X				log_calls(i);
X				return(1);
X			}
X			if (tic == param->cdelay)
X				break;
X					/* ok... try the keyboard */
X			if ((ans = wait_key(di_win, 1)) != -1)
X				break;
X
X			mvwprintw(di_win, 6, 36, "%-4d", ++tic);
X			wrefresh(di_win);
X		}
X		/*
X		 * If the modem did not return a code, then we need to
X		 * stop it.  Sending a CR will stop most modems cold,
X		 * except of course for the OBM...
X		 */
X		if (str == NULL) {
X			if (!strcmp(modem->mname[modem->m_cur], "OBM"))
X				hang_up(0);
X			else
X				write(status->fd, &cr, 1);
X			sleep(1);
X		}
X					/* if we get here, no key was pressed */
X		if (ans == -1) {
X			clear_line(di_win, 6, 14, 1);
X			mvwaddstr(di_win, 6, 27, "Pausing:");
X					/* no return code ? */
X			if (str == NULL) {
X				clear_line(di_win, 12, 36, 1);
X				waddstr(di_win, "TIMED OUT");
X				wmove(di_win, 12, 36);
X			}
X					/* do the pause */
X			tic = 0;
X			while (tic < param->pause) {
X				if ((ans = wait_key(di_win, 1)) != -1)
X					break;
X				mvwprintw(di_win, 6, 36, "%-4d", ++tic);
X				wrefresh(di_win);
X			}
X			clear_line(di_win, 6, 14, 1);
X			waddstr(di_win, "Elapse time this try:");
X		}
X					/* Process the keystroke */
X		switch(ans) {
X			case ' ':	/* next in the queue */
X				clear_line(di_win, 12, 36, 1);
X				waddstr(di_win, "RECYCLED");
X				wmove(di_win, 12, 36);
X				wrefresh(di_win);
X				/* fall thru... */
X			case -1:	/* no key was pressed */
X				i++;
X				if (i > NUM_QUEUE)
X					i = 0;
X				if (dir->q_num[i] == -1)
X					i = 0;
X				break;
X			case 127:	/* DEL key, remove from queue */
X				if (dir->q_num[1] == -1) {
X					beep();
X					clear_line(di_win, 12, 36, 1);
X					waddstr(di_win, "NO MORE ENTRIES");
X					wmove(di_win, 12, 36);
X					wrefresh(di_win);
X					wait_key(di_win, 3);
X					break;
X				}
X				clear_line(di_win, 12, 36, 1);
X				waddstr(di_win, "ENTRY DELETED");
X				wmove(di_win, 12, 36);
X				wrefresh(di_win);
X				wait_key(di_win, 3);
X
X					/* compact the queue */
X				for (j=i; j<NUM_QUEUE-1; j++)
X					dir->q_num[j] = dir->q_num[j+1];
X				dir->q_num[NUM_QUEUE-1] = -1;
X				break;
X			case 'e':
X			case 'E':	/* change delay time */
X				delay_times();
X				touchwin(di_win);
X				mvwprintw(di_win, 9, 36, "%-4d", param->cdelay);
X				mvwprintw(di_win, 10, 36, "%-4d", param->pause);
X				break;
X			case 27:	/* ESC key */
X				beep();
X				clear_line(di_win, 12, 36, 1);
X				wattrstr(di_win, A_BLINK, "DIAL ABORTED");
X				wmove(di_win, 12, 36);
X				wrefresh(di_win);
X				wait_key(di_win, 3);
X				want_out++;
X				break;
X			default:
X				beep();
X				break;
X		}
X	}
X					/* clean up and go home */
X	werase(di_win);
X	wrefresh(di_win);
X	delwin(di_win);
X	if (!want_out)
X		error_win(0, "Exceeded the maximum number number of dialing attempts", NULL);
X	return(0);
X}
X
X/*
X * Display what info we know at this time.
X */
X
Xvoid
Xdisp_queue(win, entry, pass)
XWINDOW *win;
Xint entry, pass;
X{
X	long now, time();
X	char *tbuf, *ctime();
X	void status_line();
X					/* redo the status line */
X	status_line(NULL);
X					/* system name */
X	clear_line(win, 4, 36, 1);
X	waddstr(win, dir->name[entry]);
X					/* pass number */
X	mvwprintw(win, 5, 36, "%-4d", pass);
X					/* time of this call */
X	time(&now);
X	tbuf = ctime(&now);
X	tbuf[19] = NULL;
X	mvwaddstr(win, 8, 36, &tbuf[11]);
X					/* the index field */	
X	clear_line(win, 11, 36, 1);
X	waddstr(win, dir->index[entry]);
X
X	wmove(win, 12, 36);
X	wrefresh(win);
X	return;
X}
X
X/*
X * Monitor the progress of the dialing, but returns a NULL after one
X * second of inactivity.
X */
X
Xjmp_buf md_jmp;
X
Xchar *
Xmonitor_dial()
X{
X	int force_md();
X	char *ans, *read_codes();
X	unsigned int alarm();
X
X	if (setjmp(md_jmp))
X		return(NULL);
X	signal(SIGALRM, force_md);
X	alarm(1);
X	ans = read_codes();
X	alarm(0);
X	return(ans);
X}
Xint
Xforce_md(dummy)
Xint dummy;
X{
X	void longjmp();
X
X	longjmp(md_jmp, 1);
X}
X
X/*
X * Determine if the modem can detect the synchronization of the baud
X * rate if it's different that what it expects.  To do this, we check
X * to see if any two connect strings are the same.  A return code of
X * 1 means the modem can sync.
X */
X
Xint
Xcan_sync()
X{
X	int i;
X
X	i = modem->m_cur;
X					/* not both null (sneaky trick) */
X	if (*modem->con_3[i] + *modem->con_12[i]) {
X		if (!strcmp(modem->con_3[i], modem->con_12[i]))
X			return(0);
X	}
X	if (*modem->con_12[i] + *modem->con_24[i]) {
X		if (!strcmp(modem->con_12[i], modem->con_24[i]))
X			return(0);
X	}
X	if (*modem->con_24[i] + *modem->con_48[i]) {
X		if (!strcmp(modem->con_24[i], modem->con_48[i]))
X			return(0);
X	}
X	if (*modem->con_48[i] + *modem->con_96[i]) {
X		if (!strcmp(modem->con_48[i], modem->con_96[i]))
X			return(0);
X	}
X	if (*modem->con_96[i] + *modem->con_192[i]) {
X		if (!strcmp(modem->con_96[i], modem->con_192[i]))
X			return(0);
X	}
X	return(1);
X}
SHAR_EOF
if test 9254 -ne "`wc -c < 'di_win.c'`"
then
	echo shar: "error transmitting 'di_win.c'" '(should have been 9254 characters)'
fi
fi
echo shar: "extracting 'dial.c'" '(6180 characters)'
if test -f 'dial.c'
then
	echo shar: "will not over-write existing file 'dial.c'"
else
sed 's/^X//' << \SHAR_EOF > 'dial.c'
X/*
X * The routines that dial the modem and listen for the return codes.
X */
X
X#include <stdio.h>
X#include <termio.h>
X#ifdef UNIXPC
X#include <sys/phone.h>
X#endif /* UNIXPC */
X#include "dial_dir.h"
X#include "modem.h"
X#include "param.h"
X#include "status.h"
X
X/*
X * Get the dial string ready, send it to the modem.  The parameter is not
X * the actual entry number, it is an index into the queue.
X */
X
Xvoid
Xdial_it(num)
Xint num;
X{
X	int i;
X	char s[100], number[40], *strcpy(), *strcat(), *n, *strchr();
X	void send_str();
X#ifdef UNIXPC
X	struct updata pbuf;
X	unsigned int sleep();
X#endif UNIXPC
X
X	/*
X	 * Create the string to be sent to the modem.  The long distance
X	 * codes are added if they are requested.
X	 */
X	s[0] = NULL;
X	strcpy(s, modem->dial[modem->m_cur]);
X
X	switch (dir->q_ld[num]) {
X		case 0:			/* no ld code requested */
X			break;
X		case '+':
X			strcat(s, param->ld_plus);
X			break;
X		case '-':
X			strcat(s, param->ld_minus);
X			break;
X		case '@':
X			strcat(s, param->ld_at);
X			break;
X		case '#':
X			strcat(s, param->ld_pound);
X			break;
X	}
X	/*
X	 * Purify the phone number by removing all the pretty characters
X	 * that don't need to be sent to the modem.  Typically the '-',
X	 * '(', ')', and space characters are just for looks.
X	 */
X	i = 0;
X	n = dir->number[dir->q_num[num]];
X	while (*n) {
X		if (!strchr("-() ", *n))
X			number[i++] = *n;
X		n++;
X	}
X	number[i] = NULL;
X					/* add it to the string */
X	strcat(s, number);
X	strcat(s, modem->suffix[modem->m_cur]);
X
X#ifdef UNIXPC
X					/* special case for OBM */
X	if (!strcmp(modem->mname[modem->m_cur], "OBM")) {
X					/* prepare the modem */
X		pbuf.c_lineparam = DATA|DTMF;
X		pbuf.c_waitdialtone = 5;
X		pbuf.c_linestatus = 0;
X		pbuf.c_feedback = SPEAKERON|NORMSPK;
X		pbuf.c_waitflash = 500;
X		ioctl(status->fd, PIOCSETP, &pbuf);
X
X					/* connect the dialer */
X		ioctl(status->fd, PIOCRECONN);
X		sleep(1);
X					/* dial each digit */
X		n = s;
X		while(*n) {
X			ioctl(status->fd, PIOCDIAL, n);
X			n++;
X		}
X	}
X
X#else /* UNIXPC */
X	send_str(s);
X#endif /* UNIXPC */
X	return;
X}
X
X/*
X * Send a string to the modem.  Performs all the character synonym
X * translations.  No sanity checking on the "m_cur" value.
X */
X
Xvoid
Xsend_str(s)
Xchar *s;
X{
X	int skip;
X	char c;
X	unsigned int sleep();
X					/* empty string ?? */
X	if (s == NULL || *s == NULL)
X		return;
X
X	ioctl(status->fd, TCFLSH, 1);	
X	/*
X	 * Change the character synonyms to their real values.  Writes
X	 * the characters to the modem.  To remove the special meaning
X	 * of one of the characters, prepend a '\' to it.
X	 */
X	skip = 0;
X	while (*s) {
X		c = *s;
X					/* send the literal character */
X		if (skip) {
X			skip = 0;
X			write(status->fd, &c, 1);
X			ioctl(status->fd, TCSBRK, 1);
X			s++;
X			continue;
X		}
X					/* turn off the special meaning */
X		if (c == '\\') {
X			skip = 1;
X			s++;
X			continue;
X		}
X					/* carriage return synonym */
X		if (c == param->cr_char)
X			c = '\r';
X					/* 2 character control sequence */
X		if (c == param->ctrl_char) {
X			s++;
X			c = *s;
X					/* premature EOF? */
X			if (c == NULL)
X				break;
X			if (c > '_')
X				c -= 96;
X			else
X				c -= 64;
X		}
X					/* escape synonym */
X		if (c == param->esc_char)
X			c = 27;
X					/* pause synonym */
X		if (c == param->pause_char) {
X			sleep(1);
X			s++;
X			continue;
X		}
X		write(status->fd, &c, 1);
X		/*
X		 * Because the pause char makes the timing critical, we
X		 * wait until the buffer is clear before we continue.
X		 */
X		ioctl(status->fd, TCSBRK, 1);
X		s++;
X	}
X	return;
X}
X
X/*
X * Read the result codes coming back from the modem.  Test for the 6
X * "connect" strings and the 4 "no connect" strings.  Return the connected
X * baud rate (as a string) or the error message.
X */
X
Xchar rc_buf[512];
Xint rc_index;
X
Xchar *
Xread_codes()
X{
X	char c;
X#ifdef UNIXPC
X	unsigned int sleep();
X	struct updata pbuf;
X					/* special case for OBM */
X	if (!strcmp(modem->mname[modem->m_cur], "OBM")) {
X		ioctl(status->fd, PIOCGETP, &pbuf);
X
X					/* fake the return code */
X		if (pbuf.c_linestatus & MODEMCONNECTED)
X			return("1200");
X
X		sleep(1);
X		return(NULL);
X	}
X#endif /* UNIXPC */
X					/* search for key words */
X	for (; rc_index<511; rc_index++) {
X		if (read(status->fd, &c, 1) <= 0)
X			return(NULL);
X
X		rc_buf[rc_index] = c;
X		rc_buf[rc_index+1] = NULL;
X					/* the connect strings */
X		if (match(rc_buf, modem->con_3[modem->m_cur]))
X			return("300");
X
X		if (match(rc_buf, modem->con_12[modem->m_cur]))
X			return("1200");
X
X		if (match(rc_buf, modem->con_24[modem->m_cur]))
X			return("2400");
X
X		if (match(rc_buf, modem->con_48[modem->m_cur]))
X			return("4800");
X
X		if (match(rc_buf, modem->con_96[modem->m_cur]))
X			return("9600");
X
X		if (match(rc_buf, modem->con_192[modem->m_cur]))
X			return("19200");
X
X					/* the no connect strings */
X		if (match(rc_buf, modem->no_con1[modem->m_cur]))
X			return(modem->no_con1[modem->m_cur]);
X
X		if (match(rc_buf, modem->no_con2[modem->m_cur]))
X			return(modem->no_con2[modem->m_cur]);
X
X		if (match(rc_buf, modem->no_con3[modem->m_cur]))
X			return(modem->no_con3[modem->m_cur]);
X
X		if (match(rc_buf, modem->no_con4[modem->m_cur]))
X			return(modem->no_con4[modem->m_cur]);
X	}
X					/* ran out of buffer ? */
X	return("ERROR");
X}
X
X/*
X * Test for a match between two character strings.  A return code of 1
X * means that s2 was found at the end of s1
X */
X
Xint
Xmatch(s1, s2)
Xchar *s1, *s2;
X{
X	int i, skip, diff;
X	char c, new[40];
X					/* if no string to match */
X	if (*s2 == NULL)
X		return(0);
X					/* translate synonyms */
X	i = 0;
X	skip = 0;
X	while (*s2) {
X		c = *s2;
X					/* literal character */
X		if (skip) {
X			skip = 0;
X			new[i++] = c;
X			s2++;
X			continue;
X		}
X					/* turn off the special meaning */
X		if (c == '\\') {
X			skip = 1;
X			s2++;
X			continue;
X		}
X					/* carriage return synonym */
X		if (c == param->cr_char)
X			c = '\r';
X
X					/* 2 character control sequence */
X		if (c == param->ctrl_char) {
X			s2++;
X			c = *s2;
X			if (c == NULL)
X				break;
X			if (c > '_')
X				c -= 96;
X			else
X				c -= 64;
X		}
X					/* escape synonym */
X		if (c == param->esc_char)
X			c = 27;
X
X		new[i++] = c;
X		s2++;
X	}
X	new[i] = NULL;
X
X	diff = strlen(s1) - strlen(new);
X					/* is it possible ? */
X	if (diff < 0)
X		return(0);
X					/* test it out */
X	if (!strcmp(&s1[diff], new))
X		return(1);
X	return(0);
X}
SHAR_EOF
if test 6180 -ne "`wc -c < 'dial.c'`"
then
	echo shar: "error transmitting 'dial.c'" '(should have been 6180 characters)'
fi
fi
echo shar: "extracting 'expand.c'" '(2396 characters)'
if test -f 'expand.c'
then
	echo shar: "will not over-write existing file 'expand.c'"
else
sed 's/^X//' << \SHAR_EOF > 'expand.c'
X/*
X * Do file name expansion with 'native' shell.  Using the native shell
X * (as described in the SHELL environmental variable) allows for csh or
X * ksh abbreviations that sh doesn't recognize.
X */
X
X#include <stdio.h>
X#include <signal.h>
X
Xchar *
Xexpand(input)
Xchar *input;
X{
X	FILE *pfp, *native_popen();
X	char *ans, buf[1024], *strpbrk(), *strdup();
X	extern char *null_ptr;
X	void free_ptr();
X
X					/* same rules as strdup() */
X	if (input == NULL)
X		return(NULL);
X	if (*input == NULL)
X		return(null_ptr);
X					/* any thing to expand ? */
X	ans = strdup(input);
X	if (!strpbrk(input, "$*{}[]\\?~"))
X		return(ans);
X					/* popen an echo */
X	sprintf(buf, "echo %s", input);
X
X	pfp = native_popen(buf, "r");
X	fgets(buf, 1024, pfp);
X	native_pclose(pfp);
X
X	if (!strlen(buf))
X		return(ans);
X					/* zap the line feed */
X	buf[strlen(buf)-1] = NULL;
X
X	free_ptr(ans);
X	ans = strdup(buf);
X	return(ans);
X}
X
X#define	tst(a,b) (*mode == 'r'? (b) : (a))
X#define	RDR	0
X#define	WTR	1
Xstatic int popen_pid[20];
X
XFILE *
Xnative_popen(cmd, mode)
Xchar *cmd, *mode;
X{
X	int myside, hisside, pid, p[2];
X	char *shellpath, *shell, *flags, *getenv(), *strrchr();
X	void _exit();
X
X	if (pipe(p) < 0)
X		return NULL;
X
X	myside = tst(p[WTR], p[RDR]);
X	hisside = tst(p[RDR], p[WTR]);
X					/* get the environmental variable */
X	shellpath = getenv("SHELL");
X	if (shellpath == NULL || strlen(shellpath) == 0)
X		shellpath = "/bin/sh";
X
X	shell = strrchr(shellpath, '/') + 1;
X					/* fix up the flags */
X	if (!strcmp(shell, "csh"))
X		flags = "-fc";
X	else
X		flags = "-c";		/* Korn shell too */
X
X	if (!(pid = fork())) {
X		int stdio;
X					/* no error messages please */
X		close(2);
X#ifdef SGID
X		setgid(getgid());
X#endif /* SGID */
X		stdio = tst(0, 1);
X		close(myside);
X		close(stdio);
X		fcntl(hisside, 0, stdio);
X		close(hisside);
X		execl(shellpath, shell, flags, cmd, 0);
X		_exit(1);
X	}
X	if (pid == -1) {
X		close(myside);
X		close(hisside);
X		return NULL;
X	}
X
X	popen_pid[myside] = pid;
X
X	close(hisside);
X	return(fdopen(myside, mode));
X}
X
Xnative_pclose(ptr)
XFILE *ptr;
X{
X	int f, r, (*hstat)(), (*istat)(), (*qstat)(), status;
X
X	f = fileno(ptr);
X	fclose(ptr);
X	istat = signal(SIGINT, SIG_IGN);
X	qstat = signal(SIGQUIT, SIG_IGN);
X	hstat = signal(SIGHUP, SIG_IGN);
X
X	while ((r = wait(&status)) != popen_pid[f] && r != -1)
X		;
X
X	if (r == -1)
X		status = -1;
X
X	signal(SIGINT, istat);
X	signal(SIGQUIT, qstat);
X	signal(SIGHUP, hstat);
X	return(status);
X}
SHAR_EOF
if test 2396 -ne "`wc -c < 'expand.c'`"
then
	echo shar: "error transmitting 'expand.c'" '(should have been 2396 characters)'
fi
fi
echo shar: "extracting 'getcwd.c'" '(382 characters)'
if test -f 'getcwd.c'
then
	echo shar: "will not over-write existing file 'getcwd.c'"
else
sed 's/^X//' << \SHAR_EOF > 'getcwd.c'
X/*
X * Can you believe it???  Masscomps don't have a function to return the
X * current working directory while in the AT&T universe!
X */
X
X#include <stdio.h>
X
Xchar *
Xgetcwd(buf, size)
Xchar *buf;
Xint size;
X{
X	FILE *pfp, *popen();
X
X	if (!(pfp = popen("pwd", "r")))
X		return(".");
X	
X	fgets(buf, size, pfp);
X	pclose(pfp);
X					/* zap the NL */
X	buf[strlen(buf)-1] = NULL;
X	return(buf);
X}
SHAR_EOF
if test 382 -ne "`wc -c < 'getcwd.c'`"
then
	echo shar: "error transmitting 'getcwd.c'" '(should have been 382 characters)'
fi
fi
echo shar: "extracting 'getopt.c'" '(1034 characters)'
if test -f 'getopt.c'
then
	echo shar: "will not over-write existing file 'getopt.c'"
else
sed 's/^X//' << \SHAR_EOF > 'getopt.c'
X/*
X * Parse the command line and return option flags and arguments
X */
X
X#include <stdio.h>
X
Xint optind = 1;
Xchar *optarg;
X
Xint
Xgetopt(argc, argv, opts)
Xint argc;
Xchar *argv[];
Xchar *opts;
X{
X	static int sp = 1;
X	int c, strcmp();
X	char *cp, *strchr();
X
X	if (sp == 1) {
X		if (optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0')
X			return(EOF);
X		else if (strcmp(argv[optind], "--") == NULL) {
X			optind++;
X			return(EOF);
X		}
X	}
X	c = argv[optind][sp];
X	if (c == ':' || (cp=strchr(opts, c)) == NULL) {
X		fprintf(stderr, "%s: illegal option '%c'\n", argv[0], c);
X		if (argv[optind][++sp] == '\0') {
X			optind++;
X			sp = 1;
X		}
X		return('?');
X	}
X	if (*++cp == ':') {
X		if (argv[optind][sp+1] != '\0')
X			optarg = &argv[optind++][sp+1];
X		else if (++optind >= argc) {
X			fprintf(stderr, "%s: option '%c' requires an argument\n", argv[0], c);
X			sp = 1;
X			return('?');
X		} else
X			optarg = argv[optind++];
X		sp = 1;
X	} else {
X		if (argv[optind][++sp] == '\0') {
X			sp = 1;
X			optind++;
X		}
X		optarg = NULL;
X	}
X	return(c);
X}
SHAR_EOF
if test 1034 -ne "`wc -c < 'getopt.c'`"
then
	echo shar: "error transmitting 'getopt.c'" '(should have been 1034 characters)'
fi
fi
echo shar: "extracting 'help.c'" '(1786 characters)'
if test -f 'help.c'
then
	echo shar: "will not over-write existing file 'help.c'"
else
sed 's/^X//' << \SHAR_EOF > 'help.c'
X/*
X * Display the help screen.  Press any key to continue.  If the ascii_hot
X * string is more than 4 characters wide, this screen will look silly.
X * Maybe one day, this will also contain page-full descriptions of each
X * command.
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include "misc.h"
X
Xvoid
Xhelp_screen(hot, fd)
Xchar *hot;
Xint fd;
X{
X	WINDOW *h_win, *newwin();
X
X	h_win = newwin(17, 80, 0, 0);
X
X	mvwattrstr(h_win, 1, 29, A_BOLD, "P C O M M       H E L P\n");
X	waddstr(h_win, "-------------------------------------------------------------------------------\n\n");
X	wattrstr(h_win, A_BOLD, "        Major Functions         Utility Functions         File Functions\n\n");
X	wprintw(h_win, "  Dialing Directory .%4.4s-D  Program Info .....%4.4s-I  Send files ....%4.4s-up\n", hot, hot, hot);
X	wprintw(h_win, "  Auto Redial .......%4.4s-R  Setup Screen .....%4.4s-S  Receive files .%4.4s-dn\n", hot, hot, hot);
X	wprintw(h_win, "  Keyboard Macros ...%4.4s-M  Change Directory .%4.4s-B  Directory .....%4.4s-F\n", hot, hot, hot);
X	wprintw(h_win, "  Line Settings .....%4.4s-P  Clear Screen .....%4.4s-C  Screen Dump ...%4.4s-G\n", hot, hot, hot);
X	wprintw(h_win, "  Exit Pcomm ........%4.4s-X  Toggle Duplex ....%4.4s-E  Data Logging ..%4.4s-1\n", hot, hot, hot);
X	wprintw(h_win, "  Unix Gateway ......%4.4s-4  Hangup Phone .....%4.4s-H  Toggle Log ....%4.4s-2\n", hot, hot, hot);
X	mvwprintw(h_win, 12, 29, "Printer On/Off ...%4.4s-L", hot);
X	mvwprintw(h_win, 13, 29, "Toggle CR/CR-LF ..%4.4s-3", hot);
X	mvwprintw(h_win, 14, 29, "Break Key ........%4.4s-7", hot);
X
X	box(h_win, '|', '-');
X	mvwaddstr(h_win, 16, 27, " Press any key to continue ");
X	wmove(h_win, 16, 79);
X	wrefresh(h_win);
X
X	wgetch(h_win);
X	if (fd == -1) {
X		werase(h_win);
X		wrefresh(h_win);
X	}
X	delwin(h_win);
X	return;
X}
SHAR_EOF
if test 1786 -ne "`wc -c < 'help.c'`"
then
	echo shar: "error transmitting 'help.c'" '(should have been 1786 characters)'
fi
fi
echo shar: "extracting 'info.c'" '(1269 characters)'
if test -f 'info.c'
then
	echo shar: "will not over-write existing file 'info.c'"
else
sed 's/^X//' << \SHAR_EOF > 'info.c'
X/*
X * Display the initial welcome screen (to include all of the proper
X * acknowledgements).  Press any key to continue.
X */
X
X#include <stdio.h>
X#include <curses.h>
X
Xinfo(fd)
Xint fd;
X{
X	WINDOW *w_win, *newwin();
X					/* display the welcome screen */
X	w_win = newwin(23, 80, 0, 0);
X
X	mvwaddstr(w_win, 2, 18, "PPPPPP    CCCC    OOOO    MM   MM   MM   MM");
X	mvwaddstr(w_win, 3, 18, "P    P   C       O    O   M M M M   M M M M");
X	mvwaddstr(w_win, 4, 18, "PPPPPP   C       O    O   M  M  M   M  M  M");
X	mvwaddstr(w_win, 5, 18, "P        C       O    O   M     M   M     M");
X	mvwaddstr(w_win, 6, 18, "P         CCCC    OOOO    M     M   M     M");
X
X	mvwaddstr(w_win, 10, 5, "Pcomm is a public domain telecommunication program for Unix designed");
X	mvwaddstr(w_win, 11, 5, "to operate similar to the popular MSDOS program, ProComm.  ProComm (TM)");
X	mvwaddstr(w_win, 12, 5, "is copyrighted by Datastorm Technologies, Inc.  This is a completely");
X	mvwaddstr(w_win, 13, 5, "new program and contains no ProComm source code.");
X	mvwaddstr(w_win, 19, 45, "Emmet P Gray");
X	mvwaddstr(w_win, 20, 45, "...ihnp4!uiucuxc!fthood!egray");
X
X	wmove(w_win, 22, 79);
X	wrefresh(w_win);
X	
X	wgetch(w_win);
X	if (fd == -1) {
X		werase(w_win);
X		wrefresh(w_win);
X	}
X	delwin(w_win);
X	return;
X}
SHAR_EOF
if test 1269 -ne "`wc -c < 'info.c'`"
then
	echo shar: "error transmitting 'info.c'" '(should have been 1269 characters)'
fi
fi
echo shar: "extracting 'init.c'" '(3530 characters)'
if test -f 'init.c'
then
	echo shar: "will not over-write existing file 'init.c'"
else
sed 's/^X//' << \SHAR_EOF > 'init.c'
X/*
X * Display the welcome screen and find the pcomm files.  Returns a
X * pointer to the STATUS structure.  All errors are fatal.
X */
X
X#define DEFAULT "/usr/local/lib/pcomm"
X#define VERSION "1.0"
X
X#include <stdio.h>
X#include <curses.h>
X#include "misc.h"
X#include "status.h"
X
Xstruct STATUS *
Xinit(extra, file)
Xchar *extra, *file;
X{
X	char *ans, *findfile(), *strdup(), *mktemp();
X	static struct STATUS s;
X	void s_error_win(), free_ptr();
X	extern char *null_ptr;
X					/* find the support files */
X	if ((ans = findfile(extra, "pcomm.param")) == NULL)
X		s_error_win("Can't find pcomm.param file");
X	s.p_path = strdup(ans);
X
X	if ((ans = findfile(extra, "pcomm.dial_dir")) == NULL)
X		s_error_win("Can't find pcomm.dial_dir file");
X	s.d_path = strdup(ans);
X
X	if ((ans = findfile(extra, "pcomm.modem")) == NULL)
X		s_error_win("Can't find pcomm.modem file");
X	s.m_path = strdup(ans);
X					/* some defaults */
X	s.lock_path = null_ptr;
X	s.vs_path = mktemp("/tmp/pcommXXXXXX");
X	s.log_path = strdup("NOT_DEFINED");
X	s.fd = -1;
X	s.log = 0;
X	s.print = 0;
X	s.msg = 0;
X	s.pid = -1;
X					/* display herald if no short-cut */
X	if (file == NULL) {
X
X		mvaddstr(2, 18, "PPPPPP    CCCC    OOOO    MM   MM   MM   MM");
X		mvaddstr(3, 18, "P    P   C       O    O   M M M M   M M M M");
X		mvaddstr(4, 18, "PPPPPP   C       O    O   M  M  M   M  M  M");
X		mvaddstr(5, 18, "P        C       O    O   M     M   M     M");
X		mvaddstr(6, 18, "P         CCCC    OOOO    M     M   M     M");
X
X		mvprintw(10, 26, ">>> Pcomm Version %s <<<", VERSION);
X		mvaddstr(13, 14, "A public domain telecommunication program for Unix");
X		mvaddstr(14, 8, "designed to operate similar to the popular MSDOS program, ProComm.");
X		mvaddstr(15, 11, "ProComm (TM) is copyrighted by Datastorm Technologies, Inc.");
X		mvaddstr(19, 45, "Emmet P. Gray");
X		mvaddstr(20, 45, "...!ihnp4!uiucuxc!fthood!egray");
X		move(LINES-1, COLS-1);
X		refresh();
X					/* Delay so you can read the herald */
X		wait_key(stdscr, 5);
X	}
X	erase();
X	refresh();
X	free_ptr(extra);
X	return(&s);
X}
X
X/*
X * Search the extra directory (supplied on the command line), then the
X * directory in the PCOMM environmental variable, then the current directory,
X * and lastly, the default directory.
X */
X
Xchar *
Xfindfile(extra, name)
Xchar *extra, *name;
X{
X	int i;
X	char *pcomm, *getenv(), temp[200], *path, pbuf[200];
X	char *getcwd();
X	
X					/* see if PCOMM variable is set */	
X	pcomm = getenv("PCOMM");
X	if (pcomm == NULL || *pcomm == NULL)
X		pcomm = NULL;
X	else {
X					/* zap the trailing separator */
X		if (pcomm[strlen(pcomm)-1] == '/')
X			pcomm[strlen(pcomm)-1] = NULL;
X	}
X
X	for (i=0; i<4; i++) {
X					/* directory search order */
X		switch(i) {
X			case 0:
X				path = extra;
X				break;
X			case 1:
X				path = pcomm;
X				break;
X			case 2:
X				path = getcwd(pbuf, 200);
X				break;
X			case 3:
X				path = DEFAULT;
X				break;
X		}
X		sprintf(temp, "%s/%s", path, name);
X					/* read permission checked */
X		if (!access(temp, 4))
X			return(temp);
X	}
X	return(NULL);
X}
X
X/*
X * Handle fatal errors, similar to error_win() but we can't rely on
X * the status structure (since it hasn't been created yet!).
X */
X
Xvoid
Xs_error_win(str)
Xchar *str;
X{
X	WINDOW *se_win, *newwin();
X	void exit();
X
X	se_win = newwin(7, 70, 9, 5);
X					/* display the nasty note */
X	mvwaddstr(se_win, 2, 4, str);
X	mvwattrstr(se_win, 5, 24, A_BLINK, "Press any key to exit");
X	box(se_win, '|', '-');
X	beep();
X	wrefresh(se_win);
X
X	wgetch(se_win);
X	delwin(se_win);
X					/* erase the window we made */
X	touchwin(stdscr);
X	erase();
X	refresh();
X	endwin();
X	exit(1);
X}
SHAR_EOF
if test 3530 -ne "`wc -c < 'init.c'`"
then
	echo shar: "error transmitting 'init.c'" '(should have been 3530 characters)'
fi
fi
exit 0
#	End of shell archive

egray@fthood.UUCP (03/14/88)

This is part 5 (of 6) to the Pcomm version 1.0 distribution.

Emmet P. Gray				US Army, HQ III Corps & Fort Hood
...!ihnp4!uiucuxc!fthood!egray		Attn: AFZF-DE-ENV
					Directorate of Engineering & Housing
					Environmental Management Office
					Fort Hood, TX 76544-5057

-------------------------------------------------------------------------------
#! /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:
#	s_axfer.c
#	s_gen.c
#	s_menu.c
#	s_modem.c
#	s_prompt.c
#	s_term.c
#	s_tty.c
#	screen.c
#	st_line.c
#	strings.c
#	terminal.c
#	x_ascii.c
# This archive created: Fri Mar 11 07:35:23 1988
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 's_axfer.c'" '(3885 characters)'
if test -f 's_axfer.c'
then
	echo shar: "will not over-write existing file 's_axfer.c'"
else
sed 's/^X//' << \SHAR_EOF > 's_axfer.c'
X/*
X * Display the ASCII transfer setup, query for changes.  A return code
X * of 1 means something was changed.
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include "misc.h"
X#include "param.h"
X
Xint
Xascii_xfer_setup()
X{
X	WINDOW *x_win, *newwin();
X	int i, ret_code, num;
X	char *ans, *str_prompt(), *menu_prompt(), *strdup();
X	void free_ptr();
X	extern char *v_yes[], *v_cr[], *v_lf[], *v_delay[];
X
X	x_win = newwin(23, 80, 0, 0);
X
X	waddstr(x_win, "----------------------------- ");
X	wattrstr(x_win, A_BOLD, "ASCII Transfer Setup");
X	waddstr(x_win, " -----------------------------");
X	mvwaddstr(x_win, 3, 34, "ASCII UPLOAD");
X	mvwprintw(x_win, 5, 22, "1) Echo locally ........... %s", param->lecho);
X	mvwprintw(x_win, 6, 22, "2) Expand blank lines ..... %s", param->expand);
X	mvwprintw(x_win, 7, 22, "3) CR delay (ms) .......... %d", param->cr_delay);
X	mvwprintw(x_win, 8, 22, "4) Pace the output ........ %s", param->pace);
X	mvwprintw(x_win, 9, 22, "5) CR translation ......... %s", param->cr_up);
X	mvwprintw(x_win, 10, 22, "6) LF translation ......... %s", param->lf_up);
X	mvwaddstr(x_win, 12, 32, "ASCII DOWNLOAD");
X	mvwprintw(x_win, 14, 22, "7) Transfer timeout ....... %d", param->timer);
X	mvwprintw(x_win, 15, 22, "8) CR translation ......... %s", param->cr_dn);
X	mvwprintw(x_win, 16, 22, "9) LF translation ......... %s", param->lf_dn);
X	mvwprintw(x_win, 19, 0, "--------------------------------------------------------------------------------");
X	mvwattrstr(x_win, 20, 0, A_BOLD, "OPTION ==> ");
X	mvwaddstr(x_win, 20, 60, "Press ESC to return");
X	wmove(x_win, 20, 12);
X	touchwin(x_win);
X	wrefresh(x_win);
X					/* get the option number */
X	ret_code = 0;
X	while ((i = get_num(x_win, 1)) != -1) {
X		switch(i) {
X			case 1:
X				if ((ans = menu_prompt(x_win, 5, 50, "Echo locally", v_yes)) != NULL) {
X					free_ptr(param->lecho);
X					param->lecho = strdup(ans);
X					ret_code++;
X				}
X				break;
X			case 2:
X				if ((ans = menu_prompt(x_win, 6, 50, "Expand blank lines", v_yes)) != NULL) {
X					free_ptr(param->expand);
X					param->expand = strdup(ans);
X					ret_code++;
X				}
X				break;
X			case 3:
X				if ((ans = menu_prompt(x_win, 7, 50, "CR delay (ms)", v_delay)) != NULL) {
X					param->cr_delay = atoi(ans);
X					ret_code++;
X				}
X				break;
X			case 4:
X				if ((ans = menu_prompt(x_win, 8, 50, "Pace the output", v_yes)) != NULL) {
X					free_ptr(param->pace);
X					param->pace = strdup(ans);
X					ret_code++;
X				}
X				break;
X			case 5:
X				if ((ans = menu_prompt(x_win, 9, 50, "CR translation (upload)", v_cr)) != NULL) {
X					free_ptr(param->cr_up);
X					param->cr_up = strdup(ans);
X					ret_code++;
X				}
X				break;
X			case 6:
X				if ((ans = menu_prompt(x_win, 10, 50, "LF translation (upload)", v_lf)) != NULL) {
X					free_ptr(param->lf_up);
X					param->lf_up = strdup(ans);
X					ret_code++;
X				}
X				break;
X			case 7:
X				if ((num = num_prompt(x_win, 14, 50, "Transfer timeout", NULL)) != -1) {
X					if (num > MAX_TIMER || num < MIN_TIMER) {
X						beep();
X					/* some reasonable range of values */
X						if (num < MIN_TIMER)
X							num = MIN_TIMER;
X						else
X							num = MAX_TIMER;
X						mvwaddstr(x_win, 14, 50, "   ");
X						wrefresh(x_win);
X						mvwattrnum(x_win, 14, 50, A_BOLD, num);
X						wrefresh(x_win);
X					}
X					param->timer = num;
X					ret_code++;
X				}
X				break;
X			case 8:
X				if ((ans = menu_prompt(x_win, 15, 50, "CR translation (download)", v_cr)) != NULL) {
X					free_ptr(param->cr_dn);
X					param->cr_dn = strdup(ans);
X					ret_code++;
X				}
X				break;
X			case 9:
X				if ((ans = menu_prompt(x_win, 16, 50, "LF translation (download)", v_lf)) != NULL) {
X					free_ptr(param->lf_dn);
X					param->lf_dn = strdup(ans);
X					ret_code++;
X				}
X				break;
X			default:
X				beep();
X		}
X		mvwaddch(x_win, 20, 12, ' ');
X		clear_line(x_win, 21, 0, 0);
X		clear_line(x_win, 22, 0, 0);
X		wmove(x_win, 20, 12);
X		wrefresh(x_win);
X	}
X	delwin(x_win);
X	return(ret_code);
X}
SHAR_EOF
if test 3885 -ne "`wc -c < 's_axfer.c'`"
then
	echo shar: "error transmitting 's_axfer.c'" '(should have been 3885 characters)'
fi
fi
echo shar: "extracting 's_gen.c'" '(4267 characters)'
if test -f 's_gen.c'
then
	echo shar: "will not over-write existing file 's_gen.c'"
else
sed 's/^X//' << \SHAR_EOF > 's_gen.c'
X/*
X * Display the general setup, query for changes.  A return code of 1
X * means something was changed.
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include "misc.h"
X#include "param.h"
X
Xint
Xgen_setup()
X{
X	WINDOW *g_win, *newwin();
X	int i, num, ret_code;
X	char c, *ans, *str_prompt(), *menu_prompt(), chr_prompt();
X	char *strdup();
X	void free_ptr();
X	extern char *v_yes[], *v_abort[];
X
X	g_win = newwin(23, 80, 0, 0);
X
X	waddstr(g_win, "--------------------------------- ");
X	wattrstr(g_win, A_BOLD, "General Setup");
X	waddstr(g_win, " --------------------------------");
X	mvwprintw(g_win, 3, 22, "1) Default log file ....... %s", param->logfile);
X	mvwprintw(g_win, 4, 22, "2) Screen dump file ....... %s", param->dumpfile);
X	mvwprintw(g_win, 6, 22, "3) Strip high bit  ........ %s", param->strip);
X	mvwprintw(g_win, 8, 22, "4) Pause character ........ %c", param->pause_char);
X	mvwprintw(g_win, 9, 22, "5) CR character ........... %c", param->cr_char);
X	mvwprintw(g_win, 10, 22, "6) CTRL character ......... %c", param->ctrl_char);
X	mvwprintw(g_win, 11, 22, "7) ESC character .......... %c", param->esc_char);
X	mvwprintw(g_win, 13, 22, "8) Aborted downloads ...... %s", param->abort);
X	mvwprintw(g_win, 15, 22, "9) Connect delay time ..... %d", param->cdelay);
X	mvwprintw(g_win, 16, 21, "10) Pause between redials .. %d", param->pause);
X	mvwprintw(g_win, 19, 0, "--------------------------------------------------------------------------------");
X	mvwattrstr(g_win, 20, 0, A_BOLD, "OPTION ==> ");
X	mvwaddstr(g_win, 20, 60, "Press ESC to return");
X	wmove(g_win, 20, 12);
X	touchwin(g_win);
X	wrefresh(g_win);
X					/* get the option number */
X	ret_code = 0;
X	while ((i = get_num(g_win, 2)) != -1) {
X		switch(i) {
X			case 1:
X				if ((ans = str_prompt(g_win, 3, 50, "Default log file", NULL)) != NULL) {
X					free_ptr(param->logfile);
X					param->logfile = strdup(ans);
X					ret_code++;
X				}
X				break;
X			case 2:
X				if ((ans = str_prompt(g_win, 4, 50, "Default screen dump file", NULL)) != NULL) {
X					free_ptr(param->dumpfile);
X					param->dumpfile = strdup(ans);
X					ret_code++;
X				}
X				break;
X			case 3:
X				if ((ans = menu_prompt(g_win, 6, 50, "Strip high bit ?", v_yes)) != NULL) {
X					free_ptr(param->strip);
X					param->strip = strdup(ans);
X					ret_code++;
X				}
X				break;
X			case 4:
X				if ((c = chr_prompt(g_win, 8, 50, "Pause character", "1 second")) != NULL) {
X					param->pause_char = c;
X					ret_code++;
X				}
X				break;
X			case 5:
X				if ((c = chr_prompt(g_win, 9, 50, "CR character", "(carriage return)")) != NULL) {
X					param->cr_char = c;
X					ret_code++;
X				}
X				break;
X			case 6:
X				if ((c = chr_prompt(g_win, 10, 50, "CTRL character", "(control)")) != NULL) {
X					param->ctrl_char = c;
X					ret_code++;
X				}
X				break;
X			case 7:
X				if ((c = chr_prompt(g_win, 11, 50, "ESC character", "(escape)")) != NULL) {
X					param->esc_char = c;
X					ret_code++;
X				}
X				break;
X			case 8:
X				if ((ans = menu_prompt(g_win, 13, 50, "Aborted downloads", v_abort)) != NULL) {
X					free_ptr(param->abort);
X					param->abort = strdup(ans);
X					ret_code++;
X				}
X				break;
X			case 9:
X				if ((num = num_prompt(g_win, 15, 50, "Connect delay time", "in seconds")) != -1) {
X					if (num > MAX_CDELAY || num < MIN_CDELAY) {
X						beep();
X					/* some reasonable range of values */
X						if (num < MIN_CDELAY)
X							num = MIN_CDELAY;
X						else
X							num = MAX_CDELAY;
X						mvwaddstr(g_win, 15, 50, "   ");
X						wrefresh(g_win);
X						mvwattrnum(g_win, 15, 50, A_BOLD, num);
X						wrefresh(g_win);
X					}
X					param->cdelay = num;
X					ret_code++;
X				}
X				break;
X			case 10:
X				if ((num = num_prompt(g_win, 16, 50, "Pause between redials", "in seconds")) != -1) {
X					if (num > MAX_PAUSE || num < MIN_PAUSE) {
X						beep();
X					/* some reasonable range */
X						if (num < MIN_PAUSE)
X							num = MIN_PAUSE;
X						else
X							num = MAX_PAUSE;
X						mvwaddstr(g_win, 16, 50, "    ");
X						wrefresh(g_win);
X						mvwattrnum(g_win, 16, 50, A_BOLD, num);
X						wrefresh(g_win);
X					}
X					param->pause = num;
X					ret_code++;
X				}
X				break;
X			default:
X				beep();
X		}
X		mvwaddstr(g_win, 20, 12, "  ");
X		clear_line(g_win, 21, 0, 0);
X		clear_line(g_win, 22, 0, 0);
X		wmove(g_win, 20, 12);
X		wrefresh(g_win);
X	}
X	delwin(g_win);
X	return(ret_code);
X}
SHAR_EOF
if test 4267 -ne "`wc -c < 's_gen.c'`"
then
	echo shar: "error transmitting 's_gen.c'" '(should have been 4267 characters)'
fi
fi
echo shar: "extracting 's_menu.c'" '(2698 characters)'
if test -f 's_menu.c'
then
	echo shar: "will not over-write existing file 's_menu.c'"
else
sed 's/^X//' << \SHAR_EOF > 's_menu.c'
X/*
X * Display the setup menu, prompts for a bunch of other menus.
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include "misc.h"
X
Xvoid
Xsetup_menu(fd)
Xint fd;
X{
X	WINDOW *s_win, *newwin();
X	char *ans, *get_str();
X	int param_flag, modem_flag;
X	void top_line();
X	extern int xmc;
X
X	s_win = newwin(23, 80, 0, 0);
X
X	top_line(s_win);
X	mvwaddstr(s_win, 4, 30, "1) TTY Setup");
X	mvwaddstr(s_win, 6, 30, "2) Modem Setup");
X	mvwaddstr(s_win, 8, 30, "3) Terminal Setup");
X	mvwaddstr(s_win, 10, 30, "4) General Setup");
X	mvwaddstr(s_win, 12, 30, "5) ASCII Transfer Setup");
X	mvwaddstr(s_win, 14, 30, "S) Save setup to disk");
X	mvwaddstr(s_win, 19, 0, "--------------------------------------------------------------------------------");
X	mvwattrstr(s_win, 20, 0, A_BOLD, "OPTION ==> ");
X	mvwaddstr(s_win, 20, 60, "  Press ESC to exit");
X	wmove(s_win, 20, 12);
X	wrefresh(s_win);
X
X	param_flag = 0;
X	modem_flag = 0;
X					/* get the options */
X	while ((ans = get_str(s_win, 1, "12345Ss", NULL)) != NULL) {
X		if (xmc > 0) {
X			clear_line(s_win, 0, 0, 0);
X			wrefresh(s_win);
X		}
X		switch(*ans) {
X			case '1':
X				if (tty_setup())
X					modem_flag = 1;
X				break;
X			case '2':
X				if (modem_setup())
X					modem_flag = 1;
X				break;
X			case '3':
X				if (term_setup())
X					param_flag = 1;
X				break;
X			case '4':
X				if (gen_setup())
X					param_flag = 1;
X				break;
X			case '5':
X				if (ascii_xfer_setup())
X					param_flag = 1;
X				break;
X			case 's':
X			case 'S':
X				if (xmc > 0)
X					top_line(s_win);
X				if (param_flag || modem_flag) {
X					wmove(s_win, 22, 27);
X					/*
X					 * Writes to disk are not critical,
X					 * the changes are made in memory.
X					 */
X					if (param_flag) {
X						wattrstr(s_win, A_BLINK, "Updating Parameter File");
X						wrefresh(s_win);
X						wait_key(s_win, 3);
X						if (update_param()) {
X							touchwin(s_win);
X							wrefresh(s_win);
X						}
X					}
X					if (modem_flag) {
X						wattrstr(s_win, A_BLINK, "Updating Modem Database");
X						wrefresh(s_win);
X						wait_key(s_win, 3);
X						if (update_modem()) {
X							touchwin(s_win);
X							wrefresh(s_win);
X						}
X					}
X					clear_line(s_win, 22, 27, 0);
X					wrefresh(s_win);
X				}
X				break;
X			default:
X				beep();
X		}
X		touchwin(s_win);
X		if (xmc > 0)
X			top_line(s_win);
X	
X		mvwaddch(s_win, 20, 12, ' ');
X		wmove(s_win, 20, 12);
X		wrefresh(s_win);
X	}
X	if (fd == -1) {
X		werase(s_win);
X		wrefresh(s_win);
X	}
X	delwin(s_win);
X	return;
X}
X
X/*
X * Put the top line on the window.
X */
X
Xvoid
Xtop_line(win)
XWINDOW *win;
X{
X	clear_line(win, 0, 0, 0);
X	wrefresh(win);
X	waddstr(win, "---------------------------------- ");
X	wattrstr(win, A_BOLD, "Setup Menu");
X	waddstr(win, " ----------------------------------");
X	wrefresh(win);
X	return;
X}
SHAR_EOF
if test 2698 -ne "`wc -c < 's_menu.c'`"
then
	echo shar: "error transmitting 's_menu.c'" '(should have been 2698 characters)'
fi
fi
echo shar: "extracting 's_modem.c'" '(6556 characters)'
if test -f 's_modem.c'
then
	echo shar: "will not over-write existing file 's_modem.c'"
else
sed 's/^X//' << \SHAR_EOF > 's_modem.c'
X/*
X * Display the modem setup, query for changes.  A return code of 1 means
X * something was changed.
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include "misc.h"
X#include "modem.h"
X
Xint
Xmodem_setup()
X{
X	WINDOW *mo_win, *newwin();
X	int i, j, ret_code, modem_prompt();
X	char *ans, *strdup(), *str_prompt();
X	void disp_modem(), free_ptr();
X					/* the current modem */
X	j = 0;
X	if (modem->m_cur != -1)
X		j = modem->m_cur;
X
X	mo_win = newwin(23, 80, 0, 0);
X
X	waddstr(mo_win, "---------------------------------- ");
X	wattrstr(mo_win, A_BOLD, "Modem Setup");
X	waddstr(mo_win, " ---------------------------------");
X					/* display the current settings */
X	disp_modem(mo_win, j);
X	mvwprintw(mo_win, 19, 0, "--------------------------------------------------------------------------------");
X	mvwattrstr(mo_win, 20, 0, A_BOLD, "OPTION ==> ");
X	mvwaddstr(mo_win, 20, 60, "Press ESC to return");
X	wmove(mo_win, 20, 12);
X	touchwin(mo_win);
X	wrefresh(mo_win);
X					/* get the option number */
X	ret_code = 0;
X	while ((i = get_num(mo_win, 2)) != -1) {
X		switch(i) {
X			case 1:
X				j = modem_prompt(mo_win);
X				break;
X			case 2:
X				if ((ans = str_prompt(mo_win, 4, 40, "Modem init string", "sent to the modem once")) != NULL) {
X					free_ptr(modem->init[j]);
X					modem->init[j] = strdup(ans);
X					ret_code++;
X				}
X				break;
X			case 3:
X				if ((ans = str_prompt(mo_win, 5, 40, "Dialing command", NULL)) != NULL) {
X					free_ptr(modem->dial[j]);
X					modem->dial[j] = strdup(ans);
X					ret_code++;
X				}
X				break;
X			case 4:
X				if ((ans = str_prompt(mo_win, 6, 40, "Dialing cmd suffix", "typically the CR character")) != NULL) {
X					free_ptr(modem->suffix[j]);
X					modem->suffix[j] = strdup(ans);
X					ret_code++;
X				}
X				break;
X			case 5:
X				if ((ans = str_prompt(mo_win, 7, 40, "Hangup string", NULL)) != NULL) {
X					free_ptr(modem->hangup[j]);
X					modem->hangup[j] = strdup(ans);
X					ret_code++;
X				}
X				break;
X			case 6:
X				if ((ans = str_prompt(mo_win, 8, 40, "300 baud connect string", NULL)) != NULL) {
X					free_ptr(modem->con_3[j]);
X					modem->con_3[j] = strdup(ans);
X					ret_code++;
X				}
X				break;
X			case 7:
X				if ((ans = str_prompt(mo_win, 9, 40, "1200 baud connect string", NULL)) != NULL) {
X					free_ptr(modem->con_12[j]);
X					modem->con_12[j] = strdup(ans);
X					ret_code++;
X				}
X				break;
X			case 8:
X				if ((ans = str_prompt(mo_win, 10, 40, "2400 baud connect string", NULL)) != NULL) {
X					free_ptr(modem->con_24[j]);
X					modem->con_24[j] = strdup(ans);
X					ret_code++;
X				}
X				break;
X			case 9:
X				if ((ans = str_prompt(mo_win, 11, 40, "4800 baud connect string", NULL)) != NULL) {
X					free_ptr(modem->con_48[j]);
X					modem->con_48[j] = strdup(ans);
X					ret_code++;
X				}
X				break;
X			case 10:
X				if ((ans = str_prompt(mo_win, 12, 40, "9600 baud connect string", NULL)) != NULL) {
X					free_ptr(modem->con_96[j]);
X					modem->con_96[j] = strdup(ans);
X					ret_code++;
X				}
X				break;
X			case 11:
X				if ((ans = str_prompt(mo_win, 13, 40, "19200 baud connect string", NULL)) != NULL) {
X					free_ptr(modem->con_192[j]);
X					modem->con_192[j] = strdup(ans);
X					ret_code++;
X				}
X				break;
X			case 12:
X				if ((ans = str_prompt(mo_win, 14, 40, "No connect string 1", NULL)) != NULL) {
X					free_ptr(modem->no_con1[j]);
X					modem->no_con1[j] = strdup(ans);
X					ret_code++;
X				}
X				break;
X			case 13:
X				if ((ans = str_prompt(mo_win, 15, 40, "No connect string 2", NULL)) != NULL) {
X					free_ptr(modem->no_con2[j]);
X					modem->no_con2[j] = strdup(ans);
X					ret_code++;
X				}
X				break;
X			case 14:
X				if ((ans = str_prompt(mo_win, 16, 40, "No connect string 3", NULL)) != NULL) {
X					free_ptr(modem->no_con3[j]);
X					modem->no_con3[j] = strdup(ans);
X					ret_code++;
X				}
X				break;
X			case 15:
X				if ((ans = str_prompt(mo_win, 17, 40, "No connect string 4", NULL)) != NULL) {
X					free_ptr(modem->no_con4[j]);
X					modem->no_con4[j] = strdup(ans);
X					ret_code++;
X				}
X				break;
X			default:
X				beep();
X		}
X					/* clear the previous prompts */
X		mvwaddstr(mo_win, 20, 12, "   ");
X		clear_line(mo_win, 21, 0, 0);
X		clear_line(mo_win, 22, 0, 0);
X		wmove(mo_win, 20, 12);
X		wrefresh(mo_win);
X	}
X	delwin(mo_win);
X	return(ret_code);
X}
X
X/*
X * Prompts for the modem name.  The user selects the currently showing
X * choice by hitting a carriage return.  Returns the modem entry number.
X * DOES NOT change the value of modem->m_cur.
X */
X
Xint
Xmodem_prompt(win)
XWINDOW *win;
X{
X	char ans;
X	int i;
X					/* print prompt lines */
X	mvwaddstr(win, 22, 0, "Press any key to change, or <CR> to accept");
X	mvwaddstr(win, 21, 0, "Modem name: ");
X					/* show current choice */
X	i = 0;
X	if (modem->m_cur != -1)
X		i = modem->m_cur;
X	mvwprintw(win, 21, 12, "%-30.30s", modem->mname[i]);
X	wmove(win, 21, 12);
X	wrefresh(win);
X					/* show the choices one at a time */
X	while ((ans = wgetch(win)) != '\r') {
X		i++;
X		if (*modem->mname[i] == NULL)
X			i = 0;
X		if (ans == 27)
X			return(0);
X		mvwprintw(win, 21, 12, "%-30.30s", modem->mname[i]);
X		wmove(win, 21, 12);
X		wrefresh(win);
X	}
X					/* display the new values */
X	disp_modem(win, i);
X					/* display the name in bold */
X	clear_line(win, 2, 40, 0);
X	wrefresh(win);
X	mvwattrstr(win, 2, 40, A_BOLD, modem->mname[i]);
X
X	return(i);
X}
X
X/*
X * Show the current settings for the given modem entry number.
X */
X
Xvoid
Xdisp_modem(w, i)
XWINDOW *w;
Xint i;
X{
X	mvwprintw(w, 2, 12, "1) Modem name ............. %-39.39s", modem->mname[i]);
X	mvwprintw(w, 4, 12, "2) Modem init string ...... %-39.39s", modem->init[i]);
X	mvwprintw(w, 5, 12, "3) Dialing command ........ %-39.39s", modem->dial[i]);
X	mvwprintw(w, 6, 12, "4) Dialing cmd suffix ..... %-39.39s", modem->suffix[i]);
X	mvwprintw(w, 7, 12, "5) Hangup string .......... %-39.39s", modem->hangup[i]);
X	mvwprintw(w, 8, 12, "6) 300 baud connect ....... %-39.39s", modem->con_3[i]);
X	mvwprintw(w, 9, 12, "7) 1200 baud connect ...... %-39.39s", modem->con_12[i]);
X	mvwprintw(w, 10, 12, "8) 2400 baud connect ...... %-39.39s", modem->con_24[i]);
X	mvwprintw(w, 11, 12, "9) 4800 baud connect ...... %-39.39s", modem->con_48[i]);
X	mvwprintw(w, 12, 11, "10) 9600 baud connect ...... %-39.39s", modem->con_96[i]);
X	mvwprintw(w, 13, 11, "11) 19200 baud connect ..... %-39.39s", modem->con_192[i]);
X	mvwprintw(w, 14, 11, "12) No connect string 1 .... %-39.39s", modem->no_con1[i]);
X	mvwprintw(w, 15, 11, "13) No connect string 2 .... %-39.39s", modem->no_con2[i]);
X	mvwprintw(w, 16, 11, "14) No connect string 3 .... %-39.39s", modem->no_con3[i]);
X	mvwprintw(w, 17, 11, "15) No connect string 4 .... %-39.39s", modem->no_con4[i]);
X	return;
X}
SHAR_EOF
if test 6556 -ne "`wc -c < 's_modem.c'`"
then
	echo shar: "error transmitting 's_modem.c'" '(should have been 6556 characters)'
fi
fi
echo shar: "extracting 's_prompt.c'" '(3369 characters)'
if test -f 's_prompt.c'
then
	echo shar: "will not over-write existing file 's_prompt.c'"
else
sed 's/^X//' << \SHAR_EOF > 's_prompt.c'
X/*
X * Prompting routines used in the setup menus.
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include "misc.h"
X
X/*
X * Prompt for a string at line 21 (with optional line 22 for additional
X * information).  Display the new string in bold at its original location
X * in the menu.  Used in virtually all of the *_setup() routines.
X */
X
Xchar *
Xstr_prompt(win, y, x, p1, p2)
XWINDOW *win;
Xint y, x;
Xchar *p1, *p2;
X{
X	char *ans, *get_str();
X	extern char *null_ptr;
X					/* print first prompt last */
X	mvwaddstr(win, 22, 0, p2);
X	mvwaddstr(win, 21, 0, p1);
X	waddstr(win, ": ");
X	wrefresh(win);
X
X	if ((ans = get_str(win, 39, NULL, NULL)) == NULL)
X		return(NULL);
X					/* check the value */
X	if (!strcmp(ans, " "))
X		ans = null_ptr;
X					/* display the value in bold */
X	clear_line(win, y, x, 0);
X	wattrstr(win, A_BOLD, ans);
X
X	return(ans);
X}
X
X/*
X * Same as above, except we return a single character.
X */
X
Xchar
Xchr_prompt(win, y, x, p1, p2)
XWINDOW *win;
Xint y, x;
Xchar *p1, *p2;
X{
X	char *ans, *get_str();
X					/* print first prompt last */
X	mvwaddstr(win, 22, 0, p2);
X	mvwaddstr(win, 21, 0, p1);
X	waddstr(win, ": ");
X	wrefresh(win);
X
X	if ((ans = get_str(win, 1, NULL, NULL)) == NULL)
X		return(NULL);
X					/* display the value in bold */
X	mvwaddstr(win, y, x, "  ");
X	wrefresh(win);
X	mvwattrstr(win, y, x, A_BOLD, ans);
X
X	return(*ans);
X}
X
X/*
X * Same as above, except that it prompts for a three digit number.
X */
X
Xint
Xnum_prompt(win, y, x, p1, p2)
XWINDOW *win;
Xint y, x;
Xchar *p1, *p2;
X{
X	int i, get_num();
X					/* print first prompt last */
X	mvwaddstr(win, 22, 0, p2);
X	mvwaddstr(win, 21, 0, p1);
X	waddstr(win, ": ");
X	wrefresh(win);
X
X	if ((i = get_num(win, 3)) == -1)
X		return(-1);
X					/* display the value in bold */
X	mvwaddstr(win, y, x, "    ");
X	wrefresh(win);
X	mvwattrnum(win, y, x, A_BOLD, i);
X					/* return the number */
X	return(i);
X}
X
X/*
X * Prompts for a selection from a menu.  We display the prompt lines,
X * and show the choices one at a time.  The user selects the currently
X * showing choice by hitting a carriage return.  Unlike the similar
X * routines in d_prompt(), the first choice shown is not necessarily
X * the current.
X */
X
Xchar *v_yes[3] = {"YES", "NO", NULL};
Xchar *v_crio[3] = {"CR", "CR/LF", NULL};
Xchar *v_cr[4] = {"NONE", "STRIP", "ADD LF", NULL};
Xchar *v_lf[4] = {"NONE", "STRIP", "ADD CR", NULL};
Xchar *v_abort[3] = {"KEEP", "DELETE", NULL};
Xchar *v_duplex[3] = {"FULL", "HALF", NULL};
Xchar *v_flow[3] = {"NONE", "XON/XOFF", NULL};
Xchar *v_baud[7] = {"300", "1200", "2400", "4800", "9600", "19200", NULL};
Xchar *v_delay[4] = {"0", "100", "150", NULL};
X
Xchar *
Xmenu_prompt(win, y, x, p, menu)
XWINDOW *win;
Xint y, x;
Xchar *p, *menu[];
X{
X	char ans;
X	int i, cy, cx;
X					/* print first prompt last */
X	mvwaddstr(win, 22, 0, "Press any key to change, or <CR> to accept");
X	mvwaddstr(win, 21, 0, p);
X	waddstr(win, ": ");
X					/* show first choice */
X	i = 0;
X	getyx(win, cy, cx);
X	mvwprintw(win, cy, cx, "%-30.30s", menu[i]);
X	wmove(win, cy, cx);
X	wrefresh(win);
X					/* show the choices one at a time */
X	while ((ans = wgetch(win)) != '\r') {
X		i++;
X		if (*menu[i] == NULL)
X			i = 0;
X		if (ans == 27)
X			return(NULL);
X		mvwprintw(win, cy, cx, "%-30.30s", menu[i]);
X		wmove(win, cy, cx);
X		wrefresh(win);
X	}
X					/* display the value in bold */
X	clear_line(win, y, x, 0);
X	wattrstr(win, A_BOLD, menu[i]);
X					/* return the value */
X	return(menu[i]);
X}
SHAR_EOF
if test 3369 -ne "`wc -c < 's_prompt.c'`"
then
	echo shar: "error transmitting 's_prompt.c'" '(should have been 3369 characters)'
fi
fi
echo shar: "extracting 's_term.c'" '(2743 characters)'
if test -f 's_term.c'
then
	echo shar: "will not over-write existing file 's_term.c'"
else
sed 's/^X//' << \SHAR_EOF > 's_term.c'
X/*
X * Display the terminal setup, query for changes.  A return code of 1
X * means something was changed.
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include "misc.h"
X#include "param.h"
X
Xint
Xterm_setup()
X{
X	WINDOW *t_win, *newwin();
X	int i, num, ret_code;
X	char *ans, *strdup(), *str_prompt(), *menu_prompt();
X	void free_ptr();
X	extern char *v_duplex[], *v_crio[], *v_flow[];
X
X	t_win = newwin(23, 80, 0, 0);
X
X	waddstr(t_win, "-------------------------------- ");
X	wattrstr(t_win, A_BOLD, "Terminal Setup");
X	waddstr(t_win, " --------------------------------");
X	mvwprintw(t_win, 4, 22, "1) Hot key ................ %d", param->hot);
X	mvwprintw(t_win, 6, 22, "2) ASCII version of hot ... %s", param->ascii_hot);
X	mvwprintw(t_win, 9, 22, "3) Duplex ................. %s", param->d_duplex);
X	mvwprintw(t_win, 11, 22, "4) Flow control ........... %s", param->flow);
X	mvwprintw(t_win, 13, 22, "5) CR translation (in) .... %s", param->cr_in);
X	mvwprintw(t_win, 15, 22, "6) CR translation (out) ... %s", param->cr_out);
X	mvwprintw(t_win, 19, 0, "--------------------------------------------------------------------------------");
X	mvwattrstr(t_win, 20, 0, A_BOLD, "OPTION ==> ");
X	mvwaddstr(t_win, 20, 60, "Press ESC to return");
X	wmove(t_win, 20, 12);
X	touchwin(t_win);
X	wrefresh(t_win);
X					/* get the option number */
X	ret_code = 0;
X	while ((i = get_num(t_win, 1)) != -1) {
X		switch(i) {
X			case 1:
X				if ((num = num_prompt(t_win, 4, 50, "Hot key", "decimal code for the hot key")) != -1) {
X					param->hot = num;
X					ret_code = 1;
X				}	
X				break;
X			case 2:
X				if ((ans = str_prompt(t_win, 6, 50, "ASCII version of hot key", "(printable version)")) != NULL) {
X					free_ptr(param->ascii_hot);
X					param->ascii_hot = strdup(ans);
X					ret_code = 1;
X				}	
X				break;
X			case 3:
X				if ((ans = menu_prompt(t_win, 9, 50, "Duplex", v_duplex)) != NULL ) {
X					free_ptr(param->d_duplex);
X					param->d_duplex = strdup(ans);
X					ret_code = 1;
X				}
X				break;
X			case 4:
X				if ((ans = menu_prompt(t_win, 11, 50, "Flow control", v_flow)) != NULL ) {
X					free_ptr(param->flow);
X					param->flow = strdup(ans);
X					ret_code = 1;
X				}
X				break;
X			case 5:
X				if ((ans = menu_prompt(t_win, 13, 50, "CR translation (in)", v_crio)) != NULL ) {
X					free_ptr(param->cr_in);
X					param->cr_in = strdup(ans);
X					ret_code = 1;
X				}
X				break;
X			case 6:
X				if ((ans = menu_prompt(t_win, 15, 50, "CR translation (out)", v_crio)) != NULL ) {
X					free_ptr(param->cr_out);
X					param->cr_out = strdup(ans);
X					ret_code = 1;
X				}
X				break;
X			default:
X				beep();
X		}
X		mvwaddch(t_win, 20, 12, ' ');
X		clear_line(t_win, 21, 0, 0);
X		clear_line(t_win, 22, 0, 0);
X		wmove(t_win, 20, 12);
X		wrefresh(t_win);
X	}
X	delwin(t_win);
X	return(ret_code);
X}
SHAR_EOF
if test 2743 -ne "`wc -c < 's_term.c'`"
then
	echo shar: "error transmitting 's_term.c'" '(should have been 2743 characters)'
fi
fi
echo shar: "extracting 's_tty.c'" '(4775 characters)'
if test -f 's_tty.c'
then
	echo shar: "will not over-write existing file 's_tty.c'"
else
sed 's/^X//' << \SHAR_EOF > 's_tty.c'
X/*
X * Display the tty setup, query for changes.  A return code of 1
X * means something was changed.
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include "misc.h"
X#include "modem.h"
X#include "status.h"
X
Xint
Xtty_setup()
X{
X	WINDOW *tt_win, *newwin();
X	char *strdup(), buf[80];
X	int num, i, j, ret_code;
X	void disp_tty(), create_modem(), delete_modem(), error_win();
X	void delete_tty();
X	extern char *null_ptr;
X
X	tt_win = newwin(23, 80, 0, 0);
X
X	waddstr(tt_win, "----------------------------------- ");
X	wattrstr(tt_win, A_BOLD, "TTY Setup");
X	waddstr(tt_win, " ----------------------------------");
X	mvwaddstr(tt_win, 2, 22, "TTY name");
X	mvwaddstr(tt_win, 2, 37, "Modem name");
X	mvwaddstr(tt_win, 2, 51, "Maximum baud");
X					/* display the current tty list */
X	disp_tty(tt_win);
X					/* prompt for options */
X	mvwprintw(tt_win, 15, 20, "%d) Add a TTY entry", NUM_TTY+1);
X	mvwprintw(tt_win, 16, 20, "%d) Delete a TTY entry", NUM_TTY+2);
X	mvwprintw(tt_win, 19, 0, "--------------------------------------------------------------------------------");
X	mvwattrstr(tt_win, 20, 0, A_BOLD, "OPTION ==> ");
X	mvwaddstr(tt_win, 20, 60, "Press ESC to return");
X	wmove(tt_win, 20, 12);
X	touchwin(tt_win);
X	wrefresh(tt_win);
X					/* get the option number */
X	ret_code = 0;
X	while ((i = get_num(tt_win, 2)) != -1) {
X					/* if beyond t_entries, fake it */
X		if (i>modem->t_entries && i<=NUM_TTY)
X			i=999;
X					/* change an entry  */
X		if (i>=1 && i<=NUM_TTY) {
X			if (tty_prompt(tt_win, i-1))
X				break;
X					/* requires modem update ? */
X			create_modem(modem->tname[i-1]);
X			delete_modem();
X
X			ret_code++;
X		}
X					/* add a entry */
X		if (i == NUM_TTY+1) {
X			if (modem->t_entries == NUM_TTY) {
X				sprintf(buf, "'%s'", status->m_path);
X				error_win(0, "No empty TTY slots in", buf);
X				continue;
X			}
X					/* prompt for info */
X			j = modem->t_entries;
X			if (tty_prompt(tt_win, j))
X				break;
X					/* add modem entry ? */
X			modem->t_entries++;
X			create_modem(modem->tname[j]);
X
X			ret_code++;
X		}
X					/* delete an entry */
X		if (i == NUM_TTY+2) {
X			mvwaddstr(tt_win, 21, 0, "Entry number to delete: ");
X			wrefresh(tt_win);
X			while ((num = get_num(tt_win, 4)) != -1) {
X					/* valid range */
X				if (!num || num>modem->t_entries) {
X					beep();
X					mvwaddstr(tt_win, 21, 24, "   ");
X					wrefresh(tt_win);
X					continue;
X				}
X				delete_tty(num-1);
X				delete_modem();
X
X					/* show the new list */
X				disp_tty(tt_win);
X				ret_code = 1;
X			}
X
X		}
X		if (i == 0 || i>NUM_TTY+2)
X			beep();
X		mvwaddstr(tt_win, 20, 12, "  ");
X		clear_line(tt_win, 21, 0, 0);
X		clear_line(tt_win, 22, 0, 0);
X		wmove(tt_win, 20, 12);
X		wrefresh(tt_win);
X	}
X	delwin(tt_win);
X	return(ret_code);
X}
X
X/*
X * Display the current tty list.  No scrolling yet, so if your NUM_TTY is
X * greater than ten, this routine will need some work.
X */
X
Xvoid
Xdisp_tty(win)
XWINDOW *win;
X{
X	int i;
X
X	for (i=0; i<NUM_TTY; i++)
X		mvwprintw(win, i+4, 20, "%2d) %-14.14s %-14.14s  %d\n",
X		 i+1, modem->tty[i], modem->tname[i], modem->mbaud[i]);
X	return;
X}
X
X/*
X * Prompt the user for the TTY database info.  A return code of 1 means a
X * user abort.  The second argument is the zero based index.
X */
X
Xtty_prompt(win, i)
XWINDOW *win;
Xint i;
X{
X	char *ans, *temp_tty, *temp_tname, *str_prompt(), *menu_prompt();
X	extern char *v_baud[];
X	void free_ptr();
X					/* get temp tty */
X	if ((ans = str_prompt(win, i+4, 24, "TTY name", NULL)) == NULL)
X		return(1);
X
X	temp_tty = strdup(ans);
X	clear_line(win, 21, 0, 0);
X
X					/* get temp tname */
X	if ((ans = str_prompt(win, i+4, 39, "Modem name", NULL)) == NULL)
X		return(1);
X
X	temp_tname = strdup(ans);
X	clear_line(win, 21, 0, 0);
X	
X					/* get maximum baud */
X	if ((ans = menu_prompt(win, i+4, 55, "Maximum baud", v_baud)) == NULL)
X		return(1);
X
X	wrefresh(win);
X					/* store 'em for real */
X	free_ptr(modem->tty[i]);
X	free_ptr(modem->tname[i]);
X
X	modem->tty[i] = strdup(temp_tty);
X	modem->tname[i] = strdup(temp_tname);
X	modem->mbaud[i] = atoi(ans);
X
X	free_ptr(temp_tty);
X	free_ptr(temp_tname);
X	return(0);
X}
X
X/*
X * Delete a tty entry.  Since the list must be contiguous, we collapse the
X * list to cover the hole we made.
X */
X
Xvoid
Xdelete_tty(i)
Xint i;
X{
X	int j;
X	char *strdup();
X	void free_ptr();
X	extern char *null_ptr;
X					/* collapse the list */
X	for (j=i; j<modem->t_entries-1; j++) {
X		free_ptr(modem->tty[j]);
X		free_ptr(modem->tname[j]);
X		modem->tty[j] = strdup(modem->tty[j+1]);
X		modem->tname[j] = strdup(modem->tname[j+1]);
X		modem->mbaud[j] = modem->mbaud[j+1];
X	}
X	j = modem->t_entries-1;
X					/* zap the entry */
X	free_ptr(modem->tty[j]);
X	free_ptr(modem->tname[j]);
X	modem->tty[j] = null_ptr;
X	modem->tname[j] = null_ptr;
X	modem->mbaud[j] = 0;
X					/* update the count */
X	modem->t_entries--;
X	if (modem->t_cur >= modem->t_entries)
X		modem->t_cur = -1;
X	return;
X}
SHAR_EOF
if test 4775 -ne "`wc -c < 's_tty.c'`"
then
	echo shar: "error transmitting 's_tty.c'" '(should have been 4775 characters)'
fi
fi
echo shar: "extracting 'screen.c'" '(1421 characters)'
if test -f 'screen.c'
then
	echo shar: "will not over-write existing file 'screen.c'"
else
sed 's/^X//' << \SHAR_EOF > 'screen.c'
X/*
X * Routines to read and copy the virtual screen image file.
X */
X
X#define MAX_COL	128
X
X#include <stdio.h>
X#include <curses.h>
X#include "param.h"
X#include "status.h"
X
X/*
X * Do a screen dump.  Actually, the screen is already dumped, all we
X * do is copy the file.
X */
X
Xvoid
Xscreen_dump()
X{
X	FILE *fp_in, *fp_out;
X	char buf[MAX_COL+2];
X	void error_win();
X					/* not guaranteed to exist yet */
X	if (!(fp_in = fopen(status->vs_path, "r")))
X		return;
X					/* open for append */
X	if (!(fp_out = fopen(param->dumpfile, "a"))) {
X		fclose(fp_in);
X		sprintf(buf, "'%s' for write", param->dumpfile);
X		error_win(0, "Can't open screen dump file", buf);
X		return;
X	}
X					/* skip the x, y coordinates */
X	fgets(buf, 10, fp_in);
X
X	while (fgets(buf, MAX_COL+2, fp_in) != NULL)
X		fputs(buf, fp_out);
X
X	fclose(fp_in);
X	fclose(fp_out);
X
X	return;
X}
X
X/*
X * Read the virtual screen file and paint its contents to the
X * stdscr with curses.  Leave the cursor where it belongs.
X */
X
Xvoid
Xload_vs()
X{
X	FILE *fp;
X	int row, col, i;
X	char buf[MAX_COL+2];
X					/* not guaranteed to exist yet */
X	if (!(fp = fopen(status->vs_path, "r")))
X		return;
X					/* get the x, y coordinates */
X	fgets(buf, 10, fp);
X	sscanf(buf, "%d,%d\n", &row, &col);
X	
X	clearok(stdscr, TRUE);
X	i = 0;
X	while (fgets(buf, MAX_COL+2, fp) != NULL) {
X		buf[COLS] = NULL;
X		mvaddstr(i++, 0, buf);
X	}
X	move(row, col);
X	refresh();
X	clearok(stdscr, FALSE);
X
X	fclose(fp);
X	return;
X}
SHAR_EOF
if test 1421 -ne "`wc -c < 'screen.c'`"
then
	echo shar: "error transmitting 'screen.c'" '(should have been 1421 characters)'
fi
fi
echo shar: "extracting 'st_line.c'" '(1815 characters)'
if test -f 'st_line.c'
then
	echo shar: "will not over-write existing file 'st_line.c'"
else
sed 's/^X//' << \SHAR_EOF > 'st_line.c'
X/*
X * Display the status line.  Up to now, we've never really cared how
X * large the physical screen was... but now we want the status line
X * on the bottom.
X */
X
X#include <curses.h>
X#include "dial_dir.h"
X#include "misc.h"
X#include "modem.h"
X#include "param.h"
X#include "status.h"
X
Xvoid
Xstatus_line(message)
Xchar *message;
X{
X	WINDOW *sl_win, *newwin();
X	int d, x, y;
X	static char *dn[2] = {"FDX", "HDX"};
X	static char *ln[2] = {"LOG OFF", "LOG ON"};
X	static char *pn[2] = {"PTR OFF", "PTR ON "};
X	char buf[80], field_one[15], *cur_tty;
X	extern int xmc;
X
X	/*
X	 * Sometimes curses() doesn't remember where the cursor is on
X	 * the screen, so we move it to the opposite corner to guarantee
X	 * that the status line is on the bottom.
X	 */
X	getyx(stdscr, y, x);
X	move(0, COLS-1);
X	refresh();
X
X	sl_win = newwin(1, 80, LINES-1, 0);
X					/* duplex message */
X	d = 0;
X	if (dir->duplex[dir->d_cur] == 'H')
X		d = 1;
X					/* the current tty */
X	cur_tty = "No TTY";
X	if (modem->t_cur != -1)
X		cur_tty = modem->tty[modem->t_cur];
X	
X	/*
X	 * The philosophy is:  If you press a command sequence that
X	 * doesn't generate a window on the screen, then show the user
X	 * what's going on in the status line.
X	 */
X	if (message == NULL)
X		sprintf(field_one, " %4.4s-0 HELP  ", param->ascii_hot);
X	else
X		sprintf(field_one, " %-13.13s", message);
X
X	sprintf(buf, "%s | %-9.9s| %s | %5d %c%d%d | %-7.7s | %-7.7s | %-5.5s| %-5.5s",
X	 field_one, cur_tty, dn[d], dir->baud[dir->d_cur],
X	 dir->parity[dir->d_cur], dir->dbits[dir->d_cur],
X	 dir->sbits[dir->d_cur], ln[status->log], pn[status->print],
X	 param->cr_in, param->cr_out);
X	
X	if (xmc > 0) {
X		touchwin(sl_win);
X		werase(sl_win);
X		wrefresh(sl_win);
X	}
X	wattrstr(sl_win, A_STANDOUT, buf);
X	wrefresh(sl_win);
X					/* go ahead and delete it now */
X	delwin(sl_win);
X	move(y, x);
X	return;
X}
SHAR_EOF
if test 1815 -ne "`wc -c < 'st_line.c'`"
then
	echo shar: "error transmitting 'st_line.c'" '(should have been 1815 characters)'
fi
fi
echo shar: "extracting 'strings.c'" '(1349 characters)'
if test -f 'strings.c'
then
	echo shar: "will not over-write existing file 'strings.c'"
else
sed 's/^X//' << \SHAR_EOF > 'strings.c'
X/*
X * Miscellaneous string routines.
X */
X
X#include <stdio.h>
X
X/*
X * Do a fancy string copy.  If NULL, return null.  If pointer to NULL, then
X * return the special 'null_ptr' variable.  If a normal copy, allocate the
X * memory first.
X */
X
Xchar *
Xstrdup(str)
Xchar *str;
X{
X	char *ret, *malloc(), *strcpy();
X	extern char *null_ptr;
X
X	if (str == NULL)
X		return(NULL);
X					/* if pointer to null */
X	if (*str == NULL)
X		return(null_ptr);
X
X	ret = malloc((unsigned int) strlen(str)+1);
X	strcpy(ret, str);
X	return(ret);
X}
X
X/*
X * Perform the free(2) function, but check for NULL and the special
X * 'null_ptr' variable first.
X */
X
Xvoid
Xfree_ptr(str)
Xchar *str;
X{
X	extern char *null_ptr;
X	void free();
X
X	if (str != NULL && (long) str != (long) null_ptr)
X		free(str);
X	return;
X}
X
X/*
X * This routine is similar to strtok(3).  But our version handles null
X * strings and takes a single separator character as an argument.
X * Returns a NULL on end of string or error.
X */
X
Xchar *
Xstr_tok(str, c)
Xchar *str, c;
X{
X	char *strchr();
X	static char *ptr, *sep;
X	extern char *null_ptr;
X					/* start at beginning */
X	if (str != NULL)
X		ptr = str;
X	else
X		ptr = sep;
X					/* at the end ? */
X	if (*ptr == NULL)
X		return(NULL);
X					/* no separator ? */
X	if (!(sep = strchr(ptr, c)))
X		return(NULL);
X					/* zap the sep, move past it */
X	*sep = NULL;
X	sep++;
X
X	return(ptr);
X}
SHAR_EOF
if test 1349 -ne "`wc -c < 'strings.c'`"
then
	echo shar: "error transmitting 'strings.c'" '(should have been 1349 characters)'
fi
fi
echo shar: "extracting 'terminal.c'" '(8039 characters)'
if test -f 'terminal.c'
then
	echo shar: "will not over-write existing file 'terminal.c'"
else
sed 's/^X//' << \SHAR_EOF > 'terminal.c'
X/*
X * Start the terminal dialogue, fork the input routine, watch for the
X * hot key so we can execute an option.
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include <signal.h>
X#ifdef UNIXPC
X#include <sys/phone.h>
X#include <fcntl.h>
X#endif /* UNIXPC */
X#include "dial_dir.h"
X#include "modem.h"
X#include "param.h"
X#include "status.h"
X
Xterminal(input_status)
Xint input_status;
X{
X	int i, k, cr_lf;
X	char c, lf=10, *strdup(), *new_dir, *change_dir();
X	void help_screen(), line_set(), native_shell(), load_vs();
X	void setup_menu(), hang_up(), input_on(), list_dir(), pexit();
X	void status_line(), free_ptr(), screen_dump(), input_off();
X
X					/* if starting out in command mode */
X	if (!input_status)
X		status_line(NULL);
X					/* put the terminal in raw mode */
X	resetterm();
X	cr_lf = raw_mode();
X
X	if (input_status)
X		input_on();
X
X	while(1) {
X		read(0, &c, 1);
X					/* is it the hot key? */
X		if (c == param->hot) {
X					/* suspend input */
X			input_status = 0;
X			if (status->pid != -1)
X				kill(status->pid, SIGINT);
X
X			/*
X			 * Put in terminal in the curses mode and add
X			 * the status line at the bottom.
X			 */
X			fixterm();
X			status_line(NULL);
X#ifndef OLDCURSES
X			keypad(stdscr, 1);
X#endif /* OLDCURSES */
X			i = wgetch(stdscr);
X					/* map the hot key to -1 */
X			if (i == param->hot)
X				i = -1;
X			/*
X			 * Load the virtual screen from the file.  On
X			 * very busy systems, the file might not "appear"
X			 * fast enough for this routine to detect it.
X			 * Or worse, it may contain partially written
X			 * information.
X			 */
X			load_vs();
X					/* look for options */
X			k = -1;
X			switch (i) {
X				case -1:	/* 2 'hots' means send 1 */
X					k = param->hot;
X					break;
X				case '0':	/* help screen */
X					help_screen(param->ascii_hot, status->fd);
X					break;
X				case 'd':
X				case 'D':	/* dialing directory */
X					if (dial_menu())
X						input_status = dial_win();
X					break;
X				case 'r':
X				case 'R':	/* redial */
X					if (redial(status->fd))
X						input_status = dial_win();
X					break;
X				case 'p':
X				case 'P':	/* line settings */
X					if (line_set_menu(status->fd)) {
X						line_set();
X					}
X					break;
X				case 'x':
X				case 'X':	/* exit */
X					pexit(status->fd);
X					break;
X				case '4':	/* Unix gateway */
X					native_shell();
X					break;
X				case 'i':
X				case 'I':	/* Program info screen */
X					info(status->fd);
X					break;
X				case 's':	/* setup menu */
X				case 'S':
X					setup_menu(status->fd);
X					break;
X				case 'c':	/* clear the screen */
X				case 'C':
X					unlink(status->vs_path);
X					clear();
X					clear_absolute(stdscr);
X					break;
X				case 'b':
X				case 'B':	/* Change directory */
X					if ((new_dir = change_dir(status->fd)) != NULL) {
X						chdir(new_dir);
X						free_ptr(new_dir);
X					}
X					break;
X				case 'e':
X				case 'E':	/* toggle duplex */
X					if (dir->duplex[dir->d_cur] == 'F')
X						dir->duplex[dir->d_cur] = 'H';
X					else
X						dir->duplex[dir->d_cur] = 'F';
X					line_set();
X
X						/* show changes */
X					status_line(NULL);
X					k = wait_key(stdscr, 2);
X					break;
X				case 'h':
X				case 'H':	/* hang up phone */
X					hang_up(1);
X					input_off();
X					break;
X				case 'l':
X				case 'L':	/* toggle printer */
X					status->print = status->print ? 0 : 1;
X					if (status->pid != -1)
X						kill(status->pid, SIGUSR2);
X
X						/* show changes */
X					status_line(NULL);
X					k = wait_key(stdscr, 2);
X					break;
X				case '3':	/* toggle CR  CR/LF */
X					if (!strcmp(param->cr_in, "CR"))
X						param->cr_in = strdup("CR/LF");
X					else
X						param->cr_in = strdup("CR");
X					input_off();
X					input_status = 1;
X
X						/* show changes */
X					status_line(NULL);
X					k = wait_key(stdscr, 2);
X					break;
X				case '7':	/* break key */
X					if (status->fd != -1)
X						ioctl(status->fd, TCSBRK, 0);
X
X					status_line("   break");
X					break;
X#ifndef OLDCURSES
X				case KEY_UP:
X#endif /* OLDCURSES */
X				case 'u':
X				case 'U':	/* send files */
X					input_status = xfer_menu(1);
X					break;
X#ifndef OLDCURSES
X				case KEY_DOWN:
X				case '\n':
X#endif /* OLDCURSES */
X				case 'n':
X				case 'N':	/* receive files */
X					input_status = xfer_menu(0);
X					break;
X				case 'f':
X				case 'F':	/* list directory */
X					list_dir(status->fd);
X					break;
X				case 'g':	/* screen dump */
X				case 'G':
X					screen_dump();
X					status_line(" screen dump");
X					k = wait_key(stdscr, 2);
X					break;
X				case '1':	/* data logging */
X					input_status = data_logging(status->fd);
X					break;
X				case '2':	/* toggle log */
X					if (!strcmp(status->log_path, "NOT_DEFINED")) {
X						beep();
X						status_line(" no log file");
X						k = wait_key(stdscr, 2);
X						break;
X					}
X					status->log = status->log ? 0 : 1;
X					if (status->pid != -1)
X						kill(status->pid, SIGUSR1);
X	
X						/* show changes */
X					status_line(NULL);
X					k = wait_key(stdscr, 2);
X					break;
X				default:
X					fputc(7, stderr);
X					break;
X			}
X
X			/*
X			 * Repaint the stdscr (if we are already talking),
X			 * get the terminal out of the curses mode and
X			 * into the raw mode.
X			 */
X			if (status->fd != -1) {
X				touchwin(stdscr);
X				refresh();
X			}
X			resetterm();
X			cr_lf = raw_mode();
X					/* re-start input routine */
X			if (input_status)
X				input_on();
X			else {
X					/* un-suspend (is that a word?) */
X				if (status->pid != -1)
X					kill(status->pid, SIGINT);
X			}
X			/*
X			 * If you pressed a key during one of the sleeping
X			 * periods (typically the delay to see the status
X			 * line change), let the keyboard value fall thru
X			 * to the write() below.
X			 */
X			if (k == -1)
X				continue;
X			c = k;
X		}
X		write(status->fd, &c, 1);
X					/* map cr to cr_lf ? */
X		if (cr_lf)
X			write(status->fd, &lf, 1);
X	}
X}
X
X/*
X * Put the terminal in the raw mode.  We've divided up the responsibility
X * for the line settings options between the serial port and the tty driver
X * for the stdin and stdout.  The return code is the cr_lf mapping.
X */
X
Xint
Xraw_mode()
X{
X	int ret_code;
X	struct termio tbuf;
X
X	ioctl(0, TCGETA, &tbuf);
X
X	tbuf.c_cc[4] = 1;		/* VMIN */
X	tbuf.c_cc[5] = 0;		/* VTIME */
X	tbuf.c_iflag = 0;
X	tbuf.c_oflag = 0;
X	tbuf.c_lflag = 0;
X
X	/*
X	 * Some of the output processing options have to be faked...
X	 * Unfortunately, adding a LF to CR is one of them.
X	 */
X	ret_code = 0;
X	if (!strcmp(param->cr_out, "CR/LF"))
X		ret_code++;
X					/* duplex */
X	if (dir->duplex[dir->d_cur] == 'H')
X		tbuf.c_lflag = ECHO;
X
X	ioctl(0, TCSETA, &tbuf);
X	ioctl(0, TCFLSH, 2);
X	return(ret_code);
X}
X
X/*
X * Fire up the input routine...
X */
X
Xvoid
Xinput_on()
X{
X	int pid, add_lf;
X					/* if no tty, or already on */
X	if (status->pid != -1 || status->fd == -1)
X		return;
X					/* input cr translations */
X	add_lf = !strcmp(param->cr_in, "CR/LF");
X
X					/* fork the input routine */
X	if (!(pid = fork()))
X		input(status->fd, add_lf, status->log, status->print,
X		 LINES, COLS, status->vs_path, status->log_path);
X
X	status->pid = pid;
X	return;
X}
X
X/*
X * shut it down...
X */
X
Xvoid
Xinput_off()
X{
X	if (status->pid != -1) {
X		kill(status->pid, SIGTERM);
X		status->pid = -1;
X	}
X	return;
X}
X
X/*
X * Hang up the phone but remain in the pcomm command state.
X */
X
Xvoid
Xhang_up(verbose)
Xint verbose;
X{
X	void send_str(), status_line();
X#ifdef UNIXPC
X	char buf[20], *strcpy(), *strcat();
X#endif /* UNIXPC */
X
X					/* anything to hang up? */
X	if (modem->m_cur == -1)
X		return;
X
X	if (verbose)
X		status_line("disconnecting");
X					/* special case for OBM */
X#ifdef UNIXPC
X	if (!strcmp(modem->mname[modem->m_cur], "OBM")) {
X		ioctl(status->fd, PIOCDISC);
X		/*
X		 * The PIOCDISC ioctl prevents writes on the file descriptor!
X		 * No other phone(7) ioctl can fix it...  Whatever it does, it
X		 * seems to escape detection with PIOCGETA and TCGETA.  The
X		 * best I can do is close the descriptor and start over.
X		 */
X		close(status->fd);
X		strcpy(buf, "/dev/");
X		strcat(buf, modem->tty[modem->t_cur]);
X		status->fd = open(buf, O_RDWR|O_NDELAY);
X		fcntl(status->fd, F_SETFL, fcntl(status->fd, F_GETFL, 0) & ~O_NDELAY);
X	}
X	else
X#endif /* UNIXPC */
X		send_str(modem->hangup[modem->m_cur]);
X
X	if (verbose)
X		status_line(NULL);
X	return;
X}
SHAR_EOF
if test 8039 -ne "`wc -c < 'terminal.c'`"
then
	echo shar: "error transmitting 'terminal.c'" '(should have been 8039 characters)'
fi
fi
echo shar: "extracting 'x_ascii.c'" '(5950 characters)'
if test -f 'x_ascii.c'
then
	echo shar: "will not over-write existing file 'x_ascii.c'"
else
sed 's/^X//' << \SHAR_EOF > 'x_ascii.c'
X/*
X * Transfer a file using just XON/XOFF flow control.  Currently limited to
X * 7 bit ASCII codes. (If this causes too much trouble, I'll change it).
X */
X
X#include <stdio.h>
X#include <fcntl.h>
X#include <curses.h>
X#include <signal.h>
X#include "param.h"
X#include "status.h"
X
Xvoid
Xxfer_ascii(list, up)
Xchar *list;
Xint up;
X{
X	int cr_lf;
X	char *file, *strtok();
X	void send_ascii(), rcv_ascii(), line_set(), status_line();
X	unsigned int sleep();
X
X					/* only one file from list */
X	file = strtok(list, " 	");
X
X	cr_lf = ascii_mode(up);
X	if (up) {
X					/* un-suspend the input routine */
X		if (status->pid != -1)
X			kill(status->pid, SIGINT);
X
X		send_ascii(file, cr_lf);
X					/* re-suspend the input routine */
X		if (status->pid != -1)
X			kill(status->pid, SIGINT);
X	}
X	else
X		rcv_ascii(file, cr_lf);
X
X	/*
X	 * Restoring the tty modes is easier than setting them... The
X	 * fixterm() and line_set() routines fix most of the damage.
X	 */
X	fcntl(0, F_SETFL, fcntl(0, F_GETFL, 0) & ~O_NDELAY);
X	fixterm();
X	line_set();
X	sleep(1);
X
X	status_line("xfer complete");
X	sleep(2);
X	return;
X}
X
X/*
X * Put the tty line in a mode suitable for the ASCII transfer.  Puts the
X * terminal in the raw, non-blocking mode.  Returns the status of the
X * cr_lf parameter flag.
X */
X
Xint
Xascii_mode(up)
Xint up;
X{
X	int cr_lf;
X	struct termio tbuf;
X	void input_off();
X
X	ioctl(status->fd, TCGETA, &tbuf);
X	tbuf.c_oflag = 0;
X					/* flow control & 8th bit stripping */
X	if (up) {
X		tbuf.c_iflag = (ISTRIP|IXON|IXANY);
X
X					/* use NL delays if no CR */
X		if (!strcmp(param->cr_up, "STRIP"))
X			tbuf.c_oflag = (OPOST|ONLRET);
X
X					/* CR delay times */
X		switch (param->cr_delay) {
X			case 0:
X				tbuf.c_oflag = 0;
X				break;
X			case 100:
X				tbuf.c_oflag |= (OPOST|CR2);
X				break;
X			case 150:
X				tbuf.c_oflag |= (OPOST|CR3);
X				break;
X		}
X	}
X					/* if down loading */
X	else {
X		tbuf.c_iflag = (ISTRIP|IXOFF);
X					/* kill the input routine */
X		input_off();
X	}
X
X	ioctl(status->fd, TCSETA, &tbuf);
X	ioctl(status->fd, TCFLSH, 2);
X					/* out of curses mode */
X	resetterm();
X	cr_lf = raw_mode();
X					/* non-blocking mode */
X	fcntl(0, F_SETFL, fcntl(0, F_GETFL, 0) | O_NDELAY);
X	return(cr_lf);
X}
X	
X/*
X * Send a file.  The local echo option is independent of the duplex option,
X * and would very rarely be used since the characters are most likely
X * being echoed on the screen anyway.
X */
X
Xvoid
Xsend_ascii(file, cr_lf)
Xchar *file;
Xint cr_lf;
X{
X	FILE *fp;
X	int i, j, strip_cr, strip_lf, add_cr, add_lf, expand, last;
X	int lecho, pace;
X	unsigned int sleep();
X	unsigned char c;
X					/* permission already checked */
X	if (!(fp = fopen(file, "r")))
X		return;
X					/* ASCII transfer options */
X	strip_cr = !strcmp(param->cr_up, "STRIP");
X	add_lf = !strcmp(param->cr_up, "ADD LF");
X	strip_lf = !strcmp(param->lf_up, "STRIP");
X	add_cr = !strcmp(param->lf_up, "ADD CR");
X	expand = !strcmp(param->expand, "YES");
X	lecho = !strcmp(param->lecho, "YES");
X	pace = !strcmp(param->pace, "YES");
X
X	last = 0;
X	while ((i = fgetc(fp)) != EOF) {
X					/* any keyboard activity? */
X		switch(j = getchar()) {
X			case -1:	/* no key was pressed */
X				break;
X			case 27:	/* ESC key for abort */
X				fclose(fp);
X				ioctl(status->fd, TCFLSH, 2);
X				return;
X			default:	/* send the char */
X				c = j;
X				putc_line(c);
X				if (c == 13 && cr_lf)
X					putc_line(10);
X				break;
X		}
X		c = i;
X					/* expand blank lines */
X		if (expand && last == 10 && c == 10)
X			putc_line(' ');
X		last = c;
X
X					/* CR translations */
X		if (c == 13 && strip_cr)
X			continue;
X		if (c == 13 && add_lf) {
X			putc_line(c);
X			putc_line(10);
X			continue;
X		}
X					/* LF translations */
X		if (c == 10 && strip_lf)
X			continue;
X		if (c == 10 && add_cr) {
X			putc_line(13);
X			putc_line(c);
X			continue;
X		}
X		putc_line(c);
X		/*
X		 * There's really no mechanism for delaying characters
X		 * going to the output, so we fake it by waiting for
X		 * each character to clear the I/O buffer.
X		 */
X		if (pace)
X			ioctl(status->fd, TCSBRK, 1);
X		if (lecho)
X			write(1, (char *) &c, 1);
X	}
X	sleep(1);
X	ioctl(status->fd, TCSBRK, 1);
X	fclose(fp);
X	return;
X}
X
X/*
X * Receive a file.  The timer is used to end the transfer.  This is not
X * that much different from the data logging option.  The use of getc_line()
X * and non-blocking input makes it seem like full duplex, but it's not.
X * Beware that while the timer is active the keyboard is deaf.  Input is
X * NOT loaded into the virtual screen!!
X */
X
Xvoid
Xrcv_ascii(file, cr_lf)
Xchar *file;
Xint cr_lf;
X{
X	FILE *fp;
X	int i, strip_cr, strip_lf, add_cr, add_lf, got_first;
X	unsigned int delay;
X	unsigned char c;
X					/* permission already checked */
X	if (!(fp = fopen(file, "w")))
X		return;
X					/* ASCII transfer options */
X	strip_cr = !strcmp(param->cr_dn, "STRIP");
X	add_lf = !strcmp(param->cr_dn, "ADD LF");
X	strip_lf = !strcmp(param->lf_dn, "STRIP");
X	add_cr = !strcmp(param->lf_dn, "ADD CR");
X
X	got_first = 0;
X	delay = 1;
X	while (1) {
X					/* keyboard activity */
X		switch (i = getchar()) {
X			case -1:	/* no key was pressed */
X				break;
X			case 27:	/* ESC key */
X				fclose(fp);
X				return;
X			default:	/* send it */
X				c = i;
X				putc_line(c);
X				if (c == 13 && cr_lf)
X					putc_line(10);
X				break;
X		}
X					/* read a character */
X		if ((i = getc_line(delay)) == -1) {
X			/*
X			 * The transfer timeout is not activated until the
X			 * first character is received.  Until then, it polls
X			 * the line for one second and loops backs for
X			 * keyboard input.
X			 */
X			if (got_first) {
X				fclose(fp);
X				return;
X			}
X			continue;
X		}
X		got_first = 1;
X		delay = param->timer;
X		c = i & 0177;
X					/* display it on the screen */
X		write(1, (char *) &c, 1);
X					/* CR translations */
X		if (c == 13 && strip_cr)
X			continue;
X		if (c == 13 && add_lf) {
X			fputc((char) c, fp);
X			fputc(10, fp);
X			continue;
X		}
X					/* LF translations */
X		if (c == 10 && strip_lf)
X			continue;
X		if (c == 10 && add_cr) {
X			fputc(13, fp);
X			fputc((char) c, fp);
X			continue;
X		}
X		fputc((char) c, fp);
X	}
X}
SHAR_EOF
if test 5950 -ne "`wc -c < 'x_ascii.c'`"
then
	echo shar: "error transmitting 'x_ascii.c'" '(should have been 5950 characters)'
fi
fi
exit 0
#	End of shell archive

egray@fthood.UUCP (03/14/88)

This is part 4 (of 6) to the Pcomm version 1.0 distribution.

Emmet P. Gray				US Army, HQ III Corps & Fort Hood
...!ihnp4!uiucuxc!fthood!egray		Attn: AFZF-DE-ENV
					Directorate of Engineering & Housing
					Environmental Management Office
					Fort Hood, TX 76544-5057

-------------------------------------------------------------------------------
#! /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:
#	input.c
#	line_set.c
#	list_dir.c
#	ls_menu.c
#	m_lib.c
#	main.c
#	n_shell.c
#	p_lib.c
#	pexit.c
#	port.c
#	redial.c
# This archive created: Fri Mar 11 07:35:16 1988
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'input.c'" '(6599 characters)'
if test -f 'input.c'
then
	echo shar: "will not over-write existing file 'input.c'"
else
sed 's/^X//' << \SHAR_EOF > 'input.c'
X/*
X * The input routines.  These routines are run as a child process to the
X * main pcomm program.
X */
X
X#define LPR "/usr/bin/lpr"
X
X#define MAX_ROW	64
X#define MAX_COL	128
X
X#include <stdio.h>
X#include <signal.h>
X#include <setjmp.h>
X
Xjmp_buf i_jmp;
Xunsigned char vs[MAX_ROW][MAX_COL+2];
Xint row, col;
X
X/*
X * Read the serial port and write the characters to the screen.  Watch
X * for signals from the parent process to toggle the fancy options.
X * Writes the characters received to a virtual screen buffer.
X */
Xint
Xinput(fd, add_lf, log, print, max_row, max_col, vs_file, log_file)
Xint fd, add_lf, log, print, max_row, max_col;
Xchar *vs_file, *log_file;
X{
X	FILE *logfp, *lprfp, *popen();
X	int hold, skip_row, got_sig();
X	unsigned char c;
X	char lf=10;
X	void _exit();
X					/* set the trap for the signals */
X	signal(SIGALRM, SIG_IGN);
X	signal(SIGUSR1, got_sig);
X	signal(SIGUSR2, got_sig);
X	signal(SIGINT,  got_sig);
X	signal(SIGTERM, got_sig);
X					/* resonable limits */
X	if (max_row > MAX_ROW)
X		max_row = MAX_ROW;
X	if (max_col > MAX_COL)
X		max_col = MAX_COL;
X					/* read previous screen */
X	if (!access(vs_file, 0)) {
X		read_vs(vs_file, max_row, max_col);
X		skip_row = 0;
X	}
X	else 
X		skip_row = 1;
X
X	hold = 0;
X					/* startup file pointers */
X	if (print)
X		lprfp = popen(LPR, "w");
X
X	if (log && strcmp(log_file, "NOT_DEFINED"))
X		logfp = fopen(log_file, "a");
X
X	switch(setjmp(i_jmp)) {
X		case 0:			/* no signal */
X			break;
X		case 1:			/* toggle the data logging */
X			signal(SIGUSR1, got_sig);
X			if (!strcmp(log_file, "NOT_DEFINED")) {
X				log = 0;
X				break;
X			}
X			log = log ? 0 : 1;
X			if (log)
X				logfp = fopen(log_file, "a");
X			else
X				fclose(logfp);
X			break;
X		case 2:			/* toggle the printer */
X			signal(SIGUSR2, got_sig);
X			print = print ? 0 : 1;
X			if (print)
X				lprfp = popen(LPR, "w");
X			else {
X				putc(014, lprfp);
X				pclose(lprfp);
X			}
X			break;
X		case 3:			/* suspend the input */
X			signal(SIGINT, got_sig);
X			hold = hold ? 0 : 1;
X			if (hold)
X				write_vs(vs_file, max_row, max_col);
X			break;
X		case 4:			/* cleanup and go home */
X			signal(SIGTERM, got_sig);
X			if (log)
X				fclose(logfp);
X			if (print) {
X				putc(014, lprfp);
X				pclose(lprfp);
X			}
X			_exit(0);
X			break;
X	}
X					/* any signal will awaken pause() */
X	if (hold)
X		pause();
X					/* clear if vs_path doesn't exist */
X	if (access(vs_file, 0))
X		clear_vs(max_row, max_col);
X	/*
X	 * The very first screen we see after dialing has the "Connected to..."
X	 * message at row 0, therefore we start our virtual screen at row 1.
X	 */
X	if (skip_row) {
X		skip_row = 0;
X		row = 1;
X	}
X
X	while(1) {
X		if (read(fd, (char *) &c, 1) <= 0)
X			continue;
X					/* send to logfile */
X		if (log) {
X			if (c == 015 && add_lf)
X				fwrite(&lf, 1, 1, logfp);
X					/* no carriage returns in logfile */
X			if (c != 015)
X				fwrite((char *) &c, 1, 1, logfp);
X		}
X					/* send to printer too ? */
X		if (print)
X			fwrite((char *) &c, 1, 1, lprfp);
X
X					/* put a char in virtual screen */
X		putchar_vs(c, add_lf, max_row, max_col);
X
X		write(1, (char *) &c, 1);
X					/* add LF to CR ? */
X		if (add_lf)
X			write(1, &lf, 1);
X	}
X}
X
X/*
X * Figure out which signal we just received, and fix the return code of
X * the setjmp function above to the proper value.
X */
X
Xint
Xgot_sig(sig)
Xint sig;
X{
X	void longjmp();
X
X	switch(sig) {
X		case SIGUSR1:
X			longjmp(i_jmp, 1);
X		case SIGUSR2:
X			longjmp(i_jmp, 2);
X		case SIGINT:
X			longjmp(i_jmp, 3);
X		case SIGTERM:
X			longjmp(i_jmp, 4);
X	}
X}
X
X/*
X * Put a character in the virtual screen.  This routine saves incoming
X * character in a two dimensional buffer designed to mimic the real
X * screen.  CURRENTLY DOES NOT UNDERSTAND ESCAPE SEQUENCES!
X */
X
Xint
Xputchar_vs(c, add_lf, max_row, max_col)
Xunsigned char c;
Xint add_lf, max_row, max_col;
X{
X	int tab_stop;
X
X	switch(c) {
X		case 8:			/* destructive back space */
X			col--;
X			if (col < 0)
X				col = 0;
X			vs[row][col] = ' ';
X			break;
X		case 9:			/* tab character */
X			tab_stop = col + 8 - (col % 8);
X					/* if wrap around */
X			if (tab_stop >= max_col) {
X					/* spaces up to eol */
X				for (; col<max_col; col++)
X					vs[row][col] = ' ';
X				row++;
X				if (row >= max_row)
X					scroll_vs(max_row, max_col);
X
X					/* the remainder of the tab */
X				col = tab_stop - max_col;
X			}
X			else {
X				for (; col<tab_stop; col++)
X					vs[row][col] = ' ';
X			}
X			break;
X		case 13:		/* carriage return */
X			col = 0;
X			if (!add_lf)
X				break;
X			/* fall thru...*/
X		case 10:		/* line feed */
X			row++;
X			if (row >= max_row)
X				scroll_vs(max_row, max_col);
X			break;
X		default:		/* a normal character */
X			vs[row][col] = c;
X			col++;
X					/* wrap around */
X			if (col >= max_col) {
X				col = 0;
X				row++;
X				if (row >= max_row)
X					scroll_vs(max_row, max_col);
X			}
X			break;
X	}
X	return;
X}
X
X/*
X * Save the virtual screen to a file.
X */
X
Xint
Xwrite_vs(vs_file, max_row, max_col)
Xchar *vs_file;
Xint max_row, max_col;
X{
X	FILE *fp;
X	int i;
X
X	if (!(fp = fopen(vs_file, "w")))
X		return(1);
X					/* current x y coordinates */
X	fprintf(fp, "%d,%d\n", row, col);
X
X	for (i=0; i<max_row; i++) {
X		vs[i][max_col] = NULL;
X		fprintf(fp, "%s\n", vs[i]);
X	}
X	fclose(fp);
X	return(0);
X}
X
X/*
X * Get the virtual screen image from the file.  Since input() gets
X * killed from time to time, the vs_path file is the only way to retain
X * the screen image.
X */
X
Xint
Xread_vs(vs_file, max_row, max_col)
Xchar *vs_file;
Xint max_row, max_col;
X{
X	FILE *fp;
X	int i;
X	char buf[10];
X				/* in case the fopen fails... */
X	row = 0;
X	col = 0;
X				/* not guaranteed to exist yet */
X	if (!(fp = fopen(vs_file, "r")))
X		return(1);
X				/* get the x, y coordinates */
X	fgets(buf, 10, fp);
X	scanf(buf, "%d,%d\n", &row, &col);
X
X				/* read the file into the vs array */
X	for (i=0; i<max_row; i++) {
X		fgets((char *) vs[i], MAX_COL+2, fp);
X		vs[i][max_col] = NULL;
X	}
X
X	fclose(fp);
X	return(0);
X}
X
X/*
X * If the user clears the screen with the ^A-C command, the input
X * has to be in sync.  The way it gets notified, is that the vs_path
X * file disappears.
X */
X
Xint
Xclear_vs(max_row, max_col)
Xint max_row, max_col;
X{
X	int i, j;
X
X	for (i=0; i<max_row; i++) {
X		vs[i][max_col] = NULL;
X		for (j=0; j<max_col; j++)
X			vs[i][j] = ' ';
X	}
X					/* home the "cursor" */
X	row = 0;
X	col = 0;
X	return(0);
X}
X
X/*
X * Do a software scroll on the virtual screen.  Does not alter the
X * 'col' variable.
X */
X
Xint
Xscroll_vs(max_row, max_col)
Xint max_row, max_col;
X{
X	int i, j;
X	char *strcpy();
X					/* move 'em up 1 line */
X	for (i=0; i<max_row-1; i++)
X		strcpy((char *) vs[i], (char *) vs[i+1]);
X					/* clear the bottom line */
X	for (j=0; j<max_col; j++)
X		vs[max_row-1][j] = ' ';
X
X	row = max_row -1;
X	return(0);
X}
SHAR_EOF
if test 6599 -ne "`wc -c < 'input.c'`"
then
	echo shar: "error transmitting 'input.c'" '(should have been 6599 characters)'
fi
fi
echo shar: "extracting 'line_set.c'" '(2130 characters)'
if test -f 'line_set.c'
then
	echo shar: "will not over-write existing file 'line_set.c'"
else
sed 's/^X//' << \SHAR_EOF > 'line_set.c'
X/*
X * Change the communication line settings to the new values.
X */
X
X#include <stdio.h>
X#include <termio.h>
X#include "dial_dir.h"
X#include "param.h"
X#include "status.h"
X
Xvoid
Xline_set()
X{
X	struct termio tbuf;
X
X	/*
X	 * The manual dial entry also serves to store the previous
X	 * line settings.  How else would the manual dial entry
X	 * know what line setting to use?
X	 */
X	if (dir->d_cur != 0) {
X		dir->baud[0] = dir->baud[dir->d_cur];
X		dir->parity[0] = dir->parity[dir->d_cur];
X		dir->dbits[0] = dir->dbits[dir->d_cur];
X		dir->sbits[0] = dir->sbits[dir->d_cur];
X	}
X					/* nothing to do! */
X	if (status->fd == -1)
X		return;
X					/* get the current settings */
X	ioctl(status->fd, TCGETA, &tbuf);
X					/* set some beginning values */
X	tbuf.c_cc[4] = 1;
X	tbuf.c_cc[5] = 0;
X	tbuf.c_oflag = 0;
X	tbuf.c_iflag = 0;
X	tbuf.c_cflag = (CREAD|HUPCL);
X	tbuf.c_lflag = 0;
X
X	/*
X	 * I don't think there's any need for output flow control... (I don't
X	 * know about you guys, but I can't type faster than the host can
X	 * receive!)  Besides, the file transfers reset this anyway.
X	 */
X	if (*param->flow == 'X')
X		tbuf.c_iflag |= IXOFF;
X					/* strip high bit ? */
X	if (*param->strip == 'Y')
X		tbuf.c_iflag |= ISTRIP;
X					/* the baud rate */
X	switch (dir->baud[dir->d_cur]) {
X		case 300:
X			tbuf.c_cflag |= B300;
X			break;
X		case 1200:
X			tbuf.c_cflag |= B1200;
X			break;
X		case 2400:
X			tbuf.c_cflag |= B2400;
X			break;
X		case 4800:
X			tbuf.c_cflag |= B4800;
X			break;
X		case 9600:
X			tbuf.c_cflag |= B9600;
X			break;
X		case 19200:
X			/*
X			 * Be careful here... some systems use EXTA in lieu
X			 * of B19200.
X			 */
X			tbuf.c_cflag |= B19200;
X			break;
X	}
X					/* the parity */
X	switch (dir->parity[dir->d_cur]) {
X		case 'N':
X			break;
X		case 'O':
X			tbuf.c_cflag |= (PARENB|PARODD);
X			break;
X		case 'E':
X			tbuf.c_cflag |= PARENB;
X			break;
X	}
X					/* the data bits */
X	if (dir->dbits[dir->d_cur] == 8)
X		tbuf.c_cflag |= CS8;
X	else
X		tbuf.c_cflag |= CS7;
X					/* the stop bits */
X	if (dir->sbits[dir->d_cur] == 2)
X		tbuf.c_cflag |= CSTOPB;
X
X					/* now set 'em! */
X	ioctl(status->fd, TCSETA, &tbuf);
X	ioctl(status->fd, TCFLSH, 2);
X	return;
X}
SHAR_EOF
if test 2130 -ne "`wc -c < 'line_set.c'`"
then
	echo shar: "error transmitting 'line_set.c'" '(should have been 2130 characters)'
fi
fi
echo shar: "extracting 'list_dir.c'" '(1479 characters)'
if test -f 'list_dir.c'
then
	echo shar: "will not over-write existing file 'list_dir.c'"
else
sed 's/^X//' << \SHAR_EOF > 'list_dir.c'
X/*
X * Do a shell escape with an 'ls' command
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include "misc.h"
X
Xvoid
Xlist_dir(fd)
Xint fd;
X{
X	WINDOW *ls_win, *newwin();
X	FILE *pfp, *native_popen();
X	int lines, oops;
X	char *ans, *cwd, *getcwd(), buf[200], *get_str();
X
X	ls_win = newwin(6, 70, 8, 5);
X
X	cwd = getcwd(buf, 200);
X
X	mvwprintw(ls_win, 2, 4, "Current directory: %s", cwd);
X	mvwaddstr(ls_win, 3, 4, "File spec (wildcards allowed): ");
X	box(ls_win, '|', '-');
X
X	mvwattrstr(ls_win, 0, 3, A_BOLD, " List Directory ");
X	wmove(ls_win, 3, 35);
X	wrefresh(ls_win);
X
X	if ((ans = get_str(ls_win, 60, NULL, NULL)) == NULL) {
X		if (fd == -1) {
X			werase(ls_win);
X			wrefresh(ls_win);
X		}
X		delwin(ls_win);
X		return;
X	}
X					/* popen() an ls */
X	sprintf(buf, "ls -aC %s", ans);
X	pfp = native_popen(buf, "r");
X					/* make a bigger window */
X	werase(ls_win);
X	wrefresh(ls_win);
X	delwin(ls_win);
X	ls_win = newwin(LINES-1, COLS, 0, 0);
X
X	oops = 0;
X	lines = 0;
X	while (fgets(buf, BUFSIZ, pfp) != NULL) {
X		waddstr(ls_win, buf);
X		lines++;
X		if (lines == LINES-2) {
X			lines = 0;
X			mvwaddstr(ls_win, LINES-2, 28, "Press any key for more");
X			wrefresh(ls_win);
X			if (wgetch(ls_win) == 27) {
X				oops++;
X				break;
X			}
X			werase(ls_win);
X			wrefresh(ls_win);
X		}
X	}
X	native_pclose(pfp);
X
X	if (!oops) {
X		mvwaddstr(ls_win, LINES-2, 25, "Press any key to continue");
X		wrefresh(ls_win);
X		wgetch(ls_win);
X	}
X	if (fd == -1) {
X		werase(ls_win);
X		wrefresh(ls_win);
X	}
X	delwin(ls_win);
X	return;
X}
SHAR_EOF
if test 1479 -ne "`wc -c < 'list_dir.c'`"
then
	echo shar: "error transmitting 'list_dir.c'" '(should have been 1479 characters)'
fi
fi
echo shar: "extracting 'ls_menu.c'" '(4820 characters)'
if test -f 'ls_menu.c'
then
	echo shar: "will not over-write existing file 'ls_menu.c'"
else
sed 's/^X//' << \SHAR_EOF > 'ls_menu.c'
X/*
X * Routines for displaying current line settings and prompting for changes.
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include "dial_dir.h"
X#include "misc.h"
X#include "param.h"
X
X/*
X * Display the current line settings and prompt for changes.  A return
X * code of 1 means settings were changed.
X */
X
Xint
Xline_set_menu(fd)
Xint fd;
X{
X	WINDOW *l_win, *newwin();
X	int num, ret_code;
X	void disp_settings();
X
X	l_win = newwin(20, 47, 0, 16);
X
X	mvwattrstr(l_win, 1, 16, A_BOLD, "Line Settings");
X	waddstr(l_win, "\n----------------------------------------------");
X	mvwaddstr(l_win, 6, 5, "1)     300,E,7,1     7)     300,N,8,1");
X	mvwaddstr(l_win, 7, 5, "2)    1200,E,7,1     8)    1200,N,8,1");
X	mvwaddstr(l_win, 8, 5, "3)    2400,E,7,1     9)    2400,N,8,1");
X	mvwaddstr(l_win, 9, 5, "4)    4800,E,7,1    10)    4800,N,8,1");
X	mvwaddstr(l_win, 10, 5, "5)    9600,E,7,1    11)    9600,N,8,1");
X	mvwaddstr(l_win, 11, 5, "6)   19200,E,7,1    12)   19200,N,8,1");
X	mvwaddstr(l_win, 13, 4, "Parity        Data Bits       Stop Bits");
X	mvwaddstr(l_win, 14, 4, "13) Odd       14) 7 bits      16) 1 bit");
X	mvwaddstr(l_win, 15, 18, "15) 8 bits      17) 2 bits");
X	mvwaddstr(l_win, 17, 4, "18) Save Changes");
X	mvwattrstr(l_win, 17, 28, A_BOLD, "YOUR CHOICE:");
X	wmove(l_win, 17, 41);
X	box(l_win, '|', '-');
X
X	mvwaddstr(l_win, 19, 14, " Press ESC to return ");
X					/* display current settings */
X	disp_settings(l_win);
X	wmove(l_win, 17, 41);
X	wrefresh(l_win);
X					/* get the options */
X	ret_code = 0;
X	while ((num = get_num(l_win, 2)) != -1) {
X		switch(num) {
X			case 1:
X				dir->baud[dir->d_cur] = 300;
X				dir->parity[dir->d_cur] = 'E';
X				dir->dbits[dir->d_cur] = 7;
X				dir->sbits[dir->d_cur] = 1;
X				break;
X			case 2:
X				dir->baud[dir->d_cur] = 1200;
X				dir->parity[dir->d_cur] = 'E';
X				dir->dbits[dir->d_cur] = 7;
X				dir->sbits[dir->d_cur] = 1;
X				break;
X			case 3:
X				dir->baud[dir->d_cur] = 2400;
X				dir->parity[dir->d_cur] = 'E';
X				dir->dbits[dir->d_cur] = 7;
X				dir->sbits[dir->d_cur] = 1;
X				break;
X			case 4:
X				dir->baud[dir->d_cur] = 4800;
X				dir->parity[dir->d_cur] = 'E';
X				dir->dbits[dir->d_cur] = 7;
X				dir->sbits[dir->d_cur] = 1;
X				break;
X			case 5:
X				dir->baud[dir->d_cur] = 9600;
X				dir->parity[dir->d_cur] = 'E';
X				dir->dbits[dir->d_cur] = 7;
X				dir->sbits[dir->d_cur] = 1;
X				break;
X			case 6:
X				dir->baud[dir->d_cur] = 19200;
X				dir->parity[dir->d_cur] = 'E';
X				dir->dbits[dir->d_cur] = 7;
X				dir->sbits[dir->d_cur] = 1;
X				break;
X			case 7:
X				dir->baud[dir->d_cur] = 300;
X				dir->parity[dir->d_cur] = 'N';
X				dir->dbits[dir->d_cur] = 8;
X				dir->sbits[dir->d_cur] = 1;
X				break;
X			case 8:
X				dir->baud[dir->d_cur] = 1200;
X				dir->parity[dir->d_cur] = 'N';
X				dir->dbits[dir->d_cur] = 8;
X				dir->sbits[dir->d_cur] = 1;
X				break;
X			case 9:
X				dir->baud[dir->d_cur] = 2400;
X				dir->parity[dir->d_cur] = 'N';
X				dir->dbits[dir->d_cur] = 8;
X				dir->sbits[dir->d_cur] = 1;
X				break;
X			case 10:
X				dir->baud[dir->d_cur] = 4800;
X				dir->parity[dir->d_cur] = 'N';
X				dir->dbits[dir->d_cur] = 8;
X				dir->sbits[dir->d_cur] = 1;
X				break;
X			case 11:
X				dir->baud[dir->d_cur] = 9600;
X				dir->parity[dir->d_cur] = 'N';
X				dir->dbits[dir->d_cur] = 8;
X				dir->sbits[dir->d_cur] = 1;
X				break;
X			case 12:
X				dir->baud[dir->d_cur] = 19200;
X				dir->parity[dir->d_cur] = 'N';
X				dir->dbits[dir->d_cur] = 8;
X				dir->sbits[dir->d_cur] = 1;
X				break;
X			case 13:
X				dir->parity[dir->d_cur] = 'O';
X				break;
X			case 14:
X				dir->dbits[dir->d_cur] = 7;
X				break;
X			case 15:
X				dir->dbits[dir->d_cur] = 8;
X				break;
X			case 16:
X				dir->sbits[dir->d_cur] = 1;
X				break;
X			case 17:
X				dir->sbits[dir->d_cur] = 2;
X				break;
X			case 18:
X					/* copy the current settings */
X				param->d_baud = dir->baud[dir->d_cur];
X				param->d_parity = dir->parity[dir->d_cur];
X				param->d_dbits = dir->dbits[dir->d_cur];
X				param->d_sbits = dir->sbits[dir->d_cur];
X				/*
X				 * We've changed the values in memory even
X				 * if the update fails.
X				 */
X				if (update_param()) {
X					touchwin(l_win);
X					wrefresh(l_win);
X				}
X				break;
X			default:
X				beep();
X		}
X		ret_code++;
X		disp_settings(l_win);
X		mvwaddstr(l_win, 17, 41, "    ");
X		wmove(l_win, 17, 41);
X		wrefresh(l_win);
X	}
X	if (fd == -1) {
X		werase(l_win);
X		wrefresh(l_win);
X	}
X	delwin(l_win);
X	return(ret_code);
X}
X
X/*
X * Display the current settings.  Formats the entire string at one
X * time, in case you've got a magic cookie terminal.
X */
X
Xvoid
Xdisp_settings(win)
XWINDOW *win;
X{
X	char buf[40];
X	extern int xmc;
X
X	sprintf(buf, "Current Settings: %5d,%c,%d,%d", dir->baud[dir->d_cur],
X	 dir->parity[dir->d_cur], dir->dbits[dir->d_cur],
X	 dir->sbits[dir->d_cur]);
X
X	if (xmc > 0) {
X		touchwin(win);
X		clear_line(win, 4, 8, 1);
X		wrefresh(win);
X	}
X	mvwattrstr(win, 4, 8, A_BOLD, buf);
X	return;
X}
SHAR_EOF
if test 4820 -ne "`wc -c < 'ls_menu.c'`"
then
	echo shar: "error transmitting 'ls_menu.c'" '(should have been 4820 characters)'
fi
fi
echo shar: "extracting 'm_lib.c'" '(9489 characters)'
if test -f 'm_lib.c'
then
	echo shar: "will not over-write existing file 'm_lib.c'"
else
sed 's/^X//' << \SHAR_EOF > 'm_lib.c'
X/*
X * Routines to manipulate the pcomm.modem file
X */
X
X#include <stdio.h>
X#include "modem.h"
X#include "status.h"
X
X/*
X * Read the modem database file.  Returns a pointer to a static area
X * containing the MODEM structure.  All modem entries and all tty entries
X * are created reguardless of the number of physical entries in the file.
X */
X
Xstruct MODEM *
Xread_modem()
X{
X	FILE *fp;
X	int i, tty, mod, line, oops, m_line, start, stop;
X	char *strdup(), buf[200], message[80], token[40], *str_tok(), *str;
X	char *temp_token, *t_sep, *m_sep, *m_letter;
X	static struct MODEM m;
X	void error_win();
X	extern char *null_ptr;
X
X	if (!(fp = fopen(status->m_path, "r"))) {
X		sprintf(buf, "'%s' for read", status->m_path);
X		error_win(1, "Can't open modem file", buf);
X	}
X
X	t_sep = ";;\n";
X	m_sep = ";;;;\n;;;;;\n;;;\n";
X	m_letter = "abc";
X	oops = 0;
X	tty = 0;
X	mod = 0;
X	line = 0;
X	m_line = 0;
X	while (fgets(buf, 200, fp) != NULL) {
X		line++;
X		if (tty >= NUM_TTY || mod >= NUM_MODEM)
X			break;
X					/* get the token */
X		if (!(temp_token = str_tok(buf, '='))) {
X			sprintf(message, "is missing a token at line %d", line);
X			oops++;
X			break;
X		}
X		if (*temp_token != 'T' && *temp_token != 'M') {
X			sprintf(message, "is corrupted at line %d", line);
X			oops++;
X			break;
X		}
X					/* the tty database */
X		if (*temp_token == 'T') {
X			/*
X			 * This is similar to the "real" strtok() command
X			 * but this one returns a null pointer on a missing
X			 * attribute.  Note the use of the field separator
X			 * array.
X			 */
X			for (i=0; i<3; i++) {
X				if (!(str = str_tok((char *) NULL, t_sep[i]))) {
X					sprintf(message, "is missing a parameter at line %d", line);
X					oops++;
X					break;
X				}
X				switch(i) {	
X					case 0:
X						m.tty[tty] = strdup(str);
X						break;
X					case 1:
X						m.tname[tty] = strdup(str);
X						break;
X					case 2:
X						m.mbaud[tty] = atoi(str);
X						break;
X				}
X			}
X			if (oops)
X				break;
X					/* sanity checking */
X			sprintf(token, "TTY_%d", tty+1);
X			if (strcmp(token, temp_token)) {
X				sprintf(message, "is corrupted at line %d", line);
X				oops++;
X				break;
X			}
X			tty++;
X			continue;
X		}
X					/* the modem database */
X		else {
X			sprintf(token, "MODEM_%d%c", mod+1, m_letter[m_line]);
X			if (strcmp(token, temp_token)) {
X				sprintf(message, "is corrupted at line %d", line);
X				oops++;
X				break;
X			}
X			/*
X			 * There are three lines to the modem database.  They
X			 * distinguished by the letters a, b, and, c appended
X			 * to the entry number.
X			 */
X			switch(m_line) {
X				case 0:
X					start = 0;
X					stop = 5;
X					break;
X				case 1:
X					start = 5;
X					stop = 11;
X					break;
X				case 2:
X					start = 11;
X					stop = 15;
X					break;
X			}
X			for (i=start; i<stop; i++) {
X				if (!(str = str_tok((char *) NULL, m_sep[i]))) {
X					sprintf(message, "is missing a parameter at line %d", line);
X					oops++;
X					break;
X				}
X				switch(i) {
X					case 0:
X						m.mname[mod] = strdup(str);
X						break;
X					case 1:
X						m.init[mod] = strdup(str);
X						break;
X					case 2:
X						m.dial[mod] = strdup(str);
X						break;
X					case 3:
X						m.suffix[mod] = strdup(str);
X						break;
X					case 4:
X						m.hangup[mod] = strdup(str);
X						break;
X					case 5:
X						m.con_3[mod] = strdup(str);
X						break;
X					case 6:
X						m.con_12[mod] = strdup(str);
X						break;
X					case 7:
X						m.con_24[mod] = strdup(str);
X						break;
X					case 8:
X						m.con_48[mod] = strdup(str);
X						break;
X					case 9:
X						m.con_96[mod] = strdup(str);
X						break;
X					case 10:
X						m.con_192[mod] = strdup(str);
X						break;
X					case 11:
X						m.no_con1[mod] = strdup(str);
X						break;
X					case 12:
X						m.no_con2[mod] = strdup(str);
X						break;
X					case 13:
X						m.no_con3[mod] = strdup(str);
X						break;
X					case 14:
X						m.no_con4[mod] = strdup(str);
X						break;
X				}
X			}
X			if (oops)
X				break;
X			m_line++;
X			if (m_line >= 3) {
X				m_line = 0;
X				mod++;
X			}
X		}
X	}
X	fclose(fp);
X
X	if (oops) {
X		sprintf(buf, "Modem file '%s'", status->m_path);
X		error_win(1, buf, message);
X	}
X	m.t_entries = tty;
X	m.m_entries = mod;
X	m.t_cur = -1;
X	m.m_cur = -1;
X					/* fill in the rest */
X	for (; tty<NUM_TTY; tty++) {
X		m.tty[tty] = null_ptr;
X		m.tname[tty] = null_ptr;
X		m.mbaud[tty] = 0;
X	}
X	for (; mod<NUM_MODEM; mod++) {
X		m.mname[mod] = null_ptr;
X		m.init[mod] = null_ptr;
X		m.dial[mod] = null_ptr;
X		m.suffix[mod] = null_ptr;
X		m.hangup[mod] = null_ptr;
X
X		m.con_3[mod] = null_ptr;
X		m.con_12[mod] = null_ptr;
X		m.con_24[mod] = null_ptr;
X		m.con_48[mod] = null_ptr;
X		m.con_96[mod] = null_ptr;
X		m.con_192[mod] = null_ptr;
X
X		m.no_con1[mod] = null_ptr;
X		m.no_con2[mod] = null_ptr;
X		m.no_con3[mod] = null_ptr;
X		m.no_con4[mod] = null_ptr;
X	}
X	return(&m);
X}
X
X/*
X * Update the modem database.  Other routines actually do the changes
X * or deletions in memory.  A return code of 1 means non-fatal error.
X */
X
Xint
Xupdate_modem()
X{
X	FILE *fp;
X	char buf[80];
X	int i;
X	void error_win();
X
X					/* open for write */
X	if (!(fp = fopen(status->m_path, "w"))) {
X		sprintf(buf, "'%s'", status->m_path);
X		error_win(0, "No write permission on modem file", buf);
X		return(1);
X	}
X					/* put back the tty entries */
X	for (i=0; i<modem->t_entries; i++)
X		fprintf(fp, "TTY_%d=%s;%s;%d\n", i+1, modem->tty[i],
X		 modem->tname[i], modem->mbaud[i]);
X
X					/* put back the modem entries */
X	for (i=0; i<modem->m_entries; i++) {
X		fprintf(fp, "MODEM_%da=%s;%s;%s;%s;%s\n", i+1, modem->mname[i],
X		 modem->init[i], modem->dial[i], modem->suffix[i],
X		 modem->hangup[i]);
X
X		fprintf(fp, "MODEM_%db=%s;%s;%s;%s;%s;%s\n", i+1,
X		 modem->con_3[i], modem->con_12[i], modem->con_24[i],
X		 modem->con_48[i], modem->con_96[i], modem->con_192[i]);
X
X		fprintf(fp, "MODEM_%dc=%s;%s;%s;%s\n", i+1, modem->no_con1[i],
X		 modem->no_con2[i], modem->no_con3[i], modem->no_con4[i]);
X	}
X
X	fclose(fp);
X	return(0);
X}
X
X/*
X * See if the new modem is already in the database.  If it's not,
X * then create a slot for it and update the modem->m_cur variable.
X */
X
Xvoid
Xcreate_modem(str)
Xchar *str;
X{
X	int i;
X	char *strdup(), buf[80];
X	void error_win(), free_ptr();
X					/* modem entry already exists? */
X	for (i=0; i<modem->m_entries; i++) {
X		if (!strcmp(str, modem->mname[i]))
X			return;
X	}
X					/* empty slot available? */
X	if (modem->m_entries == NUM_MODEM) {
X		sprintf(buf, "'%s'", status->m_path);
X		error_win(0, "No empty modem slots in", buf);
X		return;
X	}
X					/* create a new entry */
X	free_ptr(modem->mname[modem->m_entries]);
X	modem->mname[modem->m_entries] = strdup(str);
X
X					/* update number of entries */
X	modem->m_entries++;
X	return;
X}
X
X/*
X * See if the modem names in the list still need to be in the database.
X * If you find a "lost" entry, delete it and collapse the list.
X */
X
Xvoid
Xdelete_modem()
X{
X	int i, j, match;
X	char *strdup();
X	void free_ptr();
X	extern char *null_ptr;
X
X	for (i=0; i<modem->m_entries; i++) {
X		match = 0;
X		for (j=0; j<modem->t_entries; j++) {
X			if (!strcmp(modem->mname[i], modem->tname[j])) {
X				match = 1;
X				break;
X			}
X		}
X					/* found a "lost" modem name */
X		if (!match) {
X			for (j=i; j<modem->m_entries-1; j++) {
X				free_ptr(modem->mname[j]);
X				free_ptr(modem->init[j]);
X				free_ptr(modem->dial[j]);
X				free_ptr(modem->suffix[j]);
X				free_ptr(modem->hangup[j]);
X
X				free_ptr(modem->con_3[j]);
X				free_ptr(modem->con_12[j]);
X				free_ptr(modem->con_24[j]);
X				free_ptr(modem->con_48[j]);
X				free_ptr(modem->con_96[j]);
X				free_ptr(modem->con_192[j]);
X
X				free_ptr(modem->no_con1[j]);
X				free_ptr(modem->no_con2[j]);
X				free_ptr(modem->no_con3[j]);
X				free_ptr(modem->no_con4[j]);
X
X					/* copy the info */
X				modem->mname[j] = strdup(modem->mname[j+1]);
X				modem->init[j] = strdup(modem->init[j+1]);
X				modem->dial[j] = strdup(modem->dial[j+1]);
X				modem->suffix[j] = strdup(modem->suffix[j+1]);
X				modem->hangup[j] = strdup(modem->hangup[j+1]);
X
X				modem->con_3[j] = strdup(modem->con_3[j+1]);
X				modem->con_12[j] = strdup(modem->con_12[j+1]);
X				modem->con_24[j] = strdup(modem->con_24[j+1]);
X				modem->con_48[j] = strdup(modem->con_48[j+1]);
X				modem->con_96[j] = strdup(modem->con_96[j+1]);
X				modem->con_192[j] = strdup(modem->con_192[j+1]);
X
X				modem->no_con1[j] = strdup(modem->no_con1[j+1]);
X				modem->no_con2[j] = strdup(modem->no_con2[j+1]);
X				modem->no_con3[j] = strdup(modem->no_con3[j+1]);
X				modem->no_con4[j] = strdup(modem->no_con4[j+1]);
X			}
X			j = modem->m_entries -1;
X
X			free_ptr(modem->mname[j]);
X			free_ptr(modem->init[j]);
X			free_ptr(modem->dial[j]);
X			free_ptr(modem->suffix[j]);
X			free_ptr(modem->hangup[j]);
X
X			free_ptr(modem->con_3[j]);
X			free_ptr(modem->con_12[j]);
X			free_ptr(modem->con_24[j]);
X			free_ptr(modem->con_48[j]);
X			free_ptr(modem->con_96[j]);
X			free_ptr(modem->con_192[j]);
X
X			free_ptr(modem->no_con1[j]);
X			free_ptr(modem->no_con2[j]);
X			free_ptr(modem->no_con3[j]);
X			free_ptr(modem->no_con4[j]);
X
X					/* create an empty entry */
X			modem->mname[j] = null_ptr;
X			modem->init[j] = null_ptr;
X			modem->dial[j] = null_ptr;
X			modem->suffix[j] = null_ptr;
X			modem->hangup[j] = null_ptr;
X
X			modem->con_3[j] = null_ptr;
X			modem->con_12[j] = null_ptr;
X			modem->con_24[j] = null_ptr;
X			modem->con_48[j] = null_ptr;
X			modem->con_96[j] = null_ptr;
X			modem->con_192[j] = null_ptr;
X
X			modem->no_con1[j] = null_ptr;
X			modem->no_con2[j] = null_ptr;
X			modem->no_con3[j] = null_ptr;
X			modem->no_con4[j] = null_ptr;
X
X					/* update the counts */
X			modem->m_entries--;
X			if (modem->m_cur >= modem->m_entries)
X				modem->m_cur = -1;
X			return;
X		}
X	}
X	return;
X}
SHAR_EOF
if test 9489 -ne "`wc -c < 'm_lib.c'`"
then
	echo shar: "error transmitting 'm_lib.c'" '(should have been 9489 characters)'
fi
fi
echo shar: "extracting 'main.c'" '(4860 characters)'
if test -f 'main.c'
then
	echo shar: "will not over-write existing file 'main.c'"
else
sed 's/^X//' << \SHAR_EOF > 'main.c'
X/*
X * Pcomm is a public domain telecommunication program for Unix
X * designed to operate similar to the popular MSDOS program, ProComm.
X * ProComm (TM) is copyrighted by Datastorm Technologies, Inc.
X *
X * Emmet P. Gray			US Army, HQ III Corps & Fort Hood
X * ...!ihnp4!uiucuxc!fthood!egray	Attn: AFZF-DE-ENV
X *					Directorate of Engineering & Housing
X *					Environmental Management Office
X *					Fort Hood, TX 76544-5057
X *	Beta release	 7 Feb 88
X *	Release 1.0	12 Mar 88
X */
X
X#include <stdio.h>
X#include <signal.h>
X#include <curses.h>
X#ifndef OLDCURSES
X#include <term.h>
X#endif /* OLDCURSES */
X#include <sys/types.h>
X#include <sys/stat.h>
X#define MAIN
X#include "dial_dir.h"
X#include "modem.h"
X#include "param.h"
X#include "status.h"
X
X#ifdef OLDCURSES
Xchar bp[1024];
X#define cbreak crmode
X#endif /* OLDCURSES */
X
Xstruct PARAM *param;
Xstruct DIAL_DIR *dir;
Xstruct STATUS *status;
Xstruct MODEM *modem;
Xint xmc;
Xchar *null_ptr;
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X	int c, ret_code, i, code, quit();
X	char *mytty, *ttyname(), *term, *getenv(), *index, *strdup();
X	char *extra_dir, buf[80], message[80];
X	struct PARAM *read_param();
X	struct DIAL_DIR *read_dir();
X	struct STATUS *init();
X	struct MODEM *read_modem();
X	struct stat stbuf;
X	void exit(), error_win(), input_on(), free_ptr();
X	extern char *optarg;
X#ifdef OLDCURSES
X	char *tgetstr(), ocbuf[20];
X	char *ocbufptr = ocbuf;
X#endif /* OLDCURSES */
X
X	signal(SIGINT, SIG_IGN);
X	signal(SIGQUIT, SIG_IGN);
X	signal(SIGTERM, quit);
X	signal(SIGHUP, quit);
X
X	null_ptr = "";
X	index = NULL;
X	extra_dir = NULL;
X					/* the command line */
X	while ((c = getopt(argc, argv, "d:f:")) != EOF) {
X		switch (c) {
X			case 'd':	/* the extra directory to search */
X				extra_dir = strdup(optarg);
X				break;
X			case 'f':	/* the index into the dialing dir */
X				index = strdup(optarg);
X				break;
X			case '?':	/* default */
X				fprintf(stderr, "Usage: pcomm [-d directory] [-f index]\n");
X				exit(1);
X				break;
X		}
X	}
X					/* get terminal type */
X	term = getenv("TERM");
X	if (term == NULL || *term == NULL) {
X		fprintf(stderr, "Windows not supported (TERM not defined)\n");
X		exit(1);
X	}
X					/* see if terminfo entry exists */
X#ifdef OLDCURSES
X	ret_code = tgetent(bp, term);
X#else /* OLDCURSES */
X	setupterm(term, 1, &ret_code);
X#endif /* OLDCURSES */
X	if (ret_code != 1) {
X		fprintf(stderr, "Windows not supported (no terminfo data for '%s')\n", term);
X		exit(1);
X	}
X					/* minimum screen size */
X#ifdef OLDCURSES
X	if (tgetnum("co") < 80 || tgetnum("li") < 24) {
X#else /* OLDCURSES */
X	if (columns < 80 || lines < 24) {
X#endif /* OLDCURSES */
X		fprintf(stderr, "Windows not supported (minimum 80x24 screen required)\n");
X		exit(1);
X	}
X					/* must have cursor movement */
X#ifdef OLDCURSES
X	if (tgetstr("cm", &ocbufptr) == NULL) {
X#else /* OLDCURSES */
X	if (cursor_address == NULL) {
X#endif /* OLDCURSES */
X		fprintf(stderr, "Windows not supported (terminal too dumb)\n");
X		exit(1);
X	}
X					/* load magic cookie variable */
X#ifdef OLDCURSES
X	xmc = tgetnum("sg");
X#else /* OLDCURSES */
X	xmc = magic_cookie_glitch;
X#endif /* OLDCURSES */
X					/* ok... now lets go! */
X	initscr();
X	nonl();
X	cbreak();
X	noecho();
X
X	param = (struct PARAM *) NULL;
X	modem = (struct MODEM *) NULL;
X	dir = (struct DIAL_DIR *) NULL;
X					/* show the herald, return status */
X	status = init(extra_dir, index);
X					/* get 'msgs' status */
X	mytty = ttyname(0);
X	stat(mytty, &stbuf);
X	chmod(mytty, 0600);
X	status->msg = stbuf.st_mode & 0777;
X					/* read the support files */
X	param = read_param();
X	dir = read_dir();
X	modem = read_modem();
X					/* short-cut to dialing window ? */
X	code = 0;
X	if (index != NULL) {
X		for (i=1; i<dir->d_entries+1; i++) {
X			if (!strcmp(dir->index[i], index)) {
X				dir->q_num[0] = i;
X				dir->d_cur = i;
X				break;
X			}
X		}
X					/* if match is found */
X		if (dir->q_num[0] != -1)
X			code = dial_win();
X		else {
X			sprintf(buf, "Can't find index '%s' in dialing directory file", index);
X			sprintf(message, "'%s'", status->d_path);
X			error_win(0, buf, message);
X		}
X		free_ptr(index);
X	}
X					/* start terminal dialogue */
X	terminal(code);
X	exit(0);
X}
X
X/*
X * Something dreadful happened...  Cleanup the mess we made with the
X * tty driver and release the phone line.
X */
X
Xint
Xquit()
X{
X	void cleanup();
X
X	cleanup(1);
X					/* never returns... */
X	return(0);
X}
X
X/*
X * Check write permission with the real UID and GID.  Returns a 0 on
X * permission denied, 1 on OK, and 2 on OK-but the file already exists.
X */
X
Xint
Xcan_write(file)
Xchar *file;
X{
X	char *p, path[200], *strcpy(), *strrchr();
X
X	p = strcpy(path, file);
X					/* dissect the path component */
X	if (p = strrchr(path, '/'))
X		*(p++) = NULL;
X	else
X		strcpy(path, ".");
X					/* if it already exists */
X	if (!access(file, 0)) {
X		if (!access(file, 2))
X			return(2);
X		return(0);
X	}
X					/* if path is writable */
X	if (!access(path, 2))
X		return(1);
X	return(0);
X}
SHAR_EOF
if test 4860 -ne "`wc -c < 'main.c'`"
then
	echo shar: "error transmitting 'main.c'" '(should have been 4860 characters)'
fi
fi
echo shar: "extracting 'n_shell.c'" '(1369 characters)'
if test -f 'n_shell.c'
then
	echo shar: "will not over-write existing file 'n_shell.c'"
else
sed 's/^X//' << \SHAR_EOF > 'n_shell.c'
X/*
X * Spawn a 'native' shell.  'Native' means the shell found in the SHELL
X * environmental variable.
X */
X
X#include <stdio.h>
X#include <signal.h>
X#include <curses.h>
X
Xvoid
Xnative_shell()
X{
X	WINDOW *sh_win, *newwin();
X	int (*istat)(), (*qstat)(), status, pid, w;
X	char *shell, *shellpath, *getenv(), *strrchr();
X	unsigned int sleep();
X	void _exit();
X					/* a full window */
X	sh_win = newwin(LINES, COLS, 0, 0);
X
X	clear_absolute(sh_win);
X	waddstr(sh_win, "Pcomm <=> Unix gateway, use ^D or 'exit' to return\n");
X	wrefresh(sh_win);
X					/* out of curses mode */
X	resetterm();
X
X	shellpath = getenv("SHELL");
X	if (shellpath == NULL || *shellpath == NULL)
X		shellpath = "/bin/sh";
X
X	shell = strrchr(shellpath, '/') + 1;
X
X	if (!(pid = fork())) {
X#ifdef SGID
X		setgid(getgid());
X#endif /* SGID */
X		execl(shellpath, shell, "-i", 0);
X		_exit(1);
X	}
X	istat = signal(SIGINT, SIG_IGN);
X	qstat = signal(SIGQUIT, SIG_IGN);
X
X	while ((w = wait(&status)) != pid && w != -1)
X		;
X
X	signal(SIGINT, istat);
X	signal(SIGQUIT, qstat);
X					/* back to curses mode */
X	fixterm();
X	sleep(1);
X
X	clear_absolute(stdscr);
X	delwin(sh_win);
X	return;
X}
X
X/*
X * Clear the screen absolutely!  It's incrediblely hard to get curses() to
X * clear the screen when it thinks its already clear.
X */
X
Xint
Xclear_absolute(win)
XWINDOW *win;
X{
X	clearok(curscr, 1);
X	wrefresh(win);
X	clearok(curscr, 0);
X	return(0);
X}
SHAR_EOF
if test 1369 -ne "`wc -c < 'n_shell.c'`"
then
	echo shar: "error transmitting 'n_shell.c'" '(should have been 1369 characters)'
fi
fi
echo shar: "extracting 'p_lib.c'" '(5786 characters)'
if test -f 'p_lib.c'
then
	echo shar: "will not over-write existing file 'p_lib.c'"
else
sed 's/^X//' << \SHAR_EOF > 'p_lib.c'
X/*
X * Routines to manipulate the pcomm.param file.
X */
X
X#include <stdio.h>
X#include "param.h"
X#include "status.h"
X
X/*
X * Read the parameter structure from the pcomm.param file.  Returns a
X * pointer to the PARAM structure.  All errors are fatal.
X */
X
Xstruct PARAM *
Xread_param()
X{
X	FILE *fp;
X	int i, oops;
X	char buf[80], *temp_token, *str, *strdup();
X	char message[80], *str_tok();
X	static char *token[NUM_PARAM] = {"D_BAUD", "D_PARITY", "D_DBITS",
X	"D_SBITS", "HOT", "ASCII_HOT", "D_DUPLEX", "FLOW", "CR_IN", "CR_OUT",
X	"LOGFILE", "DUMPFILE", "STRIP", "PAUSE_CHAR", "CR_CHAR", "CTRL_CHAR",
X	"ESC_CHAR", "ABORT", "CDELAY", "PAUSE", "LECHO", "EXPAND", "CR_DELAY",
X	"PACE", "CR_UP", "LF_UP", "TIMER", "CR_DN", "LF_DN", "LD_PLUS",
X	"LD_MINUS", "LD_AT", "LD_POUND"};
X	static struct PARAM p;
X	void error_win();
X					/* read permission already checked */
X	fp = fopen(status->p_path, "r");
X
X	oops = 0;
X	for (i=0; i<NUM_PARAM; i++) {
X		if (fgets(buf, 80, fp) == NULL) {
X			sprintf(message, "is truncated at line %d", i+1);
X			oops++;
X			break;
X		}
X					/* parse the input line */
X		if (!(temp_token = str_tok(buf, '='))) {
X			sprintf(message, "is missing a token at line %d", i+1);
X			oops++;
X			break;
X		}
X		if (!(str = str_tok((char *) NULL, '\n'))) {
X			sprintf(message, "is missing a parameter at line %d", i+1);
X			oops++;
X			break;
X		}
X					/* sanity checking */
X		if (strcmp(temp_token, token[i])) {
X			sprintf(message, "is corrupted at line %d", i+1);
X			oops++;
X			break;
X		}
X
X		switch(i) {
X					/* used in line_set_menu() */
X			case LINE_SET:
X				p.d_baud = atoi(str);
X				break;
X			case LINE_SET+1:
X				p.d_parity = *str;
X				break;
X			case LINE_SET+2:
X				p.d_dbits = atoi(str);
X				break;
X			case LINE_SET+3:
X				p.d_sbits = atoi(str);
X				break;
X
X					/* used in term_setup() */
X			case TERM_SETUP:
X				p.hot = atoi(str);
X				break;
X			case TERM_SETUP+1:
X				p.ascii_hot = strdup(str);
X				break;
X			case TERM_SETUP+2:
X				p.d_duplex = strdup(str);
X				break;
X			case TERM_SETUP+3:
X				p.flow = strdup(str);
X				break;
X			case TERM_SETUP+4:
X				p.cr_in = strdup(str);
X				break;
X			case TERM_SETUP+5:
X				p.cr_out = strdup(str);
X				break;
X
X					/* used in gen_setup() */
X			case GEN_SETUP:
X				p.logfile = strdup(str);
X				break;
X			case GEN_SETUP+1:
X				p.dumpfile = strdup(str);
X				break;
X			case GEN_SETUP+2:
X				p.strip = strdup(str);
X				break;
X			case GEN_SETUP+3:
X				p.pause_char = *str;
X				break;
X			case GEN_SETUP+4:
X				p.cr_char = *str;
X				break;
X			case GEN_SETUP+5:
X				p.ctrl_char = *str;
X				break;
X			case GEN_SETUP+6:
X				p.esc_char = *str;
X				break;
X			case GEN_SETUP+7:
X				p.abort = strdup(str);
X				break;
X
X					/* used in gen_setup() delay_times() */
X			case DELAY_TIMES:
X				p.cdelay = atoi(str);
X				break;
X			case DELAY_TIMES+1:
X				p.pause = atoi(str);
X				break;
X
X					/* used in ascii_xfer_setup() */
X			case ASCII_SETUP:
X				p.lecho = strdup(str);
X				break;
X			case ASCII_SETUP+1:
X				p.expand = strdup(str);
X				break;
X			case ASCII_SETUP+2:
X				p.cr_delay = atoi(str);
X				break;
X			case ASCII_SETUP+3:
X				p.pace = strdup(str);
X				break;
X			case ASCII_SETUP+4:
X				p.cr_up = strdup(str);
X				break;
X			case ASCII_SETUP+5:
X				p.lf_up = strdup(str);
X				break;
X			case ASCII_SETUP+6:
X				p.timer = atoi(str);
X				break;
X			case ASCII_SETUP+7:
X				p.cr_dn = strdup(str);
X				break;
X			case ASCII_SETUP+8:
X				p.lf_dn = strdup(str);
X				break;
X
X					/* used in d_revise() */
X			case LD_CODES:
X				p.ld_plus = strdup(str);
X				break;
X			case LD_CODES+1:
X				p.ld_minus = strdup(str);
X				break;
X			case LD_CODES+2:
X				p.ld_at = strdup(str);
X				break;
X			case LD_CODES+3:
X				p.ld_pound = strdup(str);
X				break;
X		}
X	}
X	fclose(fp);
X	if (oops) {
X		sprintf(buf, "Parameter file '%s'", status->p_path);
X		error_win(1, buf, message);
X	}
X	return(&p);
X}
X
X/*
X * Write the updated param structure to disk.  The values in memory should
X * have already been "purified".  Later, we'll update only the entries that
X * have been explicitly asked for.  A return code of 1 means non-fatal error.
X */
X
Xint
Xupdate_param()
X{
X	FILE *fp;
X	char buf[80];
X	void error_win();
X					/* open for write */
X	if (!(fp = fopen(status->p_path, "w"))) {
X		sprintf(buf, "'%s'", status->p_path);
X		error_win(0, "No write permission on parameter file", buf);
X		return(1);
X	}
X
X	fprintf(fp, "D_BAUD=%d\n", param->d_baud);
X	fprintf(fp, "D_PARITY=%c\n", param->d_parity);
X	fprintf(fp, "D_DBITS=%d\n", param->d_dbits);
X	fprintf(fp, "D_SBITS=%d\n", param->d_sbits);
X	fprintf(fp, "HOT=%d\n", param->hot);
X	fprintf(fp, "ASCII_HOT=%s\n", param->ascii_hot);
X	fprintf(fp, "D_DUPLEX=%s\n", param->d_duplex);
X	fprintf(fp, "FLOW=%s\n", param->flow);
X	fprintf(fp, "CR_IN=%s\n", param->cr_in);
X	fprintf(fp, "CR_OUT=%s\n", param->cr_out);
X	fprintf(fp, "LOGFILE=%s\n", param->logfile);
X	fprintf(fp, "DUMPFILE=%s\n", param->dumpfile);
X	fprintf(fp, "STRIP=%s\n", param->strip);
X	fprintf(fp, "PAUSE_CHAR=%c\n", param->pause_char);
X	fprintf(fp, "CR_CHAR=%c\n", param->cr_char);
X	fprintf(fp, "CTRL_CHAR=%c\n", param->ctrl_char);
X	fprintf(fp, "ESC_CHAR=%c\n", param->esc_char);
X	fprintf(fp, "ABORT=%s\n", param->abort);
X	fprintf(fp, "CDELAY=%d\n", param->cdelay);
X	fprintf(fp, "PAUSE=%d\n", param->pause);
X	fprintf(fp, "LECHO=%s\n", param->lecho);
X	fprintf(fp, "EXPAND=%s\n", param->expand);
X	fprintf(fp, "CR_DELAY=%d\n", param->cr_delay);
X	fprintf(fp, "PACE=%s\n", param->pace);
X	fprintf(fp, "CR_UP=%s\n", param->cr_up);
X	fprintf(fp, "LF_UP=%s\n", param->lf_up);
X	fprintf(fp, "TIMER=%d\n", param->timer);
X	fprintf(fp, "CR_DN=%s\n", param->cr_dn);
X	fprintf(fp, "LF_DN=%s\n", param->lf_dn);
X	fprintf(fp, "LD_PLUS=%s\n", param->ld_plus);
X	fprintf(fp, "LD_MINUS=%s\n", param->ld_minus);
X	fprintf(fp, "LD_AT=%s\n", param->ld_at);
X	fprintf(fp, "LD_POUND=%s\n", param->ld_pound);
X
X	fclose(fp);
X	return(0);
X}
SHAR_EOF
if test 5786 -ne "`wc -c < 'p_lib.c'`"
then
	echo shar: "error transmitting 'p_lib.c'" '(should have been 5786 characters)'
fi
fi
echo shar: "extracting 'pexit.c'" '(2142 characters)'
if test -f 'pexit.c'
then
	echo shar: "will not over-write existing file 'pexit.c'"
else
sed 's/^X//' << \SHAR_EOF > 'pexit.c'
X/*
X * Exit pcomm.  A user requested abort.  There are a lot of things to do
X * before we exit!
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include "dial_dir.h"
X#include "misc.h"
X#include "param.h"
X#include "status.h"
X
Xvoid
Xpexit(fd)
Xint fd;
X{
X	WINDOW *ex_win, *newwin();
X	void cleanup(), status_line();
X
X	ex_win = newwin(5, 33, 3, 7);
X
X	box(ex_win, '|', '-');
X	mvwattrstr(ex_win, 0, 3, A_BOLD, " Exit ");
X	if (yes_prompt(ex_win, 2, 4, A_BLINK, "Exit to Unix")) {
X		status_line("   exiting");
X		cleanup(0);
X	}
X	if (fd == -1) {
X		werase(ex_win);
X		wrefresh(ex_win);
X	}
X	delwin(ex_win);
X	return;
X}
X
X/*
X * Do the cleanup detail before we exit.
X */
X
Xvoid
Xcleanup(val)
Xint val;
X{
X	void release_port(), input_off(), exit(), status_line();
X	char *ttyname();
X					/* kill the input routine */
X	input_off();
X					/* zap the virtual screen file */
X	unlink(status->vs_path);
X					/* release the port */
X	release_port(0);
X					/* erase the window we made */
X	touchwin(stdscr);
X	clear();
X	refresh();
X	endwin();
X					/* return the tty chmod */
X	chmod(ttyname(0), status->msg);
X	exit(val);
X}
X
X/*
X * Open a window to display an error message.  Handles both fatal and
X * non-fatal errors
X */
X
Xvoid
Xerror_win(code, line_one, line_two)
Xint code;
Xchar *line_one, *line_two;
X{
X	WINDOW *e_win, *newwin();
X	void cleanup(), status_line();
X
X	e_win = newwin(7, 70, 9, 5);
X					/* display the nasty note */
X	mvwaddstr(e_win, 2, 4, line_one);
X	mvwaddstr(e_win, 3, 4, line_two);
X	box(e_win, '|', '-');
X
X	if (code) {
X		mvwattrstr(e_win, 0, 4, A_BOLD, " Error ");
X		mvwattrstr(e_win, 5, 24, A_BLINK, "Press any key to exit");
X		wmove(e_win, 5, 46);
X	}
X	else {
X		mvwattrstr(e_win, 0, 4, A_BOLD, " Warning ");
X		mvwattrstr(e_win, 5, 22, A_BLINK, "Press any key to continue");
X		wmove(e_win, 5, 48);
X	}
X	beep();
X	wrefresh(e_win);
X
X	wgetch(e_win);
X	werase(e_win);
X	wrefresh(e_win);
X	delwin(e_win);
X
X	if (code) {
X		/*
X		 * Since this routine gets called if there is an error reading
X		 * the support files, the dir and param structures can't be
X		 * guaranteed to exist yet.
X		 */
X		if (dir != NULL && param != NULL)
X			status_line("   exiting");
X		cleanup(code);
X	}
X	return;
X}
SHAR_EOF
if test 2142 -ne "`wc -c < 'pexit.c'`"
then
	echo shar: "error transmitting 'pexit.c'" '(should have been 2142 characters)'
fi
fi
echo shar: "extracting 'port.c'" '(6122 characters)'
if test -f 'port.c'
then
	echo shar: "will not over-write existing file 'port.c'"
else
sed 's/^X//' << \SHAR_EOF > 'port.c'
X/*
X * Routines to get or release a tty port.
X */
X
X#define LOCKDIR "/usr/spool/uucp"
X#undef ASCII_PID
X
X#include <stdio.h>
X#include <fcntl.h>
X#include <termio.h>
X#ifdef UNIXPC
X#include <sys/phone.h>
X#endif /* UNIXPC */
X#include "dial_dir.h"
X#include "modem.h"
X#include "status.h"
X
Xint getty_status;
X/*
X * Finds a free (or requested) serial port.  Creates a lock file to hold
X * it for our use.  Loads the modem database.  A return code of 1 means
X * all ports (or the requested port) are busy.
X */
X
Xint
Xget_port()
X{
X	int i, j, k, progpid, fd, list[NUM_TTY];
X	char file[80], buf[80], message[80], *strdup();
X	void error_win(), line_set(), release_port(), send_str();
X	void free_ptr();
X	
X	/*
X	 * If we already have a port, see if it is good enough for the
X	 * current request.
X	 */
X	if (status->fd != -1) {
X		if (!strcmp(dir->index[dir->d_cur], modem->tty[modem->t_cur]) ||
X		 modem->mbaud[modem->t_cur] >= dir->baud[dir->d_cur]) {
X			/*
X			 * Re-initialize the modem because the baud
X			 * rate (or other parameters) may have changed.
X			 */
X			line_set();
X			send_str(modem->init[modem->m_cur]);
X			return(0);
X		}
X	}
X	release_port(1);
X
X	/*
X	 * See if you want a specific tty port.  If the index field in the
X	 * dialing directory is a valid device name, then use that tty.
X	 */
X	sprintf(buf, "/dev/%s", dir->index[dir->d_cur]);
X	list[0] = -1;
X					/* if index is a valid device */
X	if (!access(buf, 0)) {
X		for (i=0; i<modem->t_entries; i++) {
X					/* and it exists in modem database */
X			if (!strcmp(dir->index[dir->d_cur], modem->tty[i])) {
X				list[0] = i;
X				list[1] = -1;
X				break;
X			}
X		}
X	}
X
X	/*
X	 * Create a list of acceptable ttys.  It searches the tty database
X	 * for the requested baud rate.
X	 */
X	k = 0;
X	if (list[0] == -1) {
X		for (i=0; i<modem->t_entries; i++) {
X					/* skip ports with no modems */
X			if (!strcmp(modem->tname[i], "DIRECT"))
X				continue;
X
X					/* can handle requested baud rate ? */
X			if (modem->mbaud[i] >= dir->baud[dir->d_cur])
X				list[k++] = i;
X		}
X					/* the end of list marker */
X		list[k] = -1;
X	}
X					/* empty list ? */
X	if (list[0] == -1) {
X		sprintf(message, "No modem at a %d baud rating exists in", dir->baud[dir->d_cur]);
X		sprintf(file, "modem file '%s'", status->m_path);
X		error_win(0, message, file);
X		return(1);
X	}
X					/* check the list for a free port */	
X	i = 0;
X	while (list[i] != -1) {
X					/* create a lock file name */
X		sprintf(file, "%s/LCK..%s", LOCKDIR, modem->tty[list[i]]);
X
X		/*
X		 * See if the lock file exists... We DO NOT look to see
X		 * if the pid in the file is still active.  Maybe I'll
X		 * change this later...
X		 */
X		if (access(file, 0)) {
X			getty_status = set_getty(modem->tty[list[i]], 0);
X			
X			if ((fd = open(file, O_CREAT|O_WRONLY, 0666)) < 0) {
X				set_getty(modem->tty[list[i]], 1);
X				sprintf(buf, "'%s'", file);
X				error_win(1, "Can't create the lockfile", buf);
X			}
X#ifdef ASCII_PID
X			sprintf(buf, "%10d\n", getpid());
X			write(fd, buf, 11);
X#else /* ASCII_PID */
X			progpid = getpid();
X			write(fd, (char *)&progpid, sizeof(int));
X#endif /* ASCII_PID */
X			close(fd);
X					/* store the new values */
X			free_ptr(status->lock_path);
X			status->lock_path = strdup(file);
X			modem->t_cur = list[i];
X
X					/* open the device (hold DTR high) */
X			sprintf(buf, "/dev/%s", modem->tty[list[i]]);
X			if ((fd = open(buf, O_RDWR|O_NDELAY)) < 0) {
X				set_getty(modem->tty[list[i]], 1);
X				sprintf(file, "Can't open port '%s' for read and write", buf);
X				error_win(1, file, NULL);
X			}
X
X					/* turn off the "no delay" mode */
X			fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NDELAY);
X			status->fd = fd;
X					/* change line settings */
X			line_set();
X					/* load the modem data base */
X			for (j=0; j<modem->m_entries; j++) {
X				if (!strcmp(modem->tname[list[i]], modem->mname[j])) {
X					modem->m_cur = j;
X					break;
X				}
X			}
X					/* initialize the modem */
X			send_str(modem->init[j]);
X			return(0);
X		}
X		i++;
X	}
X	error_win(0, "All ports are busy now, try again later", NULL);
X	return(1);
X}
X
X/*
X * Release the port.  Closes the file descriptor and removes the
X * lock file
X */
X
Xvoid
Xrelease_port(verbose)
Xint verbose;
X{
X	char buf[80];
X	extern char *null_ptr;
X	void free_ptr(), hang_up();
X
X	/*
X	 * The modem structure can't be guaranteed to exist yet.  For example,
X	 * an error in reading one of the other support files would cause
X	 * this routine to be used before the MODEM structure gets allocated.
X	 */
X	if (modem == NULL)
X		return;
X					/* close the port */
X	if (status->fd != -1) {
X		ioctl(status->fd, TCFLSH, 2);
X		/*
X		 * Since HUPCL is set, the close() should drop the DTR and
X		 * hang up the modem (provided you've got the modem to
X		 * respond to DTR).  Since this is not guaranteed, we send
X		 * the hangup string first.
X		 */
X		hang_up(verbose);
X		close(status->fd);
X	}
X					/* remove the lock */
X	if (*status->lock_path != NULL) {
X		if (unlink(status->lock_path)) {
X			sprintf(buf, "'%s'", status->lock_path);
X			error_win(0, "Can't remove the lock file", buf);
X		}
X		free_ptr(status->lock_path);
X		status->lock_path = null_ptr;
X	}
X					/* turn the getty back on? */
X	if (getty_status)
X		set_getty(modem->tty[modem->t_cur], 1);
X					/* cleanup the structure */
X	status->fd = -1;
X	modem->m_cur = -1;
X	modem->t_cur = -1;
X	return;
X}
X
X/*
X * Turn the /etc/getty on or off for the specified port.  A return code
X * of 1 means that the getty was on.  Systems with uugetty or dedicated
X * dialout ports won't need this routine.
X */
X
Xint
Xset_getty(tty, on)
Xchar *tty;
Xint on;
X{
X#ifdef UNIXPC
X	int i, ret_code;
X	char buf[40];
X	unsigned int sleep();
X					/* the last three characters */
X	i = strlen(tty) -3;
X
X	ret_code = 0;
X	if (on) {
X		sprintf(buf, "setgetty %s 1", tty+i);
X		system(buf);
X	}
X	else {
X		sprintf(buf, "setgetty %s 0", tty+i);
X		if (system(buf) == 512)
X			ret_code = 1;
X		sleep(1);
X	}
X	return(ret_code);
X#else /* UNIXPC */
X	/*
X	 * If you don't have one of these cute little routines, you
X	 * might wanna write one.  It should check for an existing lock
X	 * file, edit the /etc/inittab file, and issue an init -q.
X	 * Obviously the program would be suid to root.
X	 */
X	return(0);
X#endif /* UNIXPC */
X}
SHAR_EOF
if test 6122 -ne "`wc -c < 'port.c'`"
then
	echo shar: "error transmitting 'port.c'" '(should have been 6122 characters)'
fi
fi
echo shar: "extracting 'redial.c'" '(2216 characters)'
if test -f 'redial.c'
then
	echo shar: "will not over-write existing file 'redial.c'"
else
sed 's/^X//' << \SHAR_EOF > 'redial.c'
X/*
X * The redial option (actually a misnomer, it's really a queuing system).
X * We expect a space-separated list of dialing directory entries (although
X * new users always try to put in a phone number).  A return code of 1
X * means we're ready to dial.
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include "dial_dir.h"
X#include "misc.h"
X
Xint
Xredial(fd)
Xint fd;
X{
X	WINDOW *rd_win, *newwin();
X	char *ans, *entry, *get_str(), *strchr(), *strtok();
X	int i, oops, number, ret_code;
X	
X	rd_win = newwin(6, 70, 5, 5);
X
X	mvwaddstr(rd_win, 4, 23, "(CR for previous numbers)");
X	mvwaddstr(rd_win, 2, 4, "Directory Entry Number(s): ");
X	box(rd_win, '|', '-');
X
X	mvwattrstr(rd_win, 0, 3, A_BOLD, " Redial Queue ");
X	wmove(rd_win, 2, 31);
X	wrefresh(rd_win);
X					/* get the string of numbers */
X	ret_code = 0;
X	while ((ans = get_str(rd_win, 35, "0123456789+-@# ", NULL)) != NULL) {
X		oops = 0;
X		if (*ans == NULL) {
X					/* use previous queue */
X			if (dir->q_num[0] != -1) {
X				ret_code = 1;
X				break;
X			}
X					/* there is no previous queue */
X			beep();
X			mvwattrstr(rd_win, 3, 4, A_BOLD, "No previous numbers");
X			wrefresh(rd_win);
X			wait_key(rd_win, 3);
X			clear_line(rd_win, 3, 4, 1);
X			wmove(rd_win, 2, 31);
X			wrefresh(rd_win);
X			continue;
X		}
X					/* parse the queue values */
X		entry = strtok(ans, "	 ");
X		for (i=0; i<NUM_QUEUE; i++) {
X			if (*entry == NULL) {
X				dir->q_num[i] = -1;
X				continue;
X			}
X					/* is there a LD code ? */
X			dir->q_ld[i] = NULL;
X			if (strchr("+-@#", *entry)) {
X				dir->q_ld[i] = *entry;
X				entry++;
X			}
X
X			/*
X			 * Zero is valid here, because it means use
X			 * the current entry information.
X			 */
X			number = atoi(entry);
X			if (number < -1 || number > NUM_DIR) {
X				beep();
X				mvwattrstr(rd_win, 3, 4, A_BOLD, "Invalid directory entry number");
X				wrefresh(rd_win);
X				wait_key(rd_win, 3);
X				clear_line(rd_win, 3, 4, 1);
X				clear_line(rd_win, 2, 31, 1);
X				wrefresh(rd_win);
X				oops++;
X				break;
X			}
X					/* store the number in the queue */
X			dir->q_num[i] = number;
X			entry = strtok((char *) NULL, "	 ");
X		}
X		if (oops)
X			continue;
X		ret_code = 1;
X		break;
X	}
X	if (fd == -1) {
X		werase(rd_win);
X		wrefresh(rd_win);
X	}
X	delwin(rd_win);
X	return(ret_code);
X}
SHAR_EOF
if test 2216 -ne "`wc -c < 'redial.c'`"
then
	echo shar: "error transmitting 'redial.c'" '(should have been 2216 characters)'
fi
fi
exit 0
#	End of shell archive

egray@fthood.UUCP (03/14/88)

This is part 6 (of 6) to the Pcomm version 1.0 distribution.

Emmet P. Gray				US Army, HQ III Corps & Fort Hood
...!ihnp4!uiucuxc!fthood!egray		Attn: AFZF-DE-ENV
					Directorate of Engineering & Housing
					Environmental Management Office
					Fort Hood, TX 76544-5057

-------------------------------------------------------------------------------
#! /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:
#	x_batch.c
#	x_menu.c
#	x_rcv.c
#	x_send.c
#	x_win.c
#	xmodem.c
# This archive created: Fri Mar 11 07:35:29 1988
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'x_batch.c'" '(7780 characters)'
if test -f 'x_batch.c'
then
	echo shar: "will not over-write existing file 'x_batch.c'"
else
sed 's/^X//' << \SHAR_EOF > 'x_batch.c'
X/*
X * Routines to support the batch protocols.
X */
X
X#include <stdio.h>
X#include <ctype.h>
X#include <curses.h>
X#include "misc.h"
X#include "xmodem.h"
X
X/*
X * Send the file name for the modem7 batch.  Only uses 11 characters
X * of the filename.
X */
X
Xint
Xsend_modem7(win, name)
XWINDOW *win;
Xchar *name;
X{
X	char *new_name, *fix_name();
X	unsigned char sum, calc_sum();
X
X					/* convert to 11 character name */
X	new_name = fix_name(name);
X	sum = calc_sum((unsigned char *) new_name, 12);
X
X	putc_line(ACK);
X					/* for each character in the name */
X	while (*new_name != CTRLZ) {
X		putc_line((unsigned char) *new_name);
X
X		switch (getc_line(3)) {
X			case ACK:	/* got it! */
X				break;
X			case CAN:	/* cancel transmission */
X				if (getc_line(2) == CAN) {
X					beep();
X					clear_line(win, 12, 24, 1);
X					wattrstr(win, A_BOLD, "REMOTE ABORTED");
X					wrefresh(win);
X					return(CANCEL);
X				}
X				/* fall thru... */
X			default:
X				clear_line(win, 12, 24, 1);
X				waddstr(win, "NAME FAILED");
X				wrefresh(win);
X				return(ERROR);
X		}
X		new_name++;
X	}
X	putc_line(CTRLZ);
X					/* verify the checksum */
X	if (getc_line(10) != sum) {
X		putc_line('u');
X		clear_line(win, 12, 24, 1);
X		waddstr(win, "CHECKSUM FAILED");
X		wrefresh(win);
X		return(ERROR);
X	}
X	putc_line(ACK);
X	return(0);
X}
X
X/*
X * Receive a modem 7 file name.  A return code of 1 means the end of the
X * batch transfers.
X */
X
Xint
Xrcv_modem7(win, default_err)
XWINDOW *win;
Xint default_err;
X{
X	int i, c, err_method, err_count, got_it;
X	unsigned char sum, calc_sum();
X	char temp_name[13];
X	extern char *null_ptr, file_name[15];
X	void change_name(), unfix_name();
X					/* send the first char */
X	err_method = default_err;
X	err_count = 0;
X	got_it = 0;
X	while (err_count < MAX_ERRORS) {
X					/* switch to checksum? */
X		if (default_err == 1 && err_count > MAX_ERRORS/2)
X			err_method = 0;
X
X		if (err_method)
X			putc_line('C');
X		else
X			putc_line(NAK);
X					/* what'd we get? */
X		if (getc_line(10) == ACK) {
X			got_it++;
X			break;
X		}
X		err_count++;
X	}
X	if (!got_it)
X		return(ERROR);
X					/* get the name */
X	for (i=0; i<12; i++) {
X		c = getc_line(3);
X
X		switch(c) {
X			case EOT:	/* end of batch? */
X				return(-1);
X			case CAN:	/* cancel transmission */
X				if (getc_line(2) == CAN) {
X					beep();
X					clear_line(win, 12, 24, 1);
X					wattrstr(win, A_BOLD, "REMOTE ABORTED");
X					wrefresh(win);
X					return(CANCEL);
X				}
X				/* fall thru... */
X			case 'u':	/* bad name character */
X				beep();
X				clear_line(win, 12, 24, 1);
X				wattrstr(win, A_BOLD, "BAD NAME");
X				wrefresh(win);
X				return(ERROR);
X			default:	/* the name... */
X				temp_name[i] = c;
X				if (c != CTRLZ)
X					putc_line(ACK);
X				break;
X		}
X	}
X	temp_name[12] = NULL;
X					/* send our checksum */
X	sum = calc_sum((unsigned char *) temp_name, 12);
X	putc_line(sum);
X					/* do they agree ? */
X	if (getc_line(10) != ACK) {
X		beep();
X		clear_line(win, 12, 24, 1);
X		wattrstr(win, A_BOLD, "BAD NAME");
X		wrefresh(win);
X		return(ERROR);
X	}
X					/* load the file_name array */
X	unfix_name(temp_name);
X					/* any name collisions? */
X	change_name(win, file_name);
X	return(0);
X}
X
X/*
X * Send the block 0 information for a ymodem batch transfer.  Uses only
X * the name component of the path and the file size.
X */
X
Xint
Xsend_ymodem(win, file, size)
XWINDOW *win;
Xchar *file;
Xint size;
X{
X	int i, crc;
X	char *strcpy();
X	unsigned char buf[133];
X					/* start with a clean block */
X	for (i=0; i<132; i++)
X		buf[i] = NULL;
X					/* the header */
X	buf[0] = SOH;
X	buf[1] = 0;
X	buf[2] = 255;
X
X	/*
X	 * The block zero consists of the file name (no path component),
X	 * a NULL, and the file length (as a string).  The end of batch
X	 * marker is an empty block.
X	 */
X	if (file != NULL) {
X		strcpy((char *) &buf[3], file);
X		sprintf((char *) &buf[strlen(file)+4], "%d", size);
X	}
X					/* the crc */
X	crc = calc_crc(&buf[3], 128);
X	buf[131] = crc >> 8;
X	buf[132] = crc;
X					/* the block count */
X	mvwaddstr(win, 7, 24, "0   ");
X
X	return(send_block(win, buf, 133));
X}
X
X/*
X * Receive the block 0 information for a ymodem batch transfer.  We
X * only use the file name and the size (if present).  Currently doesn't
X * support full path names.
X */
X
Xint
Xrcv_ymodem(win)
XWINDOW *win;
X{
X	int code, length_is_at;
X	extern unsigned char buf[1029];
X	extern int file_length;
X	extern char file_name[15];
X
X	file_length = 0;
X	file_name[0] = NULL;
X					/* read the zero block */
X	if (code = rcv_block(win, 1, 1024, 0))
X		return(code);
X					/* at end of batch */
X	if (buf[3] == NULL)
X		return(0);
X					/* get the file name */
X	change_name(win, (char *) &buf[3]);
X					/* any trouble ?? */
X	if (file_name[0] == NULL) {
X		putc_line(CAN);
X		return(0);
X	}
X	/*
X	 * The file length is placed after the NULL of the file name
X	 * and is terminated by another NULL.  If the length is missing,
X	 * atoi() will see a NULL and return 0.
X	 */
X	length_is_at = strlen((char *) &buf[3]) + 4;
X	file_length = atoi((char *) &buf[length_is_at]);
X	return(0);
X}
X
X/*
X * Handle file name collisions.  Prepend an 'X' to the name until you find
X * a name that doesn't already exist.  Creates a NULL name on error.
X * Loads the global character array 'file_name'.
X */
X
Xvoid
Xchange_name(win, str)
XWINDOW *win;
Xchar *str;
X{
X	int i, modified;
X	char temp[15], ans[15], *s, *strrchr(), *strcpy(), *strncat();
X	unsigned int sleep();
X	extern char file_name[15];
X					/* dissect the name component */
X	if ((s = strrchr(str, '/')))
X		strcpy(temp, s++);
X	else
X		strcpy(temp, str);
X
X	strcpy(ans, temp);
X	file_name[0] = NULL;
X					/* write permission on directory ? */
X	if (access(".", 2)) {
X		beep();
X		clear_line(win, 12, 24, 1);
X		wattrstr(win, A_BOLD, "NO WRITE ON DIRECTORY");
X		wrefresh(win);
X		return;
X	}
X					/* prepend up to 13 'X's */
X	modified = 0;
X	for (i=1; i<14; i++) {
X		if (access(ans, 0)) {
X			if (modified) {
X				beep();
X				clear_line(win, 12, 24, 1);
X				waddstr(win, "NAME COLLISION");
X				wrefresh(win);
X				sleep(1);
X			}
X			strcpy(file_name, ans);
X			return;
X		}
X
X		modified++;
X		strcpy(temp, "X");
X		strncat(temp, ans, 13);
X		temp[14] = NULL;
X		strcpy(ans, temp);
X	}
X	beep();
X	clear_line(win, 12, 24, 1);
X	waddstr(win, "BAD NAME");
X	wrefresh(win);
X	return;
X}
X
X/*
X * Convert a perfectly good Unix file name to fit the CP/M file name
X * rules.  Used for the modem7 batch file transfer.  Returns a pointer
X * to the new name.
X */
X
Xchar *
Xfix_name(path)
Xchar *path;
X{
X	int dot;
X	char *s, *name, temp[15], *ext, *strcpy(), *strrchr();
X	static char ans[13];
X					 /* ignore the path component */
X	if (s = strrchr(path, '/'))
X		strcpy(temp, s++);
X	else
X		strcpy(temp, path);
X	name = temp;
X
X	ext = NULL;
X	dot = 0;
X	for (s = name; *s; ++s) {
X		if (*s == '.' && !dot) {
X			dot = 1;
X			*s = NULL;
X			ext = s + 1;
X		}
X		if (islower(*s))
X			*s = toupper(*s);
X	}
X					/* if null name component */
X	if (*name == NULL)
X		name = "X";
X					/* if name too long */
X	if (strlen(name) > 8) 
X		*(name+8) = NULL;
X					/* if extension too long */
X	if (strlen(ext) > 3) 
X		*(ext+3) = NULL;
X
X	sprintf(ans, "%-8.8s%-3.3s%c", temp, ext, CTRLZ);
X	return(ans);
X}
X
X/*
X * Convert a CP/M style filename into a legal Unix file name.  Loads the
X * global character array 'file_name'.
X */
X
Xvoid
Xunfix_name(cpm_name)
Xchar *cpm_name;
X{
X	int i, n, dot;
X	char temp[15];
X	extern char file_name[15];
X
X	file_name[0] = NULL;
X	if (!*cpm_name)
X		return;
X
X	strcpy(temp, cpm_name);
X					/* 8 character of the name */
X	n = 0;
X	for (i=0; i<8; i++) {
X		if (temp[i] != ' ') {
X			if (isupper(temp[i]))
X				file_name[n++] = tolower(temp[i]);
X			else
X				file_name[n++] = temp[i];
X		}
X	}
X					/* 3 character extension */
X	dot = 0;
X	for (i=8; i<11; i++) {
X		if (temp[i] != ' ') {
X			if (!dot) {
X				dot++;
X				file_name[n++] = '.';
X			}
X			if (isupper(temp[i]))
X				file_name[n++] = tolower(temp[i]);
X			else
X				file_name[n++] = temp[i];
X		}
X	}
X	file_name[n] = NULL;
X	return;
X}
SHAR_EOF
if test 7780 -ne "`wc -c < 'x_batch.c'`"
then
	echo shar: "error transmitting 'x_batch.c'" '(should have been 7780 characters)'
fi
fi
echo shar: "extracting 'x_menu.c'" '(4000 characters)'
if test -f 'x_menu.c'
then
	echo shar: "will not over-write existing file 'x_menu.c'"
else
sed 's/^X//' << \SHAR_EOF > 'x_menu.c'
X/*
X * Open a window to display the choices of file transfer protocols and
X * prompt for the file name(s).  A return code of 1 means turn the
X * input routine back on.
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include "misc.h"
X#include "xmodem.h"
X
Xint
Xxfer_menu(up)
Xint up;
X{
X	WINDOW *xm_win, *newwin();
X	char *list, *get_names();
X	int type, is_batch;
X	extern char *null_ptr;
X	void xfer_win(), xfer_ascii(), free_ptr();
X
X	xm_win = newwin(15, 20, 2, 45);
X
X	mvwaddstr(xm_win, 2, 3, "1) xmodem");
X	mvwaddstr(xm_win, 3, 3, "2) xmodem-1k");
X	mvwaddstr(xm_win, 4, 3, "3) modem7");
X	mvwaddstr(xm_win, 5, 3, "4) ymodem");
X	mvwaddstr(xm_win, 6, 3, "5) ymodem-g");
X	mvwaddstr(xm_win, 7, 3, "6) ASCII");
X	mvwaddstr(xm_win, 11, 3, "ESC to Abort");
X	mvwaddstr(xm_win, 13, 3, "Protocol:");
X	box(xm_win, '|', '-');
X	if (up)
X		mvwattrstr(xm_win, 0, 6, A_BOLD, " Upload ");
X	else
X		mvwattrstr(xm_win, 0, 5, A_BOLD, " Download ");
X
X	wmove(xm_win, 13, 13);
X	wrefresh(xm_win);
X					/* get the protocol */
X	while ((type = get_num(xm_win, 1)) != -1) {
X		if (type >=1 && type <= PROTOCOLS)
X			break;
X		beep();
X		mvwaddch(xm_win, 13, 13, ' ');
X		wmove(xm_win, 13, 13);
X		wrefresh(xm_win);
X	}
X					/* is a batch protocol ? */
X	is_batch = 0;
X	switch (type-1) {
X		case MODEM7:
X		case YMODEM:
X		case YMODEM_G:
X			is_batch++;
X			break;
X		default:
X			break;
X	}
X	werase(xm_win);
X	wrefresh(xm_win);
X	delwin(xm_win);
X
X	touchwin(stdscr);
X	refresh();
X
X	if (type == -1)
X		return(0);
X	type--;
X
X	/*
X	 * When receiving files in one of the batch modes, there is
X	 * need to prompt for a list of file names.
X	 */
X	list = null_ptr;
X	if (up || !is_batch) {
X		if (!(list = get_names(up, type, is_batch)))
X			return(0);
X	}
X					/* if ascii transfer */
X	if (type == XASCII) {
X		xfer_ascii(list, up);
X		free_ptr(list);
X		if (up)
X			return(0);
X		return(1);
X	}
X	xfer_win(list, up, type);
X	free_ptr(list);
X	return(1);
X}
X
X/*
X * Prompt for a list of files for the transfer programs.  A NULL return
X * code means you chickened out.
X */
X
Xchar *
Xget_names(up, type, is_batch)
Xint up, type, is_batch;
X{
X	int can;
X	WINDOW *gn_win, *newwin();
X	char *ans, *list, *file, buf[40], *expand(), *get_str(), *strtok();
X	static char *direction[2] = {"Receive", "Send"};
X	static char *protocol[PROTOCOLS] = {"xmodem", "xmodem-1k", "modem7",
X	"ymodem", "ymodem-g", "ASCII"};
X					/* prompt for file spec */
X	gn_win = newwin(7, 70, 5, 5);
X
X	mvwaddstr(gn_win, 3, 4, "Enter filename: ");
X	box(gn_win, '|', '-');
X	sprintf(buf, " %s %s ", direction[up], protocol[type]);
X
X	while (1) {
X		mvwattrstr(gn_win, 0, 3, A_BOLD, buf);
X		wmove(gn_win, 3, 20);
X		wrefresh(gn_win);
X					/* get the answers */
X		if (is_batch)
X			ans = get_str(gn_win, 60, NULL, NULL);
X		else
X			ans = get_str(gn_win, 60, NULL, " 	");
X
X		if (ans == NULL || *ans == NULL) {
X			list = NULL;
X			break;
X		}
X		list = expand(ans);
X					/* batchs check "on the fly" */
X		if (is_batch)
X			break;
X		/*
X		 * The non-batch protocols don't check read and write
X		 * permission on the fly, so we check 'em here.  Since
X		 * they aren't batch, we use only one file.
X		 */
X		file = strtok(list, "	 ");
X					/* check read permission */
X		if (up) {
X			if (access(file, 4)) {
X				beep();
X				mvwattrstr(gn_win, 4, 15, A_BOLD, "Can't find or no read permission");
X				wrefresh(gn_win);
X				wait_key(gn_win, 3);
X				clear_line(gn_win, 4, 15, 1);
X				clear_line(gn_win, 3, 20, 1);
X				wrefresh(gn_win);
X			}
X			else
X				break;
X		}
X					/* check write permission */
X		else {
X			if (!(can = can_write(file))) {
X				beep();
X				clear_line(gn_win, 4, 15, 1);
X				mvwattrstr(gn_win, 4, 15, A_BOLD, "No write permission");
X				wrefresh(gn_win);
X				wait_key(gn_win, 3);
X				clear_line(gn_win, 4, 15, 1);
X				clear_line(gn_win, 3, 20, 1);
X				wrefresh(gn_win);
X			}
X			if (can == 2) {
X				if (!yes_prompt(gn_win, 4, 15, A_BOLD, "File exists, overwrite")) {
X					list = NULL;
X					break;
X				}
X			}
X			if (can)
X				break;
X		}
X	}
X	werase(gn_win);
X	wrefresh(gn_win);
X	delwin(gn_win);
X
X	touchwin(stdscr);
X	refresh();
X	return(list);
X}
SHAR_EOF
if test 4000 -ne "`wc -c < 'x_menu.c'`"
then
	echo shar: "error transmitting 'x_menu.c'" '(should have been 4000 characters)'
fi
fi
echo shar: "extracting 'x_rcv.c'" '(10526 characters)'
if test -f 'x_rcv.c'
then
	echo shar: "will not over-write existing file 'x_rcv.c'"
else
sed 's/^X//' << \SHAR_EOF > 'x_rcv.c'
X/*
X * Receive a list of files using a version of Ward Christensen's file
X * transfer protocol.  A return code of 1 means the user must acknowledge
X * an error condition.
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include "dial_dir.h"
X#include "misc.h"
X#include "xmodem.h"
X
Xunsigned char buf[1029];
Xchar file_name[15];
Xint file_length, err_method, tot_err, block_size;
X
Xint
Xrcv_xmodem(win, list, type, fast)
XWINDOW *win;
Xchar *list;
Xint type, fast;
X{
X	FILE *fp;
X	int default_err, is_batch, max_block, code, file_count, i, got_hdr;
X	int block, recv, hours, mins, secs;
X	float percent, performance;
X	unsigned char blk;
X	unsigned int sleep();
X	char *file, *name, *strcpy(), *strrchr(), *strtok();
X	void cancel_xfer();
X
X	/*
X	 * What type of xmodem?  The default_err means:  0=checksum only,
X	 * 1=CRC or checksum, 2=CRC only, and 3=none.
X	 */
X	switch(type) {
X		case XMODEM:
X			mvwaddstr(win, 2, 24, "xmodem");
X			default_err = 1;
X			is_batch = 0;
X			max_block = 128;
X			break;
X		case XMODEM_1k:
X			mvwaddstr(win, 2, 24, "xmodem-1k");
X			default_err = 1;
X			is_batch = 0;
X			max_block = 1024;
X			break;
X		case MODEM7:
X			mvwaddstr(win, 2, 24, "modem7");
X			default_err = 0;
X			is_batch = 1;
X			max_block = 128;
X			break;
X		case YMODEM:
X			mvwaddstr(win, 2, 24, "ymodem");
X			default_err = 2;
X			is_batch = 1;
X			max_block = 1024;
X			performance = 1.09;
X			break;
X		case YMODEM_G:
X			mvwaddstr(win, 2, 24, "ymodem-g");
X			default_err = 3;
X			is_batch = 1;
X			max_block = 1024;
X			performance = 1.02;
X			break;
X	}
X
X	tot_err = 0;
X	file_count = 0;
X	mvwaddstr(win, 11, 24, "0  ");
X
X	while (1) {
X		file_count++;
X		file_length = 0;
X					/* user supplied name */
X		if (!is_batch) {
X			if (file_count > 1)
X				break;
X
X			file = strtok(list, " 	");
X					/* dissect the file name */
X			if ((name = strrchr(file, '/')))
X				strcpy(file_name, name++);
X			else
X				strcpy(file_name, file);
X		}
X					/* get the modem7 file name */
X		if (type == MODEM7) {
X			if (code = rcv_modem7(win, default_err))
X				return(code +1);
X
X			file = file_name;
X		}
X					/* get the block 0 */
X		if (type == YMODEM || type == YMODEM_G) {
X			if (code = send_first(win, max_block, default_err))
X				return(code +1);
X
X			if (code = rcv_ymodem(win))
X				return(code +1);
X
X					/* at the end? */
X			if (buf[3] == NULL) {
X				beep();
X				wrefresh(win);
X				putc_line(ACK);
X				sleep(1);
X				return(0);
X			}
X			file = file_name;
X		}
X					/* any trouble ? */
X		if (file_name[0] == NULL)
X			continue;
X
X		clear_line(win, 3, 24, 1);
X		waddstr(win, file_name);
X					/* if file length is known */
X		if (file_length) {
X			mvwprintw(win, 4, 24, "%-10d", file_length);
X
X			secs = (file_length * 10.0 / dir->baud[dir->d_cur]) * performance;
X			hours = secs / 3600;
X			mins = (secs % 3600) / 60;
X			secs = (secs % 3600) % 60;
X
X			mvwprintw(win, 6, 24, "%d:%02d:%02d", hours, mins, secs);
X		}
X					/* some starting numbers */
X		mvwaddstr(win, 7, 24, "0    ");
X		if (file_length && fast)
X			mvwaddstr(win, 8, 24, "0%  ");
X		if (fast)
X			mvwaddstr(win, 9, 24, "0          ");
X		mvwaddstr(win, 10, 24, "0 ");
X		clear_line(win, 12, 24, 1);
X		waddstr(win, "NONE");
X		wrefresh(win);
X
X		/*
X		 * If the user supplied the name, write permission is checked
X		 * by the get_names() routine in xfer_menu().  If a modem7
X		 * or ymodem supplied name, the permission is checked by the
X		 * rcv_modem7() and rcv_ymodem() routines.
X		 */
X					/* open the file */
X		if (!(fp = fopen(file, "w"))) {
X			beep();
X			clear_line(win, 12, 24, 1);
X			wattrstr(win, A_BOLD, "CAN'T OPEN FILE");
X			wrefresh(win);
X			cancel_xfer();
X			return(1);
X		}
X					/* ACK the block 0 */
X		if (type == YMODEM || type == YMODEM_G)
X			putc_line(ACK);
X
X		if (code = send_first(win, max_block, default_err)) {
X			fclose(fp);
X			cancel_xfer();
X			return(code +1);
X		}
X					/* here we go... */
X		blk = 1;
X		block = 1;
X		recv = 0;
X		got_hdr = 1;
X		while (1) {
X			code = rcv_block(win, got_hdr, max_block, blk);
X
X			if (code < 0) {
X				fclose(fp);
X				cancel_xfer();
X				return(code +1);
X			}
X			got_hdr = 0;
X					/* are we done? */
X			if (buf[0] == EOT) {
X				if (!is_batch) {
X					beep();
X					wrefresh(win);
X					sleep(1);
X				}
X				break;
X			}
X					/* if not a duplicate block */
X			if (!code) {
X				fwrite((char *) &buf[3], sizeof(buf[0]), block_size, fp);
X				mvwprintw(win, 7, 24, "%-5d", block);
X				if (fast) {
X					recv += block_size;
X					mvwprintw(win, 9, 24, "%-10d", recv);
X				}
X				blk++;
X				block++;
X			}
X			/*
X			 * If the length is known, give the same status
X			 * report as uploading
X			 */
X			if (file_length && fast) {
X				percent = recv * 100.0 / file_length;
X				if (percent > 100.0)
X					percent = 100.0;
X				mvwprintw(win, 8, 24, "%0.1f%%", percent);
X			}
X			wrefresh(win);
X			putc_line(ACK);
X		}
X		if (file_length && fast) {
X			mvwaddstr(win, 8, 24, "100%  ");
X			wrefresh(win);
X		}
X		/*
X		 * If the file length is not known, then search backwards
X		 * from the end of the file until you find a character that
X		 * is not the ^Z padding character
X		 */
X		if (!file_length) {
X			for (i=block_size+2; i>2; i--) {
X				if (buf[i] != CTRLZ)
X					break;
X			}
X			file_length = recv - block_size + i -2;
X		}
X		fclose(fp);
X		fix_length(file_name, file_length);
X					/* ACK the EOT */
X		putc_line(ACK);
X	}
X	return(0);
X}
X
X/*
X * Send the first character to start the transmission and set the error
X * checking method.  Returns the standard error codes or 0 on success.
X * The variables err_method and block_size are global.
X */
X
Xint
Xsend_first(win, max_block, default_err)
XWINDOW *win;
Xint max_block, default_err;
X{
X	int i, err_count;
X	unsigned int sleep();
X					/* default error method */
X	err_method = default_err;
X	if (err_method > 1)
X		err_method--;
X					/* send the first char */
X	err_count = 0;
X	while (err_count < MAX_ERRORS*2) {
X		mvwprintw(win, 10, 24, "%-2d", err_count);
X
X					/* check for keyboard abort */
X		if (wgetch(win) == 27) {
X			beep();
X			clear_line(win, 12, 24, 1);
X			waddstr(win, "ABORTED");
X			wrefresh(win);
X			sleep(3);
X			return(ABORT);
X		}
X					/* switch to checksum? */
X		if (default_err == 1 && err_count > MAX_ERRORS)
X			err_method = 0;
X
X					/* send error method code */
X		clear_line(win, 5, 24, 1);
X		switch (err_method) {
X			case 0:
X				waddstr(win, "CHECKSUM");
X				putc_line(NAK);
X				break;
X			case 1:
X				waddstr(win, "CRC");
X				putc_line('C');
X				break;
X			case 2:
X				waddstr(win, "NONE");
X				putc_line('G');
X				break;
X		}
X		/*
X		 * We've cut the delay time in half, so we double
X		 * the allowable errors
X		 */
X		if ((i = getc_line(5)) == -1) {
X			err_count++;
X			clear_line(win, 12, 24, 1);
X			waddstr(win, "NO RESPONSE");
X			wrefresh(win);
X			continue;
X		}
X		buf[0] = i;
X
X		switch(buf[0]) {
X			case SOH:	/* small block follows */
X				block_size = 128;
X				return(0);
X			case STX:	/* large block follows */
X				if (max_block == 1024) {
X					block_size = 1024;
X					return(0);
X				}
X				/* fall thru */
X			default:
X				err_count++;
X				clear_line(win, 12, 24, 1);
X				waddstr(win, "BAD HEADER");
X				wrefresh(win);
X					/* read some garbage... */
X				fread_line(buf, 1028, 3);
X				putc_line(NAK);
X				break;
X		}
X	}
X	beep();
X	clear_line(win, 12, 24, 1);
X	wattrstr(win, A_BOLD, "TIMED OUT");
X	wrefresh(win);
X	return(ERROR);
X}
X
X/*
X * Receive a block of info from the host.  Returns a 0 on success, a 1 on
X * a duplicate block or the standard error codes.   The variables 
X * err_method and block_size are global.
X */
X
Xint
Xrcv_block(win, got_hdr, max_block, blk)
XWINDOW *win;
Xint got_hdr, max_block;
Xunsigned char blk;
X{
X	int i, err_count, bad_block, out_of_sync, crc;
X	unsigned int packet, sleep();
X	unsigned char calc_sum(), crc_1, crc_2;
X
X	err_count = 0;
X	while (err_count < MAX_ERRORS) {
X		mvwprintw(win, 10, 24, "%-2d", err_count);
X		mvwprintw(win, 11, 24, "%-3d", tot_err);
X
X					/* scan the keyboard for abort */
X		if (wgetch(win) == 27) {
X			beep();
X			clear_line(win, 12, 24, 1);
X			waddstr(win, "ABORTED");
X			wrefresh(win);
X			sleep(3);
X			return(ABORT);
X		}
X					/* have we already got a hdr? */
X		if (!got_hdr) {
X			if ((i = getc_line(10)) == -1) {
X				err_count++;
X				tot_err++;
X				clear_line(win, 12, 24, 1);
X				waddstr(win, "NO RESPONSE");
X				wrefresh(win);
X				continue;
X			}
X			buf[0] = i;
X					/* what'd we get? */
X			switch(buf[0]) {
X				case EOT:	/* we're done! */
X					clear_line(win, 12, 24, 1);
X					waddstr(win, "TRANSFER COMPLETE");
X					wrefresh(win);
X					sleep(1);
X					return(0);
X				case SOH:	/* small block follows */
X					block_size = 128;
X					break;
X				case STX:	/* large block follows */
X					if (max_block == 1024) {
X						block_size = 1024;
X						break;
X					}
X					/* fall thru... */
X				default:
X					err_count++;
X					tot_err++;
X					clear_line(win, 12, 24, 1);
X					waddstr(win, "BAD HEADER");
X					wrefresh(win);
X
X					/* flush a bad packet */
X					fread_line(buf, 1028, 5);
X					putc_line(NAK);
X					continue;
X			}
X		}
X		got_hdr = 0;
X					/* read the rest of the packet */
X		packet = block_size + 2 + (err_method ? 2 : 1);
X		if (fread_line(&buf[1], packet, 10) == -1) {
X			clear_line(win, 12, 24, 1);
X			waddstr(win, "TIMED OUT");
X			wrefresh(win);
X			putc_line(NAK);
X			err_count++;
X			tot_err++;
X			continue;
X		}
X
X		/*
X		 * Validation of the packet includes checking the
X		 * block number, its complement, and the crc/checksum.
X		 */
X		out_of_sync = 0;
X		if (buf[1] != blk || buf[2] != (unsigned char) ~blk)
X			out_of_sync++;
X
X		bad_block = 0;
X		switch(err_method) {
X			case 0:		/* checksum */
X				if (buf[block_size +3] != calc_sum(&buf[3], block_size))
X					bad_block++;
X				break;
X			case 1:		/* CRC */
X				crc = calc_crc(&buf[3], block_size);
X				crc_1 = crc >> 8;
X				crc_2 = crc;
X				if (buf[block_size +3] != crc_1 || buf[block_size +4] != crc_2)
X					bad_block++;
X				break;
X			case 2:		/* none */
X				return(0);
X		}
X					/* handle errors */
X		if (bad_block) {
X			clear_line(win, 12, 24, 1);
X			if (err_method)
X				waddstr(win, "CRC FAILED");
X			else
X				waddstr(win, "CHECKSUM FAILED");
X			wrefresh(win);
X			putc_line(NAK);
X			err_count++;
X			tot_err++;
X			continue;
X		}
X					/* not really an error */
X		if (out_of_sync) {
X			/*
X			 * If a perfect packet is off by 1 block number,
X			 * (a lost ACK could cause this) then treat it as
X			 * a good block but don't write it to disk.
X			 */
X			if (buf[1] == (unsigned char) blk-1)
X				return(1);
X
X			clear_line(win, 12, 24, 1);
X			waddstr(win, "OUT OF SYNC");
X			wrefresh(win);
X			putc_line(NAK);
X			err_count++;
X			tot_err++;
X			continue;
X		}
X		return(0);
X	}
X	beep();
X	clear_line(win, 12, 24, 1);
X	waddstr(win, "TOO MANY ERRORS");
X	wrefresh(win);
X	return(ERROR);
X}
SHAR_EOF
if test 10526 -ne "`wc -c < 'x_rcv.c'`"
then
	echo shar: "error transmitting 'x_rcv.c'" '(should have been 10526 characters)'
fi
fi
echo shar: "extracting 'x_send.c'" '(10461 characters)'
if test -f 'x_send.c'
then
	echo shar: "will not over-write existing file 'x_send.c'"
else
sed 's/^X//' << \SHAR_EOF > 'x_send.c'
X/*
X * Send a list of files using a version of Ward Christensen's file
X * transfer protocol.  A non-zero return code means an error must be
X * acknowledged by the user.
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include "dial_dir.h"
X#include "status.h"
X#include "misc.h"
X#include "xmodem.h"
X
Xint tot_err, err_method;
X
Xint
Xsend_xmodem(win, list, type, fast)
XWINDOW *win;
Xchar *list;
Xint type, fast;
X{
X	FILE *fp;
X	int i, block_size, file_count, secs, mins, hours, size, xmit_size;
X	int big_blocks, small_blocks, err_count, got_it, num, block, sent;
X	int crc, is_batch, code, max_block, default_err;
X	char *file, *strtok(), *name, *strrchr();
X	unsigned char buf[1029], blk, calc_sum();
X	unsigned int packet, sleep();
X	float performance, percent;
X	struct stat sbuf;
X
X	/*
X	 * What type of xmodem?  The default_err means: 0=checksum only,
X	 * 1=checksum or CRC, 2=CRC only, and 3=none.
X	 */
X	switch(type) {
X		case XMODEM:
X			mvwaddstr(win, 2, 24, "xmodem");
X			is_batch = 0;
X			default_err = 1;
X			max_block = 128;
X			performance = 1.36;
X			break;
X		case XMODEM_1k:
X			mvwaddstr(win, 2, 24, "xmodem-1k");
X			is_batch = 0;
X			default_err = 1;
X			max_block = 1024;
X			performance = 1.09;
X			break;
X		case MODEM7:
X			mvwaddstr(win, 2, 24, "modem7");
X			is_batch = 1;
X			default_err = 0;
X			max_block = 128;
X			performance = 1.36;
X			break;
X		case YMODEM:
X			mvwaddstr(win, 2, 24, "ymodem");
X			is_batch = 1;
X			default_err = 2;
X			max_block = 1024;
X			performance = 1.09;
X			break;
X		case YMODEM_G:
X			mvwaddstr(win, 2, 24, "ymodem-g");
X			is_batch = 1;
X			default_err = 3;
X			max_block = 1024;
X			performance = 1.02;
X			break;
X	}
X
X	tot_err = 0;
X	file_count = 0;
X	mvwaddstr(win, 11, 24, "0  ");
X
X					/* each one in the list */
X	file = strtok(list, " 	");
X	do {
X					/* is it a batch type ? */
X		file_count++;
X		if (file_count > 1 && !is_batch)
X			break;
X					/* display the name */
X		clear_line(win, 3, 24, 1);
X		if ((name = strrchr(file, '/')))
X			name++;
X		else
X			name = file;
X		waddstr(win, name);
X		wrefresh(win);
X					/* get the file size */	
X		if (stat(file, &sbuf) < 0) {
X			beep();
X			clear_line(win, 12, 24, 1);
X			wattrstr(win, A_BOLD, "CAN'T FIND FILE");
X			wrefresh(win);
X			sleep(3);
X			continue;
X		}
X
X		size = sbuf.st_size;
X		mvwprintw(win, 4, 24, "%-10d", size);
X		clear_line(win, 5, 24, 1);
X
X		if (access(file, 4)) {
X			beep();
X			clear_line(win, 12, 24, 1);
X			wattrstr(win, A_BOLD, "PERMISSION DENIED");
X			wrefresh(win);
X			sleep(3);
X			continue;
X		}
X		if (!(fp = fopen(file, "r"))) {
X			beep();
X			clear_line(win, 12, 24, 1);
X			wattrstr(win, A_BOLD, "CAN'T OPEN FILE");
X			wrefresh(win);
X			sleep(3);
X			continue;
X		}
X					/* get the xmit size */
X		block_size = max_block;
X		big_blocks = 0;
X		small_blocks = 0;
X		if (block_size == 128) {
X			small_blocks = size / 128;
X			if (size % 128)
X				small_blocks++;
X		}
X		else {
X			big_blocks = size / 1024;
X			small_blocks = (size % 1024) / 128;
X			if (size % 128)
X				small_blocks++;
X
X			if (small_blocks == 8 && !big_blocks) {
X				big_blocks++;
X				small_blocks = 0;
X			}
X					/* if tiny file */
X			if (big_blocks == 0)
X				block_size = 128;
X		}
X
X		xmit_size = (big_blocks * 1024) + (small_blocks * 128);
X					/* add block 0 to the size */
X		if (type == YMODEM || type == YMODEM_G)
X			xmit_size += 128;
X
X		secs = (xmit_size * 10.0 / dir->baud[dir->d_cur]) * performance;
X		hours = secs / 3600;
X		mins = (secs % 3600) / 60;
X		secs = (secs % 3600) % 60;
X
X		mvwprintw(win, 6, 24, "%d:%02d:%02d", hours, mins, secs);
X
X					/* some starting numbers */
X		mvwaddstr(win, 7, 24, "     ");
X		mvwaddstr(win, 8, 24, "0%  ");
X		mvwaddstr(win, 9, 24, "0          ");
X		mvwaddstr(win, 10, 24, "0 ");
X		clear_line(win, 12, 24, 1);
X		waddstr(win, "NONE");
X		wrefresh(win);
X					/* send the batch stuff */
X		switch (type) {
X			case MODEM7:
X				if (code = rcv_first(win, default_err)) {
X					fclose(fp);
X					return(code +1);
X				}
X
X				if (send_modem7(win, name)) {
X					fclose(fp);
X					return(1);
X				}
X				break;
X			case YMODEM:
X			case YMODEM_G:
X				if (code = rcv_first(win, default_err)) {
X					fclose(fp);
X					return(code +1);
X				}
X
X				if (code = send_ymodem(win, name, size)) {
X					fclose(fp);
X					/*
X					 * CANCEL now means that the other
X					 * end can't open that file.
X					 */
X					if (code == CANCEL)
X						break;
X					return(code +1);
X				}
X				xmit_size -= 128;
X				break;
X			default:
X				code = 0;
X				break;
X		}
X					/* remote can't receive that file ? */
X		if (code == CANCEL)
X			break;
X					/* wait for first character */
X		if (code = rcv_first(win, default_err)) {
X			fclose(fp);
X			return(code +1);
X		}
X					/* here we go... */
X		sent = 0;
X		block = 1;
X		blk = 1;
X		while (num = fread((char *) &buf[3], sizeof(buf[0]), block_size, fp)) {
X
X					/* fill short block */
X			if (num < block_size) {
X				for (i=num; i<block_size; i++)
X					buf[i+3] = CTRLZ;
X			}
X
X					/* show current stats */
X			mvwprintw(win, 7, 24, "%-5d", block);
X			if (fast) {
X				percent = sent * 100.0 / xmit_size;
X				mvwprintw(win, 8, 24, "%0.1f%%", percent);
X				mvwprintw(win, 9, 24, "%-10d", sent);
X			}
X			wrefresh(win);
X
X					/* build the header */
X			if (block_size == 128)
X				buf[0] = SOH;
X			else
X				buf[0] = STX;
X
X			buf[1] = blk;
X			buf[2] = ~blk;
X
X					/* build the error detection stuff */
X			switch (err_method) {
X				case 0:		/* checksum */
X					buf[block_size+3] = calc_sum(&buf[3], block_size);
X					packet = block_size +4;
X					break;
X				case 1:		/* CRC */
X					crc = calc_crc(&buf[3], block_size);
X					buf[block_size+3] = crc >> 8;
X					buf[block_size+4] = crc;
X					packet = block_size +5;
X					break;
X				case 2:		/* none */
X					buf[block_size+3] = 0;
X					buf[block_size+4] = 0;
X					packet = block_size +5;
X					break;
X			}
X
X					/* send the block */
X			if (code = send_block(win, buf, packet)) {
X				fclose(fp);
X				return(code +1);
X			}
X			block++;
X			blk++;
X			sent += block_size;
X
X					/* change block size ? */
X			if (xmit_size - sent < 1024)
X				block_size = 128;
X		}
X		mvwaddstr(win, 8, 24, "100%  ");
X		mvwprintw(win, 9, 24, "%-10d", sent);
X					/* at the end of the file */
X		err_count = 0;
X		got_it = 0;
X		while (err_count < MAX_ERRORS) {
X			putc_line(EOT);
X			if (getc_line(10) == ACK) {
X				got_it++;
X				break;
X			}
X			err_count++;
X		}
X		clear_line(win, 12, 24, 1);
X		if (!got_it) {
X			/*
X			 * So what???  We don't do anything if there is
X			 * no acknowledge from the host!!
X			 */
X			waddstr(win, "NO ACKNOWLEDGE");
X		}
X		else
X			waddstr(win, "TRANSFER COMPLETE");
X		if (!is_batch)
X			beep();
X		wrefresh(win);
X		sleep(2);
X					/* prepare to start again */
X		fclose(fp);
X	} while (file = strtok((char *) NULL, " 	"));
X
X	/*
X	 * The end of batch markers... For modem7 it's an ACK and EOT, for
X	 * ymodem, it's an empty block 0.
X	 */
X	switch (type) {
X		case MODEM7:
X			if (code = rcv_first(win, default_err))
X				return(code +1);
X			putc_line(ACK);
X			putc_line(EOT);
X			beep();
X			wrefresh(win);
X			break;
X		case YMODEM:
X		case YMODEM_G:
X			if (code = rcv_first(win, default_err))
X				return(code +1);
X
X			if (code = send_ymodem(win, NULL, 0))
X				return(code +1);
X			beep();
X			wrefresh(win);
X			break;
X		default:
X			break;
X	}
X	return(0);
X}
X
X/*
X * Wait for the first character to start the transmission.  This first
X * character also sets the crc/checksum method.  Returns the standard
X * error codes, or 0 on success.  The variable err_method is global.
X */
X
Xint
Xrcv_first(win, default_err)
XWINDOW *win;
Xint default_err;
X{
X	int err_count;
X	unsigned int sleep();
X
X	err_count = 0;
X	while (err_count < MAX_ERRORS) {
X
X					/* scan the keyboard for abort */
X		if (wgetch(win) == 27) {
X			beep();
X			clear_line(win, 12, 24, 1);
X			waddstr(win, "ABORTED");
X			wrefresh(win);
X			sleep(3);
X			return(ABORT);
X		}
X
X					/* scan the tty line */
X		switch(getc_line(10)) {
X			case NAK:	/* checksum marker */
X				if (default_err < 2) {
X					mvwaddstr(win, 5, 24, "CHECKSUM");
X					err_method = 0;
X					return(0);
X				}
X				err_count++;
X				break;
X			case 'C':	/* CRC marker */
X				if (default_err == 1 || default_err == 2) {
X					mvwaddstr(win, 5, 24, "CRC");
X					err_method = 1;
X					return(0);
X				}
X				err_count++;
X				break;
X			case 'G':	/* ymodem-g marker */
X				if (default_err == 3) {
X					mvwaddstr(win, 5, 24, "NONE");
X					err_method = 2;
X					return(0);
X				}
X				err_count++;
X				break;
X			case CAN:	/* two CAN's and you're out! */
X				if (getc_line(2) == CAN) {
X					beep();
X					clear_line(win, 12, 24, 1);
X					wattrstr(win, A_BOLD, "REMOTE ABORTED");
X					wrefresh(win);
X					return(CANCEL);
X				}
X				/* fall thru... */
X			default:
X				err_count++;
X				break;
X		}
X		clear_line(win, 12, 24, 1);
X		waddstr(win, "BAD HEADER");
X		mvwprintw(win, 10, 24, "%-2d", err_count);
X		wrefresh(win);
X	}
X					/* failed to get it right ? */
X	beep();
X	clear_line(win, 12, 24, 1);
X	wattrstr(win, A_BOLD, "TIMED OUT");
X	wrefresh(win);
X	return(ERROR);
X}
X
X/*
X * Send a block of data, scan the keyboard for a user abort, and check
X * the return codes from the host.  Returns standard error codes or 0
X * on success.
X */
X
Xint
Xsend_block(win, blk, packet)
XWINDOW *win;
Xunsigned char *blk;
Xunsigned int packet;
X{
X	int err_count;
X
X	err_count = 0;
X	while (err_count < MAX_ERRORS) {
X					/* write the block */
X		write(status->fd, (char *) blk, packet);
X					/* scan the keyboard */
X		if (wgetch(win) == 27) {
X			beep();
X			clear_line(win, 12, 24, 1);
X			waddstr(win, "ABORTED");
X			wrefresh(win);
X			sleep(3);
X			return(ABORT);
X		}
X					/* ymodem-g doesn't need ACKs */
X		if (err_method == 2)
X			return(0);
X					/* wait for acknowledge */
X		switch(getc_line(10)) {
X			case ACK:	/* Hooray!! we got it */
X				return(0);
X			case NAK:	/* show our disappointment... */
X				clear_line(win, 12, 24, 1);
X				if (err_method)
X					waddstr(win, "CRC FAILED");
X				else
X					waddstr(win, "CHECKSUM FAILED");
X				err_count++;
X				tot_err++;
X				break;
X			case CAN:	/* two CAN's and you're out! */
X				if (getc_line(2) == CAN) {
X					beep();
X					clear_line(win, 12, 24, 1);
X					wattrstr(win, A_BOLD, "REMOTE ABORTED");
X					wrefresh(win);
X					return(CANCEL);
X				}
X				/* fall thru... */
X			default:
X				clear_line(win, 12, 24, 1);
X				waddstr(win, "RESENDING");
X				err_count++;
X				tot_err++;
X				break;
X		}
X		mvwprintw(win, 10, 24, "%-2d", err_count);
X		mvwprintw(win, 11, 24, "%-3d", tot_err);
X		wrefresh(win);
X	}
X					/* failed to get it right */
X	beep();
X	clear_line(win, 12, 24, 1);
X	wattrstr(win, A_BOLD, "TOO MANY ERRORS");
X	wrefresh(win);
X	return(ERROR);
X}
SHAR_EOF
if test 10461 -ne "`wc -c < 'x_send.c'`"
then
	echo shar: "error transmitting 'x_send.c'" '(should have been 10461 characters)'
fi
fi
echo shar: "extracting 'x_win.c'" '(2758 characters)'
if test -f 'x_win.c'
then
	echo shar: "will not over-write existing file 'x_win.c'"
else
sed 's/^X//' << \SHAR_EOF > 'x_win.c'
X/*
X * Display the file transfer window, and invoke the transfer protocol.
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include "dial_dir.h"
X#include "misc.h"
X#include "status.h"
X#include "xmodem.h"
X
Xvoid
Xxfer_win(list, up, type)
Xchar *list;
Xint up, type;
X{
X	WINDOW *xf_win, *newwin();
X	int ret_code, fast, my_speed;
X	void xmodem_mode(), input_off(), line_set(), error_win();
X	struct termio tbuf;
X
X	if (status->fd == -1) {
X		error_win(0, "Not currently connected to any host", NULL);
X		return;
X	}
X
X	xf_win = newwin(15, 44, 2, 30);
X	/*
X	 * This window should be in the non-blocking mode, so we can
X	 * scan the keyboard for input while transferring a file.
X	 */
X	nodelay(xf_win, 1);
X					/* basic window stuff */
X	mvwaddstr(xf_win, 2, 14, "Protocol:");
X	mvwaddstr(xf_win, 3, 13, "File name:");
X	mvwaddstr(xf_win, 4, 13, "File size:");
X	mvwaddstr(xf_win, 5, 4, "Error check method:");
X	mvwaddstr(xf_win, 6, 5, "Est transfer time:");
X	mvwaddstr(xf_win, 7, 11, "Block count:");
X	mvwaddstr(xf_win, 8, 6, "Percent complete:");
X	mvwaddstr(xf_win, 9, 5, "Bytes transferred:");
X	mvwaddstr(xf_win, 10, 5, "Errors this block:");
X	mvwaddstr(xf_win, 11, 5, "Total error count:");
X	mvwaddstr(xf_win, 12, 10, "Last message: NONE");
X	box(xf_win, '|', '-');
X
X	if (up)
X		mvwattrstr(xf_win, 0, 17, A_BOLD, " Uploading ");
X	else
X		mvwattrstr(xf_win, 0, 16, A_BOLD, " Downloading ");
X	mvwaddstr(xf_win, 14, 12, " Press ESC to abort ");
X	wrefresh(xf_win);
X					/* fix up the terminal mode */
X	input_off();
X	xmodem_mode(status->fd);
X
X	/*
X	 * Is your terminal slower than the xfer baud rate?  For example:
X	 * I'm at home with my PC and 1200 baud modem, I call my system
X	 * at work so I can use their 2400 baud modems to call some other
X	 * system.  In this case, I don't wanna spend too much time updating
X	 * my screen at 1200 baud, when I'm transferring the file at 2400 baud.
X	 */
X	my_speed = 0;
X	fast = 0;
X
X	ioctl(0, TCGETA, &tbuf);
X					/* only reasonable values are here */
X	switch(tbuf.c_cflag & CBAUD) {
X		case B300:
X			my_speed = 300;
X			break;
X		case B1200:
X			my_speed = 1200;
X			break;
X		case B2400:
X			my_speed = 2400;
X			break;
X		case B4800:
X			my_speed = 4800;
X			break;
X		case B9600:
X			my_speed = 9600;
X			break;
X		case B19200:
X			my_speed = 19200;
X			break;
X	}
X	if (my_speed >= dir->baud[dir->d_cur])
X		fast++;
X
X	if (up)
X		ret_code = send_xmodem(xf_win, list, type, fast);
X	else
X		ret_code = rcv_xmodem(xf_win, list, type, fast);
X
X	nodelay(xf_win, 0);
X					/* prompt for a key on errors */
X	if (ret_code) {
X		beep();
X		clear_line(xf_win, 13, 9, 1);
X		wattrstr(xf_win, A_BOLD, "Press any key to continue");
X		wrefresh(xf_win);
X		wgetch(xf_win);
X	}
X	werase(xf_win);
X	wrefresh(xf_win);
X	delwin(xf_win);
X					/* undo what xmodem_mode() did */
X	line_set();
X	return;
X}
SHAR_EOF
if test 2758 -ne "`wc -c < 'x_win.c'`"
then
	echo shar: "error transmitting 'x_win.c'" '(should have been 2758 characters)'
fi
fi
echo shar: "extracting 'xmodem.c'" '(4611 characters)'
if test -f 'xmodem.c'
then
	echo shar: "will not over-write existing file 'xmodem.c'"
else
sed 's/^X//' << \SHAR_EOF > 'xmodem.c'
X/*
X * Miscellaneous routines to support the xmodem file transfer protocols.
X */
X
X#include <stdio.h>
X#include <signal.h>
X#include <termio.h>
X#include <setjmp.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include "param.h"
X#include "status.h"
X#include "xmodem.h"
X
X/*
X * Calculate the CRC for the given buffer
X */
X
Xint
Xcalc_crc(buf, len)
Xunsigned char *buf;
Xint len;
X{
X	int crc, i;
X	
X	crc = 0;
X	while (--len >= 0) {
X		/*
X		 * Some fancy foot work here... The algorithm looks good
X		 * in assembly, but in C it looks horrible!
X		 */
X		crc = crc ^ (int) *buf++ << 8;
X		for (i=0; i<8; i++) {
X			if (crc & 0x8000)
X				crc = crc << 1 ^ 0x1021;
X			else
X				crc = crc << 1;
X		}
X	}
X	return(crc & 0xffff);
X}
X
X/*
X * Calculate the checksum for the given buffer.
X */
X
Xunsigned char
Xcalc_sum(buf, len)
Xunsigned char *buf;
Xint len;
X{
X	unsigned char sum;
X
X	sum = 0;
X	while (--len >= 0)
X		sum += *buf++;
X
X	return(sum);
X}
X
X/*
X * Get a character from the line with a specified time-out period in
X * seconds.  If the function times-out, it returns a -1.
X */
X
Xjmp_buf gl_jmp;
X
Xint
Xgetc_line(sec)
Xunsigned int sec;
X{
X	int force_gl();
X	unsigned char c;
X	unsigned int alarm();
X
X	signal(SIGALRM, force_gl);
X	if (setjmp(gl_jmp))
X		return(-1);
X
X	alarm(sec);
X	if (read(status->fd, (char *) &c, 1) <= 0) {
X		alarm(0);
X		return(-1);
X	}
X	alarm(0);
X	return(c);
X}
Xint
Xforce_gl(dummy)
Xint dummy;
X{
X	void longjmp();
X
X	longjmp(gl_jmp, 1);
X}
X
X/*
X * Same as above, but reads a bunch of characters.  The return code is
X * now just a success/fail indicator.
X */
X
Xjmp_buf rl_jmp;
X
Xint
Xfread_line(buf, len, sec)
Xunsigned char *buf;
Xunsigned int len, sec;
X{
X	int i, force_rl();
X	unsigned int alarm();
X
X	signal(SIGALRM, force_rl);
X	if (setjmp(rl_jmp))
X		return(-1);
X
X	alarm(sec);
X	/*
X	 * Later, this will have some fine tuning to use more than
X	 * single character I/O.
X	 */
X	for (i=0; i<len; i++) {
X		if (read(status->fd, (char *) buf++, 1) <= 0) {
X			alarm(0);
X			return(-1);
X		}
X	}
X	alarm(0);
X	return(0);
X}
Xint
Xforce_rl(dummy)
Xint dummy;
X{
X	void longjmp();
X
X	longjmp(rl_jmp, 1);
X}
X
X/*
X * Put a character on the tty line.  This serves no useful purpose other
X * than making the code look pretty.
X */
X
Xint
Xputc_line(c)
Xunsigned char c;
X{
X	return(write(status->fd, (char *) &c, 1));
X}
X
X/*
X * Put the tty driver in the mode suitable for xmodem transfers.
X */
X
Xvoid
Xxmodem_mode(fd)
Xint fd;
X{
X	struct termio tbuf;
X
X	ioctl(fd, TCGETA, &tbuf);
X	/*
X	 * Turn off the XON/XOFF flow control, turn off echoing, and
X	 * switch to 8 bit no parity.  Later, the VTIME and VMIN variables
X	 * will be fine tuned, to allow for more efficient I/O.
X	 */
X	tbuf.c_cc[4] = 1;		/* VMIN */
X	tbuf.c_cc[5] = 0;		/* VTIME */
X	tbuf.c_iflag = 0;		/* no flow control or mapping */
X	tbuf.c_oflag = 0;		/* no char mapping or delays */
X	tbuf.c_lflag = 0;		/* no echo or signals */
X	tbuf.c_cflag &= ~PARENB;	/* no parity */
X	tbuf.c_cflag &= ~CSIZE;
X	tbuf.c_cflag |= CS8;		/* 8 bit */
X
X	ioctl(fd, TCSETA, &tbuf);
X	ioctl(fd, TCFLSH, 2);
X	return;
X}
X
X/*
X * Cancel the file transfer.  Send several ^X's to the remote, followed
X * by an equal number of backspace (in case they have already aborted and
X * we're really at the command line).
X */
X
Xvoid
Xcancel_xfer()
X{
X	extern char file_name[15];
X
X	if (!strcmp(param->abort, "DELETE"))
X		unlink(file_name);
X
X	putc_line(CAN);
X	putc_line(CAN);
X	putc_line(CAN);
X	putc_line(8);
X	putc_line(8);
X	putc_line(8);
X	return;
X}
X
X/*
X * Shorten a file to a predetermined length.  Used to remove the ^Z
X * padding from the end of files.  (Heaven help us, if one day a binary
X * file actually has ^Z's as part of the end of the file).
X */
X
Xint
Xfix_length(file, len)
Xchar *file;
Xint len;
X{
X	FILE *fp, *tempfp;
X	int num;
X	char *tempfile, *mktemp();
X	unsigned char buf[BUFSIZ];
X	struct stat stbuf;
X
X	if (stat(file, &stbuf) < 0)
X		return(1);
X					/* see if we have any work to do */
X	if (len >= stbuf.st_size)
X		return(0);
X
X	if (!(fp = fopen(file, "r")))
X		return(1);
X
X	/*
X	 * The temporary file should be in the same directory as the
X	 * file being received because otherwise we'd have no way of
X	 * guaranteeing they would be in the same file system.  (Hard
X	 * links across different file systems aren't allowed).
X	 */
X	tempfile = mktemp("trunXXXXXX");
X	if (!(tempfp = fopen(tempfile, "w"))) {
X		fclose(fp);
X		return(1);
X	}
X
X	while(len) {
X		num = (len > BUFSIZ) ? BUFSIZ : len;
X		fread((char *) buf, sizeof(buf[0]), num, fp);
X		fwrite((char *) buf, sizeof(buf[0]), num, tempfp);
X		len -= num;
X	}
X
X	fclose(fp);
X	fclose(tempfp);
X
X	if (unlink(file) < 0)
X		return(1);
X
X	if (link(tempfile, file) < 0)
X		return(1);
X
X	if (unlink(tempfile) < 0)
X		return(1);
X
X	return(0);
X}
SHAR_EOF
if test 4611 -ne "`wc -c < 'xmodem.c'`"
then
	echo shar: "error transmitting 'xmodem.c'" '(should have been 4611 characters)'
fi
fi
exit 0
#	End of shell archive

kevin@kosman.UUCP (Kevin O'Gorman) (03/17/88)

I just went to unpack Pcomm, and there are four files that report errors in
transmission.  I am afraid it's tab expansion in two of them, and I don't
quite know what to think of the other two.  Anyway, here's what they look
like after unpacking:

-rw-rw-rw-  1 root    users     32936 Mar 16 14:20 Doc
-rw-rw-rw-  1 root    users      6352 Mar 16 14:20 Pcomm.1
-rw-rw-rw-  1 root    users      1033 Mar 16 14:21 getopt.c
-rw-rw-rw-  1 root    users      4774 Mar 16 14:21 s_tty.c

Anyone have a good set?  Anyone else have this problem?  Is any of this
significant?

ccs@lazlo.UUCP (Clifford C. Skolnick) (02/09/89)

I'm trying to get the latest pcomm running smoothly on my system.  All seems
to be going well, except for the dialing directory.  It seems when I call up
the directory, garbage appears to the left of the newly created boxed
window.  Does anyone else have this problem?  A quick look at the code did
not provide any insight.  BTW I'm running 3.51, but did not install terminfo,
and I did set the thing to compile with OLDCURSES defined.

  Cliff

-- 
Clifford C. Skolnick  | "You told me time makes it easy, but you never told me
UUCP: ccs@lazlo.UUCP  | time stands still" -- Gary Numan                      
Phone: (716) 427-8046 |                                                       
  [Space for rent]    | ...!rutgers!rochester!kodak!pcid!gizzmo!lazlo!ccs

kevin@kosman.UUCP (Kevin O'Gorman) (02/11/89)

In article <149@lazlo.UUCP> ccs@lazlo.UUCP (Clifford C. Skolnick) writes:
>I'm trying to get the latest pcomm running smoothly on my system.  All seems
>to be going well, except for the dialing directory.  It seems when I call up
>the directory, garbage appears to the left of the newly created boxed
>window.  Does anyone else have this problem?  A quick look at the code did
>not provide any insight.  BTW I'm running 3.51, but did not install terminfo,
>and I did set the thing to compile with OLDCURSES defined.

No such trouble here, unless you count the fact that the window starts
in column two, so the stuff underneath shows through in column 1.

I'm running terminfo, though.