Atomically update subdirs.el.
[bpt/emacs.git] / lisp / mh-e / mh-comp.el
CommitLineData
dda00b2c 1;;; mh-comp.el --- MH-E functions for composing and sending messages
c26cf6c8 2
e495eaec 3;; Copyright (C) 1993, 1995, 1997,
d7a0267c 4;; 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
7382bcae 5
a1b4049d 6;; Author: Bill Wohler <wohler@newt.com>
6e65a812 7;; Maintainer: Bill Wohler <wohler@newt.com>
7382bcae 8;; Keywords: mail
a1b4049d 9;; See: mh-e.el
c26cf6c8 10
60370d40 11;; This file is part of GNU Emacs.
c26cf6c8 12
9b7bc076 13;; GNU Emacs is free software; you can redistribute it and/or modify
c26cf6c8 14;; it under the terms of the GNU General Public License as published by
ceaeecb0 15;; the Free Software Foundation; either version 3, or (at your option)
c26cf6c8
RS
16;; any later version.
17
9b7bc076 18;; GNU Emacs is distributed in the hope that it will be useful,
c26cf6c8
RS
19;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21;; GNU General Public License for more details.
22
23;; You should have received a copy of the GNU General Public License
b578f267 24;; along with GNU Emacs; see the file COPYING. If not, write to the
3a35cf56
LK
25;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
26;; Boston, MA 02110-1301, USA.
c26cf6c8
RS
27
28;;; Commentary:
29
dda00b2c
BW
30;; This file includes the functions in the MH-Folder maps that get us
31;; into MH-Letter mode, as well the functions in the MH-Letter mode
32;; that are used to send the mail. Other that those, functions that
33;; are needed in mh-letter.el should be found there.
c26cf6c8 34
847b8219
KH
35;;; Change Log:
36
c26cf6c8
RS
37;;; Code:
38
7094eefe 39(require 'mh-e)
dda00b2c
BW
40(require 'mh-gnus) ;needed because mh-gnus.el not compiled
41(require 'mh-scan)
7094eefe 42
dda00b2c 43(require 'sendmail)
bdcfe844 44
dda00b2c
BW
45(autoload 'easy-menu-add "easymenu")
46(autoload 'mml-insert-tag "mml")
c26cf6c8 47
cee9f5c6
BW
48\f
49
dda00b2c 50;;; Site Customization
847b8219
KH
51
52(defvar mh-send-prog "send"
53 "Name of the MH send program.
54Some sites need to change this because of a name conflict.")
55
fbf62741
BW
56(defvar mh-send-uses-spost-flag nil
57 "Non-nil means \"send\" uses \"spost\" to submit messages.
58
59If the value of \"postproc:\" is \"spost\", you may need to set
60this variable to t to tell MH-E to avoid using features of
61\"post\" that are not supported by \"spost\". You'll know that
62you'll need to do this if sending mail fails with an error of
63\"spost: -msgid unknown\".")
64
a1b4049d
BW
65(defvar mh-redist-background nil
66 "If non-nil redist will be done in background like send.
2dcf34f9
BW
67This allows transaction log to be visible if -watch, -verbose or
68-snoop are used.")
847b8219 69
cee9f5c6
BW
70\f
71
dda00b2c 72;;; Variables
c26cf6c8 73
c26cf6c8
RS
74(defvar mh-comp-formfile "components"
75 "Name of file to be used as a skeleton for composing messages.
2dcf34f9
BW
76
77Default is \"components\".
78
79If not an absolute file name, the file is searched for first in the
80user's MH directory, then in the system MH lib directory.")
c26cf6c8 81
847b8219
KH
82(defvar mh-repl-formfile "replcomps"
83 "Name of file to be used as a skeleton for replying to messages.
2dcf34f9
BW
84
85Default is \"replcomps\".
86
87If not an absolute file name, the file is searched for first in the
88user's MH directory, then in the system MH lib directory.")
847b8219 89
c3d6278e 90(defvar mh-repl-group-formfile "replgroupcomps"
bdcfe844 91 "Name of file to be used as a skeleton for replying to messages.
2dcf34f9 92
f0d73c14 93Default is \"replgroupcomps\".
2dcf34f9
BW
94
95This file is used to form replies to the sender and all recipients of
96a message. Only used if `(mh-variant-p 'nmh)' is non-nil.
97If not an absolute file name, the file is searched for first in the
98user's MH directory, then in the system MH lib directory.")
a1b4049d 99
c26cf6c8 100(defvar mh-rejected-letter-start
bdcfe844 101 (format "^%s$"
c3d9274a
BW
102 (regexp-opt
103 '("Content-Type: message/rfc822" ;MIME MDN
f0d73c14 104 "------ This is a copy of the message, including all the headers. ------";from exim
dda00b2c 105 "--- Below this line is a copy of the message."; from qmail
c3d9274a
BW
106 " ----- Unsent message follows -----" ;from sendmail V5
107 " --------Unsent Message below:" ; from sendmail at BU
108 " ----- Original message follows -----" ;from sendmail V8
109 "------- Unsent Draft" ;from MH itself
110 "---------- Original Message ----------" ;from zmailer
111 " --- The unsent message follows ---" ;from AIX mail system
112 " Your message follows:" ;from MMDF-II
113 "Content-Description: Returned Content" ;1993 KJ sendmail
114 ))))
c26cf6c8
RS
115
116(defvar mh-new-draft-cleaned-headers
847b8219 117 "^Date:\\|^Received:\\|^Message-Id:\\|^From:\\|^Sender:\\|^Errors-To:\\|^Delivery-Date:\\|^Return-Path:"
5a4aad03
BW
118 "Regexp of header lines to remove before offering a message as a new draft\\<mh-folder-mode-map>.
119Used by the \\[mh-edit-again] and \\[mh-extract-rejected-mail] commands.")
c26cf6c8 120
c26cf6c8 121(defvar mh-letter-mode-syntax-table nil
bdcfe844 122 "Syntax table used by MH-E while in MH-Letter mode.")
c26cf6c8
RS
123
124(if mh-letter-mode-syntax-table
125 ()
c3d9274a
BW
126 (setq mh-letter-mode-syntax-table
127 (make-syntax-table text-mode-syntax-table))
128 (modify-syntax-entry ?% "." mh-letter-mode-syntax-table))
c26cf6c8 129
799f7c09 130(defvar mh-send-args ""
bdcfe844
BW
131 "Extra args to pass to \"send\" command.")
132
133(defvar mh-annotate-char nil
134 "Character to use to annotate `mh-sent-from-msg'.")
135
136(defvar mh-annotate-field nil
137 "Field name for message annotation.")
c26cf6c8 138
aad5673d
SG
139(defvar mh-annotate-list nil
140 "Messages annotated, either a sequence name or a list of message numbers.
141This variable can be used by `mh-annotate-msg-hook'.")
142
a66894d8 143(defvar mh-insert-auto-fields-done-local nil
f0d73c14 144 "Buffer-local variable set when `mh-insert-auto-fields' called successfully.")
a66894d8
BW
145(make-variable-buffer-local 'mh-insert-auto-fields-done-local)
146
dda00b2c
BW
147\f
148
149;;; MH-E Entry Points
150
c26cf6c8
RS
151;;;###autoload
152(defun mh-smail ()
b2064e08 153 "Compose a message with the MH mail system.
f0d73c14 154See `mh-send' for more details on composing mail."
c26cf6c8
RS
155 (interactive)
156 (mh-find-path)
157 (call-interactively 'mh-send))
158
b2064e08
BW
159;;;###autoload
160(defun mh-smail-other-window ()
161 "Compose a message with the MH mail system in other window.
162See `mh-send' for more details on composing mail."
163 (interactive)
164 (mh-find-path)
165 (call-interactively 'mh-send-other-window))
166
dda00b2c
BW
167(defun mh-send-other-window (to cc subject)
168 "Compose a message in another window.
169
170See `mh-send' for more information and a description of how the
171TO, CC, and SUBJECT arguments are used."
172 (interactive (list
173 (mh-interactive-read-address "To: ")
174 (mh-interactive-read-address "Cc: ")
175 (mh-interactive-read-string "Subject: ")))
176 (let ((pop-up-windows t))
177 (mh-send-sub to cc subject (current-window-configuration))))
178
c3d9274a 179(defvar mh-error-if-no-draft nil) ;raise error over using old draft
283b03f4 180
283b03f4 181;;;###autoload
c3d6278e 182(defun mh-smail-batch (&optional to subject other-headers &rest ignored)
b2064e08
BW
183 "Compose a message with the MH mail system.
184
2dcf34f9
BW
185This function does not prompt the user for any header fields, and
186thus is suitable for use by programs that want to create a mail
187buffer. Users should use \\[mh-smail] to compose mail.
f0d73c14 188
2dcf34f9 189Optional arguments for setting certain fields include TO,
0d887b77
BW
190SUBJECT, and OTHER-HEADERS. Additional arguments are IGNORED.
191
192This function remains for Emacs 21 compatibility. New
193applications should use `mh-user-agent-compose'."
283b03f4
KH
194 (mh-find-path)
195 (let ((mh-error-if-no-draft t))
016fbe59 196 (mh-send (or to "") "" (or subject ""))))
283b03f4 197
0d887b77
BW
198;;;###autoload
199(define-mail-user-agent 'mh-e-user-agent
200 'mh-user-agent-compose 'mh-send-letter 'mh-fully-kill-draft
201 'mh-before-send-letter-hook)
202
a1b4049d
BW
203;;;###autoload
204(defun mh-user-agent-compose (&optional to subject other-headers continue
c3d9274a
BW
205 switch-function yank-action
206 send-actions)
a1b4049d 207 "Set up mail composition draft with the MH mail system.
0d887b77
BW
208This is the `mail-user-agent' entry point to MH-E. This function
209conforms to the contract specified by `define-mail-user-agent'
210which means that this function should accept the same arguments
211as `compose-mail'.
a1b4049d
BW
212
213The optional arguments TO and SUBJECT specify recipients and the
214initial Subject field, respectively.
215
2dcf34f9
BW
216OTHER-HEADERS is an alist specifying additional header fields.
217Elements look like (HEADER . VALUE) where both HEADER and VALUE
218are strings.
a1b4049d 219
2dcf34f9
BW
220CONTINUE, SWITCH-FUNCTION, YANK-ACTION and SEND-ACTIONS are
221ignored."
a1b4049d
BW
222 (mh-find-path)
223 (let ((mh-error-if-no-draft t))
224 (mh-send to "" subject)
225 (while other-headers
226 (mh-insert-fields (concat (car (car other-headers)) ":")
c3d9274a 227 (cdr (car other-headers)))
a1b4049d 228 (setq other-headers (cdr other-headers)))))
283b03f4 229
dda00b2c 230;; Shush compiler.
42f8c37f 231(defvar sendmail-coding-system) ; XEmacs
dda00b2c
BW
232
233;;;###autoload
234(defun mh-send-letter (&optional arg)
235 "Save draft and send message.
236
237When you are all through editing a message, you send it with this
238command. You can give a prefix argument ARG to monitor the first stage
239of the delivery\; this output can be found in a buffer called \"*MH-E
240Mail Delivery*\".
241
242The hook `mh-before-send-letter-hook' is run at the beginning of
243this command. For example, if you want to check your spelling in
244your message before sending, add the function `ispell-message'.
245
3fbc098d
BW
246Unless `mh-insert-auto-fields' had previously been called
247manually, the function `mh-insert-auto-fields' is called to
248insert fields based upon the recipients. If fields are added, you
249are given a chance to see and to confirm these fields before the
250message is actually sent. You can do away with this confirmation
251by turning off the option `mh-auto-fields-prompt-flag'.
252
dda00b2c
BW
253In case the MH \"send\" program is installed under a different name,
254use `mh-send-prog' to tell MH-E the name."
255 (interactive "P")
256 (run-hooks 'mh-before-send-letter-hook)
257 (if (and (mh-insert-auto-fields t)
258 mh-auto-fields-prompt-flag
259 (goto-char (point-min)))
260 (if (not (y-or-n-p "Auto fields inserted, send? "))
261 (error "Send aborted")))
262 (cond ((mh-mh-directive-present-p)
263 (mh-mh-to-mime))
264 ((or (mh-mml-tag-present-p) (not (mh-ascii-buffer-p)))
265 (mh-mml-to-mime)))
266 (save-buffer)
267 (message "Sending...")
268 (let ((draft-buffer (current-buffer))
269 (file-name buffer-file-name)
270 (config mh-previous-window-config)
271 (coding-system-for-write
272 (if (and (local-variable-p 'buffer-file-coding-system
273 (current-buffer)) ;XEmacs needs two args
274 ;; We're not sure why, but buffer-file-coding-system
275 ;; tends to get set to undecided-unix.
276 (not (memq buffer-file-coding-system
277 '(undecided undecided-unix undecided-dos))))
278 buffer-file-coding-system
279 (or (and (boundp 'sendmail-coding-system) sendmail-coding-system)
280 (and (boundp 'default-buffer-file-coding-system )
281 default-buffer-file-coding-system)
282 'iso-latin-1))))
fbf62741
BW
283 ;; Older versions of spost do not support -msgid and -mime.
284 (unless mh-send-uses-spost-flag
285 ;; Adding a Message-ID field looks good, makes it easier to search for
286 ;; message in your +outbox, and best of all doesn't break threading for
287 ;; the recipient if you reply to a message in your +outbox.
288 (setq mh-send-args (concat "-msgid " mh-send-args))
289 ;; The default BCC encapsulation will make a MIME message unreadable.
290 ;; With nmh use the -mime arg to prevent this.
291 (if (and (mh-variant-p 'nmh)
292 (mh-goto-header-field "Bcc:")
293 (mh-goto-header-field "Content-Type:"))
294 (setq mh-send-args (concat "-mime " mh-send-args))))
dda00b2c
BW
295 (cond (arg
296 (pop-to-buffer mh-mail-delivery-buffer)
297 (erase-buffer)
298 (mh-exec-cmd-output mh-send-prog t "-watch" "-nopush"
299 "-nodraftfolder" mh-send-args file-name)
300 (goto-char (point-max)) ; show the interesting part
301 (recenter -1)
302 (set-buffer draft-buffer)) ; for annotation below
303 (t
304 (mh-exec-cmd-daemon mh-send-prog nil "-nodraftfolder" "-noverbose"
16b9a476 305 (split-string mh-send-args) file-name)))
dda00b2c
BW
306 (if mh-annotate-char
307 (mh-annotate-msg mh-sent-from-msg
308 mh-sent-from-folder
309 mh-annotate-char
310 "-component" mh-annotate-field
311 "-text" (format "\"%s %s\""
312 (mh-get-header-field "To:")
313 (mh-get-header-field "Cc:"))))
314
315 (cond ((or (not arg)
316 (y-or-n-p "Kill draft buffer? "))
317 (kill-buffer draft-buffer)
318 (if config
319 (set-window-configuration config))))
320 (if arg
321 (message "Sending...done")
322 (message "Sending...backgrounded"))))
323
324;;;###autoload
325(defun mh-fully-kill-draft ()
326 "Quit editing and delete draft message.
327
328If for some reason you are not happy with the draft, you can use
329this command to kill the draft buffer and delete the draft
330message. Use the command \\[kill-buffer] if you don't want to
331delete the draft message."
332 (interactive)
333 (if (y-or-n-p "Kill draft message? ")
334 (let ((config mh-previous-window-config))
335 (if (file-exists-p buffer-file-name)
336 (delete-file buffer-file-name))
337 (set-buffer-modified-p nil)
338 (kill-buffer (buffer-name))
339 (message "")
340 (if config
341 (set-window-configuration config)))
342 (error "Message not killed")))
343
344\f
345
346;;; MH-Folder Commands
347
348;; Alphabetical.
349
c3d9274a 350;;;###mh-autoload
b2064e08
BW
351(defun mh-edit-again (message)
352 "Edit a MESSAGE to send it again.
353
2dcf34f9
BW
354If you don't complete a draft for one reason or another, and if
355the draft buffer is no longer available, you can pick your draft
356up again with this command. If you don't use a draft folder, your
357last \"draft\" file will be used. If you use draft folders,
358you'll need to visit the draft folder with \"\\[mh-visit-folder]
359drafts <RET>\", use \\[mh-next-undeleted-msg] to move to the
360appropriate message, and then use \\[mh-edit-again] to prepare
361the message for editing.
b2064e08 362
2dcf34f9
BW
363This command can also be used to take messages that were sent to
364you and to send them to more people.
b2064e08 365
2dcf34f9
BW
366Don't use this command to re-edit a message from a Mailer-Daemon
367who complained that your mail wasn't posted for some reason or
368another (see `mh-extract-rejected-mail').
b2064e08
BW
369
370The default message is the current message.
f0d73c14
BW
371
372See also `mh-send'."
c26cf6c8
RS
373 (interactive (list (mh-get-msg-num t)))
374 (let* ((from-folder mh-current-folder)
c3d9274a
BW
375 (config (current-window-configuration))
376 (draft
377 (cond ((and mh-draft-folder (equal from-folder mh-draft-folder))
b2064e08
BW
378 (pop-to-buffer (find-file-noselect (mh-msg-filename message))
379 t)
380 (rename-buffer (format "draft-%d" message))
bdcfe844
BW
381 ;; Make buffer writable...
382 (setq buffer-read-only nil)
383 ;; If buffer was being used to display the message reinsert
384 ;; from file...
385 (when (eq major-mode 'mh-show-mode)
386 (erase-buffer)
387 (insert-file-contents buffer-file-name))
c3d9274a
BW
388 (buffer-name))
389 (t
b2064e08 390 (mh-read-draft "clean-up" (mh-msg-filename message) nil)))))
c26cf6c8 391 (mh-clean-msg-header (point-min) mh-new-draft-cleaned-headers nil)
a1b4049d 392 (mh-insert-header-separator)
c26cf6c8 393 (goto-char (point-min))
283b03f4 394 (save-buffer)
c26cf6c8 395 (mh-compose-and-send-mail draft "" from-folder nil nil nil nil nil nil
c3d9274a 396 config)
a66894d8
BW
397 (mh-letter-mode-message)
398 (mh-letter-adjust-point)))
c26cf6c8 399
c3d9274a 400;;;###mh-autoload
b2064e08
BW
401(defun mh-extract-rejected-mail (message)
402 "Edit a MESSAGE that was returned by the mail system.
403
2dcf34f9
BW
404This command prepares the message for editing by removing the
405Mailer-Daemon envelope and unneeded header fields. Fix whatever
406addressing problem you had, and send the message again with
407\\[mh-send-letter].
b2064e08
BW
408
409The default message is the current message.
f0d73c14
BW
410
411See also `mh-send'."
c26cf6c8
RS
412 (interactive (list (mh-get-msg-num t)))
413 (let ((from-folder mh-current-folder)
c3d9274a 414 (config (current-window-configuration))
b2064e08 415 (draft (mh-read-draft "extraction" (mh-msg-filename message) nil)))
c26cf6c8
RS
416 (goto-char (point-min))
417 (cond ((re-search-forward mh-rejected-letter-start nil t)
c3d9274a
BW
418 (skip-chars-forward " \t\n")
419 (delete-region (point-min) (point))
420 (mh-clean-msg-header (point-min) mh-new-draft-cleaned-headers nil))
421 (t
f0d73c14 422 (message "Does not appear to be a rejected letter")))
a1b4049d 423 (mh-insert-header-separator)
c26cf6c8 424 (goto-char (point-min))
283b03f4 425 (save-buffer)
b2064e08 426 (mh-compose-and-send-mail draft "" from-folder message
c3d9274a
BW
427 (mh-get-header-field "To:")
428 (mh-get-header-field "From:")
429 (mh-get-header-field "Cc:")
430 nil nil config)
bdcfe844 431 (mh-letter-mode-message)))
c26cf6c8 432
c3d9274a 433;;;###mh-autoload
a66894d8 434(defun mh-forward (to cc &optional range)
2be362c2 435 "Forward message.
a66894d8 436
2dcf34f9
BW
437You are prompted for the TO and CC recipients. You are given a
438draft to edit that looks like it would if you had run the MH
439command \"forw\". You can then add some text.
bdcfe844 440
2dcf34f9
BW
441You can forward several messages by using a RANGE. All of the
442messages in the range are inserted into your draft. Check the
443documentation of `mh-interactive-range' to see how RANGE is read
444in interactive use.
b2064e08 445
d1699462
BW
446The hook `mh-forward-hook' is called on the draft.
447
448See also `mh-compose-forward-as-mime-flag',
449`mh-forward-subject-format', and `mh-send'."
a66894d8
BW
450 (interactive (list (mh-interactive-read-address "To: ")
451 (mh-interactive-read-address "Cc: ")
452 (mh-interactive-range "Forward")))
c26cf6c8 453 (let* ((folder mh-current-folder)
a66894d8 454 (msgs (mh-range-to-msg-list range))
c3d9274a
BW
455 (config (current-window-configuration))
456 (fwd-msg-file (mh-msg-filename (car msgs) folder))
457 ;; forw always leaves file in "draft" since it doesn't have -draft
458 (draft-name (expand-file-name "draft" mh-user-path))
459 (draft (cond ((or (not (file-exists-p draft-name))
00b6a079 460 (y-or-n-p "The file draft exists; discard it? "))
f0d73c14
BW
461 (mh-exec-cmd "forw" "-build"
462 (if (and (mh-variant-p 'nmh)
463 mh-compose-forward-as-mime-flag)
464 "-mime")
924df208
BW
465 mh-current-folder
466 (mh-coalesce-msg-list msgs))
c3d9274a
BW
467 (prog1
468 (mh-read-draft "" draft-name t)
469 (mh-insert-fields "To:" to "Cc:" cc)
470 (save-buffer)))
471 (t
472 (mh-read-draft "" draft-name nil)))))
847b8219 473 (let (orig-from
c3d9274a 474 orig-subject)
41b9a988 475 (save-excursion
c3d9274a
BW
476 (set-buffer (get-buffer-create mh-temp-buffer))
477 (erase-buffer)
478 (insert-file-contents fwd-msg-file)
479 (setq orig-from (mh-get-header-field "From:"))
480 (setq orig-subject (mh-get-header-field "Subject:")))
c26cf6c8 481 (let ((forw-subject
924df208 482 (mh-forwarded-letter-subject orig-from orig-subject)))
c3d9274a
BW
483 (mh-insert-fields "Subject:" forw-subject)
484 (goto-char (point-min))
0c47b17c
BW
485 ;; If using MML, translate MH-style directive
486 (if (equal mh-compose-insertion 'mml)
c3d9274a 487 (save-excursion
a66894d8 488 (goto-char (mh-mail-header-end))
c3d9274a
BW
489 (while
490 (re-search-forward
491 "^#forw \\[\\([^]]+\\)\\] \\(+\\S-+\\) \\(.*\\)$"
492 (point-max) t)
493 (let ((description (if (equal (match-string 1)
494 "forwarded messages")
495 "forwarded message %d"
496 (match-string 1)))
497 (msgs (split-string (match-string 3)))
498 (i 0))
499 (beginning-of-line)
500 (delete-region (point) (progn (forward-line 1) (point)))
501 (dolist (msg msgs)
502 (setq i (1+ i))
503 (mh-mml-forward-message (format description i)
d5926104
JH
504 folder msg)
505 ;; Was inserted before us, move to end of file to preserve order
506 (goto-char (point-max)))))))
c3d9274a
BW
507 ;; Postition just before forwarded message
508 (if (re-search-forward "^------- Forwarded Message" nil t)
509 (forward-line -1)
a66894d8 510 (goto-char (mh-mail-header-end))
c3d9274a
BW
511 (forward-line 1))
512 (delete-other-windows)
513 (mh-add-msgs-to-seq msgs 'forwarded t)
924df208 514 (mh-compose-and-send-mail draft "" folder msgs
c3d9274a
BW
515 to forw-subject cc
516 mh-note-forw "Forwarded:"
517 config)
a66894d8 518 (mh-letter-mode-message)
f0d73c14
BW
519 (mh-letter-adjust-point)
520 (run-hooks 'mh-forward-hook)))))
c26cf6c8
RS
521
522(defun mh-forwarded-letter-subject (from subject)
bdcfe844
BW
523 "Return a Subject suitable for a forwarded message.
524Original message has headers FROM and SUBJECT."
c26cf6c8 525 (let ((addr-start (string-match "<" from))
c3d9274a 526 (comment (string-match "(" from)))
c26cf6c8 527 (cond ((and addr-start (> addr-start 0))
c3d9274a
BW
528 ;; Full Name <luser@host>
529 (setq from (substring from 0 (1- addr-start))))
530 (comment
531 ;; luser@host (Full Name)
532 (setq from (substring from (1+ comment) (1- (length from)))))))
c26cf6c8
RS
533 (format mh-forward-subject-format from subject))
534
b2064e08
BW
535;;;###mh-autoload
536(defun mh-redistribute (to cc &optional message)
537 "Redistribute a message.
847b8219 538
2dcf34f9
BW
539This command is similar in function to forwarding mail, but it
540does not allow you to edit the message, nor does it add your name
541to the \"From\" header field. It appears to the recipient as if
542the message had come from the original sender. When you run this
543command, you are prompted for the TO and CC recipients. The
544default MESSAGE is the current message.
c26cf6c8 545
af435184 546Also investigate the command \\[mh-edit-again] for another way to
2dcf34f9 547redistribute messages.
b2064e08
BW
548
549See also `mh-redist-full-contents-flag'."
c26cf6c8 550 (interactive (list (mh-read-address "Redist-To: ")
c3d9274a
BW
551 (mh-read-address "Redist-Cc: ")
552 (mh-get-msg-num t)))
b2064e08
BW
553 (or message
554 (setq message (mh-get-msg-num t)))
c26cf6c8
RS
555 (save-window-excursion
556 (let ((folder mh-current-folder)
c3d9274a 557 (draft (mh-read-draft "redistribution"
b2064e08
BW
558 (if mh-redist-full-contents-flag
559 (mh-msg-filename message)
c3d9274a
BW
560 nil)
561 nil)))
c26cf6c8
RS
562 (mh-goto-header-end 0)
563 (insert "Resent-To: " to "\n")
564 (if (not (equal cc "")) (insert "Resent-cc: " cc "\n"))
924df208
BW
565 (mh-clean-msg-header
566 (point-min)
567 "^Message-Id:\\|^Received:\\|^Return-Path:\\|^Sender:\\|^Date:\\|^From:"
568 nil)
c26cf6c8
RS
569 (save-buffer)
570 (message "Redistributing...")
924df208
BW
571 (let ((env "mhdist=1"))
572 ;; Setup environment...
b2064e08
BW
573 (setq env (concat env " mhaltmsg="
574 (if mh-redist-full-contents-flag
575 buffer-file-name
576 (mh-msg-filename message folder))))
577 (unless mh-redist-full-contents-flag
924df208
BW
578 (setq env (concat env " mhannotate=1")))
579 ;; Redistribute...
580 (if mh-redist-background
581 (mh-exec-cmd-env-daemon env mh-send-prog nil buffer-file-name)
582 (mh-exec-cmd-error env mh-send-prog "-push" buffer-file-name))
583 ;; Annotate...
b2064e08 584 (mh-annotate-msg message folder mh-note-dist
924df208
BW
585 "-component" "Resent:"
586 "-text" (format "\"%s %s\"" to cc)))
c26cf6c8
RS
587 (kill-buffer draft)
588 (message "Redistributing...done"))))
589
c3d9274a 590;;;###mh-autoload
bdcfe844 591(defun mh-reply (message &optional reply-to includep)
b2064e08 592 "Reply to a MESSAGE.
f0d73c14 593
2dcf34f9
BW
594When you reply to a message, you are first prompted with \"Reply
595to whom?\" (unless the optional argument REPLY-TO is provided).
596You have several choices here.
b2064e08
BW
597
598 Response Reply Goes To
599
72cf2f2e 600 from The person who sent the message. This is the
2dcf34f9 601 default, so <RET> is sufficient.
b2064e08
BW
602
603 to Replies to the sender, plus all recipients in the
604 \"To:\" header field.
605
72cf2f2e
BW
606 all cc Forms a reply to the addresses in the
607 \"Mail-Followup-To:\" header field if one
608 exists; otherwise forms a reply to the sender,
609 plus all recipients.
b2064e08 610
2dcf34f9
BW
611Depending on your answer, \"repl\" is given a different argument
612to form your reply. Specifically, a choice of \"from\" or none at
613all runs \"repl -nocc all\", and a choice of \"to\" runs \"repl
614-cc to\". Finally, either \"cc\" or \"all\" runs \"repl -cc all
615-nocc me\".
b2064e08 616
2dcf34f9
BW
617Two windows are then created. One window contains the message to
618which you are replying in an MH-Show buffer. Your draft, in
72cf2f2e
BW
619MH-Letter mode (*note `mh-letter-mode'), is in the other window.
620If the reply draft was not one that you expected, check the
621things that affect the behavior of \"repl\" which include the
622\"repl:\" profile component and the \"replcomps\" and
623\"replgroupcomps\" files.
b2064e08 624
2dcf34f9
BW
625If you supply a prefix argument INCLUDEP, the message you are
626replying to is inserted in your reply after having first been run
627through \"mhl\" with the format file \"mhl.reply\".
b2064e08 628
2dcf34f9
BW
629Alternatively, you can customize the option `mh-yank-behavior'
630and choose one of its \"Automatically\" variants to do the same
631thing. If you do so, the prefix argument has no effect.
b2064e08 632
2dcf34f9
BW
633Another way to include the message automatically in your draft is
634to use \"repl: -filter repl.filter\" in your MH profile.
b2064e08 635
2dcf34f9
BW
636If you wish to customize the header or other parts of the reply
637draft, please see \"repl\" and \"mh-format\".
b2064e08 638
2dcf34f9
BW
639See also `mh-reply-show-message-flag',
640`mh-reply-default-reply-to', and `mh-send'."
bdcfe844
BW
641 (interactive (list
642 (mh-get-msg-num t)
643 (let ((minibuffer-help-form
644 "from => Sender only\nto => Sender and primary recipients\ncc or all => Sender and all recipients"))
645 (or mh-reply-default-reply-to
078cb314 646 (completing-read "Reply to whom (default from): "
bdcfe844
BW
647 '(("from") ("to") ("cc") ("all"))
648 nil
649 t)))
650 current-prefix-arg))
651 (let* ((folder mh-current-folder)
652 (show-buffer mh-show-buffer)
653 (config (current-window-configuration))
654 (group-reply (or (equal reply-to "cc") (equal reply-to "all")))
f0d73c14 655 (form-file (cond ((and (mh-variant-p 'nmh 'mu-mh) group-reply
bdcfe844
BW
656 (stringp mh-repl-group-formfile))
657 mh-repl-group-formfile)
658 ((stringp mh-repl-formfile) mh-repl-formfile)
659 (t nil))))
660 (message "Composing a reply...")
661 (mh-exec-cmd "repl" "-build" "-noquery" "-nodraftfolder"
662 (if form-file
663 (list "-form" form-file))
664 mh-current-folder message
665 (cond ((or (equal reply-to "from") (equal reply-to ""))
666 '("-nocc" "all"))
667 ((equal reply-to "to")
668 '("-cc" "to"))
f0d73c14 669 (group-reply (if (mh-variant-p 'nmh 'mu-mh)
bdcfe844
BW
670 '("-group" "-nocc" "me")
671 '("-cc" "all" "-nocc" "me"))))
0c47b17c
BW
672 (cond ((or (eq mh-yank-behavior 'autosupercite)
673 (eq mh-yank-behavior 'autoattrib))
c3d9274a
BW
674 '("-noformat"))
675 (includep '("-filter" "mhl.reply"))
676 (t '())))
bdcfe844
BW
677 (let ((draft (mh-read-draft "reply"
678 (expand-file-name "reply" mh-user-path)
679 t)))
680 (delete-other-windows)
681 (save-buffer)
a1506d29 682
bdcfe844
BW
683 (let ((to (mh-get-header-field "To:"))
684 (subject (mh-get-header-field "Subject:"))
685 (cc (mh-get-header-field "Cc:")))
686 (goto-char (point-min))
687 (mh-goto-header-end 1)
688 (or includep
689 (not mh-reply-show-message-flag)
690 (mh-in-show-buffer (show-buffer)
691 (mh-display-msg message folder)))
692 (mh-add-msgs-to-seq message 'answered t)
693 (message "Composing a reply...done")
694 (mh-compose-and-send-mail draft "" folder message to subject cc
695 mh-note-repl "Replied:" config))
0c47b17c
BW
696 (when (and (or (eq 'autosupercite mh-yank-behavior)
697 (eq 'autoattrib mh-yank-behavior))
bdcfe844
BW
698 (eq (mh-show-buffer-message-number) mh-sent-from-msg))
699 (undo-boundary)
700 (mh-yank-cur-msg))
701 (mh-letter-mode-message))))
c26cf6c8 702
c3d9274a 703;;;###mh-autoload
c26cf6c8 704(defun mh-send (to cc subject)
b2064e08
BW
705 "Compose a message.
706
2dcf34f9
BW
707Your letter appears in an Emacs buffer whose mode is
708MH-Letter (see `mh-letter-mode').
b2064e08 709
2dcf34f9
BW
710The arguments TO, CC, and SUBJECT can be used to prefill the
711draft fields or suppress the prompts if `mh-compose-prompt-flag'
712is on. They are also passed to the function set in the option
713`mh-compose-letter-function'.
b2064e08
BW
714
715See also `mh-insert-x-mailer-flag' and `mh-letter-mode-hook'.
716
2dcf34f9
BW
717Outside of an MH-Folder buffer (`mh-folder-mode'), you must call
718either \\[mh-smail] or \\[mh-smail-other-window] to compose a new
719message."
c26cf6c8 720 (interactive (list
a66894d8
BW
721 (mh-interactive-read-address "To: ")
722 (mh-interactive-read-address "Cc: ")
723 (mh-interactive-read-string "Subject: ")))
c26cf6c8
RS
724 (let ((config (current-window-configuration)))
725 (delete-other-windows)
726 (mh-send-sub to cc subject config)))
727
dda00b2c
BW
728\f
729
730;;; Support Routines
731
732(defun mh-interactive-read-address (prompt)
733 "Read an address.
734If `mh-compose-prompt-flag' is non-nil, then read an address with
735PROMPT.
736Otherwise return the empty string."
737 (if mh-compose-prompt-flag (mh-read-address prompt) ""))
738
739(defun mh-interactive-read-string (prompt)
740 "Read a string.
741If `mh-compose-prompt-flag' is non-nil, then read a string with
742PROMPT.
743Otherwise return the empty string."
744 (if mh-compose-prompt-flag (read-string prompt) ""))
745
c3d9274a 746;;;###mh-autoload
dda00b2c
BW
747(defun mh-show-buffer-message-number (&optional buffer)
748 "Message number of displayed message in corresponding show buffer.
b2064e08 749
dda00b2c
BW
750Return nil if show buffer not displayed.
751If in `mh-letter-mode', don't display the message number being replied
752to, but rather the message number of the show buffer associated with
753our originating folder buffer.
754Optional argument BUFFER can be used to specify the buffer."
755 (save-excursion
756 (if buffer
757 (set-buffer buffer))
758 (cond ((eq major-mode 'mh-show-mode)
759 (let ((number-start (mh-search-from-end ?/ buffer-file-name)))
760 (string-to-number (substring buffer-file-name
761 (1+ number-start)))))
762 ((and (eq major-mode 'mh-folder-mode)
763 mh-show-buffer
764 (get-buffer mh-show-buffer))
765 (mh-show-buffer-message-number mh-show-buffer))
766 ((and (eq major-mode 'mh-letter-mode)
767 mh-sent-from-folder
768 (get-buffer mh-sent-from-folder))
769 (mh-show-buffer-message-number mh-sent-from-folder))
770 (t
771 nil))))
c26cf6c8 772
c26cf6c8 773(defun mh-send-sub (to cc subject config)
bdcfe844
BW
774 "Do the real work of composing and sending a letter.
775Expects the TO, CC, and SUBJECT fields as arguments.
776CONFIG is the window configuration before sending mail."
c26cf6c8 777 (let ((folder mh-current-folder)
c3d9274a 778 (msg-num (mh-get-msg-num nil)))
c26cf6c8
RS
779 (message "Composing a message...")
780 (let ((draft (mh-read-draft
c3d9274a
BW
781 "message"
782 (let (components)
783 (cond
784 ((file-exists-p
785 (setq components
786 (expand-file-name mh-comp-formfile mh-user-path)))
787 components)
788 ((file-exists-p
789 (setq components
790 (expand-file-name mh-comp-formfile mh-lib)))
791 components)
c3d9274a 792 (t
05227fbe
BW
793 (error "Can't find %s in %s or %s"
794 mh-comp-formfile mh-user-path mh-lib))))
c3d9274a 795 nil)))
c26cf6c8
RS
796 (mh-insert-fields "To:" to "Subject:" subject "Cc:" cc)
797 (goto-char (point-max))
c26cf6c8 798 (mh-compose-and-send-mail draft "" folder msg-num
c3d9274a
BW
799 to subject cc
800 nil nil config)
a66894d8
BW
801 (mh-letter-mode-message)
802 (mh-letter-adjust-point))))
c26cf6c8
RS
803
804(defun mh-read-draft (use initial-contents delete-contents-file)
bdcfe844 805 "Read draft file into a draft buffer and make that buffer the current one.
2dcf34f9
BW
806
807USE is a message used for prompting about the intended use of the
808message.
bdcfe844 809INITIAL-CONTENTS is filename that is read into an empty buffer, or nil
2dcf34f9 810if buffer should not be modified. Delete the initial-contents file if
bdcfe844
BW
811DELETE-CONTENTS-FILE flag is set.
812Returns the draft folder's name.
2dcf34f9
BW
813If the draft folder facility is enabled in ~/.mh_profile, a new buffer
814is used each time and saved in the draft folder. The draft file can
815then be reused."
c26cf6c8 816 (cond (mh-draft-folder
c3d9274a
BW
817 (let ((orig-default-dir default-directory)
818 (draft-file-name (mh-new-draft-name)))
819 (pop-to-buffer (generate-new-buffer
820 (format "draft-%s"
821 (file-name-nondirectory draft-file-name))))
822 (condition-case ()
823 (insert-file-contents draft-file-name t)
824 (file-error))
825 (setq default-directory orig-default-dir)))
826 (t
827 (let ((draft-name (expand-file-name "draft" mh-user-path)))
828 (pop-to-buffer "draft") ; Create if necessary
829 (if (buffer-modified-p)
830 (if (y-or-n-p "Draft has been modified; kill anyway? ")
831 (set-buffer-modified-p nil)
832 (error "Draft preserved")))
833 (setq buffer-file-name draft-name)
834 (clear-visited-file-modtime)
835 (unlock-buffer)
836 (cond ((and (file-exists-p draft-name)
837 (not (equal draft-name initial-contents)))
838 (insert-file-contents draft-name)
839 (delete-file draft-name))))))
c26cf6c8 840 (cond ((and initial-contents
c3d9274a
BW
841 (or (zerop (buffer-size))
842 (if (y-or-n-p
843 (format "A draft exists. Use for %s? " use))
844 (if mh-error-if-no-draft
845 (error "A prior draft exists"))
846 t)))
847 (erase-buffer)
848 (insert-file-contents initial-contents)
849 (if delete-contents-file (delete-file initial-contents))))
c26cf6c8
RS
850 (auto-save-mode 1)
851 (if mh-draft-folder
c3d9274a 852 (save-buffer)) ; Do not reuse draft name
c26cf6c8
RS
853 (buffer-name))
854
c26cf6c8 855(defun mh-new-draft-name ()
bdcfe844 856 "Return the pathname of folder for draft messages."
c26cf6c8
RS
857 (save-excursion
858 (mh-exec-cmd-quiet t "mhpath" mh-draft-folder "new")
859 (buffer-substring (point-min) (1- (point-max)))))
860
c26cf6c8 861(defun mh-insert-fields (&rest name-values)
bdcfe844
BW
862 "Insert the NAME-VALUES pairs in the current buffer.
863If the field exists, append the value to it.
864Do not insert any pairs whose value is the empty string."
c26cf6c8
RS
865 (let ((case-fold-search t))
866 (while name-values
867 (let ((field-name (car name-values))
c3d9274a 868 (value (car (cdr name-values))))
f0d73c14
BW
869 (if (not (string-match "^.*:$" field-name))
870 (setq field-name (concat field-name ":")))
a2c30782
BW
871 (cond ((or (null value)
872 (equal value ""))
c3d9274a
BW
873 nil)
874 ((mh-position-on-field field-name)
875 (insert " " (or value "")))
876 (t
877 (insert field-name " " value "\n")))
878 (setq name-values (cdr (cdr name-values)))))))
c26cf6c8 879
dda00b2c
BW
880(defun mh-compose-and-send-mail (draft send-args
881 sent-from-folder sent-from-msg
882 to subject cc
883 annotate-char annotate-field
884 config)
885 "Edit and compose a draft message in buffer DRAFT and send or save it.
886SEND-ARGS is the argument passed to the send command.
887SENT-FROM-FOLDER is buffer containing scan listing of current folder,
888or nil if none exists.
889SENT-FROM-MSG is the message number or sequence name or nil.
890The TO, SUBJECT, and CC fields are passed to the
891`mh-compose-letter-function'.
892If ANNOTATE-CHAR is non-null, it is used to notate the scan listing of
893the message. In that case, the ANNOTATE-FIELD is used to build a
894string for `mh-annotate-msg'.
895CONFIG is the window configuration to restore after sending the
896letter."
897 (pop-to-buffer draft)
898 (mh-letter-mode)
847b8219 899
dda00b2c
BW
900 ;; Insert identity.
901 (mh-insert-identity mh-identity-default t)
902 (mh-identity-make-menu)
903 (mh-identity-add-menu)
c26cf6c8 904
dda00b2c
BW
905 ;; Insert extra fields.
906 (mh-insert-x-mailer)
907 (mh-insert-x-face)
c26cf6c8 908
dda00b2c 909 (mh-letter-hide-all-skipped-fields)
924df208 910
dda00b2c
BW
911 (setq mh-sent-from-folder sent-from-folder)
912 (setq mh-sent-from-msg sent-from-msg)
913 (setq mh-send-args send-args)
914 (setq mh-annotate-char annotate-char)
915 (setq mh-annotate-field annotate-field)
916 (setq mh-previous-window-config config)
917 (setq mode-line-buffer-identification (list " {%b}"))
918 (mh-logo-display)
919 (mh-make-local-hook 'kill-buffer-hook)
920 (add-hook 'kill-buffer-hook 'mh-tidy-draft-buffer nil t)
16b9a476 921 (run-hook-with-args 'mh-compose-letter-function to subject cc))
bdcfe844 922
a1b4049d 923(defun mh-insert-x-mailer ()
bdcfe844
BW
924 "Append an X-Mailer field to the header.
925The versions of MH-E, Emacs, and MH are shown."
a1b4049d 926 ;; Lazily initialize mh-x-mailer-string.
a66894d8 927 (when (and mh-insert-x-mailer-flag (null mh-x-mailer-string))
f0d73c14
BW
928 (setq mh-x-mailer-string
929 (format "MH-E %s; %s; %sEmacs %s"
930 mh-version mh-variant-in-use
931 (if mh-xemacs-flag "X" "GNU ")
d5468dff
BW
932 (cond ((not mh-xemacs-flag)
933 (string-match "[0-9]+\\.[0-9]+\\(\\.[0-9]+\\)?"
934 emacs-version)
935 (match-string 0 emacs-version))
f0d73c14
BW
936 ((string-match "[0-9.]*\\( +\([ a-z]+[0-9]+\)\\)?"
937 emacs-version)
938 (match-string 0 emacs-version))
939 (t (format "%s.%s" emacs-major-version
940 emacs-minor-version))))))
a1b4049d
BW
941 ;; Insert X-Mailer, but only if it doesn't already exist.
942 (save-excursion
a66894d8
BW
943 (when (and mh-insert-x-mailer-flag
944 (null (mh-goto-header-field "X-Mailer")))
c3d9274a 945 (mh-insert-fields "X-Mailer:" mh-x-mailer-string))))
a1b4049d 946
dda00b2c
BW
947(defun mh-insert-x-face ()
948 "Append X-Face, Face or X-Image-URL field to header.
949If the field already exists, this function does nothing."
950 (when (and (file-exists-p mh-x-face-file)
951 (file-readable-p mh-x-face-file))
952 (save-excursion
953 (unless (or (mh-position-on-field "X-Face")
954 (mh-position-on-field "Face")
955 (mh-position-on-field "X-Image-URL"))
956 (save-excursion
957 (goto-char (+ (point) (cadr (insert-file-contents mh-x-face-file))))
958 (if (not (looking-at "^"))
959 (insert "\n")))
960 (unless (looking-at "\\(X-Face\\|Face\\|X-Image-URL\\): ")
961 (insert "X-Face: "))))))
962
dda00b2c
BW
963(defun mh-tidy-draft-buffer ()
964 "Run when a draft buffer is destroyed."
965 (let ((buffer (get-buffer mh-recipients-buffer)))
966 (if buffer
967 (kill-buffer buffer))))
968
969(defun mh-letter-mode-message ()
970 "Display a help message for users of `mh-letter-mode'.
971This should be the last function called when composing the draft."
972 (message "%s" (substitute-command-keys
973 (concat "Type \\[mh-send-letter] to send message, "
974 "\\[mh-help] for help"))))
975
976(defun mh-letter-adjust-point ()
977 "Move cursor to first header field if are using the no prompt mode."
978 (unless mh-compose-prompt-flag
979 (goto-char (point-max))
980 (mh-letter-next-header-field)))
981
aad5673d
SG
982(defun mh-annotate-msg (msg folder note &rest args)
983 "Mark MSG in FOLDER with character NOTE and annotate message with ARGS.
984MSG can be a message number, a list of message numbers, or a sequence.
985The hook `mh-annotate-msg-hook' is run after annotating; see its
986documentation for variables it can use."
987 (apply 'mh-exec-cmd "anno" folder
dda00b2c
BW
988 (if (listp msg) (append msg args) (cons msg args)))
989 (save-excursion
aad5673d
SG
990 (cond ((get-buffer folder) ; Buffer may be deleted
991 (set-buffer folder)
dda00b2c
BW
992 (mh-iterate-on-range nil msg
993 (mh-notate nil note
aad5673d
SG
994 (+ mh-cmd-note mh-scan-field-destination-offset))))))
995 (let ((mh-current-folder folder)
996 ;; mh-annotate-list is a sequence name or a list of message numbers
997 (mh-annotate-list (if (numberp msg) (list msg) msg)))
998 (run-hooks 'mh-annotate-msg-hook)))
dda00b2c 999
dda00b2c
BW
1000(defun mh-insert-header-separator ()
1001 "Insert `mh-mail-header-separator', if absent."
1002 (save-excursion
1003 (goto-char (point-min))
1004 (rfc822-goto-eoh)
1005 (if (looking-at "$")
1006 (insert mh-mail-header-separator))))
bdcfe844 1007
a66894d8
BW
1008;;;###mh-autoload
1009(defun mh-insert-auto-fields (&optional non-interactive)
3b463df0 1010 "Insert custom fields if recipient is found in `mh-auto-fields-list'.
a66894d8 1011
3fbc098d
BW
1012Once the header contains one or more recipients, you may run this
1013command to insert these fields manually. However, if you use this
1014command, the automatic insertion when the message is sent is
1015disabled.
f0d73c14 1016
3fbc098d
BW
1017In a program, set buffer-local `mh-insert-auto-fields-done-local'
1018if header fields were added. If NON-INTERACTIVE is non-nil,
1019perform actions quietly and only if
1020`mh-insert-auto-fields-done-local' is nil. Return t if fields
1021added; otherwise return nil."
a66894d8 1022 (interactive)
f0d73c14
BW
1023 (when (or (not non-interactive)
1024 (not mh-insert-auto-fields-done-local))
a66894d8 1025 (save-excursion
f0d73c14
BW
1026 (when (and (or (mh-goto-header-field "To:")
1027 (mh-goto-header-field "cc:")))
1028 (let ((list mh-auto-fields-list)
1029 (fields-inserted nil))
a66894d8
BW
1030 (while list
1031 (let ((regexp (nth 0 (car list)))
1032 (entries (nth 1 (car list))))
1033 (when (mh-regexp-in-field-p regexp "To:" "cc:")
1034 (setq mh-insert-auto-fields-done-local t)
f0d73c14 1035 (setq fields-inserted t)
a66894d8 1036 (if (not non-interactive)
f0d73c14 1037 (message "Fields for %s added" regexp))
a66894d8
BW
1038 (let ((entry-list entries))
1039 (while entry-list
1040 (let ((field (caar entry-list))
1041 (value (cdar entry-list)))
1042 (cond
f0d73c14 1043 ((equal ":identity" field)
dda00b2c
BW
1044 (when
1045 ;;(and (not mh-identity-local)
a05fcb7d 1046 ;; Bug 1204506. But do we need to be able
dda00b2c
BW
1047 ;; to set an identity manually that won't be
1048 ;; overridden by mh-insert-auto-fields?
1049 (assoc value mh-identity-list)
1050 ;;)
a66894d8
BW
1051 (mh-insert-identity value)))
1052 (t
1053 (mh-modify-header-field field value
1054 (equal field "From")))))
1055 (setq entry-list (cdr entry-list))))))
f0d73c14
BW
1056 (setq list (cdr list)))
1057 fields-inserted)))))
924df208
BW
1058
1059(defun mh-modify-header-field (field value &optional overwrite-flag)
1060 "To header FIELD add VALUE.
2dcf34f9
BW
1061If OVERWRITE-FLAG is non-nil then the old value, if present, is
1062discarded."
a66894d8
BW
1063 (cond ((and overwrite-flag
1064 (mh-goto-header-field (concat field ":")))
1065 (insert " " value)
d5dc8c56 1066 (delete-region (point) (mh-line-end-position)))
a66894d8
BW
1067 ((and (not overwrite-flag)
1068 (mh-regexp-in-field-p (concat "\\b" value "\\b") field))
1069 ;; Already there, do nothing.
1070 )
1071 ((and (not overwrite-flag)
1072 (mh-goto-header-field (concat field ":")))
1073 (insert " " value ","))
1074 (t
1075 (mh-goto-header-end 0)
1076 (insert field ": " value "\n"))))
1077
dda00b2c
BW
1078(defun mh-regexp-in-field-p (regexp &rest fields)
1079 "Non-nil means REGEXP was found in FIELDS."
1080 (save-excursion
1081 (let ((search-result nil)
1082 (field))
1083 (while fields
1084 (setq field (car fields))
1085 (if (and (mh-goto-header-field field)
1086 (re-search-forward
1087 regexp (save-excursion (mh-header-field-end)(point)) t))
1088 (setq fields nil
1089 search-result t)
1090 (setq fields (cdr fields))))
1091 search-result)))
f0d73c14
BW
1092
1093(defun mh-ascii-buffer-p ()
1094 "Check if current buffer is entirely composed of ASCII.
2dcf34f9
BW
1095The function doesn't work for XEmacs since `find-charset-region'
1096doesn't exist there."
f0d73c14
BW
1097 (loop for charset in (mh-funcall-if-exists
1098 find-charset-region (point-min) (point-max))
1099 unless (eq charset 'ascii) return nil
1100 finally return t))
c26cf6c8 1101
bdcfe844
BW
1102(provide 'mh-comp)
1103
cee9f5c6
BW
1104;; Local Variables:
1105;; indent-tabs-mode: nil
1106;; sentence-end-double-space: nil
1107;; End:
60370d40 1108
cee9f5c6 1109;; arch-tag: 62865511-e610-4923-b0b5-f45a8ab70a34
60370d40 1110;;; mh-comp.el ends here