[comp.sources.unix] v11i055: Mail user's shell, Part05/12

rsalz@uunet.UU.NET (Rich Salz) (09/19/87)

Submitted-by: island!argv@Sun.COM (Dan Heller)
Posting-number: Volume 11, Issue 55
Archive-name: mush5.7/Part05

#! /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 5 (of 12)."
# Contents:  cmd_help fkeys.c select.c
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'\" \(16086 characters\)
sed "s/^X//" >'cmd_help' <<'END_OF_FILE'
X/* @(#)cmd_help	1.4	10/28/86 (Dan heller) */
X
X%?%
XThe `?' will give you a list of legal commands.  Most commands
Xaccept -? as an option.  This will give you specialized help
Xwith that particular command.
X%%
X
X%ignore%
Xusage: ignore/unignore [headers]
XUse this command to set the message headers you would like not
Xto be printed when you read a message. If no header specified,
Xthen a list of all headers currently being ignored is printed.
XYou must specify a header for unignore.
X
XYou can set the variable "alwaysignore" to force normally
Xignored headers to be ignored while saving messages, forwarding
Xmessages or including messages into message buffers.
X%%
X
X%set%
Xusage: set/unset [variable] [= value]
Xset by itself prints values for variables in its group
XTo set a boolean variable (on or off), "set variable"
XTo set a variable's value to a string, use:
Xset variable = 'value'
X
XIf you want double-quote's or white-space embedded in
Xa string, encase the string in single quotes.  If you
Xwant single quotes in a string, encase the string in
Xdouble quotes.
X
XType "set ?all" for a list of all settable variables.
X"set ?variable_name" for help on a single variable.
X%%
X
X%readmsg%
XYou can read messages in different ways.  "type" and "print"
Xwill print the current message.  "top" will only print the
Xfirst N lines of the current message where N is the value of
Xthe variable "crt".  "next" will go to the next unread message
Xand print that. "previous" will go back and read the first
Xunread message previous to the current. ^ will print the first
Xmessage, $ will print the last.
XAll can be followed by a message list and each message in
Xthat list will be printed (or piped to other commands).
X%%
X
X%alts_help%
Xusage: alts [hostnames]
Xalts contains a list of hostnames on which you have an account
XNormally, when you respond to all recipients of mail, your
Xaccount name will be listed and you send yourself mail. If you
Xdon't have metoo set, then your name will be removed from the
Xmailing list if your login name is on the list and the host
Xspecified is in the alternates list.  `*' matches all hostnames
Xand only the login name is tested.
X%%
X
X%source_help%
Xusage: source/saveopts [file]
Xsource/saveopts will load/save all variable settings, options,
Xaliases, cmd's, ignored headers ... everything you can set,
Xit 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%
XThis is the general help message. To get help on a specific
Xcommand, try "command -?". Extended help is given by typing
X`help item' where item is one of:
X    path, msg_list, prompt, hdr_format.
XHelp with msg_list is highly advisable!
X
XType "?" to get a list of available commands.  Try "? command"
Xto get help on the particular command that you specify.
X%%
X
X%path%
XWhenever "path" is specified, the following syntax is legal besides the
Xnormal 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%
XA "msg_list" references one or more messages.  The user specifies
Xa group of messages according to a special syntax.
X
X*      All messages.
X^      The first message.
X$      The last message.
X.      The current message.
XN-M    A range of messages between N and M.
X
XIn the last case, N and M may be * ^ $ . or digits referencing
Xexplicit message numbers.  The range must be in ascending order.
X
XYou can also negate messages by placing the message list inside
Xbraces, `{' `}' -- thus, the expression "2-19 {11-14}" references
Xmessages 2 through 19 except for those between 11 through 14.
X
XCommands can be "piped" to one another, because the return
Xvalue of a command is a msg_list, not text.
Xpick -f fred | lpr   will find all messages "from fred" and
Xsend them to the printer.
X
XCommands dealing with more than one message process them in
Xorder -- not necessarily the order specified.  Thus, the command,
Xsave 1-5 9 7 6 file
Xwill save the messages in ascending order; not as specified.
X%%
X
X%preserve_help%
Xusage: preserve [msg_list]
XPreserve saves deleted or read messages in your mailbox.
XWithout explicitely setting preserve, all mail that you
Xread will be saved in ~/mbox (or set mbox).  If you set
X"hold", then this is equivalent to preserving each message
Xas you read it.
X%%
X
X%save_help%
Xusage: save/write/copy [!] [msg_list] [filename]
X
XIf no filename is specified, ~/mbox (or set mbox) is used.
XSave and write will append msg if `file' already exists
XSpecifying the `!' will overwrite file (e.g. erasing it first).
XTo save messages to a filename beginning with a digit,
Xescape the filename with a backslash (\)
X`write' will write message without the headers (msg body only).
XSave and write both mark messages for deletion unless "keepsave"
Xis set.  Copy is identical to save except that messages are not
Xmarked for deletion (identical to having keepsave set).
X%%
X
X%lpr%
Xuse: lpr [-] [-] [msg_list]
X-n         print body of message only (not headers)
X-h         print all headers with message body (default true)
X-       print on printer 
X%%
X
X%respond_help%
Xusage: replysender/replyall [msg_list] [mail_flags] [users]
XReplysender only replies to the sender and replyall responds
Xto everyone on the To: and Cc: lines of the message.
X
XThe commands "repond", "reply", and "r" are identical to
X"replysender." The command, "R" is identical to "replyall."
X
XIf a message list is indicated, then each message on the list is
Xreplied to in the same manner.  All other arguments are passed
Xto the mail command ('mail_flags' and 'users').
X
XType "mail -?" for information on legal mail flags.
X%%
X
X%sort_help%
Xusage: 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
XThe optional `-' flag will reverse the order of sorting
XBy default (no arguments), sort sorts messages by status:
XNew, unread messages are first, followed by preserved messages
Xand finally the deleted messages are placed at the end
X%%
X
X%pick%
Xuse: pick [-r msg_list] [-d [-][date] ] [-s|f|t]] [-x] [-i] [<pat>]
XSearch for patterns within messages. Entire messages are searched
Xfor <pattern> unless -s, -f, or -t is specified.
XOnly one of -s, -f, -t, and -d can be specified at once. No patterns with -d.
X-r msg_list  restrict the range of messages search to msg_list
X-d: print message headers on or after [`-' before] `date'
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%
Xoptions for alias:
Xalias                           print all namelists
Xalias name                      print namelist associated with name
Xalias name namelist             set "name" to value of namelist.
Xunalias namelist                unalias names in namelist
X
XA "namelist" consists of one or more addresses. An address
Xmay be a name already set to another list, valid user, file
Xor program.  Filenames must be full pathnames beginning with
Xa '/' (or a ~ expanding to a home directory).  A "program"
Xmust start with a pipe and be encased in quotes:
X
X    "|program_name"
X
XThe command, "expand", will print addresses (including sublists)
Xassociated with the given alias.
X%%
X
X%from%
XWith no arguments, from will print the current message's header.
XIf given a message list, from will print the headers of those
Xmessages which are in the list.
X
XThe special arguments, `-' and `+' can be given to move the
Xcurrent message pointer to the previous or next message
Xrespectively while also printing that message's header.
X
XIf a message list was given in addition to `-' or `+', then
Xthe current message pointer will be set to the first or last
Xmessage, respectively, in the message list given.
X
Xfrom - 10-30 {16}
Xwill print the headers of messages 10 through 30 except for
Xmessage 16 and set the current message pointer to 10.
X
Xpick -f Dan | from +
Xwill print the headers of all messages that contain Dan in
Xin the author's name and set the current message pointer to
Xthe last one of that kind in the list.
X
Xfrom +
Xwill print the header of the message after the current message
Xand increment the current message pointer to the next message.
X%%
X
X%own_hdrs%
XHere is where you set, unset or view your own message headers.
XThese headers are included in all your outgoing mail.
X
Xoptions for my_hdrs:
Xmy_hdr                          all headers
Xmy_hdr header                   value associated with header
Xmy_hdr header: string           set header to string
Xun_hdr header                   unset header
X%%
X
X%fkey_help%
Xfkey's are function key settings in Suntools (graphics) mode
XWhen run as a tool (-t on command line), choose the Options Item,
Xand the function key menu option.
X%%
X
X%func_help%
Xcmd's are just like aliases in the c-shell.
Xcmd                     view all commands
Xcmd `command'           value associated with command
Xcmd `command' "value"   set command to value
Xuncmd `command'         unset command
X
XIf you want to reference history commands within a cmd,
Xescape the ! with a backslant. For example:
X
Xmail> cmd r 'replysender \!* ; delete -t'
X
Xwill reply using whatever arguments you will have given
Xon the command line and then delete that message and
Xthen print the next message (-t argument to "delete").
X%%
X
X%headers%
Xusage: headers [+ | - | N] [-H:c]
Xprint out a screenful of headers.
X+  print the next screenful.
X-  print the previous screenful.
XN  (where N is a number) print a screenful starting at N.
Xset show_deleted to list deleted messages.
Xcmd h headers        look like UCB-Mail
Xcmd H Headers        show deleted messages (or set show_deleted)
Xcmd z headers +      `z' is next screenful
X
XArguments 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    a    all messages (mostly for the command line argument -H:c)
X
Xpiping to headers will print the headers of the "output" messages.
X%%
X
X%hdr_format%
Xset hdr_format="string" for changing the display of message headers.
XThe string uses printf style formatting and follows these conventions:
X    %S  message Status.
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    %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.
XA field specifier may be used.  Thus, %20f will print the first 20
Xcharacters of the from line.  No matter what the formatting string,
Xthe message number followed by a '>' (if current message) is printed.
X%%
X
X%folder_help%
Xusage: folder [-N] [-r] [!] [ %[user] | # | & | file ]
XChange current folder.
XNo 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).
XIf `!' 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%
Xset 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%
Xusage: quit/exit",
Xquit will update your mailbox; if new mail has come in, you will be
Xtold 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%
XThe ls command is exactly like the UNIX command, "ls."
XAll arguments are the same.  The variable "lister" can
Xbe set to always default to the same arguments avoiding
Xhaving to specify them all the time.  The "folders"
Xcommand is nothing more than doing "ls $folder" from
Xthe Mush prompt.
X%%
X
X%shell%
Xusage: sh [command]
XIf a "command" is given, that UNIX command will be executed
Xunder the Bourne shell. If no command is specified, then an
Xinteractive shell will be started. The environment variable
XSHELL or the local mail shell variable shell  describes the
Xshell to invoke.  If none is set, then the default shell is
Xdefined by the system administrator (currently set to csh).
X
XUsers on systems with job control will probably have little
Xuse for the sh command.
X%%
X
X%stop%
XThe stop command sends a stop signal to the mail shell.
XIt is equivalent to ^Z as it will stop the process.
XSince 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'
Xwhich will bring mush into the foreground rather than
Xhaving to invoke a new shell.  New mail will be read 
Xinto the shell automatically and much time and energy 
Xis saved.
X%%
X
X%curses%
XThe curses-based interface for Mush does not require a graphics
Xdisplay, but does requires a terminal which can handle upline
Xcursor movement capabilities.  All commands are one key-stroke
Xcommands and are executed instantaneously.  A list of curses
Xcommands is given by using the `?' key in curses mode.
X%%
X
X%bind%
XBinding is done for the curses interface only.  It allows
Xthe user to bind keystrokes or key sequences to commands.
X
XTo bind keystrokes that are control characters, you must use
Xthe notation: "\CX" where "X" is in upper-case and it represents
Xthe control key you want to use. "\CN" would be control-N; "\n"
Xis carriage return.  You may not bind keyboard generated signals;
Xfor most users, those key sequences are control-C and control-\.
XFor users with job control, control-Z and control-Y are ignored.
XTo reference the escape key, use the string, "\E".
X
XThe spacebar may not be bound since it is the only way to return
Xto the main level from the "...continue..." prompt.
X
XTrying to bind a key sequence which prefixes another sequence
Xis an error and the user is warned that the longer binding will
Xnot work.
X
XAs always, -? will give help.
X%%
X
X%msg_flags%
Xusage: flags [msg_list [N O R D P U] ]
XThis command displays the state of messages as seen by the internals
Xof Mush.  This is not a documented command, so don't tell anyone.
XIf a list is given (or piped), it will tell which bits of the message
Xare set: New, Old, Read, Deleted, Preserved, or Unread.
XIf any (one or more) of the optional bits are given, then it will set
Xthe appropriate bit in the list given.  As usual, if no list is given,
Xthen the current message is used (or set bits on a pipe).
X%%
X
X%setenv%
Xusage: setenv VARIABLE [value]
X
XVariable names may be any string, but traditionally environment variables
Xare all upper case.  If no "value" is specified, then the variable name
Xwill be set to an empty string.  If the value contains spaces, you should
Xenclose the string in quotation marks.  Use printenv to print a list of
Xall your environment variables.
X%%
X
X%unsetenv%
Xusage: unsetenv VARIABLE
X
XYou must specify one and only one variable to unset in your environment
Xvariable settings.  Use printenv to print a list of all your environment
Xvariables.
X%%
END_OF_FILE
if test 16086 -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'\" \(13868 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
Xstruct 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
Xchar *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
Xchar *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
Xchar *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 */
Xfkey(key)
Xregister 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
Xfkey_settings(i, argv)
Xregister char i;
Xregister 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
Xchar *
Xkey_set_to(p)
Xregister 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
Xfkey_cmd(x, p)
Xregister 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 */
Xfunc_key(key)
Xregister 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
Xvoid
Xset_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
Xchar *MSG = "Click the appropriate mouse button over a function key";
Xready(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 } }; */
Xstatic 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 */
Xvoid
Xset_key(p, x,y)
Xregister char *p;
Xregister 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	    pw_char(msg_win, txt.x, txt.y, PIX_SRC, fonts[curfont], '_');
X	} else
X	    ready(0);
X	key_x = x, key_y = y;
X    } else {
X	int 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 */
Xchar *
Xfind_key(x,y)
Xint 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 */
Xfind_y(y)
Xregister 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
Xchar *l_msg = "Specifies which function key for setting value";
Xchar *m_msg = "Display current value for function key";
Xchar *r_msg = "Help setting and viewing function key values";
X
Xdisplay_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
Xprint_valid_functions(y)
Xregister 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 13868 -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'\" \(13090 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#define swap(a,b)         (a ^= b ^= a)   /* swap values of a pair of ints */
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
Xmsg_io(gfxsw, ibits, obits, ebits, timer)
Xregister struct gfxsubwindow *gfxsw;
Xregister int *ibits,*obits,*ebits;
Xstruct 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		pw_char(msg_win, txt.x,txt.y, PIX_OR, fonts[curfont], '_');
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		    pw_char(msg_win, txt.x, txt.y, PIX_OR, fonts[curfont], '_');
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		    pw_char(msg_win, txt.x,txt.y, PIX_SRC, fonts[curfont], '_');
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	    pw_char(msg_win, txt.x,txt.y, PIX_SRC^PIX_DST, fonts[curfont],'_');
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		    pw_char(msg_win, txt.x,txt.y, PIX_SRC, fonts[curfont], '_');
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		    pw_char(msg_win, txt.x,txt.y, PIX_CLR, fonts[curfont], '_');
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
Xstruct cursor *mice[3] = { &l_cursor, &m_cursor, &r_cursor };
X
Xhdr_io(gfxsw, ibits, obits, ebits, sw_timer)
Xregister struct gfxsubwindow *gfxsw;
Xint *ibits,*obits,*ebits;
Xstruct 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 -- this function is useless now.");
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 */
Xdo_menu(event, fd, message)
Xcaddr_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	swap(current_msg, message);
X	((struct inputevent *)event)->ie_code = MS_LEFT;
X	do_file_dir(save_item, 0, event);
X	swap(current_msg, message);
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	print("Finish editing message first");
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 */
Xfkey_misc(action, message)
Xchar *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
X    if (argv = make_command(buf, DUBL_NULL, &argc))
X	(void) do_command(argc, argv, msg_list);
X    return;
X}
X
Xview_opts_menu(event, fd)
Xstruct 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 13090 -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 5 \(of 12\).
cp /dev/null ark5isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 12 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 ke