Switch to recommended form of GPLv3 permissions notice.
[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
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)
0103690e
BW
298 (mh-exec-cmd-output mh-send-prog t
299 "-nodraftfolder" "-watch" "-nopush"
300 (split-string mh-send-args) file-name)
dda00b2c
BW
301 (goto-char (point-max)) ; show the interesting part
302 (recenter -1)
303 (set-buffer draft-buffer)) ; for annotation below
304 (t
0103690e
BW
305 (mh-exec-cmd-daemon mh-send-prog nil
306 "-nodraftfolder" "-noverbose"
16b9a476 307 (split-string mh-send-args) file-name)))
dda00b2c
BW
308 (if mh-annotate-char
309 (mh-annotate-msg mh-sent-from-msg
310 mh-sent-from-folder
311 mh-annotate-char
312 "-component" mh-annotate-field
313 "-text" (format "\"%s %s\""
314 (mh-get-header-field "To:")
315 (mh-get-header-field "Cc:"))))
316
317 (cond ((or (not arg)
318 (y-or-n-p "Kill draft buffer? "))
319 (kill-buffer draft-buffer)
320 (if config
321 (set-window-configuration config))))
322 (if arg
323 (message "Sending...done")
324 (message "Sending...backgrounded"))))
325
326;;;###autoload
327(defun mh-fully-kill-draft ()
328 "Quit editing and delete draft message.
329
330If for some reason you are not happy with the draft, you can use
331this command to kill the draft buffer and delete the draft
332message. Use the command \\[kill-buffer] if you don't want to
333delete the draft message."
334 (interactive)
335 (if (y-or-n-p "Kill draft message? ")
336 (let ((config mh-previous-window-config))
337 (if (file-exists-p buffer-file-name)
338 (delete-file buffer-file-name))
339 (set-buffer-modified-p nil)
340 (kill-buffer (buffer-name))
341 (message "")
342 (if config
343 (set-window-configuration config)))
344 (error "Message not killed")))
345
346\f
347
348;;; MH-Folder Commands
349
350;; Alphabetical.
351
c3d9274a 352;;;###mh-autoload
b2064e08
BW
353(defun mh-edit-again (message)
354 "Edit a MESSAGE to send it again.
355
2dcf34f9
BW
356If you don't complete a draft for one reason or another, and if
357the draft buffer is no longer available, you can pick your draft
358up again with this command. If you don't use a draft folder, your
359last \"draft\" file will be used. If you use draft folders,
360you'll need to visit the draft folder with \"\\[mh-visit-folder]
361drafts <RET>\", use \\[mh-next-undeleted-msg] to move to the
362appropriate message, and then use \\[mh-edit-again] to prepare
363the message for editing.
b2064e08 364
2dcf34f9
BW
365This command can also be used to take messages that were sent to
366you and to send them to more people.
b2064e08 367
2dcf34f9
BW
368Don't use this command to re-edit a message from a Mailer-Daemon
369who complained that your mail wasn't posted for some reason or
370another (see `mh-extract-rejected-mail').
b2064e08
BW
371
372The default message is the current message.
f0d73c14
BW
373
374See also `mh-send'."
c26cf6c8
RS
375 (interactive (list (mh-get-msg-num t)))
376 (let* ((from-folder mh-current-folder)
c3d9274a
BW
377 (config (current-window-configuration))
378 (draft
379 (cond ((and mh-draft-folder (equal from-folder mh-draft-folder))
b2064e08
BW
380 (pop-to-buffer (find-file-noselect (mh-msg-filename message))
381 t)
382 (rename-buffer (format "draft-%d" message))
bdcfe844
BW
383 ;; Make buffer writable...
384 (setq buffer-read-only nil)
385 ;; If buffer was being used to display the message reinsert
386 ;; from file...
387 (when (eq major-mode 'mh-show-mode)
388 (erase-buffer)
389 (insert-file-contents buffer-file-name))
c3d9274a
BW
390 (buffer-name))
391 (t
b2064e08 392 (mh-read-draft "clean-up" (mh-msg-filename message) nil)))))
c26cf6c8 393 (mh-clean-msg-header (point-min) mh-new-draft-cleaned-headers nil)
a1b4049d 394 (mh-insert-header-separator)
c26cf6c8 395 (goto-char (point-min))
283b03f4 396 (save-buffer)
c26cf6c8 397 (mh-compose-and-send-mail draft "" from-folder nil nil nil nil nil nil
c3d9274a 398 config)
a66894d8
BW
399 (mh-letter-mode-message)
400 (mh-letter-adjust-point)))
c26cf6c8 401
c3d9274a 402;;;###mh-autoload
b2064e08
BW
403(defun mh-extract-rejected-mail (message)
404 "Edit a MESSAGE that was returned by the mail system.
405
2dcf34f9
BW
406This command prepares the message for editing by removing the
407Mailer-Daemon envelope and unneeded header fields. Fix whatever
408addressing problem you had, and send the message again with
409\\[mh-send-letter].
b2064e08
BW
410
411The default message is the current message.
f0d73c14
BW
412
413See also `mh-send'."
c26cf6c8
RS
414 (interactive (list (mh-get-msg-num t)))
415 (let ((from-folder mh-current-folder)
c3d9274a 416 (config (current-window-configuration))
b2064e08 417 (draft (mh-read-draft "extraction" (mh-msg-filename message) nil)))
c26cf6c8
RS
418 (goto-char (point-min))
419 (cond ((re-search-forward mh-rejected-letter-start nil t)
c3d9274a
BW
420 (skip-chars-forward " \t\n")
421 (delete-region (point-min) (point))
422 (mh-clean-msg-header (point-min) mh-new-draft-cleaned-headers nil))
423 (t
f0d73c14 424 (message "Does not appear to be a rejected letter")))
a1b4049d 425 (mh-insert-header-separator)
c26cf6c8 426 (goto-char (point-min))
283b03f4 427 (save-buffer)
b2064e08 428 (mh-compose-and-send-mail draft "" from-folder message
c3d9274a
BW
429 (mh-get-header-field "To:")
430 (mh-get-header-field "From:")
431 (mh-get-header-field "Cc:")
432 nil nil config)
bdcfe844 433 (mh-letter-mode-message)))
c26cf6c8 434
c3d9274a 435;;;###mh-autoload
a66894d8 436(defun mh-forward (to cc &optional range)
2be362c2 437 "Forward message.
a66894d8 438
2dcf34f9
BW
439You are prompted for the TO and CC recipients. You are given a
440draft to edit that looks like it would if you had run the MH
441command \"forw\". You can then add some text.
bdcfe844 442
2dcf34f9
BW
443You can forward several messages by using a RANGE. All of the
444messages in the range are inserted into your draft. Check the
445documentation of `mh-interactive-range' to see how RANGE is read
446in interactive use.
b2064e08 447
d1699462
BW
448The hook `mh-forward-hook' is called on the draft.
449
450See also `mh-compose-forward-as-mime-flag',
451`mh-forward-subject-format', and `mh-send'."
a66894d8
BW
452 (interactive (list (mh-interactive-read-address "To: ")
453 (mh-interactive-read-address "Cc: ")
454 (mh-interactive-range "Forward")))
c26cf6c8 455 (let* ((folder mh-current-folder)
a66894d8 456 (msgs (mh-range-to-msg-list range))
c3d9274a
BW
457 (config (current-window-configuration))
458 (fwd-msg-file (mh-msg-filename (car msgs) folder))
459 ;; forw always leaves file in "draft" since it doesn't have -draft
460 (draft-name (expand-file-name "draft" mh-user-path))
461 (draft (cond ((or (not (file-exists-p draft-name))
00b6a079 462 (y-or-n-p "The file draft exists; discard it? "))
f0d73c14
BW
463 (mh-exec-cmd "forw" "-build"
464 (if (and (mh-variant-p 'nmh)
465 mh-compose-forward-as-mime-flag)
466 "-mime")
924df208
BW
467 mh-current-folder
468 (mh-coalesce-msg-list msgs))
c3d9274a
BW
469 (prog1
470 (mh-read-draft "" draft-name t)
471 (mh-insert-fields "To:" to "Cc:" cc)
472 (save-buffer)))
473 (t
474 (mh-read-draft "" draft-name nil)))))
847b8219 475 (let (orig-from
c3d9274a 476 orig-subject)
41b9a988 477 (save-excursion
c3d9274a
BW
478 (set-buffer (get-buffer-create mh-temp-buffer))
479 (erase-buffer)
480 (insert-file-contents fwd-msg-file)
481 (setq orig-from (mh-get-header-field "From:"))
482 (setq orig-subject (mh-get-header-field "Subject:")))
c26cf6c8 483 (let ((forw-subject
924df208 484 (mh-forwarded-letter-subject orig-from orig-subject)))
c3d9274a
BW
485 (mh-insert-fields "Subject:" forw-subject)
486 (goto-char (point-min))
0c47b17c
BW
487 ;; If using MML, translate MH-style directive
488 (if (equal mh-compose-insertion 'mml)
c3d9274a 489 (save-excursion
a66894d8 490 (goto-char (mh-mail-header-end))
c3d9274a
BW
491 (while
492 (re-search-forward
493 "^#forw \\[\\([^]]+\\)\\] \\(+\\S-+\\) \\(.*\\)$"
494 (point-max) t)
495 (let ((description (if (equal (match-string 1)
496 "forwarded messages")
497 "forwarded message %d"
498 (match-string 1)))
499 (msgs (split-string (match-string 3)))
500 (i 0))
501 (beginning-of-line)
502 (delete-region (point) (progn (forward-line 1) (point)))
503 (dolist (msg msgs)
504 (setq i (1+ i))
505 (mh-mml-forward-message (format description i)
d5926104
JH
506 folder msg)
507 ;; Was inserted before us, move to end of file to preserve order
508 (goto-char (point-max)))))))
c3d9274a
BW
509 ;; Postition just before forwarded message
510 (if (re-search-forward "^------- Forwarded Message" nil t)
511 (forward-line -1)
a66894d8 512 (goto-char (mh-mail-header-end))
c3d9274a
BW
513 (forward-line 1))
514 (delete-other-windows)
515 (mh-add-msgs-to-seq msgs 'forwarded t)
924df208 516 (mh-compose-and-send-mail draft "" folder msgs
c3d9274a
BW
517 to forw-subject cc
518 mh-note-forw "Forwarded:"
519 config)
a66894d8 520 (mh-letter-mode-message)
f0d73c14
BW
521 (mh-letter-adjust-point)
522 (run-hooks 'mh-forward-hook)))))
c26cf6c8
RS
523
524(defun mh-forwarded-letter-subject (from subject)
bdcfe844
BW
525 "Return a Subject suitable for a forwarded message.
526Original message has headers FROM and SUBJECT."
c26cf6c8 527 (let ((addr-start (string-match "<" from))
c3d9274a 528 (comment (string-match "(" from)))
c26cf6c8 529 (cond ((and addr-start (> addr-start 0))
c3d9274a
BW
530 ;; Full Name <luser@host>
531 (setq from (substring from 0 (1- addr-start))))
532 (comment
533 ;; luser@host (Full Name)
534 (setq from (substring from (1+ comment) (1- (length from)))))))
c26cf6c8
RS
535 (format mh-forward-subject-format from subject))
536
b2064e08
BW
537;;;###mh-autoload
538(defun mh-redistribute (to cc &optional message)
539 "Redistribute a message.
847b8219 540
2dcf34f9
BW
541This command is similar in function to forwarding mail, but it
542does not allow you to edit the message, nor does it add your name
543to the \"From\" header field. It appears to the recipient as if
544the message had come from the original sender. When you run this
545command, you are prompted for the TO and CC recipients. The
546default MESSAGE is the current message.
c26cf6c8 547
af435184 548Also investigate the command \\[mh-edit-again] for another way to
2dcf34f9 549redistribute messages.
b2064e08
BW
550
551See also `mh-redist-full-contents-flag'."
c26cf6c8 552 (interactive (list (mh-read-address "Redist-To: ")
c3d9274a
BW
553 (mh-read-address "Redist-Cc: ")
554 (mh-get-msg-num t)))
b2064e08
BW
555 (or message
556 (setq message (mh-get-msg-num t)))
c26cf6c8
RS
557 (save-window-excursion
558 (let ((folder mh-current-folder)
c3d9274a 559 (draft (mh-read-draft "redistribution"
b2064e08
BW
560 (if mh-redist-full-contents-flag
561 (mh-msg-filename message)
c3d9274a
BW
562 nil)
563 nil)))
c26cf6c8
RS
564 (mh-goto-header-end 0)
565 (insert "Resent-To: " to "\n")
566 (if (not (equal cc "")) (insert "Resent-cc: " cc "\n"))
924df208
BW
567 (mh-clean-msg-header
568 (point-min)
569 "^Message-Id:\\|^Received:\\|^Return-Path:\\|^Sender:\\|^Date:\\|^From:"
570 nil)
c26cf6c8
RS
571 (save-buffer)
572 (message "Redistributing...")
924df208
BW
573 (let ((env "mhdist=1"))
574 ;; Setup environment...
b2064e08
BW
575 (setq env (concat env " mhaltmsg="
576 (if mh-redist-full-contents-flag
577 buffer-file-name
578 (mh-msg-filename message folder))))
579 (unless mh-redist-full-contents-flag
924df208
BW
580 (setq env (concat env " mhannotate=1")))
581 ;; Redistribute...
582 (if mh-redist-background
583 (mh-exec-cmd-env-daemon env mh-send-prog nil buffer-file-name)
584 (mh-exec-cmd-error env mh-send-prog "-push" buffer-file-name))
585 ;; Annotate...
b2064e08 586 (mh-annotate-msg message folder mh-note-dist
924df208
BW
587 "-component" "Resent:"
588 "-text" (format "\"%s %s\"" to cc)))
c26cf6c8
RS
589 (kill-buffer draft)
590 (message "Redistributing...done"))))
591
c3d9274a 592;;;###mh-autoload
bdcfe844 593(defun mh-reply (message &optional reply-to includep)
b2064e08 594 "Reply to a MESSAGE.
f0d73c14 595
2dcf34f9
BW
596When you reply to a message, you are first prompted with \"Reply
597to whom?\" (unless the optional argument REPLY-TO is provided).
598You have several choices here.
b2064e08
BW
599
600 Response Reply Goes To
601
72cf2f2e 602 from The person who sent the message. This is the
2dcf34f9 603 default, so <RET> is sufficient.
b2064e08
BW
604
605 to Replies to the sender, plus all recipients in the
606 \"To:\" header field.
607
72cf2f2e
BW
608 all cc Forms a reply to the addresses in the
609 \"Mail-Followup-To:\" header field if one
610 exists; otherwise forms a reply to the sender,
611 plus all recipients.
b2064e08 612
2dcf34f9
BW
613Depending on your answer, \"repl\" is given a different argument
614to form your reply. Specifically, a choice of \"from\" or none at
615all runs \"repl -nocc all\", and a choice of \"to\" runs \"repl
616-cc to\". Finally, either \"cc\" or \"all\" runs \"repl -cc all
617-nocc me\".
b2064e08 618
2dcf34f9
BW
619Two windows are then created. One window contains the message to
620which you are replying in an MH-Show buffer. Your draft, in
72cf2f2e
BW
621MH-Letter mode (*note `mh-letter-mode'), is in the other window.
622If the reply draft was not one that you expected, check the
623things that affect the behavior of \"repl\" which include the
624\"repl:\" profile component and the \"replcomps\" and
625\"replgroupcomps\" files.
b2064e08 626
2dcf34f9
BW
627If you supply a prefix argument INCLUDEP, the message you are
628replying to is inserted in your reply after having first been run
629through \"mhl\" with the format file \"mhl.reply\".
b2064e08 630
2dcf34f9
BW
631Alternatively, you can customize the option `mh-yank-behavior'
632and choose one of its \"Automatically\" variants to do the same
633thing. If you do so, the prefix argument has no effect.
b2064e08 634
2dcf34f9
BW
635Another way to include the message automatically in your draft is
636to use \"repl: -filter repl.filter\" in your MH profile.
b2064e08 637
2dcf34f9
BW
638If you wish to customize the header or other parts of the reply
639draft, please see \"repl\" and \"mh-format\".
b2064e08 640
2dcf34f9
BW
641See also `mh-reply-show-message-flag',
642`mh-reply-default-reply-to', and `mh-send'."
bdcfe844
BW
643 (interactive (list
644 (mh-get-msg-num t)
645 (let ((minibuffer-help-form
646 "from => Sender only\nto => Sender and primary recipients\ncc or all => Sender and all recipients"))
647 (or mh-reply-default-reply-to
078cb314 648 (completing-read "Reply to whom (default from): "
bdcfe844
BW
649 '(("from") ("to") ("cc") ("all"))
650 nil
651 t)))
652 current-prefix-arg))
653 (let* ((folder mh-current-folder)
654 (show-buffer mh-show-buffer)
655 (config (current-window-configuration))
656 (group-reply (or (equal reply-to "cc") (equal reply-to "all")))
f0d73c14 657 (form-file (cond ((and (mh-variant-p 'nmh 'mu-mh) group-reply
bdcfe844
BW
658 (stringp mh-repl-group-formfile))
659 mh-repl-group-formfile)
660 ((stringp mh-repl-formfile) mh-repl-formfile)
661 (t nil))))
662 (message "Composing a reply...")
663 (mh-exec-cmd "repl" "-build" "-noquery" "-nodraftfolder"
664 (if form-file
665 (list "-form" form-file))
666 mh-current-folder message
667 (cond ((or (equal reply-to "from") (equal reply-to ""))
668 '("-nocc" "all"))
669 ((equal reply-to "to")
670 '("-cc" "to"))
f0d73c14 671 (group-reply (if (mh-variant-p 'nmh 'mu-mh)
bdcfe844
BW
672 '("-group" "-nocc" "me")
673 '("-cc" "all" "-nocc" "me"))))
0c47b17c
BW
674 (cond ((or (eq mh-yank-behavior 'autosupercite)
675 (eq mh-yank-behavior 'autoattrib))
c3d9274a
BW
676 '("-noformat"))
677 (includep '("-filter" "mhl.reply"))
678 (t '())))
bdcfe844
BW
679 (let ((draft (mh-read-draft "reply"
680 (expand-file-name "reply" mh-user-path)
681 t)))
682 (delete-other-windows)
683 (save-buffer)
a1506d29 684
bdcfe844
BW
685 (let ((to (mh-get-header-field "To:"))
686 (subject (mh-get-header-field "Subject:"))
687 (cc (mh-get-header-field "Cc:")))
688 (goto-char (point-min))
689 (mh-goto-header-end 1)
690 (or includep
691 (not mh-reply-show-message-flag)
692 (mh-in-show-buffer (show-buffer)
693 (mh-display-msg message folder)))
694 (mh-add-msgs-to-seq message 'answered t)
695 (message "Composing a reply...done")
696 (mh-compose-and-send-mail draft "" folder message to subject cc
697 mh-note-repl "Replied:" config))
0c47b17c
BW
698 (when (and (or (eq 'autosupercite mh-yank-behavior)
699 (eq 'autoattrib mh-yank-behavior))
bdcfe844
BW
700 (eq (mh-show-buffer-message-number) mh-sent-from-msg))
701 (undo-boundary)
702 (mh-yank-cur-msg))
703 (mh-letter-mode-message))))
c26cf6c8 704
c3d9274a 705;;;###mh-autoload
c26cf6c8 706(defun mh-send (to cc subject)
b2064e08
BW
707 "Compose a message.
708
2dcf34f9
BW
709Your letter appears in an Emacs buffer whose mode is
710MH-Letter (see `mh-letter-mode').
b2064e08 711
2dcf34f9
BW
712The arguments TO, CC, and SUBJECT can be used to prefill the
713draft fields or suppress the prompts if `mh-compose-prompt-flag'
714is on. They are also passed to the function set in the option
715`mh-compose-letter-function'.
b2064e08
BW
716
717See also `mh-insert-x-mailer-flag' and `mh-letter-mode-hook'.
718
2dcf34f9
BW
719Outside of an MH-Folder buffer (`mh-folder-mode'), you must call
720either \\[mh-smail] or \\[mh-smail-other-window] to compose a new
721message."
c26cf6c8 722 (interactive (list
a66894d8
BW
723 (mh-interactive-read-address "To: ")
724 (mh-interactive-read-address "Cc: ")
725 (mh-interactive-read-string "Subject: ")))
c26cf6c8
RS
726 (let ((config (current-window-configuration)))
727 (delete-other-windows)
728 (mh-send-sub to cc subject config)))
729
dda00b2c
BW
730\f
731
732;;; Support Routines
733
734(defun mh-interactive-read-address (prompt)
735 "Read an address.
736If `mh-compose-prompt-flag' is non-nil, then read an address with
737PROMPT.
738Otherwise return the empty string."
739 (if mh-compose-prompt-flag (mh-read-address prompt) ""))
740
741(defun mh-interactive-read-string (prompt)
742 "Read a string.
743If `mh-compose-prompt-flag' is non-nil, then read a string with
744PROMPT.
745Otherwise return the empty string."
746 (if mh-compose-prompt-flag (read-string prompt) ""))
747
c3d9274a 748;;;###mh-autoload
dda00b2c
BW
749(defun mh-show-buffer-message-number (&optional buffer)
750 "Message number of displayed message in corresponding show buffer.
b2064e08 751
dda00b2c
BW
752Return nil if show buffer not displayed.
753If in `mh-letter-mode', don't display the message number being replied
754to, but rather the message number of the show buffer associated with
755our originating folder buffer.
756Optional argument BUFFER can be used to specify the buffer."
757 (save-excursion
758 (if buffer
759 (set-buffer buffer))
760 (cond ((eq major-mode 'mh-show-mode)
761 (let ((number-start (mh-search-from-end ?/ buffer-file-name)))
762 (string-to-number (substring buffer-file-name
763 (1+ number-start)))))
764 ((and (eq major-mode 'mh-folder-mode)
765 mh-show-buffer
766 (get-buffer mh-show-buffer))
767 (mh-show-buffer-message-number mh-show-buffer))
768 ((and (eq major-mode 'mh-letter-mode)
769 mh-sent-from-folder
770 (get-buffer mh-sent-from-folder))
771 (mh-show-buffer-message-number mh-sent-from-folder))
772 (t
773 nil))))
c26cf6c8 774
c26cf6c8 775(defun mh-send-sub (to cc subject config)
bdcfe844
BW
776 "Do the real work of composing and sending a letter.
777Expects the TO, CC, and SUBJECT fields as arguments.
778CONFIG is the window configuration before sending mail."
c26cf6c8 779 (let ((folder mh-current-folder)
c3d9274a 780 (msg-num (mh-get-msg-num nil)))
c26cf6c8
RS
781 (message "Composing a message...")
782 (let ((draft (mh-read-draft
c3d9274a
BW
783 "message"
784 (let (components)
785 (cond
786 ((file-exists-p
787 (setq components
788 (expand-file-name mh-comp-formfile mh-user-path)))
789 components)
790 ((file-exists-p
791 (setq components
792 (expand-file-name mh-comp-formfile mh-lib)))
793 components)
c3d9274a 794 (t
05227fbe
BW
795 (error "Can't find %s in %s or %s"
796 mh-comp-formfile mh-user-path mh-lib))))
c3d9274a 797 nil)))
c26cf6c8
RS
798 (mh-insert-fields "To:" to "Subject:" subject "Cc:" cc)
799 (goto-char (point-max))
c26cf6c8 800 (mh-compose-and-send-mail draft "" folder msg-num
c3d9274a
BW
801 to subject cc
802 nil nil config)
a66894d8
BW
803 (mh-letter-mode-message)
804 (mh-letter-adjust-point))))
c26cf6c8
RS
805
806(defun mh-read-draft (use initial-contents delete-contents-file)
bdcfe844 807 "Read draft file into a draft buffer and make that buffer the current one.
2dcf34f9
BW
808
809USE is a message used for prompting about the intended use of the
810message.
bdcfe844 811INITIAL-CONTENTS is filename that is read into an empty buffer, or nil
2dcf34f9 812if buffer should not be modified. Delete the initial-contents file if
bdcfe844
BW
813DELETE-CONTENTS-FILE flag is set.
814Returns the draft folder's name.
2dcf34f9
BW
815If the draft folder facility is enabled in ~/.mh_profile, a new buffer
816is used each time and saved in the draft folder. The draft file can
817then be reused."
c26cf6c8 818 (cond (mh-draft-folder
c3d9274a
BW
819 (let ((orig-default-dir default-directory)
820 (draft-file-name (mh-new-draft-name)))
821 (pop-to-buffer (generate-new-buffer
822 (format "draft-%s"
823 (file-name-nondirectory draft-file-name))))
824 (condition-case ()
825 (insert-file-contents draft-file-name t)
826 (file-error))
827 (setq default-directory orig-default-dir)))
828 (t
829 (let ((draft-name (expand-file-name "draft" mh-user-path)))
830 (pop-to-buffer "draft") ; Create if necessary
831 (if (buffer-modified-p)
832 (if (y-or-n-p "Draft has been modified; kill anyway? ")
833 (set-buffer-modified-p nil)
834 (error "Draft preserved")))
835 (setq buffer-file-name draft-name)
836 (clear-visited-file-modtime)
837 (unlock-buffer)
838 (cond ((and (file-exists-p draft-name)
839 (not (equal draft-name initial-contents)))
840 (insert-file-contents draft-name)
841 (delete-file draft-name))))))
c26cf6c8 842 (cond ((and initial-contents
c3d9274a
BW
843 (or (zerop (buffer-size))
844 (if (y-or-n-p
845 (format "A draft exists. Use for %s? " use))
846 (if mh-error-if-no-draft
847 (error "A prior draft exists"))
848 t)))
849 (erase-buffer)
850 (insert-file-contents initial-contents)
851 (if delete-contents-file (delete-file initial-contents))))
c26cf6c8
RS
852 (auto-save-mode 1)
853 (if mh-draft-folder
c3d9274a 854 (save-buffer)) ; Do not reuse draft name
c26cf6c8
RS
855 (buffer-name))
856
c26cf6c8 857(defun mh-new-draft-name ()
bdcfe844 858 "Return the pathname of folder for draft messages."
c26cf6c8
RS
859 (save-excursion
860 (mh-exec-cmd-quiet t "mhpath" mh-draft-folder "new")
861 (buffer-substring (point-min) (1- (point-max)))))
862
c26cf6c8 863(defun mh-insert-fields (&rest name-values)
bdcfe844
BW
864 "Insert the NAME-VALUES pairs in the current buffer.
865If the field exists, append the value to it.
866Do not insert any pairs whose value is the empty string."
c26cf6c8
RS
867 (let ((case-fold-search t))
868 (while name-values
869 (let ((field-name (car name-values))
c3d9274a 870 (value (car (cdr name-values))))
f0d73c14
BW
871 (if (not (string-match "^.*:$" field-name))
872 (setq field-name (concat field-name ":")))
a2c30782
BW
873 (cond ((or (null value)
874 (equal value ""))
c3d9274a
BW
875 nil)
876 ((mh-position-on-field field-name)
877 (insert " " (or value "")))
878 (t
879 (insert field-name " " value "\n")))
880 (setq name-values (cdr (cdr name-values)))))))
c26cf6c8 881
dda00b2c
BW
882(defun mh-compose-and-send-mail (draft send-args
883 sent-from-folder sent-from-msg
884 to subject cc
885 annotate-char annotate-field
886 config)
887 "Edit and compose a draft message in buffer DRAFT and send or save it.
888SEND-ARGS is the argument passed to the send command.
889SENT-FROM-FOLDER is buffer containing scan listing of current folder,
890or nil if none exists.
891SENT-FROM-MSG is the message number or sequence name or nil.
892The TO, SUBJECT, and CC fields are passed to the
893`mh-compose-letter-function'.
894If ANNOTATE-CHAR is non-null, it is used to notate the scan listing of
895the message. In that case, the ANNOTATE-FIELD is used to build a
896string for `mh-annotate-msg'.
897CONFIG is the window configuration to restore after sending the
898letter."
899 (pop-to-buffer draft)
900 (mh-letter-mode)
847b8219 901
dda00b2c
BW
902 ;; Insert identity.
903 (mh-insert-identity mh-identity-default t)
904 (mh-identity-make-menu)
905 (mh-identity-add-menu)
c26cf6c8 906
dda00b2c
BW
907 ;; Insert extra fields.
908 (mh-insert-x-mailer)
909 (mh-insert-x-face)
c26cf6c8 910
dda00b2c 911 (mh-letter-hide-all-skipped-fields)
924df208 912
dda00b2c
BW
913 (setq mh-sent-from-folder sent-from-folder)
914 (setq mh-sent-from-msg sent-from-msg)
915 (setq mh-send-args send-args)
916 (setq mh-annotate-char annotate-char)
917 (setq mh-annotate-field annotate-field)
918 (setq mh-previous-window-config config)
919 (setq mode-line-buffer-identification (list " {%b}"))
920 (mh-logo-display)
921 (mh-make-local-hook 'kill-buffer-hook)
922 (add-hook 'kill-buffer-hook 'mh-tidy-draft-buffer nil t)
16b9a476 923 (run-hook-with-args 'mh-compose-letter-function to subject cc))
bdcfe844 924
a1b4049d 925(defun mh-insert-x-mailer ()
bdcfe844
BW
926 "Append an X-Mailer field to the header.
927The versions of MH-E, Emacs, and MH are shown."
a1b4049d 928 ;; Lazily initialize mh-x-mailer-string.
a66894d8 929 (when (and mh-insert-x-mailer-flag (null mh-x-mailer-string))
f0d73c14
BW
930 (setq mh-x-mailer-string
931 (format "MH-E %s; %s; %sEmacs %s"
932 mh-version mh-variant-in-use
a3269bc4
DN
933 (if (featurep 'xemacs) "X" "GNU ")
934 (cond ((not (featurep 'xemacs))
d5468dff
BW
935 (string-match "[0-9]+\\.[0-9]+\\(\\.[0-9]+\\)?"
936 emacs-version)
937 (match-string 0 emacs-version))
f0d73c14
BW
938 ((string-match "[0-9.]*\\( +\([ a-z]+[0-9]+\)\\)?"
939 emacs-version)
940 (match-string 0 emacs-version))
941 (t (format "%s.%s" emacs-major-version
942 emacs-minor-version))))))
a1b4049d
BW
943 ;; Insert X-Mailer, but only if it doesn't already exist.
944 (save-excursion
a66894d8
BW
945 (when (and mh-insert-x-mailer-flag
946 (null (mh-goto-header-field "X-Mailer")))
c3d9274a 947 (mh-insert-fields "X-Mailer:" mh-x-mailer-string))))
a1b4049d 948
dda00b2c
BW
949(defun mh-insert-x-face ()
950 "Append X-Face, Face or X-Image-URL field to header.
951If the field already exists, this function does nothing."
952 (when (and (file-exists-p mh-x-face-file)
953 (file-readable-p mh-x-face-file))
954 (save-excursion
955 (unless (or (mh-position-on-field "X-Face")
956 (mh-position-on-field "Face")
957 (mh-position-on-field "X-Image-URL"))
958 (save-excursion
959 (goto-char (+ (point) (cadr (insert-file-contents mh-x-face-file))))
960 (if (not (looking-at "^"))
961 (insert "\n")))
962 (unless (looking-at "\\(X-Face\\|Face\\|X-Image-URL\\): ")
963 (insert "X-Face: "))))))
964
dda00b2c
BW
965(defun mh-tidy-draft-buffer ()
966 "Run when a draft buffer is destroyed."
967 (let ((buffer (get-buffer mh-recipients-buffer)))
968 (if buffer
969 (kill-buffer buffer))))
970
971(defun mh-letter-mode-message ()
972 "Display a help message for users of `mh-letter-mode'.
973This should be the last function called when composing the draft."
974 (message "%s" (substitute-command-keys
975 (concat "Type \\[mh-send-letter] to send message, "
976 "\\[mh-help] for help"))))
977
978(defun mh-letter-adjust-point ()
979 "Move cursor to first header field if are using the no prompt mode."
980 (unless mh-compose-prompt-flag
981 (goto-char (point-max))
982 (mh-letter-next-header-field)))
983
aad5673d
SG
984(defun mh-annotate-msg (msg folder note &rest args)
985 "Mark MSG in FOLDER with character NOTE and annotate message with ARGS.
662c14da 986MSG can be a message number, a list of message numbers, or a sequence.
aad5673d
SG
987The hook `mh-annotate-msg-hook' is run after annotating; see its
988documentation for variables it can use."
989 (apply 'mh-exec-cmd "anno" folder
dda00b2c
BW
990 (if (listp msg) (append msg args) (cons msg args)))
991 (save-excursion
aad5673d
SG
992 (cond ((get-buffer folder) ; Buffer may be deleted
993 (set-buffer folder)
dda00b2c
BW
994 (mh-iterate-on-range nil msg
995 (mh-notate nil note
aad5673d
SG
996 (+ mh-cmd-note mh-scan-field-destination-offset))))))
997 (let ((mh-current-folder folder)
998 ;; mh-annotate-list is a sequence name or a list of message numbers
999 (mh-annotate-list (if (numberp msg) (list msg) msg)))
1000 (run-hooks 'mh-annotate-msg-hook)))
dda00b2c 1001
dda00b2c
BW
1002(defun mh-insert-header-separator ()
1003 "Insert `mh-mail-header-separator', if absent."
1004 (save-excursion
1005 (goto-char (point-min))
1006 (rfc822-goto-eoh)
1007 (if (looking-at "$")
1008 (insert mh-mail-header-separator))))
bdcfe844 1009
a66894d8
BW
1010;;;###mh-autoload
1011(defun mh-insert-auto-fields (&optional non-interactive)
3b463df0 1012 "Insert custom fields if recipient is found in `mh-auto-fields-list'.
a66894d8 1013
3fbc098d
BW
1014Once the header contains one or more recipients, you may run this
1015command to insert these fields manually. However, if you use this
1016command, the automatic insertion when the message is sent is
1017disabled.
f0d73c14 1018
3fbc098d
BW
1019In a program, set buffer-local `mh-insert-auto-fields-done-local'
1020if header fields were added. If NON-INTERACTIVE is non-nil,
1021perform actions quietly and only if
1022`mh-insert-auto-fields-done-local' is nil. Return t if fields
1023added; otherwise return nil."
a66894d8 1024 (interactive)
f0d73c14
BW
1025 (when (or (not non-interactive)
1026 (not mh-insert-auto-fields-done-local))
a66894d8 1027 (save-excursion
f0d73c14
BW
1028 (when (and (or (mh-goto-header-field "To:")
1029 (mh-goto-header-field "cc:")))
1030 (let ((list mh-auto-fields-list)
1031 (fields-inserted nil))
a66894d8
BW
1032 (while list
1033 (let ((regexp (nth 0 (car list)))
1034 (entries (nth 1 (car list))))
1035 (when (mh-regexp-in-field-p regexp "To:" "cc:")
1036 (setq mh-insert-auto-fields-done-local t)
f0d73c14 1037 (setq fields-inserted t)
a66894d8 1038 (if (not non-interactive)
f0d73c14 1039 (message "Fields for %s added" regexp))
a66894d8
BW
1040 (let ((entry-list entries))
1041 (while entry-list
1042 (let ((field (caar entry-list))
1043 (value (cdar entry-list)))
1044 (cond
f0d73c14 1045 ((equal ":identity" field)
dda00b2c
BW
1046 (when
1047 ;;(and (not mh-identity-local)
a05fcb7d 1048 ;; Bug 1204506. But do we need to be able
dda00b2c
BW
1049 ;; to set an identity manually that won't be
1050 ;; overridden by mh-insert-auto-fields?
1051 (assoc value mh-identity-list)
1052 ;;)
a66894d8
BW
1053 (mh-insert-identity value)))
1054 (t
1055 (mh-modify-header-field field value
1056 (equal field "From")))))
1057 (setq entry-list (cdr entry-list))))))
f0d73c14
BW
1058 (setq list (cdr list)))
1059 fields-inserted)))))
924df208
BW
1060
1061(defun mh-modify-header-field (field value &optional overwrite-flag)
1062 "To header FIELD add VALUE.
2dcf34f9
BW
1063If OVERWRITE-FLAG is non-nil then the old value, if present, is
1064discarded."
a66894d8
BW
1065 (cond ((and overwrite-flag
1066 (mh-goto-header-field (concat field ":")))
1067 (insert " " value)
d5dc8c56 1068 (delete-region (point) (mh-line-end-position)))
a66894d8
BW
1069 ((and (not overwrite-flag)
1070 (mh-regexp-in-field-p (concat "\\b" value "\\b") field))
1071 ;; Already there, do nothing.
1072 )
1073 ((and (not overwrite-flag)
1074 (mh-goto-header-field (concat field ":")))
1075 (insert " " value ","))
1076 (t
1077 (mh-goto-header-end 0)
1078 (insert field ": " value "\n"))))
1079
dda00b2c
BW
1080(defun mh-regexp-in-field-p (regexp &rest fields)
1081 "Non-nil means REGEXP was found in FIELDS."
1082 (save-excursion
1083 (let ((search-result nil)
1084 (field))
1085 (while fields
1086 (setq field (car fields))
1087 (if (and (mh-goto-header-field field)
1088 (re-search-forward
1089 regexp (save-excursion (mh-header-field-end)(point)) t))
1090 (setq fields nil
1091 search-result t)
1092 (setq fields (cdr fields))))
1093 search-result)))
f0d73c14
BW
1094
1095(defun mh-ascii-buffer-p ()
1096 "Check if current buffer is entirely composed of ASCII.
2dcf34f9
BW
1097The function doesn't work for XEmacs since `find-charset-region'
1098doesn't exist there."
f0d73c14
BW
1099 (loop for charset in (mh-funcall-if-exists
1100 find-charset-region (point-min) (point-max))
1101 unless (eq charset 'ascii) return nil
1102 finally return t))
c26cf6c8 1103
bdcfe844
BW
1104(provide 'mh-comp)
1105
cee9f5c6
BW
1106;; Local Variables:
1107;; indent-tabs-mode: nil
1108;; sentence-end-double-space: nil
1109;; End:
60370d40 1110
cee9f5c6 1111;; arch-tag: 62865511-e610-4923-b0b5-f45a8ab70a34
60370d40 1112;;; mh-comp.el ends here