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