[unix-pc.sources] Pcomm v1.1

egray@killer.DALLAS.TX.US (Emmet Gray) (09/04/88)

Howdy netlanders!

Well, here it is... hot off the presses.  This is the new release of
my Pcomm program.  I'm sending out the source in 8 parts over a period
of two days.

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

This is the second release of Pcomm.... the v1.0 release appeared in
unix-pc.sources (and in comp.sources.unix as v14i099 thru v14i105) many
months ago. There is a file called Release.notes that describes the
changes from the first release.  Just like before, there is a shell
archive called "Unixpc.shar" that contains the files that are specific
to the AT&T Unix PC 7300/3b1.

By the way... My "normal" machine is down for a few more days, so
be careful on the return path for mail to me.

This is part 1 (of 8) to the Pcomm v1.1 release package.

Emmet P. Gray				US Army, HQ III Corps & Fort Hood
..!uunet!uiucuxc!fthood!egray		Attn: AFZF-DE-ENV
         osiris!hood			DEH, Environmental Management Office
	 ^temporary path		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:
#	Doc
# This archive created: Sat Sep  3 15:46:10 1988
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'Doc'" '(53982 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.1
X
X
X
X
X				  written by
X
X				 Emmet P. Gray
X			...!uunet!uiucuxc!fthood!egray
X
X
X
X
X
X
X        Pcomm is a public domain telecommunication program for Unix that
X        is  designed  to  operate similar to the MSDOS program, ProComm.
X        ProComm (TM) is  copyrighted  by  Datastorm  Technologies,  Inc.
X        This  is a completely new program and contains no ProComm source
X        code.  This is not a Datastorm product.
X
X
X
X			       Table of Contents
X
X
X
X
X	1. INTRODUCTION .......... 3       5. UTILITY FUNCTIONS ..... 20
X	1.1 Abbreviations ........ 3       5.1 Program information .. 20
X	1.2 Requirements ......... 3       5.2 Setup screen ......... 20
X	1.3 Support files ........ 4       5.3 Change directory ..... 20
X					   5.4 Clear screen ......... 20
X	2. RUNNING PCOMM ......... 5       5.5 Toggle duplex ........ 20
X	2.1 Hot key .............. 5       5.6 Hang up the phone .... 20
X	2.2 Status line .......... 5       5.7 Printer logging ...... 21
X	2.3 Help screen .......... 6       5.8 Toggle CR - CR/LF .... 21
X	2.4 Exit Pcomm ........... 6       5.9 Break ................ 21
X
X	3. SETUP SCREENS ......... 7	   6. FILE FUNCTIONS ........ 22
X	3.1 Prompting ............ 7       6.1 Send files ........... 22
X	3.2 TTY setup ............ 8       6.2 Receive files ........ 23
X	3.3 Modem setup .......... 9       6.3 Pass thru mode ....... 24
X	3.4 Terminal setup ....... 10      6.4 Directory ............ 24
X	3.5 General setup ........ 11      6.5 Screen dump .......... 25
X	3.6 ASCII transfer setup . 12      6.6 Start data logging ... 25
X					   6.7 Toggle logging ....... 25
X	4. MAJOR FUNCTIONS ....... 15
X	4.1 Dialing directory .... 15      7. DIALING WINDOW ........ 26
X	4.2 Redial ............... 17
X	4.3 Keyboard macros ...... 17
X	4.4 Line settings ........ 18
X	4.5 Exit Pcomm ........... 19
X	4.6 Unix gateway ......... 19
X
X
X
X
X
X
X	      Appendix A - Typical Modem Configuration ...... 27
X	      Appendix B - AT&T Unix PC 7300/3b1 Dial Codes . 28
X	      Appendix C - Using Telebit Trailblazers ....... 30
X
X	1. 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 popular file transfer protocols
X		+o Data logging (log of the terminal session)
X		+o Printer logging
X		+o Screen dump
X		+o Shell escapes
X		+o Help screen
X		+o Keyboard macros
X		+o User customization
X		+o Administrative logging of phone calls
X		+o Administrative limits on long distance access
X
X	Pcomm  does  not  emulate  any  particular  terminal.   Whatever
X	terminal you're on, is what the remote system "sees".
X
X	1.1 Abbreviations
X
X	Pcomm uses the notation "^A-X" to mean control-A followed by the
X	letter  X.  The dash (-) in the notation is just for clarity, it
X	is not included in the actual command sequence.  Also, there  is
X	no distinction between upper and lower case letters.
X
X	The following abbreviations appear in Pcomm:
X
X		<CR>	carriage return key (sometimes labled "Enter")
X		<ESC>	escape key
X		<SPACE>	space bar
X		<DEL>	del key
X		<up>	up arrow key
X		<down>	down arrow key
X		LF	line feed character (control-J)
X		CR	carriage return character (control-M)
X
X	1.2 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
X	"U"  in place of "up arrow" and the letter "N" in place of "down
X	arrow" (the letter "D" would have been a  more  obvious  choice,
X	but, unfortunately, it is used elsewhere).
X
X	1.3 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	won't have write permission on these files,  it's  assumed  that
X	they  will copy one or more of these standard files to their own
X	directories and edit them to suit their needs.
X
X	Pcomm can use the environmental variable "PCOMM" to  search  for
X	these  "private"  support  files.   If  used,  the variable must
X	contain the path to the directory containing the files.  You can
X	"mix  and  match" the use of standard and private support files.
X	For example, the pcomm.modem file is rarely changed by the  user
X	so  there  would  be  no  need  to copy that file to the private
X	directory.
X
X	The following directories  are  searched  to  find  the  support
X	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 default directory (compiled into Pcomm)
X
X	2. 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
X	used when searching for the Pcomm support files.  This option is
X	often useful for "borrowing" someone else's dialing directory.
X
X	The "-f" option is used to specify automatic dialing of an entry
X	in  the  dialing  directory.   The  "index" field in the dialing
X	directory (described later) is checked against the string  given
X	on  the  command  line.   If  a  match  is  found, that entry is
X	automatically dialed.
X
X	2.1 Hot key
X
X	Pcomm uses a "hot key" to precede each command.  (The  value  of
X	the  hot key is a user tunable parameter, but for the purpose of
X	this 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
X	example,  to  get the help screen, you type control-A (to get to
X	the command mode)  then  the  number  0  (to  display  the  help
X	screen).   When  a  command  is  completed, Pcomm returns to the
X	terminal mode.
X
X	NOTE:  While in the command mode,  the  communication  with  the
X	remote system is temporarily suspended.
X
X	2.2 Status line
X
X	Whenever Pcomm is in the  command  mode  (or  is  not  currently
X	connected  to a remote) a status line is displayed at the bottom
X	of the screen.  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	2.3 Help screen
X
X	The help screen gives  a  brief  review  of  all  the  available
X	commands.   To  access  the  help screen type ^A and "0" (zero).
X	The typical help screen will 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-<down>|
X  | Keyboard Macros .. ^A-M  Change Directory. ^A-B  Pass Thru Mode. ^A-T     |
X  | Line Settings .... ^A-P  Clear Screen .... ^A-C  Directory ..... ^A-F     |
X  | Exit Pcomm ....... ^A-X  Toggle Duplex ... ^A-E  Screen Dump ....^A-G     |
X  | Unix Gateway ..... ^A-4  Hang Up Phone ... ^A-H  Start Data Log. ^A-1     |
X  |                          Printer On/Off .. ^A-L  Toggle Log .... ^A-2     |
X  |                          Toggle CR-CR/LF . ^A-3                           |
X  |                          Break Key ....... ^A-7                           |
X  |                                                                           |
X  +------------------------ Press any key to continue ------------------------+
X
X	2.4 Exit Pcomm
X
X	To exit Pcomm, you 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 press the letter "y" (carriage return not required).
X
X	3. SETUP SCREENS
X
X	Pcomm allows you to change many of the default parameters.   The
X	setup  screen  is  accessed by typing ^A and "s".  The following
X	screen is 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 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 press the escape key.
X
X	Changes made affect the current Pcomm session only.  To make the
X	changes become the default, you select the "s" option.
X
X	3.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
X	for user input and to give more information  on  what  is  being
X	asked.   Pcomm  will  beep at any illegal input.  The escape key
X	<ESC> will abort any prompt.  The prompt types are:
X
X		+o  Character  prompt.   Asks  you  to  input  a   single
X		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
X		choose  the  current  selection by pressing the carriage
X		return or change the selection  by  pressing  the  space
X		bar.
X
X	3.2 TTY setup
X
X	The TTY setup allows you to assign the serial ports  that  Pcomm
X	is allowed to use, and what is attached to each port.  A typical
X	TTY setup screen might look like this:
X
X	-------------------------- TTY Setup ---------------------------
X
X		 TTY name        Modem name      Init speed
X
X		 1) tty10        HAYES               0
X		 2) tty11        HAYES               0
X		 3) tty12        DIRECT              0
X		 4) tty13        TELEBIT             0
X		 5) tty13        FAST_TELEBIT        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 type "11" at the prompt, etc.
X
X	The TTY setup fields are:
X
X		1) TTY name.  This is the name of the serial  port  that
X		Pcomm  will  be  allowed  to  use.  Notice that the path
X		component of the name, "/dev/" is not used.
X
X		2) Modem name.  This a key word that is  used  later  to
X		link the modem database with the TTY database.  The name
X		could be any combination of  letters  or  numbers  (both
X		upper and lower 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) Init speed.  Normally Pcomm will initialize the modem
X		at  the baud rate in the dialing directory.  If the init
X		speed is non-zero, the initialization string  is  always
X		sent  at  the  specified  baud  rate.   The baud rate is
X		selected from a "menu prompt".  See Appendix C  for more
X		information about the use of this feature.
X
X	NOTE:  It is often best to put the fastest modem/TTYs at the end
X	of the TTY database.
X
X	3.3 Modem setup
X
X	The modem setup contains the commands to make  the  modem  dial,
X	hang up the phone, etc.  A typical modem setup screen might look
X	like this:
X
X	-------------------------- Modem Setup -------------------------
X
X		 1) Modem name (1 of 4) ... HAYES
X		 2) Modem init string ..... ATS7=45S11=70E0Q0V1X4&D2!
X		 3) Dialing command ....... ATDT
X		 4) Dialing cmd suffix .... !
X		 5) Hang up string ........ ~~+++~~ATH0!
X		 6) Auto baud detect ...... Y
X		 7) 300 baud connect ...... CONNECT!
X		 8) 1200 baud connect ..... CONNECT 1200
X		 9) 2400 baud connect ..... CONNECT 2400
X		10) 4800 baud connect .....
X		11) 9600 baud connect .....
X		12) 19200 baud connect ....
X		13) No connect string 1 ... BUSY
X		14) No connect string 2 ... VOICE
X		15) No connect string 3 ... NO CARRIER
X		16) 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  key  word  that  links  the
X		modem  database with the TTY database.  A menu prompt is
X		used  to  select  the  modem  name  (and  the  remaining
X		parameters  that  go  with  it).   The  "(1 of 4)" field
X		indicates there are additional modems in the database.
X
X		2) Modem initialization string.  This  is  sent  to  the
X		modem whenever the port is selected.  Consult your modem
X		manual for the codes to be used.  Notice the use of  the
X		"!"  character.  This is the "character synonym" for the
X		carriage return.
X
X	NOTE:  See section  3.5  for  the  complete  list  of  character
X	synonyms.  To remove the special meaning of a character synonym,
X	you must prepend a "\" to the character.
X
X		3) Dialing command.  The first part of  the  command  to
X		make  the  modem  dial.   It  is  assumed that the phone
X		number will immediately follow.
X
X		4) Dialing command suffix.  The last part of the command
X		to  make  the  modem  dial.   Typically this will be the
X		carriage return "character synonym".
X
X		5) Hang up string.  The command to make the  modem  hang
X		up  the  phone.   The  character  synonym for a 1 second
X		pause is the tilde "~" character.
X
X		6) Auto baud detect.  Should Pcomm attempt to change the
X		baud  rate  of  the  TTY  to  the baud rate matching the
X		connect  string?   This  feature  requires  the  connect
X		strings to be unique.
X
X		7-12) Connect strings.  The  return  messages  when  the
X		modem   has  connected  to  the  remote.   If  different
X		messages are returned for each baud rate  at  which  the
X		modem answers, then they should be specified.
X
X	NOTE:  Pcomm uses the connect strings to  determine  which  baud
X	rates  the  modem is capable of supporting.  For example, if the
X	4800 baud connect string  is  empty,  Pcomm  assumes  the  modem
X	can not support 4800 baud.
X
X	NOTE:  If two connect strings are very  similar,  (for  example,
X	"CONNECT"  is  entirely  contained  in  "CONNECT  1200"),  it is
X	possible that the return code from  the  modem  will  match  the
X	incorrect  string.   To  prevent  this  from  happening, use the
X	command synonym for the carriage return to terminate the shorter
X	string (for example, use "CONNECT!" instead of "CONNECT").
X
X		13-16) No connect strings.  The messages returned by the
X		modem when no connection is made.
X
X	3.4 Terminal setup
X
X	The terminal setup allows you to define  the  hot  key  and  the
X	mapping of the end-of-line characters.  A typical terminal setup
X	menu will look like this:
X
X	---------------------- Terminal Setup --------------------------
X
X			1) Hot key (decimal) ...... 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
X		definable  hot key.  Consult an ASCII/decimal conversion
X		chart for the decimal values of other characters.
X
X		2) ASCII version of hot  key.   This  is  the  printable
X		version  of the hot key used by Pcomm in the help screen
X		and status line.
X
X		3) Duplex.  A menu prompt is  shown  to  select  between
X		FULL  duplex  and HALF duplex.  In the half duplex mode,
X		characters sent to the remote system are  also  sent  to
X		the  the  screen.   (The duplex mode can also be changed
X		"on the fly" by the ^A-E command.)
X
X		4) Flow control.  A  menu  prompt  is  shown  to  select
X		between  XON/XOFF  flow  control  and  NONE.   The  flow
X		control selected here is only used during  the  terminal
X		session, not during file transfers.
X
X		5-6) CR translations.  The  end-of-line  characters  for
X		both  incoming  and  outgoing  carriage  returns  can be
X		altered to suit  the  remote  system's  needs.   A  menu
X		prompt provides the following choices:
X
X			+o CR (no translation)
X			+o CR/LF translate CR to CR/LF
X
X		The incoming CR translation can also be changed "on  the
X		fly" with the ^A-3 command.
X
X	3.5 General setup
X
X	The general setup allows you to define  the  character  synonyms
X	and  the  default  files  used  by  the  screen  dump  and other
X	features.  A 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			 8) Break character ........ %
X
X			 9) Aborted downloads ...... KEEP
X
X			10) Connect delay (sec) .... 35
X			11) Redial delay (sec) ..... 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
X		default  when the data logging is activated (^A-1).  The
X		log file name can be changed "on the fly"  by  the  ^A-1
X		command.
X
X		2) Screen dump file.  The file name to be used  for  the
X		screen 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
X		you  to  select  YES  or  NO.   This feature is not used
X		during file transfers.
X
X		4-8) Character synonyms.  These are symbols  that  Pcomm
X		uses to represent special characters (or perform special
X		functions) when sending commands to the modem.  Synonyms
X		are   useful   for   entering   and  displaying  special
X		characters in a human readable form.  The synonyms are:
X
X			+o Pause for 1 second
X			+o The carriage return character (control-M)
X			+o Convert the next character to control-xx
X			+o The escape character (control-[)
X			+o Send a modem break
X
X	NOTE:  To prevent the special meaning of one of these characters
X	prepend a "\" to it.
X
X		9) Aborted downloads.  When a download  aborts  (fails),
X		should  the  partially completed file be kept?  The menu
X		prompt allows "KEEP" or "DELETE".
X
X		10) Connect delay.  The number  of  seconds  Pcomm  will
X		wait for the modem to return a status code.
X
X		11) Redial delay.  The number of seconds to wait  before
X		Pcomm tries to call the number again.
X
X	3.6 ASCII transfer setup
X
X	This setup screen allows you to select options to  be  used  for
X	ASCII  uploads  and  downloads.   A typical ASCII transfer setup
X	will look 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 ......... ADD CR
X
X				 ASCII DOWNLOAD
X
X			7) Transfer timeout (sec) . 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
X		in  that  it  copies  outgoing characters to the screen.
X		The options are YES and NO.
X
X		2) Expand blank lines.  Should a blank line (LF alone)
X		be expanded to a space and LF?  Some BBS systems use a
X		blank line to signal the end of an  ASCII  upload.   The
X		options are 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,
X		100, or 150.
X
X		4) Pace output.  Should each character sent be  delayed?
X		Very  old  BBS  systems may require this.  The choice is
X		YES or NO.
X
X		5)  CR  translation.   The  menu  prompt  provides   the
X		following choices for upload translations:
X
X			+o NONE (no translation)
X			+o ADD LF translate CR to CR/LF
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 LF to CR/LF
X			+o STRIP remove the LF character
X
X		7) Transfer timeout.  The number of seconds to  be  used
X		to determine the end of an ASCII download.  You can halt
X		the transfer before the timer goes off  by  hitting  the
X		<ESC> key.
X
X		8-9) Same as 5) and 6) above, except the translations
X		apply to ASCII downloading.
X
X	4. MAJOR FUNCTIONS
X
X	When Pcomm is invoked without  the  "-f"  command  line  option,
X	you're  placed  in  the  terminal mode with a blank screen and a
X	status line.  However, since Pcomm hasn't yet selected a  serial
X	port  to  use, characters typed at the blank screen are ignored.
X	Normally the first command you'll use is ^A-D to  bring  up  the
X	dialing directory menu.
X
X	4.1 Dialing directory
X
X	To dial another system, you 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
X	dialing  code  such as "#5" in lieu of "5" alone.  Long distance
X	codes could contain access numbers such as those  that  MCI  and
X	Sprint require.
X
X	A typical dialing directory will 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               555-8686   9600-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)                   19200-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>/<down> 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  characters  are  just  for
X	looks,  and  don't  get  sent  to  the  modem.   To  prevent the
X	stripping of one of these characters, prepend a "\" to it.
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
X		with  the  "-f" command line option.  This field is also
X		used to specify a particular TTY for the entry.
X
X	NOTE:  On all hard-wired ports, the index field must be  set  to
X	the  name  of  the  port.  For example, if tty12 is a hard-wired
X	port to "System A", then the dialing directory entry for "System
X	A" will 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
X		distance  dialing code.  Prompts you to save the changes
X		to disk.  A typical revise screen would look like this:
X
X	+--------------------------------------------------------------+
X	|                                                              |
X	|   Entry to revise? _          (Entry Number, +,-,@,#)        |
X	|                                                              |
X	+--------------------------------------------------------------+
X
X		If a dialing directory entry is selected, each field  of
X		the  entry  is shown with its current settings.  You can
X		enter a new value, press a carriage return to skip  past
X		a  field,  or  enter a single space character to erase a
X		field.  An <ESC> at any field will abort the command.
X
X		P) Print (display) the long distance dialing codes.
X
X		<up>/<down>) Scroll the dialing directory up or down  10
X		lines.   Use  the  up and down arrow keys to access this
X		feature.
X
X		M) Manual dial.  Prompts you for a phone  number  rather
X		than using a number already in the dialing directory.
X
X		D) Delete an entry or a range of entries.   Prompts  you
X		to save the changes to disk.
X
X		L) Print.  Send the dialing directory to the printer  or
X		a file of your choice.
X
X		1-100) Entry number.  Dial  the  phone  for  that  entry
X		number.
X
X	NOTE:  To access the port directly without dialing  (perhaps  to
X	send  the dial codes yourself), select an empty entry or enter a
X	single space character at phone number prompt of the manual dial
X	option.
X
X		<CR> Carriage return.  Scroll the dialing directory down
X		one line.
X
X	4.2 Redial
X
X	The redial feature is a misnomer; it really is a queuing  system
X	that  allows  Pcomm to dial several numbers in a cycle until one
X	of them answers.
X
X	When you invoke the redial command with  ^A-R,  you're  prompted
X	for  a list of dialing directory numbers.  (You may also prepend
X	a long 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.  An <ESC> aborts this command.
X
X	4.3 Keyboard macros
X
X	Keyboard macros are used as a shortcut  to  send  commonly  used
X	strings  to  the  remote system with only a few keystrokes.  The
X	characters used to identify the macros are  the  shifted  number
X	keys.   For  example,  if the string "hello" was assigned to the
X	"!" key (the shifted number 1 key), then when  you  press  ^A-!,
X	the string "hello" is sent to the remote.
X
X	NOTE:  While a keyboard macro is being sent to the  remote,  the
X	incoming  characters  are  temporarily  suspended.   This  often
X	results in an awkward visual effect.
X
X	To review or edit the  keyboard  macros,  you  type  ^A-M.   The
X	following screen will appear:
X
X		+------------------------------------------------------+
X		|                   Keyboard Macros                    |
X		|------------------------------------------------------|
X		|                                                      |
X		|  ^A-! hello                                          |
X		|  ^A-@                                                |
X		|  ^A-#                                                |
X		|  ^A-$                                                |
X		|  ^A-%                                                |
X		|  ^A-^                                                |
X		|  ^A-&                                                |
X		|  ^A-*                                                |
X		|  ^A-(                                                |
X		|  ^A-)                                                |
X		|                                                      |
X		|  Macro key to revise: _                              |
X		|                                                      |
X		+---------------- Press <ESC> to continue -------------+
X
X	To edit a macro, you type the macro key character  (without  the
X	leading  hot key).  After typing the new string information, you
X	will be prompted to save the changes to disk.  To erase an entry
X	enter a single space character.
X
X	NOTE:  All of the character synonyms described  in  section  3.5
X	are available for use with the keyboard macros.
X
X	4.4 Line settings
X
X	The line settings menu is  invoked  by  ^A-P.   A  typical  line
X	settings menu will 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	While dialing  a  remote,  the  line  settings  in  the  dialing
X	directory  entry  are  automatically  used.   Therefore the line
X	settings menu is used to fine tune the values during a  terminal
X	session or to select the parameters for manual dialing.  You can
X	make the current setting the  default  by  selecting  the  "Save
X	Changes" option.
X
X	The current line settings are also displayed in the status line.
X
X	NOTE:  During file transfers,  certain  parameters  (namely  the
X	data  bits  and parity) will be temporarily changed.  The status
X	line will *not* reflect these temporary promotions.
X
X	4.5 Exit Pcomm
X
X	To exit Pcomm, you type ^A-X.  The phone is hung up (if  a  call
X	was  in  progress),  the  print  and  data  logging features are
X	closed, and the TTY resources are released.
X
X	NOTE:  Pcomm drops the DTR (Data Terminal  Ready)  on  the  port
X	before exiting to Unix.
X
X	4.6 Unix gateway
X
X	To temporarily suspend Pcomm and spawn a Unix  shell,  you  type
X	^A-4.   To  return  to  Pcomm,  you  exit  the  shell  normally,
X	typically with ^D or "exit".
X
X	NOTE:  The SHELL environmental variable  is  used  to  determine
X	which program to invoke.
X
X	5. UTILITY FUNCTIONS
X
X	The following commands perform secondary functions.
X
X	5.1 Program information
X
X	To display the opening information screen, you type ^A-I.  Press
X	any key to return to the terminal mode.
X
X	5.2 Setup screen
X
X	The setup screens are described in detail in section 3  of  this
X	manual.
X
X	5.3 Change directory
X
X	To change the  current  working  directory  while  still  inside
X	Pcomm,  you  type  ^A-B.  A screen similar to the following will
X	appear:
X
X	+-- Change directory ------------------------------------------+
X	|                                                              |
X	|   Current directory: /usr/egray                              |
X	|   New directory: _                                           |
X	|                                                              |
X	+--------------------------------------------------------------+
X
X	Abbreviations known to the shell are  acceptable;  for  example,
X	the  "~"  character  will be translated to the home directory in
X	the csh or ksh shell.
X
X	5.4 Clear screen
X
X	To clear the local screen and home the cursor, you type ^A-C.
X
X	NOTE:  The remote system may not  "know"  the  screen  has  been
X	cleared,  and  may  make  assumptions  about the screen that are
X	incorrect.
X
X	5.5 Toggle duplex
X
X	The ^A-E command changes the duplex mode from FULL to  HALF,  or
X	from  HALF  to  FULL.   The status line shows the current duplex
X	mode.
X
X	5.6 Hang up the phone
X
X	To hang up the phone, you type ^A-H.  The  word  "disconnecting"
X	will briefly show in the status line.
X
X	NOTE:  Pcomm does not drop the DTR (Data Terminal Ready)  during
X	a  hang  up.   Therefore,  this  would  have no effect on direct
X	lines.
X
X	5.7 Printer logging
X
X	The ^A-L command toggles the printer logging  on  or  off.   The
X	current printer status is displayed in the status line.
X
X	NOTE:  Since all printing goes to the normal  Unix  print  spool
X	program,  the  characters  will not print on the printer as they
X	appear on the screen.  The printing will actually begin when the
X	printer  logging  is  turned *off* and the complete print job is
X	sent to the spool.
X
X	NOTE:  Due to a technical limitation of Pcomm, characters  typed
X	while in the half duplex mode will not appear in the print log.
X
X	5.8 Toggle CR - CR/LF
X
X	The  ^A-3  command  toggles  the   incoming   line   termination
X	characters  between  CR  and CR/LF.  The status line shows
X	the current settings (in the next to the last field).
X
X	5.9 Break
X
X	The ^A-7 command sends a modem break to the remote system.   The
X	word "break" is (very) briefly displayed on the status line.
X
X	NOTE:  This not the same as the break key on  the  keyboard  (we
X	don't  want to send a break to the local system, we want to send
X	it to the *remote*).
X
X	6. FILE FUNCTIONS
X
X	One of  the  most  important  features  of  a  telecommunication
X	program  is  the  ability to transfer files.  The following file
X	transfer protocols are implemented:
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	(external)	?		?		?
X
X	Notes:  1 CP/M style file name
X		2 MSDOS style file name and file size
X		3 Not needed!
X
X	The external  "protocol"  is  really  a  method  of  running  an
X	external  program from Pcomm to accomplish a file transfer.  The
X	most common use of this feature would be to run Kermit or  Chuck
X	Forsberg's Zmodem (sz/rz/dsz) program.
X
X	NOTE: The external protocol feature can also be used (misused?)
X	to pipe the output of a Unix command to the remote.
X
X	NOTE: The protocols that send file name information, convert the
X	Unix style file name to fit the MSDOS name restrictions.
X
X	6.1 Send files
X
X	To send a file to the remote, you'll first have to instruct  the
X	remote system to receive the file, then type ^A-"up arrow".  The
X	following screen will 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					|  7) (external)   |
X					|                  |
X					|  <ESC> to Abort  |
X					|                  |
X					|  Protocol: _     |
X					+------------------+
X
X	You then select the type of protocol at the prompt, and  another
X	window similar to this will appear:
X
X	+-- Send xmodem -----------------------------------------------+
X	|                                                              |
X	|   Enter filename: _                                          |
X	|                                                              |
X	+--------------------------------------------------------------+
X
X	Now you 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 screen similar to  the
X	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
X	complete",  and  "bytes transferred" fields will be continuously
X	updated.  If errors occur the "errors  this  block"  and  "total
X	error count" fields will be updated and the "last message" field
X	will contain a message about the error.
X
X	At the end of the transfer, Pcomm will beep and  return  to  the
X	terminal  mode.   If  an  error  occurred  and  the transfer was
X	aborted, you will  be  prompted  to  acknowledge  the  error  by
X	pressing a key before returning to the terminal mode.
X
X	6.2 Receive files
X
X	To receive a file (or group of  files)  from  a  remote  system,
X	you'll  have  to  first  instruct  the  remote system, then type
X	^A-"down arrow".  Receiving a file  is  basically  the  same  as
X	sending a file.
X
X	NOTE:  Some systems  do  not  pad  the  end  of  the  file  with
X	control-Z's  and  therefore  files  might  grow  in  length when
X	received.
X
X	NOTE:  Due  to  a  technical  limitation  of  Pcomm,  characters
X	received  during  an  ASCII  download  will  not reappear on the
X	screen when you return to the terminal mode.
X
X	6.3 Pass thru mode
X
X	The pass through mode is used when you have two or more machines
X	in  a  communications  daisy chain.  The following diagram shows
X	an example of this type of arrangement:
X
X		+---------+          +---------+          +---------+
X		| IBM PC  |          | Unix    |          | IBM PC  |
X		| running | -------> | running | -------> | running |
X		| ProComm | <------- | Pcomm   | <------- | RBBS    |
X		+---------+          +---------+          +---------+
X
X	If a file is to be transferred from  the  last  machine  to  the
X	first   machine,  the  middle  machine  must  appear  completely
X	transparent.  The middle machine must "forward the data" without
X	altering it in any way.  The pass through mode "expires" after a
X	designated period of of inactivity,  after  which  the  user  is
X	returned to the terminal mode.
X
X	To access the pass through mode, you type ^A-T.  The following
X	screen will appear:
X
X	+-- Pass Thru Mode --------------------------------------------+
X	|                                                              |
X	|   Enter the expiration time (5-60 sec) : _                   |
X	|                                                              |
X	+--------------------------------------------------------------+
X
X	NOTE:  While in the pass through mode, no Pcomm command  to  the
X	middle  machine  will  be honored.  Therefore, the *only* way to
X	exit this mode is to not type anything on the keyboard until the
X	expiration period has elapsed.
X
X	NOTE:  The baud rates to and from the middle machine need not be
X	the same, however the slowest speed determines the overall speed
X	of the transfer (the weakest link in the chain).
X
X	6.4 Directory
X
X	To obtain a listing of a directory on  the  local  system  while
X	still  running  Pcomm, you type ^A-F.  The following screen will
X	appear:
X
X	+-- List Directory --------------------------------------------+
X	|                                                              |
X	|   Current directory: /usr/egray                              |
X	|   File spec (wildcards allowed): _                           |
X	|                                                              |
X	+--------------------------------------------------------------+
X
X	Abbreviations 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
X	6.5 Screen dump
X
X	To dump the contents of the current screen  (minus  any  windows
X	showing)  you type ^A-G.  The contents of the screen are written
X	to the file specified in the general setup for this purpose.  If
X	the file already exists, the screen contents are appended to the
X	file.  The message "screen dump"  will  briefly  appear  in  the
X	status line.
X
X	6.6 Start data log
X
X	To start the data logging, or change  the  file  used  for  data
X	logging, you type ^A-1.  The following screen will 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
X	prompt,  otherwise,  enter a new file name.  If the file already
X	exits, the new data is appended to the file.
X
X	The status of the logging is shown in the status line.
X
X	NOTE:  Due to a technical limitation of Pcomm, characters  typed
X	while in the half duplex mode will not appear in the log file.
X
X	6.7 Toggle logging
X
X	To temporarily suspend data logging or to start it again without
X	being prompted for the file name, you type ^A-2.
X
X	7. 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    |                  Redial delay time: 5                                |
X    |                          Index/TTY:                                  |
X    |                 Result of last try:                                  |
X    |                                                                      |
X    |   <SPACE>: Recycle    <DEL>: Remove from queue    E: Change delays   |
X    |                                                                      |
X    +------------------------- Press <ESC> to abort -----------------------+
X
X	The options available during the dialing window are:
X
X		SPACE) Press the space bar to stop the  dialing  of  the
X		current  entry and go on to the next entry in the queue.
X		If there is only one  entry  in  the  queue,  then  that
X		number is redialed.
X
X		DEL) Press the DEL key to remove the current number from
X		the queue.
X
X		E) Press the letter "E"  to  change  the  connect  delay
X		time,  or  the  redial  delay  time  (the  pause between
X		dailing attempts).  You will be  prompted  to  save  the
X		changes to disk.
X
X	NOTE:  While the DEL and E  options  are  being  processed,  the
X	dialing is temporarily suspended.
X
X	Appendix A
X
X			  Typical Modem Configuration
X
X	I can't begin to describe how to configure every modem  to  work
X	with  Pcomm.   There  are  however, several guidelines that will
X	apply to virtually any modem.
X
X		1) Pcomm  doesn't  care  about  the  DCD  (Data  Carrier
X		Detect) settings of the modem.
X
X		2) It would be nice (but not essential) if the  loss  of
X		the  DTR  (Data Terminal Ready) caused the modem to hang
X		up.
X
X		3) Pcomm doesn't care if commands are echoed back by the
X		modem  (it  might save a few milliseconds if echoing was
X		turned off).
X
X		4) Some sort of  result  codes  are  required.   Numeric
X		result  codes are ok...  but since they are displayed on
X		the screen, word result codes will make more sense.
X
X		5) If the modem can return different  result  codes  for
X		each  baud  rate at which it answers, then by all means,
X		use them.
X
X		6) Anything that is  returned  by  the  modem,  but  not
X		listed in the modem setup, is ignored.
X
X		7) Systems running uugetty (the  bi-directional  version
X		of  getty that comes with HDB uucp) should include extra
X		commands in the initialization  string  to  assure  that
X		uugetty  switches  to  its  dial  out  mode.   Normally,
X		"AT!~AT!~" causes enough dialogue to  force  uugetty  to
X		release the line.
X
X	For example,  a  2400  baud  Hayes  compatible  modem  might  be
X	configured with the following command:
X
X		AT S7=45 S11=70 E0 Q0 V1 X4 &D2
X
X			AT	Hayes attention command
X			S7=45	Wait 45 seconds for an answer
X			S11=70	70 ms touch tone dialing
X			E0	Don't echo commands (not essential)
X			Q0	Turn result codes on
X			V1	Return word result codes
X			X4	Use as many result codes as you've got
X			&D2	Hang up when DTR is lost (nice to have)
X
X
X	Appendix B
X
X			     AT&T Unix PC 7300/3b1
X				  Dial Codes
X
X	The dialing codes used by the  OBM  (On  Board  Modem)  are  not
X	straight-forward.   The  modem setup, as distributed, looks like
X	this:
X
X	-------------------------- Modem Setup -------------------------
X
X		 1) Modem name (1 of 2) ... OBM
X		 2) Modem init string .....
X		 3) Dialing command ....... %
X		 4) Dialing cmd suffix .... @
X		 5) Hang up string ........
X		 6) Auto baud detect ...... N
X		 7) 300 baud connect ...... CONNECT
X		 8) 1200 baud connect ..... CONNECT
X		 9) 2400 baud connect .....
X		10) 4800 baud connect .....
X		11) 9600 baud connect .....
X		12) 19200 baud connect ....
X		13) No connect string 1 ...
X		14) No connect string 2 ...
X		15) No connect string 3 ...
X		16) No connect string 4 ...
X
X	----------------------------------------------------------------
X	OPTION ==> _                               Press <ESC> to return
X
X	The relevant fields of the modem setup are:
X
X		1) Modem name.  This must be "OBM".
X
X	NOTE:  Pcomm uses the modem name as a flag  to  determine  which
X	dialing  method  to  use.  The string "OBM" is a "reserved word"
X	that Pcomm uses to switch to  the  AT&T Unix PC 7300/3b1 dialing
X	method.
X
X		3) Dialing command.  This should be "%" for  touch  tone
X		dialing or "^" for pulse dialing.
X
X		4) Dialing cmd suffix.  This must be the "@" character.
X
X		6) Auto baud detect.  The OBM cannot  use  the auto baud
X		detect feature.
X
X		7-8) Connect strings.  Although the OBM doesn't actually
X		return any result codes, these fake fields are required.
X
X	Additional OBM dialing codes from the phone(7) manual:
X
X		"~"	wait for next dial tone
X		","	pause 2 seconds
X		":"	pause 10 seconds
X		"&"	perform a hookflash
X		"%"	begin tone dialing
X		"^"	begin pulse dialing
X
X	These codes can be inserted into the phone  number  string,  for
X	example:
X
X		555-1234~56	dial 555-1234, wait for tone, dial 56
X		9,555-1234	dial 9, wait 2 seconds, dial 555-1234
X		%555^1234	dial 555 using tone, 1234 using pulse
X
X	NOTE:  The  dialing  codes  for  the  OBM  are  not  subject  to
X	character  synonym translations, therefore the "%", "^", and "~"
X	characters do NOT have to be preceded by the  "\"  character  to
X	remove their special meaning.
X
X	Appendix C
X
X			   Using Telebit Trailblazers
X
X	The Telebit Trailblazer modem is probably representative of  the
X	newer   high   speed  intelligent  modems  available  today  and
X	therefore warrants a more detailed discussion.
X
X	1) Locked interface speed
X
X		Trailblazers have  the  ability  to  maintain  a  locked
X		interface  speed with the computer without regard to the
X		connected baud rate.  For example, some people  find  it
X		necessary  to  lock the interface speed at 9600 baud (or
X		some other speed) for normal operations.  However, Pcomm
X		assumes the interface speed is the same as the connected
X		baud rate.
X
X		The "init speed" field of the TTY database  was  created
X		to solve this problem.  If this value is non-zero, Pcomm
X		will send the initialization string to the modem at this
X		baud  rate.   Normally, Pcomm would use the baud rate in
X		the dialing directory to send the init string.
X
X		The init string would now contain the  codes  to  unlock
X		the  interface,  enter the autobaud mode on receipt of a
X		break, and arrange for the loss of the DTR to return the
X		modem   to  its  previous  locked  state.   For  Telebit
X		Trailblazers this would be S66=0, S51=255, and S52=2.
X
X	2) Multiple setups
X
X		Users of Trailblazers often require  a  different  "init
X		string"  or  "dial  string" depending on the target baud
X		rate.  For example, the init strings for 9600 and  19200
X		baud may contain the command "S50=255" (to  wait for the
X		Telebit PEP tones) whereas the slower init strings would
X		contain "S50=0".
X
X		This problem is solved by creating an  additional  modem
X		entry  in  the  modem  database.  For example, you could
X		have an entry called "TELEBIT" for  baud  rates  in  the
X		range    of    300-2400   and   another   entry   called
X		"FAST_TELEBIT"  for  baud  rates   in   the   range   of
X		9600-19200.
X
X		Pcomm uses the connect strings to determine if the modem
X		can   handle  the  requested  baud  rate.   So,  if  the
X		"TELEBIT" entry had connect strings for 300,  1200,  and
X		2400  baud  it  would  be selected only if the requested
X		baud rate was in that range.  Likewise, the FAST_TELEBIT
X		would have connect strings only for 9600 and 19200 baud.
X
X	3) Baud rate synchronization
X
X		In contrast to the Hayes  2400  modem,  the  Trailblazer
X		does  not  immediately  synchronize with the serial port
X		when the baud rate is changed during the modem's command
X		mode.
X
X		To solve this problem, the init string and  dial  string
X		should contain the break character synonym followed by a
X		sufficient  number  of  A's  to  allow  the   modem   to
X		synchronize.   The default character synonym for a modem
X		break is the "%".
X
X	4) Sample TTY database
X
X		The following is the contents of the sample TTY database:
X
X		TTY name	Modem name	Init speed
X
X		1) tty10	HAYES		   0
X		2) tty11	HAYES		   0
X		3) tty12	DIRECT		   0
X		4) tty13	TELEBIT		   0
X		5) tty13	FAST_TELEBIT	   0
X
X		Notice that entries 4 and 5 share the same TTY.
X
X	NOTE:  The examples assume the  modem  interface  speed  is  not
X	locked.  See paragraph 1 for additional codes to be added to the
X	init string if the lock interface feature is used.
X
X	5) Sample modem database entry for TELEBIT
X
X		The third entry in the sample modem database is for  the
X		Telebit Trailblazer designated for use at slow speeds.
X
X		1) Modem name (3 of 4) .... TELEBIT
X		2) Modem init string ...... %AAAAAATS50=0S2=43S95=0M1!
X		3) Dialing command ........ %AAAAAATDTW
X		4) Dialing cmd suffix ..... !
X		5) Hang up string ......... ~~+++~~ATH0!
X		6) Auto baud detect ....... Y
X		7) 300 baud connect ....... CONNECT 300
X		8) 1200 baud connect ...... CONNECT 1200
X		9) 2400 baud connect ...... CONNECT 2400
X		10) 4800 baud connect .....
X		11) 9600 baud connect .....
X		12) 19200 baud connect ....
X		13) No connect string 1 ... BUSY
X		14) No connect string 2 ... ERROR
X		15) No connect string 3 ... NO CARRIER
X		16) No connect string 4 ...
X
X	6) Sample modem database entry for FAST_TELEBIT
X
X		The 4th entry is for the Telebit Trailblazer  designated
X		for use at higher speeds.
X
X		1) Modem name (4 of 4) .... FAST_TELEBIT
X		2) Modem init string ...... %AAAAAATS50=255S2=43S95=0M1!
X		3) Dialing command ........ %AAAAAATDTW
X		4) Dialing cmd suffix ..... !
X		5) Hang up string ......... ~~+++~~ATH0!
X		6) Auto baud detect ....... N
X		7) 300 baud connect .......
X		8) 1200 baud connect ......
X		9) 2400 baud connect ......
X		10) 4800 baud connect .....
X		11) 9600 baud connect ..... CONNECT
X		12) 19200 baud connect .... CONNECT
X		13) No connect string 1 ... BUSY
X		14) No connect string 2 ... ERROR
X		15) No connect string 3 ... NO CARRIER
X		16) No connect string 4 ...
echo shar: "46 control characters may be missing from 'Doc'"
SHAR_EOF
if test 53982 -ne "`wc -c < 'Doc'`"
then
	echo shar: "error transmitting 'Doc'" '(should have been 53982 characters)'
