Commit | Line | Data |
---|---|---|
bdcfe844 | 1 | ;;; mh-comp.el --- MH-E functions for composing messages |
c26cf6c8 | 2 | |
e495eaec | 3 | ;; Copyright (C) 1993, 1995, 1997, |
a05fcb7d | 4 | ;; 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. |
7382bcae | 5 | |
a1b4049d | 6 | ;; Author: Bill Wohler <wohler@newt.com> |
6e65a812 | 7 | ;; Maintainer: Bill Wohler <wohler@newt.com> |
7382bcae | 8 | ;; Keywords: mail |
a1b4049d | 9 | ;; See: mh-e.el |
c26cf6c8 | 10 | |
60370d40 | 11 | ;; This file is part of GNU Emacs. |
c26cf6c8 | 12 | |
9b7bc076 | 13 | ;; GNU Emacs is free software; you can redistribute it and/or modify |
c26cf6c8 RS |
14 | ;; it under the terms of the GNU General Public License as published by |
15 | ;; the Free Software Foundation; either version 2, or (at your option) | |
16 | ;; any later version. | |
17 | ||
9b7bc076 | 18 | ;; GNU Emacs is distributed in the hope that it will be useful, |
c26cf6c8 RS |
19 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
20 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
21 | ;; GNU General Public License for more details. | |
22 | ||
23 | ;; You should have received a copy of the GNU General Public License | |
b578f267 | 24 | ;; along with GNU Emacs; see the file COPYING. If not, write to the |
3a35cf56 LK |
25 | ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
26 | ;; Boston, MA 02110-1301, USA. | |
c26cf6c8 RS |
27 | |
28 | ;;; Commentary: | |
29 | ||
bdcfe844 | 30 | ;; Internal support for MH-E package. |
c26cf6c8 | 31 | |
847b8219 KH |
32 | ;;; Change Log: |
33 | ||
c26cf6c8 RS |
34 | ;;; Code: |
35 | ||
f0d73c14 BW |
36 | (eval-when-compile (require 'mh-acros)) |
37 | (mh-require-cl) | |
a1b4049d | 38 | (require 'mh-e) |
a1b4049d BW |
39 | (require 'gnus-util) |
40 | (require 'easymenu) | |
f0d73c14 | 41 | (require 'mh-gnus) |
924df208 BW |
42 | (eval-when (compile load eval) |
43 | (ignore-errors (require 'mailabbrev))) | |
bdcfe844 BW |
44 | |
45 | ;; Shush the byte-compiler | |
46 | (defvar adaptive-fill-first-line-regexp) | |
47 | (defvar font-lock-defaults) | |
48 | (defvar mark-active) | |
49 | (defvar sendmail-coding-system) | |
c3d9274a BW |
50 | (defvar mh-identity-list) |
51 | (defvar mh-identity-default) | |
f0d73c14 | 52 | (defvar mh-mml-mode-default) |
c3d9274a | 53 | (defvar mh-identity-menu) |
a1b4049d | 54 | |
cee9f5c6 | 55 | \f |
c3d9274a | 56 | ;;; Autoloads |
cee9f5c6 | 57 | |
a1b4049d | 58 | (autoload 'mail-mode-fill-paragraph "sendmail") |
bdcfe844 BW |
59 | (autoload 'mm-handle-displayed-p "mm-decode") |
60 | ||
61 | (autoload 'sc-cite-original "sc" | |
62 | "Workhorse citing function which performs the initial citation. | |
63 | This is callable from the various mail and news readers' reply | |
f0d73c14 | 64 | function according to the agreed upon standard. See `sc-describe' |
bdcfe844 BW |
65 | for more details. `sc-cite-original' does not do any yanking of the |
66 | original message but it does require a few things: | |
67 | ||
68 | 1) The reply buffer is the current buffer. | |
69 | ||
70 | 2) The original message has been yanked and inserted into the | |
71 | reply buffer. | |
72 | ||
73 | 3) Verbose mail headers from the original message have been | |
74 | inserted into the reply buffer directly before the text of the | |
75 | original message. | |
76 | ||
77 | 4) Point is at the beginning of the verbose headers. | |
78 | ||
79 | 5) Mark is at the end of the body of text to be cited. | |
80 | ||
81 | For Emacs 19's, the region need not be active (and typically isn't | |
82 | when this function is called. Also, the hook `sc-pre-hook' is run | |
83 | before, and `sc-post-hook' is run after the guts of this function.") | |
c26cf6c8 | 84 | |
cee9f5c6 BW |
85 | \f |
86 | ||
847b8219 KH |
87 | ;;; Site customization (see also mh-utils.el): |
88 | ||
89 | (defvar mh-send-prog "send" | |
90 | "Name of the MH send program. | |
91 | Some sites need to change this because of a name conflict.") | |
92 | ||
a1b4049d BW |
93 | (defvar mh-redist-background nil |
94 | "If non-nil redist will be done in background like send. | |
2dcf34f9 BW |
95 | This allows transaction log to be visible if -watch, -verbose or |
96 | -snoop are used.") | |
847b8219 | 97 | |
cee9f5c6 BW |
98 | \f |
99 | ||
f0d73c14 BW |
100 | ;;; Scan Line Formats |
101 | ||
102 | (defvar mh-note-repl ?- | |
103 | "Messages that have been replied to are marked by this character.") | |
c26cf6c8 | 104 | |
f0d73c14 BW |
105 | (defvar mh-note-forw ?F |
106 | "Messages that have been forwarded are marked by this character.") | |
c26cf6c8 | 107 | |
f0d73c14 BW |
108 | (defvar mh-note-dist ?R |
109 | "Messages that have been redistributed are marked by this character.") | |
c26cf6c8 | 110 | |
c26cf6c8 RS |
111 | (defvar mh-yank-hooks nil |
112 | "Obsolete hook for modifying a citation just inserted in the mail buffer. | |
2dcf34f9 | 113 | |
c26cf6c8 | 114 | Each hook function can find the citation between point and mark. |
2dcf34f9 BW |
115 | And each hook function should leave point and mark around the |
116 | citation text as modified. | |
c26cf6c8 | 117 | |
2dcf34f9 BW |
118 | This is a normal hook, misnamed for historical reasons. It is |
119 | semi-obsolete and is only used if `mail-citation-hook' is nil.") | |
c26cf6c8 | 120 | |
c26cf6c8 RS |
121 | (defvar mh-comp-formfile "components" |
122 | "Name of file to be used as a skeleton for composing messages. | |
2dcf34f9 BW |
123 | |
124 | Default is \"components\". | |
125 | ||
126 | If not an absolute file name, the file is searched for first in the | |
127 | user's MH directory, then in the system MH lib directory.") | |
c26cf6c8 | 128 | |
847b8219 KH |
129 | (defvar mh-repl-formfile "replcomps" |
130 | "Name of file to be used as a skeleton for replying to messages. | |
2dcf34f9 BW |
131 | |
132 | Default is \"replcomps\". | |
133 | ||
134 | If not an absolute file name, the file is searched for first in the | |
135 | user's MH directory, then in the system MH lib directory.") | |
847b8219 | 136 | |
c3d6278e | 137 | (defvar mh-repl-group-formfile "replgroupcomps" |
bdcfe844 | 138 | "Name of file to be used as a skeleton for replying to messages. |
2dcf34f9 | 139 | |
f0d73c14 | 140 | Default is \"replgroupcomps\". |
2dcf34f9 BW |
141 | |
142 | This file is used to form replies to the sender and all recipients of | |
143 | a message. Only used if `(mh-variant-p 'nmh)' is non-nil. | |
144 | If not an absolute file name, the file is searched for first in the | |
145 | user's MH directory, then in the system MH lib directory.") | |
a1b4049d | 146 | |
c26cf6c8 | 147 | (defvar mh-rejected-letter-start |
bdcfe844 | 148 | (format "^%s$" |
c3d9274a BW |
149 | (regexp-opt |
150 | '("Content-Type: message/rfc822" ;MIME MDN | |
f0d73c14 BW |
151 | "------ This is a copy of the message, including all the headers. ------";from exim |
152 | "--- Below this line is a copy of the message."; from qmail | |
c3d9274a BW |
153 | " ----- Unsent message follows -----" ;from sendmail V5 |
154 | " --------Unsent Message below:" ; from sendmail at BU | |
155 | " ----- Original message follows -----" ;from sendmail V8 | |
156 | "------- Unsent Draft" ;from MH itself | |
157 | "---------- Original Message ----------" ;from zmailer | |
158 | " --- The unsent message follows ---" ;from AIX mail system | |
159 | " Your message follows:" ;from MMDF-II | |
160 | "Content-Description: Returned Content" ;1993 KJ sendmail | |
161 | )))) | |
c26cf6c8 RS |
162 | |
163 | (defvar mh-new-draft-cleaned-headers | |
847b8219 | 164 | "^Date:\\|^Received:\\|^Message-Id:\\|^From:\\|^Sender:\\|^Errors-To:\\|^Delivery-Date:\\|^Return-Path:" |
5a4aad03 BW |
165 | "Regexp of header lines to remove before offering a message as a new draft\\<mh-folder-mode-map>. |
166 | Used by the \\[mh-edit-again] and \\[mh-extract-rejected-mail] commands.") | |
c26cf6c8 | 167 | |
847b8219 | 168 | (defvar mh-to-field-choices '(("t" . "To:") ("s" . "Subject:") ("c" . "Cc:") |
c3d9274a BW |
169 | ("b" . "Bcc:") ("f" . "Fcc:") ("r" . "From:") |
170 | ("d" . "Dcc:")) | |
a1b4049d | 171 | "Alist of (final-character . field-name) choices for `mh-to-field'.") |
c26cf6c8 RS |
172 | |
173 | (defvar mh-letter-mode-map (copy-keymap text-mode-map) | |
174 | "Keymap for composing mail.") | |
175 | ||
176 | (defvar mh-letter-mode-syntax-table nil | |
bdcfe844 | 177 | "Syntax table used by MH-E while in MH-Letter mode.") |
c26cf6c8 RS |
178 | |
179 | (if mh-letter-mode-syntax-table | |
180 | () | |
c3d9274a BW |
181 | (setq mh-letter-mode-syntax-table |
182 | (make-syntax-table text-mode-syntax-table)) | |
183 | (modify-syntax-entry ?% "." mh-letter-mode-syntax-table)) | |
c26cf6c8 | 184 | |
bdcfe844 BW |
185 | (defvar mh-sent-from-folder nil |
186 | "Folder of msg assoc with this letter.") | |
187 | ||
188 | (defvar mh-sent-from-msg nil | |
189 | "Number of msg assoc with this letter.") | |
190 | ||
191 | (defvar mh-send-args nil | |
192 | "Extra args to pass to \"send\" command.") | |
193 | ||
194 | (defvar mh-annotate-char nil | |
195 | "Character to use to annotate `mh-sent-from-msg'.") | |
196 | ||
197 | (defvar mh-annotate-field nil | |
198 | "Field name for message annotation.") | |
c26cf6c8 | 199 | |
a66894d8 | 200 | (defvar mh-insert-auto-fields-done-local nil |
f0d73c14 | 201 | "Buffer-local variable set when `mh-insert-auto-fields' called successfully.") |
a66894d8 BW |
202 | (make-variable-buffer-local 'mh-insert-auto-fields-done-local) |
203 | ||
c26cf6c8 RS |
204 | ;;;###autoload |
205 | (defun mh-smail () | |
b2064e08 | 206 | "Compose a message with the MH mail system. |
f0d73c14 | 207 | See `mh-send' for more details on composing mail." |
c26cf6c8 RS |
208 | (interactive) |
209 | (mh-find-path) | |
210 | (call-interactively 'mh-send)) | |
211 | ||
b2064e08 BW |
212 | ;;;###autoload |
213 | (defun mh-smail-other-window () | |
214 | "Compose a message with the MH mail system in other window. | |
215 | See `mh-send' for more details on composing mail." | |
216 | (interactive) | |
217 | (mh-find-path) | |
218 | (call-interactively 'mh-send-other-window)) | |
219 | ||
c3d9274a | 220 | (defvar mh-error-if-no-draft nil) ;raise error over using old draft |
283b03f4 | 221 | |
283b03f4 | 222 | ;;;###autoload |
c3d6278e | 223 | (defun mh-smail-batch (&optional to subject other-headers &rest ignored) |
b2064e08 BW |
224 | "Compose a message with the MH mail system. |
225 | ||
2dcf34f9 BW |
226 | This function does not prompt the user for any header fields, and |
227 | thus is suitable for use by programs that want to create a mail | |
228 | buffer. Users should use \\[mh-smail] to compose mail. | |
f0d73c14 | 229 | |
2dcf34f9 | 230 | Optional arguments for setting certain fields include TO, |
0d887b77 BW |
231 | SUBJECT, and OTHER-HEADERS. Additional arguments are IGNORED. |
232 | ||
233 | This function remains for Emacs 21 compatibility. New | |
234 | applications should use `mh-user-agent-compose'." | |
283b03f4 KH |
235 | (mh-find-path) |
236 | (let ((mh-error-if-no-draft t)) | |
016fbe59 | 237 | (mh-send (or to "") "" (or subject "")))) |
283b03f4 | 238 | |
0d887b77 BW |
239 | ;;;###autoload |
240 | (define-mail-user-agent 'mh-e-user-agent | |
241 | 'mh-user-agent-compose 'mh-send-letter 'mh-fully-kill-draft | |
242 | 'mh-before-send-letter-hook) | |
243 | ||
a1b4049d BW |
244 | ;;;###autoload |
245 | (defun mh-user-agent-compose (&optional to subject other-headers continue | |
c3d9274a BW |
246 | switch-function yank-action |
247 | send-actions) | |
a1b4049d | 248 | "Set up mail composition draft with the MH mail system. |
0d887b77 BW |
249 | This is the `mail-user-agent' entry point to MH-E. This function |
250 | conforms to the contract specified by `define-mail-user-agent' | |
251 | which means that this function should accept the same arguments | |
252 | as `compose-mail'. | |
a1b4049d BW |
253 | |
254 | The optional arguments TO and SUBJECT specify recipients and the | |
255 | initial Subject field, respectively. | |
256 | ||
2dcf34f9 BW |
257 | OTHER-HEADERS is an alist specifying additional header fields. |
258 | Elements look like (HEADER . VALUE) where both HEADER and VALUE | |
259 | are strings. | |
a1b4049d | 260 | |
2dcf34f9 BW |
261 | CONTINUE, SWITCH-FUNCTION, YANK-ACTION and SEND-ACTIONS are |
262 | ignored." | |
a1b4049d BW |
263 | (mh-find-path) |
264 | (let ((mh-error-if-no-draft t)) | |
265 | (mh-send to "" subject) | |
266 | (while other-headers | |
267 | (mh-insert-fields (concat (car (car other-headers)) ":") | |
c3d9274a | 268 | (cdr (car other-headers))) |
a1b4049d | 269 | (setq other-headers (cdr other-headers))))) |
283b03f4 | 270 | |
c3d9274a | 271 | ;;;###mh-autoload |
b2064e08 BW |
272 | (defun mh-edit-again (message) |
273 | "Edit a MESSAGE to send it again. | |
274 | ||
2dcf34f9 BW |
275 | If you don't complete a draft for one reason or another, and if |
276 | the draft buffer is no longer available, you can pick your draft | |
277 | up again with this command. If you don't use a draft folder, your | |
278 | last \"draft\" file will be used. If you use draft folders, | |
279 | you'll need to visit the draft folder with \"\\[mh-visit-folder] | |
280 | drafts <RET>\", use \\[mh-next-undeleted-msg] to move to the | |
281 | appropriate message, and then use \\[mh-edit-again] to prepare | |
282 | the message for editing. | |
b2064e08 | 283 | |
2dcf34f9 BW |
284 | This command can also be used to take messages that were sent to |
285 | you and to send them to more people. | |
b2064e08 | 286 | |
2dcf34f9 BW |
287 | Don't use this command to re-edit a message from a Mailer-Daemon |
288 | who complained that your mail wasn't posted for some reason or | |
289 | another (see `mh-extract-rejected-mail'). | |
b2064e08 BW |
290 | |
291 | The default message is the current message. | |
f0d73c14 BW |
292 | |
293 | See also `mh-send'." | |
c26cf6c8 RS |
294 | (interactive (list (mh-get-msg-num t))) |
295 | (let* ((from-folder mh-current-folder) | |
c3d9274a BW |
296 | (config (current-window-configuration)) |
297 | (draft | |
298 | (cond ((and mh-draft-folder (equal from-folder mh-draft-folder)) | |
b2064e08 BW |
299 | (pop-to-buffer (find-file-noselect (mh-msg-filename message)) |
300 | t) | |
301 | (rename-buffer (format "draft-%d" message)) | |
bdcfe844 BW |
302 | ;; Make buffer writable... |
303 | (setq buffer-read-only nil) | |
304 | ;; If buffer was being used to display the message reinsert | |
305 | ;; from file... | |
306 | (when (eq major-mode 'mh-show-mode) | |
307 | (erase-buffer) | |
308 | (insert-file-contents buffer-file-name)) | |
c3d9274a BW |
309 | (buffer-name)) |
310 | (t | |
b2064e08 | 311 | (mh-read-draft "clean-up" (mh-msg-filename message) nil))))) |
c26cf6c8 | 312 | (mh-clean-msg-header (point-min) mh-new-draft-cleaned-headers nil) |
a1b4049d | 313 | (mh-insert-header-separator) |
c26cf6c8 | 314 | (goto-char (point-min)) |
283b03f4 | 315 | (save-buffer) |
c26cf6c8 | 316 | (mh-compose-and-send-mail draft "" from-folder nil nil nil nil nil nil |
c3d9274a | 317 | config) |
a66894d8 BW |
318 | (mh-letter-mode-message) |
319 | (mh-letter-adjust-point))) | |
c26cf6c8 | 320 | |
c3d9274a | 321 | ;;;###mh-autoload |
b2064e08 BW |
322 | (defun mh-extract-rejected-mail (message) |
323 | "Edit a MESSAGE that was returned by the mail system. | |
324 | ||
2dcf34f9 BW |
325 | This command prepares the message for editing by removing the |
326 | Mailer-Daemon envelope and unneeded header fields. Fix whatever | |
327 | addressing problem you had, and send the message again with | |
328 | \\[mh-send-letter]. | |
b2064e08 BW |
329 | |
330 | The default message is the current message. | |
f0d73c14 BW |
331 | |
332 | See also `mh-send'." | |
c26cf6c8 RS |
333 | (interactive (list (mh-get-msg-num t))) |
334 | (let ((from-folder mh-current-folder) | |
c3d9274a | 335 | (config (current-window-configuration)) |
b2064e08 | 336 | (draft (mh-read-draft "extraction" (mh-msg-filename message) nil))) |
c26cf6c8 RS |
337 | (goto-char (point-min)) |
338 | (cond ((re-search-forward mh-rejected-letter-start nil t) | |
c3d9274a BW |
339 | (skip-chars-forward " \t\n") |
340 | (delete-region (point-min) (point)) | |
341 | (mh-clean-msg-header (point-min) mh-new-draft-cleaned-headers nil)) | |
342 | (t | |
f0d73c14 | 343 | (message "Does not appear to be a rejected letter"))) |
a1b4049d | 344 | (mh-insert-header-separator) |
c26cf6c8 | 345 | (goto-char (point-min)) |
283b03f4 | 346 | (save-buffer) |
b2064e08 | 347 | (mh-compose-and-send-mail draft "" from-folder message |
c3d9274a BW |
348 | (mh-get-header-field "To:") |
349 | (mh-get-header-field "From:") | |
350 | (mh-get-header-field "Cc:") | |
351 | nil nil config) | |
bdcfe844 | 352 | (mh-letter-mode-message))) |
c26cf6c8 | 353 | |
c3d9274a | 354 | ;;;###mh-autoload |
a66894d8 | 355 | (defun mh-forward (to cc &optional range) |
2be362c2 | 356 | "Forward message. |
a66894d8 | 357 | |
2dcf34f9 BW |
358 | You are prompted for the TO and CC recipients. You are given a |
359 | draft to edit that looks like it would if you had run the MH | |
360 | command \"forw\". You can then add some text. | |
bdcfe844 | 361 | |
2dcf34f9 BW |
362 | You can forward several messages by using a RANGE. All of the |
363 | messages in the range are inserted into your draft. Check the | |
364 | documentation of `mh-interactive-range' to see how RANGE is read | |
365 | in interactive use. | |
b2064e08 | 366 | |
d1699462 BW |
367 | The hook `mh-forward-hook' is called on the draft. |
368 | ||
369 | See also `mh-compose-forward-as-mime-flag', | |
370 | `mh-forward-subject-format', and `mh-send'." | |
a66894d8 BW |
371 | (interactive (list (mh-interactive-read-address "To: ") |
372 | (mh-interactive-read-address "Cc: ") | |
373 | (mh-interactive-range "Forward"))) | |
c26cf6c8 | 374 | (let* ((folder mh-current-folder) |
a66894d8 | 375 | (msgs (mh-range-to-msg-list range)) |
c3d9274a BW |
376 | (config (current-window-configuration)) |
377 | (fwd-msg-file (mh-msg-filename (car msgs) folder)) | |
378 | ;; forw always leaves file in "draft" since it doesn't have -draft | |
379 | (draft-name (expand-file-name "draft" mh-user-path)) | |
380 | (draft (cond ((or (not (file-exists-p draft-name)) | |
381 | (y-or-n-p "The file 'draft' exists. Discard it? ")) | |
f0d73c14 BW |
382 | (mh-exec-cmd "forw" "-build" |
383 | (if (and (mh-variant-p 'nmh) | |
384 | mh-compose-forward-as-mime-flag) | |
385 | "-mime") | |
924df208 BW |
386 | mh-current-folder |
387 | (mh-coalesce-msg-list msgs)) | |
c3d9274a BW |
388 | (prog1 |
389 | (mh-read-draft "" draft-name t) | |
390 | (mh-insert-fields "To:" to "Cc:" cc) | |
391 | (save-buffer))) | |
392 | (t | |
393 | (mh-read-draft "" draft-name nil))))) | |
847b8219 | 394 | (let (orig-from |
c3d9274a | 395 | orig-subject) |
41b9a988 | 396 | (save-excursion |
c3d9274a BW |
397 | (set-buffer (get-buffer-create mh-temp-buffer)) |
398 | (erase-buffer) | |
399 | (insert-file-contents fwd-msg-file) | |
400 | (setq orig-from (mh-get-header-field "From:")) | |
401 | (setq orig-subject (mh-get-header-field "Subject:"))) | |
c26cf6c8 | 402 | (let ((forw-subject |
924df208 | 403 | (mh-forwarded-letter-subject orig-from orig-subject))) |
c3d9274a BW |
404 | (mh-insert-fields "Subject:" forw-subject) |
405 | (goto-char (point-min)) | |
0c47b17c BW |
406 | ;; If using MML, translate MH-style directive |
407 | (if (equal mh-compose-insertion 'mml) | |
c3d9274a | 408 | (save-excursion |
a66894d8 | 409 | (goto-char (mh-mail-header-end)) |
c3d9274a BW |
410 | (while |
411 | (re-search-forward | |
412 | "^#forw \\[\\([^]]+\\)\\] \\(+\\S-+\\) \\(.*\\)$" | |
413 | (point-max) t) | |
414 | (let ((description (if (equal (match-string 1) | |
415 | "forwarded messages") | |
416 | "forwarded message %d" | |
417 | (match-string 1))) | |
418 | (msgs (split-string (match-string 3))) | |
419 | (i 0)) | |
420 | (beginning-of-line) | |
421 | (delete-region (point) (progn (forward-line 1) (point))) | |
422 | (dolist (msg msgs) | |
423 | (setq i (1+ i)) | |
424 | (mh-mml-forward-message (format description i) | |
425 | folder msg)))))) | |
426 | ;; Postition just before forwarded message | |
427 | (if (re-search-forward "^------- Forwarded Message" nil t) | |
428 | (forward-line -1) | |
a66894d8 | 429 | (goto-char (mh-mail-header-end)) |
c3d9274a BW |
430 | (forward-line 1)) |
431 | (delete-other-windows) | |
432 | (mh-add-msgs-to-seq msgs 'forwarded t) | |
924df208 | 433 | (mh-compose-and-send-mail draft "" folder msgs |
c3d9274a BW |
434 | to forw-subject cc |
435 | mh-note-forw "Forwarded:" | |
436 | config) | |
a66894d8 | 437 | (mh-letter-mode-message) |
f0d73c14 BW |
438 | (mh-letter-adjust-point) |
439 | (run-hooks 'mh-forward-hook))))) | |
c26cf6c8 RS |
440 | |
441 | (defun mh-forwarded-letter-subject (from subject) | |
bdcfe844 BW |
442 | "Return a Subject suitable for a forwarded message. |
443 | Original message has headers FROM and SUBJECT." | |
c26cf6c8 | 444 | (let ((addr-start (string-match "<" from)) |
c3d9274a | 445 | (comment (string-match "(" from))) |
c26cf6c8 | 446 | (cond ((and addr-start (> addr-start 0)) |
c3d9274a BW |
447 | ;; Full Name <luser@host> |
448 | (setq from (substring from 0 (1- addr-start)))) | |
449 | (comment | |
450 | ;; luser@host (Full Name) | |
451 | (setq from (substring from (1+ comment) (1- (length from))))))) | |
c26cf6c8 RS |
452 | (format mh-forward-subject-format from subject)) |
453 | ||
b2064e08 BW |
454 | ;;;###mh-autoload |
455 | (defun mh-redistribute (to cc &optional message) | |
456 | "Redistribute a message. | |
847b8219 | 457 | |
2dcf34f9 BW |
458 | This command is similar in function to forwarding mail, but it |
459 | does not allow you to edit the message, nor does it add your name | |
460 | to the \"From\" header field. It appears to the recipient as if | |
461 | the message had come from the original sender. When you run this | |
462 | command, you are prompted for the TO and CC recipients. The | |
463 | default MESSAGE is the current message. | |
c26cf6c8 | 464 | |
2dcf34f9 BW |
465 | Also investigate the \\[mh-edit-again] command for another way to |
466 | redistribute messages. | |
b2064e08 BW |
467 | |
468 | See also `mh-redist-full-contents-flag'." | |
c26cf6c8 | 469 | (interactive (list (mh-read-address "Redist-To: ") |
c3d9274a BW |
470 | (mh-read-address "Redist-Cc: ") |
471 | (mh-get-msg-num t))) | |
b2064e08 BW |
472 | (or message |
473 | (setq message (mh-get-msg-num t))) | |
c26cf6c8 RS |
474 | (save-window-excursion |
475 | (let ((folder mh-current-folder) | |
c3d9274a | 476 | (draft (mh-read-draft "redistribution" |
b2064e08 BW |
477 | (if mh-redist-full-contents-flag |
478 | (mh-msg-filename message) | |
c3d9274a BW |
479 | nil) |
480 | nil))) | |
c26cf6c8 RS |
481 | (mh-goto-header-end 0) |
482 | (insert "Resent-To: " to "\n") | |
483 | (if (not (equal cc "")) (insert "Resent-cc: " cc "\n")) | |
924df208 BW |
484 | (mh-clean-msg-header |
485 | (point-min) | |
486 | "^Message-Id:\\|^Received:\\|^Return-Path:\\|^Sender:\\|^Date:\\|^From:" | |
487 | nil) | |
c26cf6c8 RS |
488 | (save-buffer) |
489 | (message "Redistributing...") | |
924df208 BW |
490 | (let ((env "mhdist=1")) |
491 | ;; Setup environment... | |
b2064e08 BW |
492 | (setq env (concat env " mhaltmsg=" |
493 | (if mh-redist-full-contents-flag | |
494 | buffer-file-name | |
495 | (mh-msg-filename message folder)))) | |
496 | (unless mh-redist-full-contents-flag | |
924df208 BW |
497 | (setq env (concat env " mhannotate=1"))) |
498 | ;; Redistribute... | |
499 | (if mh-redist-background | |
500 | (mh-exec-cmd-env-daemon env mh-send-prog nil buffer-file-name) | |
501 | (mh-exec-cmd-error env mh-send-prog "-push" buffer-file-name)) | |
502 | ;; Annotate... | |
b2064e08 | 503 | (mh-annotate-msg message folder mh-note-dist |
924df208 BW |
504 | "-component" "Resent:" |
505 | "-text" (format "\"%s %s\"" to cc))) | |
c26cf6c8 RS |
506 | (kill-buffer draft) |
507 | (message "Redistributing...done")))) | |
508 | ||
bdcfe844 BW |
509 | (defun mh-show-buffer-message-number (&optional buffer) |
510 | "Message number of displayed message in corresponding show buffer. | |
2dcf34f9 | 511 | |
bdcfe844 | 512 | Return nil if show buffer not displayed. |
2dcf34f9 BW |
513 | If in `mh-letter-mode', don't display the message number being replied |
514 | to, but rather the message number of the show buffer associated with | |
515 | our originating folder buffer. | |
bdcfe844 BW |
516 | Optional argument BUFFER can be used to specify the buffer." |
517 | (save-excursion | |
518 | (if buffer | |
519 | (set-buffer buffer)) | |
520 | (cond ((eq major-mode 'mh-show-mode) | |
c3d9274a BW |
521 | (let ((number-start (mh-search-from-end ?/ buffer-file-name))) |
522 | (car (read-from-string (substring buffer-file-name | |
523 | (1+ number-start)))))) | |
bdcfe844 BW |
524 | ((and (eq major-mode 'mh-folder-mode) |
525 | mh-show-buffer | |
526 | (get-buffer mh-show-buffer)) | |
527 | (mh-show-buffer-message-number mh-show-buffer)) | |
528 | ((and (eq major-mode 'mh-letter-mode) | |
529 | mh-sent-from-folder | |
530 | (get-buffer mh-sent-from-folder)) | |
531 | (mh-show-buffer-message-number mh-sent-from-folder)) | |
532 | (t | |
533 | nil)))) | |
534 | ||
c3d9274a | 535 | ;;;###mh-autoload |
bdcfe844 | 536 | (defun mh-reply (message &optional reply-to includep) |
b2064e08 | 537 | "Reply to a MESSAGE. |
f0d73c14 | 538 | |
2dcf34f9 BW |
539 | When you reply to a message, you are first prompted with \"Reply |
540 | to whom?\" (unless the optional argument REPLY-TO is provided). | |
541 | You have several choices here. | |
b2064e08 BW |
542 | |
543 | Response Reply Goes To | |
544 | ||
2dcf34f9 BW |
545 | from The person who sent the message. This is the |
546 | default, so <RET> is sufficient. | |
b2064e08 BW |
547 | |
548 | to Replies to the sender, plus all recipients in the | |
549 | \"To:\" header field. | |
550 | ||
551 | all | |
552 | cc Forms a reply to the sender, plus all recipients. | |
553 | ||
2dcf34f9 BW |
554 | Depending on your answer, \"repl\" is given a different argument |
555 | to form your reply. Specifically, a choice of \"from\" or none at | |
556 | all runs \"repl -nocc all\", and a choice of \"to\" runs \"repl | |
557 | -cc to\". Finally, either \"cc\" or \"all\" runs \"repl -cc all | |
558 | -nocc me\". | |
b2064e08 | 559 | |
2dcf34f9 BW |
560 | Two windows are then created. One window contains the message to |
561 | which you are replying in an MH-Show buffer. Your draft, in | |
4023e353 | 562 | MH-Letter mode (see `mh-letter-mode'), is in the other window. |
b2064e08 | 563 | |
2dcf34f9 BW |
564 | If you supply a prefix argument INCLUDEP, the message you are |
565 | replying to is inserted in your reply after having first been run | |
566 | through \"mhl\" with the format file \"mhl.reply\". | |
b2064e08 | 567 | |
2dcf34f9 BW |
568 | Alternatively, you can customize the option `mh-yank-behavior' |
569 | and choose one of its \"Automatically\" variants to do the same | |
570 | thing. If you do so, the prefix argument has no effect. | |
b2064e08 | 571 | |
2dcf34f9 BW |
572 | Another way to include the message automatically in your draft is |
573 | to use \"repl: -filter repl.filter\" in your MH profile. | |
b2064e08 | 574 | |
2dcf34f9 BW |
575 | If you wish to customize the header or other parts of the reply |
576 | draft, please see \"repl\" and \"mh-format\". | |
b2064e08 | 577 | |
2dcf34f9 BW |
578 | See also `mh-reply-show-message-flag', |
579 | `mh-reply-default-reply-to', and `mh-send'." | |
bdcfe844 BW |
580 | (interactive (list |
581 | (mh-get-msg-num t) | |
582 | (let ((minibuffer-help-form | |
583 | "from => Sender only\nto => Sender and primary recipients\ncc or all => Sender and all recipients")) | |
584 | (or mh-reply-default-reply-to | |
f0d73c14 | 585 | (completing-read "Reply to whom: [from] " |
bdcfe844 BW |
586 | '(("from") ("to") ("cc") ("all")) |
587 | nil | |
588 | t))) | |
589 | current-prefix-arg)) | |
590 | (let* ((folder mh-current-folder) | |
591 | (show-buffer mh-show-buffer) | |
592 | (config (current-window-configuration)) | |
593 | (group-reply (or (equal reply-to "cc") (equal reply-to "all"))) | |
f0d73c14 | 594 | (form-file (cond ((and (mh-variant-p 'nmh 'mu-mh) group-reply |
bdcfe844 BW |
595 | (stringp mh-repl-group-formfile)) |
596 | mh-repl-group-formfile) | |
597 | ((stringp mh-repl-formfile) mh-repl-formfile) | |
598 | (t nil)))) | |
599 | (message "Composing a reply...") | |
600 | (mh-exec-cmd "repl" "-build" "-noquery" "-nodraftfolder" | |
601 | (if form-file | |
602 | (list "-form" form-file)) | |
603 | mh-current-folder message | |
604 | (cond ((or (equal reply-to "from") (equal reply-to "")) | |
605 | '("-nocc" "all")) | |
606 | ((equal reply-to "to") | |
607 | '("-cc" "to")) | |
f0d73c14 | 608 | (group-reply (if (mh-variant-p 'nmh 'mu-mh) |
bdcfe844 BW |
609 | '("-group" "-nocc" "me") |
610 | '("-cc" "all" "-nocc" "me")))) | |
0c47b17c BW |
611 | (cond ((or (eq mh-yank-behavior 'autosupercite) |
612 | (eq mh-yank-behavior 'autoattrib)) | |
c3d9274a BW |
613 | '("-noformat")) |
614 | (includep '("-filter" "mhl.reply")) | |
615 | (t '()))) | |
bdcfe844 BW |
616 | (let ((draft (mh-read-draft "reply" |
617 | (expand-file-name "reply" mh-user-path) | |
618 | t))) | |
619 | (delete-other-windows) | |
620 | (save-buffer) | |
a1506d29 | 621 | |
bdcfe844 BW |
622 | (let ((to (mh-get-header-field "To:")) |
623 | (subject (mh-get-header-field "Subject:")) | |
624 | (cc (mh-get-header-field "Cc:"))) | |
625 | (goto-char (point-min)) | |
626 | (mh-goto-header-end 1) | |
627 | (or includep | |
628 | (not mh-reply-show-message-flag) | |
629 | (mh-in-show-buffer (show-buffer) | |
630 | (mh-display-msg message folder))) | |
631 | (mh-add-msgs-to-seq message 'answered t) | |
632 | (message "Composing a reply...done") | |
633 | (mh-compose-and-send-mail draft "" folder message to subject cc | |
634 | mh-note-repl "Replied:" config)) | |
0c47b17c BW |
635 | (when (and (or (eq 'autosupercite mh-yank-behavior) |
636 | (eq 'autoattrib mh-yank-behavior)) | |
bdcfe844 BW |
637 | (eq (mh-show-buffer-message-number) mh-sent-from-msg)) |
638 | (undo-boundary) | |
639 | (mh-yank-cur-msg)) | |
640 | (mh-letter-mode-message)))) | |
c26cf6c8 | 641 | |
c3d9274a | 642 | ;;;###mh-autoload |
c26cf6c8 | 643 | (defun mh-send (to cc subject) |
b2064e08 BW |
644 | "Compose a message. |
645 | ||
2dcf34f9 BW |
646 | Your letter appears in an Emacs buffer whose mode is |
647 | MH-Letter (see `mh-letter-mode'). | |
b2064e08 | 648 | |
2dcf34f9 BW |
649 | The arguments TO, CC, and SUBJECT can be used to prefill the |
650 | draft fields or suppress the prompts if `mh-compose-prompt-flag' | |
651 | is on. They are also passed to the function set in the option | |
652 | `mh-compose-letter-function'. | |
b2064e08 BW |
653 | |
654 | See also `mh-insert-x-mailer-flag' and `mh-letter-mode-hook'. | |
655 | ||
2dcf34f9 BW |
656 | Outside of an MH-Folder buffer (`mh-folder-mode'), you must call |
657 | either \\[mh-smail] or \\[mh-smail-other-window] to compose a new | |
658 | message." | |
c26cf6c8 | 659 | (interactive (list |
a66894d8 BW |
660 | (mh-interactive-read-address "To: ") |
661 | (mh-interactive-read-address "Cc: ") | |
662 | (mh-interactive-read-string "Subject: "))) | |
c26cf6c8 RS |
663 | (let ((config (current-window-configuration))) |
664 | (delete-other-windows) | |
665 | (mh-send-sub to cc subject config))) | |
666 | ||
c3d9274a | 667 | ;;;###mh-autoload |
c26cf6c8 | 668 | (defun mh-send-other-window (to cc subject) |
b2064e08 BW |
669 | "Compose a message in another window. |
670 | ||
2dcf34f9 BW |
671 | See `mh-send' for more information and a description of how the |
672 | TO, CC, and SUBJECT arguments are used." | |
c26cf6c8 | 673 | (interactive (list |
a66894d8 BW |
674 | (mh-interactive-read-address "To: ") |
675 | (mh-interactive-read-address "Cc: ") | |
676 | (mh-interactive-read-string "Subject: "))) | |
c26cf6c8 RS |
677 | (let ((pop-up-windows t)) |
678 | (mh-send-sub to cc subject (current-window-configuration)))) | |
679 | ||
c26cf6c8 | 680 | (defun mh-send-sub (to cc subject config) |
bdcfe844 BW |
681 | "Do the real work of composing and sending a letter. |
682 | Expects the TO, CC, and SUBJECT fields as arguments. | |
683 | CONFIG is the window configuration before sending mail." | |
c26cf6c8 | 684 | (let ((folder mh-current-folder) |
c3d9274a | 685 | (msg-num (mh-get-msg-num nil))) |
c26cf6c8 RS |
686 | (message "Composing a message...") |
687 | (let ((draft (mh-read-draft | |
c3d9274a BW |
688 | "message" |
689 | (let (components) | |
690 | (cond | |
691 | ((file-exists-p | |
692 | (setq components | |
693 | (expand-file-name mh-comp-formfile mh-user-path))) | |
694 | components) | |
695 | ((file-exists-p | |
696 | (setq components | |
697 | (expand-file-name mh-comp-formfile mh-lib))) | |
698 | components) | |
699 | ((file-exists-p | |
700 | (setq components | |
701 | (expand-file-name mh-comp-formfile | |
702 | ;; What is this mh-etc ?? -sm | |
bdcfe844 BW |
703 | ;; This is dead code, so |
704 | ;; remove it. | |
c3d9274a | 705 | ;(and (boundp 'mh-etc) mh-etc) |
bdcfe844 | 706 | ))) |
c3d9274a BW |
707 | components) |
708 | (t | |
e9c2f101 JB |
709 | (error "Can't find components file \"%s\"" |
710 | components)))) | |
c3d9274a | 711 | nil))) |
c26cf6c8 RS |
712 | (mh-insert-fields "To:" to "Subject:" subject "Cc:" cc) |
713 | (goto-char (point-max)) | |
c26cf6c8 | 714 | (mh-compose-and-send-mail draft "" folder msg-num |
c3d9274a BW |
715 | to subject cc |
716 | nil nil config) | |
a66894d8 BW |
717 | (mh-letter-mode-message) |
718 | (mh-letter-adjust-point)))) | |
c26cf6c8 RS |
719 | |
720 | (defun mh-read-draft (use initial-contents delete-contents-file) | |
bdcfe844 | 721 | "Read draft file into a draft buffer and make that buffer the current one. |
2dcf34f9 BW |
722 | |
723 | USE is a message used for prompting about the intended use of the | |
724 | message. | |
bdcfe844 | 725 | INITIAL-CONTENTS is filename that is read into an empty buffer, or nil |
2dcf34f9 | 726 | if buffer should not be modified. Delete the initial-contents file if |
bdcfe844 BW |
727 | DELETE-CONTENTS-FILE flag is set. |
728 | Returns the draft folder's name. | |
2dcf34f9 BW |
729 | If the draft folder facility is enabled in ~/.mh_profile, a new buffer |
730 | is used each time and saved in the draft folder. The draft file can | |
731 | then be reused." | |
c26cf6c8 | 732 | (cond (mh-draft-folder |
c3d9274a BW |
733 | (let ((orig-default-dir default-directory) |
734 | (draft-file-name (mh-new-draft-name))) | |
735 | (pop-to-buffer (generate-new-buffer | |
736 | (format "draft-%s" | |
737 | (file-name-nondirectory draft-file-name)))) | |
738 | (condition-case () | |
739 | (insert-file-contents draft-file-name t) | |
740 | (file-error)) | |
741 | (setq default-directory orig-default-dir))) | |
742 | (t | |
743 | (let ((draft-name (expand-file-name "draft" mh-user-path))) | |
744 | (pop-to-buffer "draft") ; Create if necessary | |
745 | (if (buffer-modified-p) | |
746 | (if (y-or-n-p "Draft has been modified; kill anyway? ") | |
747 | (set-buffer-modified-p nil) | |
748 | (error "Draft preserved"))) | |
749 | (setq buffer-file-name draft-name) | |
750 | (clear-visited-file-modtime) | |
751 | (unlock-buffer) | |
752 | (cond ((and (file-exists-p draft-name) | |
753 | (not (equal draft-name initial-contents))) | |
754 | (insert-file-contents draft-name) | |
755 | (delete-file draft-name)))))) | |
c26cf6c8 | 756 | (cond ((and initial-contents |
c3d9274a BW |
757 | (or (zerop (buffer-size)) |
758 | (if (y-or-n-p | |
759 | (format "A draft exists. Use for %s? " use)) | |
760 | (if mh-error-if-no-draft | |
761 | (error "A prior draft exists")) | |
762 | t))) | |
763 | (erase-buffer) | |
764 | (insert-file-contents initial-contents) | |
765 | (if delete-contents-file (delete-file initial-contents)))) | |
c26cf6c8 RS |
766 | (auto-save-mode 1) |
767 | (if mh-draft-folder | |
c3d9274a | 768 | (save-buffer)) ; Do not reuse draft name |
c26cf6c8 RS |
769 | (buffer-name)) |
770 | ||
c26cf6c8 | 771 | (defun mh-new-draft-name () |
bdcfe844 | 772 | "Return the pathname of folder for draft messages." |
c26cf6c8 RS |
773 | (save-excursion |
774 | (mh-exec-cmd-quiet t "mhpath" mh-draft-folder "new") | |
775 | (buffer-substring (point-min) (1- (point-max))))) | |
776 | ||
c26cf6c8 | 777 | (defun mh-annotate-msg (msg buffer note &rest args) |
924df208 | 778 | "Mark MSG in BUFFER with character NOTE and annotate message with ARGS. |
2dcf34f9 BW |
779 | MSG can be a message number, a list of message numbers, or a |
780 | sequence." | |
924df208 BW |
781 | (apply 'mh-exec-cmd "anno" buffer |
782 | (if (listp msg) (append msg args) (cons msg args))) | |
c26cf6c8 | 783 | (save-excursion |
c3d9274a BW |
784 | (cond ((get-buffer buffer) ; Buffer may be deleted |
785 | (set-buffer buffer) | |
a66894d8 | 786 | (mh-iterate-on-range nil msg |
50df64d6 BW |
787 | (mh-notate nil note |
788 | (+ mh-cmd-note mh-scan-field-destination-offset))))))) | |
c26cf6c8 | 789 | |
c26cf6c8 | 790 | (defun mh-insert-fields (&rest name-values) |
bdcfe844 BW |
791 | "Insert the NAME-VALUES pairs in the current buffer. |
792 | If the field exists, append the value to it. | |
793 | Do not insert any pairs whose value is the empty string." | |
c26cf6c8 RS |
794 | (let ((case-fold-search t)) |
795 | (while name-values | |
796 | (let ((field-name (car name-values)) | |
c3d9274a | 797 | (value (car (cdr name-values)))) |
f0d73c14 BW |
798 | (if (not (string-match "^.*:$" field-name)) |
799 | (setq field-name (concat field-name ":"))) | |
c3d9274a BW |
800 | (cond ((equal value "") |
801 | nil) | |
802 | ((mh-position-on-field field-name) | |
803 | (insert " " (or value ""))) | |
804 | (t | |
805 | (insert field-name " " value "\n"))) | |
806 | (setq name-values (cdr (cdr name-values))))))) | |
c26cf6c8 | 807 | |
bdcfe844 BW |
808 | (defun mh-position-on-field (field &optional ignored) |
809 | "Move to the end of the FIELD in the header. | |
810 | Move to end of entire header if FIELD not found. | |
811 | Returns non-nil iff FIELD was found. | |
2dcf34f9 BW |
812 | The optional second arg is for pre-version 4 compatibility and is |
813 | IGNORED." | |
a1b4049d | 814 | (cond ((mh-goto-header-field field) |
c3d9274a BW |
815 | (mh-header-field-end) |
816 | t) | |
817 | ((mh-goto-header-end 0) | |
818 | nil))) | |
847b8219 | 819 | |
f0d73c14 | 820 | ;;;###mh-autoload |
847b8219 | 821 | (defun mh-get-header-field (field) |
bdcfe844 BW |
822 | "Find and return the body of FIELD in the mail header. |
823 | Returns the empty string if the field is not in the header of the | |
824 | current buffer." | |
847b8219 KH |
825 | (if (mh-goto-header-field field) |
826 | (progn | |
c3d9274a BW |
827 | (skip-chars-forward " \t") ;strip leading white space in body |
828 | (let ((start (point))) | |
829 | (mh-header-field-end) | |
830 | (buffer-substring-no-properties start (point)))) | |
847b8219 KH |
831 | "")) |
832 | ||
bdcfe844 | 833 | (fset 'mh-get-field 'mh-get-header-field) ;MH-E 4 compatibility |
847b8219 KH |
834 | |
835 | (defun mh-goto-header-field (field) | |
bdcfe844 BW |
836 | "Move to FIELD in the message header. |
837 | Move to the end of the FIELD name, which should end in a colon. | |
838 | Returns t if found, nil if not." | |
847b8219 KH |
839 | (goto-char (point-min)) |
840 | (let ((case-fold-search t) | |
c3d9274a BW |
841 | (headers-end (save-excursion |
842 | (mh-goto-header-end 0) | |
843 | (point)))) | |
847b8219 KH |
844 | (re-search-forward (format "^%s" field) headers-end t))) |
845 | ||
c26cf6c8 | 846 | (defun mh-goto-header-end (arg) |
bdcfe844 | 847 | "Move the cursor ARG lines after the header." |
9303c8db | 848 | (if (re-search-forward "^-*$" nil nil) |
c26cf6c8 RS |
849 | (forward-line arg))) |
850 | ||
c3d9274a BW |
851 | (defun mh-extract-from-header-value () |
852 | "Extract From: string from header." | |
853 | (save-excursion | |
854 | (if (not (mh-goto-header-field "From:")) | |
924df208 | 855 | nil |
c3d9274a BW |
856 | (skip-chars-forward " \t") |
857 | (buffer-substring-no-properties | |
858 | (point) (progn (mh-header-field-end)(point)))))) | |
c26cf6c8 RS |
859 | |
860 | \f | |
861 | ||
862 | ;;; Mode for composing and sending a draft message. | |
863 | ||
bdcfe844 | 864 | (put 'mh-letter-mode 'mode-class 'special) |
c26cf6c8 | 865 | |
cee9f5c6 | 866 | ;; Menu extracted from mh-menubar.el V1.1 (31 July 2001) |
bdcfe844 | 867 | (eval-when-compile (defvar mh-letter-menu nil)) |
f0d73c14 BW |
868 | (easy-menu-define |
869 | mh-letter-menu mh-letter-mode-map "Menu for MH-E letter mode." | |
870 | '("Letter" | |
871 | ["Send This Draft" mh-send-letter t] | |
872 | ["Split Current Line" mh-open-line t] | |
873 | ["Check Recipient" mh-check-whom t] | |
874 | ["Yank Current Message" mh-yank-cur-msg t] | |
875 | ["Insert a Message..." mh-insert-letter t] | |
876 | ["Insert Signature" mh-insert-signature t] | |
877 | ("Encrypt/Sign Message" | |
878 | ["Sign Message" | |
0c47b17c | 879 | mh-mml-secure-message-sign mh-pgp-support-flag] |
f0d73c14 | 880 | ["Encrypt Message" |
0c47b17c | 881 | mh-mml-secure-message-encrypt mh-pgp-support-flag] |
f0d73c14 | 882 | ["Sign+Encrypt Message" |
0c47b17c | 883 | mh-mml-secure-message-signencrypt mh-pgp-support-flag] |
f0d73c14 | 884 | ["Disable Security" |
0c47b17c | 885 | mh-mml-unsecure-message mh-pgp-support-flag] |
f0d73c14 BW |
886 | "--" |
887 | "Security Method" | |
888 | ["PGP (MIME)" (setq mh-mml-method-default "pgpmime") | |
889 | :style radio | |
890 | :selected (equal mh-mml-method-default "pgpmime")] | |
891 | ["PGP" (setq mh-mml-method-default "pgp") | |
892 | :style radio | |
893 | :selected (equal mh-mml-method-default "pgp")] | |
894 | ["S/MIME" (setq mh-mml-method-default "smime") | |
895 | :style radio | |
896 | :selected (equal mh-mml-method-default "smime")] | |
897 | "--" | |
898 | ["Save Method as Default" | |
899 | (customize-save-variable 'mh-mml-method-default mh-mml-method-default) t] | |
900 | ) | |
0c47b17c BW |
901 | ["Compose Insertion..." mh-compose-insertion t] |
902 | ["Compose Compressed tar (MH)..." | |
903 | mh-mh-compose-external-compressed-tar t] | |
904 | ["Compose Get File (MH)..." mh-mh-compose-anon-ftp t] | |
905 | ["Compose Forward..." mh-compose-forward t] | |
f0d73c14 | 906 | ;; The next two will have to be merged. But I also need to make sure the |
0c47b17c BW |
907 | ;; user can't mix tags of both types. |
908 | ["Pull in All Compositions (MH)" | |
909 | mh-mh-to-mime (mh-mh-directive-present-p)] | |
910 | ["Pull in All Compositions (MML)" | |
911 | mh-mml-to-mime (mh-mml-tag-present-p)] | |
912 | ["Revert to Non-MIME Edit (MH)" | |
913 | mh-mh-to-mime-undo (equal mh-compose-insertion 'mh)] | |
f0d73c14 | 914 | ["Kill This Draft" mh-fully-kill-draft t])) |
c26cf6c8 | 915 | |
cee9f5c6 BW |
916 | \f |
917 | ||
bdcfe844 | 918 | ;;; Help Messages |
cee9f5c6 BW |
919 | |
920 | ;; Group messages logically, more or less. | |
bdcfe844 BW |
921 | (defvar mh-letter-mode-help-messages |
922 | '((nil | |
923 | "Send letter: \\[mh-send-letter]" | |
924 | "\t\tOpen line: \\[mh-open-line]\n" | |
925 | "Kill letter: \\[mh-fully-kill-draft]" | |
926 | "\t\tInsert:\n" | |
927 | "Check recipients: \\[mh-check-whom]" | |
928 | "\t\t Current message: \\[mh-yank-cur-msg]\n" | |
f0d73c14 BW |
929 | "\t\t Attachment: \\[mh-compose-insertion]\n" |
930 | "\t\t Message to forward: \\[mh-compose-forward]\n" | |
931 | " " | |
932 | "Security:" | |
933 | "\t\t Encrypt message: \\[mh-mml-secure-message-encrypt]" | |
934 | "\t\t Sign+Encrypt message: \\[mh-mml-secure-message-signencrypt]" | |
935 | "\t\t Sign message: \\[mh-mml-secure-message-sign]\n" | |
bdcfe844 | 936 | " " |
f0d73c14 | 937 | "\t\t Signature: \\[mh-insert-signature]")) |
bdcfe844 BW |
938 | "Key binding cheat sheet. |
939 | ||
2dcf34f9 BW |
940 | This is an associative array which is used to show the most |
941 | common commands. The key is a prefix char. The value is one or | |
942 | more strings which are concatenated together and displayed in the | |
943 | minibuffer if ? is pressed after the prefix character. The | |
944 | special key nil is used to display the non-prefixed commands. | |
bdcfe844 | 945 | |
2dcf34f9 BW |
946 | The substitutions described in `substitute-command-keys' are |
947 | performed as well.") | |
bdcfe844 | 948 | |
c3d9274a | 949 | ;;;###mh-autoload |
bdcfe844 BW |
950 | (defun mh-fill-paragraph-function (arg) |
951 | "Fill paragraph at or after point. | |
2dcf34f9 BW |
952 | Prefix ARG means justify as well. This function enables |
953 | `fill-paragraph' to work better in MH-Letter mode (see | |
954 | `mh-letter-mode')." | |
bdcfe844 BW |
955 | (interactive "P") |
956 | (let ((fill-paragraph-function) (fill-prefix)) | |
957 | (if (mh-in-header-p) | |
958 | (mail-mode-fill-paragraph arg) | |
959 | (fill-paragraph arg)))) | |
c26cf6c8 | 960 | |
924df208 BW |
961 | ;; Avoid compiler warnings in XEmacs and Emacs 20 |
962 | (eval-when-compile | |
963 | (defvar tool-bar-mode) | |
964 | (defvar tool-bar-map)) | |
965 | ||
1dd9796d SD |
966 | (defvar mh-letter-buttons-init-flag nil) |
967 | ||
c26cf6c8 | 968 | ;;;###autoload |
f7c4478f | 969 | (define-derived-mode mh-letter-mode text-mode "MH-Letter" |
d1699462 | 970 | "Mode for composing letters in MH-E\\<mh-letter-mode-map>. |
a1b4049d | 971 | |
2dcf34f9 BW |
972 | When you have finished composing, type \\[mh-send-letter] to send |
973 | the message using the MH mail handling system. | |
c26cf6c8 | 974 | |
2dcf34f9 BW |
975 | There are two types of tags used by MH-E when composing MIME |
976 | messages: MML and MH. The option `mh-compose-insertion' controls | |
977 | what type of tags are inserted by MH-E commands. These tags can | |
978 | be converted to MIME body parts by running \\[mh-mh-to-mime] for | |
979 | MH-style directives or \\[mh-mml-to-mime] for MML tags. | |
c26cf6c8 | 980 | |
d1699462 BW |
981 | Options that control this mode can be changed with |
982 | \\[customize-group]; specify the \"mh-compose\" group. | |
c26cf6c8 | 983 | |
a1b4049d BW |
984 | When a message is composed, the hooks `text-mode-hook' and |
985 | `mh-letter-mode-hook' are run. | |
c26cf6c8 | 986 | |
a1b4049d | 987 | \\{mh-letter-mode-map}" |
f0d73c14 | 988 | (mh-find-path) |
c26cf6c8 RS |
989 | (make-local-variable 'mh-send-args) |
990 | (make-local-variable 'mh-annotate-char) | |
991 | (make-local-variable 'mh-annotate-field) | |
992 | (make-local-variable 'mh-previous-window-config) | |
993 | (make-local-variable 'mh-sent-from-folder) | |
994 | (make-local-variable 'mh-sent-from-msg) | |
1dd9796d SD |
995 | (mh-do-in-gnu-emacs |
996 | (unless mh-letter-buttons-init-flag | |
997 | (mh-tool-bar-letter-buttons-init) | |
998 | (setq mh-letter-buttons-init-flag t))) | |
f0d73c14 BW |
999 | ;; Set the local value of mh-mail-header-separator according to what is |
1000 | ;; present in the buffer... | |
1001 | (set (make-local-variable 'mh-mail-header-separator) | |
1002 | (save-excursion | |
1003 | (goto-char (mh-mail-header-end)) | |
1004 | (buffer-substring-no-properties (point) (line-end-position)))) | |
c26cf6c8 | 1005 | (make-local-variable 'mail-header-separator) |
a1b4049d | 1006 | (setq mail-header-separator mh-mail-header-separator) ;override sendmail.el |
bdcfe844 BW |
1007 | (make-local-variable 'mh-help-messages) |
1008 | (setq mh-help-messages mh-letter-mode-help-messages) | |
a66894d8 BW |
1009 | (setq buffer-invisibility-spec '((vanish . t) t)) |
1010 | (set (make-local-variable 'line-move-ignore-invisible) t) | |
1011 | ||
a1b4049d BW |
1012 | ;; From sendmail.el for proper paragraph fill |
1013 | ;; sendmail.el also sets a normal-auto-fill-function (not done here) | |
1014 | (make-local-variable 'paragraph-separate) | |
1015 | (make-local-variable 'paragraph-start) | |
1016 | (make-local-variable 'fill-paragraph-function) | |
bdcfe844 | 1017 | (setq fill-paragraph-function 'mh-fill-paragraph-function) |
a1b4049d BW |
1018 | (make-local-variable 'adaptive-fill-regexp) |
1019 | (setq adaptive-fill-regexp | |
c3d9274a BW |
1020 | (concat adaptive-fill-regexp |
1021 | "\\|[ \t]*[-[:alnum:]]*>+[ \t]*")) | |
a1b4049d BW |
1022 | (make-local-variable 'adaptive-fill-first-line-regexp) |
1023 | (setq adaptive-fill-first-line-regexp | |
c3d9274a BW |
1024 | (concat adaptive-fill-first-line-regexp |
1025 | "\\|[ \t]*[-[:alnum:]]*>+[ \t]*")) | |
a1b4049d BW |
1026 | ;; `-- ' precedes the signature. `-----' appears at the start of the |
1027 | ;; lines that delimit forwarded messages. | |
1028 | ;; Lines containing just >= 3 dashes, perhaps after whitespace, | |
1029 | ;; are also sometimes used and should be separators. | |
1030 | (setq paragraph-start (concat (regexp-quote mail-header-separator) | |
c3d9274a BW |
1031 | "\\|\t*\\([-|#;>* ]\\|(?[0-9]+[.)]\\)+$" |
1032 | "\\|[ \t]*[[:alnum:]]*>+[ \t]*$\\|[ \t]*$\\|" | |
1033 | "-- $\\|---+$\\|" | |
1034 | page-delimiter)) | |
a1b4049d BW |
1035 | (setq paragraph-separate paragraph-start) |
1036 | ;; --- End of code from sendmail.el --- | |
1037 | ||
924df208 BW |
1038 | ;; Enable undo since a show-mode buffer might have been reused. |
1039 | (buffer-enable-undo) | |
a66894d8 | 1040 | (set (make-local-variable 'tool-bar-map) mh-letter-tool-bar-map) |
fa4075e3 | 1041 | (mh-funcall-if-exists mh-tool-bar-init :letter) |
a1b4049d BW |
1042 | (make-local-variable 'font-lock-defaults) |
1043 | (cond | |
553fb735 BW |
1044 | ((or (equal mh-highlight-citation-style 'font-lock) |
1045 | (equal mh-highlight-citation-style 'gnus)) | |
bdcfe844 BW |
1046 | ;; Let's use font-lock even if gnus is used in show-mode. The reason |
1047 | ;; is that gnus uses static text properties which are not appropriate | |
1048 | ;; for a buffer that will be edited. So the choice here is either fontify | |
1049 | ;; the citations and header... | |
a66894d8 | 1050 | (setq font-lock-defaults '(mh-letter-font-lock-keywords t))) |
a1b4049d | 1051 | (t |
bdcfe844 | 1052 | ;; ...or the header only |
a1b4049d BW |
1053 | (setq font-lock-defaults '(mh-show-font-lock-keywords t)))) |
1054 | (easy-menu-add mh-letter-menu) | |
a1b4049d | 1055 | (setq fill-column mh-letter-fill-column) |
c3d9274a | 1056 | ;; If text-mode-hook turned on auto-fill, tune it for messages |
f7c4478f SM |
1057 | (when auto-fill-function |
1058 | (make-local-variable 'auto-fill-function) | |
1059 | (setq auto-fill-function 'mh-auto-fill-for-letter))) | |
c26cf6c8 | 1060 | |
a66894d8 BW |
1061 | (defun mh-font-lock-field-data (limit) |
1062 | "Find header field region between point and LIMIT." | |
1063 | (and (< (point) (mh-letter-header-end)) | |
1064 | (< (point) limit) | |
1065 | (let ((end (min limit (mh-letter-header-end))) | |
1066 | (point (point)) | |
1067 | data-end data-begin field) | |
1068 | (end-of-line) | |
1069 | (setq data-end (if (re-search-forward "^[^ \t]" end t) | |
1070 | (match-beginning 0) | |
1071 | end)) | |
1072 | (goto-char (1- data-end)) | |
1073 | (if (not (re-search-backward "\\(^[^ \t][^:]*\\):[ \t]*" nil t)) | |
1074 | (setq data-begin (point-min)) | |
1075 | (setq data-begin (match-end 0)) | |
1076 | (setq field (match-string 1))) | |
1077 | (setq data-begin (max point data-begin)) | |
a66894d8 | 1078 | (goto-char (if (equal point data-end) (1+ data-end) data-end)) |
a05fcb7d BW |
1079 | (cond ((and field (mh-letter-skipped-header-field-p field)) |
1080 | (set-match-data nil) | |
1081 | nil) | |
1082 | (t (set-match-data | |
1083 | (list data-begin data-end data-begin data-end)) | |
1084 | t))))) | |
a66894d8 BW |
1085 | |
1086 | (defun mh-letter-header-end () | |
f0d73c14 | 1087 | "Find the end of the message header. |
2dcf34f9 BW |
1088 | This function is to be used only for font locking. It works by |
1089 | searching for `mh-mail-header-separator' in the buffer." | |
a66894d8 | 1090 | (save-excursion |
f0d73c14 BW |
1091 | (goto-char (point-min)) |
1092 | (cond ((equal mh-mail-header-separator "") (point-min)) | |
1093 | ((search-forward (format "\n%s\n" mh-mail-header-separator) nil t) | |
1094 | (line-beginning-position 0)) | |
1095 | (t (point-min))))) | |
a66894d8 | 1096 | |
c26cf6c8 | 1097 | (defun mh-auto-fill-for-letter () |
bdcfe844 | 1098 | "Perform auto-fill for message. |
2dcf34f9 BW |
1099 | Header is treated specially by inserting a tab before continuation |
1100 | lines." | |
c26cf6c8 | 1101 | (if (mh-in-header-p) |
9303c8db | 1102 | (let ((fill-prefix "\t")) |
c3d9274a | 1103 | (do-auto-fill)) |
9303c8db | 1104 | (do-auto-fill))) |
c26cf6c8 | 1105 | |
a1b4049d | 1106 | (defun mh-insert-header-separator () |
bdcfe844 | 1107 | "Insert `mh-mail-header-separator', if absent." |
c26cf6c8 | 1108 | (save-excursion |
a1b4049d BW |
1109 | (goto-char (point-min)) |
1110 | (rfc822-goto-eoh) | |
1111 | (if (looking-at "$") | |
c3d9274a | 1112 | (insert mh-mail-header-separator)))) |
c26cf6c8 | 1113 | |
c3d9274a | 1114 | ;;;###mh-autoload |
c26cf6c8 | 1115 | (defun mh-to-field () |
0c47b17c | 1116 | "Move to specified header field. |
c26cf6c8 | 1117 | The field is indicated by the previous keystroke (the last keystroke |
2dcf34f9 BW |
1118 | of the command) according to the list in the variable |
1119 | `mh-to-field-choices'. Create the field if it does not exist. Set the | |
1120 | mark to point before moving." | |
c26cf6c8 RS |
1121 | (interactive) |
1122 | (expand-abbrev) | |
847b8219 | 1123 | (let ((target (cdr (or (assoc (char-to-string (logior last-input-char ?`)) |
c3d9274a BW |
1124 | mh-to-field-choices) |
1125 | ;; also look for a char for version 4 compat | |
1126 | (assoc (logior last-input-char ?`) | |
1127 | mh-to-field-choices)))) | |
1128 | (case-fold-search t)) | |
c26cf6c8 RS |
1129 | (push-mark) |
1130 | (cond ((mh-position-on-field target) | |
c3d9274a BW |
1131 | (let ((eol (point))) |
1132 | (skip-chars-backward " \t") | |
1133 | (delete-region (point) eol)) | |
1134 | (if (and (not (eq (logior last-input-char ?`) ?s)) | |
1135 | (save-excursion | |
1136 | (backward-char 1) | |
1137 | (not (looking-at "[:,]")))) | |
1138 | (insert ", ") | |
1139 | (insert " "))) | |
1140 | (t | |
1141 | (if (mh-position-on-field "To:") | |
1142 | (forward-line 1)) | |
1143 | (insert (format "%s \n" target)) | |
1144 | (backward-char 1))))) | |
c26cf6c8 | 1145 | |
c3d9274a | 1146 | ;;;###mh-autoload |
c26cf6c8 | 1147 | (defun mh-to-fcc (&optional folder) |
0c47b17c | 1148 | "Move to \"Fcc:\" header field. |
2dcf34f9 BW |
1149 | This command will prompt you for the FOLDER name in which to file a |
1150 | copy of the draft." | |
c26cf6c8 RS |
1151 | (interactive) |
1152 | (or folder | |
1153 | (setq folder (mh-prompt-for-folder | |
c3d9274a BW |
1154 | "Fcc" |
1155 | (or (and mh-default-folder-for-message-function | |
1156 | (save-excursion | |
1157 | (goto-char (point-min)) | |
1158 | (funcall | |
1159 | mh-default-folder-for-message-function))) | |
1160 | "") | |
1161 | t))) | |
c26cf6c8 RS |
1162 | (let ((last-input-char ?\C-f)) |
1163 | (expand-abbrev) | |
1164 | (save-excursion | |
1165 | (mh-to-field) | |
1166 | (insert (if (mh-folder-name-p folder) | |
c3d9274a BW |
1167 | (substring folder 1) |
1168 | folder))))) | |
c26cf6c8 | 1169 | |
f0d73c14 BW |
1170 | (defun mh-file-is-vcard-p (file) |
1171 | "Return t if FILE is a .vcf vcard." | |
1172 | (let ((case-fold-search t)) | |
1173 | (and (stringp file) | |
1174 | (file-exists-p file) | |
1175 | (or (and (not (mh-have-file-command)) | |
1176 | (not (null (string-match "\.vcf$" file)))) | |
1177 | (and (mh-have-file-command) | |
1178 | (string-equal "text/x-vcard" (mh-file-mime-type file))))))) | |
1179 | ||
c3d9274a | 1180 | ;;;###mh-autoload |
f0d73c14 | 1181 | (defun mh-insert-signature (&optional file) |
0c47b17c | 1182 | "Insert signature in message. |
d1699462 | 1183 | |
0c47b17c BW |
1184 | This command inserts your signature at the current cursor location. |
1185 | ||
1186 | By default, the text of your signature is taken from the file | |
d1699462 BW |
1187 | \"~/.signature\". You can read from other sources by changing the |
1188 | option `mh-signature-file-name'. | |
0c47b17c | 1189 | |
d1699462 BW |
1190 | A signature separator (\"-- \") will be added if the signature block |
1191 | does not contain one and `mh-signature-separator-flag' is on. | |
0c47b17c | 1192 | |
d1699462 BW |
1193 | The hook `mh-insert-signature-hook' is run after the signature is |
1194 | inserted. Hook functions may access the actual name of the file or the | |
1195 | function used to insert the signature with `mh-signature-file-name'. | |
0c47b17c | 1196 | |
d1699462 BW |
1197 | The signature can also be inserted using Identities (see |
1198 | `mh-identity-list'). | |
1199 | ||
1200 | In a program, you can pass in a signature FILE." | |
0c47b17c | 1201 | (interactive) |
f0d73c14 BW |
1202 | (save-excursion |
1203 | (insert "\n") | |
1204 | (let ((mh-signature-file-name (or file mh-signature-file-name)) | |
0c47b17c BW |
1205 | (mh-mh-p (mh-mh-directive-present-p)) |
1206 | (mh-mml-p (mh-mml-tag-present-p))) | |
f0d73c14 BW |
1207 | (save-restriction |
1208 | (narrow-to-region (point) (point)) | |
1209 | (cond | |
1210 | ((mh-file-is-vcard-p mh-signature-file-name) | |
0c47b17c | 1211 | (if (equal mh-compose-insertion 'mml) |
f0d73c14 BW |
1212 | (insert "<#part type=\"text/x-vcard\" filename=\"" |
1213 | mh-signature-file-name | |
1214 | "\" disposition=inline description=VCard>\n<#/part>") | |
1215 | (insert "#text/x-vcard; name=\"" | |
1216 | (file-name-nondirectory mh-signature-file-name) | |
1217 | "\" [VCard] " (expand-file-name mh-signature-file-name)))) | |
1218 | (t | |
1219 | (cond | |
0c47b17c | 1220 | (mh-mh-p |
f0d73c14 BW |
1221 | (insert "#\n" "Content-Description: Signature\n")) |
1222 | (mh-mml-p | |
1223 | (mml-insert-tag 'part 'type "text/plain" 'disposition "inline" | |
1224 | 'description "Signature"))) | |
1225 | (cond ((null mh-signature-file-name)) | |
1226 | ((and (stringp mh-signature-file-name) | |
1227 | (file-readable-p mh-signature-file-name)) | |
1228 | (insert-file-contents mh-signature-file-name)) | |
1229 | ((functionp mh-signature-file-name) | |
1230 | (funcall mh-signature-file-name))))) | |
1231 | (save-restriction | |
1232 | (widen) | |
f15ced66 | 1233 | (run-hooks 'mh-insert-signature-hook)) |
f0d73c14 BW |
1234 | (goto-char (point-min)) |
1235 | (when (and (not (mh-file-is-vcard-p mh-signature-file-name)) | |
1236 | mh-signature-separator-flag | |
1237 | (> (point-max) (point-min)) | |
1238 | (not (mh-signature-separator-p))) | |
0c47b17c | 1239 | (cond (mh-mh-p |
f0d73c14 BW |
1240 | (forward-line 2)) |
1241 | (mh-mml-p | |
1242 | (forward-line 1))) | |
1243 | (insert mh-signature-separator)) | |
1244 | (if (not (> (point-max) (point-min))) | |
1245 | (message "No signature found"))))) | |
2450bd29 | 1246 | (force-mode-line-update)) |
c26cf6c8 | 1247 | |
c3d9274a | 1248 | ;;;###mh-autoload |
c26cf6c8 | 1249 | (defun mh-check-whom () |
0c47b17c | 1250 | "Verify recipients, showing expansion of any aliases. |
2dcf34f9 BW |
1251 | |
1252 | This command expands aliases so you can check the actual address(es) | |
1253 | in the alias. A new buffer named \"*MH-E Recipients*\" is created with | |
1254 | the output of \"whom\"." | |
c26cf6c8 | 1255 | (interactive) |
847b8219 | 1256 | (let ((file-name buffer-file-name)) |
c26cf6c8 RS |
1257 | (save-buffer) |
1258 | (message "Checking recipients...") | |
3d7ca223 | 1259 | (mh-in-show-buffer (mh-recipients-buffer) |
c26cf6c8 RS |
1260 | (bury-buffer (current-buffer)) |
1261 | (erase-buffer) | |
1262 | (mh-exec-cmd-output "whom" t file-name)) | |
1263 | (message "Checking recipients...done"))) | |
1264 | ||
3d7ca223 BW |
1265 | (defun mh-tidy-draft-buffer () |
1266 | "Run when a draft buffer is destroyed." | |
1267 | (let ((buffer (get-buffer mh-recipients-buffer))) | |
1268 | (if buffer | |
1269 | (kill-buffer buffer)))) | |
1270 | ||
c26cf6c8 RS |
1271 | \f |
1272 | ||
1273 | ;;; Routines to compose and send a letter. | |
1274 | ||
bdcfe844 | 1275 | (defun mh-insert-x-face () |
924df208 | 1276 | "Append X-Face, Face or X-Image-URL field to header. |
bdcfe844 BW |
1277 | If the field already exists, this function does nothing." |
1278 | (when (and (file-exists-p mh-x-face-file) | |
1279 | (file-readable-p mh-x-face-file)) | |
1280 | (save-excursion | |
924df208 BW |
1281 | (unless (or (mh-position-on-field "X-Face") |
1282 | (mh-position-on-field "Face") | |
1283 | (mh-position-on-field "X-Image-URL")) | |
1284 | (save-excursion | |
1285 | (goto-char (+ (point) (cadr (insert-file-contents mh-x-face-file)))) | |
1286 | (if (not (looking-at "^")) | |
1287 | (insert "\n"))) | |
1288 | (unless (looking-at "\\(X-Face\\|Face\\|X-Image-URL\\): ") | |
1289 | (insert "X-Face: ")))))) | |
1290 | ||
1291 | (defvar mh-x-mailer-string nil | |
1292 | "*String containing the contents of the X-Mailer header field. | |
2dcf34f9 BW |
1293 | If nil, this variable is initialized to show the version of MH-E, |
1294 | Emacs, and MH the first time a message is composed.") | |
bdcfe844 | 1295 | |
a1b4049d | 1296 | (defun mh-insert-x-mailer () |
bdcfe844 BW |
1297 | "Append an X-Mailer field to the header. |
1298 | The versions of MH-E, Emacs, and MH are shown." | |
a1b4049d | 1299 | ;; Lazily initialize mh-x-mailer-string. |
a66894d8 | 1300 | (when (and mh-insert-x-mailer-flag (null mh-x-mailer-string)) |
f0d73c14 BW |
1301 | (setq mh-x-mailer-string |
1302 | (format "MH-E %s; %s; %sEmacs %s" | |
1303 | mh-version mh-variant-in-use | |
1304 | (if mh-xemacs-flag "X" "GNU ") | |
1305 | (cond ((not mh-xemacs-flag) emacs-version) | |
1306 | ((string-match "[0-9.]*\\( +\([ a-z]+[0-9]+\)\\)?" | |
1307 | emacs-version) | |
1308 | (match-string 0 emacs-version)) | |
1309 | (t (format "%s.%s" emacs-major-version | |
1310 | emacs-minor-version)))))) | |
a1b4049d BW |
1311 | ;; Insert X-Mailer, but only if it doesn't already exist. |
1312 | (save-excursion | |
a66894d8 BW |
1313 | (when (and mh-insert-x-mailer-flag |
1314 | (null (mh-goto-header-field "X-Mailer"))) | |
c3d9274a | 1315 | (mh-insert-fields "X-Mailer:" mh-x-mailer-string)))) |
a1b4049d | 1316 | |
bdcfe844 BW |
1317 | (defun mh-regexp-in-field-p (regexp &rest fields) |
1318 | "Non-nil means REGEXP was found in FIELDS." | |
1319 | (save-excursion | |
1320 | (let ((search-result nil) | |
1321 | (field)) | |
1322 | (while fields | |
1323 | (setq field (car fields)) | |
1324 | (if (and (mh-goto-header-field field) | |
1325 | (re-search-forward | |
1326 | regexp (save-excursion (mh-header-field-end)(point)) t)) | |
1327 | (setq fields nil | |
1328 | search-result t) | |
1329 | (setq fields (cdr fields)))) | |
1330 | search-result))) | |
1331 | ||
a66894d8 BW |
1332 | ;;;###mh-autoload |
1333 | (defun mh-insert-auto-fields (&optional non-interactive) | |
3b463df0 | 1334 | "Insert custom fields if recipient is found in `mh-auto-fields-list'. |
a66894d8 | 1335 | |
2dcf34f9 BW |
1336 | Sets buffer-local `mh-insert-auto-fields-done-local' when done |
1337 | and inserted something. If NON-INTERACTIVE is non-nil, do not be | |
1338 | verbose and only attempt matches if | |
1339 | `mh-insert-auto-fields-done-local' is nil. | |
1340 | ||
1341 | An `identity' entry is skipped if one was already entered | |
1342 | manually. | |
f0d73c14 BW |
1343 | |
1344 | Return t if fields added; otherwise return nil." | |
a66894d8 | 1345 | (interactive) |
f0d73c14 BW |
1346 | (when (or (not non-interactive) |
1347 | (not mh-insert-auto-fields-done-local)) | |
a66894d8 | 1348 | (save-excursion |
f0d73c14 BW |
1349 | (when (and (or (mh-goto-header-field "To:") |
1350 | (mh-goto-header-field "cc:"))) | |
1351 | (let ((list mh-auto-fields-list) | |
1352 | (fields-inserted nil)) | |
a66894d8 BW |
1353 | (while list |
1354 | (let ((regexp (nth 0 (car list))) | |
1355 | (entries (nth 1 (car list)))) | |
1356 | (when (mh-regexp-in-field-p regexp "To:" "cc:") | |
1357 | (setq mh-insert-auto-fields-done-local t) | |
f0d73c14 | 1358 | (setq fields-inserted t) |
a66894d8 | 1359 | (if (not non-interactive) |
f0d73c14 | 1360 | (message "Fields for %s added" regexp)) |
a66894d8 BW |
1361 | (let ((entry-list entries)) |
1362 | (while entry-list | |
1363 | (let ((field (caar entry-list)) | |
1364 | (value (cdar entry-list))) | |
1365 | (cond | |
f0d73c14 | 1366 | ((equal ":identity" field) |
a05fcb7d BW |
1367 | (when ;;(and (not mh-identity-local) |
1368 | ;; Bug 1204506. But do we need to be able | |
1369 | ;; to set an identity manually that won't be | |
1370 | ;; overridden by mh-insert-auto-fields? | |
1371 | (assoc value mh-identity-list) | |
1372 | ;;) | |
a66894d8 BW |
1373 | (mh-insert-identity value))) |
1374 | (t | |
1375 | (mh-modify-header-field field value | |
1376 | (equal field "From"))))) | |
1377 | (setq entry-list (cdr entry-list)))))) | |
f0d73c14 BW |
1378 | (setq list (cdr list))) |
1379 | fields-inserted))))) | |
924df208 BW |
1380 | |
1381 | (defun mh-modify-header-field (field value &optional overwrite-flag) | |
1382 | "To header FIELD add VALUE. | |
2dcf34f9 BW |
1383 | If OVERWRITE-FLAG is non-nil then the old value, if present, is |
1384 | discarded." | |
a66894d8 BW |
1385 | (cond ((and overwrite-flag |
1386 | (mh-goto-header-field (concat field ":"))) | |
1387 | (insert " " value) | |
1388 | (delete-region (point) (line-end-position))) | |
1389 | ((and (not overwrite-flag) | |
1390 | (mh-regexp-in-field-p (concat "\\b" value "\\b") field)) | |
1391 | ;; Already there, do nothing. | |
1392 | ) | |
1393 | ((and (not overwrite-flag) | |
1394 | (mh-goto-header-field (concat field ":"))) | |
1395 | (insert " " value ",")) | |
1396 | (t | |
1397 | (mh-goto-header-end 0) | |
1398 | (insert field ": " value "\n")))) | |
1399 | ||
c26cf6c8 | 1400 | (defun mh-compose-and-send-mail (draft send-args |
c3d9274a BW |
1401 | sent-from-folder sent-from-msg |
1402 | to subject cc | |
1403 | annotate-char annotate-field | |
1404 | config) | |
bdcfe844 BW |
1405 | "Edit and compose a draft message in buffer DRAFT and send or save it. |
1406 | SEND-ARGS is the argument passed to the send command. | |
2dcf34f9 BW |
1407 | SENT-FROM-FOLDER is buffer containing scan listing of current folder, |
1408 | or nil if none exists. | |
bdcfe844 BW |
1409 | SENT-FROM-MSG is the message number or sequence name or nil. |
1410 | The TO, SUBJECT, and CC fields are passed to the | |
1411 | `mh-compose-letter-function'. | |
2dcf34f9 BW |
1412 | If ANNOTATE-CHAR is non-null, it is used to notate the scan listing of |
1413 | the message. In that case, the ANNOTATE-FIELD is used to build a | |
1414 | string for `mh-annotate-msg'. | |
1415 | CONFIG is the window configuration to restore after sending the | |
1416 | letter." | |
c26cf6c8 RS |
1417 | (pop-to-buffer draft) |
1418 | (mh-letter-mode) | |
a1506d29 | 1419 | |
f0d73c14 | 1420 | ;; Insert identity. |
c3d9274a | 1421 | (if (and (boundp 'mh-identity-default) |
924df208 BW |
1422 | mh-identity-default |
1423 | (not mh-identity-local)) | |
c3d9274a | 1424 | (mh-insert-identity mh-identity-default)) |
f0d73c14 BW |
1425 | (mh-identity-make-menu) |
1426 | (easy-menu-add mh-identity-menu) | |
a1506d29 | 1427 | |
f0d73c14 | 1428 | ;; Insert extra fields. |
a66894d8 BW |
1429 | (mh-insert-x-mailer) |
1430 | (mh-insert-x-face) | |
f0d73c14 | 1431 | |
a66894d8 BW |
1432 | (mh-letter-hide-all-skipped-fields) |
1433 | ||
c26cf6c8 RS |
1434 | (setq mh-sent-from-folder sent-from-folder) |
1435 | (setq mh-sent-from-msg sent-from-msg) | |
1436 | (setq mh-send-args send-args) | |
1437 | (setq mh-annotate-char annotate-char) | |
1438 | (setq mh-annotate-field annotate-field) | |
1439 | (setq mh-previous-window-config config) | |
3d7ca223 BW |
1440 | (setq mode-line-buffer-identification (list " {%b}")) |
1441 | (mh-logo-display) | |
924df208 | 1442 | (mh-make-local-hook 'kill-buffer-hook) |
3d7ca223 | 1443 | (add-hook 'kill-buffer-hook 'mh-tidy-draft-buffer nil t) |
c26cf6c8 | 1444 | (if (and (boundp 'mh-compose-letter-function) |
c3d9274a | 1445 | mh-compose-letter-function) |
c26cf6c8 | 1446 | ;; run-hooks will not pass arguments. |
847b8219 | 1447 | (let ((value mh-compose-letter-function)) |
c3d9274a BW |
1448 | (if (and (listp value) (not (eq (car value) 'lambda))) |
1449 | (while value | |
1450 | (funcall (car value) to subject cc) | |
1451 | (setq value (cdr value))) | |
1452 | (funcall mh-compose-letter-function to subject cc))))) | |
c26cf6c8 | 1453 | |
bdcfe844 BW |
1454 | (defun mh-letter-mode-message () |
1455 | "Display a help message for users of `mh-letter-mode'. | |
1456 | This should be the last function called when composing the draft." | |
1457 | (message "%s" (substitute-command-keys | |
c3d9274a | 1458 | (concat "Type \\[mh-send-letter] to send message, " |
f0d73c14 BW |
1459 | "\\[mh-help] for help")))) |
1460 | ||
1461 | (defun mh-ascii-buffer-p () | |
1462 | "Check if current buffer is entirely composed of ASCII. | |
2dcf34f9 BW |
1463 | The function doesn't work for XEmacs since `find-charset-region' |
1464 | doesn't exist there." | |
f0d73c14 BW |
1465 | (loop for charset in (mh-funcall-if-exists |
1466 | find-charset-region (point-min) (point-max)) | |
1467 | unless (eq charset 'ascii) return nil | |
1468 | finally return t)) | |
c26cf6c8 | 1469 | |
c3d9274a | 1470 | ;;;###mh-autoload |
c26cf6c8 | 1471 | (defun mh-send-letter (&optional arg) |
0c47b17c | 1472 | "Save draft and send message. |
0c47b17c | 1473 | |
d1699462 BW |
1474 | When you are all through editing a message, you send it with this |
1475 | command. You can give a prefix argument ARG to monitor the first stage | |
1476 | of the delivery\; this output can be found in a buffer called \"*MH-E | |
1477 | Mail Delivery*\". | |
1478 | ||
1479 | The hook `mh-before-send-letter-hook' is run at the beginning of the | |
1480 | this command. For example, if you want to check your spelling in your | |
1481 | message before sending, add the `ispell-message' function. | |
0c47b17c | 1482 | |
d1699462 BW |
1483 | In case the MH \"send\" program is installed under a different name, |
1484 | use `mh-send-prog' to tell MH-E the name." | |
c26cf6c8 RS |
1485 | (interactive "P") |
1486 | (run-hooks 'mh-before-send-letter-hook) | |
f0d73c14 BW |
1487 | (if (and (mh-insert-auto-fields t) |
1488 | mh-auto-fields-prompt-flag | |
1489 | (goto-char (point-min))) | |
1490 | (if (not (y-or-n-p "Auto fields inserted, send? ")) | |
1491 | (error "Send aborted"))) | |
0c47b17c BW |
1492 | (cond ((mh-mh-directive-present-p) |
1493 | (mh-mh-to-mime)) | |
1494 | ((or (mh-mml-tag-present-p) (not (mh-ascii-buffer-p))) | |
924df208 | 1495 | (mh-mml-to-mime))) |
c26cf6c8 RS |
1496 | (save-buffer) |
1497 | (message "Sending...") | |
1498 | (let ((draft-buffer (current-buffer)) | |
c3d9274a BW |
1499 | (file-name buffer-file-name) |
1500 | (config mh-previous-window-config) | |
1501 | (coding-system-for-write | |
1502 | (if (and (local-variable-p 'buffer-file-coding-system | |
a1b4049d | 1503 | (current-buffer)) ;XEmacs needs two args |
c3d9274a BW |
1504 | ;; We're not sure why, but buffer-file-coding-system |
1505 | ;; tends to get set to undecided-unix. | |
1506 | (not (memq buffer-file-coding-system | |
1507 | '(undecided undecided-unix undecided-dos)))) | |
1508 | buffer-file-coding-system | |
1509 | (or (and (boundp 'sendmail-coding-system) sendmail-coding-system) | |
1510 | (and (boundp 'default-buffer-file-coding-system ) | |
a1b4049d | 1511 | default-buffer-file-coding-system) |
c3d9274a | 1512 | 'iso-latin-1)))) |
bdcfe844 BW |
1513 | ;; The default BCC encapsulation will make a MIME message unreadable. |
1514 | ;; With nmh use the -mime arg to prevent this. | |
f0d73c14 | 1515 | (if (and (mh-variant-p 'nmh) |
c3d9274a BW |
1516 | (mh-goto-header-field "Bcc:") |
1517 | (mh-goto-header-field "Content-Type:")) | |
1518 | (setq mh-send-args (format "-mime %s" mh-send-args))) | |
c26cf6c8 | 1519 | (cond (arg |
924df208 | 1520 | (pop-to-buffer mh-mail-delivery-buffer) |
c3d9274a BW |
1521 | (erase-buffer) |
1522 | (mh-exec-cmd-output mh-send-prog t "-watch" "-nopush" | |
1523 | "-nodraftfolder" mh-send-args file-name) | |
1524 | (goto-char (point-max)) ; show the interesting part | |
1525 | (recenter -1) | |
1526 | (set-buffer draft-buffer)) ; for annotation below | |
1527 | (t | |
3d7ca223 | 1528 | (mh-exec-cmd-daemon mh-send-prog nil "-nodraftfolder" "-noverbose" |
c3d9274a | 1529 | mh-send-args file-name))) |
c26cf6c8 | 1530 | (if mh-annotate-char |
c3d9274a BW |
1531 | (mh-annotate-msg mh-sent-from-msg |
1532 | mh-sent-from-folder | |
1533 | mh-annotate-char | |
1534 | "-component" mh-annotate-field | |
1535 | "-text" (format "\"%s %s\"" | |
1536 | (mh-get-header-field "To:") | |
1537 | (mh-get-header-field "Cc:")))) | |
c26cf6c8 RS |
1538 | |
1539 | (cond ((or (not arg) | |
c3d9274a BW |
1540 | (y-or-n-p "Kill draft buffer? ")) |
1541 | (kill-buffer draft-buffer) | |
1542 | (if config | |
1543 | (set-window-configuration config)))) | |
c26cf6c8 | 1544 | (if arg |
c3d9274a | 1545 | (message "Sending...done") |
c26cf6c8 RS |
1546 | (message "Sending...backgrounded")))) |
1547 | ||
c3d9274a | 1548 | ;;;###mh-autoload |
847b8219 | 1549 | (defun mh-insert-letter (folder message verbatim) |
0c47b17c | 1550 | "Insert a message. |
2dcf34f9 BW |
1551 | |
1552 | This command prompts you for the FOLDER and MESSAGE number and inserts | |
1553 | the message, indented by `mh-ins-buf-prefix' (\"> \") unless | |
1554 | `mh-yank-behavior' is set to one of the supercite flavors in which | |
1555 | case supercite is used to format the message. Certain undesirable | |
1556 | header fields (see `mh-invisible-header-fields-compiled') are removed | |
1557 | before insertion. | |
1558 | ||
1559 | If given a prefix argument VERBATIM, the header is left intact, the | |
1560 | message is not indented, and \"> \" is not inserted before each line. | |
1561 | This command leaves the mark before the letter and point after it." | |
c26cf6c8 | 1562 | (interactive |
847b8219 | 1563 | (list (mh-prompt-for-folder "Message from" mh-sent-from-folder nil) |
a10f4ace BW |
1564 | (read-string (concat "Message number" |
1565 | (if (numberp mh-sent-from-msg) | |
1566 | (format " (default %d): " mh-sent-from-msg) | |
1567 | ": "))) | |
c3d9274a | 1568 | current-prefix-arg)) |
c26cf6c8 RS |
1569 | (save-restriction |
1570 | (narrow-to-region (point) (point)) | |
1571 | (let ((start (point-min))) | |
f0d73c14 BW |
1572 | (if (and (equal message "") (numberp mh-sent-from-msg)) |
1573 | (setq message (int-to-string mh-sent-from-msg))) | |
bdcfe844 BW |
1574 | (insert-file-contents |
1575 | (expand-file-name message (mh-expand-file-name folder))) | |
1576 | (when (not verbatim) | |
f0d73c14 | 1577 | (mh-clean-msg-header start mh-invisible-header-fields-compiled nil) |
c3d9274a BW |
1578 | (goto-char (point-max)) ;Needed for sc-cite-original |
1579 | (push-mark) ;Needed for sc-cite-original | |
1580 | (goto-char (point-min)) ;Needed for sc-cite-original | |
bdcfe844 BW |
1581 | (mh-insert-prefix-string mh-ins-buf-prefix))))) |
1582 | ||
1583 | (defun mh-extract-from-attribution () | |
1584 | "Extract phrase or comment from From header field." | |
1585 | (save-excursion | |
1586 | (if (not (mh-goto-header-field "From: ")) | |
1587 | nil | |
1588 | (skip-chars-forward " ") | |
1589 | (cond | |
1590 | ((looking-at "\"\\([^\"\n]+\\)\" \\(<.+>\\)") | |
f0d73c14 | 1591 | (format "%s %s " (match-string 1)(match-string 2))) |
bdcfe844 | 1592 | ((looking-at "\\([^<\n]+<.+>\\)$") |
f0d73c14 | 1593 | (format "%s " (match-string 1))) |
bdcfe844 | 1594 | ((looking-at "\\([^ ]+@[^ ]+\\) +(\\(.+\\))$") |
f0d73c14 | 1595 | (format "%s <%s> " (match-string 2)(match-string 1))) |
bdcfe844 | 1596 | ((looking-at " *\\(.+\\)$") |
f0d73c14 | 1597 | (format "%s " (match-string 1))))))) |
c26cf6c8 | 1598 | |
c3d9274a | 1599 | ;;;###mh-autoload |
c26cf6c8 RS |
1600 | (defun mh-yank-cur-msg () |
1601 | "Insert the current message into the draft buffer. | |
0c47b17c | 1602 | |
2dcf34f9 BW |
1603 | It is often useful to insert a snippet of text from a letter that |
1604 | someone mailed to provide some context for your reply. This | |
1605 | command does this by adding an attribution, yanking a portion of | |
1606 | text from the message to which you're replying, and inserting | |
1607 | `mh-ins-buf-prefix' (`> ') before each line. | |
0c47b17c BW |
1608 | |
1609 | The attribution consists of the sender's name and email address | |
1610 | followed by the content of the `mh-extract-from-attribution-verb' | |
1611 | option. | |
1612 | ||
2dcf34f9 BW |
1613 | You can also turn on the `mh-delete-yanked-msg-window-flag' |
1614 | option to delete the window containing the original message after | |
1615 | yanking it to make more room on your screen for your reply. | |
0c47b17c | 1616 | |
2dcf34f9 BW |
1617 | You can control how the message to which you are replying is |
1618 | yanked into your reply using `mh-yank-behavior'. | |
0c47b17c | 1619 | |
2dcf34f9 BW |
1620 | If this isn't enough, you can gain full control over the |
1621 | appearance of the included text by setting `mail-citation-hook' | |
1622 | to a function that modifies it. For example, if you set this hook | |
4023e353 | 1623 | to `trivial-cite' (which is NOT part of Emacs), set |
2dcf34f9 | 1624 | `mh-yank-behavior' to \"Body and Header\" (see URL |
d1699462 BW |
1625 | `http://shasta.cs.uiuc.edu/~lrclause/tc.html'). |
1626 | ||
2dcf34f9 BW |
1627 | Note that if `mail-citation-hook' is set, `mh-ins-buf-prefix' is |
1628 | not inserted. If the option `mh-yank-behavior' is set to one of | |
1629 | the supercite flavors, the hook `mail-citation-hook' is ignored | |
1630 | and `mh-ins-buf-prefix' is not inserted." | |
c26cf6c8 | 1631 | (interactive) |
bdcfe844 BW |
1632 | (if (and mh-sent-from-folder |
1633 | (save-excursion (set-buffer mh-sent-from-folder) mh-show-buffer) | |
1634 | (save-excursion (set-buffer mh-sent-from-folder) | |
1635 | (get-buffer mh-show-buffer)) | |
1636 | mh-sent-from-msg) | |
c26cf6c8 | 1637 | (let ((to-point (point)) |
c3d9274a BW |
1638 | (to-buffer (current-buffer))) |
1639 | (set-buffer mh-sent-from-folder) | |
1640 | (if mh-delete-yanked-msg-window-flag | |
1641 | (delete-windows-on mh-show-buffer)) | |
1642 | (set-buffer mh-show-buffer) ; Find displayed message | |
1643 | (let* ((from-attr (mh-extract-from-attribution)) | |
1644 | (yank-region (mh-mark-active-p nil)) | |
bdcfe844 BW |
1645 | (mh-ins-str |
1646 | (cond ((and yank-region | |
0c47b17c BW |
1647 | (or (eq 'supercite mh-yank-behavior) |
1648 | (eq 'autosupercite mh-yank-behavior) | |
1649 | (eq t mh-yank-behavior))) | |
bdcfe844 BW |
1650 | ;; supercite needs the full header |
1651 | (concat | |
924df208 | 1652 | (buffer-substring (point-min) (mh-mail-header-end)) |
bdcfe844 BW |
1653 | "\n" |
1654 | (buffer-substring (region-beginning) (region-end)))) | |
1655 | (yank-region | |
1656 | (buffer-substring (region-beginning) (region-end))) | |
0c47b17c BW |
1657 | ((or (eq 'body mh-yank-behavior) |
1658 | (eq 'attribution mh-yank-behavior) | |
1659 | (eq 'autoattrib mh-yank-behavior)) | |
bdcfe844 BW |
1660 | (buffer-substring |
1661 | (save-excursion | |
1662 | (goto-char (point-min)) | |
1663 | (mh-goto-header-end 1) | |
1664 | (point)) | |
1665 | (point-max))) | |
0c47b17c BW |
1666 | ((or (eq 'supercite mh-yank-behavior) |
1667 | (eq 'autosupercite mh-yank-behavior) | |
1668 | (eq t mh-yank-behavior)) | |
bdcfe844 BW |
1669 | (buffer-substring (point-min) (point-max))) |
1670 | (t | |
1671 | (buffer-substring (point) (point-max)))))) | |
c3d9274a BW |
1672 | (set-buffer to-buffer) |
1673 | (save-restriction | |
1674 | (narrow-to-region to-point to-point) | |
1675 | (insert (mh-filter-out-non-text mh-ins-str)) | |
bdcfe844 | 1676 | (goto-char (point-max)) ;Needed for sc-cite-original |
c3d9274a | 1677 | (push-mark) ;Needed for sc-cite-original |
bdcfe844 | 1678 | (goto-char (point-min)) ;Needed for sc-cite-original |
c3d9274a | 1679 | (mh-insert-prefix-string mh-ins-buf-prefix) |
0c47b17c BW |
1680 | (when (or (eq 'attribution mh-yank-behavior) |
1681 | (eq 'autoattrib mh-yank-behavior)) | |
f0d73c14 BW |
1682 | (insert from-attr) |
1683 | (mh-identity-insert-attribution-verb nil) | |
1684 | (insert "\n\n")) | |
c3d9274a BW |
1685 | ;; If the user has selected a region, he has already "edited" the |
1686 | ;; text, so leave the cursor at the end of the yanked text. In | |
1687 | ;; either case, leave a mark at the opposite end of the included | |
1688 | ;; text to make it easy to jump or delete to the other end of the | |
1689 | ;; text. | |
1690 | (push-mark) | |
1691 | (goto-char (point-max)) | |
1692 | (if (null yank-region) | |
1693 | (mh-exchange-point-and-mark-preserving-active-mark))))) | |
847b8219 | 1694 | (error "There is no current message"))) |
c26cf6c8 | 1695 | |
bdcfe844 BW |
1696 | (defun mh-filter-out-non-text (string) |
1697 | "Return STRING but without adornments such as MIME buttons and smileys." | |
1698 | (with-temp-buffer | |
1699 | ;; Insert the string to filter | |
1700 | (insert string) | |
1701 | (goto-char (point-min)) | |
a1506d29 | 1702 | |
bdcfe844 BW |
1703 | ;; Remove the MIME buttons |
1704 | (let ((can-move-forward t) | |
1705 | (in-button nil)) | |
1706 | (while can-move-forward | |
1707 | (cond ((and (not (get-text-property (point) 'mh-data)) | |
1708 | in-button) | |
c3d9274a | 1709 | (delete-region (1- (point)) (point)) |
bdcfe844 BW |
1710 | (setq in-button nil)) |
1711 | ((get-text-property (point) 'mh-data) | |
1712 | (delete-region (point) | |
1713 | (save-excursion (forward-line) (point))) | |
1714 | (setq in-button t)) | |
1715 | (t (setq can-move-forward (= (forward-line) 0)))))) | |
1716 | ||
1717 | ;; Return the contents without properties... This gets rid of emphasis | |
1718 | ;; and smileys | |
1719 | (buffer-substring-no-properties (point-min) (point-max)))) | |
c26cf6c8 RS |
1720 | |
1721 | (defun mh-insert-prefix-string (mh-ins-string) | |
bdcfe844 | 1722 | "Insert prefix string before each line in buffer. |
2dcf34f9 BW |
1723 | The inserted letter is cited using `sc-cite-original' if |
1724 | `mh-yank-behavior' is one of 'supercite or 'autosupercite. | |
1725 | Otherwise, simply insert MH-INS-STRING before each line." | |
847b8219 | 1726 | (goto-char (point-min)) |
0c47b17c BW |
1727 | (cond ((or (eq mh-yank-behavior 'supercite) |
1728 | (eq mh-yank-behavior 'autosupercite)) | |
bdcfe844 BW |
1729 | (sc-cite-original)) |
1730 | (mail-citation-hook | |
c3d9274a BW |
1731 | (run-hooks 'mail-citation-hook)) |
1732 | (mh-yank-hooks ;old hook name | |
1733 | (run-hooks 'mh-yank-hooks)) | |
1734 | (t | |
1735 | (or (bolp) (forward-line 1)) | |
bdcfe844 BW |
1736 | (while (< (point) (point-max)) |
1737 | (insert mh-ins-string) | |
1738 | (forward-line 1)) | |
1739 | (goto-char (point-min))))) ;leave point like sc-cite-original | |
c26cf6c8 | 1740 | |
c3d9274a | 1741 | ;;;###mh-autoload |
c26cf6c8 | 1742 | (defun mh-fully-kill-draft () |
0c47b17c | 1743 | "Quit editing and delete draft message. |
2dcf34f9 BW |
1744 | If for some reason you are not happy with the draft, you can use |
1745 | the this command to kill the draft buffer and delete the draft | |
1746 | message. Use the \\[kill-buffer] command if you don't want to | |
1747 | delete the draft message." | |
c26cf6c8 RS |
1748 | (interactive) |
1749 | (if (y-or-n-p "Kill draft message? ") | |
1750 | (let ((config mh-previous-window-config)) | |
c3d9274a BW |
1751 | (if (file-exists-p buffer-file-name) |
1752 | (delete-file buffer-file-name)) | |
1753 | (set-buffer-modified-p nil) | |
1754 | (kill-buffer (buffer-name)) | |
1755 | (message "") | |
1756 | (if config | |
1757 | (set-window-configuration config))) | |
c26cf6c8 RS |
1758 | (error "Message not killed"))) |
1759 | ||
a1b4049d | 1760 | (defun mh-current-fill-prefix () |
bdcfe844 | 1761 | "Return the `fill-prefix' on the current line as a string." |
a1b4049d BW |
1762 | (save-excursion |
1763 | (beginning-of-line) | |
1764 | ;; This assumes that the major-mode sets up adaptive-fill-regexp | |
1765 | ;; correctly such as mh-letter-mode or sendmail.el's mail-mode. But | |
1766 | ;; perhaps I should use the variable and simply inserts its value here, | |
1767 | ;; and set it locally in a let scope. --psg | |
1768 | (if (re-search-forward adaptive-fill-regexp nil t) | |
1769 | (match-string 0) | |
1770 | ""))) | |
1771 | ||
c3d9274a | 1772 | ;;;###mh-autoload |
a1b4049d BW |
1773 | (defun mh-open-line () |
1774 | "Insert a newline and leave point after it. | |
2dcf34f9 BW |
1775 | |
1776 | This command is similar to the \\[open-line] command in that it | |
1777 | inserts a newline after point. It differs in that it also inserts | |
1778 | the right number of quoting characters and spaces so that the | |
1779 | next line begins in the same column as it was. This is useful | |
1780 | when breaking up paragraphs in replies." | |
a1b4049d BW |
1781 | (interactive) |
1782 | (let ((column (current-column)) | |
a1b4049d BW |
1783 | (prefix (mh-current-fill-prefix))) |
1784 | (if (> (length prefix) column) | |
1785 | (message "Sorry, point seems to be within the line prefix") | |
1786 | (newline 2) | |
1787 | (insert prefix) | |
1788 | (while (> column (current-column)) | |
1789 | (insert " ")) | |
1790 | (forward-line -1)))) | |
847b8219 | 1791 | |
924df208 BW |
1792 | (mh-do-in-xemacs (defvar mail-abbrevs)) |
1793 | ||
79af55a7 BW |
1794 | (defmacro mh-display-completion-list-compat (word choices) |
1795 | "Completes WORD from CHOICES using `display-completion-list'. | |
1796 | Calls `display-completion-list' correctly in older environments. | |
2dcf34f9 BW |
1797 | Versions of Emacs prior to version 22 lacked a COMMON-SUBSTRING |
1798 | argument which is used to highlight the next possible character you | |
1799 | can enter in the current list of completions." | |
79af55a7 BW |
1800 | (if (>= emacs-major-version 22) |
1801 | `(display-completion-list (all-completions ,word ,choices) ,word) | |
1802 | `(display-completion-list (all-completions ,word ,choices)))) | |
1803 | ||
a66894d8 BW |
1804 | ;;;###mh-autoload |
1805 | (defun mh-complete-word (word choices begin end) | |
1806 | "Complete WORD at from CHOICES. | |
1807 | Any match found replaces the text from BEGIN to END." | |
e495eaec BW |
1808 | (let ((completion (try-completion word choices)) |
1809 | (completions-buffer "*Completions*")) | |
a66894d8 | 1810 | (cond ((eq completion t) |
e495eaec BW |
1811 | (ignore-errors |
1812 | (kill-buffer completions-buffer)) | |
a66894d8 BW |
1813 | (message "Completed: %s" word)) |
1814 | ((null completion) | |
e495eaec BW |
1815 | (ignore-errors |
1816 | (kill-buffer completions-buffer)) | |
a66894d8 BW |
1817 | (message "No completion for `%s'" word)) |
1818 | ((stringp completion) | |
1819 | (if (equal word completion) | |
e495eaec | 1820 | (with-output-to-temp-buffer completions-buffer |
79af55a7 | 1821 | (mh-display-completion-list-compat word choices)) |
e495eaec BW |
1822 | (ignore-errors |
1823 | (kill-buffer completions-buffer)) | |
a66894d8 BW |
1824 | (delete-region begin end) |
1825 | (insert completion)))))) | |
1826 | ||
1827 | ;;;###mh-autoload | |
1828 | (defun mh-beginning-of-word (&optional n) | |
1829 | "Return position of the N th word backwards." | |
1830 | (unless n (setq n 1)) | |
1831 | (let ((syntax-table (syntax-table))) | |
1832 | (unwind-protect | |
1833 | (save-excursion | |
f0d73c14 | 1834 | (mh-mail-abbrev-make-syntax-table) |
a66894d8 BW |
1835 | (set-syntax-table mail-abbrev-syntax-table) |
1836 | (backward-word n) | |
1837 | (point)) | |
1838 | (set-syntax-table syntax-table)))) | |
1839 | ||
924df208 BW |
1840 | (defun mh-folder-expand-at-point () |
1841 | "Do folder name completion in Fcc header field." | |
1842 | (let* ((end (point)) | |
a66894d8 | 1843 | (beg (mh-beginning-of-word)) |
924df208 BW |
1844 | (folder (buffer-substring beg end)) |
1845 | (leading-plus (and (> (length folder) 0) (equal (aref folder 0) ?+))) | |
1846 | (last-slash (mh-search-from-end ?/ folder)) | |
1847 | (prefix (and last-slash (substring folder 0 last-slash))) | |
a66894d8 BW |
1848 | (choices (mapcar #'(lambda (x) |
1849 | (list (cond (prefix (format "%s/%s" prefix x)) | |
1850 | (leading-plus (format "+%s" x)) | |
1851 | (t x)))) | |
1852 | (mh-folder-completion-function folder nil t)))) | |
1853 | (mh-complete-word folder choices beg end))) | |
1854 | ||
a66894d8 BW |
1855 | (defvar mh-letter-complete-function-alist |
1856 | '((cc . mh-alias-letter-expand-alias) | |
1857 | (bcc . mh-alias-letter-expand-alias) | |
1858 | (dcc . mh-alias-letter-expand-alias) | |
1859 | (fcc . mh-folder-expand-at-point) | |
1860 | (from . mh-alias-letter-expand-alias) | |
1861 | (mail-followup-to . mh-alias-letter-expand-alias) | |
1862 | (reply-to . mh-alias-letter-expand-alias) | |
1863 | (to . mh-alias-letter-expand-alias)) | |
1864 | "Alist of header fields and completion functions to use.") | |
924df208 | 1865 | |
c3d9274a BW |
1866 | (defun mh-letter-complete (arg) |
1867 | "Perform completion on header field or word preceding point. | |
2dcf34f9 | 1868 | If the field contains addresses (for example, \"To:\" or \"Cc:\") |
4023e353 | 1869 | or folders (for example, \"Fcc:\") then this command will |
2dcf34f9 BW |
1870 | provide alias completion. In the body of the message, this |
1871 | command runs `mh-letter-complete-function' instead, which is set | |
1872 | to \"'ispell-complete-word\" by default. This command takes a | |
1873 | prefix argument ARG that is passed to the | |
0c47b17c | 1874 | `mh-letter-complete-function'." |
c3d9274a | 1875 | (interactive "P") |
a66894d8 BW |
1876 | (let ((func nil)) |
1877 | (cond ((not (mh-in-header-p)) | |
1878 | (funcall mh-letter-complete-function arg)) | |
1879 | ((setq func (cdr (assoc (mh-letter-header-field-at-point) | |
1880 | mh-letter-complete-function-alist))) | |
1881 | (funcall func)) | |
1882 | (t (funcall mh-letter-complete-function arg))))) | |
1883 | ||
1884 | (defun mh-letter-complete-or-space (arg) | |
1885 | "Perform completion or insert space. | |
2dcf34f9 BW |
1886 | Turn on the `mh-compose-space-does-completion-flag' option to use |
1887 | this command to perform completion in the header. Otherwise, a | |
1888 | space is inserted. | |
a66894d8 BW |
1889 | |
1890 | ARG is the number of spaces inserted." | |
1891 | (interactive "p") | |
1892 | (let ((func nil) | |
1893 | (end-of-prev (save-excursion | |
1894 | (goto-char (mh-beginning-of-word)) | |
1895 | (mh-beginning-of-word -1)))) | |
1896 | (cond ((not mh-compose-space-does-completion-flag) | |
1897 | (self-insert-command arg)) | |
1898 | ((not (mh-in-header-p)) (self-insert-command arg)) | |
1899 | ((> (point) end-of-prev) (self-insert-command arg)) | |
1900 | ((setq func (cdr (assoc (mh-letter-header-field-at-point) | |
1901 | mh-letter-complete-function-alist))) | |
1902 | (funcall func)) | |
1903 | (t (self-insert-command arg))))) | |
1904 | ||
1905 | (defun mh-letter-confirm-address () | |
0c47b17c | 1906 | "Flash alias expansion. |
2dcf34f9 BW |
1907 | Addresses are separated by a comma\; and when you press the |
1908 | comma, this command flashes the alias expansion in the minibuffer | |
1909 | if `mh-alias-flash-on-comma' is turned on." | |
a66894d8 BW |
1910 | (interactive) |
1911 | (cond ((not (mh-in-header-p)) (self-insert-command 1)) | |
1912 | ((eq (cdr (assoc (mh-letter-header-field-at-point) | |
1913 | mh-letter-complete-function-alist)) | |
1914 | 'mh-alias-letter-expand-alias) | |
1915 | (mh-alias-reload-maybe) | |
1916 | (mh-alias-minibuffer-confirm-address)) | |
1917 | (t (self-insert-command 1)))) | |
1918 | ||
1919 | (defvar mh-letter-header-field-regexp "^\\([A-Za-z][A-Za-z0-9-]*\\):") | |
1920 | ||
1921 | (defun mh-letter-header-field-at-point () | |
1922 | "Return the header field name at point. | |
2dcf34f9 BW |
1923 | A symbol is returned whose name is the string obtained by |
1924 | downcasing the field name." | |
a66894d8 BW |
1925 | (save-excursion |
1926 | (end-of-line) | |
1927 | (and (re-search-backward mh-letter-header-field-regexp nil t) | |
1928 | (intern (downcase (match-string 1)))))) | |
1929 | ||
1930 | ;;;###mh-autoload | |
1931 | (defun mh-letter-next-header-field-or-indent (arg) | |
1932 | "Move to next field or indent depending on point. | |
2dcf34f9 BW |
1933 | Within the header of the message, this command moves between |
1934 | fields, but skips those fields listed in | |
1935 | `mh-compose-skipped-header-fields'. After the last field, this | |
1936 | command then moves point to the message body before cycling back | |
1937 | to the first field. If point is already past the first line of | |
1938 | the message body, then this command indents by calling | |
1939 | `indent-relative' with the given prefix argument ARG." | |
a66894d8 BW |
1940 | (interactive "P") |
1941 | (let ((header-end (save-excursion | |
1942 | (goto-char (mh-mail-header-end)) | |
1943 | (forward-line) | |
1944 | (point)))) | |
1945 | (if (> (point) header-end) | |
1946 | (indent-relative arg) | |
1947 | (mh-letter-next-header-field)))) | |
1948 | ||
1949 | (defun mh-letter-next-header-field () | |
1950 | "Cycle to the next header field. | |
2dcf34f9 BW |
1951 | If we are at the last header field go to the start of the message |
1952 | body." | |
a66894d8 BW |
1953 | (let ((header-end (mh-mail-header-end))) |
1954 | (cond ((>= (point) header-end) (goto-char (point-min))) | |
1955 | ((< (point) (progn | |
1956 | (beginning-of-line) | |
1957 | (re-search-forward mh-letter-header-field-regexp | |
1958 | (line-end-position) t) | |
1959 | (point))) | |
1960 | (beginning-of-line)) | |
1961 | (t (end-of-line))) | |
1962 | (cond ((re-search-forward mh-letter-header-field-regexp header-end t) | |
1963 | (if (mh-letter-skipped-header-field-p (match-string 1)) | |
1964 | (mh-letter-next-header-field) | |
1965 | (mh-letter-skip-leading-whitespace-in-header-field))) | |
1966 | (t (goto-char header-end) | |
1967 | (forward-line))))) | |
1968 | ||
1969 | ;;;###mh-autoload | |
1970 | (defun mh-letter-previous-header-field () | |
1971 | "Cycle to the previous header field. | |
2dcf34f9 BW |
1972 | This command moves backwards between the fields and cycles to the |
1973 | body of the message after the first field. Unlike the | |
1974 | \\[mh-letter-next-header-field-or-indent] command, it will always | |
1975 | take point to the last field from anywhere in the body." | |
a66894d8 BW |
1976 | (interactive) |
1977 | (let ((header-end (mh-mail-header-end))) | |
1978 | (if (>= (point) header-end) | |
1979 | (goto-char header-end) | |
1980 | (mh-header-field-beginning)) | |
1981 | (cond ((re-search-backward mh-letter-header-field-regexp nil t) | |
1982 | (if (mh-letter-skipped-header-field-p (match-string 1)) | |
1983 | (mh-letter-previous-header-field) | |
1984 | (goto-char (match-end 0)) | |
1985 | (mh-letter-skip-leading-whitespace-in-header-field))) | |
1986 | (t (goto-char header-end) | |
1987 | (forward-line))))) | |
1988 | ||
1989 | (defun mh-letter-skipped-header-field-p (field) | |
1990 | "Check if FIELD is to be skipped." | |
1991 | (let ((field (downcase field))) | |
1992 | (loop for x in mh-compose-skipped-header-fields | |
1993 | when (equal (downcase x) field) return t | |
1994 | finally return nil))) | |
1995 | ||
1996 | (defun mh-letter-skip-leading-whitespace-in-header-field () | |
1997 | "Skip leading whitespace in a header field. | |
2dcf34f9 BW |
1998 | If the header field doesn't have at least one space after the |
1999 | colon then a space character is added." | |
a66894d8 BW |
2000 | (let ((need-space t)) |
2001 | (while (memq (char-after) '(?\t ?\ )) | |
2002 | (forward-char) | |
2003 | (setq need-space nil)) | |
2004 | (when need-space (insert " ")))) | |
2005 | ||
2006 | (defvar mh-hidden-header-keymap | |
2007 | (let ((map (make-sparse-keymap))) | |
2008 | (mh-do-in-gnu-emacs | |
2009 | (define-key map [mouse-2] 'mh-letter-toggle-header-field-display-button)) | |
2010 | (mh-do-in-xemacs | |
2011 | (define-key map '(button2) | |
2012 | 'mh-letter-toggle-header-field-display-button)) | |
2013 | map)) | |
2014 | ||
2015 | (defun mh-letter-toggle-header-field-display-button (event) | |
2016 | "Toggle header field display at location of EVENT. | |
2dcf34f9 BW |
2017 | This function does the same thing as |
2018 | `mh-letter-toggle-header-field-display' except that it is | |
2019 | callable from a mouse button." | |
a66894d8 BW |
2020 | (interactive "e") |
2021 | (mh-do-at-event-location event | |
2022 | (mh-letter-toggle-header-field-display nil))) | |
2023 | ||
2024 | (defun mh-letter-toggle-header-field-display (arg) | |
2025 | "Toggle display of header field at point. | |
a66894d8 | 2026 | |
2dcf34f9 BW |
2027 | Use this command to display truncated header fields. This command |
2028 | is a toggle so entering it again will hide the field. This | |
2029 | command takes a prefix argument ARG: if negative then the field | |
2030 | is hidden, if positive then the field is displayed." | |
a66894d8 BW |
2031 | (interactive (list nil)) |
2032 | (when (and (mh-in-header-p) | |
2033 | (progn | |
2034 | (end-of-line) | |
2035 | (re-search-backward mh-letter-header-field-regexp nil t))) | |
2036 | (let ((buffer-read-only nil) | |
2037 | (modified-flag (buffer-modified-p)) | |
2038 | (begin (point)) | |
2039 | end) | |
2040 | (end-of-line) | |
2041 | (setq end (1- (if (re-search-forward "^[^ \t]" nil t) | |
2042 | (match-beginning 0) | |
2043 | (point-max)))) | |
2044 | (goto-char begin) | |
2045 | ;; Make it clickable... | |
2046 | (add-text-properties begin end `(keymap ,mh-hidden-header-keymap | |
2047 | mouse-face highlight)) | |
2048 | (unwind-protect | |
2049 | (cond ((or (and (not arg) | |
2050 | (text-property-any begin end 'invisible 'vanish)) | |
2051 | (and (numberp arg) (>= arg 0)) | |
2052 | (and (eq arg 'long) (> (line-beginning-position 5) end))) | |
2053 | (remove-text-properties begin end '(invisible nil)) | |
2054 | (search-forward ":" (line-end-position) t) | |
2055 | (mh-letter-skip-leading-whitespace-in-header-field)) | |
0c47b17c BW |
2056 | ;; XXX Redesign to make usable by user. Perhaps use a positive |
2057 | ;; numeric prefix to make that many lines visible. | |
a66894d8 BW |
2058 | ((eq arg 'long) |
2059 | (end-of-line 4) | |
2060 | (mh-letter-truncate-header-field end) | |
2061 | (beginning-of-line)) | |
2062 | (t (end-of-line) | |
2063 | (mh-letter-truncate-header-field end) | |
2064 | (beginning-of-line))) | |
2065 | (set-buffer-modified-p modified-flag))))) | |
2066 | ||
2067 | (defun mh-letter-truncate-header-field (end) | |
2068 | "Replace text from current line till END with an ellipsis. | |
2069 | If the current line is too long truncate a part of it as well." | |
2070 | (let ((max-len (min (window-width) 62))) | |
2071 | (when (> (+ (current-column) 4) max-len) | |
2072 | (backward-char (- (+ (current-column) 5) max-len))) | |
2073 | (when (> end (point)) | |
2074 | (add-text-properties (point) end '(invisible vanish))))) | |
2075 | ||
2076 | (defun mh-letter-hide-all-skipped-fields () | |
2077 | "Hide all skipped fields." | |
2078 | (save-excursion | |
2079 | (goto-char (point-min)) | |
2080 | (save-restriction | |
2081 | (narrow-to-region (point) (mh-mail-header-end)) | |
2082 | (while (re-search-forward mh-letter-header-field-regexp nil t) | |
2083 | (if (mh-letter-skipped-header-field-p (match-string 1)) | |
2084 | (mh-letter-toggle-header-field-display -1) | |
2085 | (mh-letter-toggle-header-field-display 'long)) | |
2086 | (beginning-of-line 2))))) | |
2087 | ||
2088 | (defun mh-interactive-read-address (prompt) | |
2089 | "Read an address. | |
2dcf34f9 BW |
2090 | If `mh-compose-prompt-flag' is non-nil, then read an address with |
2091 | PROMPT. | |
a66894d8 BW |
2092 | Otherwise return the empty string." |
2093 | (if mh-compose-prompt-flag (mh-read-address prompt) "")) | |
2094 | ||
2095 | (defun mh-interactive-read-string (prompt) | |
2096 | "Read a string. | |
2dcf34f9 BW |
2097 | If `mh-compose-prompt-flag' is non-nil, then read a string with |
2098 | PROMPT. | |
a66894d8 BW |
2099 | Otherwise return the empty string." |
2100 | (if mh-compose-prompt-flag (read-string prompt) "")) | |
2101 | ||
2102 | (defun mh-letter-adjust-point () | |
2103 | "Move cursor to first header field if are using the no prompt mode." | |
2104 | (unless mh-compose-prompt-flag | |
2105 | (goto-char (point-max)) | |
2106 | (mh-letter-next-header-field))) | |
a1506d29 | 2107 | |
cee9f5c6 BW |
2108 | \f |
2109 | ||
2110 | ;;; Build mh-letter-mode keymap | |
2111 | ||
2112 | ;; If this changes, modify mh-letter-mode-help-messages accordingly, above. | |
a1b4049d | 2113 | (gnus-define-keys mh-letter-mode-map |
f0d73c14 BW |
2114 | " " mh-letter-complete-or-space |
2115 | "," mh-letter-confirm-address | |
c3d9274a | 2116 | "\C-c?" mh-help |
f0d73c14 BW |
2117 | "\C-c\C-\\" mh-fully-kill-draft ;if no C-q |
2118 | "\C-c\C-^" mh-insert-signature ;if no C-s | |
c3d9274a BW |
2119 | "\C-c\C-c" mh-send-letter |
2120 | "\C-c\C-d" mh-insert-identity | |
0c47b17c | 2121 | "\C-c\C-e" mh-mh-to-mime |
c3d9274a BW |
2122 | "\C-c\C-f\C-b" mh-to-field |
2123 | "\C-c\C-f\C-c" mh-to-field | |
2124 | "\C-c\C-f\C-d" mh-to-field | |
2125 | "\C-c\C-f\C-f" mh-to-fcc | |
2126 | "\C-c\C-f\C-r" mh-to-field | |
2127 | "\C-c\C-f\C-s" mh-to-field | |
2128 | "\C-c\C-f\C-t" mh-to-field | |
2129 | "\C-c\C-fb" mh-to-field | |
2130 | "\C-c\C-fc" mh-to-field | |
2131 | "\C-c\C-fd" mh-to-field | |
2132 | "\C-c\C-ff" mh-to-fcc | |
2133 | "\C-c\C-fr" mh-to-field | |
2134 | "\C-c\C-fs" mh-to-field | |
2135 | "\C-c\C-ft" mh-to-field | |
2136 | "\C-c\C-i" mh-insert-letter | |
f0d73c14 | 2137 | "\C-c\C-m\C-e" mh-mml-secure-message-encrypt |
c3d9274a | 2138 | "\C-c\C-m\C-f" mh-compose-forward |
0c47b17c | 2139 | "\C-c\C-m\C-g" mh-mh-compose-anon-ftp |
c3d9274a BW |
2140 | "\C-c\C-m\C-i" mh-compose-insertion |
2141 | "\C-c\C-m\C-m" mh-mml-to-mime | |
f0d73c14 BW |
2142 | "\C-c\C-m\C-n" mh-mml-unsecure-message |
2143 | "\C-c\C-m\C-s" mh-mml-secure-message-sign | |
0c47b17c BW |
2144 | "\C-c\C-m\C-t" mh-mh-compose-external-compressed-tar |
2145 | "\C-c\C-m\C-u" mh-mh-to-mime-undo | |
2146 | "\C-c\C-m\C-x" mh-mh-compose-external-type | |
f0d73c14 BW |
2147 | "\C-c\C-mee" mh-mml-secure-message-encrypt |
2148 | "\C-c\C-mes" mh-mml-secure-message-signencrypt | |
c3d9274a | 2149 | "\C-c\C-mf" mh-compose-forward |
0c47b17c | 2150 | "\C-c\C-mg" mh-mh-compose-anon-ftp |
c3d9274a BW |
2151 | "\C-c\C-mi" mh-compose-insertion |
2152 | "\C-c\C-mm" mh-mml-to-mime | |
f0d73c14 BW |
2153 | "\C-c\C-mn" mh-mml-unsecure-message |
2154 | "\C-c\C-mse" mh-mml-secure-message-signencrypt | |
2155 | "\C-c\C-mss" mh-mml-secure-message-sign | |
0c47b17c BW |
2156 | "\C-c\C-mt" mh-mh-compose-external-compressed-tar |
2157 | "\C-c\C-mu" mh-mh-to-mime-undo | |
2158 | "\C-c\C-mx" mh-mh-compose-external-type | |
c3d9274a BW |
2159 | "\C-c\C-o" mh-open-line |
2160 | "\C-c\C-q" mh-fully-kill-draft | |
c3d9274a | 2161 | "\C-c\C-s" mh-insert-signature |
f0d73c14 | 2162 | "\C-c\C-t" mh-letter-toggle-header-field-display |
c3d9274a BW |
2163 | "\C-c\C-w" mh-check-whom |
2164 | "\C-c\C-y" mh-yank-cur-msg | |
f0d73c14 | 2165 | "\C-c\M-d" mh-insert-auto-fields |
a66894d8 BW |
2166 | "\M-\t" mh-letter-complete |
2167 | "\t" mh-letter-next-header-field-or-indent | |
f0d73c14 | 2168 | [backtab] mh-letter-previous-header-field) |
a1b4049d BW |
2169 | |
2170 | ;; "C-c /" prefix is used in mh-letter-mode by pgp.el and mailcrypt.el. | |
2171 | ||
bdcfe844 BW |
2172 | (provide 'mh-comp) |
2173 | ||
cee9f5c6 BW |
2174 | ;; Local Variables: |
2175 | ;; indent-tabs-mode: nil | |
2176 | ;; sentence-end-double-space: nil | |
2177 | ;; End: | |
60370d40 | 2178 | |
cee9f5c6 | 2179 | ;; arch-tag: 62865511-e610-4923-b0b5-f45a8ab70a34 |
60370d40 | 2180 | ;;; mh-comp.el ends here |