[comp.sources.misc] v18i075: mush - Mail User's Shell, Part18/22

argv@zipcode.com (Dan Heller) (04/22/91)

Submitted-by: Dan Heller <argv@zipcode.com>
Posting-number: Volume 18, Issue 75
Archive-name: mush/part18
Supersedes: mush: Volume 12, Issue 28-47

#!/bin/sh
# do not concatenate these parts, unpack them in order with /bin/sh
# file mush.1 continued
#
if test ! -r _shar_seq_.tmp; then
	echo 'Please unpack part 1 first!'
	exit 1
fi
(read Scheck
 if test "$Scheck" != 18; then
	echo Please unpack part "$Scheck" next!
	exit 1
 else
	exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
	echo 'x - still skipping mush.1'
else
echo 'x - continuing file mush.1'
sed 's/^X//' << 'SHAR_EOF' >> 'mush.1' &&
or are strings that are automatically generated by pressing a special
key on the terminal.
On the other hand, the timeout can be used intentionally to prevent a
macro from being expanded; simply type the first character of the macro,
then wait for it to echo before typing the next.
This does not work in curses mode, because curses macros
never \*Qtime out.\*U
.PP
In any mode, macros are
.IR recursive ;
that is, if the
.I "key sequence"
of one macro appears in the
.I expansion
of another macro (or even of the same macro), the second key sequence
is recognized when the first macro is expanded, and this new key
sequence is also expanded.
Great care should be taken when creating macros to be certain that
recursive expansions do not happen unintentionally.
Expansion can be prevented in line or composition modes by using a
.I literal-next
character.
.PP
Literal-next characters may be used from the keyboard or embedded
in expansions.
In either case, they prevent the next character
from being interpreted as part of a key sequence.
.I Mush
recognizes the literal-next character from the tty settings of the
terminal, if the \*Qnew\*U BSD-style device driver is available;
otherwise, `^V' (control-V) is recognized as a literal-next.
Note that, if you have a tty literal-next character,
then when typing you need to type
.I two
of them in order to send one to \fIMush\fR; this is because the tty
driver consumes the first one.
It is not necessary to use two literal-nexts in macro expansions
unless you wish to cause the second literal-next to be literal.
.PP
Backslash can be used as a literal-next when typing, and can
sometimes be used as a literal-next in expansions; but use it
with caution, because it also introduces escape sequences
(see \*QMacro syntax,\*U below).
There is no literal-next mechanism for curses mode.
.PP
A macro always aborts whenever
.I any
command called by the macro returns an error.
This includes recursive expansions, so no matter how often a macro has
recurred, it is terminated completely.
Errors in curses mode include illegal cursor movements, such as up from
the top of the screen or down from the last message.
.PP
.BR "Macro syntax" .
.PP
A special syntax is provided for specifying control characters and other
non-printing characters in macro key sequences and expansions.
This syntax is the same as that for bindings, discussed in the
CURSES INTERFACE section; it can be summarized as:
.ta 1.25i
.in +2
.nf
\\CX	control-X (where X is any capital letter)
\\E	the escape character
\\n	a newline (other C-style escapes also work)
.fi
.in -2
.sp
Thus, to create a line mode macro for control-X control-W, as in the
example above, the command is
.sp
.ti +4
map '\\CX\\CW' save
.PP
Also provided is a syntax for executing functions from within macros.
There are two special functions that are effective in all modes;
these are
.I getstr
and
.IR getline .
Both of these functions interrupt expansion of the current macro,
and wait for a newline-terminated string to be entered from the
standard input.
This input string is inserted into the macro expansion.
The functions differ in that
.B getline
retains the newline character (carriage-return) at the end of the
input string, whereas
.B getstr
strips off the newline (one must still be typed to terminate input).
These functions can be executed by surrounding their name with
square brackets
.RB ( [ ,
.BR ] );
for example,
.sp
.ti +4
map '\\CX\\CW' save [getline]
.sp
creates a line mode macro, which is expanded when control-X control-W is
typed, and which displays \*Qsave\*U followed by a space and then waits
for the user to type a line of input; the input line is used as the
arguments to the save command.
.PP
Additional functions are currently available only in the curses mode.
However, the syntax of enclosing the function name in square brackets
applies to all functions, regardless of mode.
Note that
.I ONLY
the function name can appear in the brackets; no whitespace is allowed.
.PP
.BR "Curses mode macros" .
.PP
Macros in curses mode are the most versatile, because they can access the
full range of curses commands quickly and easily.
Every character that appears in the expansion part of a curses mode macro
can reference a curses command or another macro.
Like other curses functions, curses mode macros are created with the
.B bind
command.
For example, to sort your messages by date and then send the most recent
one to the printer, you could use
.sp
.ti +4
bind @ macro 'od$|'
.sp
When the `@' key is typed, this macro first invokes sort
(`o' from the default bindings) and instructs it to use date (d)
for sorting; it then moves the current-message pointer to the last
message ($) and prints that message (|).
.PP
Admittedly, the above macro is somewhat cryptic, and is dependent upon
the bindings for sort, last-msg, and lpr being set to the defaults.
It is better, and possibly more understandable, to refer to the
desired curses functions without using their key bindings.
To allow this, the \*Q[function]\*U syntax described above may be used
in curses mode macros to reference curses functions.
The only function that is prohibited from appearing in the \*Q[\|]\*U
is the special
.I macro
function, which cannot be called when it has no binding.
The example macro can therefore be rewritten as
.sp
.ti +4
bind @ macro [sort]d[last-msg][lpr]
.sp
Such references to curses functions may be made only in curses mode
macros, and are effective only when \fIMush\fR is actually in curses mode.
That may sound strange, but the most common use of curses macros is
to quickly perform functions that require an escape to the line mode.
For example, although there is a variation of the curses mode
.I mail
function that prompts for additional flags, there is no function
to prompt for flags to be passed to
.IR reply .
A macro can easily be created to provide this:
.sp
.ti +4
bind R macro '[line-mode]reply '
.sp
This macro binds `R' to perform an escape to line mode and type
the string \*Qreply\*U followed by a space.
Macro expansion then ends, leaving it up to the user to supply
flags to the command or to backspace over it if a different command
(or none) is desired.
Of course, the macro could also have provided some default arguments:
.sp
.ti +4
bind R macro '[line-mode]reply \-ei '
.PP
Note that, if the
.B getline
or
.B getstr
function is used in a line-mode escape, it is not possible to
erase the text that is typed before the
.IR get ;
that is, if the macro is
.sp
.ti +4
bind R macro '[line-mode]reply \-ei [getline]'
.sp
then the user is forced to use the \-ei flags.
.PP
.BR "Line mode macros" .
.PP
Line mode macros combine some of the convenience of single-keystroke
commands with the versatility of the line-oriented text interface.
As has been noted, the choice of characters for line mode key sequences
should be made carefully, so as not to interfere with normal typing.
Line mode macros are created with the
.B map
command; for example, suppose you frequently forward messages to a
friend named \*Qfred.\*U  You could create a macro to do this:
.sp
.ti +4
map '\\CF' 'mail \-f . fred\\n'
.sp
This macro causes the single keystroke `^F' (control-F) to forward
the current message to \*Qfred.\*U  Note the newline
character \*Q\\n\*U at the end of the expansion;
this causes the command to be executed immediately,
without you having to type a carriage-return.
.PP
The expansion part of a line mode macro echoes to the screen when
it is expanded, so you can see what the macro is doing.
You can therefore use parts of the expansion as a \*Qprompt.\*U  In
the above example, suppose you wished to enter a message list rather
than always forwarding the current message.
Change the macro to:
.sp
.ti +4
map '\\CF' 'mail \-f [getstr] fred\\n'
.sp
This version of the macro prints \*Qmail \-f\*U and a space, then waits
for a newline-terminated string from the standard input.
The newline is stripped, and the string is used as the message list
passed to the \*Qmail \-f\*U command.
The address \*Qfred\*U is also passed to
.BR mail ,
so the messages in the list are forwarded to fred.
.PP
If you want to be able to \*Qchange your mind\*U after starting a
line mode macro, you must leave the \*Q\\n\*U out of the expansion.
Without the newline, the macro is not executed immediately, so
you have a chance erase the line (or part of it) and type
something different.
Remember that the
.B getline
function keeps the newline in the string it gets, so if you don't
want a newline to appear, you must use
.BR getstr .
When using the
.I get
functions, you should also remember that you can
.I never
backspace past the \*Qbeginning\*U of a
.BR getline ,
and you can backspace past the beginning of a
.B getstr
only after the get has been completed.
.PP
When the
.B getstr
function is used in line mode macros,
.I Mush
reprints the current input line so you can see what the whole
thing looks like, but does not redisplay the line mode prompt
(see the entry for
.B prompt
in the VARIABLES section for information on what the
prompt looks like).
Don't let this worry you.
The input line is also reprinted when
.B getline
is used, but the newline in the input string usually results in a
new prompt being displayed.
.PP
.IR NOTE :
Line mode macros are not available when using the line-mode escape
function in curses mode.
It is necessary to escape all the way to line mode (that is, leave
curses mode by typing carriage-return at the `:' prompt) in order
to access line mode macros.
This is to prevent possible confusion when similar macros exist
in both line and curses modes.
.PP
.BR "Composition mode macros" .
.PP
Composition mode macros are very similar to line mode macros, and
provide a \*Qpower typing\*U function when composing messages.
For example, you might want to have the word \*Qpercent\*U inserted
into your message whenever you hit the `%' key:
.sp
.ti +4
map! % percent
.sp
Another use is to simulate the indentation features of editors.
For example, you might
.sp
.ti +4
map! '\\CT' '\ \ \ \ '
.sp
(where the expansion is four spaces, enclosed in single quotes).
This macro causes four spaces to be inserted into the message whenever
control-T is typed.
.PP
Composition mode macros can also be used to execute
.I tilde-escapes
(see the GENERAL USAGE section for a list of these).
For example, you could create a macro to invoke the editor:
.sp
.ti +4
map! '\\CE' '\\n~v\\n'
.sp
When control-E is typed, this macro prints a newline (to be sure that
the tilde-escape is the first thing on a line), then types \*Q~v\*U
followed by another newline, to start the editor.
Similar macros can be created for other tilde-escapes.
.PP
.BR "Mixed mode macros" .
.PP
It is not normally possible to mix macros among the different modes.
However, once expansion has begun, it is interrupted only by an error
or by the appearance of one of the special
.I get
functions.
It is therefore possible to have a macro expansion which causes
the mode to change before the expansion has completed.
In this case, recursive expansions apply to the new mode.
Suppose we are using a variation of the editor-starting macro shown
above for composition mode:
.sp
.ti +4
map! '\\CE' '\\n~v emacs\\n'
.sp
This macro causes the \*Qemacs\*U editor to be started when control-E
is typed in composition mode.
We can now create a line mode macro that makes use of this
composition mode macro:
.sp
.ti +4
map '#' 'reply \-i [getline]~t[getline]\\CE'
.sp
When the `#' key is pressed in line mode, this macro
prints \*Qreply \-i\*U and waits for a message list, then enters
composition mode (by executing the
.B reply
command).
In composition mode, it displays the To: line
(the \*Q~t\*U escape) and waits for other addresses to be added.
Finally, it recursively expands the control-E macro, to
start editing the message with emacs.
.PP
As can be seen from this example, the
.I Mush
macro facility is very powerful.
Be very careful not to accidentally expand recursive macros,
especially when using macros that change modes.
When testing new macros, it is a good idea to start
.I Mush
in
.I read-only
mode (the \-r command line flag) to be sure that messages are
not lost or altered.
.PP
.BR "Getting rid of macros" .
.PP
It is not necessary to delete a macro in order to redefine it.
New expansions for existing key sequences automatically replace
the old expansions.
If it is necessary to remove a macro completely, the commands
.BR unbind ,
.B unmap
and
.B unmap!
can be used to remove curses mode, line mode, and composition mode
macros, respectively.
Remember to use a backslash or other literal-next character to prevent
the expansion of line mode macros when using these commands, especially
.BR unmap .
.SH "MAIL ADDRESSES"
Whenever a command that requires a user address or set of addresses
is specified
.RB ( mail ,
.BR reply ,
.BR alias ,
.BR etc )
the addresses given must be separated by commas.
Most casual users specify addresses that contain no comments or whitespace.
The simplest addresses are just the login names of the users you wish to send
your message to:
.sp
.ti +2
\fBmail\fR fred barney wilma betty
.sp
In these cases,
.I Mush
can figure out that they are separate addresses and
insert commas between addresses automatically.
.sp
.ti +2
To: fred, barney, wilma, betty
.sp
Addresses may also contain `!', `@' and `%' characters which are used
to separate hostnames and the final user name from each other.
This is primarily used to mail to users on other machines.
UUCP addresses are specified as
.sp
.ti +2
host1!host2!user
.sp
where there may be as many hosts as necessary to route the message
to the recipient user.
Here, the user's account is on \*Qhost2\*U
and that machine is connected to \*Qhost1\*U.
.I Domain
addresses (also called Arpanet, Internet, RFC822, and \*Qfully qualified\*U
addresses) are specified as
.sp
.ti +2
user@host.domain
.ti +2
user%host2.domain@host1
.sp
where \*Qdomain\*U is a domain name such as \*Q.berkeley.edu\*U or \*Q.com\*U.
As in the first example, the user is on \*Qhost2\*U, but that machine talks
to \*Qhost1\*U.
It is beyond the scope of this document to discuss in detail the ramifications
of inter-network mailing.
More information can be obtained through your system manager.
.PP
.I Mush
understands addresses containing a comment field.
Comment fields do not affect the destination address of mail being sent.
These fields are purely for
human legibility and may be specified according to the following constraints: 
.sp
Anything within angle brackets is an address; whatever is outside of the
address is considered a comment:
.sp
.ti +2
Dan Heller <zipcode!argv@cad.berkeley.edu>
.ti +2
Dan Heller <argv@zipcode.com>
.sp
Anything that has parentheses is a comment; whatever is outside of the
parentheses is considered the address:
.sp
.ti +2
zipcode!argv (Dan Heller)
.ti +2
argv@zipcode.com (Dan Heller)
.sp
Double quotes (") are treated just like parentheses:
.sp
.ti +2
"Dan Heller" zipcode!argv
.ti +2
"Dan Heller" argv@zipcode.com
.sp
If the comment is to contain a comma, the first case above may not be used;
you must use either the parenthesis or double-quote cases.
.sp
.ti +2
fred@flintstone.bed.rock (Fred Flintstone, Cave Man)
.sp
If the comment contains unbalanced quotes, unpredictable results may occur
.RI ( Mush
won't deliver the mail).
.sp
Since the angle brackets have the highest precedence, quotes or parentheses
may be used in conjunction with one another.
.sp
.ti +2
Yabba Dabba Doo (Fred Flintstone) <fred>
.ti +2
Scoobie "Doobie" Doo <scooby@shaggys.mystery.machine>
.PP
Multiple addresses may appear on a line:
.sp
.in +2
argv@zipcode.com argv@garp.mit.edu dheller
.in -2
.sp
Because there is no indication of comments (parenthesis, angle bracket,
or quotes), it is assumed that these are separate addresses and
.I Mush
inserts commas between these addresses accordingly.
It is for this reason that the user is encouraged to explicitly insert
commas between all mail addresses and not depend on the automation of comma
insertion to correctly separate addresses from one another.
.PP
Mail aliases may contain addresses of the form described above.
.sp
.nf
.in +2
.ta 1.5i
alias george	George Jetson <george@spacely.space.sprockets>
alias jane	Jane Jetson <jane@sky-high.appts>
alias group	george, jane
.in -2
.fi
.sp
You can mail using the alias as an address and it is expanded
accordingly.
You cannot, however, reference an alias and specify a
comment or another address at the same time.
.sp
.ti +2
To: The Jetsons <group>
.sp
The comment \*QThe Jetsons\*U is not retained when the alias \*Qgroup\*U
is expanded, because the entire address and comment are replaced by the
expansion.
.SH FILES
.nf
.ta 2.0i
/usr/spool/mail/*	Directory for incoming mail
~/Mail	Default \fBfolder\fR directory
~/mbox	File where old mail is saved
~/.mushrc	File giving initial \fIMush\fR commands
~/.mailrc	Alternate initialization file
~/.edXXXXXXX	Temporary for file for outgoing messages
~/.mushXXXXXX	Temporary mail file (copy of current folder)
.fi
.PP
Temporary files that are created by the program are always
created with read/write access to the owner only; group and other
permissions are never set.
This is also true for the /usr/spool/mail/* files.
All other files created by the user via commands internal or external
to the program have permissions set by the user's default umask.
If the umask is reset within the program, the mask remains
intact even after exiting.
Remember to set the variable
.B unix
before attempting to set the umask value.
.PP
If your system is using Sun Microsystem's NFS, take special note to
read the manual page for mount(1).
Filesystems mounted for read/write
access should be mounted as \*Qhard\*U NFS mounts or you may lose
mailboxes during a timeout during a write or update.
.PP
Filesystems that use RFS still have bugs to be ironed out in the way
of owners and permissions concerning utime(2).
.SH "SEE ALSO"
.IR Mail (1),
.IR binmail (1),
.IR csh (1),
.IR aliases (5),
.IR mount (1),
.IR mailaddr (7),
.IR sendmail (8),
.IR printf (3),
.IR execl (3),
.IR umask (1),
.IR utime (2).
.SH AUTHOR
The original
.I Mush
was written entirely by Dan Heller.
Code to support macros, line wrapping, and a whole lot of other miscellaneous
details, was written by Bart Schaefer, who gets his name in print
because he updated and proofread this manual.
Numerous others have supplied valuable suggestions
and assorted bits and pieces.
.PP
argv@sun.com       zipcode!argv
.SH DISCLAIMERS
.I Mush
contains no
.IR UNIX (TM)
sources and never has.
It is also not a modified version of any other mail user agent.
Similarities
with any other mailer may have been designed for compatibility reasons.
.PP
.I UNIX
is a trademark of AT&T.
.PP
The Flintstones and The Jetsons are trademarks of Hannah-Barbara Inc.
.SH BUGS
The curses interface uses the curses library.
The routines from the library that are used are the most basic and simple
so as to avoid possible bugginess that
different versions of UNIX might have.
However, one unavoidable problem is the reverse video mode.
Depending on your terminal,
the termcap entry for it, and the version of curses you are running,
the reverse video may make things worse than desired.
In such situations, the user should set the variable
.B no_reverse
to not get reverse video.
\&`^R' may still be entered at runtime in the curses
interface to toggle reverse video.
.PP
Toggling from the curses mode to the line mode to get the full
functionality of the shell/line mode is unfortunately necessary
in order to maintain the display in a sensible manner and to keep the
keystroke-command interface simple and \*Quser friendly\*U.
Mostly, such escapes are only necessary
for piping of commands and using the pick command.
Macros are a big help with this.
.PP
If the program is already running and the system [later] has to swap
and there is no swap space left, there may be problems.
One such problem is sending mail.
If this happens, then sending mail
fails and a segmentation fault from the spawned/forked child may occur
(unless the -v flag was given to mail).
The unsent letter is not removed from the editing file ($home/.edXXXXXX)
and may be recovered.
.PP
Many functions available to the line oriented mode (shell mode)
are not available to the tool mode.
For example,
.B pick
may not be directly accessed although experienced users may find that
typing pick commands within single backquotes in the \*QRange:\*U panel item
above the header window and then selecting a command that uses the range
does indeed pick messages.
This is mostly for selecting the \*Qdelete range\*U item
or the middle mouse button icon in the header panel.
.PP
Version 6.5.6 was the last version designed to run under SunWindows, and is
therefore the most recent version that functioned under SunOS 2.x.
Starting with versions 7.x, the interface used is SunView, and may have
a completely new set of problems in addition to those described below.
Also, some of those described below may have been eliminated, and remain
in this discussion only for completeness.
.PP
Shell escapes (of any kind) may be called only from the \*Qpipe\*U command
in the tool mode, should not be interactive, and should produce
output only to a file.
The reason for this is that there is no tty
.I window
in which to do input/output.
Since the interactive function-key binding interface has gone away, it is
unfortunately only possible to execute commands that have been pre-defined
in the initialization file.
Future revisions may correct these deficiencies.
.PP
The function keys and their ability to
.I work
has been variable depending on the version of SunWindows/SunView
your Sun Workstation has.  From time to time, it works, but when it
doesn't, it seems to be related to other user or system definable
dot-files or whatever.
.PP
Changing the value of the
.BR screen_win ,
.BR crt_win ,
or
.B msg_win
variables after the tool is running simply has no effect.
.PP
When using
.B vi
in the tool mode, the window is periodically one or more
lines \*Qshort.\*U
That is, scrolling is off by one line and you have to redraw the
window (using \*Qz.\*U in vi) to get it in sync again.  The problem
is caused by the window having less than 24 lines in the window.
Having the tty subwindow be
.I exactly
24 lines usually eliminates the problem.  This is a bug with SunView
and will not be fixed since Sun no longer supports it.
.PP
When running on full filesystems,
.I Mush
may complain or not even run since it needs temporary space with which
to work.
Instead of finding new filesystems on its own,
.I Mush
leaves this task up to the user.
The workaround is to set the variable
.B tmpdir
in the initialization file to be a writable place in a filesystem that
has enough disk space.
Note: some systems' setcwd() system call writes temporary information in
/tmp and this cannot be overridden.  You may get error messages such as
"file system full" even if your
.B tmpdir
variable is set to a directory in a partition other than that of /tmp.
There is nothing to be concerned about; chance are that you changed
directories and the setcwd() system call can't write to its temp file.
.PP
Repeated sequences of creating and destroying compose frames
uses up file descriptors in Sun OS 3.5, due to a bug where a destroyed
ttysw does not free up its fd's.
.PP
Most of the other known and documented bugs
are in the supplied README files accompanying the source.
The source is also an excellent place to look as many known bugs are
documented in comments.
A good way to track suspicious bugs is to use the
.B debug
command, but note that
this command is very difficult to use in curses mode.
SHAR_EOF
echo 'File mush.1 is complete' &&
chmod 0644 mush.1 ||
echo 'restore of mush.1 failed'
Wc_c="`wc -c < 'mush.1'`"
test 191116 -eq "$Wc_c" ||
	echo 'mush.1: original size 191116, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= mush.h ==============
if test -f 'mush.h' -a X"$1" != X"-c"; then
	echo 'x - skipping mush.h (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting mush.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'mush.h' &&
/* @(#)mush.h	(c) copyright 1986 (Dan Heller) */
X
#include "config.h"
X
#ifdef CURSES
X
#ifdef USG
#    define _USG
#    undef USG
#endif /* USG */
#ifdef SYSV
#    define _SYSV
#    undef SYSV
#endif /* SYSV */
#include <curses.h>
#if !defined(USG) && defined(_USG)
#    define USG
#endif /* USG */
#if !defined(SYSV) && defined(_SYSV)
#    define SYSV
#endif /* SYSV */
X
#else /* CURSES */
#include <stdio.h>
#if defined(SYSV) && defined(USG)
#include <termio.h>
#endif /* SYSV && USG */
#endif /* CURSES */
X
#include <ctype.h>
#include <errno.h>
#include <setjmp.h>
#include "strings.h"
X
extern char
X    *malloc(),		/* allocate memory */
X    *calloc(),		/* allocate and clear memory */
X    *realloc();		/* re-allocate memory */
X
extern void
X    free_vec(),		/* free a malloc'ed argv */
X    xfree();		/* free malloc'ed pointers */
X
#if defined(SUNTOOL) || defined(SUN_3_5) || defined(SUN_4_0) || defined(SUN_4_1)
#if !defined(BSD) && !defined(SYSV)
#    define BSD /* default to BSD */
#endif /* !BSD && !SYSV */
#if !defined(SUN_3_5) && !defined(SUN_4_0)
#    ifndef SUN_4_1
#        define SUN_4_1 /* default to sun 4.1 */
#    endif /* SUN_4_1 */
#    define SUN_4_0 /* 4.0 stuff needed too */
#endif /* !SUN_3_5 && !SUN_4_0 */
#ifdef SUN_4_0
#    undef SUN_3_5
#    undef SIGRET
#    define SIGRET void
#endif /* SUN_4_0 */
#endif /* SUNTOOL || SUN_3_5 || SUN_4_0 || SUN_4_1 */
X
#ifdef BSD
#define fputs Fputs	/* See comments in print.c */
#endif /* BSD */
X
#if defined(BSD) || defined(GETWD)
extern char *getwd();
#define GetCwd(buf,len)	getwd(buf)
#else
extern char *getcwd();
#define GetCwd(buf,len) getcwd(buf,len)
#endif /* BSD || GETWD */
X
#ifdef SUNTOOL
#    include <suntool/sunview.h>
#ifdef SUN_4_0
#    include <suntool/alert.h>
#endif /* SUN_4_0 */
#    include <suntool/textsw.h>
#    include <sys/ioctl.h>   /* for ltchars */
#else
#    include <sys/types.h>
#    include <signal.h>
#    ifndef SYSV
#	include <sys/time.h>
#	include <sys/ioctl.h>   /* for ltchars */
#    else
#	include <time.h>
#	include <fcntl.h>
#    endif /* SYSV */
#endif /* SUNTOOL */
X
#include <sys/stat.h>
#include <sys/file.h>
X
#ifdef SUNTOOL
#    include <suntool/panel.h>
#    include <suntool/canvas.h>
#    include <suntool/tty.h>
#    include <suntool/menu.h>
#    include <suntool/icon.h>
#    include <suntool/scrollbar.h>
#    include <suntool/icon_load.h>
#endif /* SUNTOOL */
X
/* if no maximum number of files can be found, we'll use getdtablesize() */
#ifdef _NFILE
#    define MAXFILES _NFILE
#else
#ifdef NOFILE
#    define MAXFILES NOFILE
#endif /* NOFILE */
#endif /* _NFILE */
X
#ifndef MAXPATHLEN
#define MAXPATHLEN BUFSIZ
#endif /* MAXPATHLEN */
X
#ifdef CTRL
#undef CTRL
#endif /* CTRL */
#define CTRL(c)		((c) & 037)
X
#define ESC 		'\033'
X
#define NO_STRING	""
#ifdef  NULL
#undef  NULL
#endif /* NULL */
#define NULL		(char *)0
#define NULL_FILE	(FILE *)0
#define DUBL_NULL	(char **)0
#define TRPL_NULL	(char ***)0
#ifdef putchar
#undef putchar
#endif /* putchar */
#define putchar(c)	(void) (fputc(c, stdout), fflush(stdout))
#ifdef SUNTOOL
extern int bell();
#else /* SUNTOOL */
#define bell()		(void) (fputc('\007', stderr), fflush(stderr))
#endif /* SUNTOOL */
X
/* For error recovery purposes, send keyboard generated signals to a special
X * routine (interrupt) to set a global flag (WAS_INTR) and return to the
X * calling routine which is responsible for checking the flag.  For both
X * on_intr() and off_intr() macros, initialize WAS_INTR to false.
X */
#define on_intr() \
X    turnoff(glob_flags, WAS_INTR), oldint = signal(SIGINT, intrpt), \
X    oldquit = signal(SIGQUIT, intrpt)
X
#define off_intr() \
X    (void) (turnoff(glob_flags, WAS_INTR), signal(SIGINT, oldint), \
X	    signal(SIGQUIT, oldquit))
X
/* Don't flush input when setting echo or cbreak modes (allow typeahead) */
#ifdef TIOCSETN
#ifdef stty
#undef stty
#endif /* stty */
#define stty(fd, sgttybuf)	ioctl(fd, TIOCSETN, sgttybuf)
#endif /* TIOCSETN */
X
/* for system-V machines that run termio */
#if defined(SYSV) && defined(USG)
#ifdef crmode
#undef crmode
#undef nocrmode
#endif /* nocrmode */
X
unsigned char vmin, vtime;
#define sg_erase  c_cc[2]
#define sg_flags  c_lflag
#define sg_kill   c_cc[3]
#define sg_ospeed c_cflag
#define gtty(fd, SGTTYbuf)	ioctl(fd, TCGETA, SGTTYbuf)
#undef stty
#define stty(fd, SGTTYbuf)	ioctl(fd, TCSETAW, SGTTYbuf)
#define echon()    (_tty.sg_flags |= (ECHO|ECHOE),    stty(0, &_tty))
#define echoff()   (_tty.sg_flags &= ~ECHO,   stty(0, &_tty))
#define cbrkon()   \
X	(_tty.sg_flags &= ~ICANON, _tty.c_cc[VMIN] = 1, stty(0, &_tty))
#define cbrkoff()  \
X	(_tty.sg_flags |= ICANON,_tty.c_cc[VMIN] = vmin,_tty.c_iflag |= ICRNL, \
X		_tty.c_cc[VTIME] = vtime, stty(0, &_tty))
#define savetty()  \
X	(void) gtty(0, &_tty), vtime = _tty.c_cc[VTIME], vmin = _tty.c_cc[VMIN]
#define cbreak()   cbrkon()
#define nocbreak() cbrkoff()
X
/* If curses isn't defined, declare our 'tty' and macros for echo/cbreak */
#ifndef CURSES
typedef struct termio SGTTY;
#define echom()    echon()
#define noechom()  echoff()
#define crmode()   cbrkon()
#define nocrmode() cbrkoff()
X
#else /* CURSES */
/* If curses is defined, use the echo/cbreak commands in library only
X * if curses is running.  If curses isn't running, use macros above.
X */
#define echom()    ((iscurses) ? echo(): echon())
#define noechom()  ((iscurses) ? noecho(): echoff())
#define crmode()   ((iscurses) ? cbreak() : cbrkon())
#define nocrmode() ((iscurses) ? nocbreak() : cbrkoff())
#endif /* CURSES */
#endif /* SYSV && USG */
X
#if !defined(USG)
#ifndef CURSES
/* if curses is not defined, simulate the same tty based macros */
typedef struct sgttyb SGTTY;
/* Do real ioctl calls to set the tty modes */
#define crmode()   (_tty.sg_flags |= CBREAK,  stty(0, &_tty))
#define nocrmode() (_tty.sg_flags &= ~CBREAK, stty(0, &_tty))
#define echom()    (_tty.sg_flags |= ECHO,    stty(0, &_tty))
#define noechom()  (_tty.sg_flags &= ~ECHO,   stty(0, &_tty))
#define savetty()  (void) gtty(0, &_tty)
#else /* CURSES */
#define echom()    echo()
#define noechom()  noecho()
#endif /* ~CURSES */
#endif /* ~USG */
X
/* With all that out of the way, we can now declare our tty type */
SGTTY _tty;
X
extern char
X    del_line,		/* tty delete line character */
X    del_word,		/* tty delete word character */
X    del_char,		/* backspace */
X    reprint_line,	/* usually ^R */
X    eofc,		/* usually ^D */
X    lit_next,		/* usually ^V */
X    complete,		/* word completion, usually ESC */
X    complist;		/* completion listing, usually tab */
X
/* These macros now turn on/off echo/cbreak independent of the UNIX running */
#define echo_on()	\
X    if (_tty.sg_flags && isoff(glob_flags, ECHO_FLAG)) nocrmode(), echom()
#define echo_off()	\
X    if (_tty.sg_flags && isoff(glob_flags, ECHO_FLAG)) crmode(), noechom()
X
#define strdup(dst, src) (xfree (dst), dst = savestr(src))
#define Debug		if (debug == 0) {;} else (void) wprint
X
#ifdef SYSV
#ifndef L_SET
#define L_SET	0
#endif /* L_SET */
#ifndef F_OK
#define F_OK	000
#define R_OK	004
#define W_OK	002
#define E_OK	001
#endif /* F_OK */
#ifdef u_long
#undef u_long
#endif /* u_long */
#define u_long	unsigned long
#ifndef HPUX
#define vfork   fork
#endif /* HPUX */
#ifndef SIGCHLD
#define SIGCHLD SIGCLD
#endif /* SIGCHLD */
#endif /* SYSV */
X
#if !defined(SUNTOOL) && !defined(CURSES)
X
#define TRUE		  1
#define FALSE		  0
#define print		  (void) printf
#define wprint		  (void) printf
#define print_more	  (void) printf
X
#endif /* !SUNTOOL && !CURSES */
X
#ifndef max
#define max(a,b) (((a) > (b)) ? (a) : (b))
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif /* max */
X
#if defined(CURSES) && (!defined(SUNTOOL))
#define wprint	(void) printf
#endif /* CURSES && (!SUNTOOL) */
X
#ifdef SUNTOOL
/* stdout may be closed */
#define printf wprint
#else /* !SUNTOOL */
#define ok_box print
#endif /* SUNTOOL */
X
#if defined(CURSES) || defined(SUNTOOL)
#define print_more	  turnon(glob_flags, CONT_PRNT), print
void print();	/* printf to window or curses or tty accordingly */
#endif /* CURSES || SUNTOOL */
X
#define ArraySize(o)	  (sizeof(o) / sizeof(*o))
X
#ifdef SUNTOOL
X
#define NO_ITEM		(Panel_item)0
#define NO_EVENT	(struct inputevent *)0
#define TIME_OUT	60	/* sleep 60 secs between mailchecks */
#define PIX_XOR		PIX_SRC ^ PIX_DST
#define ID		event_id(event)
#define l_width()	mush_font->pf_defaultsize.x /* width of letter */
#define l_height()	mush_font->pf_defaultsize.y /* height of letter */
#define Clrtoeol(w,x,y)	((void) pw_text(w, x, y, PIX_SRC, mush_font, blank))
X
/* Miscellaneous old-SunView cleanup */
#ifndef TTY_ARGV_DO_NOT_FORK
#define TTY_ARGV_DO_NOT_FORK (-1)
#endif
X
#endif /* SUNTOOL */
X
/* bits and pieces */
#define turnon(flg,val)   ((flg) |= (u_long)(val))
#define turnoff(flg,val)  ((flg) &= ~(u_long)(val))
#define ison(flg,val)     ((u_long)(flg) & (u_long)(val))
#define isoff(flg,val)    (!ison((flg), (val)))
#define set_replied(n)	  \
X	if (isoff(msg[n].m_flags, REPLIED)) \
X	    turnon(glob_flags, DO_UPDATE), turnon(msg[n].m_flags, REPLIED)
#define set_isread(n)	  \
X	if (turnon(msg[n].m_flags, DO_UPDATE) && ison(msg[n].m_flags, UNREAD)) \
X	    turnon(glob_flags, DO_UPDATE), turnoff(msg[n].m_flags, UNREAD)
X
#define in_pipe() (ison(glob_flags, DO_PIPE|IS_PIPE))
#define in_macro() (ison(glob_flags, LINE_MACRO|IN_MACRO))
#define line_macro(s) (void) (turnon(glob_flags, LINE_MACRO), mac_push(s))
#define curs_macro(s) (void) (turnon(glob_flags, IN_MACRO), mac_push(s))
#define Ungetstr(s) (void) (turnon(glob_flags, QUOTE_MACRO), mac_push(s))
X
/* global conditions */
#define is_shell (mailfile && *mailfile)
X
/* msg lists represented by bits (8 should be replaced by sizeof(char) */
#define clear_msg_list(list)  	((void) bzero(list, (msg_cnt+7)/8))
#define msg_bit(list, n)	((list[(n) / 8] >> ((n) % 8)) & 1)
#define set_msg_bit(list, n)	(list[(n) / 8] |= (1 << ((n) % 8)))
#define unset_msg_bit(list, n)  (list[(n) / 8] &= ~(1 << ((n) % 8)))
#define bput(S1, S2, Len, op)   				\
X		do { 						\
X		    register char *s1 = S1, *s2 = S2; 		\
X		    register int len = Len; 			\
X		    while(len--) 				\
X			*s2++ op *s1++; 			\
X		} while (0)
#define bitput(m1,m2,len,op)	bput(m1, m2, (((len)+7)/8), op)
X
/* convenience and/or readability */
#define when		  break;case
#define otherwise	  break;default
#define lower(c)	  (isupper(c)? tolower(c): c)
#define Lower(c)	  (c = lower(c))
#define upper(c)	  (islower(c)? toupper(c): c)
#define Upper(c)	  (c = upper(c))
#define skipspaces(n)     for(p += (n); *p == ' ' || *p == '\t'; ++p)
#define skipdigits(n)     for(p += (n); isdigit(*p); ++p)
#define ismsgnum(c)       (isdigit(c)||c=='.'||c=='^'||c=='$'||c=='*')
#define skipmsglist(n)\
X    for(p += (n); ismsgnum(*p) || index(" \t,-{`}", *p); ++p)\
X	if (*p != '`' || !p[1]) {;} else do ++p; while (*p && *p != '`')
X
/* define a macro to declare unsigned-long bits */
#define ULBIT(bit)		((u_long)1 << (u_long)(bit))
X
/* various flags */
u_long   glob_flags;	/* global boolean flags thruout the whole program */
#define DO_UPDATE   ULBIT(0) /* folder has been modified -- update it */
#define REV_VIDEO   ULBIT(1) /* reverse video for curses or toolmode */
#define CONT_PRNT   ULBIT(2) /* continue to print without a '\n' */
#define DO_SHELL    ULBIT(3) /* run a shell even if no mail? (true if tool) */
#define DO_PIPE     ULBIT(4) /* if commands are piping to other commands */
#define IS_PIPE     ULBIT(5) /* true if commands' "input" comes from a pipe */
#define IGN_SIGS    ULBIT(6) /* true if catch() should not longjmp */
#define IGN_BANG    ULBIT(7) /* ignore ! as a history reference */
#define ECHO_FLAG   ULBIT(8) /* if true, echo|cbreak is ON, echo typing (-e) */
#define IS_GETTING  ULBIT(9) /* true if we're getting input for a letter */
#define PRE_CURSES  ULBIT(10) /* true if curses will run, but hasn't started */
#define READ_ONLY   ULBIT(11) /* -r passed to folder() for read only */
#define REDIRECT    ULBIT(12) /* true if stdin is being redirected */
#define WAS_INTR    ULBIT(13) /* catch interrupts, set this flag (signals.c) */
#define WARNING     ULBIT(14) /* if set, various warning messages are printed */
#define NEW_MAIL    ULBIT(15) /* new mail has arrived; mush is busy or closed */
#define CNTD_CMD    ULBIT(16) /* curses.c -- promotes "...continue..." prompt */
#define IS_SENDING  ULBIT(17) /* was run to send mail, not run as a shell */
#define MIL_TIME    ULBIT(19) /* if $mil_time is set, use 24hr time fmt */
#define DATE_RECV   ULBIT(20) /* $date_received: show date received on msgs */
#define IN_MACRO    ULBIT(21) /* input is currently being read from a macro */
#define LINE_MACRO  ULBIT(22) /* escape to line mode from curses in progress */
#define QUOTE_MACRO ULBIT(23) /* protect current macro from recursive expan.. */
#define NEW_FRAME   ULBIT(24) /* toolmode should build a new frame for pager */
#define HELP_TEXT   ULBIT(25) /* create textsw frame for paging help messages */
#define CORRUPTED   ULBIT(26) /* error loading new mail has occurred */
X
/* flags to control composition */
#define VERBOSE		ULBIT(0)  /* verbose flag for sendmail */
#define INCLUDE		ULBIT(1)  /* include msg in response */
#define INCLUDE_H	ULBIT(2)  /* include msg with header */
#define EDIT		ULBIT(3)  /* enter editor by default on mailing */
#define SIGN		ULBIT(4)  /* auto-include ~/.signature in mail */
#define DO_FORTUNE	ULBIT(5)  /* add a fortune at end of msgs */
#define EDIT_HDRS	ULBIT(6)  /* user edits headers using editor */
#define SEND_NOW	ULBIT(7)  /* send without further changes */
#define NO_SIGN		ULBIT(8)  /* override SIGN and DO_FORTUNE */
X
/* msg flags */
#define PRINTED		ULBIT(4)  /* sent through lpr command */
#define NO_HEADER	ULBIT(6)  /* don't print header of message */
#define DELETE		ULBIT(7)
#define OLD		ULBIT(8)
#define UNREAD		ULBIT(9)
#define UPDATE_STATUS	ULBIT(10) /* change status of msg when copyback */
#define NO_PAGE		ULBIT(11) /* don't page this message */
#define INDENT		ULBIT(12) /* indent included msg with string */
#define NO_IGNORE	ULBIT(13) /* don't ignore headers */
#define PRESERVE	ULBIT(14) /* preserve in mailbox unless deleted */
#define M_TOP		ULBIT(15) /* just print the top of msg (same as pre) */
#define FORWARD		ULBIT(16) /* Forward messages into the message buffer */
#define REPLIED		ULBIT(17) /* Messages that have been replied to */
#define NEW_SUBJECT	ULBIT(18) /* new subject regardless of $ask (mail -s) */
#define SAVED		ULBIT(19) /* when message has been saved */
#ifdef MSG_SEPARATOR
#define NO_SEPARATOR	ULBIT(20) /* don't include message separator lines */
#endif /* MSG_SEPARATOR */
X
#define M_PRIORITY(n)	ULBIT(21+(n))
/* It is possible to reset MAX_PRIORITY to as high as 10 */
#define MAX_PRIORITY	5
X
#define	MAXMSGS_BITS	MAXMSGS/sizeof(char)	/* number of bits for bitmap */
X
struct msg {
X    u_long m_flags;
X    long   m_offset;	/* offset in tempfile of msg */
X    long   m_size;	/* number of bytes in msg */
X    int    m_lines;	/* number of lines in msg */
X    char   *m_date_recv;/* Date user received msg (see dates.c for fmt) */
X    char   *m_date_sent;/* Date author sent msg (see dates.c for fmt) */
} msg[MAXMSGS];
X
struct options {
X    char *option;
X    char *value;
X    struct options *next;
} *set_options, *aliases, *ignore_hdr, *functions, *fkeys, *own_hdrs;
X
#define chk_option(v,f)	chk_two_lists(do_set(set_options,(v)), (f), "\t ,")
X
struct cmd {
X    char *command;
X    int (*func)();
};
extern struct cmd ucb_cmds[];
extern struct cmd cmds[], hidden_cmds[];
X
struct expand {
X    char *orig;		/* string beginning with substring to be expanded */
X    char *exp;		/* result of expansion of substring */
X    char *rest;		/* rest of the original string beyond substring */
};
X
FILE
X    *tmpf,		/* temporary holding place for all mail */
X    *mask_fopen(),	/* open a file with umask 077 (permissions 600) */
X    *open_file(),	/* open a file or program for write/append */
X    *lock_fopen(),	/* open and lock a file as an atomic operation */
X    *popen();		/* this should be in stdio.h */
X
extern char
X    *sys_errlist[],    /* system's list of global error messages */
X    **environ;		/* user's environment variables */
X
extern int errno;	/* global system error number */
jmp_buf jmpbuf;		/* longjmp to jmpbuf on sigs (not in tool) */
X
char
X    debug,		/* debug causes various print statements in code */
X    tempfile[MAXPATHLEN],	/* path to filename of temporary file */
X    msg_list[MAXMSGS_BITS],	/* MAXMSGS bits of boolean storage */
X    **alternates,	/* alternates list --see alts() */
X    *cmd_help,		/* filename of location for "command -?" commands. */
X    *login,		/* login name of user */
X    *mailfile,		/* path to filename of current mailfile */
X    **ourname,		/* the name and aliases of the current host */
X    **known_hosts,	/* the names of all hosts connected via uucp */
X    *prompt,		/* the prompt string -- may have %d */
X    *format_prompt(),	/* function to format prompts from the prompt string */
X    *escape,		/* the "tilde escape" when inputting text to letter */
X    *hdrs_only,		/* true if -H flag was given --set to args */
X    *hdr_format,	/* set to the header format string; referenced a lot */
X    *spoolfile,		/* MAILDIR/$USER in a string -- this is used a lot */
X    *msg_get(),		/* find start of message and return From_ line */
X    *do_range(),	/* parse a string converting to a "range" of numbers */
X    *getpath(),		/* static char returning path (expanding ~, +, %, #) */
X    *getdir(),		/* uses getpath() to expand and test directory names */
X    *do_set(),		/* set/unset an option, alias, ignored-hdr */
X    *reverse(),		/* reverse a string */
X    *trim_filename(),	/* remove or condense leading file name path */
X    *prog_name,
X
X    /* from loop.c */
X    **make_command(),	/* build a command vector (argv) */
X    **mk_argv(),	/* given a string, make a vector */
X    *variable_stuff(),	/* return information about variables */
X    *check_internal(),	/* test or evaluate internal variables */
X
X    /* from dates.c */
X    *Time(),		/* returns string expression of time (takes args) */
X    *date_to_ctime(),	/* convert a date into ctime() format */
X    *date_to_string(),	/* returns a string described by parse_date() */
X    *msg_date(),	/* return a string of the date of a message */
X    *parse_date(),	/* parse an ascii date, and return message-id str */
X    *rfc_date(),	/* create a date string compliant to RFC822 */
X
X    /* from hdrs.c */
X    *cc_to(),     	/* when responding, return str which is the cc-list */
X    *compose_hdr(),	/* passes hdr_format to format_hdr() for displays */
X    *format_hdr(),	/* returns a formatted line describing passed msg # */
X    *header_field(),    /* the line in msg described by arg (message header) */
X    *reply_to(),	/* who do we reply to when responding */
X    *subject_to(),      /* when responding, return str which is the subject */
X
X    /* addrs.c */
X    *alias_to_address(),/* convert a name[list] to "real" names */
X    *bang_form(),	/* construct a !-style form of an address */
X    *get_name_n_addr(), /* get name and addr from a well-formed address */
X    *set_header(), 	/* [interactive] proc to set/display to/subject/cc */
X    *wrap_addrs();	/* insert newlines in between headers */
X
int
X    last_msg_cnt,	/* when checking for new mail, save the last msg_cnt */
X    msg_cnt,		/* total number of messages */
X    crt,		/* min number of lines msg contains to invoke pager */
X    current_msg,	/* the current message we're dealing with */
X    exec_pid,		/* pid of a command that has been "exec"ed */
X    hist_no,		/* command's history number */
X    iscurses,		/* if we're running curses */
#if defined(SUNTOOL) || defined(lint)
X    istool,		/* argv[0] == "xxxxtool", ranges from 0 to 2 */
#else /* !SUNTOOL */
#define istool 0
#endif /* SUNTOOL */
X    n_array[128],	/* array of message numbers in the header window */
X    screen,		/* number of headers window can handle */
X    wrapcolumn,		/* compose mode line wrap, measured from left */
X
X    close_lock(), 	/* unlock and close a file opened by lock_fopen() */
X
X    mush_quit(), do_alias(), respond(), cd(), sh(), stop(),
X    folder(), folders(), merge_folders(), do_undigest(), mark_msg(),
X    save_msg(), delete(), do_mail(), lpr(), alts(), set(), do_hdrs(),
X    save_opts(), preserve(), sort(), readmsg(), edit_msg(), eval_cmd(),
X    do_pick(), print_help(), question_mark(), do_from(), my_stty(),
X    do_version(), disp_hist(), source(), do_echo(), ls(), pipe_msg(),
X    await(), nopenfiles(), file_to_fp(),
X    check_new_mail(), get_new_mail(), show_new_mail(),
X    Setenv(), Unsetenv(), Printenv(), msg_flags(), toggle_debug();
X
#ifndef SIGRET
#define SIGRET int
#endif /* SIGRET */
SIGRET
X    rm_edfile(),	/* remove letter-compose file on interrupts */
X    stop_start(),	/* handle job control signals */
X    bus_n_seg(),	/* handle runtime segfaults -- exit gracefully */
X    sigchldcatcher(),	/* account for terminated child processes */
X    catch(),		/* catch user (keyboard) generated signals */
X    intrpt();		/* handle interrupts when we don't want to */
X
long
X    spool_size,		/* size of spool mail regardless of current folder */
X    last_size,		/* the last size of the mailfile since last check */
X    time();		/* satisfy lint */
X
void
X    error(), getmail(), mail_status(), sign_letter(),
X    init(), display_msg(), cleanup(), fs_error();
X    /* printf(), fclose(), fflush(), fputs(), fputc() */
#ifdef TIOCGLTC
struct ltchars ltchars;			/* tty character settings */
#endif /* TIOCGLTC */
#ifdef BSD /* (TIOCGETC) */
struct tchars  tchars;			/* more tty character settings */
#endif /* BSD (TIOCGETC) */
X
#ifdef CURSES
X
#define STANDOUT(y,x,s) standout(), mvaddstr(y,x,s), standend()
#define redraw()	clearok(curscr, TRUE), wrefresh(curscr)
X
int
X    curses_init();	/* interpret commands via the curses interface */
#endif /* CURSES */
X
int
X    mac_push(),		/* set up a string as a macro */
X    bind_it();		/* bind strings to functions or macros */
X
void
X    mac_flush();	/* Abandon macro processing (on error) */
X
#ifdef SUNTOOL
void
X    timeout_cursors(), do_file_dir(), toggle_mail_items(), ok_box(),
X    read_mail(), opts_panel_item(), view_options(), toolquit(), wprint(),
X    update_list_textsw(), check_icons();
X
char
X    *find_key(),	/* pass x,y coords to find which function key assoc. */
X    *panel_get(),      	/* returns what has been typed in a panel item */
X    *tool_help,		/* help for tool-related things (sometimes, overlap) */
X    *more_prompt,	/* when NULL, we're paging a msg; else pager prompt */
X    blank[128];		/* use to clear to end of line */
X
int
X    time_out,		/* time out interval to wait for new mail */
X    is_iconic;		/* set if the mushview window is iconic. */
X
Notify_value
X    do_check(),		/* check for new mail on timeout */
X    destroy_proc(),	/* Destroy procedure. */
X    my_wait3(),		/* Handle wait for child exit */
X    scroll_textwin(),	/* Do fancy TEXTSW scrolling */
X    edit_msg_textwin();	/* Auto-positioning in compose TEXTSW */
X
Frame tool;		/* Main frame. */
Frame compose_frame;    /* Compose frame. */
Textsw pager_textsw;	/* for "paging" messages and other lists.. */
Textsw mfprint_sw;	/* Textsw in main mush frame for wprint() */
Canvas hdr_sw; 		/* Canvas for message headers */
Tty tty_sw; 		/* subwindow which forks a shell (usually editor) */
X
Pixwin
X    *hdr_win;		/* pixwin for message headers */
X
struct pixfont *mush_font;	/* array of fonts */
X
struct itimerval mail_timer;	/* frequency to check for new mail */
X
extern Cursor l_cursor, m_cursor, r_cursor;
extern Icon mail_icon;
X
/* When trapping events that represent scrolling actions */
typedef enum {
X    MUSH_SCROLL_TO,
X    MUSH_SCROLL_RELATIVE,
X    MUSH_SCROLL_IGNORE,
X    MUSH_SCROLL_PASS_EVENT
} Scroll_action;
#endif /* SUNTOOL */
SHAR_EOF
chmod 0644 mush.h ||
echo 'restore of mush.h failed'
Wc_c="`wc -c < 'mush.h'`"
test 23670 -eq "$Wc_c" ||
	echo 'mush.h: original size 23670, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= options.c ==============
if test -f 'options.c' -a X"$1" != X"-c"; then
	echo 'x - skipping options.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting options.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'options.c' &&
/* @(#)options.c    (c) copyright 10/10/88 (Dan Heller, Bart Schaefer) */
X
#include "mush.h"
#include "options.h"
X
/*
X * NOTE:  Any word flag which is a prefix of another word flag must be
X *  listed AFTER the flag it prefixes in the list below
X */
X
char *word_flags[][2] = {
X    { "-bcc",		"-b" },
X    { "-blindcarbon",	"-b" },
X    { "-blind",		"-b" },
X    { "-carbon",	"-c" },
X    { "-cc",		"-c" },
X    { "-copy",		"-c" },
X    { "-curses",	"-C" },
X    { "-debug",		"-d" },
X    { "-draft",		"-h" },
X    { "-echo",		"-e" },
X    { "-folder",	"-f" },	/* Maybe -file should become -f too? */
X    { "-file",		"-F" },	/* Don't really like -file for -F */
X    { "-headerfile",	"-h" },
X    { "-headers",	"-H" },
X    { "-initialize",	"-I" },
X    { "-init",		"-I" },
X    { "-interactive",	"-i" },
X    { "-interact",	"-i" },
X    { "-mailbox",	"-m" },
X    { "-message",	"-h" },
X    { "-noheaders",	"-N" },
X    { "-noinit",	"-n" },
X    { "-readonly",	"-r" },
X    { "-send",		"-U" },
X    { "-shell",		"-S" },
X    { "-source",	"-F" },	/* This is better for -F */
X    { "-subject",	"-s" },
X    { "-timeout",	"-T" },
X    { "-toolhelp",	"-2" },
X    { "-tool",		"-t" },
X    { "-user",		"-u" },
X    { "-verbose",	"-v" },
X    { "-visual",	"-C" },
X    { NULL,		NULL }	/* This must be the last entry */
};
X
fix_word_flag(argp)
register char **argp;
SHAR_EOF
true || echo 'restore of options.c failed'
fi
echo 'End of  part 18'
echo 'File options.c is continued in part 19'
echo 19 > _shar_seq_.tmp
exit 0
exit 0 # Just in case...
-- 
Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
Sterling Software, IMD           UUCP:     uunet!sparky!kent
Phone:    (402) 291-8300         FAX:      (402) 291-4362
Please send comp.sources.misc-related mail to kent@uunet.uu.net.