(Fprimitive_undo): Use base buffer's modtime field.
[bpt/emacs.git] / lisp / mh-e.el
index b094934..619556d 100644 (file)
@@ -1,12 +1,12 @@
-;;; mh-e.el --- GNU Emacs interface to the MH mailer
+;;; mh-e.el --- GNU Emacs interface to the MH mail system
 
-;;;  Copyright (C) 1985, 86, 87, 88, 89, 92 Free Software Foundation
+;;; Copyright (C) 1985, 86, 87, 88, 90, 92, 93 Free Software Foundation
 
-;; Author: James Larus <larus@ginger.berkeley.edu>
-;; Version: 3.7
-;; Keywords: mail
+(defconst mh-e-time-stamp "Time-stamp: <93/05/30 18:37:43 gildea>")
 
-(defvar mh-e-RCS-id)
+;; Maintainer: Stephen Gildea <gildea@lcs.mit.edu>
+;; Version: 3.8.2
+;; Keywords: mail
 
 ;; GNU Emacs is distributed in the hope that it will be useful,
 ;; but without any warranty.  No author or distributor
 
 ;;; Commentary:
 
-;;;  This file contains mh-e, a GNU Emacs front end to the MH mail system
-;;;  (specifically, for use with MH.5 and MH.6).
+;;; mh-e works with Emacs 18 or 19, and MH 5 or 6.
+
+;;; HOW TO USE:
+;;; M-x mh-rmail to read mail.  Type C-h m there for a list of commands.
+;;; C-u M-x mh-rmail to visit any folder.
+;;; M-x mh-smail to send mail.  From within the mail reader, "m" works, too.
+;;; Your .emacs might benefit from these bindings:
+;;; (global-set-key "\C-xm" 'mh-smail)
+;;; (global-set-key "\C-x4m" 'mh-smail-other-window)
+;;; (global-set-key "\C-cr" 'mh-rmail)
+
+;;; MH (Message Handler) is a powerful mail reader.  The MH newsgroup
+;;; is comp.mail.mh; the mailing list is mh-users@ics.uci.edu (send to
+;;; mh-users-request to be added).  See the monthly Frequently Asked
+;;; Questions posting there for information on getting MH.
 
-;;;  Original version for Gosling emacs by Brian Reid, Stanford, 1982.
-;;;  Modified by James Larus, BBN, July 1984 and UCB, 1984 & 1985.
-;;;  Rewritten for GNU Emacs, James Larus 1985.  larus@ginger.berkeley.edu
-;;;  Modified by Stephen Gildea 1988.  gildea@bbn.com
+;;; NB.  MH must have been compiled with the MHE compiler flag or several
+;;; features necessary mh-e will be missing from MH commands, specifically
+;;; the -build switch to repl and forw.
 
-;;;  NB.  MH must have been compiled with the MHE compiler flag or several
-;;;  features necessary mh-e will be missing from MH commands, specifically
-;;;  the -build switch to repl and forw.
+;;; Original version for Gosling emacs by Brian Reid, Stanford, 1982.
+;;; Modified by James Larus, BBN, July 1984 and UCB, 1984 & 1985.
+;;; Rewritten for GNU Emacs, James Larus 1985.  larus@ginger.berkeley.edu
+;;; Modified by Stephen Gildea 1988.  gildea@bbn.com
+(defconst mh-e-RCS-id "$Header: /home/fsf/rms/e19/lisp/RCS/mh-e.el,v 1.15 1993/07/20 04:35:00 rms Exp rms $")
 
 ;;; Code:
 
@@ -47,7 +61,7 @@
 ;;;(defvar mh-progs "/usr/new/mh/" "Directory containing MH commands.")
 ;;;(defvar mh-lib "/usr/new/lib/mh/" "Directory of MH library.")
 
-(defvar mh-redist-full-contents t
+(defvar mh-redist-full-contents nil
   "Non-nil if the `dist' command needs whole letter for redistribution.
 This is the case when `send' is compiled with the BERK option.")
 
@@ -70,8 +84,11 @@ It is passed three arguments: TO recipients, SUBJECT, and CC recipients.")
 (defvar mh-inc-folder-hook nil
   "Invoked after incorporating mail into a folder with \\[mh-inc-folder].")
 
+(defvar mh-before-quit-hook nil
+  "Invoked by \\[mh-quit] before quitting mh-e.  See also  mh-quit-hook")
+
 (defvar mh-quit-hook nil
-  "Invoked after quitting mh-e with \\[mh-quit].")
+  "Invoked after quitting mh-e by \\[mh-quit].  See also  mh-before-quit-hook")
 
 
 (defvar mh-ins-string nil
@@ -82,7 +99,7 @@ It is passed three arguments: TO recipients, SUBJECT, and CC recipients.")
     (save-excursion
       (goto-char (point))
       (or (bolp) (forward-line 1))
-      (while (< (point) (mark))
+      (while (< (point) (mark t))
        (insert mh-ins-string)
        (forward-line 1))))
   "Hook to run citation function.
@@ -118,12 +135,12 @@ WARNING: do not delete the messages until printing is finished;
 otherwise, your output may be truncated.")
 
 (defvar mh-summary-height 4
-  "*Number of lines in summary window.")
+  "*Number of lines in summary window (including the mode line).")
 
 (defvar mh-recenter-summary-p nil
   "*Recenter summary window when the show window is toggled off if non-nil.")
 
-(defvar mh-ins-buf-prefix ">> "
+(defvar mh-ins-buf-prefix "> "
   "*String to put before each non-blank line of a yanked or inserted message.
 Used when the message is inserted in an outgoing letter.")
 
@@ -141,7 +158,7 @@ windows displaying the message.")
 
 (defvar mh-yank-from-start-of-msg t
   "*Controls which part of a message is yanked by \\[mh-yank-cur-msg].
-If non-nil, include the entire message.  If the symbol `body, then yank the
+If non-nil, include the entire message.  If the symbol `body', then yank the
 message minus the header.  If nil, yank only the portion of the message
 following the point.  If the show buffer has a region, this variable is
 ignored.")
@@ -154,9 +171,16 @@ value and it should be one of \"from\", \"to\", or \"cc\".")
 (defvar mh-recursive-folders nil
   "*If non-nil, then commands which operate on folders do so recursively.")
 
+(defvar mh-unshar-default-directory ""
+  "*Default for directory name prompted for by mh-unshar-msg.")
+
+(defvar mh-signature-file-name "~/.signature"
+  "*Name of file containing the user's signature.
+Inserted into message by \\<mh-letter-mode-map>\\[mh-insert-signature].")
+
 
 ;;; Parameterize mh-e to work with different scan formats.  The defaults work
-;;; the standard MH scan listings.
+;;; with the standard MH scan listings.
 
 (defvar mh-cmd-note 4
   "Offset to insert notation.")
@@ -171,7 +195,7 @@ value and it should be one of \"from\", \"to\", or \"cc\".")
   "String whose first character is used to notate redistributed messages.")
 
 (defvar mh-good-msg-regexp  "^....[^D^]"
-  "Regexp specifiying the scan lines that are 'good' messages.")
+  "Regexp specifying the scan lines that are 'good' messages.")
 
 (defvar mh-deleted-msg-regexp "^....D"
   "Regexp matching scan lines of deleted messages.")
@@ -214,7 +238,10 @@ The string is displayed after the folder's name.  NIL for no annotation.")
 If `mh-visible-headers' is non-nil, it is used instead to specify what
 to keep.")
 
-(defvar mh-rejected-letter-start "^   ----- Unsent message follows -----$"
+(defvar mh-rejected-letter-start
+  (concat "^   ----- Unsent message follows -----$" ;from mail system
+         "\\|^------- Unsent Draft$"   ;from MH itself
+         "\\|^  --- The unsent message follows ---$") ;from AIX mail system
   "Regexp specifying the beginning of the wrapper around a returned letter.
 This wrapper is generated by the mail system when rejecting a letter.")
 
@@ -240,6 +267,9 @@ This wrapper is generated by the mail system when rejecting a letter.")
 (defvar mh-pick-mode-map (make-sparse-keymap)
   "Keymap for searching folder.")
 
+(defvar mh-searching-folder nil
+  "Folder this pick is searching.")
+
 (defvar mh-letter-mode-syntax-table nil
   "Syntax table used while in mh-e letter mode.")
 
@@ -266,9 +296,6 @@ NIL means do not use draft folder.")
 (defvar mh-previous-seq nil
   "Name of the sequence to which a message was last added.")
 
-(defvar mh-signature-file-name "~/.signature"
-  "Name of file containing the user's signature.")
-
 
 ;;; Macros and generic functions:
 
@@ -413,13 +440,13 @@ from a sequence."
         (config (current-window-configuration))
         (draft
          (cond ((and mh-draft-folder (equal from-folder mh-draft-folder))
-                (find-file (mh-msg-filename msg))
+                (pop-to-buffer (find-file-noselect (mh-msg-filename msg)) t)
                 (rename-buffer (format "draft-%d" msg))
                 (buffer-name))
                (t
                 (mh-read-draft "clean-up" (mh-msg-filename msg) nil)))))
     (mh-clean-msg-header (point-min)
-                        "^Date:\\|^Received:\\|^Message-Id:\\|^From:"
+                        "^Date:\\|^Received:\\|^Message-Id:\\|^From:\\|^Delivery-Date:"
                         nil)
     (goto-char (point-min))
     (set-buffer-modified-p nil)
@@ -450,7 +477,7 @@ Default is the displayed message."
           (forward-char 1)
           (delete-region (point-min) (point))
           (mh-clean-msg-header (point-min)
-                               "^Date:\\|^Received:\\|^Message-Id:\\|^From:\\|^Sender:"
+                               "^Date:\\|^Received:\\|^Message-Id:\\|^From:\\|^Sender:\\|^Return-Path:"
                                nil))
          (t
           (message "Does not appear to be a rejected letter.")))
@@ -517,7 +544,7 @@ If optional prefix argument provided, then prompt for the message sequence."
 Non-nil second argument means do not signal an error if message does not exist.
 Non-nil third argument means not to show the message.
 Return non-nil if cursor is at message."
-  (interactive "NMessage number? ")
+  (interactive "NGoto message: ")
   (let ((cur-msg (mh-get-msg-num nil))
        (starting-place (point))
        (msg-pattern (mh-msg-search-pat number)))
@@ -544,7 +571,7 @@ Return non-nil if cursor is at message."
 (defun mh-inc-folder (&optional maildrop-name)
   "Inc(orporate) new mail into +inbox.
 Optional prefix argument specifies an alternate maildrop from the default.
-If this is given, mail is incorporated into the current folder, rather
+If this is given, incorporate mail into the current folder, rather
 than +inbox.  Run `mh-inc-folder-hook' after incorporating new mail."
   (interactive (list (if current-prefix-arg
                         (expand-file-name
@@ -573,7 +600,8 @@ than +inbox.  Run `mh-inc-folder-hook' after incorporating new mail."
        (mh-remove-folder-from-folder-list folder)
        (message "Folder %s removed" folder)
        (mh-set-folder-modified-p nil)  ; so kill-buffer doesn't complain
-       (kill-buffer mh-show-buffer)
+       (if (get-buffer mh-show-buffer)
+           (kill-buffer mh-show-buffer))
        (kill-buffer folder))
       (message "Folder not removed")))
 
@@ -594,7 +622,9 @@ than +inbox.  Run `mh-inc-folder-hook' after incorporating new mail."
       (switch-to-buffer " *mh-temp*")
       (erase-buffer)
       (message "Listing folders...")
-      (mh-exec-cmd-output "folders" t)
+      (mh-exec-cmd-output "folders" t (if mh-recursive-folders
+                                         "-recurse"
+                                         "-norecurse"))
       (goto-char (point-min))
       (message "Listing folders...done"))))
 
@@ -660,7 +690,7 @@ Otherwise just send the message's body."
   (interactive
    (list current-prefix-arg (read-string "Shell command on message: ")))
   (save-excursion
-    (set-buffer mh-show-buffer)
+    (mh-display-msg (mh-get-msg-num t) mh-current-folder) ;update show buffer
     (goto-char (point-min))
     (if (not prefix-provided) (search-forward "\n\n"))
     (shell-command-on-region (point) (point-max) command nil)))
@@ -721,7 +751,7 @@ using filter mhl.reply in your MH directory."
       (message "Composing a reply...")
       (cond ((or (equal reply-to "from") (equal reply-to ""))
             (apply 'mh-exec-cmd
-                   "repl" "-build"
+                   "repl" "-build" "-noquery"
                    "-nodraftfolder" mh-current-folder
                    msg
                    "-nocc" "all"
@@ -729,7 +759,7 @@ using filter mhl.reply in your MH directory."
                        (list "-filter" "mhl.reply"))))
            ((equal reply-to "to")
             (apply 'mh-exec-cmd
-                   "repl" "-build"
+                   "repl" "-build" "-noquery"
                    "-nodraftfolder" mh-current-folder
                    msg
                    "-cc" "to"
@@ -737,7 +767,7 @@ using filter mhl.reply in your MH directory."
                        (list "-filter" "mhl.reply"))))
            ((or (equal reply-to "cc") (equal reply-to "all"))
             (apply 'mh-exec-cmd
-                   "repl" "-build"
+                   "repl" "-build" "-noquery"
                    "-nodraftfolder" mh-current-folder
                    msg
                    "-cc" "all" "-nocc" "me"
@@ -764,9 +794,11 @@ using filter mhl.reply in your MH directory."
 
 
 (defun mh-quit ()
-  "Restore the previous window configuration, if one exists.
-Finish by running mh-quit-hook."
+  "Quit mh-e.
+Start by running mh-before-quit-hook.  Restore the previous window
+configuration, if one exists.  Finish by running mh-quit-hook."
   (interactive)
+  (run-hooks 'mh-before-quit-hook)
   (if mh-previous-window-config
       (set-window-configuration mh-previous-window-config))
   (run-hooks 'mh-quit-hook))
@@ -903,7 +935,7 @@ If optional prefix argument provided, then prompt for the message sequence."
   (mh-add-msgs-to-seq from to))
 
 
-(defun mh-rescan-folder (range)
+(defun mh-rescan-folder (&optional range)
   "Rescan a folder after optionally processing the outstanding commands.
 If optional prefix argument is provided, prompt for the range of
 messages to display.  Otherwise show the entire folder."
@@ -987,7 +1019,10 @@ setting of the variable mh-redist-full-contents.  See its documentation."
 
 
 (defun mh-send (to cc subject)
-  "Compose and send a letter."
+  "Compose and send a letter.
+The letter is composed in mh-letter-mode; see its documentation for more
+details.  If `mh-compose-letter-function' is defined, it is called on the
+draft and passed three arguments: to, subject, and cc."
   (interactive "sTo: \nsCc: \nsSubject: ")
   (let ((config (current-window-configuration)))
     (delete-other-windows)
@@ -1042,14 +1077,15 @@ mh-summary-height) and the show buffer below it."
     (mh-show-message-in-other-window)
     (mh-display-msg msg folder))
   (other-window -1)
-  (shrink-window (- (window-height) mh-summary-height))
+  (if (not (= (1+ (window-height)) (screen-height))) ;not horizontally split
+      (shrink-window (- (window-height) mh-summary-height)))
   (mh-recenter nil)
   (if (not (memq msg mh-seen-list)) (mh-push msg mh-seen-list)))
 
 
 (defun mh-sort-folder ()
   "Sort the messages in the current folder by date."
-  (interactive "")
+  (interactive)
   (mh-process-or-undo-commands mh-current-folder)
   (setq mh-next-direction 'forward)
   (mh-set-folder-modified-p t)         ; lock folder while sorting
@@ -1075,21 +1111,30 @@ provided, then prompt for the message sequence."
                     (if current-prefix-arg
                         (mh-read-seq-default "Undo" t)
                         (mh-get-msg-num t))))
-
   (cond (prefix-provided
         (mh-mapc (function mh-undo-msg) (mh-seq-to-msgs msg-or-seq)))
-       ((or (looking-at mh-deleted-msg-regexp)
-            (looking-at mh-refiled-msg-regexp))
-        (mh-undo-msg (mh-get-msg-num t)))
        (t
-        (error "Nothing to undo")))
+        (let ((original-position (point)))
+          (beginning-of-line)
+          (while (not (or (looking-at mh-deleted-msg-regexp)
+                          (looking-at mh-refiled-msg-regexp)
+                          (and (eq mh-next-direction 'forward) (bobp))
+                          (and (eq mh-next-direction 'backward)
+                               (save-excursion (forward-line) (eobp)))))
+            (forward-line (if (eq mh-next-direction 'forward) -1 1)))
+          (if (or (looking-at mh-deleted-msg-regexp)
+                  (looking-at mh-refiled-msg-regexp))
+              (progn
+                (mh-undo-msg (mh-get-msg-num t))
+                (mh-maybe-show))
+              (goto-char original-position)
+              (error "Nothing to undo")))))
   ;; update the mh-refile-list so mh-outstanding-commands-p will work
   (mh-mapc (function
            (lambda (elt)
              (if (not (mh-seq-to-msgs elt))
                  (setq mh-refile-list (delq elt mh-refile-list)))))
           mh-refile-list)
-
   (if (not (mh-outstanding-commands-p))
       (mh-set-folder-modified-p nil)))
 
@@ -1098,18 +1143,17 @@ provided, then prompt for the message sequence."
   ;; Undo the deletion or refile of one MESSAGE.
   (cond ((memq msg mh-delete-list)
         (setq mh-delete-list (delq msg mh-delete-list))
-        (mh-remove-msg-from-seq msg 'deleted t)
-        (mh-notate msg ?  mh-cmd-note))
+        (mh-remove-msg-from-seq msg 'deleted t))
        (t
         (mh-mapc (function (lambda (dest)
                              (mh-remove-msg-from-seq msg dest t)))
-                 mh-refile-list)
-        (mh-notate msg ?  mh-cmd-note))))
+                 mh-refile-list)))
+  (mh-notate msg ?  mh-cmd-note))
 
 
 (defun mh-undo-folder (&rest ignore)
   "Undo all commands in current folder."
-  (interactive "")
+  (interactive)
   (cond ((or mh-do-not-confirm
             (yes-or-no-p "Undo all commands in folder? "))
         (setq mh-delete-list nil
@@ -1123,22 +1167,57 @@ provided, then prompt for the message sequence."
         (sit-for 2))))
 
 
+(defun mh-unshar-msg (dir)
+  "Unpack the shar file contained in the current message into directory DIR."
+  (interactive (list (read-file-name "Unshar message in directory: "
+                                    mh-unshar-default-directory
+                                    mh-unshar-default-directory nil)))
+  (mh-display-msg (mh-get-msg-num t) mh-current-folder) ;update show buffer
+  (mh-unshar-buffer dir))
+
+(defun mh-unshar-buffer (dir)
+  ;; Unpack the shar file contained in the current buffer into directory DIR.
+  (goto-char (point-min))
+  (if (or (re-search-forward "^#![ \t]*/bin/sh" nil t)
+         (and (re-search-forward "^[^a-z0-9\"]*cut here\b" nil t)
+              (forward-line 1))
+         (re-search-forward "^#" nil t)
+         (re-search-forward "^: " nil t))
+      (let ((default-directory (expand-file-name dir))
+           (start (progn (beginning-of-line) (point)))
+           (log-buffer (get-buffer-create "*Unshar Output*")))
+       (save-excursion
+         (set-buffer log-buffer)
+         (setq default-directory (expand-file-name dir))
+         (erase-buffer)
+         (if (file-directory-p default-directory)
+             (insert "cd " dir "\n")
+           (insert "mkdir " dir "\n")
+           (call-process "mkdir" nil log-buffer t default-directory)))
+       (set-window-start (display-buffer log-buffer) 0) ;so can watch progress
+       (call-process-region start (point-max) "sh" nil log-buffer t))
+    (error "Cannot find start of shar.")))
+       
+
 (defun mh-visit-folder (folder &optional range)
-  "Visit FOLDER and display RANGE of messages."
+  "Visit FOLDER and display RANGE of messages.
+Assumes mh-e has already been initialized."
   (interactive (list (mh-prompt-for-folder "Visit" "+inbox" t)
                     (mh-read-msg-range "Range [all]? ")))
   (let ((config (current-window-configuration)))
     (mh-scan-folder folder (or range "all"))
-    (setq mh-previous-window-config config)))
+    (setq mh-previous-window-config config))
+  nil)
 
 
 (defun mh-widen ()
   "Remove restrictions from the current folder, thereby showing all messages."
-  (interactive "")
-  (with-mh-folder-updating (t)
-    (delete-region (point-min) (point-max))
-    (widen)
-    (mh-make-folder-mode-line))
+  (interactive)
+  (if mh-narrowed-to-seq
+      (with-mh-folder-updating (t)
+       (delete-region (point-min) (point-max))
+       (widen)
+       (mh-make-folder-mode-line)))
   (setq mh-narrowed-to-seq nil))
 
 \f
@@ -1160,7 +1239,7 @@ provided, then prompt for the message sequence."
 
 
 (defun mh-refile-a-msg (msg destination)
-  ;; Refile MESSAGE in FOLDER.
+  ;; Refile MESSAGE in FOLDER.  FOLDER is a symbol, not a string.
   (save-excursion
     (mh-goto-msg msg nil t)
     (cond ((looking-at mh-deleted-msg-regexp)
@@ -1184,6 +1263,7 @@ provided, then prompt for the message sequence."
 
 (defun mh-display-msg (msg-num folder)
   ;; Display message NUMBER of FOLDER.
+  ;; Sets the current buffer to the show buffer.
   (set-buffer folder)
   ;; Bind variables in folder buffer in case they are local
   (let ((formfile mhl-formfile)
@@ -1253,7 +1333,7 @@ provided, then prompt for the message sequence."
     (save-restriction
       (goto-char start)
       (if (search-forward "\n\n" nil t)
-         (backward-char 2))
+         (backward-char 1))
       (narrow-to-region start (point))
       (goto-char (point-min))
       (if visible-headers
@@ -1293,7 +1373,7 @@ provided, then prompt for the message sequence."
   ;; reused.
   (cond (mh-draft-folder
         (let ((orig-default-dir default-directory))
-          (pop-to-buffer (find-file-noselect (mh-new-draft-name) t))
+          (pop-to-buffer (find-file-noselect (mh-new-draft-name)) t)
           (rename-buffer (format "draft-%s" (buffer-name)))
           (setq default-directory orig-default-dir)))
        (t
@@ -1329,7 +1409,7 @@ provided, then prompt for the message sequence."
     (set-buffer (get-buffer-create " *mh-temp*"))
     (erase-buffer)
     (mh-exec-cmd-output "mhpath" nil mh-draft-folder "new")
-    (buffer-substring (point) (1- (mark)))))
+    (buffer-substring (point) (1- (mark t)))))
 
 
 (defun mh-next-msg ()
@@ -1366,7 +1446,7 @@ provided, then prompt for the message sequence."
 ;;; The folder data abstraction.
 
 (defvar mh-current-folder nil "Name of current folder, a string.")
-(defvar mh-show-buffer nil "Buffer that displays mesage for this folder.")
+(defvar mh-show-buffer nil "Buffer that displays message for this folder.")
 (defvar mh-folder-filename nil "Full path of directory for this folder.")
 (defvar mh-showing nil "If non-nil, show the message in a separate window.")
 (defvar mh-next-seq-num nil "Index of free sequence id.")
@@ -1436,9 +1516,9 @@ Variables controlling mh-e operation are (defaults in parentheses):
     a messages is toggled off.
 
  mh-summary-height (4)
-    Number of lines in the summary window.
+    Number of lines in the summary window including the mode line.
 
- mh-ins-buf-prefix (\">> \")
+ mh-ins-buf-prefix (\"> \")
     String to insert before each non-blank line of a message as it is
     inserted in a draft letter.
 
@@ -1464,6 +1544,7 @@ The value of mh-folder-mode-hook is called when a new folder is set up."
    'mh-first-msg-num nil               ; Number of first msg in buffer
    'mh-last-msg-num nil                        ; Number of last msg in buffer
    'mh-previous-window-config nil)     ; Previous window configuration
+  (setq truncate-lines t)
   (auto-save-mode -1)
   (setq buffer-offer-save t)
   (make-local-variable 'write-file-hooks)
@@ -1696,7 +1777,7 @@ The value of mh-folder-mode-hook is called when a new folder is set up."
   (save-excursion
     (mh-first-msg)
     (while (and msgs (< (point) (point-max)))
-      (cond ((= (mh-get-msg-num nil) (car msgs))
+      (cond ((equal (mh-get-msg-num nil) (car msgs))
             (delete-region (point) (save-excursion (forward-line) (point)))
             (setq msgs (cdr msgs)))
            (t
@@ -1747,6 +1828,9 @@ Variables controlling this mode (defaults in parentheses):
     If nil, only the portion of the message following the point will be yanked.
     If there is a region, this variable is ignored.
 
+ mh-signature-file-name (\"~/.signature\")
+    File to be inserted into message by \\[mh-insert-signature].
+
 Upon invoking mh-letter-mode, text-mode-hook and mh-letter-mode-hook are
 invoked with no args, if those values are non-nil.
 
@@ -1769,7 +1853,10 @@ invoked with no args, if those values are non-nil.
   (mh-set-mode-name "mh-e letter")
   (set-syntax-table mh-letter-mode-syntax-table)
   (run-hooks 'text-mode-hook 'mh-letter-mode-hook)
-  (mh-when auto-fill-function
+  (mh-when (and (boundp 'auto-fill-hook) auto-fill-hook) ;emacs 18
+    (make-local-variable 'auto-fill-hook)
+    (setq auto-fill-hook 'mh-auto-fill-for-letter))
+  (mh-when (and (boundp 'auto-fill-function) auto-fill-function) ;emacs 19
     (make-local-variable 'auto-fill-function)
     (setq auto-fill-function 'mh-auto-fill-for-letter)))
 
@@ -1797,7 +1884,7 @@ invoked with no args, if those values are non-nil.
   "Move point to the end of a specified header field.
 The field is indicated by the previous keystroke.  Create the field if
 it does not exist.  Set the mark to point before moving."
-  (interactive "")
+  (interactive)
   (expand-abbrev)
   (let ((target (cdr (assoc (logior last-input-char ?`) mh-to-field-choices)))
        (case-fold-search t))
@@ -1805,9 +1892,10 @@ it does not exist.  Set the mark to point before moving."
           (let ((eol (point)))
             (skip-chars-backward " \t")
             (delete-region (point) eol))
-          (if (save-excursion
-                (backward-char 1)
-                (not (looking-at "[:,]")))
+          (if (and (not (eq (logior last-input-char ?`) ?s))
+                   (save-excursion
+                     (backward-char 1)
+                     (not (looking-at "[:,]"))))
               (insert ", ")
               (insert " ")))
          (t
@@ -1832,8 +1920,8 @@ Prompt for the field name with a completion list of the current folders."
 
 
 (defun mh-insert-signature ()
-  "Insert the file ~/.signature at the current point."
-  (interactive "")
+  "Insert the file named by mh-signature-file-name at the current point."
+  (interactive)
   (insert-file-contents mh-signature-file-name)
   (set-buffer-modified-p (buffer-modified-p))) ; force mode line update
 
@@ -1883,7 +1971,7 @@ Put messages found in a sequence named `search'."
   (interactive)
   (let ((pattern-buffer (buffer-name))
        (searching-buffer mh-searching-folder)
-       (range)
+       range msgs
        (pattern nil)
        (new-buffer nil))
     (save-excursion
@@ -1997,7 +2085,7 @@ Run mh-before-send-letter-hook before doing anything."
                                   "-nodraftfolder" mh-send-args file-name)
               (mh-exec-cmd-output "send" t "-watch" "-nopush"
                                   "-nodraftfolder" file-name))
-          (goto-char (point-max))
+          (goto-char (point-max))      ; show the interesting part
           (recenter -1)
           (set-buffer draft-buffer))   ; for annotation below
          (mh-send-args
@@ -2067,8 +2155,9 @@ yanked message will be deleted."
        (if mh-delete-yanked-msg-window
            (delete-windows-on mh-show-buffer))
        (set-buffer mh-show-buffer)     ; Find displayed message
-       (let ((mh-ins-str (cond ((mark)
-                                (buffer-substring (point) (mark)))
+       (let ((mh-ins-str (cond (mark-active
+                                (buffer-substring (region-beginning)
+                                                  (region-end)))
                                ((eq 'body mh-yank-from-start-of-msg)
                                 (buffer-substring
                                  (save-excursion
@@ -2102,7 +2191,7 @@ yanked message will be deleted."
 (defun mh-fully-kill-draft ()
   "Kill the draft message file and the draft message buffer.
 Use \\[kill-buffer] if you don't want to delete the draft message file."
-  (interactive "")
+  (interactive)
   (if (y-or-n-p "Kill draft message? ")
       (let ((config mh-previous-window-config))
        (if (file-exists-p (buffer-file-name))
@@ -2198,7 +2287,8 @@ Use \\[kill-buffer] if you don't want to delete the draft message file."
     (save-excursion
       (mh-exec-cmd-quiet " *mh-temp*" "mark" folder "-list")
       (goto-char (point-min))
-      (while (re-search-forward "^[^:]+" nil t)
+      ;; look for name in line of form "cur: 4" or "myseq (private): 23"
+      (while (re-search-forward "^[^: ]+" nil t)
        (mh-push (mh-make-seq (intern (buffer-substring (match-beginning 0)
                                                        (match-end 0)))
                              (mh-read-msg-list))
@@ -2324,7 +2414,7 @@ Use \\[kill-buffer] if you don't want to delete the draft message file."
 
 (defun mh-folder-name-p (name)
   ;; Return non-NIL if NAME is possibly the name of a folder.
-  ;; A name can be a folder name if it begins with "+".
+  ;; A name (a string or symbol) can be a folder name if it begins with "+".
   (if (symbolp name)
       (eql (aref (symbol-name name) 0) ?+)
       (eql (aref name 0) ?+)))
@@ -2458,10 +2548,11 @@ Use \\[kill-buffer] if you don't want to delete the draft message file."
   (save-excursion
     (set-buffer (get-buffer-create " *mh-temp*"))
     (erase-buffer))
-  (let ((process (apply 'start-process
-                       command nil
-                       (expand-file-name command mh-progs)
-                       (mh-list-to-string args))))
+  (let* ((process-connection-type nil)
+        (process (apply 'start-process
+                        command nil
+                        (expand-file-name command mh-progs)
+                        (mh-list-to-string args))))
     (set-process-filter process 'mh-process-daemon)))
 
 
@@ -2531,16 +2622,16 @@ Use \\[kill-buffer] if you don't want to delete the draft message file."
 ;;; User prompting commands.
 
 (defun mh-prompt-for-folder (prompt default can-create)
-  ;; Prompt for a folder name with PROMPT.  Returns the folder's name.
-  ;; DEFAULT is used if the folder exists and the user types return.
-  ;; If the CAN-CREATE flag is t, then a non-existant folder is made.
+  ;; Prompt for a folder name with PROMPT.  Returns the folder's name as a
+  ;; string.  DEFAULT is used if the folder exists and the user types return.
+  ;; If the CAN-CREATE flag is t, then a non-existent folder is made.
   (let* ((prompt (format "%s folder%s" prompt
                         (if (equal "" default)
                             "? "
                             (format " [%s]? " default))))
         name)
     (if (null mh-folder-list)
-       (setq mh-folder-list (mh-make-folder-list)))
+       (mh-set-folder-list))
     (while (and (setq name (completing-read prompt mh-folder-list
                                            nil nil "+"))
                (equal name "")
@@ -2556,17 +2647,21 @@ Use \\[kill-buffer] if you don't want to delete the draft message file."
             (message "Creating %s" name)
             (call-process "mkdir" nil nil nil (mh-expand-file-name name))
             (message "Creating %s...done" name)
-            (mh-push (list name) mh-folder-list)
-            (mh-push (list (substring name 1 nil)) mh-folder-list))
+            (mh-push (list name) mh-folder-list))
            (new-file-p
             (error "Folder %s is not created" name))
            (t
             (mh-when (null (assoc name mh-folder-list))
-              (mh-push (list name) mh-folder-list)
-              (mh-push (list (substring name 1 nil)) mh-folder-list)))))
+              (mh-push (list name) mh-folder-list)))))
     name))
 
 
+(defun mh-set-folder-list ()
+  "Sets mh-folder-list correctly.
+A useful function for the command line or for when you need to sync by hand."
+  (setq mh-folder-list (mh-make-folder-list)))
+
+
 (defun mh-make-folder-list ()
   "Return a list of the user's folders.
 Result is in a form suitable for completing read."
@@ -2687,21 +2782,15 @@ Assumes that any filename that starts with '+' is a folder name."
   ;; Returns the empty string if the field is not in the message.
   (let ((case-fold-search t))
     (goto-char (point-min))
-    (cond ((not (search-forward field nil t)) "")
+    (cond ((not (re-search-forward (format "^%s" field) nil t)) "")
          ((looking-at "[\t ]*$") "")
          (t
           (re-search-forward "[\t ]*\\([^\t \n].*\\)$" nil t)
-          (let ((field (buffer-substring (match-beginning 1)
-                                         (match-end 1)))
-                (end-of-match (point)))
-            (forward-line)
-            (while (looking-at "[ \t]") (forward-line 1))
-            (backward-char 1)
-            (if (<= (point) end-of-match)
-                field
-                (format "%s%s"
-                        field
-                        (buffer-substring end-of-match (point)))))))))
+          (let ((start (match-beginning 1)))
+            (forward-line 1)
+            (while (looking-at "[ \t]")
+              (forward-line 1))
+            (buffer-substring start (1- (point))))))))
 
 
 (defun mh-insert-fields (&rest name-values)
@@ -2725,6 +2814,7 @@ Assumes that any filename that starts with '+' is a folder name."
 (defun mh-position-on-field (field set-mark)
   ;; Set point to the end of the line beginning with FIELD.
   ;; Set the mark to the old value of point, if SET-MARK is non-nil.
+  ;; Returns non-nil iff the field was found.
   (let ((case-fold-search t))
     (if set-mark (push-mark))
     (goto-char (point-min))
@@ -2762,6 +2852,7 @@ Assumes that any filename that starts with '+' is a folder name."
 (define-key mh-folder-mode-map "\ef" 'mh-visit-folder)
 (define-key mh-folder-mode-map "\ek" 'mh-kill-folder)
 (define-key mh-folder-mode-map "\el" 'mh-list-folders)
+(define-key mh-folder-mode-map "\en" 'mh-unshar-msg)
 (define-key mh-folder-mode-map "\eo" 'mh-write-msg-to-file)
 (define-key mh-folder-mode-map "\ep" 'mh-pack-folder)
 (define-key mh-folder-mode-map "\es" 'mh-search-folder)
@@ -2779,6 +2870,7 @@ Assumes that any filename that starts with '+' is a folder name."
 (define-key mh-folder-mode-map "m" 'mh-send)
 (define-key mh-folder-mode-map "a" 'mh-reply)
 (define-key mh-folder-mode-map "j" 'mh-goto-msg)
+(define-key mh-folder-mode-map "<" 'mh-first-msg)
 (define-key mh-folder-mode-map "g" 'mh-goto-msg)
 (define-key mh-folder-mode-map "\177" 'mh-previous-page)
 (define-key mh-folder-mode-map " " 'mh-page-msg)
@@ -2832,8 +2924,8 @@ Assumes that any filename that starts with '+' is a folder name."
 
 ;;; For Gnu Emacs.
 ;;; Local Variables: ***
-;;; eval: (put 'mh-when 'lisp-indent-function 1) ***
-;;; eval: (put 'with-mh-folder-updating 'lisp-indent-function 1) ***
+;;; eval: (put 'mh-when 'lisp-indent-hook 1) ***
+;;; eval: (put 'with-mh-folder-updating 'lisp-indent-hook 1) ***
 ;;; End: ***
 
 (provide 'mh-e)