Update years in copyright notice; nfc.
[bpt/emacs.git] / lisp / mh-e / mh-e.el
index 3efe004..b5eea79 100644 (file)
@@ -1,11 +1,11 @@
 ;;; mh-e.el --- GNU Emacs interface to the MH mail system
 
 ;; Copyright (C) 1985, 86, 87, 88, 90, 92, 93, 94, 95, 97, 1999,
-;;  2000, 01, 02, 2003 Free Software Foundation, Inc.
+;;  2000, 2005 Free Software Foundation, Inc.
 
 ;; Author: Bill Wohler <wohler@newt.com>
 ;; Maintainer: Bill Wohler <wohler@newt.com>
-;; Version: 7.3+cvs
+;; Version: 7.82
 ;; Keywords: mail
 
 ;; This file is part of GNU Emacs.
 
 ;; 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@lcs.mit.edu
-;; Maintenance picked up by Bill Wohler <wohler@newt.com> and the
-;; SourceForge Crew <http://mh-e.sourceforge.net/>. 2001.
+;; Rewritten for GNU Emacs, James Larus, 1985.
+;; Modified by Stephen Gildea, 1988.
+;; Maintenance picked up by Bill Wohler and the
+;; SourceForge Crew <http://mh-e.sourceforge.net/>, 2001.
 
 ;;; Code:
 
