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