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