emacs-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-commit] emacs/lisp/mh-e mh-utils.el mh-speed.el mh-seq....


From: Bill Wohler
Subject: [Emacs-commit] emacs/lisp/mh-e mh-utils.el mh-speed.el mh-seq....
Date: Sun, 29 Jan 2006 19:35:03 +0000

CVSROOT:        /cvsroot/emacs
Module name:    emacs
Branch:         
Changes by:     Bill Wohler <address@hidden>    06/01/29 19:34:57

Modified files:
        lisp/mh-e      : mh-utils.el mh-speed.el mh-seq.el mh-search.el 
                         mh-print.el mh-mime.el mh-junk.el mh-inc.el 
                         mh-identity.el mh-gnus.el mh-funcs.el mh-e.el 
                         mh-comp.el mh-buffers.el mh-alias.el 
                         mh-acros.el ChangeLog .cvsignore 
Added files:
        lisp/mh-e      : mh-xface.el mh-tool-bar.el mh-thread.el 
                         mh-show.el mh-scan.el mh-limit.el mh-letter.el 
                         mh-folder.el mh-compat.el 
Removed files:
        lisp/mh-e      : mh-init.el mh-exec.el mh-customize.el 

Log message:
        The Great Cleanup
        Remove circular dependencies.
        mh-e.el now includes few require statements and stands alone. Other
        files should need to require mh-e.el, which requires mh-loaddefs.el,
        plus variable-only files such as mh-scan.el.
        Remove unneeded require statements.
        Remove unneeded load statements, or replace them with non-fatal
        require statements.
        Break out components into their own files that were often spread
        between many files. As a result, many functions that are now only used
        within a single file no longer need to be autoloaded.
        Rearrange and provide consistent headings.
        Untabify.
        
        * mh-acros.el: Update commentary to reflect current usage. Add
        autoload cookies to all macros.
        (mh-require-cl): Merge docstring and comment.
        (mh-do-in-xemacs): Fix typo in docstring.
        (assoc-string): Move to new file mh-compat.el.
        (with-mh-folder-updating, mh-in-show-buffer)
        (mh-do-at-event-location, mh-seq-msgs): Move here from mh-utils.el.
        (mh-iterate-on-messages-in-region, mh-iterate-on-range): Move here
        from mh-seq.el.
        
        * mh-alias.el (mh-address-mail-regexp)
        (mh-goto-address-find-address-at-point): Move here from mh-utils.el.
        (mh-folder-line-matches-show-buffer-p): Move here from mh-e.el.
        
        * mh-buffers.el: Update descriptive text.
        
        * mh-comp.el (mh-note-repl, mh-note-forw, mh-note-dist): Move to new
        file mh-scan.el.
        (mh-yank-hooks, mh-to-field-choices, mh-position-on-field)
        (mh-letter-menu, mh-letter-mode-help-messages)
        (mh-letter-buttons-init-flag, mh-letter-mode)
        (mh-font-lock-field-data, mh-letter-header-end)
        (mh-auto-fill-for-letter, mh-to-field, mh-to-fcc)
        (mh-file-is-vcard-p, mh-insert-signature, mh-check-whom)
        (mh-insert-letter, mh-extract-from-attribution, mh-yank-cur-msg)
        (mh-filter-out-non-text, mh-insert-prefix-string)
        (mh-current-fill-prefix, mh-open-line, mh-complete-word)
        (mh-folder-expand-at-point, mh-letter-complete-function-alist)
        (mh-letter-complete, mh-letter-complete-or-space)
        (mh-letter-confirm-address, mh-letter-header-field-at-point)
        (mh-letter-next-header-field-or-indent)
        (mh-letter-next-header-field, mh-letter-previous-header-field)
        (mh-letter-skipped-header-field-p)
        (mh-letter-skip-leading-whitespace-in-header-field)
        (mh-hidden-header-keymap)
        (mh-letter-toggle-header-field-display-button)
        (mh-letter-toggle-header-field-display)
        (mh-letter-truncate-header-field, mh-letter-mode-map): Move to new
        file mh-letter.el.
        (mh-letter-mode-map, mh-sent-from-folder, mh-send-args)
        (mh-pgp-support-flag, mh-x-mailer-string)
        (mh-letter-header-field-regexp): Move to mh-e.el.
        (mh-goto-header-field, mh-goto-header-end)
        (mh-extract-from-header-value, mh-beginning-of-word): Move to
        mh-utils.el.
        (mh-insert-header-separator): Move to mh-comp.el.
        (mh-display-completion-list-compat): Move to new file mh-compat.el.
        
        * mh-compat.el: New file.
        (assoc-string): Move here from mh-acros.el.
        (mh-display-completion-list): Move here from mh-comp.el.
        
        * mh-customize.el: Move content into mh-e.el and remove.
        
        * mh-e.el (mh-folder-mode-map, mh-folder-seq-tool-bar-map)
        (mh-folder-tool-bar-map, mh-inc-spool-map, mh-letter-mode-map)
        (mh-letter-tool-bar-map, mh-search-mode-map, mh-show-mode-map)
        (mh-show-seq-tool-bar-map, mh-show-tool-bar-map): All maps now
        declared here so that they can be used in docstrings.
        (mh-sent-from-folder, mh-sent-from-msg)
        (mh-letter-header-field-regexp, mh-pgp-support-flag)
        (mh-x-mailer-string): Move here from mh-comp.el.
        (mh-folder-line-matches-show-buffer-p): Move to mh-alias.el.
        (mh-thread-scan-line-map, mh-thread-scan-line-map-stack): Move here
        from mh-seq.el.
        (mh-draft-folder, mh-inbox, mh-user-path, mh-current-folder)
        (mh-previous-window-config, mh-seen-list, mh-seq-list)
        (mh-show-buffer, mh-showing-mode, mh-globals-hash)
        (mh-show-folder-buffer, mh-mail-header-separator)
        (mh-unseen-seq, mh-previous-seq, mh-page-to-next-msg-flag)
        (mh-signature-separator, mh-signature-separator-regexp)
        (mh-list-to-string, mh-list-to-string-1): Move here from mh-utils.el.
        (mh-index-max-cmdline-args, mh-xargs, mh-quote-for-shell)
        (mh-exec-cmd, mh-exec-cmd-error, mh-exec-cmd-daemon)
        (mh-exec-cmd-env-daemon, mh-process-daemon, mh-exec-cmd-quiet)
        (mh-exec-cmd-output)
        (mh-exchange-point-and-mark-preserving-active-mark)
        (mh-exec-lib-cmd-output, mh-handle-process-error): Move here from
        deprecated file mh-exec.el.
        (mh-path): Move here from deprecated file mh-customize.el.
        (mh-sys-path, mh-variants, mh-variant-in-use, mh-progs, mh-lib)
        (mh-flists-present-flag, mh-variants, mh-variant-mh-info)
        (mh-variant-mu-mh-info, mh-variant-nmh-info, mh-file-command-p)
        (mh-variant-set-variant, mh-variant-p, mh-profile-component)
        (mh-profile-component-value, mh-defface-compat): Move here from
        deprecated file mh-init.el.
        (mh-goto-next-button, mh-folder-mime-action)
        (mh-folder-toggle-mime-part, mh-folder-inline-mime-part)
        (mh-folder-save-mime-part, mh-toggle-mime-buttons): Move to to
        mh-mime.el.
        (mh-scan-format-mh, mh-scan-format-nmh, mh-note-deleted)
        (mh-note-refiled, mh-note-cur, mh-scan-good-msg-regexp)
        (mh-scan-deleted-msg-regexp, mh-scan-refiled-msg-regexp)
        (mh-scan-valid-regexp, mh-scan-cur-msg-number-regexp)
        (mh-scan-date-regexp, mh-scan-rcpt-regexp, mh-scan-body-regexp)
        (mh-scan-subject-regexp, mh-scan-sent-to-me-sender-regexp)
        (mh-scan-cmd-note-width, mh-scan-destination-width)
        (mh-scan-date-width, mh-scan-date-flag-width)
        (mh-scan-from-mbox-width, mh-scan-from-mbox-sep-width)
        (mh-scan-field-destination-offset)
        (mh-scan-field-from-start-offset, mh-scan-field-from-end-offset)
        (mh-scan-field-subject-start-offset, mh-scan-format)
        (mh-msg-num-width-to-column, mh-set-cmd-note): Move to new file
        mh-scan.el.
        (mh-partial-folder-mode-line-annotation)
        (mh-folder-font-lock-keywords, mh-folder-font-lock-subject)
        (mh-generate-sequence-font-lock, mh-last-destination)
        (mh-last-destination-write, mh-first-msg-num, mh-last-msg-num)
        (mh-rmail, mh-nmail, mh-delete-msg, mh-delete-msg-no-motion)
        (mh-execute-commands, mh-first-msg, mh-header-display)
        (mh-inc-folder, mh-last-msg, mh-next-undeleted-msg)
        (mh-folder-from-address, mh-prompt-for-refile-folder)
        (mh-refile-msg, mh-refile-or-write-again, mh-quit, mh-page-msg)
        (mh-previous-page, mh-previous-undeleted-msg)
        (mh-previous-unread-msg, mh-next-button, mh-prev-button)
        (mh-reset-threads-and-narrowing, mh-rescan-folder)
        (mh-write-msg-to-file, mh-toggle-showing, mh-undo)
        (mh-visit-folder, mh-update-sequences, mh-delete-a-msg)
        (mh-refile-a-msg, mh-next-msg, mh-next-unread-msg)
        (mh-set-scan-mode, mh-undo-msg, mh-make-folder)
        (mh-folder-sequence-menu, mh-folder-message-menu)
        (mh-folder-folder-menu, mh-remove-xemacs-horizontal-scrollbar)
        (mh-write-file-functions-compat, mh-folder-mode)
        (mh-restore-desktop-buffer, mh-scan-folder)
        (mh-regenerate-headers, mh-generate-new-cmd-note)
        (mh-get-new-mail, mh-make-folder-mode-line, mh-goto-cur-msg)
        (mh-process-or-undo-commands, mh-process-commands)
        (mh-update-unseen, mh-delete-scan-msgs)
        (mh-outstanding-commands-p): Move to new file mh-folder.el.
        (mh-mapc, mh-colors-available-p, mh-colors-in-use-p)
        (mh-make-local-vars, mh-coalesce-msg-list, mh-greaterp)
        (mh-lessp): Move to mh-utils.el.
        (mh-parse-flist-output-line, mh-folder-size-folder)
        (mh-folder-size-flist, mh-folder-size, mh-add-sequence-notation)
        (mh-remove-sequence-notation, mh-remove-cur-notation)
        (mh-remove-all-notation, mh-delete-seq-locally)
        (mh-read-folder-sequences, mh-read-msg-list)
        (mh-notate-user-sequences, mh-internal-seqs, mh-internal-seq)
        (mh-valid-seq-p, mh-delete-msg-from-seq, mh-catchup)
        (mh-delete-a-msg-from-seq, mh-undefine-sequence)
        (mh-define-sequence, mh-seq-containing-msg): Move to mh-seq.el.
        (mh-xemacs-flag)
        (mh-customize, mh-e, mh-alias, mh-folder, mh-folder-selection)
        (mh-identity, mh-inc, mh-junk, mh-letter, mh-ranges)
        (mh-scan-line-formats, mh-search, mh-sending-mail, mh-sequences)
        (mh-show, mh-speedbar, mh-thread, mh-tool-bar, mh-hooks)
        (mh-faces, mh-alias-completion-ignore-case-flag)
        (mh-alias-expand-aliases-flag, mh-alias-flash-on-comma)
        (mh-alias-insert-file, mh-alias-insertion-location)
        (mh-alias-local-users, mh-alias-local-users-prefix)
        (mh-alias-passwd-gecos-comma-separator-flag)
        (mh-new-messages-folders, mh-ticked-messages-folders)
        (mh-large-folder, mh-recenter-summary-flag)
        (mh-recursive-folders-flag, mh-sortm-args)
        (mh-default-folder-for-message-function, mh-default-folder-list)
        (mh-default-folder-must-exist-flag, mh-default-folder-prefix)
        (mh-identity-list, mh-auto-fields-list)
        (mh-auto-fields-prompt-flag, mh-identity-default)
        (mh-identity-handlers, mh-inc-prog, mh-inc-spool-list)
        (mh-junk-choice, mh-junk-function-alist, mh-junk-choose)
        (mh-junk-background, mh-junk-disposition, mh-junk-program)
        (mh-compose-insertion, mh-compose-skipped-header-fields)
        (mh-compose-space-does-completion-flag)
        (mh-delete-yanked-msg-window-flag)
        (mh-extract-from-attribution-verb, mh-ins-buf-prefix)
        (mh-letter-complete-function, mh-letter-fill-column)
        (mh-mml-method-default, mh-signature-file-name)
        (mh-signature-separator-flag, mh-x-face-file, mh-yank-behavior)
        (mh-interpret-number-as-range-flag, mh-adaptive-cmd-note-flag)
        (mh-scan-format-file-check, mh-scan-format-file)
        (mh-adaptive-cmd-note-flag-check, mh-scan-prog)
        (mh-search-program, mh-compose-forward-as-mime-flag)
        (mh-compose-letter-function, mh-compose-prompt-flag)
        (mh-forward-subject-format, mh-insert-x-mailer-flag)
        (mh-redist-full-contents-flag, mh-reply-default-reply-to)
        (mh-reply-show-message-flag, mh-refile-preserves-sequences-flag)
        (mh-tick-seq, mh-update-sequences-after-mh-show-flag)
        (mh-bury-show-buffer-flag, mh-clean-message-header-flag)
        (mh-decode-mime-flag, mh-display-buttons-for-alternatives-flag)
        (mh-display-buttons-for-inline-parts-flag)
        (mh-do-not-confirm-flag, mh-fetch-x-image-url)
        (mh-graphical-smileys-flag, mh-graphical-emphasis-flag)
        (mh-highlight-citation-style)
        (mh-invisible-header-fields-internal)
        (mh-delay-invisible-header-generation-flag)
        (mh-invisible-header-fields, mh-invisible-header-fields-default)
        (mh-invisible-header-fields-compiled, mh-invisible-headers)
        (mh-lpr-command-format, mh-max-inline-image-height)
        (mh-max-inline-image-width, mh-mhl-format-file)
        (mh-mime-save-parts-default-directory, mh-print-background-flag)
        (mh-show-maximum-size, mh-show-use-goto-addr-flag)
        (mh-show-use-xface-flag, mh-store-default-directory)
        (mh-summary-height, mh-speed-update-interval)
        (mh-show-threads-flag, mh-tool-bar-search-function)
        (mh-after-commands-processed-hook, mh-alias-reloaded-hook)
        (mh-before-commands-processed-hook, mh-before-quit-hook)
        (mh-before-send-letter-hook, mh-delete-msg-hook)
        (mh-find-path-hook, mh-folder-mode-hook, mh-forward-hook)
        (mh-inc-folder-hook, mh-insert-signature-hook)
        (mh-kill-folder-suppress-prompt-hooks, mh-letter-mode-hook)
        (mh-mh-to-mime-hook, mh-search-mode-hook, mh-quit-hook)
        (mh-refile-msg-hook, mh-show-hook, mh-show-mode-hook)
        (mh-unseen-updated-hook, mh-min-colors-defined-flag)
        (mh-folder-address, mh-folder-body)
        (mh-folder-cur-msg-number, mh-folder-date, mh-folder-deleted)
        (mh-folder-followup, mh-folder-msg-number, mh-folder-refiled)
        (mh-folder-sent-to-me-hint, mh-folder-sent-to-me-sender)
        (mh-folder-subject, mh-folder-tick, mh-folder-to)
        (mh-search-folder, mh-letter-header-field, mh-show-cc)
        (mh-show-date, mh-show-from, mh-show-header, mh-show-pgg-bad)
        (mh-show-pgg-good, mh-show-pgg-unknown, mh-show-signature)
        (mh-show-subject, mh-show-to, mh-show-xface, mh-speedbar-folder)
        (mh-speedbar-folder-with-unseen-messages)
        (mh-speedbar-selected-folder)
        (mh-speedbar-selected-folder-with-unseen-messages): Move here from
        deprecated file mh-customize.el.
        
        * mh-exec.el: Move content into mh-e.el and remove.
        
        * mh-folder.el: New file. Contains mh-folder-mode from mh-e.el
        
        * mh-funcs.el (mh-note-copied, mh-note-printed): Move to new file
        mh-scan.el.
        (mh-ephem-message, mh-help, mh-prefix-help): Move to mh-utils.el.
        
        * mh-gnus.el (mm-uu-dissect-text-parts): Add.
        (mh-mail-abbrev-make-syntax-table): Move to mh-utils.el and rename to
        mail-abbrev-make-syntax-table.
        
        * mh-identity.el (mh-identity-menu): New variable for existing menu.
        (mh-identity-make-menu-no-autoload): New alias for
        mh-identity-make-menu which can be called from mh-e.el.
        (mh-identity-list-set): Move to mh-e.el.
        (mh-identity-add-menu): New function
        (mh-insert-identity): Add optional argument maybe-insert so that local
        variable mh-identity-local does not have to be visible.
        (mh-identity-handler-default):
        
        * mh-inc.el (mh-inc-spool-map): Move declaration to mh-e.el (with rest
        of keymaps). Update key binding for ? to call mh-help with help
        messages in new argument.
        (mh-inc-spool-make-no-autoload): New alias for mh-inc-spool-make which
        can be called from mh-e.el.
        (mh-inc-spool-list-set): Simplify update of mh-inc-spool-map-help.
        
        * mh-init.el: Move content into mh-e.el and remove.
        
        * mh-junk.el: Update requires, untabify, and add mh-autoload cookies.
        
        * mh-letter.el: New file. Contains mh-letter-mode from mh-comp.el.
        
        * mh-limit.el: New file. Contains display limit commands from
        mh-mime.el.
        
        * mh-mime.el: Rearrange for consistency with other files.
        (mh-buffer-data, mh-mm-inline-media-tests): Move here from
        mh-utils.el.
        (mh-folder-inline-mime-part, mh-folder-save-mime-part)
        (mh-folder-toggle-mime-part, mh-toggle-mime-buttons)
        (mh-goto-next-button): Move here from mh-e.el.
        
        * mh-print.el: Rearrange for consistency with other files.
        
        * mh-scan.el: New file. Contains scan line constants and utilities
        from XXX, mh-funcs, mh-utils.el.
        
        * mh-search.el: Rearrange for consistency with other files.
        (mh-search-mode-map): Drop C-c C-f {dr} bindings since these fields
        which don't exist in the saved header. Replace C-c C-f f with C-c C-f
        m per mail-mode consistency.
        (mh-search-mode): Use mh-set-help instead of setting mh-help-messages.
        
        * mh-seq.el (mh-thread-message, mh-thread-container)
        (mh-thread-id-hash, mh-thread-subject-hash, mh-thread-id-table)
        (mh-thread-id-index-map, mh-thread-index-id-map)
        (mh-thread-scan-line-map, mh-thread-scan-line-map-stack)
        (mh-thread-subject-container-hash, mh-thread-duplicates)
        (mh-thread-history, mh-thread-body-width)
        (mh-thread-find-msg-subject mh-thread-initialize-hash)
        (mh-thread-initialize, mh-thread-id-container)
        (mh-thread-remove-parent-link, mh-thread-add-link)
        (mh-thread-ancestor-p, mh-thread-get-message-container)
        (mh-thread-get-message, mh-thread-canonicalize-id)
        (mh-thread-prune-subject, mh-thread-container-subject)
        (mh-thread-rewind-pruning, mh-thread-prune-containers)
        (mh-thread-sort-containers, mh-thread-group-by-subject)
        (mh-thread-process-in-reply-to, mh-thread-set-tables)
        (mh-thread-update-id-index-maps, mh-thread-generate)
        (mh-thread-inc, mh-thread-generate-scan-lines)
        (mh-thread-parse-scan-line, mh-thread-update-scan-line-map)
        (mh-thread-add-spaces, mh-thread-print-scan-lines)
        (mh-thread-folder, mh-toggle-threads, mh-thread-forget-message)
        (mh-thread-current-indentation-level, mh-thread-next-sibling)
        (mh-thread-previous-sibling, mh-thread-immediate-ancestor)
        (mh-thread-ancestor, mh-thread-find-children)
        (mh-message-id-regexp, mh-thread-delete, mh-thread-refile): Move to
        new file mh-thread.el.
        (mh-subject-to-sequence, mh-subject-to-sequence-unthreaded)
        (mh-subject-to-sequence-threaded, mh-edit-pick-expr)
        (mh-pick-args-list, mh-narrow-to-subject, mh-narrow-to-from)
        (mh-narrow-to-cc, mh-narrow-to-to, mh-narrow-to-header-field)
        (mh-current-message-header-field, mh-narrow-to-range)
        (mh-delete-subject, mh-delete-subject-or-thread): Move to new file
        mh-limit.el.
        (mh-iterate-on-messages-in-region, mh-iterate-on-range): Move to
        mh-acros.el.
        (mh-internal-seqs, mh-catchup, mh-delete-msg-from-seq)
        (mh-internal-seq, mh-valid-seq-p, mh-seq-containing-msg)
        (mh-define-sequence, mh-undefine-sequence)
        (mh-delete-a-msg-from-seq, mh-delete-seq-locally)
        (mh-folder-size, mh-folder-size-flist, mh-folder-size-folder)
        (mh-parse-flist-output-line, mh-read-folder-sequences)
        (mh-read-msg-list, mh-notate-user-sequences)
        (mh-remove-cur-notation, mh-add-sequence-notation)
        (mh-remove-sequence-notation, mh-remove-all-notation): Move here from
        mh-e.el.
        (mh-make-seq, mh-seq-name, mh-find-seq, mh-seq-to-msgs)
        (mh-add-msgs-to-seq, mh-notate): Move here from mh-utils.el.
        
        * mh-show.el: New file. Contains mh-show-mode from mh-utils.el.
        
        * mh-speed.el: Rearrange for consistency with other files.
        
        * mh-thread.el: New file. Contains threading code from mh-seq.el.
        
        * mh-tool-bar.el: New file. Contains tool bar creation code from
        deprecated file mh-customize.el.
        
        * mh-utils.el (recursive-load-depth-limit): Remove setting. No longer
        needed.
        (mh-scan-msg-number-regexp, mh-scan-msg-overflow-regexp)
        (mh-scan-msg-format-regexp, mh-scan-msg-format-string)
        (mh-scan-msg-search-regexp, mh-cmd-note, mh-note-seq)
        (mh-update-scan-format, mh-msg-num-width): Move to new file
        mh-scan.el.
        (mh-show-buffer-mode-line-buffer-id, mh-letter-header-font-lock)
        (mh-header-field-font-lock, mh-header-to-font-lock)
        (mh-header-cc-font-lock, mh-header-subject-font-lock)
        (mh-show-font-lock-keywords)
        (mh-show-font-lock-keywords-with-cite)
        (mh-show-font-lock-fontify-region)
        (mh-gnus-article-highlight-citation, mh-showing-with-headers)
        (mh-start-of-uncleaned-message, mh-invalidate-show-buffer)
        (mh-unvisit-file, mh-defun-show-buffer, mh-show-mode-map)
        (mh-show-sequence-menu, mh-show-message-menu)
        (mh-show-folder-menu, mh-show-mode, mh-show-addr)
        (mh-maybe-show, mh-show, mh-show-msg, mh-show-unquote-From)
        (mh-msg-folder, mh-display-msg, mh-clean-msg-header): Move to new file
        mh-show.el.
        (mh-mail-header-separator, mh-signature-separator-regexp)
        (mh-signature-separator, mh-globals-hash, mh-user-path)
        (mh-draft-folder, mh-unseen-seq, mh-previous-seq, mh-inbox)
        (mh-previous-window-config, mh-current-folder mh-show-buffer)
        (mh-showing-mode, mh-show-mode-map, mh-show-folder-buffer)
        (mh-showing-mode, mh-seq-list, mh-seen-list, mh-summary-height)
        (mh-list-to-string, mh-list-to-string-1): Move to mh-e.el.
        (mh-buffer-data, mh-mm-inline-media-tests): Move to mh-mime.el.
        (mh-address-mail-regexp, mh-goto-address-find-address-at-point): Move
        to mh-alias.el.
        (mh-letter-font-lock-keywords): Move to new file mh-letter.el.
        (mh-folder-filename, mh-msg-count, mh-recenter, mh-msg-filename)
        (mh-show-mouse, mh-modify, mh-goto-msg, mh-set-folder-modified-p):
        Move to new file mh-folder.el.
        (with-mh-folder-updating, mh-in-show-buffer)
        (mh-do-at-event-location, mh-seq-msgs): Moved to mh-acros.el.
        (mh-make-seq, mh-seq-name, mh-notate, mh-find-seq)
        (mh-seq-to-msgs, mh-add-msgs-to-seq, mh-canonicalize-sequence): Moved
        to mh-seq.el.
        (mh-show-xface-function, mh-uncompface-executable, mh-face-to-png)
        (mh-uncompface, mh-icontopbm, mh-face-foreground-compat)
        (mh-face-background-compat, mh-face-display-function)
        (mh-show-xface, mh-picon-directory-list)
        (mh-picon-existing-directory-list)
        (mh-picon-cache, mh-picon-image-types)
        (mh-picon-set-directory-list, mh-picon-get-image)
        (mh-picon-file-contents, mh-picon-generate-path)
        (mh-x-image-cache-directory, mh-x-image-scaling-function)
        (mh-wget-executable, mh-wget-choice, mh-wget-option)
        (mh-x-image-temp-file, mh-x-image-url, mh-x-image-marker)
        (mh-x-image-url-cache-file, mh-x-image-scale-with-pnm)
        (mh-x-image-scale-with-convert)
        (url-unreserved-chars, url-hexify-string)
        (mh-x-image-url-cache-canonicalize)
        (mh-x-image-set-download-state, mh-x-image-get-download-state)
        (mh-x-image-url-fetch-image, mh-x-image-display)
        (mh-x-image-scale-and-display, mh-x-image-url-sane-p)
        (mh-x-image-url-display): Move to new file mh-xface.el.
        (mh-logo-display): Call mh-image-load-path.
        (mh-find-path-run, mh-find-path): Move here from deprecated file
        mh-init.el.
        (mh-help-messages): Now an alist of modes to an alist of messages.
        (mh-set-help): New function used to set mh-help-messages
        (mh-help): Adjust for new format of mh-help-messages. Add
        help-messages argument.
        (mh-prefix-help): Refactor to use mh-help.
        (mh-coalesce-msg-list, mh-greaterp, mh-lessp): Move here from mh-e.el.
        (mh-clear-sub-folders-cache): New function added to avoid exposing
        mh-sub-folders-cache variable.
        
        * mh-xface.el: New file. Contains X-Face and Face header field display
        routines from mh-utils.el.

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/emacs/emacs/lisp/mh-e/mh-xface.el?rev=1.1
http://cvs.savannah.gnu.org/viewcvs/emacs/emacs/lisp/mh-e/mh-utils.el.diff?tr1=1.42&tr2=1.43&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/emacs/emacs/lisp/mh-e/mh-tool-bar.el?rev=1.1
http://cvs.savannah.gnu.org/viewcvs/emacs/emacs/lisp/mh-e/mh-thread.el?rev=1.1
http://cvs.savannah.gnu.org/viewcvs/emacs/emacs/lisp/mh-e/mh-speed.el.diff?tr1=1.15&tr2=1.16&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/emacs/emacs/lisp/mh-e/mh-show.el?rev=1.1
http://cvs.savannah.gnu.org/viewcvs/emacs/emacs/lisp/mh-e/mh-seq.el.diff?tr1=1.27&tr2=1.28&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/emacs/emacs/lisp/mh-e/mh-search.el.diff?tr1=1.5&tr2=1.6&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/emacs/emacs/lisp/mh-e/mh-scan.el?rev=1.1
http://cvs.savannah.gnu.org/viewcvs/emacs/emacs/lisp/mh-e/mh-print.el.diff?tr1=1.16&tr2=1.17&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/emacs/emacs/lisp/mh-e/mh-mime.el.diff?tr1=1.45&tr2=1.46&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/emacs/emacs/lisp/mh-e/mh-limit.el?rev=1.1
http://cvs.savannah.gnu.org/viewcvs/emacs/emacs/lisp/mh-e/mh-letter.el?rev=1.1
http://cvs.savannah.gnu.org/viewcvs/emacs/emacs/lisp/mh-e/mh-junk.el.diff?tr1=1.18&tr2=1.19&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/emacs/emacs/lisp/mh-e/mh-inc.el.diff?tr1=1.13&tr2=1.14&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/emacs/emacs/lisp/mh-e/mh-identity.el.diff?tr1=1.25&tr2=1.26&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/emacs/emacs/lisp/mh-e/mh-gnus.el.diff?tr1=1.13&tr2=1.14&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/emacs/emacs/lisp/mh-e/mh-funcs.el.diff?tr1=1.26&tr2=1.27&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/emacs/emacs/lisp/mh-e/mh-folder.el?rev=1.1
http://cvs.savannah.gnu.org/viewcvs/emacs/emacs/lisp/mh-e/mh-e.el.diff?tr1=1.57&tr2=1.58&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/emacs/emacs/lisp/mh-e/mh-compat.el?rev=1.1
http://cvs.savannah.gnu.org/viewcvs/emacs/emacs/lisp/mh-e/mh-comp.el.diff?tr1=1.42&tr2=1.43&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/emacs/emacs/lisp/mh-e/mh-buffers.el.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/emacs/emacs/lisp/mh-e/mh-alias.el.diff?tr1=1.25&tr2=1.26&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/emacs/emacs/lisp/mh-e/mh-acros.el.diff?tr1=1.16&tr2=1.17&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/emacs/emacs/lisp/mh-e/ChangeLog.diff?tr1=1.124&tr2=1.125&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/emacs/emacs/lisp/mh-e/.cvsignore.diff?tr1=1.2&tr2=1.3&r1=text&r2=text

Patches:
Index: emacs/lisp/mh-e/.cvsignore
diff -u emacs/lisp/mh-e/.cvsignore:1.2 emacs/lisp/mh-e/.cvsignore:1.3
--- emacs/lisp/mh-e/.cvsignore:1.2      Thu Oct 13 21:46:40 2005
+++ emacs/lisp/mh-e/.cvsignore  Sun Jan 29 19:34:57 2006
@@ -1,2 +1,3 @@
 mh-autoloads.el
+mh-cus-load.el
 mh-loaddefs.el
Index: emacs/lisp/mh-e/ChangeLog
diff -u emacs/lisp/mh-e/ChangeLog:1.124 emacs/lisp/mh-e/ChangeLog:1.125
--- emacs/lisp/mh-e/ChangeLog:1.124     Tue Jan 17 16:20:29 2006
+++ emacs/lisp/mh-e/ChangeLog   Sun Jan 29 19:34:57 2006
@@ -1,3 +1,430 @@
+2006-01-29  Bill Wohler  <address@hidden>
+
+       The Great Cleanup
+       Remove circular dependencies. mh-e.el now includes few require
+       statements and stands alone. Other files should need to require
+       mh-e.el, which requires mh-loaddefs.el, plus variable-only files
+       such as mh-scan.el.
+       Remove unneeded require statements.
+       Remove unneeded load statements, or replace them with non-fatal
+       require statements.
+       Break out components into their own files that were often spread
+       between many files.
+       As a result, many functions that are now only used within a single
+       file no longer need to be autoloaded.
+       Rearrange and provide consistent headings.
+       Untabify.
+
+       * mh-acros.el: Update commentary to reflect current usage. Add
+       autoload cookies to all macros.
+       (mh-require-cl): Merge docstring and comment.
+       (mh-do-in-xemacs): Fix typo in docstring.
+       (assoc-string): Move to new file mh-compat.el.
+       (with-mh-folder-updating, mh-in-show-buffer)
+       (mh-do-at-event-location, mh-seq-msgs): Move here from
+       mh-utils.el.
+       (mh-iterate-on-messages-in-region, mh-iterate-on-range): Move here
+       from mh-seq.el.
+
+       * mh-alias.el (mh-address-mail-regexp)
+       (mh-goto-address-find-address-at-point): Move here from
+       mh-utils.el.
+       (mh-folder-line-matches-show-buffer-p): Move here from mh-e.el.
+
+       * mh-buffers.el: Update descriptive text.       
+
+       * mh-comp.el (mh-note-repl, mh-note-forw, mh-note-dist): Move to
+       new file mh-scan.el.
+       (mh-yank-hooks, mh-to-field-choices, mh-position-on-field)
+       (mh-letter-menu, mh-letter-mode-help-messages)
+       (mh-letter-buttons-init-flag, mh-letter-mode)
+       (mh-font-lock-field-data, mh-letter-header-end)
+       (mh-auto-fill-for-letter, mh-to-field, mh-to-fcc)
+       (mh-file-is-vcard-p, mh-insert-signature, mh-check-whom)
+       (mh-insert-letter, mh-extract-from-attribution, mh-yank-cur-msg)
+       (mh-filter-out-non-text, mh-insert-prefix-string)
+       (mh-current-fill-prefix, mh-open-line, mh-complete-word)
+       (mh-folder-expand-at-point, mh-letter-complete-function-alist)
+       (mh-letter-complete, mh-letter-complete-or-space)
+       (mh-letter-confirm-address, mh-letter-header-field-at-point)
+       (mh-letter-next-header-field-or-indent)
+       (mh-letter-next-header-field, mh-letter-previous-header-field)
+       (mh-letter-skipped-header-field-p)
+       (mh-letter-skip-leading-whitespace-in-header-field)
+       (mh-hidden-header-keymap)
+       (mh-letter-toggle-header-field-display-button)
+       (mh-letter-toggle-header-field-display)
+       (mh-letter-truncate-header-field, mh-letter-mode-map): Move to new
+       file mh-letter.el.
+       (mh-letter-mode-map, mh-sent-from-folder, mh-send-args)
+       (mh-pgp-support-flag, mh-x-mailer-string)
+       (mh-letter-header-field-regexp): Move to mh-e.el.
+       (mh-goto-header-field, mh-goto-header-end)
+       (mh-extract-from-header-value, mh-beginning-of-word): Move to
+       mh-utils.el.
+       (mh-insert-header-separator): Move to mh-comp.el.
+       (mh-display-completion-list-compat): Move to new file
+       mh-compat.el.
+
+       * mh-compat.el: New file.
+       (assoc-string): Move here from mh-acros.el.
+       (mh-display-completion-list): Move here from mh-comp.el.
+
+       * mh-customize.el: Move content into mh-e.el and remove.
+       
+       * mh-e.el (mh-folder-mode-map, mh-folder-seq-tool-bar-map)
+       (mh-folder-tool-bar-map, mh-inc-spool-map, mh-letter-mode-map)
+       (mh-letter-tool-bar-map, mh-search-mode-map, mh-show-mode-map)
+       (mh-show-seq-tool-bar-map, mh-show-tool-bar-map): All maps now
+       declared here so that they can be used in docstrings.
+       (mh-sent-from-folder, mh-sent-from-msg)
+       (mh-letter-header-field-regexp, mh-pgp-support-flag)
+       (mh-x-mailer-string): Move here from mh-comp.el.
+       (mh-folder-line-matches-show-buffer-p): Move to mh-alias.el.
+       (mh-thread-scan-line-map, mh-thread-scan-line-map-stack): Move
+       here from mh-seq.el.
+       (mh-draft-folder, mh-inbox, mh-user-path, mh-current-folder)
+       (mh-previous-window-config, mh-seen-list, mh-seq-list)
+       (mh-show-buffer, mh-showing-mode, mh-globals-hash)
+       (mh-show-folder-buffer, mh-mail-header-separator)
+       (mh-unseen-seq, mh-previous-seq, mh-page-to-next-msg-flag)
+       (mh-signature-separator, mh-signature-separator-regexp)
+       (mh-list-to-string, mh-list-to-string-1): Move here from
+       mh-utils.el.
+       (mh-index-max-cmdline-args, mh-xargs, mh-quote-for-shell)
+       (mh-exec-cmd, mh-exec-cmd-error, mh-exec-cmd-daemon)
+       (mh-exec-cmd-env-daemon, mh-process-daemon, mh-exec-cmd-quiet)
+       (mh-exec-cmd-output)
+       (mh-exchange-point-and-mark-preserving-active-mark)
+       (mh-exec-lib-cmd-output, mh-handle-process-error): Move here from
+       deprecated file mh-exec.el.
+       (mh-path): Move here from deprecated file mh-customize.el.
+       (mh-sys-path, mh-variants, mh-variant-in-use, mh-progs, mh-lib)
+       (mh-flists-present-flag, mh-variants, mh-variant-mh-info)
+       (mh-variant-mu-mh-info, mh-variant-nmh-info, mh-file-command-p)
+       (mh-variant-set-variant, mh-variant-p, mh-profile-component)
+       (mh-profile-component-value, mh-defface-compat): Move here from
+       deprecated file mh-init.el.
+       (mh-goto-next-button, mh-folder-mime-action)
+       (mh-folder-toggle-mime-part, mh-folder-inline-mime-part)
+       (mh-folder-save-mime-part, mh-toggle-mime-buttons): Move to to
+       mh-mime.el.
+       (mh-scan-format-mh, mh-scan-format-nmh, mh-note-deleted)
+       (mh-note-refiled, mh-note-cur, mh-scan-good-msg-regexp)
+       (mh-scan-deleted-msg-regexp, mh-scan-refiled-msg-regexp)
+       (mh-scan-valid-regexp, mh-scan-cur-msg-number-regexp)
+       (mh-scan-date-regexp, mh-scan-rcpt-regexp, mh-scan-body-regexp)
+       (mh-scan-subject-regexp, mh-scan-sent-to-me-sender-regexp)
+       (mh-scan-cmd-note-width, mh-scan-destination-width)
+       (mh-scan-date-width, mh-scan-date-flag-width)
+       (mh-scan-from-mbox-width, mh-scan-from-mbox-sep-width)
+       (mh-scan-field-destination-offset)
+       (mh-scan-field-from-start-offset, mh-scan-field-from-end-offset)
+       (mh-scan-field-subject-start-offset, mh-scan-format)
+       (mh-msg-num-width-to-column, mh-set-cmd-note): Move to new file
+       mh-scan.el.
+       (mh-partial-folder-mode-line-annotation)
+       (mh-folder-font-lock-keywords, mh-folder-font-lock-subject)
+       (mh-generate-sequence-font-lock, mh-last-destination)
+       (mh-last-destination-write, mh-first-msg-num, mh-last-msg-num)
+       (mh-rmail, mh-nmail, mh-delete-msg, mh-delete-msg-no-motion)
+       (mh-execute-commands, mh-first-msg, mh-header-display)
+       (mh-inc-folder, mh-last-msg, mh-next-undeleted-msg)
+       (mh-folder-from-address, mh-prompt-for-refile-folder)
+       (mh-refile-msg, mh-refile-or-write-again, mh-quit, mh-page-msg)
+       (mh-previous-page, mh-previous-undeleted-msg)
+       (mh-previous-unread-msg, mh-next-button, mh-prev-button)
+       (mh-reset-threads-and-narrowing, mh-rescan-folder)
+       (mh-write-msg-to-file, mh-toggle-showing, mh-undo)
+       (mh-visit-folder, mh-update-sequences, mh-delete-a-msg)
+       (mh-refile-a-msg, mh-next-msg, mh-next-unread-msg)
+       (mh-set-scan-mode, mh-undo-msg, mh-make-folder)
+       (mh-folder-sequence-menu, mh-folder-message-menu)
+       (mh-folder-folder-menu, mh-remove-xemacs-horizontal-scrollbar)
+       (mh-write-file-functions-compat, mh-folder-mode)
+       (mh-restore-desktop-buffer, mh-scan-folder)
+       (mh-regenerate-headers, mh-generate-new-cmd-note)
+       (mh-get-new-mail, mh-make-folder-mode-line, mh-goto-cur-msg)
+       (mh-process-or-undo-commands, mh-process-commands)
+       (mh-update-unseen, mh-delete-scan-msgs)
+       (mh-outstanding-commands-p): Move to new file mh-folder.el.
+       (mh-mapc, mh-colors-available-p, mh-colors-in-use-p)
+       (mh-make-local-vars, mh-coalesce-msg-list, mh-greaterp)
+       (mh-lessp): Move to mh-utils.el.
+       (mh-parse-flist-output-line, mh-folder-size-folder)
+       (mh-folder-size-flist, mh-folder-size, mh-add-sequence-notation)
+       (mh-remove-sequence-notation, mh-remove-cur-notation)
+       (mh-remove-all-notation, mh-delete-seq-locally)
+       (mh-read-folder-sequences, mh-read-msg-list)
+       (mh-notate-user-sequences, mh-internal-seqs, mh-internal-seq)
+       (mh-valid-seq-p, mh-delete-msg-from-seq, mh-catchup)
+       (mh-delete-a-msg-from-seq, mh-undefine-sequence)
+       (mh-define-sequence, mh-seq-containing-msg): Move to mh-seq.el.
+       (mh-xemacs-flag)
+       (mh-customize, mh-e, mh-alias, mh-folder, mh-folder-selection)
+       (mh-identity, mh-inc, mh-junk, mh-letter, mh-ranges)
+       (mh-scan-line-formats, mh-search, mh-sending-mail, mh-sequences)
+       (mh-show, mh-speedbar, mh-thread, mh-tool-bar, mh-hooks)
+       (mh-faces, mh-alias-completion-ignore-case-flag)
+       (mh-alias-expand-aliases-flag, mh-alias-flash-on-comma)
+       (mh-alias-insert-file, mh-alias-insertion-location)
+       (mh-alias-local-users, mh-alias-local-users-prefix)
+       (mh-alias-passwd-gecos-comma-separator-flag)
+       (mh-new-messages-folders, mh-ticked-messages-folders)
+       (mh-large-folder, mh-recenter-summary-flag)
+       (mh-recursive-folders-flag, mh-sortm-args)
+       (mh-default-folder-for-message-function, mh-default-folder-list)
+       (mh-default-folder-must-exist-flag, mh-default-folder-prefix)
+       (mh-identity-list, mh-auto-fields-list)
+       (mh-auto-fields-prompt-flag, mh-identity-default)
+       (mh-identity-handlers, mh-inc-prog, mh-inc-spool-list)
+       (mh-junk-choice, mh-junk-function-alist, mh-junk-choose)
+       (mh-junk-background, mh-junk-disposition, mh-junk-program)
+       (mh-compose-insertion, mh-compose-skipped-header-fields)
+       (mh-compose-space-does-completion-flag)
+       (mh-delete-yanked-msg-window-flag)
+       (mh-extract-from-attribution-verb, mh-ins-buf-prefix)
+       (mh-letter-complete-function, mh-letter-fill-column)
+       (mh-mml-method-default, mh-signature-file-name)
+       (mh-signature-separator-flag, mh-x-face-file, mh-yank-behavior)
+       (mh-interpret-number-as-range-flag, mh-adaptive-cmd-note-flag)
+       (mh-scan-format-file-check, mh-scan-format-file)
+       (mh-adaptive-cmd-note-flag-check, mh-scan-prog)
+       (mh-search-program, mh-compose-forward-as-mime-flag)
+       (mh-compose-letter-function, mh-compose-prompt-flag)
+       (mh-forward-subject-format, mh-insert-x-mailer-flag)
+       (mh-redist-full-contents-flag, mh-reply-default-reply-to)
+       (mh-reply-show-message-flag, mh-refile-preserves-sequences-flag)
+       (mh-tick-seq, mh-update-sequences-after-mh-show-flag)
+       (mh-bury-show-buffer-flag, mh-clean-message-header-flag)
+       (mh-decode-mime-flag, mh-display-buttons-for-alternatives-flag)
+       (mh-display-buttons-for-inline-parts-flag)
+       (mh-do-not-confirm-flag, mh-fetch-x-image-url)
+       (mh-graphical-smileys-flag, mh-graphical-emphasis-flag)
+       (mh-highlight-citation-style)
+       (mh-invisible-header-fields-internal)
+       (mh-delay-invisible-header-generation-flag)
+       (mh-invisible-header-fields, mh-invisible-header-fields-default)
+       (mh-invisible-header-fields-compiled, mh-invisible-headers)
+       (mh-lpr-command-format, mh-max-inline-image-height)
+       (mh-max-inline-image-width, mh-mhl-format-file)
+       (mh-mime-save-parts-default-directory, mh-print-background-flag)
+       (mh-show-maximum-size, mh-show-use-goto-addr-flag)
+       (mh-show-use-xface-flag, mh-store-default-directory)
+       (mh-summary-height, mh-speed-update-interval)
+       (mh-show-threads-flag, mh-tool-bar-search-function)
+       (mh-after-commands-processed-hook, mh-alias-reloaded-hook)
+       (mh-before-commands-processed-hook, mh-before-quit-hook)
+       (mh-before-send-letter-hook, mh-delete-msg-hook)
+       (mh-find-path-hook, mh-folder-mode-hook, mh-forward-hook)
+       (mh-inc-folder-hook, mh-insert-signature-hook)
+       (mh-kill-folder-suppress-prompt-hooks, mh-letter-mode-hook)
+       (mh-mh-to-mime-hook, mh-search-mode-hook, mh-quit-hook)
+       (mh-refile-msg-hook, mh-show-hook, mh-show-mode-hook)
+       (mh-unseen-updated-hook, mh-min-colors-defined-flag)
+       (mh-folder-address, mh-folder-body)
+       (mh-folder-cur-msg-number, mh-folder-date, mh-folder-deleted)
+       (mh-folder-followup, mh-folder-msg-number, mh-folder-refiled)
+       (mh-folder-sent-to-me-hint, mh-folder-sent-to-me-sender)
+       (mh-folder-subject, mh-folder-tick, mh-folder-to)
+       (mh-search-folder, mh-letter-header-field, mh-show-cc)
+       (mh-show-date, mh-show-from, mh-show-header, mh-show-pgg-bad)
+       (mh-show-pgg-good, mh-show-pgg-unknown, mh-show-signature)
+       (mh-show-subject, mh-show-to, mh-show-xface, mh-speedbar-folder)
+       (mh-speedbar-folder-with-unseen-messages)
+       (mh-speedbar-selected-folder)
+       (mh-speedbar-selected-folder-with-unseen-messages): Move here from
+       deprecated file mh-customize.el.
+
+       * mh-exec.el: Move content into mh-e.el and remove.
+       
+       * mh-folder.el: New file. Contains mh-folder-mode from mh-e.el
+
+       * mh-funcs.el (mh-note-copied, mh-note-printed): Move to new file
+       mh-scan.el.
+       (mh-ephem-message, mh-help, mh-prefix-help): Move to mh-utils.el.
+
+       * mh-gnus.el (mm-uu-dissect-text-parts): Add.
+       (mh-mail-abbrev-make-syntax-table): Move to mh-utils.el and rename
+       to mail-abbrev-make-syntax-table.
+
+       * mh-identity.el (mh-identity-menu): New variable for existing
+       menu.
+       (mh-identity-make-menu-no-autoload): New alias for
+       mh-identity-make-menu which can be called from mh-e.el.
+       (mh-identity-list-set): Move to mh-e.el.
+       (mh-identity-add-menu): New function
+       (mh-insert-identity): Add optional argument maybe-insert so that
+       local variable mh-identity-local does not have to be visible.
+       (mh-identity-handler-default):
+
+       * mh-inc.el (mh-inc-spool-map): Move declaration to mh-e.el (with
+       rest of keymaps). Update key binding for ? to call mh-help with
+       help messages in new argument.
+       (mh-inc-spool-make-no-autoload): New alias for mh-inc-spool-make
+       which can be called from mh-e.el.
+       (mh-inc-spool-list-set): Simplify update of mh-inc-spool-map-help.
+
+       * mh-init.el: Move content into mh-e.el and remove.
+       
+       * mh-junk.el: Update requires, untabify, and add mh-autoload
+       cookies.
+
+       * mh-letter.el: New file. Contains mh-letter-mode from mh-comp.el.
+
+       * mh-limit.el: New file. Contains display limit commands from
+       mh-mime.el.
+
+       * mh-mime.el: Rearrange for consistency with other files.
+       (mh-buffer-data, mh-mm-inline-media-tests): Move here from
+       mh-utils.el.
+       (mh-folder-inline-mime-part, mh-folder-save-mime-part)
+       (mh-folder-toggle-mime-part, mh-toggle-mime-buttons)
+       (mh-goto-next-button): Move here from mh-e.el.
+
+       * mh-print.el: Rearrange for consistency with other files.
+
+       * mh-scan.el: New file. Contains scan line constants and utilities
+       from XXX, mh-funcs, mh-utils.el.
+
+       * mh-search.el: Rearrange for consistency with other files.
+       (mh-search-mode-map): Drop C-c C-f {dr} bindings since these
+       fields which don't exist in the saved header. Replace C-c C-f f
+       with C-c C-f m per mail-mode consistency.
+       (mh-search-mode): Use mh-set-help instead of setting
+       mh-help-messages.
+
+       * mh-seq.el (mh-thread-message, mh-thread-container)
+       (mh-thread-id-hash, mh-thread-subject-hash, mh-thread-id-table)
+       (mh-thread-id-index-map, mh-thread-index-id-map)
+       (mh-thread-scan-line-map, mh-thread-scan-line-map-stack)
+       (mh-thread-subject-container-hash, mh-thread-duplicates)
+       (mh-thread-history, mh-thread-body-width)
+       (mh-thread-find-msg-subject mh-thread-initialize-hash)
+       (mh-thread-initialize, mh-thread-id-container)
+       (mh-thread-remove-parent-link, mh-thread-add-link)
+       (mh-thread-ancestor-p, mh-thread-get-message-container)
+       (mh-thread-get-message, mh-thread-canonicalize-id)
+       (mh-thread-prune-subject, mh-thread-container-subject)
+       (mh-thread-rewind-pruning, mh-thread-prune-containers)
+       (mh-thread-sort-containers, mh-thread-group-by-subject)
+       (mh-thread-process-in-reply-to, mh-thread-set-tables)
+       (mh-thread-update-id-index-maps, mh-thread-generate)
+       (mh-thread-inc, mh-thread-generate-scan-lines)
+       (mh-thread-parse-scan-line, mh-thread-update-scan-line-map)
+       (mh-thread-add-spaces, mh-thread-print-scan-lines)
+       (mh-thread-folder, mh-toggle-threads, mh-thread-forget-message)
+       (mh-thread-current-indentation-level, mh-thread-next-sibling)
+       (mh-thread-previous-sibling, mh-thread-immediate-ancestor)
+       (mh-thread-ancestor, mh-thread-find-children)
+       (mh-message-id-regexp, mh-thread-delete, mh-thread-refile): Move
+       to new file mh-thread.el.
+       (mh-subject-to-sequence, mh-subject-to-sequence-unthreaded)
+       (mh-subject-to-sequence-threaded, mh-edit-pick-expr)
+       (mh-pick-args-list, mh-narrow-to-subject, mh-narrow-to-from)
+       (mh-narrow-to-cc, mh-narrow-to-to, mh-narrow-to-header-field)
+       (mh-current-message-header-field, mh-narrow-to-range)
+       (mh-delete-subject, mh-delete-subject-or-thread): Move to new file
+       mh-limit.el.
+       (mh-iterate-on-messages-in-region, mh-iterate-on-range): Move to
+       mh-acros.el.
+       (mh-internal-seqs, mh-catchup, mh-delete-msg-from-seq)
+       (mh-internal-seq, mh-valid-seq-p, mh-seq-containing-msg)
+       (mh-define-sequence, mh-undefine-sequence)
+       (mh-delete-a-msg-from-seq, mh-delete-seq-locally)
+       (mh-folder-size, mh-folder-size-flist, mh-folder-size-folder)
+       (mh-parse-flist-output-line, mh-read-folder-sequences)
+       (mh-read-msg-list, mh-notate-user-sequences)
+       (mh-remove-cur-notation, mh-add-sequence-notation)
+       (mh-remove-sequence-notation, mh-remove-all-notation): Move here
+       from mh-e.el.
+       (mh-make-seq, mh-seq-name, mh-find-seq, mh-seq-to-msgs)
+       (mh-add-msgs-to-seq, mh-notate): Move here from mh-utils.el.
+
+       * mh-show.el: New file. Contains mh-show-mode from mh-utils.el.
+
+       * mh-speed.el: Rearrange for consistency with other files.
+
+       * mh-thread.el: New file. Contains threading code from mh-seq.el.
+
+       * mh-tool-bar.el: New file. Contains tool bar creation code from
+       deprecated file mh-customize.el.
+
+       * mh-utils.el (recursive-load-depth-limit): Remove setting. No
+       longer needed.
+       (mh-scan-msg-number-regexp, mh-scan-msg-overflow-regexp)
+       (mh-scan-msg-format-regexp, mh-scan-msg-format-string)
+       (mh-scan-msg-search-regexp, mh-cmd-note, mh-note-seq)
+       (mh-update-scan-format, mh-msg-num-width): Move to new file
+       mh-scan.el.
+       (mh-show-buffer-mode-line-buffer-id, mh-letter-header-font-lock)
+       (mh-header-field-font-lock, mh-header-to-font-lock)
+       (mh-header-cc-font-lock, mh-header-subject-font-lock)
+       (mh-show-font-lock-keywords)
+       (mh-show-font-lock-keywords-with-cite)
+       (mh-show-font-lock-fontify-region)
+       (mh-gnus-article-highlight-citation, mh-showing-with-headers)
+       (mh-start-of-uncleaned-message, mh-invalidate-show-buffer)
+       (mh-unvisit-file, mh-defun-show-buffer, mh-show-mode-map)
+       (mh-show-sequence-menu, mh-show-message-menu)
+       (mh-show-folder-menu, mh-show-mode, mh-show-addr)
+       (mh-maybe-show, mh-show, mh-show-msg, mh-show-unquote-From)
+       (mh-msg-folder, mh-display-msg, mh-clean-msg-header): Move to new
+       file mh-show.el.
+       (mh-mail-header-separator, mh-signature-separator-regexp)
+       (mh-signature-separator, mh-globals-hash, mh-user-path)
+       (mh-draft-folder, mh-unseen-seq, mh-previous-seq, mh-inbox)
+       (mh-previous-window-config, mh-current-folder mh-show-buffer)
+       (mh-showing-mode, mh-show-mode-map, mh-show-folder-buffer)
+       (mh-showing-mode, mh-seq-list, mh-seen-list, mh-summary-height)
+       (mh-list-to-string, mh-list-to-string-1): Move to mh-e.el.
+       (mh-buffer-data, mh-mm-inline-media-tests): Move to mh-mime.el.
+       (mh-address-mail-regexp, mh-goto-address-find-address-at-point):
+       Move to mh-alias.el.
+       (mh-letter-font-lock-keywords): Move to new file mh-letter.el.
+       (mh-folder-filename, mh-msg-count, mh-recenter, mh-msg-filename)
+       (mh-show-mouse, mh-modify, mh-goto-msg, mh-set-folder-modified-p):
+       Move to new file mh-folder.el.
+       (with-mh-folder-updating, mh-in-show-buffer)
+       (mh-do-at-event-location, mh-seq-msgs): Moved to mh-acros.el.
+       (mh-make-seq, mh-seq-name, mh-notate, mh-find-seq)
+       (mh-seq-to-msgs, mh-add-msgs-to-seq, mh-canonicalize-sequence):
+       Moved to mh-seq.el.
+       (mh-show-xface-function, mh-uncompface-executable, mh-face-to-png)
+       (mh-uncompface, mh-icontopbm, mh-face-foreground-compat)
+       (mh-face-background-compat, mh-face-display-function)
+       (mh-show-xface, mh-picon-directory-list)
+       (mh-picon-existing-directory-list)
+       (mh-picon-cache, mh-picon-image-types)
+       (mh-picon-set-directory-list, mh-picon-get-image)
+       (mh-picon-file-contents, mh-picon-generate-path)
+       (mh-x-image-cache-directory, mh-x-image-scaling-function)
+       (mh-wget-executable, mh-wget-choice, mh-wget-option)
+       (mh-x-image-temp-file, mh-x-image-url, mh-x-image-marker)
+       (mh-x-image-url-cache-file, mh-x-image-scale-with-pnm)
+       (mh-x-image-scale-with-convert)
+       (url-unreserved-chars, url-hexify-string)
+       (mh-x-image-url-cache-canonicalize)
+       (mh-x-image-set-download-state, mh-x-image-get-download-state)
+       (mh-x-image-url-fetch-image, mh-x-image-display)
+       (mh-x-image-scale-and-display, mh-x-image-url-sane-p)
+       (mh-x-image-url-display): Move to new file mh-xface.el.
+       (mh-logo-display): Call mh-image-load-path.
+       (mh-find-path-run, mh-find-path): Move here from deprecated file
+       mh-init.el.
+       (mh-help-messages): Now an alist of modes to an alist of messages.
+       (mh-set-help): New function used to set mh-help-messages
+       (mh-help): Adjust for new format of mh-help-messages. Add
+       help-messages argument.
+       (mh-prefix-help): Refactor to use mh-help.
+       (mh-coalesce-msg-list, mh-greaterp, mh-lessp): Move here from
+       mh-e.el.
+       (mh-clear-sub-folders-cache): New function added to avoid exposing
+       mh-sub-folders-cache variable.
+
+       * mh-xface.el: New file. Contains X-Face and Face header field
+       display routines from mh-utils.el.
+
 2006-01-17  Bill Wohler  <address@hidden>
 
        * mh-acros.el (assoc-string): Fix typo in argument.
Index: emacs/lisp/mh-e/mh-acros.el
diff -u emacs/lisp/mh-e/mh-acros.el:1.16 emacs/lisp/mh-e/mh-acros.el:1.17
--- emacs/lisp/mh-e/mh-acros.el:1.16    Tue Jan 17 16:20:29 2006
+++ emacs/lisp/mh-e/mh-acros.el Sun Jan 29 19:34:57 2006
@@ -1,4 +1,4 @@
-;;; mh-acros.el --- Macros used in MH-E
+;;; mh-acros.el --- macros used in MH-E
 
 ;; Copyright (C) 2004, 2006 Free Software Foundation, Inc.
 
@@ -26,54 +26,62 @@
 
 ;;; Commentary:
 
-;; This file contains most, if not all, macros. It is so named with a
-;; silent "m" so that it is compiled first. Otherwise, "make
-;; recompile" in CVS Emacs may use compiled files with stale macro
-;; definitions.
-
-;; This file must always be included like this:
-;;
-;;   (eval-when-compile (require 'mh-acros))
+;; This file contains all macros that are used in more than one file.
+;; If you run "make recompile" in CVS Emacs and see the message
+;; "Source is newer than compiled," it is a sign that macro probably
+;; needs to be moved here.
+
+;; Historically, it was so named with a silent "m" so that it would be
+;; compiled first. Otherwise, "make recompile" in CVS Emacs would use
+;; compiled files with stale macro definitions. Later, no-byte-compile
+;; was added to the Local Variables section to avoid this problem and
+;; because it's pointless to compile a file full of macros. But we
+;; kept the name.
 
 ;;; Change Log:
 
 ;;; Code:
 
 (require 'cl)
-(require 'advice)
 
-;; The Emacs coding conventions require that the cl package not be required at
-;; runtime. However, the cl package in versions of Emacs prior to 21.4 left cl
-;; routines in their macro expansions. Use mh-require-cl to provide the cl
-;; routines in the best way possible.
+
+
+;;; Compatibility
+
+;;;###mh-autoload
 (defmacro mh-require-cl ()
   "Macro to load \"cl\" if needed.
-Some versions of \"cl\" produce code for the expansion of
-\(setf (gethash ...) ...) that uses functions in \"cl\" at run
-time. This macro recognizes that and loads \"cl\" where
-appropriate."
+
+Emacs coding conventions require that the \"cl\" package not be
+required at runtime. However, the \"cl\" package in Emacs 21.4
+and earlier left \"cl\" routines in their macro expansions. In
+particular, the expansion of (setf (gethash ...) ...) used
+functions in \"cl\" at run time. This macro recognizes that and
+loads \"cl\" appropriately."
   (if (eq (car (macroexpand '(setf (gethash foo bar) baz))) 'cl-puthash)
       `(require 'cl)
     `(eval-when-compile (require 'cl))))
 
-;; Macros to generate correct code for different emacs variants
-
+;;;###mh-autoload
 (defmacro mh-do-in-gnu-emacs (&rest body)
   "Execute BODY if in GNU Emacs."
   (unless (featurep 'xemacs) `(progn ,@body)))
 (put 'mh-do-in-gnu-emacs 'lisp-indent-hook 'defun)
 
+;;;###mh-autoload
 (defmacro mh-do-in-xemacs (&rest body)
-  "Execute BODY if in GNU Emacs."
+  "Execute BODY if in XEmacs."
   (when (featurep 'xemacs) `(progn ,@body)))
 (put 'mh-do-in-xemacs 'lisp-indent-hook 'defun)
 
+;;;###mh-autoload
 (defmacro mh-funcall-if-exists (function &rest args)
   "Call FUNCTION with ARGS as parameters if it exists."
   (when (fboundp function)
     `(when (fboundp ',function)
        (funcall ',function ,@args))))
 
+;;;###mh-autoload
 (defmacro mh-defun-compat (function arg-list &rest body)
   "This is a macro to define functions which are not defined.
 It is used for functions which were added to Emacs recently.
@@ -84,6 +92,7 @@
       `(defun ,function ,arg-list ,@body))))
 (put 'mh-defun-compat 'lisp-indent-function 'defun)
 
+;;;###mh-autoload
 (defmacro mh-defmacro-compat (function arg-list &rest body)
   "This is a macro to define functions which are not defined.
 It is used for macros which were added to Emacs recently.
@@ -94,6 +103,11 @@
       `(defmacro ,function ,arg-list ,@body))))
 (put 'mh-defmacro-compat 'lisp-indent-function 'defun)
 
+
+
+;;; Miscellaneous
+
+;;;###mh-autoload
 (defmacro mh-make-local-hook (hook)
   "Make HOOK local if needed.
 XEmacs and versions of GNU Emacs before 21.1 require
@@ -102,6 +116,7 @@
              (not (get 'make-local-hook 'byte-obsolete-info)))
     `(make-local-hook ,hook)))
 
+;;;###mh-autoload
 (defmacro mh-mark-active-p (check-transient-mark-mode-flag)
   "A macro that expands into appropriate code in XEmacs and nil in GNU Emacs.
 In GNU Emacs if CHECK-TRANSIENT-MARK-MODE-FLAG is non-nil then
@@ -114,6 +129,10 @@
          `(and (boundp 'transient-mark-mode) transient-mark-mode
                (boundp 'mark-active) mark-active))))
 
+;; Shush compiler.
+(eval-when-compile (mh-do-in-xemacs (defvar struct) (defvar x) (defvar y)))
+
+;;;###mh-autoload
 (defmacro mh-defstruct (name-spec &rest fields)
   "Replacement for `defstruct' from the \"cl\" package.
 The `defstruct' in the \"cl\" library produces compiler warnings,
@@ -150,15 +169,145 @@
                           (list 'nth ,x z)))
        (quote ,struct-name))))
 
-(unless (fboundp 'assoc-string)
-  (defsubst assoc-string (key list case-fold)
-    "Like `assoc' but specifically for strings.
-Case is ignored if CASE-FOLD is non-nil.
-This function added by MH-E for Emacs versions that lack
-`assoc-string', introduced in Emacs 22."
-    (if case-fold
-        (assoc-ignore-case key list)
-      (assoc key list))))
+;;;###mh-autoload
+(defmacro with-mh-folder-updating (save-modification-flag &rest body)
+  "Format is (with-mh-folder-updating (SAVE-MODIFICATION-FLAG) &body BODY).
+Execute BODY, which can modify the folder buffer without having to
+worry about file locking or the read-only flag, and return its result.
+If SAVE-MODIFICATION-FLAG is non-nil, the buffer's modification flag
+is unchanged, otherwise it is cleared."
+  (setq save-modification-flag (car save-modification-flag)) ; CL style
+  `(prog1
+       (let ((mh-folder-updating-mod-flag (buffer-modified-p))
+             (buffer-read-only nil)
+             (buffer-file-name nil))    ;don't let the buffer get locked
+         (prog1
+             (progn
+               ,@body)
+           (mh-set-folder-modified-p mh-folder-updating-mod-flag)))
+     ,@(if (not save-modification-flag)
+           '((mh-set-folder-modified-p nil)))))
+(put 'with-mh-folder-updating 'lisp-indent-hook 'defun)
+
+;;;###mh-autoload
+(defmacro mh-in-show-buffer (show-buffer &rest body)
+  "Format is (mh-in-show-buffer (SHOW-BUFFER) &body BODY).
+Display buffer SHOW-BUFFER in other window and execute BODY in it.
+Stronger than `save-excursion', weaker than `save-window-excursion'."
+  (setq show-buffer (car show-buffer))  ; CL style
+  `(let ((mh-in-show-buffer-saved-window (selected-window)))
+     (switch-to-buffer-other-window ,show-buffer)
+     (if mh-bury-show-buffer-flag (bury-buffer (current-buffer)))
+     (unwind-protect
+         (progn
+           ,@body)
+       (select-window mh-in-show-buffer-saved-window))))
+(put 'mh-in-show-buffer 'lisp-indent-hook 'defun)
+
+;;;###mh-autoload
+(defmacro mh-do-at-event-location (event &rest body)
+  "Switch to the location of EVENT and execute BODY.
+After BODY has been executed return to original window. The
+modification flag of the buffer in the event window is
+preserved."
+  (let ((event-window (make-symbol "event-window"))
+        (event-position (make-symbol "event-position"))
+        (original-window (make-symbol "original-window"))
+        (original-position (make-symbol "original-position"))
+        (modified-flag (make-symbol "modified-flag")))
+    `(save-excursion
+       (let* ((,event-window
+               (or (mh-funcall-if-exists posn-window (event-start ,event))
+                   (mh-funcall-if-exists event-window ,event)))
+              (,event-position
+               (or (mh-funcall-if-exists posn-point (event-start ,event))
+                   (mh-funcall-if-exists event-closest-point ,event)))
+              (,original-window (selected-window))
+              (,original-position (progn
+                                   (set-buffer (window-buffer ,event-window))
+                                   (set-marker (make-marker) (point))))
+              (,modified-flag (buffer-modified-p))
+              (buffer-read-only nil))
+         (unwind-protect (progn
+                           (select-window ,event-window)
+                           (goto-char ,event-position)
+                           ,@body)
+           (set-buffer-modified-p ,modified-flag)
+           (goto-char ,original-position)
+           (set-marker ,original-position nil)
+           (select-window ,original-window))))))
+(put 'mh-do-at-event-location 'lisp-indent-hook 'defun)
+
+
+
+;;; Sequences and Ranges
+
+;;;###mh-autoload
+(defmacro mh-seq-msgs (sequence)
+  "Extract messages from the given SEQUENCE."
+  (list 'cdr sequence))
+
+;;;###mh-autoload
+(defmacro mh-iterate-on-messages-in-region (var begin end &rest body)
+  "Iterate over region.
+
+VAR is bound to the message on the current line as we loop
+starting from BEGIN till END. In each step BODY is executed.
+
+If VAR is nil then the loop is executed without any binding."
+  (unless (symbolp var)
+    (error "Can not bind the non-symbol %s" var))
+  (let ((binding-needed-flag var))
+    `(save-excursion
+       (goto-char ,begin)
+       (beginning-of-line)
+       (while (and (<= (point) ,end) (not (eobp)))
+         (when (looking-at mh-scan-valid-regexp)
+           (let ,(if binding-needed-flag `((,var (mh-get-msg-num t))) ())
+             ,@body))
+         (forward-line 1)))))
+(put 'mh-iterate-on-messages-in-region 'lisp-indent-hook 'defun)
+
+;;;###mh-autoload
+(defmacro mh-iterate-on-range (var range &rest body)
+  "Iterate an operation over a region or sequence.
+
+VAR is bound to each message in turn in a loop over RANGE, which
+can be a message number, a list of message numbers, a sequence, a
+region in a cons cell, or a MH range (something like last:20) in
+a string. In each iteration, BODY is executed.
+
+The parameter RANGE is usually created with
+`mh-interactive-range' in order to provide a uniform interface to
+MH-E functions."
+  (unless (symbolp var)
+    (error "Can not bind the non-symbol %s" var))
+  (let ((binding-needed-flag var)
+        (msgs (make-symbol "msgs"))
+        (seq-hash-table (make-symbol "seq-hash-table")))
+    `(cond ((numberp ,range)
+            (when (mh-goto-msg ,range t t)
+              (let ,(if binding-needed-flag `((,var ,range)) ())
+                ,@body)))
+           ((and (consp ,range)
+                 (numberp (car ,range)) (numberp (cdr ,range)))
+            (mh-iterate-on-messages-in-region ,var
+              (car ,range) (cdr ,range)
+              ,@body))
+           (t (let ((,msgs (cond ((and ,range (symbolp ,range))
+                                  (mh-seq-to-msgs ,range))
+                                 ((stringp ,range)
+                                  (mh-translate-range mh-current-folder
+                                                      ,range))
+                                 (t ,range)))
+                    (,seq-hash-table (make-hash-table)))
+                (dolist (msg ,msgs)
+                  (setf (gethash msg ,seq-hash-table) t))
+                (mh-iterate-on-messages-in-region v (point-min) (point-max)
+                  (when (gethash v ,seq-hash-table)
+                    (let ,(if binding-needed-flag `((,var v)) ())
+                      ,@body))))))))
+(put 'mh-iterate-on-range 'lisp-indent-hook 'defun)
 
 (provide 'mh-acros)
 
Index: emacs/lisp/mh-e/mh-alias.el
diff -u emacs/lisp/mh-e/mh-alias.el:1.25 emacs/lisp/mh-e/mh-alias.el:1.26
--- emacs/lisp/mh-e/mh-alias.el:1.25    Mon Jan 16 21:34:50 2006
+++ emacs/lisp/mh-e/mh-alias.el Sun Jan 29 19:34:57 2006
@@ -1,5 +1,5 @@
 ;;; mh-alias.el --- MH-E mail alias completion and expansion
-;;
+
 ;; Copyright (C) 1994, 1995, 1996, 1997,
 ;;  2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
 
@@ -31,24 +31,9 @@
 
 ;;; Code:
 
-;;(message "> mh-alias")
-(eval-when-compile (require 'mh-acros))
-(mh-require-cl)
-(require 'mh-buffers)
 (require 'mh-e)
-;;(message "< mh-alias")
-(load "cmr" t t)                        ; Non-fatal dependency for
-                                       ; completing-read-multiple.
-(eval-when-compile (defvar mail-abbrev-syntax-table))
-
-
 
-;;; Autoloads
-
-(eval-when (compile load eval)
-  (ignore-errors
-    (require 'mailabbrev)
-    (require 'multi-prompt)))
+(mh-require-cl)
 
 (defvar mh-alias-alist 'not-read
   "Alist of MH aliases.")
@@ -61,7 +46,7 @@
 (defvar mh-alias-read-address-map nil)
 (unless mh-alias-read-address-map
   (setq mh-alias-read-address-map
-       (copy-keymap minibuffer-local-completion-map))
+        (copy-keymap minibuffer-local-completion-map))
   (define-key mh-alias-read-address-map
     "," 'mh-alias-minibuffer-confirm-address)
   (define-key mh-alias-read-address-map " " 'self-insert-command))
@@ -77,6 +62,11 @@
 automatically included. You can update the alias list manually using
 \\[mh-alias-reload].")
 
+;; Copy of `goto-address-mail-regexp'.
+(defvar mh-address-mail-regexp
+  "address@hidden([-a-zA-z0-9_]+\\.\\)+[a-zA-Z0-9]+"
+  "A regular expression probably matching an e-mail address.")
+
 
 
 ;;; Alias Loading
@@ -185,7 +175,6 @@
         (forward-line 1)))
     passwd-alist))
 
-;;;###mh-autoload
 (defun mh-alias-reload ()
   "Reload MH aliases.
 
@@ -269,11 +258,14 @@
    (t
     (mh-alias-ali alias))))
 
+(require 'crm nil t)                   ; completing-read-multiple
+(require 'multi-prompt nil t)
+
 ;;;###mh-autoload
 (defun mh-read-address (prompt)
   "Read an address from the minibuffer with PROMPT."
   (mh-alias-reload-maybe)
-  (if (not mh-alias-alist)             ; If still no aliases, just prompt
+  (if (not mh-alias-alist)              ; If still no aliases, just prompt
       (read-string prompt)
     (let* ((minibuffer-local-completion-map mh-alias-read-address-map)
            (completion-ignore-case mh-alias-completion-ignore-case-flag)
@@ -308,8 +300,6 @@
               (message "No alias for %s" the-name))))))
   (self-insert-command 1))
 
-(mh-do-in-xemacs (defvar mail-abbrevs))
-
 ;;;###mh-autoload
 (defun mh-alias-letter-expand-alias ()
   "Expand mail alias before point."
@@ -323,9 +313,10 @@
              (expansion (mh-alias-expand (buffer-substring begin end))))
         (delete-region begin end)
         (insert expansion)))))
+
 
 
-;;; Adding addresses to alias file.
+;;; Alias File Updating
 
 (defun mh-alias-suggest-alias (string &optional no-comma-swap)
   "Suggest an alias for STRING.
@@ -451,8 +442,8 @@
                                      (mh-alias-filenames t)))))
       (cond
        ((not autolist)
-        (error "No writable alias file.
-Set `mh-alias-insert-file' or the \"Aliasfile:\" profile component"))
+        (error "No writable alias file;
+set `mh-alias-insert-file' or the \"Aliasfile:\" profile component"))
        ((not (elt autolist 1))        ; Only one entry, use it
         (car autolist))
        ((or (not alias)
@@ -549,7 +540,6 @@
     (insert (format "%s: %s\n" alias address))
     (save-buffer)))
 
-;;;###mh-autoload
 (defun mh-alias-add-alias (alias address)
   "Add ALIAS for ADDRESS in personal alias file.
 
@@ -602,7 +592,6 @@
            (alias (mh-alias-suggest-alias address)))
       (mh-alias-add-alias alias address))))
 
-;;;###mh-autoload
 (defun mh-alias-add-address-under-point ()
   "Insert an alias for address under point."
   (interactive)
@@ -611,7 +600,19 @@
         (mh-alias-add-alias nil address)
       (message "No email address found under point"))))
 
-;;;###mh-autoload
+;; From goto-addr.el, which we don't want to force-load on users.
+(defun mh-goto-address-find-address-at-point ()
+  "Find e-mail address around or before point.
+
+Then search backwards to beginning of line for the start of an
+e-mail address. If no e-mail address found, return nil."
+  (re-search-backward "address@hidden" (line-beginning-position) 'lim)
+  (if (or (looking-at mh-address-mail-regexp) ; already at start
+          (and (re-search-forward mh-address-mail-regexp
+                                  (line-end-position) 'lim)
+               (goto-char (match-beginning 0))))
+      (match-string-no-properties 0)))
+
 (defun mh-alias-apropos (regexp)
   "Show all aliases or addresses that match a regular expression REGEXP."
   (interactive "sAlias regexp: ")
@@ -668,6 +669,21 @@
           (princ "\nLocal User Aliases:\n\n")
           (princ passwd-matches))))))
 
+(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, the message in the show buffer doesn't match."
+  (and (eq major-mode 'mh-folder-mode)
+       (mh-get-msg-num nil)
+       mh-show-buffer
+       (get-buffer mh-show-buffer)
+       (buffer-file-name (get-buffer mh-show-buffer))
+       (string-match ".*/\\([0-9]+\\)$"
+                     (buffer-file-name (get-buffer mh-show-buffer)))
+       (string-equal
+        (match-string 1 (buffer-file-name (get-buffer mh-show-buffer)))
+        (int-to-string (mh-get-msg-num nil)))))
+
 (provide 'mh-alias)
 
 ;; Local Variables:
Index: emacs/lisp/mh-e/mh-buffers.el
diff -u emacs/lisp/mh-e/mh-buffers.el:1.2 emacs/lisp/mh-e/mh-buffers.el:1.3
--- emacs/lisp/mh-e/mh-buffers.el:1.2   Thu Jan 12 02:33:20 2006
+++ emacs/lisp/mh-e/mh-buffers.el       Sun Jan 29 19:34:57 2006
@@ -1,4 +1,4 @@
-;;; mh-buffers.el --- Temporary buffer constants and utilities used by MH-E
+;;; mh-buffers.el --- MH-E buffer constants and utilities
 
 ;; Copyright (C) 1993, 1995, 1997,
 ;;  2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
@@ -27,8 +27,6 @@
 
 ;;; Commentary:
 
-;; Temporary buffer constants and utilities used by MH-E.
-
 ;;; Change Log:
 
 ;;; Code:
Index: emacs/lisp/mh-e/mh-comp.el
diff -u emacs/lisp/mh-e/mh-comp.el:1.42 emacs/lisp/mh-e/mh-comp.el:1.43
--- emacs/lisp/mh-e/mh-comp.el:1.42     Mon Jan 16 20:05:14 2006
+++ emacs/lisp/mh-e/mh-comp.el  Sun Jan 29 19:34:56 2006
@@ -1,4 +1,4 @@
-;;; mh-comp.el --- MH-E functions for composing messages
+;;; mh-comp.el --- MH-E functions for composing and sending messages
 
 ;; Copyright (C) 1993, 1995, 1997,
 ;;  2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
@@ -27,33 +27,23 @@
 
 ;;; Commentary:
 
-;; Internal support for MH-E package.
+;; This file includes the functions in the MH-Folder maps that get us
+;; into MH-Letter mode, as well the functions in the MH-Letter mode
+;; that are used to send the mail. Other that those, functions that
+;; are needed in mh-letter.el should be found there.
 
 ;;; Change Log:
 
 ;;; Code:
 
-;;(message "> mh-comp")
-(eval-when-compile (require 'mh-acros))
-(mh-require-cl)
-
-(require 'easymenu)
-(require 'gnus-util)
-(require 'mh-buffers)
 (require 'mh-e)
-(require 'mh-gnus)
+(require 'mh-gnus)                      ;needed because mh-gnus.el not compiled
+(require 'mh-scan)
 
-(eval-when (compile load eval)
-  (ignore-errors (require 'mailabbrev)))
-;;(message "< mh-comp")
-
-
-
-;;; Autoloads
-
-(autoload 'mail-mode-fill-paragraph "sendmail")
-(autoload 'mm-handle-displayed-p "mm-decode")
+(require 'sendmail)
 
+(autoload 'easy-menu-add "easymenu")
+(autoload 'mml-insert-tag "mml")
 (autoload 'sc-cite-original "sc"
   "Workhorse citing function which performs the initial citation.
 This is callable from the various mail and news readers' reply
@@ -80,7 +70,7 @@
 
 
 
-;;; Site customization (see also mh-utils.el):
+;;; Site Customization
 
 (defvar mh-send-prog "send"
   "Name of the MH send program.
@@ -93,26 +83,7 @@
 
 
 
-;;; Scan Line Formats
-
-(defvar mh-note-repl ?-
-  "Messages that have been replied to are marked by this character.")
-
-(defvar mh-note-forw ?F
-  "Messages that have been forwarded are marked by this character.")
-
-(defvar mh-note-dist ?R
-  "Messages that have been redistributed are marked by this character.")
-
-(defvar mh-yank-hooks nil
-  "Obsolete hook for modifying a citation just inserted in the mail buffer.
-
-Each hook function can find the citation between point and mark.
-And each hook function should leave point and mark around the
-citation text as modified.
-
-This is a normal hook, misnamed for historical reasons. It is
-semi-obsolete and is only used if `mail-citation-hook' is nil.")
+;;; Variables
 
 (defvar mh-comp-formfile "components"
   "Name of file to be used as a skeleton for composing messages.
@@ -145,7 +116,7 @@
           (regexp-opt
            '("Content-Type: message/rfc822" ;MIME MDN
              "------ This is a copy of the message, including all the headers. 
------";from exim
-            "--- Below this line is a copy of the message."; from qmail
+             "--- Below this line is a copy of the message."; from qmail
              "   ----- Unsent message follows -----" ;from sendmail V5
              " --------Unsent Message below:" ; from sendmail at BU
              "   ----- Original message follows -----" ;from sendmail V8
@@ -161,21 +132,6 @@
   "Regexp of header lines to remove before offering a message as a new 
draft\\<mh-folder-mode-map>.
 Used by the \\[mh-edit-again] and \\[mh-extract-rejected-mail] commands.")
 
-(defvar mh-to-field-choices '(("a" . "Mail-Reply-To:")
-                              ("b" . "Bcc:")
-                              ("c" . "Cc:")
-                              ("d" . "Dcc:")
-                              ("f" . "Fcc:")
-                              ("l" . "Mail-Followup-To:")
-                              ("m" . "From:")
-                              ("r" . "Reply-To:")
-                              ("s" . "Subject:")
-                              ("t" . "To:"))
-  "Alist of (final-character . field-name) choices for `mh-to-field'.")
-
-(defvar mh-letter-mode-map (copy-keymap text-mode-map)
-  "Keymap for composing mail.")
-
 (defvar mh-letter-mode-syntax-table nil
   "Syntax table used by MH-E while in MH-Letter mode.")
 
@@ -185,12 +141,6 @@
         (make-syntax-table text-mode-syntax-table))
   (modify-syntax-entry ?% "." mh-letter-mode-syntax-table))
 
-(defvar mh-sent-from-folder nil
-  "Folder of msg assoc with this letter.")
-
-(defvar mh-sent-from-msg nil
-  "Number of msg assoc with this letter.")
-
 (defvar mh-send-args nil
   "Extra args to pass to \"send\" command.")
 
@@ -204,6 +154,10 @@
   "Buffer-local variable set when `mh-insert-auto-fields' called 
successfully.")
 (make-variable-buffer-local 'mh-insert-auto-fields-done-local)
 
+
+
+;;; MH-E Entry Points
+
 ;;;###autoload
 (defun mh-smail ()
   "Compose a message with the MH mail system.
@@ -220,6 +174,18 @@
   (mh-find-path)
   (call-interactively 'mh-send-other-window))
 
+(defun mh-send-other-window (to cc subject)
+  "Compose a message in another window.
+
+See `mh-send' for more information and a description of how the
+TO, CC, and SUBJECT arguments are used."
+  (interactive (list
+                (mh-interactive-read-address "To: ")
+                (mh-interactive-read-address "Cc: ")
+                (mh-interactive-read-string "Subject: ")))
+  (let ((pop-up-windows t))
+    (mh-send-sub to cc subject (current-window-configuration))))
+
 (defvar mh-error-if-no-draft nil)       ;raise error over using old draft
 
 ;;;###autoload
@@ -271,6 +237,117 @@
                         (cdr (car other-headers)))
       (setq other-headers (cdr other-headers)))))
 
+;; Shush compiler.
+(eval-when-compile (mh-do-in-xemacs (defvar sendmail-coding-system)))
+
+;;;###autoload
+(defun mh-send-letter (&optional arg)
+  "Save draft and send message.
+
+When you are all through editing a message, you send it with this
+command. You can give a prefix argument ARG to monitor the first stage
+of the delivery\; this output can be found in a buffer called \"*MH-E
+Mail Delivery*\".
+
+The hook `mh-before-send-letter-hook' is run at the beginning of
+this command. For example, if you want to check your spelling in
+your message before sending, add the function `ispell-message'.
+
+In case the MH \"send\" program is installed under a different name,
+use `mh-send-prog' to tell MH-E the name."
+  (interactive "P")
+  (run-hooks 'mh-before-send-letter-hook)
+  (if (and (mh-insert-auto-fields t)
+           mh-auto-fields-prompt-flag
+           (goto-char (point-min)))
+      (if (not (y-or-n-p "Auto fields inserted, send? "))
+          (error "Send aborted")))
+  (cond ((mh-mh-directive-present-p)
+         (mh-mh-to-mime))
+        ((or (mh-mml-tag-present-p) (not (mh-ascii-buffer-p)))
+         (mh-mml-to-mime)))
+  (save-buffer)
+  (message "Sending...")
+  (let ((draft-buffer (current-buffer))
+        (file-name buffer-file-name)
+        (config mh-previous-window-config)
+        (coding-system-for-write
+         (if (and (local-variable-p 'buffer-file-coding-system
+                                    (current-buffer)) ;XEmacs needs two args
+                  ;; We're not sure why, but buffer-file-coding-system
+                  ;; tends to get set to undecided-unix.
+                  (not (memq buffer-file-coding-system
+                             '(undecided undecided-unix undecided-dos))))
+             buffer-file-coding-system
+           (or (and (boundp 'sendmail-coding-system) sendmail-coding-system)
+               (and (boundp 'default-buffer-file-coding-system )
+                    default-buffer-file-coding-system)
+               'iso-latin-1))))
+    ;; Adding a Message-ID field looks good, makes it easier to search for
+    ;; message in your +outbox, and best of all doesn't break threading for
+    ;; the recipient if you reply to a message in your +outbox.
+    (setq mh-send-args (concat "-msgid " mh-send-args))
+    ;; The default BCC encapsulation will make a MIME message unreadable.
+    ;; With nmh use the -mime arg to prevent this.
+    (if (and (mh-variant-p 'nmh)
+             (mh-goto-header-field "Bcc:")
+             (mh-goto-header-field "Content-Type:"))
+        (setq mh-send-args (concat "-mime " mh-send-args)))
+    (cond (arg
+           (pop-to-buffer mh-mail-delivery-buffer)
+           (erase-buffer)
+           (mh-exec-cmd-output mh-send-prog t "-watch" "-nopush"
+                               "-nodraftfolder" mh-send-args file-name)
+           (goto-char (point-max))      ; show the interesting part
+           (recenter -1)
+           (set-buffer draft-buffer))   ; for annotation below
+          (t
+           (mh-exec-cmd-daemon mh-send-prog nil "-nodraftfolder" "-noverbose"
+                               mh-send-args file-name)))
+    (if mh-annotate-char
+        (mh-annotate-msg mh-sent-from-msg
+                         mh-sent-from-folder
+                         mh-annotate-char
+                         "-component" mh-annotate-field
+                         "-text" (format "\"%s %s\""
+                                         (mh-get-header-field "To:")
+                                         (mh-get-header-field "Cc:"))))
+
+    (cond ((or (not arg)
+               (y-or-n-p "Kill draft buffer? "))
+           (kill-buffer draft-buffer)
+           (if config
+               (set-window-configuration config))))
+    (if arg
+        (message "Sending...done")
+      (message "Sending...backgrounded"))))
+
+;;;###autoload
+(defun mh-fully-kill-draft ()
+  "Quit editing and delete draft message.
+
+If for some reason you are not happy with the draft, you can use
+this command to kill the draft buffer and delete the draft
+message. Use the command \\[kill-buffer] if you don't want to
+delete the draft message."
+  (interactive)
+  (if (y-or-n-p "Kill draft message? ")
+      (let ((config mh-previous-window-config))
+        (if (file-exists-p buffer-file-name)
+            (delete-file buffer-file-name))
+        (set-buffer-modified-p nil)
+        (kill-buffer (buffer-name))
+        (message "")
+        (if config
+            (set-window-configuration config)))
+    (error "Message not killed")))
+
+
+
+;;; MH-Folder Commands
+
+;; Alphabetical.
+
 ;;;###mh-autoload
 (defun mh-edit-again (message)
   "Edit a MESSAGE to send it again.
@@ -509,32 +586,6 @@
       (kill-buffer draft)
       (message "Redistributing...done"))))
 
-(defun mh-show-buffer-message-number (&optional buffer)
-  "Message number of displayed message in corresponding show buffer.
-
-Return nil if show buffer not displayed.
-If in `mh-letter-mode', don't display the message number being replied
-to, but rather the message number of the show buffer associated with
-our originating folder buffer.
-Optional argument BUFFER can be used to specify the buffer."
-  (save-excursion
-    (if buffer
-        (set-buffer buffer))
-    (cond ((eq major-mode 'mh-show-mode)
-           (let ((number-start (mh-search-from-end ?/ buffer-file-name)))
-             (string-to-number (substring buffer-file-name
-                                          (1+ number-start)))))
-          ((and (eq major-mode 'mh-folder-mode)
-                mh-show-buffer
-                (get-buffer mh-show-buffer))
-           (mh-show-buffer-message-number mh-show-buffer))
-          ((and (eq major-mode 'mh-letter-mode)
-                mh-sent-from-folder
-                (get-buffer mh-sent-from-folder))
-           (mh-show-buffer-message-number mh-sent-from-folder))
-          (t
-           nil))))
-
 ;;;###mh-autoload
 (defun mh-reply (message &optional reply-to includep)
   "Reply to a MESSAGE.
@@ -667,18 +718,50 @@
     (delete-other-windows)
     (mh-send-sub to cc subject config)))
 
+
+
+;;; Support Routines
+
+(defun mh-interactive-read-address (prompt)
+  "Read an address.
+If `mh-compose-prompt-flag' is non-nil, then read an address with
+PROMPT.
+Otherwise return the empty string."
+  (if mh-compose-prompt-flag (mh-read-address prompt) ""))
+
+(defun mh-interactive-read-string (prompt)
+  "Read a string.
+If `mh-compose-prompt-flag' is non-nil, then read a string with
+PROMPT.
+Otherwise return the empty string."
+  (if mh-compose-prompt-flag (read-string prompt) ""))
+
 ;;;###mh-autoload
-(defun mh-send-other-window (to cc subject)
-  "Compose a message in another window.
+(defun mh-show-buffer-message-number (&optional buffer)
+  "Message number of displayed message in corresponding show buffer.
 
-See `mh-send' for more information and a description of how the
-TO, CC, and SUBJECT arguments are used."
-  (interactive (list
-                (mh-interactive-read-address "To: ")
-                (mh-interactive-read-address "Cc: ")
-                (mh-interactive-read-string "Subject: ")))
-  (let ((pop-up-windows t))
-    (mh-send-sub to cc subject (current-window-configuration))))
+Return nil if show buffer not displayed.
+If in `mh-letter-mode', don't display the message number being replied
+to, but rather the message number of the show buffer associated with
+our originating folder buffer.
+Optional argument BUFFER can be used to specify the buffer."
+  (save-excursion
+    (if buffer
+        (set-buffer buffer))
+    (cond ((eq major-mode 'mh-show-mode)
+           (let ((number-start (mh-search-from-end ?/ buffer-file-name)))
+             (string-to-number (substring buffer-file-name
+                                          (1+ number-start)))))
+          ((and (eq major-mode 'mh-folder-mode)
+                mh-show-buffer
+                (get-buffer mh-show-buffer))
+           (mh-show-buffer-message-number mh-show-buffer))
+          ((and (eq major-mode 'mh-letter-mode)
+                mh-sent-from-folder
+                (get-buffer mh-sent-from-folder))
+           (mh-show-buffer-message-number mh-sent-from-folder))
+          (t
+           nil))))
 
 (defun mh-send-sub (to cc subject config)
   "Do the real work of composing and sending a letter.
@@ -777,19 +860,6 @@
     (mh-exec-cmd-quiet t "mhpath" mh-draft-folder "new")
     (buffer-substring (point-min) (1- (point-max)))))
 
-(defun mh-annotate-msg (msg buffer note &rest args)
-  "Mark MSG in BUFFER with character NOTE and annotate message with ARGS.
-MSG can be a message number, a list of message numbers, or a
-sequence."
-  (apply 'mh-exec-cmd "anno" buffer
-         (if (listp msg) (append msg args) (cons msg args)))
-  (save-excursion
-    (cond ((get-buffer buffer)          ; Buffer may be deleted
-           (set-buffer buffer)
-           (mh-iterate-on-range nil msg
-             (mh-notate nil note
-                        (+ mh-cmd-note mh-scan-field-destination-offset)))))))
-
 (defun mh-insert-fields (&rest name-values)
   "Insert the NAME-VALUES pairs in the current buffer.
 If the field exists, append the value to it.
@@ -808,459 +878,56 @@
                (insert field-name " " value "\n")))
         (setq name-values (cdr (cdr name-values)))))))
 
-(defun mh-position-on-field (field &optional ignored)
-  "Move to the end of the FIELD in the header.
-Move to end of entire header if FIELD not found.
-Returns non-nil iff FIELD was found.
-The optional second arg is for pre-version 4 compatibility and is
-IGNORED."
-  (cond ((mh-goto-header-field field)
-         (mh-header-field-end)
-         t)
-        ((mh-goto-header-end 0)
-         nil)))
+(defun mh-compose-and-send-mail (draft send-args
+                                       sent-from-folder sent-from-msg
+                                       to subject cc
+                                       annotate-char annotate-field
+                                       config)
+  "Edit and compose a draft message in buffer DRAFT and send or save it.
+SEND-ARGS is the argument passed to the send command.
+SENT-FROM-FOLDER is buffer containing scan listing of current folder,
+or nil if none exists.
+SENT-FROM-MSG is the message number or sequence name or nil.
+The TO, SUBJECT, and CC fields are passed to the
+`mh-compose-letter-function'.
+If ANNOTATE-CHAR is non-null, it is used to notate the scan listing of
+the message. In that case, the ANNOTATE-FIELD is used to build a
+string for `mh-annotate-msg'.
+CONFIG is the window configuration to restore after sending the
+letter."
+  (pop-to-buffer draft)
+  (mh-letter-mode)
 
-;;;###mh-autoload
-(defun mh-get-header-field (field)
-  "Find and return the body of FIELD in the mail header.
-Returns the empty string if the field is not in the header of the
-current buffer."
-  (if (mh-goto-header-field field)
-      (progn
-        (skip-chars-forward " \t")      ;strip leading white space in body
-        (let ((start (point)))
-          (mh-header-field-end)
-          (buffer-substring-no-properties start (point))))
-    ""))
-
-(fset 'mh-get-field 'mh-get-header-field) ;MH-E 4 compatibility
-
-(defun mh-goto-header-field (field)
-  "Move to FIELD in the message header.
-Move to the end of the FIELD name, which should end in a colon.
-Returns t if found, nil if not."
-  (goto-char (point-min))
-  (let ((case-fold-search t)
-        (headers-end (save-excursion
-                       (mh-goto-header-end 0)
-                       (point))))
-    (re-search-forward (format "^%s" field) headers-end t)))
-
-(defun mh-goto-header-end (arg)
-  "Move the cursor ARG lines after the header."
-  (if (re-search-forward "^-*$" nil nil)
-      (forward-line arg)))
-
-(defun mh-extract-from-header-value ()
-  "Extract From: string from header."
-  (save-excursion
-    (if (not (mh-goto-header-field "From:"))
-        nil
-      (skip-chars-forward " \t")
-      (buffer-substring-no-properties
-       (point) (progn (mh-header-field-end)(point))))))
-
-
-
-;;; Mode for composing and sending a draft message.
-
-(defvar mh-pgp-support-flag (not (not (locate-library "mml2015")))
-  "Non-nil means PGP support is available.")
-
-(put 'mh-letter-mode 'mode-class 'special)
-
-;; Menu extracted from mh-menubar.el V1.1 (31 July 2001)
-(eval-when-compile (defvar mh-letter-menu nil))
-(easy-menu-define
-  mh-letter-menu mh-letter-mode-map "Menu for MH-E letter mode."
-  '("Letter"
-    ["Send This Draft"          mh-send-letter t]
-    ["Split Current Line"       mh-open-line t]
-    ["Check Recipient"          mh-check-whom t]
-    ["Yank Current Message"     mh-yank-cur-msg t]
-    ["Insert a Message..."      mh-insert-letter t]
-    ["Insert Signature"         mh-insert-signature t]
-    ("Encrypt/Sign Message"
-     ["Sign Message"
-      mh-mml-secure-message-sign mh-pgp-support-flag]
-     ["Encrypt Message"
-      mh-mml-secure-message-encrypt mh-pgp-support-flag]
-     ["Sign+Encrypt Message"
-      mh-mml-secure-message-signencrypt mh-pgp-support-flag]
-     ["Disable Security"
-      mh-mml-unsecure-message mh-pgp-support-flag]
-     "--"
-     "Security Method"
-     ["PGP (MIME)" (setq mh-mml-method-default "pgpmime")
-      :style radio
-      :selected (equal mh-mml-method-default "pgpmime")]
-     ["PGP" (setq mh-mml-method-default "pgp")
-      :style radio
-      :selected (equal mh-mml-method-default "pgp")]
-     ["S/MIME" (setq mh-mml-method-default "smime")
-      :style radio
-      :selected (equal mh-mml-method-default "smime")]
-     "--"
-     ["Save Method as Default"
-      (customize-save-variable 'mh-mml-method-default mh-mml-method-default) t]
-     )
-    ["Compose Insertion..."      mh-compose-insertion t]
-    ["Compose Compressed tar (MH)..."
-     mh-mh-compose-external-compressed-tar t]
-    ["Compose Get File (MH)..."       mh-mh-compose-anon-ftp t]
-    ["Compose Forward..."        mh-compose-forward t]
-    ;; The next two will have to be merged. But I also need to make sure the
-    ;; user can't mix tags of both types.
-    ["Pull in All Compositions (MH)"
-     mh-mh-to-mime (mh-mh-directive-present-p)]
-    ["Pull in All Compositions (MML)"
-     mh-mml-to-mime (mh-mml-tag-present-p)]
-    ["Revert to Non-MIME Edit (MH)"
-     mh-mh-to-mime-undo (equal mh-compose-insertion 'mh)]
-    ["Kill This Draft"          mh-fully-kill-draft t]))
-
-
-
-;;; Help Messages
-
-;; Group messages logically, more or less.
-(defvar mh-letter-mode-help-messages
-  '((nil
-     "Send letter:          \\[mh-send-letter]"
-     "\t\tOpen line:            \\[mh-open-line]\n"
-     "Kill letter:          \\[mh-fully-kill-draft]"
-     "\t\tInsert:\n"
-     "Check recipients:     \\[mh-check-whom]"
-     "\t\t  Current message:    \\[mh-yank-cur-msg]\n"
-     "\t\t  Attachment:             \\[mh-compose-insertion]\n"
-     "\t\t  Message to forward:     \\[mh-compose-forward]\n"
-     "                          "
-     "Security:"
-     "\t\t  Encrypt message:          \\[mh-mml-secure-message-encrypt]"
-     "\t\t  Sign+Encrypt message:     \\[mh-mml-secure-message-signencrypt]"
-     "\t\t  Sign message:             \\[mh-mml-secure-message-sign]\n"
-     "                          "
-     "\t\t  Signature:              \\[mh-insert-signature]"))
-  "Key binding cheat sheet.
-
-This is an associative array which is used to show the most
-common commands. The key is a prefix char. The value is one or
-more strings which are concatenated together and displayed in the
-minibuffer if ? is pressed after the prefix character. The
-special key nil is used to display the non-prefixed commands.
-
-The substitutions described in `substitute-command-keys' are
-performed as well.")
-
-;; Shush compiler.
-(eval-when-compile
-  (defvar adaptive-fill-first-line-regexp)
-  (defvar tool-bar-map))
-
-(defvar mh-letter-buttons-init-flag nil)
-
-;;;###autoload
-(define-derived-mode mh-letter-mode mail-mode "MH-Letter"
-  "Mode for composing letters in MH-E\\<mh-letter-mode-map>.
-
-When you have finished composing, type \\[mh-send-letter] to send
-the message using the MH mail handling system.
-
-There are two types of tags used by MH-E when composing MIME
-messages: MML and MH. The option `mh-compose-insertion' controls
-what type of tags are inserted by MH-E commands. These tags can
-be converted to MIME body parts by running \\[mh-mh-to-mime] for
-MH-style directives or \\[mh-mml-to-mime] for MML tags.
-
-Options that control this mode can be changed with
-\\[customize-group]; specify the \"mh-compose\" group.
-
-When a message is composed, the hooks `text-mode-hook',
-`mail-mode-hook', and `mh-letter-mode-hook' are run (in that
-order).
-
-\\{mh-letter-mode-map}"
-  (mh-find-path)
-  (make-local-variable 'mh-send-args)
-  (make-local-variable 'mh-annotate-char)
-  (make-local-variable 'mh-annotate-field)
-  (make-local-variable 'mh-previous-window-config)
-  (make-local-variable 'mh-sent-from-folder)
-  (make-local-variable 'mh-sent-from-msg)
-  (mh-do-in-gnu-emacs
-   (unless mh-letter-buttons-init-flag
-     (mh-tool-bar-letter-buttons-init)
-     (setq mh-letter-buttons-init-flag t)))
-  ;; Set the local value of mh-mail-header-separator according to what is
-  ;; present in the buffer...
-  (set (make-local-variable 'mh-mail-header-separator)
-       (save-excursion
-         (goto-char (mh-mail-header-end))
-         (buffer-substring-no-properties (point) (line-end-position))))
-  (make-local-variable 'mail-header-separator)
-  (setq mail-header-separator mh-mail-header-separator) ;override sendmail.el
-  (make-local-variable 'mh-help-messages)
-  (setq mh-help-messages mh-letter-mode-help-messages)
-  (setq buffer-invisibility-spec '((vanish . t) t))
-  (set (make-local-variable 'line-move-ignore-invisible) t)
-
-  ;; Enable undo since a show-mode buffer might have been reused.
-  (buffer-enable-undo)
-  (set (make-local-variable 'tool-bar-map) mh-letter-tool-bar-map)
-  (mh-funcall-if-exists mh-tool-bar-init :letter)
-  (make-local-variable 'font-lock-defaults)
-  (cond
-   ((or (equal mh-highlight-citation-style 'font-lock)
-        (equal mh-highlight-citation-style 'gnus))
-    ;; Let's use font-lock even if gnus is used in show-mode.  The reason
-    ;; is that gnus uses static text properties which are not appropriate
-    ;; for a buffer that will be edited.  So the choice here is either fontify
-    ;; the citations and header...
-    (setq font-lock-defaults '(mh-letter-font-lock-keywords t)))
-   (t
-    ;; ...or the header only
-    (setq font-lock-defaults '(mh-show-font-lock-keywords t))))
-  (easy-menu-add mh-letter-menu)
-  (setq fill-column mh-letter-fill-column)
-  ;; If text-mode-hook turned on auto-fill, tune it for messages
-  (when auto-fill-function
-    (make-local-variable 'auto-fill-function)
-    (setq auto-fill-function 'mh-auto-fill-for-letter)))
-
-(defun mh-font-lock-field-data (limit)
-  "Find header field region between point and LIMIT."
-  (and (< (point) (mh-letter-header-end))
-       (< (point) limit)
-       (let ((end (min limit (mh-letter-header-end)))
-             (point (point))
-             data-end data-begin field)
-         (end-of-line)
-         (setq data-end (if (re-search-forward "^[^ \t]" end t)
-                            (match-beginning 0)
-                          end))
-         (goto-char (1- data-end))
-         (if (not (re-search-backward "\\(^[^ \t][^:]*\\):[ \t]*" nil t))
-             (setq data-begin (point-min))
-           (setq data-begin (match-end 0))
-           (setq field (match-string 1)))
-         (setq data-begin (max point data-begin))
-         (goto-char (if (equal point data-end) (1+ data-end) data-end))
-         (cond ((and field (mh-letter-skipped-header-field-p field))
-                (set-match-data nil)
-                nil)
-               (t (set-match-data
-                   (list data-begin data-end data-begin data-end))
-                  t)))))
-
-(defun mh-letter-header-end ()
-  "Find the end of the message header.
-This function is to be used only for font locking. It works by
-searching for `mh-mail-header-separator' in the buffer."
-  (save-excursion
-    (goto-char (point-min))
-    (cond ((equal mh-mail-header-separator "") (point-min))
-          ((search-forward (format "\n%s\n" mh-mail-header-separator) nil t)
-           (line-beginning-position 0))
-          (t (point-min)))))
-
-(defun mh-auto-fill-for-letter ()
-  "Perform auto-fill for message.
-Header is treated specially by inserting a tab before continuation
-lines."
-  (if (mh-in-header-p)
-      (let ((fill-prefix "\t"))
-        (do-auto-fill))
-    (do-auto-fill)))
-
-(defun mh-insert-header-separator ()
-  "Insert `mh-mail-header-separator', if absent."
-  (save-excursion
-    (goto-char (point-min))
-    (rfc822-goto-eoh)
-    (if (looking-at "$")
-        (insert mh-mail-header-separator))))
-
-;;;###mh-autoload
-(defun mh-to-field ()
-  "Move to specified header field.
-
-The field is indicated by the previous keystroke (the last
-keystroke of the command) according to the list in the variable
-`mh-to-field-choices'.
-Create the field if it does not exist.
-Set the mark to point before moving."
-  (interactive)
-  (expand-abbrev)
-  (let ((target (cdr (or (assoc (char-to-string (logior last-input-char ?`))
-                                mh-to-field-choices)
-                         ;; also look for a char for version 4 compat
-                         (assoc (logior last-input-char ?`)
-                                mh-to-field-choices))))
-        (case-fold-search t))
-    (push-mark)
-    (cond ((mh-position-on-field target)
-           (let ((eol (point)))
-             (skip-chars-backward " \t")
-             (delete-region (point) eol))
-           (if (and (not (eq (logior last-input-char ?`) ?s))
-                    (save-excursion
-                      (backward-char 1)
-                      (not (looking-at "[:,]"))))
-               (insert ", ")
-             (insert " ")))
-          (t
-           (if (mh-position-on-field "To:")
-               (forward-line 1))
-           (insert (format "%s \n" target))
-           (backward-char 1)))))
-
-;;;###mh-autoload
-(defun mh-to-fcc (&optional folder)
-  "Move to \"Fcc:\" header field.
-
-This command will prompt you for the FOLDER name in which to file
-a copy of the draft."
-  (interactive (list (mh-prompt-for-folder
-                      "Fcc"
-                      (or (and mh-default-folder-for-message-function
-                               (save-excursion
-                                 (goto-char (point-min))
-                                 (funcall
-                                  mh-default-folder-for-message-function)))
-                          "")
-                      t)))
-  (let ((last-input-char ?\C-f))
-    (expand-abbrev)
-    (save-excursion
-      (mh-to-field)
-      (insert (if (mh-folder-name-p folder)
-                  (substring folder 1)
-                folder)))))
-
-(defun mh-file-is-vcard-p (file)
-  "Return t if FILE is a .vcf vcard."
-  (let ((case-fold-search t))
-    (and (stringp file)
-         (file-exists-p file)
-         (or (and (not (mh-have-file-command))
-                  (not (null (string-match "\.vcf$" file))))
-             (string-equal "text/x-vcard" (mh-file-mime-type file))))))
-
-;;;###mh-autoload
-(defun mh-insert-signature (&optional file)
-  "Insert signature in message.
-
-This command inserts your signature at the current cursor location.
-
-By default, the text of your signature is taken from the file
-\"~/.signature\". You can read from other sources by changing the
-option `mh-signature-file-name'.
-
-A signature separator (\"-- \") will be added if the signature block
-does not contain one and `mh-signature-separator-flag' is on.
-
-The hook `mh-insert-signature-hook' is run after the signature is
-inserted. Hook functions may access the actual name of the file or the
-function used to insert the signature with `mh-signature-file-name'.
-
-The signature can also be inserted using Identities (see
-`mh-identity-list').
-
-In a program, you can pass in a signature FILE."
-  (interactive)
-  (save-excursion
-    (insert "\n")
-    (let ((mh-signature-file-name (or file mh-signature-file-name))
-          (mh-mh-p (mh-mh-directive-present-p))
-          (mh-mml-p (mh-mml-tag-present-p)))
-      (save-restriction
-        (narrow-to-region (point) (point))
-        (cond
-         ((mh-file-is-vcard-p mh-signature-file-name)
-          (if (equal mh-compose-insertion 'mml)
-              (insert "<#part type=\"text/x-vcard\" filename=\""
-                      mh-signature-file-name
-                      "\" disposition=inline description=VCard>\n<#/part>")
-            (insert "#text/x-vcard; name=\""
-                    (file-name-nondirectory mh-signature-file-name)
-                    "\" [VCard] " (expand-file-name mh-signature-file-name))))
-         (t
-          (cond
-           (mh-mh-p
-            (insert "#\n" "Content-Description: Signature\n"))
-           (mh-mml-p
-            (mml-insert-tag 'part 'type "text/plain" 'disposition "inline"
-                            'description "Signature")))
-          (cond ((null mh-signature-file-name))
-                ((and (stringp mh-signature-file-name)
-                      (file-readable-p mh-signature-file-name))
-                 (insert-file-contents mh-signature-file-name))
-                ((functionp mh-signature-file-name)
-                 (funcall mh-signature-file-name)))))
-        (save-restriction
-          (widen)
-          (run-hooks 'mh-insert-signature-hook))
-        (goto-char (point-min))
-        (when (and (not (mh-file-is-vcard-p mh-signature-file-name))
-                   mh-signature-separator-flag
-                   (> (point-max) (point-min))
-                   (not (mh-signature-separator-p)))
-          (cond (mh-mh-p
-                 (forward-line 2))
-                (mh-mml-p
-                 (forward-line 1)))
-          (insert mh-signature-separator))
-        (if (not (> (point-max) (point-min)))
-            (message "No signature found")))))
-  (force-mode-line-update))
-
-;;;###mh-autoload
-(defun mh-check-whom ()
-  "Verify recipients, showing expansion of any aliases.
-
-This command expands aliases so you can check the actual address(es)
-in the alias. A new buffer named \"*MH-E Recipients*\" is created with
-the output of \"whom\"."
-  (interactive)
-  (let ((file-name buffer-file-name))
-    (save-buffer)
-    (message "Checking recipients...")
-    (mh-in-show-buffer (mh-recipients-buffer)
-      (bury-buffer (current-buffer))
-      (erase-buffer)
-      (mh-exec-cmd-output "whom" t file-name))
-    (message "Checking recipients...done")))
-
-(defun mh-tidy-draft-buffer ()
-  "Run when a draft buffer is destroyed."
-  (let ((buffer (get-buffer mh-recipients-buffer)))
-    (if buffer
-       (kill-buffer buffer))))
-
-
+  ;; Insert identity.
+  (mh-insert-identity mh-identity-default t)
+  (mh-identity-make-menu)
+  (mh-identity-add-menu)
 
-;;; Routines to compose and send a letter.
+  ;; Insert extra fields.
+  (mh-insert-x-mailer)
+  (mh-insert-x-face)
 
-(defun mh-insert-x-face ()
-  "Append X-Face, Face or X-Image-URL field to header.
-If the field already exists, this function does nothing."
-  (when (and (file-exists-p mh-x-face-file)
-             (file-readable-p mh-x-face-file))
-    (save-excursion
-      (unless (or (mh-position-on-field "X-Face")
-                  (mh-position-on-field "Face")
-                  (mh-position-on-field "X-Image-URL"))
-        (save-excursion
-          (goto-char (+ (point) (cadr (insert-file-contents mh-x-face-file))))
-          (if (not (looking-at "^"))
-              (insert "\n")))
-        (unless (looking-at "\\(X-Face\\|Face\\|X-Image-URL\\): ")
-          (insert "X-Face: "))))))
+  (mh-letter-hide-all-skipped-fields)
 
-(defvar mh-x-mailer-string nil
-  "*String containing the contents of the X-Mailer header field.
-If nil, this variable is initialized to show the version of MH-E,
-Emacs, and MH the first time a message is composed.")
+  (setq mh-sent-from-folder sent-from-folder)
+  (setq mh-sent-from-msg sent-from-msg)
+  (setq mh-send-args send-args)
+  (setq mh-annotate-char annotate-char)
+  (setq mh-annotate-field annotate-field)
+  (setq mh-previous-window-config config)
+  (setq mode-line-buffer-identification (list "    {%b}"))
+  (mh-logo-display)
+  (mh-make-local-hook 'kill-buffer-hook)
+  (add-hook 'kill-buffer-hook 'mh-tidy-draft-buffer nil t)
+  (if (and (boundp 'mh-compose-letter-function)
+           mh-compose-letter-function)
+      ;; run-hooks will not pass arguments.
+      (let ((value mh-compose-letter-function))
+        (if (and (listp value) (not (eq (car value) 'lambda)))
+            (while value
+              (funcall (car value) to subject cc)
+              (setq value (cdr value)))
+          (funcall mh-compose-letter-function to subject cc)))))
 
 (defun mh-insert-x-mailer ()
   "Append an X-Mailer field to the header.
@@ -1283,20 +950,89 @@
                (null (mh-goto-header-field "X-Mailer")))
       (mh-insert-fields "X-Mailer:" mh-x-mailer-string))))
 
-(defun mh-regexp-in-field-p (regexp &rest fields)
-  "Non-nil means REGEXP was found in FIELDS."
+(defun mh-insert-x-face ()
+  "Append X-Face, Face or X-Image-URL field to header.
+If the field already exists, this function does nothing."
+  (when (and (file-exists-p mh-x-face-file)
+             (file-readable-p mh-x-face-file))
+    (save-excursion
+      (unless (or (mh-position-on-field "X-Face")
+                  (mh-position-on-field "Face")
+                  (mh-position-on-field "X-Image-URL"))
+        (save-excursion
+          (goto-char (+ (point) (cadr (insert-file-contents mh-x-face-file))))
+          (if (not (looking-at "^"))
+              (insert "\n")))
+        (unless (looking-at "\\(X-Face\\|Face\\|X-Image-URL\\): ")
+          (insert "X-Face: "))))))
+
+;;;###mh-autoload
+(defun mh-letter-hide-all-skipped-fields ()
+  "Hide all skipped fields."
   (save-excursion
-    (let ((search-result nil)
-          (field))
-      (while fields
-        (setq field (car fields))
-        (if (and (mh-goto-header-field field)
-                 (re-search-forward
-                  regexp (save-excursion (mh-header-field-end)(point)) t))
-            (setq fields nil
-                  search-result t)
-          (setq fields (cdr fields))))
-      search-result)))
+    (goto-char (point-min))
+    (save-restriction
+      (narrow-to-region (point) (mh-mail-header-end))
+      (while (re-search-forward mh-letter-header-field-regexp nil t)
+        (if (mh-letter-skipped-header-field-p (match-string 1))
+            (mh-letter-toggle-header-field-display -1)
+          (mh-letter-toggle-header-field-display 'long))
+        (beginning-of-line 2)))))
+
+(defun mh-tidy-draft-buffer ()
+  "Run when a draft buffer is destroyed."
+  (let ((buffer (get-buffer mh-recipients-buffer)))
+    (if buffer
+        (kill-buffer buffer))))
+
+(defun mh-letter-mode-message ()
+  "Display a help message for users of `mh-letter-mode'.
+This should be the last function called when composing the draft."
+  (message "%s" (substitute-command-keys
+                 (concat "Type \\[mh-send-letter] to send message, "
+                         "\\[mh-help] for help"))))
+
+(defun mh-letter-adjust-point ()
+  "Move cursor to first header field if are using the no prompt mode."
+  (unless mh-compose-prompt-flag
+    (goto-char (point-max))
+    (mh-letter-next-header-field)))
+
+(defun mh-annotate-msg (msg buffer note &rest args)
+  "Mark MSG in BUFFER with character NOTE and annotate message with ARGS.
+MSG can be a message number, a list of message numbers, or a
+sequence."
+  (apply 'mh-exec-cmd "anno" buffer
+         (if (listp msg) (append msg args) (cons msg args)))
+  (save-excursion
+    (cond ((get-buffer buffer)          ; Buffer may be deleted
+           (set-buffer buffer)
+           (mh-iterate-on-range nil msg
+             (mh-notate nil note
+                        (+ mh-cmd-note mh-scan-field-destination-offset)))))))
+
+;;;###mh-autoload
+(defun mh-get-header-field (field)
+  "Find and return the body of FIELD in the mail header.
+Returns the empty string if the field is not in the header of the
+current buffer."
+  (if (mh-goto-header-field field)
+      (progn
+        (skip-chars-forward " \t")      ;strip leading white space in body
+        (let ((start (point)))
+          (mh-header-field-end)
+          (buffer-substring-no-properties start (point))))
+    ""))
+
+(fset 'mh-get-field 'mh-get-header-field) ;MH-E 4 compatibility
+
+(defun mh-insert-header-separator ()
+  "Insert `mh-mail-header-separator', if absent."
+  (save-excursion
+    (goto-char (point-min))
+    (rfc822-goto-eoh)
+    (if (looking-at "$")
+        (insert mh-mail-header-separator))))
 
 ;;;###mh-autoload
 (defun mh-insert-auto-fields (&optional non-interactive)
@@ -1332,12 +1068,13 @@
                           (value (cdar entry-list)))
                       (cond
                        ((equal ":identity" field)
-                        (when ;;(and (not mh-identity-local)
+                        (when
+                            ;;(and (not mh-identity-local)
                             ;; Bug 1204506.  But do we need to be able
-                            ;;  to set an identity manually that won't be
-                            ;;  overridden by mh-insert-auto-fields?
-                                   (assoc value mh-identity-list)
-                                   ;;)
+                            ;; to set an identity manually that won't be
+                            ;; overridden by mh-insert-auto-fields?
+                            (assoc value mh-identity-list)
+                          ;;)
                           (mh-insert-identity value)))
                        (t
                         (mh-modify-header-field field value
@@ -1365,66 +1102,20 @@
          (mh-goto-header-end 0)
          (insert field ": " value "\n"))))
 
-(defun mh-compose-and-send-mail (draft send-args
-                                       sent-from-folder sent-from-msg
-                                       to subject cc
-                                       annotate-char annotate-field
-                                       config)
-  "Edit and compose a draft message in buffer DRAFT and send or save it.
-SEND-ARGS is the argument passed to the send command.
-SENT-FROM-FOLDER is buffer containing scan listing of current folder,
-or nil if none exists.
-SENT-FROM-MSG is the message number or sequence name or nil.
-The TO, SUBJECT, and CC fields are passed to the
-`mh-compose-letter-function'.
-If ANNOTATE-CHAR is non-null, it is used to notate the scan listing of
-the message. In that case, the ANNOTATE-FIELD is used to build a
-string for `mh-annotate-msg'.
-CONFIG is the window configuration to restore after sending the
-letter."
-  (pop-to-buffer draft)
-  (mh-letter-mode)
-
-  ;; Insert identity.
-  (if (and (boundp 'mh-identity-default)
-           mh-identity-default
-           (not mh-identity-local))
-      (mh-insert-identity mh-identity-default))
-  (mh-identity-make-menu)
-  (easy-menu-add mh-identity-menu)
-
-  ;; Insert extra fields.
-  (mh-insert-x-mailer)
-  (mh-insert-x-face)
-
-  (mh-letter-hide-all-skipped-fields)
-
-  (setq mh-sent-from-folder sent-from-folder)
-  (setq mh-sent-from-msg sent-from-msg)
-  (setq mh-send-args send-args)
-  (setq mh-annotate-char annotate-char)
-  (setq mh-annotate-field annotate-field)
-  (setq mh-previous-window-config config)
-  (setq mode-line-buffer-identification (list "    {%b}"))
-  (mh-logo-display)
-  (mh-make-local-hook 'kill-buffer-hook)
-  (add-hook 'kill-buffer-hook 'mh-tidy-draft-buffer nil t)
-  (if (and (boundp 'mh-compose-letter-function)
-           mh-compose-letter-function)
-      ;; run-hooks will not pass arguments.
-      (let ((value mh-compose-letter-function))
-        (if (and (listp value) (not (eq (car value) 'lambda)))
-            (while value
-              (funcall (car value) to subject cc)
-              (setq value (cdr value)))
-          (funcall mh-compose-letter-function to subject cc)))))
-
-(defun mh-letter-mode-message ()
-  "Display a help message for users of `mh-letter-mode'.
-This should be the last function called when composing the draft."
-  (message "%s" (substitute-command-keys
-                 (concat "Type \\[mh-send-letter] to send message, "
-                         "\\[mh-help] for help"))))
+(defun mh-regexp-in-field-p (regexp &rest fields)
+  "Non-nil means REGEXP was found in FIELDS."
+  (save-excursion
+    (let ((search-result nil)
+          (field))
+      (while fields
+        (setq field (car fields))
+        (if (and (mh-goto-header-field field)
+                 (re-search-forward
+                  regexp (save-excursion (mh-header-field-end)(point)) t))
+            (setq fields nil
+                  search-result t)
+          (setq fields (cdr fields))))
+      search-result)))
 
 (defun mh-ascii-buffer-p ()
   "Check if current buffer is entirely composed of ASCII.
@@ -1435,739 +1126,6 @@
         unless (eq charset 'ascii) return nil
         finally return t))
 
-;; Shush compiler.
-(eval-when-compile (defvar sendmail-coding-system))
-
-;;;###mh-autoload
-(defun mh-send-letter (&optional arg)
-  "Save draft and send message.
-
-When you are all through editing a message, you send it with this
-command. You can give a prefix argument ARG to monitor the first stage
-of the delivery\; this output can be found in a buffer called \"*MH-E
-Mail Delivery*\".
-
-The hook `mh-before-send-letter-hook' is run at the beginning of
-this command. For example, if you want to check your spelling in
-your message before sending, add the function `ispell-message'.
-
-In case the MH \"send\" program is installed under a different name,
-use `mh-send-prog' to tell MH-E the name."
-  (interactive "P")
-  (run-hooks 'mh-before-send-letter-hook)
-  (if (and (mh-insert-auto-fields t)
-           mh-auto-fields-prompt-flag
-           (goto-char (point-min)))
-      (if (not (y-or-n-p "Auto fields inserted, send? "))
-          (error "Send aborted")))
-  (cond ((mh-mh-directive-present-p)
-         (mh-mh-to-mime))
-        ((or (mh-mml-tag-present-p) (not (mh-ascii-buffer-p)))
-         (mh-mml-to-mime)))
-  (save-buffer)
-  (message "Sending...")
-  (let ((draft-buffer (current-buffer))
-        (file-name buffer-file-name)
-        (config mh-previous-window-config)
-        (coding-system-for-write
-         (if (and (local-variable-p 'buffer-file-coding-system
-                                    (current-buffer)) ;XEmacs needs two args
-                  ;; We're not sure why, but buffer-file-coding-system
-                  ;; tends to get set to undecided-unix.
-                  (not (memq buffer-file-coding-system
-                             '(undecided undecided-unix undecided-dos))))
-             buffer-file-coding-system
-           (or (and (boundp 'sendmail-coding-system) sendmail-coding-system)
-               (and (boundp 'default-buffer-file-coding-system )
-                    default-buffer-file-coding-system)
-               'iso-latin-1))))
-    ;; Adding a Message-ID field looks good, makes it easier to search for
-    ;; message in your +outbox, and best of all doesn't break threading for
-    ;; the recipient if you reply to a message in your +outbox.
-    (setq mh-send-args (concat "-msgid " mh-send-args))
-    ;; The default BCC encapsulation will make a MIME message unreadable.
-    ;; With nmh use the -mime arg to prevent this.
-    (if (and (mh-variant-p 'nmh)
-             (mh-goto-header-field "Bcc:")
-             (mh-goto-header-field "Content-Type:"))
-        (setq mh-send-args (concat "-mime " mh-send-args)))
-    (cond (arg
-           (pop-to-buffer mh-mail-delivery-buffer)
-           (erase-buffer)
-           (mh-exec-cmd-output mh-send-prog t "-watch" "-nopush"
-                               "-nodraftfolder" mh-send-args file-name)
-           (goto-char (point-max))      ; show the interesting part
-           (recenter -1)
-           (set-buffer draft-buffer))   ; for annotation below
-          (t
-           (mh-exec-cmd-daemon mh-send-prog nil "-nodraftfolder" "-noverbose"
-                               mh-send-args file-name)))
-    (if mh-annotate-char
-        (mh-annotate-msg mh-sent-from-msg
-                         mh-sent-from-folder
-                         mh-annotate-char
-                         "-component" mh-annotate-field
-                         "-text" (format "\"%s %s\""
-                                         (mh-get-header-field "To:")
-                                         (mh-get-header-field "Cc:"))))
-
-    (cond ((or (not arg)
-               (y-or-n-p "Kill draft buffer? "))
-           (kill-buffer draft-buffer)
-           (if config
-               (set-window-configuration config))))
-    (if arg
-        (message "Sending...done")
-      (message "Sending...backgrounded"))))
-
-;;;###mh-autoload
-(defun mh-insert-letter (folder message verbatim)
-  "Insert a message.
-
-This command prompts you for the FOLDER and MESSAGE number, which
-defaults to the current message in that folder. It then inserts
-the message, indented by `mh-ins-buf-prefix' (\"> \") unless
-`mh-yank-behavior' is set to one of the supercite flavors in
-which case supercite is used to format the message. Certain
-undesirable header fields (see
-`mh-invisible-header-fields-compiled') are removed before
-insertion.
-
-If given a prefix argument VERBATIM, the header is left intact, the
-message is not indented, and \"> \" is not inserted before each line.
-This command leaves the mark before the letter and point after it."
-  (interactive
-   (let* ((folder
-           (mh-prompt-for-folder "Message from"
-                                 mh-sent-from-folder nil))
-          (default
-            (if (and (equal folder mh-sent-from-folder)
-                     (numberp mh-sent-from-msg))
-                mh-sent-from-msg
-              (nth 0 (mh-translate-range folder "cur"))))
-          (message
-           (read-string (concat "Message number"
-                                (or (and default
-                                         (format " (default %d): " default))
-                                    ": ")))))
-     (list folder message current-prefix-arg)))
-  (save-restriction
-    (narrow-to-region (point) (point))
-    (let ((start (point-min)))
-      (if (and (equal message "") (numberp mh-sent-from-msg))
-          (setq message (int-to-string mh-sent-from-msg)))
-      (insert-file-contents
-       (expand-file-name message (mh-expand-file-name folder)))
-      (when (not verbatim)
-        (mh-clean-msg-header start mh-invisible-header-fields-compiled nil)
-        (goto-char (point-max))         ;Needed for sc-cite-original
-        (push-mark)                     ;Needed for sc-cite-original
-        (goto-char (point-min))         ;Needed for sc-cite-original
-        (mh-insert-prefix-string mh-ins-buf-prefix)))))
-
-(defun mh-extract-from-attribution ()
-  "Extract phrase or comment from From header field."
-  (save-excursion
-    (if (not (mh-goto-header-field "From: "))
-        nil
-      (skip-chars-forward " ")
-      (cond
-       ((looking-at "\"\\([^\"\n]+\\)\" \\(<.+>\\)")
-        (format "%s %s " (match-string 1)(match-string 2)))
-       ((looking-at "\\([^<\n]+<.+>\\)$")
-        (format "%s " (match-string 1)))
-       ((looking-at "\\([^ address@hidden ]+\\) +(\\(.+\\))$")
-        (format "%s <%s> " (match-string 2)(match-string 1)))
-       ((looking-at " *\\(.+\\)$")
-        (format "%s " (match-string 1)))))))
-
-;;;###mh-autoload
-(defun mh-yank-cur-msg ()
-  "Insert the current message into the draft buffer.
-
-It is often useful to insert a snippet of text from a letter that
-someone mailed to provide some context for your reply. This
-command does this by adding an attribution, yanking a portion of
-text from the message to which you're replying, and inserting
-`mh-ins-buf-prefix' (`> ') before each line.
-
-The attribution consists of the sender's name and email address
-followed by the content of the option
-`mh-extract-from-attribution-verb'.
-
-You can also turn on the option
-`mh-delete-yanked-msg-window-flag' to delete the window
-containing the original message after yanking it to make more
-room on your screen for your reply.
-
-You can control how the message to which you are replying is
-yanked into your reply using `mh-yank-behavior'.
-
-If this isn't enough, you can gain full control over the
-appearance of the included text by setting `mail-citation-hook'
-to a function that modifies it. For example, if you set this hook
-to `trivial-cite' (which is NOT part of Emacs), set
-`mh-yank-behavior' to \"Body and Header\" (see URL
-`http://shasta.cs.uiuc.edu/~lrclause/tc.html').
-
-Note that if `mail-citation-hook' is set, `mh-ins-buf-prefix' is
-not inserted. If the option `mh-yank-behavior' is set to one of
-the supercite flavors, the hook `mail-citation-hook' is ignored
-and `mh-ins-buf-prefix' is not inserted."
-  (interactive)
-  (if (and mh-sent-from-folder
-           (save-excursion (set-buffer mh-sent-from-folder) mh-show-buffer)
-           (save-excursion (set-buffer mh-sent-from-folder)
-                           (get-buffer mh-show-buffer))
-           mh-sent-from-msg)
-      (let ((to-point (point))
-            (to-buffer (current-buffer)))
-        (set-buffer mh-sent-from-folder)
-        (if mh-delete-yanked-msg-window-flag
-            (delete-windows-on mh-show-buffer))
-        (set-buffer mh-show-buffer)     ; Find displayed message
-        (let* ((from-attr (mh-extract-from-attribution))
-               (yank-region (mh-mark-active-p nil))
-               (mh-ins-str
-                (cond ((and yank-region
-                            (or (eq 'supercite mh-yank-behavior)
-                                (eq 'autosupercite mh-yank-behavior)
-                                (eq t mh-yank-behavior)))
-                       ;; supercite needs the full header
-                       (concat
-                        (buffer-substring (point-min) (mh-mail-header-end))
-                        "\n"
-                        (buffer-substring (region-beginning) (region-end))))
-                      (yank-region
-                       (buffer-substring (region-beginning) (region-end)))
-                      ((or (eq 'body mh-yank-behavior)
-                           (eq 'attribution mh-yank-behavior)
-                           (eq 'autoattrib mh-yank-behavior))
-                       (buffer-substring
-                        (save-excursion
-                          (goto-char (point-min))
-                          (mh-goto-header-end 1)
-                          (point))
-                        (point-max)))
-                      ((or (eq 'supercite mh-yank-behavior)
-                           (eq 'autosupercite mh-yank-behavior)
-                           (eq t mh-yank-behavior))
-                       (buffer-substring (point-min) (point-max)))
-                      (t
-                       (buffer-substring (point) (point-max))))))
-          (set-buffer to-buffer)
-          (save-restriction
-            (narrow-to-region to-point to-point)
-            (insert (mh-filter-out-non-text mh-ins-str))
-            (goto-char (point-max))     ;Needed for sc-cite-original
-            (push-mark)                 ;Needed for sc-cite-original
-            (goto-char (point-min))     ;Needed for sc-cite-original
-            (mh-insert-prefix-string mh-ins-buf-prefix)
-            (when (or (eq 'attribution mh-yank-behavior)
-                      (eq 'autoattrib mh-yank-behavior))
-              (insert from-attr)
-              (mh-identity-insert-attribution-verb nil)
-              (insert "\n\n"))
-            ;; If the user has selected a region, he has already "edited" the
-            ;; text, so leave the cursor at the end of the yanked text. In
-            ;; either case, leave a mark at the opposite end of the included
-            ;; text to make it easy to jump or delete to the other end of the
-            ;; text.
-            (push-mark)
-            (goto-char (point-max))
-            (if (null yank-region)
-                (mh-exchange-point-and-mark-preserving-active-mark)))))
-    (error "There is no current message")))
-
-(defun mh-filter-out-non-text (string)
-  "Return STRING but without adornments such as MIME buttons and smileys."
-  (with-temp-buffer
-    ;; Insert the string to filter
-    (insert string)
-    (goto-char (point-min))
-
-    ;; Remove the MIME buttons
-    (let ((can-move-forward t)
-          (in-button nil))
-      (while can-move-forward
-        (cond ((and (not (get-text-property (point) 'mh-data))
-                    in-button)
-               (delete-region (1- (point)) (point))
-               (setq in-button nil))
-              ((get-text-property (point) 'mh-data)
-               (delete-region (point)
-                              (save-excursion (forward-line) (point)))
-               (setq in-button t))
-              (t (setq can-move-forward (= (forward-line) 0))))))
-
-    ;; Return the contents without properties... This gets rid of emphasis
-    ;; and smileys
-    (buffer-substring-no-properties (point-min) (point-max))))
-
-(defun mh-insert-prefix-string (mh-ins-string)
-  "Insert prefix string before each line in buffer.
-The inserted letter is cited using `sc-cite-original' if
-`mh-yank-behavior' is one of 'supercite or 'autosupercite.
-Otherwise, simply insert MH-INS-STRING before each line."
-  (goto-char (point-min))
-  (cond ((or (eq mh-yank-behavior 'supercite)
-             (eq mh-yank-behavior 'autosupercite))
-         (sc-cite-original))
-        (mail-citation-hook
-         (run-hooks 'mail-citation-hook))
-        (mh-yank-hooks                  ;old hook name
-         (run-hooks 'mh-yank-hooks))
-        (t
-         (or (bolp) (forward-line 1))
-         (while (< (point) (point-max))
-           (insert mh-ins-string)
-           (forward-line 1))
-         (goto-char (point-min)))))     ;leave point like sc-cite-original
-
-;;;###mh-autoload
-(defun mh-fully-kill-draft ()
-  "Quit editing and delete draft message.
-
-If for some reason you are not happy with the draft, you can use
-this command to kill the draft buffer and delete the draft
-message. Use the command \\[kill-buffer] if you don't want to
-delete the draft message."
-  (interactive)
-  (if (y-or-n-p "Kill draft message? ")
-      (let ((config mh-previous-window-config))
-        (if (file-exists-p buffer-file-name)
-            (delete-file buffer-file-name))
-        (set-buffer-modified-p nil)
-        (kill-buffer (buffer-name))
-        (message "")
-        (if config
-            (set-window-configuration config)))
-    (error "Message not killed")))
-
-(defun mh-current-fill-prefix ()
-  "Return the `fill-prefix' on the current line as a string."
-  (save-excursion
-    (beginning-of-line)
-    ;; This assumes that the major-mode sets up adaptive-fill-regexp
-    ;; correctly such as mh-letter-mode or sendmail.el's mail-mode.  But
-    ;; perhaps I should use the variable and simply inserts its value here,
-    ;; and set it locally in a let scope.  --psg
-    (if (re-search-forward adaptive-fill-regexp nil t)
-        (match-string 0)
-      "")))
-
-;;;###mh-autoload
-(defun mh-open-line ()
-  "Insert a newline and leave point before it.
-
-This command is similar to the command \\[open-line] in that it
-inserts a newline after point. It differs in that it also inserts
-the right number of quoting characters and spaces so that the
-next line begins in the same column as it was. This is useful
-when breaking up paragraphs in replies."
-  (interactive)
-  (let ((column (current-column))
-        (prefix (mh-current-fill-prefix)))
-    (if (> (length prefix) column)
-        (message "Sorry, point seems to be within the line prefix")
-      (newline 2)
-      (insert prefix)
-      (while (> column (current-column))
-        (insert " "))
-      (forward-line -1))))
-
-(mh-do-in-xemacs (defvar mail-abbrevs))
-
-(defmacro mh-display-completion-list-compat (word choices)
-  "Completes WORD from CHOICES using `display-completion-list'.
-Calls `display-completion-list' correctly in older environments.
-Versions of Emacs prior to version 22 lacked a COMMON-SUBSTRING
-argument which is used to highlight the next possible character you
-can enter in the current list of completions."
-  (if (>= emacs-major-version 22)
-      `(display-completion-list (all-completions ,word ,choices) ,word)
-    `(display-completion-list (all-completions ,word ,choices))))
-
-;;;###mh-autoload
-(defun mh-complete-word (word choices begin end)
-  "Complete WORD at from CHOICES.
-Any match found replaces the text from BEGIN to END."
-  (let ((completion (try-completion word choices))
-        (completions-buffer "*Completions*"))
-    (cond ((eq completion t)
-           (ignore-errors
-             (kill-buffer completions-buffer))
-           (message "Completed: %s" word))
-          ((null completion)
-           (ignore-errors
-             (kill-buffer completions-buffer))
-           (message "No completion for %s" word))
-          ((stringp completion)
-           (if (equal word completion)
-               (with-output-to-temp-buffer completions-buffer
-                 (mh-display-completion-list-compat word choices))
-             (ignore-errors
-               (kill-buffer completions-buffer))
-             (delete-region begin end)
-             (insert completion))))))
-
-;;;###mh-autoload
-(defun mh-beginning-of-word (&optional n)
-  "Return position of the N th word backwards."
-  (unless n (setq n 1))
-  (let ((syntax-table (syntax-table)))
-    (unwind-protect
-        (save-excursion
-          (mh-mail-abbrev-make-syntax-table)
-          (set-syntax-table mail-abbrev-syntax-table)
-          (backward-word n)
-          (point))
-      (set-syntax-table syntax-table))))
-
-(defun mh-folder-expand-at-point ()
-  "Do folder name completion in Fcc header field."
-  (let* ((end (point))
-         (beg (mh-beginning-of-word))
-         (folder (buffer-substring beg end))
-         (leading-plus (and (> (length folder) 0) (equal (aref folder 0) ?+)))
-         (last-slash (mh-search-from-end ?/ folder))
-         (prefix (and last-slash (substring folder 0 last-slash)))
-         (choices (mapcar #'(lambda (x)
-                              (list (cond (prefix (format "%s/%s" prefix x))
-                                          (leading-plus (format "+%s" x))
-                                          (t x))))
-                          (mh-folder-completion-function folder nil t))))
-    (mh-complete-word folder choices beg end)))
-
-(defvar mh-letter-complete-function-alist
-  '((bcc . mh-alias-letter-expand-alias)
-    (cc . mh-alias-letter-expand-alias)
-    (dcc . mh-alias-letter-expand-alias)
-    (fcc . mh-folder-expand-at-point)
-    (from . mh-alias-letter-expand-alias)
-    (mail-followup-to . mh-alias-letter-expand-alias)
-    (mail-reply-to . mh-alias-letter-expand-alias)
-    (reply-to . mh-alias-letter-expand-alias)
-    (to . mh-alias-letter-expand-alias))
-  "Alist of header fields and completion functions to use.")
-
-(defun mh-letter-complete (arg)
-  "Perform completion on header field or word preceding point.
-
-If the field contains addresses (for example, \"To:\" or \"Cc:\")
-or folders (for example, \"Fcc:\") then this command will provide
-alias completion. In the body of the message, this command runs
-`mh-letter-complete-function' instead, which is set to
-`ispell-complete-word' by default. This command takes a prefix
-argument ARG that is passed to the
-`mh-letter-complete-function'."
-  (interactive "P")
-  (let ((func nil))
-    (cond ((not (mh-in-header-p))
-           (funcall mh-letter-complete-function arg))
-          ((setq func (cdr (assoc (mh-letter-header-field-at-point)
-                                  mh-letter-complete-function-alist)))
-           (funcall func))
-          (t (funcall mh-letter-complete-function arg)))))
-
-(defun mh-letter-complete-or-space (arg)
-  "Perform completion or insert space.
-
-Turn on the option `mh-compose-space-does-completion-flag' to use
-this command to perform completion in the header. Otherwise, a
-space is inserted; use a prefix argument ARG to specify more than
-one space."
-  (interactive "p")
-  (let ((func nil)
-        (end-of-prev (save-excursion
-                       (goto-char (mh-beginning-of-word))
-                       (mh-beginning-of-word -1))))
-    (cond ((not mh-compose-space-does-completion-flag)
-           (self-insert-command arg))
-          ((not (mh-in-header-p)) (self-insert-command arg))
-          ((> (point) end-of-prev) (self-insert-command arg))
-          ((setq func (cdr (assoc (mh-letter-header-field-at-point)
-                                  mh-letter-complete-function-alist)))
-           (funcall func))
-          (t (self-insert-command arg)))))
-
-(defun mh-letter-confirm-address ()
-  "Flash alias expansion.
-
-Addresses are separated by a comma\; when you press the comma,
-this command flashes the alias expansion in the minibuffer if
-`mh-alias-flash-on-comma' is turned on."
-  (interactive)
-  (cond ((not (mh-in-header-p)) (self-insert-command 1))
-        ((eq (cdr (assoc (mh-letter-header-field-at-point)
-                         mh-letter-complete-function-alist))
-             'mh-alias-letter-expand-alias)
-         (mh-alias-reload-maybe)
-         (mh-alias-minibuffer-confirm-address))
-        (t (self-insert-command 1))))
-
-(defvar mh-letter-header-field-regexp "^\\([A-Za-z][A-Za-z0-9-]*\\):")
-
-(defun mh-letter-header-field-at-point ()
-  "Return the header field name at point.
-A symbol is returned whose name is the string obtained by
-downcasing the field name."
-  (save-excursion
-    (end-of-line)
-    (and (re-search-backward mh-letter-header-field-regexp nil t)
-         (intern (downcase (match-string 1))))))
-
-;;;###mh-autoload
-(defun mh-letter-next-header-field-or-indent (arg)
-  "Cycle to next field.
-
-Within the header of the message, this command moves between
-fields that are highlighted with the face
-`mh-letter-header-field', skipping those fields listed in
-`mh-compose-skipped-header-fields'. After the last field, this
-command then moves point to the message body before cycling back
-to the first field. If point is already past the first line of
-the message body, then this command indents by calling
-`indent-relative' with the given prefix argument ARG."
-  (interactive "P")
-  (let ((header-end (save-excursion
-                      (goto-char (mh-mail-header-end))
-                      (forward-line)
-                      (point))))
-    (if (> (point) header-end)
-        (indent-relative arg)
-      (mh-letter-next-header-field))))
-
-(defun mh-letter-next-header-field ()
-  "Cycle to the next header field.
-If we are at the last header field go to the start of the message
-body."
-  (let ((header-end (mh-mail-header-end)))
-    (cond ((>= (point) header-end) (goto-char (point-min)))
-          ((< (point) (progn
-                        (beginning-of-line)
-                        (re-search-forward mh-letter-header-field-regexp
-                                           (line-end-position) t)
-                        (point)))
-           (beginning-of-line))
-          (t (end-of-line)))
-    (cond ((re-search-forward mh-letter-header-field-regexp header-end t)
-           (if (mh-letter-skipped-header-field-p (match-string 1))
-               (mh-letter-next-header-field)
-             (mh-letter-skip-leading-whitespace-in-header-field)))
-          (t (goto-char header-end)
-             (forward-line)))))
-
-;;;###mh-autoload
-(defun mh-letter-previous-header-field ()
-  "Cycle to the previous header field.
-
-This command moves backwards between the fields and cycles to the
-body of the message after the first field. Unlike the command
-\\[mh-letter-next-header-field-or-indent], it will always take
-point to the last field from anywhere in the body."
-  (interactive)
-  (let ((header-end (mh-mail-header-end)))
-    (if (>= (point) header-end)
-        (goto-char header-end)
-      (mh-header-field-beginning))
-    (cond ((re-search-backward mh-letter-header-field-regexp nil t)
-           (if (mh-letter-skipped-header-field-p (match-string 1))
-               (mh-letter-previous-header-field)
-           (goto-char (match-end 0))
-           (mh-letter-skip-leading-whitespace-in-header-field)))
-          (t (goto-char header-end)
-             (forward-line)))))
-
-(defun mh-letter-skipped-header-field-p (field)
-  "Check if FIELD is to be skipped."
-  (let ((field (downcase field)))
-    (loop for x in mh-compose-skipped-header-fields
-          when (equal (downcase x) field) return t
-          finally return nil)))
-
-(defun mh-letter-skip-leading-whitespace-in-header-field ()
-  "Skip leading whitespace in a header field.
-If the header field doesn't have at least one space after the
-colon then a space character is added."
-  (let ((need-space t))
-    (while (memq (char-after) '(?\t ?\ ))
-      (forward-char)
-      (setq need-space nil))
-    (when need-space (insert " "))))
-
-(defvar mh-hidden-header-keymap
-  (let ((map (make-sparse-keymap)))
-    (mh-do-in-gnu-emacs
-      (define-key map [mouse-2] 'mh-letter-toggle-header-field-display-button))
-    (mh-do-in-xemacs
-      (define-key map '(button2)
-        'mh-letter-toggle-header-field-display-button))
-    map))
-
-(defun mh-letter-toggle-header-field-display-button (event)
-  "Toggle header field display at location of EVENT.
-This function does the same thing as
-`mh-letter-toggle-header-field-display' except that it is
-callable from a mouse button."
-  (interactive "e")
-  (mh-do-at-event-location event
-    (mh-letter-toggle-header-field-display nil)))
-
-(defun mh-letter-toggle-header-field-display (arg)
-  "Toggle display of header field at point.
-
-Use this command to display truncated header fields. This command
-is a toggle so entering it again will hide the field. This
-command takes a prefix argument ARG: if negative then the field
-is hidden, if positive then the field is displayed."
-  (interactive (list nil))
-  (when (and (mh-in-header-p)
-             (progn
-               (end-of-line)
-               (re-search-backward mh-letter-header-field-regexp nil t)))
-    (let ((buffer-read-only nil)
-          (modified-flag (buffer-modified-p))
-          (begin (point))
-          end)
-      (end-of-line)
-      (setq end (1- (if (re-search-forward "^[^ \t]" nil t)
-                        (match-beginning 0)
-                      (point-max))))
-      (goto-char begin)
-      ;; Make it clickable...
-      (add-text-properties begin end `(keymap ,mh-hidden-header-keymap
-                                       mouse-face highlight))
-      (unwind-protect
-          (cond ((or (and (not arg)
-                          (text-property-any begin end 'invisible 'vanish))
-                     (and (numberp arg) (>= arg 0))
-                     (and (eq arg 'long) (> (line-beginning-position 5) end)))
-                 (remove-text-properties begin end '(invisible nil))
-                 (search-forward ":" (line-end-position) t)
-                 (mh-letter-skip-leading-whitespace-in-header-field))
-                ;; XXX Redesign to make usable by user. Perhaps use a positive
-                ;; numeric prefix to make that many lines visible.
-                ((eq arg 'long)
-                 (end-of-line 4)
-                 (mh-letter-truncate-header-field end)
-                 (beginning-of-line))
-                (t (end-of-line)
-                   (mh-letter-truncate-header-field end)
-                   (beginning-of-line)))
-        (set-buffer-modified-p modified-flag)))))
-
-(defun mh-letter-truncate-header-field (end)
-  "Replace text from current line till END with an ellipsis.
-If the current line is too long truncate a part of it as well."
-  (let ((max-len (min (window-width) 62)))
-    (when (> (+ (current-column) 4) max-len)
-      (backward-char (- (+ (current-column) 5) max-len)))
-    (when (> end (point))
-      (add-text-properties (point) end '(invisible vanish)))))
-
-(defun mh-letter-hide-all-skipped-fields ()
-  "Hide all skipped fields."
-  (save-excursion
-    (goto-char (point-min))
-    (save-restriction
-      (narrow-to-region (point) (mh-mail-header-end))
-      (while (re-search-forward mh-letter-header-field-regexp nil t)
-        (if (mh-letter-skipped-header-field-p (match-string 1))
-            (mh-letter-toggle-header-field-display -1)
-          (mh-letter-toggle-header-field-display 'long))
-        (beginning-of-line 2)))))
-
-(defun mh-interactive-read-address (prompt)
-  "Read an address.
-If `mh-compose-prompt-flag' is non-nil, then read an address with
-PROMPT.
-Otherwise return the empty string."
-  (if mh-compose-prompt-flag (mh-read-address prompt) ""))
-
-(defun mh-interactive-read-string (prompt)
-  "Read a string.
-If `mh-compose-prompt-flag' is non-nil, then read a string with
-PROMPT.
-Otherwise return the empty string."
-  (if mh-compose-prompt-flag (read-string prompt) ""))
-
-(defun mh-letter-adjust-point ()
-  "Move cursor to first header field if are using the no prompt mode."
-  (unless mh-compose-prompt-flag
-    (goto-char (point-max))
-    (mh-letter-next-header-field)))
-
-
-
-;;; Build mh-letter-mode keymap
-
-;; If this changes, modify mh-letter-mode-help-messages accordingly, above.
-(gnus-define-keys  mh-letter-mode-map
-  " "                   mh-letter-complete-or-space
-  ","                   mh-letter-confirm-address
-  "\C-c?"               mh-help
-  "\C-c\C-\\"           mh-fully-kill-draft ;if no C-q
-  "\C-c\C-^"            mh-insert-signature ;if no C-s
-  "\C-c\C-c"            mh-send-letter
-  "\C-c\C-d"            mh-insert-identity
-  "\C-c\C-e"            mh-mh-to-mime
-  "\C-c\C-f\C-a"        mh-to-field
-  "\C-c\C-f\C-b"        mh-to-field
-  "\C-c\C-f\C-c"        mh-to-field
-  "\C-c\C-f\C-d"        mh-to-field
-  "\C-c\C-f\C-f"        mh-to-fcc
-  "\C-c\C-f\C-l"        mh-to-field
-  "\C-c\C-f\C-m"        mh-to-field
-  "\C-c\C-f\C-r"        mh-to-field
-  "\C-c\C-f\C-s"        mh-to-field
-  "\C-c\C-f\C-t"        mh-to-field
-  "\C-c\C-fa"           mh-to-field
-  "\C-c\C-fb"           mh-to-field
-  "\C-c\C-fc"           mh-to-field
-  "\C-c\C-fd"           mh-to-field
-  "\C-c\C-ff"           mh-to-fcc
-  "\C-c\C-fl"           mh-to-field
-  "\C-c\C-fm"           mh-to-field
-  "\C-c\C-fr"           mh-to-field
-  "\C-c\C-fs"           mh-to-field
-  "\C-c\C-ft"           mh-to-field
-  "\C-c\C-i"            mh-insert-letter
-  "\C-c\C-m\C-e"        mh-mml-secure-message-encrypt
-  "\C-c\C-m\C-f"        mh-compose-forward
-  "\C-c\C-m\C-g"        mh-mh-compose-anon-ftp
-  "\C-c\C-m\C-i"        mh-compose-insertion
-  "\C-c\C-m\C-m"        mh-mml-to-mime
-  "\C-c\C-m\C-n"        mh-mml-unsecure-message
-  "\C-c\C-m\C-s"        mh-mml-secure-message-sign
-  "\C-c\C-m\C-t"        mh-mh-compose-external-compressed-tar
-  "\C-c\C-m\C-u"        mh-mh-to-mime-undo
-  "\C-c\C-m\C-x"        mh-mh-compose-external-type
-  "\C-c\C-mee"          mh-mml-secure-message-encrypt
-  "\C-c\C-mes"          mh-mml-secure-message-signencrypt
-  "\C-c\C-mf"           mh-compose-forward
-  "\C-c\C-mg"           mh-mh-compose-anon-ftp
-  "\C-c\C-mi"           mh-compose-insertion
-  "\C-c\C-mm"           mh-mml-to-mime
-  "\C-c\C-mn"           mh-mml-unsecure-message
-  "\C-c\C-mse"          mh-mml-secure-message-signencrypt
-  "\C-c\C-mss"          mh-mml-secure-message-sign
-  "\C-c\C-mt"           mh-mh-compose-external-compressed-tar
-  "\C-c\C-mu"           mh-mh-to-mime-undo
-  "\C-c\C-mx"           mh-mh-compose-external-type
-  "\C-c\C-o"            mh-open-line
-  "\C-c\C-q"            mh-fully-kill-draft
-  "\C-c\C-s"            mh-insert-signature
-  "\C-c\C-t"            mh-letter-toggle-header-field-display
-  "\C-c\C-w"            mh-check-whom
-  "\C-c\C-y"            mh-yank-cur-msg
-  "\C-c\M-d"            mh-insert-auto-fields
-  "\M-\t"               mh-letter-complete
-  "\t"                  mh-letter-next-header-field-or-indent
-  [backtab]             mh-letter-previous-header-field)
-
-;; "C-c /" prefix is used in mh-letter-mode by pgp.el and mailcrypt.el.
-
 (provide 'mh-comp)
 
 ;; Local Variables:
Index: emacs/lisp/mh-e/mh-e.el
diff -u emacs/lisp/mh-e/mh-e.el:1.57 emacs/lisp/mh-e/mh-e.el:1.58
--- emacs/lisp/mh-e/mh-e.el:1.57        Mon Jan 16 20:05:14 2006
+++ emacs/lisp/mh-e/mh-e.el     Sun Jan 29 19:34:56 2006
@@ -28,16 +28,22 @@
 
 ;;; Commentary:
 
-;; How to Use:
+;; 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.
+;;   M-x mh-smail to send mail.  From within the mail reader, "s" works, too.
 
 ;; Your .emacs might benefit from these bindings:
 ;;   (global-set-key "\C-cr" 'mh-rmail)
 ;;   (global-set-key "\C-xm" 'mh-smail)
 ;;   (global-set-key "\C-x4m" 'mh-smail-other-window)
 
+;; If Emacs can't find mh-rmail or mh-smail, add the following to ~/.emacs:
+;;   (require 'mh-autoloads)
+
+;; If you want to customize MH-E before explicitly loading it, add this:
+;;   (require 'mh-cus-load)
+
 ;; MH (Message Handler) is a powerful mail reader.
 
 ;; The MH newsgroup is comp.mail.mh; the mailing list is address@hidden
@@ -59,17 +65,18 @@
 ;;   address@hidden
 ;;   address@hidden
 ;;   address@hidden
-;;
+
 ;;   Subscribe by sending a "subscribe" message to
 ;;   <list>address@hidden, or by using the web interface at
 ;;   https://sourceforge.net/mail/?group_id=13357
 
 ;; Bug Reports:
 ;;   https://sourceforge.net/tracker/?group_id=13357&atid=113357
-;;   Include the output of M-x mh-version in any bug report.
+;;   Include the output of M-x mh-version in the bug report unless
+;;   you're 110% sure we won't ask for it.
 
 ;; Feature Requests:
-;;   https://sourceforge.net/tracker/?atid=363357&group_id=13357&func=browse
+;;   https://sourceforge.net/tracker/?group_id=13357&atid=363357
 
 ;; Support:
 ;;   https://sourceforge.net/tracker/?group_id=13357&atid=213357
@@ -85,1236 +92,283 @@
 
 ;;; Code:
 
-;;(message "> mh-e")
-(provide 'mh-e)
+;; Provide functions to the rest of MH-E. However, mh-e.el must not
+;; use any definitions in files that require mh-e from mh-loaddefs,
+;; for if it does it will introduce a require loop.
+(require 'mh-loaddefs)
 
-(eval-when-compile (require 'mh-acros))
 (mh-require-cl)
 
-(require 'easymenu)
-(require 'gnus-util)
+(eval-and-compile
+  (defvar mh-xemacs-flag (featurep 'xemacs)
+    "Non-nil means the current Emacs is XEmacs."))
+(mh-do-in-xemacs
+  (require 'mh-xemacs))
+
 (require 'mh-buffers)
-(require 'mh-seq)
-(require 'mh-utils)
-;;(message "< mh-e")
-
-(defconst mh-version "7.85+cvs" "Version number of MH-E.")
-
-(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.")
-
-
-
-;;; 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' 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 column of the notations, use the `mh-set-cmd-note'
-;; function.
-
-(defvar mh-scan-format-mh
-  (concat
-   "%4(msg)"
-   "%<(cur)+%| %>"
-   "%<{replied}-"
-   "%?(nonnull(comp{to}))%<(mymbox{to})t%>"
-   "%?(nonnull(comp{cc}))%<(mymbox{cc})c%>"
-   "%?(nonnull(comp{bcc}))%<(mymbox{bcc})b%>"
-   "%?(nonnull(comp{newsgroups}))n%>"
-   "%<(zero) %>"
-   "%02(mon{date})/%02(mday{date})%<{date} %|*%>"
-   "%<(mymbox{from})%<{to}To:%14(friendly{to})%>%>"
-   "%<(zero)%17(friendly{from})%>  "
-   "%{subject}%<{body}<<%{body}%>")
-  "*Scan format string for MH.
-This string is passed to the scan program via the -format
-argument. 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.")
-
-(defvar mh-scan-format-nmh
-  (concat
-   "%4(msg)"
-   "%<(cur)+%| %>"
-   "%<{replied}-"
-   "%?(nonnull(comp{to}))%<(mymbox{to})t%>"
-   "%?(nonnull(comp{cc}))%<(mymbox{cc})c%>"
-   "%?(nonnull(comp{bcc}))%<(mymbox{bcc})b%>"
-   "%?(nonnull(comp{newsgroups}))n%>"
-   "%<(zero) %>"
-   "%02(mon{date})/%02(mday{date})%<{date} %|*%>"
-   "%<(mymbox{from})%<{to}To:%14(decode(friendly{to}))%>%>"
-   "%<(zero)%17(decode(friendly{from}))%>  "
-   "%(decode{subject})%<{body}<<%{body}%>")
-  "*Scan format string for nmh.
-This string is passed to the scan program via the -format arg.
-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: 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
-  "Messages that have been deleted are marked by this character.
-See also `mh-scan-deleted-msg-regexp'.")
-
-(defvar mh-note-refiled ?^
-  "Messages that have been refiled are marked by this character.
-See also `mh-scan-refiled-msg-regexp'.")
-
-(defvar mh-note-cur ?+
-  "The current message (in MH, not in MH-E) is marked by this character.
-See also `mh-scan-cur-msg-number-regexp'.")
-
-(defvar mh-scan-good-msg-regexp  "^\\( *[0-9]+\\)[^D^0-9]"
-  "This regular expression matches \"good\" messages.
-
-It must match from the beginning of the line. 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]\".
-
-This expression includes the leading space within the parenthesis
-since it looks better to highlight it as well. The highlighting
-is done with the face `mh-folder-msg-number'. This regular
-expression should be correct as it is needed by non-fontification
-functions.")
-
-(defvar mh-scan-deleted-msg-regexp "^\\( *[0-9]+\\)D"
-  "This regular expression matches deleted messages.
-
-It must match from the beginning of the line. 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\".
-
-This expression includes the leading space within the parenthesis
-since it looks better to highlight it as well. The highlighting
-is done with the face `mh-folder-deleted'. This regular
-expression should be correct as it is needed by non-fontification
-functions. See also `mh-note-deleted'.")
-
-(defvar mh-scan-refiled-msg-regexp  "^\\( *[0-9]+\\)\\^"
-  "This regular expression matches refiled messages.
-
-It must match from the beginning of the line. 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]+\\\\)\\\\^\".
-
-This expression includes the leading space within the parenthesis
-since it looks better to highlight it as well. The highlighting
-is done with the face `mh-folder-refiled'. This regular
-expression should be correct as it is needed by non-fontification
-functions. See also `mh-note-refiled'.")
-
-(defvar mh-scan-valid-regexp "^ *[0-9]"
-  "This regular expression describes a valid scan line.
-
-This is used to eliminate error messages that are occasionally
-produced by \"inc\".")
-
-(defvar mh-scan-cur-msg-number-regexp "^\\( *[0-9]+\\+\\).*"
-  "This regular expression matches the current message.
-
-It must match from the beginning of the line. 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]+\\\\+\\\\).*\".
-
-This expression includes the leading space and current message
-marker \"+\" within the parenthesis since it looks better to
-highlight these items as well. The highlighting is done with the
-face `mh-folder-cur-msg-number'. This regular expression should
-be correct as it is needed by non-fontification functions. See
-also `mh-note-cur'.")
-
-(defvar mh-scan-date-regexp "\\([0-9][0-9]/[0-9][0-9]\\)"
-  "This regular expression matches a valid date.
-
-It must not be anchored to the beginning or the end of the line.
-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]\\\\)\"}. If this regular expression
-is not correct, the date will not be highlighted with the face
-`mh-folder-date'.")
-
-(defvar mh-scan-rcpt-regexp  "\\(To:\\)\\(..............\\)"
-  "This regular expression 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:\\\\)\\\\(..............\\\\)\". If this regular
-expression is not correct, the \"To:\" string will not be
-highlighted with the face `mh-folder-to' and the recipient will
-not be highlighted with the face `mh-folder-address'")
-
-(defvar mh-scan-body-regexp "\\(<<\\([^\n]+\\)?\\)"
-  "This regular expression matches the message body fragment.
-
-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]+\\\\)?\\\\)\". If this regular expression is
-not correct, the body fragment will not be highlighted with the
-face `mh-folder-body'.")
-
-(defvar mh-scan-subject-regexp
-  "^ *[0-9]+........[ 
]*...................\\([Rr][Ee]\\(\\[[0-9]+\\]\\)?:\\s-*\\)*\\([^<\n]*\\)"
-  "This regular expression matches the subject.
-
-It must match from the beginning of the line. 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, and is
-highlighted with the face `mh-folder-followup'. 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 which
-is highlighted with the face `mh-folder-subject'. For example,
-the default (broken on multiple lines for readability) is
-
-  ^ *[0-9]+........[ ]*...................
-  \\\\([Rr][Ee]\\\\(\\\\\\=[[0-9]+\\\\]\\\\)?:\\\\s-*\\\\)*
-  \\\\([^<\\n]*\\\\)
-
-This regular expression should be correct as it is needed by
-non-fontification functions.")
-
-(defvar mh-scan-sent-to-me-sender-regexp
-  "^ *[0-9]+.\\([bct]\\).....[ ]*\\(..................\\)"
-  "This regular expression matches messages sent to us.
-
-Note that the default setting of `mh-folder-font-lock-keywords'
-expects this expression to contain at least two parenthesized
-expressions. The first should match the fontification hint (see
-`mh-scan-format-nmh') and the second should match the user name
-as in the default of
-
-  ^ *[0-9]+.\\\\([bct]\\\\).....[ ]*\\\\(..................\\\\)
-
-If this regular expression is not correct, the notation hints
-will not be highlighted with the face
-`mh-mh-folder-sent-to-me-hint' and the sender will not be
-highlighted with the face `mh-folder-sent-to-me-sender'.")
-
-
-
-(defvar mh-folder-font-lock-keywords
-  (list
-   ;; Folders when displaying index buffer
-   (list "^\\+.*"
-         '(0 'mh-search-folder))
-   ;; Marked for deletion
-   (list (concat mh-scan-deleted-msg-regexp ".*")
-         '(0 'mh-folder-deleted))
-   ;; Marked for refile
-   (list (concat mh-scan-refiled-msg-regexp ".*")
-         '(0 'mh-folder-refiled))
-   ;; After subject
-   (list mh-scan-body-regexp
-         '(1 'mh-folder-body nil t))
-   ;; Subject
-   '(mh-folder-font-lock-subject
-     (1 'mh-folder-followup append t)
-     (2 'mh-folder-subject append t))
-   ;; Current message number
-   (list mh-scan-cur-msg-number-regexp
-         '(1 'mh-folder-cur-msg-number))
-   ;; Message number
-   (list mh-scan-good-msg-regexp
-         '(1 'mh-folder-msg-number))
-   ;; Date
-   (list mh-scan-date-regexp
-         '(1 'mh-folder-date))
-   ;; Messages from me (To:)
-   (list mh-scan-rcpt-regexp
-         '(1 'mh-folder-to)
-         '(2 'mh-folder-address))
-   ;; Messages to me
-   (list mh-scan-sent-to-me-sender-regexp
-         '(1 'mh-folder-sent-to-me-hint)
-         '(2 'mh-folder-sent-to-me-sender)))
-  "Keywords (regular expressions) used to fontify the MH-Folder buffer.")
-
-(defvar mh-scan-cmd-note-width 1
-  "Number of columns consumed by the cmd-note field in `mh-scan-format'.
-
-This column will have one of the values: \" \", \"D\", \"^\", \"+\" and
-where \" \" is the default value,
-
-  \"D\" is the `mh-note-deleted' character,
-  \"^\" is the `mh-note-refiled' character, and
-  \"+\" is the `mh-note-cur' character.")
-
-(defvar mh-scan-destination-width 1
-  "Number of columns consumed by the destination field in `mh-scan-format'.
-
-This column will have one of \" \", \"%\", \"-\", \"t\", \"c\", \"b\", or \"n\"
-in it.
-
-  \" \" blank space is the default character.
-  \"%\" indicates that the message in in a named MH sequence.
-  \"-\" indicates that the message has been annotated with a replied field.
-  \"t\" indicates that the message contains mymbox in the To: field.
-  \"c\" indicates that the message contains mymbox in the Cc: field.
-  \"b\" indicates that the message contains mymbox in the Bcc: field.
-  \"n\" indicates that the message contains a Newsgroups: field.")
-
-(defvar mh-scan-date-width 5
-  "Number of columns consumed by the date field in `mh-scan-format'.
-This column will typically be of the form mm/dd.")
-
-(defvar mh-scan-date-flag-width 1
-  "Number of columns consumed to flag (in)valid dates in `mh-scan-format'.
-This column will have \" \" for valid and \"*\" for invalid or
-missing dates.")
-
-(defvar mh-scan-from-mbox-width 17
-  "Number of columns consumed with the \"From:\" line in `mh-scan-format'.
-This column will have a friendly name or e-mail address of the
-originator, or a \"To: address\" for outgoing e-mail messages.")
-
-(defvar mh-scan-from-mbox-sep-width 2
-  "Number of columns consumed by whitespace after from-mbox in 
`mh-scan-format'.
-This column will only ever have spaces in it.")
-
-(defvar mh-scan-field-destination-offset
-  (+ mh-scan-cmd-note-width)
-  "The offset from the `mh-cmd-note' for the destination column.")
-
-(defvar mh-scan-field-from-start-offset
-  (+ mh-scan-cmd-note-width
-     mh-scan-destination-width
-     mh-scan-date-width
-     mh-scan-date-flag-width)
-  "The offset from the `mh-cmd-note' to find the start of \"From:\" address.")
-
-(defvar mh-scan-field-from-end-offset
-  (+ mh-scan-field-from-start-offset mh-scan-from-mbox-width)
-  "The offset from the `mh-cmd-note' to find the end of \"From:\" address.")
-
-(defvar mh-scan-field-subject-start-offset
-  (+ mh-scan-cmd-note-width
-     mh-scan-destination-width
-     mh-scan-date-width
-     mh-scan-date-flag-width
-     mh-scan-from-mbox-width
-     mh-scan-from-mbox-sep-width)
-  "The offset from the `mh-cmd-note' to find the start of the subject.")
-
-(defun mh-folder-font-lock-subject (limit)
-  "Return MH-E scan subject strings to font-lock between point and LIMIT."
-  (if (not (re-search-forward mh-scan-subject-regexp limit t))
-      nil
-    (if (match-beginning 1)
-        (set-match-data (list (match-beginning 1) (match-end 3)
-                              (match-beginning 1) (match-end 3) nil nil))
-      (set-match-data (list (match-beginning 3) (match-end 3)
-                            nil nil (match-beginning 3) (match-end 3))))
-    t))
-
-
-
-;; Fontifify unseen mesages in bold.
-
-(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 ',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)
-
-
-
-;;; Internal variables:
+(require 'mh-compat)
+
+
+
+;;; Global Variables
+
+;; Try to keep variables local to a single file. Provide accessors if
+;; variables are shared. Use this section as a last resort.
+
+(defconst mh-version "7.85+sans-entropy" "Version number of MH-E.")
+
+;; Variants
+
+(defvar mh-sys-path
+  '("/usr/local/nmh/bin"                ; nmh default
+    "/usr/local/bin/mh/"
+    "/usr/local/mh/"
+    "/usr/bin/mh/"                      ; Ultrix 4.2, Linux
+    "/usr/new/mh/"                      ; Ultrix < 4.2
+    "/usr/contrib/mh/bin/"              ; BSDI
+    "/usr/pkg/bin/"                     ; NetBSD
+    "/usr/local/bin/"
+    "/usr/local/bin/mu-mh/"             ; GNU mailutils - default
+    "/usr/bin/mu-mh/")                  ; GNU mailutils - packaged
+  "List of directories to search for variants of the MH variant.
+The list `exec-path' is searched in addition to this list.
+There's no need for users to modify this list. Instead add extra
+directories to the customizable variable `mh-path'.")
+
+(defvar mh-variants nil
+  "List describing known MH variants.
+Do not access this variable directly as it may not have yet been initialized.
+Use the function `mh-variants' instead.")
+
+(defvar mh-variant-in-use nil
+  "The MH variant currently in use; a string with variant and version number.
+This differs from `mh-variant' when the latter is set to
+\"autodetect\".")
+
+(defvar mh-progs nil
+  "Directory containing MH commands, such as inc, repl, and rmm.")
+
+;;;###autoload
+(put 'mh-progs 'risky-local-variable t)
+
+(defvar mh-lib nil
+  "Directory containing the MH library.
+This directory contains, among other things, the components file.")
 
-(defvar mh-last-destination nil
-  "Destination of last refile or write command.")
+;;;###autoload
+(put 'mh-lib 'risky-local-variable t)
+
+(defvar mh-lib-progs nil
+  "Directory containing MH helper programs.
+This directory contains, among other things, the mhl program.")
+
+;;;###autoload
+(put 'mh-lib-progs 'risky-local-variable t)
 
-(defvar mh-last-destination-folder nil
-  "Destination of last refile command.")
+;; Profile Components
 
-(defvar mh-last-destination-write nil
-  "Destination of last write command.")
+(defvar mh-draft-folder nil
+  "Cached value of the \"Draft-Folder:\" MH profile component.
+Name of folder containing draft messages.
+Nil means do not use a draft folder.")
+
+(defvar mh-inbox nil
+  "Cached value of the \"Inbox:\" MH profile component.
+Set to \"+inbox\" if no such component.
+Name of the Inbox folder.")
+
+(defvar mh-user-path nil
+  "Cached value of the \"Path:\" MH profile component.
+User's mail folder directory.")
+
+;; Maps declared here so that they can be used in docstrings.
 
 (defvar mh-folder-mode-map (make-keymap)
-  "Keymap for MH folders.")
+  "Keymap for MH-Folder mode.")
+
+(defvar mh-folder-seq-tool-bar-map nil
+  "Keymap for MH-Folder tool bar.")
+
+(defvar mh-folder-tool-bar-map nil
+  "Keymap for MH-Folder tool bar.")
+
+(defvar mh-inc-spool-map (make-sparse-keymap)
+  "Keymap for MH-E's mh-inc-spool commands.")
+
+(defvar mh-letter-mode-map (copy-keymap text-mode-map)
+  "Keymap for MH-Letter mode.")
+
+(defvar mh-letter-tool-bar-map nil
+  "Keymap for MH-Letter tool bar.")
+
+(defvar mh-search-mode-map (make-sparse-keymap)
+  "Keymap for MH-Search mode.")
+
+(defvar mh-show-mode-map (make-sparse-keymap)
+  "Keymap MH-Show mode.")
+
+(defvar mh-show-seq-tool-bar-map nil
+  "Keymap for MH-Show tool bar.")
+
+(defvar mh-show-tool-bar-map nil
+  "Keymap for MH-Show tool bar.")
+
+;; MH-Folder Locals (alphabetical)
 
 (defvar mh-arrow-marker nil
   "Marker for arrow display in fringe.")
 
+(defvar mh-colors-available-flag nil
+  "Non-nil means colors are available.")
+
+(defvar mh-current-folder nil
+  "Name of current folder, a string.")
+
 (defvar mh-delete-list nil
   "List of message numbers to delete.
 This variable can be used by
 `mh-before-commands-processed-hook'.")
 
-(defvar mh-refile-list nil
-  "List of folder names in `mh-seq-list'.
-This variable can be used by
-`mh-before-commands-processed-hook'.")
-
-(defvar mh-folders-changed nil
-  "Lists which folders were affected by deletes and refiles.
-This list will always include the current folder
-`mh-current-folder'. This variable can be used by
-`mh-after-commands-processed-hook'.")
-
-(defvar mh-next-direction 'forward
-  "Direction to move to next message.")
-
-(defvar mh-view-ops ()
-  "Stack of operations that change the folder view.
-These operations include narrowing or threading.")
-
-(defvar mh-folder-view-stack ()
+(defvar mh-folder-view-stack nil
   "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 message in buffer.")
+(defvar mh-index-checksum-origin-map nil)
 
-(defvar mh-last-msg-num nil
-  "Number of last msg in buffer.")
+(defvar mh-index-sequence-search-flag nil)
 
 (defvar mh-mode-line-annotation nil
   "Message range displayed in buffer.")
 
-(defvar mh-sequence-notation-history nil
-  "Remember original notation that is overwritten by `mh-note-seq'.")
-
-(defvar mh-colors-available-flag nil
-  "Non-nil means colors are available.")
-
-
-
-;;; Macros and generic functions:
-
-(defun mh-mapc (function list)
-  "Apply FUNCTION to each element of LIST for side effects only."
-  (while list
-    (funcall function (car list))
-    (setq list (cdr list))))
-
-(defun mh-scan-format ()
-  "Return the output format argument for the scan program."
-  (if (equal mh-scan-format-file t)
-      (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 "-form" mh-scan-format-file))))
-
-
-
-;;; Entry points:
-
-;;;###autoload
-(defun mh-rmail (&optional arg)
-  "Incorporate new mail with MH.
-Scan an MH folder if ARG is non-nil.
+(defvar mh-next-direction 'forward
+  "Direction to move to next message.")
 
-This function is an entry point to MH-E, the Emacs interface to
-the MH mail system."
-  (interactive "P")
-  (mh-find-path)
-  (if arg
-      (call-interactively 'mh-visit-folder)
-    (unless (get-buffer mh-inbox)
-      (mh-visit-folder mh-inbox (symbol-name mh-unseen-seq)))
-    (mh-inc-folder)))
+(defvar mh-previous-window-config nil
+  "Window configuration before MH-E command.")
 
-;;;###autoload
-(defun mh-nmail (&optional arg)
-  "Check for new mail in inbox folder.
-Scan an MH folder if ARG is non-nil.
+(defvar mh-refile-list nil
+  "List of folder names in `mh-seq-list'.
+This variable can be used by
+`mh-before-commands-processed-hook'.")
 
-This function is an entry point to MH-E, the Emacs interface to
-the MH mail system."
-  (interactive "P")
-  (mh-find-path)                        ; init mh-inbox
-  (if arg
-      (call-interactively 'mh-visit-folder)
-    (mh-visit-folder mh-inbox)))
+(defvar mh-seen-list nil
+  "List of displayed messages to be removed from the \"Unseen\" sequence.")
 
-
+(defvar mh-seq-list nil
+  "Alist of this folder's sequences.
+Elements have the form (SEQUENCE . MESSAGES).")
 
-;;; User executable MH-E commands:
-
-(defun mh-delete-msg (range)
-  "Delete RANGE\\<mh-folder-mode-map>.
-
-To mark a message for deletion, use this command. A \"D\" is
-placed by the message in the scan window, and the next undeleted
-message is displayed. If the previous command had been
-\\[mh-previous-undeleted-msg], then the next message displayed is
-the first undeleted message previous to the message just deleted.
-Use \\[mh-next-undeleted-msg] to force subsequent
-\\[mh-delete-msg] commands to move forward to the next undeleted
-message after deleting the message under the cursor.
-
-The hook `mh-delete-msg-hook' is called after you mark a message
-for deletion. For example, a past maintainer of MH-E used this
-once when he kept statistics on his mail usage.
-
-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)
-  "Delete RANGE, don't move to next message.
-
-This command marks the RANGE for deletion but leaves the cursor
-at the current message in case you wish to perform other
-operations on the message.
-
-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\\<mh-folder-mode-map>.
-
-If you've marked messages to be deleted or refiled and you want
-to go ahead and delete or refile the messages, use this command.
-Many MH-E commands that may affect the numbering of the
-messages (such as \\[mh-rescan-folder] or \\[mh-pack-folder])
-will ask if you want to process refiles or deletes first and then
-either run this command for you or undo the pending refiles and
-deletes, which are lost.
-
-This function runs `mh-before-commands-processed-hook' before the
-commands are processed and `mh-after-commands-processed-hook'
-after the commands are processed."
-  (interactive)
-  (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
-  (mh-make-folder-mode-line)
-  t)                                    ; return t for write-file-functions
+(defvar mh-sequence-notation-history nil
+  "Remember original notation that is overwritten by `mh-note-seq'.")
 
-(defun mh-first-msg ()
-  "Display first message."
-  (interactive)
-  (goto-char (point-min))
-  (while (and (not (eobp)) (not (looking-at mh-scan-valid-regexp)))
-    (forward-line 1)))
+(defvar mh-show-buffer nil
+  "Buffer that displays message for this folder.")
 
-(defun mh-header-display ()
-  "Display message with all header fields\\<mh-folder-mode-map>.
+(defvar mh-showing-mode nil
+  "If non-nil, show the message in a separate window.")
 
-Use the command \\[mh-show] to show the message normally again."
-  (interactive)
-  (and (not mh-showing-with-headers)
-       (or mh-mhl-format-file mh-clean-message-header-flag)
-       (mh-invalidate-show-buffer))
-  (let ((mh-decode-mime-flag nil)
-        (mh-mhl-format-file nil)
-        (mh-clean-message-header-flag nil))
-    (mh-show-msg nil)
-    (mh-in-show-buffer (mh-show-buffer)
-      (goto-char (point-min))
-      (mh-recenter 0))
-    (setq mh-showing-with-headers t)))
+(defvar mh-view-ops nil
+  "Stack of operations that change the folder view.
+These operations include narrowing or threading.")
 
-(defun mh-inc-folder (&optional file folder)
-  "Incorporate new mail into a folder.
+;; MH-Show Locals (alphabetical)
 
-You can incorporate mail from any file into the current folder by
-specifying a prefix argument; you'll be prompted for the name of
-the FILE to use as well as the destination FOLDER
-
-The hook `mh-inc-folder-hook' is run after incorporating new
-mail.
-
-Do not call this function from outside MH-E; use \\[mh-rmail]
-instead."
-  (interactive (list (if current-prefix-arg
-                         (expand-file-name
-                          (read-file-name "inc mail from file: "
-                                          mh-user-path)))
-                     (if current-prefix-arg
-                         (mh-prompt-for-folder "inc mail into" mh-inbox t))))
-  (if (not folder)
-      (setq folder mh-inbox))
-  (let ((threading-needed-flag nil))
-    (let ((config (current-window-configuration)))
-      (when (and mh-show-buffer (get-buffer mh-show-buffer))
-        (delete-windows-on mh-show-buffer))
-      (cond ((not (get-buffer folder))
-             (mh-make-folder folder)
-             (setq threading-needed-flag mh-show-threads-flag)
-             (setq mh-previous-window-config config))
-            ((not (eq (current-buffer) (get-buffer folder)))
-             (switch-to-buffer folder)
-             (setq mh-previous-window-config config))))
-    (mh-get-new-mail file)
-    (when (and threading-needed-flag
-               (save-excursion
-                 (goto-char (point-min))
-                 (or (null mh-large-folder)
-                     (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))
-    (beginning-of-line)
-    (if (and mh-showing-mode (looking-at mh-scan-valid-regexp)) (mh-show))
-    (run-hooks 'mh-inc-folder-hook)))
+(defvar mh-globals-hash (make-hash-table)
+  "Keeps track of MIME data on a per buffer basis.")
 
-(defun mh-last-msg ()
-  "Display last message."
-  (interactive)
-  (goto-char (point-max))
-  (while (and (not (bobp)) (not (looking-at mh-scan-valid-regexp)))
-    (forward-line -1))
-  (mh-recenter nil))
-
-(defun mh-next-undeleted-msg (&optional count wait-after-complaining-flag)
-  "Display next message.
-
-This command can be given a prefix argument COUNT to specify how
-many unread messages to skip.
-
-In a program, pause for a second after printing message if we are
-at the last undeleted message and optional argument
-WAIT-AFTER-COMPLAINING-FLAG is non-nil."
-  (interactive "p")
-  (setq mh-next-direction 'forward)
-  (forward-line 1)
-  (cond ((re-search-forward mh-scan-good-msg-regexp nil t count)
-         (beginning-of-line)
-         (mh-maybe-show))
-        (t (forward-line -1)
-           (message "No more undeleted messages")
-           (if wait-after-complaining-flag (sit-for 1)))))
-
-(defun mh-folder-from-address ()
-  "Derive folder name from sender.
-
-The name of the folder is derived as follows:
-
-  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.
-
-  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-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
-      (when (and folder-name (not (eq (aref folder-name 0) ?+)))
-        (setq folder-name (concat "+" folder-name)))
-
-      ;; If not, is there an alias for the address?
-      (when (not folder-name)
-        (let* ((from-header (mh-extract-from-header-value))
-               (address (and from-header
-                             (nth 1 (mail-extract-address-components
-                                     from-header))))
-               (alias (and address (mh-alias-address-to-alias address))))
-          (when alias
-            (setq folder-name
-                  (and alias (concat "+" mh-default-folder-prefix alias))))))
-
-      ;; If mh-default-folder-must-exist-flag set, check that folder exists.
-      (if (and folder-name
-               (or (not mh-default-folder-must-exist-flag)
-                   (file-exists-p (mh-expand-file-name folder-name))))
-          folder-name))))
-
-(defun mh-prompt-for-refile-folder ()
-  "Prompt the user for a folder in which the message should be filed.
-The folder is returned as a string.
-
-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 (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 (range folder &optional dont-update-last-destination-flag)
-  "Refile (output) RANGE into FOLDER.
-
-You are prompted for the folder name. Note that this command can also
-be used to create folders. If you specify a folder that does not
-exist, you will be prompted to create it.
-
-The hook `mh-refile-msg-hook' is called after a message is marked to
-be refiled.
-
-Check the documentation of `mh-interactive-range' to see how RANGE is
-read in interactive use.
-
-In a program, the variables `mh-last-destination' and
-`mh-last-destination-folder' are not updated if
-DONT-UPDATE-LAST-DESTINATION-FLAG is non-nil."
-  (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-range () range
-    (mh-refile-a-msg nil folder))
-  (when (looking-at mh-scan-refiled-msg-regexp) (mh-next-msg)))
-
-(defun mh-refile-or-write-again (range &optional interactive-flag)
-  "Repeat last output command.
-
-If you are refiling several messages into the same folder, you
-can use this command to repeat the last
-refile (\\[mh-refile-msg]) or write (\\[mh-write-msg-to-file]).
-You can use a range.
-
-Check the documentation of `mh-interactive-range' to see how RANGE is
-read in interactive use.
-
-In a program, a non-nil INTERACTIVE-FLAG means that the function was
-called interactively."
-  (interactive (list (mh-interactive-range "Redo") t))
-  (if (null mh-last-destination)
-      (error "No previous refile or write"))
-  (cond ((eq (car mh-last-destination) 'refile)
-         (mh-refile-msg range (cdr mh-last-destination))
-         (message "Destination folder: %s" (cdr mh-last-destination)))
-        (t
-         (mh-iterate-on-range msg range
-           (apply 'mh-write-msg-to-file msg (cdr mh-last-destination)))
-         (mh-next-msg interactive-flag))))
-
-(defun mh-quit ()
-  "Quit the current MH-E folder.
-
-When you want to quit using MH-E and go back to editing, you can use
-this command. This buries the buffers of the current MH-E folder and
-restores the buffers that were present when you first ran
-\\[mh-rmail]. It also removes any MH-E working buffers whose name
-begins with \" *mh-\" or \"*MH-E \". You can later restore your MH-E
-session by selecting the \"+inbox\" buffer or by running \\[mh-rmail]
-again.
-
-The two hooks `mh-before-quit-hook' and `mh-quit-hook' are called by
-this function. The former one is called before the quit occurs, so you
-might use it to perform any MH-E operations; you could perform some
-query and abort the quit or call `mh-execute-commands', for example.
-The latter is not run in an MH-E context, so you might use it to
-modify the window setup."
-  (interactive)
-  (run-hooks 'mh-before-quit-hook)
-  (let ((show-buffer (get-buffer mh-show-buffer)))
-    (when show-buffer
-      (kill-buffer show-buffer)))
-  (mh-update-sequences)
-  (mh-destroy-postponed-handles)
-  (bury-buffer (current-buffer))
-
-  ;; Delete all MH-E temporary and working buffers.
-  (dolist (buffer (buffer-list))
-    (when (or (string-match "^ \\*mh-" (buffer-name buffer))
-              (string-match "^\\*MH-E " (buffer-name buffer)))
-      (kill-buffer buffer)))
-
-  (if mh-previous-window-config
-      (set-window-configuration mh-previous-window-config))
-  (run-hooks 'mh-quit-hook))
-
-(defun mh-page-msg (&optional lines)
-  "Display next page in message.
-
-You can give this command a prefix argument that specifies the
-number of LINES to scroll. This command will also show the next
-undeleted message if it is used at the bottom of a message."
-  (interactive "P")
-  (if mh-showing-mode
-      (if mh-page-to-next-msg-flag
-          (if (equal mh-next-direction 'backward)
-              (mh-previous-undeleted-msg)
-            (mh-next-undeleted-msg))
-        (if (mh-in-show-buffer (mh-show-buffer)
-              (pos-visible-in-window-p (point-max)))
-            (progn
-              (message
-               "End of message (Type %s to read %s undeleted message)"
-               (single-key-description last-input-event)
-               (if (equal mh-next-direction 'backward)
-                   "previous"
-                 "next"))
-              (setq mh-page-to-next-msg-flag t))
-          (scroll-other-window lines)))
-    (mh-show)))
+(defvar mh-show-folder-buffer nil
+  "Keeps track of folder whose message is being displayed.")
 
-(defun mh-previous-page (&optional lines)
-  "Display next page in message.
+;; MH-Letter Locals
 
-You can give this command a prefix argument that specifies the
-number of LINES to scroll."
-  (interactive "P")
-  (mh-in-show-buffer (mh-show-buffer)
-    (scroll-down lines)))
+(defvar mh-folders-changed nil
+  "Lists which folders were affected by deletes and refiles.
+This list will always include the current folder
+`mh-current-folder'. This variable can be used by
+`mh-after-commands-processed-hook'.")
 
-(defun mh-previous-undeleted-msg (&optional count wait-after-complaining-flag)
-  "Display previous message.
+(defvar mh-mail-header-separator "--------"
+  "*Line used by MH to separate headers from text in messages being composed.
 
-This command can be given a prefix argument COUNT to specify how
-many unread messages to skip.
+This variable should not be used directly in programs. Programs
+should use `mail-header-separator' instead.
+`mail-header-separator' is initialized to
+`mh-mail-header-separator' in `mh-letter-mode'; in other
+contexts, you may have to perform this initialization yourself.
 
-In a program, pause for a second after printing message if we are
-at the last undeleted message and optional argument
-WAIT-AFTER-COMPLAINING-FLAG is non-nil."
-  (interactive "p")
-  (setq mh-next-direction 'backward)
-  (beginning-of-line)
-  (cond ((re-search-backward mh-scan-good-msg-regexp nil t count)
-         (mh-maybe-show))
-        (t (message "No previous undeleted message")
-           (if wait-after-complaining-flag (sit-for 1)))))
-
-(defun mh-previous-unread-msg (&optional count)
-  "Display previous unread message.
-
-This command can be given a prefix argument COUNT to specify how
-many unread messages to skip."
-  (interactive "p")
-  (unless (> count 0)
-    (error "The function `mh-previous-unread-msg' expects positive argument"))
-  (setq count (1- count))
-  (let ((unread-sequence (cdr (assoc mh-unseen-seq mh-seq-list)))
-        (cur-msg (mh-get-msg-num nil)))
-    (cond ((and (not cur-msg) (not (bobp))
-                ;; If we are at the end of the buffer back up one line and go
-                ;; to unread message after that.
-                (progn
-                  (forward-line -1)
-                  (setq cur-msg (mh-get-msg-num nil)))
-                nil))
-          ((or (null unread-sequence) (not cur-msg))
-           ;; No unread message or there aren't any messages in buffer...
-           (message "No more unread messages"))
-          ((progn
-             ;; Skip count messages...
-             (while (and unread-sequence (>= (car unread-sequence) cur-msg))
-               (setq unread-sequence (cdr unread-sequence)))
-             (while (> count 0)
-               (setq unread-sequence (cdr unread-sequence))
-               (setq count (1- count)))
-             (not (car unread-sequence)))
-           (message "No more unread messages"))
-          (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.
-
-If BACKWARD-FLAG is non-nil search backward in the buffer for a mime
-button.
-If CRITERION is a function or a symbol which has a function binding
-then that function must return non-nil at the button we stop."
-  (unless (or (and (symbolp criterion) (fboundp criterion))
-              (functionp criterion))
-    (setq criterion (lambda (x) t)))
-  ;; Move to the next button in the buffer satisfying criterion
-  (goto-char (or (save-excursion
-                   (beginning-of-line)
-                   ;; Find point before current button
-                   (let ((point-before-current-button
-                          (save-excursion
-                            (while (get-text-property (point) 'mh-data)
-                              (unless (= (forward-line
-                                          (if backward-flag 1 -1))
-                                         0)
-                                (if backward-flag
-                                    (goto-char (point-min))
-                                  (goto-char (point-max)))))
-                            (point))))
-                     ;; Skip over current button
-                     (while (and (get-text-property (point) 'mh-data)
-                                 (not (if backward-flag (bobp) (eobp))))
-                       (forward-line (if backward-flag -1 1)))
-                     ;; Stop at next MIME button if any exists.
-                     (block loop
-                       (while (/= (progn
-                                    (unless (= (forward-line
-                                                (if backward-flag -1 1))
-                                               0)
-                                      (if backward-flag
-                                          (goto-char (point-max))
-                                        (goto-char (point-min)))
-                                      (beginning-of-line))
-                                    (point))
-                                  point-before-current-button)
-                         (when (and (get-text-property (point) 'mh-data)
-                                    (funcall criterion (point)))
-                           (return-from loop (point))))
-                       nil)))
-                 (point))))
-
-(defun mh-next-button (&optional backward-flag)
-  "Go to the next button.
-
-If the end of the buffer is reached then the search wraps over to
-the start of the buffer.
-
-If an optional prefix argument BACKWARD-FLAG is given, the cursor
-will move to the previous button."
-  (interactive (list current-prefix-arg))
-  (unless mh-showing-mode
-    (mh-show))
-  (mh-in-show-buffer (mh-show-buffer)
-    (mh-goto-next-button backward-flag)))
+Do not make this a regular expression as it may be the argument
+to `insert' and it is passed through `regexp-quote' before being
+used by functions like `re-search-forward'.")
 
-(defun mh-prev-button ()
-  "Go to the previous button.
+(defvar mh-sent-from-folder nil
+  "Folder of msg assoc with this letter.")
 
-If the beginning of the buffer is reached then the search wraps
-over to the end of the buffer."
-  (interactive)
-  (mh-next-button t))
+(defvar mh-sent-from-msg nil
+  "Number of msg assoc with this letter.")
 
-(defun mh-folder-mime-action (part-index action include-security-flag)
-  "Go to PART-INDEX and carry out ACTION.
+;; Sequences
 
-If PART-INDEX is nil then go to the next part in the buffer. The
-search for the next buffer wraps around if end of buffer is reached.
-If argument INCLUDE-SECURITY-FLAG is non-nil then include security
-info buttons when searching for a suitable parts."
-  (unless mh-showing-mode
-    (mh-show))
-  (mh-in-show-buffer (mh-show-buffer)
-    (let ((criterion
-           (cond (part-index
-                  (lambda (p)
-                    (let ((part (get-text-property p 'mh-part)))
-                      (and (integerp part) (= part part-index)))))
-                 (t (lambda (p)
-                      (if include-security-flag
-                          (get-text-property p 'mh-data)
-                        (integerp (get-text-property p 'mh-part)))))))
-          (point (point)))
-      (cond ((and (get-text-property point 'mh-part)
-                  (or (null part-index)
-                      (= (get-text-property point 'mh-part) part-index)))
-             (funcall action))
-            ((and (get-text-property point 'mh-data)
-                  include-security-flag
-                  (null part-index))
-             (funcall action))
-            (t
-             (mh-goto-next-button nil criterion)
-             (if (= (point) point)
-                 (message "No matching MIME part found")
-               (funcall action)))))))
-
-(defun mh-folder-toggle-mime-part (part-index)
-  "View attachment.
-
-This command displays (or hides) the attachment associated with
-the button under the cursor. If the cursor is not located over a
-button, then the cursor first moves to the next button, wrapping
-to the beginning of the message if necessary. This command has
-the advantage over related commands of working from the MH-Folder
-buffer.
-
-You can also provide a numeric prefix argument PART-INDEX to view
-the attachment labeled with that number. If Emacs does not know
-how to display the attachment, then Emacs offers to save the
-attachment in a file."
-  (interactive "P")
-  (when (consp part-index) (setq part-index (car part-index)))
-  (mh-folder-mime-action part-index #'mh-press-button t))
+(defvar mh-unseen-seq nil
+  "Cached value of the \"Unseen-Sequence:\" MH profile component.
+Name of the Unseen sequence.")
 
-(defun mh-folder-inline-mime-part (part-index)
-  "Show attachment verbatim.
+(defvar mh-previous-seq nil
+  "Cached value of the \"Previous-Sequence:\" MH profile component.
+Name of the Previous sequence.")
 
-You can view the raw contents of an attachment with this command.
-This command displays (or hides) the contents of the attachment
-associated with the button under the cursor verbatim. If the
-cursor is not located over a button, then the cursor first moves
-to the next button, wrapping to the beginning of the message if
-necessary.
+;; Etc. (alphabetical)
 
-You can also provide a numeric prefix argument PART-INDEX to view
-the attachment labeled with that number."
-  (interactive "P")
-  (when (consp part-index) (setq part-index (car part-index)))
-  (mh-folder-mime-action part-index #'mh-mime-inline-part nil))
+(defvar mh-flists-present-flag nil
+  "Non-nil means that we have \"flists\".")
 
-(defun mh-folder-save-mime-part (part-index)
-  "Save (output) attachment.
+(defvar mh-index-data-file ".mhe_index"
+  "MH-E specific file where index seach info is stored.")
 
-This command saves the attachment associated with the button under the
-cursor. If the cursor is not located over a button, then the cursor
-first moves to the next button, wrapping to the beginning of the
-message if necessary.
+(defvar mh-letter-header-field-regexp "^\\([A-Za-z][A-Za-z0-9-]*\\):")
 
-You can also provide a numeric prefix argument PART-INDEX to save the
-attachment labeled with that number.
+(defvar mh-page-to-next-msg-flag nil
+  "Non-nil means next SPC or whatever goes to next undeleted message.")
 
-This command prompts you for a filename and suggests a specific name
-if it is available."
-  (interactive "P")
-  (when (consp part-index) (setq part-index (car part-index)))
-  (mh-folder-mime-action part-index #'mh-mime-save-part nil))
+(defvar mh-pgp-support-flag (not (not (locate-library "mml2015")))
+  "Non-nil means PGP support is available.")
 
-(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-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)
-  "Rescan folder\\<mh-folder-mode-map>.
-
-This command is useful to grab all messages in your \"+inbox\" after
-processing your new mail for the first time. If you don't want to
-rescan the entire folder, this command will accept a RANGE. Check the
-documentation of `mh-interactive-range' to see how RANGE is read in
-interactive use.
-
-This command will ask if you want to process refiles or deletes first
-and then either run \\[mh-execute-commands] for you or undo the
-pending refiles and deletes, which are lost.
-
-In a program, the processing of outstanding commands is not performed
-if DONT-EXEC-PENDING is non-nil."
-  (interactive (list (if current-prefix-arg
-                         (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))
-        (msg-num (mh-get-msg-num nil)))
-    (mh-scan-folder mh-current-folder (or range "all") dont-exec-pending)
-    ;; If there isn't a cur sequence, mh-scan-folder goes to the first message.
-    ;; Try to stay where we were.
-    (if (null (car (mh-seq-to-msgs 'cur)))
-        (mh-goto-msg msg-num t t))
-    (cond (threaded-flag (mh-toggle-threads))
-          (mh-index-data (mh-index-insert-folder-headers)))))
-
-(defun mh-write-msg-to-file (message file no-header)
-  "Append MESSAGE to end of FILE\\<mh-folder-mode-map>.
-
-You are prompted for the filename. If the file already exists,
-the message is appended to it. You can also write the message to
-the file without the header by specifying a prefix argument
-NO-HEADER. Subsequent writes to the same file can be made with
-the command \\[mh-refile-or-write-again]."
-  (interactive
-   (list (mh-get-msg-num t)
-         (let ((default-dir (if (eq 'write (car mh-last-destination-write))
-                                (file-name-directory
-                                 (car (cdr mh-last-destination-write)))
-                              default-directory)))
-           (read-file-name (format "Save message%s in file: "
-                                   (if current-prefix-arg " body" ""))
-                           default-dir
-                           (if (eq 'write (car mh-last-destination-write))
-                               (car (cdr mh-last-destination-write))
-                             (expand-file-name "mail.out" default-dir))))
-         current-prefix-arg))
-  (let ((msg-file-to-output (mh-msg-filename message))
-        (output-file (mh-expand-file-name file)))
-    (setq mh-last-destination (list 'write file (if no-header 'no-header))
-          mh-last-destination-write mh-last-destination)
-    (save-excursion
-      (set-buffer (get-buffer-create mh-temp-buffer))
-      (erase-buffer)
-      (insert-file-contents msg-file-to-output)
-      (goto-char (point-min))
-      (if no-header (search-forward "\n\n"))
-      (append-to-file (point) (point-max) output-file))))
+(defvar mh-signature-separator "-- \n"
+  "Text of a signature separator.
+
+A signature separator is used to separate the body of a message
+from the signature. This can be used by user agents such as MH-E
+to render the signature differently or to suppress the inclusion
+of the signature in a reply. Use `mh-signature-separator-regexp'
+when searching for a separator.")
+
+(defvar mh-signature-separator-regexp "^-- $"
+  "This regular expression matches the signature separator.
+See `mh-signature-separator'.")
+
+(defvar mh-thread-scan-line-map nil
+  "Map of message index to various parts of the scan line.")
+(make-variable-buffer-local 'mh-thread-scan-line-map)
+
+(defvar mh-thread-scan-line-map-stack nil
+  "Old map of message index to various parts of the scan line.
+This is the original map that is stored when the folder is
+narrowed.")
+(make-variable-buffer-local 'mh-thread-scan-line-map-stack)
+
+(defvar mh-x-mailer-string nil
+  "*String containing the contents of the X-Mailer header field.
+If nil, this variable is initialized to show the version of MH-E,
+Emacs, and MH the first time a message is composed.")
 
-(defun mh-toggle-showing ()
-  "Toggle between MH-Folder and MH-Folder Show modes.
+
 
-This command switches between MH-Folder mode and MH-Folder Show
-mode. MH-Folder mode turns off the associated show buffer so that
-you can perform operations on the messages quickly without
-reading them. This is an excellent way to prune out your junk
-mail or to refile a group of messages to another folder for later
-examination."
-  (interactive)
-  (if mh-showing-mode
-      (mh-set-scan-mode)
-    (mh-show)))
-
-(defun mh-undo (range)
-  "Undo pending deletes or refiles in RANGE.
-
-If you've deleted a message or refiled it, but changed your mind,
-you can cancel the action before you've executed it. Use this
-command to undo a refile on or deletion of a single message. You
-can also undo refiles and deletes for messages that are found in
-a given 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)
-                           (looking-at mh-scan-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-scan-deleted-msg-regexp)
-                   (looking-at mh-scan-refiled-msg-regexp))
-               (progn
-                 (mh-undo-msg (mh-get-msg-num t))
-                 (mh-maybe-show))
-             (goto-char original-position)
-             (error "Nothing to undo"))))
-        (t (mh-iterate-on-range () range
-             (mh-undo-msg nil))))
-  (if (not (mh-outstanding-commands-p))
-      (mh-set-folder-modified-p nil)))
-
-(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, the message in the show buffer doesn't match."
-  (and (eq major-mode 'mh-folder-mode)
-       (mh-get-msg-num nil)
-       mh-show-buffer
-       (get-buffer mh-show-buffer)
-       (buffer-file-name (get-buffer mh-show-buffer))
-       (string-match ".*/\\([0-9]+\\)$"
-                     (buffer-file-name (get-buffer mh-show-buffer)))
-       (string-equal
-        (match-string 1 (buffer-file-name (get-buffer mh-show-buffer)))
-        (int-to-string (mh-get-msg-num nil)))))
+;;; MH-E Entry Points
 
 (eval-when-compile (require 'gnus))
 
@@ -1362,1489 +416,2870 @@
   (goto-char (point-min))
   (display-buffer mh-info-buffer))
 
-(defun mh-parse-flist-output-line (line &optional current-folder)
-  "Parse LINE to generate folder name, unseen messages and total messages.
-If CURRENT-FOLDER is non-nil then it contains the current folder
-name and it is used to avoid problems in corner cases involving
-folders whose names end with a '+' character."
-  (with-temp-buffer
-    (insert line)
-    (goto-char (point-max))
-    (let (folder unseen total p)
-      (when (search-backward " out of " (point-min) t)
-        (setq total (string-to-number
-                     (buffer-substring-no-properties
-                      (match-end 0) (line-end-position))))
-        (when (search-backward " in sequence " (point-min) t)
-          (setq p (point))
-          (when (search-backward " has " (point-min) t)
-            (setq unseen (string-to-number (buffer-substring-no-properties
-                                            (match-end 0) p)))
-            (while (eq (char-after) ? )
-              (backward-char))
-            (setq folder (buffer-substring-no-properties
-                          (point-min) (1+ (point))))
-            (when (and (equal (aref folder (1- (length folder))) ?+)
-                       (equal current-folder folder))
-              (setq folder (substring folder 0 (1- (length folder)))))
-            (values (format "+%s" folder) unseen total)))))))
-
-(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 (string-to-number (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 "-showzero"
-                  "-norecurse" folder "-sequence" (symbol-name mh-unseen-seq))
-    (goto-char (point-min))
-    (multiple-value-bind (folder unseen total)
-        (mh-parse-flist-output-line
-         (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.
-
-When you want to read the messages that you have refiled into folders,
-use this command to visit the folder. You are prompted for the folder
-name.
-
-The folder buffer will show just unseen messages if there are any;
-otherwise, it will show all the messages in the buffer as long there
-are fewer than `mh-large-folder' messages. If there are more, then you
-are prompted for a range of messages to scan.
-
-You can provide a prefix argument in order to specify a RANGE of
-messages to show when you visit the folder. In this case, regions are
-not used to specify the range and `mh-large-folder' is ignored. Check
-the documentation of `mh-interactive-range' to see how RANGE is read
-in interactive use.
-
-Note that this command can also be used to create folders. If you
-specify a folder that does not exist, you will be prompted to create
-it.
-
-Do not call this function from outside MH-E; use \\[mh-rmail] instead.
-
-If, in a program, RANGE is nil (the default), then all messages in
-FOLDER are displayed. If an index buffer is being created then
-INDEX-DATA is used to initialize the index buffer specific data
-structures."
-  (interactive (let ((folder-name (mh-prompt-for-folder "Visit" mh-inbox t)))
-                 (list folder-name
-                       (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)
-        (setq threaded-view-flag (memq 'unthread mh-view-ops))))
-    (when index-data
-      (mh-make-folder folder)
-      (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-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 (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 (eq current-buffer (current-buffer))
-      (setq mh-previous-window-config config)))
-  nil)
-
-(defun mh-update-sequences ()
-  "Flush MH-E's state out to MH.
-
-This function updates the sequence specified by your
-\"Unseen-Sequence:\" profile component, \"cur\", and the sequence
-listed by the `mh-tick-seq' option which is \"tick\" by default.
-The message at the cursor is used for \"cur\"."
-  (interactive)
-  ;; mh-update-sequences is the opposite of mh-read-folder-sequences,
-  ;; which updates MH-E's state from MH.
-  (let ((folder-set (mh-update-unseen))
-        (new-cur (mh-get-msg-num nil)))
-    (if new-cur
-        (let ((seq-entry (mh-find-seq 'cur)))
-          (mh-remove-cur-notation)
-          (setcdr seq-entry
-                  (list new-cur))       ;delete-seq-locally, add-msgs-to-seq
-          (mh-define-sequence 'cur (list new-cur))
-          (beginning-of-line)
-          (if (looking-at mh-scan-good-msg-regexp)
-              (mh-notate-cur)))
-      (or folder-set
-          (save-excursion
-            ;; psg - mh-current-folder is nil if mh-summary-height < 4 !
-            ;;       So I added this sanity check.
-            (if (stringp mh-current-folder)
-                (mh-exec-cmd-quiet t "folder" mh-current-folder "-fast")
-              (mh-exec-cmd-quiet t "folder" "-fast")))))))
-
 
 
-;;; Support routines.
-
-(defun mh-delete-a-msg (message)
-  "Delete MESSAGE.
-If MESSAGE is nil then the message at point is deleted.
-The hook `mh-delete-msg-hook' is called after you mark a message
-for deletion. For example, a past maintainer of MH-E used this
-once when he kept statistics on his mail usage."
-  (save-excursion
-    (if (numberp message)
-        (mh-goto-msg message nil t)
-      (beginning-of-line)
-      (setq message (mh-get-msg-num t)))
-    (if (looking-at mh-scan-refiled-msg-regexp)
-        (error "Message %d is refiled; undo refile before deleting" message))
-    (if (looking-at mh-scan-deleted-msg-regexp)
-        nil
-      (mh-set-folder-modified-p t)
-      (setq mh-delete-list (cons message mh-delete-list))
-      (mh-notate nil mh-note-deleted mh-cmd-note)
-      (run-hooks 'mh-delete-msg-hook))))
-
-(defun mh-refile-a-msg (message folder)
-  "Refile MESSAGE in FOLDER.
-If MESSAGE is nil then the message at point is refiled.
-Folder is a symbol, not a string.
-The hook `mh-refile-msg-hook' is called after a message is marked to
-be refiled."
-  (save-excursion
-    (if (numberp message)
-        (mh-goto-msg message nil t)
-      (beginning-of-line)
-      (setq message (mh-get-msg-num t)))
-    (cond ((looking-at mh-scan-deleted-msg-regexp)
-           (error "Message %d is deleted; undo delete before moving" message))
-          ((looking-at mh-scan-refiled-msg-regexp)
-           (if (y-or-n-p
-                (format "Message %d already refiled; copy to %s as well? "
-                        message folder))
-               (mh-exec-cmd "refile" (mh-get-msg-num t) "-link"
-                            "-src" mh-current-folder
-                            (symbol-name folder))
-             (message "Message not copied")))
-          (t
-           (mh-set-folder-modified-p t)
-           (cond ((null (assoc folder mh-refile-list))
-                  (push (list folder message) mh-refile-list))
-                 ((not (member message (cdr (assoc folder mh-refile-list))))
-                  (push message (cdr (assoc folder mh-refile-list)))))
-           (mh-notate nil mh-note-refiled mh-cmd-note)
-           (run-hooks 'mh-refile-msg-hook)))))
-
-(defun mh-next-msg (&optional wait-after-complaining-flag)
-  "Move backward or forward to the next undeleted message in the buffer.
-If optional argument WAIT-AFTER-COMPLAINING-FLAG is non-nil and
-we are at the last message, then wait for a second after telling
-the user that there aren't any more unread messages."
-  (if (eq mh-next-direction 'forward)
-      (mh-next-undeleted-msg 1 wait-after-complaining-flag)
-    (mh-previous-undeleted-msg 1 wait-after-complaining-flag)))
-
-(defun mh-next-unread-msg (&optional count)
-  "Display next unread message.
-
-This command can be given a prefix argument COUNT to specify how
-many unread messages to skip."
-  (interactive "p")
-  (unless (> count 0)
-    (error "The function `mh-next-unread-msg' expects positive argument"))
-  (setq count (1- count))
-  (let ((unread-sequence (reverse (cdr (assoc mh-unseen-seq mh-seq-list))))
-        (cur-msg (mh-get-msg-num nil)))
-    (cond ((and (not cur-msg) (not (bobp))
-                ;; If we are at the end of the buffer back up one line and go
-                ;; to unread message after that.
-                (progn
-                  (forward-line -1)
-                  (setq cur-msg (mh-get-msg-num nil)))
-                nil))
-          ((or (null unread-sequence) (not cur-msg))
-           ;; No unread message or there aren't any messages in buffer...
-           (message "No more unread messages"))
-          ((progn
-             ;; Skip messages
-             (while (and unread-sequence (>= cur-msg (car unread-sequence)))
-               (setq unread-sequence (cdr unread-sequence)))
-             (while (> count 0)
-               (setq unread-sequence (cdr unread-sequence))
-               (setq count (1- count)))
-             (not (car unread-sequence)))
-           (message "No more unread messages"))
-          (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."
-  (if (get-buffer mh-show-buffer)
-      (delete-windows-on mh-show-buffer))
-  (mh-showing-mode 0)
-  (force-mode-line-update)
-  (if mh-recenter-summary-flag
-      (mh-recenter nil)))
-
-(defun mh-undo-msg (msg)
-  "Undo the deletion or refile of one MSG.
-If MSG is nil then act on the message at point"
-  (save-excursion
-    (if (numberp msg)
-        (mh-goto-msg msg t t)
-      (beginning-of-line)
-      (setq msg (mh-get-msg-num t)))
-    (cond ((memq msg mh-delete-list)
-           (setq mh-delete-list (delq msg mh-delete-list)))
-          (t
-           (dolist (folder-msg-list mh-refile-list)
-             (setf (cdr folder-msg-list) (remove msg (cdr folder-msg-list))))
-           (setq mh-refile-list (loop for x in mh-refile-list
-                                      unless (null (cdr x)) collect x))))
-    (mh-notate nil ?  mh-cmd-note)))
+;;; Support Routines
+
+(defun mh-list-to-string (l)
+  "Flatten the list L and make every element of the new list into a string."
+  (nreverse (mh-list-to-string-1 l)))
+
+(defun mh-list-to-string-1 (l)
+  "Flatten the list L and make every element of the new list into a string."
+  (let ((new-list nil))
+    (while l
+      (cond ((null (car l)))
+            ((symbolp (car l))
+             (setq new-list (cons (symbol-name (car l)) new-list)))
+            ((numberp (car l))
+             (setq new-list (cons (int-to-string (car l)) new-list)))
+            ((equal (car l) ""))
+            ((stringp (car l)) (setq new-list (cons (car l) new-list)))
+            ((listp (car l))
+             (setq new-list (nconc (mh-list-to-string-1 (car l))
+                                   new-list)))
+            (t (error "Bad element in `mh-list-to-string': %s" (car l))))
+      (setq l (cdr l)))
+    new-list))
 
 
 
-;;; The folder data abstraction.
+;;; MH-E Process Support
 
-(defvar mh-index-data-file ".mhe_index"
-  "MH-E specific file where index seach info is stored.")
+(defvar mh-index-max-cmdline-args 500
+  "Maximum number of command line args.")
+
+(defun mh-xargs (cmd &rest args)
+  "Partial imitation of xargs.
+The current buffer contains a list of strings, one on each line.
+The function will execute CMD with ARGS and pass the first
+`mh-index-max-cmdline-args' strings to it. This is repeated till
+all the strings have been used."
+  (goto-char (point-min))
+  (let ((current-buffer (current-buffer)))
+    (with-temp-buffer
+      (let ((out (current-buffer)))
+        (set-buffer current-buffer)
+        (while (not (eobp))
+          (let ((arg-list (reverse args))
+                (count 0))
+            (while (and (not (eobp)) (< count mh-index-max-cmdline-args))
+              (push (buffer-substring-no-properties (point) 
(line-end-position))
+                    arg-list)
+              (incf count)
+              (forward-line))
+            (apply #'call-process cmd nil (list out nil) nil
+                   (nreverse arg-list))))
+        (erase-buffer)
+        (insert-buffer-substring out)))))
+
+;; XXX This should be applied anywhere MH-E calls out to /bin/sh.
+(defun mh-quote-for-shell (string)
+  "Quote STRING for /bin/sh.
+Adds double-quotes around entire string and quotes the characters
+\\, `, and $ with a backslash."
+  (concat "\""
+          (loop for x across string
+                concat (format (if (memq x '(?\\ ?` ?$)) "\\%c" "%c") x))
+          "\""))
+
+(defun mh-exec-cmd (command &rest args)
+  "Execute mh-command COMMAND with ARGS.
+The side effects are what is desired. Any output is assumed to be
+an error and is shown to the user. The output is not read or
+parsed by MH-E."
+  (save-excursion
+    (set-buffer (get-buffer-create mh-log-buffer))
+    (let* ((initial-size (mh-truncate-log-buffer))
+           (start (point))
+           (args (mh-list-to-string args)))
+      (apply 'call-process (expand-file-name command mh-progs) nil t nil args)
+      (when (> (buffer-size) initial-size)
+        (save-excursion
+          (goto-char start)
+          (insert "Errors when executing: " command)
+          (loop for arg in args do (insert " " arg))
+          (insert "\n"))
+        (save-window-excursion
+          (switch-to-buffer-other-window mh-log-buffer)
+          (sit-for 5))))))
+
+(defun mh-exec-cmd-error (env command &rest args)
+  "In environment ENV, execute mh-command COMMAND with ARGS.
+ENV is nil or a string of space-separated \"var=value\" elements.
+Signals an error if process does not complete successfully."
+  (save-excursion
+    (set-buffer (get-buffer-create mh-temp-buffer))
+    (erase-buffer)
+    (let ((process-environment process-environment))
+      ;; XXX: We should purge the list that split-string returns of empty
+      ;;  strings. This can happen in XEmacs if leading or trailing spaces
+      ;;  are present.
+      (dolist (elem (if (stringp env) (split-string env " ") ()))
+        (push elem process-environment))
+      (mh-handle-process-error
+       command (apply #'call-process (expand-file-name command mh-progs)
+                      nil t nil (mh-list-to-string args))))))
+
+(defun mh-exec-cmd-daemon (command filter &rest args)
+  "Execute MH command COMMAND in the background.
+
+If FILTER is non-nil then it is used to process the output
+otherwise the default filter `mh-process-daemon' is used. See
+`set-process-filter' for more details of FILTER.
 
-(defun mh-make-folder (name)
-  "Create a new mail folder called NAME.
-Make it the current folder."
-  (switch-to-buffer name)
-  (setq buffer-read-only nil)
+ARGS are passed to COMMAND as command line arguments."
+  (save-excursion
+    (set-buffer (get-buffer-create mh-log-buffer))
+    (mh-truncate-log-buffer))
+  (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 (or filter 'mh-process-daemon))
+    process))
+
+(defun mh-exec-cmd-env-daemon (env command filter &rest args)
+  "In ennvironment ENV, execute mh-command COMMAND in the background.
+
+ENV is nil or a string of space-separated \"var=value\" elements.
+Signals an error if process does not complete successfully.
+
+If FILTER is non-nil then it is used to process the output
+otherwise the default filter `mh-process-daemon' is used. See
+`set-process-filter' for more details of FILTER.
+
+ARGS are passed to COMMAND as command line arguments."
+  (let ((process-environment process-environment))
+    (dolist (elem (if (stringp env) (split-string env " ") ()))
+      (push elem process-environment))
+    (apply #'mh-exec-cmd-daemon command filter args)))
+
+(defun mh-process-daemon (process output)
+  "PROCESS daemon that puts OUTPUT into a temporary buffer.
+Any output from the process is displayed in an asynchronous
+pop-up window."
+  (with-current-buffer (get-buffer-create mh-log-buffer)
+    (insert-before-markers output)
+    (display-buffer mh-log-buffer)))
+
+(defun mh-exec-cmd-quiet (raise-error command &rest args)
+  "Signal RAISE-ERROR if COMMAND with ARGS fails.
+Execute MH command COMMAND with ARGS. ARGS is a list of strings.
+Return at start of mh-temp buffer, where output can be parsed and
+used.
+Returns value of `call-process', which is 0 for success, unless
+RAISE-ERROR is non-nil, in which case an error is signaled if
+`call-process' returns non-0."
+  (set-buffer (get-buffer-create mh-temp-buffer))
   (erase-buffer)
-  (if mh-adaptive-cmd-note-flag
-      (mh-set-cmd-note (mh-msg-num-width-to-column (mh-msg-num-width name))))
-  (setq buffer-read-only t)
-  (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.
-(put 'mh-folder-mode 'mode-class 'special)
-
-
-
-;;; Build mh-folder-mode menu
-
-;; Menu extracted from mh-menubar.el V1.1 (31 July 2001)
-;; Menus for folder mode: folder, message, sequence (in that order)
-;; folder-mode "Sequence" menu
-(easy-menu-define
-  mh-folder-sequence-menu mh-folder-mode-map "Menu for MH-E folder-sequence."
-  '("Sequence"
-    ["Add Message to Sequence..."       mh-put-msg-in-seq (mh-get-msg-num nil)]
-    ["List Sequences for Message"       mh-msg-is-in-seq (mh-get-msg-num nil)]
-    ["Delete Message from Sequence..."  mh-delete-msg-from-seq
-     (mh-get-msg-num nil)]
-    ["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-folder-view-stack]
-    "--"
-    ["Narrow to Subject Sequence"       mh-narrow-to-subject t]
-    ["Narrow to Tick Sequence"          mh-narrow-to-tick
-     (and mh-tick-seq (mh-seq-msgs (mh-find-seq mh-tick-seq)))]
-    ["Delete Rest of Same Subject"      mh-delete-subject t]
-    ["Toggle Tick Mark"                 mh-toggle-tick t]
-    "--"
-    ["Push State Out to MH"             mh-update-sequences t]))
-
-;; folder-mode "Message" menu
-(easy-menu-define
-  mh-folder-message-menu mh-folder-mode-map "Menu for MH-E folder-message."
-  '("Message"
-    ["Show Message"                     mh-show (mh-get-msg-num nil)]
-    ["Show Message with Header"         mh-header-display (mh-get-msg-num nil)]
-    ["Next Message"                     mh-next-undeleted-msg t]
-    ["Previous Message"                 mh-previous-undeleted-msg t]
-    ["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 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 (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)]
-    ["Forward Message..."               mh-forward (mh-get-msg-num nil)]
-    ["Redistribute Message..."          mh-redistribute (mh-get-msg-num nil)]
-    ["Edit Message Again"               mh-edit-again (mh-get-msg-num nil)]
-    ["Re-edit a Bounced Message"        mh-extract-rejected-mail t]
-    "--"
-    ["Copy Message to Folder..."        mh-copy-msg (mh-get-msg-num nil)]
-    ["Print Message"                    mh-print-msg (mh-get-msg-num nil)]
-    ["Write Message to File..."         mh-write-msg-to-file
-     (mh-get-msg-num nil)]
-    ["Pipe Message to Command..."       mh-pipe-msg (mh-get-msg-num nil)]
-    ["Unpack Uuencoded Message..."      mh-store-msg (mh-get-msg-num nil)]
-    ["Burst Digest Message"             mh-burst-digest (mh-get-msg-num nil)]))
-
-;; folder-mode "Folder" menu
-(easy-menu-define
-  mh-folder-folder-menu mh-folder-mode-map  "Menu for MH-E folder."
-  '("Folder"
-    ["Incorporate New Mail"             mh-inc-folder t]
-    ["Toggle Show/Folder"               mh-toggle-showing t]
-    ["Execute Delete/Refile"            mh-execute-commands
-     (mh-outstanding-commands-p)]
-    ["Rescan Folder"                    mh-rescan-folder t]
-    ["Thread Folder"                    mh-toggle-threads
-     (not (memq 'unthread mh-view-ops))]
-    ["Pack Folder"                      mh-pack-folder t]
-    ["Sort Folder"                      mh-sort-folder t]
-    "--"
-    ["List Folders"                     mh-list-folders t]
-    ["Visit a Folder..."                mh-visit-folder t]
-    ["View New Messages"                mh-index-new-messages t]
-    ["Search..."                        mh-search t]
-    "--"
-    ["Quit MH-E"                        mh-quit t]))
-
-
-
-(defmacro mh-remove-xemacs-horizontal-scrollbar ()
-  "Get rid of the horizontal scrollbar that XEmacs insists on putting in."
-  (when mh-xemacs-flag
-    `(if (and (featurep 'scrollbar)
-              (fboundp 'set-specifier))
-         (set-specifier horizontal-scrollbar-visible-p nil
-                        (cons (current-buffer) nil)))))
-
-(defmacro mh-write-file-functions-compat ()
-  "Return `write-file-functions' if it exists.
-Otherwise return `local-write-file-hooks'. This macro exists
-purely for compatibility. The former symbol is used in Emacs 21.4
-onward while the latter is used in previous versions and XEmacs."
-  (if (boundp 'write-file-functions)
-      ''write-file-functions            ;Emacs 21.4
-    ''local-write-file-hooks))          ;XEmacs
-
-;; 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))
+  (let ((value
+         (apply 'call-process
+                (expand-file-name command mh-progs) nil t nil
+                args)))
+    (goto-char (point-min))
+    (if raise-error
+        (mh-handle-process-error command value)
+      value)))
+
+(defun mh-exec-cmd-output (command display &rest args)
+  "Execute MH command COMMAND with DISPLAY flag and ARGS.
+Put the output into buffer after point.
+Set mark after inserted text.
+Output is expected to be shown to user, not parsed by MH-E."
+  (push-mark (point) t)
+  (apply 'call-process
+         (expand-file-name command mh-progs) nil t display
+         (mh-list-to-string args))
+
+  ;; The following is used instead of 'exchange-point-and-mark because the
+  ;; latter activates the current region (between point and mark), which
+  ;; turns on highlighting.  So prior to this bug fix, doing "inc" would
+  ;; highlight a region containing the new messages, which is undesirable.
+  ;; The bug wasn't seen in emacs21 but still occurred in XEmacs21.4.
+  (mh-exchange-point-and-mark-preserving-active-mark))
 
 ;; Shush compiler.
-(eval-when-compile
-  (defvar desktop-save-buffer)
-  (defvar font-lock-auto-fontify))
+(eval-when-compile (mh-do-in-xemacs (defvar mark-active)))
+
+(defun mh-exchange-point-and-mark-preserving-active-mark ()
+  "Put the mark where point is now, and point where the mark is now.
+This command works even when the mark is not active, and
+preserves whether the mark is active or not."
+  (interactive nil)
+  (let ((is-active (and (boundp 'mark-active) mark-active)))
+    (let ((omark (mark t)))
+      (if (null omark)
+          (error "No mark set in this buffer"))
+      (set-mark (point))
+      (goto-char omark)
+      (if (boundp 'mark-active)
+          (setq mark-active is-active))
+      nil)))
+
+(defun mh-exec-lib-cmd-output (command &rest args)
+  "Execute MH library command COMMAND with ARGS.
+Put the output into buffer after point.
+Set mark after inserted text."
+  (apply 'mh-exec-cmd-output (expand-file-name command mh-lib-progs) nil args))
+
+(defun mh-handle-process-error (command status)
+  "Raise error if COMMAND returned non-zero STATUS, otherwise return STATUS."
+  (if (equal status 0)
+      status
+    (goto-char (point-min))
+    (insert (if (integerp status)
+                (format "%s: exit code %d\n" command status)
+              (format "%s: %s\n" command status)))
+    (save-excursion
+      (let ((error-message (buffer-substring (point-min) (point-max))))
+        (set-buffer (get-buffer-create mh-log-buffer))
+        (mh-truncate-log-buffer)
+        (insert error-message)))
+    (error "%s failed, check buffer %s for error message"
+           command mh-log-buffer)))
 
-(defvar mh-folder-buttons-init-flag nil)
+
 
-;; Autoload cookie needed by desktop.el
-;;;###autoload
-(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>
+;;; Variant Support
 
-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.
-
-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 predefined 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}"
-  (mh-do-in-gnu-emacs
-   (unless mh-folder-buttons-init-flag
-     (mh-tool-bar-folder-buttons-init)
-     (setq mh-folder-buttons-init-flag t)))
-  (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.
-   'mh-showing-mode nil                 ; Show message also?
-   'mh-delete-list nil                  ; List of msgs nums to delete
-   'mh-refile-list nil                  ; List of folder names in mh-seq-list
-   '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-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-search, this contains info
-                                        ; about the search results.
-   'mh-index-previous-search nil        ; folder, indexer, 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)
-  (auto-save-mode -1)
-  (setq buffer-offer-save t)
-  (mh-make-local-hook (mh-write-file-functions-compat))
-  (add-hook (mh-write-file-functions-compat) 'mh-execute-commands nil t)
-  (make-local-variable 'revert-buffer-function)
-  (make-local-variable 'hl-line-mode)   ; avoid pollution
-  (mh-funcall-if-exists hl-line-mode 1)
-  (setq revert-buffer-function 'mh-undo-folder)
-  (or (assq 'mh-showing-mode minor-mode-alist)
-      (setq minor-mode-alist
-            (cons '(mh-showing-mode " Show") minor-mode-alist)))
-  (easy-menu-add mh-folder-sequence-menu)
-  (easy-menu-add mh-folder-message-menu)
-  (easy-menu-add mh-folder-folder-menu)
-  (set (make-local-variable 'tool-bar-map) mh-folder-tool-bar-map)
-  (mh-funcall-if-exists mh-tool-bar-init :folder)
-  (if (and mh-xemacs-flag
-           font-lock-auto-fontify)
-      (turn-on-font-lock)))             ; Force font-lock in XEmacs.
+(defcustom mh-path nil
+  "*Additional list of directories to search for MH.
+See `mh-variant'."
+  :group 'mh-e
+  :type '(repeat (directory)))
+
+(defun mh-variants ()
+  "Return a list of installed variants of MH on the system.
+This function looks for MH in `mh-sys-path', `mh-path' and
+`exec-path'. The format of the list of variants that is returned
+is described by the variable `mh-variants'."
+  (if mh-variants
+      mh-variants
+    (let ((list-unique))
+      ;; Make a unique list of directories, keeping the given order.
+      ;; We don't want the same MH variant to be listed multiple times.
+      (loop for dir in (append mh-path mh-sys-path exec-path) do
+            (setq dir (file-chase-links (directory-file-name dir)))
+            (add-to-list 'list-unique dir))
+      (loop for dir in (nreverse list-unique) do
+            (when (and dir (file-directory-p dir) (file-readable-p dir))
+              (let ((variant (mh-variant-info dir)))
+                (if variant
+                    (add-to-list 'mh-variants variant)))))
+      mh-variants)))
 
-(defun mh-toggle-mime-buttons ()
-  "Toggle option `mh-display-buttons-for-inline-parts-flag'."
-  (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 (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."
-
-  (while pairs
-    (set (make-local-variable (car pairs)) (car (cdr pairs)))
-    (setq pairs (cdr (cdr pairs)))))
-
-(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))
-
-;; desktop-buffer-mode-handlers appeared in Emacs 22.
-(if (fboundp 'desktop-buffer-mode-handlers)
-    (add-to-list 'desktop-buffer-mode-handlers
-                 '(mh-folder-mode . mh-restore-desktop-buffer)))
-
-(defun mh-scan-folder (folder range &optional dont-exec-pending)
-  "Scan FOLDER over RANGE.
-
-After the scan is performed, switch to the buffer associated with
-FOLDER.
-
-Check the documentation of `mh-interactive-range' to see how RANGE is
-read in interactive use.
-
-The processing of outstanding commands is not performed if
-DONT-EXEC-PENDING is non-nil."
-  (when (stringp range)
-    (setq range (delete "" (split-string range "[ \t\n]"))))
-  (cond ((null (get-buffer folder))
-         (mh-make-folder folder))
-        (t
-         (unless dont-exec-pending
-           (mh-process-or-undo-commands folder)
-           (mh-reset-threads-and-narrowing))
-         (switch-to-buffer folder)))
-  (mh-regenerate-headers range)
-  (if (zerop (buffer-size))
-      (if (equal range "all")
-          (message "Folder %s is empty" folder)
-        (message "No messages in %s, range %s" folder range))
-    (mh-goto-cur-msg))
-  (when (mh-outstanding-commands-p)
-    (mh-notate-deleted-and-refiled)))
-
-(defun mh-msg-num-width-to-column (width)
-  "Return the column for notations given message number WIDTH.
-Note that columns in Emacs start with 0.
-
-If `mh-scan-format-file' is set to \"Use MH-E scan Format\" this
-means that either `mh-scan-format-mh' or `mh-scan-format-nmh' are
-in use. This function therefore assumes that the first column is
-empty (to provide room for the cursor), the following WIDTH
-columns contain the message number, and the column for notations
-comes after that."
-  (if (eq mh-scan-format-file t)
-      (max (1+ width) 2)
-    (error "%s %s" "Can't call `mh-msg-num-width-to-column' when"
-           "`mh-scan-format-file' is not set to \"Use MH-E scan Format\"")))
-
-(defun mh-set-cmd-note (column)
-  "Set `mh-cmd-note' to COLUMN.
-Note that columns in Emacs start with 0."
-  (setq mh-cmd-note column))
-
-(defun mh-regenerate-headers (range &optional update)
-  "Scan folder over RANGE.
-If UPDATE, append the scan lines, otherwise replace."
-  (let ((folder mh-current-folder)
-        (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))
-        (delete-region (point-min) (point-max))
-        (if mh-adaptive-cmd-note-flag
-            (mh-set-cmd-note (mh-msg-num-width-to-column (mh-msg-num-width
-                                                          folder)))))
-      (setq scan-start (point))
-      (apply #'mh-exec-cmd-output
-             mh-scan-prog nil
-             (mh-scan-format)
-             "-noclear" "-noheader"
-             "-width" (window-width)
-             folder range)
-      (goto-char scan-start)
-      (cond ((looking-at "scan: no messages in")
-             (keep-lines mh-scan-valid-regexp)) ; Flush random scan lines
-            ((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
-             (keep-lines mh-scan-valid-regexp))) ; Flush random scan lines
-      (setq mh-seq-list (mh-read-folder-sequences folder nil))
-      (mh-notate-user-sequences)
-      (or update
-          (setq mh-mode-line-annotation
-                (if (equal range '("all"))
-                    nil
-                  mh-partial-folder-mode-line-annotation)))
-      (mh-make-folder-mode-line))
-    (message "Scanning %s...done" folder)))
-
-(defun mh-generate-new-cmd-note (folder)
-  "Fix the `mh-cmd-note' value for this FOLDER.
-
-After doing an `mh-get-new-mail' operation in this FOLDER, at least
-one line that looks like a truncated message number was found.
-
-Remove the text added by the last `mh-inc' command. It should be the
-messages cur-last. Call `mh-set-cmd-note', adjusting the notation
-column with the width of the largest message number in FOLDER.
-
-Reformat the message number width on each line in the buffer and trim
-the line length to fit in the window.
-
-Rescan the FOLDER in the range cur-last in order to display the
-messages that were removed earlier. They should all fit in the scan
-line now with no message truncation."
+(defun mh-variant-info (dir)
+  "Return MH variant found in DIR, or nil if none present."
   (save-excursion
-    (let ((maxcol (1- (window-width)))
-          (old-cmd-note mh-cmd-note)
-          mh-cmd-note-fmt
-          msgnum)
-      ;; Nuke all of the lines just added by the last inc
-      (delete-char (- (point-max) (point)))
-      ;; Update the current buffer to reflect the new mh-cmd-note
-      ;; value needed to display messages.
-      (mh-set-cmd-note (mh-msg-num-width-to-column (mh-msg-num-width folder)))
-      (setq mh-cmd-note-fmt (concat "%" (format "%d" mh-cmd-note) "d"))
-      ;; Cleanup the messages that are in the buffer right now
+    (let ((tmp-buffer (get-buffer-create mh-temp-buffer)))
+      (set-buffer tmp-buffer)
+      (cond
+       ((mh-variant-mh-info dir))
+       ((mh-variant-nmh-info dir))
+       ((mh-variant-mu-mh-info dir))))))
+
+(defun mh-variant-mh-info (dir)
+  "Return info for MH variant in DIR assuming a temporary buffer is setup."
+  ;; MH does not have the -version option.
+  ;; Its version number is included in the output of "-help" as:
+  ;;
+  ;; version: MH 6.8.4 #2[UCI] (burrito) of Fri Jan 15 20:01:39 EST 1999
+  ;; options: [ATHENA] [BIND] [DUMB] [LIBLOCKFILE] [LOCALE] [MAILGROUP] [MHE]
+  ;;          [MHRC] [MIME] [MORE='"/usr/bin/sensible-pager"'] [NLINK_HACK]
+  ;;          [NORUSERPASS] [OVERHEAD] [POP] [POPSERVICE='"pop-3"'] [RENAME]
+  ;;          [RFC1342] [RPATHS] [RPOP] [SENDMTS] [SMTP] [SOCKETS]
+  ;;          [SPRINTFTYPE=int] [SVR4] [SYS5] [SYS5DIR] [TERMINFO]
+  ;;          [TYPESIG=void] [UNISTD] [UTK] [VSPRINTF]
+  (let ((mhparam (expand-file-name "mhparam" dir)))
+    (when (mh-file-command-p mhparam)
+      (erase-buffer)
+      (call-process mhparam nil '(t nil) nil "-help")
       (goto-char (point-min))
-      (cond ((memq 'unthread mh-view-ops)
-             (mh-thread-add-spaces (- mh-cmd-note old-cmd-note)))
-            (t (while (re-search-forward mh-scan-msg-number-regexp nil 0 1)
-                 ;; reformat the number to fix in mh-cmd-note columns
-                 (setq msgnum (string-to-number
-                               (buffer-substring
-                                (match-beginning 1) (match-end 1))))
-                 (replace-match (format mh-cmd-note-fmt msgnum))
-                 ;; trim the line to fix in the window
-                 (end-of-line)
-                 (let ((eol (point)))
-                   (move-to-column maxcol)
-                   (if (<= (point) eol)
-                       (delete-char (- eol (point))))))))
-      ;; now re-read the lost messages
-      (goto-char (point-max))
-      (prog1 (point)
-        (mh-regenerate-headers "cur-last" t)))))
-
-(defun mh-get-new-mail (maildrop-name)
-  "Read new mail from MAILDROP-NAME into the current buffer.
-Return in the current buffer."
-  (let ((point-before-inc (point))
-        (folder mh-current-folder)
-        (new-mail-flag nil))
-    (with-mh-folder-updating (t)
-      (if maildrop-name
-          (message "inc %s -file %s..." folder maildrop-name)
-        (message "inc %s..." folder))
-      (setq mh-next-direction 'forward)
-      (goto-char (point-max))
-      (mh-remove-cur-notation)
-      (let ((start-of-inc (point)))
-        (if maildrop-name
-            ;; I think MH 5 used "-ms-file" instead of "-file",
-            ;; which would make inc'ing from maildrops fail.
-            (mh-exec-cmd-output mh-inc-prog nil folder
-                                (mh-scan-format)
-                                "-file" (expand-file-name maildrop-name)
-                                "-width" (window-width)
-                                "-truncate")
-          (mh-exec-cmd-output mh-inc-prog nil
-                              (mh-scan-format)
-                              "-width" (window-width)))
-        (if maildrop-name
-            (message "inc %s -file %s...done" folder maildrop-name)
-          (message "inc %s...done" folder))
-        (goto-char start-of-inc)
-        (cond ((save-excursion
-                 (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-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 t)
-                          (mh-remove-cur-notation)
-                          (goto-char (point-max))
-                          (setq start-of-inc (point))
-                          (insert saved-text)
-                          (goto-char start-of-inc))))
-                    nil))
-              ((re-search-forward "^inc:" nil t) ; Error messages
-               (error "Error incorporating mail"))
-              ((and
-                (equal mh-scan-format-file t)
-                mh-adaptive-cmd-note-flag
-                ;; Have we reached an edge condition?
-                (save-excursion
-                  (re-search-forward mh-scan-msg-overflow-regexp nil 0 1))
-                (setq start-of-inc (mh-generate-new-cmd-note folder))
-                nil))
-              (t
-               (setq new-mail-flag t)))
-        (keep-lines mh-scan-valid-regexp) ; Flush random scan lines
-        (let* ((sequences (mh-read-folder-sequences folder t))
-               (new-cur (assoc 'cur sequences))
-               (new-unseen (assoc mh-unseen-seq sequences)))
-          (unless (assoc 'cur mh-seq-list)
-            (push (list 'cur) mh-seq-list))
-          (unless (assoc mh-unseen-seq mh-seq-list)
-            (push (list mh-unseen-seq) mh-seq-list))
-          (setcdr (assoc 'cur mh-seq-list) (cdr new-cur))
-          (setcdr (assoc mh-unseen-seq mh-seq-list) (cdr new-unseen)))
-        (when (equal (point-max) start-of-inc)
-          (mh-notate-cur))
-        (if new-mail-flag
-            (progn
-              (mh-make-folder-mode-line)
-              (when (mh-speed-flists-active-p)
-                (mh-speed-flists t mh-current-folder))
-              (when (memq 'unthread mh-view-ops)
-                (mh-thread-inc folder start-of-inc))
-              (mh-goto-cur-msg))
-          (goto-char point-before-inc))
-        (mh-notate-user-sequences (cons start-of-inc (point-max)))))))
-
-(defun mh-make-folder-mode-line (&optional ignored)
-  "Set the fields of the mode line for a folder buffer.
-The optional argument is now obsolete and IGNORED. It used to be
-used to pass in what is now stored in the buffer-local variable
-`mh-mode-line-annotation'."
-  (save-excursion
-    (save-window-excursion
-      (mh-first-msg)
-      (let ((new-first-msg-num (mh-get-msg-num nil)))
-        (when (or (not (memq 'unthread mh-view-ops))
-                  (null mh-first-msg-num)
-                  (null new-first-msg-num)
-                  (< new-first-msg-num mh-first-msg-num))
-          (setq mh-first-msg-num new-first-msg-num)))
-      (mh-last-msg)
-      (let ((new-last-msg-num (mh-get-msg-num nil)))
-        (when (or (not (memq 'unthread mh-view-ops))
-                  (null mh-last-msg-num)
-                  (null new-last-msg-num)
-                  (> new-last-msg-num mh-last-msg-num))
-          (setq mh-last-msg-num new-last-msg-num)))
-      (setq mh-msg-count (if mh-first-msg-num
-                             (count-lines (point-min) (point-max))
-                           0))
-      (setq mode-line-buffer-identification
-            (list (format "    {%%b%s} %s msg%s"
-                          (if mh-mode-line-annotation
-                              (format "/%s" mh-mode-line-annotation)
-                            "")
-                          (if (zerop mh-msg-count)
-                              "no"
-                            (format "%d" mh-msg-count))
-                          (if (zerop mh-msg-count)
-                              "s"
-                            (cond ((> mh-msg-count 1)
-                                   (format "s (%d-%d)" mh-first-msg-num
-                                           mh-last-msg-num))
-                                  (mh-first-msg-num
-                                   (format " (%d)" mh-first-msg-num))
-                                  (""))))))
-      (mh-logo-display))))
-
-(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 (+ mh-cmd-note mh-scan-field-destination-offset))
-        (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
-                   (+ mh-cmd-note mh-scan-field-destination-offset))))))
-
-(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 (+ mh-cmd-note mh-scan-field-destination-offset))
-            (delete-char 1)
-            (insert (car stack))))
-        (setf (gethash msg mh-sequence-notation-history) (cdr stack))))))
-
-(defun mh-remove-cur-notation ()
-  "Remove old cur notation."
-  (let ((cur-msg (car (mh-seq-to-msgs 'cur))))
-    (save-excursion
-      (when (and cur-msg
-                 (mh-goto-msg cur-msg t t)
-                 (looking-at mh-scan-cur-msg-number-regexp))
-        (mh-notate nil ?  mh-cmd-note)
-        (setq overlay-arrow-position nil)))))
+      (when (search-forward-regexp "version: MH \\(\\S +\\)" nil t)
+        (let ((version (format "MH %s" (match-string 1))))
+          (erase-buffer)
+          (call-process mhparam nil '(t nil) nil "libdir")
+          (goto-char (point-min))
+          (when (search-forward-regexp "^.*$" nil t)
+            (let ((libdir (match-string 0)))
+              `(,version
+                (variant        mh)
+                (mh-lib-progs   ,libdir)
+                (mh-lib         ,libdir)
+                (mh-progs       ,dir)
+                (flists         nil)))))))))
+
+(defun mh-variant-mu-mh-info (dir)
+  "Return info for GNU mailutils variant in DIR.
+This assumes that a temporary buffer is setup."
+  ;; 'mhparam -version' output:
+  ;; mhparam (GNU mailutils 0.3.2)
+  (let ((mhparam (expand-file-name "mhparam" dir)))
+    (when (mh-file-command-p mhparam)
+      (erase-buffer)
+      (call-process mhparam nil '(t nil) nil "-version")
+      (goto-char (point-min))
+      (when (search-forward-regexp "mhparam (\\(GNU [Mm]ailutils \\S +\\))"
+                                   nil t)
+        (let ((version (match-string 1))
+              (mh-progs dir))
+          `(,version
+            (variant        mu-mh)
+            (mh-lib-progs   ,(mh-profile-component "libdir"))
+            (mh-lib         ,(mh-profile-component "etcdir"))
+            (mh-progs       ,dir)
+            (flists         ,(file-exists-p
+                              (expand-file-name "flists" dir)))))))))
+
+(defun mh-variant-nmh-info (dir)
+  "Return info for nmh variant in DIR assuming a temporary buffer is setup."
+  ;; `mhparam -version' outputs:
+  ;; mhparam -- nmh-1.1-RC1 [compiled on chaak at Fri Jun 20 11:03:28 PDT 2003]
+  (let ((mhparam (expand-file-name "mhparam" dir)))
+    (when (mh-file-command-p mhparam)
+      (erase-buffer)
+      (call-process mhparam nil '(t nil) nil "-version")
+      (goto-char (point-min))
+      (when (search-forward-regexp "mhparam -- nmh-\\(\\S +\\)" nil t)
+        (let ((version (format "nmh %s" (match-string 1)))
+              (mh-progs dir))
+          `(,version
+            (variant        nmh)
+            (mh-lib-progs   ,(mh-profile-component "libdir"))
+            (mh-lib         ,(mh-profile-component "etcdir"))
+            (mh-progs       ,dir)
+            (flists         ,(file-exists-p
+                              (expand-file-name "flists" dir)))))))))
+
+(defun mh-file-command-p (file)
+  "Return t if file FILE is the name of a executable regular file."
+  (and (file-regular-p file) (file-executable-p file)))
+
+(defun mh-variant-set-variant (variant)
+  "Setup the system variables for the MH variant named VARIANT.
+If VARIANT is a string, use that key in the alist returned by the
+function `mh-variants'.
+If VARIANT is a symbol, select the first entry that matches that
+variant."
+  (cond
+   ((stringp variant)                   ;e.g. "nmh 1.1-RC1"
+    (when (assoc variant (mh-variants))
+      (let* ((alist (cdr (assoc variant (mh-variants))))
+             (lib-progs (cadr (assoc 'mh-lib-progs alist)))
+             (lib       (cadr (assoc 'mh-lib       alist)))
+             (progs     (cadr (assoc 'mh-progs     alist)))
+             (flists    (cadr (assoc 'flists       alist))))
+        ;;(set-default mh-variant variant)
+        (setq mh-x-mailer-string     nil
+              mh-flists-present-flag flists
+              mh-lib-progs           lib-progs
+              mh-lib                 lib
+              mh-progs               progs
+              mh-variant-in-use      variant))))
+   ((symbolp variant)                   ;e.g. 'nmh (pick the first match)
+    (loop for variant-list in (mh-variants)
+          when (eq variant (cadr (assoc 'variant (cdr variant-list))))
+          return (let* ((version   (car variant-list))
+                        (alist (cdr variant-list))
+                        (lib-progs (cadr (assoc 'mh-lib-progs alist)))
+                        (lib       (cadr (assoc 'mh-lib       alist)))
+                        (progs     (cadr (assoc 'mh-progs     alist)))
+                        (flists    (cadr (assoc 'flists       alist))))
+                   ;;(set-default mh-variant flavor)
+                   (setq mh-x-mailer-string     nil
+                         mh-flists-present-flag flists
+                         mh-lib-progs           lib-progs
+                         mh-lib                 lib
+                         mh-progs               progs
+                         mh-variant-in-use      version)
+                   t)))))
+
+(defun mh-variant-p (&rest variants)
+  "Return t if variant is any of VARIANTS.
+Currently known variants are 'MH, 'nmh, and 'mu-mh."
+  (let ((variant-in-use
+         (cadr (assoc 'variant (assoc mh-variant-in-use (mh-variants))))))
+    (not (null (member variant-in-use variants)))))
 
-(defun mh-remove-all-notation ()
-  "Remove all notations on all scan lines that MH-E introduces."
+(defun mh-profile-component (component)
+  "Return COMPONENT value from mhparam, or nil if unset."
   (save-excursion
-    (setq overlay-arrow-position nil)
+    (mh-exec-cmd-quiet nil "mhparam" "-components" component)
+    (mh-profile-component-value component)))
+
+(defun mh-profile-component-value (component)
+  "Find and return the value of COMPONENT in the current buffer.
+Returns nil if the component is not in the buffer."
+  (let ((case-fold-search t))
     (goto-char (point-min))
-    (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)))
-
-(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 recenter the folder buffer."
-  (let ((cur-msg (car (mh-seq-to-msgs 'cur))))
-    (cond ((and cur-msg
-                (mh-goto-msg cur-msg t t))
-           (unless minimal-changes-flag
-             (mh-notate-cur)
-             (mh-recenter 0)
-             (mh-maybe-show cur-msg)))
+    (cond ((not (re-search-forward (format "^%s:" component) nil t)) nil)
+          ((looking-at "[\t ]*$") nil)
           (t
-           (setq overlay-arrow-position nil)
-           (message "No current message")))))
+           (re-search-forward "[\t ]*\\([^\t \n].*\\)$" nil t)
+           (let ((start (match-beginning 1)))
+             (end-of-line)
+             (buffer-substring start (point)))))))
+
+(defun mh-variant-set (variant)
+  "Set the MH variant to VARIANT.
+Sets `mh-progs', `mh-lib', `mh-lib-progs' and
+`mh-flists-present-flag'.
+If the VARIANT is \"autodetect\", then first try nmh, then MH and
+finally GNU mailutils."
+  (interactive
+   (list (completing-read
+          "MH variant: "
+          (mapcar (lambda (x) (list (car x))) (mh-variants))
+          nil t)))
+  (let ((valid-list (mapcar (lambda (x) (car x)) (mh-variants))))
+    (cond
+     ((eq variant 'none))
+     ((eq variant 'autodetect)
+      (cond
+       ((mh-variant-set-variant 'nmh)
+        (message "%s installed as MH variant" mh-variant-in-use))
+       ((mh-variant-set-variant 'mh)
+        (message "%s installed as MH variant" mh-variant-in-use))
+       ((mh-variant-set-variant 'mu-mh)
+        (message "%s installed as MH variant" mh-variant-in-use))
+       (t
+        (message "No MH variant found on the system"))))
+     ((member variant valid-list)
+      (when (not (mh-variant-set-variant variant))
+        (message "Warning: %s variant not found. Autodetecting..." variant)
+        (mh-variant-set 'autodetect)))
+     (t
+      (message "Unknown variant; use %s"
+               (mapconcat '(lambda (x) (format "%s" (car x)))
+                          (mh-variants) " or "))))))
+
+(defcustom mh-variant 'autodetect
+  "*Specifies the variant used by MH-E.
+
+The default setting of this option is \"Auto-detect\" which means
+that MH-E will automatically choose the first of nmh, MH, or GNU
+mailutils that it finds in the directories listed in
+`mh-path' (which you can customize), `mh-sys-path', and
+`exec-path'. If, for example, you have both nmh and mailutils
+installed and `mh-variant-in-use' was initialized to nmh but you
+want to use mailutils, then you can set this option to
+\"mailutils\".
+
+When this variable is changed, MH-E resets `mh-progs', `mh-lib',
+`mh-lib-progs', `mh-flists-present-flag', and `mh-variant-in-use'
+accordingly."
+  :type `(radio
+          (const :tag "Auto-detect" autodetect)
+          ,@(mapcar (lambda (x) `(const ,(car x))) (mh-variants)))
+  :set (lambda (symbol value)
+         (set-default symbol value)     ;Done in mh-variant-set-variant!
+         (mh-variant-set value))
+  :group 'mh-e)
+
+
 
-(defun mh-process-or-undo-commands (folder)
-  "If FOLDER has outstanding commands, then either process or discard them.
-Called by functions like `mh-sort-folder', so also invalidate
-show buffer."
-  (set-buffer folder)
-  (if (mh-outstanding-commands-p)
-      (if (or mh-do-not-confirm-flag
-              (y-or-n-p
-               "Process outstanding deletes and refiles? "))
-          (mh-process-commands folder)
-        (set-buffer folder)
-        (mh-undo-folder)))
-  (mh-update-unseen)
-  (mh-invalidate-show-buffer))
-
-(defun mh-process-commands (folder)
-  "Process outstanding commands for FOLDER.
-
-This function runs `mh-before-commands-processed-hook' before the
-commands are processed and `mh-after-commands-processed-hook'
-after the commands are processed."
-  (message "Processing deletes and refiles for %s..." folder)
-  (set-buffer folder)
-  (with-mh-folder-updating (nil)
-    ;; Run the before hook -- the refile and delete lists are still valid
-    (run-hooks 'mh-before-commands-processed-hook)
-
-    ;; Update the unseen sequence if it exists
-    (mh-update-unseen)
-
-    (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)
-        (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)))
-                          (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)
-                     ;; Preserve sequences in destination folder...
-                     (when mh-refile-preserves-sequences-flag
-                       (clrhash dest-map)
-                       (loop for i from (1+ (or last 0))
-                             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)
-                            ;; Can't be run in the background, since the
-                            ;; current folder is changed by mark this could
-                            ;; lead to a race condition with the next refile.
-                            (apply #'mh-exec-cmd "mark"
-                                   "-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 ())
-
-      ;; Now delete messages
-      (cond (mh-delete-list
-             (setq redraw-needed-flag t)
-             (apply 'mh-exec-cmd "rmm" folder
-                    (mh-coalesce-msg-list mh-delete-list))
-             (mh-delete-scan-msgs mh-delete-list)
-             (setq mh-delete-list nil)))
-
-      ;; Don't need to remove sequences since delete and refile do so.
-      ;; Mark cur message
-      (if (> (buffer-size) 0)
-          (mh-define-sequence 'cur (list (or (mh-get-msg-num nil) "last"))))
-
-      ;; Redraw folder buffer if needed
-      (when (and redraw-needed-flag)
-        (when (mh-speed-flists-active-p)
-          (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))))
-
-      (and (buffer-file-name (get-buffer mh-show-buffer))
-           (not (file-exists-p (buffer-file-name (get-buffer mh-show-buffer))))
-           ;; If "inc" were to put a new msg in this file,
-           ;; we would not notice, so mark it invalid now.
-           (mh-invalidate-show-buffer))
-
-      (setq mh-seq-list (mh-read-folder-sequences mh-current-folder nil))
-      (mh-remove-all-notation)
-      (mh-notate-user-sequences)
-
-      ;; Run the after hook -- now folders-changed is valid,
-      ;; but not the lists of specific messages.
-      (let ((mh-folders-changed folders-changed))
-        (run-hooks 'mh-after-commands-processed-hook)))
-
-    (message "Processing deletes and refiles for %s...done" folder)))
-
-(defun mh-update-unseen ()
-  "Synchronize the unseen sequence with MH.
-Return non-nil iff the MH folder was set.
-The hook `mh-unseen-updated-hook' is called after the unseen sequence
-is updated."
-  (if mh-seen-list
-      (let* ((unseen-seq (mh-find-seq mh-unseen-seq))
-             (unseen-msgs (mh-seq-msgs unseen-seq)))
-        (if unseen-msgs
-            (progn
-              (mh-undefine-sequence mh-unseen-seq mh-seen-list)
-              (run-hooks 'mh-unseen-updated-hook)
-              (while mh-seen-list
-                (setq unseen-msgs (delq (car mh-seen-list) unseen-msgs))
-                (setq mh-seen-list (cdr mh-seen-list)))
-              (setcdr unseen-seq unseen-msgs)
-              t)                        ;since we set the folder
-          (setq mh-seen-list nil)))))
+;;; MH-E Customization
 
-(defun mh-delete-scan-msgs (msgs)
-  "Delete the scan listing lines for MSGS."
-  (save-excursion
-    (while msgs
-      (when (mh-goto-msg (car msgs) t t)
-        (when (memq 'unthread mh-view-ops)
-          (mh-thread-forget-message (car msgs)))
-        (mh-delete-line 1))
-      (setq msgs (cdr msgs)))))
+;; All of the defgroups, defcustoms, and deffaces in MH-E are found
+;; here. This makes it possible to customize modules that aren't
+;; loaded yet. It also makes it easier to organize the customization
+;; groups.
 
-(defun mh-outstanding-commands-p ()
-  "Return non-nil if there are outstanding deletes or refiles."
-  (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.
-This is the inverse of `mh-read-msg-list', which expands ranges.
-Message lists passed to MH programs should be processed by this
-function to avoid exceeding system command line argument limits."
-  (let ((msgs (sort (copy-sequence messages) 'mh-greaterp))
-        (range-high nil)
-        (prev -1)
-        (ranges nil))
-    (while prev
-      (if range-high
-          (if (or (not (numberp prev))
-                  (not (equal (car msgs) (1- prev))))
-              (progn                    ;non-sequential, flush old range
-                (if (eq prev range-high)
-                    (setq ranges (cons range-high ranges))
-                  (setq ranges (cons (format "%s-%s" prev range-high) ranges)))
-                (setq range-high nil))))
-      (or range-high
-          (setq range-high (car msgs))) ;start new or first range
-      (setq prev (car msgs))
-      (setq msgs (cdr msgs)))
-    ranges))
-
-(defun mh-greaterp (msg1 msg2)
-  "Return the greater of two message indicators MSG1 and MSG2.
-Strings are \"smaller\" than numbers.
-Valid values are things like \"cur\", \"last\", 1, and 1820."
-  (if (numberp msg1)
-      (if (numberp msg2)
-          (> msg1 msg2)
-        t)
-    (if (numberp msg2)
-        nil
-      (string-lessp msg2 msg1))))
-
-(defun mh-lessp (msg1 msg2)
-  "Return the lesser of two message indicators MSG1 and MSG2.
-Strings are \"smaller\" than numbers.
-Valid values are things like \"cur\", \"last\", 1, and 1820."
-  (not (mh-greaterp msg1 msg2)))
-
-
-
-;;; Basic sequence handling
-
-(defun mh-delete-seq-locally (seq)
-  "Remove MH-E's record of SEQ."
-  (let ((entry (mh-find-seq seq)))
-    (setq mh-seq-list (delq entry mh-seq-list))))
-
-(defun mh-read-folder-sequences (folder save-refiles)
-  "Read and return the predefined sequences for a FOLDER.
-If SAVE-REFILES is non-nil, then keep the sequences
-that note messages to be refiled."
-  (let ((seqs ()))
-    (cond (save-refiles
-           (mh-mapc (function (lambda (seq) ; Save the refiling sequences
-                                (if (mh-folder-name-p (mh-seq-name seq))
-                                    (setq seqs (cons seq seqs)))))
-                    mh-seq-list)))
-    (save-excursion
-      (if (eq 0 (mh-exec-cmd-quiet nil "mark" folder "-list"))
-          (progn
-            ;; look for name in line of form "cur: 4" or "myseq (private): 23"
-            (while (re-search-forward "^[^: ]+" nil t)
-              (setq seqs (cons (mh-make-seq (intern (buffer-substring
-                                                     (match-beginning 0)
-                                                     (match-end 0)))
-                                            (mh-read-msg-list))
-                               seqs)))
-            (delete-region (point-min) (point))))) ; avoid race with
-                                        ; mh-process-daemon
-    seqs))
-
-(defun mh-read-msg-list ()
-  "Return a list of message numbers from point to the end of the line.
-Expands ranges into set of individual numbers."
-  (let ((msgs ())
-        (end-of-line (save-excursion (end-of-line) (point)))
-        num)
-    (while (re-search-forward "[0-9]+" end-of-line t)
-      (setq num (string-to-number (buffer-substring (match-beginning 0)
-                                                    (match-end 0))))
-      (cond ((looking-at "-")           ; Message range
-             (forward-char 1)
-             (re-search-forward "[0-9]+" end-of-line t)
-             (let ((num2 (string-to-number
-                          (buffer-substring (match-beginning 0)
-                                            (match-end 0)))))
-               (if (< num2 num)
-                   (error "Bad message range: %d-%d" num num2))
-               (while (<= num num2)
-                 (setq msgs (cons num msgs))
-                 (setq num (1+ num)))))
-            ((not (zerop num))          ;"pick" outputs "0" to mean no match
-             (setq msgs (cons num msgs)))))
-    msgs))
-
-(defun mh-notate-user-sequences (&optional range)
-  "Mark user-defined sequences in RANGE.
-
-Check the documentation of `mh-interactive-range' to see how
-RANGE is read in interactive use; 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)))
-    (dolist (seq seqs)
-      (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 mh-internal-seqs)
-      (eq name mh-unseen-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-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.
-
-In a program, non-nil INTERNAL-FLAG 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))
-        (user-sequence-flag (not (mh-internal-seq sequence)))
-        (folders-changed (list mh-current-folder))
-        (msg-list ()))
-    (when entry
-      (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))
-        (apply #'mh-speed-flists t folders-changed)))))
-
-(defun mh-catchup (range)
-  "Delete RANGE from the \"unseen\" sequence.
-
-Check the documentation 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.
-If INTERNAL-FLAG is non-nil, then do not inform MH of the
-change."
-  (let ((entry (mh-find-seq sequence)))
-    (when (and entry (memq msg (mh-seq-msgs entry)))
-      (if (not internal-flag)
-          (mh-undefine-sequence sequence (list msg)))
-      (setcdr entry (delq msg (mh-seq-msgs entry))))))
-
-(defun mh-undefine-sequence (seq msgs)
-  "Remove from the SEQ the list of MSGS."
-  (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 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-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."
-  (let ((l mh-seq-list)
-        (seqs ()))
-    (while l
-      (and (memq msg (mh-seq-msgs (car l)))
-           (or include-internal-flag
-               (not (mh-internal-seq (mh-seq-name (car l)))))
-           (setq seqs (cons (mh-seq-name (car l)) seqs)))
-      (setq l (cdr l)))
-    seqs))
+;; This section contains the following sub-sections:
+
+;; 1. MH-E Customization Groups
+
+;;    These are the customization group definitions. Every group has a
+;;    associated manual node. The ordering is alphabetical, except for
+;;    the groups mh-faces and mh-hooks which are last .
+
+;; 2. MH-E Customization
+
+;;    These are the actual customization variables. There is a
+;;    sub-section for each group in the MH-E Customization Groups
+;;    section, in the same order, separated by page breaks. Within
+;;    each section, variables are sorted alphabetically.
+
+;; 3. Hooks
+
+;;    All hooks must be placed in the mh-hook group; in addition, add
+;;    the group associated with the manual node in which the hook is
+;;    described. Since the mh-hook group appears near the end of this
+;;    section, the hooks will appear at the end of these other groups.
+
+;; 4. Faces
+
+;;    All faces must be placed in the mh-faces group; in addition, add
+;;    the group associated with the manual node in which the face is
+;;    described. Since the mh-faces group appears near the end of this
+;;    section, the faces will appear at the end of these other groups.
+
+(defun mh-customize (&optional delete-other-windows-flag)
+  "Customize MH-E variables.
+If optional argument DELETE-OTHER-WINDOWS-FLAG is non-nil, other
+windows in the frame are removed."
+  (interactive "P")
+  (customize-group 'mh-e)
+  (when delete-other-windows-flag
+    (delete-other-windows)))
+
+
+
+;;; MH-E Customization Groups
+
+(defgroup mh-e nil
+  "Emacs interface to the MH mail system.
+MH is the Rand Mail Handler. Other implementations include nmh
+and GNU mailutils."
+  :link '(custom-manual "(mh-e)Top")
+  :group 'mail)
+
+(defgroup mh-alias nil
+  "Aliases."
+  :link '(custom-manual "(mh-e)Aliases")
+  :prefix "mh-alias-"
+  :group 'mh-e)
+
+(defgroup mh-folder nil
+  "Organizing your mail with folders."
+  :prefix "mh-"
+  :link '(custom-manual "(mh-e)Folders")
+  :group 'mh-e)
+
+(defgroup mh-folder-selection nil
+  "Folder selection."
+  :prefix "mh-"
+  :link '(custom-manual "(mh-e)Folder Selection")
+  :group 'mh-e)
+
+(defgroup mh-identity nil
+  "Identities."
+  :link '(custom-manual "(mh-e)Identities")
+  :prefix "mh-identity-"
+  :group 'mh-e)
+
+(defgroup mh-inc nil
+  "Incorporating your mail."
+  :prefix "mh-inc-"
+  :link '(custom-manual "(mh-e)Incorporating Mail")
+  :group 'mh-e)
+
+(defgroup mh-junk nil
+  "Dealing with junk mail."
+  :link '(custom-manual "(mh-e)Junk")
+  :prefix "mh-junk-"
+  :group 'mh-e)
+
+(defgroup mh-letter nil
+  "Editing a draft."
+  :prefix "mh-"
+  :link '(custom-manual "(mh-e)Editing Drafts")
+  :group 'mh-e)
+
+(defgroup mh-ranges nil
+  "Ranges."
+  :prefix "mh-"
+  :link '(custom-manual "(mh-e)Ranges")
+  :group 'mh-e)
+
+(defgroup mh-scan-line-formats nil
+  "Scan line formats."
+  :link '(custom-manual "(mh-e)Scan Line Formats")
+  :prefix "mh-"
+  :group 'mh-e)
+
+(defgroup mh-search nil
+  "Searching."
+  :link '(custom-manual "(mh-e)Searching")
+  :prefix "mh-search-"
+  :group 'mh-e)
+
+(defgroup mh-sending-mail nil
+  "Sending mail."
+  :prefix "mh-"
+  :link '(custom-manual "(mh-e)Sending Mail")
+  :group 'mh-e)
+
+(defgroup mh-sequences nil
+  "Sequences."
+  :prefix "mh-"
+  :link '(custom-manual "(mh-e)Sequences")
+  :group 'mh-e)
+
+(defgroup mh-show nil
+  "Reading your mail."
+  :prefix "mh-"
+  :link '(custom-manual "(mh-e)Reading Mail")
+  :group 'mh-e)
+
+(defgroup mh-speedbar nil
+  "The speedbar."
+  :prefix "mh-speed-"
+  :link '(custom-manual "(mh-e)Speedbar")
+  :group 'mh-e)
+
+(defgroup mh-thread nil
+  "Threading."
+  :prefix "mh-thread-"
+  :link '(custom-manual "(mh-e)Threading")
+  :group 'mh-e)
+
+(defgroup mh-tool-bar nil
+  "The tool bar"
+  :link '(custom-manual "(mh-e)Tool Bar")
+  :prefix "mh-"
+  :group 'mh-e)
+
+(defgroup mh-hooks nil
+  "MH-E hooks."
+  :link '(custom-manual "(mh-e)Top")
+  :prefix "mh-"
+  :group 'mh-e)
+
+(defgroup mh-faces nil
+  "Faces used in MH-E."
+  :link '(custom-manual "(mh-e)Top")
+  :prefix "mh-"
+  :group 'faces
+  :group 'mh-e)
+
+
+
+;;; Emacs Interface to the MH Mail System (:group mh-e)
+
+;; See Variant Support, above.
+
+;;; Aliases (:group 'mh-alias)
+
+(defcustom mh-alias-completion-ignore-case-flag t
+  "*Non-nil means don't consider case significant in MH alias completion.
+
+As MH ignores case in the aliases, so too does MH-E. However, you
+may turn off this option to make case significant which can be
+used to segregate completion of your aliases. You might use
+lowercase for mailing lists and uppercase for people."
+  :type 'boolean
+  :group 'mh-alias)
+
+(defcustom mh-alias-expand-aliases-flag nil
+  "*Non-nil means to expand aliases entered in the minibuffer.
+
+In other words, aliases entered in the minibuffer will be
+expanded to the full address in the message draft. By default,
+this expansion is not performed."
+  :type 'boolean
+  :group 'mh-alias)
+
+(defcustom mh-alias-flash-on-comma t
+  "*Specify whether to flash address or warn on translation.
+
+This option controls the behavior when a [comma] is pressed while
+entering aliases or addresses. The default setting flashes the
+address associated with an address in the minibuffer briefly, but
+does not display a warning if the alias is not found."
+  :type '(choice (const :tag "Flash but Don't Warn If No Alias" t)
+                 (const :tag "Flash and Warn If No Alias" 1)
+                 (const :tag "Don't Flash Nor Warn If No Alias" nil))
+  :group 'mh-alias)
+
+(defcustom mh-alias-insert-file nil
+  "*Filename used to store a new MH-E alias.
+
+The default setting of this option is \"Use Aliasfile Profile
+Component\". This option can also hold the name of a file or a
+list a file names. If this option is set to a list of file names,
+or the \"Aliasfile:\" profile component contains more than one file
+name, MH-E will prompt for one of them when MH-E adds an alias."
+  :type '(choice (const :tag "Use Aliasfile Profile Component" nil)
+                 (file :tag "Alias File")
+                 (repeat :tag "List of Alias Files" file))
+  :group 'mh-alias)
+
+(defcustom mh-alias-insertion-location 'sorted
+  "Specifies where new aliases are entered in alias files.
+
+This option is set to \"Alphabetical\" by default. If you organize
+your alias file in other ways, then adding aliases to the \"Top\"
+or \"Bottom\" of your alias file might be more appropriate."
+  :type '(choice (const :tag "Alphabetical" sorted)
+                 (const :tag "Top" top)
+                 (const :tag "Bottom" bottom))
+  :group 'mh-alias)
+
+(defcustom mh-alias-local-users t
+  "*If on, local users are added to alias completion.
+
+Aliases are created from \"/etc/passwd\" entries with a user ID
+larger than a magical number, typically 200. This can be a handy
+tool on a machine where you and co-workers exchange messages.
+These aliases have the form \"local.first.last\" if a real name is
+present in the password file. Otherwise, the alias will have the
+form \"local.login\".
+
+If you're on a system with thousands of users you don't know, and
+the loading of local aliases slows MH-E down noticeably, then
+turn this option off.
+
+This option also takes a string which is executed to generate the
+password file. For example, use \"ypcat passwd\" to obtain the
+NIS password file."
+  :type '(choice (boolean) (string))
+  :group 'mh-alias)
+
+(defcustom mh-alias-local-users-prefix "local."
+  "*String prefixed to the real names of users from the password file.
+This option can also be set to \"Use Login\".
+
+For example, consider the following password file entry:
+
+    psg:x:1000:1000:Peter S Galbraith,,,:/home/psg:/bin/tcsh
+
+The following settings of this option will produce the associated
+aliases:
+
+    \"local.\"                  local.peter.galbraith
+    \"\"                        peter.galbraith
+    Use Login                   psg
+
+This option has no effect if variable `mh-alias-local-users' is
+turned off."
+  :type '(choice (const :tag "Use Login" nil)
+                 (string))
+  :group 'mh-alias)
+
+(defcustom mh-alias-passwd-gecos-comma-separator-flag t
+  "*Non-nil means the gecos field in the password file uses a comma separator.
+
+In the example in `mh-alias-local-users-prefix', commas are used
+to separate different values within the so-called gecos field.
+This is a fairly common usage. However, in the rare case that the
+gecos field in your password file is not separated by commas and
+whose contents may contain commas, you can turn this option off."
+  :type 'boolean
+  :group 'mh-alias)
+
+
+
+;;; Organizing Your Mail with Folders (:group 'mh-folder)
+
+(defcustom mh-new-messages-folders t
+  "Folders searched for the \"unseen\" sequence.
+
+Set this option to \"Inbox\" to search the \"+inbox\" folder or
+\"All\" to search all of the top level folders. Otherwise, list
+the folders that should be searched with the \"Choose Folders\"
+menu item.
+
+See also `mh-recursive-folders-flag'."
+  :type '(choice (const :tag "Inbox" t)
+                 (const :tag "All" nil)
+                 (repeat :tag "Choose Folders" (string :tag "Folder")))
+  :group 'mh-folder)
+
+(defcustom mh-ticked-messages-folders t
+  "Folders searched for `mh-tick-seq'.
+
+Set this option to \"Inbox\" to search the \"+inbox\" folder or
+\"All\" to search all of the top level folders. Otherwise, list
+the folders that should be searched with the \"Choose Folders\"
+menu item.
+
+See also `mh-recursive-folders-flag'."
+  :type '(choice (const :tag "Inbox" t)
+                 (const :tag "All" nil)
+                 (repeat :tag "Choose Folders" (string :tag "Folder")))
+  :group 'mh-folder)
+
+(defcustom mh-large-folder 200
+  "The number of messages that indicates a large folder.
+
+If a folder is deemed to be large, that is the number of messages
+in it exceed this value, then confirmation is needed when it is
+visited. Even when `mh-show-threads-flag' is non-nil, the folder
+is not automatically threaded, if it is large. If set to nil all
+folders are treated as if they are small."
+  :type '(choice (const :tag "No Limit") integer)
+  :group 'mh-folder)
+
+(defcustom mh-recenter-summary-flag nil
+  "*Non-nil means to recenter the summary window.
+
+If this option is turned on, recenter the summary window when the
+show window is toggled off."
+  :type 'boolean
+  :group 'mh-folder)
+
+(defcustom mh-recursive-folders-flag nil
+  "*Non-nil means that commands which operate on folders do so recursively."
+  :type 'boolean
+  :group 'mh-folder)
+
+(defcustom mh-sortm-args nil
+  "*Additional arguments for \"sortm\"\\<mh-folder-mode-map>.
+
+This option is consulted when a prefix argument is used with
+\\[mh-sort-folder]. Normally default arguments to \"sortm\" are
+specified in the MH profile. This option may be used to provide
+an alternate view. For example, \"'(\"-nolimit\" \"-textfield\"
+\"subject\")\" is a useful setting."
+  :type 'string
+  :group 'mh-folder)
+
+
+
+;;; Folder Selection (:group 'mh-folder-selection)
+
+(defcustom mh-default-folder-for-message-function nil
+  "Function to select a default folder for refiling or \"Fcc:\".
+
+The current buffer is set to the message being refiled with point
+at the start of the message. This function should return the
+default folder as a string with a leading \"+\" sign. It can also
+return nil so that the last folder name is used as the default,
+or an empty string to suppress the default entirely."
+  :type 'function
+  :group 'mh-folder-selection)
+
+(defcustom mh-default-folder-list nil
+  "*List of addresses and folders.
+
+The folder name associated with the first address found in this
+list is used as the default for `mh-refile-msg' and similar
+functions. 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.
+
+See `mh-prompt-for-refile-folder' and `mh-folder-from-address'
+for more information."
+  :type '(repeat (list (regexp :tag "Address")
+                       (string :tag "Folder")
+                       (boolean :tag "Check Recipient")))
+  :group 'mh-folder-selection)
+
+(defcustom mh-default-folder-must-exist-flag t
+  "*Non-nil means guessed folder name must exist to be used.
+
+If the derived folder does not exist, and this option is on, then
+the last folder name used is suggested. This is useful if you get
+mail from various people for whom you have an alias, but file
+them all in the same project folder.
+
+See `mh-prompt-for-refile-folder' and `mh-folder-from-address'
+for more information."
+  :type 'boolean
+  :group 'mh-folder-selection)
+
+(defcustom mh-default-folder-prefix ""
+  "*Prefix used for folder names generated from aliases.
+The prefix is used to prevent clutter in your mail directory.
+
+See `mh-prompt-for-refile-folder' and `mh-folder-from-address'
+for more information."
+  :type 'string
+  :group 'mh-folder-selection)
+
+
+
+;;; Identities (:group 'mh-identity)
+
+(eval-and-compile
+  (unless (fboundp 'mh-identity-make-menu-no-autoload)
+    (defun mh-identity-make-menu-no-autoload ()
+      "Temporary definition.
+Real definition will take effect when mh-identity is loaded."
+      nil)))
+
+(defcustom mh-identity-list nil
+  "*List of identities.
+
+To customize this option, click on the \"INS\" button and enter a label
+such as \"Home\" or \"Work\". Then click on the \"INS\" button with the
+label \"Add at least one item below\". Then choose one of the items in
+the \"Value Menu\".
+
+You can specify an alternate \"From:\" header field using the \"From
+Field\" menu item. You must include a valid email address. A standard
+format is \"First Last <login@@host.domain>\". If you use an initial
+with a period, then you must quote your name as in '\"First I. Last\"
+<login@@host.domain>'. People usually list the name of the company
+where they work using the \"Organization Field\" menu item. Set any
+arbitrary header field and value in the \"Other Field\" menu item.
+Unless the header field is a standard one, precede the name of your
+field's label with \"X-\", as in \"X-Fruit-of-the-Day:\". The value of
+\"Attribution Verb\" overrides the setting of
+`mh-extract-from-attribution-verb'. Set your signature with the
+\"Signature\" menu item. You can specify the contents of
+`mh-signature-file-name', a file, or a function. Specify a different
+key to sign or encrypt messages with the \"GPG Key ID\" menu item.
+
+You can select the identities you have added via the menu called
+\"Identity\" in the MH-Letter buffer. You can also use
+\\[mh-insert-identity]. To clear the fields and signature added by the
+identity, select the \"None\" identity.
+
+The \"Identity\" menu contains two other items to save you from having
+to set the identity on every message. The menu item \"Set Default for
+Session\" can be used to set the default identity to the current
+identity until you exit Emacs. The menu item \"Save as Default\" sets
+the option `mh-identity-default' to the current identity setting. You
+can also customize the `mh-identity-default' option in the usual
+fashion."
+  :type '(repeat (list :tag ""
+                       (string :tag "Label")
+                       (repeat :tag "Add at least one item below"
+                               (choice
+                                (cons :tag "From Field"
+                                      (const "From")
+                                      (string :tag "Value"))
+                                (cons :tag "Organization Field"
+                                      (const "Organization")
+                                      (string :tag "Value"))
+                                (cons :tag "Other Field"
+                                      (string :tag "Field")
+                                      (string :tag "Value"))
+                                (cons :tag "Attribution Verb"
+                                      (const ":attribution-verb")
+                                      (string :tag "Value"))
+                                (cons :tag "Signature"
+                                      (const :tag "Signature"
+                                             ":signature")
+                                      (choice
+                                       (const :tag "mh-signature-file-name"
+                                              nil)
+                                       (file)
+                                       (function)))
+                                (cons :tag "GPG Key ID"
+                                      (const :tag "GPG Key ID"
+                                             ":pgg-default-user-id")
+                                      (string :tag "Value"))))))
+  :set (lambda (symbol value)
+         (set-default symbol value)
+         (mh-identity-make-menu-no-autoload))
+  :group 'mh-identity)
+
+(defcustom mh-auto-fields-list nil
+  "List of recipients for which header lines are automatically inserted.
+
+This option can be used to set the identity depending on the
+recipient. To customize this option, click on the \"INS\" button and
+enter a regular expression for the recipient's address. Click on the
+\"INS\" button with the \"Add at least one item below\" label. Then choose
+one of the items in the \"Value Menu\".
+
+The \"Identity\" menu item is used to select an identity from those
+configured in `mh-identity-list'. All of the information for that
+identity will be added if the recipient matches. The \"Fcc Field\" menu
+item is used to select a folder that is used in the \"Fcc:\" header.
+When you send the message, MH will put a copy of your message in this
+folder. The \"Mail-Followup-To Field\" menu item is used to insert an
+\"Mail-Followup-To:\" header field with the recipients you provide. If
+the recipient's mail user agent supports this header field (as nmh
+does), then their replies will go to the addresses listed. This is
+useful if their replies go both to the list and to you and you don't
+have a mechanism to suppress duplicates. If you reply to someone not
+on the list, you must either remove the \"Mail-Followup-To:\" field, or
+ensure the recipient is also listed there so that he receives replies
+to your reply. Other header fields may be added using the \"Other
+Field\" menu item.
+
+These fields can only be added after the recipient is known. Once the
+header contains one or more recipients, run the
+\\[mh-insert-auto-fields] command or choose the \"Identity -> Insert
+Auto Fields\" menu item to insert these fields manually. However, you
+can just send the message and the fields will be added automatically.
+You are given a chance to see these fields and to confirm them before
+the message is actually sent. You can do away with this confirmation
+by turning off the option `mh-auto-fields-prompt-flag'.
+
+You should avoid using the same header field in `mh-auto-fields-list'
+and `mh-identity-list' definitions that may apply to the same message
+as the result is undefined."
+  :type `(repeat
+          (list :tag ""
+                (string :tag "Recipient")
+                (repeat :tag "Add at least one item below"
+                        (choice
+                         (cons :tag "Identity"
+                               (const ":identity")
+                               ,(append
+                                 '(radio)
+                                 (mapcar
+                                  (function (lambda (arg) `(const ,arg)))
+                                  (mapcar 'car mh-identity-list))))
+                         (cons :tag "Fcc Field"
+                               (const "fcc")
+                               (string :tag "Value"))
+                         (cons :tag "Mail-Followup-To Field"
+                               (const "Mail-Followup-To")
+                               (string :tag "Value"))
+                         (cons :tag "Other Field"
+                                 (string :tag "Field")
+                                 (string :tag "Value"))))))
+  :group 'mh-identity)
+
+(defcustom mh-auto-fields-prompt-flag t
+  "*Non-nil means to prompt before sending if fields inserted.
+See `mh-auto-fields-list'."
+  :type 'boolean
+  :group 'mh-identity)
+
+(defcustom mh-identity-default nil
+  "Default identity to use when `mh-letter-mode' is called.
+See `mh-identity-list'."
+  :type (append
+         '(radio)
+         (cons '(const :tag "None" nil)
+               (mapcar (function (lambda (arg) `(const ,arg)))
+                       (mapcar 'car mh-identity-list))))
+  :group 'mh-identity)
+
+(defcustom mh-identity-handlers
+  '(("From" . mh-identity-handler-top)
+    (":default" . mh-identity-handler-bottom)
+    (":attribution-verb" . mh-identity-handler-attribution-verb)
+    (":signature" . mh-identity-handler-signature)
+    (":pgg-default-user-id" . mh-identity-handler-gpg-identity))
+  "Handler functions for fields in `mh-identity-list'.
+
+This option is used to change the way that fields, signatures,
+and attributions in `mh-identity-list' are added. To customize
+`mh-identity-handlers', replace the name of an existing handler
+function associated with the field you want to change with the
+name of a function you have written. You can also click on an
+\"INS\" button and insert a field of your choice and the name of
+the function you have written to handle it.
+
+The \"Field\" field can be any field that you've used in your
+`mh-identity-list'. The special fields \":attribution-verb\",
+\":signature\", or \":pgg-default-user-id\" are used for the
+`mh-identity-list' choices \"Attribution Verb\", \"Signature\", and
+\"GPG Key ID\" respectively.
+
+The handler associated with the \":default\" field is used when no
+other field matches.
+
+The handler functions are passed two or three arguments: the
+FIELD itself (for example, \"From\"), or one of the special
+fields (for example, \":signature\"), and the ACTION 'remove or
+'add. If the action is 'add, an additional argument
+containing the VALUE for the field is given."
+  :type '(repeat (cons (string :tag "Field") function))
+  :group 'mh-identity)
+
+
+
+;;; Incorporating Your Mail (:group 'mh-inc)
+
+(defcustom mh-inc-prog "inc"
+  "*Program to incorporate new mail into a folder.
+
+This program generates a one-line summary for each of the new
+messages. Unless it is an absolute pathname, the file is assumed
+to be in the `mh-progs' directory. You may also link a file to
+\"inc\" that uses a different format. You'll then need to modify
+several scan line format variables appropriately."
+  :type 'string
+  :group 'mh-inc)
+
+(eval-and-compile
+  (unless (fboundp 'mh-inc-spool-make-no-autoload)
+    (defun mh-inc-spool-make-no-autoload ()
+      "Temporary definition.
+Real definition will take effect when mh-inc is loaded."
+      nil)))
+
+(defcustom mh-inc-spool-list nil
+  "*Alternate spool files.
+
+You can use the `mh-inc-spool-list' variable to direct MH-E to
+retrieve mail from arbitrary spool files other than your system
+mailbox, file it in folders other than your \"+inbox\", and assign
+key bindings to incorporate this mail.
+
+Suppose you are subscribed to the \"mh-e-devel\" mailing list and
+you use \"procmail\" to filter this mail into \"~/mail/mh-e\" with
+the following recipe in \".procmailrc\":
+
+    MAILDIR=$HOME/mail
+    :0:
+    * ^From address@hidden
+    mh-e
+
+In order to incorporate \"~/mail/mh-e\" into \"+mh-e\" with an
+\"I m\" (mh-inc-spool-mh-e) command, customize this option, and click
+on the \"INS\" button. Enter a \"Spool File\" of \"~/mail/mh-e\", a
+\"Folder\" of \"mh-e\", and a \"Key Binding\" of \"m\".
+
+You can use \"xbuffy\" to automate the incorporation of this mail
+using the \"gnudoit\" command in the \"gnuserv\" package as follows:
+
+    box ~/mail/mh-e
+        title mh-e
+        origMode
+        polltime 10
+        headertime 0
+        command gnudoit -q '(mh-inc-spool-mh-e)'"
+  :type '(repeat (list (file :tag "Spool File")
+                       (string :tag "Folder")
+                       (character :tag "Key Binding")))
+  :set (lambda (symbol value)
+         (set-default symbol value)
+         (mh-inc-spool-make-no-autoload))
+  :group 'mh-inc)
+
+
+
+;;; Dealing with Junk Mail (:group 'mh-junk)
+
+(defvar mh-junk-choice nil
+  "Chosen spam fighting program.")
+
+;; Available spam filter interfaces
+(defvar mh-junk-function-alist
+  '((spamassassin mh-spamassassin-blacklist mh-spamassassin-whitelist)
+    (bogofilter mh-bogofilter-blacklist mh-bogofilter-whitelist)
+    (spamprobe mh-spamprobe-blacklist mh-spamprobe-whitelist))
+  "Available choices of spam programs to use.
+
+This is an alist. For each element there are functions that
+blacklist a message as spam and whitelist a message incorrectly
+classified as spam.")
+
+(defun mh-junk-choose (symbol value)
+  "Choose spam program to use.
+
+The function is always called with SYMBOL bound to
+`mh-junk-program' and VALUE bound to the new value of
+`mh-junk-program'. The function sets the variable
+`mh-junk-choice' in addition to `mh-junk-program'."
+  (set symbol value)                    ;XXX shouldn't this be set-default?
+  (setq mh-junk-choice
+        (or value
+            (loop for element in mh-junk-function-alist
+                  until (executable-find (symbol-name (car element)))
+                  finally return (car element)))))
+
+(defcustom mh-junk-background nil
+  "If on, spam programs are run in background.
+
+By default, the programs are run in the foreground, but this can
+be slow when junking large numbers of messages. If you have
+enough memory or don't junk that many messages at the same time,
+you might try turning on this option."
+  :type '(choice (const :tag "Off" nil)
+                 (const :tag "On" 0))
+  :group 'mh-junk)
+
+(defcustom mh-junk-disposition nil
+  "Disposition of junk mail."
+  :type '(choice (const :tag "Delete Spam" nil)
+                 (string :tag "Spam Folder"))
+  :group 'mh-junk)
+
+(defcustom mh-junk-program nil
+  "Spam program that MH-E should use.
+
+The default setting of this option is \"Auto-detect\" which means
+that MH-E will automatically choose one of SpamAssassin,
+bogofilter, or SpamProbe in that order. If, for example, you have
+both SpamAssassin and bogofilter installed and you want to use
+bogofilter, then you can set this option to \"Bogofilter\"."
+  :type '(choice (const :tag "Auto-detect" nil)
+                 (const :tag "SpamAssassin" spamassassin)
+                 (const :tag "Bogofilter" bogofilter)
+                 (const :tag "SpamProbe" spamprobe))
+  :set 'mh-junk-choose
+  :group 'mh-junk)
+
+
+
+;;; Editing a Draft (:group 'mh-letter)
+
+(defcustom mh-compose-insertion (if (locate-library "mml") 'mml 'mh)
+  "Type of tags used when composing MIME messages.
+
+In addition to MH-style directives, MH-E also supports MML (MIME
+Meta Language) tags. (see Info node `(emacs-mime)Composing').
+This option can be used to choose between them. By default, this
+option is set to \"MML\" if it is supported since it provides a
+lot more functionality. This option can also be set to \"MH\" if
+MH-style directives are preferred."
+  :type '(choice (const :tag "MML" mml)
+                 (const :tag "MH"  mh))
+  :group 'mh-letter)
+
+(defcustom mh-compose-skipped-header-fields
+  '("From" "Organization" "References" "In-Reply-To"
+    "X-Face" "Face" "X-Image-URL" "X-Mailer")
+  "List of header fields to skip over when navigating in draft."
+  :type '(repeat (string :tag "Field"))
+  :group 'mh-letter)
+
+(defcustom mh-compose-space-does-completion-flag nil
+  "*Non-nil means \\<mh-letter-mode-map>\\[mh-letter-complete-or-space] does 
completion in message header."
+  :type 'boolean
+  :group 'mh-letter)
+
+(defcustom mh-delete-yanked-msg-window-flag nil
+  "*Non-nil means delete any window displaying the message.
+
+This deletes the window containing the original message after
+yanking it with \\<mh-letter-mode-map>\\[mh-yank-cur-msg] to make
+more room on your screen for your reply."
+  :type 'boolean
+  :group 'mh-letter)
+
+(defcustom mh-extract-from-attribution-verb "wrote:"
+  "*Verb to use for attribution when a message is yanked by 
\\<mh-letter-mode-map>\\[mh-yank-cur-msg].
+
+The attribution consists of the sender's name and email address
+followed by the content of this option. This option can be set to
+\"wrote:\", \"a écrit:\", and \"schrieb:\". You can also use the
+\"Custom String\" menu item to enter your own verb."
+  :type '(choice (const "wrote:")
+                 (const "a écrit:")
+                 (const "schrieb:")
+                 (string :tag "Custom String"))
+  :group 'mh-letter)
+
+(defcustom mh-ins-buf-prefix "> "
+  "*String to put before each line of a yanked or inserted message.
+
+The prefix \"> \" is the default setting of this option. I
+suggest that you not modify this option since it is used by many
+mailers and news readers: messages are far easier to read if
+several included messages have all been indented by the same
+string.
+
+This prefix is not inserted if you use one of the supercite
+flavors of `mh-yank-behavior' or you have added a
+`mail-citation-hook'."
+  :type 'string
+  :group 'mh-letter)
+
+(defcustom mh-letter-complete-function 'ispell-complete-word
+  "*Function to call when completing outside of address or folder fields.
+
+In the body of the message,
+\\<mh-letter-mode-map>\\[mh-letter-complete] runs this function,
+which is set to \"ispell-complete-word\" by default."
+  :type '(choice function (const nil))
+  :group 'mh-letter)
+
+(defcustom mh-letter-fill-column 72
+  "*Fill column to use in MH Letter mode.
+
+By default, this option is 72 to allow others to quote your
+message without line wrapping."
+  :type 'integer
+  :group 'mh-letter)
+
+(defcustom mh-mml-method-default (if mh-pgp-support-flag "pgpmime" "none")
+  "Default method to use in security tags.
+
+This option is used to select between a variety of mail security
+mechanisms. The default is \"PGP (MIME)\" if it is supported\;
+otherwise, the default is \"None\". Other mechanisms include
+vanilla \"PGP\" and \"S/MIME\".
+
+The `pgg' customization group may have some settings which may
+interest you (see Info node `(pgg)').
+
+In particular, I turn on the option `pgg-encrypt-for-me' so that
+all messages I encrypt are encrypted with my public key as well.
+If you keep a copy of all of your outgoing mail with a \"Fcc:\"
+header field, this setting is vital so that you can read the mail
+you write!"
+  :type '(choice (const :tag "PGP (MIME)" "pgpmime")
+                 (const :tag "PGP" "pgp")
+                 (const :tag "S/MIME" "smime")
+                 (const :tag "None" "none"))
+  :group 'mh-letter)
+
+(defcustom mh-signature-file-name "~/.signature"
+  "*Source of user's signature.
+
+By default, the text of your signature is taken from the file
+\"~/.signature\". You can read from other sources by changing this
+option. This file may contain a vCard in which case an attachment is
+added with the vCard.
+
+This option may also be a symbol, in which case that function is
+called. You may not want a signature separator to be added for you;
+instead you may want to insert one yourself. Options that you may find
+useful to do this include `mh-signature-separator' (when inserting a
+signature separator) and `mh-signature-separator-regexp' (for finding
+said separator). The function `mh-signature-separator-p', which
+reports t if the buffer contains a separator, may be useful as well.
+
+The signature is inserted into your message with the command
+\\<mh-letter-mode-map>\\[mh-insert-signature] or with the option
+`mh-identity-list'."
+  :type 'file
+  :group 'mh-letter)
+
+(defcustom mh-signature-separator-flag t
+  "*Non-nil means a signature separator should be inserted.
+
+It is not recommended that you change this option since various
+mail user agents, including MH-E, use the separator to present
+the signature differently, and to suppress the signature when
+replying or yanking a letter into a draft."
+  :type 'boolean
+  :group 'mh-letter)
+
+(defcustom mh-x-face-file "~/.face"
+  "*File containing face header field to insert in outgoing mail.
+
+If the file starts with either of the strings \"X-Face:\", \"Face:\"
+or \"X-Image-URL:\" then the contents are added to the message header
+verbatim. Otherwise it is assumed that the file contains the value of
+the \"X-Face:\" header field.
+
+The \"X-Face:\" header field, which is a low-resolution, black and
+white image, can be generated using the \"compface\" command (see URL
+`ftp://ftp.cs.indiana.edu/pub/faces/compface/compface.tar.Z'). The
+\"Online X-Face Converter\" is a useful resource for quick conversion
+of images into \"X-Face:\" header fields (see URL
+`http://www.dairiki.org/xface/').
+
+Use the \"make-face\" script to convert a JPEG image to the higher
+resolution, color, \"Face:\" header field (see URL
+`http://quimby.gnus.org/circus/face/make-face').
+
+The URL of any image can be used for the \"X-Image-URL:\" field and no
+processing of the image is required.
+
+To prevent the setting of any of these header fields, either set
+`mh-x-face-file' to nil, or simply ensure that the file defined by
+this option doesn't exist."
+  :type 'file
+  :group 'mh-letter)
+
+(defcustom mh-yank-behavior 'attribution
+  "*Controls which part of a message is yanked by 
\\<mh-letter-mode-map>\\[mh-yank-cur-msg].
+
+To include the entire message, including the entire header, use
+\"Body and Header\". Use \"Body\" to yank just the body without
+the header. To yank only the portion of the message following the
+point, set this option to \"Below Point\".
+
+Choose \"Invoke supercite\" to pass the entire message and header
+through supercite.
+
+If the \"Body With Attribution\" setting is used, then the
+message minus the header is yanked and a simple attribution line
+is added at the top using the value of the option
+`mh-extract-from-attribution-verb'. This is the default.
+
+If the \"Invoke supercite\" or \"Body With Attribution\" settings
+are used, the \"-noformat\" argument is passed to the \"repl\"
+program to override a \"-filter\" or \"-format\" argument. These
+settings also have \"Automatically\" variants that perform the
+action automatically when you reply so that you don't need to use
+\\[mh-yank-cur-msg] at all. Note that this automatic action is
+only performed if the show buffer matches the message being
+replied to. People who use the automatic variants tend to turn on
+the option `mh-delete-yanked-msg-window-flag' as well so that the
+show window is never displayed.
+
+If the show buffer has a region, the option `mh-yank-behavior' is
+ignored unless its value is one of Attribution variants in which
+case the attribution is added to the yanked region.
+
+If this option is set to one of the supercite flavors, the hook
+`mail-citation-hook' is ignored and `mh-ins-buf-prefix' is not
+inserted."
+  :type '(choice (const :tag "Body and Header" t)
+                 (const :tag "Body" body)
+                 (const :tag "Below Point" nil)
+                 (const :tag "Invoke supercite" supercite)
+                 (const :tag "Invoke supercite, Automatically" autosupercite)
+                 (const :tag "Body With Attribution" attribution)
+                 (const :tag "Body With Attribution, Automatically"
+                        autoattrib))
+  :group 'mh-letter)
+
+
+
+;;; Ranges (:group 'mh-ranges)
+
+(defcustom mh-interpret-number-as-range-flag t
+  "*Non-nil means interpret a number as a range.
+
+Since one of the most frequent ranges used is \"last:N\", MH-E
+will interpret input such as \"200\" as \"last:200\" if this
+option is on (which is the default). If you need to scan just the
+message 200, then use the range \"200:200\"."
+  :type 'boolean
+  :group 'mh-ranges)
+
+
+
+;;; Scan Line Formats (:group 'mh-scan-line-formats)
+
+(eval-and-compile
+  (unless (fboundp 'mh-adaptive-cmd-note-flag-check)
+    (defun mh-adaptive-cmd-note-flag-check (symbol value)
+      "Temporary definition.
+Real definition, below, uses variables that aren't defined yet."
+      (set-default symbol value))))
+
+(defcustom mh-adaptive-cmd-note-flag t
+  "*Non-nil means that the message number width is determined dynamically.
+
+If you've created your own format to handle long message numbers,
+you'll be pleased to know you no longer need it since MH-E adapts its
+internal format based upon the largest message number if this option
+is on (the default). This option may only be turned on when
+`mh-scan-format-file' is set to \"Use MH-E scan Format\".
+
+If you prefer fixed-width message numbers, turn off this option and
+call `mh-set-cmd-note' with the width specified by your format file
+\(see `mh-scan-format-file'). For example, the default width is 4, so
+you would use \"(mh-set-cmd-note 4)\"."
+  :type 'boolean
+  :group 'mh-scan-line-formats
+  :set 'mh-adaptive-cmd-note-flag-check)
+
+(defun mh-scan-format-file-check (symbol value)
+  "Check if desired setting is legal.
+Throw an error if user tries to set `mh-scan-format-file' to
+anything but t when `mh-adaptive-cmd-note-flag' is on. Otherwise,
+set SYMBOL to VALUE."
+  (if (and (not (eq value t))
+           (eq mh-adaptive-cmd-note-flag t))
+      (error "%s %s" "You must turn off `mh-adaptive-cmd-note-flag'"
+             "unless you use \"Use MH-E scan Format\"")
+    (set-default symbol value)))
+
+(defcustom mh-scan-format-file t
+  "Specifies the format file to pass to the scan program.
+
+The default setting for this option is \"Use MH-E scan Format\". This
+means that the format string will be taken from the either
+`mh-scan-format-mh' or `mh-scan-format-nmh' depending on whether MH or
+nmh (or GNU mailutils) is in use. This setting also enables you to
+turn on the `mh-adaptive-cmd-note-flag' option.
+
+You can also set this option to \"Use Default scan Format\" to get the
+same output as you would get if you ran \"scan\" from the shell. If
+you have a format file that you want MH-E to use but not MH, you can
+set this option to \"Specify a scan Format File\" and enter the name
+of your format file.
+
+If you change the format of the scan lines you'll need to tell MH-E
+how to parse the new format. As you will see, quite a lot of variables
+are involved to do that. Use \"\\[apropos] RET mh-scan.*regexp\" to
+obtain a list of these variables. You will also have to call
+`mh-set-cmd-note' if your notations are not in column 4 (columns in
+Emacs start with 0)."
+  :type '(choice (const :tag "Use MH-E scan Format" t)
+                 (const :tag "Use Default scan Format" nil)
+                 (file  :tag "Specify a scan Format File"))
+  :group 'mh-scan-line-formats
+  :set 'mh-scan-format-file-check)
+
+(defun mh-adaptive-cmd-note-flag-check (symbol value)
+  "Check if desired setting is legal.
+Throw an error if user tries to turn on
+`mh-adaptive-cmd-note-flag' when `mh-scan-format-file' isn't t.
+Otherwise, set SYMBOL to VALUE."
+  (if (and value
+           (not (eq mh-scan-format-file t)))
+      (error "%s %s" "Can't turn on unless `mh-scan-format-file'"
+             "is set to \"Use MH-E scan Format\"")
+    (set-default symbol value)))
+
+(defcustom mh-scan-prog "scan"
+  "*Program used to scan messages.
+
+The name of the program that generates a listing of one line per
+message is held in this option. Unless this variable contains an
+absolute pathname, it is assumed to be in the `mh-progs'
+directory. You may link another program to `scan' (see
+\"mh-profile(5)\") to produce a different type of listing."
+  :type 'string
+  :group 'mh-scan-line-formats)
+(make-variable-buffer-local 'mh-scan-prog)
+
+
+
+;;; Searching (:group 'mh-search)
+
+(defcustom mh-search-program nil
+  "Search program that MH-E shall use.
+
+The default setting of this option is \"Auto-detect\" which means
+that MH-E will automatically choose one of swish++, swish-e,
+mairix, namazu, pick and grep in that order. If, for example, you
+have both swish++ and mairix installed and you want to use
+mairix, then you can set this option to \"mairix\".
+
+More information about setting up an indexing program to use with
+MH-E can be found in the documentation of `mh-search'."
+  :type '(choice (const :tag "Auto-detect" nil)
+                 (const :tag "swish++" swish++)
+                 (const :tag "swish-e" swish)
+                 (const :tag "mairix" mairix)
+                 (const :tag "namazu" namazu)
+                 (const :tag "pick" pick)
+                 (const :tag "grep" grep))
+  :group 'mh-search)
+
+
+
+;;; Sending Mail (:group 'mh-sending-mail)
+
+(defcustom mh-compose-forward-as-mime-flag t
+  "*Non-nil means that messages are forwarded as attachments.
+
+By default, this option is on which means that the forwarded
+messages are included as attachments. If you would prefer to
+forward your messages verbatim (as text, inline), then turn off
+this option. Forwarding messages verbatim works well for short,
+textual messages, but your recipient won't be able to view any
+non-textual attachments that were in the forwarded message. Be
+aware that if you have \"forw: -mime\" in your MH profile, then
+forwarded messages will always be included as attachments
+regardless of the settings of this option."
+  :type 'boolean
+  :group 'mh-sending-mail)
+
+(defcustom mh-compose-letter-function nil
+  "Invoked when starting a new draft.
+
+However, it is the last function called before you edit your
+message. The consequence of this is that you can write a function
+to write and send the message for you. This function is passed
+three arguments: the contents of the TO, SUBJECT, and CC header
+fields."
+  :type '(choice (const nil) function)
+  :group 'mh-sending-mail)
+
+(defcustom mh-compose-prompt-flag nil
+  "*Non-nil means prompt for header fields when composing a new draft."
+  :type 'boolean
+  :group 'mh-sending-mail)
+
+(defcustom mh-forward-subject-format "%s: %s"
+  "*Format string for forwarded message subject.
+
+This option is a string which includes two escapes (\"%s\"). The
+first \"%s\" is replaced with the sender of the original message,
+and the second one is replaced with the original \"Subject:\"."
+  :type 'string
+  :group 'mh-sending-mail)
+
+(defcustom mh-insert-x-mailer-flag t
+  "*Non-nil means append an \"X-Mailer:\" header field to the header.
+
+This header field includes the version of MH-E and Emacs that you
+are using. If you don't want to participate in our marketing, you
+can turn this option off."
+  :type 'boolean
+  :group 'mh-sending-mail)
+
+(defcustom mh-redist-full-contents-flag nil
+  "*Non-nil means the \"dist\" command needs entire letter for redistribution.
+
+This option must be turned on if \"dist\" requires the whole
+letter for redistribution, which is the case if \"send\" is
+compiled with the BERK option (which many people abhor). If you
+find that MH will not allow you to redistribute a message that
+has been redistributed before, turn off this option."
+  :type 'boolean
+  :group 'mh-sending-mail)
+
+(defcustom mh-reply-default-reply-to nil
+  "*Sets the person or persons to whom a reply will be sent.
+
+This option is set to \"Prompt\" by default so that you are
+prompted for the recipient of a reply. If you find that most of
+the time that you specify \"cc\" when you reply to a message, set
+this option to \"cc\". Other choices include \"from\", \"to\", or
+\"all\". You can always edit the recipients in the draft."
+  :type '(choice (const :tag "Prompt" nil)
+                 (const "from")
+                 (const "to")
+                 (const "cc")
+                 (const "all"))
+  :group 'mh-sending-mail)
+
+(defcustom mh-reply-show-message-flag t
+  "*Non-nil means the MH-Show buffer is displayed when replying.
+
+If you include the message automatically, you can hide the
+MH-Show buffer by turning off this option.
+
+See also `mh-reply'."
+  :type 'boolean
+  :group 'mh-sending-mail)
+
+
+
+;;; Sequences (:group 'mh-sequences)
+
+;; If `mh-unpropagated-sequences' becomes a defcustom, add the following to
+;; the docstring: "Additional sequences that should not to be preserved can be
+;; specified by setting `mh-unpropagated-sequences' appropriately." XXX
+
+(defcustom mh-refile-preserves-sequences-flag t
+  "*Non-nil means that sequences are preserved when messages are refiled.
+
+If a message is in any sequence (except \"Previous-Sequence:\"
+and \"cur\") when it is refiled, then it will still be in those
+sequences in the destination folder. If this behavior is not
+desired, then turn off this option."
+  :type 'boolean
+  :group 'mh-sequences)
+
+(defcustom mh-tick-seq 'tick
+  "The name of the MH sequence for ticked messages.
+
+You can customize this option if you already use the \"tick\"
+sequence for your own use. You can also disable all of the
+ticking functions by choosing the \"Disable Ticking\" item but
+there isn't much advantage to that."
+  :type '(choice (const :tag "Disable Ticking" nil)
+                 symbol)
+  :group 'mh-sequences)
+
+(defcustom mh-update-sequences-after-mh-show-flag t
+  "*Non-nil means flush MH sequences to disk after message is 
shown\\<mh-folder-mode-map>.
+
+Three sequences are maintained internally by MH-E and pushed out
+to MH when a message is shown. They include the sequence
+specified by your \"Unseen-Sequence:\" profile entry, \"cur\",
+and the sequence listed by the option `mh-tick-seq' which is
+\"tick\" by default. If you do not like this behavior, turn off
+this option. You can then update the state manually with the
+\\[mh-execute-commands], \\[mh-quit], or \\[mh-update-sequences]
+commands."
+  :type 'boolean
+  :group 'mh-sequences)
+
+
+
+;;; Reading Your Mail (:group 'mh-show)
+
+(defcustom mh-bury-show-buffer-flag t
+  "*Non-nil means show buffer is buried.
+
+One advantage of not burying the show buffer is that one can
+delete the show buffer more easily in an electric buffer list
+because of its proximity to its associated MH-Folder buffer. Try
+running \\[electric-buffer-list] to see what I mean."
+  :type 'boolean
+  :group 'mh-show)
+
+(defcustom mh-clean-message-header-flag t
+  "*Non-nil means remove extraneous header fields.
+
+See also `mh-invisible-header-fields-default' and
+`mh-invisible-header-fields'."
+  :type 'boolean
+  :group 'mh-show)
+
+(defcustom mh-decode-mime-flag (not (not (locate-library "mm-decode")))
+  "*Non-nil means attachments are handled\\<mh-folder-mode-map>.
+
+MH-E can handle attachments as well if the Gnus `mm-decode'
+library is present. If so, this option will be on. Otherwise,
+you'll see the MIME body parts rather than text or attachments.
+There isn't much point in turning off this option; however, you
+can inspect it if it appears that the body parts are not being
+interpreted correctly or toggle it with the command
+\\[mh-toggle-mh-decode-mime-flag] to view the raw message.
+
+This option also controls the display of quoted-printable
+messages and other graphical widgets. See the options
+`mh-graphical-smileys-flag' and `mh-graphical-emphasis-flag'."
+  :type 'boolean
+  :group 'mh-show)
+
+(defcustom mh-display-buttons-for-alternatives-flag nil
+  "*Non-nil means display buttons for all alternative attachments.
+
+Sometimes, a mail program will produce multiple alternatives of
+the attachment in increasing degree of faithfulness to the
+original content. By default, only the preferred alternative is
+displayed. If this option is on, then the preferred part is shown
+inline and buttons are shown for each of the other alternatives."
+  :type 'boolean
+  :group 'mh-show)
+
+(defcustom mh-display-buttons-for-inline-parts-flag nil
+  "*Non-nil means display buttons for all inline 
attachments\\<mh-folder-mode-map>.
+
+The sender can request that attachments should be viewed inline so
+that they do not really appear like an attachment at all to the
+reader. Most of the time, this is desirable, so by default MH-E
+suppresses the buttons for inline attachments. On the other hand, you
+may receive code or HTML which the sender has added to his message as
+inline attachments so that you can read them in MH-E. In this case, it
+is useful to see the buttons so that you know you don't have to cut
+and paste the code into a file; you can simply save the attachment.
+
+If you want to make the buttons visible for inline attachments, you
+can use the command \\[mh-toggle-mime-buttons] to toggle the
+visibility of these buttons. You can turn on these buttons permanently
+by turning on this option.
+
+MH-E cannot display all attachments inline however. It can display
+text (including HTML) and images."
+  :type 'boolean
+  :group 'mh-show)
+
+(defcustom mh-do-not-confirm-flag nil
+  "*Non-nil means non-reversible commands do not prompt for confirmation.
+
+Commands such as `mh-pack-folder' prompt to confirm whether to
+process outstanding moves and deletes or not before continuing.
+Turning on this option means that these actions will be
+performed--which is usually desired but cannot be
+retracted--without question."
+  :type 'boolean
+  :group 'mh-show)
+
+(defcustom mh-fetch-x-image-url nil
+  "*Control fetching of \"X-Image-URL:\" header field image.
+
+Ths option controls the fetching of the \"X-Image-URL:\" header
+field image with the following values:
+
+Ask Before Fetching
+     You are prompted before the image is fetched. MH-E will
+     remember your reply and will either use the already fetched
+     image the next time the same URL is encountered or silently
+     skip it if you didn't fetch it the first time. This is a
+     good setting.
+
+Never Fetch
+     Images are never fetched and only displayed if they are
+     already present in the cache. This is the default.
+
+There isn't a value of \"Always Fetch\" for privacy and DOS (denial of
+service) reasons. For example, fetching a URL can tip off a spammer
+that you've read his email (which is why you shouldn't blindly answer
+yes if you've set this option to \"Ask Before Fetching\"). Someone may
+also flood your network and fill your disk drive by sending a torrent
+of messages, each specifying a unique URL to a very large file.
+
+The cache of images is found in the directory \".mhe-x-image-cache\"
+within your MH directory. You can add your own face to the \"From:\"
+field too. See Info node `(mh-e)Picture'.
+
+This setting only has effect if the option `mh-show-use-xface-flag' is
+turned on."
+
+  :type '(choice (const :tag "Ask Before Fetching" ask)
+                 (const :tag "Never Fetch" nil))
+  :group 'mh-show)
+
+(defcustom mh-graphical-smileys-flag t
+  "*Non-nil means graphical smileys are displayed.
+
+It is a long standing custom to inject body language using a
+cornucopia of punctuation, also known as the \"smileys\". MH-E
+can render these as graphical widgets if this option is turned
+on, which it is by default. Smileys include patterns such as :-)
+and ;-).
+
+This option is disabled if the option `mh-decode-mime-flag' is
+turned off."
+  :type 'boolean
+  :group 'mh-show)
+
+(defcustom mh-graphical-emphasis-flag t
+  "*Non-nil means graphical emphasis is displayed.
+
+A few typesetting features are indicated in ASCII text with
+certain characters. If your terminal supports it, MH-E can render
+these typesetting directives naturally if this option is turned
+on, which it is by default. For example, _underline_ will be
+underlined, *bold* will appear in bold, /italics/ will appear in
+italics, and so on. See the option `gnus-emphasis-alist' for the
+whole list.
+
+This option is disabled if the option `mh-decode-mime-flag' is
+turned off."
+  :type 'boolean
+  :group 'mh-show)
+
+(defcustom mh-highlight-citation-style 'gnus
+  "Style for highlighting citations.
+
+If the sender of the message has cited other messages in his
+message, then MH-E will highlight these citations to emphasize
+the sender's actual response. This option can be customized to
+change the highlighting style. The \"Multicolor\" method uses a
+different color for each indentation while the \"Monochrome\"
+method highlights all citations in red. To disable highlighting
+of citations entirely, choose \"None\"."
+  :type '(choice (const :tag "Multicolor" gnus)
+                 (const :tag "Monochrome" font-lock)
+                 (const :tag "None" nil))
+  :group 'mh-show)
+
+;; Keep fields alphabetized. Mention source, if known.
+(defvar mh-invisible-header-fields-internal
+  '("Approved:"
+    "Autoforwarded:"
+    "Bestservhost:"
+    "Cancel-Lock:"                      ; NNTP posts
+    "Content-"                          ; RFC 2045
+    "Delivered-To:"              ; Egroups/yahoogroups mailing list manager
+    "Delivery-Date:"                    ; MH
+    "Delivery:"
+    "DomainKey-Signature:"              ;http://antispam.yahoo.com/domainkeys
+    "Encoding:"
+    "Envelope-to:"
+    "Errors-To:"
+    "Face:"                             ; Gnus Face header
+    "Forwarded:"                        ; MH
+    "From "                             ; sendmail
+    "Importance:"                       ; MS Outlook
+    "In-Reply-To:"                      ; MH
+    "Lines:"
+    "List-"                             ; Mailman mailing list manager
+    "List-"                             ; Unknown mailing list managers
+    "List-Subscribe:"                   ; Unknown mailing list managers
+    "List-Unsubscribe:"                 ; Unknown mailing list managers
+    "Mail-from:"                        ; MH
+    "Mailing-List:"              ; Egroups/yahoogroups mailing list manager
+    "Message-Id:"                       ; RFC 822
+    "Mime-Version"                      ; RFC 2045
+    "NNTP-"                             ; News
+    "Old-Return-Path:"
+    "Original-Encoded-Information-Types:"  ; X400
+    "Original-Lines:"                   ; mail to news
+    "Original-NNTP-"                    ; mail to news
+    "Original-Newsgroups:"              ; mail to news
+    "Original-Path:"                    ; mail to news
+    "Original-Received:"                ; mail to news
+    "Original-To:"                      ; mail to news
+    "Original-X-"                       ; mail to news
+    "Originator:"
+    "P1-Content-Type:"                  ; X400
+    "P1-Message-Id:"                    ; X400
+    "P1-Recipient:"                     ; X400
+    "Path:"
+    "Precedence:"
+    "Prev-Resent"                       ; MH
+    "Priority:"
+    "Received:"                         ; RFC 822
+    "Received-SPF:"                     ; Gmail
+    "References:"
+    "Remailed-"                         ; MH
+    "Replied:"                          ; MH
+    "Resent"                            ; MH
+    "Return-Path:"                      ; RFC 822
+    "Sensitivity:"                      ; MS Outlook
+    "Status:"                           ; sendmail
+    "Thread-"
+    "Ua-Content-Id:"                    ; X400
+;;  "User-Agent:"                       ; Similar to X-Mailer, so display it.
+    "Via:"                              ; MH
+    "X-Abuse-Info:"
+    "X-Abuse-and-DMCA-"
+    "X-Accept-Language:"
+    "X-Accept-Language:"                ; Netscape/Mozilla
+    "X-Ack:"
+    "X-Administrivia-To:"
+    "X-AntiAbuse:"                      ; cPanel
+    "X-Apparently-From:"                ; MS Outlook
+    "X-Apparently-To:"           ; Egroups/yahoogroups mailing list manager
+    "X-Authentication-Warning:"         ; sendmail
+    "X-Beenthere:"                      ; Mailman mailing list manager
+    "X-Bogosity:"                       ; bogofilter
+    "X-Bugzilla-*"                      ; Bugzilla
+    "X-Complaints-To:"
+    "X-ContentStamp:"                   ; NetZero
+    "X-Cron-Env:"
+    "X-DMCA"
+    "X-Delivered"
+    "X-ELNK-Trace:"                     ; Earthlink mailer
+    "X-Envelope-Date:"                  ; GNU mailutils
+    "X-Envelope-From:"
+    "X-Envelope-Sender:"
+    "X-Envelope-To:"
+    "X-Evolution:"                      ; Evolution mail client
+    "X-Face:"
+    "X-Folder:"                         ; Spam
+    "X-From-Line"
+    "X-Gmail-"                          ; Gmail
+    "X-Gnus-Mail-Source:"               ; gnus
+    "X-Greylist:"                       ; milter-greylist-1.2.1
+    "X-Habeas-SWE-1:"                   ; Spam
+    "X-Habeas-SWE-2:"                   ; Spam
+    "X-Habeas-SWE-3:"                   ; Spam
+    "X-Habeas-SWE-4:"                   ; Spam
+    "X-Habeas-SWE-5:"                   ; Spam
+    "X-Habeas-SWE-6:"                   ; Spam
+    "X-Habeas-SWE-7:"                   ; Spam
+    "X-Habeas-SWE-8:"                   ; Spam
+    "X-Habeas-SWE-9:"                   ; Spam
+    "X-Info:"                           ; NTMail
+    "X-Juno-"                           ; Juno
+    "X-List-Host:"                      ; Unknown mailing list managers
+    "X-List-Subscribe:"                 ; Unknown mailing list managers
+    "X-List-Unsubscribe:"               ; Unknown mailing list managers
+    "X-Listprocessor-"                  ; ListProc(tm) by CREN
+    "X-Listserver:"                     ; Unknown mailing list managers
+    "X-Loop:"                           ; Unknown mailing list managers
+    "X-Lumos-SenderID:"                 ; Roving ConstantContact
+    "X-MAIL-INFO:"                      ; NetZero
+    "X-MHE-Checksum"                    ; Checksum added during index search
+    "X-MIME-Autoconverted:"             ; sendmail
+    "X-MIMETrack:"
+    "X-MS-"                             ; MS Outlook
+    "X-MailScanner"                     ; ListProc(tm) by CREN
+    "X-Mailing-List:"                   ; Unknown mailing list managers
+    "X-Mailman-Version:"                ; Mailman mailing list manager
+    "X-Majordomo:"                      ; Majordomo mailing list manager
+    "X-Message-Id"
+    "X-MessageWall-Score:"              ; Unknown mailing list manager, AUC TeX
+    "X-MimeOLE:"                        ; MS Outlook
+    "X-Mms-"                            ; T-Mobile pictures
+    "X-Mozilla-Status:"                 ; Netscape/Mozilla
+    "X-Msmail-"                         ; MS Outlook
+    "X-NAI-Spam-"                       ; Network Associates Inc. SpamKiller
+    "X-News:"                           ; News
+    "X-No-Archive:"
+    "X-Notes-Item:"                     ; Lotus Notes Domino structured header
+    "X-OperatingSystem:"
+    ;;"X-Operator:"                     ; Similar to X-Mailer, so display it
+    "X-Orcl-Content-Type:"
+    "X-Original-Complaints-To:"
+    "X-Original-Date:"                  ; SourceForge mailing list manager
+    "X-Original-To:"
+    "X-Original-Trace:"
+    "X-OriginalArrivalTime:"            ; Hotmail
+    "X-Originating-IP:"                 ; Hotmail
+    "X-Postfilter:"
+    "X-Priority:"                       ; MS Outlook
+    "X-Qotd-"                           ; User added
+    "X-RM"
+    "X-Received-Date:"
+    "X-Received:"
+    "X-Request-"
+    "X-Return-Path-Hint:"               ; Roving ConstantContact
+    "X-Roving-*"                        ; Roving ConstantContact
+    "X-SBClass:"                        ; Spam
+    "X-SBNote:"                         ; Spam
+    "X-SBPass:"                         ; Spam
+    "X-SBRule:"                         ; Spam
+    "X-SMTP-"
+    "X-Scanned-By"
+    "X-Sender:"
+    "X-Server-Date:"
+    "X-Server-Uuid:"
+    "X-Sieve:"                          ; Sieve filtering
+    "X-Source"
+    "X-Spam-"                           ; Spamassassin
+    "X-SpamBouncer:"                    ; Spam
+    "X-Status"
+    "X-Submissions-To:"
+    "X-Telecom-Digest"
+    "X-Trace:"
+    "X-UID"
+    "X-UIDL:"
+    "X-UNTD-"                           ; NetZero
+    "X-USANET-"                         ; usa.net
+    "X-UserInfo1:"
+    "X-VSMLoop:"                        ; NTMail
+    "X-Virus-Scanned"                   ; amavisd-new
+    "X-Vms-To:"
+    "X-WebTV-Signature:"
+    "X-Wss-Id:"                         ; Worldtalk gateways
+    "X-Yahoo"
+    "X-eGroups-"                 ; Egroups/yahoogroups mailing list manager
+    "X-pgp:"
+    "X-submission-address:"
+    "X400-"                             ; X400
+    "Xref:")
+  "List of default header fields that are not to be shown.
+
+Do not alter this variable directly. Instead, add entries from
+here that you would like to be displayed in
+`mh-invisible-header-fields-default' and add entries to hide in
+`mh-invisible-header-fields'.")
+
+(eval-and-compile
+  (unless (fboundp 'mh-invisible-headers)
+    (defun mh-invisible-headers ()
+      "Temporary definition.
+Real definition, below, uses variables that aren't defined yet."
+      nil)))
+
+(defvar mh-delay-invisible-header-generation-flag t
+  "Non-nil means to delay the generation of invisible header fields.
+Because the function `mh-invisible-headers' uses both
+`mh-invisible-header-fields' and `mh-invisible-header-fields', it
+cannot be run until both variables have been initialized.")
+
+(defcustom mh-invisible-header-fields nil
+  "*Additional header fields to hide.
+
+Header fields that you would like to hide that aren't listed in
+`mh-invisible-header-fields-default' can be added to this option
+with a couple of caveats. Regular expressions are not allowed.
+Unique fields should have a \":\" suffix; otherwise, the element
+can be used to render invisible an entire class of fields that
+start with the same prefix. If you think a header field should be
+generally ignored, report a bug (see URL
+`https://sourceforge.net/tracker/?group_id=13357&atid=113357').
+
+See also `mh-clean-message-header-flag'."
+
+  :type '(repeat (string :tag "Header field"))
+  :set (lambda (symbol value)
+         (set-default symbol value)
+         (mh-invisible-headers))
+  :group 'mh-show)
+
+(defcustom mh-invisible-header-fields-default nil
+  "*List of hidden header fields.
+
+The header fields listed in this option are hidden, although you
+can check off any field that you would like to see.
+
+Header fields that you would like to hide that aren't listed can
+be added to the option `mh-invisible-header-fields'.
+
+See also `mh-clean-message-header-flag'."
+  :type `(set ,@(mapcar (lambda (x) `(const ,x))
+                        mh-invisible-header-fields-internal))
+  :set (lambda (symbol value)
+         (set-default symbol value)
+         (mh-invisible-headers))
+  :group 'mh-show)
+
+(defvar mh-invisible-header-fields-compiled nil
+  "*Regexp matching lines in a message header that are not to be shown.
+Do not alter this variable directly. Instead, customize
+`mh-invisible-header-fields-default' checking for fields normally
+hidden that you wish to display, and add extra entries to hide in
+`mh-invisible-header-fields'.")
+
+(defun mh-invisible-headers ()
+  "Make or remake the variable `mh-invisible-header-fields-compiled'.
+Done using `mh-invisible-header-fields-internal' as input, from
+which entries from `mh-invisible-header-fields-default' are
+removed and entries from `mh-invisible-header-fields' are added."
+  (let ((fields mh-invisible-header-fields-internal))
+    (when mh-invisible-header-fields-default
+      ;; Remove entries from `mh-invisible-header-fields-default'
+      (setq fields
+            (loop for x in fields
+                  unless (member x mh-invisible-header-fields-default)
+                  collect x)))
+    (when (and (boundp 'mh-invisible-header-fields)
+               mh-invisible-header-fields)
+      (dolist (x mh-invisible-header-fields)
+        (unless (member x fields) (setq fields (cons x fields)))))
+    (if fields
+        (setq mh-invisible-header-fields-compiled
+              (concat
+               "^"
+               ;; workaround for insufficient default
+               (let ((max-specpdl-size 1000))
+                 (regexp-opt fields t))))
+      (setq mh-invisible-header-fields-compiled nil))))
+
+;; Compile invisible header fields.
+(mh-invisible-headers)
+
+(defcustom mh-lpr-command-format "lpr -J '%s'"
+  "*Command used to print\\<mh-folder-mode-map>.
+
+This option contains the Unix command line which performs the
+actual printing for the \\[mh-print-msg] command. The string can
+contain one escape, \"%s\", which is replaced by the name of the
+folder and the message number and is useful for print job names.
+I use \"mpage -h'%s' -b Letter -H1of -mlrtb -P\" which produces a
+nice header and adds a bit of margin so the text fits within my
+printer's margins.
+
+This options is not used by the commands \\[mh-ps-print-msg] or
+\\[mh-ps-print-msg-file]."
+  :type 'string
+  :group 'mh-show)
+
+(defcustom mh-max-inline-image-height nil
+  "*Maximum inline image height if \"Content-Disposition:\" is not present.
+
+Some older mail programs do not insert this needed plumbing to
+tell MH-E whether to display the attachments inline or not. If
+this is the case, MH-E will display these images inline if they
+are smaller than the window. However, you might want to allow
+larger images to be displayed inline. To do this, you can change
+the options `mh-max-inline-image-width' and
+`mh-max-inline-image-height' from their default value of zero to
+a large number. The size of your screen is a good choice for
+these numbers."
+  :type '(choice (const nil) integer)
+  :group 'mh-show)
+
+(defcustom mh-max-inline-image-width nil
+  "*Maximum inline image width if \"Content-Disposition:\" is not present.
+
+Some older mail programs do not insert this needed plumbing to
+tell MH-E whether to display the attachments inline or not. If
+this is the case, MH-E will display these images inline if they
+are smaller than the window. However, you might want to allow
+larger images to be displayed inline. To do this, you can change
+the options `mh-max-inline-image-width' and
+`mh-max-inline-image-height' from their default value of zero to
+a large number. The size of your screen is a good choice for
+these numbers."
+  :type '(choice (const nil) integer)
+  :group 'mh-show)
+
+(defcustom mh-mhl-format-file nil
+  "*Specifies the format file to pass to the \"mhl\" program.
+
+Normally MH-E takes care of displaying messages itself (rather than
+calling an MH program to do the work). If you'd rather have \"mhl\"
+display the message (within MH-E), change this option from its default
+value of \"Use Default mhl Format (Printing Only)\".
+
+You can set this option to \"Use Default mhl Format\" to get the same
+output as you would get if you ran \"mhl\" from the shell.
+
+If you have a format file that you want MH-E to use, you can set this
+option to \"Specify an mhl Format File\" and enter the name of your
+format file. Your format file should specify a non-zero value for
+\"overflowoffset\" to allow MH-E to parse the header. Note that
+\"mhl\" is always used for printing and forwarding; in this case, the
+value of this option is consulted if you have specified a format
+file."
+  :type '(choice (const :tag "Use Default mhl Format (Printing Only)" nil)
+                 (const :tag "Use Default mhl Format" t)
+                 (file :tag "Specify an mhl Format File"))
+  :group 'mh-show)
+
+(defcustom mh-mime-save-parts-default-directory t
+  "Default directory to use for \\<mh-folder-mode-map>\\[mh-mime-save-parts].
+
+The default value for this option is \"Prompt Always\" so that
+you are always prompted for the directory in which to save the
+attachments. However, if you usually use the same directory
+within a session, then you can set this option to \"Prompt the
+First Time\" to avoid the prompt each time. you can make this
+directory permanent by choosing \"Directory\" and entering the
+directory's name."
+  :type '(choice (const :tag "Prompt the First Time" nil)
+                 (const :tag "Prompt Always" t)
+                 directory)
+  :group 'mh-show)
+
+(defcustom mh-print-background-flag nil
+  "*Non-nil means messages should be printed in the 
background\\<mh-folder-mode-map>.
+
+Normally messages are printed in the foreground. If this is slow on
+your system, you may elect to turn off this option to print in the
+background.
+
+WARNING: If you do this, do not delete the message until it is printed
+or else the output may be truncated.
+
+This option is not used by the commands \\[mh-ps-print-msg] or
+\\[mh-ps-print-msg-file]."
+  :type 'boolean
+  :group 'mh-show)
+
+(defcustom mh-show-maximum-size 0
+  "*Maximum size of message (in bytes) to display automatically.
+
+This option provides an opportunity to skip over large messages
+which may be slow to load. The default value of 0 means that all
+message are shown regardless of size."
+  :type 'integer
+  :group 'mh-show)
+
+(defcustom mh-show-use-goto-addr-flag (and (boundp 'goto-address-highlight-p)
+                                           goto-address-highlight-p)
+  "*Non-nil means highlight URLs and email 
addresses\\<goto-address-highlight-keymap>.
+
+To send a message using the highlighted email address or to view
+the web page for the highlighted URL, use the middle mouse button
+or \\[goto-address-at-point].
+
+See Info node `(mh-e)Sending Mail' to see how to configure Emacs
+to send the message using MH-E.
+
+The default value of this option comes from the value of
+`goto-address-highlight-p'."
+  :type 'boolean
+  :group 'mh-show)
+
+(defcustom mh-show-use-xface-flag (>= emacs-major-version 21)
+  "*Non-nil means display face images in MH-show buffers.
+
+MH-E can display the content of \"Face:\", \"X-Face:\", and
+\"X-Image-URL:\" header fields. If any of these fields occur in the
+header of your message, the sender's face will appear in the \"From:\"
+header field. If more than one of these fields appear, then the first
+field found in the order \"Face:\", \"X-Face:\", and \"X-Image-URL:\"
+will be used.
+
+The option `mh-show-use-xface-flag' is used to turn this feature on
+and off. This feature will be turned on by default if your system
+supports it.
+
+The first header field used, if present, is the Gnus-specific
+\"Face:\" field. The \"Face:\" field appeared in GNU Emacs 21 and
+XEmacs. For more information, see URL
+`http://quimby.gnus.org/circus/face/'. Next is the traditional
+\"X-Face:\" header field. The display of this field requires the
+\"uncompface\" program (see URL
+`ftp://ftp.cs.indiana.edu/pub/faces/compface/compface.tar.z'). Recent
+versions of XEmacs have internal support for \"X-Face:\" images. If
+your version of XEmacs does not, then you'll need both \"uncompface\"
+and the x-face package (see URL `ftp://ftp.jpl.org/pub/elisp/').
+
+Finally, MH-E will display images referenced by the \"X-Image-URL:\"
+header field if neither the \"Face:\" nor the \"X-Face:\" fields are
+present. The display of the images requires \"wget\" (see URL
+`http://www.gnu.org/software/wget/wget.html'), \"fetch\", or \"curl\"
+to fetch the image and the \"convert\" program from the ImageMagick
+suite (see URL `http://www.imagemagick.org/'). Of the three header
+fields this is the most efficient in terms of network usage since the
+image doesn't need to be transmitted with every single mail.
+
+The option `mh-fetch-x-image-url' controls the fetching of the
+\"X-Image-URL:\" header field image."
+  :type 'boolean
+  :group 'mh-show)
+
+(defcustom mh-store-default-directory nil
+  "*Default directory for \\<mh-folder-mode-map>\\[mh-store-msg].
+
+If you would like to change the initial default directory,
+customize this option, change the value from \"Current\" to
+\"Directory\", and then enter the name of the directory for storing
+the content of these messages."
+  :type '(choice (const :tag "Current" nil)
+                 directory)
+  :group 'mh-show)
+
+(defcustom mh-summary-height nil
+  "*Number of lines in MH-Folder buffer (including the mode line).
+
+The default value of this option is \"Automatic\" which means
+that the MH-Folder buffer will maintain the same proportional
+size if the frame is resized. If you'd prefer a fixed height,
+then choose the \"Fixed Size\" option and enter the number of
+lines you'd like to see."
+  :type '(choice (const :tag "Automatic" nil)
+                 (integer :tag "Fixed Size"))
+  :group 'mh-show)
+
+
+
+;;; The Speedbar (:group 'mh-speedbar)
+
+(defcustom mh-speed-update-interval 60
+  "Time between speedbar updates in seconds.
+Set to 0 to disable automatic update."
+  :type 'integer
+  :group 'mh-speedbar)
+
+
+
+;;; Threading (:group 'mh-thread)
+
+(defcustom mh-show-threads-flag nil
+  "*Non-nil means new folders start in threaded mode.
+
+Threading large number of messages can be time consuming so this
+option is turned off by default. If you turn this option on, then
+threading will be done only if the number of messages being
+threaded is less than `mh-large-folder'."
+  :type 'boolean
+  :group 'mh-thread)
+
+
+
+;;; The Tool Bar (:group 'mh-tool-bar)
+
+;; mh-tool-bar-folder-buttons and mh-tool-bar-letter-buttons defined
+;; dynamically in mh-tool-bar.el.
+
+(defcustom mh-tool-bar-search-function 'mh-search
+  "*Function called by the tool bar search button.
+
+By default, this is set to `mh-search'. You can also choose
+\"Other Function\" from the \"Value Menu\" and enter a function
+of your own choosing."
+  :type '(choice (const mh-search)
+                 (function :tag "Other Function"))
+  :group 'mh-tool-bar)
+
+;; XEmacs has a couple of extra customizations...
+(mh-do-in-xemacs
+  (defcustom mh-xemacs-use-tool-bar-flag mh-xemacs-has-tool-bar-flag
+    "*If non-nil, use tool bar.
+
+This option controls whether to show the MH-E icons at all. By
+default, this option is turned on if the window system supports
+tool bars. If your system doesn't support tool bars, then you
+won't be able to turn on this option."
+    :type 'boolean
+    :group 'mh-tool-bar
+    :set (lambda (symbol value)
+           (if (and (eq value t)
+                    (not mh-xemacs-has-tool-bar-flag))
+               (error "Tool bar not supported"))
+           (set-default symbol value)))
+
+  (defcustom mh-xemacs-tool-bar-position nil
+    "*Tool bar location.
+
+This option controls the placement of the tool bar along the four
+edges of the frame. You can choose from one of \"Same As Default
+Tool Bar\", \"Top\", \"Bottom\", \"Left\", or \"Right\". If this
+variable is set to anything other than \"Same As Default Tool
+Bar\" and the default tool bar is in a different location, then
+two tool bars will be displayed: the MH-E tool bar and the
+default tool bar."
+    :type '(radio (const :tag "Same As Default Tool Bar" :value nil)
+                  (const :tag "Top" :value top)
+                  (const :tag "Bottom" :value bottom)
+                  (const :tag "Left" :value left)
+                  (const :tag "Right" :value right))
+    :group 'mh-tool-bar))
+
+
+
+;;; Hooks (:group 'mh-hooks + group where hook described)
+
+(defcustom mh-after-commands-processed-hook nil
+  "Hook run by \\<mh-folder-mode-map>\\[mh-execute-commands] after performing 
outstanding requests.
+
+Variables that are useful in this hook include
+`mh-folders-changed', which lists which folders were affected by
+deletes and refiles. This list will always include the current
+folder, which is also available in `mh-current-folder'."
+  :type 'hook
+  :group 'mh-hooks
+  :group 'mh-folder)
+
+(defcustom mh-alias-reloaded-hook nil
+  "Hook run by `mh-alias-reload' after loading aliases."
+  :type 'hook
+  :group 'mh-hooks
+  :group 'mh-alias)
+
+(defcustom mh-before-commands-processed-hook nil
+  "Hook run by \\<mh-folder-mode-map>\\[mh-execute-commands] before performing 
outstanding requests.
+
+Variables that are useful in this hook include `mh-delete-list'
+and `mh-refile-list' which can be used to see which changes will
+be made to the current folder, `mh-current-folder'."
+  :type 'hook
+  :group 'mh-hooks
+  :group 'mh-folder)
+
+(defcustom mh-before-quit-hook nil
+  "Hook run by \\<mh-folder-mode-map>\\[mh-quit] before quitting MH-E.
+
+This hook is called before the quit occurs, so you might use it
+to perform any MH-E operations; you could perform some query and
+abort the quit or call `mh-execute-commands', for example.
+
+See also `mh-quit-hook'."
+  :type 'hook
+  :group 'mh-hooks
+  :group 'mh-folder)
+
+(defcustom mh-before-send-letter-hook nil
+  "Hook run at the beginning of the \\<mh-letter-mode-map>\\[mh-send-letter] 
command.
+
+For example, if you want to check your spelling in your message
+before sending, add the `ispell-message' function."
+  :type 'hook
+  :options '(ispell-message)
+  :group 'mh-hooks
+  :group 'mh-letter)
+
+(defcustom mh-delete-msg-hook nil
+  "Hook run by \\<mh-letter-mode-map>\\[mh-delete-msg] after marking each 
message for deletion.
+
+For example, a past maintainer of MH-E used this once when he
+kept statistics on his mail usage."
+  :type 'hook
+  :group 'mh-hooks
+  :group 'mh-show)
+
+(defcustom mh-find-path-hook nil
+  "Hook run by `mh-find-path' after reading the user's MH profile.
+
+This hook can be used the change the value of the variables that
+`mh-find-path' sets if you need to run with different values
+between MH and MH-E."
+  :type 'hook
+  :group 'mh-hooks
+  :group 'mh-e)
+
+(defcustom mh-folder-mode-hook nil
+  "Hook run by `mh-folder-mode' when visiting a new folder."
+  :type 'hook
+  :group 'mh-hooks
+  :group 'mh-folder)
+
+(defcustom mh-forward-hook nil
+  "Hook run by `mh-forward' on a forwarded letter."
+  :type 'hook
+  :group 'mh-hooks
+  :group 'mh-sending-mail)
+
+(defcustom mh-inc-folder-hook nil
+  "Hook run by \\<mh-folder-mode-map>\\[mh-inc-folder] after incorporating 
mail into a folder."
+  :type 'hook
+  :group 'mh-hooks
+  :group 'mh-inc)
+
+(defcustom mh-insert-signature-hook nil
+  "Hook run by \\<mh-letter-mode-map>\\[mh-insert-signature] after signature 
has been inserted.
+
+Hook functions may access the actual name of the file or the
+function used to insert the signature with
+`mh-signature-file-name'."
+  :type 'hook
+  :group 'mh-hooks
+  :group 'mh-letter)
+
+(defcustom mh-kill-folder-suppress-prompt-hooks '(mh-search-p)
+  "Abnormal hook run at the beginning of 
\\<mh-folder-mode-map>\\[mh-kill-folder].
+
+The hook functions are called with no arguments and should return
+a non-nil value to suppress the normal prompt when you remove a
+folder. This is useful for folders that are easily regenerated.
+
+The default value of `mh-search-p' suppresses the prompt on
+folders generated by searching.
+
+WARNING: Use this hook with care. If there is a bug in your hook
+which returns t on \"+inbox\" and you hit \\[mh-kill-folder] by
+accident in the \"+inbox\" folder, you will not be happy."
+  :type 'hook
+  :group 'mh-hooks
+  :group 'mh-folder)
+
+(defcustom mh-letter-mode-hook nil
+  "Hook run by `mh-letter-mode' on a new letter.
+
+This hook allows you to do some processing before editing a
+letter. For example, you may wish to modify the header after
+\"repl\" has done its work, or you may have a complicated
+\"components\" file and need to tell MH-E where the cursor should
+go."
+  :type 'hook
+  :group 'mh-hooks
+  :group 'mh-sending-mail)
+
+(defcustom mh-mh-to-mime-hook nil
+  "Hook run on the formatted letter by 
\\<mh-letter-mode-map>\\[mh-mh-to-mime]."
+  :type 'hook
+  :group 'mh-hooks
+  :group 'mh-letter)
+
+(defcustom mh-search-mode-hook nil
+  "Hook run upon entry to `mh-search-mode'\\<mh-folder-mode-map>.
+
+If you find that you do the same thing over and over when editing
+the search template, you may wish to bind some shortcuts to keys.
+This can be done with this hook which is called when
+\\[mh-search] is run on a new pattern."
+  :type 'hook
+  :group 'mh-hooks
+  :group 'mh-search)
+
+(defcustom mh-quit-hook nil
+  "Hook run by \\<mh-folder-mode-map>\\[mh-quit] after quitting MH-E.
+
+This hook is not run in an MH-E context, so you might use it to
+modify the window setup.
+
+See also `mh-before-quit-hook'."
+  :type 'hook
+  :group 'mh-hooks
+  :group 'mh-folder)
+
+(defcustom mh-refile-msg-hook nil
+  "Hook run by \\<mh-folder-mode-map>\\[mh-refile-msg] after marking each 
message for refiling."
+  :type 'hook
+  :group 'mh-hooks
+  :group 'mh-folder)
+
+(defcustom mh-show-hook nil
+  "Hook run after \\<mh-folder-mode-map>\\[mh-show] shows a message.
+
+It is the last thing called after messages are displayed. It's
+used to affect the behavior of MH-E in general or when
+`mh-show-mode-hook' is too early. See `mh-show-mode-hook'."
+  :type 'hook
+  :group 'mh-hooks
+  :group 'mh-show)
+
+(defcustom mh-show-mode-hook nil
+  "Hook run upon entry to `mh-show-mode'.
+
+This hook is called early on in the process of the message
+display. It is usually used to perform some action on the
+message's content. See `mh-show-hook'."
+  :type 'hook
+  :group 'mh-hooks
+  :group 'mh-show)
+
+(defcustom mh-unseen-updated-hook nil
+  "Hook run after the unseen sequence has been updated.
+
+The variable `mh-seen-list' can be used by this hook to obtain
+the list of messages which were removed from the unseen
+sequence."
+  :type 'hook
+  :group 'mh-hooks
+  :group 'mh-sequences)
 
 
 
-;;; Build mh-folder-mode keymap:
+;;; Faces (:group 'mh-faces + group where faces described)
 
-(suppress-keymap mh-folder-mode-map)
+(if (boundp 'facemenu-unlisted-faces)
+    (add-to-list 'facemenu-unlisted-faces "^mh-"))
 
-;; Use defalias to make sure the documented primary key bindings
-;; appear in menu lists.
-(defalias 'mh-alt-show 'mh-show)
-(defalias 'mh-alt-refile-msg 'mh-refile-msg)
-(defalias 'mh-alt-send 'mh-send)
-(defalias 'mh-alt-visit-folder 'mh-visit-folder)
-
-;; Save the "b" binding for a future `back'. Maybe?
-(gnus-define-keys  mh-folder-mode-map
-  " "           mh-page-msg
-  "!"           mh-refile-or-write-again
-  "'"           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
-  "M"           mh-modify
-  "\177"        mh-previous-page
-  "\C-d"        mh-delete-msg-no-motion
-  "\t"          mh-index-next-folder
-  [backtab]     mh-index-previous-folder
-  "\M-\t"       mh-index-previous-folder
-  "\e<"         mh-first-msg
-  "\e>"         mh-last-msg
-  "\ed"         mh-redistribute
-  "\r"          mh-show
-  "^"           mh-alt-refile-msg
-  "c"           mh-copy-msg
-  "d"           mh-delete-msg
-  "e"           mh-edit-again
-  "f"           mh-forward
-  "g"           mh-goto-msg
-  "i"           mh-inc-folder
-  "k"           mh-delete-subject-or-thread
-  "m"           mh-alt-send
-  "n"           mh-next-undeleted-msg
-  "\M-n"        mh-next-unread-msg
-  "o"           mh-refile-msg
-  "p"           mh-previous-undeleted-msg
-  "\M-p"        mh-previous-unread-msg
-  "q"           mh-quit
-  "r"           mh-reply
-  "s"           mh-send
-  "t"           mh-toggle-showing
-  "u"           mh-undo
-  "v"           mh-index-visit-folder
-  "x"           mh-execute-commands
-  "|"           mh-pipe-msg)
-
-(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
-  "k"           mh-kill-folder
-  "l"           mh-list-folders
-  "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
-  "u"           mh-undo-folder
-  "v"           mh-visit-folder)
-
-(define-key mh-folder-mode-map "I" mh-inc-spool-map)
-
-(gnus-define-keys (mh-junk-map "J" mh-folder-mode-map)
-  "?"           mh-prefix-help
-  "b"           mh-junk-blacklist
-  "w"           mh-junk-whitelist)
-
-(gnus-define-keys (mh-ps-print-map "P" mh-folder-mode-map)
-  "?"           mh-prefix-help
-  "C"           mh-ps-print-toggle-color
-  "F"           mh-ps-print-toggle-faces
-  "f"           mh-ps-print-msg-file
-  "l"          mh-print-msg
-  "p"           mh-ps-print-msg)
-
-(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
-  "l"           mh-list-sequences
-  "n"           mh-narrow-to-seq
-  "p"           mh-put-msg-in-seq
-  "s"           mh-msg-is-in-seq
-  "w"           mh-widen)
-
-(gnus-define-keys (mh-thread-map "T" mh-folder-mode-map)
-  "?"           mh-prefix-help
-  "u"           mh-thread-ancestor
-  "p"           mh-thread-previous-sibling
-  "n"           mh-thread-next-sibling
-  "t"           mh-toggle-threads
-  "d"           mh-thread-delete
-  "o"           mh-thread-refile)
-
-(gnus-define-keys (mh-limit-map "/" mh-folder-mode-map)
-  "'"           mh-narrow-to-tick
-  "?"           mh-prefix-help
-  "c"           mh-narrow-to-cc
-  "g"           mh-narrow-to-range
-  "m"           mh-narrow-to-from
-  "s"           mh-narrow-to-subject
-  "t"           mh-narrow-to-to
-  "w"           mh-widen)
-
-(gnus-define-keys (mh-extract-map "X" mh-folder-mode-map)
-  "?"           mh-prefix-help
-  "s"           mh-store-msg            ;shar
-  "u"           mh-store-msg)           ;uuencode
-
-(gnus-define-keys (mh-digest-map "D" mh-folder-mode-map)
-  " "           mh-page-digest
-  "?"           mh-prefix-help
-  "\177"        mh-page-digest-backwards
-  "b"           mh-burst-digest)
-
-(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
-  "\M-\t"       mh-prev-button)
-
-(cond
- (mh-xemacs-flag
-  (define-key mh-folder-mode-map [button2] 'mh-show-mouse))
- (t
-  (define-key mh-folder-mode-map [mouse-2] 'mh-show-mouse)))
-
-;; "C-c /" prefix is used in mh-folder-mode by pgp.el and mailcrypt
-
-
-
-;;; Help Messages
-
-;; If you add a new prefix, add appropriate text to the nil key.
-;;
-;; In general, messages are grouped logically. Taking the main commands for
-;; example, the first line is "ways to view messages," the second line is
-;; "things you can do with messages", and the third is "composing" messages.
-;;
-;; When adding a new prefix, ensure that the help message contains "what" the
-;; prefix is for. For example, if the word "folder" were not present in the
-;; "F" entry, it would not be clear what these commands operated upon.
-(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"
-         "[;]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.")
-
-    (?F "[l]ist; [v]isit folder;\n"
-        "[n]ew messages; [']ticked messages; [s]earch;\n"
-        "[p]ack; [S]ort; [r]escan; [k]ill")
-    (?P "[p]rint message to [f]ile; old-style [l]pr printing;\n"
-        "Toggle printing of [C]olors, [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 [c]c, ran[g]e, fro[m], [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"
-        "[TAB] next; [SHIFT-TAB] previous")
-    (?J "[b]lacklist, [w]hitelist message"))
-  "Key binding cheat sheet.
-
-This is an associative array which is used to show the most common commands.
-The key is a prefix char. The value is one or more strings which are
-concatenated together and displayed in the minibuffer if ? is pressed after
-the prefix character. The special key nil is used to display the
-non-prefixed commands.
-
-The substitutions described in `substitute-command-keys' are performed as
-well.")
-
-
-
-(dolist (mess '("^Cursor not pointing to message$"
-                "^There is no other window$"))
-  (add-to-list 'debug-ignored-errors mess))
+(defvar mh-min-colors-defined-flag (and (not mh-xemacs-flag)
+                                        (>= emacs-major-version 22))
+  "Non-nil means defface supports min-colors display requirement.")
+
+(defun mh-defface-compat (spec)
+  "Convert SPEC for defface if necessary to run on older platforms.
+Modifies SPEC in place and returns it. See `defface' for the spec definition.
+
+When `mh-min-colors-defined-flag' is nil, this function finds
+display entries with \"min-colors\" requirements and either
+removes the \"min-colors\" requirement or strips the display
+entirely if the display does not support the number of specified
+colors."
+  (if mh-min-colors-defined-flag
+      spec
+    (let ((cells (display-color-cells))
+          new-spec)
+      ;; Remove entries with min-colors, or delete them if we have fewer colors
+      ;; than they specify.
+      (loop for entry in (reverse spec) do
+            (let ((requirement (if (eq (car entry) t)
+                                   nil
+                                 (assoc 'min-colors (car entry)))))
+              (if requirement
+                  (when (>= cells (nth 1 requirement))
+                    (setq new-spec (cons (cons (delq requirement (car entry))
+                                               (cdr entry))
+                                         new-spec)))
+                (setq new-spec (cons entry new-spec)))))
+      new-spec)))
+
+(defface mh-folder-address '((t (:inherit mh-folder-subject)))
+  "Recipient face."
+  :group 'mh-faces
+  :group 'mh-folder)
+
+(defface mh-folder-body
+  '((((class color))
+     (:inherit mh-folder-msg-number))
+    (t
+     (:inherit mh-folder-msg-number :italic t)))
+  "Body text face."
+  :group 'mh-faces
+  :group 'mh-folder)
+
+(defface mh-folder-cur-msg-number
+  '((t
+     (:inherit mh-folder-msg-number :bold t)))
+  "Current message number face."
+  :group 'mh-faces
+  :group 'mh-folder)
+
+(defface mh-folder-date '((t (:inherit mh-folder-msg-number)))
+  "Date face."
+  :group 'mh-faces
+  :group 'mh-folder)
+
+(defface mh-folder-deleted '((t (:inherit mh-folder-msg-number)))
+  "Deleted message face."
+  :group 'mh-faces
+  :group 'mh-folder)
+
+(defface mh-folder-followup
+  '((((class color) (background light))
+     (:foreground "blue3"))
+    (((class color) (background dark))
+     (:foreground "LightGoldenRod"))
+    (t
+     (:bold t)))
+  "\"Re:\" face."
+  :group 'mh-faces
+  :group 'mh-folder)
+
+(defface mh-folder-msg-number
+  (mh-defface-compat
+   '((((class color) (min-colors 88) (background light))
+      (:foreground "snow4"))
+     (((class color) (min-colors 88) (background dark))
+      (:foreground "snow3"))
+     (((class color))
+      (:foreground "cyan"))))
+
+  "Message number face."
+  :group 'mh-faces
+  :group 'mh-folder)
+
+(defface mh-folder-refiled
+  (mh-defface-compat
+   '((((class color) (min-colors 88) (background light))
+      (:foreground "DarkGoldenrod"))
+     (((class color) (min-colors 88) (background dark))
+      (:foreground "LightGoldenrod"))
+     (((class color))
+      (:foreground "yellow" :weight light))
+     (((class grayscale) (background light))
+      (:foreground "Gray90" :bold t :italic t))
+     (((class grayscale) (background dark))
+      (:foreground "DimGray" :bold t :italic t))
+     (t
+      (:bold t :italic t))))
+  "Refiled message face."
+  :group 'mh-faces
+  :group 'mh-folder)
+
+(defface mh-folder-sent-to-me-hint '((t (:inherit mh-folder-date)))
+  "Fontification hint face in messages sent directly to us.
+The detection of messages sent to us is governed by the scan
+format `mh-scan-format-nmh' and the regular expression
+`mh-scan-sent-to-me-sender-regexp'."
+  :group 'mh-faces
+  :group 'mh-folder)
+
+(defface mh-folder-sent-to-me-sender '((t (:inherit mh-folder-followup)))
+  "Sender face in messages sent directly to us.
+The detection of messages sent to us is governed by the scan
+format `mh-scan-format-nmh' and the regular expression
+`mh-scan-sent-to-me-sender-regexp'."
+  :group 'mh-faces
+  :group 'mh-folder)
+
+(defface mh-folder-subject
+  '((((class color) (background light))
+     (:foreground "blue4"))
+    (((class color) (background dark))
+     (:foreground "yellow"))
+    (t
+     (:bold t)))
+  "Subject face."
+  :group 'mh-faces
+  :group 'mh-folder)
+
+(defface mh-folder-tick
+  '((((class color) (background dark))
+     (:background "#dddf7e"))
+    (((class color) (background light))
+     (:background "#dddf7e"))
+    (t
+     (:underline t)))
+  "Ticked message face."
+  :group 'mh-faces
+  :group 'mh-folder)
+
+(defface mh-folder-to
+  (mh-defface-compat
+   '((((class color) (min-colors 88) (background light))
+      (:foreground "RosyBrown"))
+     (((class color) (min-colors 88) (background dark))
+      (:foreground "LightSalmon"))
+     (((class color))
+      (:foreground "green"))
+     (((class grayscale) (background light))
+      (:foreground "DimGray" :italic t))
+     (((class grayscale) (background dark))
+      (:foreground "LightGray" :italic t))
+     (t
+      (:italic t))))
+  "\"To:\" face."
+  :group 'mh-faces
+  :group 'mh-folder)
+
+(defface mh-search-folder
+  '((((class color) (background light))
+     (:foreground "dark green" :bold t))
+    (((class color) (background dark))
+     (:foreground "indian red" :bold t))
+    (t
+     (:bold t)))
+  "Folder heading face in MH-Folder buffers created by searches."
+  :group 'mh-faces
+  :group 'mh-search)
+
+(defface mh-letter-header-field
+  '((((class color) (background light))
+     (:background "gray90"))
+    (((class color) (background dark))
+     (:background "gray10"))
+    (t
+     (:bold t)))
+  "Editable header field value face in draft buffers."
+  :group 'mh-faces
+  :group 'mh-letter)
+
+(defface mh-show-cc
+  (mh-defface-compat
+   '((((class color) (min-colors 88) (background light))
+      (:foreground "DarkGoldenrod"))
+     (((class color) (min-colors 88) (background dark))
+      (:foreground "LightGoldenrod"))
+     (((class color))
+      (:foreground "yellow" :weight light))
+     (((class grayscale) (background light))
+      (:foreground "Gray90" :bold t :italic t))
+     (((class grayscale) (background dark))
+      (:foreground "DimGray" :bold t :italic t))
+     (t
+      (:bold t :italic t))))
+  "Face used to highlight \"cc:\" header fields."
+  :group 'mh-faces
+  :group 'mh-show)
+
+(defface mh-show-date
+  (mh-defface-compat
+   '((((class color) (min-colors 88) (background light))
+      (:foreground "ForestGreen"))
+     (((class color) (min-colors 88) (background dark))
+      (:foreground "PaleGreen"))
+     (((class color))
+      (:foreground "green"))
+     (((class grayscale) (background light))
+      (:foreground "Gray90" :bold t))
+     (((class grayscale) (background dark))
+      (:foreground "DimGray" :bold t))
+     (t
+      (:bold t :underline t))))
+  "Face used to highlight \"Date:\" header fields."
+  :group 'mh-faces
+  :group 'mh-show)
+
+(defface mh-show-from
+  '((((class color) (background light))
+     (:foreground "red3"))
+    (((class color) (background dark))
+     (:foreground "cyan"))
+    (t
+     (:bold t)))
+  "Face used to highlight \"From:\" header fields."
+  :group 'mh-faces
+  :group 'mh-show)
+
+(defface mh-show-header
+  (mh-defface-compat
+   '((((class color) (min-colors 88) (background light))
+      (:foreground "RosyBrown"))
+     (((class color) (min-colors 88) (background dark))
+      (:foreground "LightSalmon"))
+     (((class color))
+      (:foreground "green"))
+     (((class grayscale) (background light))
+      (:foreground "DimGray" :italic t))
+     (((class grayscale) (background dark))
+      (:foreground "LightGray" :italic t))
+     (t
+      (:italic t))))
+  "Face used to deemphasize less interesting header fields."
+  :group 'mh-faces
+  :group 'mh-show)
+
+(defface mh-show-pgg-bad '((t (:bold t :foreground "DeepPink1")))
+  "Bad PGG signature face."
+  :group 'mh-faces
+  :group 'mh-show)
+
+(defface mh-show-pgg-good '((t (:bold t :foreground "LimeGreen")))
+  "Good PGG signature face."
+  :group 'mh-faces
+  :group 'mh-show)
+
+(defface mh-show-pgg-unknown '((t (:bold t :foreground "DarkGoldenrod2")))
+  "Unknown or untrusted PGG signature face."
+  :group 'mh-faces
+  :group 'mh-show)
+
+(defface mh-show-signature '((t (:italic t)))
+  "Signature face."
+  :group 'mh-faces
+  :group 'mh-show)
+
+(defface mh-show-subject '((t (:inherit mh-folder-subject)))
+  "Face used to highlight \"Subject:\" header fields."
+  :group 'mh-faces
+  :group 'mh-show)
+
+(defface mh-show-to
+  '((((class color) (background light))
+     (:foreground "SaddleBrown"))
+    (((class color) (background dark))
+     (:foreground "burlywood"))
+    (((class grayscale) (background light))
+     (:foreground "DimGray" :underline t))
+    (((class grayscale) (background dark))
+     (:foreground "LightGray" :underline t))
+    (t (:underline t)))
+  "Face used to highlight \"To:\" header fields."
+  :group 'mh-faces
+  :group 'mh-show)
+
+(defface mh-show-xface '((t (:inherit (mh-show-from highlight))))
+  "X-Face image face.
+The background and foreground are used in the image."
+  :group 'mh-faces
+  :group 'mh-show)
+
+(defface mh-speedbar-folder
+  '((((class color) (background light))
+     (:foreground "blue4"))
+    (((class color) (background dark))
+     (:foreground "light blue")))
+  "Basic folder face."
+  :group 'mh-faces
+  :group 'mh-speedbar)
+
+(defface mh-speedbar-folder-with-unseen-messages
+  '((t
+     (:inherit mh-speedbar-folder :bold t)))
+  "Folder face when folder contains unread messages."
+  :group 'mh-faces
+  :group 'mh-speedbar)
+
+(defface mh-speedbar-selected-folder
+  '((((class color) (background light))
+     (:foreground "red1" :underline t))
+    (((class color) (background dark))
+     (:foreground "red1" :underline t))
+    (t
+     (:underline t)))
+  "Selected folder face."
+  :group 'mh-faces
+  :group 'mh-speedbar)
+
+(defface mh-speedbar-selected-folder-with-unseen-messages
+  '((t
+     (:inherit mh-speedbar-selected-folder :bold t)))
+  "Selected folder face when folder contains unread messages."
+  :group 'mh-faces
+  :group 'mh-speedbar)
 
 (provide 'mh-e)
 
Index: emacs/lisp/mh-e/mh-funcs.el
diff -u emacs/lisp/mh-e/mh-funcs.el:1.26 emacs/lisp/mh-e/mh-funcs.el:1.27
--- emacs/lisp/mh-e/mh-funcs.el:1.26    Sun Jan 15 08:17:55 2006
+++ emacs/lisp/mh-e/mh-funcs.el Sun Jan 29 19:34:56 2006
@@ -27,34 +27,19 @@
 
 ;;; Commentary:
 
-;; Internal support for MH-E package.
 ;; Putting these functions in a separate file lets MH-E start up faster,
 ;; since less Lisp code needs to be loaded all at once.
 
+;; Please add the functions in alphabetical order. If only one or two
+;; small support routines are needed, place them with the function;
+;; otherwise, create a separate section for them.
+
 ;;; Change Log:
 
 ;;; Code:
 
-;;(message "> mh-funcs")
-(eval-when-compile (require 'mh-acros))
-(mh-require-cl)
-(require 'mh-buffers)
 (require 'mh-e)
-;;(message "< mh-funcs")
-
-
-
-;;; Scan Line Formats
-
-(defvar mh-note-copied "C"
-  "Messages that have been copied are marked by this character.")
-
-(defvar mh-note-printed "P"
-  "Messages that have been printed are marked by this character.")
-
-
-
-;;; Functions
+(require 'mh-scan)
 
 ;;;###mh-autoload
 (defun mh-burst-digest ()
@@ -213,27 +198,6 @@
   (mh-regenerate-headers range))
 
 ;;;###mh-autoload
-(defun mh-pipe-msg (command include-header)
-  "Pipe message through shell command COMMAND.
-
-You are prompted for the Unix command through which you wish to
-run your message. If you give a prefix argument INCLUDE-HEADER to
-this command, the message header is included in the text passed
-to the command."
-  (interactive
-   (list (read-string "Shell command on message: ") current-prefix-arg))
-  (let ((msg-file-to-pipe (mh-msg-filename (mh-get-msg-num t)))
-        (message-directory default-directory))
-    (save-excursion
-      (set-buffer (get-buffer-create mh-temp-buffer))
-      (erase-buffer)
-      (insert-file-contents msg-file-to-pipe)
-      (goto-char (point-min))
-      (if (not include-header) (search-forward "\n\n"))
-      (let ((default-directory message-directory))
-        (shell-command-on-region (point) (point-max) command nil)))))
-
-;;;###mh-autoload
 (defun mh-page-digest ()
   "Display next message in digest."
   (interactive)
@@ -268,6 +232,27 @@
     (mh-recenter 0)))
 
 ;;;###mh-autoload
+(defun mh-pipe-msg (command include-header)
+  "Pipe message through shell command COMMAND.
+
+You are prompted for the Unix command through which you wish to
+run your message. If you give a prefix argument INCLUDE-HEADER to
+this command, the message header is included in the text passed
+to the command."
+  (interactive
+   (list (read-string "Shell command on message: ") current-prefix-arg))
+  (let ((msg-file-to-pipe (mh-msg-filename (mh-get-msg-num t)))
+        (message-directory default-directory))
+    (save-excursion
+      (set-buffer (get-buffer-create mh-temp-buffer))
+      (erase-buffer)
+      (insert-file-contents msg-file-to-pipe)
+      (goto-char (point-min))
+      (if (not include-header) (search-forward "\n\n"))
+      (let ((default-directory message-directory))
+        (shell-command-on-region (point) (point-max) command nil)))))
+
+;;;###mh-autoload
 (defun mh-sort-folder (&optional extra-args)
   "Sort folder.
 
@@ -289,21 +274,6 @@
           (mh-index-data (mh-index-insert-folder-headers)))))
 
 ;;;###mh-autoload
-(defun mh-undo-folder ()
-  "Undo all refiles and deletes in the current folder."
-  (interactive)
-  (cond ((or mh-do-not-confirm-flag
-             (yes-or-no-p "Undo all commands in folder? "))
-         (setq mh-delete-list nil
-               mh-refile-list nil
-               mh-seq-list nil
-               mh-next-direction 'forward)
-         (with-mh-folder-updating (nil)
-           (mh-remove-all-notation)))
-        (t
-         (message "Commands not undone"))))
-
-;;;###mh-autoload
 (defun mh-store-msg (directory)
   "Unpack message created with \"uudecode\" or \"shar\".
 
@@ -326,7 +296,6 @@
       (insert-file-contents msg-file-to-store)
       (mh-store-buffer directory))))
 
-;;;###mh-autoload
 (defun mh-store-buffer (directory)
   "Unpack buffer created with \"uudecode\" or \"shar\".
 
@@ -383,48 +352,20 @@
             (insert "\n(mh-store finished)\n"))
         (error "Error occurred during execution of %s" command)))))
 
-
-
-;;; Help Functions
-
-;;;###mh-autoload
-(defun mh-ephem-message (string)
-  "Display STRING in the minibuffer momentarily."
-  (message "%s" string)
-  (sit-for 5)
-  (message ""))
-
 ;;;###mh-autoload
-(defun mh-help ()
-  "Display cheat sheet for the MH-E commands."
-  (interactive)
-  (with-electric-help
-   (function
-    (lambda ()
-      (insert
-       (substitute-command-keys
-        (mapconcat 'identity (cdr (assoc nil mh-help-messages)) ""))))
-    mh-help-buffer)))
-
-;;;###mh-autoload
-(defun mh-prefix-help ()
-  "Display cheat sheet for the commands of the current prefix in minibuffer."
+(defun mh-undo-folder ()
+  "Undo all refiles and deletes in the current folder."
   (interactive)
-  ;; We got here because the user pressed a "?", but he pressed a prefix key
-  ;; before that. Since the the key vector starts at index 0, the index of the
-  ;; last keystroke is length-1 and thus the second to last keystroke is at
-  ;; length-2. We use that information to obtain a suitable prefix character
-  ;; from the recent keys.
-  (let* ((keys (recent-keys))
-         (prefix-char (elt keys (- (length keys) 2))))
-    (with-electric-help
-     (function
-      (lambda ()
-        (insert
-         (substitute-command-keys
-          (mapconcat 'identity
-                     (cdr (assoc prefix-char mh-help-messages)) "")))))
-     mh-help-buffer)))
+  (cond ((or mh-do-not-confirm-flag
+             (yes-or-no-p "Undo all commands in folder? "))
+         (setq mh-delete-list nil
+               mh-refile-list nil
+               mh-seq-list nil
+               mh-next-direction 'forward)
+         (with-mh-folder-updating (nil)
+           (mh-remove-all-notation)))
+        (t
+         (message "Commands not undone"))))
 
 (provide 'mh-funcs)
 
Index: emacs/lisp/mh-e/mh-gnus.el
diff -u emacs/lisp/mh-e/mh-gnus.el:1.13 emacs/lisp/mh-e/mh-gnus.el:1.14
--- emacs/lisp/mh-e/mh-gnus.el:1.13     Sun Jan 15 08:17:55 2006
+++ emacs/lisp/mh-e/mh-gnus.el  Sun Jan 29 19:34:56 2006
@@ -1,4 +1,4 @@
-;;; mh-gnus.el --- Make MH-E compatible with installed version of Gnus.
+;;; mh-gnus.el --- make MH-E compatible with various versions of Gnus
 
 ;; Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc.
 
@@ -30,18 +30,13 @@
 
 ;;; Code:
 
-;;(message "> mh-gnus")
-(eval-when-compile (require 'mh-acros))
-;;(message "< mh-gnus")
-
-;; Load libraries in a non-fatal way in order to see if certain functions are
-;; pre-defined.
-(load "mailabbrev" t t)
-(load "mailcap" t t)
-(load "mm-decode" t t)
-(load "mm-uu" t t)
-(load "mml" t t)
-(load "smiley" t t)
+(require 'mh-e)
+
+(require 'gnus-util nil t)
+(require 'mm-bodies nil t)
+(require 'mm-decode nil t)
+(require 'mm-view nil t)
+(require 'mml nil t)
 
 ;; Copy of function from gnus-util.el.
 (mh-defun-compat gnus-local-map-property (map)
@@ -68,12 +63,12 @@
     (mm-insert-inline
      handle
      (concat "\n-- \n"
-            (ignore-errors
-              (if (fboundp 'vcard-pretty-print)
-                  (vcard-pretty-print (mm-get-part handle))
-                (vcard-format-string
-                 (vcard-parse-string (mm-get-part handle)
-                                     'vcard-standard-filter))))))))
+             (ignore-errors
+               (if (fboundp 'vcard-pretty-print)
+                   (vcard-pretty-print (mm-get-part handle))
+                 (vcard-format-string
+                  (vcard-parse-string (mm-get-part handle)
+                                      'vcard-standard-filter))))))))
 
 ;; Function from mm-decode.el used in PGP messages. Just define it with older
 ;; Gnus to avoid compiler warning.
@@ -116,6 +111,10 @@
   "Older versions of Emacs don't have this function."
   nil)
 
+(mh-defun-compat mm-uu-dissect-text-parts (handles)
+  "Emacs 21 and XEmacs don't have this function."
+  nil)
+
 ;; Copy of function in mml.el.
 (mh-defun-compat mml-minibuffer-read-disposition (type &optional default)
   (unless default (setq default
@@ -128,7 +127,7 @@
                       '(("attachment") ("inline") (""))
                       nil t nil nil default)))
     (if (not (equal disposition ""))
-       disposition
+        disposition
       default)))
 
 ;; This is mm-save-part from Gnus 5.10 since that function in emacs21.2 is
@@ -158,11 +157,6 @@
   (or (and (boundp 'mm-inline-text-html-renderer) mm-inline-text-html-renderer)
       (and (boundp 'mm-text-html-renderer) mm-text-html-renderer)))
 
-(defun mh-mail-abbrev-make-syntax-table ()
-  "Call `mail-abbrev-make-syntax-table' if available."
-  (when (fboundp 'mail-abbrev-make-syntax-table)
-    (mail-abbrev-make-syntax-table)))
-
 (provide 'mh-gnus)
 
 ;; Local Variables:
Index: emacs/lisp/mh-e/mh-identity.el
diff -u emacs/lisp/mh-e/mh-identity.el:1.25 emacs/lisp/mh-e/mh-identity.el:1.26
--- emacs/lisp/mh-e/mh-identity.el:1.25 Mon Jan 16 21:34:50 2006
+++ emacs/lisp/mh-e/mh-identity.el      Sun Jan 29 19:34:56 2006
@@ -1,4 +1,4 @@
-;;; mh-identity.el --- Multiple identify support for MH-E.
+;;; mh-identity.el --- multiple identify support for MH-E
 
 ;; Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
 
@@ -27,23 +27,19 @@
 ;;; Commentary:
 
 ;; Multiple identity support for MH-E.
-;;
-;; Used to easily set different fields such as From and Organization, as
-;; well as different signature files.
-;;
-;; Customize the variable `mh-identity-list' and an Identity menu will
-;; appear in mh-letter-mode.  The command 'mh-insert-identity can be used
-;; from the command line.
+
+;; Used to easily set different fields such as From and Organization,
+;; as well as different signature files.
+
+;; Customize the variable `mh-identity-list' and see the Identity menu
+;; in MH-Letter mode. The command `mh-insert-identity' can be used
+;; to manually insert an identity.
 
 ;;; Change Log:
 
 ;;; Code:
 
-;;(message "> mh-identity")
-(eval-when-compile (require 'mh-acros))
-
-(require 'mh-comp)
-;;(message "< mh-identity")
+(require 'mh-e)
 
 (autoload 'mml-insert-tag "mml")
 
@@ -53,11 +49,17 @@
 `mh-identity-list'.")
 (make-variable-buffer-local 'mh-identity-pgg-default-user-id)
 
+(defvar mh-identity-menu nil
+  "The Identity menu.")
+
+(defalias 'mh-identity-make-menu-no-autoload 'mh-identity-make-menu)
+
 ;;;###mh-autoload
 (defun mh-identity-make-menu ()
   "Build the Identity menu.
 This should be called any time `mh-identity-list' or
-`mh-auto-fields-list' change."
+`mh-auto-fields-list' change.
+See `mh-identity-add-menu'."
   (easy-menu-define mh-identity-menu mh-letter-mode-map
     "MH-E identity menu"
     (append
@@ -88,13 +90,11 @@
        ))))
 
 ;;;###mh-autoload
-(defun mh-identity-list-set (symbol value)
-  "Update the `mh-identity-list' variable, and rebuild the menu.
-Sets the default for SYMBOL (for example, `mh-identity-list') to
-VALUE (as set in customization). This is called after 'customize
-is used to alter `mh-identity-list'."
-  (set-default symbol value)
-  (mh-identity-make-menu))
+(defun mh-identity-add-menu ()
+  "Add the current Identity menu.
+See `mh-identity-make-menu'."
+  (if mh-identity-menu
+      (easy-menu-add mh-identity-menu)))
 
 (defvar mh-identity-local nil
   "Buffer-local variable that holds the identity currently in use.")
@@ -134,8 +134,13 @@
       'mh-identity-handler-default))
 
 ;;;###mh-autoload
-(defun mh-insert-identity (identity)
+(defun mh-insert-identity (identity &optional maybe-insert)
   "Insert fields specified by given IDENTITY.
+
+In a program, do not insert fields if MAYBE-INSERT is non-nil,
+`mh-identity-default' is non-nil, and fields have already been
+inserted.
+
 See `mh-identity-list'."
   (interactive
    (list (completing-read
@@ -144,29 +149,35 @@
               (cons '("None")
                     (mapcar 'list (mapcar 'car mh-identity-list)))
             (mapcar 'list (mapcar 'car mh-identity-list)))
-          nil t)))
-  (save-excursion
-    ;;First remove old settings, if any.
-    (when mh-identity-local
-      (let ((pers-list (cadr (assoc mh-identity-local mh-identity-list))))
-        (while pers-list
-          (let* ((field (caar pers-list))
-                 (handler (mh-identity-field-handler field)))
-            (funcall handler field 'remove))
-          (setq pers-list (cdr pers-list)))))
-    ;; Then insert the replacement
-    (when (not (equal "None" identity))
-      (let ((pers-list (cadr (assoc identity mh-identity-list))))
-        (while pers-list
-          (let* ((field (caar pers-list))
-                 (value (cdar pers-list))
-                 (handler (mh-identity-field-handler field)))
-            (funcall handler field 'add value))
-          (setq pers-list (cdr pers-list))))))
-  ;; Remember what is in use in this buffer
-  (if (equal "None" identity)
-      (setq mh-identity-local nil)
-    (setq mh-identity-local identity)))
+          nil t)
+         nil))
+
+  (when (or (not maybe-insert)
+            (and (boundp 'mh-identity-default)
+                 mh-identity-default
+                 (not mh-identity-local)))
+    (save-excursion
+      ;;First remove old settings, if any.
+      (when mh-identity-local
+        (let ((pers-list (cadr (assoc mh-identity-local mh-identity-list))))
+          (while pers-list
+            (let* ((field (caar pers-list))
+                   (handler (mh-identity-field-handler field)))
+              (funcall handler field 'remove))
+            (setq pers-list (cdr pers-list)))))
+      ;; Then insert the replacement
+      (when (not (equal "None" identity))
+        (let ((pers-list (cadr (assoc identity mh-identity-list))))
+          (while pers-list
+            (let* ((field (caar pers-list))
+                   (value (cdar pers-list))
+                   (handler (mh-identity-field-handler field)))
+              (funcall handler field 'add value))
+            (setq pers-list (cdr pers-list))))))
+    ;; Remember what is in use in this buffer
+    (if (equal "None" identity)
+        (setq mh-identity-local nil)
+      (setq mh-identity-local identity))))
 
 ;;;###mh-autoload
 (defun mh-identity-handler-gpg-identity (field action &optional value)
@@ -268,7 +279,7 @@
        (t
         (goto-char (point-min))
         (if (not top)
-           (mh-goto-header-end 0))
+            (mh-goto-header-end 0))
         (insert field-colon " " value "\n")))))))
 
 ;;;###mh-autoload
Index: emacs/lisp/mh-e/mh-inc.el
diff -u emacs/lisp/mh-e/mh-inc.el:1.13 emacs/lisp/mh-e/mh-inc.el:1.14
--- emacs/lisp/mh-e/mh-inc.el:1.13      Sun Jan 15 08:17:55 2006
+++ emacs/lisp/mh-e/mh-inc.el   Sun Jan 29 19:34:56 2006
@@ -1,5 +1,5 @@
 ;;; mh-inc.el --- MH-E "inc" and separate mail spool handling
-;;
+
 ;; Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc.
 
 ;; Author: Peter S. Galbraith <address@hidden>
@@ -26,33 +26,42 @@
 
 ;;; Commentary:
 
-;;  Support for inc. In addition to reading from the system mailbox, inc can
-;;  also be used to incorporate mail from multiple spool files into separate
-;;  folders. See "C-h v mh-inc-spool-list".
+;; Support for inc. In addition to reading from the system mailbox,
+;; inc can also be used to incorporate mail from multiple spool files
+;; into separate folders. See "C-h v mh-inc-spool-list".
 
 ;;; Change Log:
 
 ;;; Code:
 
-;;(message "> mh-inc")
-(eval-when-compile (require 'mh-acros))
+(require 'mh-e)
 (mh-require-cl)
-;;(message "< mh-inc")
-
-(defvar mh-inc-spool-map (make-sparse-keymap)
-  "Keymap for MH-E's mh-inc-spool commands.")
 
 (defvar mh-inc-spool-map-help nil
-  "Help text to for `mh-inc-spool-map'.")
+  "Help text for `mh-inc-spool-map'.")
 
 (define-key mh-inc-spool-map "?"
   '(lambda ()
      (interactive)
      (if mh-inc-spool-map-help
-         (let ((mh-help-messages (list (list nil mh-inc-spool-map-help))))
-           (mh-help))
+         (mh-help mh-inc-spool-map-help)
        (mh-ephem-message
-        "There are no keys defined yet.  Customize `mh-inc-spool-list'"))))
+        "There are no keys defined yet; customize `mh-inc-spool-list'"))))
+
+;;;###mh-autoload
+(defun mh-inc-spool-make ()
+  "Make all commands and defines keys for contents of `mh-inc-spool-list'."
+  (setq mh-inc-spool-map-help nil)
+  (when mh-inc-spool-list
+    (loop for elem in mh-inc-spool-list
+          do (let ((spool (nth 0 elem))
+                   (folder (nth 1 elem))
+                   (key (nth 2 elem)))
+               (progn
+                 (mh-inc-spool-generator folder spool)
+                 (mh-inc-spool-def-key key folder))))))
+
+(defalias 'mh-inc-spool-make-no-autoload 'mh-inc-spool-make)
 
 (defun mh-inc-spool-generator (folder spool)
   "Create a command to inc into FOLDER from SPOOL file."
@@ -62,7 +71,7 @@
     (set spool1 spool)
     (setf (symbol-function (intern (concat "mh-inc-spool-" folder)))
           `(lambda ()
-             ,(format "Inc spool file %s into folder %s" spool folder)
+             ,(format "Inc spool file %s into folder %s." spool folder)
              (interactive)
              (mh-inc-folder ,spool1 (concat "+" ,folder1))))))
 
@@ -71,32 +80,9 @@
   (when (not (= 0 key))
     (define-key mh-inc-spool-map (format "%c" key)
        (intern (concat "mh-inc-spool-" folder)))
-    (setq mh-inc-spool-map-help (concat mh-inc-spool-map-help "["
-                                        (char-to-string key)
-                                        "] inc " folder " folder\n"))))
-
-;; Shush compiler.
-(eval-when-compile (defvar mh-inc-spool-list))
-
-(defun mh-inc-spool-make ()
-  "Make all commands and defines keys for contents of `mh-inc-spool-list'."
-  (when mh-inc-spool-list
-    (setq mh-inc-spool-map-help nil)
-    (loop for elem in mh-inc-spool-list
-          do (let ((spool (nth 0 elem))
-                   (folder (nth 1 elem))
-                   (key (nth 2 elem)))
-               (progn
-                 (mh-inc-spool-generator folder spool)
-                 (mh-inc-spool-def-key key folder))))))
-
-;;;###mh-autoload
-(defun mh-inc-spool-list-set (symbol value)
-  "Set-default SYMBOL to VALUE to update the `mh-inc-spool-list' variable.
-Also rebuilds the user commands.
-This is called after 'customize is used to alter `mh-inc-spool-list'."
-  (set-default symbol value)
-  (mh-inc-spool-make))
+    (add-to-list 'mh-inc-spool-map-help
+                 (concat "[" (char-to-string key) "] inc " folder " folder\n")
+                 t)))
 
 (provide 'mh-inc)
 
Index: emacs/lisp/mh-e/mh-junk.el
diff -u emacs/lisp/mh-e/mh-junk.el:1.18 emacs/lisp/mh-e/mh-junk.el:1.19
--- emacs/lisp/mh-e/mh-junk.el:1.18     Sun Jan 15 08:17:55 2006
+++ emacs/lisp/mh-e/mh-junk.el  Sun Jan 29 19:34:56 2006
@@ -1,4 +1,4 @@
-;;; mh-junk.el --- Interface to anti-spam measures
+;;; mh-junk.el --- MH-E interface to anti-spam measures
 
 ;; Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
 
@@ -32,14 +32,10 @@
 
 ;;; Code:
 
-;;(message "< mh-junk")
-(eval-when-compile (require 'mh-acros))
-(mh-require-cl)
-(require 'mh-buffers)
 (require 'mh-e)
-;;(message "> mh-junk")
+(require 'mh-scan)
+(mh-require-cl)
 
-;; Interactive functions callable from the folder buffer
 ;;;###mh-autoload
 (defun mh-junk-blacklist (range)
   "Blacklist RANGE as spam.
@@ -108,6 +104,7 @@
 (defvar mh-spamassassin-executable (executable-find "spamassassin"))
 (defvar mh-sa-learn-executable (executable-find "sa-learn"))
 
+;;;###mh-autoload
 (defun mh-spamassassin-blacklist (msg)
   "Blacklist MSG with SpamAssassin.
 
@@ -189,7 +186,7 @@
 will need to run \"sa-learn --rebuild\" periodically. This can be
 done by adding the following to your crontab:
 
-    0 * * * *  sa-learn --rebuild > /dev/null 2>&1"
+    0 * * * *   sa-learn --rebuild > /dev/null 2>&1"
   (unless mh-spamassassin-executable
     (error "Unable to find the spamassassin executable"))
   (let ((current-folder mh-current-folder)
@@ -220,6 +217,7 @@
             (message "Blacklisting message %d...done" msg))
         (message "Blacklisting message %d...not done (from my address)" 
msg)))))
 
+;;;###mh-autoload
 (defun mh-spamassassin-whitelist (msg)
   "Whitelist MSG with SpamAssassin.
 
@@ -273,6 +271,7 @@
       (if (not buffer-exists)
           (kill-buffer nil)))))
 
+;;;###mh-autoload
 (defun mh-spamassassin-identify-spammers ()
   "Identify spammers who are repeat offenders.
 
@@ -322,6 +321,7 @@
 
 (defvar mh-bogofilter-executable (executable-find "bogofilter"))
 
+;;;###mh-autoload
 (defun mh-bogofilter-blacklist (msg)
   "Blacklist MSG with bogofilter.
 
@@ -375,6 +375,7 @@
     (call-process mh-bogofilter-executable msg-file mh-junk-background
                   nil "-s")))
 
+;;;###mh-autoload
 (defun mh-bogofilter-whitelist (msg)
   "Whitelist MSG with bogofilter.
 
@@ -391,6 +392,7 @@
 
 (defvar mh-spamprobe-executable (executable-find "spamprobe"))
 
+;;;###mh-autoload
 (defun mh-spamprobe-blacklist (msg)
   "Blacklist MSG with SpamProbe.
 
@@ -421,6 +423,7 @@
     (call-process mh-spamprobe-executable msg-file mh-junk-background
                   nil "spam")))
 
+;;;###mh-autoload
 (defun mh-spamprobe-whitelist (msg)
   "Whitelist MSG with SpamProbe.
 
Index: emacs/lisp/mh-e/mh-mime.el
diff -u emacs/lisp/mh-e/mh-mime.el:1.45 emacs/lisp/mh-e/mh-mime.el:1.46
--- emacs/lisp/mh-e/mh-mime.el:1.45     Mon Jan 16 20:05:14 2006
+++ emacs/lisp/mh-e/mh-mime.el  Sun Jan 29 19:34:56 2006
@@ -1,4 +1,4 @@
-;;; mh-mime.el --- MH-E support for composing MIME messages
+;;; mh-mime.el --- MH-E MIME support
 
 ;; Copyright (C) 1993, 1995,
 ;;  2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
@@ -27,669 +27,1036 @@
 
 ;;; Commentary:
 
-;; Internal support for MH-E package.
-;; Support for generating MH-style directives for mhn or mhbuild as well as
-;; MML (MIME Meta Language) tags. MH-style directives are supported by MH 6.8
-;; or later.
+;; Message composition of MIME message is done with either MH-style
+;; directives for mhn or mhbuild (MH 6.8 or later) or MML (MIME Meta
+;; Language) tags.
+
+;; TODO:
+;;   Paragraph code should not fill # lines if MIME enabled.
+;;   Implement mh-auto-mh-to-mime (if non-nil, \\[mh-send-letter]
+;;      invokes mh-mh-to-mime automatically before sending.)
+;;      Actually, instead of mh-auto-mh-to-mime,
+;;      should read automhnproc from profile.
+;;   MIME option to mh-forward command to move to content-description
+;;   insertion point.
 
 ;;; Change Log:
 
 ;;; Code:
 
-;;(message "> mh-mime")
-(eval-when-compile (require 'mh-acros))
-(mh-require-cl)
+(require 'mh-e)
+(require 'mh-gnus)                      ;needed because mh-gnus.el not compiled
 
+(require 'font-lock)
 (require 'gnus-util)
-(require 'mh-buffers)
-(require 'mh-comp)
-(require 'mh-gnus)
-;;(message "< mh-mime")
+(require 'mailcap)
+(require 'mm-decode)
+(require 'mm-view)
+(require 'mml)
 
 (autoload 'article-emphasize "gnus-art")
-(autoload 'gnus-article-goto-header "gnus-art")
 (autoload 'gnus-eval-format "gnus-spec")
-(autoload 'gnus-get-buffer-create "gnus")
+(autoload 'mail-content-type-get "mail-parse")
+(autoload 'mail-decode-encoded-word-string "mail-parse")
+(autoload 'mail-header-parse-content-type "mail-parse")
+(autoload 'mail-header-strip "mail-parse")
 (autoload 'message-options-set-recipient "message")
+(autoload 'mm-decode-body "mm-bodies")
 (autoload 'mm-uu-dissect "mm-uu")
 (autoload 'mml-unsecure-message "mml-sec")
 (autoload 'rfc2047-decode-region "rfc2047")
 (autoload 'widget-convert-button "wid-edit")
 
+
+
+;;; Variables
+
+;; This has to be a macro, since we do: (setf (mh-buffer-data) ...)
 ;;;###mh-autoload
-(defun mh-compose-insertion (&optional inline)
-  "Add tag to include a file such as an image or sound.
+(defmacro mh-buffer-data ()
+  "Convenience macro to get the MIME data structures of the current buffer."
+  `(gethash (current-buffer) mh-globals-hash))
+
+;; Structure to keep track of MIME handles on a per buffer basis.
+(mh-defstruct (mh-buffer-data (:conc-name mh-mime-)
+                              (:constructor mh-make-buffer-data))
+  (handles ())                          ; List of MIME handles
+  (handles-cache (make-hash-table))     ; Cache to avoid multiple decodes of
+                                        ; nested messages
+  (parts-count 0)                       ; The button number is generated from
+                                        ; this number
+  (part-index-hash (make-hash-table)))  ; Avoid incrementing the part number
+                                        ; for nested messages
+
+(defvar mh-mm-inline-media-tests
+  `(("image/jpeg"
+     mm-inline-image
+     (lambda (handle)
+       (mm-valid-and-fit-image-p 'jpeg handle)))
+    ("image/png"
+     mm-inline-image
+     (lambda (handle)
+       (mm-valid-and-fit-image-p 'png handle)))
+    ("image/gif"
+     mm-inline-image
+     (lambda (handle)
+       (mm-valid-and-fit-image-p 'gif handle)))
+    ("image/tiff"
+     mm-inline-image
+     (lambda (handle)
+       (mm-valid-and-fit-image-p 'tiff handle)) )
+    ("image/xbm"
+     mm-inline-image
+     (lambda (handle)
+       (mm-valid-and-fit-image-p 'xbm handle)))
+    ("image/x-xbitmap"
+     mm-inline-image
+     (lambda (handle)
+       (mm-valid-and-fit-image-p 'xbm handle)))
+    ("image/xpm"
+     mm-inline-image
+     (lambda (handle)
+       (mm-valid-and-fit-image-p 'xpm handle)))
+    ("image/x-pixmap"
+     mm-inline-image
+     (lambda (handle)
+       (mm-valid-and-fit-image-p 'xpm handle)))
+    ("image/bmp"
+     mm-inline-image
+     (lambda (handle)
+       (mm-valid-and-fit-image-p 'bmp handle)))
+    ("image/x-portable-bitmap"
+     mm-inline-image
+     (lambda (handle)
+       (mm-valid-and-fit-image-p 'pbm handle)))
+    ("text/plain" mm-inline-text identity)
+    ("text/enriched" mm-inline-text identity)
+    ("text/richtext" mm-inline-text identity)
+    ("text/x-patch" mm-display-patch-inline
+     (lambda (handle)
+       (locate-library "diff-mode")))
+    ("application/emacs-lisp" mm-display-elisp-inline identity)
+    ("application/x-emacs-lisp" mm-display-elisp-inline identity)
+    ("text/html"
+     ,(if (fboundp 'mm-inline-text-html) 'mm-inline-text-html 'mm-inline-text)
+     (lambda (handle)
+       (or (and (boundp 'mm-inline-text-html-renderer)
+                mm-inline-text-html-renderer)
+           (and (boundp 'mm-text-html-renderer) mm-text-html-renderer))))
+    ("text/x-vcard"
+     mm-inline-text-vcard
+     (lambda (handle)
+       (or (featurep 'vcard)
+           (locate-library "vcard"))))
+    ("message/delivery-status" mm-inline-text identity)
+    ("message/rfc822" mh-mm-inline-message identity)
+    ;;("message/partial" mm-inline-partial identity)
+    ;;("message/external-body" mm-inline-external-body identity)
+    ("text/.*" mm-inline-text identity)
+    ("audio/wav" mm-inline-audio
+     (lambda (handle)
+       (and (or (featurep 'nas-sound) (featurep 'native-sound))
+            (device-sound-enabled-p))))
+    ("audio/au"
+     mm-inline-audio
+     (lambda (handle)
+       (and (or (featurep 'nas-sound) (featurep 'native-sound))
+            (device-sound-enabled-p))))
+    ("application/pgp-signature" ignore identity)
+    ("application/x-pkcs7-signature" ignore identity)
+    ("application/pkcs7-signature" ignore identity)
+    ("application/x-pkcs7-mime" ignore identity)
+    ("application/pkcs7-mime" ignore identity)
+    ("multipart/alternative" ignore identity)
+    ("multipart/mixed" ignore identity)
+    ("multipart/related" ignore identity)
+    ;; Disable audio and image
+    ("audio/.*" ignore ignore)
+    ("image/.*" ignore ignore)
+    ;; Default to displaying as text
+    (".*" mm-inline-text mm-readable-p))
+  "Alist of media types/tests saying whether types can be displayed inline.")
 
-You are prompted for the filename containing the object, the
-media type if it cannot be determined automatically, and a
-content description. If you're using MH-style directives, you
-will also be prompted for additional attributes.
+(defvar mh-mime-save-parts-directory nil
+  "Default to use for `mh-mime-save-parts-default-directory'.
+Set from last use.")
 
-The option `mh-compose-insertion' controls what type of tags are
-inserted. Optional argument INLINE means make it an inline
-attachment."
-  (interactive "P")
-  (if (equal mh-compose-insertion 'mml)
-      (if inline
-          (mh-mml-attach-file "inline")
-        (mh-mml-attach-file))
-    (call-interactively 'mh-mh-attach-file)))
+;; Copied from gnus-art.el (should be checked for other cool things that can
+;; be added to the buttons)
+(defvar mh-mime-button-commands
+  '((mh-press-button "\r" "Toggle Display")))
+(defvar mh-mime-button-map
+  (let ((map (make-sparse-keymap)))
+    (unless (>= (string-to-number emacs-version) 21)
+      ;; XEmacs doesn't care.
+      (set-keymap-parent map mh-show-mode-map))
+    (mh-do-in-gnu-emacs
+     (define-key map [mouse-2] 'mh-push-button))
+    (mh-do-in-xemacs
+     (define-key map '(button2) 'mh-push-button))
+    (dolist (c mh-mime-button-commands)
+      (define-key map (cadr c) (car c)))
+    map))
+(defvar mh-mime-button-line-format-alist
+  '((?T long-type ?s)
+    (?d description ?s)
+    (?p index ?s)
+    (?e dots ?s)))
+(defvar mh-mime-button-line-format "%{%([%p. %d%T]%)%}%e\n")
+(defvar mh-mime-security-button-pressed nil)
+(defvar mh-mime-security-button-line-format "%{%([[%t:%i]%D]%)%}\n")
+(defvar mh-mime-security-button-end-line-format "%{%([[End of %t]%D]%)%}\n")
+(defvar mh-mime-security-button-line-format-alist
+  '((?t type ?s)
+    (?i info ?s)
+    (?d details ?s)
+    (?D pressed-details ?s)))
+(defvar mh-mime-security-button-map
+  (let ((map (make-sparse-keymap)))
+    (unless (>= (string-to-number emacs-version) 21)
+      (set-keymap-parent map mh-show-mode-map))
+    (define-key map "\r" 'mh-press-button)
+    (mh-do-in-gnu-emacs
+     (define-key map [mouse-2] 'mh-push-button))
+    (mh-do-in-xemacs
+     (define-key map '(button2) 'mh-push-button))
+    map))
+
+
+
+;;; MH-Folder Commands
+
+;; Alphabetical.
 
 ;;;###mh-autoload
-(defun mh-compose-forward (&optional description folder range)
-  "Add tag to forward a message.
+(defun mh-display-with-external-viewer (part-index)
+  "View attachment externally.
 
-You are prompted for a content DESCRIPTION, the name of the
-FOLDER in which the messages to forward are located, and a RANGE
-of messages, which defaults to the current message in that
-folder. Check the documentation of `mh-interactive-range' to see
-how RANGE is read in interactive use.
+If Emacs does not know how to view an attachment, you could save
+it into a file and then run some program to open it. It is
+easier, however, to launch the program directly from MH-E with
+this command. While you'll most likely use this to view
+spreadsheets and documents, it is also useful to use your browser
+to view HTML attachments with higher fidelity than what Emacs can
+provide.
 
-The option `mh-compose-insertion' controls what type of tags are inserted."
-  (interactive
-   (let* ((description
-           (mml-minibuffer-read-description))
-          (folder
-           (mh-prompt-for-folder "Message from"
-                                 mh-sent-from-folder nil))
-          (default
-            (if (and (equal folder mh-sent-from-folder)
-                     (numberp mh-sent-from-msg))
-                mh-sent-from-msg
-              (nth 0 (mh-translate-range folder "cur"))))
-          (range
-           (mh-read-range "Forward" folder
-                          (or (and default
-                                   (number-to-string default))
-                              t)
-                          t t)))
-     (list description folder range)))
-  (let ((messages (mapconcat 'identity (mh-list-to-string range) " ")))
-    (dolist (message (mh-translate-range folder messages))
-      (if (equal mh-compose-insertion 'mml)
-          (mh-mml-forward-message description folder (format "%s" message))
-        (mh-mh-forward-message description folder (format "%s" message))))))
+This command displays the attachment associated with the button
+under the cursor. If the cursor is not located over a button,
+then the cursor first moves to the next button, wrapping to the
+beginning of the message if necessary. You can provide a numeric
+prefix argument PART-INDEX to view the attachment labeled with
+that number.
 
-;; To do:
-;; paragraph code should not fill # lines if MIME enabled.
-;; implement mh-auto-mh-to-mime (if non-nil, \\[mh-send-letter]
-;;      invokes mh-mh-to-mime automatically before sending.)
-;;      actually, instead of mh-auto-mh-to-mime,
-;;      should read automhnproc from profile
-;; MIME option to mh-forward
-;; command to move to content-description insertion point
+This command tries to provide a reasonable default for the viewer
+by calling the Emacs function `mailcap-mime-info'. This function
+usually reads the file \"/etc/mailcap\"."
+  (interactive "P")
+  (when (consp part-index) (setq part-index (car part-index)))
+  (mh-folder-mime-action
+   part-index
+   #'(lambda ()
+       (let* ((part (get-text-property (point) 'mh-data))
+              (type (mm-handle-media-type part))
+              (methods (mapcar (lambda (x) (list (cdr (assoc 'viewer x))))
+                               (mailcap-mime-info type 'all)))
+              (def (caar methods))
+              (prompt (format "Viewer%s: " (if def
+                                               (format " (default %s)" def)
+                                             "")))
+              (method (completing-read prompt methods nil nil nil nil def))
+              (folder mh-show-folder-buffer)
+              (buffer-read-only nil))
+         (when (string-match "^[^% \t]+$" method)
+           (setq method (concat method " %s")))
+         (flet ((mm-handle-set-external-undisplayer (handle function)
+                  (mh-handle-set-external-undisplayer folder handle function)))
+           (unwind-protect (mm-display-external part method)
+             (set-buffer-modified-p nil)))))
+   nil))
 
-(defvar mh-mh-to-mime-args nil
-  "Extra arguments for \\[mh-mh-to-mime] to pass to the \"mhbuild\" command.
-The arguments are passed to \"mhbuild\" if \\[mh-mh-to-mime] is
-given a prefix argument. Normally default arguments to
-\"mhbuild\" are specified in the MH profile.")
+;;;###mh-autoload
+(defun mh-folder-inline-mime-part (part-index)
+  "Show attachment verbatim.
 
-(defvar mh-media-type-regexp
-  (concat (regexp-opt '("text" "image" "audio" "video" "application"
-                        "multipart" "message") t)
-          "/[-.+a-zA-Z0-9]+")
-  "Regexp matching valid media types used in MIME attachment compositions.")
+You can view the raw contents of an attachment with this command.
+This command displays (or hides) the contents of the attachment
+associated with the button under the cursor verbatim. If the
+cursor is not located over a button, then the cursor first moves
+to the next button, wrapping to the beginning of the message if
+necessary.
 
-(defvar mh-have-file-command 'undefined
-  "Cached value of function `mh-have-file-command'.
-Do not reference this variable directly as it might not have been
-initialized. Always use the command `mh-have-file-command'.")
+You can also provide a numeric prefix argument PART-INDEX to view
+the attachment labeled with that number."
+  (interactive "P")
+  (when (consp part-index) (setq part-index (car part-index)))
+  (mh-folder-mime-action part-index #'mh-mime-inline-part nil))
+
+(defun mh-mime-inline-part ()
+  "Toggle display of the raw MIME part."
+  (interactive)
+  (let* ((buffer-read-only nil)
+         (data (get-text-property (point) 'mh-data))
+         (inserted-flag (get-text-property (point) 'mh-mime-inserted))
+         (displayed-flag (mm-handle-displayed-p data))
+         (point (point))
+         start end)
+    (cond ((and data (not inserted-flag) (not displayed-flag))
+           (let ((contents (mm-get-part data)))
+             (add-text-properties (line-beginning-position) (line-end-position)
+                                  '(mh-mime-inserted t))
+             (setq start (point-marker))
+             (forward-line 1)
+             (mm-insert-inline data contents)
+             (setq end (point-marker))
+             (add-text-properties
+              start (progn (goto-char start) (line-end-position))
+              `(mh-region (,start . ,end)))))
+          ((and data (or inserted-flag displayed-flag))
+           (mh-press-button)
+           (message "MIME part already inserted")))
+    (goto-char point)
+    (set-buffer-modified-p nil)))
 
 ;;;###mh-autoload
-(defun mh-have-file-command ()
-  "Return t if 'file' command is on the system.
-'file -i' is used to get MIME type of composition insertion."
-  (when (eq mh-have-file-command 'undefined)
-    (setq mh-have-file-command
-          (and (fboundp 'executable-find)
-               (executable-find "file") ; file command exists
-                                        ;   and accepts -i and -b args.
-               (zerop (call-process "file" nil nil nil "-i" "-b"
-                                    (expand-file-name "inc" mh-progs))))))
-  mh-have-file-command)
+(defun mh-folder-save-mime-part (part-index)
+  "Save (output) attachment.
 
-(defvar mh-file-mime-type-substitutions
-  '(("application/msword" "\.xls" "application/ms-excel")
-    ("application/msword" "\.ppt" "application/ms-powerpoint")
-    ("text/plain" "\.vcf" "text/x-vcard"))
-  "Substitutions to make for Content-Type returned from file command.
-The first element is the Content-Type returned by the file command.
-The second element is a regexp matching the file name, usually the
-extension.
-The third element is the Content-Type to replace with.")
+This command saves the attachment associated with the button under the
+cursor. If the cursor is not located over a button, then the cursor
+first moves to the next button, wrapping to the beginning of the
+message if necessary.
 
-(defun mh-file-mime-type-substitute (content-type filename)
-  "Return possibly changed CONTENT-TYPE on the FILENAME.
-Substitutions are made from the `mh-file-mime-type-substitutions'
-variable."
-  (let ((subst mh-file-mime-type-substitutions)
-        (type) (match) (answer content-type)
-        (case-fold-search t))
-    (while subst
-      (setq type (car (car subst))
-            match (elt (car subst) 1))
-      (if (and (string-equal content-type type)
-               (string-match match filename))
-          (setq answer (elt (car subst) 2)
-                subst nil)
-        (setq subst (cdr subst))))
-    answer))
+You can also provide a numeric prefix argument PART-INDEX to save the
+attachment labeled with that number.
+
+This command prompts you for a filename and suggests a specific name
+if it is available."
+  (interactive "P")
+  (when (consp part-index) (setq part-index (car part-index)))
+  (mh-folder-mime-action part-index #'mh-mime-save-part nil))
+
+(defun mh-mime-save-part ()
+  "Save MIME part at point."
+  (interactive)
+  (let ((data (get-text-property (point) 'mh-data)))
+    (when data
+      (let ((mm-default-directory
+             (file-name-as-directory (or mh-mime-save-parts-directory
+                                         default-directory))))
+        (mh-mm-save-part data)
+        (setq mh-mime-save-parts-directory mm-default-directory)))))
 
 ;;;###mh-autoload
-(defun mh-file-mime-type (filename)
-  "Return MIME type of FILENAME from file command.
-Returns nil if file command not on system."
-  (cond
-   ((not (mh-have-file-command))
-    nil)                                ;no file command, exit now
-   ((not (and (file-exists-p filename)
-              (file-readable-p filename)))
-    nil)                               ;no file or not readable, ditto
-   (t
-    (save-excursion
-      (let ((tmp-buffer (get-buffer-create mh-temp-buffer)))
-        (set-buffer tmp-buffer)
-        (unwind-protect
-            (progn
-              (call-process "file" nil '(t nil) nil "-b" "-i"
-                            (expand-file-name filename))
-              (goto-char (point-min))
-              (if (not (re-search-forward mh-media-type-regexp nil t))
-                  nil
-                (mh-file-mime-type-substitute (match-string 0) filename)))
-          (kill-buffer tmp-buffer)))))))
+(defun mh-folder-toggle-mime-part (part-index)
+  "View attachment.
 
-(defun mh-minibuffer-read-type (filename &optional default)
-  "Return the content type associated with the given FILENAME.
-If the \"file\" command exists and recognizes the given file,
-then its value is returned\; otherwise, the user is prompted for
-a type (see `mailcap-mime-types' and for Emacs 20,
-`mh-mime-content-types').
-Optional argument DEFAULT is returned if a type isn't entered."
-  (mailcap-parse-mimetypes)
-  (let* ((default (or default
-                      (mm-default-file-encoding filename)
-                      "application/octet-stream"))
-         (probed-type (mh-file-mime-type filename))
-         (type (or (and (not (equal probed-type "application/octet-stream"))
-                        probed-type)
-                   (completing-read
-                    (format "Content type (default %s): " default)
-                    (mapcar 'list (mailcap-mime-types))))))
-    (if (not (equal type ""))
-        type
-      default)))
-
-;; RFC 2045 - Multipurpose Internet Mail Extensions (MIME) Part One:
-;;            Format of Internet Message Bodies.
-;; RFC 2046 - Multipurpose Internet Mail Extensions (MIME) Part Two:
-;;            Media Types.
-;; RFC 2049 - Multipurpose Internet Mail Extensions (MIME) Part Five:
-;;            Conformance Criteria and Examples.
-;; RFC 2017 - Definition of the URL MIME External-Body Access-Type
-;; RFC 1738 - Uniform Resource Locators (URL)
-(defvar mh-access-types
-  '(("anon-ftp")        ; RFC2046 Anonymous File Transfer Protocol
-    ("file")            ; RFC1738 Host-specific file names
-    ("ftp")             ; RFC2046 File Transfer Protocol
-    ("gopher")          ; RFC1738 The Gopher Protocol
-    ("http")            ; RFC1738 Hypertext Transfer Protocol
-    ("local-file")      ; RFC2046 Local file access
-    ("mail-server")     ; RFC2046 mail-server Electronic mail address
-    ("mailto")          ; RFC1738 Electronic mail address
-    ("news")            ; RFC1738 Usenet news
-    ("nntp")            ; RFC1738 Usenet news using NNTP access
-    ("propspero")       ; RFC1738 Prospero Directory Service
-    ("telnet")          ; RFC1738 Telnet
-    ("tftp")            ; RFC2046 Trivial File Transfer Protocol
-    ("url")             ; RFC2017 URL scheme MIME access-type Protocol
-    ("wais"))           ; RFC1738 Wide Area Information Servers
-  "Valid MIME access-type values.")
+This command displays (or hides) the attachment associated with
+the button under the cursor. If the cursor is not located over a
+button, then the cursor first moves to the next button, wrapping
+to the beginning of the message if necessary. This command has
+the advantage over related commands of working from the MH-Folder
+buffer.
+
+You can also provide a numeric prefix argument PART-INDEX to view
+the attachment labeled with that number. If Emacs does not know
+how to display the attachment, then Emacs offers to save the
+attachment in a file."
+  (interactive "P")
+  (when (consp part-index) (setq part-index (car part-index)))
+  (mh-folder-mime-action part-index #'mh-press-button t))
 
 ;;;###mh-autoload
-(defun mh-mh-attach-file (filename type description attributes)
-  "Add a tag to insert a MIME message part from a file.
-You are prompted for the FILENAME containing the object, the
-media TYPE if it cannot be determined automatically, and a
-content DESCRIPTION. In addition, you are also prompted for
-additional ATTRIBUTES.
+(defun mh-mime-save-parts (prompt)
+  "Save attachments.
 
-See also \\[mh-mh-to-mime]."
-  (interactive (let ((filename (mml-minibuffer-read-file "Attach file: ")))
-                 (list
-                  filename
-                  (mh-minibuffer-read-type filename)
-                  (mml-minibuffer-read-description)
-                  (read-string "Attributes: "
-                               (concat "name=\""
-                                       (file-name-nondirectory filename)
-                                       "\"")))))
-  (mh-mh-compose-type filename type description attributes))
+You can save all of the attachments at once with this command.
+The attachments are saved in the directory specified by the
+option `mh-mime-save-parts-default-directory' unless you use a
+prefix argument PROMPT in which case you are prompted for the
+directory. These directories may be superseded by MH profile
+components, since this function calls on \"mhstore\" (\"mhn\") to
+do the work."
+  (interactive "P")
+  (let ((msg (if (eq major-mode 'mh-show-mode)
+                 (mh-show-buffer-message-number)
+               (mh-get-msg-num t)))
+        (folder (if (eq major-mode 'mh-show-mode)
+                    mh-show-folder-buffer
+                  mh-current-folder))
+        (command (if (mh-variant-p 'nmh) "mhstore" "mhn"))
+        (directory
+         (cond
+          ((and (or prompt
+                    (equal nil mh-mime-save-parts-default-directory)
+                    (equal t mh-mime-save-parts-default-directory))
+                (not mh-mime-save-parts-directory))
+           (read-file-name "Store in directory: " nil nil t nil))
+          ((and (or prompt
+                    (equal t mh-mime-save-parts-default-directory))
+                mh-mime-save-parts-directory)
+           (read-file-name (format
+                            "Store in directory (default %s): "
+                            mh-mime-save-parts-directory)
+                           "" mh-mime-save-parts-directory t ""))
+          ((stringp mh-mime-save-parts-default-directory)
+           mh-mime-save-parts-default-directory)
+          (t
+           mh-mime-save-parts-directory))))
+    (if (and (equal directory "") mh-mime-save-parts-directory)
+        (setq directory mh-mime-save-parts-directory))
+    (if (not (file-directory-p directory))
+        (message "No directory specified")
+      (if (equal nil mh-mime-save-parts-default-directory)
+          (setq mh-mime-save-parts-directory directory))
+      (save-excursion
+        (set-buffer (get-buffer-create mh-log-buffer))
+        (cd directory)
+        (setq mh-mime-save-parts-directory directory)
+        (let ((initial-size (mh-truncate-log-buffer)))
+          (apply 'call-process
+                 (expand-file-name command mh-progs) nil t nil
+                 (mh-list-to-string (list folder msg "-auto")))
+          (if (> (buffer-size) initial-size)
+              (save-window-excursion
+                (switch-to-buffer-other-window mh-log-buffer)
+                (sit-for 3))))))))
 
-(defun mh-mh-compose-type (filename type
-                                     &optional description attributes comment)
-  "Insert an MH-style directive to insert a file.
-The file specified by FILENAME is encoded as TYPE. An optional
-DESCRIPTION is used as the Content-Description field, optional
-set of ATTRIBUTES and an optional COMMENT can also be included."
-  (beginning-of-line)
-  (insert "#" type)
-  (and attributes
-       (insert "; " attributes))
-  (and comment
-       (insert " (" comment ")"))
-  (insert " [")
-  (and description
-       (insert description))
-  (insert "] " (expand-file-name filename))
-  (insert "\n"))
+;;;###mh-autoload
+(defun mh-toggle-mh-decode-mime-flag ()
+  "Toggle the value of `mh-decode-mime-flag'."
+  (interactive)
+  (setq mh-decode-mime-flag (not mh-decode-mime-flag))
+  (mh-show nil t)
+  (message "%s" (if mh-decode-mime-flag
+                    "Processing attachments normally"
+                  "Displaying raw message")))
 
 ;;;###mh-autoload
-(defun mh-mh-compose-anon-ftp (host filename type description)
-  "Add tag to include anonymous ftp reference to a file.
+(defun mh-toggle-mime-buttons ()
+  "Toggle option `mh-display-buttons-for-inline-parts-flag'."
+  (interactive)
+  (setq mh-display-buttons-for-inline-parts-flag
+        (not mh-display-buttons-for-inline-parts-flag))
+  (mh-show nil t))
 
-You can have your message initiate an \"ftp\" transfer when the
-recipient reads the message. You are prompted for the remote HOST
-and FILENAME, the media TYPE, and the content DESCRIPTION.
+
 
-See also \\[mh-mh-to-mime]."
-  (interactive (list
-                (read-string "Remote host: ")
-                (read-string "Remote filename: ")
-                (mh-minibuffer-read-type "DUMMY-FILENAME")
-                (mml-minibuffer-read-description)))
-  (mh-mh-compose-external-type "anon-ftp" host filename
-                               type description))
+;;; MIME Display Routines
 
-;;;###mh-autoload
-(defun mh-mh-compose-external-compressed-tar (host filename description)
-  "Add tag to include anonymous ftp reference to a compressed tar file.
+(defun mh-mm-inline-message (handle)
+  "Display message, HANDLE.
+The function decodes the message and displays it. It avoids
+decoding the same message multiple times."
+  (let ((b (point))
+        (clean-message-header mh-clean-message-header-flag)
+        (invisible-headers mh-invisible-header-fields-compiled)
+        (visible-headers nil))
+    (save-excursion
+      (save-restriction
+        (narrow-to-region b b)
+        (mm-insert-part handle)
+        (mh-mime-display
+         (or (gethash handle (mh-mime-handles-cache (mh-buffer-data)))
+             (setf (gethash handle (mh-mime-handles-cache (mh-buffer-data)))
+                   (let ((handles (mm-dissect-buffer nil)))
+                     (if handles
+                         (mm-uu-dissect-text-parts handles)
+                       (setq handles (mm-uu-dissect)))
+                     (setf (mh-mime-handles (mh-buffer-data))
+                           (mm-merge-handles
+                            handles (mh-mime-handles (mh-buffer-data))))
+                     handles))))
 
-In addition to retrieving the file via anonymous \"ftp\" as per
-the command \\[mh-mh-compose-anon-ftp], the file will also be
-uncompressed and untarred. You are prompted for the remote HOST
-and FILENAME and the content DESCRIPTION.
+        (goto-char (point-min))
+        (mh-show-xface)
+        (cond (clean-message-header
+               (mh-clean-msg-header (point-min)
+                                    invisible-headers
+                                    visible-headers)
+               (goto-char (point-min)))
+              (t
+               (mh-start-of-uncleaned-message)))
+        (mh-decode-message-header)
+        (mh-show-addr)
+        ;; The other highlighting types don't need anything special
+        (when (eq mh-highlight-citation-style 'gnus)
+          (mh-gnus-article-highlight-citation))
+        (goto-char (point-min))
+        (insert "\n------- Forwarded Message\n\n")
+        (mh-display-smileys)
+        (mh-display-emphasis)
+        (mm-handle-set-undisplayer
+         handle
+         `(lambda ()
+            (let (buffer-read-only)
+              (if (fboundp 'remove-specifier)
+                  ;; This is only valid on XEmacs.
+                  (mapcar (lambda (prop)
+                            (remove-specifier
+                             (face-property 'default prop) (current-buffer)))
+                          '(background background-pixmap foreground)))
+              (delete-region ,(point-min-marker) ,(point-max-marker)))))))))
 
-See also \\[mh-mh-to-mime]."
-  (interactive (list
-                (read-string "Remote host: ")
-                (read-string "Remote filename: ")
-                (mml-minibuffer-read-description)))
-  (mh-mh-compose-external-type "anon-ftp" host filename
-                               "application/octet-stream"
-                               description
-                               "type=tar; conversions=x-compress"
-                               "mode=image"))
+;;;###mh-autoload
+(defun mh-decode-message-header ()
+  "Decode RFC2047 encoded message header fields."
+  (when mh-decode-mime-flag
+    (let ((buffer-read-only nil))
+      (rfc2047-decode-region (point-min) (mh-mail-header-end)))))
 
 ;;;###mh-autoload
-(defun mh-mh-compose-external-type (access-type host filename type
-                                                &optional description
-                                                attributes parameters
-                                                comment)
-  "Add tag to refer to a remote file.
+(defun mh-mime-display (&optional pre-dissected-handles)
+  "Display (and possibly decode) MIME handles.
+Optional argument, PRE-DISSECTED-HANDLES is a list of MIME
+handles. If present they are displayed otherwise the buffer is
+parsed and then displayed."
+  (let ((handles ())
+        (folder mh-show-folder-buffer)
+        (raw-message-data (buffer-string)))
+    (flet ((mm-handle-set-external-undisplayer
+            (handle function)
+            (mh-handle-set-external-undisplayer folder handle function)))
+      (goto-char (point-min))
+      (unless (search-forward "\n\n" nil t)
+        (goto-char (point-max))
+        (insert "\n\n"))
 
-This command is a general utility for referencing external files.
-In fact, all of the other commands that insert directives to
-access external files call this command. You are prompted for the
-ACCESS-TYPE, remote HOST and FILENAME, and content TYPE. If you
-provide a prefix argument, you are also prompted for a content
-DESCRIPTION, ATTRIBUTES, PARAMETERS, and a COMMENT.
+      (condition-case err
+          (progn
+            ;; If needed dissect the current buffer
+            (if pre-dissected-handles
+                (setq handles pre-dissected-handles)
+              (if (setq handles (mm-dissect-buffer nil))
+                  (mm-uu-dissect-text-parts handles)
+                (setq handles (mm-uu-dissect)))
+              (setf (mh-mime-handles (mh-buffer-data))
+                    (mm-merge-handles handles
+                                      (mh-mime-handles (mh-buffer-data))))
+              (unless handles
+                (mh-decode-message-body)))
 
-See also \\[mh-mh-to-mime]."
-  (interactive (list
-                (completing-read "Access type: " mh-access-types)
-                (read-string "Remote host: ")
-                (read-string "Remote filename: ")
-                (mh-minibuffer-read-type "DUMMY-FILENAME")
-                (if current-prefix-arg (mml-minibuffer-read-description))
-                (if current-prefix-arg (read-string "Attributes: "))
-                (if current-prefix-arg (read-string "Parameters: "))
-                (if current-prefix-arg (read-string "Comment: "))))
-  (beginning-of-line)
-  (insert "#@" type)
-  (and attributes
-       (insert "; " attributes))
-  (and comment
-       (insert " (" comment ") "))
-  (insert " [")
-  (and description
-       (insert description))
-  (insert "] ")
-  (insert "access-type=" access-type "; ")
-  (insert "site=" host)
-  (insert "; name=" (file-name-nondirectory filename))
-  (let ((directory (file-name-directory filename)))
-    (and directory
-         (insert "; directory=\"" directory "\"")))
-  (and parameters
-       (insert "; " parameters))
-  (insert "\n"))
+            (cond ((and handles
+                        (or (not (stringp (car handles)))
+                            (cdr handles)))
+                   ;; Go to start of message body
+                   (goto-char (point-min))
+                   (or (search-forward "\n\n" nil t)
+                       (goto-char (point-max)))
 
-;;;###mh-autoload
-(defun mh-mh-forward-message (&optional description folder messages)
-  "Add tag to forward a message.
-You are prompted for a content DESCRIPTION, the name of the
-FOLDER in which the messages to forward are located, and the
-MESSAGES' numbers.
+                   ;; Delete the body
+                   (delete-region (point) (point-max))
 
-See also \\[mh-mh-to-mime]."
-  (interactive (list
-                (mml-minibuffer-read-description)
-                (mh-prompt-for-folder "Message from" mh-sent-from-folder nil)
-                (read-string (concat "Messages"
-                                     (if (numberp mh-sent-from-msg)
-                                         (format " (default %d): "
-                                                 mh-sent-from-msg)
-                                       ": ")))))
-  (beginning-of-line)
-  (insert "#forw [")
-  (and description
-       (not (string= description ""))
-       (insert description))
-  (insert "]")
-  (and folder
-       (not (string= folder ""))
-       (insert " " folder))
-  (if (and messages
-           (not (string= messages "")))
-      (let ((start (point)))
-        (insert " " messages)
-        (subst-char-in-region start (point) ?, ? ))
-    (if (numberp mh-sent-from-msg)
-        (insert " " (int-to-string mh-sent-from-msg))))
-  (insert "\n"))
+                   ;; Display the MIME handles
+                   (mh-mime-display-part handles))
+                  (t
+                   (mh-signature-highlight))))
+        (error
+         (message "Could not display body: %s" (error-message-string err))
+         (delete-region (point-min) (point-max))
+         (insert raw-message-data))))))
 
-;;;###mh-autoload
-(defun mh-mh-to-mime (&optional extra-args)
-  "Compose MIME message from MH-style directives.
+(defun mh-decode-message-body ()
+  "Decode message based on charset.
+If message has been encoded for transfer take that into account."
+  (let (ct charset cte)
+    (goto-char (point-min))
+    (re-search-forward "\n\n" nil t)
+    (save-restriction
+      (narrow-to-region (point-min) (point))
+      (setq ct (ignore-errors (mail-header-parse-content-type
+                               (message-fetch-field "Content-Type" t)))
+            charset (mail-content-type-get ct 'charset)
+            cte (message-fetch-field "Content-Transfer-Encoding")))
+    (when (stringp cte) (setq cte (mail-header-strip cte)))
+    (when (or (not ct) (equal (car ct) "text/plain"))
+      (save-restriction
+        (narrow-to-region (min (1+ (mh-mail-header-end)) (point-max))
+                          (point-max))
+        (mm-decode-body charset
+                        (and cte (intern (downcase
+                                          (gnus-strip-whitespace cte))))
+                        (car ct))))))
 
-Typically, you send a message with attachments just like any other
-message. However, you may take a sneak preview of the MIME encoding if
-you wish by running this command.
+(defun mh-mime-display-part (handle)
+  "Decides the viewer to call based on the type of HANDLE."
+  (cond ((null handle)
+         nil)
+        ((not (stringp (car handle)))
+         (mh-mime-display-single handle))
+        ((equal (car handle) "multipart/alternative")
+         (mh-mime-display-alternative (cdr handle)))
+        ((and mh-pgp-support-flag
+              (or (equal (car handle) "multipart/signed")
+                  (equal (car handle) "multipart/encrypted")))
+         (mh-mime-display-security handle))
+        (t
+         (mh-mime-display-mixed (cdr handle)))))
 
-If you wish to pass additional arguments to \"mhbuild\" (\"mhn\")
-to affect how it builds your message, use the option
-`mh-mh-to-mime-args'. For example, you can build a consistency
-check into the message by setting `mh-mh-to-mime-args' to
-\"-check\". The recipient of your message can then run \"mhbuild
--check\" on the message--\"mhbuild\" (\"mhn\") will complain if
-the message has been corrupted on the way. This command only
-consults this option when given a prefix argument EXTRA-ARGS.
+(defun mh-mime-display-mixed (handles)
+  "Display the list of MIME parts, HANDLES recursively."
+  (mapcar #'mh-mime-display-part handles))
 
-The hook `mh-mh-to-mime-hook' is called after the message has been
-formatted.
+(defun mh-mime-display-alternative (handles)
+  "Choose among the alternatives, HANDLES the part that will be displayed.
+If no part is preferred then all the parts are displayed."
+  (let* ((preferred (mm-preferred-alternative handles))
+         (others (loop for x in handles unless (eq x preferred) collect x)))
+    (cond ((and preferred
+                (stringp (car preferred)))
+           (mh-mime-display-part preferred)
+           (mh-mime-maybe-display-alternatives others))
+          (preferred
+           (save-restriction
+             (narrow-to-region (point) (if (eobp) (point) (1+ (point))))
+             (mh-mime-display-single preferred)
+             (mh-mime-maybe-display-alternatives others)
+             (goto-char (point-max))))
+          (t
+           (mh-mime-display-mixed handles)))))
 
-The effects of this command can be undone by running
-\\[mh-mh-to-mime-undo]."
-  (interactive "*P")
-  (mh-mh-quote-unescaped-sharp)
-  (save-buffer)
-  (message "Running %s..." (if (mh-variant-p 'nmh) "mhbuild" "mhn"))
-  (cond
-   ((mh-variant-p 'nmh)
-    (mh-exec-cmd-error nil
-                       "mhbuild"
-                       (if extra-args mh-mh-to-mime-args)
-                       buffer-file-name))
-   (t
-    (mh-exec-cmd-error (format "mhdraft=%s" buffer-file-name)
-                       "mhn"
-                       (if extra-args mh-mh-to-mime-args)
-                       buffer-file-name)))
-  (revert-buffer t t)
-  (message "Running %s...done" (if (mh-variant-p 'nmh) "mhbuild" "mhn"))
-  (run-hooks 'mh-mh-to-mime-hook))
+(defun mh-mime-maybe-display-alternatives (alternatives)
+  "Show buttons for ALTERNATIVES.
+If `mh-mime-display-alternatives-flag' is non-nil then display
+buttons for alternative parts that are usually suppressed."
+  (when (and mh-display-buttons-for-alternatives-flag alternatives)
+    (insert "\n----------------------------------------------------\n")
+    (insert "Alternatives:\n")
+    (dolist (x alternatives)
+      (insert "\n")
+      (mh-insert-mime-button x (mh-mime-part-index x) nil))
+    (insert "\n----------------------------------------------------\n")))
 
-(defun mh-mh-quote-unescaped-sharp ()
-  "Quote \"#\" characters that haven't been quoted for \"mhbuild\".
-If the \"#\" character is present in the first column, but it isn't
-part of a MH-style directive then \"mhbuild\" gives an error.
-This function will quote all such characters."
-  (save-excursion
-    (goto-char (point-min))
-    (while (re-search-forward "^#" nil t)
-      (beginning-of-line)
-      (unless (mh-mh-directive-present-p (point) (line-end-position))
-        (insert "#"))
-      (goto-char (line-end-position)))))
+(defun mh-mime-display-security (handle)
+  "Display PGP encrypted/signed message, HANDLE."
+  (save-restriction
+    (narrow-to-region (point) (point))
+    (insert "\n")
+    (mh-insert-mime-security-button handle)
+    (mh-mime-display-mixed (cdr handle))
+    (insert "\n")
+    (let ((mh-mime-security-button-line-format
+           mh-mime-security-button-end-line-format))
+      (mh-insert-mime-security-button handle))
+    (mm-set-handle-multipart-parameter
+     handle 'mh-region (cons (point-min-marker) (point-max-marker)))))
 
-;;;###mh-autoload
-(defun mh-mh-to-mime-undo (noconfirm)
-  "Undo effects of \\[mh-mh-to-mime].
+(defun mh-mime-display-single (handle)
+  "Display a leaf node, HANDLE in the MIME tree."
+  (let* ((type (mm-handle-media-type handle))
+         (small-image-flag (mh-small-image-p handle))
+         (attachmentp (equal (car (mm-handle-disposition handle))
+                             "attachment"))
+         (inlinep (and (equal (car (mm-handle-disposition handle)) "inline")
+                       (mm-inlinable-p handle)
+                       (mm-inlined-p handle)))
+         (displayp (or inlinep                   ; show if inline OR
+                       (mh-inline-vcard-p handle);      inline vcard OR
+                       (and (not attachmentp)    ;      if not an attachment
+                            (or small-image-flag ;        and small image
+                                                 ;        and user wants inline
+                                (and (not (equal
+                                           (mm-handle-media-supertype handle)
+                                           "image"))
+                                     (mm-inlinable-p handle)
+                                     (mm-inlined-p handle)))))))
+    (save-restriction
+      (narrow-to-region (point) (if (eobp) (point) (1+ (point))))
+      (cond ((and mh-pgp-support-flag
+                  (equal type "application/pgp-signature"))
+             nil)             ; skip signatures as they are already handled...
+            ((not displayp)
+             (insert "\n")
+             (mh-insert-mime-button handle (mh-mime-part-index handle) nil))
+            ((and displayp
+                  (not mh-display-buttons-for-inline-parts-flag))
+             (or (mm-display-part handle)
+                 (mm-display-part handle))
+             (mh-signature-highlight handle))
+            ((and displayp
+                  mh-display-buttons-for-inline-parts-flag)
+             (insert "\n")
+             (mh-insert-mime-button handle (mh-mime-part-index handle) nil)
+             (forward-line -1)
+             (mh-mm-display-part handle)))
+      (goto-char (point-max)))))
 
-It does this by reverting to a backup file. You are prompted to
-confirm this action, but you can avoid the confirmation by adding
-a prefix argument NOCONFIRM."
-  (interactive "*P")
-  (if (null buffer-file-name)
-      (error "Buffer does not seem to be associated with any file"))
-  (let ((backup-strings '("," "#"))
-        backup-file)
-    (while (and backup-strings
-                (not (file-exists-p
-                      (setq backup-file
-                            (concat (file-name-directory buffer-file-name)
-                                    (car backup-strings)
-                                    (file-name-nondirectory buffer-file-name)
-                                    ".orig")))))
-      (setq backup-strings (cdr backup-strings)))
-    (or backup-strings
-        (error "Backup file for %s no longer exists" buffer-file-name))
-    (or noconfirm
-        (yes-or-no-p (format "Revert buffer from file %s? "
-                             backup-file))
-        (error "Revert not confirmed"))
-    (let ((buffer-read-only nil))
-      (erase-buffer)
-      (insert-file-contents backup-file))
-    (after-find-file nil)))
-
-;;;###mh-autoload
-(defun mh-mh-directive-present-p (&optional begin end)
-  "Check if the text between BEGIN and END might be a MH-style directive.
-The optional argument BEGIN defaults to the beginning of the
-buffer, while END defaults to the the end of the buffer."
-  (unless begin (setq begin (point-min)))
-  (unless end (setq end (point-max)))
-  (save-excursion
-    (block 'search-for-mh-directive
-      (goto-char begin)
-      (while (re-search-forward "^#" end t)
-        (let ((s (buffer-substring-no-properties (point) (line-end-position))))
-          (cond ((equal s ""))
-                ((string-match "^forw[ \t\n]+" s)
-                 (return-from 'search-for-mh-directive t))
-                (t (let ((first-token (car (split-string s "[ \t;@]"))))
-                     (when (and first-token
-                                (string-match mh-media-type-regexp
-                                              first-token))
-                       (return-from 'search-for-mh-directive t)))))))
-      nil)))
-
-
-
-;;; MIME composition functions
-
-;;;###mh-autoload
-(defun mh-mml-to-mime ()
-  "Compose MIME message from MML tags.
-
-Typically, you send a message with attachments just like any
-other message. However, you may take a sneak preview of the MIME
-encoding if you wish by running this command.
-
-This action can be undone by running \\[undo]."
-  (interactive)
-  (require 'message)
-  (when mh-pgp-support-flag ;; This is only needed for PGP
-    (message-options-set-recipient))
-  (let ((saved-text (buffer-string))
-        (buffer (current-buffer))
-        (modified-flag (buffer-modified-p)))
-    (condition-case err (mml-to-mime)
-      (error
-       (with-current-buffer buffer
-         (delete-region (point-min) (point-max))
-         (insert saved-text)
-         (set-buffer-modified-p modified-flag))
-       (error (error-message-string err))))))
+;; There is a bug in Gnus inline image display due to which an extra line
+;; gets inserted every time it is viewed. To work around that problem we are
+;; using an extra property 'mh-region to remember the region that is added
+;; when the button is clicked. The region is then deleted to make sure that
+;; no extra lines get inserted.
+(defun mh-mm-display-part (handle)
+  "Toggle display of button for MIME part, HANDLE."
+  (beginning-of-line)
+  (let ((id (get-text-property (point) 'mh-part))
+        (point (point))
+        (window (selected-window))
+        (mail-parse-charset 'nil)
+        (mail-parse-ignored-charsets nil)
+        region buffer-read-only)
+    (save-excursion
+      (unwind-protect
+          (let ((win (get-buffer-window (current-buffer) t)))
+            (when win
+              (select-window win))
+            (goto-char point)
 
-;;;###mh-autoload
-(defun mh-mml-forward-message (description folder message)
-  "Forward a message as attachment.
+            (if (mm-handle-displayed-p handle)
+                ;; This will remove the part.
+                (progn
+                  ;; Delete the button and displayed part (if any)
+                  (let ((region (get-text-property point 'mh-region)))
+                    (when region
+                      (mh-funcall-if-exists
+                       remove-images (car region) (cdr region)))
+                    (mm-display-part handle)
+                    (when region
+                      (delete-region (car region) (cdr region))))
+                  ;; Delete button (if it still remains). This happens for
+                  ;; externally displayed parts where the previous step does
+                  ;; nothing.
+                  (unless (eolp)
+                    (delete-region (point) (progn (forward-line) (point)))))
+              (save-restriction
+                (delete-region (point) (progn (forward-line 1) (point)))
+                (narrow-to-region (point) (point))
+                ;; Maybe we need another unwind-protect here.
+                (when (equal (mm-handle-media-supertype handle) "image")
+                  (insert "\n"))
+                (when (and (not (eq (ignore-errors (mm-display-part handle))
+                                    'inline))
+                           (equal (mm-handle-media-supertype handle)
+                                  "image"))
+                  (goto-char (point-min))
+                  (delete-char 1))
+                (when (equal (mm-handle-media-supertype handle) "text")
+                  (when (eq mh-highlight-citation-style 'gnus)
+                    (mh-gnus-article-highlight-citation))
+                  (mh-display-smileys)
+                  (mh-display-emphasis)
+                  (mh-signature-highlight handle))
+                (setq region (cons (progn (goto-char (point-min))
+                                          (point-marker))
+                                   (progn (goto-char (point-max))
+                                          (point-marker)))))))
+        (when (window-live-p window)
+          (select-window window))
+        (goto-char point)
+        (beginning-of-line)
+        (mh-insert-mime-button handle id (mm-handle-displayed-p handle))
+        (goto-char point)
+        (when region
+          (add-text-properties (line-beginning-position) (line-end-position)
+                               `(mh-region ,region)))))))
 
-The function will prompt the user for a DESCRIPTION, a FOLDER and
-MESSAGE number."
-  (let ((msg (if (and (equal message "") (numberp mh-sent-from-msg))
-                 mh-sent-from-msg
-               (string-to-number message))))
-    (cond ((integerp msg)
-           (if (string= "" description)
-               ;; Rationale: mml-attach-file constructs a malformed composition
-               ;; if the description string is empty.  This fixes SF #625168.
-               (mml-attach-file (format "%s%s/%d"
-                                        mh-user-path (substring folder 1) msg)
-                                "message/rfc822")
-             (mml-attach-file (format "%s%s/%d"
-                                      mh-user-path (substring folder 1) msg)
-                              "message/rfc822"
-                              description)))
-          (t (error "The message number, %s, is not a integer" msg)))))
+(defun mh-mime-part-index (handle)
+  "Generate the button number for MIME part, HANDLE.
+Notice that a hash table is used to display the same number when
+buttons need to be displayed multiple times (for instance when
+nested messages are opened)."
+  (or (gethash handle (mh-mime-part-index-hash (mh-buffer-data)))
+      (setf (gethash handle (mh-mime-part-index-hash (mh-buffer-data)))
+            (incf (mh-mime-parts-count (mh-buffer-data))))))
 
-(defvar mh-mml-cryptographic-method-history ())
+(defun mh-small-image-p (handle)
+  "Decide whether HANDLE is a \"small\" image that can be displayed inline.
+This is only useful if a Content-Disposition header is not present."
+  (let ((media-test (caddr (assoc (car (mm-handle-type handle))
+                                  mh-mm-inline-media-tests)))
+        (mm-inline-large-images t))
+    (and media-test
+         (equal (mm-handle-media-supertype handle) "image")
+         (funcall media-test handle) ; Since mm-inline-large-images is T,
+                                        ; this only tells us if the image is
+                                        ; something that emacs can display
+         (let* ((image (mm-get-image handle)))
+           (or (mh-do-in-xemacs
+                 (and (mh-funcall-if-exists glyphp image)
+                      (< (glyph-width image)
+                         (or mh-max-inline-image-width (window-pixel-width)))
+                      (< (glyph-height image)
+                         (or mh-max-inline-image-height
+                             (window-pixel-height)))))
+               (mh-do-in-gnu-emacs
+                 (let ((size (mh-funcall-if-exists image-size image)))
+                   (and size
+                        (< (cdr size) (or mh-max-inline-image-height
+                                          (1- (window-height))))
+                        (< (car size) (or mh-max-inline-image-width
+                                          (window-width)))))))))))
 
-;;;###mh-autoload
-(defun mh-mml-query-cryptographic-method ()
-  "Read the cryptographic method to use."
-  (if current-prefix-arg
-      (let ((def (or (car mh-mml-cryptographic-method-history)
-                     mh-mml-method-default)))
-        (completing-read (format "Method (default %s): " def)
-                         '(("pgp") ("pgpmime") ("smime"))
-                         nil t nil 'mh-mml-cryptographic-method-history def))
-    mh-mml-method-default))
+(defun mh-inline-vcard-p (handle)
+  "Decide if HANDLE is a vcard that must be displayed inline."
+  (let ((type (mm-handle-type handle)))
+    (and (or (featurep 'vcard) (fboundp 'vcard-pretty-print))
+         (consp type)
+         (equal (car type) "text/x-vcard")
+         (save-excursion
+           (save-restriction
+             (widen)
+             (goto-char (point-min))
+             (not (mh-signature-separator-p)))))))
 
-;;;###mh-autoload
-(defun mh-mml-attach-file (&optional disposition)
-  "Add a tag to insert a MIME message part from a file.
+(defun mh-signature-highlight (&optional handle)
+  "Highlight message signature in HANDLE.
+The optional argument, HANDLE is a MIME handle if the function is
+being used to highlight the signature in a MIME part."
+  (let ((regexp
+         (cond ((not handle) "^-- $")
+               ((not (and (equal (mm-handle-media-supertype handle) "text")
+                          (equal (mm-handle-media-subtype handle) "html")))
+                "^-- $")
+               ((eq (mh-mm-text-html-renderer) 'lynx) "^   --$")
+               (t "^--$"))))
+    (save-excursion
+      (goto-char (point-max))
+      (when (re-search-backward regexp nil t)
+        (mh-do-in-gnu-emacs
+          (let ((ov (make-overlay (point) (point-max))))
+            (overlay-put ov 'face 'mh-show-signature)
+            (overlay-put ov 'evaporate t)))
+        (mh-do-in-xemacs
+          (set-extent-property (make-extent (point) (point-max))
+                               'face 'mh-show-signature))))))
 
-You are prompted for the filename containing the object, the
-media type if it cannot be determined automatically, a content
-description and the DISPOSITION of the attachment.
+
 
-This is basically `mml-attach-file' from Gnus, modified such that a prefix
-argument yields an \"inline\" disposition and Content-Type is determined
-automatically."
-  (let* ((file (mml-minibuffer-read-file "Attach file: "))
-         (type (mh-minibuffer-read-type file))
-         (description (mml-minibuffer-read-description))
-         (dispos (or disposition
-                     (mml-minibuffer-read-disposition type))))
-    (mml-insert-empty-tag 'part 'type type 'filename file
-                          'disposition dispos 'description description)))
+;;; Button Display
 
 ;; Shush compiler.
-(eval-when-compile (defvar mh-identity-pgg-default-user-id))
-
-(defun mh-secure-message (method mode &optional identity)
-  "Add tag to encrypt or sign message.
+(eval-when-compile (mh-do-in-xemacs (defvar dots) (defvar type) (defvar ov)))
 
-METHOD should be one of: \"pgpmime\", \"pgp\", \"smime\".
-MODE should be one of: \"sign\", \"encrypt\", \"signencrypt\", \"none\".
-IDENTITY is optionally the default-user-id to use."
-  (if (not mh-pgp-support-flag)
-      (error "Your version of Gnus does not support PGP/GPG")
-    ;; Check the arguments
-    (let ((valid-methods (list "pgpmime" "pgp" "smime"))
-          (valid-modes (list "sign" "encrypt" "signencrypt" "none")))
-      (if (not (member method valid-methods))
-          (error "Method %s is invalid" method))
-      (if (not (member mode valid-modes))
-          (error "Mode %s is invalid" mode))
-      (mml-unsecure-message)
-      (if (not (string= mode "none"))
-        (save-excursion
-          (goto-char (point-min))
-          (mh-goto-header-end 1)
-          (if mh-identity-pgg-default-user-id
-              (mml-insert-tag 'secure 'method method 'mode mode
-                              'sender mh-identity-pgg-default-user-id)
-            (mml-insert-tag 'secure 'method method 'mode mode)))))))
+(defun mh-insert-mime-button (handle index displayed)
+  "Insert MIME button for HANDLE.
+INDEX is the part number that will be DISPLAYED. It is also used
+by commands like \"K v\" which operate on individual MIME parts."
+  ;; The button could be displayed by a previous decode. In that case
+  ;; undisplay it if we need a hidden button.
+  (when (and (mm-handle-displayed-p handle) (not displayed))
+    (mm-display-part handle))
+  (let ((name (or (mail-content-type-get (mm-handle-type handle) 'name)
+                  (mail-content-type-get (mm-handle-disposition handle)
+                                         'filename)
+                  (mail-content-type-get (mm-handle-type handle) 'url)
+                  ""))
+        (type (mm-handle-media-type handle))
+        (description (mail-decode-encoded-word-string
+                      (or (mm-handle-description handle) "")))
+        (dots (if (or displayed (mm-handle-displayed-p handle)) "   " "..."))
+        long-type begin end)
+    (if (string-match ".*/" name) (setq name (substring name (match-end 0))))
+    (setq long-type (concat type (and (not (equal name ""))
+                                      (concat "; " name))))
+    (unless (equal description "")
+      (setq long-type (concat " --- " long-type)))
+    (unless (bolp) (insert "\n"))
+    (setq begin (point))
+    (gnus-eval-format
+     mh-mime-button-line-format mh-mime-button-line-format-alist
+     `(,@(gnus-local-map-property mh-mime-button-map)
+         mh-callback mh-mm-display-part
+         mh-part ,index
+         mh-data ,handle))
+    (setq end (point))
+    (widget-convert-button
+     'link begin end
+     :mime-handle handle
+     :action 'mh-widget-press-button
+     :button-keymap mh-mime-button-map
+     :help-echo
+     "Mouse-2 click or press RET (in show buffer) to toggle display")
+    (dolist (ov (mh-funcall-if-exists overlays-in begin end))
+      (mh-funcall-if-exists overlay-put ov 'evaporate t))))
 
-;;;###mh-autoload
-(defun mh-mml-unsecure-message ()
-  "Remove any secure message tags."
-  (interactive)
-  (if (not mh-pgp-support-flag)
-      (error "Your version of Gnus does not support PGP/GPG")
-    (mml-unsecure-message)))
+;; Shush compiler.
+(eval-when-compile
+  (when (< emacs-major-version 22)
+    (defvar  mm-verify-function-alist)
+    (defvar  mm-decrypt-function-alist))
+  (mh-do-in-xemacs
+    (defvar pressed-details)))
 
-;;;###mh-autoload
-(defun mh-mml-secure-message-sign (method)
-  "Add tag to sign the message.
+(defun mh-insert-mime-security-button (handle)
+  "Display buttons for PGP message, HANDLE."
+  (let* ((protocol (mm-handle-multipart-ctl-parameter handle 'protocol))
+         (crypto-type (or (nth 2 (assoc protocol mm-verify-function-alist))
+                          (nth 2 (assoc protocol mm-decrypt-function-alist))
+                          "Unknown"))
+         (type (concat crypto-type
+                       (if (equal (car handle) "multipart/signed")
+                           " Signed" " Encrypted")
+                       " Part"))
+         (info (or (mm-handle-multipart-ctl-parameter handle 'gnus-info)
+                   "Undecided"))
+         (details (mm-handle-multipart-ctl-parameter handle 'gnus-details))
+         pressed-details begin end face)
+    (setq details (if details (concat "\n" details) ""))
+    (setq pressed-details (if mh-mime-security-button-pressed details ""))
+    (setq face (mh-mime-security-button-face info))
+    (unless (bolp) (insert "\n"))
+    (setq begin (point))
+    (gnus-eval-format
+     mh-mime-security-button-line-format
+     mh-mime-security-button-line-format-alist
+     `(,@(gnus-local-map-property mh-mime-security-button-map)
+         mh-button-pressed ,mh-mime-security-button-pressed
+         mh-callback mh-mime-security-press-button
+         mh-line-format ,mh-mime-security-button-line-format
+         mh-data ,handle))
+    (setq end (point))
+    (widget-convert-button 'link begin end
+                           :mime-handle handle
+                           :action 'mh-widget-press-button
+                           :button-keymap mh-mime-security-button-map
+                           :button-face face
+                           :help-echo "Mouse-2 click or press RET (in show 
buffer) to see security details.")
+    (dolist (ov (mh-funcall-if-exists overlays-in begin end))
+      (mh-funcall-if-exists overlay-put ov 'evaporate t))
+    (when (equal info "Failed")
+      (let* ((type (if (equal (car handle) "multipart/signed")
+                       "verification" "decryption"))
+             (warning (if (equal type "decryption")
+                          "(passphrase may be incorrect)" "")))
+        (message "%s %s failed %s" crypto-type type warning)))))
 
-A proper multipart message is created for you when you send the
-message. Use the command \\[mh-mml-unsecure-message] to remove
-this tag. Use a prefix argument METHOD to be prompted for one of
-the possible security methods (see `mh-mml-method-default')."
-  (interactive (list (mh-mml-query-cryptographic-method)))
-  (mh-secure-message method "sign" mh-identity-pgg-default-user-id))
+(defun mh-mime-security-button-face (info)
+  "Return the button face to use for encrypted/signed mail based on INFO."
+  (cond ((string-match "OK" info)       ;Decrypted mail
+         'mh-show-pgg-good)
+        ((string-match "Failed" info)   ;Decryption failed or signature invalid
+         'mh-show-pgg-bad)
+        ((string-match "Undecided" info);Unprocessed mail
+         'mh-show-pgg-unknown)
+        ((string-match "Untrusted" info);Key not trusted
+         'mh-show-pgg-unknown)
+        (t
+         'mh-show-pgg-good)))
 
-;;;###mh-autoload
-(defun mh-mml-secure-message-encrypt (method)
-  "Add tag to encrypt the message.
+
 
-A proper multipart message is created for you when you send the
-message. Use the command \\[mh-mml-unsecure-message] to remove
-this tag. Use a prefix argument METHOD to be prompted for one of
-the possible security methods (see `mh-mml-method-default')."
-  (interactive (list (mh-mml-query-cryptographic-method)))
-  (mh-secure-message method "encrypt" mh-identity-pgg-default-user-id))
+;;; Button Handlers
 
-;;;###mh-autoload
-(defun mh-mml-secure-message-signencrypt (method)
-  "Add tag to encrypt and sign the message.
+(defun mh-folder-mime-action (part-index action include-security-flag)
+  "Go to PART-INDEX and carry out ACTION.
 
-A proper multipart message is created for you when you send the
-message. Use the command \\[mh-mml-unsecure-message] to remove
-this tag. Use a prefix argument METHOD to be prompted for one of
-the possible security methods (see `mh-mml-method-default')."
-  (interactive (list (mh-mml-query-cryptographic-method)))
-  (mh-secure-message method "signencrypt" mh-identity-pgg-default-user-id))
+If PART-INDEX is nil then go to the next part in the buffer. The
+search for the next buffer wraps around if end of buffer is reached.
+If argument INCLUDE-SECURITY-FLAG is non-nil then include security
+info buttons when searching for a suitable parts."
+  (unless mh-showing-mode
+    (mh-show))
+  (mh-in-show-buffer (mh-show-buffer)
+    (let ((criterion
+           (cond (part-index
+                  (lambda (p)
+                    (let ((part (get-text-property p 'mh-part)))
+                      (and (integerp part) (= part part-index)))))
+                 (t (lambda (p)
+                      (if include-security-flag
+                          (get-text-property p 'mh-data)
+                        (integerp (get-text-property p 'mh-part)))))))
+          (point (point)))
+      (cond ((and (get-text-property point 'mh-part)
+                  (or (null part-index)
+                      (= (get-text-property point 'mh-part) part-index)))
+             (funcall action))
+            ((and (get-text-property point 'mh-data)
+                  include-security-flag
+                  (null part-index))
+             (funcall action))
+            (t
+             (mh-goto-next-button nil criterion)
+             (if (= (point) point)
+                 (message "No matching MIME part found")
+               (funcall action)))))))
+
+;;;###mh-autoload
+(defun mh-goto-next-button (backward-flag &optional criterion)
+  "Search for next button satisfying criterion.
+
+If BACKWARD-FLAG is non-nil search backward in the buffer for a mime
+button.
+If CRITERION is a function or a symbol which has a function binding
+then that function must return non-nil at the button we stop."
+  (unless (or (and (symbolp criterion) (fboundp criterion))
+              (functionp criterion))
+    (setq criterion (lambda (x) t)))
+  ;; Move to the next button in the buffer satisfying criterion
+  (goto-char (or (save-excursion
+                   (beginning-of-line)
+                   ;; Find point before current button
+                   (let ((point-before-current-button
+                          (save-excursion
+                            (while (get-text-property (point) 'mh-data)
+                              (unless (= (forward-line
+                                          (if backward-flag 1 -1))
+                                         0)
+                                (if backward-flag
+                                    (goto-char (point-min))
+                                  (goto-char (point-max)))))
+                            (point))))
+                     ;; Skip over current button
+                     (while (and (get-text-property (point) 'mh-data)
+                                 (not (if backward-flag (bobp) (eobp))))
+                       (forward-line (if backward-flag -1 1)))
+                     ;; Stop at next MIME button if any exists.
+                     (block loop
+                       (while (/= (progn
+                                    (unless (= (forward-line
+                                                (if backward-flag -1 1))
+                                               0)
+                                      (if backward-flag
+                                          (goto-char (point-max))
+                                        (goto-char (point-min)))
+                                      (beginning-of-line))
+                                    (point))
+                                  point-before-current-button)
+                         (when (and (get-text-property (point) 'mh-data)
+                                    (funcall criterion (point)))
+                           (return-from loop (point))))
+                       nil)))
+                 (point))))
 
-;;;###mh-autoload
-(defun mh-mml-tag-present-p ()
-  "Check if the current buffer has text which may be a MML tag."
-  (save-excursion
-    (goto-char (point-min))
-    (re-search-forward
-     (concat
-      "\\(<#\\(mml\\|part\\)\\(.\\|\n\\)*>[ \n\t]*<#/\\(mml\\|part\\)>\\|"
-      "^<#secure.+>$\\)")
-     nil t)))
+(defun mh-widget-press-button (widget el)
+  "Callback for widget, WIDGET.
+Parameter EL is unused."
+  (goto-char (widget-get widget :from))
+  (mh-press-button))
 
-
+(defun mh-press-button ()
+  "View contents of button.
 
-;;; MIME cleanup
+This command is a toggle so if you use it again on the same
+attachment, the attachment is hidden."
+  (interactive)
+  (let ((mm-inline-media-tests mh-mm-inline-media-tests)
+        (data (get-text-property (point) 'mh-data))
+        (function (get-text-property (point) 'mh-callback))
+        (buffer-read-only nil)
+        (folder mh-show-folder-buffer))
+    (flet ((mm-handle-set-external-undisplayer
+            (handle function)
+            (mh-handle-set-external-undisplayer folder handle function)))
+      (when (and function (eolp))
+        (backward-char))
+      (unwind-protect (and function (funcall function data))
+        (set-buffer-modified-p nil)))))
 
-;;;###mh-autoload
-(defun mh-mime-cleanup ()
-  "Free the decoded MIME parts."
-  (let ((mime-data (gethash (current-buffer) mh-globals-hash)))
-    ;; This is for Emacs, what about XEmacs?
-    (mh-funcall-if-exists remove-images (point-min) (point-max))
-    (when mime-data
-      (mm-destroy-parts (mh-mime-handles mime-data))
-      (remhash (current-buffer) mh-globals-hash))))
+(defun mh-push-button (event)
+  "Click MIME button for EVENT.
 
-;;;###mh-autoload
-(defun mh-destroy-postponed-handles ()
-  "Free MIME data for externally displayed MIME parts."
-  (let ((mime-data (mh-buffer-data)))
-    (when mime-data
-      (mm-destroy-parts (mh-mime-handles mime-data)))
-    (remhash (current-buffer) mh-globals-hash)))
+If the MIME part is visible then it is removed. Otherwise the
+part is displayed. This function is called when the mouse is used
+to click the MIME button."
+  (interactive "e")
+  (mh-do-at-event-location event
+    (let ((folder mh-show-folder-buffer)
+          (mm-inline-media-tests mh-mm-inline-media-tests)
+          (data (get-text-property (point) 'mh-data))
+          (function (get-text-property (point) 'mh-callback)))
+      (flet ((mm-handle-set-external-undisplayer (handle func)
+               (mh-handle-set-external-undisplayer folder handle func)))
+        (and function (funcall function data))))))
 
 (defun mh-handle-set-external-undisplayer (folder handle function)
   "Replacement for `mm-handle-set-external-undisplayer'.
@@ -707,10 +1074,55 @@
           (push new-handle (mh-mime-handles (mh-buffer-data)))))
     (mm-handle-set-undisplayer handle function)))
 
+(defun mh-mime-security-press-button (handle)
+  "Callback from security button for part HANDLE."
+  (if (mm-handle-multipart-ctl-parameter handle 'gnus-info)
+      (mh-mime-security-show-details handle)
+    (let ((region (mm-handle-multipart-ctl-parameter handle 'mh-region))
+          point)
+      (setq point (point))
+      (goto-char (car region))
+      (delete-region (car region) (cdr region))
+      (with-current-buffer (mm-handle-multipart-ctl-parameter handle 'buffer)
+        (let* ((mm-verify-option 'known)
+               (mm-decrypt-option 'known)
+               (new (mm-possibly-verify-or-decrypt (cdr handle) handle)))
+          (unless (eq new (cdr handle))
+            (mm-destroy-parts (cdr handle))
+            (setcdr handle new))))
+      (mh-mime-display-security handle)
+      (goto-char point))))
+
+;; I rewrote the security part because Gnus doesn't seem to ever minimize
+;; the button. That is once the mime-security button is pressed there seems
+;; to be no way of getting rid of the inserted text.
+(defun mh-mime-security-show-details (handle)
+  "Toggle display of detailed security info for HANDLE."
+  (let ((details (mm-handle-multipart-ctl-parameter handle 'gnus-details)))
+    (when details
+      (let ((mh-mime-security-button-pressed
+             (not (get-text-property (point) 'mh-button-pressed)))
+            (mh-mime-security-button-line-format
+             (get-text-property (point) 'mh-line-format)))
+        (forward-char -1)
+        (while (eq (get-text-property (point) 'mh-line-format)
+                   mh-mime-security-button-line-format)
+          (forward-char -1))
+        (forward-char)
+        (save-restriction
+          (narrow-to-region (point) (point))
+          (mh-insert-mime-security-button handle))
+        (delete-region
+         (point)
+         (or (text-property-not-all
+              (point) (point-max)
+              'mh-line-format mh-mime-security-button-line-format)
+             (point-max)))
+        (forward-line -1)))))
+
 
 
-;;; MIME transformations
-(eval-when-compile (require 'font-lock))
+;;; Miscellaneous Article Washing
 
 ;;;###mh-autoload
 (defun mh-add-missing-mime-version-header ()
@@ -727,19 +1139,6 @@
         (goto-char (point-min))
         (insert "MIME-Version: 1.0\n")))))
 
-(defun mh-small-show-buffer-p ()
-  "Check if show buffer is small.
-This is used to decide if smileys and graphical emphasis will be
-displayed."
-  (let ((max nil))
-    (when (and (boundp 'font-lock-maximum-size) font-lock-maximum-size)
-      (cond ((numberp font-lock-maximum-size)
-             (setq max font-lock-maximum-size))
-            ((listp font-lock-maximum-size)
-             (setq max (cdr (or (assoc 'mh-show-mode font-lock-maximum-size)
-                                (assoc t font-lock-maximum-size)))))))
-    (or (not (numberp max)) (>= (/ max 8) (buffer-size)))))
-
 ;;;###mh-autoload
 (defun mh-display-smileys ()
   "Display smileys."
@@ -755,770 +1154,646 @@
         (goto-char (point-min))
         (article-emphasize)))))
 
-;; Copied from gnus-art.el (should be checked for other cool things that can
-;; be added to the buttons)
-(defvar mh-mime-button-commands
-  '((mh-press-button "\r" "Toggle Display")))
-(defvar mh-mime-button-map
-  (let ((map (make-sparse-keymap)))
-    (unless (>= (string-to-number emacs-version) 21)
-      ;; XEmacs doesn't care.
-      (set-keymap-parent map mh-show-mode-map))
-    (mh-do-in-gnu-emacs
-     (define-key map [mouse-2] 'mh-push-button))
-    (mh-do-in-xemacs
-     (define-key map '(button2) 'mh-push-button))
-    (dolist (c mh-mime-button-commands)
-      (define-key map (cadr c) (car c)))
-    map))
-(defvar mh-mime-button-line-format-alist
-  '((?T long-type ?s)
-    (?d description ?s)
-    (?p index ?s)
-    (?e dots ?s)))
-(defvar mh-mime-button-line-format "%{%([%p. %d%T]%)%}%e\n")
-(defvar mh-mime-security-button-pressed nil)
-(defvar mh-mime-security-button-line-format "%{%([[%t:%i]%D]%)%}\n")
-(defvar mh-mime-security-button-end-line-format "%{%([[End of %t]%D]%)%}\n")
-(defvar mh-mime-security-button-line-format-alist
-  '((?t type ?s)
-    (?i info ?s)
-    (?d details ?s)
-    (?D pressed-details ?s)))
-(defvar mh-mime-security-button-map
-  (let ((map (make-sparse-keymap)))
-    (unless (>= (string-to-number emacs-version) 21)
-      (set-keymap-parent map mh-show-mode-map))
-    (define-key map "\r" 'mh-press-button)
-    (mh-do-in-gnu-emacs
-     (define-key map [mouse-2] 'mh-push-button))
-    (mh-do-in-xemacs
-     (define-key map '(button2) 'mh-push-button))
-    map))
-
-(defvar mh-mime-save-parts-directory nil
-  "Default to use for `mh-mime-save-parts-default-directory'.
-Set from last use.")
-
-;;;###mh-autoload
-(defun mh-mime-save-parts (prompt)
-  "Save attachments.
-
-You can save all of the attachments at once with this command.
-The attachments are saved in the directory specified by the
-option `mh-mime-save-parts-default-directory' unless you use a
-prefix argument PROMPT in which case you are prompted for the
-directory. These directories may be superseded by MH profile
-components, since this function calls on \"mhstore\" (\"mhn\") to
-do the work."
-  (interactive "P")
-  (let ((msg (if (eq major-mode 'mh-show-mode)
-                 (mh-show-buffer-message-number)
-               (mh-get-msg-num t)))
-        (folder (if (eq major-mode 'mh-show-mode)
-                    mh-show-folder-buffer
-                  mh-current-folder))
-        (command (if (mh-variant-p 'nmh) "mhstore" "mhn"))
-        (directory
-         (cond
-          ((and (or prompt
-                    (equal nil mh-mime-save-parts-default-directory)
-                    (equal t mh-mime-save-parts-default-directory))
-                (not mh-mime-save-parts-directory))
-           (read-file-name "Store in directory: " nil nil t nil))
-          ((and (or prompt
-                    (equal t mh-mime-save-parts-default-directory))
-                mh-mime-save-parts-directory)
-           (read-file-name (format
-                            "Store in directory (default %s): "
-                            mh-mime-save-parts-directory)
-                           "" mh-mime-save-parts-directory t ""))
-          ((stringp mh-mime-save-parts-default-directory)
-           mh-mime-save-parts-default-directory)
-          (t
-           mh-mime-save-parts-directory))))
-    (if (and (equal directory "") mh-mime-save-parts-directory)
-        (setq directory mh-mime-save-parts-directory))
-    (if (not (file-directory-p directory))
-        (message "No directory specified")
-      (if (equal nil mh-mime-save-parts-default-directory)
-          (setq mh-mime-save-parts-directory directory))
-      (save-excursion
-        (set-buffer (get-buffer-create mh-log-buffer))
-        (cd directory)
-        (setq mh-mime-save-parts-directory directory)
-        (let ((initial-size (mh-truncate-log-buffer)))
-          (apply 'call-process
-                 (expand-file-name command mh-progs) nil t nil
-                 (mh-list-to-string (list folder msg "-auto")))
-          (if (> (buffer-size) initial-size)
-              (save-window-excursion
-                (switch-to-buffer-other-window mh-log-buffer)
-                (sit-for 3))))))))
-
-;; Avoid errors if gnus-sum isn't loaded yet...
-(defvar gnus-newsgroup-charset nil)
-(defvar gnus-newsgroup-name nil)
+(defun mh-small-show-buffer-p ()
+  "Check if show buffer is small.
+This is used to decide if smileys and graphical emphasis should be
+displayed."
+  (let ((max nil))
+    (when (and (boundp 'font-lock-maximum-size) font-lock-maximum-size)
+      (cond ((numberp font-lock-maximum-size)
+             (setq max font-lock-maximum-size))
+            ((listp font-lock-maximum-size)
+             (setq max (cdr (or (assoc 'mh-show-mode font-lock-maximum-size)
+                                (assoc t font-lock-maximum-size)))))))
+    (or (not (numberp max)) (>= (/ max 8) (buffer-size)))))
 
-(defun mh-decode-message-body ()
-  "Decode message based on charset.
-If message has been encoded for transfer take that into account."
-  (let (ct charset cte)
-    (goto-char (point-min))
-    (re-search-forward "\n\n" nil t)
-    (save-restriction
-      (narrow-to-region (point-min) (point))
-      (setq ct (ignore-errors (mail-header-parse-content-type
-                               (message-fetch-field "Content-Type" t)))
-            charset (mail-content-type-get ct 'charset)
-            cte (message-fetch-field "Content-Transfer-Encoding")))
-    (when (stringp cte) (setq cte (mail-header-strip cte)))
-    (when (or (not ct) (equal (car ct) "text/plain"))
-      (save-restriction
-        (narrow-to-region (min (1+ (mh-mail-header-end)) (point-max))
-                          (point-max))
-        (mm-decode-body charset
-                        (and cte (intern (downcase
-                                          (gnus-strip-whitespace cte))))
-                        (car ct))))))
+
 
-;;;###mh-autoload
-(defun mh-toggle-mh-decode-mime-flag ()
-  "Toggle the value of `mh-decode-mime-flag'."
-  (interactive)
-  (setq mh-decode-mime-flag (not mh-decode-mime-flag))
-  (mh-show nil t)
-  (message "%s" (if mh-decode-mime-flag
-                    "Processing attachments normally"
-                  "Displaying raw message")))
+;;; MH-Letter Commands
 
-;;;###mh-autoload
-(defun mh-decode-message-header ()
-  "Decode RFC2047 encoded message header fields."
-  (when mh-decode-mime-flag
-    (let ((buffer-read-only nil))
-      (rfc2047-decode-region (point-min) (mh-mail-header-end)))))
+;; MH-E commands are alphabetical; specific support routines follow command.
 
 ;;;###mh-autoload
-(defun mh-mime-display (&optional pre-dissected-handles)
-  "Display (and possibly decode) MIME handles.
-Optional argument, PRE-DISSECTED-HANDLES is a list of MIME
-handles. If present they are displayed otherwise the buffer is
-parsed and then displayed."
-  (let ((handles ())
-        (folder mh-show-folder-buffer)
-        (raw-message-data (buffer-string)))
-    (flet ((mm-handle-set-external-undisplayer
-            (handle function)
-            (mh-handle-set-external-undisplayer folder handle function)))
-      (goto-char (point-min))
-      (unless (search-forward "\n\n" nil t)
-        (goto-char (point-max))
-        (insert "\n\n"))
+(defun mh-compose-forward (&optional description folder range)
+  "Add tag to forward a message.
 
-      (condition-case err
-          (progn
-            ;; If needed dissect the current buffer
-            (if pre-dissected-handles
-                (setq handles pre-dissected-handles)
-              (if (setq handles (mm-dissect-buffer nil))
-                  (when (fboundp 'mm-uu-dissect-text-parts)
-                    (mm-uu-dissect-text-parts handles))
-                (setq handles (mm-uu-dissect)))
-              (setf (mh-mime-handles (mh-buffer-data))
-                    (mm-merge-handles handles
-                                      (mh-mime-handles (mh-buffer-data))))
-              (unless handles (mh-decode-message-body)))
+You are prompted for a content DESCRIPTION, the name of the
+FOLDER in which the messages to forward are located, and a RANGE
+of messages, which defaults to the current message in that
+folder. Check the documentation of `mh-interactive-range' to see
+how RANGE is read in interactive use.
 
-            (cond ((and handles
-                        (or (not (stringp (car handles))) (cdr handles)))
-                   ;; Goto start of message body
-                   (goto-char (point-min))
-                   (or (search-forward "\n\n" nil t) (goto-char (point-max)))
+The option `mh-compose-insertion' controls what type of tags are inserted."
+  (interactive
+   (let* ((description
+           (mml-minibuffer-read-description))
+          (folder
+           (mh-prompt-for-folder "Message from"
+                                 mh-sent-from-folder nil))
+          (default
+            (if (and (equal folder mh-sent-from-folder)
+                     (numberp mh-sent-from-msg))
+                mh-sent-from-msg
+              (nth 0 (mh-translate-range folder "cur"))))
+          (range
+           (mh-read-range "Forward" folder
+                          (or (and default
+                                   (number-to-string default))
+                              t)
+                          t t)))
+     (list description folder range)))
+  (let ((messages (mapconcat 'identity (mh-list-to-string range) " ")))
+    (dolist (message (mh-translate-range folder messages))
+      (if (equal mh-compose-insertion 'mml)
+          (mh-mml-forward-message description folder (format "%s" message))
+        (mh-mh-forward-message description folder (format "%s" message))))))
 
-                   ;; Delete the body
-                   (delete-region (point) (point-max))
+;;;###mh-autoload
+(defun mh-mml-forward-message (description folder message)
+  "Forward a message as attachment.
 
-                   ;; Display the MIME handles
-                   (mh-mime-display-part handles))
-                  (t (mh-signature-highlight))))
-        (error
-         (message "Could not display body: %s" (error-message-string err))
-         (delete-region (point-min) (point-max))
-         (insert raw-message-data))))))
+The function will prompt the user for a DESCRIPTION, a FOLDER and
+MESSAGE number."
+  (let ((msg (if (and (equal message "") (numberp mh-sent-from-msg))
+                 mh-sent-from-msg
+               (string-to-number message))))
+    (cond ((integerp msg)
+           (if (string= "" description)
+               ;; Rationale: mml-attach-file constructs a malformed composition
+               ;; if the description string is empty.  This fixes SF #625168.
+               (mml-attach-file (format "%s%s/%d"
+                                        mh-user-path (substring folder 1) msg)
+                                "message/rfc822")
+             (mml-attach-file (format "%s%s/%d"
+                                      mh-user-path (substring folder 1) msg)
+                              "message/rfc822"
+                              description)))
+          (t (error "The message number, %s, is not a integer" msg)))))
 
-(defun mh-mime-display-part (handle)
-  "Decides the viewer to call based on the type of HANDLE."
-  (cond ((null handle) nil)
-        ((not (stringp (car handle)))
-         (mh-mime-display-single handle))
-        ((equal (car handle) "multipart/alternative")
-         (mh-mime-display-alternative (cdr handle)))
-        ((and mh-pgp-support-flag
-              (or (equal (car handle) "multipart/signed")
-                  (equal (car handle) "multipart/encrypted")))
-         (mh-mime-display-security handle))
-        (t (mh-mime-display-mixed (cdr handle)))))
+(defun mh-mh-forward-message (&optional description folder messages)
+  "Add tag to forward a message.
+You are prompted for a content DESCRIPTION, the name of the
+FOLDER in which the messages to forward are located, and the
+MESSAGES' numbers.
 
-(defun mh-mime-display-alternative (handles)
-  "Choose among the alternatives, HANDLES the part that will be displayed.
-If no part is preferred then all the parts are displayed."
-  (let* ((preferred (mm-preferred-alternative handles))
-         (others (loop for x in handles unless (eq x preferred) collect x)))
-    (cond ((and preferred (stringp (car preferred)))
-           (mh-mime-display-part preferred)
-           (mh-mime-maybe-display-alternatives others))
-          (preferred
-           (save-restriction
-             (narrow-to-region (point) (if (eobp) (point) (1+ (point))))
-             (mh-mime-display-single preferred)
-             (mh-mime-maybe-display-alternatives others)
-             (goto-char (point-max))))
-          (t (mh-mime-display-mixed handles)))))
-
-(defun mh-mime-maybe-display-alternatives (alternatives)
-  "Show buttons for ALTERNATIVES.
-If `mh-mime-display-alternatives-flag' is non-nil then display
-buttons for alternative parts that are usually suppressed."
-  (when (and mh-display-buttons-for-alternatives-flag alternatives)
-    (insert "\n----------------------------------------------------\n")
-    (insert "Alternatives:\n")
-    (dolist (x alternatives)
-      (insert "\n")
-      (mh-insert-mime-button x (mh-mime-part-index x) nil))
-    (insert "\n----------------------------------------------------\n")))
+See also \\[mh-mh-to-mime]."
+  (interactive (list
+                (mml-minibuffer-read-description)
+                (mh-prompt-for-folder "Message from" mh-sent-from-folder nil)
+                (read-string (concat "Messages"
+                                     (if (numberp mh-sent-from-msg)
+                                         (format " (default %d): "
+                                                 mh-sent-from-msg)
+                                       ": ")))))
+  (beginning-of-line)
+  (insert "#forw [")
+  (and description
+       (not (string= description ""))
+       (insert description))
+  (insert "]")
+  (and folder
+       (not (string= folder ""))
+       (insert " " folder))
+  (if (and messages
+           (not (string= messages "")))
+      (let ((start (point)))
+        (insert " " messages)
+        (subst-char-in-region start (point) ?, ? ))
+    (if (numberp mh-sent-from-msg)
+        (insert " " (int-to-string mh-sent-from-msg))))
+  (insert "\n"))
 
-(defun mh-mime-display-mixed (handles)
-  "Display the list of MIME parts, HANDLES recursively."
-  (mapcar #'mh-mime-display-part handles))
+;;;###mh-autoload
+(defun mh-compose-insertion (&optional inline)
+  "Add tag to include a file such as an image or sound.
 
-(defun mh-mime-part-index (handle)
-  "Generate the button number for MIME part, HANDLE.
-Notice that a hash table is used to display the same number when
-buttons need to be displayed multiple times (for instance when
-nested messages are opened)."
-  (or (gethash handle (mh-mime-part-index-hash (mh-buffer-data)))
-      (setf (gethash handle (mh-mime-part-index-hash (mh-buffer-data)))
-            (incf (mh-mime-parts-count (mh-buffer-data))))))
+You are prompted for the filename containing the object, the
+media type if it cannot be determined automatically, and a
+content description. If you're using MH-style directives, you
+will also be prompted for additional attributes.
 
-(defun mh-small-image-p (handle)
-  "Decide whether HANDLE is a \"small\" image that can be displayed inline.
-This is only useful if a Content-Disposition header is not present."
-  (let ((media-test (caddr (assoc (car (mm-handle-type handle))
-                                  mh-mm-inline-media-tests)))
-        (mm-inline-large-images t))
-    (and media-test
-         (equal (mm-handle-media-supertype handle) "image")
-         (funcall media-test handle)    ; Since mm-inline-large-images is T,
-                                        ; this only tells us if the image is
-                                        ; something that emacs can display
-         (let* ((image (mm-get-image handle)))
-           (or (mh-do-in-xemacs
-                 (and (mh-funcall-if-exists glyphp image)
-                      (< (glyph-width image)
-                         (or mh-max-inline-image-width (window-pixel-width)))
-                      (< (glyph-height image)
-                         (or mh-max-inline-image-height
-                             (window-pixel-height)))))
-               (mh-do-in-gnu-emacs
-                 (let ((size (mh-funcall-if-exists image-size image)))
-                   (and size
-                        (< (cdr size) (or mh-max-inline-image-height
-                                          (1- (window-height))))
-                        (< (car size) (or mh-max-inline-image-width
-                                          (window-width)))))))))))
+The option `mh-compose-insertion' controls what type of tags are
+inserted. Optional argument INLINE means make it an inline
+attachment."
+  (interactive "P")
+  (if (equal mh-compose-insertion 'mml)
+      (if inline
+          (mh-mml-attach-file "inline")
+        (mh-mml-attach-file))
+    (call-interactively 'mh-mh-attach-file)))
 
-(defun mh-inline-vcard-p (handle)
-  "Decide if HANDLE is a vcard that must be displayed inline."
-  (let ((type (mm-handle-type handle)))
-    (and (or (featurep 'vcard) (fboundp 'vcard-pretty-print))
-         (consp type)
-         (equal (car type) "text/x-vcard")
-         (save-excursion
-           (save-restriction
-             (widen)
-             (goto-char (point-min))
-             (not (mh-signature-separator-p)))))))
+(defun mh-mml-attach-file (&optional disposition)
+  "Add a tag to insert a MIME message part from a file.
 
-(defun mh-mime-display-single (handle)
-  "Display a leaf node, HANDLE in the MIME tree."
-  (let* ((type (mm-handle-media-type handle))
-         (small-image-flag (mh-small-image-p handle))
-         (attachmentp (equal (car (mm-handle-disposition handle))
-                             "attachment"))
-         (inlinep (and (equal (car (mm-handle-disposition handle)) "inline")
-                       (mm-inlinable-p handle)
-                       (mm-inlined-p handle)))
-         (displayp (or inlinep                   ; show if inline OR
-                       (mh-inline-vcard-p handle);      inline vcard OR
-                       (and (not attachmentp)    ;      if not an attachment
-                            (or small-image-flag ;        and small image
-                                                 ;        and user wants inline
-                                (and (not (equal
-                                           (mm-handle-media-supertype handle)
-                                           "image"))
-                                     (mm-inlinable-p handle)
-                                     (mm-inlined-p handle)))))))
-    (save-restriction
-      (narrow-to-region (point) (if (eobp) (point) (1+ (point))))
-      (cond ((and mh-pgp-support-flag
-                  (equal type "application/pgp-signature"))
-             nil)             ; skip signatures as they are already handled...
-            ((not displayp)
-             (insert "\n")
-             (mh-insert-mime-button handle (mh-mime-part-index handle) nil))
-            ((and displayp (not mh-display-buttons-for-inline-parts-flag))
-             (or (mm-display-part handle) (mm-display-part handle))
-             (mh-signature-highlight handle))
-            ((and displayp mh-display-buttons-for-inline-parts-flag)
-             (insert "\n")
-             (mh-insert-mime-button handle (mh-mime-part-index handle) nil)
-             (forward-line -1)
-             (mh-mm-display-part handle)))
-      (goto-char (point-max)))))
+You are prompted for the filename containing the object, the
+media type if it cannot be determined automatically, a content
+description and the DISPOSITION of the attachment.
 
-(defun mh-signature-highlight (&optional handle)
-  "Highlight message signature in HANDLE.
-The optional argument, HANDLE is a MIME handle if the function is
-being used to highlight the signature in a MIME part."
-  (let ((regexp
-         (cond ((not handle) "^-- $")
-               ((not (and (equal (mm-handle-media-supertype handle) "text")
-                          (equal (mm-handle-media-subtype handle) "html")))
-                "^-- $")
-               ((eq (mh-mm-text-html-renderer) 'lynx) "^   --$")
-               (t "^--$"))))
-    (save-excursion
-      (goto-char (point-max))
-      (when (re-search-backward regexp nil t)
-        (mh-do-in-gnu-emacs
-          (let ((ov (make-overlay (point) (point-max))))
-            (overlay-put ov 'face 'mh-show-signature)
-            (overlay-put ov 'evaporate t)))
-        (mh-do-in-xemacs
-          (set-extent-property (make-extent (point) (point-max))
-                               'face 'mh-show-signature))))))
+This is basically `mml-attach-file' from Gnus, modified such that a prefix
+argument yields an \"inline\" disposition and Content-Type is determined
+automatically."
+  (let* ((file (mml-minibuffer-read-file "Attach file: "))
+         (type (mh-minibuffer-read-type file))
+         (description (mml-minibuffer-read-description))
+         (dispos (or disposition
+                     (mml-minibuffer-read-disposition type))))
+    (mml-insert-empty-tag 'part 'type type 'filename file
+                          'disposition dispos 'description description)))
 
-(mh-do-in-xemacs
- (defvar dots)
- (defvar type))
+(defun mh-mh-attach-file (filename type description attributes)
+  "Add a tag to insert a MIME message part from a file.
+You are prompted for the FILENAME containing the object, the
+media TYPE if it cannot be determined automatically, and a
+content DESCRIPTION. In addition, you are also prompted for
+additional ATTRIBUTES.
 
-(defun mh-insert-mime-button (handle index displayed)
-  "Insert MIME button for HANDLE.
-INDEX is the part number that will be DISPLAYED. It is also used
-by commands like \"K v\" which operate on individual MIME parts."
-  ;; The button could be displayed by a previous decode. In that case
-  ;; undisplay it if we need a hidden button.
-  (when (and (mm-handle-displayed-p handle) (not displayed))
-    (mm-display-part handle))
-  (let ((name (or (mail-content-type-get (mm-handle-type handle) 'name)
-                  (mail-content-type-get (mm-handle-disposition handle)
-                                         'filename)
-                  (mail-content-type-get (mm-handle-type handle) 'url)
-                  ""))
-        (type (mm-handle-media-type handle))
-        (description (mail-decode-encoded-word-string
-                      (or (mm-handle-description handle) "")))
-        (dots (if (or displayed (mm-handle-displayed-p handle)) "   " "..."))
-        long-type begin end)
-    (if (string-match ".*/" name) (setq name (substring name (match-end 0))))
-    (setq long-type (concat type (and (not (equal name ""))
-                                      (concat "; " name))))
-    (unless (equal description "")
-      (setq long-type (concat " --- " long-type)))
-    (unless (bolp) (insert "\n"))
-    (setq begin (point))
-    (gnus-eval-format
-     mh-mime-button-line-format mh-mime-button-line-format-alist
-     `(,@(gnus-local-map-property mh-mime-button-map)
-         mh-callback mh-mm-display-part
-         mh-part ,index
-         mh-data ,handle))
-    (setq end (point))
-    (widget-convert-button
-     'link begin end
-     :mime-handle handle
-     :action 'mh-widget-press-button
-     :button-keymap mh-mime-button-map
-     :help-echo
-     "Mouse-2 click or press RET (in show buffer) to toggle display")
-    (dolist (ov (mh-funcall-if-exists overlays-in begin end))
-      (mh-funcall-if-exists overlay-put ov 'evaporate t))))
+See also \\[mh-mh-to-mime]."
+  (interactive (let ((filename (mml-minibuffer-read-file "Attach file: ")))
+                 (list
+                  filename
+                  (mh-minibuffer-read-type filename)
+                  (mml-minibuffer-read-description)
+                  (read-string "Attributes: "
+                               (concat "name=\""
+                                       (file-name-nondirectory filename)
+                                       "\"")))))
+  (mh-mh-compose-type filename type description attributes))
 
-;; There is a bug in Gnus inline image display due to which an extra line
-;; gets inserted every time it is viewed. To work around that problem we are
-;; using an extra property 'mh-region to remember the region that is added
-;; when the button is clicked. The region is then deleted to make sure that
-;; no extra lines get inserted.
-(defun mh-mm-display-part (handle)
-  "Toggle display of button for MIME part, HANDLE."
+(defun mh-mh-compose-type (filename type
+                                     &optional description attributes comment)
+  "Insert an MH-style directive to insert a file.
+The file specified by FILENAME is encoded as TYPE. An optional
+DESCRIPTION is used as the Content-Description field, optional
+set of ATTRIBUTES and an optional COMMENT can also be included."
   (beginning-of-line)
-  (let ((id (get-text-property (point) 'mh-part))
-        (point (point))
-        (window (selected-window))
-        (mail-parse-charset 'nil)
-        (mail-parse-ignored-charsets nil)
-        region buffer-read-only)
-    (save-excursion
-      (unwind-protect
-          (let ((win (get-buffer-window (current-buffer) t)))
-            (when win
-              (select-window win))
-            (goto-char point)
-
-            (if (mm-handle-displayed-p handle)
-                ;; This will remove the part.
-                (progn
-                  ;; Delete the button and displayed part (if any)
-                  (let ((region (get-text-property point 'mh-region)))
-                    (when region
-                      (mh-funcall-if-exists
-                       remove-images (car region) (cdr region)))
-                    (mm-display-part handle)
-                    (when region
-                      (delete-region (car region) (cdr region))))
-                  ;; Delete button (if it still remains). This happens for
-                  ;; externally displayed parts where the previous step does
-                  ;; nothing.
-                  (unless (eolp)
-                    (delete-region (point) (progn (forward-line) (point)))))
-              (save-restriction
-                (delete-region (point) (progn (forward-line 1) (point)))
-                (narrow-to-region (point) (point))
-                ;; Maybe we need another unwind-protect here.
-                (when (equal (mm-handle-media-supertype handle) "image")
-                  (insert "\n"))
-                (when (and (not (eq (ignore-errors (mm-display-part handle))
-                                    'inline))
-                           (equal (mm-handle-media-supertype handle)
-                                  "image"))
-                  (goto-char (point-min))
-                  (delete-char 1))
-                (when (equal (mm-handle-media-supertype handle) "text")
-                  (when (eq mh-highlight-citation-style 'gnus)
-                    (mh-gnus-article-highlight-citation))
-                  (mh-display-smileys)
-                  (mh-display-emphasis)
-                  (mh-signature-highlight handle))
-                (setq region (cons (progn (goto-char (point-min))
-                                          (point-marker))
-                                   (progn (goto-char (point-max))
-                                          (point-marker)))))))
-        (when (window-live-p window)
-          (select-window window))
-        (goto-char point)
-        (beginning-of-line)
-        (mh-insert-mime-button handle id (mm-handle-displayed-p handle))
-        (goto-char point)
-        (when region
-          (add-text-properties (line-beginning-position) (line-end-position)
-                               `(mh-region ,region)))))))
+  (insert "#" type)
+  (and attributes
+       (insert "; " attributes))
+  (and comment
+       (insert " (" comment ")"))
+  (insert " [")
+  (and description
+       (insert description))
+  (insert "] " (expand-file-name filename))
+  (insert "\n"))
 
 ;;;###mh-autoload
-(defun mh-press-button ()
-  "View contents of button.
+(defun mh-mh-compose-anon-ftp (host filename type description)
+  "Add tag to include anonymous ftp reference to a file.
 
-This command is a toggle so if you use it again on the same
-attachment, the attachment is hidden."
-  (interactive)
-  (let ((mm-inline-media-tests mh-mm-inline-media-tests)
-        (data (get-text-property (point) 'mh-data))
-        (function (get-text-property (point) 'mh-callback))
-        (buffer-read-only nil)
-        (folder mh-show-folder-buffer))
-    (flet ((mm-handle-set-external-undisplayer
-            (handle function)
-            (mh-handle-set-external-undisplayer folder handle function)))
-      (when (and function (eolp))
-        (backward-char))
-      (unwind-protect (and function (funcall function data))
-        (set-buffer-modified-p nil)))))
+You can have your message initiate an \"ftp\" transfer when the
+recipient reads the message. You are prompted for the remote HOST
+and FILENAME, the media TYPE, and the content DESCRIPTION.
+
+See also \\[mh-mh-to-mime]."
+  (interactive (list
+                (read-string "Remote host: ")
+                (read-string "Remote filename: ")
+                (mh-minibuffer-read-type "DUMMY-FILENAME")
+                (mml-minibuffer-read-description)))
+  (mh-mh-compose-external-type "anon-ftp" host filename
+                               type description))
 
 ;;;###mh-autoload
-(defun mh-push-button (event)
-  "Click MIME button for EVENT.
+(defun mh-mh-compose-external-compressed-tar (host filename description)
+  "Add tag to include anonymous ftp reference to a compressed tar file.
 
-If the MIME part is visible then it is removed. Otherwise the
-part is displayed. This function is called when the mouse is used
-to click the MIME button."
-  (interactive "e")
-  (mh-do-at-event-location event
-    (let ((folder mh-show-folder-buffer)
-          (mm-inline-media-tests mh-mm-inline-media-tests)
-          (data (get-text-property (point) 'mh-data))
-          (function (get-text-property (point) 'mh-callback)))
-      (flet ((mm-handle-set-external-undisplayer (handle func)
-               (mh-handle-set-external-undisplayer folder handle func)))
-        (and function (funcall function data))))))
+In addition to retrieving the file via anonymous \"ftp\" as per
+the command \\[mh-mh-compose-anon-ftp], the file will also be
+uncompressed and untarred. You are prompted for the remote HOST
+and FILENAME and the content DESCRIPTION.
 
-;;;###mh-autoload
-(defun mh-mime-save-part ()
-  "Save MIME part at point."
-  (interactive)
-  (let ((data (get-text-property (point) 'mh-data)))
-    (when data
-      (let ((mm-default-directory
-             (file-name-as-directory (or mh-mime-save-parts-directory
-                                         default-directory))))
-        (mh-mm-save-part data)
-        (setq mh-mime-save-parts-directory mm-default-directory)))))
+See also \\[mh-mh-to-mime]."
+  (interactive (list
+                (read-string "Remote host: ")
+                (read-string "Remote filename: ")
+                (mml-minibuffer-read-description)))
+  (mh-mh-compose-external-type "anon-ftp" host filename
+                               "application/octet-stream"
+                               description
+                               "type=tar; conversions=x-compress"
+                               "mode=image"))
 
-;;;###mh-autoload
-(defun mh-mime-inline-part ()
-  "Toggle display of the raw MIME part."
-  (interactive)
-  (let* ((buffer-read-only nil)
-         (data (get-text-property (point) 'mh-data))
-         (inserted-flag (get-text-property (point) 'mh-mime-inserted))
-         (displayed-flag (mm-handle-displayed-p data))
-         (point (point))
-         start end)
-    (cond ((and data (not inserted-flag) (not displayed-flag))
-           (let ((contents (mm-get-part data)))
-             (add-text-properties (line-beginning-position) (line-end-position)
-                                  '(mh-mime-inserted t))
-             (setq start (point-marker))
-             (forward-line 1)
-             (mm-insert-inline data contents)
-             (setq end (point-marker))
-             (add-text-properties
-              start (progn (goto-char start) (line-end-position))
-              `(mh-region (,start . ,end)))))
-          ((and data (or inserted-flag displayed-flag))
-           (mh-press-button)
-           (message "MIME part already inserted")))
-    (goto-char point)
-    (set-buffer-modified-p nil)))
+;; RFC 2045 - Multipurpose Internet Mail Extensions (MIME) Part One:
+;;            Format of Internet Message Bodies.
+;; RFC 2046 - Multipurpose Internet Mail Extensions (MIME) Part Two:
+;;            Media Types.
+;; RFC 2049 - Multipurpose Internet Mail Extensions (MIME) Part Five:
+;;            Conformance Criteria and Examples.
+;; RFC 2017 - Definition of the URL MIME External-Body Access-Type
+;; RFC 1738 - Uniform Resource Locators (URL)
+(defvar mh-access-types
+  '(("anon-ftp")        ; RFC2046 Anonymous File Transfer Protocol
+    ("file")            ; RFC1738 Host-specific file names
+    ("ftp")             ; RFC2046 File Transfer Protocol
+    ("gopher")          ; RFC1738 The Gopher Protocol
+    ("http")            ; RFC1738 Hypertext Transfer Protocol
+    ("local-file")      ; RFC2046 Local file access
+    ("mail-server")     ; RFC2046 mail-server Electronic mail address
+    ("mailto")          ; RFC1738 Electronic mail address
+    ("news")            ; RFC1738 Usenet news
+    ("nntp")            ; RFC1738 Usenet news using NNTP access
+    ("propspero")       ; RFC1738 Prospero Directory Service
+    ("telnet")          ; RFC1738 Telnet
+    ("tftp")            ; RFC2046 Trivial File Transfer Protocol
+    ("url")             ; RFC2017 URL scheme MIME access-type Protocol
+    ("wais"))           ; RFC1738 Wide Area Information Servers
+  "Valid MIME access-type values.")
 
 ;;;###mh-autoload
-(defun mh-display-with-external-viewer (part-index)
-  "View attachment externally.
+(defun mh-mh-compose-external-type (access-type host filename type
+                                                &optional description
+                                                attributes parameters
+                                                comment)
+  "Add tag to refer to a remote file.
 
-If Emacs does not know how to view an attachment, you could save
-it into a file and then run some program to open it. It is
-easier, however, to launch the program directly from MH-E with
-this command. While you'll most likely use this to view
-spreadsheets and documents, it is also useful to use your browser
-to view HTML attachments with higher fidelity than what Emacs can
-provide.
+This command is a general utility for referencing external files.
+In fact, all of the other commands that insert directives to
+access external files call this command. You are prompted for the
+ACCESS-TYPE, remote HOST and FILENAME, and content TYPE. If you
+provide a prefix argument, you are also prompted for a content
+DESCRIPTION, ATTRIBUTES, PARAMETERS, and a COMMENT.
 
-This command displays the attachment associated with the button
-under the cursor. If the cursor is not located over a button,
-then the cursor first moves to the next button, wrapping to the
-beginning of the message if necessary. You can provide a numeric
-prefix argument PART-INDEX to view the attachment labeled with
-that number.
+See also \\[mh-mh-to-mime]."
+  (interactive (list
+                (completing-read "Access type: " mh-access-types)
+                (read-string "Remote host: ")
+                (read-string "Remote filename: ")
+                (mh-minibuffer-read-type "DUMMY-FILENAME")
+                (if current-prefix-arg (mml-minibuffer-read-description))
+                (if current-prefix-arg (read-string "Attributes: "))
+                (if current-prefix-arg (read-string "Parameters: "))
+                (if current-prefix-arg (read-string "Comment: "))))
+  (beginning-of-line)
+  (insert "#@" type)
+  (and attributes
+       (insert "; " attributes))
+  (and comment
+       (insert " (" comment ") "))
+  (insert " [")
+  (and description
+       (insert description))
+  (insert "] ")
+  (insert "access-type=" access-type "; ")
+  (insert "site=" host)
+  (insert "; name=" (file-name-nondirectory filename))
+  (let ((directory (file-name-directory filename)))
+    (and directory
+         (insert "; directory=\"" directory "\"")))
+  (and parameters
+       (insert "; " parameters))
+  (insert "\n"))
 
-This command tries to provide a reasonable default for the viewer
-by calling the Emacs function `mailcap-mime-info'. This function
-usually reads the file \"/etc/mailcap\"."
-  (interactive "P")
-  (when (consp part-index) (setq part-index (car part-index)))
-  (mh-folder-mime-action
-   part-index
-   #'(lambda ()
-       (let* ((part (get-text-property (point) 'mh-data))
-              (type (mm-handle-media-type part))
-              (methods (mapcar (lambda (x) (list (cdr (assoc 'viewer x))))
-                               (mailcap-mime-info type 'all)))
-              (def (caar methods))
-              (prompt (format "Viewer%s: " (if def
-                                               (format " (default %s)" def)
-                                             "")))
-              (method (completing-read prompt methods nil nil nil nil def))
-              (folder mh-show-folder-buffer)
-              (buffer-read-only nil))
-         (when (string-match "^[^% \t]+$" method)
-           (setq method (concat method " %s")))
-         (flet ((mm-handle-set-external-undisplayer (handle function)
-                  (mh-handle-set-external-undisplayer folder handle function)))
-           (unwind-protect (mm-display-external part method)
-             (set-buffer-modified-p nil)))))
-   nil))
+(defvar mh-mh-to-mime-args nil
+  "Extra arguments for \\[mh-mh-to-mime] to pass to the \"mhbuild\" command.
+The arguments are passed to \"mhbuild\" if \\[mh-mh-to-mime] is
+given a prefix argument. Normally default arguments to
+\"mhbuild\" are specified in the MH profile.")
 
-(defun mh-widget-press-button (widget el)
-  "Callback for widget, WIDGET.
-Parameter EL is unused."
-  (goto-char (widget-get widget :from))
-  (mh-press-button))
+;;;###mh-autoload
+(defun mh-mh-to-mime (&optional extra-args)
+  "Compose MIME message from MH-style directives.
 
-(defun mh-mime-display-security (handle)
-  "Display PGP encrypted/signed message, HANDLE."
-  (save-restriction
-    (narrow-to-region (point) (point))
-    (insert "\n")
-    (mh-insert-mime-security-button handle)
-    (mh-mime-display-mixed (cdr handle))
-    (insert "\n")
-    (let ((mh-mime-security-button-line-format
-           mh-mime-security-button-end-line-format))
-      (mh-insert-mime-security-button handle))
-    (mm-set-handle-multipart-parameter
-     handle 'mh-region (cons (point-min-marker) (point-max-marker)))))
+Typically, you send a message with attachments just like any other
+message. However, you may take a sneak preview of the MIME encoding if
+you wish by running this command.
 
-;; I rewrote the security part because Gnus doesn't seem to ever minimize
-;; the button. That is once the mime-security button is pressed there seems
-;; to be no way of getting rid of the inserted text.
-(defun mh-mime-security-show-details (handle)
-  "Toggle display of detailed security info for HANDLE."
-  (let ((details (mm-handle-multipart-ctl-parameter handle 'gnus-details)))
-    (when details
-      (let ((mh-mime-security-button-pressed
-             (not (get-text-property (point) 'mh-button-pressed)))
-            (mh-mime-security-button-line-format
-             (get-text-property (point) 'mh-line-format)))
-        (forward-char -1)
-        (while (eq (get-text-property (point) 'mh-line-format)
-                   mh-mime-security-button-line-format)
-          (forward-char -1))
-        (forward-char)
-        (save-restriction
-          (narrow-to-region (point) (point))
-          (mh-insert-mime-security-button handle))
-        (delete-region
-         (point)
-         (or (text-property-not-all
-              (point) (point-max)
-              'mh-line-format mh-mime-security-button-line-format)
-             (point-max)))
-        (forward-line -1)))))
+If you wish to pass additional arguments to \"mhbuild\" (\"mhn\")
+to affect how it builds your message, use the option
+`mh-mh-to-mime-args'. For example, you can build a consistency
+check into the message by setting `mh-mh-to-mime-args' to
+\"-check\". The recipient of your message can then run \"mhbuild
+-check\" on the message--\"mhbuild\" (\"mhn\") will complain if
+the message has been corrupted on the way. This command only
+consults this option when given a prefix argument EXTRA-ARGS.
 
-(defun mh-mime-security-button-face (info)
-  "Return the button face to use for encrypted/signed mail based on INFO."
-  (cond ((string-match "OK" info)       ;Decrypted mail
-         'mh-show-pgg-good)
-        ((string-match "Failed" info)   ;Decryption failed or signature invalid
-         'mh-show-pgg-bad)
-        ((string-match "Undecided" info);Unprocessed mail
-         'mh-show-pgg-unknown)
-        ((string-match "Untrusted" info);Key not trusted
-         'mh-show-pgg-unknown)
-        (t
-         'mh-show-pgg-good)))
+The hook `mh-mh-to-mime-hook' is called after the message has been
+formatted.
 
-(defun mh-mime-security-press-button (handle)
-  "Callback from security button for part HANDLE."
-  (if (mm-handle-multipart-ctl-parameter handle 'gnus-info)
-      (mh-mime-security-show-details handle)
-    (let ((region (mm-handle-multipart-ctl-parameter handle 'mh-region))
-          point)
-      (setq point (point))
-      (goto-char (car region))
-      (delete-region (car region) (cdr region))
-      (with-current-buffer (mm-handle-multipart-ctl-parameter handle 'buffer)
-        (let* ((mm-verify-option 'known)
-               (mm-decrypt-option 'known)
-               (new (mm-possibly-verify-or-decrypt (cdr handle) handle)))
-          (unless (eq new (cdr handle))
-            (mm-destroy-parts (cdr handle))
-            (setcdr handle new))))
-      (mh-mime-display-security handle)
-      (goto-char point))))
+The effects of this command can be undone by running
+\\[mh-mh-to-mime-undo]."
+  (interactive "*P")
+  (mh-mh-quote-unescaped-sharp)
+  (save-buffer)
+  (message "Running %s..." (if (mh-variant-p 'nmh) "mhbuild" "mhn"))
+  (cond
+   ((mh-variant-p 'nmh)
+    (mh-exec-cmd-error nil
+                       "mhbuild"
+                       (if extra-args mh-mh-to-mime-args)
+                       buffer-file-name))
+   (t
+    (mh-exec-cmd-error (format "mhdraft=%s" buffer-file-name)
+                       "mhn"
+                       (if extra-args mh-mh-to-mime-args)
+                       buffer-file-name)))
+  (revert-buffer t t)
+  (message "Running %s...done" (if (mh-variant-p 'nmh) "mhbuild" "mhn"))
+  (run-hooks 'mh-mh-to-mime-hook))
+
+(defun mh-mh-quote-unescaped-sharp ()
+  "Quote \"#\" characters that haven't been quoted for \"mhbuild\".
+If the \"#\" character is present in the first column, but it isn't
+part of a MH-style directive then \"mhbuild\" gives an error.
+This function will quote all such characters."
+  (save-excursion
+    (goto-char (point-min))
+    (while (re-search-forward "^#" nil t)
+      (beginning-of-line)
+      (unless (mh-mh-directive-present-p (point) (line-end-position))
+        (insert "#"))
+      (goto-char (line-end-position)))))
+
+;;;###mh-autoload
+(defun mh-mh-to-mime-undo (noconfirm)
+  "Undo effects of \\[mh-mh-to-mime].
+
+It does this by reverting to a backup file. You are prompted to
+confirm this action, but you can avoid the confirmation by adding
+a prefix argument NOCONFIRM."
+  (interactive "*P")
+  (if (null buffer-file-name)
+      (error "Buffer does not seem to be associated with any file"))
+  (let ((backup-strings '("," "#"))
+        backup-file)
+    (while (and backup-strings
+                (not (file-exists-p
+                      (setq backup-file
+                            (concat (file-name-directory buffer-file-name)
+                                    (car backup-strings)
+                                    (file-name-nondirectory buffer-file-name)
+                                    ".orig")))))
+      (setq backup-strings (cdr backup-strings)))
+    (or backup-strings
+        (error "Backup file for %s no longer exists" buffer-file-name))
+    (or noconfirm
+        (yes-or-no-p (format "Revert buffer from file %s? "
+                             backup-file))
+        (error "Revert not confirmed"))
+    (let ((buffer-read-only nil))
+      (erase-buffer)
+      (insert-file-contents backup-file))
+    (after-find-file nil)))
 
 ;; Shush compiler.
-(eval-when-compile
-  (defvar mm-verify-function-alist nil)
-  (defvar mm-decrypt-function-alist nil))
+(eval-when-compile (defvar mh-identity-pgg-default-user-id))
 
-(defvar pressed-details)
+;;;###mh-autoload
+(defun mh-mml-secure-message-encrypt (method)
+  "Add tag to encrypt the message.
 
-(defun mh-insert-mime-security-button (handle)
-  "Display buttons for PGP message, HANDLE."
-  (let* ((protocol (mm-handle-multipart-ctl-parameter handle 'protocol))
-         (crypto-type (or (nth 2 (assoc protocol mm-verify-function-alist))
-                          (nth 2 (assoc protocol mm-decrypt-function-alist))
-                          "Unknown"))
-         (type (concat crypto-type
-                       (if (equal (car handle) "multipart/signed")
-                           " Signed" " Encrypted")
-                       " Part"))
-         (info (or (mm-handle-multipart-ctl-parameter handle 'gnus-info)
-                   "Undecided"))
-         (details (mm-handle-multipart-ctl-parameter handle 'gnus-details))
-         pressed-details begin end face)
-    (setq details (if details (concat "\n" details) ""))
-    (setq pressed-details (if mh-mime-security-button-pressed details ""))
-    (setq face (mh-mime-security-button-face info))
-    (unless (bolp) (insert "\n"))
-    (setq begin (point))
-    (gnus-eval-format
-     mh-mime-security-button-line-format
-     mh-mime-security-button-line-format-alist
-     `(,@(gnus-local-map-property mh-mime-security-button-map)
-         mh-button-pressed ,mh-mime-security-button-pressed
-         mh-callback mh-mime-security-press-button
-         mh-line-format ,mh-mime-security-button-line-format
-         mh-data ,handle))
-    (setq end (point))
-    (widget-convert-button 'link begin end
-                           :mime-handle handle
-                           :action 'mh-widget-press-button
-                           :button-keymap mh-mime-security-button-map
-                           :button-face face
-                           :help-echo "Mouse-2 click or press RET (in show 
buffer) to see security details.")
-    (dolist (ov (mh-funcall-if-exists overlays-in begin end))
-      (mh-funcall-if-exists overlay-put ov 'evaporate t))
-    (when (equal info "Failed")
-      (let* ((type (if (equal (car handle) "multipart/signed")
-                       "verification" "decryption"))
-             (warning (if (equal type "decryption")
-                          "(passphrase may be incorrect)" "")))
-        (message "%s %s failed %s" crypto-type type warning)))))
+A proper multipart message is created for you when you send the
+message. Use the command \\[mh-mml-unsecure-message] to remove
+this tag. Use a prefix argument METHOD to be prompted for one of
+the possible security methods (see `mh-mml-method-default')."
+  (interactive (list (mh-mml-query-cryptographic-method)))
+  (mh-secure-message method "encrypt" mh-identity-pgg-default-user-id))
 
-(defun mh-mm-inline-message (handle)
-  "Display message, HANDLE.
-The function decodes the message and displays it. It avoids
-decoding the same message multiple times."
-  (let ((b (point))
-        (clean-message-header mh-clean-message-header-flag)
-        (invisible-headers mh-invisible-header-fields-compiled)
-        (visible-headers nil))
-    (save-excursion
-      (save-restriction
-        (narrow-to-region b b)
-        (mm-insert-part handle)
-        (mh-mime-display
-         (or (gethash handle (mh-mime-handles-cache (mh-buffer-data)))
-             (setf (gethash handle (mh-mime-handles-cache (mh-buffer-data)))
-                   (let ((handles (mm-dissect-buffer nil)))
-                     (if handles
-                         (when (fboundp 'mm-uu-dissect-text-parts)
-                           (mm-uu-dissect-text-parts handles))
-                       (setq handles (mm-uu-dissect)))
-                     (setf (mh-mime-handles (mh-buffer-data))
-                           (mm-merge-handles
-                            handles (mh-mime-handles (mh-buffer-data))))
-                     handles))))
+;;;###mh-autoload
+(defun mh-mml-secure-message-sign (method)
+  "Add tag to sign the message.
 
-        (goto-char (point-min))
-        (mh-show-xface)
-        (cond (clean-message-header
-               (mh-clean-msg-header (point-min)
-                                    invisible-headers
-                                    visible-headers)
-               (goto-char (point-min)))
-              (t
-               (mh-start-of-uncleaned-message)))
-        (mh-decode-message-header)
-        (mh-show-addr)
-        ;; The other highlighting types don't need anything special
-        (when (eq mh-highlight-citation-style 'gnus)
-          (mh-gnus-article-highlight-citation))
-        (goto-char (point-min))
-        (insert "\n------- Forwarded Message\n\n")
-        (mh-display-smileys)
-        (mh-display-emphasis)
-        (mm-handle-set-undisplayer
-         handle
-         `(lambda ()
-            (let (buffer-read-only)
-              (if (fboundp 'remove-specifier)
-                  ;; This is only valid on XEmacs.
-                  (mapcar (lambda (prop)
-                            (remove-specifier
-                             (face-property 'default prop) (current-buffer)))
-                          '(background background-pixmap foreground)))
-              (delete-region ,(point-min-marker) ,(point-max-marker)))))))))
+A proper multipart message is created for you when you send the
+message. Use the command \\[mh-mml-unsecure-message] to remove
+this tag. Use a prefix argument METHOD to be prompted for one of
+the possible security methods (see `mh-mml-method-default')."
+  (interactive (list (mh-mml-query-cryptographic-method)))
+  (mh-secure-message method "sign" mh-identity-pgg-default-user-id))
+
+;;;###mh-autoload
+(defun mh-mml-secure-message-signencrypt (method)
+  "Add tag to encrypt and sign the message.
+
+A proper multipart message is created for you when you send the
+message. Use the command \\[mh-mml-unsecure-message] to remove
+this tag. Use a prefix argument METHOD to be prompted for one of
+the possible security methods (see `mh-mml-method-default')."
+  (interactive (list (mh-mml-query-cryptographic-method)))
+  (mh-secure-message method "signencrypt" mh-identity-pgg-default-user-id))
+
+(defvar mh-mml-cryptographic-method-history ())
+
+(defun mh-mml-query-cryptographic-method ()
+  "Read the cryptographic method to use."
+  (if current-prefix-arg
+      (let ((def (or (car mh-mml-cryptographic-method-history)
+                     mh-mml-method-default)))
+        (completing-read (format "Method (default %s): " def)
+                         '(("pgp") ("pgpmime") ("smime"))
+                         nil t nil 'mh-mml-cryptographic-method-history def))
+    mh-mml-method-default))
+
+(defun mh-secure-message (method mode &optional identity)
+  "Add tag to encrypt or sign message.
+
+METHOD should be one of: \"pgpmime\", \"pgp\", \"smime\".
+MODE should be one of: \"sign\", \"encrypt\", \"signencrypt\", \"none\".
+IDENTITY is optionally the default-user-id to use."
+  (if (not mh-pgp-support-flag)
+      (error "Your version of Gnus does not support PGP/GPG")
+    ;; Check the arguments
+    (let ((valid-methods (list "pgpmime" "pgp" "smime"))
+          (valid-modes (list "sign" "encrypt" "signencrypt" "none")))
+      (if (not (member method valid-methods))
+          (error "Method %s is invalid" method))
+      (if (not (member mode valid-modes))
+          (error "Mode %s is invalid" mode))
+      (mml-unsecure-message)
+      (if (not (string= mode "none"))
+        (save-excursion
+          (goto-char (point-min))
+          (mh-goto-header-end 1)
+          (if mh-identity-pgg-default-user-id
+              (mml-insert-tag 'secure 'method method 'mode mode
+                              'sender mh-identity-pgg-default-user-id)
+            (mml-insert-tag 'secure 'method method 'mode mode)))))))
+
+;;;###mh-autoload
+(defun mh-mml-to-mime ()
+  "Compose MIME message from MML tags.
+
+Typically, you send a message with attachments just like any
+other message. However, you may take a sneak preview of the MIME
+encoding if you wish by running this command.
+
+This action can be undone by running \\[undo]."
+  (interactive)
+  (require 'message)
+  (when mh-pgp-support-flag ;; This is only needed for PGP
+    (message-options-set-recipient))
+  (let ((saved-text (buffer-string))
+        (buffer (current-buffer))
+        (modified-flag (buffer-modified-p)))
+    (condition-case err (mml-to-mime)
+      (error
+       (with-current-buffer buffer
+         (delete-region (point-min) (point-max))
+         (insert saved-text)
+         (set-buffer-modified-p modified-flag))
+       (error (error-message-string err))))))
+
+;;;###mh-autoload
+(defun mh-mml-unsecure-message ()
+  "Remove any secure message tags."
+  (interactive)
+  (if (not mh-pgp-support-flag)
+      (error "Your version of Gnus does not support PGP/GPG")
+    (mml-unsecure-message)))
+
+
+
+;;; Support Routines for MH-Letter Commands
+
+;;;###mh-autoload
+(defun mh-mml-tag-present-p ()
+  "Check if the current buffer has text which may be a MML tag."
+  (save-excursion
+    (goto-char (point-min))
+    (re-search-forward
+     (concat
+      "\\(<#\\(mml\\|part\\)\\(.\\|\n\\)*>[ \n\t]*<#/\\(mml\\|part\\)>\\|"
+      "^<#secure.+>$\\)")
+     nil t)))
+
+(defvar mh-media-type-regexp
+  (concat (regexp-opt '("text" "image" "audio" "video" "application"
+                        "multipart" "message") t)
+          "/[-.+a-zA-Z0-9]+")
+  "Regexp matching valid media types used in MIME attachment compositions.")
+
+;;;###mh-autoload
+(defun mh-mh-directive-present-p (&optional begin end)
+  "Check if the text between BEGIN and END might be a MH-style directive.
+The optional argument BEGIN defaults to the beginning of the
+buffer, while END defaults to the the end of the buffer."
+  (unless begin (setq begin (point-min)))
+  (unless end (setq end (point-max)))
+  (save-excursion
+    (block 'search-for-mh-directive
+      (goto-char begin)
+      (while (re-search-forward "^#" end t)
+        (let ((s (buffer-substring-no-properties (point) (line-end-position))))
+          (cond ((equal s ""))
+                ((string-match "^forw[ \t\n]+" s)
+                 (return-from 'search-for-mh-directive t))
+                (t (let ((first-token (car (split-string s "[ \t;@]"))))
+                     (when (and first-token
+                                (string-match mh-media-type-regexp
+                                              first-token))
+                       (return-from 'search-for-mh-directive t)))))))
+      nil)))
+
+(defun mh-minibuffer-read-type (filename &optional default)
+  "Return the content type associated with the given FILENAME.
+If the \"file\" command exists and recognizes the given file,
+then its value is returned\; otherwise, the user is prompted for
+a type (see `mailcap-mime-types' and for Emacs 20,
+`mh-mime-content-types').
+Optional argument DEFAULT is returned if a type isn't entered."
+  (mailcap-parse-mimetypes)
+  (let* ((default (or default
+                      (mm-default-file-encoding filename)
+                      "application/octet-stream"))
+         (probed-type (mh-file-mime-type filename))
+         (type (or (and (not (equal probed-type "application/octet-stream"))
+                        probed-type)
+                   (completing-read
+                    (format "Content type (default %s): " default)
+                    (mapcar 'list (mailcap-mime-types))))))
+    (if (not (equal type ""))
+        type
+      default)))
+
+;;;###mh-autoload
+(defun mh-file-mime-type (filename)
+  "Return MIME type of FILENAME from file command.
+Returns nil if file command not on system."
+  (cond
+   ((not (mh-have-file-command))
+    nil)                                ;no file command, exit now
+   ((not (and (file-exists-p filename)
+              (file-readable-p filename)))
+    nil)                               ;no file or not readable, ditto
+   (t
+    (save-excursion
+      (let ((tmp-buffer (get-buffer-create mh-temp-buffer)))
+        (set-buffer tmp-buffer)
+        (unwind-protect
+            (progn
+              (call-process "file" nil '(t nil) nil "-b" "-i"
+                            (expand-file-name filename))
+              (goto-char (point-min))
+              (if (not (re-search-forward mh-media-type-regexp nil t))
+                  nil
+                (mh-file-mime-type-substitute (match-string 0) filename)))
+          (kill-buffer tmp-buffer)))))))
+
+(defvar mh-file-mime-type-substitutions
+  '(("application/msword" "\.xls" "application/ms-excel")
+    ("application/msword" "\.ppt" "application/ms-powerpoint")
+    ("text/plain" "\.vcf" "text/x-vcard"))
+  "Substitutions to make for Content-Type returned from file command.
+The first element is the Content-Type returned by the file command.
+The second element is a regexp matching the file name, usually the
+extension.
+The third element is the Content-Type to replace with.")
+
+(defun mh-file-mime-type-substitute (content-type filename)
+  "Return possibly changed CONTENT-TYPE on the FILENAME.
+Substitutions are made from the `mh-file-mime-type-substitutions'
+variable."
+  (let ((subst mh-file-mime-type-substitutions)
+        (type) (match) (answer content-type)
+        (case-fold-search t))
+    (while subst
+      (setq type (car (car subst))
+            match (elt (car subst) 1))
+      (if (and (string-equal content-type type)
+               (string-match match filename))
+          (setq answer (elt (car subst) 2)
+                subst nil)
+        (setq subst (cdr subst))))
+    answer))
+
+(defvar mh-have-file-command 'undefined
+  "Cached value of function `mh-have-file-command'.
+Do not reference this variable directly as it might not have been
+initialized. Always use the command `mh-have-file-command'.")
+
+;;;###mh-autoload
+(defun mh-have-file-command ()
+  "Return t if 'file' command is on the system.
+'file -i' is used to get MIME type of composition insertion."
+  (when (eq mh-have-file-command 'undefined)
+    (setq mh-have-file-command
+          (and (fboundp 'executable-find)
+               (executable-find "file") ; file command exists
+                                        ;   and accepts -i and -b args.
+               (zerop (call-process "file" nil nil nil "-i" "-b"
+                                    (expand-file-name "inc" mh-progs))))))
+  mh-have-file-command)
+
+
+
+;;; MIME Cleanup
+
+;;;###mh-autoload
+(defun mh-mime-cleanup ()
+  "Free the decoded MIME parts."
+  (let ((mime-data (gethash (current-buffer) mh-globals-hash)))
+    ;; This is for Emacs, what about XEmacs?
+    (mh-funcall-if-exists remove-images (point-min) (point-max))
+    (when mime-data
+      (mm-destroy-parts (mh-mime-handles mime-data))
+      (remhash (current-buffer) mh-globals-hash))))
+
+;;;###mh-autoload
+(defun mh-destroy-postponed-handles ()
+  "Free MIME data for externally displayed MIME parts."
+  (let ((mime-data (mh-buffer-data)))
+    (when mime-data
+      (mm-destroy-parts (mh-mime-handles mime-data)))
+    (remhash (current-buffer) mh-globals-hash)))
 
 (provide 'mh-mime)
 
Index: emacs/lisp/mh-e/mh-print.el
diff -u emacs/lisp/mh-e/mh-print.el:1.16 emacs/lisp/mh-e/mh-print.el:1.17
--- emacs/lisp/mh-e/mh-print.el:1.16    Sun Jan 15 08:17:55 2006
+++ emacs/lisp/mh-e/mh-print.el Sun Jan 29 19:34:56 2006
@@ -30,15 +30,10 @@
 
 ;;; Code:
 
-;;(message "> mh-print")
-(eval-when-compile (require 'mh-acros))
-(mh-require-cl)
+(require 'mh-e)
+(require 'mh-scan)
+
 (require 'ps-print)
-(require 'mh-buffers)
-(require 'mh-utils)
-(require 'mh-funcs)
-(eval-when-compile (require 'mh-seq))
-;;(message "< mh-print")
 
 (defvar mh-ps-print-color-option ps-print-color-p
   "Specify how buffer's text color is printed.
@@ -48,7 +43,7 @@
    nil         - Do not print colors.
    t           - Print colors.
    black-white - Print colors on black/white printer.
-                See also `ps-black-white-faces'.
+                 See also `ps-black-white-faces'.
 
 Any other value is treated as t. This variable is initialized
 from `ps-print-color-p'.")
@@ -59,54 +54,6 @@
 Sensible choices are the functions `ps-spool-buffer' and
 `ps-spool-buffer-with-faces'.")
 
-(defun mh-ps-spool-buffer (buffer)
-  "Spool BUFFER."
-  (save-excursion
-    (set-buffer buffer)
-    (let ((ps-print-color-p mh-ps-print-color-option)
-          (ps-left-header
-           (list
-            (concat "(" (mh-get-header-field "Subject:") ")")
-            (concat "(" (mh-get-header-field "From:") ")")))
-          (ps-right-header
-           (list
-            "/pagenumberstring load"
-            (concat "(" (mh-get-header-field "Date:") ")"))))
-      (funcall mh-ps-print-func))))
-
-(defun mh-ps-spool-msg (msg)
-  "Spool MSG."
-  (let* ((folder mh-current-folder)
-         (buffer (mh-in-show-buffer (mh-show-buffer)
-                   (if (not (equal (mh-msg-filename msg folder)
-                                   buffer-file-name))
-                       (get-buffer-create mh-temp-buffer)))))
-    (unwind-protect
-        (save-excursion
-          (if buffer
-              (let ((mh-show-buffer buffer))
-                (mh-display-msg msg folder)))
-          (mh-ps-spool-buffer (if buffer buffer mh-show-buffer)))
-      (if buffer
-          (kill-buffer buffer)))))
-
-(defun mh-ps-print-range (range file)
-  "Print RANGE to FILE.
-
-This is the function that actually does the work.
-If FILE is nil, then the messages are spooled to the printer."
-  (mh-iterate-on-range msg range
-    (unwind-protect
-        (mh-ps-spool-msg msg))
-    (mh-notate msg mh-note-printed mh-cmd-note))
-  (ps-despool file))
-
-(defun mh-ps-print-preprint (prefix-arg)
-  "Provide a better default file name for `ps-print-preprint'.
-Pass along the PREFIX-ARG to it."
-  (let ((buffer-file-name (format "mh-%s" (substring (buffer-name) 1))))
-    (ps-print-preprint prefix-arg)))
-
 ;;;###mh-autoload
 (defun mh-ps-print-msg (range)
   "Print RANGE\\<mh-folder-mode-map>.
@@ -130,6 +77,48 @@
   (interactive (list (mh-interactive-range "Print")))
   (mh-ps-print-range range nil))
 
+(defun mh-ps-print-range (range file)
+  "Print RANGE to FILE.
+
+This is the function that actually does the work.
+If FILE is nil, then the messages are spooled to the printer."
+  (mh-iterate-on-range msg range
+    (unwind-protect
+        (mh-ps-spool-msg msg))
+    (mh-notate msg mh-note-printed mh-cmd-note))
+  (ps-despool file))
+
+(defun mh-ps-spool-msg (msg)
+  "Spool MSG."
+  (let* ((folder mh-current-folder)
+         (buffer (mh-in-show-buffer (mh-show-buffer)
+                   (if (not (equal (mh-msg-filename msg folder)
+                                   buffer-file-name))
+                       (get-buffer-create mh-temp-buffer)))))
+    (unwind-protect
+        (save-excursion
+          (if buffer
+              (let ((mh-show-buffer buffer))
+                (mh-display-msg msg folder)))
+          (mh-ps-spool-buffer (if buffer buffer mh-show-buffer)))
+      (if buffer
+          (kill-buffer buffer)))))
+
+(defun mh-ps-spool-buffer (buffer)
+  "Spool BUFFER."
+  (save-excursion
+    (set-buffer buffer)
+    (let ((ps-print-color-p mh-ps-print-color-option)
+          (ps-left-header
+           (list
+            (concat "(" (mh-get-header-field "Subject:") ")")
+            (concat "(" (mh-get-header-field "From:") ")")))
+          (ps-right-header
+           (list
+            "/pagenumberstring load"
+            (concat "(" (mh-get-header-field "Date:") ")"))))
+      (funcall mh-ps-print-func))))
+
 ;;;###mh-autoload
 (defun mh-ps-print-msg-file (range file)
   "Print RANGE to FILE\\<mh-folder-mode-map>.
@@ -153,6 +142,12 @@
   (interactive (list (mh-interactive-range "Print") (mh-ps-print-preprint 1)))
   (mh-ps-print-range range file))
 
+(defun mh-ps-print-preprint (prefix-arg)
+  "Provide a better default file name for `ps-print-preprint'.
+Pass along the PREFIX-ARG to it."
+  (let ((buffer-file-name (format "mh-%s" (substring (buffer-name) 1))))
+    (ps-print-preprint prefix-arg)))
+
 ;;;###mh-autoload
 (defun mh-ps-print-toggle-faces ()
  "Toggle whether printing is done with faces or not.
@@ -185,8 +180,8 @@
        (message "Colors will be printed as black & white"))
    (if (eq mh-ps-print-color-option 'black-white)
        (progn
-        (setq mh-ps-print-color-option t)
-        (message "Colors will be printed"))
+         (setq mh-ps-print-color-option t)
+         (message "Colors will be printed"))
      (setq mh-ps-print-color-option nil)
      (message "Colors will not be printed"))))
 
Index: emacs/lisp/mh-e/mh-search.el
diff -u emacs/lisp/mh-e/mh-search.el:1.5 emacs/lisp/mh-e/mh-search.el:1.6
--- emacs/lisp/mh-e/mh-search.el:1.5    Mon Jan 16 20:05:14 2006
+++ emacs/lisp/mh-e/mh-search.el        Sun Jan 29 19:34:56 2006
@@ -1,4 +1,4 @@
-;;; mh-search  ---  MH-E search
+;;; mh-search  ---  MH-Search mode
 
 ;; Copyright (C) 1993, 1995,
 ;;  2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
@@ -27,6 +27,8 @@
 
 ;;; Commentary:
 
+;; Mode used to compose search criteria.
+
 ;;  (1) The following search engines are supported:
 ;;        swish++
 ;;        swish-e
@@ -34,7 +36,7 @@
 ;;        namazu
 ;;        pick
 ;;        grep
-;;
+
 ;;  (2) To use this package, you first have to build an index. Please
 ;;      read the documentation for `mh-search' to get started. That
 ;;      documentation will direct you to the specific instructions for
@@ -44,14 +46,12 @@
 
 ;;; Code:
 
-;;(message "> mh-search")
-(eval-when-compile (require 'mh-acros))
+(require 'mh-e)
 (mh-require-cl)
 
 (require 'gnus-util)
-(require 'mh-buffers)
-(require 'mh-e)
-;;(message "< mh-search")
+(require 'imenu)
+(require 'which-func nil t)
 
 (defvar mh-searcher nil
   "Cached value of chosen search program.")
@@ -79,7 +79,7 @@
 
 
 
-;;; MH-Search mode
+;;; MH-Folder Commands
 
 ;;;###mh-autoload
 (defun* mh-search (folder search-regexp
@@ -322,6 +322,9 @@
                (loop for msg-hash being hash-values of mh-index-data
                      count (> (hash-table-count msg-hash) 0))))))
 
+;; Shush compiler.
+(eval-when-compile (mh-do-in-xemacs (defvar pick-folder)))
+
 (defun mh-search-folder (folder window-config)
   "Search FOLDER for messages matching a pattern.
 
@@ -363,11 +366,193 @@
   (add-text-properties (point) (1- (line-end-position)) '(read-only t))
   (goto-char (point-max)))
 
+;; Sequence Searches
+
 ;;;###mh-autoload
-(defvar mh-search-mode-map (make-sparse-keymap)
-  "Keymap for searching folder.")
+(defun mh-index-new-messages (folders)
+  "Display unseen messages.
+
+If you use a program such as \"procmail\" to use \"rcvstore\" to file
+your incoming mail automatically, you can display new, unseen,
+messages using this command. All messages in the \"unseen\"
+sequence from the folders in `mh-new-messages-folders' are
+listed.
+
+With a prefix argument, enter a space-separated list of FOLDERS,
+or nothing to search all folders."
+  (interactive
+   (list (if current-prefix-arg
+             (split-string (read-string "Search folder(s) (default all): "))
+           mh-new-messages-folders)))
+  (mh-index-sequenced-messages folders mh-unseen-seq))
 
 ;;;###mh-autoload
+(defun mh-index-ticked-messages (folders)
+  "Display ticked messages.
+
+All messages in `mh-tick-seq' from the folders in
+`mh-ticked-messages-folders' are listed.
+
+With a prefix argument, enter a space-separated list of FOLDERS,
+or nothing to search all folders."
+  (interactive
+   (list (if current-prefix-arg
+             (split-string (read-string "Search folder(s) (default all): "))
+           mh-ticked-messages-folders)))
+  (mh-index-sequenced-messages folders mh-tick-seq))
+
+;; Shush compiler.
+(eval-when-compile
+  (mh-do-in-xemacs
+    (defvar mh-mairix-folder)
+    (defvar mh-flists-search-folders)))
+
+;;;###mh-autoload
+(defun mh-index-sequenced-messages (folders sequence)
+  "Display messages in any sequence.
+
+All messages from the FOLDERS in `mh-new-messages-folders' in the
+SEQUENCE you provide are listed. With a prefix argument, enter a
+space-separated list of folders at the prompt, or nothing to
+search all folders."
+  (interactive
+   (list (if current-prefix-arg
+             (split-string (read-string "Search folder(s) (default all): "))
+           mh-new-messages-folders)
+         (mh-read-seq-default "Search" nil)))
+  (unless sequence (setq sequence mh-unseen-seq))
+  (let* ((mh-flists-search-folders folders)
+         (mh-flists-sequence sequence)
+         (mh-flists-called-flag t)
+         (mh-searcher 'flists)
+         (mh-search-function 'mh-flists-execute)
+         (mh-search-next-result-function 'mh-mairix-next-result)
+         (mh-mairix-folder mh-user-path)
+         (mh-search-regexp-builder nil)
+         (new-folder (format "%s/%s/%s" mh-index-folder
+                             mh-flists-results-folder sequence))
+         (window-config (if (equal new-folder mh-current-folder)
+                            mh-previous-window-config
+                          (current-window-configuration)))
+         (redo-flag nil)
+         message)
+    (cond ((buffer-live-p (get-buffer new-folder))
+           ;; The destination folder is being visited. Trick `mh-search'
+           ;; into thinking that the folder resulted from a previous search.
+           (set-buffer new-folder)
+           (setq mh-index-previous-search (list folders mh-searcher sequence))
+           (setq redo-flag t))
+          ((mh-folder-exists-p new-folder)
+           ;; Folder exists but we don't have it open. That means they are
+           ;; stale results from a old flists search. Clear it out.
+           (mh-exec-cmd-quiet nil "rmf" new-folder)))
+    (setq message (mh-search "+" mh-flists-results-folder
+                             redo-flag window-config)
+          mh-index-sequence-search-flag t
+          mh-index-previous-search (list folders mh-searcher sequence))
+    (mh-index-write-data)
+    (when (stringp message) (message "%s" message))))
+
+(defvar mh-flists-search-folders)
+
+(defun mh-flists-execute (&rest args)
+  "Execute flists.
+Search for messages belonging to `mh-flists-sequence' in the
+folders specified by `mh-flists-search-folders'. If
+`mh-recursive-folders-flag' is t, then the folders are searched
+recursively. All parameters ARGS are ignored."
+  (set-buffer (get-buffer-create mh-temp-index-buffer))
+  (erase-buffer)
+  (unless (executable-find "sh")
+    (error "Didn't find sh"))
+  (with-temp-buffer
+    (let ((seq (symbol-name mh-flists-sequence)))
+      (insert "for folder in `" (expand-file-name "flists" mh-progs) " "
+              (cond ((eq mh-flists-search-folders t)
+                     (mh-quote-for-shell mh-inbox))
+                    ((eq mh-flists-search-folders nil) "")
+                    ((listp mh-flists-search-folders)
+                     (loop for folder in mh-flists-search-folders
+                           concat
+                           (concat " " (mh-quote-for-shell folder)))))
+              (if mh-recursive-folders-flag " -recurse" "")
+              " -sequence " seq " -noshowzero -fast` ; do\n"
+              (expand-file-name "mhpath" mh-progs) " \"+$folder\" " seq "\n"
+              "done\n"))
+    (call-process-region
+     (point-min) (point-max) "sh" nil (get-buffer mh-temp-index-buffer))))
+
+;; Navigation
+
+;;;###mh-autoload
+(defun mh-index-next-folder (&optional backward-flag)
+  "Jump to the next folder marker.
+
+With non-nil optional argument BACKWARD-FLAG, jump to the previous
+group of results."
+  (interactive "P")
+  (if (null mh-index-data)
+      (message "Only applicable in an MH-E index search buffer")
+    (let ((point (point)))
+      (forward-line (if backward-flag 0 1))
+      (cond ((if backward-flag
+                 (re-search-backward "^+" (point-min) t)
+               (re-search-forward "^+" (point-max) t))
+             (beginning-of-line))
+            ((and (if backward-flag
+                      (goto-char (point-max))
+                    (goto-char (point-min)))
+                  nil))
+            ((if backward-flag
+                 (re-search-backward "^+" (point-min) t)
+               (re-search-forward "^+" (point-max) t))
+             (beginning-of-line))
+            (t (goto-char point))))))
+
+;;;###mh-autoload
+(defun mh-index-previous-folder ()
+  "Jump to the previous folder marker."
+  (interactive)
+  (mh-index-next-folder t))
+
+;;;###mh-autoload
+(defun mh-index-visit-folder ()
+  "Visit original folder from where the message at point was found."
+  (interactive)
+  (unless mh-index-data
+    (error "Not in an index folder"))
+  (let (folder msg)
+    (save-excursion
+      (cond ((and (bolp) (eolp))
+             (ignore-errors (forward-line -1))
+             (setq msg (mh-get-msg-num t)))
+            ((equal (char-after (line-beginning-position)) ?+)
+             (setq folder (buffer-substring-no-properties
+                           (line-beginning-position) (line-end-position))))
+            (t (setq msg (mh-get-msg-num t)))))
+    (when (not folder)
+      (setq folder (car (gethash (gethash msg mh-index-msg-checksum-map)
+                                 mh-index-checksum-origin-map))))
+    (when (or (not (get-buffer folder))
+              (y-or-n-p (format "Reuse buffer displaying %s? " folder)))
+      (mh-visit-folder
+       folder (loop for x being the hash-keys of (gethash folder mh-index-data)
+                    when (mh-msg-exists-p x folder) collect x)))))
+
+
+
+;;; Search Menu
+
+(easy-menu-define
+  mh-pick-menu mh-search-mode-map "Menu for MH-E Search"
+  '("Search"
+    ["Perform Search"       mh-index-do-search t]
+    ["Search with pick"     mh-pick-do-search t]))
+
+
+
+;;; MH-Search Keys
+
 ;; If this changes, modify mh-search-mode-help-messages accordingly, below.
 (gnus-define-keys  mh-search-mode-map
   "\C-c?"               mh-help
@@ -375,30 +560,24 @@
   "\C-c\C-p"            mh-pick-do-search
   "\C-c\C-f\C-b"        mh-to-field
   "\C-c\C-f\C-c"        mh-to-field
-  "\C-c\C-f\C-d"        mh-to-field
-  "\C-c\C-f\C-f"        mh-to-field
-  "\C-c\C-f\C-r"        mh-to-field
+  "\C-c\C-f\C-m"        mh-to-field
   "\C-c\C-f\C-s"        mh-to-field
   "\C-c\C-f\C-t"        mh-to-field
   "\C-c\C-fb"           mh-to-field
   "\C-c\C-fc"           mh-to-field
-  "\C-c\C-fd"           mh-to-field
-  "\C-c\C-ff"           mh-to-field
-  "\C-c\C-fr"           mh-to-field
+  "\C-c\C-fm"           mh-to-field
   "\C-c\C-fs"           mh-to-field
   "\C-c\C-ft"           mh-to-field)
 
-(easy-menu-define
-  mh-pick-menu mh-search-mode-map "Menu for MH-E Search"
-  '("Search"
-    ["Perform Search"       mh-index-do-search t]
-    ["Search with pick"     mh-pick-do-search t]))
+
+
+;;; MH-Search Help Messages
 
 ;; Group messages logically, more or less.
 (defvar mh-search-mode-help-messages
   '((nil
-     "Perform search:  \\[mh-index-do-search]\n"
-     "Search with pick:  \\[mh-pick-do-search]\n"
+     "Perform search:   \\[mh-index-do-search]\n"
+     "Search with pick: \\[mh-pick-do-search]\n\n"
      "Move to a field by typing C-c C-f C-<field>\n"
      "where <field> is the first letter of the desired field\n"
      "(except for From: which uses \"m\")."))
@@ -413,6 +592,10 @@
 The substitutions described in `substitute-command-keys' are performed
 as well.")
 
+
+
+;;; MH-Search Mode
+
 (put 'mh-search-mode 'mode-class 'special)
 
 (define-derived-mode mh-search-mode fundamental-mode "MH-Search"
@@ -435,11 +618,13 @@
 
 \\{mh-search-mode-map}"
 
-  (make-local-variable 'mh-help-messages)
   (easy-menu-add mh-pick-menu)
-  (setq mh-help-messages mh-search-mode-help-messages))
+  (mh-set-help mh-search-mode-help-messages))
+
+
+
+;;; MH-Search Commands
 
-;;;###mh-autoload
 (defun mh-index-do-search (&optional searcher)
   "Find messages using `mh-search-program'.
 If optional argument SEARCHER is present, use it instead of
@@ -452,7 +637,6 @@
         (mh-search mh-current-folder pattern nil mh-previous-window-config)
       (error "No search terms"))))
 
-;;;###mh-autoload
 (defun mh-pick-do-search ()
   "Find messages using \"pick\".
 
@@ -490,7 +674,6 @@
         (forward-line))
       pattern-list)))
 
-;;;###mh-autoload
 (defun mh-index-parse-search-regexp (input-string)
   "Construct parse tree for INPUT-STRING.
 All occurrences of &, |, ! and ~ in INPUT-STRING are replaced by
@@ -554,336 +737,47 @@
                (push `(and ,(pop operand-stack) ,token) operand-stack))
               (t (push token operand-stack))))
       (prog1 (pop operand-stack)
-        (when (or op-stack operand-stack)
-          (error "Invalid regexp: %s" input))))))
-
-(defun mh-index-add-implicit-ops (tokens)
-  "Add implicit operators in the list TOKENS."
-  (let ((result ())
-        (literal-seen nil)
-        current)
-    (while tokens
-      (setq current (pop tokens))
-      (cond ((or (equal current ")") (equal current "and") (equal current 
"or"))
-             (setq literal-seen nil)
-             (push current result))
-            ((and literal-seen
-                  (push "and" result)
-                  (setq literal-seen nil)
-                  nil))
-            (t
-             (push current result)
-             (unless (or (equal current "(") (equal current "not"))
-               (setq literal-seen t)))))
-    (nreverse result)))
-
-(defun mh-index-evaluate (op-stack operand-stack)
-  "Read expression till starting paren based on OP-STACK and OPERAND-STACK."
-  (block mh-index-evaluate
-    (let (op oper1)
-      (while op-stack
-        (setq op (pop op-stack))
-        (cond ((eq op 'paren)
-               (return-from mh-index-evaluate (values op-stack operand-stack)))
-              ((eq op 'not)
-               (push `(not ,(pop operand-stack)) operand-stack))
-              ((or (eq op 'and) (eq op 'or))
-               (setq oper1 (pop operand-stack))
-               (push `(,op ,(pop operand-stack) ,oper1) operand-stack))))
-      (error "Ran out of tokens"))))
-
-
-
-;;; Sequence browsing
-
-;;;###mh-autoload
-(defun mh-index-new-messages (folders)
-  "Display unseen messages.
-
-If you use a program such as \"procmail\" to use \"rcvstore\" to file
-your incoming mail automatically, you can display new, unseen,
-messages using this command. All messages in the \"unseen\"
-sequence from the folders in `mh-new-messages-folders' are
-listed.
-
-With a prefix argument, enter a space-separated list of FOLDERS,
-or nothing to search all folders."
-  (interactive
-   (list (if current-prefix-arg
-             (split-string (read-string "Search folder(s) (default all): "))
-           mh-new-messages-folders)))
-  (mh-index-sequenced-messages folders mh-unseen-seq))
-
-;;;###mh-autoload
-(defun mh-index-ticked-messages (folders)
-  "Display ticked messages.
-
-All messages in `mh-tick-seq' from the folders in
-`mh-ticked-messages-folders' are listed.
-
-With a prefix argument, enter a space-separated list of FOLDERS,
-or nothing to search all folders."
-  (interactive
-   (list (if current-prefix-arg
-             (split-string (read-string "Search folder(s) (default all): "))
-           mh-ticked-messages-folders)))
-  (mh-index-sequenced-messages folders mh-tick-seq))
-
-;;;###mh-autoload
-(defun mh-index-sequenced-messages (folders sequence)
-  "Display messages in any sequence.
-
-All messages from the FOLDERS in `mh-new-messages-folders' in the
-SEQUENCE you provide are listed. With a prefix argument, enter a
-space-separated list of folders at the prompt, or nothing to
-search all folders."
-  (interactive
-   (list (if current-prefix-arg
-             (split-string (read-string "Search folder(s) (default all): "))
-           mh-new-messages-folders)
-         (mh-read-seq-default "Search" nil)))
-  (unless sequence (setq sequence mh-unseen-seq))
-  (let* ((mh-flists-search-folders folders)
-         (mh-flists-sequence sequence)
-         (mh-flists-called-flag t)
-         (mh-searcher 'flists)
-         (mh-search-function 'mh-flists-execute)
-         (mh-search-next-result-function 'mh-mairix-next-result)
-         (mh-mairix-folder mh-user-path)
-         (mh-search-regexp-builder nil)
-         (new-folder (format "%s/%s/%s" mh-index-folder
-                             mh-flists-results-folder sequence))
-         (window-config (if (equal new-folder mh-current-folder)
-                            mh-previous-window-config
-                          (current-window-configuration)))
-         (redo-flag nil)
-         message)
-    (cond ((buffer-live-p (get-buffer new-folder))
-           ;; The destination folder is being visited. Trick `mh-search'
-           ;; into thinking that the folder resulted from a previous search.
-           (set-buffer new-folder)
-           (setq mh-index-previous-search (list folders mh-searcher sequence))
-           (setq redo-flag t))
-          ((mh-folder-exists-p new-folder)
-           ;; Folder exists but we don't have it open. That means they are
-           ;; stale results from a old flists search. Clear it out.
-           (mh-exec-cmd-quiet nil "rmf" new-folder)))
-    (setq message (mh-search "+" mh-flists-results-folder
-                             redo-flag window-config)
-          mh-index-sequence-search-flag t
-          mh-index-previous-search (list folders mh-searcher sequence))
-    (mh-index-write-data)
-    (when (stringp message) (message "%s" message))))
-
-(defvar mh-flists-search-folders)
-
-(defun mh-flists-execute (&rest args)
-  "Execute flists.
-Search for messages belonging to `mh-flists-sequence' in the
-folders specified by `mh-flists-search-folders'. If
-`mh-recursive-folders-flag' is t, then the folders are searched
-recursively. All parameters ARGS are ignored."
-  (set-buffer (get-buffer-create mh-temp-index-buffer))
-  (erase-buffer)
-  (unless (executable-find "sh")
-    (error "Didn't find sh"))
-  (with-temp-buffer
-    (let ((seq (symbol-name mh-flists-sequence)))
-      (insert "for folder in `" (expand-file-name "flists" mh-progs) " "
-              (cond ((eq mh-flists-search-folders t)
-                     (mh-quote-for-shell mh-inbox))
-                    ((eq mh-flists-search-folders nil) "")
-                    ((listp mh-flists-search-folders)
-                     (loop for folder in mh-flists-search-folders
-                           concat
-                           (concat " " (mh-quote-for-shell folder)))))
-              (if mh-recursive-folders-flag " -recurse" "")
-              " -sequence " seq " -noshowzero -fast` ; do\n"
-              (expand-file-name "mhpath" mh-progs) " \"+$folder\" " seq "\n"
-              "done\n"))
-    (call-process-region
-     (point-min) (point-max) "sh" nil (get-buffer mh-temp-index-buffer))))
-
-
-
-;;; Folder navigation and utilities
-
-;;;###mh-autoload
-(defun mh-index-group-by-folder ()
-  "Partition the messages based on source folder.
-Returns an alist with the the folder names in the car and the cdr
-being the list of messages originally from that folder."
-  (save-excursion
-    (goto-char (point-min))
-    (let ((result-table (make-hash-table :test #'equal)))
-      (loop for msg being hash-keys of mh-index-msg-checksum-map
-            do (push msg (gethash (car (gethash
-                                        (gethash msg mh-index-msg-checksum-map)
-                                        mh-index-checksum-origin-map))
-                                  result-table)))
-      (loop for x being the hash-keys of result-table
-            collect (cons x (nreverse (gethash x result-table)))))))
-
-;;;###mh-autoload
-(defun mh-index-insert-folder-headers ()
-  "Annotate the search results with original folder names."
-  (let ((cur-msg (mh-get-msg-num nil))
-        (old-buffer-modified-flag (buffer-modified-p))
-        (buffer-read-only nil)
-        current-folder last-folder)
-    (goto-char (point-min))
-    (while (not (eobp))
-      (setq current-folder (car (gethash (gethash (mh-get-msg-num nil)
-                                                  mh-index-msg-checksum-map)
-                                         mh-index-checksum-origin-map)))
-      (when (and current-folder (not (equal current-folder last-folder)))
-        (insert (if last-folder "\n" "") current-folder "\n")
-        (setq last-folder current-folder))
-      (forward-line))
-    (when cur-msg
-      (mh-notate-cur)
-      (mh-goto-msg cur-msg t))
-    (set-buffer-modified-p old-buffer-modified-flag))
-  (mh-index-create-imenu-index))
-
-;;;###mh-autoload
-(defun mh-index-delete-folder-headers ()
-  "Delete the folder headers."
-  (let ((cur-msg (mh-get-msg-num nil))
-        (old-buffer-modified-flag (buffer-modified-p))
-        (buffer-read-only nil))
-    (while (and (not cur-msg) (not (eobp)))
-      (forward-line)
-      (setq cur-msg (mh-get-msg-num nil)))
-    (goto-char (point-min))
-    (while (not (eobp))
-      (if (or (char-equal (char-after) ?+) (char-equal (char-after) 10))
-          (delete-region (point) (progn (forward-line) (point)))
-        (forward-line)))
-    (when cur-msg (mh-goto-msg cur-msg t t))
-    (set-buffer-modified-p old-buffer-modified-flag)))
-
-;;;###mh-autoload
-(defun mh-index-create-imenu-index ()
-  "Create alist of folder names and positions in index folder buffers."
-  (save-excursion
-    (setq which-func-mode t)
-    (let ((alist ()))
-      (goto-char (point-min))
-      (while (re-search-forward "^+" nil t)
-        (save-excursion
-          (beginning-of-line)
-          (push (cons (buffer-substring-no-properties
-                       (point) (line-end-position))
-                      (set-marker (make-marker) (point)))
-                alist)))
-      (setq imenu--index-alist (nreverse alist)))))
-
-;;;###mh-autoload
-(defun mh-index-next-folder (&optional backward-flag)
-  "Jump to the next folder marker.
+        (when (or op-stack operand-stack)
+          (error "Invalid regexp: %s" input))))))
 
-With non-nil optional argument BACKWARD-FLAG, jump to the previous
-group of results."
-  (interactive "P")
-  (if (null mh-index-data)
-      (message "Only applicable in an MH-E index search buffer")
-    (let ((point (point)))
-      (forward-line (if backward-flag 0 1))
-      (cond ((if backward-flag
-                 (re-search-backward "^+" (point-min) t)
-               (re-search-forward "^+" (point-max) t))
-             (beginning-of-line))
-            ((and (if backward-flag
-                      (goto-char (point-max))
-                    (goto-char (point-min)))
+(defun mh-index-add-implicit-ops (tokens)
+  "Add implicit operators in the list TOKENS."
+  (let ((result ())
+        (literal-seen nil)
+        current)
+    (while tokens
+      (setq current (pop tokens))
+      (cond ((or (equal current ")") (equal current "and") (equal current 
"or"))
+             (setq literal-seen nil)
+             (push current result))
+            ((and literal-seen
+                  (push "and" result)
+                  (setq literal-seen nil)
                   nil))
-            ((if backward-flag
-                 (re-search-backward "^+" (point-min) t)
-               (re-search-forward "^+" (point-max) t))
-             (beginning-of-line))
-            (t (goto-char point))))))
-
-;;;###mh-autoload
-(defun mh-index-previous-folder ()
-  "Jump to the previous folder marker."
-  (interactive)
-  (mh-index-next-folder t))
-
-;;;###mh-autoload
-(defun mh-index-visit-folder ()
-  "Visit original folder from where the message at point was found."
-  (interactive)
-  (unless mh-index-data
-    (error "Not in an index folder"))
-  (let (folder msg)
-    (save-excursion
-      (cond ((and (bolp) (eolp))
-             (ignore-errors (forward-line -1))
-             (setq msg (mh-get-msg-num t)))
-            ((equal (char-after (line-beginning-position)) ?+)
-             (setq folder (buffer-substring-no-properties
-                           (line-beginning-position) (line-end-position))))
-            (t (setq msg (mh-get-msg-num t)))))
-    (when (not folder)
-      (setq folder (car (gethash (gethash msg mh-index-msg-checksum-map)
-                                 mh-index-checksum-origin-map))))
-    (when (or (not (get-buffer folder))
-              (y-or-n-p (format "Reuse buffer displaying %s? " folder)))
-      (mh-visit-folder
-       folder (loop for x being the hash-keys of (gethash folder mh-index-data)
-                    when (mh-msg-exists-p x folder) collect x)))))
-
-;;;###mh-autoload
-(defun mh-search-p ()
-  "Non-nil means that this folder was generated by searching."
-  mh-index-data)
+            (t
+             (push current result)
+             (unless (or (equal current "(") (equal current "not"))
+               (setq literal-seen t)))))
+    (nreverse result)))
 
-;;;###mh-autoload
-(defun mh-index-execute-commands ()
-  "Delete/refile the actual messages.
-The copies in the searched folder are then deleted/refiled to get
-the desired result. Before deleting the messages we make sure
-that the message being deleted is identical to the one that the
-user has marked in the index buffer."
-  (save-excursion
-    (let ((folders ())
-          (mh-speed-flists-inhibit-flag t))
-      (maphash
-       (lambda (folder msgs)
-         (push folder folders)
-         (if (not (get-buffer folder))
-             ;; If source folder not open, just delete the messages...
-             (apply #'mh-exec-cmd "rmm" folder (mh-coalesce-msg-list msgs))
-           ;; Otherwise delete the messages in the source buffer...
-           (save-excursion
-             (set-buffer folder)
-             (let ((old-refile-list mh-refile-list)
-                   (old-delete-list mh-delete-list))
-               (setq mh-refile-list nil
-                     mh-delete-list msgs)
-               (unwind-protect (mh-execute-commands)
-                 (setq mh-refile-list
-                       (mapcar (lambda (x)
-                                 (cons (car x)
-                                       (loop for y in (cdr x)
-                                             unless (memq y msgs) collect y)))
-                               old-refile-list)
-                       mh-delete-list
-                       (loop for x in old-delete-list
-                             unless (memq x msgs) collect x))
-                 (mh-set-folder-modified-p (mh-outstanding-commands-p))
-                 (when (mh-outstanding-commands-p)
-                   (mh-notate-deleted-and-refiled)))))))
-       (mh-index-matching-source-msgs (append (loop for x in mh-refile-list
-                                                    append (cdr x))
-                                              mh-delete-list)
-                                      t))
-      folders)))
+(defun mh-index-evaluate (op-stack operand-stack)
+  "Read expression till starting paren based on OP-STACK and OPERAND-STACK."
+  (block mh-index-evaluate
+    (let (op oper1)
+      (while op-stack
+        (setq op (pop op-stack))
+        (cond ((eq op 'paren)
+               (return-from mh-index-evaluate (values op-stack operand-stack)))
+              ((eq op 'not)
+               (push `(not ,(pop operand-stack)) operand-stack))
+              ((or (eq op 'and) (eq op 'or))
+               (setq oper1 (pop operand-stack))
+               (push `(,op ,(pop operand-stack) ,oper1) operand-stack))))
+      (error "Ran out of tokens"))))
 
 
 
-;;; Indexing functions
+;;; Indexing Functions
 
 ;; Support different search programs
 (defvar mh-search-choices
@@ -930,14 +824,13 @@
             (return mh-searcher))))
       nil)))
 
-;;; Swish++ interface
+;;; Swish++
 
 (defvar mh-swish++-binary (or (executable-find "search++")
                               (executable-find "search")))
 (defvar mh-swish++-directory ".swish++")
 (defvar mh-swish-folder nil)
 
-;;;###mh-autoload
 (defun mh-swish++-execute-search (folder-path search-regexp)
   "Execute swish++.
 
@@ -1012,12 +905,11 @@
                    (symbol-name (car expr))
                    (mh-swish++-print-regexp (caddr expr))))))
 
-;;; Swish interface
+;;; Swish
 
 (defvar mh-swish-binary (executable-find "swish-e"))
 (defvar mh-swish-directory ".swish")
 
-;;;###mh-autoload
 (defun mh-swish-execute-search (folder-path search-regexp)
   "Execute swish-e.
 
@@ -1110,13 +1002,12 @@
                 nil)))
     (forward-line)))
 
-;;; Mairix interface
+;;; Mairix
 
 (defvar mh-mairix-binary (executable-find "mairix"))
 (defvar mh-mairix-directory ".mairix")
 (defvar mh-mairix-folder nil)
 
-;;;###mh-autoload
 (defun mh-mairix-execute-search (folder-path search-regexp-list)
   "Execute mairix.
 
@@ -1244,13 +1135,12 @@
                                                 (cdadr expr)))))
         (t (error "Unreachable: %s" expr))))
 
-;;; Namazu interface
+;;; Namazu
 
 (defvar mh-namazu-binary (executable-find "namazu"))
 (defvar mh-namazu-directory ".namazu")
 (defvar mh-namazu-folder nil)
 
-;;;###mh-autoload
 (defun mh-namazu-execute-search (folder-path search-regexp)
   "Execute namazu.
 
@@ -1317,14 +1207,13 @@
                   nil))))
     (forward-line)))
 
-;;; Pick interface
+;;; Pick
 
 (defvar mh-index-pick-folder)
 (defvar mh-pick-binary "pick")
 (defconst mh-pick-single-dash  '(cc date from subject to)
   "Search components that are supported by single-dash option in pick.")
 
-;;;###mh-autoload
 (defun mh-pick-execute-search (folder-path search-regexp)
   "Execute pick.
 
@@ -1408,11 +1297,10 @@
            "-rbrace"))
         (t (error "Unknown operator %s seen" (car expr)))))
 
-;;; Grep interface
+;;; Grep
 
 (defvar mh-grep-binary (executable-find "grep"))
 
-;;;###mh-autoload
 (defun mh-grep-execute-search (folder-path search-regexp)
   "Execute grep.
 
@@ -1463,7 +1351,132 @@
 
 
 
-;;; Folder support
+;;; Folder Utilities
+
+;;;###mh-autoload
+(defun mh-index-group-by-folder ()
+  "Partition the messages based on source folder.
+Returns an alist with the the folder names in the car and the cdr
+being the list of messages originally from that folder."
+  (save-excursion
+    (goto-char (point-min))
+    (let ((result-table (make-hash-table :test #'equal)))
+      (loop for msg being hash-keys of mh-index-msg-checksum-map
+            do (push msg (gethash (car (gethash
+                                        (gethash msg mh-index-msg-checksum-map)
+                                        mh-index-checksum-origin-map))
+                                  result-table)))
+      (loop for x being the hash-keys of result-table
+            collect (cons x (nreverse (gethash x result-table)))))))
+
+;;;###mh-autoload
+(defun mh-index-insert-folder-headers ()
+  "Annotate the search results with original folder names."
+  (let ((cur-msg (mh-get-msg-num nil))
+        (old-buffer-modified-flag (buffer-modified-p))
+        (buffer-read-only nil)
+        current-folder last-folder)
+    (goto-char (point-min))
+    (while (not (eobp))
+      (setq current-folder (car (gethash (gethash (mh-get-msg-num nil)
+                                                  mh-index-msg-checksum-map)
+                                         mh-index-checksum-origin-map)))
+      (when (and current-folder (not (equal current-folder last-folder)))
+        (insert (if last-folder "\n" "") current-folder "\n")
+        (setq last-folder current-folder))
+      (forward-line))
+    (when cur-msg
+      (mh-notate-cur)
+      (mh-goto-msg cur-msg t))
+    (set-buffer-modified-p old-buffer-modified-flag))
+  (mh-index-create-imenu-index))
+
+;;;###mh-autoload
+(defun mh-index-delete-folder-headers ()
+  "Delete the folder headers."
+  (let ((cur-msg (mh-get-msg-num nil))
+        (old-buffer-modified-flag (buffer-modified-p))
+        (buffer-read-only nil))
+    (while (and (not cur-msg) (not (eobp)))
+      (forward-line)
+      (setq cur-msg (mh-get-msg-num nil)))
+    (goto-char (point-min))
+    (while (not (eobp))
+      (if (or (char-equal (char-after) ?+) (char-equal (char-after) 10))
+          (delete-region (point) (progn (forward-line) (point)))
+        (forward-line)))
+    (when cur-msg (mh-goto-msg cur-msg t t))
+    (set-buffer-modified-p old-buffer-modified-flag)))
+
+;; Shush compiler.
+(eval-when-compile (mh-do-in-xemacs (defvar which-func-mode)))
+
+;;;###mh-autoload
+(defun mh-index-create-imenu-index ()
+  "Create alist of folder names and positions in index folder buffers."
+  (save-excursion
+    (if (boundp 'which-func-mode)
+        (setq which-func-mode t))
+    (let ((alist ()))
+      (goto-char (point-min))
+      (while (re-search-forward "^+" nil t)
+        (save-excursion
+          (beginning-of-line)
+          (push (cons (buffer-substring-no-properties
+                       (point) (line-end-position))
+                      (set-marker (make-marker) (point)))
+                alist)))
+      (setq imenu--index-alist (nreverse alist)))))
+
+;;;###mh-autoload
+(defun mh-search-p ()
+  "Non-nil means that this folder was generated by searching."
+  mh-index-data)
+
+;; Shush compiler
+(eval-when-compile (if mh-xemacs-flag (defvar mh-speed-flists-inhibit-flag)))
+
+;;;###mh-autoload
+(defun mh-index-execute-commands ()
+  "Delete/refile the actual messages.
+The copies in the searched folder are then deleted/refiled to get
+the desired result. Before deleting the messages we make sure
+that the message being deleted is identical to the one that the
+user has marked in the index buffer."
+  (save-excursion
+    (let ((folders ())
+          (mh-speed-flists-inhibit-flag t))
+      (maphash
+       (lambda (folder msgs)
+         (push folder folders)
+         (if (not (get-buffer folder))
+             ;; If source folder not open, just delete the messages...
+             (apply #'mh-exec-cmd "rmm" folder (mh-coalesce-msg-list msgs))
+           ;; Otherwise delete the messages in the source buffer...
+           (save-excursion
+             (set-buffer folder)
+             (let ((old-refile-list mh-refile-list)
+                   (old-delete-list mh-delete-list))
+               (setq mh-refile-list nil
+                     mh-delete-list msgs)
+               (unwind-protect (mh-execute-commands)
+                 (setq mh-refile-list
+                       (mapcar (lambda (x)
+                                 (cons (car x)
+                                       (loop for y in (cdr x)
+                                             unless (memq y msgs) collect y)))
+                               old-refile-list)
+                       mh-delete-list
+                       (loop for x in old-delete-list
+                             unless (memq x msgs) collect x))
+                 (mh-set-folder-modified-p (mh-outstanding-commands-p))
+                 (when (mh-outstanding-commands-p)
+                   (mh-notate-deleted-and-refiled)))))))
+       (mh-index-matching-source-msgs (append (loop for x in mh-refile-list
+                                                    append (cdr x))
+                                              mh-delete-list)
+                                      t))
+      folders)))
 
 (defun mh-index-generate-pretty-name (string)
   "Given STRING generate a name which is suitable for use as a folder name.
@@ -1559,7 +1572,7 @@
 
 
 
-;;; Sequence support
+;;; Sequence Support
 
 ;;;###mh-autoload
 (defun mh-index-create-sequences ()
@@ -1688,7 +1701,7 @@
 
 
 
-;;; Serialization of index data
+;;; Serialization of Index Data
 
 (defun mh-index-write-data ()
   "Write index data to file."
@@ -1756,20 +1769,21 @@
 
 
 
-;;; Checksum routines
+;;; Checksum Routines
+
+;; A few different checksum programs are supported. The supported
+;; programs are:
 
-;; A few different checksum programs are supported. The supported programs
-;; are:
-;;
 ;;   1. md5sum
 ;;   2. md5
 ;;   3. openssl
-;;
-;; To add support for your favorite checksum program add a clause to the cond
-;; statement in mh-checksum-choose. This should set the variable
-;; mh-checksum-cmd to the command line needed to run the checsum program and
-;; should set mh-checksum-parser to a function which returns a cons cell
-;; containing the message number and checksum string.
+
+;; To add support for your favorite checksum program add a clause to
+;; the cond statement in mh-checksum-choose. This should set the
+;; variable mh-checksum-cmd to the command line needed to run the
+;; checsum program and should set mh-checksum-parser to a function
+;; which returns a cons cell containing the message number and
+;; checksum string.
 
 (defvar mh-checksum-cmd)
 (defvar mh-checksum-parser)
Index: emacs/lisp/mh-e/mh-seq.el
diff -u emacs/lisp/mh-e/mh-seq.el:1.27 emacs/lisp/mh-e/mh-seq.el:1.28
--- emacs/lisp/mh-e/mh-seq.el:1.27      Mon Jan 16 20:05:14 2006
+++ emacs/lisp/mh-e/mh-seq.el   Sun Jan 29 19:34:56 2006
@@ -26,128 +26,89 @@
 ;; Boston, MA 02110-1301, USA.
 
 ;;; Commentary:
-;;
-;;   This tries to implement the algorithm described at:
-;;     http://www.jwz.org/doc/threading.html
-;;   It is also a start to implementing the IMAP Threading extension RFC. The
-;;   implementation lacks the reference and subject canonicalization of the
-;;   RFC.
-;;
-;;   In the presentation buffer, children messages are shown indented with
-;;   either [ ] or < > around them. Square brackets ([ ]) denote that the
-;;   algorithm can point out some headers which when taken together implies
-;;   that the unindented message is an ancestor of the indented message. If
-;;   no such proof exists then angles (< >) are used.
-;;
-;;   Some issues and problems are as follows:
-;;
-;;    (1) Scan truncates the fields at length 512. So longer references:
-;;        headers get mutilated. The same kind of MH format string works when
-;;        composing messages. Is there a way to avoid this? My scan command
-;;        is as follows:
-;;          scan +folder -width 10000 \
-;;               -format "%(msg)\n%{message-id}\n%{references}\n%{subject}\n"
-;;        I would really appreciate it if someone would help me with this.
-;;
-;;    (2) Implement heuristics to recognize message identifiers in
-;;        In-Reply-To: header. Right now it just assumes that the last text
-;;        between angles (< and >) is the message identifier. There is the
-;;        chance that this will incorrectly use an email address like a
-;;        message identifier.
-;;
-;;    (3) Error checking of found message identifiers should be done.
-;;
-;;    (4) Since this breaks the assumption that message indices increase as
-;;        one goes down the buffer, the binary search based mh-goto-msg
-;;        doesn't work. I have a simpler replacement which may be less
-;;        efficient.
-;;
-;;    (5) Better canonicalizing for message identifier and subject strings.
-;;
 
-;; Internal support for MH-E package.
+;; Sequences are stored in the alist `mh-seq-list' in the form:
+;;     ((seq-name msgs ...) (seq-name msgs ...) ...)
 
 ;;; Change Log:
 
 ;;; Code:
 
-;;(message "> mh-seq")
-(eval-when-compile (require 'mh-acros))
-(mh-require-cl)
-
-(require 'mh-buffers)
 (require 'mh-e)
-;;(message "< mh-seq")
-
-
-
-;;; Data structures (used in message threading)...
+(mh-require-cl)
+(require 'mh-scan)
 
-(mh-defstruct (mh-thread-message (:conc-name mh-message-)
-                                 (:constructor mh-thread-make-message))
-  (id nil)
-  (references ())
-  (subject "")
-  (subject-re-p nil))
-
-(mh-defstruct (mh-thread-container (:conc-name mh-container-)
-                                   (:constructor mh-thread-make-container))
-  message parent children
-  (real-child-p t))
+(require 'font-lock)
 
-
-
-;;; Internal variables:
+;;; Variables
 
 (defvar mh-last-seq-used nil
   "Name of seq to which a msg was last added.")
 
 (defvar mh-non-seq-mode-line-annotation nil
   "Saved value of `mh-mode-line-annotation' when narrowed to a seq.")
+(make-variable-buffer-local 'mh-non-seq-mode-line-annotation)
+
+(defvar mh-internal-seqs '(answered cur deleted forwarded printed))
+
+;;; Macros
+
+(defmacro mh-make-seq (name msgs)
+  "Create sequence NAME with the given MSGS."
+  (list 'cons name msgs))
+
+(defmacro mh-seq-name (sequence)
+  "Extract sequence name from the given SEQUENCE."
+  (list 'car sequence))
 
 
 
-;;; Maps and hashes...
+;;; MH-Folder Commands
+
+;; Alphabetical.
 
-(defvar mh-thread-id-hash nil
-  "Hashtable used to canonicalize message identifiers.")
-(defvar mh-thread-subject-hash nil
-  "Hashtable used to canonicalize subject strings.")
-(defvar mh-thread-id-table nil
-  "Thread ID table maps from message identifiers to message containers.")
-(defvar mh-thread-id-index-map nil
-  "Table to look up message index number from message identifier.")
-(defvar mh-thread-index-id-map nil
-  "Table to look up message identifier from message index.")
-(defvar mh-thread-scan-line-map nil
-  "Map of message index to various parts of the scan line.")
-(defvar mh-thread-scan-line-map-stack nil
-  "Old map of message index to various parts of the scan line.
-This is the original map that is stored when the folder is
-narrowed.")
-(defvar mh-thread-subject-container-hash nil
-  "Hashtable used to group messages by subject.")
-(defvar mh-thread-duplicates nil
-  "Hashtable used to associate messages with the same message identifier.")
-(defvar mh-thread-history ()
-  "Variable to remember the transformations to the thread tree.
-When new messages are added, these transformations are rewound,
-then the links are added from the newly seen messages. Finally
-the transformations are redone to get the new thread tree. This
-makes incremental threading easier.")
-(defvar mh-thread-body-width nil
-  "Width of scan substring that contains subject and body of message.")
-
-(make-variable-buffer-local 'mh-thread-id-hash)
-(make-variable-buffer-local 'mh-thread-subject-hash)
-(make-variable-buffer-local 'mh-thread-id-table)
-(make-variable-buffer-local 'mh-thread-id-index-map)
-(make-variable-buffer-local 'mh-thread-index-id-map)
-(make-variable-buffer-local 'mh-thread-scan-line-map)
-(make-variable-buffer-local 'mh-thread-scan-line-map-stack)
-(make-variable-buffer-local 'mh-thread-subject-container-hash)
-(make-variable-buffer-local 'mh-thread-duplicates)
-(make-variable-buffer-local 'mh-thread-history)
+;;;###mh-autoload
+(defun mh-catchup (range)
+  "Delete RANGE from the \"unseen\" sequence.
+
+Check the documentation 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))
+
+;;;###mh-autoload
+(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.
+
+In a program, non-nil INTERNAL-FLAG 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))
+        (user-sequence-flag (not (mh-internal-seq sequence)))
+        (folders-changed (list mh-current-folder))
+        (msg-list ()))
+    (when entry
+      (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))
+        (apply #'mh-speed-flists t folders-changed)))))
 
 ;;;###mh-autoload
 (defun mh-delete-seq (sequence)
@@ -240,12 +201,8 @@
                         (mh-list-to-string (mh-seq-containing-msg message t))
                         " "))))
 
-;; Shush compiler
-(eval-when-compile
-  (defvar tool-bar-map)
-  (defvar tool-bar-mode))
-
-(make-variable-buffer-local 'mh-non-seq-mode-line-annotation)
+;; Shush compiler.
+(eval-when-compile (mh-do-in-xemacs (defvar tool-bar-mode)))
 
 ;;;###mh-autoload
 (defun mh-narrow-to-seq (sequence)
@@ -290,6 +247,23 @@
            (error "No messages in sequence %s" (symbol-name sequence))))))
 
 ;;;###mh-autoload
+(defun mh-narrow-to-tick ()
+  "Limit to ticked messages.
+
+What this command does is show only those messages that are in
+the \"tick\" sequence (which you can customize via the
+`mh-tick-seq' option) in the MH-Folder buffer. In addition, it
+limits further MH-E searches to just those messages. When you
+want to widen the view to all your messages again, use
+\\[mh-widen]."
+  (interactive)
+  (cond ((not mh-tick-seq)
+         (error "Enable ticking by customizing `mh-tick-seq'"))
+        ((null (mh-seq-msgs (mh-find-seq mh-tick-seq)))
+         (message "No messages in %s sequence" mh-tick-seq))
+        (t (mh-narrow-to-seq mh-tick-seq))))
+
+;;;###mh-autoload
 (defun mh-put-msg-in-seq (range sequence)
   "Add RANGE to SEQUENCE\\<mh-folder-mode-map>.
 
@@ -319,12 +293,39 @@
     (when (and (eq sequence mh-unseen-seq) (mh-speed-flists-active-p))
       (apply #'mh-speed-flists t folders))))
 
-(defun mh-valid-view-change-operation-p (op)
-  "Check if the view change operation can be performed.
-OP is one of 'widen and 'unthread."
-  (cond ((eq (car mh-view-ops) op)
-         (pop mh-view-ops))
-        (t nil)))
+;;;###mh-autoload
+(defun mh-toggle-tick (range)
+  "Toggle tick mark of RANGE.
+
+This command adds messages to the \"tick\" sequence (which you can customize
+via the option `mh-tick-seq'). This sequence can be viewed later with the
+\\[mh-index-ticked-messages] command.
+
+Check the documentation of `mh-interactive-range' to see how RANGE is read in
+interactive use."
+  (interactive (list (mh-interactive-range "Tick")))
+  (unless mh-tick-seq
+    (error "Enable ticking by customizing `mh-tick-seq'"))
+  (let* ((tick-seq (mh-find-seq mh-tick-seq))
+         (tick-seq-msgs (mh-seq-msgs tick-seq))
+         (ticked ())
+         (unticked ()))
+    (mh-iterate-on-range msg range
+      (cond ((member msg tick-seq-msgs)
+             (push msg unticked)
+             (setcdr tick-seq (delq msg (cdr tick-seq)))
+             (when (null (cdr tick-seq)) (setq mh-last-seq-used nil))
+             (mh-remove-sequence-notation msg (mh-colors-in-use-p)))
+            (t
+             (push msg ticked)
+             (setq mh-last-seq-used mh-tick-seq)
+             (let ((mh-seq-list (cons `(,mh-tick-seq ,msg) mh-seq-list)))
+               (mh-add-sequence-notation msg (mh-colors-in-use-p))))))
+    (mh-add-msgs-to-seq ticked mh-tick-seq nil t)
+    (mh-undefine-sequence mh-tick-seq unticked)
+    (when mh-index-data
+      (mh-index-add-to-sequence mh-tick-seq ticked)
+      (mh-index-delete-from-sequence mh-tick-seq unticked))))
 
 ;;;###mh-autoload
 (defun mh-widen (&optional all-flag)
@@ -374,32 +375,9 @@
         (set-buffer (get-buffer mh-show-buffer))
         (set (make-local-variable 'tool-bar-map) mh-show-tool-bar-map)))))
 
-;; FIXME?  We may want to clear all notations and add one for current-message
-;;         and process user sequences.
-;;;###mh-autoload
-(defun mh-notate-deleted-and-refiled ()
-  "Notate messages marked for deletion or refiling.
-Messages to be deleted are given by `mh-delete-list' while
-messages to be refiled are present in `mh-refile-list'."
-  (let ((refiled-hash (make-hash-table))
-        (deleted-hash (make-hash-table)))
-    (dolist (msg mh-delete-list)
-      (setf (gethash msg deleted-hash) t))
-    (dolist (dest-msg-list mh-refile-list)
-      (dolist (msg (cdr dest-msg-list))
-        (setf (gethash msg refiled-hash) t)))
-    (mh-iterate-on-messages-in-region msg (point-min) (point-max)
-      (cond ((gethash msg refiled-hash)
-             (mh-notate nil mh-note-refiled mh-cmd-note))
-            ((gethash msg deleted-hash)
-             (mh-notate nil mh-note-deleted mh-cmd-note))))))
-
 
 
-;;; Commands to manipulate sequences.
-
-;; Sequences are stored in an alist of the form:
-;;     ((seq-name msgs ...) (seq-name msgs ...) ...)
+;;; Support Routines
 
 (defvar mh-sequence-history ())
 
@@ -433,38 +411,192 @@
         (error "No messages in sequence %s" seq))
     seq))
 
+(defun mh-internal-seq (name)
+  "Return non-nil if NAME is the name of an internal MH-E sequence."
+  (or (memq name mh-internal-seqs)
+      (eq name mh-unseen-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)))
+
+;;;###mh-autoload
+(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))))
+
+;;;###mh-autoload
+(defun mh-find-seq (name)
+  "Return sequence NAME."
+  (assoc name mh-seq-list))
+
+;;;###mh-autoload
+(defun mh-seq-to-msgs (seq)
+  "Return a list of the messages in SEQ."
+  (mh-seq-msgs (mh-find-seq seq)))
+
+(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."
+  (let ((l mh-seq-list)
+        (seqs ()))
+    (while l
+      (and (memq msg (mh-seq-msgs (car l)))
+           (or include-internal-flag
+               (not (mh-internal-seq (mh-seq-name (car l)))))
+           (setq seqs (cons (mh-seq-name (car l)) seqs)))
+      (setq l (cdr l)))
+    seqs))
+
+;;;###mh-autoload
+(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 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)))))
+
+;;;###mh-autoload
+(defun mh-undefine-sequence (seq msgs)
+  "Remove from the SEQ the list of MSGS."
+  (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))))
+
+;;;###mh-autoload
+(defun mh-add-msgs-to-seq (msgs seq &optional internal-flag dont-annotate-flag)
+  "Add MSGS to SEQ.
+
+Remove duplicates and keep sequence sorted. If optional
+INTERNAL-FLAG is non-nil, do not mark the message in the scan
+listing or inform MH of the addition.
+
+If DONT-ANNOTATE-FLAG is non-nil then the annotations in the
+folder buffer are not updated."
+  (let ((entry (mh-find-seq seq))
+        (internal-seq-flag (mh-internal-seq seq)))
+    (if (and msgs (atom msgs)) (setq msgs (list msgs)))
+    (if (null entry)
+        (setq mh-seq-list
+              (cons (mh-make-seq seq (mh-canonicalize-sequence msgs))
+                    mh-seq-list))
+      (if msgs (setcdr entry (mh-canonicalize-sequence
+                              (append msgs (mh-seq-msgs entry))))))
+    (unless internal-flag
+      (mh-add-to-sequence seq msgs)
+      (when (not dont-annotate-flag)
+        (mh-iterate-on-range msg msgs
+          (unless (memq msg (cdr entry))
+            (mh-add-sequence-notation msg internal-seq-flag)))))))
+
+(defun mh-add-to-sequence (seq msgs)
+  "The sequence SEQ is augmented with the messages in MSGS."
+  ;; Add to a SEQUENCE each message the list of MSGS.
+  (if (and (mh-valid-seq-p seq) (not (mh-folder-name-p seq)))
+      (if msgs
+          (apply 'mh-exec-cmd "mark" mh-current-folder "-add"
+                 "-sequence" (symbol-name seq)
+                 (mh-coalesce-msg-list msgs)))))
+
+(defun mh-canonicalize-sequence (msgs)
+  "Sort MSGS in decreasing order and remove duplicates."
+  (let* ((sorted-msgs (sort (copy-sequence msgs) '>))
+         (head sorted-msgs))
+    (while (cdr head)
+      (if (= (car head) (cadr head))
+          (setcdr head (cddr head))
+        (setq head (cdr head))))
+    sorted-msgs))
+
+(defun mh-delete-a-msg-from-seq (msg sequence internal-flag)
+  "Delete MSG from SEQUENCE.
+If INTERNAL-FLAG is non-nil, then do not inform MH of the
+change."
+  (let ((entry (mh-find-seq sequence)))
+    (when (and entry (memq msg (mh-seq-msgs entry)))
+      (if (not internal-flag)
+          (mh-undefine-sequence sequence (list msg)))
+      (setcdr entry (delq msg (mh-seq-msgs entry))))))
+
+(defun mh-delete-seq-locally (seq)
+  "Remove MH-E's record of SEQ."
+  (let ((entry (mh-find-seq seq)))
+    (setq mh-seq-list (delq entry mh-seq-list))))
+
+(defun mh-copy-seq-to-eob (seq)
+  "Copy SEQ to the end of the buffer."
+  ;; It is quite involved to write something which will work at any place in
+  ;; the buffer, so we will write something which works only at the end of
+  ;; the buffer. If we ever need to insert sequences in the middle of the
+  ;; buffer, this will need to be fixed.
+  (save-excursion
+    (let* ((msgs (mh-seq-to-msgs seq))
+           (coalesced-msgs (mh-coalesce-msg-list msgs)))
+      (goto-char (point-max))
+      (save-restriction
+        (narrow-to-region (point) (point))
+        (mh-regenerate-headers coalesced-msgs t)
+        (cond ((memq 'unthread mh-view-ops)
+               ;; Populate restricted scan-line map
+               (mh-remove-all-notation)
+               (mh-iterate-on-range msg (cons (point-min) (point-max))
+                 (setf (gethash msg mh-thread-scan-line-map)
+                       (mh-thread-parse-scan-line)))
+               ;; Remove scan lines and read results from pre-computed tree
+               (delete-region (point-min) (point-max))
+               (mh-thread-print-scan-lines
+                (mh-thread-generate mh-current-folder ()))
+               (mh-notate-user-sequences))
+              (mh-index-data
+               (mh-index-insert-folder-headers)))))))
+
+;;;###mh-autoload
+(defun mh-valid-view-change-operation-p (op)
+  "Check if the view change operation can be performed.
+OP is one of 'widen and 'unthread."
+  (cond ((eq (car mh-view-ops) op)
+         (pop mh-view-ops))
+        (t nil)))
+
 
 
-;;; Functions to read ranges with completion...
+;;; Ranges
 
 (defvar mh-range-seq-names)
 (defvar mh-range-history ())
 (defvar mh-range-completion-map (copy-keymap minibuffer-local-completion-map))
 (define-key mh-range-completion-map " " 'self-insert-command)
 
-(defun mh-range-completion-function (string predicate flag)
-  "Programmable completion of message ranges.
-STRING is the user input that is to be completed. PREDICATE if non-nil is a
-function used to filter the possible choices and FLAG determines whether the
-completion is over."
-  (let* ((candidates mh-range-seq-names)
-         (last-char (and (not (equal string ""))
-                         (aref string (1- (length string)))))
-         (last-word (cond ((null last-char) "")
-                          ((memq last-char '(?  ?- ?:)) "")
-                          (t (car (last (split-string string "[ -:]+"))))))
-         (prefix (substring string 0 (- (length string) (length last-word)))))
-    (cond ((eq flag nil)
-           (let ((res (try-completion last-word candidates predicate)))
-             (cond ((null res) nil)
-                   ((eq res t) t)
-                   (t (concat prefix res)))))
-          ((eq flag t)
-           (all-completions last-word candidates predicate))
-          ((eq flag 'lambda)
-           (loop for x in candidates
-                 when (equal x last-word) return t
-                 finally return nil)))))
+;;;###mh-autoload
+(defun mh-interactive-range (range-prompt &optional default)
+  "Return interactive specification for message, sequence, range or region.
+By convention, the name of this argument is RANGE.
+
+If variable `transient-mark-mode' is non-nil and the mark is active,
+then this function returns a cons-cell of the region.
+
+If optional prefix argument is provided, then prompt for message range
+with RANGE-PROMPT. A list of messages in that range is returned.
+
+If a MH range is given, say something like last:20, then a list
+containing the messages in that range is returned.
+
+If DEFAULT non-nil then it is returned.
+
+Otherwise, the message number at point is returned.
+
+This function is usually used with `mh-iterate-on-range' in order to
+provide a uniform interface to MH-E functions."
+  (cond ((mh-mark-active-p t) (cons (region-beginning) (region-end)))
+        (current-prefix-arg (mh-read-range range-prompt nil nil t t))
+        (default default)
+        (t (mh-get-msg-num t))))
 
 ;;;###mh-autoload
 (defun mh-read-range (prompt &optional folder default
@@ -550,6 +682,17 @@
           (t (error "No messages in range %s" input)))))
 
 ;;;###mh-autoload
+(defun mh-range-to-msg-list (range)
+  "Return a list of messages for RANGE.
+
+Check the documentation of `mh-interactive-range' to see how
+RANGE is read in interactive use."
+  (let (msg-list)
+    (mh-iterate-on-range msg range
+      (push msg msg-list))
+    (nreverse msg-list)))
+
+;;;###mh-autoload
 (defun mh-translate-range (folder expr)
   "In FOLDER, translate the string EXPR to a list of messages numbers."
   (save-excursion
@@ -563,23 +706,177 @@
           (push (string-to-number (match-string 1)) result))
         (nreverse result)))))
 
+(defun mh-range-completion-function (string predicate flag)
+  "Programmable completion of message ranges.
+STRING is the user input that is to be completed. PREDICATE if non-nil is a
+function used to filter the possible choices and FLAG determines whether the
+completion is over."
+  (let* ((candidates mh-range-seq-names)
+         (last-char (and (not (equal string ""))
+                         (aref string (1- (length string)))))
+         (last-word (cond ((null last-char) "")
+                          ((memq last-char '(?  ?- ?:)) "")
+                          (t (car (last (split-string string "[ -:]+"))))))
+         (prefix (substring string 0 (- (length string) (length last-word)))))
+    (cond ((eq flag nil)
+           (let ((res (try-completion last-word candidates predicate)))
+             (cond ((null res) nil)
+                   ((eq res t) t)
+                   (t (concat prefix res)))))
+          ((eq flag t)
+           (all-completions last-word candidates predicate))
+          ((eq flag 'lambda)
+           (loop for x in candidates
+                 when (equal x last-word) return t
+                 finally return nil)))))
+
 (defun mh-seq-names (seq-list)
   "Return an alist containing the names of the SEQ-LIST."
   (mapcar (lambda (entry) (list (symbol-name (mh-seq-name entry))))
           seq-list))
 
+(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-folder-size-flist (folder)
+  "Find size of FOLDER using \"flist\"."
+  (with-temp-buffer
+    (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)
+        (mh-parse-flist-output-line
+         (buffer-substring (point) (line-end-position)))
+      (values total unseen 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 (string-to-number (match-string 1)) u folder)
+        (values 0 u folder)))))
+
 ;;;###mh-autoload
-(defun mh-rename-seq (sequence new-name)
-  "Rename SEQUENCE to have NEW-NAME."
-  (interactive (list (mh-read-seq "Old" t)
-                     (intern (read-string "New sequence name: "))))
-  (let ((old-seq (mh-find-seq sequence)))
-    (or old-seq
-        (error "Sequence %s does not exist" sequence))
-    ;; create new sequence first, since it might raise an error.
-    (mh-define-sequence new-name (mh-seq-msgs old-seq))
-    (mh-undefine-sequence sequence (mh-seq-msgs old-seq))
-    (rplaca old-seq new-name)))
+(defun mh-parse-flist-output-line (line &optional current-folder)
+  "Parse LINE to generate folder name, unseen messages and total messages.
+If CURRENT-FOLDER is non-nil then it contains the current folder
+name and it is used to avoid problems in corner cases involving
+folders whose names end with a '+' character."
+  (with-temp-buffer
+    (insert line)
+    (goto-char (point-max))
+    (let (folder unseen total p)
+      (when (search-backward " out of " (point-min) t)
+        (setq total (string-to-number
+                     (buffer-substring-no-properties
+                      (match-end 0) (line-end-position))))
+        (when (search-backward " in sequence " (point-min) t)
+          (setq p (point))
+          (when (search-backward " has " (point-min) t)
+            (setq unseen (string-to-number (buffer-substring-no-properties
+                                            (match-end 0) p)))
+            (while (eq (char-after) ? )
+              (backward-char))
+            (setq folder (buffer-substring-no-properties
+                          (point-min) (1+ (point))))
+            (when (and (equal (aref folder (1- (length folder))) ?+)
+                       (equal current-folder folder))
+              (setq folder (substring folder 0 (1- (length folder)))))
+            (values (format "+%s" folder) unseen total)))))))
+
+;;;###mh-autoload
+(defun mh-read-folder-sequences (folder save-refiles)
+  "Read and return the predefined sequences for a FOLDER.
+If SAVE-REFILES is non-nil, then keep the sequences
+that note messages to be refiled."
+  (let ((seqs ()))
+    (cond (save-refiles
+           (mh-mapc (function (lambda (seq) ; Save the refiling sequences
+                                (if (mh-folder-name-p (mh-seq-name seq))
+                                    (setq seqs (cons seq seqs)))))
+                    mh-seq-list)))
+    (save-excursion
+      (if (eq 0 (mh-exec-cmd-quiet nil "mark" folder "-list"))
+          (progn
+            ;; look for name in line of form "cur: 4" or "myseq (private): 23"
+            (while (re-search-forward "^[^: ]+" nil t)
+              (setq seqs (cons (mh-make-seq (intern (buffer-substring
+                                                     (match-beginning 0)
+                                                     (match-end 0)))
+                                            (mh-read-msg-list))
+                               seqs)))
+            (delete-region (point-min) (point))))) ; avoid race with
+                                        ; mh-process-daemon
+    seqs))
+
+(defun mh-read-msg-list ()
+  "Return a list of message numbers from point to the end of the line.
+Expands ranges into set of individual numbers."
+  (let ((msgs ())
+        (end-of-line (save-excursion (end-of-line) (point)))
+        num)
+    (while (re-search-forward "[0-9]+" end-of-line t)
+      (setq num (string-to-number (buffer-substring (match-beginning 0)
+                                                    (match-end 0))))
+      (cond ((looking-at "-")           ; Message range
+             (forward-char 1)
+             (re-search-forward "[0-9]+" end-of-line t)
+             (let ((num2 (string-to-number
+                          (buffer-substring (match-beginning 0)
+                                            (match-end 0)))))
+               (if (< num2 num)
+                   (error "Bad message range: %d-%d" num num2))
+               (while (<= num num2)
+                 (setq msgs (cons num msgs))
+                 (setq num (1+ num)))))
+            ((not (zerop num))          ;"pick" outputs "0" to mean no match
+             (setq msgs (cons num msgs)))))
+    msgs))
+
+
+
+;;; Notation
+
+;;;###mh-autoload
+(defun mh-notate (msg notation offset)
+  "Mark MSG with the character NOTATION at position OFFSET.
+Null MSG means the message at cursor.
+If NOTATION is nil then no change in the buffer occurs."
+  (save-excursion
+    (if (or (null msg)
+            (mh-goto-msg msg t t))
+        (with-mh-folder-updating (t)
+          (beginning-of-line)
+          (forward-char offset)
+          (let* ((change-stack-flag
+                  (and (equal offset
+                              (+ mh-cmd-note mh-scan-field-destination-offset))
+                       (not (eq notation mh-note-seq))))
+                 (msg (and change-stack-flag (or msg (mh-get-msg-num nil))))
+                 (stack (and msg (gethash msg mh-sequence-notation-history)))
+                 (notation (or notation (char-after))))
+            (if stack
+                ;; The presence of the stack tells us that we don't need to
+                ;; notate the message, since the notation would be replaced
+                ;; by a sequence notation. So we will just put the notation
+                ;; at the bottom of the stack. If the sequence is deleted,
+                ;; the correct notation will be shown.
+                (setf (gethash msg mh-sequence-notation-history)
+                      (reverse (cons notation (cdr (reverse stack)))))
+              ;; Since we don't have any sequence notations in the way, just
+              ;; notate the scan line.
+              (delete-char 1)
+              (insert notation))
+            (when change-stack-flag
+              (mh-thread-update-scan-line-map msg notation offset)))))))
 
 ;;;###mh-autoload
 (defun mh-notate-cur ()
@@ -596,1207 +893,124 @@
       (setq overlay-arrow-position mh-arrow-marker))))
 
 ;;;###mh-autoload
-(defun mh-add-to-sequence (seq msgs)
-  "The sequence SEQ is augmented with the messages in MSGS."
-  ;; Add to a SEQUENCE each message the list of MSGS.
-  (if (and (mh-valid-seq-p seq) (not (mh-folder-name-p seq)))
-      (if msgs
-          (apply 'mh-exec-cmd "mark" mh-current-folder "-add"
-                 "-sequence" (symbol-name seq)
-                 (mh-coalesce-msg-list msgs)))))
-
-(defvar mh-thread-last-ancestor)
-
-(defun mh-copy-seq-to-eob (seq)
-  "Copy SEQ to the end of the buffer."
-  ;; It is quite involved to write something which will work at any place in
-  ;; the buffer, so we will write something which works only at the end of
-  ;; the buffer. If we ever need to insert sequences in the middle of the
-  ;; buffer, this will need to be fixed.
-  (save-excursion
-    (let* ((msgs (mh-seq-to-msgs seq))
-           (coalesced-msgs (mh-coalesce-msg-list msgs)))
-      (goto-char (point-max))
-      (save-restriction
-        (narrow-to-region (point) (point))
-        (mh-regenerate-headers coalesced-msgs t)
-        (cond ((memq 'unthread mh-view-ops)
-               ;; Populate restricted scan-line map
-               (mh-remove-all-notation)
-               (mh-iterate-on-range msg (cons (point-min) (point-max))
-                 (setf (gethash msg mh-thread-scan-line-map)
-                       (mh-thread-parse-scan-line)))
-               ;; Remove scan lines and read results from pre-computed tree
-               (delete-region (point-min) (point-max))
-               (mh-thread-print-scan-lines
-                (mh-thread-generate mh-current-folder ()))
-               (mh-notate-user-sequences))
-              (mh-index-data
-               (mh-index-insert-folder-headers)))))))
+(defun mh-remove-cur-notation ()
+  "Remove old cur notation."
+  (let ((cur-msg (car (mh-seq-to-msgs 'cur))))
+    (save-excursion
+      (when (and cur-msg
+                 (mh-goto-msg cur-msg t t)
+                 (looking-at mh-scan-cur-msg-number-regexp))
+        (mh-notate nil ?  mh-cmd-note)
+        (setq overlay-arrow-position nil)))))
 
+;; FIXME?  We may want to clear all notations and add one for current-message
+;;         and process user sequences.
 ;;;###mh-autoload
-(defmacro mh-iterate-on-messages-in-region (var begin end &rest body)
-  "Iterate over region.
-
-VAR is bound to the message on the current line as we loop
-starting from BEGIN till END. In each step BODY is executed.
-
-If VAR is nil then the loop is executed without any binding."
-  (unless (symbolp var)
-    (error "Can not bind the non-symbol %s" var))
-  (let ((binding-needed-flag var))
-    `(save-excursion
-       (goto-char ,begin)
-       (beginning-of-line)
-       (while (and (<= (point) ,end) (not (eobp)))
-         (when (looking-at mh-scan-valid-regexp)
-           (let ,(if binding-needed-flag `((,var (mh-get-msg-num t))) ())
-             ,@body))
-         (forward-line 1)))))
-
-(put 'mh-iterate-on-messages-in-region 'lisp-indent-hook 'defun)
-
-;;;###mh-autoload
-(defmacro mh-iterate-on-range (var range &rest body)
-  "Iterate an operation over a region or sequence.
-
-VAR is bound to each message in turn in a loop over RANGE, which
-can be a message number, a list of message numbers, a sequence, a
-region in a cons cell, or a MH range (something like last:20) in
-a string. In each iteration, BODY is executed.
-
-The parameter RANGE is usually created with
-`mh-interactive-range' in order to provide a uniform interface to
-MH-E functions."
-  (unless (symbolp var)
-    (error "Can not bind the non-symbol %s" var))
-  (let ((binding-needed-flag var)
-        (msgs (make-symbol "msgs"))
-        (seq-hash-table (make-symbol "seq-hash-table")))
-    `(cond ((numberp ,range)
-            (when (mh-goto-msg ,range t t)
-              (let ,(if binding-needed-flag `((,var ,range)) ())
-                ,@body)))
-           ((and (consp ,range)
-                 (numberp (car ,range)) (numberp (cdr ,range)))
-            (mh-iterate-on-messages-in-region ,var
-              (car ,range) (cdr ,range)
-              ,@body))
-           (t (let ((,msgs (cond ((and ,range (symbolp ,range))
-                                  (mh-seq-to-msgs ,range))
-                                 ((stringp ,range)
-                                  (mh-translate-range mh-current-folder
-                                                      ,range))
-                                 (t ,range)))
-                    (,seq-hash-table (make-hash-table)))
-                (dolist (msg ,msgs)
-                  (setf (gethash msg ,seq-hash-table) t))
-                (mh-iterate-on-messages-in-region v (point-min) (point-max)
-                  (when (gethash v ,seq-hash-table)
-                    (let ,(if binding-needed-flag `((,var v)) ())
-                      ,@body))))))))
-
-(put 'mh-iterate-on-range 'lisp-indent-hook 'defun)
+(defun mh-notate-deleted-and-refiled ()
+  "Notate messages marked for deletion or refiling.
+Messages to be deleted are given by `mh-delete-list' while
+messages to be refiled are present in `mh-refile-list'."
+  (let ((refiled-hash (make-hash-table))
+        (deleted-hash (make-hash-table)))
+    (dolist (msg mh-delete-list)
+      (setf (gethash msg deleted-hash) t))
+    (dolist (dest-msg-list mh-refile-list)
+      (dolist (msg (cdr dest-msg-list))
+        (setf (gethash msg refiled-hash) t)))
+    (mh-iterate-on-messages-in-region msg (point-min) (point-max)
+      (cond ((gethash msg refiled-hash)
+             (mh-notate nil mh-note-refiled mh-cmd-note))
+            ((gethash msg deleted-hash)
+             (mh-notate nil mh-note-deleted mh-cmd-note))))))
 
 ;;;###mh-autoload
-(defun mh-range-to-msg-list (range)
-  "Return a list of messages for RANGE.
+(defun mh-notate-user-sequences (&optional range)
+  "Mark user-defined sequences in RANGE.
 
 Check the documentation of `mh-interactive-range' to see how
-RANGE is read in interactive use."
-  (let (msg-list)
+RANGE is read in interactive use; 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)))
+    (dolist (seq seqs)
+      (dolist (msg (mh-seq-msgs seq))
+        (push (car seq) (gethash msg msg-hash))))
     (mh-iterate-on-range msg range
-      (push msg msg-list))
-    (nreverse msg-list)))
-
-;;;###mh-autoload
-(defun mh-interactive-range (range-prompt &optional default)
-  "Return interactive specification for message, sequence, range or region.
-By convention, the name of this argument is RANGE.
-
-If variable `transient-mark-mode' is non-nil and the mark is active,
-then this function returns a cons-cell of the region.
-
-If optional prefix argument is provided, then prompt for message range
-with RANGE-PROMPT. A list of messages in that range is returned.
-
-If a MH range is given, say something like last:20, then a list
-containing the messages in that range is returned.
-
-If DEFAULT non-nil then it is returned.
-
-Otherwise, the message number at point is returned.
-
-This function is usually used with `mh-iterate-on-range' in order to
-provide a uniform interface to MH-E functions."
-  (cond ((mh-mark-active-p t) (cons (region-beginning) (region-end)))
-        (current-prefix-arg (mh-read-range range-prompt nil nil t t))
-        (default default)
-        (t (mh-get-msg-num t))))
-
-
-
-;;; Commands to handle new 'subject sequence ("Poor man's threading" by psg)
-
-;; XXX: The function mh-subject-to-sequence-unthreaded uses the magic number
-;;  41 for the max size of the subject part. Avoiding this would be desirable.
-(defun mh-subject-to-sequence (all)
-  "Put all following messages with same subject in sequence 'subject.
-If arg ALL is t, move to beginning of folder buffer to collect all
-messages.
-If arg ALL is nil, collect only messages fron current one on forward.
-
-Return number of messages put in the sequence:
-
- nil -> there was no subject line.
-
- 0   -> there were no later messages with the same
-        subject (sequence not made)
-
- >1  -> the total number of messages including current one."
-  (if (memq 'unthread mh-view-ops)
-      (mh-subject-to-sequence-threaded all)
-    (mh-subject-to-sequence-unthreaded all)))
-
-(defun mh-subject-to-sequence-unthreaded (all)
-  "Put all following messages with same subject in sequence 'subject.
-
-This function only works with an unthreaded folder. If arg ALL is
-t, move to beginning of folder buffer to collect all messages. If
-arg ALL is nil, collect only messages fron current one on
-forward.
-
-Return number of messages put in the sequence:
-
- nil -> there was no subject line.
- 0   -> there were no later messages with the same
-        subject (sequence not made)
- >1  -> the total number of messages including current one."
-  (if (not (eq major-mode 'mh-folder-mode))
-      (error "Not in a folder buffer"))
-  (save-excursion
-    (beginning-of-line)
-    (if (or (not (looking-at mh-scan-subject-regexp))
-            (not (match-string 3))
-            (string-equal "" (match-string 3)))
-        (progn (message "No subject line")
-               nil)
-      (let ((subject (match-string-no-properties 3))
-            (list))
-        (if (> (length subject) 41)
-            (setq subject (substring subject 0 41)))
-        (save-excursion
-          (if all
-              (goto-char (point-min)))
-          (while (re-search-forward mh-scan-subject-regexp nil t)
-            (let ((this-subject (match-string-no-properties 3)))
-              (if (> (length this-subject) 41)
-                  (setq this-subject (substring this-subject 0 41)))
-              (if (string-equal this-subject subject)
-                  (setq list (cons (mh-get-msg-num t) list))))))
-        (cond
-         (list
-          ;; If we created a new sequence, add the initial message to it too.
-          (if (not (member (mh-get-msg-num t) list))
-              (setq list (cons (mh-get-msg-num t) list)))
-          (if (assoc 'subject mh-seq-list) (mh-delete-seq 'subject))
-          ;; sort the result into a sequence
-          (let ((sorted-list (sort (copy-sequence list) 'mh-lessp)))
-            (while sorted-list
-              (mh-add-msgs-to-seq (car sorted-list) 'subject nil)
-              (setq sorted-list (cdr sorted-list)))
-            (safe-length list)))
-         (t
-          0))))))
-
-(defun mh-subject-to-sequence-threaded (all)
-  "Put all messages with the same subject in the 'subject sequence.
-
-This function works when the folder is threaded. In this
-situation the subject could get truncated and so the normal
-matching doesn't work.
-
-The parameter ALL is non-nil then all the messages in the buffer
-are considered, otherwise only the messages after the current one
-are taken into account."
-  (let* ((cur (mh-get-msg-num nil))
-         (subject (mh-thread-find-msg-subject cur))
-         region msgs)
-    (if (null subject)
-        (and (message "No subject line") nil)
-      (setq region (cons (if all (point-min) (point)) (point-max)))
-      (mh-iterate-on-range msg region
-        (when (eq (mh-thread-find-msg-subject msg) subject)
-          (push msg msgs)))
-      (setq msgs (sort msgs #'mh-lessp))
-      (if (null msgs)
-          0
-        (when (assoc 'subject mh-seq-list)
-          (mh-delete-seq 'subject))
-        (mh-add-msgs-to-seq msgs 'subject)
-        (length msgs)))))
-
-(defun mh-thread-find-msg-subject (msg)
-  "Find canonicalized subject of MSG.
-This function can only be used the folder is threaded."
-  (ignore-errors
-    (mh-message-subject
-     (mh-container-message (gethash (gethash msg mh-thread-index-id-map)
-                                    mh-thread-id-table)))))
-
-(defun mh-edit-pick-expr (default)
-  "With prefix arg edit a pick expression.
-If no prefix arg is given, then return DEFAULT."
-  (let ((default-string (loop for x in default concat (format " %s" x))))
-    (if (or current-prefix-arg (equal default-string ""))
-        (mh-pick-args-list (read-string "Pick expression: "
-                                        default-string))
-      default)))
-
-(defun mh-pick-args-list (s)
-  "Form list by grouping elements in string S suitable for pick arguments.
-For example, the string \"-subject a b c -from Joe User
-<address@hidden>\" is converted to (\"-subject\" \"a b c\"
-\"-from\" \"Joe User <address@hidden>\""
-  (let ((full-list (split-string s))
-        current-arg collection arg-list)
-    (while full-list
-      (setq current-arg (car full-list))
-      (if (null (string-match "^-" current-arg))
-          (setq collection
-                (if (null collection)
-                    current-arg
-                  (format "%s %s" collection current-arg)))
-        (when collection
-          (setq arg-list (append arg-list (list collection)))
-          (setq collection nil))
-        (setq arg-list (append arg-list (list current-arg))))
-      (setq full-list (cdr full-list)))
-    (when collection
-      (setq arg-list (append arg-list (list collection))))
-    arg-list))
-
-;;;###mh-autoload
-(defun mh-narrow-to-subject (&optional pick-expr)
-  "Limit to messages with same subject.
-With a prefix argument, edit PICK-EXPR.
-
-Use \\<mh-folder-mode-map>\\[mh-widen] to undo this command."
-  (interactive
-   (list (mh-edit-pick-expr (mh-current-message-header-field 'subject))))
-  (mh-narrow-to-header-field 'subject pick-expr))
-
-;;;###mh-autoload
-(defun mh-narrow-to-from (&optional pick-expr)
-  "Limit to messages with the same \"From:\" field.
-With a prefix argument, edit PICK-EXPR.
-
-Use \\<mh-folder-mode-map>\\[mh-widen] to undo this command."
-  (interactive
-   (list (mh-edit-pick-expr (mh-current-message-header-field 'from))))
-  (mh-narrow-to-header-field 'from pick-expr))
-
-;;;###mh-autoload
-(defun mh-narrow-to-cc (&optional pick-expr)
-  "Limit to messages with the same \"Cc:\" field.
-With a prefix argument, edit PICK-EXPR.
-
-Use \\<mh-folder-mode-map>\\[mh-widen] to undo this command."
-  (interactive
-   (list (mh-edit-pick-expr (mh-current-message-header-field 'cc))))
-  (mh-narrow-to-header-field 'cc pick-expr))
-
-;;;###mh-autoload
-(defun mh-narrow-to-to (&optional pick-expr)
-  "Limit to messages with the same \"To:\" field.
-With a prefix argument, edit PICK-EXPR.
-
-Use \\<mh-folder-mode-map>\\[mh-widen] to undo this command."
-  (interactive
-   (list (mh-edit-pick-expr (mh-current-message-header-field 'to))))
-  (mh-narrow-to-header-field 'to pick-expr))
-
-(defun mh-narrow-to-header-field (header-field pick-expr)
-  "Limit to messages whose HEADER-FIELD match PICK-EXPR.
-The MH command pick is used to do the match."
-  (let ((folder mh-current-folder)
-        (original (mh-coalesce-msg-list
-                   (mh-range-to-msg-list (cons (point-min) (point-max)))))
-        (msg-list ()))
-    (with-temp-buffer
-      (apply #'mh-exec-cmd-output "pick" nil folder
-             (append original (list "-list") pick-expr))
-      (goto-char (point-min))
-      (while (not (eobp))
-        (let ((num (ignore-errors
-                     (string-to-number
-                      (buffer-substring (point) (line-end-position))))))
-          (when num (push num msg-list))
-          (forward-line))))
-    (if (null msg-list)
-        (message "No matches")
-      (when (assoc 'header mh-seq-list) (mh-delete-seq 'header))
-      (mh-add-msgs-to-seq msg-list 'header)
-      (mh-narrow-to-seq 'header))))
-
-(defun mh-current-message-header-field (header-field)
-  "Return a pick regexp to match HEADER-FIELD of the message at point."
-  (let ((num (mh-get-msg-num nil)))
-    (when num
-      (let ((folder mh-current-folder))
-        (with-temp-buffer
-          (insert-file-contents-literally (mh-msg-filename num folder))
-          (goto-char (point-min))
-          (when (search-forward "\n\n" nil t)
-            (narrow-to-region (point-min) (point)))
-          (let* ((field (or (message-fetch-field (format "%s" header-field))
-                            ""))
-                 (field-option (format "-%s" header-field))
-                 (patterns (loop for x in (split-string  field "[ ]*,[ ]*")
-                                 unless (equal x "")
-                                 collect (if (string-match 
"<\\(address@hidden)>" x)
-                                             (match-string 1 x)
-                                           x))))
-            (when patterns
-              (loop with accum = `(,field-option ,(car patterns))
-                    for e in (cdr patterns)
-                    do (setq accum `(,field-option ,e "-or" ,@accum))
-                    finally return accum))))))))
-
-;;;###mh-autoload
-(defun mh-narrow-to-range (range)
-  "Limit to RANGE.
-
-Check the documentation of `mh-interactive-range' to see how
-RANGE is read in interactive use.
-
-Use \\<mh-folder-mode-map>\\[mh-widen] to undo this command."
-  (interactive (list (mh-interactive-range "Narrow to")))
-  (when (assoc 'range mh-seq-list) (mh-delete-seq 'range))
-  (mh-add-msgs-to-seq (mh-range-to-msg-list range) 'range)
-  (mh-narrow-to-seq 'range))
-
-
-;;;###mh-autoload
-(defun mh-delete-subject ()
-  "Delete messages with same subject\\<mh-folder-mode-map>.
-
-To delete messages faster, you can use this command to delete all
-the messages with the same subject as the current message. This
-command puts these messages in a sequence named \"subject\". You
-can undo this action by using \\[mh-undo] with a prefix argument
-and then specifying the \"subject\" sequence."
-  (interactive)
-  (let ((count (mh-subject-to-sequence nil)))
-    (cond
-     ((not count)                       ; No subject line, delete msg anyway
-      (mh-delete-msg (mh-get-msg-num t)))
-     ((= 0 count)                       ; No other msgs, delete msg anyway.
-      (message "No other messages with same Subject following this one")
-      (mh-delete-msg (mh-get-msg-num t)))
-     (t                                 ; We have a subject sequence.
-      (message "Marked %d messages for deletion" count)
-      (mh-delete-msg 'subject)))))
-
-;;;###mh-autoload
-(defun mh-delete-subject-or-thread ()
-  "Delete messages with same subject or thread\\<mh-folder-mode-map>.
-
-To delete messages faster, you can use this command to delete all
-the messages with the same subject as the current message. This
-command puts these messages in a sequence named \"subject\". You
-can undo this action by using \\[mh-undo] with a prefix argument
-and then specifying the \"subject\" sequence.
-
-However, if the buffer is displaying a threaded view of the
-folder then this command behaves like \\[mh-thread-delete]."
-  (interactive)
-  (if (memq 'unthread mh-view-ops)
-      (mh-thread-delete)
-    (mh-delete-subject)))
-
-
-
-;;; Message threading:
-
-(defmacro mh-thread-initialize-hash (var test)
-  "Initialize the hash table in VAR.
-TEST is the test to use when creating a new hash table."
-  (unless (symbolp var) (error "Expected a symbol: %s" var))
-  `(if ,var (clrhash ,var) (setq ,var (make-hash-table :test ,test))))
-
-(defun mh-thread-initialize ()
-  "Make new hash tables, or clear them if already present."
-  (mh-thread-initialize-hash mh-thread-id-hash #'equal)
-  (mh-thread-initialize-hash mh-thread-subject-hash #'equal)
-  (mh-thread-initialize-hash mh-thread-id-table #'eq)
-  (mh-thread-initialize-hash mh-thread-id-index-map #'eq)
-  (mh-thread-initialize-hash mh-thread-index-id-map #'eql)
-  (mh-thread-initialize-hash mh-thread-scan-line-map #'eql)
-  (mh-thread-initialize-hash mh-thread-subject-container-hash #'eq)
-  (mh-thread-initialize-hash mh-thread-duplicates #'eq)
-  (setq mh-thread-history ()))
-
-(defsubst mh-thread-id-container (id)
-  "Given ID, return the corresponding container in `mh-thread-id-table'.
-If no container exists then a suitable container is created and
-the id-table is updated."
-  (when (not id)
-    (error "1"))
-  (or (gethash id mh-thread-id-table)
-      (setf (gethash id mh-thread-id-table)
-            (let ((message (mh-thread-make-message :id id)))
-              (mh-thread-make-container :message message)))))
-
-(defsubst mh-thread-remove-parent-link (child)
-  "Remove parent link of CHILD if it exists."
-  (let* ((child-container (if (mh-thread-container-p child)
-                              child (mh-thread-id-container child)))
-         (parent-container (mh-container-parent child-container)))
-    (when parent-container
-      (setf (mh-container-children parent-container)
-            (loop for elem in (mh-container-children parent-container)
-                  unless (eq child-container elem) collect elem))
-      (setf (mh-container-parent child-container) nil))))
-
-(defsubst mh-thread-add-link (parent child &optional at-end-p)
-  "Add links so that PARENT becomes a parent of CHILD.
-Doesn't make any changes if CHILD is already an ancestor of
-PARENT. If optional argument AT-END-P is non-nil, the CHILD is
-added to the end of the children list of PARENT."
-  (let ((parent-container (cond ((null parent) nil)
-                                ((mh-thread-container-p parent) parent)
-                                (t (mh-thread-id-container parent))))
-        (child-container (if (mh-thread-container-p child)
-                             child (mh-thread-id-container child))))
-    (when (and parent-container
-               (not (mh-thread-ancestor-p child-container parent-container))
-               (not (mh-thread-ancestor-p parent-container child-container)))
-      (mh-thread-remove-parent-link child-container)
-      (cond ((not at-end-p)
-             (push child-container (mh-container-children parent-container)))
-            ((null (mh-container-children parent-container))
-             (push child-container (mh-container-children parent-container)))
-            (t (let ((last-child (mh-container-children parent-container)))
-                 (while (cdr last-child)
-                   (setq last-child (cdr last-child)))
-                 (setcdr last-child (cons child-container nil)))))
-      (setf (mh-container-parent child-container) parent-container))
-    (unless parent-container
-      (mh-thread-remove-parent-link child-container))))
-
-(defun mh-thread-ancestor-p (ancestor successor)
-  "Return t if ANCESTOR is really an ancestor of SUCCESSOR and nil otherwise.
-In the limit, the function returns t if ANCESTOR and SUCCESSOR
-are the same containers."
-  (block nil
-    (while successor
-      (when (eq ancestor successor) (return t))
-      (setq successor (mh-container-parent successor)))
-    nil))
-
-(defsubst mh-thread-get-message-container (message)
-  "Return container which has MESSAGE in it.
-If there is no container present then a new container is
-allocated."
-  (let* ((id (mh-message-id message))
-         (container (gethash id mh-thread-id-table)))
-    (cond (container (setf (mh-container-message container) message)
-                     container)
-          (t (setf (gethash id mh-thread-id-table)
-                   (mh-thread-make-container :message message))))))
-
-(defsubst mh-thread-get-message (id subject-re-p subject refs)
-  "Return appropriate message.
-Otherwise update message already present to have the proper ID,
-SUBJECT-RE-P, SUBJECT and REFS fields."
-  (let* ((container (gethash id mh-thread-id-table))
-         (message (if container (mh-container-message container) nil)))
-    (cond (message
-           (setf (mh-message-subject-re-p message) subject-re-p)
-           (setf (mh-message-subject message) subject)
-           (setf (mh-message-id message) id)
-           (setf (mh-message-references message) refs)
-           message)
-          (container
-           (setf (mh-container-message container)
-                 (mh-thread-make-message :id id :references refs
-                                         :subject subject
-                                         :subject-re-p subject-re-p)))
-          (t (let ((message (mh-thread-make-message :id id :references refs
-                                                    :subject-re-p subject-re-p
-                                                    :subject subject)))
-               (prog1 message
-                 (mh-thread-get-message-container message)))))))
-
-(defsubst mh-thread-canonicalize-id (id)
-  "Produce canonical string representation for ID.
-This allows cheap string comparison with EQ."
-  (or (and (equal id "") (copy-sequence ""))
-      (gethash id mh-thread-id-hash)
-      (setf (gethash id mh-thread-id-hash) id)))
-
-(defsubst mh-thread-prune-subject (subject)
-  "Prune leading Re:'s, Fwd:'s etc. and trailing (fwd)'s from SUBJECT.
-If the result after pruning is not the empty string then it is
-canonicalized so that subjects can be tested for equality with
-eq. This is done so that all the messages without a subject are
-not put into a single thread."
-  (let ((case-fold-search t)
-        (subject-pruned-flag nil))
-    ;; Prune subject leader
-    (while (or (string-match "^[ \t]*\\(re\\|fwd?\\)\\(\\[[0-9]*\\]\\)?:[ \t]*"
-                             subject)
-               (string-match "^[ \t]*\\[[^\\]][ \t]*" subject))
-      (setq subject-pruned-flag t)
-      (setq subject (substring subject (match-end 0))))
-    ;; Prune subject trailer
-    (while (or (string-match "(fwd)$" subject)
-               (string-match "[ \t]+$" subject))
-      (setq subject-pruned-flag t)
-      (setq subject (substring subject 0 (match-beginning 0))))
-    ;; Canonicalize subject only if it is non-empty
-    (cond ((equal subject "") (values subject subject-pruned-flag))
-          (t (values
-              (or (gethash subject mh-thread-subject-hash)
-                  (setf (gethash subject mh-thread-subject-hash) subject))
-              subject-pruned-flag)))))
-
-(defun mh-thread-container-subject (container)
-  "Return the subject of CONTAINER.
-If CONTAINER is empty return the subject info of one of its
-children."
-  (cond ((and (mh-container-message container)
-              (mh-message-id (mh-container-message container)))
-         (mh-message-subject (mh-container-message container)))
-        (t (block nil
-             (dolist (kid (mh-container-children container))
-               (when (and (mh-container-message kid)
-                          (mh-message-id (mh-container-message kid)))
-                 (let ((kid-message (mh-container-message kid)))
-                   (return (mh-message-subject kid-message)))))
-             (error "This can't happen")))))
-
-(defun mh-thread-rewind-pruning ()
-  "Restore the thread tree to its state before pruning."
-  (while mh-thread-history
-    (let ((action (pop mh-thread-history)))
-      (cond ((eq (car action) 'DROP)
-             (mh-thread-remove-parent-link (cadr action))
-             (mh-thread-add-link (caddr action) (cadr action)))
-            ((eq (car action) 'PROMOTE)
-             (let ((node (cadr action))
-                   (parent (caddr action))
-                   (children (cdddr action)))
-               (dolist (child children)
-                 (mh-thread-remove-parent-link child)
-                 (mh-thread-add-link node child))
-               (mh-thread-add-link parent node)))
-            ((eq (car action) 'SUBJECT)
-             (let ((node (cadr action)))
-               (mh-thread-remove-parent-link node)
-               (setf (mh-container-real-child-p node) t)))))))
-
-(defun mh-thread-prune-containers (roots)
-  "Prune empty containers in the containers ROOTS."
-  (let ((dfs-ordered-nodes ())
-        (work-list roots))
-    (while work-list
-      (let ((node (pop work-list)))
-        (dolist (child (mh-container-children node))
-          (push child work-list))
-        (push node dfs-ordered-nodes)))
-    (while dfs-ordered-nodes
-      (let ((node (pop dfs-ordered-nodes)))
-        (cond ((gethash (mh-message-id (mh-container-message node))
-                        mh-thread-id-index-map)
-               ;; Keep it
-               (setf (mh-container-children node)
-                     (mh-thread-sort-containers (mh-container-children node))))
-              ((and (mh-container-children node)
-                    (or (null (cdr (mh-container-children node)))
-                        (mh-container-parent node)))
-               ;; Promote kids
-               (let ((children ()))
-                 (dolist (kid (mh-container-children node))
-                   (mh-thread-remove-parent-link kid)
-                   (mh-thread-add-link (mh-container-parent node) kid)
-                   (push kid children))
-                 (push `(PROMOTE ,node ,(mh-container-parent node) ,@children)
-                       mh-thread-history)
-                 (mh-thread-remove-parent-link node)))
-              ((mh-container-children node)
-               ;; Promote the first orphan to parent and add the other kids as
-               ;; his children
-               (setf (mh-container-children node)
-                     (mh-thread-sort-containers (mh-container-children node)))
-               (let ((new-parent (car (mh-container-children node)))
-                     (other-kids (cdr (mh-container-children node))))
-                 (mh-thread-remove-parent-link new-parent)
-                 (dolist (kid other-kids)
-                   (mh-thread-remove-parent-link kid)
-                   (setf (mh-container-real-child-p kid) nil)
-                   (mh-thread-add-link new-parent kid t))
-                 (push `(PROMOTE ,node ,(mh-container-parent node)
-                                 ,new-parent ,@other-kids)
-                       mh-thread-history)
-                 (mh-thread-remove-parent-link node)))
-              (t
-               ;; Drop it
-               (push `(DROP ,node ,(mh-container-parent node))
-                     mh-thread-history)
-               (mh-thread-remove-parent-link node)))))
-    (let ((results ()))
-      (maphash #'(lambda (k v)
-                   (declare (ignore k))
-                   (when (and (null (mh-container-parent v))
-                              (gethash (mh-message-id (mh-container-message v))
-                                       mh-thread-id-index-map))
-                     (push v results)))
-               mh-thread-id-table)
-      (mh-thread-sort-containers results))))
-
-(defun mh-thread-sort-containers (containers)
-  "Sort a list of message CONTAINERS to be in ascending order wrt index."
-  (sort containers
-        #'(lambda (x y)
-            (when (and (mh-container-message x) (mh-container-message y))
-              (let* ((id-x (mh-message-id (mh-container-message x)))
-                     (id-y (mh-message-id (mh-container-message y)))
-                     (index-x (gethash id-x mh-thread-id-index-map))
-                     (index-y (gethash id-y mh-thread-id-index-map)))
-                (and (integerp index-x) (integerp index-y)
-                     (< index-x index-y)))))))
-
-(defsubst mh-thread-group-by-subject (roots)
-  "Group the set of message containers, ROOTS based on subject.
-Bug: Check for and make sure that something without Re: is made
-the parent in preference to something that has it."
-  (clrhash mh-thread-subject-container-hash)
-  (let ((results ()))
-    (dolist (root roots)
-      (let* ((subject (mh-thread-container-subject root))
-             (parent (gethash subject mh-thread-subject-container-hash)))
-        (cond (parent (mh-thread-remove-parent-link root)
-                      (mh-thread-add-link parent root t)
-                      (setf (mh-container-real-child-p root) nil)
-                      (push `(SUBJECT ,root) mh-thread-history))
-              (t
-               (setf (gethash subject mh-thread-subject-container-hash) root)
-               (push root results)))))
-    (nreverse results)))
-
-(defun mh-thread-process-in-reply-to (reply-to-header)
-  "Extract message id's from REPLY-TO-HEADER.
-Ideally this should have some regexp which will try to guess if a
-string between < and > is a message id and not an email address.
-For now it will take the last string inside angles."
-  (let ((end (mh-search-from-end ?> reply-to-header)))
-    (when (numberp end)
-      (let ((begin (mh-search-from-end ?< (substring reply-to-header 0 end))))
-        (when (numberp begin)
-          (list (substring reply-to-header begin (1+ end))))))))
-
-(defun mh-thread-set-tables (folder)
-  "Use the tables of FOLDER in current buffer."
-  (flet ((mh-get-table (symbol)
-                       (save-excursion
-                         (set-buffer folder)
-                         (symbol-value symbol))))
-    (setq mh-thread-id-hash (mh-get-table 'mh-thread-id-hash))
-    (setq mh-thread-subject-hash (mh-get-table 'mh-thread-subject-hash))
-    (setq mh-thread-id-table (mh-get-table 'mh-thread-id-table))
-    (setq mh-thread-id-index-map (mh-get-table 'mh-thread-id-index-map))
-    (setq mh-thread-index-id-map (mh-get-table 'mh-thread-index-id-map))
-    (setq mh-thread-scan-line-map (mh-get-table 'mh-thread-scan-line-map))
-    (setq mh-thread-subject-container-hash
-          (mh-get-table 'mh-thread-subject-container-hash))
-    (setq mh-thread-duplicates (mh-get-table 'mh-thread-duplicates))
-    (setq mh-thread-history (mh-get-table 'mh-thread-history))))
-
-(defsubst mh-thread-update-id-index-maps (id index)
-  "Message with id, ID is the message in INDEX.
-The function also checks for duplicate messages (that is multiple
-messages with the same ID). These messages are put in the
-`mh-thread-duplicates' hash table."
-  (let ((old-index (gethash id mh-thread-id-index-map)))
-    (when old-index (push old-index (gethash id mh-thread-duplicates)))
-    (setf (gethash id mh-thread-id-index-map) index)
-    (setf (gethash index mh-thread-index-id-map) id)))
-
-
-
-;;; Generate Threads...
+      (loop for seq in (gethash msg msg-hash)
+            do (mh-add-sequence-notation msg (mh-internal-seq seq))))))
 
-(defvar mh-message-id-regexp "^<address@hidden>$"
-  "Regexp to recognize whether a string is a message identifier.")
-
-(defun mh-thread-generate (folder msg-list)
-  "Scan FOLDER to get info for threading.
-Only information about messages in MSG-LIST are added to the tree."
-  (with-temp-buffer
-    (mh-thread-set-tables folder)
-    (when msg-list
-      (apply
-       #'call-process (expand-file-name mh-scan-prog mh-progs) nil '(t nil) nil
-       "-width" "10000" "-format"
-       "%(msg)\n%{message-id}\n%{references}\n%{in-reply-to}\n%{subject}\n"
-       folder (mapcar #'(lambda (x) (format "%s" x)) msg-list)))
-    (goto-char (point-min))
-    (let ((roots ())
-          (case-fold-search t))
-      (block nil
-        (while (not (eobp))
-          (block process-message
-            (let* ((index-line
-                    (prog1 (buffer-substring (point) (line-end-position))
-                      (forward-line)))
-                   (index (string-to-number index-line))
-                   (id (prog1 (buffer-substring (point) (line-end-position))
-                         (forward-line)))
-                   (refs (prog1 (buffer-substring (point) (line-end-position))
-                           (forward-line)))
-                   (in-reply-to (prog1 (buffer-substring (point)
-                                                         (line-end-position))
-                                  (forward-line)))
-                   (subject (prog1
-                                (buffer-substring (point) (line-end-position))
-                              (forward-line)))
-                   (subject-re-p nil))
-              (unless (gethash index mh-thread-scan-line-map)
-                (return-from process-message))
-              (unless (integerp index) (return)) ;Error message here
-              (multiple-value-setq (subject subject-re-p)
-                (mh-thread-prune-subject subject))
-              (setq in-reply-to (mh-thread-process-in-reply-to in-reply-to))
-              (setq refs (loop for x in (append (split-string refs) 
in-reply-to)
-                               when (string-match mh-message-id-regexp x)
-                               collect x))
-              (setq id (mh-thread-canonicalize-id id))
-              (mh-thread-update-id-index-maps id index)
-              (setq refs (mapcar #'mh-thread-canonicalize-id refs))
-              (mh-thread-get-message id subject-re-p subject refs)
-              (do ((ancestors refs (cdr ancestors)))
-                  ((null (cdr ancestors))
-                   (when (car ancestors)
-                     (mh-thread-remove-parent-link id)
-                     (mh-thread-add-link (car ancestors) id)))
-                (mh-thread-add-link (car ancestors) (cadr ancestors)))))))
-      (maphash #'(lambda (k v)
-                   (declare (ignore k))
-                   (when (null (mh-container-parent v))
-                     (push v roots)))
-               mh-thread-id-table)
-      (setq roots (mh-thread-prune-containers roots))
-      (prog1 (setq roots (mh-thread-group-by-subject roots))
-        (let ((history mh-thread-history))
-          (set-buffer folder)
-          (setq mh-thread-history history))))))
-
-;;;###mh-autoload
-(defun mh-thread-inc (folder start-point)
-  "Update thread tree for FOLDER.
-All messages after START-POINT are added to the thread tree."
-  (mh-thread-rewind-pruning)
-  (mh-remove-all-notation)
-  (goto-char start-point)
-  (let ((msg-list ()))
-    (while (not (eobp))
-      (let ((index (mh-get-msg-num nil)))
-        (when (numberp index)
-          (push index msg-list)
-          (setf (gethash index mh-thread-scan-line-map)
-                (mh-thread-parse-scan-line)))
-        (forward-line)))
-    (let ((thread-tree (mh-thread-generate folder msg-list))
-          (buffer-read-only nil)
-          (old-buffer-modified-flag (buffer-modified-p)))
-      (delete-region (point-min) (point-max))
-      (mh-thread-print-scan-lines thread-tree)
-      (mh-notate-user-sequences)
-      (mh-notate-deleted-and-refiled)
-      (mh-notate-cur)
-      (set-buffer-modified-p old-buffer-modified-flag))))
-
-(defun mh-thread-generate-scan-lines (tree level)
-  "Generate scan lines.
-TREE is the hierarchical tree of messages, SCAN-LINE-MAP maps
-message indices to the corresponding scan lines and LEVEL used to
-determine indentation of the message."
-  (cond ((null tree) nil)
-        ((mh-thread-container-p tree)
-         (let* ((message (mh-container-message tree))
-                (id (mh-message-id message))
-                (index (gethash id mh-thread-id-index-map))
-                (duplicates (gethash id mh-thread-duplicates))
-                (new-level (+ level 2))
-                (dupl-flag t)
-                (force-angle-flag nil)
-                (increment-level-flag nil))
-           (dolist (scan-line (mapcar (lambda (x)
-                                        (gethash x mh-thread-scan-line-map))
-                                      (reverse (cons index duplicates))))
-             (when scan-line
-               (when (and dupl-flag (equal level 0)
-                          (mh-thread-ancestor-p mh-thread-last-ancestor tree))
-                 (setq level (+ level 2)
-                       new-level (+ new-level 2)
-                       force-angle-flag t))
-               (when (equal level 0)
-                 (setq mh-thread-last-ancestor tree)
-                 (while (mh-container-parent mh-thread-last-ancestor)
-                   (setq mh-thread-last-ancestor
-                         (mh-container-parent mh-thread-last-ancestor))))
-               (let* ((lev (if dupl-flag level new-level))
-                      (square-flag (or (and (mh-container-real-child-p tree)
-                                            (not force-angle-flag)
-                                            dupl-flag)
-                                       (equal lev 0))))
-                 (insert (car scan-line)
-                         (format (format "%%%ss" lev) "")
-                         (if square-flag "[" "<")
-                         (cadr scan-line)
-                         (if square-flag "]" ">")
-                         (truncate-string-to-width
-                          (caddr scan-line) (- mh-thread-body-width lev))
-                         "\n"))
-               (setq increment-level-flag t)
-               (setq dupl-flag nil)))
-           (unless increment-level-flag (setq new-level level))
-           (dolist (child (mh-container-children tree))
-             (mh-thread-generate-scan-lines child new-level))))
-        (t (let ((nlevel (+ level 2)))
-             (dolist (ch tree)
-               (mh-thread-generate-scan-lines ch nlevel))))))
-
-;; Another and may be better approach would be to generate all the info from
-;; the scan which generates the threading info. For now this will have to do.
-(defun mh-thread-parse-scan-line (&optional string)
-  "Parse a scan line.
-If optional argument STRING is given then that is assumed to be
-the scan line. Otherwise uses the line at point as the scan line
-to parse."
-  (let* ((string (or string
-                     (buffer-substring-no-properties (line-beginning-position)
-                                                     (line-end-position))))
-         (address-start (+ mh-cmd-note mh-scan-field-from-start-offset))
-         (body-start (+ mh-cmd-note mh-scan-field-from-end-offset))
-         (first-string (substring string 0 address-start)))
-    (list first-string
-          (substring string address-start (- body-start 2))
-          (substring string body-start)
-          string)))
-
-;;;###mh-autoload
-(defun mh-thread-update-scan-line-map (msg notation offset)
-  "In threaded view update `mh-thread-scan-line-map'.
-MSG is the message being notated with NOTATION at OFFSET."
-  (let* ((msg (or msg (mh-get-msg-num nil)))
-         (cur-scan-line (and mh-thread-scan-line-map
-                             (gethash msg mh-thread-scan-line-map)))
-         (old-scan-lines (loop for map in mh-thread-scan-line-map-stack
-                               collect (and map (gethash msg map)))))
-    (when cur-scan-line
-      (setf (aref (car cur-scan-line) offset) notation))
-    (dolist (line old-scan-lines)
-      (when line (setf (aref (car line) offset) notation)))))
-
-;;;###mh-autoload
-(defun mh-thread-add-spaces (count)
-  "Add COUNT spaces to each scan line in `mh-thread-scan-line-map'."
-  (let ((spaces (format (format "%%%ss" count) "")))
-    (while (not (eobp))
-      (let* ((msg-num (mh-get-msg-num nil))
-             (old-line (nth 3 (gethash msg-num mh-thread-scan-line-map))))
-        (when (numberp msg-num)
-          (setf (gethash msg-num mh-thread-scan-line-map)
-                (mh-thread-parse-scan-line (format "%s%s" spaces old-line)))))
-      (forward-line 1))))
-
-(defun mh-thread-print-scan-lines (thread-tree)
-  "Print scan lines in THREAD-TREE in threaded mode."
-  (let ((mh-thread-body-width (- (window-width) mh-cmd-note
-                                 (1- mh-scan-field-subject-start-offset)))
-        (mh-thread-last-ancestor nil))
-    (if (null mh-index-data)
-        (mh-thread-generate-scan-lines thread-tree -2)
-      (loop for x in (mh-index-group-by-folder)
-            do (let* ((old-map mh-thread-scan-line-map)
-                      (mh-thread-scan-line-map (make-hash-table)))
-                 (setq mh-thread-last-ancestor nil)
-                 (loop for msg in (cdr x)
-                       do (let ((v (gethash msg old-map)))
-                            (when v
-                              (setf (gethash msg mh-thread-scan-line-map) v))))
-                 (when (> (hash-table-count mh-thread-scan-line-map) 0)
-                   (insert (if (bobp) "" "\n") (car x) "\n")
-                   (mh-thread-generate-scan-lines thread-tree -2))))
-      (mh-index-create-imenu-index))))
-
-(defun mh-thread-folder ()
-  "Generate thread view of folder."
-  (message "Threading %s..." (buffer-name))
-  (mh-thread-initialize)
-  (goto-char (point-min))
-  (mh-remove-all-notation)
-  (let ((msg-list ()))
-    (mh-iterate-on-range msg (cons (point-min) (point-max))
-      (setf (gethash msg mh-thread-scan-line-map) (mh-thread-parse-scan-line))
-      (push msg msg-list))
-    (let* ((range (mh-coalesce-msg-list msg-list))
-           (thread-tree (mh-thread-generate (buffer-name) range)))
-      (delete-region (point-min) (point-max))
-      (mh-thread-print-scan-lines thread-tree)
-      (mh-notate-user-sequences)
-      (mh-notate-deleted-and-refiled)
-      (mh-notate-cur)
-      (message "Threading %s...done" (buffer-name)))))
-
-;;;###mh-autoload
-(defun mh-toggle-threads ()
-  "Toggle threaded view of folder."
-  (interactive)
-  (let ((msg-at-point (mh-get-msg-num nil))
-        (old-buffer-modified-flag (buffer-modified-p))
-        (buffer-read-only nil))
-    (cond ((memq 'unthread mh-view-ops)
-           (unless (mh-valid-view-change-operation-p 'unthread)
-             (error "Can't unthread folder"))
-           (let ((msg-list ()))
-             (goto-char (point-min))
-             (while (not (eobp))
-               (let ((index (mh-get-msg-num nil)))
-                 (when index
-                   (push index msg-list)))
-               (forward-line))
-             (mh-scan-folder mh-current-folder
-                             (mapcar #'(lambda (x) (format "%s" x))
-                                     (mh-coalesce-msg-list msg-list))
-                             t))
-           (when mh-index-data
-             (mh-index-insert-folder-headers)
-             (mh-notate-cur)))
-          (t (mh-thread-folder)
-             (push 'unthread mh-view-ops)))
-    (when msg-at-point (mh-goto-msg msg-at-point t t))
-    (set-buffer-modified-p old-buffer-modified-flag)
-    (mh-recenter nil)))
-
-;;;###mh-autoload
-(defun mh-thread-forget-message (index)
-  "Forget the message INDEX from the threading tables."
-  (let* ((id (gethash index mh-thread-index-id-map))
-         (id-index (gethash id mh-thread-id-index-map))
-         (duplicates (gethash id mh-thread-duplicates)))
-    (remhash index mh-thread-index-id-map)
-    (remhash index mh-thread-scan-line-map)
-    (cond ((and (eql index id-index) (null duplicates))
-           (remhash id mh-thread-id-index-map))
-          ((eql index id-index)
-           (setf (gethash id mh-thread-id-index-map) (car duplicates))
-           (setf (gethash (car duplicates) mh-thread-index-id-map) id)
-           (setf (gethash id mh-thread-duplicates) (cdr duplicates)))
-          (t
-           (setf (gethash id mh-thread-duplicates)
-                 (remove index duplicates))))))
-
-
-
-;;; Operations on threads
-
-(defun mh-thread-current-indentation-level ()
-  "Find the number of spaces by which current message is indented."
-  (save-excursion
-    (let ((address-start-offset (+ mh-cmd-note mh-scan-date-flag-width
-                                   mh-scan-date-width 1))
-          (level 0))
+(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)
-      (forward-char address-start-offset)
-      (while (char-equal (char-after) ? )
-        (incf level)
-        (forward-char))
-      level)))
-
-;;;###mh-autoload
-(defun mh-thread-next-sibling (&optional previous-flag)
-  "Display next sibling.
-
-With non-nil optional argument PREVIOUS-FLAG jump to the previous
-sibling."
-  (interactive)
-  (cond ((not (memq 'unthread mh-view-ops))
-         (error "Folder isn't threaded"))
-        ((eobp)
-         (error "No message at point")))
-  (beginning-of-line)
-  (let ((point (point))
-        (done nil)
-        (my-level (mh-thread-current-indentation-level)))
-    (while (and (not done)
-                (equal (forward-line (if previous-flag -1 1)) 0)
-                (not (eobp)))
-      (let ((level (mh-thread-current-indentation-level)))
-        (cond ((equal level my-level)
-               (setq done 'success))
-              ((< level my-level)
-               (message "No %s sibling" (if previous-flag "previous" "next"))
-               (setq done 'failure)))))
-    (cond ((eq done 'success) (mh-maybe-show))
-          ((eq done 'failure) (goto-char point))
-          (t (message "No %s sibling" (if previous-flag "previous" "next"))
-             (goto-char point)))))
-
-;;;###mh-autoload
-(defun mh-thread-previous-sibling ()
-  "Display previous sibling."
-  (interactive)
-  (mh-thread-next-sibling t))
-
-(defun mh-thread-immediate-ancestor ()
-  "Jump to immediate ancestor in thread tree."
-  (beginning-of-line)
-  (let ((point (point))
-        (ancestor-level (- (mh-thread-current-indentation-level) 2))
-        (done nil))
-    (if (< ancestor-level 0)
-        nil
-      (while (and (not done) (equal (forward-line -1) 0))
-        (when (equal ancestor-level (mh-thread-current-indentation-level))
-          (setq done t)))
-      (unless done
-        (goto-char point))
-      done)))
-
-;;;###mh-autoload
-(defun mh-thread-ancestor (&optional thread-root-flag)
-  "Display ancestor of current message.
-
-If you do not care for the way a particular thread has turned,
-you can move up the chain of messages with this command. This
-command can also take a prefix argument THREAD-ROOT-FLAG to jump
-to the message that started everything."
-  (interactive "P")
-  (beginning-of-line)
-  (cond ((not (memq 'unthread mh-view-ops))
-         (error "Folder isn't threaded"))
-        ((eobp)
-         (error "No message at point")))
-  (let ((current-level (mh-thread-current-indentation-level)))
-    (cond (thread-root-flag
-           (while (mh-thread-immediate-ancestor))
-           (mh-maybe-show))
-          ((equal current-level 1)
-           (message "Message has no ancestor"))
-          (t (mh-thread-immediate-ancestor)
-             (mh-maybe-show)))))
-
-(defun mh-thread-find-children ()
-  "Return a region containing the current message and its children.
-The result is returned as a list of two elements. The first is
-the point at the start of the region and the second is the point
-at the end."
-  (beginning-of-line)
-  (if (eobp)
-      nil
-    (let ((address-start-offset (+ mh-cmd-note mh-scan-date-flag-width
-                                   mh-scan-date-width 1))
-          (level (mh-thread-current-indentation-level))
-          spaces begin)
-      (setq begin (point))
-      (setq spaces (format (format "%%%ss" (1+ level)) ""))
-      (forward-line)
-      (block nil
-        (while (not (eobp))
-          (forward-char address-start-offset)
-          (unless (equal (string-match spaces (buffer-substring-no-properties
-                                               (point) (line-end-position)))
-                         0)
+      (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 (+ mh-cmd-note mh-scan-field-destination-offset))
+        (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
+                   (+ mh-cmd-note mh-scan-field-destination-offset))))))
+
+(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)
-            (backward-char)
-            (return))
-          (forward-line)))
-      (list begin (point)))))
+            (forward-char (+ mh-cmd-note mh-scan-field-destination-offset))
+            (delete-char 1)
+            (insert (car stack))))
+        (setf (gethash msg mh-sequence-notation-history) (cdr stack))))))
 
 ;;;###mh-autoload
-(defun mh-thread-delete ()
-  "Delete thread."
-  (interactive)
-  (cond ((not (memq 'unthread mh-view-ops))
-         (error "Folder isn't threaded"))
-        ((eobp)
-         (error "No message at point"))
-        (t (let ((region (mh-thread-find-children)))
-             (mh-iterate-on-messages-in-region () (car region) (cadr region)
-               (mh-delete-a-msg nil))
-             (mh-next-msg)))))
-
-;;;###mh-autoload
-(defun mh-thread-refile (folder)
-  "Refile (output) thread into FOLDER."
-  (interactive (list (intern (mh-prompt-for-refile-folder))))
-  (cond ((not (memq 'unthread mh-view-ops))
-         (error "Folder isn't threaded"))
-        ((eobp)
-         (error "No message at point"))
-        (t (let ((region (mh-thread-find-children)))
-             (mh-iterate-on-messages-in-region () (car region) (cadr region)
-               (mh-refile-a-msg nil folder))
-             (mh-next-msg)))))
+(defun mh-remove-all-notation ()
+  "Remove all notations on all scan lines that MH-E introduces."
+  (save-excursion
+    (setq overlay-arrow-position nil)
+    (goto-char (point-min))
+    (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)))
 
 
 
-;; Tick mark handling
-
-;;;###mh-autoload
-(defun mh-toggle-tick (range)
-  "Toggle tick mark of RANGE.
-
-This command adds messages to the \"tick\" sequence (which you can customize
-via the option `mh-tick-seq'). This sequence can be viewed later with the
-\\[mh-index-ticked-messages] command.
-
-Check the documentation of `mh-interactive-range' to see how RANGE is read in
-interactive use."
-  (interactive (list (mh-interactive-range "Tick")))
-  (unless mh-tick-seq
-    (error "Enable ticking by customizing `mh-tick-seq'"))
-  (let* ((tick-seq (mh-find-seq mh-tick-seq))
-         (tick-seq-msgs (mh-seq-msgs tick-seq))
-         (ticked ())
-         (unticked ()))
-    (mh-iterate-on-range msg range
-      (cond ((member msg tick-seq-msgs)
-             (push msg unticked)
-             (setcdr tick-seq (delq msg (cdr tick-seq)))
-             (when (null (cdr tick-seq)) (setq mh-last-seq-used nil))
-             (mh-remove-sequence-notation msg (mh-colors-in-use-p)))
-            (t
-             (push msg ticked)
-             (setq mh-last-seq-used mh-tick-seq)
-             (let ((mh-seq-list (cons `(,mh-tick-seq ,msg) mh-seq-list)))
-               (mh-add-sequence-notation msg (mh-colors-in-use-p))))))
-    (mh-add-msgs-to-seq ticked mh-tick-seq nil t)
-    (mh-undefine-sequence mh-tick-seq unticked)
-    (when mh-index-data
-      (mh-index-add-to-sequence mh-tick-seq ticked)
-      (mh-index-delete-from-sequence mh-tick-seq unticked))))
-
-;;;###mh-autoload
-(defun mh-narrow-to-tick ()
-  "Limit to ticked messages.
-
-What this command does is show only those messages that are in
-the \"tick\" sequence (which you can customize via the
-`mh-tick-seq' option) in the MH-Folder buffer. In addition, it
-limits further MH-E searches to just those messages. When you
-want to widen the view to all your messages again, use
-\\[mh-widen]."
-  (interactive)
-  (cond ((not mh-tick-seq)
-         (error "Enable ticking by customizing `mh-tick-seq'"))
-        ((null (mh-seq-msgs (mh-find-seq mh-tick-seq)))
-         (message "No messages in %s sequence" mh-tick-seq))
-        (t (mh-narrow-to-seq mh-tick-seq))))
+;; XXX Unused, delete, or create bind key?
+(defun mh-rename-seq (sequence new-name)
+  "Rename SEQUENCE to have NEW-NAME."
+  (interactive (list (mh-read-seq "Old" t)
+                     (intern (read-string "New sequence name: "))))
+  (let ((old-seq (mh-find-seq sequence)))
+    (or old-seq
+        (error "Sequence %s does not exist" sequence))
+    ;; Create new sequence first, since it might raise an error.
+    (mh-define-sequence new-name (mh-seq-msgs old-seq))
+    (mh-undefine-sequence sequence (mh-seq-msgs old-seq))
+    (rplaca old-seq new-name)))
 
 (provide 'mh-seq)
 
Index: emacs/lisp/mh-e/mh-speed.el
diff -u emacs/lisp/mh-e/mh-speed.el:1.15 emacs/lisp/mh-e/mh-speed.el:1.16
--- emacs/lisp/mh-e/mh-speed.el:1.15    Sun Jan 15 08:17:55 2006
+++ emacs/lisp/mh-e/mh-speed.el Sun Jan 29 19:34:56 2006
@@ -1,6 +1,6 @@
-;;; mh-speed.el --- Speedbar interface for MH-E.
+;;; mh-speed.el --- MH-E speedbar support
 
-;; Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+;; Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
 
 ;; Author: Satyaki Das <address@hidden>
 ;; Maintainer: Bill Wohler <address@hidden>
@@ -25,23 +25,21 @@
 ;; Boston, MA 02110-1301, USA.
 
 ;;; Commentary:
-;;   Future versions should only use flists.
 
-;; Speedbar support for MH-E package.
+;; Future versions should only use flists.
 
 ;;; Change Log:
 
 ;;; Code:
 
-;;(message "> mh-speed")
-(eval-when-compile (require 'mh-acros))
-(mh-require-cl)
 (require 'mh-e)
+(mh-require-cl)
+
+(require 'gnus-util)
 (require 'speedbar)
 (require 'timer)
-;;(message "< mh-speed")
 
-;; Global variables
+;; Global variables.
 (defvar mh-speed-refresh-flag nil)
 (defvar mh-speed-last-selected-folder nil)
 (defvar mh-speed-folder-map (make-hash-table :test #'equal))
@@ -50,7 +48,10 @@
 (defvar mh-speed-flists-timer nil)
 (defvar mh-speed-partial-line "")
 
-;; Add our stealth update function
+
+
+;;; Speedbar Hook
+
 (unless (member 'mh-speed-stealth-update
                 (cdr (assoc "files" speedbar-stealthy-function-list)))
   ;; Is changing constant lists in elisp safe?
@@ -59,7 +60,132 @@
   (push 'mh-speed-stealth-update
         (cdr (assoc "files" speedbar-stealthy-function-list))))
 
-;; Functions called by speedbar to initialize display...
+
+
+;;; Speedbar Menus
+
+(defvar mh-folder-speedbar-menu-items
+  '("--"
+    ["Visit Folder" mh-speed-view
+     (save-excursion
+       (set-buffer speedbar-buffer)
+       (get-text-property (line-beginning-position) 'mh-folder))]
+    ["Expand Nested Folders" mh-speed-expand-folder
+     (and (get-text-property (line-beginning-position) 'mh-children-p)
+          (not (get-text-property (line-beginning-position) 'mh-expanded)))]
+    ["Contract Nested Folders" mh-speed-contract-folder
+     (and (get-text-property (line-beginning-position) 'mh-children-p)
+          (get-text-property (line-beginning-position) 'mh-expanded))]
+    ["Refresh Speedbar" mh-speed-refresh t])
+  "Extra menu items for speedbar.")
+
+(defvar mh-show-speedbar-menu-items mh-folder-speedbar-menu-items)
+(defvar mh-letter-speedbar-menu-items mh-folder-speedbar-menu-items)
+
+
+
+;;; Speedbar Keys
+
+(defvar mh-folder-speedbar-key-map (speedbar-make-specialized-keymap)
+  "Specialized speedbar keymap for MH-E buffers.")
+
+(gnus-define-keys mh-folder-speedbar-key-map
+  "+"           mh-speed-expand-folder
+  "-"           mh-speed-contract-folder
+  "\r"          mh-speed-view
+  "r"           mh-speed-refresh)
+
+(defvar mh-show-speedbar-key-map mh-folder-speedbar-key-map)
+(defvar mh-letter-speedbar-key-map mh-folder-speedbar-key-map)
+
+
+
+;;; Speedbar Commands
+
+;; Alphabetical.
+
+(defalias 'mh-speed-contract-folder 'mh-speed-toggle)
+
+(defalias 'mh-speed-expand-folder 'mh-speed-toggle)
+
+(defun mh-speed-refresh ()
+  "Regenerates the list of folders in the speedbar.
+
+Run this command if you've added or deleted a folder, or want to
+update the unseen message count before the next automatic
+update."
+  (interactive)
+  (mh-speed-flists t)
+  (mh-speed-invalidate-map ""))
+
+(defun mh-speed-stealth-update (&optional force)
+  "Do stealth update.
+With non-nil FORCE, the update is always carried out."
+  (cond ((save-excursion (set-buffer speedbar-buffer)
+                         (get-text-property (point-min) 'mh-level))
+         ;; Execute this hook and *don't* run anything else
+         (mh-speed-update-current-folder force)
+         nil)
+        ;; Otherwise on to your regular programming
+        (t t)))
+
+(defun mh-speed-toggle (&rest args)
+  "Toggle the display of child folders in the speedbar.
+The optional ARGS from speedbar are ignored."
+  (interactive)
+  (declare (ignore args))
+  (beginning-of-line)
+  (let ((parent (get-text-property (point) 'mh-folder))
+        (kids-p (get-text-property (point) 'mh-children-p))
+        (expanded (get-text-property (point) 'mh-expanded))
+        (level (get-text-property (point) 'mh-level))
+        (point (point))
+        start-region)
+    (speedbar-with-writable
+      (cond ((not kids-p) nil)
+            (expanded
+             (forward-line)
+             (setq start-region (point))
+             (while (and (get-text-property (point) 'mh-level)
+                         (> (get-text-property (point) 'mh-level) level))
+               (let ((folder (get-text-property (point) 'mh-folder)))
+                 (when (gethash folder mh-speed-folder-map)
+                   (set-marker (gethash folder mh-speed-folder-map) nil)
+                   (remhash folder mh-speed-folder-map)))
+               (forward-line))
+             (delete-region start-region (point))
+             (forward-line -1)
+             (speedbar-change-expand-button-char ?+)
+             (add-text-properties
+              (line-beginning-position) (1+ (line-beginning-position))
+              '(mh-expanded nil)))
+            (t
+             (forward-line)
+             (mh-speed-add-buttons parent (1+ level))
+             (goto-char point)
+             (speedbar-change-expand-button-char ?-)
+             (add-text-properties
+              (line-beginning-position) (1+ (line-beginning-position))
+              `(mh-expanded t)))))))
+
+(defun mh-speed-view (&rest args)
+  "Visits the selected folder just as if you had used 
\\<mh-folder-mode-map>\\[mh-visit-folder].
+The optional ARGS from speedbar are ignored."
+  (interactive)
+  (declare (ignore args))
+  (let* ((folder (get-text-property (line-beginning-position) 'mh-folder))
+         (range (and (stringp folder)
+                     (mh-read-range "Scan" folder t nil nil
+                                    mh-interpret-number-as-range-flag))))
+    (when (stringp folder)
+      (speedbar-with-attached-buffer
+       (mh-visit-folder folder range)
+       (delete-other-windows)))))
+
+
+
+;;; Support Routines
+
 ;;;###mh-autoload
 (defun mh-folder-speedbar-buttons (buffer)
   "Interface function to create MH-E speedbar buffer.
@@ -86,37 +212,6 @@
 ;;;###mh-autoload
 (defalias 'mh-letter-speedbar-buttons 'mh-folder-speedbar-buttons)
 
-;; Keymaps for speedbar...
-(defvar mh-folder-speedbar-key-map (speedbar-make-specialized-keymap)
-  "Specialized speedbar keymap for MH-E buffers.")
-(gnus-define-keys mh-folder-speedbar-key-map
-  "+"           mh-speed-expand-folder
-  "-"           mh-speed-contract-folder
-  "\r"          mh-speed-view
-  "r"           mh-speed-refresh)
-
-(defvar mh-show-speedbar-key-map mh-folder-speedbar-key-map)
-(defvar mh-letter-speedbar-key-map mh-folder-speedbar-key-map)
-
-;; Menus for speedbar...
-(defvar mh-folder-speedbar-menu-items
-  '("--"
-    ["Visit Folder" mh-speed-view
-     (save-excursion
-       (set-buffer speedbar-buffer)
-       (get-text-property (line-beginning-position) 'mh-folder))]
-    ["Expand Nested Folders" mh-speed-expand-folder
-     (and (get-text-property (line-beginning-position) 'mh-children-p)
-          (not (get-text-property (line-beginning-position) 'mh-expanded)))]
-    ["Contract Nested Folders" mh-speed-contract-folder
-     (and (get-text-property (line-beginning-position) 'mh-children-p)
-          (get-text-property (line-beginning-position) 'mh-expanded))]
-    ["Refresh Speedbar" mh-speed-refresh t])
-  "Extra menu items for speedbar.")
-
-(defvar mh-show-speedbar-menu-items mh-folder-speedbar-menu-items)
-(defvar mh-letter-speedbar-menu-items mh-folder-speedbar-menu-items)
-
 (defmacro mh-speed-select-attached-frame ()
   "Compatibility macro to handle speedbar versions 0.11a and 0.14beta4."
   (cond ((fboundp 'dframe-select-attached-frame)
@@ -167,6 +262,19 @@
     (when (eq lastf speedbar-frame)
       (setq mh-speed-refresh-flag t))))
 
+(defun mh-speed-highlight (folder face)
+  "Set FOLDER to FACE."
+  (save-excursion
+    (speedbar-with-writable
+      (goto-char (gethash folder mh-speed-folder-map (point)))
+      (beginning-of-line)
+      (if (re-search-forward "([1-9][0-9]*/[0-9]+)" (line-end-position) t)
+          (setq face (mh-speed-bold-face face))
+        (setq face (mh-speed-normal-face face)))
+      (beginning-of-line)
+      (when (re-search-forward "\\[.\\] " (line-end-position) t)
+        (put-text-property (point) (line-end-position) 'face face)))))
+
 (defun mh-speed-normal-face (face)
   "Return normal face for given FACE."
   (cond ((eq face 'mh-speedbar-folder-with-unseen-messages)
@@ -183,30 +291,6 @@
          'mh-speedbar-selected-folder-with-unseen-messages)
         (t face)))
 
-(defun mh-speed-highlight (folder face)
-  "Set FOLDER to FACE."
-  (save-excursion
-    (speedbar-with-writable
-      (goto-char (gethash folder mh-speed-folder-map (point)))
-      (beginning-of-line)
-      (if (re-search-forward "([1-9][0-9]*/[0-9]+)" (line-end-position) t)
-          (setq face (mh-speed-bold-face face))
-        (setq face (mh-speed-normal-face face)))
-      (beginning-of-line)
-      (when (re-search-forward "\\[.\\] " (line-end-position) t)
-        (put-text-property (point) (line-end-position) 'face face)))))
-
-(defun mh-speed-stealth-update (&optional force)
-  "Do stealth update.
-With non-nil FORCE, the update is always carried out."
-  (cond ((save-excursion (set-buffer speedbar-buffer)
-                         (get-text-property (point-min) 'mh-level))
-         ;; Execute this hook and *don't* run anything else
-         (mh-speed-update-current-folder force)
-         nil)
-        ;; Otherwise on to your regular programming
-        (t t)))
-
 (defun mh-speed-goto-folder (folder)
   "Move point to line containing FOLDER.
 The function will expand out parent folders of FOLDER if needed."
@@ -295,64 +379,6 @@
                           mh-level ,level))))))
      folder-list)))
 
-;;;###mh-autoload
-(defun mh-speed-toggle (&rest args)
-  "Toggle the display of child folders in the speedbar.
-The optional ARGS from speedbar are ignored."
-  (interactive)
-  (declare (ignore args))
-  (beginning-of-line)
-  (let ((parent (get-text-property (point) 'mh-folder))
-        (kids-p (get-text-property (point) 'mh-children-p))
-        (expanded (get-text-property (point) 'mh-expanded))
-        (level (get-text-property (point) 'mh-level))
-        (point (point))
-        start-region)
-    (speedbar-with-writable
-      (cond ((not kids-p) nil)
-            (expanded
-             (forward-line)
-             (setq start-region (point))
-             (while (and (get-text-property (point) 'mh-level)
-                         (> (get-text-property (point) 'mh-level) level))
-               (let ((folder (get-text-property (point) 'mh-folder)))
-                 (when (gethash folder mh-speed-folder-map)
-                   (set-marker (gethash folder mh-speed-folder-map) nil)
-                   (remhash folder mh-speed-folder-map)))
-               (forward-line))
-             (delete-region start-region (point))
-             (forward-line -1)
-             (speedbar-change-expand-button-char ?+)
-             (add-text-properties
-              (line-beginning-position) (1+ (line-beginning-position))
-              '(mh-expanded nil)))
-            (t
-             (forward-line)
-             (mh-speed-add-buttons parent (1+ level))
-             (goto-char point)
-             (speedbar-change-expand-button-char ?-)
-             (add-text-properties
-              (line-beginning-position) (1+ (line-beginning-position))
-              `(mh-expanded t)))))))
-
-(defalias 'mh-speed-expand-folder 'mh-speed-toggle)
-(defalias 'mh-speed-contract-folder 'mh-speed-toggle)
-
-;;;###mh-autoload
-(defun mh-speed-view (&rest args)
-  "Visits the selected folder just as if you had used 
\\<mh-folder-mode-map>\\[mh-visit-folder].
-The optional ARGS from speedbar are ignored."
-  (interactive)
-  (declare (ignore args))
-  (let* ((folder (get-text-property (line-beginning-position) 'mh-folder))
-         (range (and (stringp folder)
-                     (mh-read-range "Scan" folder t nil nil
-                                    mh-interpret-number-as-range-flag))))
-    (when (stringp folder)
-      (speedbar-with-attached-buffer
-       (mh-visit-folder folder range)
-       (delete-other-windows)))))
-
 (defvar mh-speed-current-folder nil)
 (defvar mh-speed-flists-folder nil)
 
@@ -415,6 +441,7 @@
                                    'mh-speed-parse-flists-output)))))))
 
 ;; Copied from mh-make-folder-list-filter...
+;; XXX Refactor to use mh-make-folder-list-filer?
 (defun mh-speed-parse-flists-output (process output)
   "Parse the incremental results from flists.
 PROCESS is the flists process and OUTPUT is the results that must
@@ -506,17 +533,23 @@
           (setq mh-speed-last-selected-folder nil)
           (setq mh-speed-refresh-flag t)))
       (when (equal folder "")
-        (clrhash mh-sub-folders-cache)))))
-
-(defun mh-speed-refresh ()
-  "Regenerates the list of folders in the speedbar.
+        (mh-clear-sub-folders-cache)))))
 
-Run this command if you've added or deleted a folder, or want to
-update the unseen message count before the next automatic
-update."
-  (interactive)
-  (mh-speed-flists t)
-  (mh-speed-invalidate-map ""))
+;; Make it slightly more general to allow for [ ] buttons to be
+;; changed to [+].
+(defun mh-speedbar-change-expand-button-char (char)
+  "Change the expansion button character to CHAR for the current line."
+  (save-excursion
+    (beginning-of-line)
+    (if (re-search-forward "\\[.\\]" (line-end-position) t)
+        (speedbar-with-writable
+          (backward-char 2)
+          (delete-char 1)
+          (insert-char char 1 t)
+          (put-text-property (point) (1- (point)) 'invisible nil)
+          ;; make sure we fix the image on the text here.
+          (mh-funcall-if-exists
+           speedbar-insert-image-button-maybe (- (point) 2) 3)))))
 
 ;;;###mh-autoload
 (defun mh-speed-add-folder (folder)
@@ -546,22 +579,6 @@
         (mh-speed-toggle))
       (setq mh-speed-refresh-flag t))))
 
-;; Make it slightly more general to allow for [ ] buttons to be changed to
-;; [+].
-(defun mh-speedbar-change-expand-button-char (char)
-  "Change the expansion button character to CHAR for the current line."
-  (save-excursion
-    (beginning-of-line)
-    (if (re-search-forward "\\[.\\]" (line-end-position) t)
-        (speedbar-with-writable
-          (backward-char 2)
-          (delete-char 1)
-          (insert-char char 1 t)
-          (put-text-property (point) (1- (point)) 'invisible nil)
-          ;; make sure we fix the image on the text here.
-          (mh-funcall-if-exists
-           speedbar-insert-image-button-maybe (- (point) 2) 3)))))
-
 (provide 'mh-speed)
 
 ;; Local Variables:
Index: emacs/lisp/mh-e/mh-utils.el
diff -u emacs/lisp/mh-e/mh-utils.el:1.42 emacs/lisp/mh-e/mh-utils.el:1.43
--- emacs/lisp/mh-e/mh-utils.el:1.42    Mon Jan 16 05:41:26 2006
+++ emacs/lisp/mh-e/mh-utils.el Sun Jan 29 19:34:54 2006
@@ -1,4 +1,4 @@
-;;; mh-utils.el --- MH-E code needed for both sending and reading
+;;; mh-utils.el --- MH-E general utilities
 
 ;; Copyright (C) 1993, 1995, 1997,
 ;;  2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
@@ -27,53 +27,18 @@
 
 ;;; Commentary:
 
-;; Internal support for MH-E package.
-
 ;;; Change Log:
 
 ;;; Code:
 
-;;(message "> mh-utils")
-(eval-and-compile
-  (defvar recursive-load-depth-limit)
-  (if (and (boundp 'recursive-load-depth-limit)
-           (integerp recursive-load-depth-limit)
-           (< recursive-load-depth-limit 50))
-      (setq recursive-load-depth-limit 50)))
-
-(eval-when-compile (require 'mh-acros))
+(require 'mh-e)
 (mh-require-cl)
 
 (require 'font-lock)
-(require 'gnus-util)
-(require 'mh-buffers)
-(require 'mh-customize)
-(require 'mh-inc)
-(require 'mouse)
-(require 'sendmail)
-;;(message "< mh-utils")
-
-;; Non-fatal dependencies
-(load "hl-line" t t)
-(load "mm-decode" t t)
-(load "mm-view" t t)
-(load "tool-bar" t t)
-(load "vcard" t t)
-
-
-
-;;; Autoloads
-
-(autoload 'gnus-article-highlight-citation "gnus-cite")
-(autoload 'message-fetch-field "message")
-(autoload 'message-tokenize-header "message")
-(unless (fboundp 'make-hash-table)
-  (autoload 'make-hash-table "cl"))
-
-
 
 ;;; CL Replacements
 
+;;;###mh-autoload
 (defun mh-search-from-end (char string)
   "Return the position of last occurrence of CHAR in STRING.
 If CHAR is not present in STRING then return nil. The function is
@@ -82,476 +47,104 @@
         when (equal (aref string index) char) return index
         finally return nil))
 
-;; Additional header fields that might someday be added:
-;; "Sender: " "Reply-to: "
-
-
-
-;;; Scan Line Formats
-
-(defvar mh-scan-msg-number-regexp "^ *\\([0-9]+\\)"
-  "This regular expression extracts the message number.
-
-It must match from the beginning of the line. Note that the
-message number must be placed in a parenthesized expression as in
-the default of \"^ *\\\\([0-9]+\\\\)\".")
-
-(defvar mh-scan-msg-overflow-regexp "^[?0-9][0-9]"
-  "This regular expression matches overflowed message numbers.")
-
-(defvar mh-scan-msg-format-regexp "%\\([0-9]*\\)(msg)"
-  "This regular expression finds the message number width in a scan format.
-
-Note that the message number must be placed in a parenthesized
-expression as in the default of \"%\\\\([0-9]*\\\\)(msg)\". This
-variable is only consulted if `mh-scan-format-file' is set to
-\"Use MH-E scan Format\".")
-
-(defvar mh-scan-msg-format-string "%d"
-  "This is a format string for width of the message number in a scan format.
-
-Use \"0%d\" for zero-filled message numbers. This variable is only
-consulted if `mh-scan-format-file' is set to \"Use MH-E scan
-Format\".")
-
-(defvar mh-scan-msg-search-regexp "^[^0-9]*%d[^0-9]"
-  "This regular expression matches a particular message.
-
-It is a format string; use \"%d\" to represent the location of the
-message number within the expression as in the default of
-\"^[^0-9]*%d[^0-9]\".")
-
-(defvar mh-cmd-note 4
-  "Column for notations.
-
-This variable should be set with the function `mh-set-cmd-note'.
-This variable may be updated dynamically if
-`mh-adaptive-cmd-note-flag' is on.
-
-Note that columns in Emacs start with 0.")
-(make-variable-buffer-local 'mh-cmd-note)
-
-(defvar mh-note-seq ?%
-  "Messages in a user-defined sequence are marked by this character.
-
-Messages in the \"search\" sequence are marked by this character as
-well.")
-
-
-
-(defvar mh-show-buffer-mode-line-buffer-id "    {show-%s} %d"
-  "Format string to produce `mode-line-buffer-identification' for show buffers.
-
-First argument is folder name. Second is message number.")
-
 
 
-(defvar mh-mail-header-separator "--------"
-  "*Line used by MH to separate headers from text in messages being composed.
-
-This variable should not be used directly in programs. Programs
-should use `mail-header-separator' instead.
-`mail-header-separator' is initialized to
-`mh-mail-header-separator' in `mh-letter-mode'; in other
-contexts, you may have to perform this initialization yourself.
-
-Do not make this a regular expression as it may be the argument
-to `insert' and it is passed through `regexp-quote' before being
-used by functions like `re-search-forward'.")
-
-(defvar mh-signature-separator-regexp "^-- $"
-  "This regular expression matches the signature separator.
-See `mh-signature-separator'.")
-
-(defvar mh-signature-separator "-- \n"
-  "Text of a signature separator.
-
-A signature separator is used to separate the body of a message
-from the signature. This can be used by user agents such as MH-E
-to render the signature differently or to suppress the inclusion
-of the signature in a reply. Use `mh-signature-separator-regexp'
-when searching for a separator.")
-
-(defun mh-signature-separator-p ()
-  "Return non-nil if buffer includes \"^-- $\"."
-  (save-excursion
-    (goto-char (point-min))
-    (re-search-forward mh-signature-separator-regexp nil t)))
-
-;; Variables for MIME display
-
-;; Structure to keep track of MIME handles on a per buffer basis.
-(mh-defstruct (mh-buffer-data (:conc-name mh-mime-)
-                              (:constructor mh-make-buffer-data))
-  (handles ())                          ; List of MIME handles
-  (handles-cache (make-hash-table))     ; Cache to avoid multiple decodes of
-                                        ; nested messages
-  (parts-count 0)                       ; The button number is generated from
-                                        ; this number
-  (part-index-hash (make-hash-table)))  ; Avoid incrementing the part number
-                                        ; for nested messages
-
-;; This has to be a macro, since we do: (setf (mh-buffer-data) ...)
-(defmacro mh-buffer-data ()
-  "Convenience macro to get the MIME data structures of the current buffer."
-  `(gethash (current-buffer) mh-globals-hash))
-
-(defvar mh-globals-hash (make-hash-table)
-  "Keeps track of MIME data on a per buffer basis.")
-
-(defvar mh-mm-inline-media-tests
-  `(("image/jpeg"
-     mm-inline-image
-     (lambda (handle)
-       (mm-valid-and-fit-image-p 'jpeg handle)))
-    ("image/png"
-     mm-inline-image
-     (lambda (handle)
-       (mm-valid-and-fit-image-p 'png handle)))
-    ("image/gif"
-     mm-inline-image
-     (lambda (handle)
-       (mm-valid-and-fit-image-p 'gif handle)))
-    ("image/tiff"
-     mm-inline-image
-     (lambda (handle)
-       (mm-valid-and-fit-image-p 'tiff handle)) )
-    ("image/xbm"
-     mm-inline-image
-     (lambda (handle)
-       (mm-valid-and-fit-image-p 'xbm handle)))
-    ("image/x-xbitmap"
-     mm-inline-image
-     (lambda (handle)
-       (mm-valid-and-fit-image-p 'xbm handle)))
-    ("image/xpm"
-     mm-inline-image
-     (lambda (handle)
-       (mm-valid-and-fit-image-p 'xpm handle)))
-    ("image/x-pixmap"
-     mm-inline-image
-     (lambda (handle)
-       (mm-valid-and-fit-image-p 'xpm handle)))
-    ("image/bmp"
-     mm-inline-image
-     (lambda (handle)
-       (mm-valid-and-fit-image-p 'bmp handle)))
-    ("image/x-portable-bitmap"
-     mm-inline-image
-     (lambda (handle)
-       (mm-valid-and-fit-image-p 'pbm handle)))
-    ("text/plain" mm-inline-text identity)
-    ("text/enriched" mm-inline-text identity)
-    ("text/richtext" mm-inline-text identity)
-    ("text/x-patch" mm-display-patch-inline
-     (lambda (handle)
-       (locate-library "diff-mode")))
-    ("application/emacs-lisp" mm-display-elisp-inline identity)
-    ("application/x-emacs-lisp" mm-display-elisp-inline identity)
-    ("text/html"
-     ,(if (fboundp 'mm-inline-text-html) 'mm-inline-text-html 'mm-inline-text)
-     (lambda (handle)
-       (or (and (boundp 'mm-inline-text-html-renderer)
-                mm-inline-text-html-renderer)
-           (and (boundp 'mm-text-html-renderer) mm-text-html-renderer))))
-    ("text/x-vcard"
-     mm-inline-text-vcard
-     (lambda (handle)
-       (or (featurep 'vcard)
-           (locate-library "vcard"))))
-    ("message/delivery-status" mm-inline-text identity)
-    ("message/rfc822" mh-mm-inline-message identity)
-    ;;("message/partial" mm-inline-partial identity)
-    ;;("message/external-body" mm-inline-external-body identity)
-    ("text/.*" mm-inline-text identity)
-    ("audio/wav" mm-inline-audio
-     (lambda (handle)
-       (and (or (featurep 'nas-sound) (featurep 'native-sound))
-            (device-sound-enabled-p))))
-    ("audio/au"
-     mm-inline-audio
-     (lambda (handle)
-       (and (or (featurep 'nas-sound) (featurep 'native-sound))
-            (device-sound-enabled-p))))
-    ("application/pgp-signature" ignore identity)
-    ("application/x-pkcs7-signature" ignore identity)
-    ("application/pkcs7-signature" ignore identity)
-    ("application/x-pkcs7-mime" ignore identity)
-    ("application/pkcs7-mime" ignore identity)
-    ("multipart/alternative" ignore identity)
-    ("multipart/mixed" ignore identity)
-    ("multipart/related" ignore identity)
-    ;; Disable audio and image
-    ("audio/.*" ignore ignore)
-    ("image/.*" ignore ignore)
-    ;; Default to displaying as text
-    (".*" mm-inline-text mm-readable-p))
-  "Alist of media types/tests saying whether types can be displayed inline.")
-
-;; Copy of `goto-address-mail-regexp'
-(defvar mh-address-mail-regexp
-  "address@hidden([-a-zA-z0-9_]+\\.\\)+[a-zA-Z0-9]+"
-  "A regular expression probably matching an e-mail address.")
-
-;; From goto-addr.el, which we don't want to force-load on users.
-
-(defun mh-goto-address-find-address-at-point ()
-  "Find e-mail address around or before point.
-
-Then search backwards to beginning of line for the start of an
-e-mail address. If no e-mail address found, return nil."
-  (re-search-backward "address@hidden" (line-beginning-position) 'lim)
-  (if (or (looking-at mh-address-mail-regexp)  ; already at start
-         (and (re-search-forward mh-address-mail-regexp
-                                 (line-end-position) 'lim)
-              (goto-char (match-beginning 0))))
-      (match-string-no-properties 0)))
-
-(defun mh-mail-header-end ()
-  "Substitute for `mail-header-end' that doesn't widen the buffer.
-
-In MH-E we frequently need to find the end of headers in nested
-messages, where the buffer has been narrowed. This function works
-in this situation."
-  (save-excursion
-    ;; XXX: The following replaces a call to rfc822-goto-eoh. Occasionally,
-    ;; mail headers that MH-E has to read contains lines of the form:
-    ;;    From address@hidden Mon May 10 11:48:07 2004
-    ;; In this situation, rfc822-goto-eoh doesn't go to the end of the
-    ;; header. The replacement allows From_ lines in the mail header.
-    (goto-char (point-min))
-    (loop for p = (re-search-forward
-                   "^\\([:\n]\\|[^: \t\n]+[ \t\n]\\)" nil 'move)
-          do (cond ((null p) (return))
-                   (t (goto-char (match-beginning 0))
-                      (unless (looking-at "From ") (return))
-                      (goto-char p))))
-    (point)))
-
-(defun mh-in-header-p ()
-  "Return non-nil if the point is in the header of a draft message."
-  (< (point) (mh-mail-header-end)))
-
-(defun mh-header-field-beginning ()
-  "Move to the beginning of the current header field.
-Handles RFC 822 continuation lines."
-  (beginning-of-line)
-  (while (looking-at "^[ \t]")
-    (forward-line -1)))
-
-(defun mh-header-field-end ()
-  "Move to the end of the current header field.
-Handles RFC 822 continuation lines."
-  (forward-line 1)
-  (while (looking-at "^[ \t]")
-    (forward-line 1))
-  (backward-char 1))                    ;to end of previous line
-
-(defun mh-letter-header-font-lock (limit)
-  "Return the entire mail header to font-lock.
-Argument LIMIT limits search."
-  (if (= (point) limit)
-      nil
-    (let* ((mail-header-end (save-match-data (mh-mail-header-end)))
-           (lesser-limit (if (< mail-header-end limit) mail-header-end limit)))
-      (when (mh-in-header-p)
-        (set-match-data (list 1 lesser-limit))
-        (goto-char lesser-limit)
-        t))))
-
-(defun mh-header-field-font-lock (field limit)
-  "Return the value of a header field FIELD to font-lock.
-Argument LIMIT limits search."
-  (if (= (point) limit)
-      nil
-    (let* ((mail-header-end (mh-mail-header-end))
-           (lesser-limit (if (< mail-header-end limit) mail-header-end limit))
-           (case-fold-search t))
-      (when (and (< (point) mail-header-end) ;Only within header
-                 (re-search-forward (format "^%s" field) lesser-limit t))
-        (let ((match-one-b (match-beginning 0))
-              (match-one-e (match-end 0)))
-          (mh-header-field-end)
-          (if (> (point) limit)         ;Don't search for end beyond limit
-              (goto-char limit))
-          (set-match-data (list match-one-b match-one-e
-                                (1+ match-one-e) (point)))
-          t)))))
-
-(defun mh-header-to-font-lock (limit)
-  "Return the value of a header field To to font-lock.
-Argument LIMIT limits search."
-  (mh-header-field-font-lock "To:" limit))
-
-(defun mh-header-cc-font-lock (limit)
-  "Return the value of a header field cc to font-lock.
-Argument LIMIT limits search."
-  (mh-header-field-font-lock "cc:" limit))
-
-(defun mh-header-subject-font-lock (limit)
-  "Return the value of a header field Subject to font-lock.
-Argument LIMIT limits search."
-  (mh-header-field-font-lock "Subject:" limit))
-
-(eval-and-compile
-  ;; Otherwise byte-compilation fails on `mh-show-font-lock-keywords-with-cite'
-  (defvar mh-show-font-lock-keywords
-    '(("^\\(From:\\|Sender:\\)\\(.*\\)"
-       (1 'default)
-       (2 'mh-show-from))
-      (mh-header-to-font-lock
-       (0 'default)
-       (1 'mh-show-to))
-      (mh-header-cc-font-lock
-       (0 'default)
-       (1 'mh-show-cc))
-      ("^\\(Reply-To:\\|Return-Path:\\)\\(.*\\)$"
-       (1 'default)
-       (2 'mh-show-from))
-      (mh-header-subject-font-lock
-       (0 'default)
-       (1 'mh-show-subject))
-      ("^\\(Apparently-To:\\|Newsgroups:\\)\\(.*\\)"
-       (1 'default)
-       (2 'mh-show-cc))
-      ("^\\(In-reply-to\\|Date\\):\\(.*\\)$"
-       (1 'default)
-       (2 'mh-show-date))
-      (mh-letter-header-font-lock
-       (0 'mh-show-header append t)))
-    "Additional expressions to highlight in MH-Show buffers."))
-
-(defvar mh-show-font-lock-keywords-with-cite
-  (eval-when-compile
-    (let* ((cite-chars "[>|}]")
-           (cite-prefix "A-Za-z")
-           (cite-suffix (concat cite-prefix "address@hidden'\"")))
-      (append
-       mh-show-font-lock-keywords
-       (list
-        ;; Use MATCH-ANCHORED to effectively anchor the regexp left side.
-        `(,cite-chars
-          (,(concat "\\=[ \t]*"
-                    "\\(\\([" cite-prefix "]+[" cite-suffix "]*\\)?"
-                    "\\(" cite-chars "[ \t]*\\)\\)+"
-                    "\\(.*\\)")
-           (beginning-of-line) (end-of-line)
-           (2 font-lock-constant-face nil t)
-           (4 font-lock-comment-face nil t)))))))
-  "Additional expressions to highlight in MH-Show buffers.")
-
-(defvar mh-letter-font-lock-keywords
-  `(,@mh-show-font-lock-keywords-with-cite
-    (mh-font-lock-field-data
-     (1 'mh-letter-header-field prepend t)))
-  "Additional expressions to highlight in MH-Letter buffers.")
-
-(defun mh-show-font-lock-fontify-region (beg end loudly)
-  "Limit font-lock in `mh-show-mode' to the header.
-
-Used when the option `mh-highlight-citation-style' is set to
-\"Gnus\", leaving the body to be dealt with by Gnus highlighting.
-The region between BEG and END is given over to be fontified and
-LOUDLY controls if a user sees a message about the fontification
-operation."
-  (let ((header-end (mh-mail-header-end)))
-    (cond
-     ((and (< beg header-end)(< end header-end))
-      (font-lock-default-fontify-region beg end loudly))
-     ((and (< beg header-end)(>= end header-end))
-      (font-lock-default-fontify-region beg header-end loudly))
-     (t
-      nil))))
+;;; General Utilities
 
-;; Shush compiler.
-(if mh-xemacs-flag
-    (eval-and-compile
-      (require 'gnus)
-      (require 'gnus-art)
-      (require 'gnus-cite)))
-
-(defun mh-gnus-article-highlight-citation ()
-  "Highlight cited text in current buffer using Gnus."
-  (interactive)
-  ;; Requiring gnus-cite should have been sufficient. However for Emacs21.1,
-  ;; recursive-load-depth-limit is only 10, so an error occurs. Also it may be
-  ;; better to have an autoload at top-level (though that won't work because
-  ;; of recursive-load-depth-limit). That gets rid of a compiler warning as
-  ;; well.
-  (unless mh-xemacs-flag
-    (require 'gnus-art)
-    (require 'gnus-cite))
-  ;; Don't allow Gnus to create buttons while highlighting, maybe this is bad
-  ;; style?
-  (flet ((gnus-article-add-button (&rest args) nil))
-    (let* ((modified (buffer-modified-p))
-           (gnus-article-buffer (buffer-name))
-           (gnus-cite-face-list `(,@(cdr gnus-cite-face-list)
-                                    ,(car gnus-cite-face-list))))
-      (gnus-article-highlight-citation t)
-      (set-buffer-modified-p modified))))
-
-
+(require 'mailabbrev nil t)
+(mh-defun-compat mail-abbrev-make-syntax-table ()
+  "Emacs 21 and XEmacs don't have this function."
+  nil)
+
+;;;###mh-autoload
+(defun mh-beginning-of-word (&optional n)
+  "Return position of the N th word backwards."
+  (unless n (setq n 1))
+  (let ((syntax-table (syntax-table)))
+    (unwind-protect
+        (save-excursion
+          (mail-abbrev-make-syntax-table)
+          (set-syntax-table mail-abbrev-syntax-table)
+          (backward-word n)
+          (point))
+      (set-syntax-table syntax-table))))
+
+;;;###mh-autoload
+(defun mh-colors-available-p ()
+  "Check if colors are available in the Emacs being used."
+  (or mh-xemacs-flag
+      (let ((color-cells (display-color-cells)))
+        (and (numberp color-cells) (>= color-cells 8)))))
+
+;;;###mh-autoload
+(defun mh-colors-in-use-p ()
+  "Check if colors are being used in the folder buffer."
+  (and mh-colors-available-flag font-lock-mode))
 
-;;; Internal bookkeeping variables:
+;;;###mh-autoload
+(defun mh-delete-line (lines)
+  "Delete the next LINES lines."
+  (delete-region (point) (progn (forward-line lines) (point))))
 
-(defvar mh-user-path nil
-  "Cached value of the \"Path:\" MH profile component.
-User's mail folder directory.")
-
-(defvar mh-draft-folder nil
-  "Cached value of the \"Draft-Folder:\" MH profile component.
-Name of folder containing draft messages.
-Nil means do not use a draft folder.")
-
-(defvar mh-unseen-seq nil
-  "Cached value of the \"Unseen-Sequence:\" MH profile component.
-Name of the Unseen sequence.")
-
-(defvar mh-previous-seq nil
-  "Cached value of the \"Previous-Sequence:\" MH profile component.
-Name of the Previous sequence.")
-
-(defvar mh-inbox nil
-  "Cached value of the \"Inbox:\" MH profile component.
-Set to \"+inbox\" if no such component.
-Name of the Inbox folder.")
+(defvar mh-image-load-path-called-flag nil)
 
-(defvar mh-previous-window-config nil
-  "Window configuration before MH-E command.")
+;;;###mh-autoload
+(defun mh-image-load-path ()
+  "Ensure that the MH-E images are accessible by `find-image'.
+Images for MH-E are found in ../../etc/images relative to the
+files in \"lisp/mh-e\". If `image-load-path' exists (since Emacs
+22), then the images directory is added to it if isn't already
+there. Otherwise, the images directory is added to the
+`load-path' if it isn't already there."
+  (unless mh-image-load-path-called-flag
+    (let (mh-library-name mh-image-load-path)
+      ;; First, find mh-e in the load-path.
+      (setq mh-library-name (locate-library "mh-e"))
+      (if (not mh-library-name)
+        (error "Can not find MH-E in load-path"))
+      (setq mh-image-load-path
+            (expand-file-name (concat (file-name-directory mh-library-name)
+                                      "../../etc/images")))
+      (if (not (file-exists-p mh-image-load-path))
+          (error "Can not find image directory %s" mh-image-load-path))
+      (if (boundp 'image-load-path)
+          (add-to-list 'image-load-path mh-image-load-path)
+        (add-to-list 'load-path mh-image-load-path)))
+    (setq mh-image-load-path-called-flag t)))
+
+;;;###mh-autoload
+(defun mh-make-local-vars (&rest pairs)
+  "Initialize local variables according to the variable-value PAIRS."
+  (while pairs
+    (set (make-local-variable (car pairs)) (car (cdr pairs)))
+    (setq pairs (cdr (cdr pairs)))))
+
+;;;###mh-autoload
+(defun mh-mapc (function list)
+  "Apply FUNCTION to each element of LIST for side effects only."
+  (while list
+    (funcall function (car list))
+    (setq list (cdr list))))
 
-(defvar mh-page-to-next-msg-flag nil
-  "Non-nil means next SPC or whatever goes to next undeleted message.")
+;;;###mh-autoload
+(defun mh-replace-string (old new)
+  "Replace all occurrences of OLD with NEW in the current buffer.
+Ignores case when searching for OLD."
+  (goto-char (point-min))
+  (let ((case-fold-search t))
+    (while (search-forward old nil t)
+      (replace-match new t t))))
 
 
 
-;;; Internal variables local to a folder.
-
-(defvar mh-current-folder nil
-  "Name of current folder, a string.")
-
-(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-msg-count nil
-  "Number of msgs in buffer.")
-
-(defvar mh-showing-mode nil
-  "If non-nil, show the message in a separate window.")
-
-(defvar mh-show-mode-map (make-sparse-keymap)
-  "Keymap used by the show buffer.")
-
-(defvar mh-show-folder-buffer nil
-  "Keeps track of folder whose message is being displayed.")
+;;; Logo Display
 
 (defvar mh-logo-cache nil)
 
+;;;###mh-autoload
 (defun mh-logo-display ()
   "Modify mode line to display MH-E logo."
+  (mh-image-load-path)
   (mh-do-in-gnu-emacs
    (add-text-properties
     0 2
@@ -569,1474 +162,223 @@
             (cons modeline-buffer-id-left-extent "XEmacs%N:"))
           (cons modeline-buffer-id-right-extent " %17b")))))
 
-(defun mh-showing-mode (&optional arg)
-  "Change whether messages should be displayed.
+
 
-With ARG, display messages iff ARG is positive."
-  (setq mh-showing-mode
-        (if (null arg)
-            (not mh-showing-mode)
-          (> (prefix-numeric-value arg) 0))))
-
-(defvar mh-seq-list nil
-  "Alist of this folder's sequences.
-Elements have the form (SEQUENCE . MESSAGES).")
-
-(defvar mh-seen-list nil
-  "List of displayed messages to be removed from the \"Unseen\" sequence.")
-
-(defvar mh-showing-with-headers nil
-  "If non-nil, MH-Show buffer contains message with all header fields.
-If nil, MH-Show buffer contains message processed normally.")
+;;; Read MH Profile
 
-
+(defvar mh-find-path-run nil
+  "Non-nil if `mh-find-path' has been run already.
+Do not access this variable; `mh-find-path' already uses it to
+avoid running more than once.")
+
+;;;###mh-autoload
+(defun mh-find-path ()
+  "Set variables from user's MH profile.
+
+This function sets `mh-user-path' from your \"Path:\" MH profile
+component (but defaults to \"Mail\" if one isn't present),
+`mh-draft-folder' from \"Draft-Folder:\", `mh-unseen-seq' from
+\"Unseen-Sequence:\", `mh-previous-seq' from
+\"Previous-Sequence:\", and `mh-inbox' from \"Inbox:\" (defaults
+to \"+inbox\").
+
+The hook `mh-find-path-hook' is run after these variables have
+been set. This hook can be used the change the value of these
+variables if you need to run with different values between MH and
+MH-E."
+  (unless mh-find-path-run
+    ;; Sanity checks.
+    (if (and (getenv "MH")
+             (not (file-readable-p (getenv "MH"))))
+        (error "MH environment variable contains unreadable file %s"
+               (getenv "MH")))
+    (if (null (mh-variants))
+        (error "Install MH and run install-mh before running MH-E"))
+    (let ((profile "~/.mh_profile"))
+      (if (not (file-readable-p profile))
+          (error "Run install-mh before running MH-E")))
+    ;; Read MH profile.
+    (setq mh-user-path (mh-profile-component "Path"))
+    (if (not mh-user-path)
+        (setq mh-user-path "Mail"))
+    (setq mh-user-path
+          (file-name-as-directory
+           (expand-file-name mh-user-path (expand-file-name "~"))))
+    (mh-set-x-image-cache-directory (expand-file-name ".mhe-x-image-cache"
+                                                      mh-user-path))
+    (setq mh-draft-folder (mh-profile-component "Draft-Folder"))
+    (if mh-draft-folder
+        (progn
+          (if (not (mh-folder-name-p mh-draft-folder))
+              (setq mh-draft-folder (format "+%s" mh-draft-folder)))
+          (if (not (file-exists-p (mh-expand-file-name mh-draft-folder)))
+              (error
+               "Draft folder \"%s\" not found; create it and try again"
+               (mh-expand-file-name mh-draft-folder)))))
+    (setq mh-inbox (mh-profile-component "Inbox"))
+    (cond ((not mh-inbox)
+           (setq mh-inbox "+inbox"))
+          ((not (mh-folder-name-p mh-inbox))
+           (setq mh-inbox (format "+%s" mh-inbox))))
+    (setq mh-unseen-seq (mh-profile-component "Unseen-Sequence"))
+    (if mh-unseen-seq
+        (setq mh-unseen-seq (intern mh-unseen-seq))
+      (setq mh-unseen-seq 'unseen))     ;old MH default?
+    (setq mh-previous-seq (mh-profile-component "Previous-Sequence"))
+    (if mh-previous-seq
+        (setq mh-previous-seq (intern mh-previous-seq)))
+    (run-hooks 'mh-find-path-hook)
+    (mh-collect-folder-names)
+    (setq mh-find-path-run t)))
+
+
+
+;;; Help Functions
+
+;;;###mh-autoload
+(defun mh-ephem-message (string)
+  "Display STRING in the minibuffer momentarily."
+  (message "%s" string)
+  (sit-for 5)
+  (message ""))
+
+(defvar mh-help-default nil
+  "Mode to use if messages are not present for the current mode.")
+
+(defvar mh-help-messages nil
+  "Help messages for all modes.
+This is an alist of alists. The primary key is a symbol
+representing the mode; the value is described in `mh-set-help'.")
+
+;;;###mh-autoload
+(defun mh-set-help (messages &optional default)
+  "Set help messages.
+
+The MESSAGES are assumed to be an associative array. It is used
+to show help for the most common commands in the current mode.
+The key is a prefix char. The value is one or more strings which
+are concatenated together and displayed in a help buffer if ? is
+pressed after the prefix character. The special key nil is used
+to display the non-prefixed commands.
 
-;;; MH-E macros
+The substitutions described in `substitute-command-keys' are performed as
+well.
 
-(defmacro with-mh-folder-updating (save-modification-flag &rest body)
-  "Format is (with-mh-folder-updating (SAVE-MODIFICATION-FLAG) &body BODY).
-Execute BODY, which can modify the folder buffer without having to
-worry about file locking or the read-only flag, and return its result.
-If SAVE-MODIFICATION-FLAG is non-nil, the buffer's modification flag
-is unchanged, otherwise it is cleared."
-  (setq save-modification-flag (car save-modification-flag)) ; CL style
-  `(prog1
-       (let ((mh-folder-updating-mod-flag (buffer-modified-p))
-             (buffer-read-only nil)
-             (buffer-file-name nil))    ;don't let the buffer get locked
-         (prog1
-             (progn
-               ,@body)
-           (mh-set-folder-modified-p mh-folder-updating-mod-flag)))
-     ,@(if (not save-modification-flag)
-           '((mh-set-folder-modified-p nil)))))
-
-(put 'with-mh-folder-updating 'lisp-indent-hook 'defun)
-
-(defmacro mh-in-show-buffer (show-buffer &rest body)
-  "Format is (mh-in-show-buffer (SHOW-BUFFER) &body BODY).
-Display buffer SHOW-BUFFER in other window and execute BODY in it.
-Stronger than `save-excursion', weaker than `save-window-excursion'."
-  (setq show-buffer (car show-buffer))  ; CL style
-  `(let ((mh-in-show-buffer-saved-window (selected-window)))
-     (switch-to-buffer-other-window ,show-buffer)
-     (if mh-bury-show-buffer-flag (bury-buffer (current-buffer)))
-     (unwind-protect
-         (progn
-           ,@body)
-       (select-window mh-in-show-buffer-saved-window))))
-
-(put 'mh-in-show-buffer 'lisp-indent-hook 'defun)
-
-(defmacro mh-do-at-event-location (event &rest body)
-  "Switch to the location of EVENT and execute BODY.
-After BODY has been executed return to original window. The
-modification flag of the buffer in the event window is
-preserved."
-  (let ((event-window (make-symbol "event-window"))
-        (event-position (make-symbol "event-position"))
-        (original-window (make-symbol "original-window"))
-        (original-position (make-symbol "original-position"))
-        (modified-flag (make-symbol "modified-flag")))
-    `(save-excursion
-       (let* ((,event-window
-               (or (mh-funcall-if-exists posn-window (event-start ,event))
-                   (mh-funcall-if-exists event-window ,event)))
-              (,event-position
-               (or (mh-funcall-if-exists posn-point (event-start ,event))
-                   (mh-funcall-if-exists event-closest-point ,event)))
-              (,original-window (selected-window))
-              (,original-position (progn
-                                   (set-buffer (window-buffer ,event-window))
-                                   (set-marker (make-marker) (point))))
-              (,modified-flag (buffer-modified-p))
-              (buffer-read-only nil))
-         (unwind-protect (progn
-                           (select-window ,event-window)
-                           (goto-char ,event-position)
-                           ,@body)
-           (set-buffer-modified-p ,modified-flag)
-           (goto-char ,original-position)
-           (set-marker ,original-position nil)
-           (select-window ,original-window))))))
-
-(put 'mh-do-at-event-location 'lisp-indent-hook 'defun)
-
-(defmacro mh-make-seq (name msgs)
-  "Create sequence NAME with the given MSGS."
-  (list 'cons name msgs))
-
-(defmacro mh-seq-name (sequence)
-  "Extract sequence name from the given SEQUENCE."
-  (list 'car sequence))
-
-(defmacro mh-seq-msgs (sequence)
-  "Extract messages from the given SEQUENCE."
-  (list 'cdr sequence))
-
-(defun mh-recenter (arg)
-  "Like recenter but with three improvements:
-
-- At the end of the buffer it tries to show fewer empty lines.
-
-- operates only if the current buffer is in the selected window.
-  (Commands like `save-some-buffers' can make this false.)
-
-- nil ARG means recenter as if prefix argument had been given."
-  (cond ((not (eq (get-buffer-window (current-buffer)) (selected-window)))
-         nil)
-        ((= (point-max) (save-excursion
-                          (forward-line (- (/ (window-height) 2) 2))
-                          (point)))
-         (let ((lines-from-end 2))
-           (save-excursion
-             (while (> (point-max) (progn (forward-line) (point)))
-               (incf lines-from-end)))
-           (recenter (- lines-from-end))))
-        ;; '(4) is the same as C-u prefix argument.
-        (t (recenter (or arg '(4))))))
+If optional argument DEFAULT is non-nil, then these messages will
+be used if help is asked for an unknown mode."
+  (add-to-list 'mh-help-messages (cons major-mode messages))
+  (if default
+      (setq mh-help-default major-mode)))
+
+;;;###mh-autoload
+(defun mh-help (&optional help-messages)
+  "Display cheat sheet for the MH-E commands.
+See `mh-set-help' for setting the help messages.
+HELP-MESSAGES are used instead if given.
+This is a list of one or more strings which are concatenated together
+and displayed in a help buffer."
+  (interactive)
+  (let* ((help (or help-messages
+                  (cdr (assoc nil (assoc major-mode mh-help-messages)))))
+         (text (substitute-command-keys (mapconcat 'identity help ""))))
+    (with-electric-help
+     (function
+      (lambda ()
+        (insert text)))
+     mh-help-buffer)))
+
+;;;###mh-autoload
+(defun mh-prefix-help ()
+  "Display cheat sheet for the commands of the current prefix in minibuffer."
+  (interactive)
+  ;; We got here because the user pressed a "?", but he pressed a prefix key
+  ;; before that. Since the the key vector starts at index 0, the index of the
+  ;; last keystroke is length-1 and thus the second to last keystroke is at
+  ;; length-2. We use that information to obtain a suitable prefix character
+  ;; from the recent keys.
+  (let* ((keys (recent-keys))
+         (prefix-char (elt keys (- (length keys) 2)))
+         (help (cdr (assoc prefix-char (assoc major-mode mh-help-messages)))))
+    (mh-help help)))
 
-(defun mh-start-of-uncleaned-message ()
-  "Position uninteresting headers off the top of the window."
-  (let ((case-fold-search t))
-    (re-search-forward
-     "^To:\\|^Cc:\\|^From:\\|^Subject:\\|^Date:" nil t)
-    (beginning-of-line)
-    (mh-recenter 0)))
+
 
-(defun mh-invalidate-show-buffer ()
-  "Invalidate the show buffer so we must update it to use it."
-  (if (get-buffer mh-show-buffer)
-      (save-excursion
-        (set-buffer mh-show-buffer)
-        (mh-unvisit-file))))
-
-(defun mh-unvisit-file ()
-  "Separate current buffer from the message file it was visiting."
-  (or (not (buffer-modified-p))
-      (null buffer-file-name)           ;we've been here before
-      (yes-or-no-p (format "Message %s modified; flush changes? "
-                           (file-name-nondirectory buffer-file-name)))
-      (error "Flushing changes not confirmed"))
-  (clear-visited-file-modtime)
-  (unlock-buffer)
-  (setq buffer-file-name nil))
+;;; Message Number Utilities
+
+;;;###mh-autoload
+(defun mh-coalesce-msg-list (messages)
+  "Given a list of MESSAGES, return a list of message number ranges.
+This is the inverse of `mh-read-msg-list', which expands ranges.
+Message lists passed to MH programs should be processed by this
+function to avoid exceeding system command line argument limits."
+  (let ((msgs (sort (copy-sequence messages) 'mh-greaterp))
+        (range-high nil)
+        (prev -1)
+        (ranges nil))
+    (while prev
+      (if range-high
+          (if (or (not (numberp prev))
+                  (not (equal (car msgs) (1- prev))))
+              (progn                    ;non-sequential, flush old range
+                (if (eq prev range-high)
+                    (setq ranges (cons range-high ranges))
+                  (setq ranges (cons (format "%s-%s" prev range-high) ranges)))
+                (setq range-high nil))))
+      (or range-high
+          (setq range-high (car msgs))) ;start new or first range
+      (setq prev (car msgs))
+      (setq msgs (cdr msgs)))
+    ranges))
+
+(defun mh-greaterp (msg1 msg2)
+  "Return the greater of two message indicators MSG1 and MSG2.
+Strings are \"smaller\" than numbers.
+Valid values are things like \"cur\", \"last\", 1, and 1820."
+  (if (numberp msg1)
+      (if (numberp msg2)
+          (> msg1 msg2)
+        t)
+    (if (numberp msg2)
+        nil
+      (string-lessp msg2 msg1))))
+
+;;;###mh-autoload
+(defun mh-lessp (msg1 msg2)
+  "Return the lesser of two message indicators MSG1 and MSG2.
+Strings are \"smaller\" than numbers.
+Valid values are things like \"cur\", \"last\", 1, and 1820."
+  (not (mh-greaterp msg1 msg2)))
 
+;;;###mh-autoload
 (defun mh-get-msg-num (error-if-no-message)
   "Return the message number of the displayed message.
 If the argument ERROR-IF-NO-MESSAGE is non-nil, then complain if
 the cursor is not pointing to a message."
   (save-excursion
     (beginning-of-line)
-    (cond ((looking-at mh-scan-msg-number-regexp)
+    (cond ((looking-at (mh-scan-msg-number-regexp))
            (string-to-number (buffer-substring (match-beginning 1)
                                                (match-end 1))))
           (error-if-no-message
            (error "Cursor not pointing to message"))
           (t nil))))
 
-(defun mh-folder-name-p (name)
-  "Return non-nil if NAME is the name of a folder.
-A name (a string or symbol) can be a folder name if it begins
-with \"+\"."
-  (if (symbolp name)
-      (eq (aref (symbol-name name) 0) ?+)
-    (and (> (length name) 0)
-         (eq (aref name 0) ?+))))
-
-(defun mh-expand-file-name (filename &optional default)
-  "Expand FILENAME like `expand-file-name', but also handle MH folder names.
-Any filename that starts with '+' is treated as a folder name.
-See `expand-file-name' for description of DEFAULT."
-  (if (mh-folder-name-p filename)
-      (expand-file-name (substring filename 1) mh-user-path)
-    (expand-file-name filename default)))
-
-(defun mh-msg-filename (msg &optional folder)
-  "Return the file name of MSG in FOLDER (default current folder)."
-  (expand-file-name (int-to-string msg)
-                    (if folder
-                        (mh-expand-file-name folder)
-                      mh-folder-filename)))
-
-;; Infrastructure to generate show-buffer functions from folder functions
-;; XEmacs does not have deactivate-mark? What is the equivalent of
-;; transient-mark-mode for XEmacs? Should we be restoring the mark in the
-;; folder buffer after the operation has been carried out.
-(defmacro mh-defun-show-buffer (function original-function
-                                         &optional dont-return)
-  "Define FUNCTION to run ORIGINAL-FUNCTION in folder buffer.
-If the buffer we start in is still visible and DONT-RETURN is nil
-then switch to it after that."
-  `(defun ,function ()
-     ,(format "Calls %s from the message's folder.\n%s\nSee \"%s\" for more 
info.\n"
-              original-function
-              (if dont-return ""
-                "When function completes, returns to the show buffer if it is
-still visible.\n")
-              original-function)
-     (interactive)
-     (when (buffer-live-p (get-buffer mh-show-folder-buffer))
-       (let ((config (current-window-configuration))
-             (folder-buffer mh-show-folder-buffer)
-             (normal-exit nil)
-             ,@(if dont-return () '((cur-buffer-name (buffer-name)))))
-         (pop-to-buffer mh-show-folder-buffer nil)
-         (unless (equal (buffer-name
-                         (window-buffer (frame-first-window (selected-frame))))
-                        folder-buffer)
-           (delete-other-windows))
-         (mh-goto-cur-msg t)
-         (mh-funcall-if-exists deactivate-mark)
-         (unwind-protect
-             (prog1 (call-interactively (function ,original-function))
-               (setq normal-exit t))
-           (mh-funcall-if-exists deactivate-mark)
-           (when (eq major-mode 'mh-folder-mode)
-             (mh-funcall-if-exists hl-line-highlight))
-           (cond ((not normal-exit)
-                  (set-window-configuration config))
-                 ,(if dont-return
-                      `(t (setq mh-previous-window-config config))
-                    `((and (get-buffer cur-buffer-name)
-                           (window-live-p (get-buffer-window
-                                           (get-buffer cur-buffer-name))))
-                      (pop-to-buffer (get-buffer cur-buffer-name) nil)))))))))
-
-;; Generate interactive functions for the show buffer from the corresponding
-;; folder functions.
-(mh-defun-show-buffer mh-show-previous-undeleted-msg
-                      mh-previous-undeleted-msg)
-(mh-defun-show-buffer mh-show-next-undeleted-msg
-                      mh-next-undeleted-msg)
-(mh-defun-show-buffer mh-show-quit mh-quit)
-(mh-defun-show-buffer mh-show-delete-msg mh-delete-msg)
-(mh-defun-show-buffer mh-show-refile-msg mh-refile-msg)
-(mh-defun-show-buffer mh-show-undo mh-undo)
-(mh-defun-show-buffer mh-show-execute-commands mh-execute-commands)
-(mh-defun-show-buffer mh-show-reply mh-reply t)
-(mh-defun-show-buffer mh-show-redistribute mh-redistribute)
-(mh-defun-show-buffer mh-show-forward mh-forward t)
-(mh-defun-show-buffer mh-show-header-display mh-header-display)
-(mh-defun-show-buffer mh-show-refile-or-write-again
-                      mh-refile-or-write-again)
-(mh-defun-show-buffer mh-show-show mh-show)
-(mh-defun-show-buffer mh-show-write-message-to-file
-                      mh-write-msg-to-file)
-(mh-defun-show-buffer mh-show-extract-rejected-mail
-                      mh-extract-rejected-mail t)
-(mh-defun-show-buffer mh-show-delete-msg-no-motion
-                      mh-delete-msg-no-motion)
-(mh-defun-show-buffer mh-show-first-msg mh-first-msg)
-(mh-defun-show-buffer mh-show-last-msg mh-last-msg)
-(mh-defun-show-buffer mh-show-copy-msg mh-copy-msg)
-(mh-defun-show-buffer mh-show-edit-again mh-edit-again t)
-(mh-defun-show-buffer mh-show-goto-msg mh-goto-msg)
-(mh-defun-show-buffer mh-show-inc-folder mh-inc-folder)
-(mh-defun-show-buffer mh-show-delete-subject-or-thread
-                      mh-delete-subject-or-thread)
-(mh-defun-show-buffer mh-show-delete-subject mh-delete-subject)
-(mh-defun-show-buffer mh-show-print-msg mh-print-msg)
-(mh-defun-show-buffer mh-show-send mh-send t)
-(mh-defun-show-buffer mh-show-toggle-showing mh-toggle-showing t)
-(mh-defun-show-buffer mh-show-pipe-msg mh-pipe-msg t)
-(mh-defun-show-buffer mh-show-sort-folder mh-sort-folder)
-(mh-defun-show-buffer mh-show-visit-folder mh-visit-folder t)
-(mh-defun-show-buffer mh-show-rescan-folder mh-rescan-folder)
-(mh-defun-show-buffer mh-show-pack-folder mh-pack-folder)
-(mh-defun-show-buffer mh-show-kill-folder mh-kill-folder t)
-(mh-defun-show-buffer mh-show-list-folders mh-list-folders t)
-(mh-defun-show-buffer mh-show-undo-folder mh-undo-folder)
-(mh-defun-show-buffer mh-show-delete-msg-from-seq
-                      mh-delete-msg-from-seq)
-(mh-defun-show-buffer mh-show-delete-seq mh-delete-seq)
-(mh-defun-show-buffer mh-show-list-sequences mh-list-sequences)
-(mh-defun-show-buffer mh-show-narrow-to-seq mh-narrow-to-seq)
-(mh-defun-show-buffer mh-show-put-msg-in-seq mh-put-msg-in-seq)
-(mh-defun-show-buffer mh-show-msg-is-in-seq mh-msg-is-in-seq)
-(mh-defun-show-buffer mh-show-widen mh-widen)
-(mh-defun-show-buffer mh-show-narrow-to-subject mh-narrow-to-subject)
-(mh-defun-show-buffer mh-show-narrow-to-from mh-narrow-to-from)
-(mh-defun-show-buffer mh-show-narrow-to-cc mh-narrow-to-cc)
-(mh-defun-show-buffer mh-show-narrow-to-range mh-narrow-to-range)
-(mh-defun-show-buffer mh-show-narrow-to-to mh-narrow-to-to)
-(mh-defun-show-buffer mh-show-store-msg mh-store-msg)
-(mh-defun-show-buffer mh-show-page-digest mh-page-digest)
-(mh-defun-show-buffer mh-show-page-digest-backwards
-                      mh-page-digest-backwards)
-(mh-defun-show-buffer mh-show-burst-digest mh-burst-digest)
-(mh-defun-show-buffer mh-show-page-msg mh-page-msg)
-(mh-defun-show-buffer mh-show-previous-page mh-previous-page)
-(mh-defun-show-buffer mh-show-modify mh-modify t)
-(mh-defun-show-buffer mh-show-next-button mh-next-button)
-(mh-defun-show-buffer mh-show-prev-button mh-prev-button)
-(mh-defun-show-buffer mh-show-toggle-mime-part mh-folder-toggle-mime-part)
-(mh-defun-show-buffer mh-show-save-mime-part mh-folder-save-mime-part)
-(mh-defun-show-buffer mh-show-inline-mime-part mh-folder-inline-mime-part)
-(mh-defun-show-buffer mh-show-toggle-threads mh-toggle-threads)
-(mh-defun-show-buffer mh-show-thread-delete mh-thread-delete)
-(mh-defun-show-buffer mh-show-thread-refile mh-thread-refile)
-(mh-defun-show-buffer mh-show-update-sequences mh-update-sequences)
-(mh-defun-show-buffer mh-show-next-unread-msg mh-next-unread-msg)
-(mh-defun-show-buffer mh-show-previous-unread-msg mh-previous-unread-msg)
-(mh-defun-show-buffer mh-show-thread-ancestor mh-thread-ancestor)
-(mh-defun-show-buffer mh-show-thread-next-sibling mh-thread-next-sibling)
-(mh-defun-show-buffer mh-show-thread-previous-sibling
-                      mh-thread-previous-sibling)
-(mh-defun-show-buffer mh-show-index-visit-folder mh-index-visit-folder t)
-(mh-defun-show-buffer mh-show-toggle-tick mh-toggle-tick)
-(mh-defun-show-buffer mh-show-narrow-to-tick mh-narrow-to-tick)
-(mh-defun-show-buffer mh-show-junk-blacklist mh-junk-blacklist)
-(mh-defun-show-buffer mh-show-junk-whitelist mh-junk-whitelist)
-(mh-defun-show-buffer mh-show-index-new-messages mh-index-new-messages)
-(mh-defun-show-buffer mh-show-index-ticked-messages mh-index-ticked-messages)
-(mh-defun-show-buffer mh-show-index-sequenced-messages
-                      mh-index-sequenced-messages)
-(mh-defun-show-buffer mh-show-catchup mh-catchup)
-(mh-defun-show-buffer mh-show-ps-print-toggle-color mh-ps-print-toggle-color)
-(mh-defun-show-buffer mh-show-ps-print-toggle-faces mh-ps-print-toggle-faces)
-(mh-defun-show-buffer mh-show-ps-print-msg-file mh-ps-print-msg-file)
-(mh-defun-show-buffer mh-show-ps-print-msg mh-ps-print-msg)
-(mh-defun-show-buffer mh-show-toggle-mime-buttons mh-toggle-mime-buttons)
-(mh-defun-show-buffer mh-show-display-with-external-viewer
-                      mh-display-with-external-viewer)
-
-
-
-;;; Build mh-show-mode keymaps
-
-(gnus-define-keys mh-show-mode-map
-  " "    mh-show-page-msg
-  "!"    mh-show-refile-or-write-again
-  "'"    mh-show-toggle-tick
-  ","    mh-show-header-display
-  "."    mh-show-show
-  ">"    mh-show-write-message-to-file
-  "?"    mh-help
-  "E"    mh-show-extract-rejected-mail
-  "M"    mh-show-modify
-  "\177" mh-show-previous-page
-  "\C-d" mh-show-delete-msg-no-motion
-  "\t"   mh-show-next-button
-  [backtab] mh-show-prev-button
-  "\M-\t" mh-show-prev-button
-  "\ed"  mh-show-redistribute
-  "^"    mh-show-refile-msg
-  "c"    mh-show-copy-msg
-  "d"    mh-show-delete-msg
-  "e"    mh-show-edit-again
-  "f"    mh-show-forward
-  "g"    mh-show-goto-msg
-  "i"    mh-show-inc-folder
-  "k"    mh-show-delete-subject-or-thread
-  "m"    mh-show-send
-  "n"    mh-show-next-undeleted-msg
-  "\M-n" mh-show-next-unread-msg
-  "o"    mh-show-refile-msg
-  "p"    mh-show-previous-undeleted-msg
-  "\M-p" mh-show-previous-unread-msg
-  "q"    mh-show-quit
-  "r"    mh-show-reply
-  "s"    mh-show-send
-  "t"    mh-show-toggle-showing
-  "u"    mh-show-undo
-  "x"    mh-show-execute-commands
-  "v"    mh-show-index-visit-folder
-  "|"    mh-show-pipe-msg)
-
-(gnus-define-keys (mh-show-folder-map "F" mh-show-mode-map)
-  "?"    mh-prefix-help
-  "'"    mh-index-ticked-messages
-  "S"    mh-show-sort-folder
-  "c"    mh-show-catchup
-  "f"    mh-show-visit-folder
-  "k"    mh-show-kill-folder
-  "l"    mh-show-list-folders
-  "n"    mh-index-new-messages
-  "o"    mh-show-visit-folder
-  "q"    mh-show-index-sequenced-messages
-  "r"    mh-show-rescan-folder
-  "s"    mh-search
-  "t"    mh-show-toggle-threads
-  "u"    mh-show-undo-folder
-  "v"    mh-show-visit-folder)
-
-(gnus-define-keys (mh-show-sequence-map "S" mh-show-mode-map)
-  "'"    mh-show-narrow-to-tick
-  "?"    mh-prefix-help
-  "d"    mh-show-delete-msg-from-seq
-  "k"    mh-show-delete-seq
-  "l"    mh-show-list-sequences
-  "n"    mh-show-narrow-to-seq
-  "p"    mh-show-put-msg-in-seq
-  "s"    mh-show-msg-is-in-seq
-  "w"    mh-show-widen)
-
-(define-key mh-show-mode-map "I" mh-inc-spool-map)
-
-(gnus-define-keys (mh-show-junk-map "J" mh-show-mode-map)
-  "?"    mh-prefix-help
-  "b"    mh-show-junk-blacklist
-  "w"    mh-show-junk-whitelist)
-
-(gnus-define-keys (mh-show-ps-print-map "P" mh-show-mode-map)
-  "?"  mh-prefix-help
-  "C"  mh-show-ps-print-toggle-color
-  "F"  mh-show-ps-print-toggle-faces
-  "f"  mh-show-ps-print-msg-file
-  "l"   mh-show-print-msg
-  "p"  mh-show-ps-print-msg)
-
-(gnus-define-keys (mh-show-thread-map "T" mh-show-mode-map)
-  "?"    mh-prefix-help
-  "u"    mh-show-thread-ancestor
-  "p"    mh-show-thread-previous-sibling
-  "n"    mh-show-thread-next-sibling
-  "t"    mh-show-toggle-threads
-  "d"    mh-show-thread-delete
-  "o"    mh-show-thread-refile)
-
-(gnus-define-keys (mh-show-limit-map "/" mh-show-mode-map)
-  "'"    mh-show-narrow-to-tick
-  "?"    mh-prefix-help
-  "c"    mh-show-narrow-to-cc
-  "g"    mh-show-narrow-to-range
-  "m"    mh-show-narrow-to-from
-  "s"    mh-show-narrow-to-subject
-  "t"    mh-show-narrow-to-to
-  "w"    mh-show-widen)
-
-(gnus-define-keys (mh-show-extract-map "X" mh-show-mode-map)
-  "?"    mh-prefix-help
-  "s"    mh-show-store-msg
-  "u"    mh-show-store-msg)
-
-;; Untested...
-(gnus-define-keys (mh-show-digest-map "D" mh-show-mode-map)
-  "?"    mh-prefix-help
-  " "    mh-show-page-digest
-  "\177" mh-show-page-digest-backwards
-  "b"    mh-show-burst-digest)
-
-(gnus-define-keys (mh-show-mime-map "K" mh-show-mode-map)
-  "?"           mh-prefix-help
-  "a"           mh-mime-save-parts
-  "e"           mh-show-display-with-external-viewer
-  "v"           mh-show-toggle-mime-part
-  "o"           mh-show-save-mime-part
-  "i"           mh-show-inline-mime-part
-  "t"           mh-show-toggle-mime-buttons
-  "\t"          mh-show-next-button
-  [backtab]     mh-show-prev-button
-  "\M-\t"       mh-show-prev-button)
-
-(easy-menu-define
-  mh-show-sequence-menu mh-show-mode-map "Menu for MH-E folder-sequence."
-  '("Sequence"
-    ["Add Message to Sequence..."       mh-show-put-msg-in-seq t]
-    ["List Sequences for Message"       mh-show-msg-is-in-seq t]
-    ["Delete Message from Sequence..."  mh-show-delete-msg-from-seq t]
-    ["List Sequences in Folder..."      mh-show-list-sequences t]
-    ["Delete Sequence..."               mh-show-delete-seq t]
-    ["Narrow to Sequence..."            mh-show-narrow-to-seq t]
-    ["Widen from Sequence"              mh-show-widen t]
-    "--"
-    ["Narrow to Subject Sequence"       mh-show-narrow-to-subject t]
-    ["Narrow to Tick Sequence"          mh-show-narrow-to-tick
-     (save-excursion
-       (set-buffer mh-show-folder-buffer)
-       (and mh-tick-seq (mh-seq-msgs (mh-find-seq mh-tick-seq))))]
-    ["Delete Rest of Same Subject"      mh-show-delete-subject t]
-    ["Toggle Tick Mark"                 mh-show-toggle-tick t]
-    "--"
-    ["Push State Out to MH"             mh-show-update-sequences t]))
-
-(easy-menu-define
-  mh-show-message-menu mh-show-mode-map "Menu for MH-E folder-message."
-  '("Message"
-    ["Show Message"                     mh-show-show t]
-    ["Show Message with Header"         mh-show-header-display t]
-    ["Next Message"                     mh-show-next-undeleted-msg t]
-    ["Previous Message"                 mh-show-previous-undeleted-msg t]
-    ["Go to First Message"              mh-show-first-msg t]
-    ["Go to Last Message"               mh-show-last-msg t]
-    ["Go to Message by Number..."       mh-show-goto-msg t]
-    ["Modify Message"                   mh-show-modify t]
-    ["Delete Message"                   mh-show-delete-msg t]
-    ["Refile Message"                   mh-show-refile-msg t]
-    ["Undo Delete/Refile"               mh-show-undo t]
-    ["Process Delete/Refile"            mh-show-execute-commands t]
-    "--"
-    ["Compose a New Message"            mh-send t]
-    ["Reply to Message..."              mh-show-reply t]
-    ["Forward Message..."               mh-show-forward t]
-    ["Redistribute Message..."          mh-show-redistribute t]
-    ["Edit Message Again"               mh-show-edit-again t]
-    ["Re-edit a Bounced Message"        mh-show-extract-rejected-mail t]
-    "--"
-    ["Copy Message to Folder..."        mh-show-copy-msg t]
-    ["Print Message"                    mh-show-print-msg t]
-    ["Write Message to File..."         mh-show-write-msg-to-file t]
-    ["Pipe Message to Command..."       mh-show-pipe-msg t]
-    ["Unpack Uuencoded Message..."      mh-show-store-msg t]
-    ["Burst Digest Message"             mh-show-burst-digest t]))
-
-(easy-menu-define
-  mh-show-folder-menu mh-show-mode-map  "Menu for MH-E folder."
-  '("Folder"
-    ["Incorporate New Mail"             mh-show-inc-folder t]
-    ["Toggle Show/Folder"               mh-show-toggle-showing t]
-    ["Execute Delete/Refile"            mh-show-execute-commands t]
-    ["Rescan Folder"                    mh-show-rescan-folder t]
-    ["Thread Folder"                    mh-show-toggle-threads t]
-    ["Pack Folder"                      mh-show-pack-folder t]
-    ["Sort Folder"                      mh-show-sort-folder t]
-    "--"
-    ["List Folders"                     mh-show-list-folders t]
-    ["Visit a Folder..."                mh-show-visit-folder t]
-    ["View New Messages"                mh-show-index-new-messages t]
-    ["Search..."                        mh-search t]
-    "--"
-    ["Quit MH-E"                        mh-quit t]))
-
-;; Ensure new buffers won't get this mode if default-major-mode is nil.
-(put 'mh-show-mode 'mode-class 'special)
-
-;; Shush compiler.
-(eval-when-compile (defvar font-lock-auto-fontify))
-
-(define-derived-mode mh-show-mode text-mode "MH-Show"
-  "Major mode for showing messages in MH-E.\\<mh-show-mode-map>
-
-The hook `mh-show-mode-hook' is called upon entry to this mode.
-
-See also `mh-folder-mode'.
-
-\\{mh-show-mode-map}"
-  (set (make-local-variable 'mail-header-separator) mh-mail-header-separator)
-  (setq paragraph-start (default-value 'paragraph-start))
-  (mh-show-unquote-From)
-  (mh-show-xface)
-  (mh-show-addr)
-  (setq buffer-invisibility-spec '((vanish . t) t))
-  (set (make-local-variable 'line-move-ignore-invisible) t)
-  (make-local-variable 'font-lock-defaults)
-  ;;(set (make-local-variable 'font-lock-support-mode) nil)
-  (cond
-   ((equal mh-highlight-citation-style 'font-lock)
-    (setq font-lock-defaults '(mh-show-font-lock-keywords-with-cite t)))
-   ((equal mh-highlight-citation-style 'gnus)
-    (setq font-lock-defaults '((mh-show-font-lock-keywords)
-                               t nil nil nil
-                               (font-lock-fontify-region-function
-                                . mh-show-font-lock-fontify-region)))
-    (mh-gnus-article-highlight-citation))
-   (t
-    (setq font-lock-defaults '(mh-show-font-lock-keywords t))))
-  (if (and mh-xemacs-flag
-           font-lock-auto-fontify)
-      (turn-on-font-lock))
-  (set (make-local-variable 'tool-bar-map) mh-show-tool-bar-map)
-  (mh-funcall-if-exists mh-tool-bar-init :show)
-  (when mh-decode-mime-flag
-    (mh-make-local-hook 'kill-buffer-hook)
-    (add-hook 'kill-buffer-hook 'mh-mime-cleanup nil t))
-  (easy-menu-add mh-show-sequence-menu)
-  (easy-menu-add mh-show-message-menu)
-  (easy-menu-add mh-show-folder-menu)
-  (make-local-variable 'mh-show-folder-buffer)
-  (buffer-disable-undo)
-  (setq buffer-read-only t)
-  (use-local-map mh-show-mode-map))
-
-(defun mh-show-addr ()
-  "Use `goto-address'."
-  (when mh-show-use-goto-addr-flag
-    (if (not (featurep 'goto-addr))
-        (load "goto-addr" t t))
-    (if (fboundp 'goto-address)
-        (goto-address))))
-
-
-
-;; X-Face and Face display
-(defvar mh-show-xface-function
-  (cond ((and mh-xemacs-flag (locate-library "x-face") (not (featurep 'xface)))
-         (load "x-face" t t)
-         #'mh-face-display-function)
-        ((>= emacs-major-version 21)
-         #'mh-face-display-function)
-        (t #'ignore))
-  "Determine at run time what function should be called to display X-Face.")
-
-(defvar mh-uncompface-executable
-  (and (fboundp 'executable-find) (executable-find "uncompface")))
-
-(defun mh-face-to-png (data)
-  "Convert base64 encoded DATA to png image."
-  (with-temp-buffer
-    (insert data)
-    (ignore-errors (base64-decode-region (point-min) (point-max)))
-    (buffer-string)))
-
-(defun mh-uncompface (data)
-  "Run DATA through `uncompface' to generate bitmap."
-  (with-temp-buffer
-    (insert data)
-    (when (and mh-uncompface-executable
-               (equal (call-process-region (point-min) (point-max)
-                                           mh-uncompface-executable t '(t nil))
-                      0))
-      (mh-icontopbm)
-      (buffer-string))))
-
-(defun mh-icontopbm ()
-  "Elisp substitute for `icontopbm'."
-  (goto-char (point-min))
-  (let ((end (point-max)))
-    (while (re-search-forward "0x\\(..\\)\\(..\\)," nil t)
-      (save-excursion
-        (goto-char (point-max))
-        (insert (string-to-number (match-string 1) 16))
-        (insert (string-to-number (match-string 2) 16))))
-    (delete-region (point-min) end)
-    (goto-char (point-min))
-    (insert "P4\n48 48\n")))
-
-(mh-do-in-xemacs (defvar default-enable-multibyte-characters))
-
-(defmacro mh-face-foreground-compat (face &optional frame inherit)
-  "Return the foreground color name of FACE, or nil if unspecified.
-See documentation for `face-foreground' for a description of the
-arguments FACE, FRAME, and INHERIT.
-
-Calls `face-foreground' correctly in older environments. Versions
-of Emacs prior to version 22 lacked an INHERIT argument which
-when t tells `face-foreground' to consider an inherited value for
-the foreground if the face does not define one itself."
-  (if (>= emacs-major-version 22)
-      `(face-foreground ,face ,frame ,inherit)
-    `(face-foreground ,face ,frame)))
-
-(defmacro mh-face-background-compat (face &optional frame inherit)
-  "Return the background color name of face, or nil if unspecified.
-See documentation for `back-foreground' for a description of the
-arguments FACE, FRAME, and INHERIT.
-
-Calls `face-background' correctly in older environments. Versions
-of Emacs prior to version 22 lacked an INHERIT argument which
-when t tells `face-background' to consider an inherited value for
-the background if the face does not define one itself."
-  (if (>= emacs-major-version 22)
-      `(face-background ,face ,frame ,inherit)
-    `(face-background ,face ,frame)))
-
-(defun mh-face-display-function ()
-  "Display a Face, X-Face, or X-Image-URL header field.
-If more than one of these are present, then the first one found
-in this order is used."
-  (save-restriction
-    (goto-char (point-min))
-    (re-search-forward "\n\n" (point-max) t)
-    (narrow-to-region (point-min) (point))
-    (let* ((case-fold-search t)
-           (default-enable-multibyte-characters nil)
-           (face (message-fetch-field "face" t))
-           (x-face (message-fetch-field "x-face" t))
-           (url (message-fetch-field "x-image-url" t))
-           raw type)
-      (cond (face (setq raw (mh-face-to-png face)
-                        type 'png))
-            (x-face (setq raw (mh-uncompface x-face)
-                          type 'pbm))
-            (url (setq type 'url))
-            (t (multiple-value-setq (type raw) (mh-picon-get-image))))
-      (when type
-        (goto-char (point-min))
-        (when (re-search-forward "^from:" (point-max) t)
-          ;; GNU Emacs
-          (mh-do-in-gnu-emacs
-            (if (eq type 'url)
-                (mh-x-image-url-display url)
-              (mh-funcall-if-exists
-               insert-image (create-image
-                             raw type t
-                             :foreground
-                             (mh-face-foreground-compat 'mh-show-xface nil t)
-                             :background
-                             (mh-face-background-compat 'mh-show-xface nil t))
-               " ")))
-          ;; XEmacs
-          (mh-do-in-xemacs
-            (cond
-             ((eq type 'url)
-              (mh-x-image-url-display url))
-             ((eq type 'png)
-              (when (featurep 'png)
-                (set-extent-begin-glyph
-                 (make-extent (point) (point))
-                 (make-glyph (vector 'png ':data (mh-face-to-png face))))))
-             ;; Try internal xface support if available...
-             ((and (eq type 'pbm) (featurep 'xface))
-              (set-glyph-face
-               (set-extent-begin-glyph
-                (make-extent (point) (point))
-                (make-glyph (vector 'xface ':data (concat "X-Face: " x-face))))
-               'mh-show-xface))
-             ;; Otherwise try external support with x-face...
-             ((and (eq type 'pbm)
-                   (fboundp 'x-face-xmas-wl-display-x-face)
-                   (fboundp 'executable-find) (executable-find "uncompface"))
-              (mh-funcall-if-exists x-face-xmas-wl-display-x-face))
-             ;; Picon display
-             ((and raw (member type '(xpm xbm gif)))
-              (when (featurep type)
-                (set-extent-begin-glyph
-                 (make-extent (point) (point))
-                 (make-glyph (vector type ':data raw))))))
-            (when raw (insert " "))))))))
-
-(defun mh-show-xface ()
-  "Display X-Face."
-  (when (and window-system mh-show-use-xface-flag
-             (or mh-decode-mime-flag mh-mhl-format-file
-                 mh-clean-message-header-flag))
-    (funcall mh-show-xface-function)))
-
-
-
-;;; Picon display
-
-;; XXX: This should be customizable. As a side-effect of setting this
-;;   variable, arrange to reset mh-picon-existing-directory-list to 'unset.
-(defvar mh-picon-directory-list
-  '("~/.picons" "~/.picons/users" "~/.picons/usenix" "~/.picons/news"
-    "~/.picons/domains" "~/.picons/misc"
-    "/usr/share/picons/" "/usr/share/picons/users" "/usr/share/picons/usenix"
-    "/usr/share/picons/news" "/usr/share/picons/domains"
-    "/usr/share/picons/misc")
-  "List of directories where picons reside.
-The directories are searched for in the order they appear in the list.")
-
-(defvar mh-picon-existing-directory-list 'unset
-  "List of directories to search in.")
-
-(defvar mh-picon-cache (make-hash-table :test #'equal))
-
-(defvar mh-picon-image-types
-  (loop for type in '(xpm xbm gif)
-        when (or (mh-do-in-gnu-emacs
-                   (ignore-errors
-                     (mh-funcall-if-exists image-type-available-p type)))
-                 (mh-do-in-xemacs (featurep type)))
-        collect type))
-
-(defun mh-picon-set-directory-list ()
-  "Update `mh-picon-existing-directory-list' if needed."
-  (when (eq mh-picon-existing-directory-list 'unset)
-    (setq mh-picon-existing-directory-list
-          (loop for x in mh-picon-directory-list
-                when (file-directory-p x) collect x))))
-
-(defun* mh-picon-get-image ()
-  "Find the best possible match and return contents."
-  (mh-picon-set-directory-list)
-  (save-restriction
-    (let* ((from-field (ignore-errors (car (message-tokenize-header
-                                            (mh-get-header-field "from:")))))
-           (from (car (ignore-errors
-                        (mh-funcall-if-exists ietf-drums-parse-address
-                                              from-field))))
-           (host (and from
-                      (string-match "\\([^+]*\\)\\(+.*\\)address@hidden(.*\\)" 
from)
-                      (downcase (match-string 3 from))))
-           (user (and host (downcase (match-string 1 from))))
-           (canonical-address (format "address@hidden" user host))
-           (cached-value (gethash canonical-address mh-picon-cache))
-           (host-list (and host (delete "" (split-string host "\\."))))
-           (match nil))
-      (cond (cached-value (return-from mh-picon-get-image cached-value))
-            ((not host-list) (return-from mh-picon-get-image nil)))
-      (setq match
-            (block 'loop
-              ;; address@hidden search
-              (loop for dir in mh-picon-existing-directory-list
-                    do (loop for type in mh-picon-image-types
-                             ;; address@hidden
-                             for file1 = (format "%s/%s.%s"
-                                                 dir canonical-address type)
-                             when (file-exists-p file1)
-                             do (return-from 'loop file1)
-                             ;; [path]user
-                             for file2 = (format "%s/%s.%s" dir user type)
-                             when (file-exists-p file2)
-                             do (return-from 'loop file2)
-                             ;; [path]host
-                             for file3 = (format "%s/%s.%s" dir host type)
-                             when (file-exists-p file3)
-                             do (return-from 'loop file3)))
-              ;; facedb search
-              ;; Search order for address@hidden:
-              ;;   [path]net/foo/user
-              ;;   [path]net/foo/user/face
-              ;;   [path]net/user
-              ;;   [path]net/user/face
-              ;;   [path]net/foo/unknown
-              ;;   [path]net/foo/unknown/face
-              ;;   [path]net/unknown
-              ;;   [path]net/unknown/face
-              (loop for u in (list user "unknown")
-                    do (loop for dir in mh-picon-existing-directory-list
-                             do (loop for x on host-list by #'cdr
-                                      for y = (mh-picon-generate-path x u dir)
-                                      do (loop for type in mh-picon-image-types
-                                               for z1 = (format "%s.%s" y type)
-                                               when (file-exists-p z1)
-                                               do (return-from 'loop z1)
-                                               for z2 = (format "%s/face.%s"
-                                                                y type)
-                                               when (file-exists-p z2)
-                                               do (return-from 'loop z2)))))))
-      (setf (gethash canonical-address mh-picon-cache)
-            (mh-picon-file-contents match)))))
-
-(defun mh-picon-file-contents (file)
-  "Return details about FILE.
-A list of consisting of a symbol for the type of the file and the
-file contents as a string is returned. If FILE is nil, then both
-elements of the list are nil."
-  (if (stringp file)
-      (with-temp-buffer
-        (let ((type (and (string-match ".*\\.\\(...\\)$" file)
-                         (intern (match-string 1 file)))))
-          (insert-file-contents-literally file)
-          (values type (buffer-string))))
-    (values nil nil)))
-
-(defun mh-picon-generate-path (host-list user directory)
-  "Generate the image file path.
-HOST-LIST is the parsed host address of the email address, USER
-the username and DIRECTORY is the directory relative to which the
-path is generated."
-  (loop with acc = ""
-        for elem in host-list
-        do (setq acc (format "%s/%s" elem acc))
-        finally return (format "%s/%s%s" directory acc user)))
-
-
-
-;; X-Image-URL display
-
-(defvar mh-x-image-cache-directory nil
-  "Directory where X-Image-URL images are cached.")
-(defvar mh-x-image-scaling-function
-  (cond ((executable-find "convert")
-         'mh-x-image-scale-with-convert)
-        ((and (executable-find "anytopnm") (executable-find "pnmscale")
-              (executable-find "pnmtopng"))
-         'mh-x-image-scale-with-pnm)
-        (t 'ignore))
-  "Function to use to scale image to proper size.")
-(defvar mh-wget-executable nil)
-(defvar mh-wget-choice
-  (or (and (setq mh-wget-executable (executable-find "wget")) 'wget)
-      (and (setq mh-wget-executable (executable-find "fetch")) 'fetch)
-      (and (setq mh-wget-executable (executable-find "curl")) 'curl)))
-(defvar mh-wget-option
-  (cdr (assoc mh-wget-choice '((curl . "-o") (fetch . "-o") (wget . "-O")))))
-(defvar mh-x-image-temp-file nil)
-(defvar mh-x-image-url nil)
-(defvar mh-x-image-marker nil)
-(defvar mh-x-image-url-cache-file nil)
-
-;; Functions to scale image to proper size
-(defun mh-x-image-scale-with-pnm (input output)
-  "Scale image in INPUT file and write to OUTPUT file using pnm tools."
-  (let ((res (shell-command-to-string
-              (format "anytopnm < %s | pnmscale -xysize 96 48 | pnmtopng > %s"
-                      input output))))
-    (unless (equal res "")
-      (delete-file output))))
-
-(defun mh-x-image-scale-with-convert (input output)
-  "Scale image in INPUT file and write to OUTPUT file using ImageMagick."
-  (call-process "convert" nil nil nil "-geometry" "96x48" input output))
-
-;; Copy of constant from url-util.el in Emacs 22; needed by Emacs 21.
-(if (not (boundp 'url-unreserved-chars))
-    (defconst url-unreserved-chars
-      '(
-        ?a ?b ?c ?d ?e ?f ?g ?h ?i ?j ?k ?l ?m ?n ?o ?p ?q ?r ?s ?t ?u ?v ?w 
?x ?y ?z
-        ?A ?B ?C ?D ?E ?F ?G ?H ?I ?J ?K ?L ?M ?N ?O ?P ?Q ?R ?S ?T ?U ?V ?W 
?X ?Y ?Z
-        ?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9
-        ?- ?_ ?. ?! ?~ ?* ?' ?\( ?\))
-      "A list of characters that are _NOT_ reserved in the URL spec.
-This is taken from RFC 2396."))
-
-;; Copy of function from url-util.el in Emacs 22; needed by Emacs 21.
-(mh-defun-compat url-hexify-string (str)
-  "Escape characters in a string."
-  (mapconcat
-   (lambda (char)
-     ;; Fixme: use a char table instead.
-     (if (not (memq char url-unreserved-chars))
-        (if (> char 255)
-              (error "Hexifying multibyte character %s" str)
-          (format "%%%02X" char))
-       (char-to-string char)))
-   str ""))
-
-(defun mh-x-image-url-cache-canonicalize (url)
-  "Canonicalize URL.
-Replace the ?/ character with a ?! character and append .png.
-Also replaces special characters with `url-hexify-string' since
-not all characters, such as :, are legal within Windows
-filenames. See URL 
`http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/naming_a_file.asp'."
-  (format "%s/%s.png" mh-x-image-cache-directory
-          (url-hexify-string
-           (with-temp-buffer
-             (insert url)
-             (mh-replace-string "/" "!")
-             (buffer-string)))))
-
-(defun mh-x-image-set-download-state (file data)
-  "Setup a symbolic link from FILE to DATA."
-  (if data
-      (make-symbolic-link (symbol-name data) file t)
-    (delete-file file)))
-
-(defun mh-x-image-get-download-state (file)
-  "Check the state of FILE by following any symbolic links."
-  (unless (file-exists-p mh-x-image-cache-directory)
-    (call-process "mkdir" nil nil nil mh-x-image-cache-directory))
-  (cond ((file-symlink-p file)
-         (intern (file-name-nondirectory (file-chase-links file))))
-        ((not (file-exists-p file)) nil)
-        (t 'ok)))
-
-(defun mh-x-image-url-fetch-image (url cache-file marker sentinel)
-  "Fetch and display the image specified by URL.
-After the image is fetched, it is stored in CACHE-FILE. It will
-be displayed in a buffer and position specified by MARKER. The
-actual display is carried out by the SENTINEL function."
-  (if mh-wget-executable
-      (let ((buffer (get-buffer-create (generate-new-buffer-name
-                                        mh-temp-fetch-buffer)))
-            (filename (or (mh-funcall-if-exists make-temp-file "mhe-fetch")
-                          (expand-file-name (make-temp-name "~/mhe-fetch")))))
-        (save-excursion
-          (set-buffer buffer)
-          (set (make-local-variable 'mh-x-image-url-cache-file) cache-file)
-          (set (make-local-variable 'mh-x-image-marker) marker)
-          (set (make-local-variable 'mh-x-image-temp-file) filename))
-        (set-process-sentinel
-         (start-process "*mh-x-image-url-fetch*" buffer
-                        mh-wget-executable mh-wget-option filename url)
-         sentinel))
-    ;; Temporary failure
-    (mh-x-image-set-download-state cache-file 'try-again)))
-
-(defun mh-x-image-display (image marker)
-  "Display IMAGE at MARKER."
-  (save-excursion
-    (set-buffer (marker-buffer marker))
-    (let ((buffer-read-only nil)
-          (default-enable-multibyte-characters nil)
-          (buffer-modified-flag (buffer-modified-p)))
-      (unwind-protect
-          (when (and (file-readable-p image) (not (file-symlink-p image))
-                     (eq marker mh-x-image-marker))
-            (goto-char marker)
-            (mh-do-in-gnu-emacs
-              (mh-funcall-if-exists insert-image (create-image image 'png)))
-            (mh-do-in-xemacs
-              (when (featurep 'png)
-                (set-extent-begin-glyph
-                 (make-extent (point) (point))
-                 (make-glyph
-                  (vector 'png ':data (with-temp-buffer
-                                        (insert-file-contents-literally image)
-                                        (buffer-string))))))))
-        (set-buffer-modified-p buffer-modified-flag)))))
-
-(defun mh-x-image-scale-and-display (process change)
-  "When the wget PROCESS terminates scale and display image.
-The argument CHANGE is ignored."
-  (when (eq (process-status process) 'exit)
-    (let (marker temp-file cache-filename wget-buffer)
-      (save-excursion
-        (set-buffer (setq wget-buffer (process-buffer process)))
-        (setq marker mh-x-image-marker
-              cache-filename mh-x-image-url-cache-file
-              temp-file mh-x-image-temp-file))
-      (cond
-       ;; Check if we have `convert'
-       ((eq mh-x-image-scaling-function 'ignore)
-        (message "The \"convert\" program is needed to display X-Image-URL")
-        (mh-x-image-set-download-state cache-filename 'try-again))
-       ;; Scale fetched image
-       ((and (funcall mh-x-image-scaling-function temp-file cache-filename)
-             nil))
-       ;; Attempt to display image if we have it
-       ((file-exists-p cache-filename)
-        (mh-x-image-display cache-filename marker))
-       ;; We didn't find the image. Should we try to display it the next time?
-       (t (mh-x-image-set-download-state cache-filename 'try-again)))
-      (ignore-errors
-        (set-marker marker nil)
-        (delete-process process)
-        (kill-buffer wget-buffer)
-        (delete-file temp-file)))))
-
-(defun mh-x-image-url-sane-p (url)
-  "Check if URL is something sensible."
-  (let ((len (length url)))
-    (cond ((< len 5) nil)
-          ((not (equal (substring url 0 5) "http:")) nil)
-          ((> len 100) nil)
-          (t t))))
-
-(defun mh-x-image-url-display (url)
-  "Display image from location URL.
-If the URL isn't present in the cache then it is fetched with wget."
-  (let* ((cache-filename (mh-x-image-url-cache-canonicalize url))
-         (state (mh-x-image-get-download-state cache-filename))
-         (marker (set-marker (make-marker) (point))))
-    (set (make-local-variable 'mh-x-image-marker) marker)
-    (cond ((not (mh-x-image-url-sane-p url)))
-          ((eq state 'ok)
-           (mh-x-image-display cache-filename marker))
-          ((or (not mh-wget-executable)
-               (eq mh-x-image-scaling-function 'ignore)))
-          ((eq state 'never))
-          ((not mh-fetch-x-image-url)
-           (set-marker marker nil))
-          ((eq state 'try-again)
-           (mh-x-image-set-download-state cache-filename nil)
-           (mh-x-image-url-fetch-image url cache-filename marker
-                                       'mh-x-image-scale-and-display))
-          ((and (eq mh-fetch-x-image-url 'ask)
-                (not (y-or-n-p (format "Fetch %s? " url))))
-           (mh-x-image-set-download-state cache-filename 'never))
-          ((eq state nil)
-           (mh-x-image-url-fetch-image url cache-filename marker
-                                       'mh-x-image-scale-and-display)))))
+(add-to-list 'debug-ignored-errors "^Cursor not pointing to message$")
 
 
 
-(defun mh-maybe-show (&optional msg)
-  "Display message at cursor, but only if in show mode.
-If optional arg MSG is non-nil, display that message instead."
-  (if mh-showing-mode (mh-show msg)))
-
-(defun mh-show (&optional message redisplay-flag)
-  "Display message\\<mh-folder-mode-map>.
-
-If the message under the cursor is already displayed, this command
-scrolls to the beginning of the message. MH-E normally hides a lot of
-the superfluous header fields that mailers add to a message, but if
-you wish to see all of them, use the command \\[mh-header-display].
-
-Two hooks can be used to control how messages are displayed. The
-first hook, `mh-show-mode-hook', is called early on in the
-process of the message display. It is usually used to perform
-some action on the message's content. The second hook,
-`mh-show-hook', is the last thing called after messages are
-displayed. It's used to affect the behavior of MH-E in general or
-when `mh-show-mode-hook' is too early.
-
-From a program, optional argument MESSAGE can be used to display an
-alternative message. The optional argument REDISPLAY-FLAG forces the
-redisplay of the message even if the show buffer was already
-displaying the correct message.
-
-See the \"mh-show\" customization group for a litany of options that
-control what displayed messages look like."
-  (interactive (list nil t))
-  (when (or redisplay-flag
-            (and mh-showing-with-headers
-                 (or mh-mhl-format-file mh-clean-message-header-flag)))
-    (mh-invalidate-show-buffer))
-  (mh-show-msg message))
-
-(defun mh-show-mouse (event)
-  "Move point to mouse EVENT and show message."
-  (interactive "e")
-  (mouse-set-point event)
-  (mh-show))
-
-(defun mh-summary-height ()
-  "Return ideal value for the variable `mh-summary-height'.
-The current frame height is taken into consideration."
-  (or (and (fboundp 'frame-height)
-           (> (frame-height) 24)
-           (min 10 (/ (frame-height) 6)))
-      4))
-
-(defun mh-show-msg (msg)
-  "Show MSG.
-
-The hook `mh-show-hook' is called after the message has been
-displayed."
-  (if (not msg)
-      (setq msg (mh-get-msg-num t)))
-  (mh-showing-mode t)
-  (setq mh-page-to-next-msg-flag nil)
-  (let ((folder mh-current-folder)
-        (folders (list mh-current-folder))
-        (clean-message-header mh-clean-message-header-flag)
-        (show-window (get-buffer-window mh-show-buffer))
-        (display-mime-buttons-flag mh-display-buttons-for-inline-parts-flag))
-    (if (not (eq (next-window (minibuffer-window)) (selected-window)))
-        (delete-other-windows))         ; force ourself to the top window
-    (mh-in-show-buffer (mh-show-buffer)
-      (setq mh-display-buttons-for-inline-parts-flag display-mime-buttons-flag)
-      (if (and show-window
-               (equal (mh-msg-filename msg folder) buffer-file-name))
-          (progn                        ;just back up to start
-            (goto-char (point-min))
-            (if (not clean-message-header)
-                (mh-start-of-uncleaned-message)))
-        (mh-display-msg msg folder)))
-    (if (not (= (1+ (window-height)) (frame-height))) ;not horizontally split
-        (shrink-window (- (window-height) (or mh-summary-height
-                                              (mh-summary-height)))))
-    (mh-recenter nil)
-    ;; The following line is a nop which forces update of the scan line so
-    ;; that font-lock will update it (if needed)...
-    (mh-notate nil nil mh-cmd-note)
-    (if (not (memq msg mh-seen-list))
-        (setq mh-seen-list (cons msg mh-seen-list)))
-    (when mh-update-sequences-after-mh-show-flag
-      (mh-update-sequences)
-      (when mh-index-data
-        (setq folders
-              (append (mh-index-delete-from-sequence mh-unseen-seq (list msg))
-                      folders)))
-      (when (mh-speed-flists-active-p)
-        (apply #'mh-speed-flists t folders)))
-    (run-hooks 'mh-show-hook)))
-
-(defun mh-modify (&optional message)
-  "Edit message.
-
-There are times when you need to edit a message. For example, you
-may need to fix a broken Content-Type header field. You can do
-this with this command. It displays the raw message in an
-editable buffer. When you are done editing, save and kill the
-buffer as you would any other.
-
-From a program, edit MESSAGE; nil means edit current message."
-  (interactive)
-  (let* ((message (or message (mh-get-msg-num t)))
-         (msg-filename (mh-msg-filename message))
-         edit-buffer)
-    (when (not (file-exists-p msg-filename))
-      (error "Message %d does not exist" message))
-
-    ;; Invalidate the show buffer if it is showing the same message that is
-    ;; to be edited.
-    (when (and (buffer-live-p (get-buffer mh-show-buffer))
-               (equal (save-excursion (set-buffer mh-show-buffer)
-                                      buffer-file-name)
-                      msg-filename))
-      (mh-invalidate-show-buffer))
-
-    ;; Edit message
-    (find-file msg-filename)
-    (setq edit-buffer (current-buffer))
-
-    ;; Set buffer properties
-    (mh-letter-mode)
-    (use-local-map text-mode-map)
-
-    ;; Just show the edit buffer...
-    (delete-other-windows)
-    (switch-to-buffer edit-buffer)))
-
-(defun mh-show-unquote-From ()
-  "Decode >From at beginning of lines for `mh-show-mode'."
-  (save-excursion
-    (let ((modified (buffer-modified-p))
-          (case-fold-search nil)
-          (buffer-read-only nil))
-      (goto-char (mh-mail-header-end))
-      (while (re-search-forward "^>From" nil t)
-        (replace-match "From"))
-      (set-buffer-modified-p modified))))
-
-(defun mh-msg-folder (folder-name)
-  "Return the name of the buffer for FOLDER-NAME."
-  folder-name)
-
-(defun mh-display-msg (msg-num folder-name)
-  "Display MSG-NUM of FOLDER-NAME.
-Sets the current buffer to the show buffer."
-  (let ((folder (mh-msg-folder folder-name)))
-    (set-buffer folder)
-    ;; When Gnus uses external displayers it has to keep handles longer. So
-    ;; we will delete these handles when mh-quit is called on the folder. It
-    ;; would be nicer if there are weak pointers in emacs lisp, then we could
-    ;; get the garbage collector to do this for us.
-    (unless (mh-buffer-data)
-      (setf (mh-buffer-data) (mh-make-buffer-data)))
-    ;; Bind variables in folder buffer in case they are local
-    (let ((formfile mh-mhl-format-file)
-          (clean-message-header mh-clean-message-header-flag)
-          (invisible-headers mh-invisible-header-fields-compiled)
-          (visible-headers nil)
-          (msg-filename (mh-msg-filename msg-num folder-name))
-          (show-buffer mh-show-buffer)
-          (mm-inline-media-tests mh-mm-inline-media-tests))
-      (if (not (file-exists-p msg-filename))
-          (error "Message %d does not exist" msg-num))
-      (if (and (> mh-show-maximum-size 0)
-               (> (elt (file-attributes msg-filename) 7)
-                  mh-show-maximum-size)
-               (not (y-or-n-p
-                     (format
-                      "Message %d (%d bytes) exceeds %d bytes. Display it? "
-                      msg-num (elt (file-attributes msg-filename) 7)
-                      mh-show-maximum-size))))
-          (error "Message %d not displayed" msg-num))
-      (set-buffer show-buffer)
-      (cond ((not (equal msg-filename buffer-file-name))
-             (mh-unvisit-file)
-             (setq buffer-read-only nil)
-             ;; Cleanup old mime handles
-             (mh-mime-cleanup)
-             (erase-buffer)
-             ;; Changing contents, so this hook needs to be reinitialized.
-             ;; pgp.el uses this.
-             (if (boundp 'write-contents-hooks) ;Emacs 19
-                 (kill-local-variable 'write-contents-hooks))
-             (if formfile
-                 (mh-exec-lib-cmd-output "mhl" "-nobell" "-noclear"
-                                         (if (stringp formfile)
-                                             (list "-form" formfile))
-                                         msg-filename)
-               (insert-file-contents-literally msg-filename))
-             ;; Use mm to display buffer
-             (when (and mh-decode-mime-flag (not formfile))
-               (mh-add-missing-mime-version-header)
-               (setf (mh-buffer-data) (mh-make-buffer-data))
-               (mh-mime-display))
-             (mh-show-mode)
-             ;; Header cleanup
-             (goto-char (point-min))
-             (cond (clean-message-header
-                    (mh-clean-msg-header (point-min)
-                                         invisible-headers
-                                         visible-headers)
-                    (goto-char (point-min)))
-                   (t
-                    (mh-start-of-uncleaned-message)))
-             (mh-decode-message-header)
-             ;; the parts of visiting we want to do (no locking)
-             (or (eq buffer-undo-list t) ;don't save undo info for prev msgs
-                 (setq buffer-undo-list nil))
-             (set-buffer-auto-saved)
-             ;; the parts of set-visited-file-name we want to do (no locking)
-             (setq buffer-file-name msg-filename)
-             (setq buffer-backed-up nil)
-             (auto-save-mode 1)
-             (set-mark nil)
-             (unwind-protect
-                 (when (and mh-decode-mime-flag (not formfile))
-                   (setq buffer-read-only nil)
-                   (mh-display-smileys)
-                   (mh-display-emphasis))
-               (setq buffer-read-only t))
-             (set-buffer-modified-p nil)
-             (setq mh-show-folder-buffer folder)
-             (setq mode-line-buffer-identification
-                   (list (format mh-show-buffer-mode-line-buffer-id
-                                 folder-name msg-num)))
-             (mh-logo-display)
-             (set-buffer folder)
-             (setq mh-showing-with-headers nil))))))
-
-(defun mh-clean-msg-header (start invisible-headers visible-headers)
-  "Flush extraneous lines in message header.
-
-Header is cleaned from START to the end of the message header.
-INVISIBLE-HEADERS contains a regular expression specifying lines
-to delete from the header. VISIBLE-HEADERS contains a regular
-expression specifying the lines to display. INVISIBLE-HEADERS is
-ignored if VISIBLE-HEADERS is non-nil."
-  ;; XXX Note that MH-E no longer supports the `mh-visible-headers'
-  ;; variable, so this function could be trimmed of this feature too."
-  (let ((case-fold-search t)
-        (buffer-read-only nil))
-    (save-restriction
-      (goto-char start)
-      (if (search-forward "\n\n" nil 'move)
-          (backward-char 1))
-      (narrow-to-region start (point))
-      (goto-char (point-min))
-      (if visible-headers
-          (while (< (point) (point-max))
-            (cond ((looking-at visible-headers)
-                   (forward-line 1)
-                   (while (looking-at "[ \t]") (forward-line 1)))
-                  (t
-                   (mh-delete-line 1)
-                   (while (looking-at "[ \t]")
-                     (mh-delete-line 1)))))
-        (while (re-search-forward invisible-headers nil t)
-          (beginning-of-line)
-          (mh-delete-line 1)
-          (while (looking-at "[ \t]")
-            (mh-delete-line 1)))))
-    (let ((mh-compose-skipped-header-fields ()))
-      (mh-letter-hide-all-skipped-fields))
-    (unlock-buffer)))
-
-(defun mh-delete-line (lines)
-  "Delete the next LINES lines."
-  (delete-region (point) (progn (forward-line lines) (point))))
-
-(defun mh-notate (msg notation offset)
-  "Mark MSG with the character NOTATION at position OFFSET.
-Null MSG means the message at cursor.
-If NOTATION is nil then no change in the buffer occurs."
-  (save-excursion
-    (if (or (null msg)
-            (mh-goto-msg msg t t))
-        (with-mh-folder-updating (t)
-          (beginning-of-line)
-          (forward-char offset)
-          (let* ((change-stack-flag
-                  (and (equal offset
-                              (+ mh-cmd-note mh-scan-field-destination-offset))
-                       (not (eq notation mh-note-seq))))
-                 (msg (and change-stack-flag (or msg (mh-get-msg-num nil))))
-                 (stack (and msg (gethash msg mh-sequence-notation-history)))
-                 (notation (or notation (char-after))))
-            (if stack
-                ;; The presence of the stack tells us that we don't need to
-                ;; notate the message, since the notation would be replaced
-                ;; by a sequence notation. So we will just put the notation
-                ;; at the bottom of the stack. If the sequence is deleted,
-                ;; the correct notation will be shown.
-                (setf (gethash msg mh-sequence-notation-history)
-                      (reverse (cons notation (cdr (reverse stack)))))
-              ;; Since we don't have any sequence notations in the way, just
-              ;; notate the scan line.
-              (delete-char 1)
-              (insert notation))
-            (when change-stack-flag
-              (mh-thread-update-scan-line-map msg notation offset)))))))
-
-(defun mh-goto-msg (number &optional no-error-if-no-message dont-show)
-  "Go to a message\\<mh-folder-mode-map>.
-
-You can enter the message NUMBER either before or after typing
-\\[mh-goto-msg]. In the latter case, Emacs prompts you.
-
-In a program, optional non-nil second argument NO-ERROR-IF-NO-MESSAGE
-means return nil instead of signaling an error if message does not
-exist\; in this case, the cursor is positioned near where the message
-would have been. Non-nil third argument DONT-SHOW means not to show
-the message."
-  (interactive "NGo to message: ")
-  (setq number (prefix-numeric-value number))
-  (let ((point (point))
-        (return-value t))
-    (goto-char (point-min))
-    (unless (re-search-forward (format mh-scan-msg-search-regexp number) nil t)
-      (goto-char point)
-      (unless no-error-if-no-message
-        (error "No message %d" number))
-      (setq return-value nil))
-    (beginning-of-line)
-    (or dont-show (not return-value) (mh-maybe-show number))
-    return-value))
-
-(defun mh-set-folder-modified-p (flag)
-  "Mark current folder as modified or unmodified according to FLAG."
-  (set-buffer-modified-p flag))
-
-(defun mh-find-seq (name)
-  "Return sequence NAME."
-  (assoc name mh-seq-list))
-
-(defun mh-seq-to-msgs (seq)
-  "Return a list of the messages in SEQ."
-  (mh-seq-msgs (mh-find-seq seq)))
-
-(defun mh-update-scan-format (fmt width)
-  "Return a scan format with the (msg) width in the FMT replaced with WIDTH.
-
-The message number width portion of the format is discovered
-using `mh-scan-msg-format-regexp'. Its replacement is controlled
-with `mh-scan-msg-format-string'."
-  (or (and
-       (string-match mh-scan-msg-format-regexp fmt)
-       (let ((begin (match-beginning 1))
-             (end (match-end 1)))
-         (concat (substring fmt 0 begin)
-                 (format mh-scan-msg-format-string width)
-                 (substring fmt end))))
-      fmt))
-
-(defun mh-msg-num-width (folder)
-  "Return the width of the largest message number in this FOLDER."
-  (or mh-progs (mh-find-path))
-  (let ((tmp-buffer (get-buffer-create mh-temp-buffer))
-        (width 0))
-    (save-excursion
-      (set-buffer tmp-buffer)
-      (erase-buffer)
-      (apply 'call-process
-             (expand-file-name mh-scan-prog mh-progs) nil '(t nil) nil
-             (list folder "last" "-format" "%(msg)"))
-      (goto-char (point-min))
-      (if (re-search-forward mh-scan-msg-number-regexp nil 0 1)
-          (setq width (length (buffer-substring
-                               (match-beginning 1) (match-end 1))))))
-    width))
-
-(defun mh-add-msgs-to-seq (msgs seq &optional internal-flag dont-annotate-flag)
-  "Add MSGS to SEQ.
-
-Remove duplicates and keep sequence sorted. If optional
-INTERNAL-FLAG is non-nil, do not mark the message in the scan
-listing or inform MH of the addition.
-
-If DONT-ANNOTATE-FLAG is non-nil then the annotations in the
-folder buffer are not updated."
-  (let ((entry (mh-find-seq seq))
-        (internal-seq-flag (mh-internal-seq seq)))
-    (if (and msgs (atom msgs)) (setq msgs (list msgs)))
-    (if (null entry)
-        (setq mh-seq-list
-              (cons (mh-make-seq seq (mh-canonicalize-sequence msgs))
-                    mh-seq-list))
-      (if msgs (setcdr entry (mh-canonicalize-sequence
-                              (append msgs (mh-seq-msgs entry))))))
-    (unless internal-flag
-      (mh-add-to-sequence seq msgs)
-      (when (not dont-annotate-flag)
-        (mh-iterate-on-range msg msgs
-          (unless (memq msg (cdr entry))
-            (mh-add-sequence-notation msg internal-seq-flag)))))))
-
-(defun mh-canonicalize-sequence (msgs)
-  "Sort MSGS in decreasing order and remove duplicates."
-  (let* ((sorted-msgs (sort (copy-sequence msgs) '>))
-         (head sorted-msgs))
-    (while (cdr head)
-      (if (= (car head) (cadr head))
-          (setcdr head (cddr head))
-        (setq head (cdr head))))
-    sorted-msgs))
+;;; Folder Cache and Access
 
 (defvar mh-sub-folders-cache (make-hash-table :test #'equal))
 (defvar mh-current-folder-name nil)
 (defvar mh-flists-partial-line "")
 (defvar mh-flists-process nil)
 
+;;;###mh-autoload
+(defun mh-clear-sub-folders-cache ()
+  "Clear `mh-sub-folders-cache'."
+  (clrhash mh-sub-folders-cache))
+
 ;; Initialize mh-sub-folders-cache...
 (defun mh-collect-folder-names ()
   "Collect folder names by running \"folders\"."
@@ -2050,17 +392,17 @@
 PROCESS is the flists process that was run to collect folder
 names and the function is called when OUTPUT is available."
   (let ((position 0)
-       (prevailing-match-data (match-data))
-       line-end folder)
+        (prevailing-match-data (match-data))
+        line-end folder)
     (unwind-protect
-       (while (setq line-end (string-match "\n" output position))
-         (setq folder (format "+%s%s"
+        (while (setq line-end (string-match "\n" output position))
+          (setq folder (format "+%s%s"
                                mh-flists-partial-line
                                (substring output position line-end)))
-         (setq mh-flists-partial-line "")
+          (setq mh-flists-partial-line "")
           (unless (equal (aref folder 1) ?.)
             (mh-populate-sub-folders-cache folder))
-         (setq position (1+ line-end)))
+          (setq position (1+ line-end)))
       (set-match-data prevailing-match-data))
     (setq mh-flists-partial-line (substring output position))))
 
@@ -2148,6 +490,7 @@
        t
      nil))
 
+;;;###mh-autoload
 (defun mh-folder-list (folder)
   "Return FOLDER and its descendents.
 Returns a list of strings. For example,
@@ -2176,6 +519,7 @@
                             (mh-folder-list (concat folder (car f)))))))
     folder-list))
 
+;;;###mh-autoload
 (defun mh-sub-folders (folder &optional add-trailing-slash-flag)
   "Find the subfolders of FOLDER.
 The function avoids running folders unnecessarily by caching the
@@ -2244,6 +588,7 @@
                               results))))
     results))
 
+;;;###mh-autoload
 (defun mh-remove-from-sub-folders-cache (folder)
   "Remove FOLDER and its parent from `mh-sub-folders-cache'.
 FOLDER should be unconditionally removed from the cache. Also the
@@ -2269,12 +614,33 @@
             (setq one-ancestor-found t))))
       (remhash nil mh-sub-folders-cache))))
 
+
+
+;;; Folder Utilities
+
+;;;###mh-autoload
+(defun mh-folder-name-p (name)
+  "Return non-nil if NAME is the name of a folder.
+A name (a string or symbol) can be a folder name if it begins
+with \"+\"."
+  (if (symbolp name)
+      (eq (aref (symbol-name name) 0) ?+)
+    (and (> (length name) 0)
+         (eq (aref name 0) ?+))))
+
+;;;###mh-autoload
+(defun mh-expand-file-name (filename &optional default)
+  "Expand FILENAME like `expand-file-name', but also handle MH folder names.
+Any filename that starts with '+' is treated as a folder name.
+See `expand-file-name' for description of DEFAULT."
+  (if (mh-folder-name-p filename)
+      (expand-file-name (substring filename 1) mh-user-path)
+    (expand-file-name filename default)))
+
 (defvar mh-folder-hist nil)
 
 ;; Shush compiler.
-(eval-when-compile
-  (defvar mh-speed-folder-map)
-  (defvar mh-speed-flists-cache))
+(eval-when-compile (defvar mh-speed-flists-cache))
 
 (defvar mh-allow-root-folder-flag nil
   "Non-nil means \"+\" is an acceptable folder name.
@@ -2289,12 +655,14 @@
 
 (defvar mh-speed-flists-inhibit-flag nil)
 
+;;;###mh-autoload
 (defun mh-speed-flists-active-p ()
   "Check if speedbar is running with message counts enabled."
   (and (featurep 'mh-speed)
        (not mh-speed-flists-inhibit-flag)
        (> (hash-table-count mh-speed-flists-cache) 0)))
 
+;;;###mh-autoload
 (defun mh-folder-completion-function (name predicate flag)
   "Programmable completion for folder names.
 NAME is the partial folder name that has been input. PREDICATE if
@@ -2332,6 +700,12 @@
                    ((equal path mh-user-path) nil)
                    (t (file-exists-p path))))))))
 
+;; Shush compiler.
+(eval-when-compile
+  (mh-do-in-xemacs
+    (defvar completion-root-regexp)
+    (defvar minibuffer-completing-file-name)))
+
 (defun mh-folder-completing-read (prompt default allow-root-folder-flag)
   "Read folder name with PROMPT and default result DEFAULT.
 If ALLOW-ROOT-FOLDER-FLAG is non-nil then \"+\" is allowed to be
@@ -2345,6 +719,7 @@
                       'mh-folder-hist default))
    t))
 
+;;;###mh-autoload
 (defun mh-prompt-for-folder (prompt default can-create
                              &optional default-string allow-root-folder-flag)
   "Prompt for a folder name with PROMPT.
@@ -2408,37 +783,90 @@
 
 
 
-;;; List and string manipulation
+;;; Message Utilities
 
-(defun mh-list-to-string (l)
-  "Flatten the list L and make every element of the new list into a string."
-  (nreverse (mh-list-to-string-1 l)))
-
-(defun mh-list-to-string-1 (l)
-  "Flatten the list L and make every element of the new list into a string."
-  (let ((new-list nil))
-    (while l
-      (cond ((null (car l)))
-            ((symbolp (car l))
-             (setq new-list (cons (symbol-name (car l)) new-list)))
-            ((numberp (car l))
-             (setq new-list (cons (int-to-string (car l)) new-list)))
-            ((equal (car l) ""))
-            ((stringp (car l)) (setq new-list (cons (car l) new-list)))
-            ((listp (car l))
-             (setq new-list (nconc (mh-list-to-string-1 (car l))
-                                   new-list)))
-            (t (error "Bad element in `mh-list-to-string': %s" (car l))))
-      (setq l (cdr l)))
-    new-list))
+;; Functions that would ordinarily be in mh-letter.el that are needed
+;; by mh-show.el are found here in order to prevent the loading of
+;; mh-letter.el until a message is actually composed.
 
-(defun mh-replace-string (old new)
-  "Replace all occurrences of OLD with NEW in the current buffer.
-Ignores case when searching for OLD."
+;;;###mh-autoload
+(defun mh-in-header-p ()
+  "Return non-nil if the point is in the header of a draft message."
+  (< (point) (mh-mail-header-end)))
+
+;;;###mh-autoload
+(defun mh-extract-from-header-value ()
+  "Extract From: string from header."
+  (save-excursion
+    (if (not (mh-goto-header-field "From:"))
+        nil
+      (skip-chars-forward " \t")
+      (buffer-substring-no-properties
+       (point) (progn (mh-header-field-end)(point))))))
+
+;;;###mh-autoload
+(defun mh-goto-header-field (field)
+  "Move to FIELD in the message header.
+Move to the end of the FIELD name, which should end in a colon.
+Returns t if found, nil if not."
   (goto-char (point-min))
-  (let ((case-fold-search t))
-    (while (search-forward old nil t)
-      (replace-match new t t))))
+  (let ((case-fold-search t)
+        (headers-end (save-excursion
+                       (mh-goto-header-end 0)
+                       (point))))
+    (re-search-forward (format "^%s" field) headers-end t)))
+
+;;;###mh-autoload
+(defun mh-goto-header-end (arg)
+  "Move the cursor ARG lines after the header."
+  (if (re-search-forward "^-*$" nil nil)
+      (forward-line arg)))
+
+;;;###mh-autoload
+(defun mh-mail-header-end ()
+  "Substitute for `mail-header-end' that doesn't widen the buffer.
+
+In MH-E we frequently need to find the end of headers in nested
+messages, where the buffer has been narrowed. This function works
+in this situation."
+  (save-excursion
+    ;; XXX: The following replaces a call to rfc822-goto-eoh. Occasionally,
+    ;; mail headers that MH-E has to read contains lines of the form:
+    ;;    From address@hidden Mon May 10 11:48:07 2004
+    ;; In this situation, rfc822-goto-eoh doesn't go to the end of the
+    ;; header. The replacement allows From_ lines in the mail header.
+    (goto-char (point-min))
+    (loop for p = (re-search-forward
+                   "^\\([:\n]\\|[^: \t\n]+[ \t\n]\\)" nil 'move)
+          do (cond ((null p) (return))
+                   (t (goto-char (match-beginning 0))
+                      (unless (looking-at "From ") (return))
+                      (goto-char p))))
+    (point)))
+
+;;;###mh-autoload
+(defun mh-header-field-beginning ()
+  "Move to the beginning of the current header field.
+Handles RFC 822 continuation lines."
+  (beginning-of-line)
+  (while (looking-at "^[ \t]")
+    (forward-line -1)))
+
+;;;###mh-autoload
+(defun mh-header-field-end ()
+  "Move to the end of the current header field.
+Handles RFC 822 continuation lines."
+  (forward-line 1)
+  (while (looking-at "^[ \t]")
+    (forward-line 1))
+  (backward-char 1))                    ;to end of previous line
+
+;;;###mh-autoload
+(defun mh-signature-separator-p ()
+  "Return non-nil if buffer includes \"^-- $\"."
+  (save-excursion
+    (goto-char (point-min))
+    (re-search-forward mh-signature-separator-regexp nil t)))
 
 (provide 'mh-utils)
 




reply via email to

[Prev in Thread] Current Thread [Next in Thread]