Print test timings unconditionally
[emacs.git] / lisp / mh-e / mh-comp.el
blob941529330e1ccbbd20230149915af3cd782b1f82
1 ;;; mh-comp.el --- MH-E functions for composing and sending messages
3 ;; Copyright (C) 1993, 1995, 1997, 2000-2018 Free Software Foundation,
4 ;; 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 <https://www.gnu.org/licenses/>.
26 ;;; Commentary:
28 ;; This file includes the functions in the MH-Folder maps that get us
29 ;; into MH-Letter mode, as well the functions in the MH-Letter mode
30 ;; that are used to send the mail. Other that those, functions that
31 ;; are needed in mh-letter.el should be found there.
33 ;;; Change Log:
35 ;;; Code:
37 (require 'mh-e)
38 (require 'mh-gnus) ;needed because mh-gnus.el not compiled
39 (require 'mh-scan)
41 (require 'sendmail)
43 (autoload 'easy-menu-add "easymenu")
44 (autoload 'mml-insert-tag "mml")
48 ;;; Site Customization
50 (defvar mh-send-prog "send"
51 "Name of the MH send program.
52 Some sites need to change this because of a name conflict.")
54 (defvar mh-send-uses-spost-flag nil
55 "Non-nil means \"send\" uses \"spost\" to submit messages.
57 If the value of \"postproc:\" is \"spost\", you may need to set
58 this variable to t to tell MH-E to avoid using features of
59 \"post\" that are not supported by \"spost\". You'll know that
60 you'll need to do this if sending mail fails with an error of
61 \"spost: -msgid unknown\".")
63 (defvar mh-redist-background nil
64 "If non-nil redist will be done in background like send.
65 This allows transaction log to be visible if -watch, -verbose or
66 -snoop are used.")
70 ;;; Variables
72 (defvar mh-comp-formfile "components"
73 "Name of file to be used as a skeleton for composing messages.
75 Default is \"components\".
77 If not an absolute file name, the file is searched for first in the
78 user's MH directory, then in the system MH lib directory.")
80 (defvar mh-repl-formfile "replcomps"
81 "Name of file to be used as a skeleton for replying to messages.
83 Default is \"replcomps\".
85 If not an absolute file name, the file is searched for first in the
86 user's MH directory, then in the system MH lib directory.")
88 (defvar mh-repl-group-formfile "replgroupcomps"
89 "Name of file to be used as a skeleton for replying to messages.
91 Default is \"replgroupcomps\".
93 This file is used to form replies to the sender and all recipients of
94 a message. Only used if (mh-variant-p \\='nmh) is non-nil.
95 If not an absolute file name, the file is searched for first in the
96 user's MH directory, then in the system MH lib directory.")
98 (defvar mh-rejected-letter-start
99 (format "^%s$"
100 (regexp-opt
101 '("Content-Type: message/rfc822" ;MIME MDN
102 "------ This is a copy of the message, including all the headers. ------";from exim
103 "--- Below this line is a copy of the message."; from qmail
104 " ----- Unsent message follows -----" ;from sendmail V5
105 " --------Unsent Message below:" ; from sendmail at BU
106 " ----- Original message follows -----" ;from sendmail V8
107 "------- Unsent Draft" ;from MH itself
108 "---------- Original Message ----------" ;from zmailer
109 " --- The unsent message follows ---" ;from AIX mail system
110 " Your message follows:" ;from MMDF-II
111 "Content-Description: Returned Content" ;1993 KJ sendmail
112 ))))
114 (defvar mh-new-draft-cleaned-headers
115 "^Date:\\|^Received:\\|^Message-Id:\\|^From:\\|^Sender:\\|^Errors-To:\\|^Delivery-Date:\\|^Return-Path:"
116 "Regexp of header lines to remove before offering a message as a new draft\\<mh-folder-mode-map>.
117 Used by the \\[mh-edit-again] and \\[mh-extract-rejected-mail] commands.")
119 (defvar mh-letter-mode-syntax-table
120 (let ((syntax-table (make-syntax-table text-mode-syntax-table)))
121 (modify-syntax-entry ?% "." syntax-table)
122 syntax-table)
123 "Syntax table used by MH-E while in MH-Letter mode.")
125 (defvar mh-regexp-in-field-syntax-table nil
126 "Specify a syntax table for `mh-regexp-in-field-p' to use.")
128 (defvar mh-fcc-syntax-table
129 (let ((syntax-table (make-syntax-table text-mode-syntax-table)))
130 (modify-syntax-entry ?+ "w" syntax-table)
131 (modify-syntax-entry ?/ "w" syntax-table)
132 syntax-table)
133 "Syntax table used by MH-E while searching an Fcc field.")
135 (defvar mh-addr-syntax-table
136 (let ((syntax-table (make-syntax-table text-mode-syntax-table)))
137 (modify-syntax-entry ?! "w" syntax-table)
138 (modify-syntax-entry ?# "w" syntax-table)
139 (modify-syntax-entry ?$ "w" syntax-table)
140 (modify-syntax-entry ?% "w" syntax-table)
141 (modify-syntax-entry ?& "w" syntax-table)
142 (modify-syntax-entry ?' "w" syntax-table)
143 (modify-syntax-entry ?* "w" syntax-table)
144 (modify-syntax-entry ?+ "w" syntax-table)
145 (modify-syntax-entry ?- "w" syntax-table)
146 (modify-syntax-entry ?/ "w" syntax-table)
147 (modify-syntax-entry ?= "w" syntax-table)
148 (modify-syntax-entry ?? "w" syntax-table)
149 (modify-syntax-entry ?^ "w" syntax-table)
150 (modify-syntax-entry ?_ "w" syntax-table)
151 (modify-syntax-entry ?` "w" syntax-table)
152 (modify-syntax-entry ?{ "w" syntax-table)
153 (modify-syntax-entry ?| "w" syntax-table)
154 (modify-syntax-entry ?} "w" syntax-table)
155 (modify-syntax-entry ?~ "w" syntax-table)
156 (modify-syntax-entry ?. "w" syntax-table)
157 (modify-syntax-entry ?@ "w" syntax-table)
158 syntax-table)
159 "Syntax table used by MH-E while searching an address field.")
161 (defvar mh-send-args ""
162 "Extra args to pass to \"send\" command.")
164 (defvar mh-annotate-char nil
165 "Character to use to annotate `mh-sent-from-msg'.")
167 (defvar mh-annotate-field nil
168 "Field name for message annotation.")
170 (defvar mh-annotate-list nil
171 "Messages annotated, either a sequence name or a list of message numbers.
172 This variable can be used by `mh-annotate-msg-hook'.")
174 (defvar mh-insert-auto-fields-done-local nil
175 "Buffer-local variable set when `mh-insert-auto-fields' called successfully.")
176 (make-variable-buffer-local 'mh-insert-auto-fields-done-local)
180 ;;; MH-E Entry Points
182 ;;;###autoload
183 (defun mh-smail ()
184 "Compose a message with the MH mail system.
185 See `mh-send' for more details on composing mail."
186 (interactive)
187 (mh-find-path)
188 (call-interactively 'mh-send))
190 ;;;###autoload
191 (defun mh-smail-other-window ()
192 "Compose a message with the MH mail system in other window.
193 See `mh-send' for more details on composing mail."
194 (interactive)
195 (mh-find-path)
196 (call-interactively 'mh-send-other-window))
198 (defun mh-send-other-window (to cc subject)
199 "Compose a message in another window.
201 See `mh-send' for more information and a description of how the
202 TO, CC, and SUBJECT arguments are used."
203 (interactive (list
204 (mh-interactive-read-address "To: ")
205 (mh-interactive-read-address "Cc: ")
206 (mh-interactive-read-string "Subject: ")))
207 (let ((pop-up-windows t))
208 (mh-send-sub to cc subject (current-window-configuration))))
210 (defvar mh-error-if-no-draft nil) ;raise error over using old draft
212 ;;;###autoload
213 (defun mh-smail-batch (&optional to subject other-headers &rest ignored)
214 "Compose a message with the MH mail system.
216 This function does not prompt the user for any header fields, and
217 thus is suitable for use by programs that want to create a mail
218 buffer. Users should use \\[mh-smail] to compose mail.
220 Optional arguments for setting certain fields include TO,
221 SUBJECT, and OTHER-HEADERS. Additional arguments are IGNORED.
223 This function remains for Emacs 21 compatibility. New
224 applications should use `mh-user-agent-compose'."
225 (mh-find-path)
226 (let ((mh-error-if-no-draft t))
227 (mh-send (or to "") "" (or subject ""))))
229 ;;;###autoload
230 (define-mail-user-agent 'mh-e-user-agent
231 'mh-user-agent-compose 'mh-send-letter 'mh-fully-kill-draft
232 'mh-before-send-letter-hook)
234 ;;;###autoload
235 (defun mh-user-agent-compose (&optional to subject other-headers continue
236 switch-function yank-action
237 send-actions return-action
238 &rest ignored)
239 "Set up mail composition draft with the MH mail system.
240 This is the `mail-user-agent' entry point to MH-E. This function
241 conforms to the contract specified by `define-mail-user-agent'
242 which means that this function should accept the same arguments
243 as `compose-mail'.
245 The optional arguments TO and SUBJECT specify recipients and the
246 initial Subject field, respectively.
248 OTHER-HEADERS is an alist specifying additional header fields.
249 Elements look like (HEADER . VALUE) where both HEADER and VALUE
250 are strings.
252 CONTINUE, SWITCH-FUNCTION, YANK-ACTION, SEND-ACTIONS, and
253 RETURN-ACTION and any additional arguments are IGNORED."
254 (mh-find-path)
255 (let ((mh-error-if-no-draft t))
256 (mh-send to "" subject)
257 (while other-headers
258 (mh-insert-fields (concat (car (car other-headers)) ":")
259 (cdr (car other-headers)))
260 (setq other-headers (cdr other-headers)))))
262 ;; Shush compiler.
263 (mh-do-in-xemacs
264 (defvar sendmail-coding-system))
266 ;;;###autoload
267 (defun mh-send-letter (&optional arg)
268 "Save draft and send message.
270 When you are all through editing a message, you send it with this
271 command. You can give a prefix argument ARG to monitor the first stage
272 of the delivery; this output can be found in a buffer called \"*MH-E
273 Mail Delivery*\".
275 The hook `mh-before-send-letter-hook' is run at the beginning of
276 this command. For example, if you want to check your spelling in
277 your message before sending, add the function `ispell-message'.
279 Unless `mh-insert-auto-fields' had previously been called
280 manually, the function `mh-insert-auto-fields' is called to
281 insert fields based upon the recipients. If fields are added, you
282 are given a chance to see and to confirm these fields before the
283 message is actually sent. You can do away with this confirmation
284 by turning off the option `mh-auto-fields-prompt-flag'.
286 In case the MH \"send\" program is installed under a different name,
287 use `mh-send-prog' to tell MH-E the name.
289 The hook `mh-annotate-msg-hook' is run after annotating the
290 message and scan line."
291 (interactive "P")
292 (run-hooks 'mh-before-send-letter-hook)
293 (if (and (mh-insert-auto-fields t)
294 mh-auto-fields-prompt-flag
295 (goto-char (point-min)))
296 (if (not (y-or-n-p "Auto fields inserted, send? "))
297 (error "Send aborted")))
298 (cond ((mh-mh-directive-present-p)
299 (mh-mh-to-mime))
300 ((or (mh-mml-tag-present-p) (not (mh-ascii-buffer-p)))
301 (mh-mml-to-mime)))
302 (save-buffer)
303 (message "Sending...")
304 (let ((draft-buffer (current-buffer))
305 (file-name buffer-file-name)
306 (config mh-previous-window-config)
307 (coding-system-for-write
308 (if (fboundp 'select-message-coding-system)
309 (select-message-coding-system) ; Emacs has this since at least 21.1
310 (if (and (local-variable-p 'buffer-file-coding-system
311 (current-buffer)) ;XEmacs needs two args
312 ;; We're not sure why, but buffer-file-coding-system
313 ;; tends to get set to undecided-unix.
314 (not (memq buffer-file-coding-system
315 '(undecided undecided-unix undecided-dos))))
316 buffer-file-coding-system
317 (or (and (boundp 'sendmail-coding-system) sendmail-coding-system)
318 (and (default-boundp 'buffer-file-coding-system)
319 (default-value 'buffer-file-coding-system))
320 'iso-latin-1)))))
321 ;; Older versions of spost do not support -msgid and -mime.
322 (unless mh-send-uses-spost-flag
323 ;; Adding a Message-ID field looks good, makes it easier to search for
324 ;; message in your +outbox, and best of all doesn't break threading for
325 ;; the recipient if you reply to a message in your +outbox.
326 (setq mh-send-args (concat "-msgid " mh-send-args))
327 ;; The default BCC encapsulation will make a MIME message unreadable.
328 ;; With nmh use the -mime arg to prevent this.
329 (if (and (mh-variant-p 'nmh)
330 (mh-goto-header-field "Bcc:")
331 (mh-goto-header-field "Content-Type:"))
332 (setq mh-send-args (concat "-mime " mh-send-args))))
333 (cond (arg
334 (pop-to-buffer mh-mail-delivery-buffer)
335 (erase-buffer)
336 (mh-exec-cmd-output mh-send-prog t
337 "-nodraftfolder" "-watch" "-nopush"
338 (split-string mh-send-args) file-name)
339 (goto-char (point-max)) ; show the interesting part
340 (recenter -1)
341 (set-buffer draft-buffer)) ; for annotation below
343 (mh-exec-cmd-daemon mh-send-prog nil
344 "-nodraftfolder" "-noverbose"
345 (split-string mh-send-args) file-name)))
346 (if mh-annotate-char
347 (mh-annotate-msg mh-sent-from-msg
348 mh-sent-from-folder
349 mh-annotate-char
350 "-component" mh-annotate-field
351 "-text" (format "\"%s %s\""
352 (mh-get-header-field "To:")
353 (mh-get-header-field "Cc:"))))
355 (cond ((or (not arg)
356 (y-or-n-p "Kill draft buffer? "))
357 (kill-buffer draft-buffer)
358 (if config
359 (set-window-configuration config))))
360 (if arg
361 (message "Sending...done")
362 (message "Sending...backgrounded"))))
364 ;;;###autoload
365 (defun mh-fully-kill-draft ()
366 "Quit editing and delete draft message.
368 If for some reason you are not happy with the draft, you can use
369 this command to kill the draft buffer and delete the draft
370 message. Use the command \\[kill-buffer] if you don't want to
371 delete the draft message."
372 (interactive)
373 (if (y-or-n-p "Kill draft message? ")
374 (let ((config mh-previous-window-config))
375 (if (file-exists-p buffer-file-name)
376 (delete-file buffer-file-name))
377 (set-buffer-modified-p nil)
378 (kill-buffer (buffer-name))
379 (message "")
380 (if config
381 (set-window-configuration config)))
382 (error "Message not killed")))
386 ;;; MH-Folder Commands
388 ;; Alphabetical.
390 ;;;###mh-autoload
391 (defun mh-edit-again (message)
392 "Edit a MESSAGE to send it again.
394 If you don't complete a draft for one reason or another, and if
395 the draft buffer is no longer available, you can pick your draft
396 up again with this command. If you don't use a draft folder, your
397 last \"draft\" file will be used. If you use draft folders,
398 you'll need to visit the draft folder with \"\\[mh-visit-folder]
399 drafts <RET>\", use \\[mh-next-undeleted-msg] to move to the
400 appropriate message, and then use \\[mh-edit-again] to prepare
401 the message for editing.
403 This command can also be used to take messages that were sent to
404 you and to send them to more people.
406 Don't use this command to re-edit a message from a Mailer-Daemon
407 who complained that your mail wasn't posted for some reason or
408 another (see `mh-extract-rejected-mail').
410 The default message is the current message.
412 See also `mh-send'."
413 (interactive (list (mh-get-msg-num t)))
414 (let* ((from-folder mh-current-folder)
415 (config (current-window-configuration))
416 (components-file (mh-bare-components))
417 (draft
418 (cond ((and mh-draft-folder (equal from-folder mh-draft-folder))
419 (pop-to-buffer (find-file-noselect (mh-msg-filename message))
421 (rename-buffer (format "draft-%d" message))
422 ;; Make buffer writable...
423 (setq buffer-read-only nil)
424 ;; If buffer was being used to display the message reinsert
425 ;; from file...
426 (when (eq major-mode 'mh-show-mode)
427 (erase-buffer)
428 (insert-file-contents buffer-file-name))
429 (buffer-name))
431 (mh-read-draft "clean-up" (mh-msg-filename message) nil)))))
432 (mh-clean-msg-header (point-min) mh-new-draft-cleaned-headers nil)
433 (mh-insert-header-separator)
434 ;; Merge in components
435 (mh-mapc
436 (function
437 (lambda (header-field)
438 (let ((field (car header-field))
439 (value (cdr header-field))
440 (case-fold-search t))
441 (cond
442 ;; Address field
443 ((string-match field "^To$\\|^Cc$\\|^From$")
444 (cond
445 ((not (mh-goto-header-field (concat field ":")))
446 ;; Header field does not exist, add it
447 (mh-goto-header-end 0)
448 (insert field ": " value "\n"))
449 ((string-equal value "")
450 ;; Header field already exists and no value
453 ;; Header field exists and we have a value
454 (let (address mailbox (alias (mh-alias-expand value)))
455 (and alias
456 (setq address (ietf-drums-parse-address alias))
457 (setq mailbox (car address)))
458 ;; XXX - Need to parse all addresses out of field
459 (if (and
460 (not (mh-regexp-in-field-p
461 (concat "\\b" (regexp-quote value) "\\b") field))
462 mailbox
463 (not (mh-regexp-in-field-p
464 (concat "\\b" (regexp-quote mailbox) "\\b") field)))
465 (insert " " value ","))
466 ))))
467 ((string-match field "^Fcc$")
468 ;; Folder reference
469 (mh-modify-header-field field value))
470 ;; Text field, that's an easy case
472 (mh-modify-header-field field value))))))
473 (mh-components-to-list components-file))
474 (delete-file components-file)
475 (goto-char (point-min))
476 (save-buffer)
477 (mh-compose-and-send-mail
478 draft "" from-folder nil nil nil nil nil nil config)
479 (mh-letter-mode-message)
480 (mh-letter-adjust-point)))
482 (defun mh-extract-header-field ()
483 "Extract field name and field value from the field at point.
484 Returns a list of field name and value (which may be null)."
485 (let ((end (save-excursion (mh-header-field-end)
486 (point))))
487 (if (looking-at mh-letter-header-field-regexp)
488 (save-excursion
489 (goto-char (match-end 1))
490 (forward-char 1)
491 (skip-chars-forward " \t")
492 (cons (match-string-no-properties 1) (buffer-substring-no-properties (point) end))))))
495 (defun mh-components-to-list (components)
496 "Convert the COMPONENTS file to a list of field names and values."
497 (with-current-buffer (get-buffer-create mh-temp-buffer)
498 (erase-buffer)
499 (insert-file-contents components)
500 (goto-char (point-min))
501 (let
502 ((header-fields nil))
503 (while (mh-in-header-p)
504 (setq header-fields (append header-fields (list (mh-extract-header-field))))
505 (mh-header-field-end)
506 (forward-char 1)
508 header-fields)))
510 ;;;###mh-autoload
511 (defun mh-extract-rejected-mail (message)
512 "Edit a MESSAGE that was returned by the mail system.
514 This command prepares the message for editing by removing the
515 Mailer-Daemon envelope and unneeded header fields. Fix whatever
516 addressing problem you had, and send the message again with
517 \\[mh-send-letter].
519 The default message is the current message.
521 See also `mh-send'."
522 (interactive (list (mh-get-msg-num t)))
523 (let ((from-folder mh-current-folder)
524 (config (current-window-configuration))
525 (draft (mh-read-draft "extraction" (mh-msg-filename message) nil)))
526 (goto-char (point-min))
527 (cond ((re-search-forward mh-rejected-letter-start nil t)
528 (skip-chars-forward " \t\n")
529 (delete-region (point-min) (point))
530 (mh-clean-msg-header (point-min) mh-new-draft-cleaned-headers nil))
532 (message "Does not appear to be a rejected letter")))
533 (mh-insert-header-separator)
534 (goto-char (point-min))
535 (save-buffer)
536 (mh-compose-and-send-mail draft "" from-folder message
537 (mh-get-header-field "To:")
538 (mh-get-header-field "From:")
539 (mh-get-header-field "Cc:")
540 nil nil config)
541 (mh-letter-mode-message)))
543 ;;;###mh-autoload
544 (defun mh-forward (to cc &optional range)
545 "Forward message.
547 You are prompted for the TO and CC recipients. You are given a
548 draft to edit that looks like it would if you had run the MH
549 command \"forw\". You can then add some text.
551 You can forward several messages by using a RANGE. All of the
552 messages in the range are inserted into your draft. Check the
553 documentation of `mh-interactive-range' to see how RANGE is read
554 in interactive use.
556 The hook `mh-forward-hook' is called on the draft.
558 See also `mh-compose-forward-as-mime-flag',
559 `mh-forward-subject-format', and `mh-send'."
560 (interactive (list (mh-interactive-read-address "To: ")
561 (mh-interactive-read-address "Cc: ")
562 (mh-interactive-range "Forward")))
563 (let* ((folder mh-current-folder)
564 (msgs (mh-range-to-msg-list range))
565 (config (current-window-configuration))
566 (fwd-msg-file (mh-msg-filename (car msgs) folder))
567 ;; forw always leaves file in "draft" since it doesn't have -draft
568 (draft-name (expand-file-name "draft" mh-user-path))
569 (draft (cond ((or (not (file-exists-p draft-name))
570 (y-or-n-p "The file draft exists; discard it? "))
571 (mh-exec-cmd "forw" "-build"
572 (if (and (mh-variant-p 'nmh)
573 mh-compose-forward-as-mime-flag)
574 "-mime")
575 mh-current-folder
576 (mh-coalesce-msg-list msgs))
577 (prog1
578 (mh-read-draft "" draft-name t)
579 (mh-insert-fields "To:" to "Cc:" cc)
580 (save-buffer)))
582 (mh-read-draft "" draft-name nil)))))
583 (let (orig-from
584 orig-subject)
585 (with-current-buffer (get-buffer-create mh-temp-buffer)
586 (erase-buffer)
587 (insert-file-contents fwd-msg-file)
588 (setq orig-from (mh-get-header-field "From:"))
589 (setq orig-subject (mh-get-header-field "Subject:")))
590 (let ((forw-subject
591 (mh-forwarded-letter-subject orig-from orig-subject)))
592 (mh-insert-fields "Subject:" forw-subject)
593 (goto-char (point-min))
594 ;; Set the local value of mh-mail-header-separator according to what is
595 ;; present in the buffer...
596 (set (make-local-variable 'mh-mail-header-separator)
597 (save-excursion
598 (goto-char (mh-mail-header-end))
599 (buffer-substring-no-properties (point) (mh-line-end-position))))
600 (set (make-local-variable 'mail-header-separator) mh-mail-header-separator) ;override sendmail.el
601 ;; If using MML, translate MH-style directive
602 (if (equal mh-compose-insertion 'mml)
603 (save-excursion
604 (goto-char (mh-mail-header-end))
605 (while
606 (re-search-forward
607 "^#forw \\[\\([^]]+\\)\\] \\(+\\S-+\\) \\(.*\\)$"
608 (point-max) t)
609 (let ((description (if (equal (match-string 1)
610 "forwarded messages")
611 "forwarded message %d"
612 (match-string 1)))
613 (msgs (split-string (match-string 3)))
614 (i 0))
615 (beginning-of-line)
616 (delete-region (point) (progn (forward-line 1) (point)))
617 (dolist (msg msgs)
618 (setq i (1+ i))
619 (mh-mml-forward-message (format description i)
620 folder msg)
621 ;; Was inserted before us, move to end of file to preserve order
622 (goto-char (point-max)))))))
623 ;; Position just before forwarded message.
624 (if (re-search-forward "^------- Forwarded Message" nil t)
625 (forward-line -1)
626 (goto-char (mh-mail-header-end))
627 (forward-line 1))
628 (delete-other-windows)
629 (mh-add-msgs-to-seq msgs 'forwarded t)
630 (mh-compose-and-send-mail draft "" folder msgs
631 to forw-subject cc
632 mh-note-forw "Forwarded:"
633 config)
634 (mh-letter-mode-message)
635 (mh-letter-adjust-point)
636 (run-hooks 'mh-forward-hook)))))
638 (defun mh-forwarded-letter-subject (from subject)
639 "Return a Subject suitable for a forwarded message.
640 Original message has headers FROM and SUBJECT."
641 (let ((addr-start (string-match "<" from))
642 (comment (string-match "(" from)))
643 (cond ((and addr-start (> addr-start 0))
644 ;; Full Name <luser@host>
645 (setq from (substring from 0 (1- addr-start))))
646 (comment
647 ;; luser@host (Full Name)
648 (setq from (substring from (1+ comment) (1- (length from)))))))
649 (format mh-forward-subject-format from subject))
651 ;;;###mh-autoload
652 (defun mh-redistribute (to cc &optional message)
653 "Redistribute a message.
655 This command is similar in function to forwarding mail, but it
656 does not allow you to edit the message, nor does it add your name
657 to the \"From\" header field. It appears to the recipient as if
658 the message had come from the original sender. When you run this
659 command, you are prompted for the TO and CC recipients. The
660 default MESSAGE is the current message.
662 Also investigate the command \\[mh-edit-again] for another way to
663 redistribute messages.
665 See also `mh-redist-full-contents-flag'.
667 The hook `mh-annotate-msg-hook' is run after annotating the
668 message and scan line."
669 (interactive (list (mh-read-address "Redist-To: ")
670 (mh-read-address "Redist-Cc: ")
671 (mh-get-msg-num t)))
672 (or message
673 (setq message (mh-get-msg-num t)))
674 (save-window-excursion
675 (let ((folder mh-current-folder)
676 (draft (mh-read-draft "redistribution"
677 (if mh-redist-full-contents-flag
678 (mh-msg-filename message)
679 nil)
680 nil)))
681 (mh-goto-header-end 0)
682 (insert "Resent-To: " to "\n")
683 (if (not (equal cc "")) (insert "Resent-cc: " cc "\n"))
684 (mh-clean-msg-header
685 (point-min)
686 "^Message-Id:\\|^Received:\\|^Return-Path:\\|^Sender:\\|^Date:\\|^From:"
687 nil)
688 (save-buffer)
689 (message "Redistributing...")
690 (let ((env "mhdist=1"))
691 ;; Setup environment...
692 (setq env (concat env " mhaltmsg="
693 (if mh-redist-full-contents-flag
694 buffer-file-name
695 (mh-msg-filename message folder))))
696 (unless mh-redist-full-contents-flag
697 (setq env (concat env " mhannotate=1")))
698 ;; Redistribute...
699 (if mh-redist-background
700 (mh-exec-cmd-env-daemon env mh-send-prog nil buffer-file-name)
701 (mh-exec-cmd-error env mh-send-prog "-push" buffer-file-name))
702 ;; Annotate...
703 (mh-annotate-msg message folder mh-note-dist
704 "-component" "Resent:"
705 "-text" (format "\"%s %s\"" to cc)))
706 (kill-buffer draft)
707 (message "Redistributing...done"))))
709 ;;;###mh-autoload
710 (defun mh-reply (message &optional reply-to includep)
711 "Reply to a MESSAGE.
713 When you reply to a message, you are first prompted with \"Reply
714 to whom?\" (unless the optional argument REPLY-TO is provided).
715 You have several choices here.
717 Response Reply Goes To
719 from The person who sent the message. This is the
720 default, so <RET> is sufficient.
722 to Replies to the sender, plus all recipients in the
723 \"To:\" header field.
725 all cc Forms a reply to the addresses in the
726 \"Mail-Followup-To:\" header field if one
727 exists; otherwise forms a reply to the sender,
728 plus all recipients.
730 Depending on your answer, \"repl\" is given a different argument
731 to form your reply. Specifically, a choice of \"from\" or none at
732 all runs \"repl -nocc all\", and a choice of \"to\" runs \"repl
733 -cc to\". Finally, either \"cc\" or \"all\" runs \"repl -cc all
734 -nocc me\".
736 Two windows are then created. One window contains the message to
737 which you are replying in an MH-Show buffer. Your draft, in
738 MH-Letter mode (*note `mh-letter-mode'), is in the other window.
739 If the reply draft was not one that you expected, check the
740 things that affect the behavior of \"repl\" which include the
741 \"repl:\" profile component and the \"replcomps\" and
742 \"replgroupcomps\" files.
744 If you supply a prefix argument INCLUDEP, the message you are
745 replying to is inserted in your reply after having first been run
746 through \"mhl\" with the format file \"mhl.reply\".
748 Alternatively, you can customize the option `mh-yank-behavior'
749 and choose one of its \"Automatically\" variants to do the same
750 thing. If you do so, the prefix argument has no effect.
752 Another way to include the message automatically in your draft is
753 to use \"repl: -filter repl.filter\" in your MH profile.
755 If you wish to customize the header or other parts of the reply
756 draft, please see \"repl\" and \"mh-format\".
758 See also `mh-reply-show-message-flag',
759 `mh-reply-default-reply-to', and `mh-send'."
760 (interactive (list
761 (mh-get-msg-num t)
762 (let ((minibuffer-help-form
763 "from => Sender only\nto => Sender and primary recipients\ncc or all => Sender and all recipients"))
764 (or mh-reply-default-reply-to
765 (completing-read "Reply to whom (default from): "
766 '(("from") ("to") ("cc") ("all"))
768 t)))
769 current-prefix-arg))
770 (let* ((folder mh-current-folder)
771 (show-buffer mh-show-buffer)
772 (config (current-window-configuration))
773 (group-reply (or (equal reply-to "cc") (equal reply-to "all")))
774 (form-file (cond ((and (mh-variant-p 'nmh 'gnu-mh) group-reply
775 (stringp mh-repl-group-formfile))
776 mh-repl-group-formfile)
777 ((stringp mh-repl-formfile) mh-repl-formfile)
778 (t nil))))
779 (message "Composing a reply...")
780 (mh-exec-cmd "repl" "-build" "-noquery" "-nodraftfolder"
781 (if form-file
782 (list "-form" form-file))
783 mh-current-folder message
784 (cond ((or (equal reply-to "from") (equal reply-to ""))
785 '("-nocc" "all"))
786 ((equal reply-to "to")
787 '("-cc" "to"))
788 (group-reply (if (mh-variant-p 'nmh 'gnu-mh)
789 '("-group" "-nocc" "me")
790 '("-cc" "all" "-nocc" "me"))))
791 (cond ((or (eq mh-yank-behavior 'autosupercite)
792 (eq mh-yank-behavior 'autoattrib))
793 '("-noformat"))
794 (includep '("-filter" "mhl.reply"))
795 (t '())))
796 (let ((draft (mh-read-draft "reply"
797 (expand-file-name "reply" mh-user-path)
798 t)))
799 (delete-other-windows)
800 (save-buffer)
802 (let ((to (mh-get-header-field "To:"))
803 (subject (mh-get-header-field "Subject:"))
804 (cc (mh-get-header-field "Cc:")))
805 (goto-char (point-min))
806 (mh-goto-header-end 1)
807 (or includep
808 (not mh-reply-show-message-flag)
809 (mh-in-show-buffer (show-buffer)
810 (mh-display-msg message folder)))
811 (mh-add-msgs-to-seq message 'answered t)
812 (message "Composing a reply...done")
813 (mh-compose-and-send-mail draft "" folder message to subject cc
814 mh-note-repl "Replied:" config))
815 (when (and (or (eq 'autosupercite mh-yank-behavior)
816 (eq 'autoattrib mh-yank-behavior))
817 (eq (mh-show-buffer-message-number) mh-sent-from-msg))
818 (undo-boundary)
819 (mh-yank-cur-msg))
820 (mh-letter-mode-message))))
822 ;;;###mh-autoload
823 (defun mh-send (to cc subject)
824 "Compose a message.
826 Your letter appears in an Emacs buffer whose mode is
827 MH-Letter (see `mh-letter-mode').
829 The arguments TO, CC, and SUBJECT can be used to prefill the
830 draft fields or suppress the prompts if `mh-compose-prompt-flag'
831 is on. They are also passed to the function set in the option
832 `mh-compose-letter-function'.
834 See also `mh-insert-x-mailer-flag' and `mh-letter-mode-hook'.
836 Outside of an MH-Folder buffer (`mh-folder-mode'), you must call
837 either \\[mh-smail] or \\[mh-smail-other-window] to compose a new
838 message."
839 (interactive (list
840 (mh-interactive-read-address "To: ")
841 (mh-interactive-read-address "Cc: ")
842 (mh-interactive-read-string "Subject: ")))
843 (let ((config (current-window-configuration)))
844 (delete-other-windows)
845 (mh-send-sub to cc subject config)))
849 ;;; Support Routines
851 (defun mh-interactive-read-address (prompt)
852 "Read an address.
853 If `mh-compose-prompt-flag' is non-nil, then read an address with
854 PROMPT.
855 Otherwise return the empty string."
856 (if mh-compose-prompt-flag (mh-read-address prompt) ""))
858 (defun mh-interactive-read-string (prompt)
859 "Read a string.
860 If `mh-compose-prompt-flag' is non-nil, then read a string with
861 PROMPT.
862 Otherwise return the empty string."
863 (if mh-compose-prompt-flag (read-string prompt) ""))
865 ;;;###mh-autoload
866 (defun mh-show-buffer-message-number (&optional buffer)
867 "Message number of displayed message in corresponding show buffer.
869 Return nil if show buffer not displayed.
870 If in `mh-letter-mode', don't display the message number being replied
871 to, but rather the message number of the show buffer associated with
872 our originating folder buffer.
873 Optional argument BUFFER can be used to specify the buffer."
874 (save-excursion
875 (if buffer
876 (set-buffer buffer))
877 (cond ((eq major-mode 'mh-show-mode)
878 (let ((number-start (mh-search-from-end ?/ buffer-file-name)))
879 (string-to-number (substring buffer-file-name
880 (1+ number-start)))))
881 ((and (eq major-mode 'mh-folder-mode)
882 mh-show-buffer
883 (get-buffer mh-show-buffer))
884 (mh-show-buffer-message-number mh-show-buffer))
885 ((and (eq major-mode 'mh-letter-mode)
886 mh-sent-from-folder
887 (get-buffer mh-sent-from-folder))
888 (mh-show-buffer-message-number mh-sent-from-folder))
890 nil))))
892 (defun mh-send-sub (to cc subject config)
893 "Do the real work of composing and sending a letter.
894 Expects the TO, CC, and SUBJECT fields as arguments.
895 CONFIG is the window configuration before sending mail."
896 (let ((folder mh-current-folder)
897 (msg-num (mh-get-msg-num nil)))
898 (message "Composing a message...")
899 (let ((draft (mh-read-draft
900 "message"
901 (mh-bare-components)
902 t)))
903 (mh-insert-fields "To:" to "Subject:" subject "Cc:" cc)
904 (goto-char (point-max))
905 (mh-compose-and-send-mail draft "" folder msg-num
906 to subject cc
907 nil nil config)
908 (mh-letter-mode-message)
909 (mh-letter-adjust-point))))
911 (defun mh-bare-components ()
912 "Generate a temporary, clean components file and return its path."
913 ;; Let comp(1) create the skeleton for us. This is particularly
914 ;; important with nmh-1.5, because its default "components" needs
915 ;; some processing before it can be used. Unfortunately, comp(1)
916 ;; doesn't have a -build option. So, to avoid the possibility of
917 ;; clobbering an existing draft, create a temporary directory and
918 ;; use it as the drafts folder. Then copy the skeleton to a regular
919 ;; temp file, and return the regular temp file.
920 (let (new
921 (temp-folder (make-temp-file
922 (concat mh-user-path "draftfolder.") t)))
923 (mh-exec-cmd "comp" "-nowhatnowproc"
924 "-draftfolder" (format "+%s"
925 (file-name-nondirectory temp-folder))
926 (if (stringp mh-comp-formfile)
927 (list "-form" mh-comp-formfile)))
928 (setq new (make-temp-file "comp."))
929 (rename-file (concat temp-folder "/" "1") new t)
930 (delete-file (concat temp-folder "/" ".mh_sequences"))
931 (delete-directory temp-folder)
932 new))
934 (defun mh-read-draft (use initial-contents delete-contents-file)
935 "Read draft file into a draft buffer and make that buffer the current one.
937 USE is a message used for prompting about the intended use of the
938 message.
939 INITIAL-CONTENTS is filename that is read into an empty buffer, or nil
940 if buffer should not be modified. Delete the initial-contents file if
941 DELETE-CONTENTS-FILE flag is set.
942 Returns the draft folder's name.
943 If the draft folder facility is enabled in ~/.mh_profile, a new buffer
944 is used each time and saved in the draft folder. The draft file can
945 then be reused."
946 (cond (mh-draft-folder
947 (let ((orig-default-dir default-directory)
948 (draft-file-name (mh-new-draft-name)))
949 (pop-to-buffer (generate-new-buffer
950 (format "draft-%s"
951 (file-name-nondirectory draft-file-name))))
952 (condition-case ()
953 (insert-file-contents draft-file-name t)
954 (file-error))
955 (setq default-directory orig-default-dir)))
957 (let ((draft-name (expand-file-name "draft" mh-user-path)))
958 (pop-to-buffer "draft") ; Create if necessary
959 (if (buffer-modified-p)
960 (if (y-or-n-p "Draft has been modified; kill anyway? ")
961 (set-buffer-modified-p nil)
962 (error "Draft preserved")))
963 (setq buffer-file-name draft-name)
964 (clear-visited-file-modtime)
965 (unlock-buffer)
966 (cond ((and (file-exists-p draft-name)
967 (not (equal draft-name initial-contents)))
968 (insert-file-contents draft-name)
969 (delete-file draft-name))))))
970 (cond ((and initial-contents
971 (or (zerop (buffer-size))
972 (if (y-or-n-p
973 (format "A draft exists. Use for %s? " use))
974 (if mh-error-if-no-draft
975 (error "A prior draft exists"))
976 t)))
977 (erase-buffer)
978 (insert-file-contents initial-contents)
979 (if delete-contents-file (delete-file initial-contents))))
980 (auto-save-mode 1)
981 (if mh-draft-folder
982 (save-buffer)) ; Do not reuse draft name
983 (buffer-name))
985 (defun mh-new-draft-name ()
986 "Return the pathname of folder for draft messages."
987 (save-excursion
988 (mh-exec-cmd-quiet t "mhpath" mh-draft-folder "new")
989 (buffer-substring (point-min) (1- (point-max)))))
991 (defun mh-insert-fields (&rest name-values)
992 "Insert the NAME-VALUES pairs in the current buffer.
993 If the field exists, append the value to it.
994 Do not insert any pairs whose value is the empty string."
995 (let ((case-fold-search t))
996 (while name-values
997 (let ((field-name (car name-values))
998 (value (car (cdr name-values))))
999 (if (not (string-match "^.*:$" field-name))
1000 (setq field-name (concat field-name ":")))
1001 (cond ((or (null value)
1002 (equal value ""))
1003 nil)
1004 ((mh-position-on-field field-name)
1005 (insert " " (or value "")))
1007 (insert field-name " " value "\n")))
1008 (setq name-values (cdr (cdr name-values)))))))
1010 (defun mh-compose-and-send-mail (draft send-args
1011 sent-from-folder sent-from-msg
1012 to subject cc
1013 annotate-char annotate-field
1014 config)
1015 "Edit and compose a draft message in buffer DRAFT and send or save it.
1016 SEND-ARGS is the argument passed to the send command.
1017 SENT-FROM-FOLDER is buffer containing scan listing of current folder,
1018 or nil if none exists.
1019 SENT-FROM-MSG is the message number or sequence name or nil.
1020 The TO, SUBJECT, and CC fields are passed to the
1021 `mh-compose-letter-function'.
1022 If ANNOTATE-CHAR is non-null, it is used to notate the scan listing of
1023 the message. In that case, the ANNOTATE-FIELD is used to build a
1024 string for `mh-annotate-msg'.
1025 CONFIG is the window configuration to restore after sending the
1026 letter."
1027 (pop-to-buffer draft)
1028 (mh-letter-mode)
1030 ;; Insert identity.
1031 (mh-insert-identity mh-identity-default t)
1032 (mh-identity-make-menu)
1033 (mh-identity-add-menu)
1035 ;; Cleanup possibly RFC2047 encoded subject header
1036 (mh-decode-message-subject)
1038 ;; Insert extra fields.
1039 (mh-insert-x-mailer)
1040 (mh-insert-x-face)
1042 (mh-letter-hide-all-skipped-fields)
1044 (setq mh-sent-from-folder sent-from-folder)
1045 (setq mh-sent-from-msg sent-from-msg)
1046 (setq mh-send-args send-args)
1047 (setq mh-annotate-char annotate-char)
1048 (setq mh-annotate-field annotate-field)
1049 (setq mh-previous-window-config config)
1050 (setq mode-line-buffer-identification (list " {%b}"))
1051 (mh-logo-display)
1052 (mh-make-local-hook 'kill-buffer-hook)
1053 (add-hook 'kill-buffer-hook 'mh-tidy-draft-buffer nil t)
1054 (run-hook-with-args 'mh-compose-letter-function to subject cc))
1056 (defun mh-insert-x-mailer ()
1057 "Append an X-Mailer field to the header.
1058 The versions of MH-E, Emacs, and MH are shown."
1059 (or mh-variant-in-use (mh-variant-set mh-variant))
1060 ;; Lazily initialize mh-x-mailer-string.
1061 (when (and mh-insert-x-mailer-flag (null mh-x-mailer-string))
1062 (setq mh-x-mailer-string
1063 (format "MH-E %s; %s; %sEmacs %s"
1064 mh-version mh-variant-in-use
1065 (if (featurep 'xemacs) "X" "GNU ")
1066 (cond ((not (featurep 'xemacs))
1067 (string-match "[0-9]+\\.[0-9]+\\(\\.[0-9]+\\)?"
1068 emacs-version)
1069 (match-string 0 emacs-version))
1070 ((string-match "[0-9.]*\\( +([ a-z]+[0-9]+)\\)?"
1071 emacs-version)
1072 (match-string 0 emacs-version))
1073 (t (format "%s.%s" emacs-major-version
1074 emacs-minor-version))))))
1075 ;; Insert X-Mailer, but only if it doesn't already exist.
1076 (save-excursion
1077 (when (and mh-insert-x-mailer-flag
1078 (null (mh-goto-header-field "X-Mailer")))
1079 (mh-insert-fields "X-Mailer:" mh-x-mailer-string))))
1081 (defun mh-insert-x-face ()
1082 "Append X-Face, Face or X-Image-URL field to header.
1083 If the field already exists, this function does nothing."
1084 (when (and (stringp mh-x-face-file)
1085 (file-exists-p mh-x-face-file)
1086 (file-readable-p mh-x-face-file))
1087 (save-excursion
1088 (unless (or (mh-position-on-field "X-Face")
1089 (mh-position-on-field "Face")
1090 (mh-position-on-field "X-Image-URL"))
1091 (save-excursion
1092 (goto-char (+ (point) (cadr (insert-file-contents mh-x-face-file))))
1093 (if (not (looking-at "^"))
1094 (insert "\n")))
1095 (unless (looking-at "\\(X-Face\\|Face\\|X-Image-URL\\): ")
1096 (insert "X-Face: "))))))
1098 (defun mh-tidy-draft-buffer ()
1099 "Run when a draft buffer is destroyed."
1100 (let ((buffer (get-buffer mh-recipients-buffer)))
1101 (if buffer
1102 (kill-buffer buffer))))
1104 (defun mh-letter-mode-message ()
1105 "Display a help message for users of `mh-letter-mode'.
1106 This should be the last function called when composing the draft."
1107 (message "%s" (substitute-command-keys
1108 (concat "Type \\[mh-send-letter] to send message, "
1109 "\\[mh-help] for help"))))
1111 (defun mh-letter-adjust-point ()
1112 "Move cursor to first header field if are using the no prompt mode."
1113 (unless mh-compose-prompt-flag
1114 (goto-char (point-max))
1115 (mh-letter-next-header-field)))
1117 (defun mh-annotate-msg (msg folder note &rest args)
1118 "Mark MSG in FOLDER with character NOTE and annotate message with ARGS.
1119 MSG can be a message number, a list of message numbers, or a sequence.
1120 The hook `mh-annotate-msg-hook' is run after annotating; see its
1121 documentation for variables it can use."
1122 (apply 'mh-exec-cmd "anno" folder
1123 (if (listp msg) (append msg args) (cons msg args)))
1124 (save-excursion
1125 (cond ((get-buffer folder) ; Buffer may be deleted
1126 (set-buffer folder)
1127 (mh-iterate-on-range nil msg
1128 (mh-notate nil note
1129 (+ mh-cmd-note mh-scan-field-destination-offset))))))
1130 (let ((mh-current-folder folder)
1131 ;; mh-annotate-list is a sequence name or a list of message numbers
1132 (mh-annotate-list (if (numberp msg) (list msg) msg)))
1133 (run-hooks 'mh-annotate-msg-hook)))
1135 (defun mh-insert-header-separator ()
1136 "Insert `mh-mail-header-separator', if absent."
1137 (save-excursion
1138 (goto-char (point-min))
1139 (rfc822-goto-eoh)
1140 (if (looking-at "$")
1141 (insert mh-mail-header-separator))))
1143 ;;;###mh-autoload
1144 (defun mh-insert-auto-fields (&optional non-interactive)
1145 "Insert custom fields if recipient is found in `mh-auto-fields-list'.
1147 Once the header contains one or more recipients, you may run this
1148 command to insert these fields manually. However, if you use this
1149 command, the automatic insertion when the message is sent is
1150 disabled.
1152 In a program, set buffer-local `mh-insert-auto-fields-done-local'
1153 if header fields were added. If NON-INTERACTIVE is non-nil,
1154 perform actions quietly and only if
1155 `mh-insert-auto-fields-done-local' is nil. Return t if fields
1156 added; otherwise return nil."
1157 (interactive)
1158 (when (or (not non-interactive)
1159 (not mh-insert-auto-fields-done-local))
1160 (save-excursion
1161 (when (and (or (mh-goto-header-field "To:")
1162 (mh-goto-header-field "cc:")))
1163 (let ((list mh-auto-fields-list)
1164 (fields-inserted nil))
1165 (while list
1166 (let ((regexp (nth 0 (car list)))
1167 (entries (nth 1 (car list))))
1168 (when (mh-regexp-in-field-p regexp "To:" "cc:")
1169 (setq mh-insert-auto-fields-done-local t)
1170 (setq fields-inserted t)
1171 (if (not non-interactive)
1172 (message "Fields for %s added" regexp))
1173 (let ((entry-list entries))
1174 (while entry-list
1175 (let ((field (caar entry-list))
1176 (value (cdar entry-list)))
1177 (cond
1178 ((equal ":identity" field)
1179 (when
1180 ;;(and (not mh-identity-local)
1181 ;; Bug 1204506. But do we need to be able
1182 ;; to set an identity manually that won't be
1183 ;; overridden by mh-insert-auto-fields?
1184 (assoc value mh-identity-list)
1186 (mh-insert-identity value)))
1188 (mh-modify-header-field field value
1189 (equal field "From")))))
1190 (setq entry-list (cdr entry-list))))))
1191 (setq list (cdr list)))
1192 fields-inserted)))))
1194 (defun mh-modify-header-field (field value &optional overwrite-flag)
1195 "To header FIELD add VALUE.
1196 If OVERWRITE-FLAG is non-nil then the old value, if present, is
1197 discarded."
1198 (cond ((and overwrite-flag
1199 (mh-goto-header-field (concat field ":")))
1200 (insert " " value)
1201 (delete-region (point) (mh-line-end-position)))
1202 ((and (not overwrite-flag)
1203 (mh-regexp-in-field-p (concat "\\b" (regexp-quote value) "\\b") field))
1204 ;; Already there, do nothing.
1206 ((and (not overwrite-flag)
1207 (mh-goto-header-field (concat field ":")))
1208 (insert " " value ","))
1210 (mh-goto-header-end 0)
1211 (insert field ": " value "\n"))))
1213 (defun mh-regexp-in-field-p (regexp &rest fields)
1214 "Non-nil means REGEXP was found in FIELDS."
1215 (let ((old-syntax-table (syntax-table)))
1216 (unwind-protect
1217 (save-excursion
1218 (let ((search-result nil))
1219 (while fields
1220 (let* ((field (car fields))
1221 (syntax-table
1222 (or mh-regexp-in-field-syntax-table
1223 (let ((case-fold-search t))
1224 (cond
1225 ((string-match field "^To$\\|^[BD]?cc$\\|^From$")
1226 mh-addr-syntax-table)
1227 ((string-match field "^Fcc$")
1228 mh-fcc-syntax-table)
1230 (syntax-table)))
1231 ))))
1232 (if (and (mh-goto-header-field field)
1233 (set-syntax-table syntax-table)
1234 (re-search-forward
1235 regexp (save-excursion (mh-header-field-end)(point)) t))
1236 (setq fields nil
1237 search-result t)
1238 (setq fields (cdr fields)))
1239 (set-syntax-table old-syntax-table)))
1240 search-result))
1241 (set-syntax-table old-syntax-table))))
1243 (defun mh-ascii-buffer-p ()
1244 "Check if current buffer is entirely composed of ASCII.
1245 The function doesn't work for XEmacs since `find-charset-region'
1246 doesn't exist there."
1247 (loop for charset in (mh-funcall-if-exists
1248 find-charset-region (point-min) (point-max))
1249 unless (eq charset 'ascii) return nil
1250 finally return t))
1252 (provide 'mh-comp)
1254 ;; Local Variables:
1255 ;; indent-tabs-mode: nil
1256 ;; sentence-end-double-space: nil
1257 ;; End:
1259 ;;; mh-comp.el ends here