]> code.delx.au - gnu-emacs/blob - lisp/mh-e/mh-show.el
Convert consecutive FSF copyright years to ranges.
[gnu-emacs] / lisp / mh-e / mh-show.el
1 ;;; mh-show.el --- MH-Show mode
2
3 ;; Copyright (C) 1993, 1995, 1997, 2000-2011
4 ;; Free Software Foundation, Inc.
5
6 ;; Author: Bill Wohler <wohler@newt.com>
7 ;; Maintainer: Bill Wohler <wohler@newt.com>
8 ;; Keywords: mail
9 ;; See: mh-e.el
10
11 ;; This file is part of GNU Emacs.
12
13 ;; GNU Emacs is free software: you can redistribute it and/or modify
14 ;; it under the terms of the GNU General Public License as published by
15 ;; the Free Software Foundation, either version 3 of the License, or
16 ;; (at your option) any later version.
17
18 ;; GNU Emacs is distributed in the hope that it will be useful,
19 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 ;; GNU General Public License for more details.
22
23 ;; You should have received a copy of the GNU General Public License
24 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
25
26 ;;; Commentary:
27
28 ;; Mode for showing messages.
29
30 ;;; Change Log:
31
32 ;;; Code:
33
34 (require 'mh-e)
35 (require 'mh-scan)
36
37 ;; Dynamically-created function not found in mh-loaddefs.el.
38 (autoload 'mh-tool-bar-init "mh-tool-bar")
39
40 (require 'font-lock)
41 (require 'gnus-cite)
42 (require 'gnus-util)
43 (require 'goto-addr)
44
45 (autoload 'mh-make-buffer-data "mh-mime") ;can't be automatically generated
46
47 \f
48
49 ;;; MH-Folder Commands
50
51 (defvar mh-showing-with-headers nil
52 "If non-nil, MH-Show buffer contains message with all header fields.
53 If nil, MH-Show buffer contains message processed normally.")
54
55 ;;;###mh-autoload
56 (defun mh-show (&optional message redisplay-flag)
57 "Display message\\<mh-folder-mode-map>.
58
59 If the message under the cursor is already displayed, this command
60 scrolls to the beginning of the message. MH-E normally hides a lot of
61 the superfluous header fields that mailers add to a message, but if
62 you wish to see all of them, use the command \\[mh-header-display].
63
64 Two hooks can be used to control how messages are displayed. The
65 first hook, `mh-show-mode-hook', is called early on in the
66 process of the message display. It is usually used to perform
67 some action on the message's content. The second hook,
68 `mh-show-hook', is the last thing called after messages are
69 displayed. It's used to affect the behavior of MH-E in general or
70 when `mh-show-mode-hook' is too early.
71
72 From a program, optional argument MESSAGE can be used to display an
73 alternative message. The optional argument REDISPLAY-FLAG forces the
74 redisplay of the message even if the show buffer was already
75 displaying the correct message.
76
77 See the \"mh-show\" customization group for a litany of options that
78 control what displayed messages look like."
79 (interactive (list nil t))
80 (when (or redisplay-flag
81 (and mh-showing-with-headers
82 (or mh-mhl-format-file mh-clean-message-header-flag)))
83 (mh-invalidate-show-buffer))
84 (mh-show-msg message))
85
86 ;;;###mh-autoload
87 (defun mh-header-display ()
88 "Display message with all header fields\\<mh-folder-mode-map>.
89
90 Use the command \\[mh-show] to show the message normally again."
91 (interactive)
92 (and (not mh-showing-with-headers)
93 (or mh-mhl-format-file mh-clean-message-header-flag)
94 (mh-invalidate-show-buffer))
95 (let ((mh-decode-mime-flag nil)
96 (mh-mhl-format-file nil)
97 (mh-clean-message-header-flag nil))
98 (mh-show-msg nil)
99 (mh-in-show-buffer (mh-show-buffer)
100 (goto-char (point-min))
101 (mh-recenter 0))
102 (setq mh-showing-with-headers t)))
103
104 ;;;###mh-autoload
105 (defun mh-show-preferred-alternative ()
106 "Display message with the default preferred alternative.
107 This is as if `mm-discouraged-alternatives' is set to nil.
108
109 Use the command \\[mh-show] to show the message normally again."
110 (interactive)
111 (let
112 ((mm-discouraged-alternatives))
113 (mh-show nil t)))
114
115 \f
116
117 ;;; Support Routines for MH-Folder Commands
118
119 ;;;###mh-autoload
120 (defun mh-maybe-show (&optional msg)
121 "Display message at cursor, but only if in show mode.
122 If optional arg MSG is non-nil, display that message instead."
123 (if mh-showing-mode (mh-show msg)))
124
125 (defun mh-show-msg (msg)
126 "Show MSG.
127
128 The hook `mh-show-hook' is called after the message has been
129 displayed."
130 (if (not msg)
131 (setq msg (mh-get-msg-num t)))
132 (mh-showing-mode t)
133 (setq mh-page-to-next-msg-flag nil)
134 (let ((folder mh-current-folder)
135 (folders (list mh-current-folder))
136 (clean-message-header mh-clean-message-header-flag)
137 (show-window (get-buffer-window mh-show-buffer))
138 (display-mime-buttons-flag mh-display-buttons-for-inline-parts-flag))
139 (if (not (eq (next-window (minibuffer-window)) (selected-window)))
140 (delete-other-windows)) ; force ourself to the top window
141 (mh-in-show-buffer (mh-show-buffer)
142 (setq mh-display-buttons-for-inline-parts-flag display-mime-buttons-flag)
143 (if (and show-window
144 (equal (mh-msg-filename msg folder) buffer-file-name))
145 (progn ;just back up to start
146 (goto-char (point-min))
147 (if (not clean-message-header)
148 (mh-start-of-uncleaned-message)))
149 (mh-display-msg msg folder)))
150 (unless (if (fboundp 'window-full-height-p)
151 (window-full-height-p)
152 (= (1+ (window-height)) (frame-height))) ; not vertically split
153 (shrink-window (- (window-height) (or mh-summary-height
154 (mh-summary-height)))))
155 (mh-recenter nil)
156 ;; The following line is a nop which forces update of the scan line so
157 ;; that font-lock will update it (if needed)...
158 (mh-notate nil nil mh-cmd-note)
159 (if (not (memq msg mh-seen-list))
160 (setq mh-seen-list (cons msg mh-seen-list)))
161 (when mh-update-sequences-after-mh-show-flag
162 (mh-update-sequences)
163 (when mh-index-data
164 (setq folders
165 (append (mh-index-delete-from-sequence mh-unseen-seq (list msg))
166 folders)))
167 (when (mh-speed-flists-active-p)
168 (apply #'mh-speed-flists t folders)))
169 (run-hooks 'mh-show-hook)))
170
171 ;;;###mh-autoload
172 (defun mh-start-of-uncleaned-message ()
173 "Position uninteresting headers off the top of the window."
174 (let ((case-fold-search t))
175 (re-search-forward
176 "^To:\\|^Cc:\\|^From:\\|^Subject:\\|^Date:" nil t)
177 (beginning-of-line)
178 (mh-recenter 0)))
179
180 (defvar mh-show-buffer-mode-line-buffer-id " {show-%s} %d"
181 "Format string to produce `mode-line-buffer-identification' for show buffers.
182
183 First argument is folder name. Second is message number.")
184
185 ;;;###mh-autoload
186 (defun mh-display-msg (msg-num folder-name)
187 "Display MSG-NUM of FOLDER-NAME.
188 Sets the current buffer to the show buffer."
189 (let ((folder (mh-msg-folder folder-name)))
190 (set-buffer folder)
191 ;; When Gnus uses external displayers it has to keep handles longer. So
192 ;; we will delete these handles when mh-quit is called on the folder. It
193 ;; would be nicer if there are weak pointers in emacs lisp, then we could
194 ;; get the garbage collector to do this for us.
195 (unless (mh-buffer-data)
196 (setf (mh-buffer-data) (mh-make-buffer-data)))
197 ;; Bind variables in folder buffer in case they are local
198 (let ((formfile mh-mhl-format-file)
199 (clean-message-header mh-clean-message-header-flag)
200 (invisible-headers mh-invisible-header-fields-compiled)
201 (visible-headers nil)
202 (msg-filename (mh-msg-filename msg-num folder-name))
203 (show-buffer mh-show-buffer)
204 (mm-inline-media-tests mh-mm-inline-media-tests))
205 (if (not (file-exists-p msg-filename))
206 (error "Message %d does not exist" msg-num))
207 (if (and (> mh-show-maximum-size 0)
208 (> (elt (file-attributes msg-filename) 7)
209 mh-show-maximum-size)
210 (not (y-or-n-p
211 (format
212 "Message %d (%d bytes) exceeds %d bytes. Display it? "
213 msg-num (elt (file-attributes msg-filename) 7)
214 mh-show-maximum-size))))
215 (error "Message %d not displayed" msg-num))
216 (set-buffer show-buffer)
217 (cond ((not (equal msg-filename buffer-file-name))
218 (mh-unvisit-file)
219 (setq buffer-read-only nil)
220 ;; Cleanup old mime handles
221 (mh-mime-cleanup)
222 (erase-buffer)
223 ;; Changing contents, so this hook needs to be reinitialized.
224 ;; pgp.el uses this.
225 (if (boundp 'write-contents-hooks) ;Emacs 19
226 (kill-local-variable 'write-contents-hooks))
227 (if formfile
228 (mh-exec-lib-cmd-output "mhl" "-nobell" "-noclear"
229 (if (stringp formfile)
230 (list "-form" formfile))
231 msg-filename)
232 (insert-file-contents-literally msg-filename))
233 ;; Use mm to display buffer
234 (when (and mh-decode-mime-flag (not formfile))
235 (mh-add-missing-mime-version-header)
236 (setf (mh-buffer-data) (mh-make-buffer-data))
237 (mh-mime-display))
238 (mh-show-mode)
239 ;; Header cleanup
240 (goto-char (point-min))
241 (cond (clean-message-header
242 (mh-clean-msg-header (point-min)
243 invisible-headers
244 visible-headers)
245 (goto-char (point-min)))
246 (t
247 (mh-start-of-uncleaned-message)))
248 (mh-decode-message-header)
249 ;; the parts of visiting we want to do (no locking)
250 (or (eq buffer-undo-list t) ;don't save undo info for prev msgs
251 (setq buffer-undo-list nil))
252 (set-buffer-auto-saved)
253 ;; the parts of set-visited-file-name we want to do (no locking)
254 (setq buffer-file-name msg-filename)
255 (setq buffer-backed-up nil)
256 (auto-save-mode 1)
257 (set-mark nil)
258 (unwind-protect
259 (when (and mh-decode-mime-flag (not formfile))
260 (setq buffer-read-only nil)
261 (mh-display-smileys)
262 (mh-display-emphasis))
263 (setq buffer-read-only t))
264 (set-buffer-modified-p nil)
265 (setq mh-show-folder-buffer folder)
266 (setq mode-line-buffer-identification
267 (list (format mh-show-buffer-mode-line-buffer-id
268 folder-name msg-num)))
269 (mh-logo-display)
270 (set-buffer folder)
271 (setq mh-showing-with-headers nil))))))
272
273 (defun mh-msg-folder (folder-name)
274 "Return the name of the buffer for FOLDER-NAME."
275 folder-name)
276
277 ;;;###mh-autoload
278 (defun mh-clean-msg-header (start invisible-headers visible-headers)
279 "Flush extraneous lines in message header.
280
281 Header is cleaned from START to the end of the message header.
282 INVISIBLE-HEADERS contains a regular expression specifying lines
283 to delete from the header. VISIBLE-HEADERS contains a regular
284 expression specifying the lines to display. INVISIBLE-HEADERS is
285 ignored if VISIBLE-HEADERS is non-nil."
286 ;; XXX Note that MH-E no longer supports the `mh-visible-headers'
287 ;; variable, so this function could be trimmed of this feature too."
288 (let ((case-fold-search t)
289 (buffer-read-only nil))
290 (save-restriction
291 (goto-char start)
292 (if (search-forward "\n\n" nil 'move)
293 (backward-char 1))
294 (narrow-to-region start (point))
295 (goto-char (point-min))
296 (if visible-headers
297 (while (< (point) (point-max))
298 (cond ((looking-at visible-headers)
299 (forward-line 1)
300 (while (looking-at "[ \t]") (forward-line 1)))
301 (t
302 (mh-delete-line 1)
303 (while (looking-at "[ \t]")
304 (mh-delete-line 1)))))
305 (while (re-search-forward invisible-headers nil t)
306 (beginning-of-line)
307 (mh-delete-line 1)
308 (while (looking-at "[ \t]")
309 (mh-delete-line 1)))))
310 (let ((mh-compose-skipped-header-fields ()))
311 (mh-letter-hide-all-skipped-fields))
312 (unlock-buffer)))
313
314 ;;;###mh-autoload
315 (defun mh-invalidate-show-buffer ()
316 "Invalidate the show buffer so we must update it to use it."
317 (if (get-buffer mh-show-buffer)
318 (with-current-buffer mh-show-buffer
319 (mh-unvisit-file))))
320
321 (defun mh-unvisit-file ()
322 "Separate current buffer from the message file it was visiting."
323 (or (not (buffer-modified-p))
324 (null buffer-file-name) ;we've been here before
325 (yes-or-no-p (format "Message %s modified; flush changes? "
326 (file-name-nondirectory buffer-file-name)))
327 (error "Flushing changes not confirmed"))
328 (clear-visited-file-modtime)
329 (unlock-buffer)
330 (setq buffer-file-name nil))
331
332 (defun mh-summary-height ()
333 "Return ideal value for the variable `mh-summary-height'.
334 The current frame height is taken into consideration."
335 (or (and (fboundp 'frame-height)
336 (> (frame-height) 24)
337 (min 10 (/ (frame-height) 6)))
338 4))
339
340 \f
341
342 ;; Infrastructure to generate show-buffer functions from folder functions
343 ;; XEmacs does not have deactivate-mark? What is the equivalent of
344 ;; transient-mark-mode for XEmacs? Should we be restoring the mark in the
345 ;; folder buffer after the operation has been carried out.
346 (defmacro mh-defun-show-buffer (function original-function
347 &optional dont-return)
348 "Define FUNCTION to run ORIGINAL-FUNCTION in folder buffer.
349 If the buffer we start in is still visible and DONT-RETURN is nil
350 then switch to it after that."
351 `(defun ,function ()
352 ,(format "Calls %s from the message's folder.\n%s\nSee `%s' for more info.\n"
353 original-function
354 (if dont-return ""
355 "When function completes, returns to the show buffer if it is
356 still visible.\n")
357 original-function)
358 (interactive)
359 (when (buffer-live-p (get-buffer mh-show-folder-buffer))
360 (let ((config (current-window-configuration))
361 (folder-buffer mh-show-folder-buffer)
362 (normal-exit nil)
363 ,@(if dont-return () '((cur-buffer-name (buffer-name)))))
364 (pop-to-buffer mh-show-folder-buffer nil)
365 (unless (equal (buffer-name
366 (window-buffer (frame-first-window (selected-frame))))
367 folder-buffer)
368 (delete-other-windows))
369 (mh-goto-cur-msg t)
370 (mh-funcall-if-exists deactivate-mark)
371 (unwind-protect
372 (prog1 (call-interactively (function ,original-function))
373 (setq normal-exit t))
374 (mh-funcall-if-exists deactivate-mark)
375 (when (eq major-mode 'mh-folder-mode)
376 (mh-funcall-if-exists hl-line-highlight))
377 (cond ((not normal-exit)
378 (set-window-configuration config))
379 ,(if dont-return
380 `(t (setq mh-previous-window-config config))
381 `((and (get-buffer cur-buffer-name)
382 (window-live-p (get-buffer-window
383 (get-buffer cur-buffer-name))))
384 (pop-to-buffer (get-buffer cur-buffer-name) nil)))))))))
385
386 ;; Generate interactive functions for the show buffer from the corresponding
387 ;; folder functions.
388 (mh-defun-show-buffer mh-show-previous-undeleted-msg
389 mh-previous-undeleted-msg)
390 (mh-defun-show-buffer mh-show-next-undeleted-msg
391 mh-next-undeleted-msg)
392 (mh-defun-show-buffer mh-show-quit mh-quit)
393 (mh-defun-show-buffer mh-show-delete-msg mh-delete-msg)
394 (mh-defun-show-buffer mh-show-refile-msg mh-refile-msg)
395 (mh-defun-show-buffer mh-show-undo mh-undo)
396 (mh-defun-show-buffer mh-show-execute-commands mh-execute-commands)
397 (mh-defun-show-buffer mh-show-reply mh-reply t)
398 (mh-defun-show-buffer mh-show-redistribute mh-redistribute)
399 (mh-defun-show-buffer mh-show-forward mh-forward t)
400 (mh-defun-show-buffer mh-show-header-display mh-header-display)
401 (mh-defun-show-buffer mh-show-refile-or-write-again
402 mh-refile-or-write-again)
403 (mh-defun-show-buffer mh-show-show mh-show)
404 (mh-defun-show-buffer mh-show-show-preferred-alternative mh-show-preferred-alternative)
405 (mh-defun-show-buffer mh-show-write-message-to-file
406 mh-write-msg-to-file)
407 (mh-defun-show-buffer mh-show-extract-rejected-mail
408 mh-extract-rejected-mail t)
409 (mh-defun-show-buffer mh-show-delete-msg-no-motion
410 mh-delete-msg-no-motion)
411 (mh-defun-show-buffer mh-show-first-msg mh-first-msg)
412 (mh-defun-show-buffer mh-show-last-msg mh-last-msg)
413 (mh-defun-show-buffer mh-show-copy-msg mh-copy-msg)
414 (mh-defun-show-buffer mh-show-edit-again mh-edit-again t)
415 (mh-defun-show-buffer mh-show-goto-msg mh-goto-msg)
416 (mh-defun-show-buffer mh-show-inc-folder mh-inc-folder)
417 (mh-defun-show-buffer mh-show-delete-subject-or-thread
418 mh-delete-subject-or-thread)
419 (mh-defun-show-buffer mh-show-delete-subject mh-delete-subject)
420 (mh-defun-show-buffer mh-show-print-msg mh-print-msg)
421 (mh-defun-show-buffer mh-show-send mh-send t)
422 (mh-defun-show-buffer mh-show-toggle-showing mh-toggle-showing t)
423 (mh-defun-show-buffer mh-show-pipe-msg mh-pipe-msg t)
424 (mh-defun-show-buffer mh-show-sort-folder mh-sort-folder)
425 (mh-defun-show-buffer mh-show-visit-folder mh-visit-folder t)
426 (mh-defun-show-buffer mh-show-rescan-folder mh-rescan-folder)
427 (mh-defun-show-buffer mh-show-pack-folder mh-pack-folder)
428 (mh-defun-show-buffer mh-show-kill-folder mh-kill-folder t)
429 (mh-defun-show-buffer mh-show-list-folders mh-list-folders t)
430 (mh-defun-show-buffer mh-show-undo-folder mh-undo-folder)
431 (mh-defun-show-buffer mh-show-delete-msg-from-seq
432 mh-delete-msg-from-seq)
433 (mh-defun-show-buffer mh-show-delete-seq mh-delete-seq)
434 (mh-defun-show-buffer mh-show-list-sequences mh-list-sequences)
435 (mh-defun-show-buffer mh-show-narrow-to-seq mh-narrow-to-seq)
436 (mh-defun-show-buffer mh-show-put-msg-in-seq mh-put-msg-in-seq)
437 (mh-defun-show-buffer mh-show-msg-is-in-seq mh-msg-is-in-seq)
438 (mh-defun-show-buffer mh-show-widen mh-widen)
439 (mh-defun-show-buffer mh-show-narrow-to-subject mh-narrow-to-subject)
440 (mh-defun-show-buffer mh-show-narrow-to-from mh-narrow-to-from)
441 (mh-defun-show-buffer mh-show-narrow-to-cc mh-narrow-to-cc)
442 (mh-defun-show-buffer mh-show-narrow-to-range mh-narrow-to-range)
443 (mh-defun-show-buffer mh-show-narrow-to-to mh-narrow-to-to)
444 (mh-defun-show-buffer mh-show-store-msg mh-store-msg)
445 (mh-defun-show-buffer mh-show-page-digest mh-page-digest)
446 (mh-defun-show-buffer mh-show-page-digest-backwards
447 mh-page-digest-backwards)
448 (mh-defun-show-buffer mh-show-burst-digest mh-burst-digest)
449 (mh-defun-show-buffer mh-show-page-msg mh-page-msg)
450 (mh-defun-show-buffer mh-show-previous-page mh-previous-page)
451 (mh-defun-show-buffer mh-show-modify mh-modify t)
452 (mh-defun-show-buffer mh-show-next-button mh-next-button)
453 (mh-defun-show-buffer mh-show-prev-button mh-prev-button)
454 (mh-defun-show-buffer mh-show-toggle-mime-part mh-folder-toggle-mime-part)
455 (mh-defun-show-buffer mh-show-save-mime-part mh-folder-save-mime-part)
456 (mh-defun-show-buffer mh-show-inline-mime-part mh-folder-inline-mime-part)
457 (mh-defun-show-buffer mh-show-toggle-threads mh-toggle-threads)
458 (mh-defun-show-buffer mh-show-thread-delete mh-thread-delete)
459 (mh-defun-show-buffer mh-show-thread-refile mh-thread-refile)
460 (mh-defun-show-buffer mh-show-update-sequences mh-update-sequences)
461 (mh-defun-show-buffer mh-show-next-unread-msg mh-next-unread-msg)
462 (mh-defun-show-buffer mh-show-previous-unread-msg mh-previous-unread-msg)
463 (mh-defun-show-buffer mh-show-thread-ancestor mh-thread-ancestor)
464 (mh-defun-show-buffer mh-show-thread-next-sibling mh-thread-next-sibling)
465 (mh-defun-show-buffer mh-show-thread-previous-sibling
466 mh-thread-previous-sibling)
467 (mh-defun-show-buffer mh-show-index-visit-folder mh-index-visit-folder t)
468 (mh-defun-show-buffer mh-show-toggle-tick mh-toggle-tick)
469 (mh-defun-show-buffer mh-show-narrow-to-tick mh-narrow-to-tick)
470 (mh-defun-show-buffer mh-show-junk-blacklist mh-junk-blacklist)
471 (mh-defun-show-buffer mh-show-junk-whitelist mh-junk-whitelist)
472 (mh-defun-show-buffer mh-show-index-new-messages mh-index-new-messages)
473 (mh-defun-show-buffer mh-show-index-ticked-messages mh-index-ticked-messages)
474 (mh-defun-show-buffer mh-show-index-sequenced-messages
475 mh-index-sequenced-messages)
476 (mh-defun-show-buffer mh-show-catchup mh-catchup)
477 (mh-defun-show-buffer mh-show-ps-print-toggle-color mh-ps-print-toggle-color)
478 (mh-defun-show-buffer mh-show-ps-print-toggle-faces mh-ps-print-toggle-faces)
479 (mh-defun-show-buffer mh-show-ps-print-msg-file mh-ps-print-msg-file)
480 (mh-defun-show-buffer mh-show-ps-print-msg mh-ps-print-msg)
481 (mh-defun-show-buffer mh-show-toggle-mime-buttons mh-toggle-mime-buttons)
482 (mh-defun-show-buffer mh-show-display-with-external-viewer
483 mh-display-with-external-viewer)
484
485 \f
486
487 ;;; Sequence Menu
488
489 (easy-menu-define
490 mh-show-sequence-menu mh-show-mode-map "Menu for MH-E folder-sequence."
491 '("Sequence"
492 ["Add Message to Sequence..." mh-show-put-msg-in-seq t]
493 ["List Sequences for Message" mh-show-msg-is-in-seq t]
494 ["Delete Message from Sequence..." mh-show-delete-msg-from-seq t]
495 ["List Sequences in Folder..." mh-show-list-sequences t]
496 ["Delete Sequence..." mh-show-delete-seq t]
497 ["Narrow to Sequence..." mh-show-narrow-to-seq t]
498 ["Widen from Sequence" mh-show-widen t]
499 "--"
500 ["Narrow to Subject Sequence" mh-show-narrow-to-subject t]
501 ["Narrow to Tick Sequence" mh-show-narrow-to-tick
502 (with-current-buffer mh-show-folder-buffer
503 (and mh-tick-seq (mh-seq-msgs (mh-find-seq mh-tick-seq))))]
504 ["Delete Rest of Same Subject" mh-show-delete-subject t]
505 ["Toggle Tick Mark" mh-show-toggle-tick t]
506 "--"
507 ["Push State Out to MH" mh-show-update-sequences t]))
508
509 ;;; Message Menu
510
511 (easy-menu-define
512 mh-show-message-menu mh-show-mode-map "Menu for MH-E folder-message."
513 '("Message"
514 ["Show Message" mh-show-show t]
515 ["Show Message with Header" mh-show-header-display t]
516 ["Show Message with Preferred Alternative"
517 mh-show-show-preferred-alternative t]
518 ["Next Message" mh-show-next-undeleted-msg t]
519 ["Previous Message" mh-show-previous-undeleted-msg t]
520 ["Go to First Message" mh-show-first-msg t]
521 ["Go to Last Message" mh-show-last-msg t]
522 ["Go to Message by Number..." mh-show-goto-msg t]
523 ["Modify Message" mh-show-modify t]
524 ["Delete Message" mh-show-delete-msg t]
525 ["Refile Message" mh-show-refile-msg t]
526 ["Undo Delete/Refile" mh-show-undo t]
527 ["Process Delete/Refile" mh-show-execute-commands t]
528 "--"
529 ["Compose a New Message" mh-send t]
530 ["Reply to Message..." mh-show-reply t]
531 ["Forward Message..." mh-show-forward t]
532 ["Redistribute Message..." mh-show-redistribute t]
533 ["Edit Message Again" mh-show-edit-again t]
534 ["Re-edit a Bounced Message" mh-show-extract-rejected-mail t]
535 "--"
536 ["Copy Message to Folder..." mh-show-copy-msg t]
537 ["Print Message" mh-show-print-msg t]
538 ["Write Message to File..." mh-show-write-msg-to-file t]
539 ["Pipe Message to Command..." mh-show-pipe-msg t]
540 ["Unpack Uuencoded Message..." mh-show-store-msg t]
541 ["Burst Digest Message" mh-show-burst-digest t]))
542
543 ;;; Folder Menu
544
545 (easy-menu-define
546 mh-show-folder-menu mh-show-mode-map "Menu for MH-E folder."
547 '("Folder"
548 ["Incorporate New Mail" mh-show-inc-folder t]
549 ["Toggle Show/Folder" mh-show-toggle-showing t]
550 ["Execute Delete/Refile" mh-show-execute-commands t]
551 ["Rescan Folder" mh-show-rescan-folder t]
552 ["Thread Folder" mh-show-toggle-threads t]
553 ["Pack Folder" mh-show-pack-folder t]
554 ["Sort Folder" mh-show-sort-folder t]
555 "--"
556 ["List Folders" mh-show-list-folders t]
557 ["Visit a Folder..." mh-show-visit-folder t]
558 ["View New Messages" mh-show-index-new-messages t]
559 ["Search..." mh-search t]
560 "--"
561 ["Quit MH-E" mh-quit t]))
562
563 \f
564
565 ;;; MH-Show Keys
566
567 (gnus-define-keys mh-show-mode-map
568 " " mh-show-page-msg
569 "!" mh-show-refile-or-write-again
570 "'" mh-show-toggle-tick
571 "," mh-show-header-display
572 "." mh-show-show
573 ":" mh-show-show-preferred-alternative
574 ">" mh-show-write-message-to-file
575 "?" mh-help
576 "E" mh-show-extract-rejected-mail
577 "M" mh-show-modify
578 "\177" mh-show-previous-page
579 "\C-d" mh-show-delete-msg-no-motion
580 "\t" mh-show-next-button
581 [backtab] mh-show-prev-button
582 "\M-\t" mh-show-prev-button
583 "\ed" mh-show-redistribute
584 "^" mh-show-refile-msg
585 "c" mh-show-copy-msg
586 "d" mh-show-delete-msg
587 "e" mh-show-edit-again
588 "f" mh-show-forward
589 "g" mh-show-goto-msg
590 "i" mh-show-inc-folder
591 "k" mh-show-delete-subject-or-thread
592 "m" mh-show-send
593 "n" mh-show-next-undeleted-msg
594 "\M-n" mh-show-next-unread-msg
595 "o" mh-show-refile-msg
596 "p" mh-show-previous-undeleted-msg
597 "\M-p" mh-show-previous-unread-msg
598 "q" mh-show-quit
599 "r" mh-show-reply
600 "s" mh-show-send
601 "t" mh-show-toggle-showing
602 "u" mh-show-undo
603 "x" mh-show-execute-commands
604 "v" mh-show-index-visit-folder
605 "|" mh-show-pipe-msg)
606
607 (gnus-define-keys (mh-show-folder-map "F" mh-show-mode-map)
608 "?" mh-prefix-help
609 "'" mh-index-ticked-messages
610 "S" mh-show-sort-folder
611 "c" mh-show-catchup
612 "f" mh-show-visit-folder
613 "k" mh-show-kill-folder
614 "l" mh-show-list-folders
615 "n" mh-index-new-messages
616 "o" mh-show-visit-folder
617 "q" mh-show-index-sequenced-messages
618 "r" mh-show-rescan-folder
619 "s" mh-search
620 "t" mh-show-toggle-threads
621 "u" mh-show-undo-folder
622 "v" mh-show-visit-folder)
623
624 (gnus-define-keys (mh-show-sequence-map "S" mh-show-mode-map)
625 "'" mh-show-narrow-to-tick
626 "?" mh-prefix-help
627 "d" mh-show-delete-msg-from-seq
628 "k" mh-show-delete-seq
629 "l" mh-show-list-sequences
630 "n" mh-show-narrow-to-seq
631 "p" mh-show-put-msg-in-seq
632 "s" mh-show-msg-is-in-seq
633 "w" mh-show-widen)
634
635 (define-key mh-show-mode-map "I" mh-inc-spool-map)
636
637 (gnus-define-keys (mh-show-junk-map "J" mh-show-mode-map)
638 "?" mh-prefix-help
639 "b" mh-show-junk-blacklist
640 "w" mh-show-junk-whitelist)
641
642 (gnus-define-keys (mh-show-ps-print-map "P" mh-show-mode-map)
643 "?" mh-prefix-help
644 "C" mh-show-ps-print-toggle-color
645 "F" mh-show-ps-print-toggle-faces
646 "f" mh-show-ps-print-msg-file
647 "l" mh-show-print-msg
648 "p" mh-show-ps-print-msg)
649
650 (gnus-define-keys (mh-show-thread-map "T" mh-show-mode-map)
651 "?" mh-prefix-help
652 "u" mh-show-thread-ancestor
653 "p" mh-show-thread-previous-sibling
654 "n" mh-show-thread-next-sibling
655 "t" mh-show-toggle-threads
656 "d" mh-show-thread-delete
657 "o" mh-show-thread-refile)
658
659 (gnus-define-keys (mh-show-limit-map "/" mh-show-mode-map)
660 "'" mh-show-narrow-to-tick
661 "?" mh-prefix-help
662 "c" mh-show-narrow-to-cc
663 "g" mh-show-narrow-to-range
664 "m" mh-show-narrow-to-from
665 "s" mh-show-narrow-to-subject
666 "t" mh-show-narrow-to-to
667 "w" mh-show-widen)
668
669 (gnus-define-keys (mh-show-extract-map "X" mh-show-mode-map)
670 "?" mh-prefix-help
671 "s" mh-show-store-msg
672 "u" mh-show-store-msg)
673
674 (gnus-define-keys (mh-show-digest-map "D" mh-show-mode-map)
675 "?" mh-prefix-help
676 " " mh-show-page-digest
677 "\177" mh-show-page-digest-backwards
678 "b" mh-show-burst-digest)
679
680 (gnus-define-keys (mh-show-mime-map "K" mh-show-mode-map)
681 "?" mh-prefix-help
682 "a" mh-mime-save-parts
683 "e" mh-show-display-with-external-viewer
684 "v" mh-show-toggle-mime-part
685 "o" mh-show-save-mime-part
686 "i" mh-show-inline-mime-part
687 "t" mh-show-toggle-mime-buttons
688 "\t" mh-show-next-button
689 [backtab] mh-show-prev-button
690 "\M-\t" mh-show-prev-button)
691
692 \f
693
694 ;;; MH-Show Font Lock
695
696 (defun mh-header-field-font-lock (field limit)
697 "Return the value of a header field FIELD to font-lock.
698 Argument LIMIT limits search."
699 (if (= (point) limit)
700 nil
701 (let* ((mail-header-end (mh-mail-header-end))
702 (lesser-limit (if (< mail-header-end limit) mail-header-end limit))
703 (case-fold-search t))
704 (when (and (< (point) mail-header-end) ;Only within header
705 (re-search-forward (format "^%s" field) lesser-limit t))
706 (let ((match-one-b (match-beginning 0))
707 (match-one-e (match-end 0)))
708 (mh-header-field-end)
709 (if (> (point) limit) ;Don't search for end beyond limit
710 (goto-char limit))
711 (set-match-data (list match-one-b match-one-e
712 (1+ match-one-e) (point)))
713 t)))))
714
715 (defun mh-header-to-font-lock (limit)
716 "Return the value of a header field To to font-lock.
717 Argument LIMIT limits search."
718 (mh-header-field-font-lock "To:" limit))
719
720 (defun mh-header-cc-font-lock (limit)
721 "Return the value of a header field cc to font-lock.
722 Argument LIMIT limits search."
723 (mh-header-field-font-lock "cc:" limit))
724
725 (defun mh-header-subject-font-lock (limit)
726 "Return the value of a header field Subject to font-lock.
727 Argument LIMIT limits search."
728 (mh-header-field-font-lock "Subject:" limit))
729
730 (defun mh-letter-header-font-lock (limit)
731 "Return the entire mail header to font-lock.
732 Argument LIMIT limits search."
733 (if (= (point) limit)
734 nil
735 (let* ((mail-header-end (save-match-data (mh-mail-header-end)))
736 (lesser-limit (if (< mail-header-end limit) mail-header-end limit)))
737 (when (mh-in-header-p)
738 (set-match-data (list 1 lesser-limit))
739 (goto-char lesser-limit)
740 t))))
741
742 (defun mh-show-font-lock-fontify-region (beg end loudly)
743 "Limit font-lock in `mh-show-mode' to the header.
744
745 Used when the option `mh-highlight-citation-style' is set to
746 \"Gnus\", leaving the body to be dealt with by Gnus highlighting.
747 The region between BEG and END is given over to be fontified and
748 LOUDLY controls if a user sees a message about the fontification
749 operation."
750 (let ((header-end (mh-mail-header-end)))
751 (cond
752 ((and (< beg header-end)(< end header-end))
753 (font-lock-default-fontify-region beg end loudly))
754 ((and (< beg header-end)(>= end header-end))
755 (font-lock-default-fontify-region beg header-end loudly))
756 (t
757 nil))))
758
759 (defvar mh-show-font-lock-keywords
760 '(("^\\(From:\\|Sender:\\)\\(.*\\)"
761 (1 'default)
762 (2 'mh-show-from))
763 (mh-header-to-font-lock
764 (0 'default)
765 (1 'mh-show-to))
766 (mh-header-cc-font-lock
767 (0 'default)
768 (1 'mh-show-cc))
769 ("^\\(Reply-To:\\|Return-Path:\\)\\(.*\\)$"
770 (1 'default)
771 (2 'mh-show-from))
772 (mh-header-subject-font-lock
773 (0 'default)
774 (1 'mh-show-subject))
775 ("^\\(Apparently-To:\\|Newsgroups:\\)\\(.*\\)"
776 (1 'default)
777 (2 'mh-show-cc))
778 ("^\\(In-reply-to\\|Date\\):\\(.*\\)$"
779 (1 'default)
780 (2 'mh-show-date))
781 (mh-letter-header-font-lock
782 (0 'mh-show-header append t)))
783 "Additional expressions to highlight in MH-Show buffers.")
784
785 ;;;###mh-autoload
786 (defun mh-show-font-lock-keywords ()
787 "Return variable `mh-show-font-lock-keywords'."
788 mh-show-font-lock-keywords)
789
790 (defvar mh-show-font-lock-keywords-with-cite
791 (let* ((cite-chars "[>|}]")
792 (cite-prefix "A-Za-z")
793 (cite-suffix (concat cite-prefix "0-9_.@-`'\"")))
794 (append
795 mh-show-font-lock-keywords
796 (list
797 ;; Use MATCH-ANCHORED to effectively anchor the regexp left side.
798 `(,cite-chars
799 (,(concat "\\=[ \t]*"
800 "\\(\\([" cite-prefix "]+[" cite-suffix "]*\\)?"
801 "\\(" cite-chars "[ \t]*\\)\\)+"
802 "\\(.*\\)")
803 (beginning-of-line) (end-of-line)
804 (2 font-lock-constant-face nil t)
805 (4 font-lock-comment-face nil t))))))
806 "Additional expressions to highlight in MH-Show buffers.")
807
808 ;;;###mh-autoload
809 (defun mh-show-font-lock-keywords-with-cite ()
810 "Return variable `mh-show-font-lock-keywords-with-cite'."
811 mh-show-font-lock-keywords-with-cite)
812
813 \f
814
815 ;;; MH-Show Mode
816
817 ;; Ensure new buffers won't get this mode if default major-mode is nil.
818 (put 'mh-show-mode 'mode-class 'special)
819
820 ;; Shush compiler.
821 (defvar font-lock-auto-fontify)
822
823 ;;;###mh-autoload
824 (define-derived-mode mh-show-mode text-mode "MH-Show"
825 "Major mode for showing messages in MH-E.\\<mh-show-mode-map>
826
827 Email addresses and URLs in the message are highlighted if the
828 option `goto-address-highlight-p' is on, which it is by default.
829 To view the web page for a highlighted URL or to send a message
830 using a highlighted email address, use the middle mouse button or
831 \\[goto-address-at-point]. See Info node `(mh-e)Sending Mail' to
832 see how to configure Emacs to send the message using MH-E.
833
834 The hook `mh-show-mode-hook' is called upon entry to this mode.
835
836 See also `mh-folder-mode'.
837
838 \\{mh-show-mode-map}"
839 (mh-do-in-gnu-emacs
840 (if (boundp 'tool-bar-map)
841 (set (make-local-variable 'tool-bar-map) mh-show-tool-bar-map)))
842 (mh-do-in-xemacs
843 (mh-tool-bar-init :show))
844 (set (make-local-variable 'mail-header-separator) mh-mail-header-separator)
845 (setq paragraph-start (default-value 'paragraph-start))
846 (mh-show-unquote-From)
847 (mh-show-xface)
848 (mh-show-addr)
849 (setq buffer-invisibility-spec '((vanish . t) t))
850 (set (make-local-variable 'line-move-ignore-invisible) t)
851 (make-local-variable 'font-lock-defaults)
852 ;;(set (make-local-variable 'font-lock-support-mode) nil)
853 (cond
854 ((equal mh-highlight-citation-style 'font-lock)
855 (setq font-lock-defaults '(mh-show-font-lock-keywords-with-cite t)))
856 ((equal mh-highlight-citation-style 'gnus)
857 (setq font-lock-defaults '((mh-show-font-lock-keywords)
858 t nil nil nil
859 (font-lock-fontify-region-function
860 . mh-show-font-lock-fontify-region)))
861 (mh-gnus-article-highlight-citation))
862 (t
863 (setq font-lock-defaults '(mh-show-font-lock-keywords t))))
864 (if (and (featurep 'xemacs)
865 font-lock-auto-fontify)
866 (turn-on-font-lock))
867 (when mh-decode-mime-flag
868 (mh-make-local-hook 'kill-buffer-hook)
869 (add-hook 'kill-buffer-hook 'mh-mime-cleanup nil t))
870 (easy-menu-add mh-show-sequence-menu)
871 (easy-menu-add mh-show-message-menu)
872 (easy-menu-add mh-show-folder-menu)
873 (make-local-variable 'mh-show-folder-buffer)
874 (buffer-disable-undo)
875 (setq buffer-read-only t)
876 (use-local-map mh-show-mode-map))
877
878 \f
879
880 ;;; Support Routines
881
882 (defun mh-show-unquote-From ()
883 "Decode >From at beginning of lines for `mh-show-mode'."
884 (save-excursion
885 (let ((modified (buffer-modified-p))
886 (case-fold-search nil)
887 (buffer-read-only nil))
888 (goto-char (mh-mail-header-end))
889 (while (re-search-forward "^>From" nil t)
890 (replace-match "From"))
891 (set-buffer-modified-p modified))))
892
893 ;;;###mh-autoload
894 (defun mh-show-addr ()
895 "Use `goto-address'."
896 (goto-address))
897
898 ;;;###mh-autoload
899 (defun mh-gnus-article-highlight-citation ()
900 "Highlight cited text in current buffer using Gnus."
901 (interactive)
902 ;; Don't allow Gnus to create buttons while highlighting, maybe this is bad
903 ;; style?
904 (flet ((gnus-article-add-button (&rest args) nil))
905 (let* ((modified (buffer-modified-p))
906 (gnus-article-buffer (buffer-name))
907 (gnus-cite-face-list `(,@(cdr gnus-cite-face-list)
908 ,(car gnus-cite-face-list))))
909 (gnus-article-highlight-citation t)
910 (set-buffer-modified-p modified))))
911
912 (provide 'mh-show)
913
914 ;; Local Variables:
915 ;; indent-tabs-mode: nil
916 ;; sentence-end-double-space: nil
917 ;; End:
918
919 ;;; mh-show.el ends here