(idlwave-shell-set-bp): Fix typo.
[emacs.git] / lisp / mail / mh-e.el
blobe309a37b5ee32a84bfb205fbe92b2e45d54b8c2b
1 ;;; mh-e.el --- GNU Emacs interface to the MH mail system
3 ;; Copyright (C) 1985,86,87,88,90,92,93,94,95,97,2000,2001,2002 Free Software Foundation, Inc.
5 ;; Author: Bill Wohler <wohler@newt.com>
6 ;; Maintainer: Bill Wohler <wohler@newt.com>
7 ;; Version: 6.1.1
8 ;; Keywords: mail
10 ;; This file is part of GNU Emacs.
12 ;; GNU Emacs is free software; you can redistribute it and/or modify
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.
17 ;; GNU Emacs is distributed in the hope that it will be useful,
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.
22 ;; You should have received a copy of the GNU General Public License
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.
27 ;;; Commentary:
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.
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)
39 ;; MH (Message Handler) is a powerful mail reader.
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
43 ;; Questions posting there for information on getting MH and mh-e:
44 ;; http://www.faqs.org/faqs/mail/mh-faq/part1/preamble.html
46 ;; N.B. MH must have been compiled with the MHE compiler flag or several
47 ;; features necessary for mh-e will be missing from MH commands, specifically
48 ;; the -build switch to repl and forw.
50 ;; mh-e is an Emacs interface to the MH mail system.
52 ;; mh-e is supported in GNU Emacs 20 and 21, with MH 6.8.4 and nmh 1.0.4.
54 ;; Mailing Lists:
55 ;; mh-e-users@lists.sourceforge.net
56 ;; mh-e-announce@lists.sourceforge.net
57 ;; mh-e-devel@lists.sourceforge.net
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
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.
67 ;; Feature Requests:
68 ;; https://sourceforge.net/tracker/?atid=363357&group_id=13357&func=browse
70 ;; Support:
71 ;; https://sourceforge.net/tracker/?group_id=13357&atid=213357
73 ;;; Change Log:
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
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.
82 ;; $Id: mh-e.el,v 1.99.1.1 2002/10/01 19:41:43 wohler Exp $
84 ;;; Code:
86 (provide 'mh-e)
87 (require 'mh-utils)
88 (require 'gnus-util)
89 (require 'easymenu)
90 (if (save-match-data (string-match "XEmacs\\|Lucid" emacs-version))
91 (require 'mh-xemacs-compat))
92 (eval-when-compile (require 'cl))
94 (defconst mh-version "6.1.1" "Version number of mh-e.")
96 ;;; Initial Autoloads
98 (autoload 'Info-goto-node "info")
101 ;;; Hooks:
103 (defgroup mh nil
104 "Emacs interface to the MH mail system."
105 :group 'mail)
107 (defgroup mh-hook nil
108 "Hooks to mh-e mode."
109 :prefix "mh-"
110 :group 'mh)
112 (defcustom mh-folder-mode-hook nil
113 "Invoked in MH-Folder mode on a new folder."
114 :type 'hook
115 :group 'mh-hook)
117 (defcustom mh-inc-folder-hook nil
118 "Invoked by \\<mh-folder-mode-map>`\\[mh-inc-folder]' after incorporating mail into a folder."
119 :type 'hook
120 :group 'mh-hook)
122 (defcustom mh-folder-updated-hook nil
123 "Invoked when the folder actions (such as moves and deletes) are performed.
124 Variables that are useful in this hook include `mh-delete-list' and
125 `mh-refile-list' which can be used to see which changes are being made to
126 current folder, `mh-current-folder'."
127 :type 'hook
128 :group 'mh-hook)
130 (defcustom mh-show-hook nil
131 "Invoked after \\<mh-folder-mode-map>`\\[mh-show]' shows a message."
132 :type 'hook
133 :group 'mh-hook)
135 (defcustom mh-show-mode-hook nil
136 "Invoked in MH-Show mode on each message."
137 :type 'hook
138 :group 'mh-hook)
140 (defcustom mh-delete-msg-hook nil
141 "Invoked after marking each message for deletion."
142 :type 'hook
143 :group 'mh-hook)
145 (defcustom mh-refile-msg-hook nil
146 "Invoked after marking each message for refiling."
147 :type 'hook
148 :group 'mh-hook)
150 (defcustom mh-before-quit-hook nil
151 "Invoked by \\<mh-folder-mode-map>`\\[mh-quit]' before quitting mh-e.
152 See also `mh-quit-hook'."
153 :type 'hook
154 :group 'mh-hook)
156 (defcustom mh-quit-hook nil
157 "Invoked after \\<mh-folder-mode-map>`\\[mh-quit]' quits mh-e.
158 See also `mh-before-quit-hook'."
159 :type 'hook
160 :group 'mh-hook)
162 (defcustom mh-unseen-updated-hook nil
163 "Invoked after the unseen sequence has been updated.
164 The variable `mh-seen-list' can be used to obtain the list of messages which
165 will be removed from the unseen sequence."
166 :type 'hook
167 :group 'mh-hook)
169 ;;; Personal preferences:
171 (defcustom mh-lpr-command-format "lpr -J '%s'"
172 "*Format for Unix command that prints a message.
173 The string should be a Unix command line, with the string '%s' where
174 the job's name (folder and message number) should appear. The formatted
175 message text is piped to this command when you type \\<mh-folder-mode-map>`\\[mh-print-msg]'."
176 :type 'string
177 :group 'mh)
179 (defcustom mh-scan-prog "scan"
180 "*Program to run to generate one-line-per-message listing of a folder.
181 Normally \"scan\" or a file name linked to scan. This file is searched
182 for relative to the mh-progs directory unless it is an absolute pathname."
183 :type 'string
184 :group 'mh)
185 (make-variable-buffer-local 'mh-scan-prog)
187 (defcustom mh-inc-prog "inc"
188 "*Program to run to incorporate new mail into a folder.
189 Normally \"inc\". This file is searched for relative to
190 the mh-progs directory unless it is an absolute pathname."
191 :type 'string
192 :group 'mh)
194 (defcustom mh-print-background nil
195 "*Print messages in the background if non-nil.
196 WARNING: do not delete the messages until printing is finished;
197 otherwise, your output may be truncated."
198 :type 'boolean
199 :group 'mh)
201 (defcustom mh-recenter-summary-p nil
202 "*Recenter summary window when the show window is toggled off if non-nil."
203 :type 'boolean
204 :group 'mh)
206 (defcustom mh-do-not-confirm nil
207 "*Non-nil means do not prompt for confirmation.
208 Commands such as `mh-pack-folder' prompt to confirm whether to process
209 outstanding moves and deletes or not before continuing. A non-nil setting will
210 perform the action--which is usually desired but cannot be retracted--without
211 question."
212 :type 'boolean
213 :group 'mh)
215 (defcustom mh-store-default-directory nil
216 "*Last directory used by \\[mh-store-msg]; default for next store.
217 A directory name string, or nil to use current directory."
218 :type '(choice (const :tag "Current" nil)
219 directory)
220 :group 'mh)
222 (defvar mh-note-deleted "D"
223 "String whose first character is used to notate deleted messages.")
225 (defvar mh-note-refiled "^"
226 "String whose first character is used to notate refiled messages.")
228 (defvar mh-note-cur "+"
229 "String whose first character is used to notate the current message.")
231 (defvar mh-partial-folder-mode-line-annotation "select"
232 "Annotation when displaying part of a folder.
233 The string is displayed after the folder's name. NIL for no annotation.")
235 ;;; Parameterize mh-e to work with different scan formats. The defaults work
236 ;;; with the standard MH scan listings, in which the first 4 characters on
237 ;;; the line are the message number, followed by two places for notations.
239 (defcustom mh-scan-format-file t
240 "Specifies the format file to pass to the scan program.
241 If t, the format string will be taken from the either `mh-scan-format-mh'
242 or `mh-scan-format-nmh' depending on whether MH or nmh is in use.
243 If nil, the default scan output will be used.
245 If you customize the scan format, you may need to modify a few variables
246 containing regexps that mh-e uses to identify specific portions of the output.
247 Use `M-x apropos RET mh-scan.*regexp' to obtain a list of these variables."
248 :type '(choice (const :tag "Use mh-e scan format" t)
249 (const :tag "Use default scan format" nil)
250 (file :tag "Specify a scan format file"))
251 :group 'mh)
253 ;; The following scan formats are passed to the scan program if the
254 ;; setting of `mh-scan-format-file' above is nil. They are identical
255 ;; except the later one makes use of the nmh `decode' function to
256 ;; decode RFC 2047 encodings.
258 (defvar mh-scan-format-mh
259 (concat
260 "%4(msg)"
261 "%<(cur)+%| %>"
262 "%<{replied}-"
263 "%?(nonnull(comp{to}))%<(mymbox{to})t%>"
264 "%?(nonnull(comp{cc}))%<(mymbox{cc})c%>"
265 "%?(nonnull(comp{bcc}))%<(mymbox{bcc})b%>"
266 "%?(nonnull(comp{newsgroups}))n%>"
267 "%<(zero) %>"
268 "%02(mon{date})/%02(mday{date})%<{date} %|*%>"
269 "%<(mymbox{from})%<{to}To:%14(friendly{to})%>%>"
270 "%<(zero)%17(friendly{from})%> "
271 "%{subject}%<{body}<<%{body}%>")
272 "*Scan format string for MH, provided to the scan program via the -format arg.
273 This format is identical to the default except that additional hints for
274 fontification have been added to the sixth column.
276 The values of the sixth column, in priority order, are: `-' if the
277 message has been replied to, t if an address on the To: line matches
278 one of the mailboxes of the current user, `c' if the Cc: line matches,
279 `b' if the Bcc: line matches, and `n' if a non-empty Newsgroups: header
280 is present.")
282 (defvar mh-scan-format-nmh
283 (concat
284 "%4(msg)"
285 "%<(cur)+%| %>"
286 "%<{replied}-"
287 "%?(nonnull(comp{to}))%<(mymbox{to})t%>"
288 "%?(nonnull(comp{cc}))%<(mymbox{cc})c%>"
289 "%?(nonnull(comp{bcc}))%<(mymbox{bcc})b%>"
290 "%?(nonnull(comp{newsgroups}))n%>"
291 "%<(zero) %>"
292 "%02(mon{date})/%02(mday{date})%<{date} %|*%>"
293 "%<(mymbox{from})%<{to}To:%14(decode(friendly{to}))%>%>"
294 "%<(zero)%17(decode(friendly{from}))%> "
295 "%(decode{subject})%<{body}<<%{body}%>")
296 "*Scan format string for nmh, provided to the scan program via the -format arg.
297 This format is identical to the default except that additional hints for
298 fontification have been added to the sixth column.
300 The values of the sixth column, in priority order, are: `-' if the
301 message has been replied to, t if an address on the To: line matches
302 one of the mailboxes of the current user, `c' if the Cc: line matches,
303 `b' if the Bcc: line matches, and `n' if a non-empty Newsgroups: header
304 is present.")
306 (defvar mh-scan-good-msg-regexp "^\\(....\\)[^D^]"
307 "Regexp specifying the scan lines that are 'good' messages.
308 The default `mh-folder-font-lock-keywords' expects this expression to contain
309 at least one parenthesized expression which matches the message number.")
311 (defvar mh-scan-deleted-msg-regexp "^\\(....\\)D"
312 "Regexp matching scan lines of deleted messages.
313 The default `mh-folder-font-lock-keywords' expects this expression to contain
314 at least one parenthesized expression which matches the message number.")
316 (defvar mh-scan-refiled-msg-regexp "^\\(....\\)\\^"
317 "Regexp matching scan lines of refiled messages.
318 The default `mh-folder-font-lock-keywords' expects this expression to contain
319 at least one parenthesized expression which matches the message number.")
321 (defvar mh-scan-valid-regexp "^ *[0-9]"
322 "Regexp matching scan lines for messages (not error messages).")
324 (defvar mh-scan-cur-msg-number-regexp "^\\(....\\+\\).*"
325 "Regexp matching scan line for the current message.
326 The default `mh-folder-font-lock-keywords' expects this expression to contain
327 at least one parenthesized expression which matches the message number.
328 Don't disable this regexp as it's needed by non fontifying functions.")
330 (defvar mh-scan-cur-msg-regexp "^\\(....\\+DISABLED.*\\)"
331 "Regexp matching scan line for the current message.
332 The default `mh-folder-font-lock-keywords' expects this expression to contain
333 at least one parenthesized expression which matches the whole line.
334 To enable this feature, remove the string DISABLED from the regexp.")
336 (defvar mh-scan-date-regexp "\\([0-9][0-9]/[0-9][0-9]\\)"
337 "Regexp matching a valid date in scan lines.
338 The default `mh-folder-font-lock-keywords' expects this expression to contain
339 only one parenthesized expression which matches the date field
340 \(see `mh-scan-format-regexp').")
342 (defvar mh-scan-rcpt-regexp "\\(To:\\)\\(..............\\)"
343 "Regexp specifying the recipient in scan lines for messages we sent.
344 The default `mh-folder-font-lock-keywords' expects this expression to contain
345 two parenthesized expressions. The first is expected to match the To:
346 that the default scan format file generates. The second is expected to match
347 the recipient's name.")
349 (defvar mh-scan-body-regexp "\\(<<\\([^\n]+\\)?\\)"
350 "Regexp matching the message body beginning displayed in scan lines.
351 The default `mh-folder-font-lock-keywords' expects this expression to contain
352 at least one parenthesized expression which matches the body text.")
354 (defvar mh-scan-subject-regexp
355 "^...............................\\([Rr][Ee]:\\s-*\\)*\\([^<\n]*\\)"
356 "*Regexp matching the subject string in MH folder mode.
357 The default `mh-folder-font-lock-keywords' expects this expression to contain
358 at least two parenthesized expressions. The first is expected to match the Re:
359 string, if any. The second is expected to match the subject line itself.")
361 (defvar mh-scan-format-regexp
362 (concat "\\([bct]\\)" mh-scan-date-regexp " \\(..................\\)")
363 "Regexp matching the output of scan using `mh-scan-format-mh' or `mh-scan-format-nmh'.
364 The default `mh-folder-font-lock-keywords' expects this expression to contain
365 at least three parenthesized expressions. The first should match the
366 fontification hint, the second is found in `mh-scan-date-regexp', and the
367 third should match the user name.")
369 (defvar mh-folder-followup-face 'mh-folder-followup-face
370 "Face for highlighting Re: (followup) subject text in MH-Folder buffers.")
371 (defface mh-folder-followup-face
372 '((((class color) (background light))
373 (:foreground "blue3"))
374 (((class color) (background dark))
375 (:foreground "LightGoldenRod"))
377 (:bold t)))
378 "Face for highlighting Re: (followup) subject text in MH-Folder buffers."
379 :group 'mh)
380 (defvar mh-folder-address-face 'mh-folder-address-face
381 "Face for highlighting the address in MH-Folder buffers.")
382 (copy-face 'mh-folder-subject-face 'mh-folder-address-face)
383 (defvar mh-folder-scan-format-face 'mh-folder-scan-format-face
384 "Face for highlighting `mh-scan-format-regexp' matches in MH-Folder buffers.")
385 (copy-face 'mh-folder-followup-face 'mh-folder-scan-format-face)
387 (defvar mh-folder-date-face 'mh-folder-date-face
388 "Face for highlighting the date in MH-Folder buffers.")
389 (defface mh-folder-date-face
390 '((((class color) (background light))
391 (:foreground "snow4"))
392 (((class color) (background dark))
393 (:foreground "snow3"))
395 (:bold t)))
396 "Face for highlighting the date in MH-Folder buffers."
397 :group 'mh)
399 (defvar mh-folder-msg-number-face 'mh-folder-msg-number-face
400 "Face for highlighting the message number in MH-Folder buffers.")
401 (defface mh-folder-msg-number-face
402 '((((class color) (background light))
403 (:foreground "snow4"))
404 (((class color) (background dark))
405 (:foreground "snow3"))
407 (:bold t)))
408 "Face for highlighting the message number in MH-Folder buffers."
409 :group 'mh)
411 (defvar mh-folder-deleted-face 'mh-folder-deleted-face
412 "Face for highlighting deleted messages in MH-Folder buffers.")
413 (copy-face 'mh-folder-msg-number-face 'mh-folder-deleted-face)
415 (defvar mh-folder-cur-msg-face 'mh-folder-cur-msg-face
416 "Face for the current message line in MH-Folder buffers.")
417 (defface mh-folder-cur-msg-face
418 '((((type tty pc) (class color))
419 (:background "LightGreen"))
420 (((class color) (background light))
421 (:background "LightGreen") ;Use this for solid background colour
422 ;;; (:underline t) ;Use this for underlining
424 (((class color) (background dark))
425 (:background "DarkOliveGreen4"))
426 (t (:underline t)))
427 "Face for the current message line in MH-Folder buffers."
428 :group 'mh)
430 ;;mh-folder-subject-face is defined in mh-utils since it's needed there
431 ;;for mh-show-subject-face.
433 (eval-after-load "font-lock"
434 '(progn
435 (defvar mh-folder-refiled-face 'mh-folder-refiled-face
436 "Face for highlighting refiled messages in MH-Folder buffers.")
437 (copy-face 'font-lock-variable-name-face 'mh-folder-refiled-face)
438 (defvar mh-folder-cur-msg-number-face 'mh-folder-cur-msg-number-face
439 "Face for highlighting the current message in MH-Folder buffers.")
440 (copy-face 'font-lock-keyword-face 'mh-folder-cur-msg-number-face)
441 (defvar mh-folder-to-face 'mh-folder-to-face
442 "Face for highlighting the To: string in MH-Folder buffers.")
443 (copy-face 'font-lock-string-face 'mh-folder-to-face)
444 (defvar mh-folder-body-face 'mh-folder-body-face
445 "Face for highlighting body text in MH-Folder buffers.")
446 (copy-face 'font-lock-string-face 'mh-folder-body-face)
448 (defvar mh-folder-font-lock-keywords
449 (list
450 ;; Marked for deletion
451 (list (concat mh-scan-deleted-msg-regexp ".*")
452 '(0 mh-folder-deleted-face))
453 ;; Marked for refile
454 (list (concat mh-scan-refiled-msg-regexp ".*")
455 '(0 mh-folder-refiled-face))
456 ;;after subj
457 (list mh-scan-body-regexp '(1 mh-folder-body-face nil t))
458 '(mh-folder-font-lock-subject
459 (1 mh-folder-followup-face append t)
460 (2 mh-folder-subject-face append t))
461 ;;current msg
462 (list mh-scan-cur-msg-number-regexp
463 '(1 mh-folder-cur-msg-number-face))
464 (list mh-scan-good-msg-regexp
465 '(1 mh-folder-msg-number-face)) ;; Msg number
466 (list mh-scan-date-regexp '(1 mh-folder-date-face)) ;; Date
467 (list mh-scan-rcpt-regexp
468 '(1 mh-folder-to-face) ;; To:
469 '(2 mh-folder-address-face)) ;; address
470 ;; scan font-lock name
471 (list mh-scan-format-regexp
472 '(1 mh-folder-date-face)
473 '(3 mh-folder-scan-format-face))
474 ;; Current message line
475 (list mh-scan-cur-msg-regexp
476 '(1 mh-folder-cur-msg-face prepend t))
477 ;; Unseen messages in bold
478 '(mh-folder-font-lock-unseen (1 'bold append t))
480 "Regexp keywords used to fontify the MH-Folder buffer.")
483 (defun mh-folder-font-lock-subject (limit)
484 "Return mh-e scan subject strings to font-lock between point and LIMIT."
485 (if (not (re-search-forward mh-scan-subject-regexp limit t))
487 (if (match-beginning 1)
488 (set-match-data (list (match-beginning 1) (match-end 2)
489 (match-beginning 1) (match-end 2) nil nil))
490 (set-match-data (list (match-beginning 2) (match-end 2)
491 nil nil (match-beginning 2) (match-end 2))))
494 ;; Fontifify unseen mesages in bold. - Peter S Galbraith <psg@debian.org>
495 (defvar mh-folder-unseen-seq-name nil
496 "Name of unseen sequence.
497 The default for this is provided by the function `mh-folder-unseen-seq-name'
498 On nmh systems.")
500 (defun mh-folder-unseen-seq-name ()
501 "Provide name of unseen sequence from mhparam."
502 (or mh-progs (mh-find-path))
503 (save-excursion
504 (let ((tmp-buffer (get-buffer-create mh-temp-buffer))
505 (unseen-seq-name "unseen"))
506 (set-buffer tmp-buffer)
507 (unwind-protect
508 (progn
509 (call-process (expand-file-name "mhparam" mh-progs)
510 nil '(t t) nil "-component" "Unseen-Sequence")
511 (goto-char (point-min))
512 (if (re-search-forward "Unseen-Sequence: \\(.*\\)$" nil t)
513 (setq unseen-seq-name (match-string 1))))
514 (kill-buffer tmp-buffer))
515 unseen-seq-name)))
517 (defun mh-folder-unseen-seq-list ()
518 "Return a list of unseen message numbers for current folder."
519 (if (not mh-folder-unseen-seq-name)
520 (setq mh-folder-unseen-seq-name (mh-folder-unseen-seq-name)))
521 (cond
522 ((not mh-folder-unseen-seq-name)
523 nil)
525 (let ((folder mh-current-folder))
526 (save-excursion
527 (let ((tmp-buffer (get-buffer-create mh-temp-buffer)))
528 (set-buffer tmp-buffer)
529 (unwind-protect
530 (progn
531 (call-process (expand-file-name "mark" mh-progs)
532 nil '(t t) nil
533 folder "-seq" mh-folder-unseen-seq-name
534 "-list")
535 (goto-char (point-min))
536 (sort (mh-read-msg-list) '<))
537 (kill-buffer tmp-buffer))))))))
539 (defvar mh-folder-unseen-seq-cache nil
540 "Internal cache variable used for font-lock in mh-e.
541 Should only be non-nil through font-lock stepping, and nil once font-lock
542 is done highlighting.")
543 (make-variable-buffer-local 'mh-folder-unseen-seq-cache)
545 (defun mh-folder-font-lock-unseen (limit)
546 "Return unseen message lines to font-lock between point and LIMIT."
547 (if (not mh-folder-unseen-seq-cache)
548 (setq mh-folder-unseen-seq-cache (mh-folder-unseen-seq-list)))
549 (let ((cur-msg (mh-get-msg-num nil)))
550 (cond
551 ((not mh-folder-unseen-seq-cache)
552 nil)
553 ((not cur-msg) ;Presumably at end of buffer
554 (setq mh-folder-unseen-seq-cache nil)
555 nil)
556 ((member cur-msg mh-folder-unseen-seq-cache)
557 (let ((bpoint (progn (beginning-of-line)(point)))
558 (epoint (progn (forward-line 1)(point))))
559 (if (<= limit (point))
560 (setq mh-folder-unseen-seq-cache nil))
561 (set-match-data (list bpoint epoint bpoint epoint))
564 ;; move forward one line at a time, checking each message number.
565 (while (and
566 (= 0 (forward-line 1))
567 (> limit (point))
568 (not (member (mh-get-msg-num nil) mh-folder-unseen-seq-cache))))
569 ;; Examine how we must have exited the loop...
570 (let ((cur-msg (mh-get-msg-num nil)))
571 (cond
572 ((or (not cur-msg)
573 (<= limit (point))
574 (not (member cur-msg mh-folder-unseen-seq-cache)))
575 (setq mh-folder-unseen-seq-cache nil)
576 nil)
577 ((member cur-msg mh-folder-unseen-seq-cache)
578 (let ((bpoint (progn (beginning-of-line)(point)))
579 (epoint (progn (forward-line 1)(point))))
580 (if (<= limit (point))
581 (setq mh-folder-unseen-seq-cache nil))
582 (set-match-data (list bpoint epoint bpoint epoint))
583 t))))))))
584 ;; fontifify unseen mesages in bold. - end
586 ;;; Internal variables:
588 (defvar mh-last-destination nil) ;Destination of last refile or write command.
590 (defvar mh-folder-mode-map (make-keymap)
591 "Keymap for MH folders.")
593 (defvar mh-delete-list nil) ;List of msg numbers to delete.
595 (defvar mh-refile-list nil) ;List of folder names in mh-seq-list.
597 (defvar mh-next-direction 'forward) ;Direction to move to next message.
599 (defvar mh-narrowed-to-seq nil) ;Sequence display is narrowed to or nil if not narrowed.
601 (defvar mh-first-msg-num nil) ;Number of first msg in buffer.
603 (defvar mh-last-msg-num nil) ;Number of last msg in buffer.
605 (defvar mh-mode-line-annotation nil) ;Message range displayed in buffer.
607 ;;; Macros and generic functions:
609 (defun mh-mapc (func list)
610 (while list
611 (funcall func (car list))
612 (setq list (cdr list))))
614 (defun mh-scan-format ()
615 "Generate arguments to the scan program to specify which format string should be used."
616 (if (equal mh-scan-format-file t)
617 (list "-format" (if mh-nmh-p
618 (list mh-scan-format-nmh)
619 (list mh-scan-format-mh)))
620 (if (not (equal mh-scan-format-file nil))
621 (list "-form" mh-scan-format-file))))
625 ;;; Entry points:
627 ;;;###autoload
628 (defun mh-rmail (&optional arg)
629 "Inc(orporate) new mail with MH.
630 Scan an MH folder if ARG is non-nil. This function is an entry point to mh-e,
631 the Emacs front end to the MH mail system."
632 (interactive "P")
633 (mh-find-path)
634 (if arg
635 (call-interactively 'mh-visit-folder)
636 (mh-inc-folder)))
638 ;;;###autoload
639 (defun mh-nmail (&optional arg)
640 "Check for new mail in inbox folder.
641 Scan an MH folder if ARG is non-nil. This function is an entry point to mh-e,
642 the Emacs front end to the MH mail system."
643 (interactive "P")
644 (mh-find-path) ; init mh-inbox
645 (if arg
646 (call-interactively 'mh-visit-folder)
647 (mh-visit-folder mh-inbox)))
651 ;;; User executable mh-e commands:
654 (defun mh-delete-msg (msg-or-seq)
655 "Mark the specified MSG-OR-SEQ for subsequent deletion and move to the next.
657 Default is the displayed message. If optional prefix argument is given then
658 prompt for the message sequence. If variable `transient-mark-mode' is non-nil
659 and the mark is active, then the selected region is marked for deletion."
660 (interactive (list (cond
661 ((and (boundp 'transient-mark-mode)
662 transient-mark-mode mark-active)
663 (mh-region-to-sequence (region-beginning)(region-end))
664 'region)
665 (current-prefix-arg
666 (mh-read-seq-default "Delete" t))
668 (mh-get-msg-num t)))))
669 (mh-delete-msg-no-motion msg-or-seq)
670 (mh-next-msg))
673 (defun mh-delete-msg-no-motion (msg-or-seq)
674 "Mark the specified MSG-OR-SEQ for subsequent deletion.
675 Default is the displayed message. If optional prefix argument is
676 provided, then prompt for the message sequence."
677 (interactive (list (if current-prefix-arg
678 (mh-read-seq-default "Delete" t)
679 (mh-get-msg-num t))))
680 (if (numberp msg-or-seq)
681 (mh-delete-a-msg msg-or-seq)
682 (mh-map-to-seq-msgs 'mh-delete-a-msg msg-or-seq)))
685 (defun mh-execute-commands ()
686 "Process outstanding delete and refile requests."
687 (interactive)
688 (if mh-narrowed-to-seq (mh-widen))
689 (mh-process-commands mh-current-folder)
690 (mh-set-scan-mode)
691 (mh-goto-cur-msg) ; after mh-set-scan-mode for efficiency
692 (mh-make-folder-mode-line)
693 t) ; return t for [local-]write-file-hooks
696 (defun mh-first-msg ()
697 "Move to the first message."
698 (interactive)
699 (goto-char (point-min))
700 (while (and (not (eobp)) (not (looking-at mh-scan-valid-regexp)))
701 (forward-line 1)))
704 (defun mh-header-display ()
705 "Show the current message with all its headers.
706 Displays headers that might have been suppressed by setting the
707 variables `mh-clean-message-header' or `mhl-formfile', or by the fallback
708 behavior of scrolling uninteresting headers off the top of the window.
709 Type \"\\[mh-show]\" to show the message normally again."
710 (interactive)
711 (and (not mh-showing-with-headers)
712 (or mhl-formfile mh-clean-message-header)
713 (mh-invalidate-show-buffer))
714 (let ((mhl-formfile nil)
715 (mh-clean-message-header nil))
716 (mh-show-msg nil)
717 (mh-in-show-buffer (mh-show-buffer)
718 (goto-char (point-min))
719 (mh-recenter 0))
720 (setq mh-showing-with-headers t)))
723 (defun mh-inc-folder (&optional maildrop-name)
724 "Inc(orporate)s new mail into the Inbox folder.
725 Optional argument MAILDROP-NAME specifies an alternate maildrop from the
726 default. If the prefix argument is given, incorporates mail into the current
727 folder, otherwise uses the folder named by `mh-inbox'.
728 Runs `mh-inc-folder-hook' after incorporating new mail.
729 Do not call this function from outside mh-e; use \\[mh-rmail] instead."
730 (interactive (list (if current-prefix-arg
731 (expand-file-name
732 (read-file-name "inc mail from file: "
733 mh-user-path)))))
734 (let ((config (current-window-configuration)))
735 (if (not maildrop-name)
736 (cond ((not (get-buffer mh-inbox))
737 (mh-make-folder mh-inbox)
738 (setq mh-previous-window-config config))
739 ((not (eq (current-buffer) (get-buffer mh-inbox)))
740 (switch-to-buffer mh-inbox)
741 (setq mh-previous-window-config config)))))
742 (mh-get-new-mail maildrop-name)
743 (if mh-showing-mode (mh-show))
744 (run-hooks 'mh-inc-folder-hook))
747 (defun mh-last-msg ()
748 "Move to the last message."
749 (interactive)
750 (goto-char (point-max))
751 (while (and (not (bobp)) (looking-at "^$"))
752 (forward-line -1)))
755 (defun mh-next-undeleted-msg (&optional arg)
756 "Move to the next undeleted message ARG in window."
757 (interactive "p")
758 (setq mh-next-direction 'forward)
759 (forward-line 1)
760 (cond ((re-search-forward mh-scan-good-msg-regexp nil 0 arg)
761 (beginning-of-line)
762 (mh-maybe-show))
764 (forward-line -1)
765 (if (get-buffer mh-show-buffer)
766 (delete-windows-on mh-show-buffer)))))
769 (defun mh-refile-msg (msg-or-seq folder)
770 "Refile MSG-OR-SEQ (default: displayed message) into FOLDER.
771 If optional prefix argument provided, then prompt for message sequence.
772 If variable `transient-mark-mode' is non-nil and the mark is active, then the
773 selected region is marked for refiling."
774 (interactive
775 (list (cond
776 ((and (boundp 'transient-mark-mode) transient-mark-mode mark-active)
777 (mh-region-to-sequence (region-beginning)(region-end))
778 'region)
779 (current-prefix-arg
780 (mh-read-seq-default "Refile" t))
782 (mh-get-msg-num t)))
783 (intern
784 (mh-prompt-for-folder
785 "Destination"
786 (or (and mh-default-folder-for-message-function
787 (let ((refile-file (mh-msg-filename (mh-get-msg-num t))))
788 (save-excursion
789 (set-buffer (get-buffer-create mh-temp-buffer))
790 (erase-buffer)
791 (insert-file-contents refile-file)
792 (let ((buffer-file-name refile-file))
793 (funcall mh-default-folder-for-message-function)))))
794 (and (eq 'refile (car mh-last-destination))
795 (symbol-name (cdr mh-last-destination)))
797 t))))
798 (setq mh-last-destination (cons 'refile folder))
799 (if (numberp msg-or-seq)
800 (mh-refile-a-msg msg-or-seq folder)
801 (mh-map-to-seq-msgs 'mh-refile-a-msg msg-or-seq folder))
802 (mh-next-msg))
805 (defun mh-refile-or-write-again (message)
806 "Re-execute the last refile or write command on the given MESSAGE.
807 Default is the displayed message. Use the same folder or file as the
808 previous refile or write command."
809 (interactive (list (mh-get-msg-num t)))
810 (if (null mh-last-destination)
811 (error "No previous refile or write"))
812 (cond ((eq (car mh-last-destination) 'refile)
813 (mh-refile-a-msg message (cdr mh-last-destination))
814 (message "Destination folder: %s" (cdr mh-last-destination)))
816 (apply 'mh-write-msg-to-file message (cdr mh-last-destination))
817 (message "Destination: %s" (cdr mh-last-destination))))
818 (mh-next-msg))
820 (defun mh-quit ()
821 "Quit the current mh-e folder.
822 Start by running `mh-before-quit-hook'. Restore the previous window
823 configuration, if one exists. Finish by running `mh-quit-hook'."
824 (interactive)
825 (run-hooks 'mh-before-quit-hook)
826 (mh-update-sequences)
827 (mh-invalidate-show-buffer)
828 (bury-buffer (current-buffer))
829 (if (get-buffer mh-show-buffer)
830 (bury-buffer mh-show-buffer))
831 (if (get-buffer mh-temp-buffer)
832 (kill-buffer mh-temp-buffer))
833 (if (get-buffer mh-temp-folders-buffer)
834 (kill-buffer mh-temp-folders-buffer))
835 (if (get-buffer mh-temp-sequences-buffer)
836 (kill-buffer mh-temp-sequences-buffer))
837 (if mh-previous-window-config
838 (set-window-configuration mh-previous-window-config))
839 (run-hooks 'mh-quit-hook))
841 (defun mh-page-msg (&optional arg)
842 "Page the displayed message forwards.
843 Scrolls ARG lines or a full screen if no argument is supplied. Show buffer
844 first if not displayed. Show the next undeleted message if looking at the
845 bottom of the current message."
846 (interactive "P")
847 (if mh-showing-mode
848 (if mh-page-to-next-msg-p
849 (if (equal mh-next-direction 'backward)
850 (mh-previous-undeleted-msg)
851 (mh-next-undeleted-msg))
852 (if (mh-in-show-buffer (mh-show-buffer)
853 (pos-visible-in-window-p (point-max)))
854 (progn
855 (message (format
856 "End of message (Type %s to read %s undeleted message)"
857 (single-key-description last-input-event)
858 (if (equal mh-next-direction 'backward)
859 "previous"
860 "next")))
861 (setq mh-page-to-next-msg-p t))
862 (scroll-other-window arg)))
863 (mh-show)))
866 (defun mh-previous-page (&optional arg)
867 "Page the displayed message backwards.
868 Scrolls ARG lines or a full screen if no argument is supplied."
869 (interactive "P")
870 (mh-in-show-buffer (mh-show-buffer)
871 (scroll-down arg)))
874 (defun mh-previous-undeleted-msg (&optional arg)
875 "Move to the previous undeleted message ARG in window."
876 (interactive "p")
877 (setq mh-next-direction 'backward)
878 (beginning-of-line)
879 (cond ((re-search-backward mh-scan-good-msg-regexp nil 0 arg)
880 (mh-maybe-show))
882 (if (get-buffer mh-show-buffer)
883 (delete-windows-on mh-show-buffer)))))
886 (defun mh-rescan-folder (&optional range)
887 "Rescan a folder after optionally processing the outstanding commands.
888 If optional prefix argument RANGE is provided, prompt for the range of
889 messages to display. Otherwise show the entire folder."
890 (interactive (list (if current-prefix-arg
891 (mh-read-msg-range "Range to scan [all]? ")
892 nil)))
893 (setq mh-next-direction 'forward)
894 (mh-scan-folder mh-current-folder (or range "all")))
897 (defun mh-write-msg-to-file (msg file no-headers)
898 "Append MSG to the end of a FILE.
899 If prefix argument NO-HEADERS is provided, write only the message body.
900 Otherwise send the entire message including the headers."
901 (interactive
902 (list (mh-get-msg-num t)
903 (let ((default-dir (if (eq 'write (car mh-last-destination))
904 (file-name-directory (car (cdr mh-last-destination)))
905 default-directory)))
906 (read-file-name (format "Save message%s in file: "
907 (if current-prefix-arg " body" ""))
908 default-dir
909 (if (eq 'write (car mh-last-destination))
910 (car (cdr mh-last-destination))
911 (expand-file-name "mail.out" default-dir))))
912 current-prefix-arg))
913 (let ((msg-file-to-output (mh-msg-filename msg))
914 (output-file (mh-expand-file-name file)))
915 (setq mh-last-destination (list 'write file (if no-headers 'no-headers)))
916 (save-excursion
917 (set-buffer (get-buffer-create mh-temp-buffer))
918 (erase-buffer)
919 (insert-file-contents msg-file-to-output)
920 (goto-char (point-min))
921 (if no-headers (search-forward "\n\n"))
922 (append-to-file (point) (point-max) output-file))))
925 (defun mh-toggle-showing ()
926 "Toggle the scanning mode/showing mode of displaying messages."
927 (interactive)
928 (if mh-showing-mode
929 (mh-set-scan-mode)
930 (mh-show)))
933 (defun mh-undo (msg-or-seq)
934 "Undo the pending deletion or refile of the specified MSG-OR-SEQ.
935 Default is the displayed message. If optional prefix argument is
936 provided, then prompt for the message sequence.
937 If variable `transient-mark-mode' is non-nil and the mark is active, then the
938 selected region is unmarked."
939 (interactive (list (cond
940 ((and (boundp 'transient-mark-mode)
941 transient-mark-mode mark-active)
942 (mh-region-to-sequence (region-beginning)(region-end))
943 'region)
944 (current-prefix-arg
945 (mh-read-seq-default "Undo" t))
947 (mh-get-msg-num t)))))
948 (cond ((numberp msg-or-seq)
949 (let ((original-position (point)))
950 (beginning-of-line)
951 (while (not (or (looking-at mh-scan-deleted-msg-regexp)
952 (looking-at mh-scan-refiled-msg-regexp)
953 (and (eq mh-next-direction 'forward) (bobp))
954 (and (eq mh-next-direction 'backward)
955 (save-excursion (forward-line) (eobp)))))
956 (forward-line (if (eq mh-next-direction 'forward) -1 1)))
957 (if (or (looking-at mh-scan-deleted-msg-regexp)
958 (looking-at mh-scan-refiled-msg-regexp))
959 (progn
960 (mh-undo-msg (mh-get-msg-num t))
961 (mh-maybe-show))
962 (goto-char original-position)
963 (error "Nothing to undo"))))
965 (mh-map-to-seq-msgs 'mh-undo-msg msg-or-seq)))
966 ;; update the mh-refile-list so mh-outstanding-commands-p will work
967 (mh-mapc (function
968 (lambda (elt)
969 (if (not (mh-seq-to-msgs elt))
970 (setq mh-refile-list (delq elt mh-refile-list)))))
971 mh-refile-list)
972 (if (not (mh-outstanding-commands-p))
973 (mh-set-folder-modified-p nil)))
976 ;;;###autoload
977 (defun mh-version ()
978 "Display version information about mh-e and the MH mail handling system."
979 (interactive)
980 (mh-find-progs)
981 (set-buffer (get-buffer-create mh-temp-buffer))
982 (erase-buffer)
983 ;; mh-e and Emacs versions.
984 (insert "mh-e " mh-version "\n\n" (emacs-version) "\n\n")
985 ;; MH version.
986 (let ((help-start (point)))
987 (condition-case err-data
988 (mh-exec-cmd-output "inc" nil (if mh-nmh-p "-version" "-help"))
989 (file-error (insert (mapconcat 'concat (cdr err-data) ": ") "\n")))
990 (goto-char help-start)
991 (if mh-nmh-p
992 (search-forward "inc -- " nil t)
993 (search-forward "version: " nil t))
994 (delete-region help-start (point)))
995 (goto-char (point-max))
996 (insert "mh-progs:\t" mh-progs "\n"
997 "mh-lib:\t\t" mh-lib "\n"
998 "mh-lib-progs:\t" mh-lib-progs "\n\n")
999 ;; Linux version.
1000 (condition-case ()
1001 (call-process "uname" nil t nil "-a")
1002 (file-error))
1003 (goto-char (point-min))
1004 (display-buffer mh-temp-buffer))
1007 (defun mh-visit-folder (folder &optional range)
1008 "Visit FOLDER and display RANGE of messages.
1009 Do not call this function from outside mh-e; see \\[mh-rmail] instead."
1010 (interactive (list (mh-prompt-for-folder "Visit" mh-inbox t)
1011 (mh-read-msg-range "Range [all]? ")))
1012 (let ((config (current-window-configuration)))
1013 (mh-scan-folder folder (or range "all"))
1014 (setq mh-previous-window-config config))
1015 nil)
1018 (defun mh-update-sequences ()
1019 "Update MH's Unseen sequence and current folder and message.
1020 Flush mh-e's state out to MH. The message at the cursor becomes current."
1021 (interactive)
1022 ;; mh-update-sequences is the opposite of mh-read-folder-sequences,
1023 ;; which updates mh-e's state from MH.
1024 (let ((folder-set (mh-update-unseen))
1025 (new-cur (mh-get-msg-num nil)))
1026 (if new-cur
1027 (let ((seq-entry (mh-find-seq 'cur)))
1028 (mh-remove-cur-notation)
1029 (setcdr seq-entry (list new-cur)) ;delete-seq-locally, add-msgs-to-seq
1030 (mh-define-sequence 'cur (list new-cur))
1031 (beginning-of-line)
1032 (if (looking-at mh-scan-good-msg-regexp)
1033 (mh-notate nil mh-note-cur mh-cmd-note)))
1034 (or folder-set
1035 (save-excursion
1036 ;; psg - mh-current-folder is nil if mh-summary-height < 4 !
1037 ;; So I added this sanity check.
1038 (if (stringp mh-current-folder)
1039 (mh-exec-cmd-quiet t "folder" mh-current-folder "-fast")
1040 (mh-exec-cmd-quiet t "folder" "-fast")))))))
1045 ;;; Support routines.
1047 (defun mh-delete-a-msg (msg)
1048 ;; Delete the MESSAGE.
1049 (save-excursion
1050 (mh-goto-msg msg nil t)
1051 (if (looking-at mh-scan-refiled-msg-regexp)
1052 (error "Message %d is refiled. Undo refile before deleting" msg))
1053 (if (looking-at mh-scan-deleted-msg-regexp)
1055 (mh-set-folder-modified-p t)
1056 (setq mh-delete-list (cons msg mh-delete-list))
1057 (mh-add-msgs-to-seq msg 'deleted t)
1058 (mh-notate msg mh-note-deleted mh-cmd-note)
1059 (run-hooks 'mh-delete-msg-hook))))
1061 (defun mh-refile-a-msg (msg destination)
1062 ;; Refile MESSAGE in FOLDER. FOLDER is a symbol, not a string.
1063 (save-excursion
1064 (mh-goto-msg msg nil t)
1065 (cond ((looking-at mh-scan-deleted-msg-regexp)
1066 (error "Message %d is deleted. Undo delete before moving" msg))
1067 ((looking-at mh-scan-refiled-msg-regexp)
1068 (if (y-or-n-p
1069 (format "Message %d already refiled. Copy to %s as well? "
1070 msg destination))
1071 (mh-exec-cmd "refile" (mh-get-msg-num t) "-link"
1072 "-src" mh-current-folder
1073 (symbol-name destination))
1074 (message "Message not copied.")))
1076 (mh-set-folder-modified-p t)
1077 (if (not (memq destination mh-refile-list))
1078 (setq mh-refile-list (cons destination mh-refile-list)))
1079 (if (not (memq msg (mh-seq-to-msgs destination)))
1080 (mh-add-msgs-to-seq msg destination t))
1081 (mh-notate msg mh-note-refiled mh-cmd-note)
1082 (run-hooks 'mh-refile-msg-hook)))))
1085 (defun mh-next-msg ()
1086 ;; Move backward or forward to the next undeleted message in the buffer.
1087 (if (eq mh-next-direction 'forward)
1088 (mh-next-undeleted-msg 1)
1089 (mh-previous-undeleted-msg 1)))
1092 (defun mh-set-scan-mode ()
1093 ;; Display the scan listing buffer, but do not show a message.
1094 (if (get-buffer mh-show-buffer)
1095 (delete-windows-on mh-show-buffer))
1096 (mh-showing-mode 0)
1097 (force-mode-line-update)
1098 (if mh-recenter-summary-p
1099 (mh-recenter nil)))
1102 (defun mh-undo-msg (msg)
1103 ;; Undo the deletion or refile of one MESSAGE.
1104 (cond ((memq msg mh-delete-list)
1105 (setq mh-delete-list (delq msg mh-delete-list))
1106 (mh-delete-msg-from-seq msg 'deleted t))
1108 (mh-mapc (function (lambda (dest)
1109 (mh-delete-msg-from-seq msg dest t)))
1110 mh-refile-list)))
1111 (mh-notate msg ? mh-cmd-note))
1116 ;;; The folder data abstraction.
1118 (defun mh-make-folder (name)
1119 ;; Create and initialize a new mail folder called NAME and make it the
1120 ;; current folder.
1121 (switch-to-buffer name)
1122 (setq buffer-read-only nil)
1123 (erase-buffer)
1124 (setq buffer-read-only t)
1125 (mh-folder-mode)
1126 (mh-set-folder-modified-p nil)
1127 (setq buffer-file-name mh-folder-filename)
1128 (mh-make-folder-mode-line))
1131 ;;; Ensure new buffers won't get this mode if default-major-mode is nil.
1132 (put 'mh-folder-mode 'mode-class 'special)
1134 (define-derived-mode mh-folder-mode fundamental-mode "MH-Folder"
1135 "Major mh-e mode for \"editing\" an MH folder scan listing.\\<mh-folder-mode-map>
1137 You can show the message the cursor is pointing to, and step through the
1138 messages. Messages can be marked for deletion or refiling into another
1139 folder; these commands are executed all at once with a separate command.
1141 A prefix argument (\\[universal-argument]) to delete, refile, list, or undo
1142 applies the action to a message sequence. If `transient-mark-mode',
1143 is non-nil, the action is applied to the region.
1145 Options that control this mode can be changed with \\[customize-group];
1146 specify the \"mh\" group. In particular, please see the `mh-scan-format-file'
1147 option if you wish to modify scan's format.
1149 When a folder is visited, the hook `mh-folder-mode-hook' is run.
1151 \\{mh-folder-mode-map}"
1153 (make-local-variable 'font-lock-defaults)
1154 (setq font-lock-defaults '(mh-folder-font-lock-keywords t))
1155 (mh-make-local-vars
1156 'mh-current-folder (buffer-name) ; Name of folder, a string
1157 'mh-show-buffer (format "show-%s" (buffer-name)) ; Buffer that displays msgs
1158 'mh-folder-filename ; e.g. "/usr/foobar/Mail/inbox/"
1159 (file-name-as-directory (mh-expand-file-name (buffer-name)))
1160 'mh-showing-mode nil ; Show message also?
1161 'mh-delete-list nil ; List of msgs nums to delete
1162 'mh-refile-list nil ; List of folder names in mh-seq-list
1163 'mh-seq-list nil ; Alist of (seq . msgs) nums
1164 'mh-seen-list nil ; List of displayed messages
1165 'mh-next-direction 'forward ; Direction to move to next message
1166 'mh-narrowed-to-seq nil ; Sequence display is narrowed to
1167 'mh-first-msg-num nil ; Number of first msg in buffer
1168 'mh-last-msg-num nil ; Number of last msg in buffer
1169 'mh-msg-count nil ; Number of msgs in buffer
1170 'mh-mode-line-annotation nil ; Indiction this is not the full folder
1171 'mh-previous-window-config nil) ; Previous window configuration
1172 (setq truncate-lines t)
1173 (auto-save-mode -1)
1174 (setq buffer-offer-save t)
1175 (if (boundp 'local-write-file-hooks)
1176 (setq local-write-file-hooks '(mh-execute-commands)) ;Emacs 19
1177 (make-local-variable 'write-file-hooks)
1178 (setq write-file-hooks '(mh-execute-commands))) ;Emacs 18
1179 (make-local-variable 'revert-buffer-function)
1180 (make-local-variable 'hl-line-mode) ; avoid pollution
1181 (if (fboundp 'hl-line-mode)
1182 (hl-line-mode 1))
1183 (setq revert-buffer-function 'mh-undo-folder)
1184 (or (assq 'mh-showing-mode minor-mode-alist)
1185 (setq minor-mode-alist
1186 (cons '(mh-showing-mode " Show") minor-mode-alist)))
1187 (easy-menu-add mh-folder-sequence-menu)
1188 (easy-menu-add mh-folder-message-menu)
1189 (easy-menu-add mh-folder-folder-menu)
1190 (if (and (boundp 'tool-bar-mode) tool-bar-mode)
1191 (set (make-local-variable 'tool-bar-map) mh-folder-tool-bar-map)))
1194 (defun mh-make-local-vars (&rest pairs)
1195 ;; Take VARIABLE-VALUE pairs and make local variables initialized to the
1196 ;; value.
1197 (while pairs
1198 (set (make-local-variable (car pairs)) (car (cdr pairs)))
1199 (setq pairs (cdr (cdr pairs)))))
1202 (defun mh-scan-folder (folder range)
1203 ;; Scan the FOLDER over the RANGE. Return in the folder's buffer.
1204 (cond ((null (get-buffer folder))
1205 (mh-make-folder folder))
1207 (mh-process-or-undo-commands folder)
1208 (switch-to-buffer folder)))
1209 (mh-regenerate-headers range)
1210 (if (zerop (buffer-size))
1211 (if (equal range "all")
1212 (message "Folder %s is empty" folder)
1213 (message "No messages in %s, range %s" folder range))
1214 (mh-goto-cur-msg)))
1217 (defun mh-regenerate-headers (range &optional update)
1218 ;; scan folder over range RANGE.
1219 ;; If UPDATE, append the scan lines, otherwise replace.
1220 (let ((folder mh-current-folder)
1221 scan-start)
1222 (message "Scanning %s..." folder)
1223 (with-mh-folder-updating (nil)
1224 (if update
1225 (goto-char (point-max))
1226 (erase-buffer))
1227 (setq scan-start (point))
1228 (mh-exec-cmd-output mh-scan-prog nil
1229 (mh-scan-format)
1230 "-noclear" "-noheader"
1231 "-width" (window-width)
1232 folder range)
1233 (goto-char scan-start)
1234 (cond ((looking-at "scan: no messages in")
1235 (keep-lines mh-scan-valid-regexp)) ; Flush random scan lines
1236 ((looking-at "scan: bad message list ")
1237 (keep-lines mh-scan-valid-regexp))
1238 ((looking-at "scan: ")) ; Keep error messages
1240 (keep-lines mh-scan-valid-regexp))) ; Flush random scan lines
1241 (setq mh-seq-list (mh-read-folder-sequences folder nil))
1242 (mh-notate-user-sequences)
1243 (or update
1244 (setq mh-mode-line-annotation
1245 (if (equal range "all")
1247 mh-partial-folder-mode-line-annotation)))
1248 (mh-make-folder-mode-line))
1249 (message "Scanning %s...done" folder)))
1252 (defun mh-get-new-mail (maildrop-name)
1253 ;; Read new mail from a maildrop into the current buffer.
1254 ;; Return in the current buffer.
1255 (let ((point-before-inc (point))
1256 (folder mh-current-folder)
1257 (new-mail-p nil))
1258 (with-mh-folder-updating (t)
1259 (if maildrop-name
1260 (message "inc %s -file %s..." folder maildrop-name)
1261 (message "inc %s..." folder))
1262 (setq mh-next-direction 'forward)
1263 (goto-char (point-max))
1264 (let ((start-of-inc (point)))
1265 (if maildrop-name
1266 ;; I think MH 5 used "-ms-file" instead of "-file",
1267 ;; which would make inc'ing from maildrops fail.
1268 (mh-exec-cmd-output mh-inc-prog nil folder
1269 (mh-scan-format)
1270 "-file" (expand-file-name maildrop-name)
1271 "-width" (window-width)
1272 "-truncate")
1273 (mh-exec-cmd-output mh-inc-prog nil
1274 (mh-scan-format)
1275 "-width" (window-width)))
1276 (if maildrop-name
1277 (message "inc %s -file %s...done" folder maildrop-name)
1278 (message "inc %s...done" folder))
1279 (goto-char start-of-inc)
1280 (cond ((save-excursion
1281 (re-search-forward "^inc: no mail" nil t))
1282 (message "No new mail%s%s" (if maildrop-name " in " "")
1283 (if maildrop-name maildrop-name "")))
1284 ((re-search-forward "^inc:" nil t) ; Error messages
1285 (error "Error incorporating mail"))
1287 (mh-remove-cur-notation)
1288 (setq new-mail-p t)))
1289 (keep-lines mh-scan-valid-regexp) ; Flush random scan lines
1290 (setq mh-seq-list (mh-read-folder-sequences folder t))
1291 (mh-notate-user-sequences)
1292 (if new-mail-p
1293 (progn
1294 (mh-make-folder-mode-line)
1295 (mh-goto-cur-msg))
1296 (goto-char point-before-inc))))))
1299 (defun mh-make-folder-mode-line (&optional ignored)
1300 ;; Set the fields of the mode line for a folder buffer.
1301 ;; The optional argument is now obsolete. It used to be used to pass
1302 ;; in what is now stored in the buffer-local variable
1303 ;; mh-mode-line-annotation.
1304 (save-excursion
1305 (mh-first-msg)
1306 (setq mh-first-msg-num (mh-get-msg-num nil))
1307 (mh-last-msg)
1308 (setq mh-last-msg-num (mh-get-msg-num nil))
1309 (setq mh-msg-count (if mh-first-msg-num
1310 (count-lines (point-min) (point-max))
1312 (setq mode-line-buffer-identification
1313 (list (format "{%%b%s} %s msg%s"
1314 (if mh-mode-line-annotation
1315 (format "/%s" mh-mode-line-annotation)
1317 (if (zerop mh-msg-count)
1318 "no"
1319 (format "%d" mh-msg-count))
1320 (if (zerop mh-msg-count)
1322 (cond ((> mh-msg-count 1)
1323 (format "s (%d-%d)" mh-first-msg-num
1324 mh-last-msg-num))
1325 (mh-first-msg-num
1326 (format " (%d)" mh-first-msg-num))
1327 (""))))))))
1329 (defun mh-unmark-all-headers (remove-all-flags)
1330 ;; Remove all '+' flags from the headers, and if called with a non-nil
1331 ;; argument, remove all 'D', '^' and '%' flags too.
1332 ;; Optimized for speed (i.e., no regular expressions).
1333 (save-excursion
1334 (let ((case-fold-search nil)
1335 (last-line (1- (point-max)))
1336 char)
1337 (mh-first-msg)
1338 (while (<= (point) last-line)
1339 (forward-char mh-cmd-note)
1340 (setq char (following-char))
1341 (if (or (and remove-all-flags
1342 (or (= char (aref mh-note-deleted 0))
1343 (= char (aref mh-note-refiled 0))))
1344 (= char (aref mh-note-cur 0)))
1345 (progn
1346 (delete-char 1)
1347 (insert " ")))
1348 (if remove-all-flags
1349 (progn
1350 (forward-char 1)
1351 (if (= (following-char) (aref mh-note-seq 0))
1352 (progn
1353 (delete-char 1)
1354 (insert " ")))))
1355 (forward-line)))))
1358 (defun mh-remove-cur-notation ()
1359 ;; Remove old cur notation (cf mh-goto-cur-msg code).
1360 (let ((cur-msg (car (mh-seq-to-msgs 'cur))))
1361 (save-excursion
1362 (and cur-msg
1363 (mh-goto-msg cur-msg t t)
1364 (looking-at mh-scan-cur-msg-number-regexp)
1365 (mh-notate nil ? mh-cmd-note)))))
1367 (defun mh-goto-cur-msg ()
1368 ;; Position the cursor at the current message.
1369 (let ((cur-msg (car (mh-seq-to-msgs 'cur))))
1370 (cond ((and cur-msg
1371 (mh-goto-msg cur-msg t t))
1372 (mh-notate nil mh-note-cur mh-cmd-note)
1373 (mh-recenter 0)
1374 (mh-maybe-show cur-msg))
1376 (mh-last-msg)
1377 (message "No current message")))))
1380 (defun mh-process-or-undo-commands (folder)
1381 ;; If FOLDER has outstanding commands, then either process or discard them.
1382 ;; Called by functions like mh-sort-folder, so also invalidate show buffer.
1383 (set-buffer folder)
1384 (if (mh-outstanding-commands-p)
1385 (if (or mh-do-not-confirm
1386 (y-or-n-p
1387 "Process outstanding deletes and refiles (or lose them)? "))
1388 (mh-process-commands folder)
1389 (mh-undo-folder)))
1390 (mh-update-unseen)
1391 (mh-invalidate-show-buffer))
1394 (defun mh-process-commands (folder)
1395 ;; Process outstanding commands for the folder FOLDER.
1396 (message "Processing deletes and refiles for %s..." folder)
1397 (set-buffer folder)
1398 (with-mh-folder-updating (nil)
1399 ;; Run the hook while the lists are still valid
1400 (run-hooks 'mh-folder-updated-hook)
1402 ;; Update the unseen sequence if it exists
1403 (mh-update-unseen)
1405 ;; Then refile messages
1406 (mh-mapc
1407 (function
1408 (lambda (dest)
1409 (let ((msgs (mh-seq-to-msgs dest)))
1410 (cond (msgs
1411 (apply 'mh-exec-cmd "refile"
1412 "-src" folder (symbol-name dest)
1413 (mh-coalesce-msg-list msgs))
1414 (mh-delete-scan-msgs msgs))))))
1415 mh-refile-list)
1416 (setq mh-refile-list nil)
1418 ;; Now delete messages
1419 (cond (mh-delete-list
1420 (apply 'mh-exec-cmd "rmm" folder
1421 (mh-coalesce-msg-list mh-delete-list))
1422 (mh-delete-scan-msgs mh-delete-list)
1423 (setq mh-delete-list nil)))
1425 ;; Don't need to remove sequences since delete and refile do so.
1427 ;; Mark cur message
1428 (if (> (buffer-size) 0)
1429 (mh-define-sequence 'cur (list (or (mh-get-msg-num nil) "last"))))
1431 (and (buffer-file-name (get-buffer mh-show-buffer))
1432 (not (file-exists-p (buffer-file-name (get-buffer mh-show-buffer))))
1433 ;; If "inc" were to put a new msg in this file,
1434 ;; we would not notice, so mark it invalid now.
1435 (mh-invalidate-show-buffer))
1437 (setq mh-seq-list (mh-read-folder-sequences mh-current-folder nil))
1438 (mh-unmark-all-headers t)
1439 (mh-notate-user-sequences)
1440 (message "Processing deletes and refiles for %s...done" folder)))
1443 (defun mh-update-unseen ()
1444 ;; Flush updates to the Unseen sequence out to MH.
1445 ;; Return non-NIL iff set the MH folder.
1446 (if mh-seen-list
1447 (let* ((unseen-seq (mh-find-seq mh-unseen-seq))
1448 (unseen-msgs (mh-seq-msgs unseen-seq)))
1449 (if unseen-msgs
1450 (progn
1451 (mh-undefine-sequence mh-unseen-seq mh-seen-list)
1452 (run-hooks 'mh-unseen-updated-hook)
1453 (while mh-seen-list
1454 (setq unseen-msgs (delq (car mh-seen-list) unseen-msgs))
1455 (setq mh-seen-list (cdr mh-seen-list)))
1456 (setcdr unseen-seq unseen-msgs)
1457 t) ;since we set the folder
1458 (setq mh-seen-list nil)))))
1461 (defun mh-delete-scan-msgs (msgs)
1462 ;; Delete the scan listing lines for each of the msgs in the LIST.
1463 (save-excursion
1464 (while msgs
1465 (if (mh-goto-msg (car msgs) t t)
1466 (mh-delete-line 1))
1467 (setq msgs (cdr msgs)))))
1470 (defun mh-outstanding-commands-p ()
1471 ;; Returns non-nil if there are outstanding deletes or refiles.
1472 (or mh-delete-list mh-refile-list))
1475 (defun mh-coalesce-msg-list (messages)
1476 ;; Give a list of MESSAGES, return a list of message number ranges.
1477 ;; Sort of the opposite of mh-read-msg-list, which expands ranges.
1478 ;; Message lists passed to MH programs go through this so
1479 ;; command line arguments won't exceed system limits.
1480 (let ((msgs (sort (copy-sequence messages) 'mh-greaterp))
1481 (range-high nil)
1482 (prev -1)
1483 (ranges nil))
1484 (while prev
1485 (if range-high
1486 (if (or (not (numberp prev))
1487 (not (equal (car msgs) (1- prev))))
1488 (progn ;non-sequential, flush old range
1489 (if (eq prev range-high)
1490 (setq ranges (cons range-high ranges))
1491 (setq ranges (cons (format "%s-%s" prev range-high) ranges)))
1492 (setq range-high nil))))
1493 (or range-high
1494 (setq range-high (car msgs))) ;start new or first range
1495 (setq prev (car msgs))
1496 (setq msgs (cdr msgs)))
1497 ranges))
1499 (defun mh-greaterp (msg1 msg2)
1500 ;; Sort two message indicators. Strings are "smaller" than numbers.
1501 ;; Legal values are things like "cur", "last", 1, and 1820.
1502 (if (numberp msg1)
1503 (if (numberp msg2)
1504 (> msg1 msg2)
1506 (if (numberp msg2)
1508 (string-lessp msg2 msg1))))
1510 (defun mh-lessp (msg1 msg2)
1511 (not (mh-greaterp msg1 msg2)))
1514 ;;; Basic sequence handling
1516 (defun mh-delete-seq-locally (seq)
1517 ;; Remove mh-e's record of SEQUENCE.
1518 (let ((entry (mh-find-seq seq)))
1519 (setq mh-seq-list (delq entry mh-seq-list))))
1521 (defun mh-read-folder-sequences (folder save-refiles)
1522 ;; Read and return the predefined sequences for a FOLDER.
1523 ;; If SAVE-REFILES is non-nil, then keep the sequences
1524 ;; that note messages to be refiled.
1525 (let ((seqs ()))
1526 (cond (save-refiles
1527 (mh-mapc (function (lambda (seq) ; Save the refiling sequences
1528 (if (mh-folder-name-p (mh-seq-name seq))
1529 (setq seqs (cons seq seqs)))))
1530 mh-seq-list)))
1531 (save-excursion
1532 (if (eq 0 (mh-exec-cmd-quiet nil "mark" folder "-list"))
1533 (progn
1534 ;; look for name in line of form "cur: 4" or "myseq (private): 23"
1535 (while (re-search-forward "^[^: ]+" nil t)
1536 (setq seqs (cons (mh-make-seq (intern (buffer-substring
1537 (match-beginning 0)
1538 (match-end 0)))
1539 (mh-read-msg-list))
1540 seqs)))
1541 (delete-region (point-min) (point))))) ; avoid race with mh-process-daemon
1542 seqs))
1544 (defun mh-read-msg-list ()
1545 ;; Return a list of message numbers from the current point to the end of
1546 ;; the line. Expands ranges into set of individual numbers.
1547 (let ((msgs ())
1548 (end-of-line (save-excursion (end-of-line) (point)))
1549 num)
1550 (while (re-search-forward "[0-9]+" end-of-line t)
1551 (setq num (string-to-int (buffer-substring (match-beginning 0)
1552 (match-end 0))))
1553 (cond ((looking-at "-") ; Message range
1554 (forward-char 1)
1555 (re-search-forward "[0-9]+" end-of-line t)
1556 (let ((num2 (string-to-int (buffer-substring (match-beginning 0)
1557 (match-end 0)))))
1558 (if (< num2 num)
1559 (error "Bad message range: %d-%d" num num2))
1560 (while (<= num num2)
1561 (setq msgs (cons num msgs))
1562 (setq num (1+ num)))))
1563 ((not (zerop num)) ;"pick" outputs "0" to mean no match
1564 (setq msgs (cons num msgs)))))
1565 msgs))
1567 (defun mh-notate-user-sequences ()
1568 ;; Mark the scan listing of all messages in user-defined sequences.
1569 (let ((seqs mh-seq-list)
1570 name)
1571 (while seqs
1572 (setq name (mh-seq-name (car seqs)))
1573 (if (not (mh-internal-seq name))
1574 (mh-notate-seq name mh-note-seq (1+ mh-cmd-note)))
1575 (setq seqs (cdr seqs)))))
1578 (defun mh-internal-seq (name)
1579 ;; Return non-NIL if NAME is the name of an internal mh-e sequence.
1580 (or (memq name '(answered cur deleted forwarded printed))
1581 (eq name mh-unseen-seq)
1582 (eq name mh-previous-seq)
1583 (mh-folder-name-p name)))
1586 (defun mh-delete-msg-from-seq (message sequence &optional internal-flag)
1587 "Delete MESSAGE from SEQUENCE.
1588 MESSAGE defaults to displayed message. From Lisp, optional third arg
1589 INTERNAL-FLAG non-nil means do not inform MH of the change."
1590 (interactive (list (mh-get-msg-num t)
1591 (mh-read-seq-default "Delete from" t)
1592 nil))
1593 (let ((entry (mh-find-seq sequence)))
1594 (cond (entry
1595 (mh-notate-if-in-one-seq message ? (1+ mh-cmd-note) sequence)
1596 (if (not internal-flag)
1597 (mh-undefine-sequence sequence (list message)))
1598 (setcdr entry (delq message (mh-seq-msgs entry)))))))
1601 (defun mh-undefine-sequence (seq msgs)
1602 ;; Remove from the SEQUENCE the list of MSGS.
1603 (mh-exec-cmd "mark" mh-current-folder "-delete"
1604 "-sequence" (symbol-name seq)
1605 (mh-coalesce-msg-list msgs)))
1608 (defun mh-define-sequence (seq msgs)
1609 ;; Define the SEQUENCE to contain the list of MSGS.
1610 ;; Do not mark pseudo-sequences or empty sequences.
1611 ;; Signals an error if SEQUENCE is an illegal name.
1612 (if (and msgs
1613 (not (mh-folder-name-p seq)))
1614 (save-excursion
1615 (mh-exec-cmd-error nil "mark" mh-current-folder "-add" "-zero"
1616 "-sequence" (symbol-name seq)
1617 (mh-coalesce-msg-list msgs)))))
1620 (defun mh-map-over-seqs (func seq-list)
1621 ;; Apply the FUNCTION to each element in the list of SEQUENCES,
1622 ;; passing the sequence name and the list of messages as arguments.
1623 (while seq-list
1624 (funcall func (mh-seq-name (car seq-list)) (mh-seq-msgs (car seq-list)))
1625 (setq seq-list (cdr seq-list))))
1628 (defun mh-notate-if-in-one-seq (msg notation offset seq)
1629 ;; If the MESSAGE is in only the SEQUENCE, then mark the scan listing of the
1630 ;; message with the CHARACTER at the given OFFSET from the beginning of the
1631 ;; listing line.
1632 (let ((in-seqs (mh-seq-containing-msg msg nil)))
1633 (if (and (eq seq (car in-seqs)) (null (cdr in-seqs)))
1634 (mh-notate msg notation offset))))
1637 (defun mh-seq-containing-msg (msg &optional include-internal-p)
1638 ;; Return a list of the sequences containing MESSAGE.
1639 ;; If INCLUDE-INTERNAL-P non-nil, include mh-e internal sequences in list.
1640 (let ((l mh-seq-list)
1641 (seqs ()))
1642 (while l
1643 (and (memq msg (mh-seq-msgs (car l)))
1644 (or include-internal-p
1645 (not (mh-internal-seq (mh-seq-name (car l)))))
1646 (setq seqs (cons (mh-seq-name (car l)) seqs)))
1647 (setq l (cdr l)))
1648 seqs))
1653 ;;; User prompting commands.
1656 (defun mh-read-msg-range (prompt)
1657 ;; Read a list of blank-separated items.
1658 (let* ((buf (read-string prompt))
1659 (buf-size (length buf))
1660 (start 0)
1661 (input ()))
1662 (while (< start buf-size)
1663 (let ((next (read-from-string buf start buf-size)))
1664 (setq input (cons (car next) input))
1665 (setq start (cdr next))))
1666 (nreverse input)))
1670 ;;; Build the folder-mode keymap:
1672 (suppress-keymap mh-folder-mode-map)
1674 ;; Save the `b' binding for a future `back'. Maybe?
1675 (gnus-define-keys mh-folder-mode-map
1676 " " mh-page-msg
1677 "!" mh-refile-or-write-again
1678 "," mh-header-display
1679 "." mh-show ;alias
1680 ">" mh-write-msg-to-file
1681 "E" mh-extract-rejected-mail
1682 "\177" mh-previous-page
1683 "\C-d" mh-delete-msg-no-motion
1684 "\e<" mh-first-msg
1685 "\e>" mh-last-msg
1686 "\ed" mh-redistribute
1687 "\r" mh-show
1688 "^" mh-refile-msg ;alias
1689 "c" mh-copy-msg
1690 "d" mh-delete-msg
1691 "e" mh-edit-again
1692 "f" mh-forward
1693 "g" mh-goto-msg
1694 "i" mh-inc-folder
1695 "k" mh-delete-subject-thread
1696 "l" mh-print-msg
1697 "m" mh-send ;alias
1698 "n" mh-next-undeleted-msg
1699 "o" mh-refile-msg
1700 "p" mh-previous-undeleted-msg
1701 "q" mh-quit
1702 "r" mh-reply
1703 "s" mh-send
1704 "t" mh-toggle-showing
1705 "u" mh-undo
1706 "x" mh-execute-commands
1707 "|" mh-pipe-msg)
1709 (gnus-define-keys (mh-folder-map "F" mh-folder-mode-map)
1710 "S" mh-sort-folder
1711 "f" mh-visit-folder ;alias
1712 "k" mh-kill-folder
1713 "l" mh-list-folders
1714 "o" mh-visit-folder ;alias
1715 "p" mh-pack-folder
1716 "r" mh-rescan-folder
1717 "s" mh-search-folder
1718 "u" mh-undo-folder
1719 "v" mh-visit-folder)
1721 (gnus-define-keys (mh-sequence-map "S" mh-folder-mode-map)
1722 "d" mh-delete-msg-from-seq
1723 "k" mh-delete-seq
1724 "l" mh-list-sequences
1725 "n" mh-narrow-to-seq
1726 "p" mh-put-msg-in-seq
1727 "s" mh-msg-is-in-seq
1728 "w" mh-widen)
1730 (gnus-define-keys (mh-thread-map "T" mh-folder-mode-map)
1731 "d" mh-delete-subject-thread
1732 "k" mh-delete-subject-thread
1733 "s" mh-narrow-to-subject-thread
1734 "t" mh-toggle-subject-thread
1735 "u" mh-next-unseen-subject-thread)
1737 (gnus-define-keys (mh-extract-map "X" mh-folder-mode-map)
1738 "s" mh-store-msg ;shar
1739 "u" mh-store-msg) ;uuencode
1741 (gnus-define-keys (mh-digest-map "D" mh-folder-mode-map)
1742 " " mh-page-digest
1743 "\177" mh-page-digest-backwards
1744 "b" mh-burst-digest)
1746 (cond
1747 ((not (null (save-match-data (string-match "XEmacs\\|Lucid" emacs-version))))
1748 (define-key mh-folder-mode-map [button2] 'mh-show-mouse))
1750 (define-key mh-folder-mode-map [mouse-2] 'mh-show-mouse)))
1752 ;; "C-c /" prefix is used in mh-folder-mode by pgp.el and mailcrypt
1754 ;;; Menu extracted from mh-menubar.el V1.1 (31 July 2001)
1755 ;;; Menus for folder mode: folder, message, sequence (in that order)
1756 ;;; folder-mode "Sequence" menu
1757 (easy-menu-define
1758 mh-folder-sequence-menu mh-folder-mode-map "Menu for mh-e folder-sequence."
1759 '("Sequence"
1760 ["Add Msg to Seq..." mh-put-msg-in-seq (mh-get-msg-num nil)]
1761 ["List Seq's for Msg" mh-msg-is-in-seq (mh-get-msg-num nil)]
1762 ["Delete Msg from Seq..." mh-delete-msg-from-seq (mh-get-msg-num nil)]
1763 ["List Seq's in Folder..." mh-list-sequences t]
1764 ["Delete Seq..." mh-delete-seq t]
1765 ["Show Only Msgs in Seq..." mh-narrow-to-seq t]
1766 ["Show All Msgs in Folder" mh-widen mh-narrowed-to-seq]
1767 "--"
1768 ["Toggle Subject Thread" mh-toggle-subject-thread t]
1769 ["Narrow to Subject Thread" mh-narrow-to-subject-thread t]
1770 ["Delete Rest of Subject Thread" mh-delete-subject-thread t]
1771 ["Next Unseen Subject Thread" mh-next-unseen-subject-thread t]
1772 "--"
1773 ["Push State Out to MH" mh-update-sequences t]))
1775 ;;; folder-mode "Message" menu
1776 (easy-menu-define
1777 mh-folder-message-menu mh-folder-mode-map "Menu for mh-e folder-message."
1778 '("Message"
1779 ["Show Msg" mh-show (mh-get-msg-num nil)]
1780 ["Next Msg" mh-next-undeleted-msg t]
1781 ["Previous Msg" mh-previous-undeleted-msg t]
1782 ["Go to First Msg" mh-first-msg t]
1783 ["Go to Last Msg" mh-last-msg t]
1784 ["Go to Msg by Number..." mh-goto-msg t]
1785 ["Delete Msg" mh-delete-msg (mh-get-msg-num nil)]
1786 ["Refile Msg" mh-refile-msg (mh-get-msg-num nil)]
1787 ["Undo Delete/Refile" mh-undo t]
1788 ["Process Delete/Refile" mh-execute-commands
1789 (or mh-refile-list mh-delete-list)]
1790 "--"
1791 ["Compose a New Msg" mh-send t]
1792 ["Reply to Msg..." mh-reply (mh-get-msg-num nil)]
1793 ["Forward Msg..." mh-forward (mh-get-msg-num nil)]
1794 ["Redistribute Msg..." mh-redistribute (mh-get-msg-num nil)]
1795 ["Edit Msg Again" mh-edit-again (mh-get-msg-num nil)]
1796 ["Re-edit a Bounced Msg" mh-extract-rejected-mail t]
1797 "--"
1798 ["Refile Msg in Folder..." mh-refile-msg (mh-get-msg-num nil)]
1799 ["Copy Msg to Folder..." mh-copy-msg (mh-get-msg-num nil)]
1800 ["Print Msg" mh-print-msg (mh-get-msg-num nil)]
1801 ["Write Msg to File..." mh-write-msg-to-file (mh-get-msg-num nil)]
1802 ["Pipe Msg to Command..." mh-pipe-msg (mh-get-msg-num nil)]
1803 ["Unpack Uuencoded Msg..." mh-store-msg (mh-get-msg-num nil)]
1804 ["Show Msg with Header" mh-header-display (mh-get-msg-num nil)]
1805 ["Burst Digest Msg" mh-burst-digest (mh-get-msg-num nil)]))
1807 ;;; folder-mode "Folder" menu
1808 (easy-menu-define
1809 mh-folder-folder-menu mh-folder-mode-map "Menu for mh-e folder."
1810 '("Folder"
1811 ["Incorporate New Mail" mh-inc-folder t]
1812 ["Toggle Show/Folder" mh-toggle-showing t]
1813 ["Execute Delete/Refile" mh-execute-commands
1814 (or mh-refile-list mh-delete-list)]
1815 ["Rescan Folder" mh-rescan-folder t]
1816 ["Pack Folder" mh-pack-folder t]
1817 ["Sort Folder" mh-sort-folder t]
1818 "--"
1819 ["Search a Folder..." mh-search-folder t]
1820 ["Visit a Folder..." mh-visit-folder t]
1821 ["List Folders" mh-list-folders t]
1822 ["Quit MH-E" mh-quit t]))
1825 ;;; Support for emacs21 toolbar using gnus/message.el icons (and code).
1826 (eval-when-compile (defvar tool-bar-map))
1827 (when (and (fboundp 'tool-bar-add-item)
1828 tool-bar-mode)
1829 (defvar mh-folder-tool-bar-map
1830 (let ((tool-bar-map (make-sparse-keymap)))
1831 (tool-bar-add-item "mail" 'mh-inc-folder 'mh-folder-inc-folder
1832 :help "Incorporate new mail in Inbox")
1834 (tool-bar-add-item "left_arrow" 'mh-previous-undeleted-msg
1835 'mh-folder-prev :help "Previous message")
1836 (tool-bar-add-item "page-down" 'mh-page-msg 'mh-folder-page
1837 :help "Page this message")
1838 (tool-bar-add-item "right_arrow" 'mh-next-undeleted-msg 'mh-folder-next
1839 :help "Next message")
1841 (tool-bar-add-item "close" 'mh-delete-msg 'mh-folder-delete
1842 :help "Mark for deletion")
1843 (tool-bar-add-item "refile" 'mh-refile-msg 'mh-folder-refile
1844 :help "Refile this message")
1845 (tool-bar-add-item "undo" 'mh-undo 'mh-folder-undo
1846 :help "Undo this mark")
1847 (tool-bar-add-item "execute" 'mh-execute-commands 'mh-folder-exec
1848 :help "Perform moves and deletes")
1850 (tool-bar-add-item "show" 'mh-toggle-showing 'mh-folder-toggle-show
1851 :help "Toggle showing message")
1853 (tool-bar-add-item "mail/reply2" 'mh-reply 'mh-folder-reply
1854 :help "Reply to this message")
1855 (tool-bar-add-item "mail_compose" 'mh-send 'mh-folder-compose
1856 :help "Compose new message")
1858 (tool-bar-add-item "rescan" 'mh-rescan-folder 'mh-folder-rescan
1859 :help "Rescan this folder")
1860 (tool-bar-add-item "repack" 'mh-pack-folder 'mh-folder-pack
1861 :help "Repack this folder")
1863 (tool-bar-add-item "search" 'mh-search-folder 'mh-folder-search
1864 :help "Search this folder")
1865 (tool-bar-add-item "fld_open" 'mh-visit-folder 'mh-folder-visit
1866 :help "Visit other folder")
1868 (tool-bar-add-item "preferences" (lambda ()
1869 (interactive)
1870 (customize-group "mh"))
1871 'mh-folder-customize
1872 :help "mh-e preferences")
1873 (tool-bar-add-item "help" (lambda ()
1874 (interactive)
1875 (Info-goto-node "(mh-e)Top"))
1876 'mh-folder-help :help "Help")
1877 tool-bar-map))
1879 (defvar mh-folder-seq-tool-bar-map
1880 (let ((tool-bar-map (copy-keymap mh-folder-tool-bar-map)))
1881 (tool-bar-add-item "widen" 'mh-widen 'mh-folder-widen
1882 :help "Widen from this sequence")
1883 tool-bar-map)
1884 "Tool-bar to use when narrowed to a sequence in MH-Folder buffers.")
1887 ;;;autoload the other mh-e parts
1889 ;;; mh-comp
1891 (autoload 'mh-smail "mh-comp"
1892 "Compose and send mail with the MH mail system.
1893 This function is an entry point to mh-e, the Emacs front end
1894 to the MH mail system.
1895 See documentation of `\\[mh-send]' for more details on composing mail." t)
1897 (autoload 'mh-smail-other-window "mh-comp"
1898 "Compose and send mail in other window with the MH mail system.
1899 This function is an entry point to mh-e, the Emacs front end
1900 to the MH mail system.
1901 See documentation of `\\[mh-send]' for more details on composing mail." t)
1903 (autoload 'mh-edit-again "mh-comp"
1904 "Clean-up a draft or a message previously sent and make it resendable.
1905 Default is the current message.
1906 The variable mh-new-draft-cleaned-headers specifies the headers to remove.
1907 See also documentation for `\\[mh-send]' function." t)
1909 (autoload 'mh-extract-rejected-mail "mh-comp"
1910 "Extract a letter returned by the mail system and make it resendable.
1911 Default is the current message. The variable mh-new-draft-cleaned-headers
1912 gives the headers to clean out of the original message.
1913 See also documentation for `\\[mh-send]' function." t)
1915 (autoload 'mh-forward "mh-comp"
1916 "Forward a message or message sequence. Defaults to displayed message.
1917 If optional prefix argument provided, then prompt for the message sequence.
1918 See also documentation for `\\[mh-send]' function." t)
1920 (autoload 'mh-redistribute "mh-comp"
1921 "Redistribute a letter.
1922 Depending on how your copy of MH was compiled, you may need to change the
1923 setting of the variable mh-redist-full-contents. See its documentation." t)
1925 (autoload 'mh-reply "mh-comp"
1926 "Reply to a MESSAGE (default: displayed message).
1927 If optional prefix argument INCLUDEP provided, then include the message
1928 in the reply using filter mhl.reply in your MH directory.
1929 Prompts for type of addresses to reply to:
1930 from sender only,
1931 to sender and primary recipients,
1932 cc/all sender and all recipients.
1933 If the file named by `mh-repl-formfile' exists, it is used as a skeleton
1934 for the reply. See also documentation for `\\[mh-send]' function." t)
1936 (autoload 'mh-send "mh-comp"
1937 "Compose and send a letter.
1938 The file named by `mh-comp-formfile' will be used as the form.
1939 Do not call this function from outside mh-e; use \\[mh-smail] instead.
1940 The letter is composed in mh-letter-mode; see its documentation for more
1941 details. If `mh-compose-letter-function' is defined, it is called on the
1942 draft and passed three arguments: to, subject, and cc." t)
1944 (autoload 'mh-send-other-window "mh-comp"
1945 "Compose and send a letter in another window.
1946 Do not call this function from outside mh-e;
1947 use \\[mh-smail-other-window] instead.
1948 See also documentation for `\\[mh-send]' function." t)
1950 (autoload 'mh-letter-mode "mh-comp"
1951 "Mode for composing letters in mh-e.
1952 For more details, type \\[describe-mode] while in MH-Letter mode." t)
1955 ;;; mh-funcs
1957 (autoload 'mh-burst-digest "mh-funcs"
1958 "Burst apart the current message, which should be a digest.
1959 The message is replaced by its table of contents and the messages from the
1960 digest are inserted into the folder after that message." t)
1962 (autoload 'mh-copy-msg "mh-funcs"
1963 "Copy to another FOLDER the specified MESSAGE(s) without deleting them.
1964 Default is the displayed message. If optional prefix argument is
1965 provided, then prompt for the message sequence." t)
1967 (autoload 'mh-kill-folder "mh-funcs"
1968 "Remove the current folder." t)
1970 (autoload 'mh-list-folders "mh-funcs"
1971 "List mail folders." t)
1973 (autoload 'mh-pack-folder "mh-funcs"
1974 "Renumber the messages of a folder to be 1..n.
1975 First, offer to execute any outstanding commands for the current folder.
1976 If optional prefix argument provided, prompt for the range of messages
1977 to display after packing. Otherwise, show the entire folder." t)
1979 (autoload 'mh-pipe-msg "mh-funcs"
1980 "Pipe the current message through the given shell COMMAND.
1981 If INCLUDE-HEADERS (prefix argument) is provided, send the entire message.
1982 Otherwise just send the message's body without the headers." t)
1984 (autoload 'mh-page-digest "mh-funcs"
1985 "Advance displayed message to next digested message." t)
1987 (autoload 'mh-page-digest-backwards "mh-funcs"
1988 "Back up displayed message to previous digested message." t)
1990 (autoload 'mh-print-msg "mh-funcs"
1991 "Print MESSAGE(s) (default: displayed message) on printer.
1992 If optional prefix argument provided, then prompt for the message sequence.
1993 The variable mh-lpr-command-format is used to generate the print command.
1994 The messages are formatted by mhl. See the variable mhl-formfile." t)
1996 (autoload 'mh-sort-folder "mh-funcs"
1997 "Sort the messages in the current folder by date.
1998 Calls the MH program sortm to do the work.
1999 The arguments in the list mh-sortm-args are passed to sortm
2000 if this function is passed an argument." t)
2002 (autoload 'mh-undo-folder "mh-funcs"
2003 "Undo all commands in current folder." t)
2005 (autoload 'mh-store-msg "mh-funcs"
2006 "Store the file(s) contained in the current message into DIRECTORY.
2007 The message can contain a shar file or uuencoded file.
2008 Default directory is the last directory used, or initially the value of
2009 mh-store-default-directory or the current directory." t)
2011 (autoload 'mh-store-buffer "mh-funcs"
2012 "Store the file(s) contained in the current buffer into DIRECTORY.
2013 The buffer can contain a shar file or uuencoded file.
2014 Default directory is the last directory used, or initially the value of
2015 `mh-store-default-directory' or the current directory." t)
2018 ;;; mh-pick
2020 (autoload 'mh-search-folder "mh-pick"
2021 "Search FOLDER for messages matching a pattern.
2022 Add the messages found to the sequence named `search'." t)
2024 ;;; mh-seq
2026 (autoload 'mh-region-to-sequence "mh-seq"
2027 "Define sequence 'region as the messages in selected region." t)
2028 (autoload 'mh-delete-seq "mh-seq"
2029 "Delete the SEQUENCE." t)
2030 (autoload 'mh-list-sequences "mh-seq"
2031 "List the sequences defined in FOLDER." t)
2032 (autoload 'mh-msg-is-in-seq "mh-seq"
2033 "Display the sequences that contain MESSAGE (default: displayed message)." t)
2034 (autoload 'mh-narrow-to-seq "mh-seq"
2035 "Restrict display of this folder to just messages in SEQUENCE
2036 Use \\[mh-widen] to undo this command." t)
2037 (autoload 'mh-put-msg-in-seq "mh-seq"
2038 "Add MESSAGE(s) (default: displayed message) to SEQUENCE.
2039 If optional prefix argument provided, then prompt for the message sequence." t)
2040 (autoload 'mh-widen "mh-seq"
2041 "Remove restrictions from current folder, thereby showing all messages." t)
2042 (autoload 'mh-rename-seq "mh-seq"
2043 "Rename SEQUENCE to have NEW-NAME." t)
2044 (autoload 'mh-narrow-to-subject-thread "mh-seq"
2045 "Narrow to a sequence containing all following messages with same subject."
2047 (autoload 'mh-toggle-subject-thread "mh-seq"
2048 "Narrow to or widen from a sequence containing current subject sequence." t)
2049 (autoload 'mh-delete-subject-thread "mh-seq"
2050 "Mark all following messages with same subject to be deleted." t)
2051 (autoload 'mh-next-unseen-subject-thread "mh-seq"
2052 "Get the next unseen subject thread." t)
2055 (dolist (mess '("^Cursor not pointing to message$"
2056 "^There is no other window$"))
2057 (add-to-list 'debug-ignored-errors mess))
2059 ;;; mh-e.el ends here