[comp.sources.unix] REPOST v14i039: Mail User's Shell, version 6.0, Part07/14

rsalz@bbn.com (Rich Salz) (04/16/88)

Submitted-by: island!argv@sun.com (Dan Heller)
Posting-number: Volume 14, Issue 39
Archive-name: mush6.0/part07

NOTE:  This is a repost of part 6, despite what this and the previous
	subject line both said!  -rich $lz

#! /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 6 (of 14)."
# Contents:  cmd_help fkeys.c select.c
# Wrapped by rsalz@fig.bbn.com on Wed Apr 13 20:04:47 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'cmd_help' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'cmd_help'\"
else
echo shar: Extracting \"'cmd_help'\" \(16430 characters\)
sed "s/^X//" >'cmd_help' <<'END_OF_FILE'
X/* @(#)cmd_help	1.4	10/28/86 (Dan heller) */
X
X%?%
The `?' will give you a list of legal commands.  Most commands
accept -? as an option.  This will give you specialized help
with that particular command.
X%%
X
X%ignore%
usage: ignore/unignore [headers]
Use this command to set the message headers you would like not
to be printed when you read a message. If no header specified,
then a list of all headers currently being ignored is printed.
You must specify a header for unignore.
X
You can set the variable "alwaysignore" to force normally
ignored headers to be ignored while saving messages, forwarding
messages or including messages into message buffers.
X%%
X
X%set%
usage: set/unset [variable] [= value]
set by itself prints values for variables in its group
To set a boolean variable (on or off), "set variable"
To set a variable's value to a string, use:
set variable = 'value'
X
If you want double-quote's or white-space embedded in
a string, encase the string in single quotes.  If you
want single quotes in a string, encase the string in
double quotes.
X
Type "set ?all" for a list of all settable variables.
X"set ?variable_name" for help on a single variable.
X%%
X
X%readmsg%
You can read messages in different ways.  "type" and "print"
will print the current message.  "top" will only print the
first N lines of the current message where N is the value of
the variable "crt".  "next" will go to the next unread message
and print that. "previous" will go back and read the first
unread message previous to the current. ^ will print the first
message, $ will print the last.
All can be followed by a message list and each message in
that list will be printed (or piped to other commands).
X%%
X
X%alts_help%
usage: alts [hostnames]
alts contains a list of hostnames on which you have an account
Normally, when you respond to all recipients of mail, your
account name will be listed and you send yourself mail. If you
don't have metoo set, then your name will be removed from the
mailing list if your login name is on the list and the host
specified is in the alternates list.  `*' matches all hostnames
and only the login name is tested.
X%%
X
X%source_help%
usage: source/saveopts [file]
source/saveopts will load/save all variable settings, options,
aliases, cmd's, ignored headers ... everything you can set,
it loads or saves. The file named used follows these rules:
X
X1) if a filename is given, that file is used.
X2) file described by the environment variable MAILRC
X3) user's home directory: .mailrc
X%%
X
X%general%
This is the general help message. To get help on a specific
command, try "command -?". Extended help is given by typing
X`help item' where item is one of:
X    path, msg_list, prompt, hdr_format.
Help with msg_list is highly advisable!
X
Type "?" to get a list of available commands.  Try "? command"
to get help on the particular command that you specify.
X%%
X
X%path%
Whenever "path" is specified, the following syntax is legal besides the
normal path addressing scheme used by unix.
X~[user]     -- the home directory of specified user (yours by default)
X%[user]     --/usr/spool/mail/login_name [user_name] (yours by default)
X+file       --the directory described by `set folder'; file is `file'
X%%
X
X%msg_list%
A "msg_list" references one or more messages.  The user specifies
a group of messages according to a special syntax.
X
X*      All messages.
X^      The first message.
X$      The last message.
X.      The current message.
N-M    A range of messages between N and M.
X
In the last case, N and M may be * ^ $ . or digits referencing
explicit message numbers.  The range must be in ascending order.
X
You can also negate messages by placing the message list inside
braces, `{' `}' -- thus, the expression "2-19 {11-14}" references
messages 2 through 19 except for those between 11 through 14.
X
Commands can be "piped" to one another, because the return
value of a command is a msg_list, not text.
pick -f fred | lpr   will find all messages "from fred" and
send them to the printer.
X
Commands dealing with more than one message process them in
order -- not necessarily the order specified.  Thus, the command,
save 1-5 9 7 6 file
will save the messages in ascending order; not as specified.
X%%
X
X%preserve_help%
usage: preserve [msg_list]
Preserve saves deleted or read messages in your mailbox.
Without explicitely setting preserve, all mail that you
read will be saved in ~/mbox (or set mbox).  If you set
X"hold", then this is equivalent to preserving each message
as you read it.
X%%
X
X%save_help%
usage: save/write/copy [!] [msg_list] [filename]
X
If no filename is specified, ~/mbox (or set mbox) is used.
Save and write will append msg if `file' already exists
Specifying the `!' will overwrite file (e.g. erasing it first).
To save messages to a filename beginning with a digit,
escape the filename with a backslash (\)
X`write' will write message without the headers (msg body only).
Save and write both mark messages for deletion unless "keepsave"
is set.  Copy is identical to save except that messages are not
marked for deletion (identical to having keepsave set).
X%%
X
X%lpr%
use: lpr [-n] [-h] [msg_list]
X  -n         print body of message only (not headers)
X  -h         print all headers with message body (default true)
X  -Pxx       print on printer xx
X%%
X
X%respond_help%
usage: replysender/replyall [msg_list] [mail_flags] [users]
Replysender only replies to the sender and replyall responds
to everyone on the To: and Cc: lines of the message.
X
The commands "repond", "reply", and "r" are identical to
X"replysender." The command, "R" is identical to "replyall."
X
If a message list is indicated, then each message on the list is
replied to in the same manner.  All other arguments are passed
to the mail command ('mail_flags' and 'users').
X
Type "mail -?" for information on legal mail flags.
X%%
X
X%sort_help%
usage: sort [-] [d | a | s | S | R]
X  d         sort according to date received
X  a         author (alphabetical)
X  s         subject ignoring Re: as part of the subject
X  R         subject (alphabetical)
X  S         by status
The optional `-' flag will reverse the order of sorting
By default (no arguments), sort sorts messages by status:
New, unread messages are first, followed by preserved messages
and finally the deleted messages are placed at the end
X%%
X
X%pick%
use: pick [-r msg_list] [-d [-][date] ] [-s|f|t]] [-x] [-i] [-h hdr] [<pat>]
Search for patterns within messages. Entire messages are searched
for <pattern> unless -s, -f, -t, or -h is specified.
Only one of -s, -f, -t, -d and -h can be specified at once.
X-r msg_list  restrict the range of messages search to msg_list
X-d: print message headers on or after [`-' before] `date' (no patterns).
X-h hdr   requires a header to be searched for.  Pattern searched in that hdr.
X     `date' is of the form: month/date/year
X      Omitted fields default to today's values. Examples:
X      pick -d 4/20     msgs on or after Apr 20, this year
X      pick -d -/2/85   on or before the 2nd, this month, 1985
X      pick -d /        finds today's messages only.
X    At least one `/' char must be used in date.
X    There is no strong date checking; 2/30 would be considered valid
X-s search for pattern in the "subject" headers only.
X-f search for pattern in the "from" field (author) only.
X-t search for pattern in the "to" field.
X-i ignore case of letters.
X-x return those messages which do NOT match.
X%%
X
X%alias%
options for alias:
alias                           print all namelists
alias name                      print namelist associated with name
alias name namelist             set "name" to value of namelist.
unalias namelist                unalias names in namelist
X
A "namelist" consists of one or more addresses. An address
may be a name already set to another list, valid user, file
or program.  Filenames must be full pathnames beginning with
a '/' (or a ~ expanding to a home directory).  A "program"
must start with a pipe and be encased in quotes:
X
X    "|program_name"
X
The command, "expand", will print addresses (including sublists)
associated with the given alias.
X%%
X
X%from%
With no arguments, from will print the current message's header.
If given a message list, from will print the headers of those
messages which are in the list.
X
The special arguments, `-' and `+' can be given to move the
current message pointer to the previous or next message
respectively while also printing that message's header.
X
If a message list was given in addition to `-' or `+', then
the current message pointer will be set to the first or last
message, respectively, in the message list given.
X
from - 10-30 {16}
will print the headers of messages 10 through 30 except for
message 16 and set the current message pointer to 10.
X
pick -f Dan | from +
will print the headers of all messages that contain Dan in
in the author's name and set the current message pointer to
the last one of that kind in the list.
X
from +
will print the header of the message after the current message
and increment the current message pointer to the next message.
X%%
X
X%own_hdrs%
Here is where you set, unset or view your own message headers.
These headers are included in all your outgoing mail.
X
options for my_hdrs:
my_hdr                          all headers
my_hdr header                   value associated with header
my_hdr header: string           set header to string
un_hdr header                   unset header
X%%
X
X%fkey_help%
fkey's are function key settings in Suntools (graphics) mode
When run as a tool (-t on command line), choose the Options Item,
and the function key menu option.
X%%
X
X%func_help%
cmd's are just like aliases in the c-shell.
cmd                     view all commands
cmd `command'           value associated with command
cmd `command' "value"   set command to value
uncmd `command'         unset command
X
If you want to reference history commands within a cmd,
escape the ! with a backslant. For example:
X
mail> cmd r 'replysender \!* ; delete -t'
X
will reply using whatever arguments you will have given
on the command line and then delete that message and
then print the next message (-t argument to "delete").
X%%
X
X%headers%
usage: headers [+ | - | N] [-H:c]
print out a screenful of headers.
X+  print the next screenful.
X-  print the previous screenful.
N  (where N is a number) print a screenful starting at N.
set show_deleted to list deleted messages.
cmd h headers        look like UCB-Mail
cmd H Headers        show deleted messages (or set show_deleted)
cmd z headers +      `z' is next screenful
X
Arguments to the headers command include -H:c where `c' is one of
X    n    just print messages headers of NEW messages
X    d    deleted messages
X    u    unread messages
X    o    old messages
X    r    messages that have been replied to
X    a    all messages (mostly for the command line argument -H:c)
X
piping to headers will print the headers of the "output" messages.
X%%
X
X%hdr_format%
set hdr_format="string" for changing the display of message headers.
The string uses printf style formatting and follows these conventions:
X    %f  "from" field (author).
X    %a  the address of the author.
X    %n  the name of the author.
X    %t  "to" field (recipients).
X    %d  date of the message.
X    %T  the time only of the message
X    %N  the day number of the month of the message
X    %D  the day or the week (Sun, Mon, etc.)
X    %M  the month name of the message
X    %Y  the year of the message
X    %s  subject of the message.
X    %l  number of lines in the message.
X    %c  number of characters (bytes) in the message.
X    \n  a newline
X    \t  a tab.
A field specifier may be used.  Thus, %20f will print the first 20
characters of the from line.  No matter what the formatting string,
the message number followed by a '>' (if current message) is printed.
X%%
X
X%folder_help%
usage: folder [-N] [-r] [!] [ %[user] | # | & | file ]
Change current folder.
No arguments prints current folder.
X-N: No headers are displayed upon entering new folder (also command line).
X-r: read only mode (you won't be able to write changes to this folder).
If `!' is specified, current folder is not updated.
X%[user] folder to /usr/spool/mail/[user] (you default)
X#  folder accessed previous to current folder
X&  "mbox" -- default is ~/mbox; or set mbox = "file"
X%%
X
X%prompt%
set prompt = "string"
X"string" is follows printf style formatting conventions:
X    \t, \n will be replaced by a tab or newline respectively.
X    %m	 current message number
X    %t	 total number of messages
X    %d	 number of deleted messages
X    %u	 number of unread messages
X    %n	 number of new messages
X    %f	 name of the current working folder
X    %T	 current time
X    %D	 day of the week
X    %Y	 year
X    %M	 month
X    %N	 number of the day in the month (date)
X%%
X
X%quit_help%
usage: quit/exit",
quit will update your mailbox; if new mail has come in, you will be
told so and given an option whether to really quit or not.
X"exit" will leave mail not updating your mailbox nor check for new mail.
X%%
X
X%ls%
The ls command is exactly like the UNIX command, "ls."
All arguments are the same.  The variable "lister" can
be set to always default to the same arguments avoiding
having to specify them all the time.  The "folders"
command is nothing more than doing "ls $folder" from
the Mush prompt.
X%%
X
X%shell%
usage: sh [command]
If a "command" is given, that UNIX command will be executed
under the Bourne shell. If no command is specified, then an
interactive shell will be started. The environment variable
SHELL or the local mail shell variable shell  describes the
shell to invoke.  If none is set, then the default shell is
defined by the system administrator (currently set to csh).
X
Users on systems with job control will probably have little
use for the sh command.
X%%
X
X%stop%
The stop command sends a stop signal to the mail shell.
It is equivalent to ^Z as it will stop the process.
Since the shell never needs to be exited, the command
X'q' may be aliased to "stop" and the shell may have,
X% alias 'mail   ?mush'
which will bring mush into the foreground rather than
having to invoke a new shell.  New mail will be read 
into the shell automatically and much time and energy 
is saved.
X%%
X
X%curses%
The curses-based interface for Mush does not require a graphics
display, but does requires a terminal which can handle upline
cursor movement capabilities.  All commands are one key-stroke
commands and are executed instantaneously.  A list of curses
commands is given by using the `?' key in curses mode.
X%%
X
X%bind%
Binding is done for the curses interface only.  It allows
the user to bind keystrokes or key sequences to commands.
X
To bind keystrokes that are control characters, you must use
the notation: "\CX" where "X" is in upper-case and it represents
the control key you want to use. "\CN" would be control-N; "\n"
is carriage return.  You may not bind keyboard generated signals;
for most users, those key sequences are control-C and control-\.
For users with job control, control-Z and control-Y are ignored.
To reference the escape key, use the string, "\E".
X
The spacebar may not be bound since it is the only way to return
to the main level from the "...continue..." prompt.
X
Trying to bind a key sequence which prefixes another sequence
is an error and the user is warned that the longer binding will
not work.
X
As always, -? will give help.
X%%
X
X%msg_flags%
usage: flags [msg_list [N O R D P U R r] ]
This command displays the state of messages as seen by the internals
of Mush.  This is not a documented command, so don't tell anyone.
If a list is given (or piped), it will tell which bits of the message
are set: New, Old, Read, Deleted, Preserved, Unread, Read, and replied.
If any (one or more) of the optional bits are given, then it will set
the appropriate bit in the list given.  As usual, if no list is given,
then the current message is used (or set bits on a pipe).
X%%
X
X%setenv%
usage: setenv VARIABLE [value]
X
Variable names may be any string, but traditionally environment variables
are all upper case.  If no "value" is specified, then the variable name
will be set to an empty string.  If the value contains spaces, you should
enclose the string in quotation marks.  Use printenv to print a list of
all your environment variables.
X%%
X
X%unsetenv%
usage: unsetenv VARIABLE
X
You must specify one and only one variable to unset in your environment
variable settings.  Use printenv to print a list of all your environment
variables.
X%%
END_OF_FILE
if test 16430 -ne `wc -c <'cmd_help'`; then
    echo shar: \"'cmd_help'\" unpacked with wrong size!
fi
# end of 'cmd_help'
fi
if test -f 'fkeys.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'fkeys.c'\"
else
echo shar: Extracting \"'fkeys.c'\" \(13831 characters\)
sed "s/^X//" >'fkeys.c' <<'END_OF_FILE'
X/* @(#)fkeys.c		(c) copyright 10/18/86 (Dan Heller) */
X
X#include "mush.h"
X#define draw(x1,y1,x2,y2,OP) pw_vector(msg_win, x1,y1,x2,y2,OP,1)
X#define box(x1,y1,x2,y2,OP)  \
X	draw(x1,y1, x1,y2,OP), draw(x1,y2, x2,y2,OP), \
X        draw(x2,y2, x2,y1,OP), draw(x2,y1, x1,y1,OP)
X
struct cmd fkey_cmds[] = {
X    { "top", fkey_cmd }, { "close", fkey_cmd }, { "bottom", fkey_cmd },
X    { "move", fkey_cmd }, { "stretch", fkey_cmd }, { "repaint", fkey_cmd },
X    { "settings", fkey_settings }, { NULL, quit }
X};
X
X#define L(n)		KEY_LEFTFIRST+(n)-1
X#define R(n)		KEY_RIGHTFIRST+(n)-1
X#define F(n)		KEY_TOPFIRST+(n)-1
X#define BREAK_KEY	KEY_TOPLAST
X
char *leftkey_default_settings[] = {
X    "Left Function Key Settings",
X    "Unused",		/* L1  */    "next",      	/* L2  */
X    "undelete",	 	/* L3  */    "delete", 		/* L4  */
X    "replyall",  	/* L5  */    "replysender",   	/* L6  */
X    "mail",		/* L7  */    "Unset",		/* L8  */
X    "lpr",  		/* L9  */    "settings L",      /* L10 */
X    0
X};
X
char *topkey_default_settings[] = {
X    "Top Function Key Settings",
X    "top",		/* T1  */     "close",	    	/* T2  */
X    "move",		/* T3  */     "stretch", 	/* T4  */
X    "bottom",		/* T5  */     "repaint",   	/* T6  */
X    "Unset",		/* T7  */     "Unset",		/* T8  */
X    "settings F", 	/* T9  */
X    0
X};
X
char *rightkey_default_settings[] = {
X    "Right Function Key Settings",
X    "Unset",		/* R1  */     "Unset",		 /* R2  */
X    "Unset",		/* R3  */     "Unset",		 /* R4  */
X    "Unset",		/* R5  */     "Unset",		 /* R6  */
X    "Unset",		/* R7  */     "Unset",		 /* R8  */
X    "Unset",		/* R9  */     "Unset",		 /* R10 */
X    "Unset",		/* R11 */     "Unset",		 /* R12 */
X    "Unset",		/* R13 */     "Unset",		 /* R14 */
X    "settings R",       /* R15 */
X    0
X};
X
X/*
X * Execute commands defined by a function key.
X * Left keys:
X * L1 = (null)  can't be set
X * L2 ... L10
X * Top function keys
X * F1 ... F9, BREAK/backspace (key not definable)
X * Right function keys
X * R1 ... R15
X * Usually, the last Function key displays the others' settings.
X */
fkey(key)
register char *key;
X{
X    register char **argv, *p;
X    char buf[256];
X    int n;
X
X    /* user defined here...        ... default settings here */
X    if (!strncmp((p = key_set_to(key)), "Un", 2)) {
X	print("Funciton key: %s  %s", key, p);
X	return 0;
X    }
X    /* make_command will screw up "p", so copy it first */
X    (void) strcpy(buf, p);
X    Debug("(%s) \"%s\": ", key, p), turnon(glob_flags, CONT_PRNT);
X    if (argv = make_command(buf, TRPL_NULL, &n))
X	(void) do_command(n, argv, msg_list);
X    return -1;
X}
X
fkey_settings(i, argv)
register char i;
register char **argv;
X{
X    register char key, *p, **fkey_str;
X    char buf[256];
X    char *help_args[17];
X
X    if (!*++argv) {
X	print("Must specify one of L, F or R to identify a function key set");
X	return -1;
X    }
X    key = **argv;
X    switch(Upper(key)) {
X	when 'L': fkey_str = leftkey_default_settings;
X	when 'F': fkey_str = topkey_default_settings;
X	when 'R': fkey_str = rightkey_default_settings;
X	otherwise: print("Invalid key set: %c (choose L, F or R)", key);
X		   return -1;
X    }
X    help_args[0] = fkey_str[0];
X    for (i = 1; fkey_str[i]; i++) {
X	p = key_set_to(sprintf(buf, "%c%d", key, i));
X	help_args[i] = savestr(sprintf(buf, "%c%-2.d       %s", key, i, p));
X    }
X    help_args[i] = 0;  /* null terminate list */
X    (void) help(print_sw->ts_windowfd, help_args, NULL);
X
X    free_vec(help_args+1);
X    return 0;
X}
X
char *
key_set_to(p)
register char *p;
X{
X    register char *p2, **fkey_str;
X
X    switch(*p) {
X	when 'L': fkey_str = leftkey_default_settings;
X	when 'F': fkey_str = topkey_default_settings;
X	when 'R': fkey_str = rightkey_default_settings;
X    }
X    p2 = do_set(fkeys, p);
X    return (p2)? p2: fkey_str[atoi(p+1)];
X}
X
fkey_cmd(x, p)
register char **p;
X{
X    if (!strcmp(*p, "close"))
X	toolquit(NO_ITEM, 0, NO_EVENT);
X    else if (!strcmp(*p, "top"))
X	wmgr_top(tool->tl_windowfd, rootfd);
X    else if (!strcmp(*p, "move"))
X	wmgr_move(tool->tl_windowfd, rootfd);
X    else if (!strcmp(*p, "stretch"))
X	wmgr_stretch(tool->tl_windowfd, rootfd);
X    else if (!strcmp(*p, "bottom"))
X	wmgr_bottom(tool->tl_windowfd, rootfd);
X    else if (!strcmp(*p, "repaint"))
X	wmgr_refreshwindow(tool->tl_windowfd, rootfd);
X    return -1;
X}
X
X/* execute a command given a function key, if the key is user defined,
X * call fkey() at top of file. Parameter is the key number in "ascii"
X */
func_key(key)
register int key;
X{
X    register char *p;
X    char buf[4];
X    int nkey;
X
X    if (key >= KEY_LEFTFIRST && key <= KEY_LEFTLAST)
X	buf[0] = 'L', nkey = key - KEY_LEFTFIRST;
X    else if (key >= KEY_TOPFIRST && key <= KEY_TOPLAST)
X	buf[0] = 'F', nkey = key - KEY_TOPFIRST;
X    else if (key >= KEY_RIGHTFIRST && key <= KEY_RIGHTLAST)
X	buf[0] = 'R', nkey = key - KEY_RIGHTFIRST;
X    (void) sprintf(buf+1, "%d", nkey+1);
X
X    return fkey(buf);
X}
X
void
set_fkeys()
X{
X    ready(display_keys() + 10);
X    print_valid_functions(txt.y+20);
X    getting_opts = 2;
X    win_setcursor(msg_sw->ts_windowfd, &checkmark);
X}
X
char *MSG = "Click the appropriate mouse button over a function key";
ready(Y)
X{
X    static int y;
X    int x = (msg_rect.r_width - strlen(MSG)*l_width(LARGE))/2;
X    if (Y)
X	y = Y;
X    Clrtoeol(msg_win, (txt.x = 0), (txt.y = y), LARGE);
X    highlight(msg_win, x, y, LARGE, MSG);
X}
X
X/* number of pixels in x and y directions describing the size of a graphical
X * function key.  they represent the little keys and big keys respectively.
X */
X/* static struct pr_pos fkey_sizes[2] = { { 23, 23 }, { 50, 23 } }; */
static struct pr_pos fkey_sizes[2] = { { 24, 23 }, { 52, 23 } };
X
X#define BORDER		4   /* border (distance) between keys */
X#define KEYTOP		15  /* distance from top to start drawing */
X#define LEFT_START	15  /* pixels from left to start drawing boxes */
X#define TOP_START	(LEFT_START+2*fkey_sizes[0].x + fkey_sizes[1].x+BORDER)
X#define RIGHT_START	(TOP_START + 5*(fkey_sizes[0].x+BORDER) + \
X				     5*(fkey_sizes[1].x+BORDER))
X
X/*
X * if !p, we're setting key at location x,y.
X * else Set that key to this string (p).
X */
void
set_key(p, x,y)
register char *p;
register int x,y;
X{
X    char 	buf[256], **argv;
X    static char *key;
X    int 	argc;
X
X    static int key_x, key_y;
X    if (!p) {
X	if (key = find_key(x,y)) {
X	    print("Type new setting for key: %s", key);
X	    (void) sprintf(buf, "Function key \"%s\": ", key);
X	    highlight(msg_win, 20, txt.y, LARGE, buf);
X	    txt.x = 20 + strlen(buf)*l_width(LARGE);
X	    Clrtoeol(msg_win, txt.x, txt.y, LARGE);
X	    type_cursor(PIX_SRC);
X	} else
X	    ready(0);
X	key_x = x, key_y = y;
X    } else {
X	u_long save_bang = ison(glob_flags, IGN_BANG);
X	if (!*p)
X	    (void) sprintf(buf, "unfkey %s", key);
X	else
X	    (void) sprintf(buf, "fkey %s \"%s\"", key, p);
X	turnon(glob_flags, IGN_BANG);
X	if (argv = make_command(buf, TRPL_NULL, &argc)) {
X	    (void) do_command(argc, argv, msg_list);
X	    print("Function key %s:  %s", key, key_set_to(key));
X	}
X	if (!save_bang)
X	    turnoff(glob_flags, IGN_BANG);
X	ready(0);
X    }
X}
X
X/* passed the x and y coords of a mouse click, return the function key
X * that exists in that position. NULL if no key there.  string will be
X * something like "L6" or "F9" or "R12"
X */
char *
find_key(x,y)
int x, y;
X{
X    static char buf[6];
X    int row, col;
X    static int old_left, old_top, old_right, old_bot;
X
X    if (!(row = find_y(&y)))
X	return NULL;
X    if (x < LEFT_START || x > RIGHT_START + 3*(fkey_sizes[0].x+BORDER))
X	return NULL;   /* out of range */
X    if (x > LEFT_START && x < TOP_START-fkey_sizes[0].x - BORDER) {
X	if ((col = (x > LEFT_START + fkey_sizes[0].x + BORDER)+1) == 1)
X	    x = LEFT_START+1;
X	else x = LEFT_START + fkey_sizes[0].x + BORDER + 1;
X	if (col == 1 && row == 1)
X	    return NULL;
X	/* unhighlight the old function key image */
X	if (old_left)
X	    box(old_left, old_top, old_right, old_bot, PIX_CLR);
X	old_left = x, old_top = y;
X	old_right = x+fkey_sizes[(col != 1)].x-2, old_bot = y+fkey_sizes[0].y-2;
X	/* highlight most recently selected function key image */
X	box(x,y, old_right, old_bot, PIX_SRC);
X
X	return sprintf(buf, "L%d", col + 2*(row-1));
X    }
X    if (x > TOP_START && x < RIGHT_START - fkey_sizes[0].x - BORDER) {
X	int which;
X	if (row > 1)
X	    return NULL;
X	which = (x - TOP_START) / (fkey_sizes[0].x + BORDER) + 1;
X	if (which == 15)
X	    return NULL;   /* Can't set break key (backspace on a sun3) */
X	if (which == 14)
X	    x = TOP_START + ((which = 9)-2) * (fkey_sizes[1].x+BORDER) -
X		    fkey_sizes[0].x - BORDER + 1;
X	else if (which <= 2)
X	    x = TOP_START + (which-1) * (fkey_sizes[0].x+BORDER) + 1;
X	else {
X	    which = (which+3)/2;
X	    x = TOP_START + (which-2) * (fkey_sizes[1].x+BORDER) + 1;
X	}
X
X	/* unhighlight the old function key image */
X	if (old_left)
X	    box(old_left, old_top, old_right, old_bot, PIX_CLR);
X	old_left = x, old_top = y;
X	old_right = x+fkey_sizes[(which > 2 && which < 8)].x-2;
X	old_bot = y+fkey_sizes[0].y-2;
X	/* highlight most recently selected function key image */
X	box(x,y, old_right, old_bot, PIX_SRC);
X
X	return sprintf(buf, "F%d", which);
X    }
X    if (x > RIGHT_START) {
X	if (x < RIGHT_START + fkey_sizes[0].x)
X	    x = RIGHT_START+1, col = 1;
X	else if (x < RIGHT_START + fkey_sizes[0].x + BORDER)
X	    return NULL;  /* cursor was clicked between keys */
X	else if (x < RIGHT_START + 2*fkey_sizes[0].x + BORDER)
X	    x = RIGHT_START+fkey_sizes[0].x+BORDER+1, col = 2;
X	else if (x < RIGHT_START + 2 * (fkey_sizes[0].x+BORDER))
X	    return NULL;  /* click between keys again */
X	else x = RIGHT_START + 2*(fkey_sizes[0].x+BORDER)+1, col = 3;
X
X	/* unhighlight the old function key image */
X	if (old_left)
X	    box(old_left, old_top, old_right, old_bot, PIX_CLR);
X	old_left = x, old_top = y;
X	old_right = x+fkey_sizes[0].x-2, old_bot = y+fkey_sizes[0].y-2;
X	/* highlight most recently selected function key image */
X	box(x,y, old_right, old_bot, PIX_SRC);
X
X	return sprintf(buf, "R%d", col + 3*(row-1));
X    }
X    return NULL;
X}
X
X/* find_y will find which row in a function key pad a y coordinate
X * represents. return 1,2,3,4, or 5   0 if inbetween rows
X */
find_y(y)
register int *y;
X{
X    int Y, y_incr = fkey_sizes[0].y, ret_value = 0;
X    for (Y = KEYTOP; Y <= KEYTOP + 6*y_incr + 4 * BORDER; Y += y_incr + BORDER)
X	if (*y < Y) {
X	    *y = (Y - y_incr - BORDER) + 1;
X	    return ret_value;
X	} else ret_value++;
X    return 0;
X}
X
char *l_msg = "Specifies which function key for setting value";
char *m_msg = "Display current value for function key";
char *r_msg = "Help setting and viewing function key values";
X
display_keys()
X{
X    register int i, x,y;
X    register char *p;
X
X    do_clear();
X
X    x = LEFT_START, y = KEYTOP;
X    /* print left keys */
X    for (i = 0; i < 10; i++) {
X	box(x, y, x + fkey_sizes[i%2].x, y + fkey_sizes[i%2].y, PIX_SRC);
X	box(x+2, y+2, x+fkey_sizes[i%2].x-2, y+fkey_sizes[i%2].y-2, PIX_SRC);
X	if (i && (p = find_key(x+4,y+4)))
X	    pw_text(msg_win, x+3, y+3+l_height(SMALL), PIX_SRC,fonts[SMALL], p);
X	else pw_replrop(msg_win, x+3, y+3, fkey_sizes[0].x-5, fkey_sizes[0].y-5,
X		 PIX_SRC | PIX_DST, &shade_50, 0,0);
X	if (i % 2)
X	    y += fkey_sizes[0].y + BORDER, x = LEFT_START;
X	else
X	    x += fkey_sizes[0].x + BORDER;
X    }
X
X    x = TOP_START, y = KEYTOP;
X    /* print top keys */
X    for (i = 1; i <= 10; i++) {
X	register int n = (i >= 3 && i <= 7);
X	box(x, y, x + fkey_sizes[n].x, y + fkey_sizes[n].y, PIX_SRC);
X	box(x+2, y+2, x + fkey_sizes[n].x-2, y + fkey_sizes[n].y-2, PIX_SRC);
X	if (i != 10 && (p = find_key(x+4,y+4)))
X	    pw_text(msg_win, x+3, y+3+l_height(SMALL), PIX_SRC,fonts[SMALL], p);
X	/* shade the break key (backspace on sun3's) -- can't set */
X	else if (i == 10)
X	    pw_replrop(msg_win, x+3, y+3, fkey_sizes[n].x-5, fkey_sizes[n].y-5,
X		 PIX_SRC | PIX_DST, &shade_50, 0,0);
X	x += fkey_sizes[n].x + BORDER;
X    }
X
X    x = RIGHT_START;
X    /* print right keys */
X    for (i = 0; i < 15; i++) {
X	box(x, y, x + fkey_sizes[0].x, y + fkey_sizes[0].y, PIX_SRC);
X	box(x+2, y+2, x + fkey_sizes[0].x-2, y + fkey_sizes[0].y-2, PIX_SRC);
X	if (p = find_key(x+4,y+4))
X	    pw_text(msg_win, x+3, y+3+l_height(SMALL),PIX_SRC, fonts[SMALL], p);
X	if (!((i+1) % 3))
X	    y += fkey_sizes[0].y + BORDER, x -= 2*(fkey_sizes[0].x + BORDER);
X	else
X	    x += fkey_sizes[0].x + BORDER;
X    }
X    x = TOP_START;
X    y = KEYTOP + BORDER + fkey_sizes[0].y + l_height(DEFAULT);
X    pw_rop(msg_win, x, y-11, 16,16, PIX_SRC, &mouse_left, 0,0);
X    pw_text(msg_win, x+30, y, PIX_SRC, fonts[DEFAULT], l_msg);
X
X    y += BORDER + fkey_sizes[0].y;
X    pw_rop(msg_win, x,y-11, 16,16, PIX_SRC, &mouse_middle, 0,0);
X    pw_text(msg_win, x+30, y, PIX_SRC, fonts[DEFAULT], m_msg);
X
X    y += BORDER + fkey_sizes[0].y;
X    pw_rop(msg_win, x,y-11, 16,16, PIX_SRC, &mouse_right, 0,0);
X    pw_text(msg_win, x+30, y, PIX_SRC, fonts[DEFAULT], r_msg);
X
X    x = (msg_rect.r_width - 26*l_width(DEFAULT))/2;
X    y += BORDER + fkey_sizes[0].y;
X    highlight(msg_win, x, y, DEFAULT, "You may not set shaded keys");
X
X    y += BORDER + fkey_sizes[0].y + 15;
X    for (i = 0; i < BORDER; i++)
X	draw(0, y+i, msg_rect.r_width, y+i, PIX_SRC);
X    y += 10;
X    for (i = 0; i < BORDER; i++)
X	draw(0, y+l_height(LARGE)+i, msg_rect.r_width, y+l_height(LARGE)+i,
X	     PIX_SRC);
X    return y;
X}
X
print_valid_functions(y)
register int y;
X{
X    register int x, n, cmd_len = 12 * l_width(DEFAULT);
X    register char *p;
X
X    y += 20, x = (msg_rect.r_width - 25*l_width(LARGE))/2;
X    highlight (msg_win, x, y, LARGE, "Available Command Names");
X    y += 20, x = 30;
X    for (n = 0; p = cmds[n].command; n++) {
X	if (x + cmd_len > msg_rect.r_width - 5)
X	    y += l_height(DEFAULT), x = 30;
X	pw_text(msg_win, x, y, PIX_SRC, fonts[DEFAULT], p);
X	x += cmd_len;
X    }
X    for (n = 0; p = fkey_cmds[n].command; n++) {
X	if (x + cmd_len > msg_rect.r_width - 5)
X	    y += l_height(DEFAULT), x = 30;
X	pw_text(msg_win, x, y, PIX_SRC, fonts[DEFAULT], p);
X	x += cmd_len;
X    }
X}
END_OF_FILE
if test 13831 -ne `wc -c <'fkeys.c'`; then
    echo shar: \"'fkeys.c'\" unpacked with wrong size!
fi
# end of 'fkeys.c'
fi
if test -f 'select.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'select.c'\"
else
echo shar: Extracting \"'select.c'\" \(13055 characters\)
sed "s/^X//" >'select.c' <<'END_OF_FILE'
X/* select.c	(c) copyright 1986 (Dan Heller) */
X
X/* 
X * Routine which handle io (selection on file descriptors) between user and
X * the various windows.
X *
X * In toolmode, the user types characters and each character is interpreted
X * here and, if applicable, is sent to rite.c where it is appended to a 
X * string similar to a tty driver and fgets. When the user types a '\n' the
X * rite() routine returns the string and we call add_to_letter to append the
X * string to the letter.  Signals are caught here as well.  that is the signal
X * characters setup by the user are checked and if one matches, call the signal
X * handling routine as if there were a real signal.
X *
X * Mouse handling is done here. See code for more detail.
X */
X#include "mush.h"
X
X#define READ_MSG	(char *)'r'
X#define DEL_MSG		(char *)'d'
X#define UNDEL_MSG	(char *)'u'
X#define REPL_MSG	(char *)'R'
X#define SAVE_MSG	(char *)'s'
X#define PRNT_MSG	(char *)'p'
X#define PRE_MSG		(char *)'P'
X#define E_EDIT     	(char *)'e'
X#define E_VIEW     	(char *)'v'
X#define E_INCLUDE  	(char *)'i'
X#define E_SEND		(char *)'S'
X#define E_ABORT   	(char *)'a'
X#define MENU_HELP	(char *)'h'
X#define O_SAVE		(char *)'s'
X#define O_QUIT		(char *)'q'
X#define O_RSTR		(char *)'r'
X
X#define N_MENU_ITEMS	8
X#define E_MENU_ITEMS	6
X
msg_io(gfxsw, ibits, obits, ebits, timer)
register struct gfxsubwindow *gfxsw;
register int *ibits,*obits,*ebits;
struct timeval **timer;
X{
X    register char	*p;
X    struct inputevent 	event;
X    static char 	lastchar;
X    static int 		line, count;
X
X    if (*ibits & ~(1 << gfxsw->gfx_windowfd)) {
X	*ibits = *obits = *ebits = 0;
X	return;
X    }
X    if (input_readevent(msg_sw->ts_windowfd, &event) == -1) {
X	error("input event");
X	return;
X    }
X    /*
X    if (ID == LOC_WINENTER) {
X	int x;
X	struct inputmask im;
X	win_getinputmask(gfxsw->gfx_windowfd, &im, &x);
X	win_setinputmask(hdr_sw->ts_windowfd, &im, &im, x);
X    }
X    */
X    if (ID >= KEY_LEFTFIRST)
X	if (ison(glob_flags, IS_GETTING))
X	    print("Finish editing letter first");
X	else
X	    (void) func_key(ID);
X    else if (isascii(ID) && (msg_pix || ison(glob_flags, IS_GETTING) ||
X	getting_opts)) {
X	if (getting_opts) {
X	    /*
X	     * txt.x <= 5 indicates not to accept typed input for options
X	     * and function key setting.
X	     */
X	    if (txt.x > 5) {
X		/* ^C, ^\ or ^U kills line */
X		type_cursor(PIX_XOR);
X		if (ID == tchars.t_intrc || ID == tchars.t_quitc ||
X					    ID == _tty.sg_kill) {
X		    rite(_tty.sg_kill), txt.x = 5;
X		    if (getting_opts == 1)
X			option_line(line), display_opts(0);
X		    else
X			set_key(0, 0, 0);
X		} else if (p = rite((char)ID)) {
X		    /* if no string entered, preserve old value */
X		    if (*p && getting_opts == 1)
X			add_opt(p, line);
X		    if (getting_opts == 2)
X			set_key(p, 0,0);
X		} else
X		    type_cursor(PIX_XOR);
X	    }
X	}
X	/*
X	 * This section MUST BE BEFORE the following "is_getting" section.
X	 * If user displays a message while editing a letter, he must hit 'q'
X	 * to return to edit mode.  He may not edit a new letter while one is
X	 * already being edited.
X	 */
X	else if (msg_pix)
X	    if (isdigit(ID)) {
X		if (!isdigit(lastchar))
X		    count = 0;
X		count = count * 10 + ID - '0';
X	    } else {
X		/* scroll <count> lines */
X		if (!count || count > msg_pix->pr_size.y / l_height(curfont))
X		    count = 1;
X		if (ID == 'k' || ID == 'K' || ID == '-')
X		    scroll_win(-count);
X		else if (ID == '\n' || ID == '\r' || ID == 'j')
X		    scroll_win(count);
X		else if (ID == ' ')
X		    scroll_win(crt);
X		else if ((ID == 'q' || ID == 'Q') &&
X			ison(glob_flags, IS_GETTING)) {
X		    pr_destroy(msg_pix), msg_pix = (struct pixrect *)NULL;
X		    win_setcursor(msg_sw->ts_windowfd, &write_cursor);
X		    txt.x = 5, txt.y = msg_rect.r_height - l_height(curfont);
X		    wprint("\n(continue editing letter)\n");
X		    clr_bot_line();
X		    type_cursor(PIX_SRC);
X		}
X	    }
X	/*
X	 * If msg_pix is NULL, then we are not reading a message. If we are
X	 * editing a letter, then enter the keys typed.  If we are doing
X	 * nothing, ignore this input.
X	 */
X	else if (ison(glob_flags, IS_GETTING)) {
X	    type_cursor(PIX_XOR);
X	    if (lastchar != ltchars.t_lnextc &&
X		(ID == tchars.t_intrc || ID == tchars.t_quitc)) {
X		    (void) rite(_tty.sg_kill);
X		    (void) rm_edfile(SIGINT);
X	    } else {
X		register int n = 1;
X		if (ID == tchars.t_eofc && txt.x == 5
X		    || (p = rite((char)ID)) && !(n = add_to_letter(p)))
X		    finish_up_letter();
X		else if (n > 0)
X		    type_cursor(PIX_XOR);
X	    }
X	}
X	lastchar = ID;
X    } else switch(ID) {
X	when MS_LEFT : case MS_MIDDLE:
X	    if (getting_opts == 2)
X		if (ID == MS_LEFT)
X		    set_key(NULL, event.ie_locx, event.ie_locy);
X		else {
X		    register char *p = find_key(event.ie_locx, event.ie_locy);
X		    if (p)
X			print("Function key %s:  %s", p, key_set_to(p));
X		}
X	    else if (getting_opts) {
X		int y = event.ie_locy - 50;
X		if (y < -24)
X		    break;
X		if (y < 0) {
X		    register int x = event.ie_locx;
X		    register int X = 60*l_width(LARGE);
X		    if (x >= X && x <= X+16)
X			display_opts(-1); /* scroll options back one value */
X		    else if (x >= X+20 && x <= X+36)
X			display_opts(1); /* scroll options forward one value */
X		    break;
X		}
X		/* the user was typing something -- stopped by using mouse */
X		if (txt.x > 5) {
X		    type_cursor(PIX_CLR);
X		    (void) rite(_tty.sg_kill), txt.x = 5;
X		    option_line(line), display_opts(0);
X		}
X	        line = y/20;
X		if (ID == MS_LEFT)
X		    toggle_opt(line);
X		help_opt(line);   /* display help (short info) in both cases */
X	    } else if (msg_pix)
X		if (ID == MS_LEFT)
X		    scroll_win(crt-3);
X		else
X		    scroll_win(-(crt-3));
X	when MS_RIGHT:
X	    if (getting_opts)
X		(void) view_opts_menu(&event, gfxsw->gfx_windowfd);
X	    else if (isoff(glob_flags, IS_GETTING))
X		(void) do_menu(&event, gfxsw->gfx_windowfd, current_msg);
X	    else
X		(void) edit_menu(&event, gfxsw->gfx_windowfd);
X	otherwise: ;
X    }
X    *ibits = *obits = *ebits = 0;
X}
X
struct cursor *mice[3] = { &l_cursor, &m_cursor, &r_cursor };
X
hdr_io(gfxsw, ibits, obits, ebits, sw_timer)
register struct gfxsubwindow *gfxsw;
int *ibits,*obits,*ebits;
struct timeval **sw_timer;
X{
X    static int 		which_cursor;
X    struct inputmask 	im;
X    struct inputevent 	event;
X    int 		line;
X
X    if (*ibits & ~(1 << gfxsw->gfx_windowfd)) {
X	*ibits = *obits = *ebits = 0;
X	return;
X    }
X    /* make curosr change which button is lit */
X    win_setcursor(gfxsw->gfx_windowfd, mice[which_cursor]);
X
X    which_cursor = (which_cursor+1) % 3;
X    if (input_readevent(hdr_sw->ts_windowfd, &event) == -1) {
X	error("input event");
X	return;
X    }
X    /* I'm not sure why I have to do this.
X     * I'm doing it because sometimes the IO hangs completely and no input
X     * is accepted. What I do here is get the current mask, save it, then
X     * reset it. This action seems to flush the IO queue, and I don't have hung
X     * IO anymore.  This shouldn't be necessary, but it appears to work.
X     * (occurances have droped about 90%)
X     */
X    if (ID == LOC_WINENTER) {
X	int x;
X	win_getinputmask(gfxsw->gfx_windowfd, &im, &x);
X	win_setinputmask(hdr_sw->ts_windowfd, &im, &im, x);
X    }
X    /* just return -- we just wanted to make the cursor flicker */
X    if (ID == LOC_STILL || ID == LOC_MOVE || ID == LOC_WINENTER) {
X	*ibits = *obits = *ebits = 0;
X	return;
X    }
X    line = event.ie_locy / l_height(DEFAULT);
X    if (ID >= KEY_LEFTFIRST)
X	(void) func_key(ID);
X    else if (n_array[line] > msg_cnt)
X	if (!msg_cnt)
X	    print("-- You have no messages -- ");
X	else
X	    print("Message out of range.  Place mouse over a legal message.");
X    else switch(ID) {
X	when MS_LEFT: case MS_MIDDLE:
X	    (void) do_menu((ID == MS_LEFT)? READ_MSG: DEL_MSG, 0,n_array[line]);
X	when MS_RIGHT:
X	    (void) do_menu(&event, gfxsw->gfx_windowfd, n_array[line]);
X	otherwise : print("Unkown ID = %d", ID);
X    }
X    *ibits = *obits = *ebits = 0;
X}
X
X/* if "fd" is 0, then event points to the action to be taken.
X * otherwise, determine action to be taken by displaying a menu.
X * message is the number current_msg should be changed to (may be the same).
X */
do_menu(event, fd, message)
caddr_t event;
X{
X    static char buf[20];
X    struct menuitem *m_item;
X    char *action;
X    static struct menuitem msg_menu_items[] = {
X	{ MENU_IMAGESTRING,  "Read",     READ_MSG   },
X	{ MENU_IMAGESTRING,  "Delete",   DEL_MSG    },
X	{ MENU_IMAGESTRING,  "Undelete", UNDEL_MSG  },
X	{ MENU_IMAGESTRING,  "Reply",    REPL_MSG   },
X	{ MENU_IMAGESTRING,  "Save",     SAVE_MSG   },
X	{ MENU_IMAGESTRING,  "Preserve", PRE_MSG    },
X	{ MENU_IMAGESTRING,  "Print",    PRNT_MSG   },
X	{ MENU_IMAGESTRING,  "Help",     MENU_HELP  }
X    };
X    static struct menu help_menu = {
X        MENU_IMAGESTRING, "Item Help",
X	N_MENU_ITEMS, msg_menu_items,
X	(struct menu *)NULL, NULL
X    };
X    static struct menu msgs_menu = {
X        MENU_IMAGESTRING, buf, N_MENU_ITEMS,
X	msg_menu_items, &help_menu, NULL
X    };
X    /* to have the menu stack maintain order of menus upon each invokation,
X     * declare menu_ptr to be static and remove the following two lines
X     * after the declaration.
X     */
X    struct menu *menu_ptr = &msgs_menu;
X    msgs_menu.m_next = &help_menu;
X    help_menu.m_next = (struct menu *)NULL;
X
X    if (!msg_cnt) {
X	print("No Messages.");
X	return;
X    }
X    if (fd) {
X	(void) sprintf(buf, "Message #%d", message+1);
X	if (m_item = menu_display(&menu_ptr, (struct inputevent *)event, fd))
X	    action = m_item->mi_data;
X	else
X	    return;
X    } else
X	action = event;
X
X    if (menu_ptr == &help_menu || action == MENU_HELP) {
X	switch(action) {
X	    when DEL_MSG: case UNDEL_MSG:
X		(void) help(fd, "menu_delete", tool_help);
X	    when READ_MSG: (void) help(fd, "next", tool_help);
X	    when REPL_MSG: (void) help(fd, "menu_respond", tool_help);
X	    when SAVE_MSG: (void) help(fd, "save", tool_help);
X	    when PRE_MSG: (void)  help(fd, "preserve", tool_help);
X	    when PRNT_MSG: (void) help(fd, "printer", tool_help);
X	    when MENU_HELP:
X		if (menu_ptr == &help_menu)
X		    (void) help(fd, "help_menu_help_msg", tool_help);
X		else
X		    (void) help(fd, "msg_menu", tool_help);
X	}
X	return;
X    }
X    set_isread(message);
X    if (action == SAVE_MSG) {
X	panel_set(msg_num_item, PANEL_VALUE, sprintf(buf, "%d", message+1), 0);
X	((struct inputevent *)event)->ie_code = MS_LEFT;
X	do_file_dir(save_item, 0, event);
X	panel_set(msg_num_item, PANEL_VALUE, NO_STRING, 0);
X	return;
X    } else if (action == PRNT_MSG  || action == PRE_MSG ||
X	       action == UNDEL_MSG || action == DEL_MSG) {
X	fkey_misc(action, message);
X	return;
X    }
X    if (isoff(glob_flags, IS_GETTING)) {
X	current_msg = message;
X	(void) do_hdrs(0, DUBL_NULL, NULL);
X    }
X    if (action == REPL_MSG) {
X	respond_mail(respond_item, 0, event);
X	return;
X    } else if (ison(glob_flags, IS_GETTING)) {
X	if (exec_pid)
X	    /* User can read a message as long as he's not in an editor */
X	    print("Finish editing message first");
X	else {
X	    (void) do_hdrs(0, DUBL_NULL, NULL);
X	    display_msg(message, (long)0);
X	}
X	return;
X    }
X    display_msg(current_msg, (long)0);
X}
X
X/* miscellaneous function key actions there are here because the defines
X * for DEL_MSG, etc are here in this file and the function is called from
X * here more often.
X */
fkey_misc(action, message)
char *action;
X{
X    int argc;
X    register char **argv;
X    char buf[30];
X
X    print("Message #%d ", message+1);
X    if (action == UNDEL_MSG || action == DEL_MSG)
X	print_more("%sd. ", sprintf(buf, "%selete",
X			    (action == DEL_MSG)? "d": "und"));
X    else if (action == PRNT_MSG) {
X	print_more("sent to printer");
X	(void) strcpy(buf, "lpr");
X    } else if (action == PRE_MSG)
X	print_more("%sd", strcpy(buf, "preseve"));
X    (void) sprintf(&buf[strlen(buf)], " %d", message+1);
X    if (message == current_msg && action == DEL_MSG)
X	do_clear();
X
X    if (argv = make_command(buf, DUBL_NULL, &argc))
X	(void) do_command(argc, argv, msg_list);
X    return;
X}
X
view_opts_menu(event, fd)
struct inputevent *event;
X{
X    static char buf[5];
X    struct menuitem *m_item;
X    char *action;
X    static struct menuitem opts_items[] = {
X	{ MENU_IMAGESTRING,  "Save Options",	O_SAVE  },
X	{ MENU_IMAGESTRING,  "Restore Options",	O_RSTR  },
X	{ MENU_IMAGESTRING,  "Quit Options",	O_QUIT  },
X	{ MENU_IMAGESTRING,  "Help",		MENU_HELP  }
X    };
X    static struct menu msgs_menu = {
X        MENU_IMAGESTRING, "Options", 4, opts_items, (struct menu *)NULL, NULL
X    };
X    struct menu *menu_ptr = &msgs_menu;
X
X    if (m_item = menu_display(&menu_ptr, event, fd))
X	action = m_item->mi_data;
X    else
X	return;
X    switch(action) {
X	case O_SAVE:
X	    save_opts(0, DUBL_NULL);
X	when O_RSTR:
X	    init();
X	    if (getting_opts == 1)
X		view_options();
X	    else
X		set_fkeys();
X	when O_QUIT:
X	    do_clear();
X	    unlock_cursors(); /* actually resets msg_win's cursor */
X	    if (isoff(glob_flags, IS_GETTING) && msg_cnt)
X		if (isoff(msg[current_msg].m_flags, DELETE))
X		    display_msg(current_msg, (long)0);
X		else
X		    (void) read_mail(NO_ITEM, 0, NO_EVENT);
X	when MENU_HELP:
X	    (void) help(fd, (getting_opts == 1)? "options": "fkeys", tool_help);
X    }
X}
END_OF_FILE
if test 13055 -ne `wc -c <'select.c'`; then
    echo shar: \"'select.c'\" unpacked with wrong size!
fi
# end of 'select.c'
fi
echo shar: End of archive 6 \(of 14\).
cp /dev/null ark6isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 14 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