1 ;;; message.el --- composing mail and news messages
2 ;; Copyright (C) 1996,97,98,99 Free Software Foundation, Inc.
4 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
5 ;; Keywords: mail, news
7 ;; This file is part of GNU Emacs.
9 ;; GNU Emacs is free software; you can redistribute it and/or modify
10 ;; it under the terms of the GNU General Public License as published by
11 ;; the Free Software Foundation; either version 2, or (at your option)
14 ;; GNU Emacs is distributed in the hope that it will be useful,
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ;; GNU General Public License for more details.
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with GNU Emacs; see the file COPYING. If not, write to the
21 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 ;; Boston, MA 02111-1307, USA.
26 ;; This mode provides mail-sending facilities from within Emacs. It
27 ;; consists mainly of large chunks of code from the sendmail.el,
28 ;; gnus-msg.el and rnewspost.el files.
32 (eval-when-compile (require 'cl))
38 (if (string-match "XEmacs\\|Lucid" emacs-version)
39 (require 'mail-abbrevs)
40 (require 'mailabbrev))
46 (defgroup message '((user-mail-address custom-variable)
47 (user-full-name custom-variable))
48 "Mail and news message composing."
49 :link '(custom-manual "(message)Top")
53 (put 'user-mail-address 'custom-type 'string)
54 (put 'user-full-name 'custom-type 'string)
56 (defgroup message-various nil
57 "Various Message Variables"
58 :link '(custom-manual "(message)Various Message Variables")
61 (defgroup message-buffers nil
63 :link '(custom-manual "(message)Message Buffers")
66 (defgroup message-sending nil
68 :link '(custom-manual "(message)Sending Variables")
71 (defgroup message-interface nil
73 :link '(custom-manual "(message)Interface")
76 (defgroup message-forwarding nil
78 :link '(custom-manual "(message)Forwarding")
79 :group 'message-interface)
81 (defgroup message-insertion nil
83 :link '(custom-manual "(message)Insertion")
86 (defgroup message-headers nil
88 :link '(custom-manual "(message)Message Headers")
91 (defgroup message-news nil
92 "Composing News Messages"
95 (defgroup message-mail nil
96 "Composing Mail Messages"
99 (defgroup message-faces nil
100 "Faces used for message composing."
104 (defcustom message-directory "~/Mail/"
105 "*Directory from which all other mail file variables are derived."
106 :group 'message-various
109 (defcustom message-max-buffers 10
110 "*How many buffers to keep before starting to kill them off."
111 :group 'message-buffers
114 (defcustom message-send-rename-function nil
115 "Function called to rename the buffer after sending it."
116 :group 'message-buffers
119 (defcustom message-fcc-handler-function 'message-output
120 "*A function called to save outgoing articles.
121 This function will be called with the name of the file to store the
122 article in. The default function is `message-output' which saves in Unix
124 :type '(radio (function-item message-output)
125 (function :tag "Other"))
126 :group 'message-sending)
128 (defcustom message-courtesy-message
129 "The following message is a courtesy copy of an article\nthat has been posted to %s as well.\n\n"
130 "*This is inserted at the start of a mailed copy of a posted message.
131 If the string contains the format spec \"%s\", the Newsgroups
132 the article has been posted to will be inserted there.
133 If this variable is nil, no such courtesy message will be added."
134 :group 'message-sending
137 (defcustom message-ignored-bounced-headers "^\\(Received\\|Return-Path\\):"
138 "*Regexp that matches headers to be removed in resent bounced mail."
139 :group 'message-interface
143 (defcustom message-from-style 'default
144 "*Specifies how \"From\" headers look.
146 If `nil', they contain just the return address like:
148 If `parens', they look like:
149 king@grassland.com (Elvis Parsley)
150 If `angles', they look like:
151 Elvis Parsley <king@grassland.com>
153 Otherwise, most addresses look like `angles', but they look like
154 `parens' if `angles' would need quoting and `parens' would not."
155 :type '(choice (const :tag "simple" nil)
159 :group 'message-headers)
161 (defcustom message-syntax-checks nil
162 ; Guess this one shouldn't be easy to customize...
163 "*Controls what syntax checks should not be performed on outgoing posts.
164 To disable checking of long signatures, for instance, add
165 `(signature . disabled)' to this list.
167 Don't touch this variable unless you really know what you're doing.
169 Checks include subject-cmsg multiple-headers sendsys message-id from
170 long-lines control-chars size new-text redirected-followup signature
171 approved sender empty empty-headers message-id from subject
172 shorten-followup-to existing-newsgroups buffer-file-name unchanged
174 :group 'message-news)
176 (defcustom message-required-news-headers
177 '(From Newsgroups Subject Date Message-ID
178 (optional . Organization) Lines
179 (optional . User-Agent))
180 "*Headers to be generated or prompted for when posting an article.
181 RFC977 and RFC1036 require From, Date, Newsgroups, Subject,
182 Message-ID. Organization, Lines, In-Reply-To, Expires, and
183 User-Agent are optional. If don't you want message to insert some
184 header, remove it from this list."
186 :group 'message-headers
187 :type '(repeat sexp))
189 (defcustom message-required-mail-headers
190 '(From Subject Date (optional . In-Reply-To) Message-ID Lines
191 (optional . User-Agent))
192 "*Headers to be generated or prompted for when mailing a message.
193 RFC822 required that From, Date, To, Subject and Message-ID be
194 included. Organization, Lines and User-Agent are optional."
196 :group 'message-headers
197 :type '(repeat sexp))
199 (defcustom message-deletable-headers '(Message-ID Date Lines)
200 "Headers to be deleted if they already exist and were generated by message previously."
201 :group 'message-headers
204 (defcustom message-ignored-news-headers
205 "^NNTP-Posting-Host:\\|^Xref:\\|^[BGF]cc:\\|^Resent-Fcc:"
206 "*Regexp of headers to be removed unconditionally before posting."
208 :group 'message-headers
211 (defcustom message-ignored-mail-headers "^[GF]cc:\\|^Resent-Fcc:\\|^Xref:"
212 "*Regexp of headers to be removed unconditionally before mailing."
214 :group 'message-headers
217 (defcustom message-ignored-supersedes-headers "^Path:\\|^Date\\|^NNTP-Posting-Host:\\|^Xref:\\|^Lines:\\|^Received:\\|^X-From-Line:\\|^X-Trace:\\|^X-Complaints-To:\\|Return-Path:\\|^Supersedes:\\|^NNTP-Posting-Date:\\|^X-Trace:\\|^X-Complaints-To:"
218 "*Header lines matching this regexp will be deleted before posting.
219 It's best to delete old Path and Date headers before posting to avoid
221 :group 'message-interface
224 (defcustom message-subject-re-regexp "^[ \t]*\\([Rr][Ee]:[ \t]*\\)*[ \t]*"
225 "*Regexp matching \"Re: \" in the subject line."
226 :group 'message-various
230 (defcustom message-signature-separator "^-- *$"
231 "Regexp matching the signature separator."
233 :group 'message-various)
235 (defcustom message-elide-elipsis "\n[...]\n\n"
236 "*The string which is inserted for elided text."
238 :group 'message-various)
240 (defcustom message-interactive nil
241 "Non-nil means when sending a message wait for and display errors.
242 nil means let mailer mail back a message to report errors."
243 :group 'message-sending
247 (defcustom message-generate-new-buffers 'unique
248 "*Non-nil means that a new message buffer will be created whenever `message-setup' is called.
249 If this is a function, call that function with three parameters: The type,
250 the to address and the group name. (Any of these may be nil.) The function
251 should return the new buffer name."
252 :group 'message-buffers
253 :type '(choice (const :tag "off" nil)
254 (const :tag "unique" unique)
255 (const :tag "unsent" unsent)
258 (defcustom message-kill-buffer-on-exit nil
259 "*Non-nil means that the message buffer will be killed after sending a message."
260 :group 'message-buffers
263 (defvar gnus-local-organization)
264 (defcustom message-user-organization
265 (or (and (boundp 'gnus-local-organization)
266 (stringp gnus-local-organization)
267 gnus-local-organization)
268 (getenv "ORGANIZATION")
270 "*String to be used as an Organization header.
271 If t, use `message-user-organization-file'."
272 :group 'message-headers
273 :type '(choice string
274 (const :tag "consult file" t)))
277 (defcustom message-user-organization-file "/usr/lib/news/organization"
278 "*Local news organization file."
280 :group 'message-headers)
282 (defcustom message-make-forward-subject-function
283 'message-forward-subject-author-subject
284 "*A list of functions that are called to generate a subject header for forwarded messages.
285 The subject generated by the previous function is passed into each
288 The provided functions are:
290 * message-forward-subject-author-subject (Source of article (author or
291 newsgroup)), in brackets followed by the subject
292 * message-forward-subject-fwd (Subject of article with 'Fwd:' prepended
294 :group 'message-forwarding
295 :type '(radio (function-item message-forward-subject-author-subject)
296 (function-item message-forward-subject-fwd)))
298 (defcustom message-wash-forwarded-subjects nil
299 "*If non-nil, try to remove as much old cruft as possible from the subject of messages before generating the new subject of a forward."
300 :group 'message-forwarding
303 (defcustom message-ignored-resent-headers "^Return-receipt\\|^X-Gnus\\|^Gnus-Warning:"
304 "*All headers that match this regexp will be deleted when resending a message."
305 :group 'message-interface
309 (defcustom message-forward-ignored-headers nil
310 "*All headers that match this regexp will be deleted when forwarding a message."
311 :group 'message-forwarding
312 :type '(choice (const :tag "None" nil)
315 (defcustom message-ignored-cited-headers "."
316 "*Delete these headers from the messages you yank."
317 :group 'message-insertion
320 (defcustom message-cancel-message "I am canceling my own article."
321 "Message to be inserted in the cancel message."
322 :group 'message-interface
325 ;; Useful to set in site-init.el
327 (defcustom message-send-mail-function 'message-send-mail-with-sendmail
328 "Function to call to send the current buffer as mail.
329 The headers should be delimited by a line whose contents match the
330 variable `mail-header-separator'.
332 Valid values include `message-send-mail-with-sendmail' (the default),
333 `message-send-mail-with-mh', `message-send-mail-with-qmail' and
335 :type '(radio (function-item message-send-mail-with-sendmail)
336 (function-item message-send-mail-with-mh)
337 (function-item message-send-mail-with-qmail)
338 (function-item smtpmail-send-it)
339 (function :tag "Other"))
340 :group 'message-sending
341 :group 'message-mail)
343 (defcustom message-send-news-function 'message-send-news
344 "Function to call to send the current buffer as news.
345 The headers should be delimited by a line whose contents match the
346 variable `mail-header-separator'."
347 :group 'message-sending
351 (defcustom message-reply-to-function nil
352 "Function that should return a list of headers.
353 This function should pick out addresses from the To, Cc, and From headers
354 and respond with new To and Cc headers."
355 :group 'message-interface
358 (defcustom message-wide-reply-to-function nil
359 "Function that should return a list of headers.
360 This function should pick out addresses from the To, Cc, and From headers
361 and respond with new To and Cc headers."
362 :group 'message-interface
365 (defcustom message-followup-to-function nil
366 "Function that should return a list of headers.
367 This function should pick out addresses from the To, Cc, and From headers
368 and respond with new To and Cc headers."
369 :group 'message-interface
372 (defcustom message-use-followup-to 'ask
373 "*Specifies what to do with Followup-To header.
374 If nil, always ignore the header. If it is t, use its value, but
375 query before using the \"poster\" value. If it is the symbol `ask',
376 always query the user whether to use the value. If it is the symbol
377 `use', always use the value."
378 :group 'message-interface
379 :type '(choice (const :tag "ignore" nil)
383 ;; stuff relating to broken sendmail in MMDF
384 (defcustom message-sendmail-f-is-evil nil
385 "*Non-nil means that \"-f username\" should not be added to the sendmail
386 command line, because it is even more evil than leaving it out."
387 :group 'message-sending
390 ;; qmail-related stuff
391 (defcustom message-qmail-inject-program "/var/qmail/bin/qmail-inject"
392 "Location of the qmail-inject program."
393 :group 'message-sending
396 (defcustom message-qmail-inject-args nil
397 "Arguments passed to qmail-inject programs.
398 This should be a list of strings, one string for each argument.
400 For e.g., if you wish to set the envelope sender address so that bounces
401 go to the right place or to deal with listserv's usage of that address, you
402 might set this variable to '(\"-f\" \"you@some.where\")."
403 :group 'message-sending
404 :type '(repeat string))
406 (defvar gnus-post-method)
407 (defvar gnus-select-method)
408 (defcustom message-post-method
409 (cond ((and (boundp 'gnus-post-method)
410 (listp gnus-post-method)
413 ((boundp 'gnus-select-method)
416 "*Method used to post news.
417 Note that when posting from inside Gnus, for instance, this
418 variable isn't used."
420 :group 'message-sending
421 ;; This should be the `gnus-select-method' widget, but that might
422 ;; create a dependence to `gnus.el'.
425 (defcustom message-generate-headers-first nil
426 "*If non-nil, generate all possible headers before composing."
427 :group 'message-headers
430 (defcustom message-setup-hook nil
431 "Normal hook, run each time a new outgoing message is initialized.
432 The function `message-setup' runs this hook."
433 :group 'message-various
436 (defcustom message-cancel-hook nil
437 "Hook run when cancelling articles."
438 :group 'message-various
441 (defcustom message-signature-setup-hook nil
442 "Normal hook, run each time a new outgoing message is initialized.
443 It is run after the headers have been inserted and before
444 the signature is inserted."
445 :group 'message-various
448 (defcustom message-mode-hook nil
449 "Hook run in message mode buffers."
450 :group 'message-various
453 (defcustom message-header-hook nil
454 "Hook run in a message mode buffer narrowed to the headers."
455 :group 'message-various
458 (defcustom message-header-setup-hook nil
459 "Hook called narrowed to the headers when setting up a message buffer."
460 :group 'message-various
464 (defcustom message-citation-line-function 'message-insert-citation-line
465 "*Function called to insert the \"Whomever writes:\" line."
467 :group 'message-insertion)
470 (defcustom message-yank-prefix "> "
471 "*Prefix inserted on the lines of yanked messages."
473 :group 'message-insertion)
475 (defcustom message-indentation-spaces 3
476 "*Number of spaces to insert at the beginning of each cited line.
477 Used by `message-yank-original' via `message-yank-cite'."
478 :group 'message-insertion
482 (defcustom message-cite-function 'message-cite-original
483 "*Function for citing an original message.
484 Predefined functions include `message-cite-original' and
485 `message-cite-original-without-signature'.
486 Note that `message-cite-original' uses `mail-citation-hook' if that is non-nil."
487 :type '(radio (function-item message-cite-original)
488 (function-item message-cite-original-without-signature)
489 (function-item sc-cite-original)
490 (function :tag "Other"))
491 :group 'message-insertion)
494 (defcustom message-indent-citation-function 'message-indent-citation
495 "*Function for modifying a citation just inserted in the mail buffer.
496 This can also be a list of functions. Each function can find the
497 citation between (point) and (mark t). And each function should leave
498 point and mark around the citation text as modified."
500 :group 'message-insertion)
502 (defvar message-abbrevs-loaded nil)
505 (defcustom message-signature t
506 "*String to be inserted at the end of the message buffer.
507 If t, the `message-signature-file' file will be inserted instead.
508 If a function, the result from the function will be used instead.
509 If a form, the result from the form will be used instead."
511 :group 'message-insertion)
514 (defcustom message-signature-file "~/.signature"
515 "*File containing the text inserted at end of message buffer."
517 :group 'message-insertion)
519 (defcustom message-distribution-function nil
520 "*Function called to return a Distribution header."
522 :group 'message-headers
525 (defcustom message-expires 14
526 "Number of days before your article expires."
528 :group 'message-headers
529 :link '(custom-manual "(message)News Headers")
532 (defcustom message-user-path nil
533 "If nil, use the NNTP server name in the Path header.
534 If stringp, use this; if non-nil, use no host name (user name only)."
536 :group 'message-headers
537 :link '(custom-manual "(message)News Headers")
538 :type '(choice (const :tag "nntp" nil)
540 (sexp :tag "none" :format "%t" t)))
542 (defvar message-reply-buffer nil)
543 (defvar message-reply-headers nil)
544 (defvar message-newsreader nil)
545 (defvar message-mailer nil)
546 (defvar message-sent-message-via nil)
547 (defvar message-checksum nil)
548 (defvar message-send-actions nil
549 "A list of actions to be performed upon successful sending of a message.")
550 (defvar message-exit-actions nil
551 "A list of actions to be performed upon exiting after sending a message.")
552 (defvar message-kill-actions nil
553 "A list of actions to be performed before killing a message buffer.")
554 (defvar message-postpone-actions nil
555 "A list of actions to be performed after postponing a message.")
557 (define-widget 'message-header-lines 'text
558 "All header lines must be LFD terminated."
561 :error "All header lines must be newline terminated")
563 (defcustom message-default-headers ""
564 "*A string containing header lines to be inserted in outgoing messages.
565 It is inserted before you edit the message, so you can edit or delete
567 :group 'message-headers
568 :type 'message-header-lines)
570 (defcustom message-default-mail-headers ""
571 "*A string of header lines to be inserted in outgoing mails."
572 :group 'message-headers
574 :type 'message-header-lines)
576 (defcustom message-default-news-headers ""
577 "*A string of header lines to be inserted in outgoing news
579 :group 'message-headers
581 :type 'message-header-lines)
583 ;; Note: could use /usr/ucb/mail instead of sendmail;
584 ;; options -t, and -v if not interactive.
585 (defcustom message-mailer-swallows-blank-line
586 (if (and (string-match "sparc-sun-sunos\\(\\'\\|[^5]\\)"
587 system-configuration)
588 (file-readable-p "/etc/sendmail.cf")
589 (let ((buffer (get-buffer-create " *temp*")))
593 (insert-file-contents "/etc/sendmail.cf")
594 (goto-char (point-min))
595 (let ((case-fold-search nil))
596 (re-search-forward "^OR\\>" nil t)))
597 (kill-buffer buffer))))
598 ;; According to RFC822, "The field-name must be composed of printable
599 ;; ASCII characters (i. e., characters that have decimal values between
600 ;; 33 and 126, except colon)", i. e., any chars except ctl chars,
602 '(looking-at "[ \t]\\|[][!\"#$%&'()*+,-./0-9;<=>?@A-Z\\\\^_`a-z{|}~]+:"))
603 "*Set this non-nil if the system's mailer runs the header and body together.
604 \(This problem exists on Sunos 4 when sendmail is run in remote mode.)
605 The value should be an expression to test whether the problem will
607 :group 'message-sending
610 ;; Ignore errors in case this is used in Emacs 19.
611 ;; Don't use ignore-errors because this is copied into loaddefs.el.
614 (define-mail-user-agent 'message-user-agent
615 'message-mail 'message-send-and-exit
616 'message-kill-buffer 'message-send-hook))
618 (defvar message-mh-deletable-headers '(Message-ID Date Lines Sender)
619 "If non-nil, delete the deletable headers before feeding to mh.")
621 (defvar message-send-method-alist
622 '((news message-news-p message-send-via-news)
623 (mail message-mail-p message-send-via-mail))
624 "Alist of ways to send outgoing messages.
625 Each element has the form
627 \(TYPE PREDICATE FUNCTION)
629 where TYPE is a symbol that names the method; PREDICATE is a function
630 called without any parameters to determine whether the message is
631 a message of type TYPE; and FUNCTION is a function to be called if
632 PREDICATE returns non-nil. FUNCTION is called with one parameter --
635 (defvar message-mail-alias-type 'abbrev
636 "*What alias expansion type to use in Message buffers.
637 The default is `abbrev', which uses mailabbrev. nil switches
640 (defcustom message-auto-save-directory
641 (nnheader-concat message-directory "drafts/")
642 "*Directory where Message auto-saves buffers if Gnus isn't running.
643 If nil, Message won't auto-save."
644 :group 'message-buffers
647 (defcustom message-buffer-naming-style 'unique
648 "*The way new message buffers are named.
649 Valid valued are `unique' and `unsent'."
650 :group 'message-buffers
651 :type '(choice (const :tag "unique" unique)
652 (const :tag "unsent" unsent)))
654 (defcustom message-default-charset nil
655 "Default charset used in non-MULE XEmacsen."
659 (defcustom message-dont-reply-to-names rmail-dont-reply-to-names
660 "*A regexp specifying names to prune when doing wide replies.
661 A value of nil means exclude your own name only."
663 :type '(choice (const :tag "Yourself" nil)
666 ;;; Internal variables.
667 ;;; Well, not really internal.
669 (defvar message-mode-syntax-table
670 (let ((table (copy-syntax-table text-mode-syntax-table)))
671 (modify-syntax-entry ?% ". " table)
672 (modify-syntax-entry ?> ". " table)
673 (modify-syntax-entry ?< ". " table)
675 "Syntax table used while in Message mode.")
677 (defvar message-mode-abbrev-table text-mode-abbrev-table
678 "Abbrev table used in Message mode buffers.
679 Defaults to `text-mode-abbrev-table'.")
680 (defgroup message-headers nil
682 :link '(custom-manual "(message)Variables")
685 (defface message-header-to-face
688 (:foreground "green2" :bold t))
691 (:foreground "MidnightBlue" :bold t))
693 (:bold t :italic t)))
694 "Face used for displaying From headers."
695 :group 'message-faces)
697 (defface message-header-cc-face
700 (:foreground "green4" :bold t))
703 (:foreground "MidnightBlue"))
706 "Face used for displaying Cc headers."
707 :group 'message-faces)
709 (defface message-header-subject-face
712 (:foreground "green3"))
715 (:foreground "navy blue" :bold t))
718 "Face used for displaying subject headers."
719 :group 'message-faces)
721 (defface message-header-newsgroups-face
724 (:foreground "yellow" :bold t :italic t))
727 (:foreground "blue4" :bold t :italic t))
729 (:bold t :italic t)))
730 "Face used for displaying newsgroups headers."