declare smobs in alloc.c
[bpt/emacs.git] / lisp / mh-e / mh-comp.el
... / ...
CommitLineData
1;;; mh-comp.el --- MH-E functions for composing and sending messages
2
3;; Copyright (C) 1993, 1995, 1997, 2000-2014 Free Software Foundation,
4;; Inc.
5
6;; Author: Bill Wohler <wohler@newt.com>
7;; Maintainer: Bill Wohler <wohler@newt.com>
8;; Keywords: mail
9;; See: mh-e.el
10
11;; This file is part of GNU Emacs.
12
13;; GNU Emacs is free software: you can redistribute it and/or modify
14;; it under the terms of the GNU General Public License as published by
15;; the Free Software Foundation, either version 3 of the License, or
16;; (at your option) any later version.
17
18;; GNU Emacs is distributed in the hope that it will be useful,
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
24;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
25
26;;; Commentary:
27
28;; This file includes the functions in the MH-Folder maps that get us
29;; into MH-Letter mode, as well the functions in the MH-Letter mode
30;; that are used to send the mail. Other that those, functions that
31;; are needed in mh-letter.el should be found there.
32
33;;; Change Log:
34
35;;; Code:
36
37(require 'mh-e)
38(require 'mh-gnus) ;needed because mh-gnus.el not compiled
39(require 'mh-scan)
40
41(require 'sendmail)
42
43(autoload 'easy-menu-add "easymenu")
44(autoload 'mml-insert-tag "mml")
45
46\f
47
48;;; Site Customization
49
50(defvar mh-send-prog "send"
51 "Name of the MH send program.
52Some sites need to change this because of a name conflict.")
53
54(defvar mh-send-uses-spost-flag nil
55 "Non-nil means \"send\" uses \"spost\" to submit messages.
56
57If the value of \"postproc:\" is \"spost\", you may need to set
58this variable to t to tell MH-E to avoid using features of
59\"post\" that are not supported by \"spost\". You'll know that
60you'll need to do this if sending mail fails with an error of
61\"spost: -msgid unknown\".")
62
63(defvar mh-redist-background nil
64 "If non-nil redist will be done in background like send.
65This allows transaction log to be visible if -watch, -verbose or
66-snoop are used.")
67
68\f
69
70;;; Variables
71
72(defvar mh-comp-formfile "components"
73 "Name of file to be used as a skeleton for composing messages.
74
75Default is \"components\".
76
77If not an absolute file name, the file is searched for first in the
78user's MH directory, then in the system MH lib directory.")
79
80(defvar mh-repl-formfile "replcomps"
81 "Name of file to be used as a skeleton for replying to messages.
82
83Default is \"replcomps\".
84
85If not an absolute file name, the file is searched for first in the
86user's MH directory, then in the system MH lib directory.")
87
88(defvar mh-repl-group-formfile "replgroupcomps"
89 "Name of file to be used as a skeleton for replying to messages.
90
91Default is \"replgroupcomps\".
92
93This file is used to form replies to the sender and all recipients of
94a message. Only used if `(mh-variant-p 'nmh)' is non-nil.
95If not an absolute file name, the file is searched for first in the
96user's MH directory, then in the system MH lib directory.")
97
98(defvar mh-rejected-letter-start
99 (format "^%s$"
100 (regexp-opt
101 '("Content-Type: message/rfc822" ;MIME MDN
102 "------ This is a copy of the message, including all the headers. ------";from exim
103 "--- Below this line is a copy of the message."; from qmail
104 " ----- Unsent message follows -----" ;from sendmail V5
105 " --------Unsent Message below:" ; from sendmail at BU
106 " ----- Original message follows -----" ;from sendmail V8
107 "------- Unsent Draft" ;from MH itself
108 "---------- Original Message ----------" ;from zmailer
109 " --- The unsent message follows ---" ;from AIX mail system
110 " Your message follows:" ;from MMDF-II
111 "Content-Description: Returned Content" ;1993 KJ sendmail
112 ))))
113
114(defvar mh-new-draft-cleaned-headers
115 "^Date:\\|^Received:\\|^Message-Id:\\|^From:\\|^Sender:\\|^Errors-To:\\|^Delivery-Date:\\|^Return-Path:"
116 "Regexp of header lines to remove before offering a message as a new draft\\<mh-folder-mode-map>.
117Used by the \\[mh-edit-again] and \\[mh-extract-rejected-mail] commands.")
118
119(defvar mh-letter-mode-syntax-table
120 (let ((syntax-table (make-syntax-table text-mode-syntax-table)))
121 (modify-syntax-entry ?% "." syntax-table)
122 syntax-table)
123 "Syntax table used by MH-E while in MH-Letter mode.")
124
125(defvar mh-regexp-in-field-syntax-table nil
126 "Specify a syntax table for `mh-regexp-in-field-p' to use.")
127
128(defvar mh-fcc-syntax-table
129 (let ((syntax-table (make-syntax-table text-mode-syntax-table)))
130 (modify-syntax-entry ?+ "w" syntax-table)
131 (modify-syntax-entry ?/ "w" syntax-table)
132 syntax-table)
133 "Syntax table used by MH-E while searching an Fcc field.")
134
135(defvar mh-addr-syntax-table
136 (let ((syntax-table (make-syntax-table text-mode-syntax-table)))
137 (modify-syntax-entry ?! "w" syntax-table)
138 (modify-syntax-entry ?# "w" syntax-table)
139 (modify-syntax-entry ?$ "w" syntax-table)
140 (modify-syntax-entry ?% "w" syntax-table)
141 (modify-syntax-entry ?& "w" syntax-table)
142 (modify-syntax-entry ?' "w" syntax-table)
143 (modify-syntax-entry ?* "w" syntax-table)
144 (modify-syntax-entry ?+ "w" syntax-table)
145 (modify-syntax-entry ?- "w" syntax-table)
146 (modify-syntax-entry ?/ "w" syntax-table)
147 (modify-syntax-entry ?= "w" syntax-table)
148 (modify-syntax-entry ?? "w" syntax-table)
149 (modify-syntax-entry ?^ "w" syntax-table)
150 (modify-syntax-entry ?_ "w" syntax-table)
151 (modify-syntax-entry ?` "w" syntax-table)
152 (modify-syntax-entry ?{ "w" syntax-table)
153 (modify-syntax-entry ?| "w" syntax-table)
154 (modify-syntax-entry ?} "w" syntax-table)
155 (modify-syntax-entry ?~ "w" syntax-table)
156 (modify-syntax-entry ?. "w" syntax-table)
157 (modify-syntax-entry ?@ "w" syntax-table)
158 syntax-table)
159 "Syntax table used by MH-E while searching an address field.")
160
161(defvar mh-send-args ""
162 "Extra args to pass to \"send\" command.")
163
164(defvar mh-annotate-char nil
165 "Character to use to annotate `mh-sent-from-msg'.")
166
167(defvar mh-annotate-field nil
168 "Field name for message annotation.")
169
170(defvar mh-annotate-list nil
171 "Messages annotated, either a sequence name or a list of message numbers.
172This variable can be used by `mh-annotate-msg-hook'.")
173
174(defvar mh-insert-auto-fields-done-local nil
175 "Buffer-local variable set when `mh-insert-auto-fields' called successfully.")
176(make-variable-buffer-local 'mh-insert-auto-fields-done-local)
177
178\f
179
180;;; MH-E Entry Points
181
182;;;###autoload
183(defun mh-smail ()
184 "Compose a message with the MH mail system.
185See `mh-send' for more details on composing mail."
186 (interactive)
187 (mh-find-path)
188 (call-interactively 'mh-send))
189
190;;;###autoload
191(defun mh-smail-other-window ()
192 "Compose a message with the MH mail system in other window.
193See `mh-send' for more details on composing mail."
194 (interactive)
195 (mh-find-path)
196 (call-interactively 'mh-send-other-window))
197
198(defun mh-send-other-window (to cc subject)
199 "Compose a message in another window.
200
201See `mh-send' for more information and a description of how the
202TO, CC, and SUBJECT arguments are used."
203 (interactive (list
204 (mh-interactive-read-address "To: ")
205 (mh-interactive-read-address "Cc: ")
206 (mh-interactive-read-string "Subject: ")))
207 (let ((pop-up-windows t))
208 (mh-send-sub to cc subject (current-window-configuration))))
209
210(defvar mh-error-if-no-draft nil) ;raise error over using old draft
211
212;;;###autoload
213(defun mh-smail-batch (&optional to subject other-headers &rest ignored)
214 "Compose a message with the MH mail system.
215
216This function does not prompt the user for any header fields, and
217thus is suitable for use by programs that want to create a mail
218buffer. Users should use \\[mh-smail] to compose mail.
219
220Optional arguments for setting certain fields include TO,
221SUBJECT, and OTHER-HEADERS. Additional arguments are IGNORED.
222
223This function remains for Emacs 21 compatibility. New
224applications should use `mh-user-agent-compose'."
225 (mh-find-path)
226 (let ((mh-error-if-no-draft t))
227 (mh-send (or to "") "" (or subject ""))))
228
229;;;###autoload
230(define-mail-user-agent 'mh-e-user-agent
231 'mh-user-agent-compose 'mh-send-letter 'mh-fully-kill-draft
232 'mh-before-send-letter-hook)
233
234;;;###autoload
235(defun mh-user-agent-compose (&optional to subject other-headers continue
236 switch-function yank-action
237 send-actions return-action
238 &rest ignored)
239 "Set up mail composition draft with the MH mail system.
240This is the `mail-user-agent' entry point to MH-E. This function
241conforms to the contract specified by `define-mail-user-agent'
242which means that this function should accept the same arguments
243as `compose-mail'.
244
245The optional arguments TO and SUBJECT specify recipients and the
246initial Subject field, respectively.
247
248OTHER-HEADERS is an alist specifying additional header fields.
249Elements look like (HEADER . VALUE) where both HEADER and VALUE
250are strings.
251
252CONTINUE, SWITCH-FUNCTION, YANK-ACTION, SEND-ACTIONS, and
253RETURN-ACTION and any additional arguments are IGNORED."
254 (mh-find-path)
255 (let ((mh-error-if-no-draft t))
256 (mh-send to "" subject)
257 (while other-headers
258 (mh-insert-fields (concat (car (car other-headers)) ":")
259 (cdr (car other-headers)))
260 (setq other-headers (cdr other-headers)))))
261
262;; Shush compiler.
263(mh-do-in-xemacs
264 (defvar sendmail-coding-system))
265
266;;;###autoload
267(defun mh-send-letter (&optional arg)
268 "Save draft and send message.
269
270When you are all through editing a message, you send it with this
271command. You can give a prefix argument ARG to monitor the first stage
272of the delivery\; this output can be found in a buffer called \"*MH-E
273Mail Delivery*\".
274
275The hook `mh-before-send-letter-hook' is run at the beginning of
276this command. For example, if you want to check your spelling in
277your message before sending, add the function `ispell-message'.
278
279Unless `mh-insert-auto-fields' had previously been called
280manually, the function `mh-insert-auto-fields' is called to
281insert fields based upon the recipients. If fields are added, you
282are given a chance to see and to confirm these fields before the
283message is actually sent. You can do away with this confirmation
284by turning off the option `mh-auto-fields-prompt-flag'.
285
286In case the MH \"send\" program is installed under a different name,
287use `mh-send-prog' to tell MH-E the name.
288
289The hook `mh-annotate-msg-hook' is run after annotating the
290message and scan line."
291 (interactive "P")
292 (run-hooks 'mh-before-send-letter-hook)
293 (if (and (mh-insert-auto-fields t)
294 mh-auto-fields-prompt-flag
295 (goto-char (point-min)))
296 (if (not (y-or-n-p "Auto fields inserted, send? "))
297 (error "Send aborted")))
298 (cond ((mh-mh-directive-present-p)
299 (mh-mh-to-mime))
300 ((or (mh-mml-tag-present-p) (not (mh-ascii-buffer-p)))
301 (mh-mml-to-mime)))
302 (save-buffer)
303 (message "Sending...")
304 (let ((draft-buffer (current-buffer))
305 (file-name buffer-file-name)
306 (config mh-previous-window-config)
307 (coding-system-for-write
308 (if (and (local-variable-p 'buffer-file-coding-system
309 (current-buffer)) ;XEmacs needs two args
310 ;; We're not sure why, but buffer-file-coding-system
311 ;; tends to get set to undecided-unix.
312 (not (memq buffer-file-coding-system
313 '(undecided undecided-unix undecided-dos))))
314 buffer-file-coding-system
315 (or (and (boundp 'sendmail-coding-system) sendmail-coding-system)
316 (and (default-boundp 'buffer-file-coding-system)
317 (default-value 'buffer-file-coding-system))
318 'iso-latin-1))))
319 ;; Older versions of spost do not support -msgid and -mime.
320 (unless mh-send-uses-spost-flag
321 ;; Adding a Message-ID field looks good, makes it easier to search for
322 ;; message in your +outbox, and best of all doesn't break threading for
323 ;; the recipient if you reply to a message in your +outbox.
324 (setq mh-send-args (concat "-msgid " mh-send-args))
325 ;; The default BCC encapsulation will make a MIME message unreadable.
326 ;; With nmh use the -mime arg to prevent this.
327 (if (and (mh-variant-p 'nmh)
328 (mh-goto-header-field "Bcc:")
329 (mh-goto-header-field "Content-Type:"))
330 (setq mh-send-args (concat "-mime " mh-send-args))))
331 (cond (arg
332 (pop-to-buffer mh-mail-delivery-buffer)
333 (erase-buffer)
334 (mh-exec-cmd-output mh-send-prog t
335 "-nodraftfolder" "-watch" "-nopush"
336 (split-string mh-send-args) file-name)
337 (goto-char (point-max)) ; show the interesting part
338 (recenter -1)
339 (set-buffer draft-buffer)) ; for annotation below
340 (t
341 (mh-exec-cmd-daemon mh-send-prog nil
342 "-nodraftfolder" "-noverbose"
343 (split-string mh-send-args) file-name)))
344 (if mh-annotate-char
345 (mh-annotate-msg mh-sent-from-msg
346 mh-sent-from-folder
347 mh-annotate-char
348 "-component" mh-annotate-field
349 "-text" (format "\"%s %s\""
350 (mh-get-header-field "To:")
351 (mh-get-header-field "Cc:"))))
352
353 (cond ((or (not arg)
354 (y-or-n-p "Kill draft buffer? "))
355 (kill-buffer draft-buffer)
356 (if config
357 (set-window-configuration config))))
358 (if arg
359 (message "Sending...done")
360 (message "Sending...backgrounded"))))
361
362;;;###autoload
363(defun mh-fully-kill-draft ()
364 "Quit editing and delete draft message.
365
366If for some reason you are not happy with the draft, you can use
367this command to kill the draft buffer and delete the draft
368message. Use the command \\[kill-buffer] if you don't want to
369delete the draft message."
370 (interactive)
371 (if (y-or-n-p "Kill draft message? ")
372 (let ((config mh-previous-window-config))
373 (if (file-exists-p buffer-file-name)
374 (delete-file buffer-file-name))
375 (set-buffer-modified-p nil)
376 (kill-buffer (buffer-name))
377 (message "")
378 (if config
379 (set-window-configuration config)))
380 (error "Message not killed")))
381
382\f
383
384;;; MH-Folder Commands
385
386;; Alphabetical.
387
388;;;###mh-autoload
389(defun mh-edit-again (message)
390 "Edit a MESSAGE to send it again.
391
392If you don't complete a draft for one reason or another, and if
393the draft buffer is no longer available, you can pick your draft
394up again with this command. If you don't use a draft folder, your
395last \"draft\" file will be used. If you use draft folders,
396you'll need to visit the draft folder with \"\\[mh-visit-folder]
397drafts <RET>\", use \\[mh-next-undeleted-msg] to move to the
398appropriate message, and then use \\[mh-edit-again] to prepare
399the message for editing.
400
401This command can also be used to take messages that were sent to
402you and to send them to more people.
403
404Don't use this command to re-edit a message from a Mailer-Daemon
405who complained that your mail wasn't posted for some reason or
406another (see `mh-extract-rejected-mail').
407
408The default message is the current message.
409
410See also `mh-send'."
411 (interactive (list (mh-get-msg-num t)))
412 (let* ((from-folder mh-current-folder)
413 (config (current-window-configuration))
414 (draft
415 (cond ((and mh-draft-folder (equal from-folder mh-draft-folder))
416 (pop-to-buffer (find-file-noselect (mh-msg-filename message))
417 t)
418 (rename-buffer (format "draft-%d" message))
419 ;; Make buffer writable...
420 (setq buffer-read-only nil)
421 ;; If buffer was being used to display the message reinsert
422 ;; from file...
423 (when (eq major-mode 'mh-show-mode)
424 (erase-buffer)
425 (insert-file-contents buffer-file-name))
426 (buffer-name))
427 (t
428 (mh-read-draft "clean-up" (mh-msg-filename message) nil)))))
429 (mh-clean-msg-header (point-min) mh-new-draft-cleaned-headers nil)
430 (mh-insert-header-separator)
431 ;; Merge in components
432 (mh-mapc
433 (function
434 (lambda (header-field)
435 (let ((field (car header-field))
436 (value (cdr header-field))
437 (case-fold-search t))
438 (cond
439 ;; Address field
440 ((string-match field "^To$\\|^Cc$\\|^From$")
441 (cond
442 ((not (mh-goto-header-field (concat field ":")))
443 ;; Header field does not exist, add it
444 (mh-goto-header-end 0)
445 (insert field ": " value "\n"))
446 ((string-equal value "")
447 ;; Header field already exists and no value
448 )
449 (t
450 ;; Header field exists and we have a value
451 (let (address mailbox (alias (mh-alias-expand value)))
452 (and alias
453 (setq address (ietf-drums-parse-address alias))
454 (setq mailbox (car address)))
455 ;; XXX - Need to parse all addresses out of field
456 (if (and
457 (not (mh-regexp-in-field-p
458 (concat "\\b" (regexp-quote value) "\\b") field))
459 mailbox
460 (not (mh-regexp-in-field-p
461 (concat "\\b" (regexp-quote mailbox) "\\b") field)))
462 (insert " " value ","))
463 ))))
464 ((string-match field "^Fcc$")
465 ;; Folder reference
466 (mh-modify-header-field field value))
467 ;; Text field, that's an easy case
468 (t
469 (mh-modify-header-field field value))))))
470 (mh-components-to-list (mh-find-components)))
471 (goto-char (point-min))
472 (save-buffer)
473 (mh-compose-and-send-mail
474 draft "" from-folder nil nil nil nil nil nil config)
475 (mh-letter-mode-message)
476 (mh-letter-adjust-point)))
477
478(defun mh-extract-header-field ()
479 "Extract field name and field value from the field at point.
480Returns a list of field name and value (which may be null)."
481 (let ((end (save-excursion (mh-header-field-end)
482 (point))))
483 (if (looking-at mh-letter-header-field-regexp)
484 (save-excursion
485 (goto-char (match-end 1))
486 (forward-char 1)
487 (skip-chars-forward " \t")
488 (cons (match-string-no-properties 1) (buffer-substring-no-properties (point) end))))))
489
490
491(defun mh-components-to-list (components)
492 "Convert the COMPONENTS file to a list of field names and values."
493 (with-current-buffer (get-buffer-create mh-temp-buffer)
494 (erase-buffer)
495 (insert-file-contents components)
496 (goto-char (point-min))
497 (let
498 ((header-fields nil))
499 (while (mh-in-header-p)
500 (setq header-fields (append header-fields (list (mh-extract-header-field))))
501 (mh-header-field-end)
502 (forward-char 1)
503 )
504 header-fields)))
505
506;;;###mh-autoload
507(defun mh-extract-rejected-mail (message)
508 "Edit a MESSAGE that was returned by the mail system.
509
510This command prepares the message for editing by removing the
511Mailer-Daemon envelope and unneeded header fields. Fix whatever
512addressing problem you had, and send the message again with
513\\[mh-send-letter].
514
515The default message is the current message.
516
517See also `mh-send'."
518 (interactive (list (mh-get-msg-num t)))
519 (let ((from-folder mh-current-folder)
520 (config (current-window-configuration))
521 (draft (mh-read-draft "extraction" (mh-msg-filename message) nil)))
522 (goto-char (point-min))
523 (cond ((re-search-forward mh-rejected-letter-start nil t)
524 (skip-chars-forward " \t\n")
525 (delete-region (point-min) (point))
526 (mh-clean-msg-header (point-min) mh-new-draft-cleaned-headers nil))
527 (t
528 (message "Does not appear to be a rejected letter")))
529 (mh-insert-header-separator)
530 (goto-char (point-min))
531 (save-buffer)
532 (mh-compose-and-send-mail draft "" from-folder message
533 (mh-get-header-field "To:")
534 (mh-get-header-field "From:")
535 (mh-get-header-field "Cc:")
536 nil nil config)
537 (mh-letter-mode-message)))
538
539;;;###mh-autoload
540(defun mh-forward (to cc &optional range)
541 "Forward message.
542
543You are prompted for the TO and CC recipients. You are given a
544draft to edit that looks like it would if you had run the MH
545command \"forw\". You can then add some text.
546
547You can forward several messages by using a RANGE. All of the
548messages in the range are inserted into your draft. Check the
549documentation of `mh-interactive-range' to see how RANGE is read
550in interactive use.
551
552The hook `mh-forward-hook' is called on the draft.
553
554See also `mh-compose-forward-as-mime-flag',
555`mh-forward-subject-format', and `mh-send'."
556 (interactive (list (mh-interactive-read-address "To: ")
557 (mh-interactive-read-address "Cc: ")
558 (mh-interactive-range "Forward")))
559 (let* ((folder mh-current-folder)
560 (msgs (mh-range-to-msg-list range))
561 (config (current-window-configuration))
562 (fwd-msg-file (mh-msg-filename (car msgs) folder))
563 ;; forw always leaves file in "draft" since it doesn't have -draft
564 (draft-name (expand-file-name "draft" mh-user-path))
565 (draft (cond ((or (not (file-exists-p draft-name))
566 (y-or-n-p "The file draft exists; discard it? "))
567 (mh-exec-cmd "forw" "-build"
568 (if (and (mh-variant-p 'nmh)
569 mh-compose-forward-as-mime-flag)
570 "-mime")
571 mh-current-folder
572 (mh-coalesce-msg-list msgs))
573 (prog1
574 (mh-read-draft "" draft-name t)
575 (mh-insert-fields "To:" to "Cc:" cc)
576 (save-buffer)))
577 (t
578 (mh-read-draft "" draft-name nil)))))
579 (let (orig-from
580 orig-subject)
581 (with-current-buffer (get-buffer-create mh-temp-buffer)
582 (erase-buffer)
583 (insert-file-contents fwd-msg-file)
584 (setq orig-from (mh-get-header-field "From:"))
585 (setq orig-subject (mh-get-header-field "Subject:")))
586 (let ((forw-subject
587 (mh-forwarded-letter-subject orig-from orig-subject)))
588 (mh-insert-fields "Subject:" forw-subject)
589 (goto-char (point-min))
590 ;; Set the local value of mh-mail-header-separator according to what is
591 ;; present in the buffer...
592 (set (make-local-variable 'mh-mail-header-separator)
593 (save-excursion
594 (goto-char (mh-mail-header-end))
595 (buffer-substring-no-properties (point) (mh-line-end-position))))
596 (set (make-local-variable 'mail-header-separator) mh-mail-header-separator) ;override sendmail.el
597 ;; If using MML, translate MH-style directive
598 (if (equal mh-compose-insertion 'mml)
599 (save-excursion
600 (goto-char (mh-mail-header-end))
601 (while
602 (re-search-forward
603 "^#forw \\[\\([^]]+\\)\\] \\(+\\S-+\\) \\(.*\\)$"
604 (point-max) t)
605 (let ((description (if (equal (match-string 1)
606 "forwarded messages")
607 "forwarded message %d"
608 (match-string 1)))
609 (msgs (split-string (match-string 3)))
610 (i 0))
611 (beginning-of-line)
612 (delete-region (point) (progn (forward-line 1) (point)))
613 (dolist (msg msgs)
614 (setq i (1+ i))
615 (mh-mml-forward-message (format description i)
616 folder msg)
617 ;; Was inserted before us, move to end of file to preserve order
618 (goto-char (point-max)))))))
619 ;; Position just before forwarded message.
620 (if (re-search-forward "^------- Forwarded Message" nil t)
621 (forward-line -1)
622 (goto-char (mh-mail-header-end))
623 (forward-line 1))
624 (delete-other-windows)
625 (mh-add-msgs-to-seq msgs 'forwarded t)
626 (mh-compose-and-send-mail draft "" folder msgs
627 to forw-subject cc
628 mh-note-forw "Forwarded:"
629 config)
630 (mh-letter-mode-message)
631 (mh-letter-adjust-point)
632 (run-hooks 'mh-forward-hook)))))
633
634(defun mh-forwarded-letter-subject (from subject)
635 "Return a Subject suitable for a forwarded message.
636Original message has headers FROM and SUBJECT."
637 (let ((addr-start (string-match "<" from))
638 (comment (string-match "(" from)))
639 (cond ((and addr-start (> addr-start 0))
640 ;; Full Name <luser@host>
641 (setq from (substring from 0 (1- addr-start))))
642 (comment
643 ;; luser@host (Full Name)
644 (setq from (substring from (1+ comment) (1- (length from)))))))
645 (format mh-forward-subject-format from subject))
646
647;;;###mh-autoload
648(defun mh-redistribute (to cc &optional message)
649 "Redistribute a message.
650
651This command is similar in function to forwarding mail, but it
652does not allow you to edit the message, nor does it add your name
653to the \"From\" header field. It appears to the recipient as if
654the message had come from the original sender. When you run this
655command, you are prompted for the TO and CC recipients. The
656default MESSAGE is the current message.
657
658Also investigate the command \\[mh-edit-again] for another way to
659redistribute messages.
660
661See also `mh-redist-full-contents-flag'.
662
663The hook `mh-annotate-msg-hook' is run after annotating the
664message and scan line."
665 (interactive (list (mh-read-address "Redist-To: ")
666 (mh-read-address "Redist-Cc: ")
667 (mh-get-msg-num t)))
668 (or message
669 (setq message (mh-get-msg-num t)))
670 (save-window-excursion
671 (let ((folder mh-current-folder)
672 (draft (mh-read-draft "redistribution"
673 (if mh-redist-full-contents-flag
674 (mh-msg-filename message)
675 nil)
676 nil)))
677 (mh-goto-header-end 0)
678 (insert "Resent-To: " to "\n")
679 (if (not (equal cc "")) (insert "Resent-cc: " cc "\n"))
680 (mh-clean-msg-header
681 (point-min)
682 "^Message-Id:\\|^Received:\\|^Return-Path:\\|^Sender:\\|^Date:\\|^From:"
683 nil)
684 (save-buffer)
685 (message "Redistributing...")
686 (let ((env "mhdist=1"))
687 ;; Setup environment...
688 (setq env (concat env " mhaltmsg="
689 (if mh-redist-full-contents-flag
690 buffer-file-name
691 (mh-msg-filename message folder))))
692 (unless mh-redist-full-contents-flag
693 (setq env (concat env " mhannotate=1")))
694 ;; Redistribute...
695 (if mh-redist-background
696 (mh-exec-cmd-env-daemon env mh-send-prog nil buffer-file-name)
697 (mh-exec-cmd-error env mh-send-prog "-push" buffer-file-name))
698 ;; Annotate...
699 (mh-annotate-msg message folder mh-note-dist
700 "-component" "Resent:"
701 "-text" (format "\"%s %s\"" to cc)))
702 (kill-buffer draft)
703 (message "Redistributing...done"))))
704
705;;;###mh-autoload
706(defun mh-reply (message &optional reply-to includep)
707 "Reply to a MESSAGE.
708
709When you reply to a message, you are first prompted with \"Reply
710to whom?\" (unless the optional argument REPLY-TO is provided).
711You have several choices here.
712
713 Response Reply Goes To
714
715 from The person who sent the message. This is the
716 default, so <RET> is sufficient.
717
718 to Replies to the sender, plus all recipients in the
719 \"To:\" header field.
720
721 all cc Forms a reply to the addresses in the
722 \"Mail-Followup-To:\" header field if one
723 exists; otherwise forms a reply to the sender,
724 plus all recipients.
725
726Depending on your answer, \"repl\" is given a different argument
727to form your reply. Specifically, a choice of \"from\" or none at
728all runs \"repl -nocc all\", and a choice of \"to\" runs \"repl
729-cc to\". Finally, either \"cc\" or \"all\" runs \"repl -cc all
730-nocc me\".
731
732Two windows are then created. One window contains the message to
733which you are replying in an MH-Show buffer. Your draft, in
734MH-Letter mode (*note `mh-letter-mode'), is in the other window.
735If the reply draft was not one that you expected, check the
736things that affect the behavior of \"repl\" which include the
737\"repl:\" profile component and the \"replcomps\" and
738\"replgroupcomps\" files.
739
740If you supply a prefix argument INCLUDEP, the message you are
741replying to is inserted in your reply after having first been run
742through \"mhl\" with the format file \"mhl.reply\".
743
744Alternatively, you can customize the option `mh-yank-behavior'
745and choose one of its \"Automatically\" variants to do the same
746thing. If you do so, the prefix argument has no effect.
747
748Another way to include the message automatically in your draft is
749to use \"repl: -filter repl.filter\" in your MH profile.
750
751If you wish to customize the header or other parts of the reply
752draft, please see \"repl\" and \"mh-format\".
753
754See also `mh-reply-show-message-flag',
755`mh-reply-default-reply-to', and `mh-send'."
756 (interactive (list
757 (mh-get-msg-num t)
758 (let ((minibuffer-help-form
759 "from => Sender only\nto => Sender and primary recipients\ncc or all => Sender and all recipients"))
760 (or mh-reply-default-reply-to
761 (completing-read "Reply to whom (default from): "
762 '(("from") ("to") ("cc") ("all"))
763 nil
764 t)))
765 current-prefix-arg))
766 (let* ((folder mh-current-folder)
767 (show-buffer mh-show-buffer)
768 (config (current-window-configuration))
769 (group-reply (or (equal reply-to "cc") (equal reply-to "all")))
770 (form-file (cond ((and (mh-variant-p 'nmh 'gnu-mh) group-reply
771 (stringp mh-repl-group-formfile))
772 mh-repl-group-formfile)
773 ((stringp mh-repl-formfile) mh-repl-formfile)
774 (t nil))))
775 (message "Composing a reply...")
776 (mh-exec-cmd "repl" "-build" "-noquery" "-nodraftfolder"
777 (if form-file
778 (list "-form" form-file))
779 mh-current-folder message
780 (cond ((or (equal reply-to "from") (equal reply-to ""))
781 '("-nocc" "all"))
782 ((equal reply-to "to")
783 '("-cc" "to"))
784 (group-reply (if (mh-variant-p 'nmh 'gnu-mh)
785 '("-group" "-nocc" "me")
786 '("-cc" "all" "-nocc" "me"))))
787 (cond ((or (eq mh-yank-behavior 'autosupercite)
788 (eq mh-yank-behavior 'autoattrib))
789 '("-noformat"))
790 (includep '("-filter" "mhl.reply"))
791 (t '())))
792 (let ((draft (mh-read-draft "reply"
793 (expand-file-name "reply" mh-user-path)
794 t)))
795 (delete-other-windows)
796 (save-buffer)
797
798 (let ((to (mh-get-header-field "To:"))
799 (subject (mh-get-header-field "Subject:"))
800 (cc (mh-get-header-field "Cc:")))
801 (goto-char (point-min))
802 (mh-goto-header-end 1)
803 (or includep
804 (not mh-reply-show-message-flag)
805 (mh-in-show-buffer (show-buffer)
806 (mh-display-msg message folder)))
807 (mh-add-msgs-to-seq message 'answered t)
808 (message "Composing a reply...done")
809 (mh-compose-and-send-mail draft "" folder message to subject cc
810 mh-note-repl "Replied:" config))
811 (when (and (or (eq 'autosupercite mh-yank-behavior)
812 (eq 'autoattrib mh-yank-behavior))
813 (eq (mh-show-buffer-message-number) mh-sent-from-msg))
814 (undo-boundary)
815 (mh-yank-cur-msg))
816 (mh-letter-mode-message))))
817
818;;;###mh-autoload
819(defun mh-send (to cc subject)
820 "Compose a message.
821
822Your letter appears in an Emacs buffer whose mode is
823MH-Letter (see `mh-letter-mode').
824
825The arguments TO, CC, and SUBJECT can be used to prefill the
826draft fields or suppress the prompts if `mh-compose-prompt-flag'
827is on. They are also passed to the function set in the option
828`mh-compose-letter-function'.
829
830See also `mh-insert-x-mailer-flag' and `mh-letter-mode-hook'.
831
832Outside of an MH-Folder buffer (`mh-folder-mode'), you must call
833either \\[mh-smail] or \\[mh-smail-other-window] to compose a new
834message."
835 (interactive (list
836 (mh-interactive-read-address "To: ")
837 (mh-interactive-read-address "Cc: ")
838 (mh-interactive-read-string "Subject: ")))
839 (let ((config (current-window-configuration)))
840 (delete-other-windows)
841 (mh-send-sub to cc subject config)))
842
843\f
844
845;;; Support Routines
846
847(defun mh-interactive-read-address (prompt)
848 "Read an address.
849If `mh-compose-prompt-flag' is non-nil, then read an address with
850PROMPT.
851Otherwise return the empty string."
852 (if mh-compose-prompt-flag (mh-read-address prompt) ""))
853
854(defun mh-interactive-read-string (prompt)
855 "Read a string.
856If `mh-compose-prompt-flag' is non-nil, then read a string with
857PROMPT.
858Otherwise return the empty string."
859 (if mh-compose-prompt-flag (read-string prompt) ""))
860
861;;;###mh-autoload
862(defun mh-show-buffer-message-number (&optional buffer)
863 "Message number of displayed message in corresponding show buffer.
864
865Return nil if show buffer not displayed.
866If in `mh-letter-mode', don't display the message number being replied
867to, but rather the message number of the show buffer associated with
868our originating folder buffer.
869Optional argument BUFFER can be used to specify the buffer."
870 (save-excursion
871 (if buffer
872 (set-buffer buffer))
873 (cond ((eq major-mode 'mh-show-mode)
874 (let ((number-start (mh-search-from-end ?/ buffer-file-name)))
875 (string-to-number (substring buffer-file-name
876 (1+ number-start)))))
877 ((and (eq major-mode 'mh-folder-mode)
878 mh-show-buffer
879 (get-buffer mh-show-buffer))
880 (mh-show-buffer-message-number mh-show-buffer))
881 ((and (eq major-mode 'mh-letter-mode)
882 mh-sent-from-folder
883 (get-buffer mh-sent-from-folder))
884 (mh-show-buffer-message-number mh-sent-from-folder))
885 (t
886 nil))))
887
888(defun mh-find-components ()
889 "Return the path to the components file."
890 (let (components)
891 (cond
892 ((file-exists-p
893 (setq components
894 (expand-file-name mh-comp-formfile mh-user-path)))
895 components)
896 ((file-exists-p
897 (setq components
898 (expand-file-name mh-comp-formfile mh-lib)))
899 components)
900 (t
901 (error "Can't find %s in %s or %s"
902 mh-comp-formfile mh-user-path mh-lib)))))
903
904(defun mh-send-sub (to cc subject config)
905 "Do the real work of composing and sending a letter.
906Expects the TO, CC, and SUBJECT fields as arguments.
907CONFIG is the window configuration before sending mail."
908 (let ((folder mh-current-folder)
909 (msg-num (mh-get-msg-num nil)))
910 (message "Composing a message...")
911 (let ((draft (mh-read-draft
912 "message"
913 (mh-find-components)
914 nil)))
915 (mh-insert-fields "To:" to "Subject:" subject "Cc:" cc)
916 (goto-char (point-max))
917 (mh-compose-and-send-mail draft "" folder msg-num
918 to subject cc
919 nil nil config)
920 (mh-letter-mode-message)
921 (mh-letter-adjust-point))))
922
923(defun mh-read-draft (use initial-contents delete-contents-file)
924 "Read draft file into a draft buffer and make that buffer the current one.
925
926USE is a message used for prompting about the intended use of the
927message.
928INITIAL-CONTENTS is filename that is read into an empty buffer, or nil
929if buffer should not be modified. Delete the initial-contents file if
930DELETE-CONTENTS-FILE flag is set.
931Returns the draft folder's name.
932If the draft folder facility is enabled in ~/.mh_profile, a new buffer
933is used each time and saved in the draft folder. The draft file can
934then be reused."
935 (cond (mh-draft-folder
936 (let ((orig-default-dir default-directory)
937 (draft-file-name (mh-new-draft-name)))
938 (pop-to-buffer (generate-new-buffer
939 (format "draft-%s"
940 (file-name-nondirectory draft-file-name))))
941 (condition-case ()
942 (insert-file-contents draft-file-name t)
943 (file-error))
944 (setq default-directory orig-default-dir)))
945 (t
946 (let ((draft-name (expand-file-name "draft" mh-user-path)))
947 (pop-to-buffer "draft") ; Create if necessary
948 (if (buffer-modified-p)
949 (if (y-or-n-p "Draft has been modified; kill anyway? ")
950 (set-buffer-modified-p nil)
951 (error "Draft preserved")))
952 (setq buffer-file-name draft-name)
953 (clear-visited-file-modtime)
954 (unlock-buffer)
955 (cond ((and (file-exists-p draft-name)
956 (not (equal draft-name initial-contents)))
957 (insert-file-contents draft-name)
958 (delete-file draft-name))))))
959 (cond ((and initial-contents
960 (or (zerop (buffer-size))
961 (if (y-or-n-p
962 (format "A draft exists. Use for %s? " use))
963 (if mh-error-if-no-draft
964 (error "A prior draft exists"))
965 t)))
966 (erase-buffer)
967 (insert-file-contents initial-contents)
968 (if delete-contents-file (delete-file initial-contents))))
969 (auto-save-mode 1)
970 (if mh-draft-folder
971 (save-buffer)) ; Do not reuse draft name
972 (buffer-name))
973
974(defun mh-new-draft-name ()
975 "Return the pathname of folder for draft messages."
976 (save-excursion
977 (mh-exec-cmd-quiet t "mhpath" mh-draft-folder "new")
978 (buffer-substring (point-min) (1- (point-max)))))
979
980(defun mh-insert-fields (&rest name-values)
981 "Insert the NAME-VALUES pairs in the current buffer.
982If the field exists, append the value to it.
983Do not insert any pairs whose value is the empty string."
984 (let ((case-fold-search t))
985 (while name-values
986 (let ((field-name (car name-values))
987 (value (car (cdr name-values))))
988 (if (not (string-match "^.*:$" field-name))
989 (setq field-name (concat field-name ":")))
990 (cond ((or (null value)
991 (equal value ""))
992 nil)
993 ((mh-position-on-field field-name)
994 (insert " " (or value "")))
995 (t
996 (insert field-name " " value "\n")))
997 (setq name-values (cdr (cdr name-values)))))))
998
999(defun mh-compose-and-send-mail (draft send-args
1000 sent-from-folder sent-from-msg
1001 to subject cc
1002 annotate-char annotate-field
1003 config)
1004 "Edit and compose a draft message in buffer DRAFT and send or save it.
1005SEND-ARGS is the argument passed to the send command.
1006SENT-FROM-FOLDER is buffer containing scan listing of current folder,
1007or nil if none exists.
1008SENT-FROM-MSG is the message number or sequence name or nil.
1009The TO, SUBJECT, and CC fields are passed to the
1010`mh-compose-letter-function'.
1011If ANNOTATE-CHAR is non-null, it is used to notate the scan listing of
1012the message. In that case, the ANNOTATE-FIELD is used to build a
1013string for `mh-annotate-msg'.
1014CONFIG is the window configuration to restore after sending the
1015letter."
1016 (pop-to-buffer draft)
1017 (mh-letter-mode)
1018
1019 ;; Insert identity.
1020 (mh-insert-identity mh-identity-default t)
1021 (mh-identity-make-menu)
1022 (mh-identity-add-menu)
1023
1024 ;; Cleanup possibly RFC2047 encoded subject header
1025 (mh-decode-message-subject)
1026
1027 ;; Insert extra fields.
1028 (mh-insert-x-mailer)
1029 (mh-insert-x-face)
1030
1031 (mh-letter-hide-all-skipped-fields)
1032
1033 (setq mh-sent-from-folder sent-from-folder)
1034 (setq mh-sent-from-msg sent-from-msg)
1035 (setq mh-send-args send-args)
1036 (setq mh-annotate-char annotate-char)
1037 (setq mh-annotate-field annotate-field)
1038 (setq mh-previous-window-config config)
1039 (setq mode-line-buffer-identification (list " {%b}"))
1040 (mh-logo-display)
1041 (mh-make-local-hook 'kill-buffer-hook)
1042 (add-hook 'kill-buffer-hook 'mh-tidy-draft-buffer nil t)
1043 (run-hook-with-args 'mh-compose-letter-function to subject cc))
1044
1045(defun mh-insert-x-mailer ()
1046 "Append an X-Mailer field to the header.
1047The versions of MH-E, Emacs, and MH are shown."
1048 ;; Lazily initialize mh-x-mailer-string.
1049 (when (and mh-insert-x-mailer-flag (null mh-x-mailer-string))
1050 (setq mh-x-mailer-string
1051 (format "MH-E %s; %s; %sEmacs %s"
1052 mh-version mh-variant-in-use
1053 (if (featurep 'xemacs) "X" "GNU ")
1054 (cond ((not (featurep 'xemacs))
1055 (string-match "[0-9]+\\.[0-9]+\\(\\.[0-9]+\\)?"
1056 emacs-version)
1057 (match-string 0 emacs-version))
1058 ((string-match "[0-9.]*\\( +\([ a-z]+[0-9]+\)\\)?"
1059 emacs-version)
1060 (match-string 0 emacs-version))
1061 (t (format "%s.%s" emacs-major-version
1062 emacs-minor-version))))))
1063 ;; Insert X-Mailer, but only if it doesn't already exist.
1064 (save-excursion
1065 (when (and mh-insert-x-mailer-flag
1066 (null (mh-goto-header-field "X-Mailer")))
1067 (mh-insert-fields "X-Mailer:" mh-x-mailer-string))))
1068
1069(defun mh-insert-x-face ()
1070 "Append X-Face, Face or X-Image-URL field to header.
1071If the field already exists, this function does nothing."
1072 (when (and (file-exists-p mh-x-face-file)
1073 (file-readable-p mh-x-face-file))
1074 (save-excursion
1075 (unless (or (mh-position-on-field "X-Face")
1076 (mh-position-on-field "Face")
1077 (mh-position-on-field "X-Image-URL"))
1078 (save-excursion
1079 (goto-char (+ (point) (cadr (insert-file-contents mh-x-face-file))))
1080 (if (not (looking-at "^"))
1081 (insert "\n")))
1082 (unless (looking-at "\\(X-Face\\|Face\\|X-Image-URL\\): ")
1083 (insert "X-Face: "))))))
1084
1085(defun mh-tidy-draft-buffer ()
1086 "Run when a draft buffer is destroyed."
1087 (let ((buffer (get-buffer mh-recipients-buffer)))
1088 (if buffer
1089 (kill-buffer buffer))))
1090
1091(defun mh-letter-mode-message ()
1092 "Display a help message for users of `mh-letter-mode'.
1093This should be the last function called when composing the draft."
1094 (message "%s" (substitute-command-keys
1095 (concat "Type \\[mh-send-letter] to send message, "
1096 "\\[mh-help] for help"))))
1097
1098(defun mh-letter-adjust-point ()
1099 "Move cursor to first header field if are using the no prompt mode."
1100 (unless mh-compose-prompt-flag
1101 (goto-char (point-max))
1102 (mh-letter-next-header-field)))
1103
1104(defun mh-annotate-msg (msg folder note &rest args)
1105 "Mark MSG in FOLDER with character NOTE and annotate message with ARGS.
1106MSG can be a message number, a list of message numbers, or a sequence.
1107The hook `mh-annotate-msg-hook' is run after annotating; see its
1108documentation for variables it can use."
1109 (apply 'mh-exec-cmd "anno" folder
1110 (if (listp msg) (append msg args) (cons msg args)))
1111 (save-excursion
1112 (cond ((get-buffer folder) ; Buffer may be deleted
1113 (set-buffer folder)
1114 (mh-iterate-on-range nil msg
1115 (mh-notate nil note
1116 (+ mh-cmd-note mh-scan-field-destination-offset))))))
1117 (let ((mh-current-folder folder)
1118 ;; mh-annotate-list is a sequence name or a list of message numbers
1119 (mh-annotate-list (if (numberp msg) (list msg) msg)))
1120 (run-hooks 'mh-annotate-msg-hook)))
1121
1122(defun mh-insert-header-separator ()
1123 "Insert `mh-mail-header-separator', if absent."
1124 (save-excursion
1125 (goto-char (point-min))
1126 (rfc822-goto-eoh)
1127 (if (looking-at "$")
1128 (insert mh-mail-header-separator))))
1129
1130;;;###mh-autoload
1131(defun mh-insert-auto-fields (&optional non-interactive)
1132 "Insert custom fields if recipient is found in `mh-auto-fields-list'.
1133
1134Once the header contains one or more recipients, you may run this
1135command to insert these fields manually. However, if you use this
1136command, the automatic insertion when the message is sent is
1137disabled.
1138
1139In a program, set buffer-local `mh-insert-auto-fields-done-local'
1140if header fields were added. If NON-INTERACTIVE is non-nil,
1141perform actions quietly and only if
1142`mh-insert-auto-fields-done-local' is nil. Return t if fields
1143added; otherwise return nil."
1144 (interactive)
1145 (when (or (not non-interactive)
1146 (not mh-insert-auto-fields-done-local))
1147 (save-excursion
1148 (when (and (or (mh-goto-header-field "To:")
1149 (mh-goto-header-field "cc:")))
1150 (let ((list mh-auto-fields-list)
1151 (fields-inserted nil))
1152 (while list
1153 (let ((regexp (nth 0 (car list)))
1154 (entries (nth 1 (car list))))
1155 (when (mh-regexp-in-field-p regexp "To:" "cc:")
1156 (setq mh-insert-auto-fields-done-local t)
1157 (setq fields-inserted t)
1158 (if (not non-interactive)
1159 (message "Fields for %s added" regexp))
1160 (let ((entry-list entries))
1161 (while entry-list
1162 (let ((field (caar entry-list))
1163 (value (cdar entry-list)))
1164 (cond
1165 ((equal ":identity" field)
1166 (when
1167 ;;(and (not mh-identity-local)
1168 ;; Bug 1204506. But do we need to be able
1169 ;; to set an identity manually that won't be
1170 ;; overridden by mh-insert-auto-fields?
1171 (assoc value mh-identity-list)
1172 ;;)
1173 (mh-insert-identity value)))
1174 (t
1175 (mh-modify-header-field field value
1176 (equal field "From")))))
1177 (setq entry-list (cdr entry-list))))))
1178 (setq list (cdr list)))
1179 fields-inserted)))))
1180
1181(defun mh-modify-header-field (field value &optional overwrite-flag)
1182 "To header FIELD add VALUE.
1183If OVERWRITE-FLAG is non-nil then the old value, if present, is
1184discarded."
1185 (cond ((and overwrite-flag
1186 (mh-goto-header-field (concat field ":")))
1187 (insert " " value)
1188 (delete-region (point) (mh-line-end-position)))
1189 ((and (not overwrite-flag)
1190 (mh-regexp-in-field-p (concat "\\b" (regexp-quote value) "\\b") field))
1191 ;; Already there, do nothing.
1192 )
1193 ((and (not overwrite-flag)
1194 (mh-goto-header-field (concat field ":")))
1195 (insert " " value ","))
1196 (t
1197 (mh-goto-header-end 0)
1198 (insert field ": " value "\n"))))
1199
1200(defun mh-regexp-in-field-p (regexp &rest fields)
1201 "Non-nil means REGEXP was found in FIELDS."
1202 (let ((old-syntax-table (syntax-table)))
1203 (unwind-protect
1204 (save-excursion
1205 (let ((search-result nil))
1206 (while fields
1207 (let* ((field (car fields))
1208 (syntax-table
1209 (or mh-regexp-in-field-syntax-table
1210 (let ((case-fold-search t))
1211 (cond
1212 ((string-match field "^To$\\|^[BD]?cc$\\|^From$")
1213 mh-addr-syntax-table)
1214 ((string-match field "^Fcc$")
1215 mh-fcc-syntax-table)
1216 (t
1217 (syntax-table)))
1218 ))))
1219 (if (and (mh-goto-header-field field)
1220 (set-syntax-table syntax-table)
1221 (re-search-forward
1222 regexp (save-excursion (mh-header-field-end)(point)) t))
1223 (setq fields nil
1224 search-result t)
1225 (setq fields (cdr fields)))
1226 (set-syntax-table old-syntax-table)))
1227 search-result))
1228 (set-syntax-table old-syntax-table))))
1229
1230(defun mh-ascii-buffer-p ()
1231 "Check if current buffer is entirely composed of ASCII.
1232The function doesn't work for XEmacs since `find-charset-region'
1233doesn't exist there."
1234 (loop for charset in (mh-funcall-if-exists
1235 find-charset-region (point-min) (point-max))
1236 unless (eq charset 'ascii) return nil
1237 finally return t))
1238
1239(provide 'mh-comp)
1240
1241;; Local Variables:
1242;; indent-tabs-mode: nil
1243;; sentence-end-double-space: nil
1244;; End:
1245
1246;;; mh-comp.el ends here