-(require 'cl)
-
-(defvar recursive-load-depth-limit)
-(eval-when (compile load eval)
-  (if (and (boundp 'recursive-load-depth-limit)
-           (integerp recursive-load-depth-limit)
-           (> 50 recursive-load-depth-limit))
-      (setq recursive-load-depth-limit 50)))
+(provide 'mh-e)
 
-(require 'mh-inc)
+(eval-when-compile (require 'mh-acros))
+(mh-require-cl)
 (require 'mh-utils)
+(require 'mh-init)
+(require 'mh-inc)
+(require 'mh-seq)
 (require 'gnus-util)
 (require 'easymenu)
-(if mh-xemacs-flag
-    (require 'mh-xemacs-compat))
 
 ;; Shush the byte-compiler
 (defvar font-lock-auto-fontify)
 (defvar font-lock-defaults)
 
-(defconst mh-version "7.3+cvs" "Version number of MH-E.")
+(defconst mh-version "7.82" "Version number of MH-E.")
 
 ;;; Autoloads
 (autoload 'Info-goto-node "info")
 
-\f
-
-(defvar mh-note-deleted "D"
-  "String whose first character is used to notate deleted messages.")
-
-(defvar mh-note-refiled "^"
-  "String whose first character is used to notate refiled messages.")
-
-(defvar mh-note-cur "+"
-  "String whose first character is used to notate the current message.")
-
 (defvar mh-partial-folder-mode-line-annotation "select"
   "Annotation when displaying part of a folder.
 The string is displayed after the folder's name.  nil for no annotation.")
 
+\f
+;;; Scan Line Formats
+
 ;;; Parameterize MH-E to work with different scan formats.  The defaults work
 ;;; with the standard MH scan listings, in which the first 4 characters on
 ;;; the line are the message number, followed by two places for notations.
 
-;; The following scan formats are passed to the scan program if the
-;; setting of `mh-scan-format-file' above is nil.  They are identical
-;; except the later one makes use of the nmh `decode' function to
-;; decode RFC 2047 encodings. If you just want to change the width of
-;; the msg number, use the `mh-set-cmd-note' function.
+;; The following scan formats are passed to the scan program if the setting of
+;; `mh-scan-format-file' is t. They are identical except the later one makes
+;; use of the nmh `decode' function to decode RFC 2047 encodings. If you just
+;; want to change the width of the msg number, use the `mh-set-cmd-note'
+;; function.
 
 (defvar mh-scan-format-mh
   (concat
@@ -151,11 +138,10 @@ This format is identical to the default except that additional hints for
 fontification have been added to the fifth column (remember that in Emacs, the
 first column is 0).
 
-The values of the fifth column, in priority order, are: `-' if the
-message has been replied to, t if an address on the To: line matches
-one of the mailboxes of the current user, `c' if the Cc: line matches,
-`b' if the Bcc: line matches, and `n' if a non-empty Newsgroups: header
-is present.")
+The values of the fifth column, in priority order, are: `-' if the message has
+been replied to, t if an address on the To: line matches one of the
+mailboxes of the current user, `c' if the Cc: line matches, `b' if the Bcc:
+line matches, and `n' if a non-empty Newsgroups: header is present.")
 
 (defvar mh-scan-format-nmh
   (concat
@@ -177,78 +163,94 @@ This format is identical to the default except that additional hints for
 fontification have been added to the fifth column (remember that in Emacs, the
 first column is 0).
 
-The values of the fifth column, in priority order, are: `-' if the
-message has been replied to, t if an address on the To: line matches
-one of the mailboxes of the current user, `c' if the Cc: line matches,
-`b' if the Bcc: line matches, and `n' if a non-empty Newsgroups: header
-is present.")
+The values of the fifth column, in priority order, are: `-' if the message has
+been replied to, t if an address on the To: field matches one of the
+mailboxes of the current user, `c' if the Cc: field matches, `b' if the Bcc:
+field matches, and `n' if a non-empty Newsgroups: field is present.")
+
+(defvar mh-note-deleted ?D
+  "Deleted messages are marked by this character.
+See also `mh-scan-deleted-msg-regexp'.")
+
+(defvar mh-note-refiled ?^
+  "Refiled messages are marked by this character.
+See also `mh-scan-refiled-msg-regexp'.")
+
+(defvar mh-note-cur ?+
+  "The current message (in MH) is marked by this character.
+See also `mh-scan-cur-msg-number-regexp'.")
 
 (defvar mh-scan-good-msg-regexp  "^\\( *[0-9]+\\)[^D^0-9]"
-  "Regexp specifying the scan lines that are 'good' messages.
-The default `mh-folder-font-lock-keywords' expects this expression to contain
-at least one parenthesized expression which matches the message number.")
+  "This regexp specifies the scan lines that are 'good' messages.
+Note that the default setting of `mh-folder-font-lock-keywords' expects this
+expression to contain at least one parenthesized expression which matches the
+message number as in the default of \"^\\\\( *[0-9]+\\\\)[^D^0-9]\".")
 
 (defvar mh-scan-deleted-msg-regexp "^\\( *[0-9]+\\)D"
-  "Regexp matching scan lines of deleted messages.
-The default `mh-folder-font-lock-keywords' expects this expression to contain
-at least one parenthesized expression which matches the message number.")
+  "This regexp matches deleted messages.
+Note that the default setting of `mh-folder-font-lock-keywords' expects this
+expression to contain at least one parenthesized expression which matches the
+message number as in the default of \"^\\\\( *[0-9]+\\\\)D\".
+See also `mh-note-deleted'.")
 
 (defvar mh-scan-refiled-msg-regexp  "^\\( *[0-9]+\\)\\^"
-  "Regexp matching scan lines of refiled messages.
-The default `mh-folder-font-lock-keywords' expects this expression to contain
-at least one parenthesized expression which matches the message number.")
+  "This regexp matches refiled messages.
+Note that the default setting of `mh-folder-font-lock-keywords' expects this
+expression to contain at least one parenthesized expression which matches the
+message number as in the default of \"^\\\\( *[0-9]+\\\\)\\\\^\".
+See also `mh-note-refiled'.")
 
 (defvar mh-scan-valid-regexp "^ *[0-9]"
-  "Regexp matching scan lines for messages (not error messages).")
+  "This regexp matches scan lines for messages (not error messages).")
 
 (defvar mh-scan-cur-msg-number-regexp "^\\( *[0-9]+\\+\\).*"
-  "Regexp matching scan line for the current message.
-The default `mh-folder-font-lock-keywords' expects this expression to contain
-at least one parenthesized expression which matches the message number.
-Don't disable this regexp as it's needed by non fontifying functions.")
-
-(defvar mh-scan-cur-msg-regexp "^\\( *[0-9]+\\+DISABLED.*\\)"
-  "Regexp matching scan line for the current message.
-The default `mh-folder-font-lock-keywords' expects this expression to contain
-at least one parenthesized expression which matches the whole line.
-To enable this feature, remove the string DISABLED from the regexp.")
+  "This regexp matches the current message.
+Note that the default setting of `mh-folder-font-lock-keywords' expects this
+expression to contain at least one parenthesized expression which matches the
+message number as in the default of \"^\\\\( *[0-9]+\\\\+\\\\).*\". Don't
+disable this regexp as it's needed by non-fontifying functions.
+See also `mh-note-cur'.")
 
 (defvar mh-scan-date-regexp "\\([0-9][0-9]/[0-9][0-9]\\)"
-  "Regexp matching a valid date in scan lines.
-The default `mh-folder-font-lock-keywords' expects this expression to contain
-only one parenthesized expression which matches the date field
-\(see `mh-scan-format-regexp').")
+  "This regexp matches a valid date.
+Note that the default setting of `mh-folder-font-lock-keywords' expects this
+expression to contain only one parenthesized expression which matches the date
+field as in the default of \"\\\\([0-9][0-9]/[0-9][0-9]\\\\)\"}.
+See also `mh-scan-format-regexp'.")
 
 (defvar mh-scan-rcpt-regexp  "\\(To:\\)\\(..............\\)"
-  "Regexp specifying the recipient in scan lines for messages we sent.
-The default `mh-folder-font-lock-keywords' expects this expression to contain
-two parenthesized expressions.  The first is expected to match the To:
-that the default scan format file generates.  The second is expected to match
-the recipient's name.")
+  "This regexp specifies the recipient in messages you sent.
+Note that the default setting of `mh-folder-font-lock-keywords'
+expects this expression to contain two parenthesized expressions. The
+first is expected to match the `To:' that the default scan format
+file generates. The second is expected to match the recipient's name
+as in the default of \"\\\\(To:\\\\)\\\\(..............\\\\)\".")
 
 (defvar mh-scan-body-regexp "\\(<<\\([^\n]+\\)?\\)"
-  "Regexp matching the message body beginning displayed in scan lines.
-The default `mh-folder-font-lock-keywords' expects this expression to contain
-at least one parenthesized expression which matches the body text.")
+  "This regexp matches the message body fragment displayed in scan lines.
+Note that the default setting of `mh-folder-font-lock-keywords' expects this
+expression to contain at least one parenthesized expression which matches the
+body text as in the default of \"\\\\(<<\\\\([^\\n]+\\\\)?\\\\)\".")
 
 (defvar mh-scan-subject-regexp
-  ;;"^ *[0-9]+........[ ]*...................\\([Rr][Ee]:\\s-*\\)*\\([^<\n]*\\)"
   "^ *[0-9]+........[ ]*...................\\([Rr][Ee]\\(\\[[0-9]+\\]\\)?:\\s-*\\)*\\([^<\n]*\\)"
-  "*Regexp matching the subject string in MH folder mode.
-The default `mh-folder-font-lock-keywords' expects this expression to contain
-at least tree parenthesized expressions. The first is expected to match the Re:
-string, if any. The second matches an optional bracketed number after Re,
-such as in Re[2]: and the third is expected to match the subject line itself.")
+  "This regexp matches the subject.
+Note that the default setting of `mh-folder-font-lock-keywords' expects this
+expression to contain at least three parenthesized expressions. The first is
+expected to match the `Re:' string, if any. The second matches an optional
+bracketed number after `Re:', such as in `Re[2]:' (and is thus a
+sub-expression of the first expression) and the third is expected to match
+the subject line itself as in the default of \"^ *[0-9]+........[ ]*...................\\\\([Rr][Ee]\\\\(\\\\\\=[[0-9]+\\\\]\\\\)?:\\\\s-*\\\\)*\\\\([^<\\n]*\\\\)\".")
 
 (defvar mh-scan-format-regexp
   (concat "\\([bct]\\)" mh-scan-date-regexp " *\\(..................\\)")
-  "Regexp matching the output of scan.
-The default value is based upon the default values of either
-`mh-scan-format-mh' or `mh-scan-format-nmh'.
-The default `mh-folder-font-lock-keywords' expects this expression to contain
-at least three parenthesized expressions. The first should match the
-fontification hint, the second is found in `mh-scan-date-regexp', and the
-third should match the user name.")
+  "This regexp matches the output of scan.
+Note that the default setting of `mh-folder-font-lock-keywords' expects this
+expression to contain at least three parenthesized expressions. The first
+should match the fontification hint, the second is found in
+`mh-scan-date-regexp', and the third should match the user name as in the
+default of \"(concat \"\\\\([bct]\\\\)\" mh-scan-date-regexp
+                     \"*\\\\(..................\\\\)\")\".")
 
 \f
 
@@ -280,12 +282,7 @@ third should match the user name.")
    ;; scan font-lock name
    (list mh-scan-format-regexp
          '(1 mh-folder-date-face)
-         '(3 mh-folder-scan-format-face))
-   ;; Current message line
-   (list mh-scan-cur-msg-regexp
-         '(1 mh-folder-cur-msg-face prepend t))
-   ;; Unseen messages in bold
-   '(mh-folder-font-lock-unseen (1 'bold append t)))
+         '(3 mh-folder-scan-format-face)))
   "Regexp keywords used to fontify the MH-Folder buffer.")
 
 (defvar mh-scan-cmd-note-width 1
@@ -359,90 +356,61 @@ This column will only ever have spaces in it.")
 
 ;; Fontifify unseen mesages in bold.
 
-(defvar mh-folder-unseen-seq-name nil
-  "Name of unseen sequence.
-The default for this is provided by the function `mh-folder-unseen-seq-name'
-On nmh systems.")
-
-(defun mh-folder-unseen-seq-name ()
-  "Provide name of unseen sequence from mhparam."
-  (or mh-progs (mh-find-path))
-  (save-excursion
-    (let ((unseen-seq-name "unseen"))
-      (with-temp-buffer
-        (unwind-protect
-            (progn
-              (call-process (expand-file-name "mhparam" mh-progs)
-                            nil '(t t) nil "-component" "Unseen-Sequence")
-              (goto-char (point-min))
-              (if (re-search-forward "Unseen-Sequence: \\(.*\\)$" nil t)
-                  (setq unseen-seq-name (match-string 1))))))
-      unseen-seq-name)))
-
-(defun mh-folder-unseen-seq-list ()
-  "Return a list of unseen message numbers for current folder."
-  (if (not mh-folder-unseen-seq-name)
-      (setq mh-folder-unseen-seq-name (mh-folder-unseen-seq-name)))
-  (cond
-   ((not mh-folder-unseen-seq-name)
-    nil)
-   (t
-    (let ((folder mh-current-folder))
-      (save-excursion
-        (with-temp-buffer
-          (unwind-protect
-              (progn
-                (call-process (expand-file-name "mark" mh-progs)
-                              nil '(t t) nil
-                              folder "-seq" mh-folder-unseen-seq-name
-                              "-list")
-                (goto-char (point-min))
-                (sort (mh-read-msg-list) '<)))))))))
-
-(defvar mh-folder-unseen-seq-cache nil
-  "Internal cache variable used for font-lock in MH-E.
+(defmacro mh-generate-sequence-font-lock (seq prefix face)
+  "Generate the appropriate code to fontify messages in SEQ.
+PREFIX is used to generate unique names for the variables and functions
+defined by the macro. So a different prefix should be provided for every
+invocation.
+FACE is the font-lock face used to display the matching scan lines."
+  (let ((cache (intern (format "mh-folder-%s-seq-cache" prefix)))
+        (func (intern (format "mh-folder-font-lock-%s" prefix))))
+    `(progn
+       (defvar ,cache nil
+         "Internal cache variable used for font-lock in MH-E.
 Should only be non-nil through font-lock stepping, and nil once font-lock
 is done highlighting.")
-(make-variable-buffer-local 'mh-folder-unseen-seq-cache)
-
-(defun mh-folder-font-lock-unseen (limit)
-  "Return unseen message lines to font-lock between point and LIMIT."
-  (if (not mh-folder-unseen-seq-cache)
-      (setq mh-folder-unseen-seq-cache (mh-folder-unseen-seq-list)))
-  (let ((cur-msg (mh-get-msg-num nil)))
-    (cond
-     ((not mh-folder-unseen-seq-cache)
-      nil)
-     ((>= (point) limit)                 ;Presumably at end of buffer
-      (setq mh-folder-unseen-seq-cache nil)
-      nil)
-     ((member cur-msg mh-folder-unseen-seq-cache)
-      (let ((bpoint (progn (beginning-of-line)(point)))
-            (epoint (progn (forward-line 1)(point))))
-        (if (<= limit (point))
-            (setq  mh-folder-unseen-seq-cache nil))
-        (set-match-data (list bpoint epoint bpoint epoint))
-        t))
-     (t
-      ;; move forward one line at a time, checking each message number.
-      (while (and
-              (= 0 (forward-line 1))
-              (> limit (point))
-              (not (member (mh-get-msg-num nil) mh-folder-unseen-seq-cache))))
-      ;; Examine how we must have exited the loop...
-      (let ((cur-msg (mh-get-msg-num nil)))
-        (cond
-         ((or (<= limit (point))
-              (not (member cur-msg mh-folder-unseen-seq-cache)))
-          (setq mh-folder-unseen-seq-cache nil)
-          nil)
-         ((member cur-msg mh-folder-unseen-seq-cache)
-          (let ((bpoint (progn (beginning-of-line)(point)))
-                (epoint (progn (forward-line 1)(point))))
-            (if (<= limit (point))
-                (setq  mh-folder-unseen-seq-cache nil))
-            (set-match-data (list bpoint epoint bpoint epoint))
-            t))))))))
+       (make-variable-buffer-local ',cache)
+
+       (defun ,func (limit)
+         "Return unseen message lines to font-lock between point and LIMIT."
+         (if (not ,cache) (setq ,cache (mh-seq-msgs (mh-find-seq ,seq))))
+         (let ((cur-msg (mh-get-msg-num nil)))
+           (cond ((not ,cache)
+                  nil)
+                 ((>= (point) limit)              ;Presumably at end of buffer
+                  (setq ,cache nil)
+                  nil)
+                 ((member cur-msg ,cache)
+                  (let ((bpoint (progn (beginning-of-line)(point)))
+                        (epoint (progn (forward-line 1)(point))))
+                    (if (<= limit (point)) (setq  ,cache nil))
+                    (set-match-data (list bpoint epoint bpoint epoint))
+                    t))
+                 (t
+                  ;; move forward one line at a time, checking each message
+                  (while (and (= 0 (forward-line 1))
+                              (> limit (point))
+                              (not (member (mh-get-msg-num nil) ,cache))))
+                  ;; Examine how we must have exited the loop...
+                  (let ((cur-msg (mh-get-msg-num nil)))
+                    (cond ((or (<= limit (point))
+                               (not (member cur-msg ,cache)))
+                           (setq ,cache nil)
+                           nil)
+                          ((member cur-msg ,cache)
+                           (let ((bpoint (progn (beginning-of-line) (point)))
+                                 (epoint (progn (forward-line 1) (point))))
+                             (if (<= limit (point)) (setq ,cache nil))
+                             (set-match-data
+                              (list bpoint epoint bpoint epoint))
+                             t))))))))
+
+       (setq mh-folder-font-lock-keywords
+             (append mh-folder-font-lock-keywords
+                     (list (list ',func (list 1 '',face 'prepend t))))))))
+
+(mh-generate-sequence-font-lock mh-unseen-seq unseen bold)
+(mh-generate-sequence-font-lock mh-tick-seq tick mh-folder-tick-face)
 
 \f
 
@@ -464,20 +432,15 @@ is done highlighting.")
 
 (defvar mh-next-direction 'forward)     ;Direction to move to next message.
 
-(defvar mh-narrowed-to-seq nil)         ;Sequence display is narrowed to or
-                                        ;nil if not narrowed.
-
-(defvar mh-tick-seq-changed-when-narrowed-flag nil)
-                                        ;Has tick sequence changed while the
-                                        ;folder was narrowed to it?
-
 (defvar mh-view-ops ())                 ;Stack of ops that change the folder
                                         ;view (such as narrowing or threading).
+(defvar mh-folder-view-stack ())        ;Stack of previous folder views.
 
 (defvar mh-index-data nil)              ;Info about index search results
 (defvar mh-index-previous-search nil)
 (defvar mh-index-msg-checksum-map nil)
 (defvar mh-index-checksum-origin-map nil)
+(defvar mh-index-sequence-search-flag nil)
 
 (defvar mh-first-msg-num nil)           ;Number of first msg in buffer.
 
@@ -485,6 +448,12 @@ is done highlighting.")
 
 (defvar mh-mode-line-annotation nil)    ;Message range displayed in buffer.
 
+(defvar mh-sequence-notation-history nil)
+                                        ;Rememeber original notation that
+                                        ;is overwritten by `mh-note-seq'.
+
+(defvar mh-colors-available-flag nil)   ;Are colors available?
+
 ;;; Macros and generic functions:
 
 (defun mh-mapc (function list)
@@ -494,15 +463,15 @@ is done highlighting.")
     (setq list (cdr list))))
 
 (defun mh-scan-format ()
-  "Return \"-format\" argument for the scan program."
+  "Return the output format argument for the scan program."
   (if (equal mh-scan-format-file t)
-      (list "-format" (if mh-nmh-flag
+      (list "-format" (if (mh-variant-p 'nmh 'mu-mh)
                           (list (mh-update-scan-format
                                  mh-scan-format-nmh mh-cmd-note))
                         (list (mh-update-scan-format
                                mh-scan-format-mh mh-cmd-note))))
     (if (not (equal mh-scan-format-file nil))
-        (list "-format" mh-scan-format-file))))
+        (list "-form" mh-scan-format-file))))
 
 \f
 
@@ -512,7 +481,7 @@ is done highlighting.")
 (defun mh-rmail (&optional arg)
   "Inc(orporate) new mail with MH.
 Scan an MH folder if ARG is non-nil. This function is an entry point to MH-E,
-the Emacs front end to the MH mail system."
+the Emacs interface to the MH mail system."
   (interactive "P")
   (mh-find-path)
   (if arg
@@ -525,7 +494,7 @@ the Emacs front end to the MH mail system."
 (defun mh-nmail (&optional arg)
   "Check for new mail in inbox folder.
 Scan an MH folder if ARG is non-nil. This function is an entry point to MH-E,
-the Emacs front end to the MH mail system."
+the Emacs interface to the MH mail system."
   (interactive "P")
   (mh-find-path)                        ; init mh-inbox
   (if arg
@@ -536,34 +505,29 @@ the Emacs front end to the MH mail system."
 
 ;;; User executable MH-E commands:
 
-(defun mh-delete-msg (msg-or-seq)
-  "Mark the specified MSG-OR-SEQ for subsequent deletion and move to the next.
-Default is the displayed message.
-If optional prefix argument is provided, then prompt for the message sequence.
-If variable `transient-mark-mode' is non-nil and the mark is active, then the
-selected region is marked for deletion.
-In a program, MSG-OR-SEQ can be a message number, a list of message numbers, a
-region in a cons cell, or a sequence."
-  (interactive (list (mh-interactive-msg-or-seq "Delete")))
-  (mh-delete-msg-no-motion msg-or-seq)
-  (mh-next-msg))
-
-(defun mh-delete-msg-no-motion (msg-or-seq)
-  "Mark the specified MSG-OR-SEQ for subsequent deletion.
+(defun mh-delete-msg (range)
+  "Mark the specified RANGE for subsequent deletion and move to the next.
 Default is the displayed message.
-If optional prefix argument is provided, then prompt for the message sequence.
-If variable `transient-mark-mode' is non-nil and the mark is active, then the
-selected region is marked for deletion.
-In a program, MSG-OR-SEQ can be a message number, a list of message numbers, a
-region in a cons cell, or a sequence."
-  (interactive (list (mh-interactive-msg-or-seq "Delete")))
-  (mh-iterate-on-msg-or-seq () msg-or-seq
+
+Check the documentation of `mh-interactive-range' to see how RANGE is read in
+interactive use."
+  (interactive (list (mh-interactive-range "Delete")))
+  (mh-delete-msg-no-motion range)
+  (if (looking-at mh-scan-deleted-msg-regexp) (mh-next-msg)))
+
+(defun mh-delete-msg-no-motion (range)
+  "Mark the specified RANGE for subsequent deletion.
+
+Check the documentation of `mh-interactive-range' to see how RANGE is read in
+interactive use."
+  (interactive (list (mh-interactive-range "Delete")))
+  (mh-iterate-on-range () range
     (mh-delete-a-msg nil)))
 
 (defun mh-execute-commands ()
   "Process outstanding delete and refile requests."
   (interactive)
-  (if mh-narrowed-to-seq (mh-widen))
+  (if mh-folder-view-stack (mh-widen t))
   (mh-process-commands mh-current-folder)
   (mh-set-scan-mode)
   (mh-goto-cur-msg)                    ; after mh-set-scan-mode for efficiency
@@ -614,6 +578,7 @@ Do not call this function from outside MH-E; use \\[mh-rmail] instead."
       (setq folder mh-inbox))
   (let ((threading-needed-flag nil))
     (let ((config (current-window-configuration)))
+      (delete-other-windows)
       (cond ((not (get-buffer folder))
              (mh-make-folder folder)
              (setq threading-needed-flag mh-show-threads-flag)
@@ -626,7 +591,7 @@ Do not call this function from outside MH-E; use \\[mh-rmail] instead."
                (save-excursion
                  (goto-char (point-min))
                  (or (null mh-large-folder)
-                     (not (equal (forward-line mh-large-folder) 0))
+                     (not (equal (forward-line (1+ mh-large-folder)) 0))
                      (and (message "Not threading since the number of messages exceeds `mh-large-folder'")
                           nil))))
       (mh-toggle-threads))
@@ -657,47 +622,36 @@ last undeleted message then pause for a second after printing message."
            (if wait-after-complaining-flag (sit-for 1)))))
 
 (defun mh-folder-from-address ()
-  "Determine folder name from address in From field.
-Takes the address in the From: header field, and returns one of:
+  "Derive folder name from sender.
 
-  a) The folder name associated with the address in the alist
-     `mh-default-folder-list'.  If the `Check Recipient' boolean
-      is set, then the `mh-default-folder-list' addresses are
-      checked against the recipient instead of the originator
-      (making possible to use this feature for mailing lists).
-      The first match found in `mh-default-folder-list' is used.
+The name of the folder is derived as follows:
 
-  b) The address' corresponding alias from the user's personal
-     aliases file prefixed by `mh-default-folder-prefix'.
+  a) The folder name associated with the first address found in the list
+     `mh-default-folder-list' is used. Each element in this list contains a
+     `Check Recipient' item. If this item is turned on, then the address is
+     checked against the recipient instead of the sender. This is useful for
+     mailing lists.
 
-Returns nil if the address was not found in either place or if the variable
-`mh-default-folder-must-exist-flag' is nil and the folder does not exist."
+  b) An alias prefixed by `mh-default-folder-prefix' corresponding to the
+     address is used. The prefix is used to prevent clutter in your mail
+     directory.
+
+Return nil if a folder name was not derived, or if the variable
+`mh-default-folder-must-exist-flag' is t and the folder does not exist."
   ;; Loop for all entries in mh-default-folder-list
-  (save-excursion
-    (let ((folder-name
-           (car
-            (delq nil
-                  (mapcar
-                   (lambda (list)
-                     (let ((address-regexp (nth 0 list))
-                           (folder (nth 1 list))
-                           (to-flag (nth 2 list)))
-                       (when (or
-                              (mh-goto-header-field (if to-flag "To:" "From:"))
-                              ; if the To: field is missing, try Cc:
-                              (and to-flag (mh-goto-header-field "cc:")))
-                         (let ((endfield (save-excursion
-                                           (mh-header-field-end)(point))))
-                           (if (re-search-forward address-regexp endfield t)
-                               folder
-                             (when to-flag ;Try Cc: as well
-                               (mh-goto-header-field "cc:")
-                               (let ((endfield (save-excursion
-                                                 (mh-header-field-end)(point))))
-                                 (when (re-search-forward
-                                        address-regexp endfield t)
-                                   folder))))))))
-                   mh-default-folder-list)))))
+  (save-restriction
+    (goto-char (point-min))
+    (re-search-forward "\n\n" nil 'limit)
+    (narrow-to-region (point-min) (point))
+    (let ((to/cc (concat (or (message-fetch-field "to") "") ", "
+                         (or (message-fetch-field "cc") "")))
+          (from (or (message-fetch-field "from") ""))
+          folder-name)
+      (setq folder-name
+            (loop for list in mh-default-folder-list
+                  when (string-match (nth 0 list) (if (nth 2 list) to/cc from))
+                  return (nth 1 list)
+                  finally return nil))
 
       ;; Make sure a result from `mh-default-folder-list' begins with "+"
       ;; since 'mh-expand-file-name below depends on it
@@ -725,48 +679,43 @@ Returns nil if the address was not found in either place or if the variable
   "Prompt the user for a folder in which the message should be filed.
 The folder is returned as a string.
 
-If `mh-default-folder-for-message-function' is a function then the message
-being refiled is yanked into a temporary buffer and the function is called to
-intelligently guess where the message is to be refiled.
-
-Otherwise, a default folder name is generated by `mh-folder-from-address'."
+The default folder name is generated by the option
+`mh-default-folder-for-message-function' if it is non-nil or
+`mh-folder-from-address'."
   (mh-prompt-for-folder
    "Destination"
-   (let ((refile-file (mh-msg-filename (mh-get-msg-num t))))
-     (save-excursion
-       (set-buffer (get-buffer-create mh-temp-buffer))
-       (erase-buffer)
-       (insert-file-contents refile-file)
-       (or (and mh-default-folder-for-message-function
-                (let ((buffer-file-name refile-file))
-                  (funcall mh-default-folder-for-message-function)))
-           (mh-folder-from-address)
-           (and (eq 'refile (car mh-last-destination-folder))
-                (symbol-name (cdr mh-last-destination-folder)))
-           "")))
+   (let ((refile-file (ignore-errors (mh-msg-filename (mh-get-msg-num t)))))
+     (if (null refile-file) ""
+       (save-excursion
+         (set-buffer (get-buffer-create mh-temp-buffer))
+         (erase-buffer)
+         (insert-file-contents refile-file)
+         (or (and mh-default-folder-for-message-function
+                  (let ((buffer-file-name refile-file))
+                    (funcall mh-default-folder-for-message-function)))
+             (mh-folder-from-address)
+             (and (eq 'refile (car mh-last-destination-folder))
+                  (symbol-name (cdr mh-last-destination-folder)))
+             ""))))
    t))
 
-(defun mh-refile-msg (msg-or-seq folder
-                      &optional dont-update-last-destination-flag)
-  "Refile MSG-OR-SEQ into FOLDER.
-Default is the displayed message.
-If optional prefix argument is provided, then prompt for the message sequence.
-If variable `transient-mark-mode' is non-nil and the mark is active, then the
-selected region is marked for refiling.
-In a program, MSG-OR-SEQ can be a message number, a list of message numbers, a
-region in a cons cell, or a sequence.
+(defun mh-refile-msg (range folder &optional dont-update-last-destination-flag)
+  "Refile RANGE into FOLDER.
+
+Check the documentation of `mh-interactive-range' to see how RANGE is read in
+interactive use.
 
 If optional argument DONT-UPDATE-LAST-DESTINATION-FLAG is non-nil then the
 variables `mh-last-destination' and `mh-last-destination-folder' are not
 updated."
-  (interactive (list (mh-interactive-msg-or-seq "Refile")
+  (interactive (list (mh-interactive-range "Refile")
                      (intern (mh-prompt-for-refile-folder))))
   (unless dont-update-last-destination-flag
     (setq mh-last-destination (cons 'refile folder)
           mh-last-destination-folder mh-last-destination))
-  (mh-iterate-on-msg-or-seq () msg-or-seq
+  (mh-iterate-on-range () range
     (mh-refile-a-msg nil folder))
-  (mh-next-msg))
+  (when (looking-at mh-scan-refiled-msg-regexp) (mh-next-msg)))
 
 (defun mh-refile-or-write-again (message)
   "Re-execute the last refile or write command on the given MESSAGE.
@@ -886,7 +835,9 @@ are skipped."
                (setq count (1- count)))
              (not (car unread-sequence)))
            (message "No more unread messages"))
-          (t (mh-goto-msg (car unread-sequence))))))
+          (t (loop for msg in unread-sequence
+                   when (mh-goto-msg msg t) return nil
+                   finally (message "No more unread messages"))))))
 
 (defun mh-goto-next-button (backward-flag &optional criterion)
   "Search for next button satisfying criterion.
@@ -1015,11 +966,14 @@ end of buffer is reached) and save it."
   (when (consp part-index) (setq part-index (car part-index)))
   (mh-folder-mime-action part-index #'mh-mime-save-part nil))
 
+(defvar mh-thread-scan-line-map-stack)
+
 (defun mh-reset-threads-and-narrowing ()
   "Reset all variables pertaining to threads and narrowing.
 Also removes all content from the folder buffer."
   (setq mh-view-ops ())
-  (setq mh-narrowed-to-seq nil)
+  (setq mh-folder-view-stack ())
+  (setq mh-thread-scan-line-map-stack ())
   (let ((buffer-read-only nil)) (erase-buffer)))
 
 (defun mh-rescan-folder (&optional range dont-exec-pending)
@@ -1029,7 +983,8 @@ messages to display. Otherwise show the entire folder.
 If optional argument DONT-EXEC-PENDING is non-nil then pending deletes and
 refiles aren't carried out."
   (interactive (list (if current-prefix-arg
-                         (mh-read-msg-range mh-current-folder t)
+                         (mh-read-range "Rescan" mh-current-folder t nil t
+                                        mh-interpret-number-as-range-flag)
                        nil)))
   (setq mh-next-direction 'forward)
   (let ((threaded-flag (memq 'unthread mh-view-ops)))
@@ -1073,16 +1028,13 @@ Otherwise send the entire message including the headers."
       (mh-set-scan-mode)
     (mh-show)))
 
-(defun mh-undo (msg-or-seq)
-  "Undo the pending deletion or refile of the specified MSG-OR-SEQ.
-Default is the displayed message.
-If optional prefix argument is provided, then prompt for the message sequence.
-If variable `transient-mark-mode' is non-nil and the mark is active, then the
-selected region is unmarked.
-In a program, MSG-OR-SEQ can be a message number, a list of message numbers, a
-region in a cons cell, or a sequence."
-  (interactive (list (mh-interactive-msg-or-seq "Undo")))
-  (cond ((numberp msg-or-seq)
+(defun mh-undo (range)
+  "Undo the pending deletion or refile of the specified RANGE.
+
+Check the documentation of `mh-interactive-range' to see how RANGE is read in
+interactive use."
+  (interactive (list (mh-interactive-range "Undo")))
+  (cond ((numberp range)
          (let ((original-position (point)))
            (beginning-of-line)
            (while (not (or (looking-at mh-scan-deleted-msg-regexp)
@@ -1098,12 +1050,12 @@ region in a cons cell, or a sequence."
                  (mh-maybe-show))
              (goto-char original-position)
              (error "Nothing to undo"))))
-        (t (mh-iterate-on-msg-or-seq () msg-or-seq
+        (t (mh-iterate-on-range () range
              (mh-undo-msg nil))))
   (if (not (mh-outstanding-commands-p))
       (mh-set-folder-modified-p nil)))
 
-;;;###mh-autoload
+
 (defun mh-folder-line-matches-show-buffer-p ()
   "Return t if the message under point in folder-mode is in the show buffer.
 Return nil in any other circumstance (no message under point, no show buffer,
@@ -1136,7 +1088,6 @@ compiled then macro expansion happens at compile time."
 (defun mh-version ()
   "Display version information about MH-E and the MH mail handling system."
   (interactive)
-  (mh-find-progs)
   (set-buffer (get-buffer-create mh-info-buffer))
   (erase-buffer)
   ;; MH-E version.
@@ -1153,19 +1104,12 @@ compiled then macro expansion happens at compile time."
   ;; Emacs version.
   (insert (emacs-version) "\n\n")
   ;; MH version.
-  (let ((help-start (point)))
-    (condition-case err-data
-        (mh-exec-cmd-output "inc" nil (if mh-nmh-flag "-version" "-help"))
-      (file-error (insert (mapconcat 'concat (cdr err-data) ": ") "\n")))
-    (goto-char help-start)
-    (if mh-nmh-flag
-        (search-forward "inc -- " nil t)
-      (search-forward "version: " nil t))
-    (delete-region help-start (point)))
-  (goto-char (point-max))
-  (insert " mh-progs:\t" mh-progs "\n"
-          " mh-lib:\t" mh-lib "\n"
-          " mh-lib-progs:\t" mh-lib-progs "\n\n")
+  (if mh-variant-in-use
+      (insert mh-variant-in-use "\n"
+              " mh-progs:\t" mh-progs "\n"
+              " mh-lib:\t" mh-lib "\n"
+              " mh-lib-progs:\t" mh-lib-progs "\n\n")
+    (insert "No MH variant detected\n"))
   ;; Linux version.
   (condition-case ()
       (call-process "uname" nil t nil "-a")
@@ -1200,10 +1144,22 @@ used to avoid problems in corner cases involving folders whose names end with a
               (setq folder (substring folder 0 (1- (length folder)))))
             (values (format "+%s" folder) (car unseen) (car total))))))))
 
-(defun mh-folder-size (folder)
-  "Find size of FOLDER."
+(defun mh-folder-size-folder (folder)
+  "Find size of FOLDER using `folder'."
+  (with-temp-buffer
+    (let ((u (length (cdr (assoc mh-unseen-seq
+                                 (mh-read-folder-sequences folder nil))))))
+      (call-process (expand-file-name "folder" mh-progs) nil t nil
+                    "-norecurse" folder)
+      (goto-char (point-min))
+      (if (re-search-forward " has \\([0-9]+\\) " nil t)
+          (values (car (read-from-string (match-string 1))) u folder)
+        (values 0 u folder)))))
+
+(defun mh-folder-size-flist (folder)
+  "Find size of FOLDER using `flist'."
   (with-temp-buffer
-    (call-process (expand-file-name "flist" mh-progs) nil t nil
+    (call-process (expand-file-name "flist" mh-progs) nil t nil "-showzero"
                   "-norecurse" folder "-sequence" (symbol-name mh-unseen-seq))
     (goto-char (point-min))
     (multiple-value-bind (folder unseen total)
@@ -1211,6 +1167,12 @@ used to avoid problems in corner cases involving folders whose names end with a
          (buffer-substring (point) (line-end-position)))
       (values total unseen folder))))
 
+(defun mh-folder-size (folder)
+  "Find size of FOLDER."
+  (if mh-flists-present-flag
+      (mh-folder-size-flist folder)
+    (mh-folder-size-folder folder)))
+
 (defun mh-visit-folder (folder &optional range index-data)
   "Visit FOLDER and display RANGE of messages.
 Do not call this function from outside MH-E; see \\[mh-rmail] instead.
@@ -1225,10 +1187,13 @@ A prefix argument will cause a prompt for the RANGE of messages
 regardless of the size of the `mh-large-folder' variable."
   (interactive (let ((folder-name (mh-prompt-for-folder "Visit" mh-inbox t)))
                  (list folder-name
-                       (mh-read-msg-range folder-name current-prefix-arg))))
+                       (mh-read-range "Scan" folder-name t nil
+                                      current-prefix-arg
+                                      mh-interpret-number-as-range-flag))))
   (let ((config (current-window-configuration))
         (current-buffer (current-buffer))
         (threaded-view-flag mh-show-threads-flag))
+    (delete-other-windows)
     (save-excursion
       (when (get-buffer folder)
         (set-buffer folder)
@@ -1238,24 +1203,24 @@ regardless of the size of the `mh-large-folder' variable."
       (setq mh-index-data (car index-data)
             mh-index-msg-checksum-map (make-hash-table :test #'equal)
             mh-index-checksum-origin-map (make-hash-table :test #'equal))
-      (mh-index-update-maps folder (cadr index-data)))
+      (mh-index-update-maps folder (cadr index-data))
+      (mh-index-create-sequences))
     (mh-scan-folder folder (or range "all"))
     (cond ((and threaded-view-flag
                 (save-excursion
                   (goto-char (point-min))
                   (or (null mh-large-folder)
-                      (not (equal (forward-line mh-large-folder) 0))
+                      (not (equal (forward-line (1+ mh-large-folder)) 0))
                       (and (message "Not threading since the number of messages exceeds `mh-large-folder'")
                            nil))))
            (mh-toggle-threads))
           (mh-index-data
            (mh-index-insert-folder-headers)))
-    (unless mh-showing-mode (delete-other-windows))
     (unless (eq current-buffer (current-buffer))
       (setq mh-previous-window-config config)))
   nil)
 
-;;;###mh-autoload
+
 (defun mh-update-sequences ()
   "Update MH's Unseen-Sequence and current folder and message.
 Flush MH-E's state out to MH. The message at the cursor becomes current."
@@ -1326,7 +1291,7 @@ arguments, after the message has been refiled."
                (mh-exec-cmd "refile" (mh-get-msg-num t) "-link"
                             "-src" mh-current-folder
                             (symbol-name folder))
-             (message "Message not copied.")))
+             (message "Message not copied")))
           (t
            (mh-set-folder-modified-p t)
            (cond ((null (assoc folder mh-refile-list))
@@ -1373,7 +1338,9 @@ With optional argument COUNT, COUNT-1 unread messages are skipped."
                (setq count (1- count)))
              (not (car unread-sequence)))
            (message "No more unread messages"))
-          (t (mh-goto-msg (car unread-sequence))))))
+          (t (loop for msg in unread-sequence
+                   when (mh-goto-msg msg t) return nil
+                   finally (message "No more unread messages"))))))
 
 (defun mh-set-scan-mode ()
   "Display the scan listing buffer, but do not show a message."
@@ -1405,6 +1372,9 @@ If MSG is nil then act on the message at point"
 
 ;;; The folder data abstraction.
 
+(defvar mh-index-data-file ".mhe_index"
+  "MH-E specific file where index seach info is stored.")
+
 (defun mh-make-folder (name)
   "Create a new mail folder called NAME.
 Make it the current folder."
@@ -1417,6 +1387,9 @@ Make it the current folder."
   (mh-folder-mode)
   (mh-set-folder-modified-p nil)
   (setq buffer-file-name mh-folder-filename)
+  (when (and (not mh-index-data)
+             (file-exists-p (concat buffer-file-name mh-index-data-file)))
+    (mh-index-read-data))
   (mh-make-folder-mode-line))
 
 ;;; Ensure new buffers won't get this mode if default-major-mode is nil.
@@ -1437,7 +1410,7 @@ Make it the current folder."
     ["List Sequences in Folder..."      mh-list-sequences t]
     ["Delete Sequence..."               mh-delete-seq t]
     ["Narrow to Sequence..."            mh-narrow-to-seq t]
-    ["Widen from Sequence"              mh-widen mh-narrowed-to-seq]
+    ["Widen from Sequence"              mh-widen mh-folder-view-stack]
     "--"
     ["Narrow to Subject Sequence"       mh-narrow-to-subject t]
     ["Narrow to Tick Sequence"          mh-narrow-to-tick
@@ -1458,12 +1431,12 @@ Make it the current folder."
     ["Go to First Message"              mh-first-msg t]
     ["Go to Last Message"               mh-last-msg t]
     ["Go to Message by Number..."       mh-goto-msg t]
-    ["Modify Message"                   mh-modify]
+    ["Modify Message"                   mh-modify t]
     ["Delete Message"                   mh-delete-msg (mh-get-msg-num nil)]
     ["Refile Message"                   mh-refile-msg (mh-get-msg-num nil)]
-    ["Undo Delete/Refile"               mh-undo t]
-    ["Process Delete/Refile"            mh-execute-commands
-     (or mh-refile-list mh-delete-list)]
+    ["Undo Delete/Refile"               mh-undo (mh-outstanding-commands-p)]
+    ["Execute Delete/Refile"            mh-execute-commands
+     (mh-outstanding-commands-p)]
     "--"
     ["Compose a New Message"            mh-send t]
     ["Reply to Message..."              mh-reply (mh-get-msg-num nil)]
@@ -1487,7 +1460,7 @@ Make it the current folder."
     ["Incorporate New Mail"             mh-inc-folder t]
     ["Toggle Show/Folder"               mh-toggle-showing t]
     ["Execute Delete/Refile"            mh-execute-commands
-     (or mh-refile-list mh-delete-list)]
+     (mh-outstanding-commands-p)]
     ["Rescan Folder"                    mh-rescan-folder t]
     ["Thread Folder"                    mh-toggle-threads
      (not (memq 'unthread mh-view-ops))]
@@ -1512,9 +1485,6 @@ Make it the current folder."
          (set-specifier horizontal-scrollbar-visible-p nil
                         (cons (current-buffer) nil)))))
 
-;; Avoid compiler warnings in XEmacs and GNU Emacs 20
-(eval-when-compile (defvar tool-bar-mode))
-
 (defmacro mh-write-file-functions-compat ()
   "Return `write-file-functions' if it exists.
 Otherwise return `local-write-file-hooks'. This macro exists purely for
@@ -1524,8 +1494,17 @@ is used in previous versions and XEmacs."
       ''write-file-functions            ;Emacs 21.4
     ''local-write-file-hooks))          ;<Emacs 21.4, XEmacs
 
-;; Avoid compiler warning
-(defvar tool-bar-map)
+;; Avoid compiler warnings in non-bleeding edge versions of Emacs.
+(eval-when-compile
+  (defvar tool-bar-mode)
+  (defvar tool-bar-map)
+  (defvar desktop-save-buffer))         ;Emacs 21.4
+
+;; Register mh-folder-mode as supporting which-function-mode...
+(load "which-func" t t)
+(when (and (boundp 'which-func-modes)
+           (not (member 'mh-folder-mode which-func-modes)))
+  (push 'mh-folder-mode which-func-modes))
 
 (define-derived-mode mh-folder-mode fundamental-mode "MH-Folder"
   "Major MH-E mode for \"editing\" an MH folder scan listing.\\<mh-folder-mode-map>
@@ -1534,25 +1513,65 @@ You can show the message the cursor is pointing to, and step through the
 messages.  Messages can be marked for deletion or refiling into another
 folder; these commands are executed all at once with a separate command.
 
-A prefix argument (\\[universal-argument]) to delete, refile, list, or undo
-applies the action to a message sequence. If `transient-mark-mode',
-is non-nil, the action is applied to the region.
-
 Options that control this mode can be changed with \\[customize-group];
 specify the \"mh\" group. In particular, please see the `mh-scan-format-file'
 option if you wish to modify scan's format.
 
 When a folder is visited, the hook `mh-folder-mode-hook' is run.
 
+Ranges
+======
+Many commands that operate on individual messages, such as `mh-forward' or
+`mh-refile-msg' take a RANGE argument. This argument can be used in several
+ways.
+
+If you provide the prefix argument (\\[universal-argument]) to these commands,
+then you will be prompted for the message range. This can be any valid MH
+range which can include messages, sequences, and the abbreviations (described
+in the mh(1) man page):
+
+<num1>-<num2>
+    Indicates all messages in the range <num1> to <num2>, inclusive. The range
+    must be nonempty.
+
+`<num>:N'
+`<num>:+N'
+`<num>:-N'
+    Up to N messages beginning with (or ending with) message num. Num may be
+    any of the pre-defined symbols: first, prev, cur, next or last.
+
+`first:N'
+`prev:N'
+`next:N'
+`last:N'
+    The first, previous, next or last messages, if they exist.
+
+`all'
+    All of the messages.
+
+For example, a range that shows all of these things is `1 2 3 5-10 last:5
+unseen'.
+
+If the option `transient-mark-mode' is set to t and you set a region in the
+MH-Folder buffer, then the MH-E command will perform the operation on all
+messages in that region.
+
 \\{mh-folder-mode-map}"
 
   (make-local-variable 'font-lock-defaults)
   (setq font-lock-defaults '(mh-folder-font-lock-keywords t))
+  (make-local-variable 'desktop-save-buffer)
+  (setq desktop-save-buffer t)
   (mh-make-local-vars
+   'mh-colors-available-flag (mh-colors-available-p)
+                                        ; Do we have colors available
    'mh-current-folder (buffer-name)     ; Name of folder, a string
    'mh-show-buffer (format "show-%s" (buffer-name)) ; Buffer that displays msgs
    'mh-folder-filename                  ; e.g. "/usr/foobar/Mail/inbox/"
    (file-name-as-directory (mh-expand-file-name (buffer-name)))
+   'mh-display-buttons-for-inline-parts-flag
+   mh-display-buttons-for-inline-parts-flag ; Allow for display of buttons to
+                                        ; be  toggled.
    'mh-arrow-marker (make-marker)       ; Marker where arrow is displayed
    'overlay-arrow-position nil          ; Allow for simultaneous display in
    'overlay-arrow-string ">"            ;  different MH-E buffers.
@@ -1562,22 +1581,27 @@ When a folder is visited, the hook `mh-folder-mode-hook' is run.
    'mh-seq-list nil                     ; Alist of (seq . msgs) nums
    'mh-seen-list nil                    ; List of displayed messages
    'mh-next-direction 'forward          ; Direction to move to next message
-   'mh-narrowed-to-seq nil              ; Sequence display is narrowed to
-   'mh-tick-seq-changed-when-narrowed-flag nil
-                                        ; Tick seq changed while narrowed
    'mh-view-ops ()                      ; Stack that keeps track of the order
                                         ; in which narrowing/threading has been
                                         ; carried out.
+   'mh-folder-view-stack ()             ; Stack of previous views of the
+                                        ; folder.
    'mh-index-data nil                   ; If the folder was created by a call
                                         ; to mh-index-search this contains info
                                         ; about the search results.
    'mh-index-previous-search nil        ; Previous folder and search-regexp
    'mh-index-msg-checksum-map nil       ; msg -> checksum map
    'mh-index-checksum-origin-map nil    ; checksum -> ( orig-folder, orig-msg )
+   'mh-index-sequence-search-flag nil   ; folder resulted from sequence search
    'mh-first-msg-num nil                ; Number of first msg in buffer
    'mh-last-msg-num nil                 ; Number of last msg in buffer
    'mh-msg-count nil                    ; Number of msgs in buffer
    'mh-mode-line-annotation nil         ; Indicates message range
+   'mh-sequence-notation-history (make-hash-table)
+                                        ; Remember what is overwritten by
+                                        ; mh-note-seq.
+   'imenu-create-index-function 'mh-index-create-imenu-index
+                                        ; Setup imenu support
    'mh-previous-window-config nil)      ; Previous window configuration
   (mh-remove-xemacs-horizontal-scrollbar)
   (setq truncate-lines t)
@@ -1595,13 +1619,32 @@ When a folder is visited, the hook `mh-folder-mode-hook' is run.
   (easy-menu-add mh-folder-sequence-menu)
   (easy-menu-add mh-folder-message-menu)
   (easy-menu-add mh-folder-folder-menu)
-  (if (and (boundp 'tool-bar-mode) tool-bar-mode)
-      (set (make-local-variable 'tool-bar-map) mh-folder-tool-bar-map))
+  (set (make-local-variable 'tool-bar-map) mh-folder-tool-bar-map)
   (mh-funcall-if-exists mh-toolbar-init :folder)
   (if (and mh-xemacs-flag
            font-lock-auto-fontify)
       (turn-on-font-lock)))             ; Force font-lock in XEmacs.
 
+(defun mh-toggle-mime-buttons ()
+  "Toggle display of buttons for inline MIME parts."
+  (interactive)
+  (setq mh-display-buttons-for-inline-parts-flag
+        (not mh-display-buttons-for-inline-parts-flag))
+  (mh-show nil t))
+
+(defun mh-colors-available-p ()
+  "Check if colors are available in the Emacs being used."
+  (or mh-xemacs-flag
+      (let ((color-cells
+             (or (ignore-errors (mh-funcall-if-exists display-color-cells))
+                 (ignore-errors (mh-funcall-if-exists
+                                 x-display-color-cells)))))
+        (and (numberp color-cells) (>= color-cells 8)))))
+
+(defun mh-colors-in-use-p ()
+  "Check if colors are being used in the folder buffer."
+  (and mh-colors-available-flag font-lock-mode))
+
 (defun mh-make-local-vars (&rest pairs)
   "Initialize local variables according to the variable-value PAIRS."
 
@@ -1609,11 +1652,26 @@ When a folder is visited, the hook `mh-folder-mode-hook' is run.
     (set (make-local-variable (car pairs)) (car (cdr pairs)))
     (setq pairs (cdr (cdr pairs)))))
 
+;;;###autoload
+(defun mh-restore-desktop-buffer (desktop-buffer-file-name
+                                  desktop-buffer-name
+                                  desktop-buffer-misc)
+  "Restore an MH folder buffer specified in a desktop file.
+When desktop creates a buffer, DESKTOP-BUFFER-FILE-NAME holds the file name to
+visit, DESKTOP-BUFFER-NAME holds the desired buffer name, and
+DESKTOP-BUFFER-MISC holds a list of miscellaneous info used by the
+`desktop-buffer-handlers' functions."
+  (mh-find-path)
+  (mh-visit-folder desktop-buffer-name)
+  (current-buffer))
+
 (defun mh-scan-folder (folder range &optional dont-exec-pending)
   "Scan the FOLDER over the RANGE.
 If the optional argument DONT-EXEC-PENDING is non-nil then pending deletes and
 refiles aren't carried out.
 Return in the folder's buffer."
+  (when (stringp range)
+    (setq range (delete "" (split-string range "[ \t\n]"))))
   (cond ((null (get-buffer folder))
          (mh-make-folder folder))
         (t
@@ -1649,6 +1707,7 @@ If UPDATE, append the scan lines, otherwise replace."
         (range (if (and range (atom range)) (list range) range))
         scan-start)
     (message "Scanning %s..." folder)
+    (mh-remove-all-notation)
     (with-mh-folder-updating (nil)
       (if update
           (goto-char (point-max))
@@ -1665,7 +1724,9 @@ If UPDATE, append the scan lines, otherwise replace."
       (goto-char scan-start)
       (cond ((looking-at "scan: no messages in")
              (keep-lines mh-scan-valid-regexp)) ; Flush random scan lines
-            ((looking-at "scan: bad message list ")
+            ((looking-at (if (mh-variant-p 'mu-mh)
+                             "scan: message set .* does not exist"
+                           "scan: bad message list "))
              (keep-lines mh-scan-valid-regexp))
             ((looking-at "scan: "))     ; Keep error messages
             (t
@@ -1740,8 +1801,8 @@ Return in the current buffer."
         (message "inc %s..." folder))
       (setq mh-next-direction 'forward)
       (goto-char (point-max))
+      (mh-remove-all-notation)
       (let ((start-of-inc (point)))
-        (mh-remove-cur-notation)
         (if maildrop-name
             ;; I think MH 5 used "-ms-file" instead of "-file",
             ;; which would make inc'ing from maildrops fail.
@@ -1761,11 +1822,12 @@ Return in the current buffer."
                  (re-search-forward "^inc: no mail" nil t))
                (message "No new mail%s%s" (if maildrop-name " in " "")
                         (if maildrop-name maildrop-name "")))
-              ((and (when mh-narrowed-to-seq
+              ((and (when mh-folder-view-stack
                       (let ((saved-text (buffer-substring-no-properties
                                          start-of-inc (point-max))))
                         (delete-region start-of-inc (point-max))
-                        (unwind-protect (mh-widen)
+                        (unwind-protect (mh-widen t)
+                          (mh-remove-all-notation)
                           (goto-char (point-max))
                           (setq start-of-inc (point))
                           (insert saved-text)
@@ -1787,7 +1849,6 @@ Return in the current buffer."
         (setq mh-seq-list (mh-read-folder-sequences folder t))
         (when (equal (point-max) start-of-inc)
           (mh-notate-cur))
-        (mh-notate-user-sequences)
         (if new-mail-flag
             (progn
               (mh-make-folder-mode-line)
@@ -1796,7 +1857,9 @@ Return in the current buffer."
               (when (memq 'unthread mh-view-ops)
                 (mh-thread-inc folder start-of-inc))
               (mh-goto-cur-msg))
-          (goto-char point-before-inc))))))
+          (goto-char point-before-inc))
+        (mh-notate-user-sequences)
+        (mh-notate-deleted-and-refiled)))))
 
 (defun mh-make-folder-mode-line (&optional ignored)
   "Set the fields of the mode line for a folder buffer.
@@ -1839,33 +1902,48 @@ in what is now stored in the buffer-local variable `mh-mode-line-annotation'."
                                   (""))))))
       (mh-logo-display))))
 
-(defun mh-unmark-all-headers (remove-all-flags)
-  "Remove all '+' flags from the folder listing.
-With non-nil argument REMOVE-ALL-FLAGS, remove all 'D', '^' and '%' flags too.
-Optimized for speed (i.e., no regular expressions)."
-  (save-excursion
-    (let ((case-fold-search nil)
-          (last-line (1- (point-max)))
-          char)
-      (mh-first-msg)
-      (while (<= (point) last-line)
-        (forward-char mh-cmd-note)
-        (setq char (following-char))
-        (if (or (and remove-all-flags
-                     (or (= char (aref mh-note-deleted 0))
-                         (= char (aref mh-note-refiled 0))))
-                (= char (aref mh-note-cur 0)))
-            (progn
-              (delete-char 1)
-              (insert " ")))
-        (if remove-all-flags
-            (progn
-              (forward-char 1)
-              (if (= (following-char) (aref mh-note-seq 0))
-                  (progn
-                    (delete-char 1)
-                    (insert " ")))))
-        (forward-line)))))
+(defun mh-add-sequence-notation (msg internal-seq-flag)
+  "Add sequence notation to the MSG on the current line.
+If INTERNAL-SEQ-FLAG is non-nil, then refontify the scan line if font-lock is
+turned on."
+  (with-mh-folder-updating (t)
+    (save-excursion
+      (beginning-of-line)
+      (if internal-seq-flag
+          (progn
+            ;; Change the buffer so that if transient-mark-mode is active
+            ;; and there is an active region it will get deactivated as in
+            ;; the case of user sequences.
+            (mh-notate nil nil mh-cmd-note)
+            (when font-lock-mode
+              (font-lock-fontify-region (point) (line-end-position))))
+        (forward-char (1+ mh-cmd-note))
+        (let ((stack (gethash msg mh-sequence-notation-history)))
+          (setf (gethash msg mh-sequence-notation-history)
+                (cons (char-after) stack)))
+        (mh-notate nil mh-note-seq (1+ mh-cmd-note))))))
+
+(defun mh-remove-sequence-notation (msg internal-seq-flag &optional all)
+  "Remove sequence notation from the MSG on the current line.
+If INTERNAL-SEQ-FLAG is non-nil, then `font-lock' was used to highlight the
+sequence. In that case, no notation needs to be removed. Otherwise the effect
+of inserting `mh-note-seq' needs to be reversed.
+If ALL is non-nil, then all sequence marks on the scan line are removed."
+  (with-mh-folder-updating (t)
+    ;; This takes care of internal sequences...
+    (mh-notate nil nil mh-cmd-note)
+    (unless internal-seq-flag
+      ;; ... and this takes care of user sequences.
+      (let ((stack (gethash msg mh-sequence-notation-history)))
+        (while (and all (cdr stack))
+          (setq stack (cdr stack)))
+        (when stack
+          (save-excursion
+            (beginning-of-line)
+            (forward-char (1+ mh-cmd-note))
+            (delete-char 1)
+            (insert (car stack))))
+        (setf (gethash msg mh-sequence-notation-history) (cdr stack))))))
 
 (defun mh-remove-cur-notation ()
   "Remove old cur notation."
@@ -1882,14 +1960,12 @@ Optimized for speed (i.e., no regular expressions)."
   (save-excursion
     (setq overlay-arrow-position nil)
     (goto-char (point-min))
-    (while (not (eobp))
-      (unless (or (equal (char-after) ?+) (eolp))
-        (mh-notate nil ?  mh-cmd-note)
-        (when (eq (char-after (+ (point) mh-cmd-note 1)) (elt mh-note-seq 0))
-          (mh-notate nil ?  (1+ mh-cmd-note))))
-      (forward-line))))
+    (mh-iterate-on-range msg (cons (point-min) (point-max))
+      (mh-notate nil ?  mh-cmd-note)
+      (mh-remove-sequence-notation msg nil t))
+    (clrhash mh-sequence-notation-history)))
+
 
-;;;###mh-autoload
 (defun mh-goto-cur-msg (&optional minimal-changes-flag)
   "Position the cursor at the current message.
 When optional argument MINIMAL-CHANGES-FLAG is non-nil, the function doesn't
@@ -1932,22 +2008,47 @@ with no arguments, before the commands are processed."
     ;; Update the unseen sequence if it exists
     (mh-update-unseen)
 
-    (let ((redraw-needed-flag mh-index-data))
+    (let ((redraw-needed-flag mh-index-data)
+          (folders-changed (list mh-current-folder))
+          (seq-map (and mh-refile-list mh-refile-preserves-sequences-flag
+                        (mh-create-sequence-map mh-seq-list)))
+          (dest-map (and mh-refile-list mh-refile-preserves-sequences-flag
+                         (make-hash-table))))
       ;; Remove invalid scan lines if we are in an index folder and then remove
       ;; the real messages
       (when mh-index-data
         (mh-index-delete-folder-headers)
-        (mh-index-execute-commands))
+        (setq folders-changed
+              (append folders-changed (mh-index-execute-commands))))
 
       ;; Then refile messages
       (mh-mapc #'(lambda (folder-msg-list)
-                   (let ((dest-folder (symbol-name (car folder-msg-list)))
-                         (msgs (cdr folder-msg-list)))
+                   (let* ((dest-folder (symbol-name (car folder-msg-list)))
+                          (last (car (mh-translate-range dest-folder "last")))
+                          (msgs (cdr folder-msg-list)))
+                     (push dest-folder folders-changed)
                      (setq redraw-needed-flag t)
                      (apply #'mh-exec-cmd
                             "refile" "-src" folder dest-folder
                             (mh-coalesce-msg-list msgs))
-                     (mh-delete-scan-msgs msgs)))
+                     (mh-delete-scan-msgs msgs)
+                     ;; Preserve sequences in destination folder...
+                     (when (and mh-refile-preserves-sequences-flag
+                                (numberp last))
+                       (clrhash dest-map)
+                       (loop for i from (1+ last)
+                             for msg in (sort (copy-sequence msgs) #'<)
+                             do (loop for seq-name in (gethash msg seq-map)
+                                      do (push i (gethash seq-name dest-map))))
+                       (maphash
+                        #'(lambda (seq msgs)
+                            ;; Run it in the background, since we don't care
+                            ;; about the results.
+                            (apply #'mh-exec-cmd-daemon "mark" #'ignore
+                                   "-sequence" (symbol-name seq) dest-folder
+                                   "-add" (mapcar #'(lambda (x) (format "%s" x))
+                                                  (mh-coalesce-msg-list msgs))))
+                        dest-map))))
                mh-refile-list)
       (setq mh-refile-list ())
 
@@ -1967,7 +2068,7 @@ with no arguments, before the commands are processed."
       ;; Redraw folder buffer if needed
       (when (and redraw-needed-flag)
         (when (mh-speed-flists-active-p)
-          (mh-speed-flists t mh-current-folder))
+          (apply #'mh-speed-flists t folders-changed))
         (cond ((memq 'unthread mh-view-ops) (mh-thread-inc folder (point-max)))
               (mh-index-data (mh-index-insert-folder-headers)))))
 
@@ -1978,7 +2079,7 @@ with no arguments, before the commands are processed."
          (mh-invalidate-show-buffer))
 
     (setq mh-seq-list (mh-read-folder-sequences mh-current-folder nil))
-    (mh-unmark-all-headers t)
+    (mh-remove-all-notation)
     (mh-notate-user-sequences)
     (message "Processing deletes and refiles for %s...done" folder)))
 
@@ -2013,7 +2114,10 @@ with no arguments, after the unseen sequence is updated."
 
 (defun mh-outstanding-commands-p ()
   "Return non-nil if there are outstanding deletes or refiles."
-  (or mh-delete-list mh-refile-list))
+  (save-excursion
+    (when (eq major-mode 'mh-show-mode)
+      (set-buffer mh-show-folder-buffer))
+    (or mh-delete-list mh-refile-list)))
 
 (defun mh-coalesce-msg-list (messages)
   "Given a list of MESSAGES, return a list of message number ranges.
@@ -2042,7 +2146,7 @@ to avoid exceeding system command line argument limits."
 (defun mh-greaterp (msg1 msg2)
   "Return the greater of two message indicators MSG1 and MSG2.
 Strings are \"smaller\" than numbers.
-Legal values are things like \"cur\", \"last\", 1, and 1820."
+Valid values are things like \"cur\", \"last\", 1, and 1820."
   (if (numberp msg1)
       (if (numberp msg2)
           (> msg1 msg2)
@@ -2054,7 +2158,7 @@ Legal values are things like \"cur\", \"last\", 1, and 1820."
 (defun mh-lessp (msg1 msg2)
   "Return the lesser of two message indicators MSG1 and MSG2.
 Strings are \"smaller\" than numbers.
-Legal values are things like \"cur\", \"last\", 1, and 1820."
+Valid values are things like \"cur\", \"last\", 1, and 1820."
   (not (mh-greaterp msg1 msg2)))
 
 \f
@@ -2113,55 +2217,76 @@ Expands ranges into set of individual numbers."
              (setq msgs (cons num msgs)))))
     msgs))
 
-(defun mh-notate-user-sequences (&optional msg-or-seq)
-  "Mark user-defined sequences in the messages specified by MSG-OR-SEQ.
-The optional argument MSG-OR-SEQ can be a message number, a list of message
-numbers, a sequence, a region in a cons cell, or nil in which case all
-messages in the folder buffer are notated."
-  (unless msg-or-seq
-    (setq msg-or-seq (cons (point-min) (point-max))))
+(defun mh-notate-user-sequences (&optional range)
+  "Mark user-defined sequences in the messages specified by RANGE.
+The optional argument RANGE can be a message number, a list of message
+numbers, a sequence, a region in a cons cell. If nil all messages are notated."
+  (unless range
+    (setq range (cons (point-min) (point-max))))
   (let ((seqs mh-seq-list)
-        (msg-hash (make-hash-table))
-        (tick-msgs (and mh-tick-seq (mh-seq-msgs (mh-find-seq mh-tick-seq)))))
+        (msg-hash (make-hash-table)))
     (dolist (seq seqs)
-      (unless (mh-internal-seq (mh-seq-name seq))
-        (dolist (msg (mh-seq-msgs seq))
-          (setf (gethash msg msg-hash) t))))
-    (mh-iterate-on-msg-or-seq msg msg-or-seq
-      (when (gethash msg msg-hash)
-        (mh-notate nil mh-note-seq (1+ mh-cmd-note)))
-      (mh-notate-tick msg tick-msgs))))
+      (dolist (msg (mh-seq-msgs seq))
+        (push (car seq) (gethash msg msg-hash))))
+    (mh-iterate-on-range msg range
+      (loop for seq in (gethash msg msg-hash)
+            do (mh-add-sequence-notation msg (mh-internal-seq seq))))))
+
+(defvar mh-internal-seqs '(answered cur deleted forwarded printed))
 
 (defun mh-internal-seq (name)
   "Return non-nil if NAME is the name of an internal MH-E sequence."
-  (or (memq name '(answered cur deleted forwarded printed))
+  (or (memq name mh-internal-seqs)
       (eq name mh-unseen-seq)
-      (and mh-tick-seq (eq name mh-tick-seq))
+      (and (mh-colors-in-use-p) mh-tick-seq (eq name mh-tick-seq))
       (eq name mh-previous-seq)
       (mh-folder-name-p name)))
 
-(defun mh-delete-msg-from-seq (msg-or-seq sequence &optional internal-flag)
-  "Delete MSG-OR-SEQ from SEQUENCE.
-Default value of MSG-OR-SEQ is the displayed message.
-If optional prefix argument is provided, then prompt for the message sequence.
-If variable `transient-mark-mode' is non-nil and the mark is active, then the
-selected region is deleted from SEQUENCE..
-In a program, MSG-OR-SEQ can be a message number, a list of message numbers, a
-region in a cons cell, or a sequence; optional third arg INTERNAL-FLAG non-nil
-means do not inform MH of the change."
-  (interactive (list (mh-interactive-msg-or-seq "Delete")
+(defun mh-valid-seq-p (name)
+  "Return non-nil if NAME is a valid MH sequence name."
+  (and (symbolp name)
+       (string-match "^[a-zA-Z][a-zA-Z0-9]*$" (symbol-name name))))
+
+(defun mh-delete-msg-from-seq (range sequence &optional internal-flag)
+  "Delete RANGE from SEQUENCE.
+
+Check the documentation of `mh-interactive-range' to see how RANGE is read in
+interactive use.
+
+Optional third arg INTERNAL-FLAG non-nil means do not inform MH of the
+change."
+  (interactive (list (mh-interactive-range "Delete")
                      (mh-read-seq-default "Delete from" t)
                      nil))
-  (let ((entry (mh-find-seq sequence)))
+  (let ((entry (mh-find-seq sequence))
+        (user-sequence-flag (not (mh-internal-seq sequence)))
+        (folders-changed (list mh-current-folder))
+        (msg-list ()))
     (when entry
-      (mh-iterate-on-msg-or-seq msg msg-or-seq
-        (when (memq msg (mh-seq-msgs entry))
-          (mh-notate nil ?  (1+ mh-cmd-note)))
-        (mh-delete-a-msg-from-seq msg sequence internal-flag)
-        (mh-clear-text-properties nil))
-      (mh-notate-user-sequences msg-or-seq)
+      (mh-iterate-on-range msg range
+        (push msg msg-list)
+        ;; Calling "mark" repeatedly takes too long. So we will pretend here
+        ;; that we are just modifying an internal sequence...
+        (when (memq msg (cdr entry))
+          (mh-remove-sequence-notation msg (not user-sequence-flag)))
+        (mh-delete-a-msg-from-seq msg sequence t))
+      ;; ... and here we will "mark" all the messages at one go.
+      (unless internal-flag (mh-undefine-sequence sequence msg-list))
+      (when (and mh-index-data (not internal-flag))
+        (setq folders-changed
+              (append folders-changed
+                      (mh-index-delete-from-sequence sequence msg-list))))
       (when (and (eq sequence mh-unseen-seq) (mh-speed-flists-active-p))
-        (mh-speed-flists t mh-current-folder)))))
+        (apply #'mh-speed-flists t folders-changed)))))
+
+(defun mh-catchup (range)
+  "Delete RANGE from the `mh-unseen-seq' sequence.
+
+Check the document of `mh-interactive-range' to see how RANGE is read in
+interactive use."
+  (interactive (list (mh-interactive-range "Catchup"
+                                           (cons (point-min) (point-max)))))
+  (mh-delete-msg-from-seq range mh-unseen-seq))
 
 (defun mh-delete-a-msg-from-seq (msg sequence internal-flag)
   "Delete MSG from SEQUENCE.
@@ -2172,54 +2297,24 @@ If INTERNAL-FLAG is non-nil, then do not inform MH of the change."
           (mh-undefine-sequence sequence (list msg)))
       (setcdr entry (delq msg (mh-seq-msgs entry))))))
 
-(defun mh-clear-text-properties (message)
-  "Clear all text properties (except mh-tick) from the scan line for MESSAGE."
-  (save-excursion
-    (with-mh-folder-updating (t)
-      (when (or (not message) (mh-goto-msg message t t))
-        (beginning-of-line)
-        (let ((tick-property (get-text-property (point) 'mh-tick)))
-          (set-text-properties (point) (line-end-position) nil)
-          (when tick-property
-            (add-text-properties (point) (line-end-position)
-                                 `(mh-tick ,tick-property))))))))
-
 (defun mh-undefine-sequence (seq msgs)
   "Remove from the SEQ the list of MSGS."
-  (prog1 (mh-exec-cmd "mark" mh-current-folder "-delete"
-                      "-sequence" (symbol-name seq)
-                      (mh-coalesce-msg-list msgs))
-    (when (and (eq seq mh-unseen-seq) (mh-speed-flists-active-p))
-      (mh-speed-flists t mh-current-folder))))
+  (when (and (mh-valid-seq-p seq) msgs)
+    (apply #'mh-exec-cmd "mark" mh-current-folder "-delete"
+           "-sequence" (symbol-name seq) (mh-coalesce-msg-list msgs))))
 
 (defun mh-define-sequence (seq msgs)
   "Define the SEQ to contain the list of MSGS.
 Do not mark pseudo-sequences or empty sequences.
-Signals an error if SEQ is an illegal name."
+Signals an error if SEQ is an invalid name."
   (if (and msgs
+           (mh-valid-seq-p seq)
            (not (mh-folder-name-p seq)))
       (save-excursion
         (mh-exec-cmd-error nil "mark" mh-current-folder "-add" "-zero"
                            "-sequence" (symbol-name seq)
                            (mh-coalesce-msg-list msgs)))))
 
