Upgraded to MH-E version 7.0.
[bpt/emacs.git] / lisp / mail / mh-e.el
CommitLineData
c26cf6c8
RS
1;;; mh-e.el --- GNU Emacs interface to the MH mail system
2
a1b4049d 3;; Copyright (C) 1985,86,87,88,90,92,93,94,95,97,2000,2001,2002 Free Software Foundation, Inc.
c26cf6c8 4
a1b4049d 5;; Author: Bill Wohler <wohler@newt.com>
6e65a812 6;; Maintainer: Bill Wohler <wohler@newt.com>
bdcfe844 7;; Version: 7.0
c26cf6c8
RS
8;; Keywords: mail
9
60370d40 10;; This file is part of GNU Emacs.
9b7bc076
KH
11
12;; GNU Emacs is free software; you can redistribute it and/or modify
c26cf6c8
RS
13;; it under the terms of the GNU General Public License as published by
14;; the Free Software Foundation; either version 2, or (at your option)
15;; any later version.
16
9b7bc076 17;; GNU Emacs is distributed in the hope that it will be useful,
c26cf6c8
RS
18;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20;; GNU General Public License for more details.
21
22;; You should have received a copy of the GNU General Public License
b578f267
EN
23;; along with GNU Emacs; see the file COPYING. If not, write to the
24;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25;; Boston, MA 02111-1307, USA.
c26cf6c8
RS
26
27;;; Commentary:
28
a1b4049d
BW
29;; How to Use:
30;; M-x mh-rmail to read mail. Type C-h m there for a list of commands.
31;; C-u M-x mh-rmail to visit any folder.
32;; M-x mh-smail to send mail. From within the mail reader, "m" works, too.
b578f267 33
a1b4049d
BW
34;; Your .emacs might benefit from these bindings:
35;; (global-set-key "\C-cr" 'mh-rmail)
36;; (global-set-key "\C-xm" 'mh-smail)
37;; (global-set-key "\C-x4m" 'mh-smail-other-window)
b578f267 38
a1b4049d 39;; MH (Message Handler) is a powerful mail reader.
b578f267 40
a1b4049d
BW
41;; The MH newsgroup is comp.mail.mh; the mailing list is mh-users@ics.uci.edu
42;; (send to mh-users-request to be added). See the monthly Frequently Asked
bdcfe844 43;; Questions posting there for information on getting MH and MH-E:
a1b4049d 44;; http://www.faqs.org/faqs/mail/mh-faq/part1/preamble.html
b578f267 45
a1b4049d 46;; N.B. MH must have been compiled with the MHE compiler flag or several
bdcfe844 47;; features necessary for MH-E will be missing from MH commands, specifically
b578f267
EN
48;; the -build switch to repl and forw.
49
bdcfe844 50;; MH-E is an Emacs interface to the MH mail system.
a1b4049d 51
bdcfe844 52;; MH-E is supported in GNU Emacs 20 and 21, with MH 6.8.4 and nmh 1.0.4.
a1b4049d
BW
53
54;; Mailing Lists:
55;; mh-e-users@lists.sourceforge.net
56;; mh-e-announce@lists.sourceforge.net
57;; mh-e-devel@lists.sourceforge.net
58;;
59;; Subscribe by sending a "subscribe" message to
60;; <list>-request@lists.sourceforge.net, or by using the web interface at
61;; https://sourceforge.net/mail/?group_id=13357
62
63;; Bug Reports:
64;; https://sourceforge.net/tracker/?group_id=13357&atid=113357
65;; Include the output of M-x mh-version in any bug report.
66
67;; Feature Requests:
68;; https://sourceforge.net/tracker/?atid=363357&group_id=13357&func=browse
69
70;; Support:
71;; https://sourceforge.net/tracker/?group_id=13357&atid=213357
b578f267 72
717e06e5 73;;; Change Log:
b578f267
EN
74
75;; Original version for Gosling emacs by Brian Reid, Stanford, 1982.
76;; Modified by James Larus, BBN, July 1984 and UCB, 1984 & 1985.
77;; Rewritten for GNU Emacs, James Larus 1985. larus@ginger.berkeley.edu
a1b4049d
BW
78;; Modified by Stephen Gildea 1988. gildea@lcs.mit.edu
79;; Maintenance picked up by Bill Wohler <wohler@newt.com> and the
80;; SourceForge Crew <http://mh-e.sourceforge.net/>. 2001.
81
bdcfe844 82;; $Id: mh-e.el,v 1.198 2002/11/29 15:33:37 wohler Exp $
c26cf6c8
RS
83
84;;; Code:
85
bdcfe844 86(require 'cl)
c26cf6c8 87(require 'mh-utils)
a1b4049d
BW
88(require 'gnus-util)
89(require 'easymenu)
bdcfe844 90(if mh-xemacs-flag
a1b4049d 91 (require 'mh-xemacs-compat))
a1b4049d 92
bdcfe844
BW
93;; Shush the byte-compiler
94(defvar font-lock-auto-fontify)
95(defvar font-lock-defaults)
96(defvar tool-bar-mode)
97
98(defconst mh-version "7.0" "Version number of MH-E.")
a1b4049d
BW
99
100;;; Initial Autoloads
bdcfe844
BW
101;;; The autoloads for mh-undo-folder, mh-widen and mh-reply are needed before
102;;; they are used to avoid compiler warnings.
103(autoload 'mh-undo-folder "mh-funcs"
104 "Undo all commands in current folder." t)
105(autoload 'mh-widen "mh-seq"
106 "Remove restrictions from current folder, thereby showing all messages." t)
107(autoload 'mh-reply "mh-comp"
108 "Reply to a MESSAGE (default: displayed message).
109If optional prefix argument INCLUDEP provided, then include the message
110in the reply using filter mhl.reply in your MH directory.
111Prompts for type of addresses to reply to:
112 from sender only,
113 to sender and primary recipients,
114 cc/all sender and all recipients.
115If the file named by `mh-repl-formfile' exists, it is used as a skeleton
116for the reply. See also documentation for `\\[mh-send]' function." t)
117(autoload 'mh-map-to-seq-msgs "mh-seq")
118(autoload 'mh-notate-seq "mh-seq")
119(autoload 'mh-destroy-postponed-handles "mh-mime")
120(autoload 'mh-press-button "mh-mime")
121(autoload 'mh-mime-save-part "mh-mime")
122(autoload 'mh-mime-inline-part "mh-mime")
123(autoload 'mh-mime-save-parts "mh-mime")
124(autoload 'mh-thread-inc "mh-seq")
125(autoload 'mh-thread-forget-message "mh-seq")
126(autoload 'mh-thread-add-spaces "mh-seq")
a1b4049d
BW
127
128(autoload 'Info-goto-node "info")
c26cf6c8
RS
129
130\f
bdcfe844 131
c26cf6c8
RS
132;;; Hooks:
133
abbc1a7a 134(defgroup mh nil
a1b4049d 135 "Emacs interface to the MH mail system."
abbc1a7a 136 :group 'mail)
c26cf6c8 137
abbc1a7a 138(defgroup mh-hook nil
bdcfe844 139 "Hooks to MH-E mode."
abbc1a7a
RS
140 :prefix "mh-"
141 :group 'mh)
c26cf6c8 142
abbc1a7a 143(defcustom mh-folder-mode-hook nil
bdcfe844 144 "Invoked in `mh-folder-mode' on a new folder."
abbc1a7a
RS
145 :type 'hook
146 :group 'mh-hook)
c26cf6c8 147
abbc1a7a
RS
148(defcustom mh-inc-folder-hook nil
149 "Invoked by \\<mh-folder-mode-map>`\\[mh-inc-folder]' after incorporating mail into a folder."
150 :type 'hook
151 :group 'mh-hook)
c26cf6c8 152
a1b4049d
BW
153(defcustom mh-folder-updated-hook nil
154 "Invoked when the folder actions (such as moves and deletes) are performed.
155Variables that are useful in this hook include `mh-delete-list' and
156`mh-refile-list' which can be used to see which changes are being made to
157current folder, `mh-current-folder'."
158 :type 'hook
159 :group 'mh-hook)
160
abbc1a7a
RS
161(defcustom mh-delete-msg-hook nil
162 "Invoked after marking each message for deletion."
163 :type 'hook
164 :group 'mh-hook)
165
166(defcustom mh-refile-msg-hook nil
167 "Invoked after marking each message for refiling."
168 :type 'hook
169 :group 'mh-hook)
170
bdcfe844
BW
171(defcustom mh-folder-list-change-hook nil
172 "Invoked whenever the cached folder list `mh-folder-list' is changed."
173 :type 'hook
174 :group 'mh-hook)
175
abbc1a7a 176(defcustom mh-before-quit-hook nil
bdcfe844 177 "Invoked by \\<mh-folder-mode-map>`\\[mh-quit]' before quitting MH-E.
a1b4049d 178See also `mh-quit-hook'."
abbc1a7a
RS
179 :type 'hook
180 :group 'mh-hook)
181
182(defcustom mh-quit-hook nil
bdcfe844 183 "Invoked after \\<mh-folder-mode-map>`\\[mh-quit]' quits MH-E.
a1b4049d 184See also `mh-before-quit-hook'."
abbc1a7a
RS
185 :type 'hook
186 :group 'mh-hook)
c26cf6c8 187
a1b4049d
BW
188(defcustom mh-unseen-updated-hook nil
189 "Invoked after the unseen sequence has been updated.
190The variable `mh-seen-list' can be used to obtain the list of messages which
191will be removed from the unseen sequence."
192 :type 'hook
193 :group 'mh-hook)
c26cf6c8
RS
194
195;;; Personal preferences:
196
abbc1a7a 197(defcustom mh-lpr-command-format "lpr -J '%s'"
c26cf6c8
RS
198 "*Format for Unix command that prints a message.
199The string should be a Unix command line, with the string '%s' where
200the job's name (folder and message number) should appear. The formatted
abbc1a7a
RS
201message text is piped to this command when you type \\<mh-folder-mode-map>`\\[mh-print-msg]'."
202 :type 'string
203 :group 'mh)
c26cf6c8 204
abbc1a7a 205(defcustom mh-scan-prog "scan"
c26cf6c8
RS
206 "*Program to run to generate one-line-per-message listing of a folder.
207Normally \"scan\" or a file name linked to scan. This file is searched
a1b4049d 208for relative to the mh-progs directory unless it is an absolute pathname."
abbc1a7a
RS
209 :type 'string
210 :group 'mh)
c26cf6c8
RS
211(make-variable-buffer-local 'mh-scan-prog)
212
abbc1a7a 213(defcustom mh-inc-prog "inc"
c26cf6c8
RS
214 "*Program to run to incorporate new mail into a folder.
215Normally \"inc\". This file is searched for relative to
abbc1a7a
RS
216the mh-progs directory unless it is an absolute pathname."
217 :type 'string
218 :group 'mh)
c26cf6c8 219
bdcfe844
BW
220(defcustom mh-print-background-flag nil
221 "*Non-nil means messages should be printed in the background.
c26cf6c8 222WARNING: do not delete the messages until printing is finished;
abbc1a7a
RS
223otherwise, your output may be truncated."
224 :type 'boolean
225 :group 'mh)
c26cf6c8 226
bdcfe844
BW
227(defcustom mh-recenter-summary-flag nil
228 "*Non-nil means to recenter the summary window.
229
230Recenter the summary window when the show window is toggled off if non-nil."
abbc1a7a
RS
231 :type 'boolean
232 :group 'mh)
c26cf6c8 233
bdcfe844 234(defcustom mh-do-not-confirm-flag nil
a1b4049d
BW
235 "*Non-nil means do not prompt for confirmation.
236Commands such as `mh-pack-folder' prompt to confirm whether to process
237outstanding moves and deletes or not before continuing. A non-nil setting will
238perform the action--which is usually desired but cannot be retracted--without
239question."
abbc1a7a
RS
240 :type 'boolean
241 :group 'mh)
c26cf6c8 242
abbc1a7a 243(defcustom mh-store-default-directory nil
c26cf6c8 244 "*Last directory used by \\[mh-store-msg]; default for next store.
abbc1a7a
RS
245A directory name string, or nil to use current directory."
246 :type '(choice (const :tag "Current" nil)
247 directory)
248 :group 'mh)
c26cf6c8 249
847b8219
KH
250(defvar mh-note-deleted "D"
251 "String whose first character is used to notate deleted messages.")
252
253(defvar mh-note-refiled "^"
254 "String whose first character is used to notate refiled messages.")
255
256(defvar mh-note-cur "+"
257 "String whose first character is used to notate the current message.")
c26cf6c8
RS
258
259(defvar mh-partial-folder-mode-line-annotation "select"
260 "Annotation when displaying part of a folder.
bdcfe844 261The string is displayed after the folder's name. nil for no annotation.")
a1b4049d 262
bdcfe844 263;;; Parameterize MH-E to work with different scan formats. The defaults work
a1b4049d
BW
264;;; with the standard MH scan listings, in which the first 4 characters on
265;;; the line are the message number, followed by two places for notations.
266
267(defcustom mh-scan-format-file t
268 "Specifies the format file to pass to the scan program.
269If t, the format string will be taken from the either `mh-scan-format-mh'
270or `mh-scan-format-nmh' depending on whether MH or nmh is in use.
271If nil, the default scan output will be used.
272
273If you customize the scan format, you may need to modify a few variables
bdcfe844
BW
274containing regexps that MH-E uses to identify specific portions of the output.
275Use `M-x apropos RET mh-scan.*regexp' to obtain a list of these variables. You
276may also have to call `mh-set-cmd-note' with the width of your message
277numbers. See also `mh-adaptive-cmd-note-flag'."
278 :type '(choice (const :tag "Use MH-E scan format" t)
a1b4049d
BW
279 (const :tag "Use default scan format" nil)
280 (file :tag "Specify a scan format file"))
281 :group 'mh)
282
283;; The following scan formats are passed to the scan program if the
284;; setting of `mh-scan-format-file' above is nil. They are identical
285;; except the later one makes use of the nmh `decode' function to
bdcfe844
BW
286;; decode RFC 2047 encodings. If you just want to change the width of
287;; the msg number, use the `mh-set-cmd-note' function.
a1b4049d
BW
288
289(defvar mh-scan-format-mh
290 (concat
291 "%4(msg)"
292 "%<(cur)+%| %>"
293 "%<{replied}-"
294 "%?(nonnull(comp{to}))%<(mymbox{to})t%>"
295 "%?(nonnull(comp{cc}))%<(mymbox{cc})c%>"
296 "%?(nonnull(comp{bcc}))%<(mymbox{bcc})b%>"
297 "%?(nonnull(comp{newsgroups}))n%>"
298 "%<(zero) %>"
299 "%02(mon{date})/%02(mday{date})%<{date} %|*%>"
300 "%<(mymbox{from})%<{to}To:%14(friendly{to})%>%>"
301 "%<(zero)%17(friendly{from})%> "
302 "%{subject}%<{body}<<%{body}%>")
303 "*Scan format string for MH, provided to the scan program via the -format arg.
304This format is identical to the default except that additional hints for
bdcfe844
BW
305fontification have been added to the fifth column (remember that in Emacs, the
306first column is 0).
a1b4049d 307
bdcfe844 308The values of the fifth column, in priority order, are: `-' if the
a1b4049d
BW
309message has been replied to, t if an address on the To: line matches
310one of the mailboxes of the current user, `c' if the Cc: line matches,
311`b' if the Bcc: line matches, and `n' if a non-empty Newsgroups: header
312is present.")
313
314(defvar mh-scan-format-nmh
315 (concat
316 "%4(msg)"
317 "%<(cur)+%| %>"
318 "%<{replied}-"
319 "%?(nonnull(comp{to}))%<(mymbox{to})t%>"
320 "%?(nonnull(comp{cc}))%<(mymbox{cc})c%>"
321 "%?(nonnull(comp{bcc}))%<(mymbox{bcc})b%>"
322 "%?(nonnull(comp{newsgroups}))n%>"
323 "%<(zero) %>"
324 "%02(mon{date})/%02(mday{date})%<{date} %|*%>"
325 "%<(mymbox{from})%<{to}To:%14(decode(friendly{to}))%>%>"
326 "%<(zero)%17(decode(friendly{from}))%> "
327 "%(decode{subject})%<{body}<<%{body}%>")
bdcfe844
BW
328 "*Scan format string for nmh.
329This string is passed to the scan program via the -format arg.
a1b4049d 330This format is identical to the default except that additional hints for
bdcfe844
BW
331fontification have been added to the fifth column (remember that in Emacs, the
332first column is 0).
a1b4049d 333
bdcfe844 334The values of the fifth column, in priority order, are: `-' if the
a1b4049d
BW
335message has been replied to, t if an address on the To: line matches
336one of the mailboxes of the current user, `c' if the Cc: line matches,
337`b' if the Bcc: line matches, and `n' if a non-empty Newsgroups: header
338is present.")
339
bdcfe844 340(defvar mh-scan-good-msg-regexp "^\\( *[0-9]+\\)[^D^0-9]"
a1b4049d
BW
341 "Regexp specifying the scan lines that are 'good' messages.
342The default `mh-folder-font-lock-keywords' expects this expression to contain
343at least one parenthesized expression which matches the message number.")
344
bdcfe844 345(defvar mh-scan-deleted-msg-regexp "^\\( *[0-9]+\\)D"
a1b4049d
BW
346 "Regexp matching scan lines of deleted messages.
347The default `mh-folder-font-lock-keywords' expects this expression to contain
348at least one parenthesized expression which matches the message number.")
349
bdcfe844 350(defvar mh-scan-refiled-msg-regexp "^\\( *[0-9]+\\)\\^"
a1b4049d
BW
351 "Regexp matching scan lines of refiled messages.
352The default `mh-folder-font-lock-keywords' expects this expression to contain
353at least one parenthesized expression which matches the message number.")
354
355(defvar mh-scan-valid-regexp "^ *[0-9]"
356 "Regexp matching scan lines for messages (not error messages).")
357
bdcfe844 358(defvar mh-scan-cur-msg-number-regexp "^\\( *[0-9]+\\+\\).*"
a1b4049d
BW
359 "Regexp matching scan line for the current message.
360The default `mh-folder-font-lock-keywords' expects this expression to contain
361at least one parenthesized expression which matches the message number.
362Don't disable this regexp as it's needed by non fontifying functions.")
363
bdcfe844 364(defvar mh-scan-cur-msg-regexp "^\\( *[0-9]+\\+DISABLED.*\\)"
a1b4049d
BW
365 "Regexp matching scan line for the current message.
366The default `mh-folder-font-lock-keywords' expects this expression to contain
367at least one parenthesized expression which matches the whole line.
368To enable this feature, remove the string DISABLED from the regexp.")
369
370(defvar mh-scan-date-regexp "\\([0-9][0-9]/[0-9][0-9]\\)"
371 "Regexp matching a valid date in scan lines.
372The default `mh-folder-font-lock-keywords' expects this expression to contain
373only one parenthesized expression which matches the date field
374\(see `mh-scan-format-regexp').")
375
376(defvar mh-scan-rcpt-regexp "\\(To:\\)\\(..............\\)"
377 "Regexp specifying the recipient in scan lines for messages we sent.
378The default `mh-folder-font-lock-keywords' expects this expression to contain
379two parenthesized expressions. The first is expected to match the To:
380that the default scan format file generates. The second is expected to match
381the recipient's name.")
382
383(defvar mh-scan-body-regexp "\\(<<\\([^\n]+\\)?\\)"
384 "Regexp matching the message body beginning displayed in scan lines.
385The default `mh-folder-font-lock-keywords' expects this expression to contain
386at least one parenthesized expression which matches the body text.")
387
388(defvar mh-scan-subject-regexp
bdcfe844
BW
389;;"^ *[0-9]+........[ ]*...................\\([Rr][Ee]:\\s-*\\)*\\([^<\n]*\\)"
390 "^ *[0-9]+........[ ]*...................\\([Rr][Ee]\\(\\[[0-9]+\\]\\)?:\\s-*\\)*\\([^<\n]*\\)"
a1b4049d
BW
391 "*Regexp matching the subject string in MH folder mode.
392The default `mh-folder-font-lock-keywords' expects this expression to contain
bdcfe844
BW
393at least tree parenthesized expressions. The first is expected to match the Re:
394string, if any. The second matches an optional bracketed number after Re,
395such as in Re[2]: and the third is expected to match the subject line itself.")
a1b4049d
BW
396
397(defvar mh-scan-format-regexp
bdcfe844
BW
398 (concat "\\([bct]\\)" mh-scan-date-regexp " *\\(..................\\)")
399 "Regexp matching the output of scan.
400The default value is based upon the default values of either
401`mh-scan-format-mh' or `mh-scan-format-nmh'.
a1b4049d
BW
402The default `mh-folder-font-lock-keywords' expects this expression to contain
403at least three parenthesized expressions. The first should match the
404fontification hint, the second is found in `mh-scan-date-regexp', and the
405third should match the user name.")
406
407(defvar mh-folder-followup-face 'mh-folder-followup-face
408 "Face for highlighting Re: (followup) subject text in MH-Folder buffers.")
409(defface mh-folder-followup-face
410 '((((class color) (background light))
411 (:foreground "blue3"))
412 (((class color) (background dark))
413 (:foreground "LightGoldenRod"))
414 (t
415 (:bold t)))
416 "Face for highlighting Re: (followup) subject text in MH-Folder buffers."
417 :group 'mh)
418(defvar mh-folder-address-face 'mh-folder-address-face
419 "Face for highlighting the address in MH-Folder buffers.")
420(copy-face 'mh-folder-subject-face 'mh-folder-address-face)
421(defvar mh-folder-scan-format-face 'mh-folder-scan-format-face
422 "Face for highlighting `mh-scan-format-regexp' matches in MH-Folder buffers.")
423(copy-face 'mh-folder-followup-face 'mh-folder-scan-format-face)
424
425(defvar mh-folder-date-face 'mh-folder-date-face
426 "Face for highlighting the date in MH-Folder buffers.")
427(defface mh-folder-date-face
428 '((((class color) (background light))
429 (:foreground "snow4"))
430 (((class color) (background dark))
431 (:foreground "snow3"))
432 (t
433 (:bold t)))
434 "Face for highlighting the date in MH-Folder buffers."
435 :group 'mh)
436
437(defvar mh-folder-msg-number-face 'mh-folder-msg-number-face
438 "Face for highlighting the message number in MH-Folder buffers.")
439(defface mh-folder-msg-number-face
440 '((((class color) (background light))
441 (:foreground "snow4"))
442 (((class color) (background dark))
443 (:foreground "snow3"))
444 (t
445 (:bold t)))
446 "Face for highlighting the message number in MH-Folder buffers."
447 :group 'mh)
c26cf6c8 448
a1b4049d
BW
449(defvar mh-folder-deleted-face 'mh-folder-deleted-face
450 "Face for highlighting deleted messages in MH-Folder buffers.")
451(copy-face 'mh-folder-msg-number-face 'mh-folder-deleted-face)
452
453(defvar mh-folder-cur-msg-face 'mh-folder-cur-msg-face
454 "Face for the current message line in MH-Folder buffers.")
455(defface mh-folder-cur-msg-face
456 '((((type tty pc) (class color))
457 (:background "LightGreen"))
458 (((class color) (background light))
459 (:background "LightGreen") ;Use this for solid background colour
460;;; (:underline t) ;Use this for underlining
461 )
462 (((class color) (background dark))
463 (:background "DarkOliveGreen4"))
464 (t (:underline t)))
465 "Face for the current message line in MH-Folder buffers."
466 :group 'mh)
467
468;;mh-folder-subject-face is defined in mh-utils since it's needed there
469;;for mh-show-subject-face.
470
bdcfe844
BW
471(defvar mh-folder-refiled-face 'mh-folder-refiled-face
472 "Face for highlighting refiled messages in MH-Folder buffers.")
473(defface mh-folder-refiled-face
474 '((((type tty) (class color)) (:foreground "yellow" :weight light))
475 (((class grayscale) (background light))
476 (:foreground "Gray90" :bold t :italic t))
477 (((class grayscale) (background dark))
478 (:foreground "DimGray" :bold t :italic t))
479 (((class color) (background light)) (:foreground "DarkGoldenrod"))
480 (((class color) (background dark)) (:foreground "LightGoldenrod"))
481 (t (:bold t :italic t)))
482 "Face for highlighting refiled messages in MH-Folder buffers."
483 :group 'mh)
484
485(defvar mh-folder-cur-msg-number-face 'mh-folder-cur-msg-number-face
486 "Face for highlighting the current message in MH-Folder buffers.")
487(defface mh-folder-cur-msg-number-face
488 '((((type tty) (class color)) (:foreground "cyan" :weight bold))
489 (((class grayscale) (background light)) (:foreground "LightGray" :bold t))
490 (((class grayscale) (background dark)) (:foreground "DimGray" :bold t))
491 (((class color) (background light)) (:foreground "Purple"))
492 (((class color) (background dark)) (:foreground "Cyan"))
493 (t (:bold t)))
494 "Face for highlighting the current message in MH-Folder buffers."
495 :group 'mh)
496
497(defvar mh-folder-to-face 'mh-folder-to-face
498 "Face for highlighting the To: string in MH-Folder buffers.")
499(defface mh-folder-to-face
500 '((((type tty) (class color)) (:foreground "green"))
501 (((class grayscale) (background light)) (:foreground "DimGray" :italic t))
502 (((class grayscale) (background dark)) (:foreground "LightGray" :italic t))
503 (((class color) (background light)) (:foreground "RosyBrown"))
504 (((class color) (background dark)) (:foreground "LightSalmon"))
505 (t (:italic t)))
506 "Face for highlighting the To: string in MH-Folder buffers."
507 :group 'mh)
508
509(defvar mh-folder-body-face 'mh-folder-body-face
510 "Face for highlighting body text in MH-Folder buffers.")
511(defface mh-folder-body-face
512 '((((type tty) (class color)) (:foreground "green"))
513 (((class grayscale) (background light)) (:foreground "DimGray" :italic t))
514 (((class grayscale) (background dark)) (:foreground "LightGray" :italic t))
515 (((class color) (background light)) (:foreground "RosyBrown"))
516 (((class color) (background dark)) (:foreground "LightSalmon"))
517 (t (:italic t)))
518 "Face for highlighting body text in MH-Folder buffers."
519 :group 'mh)
a1b4049d 520
bdcfe844
BW
521(defvar mh-folder-font-lock-keywords
522 (list
523 ;; Marked for deletion
524 (list (concat mh-scan-deleted-msg-regexp ".*")
525 '(0 mh-folder-deleted-face))
526 ;; Marked for refile
527 (list (concat mh-scan-refiled-msg-regexp ".*")
528 '(0 mh-folder-refiled-face))
529 ;;after subj
530 (list mh-scan-body-regexp '(1 mh-folder-body-face nil t))
531 '(mh-folder-font-lock-subject
532 (1 mh-folder-followup-face append t)
533 (2 mh-folder-subject-face append t))
534 ;;current msg
535 (list mh-scan-cur-msg-number-regexp
536 '(1 mh-folder-cur-msg-number-face))
537 (list mh-scan-good-msg-regexp
538 '(1 mh-folder-msg-number-face)) ;; Msg number
539 (list mh-scan-date-regexp '(1 mh-folder-date-face)) ;; Date
540 (list mh-scan-rcpt-regexp
541 '(1 mh-folder-to-face) ;; To:
542 '(2 mh-folder-address-face)) ;; address
543 ;; scan font-lock name
544 (list mh-scan-format-regexp
545 '(1 mh-folder-date-face)
546 '(3 mh-folder-scan-format-face))
547 ;; Current message line
548 (list mh-scan-cur-msg-regexp
549 '(1 mh-folder-cur-msg-face prepend t))
550 ;; Unseen messages in bold
551 '(mh-folder-font-lock-unseen (1 'bold append t))
552 )
553 "Regexp keywords used to fontify the MH-Folder buffer.")
554
555(defvar mh-scan-cmd-note-width 1
556 "Number of columns consumed by the cmd-note field in `mh-scan-format'.
557This column will have one of the values: ` ', `D', `^', `+' and where
558` ' is the default value,
559`D' is the `mh-note-deleted' character,
560`^' is the `mh-note-refiled' character, and
561`+' is the `mh-note-cur' character.")
562
563(defvar mh-scan-destination-width 1
564 "Number of columns consumed by the destination field in `mh-scan-format'.
565This column will have one of ' ', '%', '-', 't', 'c', 'b', or `n' in it.
566A ' ' blank space is the default character.
567A '%' indicates that the message in in a named MH sequence.
568A '-' indicates that the message has been annotated with a replied field.
569A 't' indicates that the message contains mymbox in the To: field.
570A 'c' indicates that the message contains mymbox in the Cc: field.
571A 'b' indicates that the message contains mymbox in the Bcc: field.
572A 'n' indicates that the message contains a Newsgroups: field.")
573
574(defvar mh-scan-date-width 5
575 "Number of columns consumed by the date field in `mh-scan-format'.
576This column will typically be of the form mm/dd.")
577
578(defvar mh-scan-date-flag-width 1
579 "Number of columns consumed to flag (in)valid dates in `mh-scan-format'.
580This column will have ` ' for valid and `*' for invalid or missing dates.")
581
582(defvar mh-scan-from-mbox-width 17
583 "Number of columns consumed with the \"From:\" line in `mh-scan-format'.
584This column will have a friendly name or e-mail address of the
585originator, or a \"To: address\" for outgoing e-mail messages.")
586
587(defvar mh-scan-from-mbox-sep-width 2
588 "Number of columns consumed by whitespace after from-mbox in `mh-scan-format'.
589This column will only ever have spaces in it.")
590
591(defvar mh-scan-field-from-start-offset
592 (+ mh-scan-cmd-note-width
593 mh-scan-destination-width
594 mh-scan-date-width
595 mh-scan-date-flag-width)
596 "The offset from the `mh-cmd-note' to find the start of \"From:\" address.")
597
598(defvar mh-scan-field-from-end-offset
599 (+ mh-scan-field-from-start-offset mh-scan-from-mbox-width)
600 "The offset from the `mh-cmd-note' to find the end of \"From:\" address.")
601
602(defvar mh-scan-field-subject-start-offset
603 (+ mh-scan-cmd-note-width
604 mh-scan-destination-width
605 mh-scan-date-width
606 mh-scan-date-flag-width
607 mh-scan-from-mbox-width
608 mh-scan-from-mbox-sep-width)
609 "The offset from the `mh-cmd-note' to find the start of the subject.")
a1b4049d
BW
610
611(defun mh-folder-font-lock-subject (limit)
bdcfe844 612 "Return MH-E scan subject strings to font-lock between point and LIMIT."
a1b4049d
BW
613 (if (not (re-search-forward mh-scan-subject-regexp limit t))
614 nil
615 (if (match-beginning 1)
bdcfe844
BW
616 (set-match-data (list (match-beginning 1) (match-end 3)
617 (match-beginning 1) (match-end 3) nil nil))
618 (set-match-data (list (match-beginning 3) (match-end 3)
619 nil nil (match-beginning 3) (match-end 3))))
a1b4049d
BW
620 t))
621
bdcfe844
BW
622\f
623
624;; Fontifify unseen mesages in bold.
625
a1b4049d
BW
626(defvar mh-folder-unseen-seq-name nil
627 "Name of unseen sequence.
628The default for this is provided by the function `mh-folder-unseen-seq-name'
629On nmh systems.")
630
631(defun mh-folder-unseen-seq-name ()
632 "Provide name of unseen sequence from mhparam."
633 (or mh-progs (mh-find-path))
634 (save-excursion
bdcfe844
BW
635 (let ((unseen-seq-name "unseen"))
636 (with-temp-buffer
637 (unwind-protect
638 (progn
639 (call-process (expand-file-name "mhparam" mh-progs)
640 nil '(t t) nil "-component" "Unseen-Sequence")
641 (goto-char (point-min))
642 (if (re-search-forward "Unseen-Sequence: \\(.*\\)$" nil t)
643 (setq unseen-seq-name (match-string 1))))))
a1b4049d
BW
644 unseen-seq-name)))
645
646(defun mh-folder-unseen-seq-list ()
647 "Return a list of unseen message numbers for current folder."
648 (if (not mh-folder-unseen-seq-name)
649 (setq mh-folder-unseen-seq-name (mh-folder-unseen-seq-name)))
650 (cond
651 ((not mh-folder-unseen-seq-name)
652 nil)
653 (t
654 (let ((folder mh-current-folder))
655 (save-excursion
bdcfe844 656 (with-temp-buffer
a1b4049d
BW
657 (unwind-protect
658 (progn
659 (call-process (expand-file-name "mark" mh-progs)
bdcfe844 660 nil '(t t) nil
a1b4049d
BW
661 folder "-seq" mh-folder-unseen-seq-name
662 "-list")
663 (goto-char (point-min))
bdcfe844 664 (sort (mh-read-msg-list) '<)))))))))
a1b4049d
BW
665
666(defvar mh-folder-unseen-seq-cache nil
bdcfe844 667 "Internal cache variable used for font-lock in MH-E.
a1b4049d
BW
668Should only be non-nil through font-lock stepping, and nil once font-lock
669is done highlighting.")
670(make-variable-buffer-local 'mh-folder-unseen-seq-cache)
671
672(defun mh-folder-font-lock-unseen (limit)
673 "Return unseen message lines to font-lock between point and LIMIT."
674 (if (not mh-folder-unseen-seq-cache)
675 (setq mh-folder-unseen-seq-cache (mh-folder-unseen-seq-list)))
676 (let ((cur-msg (mh-get-msg-num nil)))
677 (cond
678 ((not mh-folder-unseen-seq-cache)
679 nil)
680 ((not cur-msg) ;Presumably at end of buffer
681 (setq mh-folder-unseen-seq-cache nil)
682 nil)
683 ((member cur-msg mh-folder-unseen-seq-cache)
684 (let ((bpoint (progn (beginning-of-line)(point)))
685 (epoint (progn (forward-line 1)(point))))
686 (if (<= limit (point))
687 (setq mh-folder-unseen-seq-cache nil))
688 (set-match-data (list bpoint epoint bpoint epoint))
689 t))
690 (t
691 ;; move forward one line at a time, checking each message number.
692 (while (and
693 (= 0 (forward-line 1))
694 (> limit (point))
695 (not (member (mh-get-msg-num nil) mh-folder-unseen-seq-cache))))
696 ;; Examine how we must have exited the loop...
697 (let ((cur-msg (mh-get-msg-num nil)))
698 (cond
699 ((or (not cur-msg)
700 (<= limit (point))
701 (not (member cur-msg mh-folder-unseen-seq-cache)))
702 (setq mh-folder-unseen-seq-cache nil)
703 nil)
704 ((member cur-msg mh-folder-unseen-seq-cache)
705 (let ((bpoint (progn (beginning-of-line)(point)))
706 (epoint (progn (forward-line 1)(point))))
707 (if (<= limit (point))
708 (setq mh-folder-unseen-seq-cache nil))
709 (set-match-data (list bpoint epoint bpoint epoint))
710 t))))))))
bdcfe844
BW
711
712\f
c26cf6c8
RS
713
714;;; Internal variables:
715
bdcfe844
BW
716(defvar mh-last-destination nil) ;Destination of last refile or write
717 ;command.
718(defvar mh-last-destination-folder nil) ;Destination of last refile command.
719(defvar mh-last-destination-write nil) ;Destination of last write command.
c26cf6c8
RS
720
721(defvar mh-folder-mode-map (make-keymap)
722 "Keymap for MH folders.")
723
847b8219 724(defvar mh-delete-list nil) ;List of msg numbers to delete.
c26cf6c8 725
847b8219 726(defvar mh-refile-list nil) ;List of folder names in mh-seq-list.
c26cf6c8 727
847b8219 728(defvar mh-next-direction 'forward) ;Direction to move to next message.
c26cf6c8 729
bdcfe844
BW
730(defvar mh-narrowed-to-seq nil) ;Sequence display is narrowed to or
731 ;nil if not narrowed.
732
733(defvar mh-view-ops ()) ;Stack of ops that change the folder
734 ;view (such as narrowing or threading).
c26cf6c8 735
847b8219 736(defvar mh-first-msg-num nil) ;Number of first msg in buffer.
c26cf6c8 737
847b8219 738(defvar mh-last-msg-num nil) ;Number of last msg in buffer.
c26cf6c8 739
a1b4049d 740(defvar mh-mode-line-annotation nil) ;Message range displayed in buffer.
c26cf6c8
RS
741
742;;; Macros and generic functions:
743
bdcfe844
BW
744(defun mh-mapc (function list)
745 "Apply FUNCTION to each element of LIST for side effects only."
c26cf6c8 746 (while list
bdcfe844 747 (funcall function (car list))
c26cf6c8
RS
748 (setq list (cdr list))))
749
a1b4049d 750(defun mh-scan-format ()
bdcfe844 751 "Return \"-format\" argument for the scan program."
a1b4049d 752 (if (equal mh-scan-format-file t)
bdcfe844
BW
753 (list "-format" (if mh-nmh-flag
754 (list (mh-update-scan-format
755 mh-scan-format-nmh mh-cmd-note))
756 (list (mh-update-scan-format
757 mh-scan-format-mh mh-cmd-note))))
a1b4049d 758 (if (not (equal mh-scan-format-file nil))
bdcfe844 759 (list "-format" mh-scan-format-file))))
a1b4049d 760
c26cf6c8
RS
761\f
762
763;;; Entry points:
764
765;;;###autoload
766(defun mh-rmail (&optional arg)
a1b4049d 767 "Inc(orporate) new mail with MH.
bdcfe844 768Scan an MH folder if ARG is non-nil. This function is an entry point to MH-E,
a1b4049d 769the Emacs front end to the MH mail system."
c26cf6c8
RS
770 (interactive "P")
771 (mh-find-path)
772 (if arg
773 (call-interactively 'mh-visit-folder)
774 (mh-inc-folder)))
775
a1b4049d
BW
776;;;###autoload
777(defun mh-nmail (&optional arg)
778 "Check for new mail in inbox folder.
bdcfe844 779Scan an MH folder if ARG is non-nil. This function is an entry point to MH-E,
a1b4049d
BW
780the Emacs front end to the MH mail system."
781 (interactive "P")
782 (mh-find-path) ; init mh-inbox
783 (if arg
784 (call-interactively 'mh-visit-folder)
785 (mh-visit-folder mh-inbox)))
c26cf6c8
RS
786
787\f
788
bdcfe844 789;;; User executable MH-E commands:
c26cf6c8
RS
790
791
792(defun mh-delete-msg (msg-or-seq)
a1b4049d
BW
793 "Mark the specified MSG-OR-SEQ for subsequent deletion and move to the next.
794
795Default is the displayed message. If optional prefix argument is given then
796prompt for the message sequence. If variable `transient-mark-mode' is non-nil
797and the mark is active, then the selected region is marked for deletion."
798 (interactive (list (cond
bdcfe844
BW
799 ((mh-mark-active-p t)
800 (mh-region-to-sequence (region-beginning) (region-end))
a1b4049d
BW
801 'region)
802 (current-prefix-arg
803 (mh-read-seq-default "Delete" t))
804 (t
805 (mh-get-msg-num t)))))
c26cf6c8
RS
806 (mh-delete-msg-no-motion msg-or-seq)
807 (mh-next-msg))
808
c26cf6c8 809(defun mh-delete-msg-no-motion (msg-or-seq)
a1b4049d 810 "Mark the specified MSG-OR-SEQ for subsequent deletion.
bdcfe844
BW
811Default is the displayed message. If optional prefix argument is provided,
812then prompt for the message sequence."
c26cf6c8
RS
813 (interactive (list (if current-prefix-arg
814 (mh-read-seq-default "Delete" t)
815 (mh-get-msg-num t))))
816 (if (numberp msg-or-seq)
817 (mh-delete-a-msg msg-or-seq)
818 (mh-map-to-seq-msgs 'mh-delete-a-msg msg-or-seq)))
819
c26cf6c8
RS
820(defun mh-execute-commands ()
821 "Process outstanding delete and refile requests."
822 (interactive)
823 (if mh-narrowed-to-seq (mh-widen))
824 (mh-process-commands mh-current-folder)
825 (mh-set-scan-mode)
826 (mh-goto-cur-msg) ; after mh-set-scan-mode for efficiency
827 (mh-make-folder-mode-line)
bdcfe844 828 t) ; return t for write-file-functions
c26cf6c8
RS
829
830(defun mh-first-msg ()
831 "Move to the first message."
832 (interactive)
847b8219 833 (goto-char (point-min))
a1b4049d 834 (while (and (not (eobp)) (not (looking-at mh-scan-valid-regexp)))
847b8219 835 (forward-line 1)))
c26cf6c8 836
c26cf6c8
RS
837(defun mh-header-display ()
838 "Show the current message with all its headers.
86a32538 839Displays headers that might have been suppressed by setting the
bdcfe844 840variables `mh-clean-message-header-flag' or `mhl-formfile', or by the fallback
86a32538
RS
841behavior of scrolling uninteresting headers off the top of the window.
842Type \"\\[mh-show]\" to show the message normally again."
c26cf6c8
RS
843 (interactive)
844 (and (not mh-showing-with-headers)
bdcfe844 845 (or mhl-formfile mh-clean-message-header-flag)
c26cf6c8 846 (mh-invalidate-show-buffer))
bdcfe844
BW
847 (let ((mh-decode-mime-flag nil)
848 (mhl-formfile nil)
849 (mh-clean-message-header-flag nil))
c26cf6c8
RS
850 (mh-show-msg nil)
851 (mh-in-show-buffer (mh-show-buffer)
852 (goto-char (point-min))
853 (mh-recenter 0))
854 (setq mh-showing-with-headers t)))
855
c26cf6c8 856(defun mh-inc-folder (&optional maildrop-name)
847b8219 857 "Inc(orporate)s new mail into the Inbox folder.
a1b4049d
BW
858Optional argument MAILDROP-NAME specifies an alternate maildrop from the
859default. If the prefix argument is given, incorporates mail into the current
847b8219 860folder, otherwise uses the folder named by `mh-inbox'.
bdcfe844
BW
861The value of `mh-inc-folder-hook' is a list of functions to be called, with no
862arguments, after incorporating new mail.
863Do not call this function from outside MH-E; use \\[mh-rmail] instead."
c26cf6c8
RS
864 (interactive (list (if current-prefix-arg
865 (expand-file-name
866 (read-file-name "inc mail from file: "
867 mh-user-path)))))
868 (let ((config (current-window-configuration)))
869 (if (not maildrop-name)
847b8219
KH
870 (cond ((not (get-buffer mh-inbox))
871 (mh-make-folder mh-inbox)
c26cf6c8 872 (setq mh-previous-window-config config))
847b8219
KH
873 ((not (eq (current-buffer) (get-buffer mh-inbox)))
874 (switch-to-buffer mh-inbox)
c26cf6c8
RS
875 (setq mh-previous-window-config config)))))
876 (mh-get-new-mail maildrop-name)
a1b4049d 877 (if mh-showing-mode (mh-show))
c26cf6c8
RS
878 (run-hooks 'mh-inc-folder-hook))
879
c26cf6c8
RS
880(defun mh-last-msg ()
881 "Move to the last message."
882 (interactive)
883 (goto-char (point-max))
884 (while (and (not (bobp)) (looking-at "^$"))
bdcfe844
BW
885 (forward-line -1))
886 (mh-recenter nil))
c26cf6c8
RS
887
888(defun mh-next-undeleted-msg (&optional arg)
a1b4049d 889 "Move to the next undeleted message ARG in window."
847b8219 890 (interactive "p")
c26cf6c8 891 (setq mh-next-direction 'forward)
847b8219 892 (forward-line 1)
bdcfe844 893 (cond ((re-search-forward mh-scan-good-msg-regexp nil t arg)
c26cf6c8
RS
894 (beginning-of-line)
895 (mh-maybe-show))
bdcfe844
BW
896 (t (forward-line -1)
897 (message "No more undeleted messages"))))
c26cf6c8 898
847b8219 899(defun mh-refile-msg (msg-or-seq folder)
a1b4049d
BW
900 "Refile MSG-OR-SEQ (default: displayed message) into FOLDER.
901If optional prefix argument provided, then prompt for message sequence.
902If variable `transient-mark-mode' is non-nil and the mark is active, then the
903selected region is marked for refiling."
c26cf6c8 904 (interactive
a1b4049d 905 (list (cond
bdcfe844
BW
906 ((mh-mark-active-p t)
907 (mh-region-to-sequence (region-beginning) (region-end))
a1b4049d
BW
908 'region)
909 (current-prefix-arg
910 (mh-read-seq-default "Refile" t))
911 (t
912 (mh-get-msg-num t)))
c26cf6c8
RS
913 (intern
914 (mh-prompt-for-folder
915 "Destination"
847b8219
KH
916 (or (and mh-default-folder-for-message-function
917 (let ((refile-file (mh-msg-filename (mh-get-msg-num t))))
c26cf6c8 918 (save-excursion
847b8219 919 (set-buffer (get-buffer-create mh-temp-buffer))
c26cf6c8 920 (erase-buffer)
847b8219
KH
921 (insert-file-contents refile-file)
922 (let ((buffer-file-name refile-file))
923 (funcall mh-default-folder-for-message-function)))))
bdcfe844
BW
924 (and (eq 'refile (car mh-last-destination-folder))
925 (symbol-name (cdr mh-last-destination-folder)))
c26cf6c8
RS
926 "")
927 t))))
bdcfe844
BW
928 (setq mh-last-destination (cons 'refile folder)
929 mh-last-destination-folder mh-last-destination)
c26cf6c8 930 (if (numberp msg-or-seq)
847b8219
KH
931 (mh-refile-a-msg msg-or-seq folder)
932 (mh-map-to-seq-msgs 'mh-refile-a-msg msg-or-seq folder))
c26cf6c8
RS
933 (mh-next-msg))
934
847b8219 935(defun mh-refile-or-write-again (message)
c26cf6c8 936 "Re-execute the last refile or write command on the given MESSAGE.
bdcfe844
BW
937Default is the displayed message. Use the same folder or file as the previous
938refile or write command."
c26cf6c8
RS
939 (interactive (list (mh-get-msg-num t)))
940 (if (null mh-last-destination)
941 (error "No previous refile or write"))
942 (cond ((eq (car mh-last-destination) 'refile)
847b8219 943 (mh-refile-a-msg message (cdr mh-last-destination))
c26cf6c8
RS
944 (message "Destination folder: %s" (cdr mh-last-destination)))
945 (t
847b8219 946 (apply 'mh-write-msg-to-file message (cdr mh-last-destination))
c26cf6c8
RS
947 (message "Destination: %s" (cdr mh-last-destination))))
948 (mh-next-msg))
949
c26cf6c8 950(defun mh-quit ()
bdcfe844
BW
951 "Quit the current MH-E folder.
952Restore the previous window configuration, if one exists.
953The value of `mh-before-quit-hook' is a list of functions to be called, with
954no arguments, immediately upon entry to this function.
955The value of `mh-quit-hook' is a list of functions to be called, with no
956arguments, upon exit of this function."
c26cf6c8 957 (interactive)
a1b4049d 958 (run-hooks 'mh-before-quit-hook)
bdcfe844
BW
959 (let ((show-buffer (get-buffer mh-show-buffer)))
960 (when show-buffer
961 (kill-buffer show-buffer)))
847b8219 962 (mh-update-sequences)
bdcfe844 963 (mh-destroy-postponed-handles)
6d4de1a7 964 (bury-buffer (current-buffer))
a1b4049d
BW
965 (if (get-buffer mh-temp-buffer)
966 (kill-buffer mh-temp-buffer))
967 (if (get-buffer mh-temp-folders-buffer)
968 (kill-buffer mh-temp-folders-buffer))
969 (if (get-buffer mh-temp-sequences-buffer)
970 (kill-buffer mh-temp-sequences-buffer))
c26cf6c8
RS
971 (if mh-previous-window-config
972 (set-window-configuration mh-previous-window-config))
973 (run-hooks 'mh-quit-hook))
974
975(defun mh-page-msg (&optional arg)
976 "Page the displayed message forwards.
a1b4049d
BW
977Scrolls ARG lines or a full screen if no argument is supplied. Show buffer
978first if not displayed. Show the next undeleted message if looking at the
979bottom of the current message."
c26cf6c8 980 (interactive "P")
a1b4049d 981 (if mh-showing-mode
bdcfe844 982 (if mh-page-to-next-msg-flag
a1b4049d
BW
983 (if (equal mh-next-direction 'backward)
984 (mh-previous-undeleted-msg)
985 (mh-next-undeleted-msg))
986 (if (mh-in-show-buffer (mh-show-buffer)
987 (pos-visible-in-window-p (point-max)))
988 (progn
989 (message (format
990 "End of message (Type %s to read %s undeleted message)"
991 (single-key-description last-input-event)
992 (if (equal mh-next-direction 'backward)
993 "previous"
994 "next")))
bdcfe844 995 (setq mh-page-to-next-msg-flag t))
a1b4049d
BW
996 (scroll-other-window arg)))
997 (mh-show)))
c26cf6c8 998
c26cf6c8
RS
999(defun mh-previous-page (&optional arg)
1000 "Page the displayed message backwards.
1001Scrolls ARG lines or a full screen if no argument is supplied."
1002 (interactive "P")
1003 (mh-in-show-buffer (mh-show-buffer)
1004 (scroll-down arg)))
1005
c26cf6c8 1006(defun mh-previous-undeleted-msg (&optional arg)
a1b4049d 1007 "Move to the previous undeleted message ARG in window."
c26cf6c8
RS
1008 (interactive "p")
1009 (setq mh-next-direction 'backward)
1010 (beginning-of-line)
bdcfe844 1011 (cond ((re-search-backward mh-scan-good-msg-regexp nil t arg)
c26cf6c8 1012 (mh-maybe-show))
bdcfe844
BW
1013 (t (message "No previous undeleted message"))))
1014
1015(defun mh-goto-next-button (backward-flag &optional criterion)
1016 "Search for next button satisfying criterion.
1017If BACKWARD-FLAG is non-nil search backward in the buffer for a mime button. If
1018CRITERION is a function or a symbol which has a function binding then that
1019function must return non-nil at the button we stop."
1020 (unless (or (and (symbolp criterion) (fboundp criterion))
1021 (functionp criterion))
1022 (setq criterion (lambda (x) t)))
1023 ;; Move to the next button in the buffer satisfying criterion
1024 (goto-char (or (save-excursion
1025 (beginning-of-line)
1026 ;; Find point before current button
1027 (let ((point-before-current-button
1028 (save-excursion
1029 (while (get-text-property (point) 'mh-data)
1030 (unless (= (forward-line
1031 (if backward-flag 1 -1))
1032 0)
1033 (if backward-flag
1034 (goto-char (point-min))
1035 (goto-char (point-max)))))
1036 (point))))
1037 ;; Skip over current button
1038 (while (and (get-text-property (point) 'mh-data)
1039 (not (if backward-flag (bobp) (eobp))))
1040 (forward-line (if backward-flag -1 1)))
1041 ;; Stop at next MIME button if any exists.
1042 (block loop
1043 (while (/= (progn
1044 (unless (= (forward-line
1045 (if backward-flag -1 1))
1046 0)
1047 (if backward-flag
1048 (goto-char (point-max))
1049 (goto-char (point-min)))
1050 (beginning-of-line))
1051 (point))
1052 point-before-current-button)
1053 (when (and (get-text-property (point) 'mh-data)
1054 (funcall criterion (point)))
1055 (return-from loop (point))))
1056 nil)))
1057 (point))))
1058
1059(defun mh-next-button (&optional backward-flag)
1060 "Go to the next MIME button.
1061Advance point to the next MIME button in the show buffer. If the end
1062of buffer is reached then the search wraps over to the start of the
1063buffer. With prefix argument, BACKWARD-FLAG the point will move to the
1064previous MIME button."
1065 (interactive (list current-prefix-arg))
1066 (unless mh-showing-mode
1067 (mh-show))
1068 (mh-in-show-buffer (mh-show-buffer)
1069 (mh-goto-next-button backward-flag)))
c26cf6c8 1070
bdcfe844
BW
1071(defun mh-prev-button ()
1072 "Go to the prev MIME button.
1073Move point to the previous MIME button in the show buffer. If the beginning
1074of the buffer is reached then the search wraps over to the end of the
1075buffer."
1076 (interactive)
1077 (mh-next-button t))
1078
1079(defun mh-folder-mime-action (part-index action include-security-flag)
1080 "Go to PART-INDEX and carry out ACTION.
1081If PART-INDEX is nil then go to the next part in the buffer. The search for
1082the next buffer wraps around if end of buffer is reached. If argument
1083INCLUDE-SECURITY-FLAG is non-nil then include security info buttons when
1084searching for a suitable parts."
1085 (unless mh-showing-mode
1086 (mh-show))
1087 (mh-in-show-buffer (mh-show-buffer)
1088 (let ((criterion
1089 (cond (part-index
1090 (lambda (p)
1091 (let ((part (get-text-property p 'mh-part)))
1092 (and (integerp part) (= part part-index)))))
1093 (t (lambda (p)
1094 (if include-security-flag
1095 (get-text-property p 'mh-data)
1096 (integerp (get-text-property p 'mh-part)))))))
1097 (point (point)))
1098 (cond ((and (get-text-property point 'mh-part)
1099 (or (null part-index)
1100 (= (get-text-property point 'mh-part) part-index)))
1101 (funcall action))
1102 ((and (get-text-property point 'mh-data)
1103 include-security-flag
1104 (null part-index))
1105 (funcall action))
1106 (t
1107 (mh-goto-next-button nil criterion)
1108 (if (= (point) point)
1109 (message "No matching MIME part found")
1110 (funcall action)))))))
1111
1112(defun mh-folder-toggle-mime-part (part-index)
1113 "Toggle display of button.
1114If point in show buffer is at a button then that part is toggled.
1115If not at a button and PART-INDEX is non-nil point is moved to that part.
1116With nil PART-INDEX find the first button after point (search wraps around if
1117end of buffer is reached) and toggle it."
1118 (interactive "P")
1119 (when (consp part-index) (setq part-index (car part-index)))
1120 (mh-folder-mime-action part-index #'mh-press-button t))
1121
1122(defun mh-folder-inline-mime-part (part-index)
1123 "Show the raw bytes of MIME part inline.
1124If point in show buffer is at a mime part then that part is inlined.
1125If not at a mime-part and PART-INDEX is non-nil point is moved to that part.
1126With nil PART-INDEX find the first button after point (search wraps around if
1127end of buffer is reached) and inline it."
1128 (interactive "P")
1129 (when (consp part-index) (setq part-index (car part-index)))
1130 (mh-folder-mime-action part-index #'mh-mime-inline-part nil))
1131
1132(defun mh-folder-save-mime-part (part-index)
1133 "Save MIME part.
1134If point in show buffer is at a mime part then that part is saved.
1135If not at a mime-part and PART-INDEX is non-nil point is moved to that part.
1136With nil PART-INDEX find the first button after point (search wraps around if
1137end of buffer is reached) and save it."
1138 (interactive "P")
1139 (when (consp part-index) (setq part-index (car part-index)))
1140 (mh-folder-mime-action part-index #'mh-mime-save-part nil))
1141
1142(defun mh-reset-threads-and-narrowing ()
1143 "Reset all variables pertaining to threads and narrowing.
1144Also removes all content from the folder buffer."
1145 (setq mh-view-ops ())
1146 (setq mh-narrowed-to-seq nil)
1147 (let ((buffer-read-only nil)) (erase-buffer)))
c26cf6c8 1148
bdcfe844 1149(defun mh-rescan-folder (&optional range dont-exec-pending)
c26cf6c8 1150 "Rescan a folder after optionally processing the outstanding commands.
a1b4049d 1151If optional prefix argument RANGE is provided, prompt for the range of
bdcfe844
BW
1152messages to display. Otherwise show the entire folder.
1153If optional argument DONT-EXEC-PENDING is non-nil then pending deletes and
1154refiles aren't carried out."
c26cf6c8
RS
1155 (interactive (list (if current-prefix-arg
1156 (mh-read-msg-range "Range to scan [all]? ")
1157 nil)))
1158 (setq mh-next-direction 'forward)
bdcfe844
BW
1159 (mh-reset-threads-and-narrowing)
1160 (mh-scan-folder mh-current-folder (or range "all") dont-exec-pending))
c26cf6c8
RS
1161
1162(defun mh-write-msg-to-file (msg file no-headers)
a1b4049d
BW
1163 "Append MSG to the end of a FILE.
1164If prefix argument NO-HEADERS is provided, write only the message body.
c26cf6c8
RS
1165Otherwise send the entire message including the headers."
1166 (interactive
1167 (list (mh-get-msg-num t)
bdcfe844
BW
1168 (let ((default-dir (if (eq 'write (car mh-last-destination-write))
1169 (file-name-directory
1170 (car (cdr mh-last-destination-write)))
c26cf6c8 1171 default-directory)))
847b8219
KH
1172 (read-file-name (format "Save message%s in file: "
1173 (if current-prefix-arg " body" ""))
1174 default-dir
bdcfe844
BW
1175 (if (eq 'write (car mh-last-destination-write))
1176 (car (cdr mh-last-destination-write))
847b8219 1177 (expand-file-name "mail.out" default-dir))))
c26cf6c8 1178 current-prefix-arg))
847b8219 1179 (let ((msg-file-to-output (mh-msg-filename msg))
c26cf6c8 1180 (output-file (mh-expand-file-name file)))
bdcfe844
BW
1181 (setq mh-last-destination (list 'write file (if no-headers 'no-headers))
1182 mh-last-destination-write mh-last-destination)
c26cf6c8 1183 (save-excursion
847b8219 1184 (set-buffer (get-buffer-create mh-temp-buffer))
c26cf6c8 1185 (erase-buffer)
847b8219 1186 (insert-file-contents msg-file-to-output)
c26cf6c8
RS
1187 (goto-char (point-min))
1188 (if no-headers (search-forward "\n\n"))
1189 (append-to-file (point) (point-max) output-file))))
1190
c26cf6c8
RS
1191(defun mh-toggle-showing ()
1192 "Toggle the scanning mode/showing mode of displaying messages."
1193 (interactive)
a1b4049d 1194 (if mh-showing-mode
c26cf6c8 1195 (mh-set-scan-mode)
a1b4049d 1196 (mh-show)))
c26cf6c8 1197
c26cf6c8 1198(defun mh-undo (msg-or-seq)
a1b4049d 1199 "Undo the pending deletion or refile of the specified MSG-OR-SEQ.
bdcfe844
BW
1200Default is the displayed message.
1201If optional prefix argument is provided, then prompt for the message sequence.
a1b4049d
BW
1202If variable `transient-mark-mode' is non-nil and the mark is active, then the
1203selected region is unmarked."
1204 (interactive (list (cond
bdcfe844
BW
1205 ((mh-mark-active-p t)
1206 (mh-region-to-sequence (region-beginning) (region-end))
a1b4049d
BW
1207 'region)
1208 (current-prefix-arg
1209 (mh-read-seq-default "Undo" t))
1210 (t
1211 (mh-get-msg-num t)))))
c26cf6c8
RS
1212 (cond ((numberp msg-or-seq)
1213 (let ((original-position (point)))
1214 (beginning-of-line)
a1b4049d
BW
1215 (while (not (or (looking-at mh-scan-deleted-msg-regexp)
1216 (looking-at mh-scan-refiled-msg-regexp)
c26cf6c8
RS
1217 (and (eq mh-next-direction 'forward) (bobp))
1218 (and (eq mh-next-direction 'backward)
1219 (save-excursion (forward-line) (eobp)))))
1220 (forward-line (if (eq mh-next-direction 'forward) -1 1)))
a1b4049d
BW
1221 (if (or (looking-at mh-scan-deleted-msg-regexp)
1222 (looking-at mh-scan-refiled-msg-regexp))
c26cf6c8
RS
1223 (progn
1224 (mh-undo-msg (mh-get-msg-num t))
1225 (mh-maybe-show))
1226 (goto-char original-position)
1227 (error "Nothing to undo"))))
1228 (t
847b8219 1229 (mh-map-to-seq-msgs 'mh-undo-msg msg-or-seq)))
c26cf6c8
RS
1230 (if (not (mh-outstanding-commands-p))
1231 (mh-set-folder-modified-p nil)))
1232
847b8219 1233;;;###autoload
c26cf6c8 1234(defun mh-version ()
bdcfe844 1235 "Display version information about MH-E and the MH mail handling system."
c26cf6c8
RS
1236 (interactive)
1237 (mh-find-progs)
847b8219 1238 (set-buffer (get-buffer-create mh-temp-buffer))
c26cf6c8 1239 (erase-buffer)
bdcfe844
BW
1240 ;; MH-E and Emacs versions.
1241 (insert "MH-E " mh-version "\n\n" (emacs-version) "\n\n")
a1b4049d 1242 ;; MH version.
c26cf6c8
RS
1243 (let ((help-start (point)))
1244 (condition-case err-data
bdcfe844 1245 (mh-exec-cmd-output "inc" nil (if mh-nmh-flag "-version" "-help"))
a1b4049d 1246 (file-error (insert (mapconcat 'concat (cdr err-data) ": ") "\n")))
c26cf6c8 1247 (goto-char help-start)
bdcfe844 1248 (if mh-nmh-flag
a1b4049d
BW
1249 (search-forward "inc -- " nil t)
1250 (search-forward "version: " nil t))
1251 (delete-region help-start (point)))
1252 (goto-char (point-max))
1253 (insert "mh-progs:\t" mh-progs "\n"
1254 "mh-lib:\t\t" mh-lib "\n"
1255 "mh-lib-progs:\t" mh-lib-progs "\n\n")
1256 ;; Linux version.
1257 (condition-case ()
1258 (call-process "uname" nil t nil "-a")
1259 (file-error))
1260 (goto-char (point-min))
847b8219 1261 (display-buffer mh-temp-buffer))
c26cf6c8 1262
c26cf6c8 1263(defun mh-visit-folder (folder &optional range)
847b8219 1264 "Visit FOLDER and display RANGE of messages.
bdcfe844 1265Do not call this function from outside MH-E; see \\[mh-rmail] instead."
847b8219 1266 (interactive (list (mh-prompt-for-folder "Visit" mh-inbox t)
c26cf6c8
RS
1267 (mh-read-msg-range "Range [all]? ")))
1268 (let ((config (current-window-configuration)))
1269 (mh-scan-folder folder (or range "all"))
1270 (setq mh-previous-window-config config))
1271 nil)
1272
847b8219 1273(defun mh-update-sequences ()
bdcfe844
BW
1274 "Update MH's Unseen-Sequence and current folder and message.
1275Flush MH-E's state out to MH. The message at the cursor becomes current."
847b8219
KH
1276 (interactive)
1277 ;; mh-update-sequences is the opposite of mh-read-folder-sequences,
bdcfe844 1278 ;; which updates MH-E's state from MH.
847b8219
KH
1279 (let ((folder-set (mh-update-unseen))
1280 (new-cur (mh-get-msg-num nil)))
1281 (if new-cur
1282 (let ((seq-entry (mh-find-seq 'cur)))
1283 (mh-remove-cur-notation)
1284 (setcdr seq-entry (list new-cur)) ;delete-seq-locally, add-msgs-to-seq
1285 (mh-define-sequence 'cur (list new-cur))
1286 (beginning-of-line)
a1b4049d 1287 (if (looking-at mh-scan-good-msg-regexp)
847b8219
KH
1288 (mh-notate nil mh-note-cur mh-cmd-note)))
1289 (or folder-set
1290 (save-excursion
a1b4049d
BW
1291 ;; psg - mh-current-folder is nil if mh-summary-height < 4 !
1292 ;; So I added this sanity check.
1293 (if (stringp mh-current-folder)
1294 (mh-exec-cmd-quiet t "folder" mh-current-folder "-fast")
1295 (mh-exec-cmd-quiet t "folder" "-fast")))))))
847b8219 1296
c26cf6c8
RS
1297\f
1298
1299;;; Support routines.
1300
1301(defun mh-delete-a-msg (msg)
bdcfe844
BW
1302 "Delete the MSG.
1303The value of `mh-delete-msg-hook' is a list of functions to be called, with no
1304arguments, after the message has been deleted."
c26cf6c8
RS
1305 (save-excursion
1306 (mh-goto-msg msg nil t)
a1b4049d 1307 (if (looking-at mh-scan-refiled-msg-regexp)
60370d40 1308 (error "Message %d is refiled. Undo refile before deleting" msg))
a1b4049d 1309 (if (looking-at mh-scan-deleted-msg-regexp)
c26cf6c8
RS
1310 nil
1311 (mh-set-folder-modified-p t)
1312 (setq mh-delete-list (cons msg mh-delete-list))
847b8219 1313 (mh-notate msg mh-note-deleted mh-cmd-note)
c26cf6c8
RS
1314 (run-hooks 'mh-delete-msg-hook))))
1315
bdcfe844
BW
1316(defun mh-refile-a-msg (msg folder)
1317 "Refile MSG in FOLDER.
1318Folder is a symbol, not a string.
1319The value of `mh-refile-msg-hook' is a list of functions to be called, with no
1320arguments, after the message has been refiled."
c26cf6c8
RS
1321 (save-excursion
1322 (mh-goto-msg msg nil t)
a1b4049d 1323 (cond ((looking-at mh-scan-deleted-msg-regexp)
60370d40 1324 (error "Message %d is deleted. Undo delete before moving" msg))
a1b4049d 1325 ((looking-at mh-scan-refiled-msg-regexp)
c26cf6c8
RS
1326 (if (y-or-n-p
1327 (format "Message %d already refiled. Copy to %s as well? "
bdcfe844 1328 msg folder))
c26cf6c8
RS
1329 (mh-exec-cmd "refile" (mh-get-msg-num t) "-link"
1330 "-src" mh-current-folder
bdcfe844 1331 (symbol-name folder))
c26cf6c8
RS
1332 (message "Message not copied.")))
1333 (t
1334 (mh-set-folder-modified-p t)
bdcfe844
BW
1335 (if (null (assoc folder mh-refile-list))
1336 (push (list folder msg) mh-refile-list)
1337 (pushnew msg (cdr (assoc folder mh-refile-list))))
847b8219 1338 (mh-notate msg mh-note-refiled mh-cmd-note)
c26cf6c8
RS
1339 (run-hooks 'mh-refile-msg-hook)))))
1340
c26cf6c8 1341(defun mh-next-msg ()
bdcfe844 1342 "Move backward or forward to the next undeleted message in the buffer."
c26cf6c8
RS
1343 (if (eq mh-next-direction 'forward)
1344 (mh-next-undeleted-msg 1)
1345 (mh-previous-undeleted-msg 1)))
1346
c26cf6c8 1347(defun mh-set-scan-mode ()
bdcfe844 1348 "Display the scan listing buffer, but do not show a message."
c26cf6c8
RS
1349 (if (get-buffer mh-show-buffer)
1350 (delete-windows-on mh-show-buffer))
a1b4049d 1351 (mh-showing-mode 0)
dc9bdc98 1352 (force-mode-line-update)
bdcfe844 1353 (if mh-recenter-summary-flag
c26cf6c8
RS
1354 (mh-recenter nil)))
1355
c26cf6c8 1356(defun mh-undo-msg (msg)
bdcfe844 1357 "Undo the deletion or refile of one MSG."
c26cf6c8 1358 (cond ((memq msg mh-delete-list)
bdcfe844 1359 (setq mh-delete-list (delq msg mh-delete-list)))
c26cf6c8 1360 (t
bdcfe844
BW
1361 (dolist (folder-msg-list mh-refile-list)
1362 (setf (cdr folder-msg-list) (remove msg (cdr folder-msg-list))))
1363 (setq mh-refile-list (remove-if #'(lambda (x) (null (cdr x)))
1364 mh-refile-list))))
c26cf6c8
RS
1365 (mh-notate msg ? mh-cmd-note))
1366
c26cf6c8
RS
1367\f
1368
1369;;; The folder data abstraction.
1370
1371(defun mh-make-folder (name)
bdcfe844
BW
1372 "Create a new mail folder called NAME.
1373Make it the current folder."
c26cf6c8
RS
1374 (switch-to-buffer name)
1375 (setq buffer-read-only nil)
1376 (erase-buffer)
bdcfe844
BW
1377 (if mh-adaptive-cmd-note-flag
1378 (mh-set-cmd-note (mh-message-number-width name)))
c26cf6c8
RS
1379 (setq buffer-read-only t)
1380 (mh-folder-mode)
1381 (mh-set-folder-modified-p nil)
847b8219
KH
1382 (setq buffer-file-name mh-folder-filename)
1383 (mh-make-folder-mode-line))
c26cf6c8 1384
c26cf6c8
RS
1385;;; Ensure new buffers won't get this mode if default-major-mode is nil.
1386(put 'mh-folder-mode 'mode-class 'special)
1387
bdcfe844
BW
1388\f
1389
1390;;; Menu extracted from mh-menubar.el V1.1 (31 July 2001)
1391;;; Menus for folder mode: folder, message, sequence (in that order)
1392;;; folder-mode "Sequence" menu
1393(easy-menu-define
1394 mh-folder-sequence-menu mh-folder-mode-map "Menu for MH-E folder-sequence."
1395 '("Sequence"
1396 ["Add Message to Sequence..." mh-put-msg-in-seq (mh-get-msg-num nil)]
1397 ["List Sequences for Message" mh-msg-is-in-seq (mh-get-msg-num nil)]
1398 ["Delete Message from Sequence..." mh-delete-msg-from-seq
1399 (mh-get-msg-num nil)]
1400 ["List Sequences in Folder..." mh-list-sequences t]
1401 ["Delete Sequence..." mh-delete-seq t]
1402 ["Narrow to Sequence..." mh-narrow-to-seq t]
1403 ["Widen from Sequence" mh-widen mh-narrowed-to-seq]
1404 "--"
1405 ["Narrow to Subject Sequence" mh-narrow-to-subject t]
1406 ["Delete Rest of Same Subject" mh-delete-subject t]
1407 "--"
1408 ["Push State Out to MH" mh-update-sequences t]))
1409
1410;;; folder-mode "Message" menu
1411(easy-menu-define
1412 mh-folder-message-menu mh-folder-mode-map "Menu for MH-E folder-message."
1413 '("Message"
1414 ["Show Message" mh-show (mh-get-msg-num nil)]
1415 ["Show Message with Header" mh-header-display (mh-get-msg-num nil)]
1416 ["Next Message" mh-next-undeleted-msg t]
1417 ["Previous Message" mh-previous-undeleted-msg t]
1418 ["Go to First Message" mh-first-msg t]
1419 ["Go to Last Message" mh-last-msg t]
1420 ["Go to Message by Number..." mh-goto-msg t]
1421 ["Modify Message" mh-modify]
1422 ["Delete Message" mh-delete-msg (mh-get-msg-num nil)]
1423 ["Refile Message" mh-refile-msg (mh-get-msg-num nil)]
1424 ["Undo Delete/Refile" mh-undo t]
1425 ["Process Delete/Refile" mh-execute-commands
1426 (or mh-refile-list mh-delete-list)]
1427 "--"
1428 ["Compose a New Message" mh-send t]
1429 ["Reply to Message..." mh-reply (mh-get-msg-num nil)]
1430 ["Forward Message..." mh-forward (mh-get-msg-num nil)]
1431 ["Redistribute Message..." mh-redistribute (mh-get-msg-num nil)]
1432 ["Edit Message Again" mh-edit-again (mh-get-msg-num nil)]
1433 ["Re-edit a Bounced Message" mh-extract-rejected-mail t]
1434 "--"
1435 ["Copy Message to Folder..." mh-copy-msg (mh-get-msg-num nil)]
1436 ["Print Message" mh-print-msg (mh-get-msg-num nil)]
1437 ["Write Message to File..." mh-write-msg-to-file
1438 (mh-get-msg-num nil)]
1439 ["Pipe Message to Command..." mh-pipe-msg (mh-get-msg-num nil)]
1440 ["Unpack Uuencoded Message..." mh-store-msg (mh-get-msg-num nil)]
1441 ["Burst Digest Message" mh-burst-digest (mh-get-msg-num nil)]))
1442
1443;;; folder-mode "Folder" menu
1444(easy-menu-define
1445 mh-folder-folder-menu mh-folder-mode-map "Menu for MH-E folder."
1446 '("Folder"
1447 ["Incorporate New Mail" mh-inc-folder t]
1448 ["Toggle Show/Folder" mh-toggle-showing t]
1449 ["Execute Delete/Refile" mh-execute-commands
1450 (or mh-refile-list mh-delete-list)]
1451 ["Rescan Folder" mh-rescan-folder t]
1452 ["Thread Folder" mh-toggle-threads
1453 (not (memq 'unthread mh-view-ops))]
1454 ["Pack Folder" mh-pack-folder t]
1455 ["Sort Folder" mh-sort-folder t]
1456 "--"
1457 ["List Folders" mh-list-folders t]
1458 ["Visit a Folder..." mh-visit-folder t]
1459 ["Search a Folder..." mh-search-folder t]
1460 ["Indexed Search..." mh-index-search t]
1461 "--"
1462 ["Quit MH-E" mh-quit t]))
1463
1464\f
1465
1466;;; Support for emacs21 toolbar using gnus/message.el icons (and code).
1467(eval-when-compile (defvar tool-bar-map))
1468(defvar mh-folder-tool-bar-map nil)
1469(defvar mh-folder-seq-tool-bar-map nil
1470 "Tool-bar to use when narrowed to a sequence in MH-Folder buffers.")
1471(when (and (fboundp 'tool-bar-add-item)
1472 tool-bar-mode)
1473 (setq mh-folder-tool-bar-map
1474 (let ((tool-bar-map (make-sparse-keymap)))
1475 (tool-bar-add-item "mail" 'mh-inc-folder 'mh-foldertoolbar-inc-folder
1476 :help "Incorporate new mail in Inbox")
1477 (tool-bar-add-item "attach" 'mh-mime-save-parts
1478 'mh-foldertoolbar-mime-save-parts
1479 :help "Save MIME parts")
1480
1481 (tool-bar-add-item "left_arrow" 'mh-previous-undeleted-msg
1482 'mh-foldertoolbar-prev :help "Previous message")
1483 (tool-bar-add-item "page-down" 'mh-page-msg 'mh-foldertoolbar-page
1484 :help "Page this message")
1485 (tool-bar-add-item "right_arrow" 'mh-next-undeleted-msg
1486 'mh-foldertoolbar-next :help "Next message")
1487
1488 (tool-bar-add-item "close" 'mh-delete-msg 'mh-foldertoolbar-delete
1489 :help "Mark for deletion")
1490 (tool-bar-add-item "refile" 'mh-refile-msg 'mh-foldertoolbar-refile
1491 :help "Refile this message")
1492 (tool-bar-add-item "undo" 'mh-undo 'mh-foldertoolbar-undo
1493 :help "Undo this mark")
1494 (tool-bar-add-item "execute" 'mh-execute-commands 'mh-foldertoolbar-exec
1495 :help "Perform moves and deletes")
1496
1497 (tool-bar-add-item "show" 'mh-toggle-showing
1498 'mh-foldertoolbar-toggle-show
1499 :help "Toggle showing message")
1500
1501 (cond
1502 (mh-tool-bar-reply-3-buttons-flag
1503 (tool-bar-add-item "reply-from" (lambda (&optional arg)
1504 (interactive "P")
1505 (mh-reply (mh-get-msg-num nil)
1506 "from" arg))
1507 'mh-foldertoolbar-reply-from
1508 :help "Reply to \"from\"")
1509 (tool-bar-add-item "reply-to" (lambda (&optional arg)
1510 (interactive "P")
1511 (mh-reply (mh-get-msg-num nil)
1512 "to" arg))
1513 'mh-foldertoolbar-reply-to
1514 :help "Reply to \"to\"")
1515 (tool-bar-add-item "reply-all" (lambda (&optional arg)
1516 (interactive "P")
1517 (mh-reply (mh-get-msg-num nil)
1518 "all" arg))
1519 'mh-foldertoolbar-reply-all
1520 :help "Reply to \"all\""))
1521 (t
1522 (tool-bar-add-item "mail/reply2" 'mh-reply 'mh-foldertoolbar-reply
1523 :help "Reply to this message")))
1524 (tool-bar-add-item "mail_compose" 'mh-send 'mh-foldertoolbar-compose
1525 :help "Compose new message")
1526
1527 (tool-bar-add-item "rescan" 'mh-rescan-folder 'mh-foldertoolbar-rescan
1528 :help "Rescan this folder")
1529 (tool-bar-add-item "repack" 'mh-pack-folder 'mh-foldertoolbar-pack
1530 :help "Repack this folder")
1531
1532 (tool-bar-add-item "search"
1533 (lambda (&optional arg)
1534 (interactive "P")
1535 (call-interactively mh-tool-bar-search-function))
1536 'mh-foldertoolbar-search :help "Search")
1537 (tool-bar-add-item "fld_open" 'mh-visit-folder 'mh-foldertoolbar-visit
1538 :help "Visit other folder")
1539
1540 (tool-bar-add-item "preferences" (lambda ()
1541 (interactive)
1542 (customize-group "mh"))
1543 'mh-foldertoolbar-customize
1544 :help "mh-e preferences")
1545 (tool-bar-add-item "help" (lambda ()
1546 (interactive)
1547 (Info-goto-node "(mh-e)Top"))
1548 'mh-foldertoolbar-help :help "Help")
1549 tool-bar-map))
1550
1551 (setq mh-folder-seq-tool-bar-map
1552 (let ((tool-bar-map (copy-keymap mh-folder-tool-bar-map)))
1553 (tool-bar-add-item "widen" 'mh-widen 'mh-foldertoolbar-widen
1554 :help "Widen from this sequence")
1555 tool-bar-map))
1556 )
1557
1558\f
1559
1560(defmacro mh-remove-xemacs-horizontal-scrollbar ()
1561 "Get rid of the horizontal scrollbar that XEmacs insists on putting in."
1562 (when mh-xemacs-flag
1563 `(if (and (featurep 'scrollbar)
1564 (fboundp 'set-specifier))
1565 (set-specifier horizontal-scrollbar-visible-p nil
1566 (cons (current-buffer) nil)))))
1567
1568(defmacro mh-write-file-functions-compat ()
1569 "Return `write-file-functions' if it exists.
1570Otherwise return `local-write-file-hooks'. This macro exists purely for
1571compatibility. The former symbol is used in Emacs 21.4 onward while the latter
1572is used in previous versions and XEmacs."
1573 (if (boundp 'write-file-functions)
1574 ''write-file-functions ;Emacs 21.4
1575 ''local-write-file-hooks)) ;<Emacs 21.4, XEmacs
1576
a1b4049d 1577(define-derived-mode mh-folder-mode fundamental-mode "MH-Folder"
bdcfe844 1578 "Major MH-E mode for \"editing\" an MH folder scan listing.\\<mh-folder-mode-map>
a1b4049d 1579
c26cf6c8
RS
1580You can show the message the cursor is pointing to, and step through the
1581messages. Messages can be marked for deletion or refiling into another
1582folder; these commands are executed all at once with a separate command.
1583
1584A prefix argument (\\[universal-argument]) to delete, refile, list, or undo
a1b4049d
BW
1585applies the action to a message sequence. If `transient-mark-mode',
1586is non-nil, the action is applied to the region.
c26cf6c8 1587
a1b4049d
BW
1588Options that control this mode can be changed with \\[customize-group];
1589specify the \"mh\" group. In particular, please see the `mh-scan-format-file'
1590option if you wish to modify scan's format.
c26cf6c8 1591
a1b4049d 1592When a folder is visited, the hook `mh-folder-mode-hook' is run.
c26cf6c8 1593
a1b4049d 1594\\{mh-folder-mode-map}"
c26cf6c8 1595
a1b4049d
BW
1596 (make-local-variable 'font-lock-defaults)
1597 (setq font-lock-defaults '(mh-folder-font-lock-keywords t))
847b8219 1598 (mh-make-local-vars
c26cf6c8
RS
1599 'mh-current-folder (buffer-name) ; Name of folder, a string
1600 'mh-show-buffer (format "show-%s" (buffer-name)) ; Buffer that displays msgs
1601 'mh-folder-filename ; e.g. "/usr/foobar/Mail/inbox/"
1602 (file-name-as-directory (mh-expand-file-name (buffer-name)))
a1b4049d 1603 'mh-showing-mode nil ; Show message also?
c26cf6c8
RS
1604 'mh-delete-list nil ; List of msgs nums to delete
1605 'mh-refile-list nil ; List of folder names in mh-seq-list
1606 'mh-seq-list nil ; Alist of (seq . msgs) nums
1607 'mh-seen-list nil ; List of displayed messages
1608 'mh-next-direction 'forward ; Direction to move to next message
1609 'mh-narrowed-to-seq nil ; Sequence display is narrowed to
bdcfe844
BW
1610 'mh-view-ops () ; Stack that keeps track of the order
1611 ; in which narrowing/threading has been
1612 ; carried out.
c26cf6c8
RS
1613 'mh-first-msg-num nil ; Number of first msg in buffer
1614 'mh-last-msg-num nil ; Number of last msg in buffer
942fc772 1615 'mh-msg-count nil ; Number of msgs in buffer
847b8219 1616 'mh-mode-line-annotation nil ; Indiction this is not the full folder
c26cf6c8 1617 'mh-previous-window-config nil) ; Previous window configuration
bdcfe844 1618 (mh-remove-xemacs-horizontal-scrollbar)
c26cf6c8
RS
1619 (setq truncate-lines t)
1620 (auto-save-mode -1)
1621 (setq buffer-offer-save t)
bdcfe844 1622 (add-hook (mh-write-file-functions-compat) 'mh-execute-commands nil t)
c26cf6c8 1623 (make-local-variable 'revert-buffer-function)
a1b4049d
BW
1624 (make-local-variable 'hl-line-mode) ; avoid pollution
1625 (if (fboundp 'hl-line-mode)
1626 (hl-line-mode 1))
c26cf6c8 1627 (setq revert-buffer-function 'mh-undo-folder)
a1b4049d 1628 (or (assq 'mh-showing-mode minor-mode-alist)
c26cf6c8 1629 (setq minor-mode-alist
a1b4049d
BW
1630 (cons '(mh-showing-mode " Show") minor-mode-alist)))
1631 (easy-menu-add mh-folder-sequence-menu)
1632 (easy-menu-add mh-folder-message-menu)
1633 (easy-menu-add mh-folder-folder-menu)
1634 (if (and (boundp 'tool-bar-mode) tool-bar-mode)
bdcfe844
BW
1635 (set (make-local-variable 'tool-bar-map) mh-folder-tool-bar-map))
1636 (if (and mh-xemacs-flag
1637 font-lock-auto-fontify)
1638 (turn-on-font-lock))) ; Force font-lock in XEmacs.
c26cf6c8 1639
847b8219 1640(defun mh-make-local-vars (&rest pairs)
bdcfe844
BW
1641 "Initialize local variables according to the variable-value PAIRS."
1642
c26cf6c8 1643 (while pairs
1e495fc7 1644 (set (make-local-variable (car pairs)) (car (cdr pairs)))
c26cf6c8
RS
1645 (setq pairs (cdr (cdr pairs)))))
1646
bdcfe844
BW
1647(defun mh-scan-folder (folder range &optional dont-exec-pending)
1648 "Scan the FOLDER over the RANGE.
1649If the optional argument DONT-EXEC-PENDING is non-nil then pending deletes and
1650refiles aren't carried out.
1651Return in the folder's buffer."
c26cf6c8
RS
1652 (cond ((null (get-buffer folder))
1653 (mh-make-folder folder))
1654 (t
bdcfe844 1655 (or dont-exec-pending (mh-process-or-undo-commands folder))
c26cf6c8
RS
1656 (switch-to-buffer folder)))
1657 (mh-regenerate-headers range)
a1b4049d 1658 (if (zerop (buffer-size))
bdcfe844
BW
1659 (if (equal range "all")
1660 (message "Folder %s is empty" folder)
1661 (message "No messages in %s, range %s" folder range))
1662 (mh-goto-cur-msg))
1663 (save-excursion
1664 (when dont-exec-pending
1665 ;; Re-annotate messages to be refiled...
1666 (dolist (folder-msg-list mh-refile-list)
1667 (dolist (msg (cdr folder-msg-list))
1668 (mh-notate msg mh-note-refiled mh-cmd-note)))
1669 ;; Re-annotate messages to be deleted...
1670 (dolist (msg mh-delete-list)
1671 (mh-notate msg mh-note-deleted mh-cmd-note)))))
c26cf6c8 1672
847b8219 1673(defun mh-regenerate-headers (range &optional update)
bdcfe844
BW
1674 "Scan folder over range RANGE.
1675If UPDATE, append the scan lines, otherwise replace."
847b8219 1676 (let ((folder mh-current-folder)
bdcfe844 1677 (range (if (and range (atom range)) (list range) range))
847b8219 1678 scan-start)
c26cf6c8
RS
1679 (message "Scanning %s..." folder)
1680 (with-mh-folder-updating (nil)
847b8219
KH
1681 (if update
1682 (goto-char (point-max))
bdcfe844
BW
1683 (delete-region (point-min) (point-max))
1684 (if mh-adaptive-cmd-note-flag
1685 (mh-set-cmd-note (mh-message-number-width folder))))
847b8219 1686 (setq scan-start (point))
bdcfe844
BW
1687 (apply #'mh-exec-cmd-output
1688 mh-scan-prog nil
1689 (mh-scan-format)
1690 "-noclear" "-noheader"
1691 "-width" (window-width)
1692 folder range)
847b8219 1693 (goto-char scan-start)
c26cf6c8 1694 (cond ((looking-at "scan: no messages in")
a1b4049d
BW
1695 (keep-lines mh-scan-valid-regexp)) ; Flush random scan lines
1696 ((looking-at "scan: bad message list ")
1697 (keep-lines mh-scan-valid-regexp))
c26cf6c8
RS
1698 ((looking-at "scan: ")) ; Keep error messages
1699 (t
a1b4049d 1700 (keep-lines mh-scan-valid-regexp))) ; Flush random scan lines
c26cf6c8
RS
1701 (setq mh-seq-list (mh-read-folder-sequences folder nil))
1702 (mh-notate-user-sequences)
847b8219
KH
1703 (or update
1704 (setq mh-mode-line-annotation
bdcfe844 1705 (if (equal range '("all"))
847b8219
KH
1706 nil
1707 mh-partial-folder-mode-line-annotation)))
1708 (mh-make-folder-mode-line))
c26cf6c8
RS
1709 (message "Scanning %s...done" folder)))
1710
bdcfe844
BW
1711(defun mh-generate-new-cmd-note (folder)
1712 "Fix the `mh-cmd-note' value for this FOLDER.
1713
1714After doing an `mh-get-new-mail' operation in this FOLDER, at least
1715one line that looks like a truncated message number was found.
1716
1717Remove the text added by the last `mh-inc' command. It should be the
1718messages cur-last. Call `mh-set-cmd-note' with the widest message number
1719in FOLDER.
1720
1721Reformat the message number width on each line in the buffer and trim
1722the line length to fit in the window.
1723
1724Rescan the FOLDER in the range cur-last in order to display the
1725messages that were removed earlier. They should all fit in the scan
1726line now with no message truncation."
1727 (save-excursion
1728 (let ((maxcol (1- (window-width)))
1729 (old-cmd-note mh-cmd-note)
1730 mh-cmd-note-fmt
1731 msgnum)
1732 ;; Nuke all of the lines just added by the last inc
1733 (delete-char (- (point-max) (point)))
1734 ;; Update the current buffer to reflect the new mh-cmd-note
1735 ;; value needed to display messages.
1736 (mh-set-cmd-note (mh-message-number-width folder))
1737 (setq mh-cmd-note-fmt (concat "%" (format "%d" mh-cmd-note) "d"))
1738 ;; Cleanup the messages that are in the buffer right now
1739 (goto-char (point-min))
1740 (cond ((memq 'unthread mh-view-ops)
1741 (mh-thread-add-spaces (- mh-cmd-note old-cmd-note)))
1742 (t (while (re-search-forward mh-scan-msg-number-regexp nil 0 1)
1743 ;; reformat the number to fix in mh-cmd-note columns
1744 (setq msgnum (string-to-number
1745 (buffer-substring
1746 (match-beginning 1) (match-end 1))))
1747 (replace-match (format mh-cmd-note-fmt msgnum))
1748 ;; trim the line to fix in the window
1749 (end-of-line)
1750 (let ((eol (point)))
1751 (move-to-column maxcol)
1752 (if (<= (point) eol)
1753 (delete-char (- eol (point))))))))
1754 ;; now re-read the lost messages
1755 (goto-char (point-max))
1756 (prog1 (point)
1757 (mh-regenerate-headers "cur-last" t)))))
c26cf6c8
RS
1758
1759(defun mh-get-new-mail (maildrop-name)
bdcfe844
BW
1760 "Read new mail from MAILDROP-NAME into the current buffer.
1761Return in the current buffer."
c26cf6c8
RS
1762 (let ((point-before-inc (point))
1763 (folder mh-current-folder)
bdcfe844 1764 (new-mail-flag nil))
c26cf6c8 1765 (with-mh-folder-updating (t)
f965c3d7
KH
1766 (if maildrop-name
1767 (message "inc %s -file %s..." folder maildrop-name)
1768 (message "inc %s..." folder))
c26cf6c8
RS
1769 (setq mh-next-direction 'forward)
1770 (goto-char (point-max))
1771 (let ((start-of-inc (point)))
bdcfe844 1772 (mh-remove-cur-notation)
c26cf6c8 1773 (if maildrop-name
847b8219
KH
1774 ;; I think MH 5 used "-ms-file" instead of "-file",
1775 ;; which would make inc'ing from maildrops fail.
c26cf6c8 1776 (mh-exec-cmd-output mh-inc-prog nil folder
a1b4049d 1777 (mh-scan-format)
c26cf6c8
RS
1778 "-file" (expand-file-name maildrop-name)
1779 "-width" (window-width)
1780 "-truncate")
bdcfe844
BW
1781 (mh-exec-cmd-output mh-inc-prog nil
1782 (mh-scan-format)
1783 "-width" (window-width)))
f965c3d7
KH
1784 (if maildrop-name
1785 (message "inc %s -file %s...done" folder maildrop-name)
1786 (message "inc %s...done" folder))
c26cf6c8 1787 (goto-char start-of-inc)
847b8219
KH
1788 (cond ((save-excursion
1789 (re-search-forward "^inc: no mail" nil t))
c26cf6c8
RS
1790 (message "No new mail%s%s" (if maildrop-name " in " "")
1791 (if maildrop-name maildrop-name "")))
bdcfe844
BW
1792 ((and (when mh-narrowed-to-seq
1793 (let ((saved-text (buffer-substring-no-properties
1794 start-of-inc (point-max))))
1795 (delete-region start-of-inc (point-max))
1796 (unwind-protect (mh-widen)
1797 (goto-char (point-max))
1798 (setq start-of-inc (point))
1799 (insert saved-text)
1800 (goto-char start-of-inc))))
1801 nil))
1802 ((re-search-forward "^inc:" nil t) ; Error messages
a1b4049d 1803 (error "Error incorporating mail"))
bdcfe844
BW
1804 ((and
1805 (equal mh-scan-format-file t)
1806 mh-adaptive-cmd-note-flag
1807 ;; Have we reached an edge condition?
1808 (save-excursion
1809 (re-search-forward mh-scan-msg-overflow-regexp nil 0 1))
1810 (setq start-of-inc (mh-generate-new-cmd-note folder))
1811 nil))
c26cf6c8 1812 (t
bdcfe844 1813 (setq new-mail-flag t)))
a1b4049d 1814 (keep-lines mh-scan-valid-regexp) ; Flush random scan lines
bdcfe844 1815 (setq mh-seq-list (mh-read-folder-sequences folder t))
c26cf6c8 1816 (mh-notate-user-sequences)
bdcfe844 1817 (if new-mail-flag
c26cf6c8 1818 (progn
942fc772 1819 (mh-make-folder-mode-line)
bdcfe844
BW
1820 (when (memq 'unthread mh-view-ops)
1821 (mh-thread-inc folder start-of-inc))
942fc772 1822 (mh-goto-cur-msg))
c26cf6c8
RS
1823 (goto-char point-before-inc))))))
1824
847b8219 1825(defun mh-make-folder-mode-line (&optional ignored)
bdcfe844
BW
1826 "Set the fields of the mode line for a folder buffer.
1827The optional argument is now obsolete and IGNORED. It used to be used to pass
1828in what is now stored in the buffer-local variable `mh-mode-line-annotation'."
c26cf6c8 1829 (save-excursion
bdcfe844
BW
1830 (save-window-excursion
1831 (mh-first-msg)
1832 (let ((new-first-msg-num (mh-get-msg-num nil)))
1833 (when (or (not (memq 'unthread mh-view-ops))
1834 (null mh-first-msg-num)
1835 (null new-first-msg-num)
1836 (< new-first-msg-num mh-first-msg-num))
1837 (setq mh-first-msg-num new-first-msg-num)))
1838 (mh-last-msg)
1839 (let ((new-last-msg-num (mh-get-msg-num nil)))
1840 (when (or (not (memq 'unthread mh-view-ops))
1841 (null mh-last-msg-num)
1842 (null new-last-msg-num)
1843 (> new-last-msg-num mh-last-msg-num))
1844 (setq mh-last-msg-num new-last-msg-num)))
1845 (setq mh-msg-count (if mh-first-msg-num
1846 (count-lines (point-min) (point-max))
1847 0))
1848 (setq mode-line-buffer-identification
1849 (list (format "{%%b%s} %s msg%s"
1850 (if mh-mode-line-annotation
1851 (format "/%s" mh-mode-line-annotation)
1852 "")
1853 (if (zerop mh-msg-count)
1854 "no"
1855 (format "%d" mh-msg-count))
1856 (if (zerop mh-msg-count)
1857 "s"
1858 (cond ((> mh-msg-count 1)
1859 (format "s (%d-%d)" mh-first-msg-num
1860 mh-last-msg-num))
1861 (mh-first-msg-num
1862 (format " (%d)" mh-first-msg-num))
1863 ("")))))))))
c26cf6c8
RS
1864
1865(defun mh-unmark-all-headers (remove-all-flags)
bdcfe844
BW
1866 "Remove all '+' flags from the folder listing.
1867With non-nil argument REMOVE-ALL-FLAGS, remove all 'D', '^' and '%' flags too.
1868Optimized for speed (i.e., no regular expressions)."
c26cf6c8
RS
1869 (save-excursion
1870 (let ((case-fold-search nil)
847b8219 1871 (last-line (1- (point-max)))
c26cf6c8
RS
1872 char)
1873 (mh-first-msg)
1874 (while (<= (point) last-line)
1875 (forward-char mh-cmd-note)
1876 (setq char (following-char))
1877 (if (or (and remove-all-flags
3bb2a8af
RS
1878 (or (= char (aref mh-note-deleted 0))
1879 (= char (aref mh-note-refiled 0))))
1880 (= char (aref mh-note-cur 0)))
c26cf6c8
RS
1881 (progn
1882 (delete-char 1)
1883 (insert " ")))
847b8219
KH
1884 (if remove-all-flags
1885 (progn
1886 (forward-char 1)
3bb2a8af 1887 (if (= (following-char) (aref mh-note-seq 0))
847b8219
KH
1888 (progn
1889 (delete-char 1)
1890 (insert " ")))))
c26cf6c8
RS
1891 (forward-line)))))
1892
847b8219 1893(defun mh-remove-cur-notation ()
bdcfe844 1894 "Remove old cur notation."
847b8219
KH
1895 (let ((cur-msg (car (mh-seq-to-msgs 'cur))))
1896 (save-excursion
1897 (and cur-msg
1898 (mh-goto-msg cur-msg t t)
a1b4049d 1899 (looking-at mh-scan-cur-msg-number-regexp)
847b8219
KH
1900 (mh-notate nil ? mh-cmd-note)))))
1901
bdcfe844
BW
1902(defun mh-remove-all-notation ()
1903 "Remove all notations on all scan lines that MH-E introduces."
1904 (save-excursion
1905 (goto-char (point-min))
1906 (while (not (eobp))
1907 (mh-notate nil ? mh-cmd-note)
1908 (when (eq (char-after (+ (point) mh-cmd-note 1)) (elt mh-note-seq 0))
1909 (mh-notate nil ? (1+ mh-cmd-note)))
1910 (forward-line))))
1911
1912(defun mh-goto-cur-msg (&optional minimal-changes-flag)
1913 "Position the cursor at the current message.
1914When optional argument MINIMAL-CHANGES-FLAG is non-nil, the function doesn't
1915recenter the folder buffer."
c26cf6c8
RS
1916 (let ((cur-msg (car (mh-seq-to-msgs 'cur))))
1917 (cond ((and cur-msg
847b8219 1918 (mh-goto-msg cur-msg t t))
bdcfe844
BW
1919 (unless minimal-changes-flag
1920 (mh-notate nil mh-note-cur mh-cmd-note)
1921 (mh-recenter 0)
1922 (mh-maybe-show cur-msg)))
c26cf6c8 1923 (t
c26cf6c8
RS
1924 (message "No current message")))))
1925
c26cf6c8 1926(defun mh-process-or-undo-commands (folder)
bdcfe844
BW
1927 "If FOLDER has outstanding commands, then either process or discard them.
1928Called by functions like `mh-sort-folder', so also invalidate show buffer."
c26cf6c8
RS
1929 (set-buffer folder)
1930 (if (mh-outstanding-commands-p)
bdcfe844 1931 (if (or mh-do-not-confirm-flag
c26cf6c8 1932 (y-or-n-p
a1b4049d 1933 "Process outstanding deletes and refiles (or lose them)? "))
c26cf6c8 1934 (mh-process-commands folder)
a1b4049d 1935 (mh-undo-folder)))
c26cf6c8
RS
1936 (mh-update-unseen)
1937 (mh-invalidate-show-buffer))
1938
c26cf6c8 1939(defun mh-process-commands (folder)
bdcfe844
BW
1940 "Process outstanding commands for FOLDER.
1941The value of `mh-folder-updated-hook' is a list of functions to be called,
1942with no arguments, before the commands are processed."
c26cf6c8
RS
1943 (message "Processing deletes and refiles for %s..." folder)
1944 (set-buffer folder)
1945 (with-mh-folder-updating (nil)
a1b4049d
BW
1946 ;; Run the hook while the lists are still valid
1947 (run-hooks 'mh-folder-updated-hook)
1948
c26cf6c8
RS
1949 ;; Update the unseen sequence if it exists
1950 (mh-update-unseen)
1951
bdcfe844
BW
1952 (let ((redraw-needed-flag nil))
1953 ;; Then refile messages
1954 (mh-mapc #'(lambda (folder-msg-list)
1955 (let ((dest-folder (symbol-name (car folder-msg-list)))
1956 (msgs (cdr folder-msg-list)))
1957 (setq redraw-needed-flag t)
1958 (apply #'mh-exec-cmd
1959 "refile" "-src" folder dest-folder
1960 (mh-coalesce-msg-list msgs))
1961 (mh-delete-scan-msgs msgs)))
1962 mh-refile-list)
1963 (setq mh-refile-list ())
1964
1965 ;; Now delete messages
1966 (cond (mh-delete-list
1967 (setq redraw-needed-flag t)
1968 (apply 'mh-exec-cmd "rmm" folder
1969 (mh-coalesce-msg-list mh-delete-list))
1970 (mh-delete-scan-msgs mh-delete-list)
1971 (setq mh-delete-list nil)))
1972
1973 ;; Don't need to remove sequences since delete and refile do so.
1974 ;; Mark cur message
1975 (if (> (buffer-size) 0)
1976 (mh-define-sequence 'cur (list (or (mh-get-msg-num nil) "last"))))
1977
1978 ;; Redraw folder window if needed
1979 (when (and (memq 'unthread mh-view-ops) redraw-needed-flag)
1980 (mh-thread-inc folder (point-max))))
c26cf6c8
RS
1981
1982 (and (buffer-file-name (get-buffer mh-show-buffer))
1983 (not (file-exists-p (buffer-file-name (get-buffer mh-show-buffer))))
1984 ;; If "inc" were to put a new msg in this file,
1985 ;; we would not notice, so mark it invalid now.
1986 (mh-invalidate-show-buffer))
1987
1988 (setq mh-seq-list (mh-read-folder-sequences mh-current-folder nil))
1989 (mh-unmark-all-headers t)
1990 (mh-notate-user-sequences)
1991 (message "Processing deletes and refiles for %s...done" folder)))
1992
c26cf6c8 1993(defun mh-update-unseen ()
bdcfe844
BW
1994 "Synchronize the unseen sequence with MH.
1995Return non-nil iff the MH folder was set.
1996The value of `mh-unseen-updated-hook' is a list of functions to be called,
1997with no arguments, after the unseen sequence is updated."
c26cf6c8 1998 (if mh-seen-list
847b8219
KH
1999 (let* ((unseen-seq (mh-find-seq mh-unseen-seq))
2000 (unseen-msgs (mh-seq-msgs unseen-seq)))
2001 (if unseen-msgs
2002 (progn
2003 (mh-undefine-sequence mh-unseen-seq mh-seen-list)
a1b4049d 2004 (run-hooks 'mh-unseen-updated-hook)
847b8219
KH
2005 (while mh-seen-list
2006 (setq unseen-msgs (delq (car mh-seen-list) unseen-msgs))
2007 (setq mh-seen-list (cdr mh-seen-list)))
2008 (setcdr unseen-seq unseen-msgs)
2009 t) ;since we set the folder
2010 (setq mh-seen-list nil)))))
c26cf6c8 2011
c26cf6c8 2012(defun mh-delete-scan-msgs (msgs)
bdcfe844 2013 "Delete the scan listing lines for MSGS."
c26cf6c8 2014 (save-excursion
942fc772 2015 (while msgs
bdcfe844
BW
2016 (when (mh-goto-msg (car msgs) t t)
2017 (when (memq 'unthread mh-view-ops)
2018 (mh-thread-forget-message (car msgs)))
2019 (mh-delete-line 1))
942fc772 2020 (setq msgs (cdr msgs)))))
c26cf6c8 2021
c26cf6c8 2022(defun mh-outstanding-commands-p ()
bdcfe844 2023 "Return non-nil if there are outstanding deletes or refiles."
c26cf6c8
RS
2024 (or mh-delete-list mh-refile-list))
2025
847b8219 2026(defun mh-coalesce-msg-list (messages)
bdcfe844
BW
2027 "Give a list of MESSAGES, return a list of message number ranges.
2028Sort of the opposite of `mh-read-msg-list', which expands ranges.
2029Message lists passed to MH programs go through this so
2030command line arguments won't exceed system limits."
847b8219
KH
2031 (let ((msgs (sort (copy-sequence messages) 'mh-greaterp))
2032 (range-high nil)
2033 (prev -1)
2034 (ranges nil))
2035 (while prev
2036 (if range-high
2037 (if (or (not (numberp prev))
3bb2a8af 2038 (not (equal (car msgs) (1- prev))))
847b8219 2039 (progn ;non-sequential, flush old range
3bb2a8af 2040 (if (eq prev range-high)
847b8219
KH
2041 (setq ranges (cons range-high ranges))
2042 (setq ranges (cons (format "%s-%s" prev range-high) ranges)))
2043 (setq range-high nil))))
2044 (or range-high
2045 (setq range-high (car msgs))) ;start new or first range
2046 (setq prev (car msgs))
2047 (setq msgs (cdr msgs)))
2048 ranges))
2049
2050(defun mh-greaterp (msg1 msg2)
bdcfe844
BW
2051 "Return the greater of two message indicators MSG1 and MSG2.
2052Strings are \"smaller\" than numbers.
2053Legal values are things like \"cur\", \"last\", 1, and 1820."
847b8219
KH
2054 (if (numberp msg1)
2055 (if (numberp msg2)
2056 (> msg1 msg2)
2057 t)
2058 (if (numberp msg2)
2059 nil
2060 (string-lessp msg2 msg1))))
2061
a1b4049d 2062(defun mh-lessp (msg1 msg2)
bdcfe844
BW
2063 "Return the lesser of two message indicators MSG1 and MSG2.
2064Strings are \"smaller\" than numbers.
2065Legal values are things like \"cur\", \"last\", 1, and 1820."
a1b4049d 2066 (not (mh-greaterp msg1 msg2)))
bdcfe844 2067
c26cf6c8
RS
2068\f
2069
2070;;; Basic sequence handling
2071
2072(defun mh-delete-seq-locally (seq)
bdcfe844 2073 "Remove MH-E's record of SEQ."
c26cf6c8
RS
2074 (let ((entry (mh-find-seq seq)))
2075 (setq mh-seq-list (delq entry mh-seq-list))))
2076
2077(defun mh-read-folder-sequences (folder save-refiles)
bdcfe844
BW
2078 "Read and return the predefined sequences for a FOLDER.
2079If SAVE-REFILES is non-nil, then keep the sequences
2080that note messages to be refiled."
c26cf6c8
RS
2081 (let ((seqs ()))
2082 (cond (save-refiles
2083 (mh-mapc (function (lambda (seq) ; Save the refiling sequences
2084 (if (mh-folder-name-p (mh-seq-name seq))
2085 (setq seqs (cons seq seqs)))))
2086 mh-seq-list)))
2087 (save-excursion
2088 (if (eq 0 (mh-exec-cmd-quiet nil "mark" folder "-list"))
2089 (progn
2090 ;; look for name in line of form "cur: 4" or "myseq (private): 23"
2091 (while (re-search-forward "^[^: ]+" nil t)
2092 (setq seqs (cons (mh-make-seq (intern (buffer-substring
2093 (match-beginning 0)
2094 (match-end 0)))
2095 (mh-read-msg-list))
2096 seqs)))
bdcfe844
BW
2097 (delete-region (point-min) (point))))) ; avoid race with
2098 ; mh-process-daemon
c26cf6c8
RS
2099 seqs))
2100
2101(defun mh-read-msg-list ()
bdcfe844
BW
2102 "Return a list of message numbers from point to the end of the line.
2103Expands ranges into set of individual numbers."
c26cf6c8
RS
2104 (let ((msgs ())
2105 (end-of-line (save-excursion (end-of-line) (point)))
2106 num)
2107 (while (re-search-forward "[0-9]+" end-of-line t)
2108 (setq num (string-to-int (buffer-substring (match-beginning 0)
2109 (match-end 0))))
2110 (cond ((looking-at "-") ; Message range
2111 (forward-char 1)
2112 (re-search-forward "[0-9]+" end-of-line t)
2113 (let ((num2 (string-to-int (buffer-substring (match-beginning 0)
2114 (match-end 0)))))
2115 (if (< num2 num)
2116 (error "Bad message range: %d-%d" num num2))
2117 (while (<= num num2)
2118 (setq msgs (cons num msgs))
2119 (setq num (1+ num)))))
847b8219
KH
2120 ((not (zerop num)) ;"pick" outputs "0" to mean no match
2121 (setq msgs (cons num msgs)))))
c26cf6c8
RS
2122 msgs))
2123
2124(defun mh-notate-user-sequences ()
bdcfe844 2125 "Mark the scan listing of all messages in user-defined sequences."
c26cf6c8
RS
2126 (let ((seqs mh-seq-list)
2127 name)
2128 (while seqs
2129 (setq name (mh-seq-name (car seqs)))
2130 (if (not (mh-internal-seq name))
847b8219 2131 (mh-notate-seq name mh-note-seq (1+ mh-cmd-note)))
c26cf6c8
RS
2132 (setq seqs (cdr seqs)))))
2133
c26cf6c8 2134(defun mh-internal-seq (name)
bdcfe844 2135 "Return non-nil if NAME is the name of an internal MH-E sequence."
c26cf6c8
RS
2136 (or (memq name '(answered cur deleted forwarded printed))
2137 (eq name mh-unseen-seq)
2138 (eq name mh-previous-seq)
2139 (mh-folder-name-p name)))
2140
847b8219 2141(defun mh-delete-msg-from-seq (message sequence &optional internal-flag)
a1b4049d
BW
2142 "Delete MESSAGE from SEQUENCE.
2143MESSAGE defaults to displayed message. From Lisp, optional third arg
2144INTERNAL-FLAG non-nil means do not inform MH of the change."
c26cf6c8
RS
2145 (interactive (list (mh-get-msg-num t)
2146 (mh-read-seq-default "Delete from" t)
2147 nil))
847b8219 2148 (let ((entry (mh-find-seq sequence)))
c26cf6c8 2149 (cond (entry
847b8219 2150 (mh-notate-if-in-one-seq message ? (1+ mh-cmd-note) sequence)
c26cf6c8 2151 (if (not internal-flag)
847b8219
KH
2152 (mh-undefine-sequence sequence (list message)))
2153 (setcdr entry (delq message (mh-seq-msgs entry)))))))
c26cf6c8 2154
c26cf6c8 2155(defun mh-undefine-sequence (seq msgs)
bdcfe844 2156 "Remove from the SEQ the list of MSGS."
c26cf6c8
RS
2157 (mh-exec-cmd "mark" mh-current-folder "-delete"
2158 "-sequence" (symbol-name seq)
847b8219 2159 (mh-coalesce-msg-list msgs)))
c26cf6c8 2160
c26cf6c8 2161(defun mh-define-sequence (seq msgs)
bdcfe844
BW
2162 "Define the SEQ to contain the list of MSGS.
2163Do not mark pseudo-sequences or empty sequences.
2164Signals an error if SEQ is an illegal name."
c26cf6c8
RS
2165 (if (and msgs
2166 (not (mh-folder-name-p seq)))
2167 (save-excursion
2168 (mh-exec-cmd-error nil "mark" mh-current-folder "-add" "-zero"
2169 "-sequence" (symbol-name seq)
847b8219 2170 (mh-coalesce-msg-list msgs)))))
c26cf6c8 2171
bdcfe844
BW
2172(defun mh-map-over-seqs (function seq-list)
2173 "Apply FUNCTION to each sequence in SEQ-LIST.
2174The sequence name and the list of messages are passed as arguments."
c26cf6c8 2175 (while seq-list
bdcfe844
BW
2176 (funcall function
2177 (mh-seq-name (car seq-list))
2178 (mh-seq-msgs (car seq-list)))
c26cf6c8
RS
2179 (setq seq-list (cdr seq-list))))
2180
bdcfe844
BW
2181(defun mh-notate-if-in-one-seq (msg character offset seq)
2182 "Notate MSG.
2183The CHARACTER is placed at the given OFFSET from the beginning of the listing.
2184The notation is performed if the MSG is only in SEQ."
847b8219 2185 (let ((in-seqs (mh-seq-containing-msg msg nil)))
c26cf6c8 2186 (if (and (eq seq (car in-seqs)) (null (cdr in-seqs)))
bdcfe844 2187 (mh-notate msg character offset))))
c26cf6c8 2188
bdcfe844
BW
2189(defun mh-seq-containing-msg (msg &optional include-internal-flag)
2190 "Return a list of the sequences containing MSG.
2191If INCLUDE-INTERNAL-FLAG non-nil, include MH-E internal sequences in list."
c26cf6c8
RS
2192 (let ((l mh-seq-list)
2193 (seqs ()))
2194 (while l
847b8219 2195 (and (memq msg (mh-seq-msgs (car l)))
bdcfe844 2196 (or include-internal-flag
847b8219
KH
2197 (not (mh-internal-seq (mh-seq-name (car l)))))
2198 (setq seqs (cons (mh-seq-name (car l)) seqs)))
c26cf6c8
RS
2199 (setq l (cdr l)))
2200 seqs))
2201
c26cf6c8
RS
2202\f
2203
2204;;; User prompting commands.
2205
c26cf6c8 2206(defun mh-read-msg-range (prompt)
bdcfe844 2207 "Read a list of blank-separated messages using the given PROMPT."
c26cf6c8
RS
2208 (let* ((buf (read-string prompt))
2209 (buf-size (length buf))
2210 (start 0)
2211 (input ()))
2212 (while (< start buf-size)
2213 (let ((next (read-from-string buf start buf-size)))
2214 (setq input (cons (car next) input))
2215 (setq start (cdr next))))
2216 (nreverse input)))
2217
2218\f
2219
2220;;; Build the folder-mode keymap:
2221
2222(suppress-keymap mh-folder-mode-map)
a1b4049d 2223
bdcfe844
BW
2224;; Use defalias to make sure the documented primary key bindings
2225;; appear in menu lists.
2226(defalias 'mh-alt-show 'mh-show)
2227(defalias 'mh-alt-refile-msg 'mh-refile-msg)
2228(defalias 'mh-alt-send 'mh-send)
2229(defalias 'mh-alt-visit-folder 'mh-visit-folder)
2230
a1b4049d
BW
2231;; Save the `b' binding for a future `back'. Maybe?
2232(gnus-define-keys mh-folder-mode-map
2233 " " mh-page-msg
2234 "!" mh-refile-or-write-again
2235 "," mh-header-display
bdcfe844 2236 "." mh-alt-show
a1b4049d 2237 ">" mh-write-msg-to-file
bdcfe844 2238 "?" mh-help
a1b4049d 2239 "E" mh-extract-rejected-mail
bdcfe844 2240 "M" mh-modify
a1b4049d
BW
2241 "\177" mh-previous-page
2242 "\C-d" mh-delete-msg-no-motion
bdcfe844
BW
2243 "\t" mh-next-button
2244 [backtab] mh-prev-button
2245 "\M-\t" mh-prev-button
a1b4049d
BW
2246 "\e<" mh-first-msg
2247 "\e>" mh-last-msg
2248 "\ed" mh-redistribute
2249 "\r" mh-show
bdcfe844 2250 "^" mh-alt-refile-msg
a1b4049d
BW
2251 "c" mh-copy-msg
2252 "d" mh-delete-msg
2253 "e" mh-edit-again
2254 "f" mh-forward
2255 "g" mh-goto-msg
2256 "i" mh-inc-folder
bdcfe844 2257 "k" mh-delete-subject
a1b4049d 2258 "l" mh-print-msg
bdcfe844 2259 "m" mh-alt-send
a1b4049d
BW
2260 "n" mh-next-undeleted-msg
2261 "o" mh-refile-msg
2262 "p" mh-previous-undeleted-msg
2263 "q" mh-quit
2264 "r" mh-reply
2265 "s" mh-send
2266 "t" mh-toggle-showing
2267 "u" mh-undo
2268 "x" mh-execute-commands
2269 "|" mh-pipe-msg)
2270
2271(gnus-define-keys (mh-folder-map "F" mh-folder-mode-map)
bdcfe844 2272 "?" mh-prefix-help
a1b4049d 2273 "S" mh-sort-folder
bdcfe844
BW
2274 "f" mh-alt-visit-folder
2275 "i" mh-index-search
a1b4049d
BW
2276 "k" mh-kill-folder
2277 "l" mh-list-folders
bdcfe844 2278 "o" mh-alt-visit-folder
a1b4049d
BW
2279 "p" mh-pack-folder
2280 "r" mh-rescan-folder
2281 "s" mh-search-folder
2282 "u" mh-undo-folder
2283 "v" mh-visit-folder)
2284
2285(gnus-define-keys (mh-sequence-map "S" mh-folder-mode-map)
bdcfe844 2286 "?" mh-prefix-help
a1b4049d
BW
2287 "d" mh-delete-msg-from-seq
2288 "k" mh-delete-seq
2289 "l" mh-list-sequences
2290 "n" mh-narrow-to-seq
2291 "p" mh-put-msg-in-seq
2292 "s" mh-msg-is-in-seq
2293 "w" mh-widen)
2294
2295(gnus-define-keys (mh-thread-map "T" mh-folder-mode-map)
bdcfe844
BW
2296 "?" mh-prefix-help
2297 "t" mh-toggle-threads)
2298
2299(gnus-define-keys (mh-limit-map "/" mh-folder-mode-map)
2300 "?" mh-prefix-help
2301 "s" mh-narrow-to-subject
2302 "w" mh-widen)
a1b4049d
BW
2303
2304(gnus-define-keys (mh-extract-map "X" mh-folder-mode-map)
bdcfe844 2305 "?" mh-prefix-help
a1b4049d
BW
2306 "s" mh-store-msg ;shar
2307 "u" mh-store-msg) ;uuencode
2308
2309(gnus-define-keys (mh-digest-map "D" mh-folder-mode-map)
2310 " " mh-page-digest
bdcfe844 2311 "?" mh-prefix-help
a1b4049d
BW
2312 "\177" mh-page-digest-backwards
2313 "b" mh-burst-digest)
2314
bdcfe844
BW
2315(gnus-define-keys (mh-mime-map "K" mh-folder-mode-map)
2316 "?" mh-prefix-help
2317 "a" mh-mime-save-parts
2318 "i" mh-folder-inline-mime-part
2319 "o" mh-folder-save-mime-part
2320 "v" mh-folder-toggle-mime-part
2321 "\t" mh-next-button
2322 [backtab] mh-prev-button
2323 "\M-\t" mh-prev-button)
2324
a1b4049d 2325(cond
bdcfe844 2326 (mh-xemacs-flag
a1b4049d
BW
2327 (define-key mh-folder-mode-map [button2] 'mh-show-mouse))
2328 (t
2329 (define-key mh-folder-mode-map [mouse-2] 'mh-show-mouse)))
c26cf6c8 2330
942fc772
KH
2331;; "C-c /" prefix is used in mh-folder-mode by pgp.el and mailcrypt
2332
c26cf6c8
RS
2333\f
2334
bdcfe844
BW
2335;;; Help Messages
2336
2337;;; If you add a new prefix, add appropriate text to the nil key.
2338;;;
2339;;; In general, messages are grouped logically. Taking the main commands for
2340;;; example, the first line is "ways to view messages," the second line is
2341;;; "things you can do with messages", and the third is "composing" messages.
2342;;;
2343;;; When adding a new prefix, ensure that the help message contains "what" the
2344;;; prefix is for. For example, if the word "folder" were not present in the
2345;;; `F' entry, it would not be clear what these commands operated upon.
2346(defvar mh-help-messages
2347 '((nil "[i]nc, [.]show, [,]show all, [n]ext, [p]revious,\n"
2348 "[d]elete, [o]refile, e[x]ecute,\n"
2349 "[s]end, [r]eply.\n"
2350 "Prefix characters:\n [F]older, [S]equence, MIME [K]eys, "
2351 "[T]hread, / Limit, e[X]tract, [D]igest.")
2352
2353 (?F "[l]ist, [v]isit folder;\n"
2354 "[t]hread; [s]earch; [i]ndexed search;\n"
2355 "[p]ack; [S]ort; [r]escan; [k]ill")
2356 (?S "[p]ut message in sequence, [n]arrow, [w]iden,\n"
2357 "[s]equences, [l]ist,\n"
2358 "[d]elete message from sequence, [k]ill sequence")
2359 (?T "[t]oggle thread")
2360 (?/ "Limit to [s]ubject; [w]iden")
2361 (?X "un[s]har, [u]udecode message")
2362 (?D "[b]urst digest")
2363 (?K "[v]iew, [i]nline, [o]utput/save MIME part; save [a]ll parts; \n"
2364 "[TAB] next; [SHIFT-TAB] previous"))
2365 "Key binding cheat sheet.
2366
2367This is an associative array which is used to show the most common commands.
2368The key is a prefix char. The value is one or more strings which are
2369concatenated together and displayed in the minibuffer if ? is pressed after
2370the prefix character. The special key nil is used to display the
2371non-prefixed commands.
2372
2373The substitutions described in `substitute-command-keys' are performed as
2374well.")
a1b4049d 2375
bdcfe844 2376\f
a1b4049d 2377
bdcfe844 2378;;; autoload the other MH-E parts
c26cf6c8
RS
2379
2380;;; mh-comp
2381
2382(autoload 'mh-smail "mh-comp"
847b8219 2383 "Compose and send mail with the MH mail system.
bdcfe844 2384This function is an entry point to MH-E, the Emacs front end
847b8219
KH
2385to the MH mail system.
2386See documentation of `\\[mh-send]' for more details on composing mail." t)
2387
c26cf6c8 2388(autoload 'mh-smail-other-window "mh-comp"
847b8219 2389 "Compose and send mail in other window with the MH mail system.
bdcfe844 2390This function is an entry point to MH-E, the Emacs front end
847b8219
KH
2391to the MH mail system.
2392See documentation of `\\[mh-send]' for more details on composing mail." t)
2393
c26cf6c8 2394(autoload 'mh-edit-again "mh-comp"
847b8219
KH
2395 "Clean-up a draft or a message previously sent and make it resendable.
2396Default is the current message.
2397The variable mh-new-draft-cleaned-headers specifies the headers to remove.
2398See also documentation for `\\[mh-send]' function." t)
2399
c26cf6c8 2400(autoload 'mh-extract-rejected-mail "mh-comp"
847b8219
KH
2401 "Extract a letter returned by the mail system and make it resendable.
2402Default is the current message. The variable mh-new-draft-cleaned-headers
2403gives the headers to clean out of the original message.
2404See also documentation for `\\[mh-send]' function." t)
2405
c26cf6c8 2406(autoload 'mh-forward "mh-comp"
847b8219
KH
2407 "Forward a message or message sequence. Defaults to displayed message.
2408If optional prefix argument provided, then prompt for the message sequence.
2409See also documentation for `\\[mh-send]' function." t)
2410
c26cf6c8 2411(autoload 'mh-redistribute "mh-comp"
847b8219
KH
2412 "Redistribute a letter.
2413Depending on how your copy of MH was compiled, you may need to change the
2414setting of the variable mh-redist-full-contents. See its documentation." t)
2415
c26cf6c8 2416(autoload 'mh-send "mh-comp"
847b8219
KH
2417 "Compose and send a letter.
2418The file named by `mh-comp-formfile' will be used as the form.
bdcfe844 2419Do not call this function from outside MH-E; use \\[mh-smail] instead.
847b8219
KH
2420The letter is composed in mh-letter-mode; see its documentation for more
2421details. If `mh-compose-letter-function' is defined, it is called on the
2422draft and passed three arguments: to, subject, and cc." t)
2423
c26cf6c8 2424(autoload 'mh-send-other-window "mh-comp"
847b8219 2425 "Compose and send a letter in another window.
bdcfe844 2426Do not call this function from outside MH-E;
847b8219
KH
2427use \\[mh-smail-other-window] instead.
2428See also documentation for `\\[mh-send]' function." t)
2429
c26cf6c8 2430(autoload 'mh-letter-mode "mh-comp"
bdcfe844 2431 "Mode for composing letters in MH-E.
847b8219 2432For more details, type \\[describe-mode] while in MH-Letter mode." t)
c26cf6c8 2433
c26cf6c8
RS
2434;;; mh-funcs
2435
2436(autoload 'mh-burst-digest "mh-funcs"
847b8219
KH
2437 "Burst apart the current message, which should be a digest.
2438The message is replaced by its table of contents and the messages from the
2439digest are inserted into the folder after that message." t)
2440
c26cf6c8 2441(autoload 'mh-copy-msg "mh-funcs"
847b8219
KH
2442 "Copy to another FOLDER the specified MESSAGE(s) without deleting them.
2443Default is the displayed message. If optional prefix argument is
2444provided, then prompt for the message sequence." t)
2445
c26cf6c8
RS
2446(autoload 'mh-kill-folder "mh-funcs"
2447 "Remove the current folder." t)
847b8219 2448
c26cf6c8
RS
2449(autoload 'mh-list-folders "mh-funcs"
2450 "List mail folders." t)
847b8219 2451
c26cf6c8 2452(autoload 'mh-pack-folder "mh-funcs"
847b8219
KH
2453 "Renumber the messages of a folder to be 1..n.
2454First, offer to execute any outstanding commands for the current folder.
2455If optional prefix argument provided, prompt for the range of messages
2456to display after packing. Otherwise, show the entire folder." t)
2457
c26cf6c8 2458(autoload 'mh-pipe-msg "mh-funcs"
847b8219
KH
2459 "Pipe the current message through the given shell COMMAND.
2460If INCLUDE-HEADERS (prefix argument) is provided, send the entire message.
2461Otherwise just send the message's body without the headers." t)
2462
c26cf6c8
RS
2463(autoload 'mh-page-digest "mh-funcs"
2464 "Advance displayed message to next digested message." t)
847b8219 2465
c26cf6c8
RS
2466(autoload 'mh-page-digest-backwards "mh-funcs"
2467 "Back up displayed message to previous digested message." t)
847b8219 2468
c26cf6c8 2469(autoload 'mh-print-msg "mh-funcs"
847b8219
KH
2470 "Print MESSAGE(s) (default: displayed message) on printer.
2471If optional prefix argument provided, then prompt for the message sequence.
2472The variable mh-lpr-command-format is used to generate the print command.
2473The messages are formatted by mhl. See the variable mhl-formfile." t)
2474
c26cf6c8 2475(autoload 'mh-sort-folder "mh-funcs"
847b8219
KH
2476 "Sort the messages in the current folder by date.
2477Calls the MH program sortm to do the work.
2478The arguments in the list mh-sortm-args are passed to sortm
2479if this function is passed an argument." t)
2480
c26cf6c8 2481(autoload 'mh-store-msg "mh-funcs"
86a32538 2482 "Store the file(s) contained in the current message into DIRECTORY.
847b8219
KH
2483The message can contain a shar file or uuencoded file.
2484Default directory is the last directory used, or initially the value of
2485mh-store-default-directory or the current directory." t)
2486
86a32538
RS
2487(autoload 'mh-store-buffer "mh-funcs"
2488 "Store the file(s) contained in the current buffer into DIRECTORY.
847b8219
KH
2489The buffer can contain a shar file or uuencoded file.
2490Default directory is the last directory used, or initially the value of
2491`mh-store-default-directory' or the current directory." t)
c26cf6c8 2492
bdcfe844
BW
2493(autoload 'mh-help "mh-funcs"
2494 "Display cheat sheet for MH-E commands in minibuffer." t)
2495
2496(autoload 'mh-prefix-help "mh-funcs"
2497 "Display cheat sheet for the commands of the current prefix in minibuffer."
2498 t)
c26cf6c8
RS
2499
2500;;; mh-pick
2501
2502(autoload 'mh-search-folder "mh-pick"
847b8219
KH
2503 "Search FOLDER for messages matching a pattern.
2504Add the messages found to the sequence named `search'." t)
c26cf6c8
RS
2505
2506;;; mh-seq
2507
a1b4049d
BW
2508(autoload 'mh-region-to-sequence "mh-seq"
2509 "Define sequence 'region as the messages in selected region." t)
c26cf6c8
RS
2510(autoload 'mh-delete-seq "mh-seq"
2511 "Delete the SEQUENCE." t)
2512(autoload 'mh-list-sequences "mh-seq"
2513 "List the sequences defined in FOLDER." t)
2514(autoload 'mh-msg-is-in-seq "mh-seq"
2515 "Display the sequences that contain MESSAGE (default: displayed message)." t)
2516(autoload 'mh-narrow-to-seq "mh-seq"
847b8219
KH
2517 "Restrict display of this folder to just messages in SEQUENCE
2518Use \\[mh-widen] to undo this command." t)
2519(autoload 'mh-put-msg-in-seq "mh-seq"
2520 "Add MESSAGE(s) (default: displayed message) to SEQUENCE.
2521If optional prefix argument provided, then prompt for the message sequence." t)
c26cf6c8 2522(autoload 'mh-rename-seq "mh-seq"
847b8219 2523 "Rename SEQUENCE to have NEW-NAME." t)
bdcfe844 2524(autoload 'mh-narrow-to-subject "mh-seq"
a1b4049d
BW
2525 "Narrow to a sequence containing all following messages with same subject."
2526 t)
bdcfe844
BW
2527(autoload 'mh-toggle-threads "mh-seq"
2528 "Toggle threaded view of folder." t)
2529(autoload 'mh-delete-subject "mh-seq"
a1b4049d 2530 "Mark all following messages with same subject to be deleted." t)
a1b4049d 2531
bdcfe844
BW
2532;;; mh-speed
2533
2534(autoload 'mh-folder-speedbar-buttons "mh-speed")
2535(autoload 'mh-show-speedbar-buttons "mh-speed")
2536(autoload 'mh-index-folder-speedbar-buttons "mh-speed")
2537(autoload 'mh-index-show-speedbar-buttons "mh-speed")
2538(autoload 'mh-letter-speedbar-buttons "mh-speed")
c26cf6c8 2539
f1ed9461
DL
2540(dolist (mess '("^Cursor not pointing to message$"
2541 "^There is no other window$"))
2542 (add-to-list 'debug-ignored-errors mess))
2543
bdcfe844
BW
2544(provide 'mh-e)
2545
2546;;; Local Variables:
2547;;; sentence-end-double-space: nil
2548;;; End:
2549
c26cf6c8 2550;;; mh-e.el ends here