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