Mercurial > emacs
comparison lisp/mh-e/mh-utils.el @ 56673:e9a6cbc8ca5e
Upgraded to MH-E version 7.4.80.
See etc/MH-E-NEWS and lisp/mh-e/ChangeLog for details.
author | Bill Wohler <wohler@newt.com> |
---|---|
date | Sun, 15 Aug 2004 22:00:06 +0000 |
parents | d36b00b98db0 |
children | 4f4f410e6fe8 d8411455de48 |
comparison
equal
deleted
inserted
replaced
56672:83ab2b01744a | 56673:e9a6cbc8ca5e |
---|---|
31 | 31 |
32 ;;; Change Log: | 32 ;;; Change Log: |
33 | 33 |
34 ;;; Code: | 34 ;;; Code: |
35 | 35 |
36 ;; Is this XEmacs-land? Located here since needed by mh-customize.el. | 36 (defvar recursive-load-depth-limit) |
37 (defvar mh-xemacs-flag (featurep 'xemacs) | 37 (eval-and-compile |
38 "Non-nil means the current Emacs is XEmacs.") | 38 (if (and (boundp 'recursive-load-depth-limit) |
39 | 39 (integerp recursive-load-depth-limit) |
40 ;; The Emacs coding conventions require that the cl package not be required at | 40 (> 50 recursive-load-depth-limit)) |
41 ;; runtime. However, the cl package in versions of Emacs prior to 21.4 left cl | 41 (setq recursive-load-depth-limit 50))) |
42 ;; routines in their macro expansions. Use mh-require-cl to provide the cl | 42 |
43 ;; routines in the best way possible. | 43 (eval-when-compile (require 'mh-acros)) |
44 (eval-when-compile (require 'cl)) | |
45 (defmacro mh-require-cl () | |
46 (if (eq (car (macroexpand '(setf (gethash foo bar) baz))) 'cl-puthash) | |
47 `(require 'cl) | |
48 `(eval-when-compile (require 'cl)))) | |
49 | |
50 (mh-require-cl) | 44 (mh-require-cl) |
51 (require 'gnus-util) | 45 (require 'gnus-util) |
52 (require 'font-lock) | 46 (require 'font-lock) |
53 (require 'mouse) | 47 (require 'mouse) |
54 (load "tool-bar" t t) | 48 (load "tool-bar" t t) |
56 (require 'mh-customize) | 50 (require 'mh-customize) |
57 (require 'mh-inc) | 51 (require 'mh-inc) |
58 | 52 |
59 (load "mm-decode" t t) ; Non-fatal dependency | 53 (load "mm-decode" t t) ; Non-fatal dependency |
60 (load "mm-view" t t) ; Non-fatal dependency | 54 (load "mm-view" t t) ; Non-fatal dependency |
55 (load "vcard" t t) ; Non-fatal dependency | |
61 (load "hl-line" t t) ; Non-fatal dependency | 56 (load "hl-line" t t) ; Non-fatal dependency |
62 (load "executable" t t) ; Non-fatal dependency on | 57 (load "executable" t t) ; Non-fatal dependency on |
63 ; executable-find | 58 ; executable-find |
64 | 59 |
65 ;; Shush the byte-compiler | 60 ;; Shush the byte-compiler |
67 (defvar font-lock-defaults) | 62 (defvar font-lock-defaults) |
68 (defvar mark-active) | 63 (defvar mark-active) |
69 | 64 |
70 ;;; Autoloads | 65 ;;; Autoloads |
71 (autoload 'gnus-article-highlight-citation "gnus-cite") | 66 (autoload 'gnus-article-highlight-citation "gnus-cite") |
67 (autoload 'message-fetch-field "message") | |
68 (autoload 'message-tokenize-header "message") | |
72 (require 'sendmail) | 69 (require 'sendmail) |
73 (autoload 'Info-goto-node "info") | |
74 (unless (fboundp 'make-hash-table) | 70 (unless (fboundp 'make-hash-table) |
75 (autoload 'make-hash-table "cl")) | 71 (autoload 'make-hash-table "cl")) |
76 | |
77 ;;; Set for local environment: | |
78 ;;; mh-progs and mh-lib used to be set in paths.el, which tried to | |
79 ;;; figure out at build time which of several possible directories MH | |
80 ;;; was installed into. But if you installed MH after building Emacs, | |
81 ;;; this would almost certainly be wrong, so now we do it at run time. | |
82 | |
83 (defvar mh-progs nil | |
84 "Directory containing MH commands, such as inc, repl, and rmm.") | |
85 | |
86 (defvar mh-lib nil | |
87 "Directory containing the MH library. | |
88 This directory contains, among other things, the components file.") | |
89 | |
90 (defvar mh-lib-progs nil | |
91 "Directory containing MH helper programs. | |
92 This directory contains, among other things, the mhl program.") | |
93 | |
94 (defvar mh-nmh-flag nil | |
95 "Non-nil means nmh is installed on this system instead of MH.") | |
96 | |
97 (defvar mh-flists-present-flag nil | |
98 "Non-nil means that we have `flists'.") | |
99 | |
100 ;;;###autoload | |
101 (put 'mh-progs 'risky-local-variable t) | |
102 ;;;###autoload | |
103 (put 'mh-lib 'risky-local-variable t) | |
104 ;;;###autoload | |
105 (put 'mh-lib-progs 'risky-local-variable t) | |
106 ;;;###autoload | |
107 (put 'mh-nmh-flag 'risky-local-variable t) | |
108 | 72 |
109 ;;; CL Replacements | 73 ;;; CL Replacements |
110 (defun mh-search-from-end (char string) | 74 (defun mh-search-from-end (char string) |
111 "Return the position of last occurrence of CHAR in STRING. | 75 "Return the position of last occurrence of CHAR in STRING. |
112 If CHAR is not present in STRING then return nil. The function is used in lieu | 76 If CHAR is not present in STRING then return nil. The function is used in lieu |
113 of `search' in the CL package." | 77 of `search' in the CL package." |
114 (loop for index from (1- (length string)) downto 0 | 78 (loop for index from (1- (length string)) downto 0 |
115 when (equal (aref string index) char) return index | 79 when (equal (aref string index) char) return index |
116 finally return nil)) | 80 finally return nil)) |
117 | 81 |
118 ;;; Macros to generate correct code for different emacs variants | |
119 | |
120 (defmacro mh-do-in-gnu-emacs (&rest body) | |
121 "Execute BODY if in GNU Emacs." | |
122 (unless mh-xemacs-flag `(progn ,@body))) | |
123 (put 'mh-do-in-gnu-emacs 'lisp-indent-hook 'defun) | |
124 | |
125 (defmacro mh-do-in-xemacs (&rest body) | |
126 "Execute BODY if in GNU Emacs." | |
127 (when mh-xemacs-flag `(progn ,@body))) | |
128 (put 'mh-do-in-xemacs 'lisp-indent-hook 'defun) | |
129 | |
130 (defmacro mh-funcall-if-exists (function &rest args) | |
131 "Call FUNCTION with ARGS as parameters if it exists." | |
132 (if (fboundp function) | |
133 `(funcall ',function ,@args))) | |
134 | |
135 (defmacro mh-make-local-hook (hook) | |
136 "Make HOOK local if needed. | |
137 XEmacs and versions of GNU Emacs before 21.1 require `make-local-hook' to be | |
138 called." | |
139 (when (and (fboundp 'make-local-hook) | |
140 (not (get 'make-local-hook 'byte-obsolete-info))) | |
141 `(make-local-hook ,hook))) | |
142 | |
143 (defmacro mh-mark-active-p (check-transient-mark-mode-flag) | |
144 "A macro that expands into appropriate code in XEmacs and nil in GNU Emacs. | |
145 In GNU Emacs if CHECK-TRANSIENT-MARK-MODE-FLAG is non-nil then check if | |
146 variable `transient-mark-mode' is active." | |
147 (cond (mh-xemacs-flag ;XEmacs | |
148 `(and (boundp 'zmacs-regions) zmacs-regions (region-active-p))) | |
149 ((not check-transient-mark-mode-flag) ;GNU Emacs | |
150 `(and (boundp 'mark-active) mark-active)) | |
151 (t ;GNU Emacs | |
152 `(and (boundp 'transient-mark-mode) transient-mark-mode | |
153 (boundp 'mark-active) mark-active)))) | |
154 | |
155 ;;; Additional header fields that might someday be added: | 82 ;;; Additional header fields that might someday be added: |
156 ;;; "Sender: " "Reply-to: " | 83 ;;; "Sender: " "Reply-to: " |
157 | 84 |
85 | |
86 ;;; Scan Line Formats | |
87 | |
158 (defvar mh-scan-msg-number-regexp "^ *\\([0-9]+\\)" | 88 (defvar mh-scan-msg-number-regexp "^ *\\([0-9]+\\)" |
159 "Regexp to find the number of a message in a scan line. | 89 "This regexp is used to extract the message number from a scan line. |
160 The message's number must be surrounded with \\( \\)") | 90 Note that the message number must be placed in a parenthesized expression as |
91 in the default of \"^ *\\\\([0-9]+\\\\)\".") | |
161 | 92 |
162 (defvar mh-scan-msg-overflow-regexp "^[?0-9][0-9]" | 93 (defvar mh-scan-msg-overflow-regexp "^[?0-9][0-9]" |
163 "Regexp to find a scan line in which the message number overflowed. | 94 "This regexp matches scan lines in which the message number overflowed.") |
164 The message's number is left truncated in this case.") | |
165 | 95 |
166 (defvar mh-scan-msg-format-regexp "%\\([0-9]*\\)(msg)" | 96 (defvar mh-scan-msg-format-regexp "%\\([0-9]*\\)(msg)" |
167 "Regexp to find message number width in an scan format. | 97 "This regexp is used to find the message number width in a scan format. |
168 The message number width must be surrounded with \\( \\).") | 98 Note that the message number must be placed in a parenthesized expression as |
99 in the default of \"%\\\\([0-9]*\\\\)(msg)\".") | |
169 | 100 |
170 (defvar mh-scan-msg-format-string "%d" | 101 (defvar mh-scan-msg-format-string "%d" |
171 "Format string for width of the message number in a scan format. | 102 "This is a format string for width of the message number in a scan format. |
172 Use `0%d' for zero-filled message numbers.") | 103 Use `0%d' for zero-filled message numbers.") |
173 | 104 |
174 (defvar mh-scan-msg-search-regexp "^[^0-9]*%d[^0-9]" | 105 (defvar mh-scan-msg-search-regexp "^[^0-9]*%d[^0-9]" |
175 "Format string containing a regexp matching the scan listing for a message. | 106 "This format string regexp matches the scan line for a particular message. |
176 The desired message's number will be an argument to format.") | 107 Use `%d' to represent the location of the message number within the |
177 | 108 expression as in the default of \"^[^0-9]*%d[^0-9]\".") |
178 (defvar mh-default-folder-for-message-function nil | 109 |
179 "Function to select a default folder for refiling or Fcc. | 110 (defvar mh-cmd-note 4 |
180 If set to a function, that function is called with no arguments by | 111 "This is the number of characters to skip over before inserting notation. |
181 `\\[mh-refile-msg]' and `\\[mh-to-fcc]' to get a default when | 112 This variable should be set with the function `mh-set-cmd-note'. This variable |
182 prompting the user for a folder. The function is called from within a | 113 may be updated dynamically if `mh-adaptive-cmd-note-flag' is non-nil and |
183 `save-excursion', with point at the start of the message. It should | 114 `mh-scan-format-file' is t.") |
184 return the folder to offer as the refile or Fcc folder, as a string | 115 (make-variable-buffer-local 'mh-cmd-note) |
185 with a leading `+' sign. It can also return an empty string to use no | 116 |
186 default, or nil to calculate the default the usual way. | 117 (defvar mh-note-seq ?% |
187 NOTE: This variable is not an ordinary hook; | 118 "Messages in a user-defined sequence are marked by this character. |
188 It may not be a list of functions.") | 119 Messages in the `search' sequence are marked by this character as well.") |
120 | |
121 | |
189 | 122 |
190 (defvar mh-show-buffer-mode-line-buffer-id " {show-%s} %d" | 123 (defvar mh-show-buffer-mode-line-buffer-id " {show-%s} %d" |
191 "Format string to produce `mode-line-buffer-identification' for show buffers. | 124 "Format string to produce `mode-line-buffer-identification' for show buffers. |
192 First argument is folder name. Second is message number.") | 125 First argument is folder name. Second is message number.") |
193 | 126 |
194 (defvar mh-cmd-note 4 | 127 |
195 "Column to insert notation. | |
196 Use `mh-set-cmd-note' to modify it. | |
197 This value may be dynamically updated if `mh-adaptive-cmd-note-flag' is | |
198 non-nil and `mh-scan-format-file' is t. | |
199 Note that the first column is column number 0.") | |
200 (make-variable-buffer-local 'mh-cmd-note) | |
201 | |
202 (defvar mh-note-seq "%" | |
203 "String whose first character is used to notate messages in a sequence.") | |
204 | 128 |
205 (defvar mh-mail-header-separator "--------" | 129 (defvar mh-mail-header-separator "--------" |
206 "*Line used by MH to separate headers from text in messages being composed. | 130 "*Line used by MH to separate headers from text in messages being composed. |
207 This variable should not be used directly in programs. Programs should use | 131 This variable should not be used directly in programs. Programs should use |
208 `mail-header-separator' instead. `mail-header-separator' is initialized to | 132 `mail-header-separator' instead. `mail-header-separator' is initialized to |
211 | 135 |
212 Do not make this a regexp as it may be the argument to `insert' and it is | 136 Do not make this a regexp as it may be the argument to `insert' and it is |
213 passed through `regexp-quote' before being used by functions like | 137 passed through `regexp-quote' before being used by functions like |
214 `re-search-forward'.") | 138 `re-search-forward'.") |
215 | 139 |
140 (defvar mh-signature-separator-regexp "^-- $" | |
141 "Regexp used to find signature separator. | |
142 See `mh-signature-separator'.") | |
143 | |
144 (defvar mh-signature-separator "-- \n" | |
145 "Text of a signature separator. | |
146 A signature separator is used to separate the body of a message from the | |
147 signature. This can be used by user agents such as MH-E to render the | |
148 signature differently or to suppress the inclusion of the signature in a | |
149 reply. | |
150 Use `mh-signature-separator-regexp' when searching for a separator.") | |
151 | |
152 (defun mh-signature-separator-p () | |
153 "Return non-nil if buffer includes \"^-- $\"." | |
154 (save-excursion | |
155 (goto-char (point-min)) | |
156 (re-search-forward mh-signature-separator-regexp nil t))) | |
157 | |
216 ;; Variables for MIME display | 158 ;; Variables for MIME display |
217 | 159 |
218 ;; Structure to keep track of MIME handles on a per buffer basis. | 160 ;; Structure to keep track of MIME handles on a per buffer basis. |
219 (defstruct (mh-buffer-data (:conc-name mh-mime-) | 161 (mh-defstruct (mh-buffer-data (:conc-name mh-mime-) |
220 (:constructor mh-make-buffer-data)) | 162 (:constructor mh-make-buffer-data)) |
221 (handles ()) ; List of MIME handles | 163 (handles ()) ; List of MIME handles |
222 (handles-cache (make-hash-table)) ; Cache to avoid multiple decodes of | 164 (handles-cache (make-hash-table)) ; Cache to avoid multiple decodes of |
223 ; nested messages | 165 ; nested messages |
224 (parts-count 0) ; The button number is generated from | 166 (parts-count 0) ; The button number is generated from |
225 ; this number | 167 ; this number |
329 (defvar mh-address-mail-regexp | 271 (defvar mh-address-mail-regexp |
330 "[-a-zA-Z0-9._]+@\\([-a-zA-z0-9_]+\\.\\)+[a-zA-Z0-9]+" | 272 "[-a-zA-Z0-9._]+@\\([-a-zA-z0-9_]+\\.\\)+[a-zA-Z0-9]+" |
331 "A regular expression probably matching an e-mail address.") | 273 "A regular expression probably matching an e-mail address.") |
332 | 274 |
333 ;; From goto-addr.el, which we don't want to force-load on users. | 275 ;; From goto-addr.el, which we don't want to force-load on users. |
334 ;;;###mh-autoload | 276 |
335 (defun mh-goto-address-find-address-at-point () | 277 (defun mh-goto-address-find-address-at-point () |
336 "Find e-mail address around or before point. | 278 "Find e-mail address around or before point. |
337 Then search backwards to beginning of line for the start of an e-mail | 279 Then search backwards to beginning of line for the start of an e-mail |
338 address. If no e-mail address found, return nil." | 280 address. If no e-mail address found, return nil." |
339 (re-search-backward "[^-_A-z0-9.@]" (line-beginning-position) 'lim) | 281 (re-search-backward "[^-_A-z0-9.@]" (line-beginning-position) 'lim) |
346 (defun mh-mail-header-end () | 288 (defun mh-mail-header-end () |
347 "Substitute for `mail-header-end' that doesn't widen the buffer. | 289 "Substitute for `mail-header-end' that doesn't widen the buffer. |
348 In MH-E we frequently need to find the end of headers in nested messages, where | 290 In MH-E we frequently need to find the end of headers in nested messages, where |
349 the buffer has been narrowed. This function works in this situation." | 291 the buffer has been narrowed. This function works in this situation." |
350 (save-excursion | 292 (save-excursion |
351 (rfc822-goto-eoh) | 293 ;; XXX: The following replaces a call to rfc822-goto-eoh. Occasionally, |
294 ;; mail headers that MH-E has to read contains lines of the form: | |
295 ;; From xxx@yyy Mon May 10 11:48:07 2004 | |
296 ;; In this situation, rfc822-goto-eoh doesn't go to the end of the | |
297 ;; header. The replacement allows From_ lines in the mail header. | |
298 (goto-char (point-min)) | |
299 (loop for p = (re-search-forward | |
300 "^\\([:\n]\\|[^: \t\n]+[ \t\n]\\)" nil 'move) | |
301 do (cond ((null p) (return)) | |
302 (t (goto-char (match-beginning 0)) | |
303 (unless (looking-at "From ") (return)) | |
304 (goto-char p)))) | |
352 (point))) | 305 (point))) |
353 | 306 |
354 (defun mh-in-header-p () | 307 (defun mh-in-header-p () |
355 "Return non-nil if the point is in the header of a draft message." | 308 "Return non-nil if the point is in the header of a draft message." |
356 (< (point) (mh-mail-header-end))) | 309 (< (point) (mh-mail-header-end))) |
526 | 479 |
527 ;; The names of ephemeral buffers have a " *mh-" prefix (so that they are | 480 ;; The names of ephemeral buffers have a " *mh-" prefix (so that they are |
528 ;; hidden and can be programmatically removed in mh-quit), and the variable | 481 ;; hidden and can be programmatically removed in mh-quit), and the variable |
529 ;; names have the form mh-temp-.*-buffer. | 482 ;; names have the form mh-temp-.*-buffer. |
530 (defconst mh-temp-buffer " *mh-temp*") ;scratch | 483 (defconst mh-temp-buffer " *mh-temp*") ;scratch |
484 (defconst mh-temp-fetch-buffer " *mh-fetch*") ;wget/curl/fetch output | |
531 | 485 |
532 ;; The names of MH-E buffers that are not ephemeral and can be used by the | 486 ;; The names of MH-E buffers that are not ephemeral and can be used by the |
533 ;; user (and deleted by the user when no longer needed) have a "*MH-E " prefix | 487 ;; user (and deleted by the user when no longer needed) have a "*MH-E " prefix |
534 ;; (so they can be programmatically removed in mh-quit), and the variable | 488 ;; (so they can be programmatically removed in mh-quit), and the variable |
535 ;; names have the form mh-.*-buffer. | 489 ;; names have the form mh-.*-buffer. |
490 (defconst mh-aliases-buffer "*MH-E Aliases*") ;alias lookups | |
536 (defconst mh-folders-buffer "*MH-E Folders*") ;folder list | 491 (defconst mh-folders-buffer "*MH-E Folders*") ;folder list |
492 (defconst mh-help-buffer "*MH-E Help*") ;quick help | |
537 (defconst mh-info-buffer "*MH-E Info*") ;version information buffer | 493 (defconst mh-info-buffer "*MH-E Info*") ;version information buffer |
538 (defconst mh-log-buffer "*MH-E Log*") ;output of MH commands and so on | 494 (defconst mh-log-buffer "*MH-E Log*") ;output of MH commands and so on |
495 (defconst mh-mail-delivery-buffer "*MH-E Mail Delivery*") ;mail delivery log | |
539 (defconst mh-recipients-buffer "*MH-E Recipients*") ;killed when draft sent | 496 (defconst mh-recipients-buffer "*MH-E Recipients*") ;killed when draft sent |
540 (defconst mh-sequences-buffer "*MH-E Sequences*") ;sequences list | 497 (defconst mh-sequences-buffer "*MH-E Sequences*") ;sequences list |
541 (defconst mh-mail-delivery-buffer "*MH-E Mail Delivery*") ;mail delivery log | |
542 | 498 |
543 ;; Number of lines to keep in mh-log-buffer. | 499 ;; Number of lines to keep in mh-log-buffer. |
544 (defvar mh-log-buffer-lines 100) | 500 (defvar mh-log-buffer-lines 100) |
545 | 501 |
546 ;; Window configuration before MH-E command. | 502 ;; Window configuration before MH-E command. |
591 (if mh-modeline-glyph | 547 (if mh-modeline-glyph |
592 (cons modeline-buffer-id-left-extent mh-modeline-glyph) | 548 (cons modeline-buffer-id-left-extent mh-modeline-glyph) |
593 (cons modeline-buffer-id-left-extent "XEmacs%N:")) | 549 (cons modeline-buffer-id-left-extent "XEmacs%N:")) |
594 (cons modeline-buffer-id-right-extent " %17b"))))) | 550 (cons modeline-buffer-id-right-extent " %17b"))))) |
595 | 551 |
596 | |
597 ;;; This holds a documentation string used by describe-mode. | 552 ;;; This holds a documentation string used by describe-mode. |
598 (defun mh-showing-mode (&optional arg) | 553 (defun mh-showing-mode (&optional arg) |
599 "Change whether messages should be displayed. | 554 "Change whether messages should be displayed. |
600 With arg, display messages iff ARG is positive." | 555 With arg, display messages iff ARG is positive." |
601 (setq mh-showing-mode | 556 (setq mh-showing-mode |
611 | 566 |
612 ;; If non-nil, show buffer contains message with all headers. | 567 ;; If non-nil, show buffer contains message with all headers. |
613 ;; If nil, show buffer contains message processed normally. | 568 ;; If nil, show buffer contains message processed normally. |
614 ;; Showing message with headers or normally. | 569 ;; Showing message with headers or normally. |
615 (defvar mh-showing-with-headers nil) | 570 (defvar mh-showing-with-headers nil) |
616 | |
617 | 571 |
618 ;;; MH-E macros | 572 ;;; MH-E macros |
619 | 573 |
620 (defmacro with-mh-folder-updating (save-modification-flag &rest body) | 574 (defmacro with-mh-folder-updating (save-modification-flag &rest body) |
621 "Format is (with-mh-folder-updating (SAVE-MODIFICATION-FLAG) &body BODY). | 575 "Format is (with-mh-folder-updating (SAVE-MODIFICATION-FLAG) &body BODY). |
740 (error "Flushing changes not confirmed")) | 694 (error "Flushing changes not confirmed")) |
741 (clear-visited-file-modtime) | 695 (clear-visited-file-modtime) |
742 (unlock-buffer) | 696 (unlock-buffer) |
743 (setq buffer-file-name nil)) | 697 (setq buffer-file-name nil)) |
744 | 698 |
745 ;;;###mh-autoload | 699 |
746 (defun mh-get-msg-num (error-if-no-message) | 700 (defun mh-get-msg-num (error-if-no-message) |
747 "Return the message number of the displayed message. | 701 "Return the message number of the displayed message. |
748 If the argument ERROR-IF-NO-MESSAGE is non-nil, then complain if the cursor is | 702 If the argument ERROR-IF-NO-MESSAGE is non-nil, then complain if the cursor is |
749 not pointing to a message." | 703 not pointing to a message." |
750 (save-excursion | 704 (save-excursion |
913 (mh-defun-show-buffer mh-show-junk-whitelist mh-junk-whitelist) | 867 (mh-defun-show-buffer mh-show-junk-whitelist mh-junk-whitelist) |
914 (mh-defun-show-buffer mh-show-index-new-messages mh-index-new-messages) | 868 (mh-defun-show-buffer mh-show-index-new-messages mh-index-new-messages) |
915 (mh-defun-show-buffer mh-show-index-ticked-messages mh-index-ticked-messages) | 869 (mh-defun-show-buffer mh-show-index-ticked-messages mh-index-ticked-messages) |
916 (mh-defun-show-buffer mh-show-index-sequenced-messages | 870 (mh-defun-show-buffer mh-show-index-sequenced-messages |
917 mh-index-sequenced-messages) | 871 mh-index-sequenced-messages) |
872 (mh-defun-show-buffer mh-show-catchup mh-catchup) | |
873 (mh-defun-show-buffer mh-show-ps-print-toggle-mime mh-ps-print-toggle-mime) | |
874 (mh-defun-show-buffer mh-show-ps-print-toggle-color mh-ps-print-toggle-color) | |
875 (mh-defun-show-buffer mh-show-ps-print-toggle-faces mh-ps-print-toggle-faces) | |
876 (mh-defun-show-buffer mh-show-ps-print-msg-file mh-ps-print-msg-file) | |
877 (mh-defun-show-buffer mh-show-ps-print-msg mh-ps-print-msg) | |
878 (mh-defun-show-buffer mh-show-ps-print-msg-show mh-ps-print-msg-show) | |
879 (mh-defun-show-buffer mh-show-toggle-mime-buttons mh-toggle-mime-buttons) | |
880 (mh-defun-show-buffer mh-show-display-with-external-viewer | |
881 mh-display-with-external-viewer) | |
918 | 882 |
919 ;;; Populate mh-show-mode-map | 883 ;;; Populate mh-show-mode-map |
920 (gnus-define-keys mh-show-mode-map | 884 (gnus-define-keys mh-show-mode-map |
921 " " mh-show-page-msg | 885 " " mh-show-page-msg |
922 "!" mh-show-refile-or-write-again | 886 "!" mh-show-refile-or-write-again |
939 "e" mh-show-edit-again | 903 "e" mh-show-edit-again |
940 "f" mh-show-forward | 904 "f" mh-show-forward |
941 "g" mh-show-goto-msg | 905 "g" mh-show-goto-msg |
942 "i" mh-show-inc-folder | 906 "i" mh-show-inc-folder |
943 "k" mh-show-delete-subject-or-thread | 907 "k" mh-show-delete-subject-or-thread |
944 "l" mh-show-print-msg | |
945 "m" mh-show-send | 908 "m" mh-show-send |
946 "n" mh-show-next-undeleted-msg | 909 "n" mh-show-next-undeleted-msg |
947 "\M-n" mh-show-next-unread-msg | 910 "\M-n" mh-show-next-unread-msg |
948 "o" mh-show-refile-msg | 911 "o" mh-show-refile-msg |
949 "p" mh-show-previous-undeleted-msg | 912 "p" mh-show-previous-undeleted-msg |
959 | 922 |
960 (gnus-define-keys (mh-show-folder-map "F" mh-show-mode-map) | 923 (gnus-define-keys (mh-show-folder-map "F" mh-show-mode-map) |
961 "?" mh-prefix-help | 924 "?" mh-prefix-help |
962 "'" mh-index-ticked-messages | 925 "'" mh-index-ticked-messages |
963 "S" mh-show-sort-folder | 926 "S" mh-show-sort-folder |
927 "c" mh-show-catchup | |
964 "f" mh-show-visit-folder | 928 "f" mh-show-visit-folder |
965 "i" mh-index-search | 929 "i" mh-index-search |
966 "k" mh-show-kill-folder | 930 "k" mh-show-kill-folder |
967 "l" mh-show-list-folders | 931 "l" mh-show-list-folders |
968 "n" mh-index-new-messages | 932 "n" mh-index-new-messages |
990 (gnus-define-keys (mh-show-junk-map "J" mh-show-mode-map) | 954 (gnus-define-keys (mh-show-junk-map "J" mh-show-mode-map) |
991 "?" mh-prefix-help | 955 "?" mh-prefix-help |
992 "b" mh-show-junk-blacklist | 956 "b" mh-show-junk-blacklist |
993 "w" mh-show-junk-whitelist) | 957 "w" mh-show-junk-whitelist) |
994 | 958 |
959 (gnus-define-keys (mh-show-ps-print-map "P" mh-show-mode-map) | |
960 "?" mh-prefix-help | |
961 "A" mh-show-ps-print-toggle-mime | |
962 "C" mh-show-ps-print-toggle-color | |
963 "F" mh-show-ps-print-toggle-faces | |
964 "M" mh-show-ps-print-toggle-mime | |
965 "f" mh-show-ps-print-msg-file | |
966 "l" mh-show-print-msg | |
967 "p" mh-show-ps-print-msg | |
968 "s" mh-show-ps-print-msg-show) | |
969 | |
995 (gnus-define-keys (mh-show-thread-map "T" mh-show-mode-map) | 970 (gnus-define-keys (mh-show-thread-map "T" mh-show-mode-map) |
996 "?" mh-prefix-help | 971 "?" mh-prefix-help |
997 "u" mh-show-thread-ancestor | 972 "u" mh-show-thread-ancestor |
998 "p" mh-show-thread-previous-sibling | 973 "p" mh-show-thread-previous-sibling |
999 "n" mh-show-thread-next-sibling | 974 "n" mh-show-thread-next-sibling |
1024 "b" mh-show-burst-digest) | 999 "b" mh-show-burst-digest) |
1025 | 1000 |
1026 (gnus-define-keys (mh-show-mime-map "K" mh-show-mode-map) | 1001 (gnus-define-keys (mh-show-mime-map "K" mh-show-mode-map) |
1027 "?" mh-prefix-help | 1002 "?" mh-prefix-help |
1028 "a" mh-mime-save-parts | 1003 "a" mh-mime-save-parts |
1004 "e" mh-show-display-with-external-viewer | |
1029 "v" mh-show-toggle-mime-part | 1005 "v" mh-show-toggle-mime-part |
1030 "o" mh-show-save-mime-part | 1006 "o" mh-show-save-mime-part |
1031 "i" mh-show-inline-mime-part | 1007 "i" mh-show-inline-mime-part |
1008 "t" mh-show-toggle-mime-buttons | |
1032 "\t" mh-show-next-button | 1009 "\t" mh-show-next-button |
1033 [backtab] mh-show-prev-button | 1010 [backtab] mh-show-prev-button |
1034 "\M-\t" mh-show-prev-button) | 1011 "\M-\t" mh-show-prev-button) |
1035 | 1012 |
1036 (easy-menu-define | 1013 (easy-menu-define |
1113 (defvar tool-bar-map)) | 1090 (defvar tool-bar-map)) |
1114 | 1091 |
1115 (define-derived-mode mh-show-mode text-mode "MH-Show" | 1092 (define-derived-mode mh-show-mode text-mode "MH-Show" |
1116 "Major mode for showing messages in MH-E.\\<mh-show-mode-map> | 1093 "Major mode for showing messages in MH-E.\\<mh-show-mode-map> |
1117 The value of `mh-show-mode-hook' is a list of functions to | 1094 The value of `mh-show-mode-hook' is a list of functions to |
1118 be called, with no arguments, upon entry to this mode." | 1095 be called, with no arguments, upon entry to this mode. |
1096 See also `mh-folder-mode'. | |
1097 | |
1098 \\{mh-show-mode-map}" | |
1119 (set (make-local-variable 'mail-header-separator) mh-mail-header-separator) | 1099 (set (make-local-variable 'mail-header-separator) mh-mail-header-separator) |
1120 (setq paragraph-start (default-value 'paragraph-start)) | 1100 (setq paragraph-start (default-value 'paragraph-start)) |
1121 (mh-show-unquote-From) | 1101 (mh-show-unquote-From) |
1122 (mh-show-xface) | 1102 (mh-show-xface) |
1123 (mh-show-addr) | 1103 (mh-show-addr) |
1208 (insert "P4\n48 48\n"))) | 1188 (insert "P4\n48 48\n"))) |
1209 | 1189 |
1210 (mh-do-in-xemacs (defvar default-enable-multibyte-characters)) | 1190 (mh-do-in-xemacs (defvar default-enable-multibyte-characters)) |
1211 | 1191 |
1212 (defun mh-face-display-function () | 1192 (defun mh-face-display-function () |
1213 "Display a Face or X-Face header field. | 1193 "Display a Face, X-Face, or X-Image-URL header field. |
1214 Display Face if both are present." | 1194 If more than one of these are present, then the first one found in this order |
1195 is used." | |
1215 (save-restriction | 1196 (save-restriction |
1216 (goto-char (point-min)) | 1197 (goto-char (point-min)) |
1217 (re-search-forward "\n\n" (point-max) t) | 1198 (re-search-forward "\n\n" (point-max) t) |
1218 (narrow-to-region (point-min) (point)) | 1199 (narrow-to-region (point-min) (point)) |
1219 (let* ((case-fold-search t) | 1200 (let* ((case-fold-search t) |
1224 raw type) | 1205 raw type) |
1225 (cond (face (setq raw (mh-face-to-png face) | 1206 (cond (face (setq raw (mh-face-to-png face) |
1226 type 'png)) | 1207 type 'png)) |
1227 (x-face (setq raw (mh-uncompface x-face) | 1208 (x-face (setq raw (mh-uncompface x-face) |
1228 type 'pbm)) | 1209 type 'pbm)) |
1229 (url (setq type 'url))) | 1210 (url (setq type 'url)) |
1211 (t (multiple-value-setq (type raw) (mh-picon-get-image)))) | |
1230 (when type | 1212 (when type |
1231 (goto-char (point-min)) | 1213 (goto-char (point-min)) |
1232 (when (re-search-forward "^from:" (point-max) t) | 1214 (when (re-search-forward "^from:" (point-max) t) |
1233 ;; GNU Emacs | 1215 ;; GNU Emacs |
1234 (mh-do-in-gnu-emacs | 1216 (mh-do-in-gnu-emacs |
1259 'mh-show-xface-face)) | 1241 'mh-show-xface-face)) |
1260 ;; Otherwise try external support with x-face... | 1242 ;; Otherwise try external support with x-face... |
1261 ((and (eq type 'pbm) | 1243 ((and (eq type 'pbm) |
1262 (fboundp 'x-face-xmas-wl-display-x-face) | 1244 (fboundp 'x-face-xmas-wl-display-x-face) |
1263 (fboundp 'executable-find) (executable-find "uncompface")) | 1245 (fboundp 'executable-find) (executable-find "uncompface")) |
1264 (mh-funcall-if-exists x-face-xmas-wl-display-x-face))) | 1246 (mh-funcall-if-exists x-face-xmas-wl-display-x-face)) |
1247 ;; Picon display | |
1248 ((and raw (member type '(xpm xbm gif))) | |
1249 (when (featurep type) | |
1250 (set-extent-begin-glyph | |
1251 (make-extent (point) (point)) | |
1252 (make-glyph (vector type ':data raw)))))) | |
1265 (when raw (insert " ")))))))) | 1253 (when raw (insert " ")))))))) |
1266 | |
1267 | 1254 |
1268 (defun mh-show-xface () | 1255 (defun mh-show-xface () |
1269 "Display X-Face." | 1256 "Display X-Face." |
1270 (when (and window-system mh-show-use-xface-flag | 1257 (when (and window-system mh-show-use-xface-flag |
1271 (or mh-decode-mime-flag mhl-formfile | 1258 (or mh-decode-mime-flag mhl-formfile |
1272 mh-clean-message-header-flag)) | 1259 mh-clean-message-header-flag)) |
1273 (funcall mh-show-xface-function))) | 1260 (funcall mh-show-xface-function))) |
1274 | 1261 |
1275 | 1262 |
1276 | 1263 |
1264 ;; Picon display | |
1265 | |
1266 ;;; XXX: This should be customizable. As a side-effect of setting this | |
1267 ;;; variable, arrange to reset mh-picon-existing-directory-list to 'unset. | |
1268 (defvar mh-picon-directory-list | |
1269 '("~/.picons" "~/.picons/users" "~/.picons/usenix" "~/.picons/news" | |
1270 "~/.picons/domains" "~/.picons/misc" | |
1271 "/usr/share/picons/" "/usr/share/picons/users" "/usr/share/picons/usenix" | |
1272 "/usr/share/picons/news" "/usr/share/picons/domains" | |
1273 "/usr/share/picons/misc") | |
1274 "List of directories where picons reside. | |
1275 The directories are searched for in the order they appear in the list.") | |
1276 | |
1277 (defvar mh-picon-existing-directory-list 'unset | |
1278 "List of directories to search in.") | |
1279 | |
1280 (defvar mh-picon-cache (make-hash-table :test #'equal)) | |
1281 | |
1282 (defvar mh-picon-image-types | |
1283 (loop for type in '(xpm xbm gif) | |
1284 when (or (mh-do-in-gnu-emacs | |
1285 (ignore-errors | |
1286 (mh-funcall-if-exists image-type-available-p type))) | |
1287 (mh-do-in-xemacs (featurep type))) | |
1288 collect type)) | |
1289 | |
1290 (defun mh-picon-set-directory-list () | |
1291 "Update `mh-picon-existing-directory-list' if needed." | |
1292 (when (eq mh-picon-existing-directory-list 'unset) | |
1293 (setq mh-picon-existing-directory-list | |
1294 (loop for x in mh-picon-directory-list | |
1295 when (file-directory-p x) collect x)))) | |
1296 | |
1297 (defun* mh-picon-get-image () | |
1298 "Find the best possible match and return contents." | |
1299 (mh-picon-set-directory-list) | |
1300 (save-restriction | |
1301 (let* ((from-field (ignore-errors (car (message-tokenize-header | |
1302 (mh-get-header-field "from:"))))) | |
1303 (from (car (ignore-errors | |
1304 (mh-funcall-if-exists ietf-drums-parse-address | |
1305 from-field)))) | |
1306 (host (and from | |
1307 (string-match "\\([^+]*\\)\\(+.*\\)?@\\(.*\\)" from) | |
1308 (downcase (match-string 3 from)))) | |
1309 (user (and host (downcase (match-string 1 from)))) | |
1310 (canonical-address (format "%s@%s" user host)) | |
1311 (cached-value (gethash canonical-address mh-picon-cache)) | |
1312 (host-list (and host (delete "" (split-string host "\\.")))) | |
1313 (match nil)) | |
1314 (cond (cached-value (return-from mh-picon-get-image cached-value)) | |
1315 ((not host-list) (return-from mh-picon-get-image nil))) | |
1316 (setq match | |
1317 (block 'loop | |
1318 ;; u@h search | |
1319 (loop for dir in mh-picon-existing-directory-list | |
1320 do (loop for type in mh-picon-image-types | |
1321 ;; [path]user@host | |
1322 for file1 = (format "%s/%s.%s" | |
1323 dir canonical-address type) | |
1324 when (file-exists-p file1) | |
1325 do (return-from 'loop file1) | |
1326 ;; [path]user | |
1327 for file2 = (format "%s/%s.%s" dir user type) | |
1328 when (file-exists-p file2) | |
1329 do (return-from 'loop file2) | |
1330 ;; [path]host | |
1331 for file3 = (format "%s/%s.%s" dir host type) | |
1332 when (file-exists-p file3) | |
1333 do (return-from 'loop file3))) | |
1334 ;; facedb search | |
1335 ;; Search order for user@foo.net: | |
1336 ;; [path]net/foo/user | |
1337 ;; [path]net/foo/user/face | |
1338 ;; [path]net/user | |
1339 ;; [path]net/user/face | |
1340 ;; [path]net/foo/unknown | |
1341 ;; [path]net/foo/unknown/face | |
1342 ;; [path]net/unknown | |
1343 ;; [path]net/unknown/face | |
1344 (loop for u in (list user "unknown") | |
1345 do (loop for dir in mh-picon-existing-directory-list | |
1346 do (loop for x on host-list by #'cdr | |
1347 for y = (mh-picon-generate-path x u dir) | |
1348 do (loop for type in mh-picon-image-types | |
1349 for z1 = (format "%s.%s" y type) | |
1350 when (file-exists-p z1) | |
1351 do (return-from 'loop z1) | |
1352 for z2 = (format "%s/face.%s" | |
1353 y type) | |
1354 when (file-exists-p z2) | |
1355 do (return-from 'loop z2))))))) | |
1356 (setf (gethash canonical-address mh-picon-cache) | |
1357 (mh-picon-file-contents match))))) | |
1358 | |
1359 (defun mh-picon-file-contents (file) | |
1360 "Return details about FILE. | |
1361 A list of consisting of a symbol for the type of the file and the file | |
1362 contents as a string is returned. If FILE is nil, then both elements of the | |
1363 list are nil." | |
1364 (if (stringp file) | |
1365 (with-temp-buffer | |
1366 (let ((type (and (string-match ".*\\.\\(...\\)$" file) | |
1367 (intern (match-string 1 file))))) | |
1368 (insert-file-contents-literally file) | |
1369 (values type (buffer-string)))) | |
1370 (values nil nil))) | |
1371 | |
1372 (defun mh-picon-generate-path (host-list user directory) | |
1373 "Generate the image file path. | |
1374 HOST-LIST is the parsed host address of the email address, USER the username | |
1375 and DIRECTORY is the directory relative to which the path is generated." | |
1376 (loop with acc = "" | |
1377 for elem in host-list | |
1378 do (setq acc (format "%s/%s" elem acc)) | |
1379 finally return (format "%s/%s%s" directory acc user))) | |
1380 | |
1381 | |
1382 | |
1277 ;; X-Image-URL display | 1383 ;; X-Image-URL display |
1278 | 1384 |
1279 (defvar mh-x-image-cache-directory nil | 1385 (defvar mh-x-image-cache-directory nil |
1280 "Directory where X-Image-URL images are cached.") | 1386 "Directory where X-Image-URL images are cached.") |
1281 | 1387 (defvar mh-x-image-scaling-function |
1282 (defvar mh-convert-executable (executable-find "convert")) | 1388 (cond ((executable-find "convert") |
1283 (defvar mh-wget-executable (executable-find "wget")) | 1389 'mh-x-image-scale-with-convert) |
1390 ((and (executable-find "anytopnm") (executable-find "pnmscale") | |
1391 (executable-find "pnmtopng")) | |
1392 'mh-x-image-scale-with-pnm) | |
1393 (t 'ignore)) | |
1394 "Function to use to scale image to proper size.") | |
1395 (defvar mh-wget-executable nil) | |
1396 (defvar mh-wget-choice | |
1397 (or (and (setq mh-wget-executable (executable-find "wget")) 'wget) | |
1398 (and (setq mh-wget-executable (executable-find "fetch")) 'fetch) | |
1399 (and (setq mh-wget-executable (executable-find "curl")) 'curl))) | |
1400 (defvar mh-wget-option | |
1401 (cdr (assoc mh-wget-choice '((curl . "-o") (fetch . "-o") (wget . "-O"))))) | |
1284 (defvar mh-x-image-temp-file nil) | 1402 (defvar mh-x-image-temp-file nil) |
1285 (defvar mh-x-image-url nil) | 1403 (defvar mh-x-image-url nil) |
1286 (defvar mh-x-image-marker nil) | 1404 (defvar mh-x-image-marker nil) |
1287 (defvar mh-x-image-url-cache-file nil) | 1405 (defvar mh-x-image-url-cache-file nil) |
1288 | 1406 |
1407 ;; Functions to scale image to proper size | |
1408 (defun mh-x-image-scale-with-pnm (input output) | |
1409 "Scale image in INPUT file and write to OUTPUT file using pnm tools." | |
1410 (let ((res (shell-command-to-string | |
1411 (format "anytopnm < %s | pnmscale -xysize 96 48 | pnmtopng > %s" | |
1412 input output)))) | |
1413 (unless (equal res "") | |
1414 (delete-file output)))) | |
1415 | |
1416 (defun mh-x-image-scale-with-convert (input output) | |
1417 "Scale image in INPUT file and write to OUTPUT file using ImageMagick." | |
1418 (call-process "convert" nil nil nil "-geometry" "96x48" input output)) | |
1419 | |
1289 (defun mh-x-image-url-cache-canonicalize (url) | 1420 (defun mh-x-image-url-cache-canonicalize (url) |
1290 "Canonicalize URL. | 1421 "Canonicalize URL. |
1291 Replace the ?/ character with a ?! character." | 1422 Replace the ?/ character with a ?! character and append .png." |
1292 (with-temp-buffer | 1423 (format "%s/%s.png" mh-x-image-cache-directory |
1293 (insert url) | 1424 (with-temp-buffer |
1294 (goto-char (point-min)) | 1425 (insert url) |
1295 (while (search-forward "/" nil t) (replace-match "!")) | 1426 (mh-replace-string "/" "!") |
1296 (format "%s/%s.png" mh-x-image-cache-directory (buffer-string)))) | 1427 (buffer-string)))) |
1428 | |
1429 (defun mh-x-image-set-download-state (file data) | |
1430 "Setup a symbolic link from FILE to DATA." | |
1431 (if data | |
1432 (make-symbolic-link (symbol-name data) file t) | |
1433 (delete-file file))) | |
1434 | |
1435 (defun mh-x-image-get-download-state (file) | |
1436 "Check the state of FILE by following any symbolic links." | |
1437 (unless (file-exists-p mh-x-image-cache-directory) | |
1438 (call-process "mkdir" nil nil nil mh-x-image-cache-directory)) | |
1439 (cond ((file-symlink-p file) | |
1440 (intern (file-name-nondirectory (file-chase-links file)))) | |
1441 ((not (file-exists-p file)) nil) | |
1442 (t 'ok))) | |
1297 | 1443 |
1298 (defun mh-x-image-url-fetch-image (url cache-file marker sentinel) | 1444 (defun mh-x-image-url-fetch-image (url cache-file marker sentinel) |
1299 "Fetch and display the image specified by URL. | 1445 "Fetch and display the image specified by URL. |
1300 After the image is fetched, it is stored in CACHE-FILE. It will be displayed | 1446 After the image is fetched, it is stored in CACHE-FILE. It will be displayed |
1301 in a buffer and position specified by MARKER. The actual display is carried | 1447 in a buffer and position specified by MARKER. The actual display is carried |
1302 out by the SENTINEL function." | 1448 out by the SENTINEL function." |
1303 (if (and mh-wget-executable | 1449 (if mh-wget-executable |
1304 mh-fetch-x-image-url | 1450 (let ((buffer (get-buffer-create (generate-new-buffer-name |
1305 (or (eq mh-fetch-x-image-url t) | 1451 mh-temp-fetch-buffer))) |
1306 (y-or-n-p (format "Fetch %s? " url)))) | 1452 (filename (or (mh-funcall-if-exists make-temp-file "mhe-fetch") |
1307 (let ((buffer (get-buffer-create (generate-new-buffer-name " *mh-url*"))) | 1453 (expand-file-name (make-temp-name "~/mhe-fetch"))))) |
1308 (filename (make-temp-name "/tmp/mhe-wget"))) | |
1309 (save-excursion | 1454 (save-excursion |
1310 (set-buffer buffer) | 1455 (set-buffer buffer) |
1311 (set (make-local-variable 'mh-x-image-url-cache-file) cache-file) | 1456 (set (make-local-variable 'mh-x-image-url-cache-file) cache-file) |
1312 (set (make-local-variable 'mh-x-image-marker) marker) | 1457 (set (make-local-variable 'mh-x-image-marker) marker) |
1313 (set (make-local-variable 'mh-x-image-temp-file) filename)) | 1458 (set (make-local-variable 'mh-x-image-temp-file) filename)) |
1314 (set-process-sentinel | 1459 (set-process-sentinel |
1315 (start-process "*wget*" buffer mh-wget-executable "-O" filename url) | 1460 (start-process "*mh-x-image-url-fetch*" buffer |
1461 mh-wget-executable mh-wget-option filename url) | |
1316 sentinel)) | 1462 sentinel)) |
1317 ;; Make sure we don't ask about this image again | 1463 ;; Temporary failure |
1318 (when (and mh-wget-executable (eq mh-fetch-x-image-url 'ask)) | 1464 (mh-x-image-set-download-state cache-file 'try-again))) |
1319 (make-symbolic-link mh-x-image-cache-directory cache-file t)))) | |
1320 | 1465 |
1321 (defun mh-x-image-display (image marker) | 1466 (defun mh-x-image-display (image marker) |
1322 "Display IMAGE at MARKER." | 1467 "Display IMAGE at MARKER." |
1323 (save-excursion | 1468 (save-excursion |
1324 (set-buffer (marker-buffer marker)) | 1469 (set-buffer (marker-buffer marker)) |
1325 (let ((buffer-read-only nil) | 1470 (let ((buffer-read-only nil) |
1326 (default-enable-multibyte-characters nil) | 1471 (default-enable-multibyte-characters nil) |
1327 (buffer-modified-flag (buffer-modified-p))) | 1472 (buffer-modified-flag (buffer-modified-p))) |
1328 (unwind-protect | 1473 (unwind-protect |
1329 (when (and (file-readable-p image) (not (file-symlink-p image))) | 1474 (when (and (file-readable-p image) (not (file-symlink-p image)) |
1475 (eq marker mh-x-image-marker)) | |
1330 (goto-char marker) | 1476 (goto-char marker) |
1331 (mh-do-in-gnu-emacs | 1477 (mh-do-in-gnu-emacs |
1332 (mh-funcall-if-exists insert-image (create-image image 'png))) | 1478 (mh-funcall-if-exists insert-image (create-image image 'png))) |
1333 (mh-do-in-xemacs | 1479 (mh-do-in-xemacs |
1334 (when (featurep 'png) | 1480 (when (featurep 'png) |
1348 (save-excursion | 1494 (save-excursion |
1349 (set-buffer (setq wget-buffer (process-buffer process))) | 1495 (set-buffer (setq wget-buffer (process-buffer process))) |
1350 (setq marker mh-x-image-marker | 1496 (setq marker mh-x-image-marker |
1351 cache-filename mh-x-image-url-cache-file | 1497 cache-filename mh-x-image-url-cache-file |
1352 temp-file mh-x-image-temp-file)) | 1498 temp-file mh-x-image-temp-file)) |
1353 (when mh-convert-executable | 1499 (cond |
1354 (call-process mh-convert-executable nil nil nil "-resize" "96x48" | 1500 ;; Check if we have `convert' |
1355 temp-file cache-filename)) | 1501 ((eq mh-x-image-scaling-function 'ignore) |
1356 (if (file-exists-p cache-filename) | 1502 (message "The `convert' program is needed to display X-Image-URL") |
1357 (mh-x-image-display cache-filename marker) | 1503 (mh-x-image-set-download-state cache-filename 'try-again)) |
1358 (make-symbolic-link mh-x-image-cache-directory cache-filename t)) | 1504 ;; Scale fetched image |
1505 ((and (funcall mh-x-image-scaling-function temp-file cache-filename) | |
1506 nil)) | |
1507 ;; Attempt to display image if we have it | |
1508 ((file-exists-p cache-filename) | |
1509 (mh-x-image-display cache-filename marker)) | |
1510 ;; We didn't find the image. Should we try to display it the next time? | |
1511 (t (mh-x-image-set-download-state cache-filename 'try-again))) | |
1359 (ignore-errors | 1512 (ignore-errors |
1360 (set-marker marker nil) | 1513 (set-marker marker nil) |
1361 (delete-process process) | 1514 (delete-process process) |
1362 (kill-buffer wget-buffer) | 1515 (kill-buffer wget-buffer) |
1363 (delete-file temp-file))))) | 1516 (delete-file temp-file))))) |
1364 | 1517 |
1518 (defun mh-x-image-url-sane-p (url) | |
1519 "Check if URL is something sensible." | |
1520 (let ((len (length url))) | |
1521 (cond ((< len 5) nil) | |
1522 ((not (equal (substring url 0 5) "http:")) nil) | |
1523 ((> len 100) nil) | |
1524 (t t)))) | |
1525 | |
1365 (defun mh-x-image-url-display (url) | 1526 (defun mh-x-image-url-display (url) |
1366 "Display image from location URL. | 1527 "Display image from location URL. |
1367 If the URL isn't present in the cache then it is fetched with wget." | 1528 If the URL isn't present in the cache then it is fetched with wget." |
1368 (let ((cache-filename (mh-x-image-url-cache-canonicalize url)) | 1529 (let* ((cache-filename (mh-x-image-url-cache-canonicalize url)) |
1369 (marker (set-marker (make-marker) (point)))) | 1530 (state (mh-x-image-get-download-state cache-filename)) |
1370 (cond ((file-exists-p cache-filename) | 1531 (marker (set-marker (make-marker) (point)))) |
1532 (set (make-local-variable 'mh-x-image-marker) marker) | |
1533 (cond ((not (mh-x-image-url-sane-p url))) | |
1534 ((eq state 'ok) | |
1371 (mh-x-image-display cache-filename marker)) | 1535 (mh-x-image-display cache-filename marker)) |
1536 ((or (not mh-wget-executable) | |
1537 (eq mh-x-image-scaling-function 'ignore))) | |
1538 ((eq state 'never)) | |
1372 ((not mh-fetch-x-image-url) | 1539 ((not mh-fetch-x-image-url) |
1373 (set-marker marker nil)) | 1540 (set-marker marker nil)) |
1374 ((and (not (file-exists-p mh-x-image-cache-directory)) | 1541 ((eq state 'try-again) |
1375 (call-process "mkdir" nil nil nil mh-x-image-cache-directory) | 1542 (mh-x-image-set-download-state cache-filename nil) |
1376 nil)) | 1543 (mh-x-image-url-fetch-image url cache-filename marker |
1377 ((and (file-exists-p mh-x-image-cache-directory) | 1544 'mh-x-image-scale-and-display)) |
1378 (file-directory-p mh-x-image-cache-directory)) | 1545 ((and (eq mh-fetch-x-image-url 'ask) |
1546 (not (y-or-n-p (format "Fetch %s? " url)))) | |
1547 (mh-x-image-set-download-state cache-filename 'never)) | |
1548 ((eq state nil) | |
1379 (mh-x-image-url-fetch-image url cache-filename marker | 1549 (mh-x-image-url-fetch-image url cache-filename marker |
1380 'mh-x-image-scale-and-display))))) | 1550 'mh-x-image-scale-and-display))))) |
1381 | 1551 |
1382 | 1552 |
1383 | 1553 |
1384 (defun mh-maybe-show (&optional msg) | 1554 (defun mh-maybe-show (&optional msg) |
1385 "Display message at cursor, but only if in show mode. | 1555 "Display message at cursor, but only if in show mode. |
1386 If optional arg MSG is non-nil, display that message instead." | 1556 If optional arg MSG is non-nil, display that message instead." |
1387 (if mh-showing-mode (mh-show msg))) | 1557 (if mh-showing-mode (mh-show msg))) |
1388 | 1558 |
1389 (defun mh-show (&optional message) | 1559 (defun mh-show (&optional message redisplay-flag) |
1390 "Show message at cursor. | 1560 "Show message at cursor. |
1391 If optional argument MESSAGE is non-nil, display that message instead. | 1561 If optional argument MESSAGE is non-nil, display that message instead. |
1392 Force a two-window display with the folder window on top (size given by the | 1562 Force a two-window display with the folder window on top (size given by the |
1393 variable `mh-summary-height') and the show buffer below it. | 1563 variable `mh-summary-height') and the show buffer below it. |
1394 If the message is already visible, display the start of the message. | 1564 If the message is already visible, display the start of the message. |
1395 | 1565 |
1566 If REDISPLAY-FLAG is non-nil, the default when called interactively, the | |
1567 message is redisplayed even if the show buffer was already displaying the | |
1568 correct message. | |
1569 | |
1396 Display of the message is controlled by setting the variables | 1570 Display of the message is controlled by setting the variables |
1397 `mh-clean-message-header-flag' and `mhl-formfile'. The default behavior is | 1571 `mh-clean-message-header-flag' and `mhl-formfile'. The default behavior is |
1398 to scroll uninteresting headers off the top of the window. | 1572 to scroll uninteresting headers off the top of the window. |
1399 Type \"\\[mh-header-display]\" to see the message with all its headers." | 1573 Type \"\\[mh-header-display]\" to see the message with all its headers." |
1400 (interactive) | 1574 (interactive (list nil t)) |
1401 (and mh-showing-with-headers | 1575 (when (or redisplay-flag |
1402 (or mhl-formfile mh-clean-message-header-flag) | 1576 (and mh-showing-with-headers |
1403 (mh-invalidate-show-buffer)) | 1577 (or mhl-formfile mh-clean-message-header-flag))) |
1578 (mh-invalidate-show-buffer)) | |
1404 (mh-show-msg message)) | 1579 (mh-show-msg message)) |
1405 | 1580 |
1406 (defun mh-show-mouse (EVENT) | 1581 (defun mh-show-mouse (event) |
1407 "Move point to mouse EVENT and show message." | 1582 "Move point to mouse EVENT and show message." |
1408 (interactive "e") | 1583 (interactive "e") |
1409 (mouse-set-point EVENT) | 1584 (mouse-set-point event) |
1410 (mh-show)) | 1585 (mh-show)) |
1411 | 1586 |
1412 (defun mh-summary-height () | 1587 (defun mh-summary-height () |
1413 "Return ideal value for the variable `mh-summary-height'. | 1588 "Return ideal value for the variable `mh-summary-height'. |
1414 The current frame height is taken into consideration." | 1589 The current frame height is taken into consideration." |
1426 (mh-showing-mode t) | 1601 (mh-showing-mode t) |
1427 (setq mh-page-to-next-msg-flag nil) | 1602 (setq mh-page-to-next-msg-flag nil) |
1428 (let ((folder mh-current-folder) | 1603 (let ((folder mh-current-folder) |
1429 (folders (list mh-current-folder)) | 1604 (folders (list mh-current-folder)) |
1430 (clean-message-header mh-clean-message-header-flag) | 1605 (clean-message-header mh-clean-message-header-flag) |
1431 (show-window (get-buffer-window mh-show-buffer))) | 1606 (show-window (get-buffer-window mh-show-buffer)) |
1607 (display-mime-buttons-flag mh-display-buttons-for-inline-parts-flag)) | |
1432 (if (not (eq (next-window (minibuffer-window)) (selected-window))) | 1608 (if (not (eq (next-window (minibuffer-window)) (selected-window))) |
1433 (delete-other-windows)) ; force ourself to the top window | 1609 (delete-other-windows)) ; force ourself to the top window |
1434 (mh-in-show-buffer (mh-show-buffer) | 1610 (mh-in-show-buffer (mh-show-buffer) |
1611 (setq mh-display-buttons-for-inline-parts-flag display-mime-buttons-flag) | |
1435 (if (and show-window | 1612 (if (and show-window |
1436 (equal (mh-msg-filename msg folder) buffer-file-name)) | 1613 (equal (mh-msg-filename msg folder) buffer-file-name)) |
1437 (progn ;just back up to start | 1614 (progn ;just back up to start |
1438 (goto-char (point-min)) | 1615 (goto-char (point-min)) |
1439 (if (not clean-message-header) | 1616 (if (not clean-message-header) |
1441 (mh-display-msg msg folder))) | 1618 (mh-display-msg msg folder))) |
1442 (if (not (= (1+ (window-height)) (frame-height))) ;not horizontally split | 1619 (if (not (= (1+ (window-height)) (frame-height))) ;not horizontally split |
1443 (shrink-window (- (window-height) (or mh-summary-height | 1620 (shrink-window (- (window-height) (or mh-summary-height |
1444 (mh-summary-height))))) | 1621 (mh-summary-height))))) |
1445 (mh-recenter nil) | 1622 (mh-recenter nil) |
1623 ;; The following line is a nop which forces update of the scan line so | |
1624 ;; that font-lock will update it (if needed)... | |
1625 (mh-notate nil nil mh-cmd-note) | |
1446 (if (not (memq msg mh-seen-list)) | 1626 (if (not (memq msg mh-seen-list)) |
1447 (setq mh-seen-list (cons msg mh-seen-list))) | 1627 (setq mh-seen-list (cons msg mh-seen-list))) |
1448 (when mh-update-sequences-after-mh-show-flag | 1628 (when mh-update-sequences-after-mh-show-flag |
1449 (mh-update-sequences) | 1629 (mh-update-sequences) |
1450 (when mh-index-data | 1630 (when mh-index-data |
1516 (unless (mh-buffer-data) | 1696 (unless (mh-buffer-data) |
1517 (setf (mh-buffer-data) (mh-make-buffer-data))) | 1697 (setf (mh-buffer-data) (mh-make-buffer-data))) |
1518 ;; Bind variables in folder buffer in case they are local | 1698 ;; Bind variables in folder buffer in case they are local |
1519 (let ((formfile mhl-formfile) | 1699 (let ((formfile mhl-formfile) |
1520 (clean-message-header mh-clean-message-header-flag) | 1700 (clean-message-header mh-clean-message-header-flag) |
1521 (invisible-headers mh-invisible-headers) | 1701 (invisible-headers mh-invisible-header-fields-compiled) |
1522 (visible-headers mh-visible-headers) | 1702 (visible-headers nil) |
1523 (msg-filename (mh-msg-filename msg-num folder-name)) | 1703 (msg-filename (mh-msg-filename msg-num folder-name)) |
1524 (show-buffer mh-show-buffer) | 1704 (show-buffer mh-show-buffer) |
1525 (mm-inline-media-tests mh-mm-inline-media-tests)) | 1705 (mm-inline-media-tests mh-mm-inline-media-tests)) |
1526 (if (not (file-exists-p msg-filename)) | 1706 (if (not (file-exists-p msg-filename)) |
1527 (error "Message %d does not exist" msg-num)) | 1707 (error "Message %d does not exist" msg-num)) |
1594 (defun mh-clean-msg-header (start invisible-headers visible-headers) | 1774 (defun mh-clean-msg-header (start invisible-headers visible-headers) |
1595 "Flush extraneous lines in message header. | 1775 "Flush extraneous lines in message header. |
1596 Header is cleaned from START to the end of the message header. | 1776 Header is cleaned from START to the end of the message header. |
1597 INVISIBLE-HEADERS contains a regular expression specifying lines to delete | 1777 INVISIBLE-HEADERS contains a regular expression specifying lines to delete |
1598 from the header. VISIBLE-HEADERS contains a regular expression specifying the | 1778 from the header. VISIBLE-HEADERS contains a regular expression specifying the |
1599 lines to display. INVISIBLE-HEADERS is ignored if VISIBLE-HEADERS is non-nil." | 1779 lines to display. INVISIBLE-HEADERS is ignored if VISIBLE-HEADERS is non-nil. |
1780 | |
1781 Note that MH-E no longer supports the `mh-visible-headers' variable, so | |
1782 this function could be trimmed of this feature too." | |
1600 (let ((case-fold-search t) | 1783 (let ((case-fold-search t) |
1601 (buffer-read-only nil) | 1784 (buffer-read-only nil) |
1602 (after-change-functions nil)) ;Work around emacs-20 font-lock bug | 1785 (after-change-functions nil)) ;Work around emacs-20 font-lock bug |
1603 ;causing an endless loop. | 1786 ;causing an endless loop. |
1604 (save-restriction | 1787 (save-restriction |
1637 (if (or (null msg) | 1820 (if (or (null msg) |
1638 (mh-goto-msg msg t t)) | 1821 (mh-goto-msg msg t t)) |
1639 (with-mh-folder-updating (t) | 1822 (with-mh-folder-updating (t) |
1640 (beginning-of-line) | 1823 (beginning-of-line) |
1641 (forward-char offset) | 1824 (forward-char offset) |
1642 (let* ((change-stack-flag (and (stringp notation) | 1825 (let* ((change-stack-flag (and (equal offset (1+ mh-cmd-note)) |
1643 (equal offset (1+ mh-cmd-note)) | |
1644 (not (eq notation mh-note-seq)))) | 1826 (not (eq notation mh-note-seq)))) |
1645 (msg (and change-stack-flag (or msg (mh-get-msg-num nil)))) | 1827 (msg (and change-stack-flag (or msg (mh-get-msg-num nil)))) |
1646 (stack (and msg (gethash msg mh-sequence-notation-history))) | 1828 (stack (and msg (gethash msg mh-sequence-notation-history))) |
1647 (notation (or notation (char-after)))) | 1829 (notation (or notation (char-after)))) |
1648 (if stack | 1830 (if stack |
1650 ;; notate the message, since the notation would be replaced | 1832 ;; notate the message, since the notation would be replaced |
1651 ;; by a sequence notation. So we will just put the notation | 1833 ;; by a sequence notation. So we will just put the notation |
1652 ;; at the bottom of the stack. If the sequence is deleted, | 1834 ;; at the bottom of the stack. If the sequence is deleted, |
1653 ;; the correct notation will be shown. | 1835 ;; the correct notation will be shown. |
1654 (setf (gethash msg mh-sequence-notation-history) | 1836 (setf (gethash msg mh-sequence-notation-history) |
1655 (reverse (cons (aref notation 0) (cdr (reverse stack))))) | 1837 (reverse (cons notation (cdr (reverse stack))))) |
1656 ;; Since we don't have any sequence notations in the way, just | 1838 ;; Since we don't have any sequence notations in the way, just |
1657 ;; notate the scan line. | 1839 ;; notate the scan line. |
1658 (delete-char 1) | 1840 (delete-char 1) |
1659 (insert notation)) | 1841 (insert notation)) |
1660 (when change-stack-flag | 1842 (when change-stack-flag |
1661 (mh-thread-update-scan-line-map msg notation offset))))))) | 1843 (mh-thread-update-scan-line-map msg notation offset))))))) |
1662 | |
1663 (defun mh-find-msg-get-num (step) | |
1664 "Return the message number of the message nearest the cursor. | |
1665 Jumps over non-message lines, such as inc errors. | |
1666 If we have to search, STEP tells whether to search forward or backward." | |
1667 (or (mh-get-msg-num nil) | |
1668 (let ((msg-num nil) | |
1669 (nreverses 0)) | |
1670 (while (and (not msg-num) | |
1671 (< nreverses 2)) | |
1672 (cond ((eobp) | |
1673 (setq step -1) | |
1674 (setq nreverses (1+ nreverses))) | |
1675 ((bobp) | |
1676 (setq step 1) | |
1677 (setq nreverses (1+ nreverses)))) | |
1678 (forward-line step) | |
1679 (setq msg-num (mh-get-msg-num nil))) | |
1680 msg-num))) | |
1681 | 1844 |
1682 (defun mh-goto-msg (number &optional no-error-if-no-message dont-show) | 1845 (defun mh-goto-msg (number &optional no-error-if-no-message dont-show) |
1683 "Position the cursor at message NUMBER. | 1846 "Position the cursor at message NUMBER. |
1684 Optional non-nil second argument NO-ERROR-IF-NO-MESSAGE means return nil | 1847 Optional non-nil second argument NO-ERROR-IF-NO-MESSAGE means return nil |
1685 instead of signaling an error if message does not exist; in this case, the | 1848 instead of signaling an error if message does not exist; in this case, the |
1697 (setq return-value nil)) | 1860 (setq return-value nil)) |
1698 (beginning-of-line) | 1861 (beginning-of-line) |
1699 (or dont-show (not return-value) (mh-maybe-show number)) | 1862 (or dont-show (not return-value) (mh-maybe-show number)) |
1700 return-value)) | 1863 return-value)) |
1701 | 1864 |
1702 (defun mh-msg-search-pat (n) | |
1703 "Return a search pattern for message N in the scan listing." | |
1704 (format mh-scan-msg-search-regexp n)) | |
1705 | |
1706 (defun mh-get-profile-field (field) | 1865 (defun mh-get-profile-field (field) |
1707 "Find and return the value of FIELD in the current buffer. | 1866 "Find and return the value of FIELD in the current buffer. |
1708 Returns nil if the field is not in the buffer." | 1867 Returns nil if the field is not in the buffer." |
1709 (let ((case-fold-search t)) | 1868 (let ((case-fold-search t)) |
1710 (goto-char (point-min)) | 1869 (goto-char (point-min)) |
1714 (re-search-forward "[\t ]*\\([^\t \n].*\\)$" nil t) | 1873 (re-search-forward "[\t ]*\\([^\t \n].*\\)$" nil t) |
1715 (let ((start (match-beginning 1))) | 1874 (let ((start (match-beginning 1))) |
1716 (end-of-line) | 1875 (end-of-line) |
1717 (buffer-substring start (point))))))) | 1876 (buffer-substring start (point))))))) |
1718 | 1877 |
1719 (defvar mail-user-agent) | |
1720 (defvar read-mail-command) | |
1721 | |
1722 (defvar mh-find-path-run nil | 1878 (defvar mh-find-path-run nil |
1723 "Non-nil if `mh-find-path' has been run already.") | 1879 "Non-nil if `mh-find-path' has been run already.") |
1724 | 1880 |
1725 (defun mh-find-path () | 1881 (defun mh-find-path () |
1726 "Set `mh-progs', `mh-lib', and `mh-lib-progs' variables. | 1882 "Set variables from user's MH profile. |
1727 Set `mh-user-path', `mh-draft-folder', `mh-unseen-seq', `mh-previous-seq', | 1883 Set `mh-user-path', `mh-draft-folder', `mh-unseen-seq', `mh-previous-seq', |
1728 `mh-inbox' from user's MH profile. | 1884 `mh-inbox' from user's MH profile. |
1729 The value of `mh-find-path-hook' is a list of functions to be called, with no | 1885 The value of `mh-find-path-hook' is a list of functions to be called, with no |
1730 arguments, after these variable have been set." | 1886 arguments, after these variable have been set." |
1731 (mh-find-progs) | 1887 (mh-variants) |
1732 (unless mh-find-path-run | 1888 (unless mh-find-path-run |
1733 (setq mh-find-path-run t) | 1889 (setq mh-find-path-run t) |
1734 (setq read-mail-command 'mh-rmail) | 1890 (save-excursion |
1735 (setq mail-user-agent 'mh-e-user-agent)) | 1891 ;; Be sure profile is fully expanded before switching buffers |
1736 (save-excursion | 1892 (let ((profile (expand-file-name (or (getenv "MH") "~/.mh_profile")))) |
1737 ;; Be sure profile is fully expanded before switching buffers | 1893 (set-buffer (get-buffer-create mh-temp-buffer)) |
1738 (let ((profile (expand-file-name (or (getenv "MH") "~/.mh_profile")))) | 1894 (setq buffer-offer-save nil) ;for people who set default to t |
1739 (set-buffer (get-buffer-create mh-temp-buffer)) | 1895 (erase-buffer) |
1740 (setq buffer-offer-save nil) ;for people who set default to t | 1896 (condition-case err |
1741 (erase-buffer) | 1897 (insert-file-contents profile) |
1742 (condition-case err | 1898 (file-error |
1743 (insert-file-contents profile) | 1899 (mh-install profile err))) |
1744 (file-error | 1900 (setq mh-user-path (mh-get-profile-field "Path:")) |
1745 (mh-install profile err))) | 1901 (if (not mh-user-path) |
1746 (setq mh-user-path (mh-get-profile-field "Path:")) | 1902 (setq mh-user-path "Mail")) |
1747 (if (not mh-user-path) | 1903 (setq mh-user-path |
1748 (setq mh-user-path "Mail")) | 1904 (file-name-as-directory |
1749 (setq mh-user-path | 1905 (expand-file-name mh-user-path (expand-file-name "~")))) |
1750 (file-name-as-directory | 1906 (unless mh-x-image-cache-directory |
1751 (expand-file-name mh-user-path (expand-file-name "~")))) | 1907 (setq mh-x-image-cache-directory |
1752 (unless mh-x-image-cache-directory | 1908 (expand-file-name ".mhe-x-image-cache" mh-user-path))) |
1753 (setq mh-x-image-cache-directory | 1909 (setq mh-draft-folder (mh-get-profile-field "Draft-Folder:")) |
1754 (expand-file-name ".mhe-x-image-cache" mh-user-path))) | 1910 (if mh-draft-folder |
1755 (setq mh-draft-folder (mh-get-profile-field "Draft-Folder:")) | 1911 (progn |
1756 (if mh-draft-folder | 1912 (if (not (mh-folder-name-p mh-draft-folder)) |
1757 (progn | 1913 (setq mh-draft-folder (format "+%s" mh-draft-folder))) |
1758 (if (not (mh-folder-name-p mh-draft-folder)) | 1914 (if (not (file-exists-p (mh-expand-file-name mh-draft-folder))) |
1759 (setq mh-draft-folder (format "+%s" mh-draft-folder))) | 1915 (error |
1760 (if (not (file-exists-p (mh-expand-file-name mh-draft-folder))) | 1916 "Draft folder \"%s\" not found. Create it and try again" |
1761 (error "Draft folder \"%s\" not found. Create it and try again" | 1917 (mh-expand-file-name mh-draft-folder))))) |
1762 (mh-expand-file-name mh-draft-folder))))) | 1918 (setq mh-inbox (mh-get-profile-field "Inbox:")) |
1763 (setq mh-inbox (mh-get-profile-field "Inbox:")) | 1919 (cond ((not mh-inbox) |
1764 (cond ((not mh-inbox) | 1920 (setq mh-inbox "+inbox")) |
1765 (setq mh-inbox "+inbox")) | 1921 ((not (mh-folder-name-p mh-inbox)) |
1766 ((not (mh-folder-name-p mh-inbox)) | 1922 (setq mh-inbox (format "+%s" mh-inbox)))) |
1767 (setq mh-inbox (format "+%s" mh-inbox)))) | 1923 (setq mh-unseen-seq (mh-get-profile-field "Unseen-Sequence:")) |
1768 (setq mh-unseen-seq (mh-get-profile-field "Unseen-Sequence:")) | 1924 (if mh-unseen-seq |
1769 (if mh-unseen-seq | 1925 (setq mh-unseen-seq (intern mh-unseen-seq)) |
1770 (setq mh-unseen-seq (intern mh-unseen-seq)) | 1926 (setq mh-unseen-seq 'unseen)) ;old MH default? |
1771 (setq mh-unseen-seq 'unseen)) ;old MH default? | 1927 (setq mh-previous-seq (mh-get-profile-field "Previous-Sequence:")) |
1772 (setq mh-previous-seq (mh-get-profile-field "Previous-Sequence:")) | 1928 (if mh-previous-seq |
1773 (if mh-previous-seq | 1929 (setq mh-previous-seq (intern mh-previous-seq))) |
1774 (setq mh-previous-seq (intern mh-previous-seq))) | 1930 (run-hooks 'mh-find-path-hook) |
1775 (run-hooks 'mh-find-path-hook) | 1931 (mh-collect-folder-names))))) |
1776 (mh-collect-folder-names)))) | |
1777 | 1932 |
1778 (defun mh-file-command-p (file) | 1933 (defun mh-file-command-p (file) |
1779 "Return t if file FILE is the name of a executable regular file." | 1934 "Return t if file FILE is the name of a executable regular file." |
1780 (and (file-regular-p file) (file-executable-p file))) | 1935 (and (file-regular-p file) (file-executable-p file))) |
1781 | |
1782 (defun mh-find-progs () | |
1783 "Find the directories for the installed MH/nmh binaries and config files. | |
1784 Set the `mh-progs' and `mh-lib', and `mh-lib-progs' variables to the | |
1785 directory names and set `mh-nmh-flag' if we detect nmh instead of MH." | |
1786 (unless (and mh-progs mh-lib mh-lib-progs) | |
1787 (let ((path (or (mh-path-search exec-path "mhparam") | |
1788 (mh-path-search '("/usr/local/nmh/bin" ; nmh default | |
1789 "/usr/local/bin/mh/" | |
1790 "/usr/local/mh/" | |
1791 "/usr/bin/mh/" ;Ultrix 4.2, Linux | |
1792 "/usr/new/mh/" ;Ultrix <4.2 | |
1793 "/usr/contrib/mh/bin/" ;BSDI | |
1794 "/usr/pkg/bin/" ; NetBSD | |
1795 "/usr/local/bin/" | |
1796 ) | |
1797 "mhparam")))) | |
1798 (if (not path) | |
1799 (error "Unable to find the `mhparam' command")) | |
1800 (save-excursion | |
1801 (let ((tmp-buffer (get-buffer-create mh-temp-buffer))) | |
1802 (set-buffer tmp-buffer) | |
1803 (unwind-protect | |
1804 (progn | |
1805 (call-process (expand-file-name "mhparam" path) | |
1806 nil '(t nil) nil "libdir" "etcdir") | |
1807 (goto-char (point-min)) | |
1808 (if (search-forward-regexp "^libdir:\\s-\\(\\S-+\\)\\s-*$" | |
1809 nil t) | |
1810 (setq mh-lib-progs (match-string 1) | |
1811 mh-lib mh-lib-progs | |
1812 mh-progs path)) | |
1813 (goto-char (point-min)) | |
1814 (if (search-forward-regexp "^etcdir:\\s-\\(\\S-+\\)\\s-*$" | |
1815 nil t) | |
1816 (setq mh-lib (match-string 1) | |
1817 mh-nmh-flag t))) | |
1818 (kill-buffer tmp-buffer)))) | |
1819 (unless (and mh-progs mh-lib mh-lib-progs) | |
1820 (error "Unable to determine paths from `mhparam' command")) | |
1821 (setq mh-flists-present-flag | |
1822 (file-exists-p (expand-file-name "flists" mh-progs)))))) | |
1823 | |
1824 (defun mh-path-search (path file) | |
1825 "Search PATH, a list of directory names, for FILE. | |
1826 Returns the element of PATH that contains FILE, or nil if not found." | |
1827 (while (and path | |
1828 (not (funcall 'mh-file-command-p | |
1829 (expand-file-name file (car path))))) | |
1830 (setq path (cdr path))) | |
1831 (car path)) | |
1832 | 1936 |
1833 (defvar mh-no-install nil) ;do not run install-mh | 1937 (defvar mh-no-install nil) ;do not run install-mh |
1834 | 1938 |
1835 (defun mh-install (profile error-val) | 1939 (defun mh-install (profile error-val) |
1836 "Initialize the MH environment. | 1940 "Initialize the MH environment. |
1909 If DONT-ANNOTATE-FLAG is non-nil then the annotations in the folder buffer are | 2013 If DONT-ANNOTATE-FLAG is non-nil then the annotations in the folder buffer are |
1910 not updated." | 2014 not updated." |
1911 (let ((entry (mh-find-seq seq)) | 2015 (let ((entry (mh-find-seq seq)) |
1912 (internal-seq-flag (mh-internal-seq seq))) | 2016 (internal-seq-flag (mh-internal-seq seq))) |
1913 (if (and msgs (atom msgs)) (setq msgs (list msgs))) | 2017 (if (and msgs (atom msgs)) (setq msgs (list msgs))) |
2018 (if (null entry) | |
2019 (setq mh-seq-list | |
2020 (cons (mh-make-seq seq (mh-canonicalize-sequence msgs)) | |
2021 mh-seq-list)) | |
2022 (if msgs (setcdr entry (mh-canonicalize-sequence | |
2023 (append msgs (mh-seq-msgs entry)))))) | |
1914 (unless internal-flag | 2024 (unless internal-flag |
1915 (mh-add-to-sequence seq msgs) | 2025 (mh-add-to-sequence seq msgs) |
1916 (when (not dont-annotate-flag) | 2026 (when (not dont-annotate-flag) |
1917 (mh-iterate-on-range msg msgs | 2027 (mh-iterate-on-range msg msgs |
1918 (unless (memq msg (cdr entry)) | 2028 (unless (memq msg (cdr entry)) |
1919 (mh-add-sequence-notation msg internal-seq-flag))))) | 2029 (mh-add-sequence-notation msg internal-seq-flag))))))) |
1920 (if (null entry) | |
1921 (setq mh-seq-list | |
1922 (cons (mh-make-seq seq (mh-canonicalize-sequence msgs)) | |
1923 mh-seq-list)) | |
1924 (if msgs (setcdr entry (mh-canonicalize-sequence | |
1925 (append msgs (mh-seq-msgs entry)))))))) | |
1926 | 2030 |
1927 (defun mh-canonicalize-sequence (msgs) | 2031 (defun mh-canonicalize-sequence (msgs) |
1928 "Sort MSGS in decreasing order and remove duplicates." | 2032 "Sort MSGS in decreasing order and remove duplicates." |
1929 (let* ((sorted-msgs (sort (copy-sequence msgs) '>)) | 2033 (let* ((sorted-msgs (sort (copy-sequence msgs) '>)) |
1930 (head sorted-msgs)) | 2034 (head sorted-msgs)) |
2074 (with-temp-buffer | 2178 (with-temp-buffer |
2075 (apply #'call-process arg-list) | 2179 (apply #'call-process arg-list) |
2076 (goto-char (point-min)) | 2180 (goto-char (point-min)) |
2077 (while (not (and (eolp) (bolp))) | 2181 (while (not (and (eolp) (bolp))) |
2078 (goto-char (line-end-position)) | 2182 (goto-char (line-end-position)) |
2079 (let ((has-pos (search-backward " has " (line-beginning-position) t))) | 2183 (let ((start-pos (line-beginning-position)) |
2184 (has-pos (search-backward " has " (line-beginning-position) t))) | |
2080 (when (integerp has-pos) | 2185 (when (integerp has-pos) |
2081 (while (equal (char-after has-pos) ? ) | 2186 (while (equal (char-after has-pos) ? ) |
2082 (decf has-pos)) | 2187 (decf has-pos)) |
2083 (incf has-pos) | 2188 (incf has-pos) |
2084 (let* ((name (buffer-substring (line-beginning-position) has-pos)) | 2189 (while (equal (char-after start-pos) ? ) |
2190 (incf start-pos)) | |
2191 (let* ((name (buffer-substring start-pos has-pos)) | |
2085 (first-char (aref name 0)) | 2192 (first-char (aref name 0)) |
2086 (last-char (aref name (1- (length name))))) | 2193 (last-char (aref name (1- (length name))))) |
2087 (unless (member first-char '(?. ?# ?,)) | 2194 (unless (member first-char '(?. ?# ?,)) |
2088 (when (and (equal last-char ?+) (equal name current-folder)) | 2195 (when (and (equal last-char ?+) (equal name current-folder)) |
2089 (setq name (substring name 0 (1- (length name))))) | 2196 (setq name (substring name 0 (1- (length name))))) |
2187 (defun mh-folder-completing-read (prompt default allow-root-folder-flag) | 2294 (defun mh-folder-completing-read (prompt default allow-root-folder-flag) |
2188 "Read folder name with PROMPT and default result DEFAULT. | 2295 "Read folder name with PROMPT and default result DEFAULT. |
2189 If ALLOW-ROOT-FOLDER-FLAG is non-nil then \"+\" is allowed to be a folder name | 2296 If ALLOW-ROOT-FOLDER-FLAG is non-nil then \"+\" is allowed to be a folder name |
2190 corresponding to `mh-user-path'." | 2297 corresponding to `mh-user-path'." |
2191 (mh-normalize-folder-name | 2298 (mh-normalize-folder-name |
2192 (let ((minibuffer-local-completion-map mh-folder-completion-map) | 2299 (let ((minibuffer-completing-file-name t) |
2300 (completion-root-regexp "^[+/]") | |
2301 (minibuffer-local-completion-map mh-folder-completion-map) | |
2193 (mh-allow-root-folder-flag allow-root-folder-flag)) | 2302 (mh-allow-root-folder-flag allow-root-folder-flag)) |
2194 (completing-read prompt 'mh-folder-completion-function nil nil nil | 2303 (completing-read prompt 'mh-folder-completion-function nil nil nil |
2195 'mh-folder-hist default)) | 2304 'mh-folder-hist default)) |
2196 t)) | 2305 t)) |
2197 | 2306 |
2204 non-nil, use it in the prompt instead of DEFAULT. If ALLOW-ROOT-FOLDER-FLAG is | 2313 non-nil, use it in the prompt instead of DEFAULT. If ALLOW-ROOT-FOLDER-FLAG is |
2205 non-nil then the function will accept the folder +, which means all folders | 2314 non-nil then the function will accept the folder +, which means all folders |
2206 when used in searching." | 2315 when used in searching." |
2207 (if (null default) | 2316 (if (null default) |
2208 (setq default "")) | 2317 (setq default "")) |
2209 (let* ((default-string (cond (default-string (format " [%s]? " | 2318 (let* ((default-string (cond (default-string (format "[%s] " default-string)) |
2210 default-string)) | 2319 ((equal "" default) "") |
2211 ((equal "" default) "? ") | 2320 (t (format "[%s] " default)))) |
2212 (t (format " [%s]? " default)))) | 2321 (prompt (format "%s folder: %s" prompt default-string)) |
2213 (prompt (format "%s folder%s" prompt default-string)) | |
2214 (mh-current-folder-name mh-current-folder) | 2322 (mh-current-folder-name mh-current-folder) |
2215 read-name folder-name) | 2323 read-name folder-name) |
2216 (while (and (setq read-name (mh-folder-completing-read | 2324 (while (and (setq read-name (mh-folder-completing-read |
2217 prompt default allow-root-folder-flag)) | 2325 prompt default allow-root-folder-flag)) |
2218 (equal read-name "") | 2326 (equal read-name "") |
2450 new-list))) | 2558 new-list))) |
2451 (t (error "Bad element in mh-list-to-string: %s" (car l)))) | 2559 (t (error "Bad element in mh-list-to-string: %s" (car l)))) |
2452 (setq l (cdr l))) | 2560 (setq l (cdr l))) |
2453 new-list)) | 2561 new-list)) |
2454 | 2562 |
2563 (defun mh-replace-string (old new) | |
2564 "Replace all occurrences of OLD with NEW in the current buffer." | |
2565 (goto-char (point-min)) | |
2566 (let ((case-fold-search t)) | |
2567 (while (search-forward old nil t) | |
2568 (replace-match new t t)))) | |
2569 | |
2455 (defun mh-replace-in-string (regexp newtext string) | 2570 (defun mh-replace-in-string (regexp newtext string) |
2456 "Replace REGEXP with NEWTEXT everywhere in STRING and return result. | 2571 "Replace REGEXP with NEWTEXT everywhere in STRING and return result. |
2457 NEWTEXT is taken literally---no \\DIGIT escapes will be recognized. | 2572 NEWTEXT is taken literally---no \\DIGIT escapes will be recognized. |
2458 | 2573 |
2459 The function body was copied from `dired-replace-in-string' in dired.el. | 2574 The function body was copied from `dired-replace-in-string' in dired.el. |