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

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

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

#!/bin/sh
# do not concatenate these parts, unpack them in order with /bin/sh
# file tool_help continued
#
if test ! -r _shar_seq_.tmp; then
	echo 'Please unpack part 1 first!'
	exit 1
fi
(read Scheck
 if test "$Scheck" != 22; then
	echo Please unpack part "$Scheck" next!
	exit 1
 else
	exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
	echo 'x - still skipping tool_help'
else
echo 'x - continuing file tool_help'
sed 's/^X//' << 'SHAR_EOF' >> 'tool_help' &&
a menu of things to do then. Included in the menu, is a help item
which describes the selections in the menu.
%%
X
%Menu Read%
When pointing at a message header in the header subwindow, hold down
the RIGHT mouse button and select "Read" from the menu.  A new window
will open containing the text of the message.  In this way, you can
display more than one message at a time.
X
This operation sometimes fails on SunOS 3.5 systems due to limitations
on the number of windows Mush can open at once.  When all the available
windows are in use, the selected message is displayed in the message
subwindow at the bottom of the main window.
%%
X
%preserve%
Usually, after you read mail and you "update" or quit  Mushview, unread
messages are copied back into your system mailbox, deleted messages are
removed, and messages which have been read but not deleted are saved in
your "mbox" file.  Specifying "hold" prevents this from ever happening,
but you can mark specific messages to be held in your system mailbox by
preserving them.
%%
X
%compose%
When you start to compose a letter for mailing, you will be prompted
for a recipient (To:) and other optional mail headers.  The cursor for
the text subwindow will look like a bent arrow to indicate that when
you hit RETURN, the cursor will automatically forward to the next
header (the Subject: line, for example).
X
When the cursor resumes its original shape, the RETURN key enters new
lines as normal.
X
There must be a recipient specified in order to send a message.  The
recipient may be a user or a file or program name.
%%
X
%next%
You can page through all your messages by selecting  "Next" after reading
each message. The same effect is gotten when you select the "Delete" item
when the option,  "autoprint" is set to be true  (see "opts") except that
the current message is deleted before the next one is displayed. Deleting
mail which is  not important  helps the  efficiency of Mushview and reduces
unnecessary use of system resources.
X
In the Header Window, you will notice the cursor looks like the mouse you
use.  The blinking buttons on the mouse image remind you that you can use
any of the  three buttons  at any  time.  When you  move the mouse over a
message and choose a button, the message under the  mouse is going to be
the one affected.  Choosing left button will read the message, the middle
button will delete it, and the right button will give you a menu.
%%
X
%aliases%
Aliases are used as a method of mailing to users with long addresses using
short names. For example, if you wanted to mail to
X    argv@sun.com
but didn't want to type that all the time, then you could make an alias by
selecting the alias menu item that specifies "adding alias" and then TYPE:
X    Dan argv@sun.com
If you want to mail to a list of people and do so frequently enough to want
an alias name for the whole list, then  you would type something like this:
X    project-group fred mary bob@foo-bar herb sly@baz.bitnet
X
To mail to an "alias" you would compose a letter and address the letter:
X
To: Dan
Subject: Alias example
Cc: project-group
(rest of letter)
%%
X
%alts%
"Alternates" are alternate names for YOU.  In messages you receive,
your account will appear on the "To" or "Cc" list.  When you REPLY to
those messages, Mushview will construct a message header for your
letter which will contain the To and Cc lists of recipients from the
original message. You would probably want your name taken off the list
so you do not mail yourself a copy of your own message. If you have
other account names or accounts on other machines, you can let Mushview
know what those mail addresses are so they can be removed from the
lists as well.
X
Note, that if YOU add your name MANUALLY (type it yourself) to either
of the lists, it will not be removed.
X
You can set such a list in your .mailrc file in your home directory by
adding the line:
X
alts hostname1 hostname2 ...
X
If you prefer to not have your name removed from lists when responding
to mail, set the option "metoo"; this prevents the need for alternates
and your name will never be removed.
%%
X
%options%
To set or unset options and their values, move the mouse over the
option of your choice and select the LEFT button to toggle true/false
values. If an option requires a string value, you must type the value,
so select the LEFT button to reference the option, and then type away.
X
NOTE: You must use a Carriage Return to enter the final value for the
option or the value will not change.
%%
X
%ignore%
When reading mail, the message "headers" may clutter up the
window with information you are not interested in.  For
example, you may not be interested in the "Received" or
"Message-Id" field of the mail message. You would find that
in time, it will become annoying to see these uninteresting
message headers.
X
You can specify which message headers should not be shown,
thus shortening the appearance of the length of the message.
X
Typical settings:
X    Received
X    Message-Id
X    Status
%%
X
%printer%
This item will send the current message, or the message specified on
the range item, to the printer.  The printer used is given by the
variable $printer.  To specify a different printer, change the printer
option by selecting the item "Options" in the Main Panel Window, moving
the mouse over the "printer" option, selecting the LEFT mouse button
and typing the name of the printer which you'd like to use.
X
Be sure to set this option before printing because the DEFAULT option
may not be what you want.
X
You can print messages that are NOT the current message by moving the
mouse into the Header Window and selecting the RIGHT mouse button on
top of the message you want to print and selecting the PRINT menu
option.
%%
X
%windows%
"Windows" are the boxes which contain items, text, or graphic
images.  There are two "panel" windows. A panel window is one
which contains items,  which are the little boxes  with words
that you can place the mouse over and click the left or mouse
button.
X
Each  window has a separate  function for different purposes.
Starting at the top of the main "tool" (contains all windows)
we have the "header panel." Everything in this panel pertains
to the message headers, only.  The panel in the middle of the
tool is the "mail panel" which is more general and applies to
just about everything. For a description of each of the items
within any panel, select the  "Help"  option  from  the  menu
you get by selecting the RIGHT mouse button.
%%
X
%message range%
You can specify a large group of messages using a combination of special
symbols in addition to numbers.  For example, if you wish to save all of
the messages, then you can use `*' to represent them all. If you were to
type the  "star" and select the Save  menu option for "save range", then
you would save ALL the messages you have (including deleted ones).
X
If you would like to save messages 4 through 9, then you would specify:
X      4-9
If you want to specify the messages between 2 and 32 except for messages
6, 8 and message 12-14, you would type:
X      2-32 {6,8,12-14}
Commas or spaces can be used to separate numbers.
X
Note that you cannot specify negated messages without first specifying
normal messages; e.g. {2-5} 1-11   doesn't make sense.
%%
X
%sort%
Sorting messages can   be accomplished by  selecting one  of the
menu items in this panel item.  By default (using the LEFT mouse
button),  sorting is  done by  message status.  New messages are
first, followed  by unread messages,  old/read messages, replied
to  messages,  and  finally deleted messages.  You may also sort
messages by author, date, or subject by selecting the menu item.
%%
X
%include%
To include a message in your letter, first enter the number of the
message you wish to include in the  Range:  item of the main  mush
frame.  Then select  Include  from the composition window panel by
pressing the LEFT mouse button.    If you do not specify a message
in the  Range:  item, the current message will be included.
X
To forward a message, choose the message to be forwarded as above,
use the RIGHT mouse button on the  Include item and select Forward
Message from the menu.
%%
X
%mark%
Marks can be used to tag messages for later reference.  They are
temporary and will not be saved when the folder is updated.  A
priority setting beteween A and E may also be set on message(s).
Priorities are saved across updated folders.  Sorting by marks
and priorities is also available (marks having highest priority,
followed by A, B, etc.).
X
Marks are set on the current message only while priorities are set
(or unset) on the message list specified in the Range: text field.
X
Messages may have both a temporary mark and a priority, but may not
have more than one priority.  The presence of a mark or a priority
setting is shown by a `+' character immediately following the message
number in the "headers" command display.
%%
X
%close%
There  are various  ways in which  you  may be  finished with  the
compose window. The most commonly used method is to simply "close"
the window to an iconic form.  This means that you  haven't really
quit,  but you  have merely put  it on "hold" till later.  It will
become an icon on the  side or corner of the  screen and appear to
sit  and do  nothing.  To close the window to icon form, there are
two methods. Both methods will have the same effect.
X
The first method is to select  this panel item with the left mouse
button. The second method is to use the tool manager around the
perimeter of the window and select "close".
X
There are two equally similar methods of removing the compose win-
dow rather than just closing to an icon: you may select the second
menu item in  the menu given by this panel item or you may use the
tool manager "quit" item.
%%
SHAR_EOF
echo 'File tool_help is complete' &&
chmod 0644 tool_help ||
echo 'restore of tool_help failed'
Wc_c="`wc -c < 'tool_help'`"
test 18926 -eq "$Wc_c" ||
	echo 'tool_help: original size 18926, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= tooledit.c ==============
if test -f 'tooledit.c' -a X"$1" != X"-c"; then
	echo 'x - skipping tooledit.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting tooledit.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'tooledit.c' &&
/* @(#)tooledit.c	(c) copyright	2/14/90 (Dan Heller) */
X
/*
X * intercept events in the compose window for auto-
X *	positioning and tilde command recognition.
X */
#include "mush.h"
X
static short dat_bentarrow[] = {
X    0x007F, 0x007F, 0x007F, 0x0007, 0x0407, 0x0C07, 0x1C07, 0x3807, 
X    0x7FFF, 0xFFFF, 0x7FFF, 0x3800, 0x1C00, 0x0C00, 0x0400, 0x0000
};
mpr_static(bent_arrow, 16, 16, 1, dat_bentarrow);
Cursor bentarrow;
X
extern void do_send(), do_edit();
X
/* Return the byte position in the textsw of the header specified */
Textsw_index
header_position(textsw, str)
Textsw textsw;
char *str;
{
X    char buf[256];
X    register char *p = buf, *p2;
X    int contd_hdr = 0, add_newline = 0;
X    Textsw_index pos = 0L, ret_pos = 0L;
X
X    buf[0] = 0;
X    for (;;) {
X	/* get a line at a time from the textsw */
X	(void) window_get(textsw, TEXTSW_CONTENTS, pos, buf, 256);
X	if (p = index(buf, '\n'))
X	    *p = 0;
X	else
X	    add_newline++;
X	p = buf;
X	skipspaces(0);
X	if (!*p) /* newline alone -- end of headers */
X	    break;
X	pos += strlen(buf) + 1; /* advance position to next line */
X	if (*p != ' ' && *p != '\t') {
X	    contd_hdr = 0;
X	    /* strcmp ignoring case */
X	    for (p2 = str; *p && *p2 && lower(*p2) == lower(*p); ++p, ++p2)
X		;
X	    /* MATCH is true if p2 is at the end of str and *p is ':' */
X	    if (*p2 || *p != ':') {
X		if (!*p2 && isspace(*any(p, ": \t"))) {
X		    /* Not a legal or continued header */
X		    pos -= strlen(buf) + 1; /* go back to beginning of line */
X		    break;
X		}
X		continue;
X	    } else {
X		contd_hdr = 1;
X		ret_pos = pos - 1;
X	    }
X	} else if (!contd_hdr)
X	    continue;
X    }
X    if (!ret_pos) {
X	/* coudn't find the header -- add it */
X	window_set(textsw, TEXTSW_INSERTION_POINT, pos, NULL);
X	p = buf;
X	if (add_newline)
X	    *p++ = '\n', pos--;
X	for (p2 = str; *p2; ++p2) {
X	    if (p2 == str || p2[-1] == '-')
X		*p++ = upper(*p2);
X	    else
X		*p++ = *p2;
X	}
X	*p++ = ':', *p++ = ' ', *p++ = '\n', *p = 0;
X	textsw_insert(textsw, buf, strlen(buf));
X	ret_pos = pos + strlen(buf) - 1;
X    }
X    return ret_pos;
}
X
/* position_flags indicates which header to go to when uses tilde commands */
static u_long position_flags;
static char *tilde_hdrs[] = {
#define POSITION_TO	ULBIT(0)
X    "to",
#define POSITION_SUBJ	ULBIT(1)
X    "subject",
#define POSITION_CC	ULBIT(2)
X    "cc",
#define POSITION_BCC	ULBIT(3)
X    "bcc",
#define POSITION_FCC	ULBIT(4)
X    "fcc"
};
#define POSITION_ALL \
X    ((POSITION_TO) | (POSITION_SUBJ) | (POSITION_CC) | (POSITION_BCC))
#define POSITION_END	ULBIT(5)
#define TOTAL_POSITIONS	6
X
/*
X * position_flags identifies which header is requested by the calling func.
X * use header_position to find the position of the header associated with
X * with the flags.
X */
static void
go_to_next_pos(textsw)
Textsw textsw;
{
X    Textsw_index pos;
X    int i = 0;
X
X    while (i < TOTAL_POSITIONS && isoff(position_flags, ULBIT(i)))
X	i++;
X    if (i == TOTAL_POSITIONS)
X	return;
X    if (i < ArraySize(tilde_hdrs))
X	pos = header_position(textsw, tilde_hdrs[i]);
X    else
X	pos = (Textsw_index)window_get(textsw, TEXTSW_LENGTH);
X    turnoff(position_flags, ULBIT(i));
X    if (!position_flags)
X	/* restore old cursor */
X	window_set(textsw,WIN_CURSOR, window_get(mfprint_sw, WIN_CURSOR), NULL);
X    else
X	window_set(textsw, WIN_CURSOR, bentarrow, NULL);
X    window_set(textsw, TEXTSW_INSERTION_POINT, pos, NULL);
X    textsw_normalize_view(textsw, (Textsw_index)0);
}
X
tilde_from_menu(item, value, event)
Panel_item item;
int value;
Event	*event;
{
X    Textsw textsw = (Textsw)panel_get(panel_get(item, PANEL_PARENT_PANEL),
X	PANEL_CLIENT_DATA);
X    if (value == 0 || event_id(event) == MS_LEFT)
X	position_flags = POSITION_ALL;
X    else
X	turnon(position_flags, ULBIT(value - 1));
X    panel_set_value(item, 0);
X    go_to_next_pos(textsw);
}
X
/*
X * This interpose function is here to parse for tilde escapes.
X * Note: this is a (currently) undocumented feature and is intended
X * as an accelerator for advanced users.  Supported tilde escapes
X * are: t,s,c,b,x,e and v.
X */
Notify_value
edit_msg_textwin(textsw, event, arg, type)
Textsw	textsw;
Event	*event;
Notify_arg	arg;
Notify_event_type	type;
{
X    char buf[2];
X    static char do_tilde;
X    Textsw_index pos;
X
X    if (do_tilde == 1 && event_is_ascii(event) &&
X	    /* make sure we are going to catch this switch */
X	    index("bschetv", event_id(event))) {
X	textsw_erase(textsw,
X	    (unsigned)window_get(textsw, TEXTSW_INSERTION_POINT)-1,
X	    (unsigned)window_get(textsw, TEXTSW_INSERTION_POINT));
X	switch (event_id(event)) {
X	    case 'h':
X		turnon(position_flags, POSITION_ALL);
X	    when 't':
X		turnon(position_flags, POSITION_TO);
X	    when 's':
X		turnon(position_flags, POSITION_SUBJ);
X	    when 'c':
X		turnon(position_flags, POSITION_CC);
X	    when 'b':
X		turnon(position_flags, POSITION_BCC);
X	    when 'e' : case 'v' : {
X		/* shouldn't use global -- hack for now */
X		extern Panel_item edit_item;
X		do_edit(edit_item);
X		return NOTIFY_DONE;
X	    }
X	}
X	do_tilde = 0;
X	go_to_next_pos(textsw);
X	return NOTIFY_DONE;
X    }
X    do_tilde = 0;
X    /* check to see if this is a potential tilde escape */
X    if (event_id(event) == *escape) {
X	/* get previous character entered */
X	pos = (Textsw_index)window_get(textsw, TEXTSW_INSERTION_POINT);
X	if (pos > 0)
X	    (void) window_get(textsw, TEXTSW_CONTENTS, pos-1, buf, 1);
X	/* test to see if ~ came at the beginning of a line */
X	if (pos < 1 || buf[0] == '\n')
X	    do_tilde = 1;
X    }
X    /* check for auto-next-header .. e.g. when you hit CR on To: go to Subj:
X     * special case backspace keys since textsw_start_of_display_line() has
X     * a bug where it gets the line # wrong when backspacing.
X     */
X    if (position_flags != 0L && ID != CTRL('H') && ID != 127) {
X	Notify_value val;
X	if (ID == '\n' || ID == '\r') {
X	    go_to_next_pos(textsw);
X	    return NOTIFY_DONE; /* don't process event */
X	}
X	/* we're still processing this header -- continue to do so unless
X	 * the event in question changes the line# of the insertion point.
X	 * first get current position...
X	 */
X	pos = (Textsw_index)window_get(textsw, TEXTSW_INSERTION_POINT);
X	/* now let the event be processed... */
X	val = notify_next_event_func(textsw, event, arg, type);
X	/* see if the line # for the new insertion point has changed. */
X	if (textsw_start_of_display_line(textsw, pos) !=
X	    textsw_start_of_display_line(textsw,
X		(Textsw_index)window_get(textsw, TEXTSW_INSERTION_POINT))) {
X	    /* the event (mouse button, ACTION_??), changed the line # */
X	    position_flags = 0L; /* disable auto-next-header */
X	    /* restore cursor */
X	    window_set(textsw,
X		WIN_CURSOR, window_get(mfprint_sw, WIN_CURSOR),
X		NULL);
X	}
X	return val;
X    }
X    return notify_next_event_func(textsw, event, arg, type);
}
X
/*
X * start the compose textsw.  This is here because we need position_flags
X * and the tilde-bits to set the insertion point at the To: line if
X * do_position is true.
X */
void
start_textsw_edit(textsw, do_position)
Textsw textsw;
{
X    extern char *hfile;
X    char *file = (char *)window_get(textsw, TEXTSW_CLIENT_DATA);
X    Textsw_index first, last, to_index;
X    int		i;
X
X    strdup(file, hfile);
#ifdef SUN_4_0 /* SunOS 4.0+ */
X    window_set(textsw,
X	TEXTSW_CLIENT_DATA,		file,
X	TEXTSW_FILE_CONTENTS,		hfile,
X	TEXTSW_READ_ONLY,		FALSE,
X	TEXTSW_STORE_CHANGES_FILE,	FALSE,
X	NULL);
#else /* SUN_4_0 */
X    textsw_load_file(textsw, hfile, 1, 0, 0);
X    window_set(textsw,
X	TEXTSW_CLIENT_DATA,		file,
X	TEXTSW_READ_ONLY,		FALSE,
X	TEXTSW_STORE_CHANGES_FILE,	FALSE,
X	NULL);
#endif /* SUN_4_0 */
X    position_flags = 0L;
X    if (do_position) {
X	turnon(position_flags, POSITION_TO);
X	if (do_set(set_options, "ask") || do_set(set_options, "asksub"))
X	    turnon(position_flags, POSITION_SUBJ);
X	if (do_set(set_options, "askcc"))
X	    turnon(position_flags, POSITION_CC);
X    }
X    turnon(position_flags, POSITION_END);
X    go_to_next_pos(textsw);
X    (void) unlink(hfile);
X    xfree(hfile), hfile = NULL;
}
X
/*ARGSUSED*/
void
do_edit(item, value, event)
Panel_item item;
int value;
register Event *event;
{
X    int argc;
X    char *file, **argv, *edit, cmd[MAXPATHLEN];
X    Panel_item next;
X    Panel panel = (Panel)panel_get(item, PANEL_PARENT_PANEL);
X    Textsw textsw = (Textsw)panel_get(panel, PANEL_CLIENT_DATA);
X
X    file = (char *)window_get(textsw, TEXTSW_CLIENT_DATA);
X    if (textsw_store_file(textsw, file, 0, 0)) {
X	error("Can't start editor");
X	return;
X    }
X    if ((!(edit = do_set(set_options, "visual")) || !*edit) &&
X	(!(edit = do_set(set_options, "editor")) || !*edit))
X	edit = DEF_EDITOR;
X    (void) sprintf(cmd, "%s %s", edit, file);
X    argc = 0;
X    if (!(argv = mk_argv(cmd, &argc, FALSE))) {
X	unlink(file);
X	return;
X    }
X    if (tool_edit_letter(textsw, argv) > -1) {
X	/* skip first panel item */
X	item = (Panel_item) panel_get(panel, PANEL_FIRST_ITEM);
X	for (item = (Panel_item) panel_get(item, PANEL_NEXT_ITEM);
X	     item; item = next) {
X	     next = (Panel_item) panel_get(item, PANEL_NEXT_ITEM);
X	     (void) panel_set(item, PANEL_SHOW_ITEM, FALSE, NULL);
X	}
X	position_flags = 0L;
X	window_set(textsw,WIN_CURSOR, window_get(mfprint_sw,WIN_CURSOR), NULL);
X    }
X    free_vec(argv);
}
SHAR_EOF
chmod 0644 tooledit.c ||
echo 'restore of tooledit.c failed'
Wc_c="`wc -c < 'tooledit.c'`"
test 9136 -eq "$Wc_c" ||
	echo 'tooledit.c: original size 9136, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= version.h ==============
if test -f 'version.h' -a X"$1" != X"-c"; then
	echo 'x - skipping version.h (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting version.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'version.h' &&
/* @(#)version.h	(c) Copyright 1989, 1990, 1991 (Dan Heller) */
X
#define MUSHNAME	"Mail User's Shell"
#define RELEASE_DATE	"4/12/91"
#define RELEASE		7
#define REVISION	"2"
#define PATCHLEVEL	2
SHAR_EOF
chmod 0644 version.h ||
echo 'restore of version.h failed'
Wc_c="`wc -c < 'version.h'`"
test 194 -eq "$Wc_c" ||
	echo 'version.h: original size 194, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= viewopts.c ==============
if test -f 'viewopts.c' -a X"$1" != X"-c"; then
	echo 'x - skipping viewopts.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting viewopts.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'viewopts.c' &&
/* @(#)viewopts.c	(c) copyright	10/18/86 (Dan Heller) */
X
#include "mush.h"
X
struct viewopts {
X    char *v_opt;
X    char *v_prompt;
X    char *v_description;
#ifdef SUNTOOL
X    Panel_item v_choice;
X    Panel_item v_text;
#endif /* SUNTOOL */
};
X
#ifdef SUNTOOL
short dat_cycle_cursor[] = {
X    0x07C0, 0x0FE0, 0x1834, 0x301C, 0x601C, 0x203C, 0x0000, 0x0000,
X    0x7808, 0x700C, 0x7018, 0x5830, 0x0FE0, 0x07C0, 0x0000, 0x0000
X
};
mpr_static(cycle,           16, 16, 1, dat_cycle_cursor);
#endif /* SUNTOOL */
X
/*
X * struct contains the option, a prompt if it has a string value, whether
X * or not it applies to non suntools, line mode, or both, and a
X * string describing what the option does. If the prompt string starts
X * with a minus sign, then the value can be set without a value. This
X * is there to indicate to option_line to print a toggle (cycle) pixrect
X * and to print TRUE/FALSE telling whether the value is on or off regardless
X * of it's "string" value.
X */
struct viewopts viewopts[] = {
X    { "alwaysignore", NULL,
X	"Always ignore the message headers on the 'ignored' list." },
X    { "ask", NULL,
X	"Prompts for a subject on outgoing mail." },
X    { "askcc", NULL,
X	"Ask for list of Carbon Copy recipients whenever sending mail." },
X    { "autodelete", NULL,
X	"Automatically delete ALL READ messages whenever you update mail." },
X    { "autoedit", NULL,
X	"Automatically enter editor for REPLIES only (not toolmode)." },
X    { "autoinclude", NULL,
X	"Include a copy of author's message each time you reply to mail." },
X    { "autoprint", NULL,
X	"Display the next message on the list when you delete a message." },
X    { "auto_route", "-Host/Path:",
X	"Remove redundant uucp addresses when replying to messages." },
X    { "autosign", "-Filename:",
X	"Add file (~/.signature if set but no value) at end of all letters." },
X    { "autosign2", "Addr:File:",
X	"Signature to use for specific addresses. \"addr, ... : <signature>\""},
X    { "cdpath", "Path:",
X	"Path to search for directories when the \"cd\" command is issued." },
X    { "cmd_help", "Path:",
X	"Location of the general help file for line and curses modes." },
X    { "complete", "Character:",
X	"The character typed to cause a word completion to occur." },
X    { "compose_icon", "-Filename:",
X	"Alternate pixmap to use when compose window is closed to an icon." },
X    { "crt", "Lines:",
X	"The number of lines a message must have for 'pager' to be invoked." },
X    { "crt_win", "Lines:",
X	"Lines in the tool mode text subwindow for paging messages." },
X    { "curses_help", "-Commands:",
X	"List of curses commands whose bindings appear in the help display." },
X    { "date_received", NULL,
X	"Time displayed for message headers shows date received (or sent)." },
X    { "dead", "Filename:",
X	"The name of the file to store dead mail (default = ~/dead.letter)." },
X    { "domain_route", "-Host/Path:",
X	"Cause short-circuiting of domain addresses when auto-routing." },
X    { "dot", NULL,
X	"Allow \".\" on a line by itself to send letter." },
X    { "edit_hdrs", NULL,
X	"Allow headers of messages to be edited using your editor." },
X    { "editor", "Editor:",
X	"Editor for message editing (default = env EDITOR or \"vi\")." },
X    { "escape", "Character:",
X	"Escape character for extended editing commands (default = ~)." },
X    { "fignore", "Patterns:",
X	"Filename extensions or patterns ignored in completions." },
X    { "folder", "Pathname:",
X	"Full pathname to the directory where personal folders are kept." },
X    { "fortune", "-Flag:",
X	"Add fortune to end of letters.  Flag to \"fortune\" is optional." },
X    { "fortunates", "Users:",
X	"Those who will receive fortunes if fortune is set (default: All)." },
X    { "hdr_format", "Format:",
X	"Formatting string for headers.  \"headers -?\" or help hdr_format." },
X    { "history", "Number:",
X	"How many commands to remember (like csh)." },
X    { "hold", NULL,
X	"Read but not deleted messages are saved in spool -- not mbox." },
X    { "home", "Directory:",
X	"The user's home directory." },
X    { "hostname", "Hostname:",
X	"User-definable name for the name of your machine." },
X    { "ignore_bang", NULL,
X	"Ignore '!' as a history reference.  Otherwise, escape by: \\!" },
X    { "ignoreeof", "-Command:",
X	"Ignores ^D as exit, or (if set), execute \"command\"." },
X    { "indent_str", "String:",
X	"String to offset included messages within your letters." },
X    { "in_reply_to", "-String:",
X	"When responding to mail, add In-Reply-To: to message headers." },
X    { "keepsave", NULL,
X	"Prevents messages from being marked as `deleted' when you `save'." },
X    { "known_hosts", "Host list:",
X	"List of hosts that your site is known to uucp mail to." },
X    { "logfile", "Filename:",
X	"Log outgoing mail headers only.  Message text not logged." },
X    { "mail_icon", "Filename:",
X	"Alternate pixmap to use when tool is closed to an icon." },
X    { "mbox", "Filename:",
X	"Filename to use instead of ~/mbox for default mailbox." },
X    { "metoo", NULL,
X	"When replying to mail, metoo preserves your name on mailing list." },
X    { "mil_time", NULL,
X	"24-hour military time format is used whenever a time is printed." },
X    { "msg_win", "Lines:",
X	"Number of lines in the message composition window for tool mode." },
X    { "newline", "-Command:",
X	"Ignore RETURN.  If set to a command, execute that command." },
X    { "newmail_icon", "Filename:",
X	"Alternate icon shown when new mail is available." },
X    { "no_expand", NULL,
X	"Prevents expansion of Mush aliases in outgoing mail headers." },
X    { "no_hdrs", NULL,
X	"If set, personalized headers are NOT inserted to outgoing mail." },
X    { "no_reverse", NULL,
X	"Disables reverse video in curses mode -- uses \"bold\" in tool mode."},
X    { "nonobang", NULL,
X	"Suppresses errors from unsuccessful history references." },
X    { "nosave", NULL,
X	"Prevents aborted mail from being saved in $dead." },
X    { "output", NULL,
X	"The message list produced as output of the last command." },
X    { "pager", "Program:",
X	"Program name to be used as a pager for messages longer than crt." },
X    { "pre_indent_str", "String:",
X	"String to precede message text interpolated into message body." },
X    { "post_indent_str", "String:",
X	"String to succeed message text interpolated into message body." },
X    { "print_cmd", "Program:",
X	"Alternate program to use to send messages to the printer." },
X    { "printer", "Printer:",
X	"Printer to send messages to (default = environment PRINTER)." },
X    { "prompt", "String:",
X	"Your prompt.  \"help prompt\" for more information." },
X    { "quiet", "-Conditions:",
X	"Turn off verbose messages and error bells in various conditions." },
X    { "realname", "Name:",
X	"Your real name." },
X    { "record", "Filename:",
X	"Save all outgoing mail in specified filename." },
X    { "reply_to_hdr", "Headers:",
X	"List of headers use to construct reply addresses from a message." },
X    { "save_empty", NULL,
X	"Folders which have all messages deleted are NOT removed on updates." },
X    { "screen", "# of Headers:",
X	"Number of headers to print in non-suntools (text) mode." },
X    { "screen_win", "# of Headers:",
X	"Set the size of the header window for the tool mode only." },
X    { "show_deleted", NULL,
X	"Show deleted messages in headers listings (unused in curses mode)." },
X    { "show_hdrs", "Headers:",
X	"When displaying a message, show list of \"headers\" only." },
X    { "sendmail", "Program:",
X	"Program to use to deliver mail instead of using the default."},
X    { "sort", "-Option:",
X	"Pre-sorting of messages on mush startup (set to valid sort option)." },
X    { "squeeze", NULL,
X	"When reading messages, squeeze all blank lines into one." },
X    { "status", NULL,
X	"The success or failure status of the most recent command." },
X    { "thisfolder", "Folder:",
X	"This read-only variable gives the current folder name." },
X    { "tool_help", "Path:",
X	"Location of the help file for tool mode."  },
X    { "toplines", "Lines:",
X	"Number of lines to print of a message for the 'top' command."  },
X    { "tmpdir", "Directory:",
X	"Directory to use for temporary files used by Mush." },
X    { "unix", NULL,
X	"Non-mush commands are considered to be UNIX commands." },
X    { "verify", NULL,
X	"Verify before acting in various situations, such as sending mail." },
X    { "visual", "Visual editor:",
X	"Visual editor for messages (default = $editor or env VISUAL)."},
X    { "warning", NULL,
X	"Print warning messages for non-fatal errors." },
X    { "wrap", NULL,
X	"After referencing last message, message pointer wraps to start." },
X    { "wrapcolumn", "-Column to wrap [78]:",
X	"Column at which to wrap lines when composing messages." },
};
X
#ifdef SUNTOOL
X
#define OPTIONS_PANEL_WIDTH	550
X
int set_value(), toggle_value(), help_opt();
X
Frame opts_frame;
Panel opts_panel;
Panel_item desc_msg;
Panel_item file_text_item;
X
static void
frame_done()
{
#ifdef SUN_4_0 /* SunOS 4.0+ */
X    window_set(opts_frame, WIN_SHOW, FALSE, NULL);
#else /* SUN_4_0 */
X    /* not enough fd's to keep it lying around for SunOS 3.X */
X    window_destroy(opts_frame);
X    opts_frame = (Frame) 0;
#endif /* SUN_4_0 */
}
X
static void
opts_help()
{
X    help(0, "options", tool_help);
}
X
static void
opts_save_load(item)
Panel_item item;
{
X    int (*func)() = (int (*)())panel_get(item, PANEL_CLIENT_DATA);
X    int result;
X    char buf[MAXPATHLEN];
X    char *argv[3], *file = panel_get_value(file_text_item);
X
X    if (!*file) {
X	result = (*func)(0, DUBL_NULL);
X	file = ".mushrc";
X    } else {
X	argv[1] = file;
X	argv[2] = NULL;
X	result = (*func)(2, argv);
X    }
X    switch (result) {
X	case 0:
X	    sprintf(buf, "%s %s",
X		(func == source)? "Loaded options from" : "Saved options to",
X		file);
X	when -1:
X	    sprintf(buf, "%s: %s", file, sys_errlist[errno]);
X	when -2:
X	    sprintf(buf, "%s is a directory.", file);
X	when -3:
X	    /* save_opts() returns -3 if user doesn't confirm overwrite */
X	    strcpy(buf, "Save operation aborted.");
X    }
X    panel_set(desc_msg, PANEL_LABEL_STRING, buf, NULL);
}
X
static void
unset_opts()
{
X    cmd_line("unset *", NULL);
}
X
static void
reset_opts()
{
X    source(0, DUBL_NULL);
}
X
/*
X * Public routine which creates a subframe which contains two panels.
X * The first contains options for loading and saving options from a
X * file (text item) and so on... the second panel contains all the items
X * which correspond to each mush variable that exists.
X */
void
view_options()
{
X    extern Notify_value fkey_interposer();
X    register char *p;
X    int count;
X
X    if (opts_frame) {
X	window_set(opts_frame, WIN_SHOW, TRUE, NULL);
X	opts_panel_item(NULL);
X	return;
X    }
#ifdef SUN_3_5
X    if (nopenfiles(0) < 3) {
X	ok_box("Too many frames; close one first!\n");
X	return;
X    }
#endif /* SUN_3_5 */
X
X    opts_frame = window_create(tool, FRAME,
X	FRAME_DONE_PROC,	frame_done,
X	FRAME_LABEL,		"Mush Options",
X	FRAME_NO_CONFIRM,	TRUE,
X	FRAME_SHOW_LABEL,	TRUE,
X	WIN_WIDTH,		OPTIONS_PANEL_WIDTH,
X	NULL);
X
X    opts_panel = window_create(opts_frame, PANEL,
X	WIN_WIDTH,		OPTIONS_PANEL_WIDTH,
X	NULL);
X    (void) notify_interpose_event_func(opts_panel,
X	fkey_interposer, NOTIFY_SAFE);
X    panel_create_item(opts_panel, PANEL_BUTTON,
X	PANEL_LABEL_IMAGE,
X	    panel_button_image(opts_panel, "Done", 4, mush_font),
X	PANEL_NOTIFY_PROC,	frame_done,
X	NULL);
X    panel_create_item(opts_panel, PANEL_BUTTON,
X	PANEL_LABEL_IMAGE,
X	    panel_button_image(opts_panel, "Help", 4, mush_font),
X	PANEL_NOTIFY_PROC,	opts_help,
X	NULL);
X    panel_create_item(opts_panel, PANEL_BUTTON,
X	PANEL_LABEL_IMAGE,
X	    panel_button_image(opts_panel, "Save", 4, mush_font),
X	PANEL_NOTIFY_PROC,	opts_save_load,
X	PANEL_CLIENT_DATA,	save_opts,
X	NULL);
X    panel_create_item(opts_panel, PANEL_BUTTON,
X	PANEL_LABEL_IMAGE,
X	    panel_button_image(opts_panel, "Load", 4, mush_font),
X	PANEL_NOTIFY_PROC,	opts_save_load,
X	PANEL_CLIENT_DATA,	source,
X	NULL);
X    panel_create_item(opts_panel, PANEL_BUTTON,
X	PANEL_LABEL_IMAGE,
X	    panel_button_image(opts_panel, "Clear", 5, mush_font),
X	PANEL_NOTIFY_PROC,	unset_opts,
X	NULL);
X    panel_create_item(opts_panel, PANEL_BUTTON,
X	PANEL_LABEL_IMAGE,
X	    panel_button_image(opts_panel, "Restart", 7, mush_font),
X	PANEL_NOTIFY_PROC,	reset_opts,
X	NULL);
X    file_text_item = panel_create_item(opts_panel, PANEL_TEXT,
X	PANEL_LABEL_STRING,	"Save/Load File:",
X	PANEL_VALUE_DISPLAY_LENGTH, 30,
X	NULL);
X    desc_msg = panel_create_item(opts_panel, PANEL_MESSAGE,
X	PANEL_LABEL_STRING,	"Help Descriptions -- Click on Variable Name",
X	NULL);
X    window_fit_height(opts_panel);
X
X    /* reuse opts_panel -- we don't need the other one */
X    opts_panel = window_create(opts_frame, PANEL,
X	WIN_BELOW,			opts_panel,
X	WIN_X,				0,
X	WIN_COLUMN_GAP,			120,
X	WIN_TOP_MARGIN,			10,
X	WIN_LEFT_MARGIN,		10,
X	WIN_WIDTH,			OPTIONS_PANEL_WIDTH,
X	PANEL_VERTICAL_SCROLLBAR,	scrollbar_create(NULL),
X	NULL);
X    (void) notify_interpose_event_func(opts_panel,
X	fkey_interposer, NOTIFY_SAFE);
X
X    for (count = 0; count < ArraySize(viewopts); count++) {
X	panel_create_item(opts_panel, PANEL_MESSAGE,
X	    PANEL_ITEM_X,	ATTR_COL(0),
X	    PANEL_ITEM_Y,	ATTR_ROW(count),
X	    PANEL_LABEL_STRING,	viewopts[count].v_opt,
X	    PANEL_NOTIFY_PROC,	help_opt,
X	    PANEL_CLIENT_DATA,	count,
X	    NULL);
X
X	if (!(p = viewopts[count].v_prompt) || *p == '-') {
X	    if (p && *p)
X		p++;
X	    viewopts[count].v_choice = panel_create_item(opts_panel,
X		PANEL_CHOICE,
X		PANEL_LABEL_IMAGE,	&cycle,
X		PANEL_LAYOUT,		PANEL_HORIZONTAL,
X		PANEL_CHOICE_STRINGS,	"False", "True", NULL,
X		PANEL_DISPLAY_LEVEL,	PANEL_CURRENT,
X		PANEL_ITEM_X,		ATTR_COL(1),
X		PANEL_ITEM_Y,		ATTR_ROW(count),
X		PANEL_NOTIFY_PROC,	toggle_value,
X		PANEL_CLIENT_DATA,	count,
X		NULL);
X	}
X	if (p) {
X	    viewopts[count].v_text = panel_create_item(opts_panel, PANEL_TEXT,
X		PANEL_VALUE_DISPLAY_LENGTH,	10,
X		PANEL_VALUE_UNDERLINED,		TRUE,
X		PANEL_LABEL_STRING,		p,
X		PANEL_ITEM_X,			ATTR_COL(2),
X		PANEL_ITEM_Y,			ATTR_ROW(count),
X		PANEL_NOTIFY_PROC,		set_value,
X		PANEL_CLIENT_DATA,		count,
X		NULL);
X	}
X    }
X    /* set the panel items' values */
X    opts_panel_item(NULL);
X
X    window_set(opts_panel,
X	WIN_HEIGHT,	400,
X	WIN_FIT_HEIGHT,	0,
X	NULL);
X    window_set(opts_frame, WIN_SHOW, TRUE, NULL);
}
X
/*
X * Sets the items in the panels to reflect that variable's value.
X * If "var" is NULL, do it for all the items.
X */
void
opts_panel_item(var)
char *var;
{
X    int count;
X    char *value;
X
X    if (!opts_frame)
X	return;
X
X    for (count = 0; count < ArraySize(viewopts); count++) {
X	if (var && strcmp(var, viewopts[count].v_opt))
X	    continue;
X	value = do_set(set_options, viewopts[count].v_opt);
X
X	if (!viewopts[count].v_prompt || *viewopts[count].v_prompt == '-')
X	    panel_set_value(viewopts[count].v_choice, value != NULL);
X	if (viewopts[count].v_prompt)
X	    panel_set_value(viewopts[count].v_text, value? value : "");
X	if (var)
X	    break;
X    }
}
X
/*
X * Callback for choice items -- for variables that have boolean settings.
X * CLIENT_DATA is the index in the viewopts array.
X */
static
toggle_value(item, value)
Panel_item item;
int value;
{
X    int count = (int) panel_get(item, PANEL_CLIENT_DATA);
X    char *p, *argv[4];
X    char *text_value = NULL;
X
X    if (check_internal(viewopts[count].v_opt)) {
X	panel_set(desc_msg, PANEL_LABEL_STRING,
X	    "This is an internal variable which cannot be changed.",
X	    NULL);
X	/* can't change it - restore previous setting */
X	panel_set_value(viewopts[count].v_choice, !value);
X	return -1;
X    }
X
X    if (p = viewopts[count].v_prompt) /* set equal */
X	text_value = panel_get_value(viewopts[count].v_text);
X
X    if (!value) {
X	if (un_set(&set_options, viewopts[count].v_opt) == -1) {
X	    /* can't change it - restore previous setting */
X	    panel_set_value(viewopts[count].v_choice, !value);
X	    return -1;
X	}
X    } else {
X	/* Turn it on if it's entirely boolean or bool/str, but no str value */
X	if (!p || text_value && !*text_value) {
X	    argv[0] = viewopts[count].v_opt; /* it's a boolean */
X	    argv[1] = NULL;
X	} else {
X	    /* string value -- determine the text from the typed in value */
X	    argv[0] = viewopts[count].v_opt;
X	    argv[1] = "=";
X	    argv[2] = text_value;
X	    argv[3] = NULL;
X	}
X	if (add_option(&set_options, argv) != 1) {
X	    /* can't change it - restore previous setting */
X	    panel_set_value(viewopts[count].v_choice, !value);
X	    return -1;
X	}
X    }
X
X    if (!strcmp(viewopts[count].v_opt, "no_reverse") ||
X	!strcmp(viewopts[count].v_opt, "show_deleted"))
X	do_hdrs(0, DUBL_NULL, NULL);
X
X    return 0;
}
X
/* callback for text items -- set vars to the string typed. */
static
set_value(item, event)
Panel_item item;
Event *event;
{
X    int count = (int)panel_get(item, PANEL_CLIENT_DATA);
X    char *p, *argv[4], *value;
X
X    if (event_id(event) == '\t')
X	return (int) PANEL_NEXT;
X
X    p = viewopts[count].v_prompt;
X    value = panel_get_value(item);
X
X    if (check_internal(viewopts[count].v_opt)) {
X	panel_set(desc_msg, PANEL_LABEL_STRING,
X	    "This is an internal variable which cannot be changed.",
X	    NULL);
X	return (int) PANEL_NONE;
X    }
X
X    /*
X     * You can "unset" string-only values by entering a blank string.
X     * If the "prompt" starts with a -, then you can only "unset" the
X     * variable by setting the associated choice item to false.
X     */
X    if (*p != '-' && !*value) {
X	(void) un_set(&set_options, viewopts[count].v_opt);
X	return (int) PANEL_NONE; /* do not advance caret */
X    }
X    /* Turn it on, but not to a value */
X    if (!*value) {
X	argv[0] = viewopts[count].v_opt; /* it's a boolean */
X	argv[1] = NULL;
X    } else {
X	/* string value -- determine the text from the typed in value */
X	argv[0] = viewopts[count].v_opt;
X	argv[1] = "=";
X	argv[2] = value;
X	argv[3] = NULL;
X    }
X
X    if (add_option(&set_options, argv) == 1 && p && *p == '-')
X	panel_set_value(viewopts[count].v_choice, TRUE);
X
X    return (int) PANEL_NONE;
}
X
/* when user clicks on variable label itself */
static
help_opt(item, event)
Panel_item item;
Event *event;
{
X    int count = (int)panel_get(item, PANEL_CLIENT_DATA);
X
X    panel_set(desc_msg,
X	PANEL_LABEL_STRING, viewopts[count].v_description,
X	NULL);
X    return 0;
}
X
#endif /* SUNTOOL */
X
/*
X * return a string describing a variable.
X * parameters: count, str, buf.
X * If str != NULL, check str against ALL variables
X * in viewopts array.  The one that matches, set count to it and 
X * print up all the stuff from the viewopts[count] into the buffer
X * space in "buf" and return it.
X */
char *
variable_stuff(count, str, buf)
register char *str, *buf;
{
X    if (str)
X	for (count = 0; count < ArraySize(viewopts); count++)
X	    if (!strcmp(str, viewopts[count].v_opt))
X		break;
X    if (count >= ArraySize(viewopts)) {
X	(void) sprintf(buf, "%s: Not a default %s variable.",
X			   str? str : itoa(count), prog_name);
X	return NULL;
X    }
X    return sprintf(buf, "%s: %s",
X	viewopts[count].v_opt, viewopts[count].v_description);
}
SHAR_EOF
chmod 0644 viewopts.c ||
echo 'restore of viewopts.c failed'
Wc_c="`wc -c < 'viewopts.c'`"
test 18782 -eq "$Wc_c" ||
	echo 'viewopts.c: original size 18782, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
rm -f _shar_seq_.tmp
echo You have unpacked the last part
exit 0
exit 0 # Just in case...
-- 
Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
Sterling Software, IMD           UUCP:     uunet!sparky!kent
Phone:    (402) 291-8300         FAX:      (402) 291-4362
Please send comp.sources.misc-related mail to kent@uunet.uu.net.