[comp.sources.misc] v14i005: Submission: Patch #2 for Mush 7.1

schaefer@cse.ogi.edu (Barton E. Schaefer) (07/16/90)

Posting-number: Volume 14, Issue 5
Submitted-by: schaefer@cse.ogi.edu (Barton E. Schaefer)
Archive-name: mush/patch01

Mush was posted to comp.sources.misc at patchlevel 1.  You can omit
everything up through the @OFF line when posting this; that line is
a directive to my mail server to prevent it from recognizing the
later @-directives should this bounce back to me.

@OFF

This is Official Patch #2 for Mush 7.1.  Mush was previously posted
to comp.sources.misc at patch level 1.  A copy of this message has
been sent to the comp.sources.misc moderator for posting and archiving.

As usual, complete sources for Mush (already including the changes in
this patch) can be obtained via anonymous ftp from either of:

            ucbvax.berkeley.edu:pub/mailers/mush-7.1.tar.Z

                  cse.ogi.edu:pub/mush/mush-7.1.tar.Z

Be aware that a version of mush with RELEASE_DATE (from version.h) of
7/10/90 was incorrectly made available for ftp for approximately 24
hours spanning the night of July 10th and most of the day July 11th.
The correct RELEASE_DATE is 7/11/90.  If you have the 7/10 version,
please pick up the more recent one.  The only change was to enable
walking menus by default (see below); the functionality is the same.
This affects Sun systems only, but for purposes of patching you should
obtain the correct version.

If you need any earlier patches, they are available for ftp from
cse.ogi.edu, or you can send E-mail to me:

                         schaefer@cse.ogi.edu
     {decwrl,garp,harvard,rutgers,sdsu,ucsd,unmvax}!ogicse!schaefer

Include in your message a line of the form

@PATCH patch-number path-from-ogicse-to-you

