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