summaryrefslogtreecommitdiff
path: root/lisp/mh-e/mh-folder.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/mh-e/mh-folder.el')
-rw-r--r--lisp/mh-e/mh-folder.el1989
1 files changed, 1989 insertions, 0 deletions
diff --git a/lisp/mh-e/mh-folder.el b/lisp/mh-e/mh-folder.el
new file mode 100644
index 00000000000..c2bb229bde1
--- /dev/null
+++ b/lisp/mh-e/mh-folder.el
@@ -0,0 +1,1989 @@
+;;; mh-folder.el --- MH-Folder mode
+
+;; Copyright (C) 2002, 2003, 2005, 2006 Free Software Foundation, Inc.
+
+;; Author: Bill Wohler <wohler@newt.com>
+;; Maintainer: Bill Wohler <wohler@newt.com>
+;; Keywords: mail
+;; See: mh-e.el
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING. If not, write to the
+;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
+
+;;; Commentary:
+
+;; Mode for browsing folders
+
+;;; Change Log:
+
+;;; Code:
+
+(require 'mh-e)
+(require 'mh-scan)
+(mh-require-cl)
+
+;; Dynamically-created function not found in mh-loaddefs.el.
+(autoload 'mh-tool-bar-folder-buttons-init "mh-tool-bar")
+
+(require 'gnus-util)
+(autoload 'message-fetch-field "message")
+
+
+
+;;; MH-E Entry Points
+
+;;;###autoload
+(defun mh-rmail (&optional arg)
+ "Incorporate new mail with MH.
+Scan an MH folder if ARG is non-nil.
+
+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)))
+
+;;;###autoload
+(defun mh-nmail (&optional arg)
+ "Check for new mail in inbox folder.
+Scan an MH folder if ARG is non-nil.
+
+This function is an entry point to MH-E, the Emacs 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)))
+
+
+;;; Desktop Integration
+
+;; 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-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))
+
+
+
+;;; Variables
+
+(defvar mh-folder-filename nil
+ "Full path of directory for this folder.")
+
+(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.")
+
+(defvar mh-last-destination nil
+ "Destination of last refile or write command.")
+
+(defvar mh-last-destination-folder nil
+ "Destination of last refile command.")
+
+(defvar mh-last-destination-write nil
+ "Destination of last write command.")
+
+(defvar mh-first-msg-num nil
+ "Number of first message in buffer.")
+
+(defvar mh-last-msg-num nil
+ "Number of last msg in buffer.")
+
+(defvar mh-msg-count nil
+ "Number of msgs in buffer.")
+
+
+
+;;; 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]))
+
+;;; 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 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]))
+
+
+
+;;; MH-Folder Keys
+
+(suppress-keymap mh-folder-mode-map)
+
+;; 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
+
+
+
+;;; MH-Folder 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-folder-mode-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.
+See `mh-set-help'.")
+
+
+
+;;; MH-Folder Font Lock
+
+(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.")
+
+(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))
+
+;; Fontify unseen messages 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)
+
+
+
+;;; MH-Folder Mode
+
+(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...
+(require 'which-func nil t)
+(when (boundp 'which-func-modes)
+ (add-to-list 'which-func-modes 'mh-folder-mode))
+
+;; Shush compiler.
+(eval-when-compile
+ (defvar desktop-save-buffer)
+ (defvar font-lock-auto-fontify)
+ (mh-do-in-xemacs (defvar font-lock-defaults)))
+
+(defvar mh-folder-buttons-init-flag nil)
+
+;; Ensure new buffers won't get this mode if default-major-mode is nil.
+(put 'mh-folder-mode 'mode-class 'special)
+
+;; 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>
+
+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)
+ (mh-inc-spool-make)
+ (set (make-local-variable 'tool-bar-map) mh-folder-tool-bar-map)
+ (mh-funcall-if-exists mh-tool-bar-init :folder)
+ (mh-set-help mh-folder-mode-help-messages)
+ (if (and mh-xemacs-flag
+ font-lock-auto-fontify)
+ (turn-on-font-lock))) ; Force font-lock in XEmacs.
+
+
+
+;;; MH-Folder Commands
+
+;; Alphabetical.
+;; See also mh-comp.el, mh-junk.el, mh-mime.el, mh-print.el,
+;; mh-search.el, and mh-seq.el.
+
+;;;###mh-autoload
+(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)))
+
+;;;###mh-autoload
+(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)))
+
+;;;###mh-autoload
+(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
+
+;;;###mh-autoload
+(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)))
+
+;;;###mh-autoload
+(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))
+
+;;;###mh-autoload
+(defun mh-inc-folder (&optional file folder)
+ "Incorporate new mail into a folder.
+
+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)))
+
+;;;###mh-autoload
+(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))
+
+;;;###mh-autoload
+(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)))
+
+;;;###mh-autoload
+(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)))
+
+;;;###mh-autoload
+(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)))))
+
+;;;###mh-autoload
+(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"))))))
+
+;;;###mh-autoload
+(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)))
+
+;;;###mh-autoload
+(defun mh-prev-button ()
+ "Go to the previous button.
+
+If the beginning of the buffer is reached then the search wraps
+over to the end of the buffer."
+ (interactive)
+ (mh-next-button t))
+
+;;;###mh-autoload
+(defun mh-previous-page (&optional lines)
+ "Display next page in message.
+
+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)))
+
+;;;###mh-autoload
+(defun mh-previous-undeleted-msg (&optional count wait-after-complaining-flag)
+ "Display previous 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 '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)))))
+
+;;;###mh-autoload
+(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"))))))
+
+;;;###mh-autoload
+(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))
+
+;;;###mh-autoload
+(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)))
+
+;;;###mh-autoload
+(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))))
+
+;;;###mh-autoload
+(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-show-mouse (event)
+ "Move point to mouse EVENT and show message."
+ (interactive "e")
+ (mouse-set-point event)
+ (mh-show))
+
+;;;###mh-autoload
+(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)))
+
+;;;###mh-autoload
+(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)))
+
+;;;###mh-autoload
+(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)
+
+;;;###mh-autoload
+(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))))
+
+;;;###mh-autoload
+(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-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-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."
+ (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
+ (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)))))
+
+;;;###mh-autoload
+(defun mh-goto-cur-msg (&optional minimal-changes-flag)
+ "Position the cursor at the current message.
+When optional argument MINIMAL-CHANGES-FLAG is non-nil, the
+function doesn't 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)))
+ (t
+ (setq overlay-arrow-position nil)
+ (message "No current message")))))
+
+;;;###mh-autoload
+(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))))))
+
+(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-autoload
+(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)))
+
+;;;###mh-autoload
+(defun mh-set-folder-modified-p (flag)
+ "Mark current folder as modified or unmodified according to FLAG."
+ (set-buffer-modified-p flag))
+
+(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-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)))))
+
+(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)))
+
+;;;###mh-autoload
+(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))))
+
+;;;###mh-autoload
+(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)))
+
+;;;###mh-autoload
+(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))
+
+;;;###mh-autoload
+(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)))
+
+;;;###mh-autoload
+(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-make-folder (name)
+ "Create a new mail folder called NAME.
+Make it the current folder."
+ (switch-to-buffer name)
+ (setq buffer-read-only nil)
+ (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))
+
+;;;###mh-autoload
+(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)))
+
+;;;###mh-autoload
+(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))
+
+;;;###mh-autoload
+(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))))
+
+;;;###mh-autoload
+(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))))
+
+;;;###mh-autoload
+(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-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)))
+
+;;;###mh-autoload
+(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)))
+
+(provide 'mh-folder)
+
+;; Local Variables:
+;; indent-tabs-mode: nil
+;; sentence-end-double-space: nil
+;; End:
+
+;;; mh-folder.el ends here