Sync to HEAD
[bpt/emacs.git] / lisp / mh-e / mh-comp.el
CommitLineData
bdcfe844 1;;; mh-comp.el --- MH-E functions for composing messages
c26cf6c8 2
924df208
BW
3;; Copyright (C) 1993, 95, 1997,
4;; 2000, 01, 02, 2003 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
EN
24;; along with GNU Emacs; see the file COPYING. If not, write to the
25;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
26;; Boston, MA 02111-1307, USA.
c26cf6c8
RS
27
28;;; Commentary:
29
bdcfe844 30;; Internal support for MH-E package.
c26cf6c8 31
847b8219
KH
32;;; Change Log:
33
c26cf6c8
RS
34;;; Code:
35
a1b4049d 36(require 'mh-e)
a1b4049d
BW
37(require 'gnus-util)
38(require 'easymenu)
bdcfe844 39(require 'cl)
924df208
BW
40(eval-when (compile load eval)
41 (ignore-errors (require 'mailabbrev)))
bdcfe844
BW
42
43;; Shush the byte-compiler
44(defvar adaptive-fill-first-line-regexp)
45(defvar font-lock-defaults)
46(defvar mark-active)
47(defvar sendmail-coding-system)
c3d9274a
BW
48(defvar mh-identity-list)
49(defvar mh-identity-default)
50(defvar mh-identity-menu)
a1b4049d 51
c3d9274a 52;;; Autoloads
a1b4049d
BW
53(autoload 'Info-goto-node "info")
54(autoload 'mail-mode-fill-paragraph "sendmail")
bdcfe844
BW
55(autoload 'mm-handle-displayed-p "mm-decode")
56
57(autoload 'sc-cite-original "sc"
58 "Workhorse citing function which performs the initial citation.
59This is callable from the various mail and news readers' reply
60function according to the agreed upon standard. See `\\[sc-describe]'
61for more details. `sc-cite-original' does not do any yanking of the
62original message but it does require a few things:
63
64 1) The reply buffer is the current buffer.
65
66 2) The original message has been yanked and inserted into the
67 reply buffer.
68
69 3) Verbose mail headers from the original message have been
70 inserted into the reply buffer directly before the text of the
71 original message.
72
73 4) Point is at the beginning of the verbose headers.
74
75 5) Mark is at the end of the body of text to be cited.
76
77For Emacs 19's, the region need not be active (and typically isn't
78when this function is called. Also, the hook `sc-pre-hook' is run
79before, and `sc-post-hook' is run after the guts of this function.")
c26cf6c8 80
847b8219
KH
81;;; Site customization (see also mh-utils.el):
82
83(defvar mh-send-prog "send"
84 "Name of the MH send program.
85Some sites need to change this because of a name conflict.")
86
87(defvar mh-redist-full-contents nil
88 "Non-nil if the `dist' command needs whole letter for redistribution.
89This is the case only when `send' is compiled with the BERK option.
90If MH will not allow you to redist a previously redist'd msg, set to nil.")
91
a1b4049d
BW
92(defvar mh-redist-background nil
93 "If non-nil redist will be done in background like send.
bdcfe844
BW
94This allows transaction log to be visible if -watch, -verbose or -snoop are
95used.")
847b8219 96
c26cf6c8
RS
97(defvar mh-note-repl "-"
98 "String whose first character is used to notate replied to messages.")
99
100(defvar mh-note-forw "F"
101 "String whose first character is used to notate forwarded messages.")
102
103(defvar mh-note-dist "R"
104 "String whose first character is used to notate redistributed messages.")
105
c26cf6c8
RS
106(defvar mh-yank-hooks nil
107 "Obsolete hook for modifying a citation just inserted in the mail buffer.
108Each hook function can find the citation between point and mark.
109And each hook function should leave point and mark around the citation
110text as modified.
111
112This is a normal hook, misnamed for historical reasons.
1838eb6c 113It is semi-obsolete and is only used if `mail-citation-hook' is nil.")
c26cf6c8
RS
114
115(defvar mail-citation-hook nil
116 "*Hook for modifying a citation just inserted in the mail buffer.
117Each hook function can find the citation between point and mark.
118And each hook function should leave point and mark around the citation
119text as modified.
120
121If this hook is entirely empty (nil), the text of the message is inserted
1838eb6c 122with `mh-ins-buf-prefix' prefixed to each line.
c26cf6c8 123
1838eb6c 124See also the variable `mh-yank-from-start-of-msg', which controls how
bdcfe844
BW
125much of the message passed to the hook.
126
127This hook was historically provided to set up supercite. You may now leave
128this nil and set up supercite by setting the variable
129`mh-yank-from-start-of-msg' to 'supercite or, for more automatic insertion,
130to 'autosupercite.")
c26cf6c8 131
c26cf6c8
RS
132(defvar mh-comp-formfile "components"
133 "Name of file to be used as a skeleton for composing messages.
1838eb6c 134Default is \"components\". If not an absolute file name, the file
c26cf6c8
RS
135is searched for first in the user's MH directory, then in the
136system MH lib directory.")
137
847b8219
KH
138(defvar mh-repl-formfile "replcomps"
139 "Name of file to be used as a skeleton for replying to messages.
1838eb6c 140Default is \"replcomps\". If not an absolute file name, the file
847b8219
KH
141is searched for first in the user's MH directory, then in the
142system MH lib directory.")
143
c3d6278e 144(defvar mh-repl-group-formfile "replgroupcomps"
bdcfe844
BW
145 "Name of file to be used as a skeleton for replying to messages.
146This file is used to form replies to the sender and all recipients of a
147message. Only used if `mh-nmh-flag' is non-nil. Default is \"replgroupcomps\".
148If not an absolute file name, the file is searched for first in the user's MH
149directory, then in the system MH lib directory.")
a1b4049d 150
c26cf6c8 151(defvar mh-rejected-letter-start
bdcfe844 152 (format "^%s$"
c3d9274a
BW
153 (regexp-opt
154 '("Content-Type: message/rfc822" ;MIME MDN
155 " ----- Unsent message follows -----" ;from sendmail V5
156 " --------Unsent Message below:" ; from sendmail at BU
157 " ----- Original message follows -----" ;from sendmail V8
158 "------- Unsent Draft" ;from MH itself
159 "---------- Original Message ----------" ;from zmailer
160 " --- The unsent message follows ---" ;from AIX mail system
161 " Your message follows:" ;from MMDF-II
162 "Content-Description: Returned Content" ;1993 KJ sendmail
163 ))))
c26cf6c8
RS
164
165(defvar mh-new-draft-cleaned-headers
847b8219 166 "^Date:\\|^Received:\\|^Message-Id:\\|^From:\\|^Sender:\\|^Errors-To:\\|^Delivery-Date:\\|^Return-Path:"
c26cf6c8
RS
167 "Regexp of header lines to remove before offering a message as a new draft.
168Used by the \\<mh-folder-mode-map>`\\[mh-edit-again]' and `\\[mh-extract-rejected-mail]' commands.")
169
847b8219 170(defvar mh-to-field-choices '(("t" . "To:") ("s" . "Subject:") ("c" . "Cc:")
c3d9274a
BW
171 ("b" . "Bcc:") ("f" . "Fcc:") ("r" . "From:")
172 ("d" . "Dcc:"))
a1b4049d 173 "Alist of (final-character . field-name) choices for `mh-to-field'.")
c26cf6c8
RS
174
175(defvar mh-letter-mode-map (copy-keymap text-mode-map)
176 "Keymap for composing mail.")
177
178(defvar mh-letter-mode-syntax-table nil
bdcfe844 179 "Syntax table used by MH-E while in MH-Letter mode.")
c26cf6c8
RS
180
181(if mh-letter-mode-syntax-table
182 ()
c3d9274a
BW
183 (setq mh-letter-mode-syntax-table
184 (make-syntax-table text-mode-syntax-table))
185 (modify-syntax-entry ?% "." mh-letter-mode-syntax-table))
c26cf6c8 186
bdcfe844
BW
187(defvar mh-sent-from-folder nil
188 "Folder of msg assoc with this letter.")
189
190(defvar mh-sent-from-msg nil
191 "Number of msg assoc with this letter.")
192
193(defvar mh-send-args nil
194 "Extra args to pass to \"send\" command.")
195
196(defvar mh-annotate-char nil
197 "Character to use to annotate `mh-sent-from-msg'.")
198
199(defvar mh-annotate-field nil
200 "Field name for message annotation.")
c26cf6c8
RS
201
202;;;###autoload
203(defun mh-smail ()
204 "Compose and send mail with the MH mail system.
bdcfe844 205This function is an entry point to MH-E, the Emacs front end
847b8219
KH
206to the MH mail system.
207
208See documentation of `\\[mh-send]' for more details on composing mail."
c26cf6c8
RS
209 (interactive)
210 (mh-find-path)
211 (call-interactively 'mh-send))
212
c3d9274a 213(defvar mh-error-if-no-draft nil) ;raise error over using old draft
283b03f4 214
283b03f4 215;;;###autoload
c3d6278e 216(defun mh-smail-batch (&optional to subject other-headers &rest ignored)
283b03f4 217 "Set up a mail composition draft with the MH mail system.
bdcfe844 218This function is an entry point to MH-E, the Emacs front end
283b03f4
KH
219to the MH mail system. This function does not prompt the user
220for any header fields, and thus is suitable for use by programs
221that want to create a mail buffer.
a1b4049d
BW
222Users should use `\\[mh-smail]' to compose mail.
223Optional arguments for setting certain fields include TO, SUBJECT, and
bdcfe844 224OTHER-HEADERS. Additional arguments are IGNORED."
283b03f4
KH
225 (mh-find-path)
226 (let ((mh-error-if-no-draft t))
016fbe59 227 (mh-send (or to "") "" (or subject ""))))
283b03f4 228
a1b4049d
BW
229;; XEmacs needs this:
230;;;###autoload
231(defun mh-user-agent-compose (&optional to subject other-headers continue
c3d9274a
BW
232 switch-function yank-action
233 send-actions)
a1b4049d 234 "Set up mail composition draft with the MH mail system.
bdcfe844 235This is `mail-user-agent' entry point to MH-E.
a1b4049d
BW
236
237The optional arguments TO and SUBJECT specify recipients and the
238initial Subject field, respectively.
239
240OTHER-HEADERS is an alist specifying additional
241header fields. Elements look like (HEADER . VALUE) where both
242HEADER and VALUE are strings.
243
244CONTINUE, SWITCH-FUNCTION, YANK-ACTION and SEND-ACTIONS are ignored."
245 (mh-find-path)
246 (let ((mh-error-if-no-draft t))
247 (mh-send to "" subject)
248 (while other-headers
249 (mh-insert-fields (concat (car (car other-headers)) ":")
c3d9274a 250 (cdr (car other-headers)))
a1b4049d 251 (setq other-headers (cdr other-headers)))))
283b03f4 252
c3d9274a 253;;;###mh-autoload
c26cf6c8 254(defun mh-edit-again (msg)
a1b4049d 255 "Clean up a draft or a message MSG previously sent and make it resendable.
847b8219 256Default is the current message.
a1b4049d 257The variable `mh-new-draft-cleaned-headers' specifies the headers to remove.
c26cf6c8
RS
258See also documentation for `\\[mh-send]' function."
259 (interactive (list (mh-get-msg-num t)))
260 (let* ((from-folder mh-current-folder)
c3d9274a
BW
261 (config (current-window-configuration))
262 (draft
263 (cond ((and mh-draft-folder (equal from-folder mh-draft-folder))
264 (pop-to-buffer (find-file-noselect (mh-msg-filename msg)) t)
265 (rename-buffer (format "draft-%d" msg))
bdcfe844
BW
266 ;; Make buffer writable...
267 (setq buffer-read-only nil)
268 ;; If buffer was being used to display the message reinsert
269 ;; from file...
270 (when (eq major-mode 'mh-show-mode)
271 (erase-buffer)
272 (insert-file-contents buffer-file-name))
c3d9274a
BW
273 (buffer-name))
274 (t
275 (mh-read-draft "clean-up" (mh-msg-filename msg) nil)))))
c26cf6c8 276 (mh-clean-msg-header (point-min) mh-new-draft-cleaned-headers nil)
a1b4049d 277 (mh-insert-header-separator)
c26cf6c8 278 (goto-char (point-min))
283b03f4 279 (save-buffer)
c26cf6c8 280 (mh-compose-and-send-mail draft "" from-folder nil nil nil nil nil nil
c3d9274a 281 config)
bdcfe844 282 (mh-letter-mode-message)))
c26cf6c8 283
c3d9274a 284;;;###mh-autoload
c26cf6c8 285(defun mh-extract-rejected-mail (msg)
a1b4049d 286 "Extract message MSG returned by the mail system and make it resendable.
1838eb6c 287Default is the current message. The variable `mh-new-draft-cleaned-headers'
c26cf6c8
RS
288gives the headers to clean out of the original message.
289See also documentation for `\\[mh-send]' function."
290 (interactive (list (mh-get-msg-num t)))
291 (let ((from-folder mh-current-folder)
c3d9274a
BW
292 (config (current-window-configuration))
293 (draft (mh-read-draft "extraction" (mh-msg-filename msg) nil)))
c26cf6c8
RS
294 (goto-char (point-min))
295 (cond ((re-search-forward mh-rejected-letter-start nil t)
c3d9274a
BW
296 (skip-chars-forward " \t\n")
297 (delete-region (point-min) (point))
298 (mh-clean-msg-header (point-min) mh-new-draft-cleaned-headers nil))
299 (t
300 (message "Does not appear to be a rejected letter.")))
a1b4049d 301 (mh-insert-header-separator)
c26cf6c8 302 (goto-char (point-min))
283b03f4 303 (save-buffer)
847b8219 304 (mh-compose-and-send-mail draft "" from-folder msg
c3d9274a
BW
305 (mh-get-header-field "To:")
306 (mh-get-header-field "From:")
307 (mh-get-header-field "Cc:")
308 nil nil config)
bdcfe844 309 (mh-letter-mode-message)))
c26cf6c8 310
c3d9274a 311;;;###mh-autoload
c26cf6c8 312(defun mh-forward (to cc &optional msg-or-seq)
924df208
BW
313 "Forward messages to the recipients TO and CC.
314Use optional MSG-OR-SEQ argument to specify a message or sequence to forward.
315Default is the displayed message.
316If optional prefix argument is provided, then prompt for the message sequence.
317If variable `transient-mark-mode' is non-nil and the mark is active, then the
318selected region is forwarded.
319In a program, MSG-OR-SEQ can be a message number, a list of message numbers, a
320region in a cons cell, or a sequence.
bdcfe844 321
bdcfe844 322See also documentation for `\\[mh-send]' function."
c26cf6c8 323 (interactive (list (mh-read-address "To: ")
c3d9274a 324 (mh-read-address "Cc: ")
924df208 325 (mh-interactive-msg-or-seq "Forward")))
c26cf6c8 326 (let* ((folder mh-current-folder)
924df208 327 (msgs (mh-msg-or-seq-to-msg-list msg-or-seq))
c3d9274a
BW
328 (config (current-window-configuration))
329 (fwd-msg-file (mh-msg-filename (car msgs) folder))
330 ;; forw always leaves file in "draft" since it doesn't have -draft
331 (draft-name (expand-file-name "draft" mh-user-path))
332 (draft (cond ((or (not (file-exists-p draft-name))
333 (y-or-n-p "The file 'draft' exists. Discard it? "))
334 (mh-exec-cmd "forw" "-build" (if mh-nmh-flag "-mime")
924df208
BW
335 mh-current-folder
336 (mh-coalesce-msg-list msgs))
c3d9274a
BW
337 (prog1
338 (mh-read-draft "" draft-name t)
339 (mh-insert-fields "To:" to "Cc:" cc)
340 (save-buffer)))
341 (t
342 (mh-read-draft "" draft-name nil)))))
847b8219 343 (let (orig-from
c3d9274a 344 orig-subject)
41b9a988 345 (save-excursion
c3d9274a
BW
346 (set-buffer (get-buffer-create mh-temp-buffer))
347 (erase-buffer)
348 (insert-file-contents fwd-msg-file)
349 (setq orig-from (mh-get-header-field "From:"))
350 (setq orig-subject (mh-get-header-field "Subject:")))
c26cf6c8 351 (let ((forw-subject
924df208 352 (mh-forwarded-letter-subject orig-from orig-subject)))
c3d9274a
BW
353 (mh-insert-fields "Subject:" forw-subject)
354 (goto-char (point-min))
355 ;; If using MML, translate mhn
356 (if (equal mh-compose-insertion 'gnus)
357 (save-excursion
c3d9274a
BW
358 (re-search-forward (format "^\\(%s\\)?$"
359 mh-mail-header-separator))
360 (while
361 (re-search-forward
362 "^#forw \\[\\([^]]+\\)\\] \\(+\\S-+\\) \\(.*\\)$"
363 (point-max) t)
364 (let ((description (if (equal (match-string 1)
365 "forwarded messages")
366 "forwarded message %d"
367 (match-string 1)))
368 (msgs (split-string (match-string 3)))
369 (i 0))
370 (beginning-of-line)
371 (delete-region (point) (progn (forward-line 1) (point)))
372 (dolist (msg msgs)
373 (setq i (1+ i))
374 (mh-mml-forward-message (format description i)
375 folder msg))))))
376 ;; Postition just before forwarded message
377 (if (re-search-forward "^------- Forwarded Message" nil t)
378 (forward-line -1)
379 (re-search-forward (format "^\\(%s\\)?$" mh-mail-header-separator))
380 (forward-line 1))
381 (delete-other-windows)
382 (mh-add-msgs-to-seq msgs 'forwarded t)
924df208 383 (mh-compose-and-send-mail draft "" folder msgs
c3d9274a
BW
384 to forw-subject cc
385 mh-note-forw "Forwarded:"
386 config)
c3d9274a 387 (mh-letter-mode-message)))))
c26cf6c8
RS
388
389(defun mh-forwarded-letter-subject (from subject)
bdcfe844
BW
390 "Return a Subject suitable for a forwarded message.
391Original message has headers FROM and SUBJECT."
c26cf6c8 392 (let ((addr-start (string-match "<" from))
c3d9274a 393 (comment (string-match "(" from)))
c26cf6c8 394 (cond ((and addr-start (> addr-start 0))
c3d9274a
BW
395 ;; Full Name <luser@host>
396 (setq from (substring from 0 (1- addr-start))))
397 (comment
398 ;; luser@host (Full Name)
399 (setq from (substring from (1+ comment) (1- (length from)))))))
c26cf6c8
RS
400 (format mh-forward-subject-format from subject))
401
c26cf6c8
RS
402;;;###autoload
403(defun mh-smail-other-window ()
404 "Compose and send mail in other window with the MH mail system.
bdcfe844 405This function is an entry point to MH-E, the Emacs front end
847b8219
KH
406to the MH mail system.
407
408See documentation of `\\[mh-send]' for more details on composing mail."
c26cf6c8
RS
409 (interactive)
410 (mh-find-path)
411 (call-interactively 'mh-send-other-window))
412
c3d9274a 413;;;###mh-autoload
c26cf6c8 414(defun mh-redistribute (to cc &optional msg)
a1b4049d
BW
415 "Redistribute displayed message to recipients TO and CC.
416Use optional argument MSG to redistribute another message.
c26cf6c8 417Depending on how your copy of MH was compiled, you may need to change the
1838eb6c 418setting of the variable `mh-redist-full-contents'. See its documentation."
c26cf6c8 419 (interactive (list (mh-read-address "Redist-To: ")
c3d9274a
BW
420 (mh-read-address "Redist-Cc: ")
421 (mh-get-msg-num t)))
c26cf6c8
RS
422 (or msg
423 (setq msg (mh-get-msg-num t)))
424 (save-window-excursion
425 (let ((folder mh-current-folder)
c3d9274a
BW
426 (draft (mh-read-draft "redistribution"
427 (if mh-redist-full-contents
428 (mh-msg-filename msg)
429 nil)
430 nil)))
c26cf6c8
RS
431 (mh-goto-header-end 0)
432 (insert "Resent-To: " to "\n")
433 (if (not (equal cc "")) (insert "Resent-cc: " cc "\n"))
924df208
BW
434 (mh-clean-msg-header
435 (point-min)
436 "^Message-Id:\\|^Received:\\|^Return-Path:\\|^Sender:\\|^Date:\\|^From:"
437 nil)
c26cf6c8
RS
438 (save-buffer)
439 (message "Redistributing...")
924df208
BW
440 (let ((env "mhdist=1"))
441 ;; Setup environment...
442 (setq env (concat env " mhaltmsg=" (if mh-redist-full-contents
443 buffer-file-name
444 (mh-msg-filename msg folder))))
445 (unless mh-redist-full-contents
446 (setq env (concat env " mhannotate=1")))
447 ;; Redistribute...
448 (if mh-redist-background
449 (mh-exec-cmd-env-daemon env mh-send-prog nil buffer-file-name)
450 (mh-exec-cmd-error env mh-send-prog "-push" buffer-file-name))
451 ;; Annotate...
452 (mh-annotate-msg msg folder mh-note-dist
453 "-component" "Resent:"
454 "-text" (format "\"%s %s\"" to cc)))
c26cf6c8
RS
455 (kill-buffer draft)
456 (message "Redistributing...done"))))
457
bdcfe844
BW
458(defun mh-show-buffer-message-number (&optional buffer)
459 "Message number of displayed message in corresponding show buffer.
460Return nil if show buffer not displayed.
461If in `mh-letter-mode', don't display the message number being replied to,
462but rather the message number of the show buffer associated with our
463originating folder buffer.
464Optional argument BUFFER can be used to specify the buffer."
465 (save-excursion
466 (if buffer
467 (set-buffer buffer))
468 (cond ((eq major-mode 'mh-show-mode)
c3d9274a
BW
469 (let ((number-start (mh-search-from-end ?/ buffer-file-name)))
470 (car (read-from-string (substring buffer-file-name
471 (1+ number-start))))))
bdcfe844
BW
472 ((and (eq major-mode 'mh-folder-mode)
473 mh-show-buffer
474 (get-buffer mh-show-buffer))
475 (mh-show-buffer-message-number mh-show-buffer))
476 ((and (eq major-mode 'mh-letter-mode)
477 mh-sent-from-folder
478 (get-buffer mh-sent-from-folder))
479 (mh-show-buffer-message-number mh-sent-from-folder))
480 (t
481 nil))))
482
c3d9274a 483;;;###mh-autoload
bdcfe844 484(defun mh-reply (message &optional reply-to includep)
924df208
BW
485 "Reply to MESSAGE.
486Default is the displayed message.
bdcfe844
BW
487If the optional argument REPLY-TO is not given, prompts for type of addresses
488to reply to:
c26cf6c8
RS
489 from sender only,
490 to sender and primary recipients,
491 cc/all sender and all recipients.
bdcfe844
BW
492If optional prefix argument INCLUDEP provided, then include the message
493in the reply using filter `mhl.reply' in your MH directory.
847b8219
KH
494If the file named by `mh-repl-formfile' exists, it is used as a skeleton
495for the reply. See also documentation for `\\[mh-send]' function."
bdcfe844
BW
496 (interactive (list
497 (mh-get-msg-num t)
498 (let ((minibuffer-help-form
499 "from => Sender only\nto => Sender and primary recipients\ncc or all => Sender and all recipients"))
500 (or mh-reply-default-reply-to
501 (completing-read "Reply to whom? (from, to, all) [from]: "
502 '(("from") ("to") ("cc") ("all"))
503 nil
504 t)))
505 current-prefix-arg))
506 (let* ((folder mh-current-folder)
507 (show-buffer mh-show-buffer)
508 (config (current-window-configuration))
509 (group-reply (or (equal reply-to "cc") (equal reply-to "all")))
510 (form-file (cond ((and mh-nmh-flag group-reply
511 (stringp mh-repl-group-formfile))
512 mh-repl-group-formfile)
513 ((stringp mh-repl-formfile) mh-repl-formfile)
514 (t nil))))
515 (message "Composing a reply...")
516 (mh-exec-cmd "repl" "-build" "-noquery" "-nodraftfolder"
517 (if form-file
518 (list "-form" form-file))
519 mh-current-folder message
520 (cond ((or (equal reply-to "from") (equal reply-to ""))
521 '("-nocc" "all"))
522 ((equal reply-to "to")
523 '("-cc" "to"))
524 (group-reply (if mh-nmh-flag
525 '("-group" "-nocc" "me")
526 '("-cc" "all" "-nocc" "me"))))
c3d9274a
BW
527 (cond ((or (eq mh-yank-from-start-of-msg 'autosupercite)
528 (eq mh-yank-from-start-of-msg 'autoattrib))
529 '("-noformat"))
530 (includep '("-filter" "mhl.reply"))
531 (t '())))
bdcfe844
BW
532 (let ((draft (mh-read-draft "reply"
533 (expand-file-name "reply" mh-user-path)
534 t)))
535 (delete-other-windows)
536 (save-buffer)
a1506d29 537
bdcfe844
BW
538 (let ((to (mh-get-header-field "To:"))
539 (subject (mh-get-header-field "Subject:"))
540 (cc (mh-get-header-field "Cc:")))
541 (goto-char (point-min))
542 (mh-goto-header-end 1)
543 (or includep
544 (not mh-reply-show-message-flag)
545 (mh-in-show-buffer (show-buffer)
546 (mh-display-msg message folder)))
547 (mh-add-msgs-to-seq message 'answered t)
548 (message "Composing a reply...done")
549 (mh-compose-and-send-mail draft "" folder message to subject cc
550 mh-note-repl "Replied:" config))
551 (when (and (or (eq 'autosupercite mh-yank-from-start-of-msg)
552 (eq 'autoattrib mh-yank-from-start-of-msg))
553 (eq (mh-show-buffer-message-number) mh-sent-from-msg))
554 (undo-boundary)
555 (mh-yank-cur-msg))
556 (mh-letter-mode-message))))
c26cf6c8 557
c3d9274a 558;;;###mh-autoload
c26cf6c8
RS
559(defun mh-send (to cc subject)
560 "Compose and send a letter.
a1b4049d 561
bdcfe844 562Do not call this function from outside MH-E; use \\[mh-smail] instead.
847b8219 563
a1b4049d
BW
564The file named by `mh-comp-formfile' will be used as the form.
565The letter is composed in `mh-letter-mode'; see its documentation for more
566details.
567If `mh-compose-letter-function' is defined, it is called on the draft and
568passed three arguments: TO, CC, and SUBJECT."
c26cf6c8 569 (interactive (list
c3d9274a
BW
570 (mh-read-address "To: ")
571 (mh-read-address "Cc: ")
572 (read-string "Subject: ")))
c26cf6c8
RS
573 (let ((config (current-window-configuration)))
574 (delete-other-windows)
575 (mh-send-sub to cc subject config)))
576
c3d9274a 577;;;###mh-autoload
c26cf6c8
RS
578(defun mh-send-other-window (to cc subject)
579 "Compose and send a letter in another window.
a1b4049d 580
bdcfe844 581Do not call this function from outside MH-E; use \\[mh-smail-other-window]
a1b4049d
BW
582instead.
583
584The file named by `mh-comp-formfile' will be used as the form.
585The letter is composed in `mh-letter-mode'; see its documentation for more
586details.
587If `mh-compose-letter-function' is defined, it is called on the draft and
588passed three arguments: TO, CC, and SUBJECT."
c26cf6c8 589 (interactive (list
c3d9274a
BW
590 (mh-read-address "To: ")
591 (mh-read-address "Cc: ")
592 (read-string "Subject: ")))
c26cf6c8
RS
593 (let ((pop-up-windows t))
594 (mh-send-sub to cc subject (current-window-configuration))))
595
c26cf6c8 596(defun mh-send-sub (to cc subject config)
bdcfe844
BW
597 "Do the real work of composing and sending a letter.
598Expects the TO, CC, and SUBJECT fields as arguments.
599CONFIG is the window configuration before sending mail."
c26cf6c8 600 (let ((folder mh-current-folder)
c3d9274a 601 (msg-num (mh-get-msg-num nil)))
c26cf6c8
RS
602 (message "Composing a message...")
603 (let ((draft (mh-read-draft
c3d9274a
BW
604 "message"
605 (let (components)
606 (cond
607 ((file-exists-p
608 (setq components
609 (expand-file-name mh-comp-formfile mh-user-path)))
610 components)
611 ((file-exists-p
612 (setq components
613 (expand-file-name mh-comp-formfile mh-lib)))
614 components)
615 ((file-exists-p
616 (setq components
617 (expand-file-name mh-comp-formfile
618 ;; What is this mh-etc ?? -sm
bdcfe844
BW
619 ;; This is dead code, so
620 ;; remove it.
c3d9274a 621 ;(and (boundp 'mh-etc) mh-etc)
bdcfe844 622 )))
c3d9274a
BW
623 components)
624 (t
625 (error (format "Can't find components file \"%s\""
626 components)))))
627 nil)))
c26cf6c8
RS
628 (mh-insert-fields "To:" to "Subject:" subject "Cc:" cc)
629 (goto-char (point-max))
c26cf6c8 630 (mh-compose-and-send-mail draft "" folder msg-num
c3d9274a
BW
631 to subject cc
632 nil nil config)
bdcfe844 633 (mh-letter-mode-message))))
c26cf6c8
RS
634
635(defun mh-read-draft (use initial-contents delete-contents-file)
bdcfe844
BW
636 "Read draft file into a draft buffer and make that buffer the current one.
637USE is a message used for prompting about the intended use of the message.
638INITIAL-CONTENTS is filename that is read into an empty buffer, or nil
639if buffer should not be modified. Delete the initial-contents file if
640DELETE-CONTENTS-FILE flag is set.
641Returns the draft folder's name.
642If the draft folder facility is enabled in ~/.mh_profile, a new buffer is
643used each time and saved in the draft folder. The draft file can then be
644reused."
c26cf6c8 645 (cond (mh-draft-folder
c3d9274a
BW
646 (let ((orig-default-dir default-directory)
647 (draft-file-name (mh-new-draft-name)))
648 (pop-to-buffer (generate-new-buffer
649 (format "draft-%s"
650 (file-name-nondirectory draft-file-name))))
651 (condition-case ()
652 (insert-file-contents draft-file-name t)
653 (file-error))
654 (setq default-directory orig-default-dir)))
655 (t
656 (let ((draft-name (expand-file-name "draft" mh-user-path)))
657 (pop-to-buffer "draft") ; Create if necessary
658 (if (buffer-modified-p)
659 (if (y-or-n-p "Draft has been modified; kill anyway? ")
660 (set-buffer-modified-p nil)
661 (error "Draft preserved")))
662 (setq buffer-file-name draft-name)
663 (clear-visited-file-modtime)
664 (unlock-buffer)
665 (cond ((and (file-exists-p draft-name)
666 (not (equal draft-name initial-contents)))
667 (insert-file-contents draft-name)
668 (delete-file draft-name))))))
c26cf6c8 669 (cond ((and initial-contents
c3d9274a
BW
670 (or (zerop (buffer-size))
671 (if (y-or-n-p
672 (format "A draft exists. Use for %s? " use))
673 (if mh-error-if-no-draft
674 (error "A prior draft exists"))
675 t)))
676 (erase-buffer)
677 (insert-file-contents initial-contents)
678 (if delete-contents-file (delete-file initial-contents))))
c26cf6c8
RS
679 (auto-save-mode 1)
680 (if mh-draft-folder
c3d9274a 681 (save-buffer)) ; Do not reuse draft name
c26cf6c8
RS
682 (buffer-name))
683
c26cf6c8 684(defun mh-new-draft-name ()
bdcfe844 685 "Return the pathname of folder for draft messages."
c26cf6c8
RS
686 (save-excursion
687 (mh-exec-cmd-quiet t "mhpath" mh-draft-folder "new")
688 (buffer-substring (point-min) (1- (point-max)))))
689
c26cf6c8 690(defun mh-annotate-msg (msg buffer note &rest args)
924df208
BW
691 "Mark MSG in BUFFER with character NOTE and annotate message with ARGS.
692MSG can be a message number, a list of message numbers, or a sequence."
693 (apply 'mh-exec-cmd "anno" buffer
694 (if (listp msg) (append msg args) (cons msg args)))
c26cf6c8 695 (save-excursion
c3d9274a
BW
696 (cond ((get-buffer buffer) ; Buffer may be deleted
697 (set-buffer buffer)
924df208
BW
698 (mh-iterate-on-msg-or-seq nil msg
699 (mh-notate nil note (1+ mh-cmd-note)))))))
c26cf6c8 700
c26cf6c8 701(defun mh-insert-fields (&rest name-values)
bdcfe844
BW
702 "Insert the NAME-VALUES pairs in the current buffer.
703If the field exists, append the value to it.
704Do not insert any pairs whose value is the empty string."
c26cf6c8
RS
705 (let ((case-fold-search t))
706 (while name-values
707 (let ((field-name (car name-values))
c3d9274a
BW
708 (value (car (cdr name-values))))
709 (cond ((equal value "")
710 nil)
711 ((mh-position-on-field field-name)
712 (insert " " (or value "")))
713 (t
714 (insert field-name " " value "\n")))
715 (setq name-values (cdr (cdr name-values)))))))
c26cf6c8 716
bdcfe844
BW
717(defun mh-position-on-field (field &optional ignored)
718 "Move to the end of the FIELD in the header.
719Move to end of entire header if FIELD not found.
720Returns non-nil iff FIELD was found.
721The optional second arg is for pre-version 4 compatibility and is IGNORED."
a1b4049d 722 (cond ((mh-goto-header-field field)
c3d9274a
BW
723 (mh-header-field-end)
724 t)
725 ((mh-goto-header-end 0)
726 nil)))
847b8219 727
847b8219 728(defun mh-get-header-field (field)
bdcfe844
BW
729 "Find and return the body of FIELD in the mail header.
730Returns the empty string if the field is not in the header of the
731current buffer."
847b8219
KH
732 (if (mh-goto-header-field field)
733 (progn
c3d9274a
BW
734 (skip-chars-forward " \t") ;strip leading white space in body
735 (let ((start (point)))
736 (mh-header-field-end)
737 (buffer-substring-no-properties start (point))))
847b8219
KH
738 ""))
739
bdcfe844 740(fset 'mh-get-field 'mh-get-header-field) ;MH-E 4 compatibility
847b8219
KH
741
742(defun mh-goto-header-field (field)
bdcfe844
BW
743 "Move to FIELD in the message header.
744Move to the end of the FIELD name, which should end in a colon.
745Returns t if found, nil if not."
847b8219
KH
746 (goto-char (point-min))
747 (let ((case-fold-search t)
c3d9274a
BW
748 (headers-end (save-excursion
749 (mh-goto-header-end 0)
750 (point))))
847b8219
KH
751 (re-search-forward (format "^%s" field) headers-end t)))
752
c26cf6c8 753(defun mh-goto-header-end (arg)
bdcfe844 754 "Move the cursor ARG lines after the header."
9303c8db 755 (if (re-search-forward "^-*$" nil nil)
c26cf6c8
RS
756 (forward-line arg)))
757
c3d9274a
BW
758(defun mh-extract-from-header-value ()
759 "Extract From: string from header."
760 (save-excursion
761 (if (not (mh-goto-header-field "From:"))
924df208 762 nil
c3d9274a
BW
763 (skip-chars-forward " \t")
764 (buffer-substring-no-properties
765 (point) (progn (mh-header-field-end)(point))))))
c26cf6c8
RS
766
767\f
768
769;;; Mode for composing and sending a draft message.
770
bdcfe844 771(put 'mh-letter-mode 'mode-class 'special)
c26cf6c8 772
bdcfe844
BW
773;;; Menu extracted from mh-menubar.el V1.1 (31 July 2001)
774(eval-when-compile (defvar mh-letter-menu nil))
775(cond
776 ((fboundp 'easy-menu-define)
777 (easy-menu-define
778 mh-letter-menu mh-letter-mode-map "Menu for MH-E letter mode."
779 '("Letter"
780 ["Send This Draft" mh-send-letter t]
781 ["Split Current Line" mh-open-line t]
782 ["Check Recipient" mh-check-whom t]
783 ["Yank Current Message" mh-yank-cur-msg t]
784 ["Insert a Message..." mh-insert-letter t]
785 ["Insert Signature" mh-insert-signature t]
c3d9274a
BW
786 ["GPG Sign message"
787 mh-mml-secure-message-sign-pgpmime mh-gnus-pgp-support-flag]
788 ["GPG Encrypt message"
789 mh-mml-secure-message-encrypt-pgpmime mh-gnus-pgp-support-flag]
bdcfe844 790 ["Compose Insertion (MIME)..." mh-compose-insertion t]
c3d9274a
BW
791 ;; ["Compose Compressed tar (MIME)..."
792 ;;mh-mhn-compose-external-compressed-tar t]
793 ;; ["Compose Anon FTP (MIME)..." mh-mhn-compose-anon-ftp t]
bdcfe844 794 ["Compose Forward (MIME)..." mh-compose-forward t]
c3d9274a
BW
795 ;; The next two will have to be merged. But I also need to make sure the
796 ;; user can't mix directives of both types.
797 ["Pull in All Compositions (mhn)"
924df208 798 mh-edit-mhn (mh-mhn-directive-present-p)]
c3d9274a 799 ["Pull in All Compositions (gnus)"
924df208 800 mh-mml-to-mime (mh-mml-directive-present-p)]
c3d9274a
BW
801 ["Revert to Non-MIME Edit (mhn)"
802 mh-revert-mhn-edit (equal mh-compose-insertion 'mhn)]
bdcfe844 803 ["Kill This Draft" mh-fully-kill-draft t]))))
c26cf6c8 804
bdcfe844
BW
805;;; Help Messages
806;;; Group messages logically, more or less.
807(defvar mh-letter-mode-help-messages
808 '((nil
809 "Send letter: \\[mh-send-letter]"
810 "\t\tOpen line: \\[mh-open-line]\n"
811 "Kill letter: \\[mh-fully-kill-draft]"
812 "\t\tInsert:\n"
813 "Check recipients: \\[mh-check-whom]"
814 "\t\t Current message: \\[mh-yank-cur-msg]\n"
815 "Encrypt message: \\[mh-mml-secure-message-encrypt-pgpmime]"
816 "\t\t Attachment: \\[mh-compose-insertion]\n"
817 "Sign message: \\[mh-mml-secure-message-sign-pgpmime]"
818 "\t\t Message to forward: \\[mh-compose-forward]\n"
819 " "
820 "\t\t Signature: \\[mh-insert-signature]"))
821 "Key binding cheat sheet.
822
823This is an associative array which is used to show the most common commands.
824The key is a prefix char. The value is one or more strings which are
825concatenated together and displayed in the minibuffer if ? is pressed after
826the prefix character. The special key nil is used to display the
827non-prefixed commands.
828
829The substitutions described in `substitute-command-keys' are performed as
830well.")
831
c3d9274a 832;;;###mh-autoload
bdcfe844
BW
833(defun mh-fill-paragraph-function (arg)
834 "Fill paragraph at or after point.
835Prefix ARG means justify as well. This function enables `fill-paragraph' to
836work better in MH-Letter mode."
837 (interactive "P")
838 (let ((fill-paragraph-function) (fill-prefix))
839 (if (mh-in-header-p)
840 (mail-mode-fill-paragraph arg)
841 (fill-paragraph arg))))
c26cf6c8 842
924df208
BW
843;; Avoid compiler warnings in XEmacs and Emacs 20
844(eval-when-compile
845 (defvar tool-bar-mode)
846 (defvar tool-bar-map))
847
c26cf6c8 848;;;###autoload
f7c4478f 849(define-derived-mode mh-letter-mode text-mode "MH-Letter"
bdcfe844 850 "Mode for composing letters in MH-E.\\<mh-letter-mode-map>
a1b4049d 851
847b8219
KH
852When you have finished composing, type \\[mh-send-letter] to send the message
853using the MH mail handling system.
c26cf6c8 854
c3d9274a
BW
855There are two types of MIME directives used by MH-E: Gnus and MH. The option
856`mh-compose-insertion' controls what type of directives are inserted by MH-E
857commands. These directives can be converted to MIME body parts by running
858\\[mh-edit-mhn] for mhn directives or \\[mh-mml-to-mime] for Gnus directives.
859This step is mandatory if these directives are added manually. If the
860directives are inserted with MH-E commands such as \\[mh-compose-insertion],
861the directives are expanded automatically when the letter is sent.
c26cf6c8 862
a1b4049d
BW
863Options that control this mode can be changed with
864\\[customize-group]; specify the \"mh-compose\" group.
c26cf6c8 865
a1b4049d
BW
866When a message is composed, the hooks `text-mode-hook' and
867`mh-letter-mode-hook' are run.
c26cf6c8 868
a1b4049d 869\\{mh-letter-mode-map}"
c26cf6c8 870
c26cf6c8 871 (or mh-user-path (mh-find-path))
c26cf6c8
RS
872 (make-local-variable 'mh-send-args)
873 (make-local-variable 'mh-annotate-char)
874 (make-local-variable 'mh-annotate-field)
875 (make-local-variable 'mh-previous-window-config)
876 (make-local-variable 'mh-sent-from-folder)
877 (make-local-variable 'mh-sent-from-msg)
878 (make-local-variable 'mail-header-separator)
a1b4049d 879 (setq mail-header-separator mh-mail-header-separator) ;override sendmail.el
bdcfe844
BW
880 (make-local-variable 'mh-help-messages)
881 (setq mh-help-messages mh-letter-mode-help-messages)
a1b4049d
BW
882
883 ;; From sendmail.el for proper paragraph fill
884 ;; sendmail.el also sets a normal-auto-fill-function (not done here)
885 (make-local-variable 'paragraph-separate)
886 (make-local-variable 'paragraph-start)
887 (make-local-variable 'fill-paragraph-function)
bdcfe844 888 (setq fill-paragraph-function 'mh-fill-paragraph-function)
a1b4049d
BW
889 (make-local-variable 'adaptive-fill-regexp)
890 (setq adaptive-fill-regexp
c3d9274a
BW
891 (concat adaptive-fill-regexp
892 "\\|[ \t]*[-[:alnum:]]*>+[ \t]*"))
a1b4049d
BW
893 (make-local-variable 'adaptive-fill-first-line-regexp)
894 (setq adaptive-fill-first-line-regexp
c3d9274a
BW
895 (concat adaptive-fill-first-line-regexp
896 "\\|[ \t]*[-[:alnum:]]*>+[ \t]*"))
a1b4049d
BW
897 ;; `-- ' precedes the signature. `-----' appears at the start of the
898 ;; lines that delimit forwarded messages.
899 ;; Lines containing just >= 3 dashes, perhaps after whitespace,
900 ;; are also sometimes used and should be separators.
901 (setq paragraph-start (concat (regexp-quote mail-header-separator)
c3d9274a
BW
902 "\\|\t*\\([-|#;>* ]\\|(?[0-9]+[.)]\\)+$"
903 "\\|[ \t]*[[:alnum:]]*>+[ \t]*$\\|[ \t]*$\\|"
904 "-- $\\|---+$\\|"
905 page-delimiter))
a1b4049d
BW
906 (setq paragraph-separate paragraph-start)
907 ;; --- End of code from sendmail.el ---
908
924df208
BW
909 ;; Enable undo since a show-mode buffer might have been reused.
910 (buffer-enable-undo)
a1b4049d
BW
911 (if (and (boundp 'tool-bar-mode) tool-bar-mode)
912 (set (make-local-variable 'tool-bar-map) mh-letter-tool-bar-map))
924df208 913 (mh-funcall-if-exists mh-toolbar-init :letter)
a1b4049d
BW
914 (make-local-variable 'font-lock-defaults)
915 (cond
bdcfe844
BW
916 ((or (equal mh-highlight-citation-p 'font-lock)
917 (equal mh-highlight-citation-p 'gnus))
918 ;; Let's use font-lock even if gnus is used in show-mode. The reason
919 ;; is that gnus uses static text properties which are not appropriate
920 ;; for a buffer that will be edited. So the choice here is either fontify
921 ;; the citations and header...
a1b4049d 922 (setq font-lock-defaults '(mh-show-font-lock-keywords-with-cite t)))
a1b4049d 923 (t
bdcfe844 924 ;; ...or the header only
a1b4049d
BW
925 (setq font-lock-defaults '(mh-show-font-lock-keywords t))))
926 (easy-menu-add mh-letter-menu)
a1b4049d 927 (setq fill-column mh-letter-fill-column)
c3d9274a 928 ;; If text-mode-hook turned on auto-fill, tune it for messages
f7c4478f
SM
929 (when auto-fill-function
930 (make-local-variable 'auto-fill-function)
931 (setq auto-fill-function 'mh-auto-fill-for-letter)))
c26cf6c8 932
c26cf6c8 933(defun mh-auto-fill-for-letter ()
bdcfe844
BW
934 "Perform auto-fill for message.
935Header is treated specially by inserting a tab before continuation lines."
c26cf6c8 936 (if (mh-in-header-p)
9303c8db 937 (let ((fill-prefix "\t"))
c3d9274a 938 (do-auto-fill))
9303c8db 939 (do-auto-fill)))
c26cf6c8 940
a1b4049d 941(defun mh-insert-header-separator ()
bdcfe844 942 "Insert `mh-mail-header-separator', if absent."
c26cf6c8 943 (save-excursion
a1b4049d
BW
944 (goto-char (point-min))
945 (rfc822-goto-eoh)
946 (if (looking-at "$")
c3d9274a 947 (insert mh-mail-header-separator))))
c26cf6c8 948
c3d9274a 949;;;###mh-autoload
c26cf6c8
RS
950(defun mh-to-field ()
951 "Move point to the end of a specified header field.
952The field is indicated by the previous keystroke (the last keystroke
1838eb6c 953of the command) according to the list in the variable `mh-to-field-choices'.
c26cf6c8
RS
954Create the field if it does not exist. Set the mark to point before moving."
955 (interactive)
956 (expand-abbrev)
847b8219 957 (let ((target (cdr (or (assoc (char-to-string (logior last-input-char ?`))
c3d9274a
BW
958 mh-to-field-choices)
959 ;; also look for a char for version 4 compat
960 (assoc (logior last-input-char ?`)
961 mh-to-field-choices))))
962 (case-fold-search t))
c26cf6c8
RS
963 (push-mark)
964 (cond ((mh-position-on-field target)
c3d9274a
BW
965 (let ((eol (point)))
966 (skip-chars-backward " \t")
967 (delete-region (point) eol))
968 (if (and (not (eq (logior last-input-char ?`) ?s))
969 (save-excursion
970 (backward-char 1)
971 (not (looking-at "[:,]"))))
972 (insert ", ")
973 (insert " ")))
974 (t
975 (if (mh-position-on-field "To:")
976 (forward-line 1))
977 (insert (format "%s \n" target))
978 (backward-char 1)))))
c26cf6c8 979
c3d9274a 980;;;###mh-autoload
c26cf6c8
RS
981(defun mh-to-fcc (&optional folder)
982 "Insert an Fcc: FOLDER field in the current message.
983Prompt for the field name with a completion list of the current folders."
984 (interactive)
985 (or folder
986 (setq folder (mh-prompt-for-folder
c3d9274a
BW
987 "Fcc"
988 (or (and mh-default-folder-for-message-function
989 (save-excursion
990 (goto-char (point-min))
991 (funcall
992 mh-default-folder-for-message-function)))
993 "")
994 t)))
c26cf6c8
RS
995 (let ((last-input-char ?\C-f))
996 (expand-abbrev)
997 (save-excursion
998 (mh-to-field)
999 (insert (if (mh-folder-name-p folder)
c3d9274a
BW
1000 (substring folder 1)
1001 folder)))))
c26cf6c8 1002
c3d9274a 1003;;;###mh-autoload
c26cf6c8 1004(defun mh-insert-signature ()
bdcfe844
BW
1005 "Insert the file named by `mh-signature-file-name' at point.
1006The value of `mh-letter-insert-signature-hook' is a list of functions to be
1007called, with no arguments, before the signature is actually inserted."
c26cf6c8 1008 (interactive)
bdcfe844
BW
1009 (let ((mh-signature-file-name mh-signature-file-name))
1010 (run-hooks 'mh-letter-insert-signature-hook)
1011 (if mh-signature-file-name
c3d9274a 1012 (insert-file-contents mh-signature-file-name)))
2450bd29 1013 (force-mode-line-update))
c26cf6c8 1014
c3d9274a 1015;;;###mh-autoload
c26cf6c8 1016(defun mh-check-whom ()
847b8219 1017 "Verify recipients of the current letter, showing expansion of any aliases."
c26cf6c8 1018 (interactive)
847b8219 1019 (let ((file-name buffer-file-name))
c26cf6c8
RS
1020 (save-buffer)
1021 (message "Checking recipients...")
3d7ca223 1022 (mh-in-show-buffer (mh-recipients-buffer)
c26cf6c8
RS
1023 (bury-buffer (current-buffer))
1024 (erase-buffer)
1025 (mh-exec-cmd-output "whom" t file-name))
1026 (message "Checking recipients...done")))
1027
3d7ca223
BW
1028(defun mh-tidy-draft-buffer ()
1029 "Run when a draft buffer is destroyed."
1030 (let ((buffer (get-buffer mh-recipients-buffer)))
1031 (if buffer
1032 (kill-buffer buffer))))
1033
c26cf6c8
RS
1034\f
1035
1036;;; Routines to compose and send a letter.
1037
bdcfe844 1038(defun mh-insert-x-face ()
924df208 1039 "Append X-Face, Face or X-Image-URL field to header.
bdcfe844
BW
1040If the field already exists, this function does nothing."
1041 (when (and (file-exists-p mh-x-face-file)
1042 (file-readable-p mh-x-face-file))
1043 (save-excursion
924df208
BW
1044 (unless (or (mh-position-on-field "X-Face")
1045 (mh-position-on-field "Face")
1046 (mh-position-on-field "X-Image-URL"))
1047 (save-excursion
1048 (goto-char (+ (point) (cadr (insert-file-contents mh-x-face-file))))
1049 (if (not (looking-at "^"))
1050 (insert "\n")))
1051 (unless (looking-at "\\(X-Face\\|Face\\|X-Image-URL\\): ")
1052 (insert "X-Face: "))))))
1053
1054(defvar mh-x-mailer-string nil
1055 "*String containing the contents of the X-Mailer header field.
1056If nil, this variable is initialized to show the version of MH-E, Emacs, and
1057MH the first time a message is composed.")
bdcfe844 1058
a1b4049d 1059(defun mh-insert-x-mailer ()
bdcfe844
BW
1060 "Append an X-Mailer field to the header.
1061The versions of MH-E, Emacs, and MH are shown."
a1b4049d
BW
1062
1063 ;; Lazily initialize mh-x-mailer-string.
1064 (when (null mh-x-mailer-string)
1065 (save-window-excursion
3d7ca223
BW
1066 ;; User would be confused if version info buffer disappeared magically,
1067 ;; so don't delete buffer if it already existed.
1068 (let ((info-buffer-exists-p (get-buffer mh-info-buffer)))
1069 (mh-version)
1070 (set-buffer mh-info-buffer)
1071 (if mh-nmh-flag
1072 (search-forward-regexp "^nmh-\\(\\S +\\)")
1073 (search-forward-regexp "^MH \\(\\S +\\)" nil t))
1074 (let ((x-mailer-mh (buffer-substring (match-beginning 1)
1075 (match-end 1))))
1076 (setq mh-x-mailer-string
1077 (format "MH-E %s; %s %s; %sEmacs %s"
1078 mh-version (if mh-nmh-flag "nmh" "MH") x-mailer-mh
1079 (if mh-xemacs-flag "X" "GNU ")
1080 (cond ((not mh-xemacs-flag) emacs-version)
1081 ((string-match "[0-9.]*\\( +\([ a-z]+[0-9]+\)\\)?"
1082 emacs-version)
1083 (match-string 0 emacs-version))
1084 (t (format "%s.%s"
1085 emacs-major-version
1086 emacs-minor-version))))))
1087 (if (not info-buffer-exists-p)
1088 (kill-buffer mh-info-buffer)))))
a1b4049d
BW
1089 ;; Insert X-Mailer, but only if it doesn't already exist.
1090 (save-excursion
1091 (when (null (mh-goto-header-field "X-Mailer"))
c3d9274a 1092 (mh-insert-fields "X-Mailer:" mh-x-mailer-string))))
a1b4049d 1093
bdcfe844
BW
1094(defun mh-regexp-in-field-p (regexp &rest fields)
1095 "Non-nil means REGEXP was found in FIELDS."
1096 (save-excursion
1097 (let ((search-result nil)
1098 (field))
1099 (while fields
1100 (setq field (car fields))
1101 (if (and (mh-goto-header-field field)
1102 (re-search-forward
1103 regexp (save-excursion (mh-header-field-end)(point)) t))
1104 (setq fields nil
1105 search-result t)
1106 (setq fields (cdr fields))))
1107 search-result)))
1108
924df208
BW
1109(defun mh-insert-auto-fields ()
1110 "Insert custom fields if To or Cc match `mh-auto-fields-list'."
bdcfe844 1111 (save-excursion
924df208
BW
1112 (when (and (or (mh-goto-header-field "To:")(mh-goto-header-field "cc:")))
1113 (let ((list mh-auto-fields-list))
1114 (while list
1115 (let ((regexp (nth 0 (car list)))
1116 (entries (nth 1 (car list))))
1117 (when (mh-regexp-in-field-p regexp "To:" "cc:")
1118 (let ((entry-list entries))
1119 (while entry-list
1120 (let ((field (caar entry-list))
1121 (value (cdar entry-list)))
1122 (cond
1123 ((equal "identity" field)
1124 (when (assoc value mh-identity-list)
1125 (mh-insert-identity value)))
1126 (t
1127 (mh-modify-header-field field value
1128 (equal field "From")))))
1129 (setq entry-list (cdr entry-list))))))
1130 (setq list (cdr list)))))))
1131
1132(defun mh-modify-header-field (field value &optional overwrite-flag)
1133 "To header FIELD add VALUE.
1134If OVERWRITE-FLAG is non-nil then the old value, if present, is discarded."
1135 (cond ((mh-goto-header-field (concat field ":"))
1136 (insert value)
1137 (if overwrite-flag
1138 (delete-region (point) (line-end-position))
1139 (insert ", ")))
1140 (t (mh-goto-header-end 0)
1141 (insert field ": " value "\n"))))
a1b4049d 1142
c26cf6c8 1143(defun mh-compose-and-send-mail (draft send-args
c3d9274a
BW
1144 sent-from-folder sent-from-msg
1145 to subject cc
1146 annotate-char annotate-field
1147 config)
bdcfe844
BW
1148 "Edit and compose a draft message in buffer DRAFT and send or save it.
1149SEND-ARGS is the argument passed to the send command.
1150SENT-FROM-FOLDER is buffer containing scan listing of current folder, or
1151nil if none exists.
1152SENT-FROM-MSG is the message number or sequence name or nil.
1153The TO, SUBJECT, and CC fields are passed to the
1154`mh-compose-letter-function'.
1155If ANNOTATE-CHAR is non-null, it is used to notate the scan listing of the
1156message. In that case, the ANNOTATE-FIELD is used to build a string
1157for `mh-annotate-msg'.
1158CONFIG is the window configuration to restore after sending the letter."
c26cf6c8 1159 (pop-to-buffer draft)
924df208 1160 (mh-insert-auto-fields)
c26cf6c8 1161 (mh-letter-mode)
a1506d29 1162
c3d9274a
BW
1163 ;; mh-identity support
1164 (if (and (boundp 'mh-identity-default)
924df208
BW
1165 mh-identity-default
1166 (not mh-identity-local))
c3d9274a
BW
1167 (mh-insert-identity mh-identity-default))
1168 (when (and (boundp 'mh-identity-list)
1169 mh-identity-list)
1170 (mh-identity-make-menu)
1171 (easy-menu-add mh-identity-menu))
a1506d29 1172
c26cf6c8
RS
1173 (setq mh-sent-from-folder sent-from-folder)
1174 (setq mh-sent-from-msg sent-from-msg)
1175 (setq mh-send-args send-args)
1176 (setq mh-annotate-char annotate-char)
1177 (setq mh-annotate-field annotate-field)
1178 (setq mh-previous-window-config config)
3d7ca223
BW
1179 (setq mode-line-buffer-identification (list " {%b}"))
1180 (mh-logo-display)
924df208 1181 (mh-make-local-hook 'kill-buffer-hook)
3d7ca223 1182 (add-hook 'kill-buffer-hook 'mh-tidy-draft-buffer nil t)
c26cf6c8 1183 (if (and (boundp 'mh-compose-letter-function)
c3d9274a 1184 mh-compose-letter-function)
c26cf6c8 1185 ;; run-hooks will not pass arguments.
847b8219 1186 (let ((value mh-compose-letter-function))
c3d9274a
BW
1187 (if (and (listp value) (not (eq (car value) 'lambda)))
1188 (while value
1189 (funcall (car value) to subject cc)
1190 (setq value (cdr value)))
1191 (funcall mh-compose-letter-function to subject cc)))))
c26cf6c8 1192
bdcfe844
BW
1193(defun mh-letter-mode-message ()
1194 "Display a help message for users of `mh-letter-mode'.
1195This should be the last function called when composing the draft."
1196 (message "%s" (substitute-command-keys
c3d9274a
BW
1197 (concat "Type \\[mh-send-letter] to send message, "
1198 "\\[mh-help] for help."))))
c26cf6c8 1199
c3d9274a 1200;;;###mh-autoload
c26cf6c8
RS
1201(defun mh-send-letter (&optional arg)
1202 "Send the draft letter in the current buffer.
a1b4049d 1203If optional prefix argument ARG is provided, monitor delivery.
bdcfe844
BW
1204The value of `mh-before-send-letter-hook' is a list of functions to be called,
1205with no arguments, before doing anything.
924df208
BW
1206Run `\\[mh-edit-mhn]' if mhn directives are present; otherwise
1207run `\\[mh-mml-to-mime]' if mml directives are present.
c3d9274a
BW
1208Insert X-Mailer field if variable `mh-insert-x-mailer-flag' is set.
1209Insert X-Face field if the file specified by `mh-x-face-file' exists."
c26cf6c8
RS
1210 (interactive "P")
1211 (run-hooks 'mh-before-send-letter-hook)
924df208
BW
1212 (cond ((mh-mhn-directive-present-p)
1213 (mh-edit-mhn))
1214 ((mh-mml-directive-present-p)
1215 (mh-mml-to-mime)))
bdcfe844
BW
1216 (if mh-insert-x-mailer-flag (mh-insert-x-mailer))
1217 (mh-insert-x-face)
c26cf6c8
RS
1218 (save-buffer)
1219 (message "Sending...")
1220 (let ((draft-buffer (current-buffer))
c3d9274a
BW
1221 (file-name buffer-file-name)
1222 (config mh-previous-window-config)
1223 (coding-system-for-write
1224 (if (and (local-variable-p 'buffer-file-coding-system
a1b4049d 1225 (current-buffer)) ;XEmacs needs two args
c3d9274a
BW
1226 ;; We're not sure why, but buffer-file-coding-system
1227 ;; tends to get set to undecided-unix.
1228 (not (memq buffer-file-coding-system
1229 '(undecided undecided-unix undecided-dos))))
1230 buffer-file-coding-system
1231 (or (and (boundp 'sendmail-coding-system) sendmail-coding-system)
1232 (and (boundp 'default-buffer-file-coding-system )
a1b4049d 1233 default-buffer-file-coding-system)
c3d9274a 1234 'iso-latin-1))))
bdcfe844
BW
1235 ;; The default BCC encapsulation will make a MIME message unreadable.
1236 ;; With nmh use the -mime arg to prevent this.
1237 (if (and mh-nmh-flag
c3d9274a
BW
1238 (mh-goto-header-field "Bcc:")
1239 (mh-goto-header-field "Content-Type:"))
1240 (setq mh-send-args (format "-mime %s" mh-send-args)))
c26cf6c8 1241 (cond (arg
924df208 1242 (pop-to-buffer mh-mail-delivery-buffer)
c3d9274a
BW
1243 (erase-buffer)
1244 (mh-exec-cmd-output mh-send-prog t "-watch" "-nopush"
1245 "-nodraftfolder" mh-send-args file-name)
1246 (goto-char (point-max)) ; show the interesting part
1247 (recenter -1)
1248 (set-buffer draft-buffer)) ; for annotation below
1249 (t
3d7ca223 1250 (mh-exec-cmd-daemon mh-send-prog nil "-nodraftfolder" "-noverbose"
c3d9274a 1251 mh-send-args file-name)))
c26cf6c8 1252 (if mh-annotate-char
c3d9274a
BW
1253 (mh-annotate-msg mh-sent-from-msg
1254 mh-sent-from-folder
1255 mh-annotate-char
1256 "-component" mh-annotate-field
1257 "-text" (format "\"%s %s\""
1258 (mh-get-header-field "To:")
1259 (mh-get-header-field "Cc:"))))
c26cf6c8
RS
1260
1261 (cond ((or (not arg)
c3d9274a
BW
1262 (y-or-n-p "Kill draft buffer? "))
1263 (kill-buffer draft-buffer)
1264 (if config
1265 (set-window-configuration config))))
c26cf6c8 1266 (if arg
c3d9274a 1267 (message "Sending...done")
c26cf6c8
RS
1268 (message "Sending...backgrounded"))))
1269
c3d9274a 1270;;;###mh-autoload
847b8219
KH
1271(defun mh-insert-letter (folder message verbatim)
1272 "Insert a message into the current letter.
c3d9274a
BW
1273Removes the header fields according to the variable `mh-invisible-headers'.
1274Prefixes each non-blank line with `mh-ins-buf-prefix', unless
1275`mh-yank-from-start-of-msg' is set for supercite in which case supercite is
1276used to format the message.
bdcfe844
BW
1277Prompts for FOLDER and MESSAGE. If prefix argument VERBATIM provided, do
1278not indent and do not delete headers. Leaves the mark before the letter
1279and point after it."
c26cf6c8 1280 (interactive
847b8219 1281 (list (mh-prompt-for-folder "Message from" mh-sent-from-folder nil)
c3d9274a
BW
1282 (read-input (format "Message number%s: "
1283 (if (numberp mh-sent-from-msg)
1284 (format " [%d]" mh-sent-from-msg)
1285 "")))
1286 current-prefix-arg))
c26cf6c8
RS
1287 (save-restriction
1288 (narrow-to-region (point) (point))
1289 (let ((start (point-min)))
847b8219 1290 (if (equal message "") (setq message (int-to-string mh-sent-from-msg)))
bdcfe844
BW
1291 (insert-file-contents
1292 (expand-file-name message (mh-expand-file-name folder)))
1293 (when (not verbatim)
1294 (mh-clean-msg-header start mh-invisible-headers mh-visible-headers)
c3d9274a
BW
1295 (goto-char (point-max)) ;Needed for sc-cite-original
1296 (push-mark) ;Needed for sc-cite-original
1297 (goto-char (point-min)) ;Needed for sc-cite-original
bdcfe844
BW
1298 (mh-insert-prefix-string mh-ins-buf-prefix)))))
1299
1300(defun mh-extract-from-attribution ()
1301 "Extract phrase or comment from From header field."
1302 (save-excursion
1303 (if (not (mh-goto-header-field "From: "))
1304 nil
1305 (skip-chars-forward " ")
1306 (cond
1307 ((looking-at "\"\\([^\"\n]+\\)\" \\(<.+>\\)")
1308 (format "%s %s %s" (match-string 1)(match-string 2)
1309 mh-extract-from-attribution-verb))
1310 ((looking-at "\\([^<\n]+<.+>\\)$")
1311 (format "%s %s" (match-string 1) mh-extract-from-attribution-verb))
1312 ((looking-at "\\([^ ]+@[^ ]+\\) +(\\(.+\\))$")
1313 (format "%s <%s> %s" (match-string 2)(match-string 1)
1314 mh-extract-from-attribution-verb))
1315 ((looking-at " *\\(.+\\)$")
1316 (format "%s %s" (match-string 1) mh-extract-from-attribution-verb))))))
c26cf6c8 1317
c3d9274a 1318;;;###mh-autoload
c26cf6c8
RS
1319(defun mh-yank-cur-msg ()
1320 "Insert the current message into the draft buffer.
1321Prefix each non-blank line in the message with the string in
1322`mh-ins-buf-prefix'. If a region is set in the message's buffer, then
1323only the region will be inserted. Otherwise, the entire message will
1324be inserted if `mh-yank-from-start-of-msg' is non-nil. If this variable
1325is nil, the portion of the message following the point will be yanked.
bdcfe844 1326If `mh-delete-yanked-msg-window-flag' is non-nil, any window displaying the
c26cf6c8
RS
1327yanked message will be deleted."
1328 (interactive)
bdcfe844
BW
1329 (if (and mh-sent-from-folder
1330 (save-excursion (set-buffer mh-sent-from-folder) mh-show-buffer)
1331 (save-excursion (set-buffer mh-sent-from-folder)
1332 (get-buffer mh-show-buffer))
1333 mh-sent-from-msg)
c26cf6c8 1334 (let ((to-point (point))
c3d9274a
BW
1335 (to-buffer (current-buffer)))
1336 (set-buffer mh-sent-from-folder)
1337 (if mh-delete-yanked-msg-window-flag
1338 (delete-windows-on mh-show-buffer))
1339 (set-buffer mh-show-buffer) ; Find displayed message
1340 (let* ((from-attr (mh-extract-from-attribution))
1341 (yank-region (mh-mark-active-p nil))
bdcfe844
BW
1342 (mh-ins-str
1343 (cond ((and yank-region
1344 (or (eq 'supercite mh-yank-from-start-of-msg)
1345 (eq 'autosupercite mh-yank-from-start-of-msg)
1346 (eq t mh-yank-from-start-of-msg)))
1347 ;; supercite needs the full header
1348 (concat
924df208 1349 (buffer-substring (point-min) (mh-mail-header-end))
bdcfe844
BW
1350 "\n"
1351 (buffer-substring (region-beginning) (region-end))))
1352 (yank-region
1353 (buffer-substring (region-beginning) (region-end)))
1354 ((or (eq 'body mh-yank-from-start-of-msg)
1355 (eq 'attribution
1356 mh-yank-from-start-of-msg)
1357 (eq 'autoattrib
1358 mh-yank-from-start-of-msg))
1359 (buffer-substring
1360 (save-excursion
1361 (goto-char (point-min))
1362 (mh-goto-header-end 1)
1363 (point))
1364 (point-max)))
1365 ((or (eq 'supercite mh-yank-from-start-of-msg)
1366 (eq 'autosupercite mh-yank-from-start-of-msg)
1367 (eq t mh-yank-from-start-of-msg))
1368 (buffer-substring (point-min) (point-max)))
1369 (t
1370 (buffer-substring (point) (point-max))))))
c3d9274a
BW
1371 (set-buffer to-buffer)
1372 (save-restriction
1373 (narrow-to-region to-point to-point)
1374 (insert (mh-filter-out-non-text mh-ins-str))
bdcfe844 1375 (goto-char (point-max)) ;Needed for sc-cite-original
c3d9274a 1376 (push-mark) ;Needed for sc-cite-original
bdcfe844 1377 (goto-char (point-min)) ;Needed for sc-cite-original
c3d9274a 1378 (mh-insert-prefix-string mh-ins-buf-prefix)
bdcfe844
BW
1379 (if (or (eq 'attribution mh-yank-from-start-of-msg)
1380 (eq 'autoattrib mh-yank-from-start-of-msg))
1381 (insert from-attr "\n\n"))
c3d9274a
BW
1382 ;; If the user has selected a region, he has already "edited" the
1383 ;; text, so leave the cursor at the end of the yanked text. In
1384 ;; either case, leave a mark at the opposite end of the included
1385 ;; text to make it easy to jump or delete to the other end of the
1386 ;; text.
1387 (push-mark)
1388 (goto-char (point-max))
1389 (if (null yank-region)
1390 (mh-exchange-point-and-mark-preserving-active-mark)))))
847b8219 1391 (error "There is no current message")))
c26cf6c8 1392
bdcfe844
BW
1393(defun mh-filter-out-non-text (string)
1394 "Return STRING but without adornments such as MIME buttons and smileys."
1395 (with-temp-buffer
1396 ;; Insert the string to filter
1397 (insert string)
1398 (goto-char (point-min))
a1506d29 1399
bdcfe844
BW
1400 ;; Remove the MIME buttons
1401 (let ((can-move-forward t)
1402 (in-button nil))
1403 (while can-move-forward
1404 (cond ((and (not (get-text-property (point) 'mh-data))
1405 in-button)
c3d9274a 1406 (delete-region (1- (point)) (point))
bdcfe844
BW
1407 (setq in-button nil))
1408 ((get-text-property (point) 'mh-data)
1409 (delete-region (point)
1410 (save-excursion (forward-line) (point)))
1411 (setq in-button t))
1412 (t (setq can-move-forward (= (forward-line) 0))))))
1413
1414 ;; Return the contents without properties... This gets rid of emphasis
1415 ;; and smileys
1416 (buffer-substring-no-properties (point-min) (point-max))))
c26cf6c8
RS
1417
1418(defun mh-insert-prefix-string (mh-ins-string)
bdcfe844
BW
1419 "Insert prefix string before each line in buffer.
1420The inserted letter is cited using `sc-cite-original' if
1421`mh-yank-from-start-of-msg' is one of 'supercite or 'autosupercite. Otherwise,
1422simply insert MH-INS-STRING before each line."
847b8219 1423 (goto-char (point-min))
bdcfe844
BW
1424 (cond ((or (eq mh-yank-from-start-of-msg 'supercite)
1425 (eq mh-yank-from-start-of-msg 'autosupercite))
1426 (sc-cite-original))
1427 (mail-citation-hook
c3d9274a
BW
1428 (run-hooks 'mail-citation-hook))
1429 (mh-yank-hooks ;old hook name
1430 (run-hooks 'mh-yank-hooks))
1431 (t
1432 (or (bolp) (forward-line 1))
bdcfe844
BW
1433 (while (< (point) (point-max))
1434 (insert mh-ins-string)
1435 (forward-line 1))
1436 (goto-char (point-min))))) ;leave point like sc-cite-original
c26cf6c8 1437
c3d9274a 1438;;;###mh-autoload
c26cf6c8
RS
1439(defun mh-fully-kill-draft ()
1440 "Kill the draft message file and the draft message buffer.
1441Use \\[kill-buffer] if you don't want to delete the draft message file."
1442 (interactive)
1443 (if (y-or-n-p "Kill draft message? ")
1444 (let ((config mh-previous-window-config))
c3d9274a
BW
1445 (if (file-exists-p buffer-file-name)
1446 (delete-file buffer-file-name))
1447 (set-buffer-modified-p nil)
1448 (kill-buffer (buffer-name))
1449 (message "")
1450 (if config
1451 (set-window-configuration config)))
c26cf6c8
RS
1452 (error "Message not killed")))
1453
a1b4049d 1454(defun mh-current-fill-prefix ()
bdcfe844 1455 "Return the `fill-prefix' on the current line as a string."
a1b4049d
BW
1456 (save-excursion
1457 (beginning-of-line)
1458 ;; This assumes that the major-mode sets up adaptive-fill-regexp
1459 ;; correctly such as mh-letter-mode or sendmail.el's mail-mode. But
1460 ;; perhaps I should use the variable and simply inserts its value here,
1461 ;; and set it locally in a let scope. --psg
1462 (if (re-search-forward adaptive-fill-regexp nil t)
1463 (match-string 0)
1464 "")))
1465
c3d9274a 1466;;;###mh-autoload
a1b4049d
BW
1467(defun mh-open-line ()
1468 "Insert a newline and leave point after it.
1469In addition, insert newline and quoting characters before text after point.
1470This is useful in breaking up paragraphs in replies."
1471 (interactive)
1472 (let ((column (current-column))
a1b4049d
BW
1473 (prefix (mh-current-fill-prefix)))
1474 (if (> (length prefix) column)
1475 (message "Sorry, point seems to be within the line prefix")
1476 (newline 2)
1477 (insert prefix)
1478 (while (> column (current-column))
1479 (insert " "))
1480 (forward-line -1))))
847b8219 1481
924df208
BW
1482(mh-do-in-xemacs (defvar mail-abbrevs))
1483
1484(defun mh-folder-expand-at-point ()
1485 "Do folder name completion in Fcc header field."
1486 (let* ((end (point))
1487 (syntax-table (syntax-table))
1488 (beg (unwind-protect
1489 (save-excursion
1490 (mh-funcall-if-exists mail-abbrev-make-syntax-table)
1491 (set-syntax-table mail-abbrev-syntax-table)
1492 (backward-word 1)
1493 (point))
1494 (set-syntax-table syntax-table)))
1495 (folder (buffer-substring beg end))
1496 (leading-plus (and (> (length folder) 0) (equal (aref folder 0) ?+)))
1497 (last-slash (mh-search-from-end ?/ folder))
1498 (prefix (and last-slash (substring folder 0 last-slash)))
1499 (mail-abbrevs
1500 (mapcar #'(lambda (x)
1501 (list (cond (prefix (format "%s/%s" prefix x))
1502 (leading-plus (format "+%s" x))
1503 (t x))))
1504 (mh-folder-completion-function folder nil t))))
1505 (if (fboundp 'mail-abbrev-complete-alias)
1506 (mh-funcall-if-exists mail-abbrev-complete-alias)
1507 (error "Fcc completion not supported in your version of Emacs"))))
1508
c3d9274a
BW
1509;;;###mh-autoload
1510(defun mh-letter-complete (arg)
1511 "Perform completion on header field or word preceding point.
1512Alias completion is done within the mail header on selected fields and
1513by the function designated by `mh-letter-complete-function' elsewhere,
1514passing the prefix ARG if any."
1515 (interactive "P")
1516 (let ((case-fold-search t))
924df208
BW
1517 (cond
1518 ((and (mh-in-header-p)
1519 (save-excursion
1520 (mh-header-field-beginning)
1521 (looking-at "^fcc:")))
1522 (mh-folder-expand-at-point))
1523 ((and (mh-in-header-p)
1524 (save-excursion
1525 (mh-header-field-beginning)
1526 (looking-at "^.*\\(to\\|cc\\|from\\):")))
1527 (mh-alias-letter-expand-alias))
1528 (t
1529 (funcall mh-letter-complete-function arg)))))
a1506d29 1530
a1b4049d 1531;;; Build the letter-mode keymap:
bdcfe844 1532;;; If this changes, modify mh-letter-mode-help-messages accordingly, above.
a1b4049d 1533(gnus-define-keys mh-letter-mode-map
c3d9274a
BW
1534 "\C-c?" mh-help
1535 "\C-c\C-c" mh-send-letter
1536 "\C-c\C-d" mh-insert-identity
1537 "\C-c\C-e" mh-edit-mhn
1538 "\C-c\C-f\C-b" mh-to-field
1539 "\C-c\C-f\C-c" mh-to-field
1540 "\C-c\C-f\C-d" mh-to-field
1541 "\C-c\C-f\C-f" mh-to-fcc
1542 "\C-c\C-f\C-r" mh-to-field
1543 "\C-c\C-f\C-s" mh-to-field
1544 "\C-c\C-f\C-t" mh-to-field
1545 "\C-c\C-fb" mh-to-field
1546 "\C-c\C-fc" mh-to-field
1547 "\C-c\C-fd" mh-to-field
1548 "\C-c\C-ff" mh-to-fcc
1549 "\C-c\C-fr" mh-to-field
1550 "\C-c\C-fs" mh-to-field
1551 "\C-c\C-ft" mh-to-field
1552 "\C-c\C-i" mh-insert-letter
1553 "\C-c\C-m\C-e" mh-mml-secure-message-encrypt-pgpmime
1554 "\C-c\C-m\C-f" mh-compose-forward
1555 "\C-c\C-m\C-i" mh-compose-insertion
1556 "\C-c\C-m\C-m" mh-mml-to-mime
1557 "\C-c\C-m\C-s" mh-mml-secure-message-sign-pgpmime
1558 "\C-c\C-m\C-u" mh-revert-mhn-edit
1559 "\C-c\C-me" mh-mml-secure-message-encrypt-pgpmime
1560 "\C-c\C-mf" mh-compose-forward
1561 "\C-c\C-mi" mh-compose-insertion
1562 "\C-c\C-mm" mh-mml-to-mime
1563 "\C-c\C-ms" mh-mml-secure-message-sign-pgpmime
1564 "\C-c\C-mu" mh-revert-mhn-edit
1565 "\C-c\C-o" mh-open-line
1566 "\C-c\C-q" mh-fully-kill-draft
1567 "\C-c\C-\\" mh-fully-kill-draft ;if no C-q
1568 "\C-c\C-s" mh-insert-signature
1569 "\C-c\C-^" mh-insert-signature ;if no C-s
1570 "\C-c\C-w" mh-check-whom
1571 "\C-c\C-y" mh-yank-cur-msg
1572 "\M-\t" mh-letter-complete)
a1b4049d
BW
1573
1574;; "C-c /" prefix is used in mh-letter-mode by pgp.el and mailcrypt.el.
1575
924df208
BW
1576;;;###autoload(add-to-list 'auto-mode-alist '("/drafts/[0-9]+\\'" . mh-letter-mode))
1577
bdcfe844
BW
1578(provide 'mh-comp)
1579
1580;;; Local Variables:
c3d9274a 1581;;; indent-tabs-mode: nil
bdcfe844
BW
1582;;; sentence-end-double-space: nil
1583;;; End:
60370d40 1584
6b61353c 1585;;; arch-tag: 62865511-e610-4923-b0b5-f45a8ab70a34
60370d40 1586;;; mh-comp.el ends here