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

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

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

#!/bin/sh
# do not concatenate these parts, unpack them in order with /bin/sh
# file dates.c continued
#
if test ! -r _shar_seq_.tmp; then
	echo 'Please unpack part 1 first!'
	exit 1
fi
(read Scheck
 if test "$Scheck" != 7; 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 dates.c'
else
echo 'x - continuing file dates.c'
sed 's/^X//' << 'SHAR_EOF' >> 'dates.c' &&
X
X    (void) strncpy(zone, tz, 7), zone[7] = 0;
X    return T;
}
X
/* Time() returns a string according to criteria:
X *   if "now" is 0, then the current time is gotten and used.
X *       else, use the time described by now
X *   opts points to a string of args which is parsed until an unknown
X *       arg is found and opts will point to that upon return.
X *   valid args are T (time of day), D (day of week), M (month), Y (year),
X *       N (number of day in month -- couldn't think of a better letter).
X */
char *
Time(opts, now)
register char *opts;
long now;
{
X    static char time_buf[30];
X    struct tm 	  *T;
X    register char *p = time_buf;
X    long	  x;
X
X    if (!opts)
X	return NULL;
X    if (now)
X	x = now;
X    else
X	(void) time(&x);
X    T = localtime(&x);
X    for (;; opts++) {
X	switch(*opts) {
X	    case 'T':
X		if (ison(glob_flags, MIL_TIME))
X		    (void) sprintf(p, "%2d:%02d", T->tm_hour, T->tm_min);
X		else
X		    (void) sprintf(p, "%d:%02d", (T->tm_hour) ?
X			  ((T->tm_hour <= 12) ? T->tm_hour : T->tm_hour - 12) :
X			  12, T->tm_min);
X	    when 'D': case 'W': (void) strcpy(p, day_names[T->tm_wday]);
X	    when 'M': (void) strcpy(p, month_names[T->tm_mon]);
X	    when 'y': (void) sprintf(p, "%d", T->tm_year);
X	    when 'Y': (void) sprintf(p, "%d", T->tm_year + 1900);
X	    when 'N': (void) sprintf(p, "%d", T->tm_mday);
X	    otherwise: *--p = 0; return time_buf;
X	}
X	p += strlen(p);
X	*p++ = ' ';
X    }
}
X
/* parse date and return a string that looks like
X *   %ld%3c%s	gmt_in_secs weekday orig_timezone
X * This function is a bunch of scanfs on known date formats.  Don't
X * trust the "weekday" name fields because they may not be spelled
X * right, or have the correct punctuation.  Figure it out once the
X * year and month and date have been determined.
X */
char *
parse_date(p)
register char *p;
{
X    /* When scanf-ing if month isn't a month, it could be a _long_ string.
X     * this is also the static buffer whose address we return.
X     */
X    static char month[64];
X    char Wkday[4], Zone[12], dst[4];
X    char a_or_p;
X    int Month = 0, Day = 0, Year = 0;
X    int Hours = -1, Mins = -1;
X    struct tm T;
X
X    Zone[0] = dst[0] = 0;
X    skipspaces(0);
X
X    /* programmer's note -- there are too many scanfs here for some compilers
X     * to put them all into one if statement.  Use goto's :-(  Also reset
X     * Zone[0] after any sscanf() that could corrupt it on a partial match.
X     *
X     * Not yet handling all possible combinations of mailers using two-word
X     * time zones, e.g. MET DST instead of MEST.  Only the specific case
X     * where this was reported has been handled here.
X     */
X
X    /* RFC822 formats and minor variations -- order important */
X
X    /*   day_number month_name year_number time timezone */
X    if (sscanf(p, "%d %s %d %d:%d:%*d %7s %3s",
X	    &Day, month, &Year, &Hours, &Mins, Zone, dst) >= 5 && Day)
X	goto gotit;
X    Zone[0] = dst[0] = 0;
X    if (sscanf(p, "%d %s %d %d:%d %7s",
X	    &Day, month, &Year, &Hours, &Mins, Zone, dst) >= 5 && Day)
X	goto gotit;
X    Zone[0] = dst[0] = 0;
X    /*   day_name day_number month_name year_number time timezone */
X    if (sscanf(p, "%*s %d %s %d %d:%d:%*d %7s %3s",
X	    &Day, month, &Year, &Hours, &Mins, Zone, dst) >= 5 && Day)
X	goto gotit;
X    Zone[0] = dst[0] = 0;
X    if (sscanf(p, "%*s %d %s %d %d:%d %7s %3s",
X	    &Day, month, &Year, &Hours, &Mins, Zone, dst) >= 5 && Day)
X	goto gotit;
X    Zone[0] = dst[0] = 0;
X
X    /* Ctime format (From_ lines) -- timezone almost never found */
X
X    /*   day_name month_name day_number time year_number */
X    if (sscanf(p, "%*s %s %d %d:%d:%*d %d",
X	    month, &Day, &Hours, &Mins, &Year) == 5)
X	goto gotit;
X    /*   day_name month_name day_number time timezone year_number */
X    if (sscanf(p, "%*s %s %d %d:%d:%*d %7s %d",
X	    month, &Day, &Hours, &Mins, Zone, &Year) == 6)
X	goto gotit;
X    Zone[0] = 0;
X    if (sscanf(p, "%*s %s %d %d:%d:%*d %7s %3s %d",
X	    month, &Day, &Hours, &Mins, Zone, dst, &Year) == 7)
X	goto gotit;
X    Zone[0] = dst[0] = 0;
X
X    /* Other common variants */
X
X    /*   day_number month_name year_number time-timezone (day) */
X    /*                                       ^no colon separator */
X    if (sscanf(p, "%d %s %d %2d%2d-%6[0123456789]",
X	    &Day, month, &Year, &Hours, &Mins, &Zone[1]) == 6) {
X	Zone[0] = '-';
X	goto gotit;
X    }
X    if (sscanf(p, "%d %s %d %2d%2d-%7s",
X	    &Day, month, &Year, &Hours, &Mins, Zone) == 6)
X	goto gotit;
X    Zone[0] = 0;
X
X    /*   day_number month_name year_number time timezone	*/
X    /*                                      ^no colon separator */
X    /*   (This is the odd one in the RFC822 examples section;	*/
X    /*    also catches the slop from partial hits above.)	*/
X    if (sscanf(p, "%d %s %d %2d%2d %7s",
X	    &Day, month, &Year, &Hours, &Mins, Zone) >= 5 && Day)
X	goto gotit;
X    Zone[0] = 0;
X    
X    Zone[1] = 0;	/* Yes, Zone[1] -- tested below */
X
X    /*   day_number month_name year_number, time "-" ?? */
X    if (sscanf(p,"%d %s %d, %d:%d:%*d -%6[0123456789]",
X	    &Day, month, &Year, &Hours, &Mins, &Zone[1]) >= 5 && Day) {
X	if (Zone[1])
X	    Zone[0] = '-';
X	goto gotit;
X    }
X
X    /*   day_number month_name year_number 12_hour_time a_or_p */
X    if (sscanf(p, "%d %s %d %d:%d:%*d %cm %7s",
X	    &Day, month, &Year, &Hours, &Mins, &a_or_p, Zone) >= 6) {
X	if (a_or_p == 'p')
X	    Hours += 12;
X	goto gotit;
X    }
X
X    /*   day_name month_name day_number year_number time */
X    if (sscanf(p, "%*s %s %d %d %d:%d:%*d %7s",
X	    month, &Day, &Year, &Hours, &Mins, Zone) >= 5)
X	goto gotit;
X    Zone[0] = 0;
X    if (sscanf(p, "%*s %s %d %d %d:%d %7s",
X	    month, &Day, &Year, &Hours, &Mins, Zone) >= 5)
X	goto gotit;
X    Zone[0] = 0;
X
X    /*   day_name month_name day_number time timezone year_number */
X    if (sscanf(p, "%*s %s %d %d:%d:%*d %7s %d",
X	    month, &Day, &Hours, &Mins, Zone, &Year) == 6)
X	goto gotit;
X    Zone[0] = 0;
X    if (sscanf(p, "%*s %s %d %d:%d %7s %d",
X	    month, &Day, &Hours, &Mins, Zone, &Year) == 6)
X	goto gotit;
X    Zone[0] = 0;
X
X    /*   day_number-month_name-year time */
X    if (sscanf(p,"%d-%[^-]-%d %d:%d", &Day, month, &Year, &Hours, &Mins) == 5)
X	goto gotit;
X
X    /*   day_name, day_number-month_name-year time */
X    if (sscanf(p,"%*s %d-%[^-]-%d %d:%d",
X	    &Day, month, &Year, &Hours, &Mins) == 5)
X	goto gotit;
X
X    /*   year_number-month_number-day_number time */
X    if (sscanf(p, "%d-%d-%d %d:%d", &Year, &Month, &Day, &Hours, &Mins) == 5)
X	goto gotit;
X
X    /*   month_name day_number time year Zone */
X    /*   (ctime, but without the day name)    */
X    if (sscanf(p, "%s %d %d:%d:%*d %d %7s",
X	    month, &Day, &Hours, &Mins, &Year, Zone) >= 5)
X	goto gotit;
X    Zone[0] = 0;
X
X    if (ison(glob_flags, WARNING))
X	print("Unknown date format: %s\n", p);
X    return NULL;
X
gotit:
X    if (!lcase_strncmp(dst, "dst", -1)) {
X	(void) strcat(Zone, " ");
X	(void) strcat(Zone, dst);
X    }
X    if (Year > 1900)
X	Year -= 1900;
X    if (!Month && (Month = month_to_n(month)) == -1) {
X	print("bad month: %s\n", p);
X	return NULL;
X    }
X    if (Zone[0] == 0) {
X	/* Use local time zone if none found -- important for date_recv */
X	(void) time_n_zone(Zone);
X    }
X    {
X	/* Lots of foolishness with casts for Xenix-286 16-bit ints */
X
X	long days_ctr;	/* 16-bit ints overflowed Sept 12, 1989 */
X
X    	days_ctr = ((long)Year * 365L) + ((Year + 3) / 4);
X    	days_ctr += mtbl[Month-1] + Day + 6;
X    	if (Month > 2 && (Year % 4 == 0))
X	    days_ctr++;
X    	(void) (sprintf(Wkday, "%.3s", day_names[(int)(days_ctr % 7L)]));
X    }
X    T.tm_sec = 0;		/* not recorded, so ignore it */
X    T.tm_min = Mins;
X    T.tm_hour = Hours;
X    T.tm_mday = Day;
X    T.tm_mon = Month - 1;
X    T.tm_year = Year;
X    T.tm_wday = T.tm_yday = 0;	/* not used in time2gmt() */
X    T.tm_isdst = 0;		/* determined from Zone */
X    return sprintf(month, "%ld%s%s", time2gmt(&T, Zone, 1), Wkday, Zone);
}
X
/* pass a string in the standard date format, put into string.
X * return values in buffers provided they are not null.
X */
char *
date_to_string(Date, Yr, Mon, Day, Wkday, Tm, Zone, ret_buf)
char *Date, *Yr, *Mon, *Day, *Wkday, *Tm, *Zone, *ret_buf;
{
X    long gmt;
X    struct tm *T;
X    char a_or_p, *p = ret_buf;
X
X    Zone[0] = 0;
X    (void) sscanf(Date, "%ld%3c%s", &gmt, Wkday, Zone);
X    Wkday[3] = 0;
X    gmt += getzoff(Zone);
X    T = gmtime(&gmt);
X    a_or_p = (T->tm_hour < 12)? 'a': 'p';
X
X    (void) sprintf(Yr, "%d", T->tm_year + 1900);
X    (void) sprintf(Day, "%d", T->tm_mday);
X    (void) strcpy(Mon, month_names[T->tm_mon]);
X    p += strlen(sprintf(p, "%s %2.d, ", Mon, T->tm_mday));
X
X    if (ison(glob_flags, MIL_TIME))
X	(void) sprintf(p, "%2d:%02d",T->tm_hour,T->tm_min);
X    else
X	(void) sprintf(p, "%2.d:%02d%cm",
X	      (T->tm_hour)? (T->tm_hour <= 12)? T->tm_hour: T->tm_hour-12: 12,
X	      T->tm_min, a_or_p);
X    (void) strcpy(Tm, p);
X
X    return ret_buf;
}
X
/* pass a string in the internal mush date format.
X * return pointer to static buffer holding ctime-format date.
X */
char *
date_to_ctime(Date)
char *Date;
{
X    static char ret_buf[32];
X    long gmt;
X
X    ret_buf[0] = 0;
X    (void) sscanf(Date, "%ld", &gmt);
X    (void) strcpy(ret_buf, ctime(&gmt));
X
X    return ret_buf;
}
X
/*
X * Build a date string according to the specification in the RFC for Date:
X */
char *
rfc_date(buf)
char buf[];
{
X    struct tm *T;
X    char zone[8];
X
X    T = time_n_zone(zone);
#ifndef USA
X    {
X	long zoff_hr, zoff_sec = getzoff(zone);
X	if (zoff_sec < 0) {
X	    zone[0] = '-';
X	    zoff_sec = -zoff_sec; 
X	} else
X	    zone[0] = '+';
X	zoff_hr = zoff_sec / 3600;
X	zoff_sec -= zoff_hr * 3600;
X	(void) sprintf(&zone[1], "%02d%02d", zoff_hr, zoff_sec / 60);
X    }
#endif /* !USA */
X
X    return sprintf(buf, "%s, %d %s %d %02d:%02d:%02d %s",
X	day_names[T->tm_wday],	/* day name */
X	T->tm_mday,		/* day of the month */
X	month_names[T->tm_mon],	/* month name */
X	T->tm_year + 1900,	/* year number */
X	T->tm_hour,		/* hours (24hr) */
X	T->tm_min, T->tm_sec,	/* mins/secs */
X	zone);			/* timezone */
}
X
#define JAN	1
#define FEB	2
#define MAR	3
#define APR	4
#define MAY	5
#define JUN	6
#define JUL	7
#define AUG	8
#define SEP	9
#define OCT	10
#define NOV	11
#define DEC	12
X
/* stolen direct from ELM */
month_to_n(name)
register char *name;
{
X    /** return the month number given the month name... **/
X
X    register char ch;
X
X    switch (lower(*name)) {
X	case 'a' : if ((ch = lower(name[1])) == 'p')
X		       return(APR);
X		   else if (ch == 'u')
X		       return(AUG);
X		   else return(-1);	/* error! */
X	case 'd' : return(DEC);
X	case 'f' : return(FEB);
X	case 'j' : if ((ch = lower(name[1])) == 'a')
X		       return(JAN);
X		   else if (ch == 'u') {
X		     if ((ch = lower(name[2])) == 'n')
X			 return(JUN);
X		     else if (ch == 'l')
X			 return(JUL);
X		     else return(-1);		/* error! */
X		   }
X		   else return(-1);		/* error */
X	case 'm' : if ((ch = lower(name[2])) == 'r')
X		       return(MAR);
X		   else if (ch == 'y')
X		       return(MAY);
X		   else return(-1);		/* error! */
X	case 'n' : return(NOV);
X	case 'o' : return(OCT);
X	case 's' : return(SEP);
X	default  : return(-1);
X    }
}
SHAR_EOF
echo 'File dates.c is complete' &&
chmod 0644 dates.c ||
echo 'restore of dates.c failed'
Wc_c="`wc -c < 'dates.c'`"
test 15621 -eq "$Wc_c" ||
	echo 'dates.c: original size 15621, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= digestify ==============