fi
fi
exit 0
#	End of shell archive

egray@killer.DALLAS.TX.US (Emmet Gray) (09/04/88)

This is part 2 (of 8) to the Pcomm v1.1 release package.

Emmet P. Gray				US Army, HQ III Corps & Fort Hood
..!uunet!uiucuxc!fthood!egray		Attn: AFZF-DE-ENV
					DEH, 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
#	Makefile
#	Pcomm.1
#	Pcomm.dial_dir
#	Pcomm.modem
#	Pcomm.param
#	Unixpc.shar
#	config.h
#	dial_dir.h
#	misc.h
#	modem.h
#	param.h
#	status.h
#	vcs.h
#	xmodem.h
# This archive created: Sat Sep  3 15:34:53 1988
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'Readme'" '(6391 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
XThings to do first:
X
X	1) Figure out what files you need to extract.  There is a shell
X	archive called "Unixpc.shar" that contains additional (and
X	replacement) files for users of the AT&T Unix PC 7300/3b1.
X
X	2) Create a default directory where the Pcomm support files will
X	go.  A good location might be /usr/local/lib/pcomm.
X
X	3) Copy the sample support files Pcomm.dial_dir, Pcomm.modem,
X	and Pcomm.param to the default directory and rename them to
X	change the uppercase "P" to a lower case "p".  The files should
X	*not* have write permission to all.
X
X	4) Copy (and rename as appropriate) the Pcomm.1 nroff manual to
X	the proper /usr/man directory.
X
X	5) Print the Doc file by piping the output of the Unix "pr"
X	command with the title separated by lots of white space (to help
X	center it), for example:
X
X	pr -h "           Pcomm Reference Manual            " Doc | lp
X
XHow to configure Pcomm:
X
X	1) Edit the "config.h" file to suit your system's needs and your
X	personal taste.  Sites running HoneyDanBer (HDB) UUCP should pay
X	particular attention to the LOCK_DIR, ASCII_PID, and SETUGID
X	definitions.  The definitions in config.h are:
X
X	UNIXPC		If defined, use the dial(3) routines specific
X			to the AT&T Unix PC 7300/3b1.  Useful only if
X			the On Board Modem (OBM) is to be used.
X
X	OLDCURSES	If defined, use the older version of curses(3).
X			(uses termcap in lieu of terminfo).  Some
X			versions of the AT&T Unix PC 7300/3b1 may
X			require this.
X
X	SHAREDMEM	If defined, keeps the virtual screen area in
X			shared memory rather than in a file.  Some
X			performance gains are realized if shared memory
X			is used.
X
X	NOPROMOTE	If defined, do not promote missing video
X			attributes to standout.  Normally, curses(3)
X			attempts to compensate for missing attributes.
X
X	SETUGID		If defined, extra precautions are taken before
X			opening files or doing a shell escape to restore
X			the real UID/GID.  Useful if Pcomm is installed
X			as a set-user-id or get-group-id program.  HDB
X			programs often are set-user-id to uucp.
X
X	LOG_CALLS	If defined, Pcomm will keep an administrative log
X			of all calls.  The log contains the name of the
X			person making the call, the phone number, and a
X			date/time stamp.  Useful for verifying long
X			distance phone bills.
X
X	LOGFILE		The path to the log file (if LOG_CALLS is
X			defined).  It should have write permission to
X			all or be writeable under set-user/group-id
X			conditions.
X
X	LIMIT_LD	If defined, Pcomm will limit long distance
X			(toll) calls to a privileged group.  The file
X			"admin.c" may require tweeking to detect what is
X			a long distance number.
X
X	GROUP_NAME	The name of the group that is allowed to make
X			long distance calls (if LIMIT_LD is defined).
X
X	LPR		The path to the line printer program (this is
X			not the name of the device).
X
X	LPRINT		The path to the "pretty" line printer program.
X			Typically a program that performs a "pr | lp"
X			function.  If none exist, use the same as LPR.
X
X	DEFAULT_DIR	The path to the directory that contains the
X			default Pcomm support files.
X
X	LOCK_DIR	The path to the directory where the UUCP lock
X			files are found.  On HDB systems this would
X			typically be /usr/spool/locks.
X
X	ASCII_PID	If defined, the lock files will contain an ASCII
X			encoded process id (PID).  On HDB systems this
X			is the default.
X
X	KEEP_PORT	If defined, the port will be kept open between
X			dialing attempts to save time.  Some systems
X			may require the modem to be closed and reopened
X			every time.
X
X	XMC_BROKE	Does the status line scroll up when using "magic
X			cookie" terminals?  Some Pyramid and AT&T
X			systems may require this to be defined.  Find a
X			magic cookie terminal (a Wyse 50 for example),
X			and see what happens.
X
X	WGETCH_BROKE	Does the alarm() system call work correctly with
X			the wgetch() function?  Some Masscomp systems
X			will require this to be defined.  Symptom: the
X			initial screen doesn't go away by itself after 5
X			seconds.
X
X	2) Edit the Makefile.  There are provisions in the Makefile to
X	include getcwd() and getopt() routines if they are missing from
X	your system.  You may want to customize the CFLAGS, LDFLAGS, and
X	BIN assignments to suit your needs.
X
X	3) Compile pcomm and pcomm_input.  Type "make".  The Makefile
X	will attempt to install "pcomm" and "pcomm_input" into the BIN
X	directory given in the Makefile.  However, those sites running
X	HDB UUCP software may require you to change the mode of "pcomm"
X	to be set-user-id to uucp.  DO NOT CHANGE THE SET-UID/GID BITS
X	ON THE "pcomm_input" PROGRAM.
X
X	4) Update the sample modem/TTY database.  I know I'm asking the
X	impossible, but...  Read section 3 and the Appendices of the Doc
X	file first, then run Pcomm to update the modem/TTY database by
X	using the TTY Setup and the Modem Setup menues.  You will need
X	to know:
X
X		o The types and number of modems available for dial out
X		o The TTY ports attached to the modems
X		o The range of baud rates at which the modems operate
X		o How to initialize the modems to suit Pcomm's needs
X		o How to make the modems dial
X
X	During this step, you will need write permission on the support
X	files in the default directory.  RESIST THE TEMPTATION TO EDIT
X	THE SUPPORT FILES DIRECTLY.
X
XPortability considerations:
X
X	1) This program was written with AT&T System V in mind.  It
X	makes use of System V specific routines such as shared memory
X	and the ioctl() calls of termio(7).  There is currently no
X	port to Berkeley or v7 Unix.
X
X	2) Pcomm makes use of the bold, blinking and standout video
X	attributes.  My concept of "standout" and "reverse" might be
X	different than yours (I like "standout" to be a brighter version
X	of "reverse").  Check your terminfo database...
X
X	3) The "port.c" file has a place where you can include your own
X	routine to toggle the getty process on a port (if required).
X
X	4) If you compile Pcomm with LOG_CALLS defined, you'll have to
X	look at the code in "admin.c" to see if the long distance
X	detection routine is correct for your site.
X
X	5) Compilers that adhere to the draft ANSI C Standard will bark
X	at the declartions of signal(), perror(), malloc(), fread(), and
X	fwrite().
X
XEmmet P. Gray				US Army, HQ III Corps & Fort Hood
X...!uunet!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 6391 -ne "`wc -c < 'Readme'`"
then
	echo shar: "error transmitting 'Readme'" '(should have been 6391 characters)'
fi
fi
echo shar: "extracting 'Release.notes'" '(5256 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.1
X				21 Aug 88
X
XIncompatibilities with v1.0:
X
X	I've added a few more fields to the pcomm.param and pcomm.modem
X	files.  This means that those files created under previous
X	releases will not be compatible with the v1.1 release.  It might
X	be a good idea to abandon the older files and start over with
X	the sample files in this release.
X
XThings that have changed:
X
X	An awful lot of sloppy programming on my part has now been
X	cleaned up.  This means that porting Pcomm to different versions
X	of Unix will be considerably less painful than before.
X
X	All of the tunable parameters are now in "config.h".
X
X	Pcomm now uses buffered I/O routines.  This yields higher
X	performance I/O at large baud rates.
X
X	File transfers now use high performance CRC calculations.
X
X	If a UUCP lockfile does exist, Pcomm now attempts to determine
X	if the process is still active.
X
X	An external file transfer program can be invoked from the file
X	transfer menu.
X
X	The keyboard macro feature is now supported (although it is
X	rather crude).
X
X	The virtual screen routine now understands a limited subset of
X	escape sequences.
X
X	The virtual screen can now be held in shared memory or in a file.
X
X	The input routine is now contained in a separate program called
X	pcomm_input.
X
X	You can now include a "modem break" in a dial or initialization
X	string.
X
X	A separate "initialization speed" feature was added to support
X	9600 baud modems such as the Telebit Trailblazer.  See Appendix
X	C of the Doc file for more info on the use of this feature.
X
X	I've added a transparent pass through mode to be used in a
X	communications daisy chain.
X
XKnown limitations:
X
X	Whenever Pcomm makes the transition from the terminal mode to
X	the command mode, the true screen contents are lost.  Pcomm
X	tries to keep track of what the true screen looks like in an
X	internal "virtual screen".  This means that the escape sequences
X	known to the hardware have to be emulated in the virtual screen.
X	Unfortunately, the number of escape sequences that are emulated
X	is quite small, so the representation of the true screen is
X	sometimes wrong.
X
X	For the VCS (video command sequence) emulation to work, the
X	terminfo entries on the host machine must match the entries on
X	the remote.
X
X	The disp_tty() routine in s_tty.c currently does not support a
X	NUM_TTY definition of greater than 10.
X
XFuture directions:
X
X	Continue work on the virtual screen routines.
X
X	Add dial back support.
X
X	Use shared memory to overcome the current limitation of outgoing
X	characters in the half duplex mode not appearing in the virtual
X	screen, log files, and print logs.
X
XMany thanks to the following people for bug reports and ideas for
Ximproving the code:
X
X	Andy Pitts	...{mtune,pacbell,kd4nc}!gladys!rbdc!andy
X	Chris Wiener	...ihnp4!{killer,attnssc}!crlabs!cwiener
X	David Brierley	...{sun,decuac,cbosgd,gatech,necntc,ukma}!rayssd!dhb
X	Karl Fox	...cbosgd!mstar!karl
X	Michael Young	...panda!genrad!mrst!sdti!mjy
X	Mark Mendel	...ihnp4!umn-cs!hyper!mark
X	Viet Hoang	...ihnp4!drutx!vgh
X
X--------------------------------------------------------------------------------
X
X			     Pcomm version 1.0
X				12 Mar 88
X
XIncompatibilities with the beta release:
X
X	I've added a bunch of new parameters to the pcomm.param and
X	pcomm.modem files, so the files used with the beta release won't
X	work with the v1.0 release.
X
XThings that have changed:
X
X	Pcomm will attempt to determine if the modem has synchronized at
X	a baud rate different than 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
X	been changed slightly.
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
X	like.  Escape sequences in the virtual screen image will be
X	ignored when the background is repainted.  For example, if
X	you're on a vt100 and you recieve a ^[[2J to clear the screen,
X	the screen *will* be cleared...  but when the screen is
X	repainted, it will contain the characters ^[, [, 2, J (instead
X	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
X	commonly used escape sequences (known to terminfo) will be
X	processed.
X
X	I plan to have an option at compile time to have the virtual
X	screen buffer held on disk [] or in shared memory [].
X
X	The input routine is designed so it could be a standalone
X	program that gets called from Pcomm. []
X
X-------------------------------------------------------------------------------
X
XHave fun...
X
XEmmet P. Gray				US Army, HQ III Corps & Fort Hood
X...!uunet!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 5256 -ne "`wc -c < 'Release.notes'`"
then
	echo shar: "error transmitting 'Release.notes'" '(should have been 5256 characters)'
fi
fi
echo shar: "extracting 'Makefile'" '(3691 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 generic System V Unix
X#
X# for systems without getcwd(3) or getopt(3)
X#
X#GETCWD = getcwd.o
X#GETOPT = getopt.o
X
XCFLAGS = -O
X#CURSES = -ltermlib -lcurses
XCURSES = -lcurses
XLDFLAGS = -s
XSHAR = shar -a
XBIN = /usr/local/bin
X
XPCOMM = $(GETCWD) $(GETOPT) admin.o chg_dir.o curses.o d_delete.o \
X	d_lib.o d_manual.o d_menu.o d_print.o d_prompt.o d_revise.o \
X	data_log.o di_delay.o di_win.o dial.o expand.o help.o info.o \
X	init.o line_set.o list_dir.o ls_menu.o m_lib.o macro.o main.o \
X	n_shell.o p_lib.o passthru.o pexit.o port.o redial.o s_axfer.o \
X	s_gen.o s_menu.o s_modem.o s_prompt.o s_term.o s_tty.o screen.o \
X	st_line.o strings.o terminal.o x_ascii.o x_batch.o x_extrnl.o \
X	x_menu.o x_rcv.o x_send.o x_win.o xmodem.o
X
XINPUT =	input.o vcs.o
X
Xall:	pcomm pcomm_input install
X
Xpcomm:	$(PCOMM)
X	$(CC) $(LDFLAGS) $(PCOMM) -o pcomm $(CURSES)
X
Xpcomm_input:	$(INPUT)
X	$(CC) $(LDFLAGS) $(INPUT) -o pcomm_input $(CURSES)
X	
Xinstall:
X	cp pcomm $(BIN)
X#	rm pcomm
X	cp pcomm_input $(BIN)
X#	rm pcomm_input
X
Xlint:
X	lint -p -Dlint *.c
X
Xshar:
X	cat Doc > pcomm_sh.1
X	$(SHAR) Readme Release.notes Makefile Pcomm.1 Pcomm.dial_dir \
X	Pcomm.modem Pcomm.param Unixpc.shar config.h dial_dir.h misc.h \
X	modem.h param.h status.h vcs.h xmodem.h > pcomm_sh.2
X	$(SHAR) admin.c chg_dir.c curses.c d_delete.c d_lib.c d_manual.c \
X	d_menu.c d_print.c d_prompt.c d_revise.c data_log.c di_delay.c \
X	> pcomm_sh.3
X	$(SHAR) di_win.c dial.c expand.c getcwd.c getopt.c help.c info.c \
X	init.c input.c line_set.c list_dir.c ls_menu.c > pcomm_sh.4
X	$(SHAR) m_lib.c macro.c main.c n_shell.c p_lib.c passthru.c \
X	pexit.c port.c redial.c > pcomm_sh.5
X	$(SHAR) s_axfer.c s_gen.c s_menu.c s_modem.c s_prompt.c s_term.c \
X	s_tty.c screen.c st_line.c strings.c terminal.c > pcomm_sh.6
X	$(SHAR) vcs.c x_ascii.c x_batch.c x_extrnl.c x_menu.c x_rcv.c \
X	> pcomm_sh.7
X	$(SHAR) x_send.c x_win.c xmodem.c > pcomm_sh.8
X
Xadmin.o:	config.h dial_dir.h param.h
Xchg_dir.o:	config.h misc.h
Xcurses.o:	config.h misc.h
Xd_delete.o:	config.h dial_dir.h misc.h param.h
Xd_lib.o:	dial_dir.h param.h
Xd_manual.o:	config.h misc.h dial_dir.h
Xd_menu.o:	config.h dial_dir.h misc.h param.h
Xd_print.o:	config.h dial_dir.h misc.h
Xd_prompt.o:	config.h dial_dir.h misc.h
Xd_revise.o:	config.h dial_dir.h misc.h param.h
Xdata_log.o:	config.h misc.h param.h status.h
Xdi_delay.o:	config.h misc.h param.h
Xdi_win.o:	config.h dial_dir.h misc.h modem.h param.h
Xdial.o:		config.h dial_dir.h misc.h modem.h param.h
Xexpand.o:	config.h
Xhelp.o:		config.h misc.h
Xinit.o:		config.h misc.h status.h
Xinput.o:	config.h misc.h status.h vcs.h
Xline_set.o:	dial_dir.h param.h
Xlist_dir.o:	config.h misc.h
Xls_menu.o:	config.h dial_dir.h misc.h param.h
Xm_lib.o:	modem.h
Xmacro.o:	config.h misc.h param.h
Xmain.o:		config.h dial_dir.h modem.h param.h status.h
Xn_shell.o:	config.h
Xp_lib.o:	param.h
Xpassthru.o:	config.h misc.h
Xpexit.o:	config.h dial_dir.h misc.h param.h status.h
Xport.o:		config.h dial_dir.h modem.h
Xredial.o:	config.h dial_dir.h misc.h
Xs_axfer.o:	config.h misc.h param.h
Xs_gen.o:	config.h misc.h param.h
Xs_menu.o:	config.h misc.h
Xs_modem.o:	config.h misc.h modem.h
Xs_prompt.o:	config.h misc.h
Xs_term.o:	config.h misc.h param.h status.h
Xs_tty.o:	config.h misc.h modem.h
Xscreen.o:	config.h param.h status.h
Xst_line.o:	config.h dial_dir.h misc.h modem.h param.h status.h
Xterminal.o:	config.h dial_dir.h misc.h modem.h param.h status.h
Xvcs.o:		config.h vcs.h
Xx_ascii.o:	config.h misc.h param.h
Xx_batch.o:	config.h misc.h xmodem.h
Xx_extrnl.o:	config.h
Xx_menu.o:	config.h misc.h xmodem.h
Xx_rcv.o:	config.h dial_dir.h misc.h xmodem.h
Xx_send.o:	config.h dial_dir.h misc.h xmodem.h
Xx_win.o:	config.h dial_dir.h misc.h xmodem.h
Xxmodem.o:	config.h misc.h param.h xmodem.h
SHAR_EOF
if test 3691 -ne "`wc -c < 'Makefile'`"
then
	echo shar: "error transmitting 'Makefile'" '(should have been 3691 characters)'
fi
fi
echo shar: "extracting 'Pcomm.1'" '(7955 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
Xdirectory ] [
X.B -f
Xindex ]
X.SH DESCRIPTION
X.I Pcomm
Xis a public domain telecommunication program for Unix that is designed
Xto operate similar to the MSDOS program, ProComm.  ProComm (TM) is
Xcopyrighted by Datastorm Technologies, Inc.
X.PP
XThe "-d" option is used to specify an additional path to search for the
XPcomm support files.
X.PP
XThe "-f" option is used to specify automatic dialing of an entry in the
Xdialing directory.  The "index" field in the dialing directory is
Xchecked against the string given on the command line.  If a match is
Xfound, 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
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.fi
X.RE
X.SH COMMANDS
XThe following commands are accessible by pressing a user definable "hot
Xkey" followed by a letter, number, or arrow key.  The default "hot key"
Xis control-A.  The notatation "^A-X" means control-A followed by the
Xletter X.  The dash (-) is for clarity, and is not a part of the command
Xsequence.
X.TP
X.B ^A-0
XHelp Screen.  Display a brief review of the available commands.  Uses
Xthe number zero "0" not the letter "O".
X.TP
X.B ^A-D
XDialing Directory.  The dialing directory screen is used to display and
Xmaintain the database of phone number entries, and to select an entry
Xfor dialing.  To select an entry to dial, just enter the entry number at
Xthe prompt.  The following commands are available from the dialing
Xdirectory:
X.RS 5
X.TP
X.B R
XRevise (or add) a dialing directory entry or a long distance dialing
Xcode.
X.TP
X.B P
XPrint (display) the long distance dialing codes.
X.TP
X.B up/down
XScroll the dialing directory up or down 10 lines.  Uses the up and down
Xarrow keys.
X.TP
X.B M
XManual dial.  Prompts for a phone number rather than using a number
Xalready in the dialing directory.
X.TP
X.B D
XDelete an entry or a range of entries.
X.TP
X.B L
XPrint.  Send the dialing directory to the printer or a file of your
Xchoice.
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.I Pcomm
Xwill dial the numbers in a cycle until one of them answers.
X.TP
X.B ^A-M
XAllows the user to maintain a list of keyboard macros assigned to the
Xshifted number keys.  When pressed, the string assigned to that key is
Xsent to the remote system.
X.TP
X.B ^A-P
XAdjust the current communication line settings.  Display a menu of baud
Xrate, parity, data bit, and stop bit choices.  Allows the new choice to
Xbe saved and become the default.  After dialing a remote, the line
Xsettings in the dialing directory entry are automatically used.  The
Xcurrent line settings are shown in the status line.
X.TP
X.B ^A-X
XExit from
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
XDisplay the program information screen.
X.TP
X.B ^A-S
XDisplay a choice of setup screens.  The following sub-menus are
Xavailable:
X.RS 5
X.TP
X.B 1
XTTY Setup.  This setup assigns the tty ports that
X.I Pcomm
Xis allowed to use, and what is attached to each port.
X.TP
X.B 2
XModem Setup.  The modem setup contains the commands to make the modem
Xdial, hang up the phone, etc.
X.TP
X.B 3
XTerminal Setup.  The terminal setup contains the definition of the "hot
Xkey" and the mapping of the end-of-line characters.
X.TP
X.B 4
XGeneral Setup.  The general setup contains the default log file name,
Xand the set of character synonyms.
X.TP
X.B 5
XASCII Transfer Setup.  This setup screen contains additional character
Xtranslations allowed during ASCII file transfers.
X.TP
X.B S
XSave the changes to disk.
X.RE
X.TP
X.B ^A-B
XChange the current working directory.
X.TP
X.B ^A-C
XClear the local screen and home the cursor.
X.TP
X.B ^A-E
XToggle the duplex mode from full to half, or from half to full.  The
Xstatus line shows the current duplex mode.
X.TP
X.B ^A-H
XHang up the phone.  Disconnect the phone, but remain in
X.I Pcomm.
X.TP
X.B ^A-L
XToggle 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 incoming line termination characters between the carriage
Xreturn and the carriage return line feed pair.  This affects the
Xterminal session only, not the file transfers.  The current settings are
Xshown in the status 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
XDisplay a menu of file transfer protocols to be used to send files to a
Xremote system.  Uses the up arrow key.
X.TP
X.B ^A-down
XDisplay file transfer protocols to be used to receive files from a
Xremote system.  Uses the down arrow key.
X.TP
X.B ^A-F
XDisplay the contents of a Unix directory.
X.TP
X.B ^A-G
XDump the contents of the screen to a specified file.  Special graphics
Xcharacters may not be represented accurately in the file.
X.TP
X.B ^A-1
XBegin data logging.  Prompts the user for the name of the file that will
Xbe used to collect a complete record of the terminal session.
X.TP
X.B ^A-2
XToggle the data logging option without prompting for a new file name.
XThe status line shows the current data logging mode.
X.SH FILE TRANSFERS
X.I Pcomm
Xunderstands the following file transfer protocols:
X.PP
X.RS 5
X.nf
Xprotocol        packet          error           multiple
Xname            size            method          files?
X---------       --------        ------------    --------
Xxmodem          128             checksum/CRC    no
Xxmodem-1k       128/1024        checksum/CRC    no
Xmodem7          128             checksum        yes
Xymodem          128/1024        CRC             yes
Xymodem-g        128/1024        none            yes
XASCII           none            none            no
X.fi
X.RE
X.PP
XIn addition,
X.I Pcomm
Xcan use an external program, such as kermit or the sz/rz/dsz programs,
Xto transfer files.
X.PP
X.SH CONFIGURATION
X.I Pcomm
Xmust have access to the terminfo or termcap data for the terminal being
Xused.  The minimum capabilities include a screen size of at least 80
Xcolumns by 24 lines and cursor movement capabilities.  Running
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 letter "U"
Xfor "up arrow" and "N" for "down arrow".
X.PP
XThere are three Pcomm support files that contain the default parameters,
Xthe modem/tty database, and dialing directory entries.  Users may
Xmaintain private versions of these files in a directory of their choice.
X.I Pcomm
Xuses the environmental variable PCOMM to search for these "private"
Xversions.  The following directories are searched to find the support
Xfiles:
X.PP
X.RS 5
X.nf
X+o directory given with the "-d" option
X+o directory in the PCOMM environmental variable
X+o current directory
X+o default directory (compiled into Pcomm)
X.fi
X.RE
X.PP
XThe "index" field in the dialing directory serves two purposes.  The
Xfirst 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 device
Xis 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
XPcomm Reference Manual, xmodem(1), mdm(1)
echo shar: "12 control characters may be missing from 'Pcomm.1'"
SHAR_EOF
if test 7955 -ne "`wc -c < 'Pcomm.1'`"
then
	echo shar: "error transmitting 'Pcomm.1'" '(should have been 7955 characters)'
fi
fi
echo shar: "extracting 'Pcomm.dial_dir'" '(320 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;555-8686;9600-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);;19200-E-7-1;F;tty12
SHAR_EOF
if test 320 -ne "`wc -c < 'Pcomm.dial_dir'`"
then
	echo shar: "error transmitting 'Pcomm.dial_dir'" '(should have been 320 characters)'
fi
fi
echo shar: "extracting 'Pcomm.modem'" '(598 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;0
XTTY_2=tty11;HAYES;0
XTTY_3=tty12;DIRECT;0
XTTY_4=tty13;TELEBIT;0
XTTY_5=tty13;FAST_TELEBIT;0
XMODEM_1a=HAYES;ATS7=45S11=70E0Q0V1X4&D2!;ATDT;!;~~+++~~ATH0!
XMODEM_1b=Y;CONNECT!;CONNECT 1200;CONNECT 2400;;;
XMODEM_1c=BUSY;VOICE;NO CARRIER;
XMODEM_2a=DIRECT;;;;
XMODEM_2b=N;;;;;;
XMODEM_2c=;;;
XMODEM_3a=TELEBIT;%AAAAAATS50=0S2=43S95=0M1!;%AAAAAATDTW;!;~~+++~~ATH0!
XMODEM_3b=Y;CONNECT 300;CONNECT 1200;CONNECT 2400;;;
XMODEM_3c=BUSY;ERROR;NO CARRIER;
XMODEM_4a=FAST_TELEBIT;%AAAAAATS50=255S2=43S95=0M1!;%AAAAAATDTW;!;~~+++~~ATH0!
XMODEM_4b=N;;;;;CONNECT;CONNECT
XMODEM_4c=BUSY;ERROR;NO CARRIER;
SHAR_EOF
if test 598 -ne "`wc -c < 'Pcomm.modem'`"
then
	echo shar: "error transmitting 'Pcomm.modem'" '(should have been 598 characters)'
fi
fi
echo shar: "extracting 'Pcomm.param'" '(453 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=|
XBRK_CHAR=%
XABORT=KEEP
XC_DELAY=35
XR_DELAY=5
XLECHO=NO
XEXPAND=NO
XCR_DELAY=0
XPACE=NO
XCR_UP=NONE
XLF_UP=ADD CR
XTIMER=5
XCR_DN=STRIP
XLF_DN=NONE
XLD_PLUS=
XLD_MINUS=
XLD_AT=8,
XLD_POUND=9
XMAC_1=hello
XMAC_2=
XMAC_3=
XMAC_4=
XMAC_5=
XMAC_6=
XMAC_7=
XMAC_8=
XMAC_9=
XMAC_0=
SHAR_EOF
if test 453 -ne "`wc -c < 'Pcomm.param'`"
then
	echo shar: "error transmitting 'Pcomm.param'" '(should have been 453 characters)'
fi
fi
echo shar: "extracting 'Unixpc.shar'" '(12507 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#	Readme.7300
X#	config.h
X# This archive created: Wed Aug 24 22:01:02 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'" '(3891 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
XXCFLAGS = -O
XX#CURSES = -lcurses -ltermcap
XXCURSES = -lcurses
XXLD = ld -s
XXSHAR = shar -a
XXBIN = /usr/local/bin
XX
XXSHAREDLIB = shlib_c.ifile
XX
XXPCOMM = admin.o chg_dir.o curses.o d_delete.o d_lib.o d_manual.o \
XX	d_menu.o d_print.o d_prompt.o d_revise.o data_log.o di_delay.o \
XX	di_win.o dial.o expand.o help.o info.o init.o line_set.o \
XX	list_dir.o ls_menu.o m_lib.o macro.o main.o n_shell.o p_lib.o \
XX	passthru.o pexit.o port.o redial.o s_axfer.o s_gen.o s_menu.o \
XX	s_modem.o s_prompt.o s_term.o s_tty.o screen.o st_line.o \
XX	strings.o terminal.o x_ascii.o x_batch.o x_extrnl.o x_menu.o \
XX	x_rcv.o x_send.o x_win.o xmodem.o
XX
XXINPUT =	input.o vcs.o
XX
XXOTHERS = setvbuf.o doprnt.o
XX
XXall:	pcomm pcomm_input install
XX
XXpcomm:	$(PCOMM) $(OTHERS) $(SHAREDLIB)
XX	$(LD) $(PCOMM) $(OTHERS) $(CURSES) /lib/crt0s.o $(SHAREDLIB) -o pcomm
XX
XXpcomm_input:	$(INPUT) $(OTHERS) $(SHAREDLIB)
XX	$(LD) $(INPUT) $(OTHERS) $(CURSES) /lib/crt0s.o $(SHAREDLIB) -o pcomm_input
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
XXinstall:
XX	cp pcomm $(BIN)
XX#	rm pcomm
XX	cp pcomm_input $(BIN)
XX#	rm pcomm_input
XX
XXlint:
XX	lint -p -Dlint *.c
XX
XXshar:
XX	cat Doc > pcomm_sh.1
XX	$(SHAR) Readme Release.notes Makefile Pcomm.1 Pcomm.dial_dir \
XX	Pcomm.modem Pcomm.param Unixpc.shar config.h dial_dir.h misc.h \
XX	modem.h param.h status.h vcs.h xmodem.h > pcomm_sh.2
XX	$(SHAR) admin.c chg_dir.c curses.c d_delete.c d_lib.c d_manual.c \
XX	d_menu.c d_print.c d_prompt.c d_revise.c data_log.c di_delay.c \
XX	> pcomm_sh.3
XX	$(SHAR) di_win.c dial.c expand.c getcwd.c getopt.c help.c info.c \
XX	init.c input.c line_set.c list_dir.c ls_menu.c > pcomm_sh.4
XX	$(SHAR) m_lib.c macro.c main.c n_shell.c p_lib.c passthru.c \
XX	pexit.c port.c redial.c > pcomm_sh.5
XX	$(SHAR) s_axfer.c s_gen.c s_menu.c s_modem.c s_prompt.c s_term.c \
XX	s_tty.c screen.c st_line.c strings.c terminal.c > pcomm_sh.6
XX	$(SHAR) vcs.c x_ascii.c x_batch.c x_extrnl.c x_menu.c x_rcv.c \
XX	> pcomm_sh.7
XX	$(SHAR) x_send.c x_win.c xmodem.c > pcomm_sh.8
XX
XXadmin.o:	config.h dial_dir.h param.h
XXchg_dir.o:	config.h misc.h
XXcurses.o:	config.h misc.h
XXd_delete.o:	config.h dial_dir.h misc.h param.h
XXd_lib.o:	dial_dir.h param.h
XXd_manual.o:	config.h misc.h dial_dir.h
XXd_menu.o:	config.h dial_dir.h misc.h param.h
XXd_print.o:	config.h dial_dir.h misc.h
XXd_prompt.o:	config.h dial_dir.h misc.h
XXd_revise.o:	config.h dial_dir.h misc.h param.h
XXdata_log.o:	config.h misc.h param.h status.h
XXdi_delay.o:	config.h misc.h param.h
XXdi_win.o:	config.h dial_dir.h misc.h modem.h param.h
XXdial.o:		config.h dial_dir.h misc.h modem.h param.h
XXexpand.o:	config.h
XXhelp.o:		config.h misc.h
XXinit.o:		config.h misc.h status.h
XXinput.o:	config.h misc.h status.h vcs.h
XXline_set.o:	dial_dir.h param.h
XXlist_dir.o:	config.h misc.h
XXls_menu.o:	config.h dial_dir.h misc.h param.h
XXm_lib.o:	modem.h
XXmacro.o:	config.h misc.h param.h
XXmain.o:		config.h dial_dir.h modem.h param.h status.h
XXn_shell.o:	config.h
XXp_lib.o:	param.h
XXpassthru.o:	config.h misc.h
XXpexit.o:	config.h dial_dir.h misc.h param.h status.h
XXport.o:		config.h dial_dir.h modem.h
XXredial.o:	config.h dial_dir.h misc.h
XXs_axfer.o:	config.h misc.h param.h
XXs_gen.o:	config.h misc.h param.h
XXs_menu.o:	config.h misc.h
XXs_modem.o:	config.h misc.h modem.h
XXs_prompt.o:	config.h misc.h
XXs_term.o:	config.h misc.h param.h status.h
XXs_tty.o:	config.h misc.h modem.h
XXscreen.o:	config.h param.h status.h
XXst_line.o:	config.h dial_dir.h misc.h modem.h param.h status.h
XXterminal.o:	config.h dial_dir.h misc.h modem.h param.h status.h
XXvcs.o:		config.h vcs.h
XXx_ascii.o:	config.h misc.h param.h
XXx_batch.o:	config.h misc.h xmodem.h
XXx_extrnl.o:	config.h
XXx_menu.o:	config.h misc.h xmodem.h
XXx_rcv.o:	config.h dial_dir.h misc.h xmodem.h
XXx_send.o:	config.h dial_dir.h misc.h xmodem.h
XXx_win.o:	config.h dial_dir.h misc.h xmodem.h
XXxmodem.o:	config.h misc.h param.h xmodem.h
XSHAR_EOF
Xif test 3891 -ne "`wc -c < 'Makefile'`"
Xthen
X	echo shar: "error transmitting 'Makefile'" '(should have been 3891 characters)'
Xfi
Xfi
Xecho shar: "extracting 'Pcomm.modem'" '(151 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;0
XXTTY_2=tty000;DIRECT;0
XXMODEM_1a=OBM;;%;@;
XXMODEM_1b=N;CONNECT;CONNECT;;;;
XXMODEM_1c=;;;
XXMODEM_2a=DIRECT;;;;
XXMODEM_2b=N;;;;;;
XXMODEM_2c=;;;
XSHAR_EOF
Xif test 151 -ne "`wc -c < 'Pcomm.modem'`"
Xthen
X	echo shar: "error transmitting 'Pcomm.modem'" '(should have been 151 characters)'
Xfi
Xfi
Xecho shar: "extracting 'Readme.7300'" '(3827 characters)'
Xif test -f 'Readme.7300'
Xthen
X	echo shar: "will not over-write existing file 'Readme.7300'"
Xelse
Xsed 's/^X//' << \SHAR_EOF > 'Readme.7300'
XX				  Pcomm v1.1
XX			 Additional Notes for users of
XX			     AT&T Unix PC 7300/3b1
XX
XX	1) The shared libraries on your system contain Terminal Access
XX	Method (TAM) routines in lieu of curses(3) routines.  However,
XX	many of the routines have the same names!  This means that
XX	curses library is not compatible with the shared library.  So,
XX	to circumvent the problem, an alternate shared library "link
XX	directive file" is needed.  The Ifile.sh file is a shell script
XX	that is run by the Makefile to create this alternate file.  The
XX	alternate file has the references to the TAM routines removed
XX	(actually, they just have an 'x' placed in the names).  The
XX	actual shared library binaries are NOT altered.  We just fool
XX	the linker into believing that the TAM routines aren't there.
XX
XX	2) Before Pcomm can be compiled, the curses library routines
XX	must be installed on your system.  The diskette labled
XX	"Curses/Terminfo Programmer's Package" is a part of the "Unix
XX	Developement Set".  Likewise, before Pcomm can be used, the
XX	terminfo database must be installed.  The diskettes labled
XX	"Curses/Terminfo End User Package" and "Terminfo Database" are
XX	a part of the "Unix Foundation Set"
XX
XX	3) If you are running Unix version 3.0 or older, you must edit
XX	the "config.h" file to change the OLDCURSES definition from
XX	"#undef" to "#define".  I understand the older version of
XX	curses(3) is very buggy.
XX
XX	4) Did you know that your system can use DEC vt100 style line
XX	drawing character?  Curses automatically uses the "alternate"
XX	character set (if found) to draw the boxes and lines rather than
XX	using the '-' and '|' characters.  To allow your system to use
XX	this feature, there are two things you must do:
XX
XX		1) Load the line drawing font in slot 1 prior to running
XX		a program requiring them.  This can be done by typing:
XX
XX			setf /usr/lib/wfont/BLD.ft 1
XX
XX		...or permanently install this font in slot 1 by adding
XX		the following two lines to the end of the /etc/rc file:
XX
XX			sfont /usr/lib/wfont/BLD.ft 1
XX			setf /usr/lib/wfont/BLD.ft 1
XX
XX		2) Tell curses(3) about the alternate character set by
XX		editing the terminfo database.
XX
XX		To get a copy of the terminfo entry to play with,
XX		you type:
XX
XX			infocmp -I s4 > s4.ti
XX
XX		now add the following line (with a leading tab) to the
XX		's4.ti' file:
XX
XX			acsc=+h\,g.e-fjjkkllmmnnqqttuuvvwwxx,
XX
XX		recompile the new entry:
XX
XX			tic s4.ti
XX
XX	5) The "tset" command is broken on every version of Unix this
XX	box has ever seen (it is commented out of /etc/profile for a
XX	good reason).  One of tset's functions is to send a string to
XX	initialize the settings of the terminal and to set the tab
XX	stops.  The fact that this program doesn't work is often
XX	overlooked because the console (as well as a lot of other
XX	terminals) doesn't require any initialization.  However, if you
XX	call into your system from a remote terminal that *does* require
XX	initialization, you've got trouble.
XX
XX	For example, curses(3) looks at the terminfo database to see if
XX	your terminal has "hardware tabs", if so, it expects the tab
XX	stops to be set.  Ignoring tabs by using "stty -tabs" (to
XX	convert tabs to spaces) won't work, in fact, curses(3) RESETS
XX	things as if you had typed "stty tabs"!
XX
XX	Likewise, my terminfo entry for PCPLUS v1.1's emulation of a
XX	vt102 has "^[)0" in the initialization string to load the line
XX	drawing character set.  It needs to be sent to the terminal
XX	before running Pcomm.
XX
XX	I understand that future version of Unix will have an option to
XX	the "tput" command to perform all the initialization with only
XX	one argument.  Meanwhile, a somewhat longer solution is to edit
XX	/etc/profile and add the following commands at the bottom:
XX
XX		eval `tput iprog`
XX		tput is1
XX		tput is2
XX		if [ -n "`tput tab`" ] ;then
XX			stty tabs
XX		else
XX			stty -tabs
XX		fi
XX		tabs
XX		cat -s "`tput if`"
XX		tpuf is3
XX		echo "\r\c"
XSHAR_EOF
Xif test 3827 -ne "`wc -c < 'Readme.7300'`"
Xthen
X	echo shar: "error transmitting 'Readme.7300'" '(should have been 3827 characters)'
Xfi
Xfi
Xecho shar: "extracting 'config.h'" '(1584 characters)'
Xif test -f 'config.h'
Xthen
X	echo shar: "will not over-write existing file 'config.h'"
Xelse
Xsed 's/^X//' << \SHAR_EOF > 'config.h'
XX/*
XX * Various tunable parameters.  This should appear before any other local
XX * header file.
XX */
XX
XX/* Use the dialing routines specific to the AT&T Unix PC 7300/3b1 */
XX#define	UNIXPC
XX
XX/* Older versions of curses(3) use termcap in lieu of terminfo */
XX#undef	OLDCURSES
XX
XX/* Use shared memory in lieu of a file for the virtual screen */
XX#define	SHAREDMEM
XX
XX/* Should a missing video attribute be promoted to standout? */
XX#define NOPROMOTE
XX
XX/* Use extra precautions if Pcomm is set-user-id or set-group-id */
XX#undef	SETUGID
XX
XX/* Should Pcomm make a log of all phone calls? */
XX#undef	LOG_CALLS
XX
XX/* The name of the log file (if used).  */
XX#define	LOGFILE		"/usr/adm/phone.calls"
XX
XX/* Should long distance (toll) calls be limited to a specific group? */
XX#undef	LIMIT_LD
XX
XX/* The name of the privileged group for limiting long distance calls */
XX#define	GROUP_NAME	"uucp"
XX
XX/* The path to the line printer program */
XX#define	LPR		"/usr/bin/lp"
XX
XX/* The path to the "pretty" printer program (if none, use same as LPR) */
XX#define	LPRINT		"/usr/bin/lp"
XX
XX/* The path to the default directory containing the Pcomm support files */
XX#define	DEFAULT_DIR	"/usr/local/lib/pcomm"
XX
XX/* The path to the directory where UUCP locks are found */
XX#define	LOCK_DIR	"/usr/spool/uucp"
XX
XX/* Do the lock files use ASCII encoded PID's? */
XX#undef	ASCII_PID
XX
XX/* Should Pcomm optimize redialing by keeping the TTY port open */
XX#define	KEEP_PORT
XX
XX/* Does the status line scroll up on "magic cookie" terminals? */
XX#define XMC_BROKE
XX
XX/* Does the alarm() system call work correctly with the wgetch() function? */
XX#undef	WGETCH_BROKE
XSHAR_EOF
Xif test 1584 -ne "`wc -c < 'config.h'`"
Xthen
X	echo shar: "error transmitting 'config.h'" '(should have been 1584 characters)'
Xfi
Xfi
Xexit 0
X#	End of shell archive
SHAR_EOF
if test 12507 -ne "`wc -c < 'Unixpc.shar'`"
then
	echo shar: "error transmitting 'Unixpc.shar'" '(should have been 12507 characters)'
