[comp.sources.amiga] v90i055: uucp 1.03D - unix compatible uucp/mail/news system, Part11/16

Amiga-Request@cs.odu.edu (Amiga Sources/Binaries Moderator) (02/04/90)

Submitted-by: overload!dillon (Matt Dillon)
Posting-number: Volume 90, Issue 055
Archive-name: unix/uucp-1.03d/part11

#!/bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 11 (of 16)."
# Contents:  man/dmail.help src/uucico/uucico.c
# Wrapped by tadguy@xanth on Sat Feb  3 20:51:18 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'man/dmail.help' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'man/dmail.help'\"
else
echo shar: Extracting \"'man/dmail.help'\" \(23648 characters\)
sed "s/^X//" >'man/dmail.help' <<'END_OF_FILE'
X
X'help TOPIC' for more information on a command.  Many commands take
Xmessage numbers or message lists:
X	[msg]	is an optionaly specified message number (usually the
X		operation is on the current message if no number is
X		specified)
X	<list>	is an optionaly specified message list.  Message lists
X		consists of number ranges of the form N -N N- or N-N, and
X		keywords (help keywords)
X
X
XOTHER HELP AVAILABLE (in addition to the commands):
X	pager sendmail tilde header newmail keywords enviroment
X
XDMAIL written by Matthew Dillon, U.C. Berkeley -UCF
X
X(C)Copyright 1985-1989 by Matthew Dillon, All Rights Reserved
X
X.pager
Xset page [rows/command]
X
X	'page' is a SET variable which determines the type of paging list and
Xdisplay commands will use.  If not defined, no filter is used.	If a numerical
Xvalue (i.e. 24) is specified, the page length will be set to that value and
Xa rather stupid, simple internal paging routine will be used.  If the
Xvariable is set to an alpha-numeric string, output will be piped through
Xthat filter.  For instance:
X
X	unset page		-no paging
X	set page more		-use more filter
X	set page page		-use 'page' filter
X	set page > x		-redirect to a file (be careful)
X	set page 24		-use internal paging, page length 24 rows.
X
X	For internal paging, use <return> to continue, or your INTR
Xcharacter to break out.  Note that if you have paging set to a program,
Xresponse time may be slower because dmail must execute that program.
X
X.sendmail
Xset sendmail sendmail-path
X
X	Inform DMAIL as to where the sendmail program is.  The default
X(variable unset) is /usr/lib/sendmail.  This variable is useful only for
Xthose of us who like to hack-up our own sendmail.
X
X.tilde
X~ ~user directory expansion
X
X	In all expressions except those within double quotes, the tilde
X`~` will be expanded to either your home directory, or the directory of
Xa specified user, depending.  Note that '*' and '?' are not expanded by
XDMAIL, though they will be by any shell commands you execute.
X
X	It is probably a good idea to use ~ in any aliases, etc... in case
Xyou change directories using the 'cd' command.
X
X	alias resource source ~/.dmailrc		-example using ~
X
X.header
Xset header filepath
X
X	Set the location of your header file, which will appended to the
Xscratch mail file before you are placed in the editor (usually vi).
X
X	set header ~/.header			-set header file to ~/.header
X	unset header				-no header file
X
X.newmail
XWhen new mail comes in:
X
X	Whenever newmail arrives, it will be automatically incorporated into
Xa running DMAIL.  However, to see it, you must 'select all' (or select on
Xanything that would include it).
X
X.keywords
X.range
X.message
XKEYWORDS, MESSAGE LISTS
X
X	Many commands in DMAIL require a range of messages be given.  A Range
Xconsists of message numbers (3 4 5), message ranges (1-45 -9 9-), and
Xkeywords.  Keywords select certain messages from the entire SELECTED list:
X
X	all		-All messages
X	tag		-All TAGGED messages
X	mark		-All MARKED (read) messages
X	deleted 	-All DELETED messages
X	written 	-All WRITTEN messages
X	untag		-All messages NOT TAGGED
X	unmark		-All messages NOT MARKED (i.e. read)
X	undeleted	-All messages NOT DELETED
X	unwritten	-All messages NOT WRITTEN
X
X	Only the first three letters need be specified.  For instance, the
X'all' keyword selects all the messages currently selected.  You could select
Xon some subject, say, and then 'delete all'.
X
X	The message number 0 refers to the last message. the 'undeleted'
Xkeyword exists only for completeness; you will probably never use it.
X
X.ver
X.version
XVER
X
X	returns the version number.
X
X.if
X.else
X.endif
XIF [!]variable
XELSE
XENDIF
X
X	Conditionals.  Example:
X
X	if verbose
X		.... do stuff if the variable exists
X	else
X		... do stuff if the variable does not exist
X	endif
X	if !page; echo no page variable; endif
X
X.nobreak
X.breakok
XNOBREAK
XBREAKOK
X
X	Disable or Enable your INTR key.  This command is stackable, thus
Xthere is no problem with recursive aliases which use it.  Be careful that
Xyou match any NOBREAK to a BREAKOK, or you may accidently put yourself into
XNOBREAK mode (and a single BREAKOK may not fix it because it's stackable).
X
X	A good example would be a command which needs the page variable set
Xfor the duration... say an alias to TYPE to a file:
X
Xalias file "%_a nobreak; set _b $page; set page cat > $_a; type; set page $_b; unset _b; breakok"
X
X	You can see that if the user were to hit his INTR character at the
Xwrong time, the page variable would be incorrectly set.  The nobreak/breakok
Xcommands fix this problem.  For simplicity, most people don't bother with
Xbreak/nobreak, as it clutter's aliases up.
X
X.delete
XDELETE <message list>
X
X	Mark the specified messages for deletion.  They will no longer show up
Xon LISTings, (gaps will appear in message numbering).  However, you can
Xstill TYPE them, if you remember the message number, and you can always
XUNDELETE them.	Remember that the particular message # you've deleted
Xmay be different if you change the SELECT parameters.  For example,
Xmessage #3 selecting 'To' & 'foo' may actually be message #45 when you
Xare selecting ALL (see SELECT).  Upon a QUIT, messages marked for
Xdeletion are actually deleted from the mail file.
X
X.undelete
XUNDELETE   <message list>
X
X	UNDELETES messages.  Without arguments, UNDELETE will
Xrestore the last message you deleted.  Specifying 'all' (undelete all), will
Xundelete any deleted messages in the currently selected message list.
X
X.header
XHEADER [message]
X
X	Display the entire header of a message.  This does not cause the
Xmessage to be marked 'read'.  TYPE, on the other hand, only displays
Xheader information specified by SETLIST.
X
X.type
XTYPE [message]
X
X	Type the text of a message.  Only header fields defined by SETLIST
Xare displayed.	Otherwise, only the text is displayed.	This marks
Xthe particular message as 'read', and also makes that message the
Xcurrent message.
X
X.echo
XECHO [string]
X
X	Echo the given string onto the screen.
X
X.go
XGO #
X	go to a message, don't type it out or anything.  Remember that you
Xcan go to the last message by using the message # 0.  By placing a keyword
X(help range), you can go to the first TAGGED message, etc...
X
X.reply
X.Reply
XREPLY
X
X	Reply to the current letter.  There are two forms of 'reply'.  The
Xfirst does not include the senders original letter, the second does.
XIn both cases, Dmail will place you in VI, with the To:, Cc:, and
Xsubject lines filled out.  The second form is 'Reply', with an
Xupper case 'R'.  This form includes the sender's message shifted to
Xthe right with '>'s on the left hand side.  See FORWARD for another
Xmethod of replying to mail.
X
X	In any case, you may get the sender's letter by reading the file '#'
Xfrom VI.  That sequence would be ':r\\#'
X
X	See MAIL for more information on VI
X
X.forward
XFORWARD [user user user....]
X
X	Forward the current message to a list of users.  The sender's
Xentire message is placed in the text portion.  The To: field will
Xcontain the user's named above, and the Subject: field will contain
Xa 'Fo:' (you append your own subject)
X
X	See MAIL for more information on VI
X
X.mail
XMAIL [user user user user...]
X
X	Mail to [users].  You are given a VI to work from, and may modify
Xany of the header fields.  the From: field is inserted automatically
Xby SENDMAIL, but you can overide it if you wish.
X
X	Quitting out of VI without writing the output file will cause an
Xabort, and no mail will be sent.   Additionaly, you may use the 'vibreak'
Xvariable to enable your INTR character (usually CTL-C) to break you out of
XVI.
X
X	When modifying the users list in To and Cc fields, remember that
Xthey should be all comma delimited, or none comma delimited.
X
X.select
XSELECT ALL
XSELECT Field  match match match match...
XSELECT Field  !match
XSELECT Field  match match match , Field match , .....
X
X	Select what you want to look at.  Select will take the field header
Xyou supply and attempt to match arguments with that field in the mail
Xfile.  You can then work on the selected material as if the rest of
Xyour mail didn't exist.  For instance, 'select To dillon', will select
Xall messages addressed to you.	Note that case is checked for the
XFIELD-HEADER, but not for arguments, so the latter will also find
Xanything addressed to Dillon or DILLON.  You only have to give a
Xpartial match, so 'select To di' would work just as well.
X
X	Select then, allows you to quickly find what you want even though
Xyou may have 12000 messages (though it may take a while with that many)
XYou may also specify what you DON'T want to select on:
X
X select To !foo
X
Xwill select all letters not addressed to 'foo'.  You may select on any
Xfield you wish.  At any time, you may say 'select ALL' to select the
Xentire message list.  Use RESELECT to select on the current message
Xlist.  SELECT always selects from the entire message-list
X
X select Cc hack , To hack
X
Xwill select any mail with Cc or To fields containing hack.  You may
Xhave as many comma operators as you wish.  The comma must be a field
Xof its own (spaces on either side... will be fixed in a later version)
X
X.reselect
XRESELECT ALL
XRESELECT Field	match match match match...
XRESELECT Field	!match
X
X	SEE SELECT.  Reselect allows you to CONTINUE to narrow down a topic
Xor whatever.  It will select on the current message list (which you have
Xalready narrowed down with SELECT or RESELECT).
X
X.defer
XDEFER
X
X	Deselects any marked messages .. messages marked as 'read'.  This is
Xas if you did a RESELECT on all unread messages in the current select field.
XThus, the messages will be renumbered.	To see these messages again, you must
Xuse SELECT.
X
X.rlist <num>
XRLIST <num>		-<num> > 0 (next N), < 0 (prev N).
XRLIST			-Lists next 20 (or previous 20 if near the end)
X
X	Relative list.	See LIST for details of the list command.  This
Xcommand will display the next <num> messages beginning at the current
Xmessage.  If <num> is negative, it displays the previous 20 ending at
Xthe current message.  If there are not enough messages remaining in the
Xforward or reverse direction, it lists in the opposite direction to try
Xto bring the total messages listed to <num>
X
X.list
XLIST <message list>
XLIST			-Lists all selected messages
X
X	Display header information on a message as specified by SETLIST,
Xin a one line per message format.  The default lists ALL messages.
X
XLeftword flags:    r	-indicates message has been read.  Message will be
X			 moved to the destination file on QUIT
X		   >	-indicates message is the current message
X		   w	-indicates message has been written to a file.
X			 Message will be deleted from source file on QUIT
X		   T	-indicates message has been taged by the user
X
X.next
XNEXT
X
X	Execute TYPE or HEADER for the next message, depending on which of
XTYPE or HEADER was last executed by you
X
X._next
X_NEXT
X
X	Go to next message, do not print it out.
X
X.back
XBACK
X
X	Execute TYPE or HEADER for the previous message, depending on which
Xof TYPE or HEADER was last executed by you
X
X._back
X_BACK
X
X	Go to previous message, do not print it out.
X
X.db
XDB
X	Delete the current message, type (or header) the previous message.
XThis command could not be implemented with "del;prev" due to a special case
Xwhen one is on the last message.
X
X.dt
XDT
X	Delete current message, type (or header) next message.  This command
Xwill warn you when you reach the end of the message list.
X
X	References: DELETE and NEXT
X
X.enviroment
XENVIROMENT VARIABLE ACCESS
X
X	Access may be gained to enviroment variables by using $$ instead of
X	a single $.  For example:  echo $$USER
X
X	'help dmail' for command line options,
X	'help set'   for description of special variables
X
X.set
XSET [variable [string]]
X
X	see 'enviroment' for enviroment variables
X
X	With no arguments, SET prints out all currently active variables.
XNote that this variable list is a different list than the ALIAS list.  With
Xone argument, the specified variable is displayed if it exists, or created
Xif it doesn't.  With more than one argument, the specified variable is set
Xto the specified string.  Variables may be references on the command line by
X$variable .  The variable's contents will replace the reference.  Unlike
Xaliases, however, variable substitutions may take place anywhere on the
Xcommand line rather than substitute just the command name.  Note also that
Xif you use a $ substitution for an argument of a command, the entire
Xvariable's contents is ONE argument (i.e. if a = "b c d", and you say
Xsomething like: 'unset $a', it would attempt to unset a single variable
Xwhos name is "b c d".
X
X	There are several reserved SET variables, which define options in
XDMAIL.	Changing these will modify the option:
X
X	page		set paging on or to a specific command (i.e. more)
X	sendmail	set the path to the sendmail program
X	vibreak 	enable your INTR character even when in VI.
X	verbose 	reflects verbose option to sendmail
X	comlinemail	set when dmail executed w/ command line mailing list
X	header		header file to append to any messages you send.
X	ask		ask what to do after vi'ing mail
X	archive 	file to archive any mail you send out in.
X	_headchar	string used to precede included text, default ">"
X	replyfields	fields to search to find the reply path
X
X	page
X
X	 This variable determines what kind of paging is used for LIST,
X	 TYPE, and HEADER commands.  If the variable does not exist, paging
X	 is turned off.  If set to null (no string), an internal paging
X	 routine is used.  If set to a value, an internal paging routine is
X	 used using the value as the page length.  the 'page' variable can
X	 also be set to a command, such as 'more' or 'page', in which case,
X	 the output is piped through those commands:
X
X	 set page		Turn paging on (internal page routine)
X	 set page 25		Internal page routine... 25 rows/screen
X	 set page more		Use 'more' command to pipe output through
X	 set page page		Use 'page' command to pipe output through
X
X	 you could also conceviably say:  'set page cat > x', or
X	 'set page cat | lpr', but be very careful.
X
X	sendmail
X
X	 This variable will redirect DMAIL as to where the mailer program
X	 is.  The mailer program must be compatible with /usr/lib/sendmail
X	 which is the default used if the 'sendmail' variable isn't set
X	 to anything:
X
X	 set sendmail bin/mysendmail
X
X	vibreak
X
X	 This variable, when set, allows the INTR character to abort a
X	 reply, mail, or forward command.  Otherwise, if this variable is
X	 not present, INTR will not abort the above commands.
X
X	verbose
X
X	 This variable, when set, causes the -v flag to be sent to
X	 sendmail.  In addition, DMAIL will wait for sendmail to complete
X	 before returning your prompt.
X
X	comlinemail
X
X	 This variable is set when dmail is invoked with a command line
X	 user list (e.g.  dmail charlie mary mark). Usually, one uses
X	 this variable in an IF construct.  A good example would be that
X	 you may usually CD to a mail directory, but you don't want to
X	 CD when dmail is run with a command line user-list:
X
X		if !comlinemail
X			cd  ...
X
X	 alternate definition: The comlinemail variable will NOT be set
X	 if dmail is in interactive mode.
X
X	header
X
X	 The file specified by this variable will be appended onto the temp
X	 vi files in reply and mail.  The file is appended before you go into
X	 vi, so when you do, what you see is still what you get.
X
X	ask
X
X	 If set, dmail will ask you what to to (quit, send, re-edit) after you
X	 leave the editor when sending mail.  If not set, the mail is sent as
X	 soon as you leave the editor (unless you didn't write anything).
X
X	archive
X
X	 If set (to a file name), any mail you send out (mail/reply/etc...)
X	 will be archived to this file.  Usually, you provide a fully
X	 specified path so cd's won't effect the file location.
X
X	_headchar
X
X	 This string is prepend to any included text when you do an upper-case
X	 reply (R) command.
X
X	replyfields
X
X	 This string holds a list of fields which are searched for to
X	 determine which one to use in the To: field of your reply.  If
X	 this variable does not exist or none of the specified fields could
X	 be found, the 'From ' (not From:) mail header will be used.  The
X	 search ends at the first field found.	Example:
X
X	 set replyfields "Reply-To: From:"
X
X.replyfields
XSET replyfields "field1 field2 ..."
X
X	 This string holds a list of fields which are searched for to
X	 determine which one to use in the To: field of your reply.  If
X	 this variable does not exist or none of the specified fields could
X	 be found, the 'From ' (not From:) mail header will be used.  The
X	 search ends at the first field found.	Example:
X
X	 set replyfields "Reply-To: From:"
X
X.>
XSET _HEADCHAR "string"
X
X	see SET.  The _headchar variable determines the string prepending all
X	included text when you do an upper-case reply (R) command.
X
X.archive
XSET ARCHIVE file
X
X	if the archive variable is set to a file path, any mail you send out
X	will automatically be appended to that file.  Dmail pre-pends a
X	"From ", so it is compatible with /bin/mail and so that you can
X	dmail -f your archive file.  Additionaly, a "Date: " field is
X	pre-pended so you know when you sent the message.  example:
X
X	set archive ~/Dmail/arch
X
X	since your .dmailrc is sourced even when you "dmail user .." from
X	your csh, putting the above line in your .dmailrc will turn on
X	archiving whenever you use dmail to send mail, command line or
X	dmail prompt.
X
X	if unset or set to nothing, no archive is made.
X
X.ask
XSET ASK
X
X	if the 'ask' variable is set (set ask), dmail will ask you what to do
X	when you are finished editing mail rather than send it immediately.
X	(see 'help set')
X
X.alias
XALIAS [variable [string]]
X
X	Create an alias for a command.	With no arguments, ALIAS will display
Xall active aliases.  With one argument, a particular alias is displayed (if
Xit exists), or defined (if it did not previously exist).  With more than one
Xargument, the particular alias is set to the string list specified.
X
Xalias
Xalias hack "select From hacker , To hacker , Cc hacker"
Xalias bye quit
Xalias stuff "setlist 60 To ; list"
X
X	Usually, any arguments following the alias are appended to the
Xexpansion.  However, you can place such arguments inside the alias somewhere
Xby using the following construction:
X
Xalias myecho "%var echo $var ; list"
X
Xmyecho hello there  ---> echo hello there ; list
X
X	to unalias an alias, use the UNALIAS command.
X
X.unset
X.unalias
XUNSET var var var...
XUNALIAS var var var...
X
X	Eradicate variables or aliases from memory.
X
X.setlist
XSETLIST [-s] [columns] Field [columns] Field ...
X
X	-s prevents display of the list.
XSet the list format used for LIST and TYPE.  The optional [columns]
Xindicates how many columns to allocate for the Field specified.  The
XField can be a partial match. However, case is observed:
X
Xsetlist 18 Fro	38 Sub	10 To  0 Dat
X
X18 columns for the From: field, etc... when TYPEing messages, the
X[columns] is ignored, and each field is printed in its entirety.
XNote that 0 columns have been allocated for the Date: field.
XTherefore, the Date: field will not show up on the LIST command,
Xbut will show up in the TYPE command.
X
X.cd
XCD PATH
X
X	cd, as in csh.	Changes your base directory.  You can use
X the shell escape '! pwd' to get your current working directory.
X
X.source
XSOURCE file
X
X	Source a file.	The file is read in an executed in sequence.
X
X.preserve
XPRE	<message list>
X
X	PRESERVE messages.  A message is MARKED if it has been read (has an 'r'
Xflag from the LIST command).  Marked messages are moved from your readfile
Xinto your outfile upon a QUIT.	If you are reading and writing to the same
Xfile (i.e. from your mbox to your mbox), the 'r' flag has no effect.
X
X	However, if you are reading from your spool file, and want to keep
Xread messages in your spool (that is, not move them to your mbox), you want
Xto PRESERVE them.  This command simply unmarks them, so they appear not to
Xhave been read.
X
X.mark
XMARK <message list>
X
X	Mark messages specified as being already 'read'.  Remember that if
Xyou executed DMAIL without a -f option, any message 'read' at the time
Xyou quit will be moved to MBOX (or file specified by -o)
X
X.tag
X.untag
XTAG <list>
XUNTAG <list>
X
X	The TAG command allow you to flag any message.	You can tag a set of
Xmessages, then reference them all at once.  For instance, if you tag
Xinteresting messages as you glance at them, you may then write them all
Xto a file by 'write filename tag',  or list them with 'list tag'.
XAlternately, you could delete all your taged messages with a single delete
Xcommand 'delete tag'.  The 'tag' operand works in the same way as the 'all'
Xoperand, except it works only on taged messages.
X
X	UNTAG will untag a particular message in your message list.  For
Xinstance, to untag any taged messages in the entire message list, you would:
X
X select all
X untag all	OR	 untag tag
X
X	Note that 'untag all' and 'untag tag' have the same effect.
X
X.write
XWRITE file <message list>
X
X	Write the given messages or the current message to a file.  The file
Xfile is appended to.  Remember that you may specify 'all' to write
Xall messages in the current select field to the file.  Messages will be
Xmarked as having been writen, and will be deleted from the mail file
Xwhen you 'quit'.  However, you may cause them to be kept in the mail
Xfile by UNdeleting the messages (i.e.  undelete all)
X
X	You can also TAG the messages you want to write, and say
X'write file tag' to write to the file all taged messages.
X
X.!
X! [shell command]
X
X	Give yourself a shell or execute a shell command.  The shell forked
Xis that specified by your SHELL enviroment variable, or /bin/sh if there is
Xno SHELL enviroment variable.
X
X.x
X.exit
XX (EXIT)
X
X	EXIT out of DMAIL without changing any files.  Usually, one exits
Xwith QUIT, which would cause deleted messages to disappear, and TYPEd
Xmessages to go to MBOX (if you did not use the -f option with DMAIL).
X
X	If your outfile is the same as your infile, reading a message does
Xnot effect anything.
X
X.quit
XQUIT
X
X	Quit out of DMAIL. Delete any messages that were marked for deletion
Xand if you executed DMAIL on /usr/spool/mail/ (default), any mail
Xmarked 'read' will be placed in MBOX in your home directory
X
X.xswitch
X.qswitch
XXSWITCH fromfile [tofile]
XQSWITCH fromfile [tofile]
X
X	Switch to a different set of files.  XSWITCH doesn't modify your
Xold from and to files before switching, QSWITCH works as if you had QUIT
Xstuff before switching to another set of files.
X
X	If no [tofile] is specified, the new tofile will be the same as the
Xfromfile you specify.
X
X.help
X.?
XHELP [topic]
X
X	Give me help on a topic
X
X.dmail
XCOMMAND LINE OPTIONS FOR DMAIL
X
X	dmail -O [-l rcfile] -f [file] -o [file] -F field -F field -F field ...
X
X	Default conditions:
X		Home directory gotten from password entry
X		User gotten from password entry
X		Visual editor set to /usr/ucb/vi
X
X		VI BREAKOUT enabled
X		READ file is /usr/spool/mail/$USER
X		WRITE file is $HOME/mbox
X		From:,	To:, and Subject: fields will be loaded into memory.
X
X	HOME	enviroment variable becomes home directory
X	USER	enviroment variable becomes user name
X	VISUAL	enviroment variable becomes editor used
X
X	-O			Go into interactive mode, even if there is no
X				mail to read.
X
X	-f [from file]		Specify spool file to get mail from. If no file
X				Argument is given, $HOME/MBOX is used.
X
X	-o [to file]		Specify file to write to, If no Argument
X				is given, $HOME/.MBOX is used.	Note that
X				the default without -o is $HOME/MBOX
X
X	-f -o			With no file arguments causes both READ and
X				WRITE files to be $HOME/.MBOX
X
X	-F field		Append this field to those which will be
X				used on initial load.  If, During usage of the
X				program you specify a field which is not in
X				memory, DMAIL will be forced to re-load the
X				entire spool file, which can take a long time
X				if you have more than 64K in the file
X
X	-l rcfile		Use this as the rc file rather than .dmailrc
X
X	-L			Do not source the rc file on boot
X
X
END_OF_FILE
if test 23648 -ne `wc -c <'man/dmail.help'`; then
    echo shar: \"'man/dmail.help'\" unpacked with wrong size!
fi
# end of 'man/dmail.help'
fi
if test -f 'src/uucico/uucico.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/uucico/uucico.c'\"
else
echo shar: Extracting \"'src/uucico/uucico.c'\" \(32949 characters\)
sed "s/^X//" >'src/uucico/uucico.c' <<'END_OF_FILE'
X
X/*
X *  UUCICO.C
X *
X *  (C) Copyright 1987 by John Gilmore.
X *  Copying and use of this program are controlled by the terms of the Free
X *  Software Foundation's GNU Emacs General Public License.
X *
X *  Derived from:
X *  i[$]uuslave.c	 1.7 08/12/85 14:04:20
X *  which came from the ACGNJ BBS system at +1 201 753 9758.  Original
X *  author unknown.
X *
X *  Ported to Amiga by William Loftus
X *  Amiga Changes Copyright 1988 by William Loftus.  All rights reserved.
X *  Additional Major Changes (c)Copyright 1989 by Matthew Dillon, All rights reserved
X *
X * 14-Oct-89, moved modem_init() to before poll_sys.
X *
X * -r option	(-r1 does a call out to all systems we have mail for)
X * -D[EVICE] dev    sets serial device name (automatic from Getty)
X * -U[NIT] unit     sets unit name (automatic from Getty)
X * -h0		    Ignore CD (carrier detect)
X */
X
X#include "/version.h"
X
X#include "includes.h"           /* System include files, system dependent */
X#include "uucp.h"               /* Uucp definitions and parameters */
X#include "sysdep.h"             /* System dependent parts of gnuucp */
X#include "modem.h"              /* Modem commands */
X#include <log.h>
X#include <tmpfile.h>
X
Xint sigint();
Xvoid modem_init();
Xvoid cleanup();
X
X#define MAX_FLAGS	40
X
Xextern int errno;
X
XIDENT(".06");
X
Xstatic char *Copyright = COPYRIGHT;
X
Xchar	ttynam[NAMESIZE],		/* Name of tty we use as serial port */
X	srcnam[NAMESIZE],		/* Source file name */
X	dstnam[NAMESIZE],		/* Dest file name */
X	who[NAMESIZE] = "-",            /* Who sent the file */
X	flags[MAX_FLAGS],		/* Flags from file xfer cmd */
X	temp[NAMESIZE]; 		/* Temp file name */
X
Xint	ourpid = 0,			/* Our process ID */
X	ignore_time_restrictions = 0,	/* Call out even if L.sys sez no */
X	mode;				/* File mode from file xfer cmd */
X
Xchar  host_name[MAX_HOST] = "AmigaUUCP";  /* Other guy's host name */
Xchar  our_name[MAX_HOST];	/* Our uucp hostname, set from usenet.ctl */
Xchar  path[128];
Xint   debug   = -1;	/* -1 indicates not set by command line or ctl file */
Xint   f_wait  = 0;	/* wait for a call (-w) or calls (-w -e) after outbnd */
Xint   loop    = 0;	/* Loop accepting logins if tty name specified */
Xint   curtemp = 0;
Xint   Overide = 0;	/* overide modem protocol	    */
Xint   Getty   = 0;	/* -Getty initiated		    */
Xint   IgnoreCD= 0;	/* xgetc() should ignore carrier?   */
Xint   OurNameOv= 0;
Xint   WindowOne= 0;
X
X#define MAX_STRING	200	/* Max length string to send/expect */
X
X#define MSGO2IDX	7
X
X/* We print these prompts */
X
Xchar msgo0[] = "login: ";
Xchar msgo1[] = "Password:";
Xchar msgo2[10+MAX_HOST] = { "\20Shere" };   /*  NO =    */
Xchar msgo3[] = "\20ROK\0";
Xchar msgo3a[]= "\20P";
Xchar msgo3b[]= "\20Pg\0";
Xchar msgo4[] = "\20OOOOOOO\0";
X
X/* We expect to receive these strings */
X
Xchar msgi0[] = "uucp\r";
Xchar msgi1[] = "s8000\r";
X/* char msgi2[] = "\20S*\0"; We now scan it specially FIXME */
Xchar msgi3[] = "\20Ug\0";
Xchar msgi4[] = "OOOOOO";
X
X#define SPOOLDIR "UUSPOOL:"
X
X/*
X * Protocol switch data structure
X */
X
Xextern int gturnon(), grdmsg(), gwrmsg(), grddata(), gwrdata(), gturnoff();
X
X#define turnon	gturnon
X#define rdmsg	grdmsg
X#define wrmsg	gwrmsg
X#define rddata	grddata
X#define wrdata	gwrdata
X#define turnoff gturnoff
X
Xint
Xgetname(isshere)
X{
X    int data, count = 0;
X    static char msgi[MAX_STRING+SLOP];	/* Incoming trash buffer */
X
X    /* Read data until null character */
X
X    while ((data = xgetc(BYTE_TO)) != EOF) {
X	data &= 0x7F;
X	if (data == 020)
X	    break;
X    }
X    if (data == EOF)
X	return FAIL;
X
X    while ((data = xgetc(BYTE_TO)) != EOF && (data & 0x7F)) {
X	data &= 0x7F;
X	if (count == 0 && data != 'S')
X	    continue;
X	if (count > sizeof(msgi) - 2)
X	    continue;
X	msgi[count++] = (char)data;
X    }
X    msgi[count] = 0;
X
X    if (debug > 8)
X	printf("GETNAME MSG (%d): %s\n", count, msgi);
X
X    if (msgi[0] != 'S')
X	return FAIL;
X    if (isshere) {
X	for (count = 1; msgi[count] && msgi[count] != '='; ++count);
X	if (msgi[count] == '=')
X	    ++count;
X    } else {
X	count = 1;
X    }
X    if (msgi[count]) {
X	if (debug > 8)
X	    printf("Compare host names: '%s' '%s'\n", host_name, msgi + count);
X	strcpy (host_name, msgi + count);
X    }
X    strtok(host_name, " ");     /*  put \0 after hostname */
X    if (debug > 8)
X	printf("Hostname is '%s'\n", host_name);
X    return SUCCESS;
X}
X
X/*
X *  get_proto() checks the list of protos given by the foriegn machine
X *  checking for 'g' (which is the only proto we have).  Use only in master
X *  mode.
X */
X
Xint
Xget_proto()
X{
X    int data;
X
X    while ((data = xgetc(BYTE_TO)) != EOF) {
X	data &= 0x7F;
X	if (data == 0)
X	    break;
X	if (data == 'g')
X	    return(SUCCESS);
X    }
X    return FAIL;
X}
X
X/*
X * Medium level input routine.
X *
X * Look for an input string for the send-expect sequence.
X * Return 0 for matching string, 1 for timeout before we found it.
X * FIXME:  we only time out if the other end stops sending.  If it
X *	   keeps sending, we keep listening forever.
X */
X
Xinstr(s, n)
Xchar *s;
Xint n;
X{
X    int data,count,j;
X    int i;
X    static char msgi[512];  /* Incoming trash buffer */
X
X    count = 0;
X
X    if (debug > 8) {
X	printf("Expecting ");
X	for (i = 0; i < n; i++)
X	    printc(s[i]);
X	printf("\n");
X    }
X
X    while ((data = xgetc(BYTE_TO)) != EOF) {
X	msgi[count++] = (char)data & 0x7F;
X
X	if (count == sizeof(msgi)) {    /*  throw away first half */
X	    count = sizeof(msgi) / 2;
X	    bcopy(msgi + sizeof(msgi) / 2, msgi, sizeof(msgi) / 2);
X	}
X
X	if (count >= n) {
X	    for (i = n - 1, j = count - 1; i >= 0; i--, j--) {
X		if (*(s+i) != msgi[j])
X		    break;
X	    }
X	    if (i < 0) {
X		if (debug > 8)
X		    printf("\n");
X		return(0);
X	    }
X	}
X    }
X
X    if (debug > 8)
X	printf("\n");
X    msgi[count] = (char)0;
X    return(1);
X}
X
X/*
X * Debugging hack for stuff written to the modem.
X */
X
Xint
Xtwrite(s, n)
Xchar *s;
Xint  n;
X{
X    int i;
X
X    if (debug > 8) {
X	printf("Wrote:  ");
X	for (i = 0; i < n; i++)
X	    printc(s[i]);
X	printf("\n");
X    }
X    return xwrite(s, n);
X}
X
X
X/*
X * MAIN ROUTINE.
X *
X * This is called at program startup.  It parses the arguments to the
X * program (if any) and sets up to receive a call on the modem.
X *
X * If there are no arguments, we assume the caller is already on standard
X * input, waiting to do uucp protocols (past the login prompt), and we
X * just handle one caller.
X *
X * If there is an argument, it is the name of the tty device where we
X * should listen for multiple callers and handle login and password.
X */
X
Xvoid
Xmain(argc,argv)
Xint argc;
Xchar *argv[];
X{
X    int     i;
X    char    *poll_sys = (char *)NULL;   /* System name to poll, or none */
X    short   rmode = 0;			/* 1 = master, 0 = slave	*/
X
X    LogProgram = "uucico";
X    LogHost = host_name;
X    LogWho  = who;
X
X    signal(SIGINT,sigint);  /* Allow the user to break */
X
X    /* FIXME, use getopt */
X    /* scan command line arguments, kinda kludgy but it works */
X
X    for (i = 1; i < argc; ++i) {
X	if (argv[i][0] != '-') {
X	    printf("uucico: warning, extra args ignored: %s\n", argv[i]);
X	    break;
X	}
X	switch (argv[i][1]) {
X	case 'N':
X	    strcpy(our_name, argv[i] + 2);
X	    OurNameOv = 1;
X	    break;
X	case 'D':       /*  Serial Device   */
X	    {
X		extern char *DeviceName;
X		DeviceName = argv[++i];
X	    }
X	    break;
X	case 'U':       /*  Serial Unit     */
X	    {
X		extern long DeviceUnit;
X		DeviceUnit = atoi(argv[++i]);
X	    }
X	    break;
X	case 'g':
X	case 'G':
X	    Getty = 1;
X	    break;
X	case 'h':
X	    IgnoreCD = atoi(argv[i] + 2);
X	    break;
X	case 'w':
X	    ++f_wait;
X	    break;
X	case 'r':
X	    rmode = atoi(&argv[i][2]);
X	    break;
X	case 'x':
X	    debug = atoi(&argv[i][2]);
X	    LogLevel = debug;
X	    LogToStdout = 1;
X	    printf("uucico: debug level set to %d\n", debug);
X	    break;
X	case 'o':
X	    Overide = 1;
X	    break;
X	case 'n':
X	    WindowOne = 1;  /*	force windowing mode to size=1	 */
X	    break;
X	case 'S':
X	    ignore_time_restrictions++;
X	case 's':
X	    poll_sys = &argv[i][2];
X	    break;
X	case 'e':
X	    ++loop;
X	    break;
X	/* Is -t needed for MSDOS?  Why?  -- hoptoad!gnu */
X	case 't':
X	    curtemp++;
X	    printf("uucico: using ~uutemp.$$$ for temp file\n");
X	    break;
X	default:
X	    printf("uucico: warning, bad flag %s\n", argv[i]);
X	    break;
X	}
X    }
X
X    /* If argument provided, use it as name of comm port */
X
X    /* FIXME, this needs some thought. */
X
X    getcwd(path,128);
X    if (chdir(SPOOLDIR)) {
X	perror("Can't chdir to Spool directory");
X	exit(2);
X    }
X
X    read_ctl();             /* Read control file FIXME */
X
X    /*
X     * If running via getty/login, our debug stdout had better
X     * go to a file, not to the usual stdout!
X     */
X
X    if (debug > 0 && Getty) {
X	freopen("T:uuslave.log", "a", stdout);
X    }
X
X    setvbuf(stdout, NULL, _IOLBF, 0);
X
X    /* Timestamp the long debug log */
X
X    if (debug > 0) {
X	long clock;
X
X	time(&clock);
X	printf("\014\nuuslave log on tty '%s' starting %s\n",
X		ttynam, ctime(&clock));
X    }
X
X    /* Log our presence so we humans reading the logs can find the
X       entries created by uuslave. */
X
X    ulog(-1, "Startup %s", VERSION);
X
X    amiga_setup();
X
X    modem_init();
X
X    if (poll_sys) {
X	if (*poll_sys == '\0')
X	    poll_sys = (char *)NULL;
X	call_system(poll_sys);
X	if (!f_wait)
X	    goto end;
X    } else {
X	if (rmode) {
X	    do_outbound();
X	    if (!f_wait)
X		goto end;
X	}
X    }
X
X    do {
X	/*
X	 *  Set up serial channel, wait for incoming call.
X	 */
X	DEBUG(0, "\nRestarting\n", 0);
X
X	if (Getty == 0 && Overide == 0)
X	    openline();
X
X	do_session(Getty);
X
X	hangup();
X	DEBUG(0, "\nEnd of call\n", 0);
X    } while (loop && !Getty);
X
Xend:
X    cleanup();
X}
X
X/*
X * translate embedded escape characters
X */
X
Xvoid
Xxlat_str(msg, out)
Xchar	*msg;
Xchar	*out;
X{
X    int i  = 0;
X    int cr = 1;
X    /*int j  = 0;*/
X
X    while (msg[i]) {
X	if (msg[i] == '\\') {
X	    switch (msg[++i]) {
X	    case 'r':            /* carriage return */
X		twrite("\r", 1);
X		/*out[j++] = 0x0d;*/
X		break;
X	    case 'n':            /* line feed */
X		twrite("\n", 1);
X		/*out[j++] = 0x0a;*/
X		break;
X	    case '\\':           /* back slash */
X		twrite("\\", 1);
X		/*out[j++] = '\\';*/
X		break;
X	    case 't':            /* tab */
X		twrite("\t", 1);
X		/*out[j++] = '\t';*/
X		break;
X	    case 'b':
X		SendBreak();
X		break;
X	    case 'd':            /* delay */
X		Delay(180);
X		break;
X	    case 's':            /* space */
X		twrite(" ", 1);
X		/*out[j++] = ' ';*/
X		break;
X	    case 'c':            /* no CR at end */
X		cr = 0;
X		break;
X	    default:		/* don't know so skip it */
X		break;
X	    }
X	    ++i;
X	} else {
X	    twrite(msg + i, 1);
X	    ++i;
X	    /*out[j++] = msg[i++];*/
X	}
X    }
X    if (cr) {
X	twrite("\r", 1);
X	/*out[j++] = 0x0d;*/
X    }
X    /*out[j] = '\0';*/
X}
X
X/*
X * Read the control file and grab a few parameters.
X */
X
Xread_ctl()
X{
X    FILE  *fd;
X    static char buf[MAX_CTLLINE];
X
X    if (!(fd = fopen("UULIB:Config", "r"))) {
X	printf("Can't Find config file");
X	chdir(path);
X	exit(3);
X    }
X
X    /* find path to inbound news */
X
X    while (NULL != fgets(buf, sizeof buf, fd)) {
X	if (strncmp(buf, "NodeName", 8) == 0) {
X	    if (OurNameOv == 0)
X		strcpy(our_name, strtok(&buf[9], CTL_DELIM) ) ;
X	} else if (strncmp(buf, "Debug", 5) == 0)
X	    if (debug < 0)
X		debug = atoi(strtok(&buf[6], CTL_DELIM));
X    }
X    fclose(fd);
X    return (1);
X}
X
X/*
X * Search spool queues for work, call the systems we need to call.
X */
X
Xdo_outbound()
X{
X    return call_system((char *)NULL);
X}
X
X/*
X * Call a specific system, or all systems that have work pending.
X */
X
Xcall_system(sys)
Xchar	*sys;
X{
X    FILE    *lsys;
X    static char buf[MAX_LSYS];
X    static char sysnam[MAX_HOST];
X    static char prev_name[MAX_HOST];
X    int     called = FAIL;
X
X    /*
X     * Unix uucico just reads the directory, and calls the systems
X     * in the order of the files in the directory.  We want more
X     * control than that, though I'm not sure that L.sys order is
X     * best either.  For example, in the first call after 11PM,
X     * I'd like to call the sites that haven't been callable before
X     * 11PM first, and finish up with the ones I've been able to call
X     * all day.  FIXME.
X     */
X
X    if (! (lsys = fopen("UULIB:L.sys", "r"))) {
X	    DEBUG(0, "uucico: can't open L.sys, errno %d\n", errno);
X	    return 0;
X    }
X    sysnam[0] = '\0';               /* Initially, no previous sys */
X
X    /* Once per system in L.sys... */
X    /* FIXME, handle continuation lines (trailing "\") */
X
X    while (fgets(buf, sizeof buf, lsys)) {
X	if (buf[0] == '#' || buf[0] == '\n')
X	    continue;
X
X	/*
X	 * Grab the system name.  If same as previous, and
X	 * the previous call worked, skip it.
X	 */
X
X	strcpy(prev_name, sysnam);
X	(void) sscanf(buf, "%s", sysnam);
X	if (!strcmp(sysnam, prev_name)) {
X	    if (called == SUCCESS)
X		continue;
X	}
X
X	/*
X	 * If a system name was specified, skip til we find it
X	 * If none was specified, only call if there is work.
X	 */
X
X	if (sys) {
X	    if (strcmp(sys, sysnam) != 0)
X		continue;
X	} else {
X	    DEBUG(3,"searching for outbound to %s\n", sysnam);
X	    if (!work_scan(sysnam)) {
X		DEBUG(3,"no work for %s\n", sysnam);
X		called = SUCCESS;	/* Don't try further */
X		continue;
X	    }
X	    DEBUG(2, "uucico: found work for %s\n", sysnam);
X	}
X
X	called = call_sysline(buf);
X
X	if (called == SUCCESS && sys)
X	    break;
X    }
X
X    fclose(lsys);
X    if (called == FAIL && sys)
X	DEBUG(0, "Could not call system %s\n", sys);
X    return 0;
X}
X
X/*
X *  Call out to a system, given its L.sys line.
X */
X
Xcall_sysline(lsysline)
Xchar *lsysline;
X{
X    static char    tempname[MAX_HOST + 30 + SLOP];
X    static char    strbuf[MAX_STRING+SLOP];
X    char    *sysnam,
X	    *times,
X	    *acu,
X	    *sbaud,
X	    *telno,
X	    *send,
X	    *expct;
X    int     baud;
X
X    who[0] = '-'; who[1] = '\0';    /* No user now (for logit) */
X
X    /* FIXME, use the values it is ignoring here */
X
X    sysnam = strtok(lsysline, " ");
X    times =  strtok(NULL, " ");   /* Time */
X    acu =    strtok(NULL, " ");     /* ACU */
X    sbaud =  strtok(NULL, " ");   /* Baud */
X    telno =  strtok(NULL," ");    /* phone */
X
X    strcpy(host_name, sysnam);
X
X    if ((!ignore_time_restrictions) && (strcmp(times,"Any"))) {
X	/* FIXME, check the time parameter and return FAIL if
X	 * it does not allow calls now.  Meanwhile, bounce
X	 * all calls unless -S is specified. */
X	ulog(-1, "Wrong Time To Call %s", sysnam);
X	return FAIL;
X    }
X
X    baud = atoi(sbaud);
X
X    /*	FIX ME, acu not implemented ?	*/
X    DEBUG(4, "Opening outgoing line %s\n", acu);
X    if (openout(acu, baud) != SUCCESS)
X	return FAIL;
X
X    if (Overide == 0) {
X	if (dial_nbr(telno)) {
X	    ulog(-1, "FAILED call to %s", host_name);
X	    return FAIL;
X	}
X    }
X
X    /* FIXME, log tty, baud rate, ... */
X    ulog(-1, "DIALED %s", host_name);
X
X    /*
X     * Process send-expect strings.
X     * FIXME, deal with "-", BREAK, etc.
X     */
X
X    while (send = (char*)strtok((char *)NULL, " ")) {
X	if (send[0] != '"' || send[1] != '"' || send[2] != '\0') {
X	    if (instr(send, strlen(send)))
X		    goto bort1;
X	}
X
X	if (expct = (char*)strtok((char *)NULL, " ")) {
X	    /* FIXME secondary strings, e.g. ogin:-EOT-ogin: */
X	    xlat_str(expct, strbuf);
X
X	    /*twrite(strbuf, strlen(strbuf));*/
X	}
X    }
X
X    /*
X     * FIXME, there should be a way to detect login/passwd
X     * failure here and keep doing the script rather than
X     * continuing to expect Shere at another login: prompt.
X     */
X
X    ulog(-1, "SUCCEEDED call to %s", host_name);
X
X
X    if (getname(1))         /*  get name        */
X	goto bort1;
X			    /*	send response	*/
X    sprintf(tempname, "\20S%s -Q0 -x%d\0", our_name, debug);
X    twrite(tempname, strlen(tempname)+1); /* Including null */
X
X    /* wait for ok message, wait for protocol request
X     * send protocol 'g' response */
X    /* FIXME, we don't actually wait for the ROK message, since
X     * it is immediately followed by the Pprotos message.  We
X     * currently just look for a Pg message.  This needs work.
X     * FIXME, WE CAN'T TALK TO SITES THAT SUPPORT more than 'g'.
X     */
X
X    if (instr(msgo3a, sizeof(msgo3a)-1)) {
X	if (!get_proto())
X	   goto bort1;
X    }
X
X
X    twrite( msgi3, sizeof(msgi3)-1);
X
X    if (turnon(1))
X	goto bort1;
X
X    ulog(-1, "OK Startup");
X
X    top_level(1);
X    hangup();
X    return SUCCESS;
X
Xbort1:
X    hangup();
X    return FAIL;
X}
X
X/* Handle a single uucp [slave] login session */
X
Xdo_session(ontheline)
Xint ontheline;
X{
X    if (ontheline == 0) {
X	/* output login request, verify uucp */
X	twrite(msgo0,sizeof(msgo0)-1);
X	if (instr(msgi0,sizeof(msgi0)-1)) {
X	    printf("uucico: invalid login name\n");
X	    goto bort;
X	}
X
X	/* output password request, verify s8000 */
X	twrite(msgo1,sizeof(msgo1)-1);
X	if (instr(msgi1,sizeof(msgi1)-1)) {
X	    printf("uucico: invalid password\n");
X	    goto bort;
X	}
X
X	printf("uucico: correct login\n");
X    }
X
X    /*
X     *	send Shere=<myhost>
X     *
X     *	Apparently mac UUCP has a bug that only allows 7
X     *	char host names, and it fails if it gets shere=<myhost>
X     *	where <myhost> is > 7 chars.
X     */
X
X    /*strcpy(msgo2 + MSGO2IDX, our_name);*/
X    twrite(msgo2,strlen(msgo2)+1);
X
X    /*
X     *	get \020S<host> -Qn n	(??)
X     */
X
X    if (getname(0))
X	goto bort;
X
X    /* output ok message, output protocol request, wait for response */
X
X    twrite(msgo3,sizeof(msgo3)-1);
X
X    /* FIXME, make the protocol list here, and use it */
X    twrite(msgo3b,sizeof(msgo3b)-1);
X    if (instr(msgi3,sizeof(msgi3)-1))
X	    goto bort;
X
X    if (turnon(0))
X	goto bort;
X
X    ulog(-1, "OK Startup");
X    top_level(0);
X
Xbort:
X    if (debug > 0)
X	printf("uucico: call complete\n");
X    return (1);
X}
X
X/*
X * Handle transactions "at top level", as Unix uucp's debug log says.
X *
X * As master, we scan our queues for work and send requests to the
X * other side.	When done, we send a hangup request and switch to slave mode.
X *
X * As slave, we accept requests from the other side; when it is done,
X * it sends a hangup request, and we switch to master mode, if we have
X * any work queued up for that system.
X *
X * This repeats as long as either side has work to do.	When all the
X * queued work is done, we agree to hang up, terminate the packet protocol,
X * and return to the caller.  (We still haven't hung up the phone line yet.)
X *
X * A curious feature of the hangup protocol is that it is not a simple
X * question-answer.  The master says "H", asking about hangup.  The
X * slave responds "HY" saying OK.  The master then says "HY" also,
X * then both of them hang up.  Maybe this is to make sure the first HY
X * got ack'ed?  Anyway, an "H" is reported as HANGUP and an "HY" as
X * HANGNOW.  After we send an HY, we go back to listening for commands;
X * if the master sends something other than HY, we'll do it.
X */
X
X#define HANGUP	2		/* Signal to switch master/slave roles */
X#define HANGNOW 3		/* Signal to hang up now */
X#define COPYFAIL	4	/* File copy failed */
X
Xint
Xtop_level(master_mode)
Xint master_mode;
X{
X    static char    buf[MAXMSGLEN];	   /* For hangup responses */
X
X    if (master_mode) {
X	(void) work_scan(host_name);    /* Kick off queue scan */
X	goto master;
X    }
X
X    for (;;) {
X    slave:			/*  SLAVE SIDE	*/
X	for (;;) {
X	    DEBUG(4, "*** TOP *** - slave\n", 0);
X	    switch (do_one_slave()) {
X	    case SUCCESS:
X		break;
X	    case FAIL:
X		return FAIL;
X	    case HANGUP:
X		if (work_scan(host_name)) {
X		    if (wrmsg("HN"))
X			return FAIL;
X		    goto master;
X		} else {
X		    if (wrmsg("HY"))
X			return FAIL;
X		    break;	/*  go to master mode */
X		}
X	    case HANGNOW:
X		goto quit;
X	    }
X	}
X    master:	/*  MASTER SIDE */
X	for (;;) {
X	    DEBUG(4, "*** TOP *** - master\n", 0);
X	    switch (do_one_master()) {
X	    case SUCCESS:
X		break;
X	    case FAIL:
X		return FAIL;
X	    case HANGUP:
X		/* We wrote an H command, what's the resp? */
X		if (rdmsg(buf, MAXMSGLEN) != SUCCESS) {
X		    return FAIL;
X		}
X		if (buf[0] != 'H')
X		    return FAIL;
X		if (buf[1] == 'N')
X		    goto slave;
X		else {
X		    /* Write the final HY */
X		    if (wrmsg("HY"))
X			return FAIL;
X		    goto quit;
X		}
X	    }
X	}
X    }
X
Xquit:
X    /* Shut down the packet protocol */
X
X    turnoff();
X
X    /* Write the closing sequence */
X
X    twrite(msgo4, sizeof(msgo4)-1);
X    (void) instr(msgi4, sizeof(msgi4)-1);
X
X    twrite(msgo4, sizeof(msgo4)-1);
X
X    strcpy(who, "-");
X    ulog(-1, "OK Conversation complete");
X
X    return SUCCESS;   /* Go byebye */
X}
X
X/*
X * We are slave; get a command from the other side and execute it.
X *
X * Result is SUCCESS, FAIL, HANGUP, or HANGNOW.
X */
X
Xint
Xdo_one_slave()
X{
X    static char msg[MAXMSGLEN]; 	   /* Master's message to us */
X
X    /* Get master's command */
X    if (rdmsg(msg, MAXMSGLEN) != SUCCESS)
X	return FAIL;
X
X    /* Print it for easy debugging */
X    DEBUG(5,"\nCommand: %s\n\n", msg);
X
X    switch (msg[0]) {
X    case 'S':
X	if (msg[1] != ' ')
X	    break;
X	return host_send_file(msg);
X    case 'R':
X	if (msg[1] != ' ')
X	    break;
X	return host_receive_file(msg);
X    case 'X':
X	/*
X	 * Cause uuxqt to run (on certain files?)
X	 * See Protocol.doc for sketchy details.
X	 */
X	break;
X    case 'H':
X	if (msg[1] == '\0') return HANGUP;
X	if (msg[1] == 'Y')  return HANGNOW;
X	if (msg[1] == 'N')  return SUCCESS;     /* Ignore HN to slave */
X	break;
X    }
X
X    /* Unrecognized packet from the other end */
X
X    DEBUG(0, "Bad control packet refused: %s\n", msg);
X    if (yesno(msg[0], 0, 0))        /* FIXME: return error code */
X	return FAIL;
X    return SUCCESS;
X}
X
X/*
X *  Do one piece of work as master.
X *
X *  FIXME:  we don't handle the flags, e.g. -c, properly!
X *
X *  Now only dequeues queue file if all transfers were successful.
X */
X
Xint
Xdo_one_master()
X{
X    FILE    *fd;
X    char    *sname;
X    char    cmnd[1];		    /* Command character */
X    static char buf[256];
X    int     fail = SUCCESS;
X    int     failaccum = 0;
X    int     num;
X    int     delmeflag;
X    static char notify[NAMESIZE];   /* A bit large...FIXME */
X    char    *delList[16];	    /* delete files list   */
X    short   di = 0;
X
X    /* FIXME: do the notify stuff */
X
X    sname = work_next();
X    if (!sname) {
X	/* No more work, time to hang up. */
X	if (wrmsg("H"))
X		return FAIL;
X	return HANGUP;
X    }
X
X    DEBUG(2, "Request file %s\n", sname);
X
X    LockFile(sname);
X
X    fd = fopen(sname, "r");
X    if (fd == NULL) {
X	UnLockFile(sname);
X	DEBUG(0, "uucico: couldn't open %s\n", sname);
X	return SUCCESS;
X    }
X
X    while (fgets(buf, sizeof buf, fd)) {
X	DEBUG(3, "Queued request: %s", buf);
X
X	if (buf[1] != ' ')
X	    goto badnum;
X
X	num = sscanf(buf, "%s %s %s %s %s %s %o\n",
X	    cmnd, srcnam, dstnam, who, flags, temp, &mode, notify
X	);
X
X	switch (cmnd[0]) {
X	case 'S':
X	    if (num < 7 || num > 8)
X		goto badnum;
X	    fail = local_send_file(buf, &delmeflag);
X	    if (delmeflag) {
X		if (di == sizeof(delList)/sizeof(delList[0])) {
X		    ulog(-1, "Too many source files in Cmd file! %s", sname);
X		} else {
X		    delList[di] = malloc(strlen(temp) + 1);
X		    strcpy(delList[di], temp);
X		    ++di;
X		}
X	    }
X	    break;
X	case 'R':
X	    if (num != 5)
X		goto badnum;
X	    fail = local_receive_file(buf);
X	    break;
X	default:
X	badnum:
X	    DEBUG(0, "Unknown/invalid queued request: %s\n", buf);
X	    ++fail;
X	    break;
X	}
X	if (fail != SUCCESS)
X	    ++failaccum;
X
X	/* FIXME, what does uucp do if one of N xfers fails? */
X
X	if (fail == FAIL) {
X	    ulog(-1, "Error in work file %s", sname);
X	    ulog(-1, "Bad line is: %s", buf);
X	}
X    }
X    fclose(fd);
X
X    /*
X     *	If we successfuly copied everything zap the queue file
X     *	and any local data files...
X     */
X
X    if (failaccum == 0) {
X	while (di) {
X	    --di;
X	    remove(delList[di]);
X	    free(delList[di]);
X	}
X	fail = remove(sname);
X	UnLockFile(sname);
X	if (fail != 0) {
X	    ulog(-1, "Unable to remove work file %s", sname);
X	    DEBUG(0, "Can't remove, errno %d\n", errno);
X	} else {
X	    DEBUG(4, "Removed work file %s\n", sname);
X	}
X    } else {
X	UnLockFile(sname);
X    }
X    return SUCCESS;
X}
X
X/* Send a "yes or no" packet with character 'c'. */
X
Xint
Xyesno(c, true, err)
Xchar c;
Xint true;
Xint err;
X{
X    char buf[21];
X
X    buf[0] = c;
X    buf[1] = true? 'Y': 'N';
X    buf[2] = 0;
X    if (err && !true)
X	sprintf(buf+2,"%d", err);
X
X    return wrmsg(buf);
X}
X
X/*
X *  SLAVE MODE, Master wishes to send a file to us
X *
X *  SECURITY:	If file is not in list of allowed directories
X *		disallow transfer.  UUSPOOL:   is always in the
X *		list.
X *
X *		If file is for UUSPOOL: (the current dir), disallow "C." files
X *		NOTE: success return and file redirected to T: as this can
X *		occur only if somebody purposefully is trying to break us.
X *
X *  Return 0 = success
X */
X
Xint
Xhost_send_file(msg)
Xchar  *msg;
X{
X    FILE *fddsk;		    /* Disk file pointer */
X    char    cmnd[1];		    /* Command character */
X    int r;
X    int nor = 0;
X
X    sscanf(msg,"%s %s %s %s %s %s %o",
X	    cmnd, srcnam, dstnam, who, flags, temp, &mode);
X
X    ulog(-1, "REQUESTED %s", msg);
X    munge_filename(dstnam, dstnam);           /* Translate to local name */
X    strcpy (temp, TmpFileName(dstnam));       /* Create a handy temp file */
X
X    if (SecurityDisallow(dstnam, 'w')) {
X	ulog(-1, "REQUEST FAILED -- SECURITY");
X	if (yesno('S', 0, 4))
X	    return FAIL;
X	return SUCCESS;
X    }
X    if (SecurityDisallow(dstnam, 'c') > 0) {
X	ulog(-1, "REQUEST FAILED -- SECURITY, REMOTE TRIED TO SEND");
X	ulog(-1, "US A COMMAND FILE: %s, FILE COPIED TO T:Bad-Cmd", dstnam);
X	strcpy(dstnam, "T:Bad-Cmd");
X	nor = 1;
X    }
X
X    /* FIXME: deal with file modes now that we fopen. */
X
X    LockFile(temp);
X
X    fddsk = fopen(temp, "wb" /*, mode|0600 */);
X    if (fddsk == NULL) {
X	UnLockFile(temp);
X	/* Can't open file -- send error response */
X	if (debug > 0) {
X	    printf("Cannot open temp file %s (%s) for writing, errno=%d\n",
X		temp,
X		dstnam,
X		errno
X	    );
X	}
X	ulog(-1, "REQUEST FAILED -- TEMP FILE");
X	if (yesno('S', 0, 4))
X	    return FAIL;
X	return SUCCESS;
X    }
X
X    /* FIXME: Are the above permissions right?? */
X    /* FIXME: Should we create directories for the file? */
X
X    if (yesno('S',1, 0)) {  /* Say yes */
X	fclose(fddsk);
X	unlink(temp);
X	UnLockFile(temp);
X	return 1;
X    }
X    r = receive_file(fddsk, temp, dstnam, srcnam, nor);
X    UnLockFile(temp);
X    return(r);
X}
X
X/*
X *  SLAVE MODE, Master wants us to send a file to it
X *
X *  SECURITY:	If file is not in list of allowed directories
X *		disallow transfer.  UUSPOOL:   is always in the
X *		list.
X *
X *  0 = sucess
X */
X
Xhost_receive_file(msg)
Xchar  *msg;
X{
X    FILE *fddsk;     /* Disk file descriptor */
X    int x;
X    char    cmnd[1];		    /* Command character */
X
X    ulog(-1, "REQUESTED %s", msg);
X
X    sscanf(msg,"%s %s %s",cmnd,srcnam,dstnam);
X    munge_filename(srcnam, temp);
X
X    if (SecurityDisallow(srcnam, 'r')) {
X	ulog(-1, "COPY FAILED -- SECURITY");
X	if (yesno('S', 0, 4))
X	    return FAIL;
X	return SUCCESS;
X    }
X
X    fddsk = fopen(temp, "rb");              /* Try to open the file */
X    if (fddsk == NULL) {
X	/* File didn't open, sigh. */
X	if (debug > 0) {
X	    printf("Cannot open file %s (%s) for reading, errno=%d\n",
X		temp, srcnam, errno
X	    );
X	}
X	ulog(-1, "DENIED CAN'T OPEN %s", temp);
X	if (yesno('R', 0, 2))
X	    return 1;
X	return 0;
X    }
X
X    if (yesno('R',1, 0)) {  /* Say yes */
X	fclose(fddsk);
X	return 1;
X    }
X
X    x = send_file(fddsk);
X
X    switch (x) {
X    default:
X	return x;
X    case COPYFAIL:
X	/* We don't care if the copy failed, since the master
X	   asked for the file and knows the result. */
X	return SUCCESS;
X    }
X    return 1;
X}
X
X/*
X *  MASTER MODE, We want to send a file.
X *
X *  Return FAIL, SUCCESS, or COPYFAIL.
X *
X *  SUCCESS is returned either if the file was not found locally (local
X *  error, and the queued transfer should be flushed) or if it was moved
X *  successfully.  COPYFAIL indicates that the queued transfer should be
X *  left queued, and later retried.  FIXME, there are several failure points
X *  in the transaction (see Protocol.doc) and we need finer control here.
X */
X
Xint
Xlocal_send_file(workstr, delmeflag)
Xchar *workstr;
Xint *delmeflag;
X{
X    static char buf[MAXMSGLEN];    /* Used for both xmit and receive */
X    FILE *fddsk;	    /* Disk file descriptor */
X    int res;		    /* Result and file removal status */
X
X    *delmeflag = 0;
X
X    /* WHY are temp and srcnam switched?  FIXME!  And no notify? */
X
X    sprintf(buf,"S %s %s %s %s %s 0%o %s",
X	temp, dstnam, who, flags, srcnam, mode, who
X    );
X
X    ulog(-1, "REQUEST %s", buf);
X
X    if (strchr(flags, 'c')) {
X	munge_filename(srcnam, temp);
X    } else {
X	munge_filename(temp, temp);
X    }
X    LockFile(temp);
X    fddsk = fopen(temp, "rb");
X    if (fddsk == NULL) {
X	UnLockFile(temp);
X	/* FIXME -- handle queued request for nonexistent file */
X	if (debug > 0)
X	    printf("Can't open file %s (%s), errno=%d\n",
X		temp,
X		srcnam,
X		errno
X	    );
X	ulog(-1, "NOT FOUND %s", temp);
X	/* return COPYFAIL;*/
X	return SUCCESS;     /*	assume file previously sent */
X    }
X
X    /* Tell the other side we want to send this file */
X
X    if (wrmsg(buf) != SUCCESS) {
X	DEBUG(0, "problem sending request\n", 0);
X	fclose(fddsk);
X	UnLockFile(temp);
X	return FAIL;
X    }
X
X    /* See what they have to say about it */
X
X    if (rdmsg(buf, MAXMSGLEN) != SUCCESS) {
X	fclose(fddsk);
X	UnLockFile(temp);
X	return FAIL;
X    }
X    if ((buf[0] != 'S') || (buf[1] != 'Y')) {
X	ulog(-1, "REQUEST DENIED %s", buf);
X	fclose(fddsk);
X	UnLockFile(temp);
X	return FAIL;
X    }
X    res = send_file(fddsk); /* FAIL, SUCCESS, or COPYFAIL */
X
X    /* Delete the source file if it was just a copy */
X
X    if (res != SUCCESS) {
X	UnLockFile(temp);
X	return res;
X    }
X    if (strchr(flags, 'c')) {   /* If copied direct from source */
X	UnLockFile(temp);
X	return res;		/* ...just return. */
X    }
X    *delmeflag = 1;
X    UnLockFile(temp);
X
X    return res;
X}
X
X/*
X *  MASTER MODE, We wish to receive a specific file so we ask for it
X *
X *  Return 0 = success
X */
X
Xint
Xlocal_receive_file()
X{
X    static char buf[MAXMSGLEN];
X    FILE *fddsk;		    /* Disk file pointer */
X    int r;
X
X    /* FIXME, test dest file access before we ask for it. */
X
X    sprintf(buf,"R %s %s %s %s %s 0%o %s",
X	srcnam, dstnam, who, flags, temp, mode, who
X    );
X
X    munge_filename(dstnam, dstnam);           /* tlate to local name      */
X    strcpy (temp, TmpFileName(dstnam));       /* Create a handy temp file */
X
X    /* FIXME: deal with file modes now that we fopen. */
X    /* FIXME: Are the above permissions right?? */
X    /* FIXME: Should we create directories for the file? */
X
X    LockFile(temp);
X    fddsk = fopen(temp, "wb" /*, mode|060 */);
X
X    if (fddsk == NULL) {
X	UnLockFile(temp);
X	/* Can't open temp file -- send error response */
X	if (debug > 0) {
X	    printf("Cannot open temp file %s (%s) for writing, errno=%d\n",
X		temp,
X		dstnam,
X		errno
X	    );
X	}
X	ulog(-1, "REQUEST FAILED -- TEMPFILE");
X	return FAIL;
X    }
X
X    ulog(-1, "REQUEST %s", buf);
X    if (wrmsg(buf) != SUCCESS) {
X	fclose(fddsk);
X	UnLockFile(temp);
X	printf("uucico: problem sending request\n");
X	return FAIL;
X    }
X
X    /* See what the other side has to say about it */
X
X    if (rdmsg(buf, MAXMSGLEN) != SUCCESS) {
X	fclose(fddsk);
X	UnLockFile(temp);
X	return FAIL;
X    }
X    if ((buf[0] != 'R') || (buf[1] != 'Y')) {
X	ulog(-1, "REQUEST DENIED %s", buf);
X	fclose(fddsk);
X	UnLockFile(temp);
X	return SUCCESS; /* FIXME, should do something more here */
X    }
X
X    r = receive_file(fddsk, temp, dstnam, srcnam, 0);
X    UnLockFile(temp);
X    return(r);
X}
X
X/*
X *  General receive file
X */
X
Xint
Xreceive_file(fddsk, temp, dstnam, srcnam, norename)
XFILE *fddsk;
Xchar	*temp, *dstnam, *srcnam;
X{
X    int status;
X    int error = 0;		    /* No errors so far */
X
X    if (rddata(fddsk) != SUCCESS)
X	error++;
X    status = fclose(fddsk);         /* Make sure the data got here */
X    if (status != 0) {
X	error++;
X	DEBUG(0, "fclose errno=%d\n", errno);
X    }
X
X    /*
X     *	Move the file from its temp location to its real location,
X     *	This needs to be able to copy a file if a simple rename
X     *	does not suffice.  Should create directories if necesary.
X     *	should use source ]name if target is a directory (i.e. no
X     *	target source name
X     */
X
X    unlink(dstnam);
X
X    if (norename)       /*  for security redirect   */
X	status = 0;
X    else
X	status = rename(temp, dstnam);
X
X    if (status != 0) {
X	error++;
X	if (debug > 0) {
X	    printf("Cannot rename file %s to %s, errno=%d\n",
X		temp, dstnam, errno);
X	}
X    }
X
X    ulog(-1, "COPY %s", error ? "FAILED": "SUCCEEDED");
X
X    if (yesno('C', error == 0, 5))  /* Send yes or no */
X	return FAIL;
X
X    return SUCCESS;
X}
X
X/*
X * general file send routine
X * Return SUCCESS, FAIL, or COPYFAIL.
X */
X
Xint
Xsend_file(fddsk)
XFILE *fddsk;	 /* Disk file pointer */
X{
X    static char ansbuf[MAXMSGLEN];
X
X    if (wrdata(fddsk) != SUCCESS) {
X	fclose(fddsk);
X	return COPYFAIL;
X    }
X    fclose(fddsk);
X
X    /* Await the "CY" or "CNddd" packet, and toss it. */
X
X    while (1) {
X	if (rdmsg(ansbuf, MAXMSGLEN) != SUCCESS)
X	    return COPYFAIL;
X	if (ansbuf[0] != 'C') {
X	    DEBUG(0,"\nDidn't get 'CY' or 'CN', got %s\n", ansbuf);
X	    /* and loop looking for C message */
X	} else if (ansbuf[1] == 'Y') {
X	    ulog(-1, "REQUESTED %s", ansbuf);
X	    return SUCCESS;
X	} else {
X	    ulog(-1, "COPY FAILED %s", ansbuf);
X	    return COPYFAIL;
X	}
X    }
X    return COPYFAIL;
X}
X
END_OF_FILE
if test 32949 -ne `wc -c <'src/uucico/uucico.c'`; then
    echo shar: \"'src/uucico/uucico.c'\" unpacked with wrong size!
fi
# end of 'src/uucico/uucico.c'
fi
echo shar: End of archive 11 \(of 16\).
cp /dev/null ark11isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 16 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
-- 
Submissions to comp.sources.amiga and comp.binaries.amiga should be sent to:
	amiga@cs.odu.edu	
or	amiga@xanth.cs.odu.edu	( obsolescent mailers may need this address )
or	...!uunet!xanth!amiga	( very obsolescent mailers need this address )

Comments, questions, and suggestions should be addressed to ``amiga-request''
(please only use ``amiga'' for actual submissions) at the above addresses.