-(defun mh-map-over-seqs (function seq-list)
-  "Apply FUNCTION to each sequence in SEQ-LIST.
-The sequence name and the list of messages are passed as arguments."
-  (while seq-list
-    (funcall function
-             (mh-seq-name (car seq-list))
-             (mh-seq-msgs (car seq-list)))
-    (setq seq-list (cdr seq-list))))
-
-(defun mh-notate-if-in-one-seq (msg character offset seq)
-  "Notate MSG.
-The CHARACTER is placed at the given OFFSET from the beginning of the listing.
-The notation is performed if the MSG is only in SEQ."
-  (let ((in-seqs (mh-seq-containing-msg msg nil)))
-    (if (and (eq seq (car in-seqs)) (null (cdr in-seqs)))
-        (mh-notate msg character offset))))
-
 (defun mh-seq-containing-msg (msg &optional include-internal-flag)
   "Return a list of the sequences containing MSG.
 If INCLUDE-INTERNAL-FLAG non-nil, include MH-E internal sequences in list."
@@ -2235,31 +2330,6 @@ If INCLUDE-INTERNAL-FLAG non-nil, include MH-E internal sequences in list."
 
 \f
 
-;;; User prompting commands.
-
-(defun mh-read-msg-range (folder &optional always-prompt-flag)
-  "Prompt for message range from FOLDER.
-If optional second argument ALWAYS-PROMPT-FLAG is non-nil then always ask for
-range."
-  (multiple-value-bind (total unseen) (mh-folder-size folder)
-    (cond
-     ((and (not always-prompt-flag) (numberp unseen) (> unseen 0))
-      (list (symbol-name mh-unseen-seq)))
-     ((or (null mh-large-folder) (not (numberp total)))
-      (list "all"))
-     ((and (numberp total) (or always-prompt-flag (> total mh-large-folder)))
-      (let* ((prompt
-              (format "Range or number of messages to read (default: %s): "
-                      total))
-             (in (read-string prompt nil nil (number-to-string total))))
-        (cond ((string-match "^[ \f\t\n\r\v]*[0-9]+[ \f\t\n\r\v]*$" in)
-               (list (format "last:%s" (car (read-from-string in)))))
-              ((equal in "") (list "all"))
-              (t (split-string in)))))
-     (t (list "all")))))
-
-\f
-
 ;;; Build the folder-mode keymap:
 
 (suppress-keymap mh-folder-mode-map)
@@ -2278,6 +2348,7 @@ range."
   "'"           mh-toggle-tick
   ","           mh-header-display
   "."           mh-alt-show
+  ";"           mh-toggle-mh-decode-mime-flag
   ">"           mh-write-msg-to-file
   "?"           mh-help
   "E"           mh-extract-rejected-mail
@@ -2299,7 +2370,6 @@ range."
   "g"           mh-goto-msg
   "i"           mh-inc-folder
   "k"           mh-delete-subject-or-thread
-  "l"           mh-print-msg
   "m"           mh-alt-send
   "n"           mh-next-undeleted-msg
   "\M-n"        mh-next-unread-msg
@@ -2317,7 +2387,9 @@ range."
 
 (gnus-define-keys (mh-folder-map "F" mh-folder-mode-map)
   "?"           mh-prefix-help
+  "'"           mh-index-ticked-messages
   "S"           mh-sort-folder
+  "c"           mh-catchup
   "f"           mh-alt-visit-folder
   "i"           mh-index-search
   "k"           mh-kill-folder
@@ -2325,6 +2397,7 @@ range."
   "n"           mh-index-new-messages
   "o"           mh-alt-visit-folder
   "p"           mh-pack-folder
+  "q"           mh-index-sequenced-messages
   "r"           mh-rescan-folder
   "s"           mh-search-folder
   "u"           mh-undo-folder
@@ -2337,7 +2410,19 @@ range."
   "b"           mh-junk-blacklist
   "w"           mh-junk-whitelist)
 
+(gnus-define-keys (mh-ps-print-map "P" mh-folder-mode-map)
+  "?"           mh-prefix-help
+  "A"           mh-ps-print-toggle-mime
+  "C"           mh-ps-print-toggle-color
+  "F"           mh-ps-print-toggle-faces
+  "M"           mh-ps-print-toggle-mime
+  "f"           mh-ps-print-msg-file
+  "l"          mh-print-msg
+  "p"           mh-ps-print-msg
+  "s"           mh-ps-print-msg-show)
+
 (gnus-define-keys (mh-sequence-map "S" mh-folder-mode-map)
+  "'"           mh-narrow-to-tick
   "?"           mh-prefix-help
   "d"           mh-delete-msg-from-seq
   "k"           mh-delete-seq
@@ -2359,7 +2444,11 @@ range."
 (gnus-define-keys (mh-limit-map "/" mh-folder-mode-map)
   "'"           mh-narrow-to-tick
   "?"           mh-prefix-help
+  "c"           mh-narrow-to-cc
+  "f"           mh-narrow-to-from
+  "r"           mh-narrow-to-range
   "s"           mh-narrow-to-subject
+  "t"           mh-narrow-to-to
   "w"           mh-widen)
 
 (gnus-define-keys (mh-extract-map "X" mh-folder-mode-map)
@@ -2376,8 +2465,10 @@ range."
 (gnus-define-keys (mh-mime-map "K" mh-folder-mode-map)
   "?"           mh-prefix-help
   "a"           mh-mime-save-parts
+  "e"           mh-display-with-external-viewer
   "i"           mh-folder-inline-mime-part
   "o"           mh-folder-save-mime-part
+  "t"           mh-toggle-mime-buttons
   "v"           mh-folder-toggle-mime-part
   "\t"          mh-next-button
   [backtab]     mh-prev-button
@@ -2407,18 +2498,22 @@ range."
 (defvar mh-help-messages
   '((nil "[i]nc, [.]show, [,]show all, [n]ext, [p]revious,\n"
          "[d]elete, [o]refile, e[x]ecute,\n"
-         "[s]end, [r]eply.\n"
+         "[s]end, [r]eply,\n"
+         "[;]toggle MIME decoding.\n"
          "Prefix characters:\n [F]older, [S]equence, [J]unk, MIME [K]eys,"
-         "\n [T]hread, / Limit, e[X]tract, [D]igest, [I]nc spools.")
+         "\n [T]hread, [/]limit, e[X]tract, [D]igest, [I]nc spools.")
 
-    (?F "[l]ist, [v]isit folder;\n"
-        "[t]hread; [s]earch; [i]ndexed search;\n"
+    (?F "[l]ist; [v]isit folder;\n"
+        "[n]ew messages; [']ticked messages; [s]earch; [i]ndexed search;\n"
         "[p]ack; [S]ort; [r]escan; [k]ill")
-    (?S "[p]ut message in sequence, [n]arrow, [w]iden,\n"
+    (?P "PS [p]rint message; [l]non-PS print;\n"
+        "PS Print [s]how window, message to [f]ile;\n"
+        "Toggle printing of [M]IME parts, [C]olor, [F]aces")
+    (?S "[p]ut message in sequence, [n]arrow, [']narrow to ticked, [w]iden,\n"
         "[s]equences, [l]ist,\n"
         "[d]elete message from sequence, [k]ill sequence")
     (?T "[t]oggle, [d]elete, [o]refile thread")
-    (?/ "Limit to [s]ubject; [w]iden")
+    (?/ "Limit to [c]c, [f]rom, [r]ange, [s]ubject, [t]o; [w]iden")
     (?X "un[s]har, [u]udecode message")
     (?D "[b]urst digest")
     (?K "[v]iew, [i]nline, [o]utput/save MIME part; save [a]ll parts; \n"
@@ -2448,4 +2543,5 @@ well.")
 ;;; sentence-end-double-space: nil
 ;;; End:
 
+;;; arch-tag: cce884de-bd37-4104-9963-e4439d5ed22b
 ;;; mh-e.el ends here