fi
fi
echo shar: "extracting 'config.h'" '(1582 characters)'
if test -f 'config.h'
then
	echo shar: "will not over-write existing file 'config.h'"
else
sed 's/^X//' << \SHAR_EOF > 'config.h'
X/*
X * Various tunable parameters.  This should appear before any other local
X * header file.
X */
X
X/* Use the dialing routines specific to the AT&T Unix PC 7300/3b1 */
X#undef	UNIXPC
X
X/* Older versions of curses(3) use termcap in lieu of terminfo */
X#undef	OLDCURSES
X
X/* Use shared memory in lieu of a file for the virtual screen */
X#define	SHAREDMEM
X
X/* Should a missing video attribute be promoted to standout? */
X#define NOPROMOTE
X
X/* Use extra precautions if Pcomm is set-user-id or set-group-id */
X#undef	SETUGID
X
X/* Should Pcomm make a log of all phone calls? */
X#undef	LOG_CALLS
X
X/* The name of the log file (if used).  */
X#define	LOGFILE		"/usr/adm/phone.calls"
X
X/* Should long distance (toll) calls be limited to a specific group? */
X#undef	LIMIT_LD
X
X/* The name of the privileged group for limiting long distance calls */
X#define	GROUP_NAME	"uucp"
X
X/* The path to the line printer program */
X#define	LPR		"/usr/bin/lp"
X
X/* The path to the "pretty" printer program (if none, use same as LPR) */
X#define	LPRINT		"/usr/bin/lp"
X
X/* The path to the default directory containing the Pcomm support files */
X#define	DEFAULT_DIR	"/usr/local/lib/pcomm"
X
X/* The path to the directory where UUCP locks are found */
X#define	LOCK_DIR	"/usr/spool/uucp"
X
X/* Do the lock files use ASCII encoded PID's? */
X#undef	ASCII_PID
X
X/* Should Pcomm optimize redialing by keeping the TTY port open */
X#define	KEEP_PORT
X
X/* Does the status line scroll up on "magic cookie" terminals? */
X#undef	XMC_BROKE
X
X/* Does the alarm() system call work correctly with the wgetch() function? */
X#undef	WGETCH_BROKE
SHAR_EOF
if test 1582 -ne "`wc -c < 'config.h'`"
then
	echo shar: "error transmitting 'config.h'" '(should have been 1582 characters)'
fi
fi
echo shar: "extracting 'dial_dir.h'" '(870 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	q_num[NUM_QUEUE];	/* entry numbers in the queue */
X	char	q_ld[NUM_QUEUE];	/* LD codes in the queue */
X
X	int	d_entries;		/* number of entries in the file */
X	int	d_cur;			/* the current entry */
X
X	char	*d_path;		/* path to the pcomm.dial_dir file */
X};
X
X#ifndef MAIN
Xextern struct DIAL_DIR *dir;
X#endif /* MAIN */
SHAR_EOF
if test 870 -ne "`wc -c < 'dial_dir.h'`"
then
	echo shar: "error transmitting 'dial_dir.h'" '(should have been 870 characters)'
fi
fi
echo shar: "extracting 'misc.h'" '(1404 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(3) functions and to make
X * the old curses(3) routines happy.  ("config.h" must be included first).
X */
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 */
X
X#ifdef OLDCURSES
Xtypedef char chtype
X#endif /* OLDCURSES */
X
X#ifdef ACS_HLINE
X#define VERT		(chtype)0
X#define HORZ		(chtype)0
X#else /* ACS_HLINE */
X#define VERT		(chtype)'|'
X#define HORZ		(chtype)'-'
X#define ACS_VLINE	(chtype)'|'
X#define ACS_HLINE	(chtype)'-'
X#endif /* ACS_HLINE */
X
X#define BEL		7
X#define BS		8
X#define ESC		27
X#define DEL		127
SHAR_EOF
if test 1404 -ne "`wc -c < 'misc.h'`"
then
	echo shar: "error transmitting 'misc.h'" '(should have been 1404 characters)'
fi
fi
echo shar: "extracting 'modem.h'" '(1538 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 16 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	init_sp[NUM_TTY];	/* initialization 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	*hang_up[NUM_MODEM];	/* hang up the modem */
X	char	auto_baud[NUM_MODEM];	/* should we sync baud rates? */
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	char	*m_path;		/* path to the pcomm.modem file */
X};
X
X#ifndef MAIN
Xextern struct MODEM *modem;
X#endif /* MAIN */
SHAR_EOF
if test 1538 -ne "`wc -c < 'modem.h'`"
then
	echo shar: "error transmitting 'modem.h'" '(should have been 1538 characters)'
fi
fi
echo shar: "extracting 'param.h'" '(2757 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	44
X#define LINE_SET	0
X#define TERM_SETUP	4
X#define GEN_SETUP	10
X#define DELAY_TIMES	19
X#define ASCII_SETUP	21
X#define LD_CODES	30
X#define MACROS		34
X
Xstruct PARAM {
X				/* 0-3 used in ls_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-18 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	brk_char;		/* modem break synonym */
X	char	*abort;			/* destination of aborted downloads */
X
X				/* 19-20 used in gen_setup() & delay_times() */
X	int	c_delay;		/* connect delay time */
X	int	r_delay;		/* redial delay time */
X
X				/* 21-29 used in axfer_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				/* 30-33 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				/* 34-43 used in macro() */
X	char	*mac_1;			/* shifted 1 macro */
X	char	*mac_2;			/* shifted 2 macro */
X	char	*mac_3;			/* shifted 3 macro */
X	char	*mac_4;			/* shifted 4 macro */
X	char	*mac_5;			/* shifted 5 macro */
X	char	*mac_6;			/* shifted 6 macro */
X	char	*mac_7;			/* shifted 7 macro */
X	char	*mac_8;			/* shifted 8 macro */
X	char	*mac_9;			/* shifted 9 macro */
X	char	*mac_0;			/* shifted 0 macro */
X
X	char	*p_path;		/* path to the pcomm.param file */
X};
X
X#ifndef MAIN
Xextern struct PARAM *param;
X#endif /* MAIN */
SHAR_EOF
if test 2757 -ne "`wc -c < 'param.h'`"
then
	echo shar: "error transmitting 'param.h'" '(should have been 2757 characters)'
fi
fi
echo shar: "extracting 'status.h'" '(767 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 status flags, and other various changeable things.  Obviously
X * the "config.h" file must appear before this file.
X */
X
X#define MAX_ROW		64
X#define MAX_COL		128
X#define PATH		128
X
Xstruct STATUS {
X	int	fd;			/* file descriptor for TTY */
X	int	add_lf;			/* add <CR> to <LF>? */
X	int	log;			/* status of log option */
X	int	print;			/* status of print option */
X	char	log_path[PATH];		/* data logging file */
X#ifdef SHAREDMEM
X	int	clr;			/* flag to clear the screen */
X	int	row;			/* cursor row position */
X	int	col;			/* cursor column position */
X	char	vs[MAX_ROW][MAX_COL+1];	/* the virtual screen */
X#else /* SHAREDMEM */
X	char	vs_path[PATH];		/* virtual screen file */
X#endif /* SHAREDMEM */
X};
X
X#ifndef MAIN
Xextern struct STATUS *status;
X#endif /* MAIN */
SHAR_EOF
if test 767 -ne "`wc -c < 'status.h'`"
then
	echo shar: "error transmitting 'status.h'" '(should have been 767 characters)'
fi
fi
echo shar: "extracting 'vcs.h'" '(330 characters)'
if test -f 'vcs.h'
then
	echo shar: "will not over-write existing file 'vcs.h'"
else
sed 's/^X//' << \SHAR_EOF > 'vcs.h'
X/*
X * Definitions to support the detection of video command sequences
X */
X
X#define VCS_SIZE	25
X#define NUM_VCS		9
X
X#define HOME		0
X#define CLR_EOL		1
X#define CLR_EOS		2
X#define CLEAR		3
X#define MV_UP		4
X#define MV_DOWN		5
X#define MV_RIGHT	6
X#define MV_LEFT		7
X#define MV_DIRECT	8
X
X#define YES		1
X#define NO		0
X#define MAYBE		(-1)
SHAR_EOF
if test 330 -ne "`wc -c < 'vcs.h'`"
then
	echo shar: "error transmitting 'vcs.h'" '(should have been 330 characters)'
fi
fi
echo shar: "extracting 'xmodem.h'" '(464 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	7
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#define EXTRNL		6
X
X#define ABORT		(-1)
X#define ERROR		(-2)
X#define CANCEL		(-3)
X
X#define CHECKSUM	0
X#define CRC_CHECKSUM	1
X#define CRC		2
X#define NONE		3
SHAR_EOF
if test 464 -ne "`wc -c < 'xmodem.h'`"
then
	echo shar: "error transmitting 'xmodem.h'" '(should have been 464 characters)'
fi
fi
exit 0
#	End of shell archive

egray@killer.DALLAS.TX.US (Emmet Gray) (09/04/88)

This is part 3 (of 8) to the Pcomm v1.1 release package.

Emmet P. Gray				US Army, HQ III Corps & Fort Hood
..!uunet!uiucuxc!fthood!egray		Attn: AFZF-DE-ENV
					DEH, 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:
#	admin.c
#	chg_dir.c
#	curses.c
#	d_delete.c
#	d_lib.c
#	d_manual.c
#	d_menu.c
#	d_print.c
#	d_prompt.c
#	d_revise.c
#	data_log.c
#	di_delay.c
# This archive created: Sat Sep  3 15:34:55 1988
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'admin.c'" '(2880 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#include <stdio.h>
X#include <grp.h>
X#include "config.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
X/*ARGSUSED*/
Xvoid
Xlog_calls(i)
Xint i;
X{
X#ifdef LOG_CALLS
X	FILE *fp;
X	char *number, *build_num(), *date, *ctime(), *getlogin(), buf[80];
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		sprintf(buf, "Can't open log file '%s'", LOGFILE);
X		error_win(1, buf, "Contact your system administrator");
X	}
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;
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
X/*ARGSUSED*/
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(GROUP_NAME);
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", "");
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#if defined(LOG_CALLS) || defined(LIMIT_LD)
X/*
X * Put together the complete phone number but strip out the extraneous
X * characters.
X */
X
Xstatic char *
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 2880 -ne "`wc -c < 'admin.c'`"
then
	echo shar: "error transmitting 'admin.c'" '(should have been 2880 characters)'
