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

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

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

#!/bin/sh
# do not concatenate these parts, unpack them in order with /bin/sh
# file options.c continued
#
if test ! -r _shar_seq_.tmp; then
	echo 'Please unpack part 1 first!'
	exit 1
fi
(read Scheck
 if test "$Scheck" != 19; 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 options.c'
else
echo 'x - continuing file options.c'
sed 's/^X//' << 'SHAR_EOF' >> 'options.c' &&
{
X    int i;
X
X    Debug("%s --> ", *argp);
X    for (i = 0; word_flags[i][0]; i++) {
X	int len = strlen(word_flags[i][0]);
X	if (! strncmp(*argp, word_flags[i][0], len)) {
X	    char buf[BUFSIZ], *p = buf;
X	    p += Strcpy(buf, word_flags[i][1]);
X	    (void) strcpy(p, *argp + len);
X	    (void) strcpy(*argp, buf);
X	}
X    }
X    Debug("%s\n", *argp);
}
X
/*
X * preparse the command line to determine whether or not we're going
X * to bail out after checking that the user has no mail.  Also, check
X * to see if we're going to run a tool because it must be built first.
X */
preparse_opts(argcp, argv)
register int *argcp;	/* Pointer to argument count */
register char **argv;	/* Argument vector */
{
X    int n = FALSE;
X    char **args;
X
#ifdef SUNTOOL
X    /* Note: we are assigning a boolean result to n and istool here */
X    if (n = istool = (strlen(prog_name) > 3 &&
X		 (!strcmp(prog_name+strlen(prog_name)-4, "tool") ||
X		  !strcmp(prog_name+strlen(prog_name)-4, "view")))) {
X	turnon(glob_flags, DO_SHELL);
X	parse_tool_opts(argcp, argv);
X    }
#endif /* SUNTOOL */
X
X    if (!istool && *argcp > 1) {
X	for (args = argv+1; *args && args[0][0] == '-'; args++) {
X	    int next = 1;
X	    fix_word_flag(&args[0]);
DoNext:
X	    switch (args[0][next]) {
#ifdef SUNTOOL
X		case 'T' :
X		    if (args[1])
X			args++;
X		case 't' :
X		    /* Note: we won't ever get here if started as
X		     * "mushtool" or "mushview" because istool is true.
X		     */
X		    istool = 1;
X		    parse_tool_opts(argcp, argv);
X		    turnon(glob_flags, DO_SHELL);
X		    return TRUE;
X		    /* break; */
#endif /* SUNTOOL */
X		case 'S' :
X		    turnon(glob_flags, DO_SHELL);
X		    n = TRUE;
X		    break;
X		case 'f' :
X		case 'F' :
X		case 'h' :
X		case 'm' :
X		case 'u' :
X		    n = TRUE;
X		case 'b' :
X		case 'c' :
X		case 'I' :
X		case 's' :
X		    if (args[1]) {
X			args++;
X			next = 0;
X		    }
X		    break;
X		case 'H' :
X		    if (args[0][next+1] == ':')
X			next = 0;
X		    break;
X		case '\0':
X		    next = 0;
X		default : ;
X	    }
X	    if (next) {
X		++next;
X		goto DoNext;
X	    }
X	}
X	if (*args) {  /* unused args indicates sending mail to someone */
X	    n = TRUE;
X	    if (!istool)
X		turnon(glob_flags, IS_SENDING);
X	}
X    }
X
X    return n;
}
X
static char *usage_str =
#ifdef SUNTOOL
X    "usage: %s [-t] [-C] [-i] [-f [folder] ] [-v] [-S] [-s subject] [users]\n";
#else
#ifdef CURSES
X    "usage: %s [-C] [-i] [-f [folder] ] [-v] [-S] [-s subject] [user list]\n";
#else
X    "usage: %s [-i] [-f [folder] ] [-v] [-S] [-s subject] [user list]\n";
#endif /* CURSES */
#endif /* SUNTOOL */
X
parse_options(argvp, flags)
register char ***argvp;
struct mush_flags *flags;
{
X    char buf[256];
X
X    bzero((char *) flags, sizeof (struct mush_flags));
X    flags->source_rc = TRUE;
X    flags->folder = "";
X
X    for (++(*argvp); **argvp && ***argvp == '-'; (*argvp)++) {
X	int look_again;
DoLookAgain:
X	look_again = TRUE;
X	switch ((*argvp)[0][1]) {
X	    case 'e':
X		/*
X		 * don't set tty modes -- e.g. echo and cbreak modes aren't
X		 * changed.
X		 */
X		turnon(glob_flags, ECHO_FLAG);
#ifdef CURSES
X	    when 'C':
X		/* don't init curses -- don't even set iscurses.   */
X		if (istool) {
X		    puts("-C: You are already running in tool mode");
X		    turnoff(glob_flags, PRE_CURSES);
X		} else if (hdrs_only)
X		    puts("headers only: ignoring -C flag");
X		else
X		    turnon(glob_flags, PRE_CURSES);
#endif /* CURSES */
X	    when 'F':
X		flags->src_n_exit = ((*argvp)[0][2] == '!');
X		if (!(flags->src_file = *++(*argvp)))
X		    puts("specify filename to source"), exit(1);
X		look_again = FALSE;
X		/* fall thru! */
X	    case 'N':
X		(void) strcat(flags->f_flags, "-N ");
X	    when 'r':
X		(void) strcat(flags->f_flags, "-r "); /* folder() argument */
X	    when 'H':
X		if (istool) {
X		    puts("running in tool-mode; -H option ignored.");
X		    break;
X		}
X		turnoff(glob_flags, PRE_CURSES);
X		if (*(hdrs_only = (*(*argvp))+2) != ':')
X		    hdrs_only = ":a";
X		else
X		    look_again = FALSE;
X		/* read only cuz no updates */
X		(void) strcat(flags->f_flags, "-N -r ");
X	    when 'i':
X		/* force interactive even if !isatty(0) */
X		turnoff(glob_flags, REDIRECT);
X	    when 'u': /* specify a user's mailbox */
X		if (*(flags->folder))
X		    puts("You can't specify more than one mailbox"), exit(1);
#ifdef HOMEMAIL
X		{
X		    char *p;
X		    int isdir = 1;
X		    (void) sprintf(buf, "%%%s",
X				(*argvp)[1] ? (*argvp)[1] : "root");
X		    if ((p = getpath(buf, &isdir)) && !isdir)
X			strdup(flags->folder, p);
X		    else if (isdir < 0)
X			puts(p), exit(1);
X		    else if (isdir)
X			(void) printf("\"%s\" is a directory\n", p), exit(1);
X		}
#else /* HOMEMAIL */
X		strdup(flags->folder, sprintf(buf, "%s/%s",
X			       MAILDIR, ((*argvp)[1])? (*argvp)[1] : "root"));
#endif /* HOMEMAIL */
X		if ((*argvp)[1])
X		    ++(*argvp);
X		look_again = FALSE;
X	    when 'h':
X		if (istool)
X		    puts("bad option when run as a tool"), exit(1);
X		if ((*argvp)[1])
X		    flags->draft = *++(*argvp);
X		else
X		    (void) printf("-h: missing file name.\n"), exit(1);
X		look_again = FALSE;
X		turnon(glob_flags, IS_SENDING);
X	    when 'U':
X		if (istool)
X		    puts("bad option when run as a tool"), exit(1);
X		turnon(flags->flg, SEND_NOW);
X		if ((*argvp)[0][2] == '!') {
X		    turnon(flags->flg, NO_SIGN);
X		    ++(**argvp);
X		}
X	    when 'm':
X		if ((*argvp)[1])
X		    strdup(spoolfile, *++(*argvp));
X		else
X		    (void) printf("-m: missing mailbox name.\n"), exit(1);
X		look_again = FALSE;
X	    when 'f':
X		if (*(flags->folder))
X		    puts("You can't specify more than one mailbox"), exit(1);
X		if ((*argvp)[1]) {
X		    strdup(flags->folder, *++(*argvp));
X		    look_again = FALSE;
X		} else
X		    strdup(flags->folder, "&");
X	    when 's':
X		if (istool)
X		    puts("bad option when run as a tool"), exit(1);
X		else if ((*argvp)[1])
X		    flags->Subj = *++(*argvp);
X		else
X		    puts("-s \"subject\""), exit(1);
X		look_again = FALSE;
X	    when 'b':
X		if (istool)
X		    puts("-b: bad option when run as a tool"), exit(1);
X		else if ((*argvp)[1])
X		    flags->Bcc = *++(*argvp);
X		else
X		    puts("-b \"bcc list\""), exit(1);
X		look_again = FALSE;
X	    when 'c':
X		if (istool)
X		    puts("-c: bad option when run as a tool"), exit(1);
X		else if ((*argvp)[1])
X		    flags->Cc = *++(*argvp);
X		else
X		    puts("-c \"cc list\""), exit(1);
X		look_again = FALSE;
X		break;
#ifdef VERBOSE_ARG
X	    case 'v':
X		if (istool)
X		    puts("bad option when run as a tool"), exit(1);
X		turnon(flags->flg, VERBOSE);
X		break;
#endif /* VERBOSE_ARG */
#ifdef SUNTOOL
X	    case 'T':
X		if ((time_out = atoi(*(*argvp))) <= 29)
X		    time_out = 30;
X		look_again = FALSE;
X		/* -T implies -t */
X	    case 't': istool = 1;
#endif /* SUNTOOL */
X	    case 'S': turnon(glob_flags, DO_SHELL);
X	    when 'n':
X		if ((*argvp)[0][2] == '!') {
X		    ++(**argvp);
X		    flags->source_rc = -1;	/* No init files sourced */
X		} else
X		    flags->source_rc = 0;	/* Only ~/.mushrc sourced */
X	    when 'I':
X		if ((*argvp)[0][2] == '!' && flags->source_rc > 0)
X		    flags->source_rc = 0;	/* Only ~/.mushrc sourced */
X		if (!(flags->init_file = *++(*argvp)))
X		    puts("specify filename for init"), exit(1);
X		look_again = FALSE;
X	    when 'd': debug = 1;
X	    when '\0' : look_again = FALSE;
X	    otherwise:
X		print("%s: unknown option: `%c'\n", prog_name,
X		    (*argvp)[0][1]? (*argvp)[0][1] : '-');
X		print(usage_str, prog_name);
X	}
X	if (look_again && ++(**argvp) != '\0')
X	    goto DoLookAgain;
X    }
X
X    if (ison(flags->flg, SEND_NOW) && !flags->draft) {
X	print("You must specify a draft file to autosend\n");
X	exit(1);
X    }
}
SHAR_EOF
echo 'File options.c is complete' &&
chmod 0644 options.c ||
echo 'restore of options.c failed'
Wc_c="`wc -c < 'options.c'`"
test 8816 -eq "$Wc_c" ||
	echo 'options.c: original size 8816, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= options.h ==============
if test -f 'options.h' -a X"$1" != X"-c"; then
	echo 'x - skipping options.h (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting options.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'options.h' &&
/* @(#)options.h    (c) copyright 10/10/88 (Dan Heller, Bart Schaefer) */
X
/* Must #include mush.h before #including this file */
X
/* Structure to hold assorted information collected from command line flags.  
X *  Other information is held in the following global variables:
X *	cmd_help	General help file, specified by -1
X *	debug		Debugging mode, toggled by -d
X *	glob_flags	Bits set by -C, -e, -i, -S, -t and many commands
X *	hdrs_only	Show headers and exit, specified by -H
X *	iscurses	Curses mode, specified by -C or "curses" command
X *	istool		Tool mode, specified by -t or -T
X *	mailfile	File specified by -u or -f or "folder" command
X *	prog_name	Name under which mush is running
X *	time_out	Tool mode timeout, specified by -T
X *	tool_help	Tool mode help file, specified by -2
X */
X
struct mush_flags {
X    u_long flg;		/* Set by -v, -h, -U, vars */
X    char *init_file;	/* Set by -I or -I! */
X    char *src_file;	/* Set by -F */
X    int src_n_exit;	/* Set by -F! */
X    char *folder;	/* Set by -f or -u */
X    char *draft;	/* Set by -h */
X    char f_flags[10];	/* Set by -r, -N, etc.; passed to folder() */
X    char *Subj;		/* Set by -s */
X    char *Cc;		/* Set by -c */
X    char *Bcc;		/* Set by -b */
X    int source_rc;	/* Set by -n */
};
SHAR_EOF
chmod 0644 options.h ||
echo 'restore of options.h failed'
Wc_c="`wc -c < 'options.h'`"
test 1248 -eq "$Wc_c" ||
	echo 'options.h: original size 1248, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= panels.c ==============
if test -f 'panels.c' -a X"$1" != X"-c"; then
	echo 'x - skipping panels.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting panels.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'panels.c' &&
/* @(#)panel.c	(c) copyright	10/18/86 (Dan Heller) */
/* @(#)panels.c	(c) copyright	9/29/89 (Dan Heller) */
X
#include "mush.h"
/* mouse symbols */
short dat_mouse_left[] = {
X    0x1FF8, 0x3FFC, 0x336C, 0x336C, 0x336C, 0x336C, 0x336C, 0x336C, 
X    0x3FFC, 0x3FFC, 0x3FFC, 0x3FFC, 0x3FFC, 0x3FC4, 0x3FFC, 0x1FF8
};
X
short dat_mouse_middle[] = {
X    0x1FF8, 0x3FFC, 0x366C, 0x366C, 0x366C, 0x366C, 0x366C, 0x366C, 
X    0x3FFC, 0x3FFC, 0x3FFC, 0x3FFC, 0x3FFC, 0x3FC4, 0x3FFC, 0x1FF8
};
X
short dat_mouse_right[] = {
X    0x1FF8, 0x3FFC, 0x36CC, 0x36CC, 0x36CC, 0x36CC, 0x36CC, 0x36CC, 
X    0x3FFC, 0x3FFC, 0x3FFC, 0x3FFC, 0x3FFC, 0x3FC4, 0x3FFC, 0x1FF8
};
X
mpr_static(mouse_left,      16, 16, 1, dat_mouse_left);
mpr_static(mouse_middle,    16, 16, 1, dat_mouse_middle);
mpr_static(mouse_right,     16, 16, 1, dat_mouse_right);
X
Panel_item
X    folder_item,	/* change folders */
X    folder_text_item,	/* text item for the folder item */
X    file_item, 		/* text item for the save item */
X    msg_num_item,	/* text item explicitly states which message to read */
X    read_item,		/* read the current message */
X    save_item,		/* saves messages */
X    sub_hdr_item[6];	/* display items that just sit there and give help */
X
#ifndef NO_WALK_MENUS
Panel
X    folder_panel,
X    save_panel;
Menu	  folder_menu;	/* Menu of folders for folder button */
Menu	  save_menu;	/* Menu of folders for save button */
Menu	  hdr_save_menu;/* Menu of folders for save option in hdr window */
extern Menu msg_menu;	/* header subwindow menu, defined in hdr_sw.c */
walk_menu_event();
#endif /* NO_WALK_MENUS */
X
/* These global panel items for letter composition should eventually go away */
Panel_item
X    edit_item,		/* edit a message */
X    reply_item;		/* reply button -- also called from hdr_sw menu */
X
extern void
X    close_frame(), do_options(), do_compose(), do_send(), do_sort(),
X    do_edit(), delete_mail(), respond_mail(), do_help(), do_lpr(),
X    do_update(), abort_mail(), do_include(), load_from_file(),
X    save_to_file(), tilde_from_menu(), fkey_interposer(), do_mark(),
X    close_compose();
X
extern Panel_setting
X    msg_num_done(), file_dir();
X
Panel
make_hdr_panel(parent, choice_args, button_args)
Frame parent;
char **choice_args, **button_args;
{
X    Panel panel = window_create(parent, PANEL,
X	WIN_CONSUME_KBD_EVENTS,
X	    WIN_LEFT_KEYS, WIN_TOP_KEYS, WIN_RIGHT_KEYS, NULL,
X	NULL);
X    (void) notify_interpose_event_func(panel, fkey_interposer, NOTIFY_SAFE);
X
X    (void) panel_create_item(panel, PANEL_CHOICE,
X	PANEL_ATTRIBUTE_LIST, 		choice_args,
X	PANEL_LABEL_IMAGE,
X	    panel_button_image(panel, "Done", 4, mush_font),
X	PANEL_CHOICE_STRINGS,
X	    "Close to Icon", "Quit Tool", "Help", NULL,
X	PANEL_NOTIFY_PROC, 		toolquit,
X	NULL);
X
X    (void) panel_create_item(panel, PANEL_CHOICE,
X	PANEL_ATTRIBUTE_LIST, 		choice_args,
X	PANEL_LABEL_IMAGE,
X	    panel_button_image(panel, "Help", 4, mush_font),
X	PANEL_CHOICE_STRINGS,
X	    "About", "Help with \"help\"", "The Mouse", "Windows",
X	    "Message headers", "Message lists", "Folders", NULL,
X	PANEL_NOTIFY_PROC, 		do_help,
X	NULL);
X
#ifndef NO_WALK_MENUS
X    folder_panel = panel;
X    folder_item = panel_create_item(panel, PANEL_BUTTON,
X	PANEL_ATTRIBUTE_LIST, 		button_args,
X	PANEL_LABEL_IMAGE,
X	    panel_button_image(panel, "Folder", 6, mush_font),
X	PANEL_NOTIFY_PROC, 		do_file_dir,
X	PANEL_EVENT_PROC,		walk_menu_event,
X	NULL);
#else /* NO_WALK_MENUS */
X    folder_item = panel_create_item(panel, PANEL_CHOICE,
X	PANEL_ATTRIBUTE_LIST, 		choice_args,
X	PANEL_LABEL_IMAGE,
X	    panel_button_image(panel, "Folder", 6, mush_font),
X	PANEL_CHOICE_STRINGS,
X	    "System Mailbox", "Main Mailbox", "Last Accessed Folder", NULL,
X	PANEL_NOTIFY_PROC, 		do_file_dir,
X	NULL);
X
X    add_folder_to_menu(folder_item, 3);
#endif /* NO_WALK_MENUS */
X
X    folder_text_item = panel_create_item(panel, PANEL_TEXT,
X	PANEL_ATTRIBUTE_LIST, 		choice_args,
X	PANEL_LABEL_FONT, 		mush_font,
X	PANEL_LABEL_STRING,		"Filename:",
X	PANEL_VALUE_DISPLAY_LENGTH, 	28,
X	PANEL_NOTIFY_STRING, 		"\n\r\033",
X	PANEL_NOTIFY_PROC, 		file_dir,
X	NULL);
X
X    (void) panel_create_item(panel, PANEL_CHOICE,
X	PANEL_ATTRIBUTE_LIST, 		choice_args,
X	PANEL_LABEL_IMAGE,
X	    panel_button_image(panel, "Update", 6, mush_font),
X	PANEL_CHOICE_STRINGS, 		"New Mail", "Help", NULL,
X	PANEL_NOTIFY_PROC, 		do_update,
X	NULL);
X
X    (void) panel_create_item(panel, PANEL_CHOICE,
X	PANEL_ATTRIBUTE_LIST, 		choice_args,
X	PANEL_LABEL_IMAGE,
X	    panel_button_image(panel, "Options", 7, mush_font),
X	PANEL_CHOICE_STRINGS,		"Variables", "Headers", "Aliases", NULL,
X	PANEL_NOTIFY_PROC, 		do_options,
X	NULL);
X
X    msg_num_item = panel_create_item(panel, PANEL_TEXT,
X	PANEL_ATTRIBUTE_LIST,		choice_args,
X	PANEL_LABEL_STRING,		"Range:",
X	PANEL_MENU_CHOICE_STRINGS, 	"Help", NULL,
X	PANEL_VALUE_DISPLAY_LENGTH, 	17,
X	PANEL_VALUE_STORED_LENGTH, 	80,
X	PANEL_LABEL_FONT, 		mush_font,
X	PANEL_NOTIFY_STRING, 		"\n\r",
X	PANEL_NOTIFY_PROC, 		msg_num_done,
X	NULL);
X
X    sub_hdr_item[0] = panel_create_item(panel, PANEL_CHOICE,
X	PANEL_ATTRIBUTE_LIST, 		choice_args,
X	PANEL_LABEL_IMAGE,    		&mouse_left,
X	PANEL_CHOICE_STRINGS, 		"Help", NULL,
X	PANEL_NOTIFY_PROC,    		read_mail,
X	NULL);
X    sub_hdr_item[1] = panel_create_item(panel, PANEL_CHOICE,
X	PANEL_ATTRIBUTE_LIST, 		choice_args,
X	PANEL_LABEL_STRING,   		"Read ",
X	PANEL_MENU_TITLE_IMAGE, 	&mouse_left,
X	PANEL_CHOICE_STRINGS,		"Help", NULL,
X	PANEL_NOTIFY_PROC,    		read_mail,
X	NULL);
X    sub_hdr_item[2] = panel_create_item(panel, PANEL_CHOICE,
X	PANEL_ATTRIBUTE_LIST, 		choice_args,
X	PANEL_LABEL_IMAGE,    		&mouse_middle,
X	PANEL_CHOICE_STRINGS, 		"Help", NULL,
X	PANEL_NOTIFY_PROC,    		delete_mail,
X	NULL);
X    sub_hdr_item[3] = panel_create_item(panel, PANEL_CHOICE,
X	PANEL_ATTRIBUTE_LIST, 		choice_args,
X	PANEL_LABEL_STRING,   		"Delete ",
X	PANEL_MENU_TITLE_IMAGE, 	&mouse_middle,
X	PANEL_CHOICE_STRINGS, 		"Help", NULL,
X	PANEL_NOTIFY_PROC,    		delete_mail,
X	NULL);
X    sub_hdr_item[4] = panel_create_item(panel, PANEL_CHOICE,
X	PANEL_ATTRIBUTE_LIST, 		choice_args,
X	PANEL_LABEL_IMAGE,    		&mouse_right,
X	PANEL_CHOICE_STRINGS, 		"Help", NULL,
X	PANEL_NOTIFY_PROC,    		read_mail,
X	NULL);
X    sub_hdr_item[5] = panel_create_item(panel, PANEL_CHOICE,
X	PANEL_ATTRIBUTE_LIST, 		choice_args,
X	PANEL_LABEL_STRING,   		"Menu   ",
X	PANEL_MENU_TITLE_IMAGE,	    	&mouse_right,
X	PANEL_CHOICE_STRINGS, 		"Help", NULL,
X	PANEL_NOTIFY_PROC,    		read_mail,
X	NULL);
X
X    (void) panel_create_item(panel, PANEL_CHOICE,
X	PANEL_ATTRIBUTE_LIST, 		choice_args,
X	PANEL_LABEL_IMAGE,
X	    panel_button_image(panel, "Mark", 4, mush_font),
X	PANEL_CHOICE_STRINGS,
X	    "Toggle Mark", "Priority A", "Priority B", "Priority C",
X	    "Priority D", "Priority E", "Clear Priority", "Help", NULL,
X	PANEL_NOTIFY_PROC, 		do_mark,
X	NULL);
X
X    (void) panel_create_item(panel, PANEL_CHOICE,
X	PANEL_ATTRIBUTE_LIST, 		choice_args,
X	PANEL_LABEL_IMAGE,
X	    panel_button_image(panel, "Printer", 7, mush_font),
X	PANEL_CHOICE_STRINGS, 		"Help", NULL,
X	PANEL_NOTIFY_PROC, 		do_lpr,
X	NULL);
X
X    (void) panel_create_item(panel, PANEL_CHOICE,
X	PANEL_ATTRIBUTE_LIST, 		choice_args,
X	PANEL_LABEL_IMAGE,
X	    panel_button_image(panel, "Sort", 4, mush_font),
X	PANEL_CHOICE_STRINGS,
X	    "By Status", "By Author", "By Size", "By Subject",
X	    "By Subject (ignore Re:)", "By Date",
X	    "By Priority", "Value of $sort", "Help", NULL,
X	PANEL_NOTIFY_PROC, 		do_sort,
X	NULL);
X
X    window_fit_height(panel);
X    return panel;
}
X
Panel
make_main_panel(parent, choice_args, button_args)
Frame parent;
char **choice_args, **button_args;
{
X    /* main panel stuff: */
X    Panel panel = window_create(parent, PANEL,
X	WIN_CONSUME_KBD_EVENTS,
X	    WIN_LEFT_KEYS, WIN_TOP_KEYS, WIN_RIGHT_KEYS, NULL,
X	NULL);
X    (void) notify_interpose_event_func(panel, fkey_interposer, NOTIFY_SAFE);
X
X    read_item = panel_create_item(panel, PANEL_CHOICE,
X	PANEL_ATTRIBUTE_LIST, 		choice_args,
X	PANEL_LABEL_IMAGE,
X	    panel_button_image(panel, "Next", 4, mush_font),
X	PANEL_CHOICE_STRINGS, 		"Help", NULL,
X	PANEL_NOTIFY_PROC, 		read_mail,
X	NULL);
X
X    (void) panel_create_item(panel, PANEL_CHOICE,
X	PANEL_ATTRIBUTE_LIST, 		choice_args,
X	PANEL_LABEL_IMAGE,
X	    panel_button_image(panel, "Delete", 6, mush_font),
X	PANEL_CHOICE_STRINGS, 		"Delete",
X					"Undelete",
X					"Help", NULL,
X	PANEL_NOTIFY_PROC, 		delete_mail,
X	NULL);
X
#ifndef NO_WALK_MENUS
X    save_panel = panel;
X    save_item = panel_create_item(panel, PANEL_BUTTON,
X	PANEL_ATTRIBUTE_LIST, 		button_args,
X	PANEL_LABEL_IMAGE, panel_button_image(panel, "Save", 4, mush_font),
X	PANEL_NOTIFY_PROC, 		do_file_dir,
X	PANEL_EVENT_PROC,		walk_menu_event,
X	NULL);
X
X    create_folder_menus();
#else /* NO_WALK_MENUS */
X    {
X	char *mbox = do_set(set_options, "mbox");
X	if (!mbox || !*mbox)
X	    mbox = DEF_MBOX;
X	save_item = panel_create_item(panel, PANEL_CHOICE,
X	    PANEL_ATTRIBUTE_LIST, 	choice_args,
X	    PANEL_LABEL_IMAGE, panel_button_image(panel, "Save", 4, mush_font),
X	    PANEL_CHOICE_STRINGS, 	trim_filename(mbox), NULL,
X	    PANEL_NOTIFY_PROC, 		do_file_dir,
X	    NULL);
X    }
X
X    add_folder_to_menu(save_item, 1);
#endif /* NO_WALK_MENUS */
X
X    file_item = panel_create_item(panel, PANEL_TEXT,
X	PANEL_ATTRIBUTE_LIST, 		choice_args,
X	PANEL_LABEL_FONT, 		mush_font,
X	PANEL_SHOW_MENU,		TRUE,
X	PANEL_LABEL_STRING, 		"Filename:",
X	PANEL_MENU_CHOICE_STRINGS,	"Save message without message header",
X					NULL,
X	PANEL_VALUE_DISPLAY_LENGTH, 	28,
X	PANEL_NOTIFY_STRING, 		"\n\r\033",
X	PANEL_NOTIFY_PROC, 		file_dir,
X	NULL);
X
X    (void) panel_create_item(panel, PANEL_CHOICE,
X	PANEL_ATTRIBUTE_LIST, 		choice_args,
X	PANEL_LABEL_IMAGE,
X	    panel_button_image(panel, "Compose", 7, mush_font),
X	PANEL_CHOICE_STRINGS, 		"Help", NULL,
X	PANEL_NOTIFY_PROC,		do_compose,
X	NULL);
X
X    reply_item = panel_create_item(panel, PANEL_CHOICE,
X	PANEL_ATTRIBUTE_LIST, 		choice_args,
X	PANEL_LABEL_IMAGE,
X	    panel_button_image(panel, "Reply", 5, mush_font),
X	PANEL_CHOICE_STRINGS,
X	    "Sender Only", "Sender Only (include msg)",
X	    "All Recipients", "All Recipients (include msg)", "Help", NULL,
X	PANEL_NOTIFY_PROC, 		respond_mail,
X	NULL);
X
X    window_fit_height(panel);
X    return panel;
}
X
Panel
make_compose_panel(parent, choice_args, button_args)
Frame parent;
char **choice_args, **button_args;
{
X    Panel panel = window_create(parent, PANEL, NULL);
X    Panel_item filename_item, fortune_item, sign_item, send_item;
X
X    (void) notify_interpose_event_func(panel, fkey_interposer, NOTIFY_SAFE);
X
X    if (do_set(set_options, "compose_icon"))
X	(void) panel_create_item(panel, PANEL_CHOICE,
X	    PANEL_ATTRIBUTE_LIST, 		choice_args,
X	    PANEL_LABEL_IMAGE,
X		panel_button_image(panel, "Close", 5, mush_font),
X	    PANEL_CHOICE_STRINGS,
X		"Close to Icon", "Quit", "Help", NULL,
X	    PANEL_NOTIFY_PROC, 		close_compose,
X	    NULL);
X    else
X	(void) panel_create_item(panel, PANEL_BUTTON,
X	    PANEL_ATTRIBUTE_LIST, 		button_args,
X	    PANEL_LABEL_IMAGE,
X		panel_button_image(panel, "Close", 5, mush_font),
X	    PANEL_NOTIFY_PROC, 		close_frame,
X	    NULL);
X
X    (void) panel_create_item(panel, PANEL_CHOICE,
X	PANEL_ATTRIBUTE_LIST, 		choice_args,
X	PANEL_LABEL_IMAGE,
X	    panel_button_image(panel, "Compose", 7, mush_font),
X	PANEL_CHOICE_STRINGS, 		"Help", NULL,
X	PANEL_NOTIFY_PROC, 		do_compose,
X	NULL);
X
X    send_item = panel_create_item(panel, PANEL_BUTTON,
X	PANEL_ATTRIBUTE_LIST, 		button_args,
X	PANEL_SHOW_ITEM, 		FALSE,
X	PANEL_LABEL_IMAGE,
X	    panel_button_image(panel, "Send", 4, mush_font),
X	PANEL_NOTIFY_PROC, 		do_send,
X	NULL);
X
X    (void) panel_create_item(panel, PANEL_BUTTON,
X	PANEL_ATTRIBUTE_LIST, 		button_args,
X	PANEL_SHOW_ITEM,		FALSE,
X	PANEL_LABEL_IMAGE,
X	    panel_button_image(panel, "Abort", 5, mush_font),
X	PANEL_NOTIFY_PROC, 		abort_mail,
X	NULL);
X
X    (void) panel_create_item(panel, PANEL_CHOICE,
X	PANEL_ATTRIBUTE_LIST, 		choice_args,
X	PANEL_SHOW_ITEM, 		FALSE,
X	PANEL_LABEL_IMAGE,
X	    panel_button_image(panel, "Include", 7, mush_font),
X	PANEL_CHOICE_STRINGS, 		"Include Message",
X					"Forward Message",
X					"Help", NULL,
X	PANEL_NOTIFY_PROC, 		do_include,
X	NULL);
X
X    edit_item = panel_create_item(panel, PANEL_BUTTON,
X	PANEL_ATTRIBUTE_LIST, 		button_args,
X	PANEL_SHOW_ITEM, 		FALSE,
X	PANEL_LABEL_IMAGE,
X	    panel_button_image(panel, "Edit", 4, mush_font),
X	PANEL_NOTIFY_PROC, 		do_edit,
X	NULL);
X
X    (void) panel_create_item(panel, PANEL_CHOICE,
X	PANEL_ATTRIBUTE_LIST, 		choice_args,
X	PANEL_SHOW_ITEM,		FALSE,
X	PANEL_LABEL_IMAGE,
X	    panel_button_image(panel, "Headers", 7, mush_font),
X	PANEL_CHOICE_STRINGS,	
X	    "ALL      ~h", "To:      ~t", "Subject: ~s",
X	    "Cc:      ~c", "Bcc:     ~b", "Fcc:", NULL,
X	PANEL_NOTIFY_PROC,		tilde_from_menu,
X	NULL);
X
X    sign_item = panel_create_item(panel, PANEL_CHOICE,
X	PANEL_ATTRIBUTE_LIST, 		choice_args,
X	PANEL_DISPLAY_LEVEL,		PANEL_ALL,
X	PANEL_SHOW_MENU_MARK,		TRUE,
X	PANEL_SHOW_ITEM, 		FALSE,
X	PANEL_LABEL_STRING,		"Autosign:",
X	PANEL_CHOICE_STRINGS,		"Off", "On", NULL,
X	NULL);
X    panel_set_value(sign_item, !!do_set(set_options, "autosign"));
X    /* Create a link to avoid global */
X    panel_set(send_item, PANEL_CLIENT_DATA, sign_item, NULL);
X
X    filename_item = panel_create_item(panel, PANEL_TEXT,
X	PANEL_ATTRIBUTE_LIST, 		button_args,
X	PANEL_SHOW_ITEM,		FALSE,
X	PANEL_LABEL_STRING,		"Filename:",
X	PANEL_VALUE_DISPLAY_LENGTH, 	30,
X	PANEL_NOTIFY_STRING, 		"\033",
X	PANEL_NOTIFY_PROC, 		file_dir,
X	NULL);
X
X    (void) panel_create_item(panel, PANEL_CHOICE,
X	PANEL_ATTRIBUTE_LIST, 		choice_args,
X	PANEL_SHOW_ITEM,		FALSE,
X	PANEL_CLIENT_DATA,		filename_item,
X	PANEL_LABEL_IMAGE,
X	    panel_button_image(panel, "Import", 6, mush_font),
X	PANEL_CHOICE_STRINGS,		"Insert", "Replace", NULL,
X	PANEL_NOTIFY_PROC,		load_from_file,
X	NULL);
X
X    (void) panel_create_item(panel, PANEL_BUTTON,
X	PANEL_ATTRIBUTE_LIST, 		button_args,
X	PANEL_SHOW_ITEM,		FALSE,
X	PANEL_CLIENT_DATA,		filename_item,
X	PANEL_LABEL_IMAGE,
X	    panel_button_image(panel, "Export", 6, mush_font),
X	PANEL_NOTIFY_PROC,		save_to_file,
X	NULL);
X
X    fortune_item = panel_create_item(panel, PANEL_CHOICE,
X	PANEL_ATTRIBUTE_LIST, 		choice_args,
X	PANEL_DISPLAY_LEVEL,		PANEL_ALL,
X	PANEL_SHOW_MENU_MARK,		TRUE,
X	PANEL_SHOW_ITEM, 		FALSE,
X	PANEL_LABEL_STRING,		"Fortune:",
X	PANEL_CHOICE_STRINGS,		"Off", "On", NULL,
X	NULL);
X    panel_set_value(fortune_item, !!do_set(set_options, "fortune"));
X    /* Create a link to avoid global */
X    panel_set(sign_item, PANEL_CLIENT_DATA, fortune_item, NULL);
X
X    window_fit_height(panel);
X    return panel;
}
X
#include "glob.h"
X
#ifndef NO_WALK_MENUS
X
static
Menu_item
make_folder_item(path)
char *path;
{
X    Menu_item		mi;
X    Menu_item		sub_mi;
X    Menu		next_menu;
X    char		**names, **np;
X    struct stat 	s_buf;
X    char		buf[MAXPATHLEN];
X
X    if (glob(path, "*/{.,..}")) {
X	return NULL;
X    }
X
X    /* don't add a folder to the list if user can't read it */
X    if (stat(path, &s_buf) == -1 || !(s_buf.st_mode & S_IREAD)) {
X	return NULL;
X    }
X    mi = menu_create_item(
X	MENU_STRING,		savestr(basename(trim_filename(path))),
X	MENU_CLIENT_DATA,	NULL,
X	MENU_RELEASE,		/* no value */
X	NULL);
X    if ((s_buf.st_mode & S_IFMT) == S_IFDIR) {
X	int cnt = 0;
X	next_menu = menu_create(MENU_NOTIFY_PROC, menu_return_item, NULL);
X	sprintf(buf, "%s/{.*,*}", path);
X	if (filexp(buf, &names) > 0) {
X	    for (np = names; np && *np; np++) {
X		if ((sub_mi = make_folder_item(*np)) != NULL) {
X		    menu_set(next_menu, MENU_APPEND_ITEM, sub_mi, NULL);
X		    ++cnt;
X		}
X	    }
X	    free_vec(names);
X	}
X	if (! cnt) {
X	    menu_destroy(next_menu);
X	    menu_set(mi, MENU_INACTIVE, TRUE, NULL);
X	} else {
X	    menu_set(mi, MENU_PULLRIGHT, next_menu, NULL);
X	}
X    } else if (test_folder(path, NULL)) {
X	menu_set(mi, MENU_CLIENT_DATA, savestr(path), NULL);
X    } else {
X	menu_destroy(mi);
X	mi = NULL;
X    }
X    return mi;
}
X
static
void
destroy_folder_item(menu_item, menu_type)
Menu_item menu_item;
Menu_attribute menu_type;
{
X    char	*ptr;
X
X    if (menu_type == MENU_ITEM) {
X	if ((ptr = (char *)menu_get(menu_item, MENU_STRING)) != NULL) {
X	    free(ptr);
X	}
X	if ((ptr = (char *)menu_get(menu_item, MENU_CLIENT_DATA)) != NULL) {
X	    free(ptr);
X	}
X    }
X    return;
}
X
create_folder_menus()
{
X    int 	  item_number;
X    Menu	  menu;
X    Menu_item	  menu_item;
X    int 	  nitems;
X    char	 *mbox;
X    char	 *tmp = NULL;
X    char	 *p;
X    static int	  menus_exist = 0;
X
X    if (menus_exist) {
X	/* remove duplicated menu items from save_menu */
X	for (item_number = (int)menu_get(save_menu, MENU_NITEMS) ;
X	      item_number > 1 ; --item_number) {
X	    menu_set(save_menu, MENU_REMOVE, item_number, NULL);
X	}
X	/* remove duplicated menu items from hdr_save_menu */
X	for (item_number = (int)menu_get(hdr_save_menu, MENU_NITEMS) ;
X	      item_number > 1 ; --item_number) {
X	    menu_set(save_menu, MENU_REMOVE, item_number, NULL);
X	}
X	menu_destroy_with_proc(hdr_save_menu, destroy_folder_item);
X	menu_destroy_with_proc(save_menu, destroy_folder_item);
X	menu_destroy_with_proc(folder_menu, destroy_folder_item);
X    }
X
X    if (!(p = do_set(set_options, "folder")) || !*p) {
X	p = DEF_FOLDER;
X    }
X    if (p) {
X	int x = 0;
X	tmp = getpath(p, &x);
X	if (x == -1) {
X	    if (errno != ENOENT)
X		print("%s: %s\n", p, tmp);
X	    tmp = NULL;
X	}
X    }
X    menu = NULL;
X    menu_item = NULL;
X    if (tmp != NULL) {
X	if ((menu_item = make_folder_item(tmp)) != NULL) {
X	    if ((menu = menu_get(menu_item, MENU_PULLRIGHT)) != NULL) {
X	        /* $folder was a directory, use the pullright
X		 * instead of the directory menu item.
X		 */
X		/* "unhook" the pullright (so it is not released) */
X		menu_set(menu_item, MENU_PULLRIGHT, NULL, NULL);
X		/* destroy the menu item */
X		menu_destroy_with_proc(menu_item, destroy_folder_item);
X		menu_item = NULL;
X	    }
X	}
X    }
X    if (menu == NULL) {
X	menu = menu_create(MENU_NOTIFY_PROC, menu_return_item, NULL);
X	if (menu_item != NULL) {
X	    menu_set(menu, MENU_APPEND_ITEM, menu_item, NULL);
X	}
X    }
X
X    /* create save_menu */
X    save_menu = menu_create(MENU_NOTIFY_PROC, menu_return_item, NULL);
X    /* add magic first item */
X    mbox = do_set(set_options, "mbox");
X    if (!mbox || !*mbox) {
X	mbox = DEF_MBOX;
X    }
X    menu_item = menu_create_item(
X	MENU_STRING,		savestr(trim_filename(mbox)),
X	MENU_CLIENT_DATA,	savestr(mbox),
X	MENU_RELEASE,		/* no value */
X	NULL);
X    menu_set(save_menu, MENU_APPEND_ITEM, menu_item, NULL);
X    /* copy menu for save_menu */
X    nitems = (int)menu_get(menu, MENU_NITEMS);
X    for (item_number = 1 ; item_number <= nitems ; ++item_number) {
X	menu_set(save_menu,
X	    MENU_APPEND_ITEM, menu_get(menu, MENU_NTH_ITEM, item_number),
X	    NULL);
X    }
X
X    /* create hdr_save_menu */
X    hdr_save_menu = menu_create(MENU_NOTIFY_PROC, menu_return_item, NULL);
X    /* add magic first item */
X    menu_item = menu_create_item(
X	MENU_STRING,		savestr("use Filename:"),
X	MENU_CLIENT_DATA,	savestr(""),	/* magic */
X	MENU_RELEASE,		/* no value */
X	NULL);
X    menu_set(hdr_save_menu, MENU_APPEND_ITEM, menu_item, NULL);
X    /* copy save_menu for hdr_save_menu */
X    nitems = (int)menu_get(save_menu, MENU_NITEMS);
X    for (item_number = 1 ; item_number <= nitems ; ++item_number) {
X	menu_set(hdr_save_menu,
X	    MENU_APPEND_ITEM, menu_get(save_menu, MENU_NTH_ITEM, item_number),
X	    NULL);
X    }
X    /* Make sure the header subwindow menu exists so we can tack on a
X     * pullright for Save.
X     */
X    if (! msg_menu) {
X	get_msg_menu();
X    }
X    if ((menu_item = menu_find(msg_menu, MENU_STRING, "Save", NULL))
X	    != NULL) {
X	menu_set(menu_item, MENU_PULLRIGHT, hdr_save_menu, NULL);
X    }
X
X    /* insert folder-specific initial options to menu */
X    folder_menu = menu;
X    menu_item = menu_create_item(
X	MENU_STRING,		savestr("System Mailbox"),
X	MENU_CLIENT_DATA,	savestr("%"),
X	MENU_RELEASE,		/* no value */
X	NULL);
X    menu_set(folder_menu, MENU_INSERT, 0, menu_item, NULL);
X    menu_item = menu_create_item(
X	MENU_STRING,		savestr("Main Mailbox"),
X	MENU_CLIENT_DATA,	savestr("&"),
X	MENU_RELEASE,		/* no value */
X	NULL);
X    menu_set(folder_menu, MENU_INSERT, 1, menu_item, NULL);
X    menu_item = menu_create_item(
X	MENU_STRING,		savestr("Last Accessed Folder"),
X	MENU_CLIENT_DATA,	savestr("#"),
X	MENU_RELEASE,		/* no value */
X	NULL);
X    menu_set(folder_menu, MENU_INSERT, 2, menu_item, NULL);
X
X    menus_exist = 1;
X    return;
}
X
static
walk_menu_event(item, event)
Panel_item item;
Event *event;
{
X    char	 *folder_name;
X    Menu_item 	  selection;
X    Menu	  menu;
X    Panel	  panel;
X    void xx_file_dir();
X
X    if (event_id(event) == MS_RIGHT && event_is_down(event)) {
X	if (item == folder_item) {
X	    menu = folder_menu;
X	    panel = folder_panel;
X	} else {
X	    menu = save_menu;
X	    panel = save_panel;
X	}
X	selection = (Menu_item)menu_show(menu, panel, event, 0);
X	if (! selection) {
X	    /* no selection was made */
X	    return;
X	}
X	if ((folder_name = (char *)menu_get(selection, MENU_CLIENT_DATA))
X		!= NULL) {
X	    xx_file_dir(item, folder_name);
X	}
X    } else {
X	panel_default_handle_event(item, event);
X    }
}
X
#else /* NO_WALK_MENUS */
X
static
add_path_to_menu(item, path, n)
Panel_item item;
char *path;
int *n;
{
X    char		**names, **np;
X    struct stat 	s_buf;
X    char		buf[MAXPATHLEN];
X
X    /* don't add a folder to the list if user can't read it */
X    if (stat(path, &s_buf) == -1 || !(s_buf.st_mode & S_IREAD))
X	return;
X    if ((s_buf.st_mode & S_IFMT) == S_IFDIR) {
X	sprintf(buf, "%s/{.*,*}", path);
X	if (filexp(buf, &names) > 0) {
X	    for (np = names; np && *np; np++) {
X		if (!glob(*np, "*/{.,..}"))
X		    add_path_to_menu(item, *np, n);
X	    }
X	    free_vec(names);
X	}
X    } else if (test_folder(path, NULL))
X	panel_set(item,
X	    PANEL_CHOICE_STRING, (*n)++, savestr(trim_filename(path)),
X	    NULL);
}
X
/*
X * Open the user's mail folder (either user set or default path) and find all
X * the files (assumed to be mail folders) and add them to the menu list of
X * folders to use.
X */
add_folder_to_menu(item, n)
Panel_item item;
{
X    char	*tmp = NULL, *p;
X
X    if (!(p = do_set(set_options, "folder")) || !*p)
X	p = DEF_FOLDER;
X    if (p) {
X	int x = 0;
X	tmp = getpath(p, &x);
X	if (x == -1) {
X	    if (errno != ENOENT)
X		print("%s: %s\n", p, tmp);
X	    tmp = NULL;
X	}
X    }
X    if (tmp) {
X	add_path_to_menu(item, tmp, &n);
X    }
}
#endif /* NO_WALK_MENUS */
SHAR_EOF
chmod 0644 panels.c ||
echo 'restore of panels.c failed'
Wc_c="`wc -c < 'panels.c'`"
test 22092 -eq "$Wc_c" ||
	echo 'panels.c: original size 22092, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= pick.c ==============
if test -f 'pick.c' -a X"$1" != X"-c"; then
	echo 'x - skipping pick.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting pick.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'pick.c' &&
/* @(#)pick.c	2.4	(c) copyright 10/18/86 (Dan Heller) */
X
#include "mush.h"
X
static int before, after, search_from, search_subj, search_to, xflg, icase;
static u_long match_priority;
static char search_hdr[64];
static int mdy[3];
static int pick();
static void month_day_year();
X
do_pick(n, argv, list)
register int n;
register char **argv, list[];
{
X    char ret_list[MAXMSGS_BITS];
X
X    if (n > 1 && !strcmp(argv[1], "-?"))
X	return help(0, "pick", cmd_help);
X
X    clear_msg_list(ret_list);
X    /* if is_pipe, then the messages to search for are already set.
X     * if not piped, then reverse the bits for all message numbers.
X     * That is, search EACH message. only those matching will be returned.
X     */
X    if (isoff(glob_flags, IS_PIPE))
X	bitput(ret_list, list, msg_cnt, =~); /* macro, turn on all bits */
X    /* Use n temporarily as verbosity flag */
X    n = (!chk_option("quiet", "pick") &&
X	    isoff(glob_flags, DO_PIPE));
X    if ((n = pick(argv, list, ret_list, n)) == -1)
X	return -1;
X    if (istool && isoff(glob_flags, DO_PIPE))
X	print("%d matches:\n", n);
X    for (n = 0; n < msg_cnt; n++)
X	if (msg_bit(ret_list, n)) {
X	    if (isoff(glob_flags, DO_PIPE))
X		if (istool)
X		    print_more("%d ", n+1);
X		else
X		    print("%s\n", compose_hdr(n));
X	    set_msg_bit(list, n);
X	} else
X	    unset_msg_bit(list, n);
X    return 0;
}
X
/*
X * search for messages.  Return the number of matches.  Errors such
X * as internal errors or syntax errors, return -1.
X * "head" and "tail" are specified using +<num> or -<num> as args.
X * Both can be specified and the order is significant.
X *    pick +5 -3
X * returns the last three of the first five matches.
X *    pick -3 +2
X * returns the first two of the last three matches.
X */
static int
pick(argv, list, ret_list, verbose)
register char **argv, list[], ret_list[];
{
X    register char c;
X    int matches = 0;
X    char pattern[256];
X    short head_first, head_cnt, tail_cnt, search = TRUE;
X    int n;
X
X    if (!msg_cnt) {
X	print("No Messages.\n");
X	return -1;
X    }
X
X    head_first = TRUE;
X    head_cnt = tail_cnt = -1;
X    match_priority = 0;
X    icase = before = after = search_from = search_subj = search_to = xflg = 0;
X    mdy[0] = mdy[1] = search_hdr[0] = 0;
X    while (*argv && *++argv && (**argv == '-' || **argv == '+'))
X	if (**argv == '+' || isdigit(argv[0][1])) {
X	    if (**argv == '+')
X		head_cnt = atoi(&argv[0][1]);
X	    else {
X		tail_cnt = atoi(&argv[0][1]);
X		if (head_cnt == -1)
X		    head_first = FALSE;
X	    }
X	    if (head_cnt == 0 || tail_cnt == 0) {
X		print("pick: invalid head/tail number: %s\n", &argv[0][1]);
X		clear_msg_list(ret_list);
X		return -1;
X	    }
X	} else if ((c = argv[0][1]) == 'e') {
X	    if (!*++argv) {
X		print("usage: -e expression...\n");
X		return -1;
X	    }
X	    break;
X	} else switch (c) {
X	    /* user specifies a range */
X	    case 'r': {
X		int X = 2;
X		/* if not a pipe, then clear all bits cuz we only want
X		 * to search the message specified here...
X		 * If it is a pipe, then add to the messages searched for.
X		 */
X		if (isoff(glob_flags, IS_PIPE))
X		    clear_msg_list(list);
X		/*  "-r10-15"
X		 *     ^argv[1][2]  if NULL, then
X		 * list detached from "r" e.g. "-r" "5-20"
X		 */
X		if (!argv[0][X])
X		    argv++, X = 0;
X		(*argv) += X;
X		n = get_msg_list(argv, list);
X		(*argv) -= X;
X		if (n == -1)
X		    return -1;
X		argv += (n-1); /* we're going to increment another up top */
X	    }
X	    when 'a': {
X		if ((n = ago_date(++argv)) == -1)
X		    return -1;
X		argv += n;
X	    }
X	    when 'd':
X		if (!*++argv) {
X		    print("Specify a date for -%c\n", c);
X		    return -1;
X		}
X		if (!date1(*argv))
X		    return -1;
X	    when 's' : case 'f': case 't': case 'h':
X		if (search_subj + search_from + search_to + *search_hdr > 1) {
X		    print("Specify one of `s', `f', `t' or `h' only\n");
X		    return -1;
X	        }
X	        if (c == 's')
X		    search_subj = 1;
X		else if (c == 'f')
X		    search_from = 1;
X		else if (c == 'h')
X		    if (!*++argv)
X			print("Specify header to search for.\n");
X		    else
X			(void) lcase_strcpy(search_hdr, *argv);
X		else
X		    search_to = 1;
X	    when 'p' :	/* Select on priority field */
X		if (!*++argv || (c = upper(**argv)) < 'A' ||
X			c > MAX_PRIORITY + 'A') {
X		    print("pick: invalid priority: %s\n", argv[0]);
X		    clear_msg_list(ret_list);
X		    return -1;
X		}
X		turnon(match_priority, M_PRIORITY(c - 'A' + 1));
X	    when 'x' : xflg = 1;
X	    when 'i' : icase = 1;
X	    otherwise:
X		print("pick: unknown flag: %c\n", argv[0][1]);
X		clear_msg_list(ret_list);
X		return -1;
X	}
X    if (xflg && head_cnt + tail_cnt >= 0) {
X	print("Can't specify -x and head/tail options together.\n");
X	return -1;
X    }
X    if (!mdy[1]) {
X	pattern[0] = 0;
X	(void) argv_to_string(pattern, argv);
X	if (pattern[0] == '\0' && match_priority == 0 &&
X		head_cnt + tail_cnt < 0) {
X	    print("No pattern specified\n");
X	    clear_msg_list(ret_list);  /* doesn't matter really */
X	    return -1;
X	}
X    }
X    search = (pattern[0] || mdy[1] || match_priority > 0);
X    if (verbose) {
X	if (head_cnt + tail_cnt >= 0) {
X	    print("Finding the ");
X	    if (head_cnt > 0) {
X		if (head_first)
X		    if (tail_cnt == -1)
X			print_more("first %d message%s",
X			    head_cnt, head_cnt > 1? "s" : "");
X		    else
X			print_more("last %d message%s",
X			    tail_cnt, tail_cnt > 1? "s" : "");
X		else /* there must be a tail_cnt and it comes first */
X		    print_more("first %d message%s",
X			    head_cnt, head_cnt > 1? "s" : "");
X	    } else
X		print_more("last %d message%s",
X		    tail_cnt, tail_cnt > 1? "s" : "");
X	    if (tail_cnt > 0 && head_cnt > 0)
X		if (head_first)
X		    print_more(" of the first %d", head_cnt);
X		else
X		    print_more(" of the last %d", tail_cnt);
X	} else
X	    print_more("Searching for %smessages",
X		match_priority > 0 ? "priority " : "");
X	if (!search) {
X	    if (tail_cnt > 0 && head_cnt > 0)
X		print_more(" messages");
X	    if (ison(glob_flags, IS_PIPE))
X		print_more(" from the input list");
X	} else if (pattern[0]) {
X	    print_more(" that %scontain \"%s\"", (xflg)? "do not ": "",
X			    pattern);
X	    if (search_subj)
X		print_more(" in subject line");
X	    else if (search_from)
X		print_more(" from author names");
X	    else if (search_to)
X		print_more(" from the To: field");
X	    else if (search_hdr[0])
X		print_more(" from the message header \"%s:\"", search_hdr);
X	} else if (mdy[1]) {
X	    extern char *month_names[]; /* from dates.c */
X	    print_more(" dated ");
X	    if (before || after)
X		if (xflg)
X		    print_more("%s ", (!before)? "before": "after");
X		else
X		    print_more("on or %s ", (before)? "before": "after");
X	    print_more("%s. %d, %d",
X		      month_names[mdy[0]], mdy[1], mdy[2] + 1900);
X	}
X	print_more(".\n");
X    }
X    if (mdy[1] > 0 && icase)
X	print("using date: -i flag ignored.\n");
X    if (!search) {
X	for (n = 0; n < msg_cnt && (!head_first || matches < head_cnt); n++)
X	    if (msg_bit(list, n))
X		++matches, set_msg_bit(ret_list, n);
X    } else
X	matches = find_pattern(head_first? head_cnt : msg_cnt,
X			   pattern, list, ret_list);
X    if (xflg && matches >= 0) {
X	/* invert items in ret_list that also appear in list */
X	bitput(list, ret_list, msg_cnt, ^=);
X	/* there should be a faster way to do this count ... */
X	for (matches = n = 0; n < msg_cnt; n++)
X	    if (msg_bit(ret_list, n))
X		++matches;
X    }
X    Debug("matches = %d\n", matches);
X    if (!matches)
X	return 0;
X
X    /* ok, the list we've got is a list of matched messages.  If "tailing"
X     * is set, reduce the number of matches to at least tail_cnt.
X     */
X    if (tail_cnt >= 0)
X	for (n = 0; n < msg_cnt && matches > tail_cnt; n++)
X	    if (msg_bit(ret_list, n)) {
X		Debug("tail: dropping %d\n", n+1);
X		unset_msg_bit(ret_list, n);
X		matches--;
X	    }
X
X    /* if tailing came before heading, we need to do the heading now. */
X    if (!head_first && head_cnt >= 0)
X	for (n = 0; n < msg_cnt; n++)
X	    if (msg_bit(ret_list, n))
X		if (head_cnt > 0)
X		    head_cnt--;
X		else {
X		    unset_msg_bit(ret_list, n);
X		    matches--;
X		}
X    return matches;
}
X
/*
X * find_pattern will search thru all the messages set in the check_list
X * until the list runs out or "cnt" has been exhasted.  ret_list contains
X * the list of messages which have matched the pattern.
X * return -1 for internal error or # of pattern matches.
X */
find_pattern(cnt, p, check_list, ret_list)
int cnt;
register char *p;
char check_list[], ret_list[];
{
X    register int n, val, i; /* val is return value from regex or re_exec */
X    int matches = 0;
X    long bytes = 0;
X    char buf[HDRSIZ];
X    static char *err = (char *)-1;
#ifdef REGCMP
X    char *regcmp(), *regex();
#else /* REGCMP */
X    char *re_comp();
#endif /* REGCMP */
X
X    if (p && *p == '\\')
X	p++;  /* take care of escaping special cases (`-', `\') */
X
X    /* specify what we're looking for */
X    if (p && *p) {
X	if (icase)
X	    p = lcase_strcpy(buf, p);
#ifdef REGCMP
X	if (err && p)
X	    xfree(err);
X	if (p && !(err = regcmp(p, NULL))) {
X	    print("regcmp error: %s\n", p);
X	    clear_msg_list(ret_list);
X	    return -1;
X	}
#else /* REGCMP */
X	if (err = re_comp(p)) {
X	    print("re_comp error: %s\n", err);
X	    clear_msg_list(ret_list);
X	    return -1;
X	}
#endif /* REGCMP */
X    } else if (err == (char *)-1 && mdy[1] <= 0 && match_priority == 0) {
X	print("No previous regular expression\n");
X	clear_msg_list(ret_list);  /* doesn't matter really */
X	return -1;
X    }
X    /* start searching: set bytes, and message number: n */
X    for (n = 0; cnt && n < msg_cnt; n++)
X	if (msg_bit(check_list, n)) {
X	    if (match_priority > 0) {
X		if (msg[n].m_flags & match_priority)
X		    ++matches, set_msg_bit(ret_list, n);
X		continue;
X	    }
X	    if (mdy[1] > 0) {
X		int msg_mdy[3];
X		if (ison(glob_flags, DATE_RECV))
X		    p = msg[n].m_date_recv;
X		else
X		    p = msg[n].m_date_sent;
X		/* Ick -- fix this mdy thing asap */
X		month_day_year(p, &msg_mdy[0], &msg_mdy[1], &msg_mdy[2]);
X		Debug("checking %d's date: %d-%d-%d  ",
X			     n+1, msg_mdy[0]+1, msg_mdy[1], msg_mdy[2]);
X		/* start at year and wrap around.
X		 * only when match the day (4), check for == (match)
X		 */
X		for (i = 2; i < 5; i++)
X		    if (before && msg_mdy[i%3] < mdy[i%3]
X		    ||  after  && msg_mdy[i%3] > mdy[i%3]
X		    ||  i == 4 && (msg_mdy[i%3] == mdy[i%3])) {
X			    Debug("matched (%s).\n",
X				(i == 2)? "year" : (i == 3)? "month" : "day");
X			    set_msg_bit(ret_list, n);
X			    cnt--, matches++;
X			    break;
X		    } else if (msg_mdy[i%3] != mdy[i%3]) {
X			Debug("failed.\n");
X			break;
X		    }
X		continue;
X	    }
X	    /* we must have the right date -- if we're searching for a
X	     * string, find it.
X	     */
X	    (void) msg_get(n, NULL, 0);
X	    bytes = 0;
X	    while (bytes < msg[n].m_size) {
X		if (!search_subj && !search_from && !search_to &&
X		    !*search_hdr && !(p = fgets(buf, sizeof buf, tmpf)))
X		    break;
X		else if (search_subj) {
X		    if (!(p = header_field(n, "subject")))
X			break;
X		} else if (search_from) {
X		    if (!(p = header_field(n, "from"))) {
X			/*
X			 * Check for MSG_SEPARATOR here?  Maybe not...
X			 */
X			register char *p2;
X			(void) msg_get(n, NULL, 0);
X			if (!(p2 = fgets(buf, sizeof buf, tmpf)) ||
X			    !(p = index(p2, ' ')))
X			    continue;
X			p++;
X			if (p2 = any(p, " \t"))
X			    *p2 = 0;
X		    }
X		} else if (search_to) {
X		    if (!(p = header_field(n, "to")) &&
X		        !(p = header_field(n, "apparently-to")))
X			break;
X		} else if (*search_hdr) {
X		    if (!(p = header_field(n, search_hdr)))
X			break;
X		}
X		if (icase)
X		    p = lcase_strcpy(buf, p);
#ifdef REGCMP
X		val = !!regex(err, p, NULL); /* convert value to a boolean */
#else /* REGCMP */
X		val = re_exec(p);
#endif /* REGCMP */
X		if (val == -1) {   /* doesn't apply in system V */
X		    print("Internal error for pattern search.\n");
X		    clear_msg_list(ret_list); /* it doesn't matter, really */
X		    return -1;
X		}
X		if (val) {
X		    set_msg_bit(ret_list, n);
X		    cnt--, matches++;
X		    break;
X		}
X		if (search_subj || search_from || search_to || *search_hdr)
X		    break;
X		else
X		    bytes += strlen(p);
X	    }
X	}
X    return matches;
}
X
#ifdef CURSES
/*
X * search for a pattern in composed message headers -- also see next function
X * flags ==  0   forward search (prompt).
X * flags == -1   continue search (no prompt).
X * flags ==  1   backward search (prompt).
X */
search(flags)
register int flags;
{
X    register char   *p;
X    char   	    pattern[128];
X    register int    this_msg = current_msg, val = 0;
X    static char     *err = (char *)-1, direction;
X    SIGRET	    (*oldint)(), (*oldquit)();
#ifdef REGCMP
X    char *regcmp();
#else /* REGCMP */
X    char *re_comp();
#endif /* REGCMP */
X
X    if (msg_cnt <= 1) {
X	print("Not enough messages to invoke a search.\n");
X	return 0;
X    }
X    pattern[0] = '\0';
X    if (flags == -1)
X	print("continue %s search...", direction? "forward" : "backward");
X    else
X	print("%s search: ", flags? "backward" : "forward");
X    if (flags > -1)
X	if (Getstr(pattern, COLS-18, 0) < 0)
X	    return 0;
X	else
X	    direction = !flags;
#ifdef REGCMP
X    if (err && *pattern)
X	xfree(err);
X    else if (err == (char *)-1 && !*pattern) {
X	print("No previous regular expression.");
X	return 0;
X    }
X    if (*pattern && !(err = regcmp(pattern, NULL))) {
X	print("Error in regcmp in %s", pattern);
X	return 0;
X    }
#else /* REGCMP */
X    if (err = re_comp(pattern)) {
X	print(err);
X	return 0;
X    }
#endif /* REGCMP */
X    move(LINES-1, 0), refresh();
X    on_intr();
X
X    do  {
X	if (direction)
X	    current_msg = (current_msg+1) % msg_cnt;
X	else
X	    if (--current_msg < 0)
X		current_msg = msg_cnt-1;
X	p = compose_hdr(current_msg);
#ifdef REGCMP
X	val = !!regex(err, p, NULL); /* convert value to a boolean */
#else /* REGCMP */
X	val = re_exec(p);
#endif /* REGCMP */
X	if (val == -1)     /* doesn't apply in system V */
X	    print("Internal error for pattern search.\n");
X    } while (!val && current_msg != this_msg && isoff(glob_flags, WAS_INTR));
X
X    if (ison(glob_flags, WAS_INTR)) {
X	print("Pattern search interrupted.");
X	current_msg = this_msg;
X    } else if (val == 0)
X	print("Pattern not found.");
X
X    off_intr();
X    return val;
}
#endif /* CURSES */
X
/*
X * Get just the month, day, and year from a date.
X * This is a temporary measure until the date compares in pick()
X * can be overhauled.  It really should be in dates.c, but ...
X */
static
void
month_day_year(date, month, day, year)
char *date;
int *month, *day, *year;
{
X    long gmt;
X    char unused[4], zone[8];
X    struct tm *t;
X    extern long getzoff();
X
X    (void) sscanf(date, "%ld%3c%s", &gmt, unused, zone);
X    gmt += getzoff(zone);
X    t = gmtime(&gmt);
X    *month = t->tm_mon;
X    *day = t->tm_mday;
X    *year = t->tm_year;
}
X
/*
X * parse a user given date string and set mdy[] array with correct
X * values.  Return 0 on failure.
X */
date1(p)
register char *p;
{
X    register char *p2;
X    long	  t;
X    int 	  i;
X    struct tm 	  *today;
X
X    if (*p == '-' || *p == '+') {
X	before = !(after = *p == '+');
X	skipspaces(1);
X    }
X    if (!isdigit(*p) && *p != '/') {
X	print("syntax error on date: \"%s\"\n", p);
X	return 0;
X    }
X    (void) time (&t);
X    today = localtime(&t);
X    for (i = 0; i < 3; i++)
X	if (!p || !*p || *p == '/') {
X	    switch(i) {   /* default to today's date */
X		case 0: mdy[0] = today->tm_mon;
X		when 1: mdy[1] = today->tm_mday;
X		when 2: mdy[2] = today->tm_year;
X	    }
X	    if (p && *p)
X		p++;
X	} else {
X	    p2 = (*p)? index(p+1, '/') : NULL;
X	    mdy[i] = atoi(p); /* atoi will stop at the '/' */
X	    if (i == 0 && (--(mdy[0]) < 0 || mdy[0] > 11)) {
X		print("Invalid month: %s\n", p);
X		return 0;
X	    } else if (i == 1 && (mdy[1] < 1 || mdy[1] > 31)) {
X		print("Invalid day: %s\n", p);
X		return 0;
X	    }
X	    if (p = p2) /* set p to p2 and check to see if it's valid */
X		p++;
X	}
X    return 1;
}
X
/*
X * Parse arguments specifying days/months/years "ago" (relative to today).
X * Legal syntax: -ago [+-][args]
X *    where "args" is defined to be:
X *    [0-9]+[ ]*[dD][a-Z]*[ ,]*[0-9]+[mM][a-Z]*[ ,]*[0-9]+[ ]*[yY][a-Z]*
X *    1 or more digits, 0 or more spaces, d or D followed by 0 or more chars,
X *    0 or more whitespaces or commas, repeat for months and years...
X * Examples:
X *    1 day, 2 months, 0 years
X *    2 weeks 1 year
X *    10d, 5m
X *    3w
SHAR_EOF
true || echo 'restore of pick.c failed'
fi
echo 'End of  part 19'
echo 'File pick.c is continued in part 20'
echo 20 > _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.