where patch-number is the number of the patch you need (digit, 1 or 2)
and path-from-ogicse-to-you is either your Internet domain address or
a UUCP path from site ogicse to you at your site.  There continue to
be sendmail configuration problems at ogicse so please do not use mixed
UUCP and Internet addresses and do not use domain names (with `.'s) in
UUCP paths.  Ogicse does do UUCP map lookups now, so user@site.UUCP will
often work if your site is registered.  If you don't get your patches
in 2 or 3 days, try again, but use a different path.

You may include one @PATCH line for each patch you need.

You can also recieve a complete set of sources by E-mail by including
a line of the form

@MUSH path-from-ogicse-to-you

where path-from-ogicse-to-you is as above.  You need not request both
source and patches; the source you receive will include all current
patches.  Sources are shipped as a 9-part compressed tar file, encoded
for mailing with the "btoa" utility.  You will receive instructions
explaining how to unpack the tar file in a separate message.

CSNet also operates an E-mail server that accesses anonymous ftp.  It
may or may not be functional at this time.  To find out, and to get
instructions for using the server, send a message to info-server@cs.net
with the following lines in the text:

request: info
topic: help-ftp
request: end

Other information, plus questions and answers, on mush and mush patches
is available from the mush-users mailing list, which is gatewayed in
both directions with newsgroup comp.mail.mush.  The list currently
resides at mush-users@garp.mit.edu, but may in the near future be moving
to mush-users@apple.com.  Requests to be added to or deleted from the
list should be sent to mush-users-request@garp.mit.edu, for now.

Changes/Fixes in this patch:

    The "undelete" operation in the Mailrc configuration file for UCB
    Mail emulation has been adjusted to change the current message to
    the last message in the undeleted list.  This causes one message
    header summary to be printed whenever "undelete" is used.

    The "delete" operation in tool mode will now bring the new current
    message onto the header display if and only if it was changed by
    the deletion.

    Failure to truncate and recreate the editor temp file (e.g. by ~E)
    is now detected and handled properly.

    Handling of "corrupted" spool mailboxes has been improved.  The
    size of the spool file is now correctly recorded on new mail checks,
    which should reduce the frequency of corruption reports on systems
    that rely on DOT_LOCKing.  See also the locking corrections for MMDF,
    noted below.  Once possible corruption is detected, new mail is no
    longer checked, and upon quit or any folder change operation the
    user is warned of the error.  If mush exits with the folder still
    in a corrupt state, no update is done and the temporary copy is not
    removed.  Further improvements in this error handling are planned
    for future patches.

    SYSV systems that support BSD-style directory functions will now
    correctly #include <dirent.h> if DIRECTORY is defined.

    Addresses containing UUCP !-paths ending in a domain-style @host
    suffix will now be shifted to the right in header summaries to show 
    as at least the last two hosts of the UUCP path tail.  This assumes
    that the correct parsing of host2!host3!user@host1 is the same as
    host1!host2!host3!user.

    Use of the file locking routines from the MMDF libraries has been
    fixed.  Previous usage assumed that the MMDF routines locked in a
    blocking manner, waiting until the lock was obtained; this is not
    correct, and mush now loops until the lock is obtained.

    The "history" command now includes itself in the listing of the
    last N history items when invoked with a numeric argument.  E.g.,
    "history 5" will now show "history 5" as the most recent of the
    five commands displayed.  This is consistent with "history -r 5"
    and the csh usage.

    $verify is now treated as a multivalued variable.  In addition to
    the old usage of verifying send/edit/discard on outgoing mail, it
    is now necessary to "set verify=save" to enable the toolmode query
    boxes that confirm save operations.  The other valid settings are
    "mail" and no value, both of which behave as $verify did before.
    To verify both outgoing mail and tool mode save operations, use
    "set verify=mail,save".

    Stray alarm timers could be triggered by use of the "await" command
    under SysV, resulting in core dumps.  This has been corrected.

    For SunView users, walking menus are now used for the file names
    displayed under the <Folder> and <Save> items.  This neatens up
    display of nested directory structures and avoids the menu size
    limits of SunView in most cases.  Thanks to J. William Claypool
    <unify!jwc@Sun.COM> for contributing 99% of this.  If you run into
    any problems with this, compilation with -DNO_WALK_MENUS will
    revert to the previous menu format.

*** /tmp/,RCSt1002753	Wed Jul 11 21:30:33 1990
--- Mailrc	Wed Jul  4 15:36:14 1990
***************
*** 52,59 ****
  cmd se set
  cmd shell sh
  cmd so source
! cmd un undelete
! cmd unread 'flags \!* U'	# "unread" is undocumented in Mail
  cmd uns unset
  cmd vi v
  cmd z 'z \!* + | from -'	# "z" changes current message in Mail
--- 52,61 ----
  cmd se set
  cmd shell sh
  cmd so source
! cmd u 'u \!* | pick -1 | from -' # "u" changes current message in Mail
! cmd un u
! cmd undelete u
! cmd unread 'flags \!* +U'	# "unread" is undocumented in Mail
  cmd uns unset
  cmd vi v
  cmd z 'z \!* + | from -'	# "z" changes current message in Mail
*** /tmp/,RCSt1002753	Wed Jul 11 21:32:30 1990
--- README	Wed Jul 11 21:32:23 1990
***************
*** 81,86 ****
--- 81,89 ----
      SUN_4_0, or SUN_4_1 depending on your SunOS version.  If SUNTOOL is
      the only thing defined, SUN_4_0 will be used.
  
+     You may also choose to define NO_WALK_MENUS to disable walking menus
+     for file names selectable from the "folder" and "save" command items.
+ 
  If you are on a BSD UNIX machine:
  
      You should use the makefile.bsd makefile.
*** /tmp/,RCSt1002753	Wed Jul 11 21:32:39 1990
--- commands.c	Wed Jul 11 21:26:46 1990
***************
*** 440,447 ****
--- 440,451 ----
  	if (firstchar != 'c' && n > 0)
  	    (void) do_hdrs(0, DUBL_NULL, NULL);
  	if (*mode == 'w' && n > 0) {
+ #ifndef NO_WALK_MENUS
+ 	    create_folder_menus();
+ #else /* NO_WALK_MENUS */
  	    add_folder_to_menu(folder_item, 3);
  	    add_folder_to_menu(save_item, 1);
+ #endif /* NO_WALK_MENUS */
  	}
      }
  #endif /* SUNTOOL */
***************
*** 615,623 ****
      /* goto next available message if current was just deleted.
       * If there are no more messages, turnoff prnt_next.
       */
!     if (!iscurses && !undel && msg_bit(list, current_msg) &&
! 	    (ison(msg[current_msg].m_flags, DELETE) ||
! 	    ison(msg[current_msg].m_flags, SAVED)))
  	(void) next_msg();
      else
  	prnt_next = 0;
--- 619,625 ----
      /* goto next available message if current was just deleted.
       * If there are no more messages, turnoff prnt_next.
       */
!     if (!iscurses && !undel && msg_bit(list, current_msg))
  	(void) next_msg();
      else
  	prnt_next = 0;
***************
*** 632,643 ****
  	}
  #ifdef SUNTOOL
      if (istool && isoff(glob_flags, IS_PIPE)) {
! 	char *av[3], buf[8];
! 	/* do_hdrs(0, ...) repositions the display, so pass an arg */
! 	av[0] = "h";
! 	av[1] = sprintf(buf, "%d", n_array[0] + 1);
! 	av[2] = NULL;
! 	(void) do_hdrs(2, av, NULL);
      }
  #endif /* SUNTOOL */
      return 0;
--- 634,649 ----
  	}
  #ifdef SUNTOOL
      if (istool && isoff(glob_flags, IS_PIPE)) {
! 	if (current_msg != old_msg && !do_set(set_options, "show_deleted"))
! 	    (void) do_hdrs(0, DUBL_NULL, NULL);
! 	else {
! 	    char *av[3], buf[8];
! 	    /* do_hdrs(0, ...) repositions the display, so pass an arg */
! 	    av[0] = "h";
! 	    av[1] = sprintf(buf, "%d", n_array[0] + 1);
! 	    av[2] = NULL;
! 	    (void) do_hdrs(2, av, NULL);
! 	}
      }
  #endif /* SUNTOOL */
      return 0;
*** /tmp/,RCSt1002753	Wed Jul 11 21:32:40 1990
--- config.h-dist	Tue Jul 10 08:34:56 1990
***************
*** 85,93 ****
  /* If your mailer does not understand commas between addresses, you should
   * define NO_COMMAS.  This includes pre-3.0 smail and default MTAs used on
   * xenix, and sys-v systems.
!  * This does NOT apply to MMDF or sendmail.
   */
! /* #define NO_COMMAS /**/
  
  /*
   * Most RFC822 compliant mailers (sendmail) will add the headers From:
--- 85,95 ----
  /* If your mailer does not understand commas between addresses, you should
   * define NO_COMMAS.  This includes pre-3.0 smail and default MTAs used on
   * xenix, and sys-v systems.
!  * This does NOT apply to MMDF or sendmail, in most cases.
   */
! #ifdef SUN_4_1		/* SunOS 4.1 has warped sendmail.cf */
! #define NO_COMMAS /**/
! #endif /* SUN_4_1
  
  /*
   * Most RFC822 compliant mailers (sendmail) will add the headers From:
*** /tmp/,RCSt1002753	Wed Jul 11 21:32:46 1990
--- file.c	Thu May  3 12:44:05 1990
***************
*** 217,223 ****
  	(void) fclose(*fp);
  	if (!(*fp = fopen(fname, "w")))
  	    ret = -1;
! 	ret = 0;
  	(void) umask(omask);
  	return ret;
      }
--- 217,224 ----
  	(void) fclose(*fp);
  	if (!(*fp = fopen(fname, "w")))
  	    ret = -1;
! 	else
! 	    ret = 0;
  	(void) umask(omask);
  	return ret;
      }
*** /tmp/,RCSt1002753	Wed Jul 11 21:32:47 1990
--- folders.c	Wed Jul  4 16:54:04 1990
***************
*** 125,130 ****
--- 125,131 ----
  	/* an error occured updating the folder */
  	return -1;
      }
+     turnoff(glob_flags, CORRUPTED);	/* copyback() was successful */
      /* Assure that both oldfolder and mailfile are full paths */
      if (strcmp(mailfile, buf) || !*oldfolder) {
  	n = 1; /* force load of new folder */
*** /tmp/,RCSt1002753	Wed Jul 11 21:32:49 1990
--- glob.h	Wed May 23 19:58:51 1990
***************
*** 3,10 ****
--- 3,14 ----
  #endif /* BSD */
  
  #ifdef DIRECTORY
+ #ifdef SYSV /* Some SysV 3.0 or higher */
+ #include <dirent.h>
+ #else /* SYSV */
  #include <sys/dir.h>
  #define dirent direct
+ #endif
  #else /* !DIRECTORY */
  
  /*
*** /tmp/,RCSt1002753	Wed Jul 11 21:32:50 1990
--- hdrs.c	Thu Jul  5 09:22:07 1990
***************
*** 529,537 ****
  		 * "important" part is readable only for ! paths/addresses.
  		 */
  		while (p3 = index(p2, '!')) {
! 		    int tmp = strlen(p3+1); /* xenix has compiler problems */
  		    p2 = p3+1;
! 		    if (tmp + isauthor*4 < pad) {
  			if (isauthor && (p2 -= 4) < old_p2)
  			    p2 = old_p2;
  			break;
--- 529,537 ----
  		 * "important" part is readable only for ! paths/addresses.
  		 */
  		while (p3 = index(p2, '!')) {
! 		    len = strlen(p3+1); /* xenix has compiler problems */
  		    p2 = p3+1;
! 		    if (len + isauthor*4 < pad) {
  			if (isauthor && (p2 -= 4) < old_p2)
  			    p2 = old_p2;
  			break;
***************
*** 539,544 ****
--- 539,551 ----
  		}
  		if (isauthor && p2 > old_p2+4 && !p3 && strlen(p2) + 4 > pad)
  		    p2 -= 4;
+ 		if (p3 && (p3 = rindex(p2, '@'))) {
+ 		    len = strlen(p3);
+ 		    while (len-- && --p2 > old_p2) {
+ 			if (*(p2 + isauthor*4 - 1) == '!')
+ 			    break;
+ 		    }
+ 		}
  		if (old_p2 != p2 && isauthor)
  		    (void) strncpy(p2, "TO: ", 4); /* doesn't null terminate */
  	    }
*** /tmp/,RCSt1002753	Wed Jul 11 21:32:53 1990
--- lock.c	Tue Jun 19 13:19:03 1990
***************
*** 123,133 ****
  char *mode;
  {
      FILE *mail_fp = NULL_FILE;
- #ifndef LCKDFLDIR
      int fd, lk;
      int cnt = 0;
      SIGRET (*oldint)(), (*oldquit)();
! #else /* LCKDFLDIR */
      extern FILE *lk_fopen();
  #endif /* !LCKDFLDIR */
  
--- 123,132 ----
  char *mode;
  {
      FILE *mail_fp = NULL_FILE;
      int fd, lk;
      int cnt = 0;
      SIGRET (*oldint)(), (*oldquit)();
! #ifdef LCKDFLDIR
      extern FILE *lk_fopen();
  #endif /* !LCKDFLDIR */
  
***************
*** 136,145 ****
  	return NULL_FILE;
      }
  
- #ifdef LCKDFLDIR
-     return lk_fopen(filename, mode, NULL, NULL, 0);
- #else /* !LCKDFLDIR */
- 
  #ifdef DOT_LOCK
      if (dot_lock(filename) == 0)
  #endif /* DOT_LOCK */
--- 135,140 ----
***************
*** 154,161 ****
  	lk = LOCK_SH | LOCK_NB;
  
      on_intr();
!     while (isoff(glob_flags, WAS_INTR) && flock(fd, lk)) {
! 	if (errno == EWOULDBLOCK) {
  	    if (isoff(glob_flags, REDIRECT))
  		if (!cnt++)
  		    print("\nwaiting to lock");
--- 149,168 ----
  	lk = LOCK_SH | LOCK_NB;
  
      on_intr();
! #ifdef LCKDFLDIR
!     (void) fclose(mail_fp);
!     while (isoff(glob_flags, WAS_INTR) &&
! 	    !(mail_fp = lk_fopen(filename, mode, NULL, NULL, 0)))
! #else /* !LCKDFLDIR */
!     while (isoff(glob_flags, WAS_INTR) && flock(fd, lk))
! #endif /* LCKDFLDIR */
!     {
! #ifdef LCKDFLDIR
! 	if (Access(filename, any(mode, "aw+") ? W_OK : R_OK) == 0)
! #else /* !LCKDFLDIR */
! 	if (errno == EWOULDBLOCK)
! #endif /* LCKDFLDIR */
! 	{
  	    if (isoff(glob_flags, REDIRECT))
  		if (!cnt++)
  		    print("\nwaiting to lock");
***************
*** 179,185 ****
  	return NULL_FILE;
      }
      return mail_fp;
- #endif /* LCKDFLDIR */
  }
  
  /*ARGSUSED*/
--- 186,191 ----
*** /tmp/,RCSt1002753	Wed Jul 11 21:32:54 1990
--- loop.c	Wed Jul  4 15:39:39 1990
***************
*** 1280,1287 ****
  	num_of_hists = min(hist_size, hist_no);
  
      if (!reverse)
! 	while (hist_no - hist->histno > num_of_hists) {
! 	    (void) printf("skipping %d\n", hist->histno);
  	    hist = hist->next;
  	}
  
--- 1280,1287 ----
  	num_of_hists = min(hist_size, hist_no);
  
      if (!reverse)
! 	while (hist_no - hist->histno >= num_of_hists) {
! 	    Debug("skipping %d\n", hist->histno);
  	    hist = hist->next;
  	}
  
*** /tmp/,RCSt1002753	Wed Jul 11 21:32:57 1990
--- mail.c	Wed Jul  4 15:28:00 1990
***************
*** 899,907 ****
  	    }
  	    if (*p != '!' && !do_set(set_options, "nosave"))
  		dead_letter(0);
! 	    if (emptyfile(&ed_fp, edfile) == -1)
  		error(edfile);
! 	    else
  		print("Message buffer empty\n");
  	when 'q':
  	    /* save in dead.letter if nosave not set -- rm_edfile(-2). */
--- 899,908 ----
  	    }
  	    if (*p != '!' && !do_set(set_options, "nosave"))
  		dead_letter(0);
! 	    if (emptyfile(&ed_fp, edfile) == -1) {
  		error(edfile);
! 		return -1;
! 	    } else
  		print("Message buffer empty\n");
  	when 'q':
  	    /* save in dead.letter if nosave not set -- rm_edfile(-2). */
***************
*** 982,988 ****
  	}
  	/* ~v on the Cc line asks for verification, first initialize p! */
  	p = NULL;
! 	if (!strncmp(Cc, "~v", 2) || (p = do_set(set_options, "verify"))) {
  	    if (!p) /* so we don't Cc to ~v! */
  		*Cc = 0;
  	    for (;;) {
--- 983,992 ----
  	}
  	/* ~v on the Cc line asks for verification, first initialize p! */
  	p = NULL;
! 	if (!strncmp(Cc, "~v", 2) ||
! 		/* Flashy test for $verify either empty or set to "mail" */
! 		glob(p = do_set(set_options, "verify"),
! 					    "{,{,*[ \\,]}mail{,[ \\,]*}}")) {
  	    if (!p) /* so we don't Cc to ~v! */
  		*Cc = 0;
  	    for (;;) {
***************
*** 1504,1510 ****
       * created a From: header with the my_hdr command (the own_hdrs list).
       * If his is not legitimate, warn user and use the other header.
       */
!     if ((for_editor || isoff(glob_flags, EDIT_HDRS)) &&
  	    own_hdrs && !do_set(set_options, "no_hdrs")) {
  	for (opts = own_hdrs; opts; opts = opts->next)
  	    if (!strcmp(opts->option, "From:")) {
--- 1508,1514 ----
       * created a From: header with the my_hdr command (the own_hdrs list).
       * If his is not legitimate, warn user and use the other header.
       */
!     if ((for_editor || isoff(flags, EDIT_HDRS)) &&
  	    own_hdrs && !do_set(set_options, "no_hdrs")) {
  	for (opts = own_hdrs; opts; opts = opts->next)
  	    if (!strcmp(opts->option, "From:")) {
*** /tmp/,RCSt1002753	Wed Jul 11 21:33:00 1990
--- main.c	Wed Jul  4 07:23:41 1990
***************
*** 40,49 ****
  #ifdef LCKDFLDIR
      lckdfldir = LCKDFLDIR;
  #endif /* LCKDFLDIR */
!     if (prog_name = rindex(*argv, '/'))
! 	prog_name++;
!     else
! 	prog_name = *argv;
  
      (void) signal(SIGBUS,  bus_n_seg);
      (void) signal(SIGSEGV, bus_n_seg);
--- 40,46 ----
  #ifdef LCKDFLDIR
      lckdfldir = LCKDFLDIR;
  #endif /* LCKDFLDIR */
!     prog_name = basename(*argv);
  
      (void) signal(SIGBUS,  bus_n_seg);
      (void) signal(SIGSEGV, bus_n_seg);
*** /tmp/,RCSt1002753	Wed Jul 11 21:33:06 1990
--- msgs.c	Wed Jul  4 17:07:44 1990
***************
*** 270,277 ****
       */
      if (!first && mail_size()) {
  lost_lock:
! 	if (get_new_mail(TRUE) && prompt && isoff(glob_flags, REDIRECT)
! 		&& show_new_mail()) {
  	    char buf[80];
  	    if (iscurses)
  		putchar('\n'), turnon(glob_flags, CNTD_CMD);
--- 270,277 ----
       */
      if (!first && mail_size()) {
  lost_lock:
! 	if ((ison(glob_flags, CORRUPTED) || get_new_mail(TRUE)) &&
! 		prompt && isoff(glob_flags, REDIRECT) && show_new_mail()) {
  	    char buf[80];
  	    if (iscurses)
  		putchar('\n'), turnon(glob_flags, CNTD_CMD);
***************
*** 280,286 ****
  	    buf[0] = 0;
  #ifdef SUNTOOL
  	    if (istool) {
! 		(void) sprintf(buf, "New mail -- %s", prompt);
  		if (ask(buf) != TRUE)
  		    return 0;
  	    } else
--- 280,288 ----
  	    buf[0] = 0;
  #ifdef SUNTOOL
  	    if (istool) {
! 		(void) sprintf(buf, "%s -- %s",
! 			ison(glob_flags, CORRUPTED) ? "Error" : "New mail",
! 			prompt);
  		if (ask(buf) != TRUE)
  		    return 0;
  	    } else
***************
*** 287,298 ****
  #endif /* SUNTOOL */
  		if (!Getstr(buf, sizeof (buf), 0) || lower(*buf) != 'y')
  		    return 0;
  	}
      }
      first = 0;
  
      /* If the user hasn't changed anything, just return true */
!     if (isoff(glob_flags, DO_UPDATE))
  	return 1;
      if (ison(glob_flags, READ_ONLY)) {
  	print("Unable to update %s: read only\n", mailfile);
--- 289,301 ----
  #endif /* SUNTOOL */
  		if (!Getstr(buf, sizeof (buf), 0) || lower(*buf) != 'y')
  		    return 0;
+ 	    turnoff(glob_flags, CORRUPTED); /* User says go ahead */
  	}
      }
      first = 0;
  
      /* If the user hasn't changed anything, just return true */
!     if (isoff(glob_flags, DO_UPDATE) || ison(glob_flags, CORRUPTED))
  	return 1;
      if (ison(glob_flags, READ_ONLY)) {
  	print("Unable to update %s: read only\n", mailfile);
***************
*** 316,323 ****
      if (!(mail_fp = lock_fopen(mailfile, "r+"))) {
  	error("WARNING: unable to lock %s -- update aborted", mailfile);
  #ifdef SUNTOOL
! 	write_err = 1;	/* forces return 0; below */
! 	goto resume_timer;	/* blecch */
  #else /* !SUNTOOL */
  	return 0;
  #endif /* SUNTOOL */
--- 319,328 ----
      if (!(mail_fp = lock_fopen(mailfile, "r+"))) {
  	error("WARNING: unable to lock %s -- update aborted", mailfile);
  #ifdef SUNTOOL
! 	if (istool) {
! 	    write_err = 1;	/* forces return 0; below */
! 	    goto resume_timer;	/* blecch */
! 	}
  #else /* !SUNTOOL */
  	return 0;
  #endif /* SUNTOOL */
*** /tmp/,RCSt1002753	Wed Jul 11 21:33:10 1990
--- mush.1	Wed Jul  4 07:47:47 1990
***************
*** 2937,2944 ****
  searches for special mail headers in the author's message that
  indicate the most efficient mail path for return mail.
  .I Mush
! will search for the \*QReply-To:\*U, \*QReturn-Path:\*U,
! and \*QFrom:\*U headers, in that order, by default.
  .sp
  If none of these fields are found in the message, the first line of the
  message is parsed if possible;
--- 2937,2944 ----
  searches for special mail headers in the author's message that
  indicate the most efficient mail path for return mail.
  .I Mush
! will search for the \*QReply-To:\*U,
! \*QFrom:\*U, and \*QReturn-Path:\*U headers, in that order, by default.
  .sp
  If none of these fields are found in the message, the first line of the
  message is parsed if possible;
***************
*** 4291,4296 ****
--- 4291,4297 ----
  If set to a string, that string is executed as a command when a
  carriage return is typed.
  Otherwise, carriage return prints the next undeleted message.
+ .TP
  .B newmail_icon
  (String)
  Set to a pathname for an alternate icon pixmap to use
***************
*** 4578,4584 ****
  When replying to mail,
  .I Mush
  searches for return paths from the message by searching for
! the message headings \*QReply-to\*U, \*QReturn-path\*U, and \*QFrom:\*U,
  in that order.
  If none are found, then the first line of the
  message created by the delivery system is parsed and the address
--- 4579,4585 ----
  When replying to mail,
  .I Mush
  searches for return paths from the message by searching for
! the message headings \*QReply-to\*U, \*QFrom:\*U, and \*QReturn-path\*U,
  in that order.
  If none are found, then the first line of the
  message created by the delivery system is parsed and the address
***************
*** 4778,4788 ****
  to print additional information about the sending process.
  .TP
  .B verify
! (Boolean)
! When through editing messages, just before sending,
  .B verify
! will ask you if you want to send, continue editing, or abort the
! whole message altogether.
  .TP
  .B version
  (Read-only String)
--- 4779,4805 ----
  to print additional information about the sending process.
  .TP
  .B verify
! (Boolean/Multivalued)
! This variable causes mush to request confirmation of certain actions.
! If set only as a boolean (no string value), 
  .B verify
! will ask just before sending mail whether you want to send, continue
! editing, or abort the message altogether.
! Otherwise,
! .B verify
! can be set to one or more of these words:
! .sp
! .nf
! .ta 1.5i
! .in +4
! .\" \& escapes are to make obvious the tab after each word
! mail\&\&	Confirm sending of mail (as above).
! save\&\&	Confirm save-item selections (tool only).
! .in -4
! .fi
! .sp
! Appending of messages to files that are not folders is verified regardless
! of the setting of this variable.
  .TP
  .B version
  (Read-only String)
*** /tmp/,RCSt1002753	Wed Jul 11 21:33:19 1990
--- mush.h	Wed Jul  4 16:36:00 1990
***************
*** 379,384 ****
--- 379,385 ----
  #define QUOTE_MACRO ULBIT(23) /* protect current macro from recursive expan.. */
  #define NEW_FRAME   ULBIT(24) /* toolmode should build a new frame for pager */
  #define HELP_TEXT   ULBIT(25) /* create textsw frame for paging help messages */
+ #define CORRUPTED   ULBIT(26) /* error loading new mail has occurred */
  
  /* flags to control composition */
  #define VERBOSE		ULBIT(0)  /* verbose flag for sendmail */
*** /tmp/,RCSt1002753	Wed Jul 11 21:33:25 1990
--- signals.c	Tue Jul 10 08:38:54 1990
***************
*** 74,79 ****
--- 74,86 ----
  		wrapcolumn = atoi(fix);
  	}
  	turnoff(glob_flags, IS_GETTING);
+ #ifdef SYSV
+ 	/* Interrupting "await" leaves an alarm timer running, which
+ 	 * some SysV systems mishandle.  Clean up.
+ 	 */
+ 	if (!istool)
+ 	    (void) signal(SIGALRM, SIG_IGN);
+ #endif /* SYSV */
  	longjmp(jmpbuf, 1);
      } else
  	puts("exiting"), cleanup(sig);
***************
*** 176,182 ****
  	    c = lower(*buf);
      }
      if (c != 'n' && *tempfile) {
! 	if (sig == SIGHUP && do_set(set_options, "hangup") && copyback(NULL))
  	    (void) unlink(tempfile);
  	else if (unlink(tempfile) && !sig && errno != ENOENT)
  	    error(tempfile);
--- 183,190 ----
  	    c = lower(*buf);
      }
      if (c != 'n' && *tempfile) {
! 	if (sig == SIGHUP && do_set(set_options, "hangup") &&
! 		copyback(NULL) && isoff(glob_flags, CORRUPTED))
  	    (void) unlink(tempfile);
  	else if (unlink(tempfile) && !sig && errno != ENOENT)
  	    error(tempfile);
***************
*** 229,238 ****
  	if (isoff(glob_flags, READ_ONLY))
  	    (void) emptyfile(&tmpf, tempfile);
  	current_msg = msg_cnt = 0;
      }
      if (load_folder(mailfile, 1, NULL) < 1) {
  	print("Can't load new mail: \"%s\" may be corrupted!\n", mailfile);
! 	turnon(glob_flags, DO_UPDATE);	/* Don't reload without rewrite */
  	return update_size;
  	/* NOTE: The above is used to stop check_new_mail() from calling
  	 * show_new_mail(), while still allowing copyback() to detect the
--- 237,249 ----
  	if (isoff(glob_flags, READ_ONLY))
  	    (void) emptyfile(&tmpf, tempfile);
  	current_msg = msg_cnt = 0;
+ 	turnoff(glob_flags, CORRUPTED);
      }
+     if (ison(glob_flags, CORRUPTED))
+ 	return 0;
      if (load_folder(mailfile, 1, NULL) < 1) {
  	print("Can't load new mail: \"%s\" may be corrupted!\n", mailfile);
! 	turnon(glob_flags, CORRUPTED);
  	return update_size;
  	/* NOTE: The above is used to stop check_new_mail() from calling
  	 * show_new_mail(), while still allowing copyback() to detect the
***************
*** 240,245 ****
--- 251,260 ----
  	 * should be a better-defined way to handle this.
  	 */
      }
+     /* Prevent both bogus "new mail" messages and missed new mail */
+     last_size = msg[msg_cnt].m_offset;
+     if (!strcmp(mailfile, spoolfile))
+ 	spool_size = last_size;
      if (last_spool_size != spool_size) {
  	if (update_size)
  	    last_spool_size = spool_size;
*** /tmp/,RCSt1002753	Wed Jul 11 21:33:27 1990
--- strings.c	Wed Jul  4 07:26:33 1990
***************
*** 442,444 ****
--- 442,458 ----
      *s_out = 0;
      return start;
  }
+ 
+ /*
+  * This routine returns a pointer to the file portion of a path/file name.
+  */
+ char *
+ basename(path)
+ register char *path;
+ {
+     char *file;
+ 
+     if (file = rindex(path, '/'))
+ 	return ++file;
+     return path;
+ }
*** /tmp/,RCSt1002753	Wed Jul 11 21:33:28 1990
--- strings.h	Wed Jul  4 15:51:50 1990
***************
*** 21,26 ****
--- 21,27 ----
      *Sprintf(),		/* See comments above function in strings.c */
      *argv_to_string(),	/* convert a vector of strings into one string */
      *any(), 		/* return first char in str2 that exists in str1 */
+     *basename(),	/* return the last component of a file path */
      *ctrl_strcpy(),	/* string copy converting control chars to ascii */
      *itoa(),		/* return a string representation of a number */
      *lcase_strcpy(),	/* just like strcpy, but convert all chars to lower */
*** /tmp/,RCSt1002753	Wed Jul 11 21:33:29 1990
--- version.h	Wed Jul 11 21:30:09 1990
***************
*** 1,7 ****
  /* @(#)version.h	(c) Copyright 1989 (Dan Heller) */
  
  #define MUSHNAME	"Mail User's Shell"
! #define RELEASE_DATE	"5/02/90"
  #define RELEASE		7
  #define REVISION	"1"
! #define PATCHLEVEL	1
--- 1,7 ----
  /* @(#)version.h	(c) Copyright 1989 (Dan Heller) */
  
  #define MUSHNAME	"Mail User's Shell"
! #define RELEASE_DATE	"7/11/90"
  #define RELEASE		7
  #define REVISION	"1"
! #define PATCHLEVEL	2
*** /tmp/,RCSt1002753	Wed Jul 11 21:33:29 1990
--- viewopts.c	Wed Jul  4 07:39:03 1990
***************
*** 184,190 ****
      { "unix", NULL,
  	"Non-mush commands are considered to be UNIX commands." },
      { "verify", NULL,
! 	"Verify to send, re-edit, or abort letter after editing." },
      { "visual", "Visual editor:",
  	"Visual editor for messages (default = $editor or env VISUAL)."},
      { "warning", NULL,
--- 184,190 ----
      { "unix", NULL,
  	"Non-mush commands are considered to be UNIX commands." },
      { "verify", NULL,
! 	"Verify before acting in various situations, such as sending mail." },
      { "visual", "Visual editor:",
  	"Visual editor for messages (default = $editor or env VISUAL)."},
      { "warning", NULL,
*** /tmp/,RCSt1002926	Wed Jul 11 21:33:32 1990
--- doproc.c	Wed Jul 11 21:26:46 1990
***************
*** 139,148 ****
  	if (!(p = panel_get_value(item)) || !*p &&
  	    (!(p = do_set(set_options, "mbox")) || !*p))
  		p = DEF_MBOX;
! 	(void) sprintf(msgstr, "%s in \"%s\"?", buf, trim_filename(p));
! 	if (ask(msgstr) != TRUE) {
! 	    wprint("Message not saved\n");
! 	    return PANEL_NONE;
  	}
  	(void) strcpy(b, p); /* now add to command */
      }
--- 139,150 ----
  	if (!(p = panel_get_value(item)) || !*p &&
  	    (!(p = do_set(set_options, "mbox")) || !*p))
  		p = DEF_MBOX;
! 	if (chk_option("verify", "save")) {
! 	    (void) sprintf(msgstr, "%s in \"%s\"?", buf, trim_filename(p));
! 	    if (ask(msgstr) != TRUE) {
! 		wprint("Message not saved\n");
! 		return PANEL_NONE;
! 	    }
  	}
  	(void) strcpy(b, p); /* now add to command */
      }
***************
*** 153,163 ****
--- 155,231 ----
      return PANEL_NONE;
  }
  
+ #ifndef NO_WALK_MENUS
+ void
+ xx_file_dir(item, value)
+ Panel_item item;
+ char * value;
+ {
+     char buf[BUFSIZ];
+     u_long bang = ison(glob_flags, IGN_BANG);
+ 
+     if (item == folder_item) {
+ 	(void) sprintf(buf, "folder %s ",
+ 	    (ison(glob_flags, READ_ONLY) || ison(glob_flags, DO_UPDATE) &&
+ 	    !ask("Folder has been modified.  Update changes?"))? "!" : "");
+ 	strcat(buf, value);
+     } else if (item == save_item) {
+ 	char msgstr[BUFSIZ], *p;
+ 	register char *p2 = (char *)panel_get_value(msg_num_item);
+ 	(void) strcpy(buf, "save ");
+ 
+ 	if (p2 && *p2) {
+ 	    (void) strcat(buf, p2);
+ 	    (void) strcat(buf, " ");
+ 	}
+ 	(void) strcat(buf, value);
+ 	if (chk_option("verify", "save")) {
+ 	    (void) sprintf(msgstr, "Save in %s? ", trim_filename(value));
+ 	    if (ask(msgstr) != TRUE) {
+ 		wprint("Message not saved\n");
+ 		return;
+ 	    }
+ 	}
+     }
+     turnon(glob_flags, IGN_BANG);
+     (void) cmd_line(buf, msg_list);
+     if (!bang)
+ 	turnoff(glob_flags, IGN_BANG);
+     (void) panel_set(item, PANEL_VALUE, 0, NULL); /* remove last value */
+ }
+ 
  /*
   * callback routine for the panel items that need filename input.
   * (folder and save)
   */
  void
+ do_file_dir(item, event)
+ Panel_item item;
+ Event *event;
+ {
+     if (item == folder_item) {
+ 	char *p = panel_get_value(folder_text_item);
+ 	if (!*p) {
+ 	    ok_box("Enter folder name.");
+ 	    return;
+ 	}
+ 	xx_file_dir(item, p);
+     } else if (item == save_item) {
+ 	if (!strcmp("Filename:", panel_get(file_item,PANEL_LABEL_STRING))) {
+ 	    event_id(event) = '\n';  /* let file_dir think it got a \n */
+ 	    file_dir(file_item, event);
+ 	    return;
+ 	}
+     }
+     (void) panel_set(item, PANEL_VALUE, 0, NULL); /* remove last value */
+ }
+ #else /* NO_WALK_MENUS */
+ 
+ /*
+  * callback routine for the panel items that need filename input.
+  * (folder and save)
+  */
+ void
  do_file_dir(item, value, event)
  Panel_item item;
  int value;
***************
*** 206,215 ****
  	    (void) strcat(buf, p);
  	} else
  	    (void) strcat(buf, p = panel_get(item, PANEL_CHOICE_STRING, value));
! 	(void) sprintf(msgstr, "Save in %s? ", trim_filename(p));
! 	if (ask(msgstr) != TRUE) {
! 	    wprint("Message not saved\n");
! 	    return;
  	}
      }
      turnon(glob_flags, IGN_BANG);
--- 274,285 ----
  	    (void) strcat(buf, p);
  	} else
  	    (void) strcat(buf, p = panel_get(item, PANEL_CHOICE_STRING, value));
! 	if (chk_option("verify", "save")) {
! 	    (void) sprintf(msgstr, "Save in %s? ", trim_filename(p));
! 	    if (ask(msgstr) != TRUE) {
! 		wprint("Message not saved\n");
! 		return;
! 	    }
  	}
      }
      turnon(glob_flags, IGN_BANG);
***************
*** 218,223 ****
--- 288,294 ----
  	turnoff(glob_flags, IGN_BANG);
      (void) panel_set(item, PANEL_VALUE, 0, NULL); /* remove last value */
  }
+ #endif /* NO_WALK_MENUS */
  
  /*ARGSUSED*/
  void
*** /tmp/,RCSt1002926	Wed Jul 11 21:33:35 1990
--- hdr_sw.c	Wed Jul 11 21:26:47 1990
***************
*** 19,26 ****
  
  static Notify_value scroll_hdr();
  static void msg_menu_func(), do_menu(), msg_menu_notify();
! static Menu msg_menu;
! static Menu_item cur_msg_item;
  
  void
  make_hdr_sw(parent)
--- 19,25 ----
  
  static Notify_value scroll_hdr();
  static void msg_menu_func(), do_menu(), msg_menu_notify();
! Menu msg_menu;
  
  void
  make_hdr_sw(parent)
***************
*** 261,267 ****
      char *data;	/* Menu item client data. */
  };
  
! static void
  get_msg_menu()
  {
      int i;
--- 260,266 ----
      char *data;	/* Menu item client data. */
  };
  
! void
  get_msg_menu()
  {
      int i;
***************
*** 278,284 ****
  	{ "Help",            HELP_MSG  },
      };
  
!     msg_menu = menu_create(MENU_NOTIFY_PROC, msg_menu_notify, NULL);
      for (i = 0; i < ArraySize(msg_items); i++) {
  	mi = menu_create_item(MENU_STRING,	msg_items[i].str,
  			      MENU_CLIENT_DATA,	msg_items[i].data,
--- 277,283 ----
  	{ "Help",            HELP_MSG  },
      };
  
!     msg_menu = menu_create(MENU_NOTIFY_PROC, menu_return_item, NULL);
      for (i = 0; i < ArraySize(msg_items); i++) {
  	mi = menu_create_item(MENU_STRING,	msg_items[i].str,
  			      MENU_CLIENT_DATA,	msg_items[i].data,
***************
*** 288,301 ****
  }
  
  static void
- msg_menu_notify(menu, item)
- Menu menu;
- Menu_item item;
- {
-     cur_msg_item = item;
- }
- 
- static void
  do_menu(can_sw, event, fd, message)
  Canvas can_sw;
  Event *event;
--- 287,292 ----
***************
*** 302,307 ****
--- 293,300 ----
  int fd, message;
  {
      char *action;
+     char * save_place;
+     Menu_item cur_msg_item;
      static char buf[16];
  
      if (!msg_cnt) {
***************
*** 323,329 ****
  	box(0, 5 + line * l_height(),
  	    hdr_rect->r_width, 5 + (line+1) * l_height());
  	/* show menu */
! 	menu_show(msg_menu, can_sw, event, NULL);
  	/* remove feedback */
  	box(0, 5 + line * l_height(),
  	    hdr_rect->r_width, 5 + (line+1) * l_height());
--- 316,322 ----
  	box(0, 5 + line * l_height(),
  	    hdr_rect->r_width, 5 + (line+1) * l_height());
  	/* show menu */
! 	cur_msg_item = menu_show(msg_menu, can_sw, event, NULL);
  	/* remove feedback */
  	box(0, 5 + line * l_height(),
  	    hdr_rect->r_width, 5 + (line+1) * l_height());
***************
*** 330,337 ****
  	/* if user selected something, figure out what was selected. */
  	if (!cur_msg_item)
  	    return;
! 	action = (char *) menu_get(cur_msg_item, MENU_CLIENT_DATA);
! 	cur_msg_item = (Menu_item)NULL;
      } else
  	action = (char *) event;
  
--- 323,338 ----
  	/* if user selected something, figure out what was selected. */
  	if (!cur_msg_item)
  	    return;
! #ifndef NO_WALK_MENUS
! 	    if ((Menu)menu_get(cur_msg_item, MENU_PARENT) == msg_menu) {
! 		action = (char *) menu_get(cur_msg_item, MENU_CLIENT_DATA);
! 	    } else {
! 		save_place = (char *)menu_get(cur_msg_item, MENU_CLIENT_DATA);
! 		action = SAVE_MSG;
! 	    }   /* endif */
! #else /* NO_WALK_MENUS */
! 	    action = (char *) menu_get(cur_msg_item, MENU_CLIENT_DATA);
! #endif /* NO_WALK_MENUS */
      } else
  	action = (char *) event;
  
***************
*** 341,348 ****
  	    extern Panel_item msg_num_item, save_item;
  	    (void) panel_set(msg_num_item, PANEL_VALUE,
  					sprintf(buf, "%d", message+1), NULL);
! 	    event_id(event) = MS_LEFT;
! 	    do_file_dir(save_item, 0, event);
  	    (void) panel_set(msg_num_item, PANEL_VALUE, NO_STRING, NULL);
  	}
  	when HELP_MSG :
--- 342,357 ----
  	    extern Panel_item msg_num_item, save_item;
  	    (void) panel_set(msg_num_item, PANEL_VALUE,
  					sprintf(buf, "%d", message+1), NULL);
! #ifndef NO_WALK_MENUS
! 		if (*save_place == '\0') { /* magic to mean "use Filename:" */
! 		    do_file_dir(save_item, event);
! 		} else {
! 		    xx_file_dir(save_item, save_place);
! 		}   /* endif */
! #else /* NO_WALK_MENUS */
! 		event_id(event) = MS_LEFT;
! 		do_file_dir(save_item, 0, event);
! #endif /* NO_WALK_MENUS */
  	    (void) panel_set(msg_num_item, PANEL_VALUE, NO_STRING, NULL);
  	}
  	when HELP_MSG :
*** /tmp/,RCSt1002926	Wed Jul 11 21:33:38 1990
--- panels.c	Wed Jul 11 21:26:47 1990
***************
*** 31,36 ****
--- 31,47 ----
      save_item,		/* saves messages */
      sub_hdr_item[6];	/* display items that just sit there and give help */
  
+ #ifndef NO_WALK_MENUS
+ Panel
+     folder_panel,
+     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 */
+ 
  /* These global panel items for letter composition should eventually go away */
  Panel_item
      edit_item,		/* edit a message */
***************
*** 75,80 ****
--- 86,101 ----
  	PANEL_NOTIFY_PROC, 		do_help,
  	NULL);
  
+ #ifndef NO_WALK_MENUS
+     folder_panel = panel;
+     folder_item = panel_create_item(panel, PANEL_BUTTON,
+ 	PANEL_ATTRIBUTE_LIST, 		button_args,
+ 	PANEL_LABEL_IMAGE,
+ 	    panel_button_image(panel, "Folder", 6, mush_font),
+ 	PANEL_NOTIFY_PROC, 		do_file_dir,
+ 	PANEL_EVENT_PROC,		walk_menu_event,
+ 	NULL);
+ #else /* NO_WALK_MENUS */
      folder_item = panel_create_item(panel, PANEL_CHOICE,
  	PANEL_ATTRIBUTE_LIST, 		choice_args,
  	PANEL_LABEL_IMAGE,
***************
*** 85,90 ****
--- 106,112 ----
  	NULL);
  
      add_folder_to_menu(folder_item, 3);
+ #endif /* NO_WALK_MENUS */
  
      folder_text_item = panel_create_item(panel, PANEL_TEXT,
  	PANEL_ATTRIBUTE_LIST, 		choice_args,
***************
*** 214,219 ****
--- 236,252 ----
  	PANEL_NOTIFY_PROC, 		delete_mail,
  	NULL);
  
+ #ifndef NO_WALK_MENUS
+     save_panel = panel;
+     save_item = panel_create_item(panel, PANEL_BUTTON,
+ 	PANEL_ATTRIBUTE_LIST, 		button_args,
+ 	PANEL_LABEL_IMAGE, panel_button_image(panel, "Save", 4, mush_font),
+ 	PANEL_NOTIFY_PROC, 		do_file_dir,
+ 	PANEL_EVENT_PROC,		walk_menu_event,
+ 	NULL);
+ 
+     create_folder_menus();
+ #else /* NO_WALK_MENUS */
      {
  	char *mbox = do_set(set_options, "mbox");
  	if (!mbox || !*mbox)
***************
*** 227,232 ****
--- 260,266 ----
      }
  
      add_folder_to_menu(save_item, 1);
+ #endif /* NO_WALK_MENUS */
  
      file_item = panel_create_item(panel, PANEL_TEXT,
  	PANEL_ATTRIBUTE_LIST, 		choice_args,
***************
*** 391,445 ****
  
  #include "glob.h"
  
! #ifdef WALK_MENUS
! folder_menu_notify(menu, mi)
! Menu menu;
! Menu_item mi;
! {
! }
  
! static Menu_item
! add_path_to_menu(menu, path)
! Menu menu;
  char *path;
  {
-     DIR			*dirp;
-     struct dirent	*dp;
-     struct stat 	s_buf;
      Menu_item		mi;
      Menu		next_menu;
      char		buf[MAXPATHLEN];
  
      /* don't add a folder to the list if user can't read it */
!     if (stat(path, &s_buf) == -1 || !(s_buf.st_mode & S_IREAD))
  	return NULL;
      if ((s_buf.st_mode & S_IFMT) == S_IFDIR) {
  	int cnt = 0;
! 	if (!(dirp = opendir(path)))
! 	    return NULL; /* don't bother adding to list if we can't scan it */
! 	next_menu = menu_create(MENU_NOTIFY_PROC, folder_menu_notify, NULL);
! 	while (dp = readdir(dirp))
! 	    if (strcmp(dp->d_name, ".") && strcmp(dp->d_name, ".."))
! 		if (mi = add_path_to_menu(next_menu,
! 			sprintf(buf, "%s/%s", path, dp->d_name))) {
! 		    menu_set(next_menu, MENU_APPEND_ITEM, mi, NULL);
! 		    cnt++;
  		}
! 	closedir(dirp);
! 	mi = menu_create_item(MENU_STRING, trim_filename(path), NULL);
! 	if (!cnt) {
  	    menu_destroy(next_menu);
  	    menu_set(mi, MENU_INACTIVE, TRUE, NULL);
! 	} else
  	    menu_set(mi, MENU_PULLRIGHT, next_menu, NULL);
! 	return mi;
      }
!     /* we should check that this file is actually a folder */
!     return menu_create_item(MENU_STRING, trim_filename(path), NULL);
  }
- #endif /* WALK_MENUS */
  
  static
  add_path_to_menu(item, path, n)
  Panel_item item;
  char *path;
--- 425,675 ----
  
  #include "glob.h"
  
! #ifndef NO_WALK_MENUS
  
! static
! Menu_item
! make_folder_item(path)
  char *path;
  {
      Menu_item		mi;
+     Menu_item		sub_mi;
      Menu		next_menu;
+     char		**names, **np;
+     struct stat 	s_buf;
      char		buf[MAXPATHLEN];
  
+     if (glob(path, "*/{.,..}")) {
+ 	return NULL;
+     }
+ 
      /* don't add a folder to the list if user can't read it */
!     if (stat(path, &s_buf) == -1 || !(s_buf.st_mode & S_IREAD)) {
  	return NULL;
+     }
+     mi = menu_create_item(
+ 	MENU_STRING,		savestr(basename(trim_filename(path))),
+ 	MENU_CLIENT_DATA,	NULL,
+ 	MENU_RELEASE,		/* no value */
+ 	NULL);
      if ((s_buf.st_mode & S_IFMT) == S_IFDIR) {
  	int cnt = 0;
! 	next_menu = menu_create(MENU_NOTIFY_PROC, menu_return_item, NULL);
! 	sprintf(buf, "%s/{.*,*}", path);
! 	if (filexp(buf, &names) > 0) {
! 	    for (np = names; np && *np; np++) {
! 		if ((sub_mi = make_folder_item(*np)) != NULL) {
! 		    menu_set(next_menu, MENU_APPEND_ITEM, sub_mi, NULL);
! 		    ++cnt;
  		}
! 	    }
! 	    free_vec(names);
! 	}
! 	if (! cnt) {
  	    menu_destroy(next_menu);
  	    menu_set(mi, MENU_INACTIVE, TRUE, NULL);
! 	} else {
  	    menu_set(mi, MENU_PULLRIGHT, next_menu, NULL);
! 	}
!     } else if (test_folder(path, NULL)) {
! 	menu_set(mi, MENU_CLIENT_DATA, savestr(path), NULL);
!     } else {
! 	menu_destroy(mi);
! 	mi = NULL;
      }
!     return mi;
  }
  
  static
+ void
+ destroy_folder_item(menu_item, menu_type)
+ Menu_item menu_item;
+ Menu_attribute menu_type;
+ {
+     char	*ptr;
+ 
+     if (menu_type == MENU_ITEM) {
+ 	if ((ptr = (char *)menu_get(menu_item, MENU_STRING)) != NULL) {
+ 	    free(ptr);
+ 	}
+ 	if ((ptr = (char *)menu_get(menu_item, MENU_CLIENT_DATA)) != NULL) {
+ 	    free(ptr);
+ 	}
+     }
+     return;
+ }
+ 
+ create_folder_menus()
+ {
+     int 	  item_number;
+     Menu	  menu;
+     Menu_item	  menu_item;
+     int 	  nitems;
+     char	 *mbox;
+     char	 *tmp = NULL;
+     char	 *p;
+     static int	  menus_exist = 0;
+ 
+     if (menus_exist) {
+ 	/* remove duplicated menu items from save_menu */
+ 	for (item_number = (int)menu_get(save_menu, MENU_NITEMS) ;
+ 	      item_number > 1 ; --item_number) {
+ 	    menu_set(save_menu, MENU_REMOVE, item_number, NULL);
+ 	}
+ 	/* remove duplicated menu items from hdr_save_menu */
+ 	for (item_number = (int)menu_get(hdr_save_menu, MENU_NITEMS) ;
+ 	      item_number > 1 ; --item_number) {
+ 	    menu_set(save_menu, MENU_REMOVE, item_number, NULL);
+ 	}
+ 	menu_destroy_with_proc(hdr_save_menu, destroy_folder_item);
+ 	menu_destroy_with_proc(save_menu, destroy_folder_item);
+ 	menu_destroy_with_proc(folder_menu, destroy_folder_item);
+     }
+ 
+     if (!(p = do_set(set_options, "folder")) || !*p) {
+ 	p = DEF_FOLDER;
+     }
+     if (p) {
+ 	int x = 0;
+ 	tmp = getpath(p, &x);
+ 	if (x == -1) {
+ 	    if (errno != ENOENT)
+ 		print("%s: %s\n", p, tmp);
+ 	    tmp = NULL;
+ 	}
+     }
+     menu = NULL;
+     menu_item = NULL;
+     if (tmp != NULL) {
+ 	if ((menu_item = make_folder_item(tmp)) != NULL) {
+ 	    if ((menu = menu_get(menu_item, MENU_PULLRIGHT)) != NULL) {
+ 	        /* $folder was a directory, use the pullright
+ 		 * instead of the directory menu item.
+ 		 */
+ 		/* "unhook" the pullright (so it is not released) */
+ 		menu_set(menu_item, MENU_PULLRIGHT, NULL, NULL);
+ 		/* destroy the menu item */
+ 		menu_destroy_with_proc(menu_item, destroy_folder_item);
+ 		menu_item = NULL;
+ 	    }
+ 	}
+     }
+     if (menu == NULL) {
+ 	menu = menu_create(MENU_NOTIFY_PROC, menu_return_item, NULL);
+ 	if (menu_item != NULL) {
+ 	    menu_set(menu, MENU_APPEND_ITEM, menu_item, NULL);
+ 	}
+     }
+ 
+     /* create save_menu */
+     save_menu = menu_create(MENU_NOTIFY_PROC, menu_return_item, NULL);
+     /* add magic first item */
+     mbox = do_set(set_options, "mbox");
+     if (!mbox || !*mbox) {
+ 	mbox = DEF_MBOX;
+     }
+     menu_item = menu_create_item(
+ 	MENU_STRING,		savestr(trim_filename(mbox)),
+ 	MENU_CLIENT_DATA,	savestr(mbox),
+ 	MENU_RELEASE,		/* no value */
+ 	NULL);
+     menu_set(save_menu, MENU_APPEND_ITEM, menu_item, NULL);
+     /* copy menu for save_menu */
+     nitems = (int)menu_get(menu, MENU_NITEMS);
+     for (item_number = 1 ; item_number <= nitems ; ++item_number) {
+ 	menu_set(save_menu,
+ 	    MENU_APPEND_ITEM, menu_get(menu, MENU_NTH_ITEM, item_number),
+ 	    NULL);
+     }
+ 
+     /* create hdr_save_menu */
+     hdr_save_menu = menu_create(MENU_NOTIFY_PROC, menu_return_item, NULL);
+     /* add magic first item */
+     menu_item = menu_create_item(
+ 	MENU_STRING,		savestr("use Filename:"),
+ 	MENU_CLIENT_DATA,	savestr(""),	/* magic */
+ 	MENU_RELEASE,		/* no value */
+ 	NULL);
+     menu_set(hdr_save_menu, MENU_APPEND_ITEM, menu_item, NULL);
+     /* copy save_menu for hdr_save_menu */
+     nitems = (int)menu_get(save_menu, MENU_NITEMS);
+     for (item_number = 1 ; item_number <= nitems ; ++item_number) {
+ 	menu_set(hdr_save_menu,
+ 	    MENU_APPEND_ITEM, menu_get(save_menu, MENU_NTH_ITEM, item_number),
+ 	    NULL);
+     }
+     /* Make sure the header subwindow menu exists so we can tack on a
+      * pullright for Save.
+      */
+     if (! msg_menu) {
+ 	get_msg_menu();
+     }
+     if ((menu_item = menu_find(msg_menu, MENU_STRING, "Save", NULL))
+ 	    != NULL) {
+ 	menu_set(menu_item, MENU_PULLRIGHT, hdr_save_menu, NULL);
+     }
+ 
+     /* insert folder-specific initial options to menu */
+     folder_menu = menu;
+     menu_item = menu_create_item(
+ 	MENU_STRING,		savestr("System Mailbox"),
+ 	MENU_CLIENT_DATA,	savestr("%"),
+ 	MENU_RELEASE,		/* no value */
+ 	NULL);
+     menu_set(folder_menu, MENU_INSERT, 0, menu_item, NULL);
+     menu_item = menu_create_item(
+ 	MENU_STRING,		savestr("Main Mailbox"),
+ 	MENU_CLIENT_DATA,	savestr("&"),
+ 	MENU_RELEASE,		/* no value */
+ 	NULL);
+     menu_set(folder_menu, MENU_INSERT, 1, menu_item, NULL);
+     menu_item = menu_create_item(
+ 	MENU_STRING,		savestr("Last Accessed Folder"),
+ 	MENU_CLIENT_DATA,	savestr("#"),
+ 	MENU_RELEASE,		/* no value */
+ 	NULL);
+     menu_set(folder_menu, MENU_INSERT, 2, menu_item, NULL);
+ 
+     menus_exist = 1;
+     return;
+ }
+ 
+ static
+ walk_menu_event(item, event)
+ Panel_item item;
+ Event *event;
+ {
+     char	 *folder_name;
+     Menu_item 	  selection;
+     Menu	  menu;
+     Panel	  panel;
+     void xx_file_dir();
+ 
+     if (event_id(event) == MS_RIGHT && event_is_down(event)) {
+ 	if (item == folder_item) {
+ 	    menu = folder_menu;
+ 	    panel = folder_panel;
+ 	} else {
+ 	    menu = save_menu;
+ 	    panel = save_panel;
+ 	}
+ 	selection = (Menu_item)menu_show(menu, panel, event, 0);
+ 	if (! selection) {
+ 	    /* no selection was made */
+ 	    return;
+ 	}
+ 	if ((folder_name = (char *)menu_get(selection, MENU_CLIENT_DATA))
+ 		!= NULL) {
+ 	    xx_file_dir(item, folder_name);
+ 	}
+     } else {
+ 	panel_default_handle_event(item, event);
+     }
+ }
+ 
+ #else /* NO_WALK_MENUS */
+ 
+ static
  add_path_to_menu(item, path, n)
  Panel_item item;
  char *path;
***************
*** 476,484 ****
  Panel_item item;
  {
      char	*tmp = NULL, *p;
- #ifdef WALK_MENUS
-     Menu_item	mi;
- #endif /* WALK_MENUS */
  
      if (!(p = do_set(set_options, "folder")) || !*p)
  	p = DEF_FOLDER;
--- 706,711 ----
***************
*** 492,501 ****
  	}
      }
      if (tmp) {
- #ifdef WALK_MENUS
- 	mi = add_path_to_menu(menu, tmp);
- #else /* WALK_MENUS */
  	add_path_to_menu(item, tmp, &n);
- #endif /* WALK_MENUS */
      }
  }
--- 719,725 ----
  	}
      }
      if (tmp) {
  	add_path_to_menu(item, tmp, &n);
      }
  }
+ #endif /* NO_WALK_MENUS */

-- 
Bart Schaefer						schaefer@cse.ogi.edu