fi
fi
echo shar: "extracting 'chg_dir.c'" '(1305 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 you have
X * search permission.
X */
X
X#include <curses.h>
X#include "config.h"
X#include "misc.h"
X
Xvoid
Xchg_dir()
X{
X	extern int fd;
X	WINDOW *ch_win, *newwin();
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, VERT, HORZ);
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	while ((ans = get_str(ch_win, 60, "", " 	")) != NULL) {
X					/* a CR means no change */
X		if (*ans == NULL)
X			break;
X					/* expand the input */
X		dir = expand(ans);
X					/* if you have search permission */
X		if (!access(dir, 1)) {
X			if (!chdir(dir)) {
X				free_ptr(dir);
X				break;
X			}
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					/* clean up 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	return;
X}
SHAR_EOF
if test 1305 -ne "`wc -c < 'chg_dir.c'`"
then
	echo shar: "error transmitting 'chg_dir.c'" '(should have been 1305 characters)'
fi
fi
echo shar: "extracting 'curses.c'" '(8404 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(3) routines.
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include <signal.h>
X#include "config.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 == BS) {
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, (chtype) ' ');
X			wmove(win, y, x);
X			wrefresh(win);
X			continue;
X		}
X					/* an <ESC> anywhere in the string */
X		if (ans == ESC)
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, (chtype) 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 == BS) {
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, (chtype) ' ');
X			wmove(win, y, x);
X			wrefresh(win);
X			continue;
X		}
X					/* an <ESC> anywhere in the string */
X		if (ans == ESC)
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, (chtype) 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 config.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;
Xchtype 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;
Xchtype 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, (chtype) 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, (chtype) 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;
Xchtype attr;
Xint 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;
Xchtype 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 = -1;
X	while (ret_code == -1) {
X		save = wgetch(win);
X		switch (save) {
X			case 'y':
X			case 'Y':
X				waddstr(win, "Yes");
X				ret_code = 1;
X				break;
X			case 'n':
X			case 'N':
X			case ESC:
X				waddstr(win, "No");
X				ret_code = 0;
X				break;
X			default:
X				beep();
X
X		}
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, (chtype) ACS_VLINE);
X		wmove(win, y, x);
X	}
X	return(0);
X}
X
X/*
X * Routine to make a horizontal line.  Does NOT do a wrefresh().
X */
X
Xint
Xhorizontal(win, x, y, len)
XWINDOW *win;
Xint x, y, len;
X{
X	wmove(win, x, y);
X
X	while (len--)
X		waddch(win, ACS_HLINE);
X
X	return(0);
X}
X
X/*
X * Wait for a key or time out.  Returns a -1 on timeout.  This is similar
X * to the half-delay mode in the newer versions of curses(3).
X */
X
Xstatic int wk_flag;
X
Xint
Xwait_key(win, sec)
XWINDOW *win;
Xunsigned int sec;
X{
X	int key, wk_force();
X	unsigned int alarm();
X#ifdef WGETCH_BROKE
X	char c;
X#endif /* WGETCH_BROKE */
X
X	signal(SIGALRM, wk_force);
X	wk_flag = 0;
X
X	alarm(sec);
X#ifdef WGETCH_BROKE
X	read(0, &c, 1);
X	key = c;
X#else /* WGETCH_BROKE */
X	key = wgetch(win);
X#endif /* WGETCH_BROKE */
X	if (wk_flag)
X		return(-1);
X	alarm(0);
X	return(key);
X}
X/*ARGSUSED*/
Xstatic int
Xwk_force(dummy)
Xint dummy;
X{
X	wk_flag = 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(BEL, 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	return(putchar(c));
X}
Xint
Xfixterm()
X{
X	int myputchar();
X	extern char *TI, *VS;
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 8404 -ne "`wc -c < 'curses.c'`"
then
	echo shar: "error transmitting 'curses.c'" '(should have been 8404 characters)'
fi
fi
echo shar: "extracting 'd_delete.c'" '(2009 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 "config.h"
X#include "dial_dir.h"
X#include "misc.h"
X#include "param.h"
X
Xint
Xdelete()
X{
X	extern char *null_ptr;
X	WINDOW *d_win, *newwin();
X	int i, first, last;
X	void free_ptr();
X
X	d_win = newwin(6, 32, 10, 15);
X
X	mvwaddstr(d_win, 2, 2, "Delete entry:     thru:");
X	box(d_win, VERT, HORZ);
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 2009 -ne "`wc -c < 'd_delete.c'`"
then
	echo shar: "error transmitting 'd_delete.c'" '(should have been 2009 characters)'
fi
fi
echo shar: "extracting 'd_lib.c'" '(6787 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
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 * regardless 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(extra)
Xchar *extra;
X{
X	extern char *null_ptr;
X	FILE *fp, *my_fopen();
X	int i, j, oops;
X	char *strdup(), buf[80], *temp_token, *str, *str_tok(), token[20];
X	char message[80], *sep, *findfile();
X	static struct DIAL_DIR d;
X	void error_win();
X
X	if ((d.d_path = findfile(extra, "pcomm.dial_dir")) == NULL)
X		error_win(1, "Support file 'pcomm.dial_dir' is missing", "or no read permission");
X
X	if (!(fp = my_fopen(d.d_path, "r"))) {
X		sprintf(buf, "'%s' for read", d.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, "Dialing directory file '%s'", d.d_path);
X		error_win(1, buf, message);
X	}
X	d.d_entries = i;
X					/* if empty database */
X	if (!i) {
X		sprintf(buf, "Dialing directory file '%s'", d.d_path);
X		error_win(0, buf, "has no data");
X	}
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 start up 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
Xup_dir(entry)
Xint entry;
X{
X	FILE *fp_in, *fp_out, *my_fopen();
X	int i;
X	char *temp[NUM_DIR+1], buf[80], *strdup();
X	void error_win(), free_ptr();
X
X					/* open for read */
X	if (!(fp_in = my_fopen(dir->d_path, "r"))) {
X		sprintf(buf, "'%s' for read", dir->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 write */
X	if (!(fp_out = my_fopen(dir->d_path, "w"))) {
X		for (i=1; i<=dir->d_entries; i++)
X			free_ptr(temp[i]);
X		sprintf(buf, "'%s'", dir->d_path);
X		error_win(0, "No write permission on dialing 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, *my_fopen();
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 = my_fopen(dir->d_path, "r"))) {
X		sprintf(buf, "'%s' for read", dir->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 = my_fopen(dir->d_path, "w"))) {
X		for (i=1; i<=dir->d_entries; i++)
X			free_ptr(temp[i]);
X		sprintf(buf, "'%s'", dir->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 6787 -ne "`wc -c < 'd_lib.c'`"
then
	echo shar: "error transmitting 'd_lib.c'" '(should have been 6787 characters)'
fi
fi
echo shar: "extracting 'd_manual.c'" '(1920 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 "config.h"
X#include "misc.h"
X#include "dial_dir.h"
X
Xint
Xmanual()
X{
X	extern int xmc;
X	extern char *null_ptr;
X	WINDOW *m_win, *newwin();
X	char *number, *strdup(), *get_str(), ld_code, *strchr();
X	void fix_xmc(), free_ptr();
X
X	m_win = newwin(5, 50, 0, 20);
X
X	box(m_win, VERT, HORZ);
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) {
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					/* if space, change to null */
X	if (!strcmp(number, " "))
X		dir->number[0] = null_ptr;
X	else
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
Xstatic void
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 1920 -ne "`wc -c < 'd_manual.c'`"
then
	echo shar: "error transmitting 'd_manual.c'" '(should have been 1920 characters)'
fi
fi
echo shar: "extracting 'd_menu.c'" '(6921 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 "config.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 non-zero return
X * code means we're ready to dial.
X */
X
Xint
Xdial_menu()
X{
X	extern int xmc;
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 dir_scroll(), active_ld(), disp_ld(), print_dir(), st_line();
X
X	touchwin(stdscr);
X	refresh();
X	st_line("");
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	horizontal(dm_win, 2, 0, 78);
X	mvwattrstr(dm_win, 3, 0, A_STANDOUT, "           Name                   Number        Baud P D S Dpx  Index/TTY    ");
X					/* show the first 10 entries */
X	dir_scroll(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, 34, 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, 34, 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>/<down>");
X	waddstr(dm_win, " Page");
X	mvwattrch(dm_win, 17, 34, 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, VERT, HORZ);
X	y = 15;
X	x = 8;
X	wmove(dm_win, 15, 8);
X	wrefresh(dm_win);
X#ifndef OLDCURSES
X	keypad(dm_win, TRUE);
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, (chtype) ans);
X			wrefresh(dm_win);
X			count++;
X			continue;
X		}
X		switch (ans) {
X			case BS:	/* 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, (chtype) ' ');
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				dir_scroll(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				dir_scroll(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					dir_scroll(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++;
X					break;
X				}
X				break;
X			case 'r':
X			case 'R':	/* revise */
X				if (revise()) {
X					active_ld(dm_win);
X					dir_scroll(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++;
X				break;
X			case 'd':
X			case 'D':	/* delete a range of entries */
X				if (delete())
X					dir_scroll(dm_win, current);
X				touchwin(dm_win);
X				break;
X			case 'm':
X			case 'M':	/* manual dial */
X				if (manual()) {
X					ret_code++;
X					break;
X				}
X				touchwin(dm_win);
X				needs_repair++;
X				break;
X			case 'l':
X			case 'L':	/* print the entries */
X				print_dir();
X				touchwin(dm_win);
X				needs_repair++;
X				break;
X			case '+':	/* LD codes */
X			case '-':
X			case '@':
X			case '#':
X				waddch(dm_win, (chtype) ans);
X				wrefresh(dm_win);
X				ld_code = ans;
X				continue;
X			case ESC:	/* <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, VERT, HORZ);
X		}
X		wmove(dm_win, y, x);
X		wrefresh(dm_win);
X	} while (ans != ESC);
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
Xstatic void
Xdir_scroll(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, VERT, HORZ);
X	return;
X}
X
X/*
X * Display the Long Distance codes.  Press any key to continue.
X */
X
Xstatic void
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	horizontal(ld_win, 2, 0, 30);
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, VERT, HORZ);
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
Xstatic void
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 6921 -ne "`wc -c < 'd_menu.c'`"
then
	echo shar: "error transmitting 'd_menu.c'" '(should have been 6921 characters)'
fi
fi
echo shar: "extracting 'd_print.c'" '(3496 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#include <stdio.h>
X#include <curses.h>
X#include "config.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, *e_get_str(), 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, VERT, HORZ);
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 = e_get_str(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 program", buf);
X			werase(p_win);
X			wrefresh(p_win);
X			delwin(p_win);
X			return;
X		}
X		is_printer++;
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, VERT, HORZ);
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		fp = fopen(file, "w");
X	}
X
X	werase(p_win);
X	mvwaddstr(p_win, 2, 13, "Printing Pcomm directory");
X	box(p_win, VERT, HORZ);
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
Xstatic char *
Xe_get_str(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 == BS) {
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, (chtype) ' ');
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 == ESC)
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++;
X		}
X
X		buf[count] = ans;
X		waddch(win, (chtype) ans);
X		wrefresh(win);
X		count++;
X	}
X	buf[count] = NULL;
X	return(buf);
X}
SHAR_EOF
if test 3496 -ne "`wc -c < 'd_print.c'`"
then
	echo shar: "error transmitting 'd_print.c'" '(should have been 3496 characters)'
fi
fi
echo shar: "extracting 'd_prompt.c'" '(6003 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 "config.h"
X#include "dial_dir.h"
X#include "misc.h"
X
Xint
Xprompt_lib(win, i)
XWINDOW *win;
Xint i;
X{
X	extern int xmc;
X	extern char *null_ptr;
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[40], number[40], index[40];
X	char parity, duplex, *strdup(), *strcpy(), buf[40];
X	void free_ptr();
X					/* make copies */
X	strcpy(name, dir->name[i]);
X	strcpy(number, 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	strcpy(index, 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, VERT, HORZ);
X
X					/* prompt for name */
X	mvwaddstr(win, 4, 4, "Name: ");
X	wrefresh(win);
X
X	if ((ans = get_str(win, 20, "", ";")) == NULL)
X		return(0);
X	if (*ans != NULL) {
X		strcpy(name, 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)
X		return(0);
X	if (*ans != NULL) {
X		strcpy(number, 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 == ESC)
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 == ESC)
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 == ESC)
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 == ESC)
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 == ESC)
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)
X		return(0);
X	if (*ans != NULL) {
X		strcpy(index, ans);
X		mvwaddstr(win, 2, 62, "              ");
X		wrefresh(win);
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	if (!strcmp(name, " "))
X		dir->name[i] = null_ptr;
X	else
X		dir->name[i] = strdup(name);
X	if (!strcmp(number, " "))
X		dir->number[i] = null_ptr;
X	else
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	if (!strcmp(index, " "))
X		dir->index[i] = null_ptr;
X	else
X		dir->index[i] = strdup(index);
X
X	return(1);
X}
SHAR_EOF
if test 6003 -ne "`wc -c < 'd_prompt.c'`"
then
	echo shar: "error transmitting 'd_prompt.c'" '(should have been 6003 characters)'
fi
fi
echo shar: "extracting 'd_revise.c'" '(4006 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 "config.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, *ld_prompt(), *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, VERT, HORZ);
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)) != ESC) {
X		if (ans >= '0' && ans <= '9') {
X			if (count == 3) {
X				beep();
X				continue;
X			}
X			buf[count] = ans;
X			waddch(r_win, (chtype) 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 == BS) {
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, (chtype) ' ');
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 = ld_prompt(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 = ld_prompt(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 = ld_prompt(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 = ld_prompt(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 (up_dir(num)) {
X			touchwin(r_win);
X			wrefresh(r_win);
X		}
X	}
X	if (save && param_flag) {
X		if (up_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
Xstatic char *
Xld_prompt(win, current_ld, name)
XWINDOW *win;
Xchar *current_ld, name;
X{
X	extern char *null_ptr;
X	char *ans, *get_str();
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, VERT, HORZ);
X	wrefresh(win);
X
X	if ((ans = get_str(win, 20, "", "")) == 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 4006 -ne "`wc -c < 'd_revise.c'`"
then
	echo shar: "error transmitting 'd_revise.c'" '(should have been 4006 characters)'
fi
fi
echo shar: "extracting 'data_log.c'" '(1801 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.  Also turns on the data logging.  A return code of 1 means we
X * need to restart the input routine.
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include "config.h"
X#include "misc.h"
X#include "param.h"
X#include "status.h"
X
Xint
Xdata_logging()
X{
X	extern int fd;
X	extern char *null_ptr;
X	int ret_code;
X	WINDOW *dl_win, *newwin();
X	char *ans, *path, *expand(), *get_str(), *strdup(), *strcpy();
X	void input_off(), free_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, VERT, HORZ);
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) {
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					/* clean up 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		strcpy(status->log_path, path);
X		status->log = 1;
X		/*
X		 * Without shared memory, killing and restarting the input
X		 * routine is the only way to change the name of the file
X		 * that the input routines uses.
X		 */
X#ifdef SHAREDMEM
X		ret_code = 0;
X#else /* SHAREDMEM */
X		input_off();
X#endif /* SHAREDMEM */
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 1801 -ne "`wc -c < 'data_log.c'`"
then
	echo shar: "error transmitting 'data_log.c'" '(should have been 1801 characters)'
fi
fi
echo shar: "extracting 'di_delay.c'" '(1978 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 "config.h"
X#include "misc.h"
X#include "param.h"
X
Xvoid
Xdelay_times()
X{
X	WINDOW *dt_win, *newwin();
X	int cdelay, rdelay;
X
X	dt_win = newwin(9, 45, 7, 15);
X
X	mvwprintw(dt_win, 2, 4, "Current connect delay time: %d", param->c_delay);
X	mvwprintw(dt_win, 3, 4, "Current redial delay time: %d", param->r_delay);
X	mvwaddstr(dt_win, 5, 4, "New connect delay: ");
X	mvwaddstr(dt_win, 6, 4, "New redial delay: ");
X	box(dt_win, VERT, HORZ);
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->c_delay;
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 rdelay number */
X	wmove(dt_win, 6, 20);
X	wrefresh(dt_win);
X	if ((rdelay = get_num(dt_win, 3)) == -1) {
X		delwin(dt_win);
X		return;
X	}
X					/* give 'em the current settings */
X	if (!rdelay) {
X		rdelay = param->r_delay;
X		wprintw(dt_win, "%-3d", rdelay);
X	}
X	else {
X					/* some reasonable limit */
X		if (rdelay > MAX_PAUSE || rdelay < MIN_PAUSE) {
X			beep();
X			if (rdelay > MAX_PAUSE)
X				rdelay = MAX_PAUSE;
X			else
X				rdelay = MIN_PAUSE;
X			mvwprintw(dt_win, 6, 20, "%-3d", rdelay);
X		}
X	}
X					/* set 'em */
X	param->c_delay = cdelay;
X	param->r_delay = rdelay;
X					/* save 'em to disk? */
X	if (yes_prompt(dt_win, 7, 12, A_BOLD, "Save to disk")) {
X		if (up_param()) {
X			touchwin(dt_win);
X			wrefresh(dt_win);
X		}
X	}
X
X	delwin(dt_win);
X	return;
X}
SHAR_EOF
if test 1978 -ne "`wc -c < 'di_delay.c'`"
then
	echo shar: "error transmitting 'di_delay.c'" '(should have been 1978 characters)'
fi
fi
exit 0
#	End of shell archive

egray@killer.DALLAS.TX.US (Emmet Gray) (09/05/88)

This is part 4 (of 8) to the Pcomm v1.1 release package.

Emmet P. Gray				US Army, HQ III Corps & Fort Hood
..!uunet!uiucuxc!fthood!egray		Attn: AFZF-DE-ENV
					DEH, 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:
#	di_win.c
#	dial.c
#	expand.c
#	getcwd.c
#	getopt.c
#	help.c
#	info.c
#	init.c
#	input.c
#	line_set.c
#	list_dir.c
#	ls_menu.c
# This archive created: Sat Sep  3 15:34:58 1988
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'di_win.c'" '(9165 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 "config.h"
X#include "dial_dir.h"
X#include "misc.h"
X#include "modem.h"
X#include "param.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 routine.
X */
X
Xint
Xdial_win()
X{
X	extern int rc_index, fd;
X	WINDOW *di_win, *newwin();
X	int i, j, key, want_out, pass, tic, baud;
X	long now, time();
X	char *tbuf, *ctime(), *str, cr=13, *read_codes();
X	void disp_queue(), send_str(), dial_it(), delay_times(), input_off();
X	void error_win(), line_set(), hang_up(), zap_vs(), log_calls();
X	void st_line();
X	unsigned int sleep();
X					/* are we already talking? */
X	input_off();
X	hang_up(1);
X
X	touchwin(stdscr);
X	refresh();
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 On Board Modem directly",
X			 "You must use the automatic dialing feature");
X			return(0);
X		}
X
X		zap_vs();
X		touchwin(stdscr);
X		clear();
X		printw("Connected to /dev/%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	horizontal(di_win, 2, 0, 70);
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, 17, "Redial delay time:");
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, 22, "<DEL>: Remove from queue");
X	mvwaddstr(di_win, 14, 49, "E: Change delays");
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->c_delay);
X	mvwprintw(di_win, 10, 36, "%-4d", param->r_delay);
X
X	box(di_win, VERT, HORZ);
X	mvwaddstr(di_win, 16, 24, " Press <ESC> to abort ");
X
X	pass = 0;
X	i = 0;
X	want_out = 0;
X	while (!want_out && pass <= MAX_PASS) {
X		key = -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			want_out++;
X			break;
X		}
X					/* get a port */
X		if (get_port()) {
X			want_out++;
X			break;
X		}
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(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->c_delay) {
X			if ((str = read_codes()) == NULL) {
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 (dir->baud[dir->d_cur] != baud) {
X					if (can_sync(baud)) {
X						dir->baud[dir->d_cur] = baud;
X						line_set();
X					}
X				}
X
X				zap_vs();
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->c_delay)
X				break;
X					/* ok... try the keyboard */
X			if ((key = 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(fd, &cr, 1);
X			sleep(1);
X		}
X					/* if we get here, no key was pressed */
X		if (key == -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->r_delay) {
X				if ((key = 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		mvwaddstr(di_win, 6, 36, "0   ");
X					/* Process the keystroke */
X		switch (key) {
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 DEL:	/* <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->c_delay);
X				mvwprintw(di_win, 10, 36, "%-4d", param->r_delay);
X				break;
X			case ESC:	/* <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", "");
X	return(0);
X}
X
X/*
X * Display what info we know at this time.
X */
X
Xstatic void
Xdisp_queue(win, entry, pass)
XWINDOW *win;
Xint entry, pass;
X{
X	long now, time();
X	char *tbuf, *ctime();
X	void st_line();
X					/* redo the status line */
X	st_line("");
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 * Determine if the modem can detect the synchronization of the connected
X * baud rate.  We check the modem database and see if the connect string
X * is unique.  A return code of 1 means the modem can sync.
X */
X
Xstatic int
Xcan_sync(baud)
Xint baud;
X{
X	int i;
X	char *str;
X					/* feature disabled? */
X	if (modem->auto_baud[modem->m_cur] != 'Y')
X		return(0);
X					/* re-construct the string */
X	switch (baud) {
X		case 300:
X			str = modem->con_3[modem->m_cur];
X			break;
X		case 1200:
X			str = modem->con_12[modem->m_cur];
X			break;
X		case 2400:
X			str = modem->con_24[modem->m_cur];
X			break;
X		case 4800:
X			str = modem->con_48[modem->m_cur];
X			break;
X		case 9600:
X			str = modem->con_96[modem->m_cur];
X			break;
X		case 19200:
X			str = modem->con_192[modem->m_cur];
X			break;
X		default:
X			return(0);
X	}
X
X	if (*str == NULL)
X		return(0);
X					/* test "str" against all others */
X	i = 0;
X	if (!strcmp(str, modem->con_3[modem->m_cur]))
X		i++;
X	if (!strcmp(str, modem->con_12[modem->m_cur]))
X		i++;
X	if (!strcmp(str, modem->con_24[modem->m_cur]))
X		i++;
X	if (!strcmp(str, modem->con_48[modem->m_cur]))
X		i++;
X	if (!strcmp(str, modem->con_96[modem->m_cur]))
X		i++;
X	if (!strcmp(str, modem->con_192[modem->m_cur]))
X		i++;
X					/* should match only itself */
X	if (i == 1)
X		return(1);
X	return(0);
X}
SHAR_EOF
if test 9165 -ne "`wc -c < 'di_win.c'`"
then
	echo shar: "error transmitting 'di_win.c'" '(should have been 9165 characters)'
fi
fi
echo shar: "extracting 'dial.c'" '(7336 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#include "config.h"
X#ifdef UNIXPC
X#include <sys/phone.h>
X#endif /* UNIXPC */
X#include "dial_dir.h"
X#include "misc.h"
X#include "modem.h"
X#include "param.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	extern int fd;
X	int i, skip;
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.  To prevent
X	 * this action, prepend a "\" to the character.
X	 */
X	i = 0;
X	skip = 0;
X	n = dir->number[dir->q_num[num]];
X	while (*n) {
X		if (*n == '\\' && !skip) {
X			skip++;
X			n++;
X			continue;
X		}
X		if (!strchr("-() ", *n) || skip)
X			number[i++] = *n;
X		n++;
X		skip = 0;
X	}
X	number[i] = NULL;
X					/* add it to the string */
X	strcat(s, number);
X	strcat(s, modem->suffix[modem->m_cur]);
X#ifdef DEBUG
X	fprintf(stderr, "raw dial string: '%s'\n", s);
X#endif /* DEBUG */
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(fd, PIOCSETP, &pbuf);
X		sleep(1);
X					/* connect the dialer */
X		ioctl(fd, PIOCRECONN);
X		sleep(1);
X					/* dial each digit */
X		n = s;
X		while (*n) {
X					/* switch tone/pulse dialing? */
X			switch (*n) {
X				case '^':
X					pbuf.c_lineparam = DATA|PULSE;
X					ioctl(fd, PIOCSETP, &pbuf);
X					break;
X				case '%':
X					pbuf.c_lineparam = DATA|DTMF;
X					ioctl(fd, PIOCSETP, &pbuf);
X					break;
X				default:
X					ioctl(fd, PIOCDIAL, n);
X					break;
X			}
X			n++;
X		}
X		return;
X	}
X#endif /* UNIXPC */
X
X	send_str(s);
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	extern int fd;
X	int skip;
X	unsigned int sleep();
X					/* empty string? */
X	if (s == NULL || *s == NULL)
X		return;
X
X	ioctl(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					/* send the literal character */
X		if (skip) {
X			skip = 0;
X			write(fd, s, 1);
X			ioctl(fd, TCSBRK, 1);
X#ifdef DEBUG
X			fprintf(stderr, "send_str: '%c', %02x, %03o, %d\n", *s, *s, *s, *s);
X#endif /* DEBUG */
X			s++;
X			continue;
X		}
X					/* turn off the special meaning */
X		if (*s == '\\') {
X			skip++;
X			s++;
X			continue;
X		}
X					/* pause synonym */
X		if (*s == param->pause_char) {
X			sleep(1);
X			s++;
X			continue;
X		}
X					/* carriage return synonym */
X		if (*s == param->cr_char)
X			*s = '\r';
X					/* 2 character control sequence */
X		if (*s == param->ctrl_char) {
X			s++;
X					/* premature EOF? */
X			if (*s == NULL)
X				break;
X					/* upper and lower case */
X			if (*s > '_')
X				*s -= 96;
X			else
X				*s -= 64;
X		}
X					/* escape synonym */
X		if (*s == param->esc_char)
X			*s = ESC;
X					/* modem break synonym */
X		if (*s == param->brk_char) {
X			ioctl(fd, TCSBRK, 0);
X			sleep(1);
X			s++;
X			continue;
X		}
X
X		write(fd, s, 1);
X#ifdef DEBUG
X		fprintf(stderr, "send_str: '%c', %02x, %03o, %d\n", *s, *s, *s, *s);
X#endif /* DEBUG */
X		/*
X		 * Because the pause char makes the timing critical, we
X		 * wait until the buffer is clear before we continue.
X		 */
X		ioctl(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	extern int fd;
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(fd, PIOCGETP, &pbuf);
X
X		/*
X		 * The OBM doesn't use a return message to announce the
X		 * connection to a remote, so we fake one.  The 1200
X		 * is quite arbitrary... it is not an indicator of the
X		 * connected baud rate.
X		 */
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 ((int) (c = getc_line(1)) <= 0)
X			return(NULL);
X#ifdef DEBUG
X		fprintf(stderr, "read_codes: '%c', %02x, %03o, %d\n", c, c, c, c);
X#endif /* DEBUG */
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
Xstatic int
Xmatch(s1, s2)
Xchar *s1, *s2;
X{
X	register int i;
X	int skip, diff;
X	char 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					/* literal character */
X		if (skip) {
X			skip = 0;
X			new[i++] = *s2;
X			s2++;
X			continue;
X		}
X					/* turn off the special meaning */
X		if (*s2 == '\\') {
X			skip++;
X			s2++;
X			continue;
X		}
X					/* carriage return synonym */
X		if (*s2 == param->cr_char)
X			*s2 = '\r';
X
X					/* 2 character control sequence */
X		if (*s2 == param->ctrl_char) {
X			s2++;
X			if (*s2 == NULL)
X				break;
X			if (*s2 > '_')
X				*s2 -= 96;
X			else
X				*s2 -= 64;
X		}
X					/* escape synonym */
X		if (*s2 == param->esc_char)
X			*s2 = ESC;
X
X		new[i++] = *s2;
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 7336 -ne "`wc -c < 'dial.c'`"
then
	echo shar: "error transmitting 'dial.c'" '(should have been 7336 characters)'
fi
fi
echo shar: "extracting 'expand.c'" '(2683 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#include <fcntl.h>
X#include "config.h"
X
Xchar *
Xexpand(input)
Xchar *input;
X{
X	extern char *null_ptr;
X	FILE *pfp, *n_popen();
X	int last;
X	char *ans, buf[1024], *strpbrk(), *strdup();
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 = n_popen(buf, "r");
X	fgets(buf, 1024, pfp);
X	n_pclose(pfp);
X
X	if (!strlen(buf))
X		return(ans);
X	/*
X	 * A horrible kludge...  if the last character is not a line
X	 * feed, then the csh has returned an error message.  Otherwise
X	 * zap the line feed.
X	 */
X	last = strlen(buf) -1;
X	if (buf[last] != '\n')
X		return(ans);
X	else
X		buf[last] = 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 *
Xn_popen(cmd, mode)
Xchar *cmd, *mode;
X{
X	int myside, hisside, ppid, 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 || *shellpath == NULL)
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 (!(ppid = fork())) {
X		int stdio;
X					/* no error messages please */
X		close(2);
X		open("/dev/null", O_WRONLY);
X#ifdef SETUGID
X		setgid(getgid());
X		setuid(getuid());
X#endif /* SETUGID */
X		stdio = tst(0, 1);
X		close(myside);
X		close(stdio);
X		fcntl(hisside, F_DUPFD, stdio);
X		close(hisside);
X		execl(shellpath, shell, flags, cmd, (char *) 0);
X		_exit(1);
X	}
X	if (ppid == -1) {
X		close(myside);
X		close(hisside);
X		return NULL;
X	}
X
X	popen_pid[myside] = ppid;
X
X	close(hisside);
X	return(fdopen(myside, mode));
X}
X
Xn_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 2683 -ne "`wc -c < 'expand.c'`"
then
	echo shar: "error transmitting 'expand.c'" '(should have been 2683 characters)'
fi
fi
echo shar: "extracting 'getcwd.c'" '(387 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 new line */
X	buf[strlen(buf)-1] = NULL;
X	return(buf);
X}
SHAR_EOF
if test 387 -ne "`wc -c < 'getcwd.c'`"
then
	echo shar: "error transmitting 'getcwd.c'" '(should have been 387 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'" '(1802 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 "config.h"
X#include "misc.h"
X
Xvoid
Xhelp_screen(hot)
Xchar *hot;
X{
X	extern int fd;
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	horizontal(h_win, 2, 0, 80);
X	mvwattrstr(h_win, 4, 0, A_BOLD, "       Major Functions          Utility Functions         File Functions\n\n");
X	mvwprintw(h_win,  6,  2, "Dialing Directory.%4.4s-D  Program Info ....%4.4s-I  Send Files ....%4.4s-<up>", hot, hot, hot);
X	mvwprintw(h_win,  7,  2, "Auto Redial ......%4.4s-R  Setup Screen ....%4.4s-S  Receive Files .%4.4s-<down>", hot, hot, hot);
X	mvwprintw(h_win,  8,  2, "Keyboard Macros ..%4.4s-M  Change Directory.%4.4s-B  Pass Thru Mode.%4.4s-T", hot, hot, hot);
X	mvwprintw(h_win,  9,  2, "Line Settings ....%4.4s-P  Clear Screen ....%4.4s-C  Directory .....%4.4s-F", hot, hot, hot);
X	mvwprintw(h_win, 10,  2, "Exit Pcomm .......%4.4s-X  Toggle Duplex ...%4.4s-E  Screen Dump ...%4.4s-G", hot, hot, hot);
X	mvwprintw(h_win, 11,  2, "Unix Gateway .....%4.4s-4  Hang Up Phone ...%4.4s-H  Start Data Log.%4.4s-1", hot, hot, hot);
X	mvwprintw(h_win, 12, 28, "Printer On/Off ..%4.4s-L  Toggle Log ....%4.4s-2", hot, hot);
X	mvwprintw(h_win, 13, 28, "Toggle CR-CR/LF .%4.4s-3", hot);
X	mvwprintw(h_win, 14, 28, "Break Key .......%4.4s-7", hot);
X
X	box(h_win, VERT, HORZ);
X	mvwaddstr(h_win, 16, 26, " 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 1802 -ne "`wc -c < 'help.c'`"
then
	echo shar: "error transmitting 'help.c'" '(should have been 1802 characters)'
fi
fi
echo shar: "extracting 'info.c'" '(1532 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#define VERSION "1.1"
X#define DATE	"21 Aug 88"
X
X#include <stdio.h>
X#include <curses.h>
X
Xvoid
Xinfo(delay)
Xint delay;
X{
X	extern int fd;
X	WINDOW *w_win, *newwin();
X	char buf[80];
X					/* display the welcome screen */
X	w_win = newwin(23, 80, 0, 0);
X	mvwaddstr(w_win, 3, 18, "PPPPPP    CCCC    OOOO    MM   MM   MM   MM");
X	mvwaddstr(w_win, 4, 18, "P    P   C       O    O   M M M M   M M M M");
X	mvwaddstr(w_win, 5, 18, "PPPPPP   C       O    O   M  M  M   M  M  M");
X	mvwaddstr(w_win, 6, 18, "P        C       O    O   M     M   M     M");
X	mvwaddstr(w_win, 7, 18, "P         CCCC    OOOO    M     M   M     M");
X
X	sprintf(buf, ">>> Pcomm Version %s <<<", VERSION);
X	mvwaddstr(w_win, 10, (80-strlen(buf))/2, buf);
X	sprintf(buf, "Release date: %s", DATE);
X	mvwaddstr(w_win, 11, (80-strlen(buf))/2, buf);
X
X	mvwaddstr(w_win, 13, 8, "Pcomm is a public domain telecommunication program for Unix that");
X	mvwaddstr(w_win, 14, 8, "is designed to operate similar to the MSDOS program, ProComm.");
X	mvwaddstr(w_win, 15, 8, "ProComm (TM) is copyrighted by Datastorm Technologies, Inc.");
X	mvwaddstr(w_win, 19, 45, "Emmet P. Gray");
X	mvwaddstr(w_win, 20, 45, "...!uunet!uiucuxc!fthood!egray");
X	wmove(w_win, 22, 79);
X	wrefresh(w_win);
X					/* Delay so you can read the herald */
X	if (delay)
X		wait_key(w_win, 5);
X	else
X		wgetch(w_win);
X
X	if (fd == -1) {
X		werase(w_win);
X		wrefresh(w_win);
X	}
X	delwin(w_win);
X	return;
X}
SHAR_EOF
if test 1532 -ne "`wc -c < 'info.c'`"
then
	echo shar: "error transmitting 'info.c'" '(should have been 1532 characters)'
fi
fi
echo shar: "extracting 'init.c'" '(2944 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 support files.  Returns a
X * pointer to the STATUS structure.  All errors are fatal.
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include "config.h"
X#ifdef SHAREDMEM
X#include <sys/types.h>
X#include <sys/ipc.h>
X#include <sys/shm.h>
X#endif /* SHAREDMEM */
X#include "misc.h"
X#include "status.h"
X
Xstruct STATUS *
Xinit(short_cut)
Xchar *short_cut;
X{
X	char *mktemp(), *strcpy();
X	struct STATUS *s_ptr;
X	void info();
X#ifdef SHAREDMEM
X	int i, j, mode;
X	extern int shm_id;
X	char *shmat();
X	void exit();
X
X	/*
X	 * Since the "pcomm_input" program does not run set-user/group-id
X	 * the mode must be set so the effective ID can read/write to the
X	 * shared memory segment.  Kinda strange... real ID's aren't used.
X	 */
X#ifdef SETUGID
X	mode = 0666;
X#else /* SETUGID */
X	mode = 0600;
X#endif /* SETUGID */
X					/* create a shared memory segment */
X	shm_id = shmget(IPC_PRIVATE, sizeof (struct STATUS),  mode|IPC_CREAT|IPC_EXCL|IPC_NOWAIT);
X	if (shm_id < 0) {
X		endwin();
X		perror("shmget");
X		exit(1);
X	}
X	s_ptr = (struct STATUS *) shmat(shm_id, (char *) 0, 0);
X	if ((int) s_ptr == -1) {
X		endwin();
X		perror("shmat");
X		exit(1);
X	}
X#else /* SHAREDMEM */
X	static struct STATUS s;
X	s_ptr = &s;
X#endif /* SHAREDMEM */
X					/* some defaults */
X	s_ptr->fd = -1;
X	s_ptr->add_lf = 0;
X	s_ptr->log = 0;
X	s_ptr->print = 0;
X	strcpy(s_ptr->log_path, "NOT_DEFINED");
X#ifdef SHAREDMEM
X	s_ptr->clr = 0;
X	s_ptr->row = 0;
X	s_ptr->col = 0;
X	for (i=0; i<LINES; i++) {
X		for (j=0; j<COLS; j++)
X			s_ptr->vs[i][j] = ' ';
X		s_ptr->vs[i][COLS] = NULL;
X	}
X#else /* SHAREDMEM */
X	strcpy(s_ptr->vs_path, mktemp("/tmp/pcommXXXXXX"));
X#endif /* SHAREDMEM */
X					/* display herald if no short-cut */
X	if (short_cut == NULL)
X		info(1);
X
X	erase();
X	refresh();
X	return(s_ptr);
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 working
X * directory, and lastly, the default directory.
X */
X
Xchar *
Xfindfile(extra, name)
Xchar *extra, *name;
X{
X	int i;
X	char *pcomm, *getenv(), *path, pbuf[200], *getcwd(), *strdup();
X	char temp[200];
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:		/* extra directory from command line */
X				path = extra;
X				break;
X			case 1:		/* PCOMM environmental variable */
X				path = pcomm;
X				break;
X			case 2:		/* current working directory */
X				path = getcwd(pbuf, 200);
X				break;
X			case 3:		/* Pcomm's default directory */
X				path = DEFAULT_DIR;
X				break;
X		}
X		if (path == NULL)
X			continue;
X
X		sprintf(temp, "%s/%s", path, name);
X					/* read permission checked */
X		if (!access(temp, 4))
X			return(strdup(temp));
X	}
X	return(NULL);
X}
SHAR_EOF
if test 2944 -ne "`wc -c < 'init.c'`"
then
	echo shar: "error transmitting 'init.c'" '(should have been 2944 characters)'
fi
fi
echo shar: "extracting 'input.c'" '(10147 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.  This program runs as a child process to the
X * Pcomm program.
X */
X
X#define CLIST 64
X
X#include <stdio.h>
X#include <signal.h>
X#include <setjmp.h>
X#include "config.h"
X#ifdef SHAREDMEM
X#include <sys/types.h>
X#include <sys/ipc.h>
X#include <sys/shm.h>
X#endif /* SHAREDMEM */
X#define MAIN
X#include "misc.h"
X#include "status.h"
X#include "vcs.h"
X
Xjmp_buf i_jmp;
Xint vcs_param[NUM_VCS][5];		/* positional parameters */
Xint vcs_opt[NUM_VCS][10];		/* options unique to each vcs */
Xint vcs_codes[NUM_VCS][VCS_SIZE];	/* the vcs codes */
Xint vcs_leadin[NUM_VCS];		/* unique list of lead-in characters */
Xint num_leadin;				/* length of lead-in list */
Xint hold, max_row, max_col, skip_row;
XFILE *logfp, *lprfp;
Xstruct STATUS *status;
X
X#ifdef SHAREDMEM
X#define VROW	status->row
X#define VCOL	status->col
X#define VS	status->vs
X#else /* SHAREDMEM */
Xint VROW, VCOL;
Xchar VS[MAX_ROW][MAX_COL+2];
Xstruct STATUS s;
X#endif /* SHAREDMEM */
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 */
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X	FILE *popen();
X	int got_sig();
X	char c, *strcpy();
X	void _exit(), exit(), vcs_table();
X#ifdef SHAREDMEM
X	int shm_id;
X	char *shmat();
X#endif /* SHAREDMEM */
X					/* set the trap for the signals */
X	signal(SIGALRM, SIG_IGN);
X	signal(SIGHUP,  SIG_IGN);
X	signal(SIGQUIT, SIG_IGN);
X	signal(SIGUSR1, got_sig);
X	signal(SIGUSR2, got_sig);
X	signal(SIGINT,  got_sig);
X	signal(SIGTERM, got_sig);
X					/* unbuffered output */
X	setbuf(stdout, (char *) NULL);
X					/* for the curious... */
X	if (argc == 1) {
X		fprintf(stderr, "This is the input routine for the Pcomm program\n");
X		fprintf(stderr, "It is not designed to be run as a separate program\n");
X		exit(1);
X	}
X#ifdef SHAREDMEM
X	shm_id = atoi(argv[1]);
X	status = (struct STATUS *) shmat(shm_id, (char *) 0, 0);
X	if ((int) status == -1) {
X		perror("shmat");
X		_exit(1);
X	}
X#else /* SHAREDMEM */
X	status = &s;
X#endif /* SHAREDMEM */
X					/* load the VCS table */
X	vcs_table();
X	if (max_row > MAX_ROW)
X		max_row = MAX_ROW;
X	if (max_col > MAX_COL)
X		max_col = MAX_COL;
X					/* parse the command line */
X#ifndef SHAREDMEM
X	status->fd = atoi(argv[1]);
X	status->add_lf = atoi(argv[2]);
X	status->log = atoi(argv[3]);
X	status->print = atoi(argv[4]);
X	strcpy(status->log_path, argv[5]);
X	strcpy(status->vs_path, argv[6]);
X#endif /* SHAREDMEM */
X
X	skip_row = 0;
X#ifdef SHAREDMEM
X	if (status->clr)
X		skip_row = 1;
X#else /* SHAREDMEM */
X					/* read previous screen */
X	if (!access(status->vs_path, 0))
X		read_vs();
X	else
X		skip_row = 1;
X#endif /* SHAREDMEM */
X
X	hold = 0;
X					/* start up file pointers */
X	lprfp = (FILE *) NULL;
X	logfp = (FILE *) NULL;
X
X	switch (setjmp(i_jmp)) {
X		case 0:			/* no signal */
X			break;
X		case 1:			/* toggle the data logging */
X			status->log = status->log ? 0 : 1;
X			break;
X		case 2:			/* toggle the printer */
X			status->print = status->print ? 0 : 1;
X			break;
X		case 3:			/* suspend the input */
X			hold = hold ? 0 : 1;
X#ifndef SHAREDMEM
X			if (hold)
X				write_vs();
X#endif /* SHAREDMEM */
X			break;
X		case 4:			/* clean up and go home */
X			if (status->log)
X				fclose(logfp);
X			if (status->print) {
X				putc('\f', lprfp);
X				pclose(lprfp);
X			}
X#ifdef SHAREDMEM
X					/* detach shared memory */
X			shmdt((char *) status);
X#endif /* SHAREDMEM */
X			_exit(0);
X			break;
X	}
X					/* any signal will awaken pause() */
X	if (hold)
X		pause();
X					/* open or close the printer */
X	if (status->print && lprfp == NULL)
X		lprfp = popen(LPR, "w");
X
X	if (!status->print && lprfp != NULL) {
X		putc('\f', lprfp);
X		pclose(lprfp);
X		lprfp = (FILE *) NULL;
X	}
X					/* open or close the log file */
X	if (status->log && logfp == NULL) {
X		if (strcmp(status->log_path, "NOT_DEFINED")) {
X			if (!(logfp = fopen(status->log_path, "a")))
X				status->log = 0;
X		}
X		else
X			status->log = 0;
X	}
X	if (!status->log && logfp != NULL) {
X		fclose(logfp);
X		logfp = (FILE *) NULL;
X	}
X
X#ifdef SHAREDMEM
X	if (status->clr) {
X		status->clr = 0;
X		vs_clear();
X	}
X#else /* SHAREDMEM */
X					/* clear if vs_path doesn't exist */
X	if (access(status->vs_path, 0))
X		vs_clear();
X#endif /* SHAREDMEM */
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		VROW = 1;
X	}
X
X	while (1) {
X		if ((int) (c = readbyte()) <= 0)
X			continue;
X					/* send to logfile */
X		if (status->log) {
X			if (c == '\r' && status->add_lf)
X				putc('\n', logfp);
X					/* no carriage returns in logfile */
X			if (c != '\r')
X				putc(c, logfp);
X		}
X					/* send to printer too? */
X		if (status->print)
X			putc(c, lprfp);
X
X					/* put a char in virtual screen */
X		vs_putchar(c);
X
X		putchar(c);
X					/* add LF to CR? */
X		if (c == '\r' && status->add_lf)
X			putchar('\n');
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	switch (sig) {
X		case SIGUSR1:
X			signal(SIGUSR1, got_sig);
X			longjmp(i_jmp, 1);
X		case SIGUSR2:
X			signal(SIGUSR2, got_sig);
X			longjmp(i_jmp, 2);
X		case SIGINT:
X			signal(SIGINT, got_sig);
X			longjmp(i_jmp, 3);
X		case SIGTERM:
X			signal(SIGTERM, got_sig);
X			longjmp(i_jmp, 4);
X	}
X}
X
X/*
X * Put a character in the virtual screen.  This routine saves incoming
X * characters in a two dimensional buffer designed to mimic the real
X * screen.
X */
X
Xint
Xvs_putchar(c)
Xchar c;
X{
X	register int j, i;
X	int tab_stop;
X
X	switch (vcs_filter(c)) {
X		case MAYBE:		/* wait and see... */
X			break;
X		case 256+HOME:		/* home virtual screen "cursor" */
X			VROW = 0;
X			VCOL = 0;
X			break;
X		case 256+CLR_EOL:	/* clear to end of line */
X			for (i=VCOL; i<max_col; i++)
X				VS[VROW][i] = ' ';
X			break;
X		case 256+CLR_EOS:	/* clear to end of screen */
X			for (j=VCOL; j<max_col; j++)
X				VS[VROW][j] = ' ';
X			for (i=VROW+1; i<max_row; i++) {
X				for (j=0; j<max_col; j++)
X					VS[i][j] = ' ';
X			}
X			break;
X		case 256+CLEAR:		/* clear all and home "cursor" */
X			for (i=0; i<max_row; i++) {
X				for (j=0; j<max_col; j++)
X					VS[i][j] = ' ';
X			}
X			VROW = 0;
X			VCOL = 0;
X			break;
X		case 256+MV_UP:		/* move "cursor" up */
X			VROW--;
X			if (VROW < 0)
X				VROW = 0;
X			break;
X		case 256+MV_DOWN:	/* move "cursor" down */
X			VROW++;
X			if (VROW >= max_row)
X				VROW = max_row -1;
X			break;
X		case 256+MV_RIGHT:	/* move "cursor" right */
X			VCOL++;
X			if (VCOL >= max_col)
X				VCOL = max_col -1;
X			break;
X		case 256+MV_LEFT:	/* move "cursor" left */
X		case BS:		/* non destructive back space */
X			VCOL--;
X			if (VCOL < 0)
X				VCOL = 0;
X			break;
X		case 256+MV_DIRECT:	/* direct cursor movement */
X			VROW = vcs_param[MV_DIRECT][0];
X			VCOL = vcs_param[MV_DIRECT][1];
X
X					/* if "add one" and "decimal" */
X			if (vcs_opt[MV_DIRECT][0] && vcs_opt[MV_DIRECT][1]) {
X				VROW--;
X				VCOL--;
X			}
X					/* if "character" */
X			if (vcs_opt[MV_DIRECT][2]) {
X					/* if "add offset" */
X				if (vcs_opt[MV_DIRECT][3]) {
X					VROW -= vcs_opt[MV_DIRECT][5];
X					VCOL -= vcs_opt[MV_DIRECT][5];
X				}
X					/* if "subtract offset" */
X				if (vcs_opt[MV_DIRECT][4]) {
X					VROW += vcs_opt[MV_DIRECT][5];
X					VCOL += vcs_opt[MV_DIRECT][5];
X				}
X				VROW--;
X				VCOL--;
X			}
X			break;
X		case '\t':		/* tab character */
X			tab_stop = VCOL + 8 - (VCOL % 8);
X					/* if wrap around */
X			if (tab_stop >= max_col) {
X					/* spaces up to eol */
X				for (; VCOL<max_col; VCOL++)
X					VS[VROW][VCOL] = ' ';
X				VROW++;
X				if (VROW >= max_row)
X					vs_scroll();
X
X					/* the remainder of the tab */
X				VCOL = tab_stop - max_col;
X			}
X			else {
X				for (; VCOL<tab_stop; VCOL++)
X					VS[VROW][VCOL] = ' ';
X			}
X			break;
X		case '\r':		/* carriage return */
X			VCOL = 0;
X			if (!status->add_lf)
X				break;
X			/* fall thru...*/
X		case '\n':		/* line feed */
X			VROW++;
X			if (VROW >= max_row)
X				vs_scroll();
X			break;
X		default:		/* a normal character */
X			VS[VROW][VCOL] = c;
X			VCOL++;
X					/* wrap around */
X			if (VCOL >= max_col) {
X				VCOL = 0;
X				VROW++;
X				if (VROW >= max_row)
X					vs_scroll();
X			}
X			break;
X	}
X	return(0);
X}
X
X#ifndef SHAREDMEM
X/*
X * Save the virtual screen to a file.
X */
X
Xint
Xwrite_vs()
X{
X	FILE *fp;
X	register int i;
X
X	if (!(fp = fopen(status->vs_path, "w")))
X		return(1);
X					/* current x y coordinates */
X	fprintf(fp, "%d,%d\n", VROW, VCOL);
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()
X{
X	FILE *fp;
X	register int i;
X	char buf[10];
X				/* in case the fopen fails... */
X	VROW = 0;
X	VCOL = 0;
X				/* not guaranteed to exist yet */
X	if (!(fp = fopen(status->vs_path, "r")))
X		return(1);
X				/* get the x, y coordinates */
X	fgets(buf, 10, fp);
X	scanf(buf, "%d,%d\n", VROW, VCOL);
X
X				/* read the file into the vs array */
X	for (i=0; i<max_row; i++) {
X		fgets(VS[i], MAX_COL+2, fp);
X		VS[i][max_col] = NULL;
X	}
X	fclose(fp);
X	return(0);
X}
X#endif /* SHAREDMEM */
X
X/*
X * If the user clears the screen with the ^A-C command, the input
X * has to be in sync.
X */
X
Xint
Xvs_clear()
X{
X	register int j, i;
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	VROW = 0;
X	VCOL = 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
Xvs_scroll()
X{
X	register int i;
X	char *strcpy();
X					/* move 'em up 1 line */
X	for (i=0; i<max_row-1; i++)
X		strcpy(VS[i], VS[i+1]);
X					/* clear the bottom line */
X	for (i=0; i<max_col; i++)
X		VS[max_row-1][i] = ' ';
X
X	VROW = max_row -1;
X	return(0);
X}
X
X/*
X * Do a buffered read from the serial port.
X */
X
Xint
Xreadbyte()
X{
X	static char buf[CLIST];
X	static char *bufp = buf;
X	static int n = 0;
X
X	if (n <= 0) {
X		if ((n = read(status->fd, buf, CLIST)) <= 0)
X			return(-1);
X		bufp = buf;
X	}
X	while (--n >= 0)
X		return(*bufp++ & 0xff);
X	return(-1);
X}
SHAR_EOF
if test 10147 -ne "`wc -c < 'input.c'`"
then
	echo shar: "error transmitting 'input.c'" '(should have been 10147 characters)'
fi
fi
echo shar: "extracting 'line_set.c'" '(1944 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
Xvoid
Xline_set()
X{
X	extern int fd;
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 (fd == -1)
X		return;
X					/* get the current settings */
X	ioctl(fd, TCGETA, &tbuf);
X					/* set some beginning values */
X	tbuf.c_cc[4] = 1;		/* VMIN */
X	tbuf.c_cc[5] = 0;		/* VTIME */
X	tbuf.c_oflag = 0;
X	tbuf.c_iflag = 0;
X	tbuf.c_cflag = (CREAD|HUPCL|CLOCAL);
X	tbuf.c_lflag = 0;
X
X	if (*param->flow == 'X')
X		tbuf.c_iflag |= IXON|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#ifdef B19200
X			tbuf.c_cflag |= B19200;
X#else /* B19200 */
X#ifdef EXTA
X			tbuf.c_cflag |= EXTA;
X#endif /* EXTA */
X#endif /* 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(fd, TCSETA, &tbuf);
X	ioctl(fd, TCFLSH, 2);
X	return;
X}
SHAR_EOF
if test 1944 -ne "`wc -c < 'line_set.c'`"
then
	echo shar: "error transmitting 'line_set.c'" '(should have been 1944 characters)'
fi
fi
echo shar: "extracting 'list_dir.c'" '(1508 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 "config.h"
X#include "misc.h"
X
Xvoid
Xlist_dir()
X{
X	extern int fd;
X	WINDOW *ls_win, *newwin();
X	FILE *pfp, *n_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, VERT, HORZ);
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) {
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 = n_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	touchwin(ls_win);
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) == ESC) {
X				oops++;
X				break;
X			}
X			werase(ls_win);
X			wrefresh(ls_win);
X		}
X	}
X	n_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 1508 -ne "`wc -c < 'list_dir.c'`"
then
	echo shar: "error transmitting 'list_dir.c'" '(should have been 1508 characters)'
fi
fi
echo shar: "extracting 'ls_menu.c'" '(4809 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 "config.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
Xls_menu()
X{
X	extern int fd;
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	horizontal(l_win, 2, 0, 47);
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, VERT, HORZ);
X
X	mvwaddstr(l_win, 19, 13, " 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 (up_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
Xstatic void
Xdisp_settings(win)
XWINDOW *win;
X{
X	extern int xmc;
X	char buf[40];
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 4809 -ne "`wc -c < 'ls_menu.c'`"
then
	echo shar: "error transmitting 'ls_menu.c'" '(should have been 4809 characters)'
fi
fi
exit 0
#	End of shell archive

egray@killer.DALLAS.TX.US (Emmet Gray) (09/05/88)

This is part 5 (of 8) to the Pcomm v1.1 release package.

Emmet P. Gray				US Army, HQ III Corps & Fort Hood
..!uunet!uiucuxc!fthood!egray		Attn: AFZF-DE-ENV
					DEH, 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:
#	m_lib.c
#	macro.c
#	main.c
#	n_shell.c
#	p_lib.c
#	passthru.c
#	pexit.c
#	port.c
#	redial.c
# This archive created: Sat Sep  3 15:35:00 1988
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'm_lib.c'" '(10070 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
X/*
X * Read the modem/TTY database file.  Returns a pointer to a static area
X * containing the MODEM structure.  All modem entries and all TTY entries
X * are created regardless of the number of physical entries in the file.
X */
X
Xstruct MODEM *
Xread_modem(extra)
Xchar *extra;
X{
X	extern char *null_ptr;
X	FILE *fp, *my_fopen();
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, *findfile();
X	static struct MODEM m;
X	void error_win();
X
X	if ((m.m_path = findfile(extra, "pcomm.modem")) == NULL)
X		error_win(1, "Support file 'pcomm.modem' is missing", "or no read permission");
X					/* read permission checked */
X	fp = my_fopen(m.m_path, "r");
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.init_sp[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			 * are distinguished by the letters a, b, and, c
X			 * appended 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 = 12;
X					break;
X				case 2:
X					start = 12;
X					stop = 16;
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.hang_up[mod] = strdup(str);
X						break;
X					case 5:
X						m.auto_baud[mod] = *str;
X						break;
X					case 6:
X						m.con_3[mod] = strdup(str);
X						break;
X					case 7:
X						m.con_12[mod] = strdup(str);
X						break;
X					case 8:
X						m.con_24[mod] = strdup(str);
X						break;
X					case 9:
X						m.con_48[mod] = strdup(str);
X						break;
X					case 10:
X						m.con_96[mod] = strdup(str);
X						break;
X					case 11:
X						m.con_192[mod] = strdup(str);
X						break;
X					case 12:
X						m.no_con1[mod] = strdup(str);
X						break;
X					case 13:
X						m.no_con2[mod] = strdup(str);
X						break;
X					case 14:
X						m.no_con3[mod] = strdup(str);
X						break;
X					case 15:
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/TTY database file '%s'", m.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					/* if empty database */
X	if (!tty) {
X		sprintf(buf, "Modem/TTY database file '%s'", m.m_path);
X		error_win(0, buf, "has no TTY data");
X	}
X	if (!mod) {
X		sprintf(buf, "Modem/TTY database file '%s'", m.m_path);
X		error_win(0, buf, "has no modem data");
X	}
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.init_sp[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.hang_up[mod] = null_ptr;
X
X		m.auto_baud[mod] = 'Y';
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
Xup_modem()
X{
X	FILE *fp, *my_fopen();
X	char buf[80];
X	int i;
X	void error_win();
X
X					/* open for write */
X	if (!(fp = my_fopen(modem->m_path, "w"))) {
X		sprintf(buf, "'%s'", modem->m_path);
X		error_win(0, "No write permission on modem/TTY database 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->init_sp[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->hang_up[i]);
X
X		fprintf(fp, "MODEM_%db=%c;%s;%s;%s;%s;%s;%s\n", i+1,
X		 modem->auto_baud[i], modem->con_3[i], modem->con_12[i],
X		 modem->con_24[i], modem->con_48[i], modem->con_96[i],
X		 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, create
X * 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'", modem->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
Xdel_modem()
X{
X	extern char *null_ptr;
X	int i, j, match;
X	char *strdup();
X	void free_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++;
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->hang_up[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->hang_up[j] = strdup(modem->hang_up[j+1]);
X
X				modem->auto_baud[j] = modem->auto_baud[j+1];
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->hang_up[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->hang_up[j] = null_ptr;
X
X			modem->auto_baud[j] = 'Y';
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 10070 -ne "`wc -c < 'm_lib.c'`"
then
	echo shar: "error transmitting 'm_lib.c'" '(should have been 10070 characters)'
fi
fi
echo shar: "extracting 'macro.c'" '(5243 characters)'
if test -f 'macro.c'
then
	echo shar: "will not over-write existing file 'macro.c'"
else
sed 's/^X//' << \SHAR_EOF > 'macro.c'
X/*
X * The keyboard macro feature.  Displays (and prompts for editing) the
X * macros assigned to the shifted number keys.  Prompts for saving
X * changes to disk.
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include "config.h"
X#include "misc.h"
X#include "param.h"
X
Xint
Xmacro()
X{
X	extern int fd;
X	WINDOW *ma_win, *newwin();
X	int ans, ret_code;
X	char *mac, *strdup(), *mac_prompt();
X	void free_ptr();
X
X	ma_win = newwin(18, 65, 2, 15);
X	mvwattrstr(ma_win, 1, 25, A_BOLD, "Keyboard Macros");
X	horizontal(ma_win, 2, 0, 65);
X	mvwprintw(ma_win, 4, 0, " %4.4s-!  %-50.50s\n", param->ascii_hot, param->mac_1);
X	wprintw(ma_win, " %4.4s-@  %-50.50s\n", param->ascii_hot, param->mac_2);
X	wprintw(ma_win, " %4.4s-#  %-50.50s\n", param->ascii_hot, param->mac_3);
X	wprintw(ma_win, " %4.4s-$  %-50.50s\n", param->ascii_hot, param->mac_4);
X	wprintw(ma_win, " %4.4s-%%  %-50.50s\n", param->ascii_hot, param->mac_5);
X	wprintw(ma_win, " %4.4s-^  %-50.50s\n", param->ascii_hot, param->mac_6);
X	wprintw(ma_win, " %4.4s-&  %-50.50s\n", param->ascii_hot, param->mac_7);
X	wprintw(ma_win, " %4.4s-*  %-50.50s\n", param->ascii_hot, param->mac_8);
X	wprintw(ma_win, " %4.4s-(  %-50.50s\n", param->ascii_hot, param->mac_9);
X	wprintw(ma_win, " %4.4s-)  %-50.50s\n", param->ascii_hot, param->mac_0);
X	mvwaddstr(ma_win, 15, 5, "Macro key to revise:");
X	box(ma_win, VERT, HORZ);
X					/* on the bottom line */
X	mvwaddstr(ma_win, 17, 21, " Press <ESC> to continue ");
X	wmove(ma_win, 15, 26);
X	wrefresh(ma_win);
X
X	ret_code = 0;
X
X	while ((ans = wgetch(ma_win)) != ESC) {
X		switch (ans) {
X			case '!':	/* shifted 1 */
X				if ((mac = mac_prompt(ans, param->mac_1)) != NULL) {
X					free_ptr(param->mac_1);
X					param->mac_1 = strdup(mac);
X					clear_line(ma_win, 4, 9, 1);
X					mvwattrstr(ma_win, 4, 9, A_BOLD, mac);
X					ret_code++;
X				}
X				break;
X			case '@':	/* shifted 2 */
X				if ((mac = mac_prompt(ans, param->mac_2)) != NULL) {
X					free_ptr(param->mac_2);
X					param->mac_2 = strdup(mac);
X					clear_line(ma_win, 5, 9, 1);
X					mvwattrstr(ma_win, 5, 9, A_BOLD, mac);
X					ret_code++;
X				}
X				break;
X			case '#':	/* shifted 3 */
X				if ((mac = mac_prompt(ans, param->mac_3)) != NULL) {
X					free_ptr(param->mac_3);
X					param->mac_3 = strdup(mac);
X					clear_line(ma_win, 6, 9, 1);
X					mvwattrstr(ma_win, 6, 9, A_BOLD, mac);
X					ret_code++;
X				}
X				break;
X			case '$':	/* shifted 4 */
X				if ((mac = mac_prompt(ans, param->mac_4)) != NULL) {
X					free_ptr(param->mac_4);
X					param->mac_4 = strdup(mac);
X					clear_line(ma_win, 7, 9, 1);
X					mvwattrstr(ma_win, 7, 9, A_BOLD, mac);
X					ret_code++;
X				}
X				break;
X			case '%':	/* shifted 5 */
X				if ((mac = mac_prompt(ans, param->mac_5)) != NULL) {
X					free_ptr(param->mac_5);
X					param->mac_5 = strdup(mac);
X					clear_line(ma_win, 8, 9, 1);
X					mvwattrstr(ma_win, 8, 9, A_BOLD, mac);
X					ret_code++;
X				}
X				break;
X			case '^':	/* shifted 6 */
X				if ((mac = mac_prompt(ans, param->mac_6)) != NULL) {
X					free_ptr(param->mac_6);
X					param->mac_6 = strdup(mac);
X					clear_line(ma_win, 9, 9, 1);
X					mvwattrstr(ma_win, 9, 9, A_BOLD, mac);
X					ret_code++;
X				}
X				break;
X			case '&':	/* shifted 7 */
X				if ((mac = mac_prompt(ans, param->mac_7)) != NULL) {
X					free_ptr(param->mac_7);
X					param->mac_7 = strdup(mac);
X					clear_line(ma_win, 10, 9, 1);
X					mvwattrstr(ma_win, 10, 9, A_BOLD, mac);
X					ret_code++;
X				}
X				break;
X			case '*':	/* shifted 8 */
X				if ((mac = mac_prompt(ans, param->mac_8)) != NULL) {
X					free_ptr(param->mac_8);
X					param->mac_8 = strdup(mac);
X					clear_line(ma_win, 11, 9, 1);
X					mvwattrstr(ma_win, 11, 9, A_BOLD, mac);
X					ret_code++;
X				}
X				break;
X			case '(':	/* shifted 9 */
X				if ((mac = mac_prompt(ans, param->mac_9)) != NULL) {
X					free_ptr(param->mac_9);
X					param->mac_9 = strdup(mac);
X					clear_line(ma_win, 12, 9, 1);
X					mvwattrstr(ma_win, 12, 9, A_BOLD, mac);
X					ret_code++;
X				}
X				break;
X			case ')':	/* shifted 0 */
X				if ((mac = mac_prompt(ans, param->mac_0)) != NULL) {
X					free_ptr(param->mac_0);
X					param->mac_0 = strdup(mac);
X					clear_line(ma_win, 13, 9, 1);
X					mvwattrstr(ma_win, 13, 9, A_BOLD, mac);
X					ret_code++;
X				}
X				break;
X			default:
X				beep();
X				break;
X		}
X		touchwin(ma_win);
X		wmove(ma_win, 15, 26);
X		wrefresh(ma_win);
X	}
X					/* if something changed */
X	if (ret_code) {
X					/* save to disk? */
X		if (yes_prompt(ma_win, 15, 30, A_BOLD, "Save to disk")) {
X			if (up_param()) {
X				touchwin(ma_win);
X				wrefresh(ma_win);
X			}
X		}
X	}
X	if (fd == -1) {
X		werase(ma_win);
X		wrefresh(ma_win);
X	}
X	delwin(ma_win);
X	return(ret_code);
X}
X
X/*
X * Sounds like Mac Donalds doesn't it?  Actually, it opens a new window
X * and prompts for the new macro.  Returns a pointer to the new string.
X */
X
Xstatic char *
Xmac_prompt(key, string)
Xchar key, *string;
X{
X	extern char *null_ptr;
X	WINDOW *mp_win, *newwin();
X	char *new, *get_str();
X
X	mp_win = newwin(6, 65, 8, 0);
X	mvwprintw(mp_win, 2, 3, "%4.4s-%c  %-50.50s", param->ascii_hot, key, string);
X	mvwaddstr(mp_win, 3, 5, "New : ");
X	box(mp_win, VERT, HORZ);
X	wrefresh(mp_win);
X
X	new = get_str(mp_win, 50, "", "");
X					/* if space, change to NULL pointer */
X	if (!strcmp(new, " "))
X		new = null_ptr;
X
X	werase(mp_win);
X	wrefresh(mp_win);
X	delwin(mp_win);
X	return(new);
X}
SHAR_EOF
if test 5243 -ne "`wc -c < 'macro.c'`"
then
	echo shar: "error transmitting 'macro.c'" '(should have been 5243 characters)'
fi
fi
echo shar: "extracting 'main.c'" '(6133 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 that
X * is designed to operate similar to the 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 * ...!uunet!uiucuxc!fthood!egray	Attn: AFZF-DE-ENV
X *					Directorate of Engineering & Housing
X *					Environmental Management Office
X *					Fort Hood, TX 76544-5057
X *
X *	Release v1.0	12 Mar 88
X *	  patch #1	22 Mar 88
X *	  patch #2	26 Mar 88
X *	  patch #3	 3 Apr 88
X *	  patch #4	14 Apr 88
X *	  patch #5	25 May 88
X *	Release v1.1	21 Aug 88
X */
X
X#include <stdio.h>
X#include <signal.h>
X#include <curses.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include "config.h"
X#ifndef OLDCURSES
X#include <term.h>
X#endif /* OLDCURSES */
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 tcbuf[1024], *TI, *VS;
X#define cbreak crmode
X#endif /* OLDCURSES */
X
X#ifdef SHAREDMEM
Xint shm_id;
X#endif /* SHAREDMEM */
X
Xstruct PARAM *param;
Xstruct DIAL_DIR *dir;
Xstruct STATUS *status;
Xstruct MODEM *modem;
X
Xint fd = -1;				/* file descriptor for port */
Xint xmc;				/* magic cookie terminal */
Xint msg_status;				/* read/write permissions on TTY */
Xchar *null_ptr = "";			/* generic null pointer */
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X	extern char *optarg;
X	int c, ret_code, i, code, quit();
X	char *mytty, *ttyname(), *term, *getenv(), *short_cut, *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(), free_ptr();
X#ifdef OLDCURSES
X	char *tgetstr(), *t, tb[1024];
X	t = tcbuf;
X#endif /* OLDCURSES */
X
X	signal(SIGINT, SIG_IGN);
X	signal(SIGQUIT, SIG_IGN);
X	signal(SIGTERM, quit);
X	signal(SIGHUP, quit);
X
X	short_cut = 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				short_cut = 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(tb, 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", &t) == 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	TI = tgetstr("ti", &t);
X	VS = tgetstr("vs", &t);
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(short_cut);
X					/* get "msgs" status */
X	mytty = ttyname(0);
X	stat(mytty, &stbuf);
X	chmod(mytty, 0600);
X	msg_status = stbuf.st_mode & 0777;
X					/* read the support files */
X	param = read_param(extra_dir);
X	dir = read_dir(extra_dir);
X	modem = read_modem(extra_dir);
X	free_ptr(extra_dir);
X					/* warning about screen size */
X	if (LINES > MAX_ROW || COLS > MAX_COL)
X		error_win(0, "Your screen size exceeds an internal Pcomm limit",
X		 "The edges of the screen may contain garbage");
X
X					/* short-cut to dialing window? */
X	code = 0;
X	if (short_cut != NULL) {
X		for (i=1; i<dir->d_entries+1; i++) {
X			if (!strcmp(dir->index[i], short_cut)) {
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", short_cut);
X			sprintf(message, "file '%s'", dir->d_path);
X			error_win(0, buf, message);
X		}
X		free_ptr(short_cut);
X	}
X					/* start terminal dialogue */
X	terminal(code);
X	exit(0);
X}
X
X/*
X * Something dreadful happened...  Clean up 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}
X
X/*
X * Check the read and write permissions before opening a file.  This
X * is a horrible kludge to work around that fact that a lot of systems
X * that claim to be SVID compatible don't treat setuid(2) and setgid(2)
X * properly.  For example, on a Masscomp, you can't flip-flop back and
X * forth between the real and effective UID/GID.
X */
X
XFILE *
Xmy_fopen(file, mode)
Xchar *file, *mode;
X{
X#ifdef SETUGID
X	switch (*mode) {
X		case 'a':
X		case 'w':
X			if (!can_write(file))
X				return(NULL);
X			break;
X		case 'r':
X			if (access(file, 4))
X				return(NULL);
X			break;
X	}
X#endif /* SETUGID */
X	return ((FILE *) fopen(file, mode));
X}
SHAR_EOF
if test 6133 -ne "`wc -c < 'main.c'`"
then
	echo shar: "error transmitting 'main.c'" '(should have been 6133 characters)'
fi
fi
echo shar: "extracting 'n_shell.c'" '(1255 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#include "config.h"
X
Xvoid
Xn_shell()
X{
X	WINDOW *sh_win, *newwin();
X	int (*istat)(), (*qstat)(), status, spid, 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	touchwin(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 (!(spid = fork())) {
X		signal(SIGINT, SIG_DFL);
X		signal(SIGQUIT, SIG_DFL);
X#ifdef SETUGID
X		setgid(getgid());
X		setuid(getuid());
X#endif /* SETUGID */
X		execl(shellpath, shell, "-i", (char *) 0);
X		_exit(1);
X	}
X	istat = signal(SIGINT, SIG_IGN);
X	qstat = signal(SIGQUIT, SIG_IGN);
X
X	while ((w = wait(&status)) != spid && w != -1)
X		;
X
X	signal(SIGINT, istat);
X	signal(SIGQUIT, qstat);
X					/* back to curses mode */
X	sleep(1);
X	fixterm();
X
X	clearok(curscr, TRUE);
X	werase(sh_win);
X	wrefresh(sh_win);
X	delwin(sh_win);
X	return;
X}
SHAR_EOF
if test 1255 -ne "`wc -c < 'n_shell.c'`"
then
	echo shar: "error transmitting 'n_shell.c'" '(should have been 1255 characters)'
fi
fi
echo shar: "extracting 'p_lib.c'" '(7151 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
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(extra)
Xchar *extra;
X{
X	FILE *fp;
X	int i, oops;
X	char buf[80], *temp_token, *str, *strdup(), *findfile();
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", "BRK_CHAR", "ABORT", "C_DELAY", "R_DELAY", "LECHO",
X	"EXPAND", "CR_DELAY", "PACE", "CR_UP", "LF_UP", "TIMER", "CR_DN",
X	"LF_DN", "LD_PLUS", "LD_MINUS", "LD_AT", "LD_POUND", "MAC_1",
X	"MAC_2", "MAC_3", "MAC_4", "MAC_5", "MAC_6", "MAC_7", "MAC_8",
X	"MAC_9", "MAC_0"};
X	static struct PARAM p;
X	void error_win();
X
X	if ((p.p_path = findfile(extra, "pcomm.param")) == NULL)
X		error_win(1, "Support file 'pcomm.param' is missing", "or no read permission");
X					/* read permission already checked */
X	fp = fopen(p.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 ls_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.brk_char = *str;
X				break;
X			case GEN_SETUP+8:
X				p.abort = strdup(str);
X				break;
X
X					/* used in gen_setup() delay_times() */
X			case DELAY_TIMES:
X				p.c_delay = atoi(str);
X				break;
X			case DELAY_TIMES+1:
X				p.r_delay = atoi(str);
X				break;
X
X					/* used in axfer_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					/* used in macro() */
X			case MACROS:
X				p.mac_1 = strdup(str);
X				break;
X			case MACROS+1:
X				p.mac_2 = strdup(str);
X				break;
X			case MACROS+2:
X				p.mac_3 = strdup(str);
X				break;
X			case MACROS+3:
X				p.mac_4 = strdup(str);
X				break;
X			case MACROS+4:
X				p.mac_5 = strdup(str);
X				break;
X			case MACROS+5:
X				p.mac_6 = strdup(str);
X				break;
X			case MACROS+6:
X				p.mac_7 = strdup(str);
X				break;
X			case MACROS+7:
X				p.mac_8 = strdup(str);
X				break;
X			case MACROS+8:
X				p.mac_9 = strdup(str);
X				break;
X			case MACROS+9:
X				p.mac_0 = strdup(str);
X				break;
X		}
X	}
X	fclose(fp);
X	if (oops) {
X		sprintf(buf, "Parameter file '%s'", p.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
Xup_param()
X{
X	FILE *fp, *my_fopen();
X	char buf[80];
X	void error_win();
X					/* open for write */
X	if (!(fp = my_fopen(param->p_path, "w"))) {
X		sprintf(buf, "'%s'", param->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, "BRK_CHAR=%c\n", param->brk_char);
X	fprintf(fp, "ABORT=%s\n", param->abort);
X	fprintf(fp, "C_DELAY=%d\n", param->c_delay);
X	fprintf(fp, "R_DELAY=%d\n", param->r_delay);
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	fprintf(fp, "MAC_1=%s\n", param->mac_1);
X	fprintf(fp, "MAC_2=%s\n", param->mac_2);
X	fprintf(fp, "MAC_3=%s\n", param->mac_3);
X	fprintf(fp, "MAC_4=%s\n", param->mac_4);
X	fprintf(fp, "MAC_5=%s\n", param->mac_5);
X	fprintf(fp, "MAC_6=%s\n", param->mac_6);
X	fprintf(fp, "MAC_7=%s\n", param->mac_7);
X	fprintf(fp, "MAC_8=%s\n", param->mac_8);
X	fprintf(fp, "MAC_9=%s\n", param->mac_9);
X	fprintf(fp, "MAC_0=%s\n", param->mac_0);
X
X	fclose(fp);
X	return(0);
X}
SHAR_EOF
if test 7151 -ne "`wc -c < 'p_lib.c'`"
then
	echo shar: "error transmitting 'p_lib.c'" '(should have been 7151 characters)'
fi
fi
echo shar: "extracting 'passthru.c'" '(2141 characters)'
if test -f 'passthru.c'
then
	echo shar: "will not over-write existing file 'passthru.c'"
else
sed 's/^X//' << \SHAR_EOF > 'passthru.c'
X/*
X * A transparent "pass-thru" mode, designed to allow binary transfers
X * between 3 machines (with the middle machine in the pass-thru mode).
X * A non-zero return code means the input routine should be restarted.
X */
X
X#include <stdio.h>
X#include <signal.h>
X#include <curses.h>
X#include "config.h"
X#include "misc.h"
X
Xint
Xpass_thru()
X{
X	extern int fd;
X	WINDOW *pt_win, *newwin();
X	int num;
X	void cpio();
X
X	pt_win = newwin(5, 70, 5, 5);
X
X	mvwaddstr(pt_win, 2, 4, "Enter the expiration time (5-60 sec): ");
X	box(pt_win, VERT, HORZ);
X
X	mvwattrstr(pt_win, 0, 3, A_BOLD, " Pass Through Mode ");
X	wmove(pt_win, 2, 43);
X	wrefresh(pt_win);
X					/* get the answer */
X	while ((num = get_num(pt_win, 2)) != -1) {
X					/* out of bounds */
X		if (num < 5 || num > 60) {
X			beep();
X			clear_line(pt_win, 2, 43, 1);
X			wmove(pt_win, 2, 43);
X			wrefresh(pt_win);
X		}
X		else {
X			werase(pt_win);
X			wrefresh(pt_win);
X			delwin(pt_win);
X
X			touchwin(stdscr);
X			refresh();
X
X			cpio((unsigned int) num);
X			return(1);
X		}
X	}
X	if (fd == -1) {
X		werase(pt_win);
X		wrefresh(pt_win);
X	}
X	delwin(pt_win);
X	return(0);
X}
X
X/*
X * Copy the stdin to the TTYout and copy the TTYin to the stdout.  Uses
X * multi character reads.  I'm not too concerned about the excess bagage
X * caused by the entire image being forked... this feature won't be used
X * that often.
X */
X
Xstatic int cp_flag;
X
Xstatic void
Xcpio(num)
Xunsigned int num;
X{
X	extern int fd;
X	int cpid, n, cp_force();
X	char buf[BUFSIZ];
X	unsigned int alarm(), sleep();
X	void line_set(), xmodem_mode(), input_off();
X
X					/* out of curses mode */
X	resetterm();
X
X	input_off();
X	xmodem_mode(0);
X	xmodem_mode(fd);
X
X					/* copy the TTYin to stdout */
X	if (!(cpid = fork())) {
X		while (1) {
X			n = read(fd, buf, BUFSIZ);
X			write(1, buf, n);
X		}
X	}
X
X	cp_flag = 0;
X	signal(SIGALRM, cp_force);
X					/* copy the stdin to TTYout */
X	while (1) {
X		alarm(num);
X		n = read(0, buf, BUFSIZ);
X		if (cp_flag)
X			break;
X		write(fd, buf, n);
X	}
X	kill(cpid, SIGKILL);
X					/* back to curses mode */
X	sleep(1);
X	fixterm();
X	beep();
X	line_set();
X	clearok(curscr, TRUE);
X	return;
X}
X/*ARGSUSED*/
Xstatic int
Xcp_force(dummy)
X{
X	cp_flag = 1;
X}
SHAR_EOF
if test 2141 -ne "`wc -c < 'passthru.c'`"
then
	echo shar: "error transmitting 'passthru.c'" '(should have been 2141 characters)'
fi
fi
echo shar: "extracting 'pexit.c'" '(2504 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 "config.h"
X#ifdef SHAREDMEM
X#include <sys/types.h>
X#include <sys/ipc.h>
X#include <sys/shm.h>
X#endif /* SHAREDMEM */
X#include "dial_dir.h"
X#include "misc.h"
X#include "param.h"
X#include "status.h"
X
Xvoid
Xpexit()
X{
X	extern int fd;
X	WINDOW *ex_win, *newwin();
X	void cleanup(), st_line();
X
X	ex_win = newwin(5, 33, 3, 7);
X
X	box(ex_win, VERT, HORZ);
X	mvwattrstr(ex_win, 0, 3, A_BOLD, " Exit ");
X	if (yes_prompt(ex_win, 2, 4, A_BLINK, "Exit to Unix")) {
X		st_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 clean up detail before we exit.  Only the status structure
X * is guaranteed to exit.
X */
X
Xvoid
Xcleanup(val)
Xint val;
X{
X	extern int msg_status;
X	void release_port(), input_off(), exit();
X	char *ttyname();
X#ifdef SHAREDMEM
X	extern int shm_id;
X#endif /* SHAREDMEM */
X					/* kill the input routine */
X	input_off();
X					/* release the port */
X	release_port(0);
X					/* zap the virtual screen */
X#ifdef SHAREDMEM
X	if (shmdt((char *) status) < 0)
X		perror("shmdt");
X	if (shmctl(shm_id, IPC_RMID, (struct shmid_ds *) NULL) < 0)
X		perror("shmctl");
X#else /* SHAREDMEM */
X	unlink(status->vs_path);
X#endif /* SHAREDMEM */
X
X	/*
X	 * If we die an un-natural death (such as a SIGHUP on the loss of
X	 * the controlling terminal) we won't have a terminal to mess with.
X	 */
X	if (isatty(0)) {
X		touchwin(stdscr);
X		clear();
X		refresh();
X		endwin();
X					/* return the TTY chmod */
X		chmod(ttyname(0), msg_status);
X	}
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(), st_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, VERT, HORZ);
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		st_line("   exiting");
X		cleanup(code);
X	}
X	return;
X}
SHAR_EOF
if test 2504 -ne "`wc -c < 'pexit.c'`"
then
	echo shar: "error transmitting 'pexit.c'" '(should have been 2504 characters)'
fi
fi
echo shar: "extracting 'port.c'" '(9459 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 MAX_PID 30000
X
X#include <stdio.h>
X#include <fcntl.h>
X#include <termio.h>
X#include <errno.h>
X#include "config.h"
X#ifdef UNIXPC
X#include <sys/phone.h>
X#endif /* UNIXPC */
X#include "dial_dir.h"
X#include "modem.h"
X
Xstatic int getty_status;
Xstatic char *lock_path = NULL;
X/*
X * Finds a free (or requested) serial port.  Creates a lock file to hold
X * 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	extern int fd;
X	register int i;
X	int j, k, lfd, list[NUM_TTY], cmask, tbaud;
X	char file[80], buf[80], message[80], *strdup();
X	unsigned int sleep();
X	void error_win(), line_set(), release_port(), send_str();
X	void free_ptr();
X#ifndef ASCII_PID
X	int progpid;
X#endif /* ASCII_PID */
X
X	/*
X	 * If we already have a port, see if it is good enough for the
X	 * current request.
X	 */
X#ifdef KEEP_PORT
X	if (fd != -1) {
X		if (!strcmp(dir->index[dir->d_cur], modem->tty[modem->t_cur]) ||
X		 ck_speed(modem->t_cur, dir->baud[dir->d_cur])) {
X			/*
X			 * Reset the line because the baud rate (or other
X			 * parameters) may have changed.
X			 */
X			line_set();
X			return(0);
X		}
X	}
X#endif /* KEEP_PORT */
X	release_port(1);
X
X	list[0] = -1;
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	if (*dir->index[dir->d_cur] != NULL) {
X		sprintf(buf, "/dev/%s", dir->index[dir->d_cur]);
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	/*
X	 * Create a list of acceptable TTYs.  It searches the modem 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 (ck_speed(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 the", dir->baud[dir->d_cur]);
X		sprintf(buf, "modem database '%s'", modem->m_path);
X		error_win(0, message, buf);
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", LOCK_DIR, modem->tty[list[i]]);
X#ifdef DEBUG
X		fprintf(stderr, "get_port: checking '/dev/%s'\n", modem->tty[list[i]]);
X#endif /* DEBUG */
X
X					/* does it exist or is it dead? */
X		if (checklock(file)) {
X			getty_status = set_getty(modem->tty[list[i]], 0);
X
X			cmask = umask(0);
X			if ((lfd = open(file, O_CREAT|O_EXCL|O_WRONLY, 0666)) < 0) {
X				if (getty_status)
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			umask(cmask);
X#ifdef ASCII_PID
X			sprintf(buf, "%10d\n", getpid());
X			write(lfd, buf, 11);
X#else /* ASCII_PID */
X			progpid = getpid();
X			write(lfd, (char *) &progpid, sizeof(int));
X#endif /* ASCII_PID */
X			close(lfd);
X					/* store the new values */
X			free_ptr(lock_path);
X			lock_path = strdup(file);
X			modem->t_cur = list[i];
X
X					/* open the device (ignore DCD) */
X			sprintf(buf, "/dev/%s", modem->tty[modem->t_cur]);
X			if ((fd = open(buf, O_RDWR|O_NDELAY)) < 0) {
X				if (getty_status)
X					set_getty(modem->tty[modem->t_cur], 1);
X				sprintf(file, "Can't open port '%s' for read and write", buf);
X				error_win(1, file, "");
X			}
X					/* turn off the "no delay" mode */
X			fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NDELAY);
X					/* change line settings */
X			line_set();
X					/* load the modem data base */
X			modem->m_cur = -1;
X			for (j=0; j<modem->m_entries; j++) {
X				if (!strcmp(modem->tname[modem->t_cur], modem->mname[j])) {
X					modem->m_cur = j;
X					break;
X				}
X			}
X			if (modem->m_cur == -1) {
X				sprintf(buf, "Modem name '%s' in TTY database",
X				 modem->tname[modem->t_cur]);
X				error_win(1, buf, "does not exist in modem database");
X			}
X					/* initialize the modem */
X			if (modem->init_sp[modem->t_cur]) {
X				tbaud = dir->baud[dir->d_cur];
X				dir->baud[dir->d_cur] = modem->init_sp[modem->t_cur];
X				line_set();
X				send_str(modem->init[modem->m_cur]);
X				dir->baud[dir->d_cur] = tbaud;
X			}
X			else
X				send_str(modem->init[modem->m_cur]);
X			sleep(1);
X			return(0);
X		}
X		i++;
X	}
X	error_win(0, "All ports are busy now, try again later", "");
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	extern int fd;
X	extern char *null_ptr;
X	char buf[80];
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 (fd != -1) {
X		ioctl(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 hang_up string first.
X		 */
X		hang_up(verbose);
X		close(fd);
X	}
X					/* remove the lock */
X	if (*lock_path != NULL && lock_path != NULL) {
X		if (unlink(lock_path)) {
X			sprintf(buf, "'%s'", lock_path);
X			error_win(0, "Can't remove the lock file", buf);
X		}
X		free_ptr(lock_path);
X		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					/* clean up the structure */
X	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
X/*ARGSUSED*/
Xstatic int
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++;
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	 * The return code should tell if there was a getty or not.
X	 * Obviously the program would be suid to root.
X	 */
X	return(0);
X#endif /* UNIXPC */
X}
X
X/*
X * Check the lock file for a valid pid value.  Error conditions such
X * as not being able to open the lock file or not being able to interpret
X * the contents of the lock file cause the code to assume that the lock
X * file is valid.  Let the user worry about weird special cases.  A return
X * code of 1 means the lock is dead or doesn't exist.
X */
X
Xstatic int
Xchecklock(lockfile)
Xchar *lockfile;
X{
X	extern int errno;
X	int lfd, lckpid;
X#ifdef ASCII_PID
X	int n;
X	char buf[40];
X#endif /* ASCII_PID */
X					/* doesn't exist */
X	if (access(lockfile, 0))
X		return(1);
X					/* can't open the lock file */
X	if ((lfd = open(lockfile, 0)) < 0)
X		return(0);
X
X#ifdef ASCII_PID
X	if ((n = read(lfd, buf, 40)) <= 0) {
X		close(lfd);
X		return(0);
X	}
X	close(lfd);
X	buf[n--] = '\0';
X	lckpid = atoi(buf);
X#else /* ASCII_PID */
X	if (read(lfd, (char *) &lckpid, sizeof(int)) != sizeof(int)) {
X		close(lfd);
X		return(0);
X	}
X	close(lfd);
X#endif /* ASCII_PID */
X					/* invalid pid? */
X	if (lckpid <= 0 || lckpid > MAX_PID)
X		return(0);
X
X	if ((kill(lckpid, 0) == -1) && (errno == ESRCH)) {
X		/*
X		 * If the kill was unsuccessful due to an ESRCH error,
X		 * that means the process is no longer active and the
X		 * lock file can be safely removed.
X		 */
X		unlink(lockfile);
X		sleep(1);
X		return(1);
X	}
X	/*
X	 * If the kill() was successful, that means the process must
X	 * still active.
X	 */
X	return(0);
X}
X
X/*
X * Check to see if the desired baud rate can be handled by the modem.
X * Uses the connect strings to make this determination.  The first
X * argument is the index into the TTY database.  A return code of 1
X * means yes.
X */
X
Xstatic int
Xck_speed(tty, baud)
Xint tty, baud;
X{
X	int i, mod;
X	char buf[60];
X					/* find the modem database */
X	mod = -1;
X	for (i=0; i<modem->m_entries; i++) {
X		if (!strcmp(modem->mname[i], modem->tname[tty])) {
X			mod = i;
X			break;
X		}
X	}
X	if (mod == -1) {
X		sprintf(buf, "Modem name '%s' in TTY database", modem->tname[tty]);
X		error_win(1, buf, "does not exist in modem database");
X	}
X#ifdef DEBUG
X	fprintf(stderr, "ck_speed: checking modem '%s' for %d buad\n", modem->mname[mod], baud);
X#endif /* DEBUG */
X
X	switch (baud) {
X		case 300:
X			if (*modem->con_3[mod] != NULL)
X				return(1);
X			break;
X		case 1200:
X			if (*modem->con_12[mod] != NULL)
X				return(1);
X			break;
X		case 2400:
X			if (*modem->con_24[mod] != NULL)
X				return(1);
X			break;
X		case 4800:
X			if (*modem->con_48[mod] != NULL)
X				return(1);
X			break;
X		case 9600:
X			if (*modem->con_96[mod] != NULL)
X				return(1);
X			break;
X		case 19200:
X			if (*modem->con_192[mod] != NULL)
X				return(1);
X			break;
X	}
X	return(0);
X}
SHAR_EOF
if test 9459 -ne "`wc -c < 'port.c'`"
then
	echo shar: "error transmitting 'port.c'" '(should have been 9459 characters)'
fi
fi
echo shar: "extracting 'redial.c'" '(2242 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 non-zero return code
X * means we're ready to dial.
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include "config.h"
X#include "dial_dir.h"
X#include "misc.h"
X
Xint
Xredial()
X{
X	extern int fd;
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, VERT, HORZ);
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) {
X		oops = 0;
X		if (*ans == NULL) {
X					/* use previous queue */
X			if (dir->q_num[0] != -1) {
X				ret_code++;
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++;
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 2242 -ne "`wc -c < 'redial.c'`"
then
	echo shar: "error transmitting 'redial.c'" '(should have been 2242 characters)'
fi
fi
exit 0
#	End of shell archive

egray@killer.DALLAS.TX.US (Emmet Gray) (09/05/88)

This is part 6 (of 8) to the Pcomm v1.1 release package.

Emmet P. Gray				US Army, HQ III Corps & Fort Hood
..!uunet!uiucuxc!fthood!egray		Attn: AFZF-DE-ENV
					DEH, 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
# This archive created: Sat Sep  3 15:35:04 1988
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 's_axfer.c'" '(3938 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 "config.h"
X#include "misc.h"
X#include "param.h"
X
Xint
Xaxfer_setup()
X{
X	extern char *v_yes[];
X	WINDOW *x_win, *newwin();
X	int i, ret_code, num;
X	char *ans, *menu_prompt(), *strdup();
X	void free_ptr();
X	static char *v_cr[4] = {"NONE", "STRIP", "ADD LF", NULL};
X	static char *v_lf[4] = {"NONE", "STRIP", "ADD CR", NULL};
X	static char *v_delay[4] = {"0", "100", "150", NULL};
X
X	x_win = newwin(23, 80, 0, 0);
X
X	horizontal(x_win, 0, 0, 28);
X	mvwattrstr(x_win, 0, 29, A_BOLD, "ASCII Transfer Setup");
X	horizontal(x_win, 0, 50, 29);
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 (sec) . %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	horizontal(x_win, 19, 0, 80);
X	mvwattrstr(x_win, 20, 0, A_BOLD, "OPTION ==> ");
X	mvwaddstr(x_win, 20, 58, "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", "(in seconds)")) != -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, (chtype) ' ');
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 3938 -ne "`wc -c < 's_axfer.c'`"
then
	echo shar: "error transmitting 's_axfer.c'" '(should have been 3938 characters)'
fi
fi
echo shar: "extracting 's_gen.c'" '(4457 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 "config.h"
X#include "misc.h"
X#include "param.h"
X
Xint
Xgen_setup()
X{
X	extern char *v_yes[];
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(), line_set();
X	static char *v_abort[3] = {"KEEP", "DELETE", NULL};
X
X	g_win = newwin(23, 80, 0, 0);
X
X	horizontal(g_win, 0, 0, 32);
X	mvwattrstr(g_win, 0, 33, A_BOLD, "General Setup");
X	horizontal(g_win, 0, 47, 32);
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, 12, 22, "8) Break character ........ %c", param->brk_char);
X	mvwprintw(g_win, 14, 22, "9) Aborted downloads ...... %s", param->abort);
X	mvwprintw(g_win, 16, 21, "10) Connect delay (sec) .... %d", param->c_delay);
X	mvwprintw(g_win, 17, 21, "11) Redial delay (sec) ..... %d", param->r_delay);
X	horizontal(g_win, 19, 0, 80);
X	mvwattrstr(g_win, 20, 0, A_BOLD, "OPTION ==> ");
X	mvwaddstr(g_win, 20, 58, "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) {
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) {
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					line_set();
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 ((c = chr_prompt(g_win, 12, 50, "Break character", "")) != NULL) {
X					param->brk_char = c;
X					ret_code++;
X				}
X			case 9:
X				if ((ans = menu_prompt(g_win, 14, 50, "Aborted downloads", v_abort)) != NULL) {
X					free_ptr(param->abort);
X					param->abort = strdup(ans);
X					ret_code++;
X				}
X				break;
X			case 10:
X				if ((num = num_prompt(g_win, 16, 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, 16, 50, "   ");
X						wrefresh(g_win);
X						mvwattrnum(g_win, 16, 50, A_BOLD, num);
X						wrefresh(g_win);
X					}
X					param->c_delay = num;
X					ret_code++;
X				}
X				break;
X			case 11:
X				if ((num = num_prompt(g_win, 17, 50, "Redial delay time", "(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, 17, 50, "    ");
X						wrefresh(g_win);
X						mvwattrnum(g_win, 17, 50, A_BOLD, num);
X						wrefresh(g_win);
X					}
X					param->r_delay = 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 4457 -ne "`wc -c < 's_gen.c'`"
then
	echo shar: "error transmitting 's_gen.c'" '(should have been 4457 characters)'
fi
fi
echo shar: "extracting 's_menu.c'" '(2732 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.  A return
X * code of 1 means we have to restart the input routine.
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include "config.h"
X#include "misc.h"
X
Xint
Xsetup_menu()
X{
X	extern int fd, xmc;
X	WINDOW *s_win, *newwin();
X	char *ans, *get_str();
X	int param_flag, modem_flag, ret_code;
X	void top_line();
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	horizontal(s_win, 19, 0, 80);
X	mvwattrstr(s_win, 20, 0, A_BOLD, "OPTION ==> ");
X	mvwaddstr(s_win, 20, 58, "  Press <ESC> to exit");
X	wmove(s_win, 20, 12);
X	touchwin(s_win);
X	wrefresh(s_win);
X
X	param_flag = 0;
X	modem_flag = 0;
X	ret_code = 0;
X					/* get the options */
X	while ((ans = get_str(s_win, 1, "12345Ss", "")) != 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++;
X				break;
X			case '2':
X				if (modem_setup())
X					modem_flag++;
X				break;
X			case '3':
X				if (ret_code = term_setup()) {
X					ret_code--;
X					param_flag++;
X				}
X				break;
X			case '4':
X				if (gen_setup())
X					param_flag++;
X				break;
X			case '5':
X				if (axfer_setup())
X					param_flag++;
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 (up_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 (up_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, (chtype) ' ');
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(ret_code);
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	horizontal(win, 0, 0, 33);
X	mvwattrstr(win, 0, 34, A_BOLD, "Setup Menu");
X	horizontal(win, 0, 45, 34);
X	wrefresh(win);
X	return;
X}
SHAR_EOF
if test 2732 -ne "`wc -c < 's_menu.c'`"
then
	echo shar: "error transmitting 's_menu.c'" '(should have been 2732 characters)'
fi
fi
echo shar: "extracting 's_modem.c'" '(6867 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 "config.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, mod_prompt();
X	char *ans, *strdup(), *str_prompt(), *menu_prompt();
X	void disp_modem(), free_ptr();
X	static char *v_yn[3] = {"Y", "N", NULL};
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	horizontal(mo_win, 0, 0, 33);
X	mvwattrstr(mo_win, 0, 34, A_BOLD, "Modem Setup");
X	horizontal(mo_win, 0, 46, 34);
X					/* display the current settings */
X	disp_modem(mo_win, j);
X	horizontal(mo_win, 19, 0, 80);
X	mvwattrstr(mo_win, 20, 0, A_BOLD, "OPTION ==> ");
X	mvwaddstr(mo_win, 20, 58, "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 = mod_prompt(mo_win);
X				break;
X			case 2:
X				if ((ans = str_prompt(mo_win, 3, 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, 4, 40, "Dialing command", "")) != 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, 5, 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, 6, 40, "Hang up string", "")) != NULL) {
X					free_ptr(modem->hang_up[j]);
X					modem->hang_up[j] = strdup(ans);
X					ret_code++;
X				}
X				break;
X			case 6:
X				if ((ans = menu_prompt(mo_win, 7, 40, "Auto Baud detect", v_yn)) != NULL) {
X					modem->auto_baud[j] = *ans;
X					ret_code++;
X				}
X				break;
X			case 7:
X				if ((ans = str_prompt(mo_win, 8, 40, "300 baud connect string", "")) != NULL) {
X					free_ptr(modem->con_3[j]);
X					modem->con_3[j] = strdup(ans);
X					ret_code++;
X				}
X				break;
X			case 8:
X				if ((ans = str_prompt(mo_win, 9, 40, "1200 baud connect string", "")) != NULL) {
X					free_ptr(modem->con_12[j]);
X					modem->con_12[j] = strdup(ans);
X					ret_code++;
X				}
X				break;
X			case 9:
X				if ((ans = str_prompt(mo_win, 10, 40, "2400 baud connect string", "")) != NULL) {
X					free_ptr(modem->con_24[j]);
X					modem->con_24[j] = strdup(ans);
X					ret_code++;
X				}
X				break;
X			case 10:
X				if ((ans = str_prompt(mo_win, 11, 40, "4800 baud connect string", "")) != NULL) {
X					free_ptr(modem->con_48[j]);
X					modem->con_48[j] = strdup(ans);
X					ret_code++;
X				}
X				break;
X			case 11:
X				if ((ans = str_prompt(mo_win, 12, 40, "9600 baud connect string", "")) != NULL) {
X					free_ptr(modem->con_96[j]);
X					modem->con_96[j] = strdup(ans);
X					ret_code++;
X				}
X				break;
X			case 12:
X				if ((ans = str_prompt(mo_win, 13, 40, "19200 baud connect string", "")) != NULL) {
X					free_ptr(modem->con_192[j]);
X					modem->con_192[j] = strdup(ans);
X					ret_code++;
X				}
X				break;
X			case 13:
X				if ((ans = str_prompt(mo_win, 14, 40, "No connect string 1", "")) != NULL) {
X					free_ptr(modem->no_con1[j]);
X					modem->no_con1[j] = strdup(ans);
X					ret_code++;
X				}
X				break;
X			case 14:
X				if ((ans = str_prompt(mo_win, 15, 40, "No connect string 2", "")) != NULL) {
X					free_ptr(modem->no_con2[j]);
X					modem->no_con2[j] = strdup(ans);
X					ret_code++;
X				}
X				break;
X			case 15:
X				if ((ans = str_prompt(mo_win, 16, 40, "No connect string 3", "")) != NULL) {
X					free_ptr(modem->no_con3[j]);
X					modem->no_con3[j] = strdup(ans);
X					ret_code++;
X				}
X				break;
X			case 16:
X				if ((ans = str_prompt(mo_win, 17, 40, "No connect string 4", "")) != 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
Xstatic int
Xmod_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 == ESC)
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	mvwprintw(win, 2, 26, "(%d of %d) ", i+1, modem->m_entries);
X
X	return(i);
X}
X
X/*
X * Show the current settings for the given modem entry number.
X */
X
Xstatic void
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, 2, 26, "(%d of %d) ", i+1, modem->m_entries);
X	mvwprintw(w, 3, 12, "2) Modem init string ...... %-39.39s", modem->init[i]);
X	mvwprintw(w, 4, 12, "3) Dialing command ........ %-39.39s", modem->dial[i]);
X	mvwprintw(w, 5, 12, "4) Dialing cmd suffix ..... %-39.39s", modem->suffix[i]);
X	mvwprintw(w, 6, 12, "5) Hang up string ......... %-39.39s", modem->hang_up[i]);
X	mvwprintw(w, 7, 12, "6) Auto baud detect ....... %c", modem->auto_baud[i]);
X	mvwprintw(w, 8, 12, "7) 300 baud connect ....... %-39.39s", modem->con_3[i]);
X	mvwprintw(w, 9, 12, "8) 1200 baud connect ...... %-39.39s", modem->con_12[i]);
X	mvwprintw(w, 10, 12, "9) 2400 baud connect ...... %-39.39s", modem->con_24[i]);
X	mvwprintw(w, 11, 11, "10) 4800 baud connect ...... %-39.39s", modem->con_48[i]);
X	mvwprintw(w, 12, 11, "11) 9600 baud connect ...... %-39.39s", modem->con_96[i]);
X	mvwprintw(w, 13, 11, "12) 19200 baud connect ..... %-39.39s", modem->con_192[i]);
X	mvwprintw(w, 14, 11, "13) No connect string 1 .... %-39.39s", modem->no_con1[i]);
X	mvwprintw(w, 15, 11, "14) No connect string 2 .... %-39.39s", modem->no_con2[i]);
X	mvwprintw(w, 16, 11, "15) No connect string 3 .... %-39.39s", modem->no_con3[i]);
X	mvwprintw(w, 17, 11, "16) No connect string 4 .... %-39.39s", modem->no_con4[i]);
X	return;
X}
SHAR_EOF
if test 6867 -ne "`wc -c < 's_modem.c'`"
then
	echo shar: "error transmitting 's_modem.c'" '(should have been 6867 characters)'
fi
fi
echo shar: "extracting 's_prompt.c'" '(2972 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 "config.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	extern char *null_ptr;
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, 39, "", "")) == 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)
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;
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};
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 == ESC)
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 2972 -ne "`wc -c < 's_prompt.c'`"
then
	echo shar: "error transmitting 's_prompt.c'" '(should have been 2972 characters)'
fi
fi
echo shar: "extracting 's_term.c'" '(3172 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, 2 means we have to kill and restart
X * the input routine.
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include "config.h"
X#include "misc.h"
X#include "param.h"
X#include "status.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(), input_off(), line_set();
X	static char *v_crio[3] = {"CR", "CR/LF", NULL};
X	static char *v_duplex[3] = {"FULL", "HALF", NULL};
X	static char *v_flow[3] = {"NONE", "XON/XOFF", NULL};
X
X	t_win = newwin(23, 80, 0, 0);
X
X	horizontal(t_win, 0, 0, 32);
X	mvwattrstr(t_win, 0, 33, A_BOLD, "Terminal Setup");
X	horizontal(t_win, 0, 48, 32);
X	mvwprintw(t_win, 4, 22, "1) Hot key (decimal) ...... %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	horizontal(t_win, 19, 0, 80);
X	mvwattrstr(t_win, 20, 0, A_BOLD, "OPTION ==> ");
X	mvwaddstr(t_win, 20, 58, "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					line_set();
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
X					/*
X					 * the "add lf to cr" function is
X					 * performed by the input routine
X					 */
X					param->cr_in = strdup(ans);
X					if (!strcmp(ans, "CR/LF"))
X						status->add_lf = 1;
X					else
X						status->add_lf = 0;
X#ifdef SHAREDMEM
X					ret_code = 1;
X#else /* SHAREDMEM */
X					input_off();
X					ret_code = 2;
X#endif /* SHAREDMEM */
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, (chtype) ' ');
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 3172 -ne "`wc -c < 's_term.c'`"
then
	echo shar: "error transmitting 's_term.c'" '(should have been 3172 characters)'
fi
fi
echo shar: "extracting 's_tty.c'" '(4800 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 "config.h"
X#include "misc.h"
X#include "modem.h"
X
Xint
Xtty_setup()
X{
X	extern char *null_ptr;
X	WINDOW *tt_win, *newwin();
X	char *strdup(), message[80];
X	int num, i, j, ret_code;
X	void disp_tty(), create_modem(), del_modem(), error_win();
X	void del_tty();
X
X	tt_win = newwin(23, 80, 0, 0);
X
X	horizontal(tt_win, 0, 0, 34);
X	mvwattrstr(tt_win, 0, 35, A_BOLD, "TTY Setup");
X	horizontal(tt_win, 0, 45, 34);
X	mvwaddstr(tt_win, 2, 22, "TTY name");
X	mvwaddstr(tt_win, 2, 37, "Modem name");
X	mvwaddstr(tt_win, 2, 51, "Init speed");
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	horizontal(tt_win, 19, 0, 80);
X	mvwattrstr(tt_win, 20, 0, A_BOLD, "OPTION ==> ");
X	mvwaddstr(tt_win, 20, 58, "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			del_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(message, "'%s'", modem->m_path);
X				error_win(0, "No empty TTY slots in modem/TTY database", message);
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					wmove(tt_win, 21, 24);
X					wrefresh(tt_win);
X					continue;
X				}
X				del_tty(num-1);
X				del_modem();
X
X					/* show the new list */
X				disp_tty(tt_win);
X				ret_code++;
X				break;
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
Xstatic void
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->init_sp[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
Xstatic int
Xtty_prompt(win, i)
XWINDOW *win;
Xint i;
X{
X	char *ans, *temp_tty, *temp_tname, *str_prompt(), *menu_prompt();
X	void free_ptr();
X	static char *v_baud[8] = {"0", "300", "1200", "2400", "4800", "9600",
X	 "19200", NULL};
X					/* get temp TTY */
X	if ((ans = str_prompt(win, i+4, 24, "TTY name", "")) == 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)
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, "Init speed", 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->init_sp[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
Xstatic void
Xdel_tty(i)
Xint i;
X{
X	extern char *null_ptr;
X	int j;
X	char *strdup();
X	void free_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->init_sp[j] = modem->init_sp[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->init_sp[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 4800 -ne "`wc -c < 's_tty.c'`"
then
	echo shar: "error transmitting 's_tty.c'" '(should have been 4800 characters)'
fi
fi
echo shar: "extracting 'screen.c'" '(2074 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#include <stdio.h>
X#include <curses.h>
X#include "config.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_out, *my_fopen();
X	char buf[MAX_COL+2];
X	void error_win();
X#ifdef SHAREDMEM
X	int i;
X#else /* SHAREDMEM */
X	FILE *fp_in;
X#endif /* SHAREDMEM */
X					/* open for append */
X	if (!(fp_out = my_fopen(param->dumpfile, "a"))) {
X		sprintf(buf, "'%s' for write", param->dumpfile);
X		error_win(0, "Can't open screen dump file", buf);
X		return;
X	}
X#ifdef SHAREDMEM
X	for (i=0; i<LINES; i++)
X		fprintf(fp_out, "%s\n", status->vs[i]);
X
X#else /* SHAREDMEM */
X					/* not guaranteed to exist yet */
X	if (!(fp_in = my_fopen(status->vs_path, "r"))) {
X		fclose(fp_in);
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#endif /* SHAREDMEM */
X	fclose(fp_out);
X
X	return;
X}
X
X/*
X * Read the virtual screen and paint its contents to the stdscr using
X * curses(3).  Move the cursor where it belongs.
X */
X
Xvoid
Xload_vs()
X{
X	register int i;
X#ifndef SHAREDMEM
X	FILE *fp, *my_fopen();
X	int row, col;
X	char buf[MAX_COL+2];
X#endif /* SHAREDMEM */
X
X	clearok(curscr, TRUE);
X	erase();
X#ifdef SHAREDMEM
X	for (i=0; i<LINES; i++)
X		mvaddstr(i, 0, status->vs[i]);
X
X	move(status->row, status->col);
X#else /* SHAREDMEM */
X					/* not guaranteed to exist yet */
X	if (!(fp = my_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	i = 0;
X	while (fgets(buf, MAX_COL+2, fp) != NULL) {
X					/* zap the line feed */
X		buf[COLS] = NULL;
X		mvaddstr(i++, 0, buf);
X	}
X	fclose(fp);
X	move(row, col);
X#endif /* SHAREDMEM */
X
X	refresh();
X	return;
X}
X
X/*
X * Zap the virtual screen file (or clear it)
X */
X
Xvoid
Xzap_vs()
X{
X#ifdef SHAREDMEM
X	status->clr = 1;
X#else /* SHAREDMEM */
X	unlink(status->vs_path);
X#endif /* SHAREDMEM */
X	return;
X}
SHAR_EOF
if test 2074 -ne "`wc -c < 'screen.c'`"
then
	echo shar: "error transmitting 'screen.c'" '(should have been 2074 characters)'
fi
fi
echo shar: "extracting 'st_line.c'" '(2103 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 "config.h"
X#include "dial_dir.h"
X#include "misc.h"
X#include "modem.h"
X#include "param.h"
X#include "status.h"
X
Xvoid
Xst_line(message)
Xchar *message;
X{
X	extern int xmc;
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
X					/* is anybody missing? */
X	if (dir == NULL || modem == NULL || param == NULL)
X		return;
X					/* remember where we parked the car.. */
X	getyx(stdscr, y, x);
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++;
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#ifdef XMC_BROKE
X	if (xmc > 0)
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	else
X#endif /* XMC_BROKE */
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 2103 -ne "`wc -c < 'st_line.c'`"
then
	echo shar: "error transmitting 'st_line.c'" '(should have been 2103 characters)'
fi
fi
echo shar: "extracting 'strings.c'" '(1329 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
X * memory first.
X */
X
Xchar *
Xstrdup(str)
Xchar *str;
X{
X	extern char *null_ptr;
X	char *ret, *malloc(), *strcpy();
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 && str != 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	extern char *null_ptr;
X	char *strchr();
X	static char *ptr, *sep;
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 1329 -ne "`wc -c < 'strings.c'`"
then
	echo shar: "error transmitting 'strings.c'" '(should have been 1329 characters)'
fi
fi
echo shar: "extracting 'terminal.c'" '(9686 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#include "config.h"
X#ifdef OLDCURSES
X#include <termio.h>
X#endif /* OLDCURSES */
X#ifdef UNIXPC
X#include <sys/phone.h>
X#include <fcntl.h>
X#endif /* UNIXPC */
X#include "dial_dir.h"
X#include "misc.h"
X#include "modem.h"
X#include "param.h"
X#include "status.h"
X
Xstatic int pid = -1;
X
Xterminal(input_status)
Xint input_status;
X{
X	extern int fd;
X	int i, k, cr_lf;
X	char c, lf=10, *strdup();
X	void help_screen(), line_set(), n_shell(), load_vs(), send_str();
X	void hang_up(), do_input(), list_dir(), pexit(), zap_vs();
X	void st_line(), chg_dir(), screen_dump(), input_off(), suspend();
X	void info(), term_mode();
X
X					/* if starting out in command mode */
X	if (!input_status)
X		st_line("");
X					/* put stdin/stdout in terminal mode */
X	resetterm();
X	term_mode();
X
X	if (input_status)
X		do_input();
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			suspend(1);
X
X			/*
X			 * Put in terminal in the curses mode, load the
X			 * virtual screen and add the status line at the bottom.
X			 */
X			fixterm();
X			load_vs();
X			st_line("");
X#ifndef OLDCURSES
X			keypad(stdscr, TRUE);
X#endif /* OLDCURSES */
X			i = wgetch(stdscr);
X					/* map an additional hot key to -1 */
X			if (i == param->hot)
X				i = -1;
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);
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())
X						input_status = dial_win();
X					break;
X				case 'm':
X				case 'M':	/* keyboard macros */
X					macro();
X					break;
X				case 'p':
X				case 'P':	/* line settings */
X					if (ls_menu())
X						line_set();
X					break;
X				case 'x':
X				case 'X':	/* exit */
X					pexit();
X					break;
X				case '4':	/* Unix gateway */
X					n_shell();
X					break;
X				case 'i':
X				case 'I':	/* Program info screen */
X					info(0);
X					break;
X				case 's':	/* setup menu */
X				case 'S':
X					input_status = setup_menu();
X					break;
X				case 'c':	/* clear the screen */
X				case 'C':
X					zap_vs();
X					erase();
X					break;
X				case 'b':
X				case 'B':	/* Change directory */
X					chg_dir();
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
X						/* show changes */
X					st_line("");
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#ifndef SHAREDMEM
X					if (pid != -1)
X						kill(pid, SIGUSR2);
X#endif /* SHAREDMEM */
X						/* show changes */
X					st_line("");
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						status->add_lf = 1;
X					}
X					else {
X						param->cr_in = strdup("CR");
X						status->add_lf = 0;
X					}
X#ifndef SHAREDMEM
X					input_off();
X					input_status++;
X#endif /* SHAREDMEM */
X						/* show changes */
X					st_line("");
X					k = wait_key(stdscr, 2);
X					break;
X				case '7':	/* break key */
X					if (fd != -1)
X						ioctl(fd, TCSBRK, 0);
X
X					st_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 't':
X				case 'T':
X					input_status = pass_thru();
X					break;
X				case 'f':
X				case 'F':	/* list directory */
X					list_dir();
X					break;
X				case 'g':	/* screen dump */
X				case 'G':
X					screen_dump();
X					st_line(" screen dump");
X					k = wait_key(stdscr, 2);
X					break;
X				case '1':	/* data logging */
X					input_status = data_logging();
X					break;
X				case '2':	/* toggle log */
X					if (!strcmp(status->log_path, "NOT_DEFINED")) {
X						beep();
X						st_line(" no log file");
X						k = wait_key(stdscr, 2);
X						break;
X					}
X					status->log = status->log ? 0 : 1;
X#ifndef SHAREDMEM
X					if (pid != -1)
X						kill(pid, SIGUSR1);
X#endif /* SHAREDMEM */
X						/* show changes */
X					st_line("");
X					k = wait_key(stdscr, 2);
X					break;
X				/*
X				 * The following are the keyboard macros
X				 * corresponding to the shifted number keys.
X				 * (Too many keys... [control] [A] [shift] [1]
X				 * is hardly a shortcut!)
X				 */
X				case '!':
X					send_str(param->mac_1);
X					break;
X				case '@':
X					send_str(param->mac_2);
X					break;
X				case '#':
X					send_str(param->mac_3);
X					break;
X				case '$':
X					send_str(param->mac_4);
X					break;
X				case '%':
X					send_str(param->mac_5);
X					break;
X				case '^':
X					send_str(param->mac_6);
X					break;
X				case '&':
X					send_str(param->mac_7);
X					break;
X				case '*':
X					send_str(param->mac_8);
X					break;
X				case '(':
X					send_str(param->mac_9);
X					break;
X				case ')':
X					send_str(param->mac_0);
X					break;
X				default:
X					fputc(BEL, stderr);
X					break;
X			}
X
X			/*
X			 * Repaint the stdscr (if we are already talking),
X			 * get the stdin/stdout out of the curses mode and
X			 * into the terminal mode.
X			 */
X			if (fd != -1) {
X				touchwin(stdscr);
X				refresh();
X			}
X			resetterm();
X			term_mode();
X
X			/*
X			 * Some of the output processing options have to be
X			 * faked...  Unfortunately, adding a LF to CR on
X			 * output is one of them.
X			 */
X			cr_lf = !strcmp(param->cr_out, "CR/LF");
X
X					/* re-start input routine */
X			if (input_status)
X				do_input();
X			else
X				suspend(0);
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					/* ignore errors if fd == -1 */
X		write(fd, &c, 1);
X					/* map cr to cr_lf? */
X		if (c == '\r' && cr_lf)
X			write(fd, &lf, 1);
X	}
X}
X
X/*
X * Put the stdin/stdout in terminal mode.  We've divided up the
X * responsibility for the line settings options between the serial port
X * and the stdin and stdout.
X */
X
Xvoid
Xterm_mode()
X{
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					/* 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;
X}
X
X/*
X * Fire up the input routine...
X */
X
Xstatic void
Xdo_input()
X{
X	extern int fd;
X	void error_win();
X	char first[(sizeof(int)*8)+1];
X#ifdef SHAREDMEM
X	extern int shm_id;
X#else /* SHAREDMEM */
X	char add_lf[2], log[2], print[2];
X#endif /* SHAREDMEM */
X					/* if no TTY, or already on */
X	if (pid != -1 || fd == -1)
X		return;
X
X	status->fd = fd;
X	if (!strcmp(param->cr_in, "CR/LF"))
X		status->add_lf = 1;
X	else
X		status->add_lf = 0;
X
X#ifdef SHAREDMEM
X	sprintf(first, "%d", shm_id);
X#else /* SHAREDMEM */
X	sprintf(first, "%d", status->fd);
X	sprintf(add_lf, "%d", status->add_lf);
X	sprintf(log, "%d", status->log);
X	sprintf(print, "%d", status->print);
X#endif /* SHAREDMEM */
X
X					/* fork the input routine */
X	if (!(pid = fork())) {
X#ifdef SETUGID
X		setuid(getuid());
X		setgid(getgid());
X#endif /* SETUGID */
X#ifdef SHAREDMEM
X		execlp("pcomm_input", "pcomm_input", first, (char *) 0);
X#else /* SHAREDMEM */
X		execlp("pcomm_input", "pcomm_input", first, add_lf, log,
X		 print, status->log_path, status->vs_path, (char *) 0);
X#endif /* SHAREDMEM */
X		error_win(1, "Cannot find (or execute) the 'pcomm_input' program", "");
X	}
X
X	return;
X}
X
X/*
X * shut it down...
X */
X
Xvoid
Xinput_off()
X{
X	if (pid != -1) {
X		kill(pid, SIGTERM);
X		pid = -1;
X	}
X	return;
X}
X
X/*
X * Hang up the phone but remain in the Pcomm command state.  Uses the
X * hang_up string only, does *not* drop the DTR!
X */
X
Xvoid
Xhang_up(verbose)
Xint verbose;
X{
X	extern int fd;
X	void send_str(), st_line(), line_set();
X#ifdef UNIXPC
X	char buf[40], *strcpy(), *ttyname();
X#endif /* UNIXPC */
X					/* sanity checking */
X	if (modem == NULL)
X		return;
X					/* anything to hang up? */
X	if (modem->m_cur == -1 || fd == -1)
X		return;
X
X	if (verbose)
X		st_line("disconnecting");
X					/* special case for OBM */
X#ifdef UNIXPC
X	if (!strcmp(modem->mname[modem->m_cur], "OBM")) {
X		ioctl(fd, PIOCDISC);
X		/*
X		 * The PIOCDISC ioctl screws up the file descriptor!!!
X		 * No other phone(7) ioctl can fix it.  Whatever it does,
X		 * it seems to escape detection with PIOCGETA and TCGETA.
X		 * The best I can do is close the port and start over.
X		 */
X		strcpy(buf, ttyname(fd));
X		close(fd);
X		fd = open(buf, O_RDWR|O_NDELAY);
X		fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NDELAY);
X		line_set();
X	}
X	else
X#endif /* UNIXPC */
X		send_str(modem->hang_up[modem->m_cur]);
X
X	if (verbose)
X		st_line("");
X	return;
X}
X
X/*
X * Suspend or un-suspend the input routine.  The argument is used in
X * non-shared memory configurations to give the vs_path file a fighting
X * chance of being written to disk before load_vs() reads it.
X */
X
X/*ARGSUSED*/
Xvoid
Xsuspend(on)
Xint on;
X{
X	unsigned int sleep();
X
X	if (pid == -1)
X		return;
X	kill(pid, SIGINT);
X#ifndef SHAREDMEM
X	if (on)
X		sleep(1);
X#endif /* SHAREDMEM */
X	return;
X}
SHAR_EOF
if test 9686 -ne "`wc -c < 'terminal.c'`"
then
	echo shar: "error transmitting 'terminal.c'" '(should have been 9686 characters)'
fi
fi
exit 0
#	End of shell archive

egray@killer.DALLAS.TX.US (Emmet Gray) (09/05/88)

This is part 7 (of 8) to the Pcomm v1.1 release package.

Emmet P. Gray				US Army, HQ III Corps & Fort Hood
..!uunet!uiucuxc!fthood!egray		Attn: AFZF-DE-ENV
					DEH, 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:
#	vcs.c
#	x_ascii.c
#	x_batch.c
#	x_extrnl.c
#	x_menu.c
#	x_rcv.c
# This archive created: Sat Sep  3 15:35:07 1988
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'vcs.c'" '(10169 characters)'
if test -f 'vcs.c'
then
	echo shar: "will not over-write existing file 'vcs.c'"
else
sed 's/^X//' << \SHAR_EOF > 'vcs.c'
X/*
X * Routines for VCS detection.
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include "config.h"
X#ifndef OLDCURSES
X#include <term.h>
X#endif /* OLDCURSES */
X#include "vcs.h"
X
Xstatic int putc_cnt;
Xstatic char putc_buf[VCS_SIZE];
X
X/*
X * Test for possible VCS (video command sequence).  A character return
X * code means no match.  An return code greater than 255 means a VCS
X * was found.
X */
X
Xint
Xvcs_filter(c)
Xchar c;
X{
X	extern int vcs_codes[NUM_VCS][VCS_SIZE], vcs_leadin[NUM_VCS];
X	extern int num_leadin;
X	static int buf[VCS_SIZE];
X	static int ptr = 0;
X	register int i;
X	int maybe, possible;
X
X					/* see if possible */
X	possible = 0;
X	if (ptr == 0) {
X					/* lead-in less than a space */
X		if (c >= ' ')
X			return(c & 0xff);
X					/* check the list */
X		for (i=0; i<num_leadin; i++) {
X			if (c == vcs_leadin[i]) {
X				possible++;
X				break;
X			}
X		}
X		if (!possible)
X			return(c & 0xff);
X	}
X
X					/* build the string */
X	buf[ptr++] = c;
X	buf[ptr] = -1;
X					/* test for match */
X	maybe = 0;
X	for (i=0; i<NUM_VCS; i++) {
X		switch (match_codes(buf, vcs_codes[i], i)) {
X			case YES:
X				ptr = 0;
X				return(i+256);
X			case NO:
X				break;
X			case MAYBE:
X				maybe++;
X				break;
X		}
X	}
X					/* abandon what you've got */
X	if (maybe && ptr == VCS_SIZE-1) {
X		ptr = 0;
X		return(c & 0xff);
X	}
X					/* hang on, wait and see */
X	if (maybe)
X		return(MAYBE);
X					/* a clean miss */
X	ptr = 0;
X	return(c & 0xff);
X}
X
X/*
X * See if the two integer arrays "match".  Character parameters are
X * designated by codes > 1000 and ASCII digit parameters are designated
X * by codes > 2000.  Uses a simple linear search, so if NUM_VCS grows
X * this routine will have to mature a bit.
X */
X
Xstatic int
Xmatch_codes(test, code, k)
Xint test[], code[], k;
X{
X	extern int vcs_param[NUM_VCS][5];
X	register int i, j;
X	int pos, done;
X					/* doesn't exist */
X	if (code[0] == -1)
X		return(NO);
X
X	i = 0;
X	j = 0;
X	while (i<VCS_SIZE && j<VCS_SIZE) {
X					/* at the end (a match) */
X		if (test[i] == -1 && code[j] == -1)
X			return(YES);
X					/* ran out of input */
X		if (test[i] == -1)
X			break;
X		/*
X		 * The char parameter (code 1000) always matches the
X		 * character.
X		 */
X		if (code[j] >= 1000 && code[j] < 2000) {
X			pos = code[j] -1000;
X			vcs_param[k][pos] = test[i];
X			i++;
X			j++;
X			continue;
X		}
X		/*
X		 * The digit parameter (code 2000) tries to match as many
X		 * ASCII digits as it can.
X		 */
X		if (code[j] >= 2000) {
X			pos = code[j] -2000;
X					/* done with this number? */
X			if (vcs_param[k][pos])
X				done = 1;
X			else
X				done = 0;
X					/* only digits */
X			while (test[i] >= 48 && test[i] <= 57) {
X				if (!done)
X					vcs_param[k][pos] = (vcs_param[k][pos] * 10) + test[i] -48;
X				i++;
X			}
X					/* ended in a digit */
X			if (test[i] == -1 && code[j+1] != -1) {
X				vcs_param[k][pos] = 0;
X				break;
X			}
X			j++;
X			continue;
X		}
X					/* a clean miss */
X		if (test[i] != code[j]) {
X			for (j=0; j<5; j++)
X				vcs_param[k][j] = 0;
X			return(NO);
X		}
X		i++;
X		j++;
X	}
X					/* a maybe */
X	return(MAYBE);
X}
X
X/*
X * Build the table of VCS codes.  Actually we cheat... We tell curses(3)
X * to build the strings to perform the function, and then we decipher
X * what it did.
X */
X
Xvoid
Xvcs_table()
X{
X	extern int vcs_codes[NUM_VCS][VCS_SIZE], vcs_opt[NUM_VCS][10];
X	extern int vcs_leadin[NUM_VCS], num_leadin, max_row, max_col;
X	int i, j, k, match, temp[VCS_SIZE];
X	char *p, *strcpy(), buf[VCS_SIZE], *getenv(), *tparm();
X	void fake_it();
X
X#ifdef OLDCURSES
X	char tcbuf[1024], tb[1024], *t, *cursor_home, *clr_eol, *clr_eos;
X	char *clear_screen, *cursor_up, *cursor_down, *cursor_right;
X	char *cursor_left, *cursor_address, *getenv(), *tgetstr(), *tgoto();
X
X	tgetent(tb, getenv("TERM"));
X	t = tcbuf;
X
X	cursor_home = tgetstr("ho", &t);
X	clr_eol = tgetstr("ce", &t);
X	clr_eos = tgetstr("cd", &t);
X	clear_screen = tgetstr("cl", &t);
X	cursor_up = tgetstr("up", &t);
X	cursor_down = tgetstr("do", &t);
X	cursor_right = tgetstr("nd", &t);
X	cursor_left = tgetstr("le", &t);
X	cursor_address = tgetstr("cm", &t);
X	max_row = tgetnum("li");
X	max_col = tgetnum("co");
X#else /* OLDCURSES */
X	setupterm(getenv("TERM"), 1, &i);
X	max_row = lines;
X	max_col = columns;
X#endif /* OLDCURSES */
X
X	/*
X	 * Do the easy ones first.  These don't take positional parameters,
X	 * so all we have to do is strip the padding info.
X	 */
X	for (i=0; i<NUM_VCS; i++) {
X		switch (i) {
X			case HOME:
X				p = cursor_home;
X				break;
X			case CLR_EOL:
X				p = clr_eol;
X				break;
X			case CLR_EOS:
X				p = clr_eos;
X				break;
X			case CLEAR:
X				p = clear_screen;
X				break;
X			case MV_UP:
X				p = cursor_up;
X				break;
X			case MV_DOWN:
X				p = cursor_down;
X				break;
X			case MV_RIGHT:
X				p = cursor_right;
X				break;
X			case MV_LEFT:
X				p = cursor_left;
X				break;
X			default:
X				p = "";
X				break;
X		}
X		/*
X		 * Either the capability doesn't exist, or we're gonna
X		 * do this one by hand (i.e.: ones with positional parameters)
X		 */
X		if (!p) {
X			vcs_codes[i][0] = -1;
X			continue;
X		}
X					/* fake an "output" */
X		fake_it(p);
X					/* copy what it did */
X		j = 0;
X		while (putc_buf[j]) {
X			vcs_codes[i][j] = putc_buf[j];
X			j++;
X			if (j == VCS_SIZE-1)
X				break;
X		}
X		vcs_codes[i][j] = -1;
X	}
X
X	/*
X	 * And now for the difficult ones.  The way it's done is: load the
X	 * string with a few known parameters and then find where the
X	 * parameters end up.  The vcs_opt[][] array is "free-flowing"
X	 * and means something only to the routine being used.
X	 */
X					/* add one to the param */
X	if (substr(cursor_address, "%i") > 0)
X		vcs_opt[MV_DIRECT][0] = 1;
X					/* decimal codes used */
X	if (substr(cursor_address, "%d") > 0)
X		vcs_opt[MV_DIRECT][1] = 1;
X					/* character codes used */
X	if (substr(cursor_address, "%c") > 0)
X		vcs_opt[MV_DIRECT][2] = 1;
X					/* add an offset */
X	if (substr(cursor_address, "%+") > 0)
X		vcs_opt[MV_DIRECT][3] = 1;
X					/* subtract an offset */
X	if (substr(cursor_address, "%-") > 0)
X		vcs_opt[MV_DIRECT][4] = 1;
X					/* load with parameters 12 & 34 */
X#ifdef OLDCURSES
X	fake_it(tgoto(cursor_address, 12, 34));
X#else /* OLDCURSES */
X	fake_it(tparm(cursor_address, 12, 34));
X#endif /* OLDCURSES */
X	j = 0;
X	while (putc_buf[j]) {
X		temp[j] = putc_buf[j];
X		j++;
X		if (j == VCS_SIZE-1)
X			break;
X	}
X	temp[j] = -1;
X					/* if decimal parameters */
X	if (vcs_opt[MV_DIRECT][1]) {
X					/* if add one */
X		if (vcs_opt[MV_DIRECT][0])
X			sprintf(buf, "13");
X		else
X			sprintf(buf, "12");
X					/* where is the 12 (or 13)? */
X		if ((i = substr(putc_buf, buf)) > 0) {
X			temp[i] = 2000;
X			temp[i+1] = -2;
X		}
X		else
X			temp[0] = -1;
X					/* if add one */
X		if (vcs_opt[MV_DIRECT][0])
X			sprintf(buf, "35");
X		else
X			sprintf(buf, "34");
X					/* where is the 34 (or 35)? */
X		if ((i = substr(putc_buf, buf)) > 0) {
X			temp[i] = 2001;
X			temp[i+1] = -2;
X		}
X		else
X			temp[0] = -1;
X	}
X					/* if character parameters */
X	if (vcs_opt[MV_DIRECT][2]) {
X					/* original with 12 and 34 */
X		strcpy(buf, putc_buf);
X					/* change 12 to 13 */
X#ifdef OLDCURSES
X		fake_it(tgoto(cursor_address, 13, 34));
X#else /* OLDCURSES */
X		fake_it(tparm(cursor_address, 13, 34));
X#endif /* OLDCURSES */
X					/* where are they different */
X		i = 0;
X		while (buf[i] != NULL) {
X			if (buf[i] != putc_buf[i])
X				break;
X			i++;
X		}
X					/* sanity checking */
X		if (buf[i] == NULL)
X			temp[0] = -1;
X					/* if add, what is offset? */
X		if (vcs_opt[MV_DIRECT][3])
X			vcs_opt[MV_DIRECT][5] = temp[i] - 13;
X
X					/* if subtract, what is offset? */
X		if (vcs_opt[MV_DIRECT][4])
X			vcs_opt[MV_DIRECT][5] = 13 - temp[i];
X
X		temp[i] = 1000;
X					/* change 34 to 35 */
X#ifdef OLDCURSES
X		fake_it(tgoto(cursor_address, 12, 35));
X#else /* OLDCURSES */
X		fake_it(tparm(cursor_address, 12, 35));
X#endif /* OLDCURSES */
X					/* where are they different */
X		i = 0;
X		while (buf[i] != NULL) {
X			if (buf[i] != putc_buf[i])
X				break;
X			i++;
X		}
X		temp[i] = 1001;
X		if (buf[i] == NULL)
X			temp[0] = -1;
X	}
X					/* strip the -2's out, if any */
X	i = 0;
X	j = 0;
X	while (temp[i] != -1) {
X		if (temp[i] != -2)
X			vcs_codes[MV_DIRECT][j++] = temp[i];
X		i++;
X	}
X	vcs_codes[MV_DIRECT][j] = -1;
X
X	/*
X	 * Simplify the list.  Some codes are already handled by the
X	 * virtual screen routines... no need to duplicate them.
X	 */
X	if (vcs_codes[MV_DOWN][0] == '\n')
X		vcs_codes[MV_DOWN][0] = -1;
X
X	if (vcs_codes[MV_LEFT][0] == 8)
X		vcs_codes[MV_LEFT][0] = -1;
X
X	/*
X	 * Often the "clear screen" sequence will contain the "home"
X	 * sequence... if so, don't duplicate the "home" portion.
X	 */
X	fake_it(cursor_home);
X	strcpy(buf, putc_buf);
X
X	fake_it(clear_screen);
X					/* if "home" inside "clear screen" */
X	if ((k = substr(putc_buf, buf)) >= 0) {
X					/* if at the beginning */
X		if (k == 0) {
X			i = 0;
X			for (j=strlen(buf); j<VCS_SIZE; j++)
X				vcs_codes[CLEAR][i++] = putc_buf[j];
X			vcs_codes[CLEAR][i] = -1;
X		}
X					/* if at the end */
X		else if (strlen(buf)+k == strlen(putc_buf))
X			vcs_codes[CLEAR][k] = -1;
X	}
X					/* is "clear screen" still unique */
X	k = 0;
X	for (i=0; i<NUM_VCS; i++) {
X		if (vcs_codes[CLEAR][i] == -1 || vcs_codes[CLR_EOS][i] == -1)
X			break;
X		if (vcs_codes[CLEAR][i] != vcs_codes[CLR_EOS][i]) {
X			k++;
X			break;
X		}
X	}
X	if (k == 0)
X		vcs_codes[CLEAR][0] = -1;
X
X	/*
X	 * Make a list of unique lead-in characters to be used as a
X	 * simple hash table.
X	 */
X	num_leadin = 0;
X	for (i=0; i<NUM_VCS; i++) {
X		if (vcs_codes[i][0] == -1)
X			continue;
X					/* add any new lead-in character */
X		match = 0;
X		for (j=0; j<num_leadin; j++) {
X			if (vcs_leadin[j] == vcs_codes[i][0])
X				match++;
X		}
X		if (!match)
X			vcs_leadin[num_leadin++] = vcs_codes[i][0];
X	}
X	return;
X}
X
X/*
X * The routines that fakes curses(3) into outputing the string info with
X * the padding removed.
X */
Xstatic void
Xfake_it(s)
Xchar *s;
X{
X	int fake_putc();
X
X	putc_cnt = 0;
X	putc_buf[0] = NULL;
X	tputs(s, 1, fake_putc);
X	putc_buf[putc_cnt] = NULL;
X	return;
X}
Xstatic int
Xfake_putc(c)
Xchar c;
X{
X	putc_buf[putc_cnt++] = c;
X	return(c);
X}
X
X/*
X * Is string2 contained in string1?  If so, return the offset otherwise
X * return a -1.
X */
X
Xstatic int
Xsubstr(s1, s2)
Xchar *s1, *s2;
X{
X	int i, len;
X
X	len = strlen(s2);
X					/* not possible */
X	if (len > strlen(s1))
X		return(-1);
X
X	i = 0;
X	while (*s1) {
X		if (!strncmp(s1, s2, len))
X			return(i);
X		s1++;
X		i++;
X	}
X	return(-1);
X}
SHAR_EOF
if test 10169 -ne "`wc -c < 'vcs.c'`"
then
	echo shar: "error transmitting 'vcs.c'" '(should have been 10169 characters)'
fi
fi
echo shar: "extracting 'x_ascii.c'" '(7019 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#define CLIST	64
X
X#include <stdio.h>
X#include <fcntl.h>
X#include <curses.h>
X#include <signal.h>
X#include "config.h"
X#include "misc.h"
X#include "param.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(), st_line(), suspend();
X	void load_vs(), ascii_mode();
X	unsigned int sleep();
X
X	touchwin(stdscr);
X	refresh();
X					/* only one file from list */
X	file = strtok(list, " 	");
X
X	cr_lf = !strcmp(param->cr_out, "CR/LF");
X	ascii_mode(up);
X	if (up) {
X					/* un-suspend the input routine */
X		suspend(0);
X
X		send_ascii(file, cr_lf);
X					/* re-suspend the input routine */
X		suspend(1);
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	line_set();
X	fixterm();
X
X	/*
X	 * On downloading, the contents of the virtual screen won't contain
X	 * the characters shown during the transfer.  Too bad...
X	 */
X	load_vs();
X	beep();
X	st_line("xfer complete");
X
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.
X */
X
Xstatic void
Xascii_mode(up)
Xint up;
X{
X	extern int fd;
X	struct termio tbuf;
X	void input_off(), term_mode();
X
X	ioctl(fd, TCGETA, &tbuf);
X	tbuf.c_oflag = 0;
X					/* flow control & 8th bit stripping */
X	if (up) {
X		tbuf.c_iflag = (ISTRIP|IXON);
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(fd, TCSETA, &tbuf);
X	ioctl(fd, TCFLSH, 2);
X					/* out of curses mode */
X	resetterm();
X	term_mode();
X					/* non-blocking mode */
X	fcntl(0, F_SETFL, fcntl(0, F_GETFL, 0) | O_NDELAY);
X	return;
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
Xstatic void
Xsend_ascii(file, cr_lf)
Xchar *file;
Xint cr_lf;
X{
X	extern int fd;
X	FILE *fp;
X	int i, j, strip_cr, strip_lf, add_cr, add_lf, expand, lecho, pace;
X	unsigned char c, last;
X	unsigned int sleep();
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 ESC:	/* <ESC> key for abort */
X				fclose(fp);
X				sleep(2);
X				ioctl(fd, TCSBRK, 1);
X				return;
X			default:	/* send the char */
X				c = j & 0xff;
X				putc_line(c);
X				if (c == '\r' && cr_lf)
X					putc_line('\n');
X				break;
X		}
X		c = i & 0xff;
X					/* expand blank lines */
X		if (expand && last == '\n' && c == '\n')
X			putc_line(' ');
X		last = c;
X
X					/* CR translations */
X		if (c == '\r' && strip_cr)
X			continue;
X		if (c == '\r' && add_lf) {
X			putc_line(c);
X			putc_line('\n');
X			continue;
X		}
X					/* LF translations */
X		if (c == '\n' && strip_lf)
X			continue;
X		if (c == '\n' && add_cr) {
X			putc_line('\r');
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(fd, TCSBRK, 1);
X		if (lecho) {
X			putchar((char) c);
X			fflush(stdout);
X		}
X	}
X	fclose(fp);
X	sleep(2);
X	ioctl(fd, TCSBRK, 1);
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 bgetc_line()
X * and non-blocking input makes it seem like full duplex, but it's not.
X * Be aware that while the timer is active the keyboard is deaf.  Input is
X * NOT loaded into the virtual screen!!
X */
X
Xstatic void
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	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 ESC:	/* <ESC> key */
X				fclose(fp);
X				return;
X			default:	/* send it */
X				c = i & 0xff;
X				putc_line((unsigned char) c);
X				if (c == '\r' && cr_lf)
X					putc_line('\n');
X				break;
X		}
X					/* read a character */
X		if ((i = bgetc_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 & 0xff;
X					/* display it on the screen */
X		putchar(c);
X		fflush(stdout);
X					/* CR translations */
X		if (c == '\r' && strip_cr)
X			continue;
X		if (c == '\r' && add_lf) {
X			fputc(c, fp);
X			fputc('\n', fp);
X			continue;
X		}
X					/* LF translations */
X		if (c == '\n' && strip_lf)
X			continue;
X		if (c == '\n' && add_cr) {
X			fputc('\r', fp);
X			fputc(c, fp);
X			continue;
X		}
X		fputc(c, fp);
X	}
X}
X
X/*
X * Get a character from the line (using buffered I/O) with a specified
X * time-out period in seconds.  If the function times-out, it returns a -1.
X */
X
Xstatic int bl_flag;
X
Xstatic int
Xbgetc_line(sec)
Xunsigned int sec;
X{
X	int bl_force();
X	char c;
X	unsigned int alarm();
X
X	signal(SIGALRM, bl_force);
X	bl_flag = 0;
X
X	alarm(sec);
X	if ((int) (c = buf_read()) < 0) {
X		alarm(0);
X		return(-1);
X	}
X	if (bl_flag)
X		return(-1);
X	alarm(0);
X	return(c & 0xff);
X}
X/*ARGSUSED*/
Xstatic int
Xbl_force(dummy)
Xint dummy;
X{
X	bl_flag = 1;
X}
X
X/*
X * Do a single character buffered read from the serial port.
X */
X
Xstatic int
Xbuf_read()
X{
X	extern int fd;
X	static char buf[CLIST];
X	static char *bufp = buf;
X	static int n = 0;
X
X	if (n <= 0) {
X		if ((n = read(fd, buf, CLIST)) <= 0)
X			return(-1);
X		bufp = buf;
X	}
X	while (--n >= 0)
X		return(*bufp++ & 0xff);
X	return(-1);
X}
SHAR_EOF
if test 7019 -ne "`wc -c < 'x_ascii.c'`"
then
	echo shar: "error transmitting 'x_ascii.c'" '(should have been 7019 characters)'
fi
fi
echo shar: "extracting 'x_batch.c'" '(8478 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 "config.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 -1:	/* timed out */
X				clear_line(win, 12, 24, 1);
X				waddstr(win, "NO RESPONSE");
X				wrefresh(win);
X				return(ERROR);
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 modem7 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	extern char file_name[15];
X	int i, j, err_method, err_count, got_it;
X	unsigned char sum, calc_sum();
X	char temp_name[13];
X	void change_name(), unfix_name();
X
X	err_method = default_err;
X	if (default_err == CRC_CHECKSUM)
X		err_method = CRC;
X
X	err_count = 0;
X	got_it = 0;
X	while (err_count < MAX_ERRORS) {
X					/* switch to checksum? */
X		if (default_err == CRC_CHECKSUM && err_count > MAX_ERRORS/2)
X			err_method = CHECKSUM;
X
X		if (err_method == CRC)
X			putc_line('C');
X		else
X			putc_line(NAK);
X					/* what'd we get? */
X		switch (getc_line(10)) {
X			case -1:	/* timed out */
X				clear_line(win, 12, 24, 1);
X				wattrstr(win, A_BOLD, "NO RESPONSE");
X				wrefresh(win);
X				err_count++;
X			case ACK:	/* ready to go... */
X				got_it++;
X				break;
X			default:	/* huh? */
X				clear_line(win, 12, 24, 1);
X				wattrstr(win, A_BOLD, "BAD HEADER");
X				wrefresh(win);
X				err_count++;
X		}
X	}
X	if (!got_it)
X		return(ERROR);
X					/* get the name */
X	for (i=0; i<12; i++) {
X		j = getc_line(3);
X
X		switch (j) {
X			case -1:	/* timed out */
X				clear_line(win, 12, 24, 1);
X				wattrstr(win, A_BOLD, "NO RESPONSE");
X				wrefresh(win);
X				return(ERROR);
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] = j & 0xff;
X				if (j != 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;
Xlong size;
X{
X	register int i;
X	unsigned short crc, calc_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], "%ld", 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	extern unsigned char buf[1029];
X	extern long file_length;
X	extern char file_name[15];
X	int code, length_is_at;
X	long atol();
X
X	file_length = 0L;
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	 * atol() will see a NULL and return 0.
X	 */
X	length_is_at = strlen((char *) &buf[3]) + 4;
X	file_length = atol((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	extern char file_name[15];
X	register int i;
X	int modified;
X	char temp[15], ans[15], *s, *strrchr(), *strcpy(), *strncat();
X	unsigned int sleep();
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++;
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	extern char file_name[15];
X	register int i, n;
X	int dot;
X	char temp[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 8478 -ne "`wc -c < 'x_batch.c'`"
then
	echo shar: "error transmitting 'x_batch.c'" '(should have been 8478 characters)'
fi
fi
echo shar: "extracting 'x_extrnl.c'" '(1569 characters)'
if test -f 'x_extrnl.c'
then
	echo shar: "will not over-write existing file 'x_extrnl.c'"
else
sed 's/^X//' << \SHAR_EOF > 'x_extrnl.c'
X/*
X * Spawn a shell with the stdin and stdout swapped with the remote
X * system.  An undocumented feature:  The external protocol gateway
X * can be used to pipe the output of a normal Unix command to the
X * remote system.
X */
X
X#include <stdio.h>
X#include <signal.h>
X#include <curses.h>
X#include <fcntl.h>
X#include "config.h"
X
Xvoid
Xextrnl(cmd)
Xchar *cmd;
X{
X	extern int fd;
X	WINDOW *xt_win, *newwin();
X	int (*istat)(), (*qstat)(), status, epid, w;
X	char *shell, *shellpath, *getenv(), *strrchr(), buf[40], *ttyname();
X	char *strcpy();
X	unsigned int sleep();
X	void _exit(), input_off();
X
X	input_off();
X					/* a full window */
X	xt_win = newwin(LINES, COLS, 0, 0);
X	touchwin(xt_win);
X	wrefresh(xt_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 (!(epid = fork())) {
X						/* recreate the device name */
X		strcpy(buf, ttyname(fd));
X		close(fd);
X						/* swap the stdin */
X		close(0);
X		open(buf, O_RDONLY);
X						/* swap the stdout */
X		close(1);
X		open(buf, O_WRONLY);
X#ifdef SETUGID
X		setgid(getgid());
X		setuid(getuid());
X#endif /* SETUGID */
X		execl(shellpath, shell, "-c", cmd, (char *) 0);
X		_exit(1);
X	}
X	istat = signal(SIGINT, SIG_IGN);
X	qstat = signal(SIGQUIT, SIG_IGN);
X
X	while ((w = wait(&status)) != epid && w != -1)
X		;
X
X	signal(SIGINT, istat);
X	signal(SIGQUIT, qstat);
X					/* back to curses mode */
X	sleep(1);
X	fixterm();
X
X	clearok(curscr, TRUE);
X	werase(xt_win);
X	wrefresh(xt_win);
X	delwin(xt_win);
X	return;
X}
SHAR_EOF
if test 1569 -ne "`wc -c < 'x_extrnl.c'`"
then
	echo shar: "error transmitting 'x_extrnl.c'" '(should have been 1569 characters)'
fi
fi
echo shar: "extracting 'x_menu.c'" '(5812 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 <sys/types.h>
X#include <sys/stat.h>
X#include <curses.h>
X#include "config.h"
X#include "misc.h"
X#include "xmodem.h"
X
Xint
Xxfer_menu(up)
Xint up;
X{
X	extern int fd;
X	extern char *null_ptr;
X	WINDOW *xm_win, *newwin();
X	char *list, *get_names(), *get_extrnl();
X	int type, is_batch;
X	void xfer_win(), xfer_ascii(), free_ptr(), extrnl(), error_win();
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, 8, 3, "7) (external)");
X	mvwaddstr(xm_win, 11, 3, "<ESC> to Abort");
X	mvwaddstr(xm_win, 13, 3, "Protocol:");
X	box(xm_win, VERT, HORZ);
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, (chtype) ' ');
X		wmove(xm_win, 13, 13);
X		wrefresh(xm_win);
X	}
X	type--;
X	werase(xm_win);
X	wrefresh(xm_win);
X	delwin(xm_win);
X					/* chickened out */
X	if (type < 0)
X		return(0);
X
X	if (fd == -1) {
X		error_win(0, "Not currently connected to any host", "");
X		return(0);
X	}
X					/* is the external protocol? */
X	if (type == EXTRNL) {
X					/* get the command line */
X		if (!(list = get_extrnl(up)))
X			return(0);
X		extrnl(list);
X		return(1);
X	}
X					/* is a batch protocol? */
X	is_batch = 0;
X	switch (type) {
X		case MODEM7:
X		case YMODEM:
X		case YMODEM_G:
X			is_batch++;
X			break;
X		default:
X			break;
X	}
X
X	/*
X	 * When receiving files in one of the batch modes, there is no
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
Xchar *protocol[PROTOCOLS] = {"xmodem", "xmodem-1k", "modem7", "ymodem",
X	"ymodem-g", "ASCII", "(external)"};
X
X/*
X * Prompt for a list of files for the transfer programs.  A NULL return
X * code means you chickened out.
X */
X
Xstatic char *
Xget_names(up, type, is_batch)
Xint up, type, is_batch;
X{
X	int can;
X	WINDOW *gn_win, *newwin();
X	char *list, *ans, *file, buf[40], *expand(), *get_str(), *strtok();
X	void st_line();
X	struct stat stbuf;
X
X	touchwin(stdscr);
X	refresh();
X	st_line("");
X
X	gn_win = newwin(7, 70, 5, 5);
X	mvwaddstr(gn_win, 3, 4, "Enter filename: ");
X	box(gn_win, VERT, HORZ);
X	if (up)
X		sprintf(buf, " Send %s ", protocol[type]);
X	else
X		sprintf(buf, " Receive %s ", protocol[type]);
X	mvwattrstr(gn_win, 0, 3, A_BOLD, buf);
X
X	while (1) {
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, "", "");
X		else
X			ans = get_str(gn_win, 60, "", " 	");
X
X		if (ans == NULL || *ans == NULL) {
X			list = NULL;
X			break;
X		}
X		list = expand(ans);
X
X		if (is_batch)
X			break;
X		/*
X		 * Here we have the opportunity to determine the read and
X		 * write permissions before things get started.  Much nicer
X		 * than finding out later when there's no way to fix it.
X		 */
X		file = strtok(list, " 	");
X					/* sanity checking */
X		if (!stat(file, &stbuf)) {
X			if ((stbuf.st_mode & S_IFREG) != S_IFREG) {
X				beep();
X				clear_line(gn_win, 4, 15, 1);
X				mvwattrstr(gn_win, 4, 15, A_BOLD, "Not a regular file");
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				continue;
X			}
X		}
X					/* check read permission */
X		if (up) {
X			if (access(file, 0)) {
X				beep();
X				mvwattrstr(gn_win, 4, 15, A_BOLD, "Can't find file");
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				continue;
X			}
X			if (access(file, 4)) {
X				beep();
X				mvwattrstr(gn_win, 4, 15, A_BOLD, "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				continue;
X			}
X			break;
X		}
X					/* check write permission */
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			continue;
X		}
X		if (can == 2) {
X			if (!yes_prompt(gn_win, 4, 15, A_BOLD, "File exists, overwrite")) {
X				clear_line(gn_win, 4, 15, 1);
X				clear_line(gn_win, 3, 20, 1);
X				continue;
X			}
X			break;
X		}
X		break;
X	}
X	werase(gn_win);
X	wrefresh(gn_win);
X	delwin(gn_win);
X
X	return(list);
X}
X
X/*
X * Prompt for the Unix command line to be used as an external file
X * transfer program.  A return code of NULL means forget it.
X */
X
Xstatic char *
Xget_extrnl(up)
Xint up;
X{
X	WINDOW *ge_win, *newwin();
X	char *cmd, *ans, *get_str(), *expand();
X	void st_line();
X
X	touchwin(stdscr);
X	refresh();
X	st_line("");
X					/* prompt for command line */
X	ge_win = newwin(7, 70, 5, 5);
X	mvwaddstr(ge_win, 3, 4, "Enter Unix command: ");
X	box(ge_win, VERT, HORZ);
X	if (up)
X		mvwattrstr(ge_win, 0, 3, A_BOLD, " Send (external) ");
X	else
X		mvwattrstr(ge_win, 0, 3, A_BOLD, " Receive (external) ");
X	wmove(ge_win, 3, 24);
X	wrefresh(ge_win);
X					/* get the line */
X	ans = get_str(ge_win, 60, "", "");
X	cmd = expand(ans);
X	if (*cmd == NULL)
X		cmd = NULL;
X
X	werase(ge_win);
X	wrefresh(ge_win);
X	delwin(ge_win);
X	return(cmd);
X}
SHAR_EOF
if test 5812 -ne "`wc -c < 'x_menu.c'`"
then
	echo shar: "error transmitting 'x_menu.c'" '(should have been 5812 characters)'
fi
fi
echo shar: "extracting 'x_rcv.c'" '(11805 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 (a user generated abort returns a 0).  Write errors
X * are considered fatal.
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include "config.h"
X#include "dial_dir.h"
X#include "misc.h"
X#include "xmodem.h"
X
Xunsigned char buf[1029];
Xchar file_name[15];
Xlong file_length;
X
Xstatic int err_method, tot_err, block_size;
X
Xint
Xrcv_xmodem(win, list, type, fast)
XWINDOW *win;
Xchar *list;
Xint type, fast;
X{
X	extern char *protocol[];
X	FILE *fp, *my_fopen();
X	int i, default_err, is_batch, max_block, code, file_count, got_hdr;
X	int hours, mins, secs, len;
X	long block, recv;
X	float percent, performance;
X	unsigned char blk;
X	unsigned int sleep();
X	char *file, *name, *strcpy(), *strrchr(), *strtok();
X	void cancel_xfer();
X					/* which protocol? */
X	switch (type) {
X		case XMODEM:
X			default_err = CRC_CHECKSUM;
X			is_batch = 0;
X			max_block = 128;
X			break;
X		case XMODEM_1k:
X			default_err = CRC_CHECKSUM;
X			is_batch = 0;
X			max_block = 1024;
X			break;
X		case MODEM7:
X			default_err = CHECKSUM;
X			is_batch = 1;
X			max_block = 128;
X			break;
X		case YMODEM:
X			default_err = CRC;
X			is_batch = 1;
X			max_block = 1024;
X			performance = 1.09;
X			break;
X		case YMODEM_G:
X			default_err = NONE;
X			is_batch = 1;
X			max_block = 1024;
X			performance = 1.02;
X			break;
X		default:
X			return(1);
X	}
X
X	tot_err = 0;
X	file_count = 0;
X	mvwaddstr(win, 2, 24, protocol[type]);
X	mvwaddstr(win, 11, 24, "0  ");
X
X	while (1) {
X		file_count++;
X		file_length = 0L;
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 != 0L) {
X			mvwprintw(win, 4, 24, "%-10ld", 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 != 0L && 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 modem7
X		 * or ymodem supplied name, the name is unique and the write
X		 * permission on the directory is checked by the change_name()
X		 * routines.  So why is this here?
X		 */
X					/* open the file */
X		if (!(fp = my_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(1);
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			return(code +1);
X		}
X					/* here we go... */
X		clear_line(win, 12, 24, 1);
X		waddstr(win, "NONE");
X		wrefresh(win);
X		blk = 1;
X		block = 1L;
X		recv = 0L;
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				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				if (file_length != 0L) {
X					len = file_length - recv;
X					if (len > block_size)
X						len = block_size;
X				}
X				else
X					len = block_size;
X
X				if (fwrite((char *) &buf[3], sizeof(char), len, fp) != len) {
X					beep();
X					clear_line(win, 12, 24, 1);
X					wattrstr(win, A_BOLD, "WRITE ERROR");
X					wrefresh(win);
X					cancel_xfer(1);
X					fclose(fp);
X					/* fatal */
X					return(1);
X				}
X				mvwprintw(win, 7, 24, "%-5ld", block);
X				recv = recv + (unsigned int) len;
X				if (fast)
X					mvwprintw(win, 9, 24, "%-10ld", recv);
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 != 0L && 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 != 0L && fast) {
X			mvwaddstr(win, 8, 24, "100%  ");
X			wrefresh(win);
X		}
X		/*
X		 * If the file length is not known, search backwards from
X		 * the end of the file until you find a character that is
X		 * not the ^Z padding character.
X		 */
X		if (file_length == 0L) {
X			for (i=block_size+2; i>2; i--) {
X				if (buf[i] != CTRLZ)
X					break;
X			}
X			file_length = recv - (unsigned int) block_size + (unsigned int) i -2L;
X			fclose(fp);
X			if (fix_length(file_name, file_length)) {
X				beep();
X				clear_line(win, 12, 24, 1);
X				wattrstr(win, A_BOLD, "TRUNCATE ERROR");
X				wrefresh(win);
X					/* fatal */
X				return(1);
X			}
X		}
X		else
X			fclose(fp);
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
Xstatic int
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	void cancel_xfer();
X					/* default error method */
X	err_method = default_err;
X	if (default_err == CRC_CHECKSUM)
X		err_method = CRC;
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) == ESC) {
X			beep();
X			clear_line(win, 12, 24, 1);
X			waddstr(win, "ABORTED");
X			wrefresh(win);
X			cancel_xfer(1);
X			sleep(3);
X			return(ABORT);
X		}
X					/* switch to checksum? */
X		if (default_err == CRC_CHECKSUM && err_count > MAX_ERRORS/2)
X			err_method = CHECKSUM;
X
X					/* send error method code */
X		clear_line(win, 5, 24, 1);
X		switch (err_method) {
X			case CHECKSUM:
X				waddstr(win, "CHECKSUM");
X				putc_line(NAK);
X				break;
X			case CRC:
X				waddstr(win, "CRC");
X				putc_line('C');
X				break;
X			case NONE:
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#ifdef DEBUG
X		fprintf(stderr, "send_first: got header %02x, %03o, %d\n", buf[0], buf[0], buf[0]);
X#endif /* DEBUG */
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;
X	unsigned short crc, calc_crc();
X	unsigned int packet, sleep();
X	unsigned char calc_sum(), crc_1, crc_2;
X	void cancel_xfer();
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) == ESC) {
X			beep();
X			clear_line(win, 12, 24, 1);
X			waddstr(win, "ABORTED");
X			wrefresh(win);
X			cancel_xfer(1);
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#ifdef DEBUG
X			fprintf(stderr, "rcv_block: got header %02x, %03o, %d\n", buf[0], buf[0], buf[0]);
X#endif /* DEBUG */
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 == CHECKSUM ? 1 : 2);
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 CHECKSUM:
X#ifdef DEBUG
X				fprintf(stderr, "blk=%d, checksum=%d\n", blk, calc_sum(&buf[3], block_size));
X#endif /* DEBUG */
X				if (buf[block_size +3] != calc_sum(&buf[3], block_size))
X					bad_block++;
X				break;
X			case CRC:
X				crc = calc_crc(&buf[3], block_size);
X				crc_1 = crc >> 8;
X				crc_2 = crc;
X#ifdef DEBUG
X				fprintf(stderr, "blk=%d, crc1=%d, crc2=%d\n", blk, crc_1, crc_2);
X#endif /* DEBUG */
X				if (buf[block_size +3] != crc_1 || buf[block_size +4] != crc_2)
X					bad_block++;
X				break;
X			case NONE:
X				return(0);
X		}
X					/* handle errors */
X		if (bad_block) {
X			clear_line(win, 12, 24, 1);
X			if (err_method == CRC)
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	cancel_xfer(1);
X	return(ERROR);
X}
SHAR_EOF
if test 11805 -ne "`wc -c < 'x_rcv.c'`"
then
	echo shar: "error transmitting 'x_rcv.c'" '(should have been 11805 characters)'
fi
fi
exit 0
#	End of shell archive

egray@killer.DALLAS.TX.US (Emmet Gray) (09/05/88)

This is part 8 (of 8) to the Pcomm v1.1 release package.

Emmet P. Gray				US Army, HQ III Corps & Fort Hood
..!uunet!uiucuxc!fthood!egray		Attn: AFZF-DE-ENV
					DEH, 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_send.c
#	x_win.c
#	xmodem.c
# This archive created: Sat Sep  3 15:35:13 1988
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'x_send.c'" '(11511 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 (a user generated abort returns a 0).
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include "config.h"
X#include "dial_dir.h"
X#include "misc.h"
X#include "xmodem.h"
X
Xstatic int tot_err, err_method;
X
Xint
Xsend_xmodem(win, list, type, fast)
XWINDOW *win;
Xchar *list;
Xint type, fast;
X{
X	extern char *protocol[];
X	FILE *fp, *my_fopen();
X	int i, block_size, file_count, secs, mins, hours, big_blocks;
X	int small_blocks, err_count, got_it, num, is_batch, code;
X	int max_block, default_err;
X	long size, block, sent, xmit_size;
X	char *file, *strtok(), *name, *strrchr();
X	unsigned short crc, calc_crc();
X	unsigned char buf[1029], blk, calc_sum();
X	unsigned int packet, sleep();
X	float performance, percent;
X	struct stat stbuf;
X					/* which protocol? */
X	switch (type) {
X		case XMODEM:
X			is_batch = 0;
X			default_err = CRC_CHECKSUM;
X			max_block = 128;
X			performance = 1.36;
X			break;
X		case XMODEM_1k:
X			is_batch = 0;
X			default_err = CRC_CHECKSUM;
X			max_block = 1024;
X			performance = 1.09;
X			break;
X		case MODEM7:
X			is_batch = 1;
X			default_err = CHECKSUM;
X			max_block = 128;
X			performance = 1.36;
X			break;
X		case YMODEM:
X			is_batch = 1;
X			default_err = CRC;
X			max_block = 1024;
X			performance = 1.09;
X			break;
X		case YMODEM_G:
X			is_batch = 1;
X			default_err = NONE;
X			max_block = 1024;
X			performance = 1.02;
X			break;
X		default:
X			return(1);
X	}
X
X	tot_err = 0;
X	file_count = 0;
X	mvwaddstr(win, 2, 24, protocol[type]);
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, &stbuf) < 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					/* sanity checking */
X		if ((stbuf.st_mode & S_IFREG) != S_IFREG) {
X			beep();
X			clear_line(win, 12, 24, 1);
X			wattrstr(win, A_BOLD, "NOT REGULAR FILE");
X			wrefresh(win);
X			sleep(3);
X			continue;
X		}
X
X		size = stbuf.st_size;
X		mvwprintw(win, 4, 24, "%-10ld", size);
X		clear_line(win, 5, 24, 1);
X
X		if (!(fp = my_fopen(file, "r"))) {
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					/* 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 = ((unsigned int) big_blocks * 1024L) + ((unsigned int) small_blocks * 128L);
X					/* add block 0 to the size */
X		if (type == YMODEM || type == YMODEM_G)
X			xmit_size += 128L;
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 -= 128L;
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		clear_line(win, 12, 24, 1);
X		waddstr(win, "NONE");
X		wrefresh(win);
X		sent = 0L;
X		block = 1L;
X		blk = 1;
X		while (num = fread((char *) &buf[3], sizeof(char), 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, "%-5ld", block);
X			if (fast) {
X				percent = sent * 100.0 / xmit_size;
X				mvwprintw(win, 8, 24, "%0.1f%%", percent);
X				mvwprintw(win, 9, 24, "%-10ld", 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 CHECKSUM:
X					buf[block_size+3] = calc_sum(&buf[3], block_size);
X#ifdef DEBUG
X					fprintf(stderr, "blk=%d, checksum=%d\n", blk, buf[block_size+3]);
X#endif /* DEBUG */
X					packet = block_size +4;
X					break;
X				case CRC:
X					crc = calc_crc(&buf[3], block_size);
X					buf[block_size+3] = crc >> 8;
X					buf[block_size+4] = crc;
X#ifdef DEBUG
X					fprintf(stderr, "blk=%d, crc1=%d, crc2=%d\n", blk, buf[block_size+3], buf[block_size+4]);
X#endif /* DEBUG */
X					packet = block_size +5;
X					break;
X				case 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 = sent + (unsigned int) 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, "%-10ld", 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, "", 0L))
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
Xstatic int
Xrcv_first(win, default_err)
XWINDOW *win;
Xint default_err;
X{
X	int i, err_count;
X	unsigned int sleep();
X	void cancel_xfer();
X
X	err_count = 0;
X	while (err_count < MAX_ERRORS) {
X
X					/* scan the keyboard for abort */
X		if (wgetch(win) == ESC) {
X			beep();
X			clear_line(win, 12, 24, 1);
X			waddstr(win, "ABORTED");
X			wrefresh(win);
X			cancel_xfer(0);
X			sleep(3);
X			return(ABORT);
X		}
X					/* scan the TTY line */
X		i = getc_line(10);
X#ifdef DEBUG
X		fprintf(stderr, "rcv_first: got '%c', %02x, %03o, %d\n", i, i, i, i);
X#endif /* DEBUG */
X		switch (i) {
X			case -1:	/* timed out */
X				clear_line(win, 12, 24, 1);
X				wattrstr(win, A_BOLD, "NO RESPONSE");
X				err_count++;
X				break;
X			case NAK:	/* checksum marker */
X				if (default_err == CHECKSUM || default_err == CRC_CHECKSUM) {
X					mvwaddstr(win, 5, 24, "CHECKSUM");
X					err_method = CHECKSUM;
X					return(0);
X				}
X				err_count++;
X				break;
X			case 'C':	/* CRC marker */
X				if (default_err == CRC_CHECKSUM || default_err == CRC) {
X					mvwaddstr(win, 5, 24, "CRC");
X					err_method = CRC;
X					return(0);
X				}
X				err_count++;
X				break;
X			case 'G':	/* ymodem-g marker */
X				if (default_err == NONE) {
X					mvwaddstr(win, 5, 24, "NONE");
X					err_method = NONE;
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				err_count++;
X				break;
X			default:
X				clear_line(win, 12, 24, 1);
X				waddstr(win, "BAD HEADER");
X				err_count++;
X				break;
X		}
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	extern int fd;
X	int i, err_count;
X	void cancel_xfer();
X
X	err_count = 0;
X	mvwaddstr(win, 10, 24, "0 ");
X
X	while (err_count < MAX_ERRORS) {
X					/* write the block */
X		write(fd, (char *) blk, packet);
X					/* scan the keyboard */
X		if (wgetch(win) == ESC) {
X			beep();
X			clear_line(win, 12, 24, 1);
X			waddstr(win, "ABORTED");
X			wrefresh(win);
X			cancel_xfer(0);
X			sleep(3);
X			return(ABORT);
X		}
X					/* ymodem-g doesn't need ACKs */
X		if (err_method == NONE)
X			return(0);
X					/* wait for acknowledge */
X		i = getc_line(10);
X#ifdef DEBUG
X		fprintf(stderr, "send_block: got '%c', %02x, %03o, %d\n", i, i, i, i);
X#endif /* DEBUG */
X		switch (i) {
X			case -1:	/* timed out */
X				clear_line(win, 12, 24, 1);
X				waddstr(win, "NO RESPONSE");
X				err_count++;
X				tot_err++;
X				break;
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 == CRC)
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	cancel_xfer(0);
X	return(ERROR);
X}
SHAR_EOF
if test 11511 -ne "`wc -c < 'x_send.c'`"
then
	echo shar: "error transmitting 'x_send.c'" '(should have been 11511 characters)'
fi
fi
echo shar: "extracting 'x_win.c'" '(2577 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 "config.h"
X#ifdef OLDCURSES
X#include <termio.h>
X#endif /* OLDCURSES */
X#include "dial_dir.h"
X#include "misc.h"
X#include "xmodem.h"
X
Xvoid
Xxfer_win(list, up, type)
Xchar *list;
Xint up, type;
X{
X	extern int fd;
X	WINDOW *xf_win, *newwin();
X	int ret_code, fast, my_speed;
X	void xmodem_mode(), input_off(), line_set(), error_win(), st_line();
X	static int speed[15] = {0, 50, 75, 110, 134, 150, 200, 300, 600,
X	1200, 1800, 2400, 4800, 9600, 19200};
X	struct termio tbuf;
X
X	touchwin(stdscr);
X	refresh();
X	st_line("");
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, VERT, HORZ);
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, 11, " Press <ESC> to abort ");
X	wrefresh(xf_win);
X					/* fix up the terminal mode */
X	input_off();
X	xmodem_mode(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	fast = 0;
X
X	ioctl(0, TCGETA, &tbuf);
X	my_speed = speed[tbuf.c_cflag & CBAUD];
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 2577 -ne "`wc -c < 'x_win.c'`"
then
	echo shar: "error transmitting 'x_win.c'" '(should have been 2577 characters)'
fi
fi
echo shar: "extracting 'xmodem.c'" '(6652 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#define CLIST 64
X
X#include <stdio.h>
X#include <signal.h>
X#include <termio.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include "config.h"
X#include "misc.h"
X#include "param.h"
X#include "xmodem.h"
X
X/*
X * Calculate the CRC for the given buffer
X */
X
Xunsigned short
Xcalc_crc(buf, len)
Xunsigned char *buf;
Xint len;
X{
X	register int i;
X	unsigned short crc;
X	static unsigned short crctab[256] = {
X	0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
X	0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
X	0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
X	0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
X	0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
X	0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
X	0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
X	0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
X	0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
X	0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
X	0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
X	0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
X	0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
X	0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
X	0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
X	0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
X	0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
X	0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
X	0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
X	0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
X	0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
X	0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
X	0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
X	0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
X	0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
X	0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
X	0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
X	0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
X	0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
X	0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
X	0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
X	0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0};
X
X	crc = 0;
X	for (i=0; i<len; i++)
X		crc = (crc<<8) ^ crctab[(crc>>8) ^ *buf++];
X
X	return(crc);
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 single character from the line with a specified time-out period
X * in seconds.  If the function times-out, it returns a -1.
X */
X
Xstatic int gl_flag;
X
Xint
Xgetc_line(sec)
Xunsigned int sec;
X{
X	extern int fd;
X	int gl_force();
X	char c;
X	unsigned int alarm();
X
X	signal(SIGALRM, gl_force);
X	gl_flag = 0;
X
X	alarm(sec);
X	if (read(fd, &c, 1) <= 0) {
X		alarm(0);
X		return(-1);
X	}
X	if (gl_flag)
X		return(-1);
X	alarm(0);
X	return(c & 0xff);
X}
X/*ARGSUSED*/
Xstatic int
Xgl_force(dummy)
Xint dummy;
X{
X	gl_flag = 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
Xstatic int rl_flag;
X
Xint
Xfread_line(buf, len, sec)
Xunsigned char *buf;
Xunsigned int len, sec;
X{
X	extern int fd;
X	int n, rl_force();
X	unsigned int try, alarm();
X
X	signal(SIGALRM, rl_force);
X	rl_flag = 0;
X
X	alarm(sec);
X	while (len) {
X					/* read at most CLIST characters */
X		try = (len > CLIST) ? CLIST : len;
X		if ((n = read(fd, (char *) buf, try)) <= 0) {
X			alarm(0);
X			return(-1);
X		}
X		if (rl_flag)
X			return(-1);
X		len -= n;
X		buf = buf + n;
X	}
X	alarm(0);
X	return(0);
X}
X/*ARGSUSED*/
Xstatic int
Xrl_force(dummy)
Xint dummy;
X{
X	rl_flag = 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	extern int fd;
X
X	return(write(fd, (char *) &c, 1));
X}
X
X/*
X * Put the TTY driver in the mode suitable for xmodem transfers.
X */
X
Xvoid
Xxmodem_mode(filedes)
Xint filedes;
X{
X	struct termio tbuf;
X
X	ioctl(filedes, TCGETA, &tbuf);
X	/*
X	 * Turn off the XON/XOFF flow control, turn off echoing, and
X	 * switch to 8 bit no parity.
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(filedes, TCSETA, &tbuf);
X	ioctl(filedes, 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 backspaces (in case they have already aborted and
X * we're really at the command line).
X */
X
Xvoid
Xcancel_xfer(recv)
Xint recv;
X{
X	extern char file_name[15];
X
X	if (recv && !strcmp(param->abort, "DELETE"))
X		unlink(file_name);
X
X	putc_line(CAN);
X	putc_line(CAN);
X	putc_line(CAN);
X	putc_line(BS);
X	putc_line(BS);
X	putc_line(BS);
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;
Xlong len;
X{
X	FILE *fp, *tempfp, *my_fopen();
X	register int num;
X	char *tempfile, *mktemp(), 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 = my_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 = my_fopen(tempfile, "w"))) {
X		fclose(fp);
X		return(1);
X	}
X
X	while (len != 0L) {
X		num = (len > BUFSIZ) ? BUFSIZ : len;
X		fread(buf, sizeof(char), num, fp);
X		if (fwrite(buf, sizeof(char), num, tempfp) != num) {
X			fclose(fp);
X			fclose(tempfp);
X			return(1);
X		}
X		len = len - (unsigned int) 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 6652 -ne "`wc -c < 'xmodem.c'`"
then
	echo shar: "error transmitting 'xmodem.c'" '(should have been 6652 characters)'
fi
fi
exit 0
#	End of shell archive