if test -f 'digestify' -a X"$1" != X"-c"; then
	echo 'x - skipping digestify (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting digestify (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'digestify' &&
#! ../bin/mush -F!
#
# Mush digestifier.  Makes a folder or a list of messages into a digest.
#
# A "digest" is a collection of E-mail messages bundled together into a
# single message for ease of redistribution.  The individual messages
# in the digest are called "articles".  Each article has a small set of
# essential headers (usually From:, Date:, and Subject:) and is divided
# from the preceding and following articles by an "article separator"
# string (usually eight hyphens, "--------").  The Mush built-in command
# "undigest" unpacks most digests, including those made by this script.
#
# Usage:
#  From your shell:		digestify -f mailbox
#  From within mush:	
#	First:		cmd digest "set digest = '\!*' ; source digestify"
#	Then:		digest [msg-list]
#	Or:		message-selection-command | digest
#
# Note that by default it makes a digest of the ENTIRE folder!
#
X
#
# Rudimentary sanity checks
#
if ! $?version
X    echo "You must have Mush version 7.0 or higher to run this script"
X    exit
endif
if ! $?thisfolder
X    echo "You can't use this script as an init file; try using -F"
X    exit
endif
X
#
# Set up defaults
#
if ! $?digest
X    set digest = *
X    if $?interact
X	unset interact		# Assume non-interactive if no input list
X    endif
else
X    set interact		# Note that this is interactive
X    if "X$digest" == X
X        set digest = *		# Default to all messages for empty input
X    else
X	$digest | set digest	# Pre-expand message numbers
X    endif
endif
X
#
# Suppress any "that isn't set" messages from "unset"
#
if $?warning
X    set savewarn
endif
unset warning oldpre oldpost oldindent oldign oldshow
X
#
# Save everything in case the user wants it back.
# Could wrap all this with "if $?interact" but this script
# might be read by "mush -F", in which case we need this.
#
if $?pre_indent_str
X    set oldpre = "$pre_indent_str"
endif
if $?post_indent_str
X    set oldpost = "$post_indent_str"
endif
if $?indent_str
X    set oldindent = "$indent_str"
endif
if $?alwaysignore
X    set oldign = "$alwaysignore"
endif
if $?show_hdrs
X    set oldshow = "$show_hdrs"
endif
if $?quiet
X    set oldquiet = "$quiet"
endif
if $?no_expand
X    set savenoex
endif
X
#
# Prepare to form the digest.
#
set indent_str no_expand alwaysignore=include quiet=await,newmail
unset post_indent_str
alias DIGEST $thisfolder		# Any target in place of $thisfolder
set pre_indent_str="--------"		# Insert your digest separator here
set show_hdrs=from,date,subject		# Add any other headers you want
X
#
# Now do it.  All that work for a two-line operation ....
# NOTE: If you change DIGEST above, remove the "await" command here!
# Backslashes prevent any cmd expansion from confusing us.
#
\delete $digest
\mail -UH /dev/null -I $digest -s "Digest of $thisfolder" DIGEST; \await -T 1
X
#
# Clean out the deleted stuff if not interactive
#
if ! $?interact
X    \update
endif
X
#
# Be neat and put everything back the way it was.
#
unset indent_str no_expand alwaysignore quiet pre_indent_str show_hdrs
unalias DIGEST
if $?savenoex
X    set no_expand
endif
if $?oldquiet
X    set quiet = "$oldquiet"
endif
if $?oldpre
X    set pre_indent_str = "$oldpre"
endif
if $?oldpost
X    set post_indent_str = "$oldpost"
endif
if $?oldindent
X    set indent_str = "$oldindent"
endif
if $?oldign
X    set alwaysignore = "$oldign"
endif
if $?oldshow
X    set show_hdrs = "$oldshow"
endif
unset oldpre oldpost oldindent oldign oldshow oldquiet nonoex digest
if $?savewarn
X    unset savewarn
X    set warning
endif
SHAR_EOF
chmod 0755 digestify ||
echo 'restore of digestify failed'
Wc_c="`wc -c < 'digestify'`"
test 3468 -eq "$Wc_c" ||
	echo 'digestify: original size 3468, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= doproc.c ==============
