*** empty log message ***
[bpt/emacs.git] / lisp / mail / mh-comp.el
CommitLineData
c26cf6c8 1;;; mh-comp --- mh-e functions for composing messages
283b03f4 2;; Time-stamp: <95/08/19 17:48:59 gildea>
c26cf6c8 3
20f0de75 4;; Copyright (C) 1993, 1995, 1997 Free Software Foundation, Inc.
c26cf6c8 5
283b03f4 6;; This file is part of mh-e, part of GNU Emacs.
c26cf6c8 7
9b7bc076 8;; GNU Emacs is free software; you can redistribute it and/or modify
c26cf6c8
RS
9;; it under the terms of the GNU General Public License as published by
10;; the Free Software Foundation; either version 2, or (at your option)
11;; any later version.
12
9b7bc076 13;; GNU Emacs is distributed in the hope that it will be useful,
c26cf6c8
RS
14;; but WITHOUT ANY WARRANTY; without even the implied warranty of
15;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16;; GNU General Public License for more details.
17
18;; You should have received a copy of the GNU General Public License
b578f267
EN
19;; along with GNU Emacs; see the file COPYING. If not, write to the
20;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21;; Boston, MA 02111-1307, USA.
c26cf6c8
RS
22
23;;; Commentary:
24
25;; Internal support for mh-e package.
26
847b8219
KH
27;;; Change Log:
28
41b9a988 29;; $Id: mh-comp.el,v 1.14 1999/03/01 03:47:07 kwzh Exp rms $
847b8219 30
c26cf6c8
RS
31;;; Code:
32
33(provide 'mh-comp)
34(require 'mh-utils)
35
847b8219
KH
36;;; Site customization (see also mh-utils.el):
37
20f0de75
RS
38(defgroup mh-compose nil
39 "Mh-e functions for composing messages"
40 :prefix "mh-"
41 :group 'mh)
42
43
847b8219
KH
44(defvar mh-send-prog "send"
45 "Name of the MH send program.
46Some sites need to change this because of a name conflict.")
47
48(defvar mh-redist-full-contents nil
49 "Non-nil if the `dist' command needs whole letter for redistribution.
50This is the case only when `send' is compiled with the BERK option.
51If MH will not allow you to redist a previously redist'd msg, set to nil.")
52
53
c26cf6c8
RS
54(defvar mh-note-repl "-"
55 "String whose first character is used to notate replied to messages.")
56
57(defvar mh-note-forw "F"
58 "String whose first character is used to notate forwarded messages.")
59
60(defvar mh-note-dist "R"
61 "String whose first character is used to notate redistributed messages.")
62
c26cf6c8
RS
63(defvar mh-yank-hooks nil
64 "Obsolete hook for modifying a citation just inserted in the mail buffer.
65Each hook function can find the citation between point and mark.
66And each hook function should leave point and mark around the citation
67text as modified.
68
69This is a normal hook, misnamed for historical reasons.
1838eb6c 70It is semi-obsolete and is only used if `mail-citation-hook' is nil.")
c26cf6c8
RS
71
72(defvar mail-citation-hook nil
73 "*Hook for modifying a citation just inserted in the mail buffer.
74Each hook function can find the citation between point and mark.
75And each hook function should leave point and mark around the citation
76text as modified.
77
78If this hook is entirely empty (nil), the text of the message is inserted
1838eb6c 79with `mh-ins-buf-prefix' prefixed to each line.
c26cf6c8 80
1838eb6c 81See also the variable `mh-yank-from-start-of-msg', which controls how
c26cf6c8
RS
82much of the message passed to the hook.")
83
84;;; Copied from sendmail.el for Hyperbole
85(defvar mail-header-separator "--------"
86 "*Line used by MH to separate headers from text in messages being composed.")
87
88;;; Personal preferences:
89
20f0de75 90(defcustom mh-delete-yanked-msg-window nil
c26cf6c8
RS
91 "*Controls window display when a message is yanked by \\<mh-letter-mode-map>\\[mh-yank-cur-msg].
92If non-nil, yanking the current message into a draft letter deletes any
20f0de75
RS
93windows displaying the message."
94 :type 'boolean
95 :group 'mh-compose)
c26cf6c8 96
20f0de75 97(defcustom mh-yank-from-start-of-msg t
c26cf6c8
RS
98 "*Controls which part of a message is yanked by \\<mh-letter-mode-map>\\[mh-yank-cur-msg].
99If non-nil, include the entire message. If the symbol `body', then yank the
100message minus the header. If nil, yank only the portion of the message
101following the point. If the show buffer has a region, this variable is
20f0de75 102ignored."
a6639a16
AS
103 :type '(choice (const :tag "Below point" nil)
104 (const :tag "Without header" body)
105 (other :tag "Entire message" t))
20f0de75 106 :group 'mh-compose)
c26cf6c8 107
20f0de75 108(defcustom mh-ins-buf-prefix "> "
847b8219
KH
109 "*String to put before each non-blank line of a yanked or inserted message.
110\\<mh-letter-mode-map>Used when the message is inserted into an outgoing letter
20f0de75
RS
111by \\[mh-insert-letter] or \\[mh-yank-cur-msg]."
112 :type 'string
113 :group 'mh-compose)
847b8219 114
20f0de75 115(defcustom mh-reply-default-reply-to nil
c26cf6c8
RS
116 "*Sets the person or persons to whom a reply will be sent.
117If nil, prompt for recipient. If non-nil, then \\<mh-folder-mode-map>`\\[mh-reply]' will use this
847b8219 118value and it should be one of \"from\", \"to\", \"cc\", or \"all\".
20f0de75
RS
119The values \"cc\" and \"all\" do the same thing."
120 :type '(choice (const :tag "Prompt" nil)
121 (const "from") (const "to")
122 (const "cc") (const "all"))
123 :group 'mh-compose)
c26cf6c8 124
20f0de75 125(defcustom mh-signature-file-name "~/.signature"
c26cf6c8 126 "*Name of file containing the user's signature.
20f0de75
RS
127Inserted into message by \\<mh-letter-mode-map>\\[mh-insert-signature]."
128 :type 'file
129 :group 'mh-compose)
c26cf6c8 130
20f0de75 131(defcustom mh-forward-subject-format "%s: %s"
c26cf6c8
RS
132 "*Format to generate the Subject: line contents for a forwarded message.
133The two string arguments to the format are the sender of the original
20f0de75
RS
134message and the original subject line."
135 :type 'string
136 :group 'mh-compose)
c26cf6c8
RS
137
138(defvar mh-comp-formfile "components"
139 "Name of file to be used as a skeleton for composing messages.
1838eb6c 140Default is \"components\". If not an absolute file name, the file
c26cf6c8
RS
141is searched for first in the user's MH directory, then in the
142system MH lib directory.")
143
847b8219
KH
144(defvar mh-repl-formfile "replcomps"
145 "Name of file to be used as a skeleton for replying to messages.
1838eb6c 146Default is \"replcomps\". If not an absolute file name, the file
847b8219
KH
147is searched for first in the user's MH directory, then in the
148system MH lib directory.")
149
c3d6278e
KH
150(defvar mh-repl-group-formfile "replgroupcomps"
151 "Name of file to be used as a skeleton for replying to the sender
152and all recipients of a messages. Only used if mh-nmh-p is non-nil.
153Default is \"replgroupcomps\". If not an absolute file name, the file
154is searched for first in the user's MH directory, then in the system
155MH lib directory.")
156
c26cf6c8
RS
157;;; Hooks:
158
20f0de75
RS
159(defcustom mh-letter-mode-hook nil
160 "Invoked in `mh-letter-mode' on a new letter."
161 :type 'hook
162 :group 'mh-compose)
c26cf6c8 163
20f0de75 164(defcustom mh-compose-letter-function nil
847b8219 165 "Invoked when setting up a letter draft.
20f0de75
RS
166It is passed three arguments: TO recipients, SUBJECT, and CC recipients."
167 :type 'function
168 :group 'mh-compose)
169
170(defcustom mh-before-send-letter-hook nil
171 "Invoked at the beginning of the \\<mh-letter-mode-map>\\[mh-send-letter] command."
172 :type 'hook
173 :group 'mh-compose)
c26cf6c8
RS
174
175
176(defvar mh-rejected-letter-start
847b8219
KH
177 (concat "^ ----- Unsent message follows -----$" ;from sendmail V5
178 "\\|^ ----- Original message follows -----$" ;from sendmail V8
179 "\\|^------- Unsent Draft$" ;from MH itself
c26cf6c8 180 "\\|^---------- Original Message ----------$" ;from zmailer
847b8219
KH
181 "\\|^ --- The unsent message follows ---$" ;from AIX mail system
182 "\\|^ Your message follows:$" ;from MMDF-II
183 "\\|^Content-Description: Returned Content$" ;1993 KJ sendmail
184 )
c26cf6c8
RS
185 "Regexp specifying the beginning of the wrapper around a returned letter.
186This wrapper is generated by the mail system when rejecting a letter.")
187
188(defvar mh-new-draft-cleaned-headers
847b8219 189 "^Date:\\|^Received:\\|^Message-Id:\\|^From:\\|^Sender:\\|^Errors-To:\\|^Delivery-Date:\\|^Return-Path:"
c26cf6c8
RS
190 "Regexp of header lines to remove before offering a message as a new draft.
191Used by the \\<mh-folder-mode-map>`\\[mh-edit-again]' and `\\[mh-extract-rejected-mail]' commands.")
192
847b8219
KH
193(defvar mh-to-field-choices '(("t" . "To:") ("s" . "Subject:") ("c" . "Cc:")
194 ("b" . "Bcc:") ("f" . "Fcc:") ("r" . "From:")
195 ("d" . "Dcc:"))
c26cf6c8
RS
196 "Alist of (final-character . field-name) choices for mh-to-field.")
197
198(defvar mh-letter-mode-map (copy-keymap text-mode-map)
199 "Keymap for composing mail.")
200
201(defvar mh-letter-mode-syntax-table nil
202 "Syntax table used by mh-e while in MH-Letter mode.")
203
204(if mh-letter-mode-syntax-table
205 ()
206 (setq mh-letter-mode-syntax-table
207 (make-syntax-table text-mode-syntax-table))
208 (modify-syntax-entry ?% "." mh-letter-mode-syntax-table))
209
210
211;;;###autoload
212(defun mh-smail ()
213 "Compose and send mail with the MH mail system.
214This function is an entry point to mh-e, the Emacs front end
847b8219
KH
215to the MH mail system.
216
217See documentation of `\\[mh-send]' for more details on composing mail."
c26cf6c8
RS
218 (interactive)
219 (mh-find-path)
220 (call-interactively 'mh-send))
221
222
283b03f4
KH
223(defvar mh-error-if-no-draft nil) ;raise error over using old draft
224
225
226;;;###autoload
c3d6278e 227(defun mh-smail-batch (&optional to subject other-headers &rest ignored)
283b03f4
KH
228 "Set up a mail composition draft with the MH mail system.
229This function is an entry point to mh-e, the Emacs front end
230to the MH mail system. This function does not prompt the user
231for any header fields, and thus is suitable for use by programs
232that want to create a mail buffer.
233Users should use `\\[mh-smail]' to compose mail."
234 (mh-find-path)
235 (let ((mh-error-if-no-draft t))
c3d6278e 236 (mh-send to "" subject)))
283b03f4
KH
237
238
c26cf6c8
RS
239(defun mh-edit-again (msg)
240 "Clean-up a draft or a message previously sent and make it resendable.
847b8219 241Default is the current message.
c26cf6c8
RS
242The variable mh-new-draft-cleaned-headers specifies the headers to remove.
243See also documentation for `\\[mh-send]' function."
244 (interactive (list (mh-get-msg-num t)))
245 (let* ((from-folder mh-current-folder)
246 (config (current-window-configuration))
247 (draft
248 (cond ((and mh-draft-folder (equal from-folder mh-draft-folder))
249 (pop-to-buffer (find-file-noselect (mh-msg-filename msg)) t)
250 (rename-buffer (format "draft-%d" msg))
251 (buffer-name))
252 (t
253 (mh-read-draft "clean-up" (mh-msg-filename msg) nil)))))
254 (mh-clean-msg-header (point-min) mh-new-draft-cleaned-headers nil)
255 (goto-char (point-min))
283b03f4 256 (save-buffer)
c26cf6c8
RS
257 (mh-compose-and-send-mail draft "" from-folder nil nil nil nil nil nil
258 config)))
259
260
261(defun mh-extract-rejected-mail (msg)
262 "Extract a letter returned by the mail system and make it resendable.
1838eb6c 263Default is the current message. The variable `mh-new-draft-cleaned-headers'
c26cf6c8
RS
264gives the headers to clean out of the original message.
265See also documentation for `\\[mh-send]' function."
266 (interactive (list (mh-get-msg-num t)))
267 (let ((from-folder mh-current-folder)
268 (config (current-window-configuration))
269 (draft (mh-read-draft "extraction" (mh-msg-filename msg) nil)))
270 (goto-char (point-min))
271 (cond ((re-search-forward mh-rejected-letter-start nil t)
272 (skip-chars-forward " \t\n")
273 (delete-region (point-min) (point))
274 (mh-clean-msg-header (point-min) mh-new-draft-cleaned-headers nil))
275 (t
276 (message "Does not appear to be a rejected letter.")))
277 (goto-char (point-min))
283b03f4 278 (save-buffer)
847b8219
KH
279 (mh-compose-and-send-mail draft "" from-folder msg
280 (mh-get-header-field "To:")
281 (mh-get-header-field "From:")
282 (mh-get-header-field "Cc:")
c26cf6c8
RS
283 nil nil config)))
284
285
286(defun mh-forward (to cc &optional msg-or-seq)
287 "Forward a message or message sequence. Defaults to displayed message.
288If optional prefix argument provided, then prompt for the message sequence.
289See also documentation for `\\[mh-send]' function."
290 (interactive (list (mh-read-address "To: ")
291 (mh-read-address "Cc: ")
292 (if current-prefix-arg
293 (mh-read-seq-default "Forward" t)
847b8219 294 (mh-get-msg-num t))))
c26cf6c8
RS
295 (or msg-or-seq
296 (setq msg-or-seq (mh-get-msg-num t)))
297 (let* ((folder mh-current-folder)
298 (config (current-window-configuration))
299 ;; forw always leaves file in "draft" since it doesn't have -draft
300 (draft-name (expand-file-name "draft" mh-user-path))
301 (draft (cond ((or (not (file-exists-p draft-name))
302 (y-or-n-p "The file 'draft' exists. Discard it? "))
847b8219
KH
303 (mh-exec-cmd "forw" "-build"
304 mh-current-folder msg-or-seq)
c26cf6c8
RS
305 (prog1
306 (mh-read-draft "" draft-name t)
307 (mh-insert-fields "To:" to "Cc:" cc)
283b03f4 308 (save-buffer)))
c26cf6c8 309 (t
41b9a988
RS
310 (mh-read-draft "" draft-name nil))))
311 (fwd-msg-file (mh-msg-filename (if (numberp msg-or-seq)
312 msg-or-seq
313 (car (mh-seq-to-msgs msg-or-seq)))
314 folder)))
847b8219
KH
315 (let (orig-from
316 orig-subject)
41b9a988
RS
317 (save-excursion
318 (set-buffer (get-buffer-create mh-temp-buffer))
319 (erase-buffer)
320 (insert-file-contents fwd-msg-file)
847b8219
KH
321 (setq orig-from (mh-get-header-field "From:"))
322 (setq orig-subject (mh-get-header-field "Subject:")))
c26cf6c8
RS
323 (let ((forw-subject
324 (mh-forwarded-letter-subject orig-from orig-subject)))
847b8219
KH
325 (mh-insert-fields "Subject:" forw-subject)
326 (goto-char (point-min))
41b9a988
RS
327 (if (re-search-forward "^------- Forwarded Message" nil t)
328 (forward-line -1)
329 (re-search-forward "^--------")
330 (forward-line 1))
847b8219
KH
331 (delete-other-windows)
332 (if (numberp msg-or-seq)
333 (mh-add-msgs-to-seq msg-or-seq 'forwarded t)
c26cf6c8 334 (mh-add-msgs-to-seq (mh-seq-to-msgs msg-or-seq) 'forwarded t))
847b8219
KH
335 (mh-compose-and-send-mail draft "" folder msg-or-seq
336 to forw-subject cc
337 mh-note-forw "Forwarded:"
338 config)))))
c26cf6c8
RS
339
340(defun mh-forwarded-letter-subject (from subject)
341 ;; Return a Subject suitable for a forwarded message.
342 ;; Original message has headers FROM and SUBJECT.
343 (let ((addr-start (string-match "<" from))
344 (comment (string-match "(" from)))
345 (cond ((and addr-start (> addr-start 0))
346 ;; Full Name <luser@host>
347 (setq from (substring from 0 (1- addr-start))))
348 (comment
349 ;; luser@host (Full Name)
350 (setq from (substring from (1+ comment) (1- (length from)))))))
351 (format mh-forward-subject-format from subject))
352
353
354;;;###autoload
355(defun mh-smail-other-window ()
356 "Compose and send mail in other window with the MH mail system.
357This function is an entry point to mh-e, the Emacs front end
847b8219
KH
358to the MH mail system.
359
360See documentation of `\\[mh-send]' for more details on composing mail."
c26cf6c8
RS
361 (interactive)
362 (mh-find-path)
363 (call-interactively 'mh-send-other-window))
364
365
366(defun mh-redistribute (to cc &optional msg)
367 "Redistribute a letter.
368Depending on how your copy of MH was compiled, you may need to change the
1838eb6c 369setting of the variable `mh-redist-full-contents'. See its documentation."
c26cf6c8
RS
370 (interactive (list (mh-read-address "Redist-To: ")
371 (mh-read-address "Redist-Cc: ")
372 (mh-get-msg-num t)))
373 (or msg
374 (setq msg (mh-get-msg-num t)))
375 (save-window-excursion
376 (let ((folder mh-current-folder)
377 (draft (mh-read-draft "redistribution"
378 (if mh-redist-full-contents
379 (mh-msg-filename msg)
380 nil)
381 nil)))
382 (mh-goto-header-end 0)
383 (insert "Resent-To: " to "\n")
384 (if (not (equal cc "")) (insert "Resent-cc: " cc "\n"))
385 (mh-clean-msg-header (point-min)
386 "^Message-Id:\\|^Received:\\|^Return-Path:\\|^Sender:\\|^Date:\\|^From:"
387 nil)
388 (save-buffer)
389 (message "Redistributing...")
390 (if mh-redist-full-contents
391 (call-process "/bin/sh" nil 0 nil "-c"
392 (format "mhdist=1 mhaltmsg=%s %s -push %s"
847b8219 393 buffer-file-name
c26cf6c8 394 (expand-file-name mh-send-prog mh-progs)
847b8219 395 buffer-file-name))
c26cf6c8
RS
396 (call-process "/bin/sh" nil 0 nil "-c"
397 (format "mhdist=1 mhaltmsg=%s mhannotate=1 %s -push %s"
398 (mh-msg-filename msg folder)
399 (expand-file-name mh-send-prog mh-progs)
847b8219 400 buffer-file-name)))
c26cf6c8
RS
401 (mh-annotate-msg msg folder mh-note-dist
402 "-component" "Resent:"
403 "-text" (format "\"%s %s\"" to cc))
404 (kill-buffer draft)
405 (message "Redistributing...done"))))
406
407
847b8219
KH
408(defun mh-reply (message &optional includep)
409 "Reply to MESSAGE (default: current message).
c26cf6c8 410If optional prefix argument INCLUDEP provided, then include the message
1838eb6c 411in the reply using filter `mhl.reply' in your MH directory.
c26cf6c8
RS
412Prompts for type of addresses to reply to:
413 from sender only,
414 to sender and primary recipients,
415 cc/all sender and all recipients.
847b8219
KH
416If the file named by `mh-repl-formfile' exists, it is used as a skeleton
417for the reply. See also documentation for `\\[mh-send]' function."
c26cf6c8
RS
418 (interactive (list (mh-get-msg-num t) current-prefix-arg))
419 (let ((minibuffer-help-form
420 "from => Sender only\nto => Sender and primary recipients\ncc or all => Sender and all recipients"))
c3d6278e 421 (let* ((reply-to (or mh-reply-default-reply-to
c26cf6c8
RS
422 (completing-read "Reply to whom: "
423 '(("from") ("to") ("cc") ("all"))
424 nil
425 t)))
c3d6278e
KH
426 (folder mh-current-folder)
427 (show-buffer mh-show-buffer)
428 (config (current-window-configuration))
429 (group-reply (or (equal reply-to "cc") (equal reply-to "all")))
430 (form-file (cond ((and mh-nmh-p group-reply
431 (stringp mh-repl-group-formfile))
432 mh-repl-group-formfile)
433 ((stringp mh-repl-formfile) mh-repl-formfile)
434 (t nil))))
c26cf6c8
RS
435 (message "Composing a reply...")
436 (mh-exec-cmd "repl" "-build" "-noquery" "-nodraftfolder"
c3d6278e
KH
437 (if form-file
438 (list "-form" form-file))
847b8219 439 mh-current-folder message
c26cf6c8
RS
440 (cond ((or (equal reply-to "from") (equal reply-to ""))
441 '("-nocc" "all"))
442 ((equal reply-to "to")
443 '("-cc" "to"))
c3d6278e
KH
444 (group-reply (if mh-nmh-p
445 '("-group" "-nocc" "me")
446 '("-cc" "all" "-nocc" "me"))))
c26cf6c8
RS
447 (if includep
448 '("-filter" "mhl.reply")))
449 (let ((draft (mh-read-draft "reply"
450 (expand-file-name "reply" mh-user-path)
451 t)))
452 (delete-other-windows)
283b03f4 453 (save-buffer)
c26cf6c8 454
847b8219
KH
455 (let ((to (mh-get-header-field "To:"))
456 (subject (mh-get-header-field "Subject:"))
457 (cc (mh-get-header-field "Cc:")))
c26cf6c8
RS
458 (goto-char (point-min))
459 (mh-goto-header-end 1)
460 (or includep
461 (mh-in-show-buffer (show-buffer)
847b8219
KH
462 (mh-display-msg message folder)))
463 (mh-add-msgs-to-seq message 'answered t)
c26cf6c8 464 (message "Composing a reply...done")
847b8219 465 (mh-compose-and-send-mail draft "" folder message to subject cc
c26cf6c8
RS
466 mh-note-repl "Replied:" config))))))
467
468
469(defun mh-send (to cc subject)
470 "Compose and send a letter.
471The file named by `mh-comp-formfile' will be used as the form.
847b8219
KH
472Do not call this function from outside mh-e; use \\[mh-smail] instead.
473
c26cf6c8
RS
474The letter is composed in mh-letter-mode; see its documentation for more
475details. If `mh-compose-letter-function' is defined, it is called on the
1838eb6c 476draft and passed three arguments: TO, SUBJECT, and CC."
c26cf6c8
RS
477 (interactive (list
478 (mh-read-address "To: ")
479 (mh-read-address "Cc: ")
480 (read-string "Subject: ")))
481 (let ((config (current-window-configuration)))
482 (delete-other-windows)
483 (mh-send-sub to cc subject config)))
484
485
486(defun mh-send-other-window (to cc subject)
487 "Compose and send a letter in another window.
488Do not call this function from outside mh-e;
489use \\[mh-smail-other-window] instead.
490See also documentation for `\\[mh-send]' function."
491 (interactive (list
492 (mh-read-address "To: ")
493 (mh-read-address "Cc: ")
494 (read-string "Subject: ")))
495 (let ((pop-up-windows t))
496 (mh-send-sub to cc subject (current-window-configuration))))
497
498
499(defun mh-send-sub (to cc subject config)
847b8219
KH
500 ;; Do the real work of composing and sending a letter.
501 ;; Expects the TO, CC, and SUBJECT fields as arguments.
502 ;; CONFIG is the window configuration before sending mail.
c26cf6c8
RS
503 (let ((folder mh-current-folder)
504 (msg-num (mh-get-msg-num nil)))
505 (message "Composing a message...")
506 (let ((draft (mh-read-draft
507 "message"
508 (let (components)
509 (cond
510 ((file-exists-p
511 (setq components
512 (expand-file-name mh-comp-formfile mh-user-path)))
513 components)
514 ((file-exists-p
515 (setq components
516 (expand-file-name mh-comp-formfile mh-lib)))
517 components)
518 (t
519 (error (format "Can't find components file \"%s\""
520 components)))))
521 nil)))
522 (mh-insert-fields "To:" to "Subject:" subject "Cc:" cc)
523 (goto-char (point-max))
524 (message "Composing a message...done")
525 (mh-compose-and-send-mail draft "" folder msg-num
526 to subject cc
527 nil nil config))))
528
529
530(defun mh-read-draft (use initial-contents delete-contents-file)
531 ;; Read draft file into a draft buffer and make that buffer the current one.
532 ;; USE is a message used for prompting about the intended use of the message.
533 ;; INITIAL-CONTENTS is filename that is read into an empty buffer, or NIL
534 ;; if buffer should not be modified. Delete the initial-contents file if
535 ;; DELETE-CONTENTS-FILE flag is set.
536 ;; Returns the draft folder's name.
537 ;; If the draft folder facility is enabled in ~/.mh_profile, a new buffer is
538 ;; used each time and saved in the draft folder. The draft file can then be
539 ;; reused.
540 (cond (mh-draft-folder
541 (let ((orig-default-dir default-directory)
542 (draft-file-name (mh-new-draft-name)))
543 (pop-to-buffer (generate-new-buffer
544 (format "draft-%s"
545 (file-name-nondirectory draft-file-name))))
546 (condition-case ()
547 (insert-file-contents draft-file-name t)
548 (file-error))
549 (setq default-directory orig-default-dir)))
550 (t
551 (let ((draft-name (expand-file-name "draft" mh-user-path)))
552 (pop-to-buffer "draft") ; Create if necessary
553 (if (buffer-modified-p)
554 (if (y-or-n-p "Draft has been modified; kill anyway? ")
555 (set-buffer-modified-p nil)
556 (error "Draft preserved")))
557 (setq buffer-file-name draft-name)
558 (clear-visited-file-modtime)
559 (unlock-buffer)
560 (cond ((and (file-exists-p draft-name)
561 (not (equal draft-name initial-contents)))
562 (insert-file-contents draft-name)
563 (delete-file draft-name))))))
564 (cond ((and initial-contents
565 (or (zerop (buffer-size))
283b03f4
KH
566 (if (y-or-n-p
567 (format "A draft exists. Use for %s? " use))
568 (if mh-error-if-no-draft
569 (error "A prior draft exists."))
570 t)))
c26cf6c8
RS
571 (erase-buffer)
572 (insert-file-contents initial-contents)
573 (if delete-contents-file (delete-file initial-contents))))
574 (auto-save-mode 1)
575 (if mh-draft-folder
576 (save-buffer)) ; Do not reuse draft name
577 (buffer-name))
578
579
580(defun mh-new-draft-name ()
581 ;; Returns the pathname of folder for draft messages.
582 (save-excursion
583 (mh-exec-cmd-quiet t "mhpath" mh-draft-folder "new")
584 (buffer-substring (point-min) (1- (point-max)))))
585
586
587(defun mh-annotate-msg (msg buffer note &rest args)
588 ;; Mark the MESSAGE in BUFFER listing with the character NOTE and annotate
589 ;; the saved message with ARGS.
590 (apply 'mh-exec-cmd "anno" buffer msg args)
591 (save-excursion
592 (cond ((get-buffer buffer) ; Buffer may be deleted
593 (set-buffer buffer)
594 (if (symbolp msg)
595 (mh-notate-seq msg note (1+ mh-cmd-note))
596 (mh-notate msg note (1+ mh-cmd-note)))))))
597
598
599(defun mh-insert-fields (&rest name-values)
600 ;; Insert the NAME-VALUE pairs in the current buffer.
601 ;; If field NAME exists, append VALUE to it.
602 ;; Do not insert any pairs whose value is the empty string.
603 (let ((case-fold-search t))
604 (while name-values
605 (let ((field-name (car name-values))
606 (value (car (cdr name-values))))
607 (cond ((equal value "")
608 nil)
609 ((mh-position-on-field field-name)
610 (insert " " value))
611 (t
612 (insert field-name " " value "\n")))
613 (setq name-values (cdr (cdr name-values)))))))
614
615
616(defun mh-position-on-field (field &optional ignore)
617 ;; Move to the end of the FIELD in the header.
618 ;; Move to end of entire header if FIELD not found.
619 ;; Returns non-nil iff FIELD was found.
620 ;; The optional second arg is for pre-version 4 compatibility.
847b8219
KH
621 (if (mh-goto-header-field field)
622 (progn
623 (mh-header-field-end)
624 t)))
625
626
627(defun mh-get-header-field (field)
628 ;; Find and return the body of FIELD in the mail header.
629 ;; Returns the empty string if the field is not in the header of the
630 ;; current buffer.
631 (if (mh-goto-header-field field)
632 (progn
633 (skip-chars-forward " \t") ;strip leading white space in body
634 (let ((start (point)))
635 (mh-header-field-end)
636 (buffer-substring start (point))))
637 ""))
638
639(fset 'mh-get-field 'mh-get-header-field) ;mh-e 4 compatibility
640
641(defun mh-goto-header-field (field)
642 ;; Move to FIELD in the message header.
643 ;; Move to the end of the FIELD name, which should end in a colon.
644 ;; Returns T if found, NIL if not.
645 (goto-char (point-min))
646 (let ((case-fold-search t)
647 (headers-end (save-excursion
648 (mh-goto-header-end 0)
649 (point))))
650 (re-search-forward (format "^%s" field) headers-end t)))
651
652(defun mh-header-field-end ()
653 ;; Move to the end of the current header field.
654 ;; Handles RFC 822 continuation lines.
655 (forward-line 1)
656 (while (looking-at "^[ \t]")
657 (forward-line 1))
658 (backward-char 1)) ;to end of previous line
659
c26cf6c8
RS
660
661(defun mh-goto-header-end (arg)
662 ;; Find the end of the message header in the current buffer and position
663 ;; the cursor at the ARG'th newline after the header.
9303c8db 664 (if (re-search-forward "^-*$" nil nil)
c26cf6c8
RS
665 (forward-line arg)))
666
667
668(defun mh-read-address (prompt)
669 ;; Read a To: or Cc: address, prompting in the minibuffer with PROMPT.
670 ;; May someday do completion on aliases.
671 (read-string prompt))
672
673\f
674
675;;; Mode for composing and sending a draft message.
676
847b8219 677(defvar mh-sent-from-folder nil) ;Folder of msg assoc with this letter.
c26cf6c8 678
847b8219 679(defvar mh-sent-from-msg nil) ;Number of msg assoc with this letter.
c26cf6c8 680
847b8219 681(defvar mh-send-args nil) ;Extra args to pass to "send" command.
c26cf6c8 682
847b8219 683(defvar mh-annotate-char nil) ;Character to use to annotate mh-sent-from-msg.
c26cf6c8 684
847b8219 685(defvar mh-annotate-field nil) ;Field name for message annotation.
c26cf6c8
RS
686
687(put 'mh-letter-mode 'mode-class 'special)
688
689;;;###autoload
690(defun mh-letter-mode ()
691 "Mode for composing letters in mh-e.\\<mh-letter-mode-map>
847b8219
KH
692When you have finished composing, type \\[mh-send-letter] to send the message
693using the MH mail handling system.
694See the documentation for \\[mh-edit-mhn] for information on composing MIME
695messages.
c26cf6c8
RS
696
697\\{mh-letter-mode-map}
698
699Variables controlling this mode (defaults in parentheses):
700
701 mh-delete-yanked-msg-window (nil)
702 If non-nil, \\[mh-yank-cur-msg] will delete any windows displaying
703 the yanked message.
704
705 mh-yank-from-start-of-msg (t)
706 If non-nil, \\[mh-yank-cur-msg] will include the entire message.
707 If `body', just yank the body (no header).
708 If nil, only the portion of the message following the point will be yanked.
709 If there is a region, this variable is ignored.
710
847b8219
KH
711 mh-ins-buf-prefix (\"> \")
712 String to insert before each non-blank line of a message as it is
713 inserted in a draft letter.
714
c26cf6c8
RS
715 mh-signature-file-name (\"~/.signature\")
716 File to be inserted into message by \\[mh-insert-signature].
717
1838eb6c 718This command runs the normal hooks `text-mode-hook' and `mh-letter-mode-hook'."
c26cf6c8
RS
719
720 (interactive)
721 (or mh-user-path (mh-find-path))
c26cf6c8 722 (make-local-variable 'paragraph-start)
847b8219 723 (setq paragraph-start (concat "^[ \t]*[-_][-_][-_]+$\\|" paragraph-start))
c26cf6c8
RS
724 (make-local-variable 'paragraph-separate)
725 (setq paragraph-separate
847b8219 726 (concat "^[ \t]*[-_][-_][-_]+$\\|" paragraph-separate))
c26cf6c8
RS
727 (make-local-variable 'mh-send-args)
728 (make-local-variable 'mh-annotate-char)
729 (make-local-variable 'mh-annotate-field)
730 (make-local-variable 'mh-previous-window-config)
731 (make-local-variable 'mh-sent-from-folder)
732 (make-local-variable 'mh-sent-from-msg)
733 (make-local-variable 'mail-header-separator)
734 (setq mail-header-separator "--------") ;for Hyperbole
735 (use-local-map mh-letter-mode-map)
736 (setq major-mode 'mh-letter-mode)
737 (mh-set-mode-name "MH-Letter")
738 (set-syntax-table mh-letter-mode-syntax-table)
739 (run-hooks 'text-mode-hook)
740 ;; if text-mode-hook turned on auto-fill, tune it for messages
741 (cond ((and (boundp 'auto-fill-hook) auto-fill-hook) ;emacs 18
742 (make-local-variable 'auto-fill-hook)
743 (setq auto-fill-hook 'mh-auto-fill-for-letter)))
744 (cond ((and (boundp 'auto-fill-function) auto-fill-function) ;emacs 19
745 (make-local-variable 'auto-fill-function)
746 (setq auto-fill-function 'mh-auto-fill-for-letter)))
747 (run-hooks 'mh-letter-mode-hook))
748
749
750(defun mh-auto-fill-for-letter ()
751 ;; Auto-fill in letters treats the header specially by inserting a tab
752 ;; before continuation line.
c26cf6c8 753 (if (mh-in-header-p)
9303c8db
KH
754 (let ((fill-prefix "\t"))
755 (do-auto-fill))
756 (do-auto-fill)))
c26cf6c8
RS
757
758
759(defun mh-in-header-p ()
760 ;; Return non-nil if the point is in the header of a draft message.
761 (save-excursion
762 (let ((cur-point (point)))
763 (goto-char (point-min))
764 (re-search-forward "^-*$" nil t)
765 (< cur-point (point)))))
766
767
768(defun mh-to-field ()
769 "Move point to the end of a specified header field.
770The field is indicated by the previous keystroke (the last keystroke
1838eb6c 771of the command) according to the list in the variable `mh-to-field-choices'.
c26cf6c8
RS
772Create the field if it does not exist. Set the mark to point before moving."
773 (interactive)
774 (expand-abbrev)
847b8219
KH
775 (let ((target (cdr (or (assoc (char-to-string (logior last-input-char ?`))
776 mh-to-field-choices)
777 ;; also look for a char for version 4 compat
778 (assoc (logior last-input-char ?`) mh-to-field-choices))))
c26cf6c8
RS
779 (case-fold-search t))
780 (push-mark)
781 (cond ((mh-position-on-field target)
782 (let ((eol (point)))
783 (skip-chars-backward " \t")
784 (delete-region (point) eol))
785 (if (and (not (eq (logior last-input-char ?`) ?s))
786 (save-excursion
787 (backward-char 1)
788 (not (looking-at "[:,]"))))
789 (insert ", ")
790 (insert " ")))
791 (t
792 (if (mh-position-on-field "To:")
793 (forward-line 1))
794 (insert (format "%s \n" target))
795 (backward-char 1)))))
796
797
798(defun mh-to-fcc (&optional folder)
799 "Insert an Fcc: FOLDER field in the current message.
800Prompt for the field name with a completion list of the current folders."
801 (interactive)
802 (or folder
803 (setq folder (mh-prompt-for-folder
804 "Fcc"
847b8219 805 (or (and mh-default-folder-for-message-function
c26cf6c8
RS
806 (save-excursion
807 (goto-char (point-min))
847b8219 808 (funcall mh-default-folder-for-message-function)))
c26cf6c8
RS
809 "")
810 t)))
811 (let ((last-input-char ?\C-f))
812 (expand-abbrev)
813 (save-excursion
814 (mh-to-field)
815 (insert (if (mh-folder-name-p folder)
816 (substring folder 1)
817 folder)))))
818
819
820(defun mh-insert-signature ()
1838eb6c 821 "Insert the file named by `mh-signature-file-name' at point."
c26cf6c8
RS
822 (interactive)
823 (insert-file-contents mh-signature-file-name)
2450bd29 824 (force-mode-line-update))
c26cf6c8
RS
825
826
827(defun mh-check-whom ()
847b8219 828 "Verify recipients of the current letter, showing expansion of any aliases."
c26cf6c8 829 (interactive)
847b8219 830 (let ((file-name buffer-file-name))
c26cf6c8
RS
831 (save-buffer)
832 (message "Checking recipients...")
833 (mh-in-show-buffer ("*Recipients*")
834 (bury-buffer (current-buffer))
835 (erase-buffer)
836 (mh-exec-cmd-output "whom" t file-name))
837 (message "Checking recipients...done")))
838
839\f
840
841;;; Routines to compose and send a letter.
842
843(defun mh-compose-and-send-mail (draft send-args
844 sent-from-folder sent-from-msg
845 to subject cc
846 annotate-char annotate-field
847 config)
848 ;; Edit and compose a draft message in buffer DRAFT and send or save it.
849 ;; SENT-FROM-FOLDER is buffer containing scan listing of current folder, or
850 ;; nil if none exists.
851 ;; SENT-FROM-MSG is the message number or sequence name or nil.
852 ;; SEND-ARGS is an optional argument passed to the send command.
853 ;; The TO, SUBJECT, and CC fields are passed to the
854 ;; mh-compose-letter-function.
855 ;; If ANNOTATE-CHAR is non-null, it is used to notate the scan listing of the
856 ;; message. In that case, the ANNOTATE-FIELD is used to build a string
857 ;; for mh-annotate-msg.
858 ;; CONFIG is the window configuration to restore after sending the letter.
859 (pop-to-buffer draft)
860 (mh-letter-mode)
861 (setq mh-sent-from-folder sent-from-folder)
862 (setq mh-sent-from-msg sent-from-msg)
863 (setq mh-send-args send-args)
864 (setq mh-annotate-char annotate-char)
865 (setq mh-annotate-field annotate-field)
866 (setq mh-previous-window-config config)
867 (setq mode-line-buffer-identification (list "{%b}"))
868 (if (and (boundp 'mh-compose-letter-function)
847b8219 869 mh-compose-letter-function)
c26cf6c8 870 ;; run-hooks will not pass arguments.
847b8219 871 (let ((value mh-compose-letter-function))
c26cf6c8
RS
872 (if (and (listp value) (not (eq (car value) 'lambda)))
873 (while value
874 (funcall (car value) to subject cc)
875 (setq value (cdr value)))
876 (funcall mh-compose-letter-function to subject cc)))))
877
878
879(defun mh-send-letter (&optional arg)
880 "Send the draft letter in the current buffer.
881If optional prefix argument is provided, monitor delivery.
1838eb6c 882Run `mh-before-send-letter-hook' before actually doing anything."
c26cf6c8
RS
883 (interactive "P")
884 (run-hooks 'mh-before-send-letter-hook)
c26cf6c8
RS
885 (save-buffer)
886 (message "Sending...")
887 (let ((draft-buffer (current-buffer))
847b8219 888 (file-name buffer-file-name)
1838eb6c
RS
889 (config mh-previous-window-config)
890 (coding-system-for-write
03d9b139
RS
891 (if (and (local-variable-p 'buffer-file-coding-system)
892 ;; We're not sure why, but buffer-file-coding-system
893 ;; tends to get set to undecided-unix.
894 (not (memq buffer-file-coding-system
895 '(undecided undecided-unix undecided-dos))))
1838eb6c
RS
896 buffer-file-coding-system
897 (or sendmail-coding-system
898 default-buffer-file-coding-system
899 'iso-latin-1))))
c26cf6c8
RS
900 (cond (arg
901 (pop-to-buffer "MH mail delivery")
902 (erase-buffer)
903 (mh-exec-cmd-output mh-send-prog t "-watch" "-nopush"
904 "-nodraftfolder" mh-send-args file-name)
905 (goto-char (point-max)) ; show the interesting part
906 (recenter -1)
907 (set-buffer draft-buffer)) ; for annotation below
908 (t
909 (mh-exec-cmd-daemon mh-send-prog "-nodraftfolder" "-noverbose"
910 mh-send-args file-name)))
911 (if mh-annotate-char
912 (mh-annotate-msg mh-sent-from-msg
913 mh-sent-from-folder
914 mh-annotate-char
915 "-component" mh-annotate-field
916 "-text" (format "\"%s %s\""
847b8219
KH
917 (mh-get-header-field "To:")
918 (mh-get-header-field "Cc:"))))
c26cf6c8
RS
919
920 (cond ((or (not arg)
921 (y-or-n-p "Kill draft buffer? "))
922 (kill-buffer draft-buffer)
923 (if config
924 (set-window-configuration config))))
925 (if arg
926 (message "Sending...done")
927 (message "Sending...backgrounded"))))
928
929
847b8219
KH
930(defun mh-insert-letter (folder message verbatim)
931 "Insert a message into the current letter.
1838eb6c
RS
932Removes the message's headers using `mh-invisible-headers'. Prefixes
933each non-blank line with `mh-ins-buf-prefix'. Prompts for FOLDER and
847b8219
KH
934MESSAGE. If prefix argument VERBATIM provided, do not indent and do
935not delete headers. Leaves the mark before the letter and point after it."
c26cf6c8 936 (interactive
847b8219
KH
937 (list (mh-prompt-for-folder "Message from" mh-sent-from-folder nil)
938 (read-input (format "Message number%s: "
c26cf6c8
RS
939 (if mh-sent-from-msg
940 (format " [%d]" mh-sent-from-msg)
847b8219 941 "")))
c26cf6c8
RS
942 current-prefix-arg))
943 (save-restriction
944 (narrow-to-region (point) (point))
945 (let ((start (point-min)))
847b8219 946 (if (equal message "") (setq message (int-to-string mh-sent-from-msg)))
c26cf6c8 947 (mh-exec-lib-cmd-output "mhl" "-nobell" "-noclear"
847b8219 948 (expand-file-name message
c26cf6c8 949 (mh-expand-file-name folder)))
847b8219 950 (cond ((not verbatim)
c26cf6c8
RS
951 (mh-clean-msg-header start mh-invisible-headers mh-visible-headers)
952 (set-mark start) ; since mh-clean-msg-header moves it
953 (mh-insert-prefix-string mh-ins-buf-prefix))))))
954
955
956(defun mh-yank-cur-msg ()
957 "Insert the current message into the draft buffer.
958Prefix each non-blank line in the message with the string in
959`mh-ins-buf-prefix'. If a region is set in the message's buffer, then
960only the region will be inserted. Otherwise, the entire message will
961be inserted if `mh-yank-from-start-of-msg' is non-nil. If this variable
962is nil, the portion of the message following the point will be yanked.
963If `mh-delete-yanked-msg-window' is non-nil, any window displaying the
964yanked message will be deleted."
965 (interactive)
966 (if (and mh-sent-from-folder mh-sent-from-msg)
967 (let ((to-point (point))
968 (to-buffer (current-buffer)))
969 (set-buffer mh-sent-from-folder)
970 (if mh-delete-yanked-msg-window
971 (delete-windows-on mh-show-buffer))
972 (set-buffer mh-show-buffer) ; Find displayed message
973 (let ((mh-ins-str (cond ((if (boundp 'mark-active)
847b8219
KH
974 mark-active ;Emacs 19
975 (mark)) ;Emacs 18
c26cf6c8
RS
976 (buffer-substring (region-beginning)
977 (region-end)))
978 ((eq 'body mh-yank-from-start-of-msg)
979 (buffer-substring
980 (save-excursion
981 (goto-char (point-min))
982 (mh-goto-header-end 1)
983 (point))
984 (point-max)))
985 (mh-yank-from-start-of-msg
986 (buffer-substring (point-min) (point-max)))
987 (t
988 (buffer-substring (point) (point-max))))))
989 (set-buffer to-buffer)
847b8219
KH
990 (save-restriction
991 (narrow-to-region to-point to-point)
992 (push-mark)
993 (insert mh-ins-str)
994 (mh-insert-prefix-string mh-ins-buf-prefix)
995 (insert "\n"))))
996 (error "There is no current message")))
c26cf6c8
RS
997
998
999(defun mh-insert-prefix-string (mh-ins-string)
847b8219 1000 ;; Run mail-citation-hook to insert a prefix string before each line
c26cf6c8 1001 ;; in the buffer. Generality for supercite users.
847b8219
KH
1002 (set-mark (point-max))
1003 (goto-char (point-min))
1004 (cond (mail-citation-hook
1005 (run-hooks 'mail-citation-hook))
1006 (mh-yank-hooks ;old hook name
1007 (run-hooks 'mh-yank-hooks))
1008 (t
1009 (or (bolp) (forward-line 1))
1010 (let ((zmacs-regions nil)) ;so "(mark)" works in XEmacs
c26cf6c8
RS
1011 (while (< (point) (mark))
1012 (insert mh-ins-string)
1013 (forward-line 1))))))
1014
1015
1016(defun mh-fully-kill-draft ()
1017 "Kill the draft message file and the draft message buffer.
1018Use \\[kill-buffer] if you don't want to delete the draft message file."
1019 (interactive)
1020 (if (y-or-n-p "Kill draft message? ")
1021 (let ((config mh-previous-window-config))
847b8219
KH
1022 (if (file-exists-p buffer-file-name)
1023 (delete-file buffer-file-name))
c26cf6c8
RS
1024 (set-buffer-modified-p nil)
1025 (kill-buffer (buffer-name))
1026 (message "")
1027 (if config
1028 (set-window-configuration config)))
1029 (error "Message not killed")))
1030
847b8219 1031
c26cf6c8
RS
1032;;; Build the letter-mode keymap:
1033
1034(define-key mh-letter-mode-map "\C-c\C-f\C-b" 'mh-to-field)
1035(define-key mh-letter-mode-map "\C-c\C-f\C-c" 'mh-to-field)
847b8219 1036(define-key mh-letter-mode-map "\C-c\C-f\C-d" 'mh-to-field)
c26cf6c8 1037(define-key mh-letter-mode-map "\C-c\C-f\C-f" 'mh-to-fcc)
847b8219 1038(define-key mh-letter-mode-map "\C-c\C-f\C-r" 'mh-to-field)
c26cf6c8
RS
1039(define-key mh-letter-mode-map "\C-c\C-f\C-s" 'mh-to-field)
1040(define-key mh-letter-mode-map "\C-c\C-f\C-t" 'mh-to-field)
1041(define-key mh-letter-mode-map "\C-c\C-fb" 'mh-to-field)
1042(define-key mh-letter-mode-map "\C-c\C-fc" 'mh-to-field)
847b8219 1043(define-key mh-letter-mode-map "\C-c\C-fd" 'mh-to-field)
c26cf6c8 1044(define-key mh-letter-mode-map "\C-c\C-ff" 'mh-to-fcc)
847b8219 1045(define-key mh-letter-mode-map "\C-c\C-fr" 'mh-to-field)
c26cf6c8
RS
1046(define-key mh-letter-mode-map "\C-c\C-fs" 'mh-to-field)
1047(define-key mh-letter-mode-map "\C-c\C-ft" 'mh-to-field)
847b8219 1048(define-key mh-letter-mode-map "\C-c\C-i" 'mh-insert-letter)
c26cf6c8 1049(define-key mh-letter-mode-map "\C-c\C-q" 'mh-fully-kill-draft)
847b8219
KH
1050(define-key mh-letter-mode-map "\C-c\C-\\" 'mh-fully-kill-draft) ;if no C-q
1051(define-key mh-letter-mode-map "\C-c\C-s" 'mh-insert-signature)
1052(define-key mh-letter-mode-map "\C-c\C-^" 'mh-insert-signature) ;if no C-s
c26cf6c8 1053(define-key mh-letter-mode-map "\C-c\C-w" 'mh-check-whom)
c26cf6c8 1054(define-key mh-letter-mode-map "\C-c\C-y" 'mh-yank-cur-msg)
c26cf6c8
RS
1055(define-key mh-letter-mode-map "\C-c\C-c" 'mh-send-letter)
1056(define-key mh-letter-mode-map "\C-c\C-m\C-f" 'mh-mhn-compose-forw)
1057(define-key mh-letter-mode-map "\C-c\C-m\C-e" 'mh-mhn-compose-anon-ftp)
1058(define-key mh-letter-mode-map "\C-c\C-m\C-t" 'mh-mhn-compose-external-compressed-tar)
1059(define-key mh-letter-mode-map "\C-c\C-m\C-i" 'mh-mhn-compose-insertion)
1060(define-key mh-letter-mode-map "\C-c\C-e" 'mh-edit-mhn)
1061(define-key mh-letter-mode-map "\C-c\C-m\C-u" 'mh-revert-mhn-edit)
1062
283b03f4 1063;; "C-c /" prefix is used in mh-letter-mode by pgp.el
c26cf6c8
RS
1064
1065;;; autoloads from mh-mime
1066
1067(autoload 'mh-mhn-compose-insertion "mh-mime"
9303c8db 1068 "Add a directive to insert a MIME message part from a file.
847b8219
KH
1069This is the typical way to insert non-text parts in a message.
1070See also \\[mh-edit-mhn]." t)
1071
c26cf6c8 1072(autoload 'mh-mhn-compose-anon-ftp "mh-mime"
9303c8db 1073 "Add a directive for a MIME anonymous ftp external body part.
847b8219
KH
1074This directive tells MH to include a reference to a
1075message/external-body part retrievable by anonymous FTP.
1076See also \\[mh-edit-mhn]." t)
1077
c26cf6c8 1078(autoload 'mh-mhn-compose-external-compressed-tar "mh-mime"
9303c8db 1079 "Add a directive to include a MIME reference to a compressed tar file.
847b8219
KH
1080The file should be available via anonymous ftp. This directive
1081tells MH to include a reference to a message/external-body part.
1082See also \\[mh-edit-mhn]." t)
1083
c26cf6c8 1084(autoload 'mh-mhn-compose-forw "mh-mime"
9303c8db 1085 "Add a forw directive to this message, to forward a message with MIME.
847b8219
KH
1086This directive tells MH to include another message in this one.
1087See also \\[mh-edit-mhn]." t)
1088
c26cf6c8 1089(autoload 'mh-edit-mhn "mh-mime"
847b8219
KH
1090 "Format the current draft for MIME, expanding any mhn directives.
1091Process the current draft with the mhn program, which,
1092using directives already inserted in the draft, fills in
c26cf6c8
RS
1093all the MIME components and header fields.
1094This step should be done last just before sending the message.
1095The mhn program is part of MH version 6.8 or later.
1838eb6c 1096The \\[mh-revert-mhn-edit] command undoes this command.
847b8219 1097For assistance with creating mhn directives to insert
c26cf6c8
RS
1098various types of components in a message, see
1099\\[mh-mhn-compose-insertion] (generic insertion from a file),
1100\\[mh-mhn-compose-anon-ftp] (external reference to file via anonymous ftp),
1101\\[mh-mhn-compose-external-compressed-tar] \
1102\(reference to compressed tar file via anonymous ftp), and
1103\\[mh-mhn-compose-forw] (forward message)." t)
1104
1105(autoload 'mh-revert-mhn-edit "mh-mime"
847b8219
KH
1106 "Undoes the effect of \\[mh-edit-mhn] by reverting to the backup file.
1107Optional non-nil argument means don't ask for confirmation." t)