if test -f 'doproc.c' -a X"$1" != X"-c"; then
	echo 'x - skipping doproc.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting doproc.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'doproc.c' &&
/* @(#)doproc.c		(c) copyright	10/18/86 (Dan Heller) */
X
/* do main panel item procedures */
#include "mush.h"
X
extern void start_textsw_edit();
extern Panel get_compose_panel();
void set_comp_items();
X
extern Panel_item
X    file_item, folder_text_item, folder_item, msg_num_item, read_item,
X    reply_item, save_item, sub_hdr_item[6];
X
/* following macro is for the next two procedures */
#define hdr_item(item) \
X    (item == sub_hdr_item[0] || item == sub_hdr_item[1] || \
X     item == sub_hdr_item[2] || item == sub_hdr_item[3] || \
X     item == sub_hdr_item[4] || item == sub_hdr_item[5])
X
void
delete_mail(item, value, event)
register Panel_item item;
int value;
register Event *event;
{
X    int val = value; /* save cuz we reset value immediately */
X    u_long bang = ison(glob_flags, IGN_BANG);
X    char buf[128];
X
X    (void) panel_set(item, PANEL_VALUE, 0, 0);
X    if (hdr_item(item) && event_id(event) != MS_LEFT || val == 2) {
X	help(0, "delete", tool_help);
X	return;
X    }
X    /* delete current message */
X    wprint(sprintf(buf, "\\%sdelete %s\n",
X	((event_id(event) == MS_LEFT || val == 0)? "" : "un"),
X	panel_get_value(msg_num_item)) + 1); /* +1 skips the backslash */
X    turnon(glob_flags, IGN_BANG);
X    (void) cmd_line(buf, msg_list);
X    if (!bang)
X	turnoff(glob_flags, IGN_BANG);
}
X
void
read_mail(item, value, event)
Panel_item item;
Event *event;
{
X    int this_msg = current_msg;
X
X    /* check "event" in case we were called from hdr_sw.c
X     * in which case event would be NULL
X     */
X    if (event && event_id(event) == MS_RIGHT && item &&
X	(item == read_item ||
X	(item == sub_hdr_item[0] || item == sub_hdr_item[1]))) {
X	(void) help(0, "next", tool_help);
X	return;
X    }
X    if (item && (item == sub_hdr_item[4] || item == sub_hdr_item[5])) {
X	(void) help(0, "Menu Read", tool_help);
X	return;
X    }
X    if (!msg_cnt) {
X	wprint ("No Mail.\n");
X	return;
X    }
X    if (item && item == read_item || ison(msg[current_msg].m_flags, DELETE))
X	(void) next_msg();
X    if (this_msg != current_msg || ison(msg[current_msg].m_flags, UNREAD) ||
X	    (current_msg < n_array[0] || current_msg > n_array[screen])) {
X	set_isread(current_msg);
X	(void) do_hdrs(0, DUBL_NULL, NULL);
X    }
X    if (isoff(msg[current_msg].m_flags, DELETE))
X	display_msg(current_msg, (u_long)0);
}
X
/* the panel button that says "filename" and "directory", etc... text item */
Panel_setting
file_dir(item, event)
Panel_item item;
Event *event;
{
X    register char *p;
X    u_long bang = ison(glob_flags, IGN_BANG);
X    char buf[MAXPATHLEN];
X
X    if (event_id(event) == ESC) {
X	/* file expansion request */
X	int n;
X	char **files;
X	p = panel_get_value(item);
X	(void) sprintf(buf, "%s*", p);
X	timeout_cursors(1);
X	if ((n = filexp(buf, &files)) > 0) {
X	    Debug("%d: ",n), print_argv(files);
X	    if (n > 1) {
X		n = lcprefix(files, 0);
X		files[0][n] = 0;
X	    }
X	    panel_set_value(item, trim_filename(files[0]));
X	    free_vec(files);
X	} else
X	    errbell(n);	/* see curs_io.c */
X	timeout_cursors(0);
X	return PANEL_NONE;
X    }
X
X    if (item == folder_text_item) {
X	(void) sprintf(buf, "folder %s %s",
X	    (ison(glob_flags, READ_ONLY) || ison(glob_flags, DO_UPDATE) &&
X		!ask("Folder has been modified.  Update changes?"))? "!" : "",
X		panel_get_value(folder_text_item));
X    }
X    else if (item == file_item) {
X	register char *b = buf;
X	char msgstr[BUFSIZ];
X
X	if (event_id(event) == '\n' || event_id(event) == '\r')
X	    b += Strcpy(buf, "save  ");
X	else
X	    b += Strcpy(buf, "write ");
X	if ((p = panel_get_value(msg_num_item)) && *p)
X	    b += Strcpy(b, p);
X	else {
X	    if (ison(msg[current_msg].m_flags, DELETE) &&
X		    !do_set(set_options, "show_deleted")) {
X		(void) sprintf(msgstr, "Message %d deleted -- save anyway?",
X					    current_msg+1);
X		if (ask(msgstr) != TRUE) {
X		    wprint("Message not saved\n");
X		    return PANEL_NONE;
X		}
X	    }
X	    b += strlen(sprintf(b, "%d", current_msg+1));
X	}
X	*b++ = ' ', *b = 0;
X	if (!(p = panel_get_value(item)) || !*p &&
X	    (!(p = do_set(set_options, "mbox")) || !*p))
X		p = DEF_MBOX;
X	if (chk_option("verify", "save")) {
X	    (void) sprintf(msgstr, "%s in \"%s\"?", buf, trim_filename(p));
X	    if (ask(msgstr) != TRUE) {
X		wprint("Message not saved\n");
X		return PANEL_NONE;
X	    }
X	}
X	(void) strcpy(b, p); /* now add to command */
X    }
X    turnon(glob_flags, IGN_BANG);
X    (void) cmd_line(buf, msg_list);
X    if (!bang)
X	turnoff(glob_flags, IGN_BANG);
X    return PANEL_NONE;
}
X
#ifndef NO_WALK_MENUS
void
xx_file_dir(item, value)
Panel_item item;
char * value;
{
X    char buf[BUFSIZ];
X    u_long bang = ison(glob_flags, IGN_BANG);
X
X    if (item == folder_item) {
X	(void) sprintf(buf, "folder %s ",
X	    (ison(glob_flags, READ_ONLY) || ison(glob_flags, DO_UPDATE) &&
X	    !ask("Folder has been modified.  Update changes?"))? "!" : "");
X	strcat(buf, value);
X    } else if (item == save_item) {
X	char msgstr[BUFSIZ], *p;
X	register char *p2 = (char *)panel_get_value(msg_num_item);
X	(void) strcpy(buf, "save ");
X
X	if (p2 && *p2) {
X	    (void) strcat(buf, p2);
X	    (void) strcat(buf, " ");
X	}
X	(void) strcat(buf, value);
X	if (chk_option("verify", "save")) {
X	    (void) sprintf(msgstr, "Save in %s? ", trim_filename(value));
X	    if (ask(msgstr) != TRUE) {
X		wprint("Message not saved\n");
X		return;
X	    }
X	}
X    }
X    turnon(glob_flags, IGN_BANG);
X    (void) cmd_line(buf, msg_list);
X    if (!bang)
X	turnoff(glob_flags, IGN_BANG);
X    (void) panel_set(item, PANEL_VALUE, 0, NULL); /* remove last value */
}
X
/*
X * callback routine for the panel items that need filename input.
X * (folder and save)
X */
void
do_file_dir(item, event)
Panel_item item;
Event *event;
{
X    if (item == folder_item) {
X	char *p = panel_get_value(folder_text_item);
X	if (!*p) {
X	    ok_box("Enter folder name.");
X	    return;
X	}
X	xx_file_dir(item, p);
X    } else if (item == save_item) {
X	if (!strcmp("Filename:", panel_get(file_item,PANEL_LABEL_STRING))) {
X	    event_id(event) = '\n';  /* let file_dir think it got a \n */
X	    file_dir(file_item, event);
X	    return;
X	}
X    }
X    (void) panel_set(item, PANEL_VALUE, 0, NULL); /* remove last value */
}
#else /* NO_WALK_MENUS */
X
/*
X * callback routine for the panel items that need filename input.
X * (folder and save)
X */
void
do_file_dir(item, value, event)
Panel_item item;
int value;
Event *event;
{
X    char buf[BUFSIZ];
X    u_long bang = ison(glob_flags, IGN_BANG);
X
X    if (item == folder_item) {
X	(void) sprintf(buf, "folder %s ",
X	    (ison(glob_flags, READ_ONLY) || ison(glob_flags, DO_UPDATE) &&
X	    !ask("Folder has been modified.  Update changes?"))? "!" : "");
X	if (event_id(event) == MS_LEFT) {
X	    char *p = panel_get_value(folder_text_item);
X	    if (!*p) {
X		ok_box("Enter folder name.");
X		return;
X	    }
X	    (void) strcat(buf, p);
X	} else if (!value)
X	    (void) strcat(buf, "%");
X	else if (value == 1)
X	    (void) strcat(buf, "&");
X	else if (value == 2)
X	    (void) strcat(buf, "#");
X	else
X	    (void) strcat(buf, panel_get(item, PANEL_CHOICE_STRING, value));
X    } else if (item == save_item) {
X	char msgstr[BUFSIZ], *p;
X	(void) strcpy(buf, "save ");
X	if (event_id(event) == MS_LEFT) {
X	    if (!strcmp("Filename:", panel_get(file_item,PANEL_LABEL_STRING))) {
X		event_id(event) = '\n';  /* let file_dir think it got a \n */
X		file_dir(file_item, event);
X		return;
X	    }
X	} else if (value == 0) {
X	    register char *p2 = (char *)panel_get_value(msg_num_item);
X
X	    if (!(p = do_set(set_options, "mbox")) || !*p)
X		p = DEF_MBOX;
X	    if (p2 && *p2) {
X		(void) strcat(buf, p2);
X		(void) strcat(buf, " ");
X	    }
X	    (void) strcat(buf, p);
X	} else
X	    (void) strcat(buf, p = panel_get(item, PANEL_CHOICE_STRING, value));
X	if (chk_option("verify", "save")) {
X	    (void) sprintf(msgstr, "Save in %s? ", trim_filename(p));
X	    if (ask(msgstr) != TRUE) {
X		wprint("Message not saved\n");
X		return;
X	    }
X	}
X    }
X    turnon(glob_flags, IGN_BANG);
X    (void) cmd_line(buf, msg_list);
X    if (!bang)
X	turnoff(glob_flags, IGN_BANG);
X    (void) panel_set(item, PANEL_VALUE, 0, NULL); /* remove last value */
}
#endif /* NO_WALK_MENUS */
X
/*ARGSUSED*/
void
do_help(item, value, event)
Panel_item item;
register int value;
Event *event;
{
X    register char *p, *helpfile = tool_help;
X    if (!event || event_id(event) == MS_LEFT)
X	value = 0;
X    switch(value) {
X	case 0: p = "about", helpfile = cmd_help;
X	when 1: p = "help";
X	when 2: p = "mouse";
X	when 3: p = "windows";
X	when 4: p = "hdr_format", helpfile = cmd_help;
X	when 5: p = "msg_list", helpfile = cmd_help;
X	when 6: p = "folder";
X	otherwise: p = "general";
X    }
X    (void) help(0, p, helpfile);
}
X
/*ARGSUSED*/
void
do_update(item, value, event)
Panel_item item;
int value;
Event *event;
{
X    char *argv[2];
X    if (event && event_id(event) != MS_LEFT) {
X	if (value == 0) {
X	    if (check_new_mail() == 0)
X		print("No new mail.\n");
X	} else
X	    (void) help(0, "update", tool_help);
X	return;
X    }
X    argv[0] = "update";
X    argv[1] = NULL;
X    timeout_cursors(TRUE);
X    (void) folder(0, argv, NULL);
X    timeout_cursors(FALSE);
}
X
/*ARGSUSED*/
void
toolquit(item, value, event)
Panel_item item;
int value;
Event *event;
{
X    void wmgr_changestate(), wmgr_changelevel();
X    register int which;
X
X    if (!value || event_id(event) == MS_LEFT) {
X	if (ison(glob_flags, DO_UPDATE)) {
X	    do_update(NO_ITEM, 0, NO_EVENT);
X	    turnoff(glob_flags, NEW_MAIL);
X	}
X	check_icons();
X	mail_status(0); /* lower flag (if up) print current num of msgs */
X	/* wmgr_changestate (window_get(tool, WIN_FD), rootfd, TRUE); */
X	/* wmgr_changelevel (window_get(tool, WIN_FD), parentfd, TRUE); */
X	close_frame();
X	window_set(tool, FRAME_CLOSED, TRUE, NULL);
X	is_iconic = ((int) window_get(tool, FRAME_CLOSED));
X	return;
X    } else if (value == 2) {
X	(void) help(0, "quit", tool_help);
X	return;
X    }
X    /* modify this to check for "abort" choice when ternary return values
X     * are possible!
X     */
X    if (isoff(glob_flags, DO_UPDATE) ||
X	    ask("Folder has been modified -- update?")) {
X	if (!copyback("Quit anyway?", TRUE))
X	    return;
X    }
X    cleanup(0);
}
X
/*ARGSUSED*/
void
do_mark(item, value, event)
Panel_item item;
int value;
Event *event;
{
X    if (event && (event_id(event) == MS_LEFT) || value == 0) {
X	int msg_num = event? current_msg : (int)item;
X	/* mark message */
X	if (ison(msg[msg_num].m_flags, M_PRIORITY(0)))
X	    turnoff(msg[msg_num].m_flags, M_PRIORITY(0));
X	else
X	    turnon(msg[msg_num].m_flags, M_PRIORITY(0));
X	(void) do_hdrs(0, DUBL_NULL, NULL);
X    } else if (value < 7) {
X	/* set priority */
X	char buf[90];
X	(void) cmd_line(sprintf(buf, "mark -%c %s",
X	    value < 6? value + 'A' - 1 : ' ',
X	    panel_get_value(msg_num_item)), NULL);
X    } else
X	(void) help(0, "mark", tool_help);
X    if (value != 7 && item)
X	panel_set_value(item, 0);
}
X
/*ARGSUSED*/
void
do_lpr(item, value, event)
Panel_item item;
int value;
Event *event;
{
X    char buf[128];
X
X    if (event && (event_id(event) == MS_LEFT)) {
X	wprint("Sending message %d to printer...\n", current_msg+1);
X	(void) strcpy(buf, "lpr ");
X	if (value)
X	    (void) sprintf(buf, "lpr \"%s\"", panel_get_value(msg_num_item));
X	timeout_cursors(TRUE);
X	(void) cmd_line(buf, msg_list);
X	timeout_cursors(FALSE);
X    } else
X	(void) help(0, "printer", tool_help);
}
X
/* panel selection button pressed to send a letter.
X * we've attached the sign panel item to this item to 1) avoid
X * using a global and 2) make it general enough so that multiple
X * compose windows can have multiple send_items and we can
X * identify which sign/fortune items are associated with this
X * particular letter.  The fortune item is attached to the sign
X * item.
X */
/*ARGSUSED*/
void
do_send(item, value, event)
Panel_item item;
int value;
register Event *event;
{
X    Panel panel = (Panel)panel_get(item, PANEL_PARENT_PANEL);
X    Panel_item sign_item = (Panel_item)panel_get(item, PANEL_CLIENT_DATA);
X    Panel_item fortune_item =
X	(Panel_item)panel_get(sign_item, PANEL_CLIENT_DATA);
X    Textsw textsw = (Textsw)panel_get(panel, PANEL_CLIENT_DATA);
X    char *argv[5], buf[64];
X    char *file = (char *)window_get(textsw, TEXTSW_CLIENT_DATA);
X    char *p, *oldsign = NULL, *oldfortune = NULL;
X
X    if (textsw_store_file(textsw, file, 0, 0)) {
X	error("Can't save to %s", file);
X	return;
X    }
X    /* check if user changed variables before sending */
X    if (p = do_set(set_options, "autosign"))
X	oldsign = savestr(p);
X    if (panel_get_value(sign_item) && !oldsign)
X	cmd_line(strcpy(buf, "\\set autosign"), NULL);
X    else if (!panel_get_value(sign_item) && oldsign)
X	cmd_line(strcpy(buf, "\\unset autosign"), NULL);
X    if (p = do_set(set_options, "fortune"))
X	oldfortune = savestr(p);
X    if (panel_get_value(fortune_item) && !oldfortune)
X	(void) cmd_line(strcpy(buf, "\\set fortune"), NULL);
X    else if (!panel_get_value(fortune_item) && oldfortune)
X	(void) cmd_line(strcpy(buf, "\\unset fortune"), NULL);
X    turnoff(glob_flags, IS_GETTING);
X    argv[0] = "mail";
X    argv[1] = "-Uh";
X    argv[2] = file;
X    argv[3] = NULL;
X    clear_msg_list(msg_list);
X    timeout_cursors(TRUE);
X    if (do_mail(3, argv, msg_list) == 0) {
X	(void) unlink(file);
X	set_comp_items(panel);
X    }
X    if (panel_get_value(sign_item) && !oldsign)
X	(void) cmd_line(strcpy(buf, "\\unset autosign"), NULL);
X    else if (!panel_get_value(sign_item) && oldsign) {
X	argv[0] = "set";
X	argv[1] = "autosign";
X	if (*oldsign) {
X	    argv[2] = "=";
X	    argv[3] = oldsign;
X	    argv[4] = NULL;
X	    (void) set(4, argv, NULL);
X	} else {
X	    argv[2] = NULL;
X	    (void) set(2, argv, NULL);
X	}
X    }
X    if (panel_get_value(fortune_item) && !oldfortune)
X	cmd_line(strcpy(buf, "\\unset fortune"), NULL);
X    else if (!panel_get_value(fortune_item) && oldfortune) {
X	argv[0] = "set";
X	argv[1] = "fortune";
X	if (*oldfortune) {
X	    argv[2] = "=";
X	    argv[3] = oldfortune;
X	    argv[4] = NULL;
X	    (void) set(4, argv, NULL);
X	} else {
X	    argv[2] = NULL;
X	    (void) set(2, argv, NULL);
X	}
X    }
X    xfree(oldsign), xfree(oldfortune);
X    timeout_cursors(FALSE);
}
X
/*ARGSUSED*/
void
do_include(item, value, event)
Panel_item item;
int value;
Event *event;
{
X    extern FILE *ed_fp;
X    char *p, buf[64], *file;
X    Textsw textsw = (Textsw)panel_get(panel_get(item, PANEL_PARENT_PANEL),
X	PANEL_CLIENT_DATA);
X
X    if (event && event_id(event) == MS_LEFT)
X	value = 0;
X    if (value == 2) {
X	(void) help(0, "include", tool_help);
X	return;
X    }
X    p = panel_get_value(msg_num_item);
X    (void) sprintf(buf, "%c%c%s", *escape, value == 0? 'i' : 'f', p? p : "");
X
X    file = (char *)window_get(textsw, TEXTSW_CLIENT_DATA);
X    if (textsw_store_file(textsw, file, 0, 0)) {
X	(void) ask("Something's wrong... Click anything.");
X	return;
X    }
X    if (ed_fp) {
X	(void) ask("tmpfile already in use... Click anything.");
X	(void) fclose(ed_fp);
X    }
X    if (!(ed_fp = mask_fopen(file, "a"))) {
X	error("Cannot open %s to append msg.", file);
X	return;
X    }
X    (void) add_to_letter(buf);
X    (void) fclose(ed_fp), ed_fp = NULL_FILE;
#ifdef SUN_4_0 /* SunOS 4.0+ */
X    window_set(textsw, TEXTSW_FILE_CONTENTS, file, NULL);
#else /* SUN_4_0 */
X    textsw_load_file(textsw, file, 1, 0, 0);
#endif /* SUN_4_0 */
X    window_set(textsw, TEXTSW_UPDATE_SCROLLBAR, NULL);
X    (void) unlink(file);
}
X
/*ARGSUSED*/
void
do_compose(item, value, event)
Panel_item item;
int value;
Event *event;
{
X    char buf[5];
X
X    if (event && event_id(event) != MS_LEFT) {
X	(void) help(0, "compose", tool_help);
X	return;
X    }
X    open_compose();
X    if (!compose_frame)
X	return;	/* open failed */
X    clear_msg_list(msg_list);
X    if (do_mail(0, DUBL_NULL, msg_list) == 0) {
X	Panel panel = get_compose_panel();
X	Textsw textsw = (Textsw)panel_get(panel, PANEL_CLIENT_DATA);
X	start_textsw_edit(textsw, TRUE);
X	set_comp_items(panel);
X    }
}
X
/*
X * notify proc for reply button -- also called from select.c (do_menu()) ,
X * in which case "event" is null and "value" contains the message
X * number of the message to reply to.
X */
/*ARGSUSED*/
void
respond_mail(item, value, event)
Panel_item item;
int value;
Event *event;
{
X    int tmp = current_msg;
X    char buf[256];
X
X    if (event && event_id(event) == MS_LEFT)
X	value = 0;
X    if (event && value == 4) {
X	(void) help(0, "respond", tool_help);
X	return;
X    }
X    if (!msg_cnt) {
X	wprint("No messages to respond to.\n");
X	return;
X    }
X    if (ison(glob_flags, IS_GETTING)) {
X	wprint("Finish editing current message first.\n");
X	return;
X    }
X    if (!event)
X	tmp = value, value = 0;
X    open_compose();
X    if (!compose_frame)
X	return;	/* open failed */
X    (void) sprintf(buf, "%s %s %d",
X	(value == 2 || value == 3)? "\\replyall" : "\\replysender",
X	(value == 1 || value == 3)? "-i": NO_STRING, tmp+1);
X    if (cmd_line(buf, NULL) != -1) {
X	Panel panel = get_compose_panel();
X	Textsw textsw = (Textsw)panel_get(panel, PANEL_CLIENT_DATA);
X	wprint("Responding to message %d\n", tmp+1);
X	start_textsw_edit(textsw, FALSE);
X	set_comp_items(panel);
X    }
}
X
/*ARGSUSED*/
void
load_from_file(item, value, event)
Panel_item item;
int value;
Event *event;
{
X    int x = 0;
X    Textsw textsw;
X    Panel_item filename_item = (Panel_item)panel_get(item, PANEL_CLIENT_DATA);
X    char *file, *p = panel_get_value(filename_item);
#ifndef SUN_4_0 /* SunOS 4.0+ */
X    char *sfile, buf[128];
X    extern FILE *ed_fp;
#endif /* SUN_4_0 */
X    
X    if (!*p) {
X	wprint("Specify Filename.\n");
X	return;
X    }
X    file = getpath(p, &x);
X    if (x == 1)
X	wprint("%s: is a directory.\n", p);
X    else if (x == -1)
X	wprint("%s: %s\n", p, file);
X    if (x)
X	return;
X    timeout_cursors(TRUE);
X    textsw = (Textsw)panel_get(panel_get(item, PANEL_PARENT_PANEL),
X	PANEL_CLIENT_DATA);
X    if (event_id(event) != MS_LEFT && value == 1)
X	/* replace */
X	textsw_load_file(textsw, file, 1, 0, 0);
X    else {
X	/* insert */
#ifdef SUN_4_0 /* SunOS 4.0+ */
X	window_set(textsw, TEXTSW_INSERT_FROM_FILE, file, NULL);
#else /* SUN_4_0 */
X	/* best we can do with pre 4.0 is save the current file
X	 * and append the new file onto the end.
X	 */
X	sfile = (char *)window_get(textsw, TEXTSW_CLIENT_DATA);
X	if (textsw_store_file(textsw, sfile, 0, 0)) {
X	    (void) ask("Can't save file... Click anything.");
X	    return;
X	}
X	if (ed_fp) {
X	    (void) ask("tmpfile already in use... Click anything.");
X	    fclose(ed_fp);
X	}
X	if (!(ed_fp = mask_fopen(sfile, "a"))) {
X	    error("Cannot open %s.", sfile);
X	    return;
X	}
X	(void) sprintf(buf, "%c%c%s", *escape, 'r', trim_filename(p));
X	(void) add_to_letter(buf);
X	(void) fclose(ed_fp), ed_fp = NULL_FILE;
X	textsw_load_file(textsw, sfile, 1, 0, 0);
X	(void) unlink(sfile);
#endif /* SUN_4_0 */
X    }
X    window_set(textsw, TEXTSW_UPDATE_SCROLLBAR, NULL);
X    panel_set_value(item, 0);
X    timeout_cursors(FALSE);
}
X
/*ARGSUSED*/
void
save_to_file(item, value, event)
Panel_item item;
Event *event;
{
X    Panel_item filename_item = panel_get(item, PANEL_CLIENT_DATA);
X    char *file = panel_get_value(filename_item);
X    FILE *fp;
X    Textsw textsw = (Textsw)panel_get(panel_get(item, PANEL_PARENT_PANEL),
X	PANEL_CLIENT_DATA);
X
X    if (!*file) {
X	wprint("Specify Filename\n");
X	return;
X    }
X    timeout_cursors(TRUE);
X    /* append to file -- no confirmation necessary */
X    if (fp = open_file(file, FALSE, TRUE)) {
X	char buf[BUFSIZ];
X	Textsw_index next_pos = 0, tmp;
X	Textsw_index length =
X	    (Textsw_index)window_get(textsw, TEXTSW_LENGTH);
X	do  {
X	    tmp = next_pos;
X	    next_pos = (Textsw_index) window_get(textsw, TEXTSW_CONTENTS,
X		next_pos, buf, sizeof(buf));
X	    if (fwrite(buf, sizeof(char), (int)(next_pos - tmp), fp) == 0)
X		error("%s may be incomplete", file);
X	} while (next_pos < length);
X	(void) close_lock(file, fp);
X	wprint("Wrote %d bytes to %s\n", length, trim_filename(file));
X    }
X    timeout_cursors(FALSE);
}
X
void
abort_mail(item, event)
Panel_item item;
Event *event;
{
X    Panel panel = (Panel)panel_get(item, PANEL_PARENT_PANEL);
X    Textsw textsw = (Textsw)panel_get(panel, PANEL_CLIENT_DATA);
X    wprint("Aborted letter.\n");
X    textsw_reset(textsw, 0, 0);
X    rm_edfile(0);
X    set_comp_items(panel);
}
X
/* set the compose panel items */
void
set_comp_items(panel)
Panel panel;
{
X    Panel_item item, next;
X    Textsw textsw = (Textsw)panel_get(panel, PANEL_CLIENT_DATA);
X    int getting = ison(glob_flags, IS_GETTING) != 0;
X    int i = 0;
X
X    window_set(textsw, TEXTSW_READ_ONLY, !getting, NULL);
X    /* remove next line when multiple composes become a reality */
X    (void) panel_set(reply_item, PANEL_SHOW_ITEM, !getting, NULL);
X    /* skip "close" 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,
X	    PANEL_SHOW_ITEM, (i++ < 1)? !getting : getting, NULL);
X    }
}
X
/*
X * Ask a yes/no question and return an answer: TRUE or FALSE.
X */
ask(question)
char *question;
{
#ifdef SUN_4_0 /* SunOS 4.0+ */
X    return alert_prompt(tool, (Event *)NULL,
X	ALERT_MESSAGE_STRINGS,	question, NULL,
X	ALERT_BUTTON_YES,	"Yes",
X	ALERT_BUTTON_NO,	"No",
X	NULL) == ALERT_YES;
#else /* SUN_4_0 */
X    Event event;
X    struct prompt prompt;
X    Rect *rect = (Rect *)window_get(tool, WIN_RECT);
X    char buf[MAXPATHLEN];
X
X    (void) sprintf(buf,
X	    "%s  \nPress LEFT Button to Confirm.  Anything else to cancel.",
X	    question);
X    prompt.prt_rect.r_left = rect->r_left + (rect->r_width / 3);
X    prompt.prt_rect.r_top = rect->r_top + (rect->r_height / 3);
X    prompt.prt_rect.r_width = prompt.prt_rect.r_height = PROMPT_FLEXIBLE;
X    prompt.prt_font = mush_font;
X    prompt.prt_text = buf;
X
X    menu_prompt(&prompt, &event, window_get(tool, WIN_FD));
X    return event_id(&event) == MS_LEFT;
#endif /* SUN_4_0 */
}
X
void
ok_box(buf)
char *buf;
{
#ifdef SUN_4_0
X    (void) alert_prompt(tool, (Event *)NULL,
X	ALERT_MESSAGE_STRINGS,	buf, NULL,
X	ALERT_BUTTON_YES,		"Ok",
X	NULL);
#else /* SUN_4_0 */
X    Event event;
X    struct prompt prompt;
X    Rect *rect = (Rect *)window_get(tool, WIN_RECT);
X    (void) strcat(buf, "  \nPress LEFT Button to Continue.");
X    prompt.prt_rect.r_left = rect->r_left + (rect->r_width / 3);
X    prompt.prt_rect.r_top = rect->r_top + (rect->r_height / 3);
X    prompt.prt_rect.r_width = prompt.prt_rect.r_height = PROMPT_FLEXIBLE;
X    prompt.prt_font = mush_font;
X    prompt.prt_text = buf;
X    menu_prompt(&prompt, &event, window_get(tool, WIN_FD));
#endif /* SUN_4_0 */
}
X
Panel_setting
msg_num_done(item, event)
Panel_item item;
Event *event;
{
X    char buf[82];
X    u_long bang = ison(glob_flags, IGN_BANG);
X    register char *p;
X    int n;
X
X    if (event_id(event) != '\n' && event_id(event) != '\r') {
X	(void) help(0, "message range", tool_help);
X	return PANEL_NONE;
X    }
X    (void) sprintf(buf, "headers %s", (p = (char *)panel_get_value(item)));
X    (void) panel_set(item, PANEL_VALUE, NO_STRING, NULL);
X    if (!(n = chk_msg(p)))
X	return PANEL_NONE;
X    current_msg = --n;
X    turnon(glob_flags, IGN_BANG);
X    (void) cmd_line(buf, msg_list);
X    if (!bang)
X	turnoff(glob_flags, IGN_BANG);
X    (void) display_msg(n, (u_long)0);
X    return PANEL_NONE;
}
X
void
do_sort(item, value, event)
Panel_item item;
int value;
Event *event;
{
X    char *argv[3], list[MAXMSGS_BITS];
X    char *p = (char *)panel_get_value(msg_num_item);
X    int n = 0;
X
X    if (p && *p) {
X	argv[0] = p;
X	argv[1] = NULL;
X	n = get_msg_list(argv, list);
X    }
X    argv[0] = "sort";
X    argv[2] = NULL;
X
X    if (event_id(event) == MS_LEFT)
X	value = 0;
X    switch(value) {
X	case 0: argv[1] = "S";
X	when 1: argv[1] = "a";
X	when 2: argv[1] = "l";
X	when 3: argv[1] = "R";
X	when 4: argv[1] = "s";
X	when 5: argv[1] = "d";
X	when 6: argv[1] = "p";
X	when 7: do_set(set_options, "sort");
X	when 8: (void) help(0, "sort", tool_help);
X    }
X    if (value != 8) {
X	if (n > 0) {
X	    turnon(glob_flags, IS_PIPE);
X	    (void) sort(2, argv, list);
X	    turnoff(glob_flags, IS_PIPE);
X	} else
X	    (void) sort(2, argv, NULL);
X	(void) do_hdrs(0, DUBL_NULL, NULL);
X    }
X    (void) panel_set(item, PANEL_VALUE, 0, NULL);
}
X
void
do_options(item, value, event)
Panel_item item;
int value;
Event *event;
{
X    if (event_id(event) == MS_LEFT) {
X	view_options();
X	return;
X    }
X    switch (value) {
X	case 0:
X	    view_options();
X	when 1:
X	    do_ignore();
X	when 2:
X	    do_aliases();
X    }
}
SHAR_EOF
chmod 0644 doproc.c ||
echo 'restore of doproc.c failed'
Wc_c="`wc -c < 'doproc.c'`"
test 24153 -eq "$Wc_c" ||
	echo 'doproc.c: original size 24153, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= execute.c ==============
if test -f 'execute.c' -a X"$1" != X"-c"; then
	echo 'x - skipping execute.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting execute.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'execute.c' &&
/* execute.c 	(c) copyright	10/28/86 (Dan Heller) */
X
#include "mush.h"
#ifdef BSD
#include <sys/wait.h>
#else
#ifndef SYSV
#include <wait.h>
#endif /* SYSV */
#endif /* BSD */
X
#ifdef lint
#include <sys/resource.h>
#endif /* lint */
X
static jmp_buf execjbuf;
X
#ifdef SUNTOOL
X
/*ARGSUSED*/
Notify_value
my_wait3(tty, pid, status, rusage)
Tty tty;
int pid;
union wait *status;
struct rusage *rusage;
{
X    extern Panel_item edit_item;
X    Textsw textsw = (Textsw)window_get(tty, WIN_CLIENT_DATA);
X    char *file = (char *)window_get(textsw, TEXTSW_CLIENT_DATA);
X    int i = 0;
X
X    if (WIFSTOPPED(*status)) {
X	kill(pid, SIGCONT);
X	return (NOTIFY_IGNORED);
X    }
X    if (pid != exec_pid || exec_pid <= 0) /* if the editor didn't die, return */
X	return NOTIFY_DONE;
X    /* editor died -- reset exec_pid so no one thinks we're running */
X    exec_pid = 0;
X    (void) window_set(tty, TTY_ARGV, TTY_ARGV_DO_NOT_FORK, NULL);
X    wprint("Editor done.\n");
X    (void) window_set(tty_sw, WIN_SHOW, FALSE, NULL);
#ifdef SUN_4_0 /* SunOS 4.0+ */
X    (void) window_set(textsw,
X	WIN_SHOW,		TRUE,
X	TEXTSW_FILE_CONTENTS,	file,
X	NULL);
#else /* SUN_4_0 */
X    textsw_load_file(textsw, file, 1, 0, 0);
X    textsw_set(textsw, WIN_SHOW, TRUE, NULL);
#endif /* SUN_4_0 */
X    textsw_normalize_view(textsw, (Textsw_index)0);
X    (void) unlink(file);
X    set_comp_items(panel_get(edit_item, PANEL_PARENT_PANEL));
X
X    return NOTIFY_DONE;
}
X
tool_edit_letter(textsw, argv)
Textsw textsw;
char **argv;
{
X    Rect *msg_rect = (Rect *)window_get(textsw, WIN_RECT);
X
X    wprint("Starting \"%s\"...\n", *argv);
#ifdef SUN_4_0
X    window_set(textsw, WIN_SHOW, FALSE, NULL);
#else /* SUN_4_0 */
X    textsw_set(textsw, WIN_SHOW, FALSE, NULL);
#endif /* SUN_4_0 */
X    ttysw_output(tty_sw, "\f", 1);  /* clear screen */
X    (void) window_set(tty_sw,
X	WIN_RECT,	msg_rect,
X	TTY_ARGV,	argv,
X	WIN_SHOW,	TRUE,
X	NULL);
X    if ((exec_pid = (int) window_get(tty_sw, TTY_PID)) == -1) {
X	error("Couldn't execute %s", *argv);
X	return -1;
X    }
X    notify_set_wait3_func(tty_sw, my_wait3, exec_pid);
X    Debug("tty pid = %d\n", exec_pid);
X    return 0;
}
#endif /* SUNTOOL */
X
execute(argv)
char **argv;
{
#ifdef SYSV
X    int status;
#else
X    union wait status;
#endif /* SYSV */
#ifdef SIGCONT
X    SIGRET (*oldstop)(), (*oldcont)();
#endif /* SIGCONT */
X    int pid;
X    SIGRET (*oldint)(), (*oldquit)();
X
X    oldint = signal(SIGINT, SIG_IGN);
X    oldquit = signal(SIGQUIT, SIG_IGN);
#ifdef SIGCONT
X    oldstop = signal(SIGTSTP, SIG_DFL);
X    oldcont = signal(SIGCONT, SIG_DFL);
#endif /* SIGCONT */
X    turnon(glob_flags, IGN_SIGS);
X
X    echo_on();
X    if (!setjmp(execjbuf)) {
X	if ((exec_pid = vfork()) == 0) {
X	    (void) signal(SIGINT, SIG_DFL);
X	    (void) signal(SIGQUIT, SIG_DFL);
X	    (void) signal(SIGPIPE, SIG_DFL);
X	    (void) closefileds(3);	/* close all descriptors above 2 */
X	    execvp(*argv, argv);
X	    if (errno == ENOENT)
X		print("%s: command not found.\n", *argv);
X	    else
X		error(*argv);
X	    _exit(-1);
X	}
X	/* Parent's got to do something; sigchldcatcher may also be waiting.
X	 * This loop will usually get broken by the longjmp() (except tool),
X	 * but in certain circumstances sigchldcatcher isn't yet active.
X	 */
X	while ((pid = wait(&status)) != -1 && pid != exec_pid)
X	    Debug("The exec loop caught a signal? (pid = %d)\n", pid);
X    }
X    /* reset our ttymodes */
X    echo_off();
X    (void) signal(SIGINT, oldint);
X    (void) signal(SIGQUIT, oldquit);
#ifdef SIGCONT
X    (void) signal(SIGTSTP, oldstop);
X    (void) signal(SIGCONT, oldcont);
#endif /* SIGCONT */
X    turnoff(glob_flags, IGN_SIGS);
}
X
SIGRET
sigchldcatcher()
{
#ifdef SYSV
X    int status;
#else
X    union wait status;
#endif /* SYSV */
X    int	   pid;
X
#ifdef BSD
X    while ((pid = wait3(&status, WNOHANG, (struct rusage *)0)) > 0) {
X	Debug("%d died...\n", pid);
X	if (pid == exec_pid)
X	    break;
X    }
#else
#ifndef SYSV
X    while ((pid = wait2(&status, WNOHANG)) > 0 && pid != exec_pid)
X	Debug("%d died...\n", pid);
#else /* SYSV */
X    while ((pid = wait((int *)0)) > 0 && pid != exec_pid)
X	Debug("%d died...\n", pid);
#endif /* SYSV */
#endif /* BSD */
X    if (pid == exec_pid && pid > 0) {
X	exec_pid = 0;
X	longjmp(execjbuf, 1);
X    }
}
SHAR_EOF
chmod 0644 execute.c ||
echo 'restore of execute.c failed'
Wc_c="`wc -c < 'execute.c'`"
test 4196 -eq "$Wc_c" ||
	echo 'execute.c: original size 4196, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= expr.c ==============
if test -f 'expr.c' -a X"$1" != X"-c"; then
	echo 'x - skipping expr.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting expr.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'expr.c' &&
/* @(#)expr.c	2.3	(c) copyright 10/15/86 (Dan Heller) */
X
#include "mush.h"
X
char *eval_expr();
X
/* Parse a string (p) to interpret numbers and ranges of numbers (n-m)
X * delimited by whitespace or comma's. Set msg_list bitfields using
X * macros in mush.h.
X * Return the address of the end of whatever we parsed (in case there's
X * more that the calling routine cares to deal with).
X * Finally, remember that user specifies one more than actual message number
X */
char *
do_range(p, list1)
register char *p, *list1;
{
X    register int num1 = -1, num2 = -1, except = 0;
X    register char *p2;
X    char list2[MAXMSGS_BITS];
X
X    if (!p)
X	return "";
X    while (*p) {
X	if (isdigit(*p) || *p == '$' || *p == '.' || *p == '^') {
X	    if (isdigit(*p)) {
X		char c;
X		p2 = p;
X		skipdigits(0);  /* find the end of the digits */
X		c = *p, *p = 0; /* temporarily plug a null */
X		if (!(num2 = chk_msg(p2))) {
X		    clear_msg_list(list1);
X		    return NULL;
X		}
X		*p = c;
X	    } else if (*p == '$')
X		p++, num2 = msg_cnt;
X	    else if (*p == '.')
X		p++, num2 = current_msg+1;
X	    else if (*p == '^')
X		p++, num2 = 1;
X	    if (except)
X		unset_msg_bit(list1, num2-1);
X	    else
X		set_msg_bit(list1, num2-1);
X	    if (num1 >= 0) {
X		if (num1 > num2) {
X		    print("syntax error: range sequence order reversed.\n");
X		    clear_msg_list(list1);
X		    return NULL;
X		}
X		while (++num1 < num2)
X		    if (except)
X			unset_msg_bit(list1, num1-1);
X		    else
X			set_msg_bit(list1, num1-1);
X		num1 = num2 = -1;
X	    }
X	}
X	/* expressions to evaluate start with a `
X	 * p2 points to first char passed the last char parsed.
X	 */
X	if (*p == '`') {
X	    clear_msg_list(list2);
X	    if (!(p = eval_expr(p, list2))) {
X		clear_msg_list(list1);
X		return NULL;
X	    } else {
X		if (except)
X		    bitput(list2, list1, msg_cnt, &=~); /* MACRO */
X		else
X		    bitput(list2, list1, msg_cnt, |=); /* MACRO */
X	    }
X	}
X	/* NOT operator: `* {5}' (everything except for 5)
X	 * `4-16 {8-10}'  (4 thru 16 except for 8,9,10)
X	 */
X	if (*p == '{' || *p == '}') {
X	    if (*p == '{' && (except || num1 >= 0))
X		break;
X	    if (*p == '}' && !except) {
X		print("syntax error: missing {\n"); /* } */
X		break;
X	    }
X	    except = !except;
X	} else if (*p == '-')
X	    if (num1 >= 0 || num2 < 0
X		    || !index(" \t{},.*`$", *(p+1)) && !isdigit(*(p+1)))
X		break;
X	    else
X		num1 = num2;
X	else if (*p == ',' || *p == '*') {
X	    if (num1 >= 0)
X		break;
X	    else if (*p == '*') {
X		if (except)
X		    clear_msg_list(list1);
X		else
X		    for (num1 = 0; num1 < msg_cnt; num1++)
X			set_msg_bit(list1, num1);
X		num1 = -1;
X	    }
X	} else if (!index(" \t`", *p))
X	    break;
X	if (*p)
X	    skipspaces(1); /* don't make user type stuff squished together */
X    }
X    if (num1 >= 0 || except) {
X	if (except)
X	    /* { */ print("syntax error: unmatched }\n");
X	else
X	    print("syntax error: unfinished range\n");
X	clear_msg_list(list1);
X	return NULL;
X    }
X    return p;
}
X
/*
X * convert a message list to an ascii string.
X */
void
list_to_str(list, str)
char list[], *str;
{
X    int n, m = -1;
X
X    for (n = 0; n < msg_cnt; n++) {
X	if (msg_bit(list, n)) {
X	    if (m == -1)
X		str += strlen(sprintf(str, "%d", (m = n) + 1 ));
X	    continue;
X	}
X	if (m == -1)
X	    continue;
X	if (n - m > 2)
X	    str += strlen(sprintf(str, "-%d", n));
X	else if (n - m == 2)
X	    str += strlen(sprintf(str, " %d", n));
X	*str++ = ' ';
X	m = -1;
X    }
X    if (m > -1 && m != n - 1) {
X	if (n - m > 2)
X	    *str++ = '-';
X	else
X	    *str++ = ' ';
X	str += Strcpy(str, itoa(msg_cnt));
X    }
X    *str = 0;
}
X
/* evaluate expressions:
X * mail> delete `pick -f root`     deletes all messages from root.
X * mail> save * {`pick -s "Re:"`}  save all message that don't have "Re:"
X *				   in the subject header.
X * mail> save `pick -x -s "Re:"`   same
X * args as follows:
X *   p should point to the first ` -- check for it.
X *   on tells whether to turn bits on or off if messages match.
SHAR_EOF
true || echo 'restore of expr.c failed'
fi
echo 'End of  part 7'
echo 'File expr.c is continued in part 8'
echo 8 > _shar_seq_.tmp
exit 0
exit 0 # Just in case...
-- 
Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
Sterling Software, IMD           UUCP:     uunet!sparky!kent
Phone:    (402) 291-8300         FAX:      (402) 291-4362
Please send comp.sources.misc-related mail to kent@uunet.uu.net.