;;; message.el --- composing mail and news messages
;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
-;; 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+;; 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
;; Keywords: mail, news
;; This file is part of GNU Emacs.
-;; GNU Emacs is free software; you can redistribute it and/or modify
+;; GNU Emacs is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING. If not, write to the
-;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
(eval-when-compile
(require 'cl))
-(require 'hashcash)
-(require 'canlock)
(require 'mailheader)
(require 'gmm-utils)
-(require 'nnheader)
+(require 'mail-utils)
+;; Only for the trivial macros mail-header-from, mail-header-date
+;; mail-header-references, mail-header-subject, mail-header-id
+(eval-when-compile (require 'nnheader))
;; This is apparently necessary even though things are autoloaded.
;; Because we dynamically bind mail-abbrev-mode-regexp, we'd better
;; require mailabbrev here.
(require 'mail-parse)
(require 'mml)
(require 'rfc822)
-(require 'ecomplete)
(autoload 'mailclient-send-it "mailclient") ;; Emacs 22 or contrib/
Otherwise, most addresses look like `angles', but they look like
`parens' if `angles' would need quoting and `parens' would not."
+ :version "23.2"
:type '(choice (const :tag "simple" nil)
(const parens)
(const angles)
;;; End of variables adopted from `message-utils.el'.
-(defcustom message-signature-separator "^-- *$"
- "Regexp matching the signature separator."
- :type 'regexp
+(defcustom message-signature-separator "^-- $"
+ "Regexp matching the signature separator.
+This variable is used to strip off the signature from quoted text
+when `message-cite-function' is
+`message-cite-original-without-signature'. Most useful values
+are \"^-- $\" (strict) and \"^-- *$\" (loose; allow missing
+whitespace)."
+ :type '(choice (const :tag "strict" "^-- $")
+ (const :tag "loose" "^-- *$")
+ regexp)
+ :version "22.3" ;; Gnus 5.10.12 (changed default)
:link '(custom-manual "(message)Various Message Variables")
:group 'message-various)
(defcustom message-interactive t
"Non-nil means when sending a message wait for and display errors.
-nil means let mailer mail back a message to report errors."
+A value of nil means let mailer mail back a message to report errors."
+ :version "23.2"
+ :group 'message-sending
+ :group 'message-mail
+ :link '(custom-manual "(message)Sending Variables")
+ :type 'boolean)
+
+(defcustom message-confirm-send nil
+ "When non-nil, ask for confirmation when sending a message."
:group 'message-sending
:group 'message-mail
+ :version "23.1" ;; No Gnus
:link '(custom-manual "(message)Sending Variables")
:type 'boolean)
:link '(custom-manual "(message)Forwarding")
:type 'boolean)
-(defcustom message-ignored-resent-headers "^Return-receipt\\|^X-Gnus\\|^Gnus-Warning:\\|^>?From "
+(defcustom message-ignored-resent-headers
+ ;; `Delivered-To' needs to be removed because some mailers use it to
+ ;; detect loops, so if you resend a message to an address that ultimately
+ ;; comes back to you (e.g. a mailing-list to which you subscribe, in which
+ ;; case you may be removed from the list on the grounds that mail to you
+ ;; bounced with a "mailing loop" error).
+ "^Return-receipt\\|^X-Gnus\\|^Gnus-Warning:\\|^>?From \\|^Delivered-To:"
"*All headers that match this regexp will be deleted when resending a message."
:group 'message-interface
:link '(custom-manual "(message)Resending")
non-word-constituents
"]\\)+>+\\|[ \t]*[]>|}]\\)+"))))
"*Regexp matching the longest possible citation prefix on a line."
- :version "22.1"
+ :version "23.2"
:group 'message-insertion
:link '(custom-manual "(message)Insertion Variables")
:type 'regexp
:link '(custom-manual "(message)Canceling News")
:type 'string)
-(defvar smtpmail-default-smtp-server)
-
(defun message-send-mail-function ()
"Return suitable value for the variable `message-send-mail-function'."
(cond ((and (require 'sendmail)
(executable-find sendmail-program))
'message-send-mail-with-sendmail)
((and (locate-library "smtpmail")
- (require 'smtpmail)
+ (boundp 'smtpmail-default-smtp-server)
smtpmail-default-smtp-server)
'message-smtpmail-send-it)
((locate-library "mailclient")
'message-send-mail-with-mailclient)
(t
- (lambda ()
- (error "Don't know how to send mail. Please customize `message-send-mail-function'")))))
+ (error "Don't know how to send mail. Please customize `message-send-mail-function'"))))
;; Useful to set in site-init.el
-(defcustom message-send-mail-function (message-send-mail-function)
+(defcustom message-send-mail-function
+ (cond ((eq send-mail-function 'smtpmail-send-it) 'message-smtpmail-send-it)
+ ((eq send-mail-function 'feedmail-send-it) 'feedmail-send-it)
+ ((eq send-mail-function 'mailclient-send-it)
+ 'message-send-mail-with-mailclient)
+ (t (message-send-mail-function)))
"Function to call to send the current buffer as mail.
The headers should be delimited by a line whose contents match the
variable `mail-header-separator'.
:tag "Use Mailclient package")
(function :tag "Other"))
:group 'message-sending
- :version "23.1" ;; No Gnus
+ :version "23.2"
:initialize 'custom-initialize-default
:link '(custom-manual "(message)Mail Variables")
:group 'message-mail)
"*Envelope-from when sending mail with sendmail.
If this is nil, use `user-mail-address'. If it is the symbol
`header', use the From: header of the message."
- :version "22.1"
+ :version "23.2"
:type '(choice (string :tag "From name")
(const :tag "Use From: header from message" header)
(const :tag "Use `user-mail-address'" nil))
(defcustom message-qmail-inject-args nil
"Arguments passed to qmail-inject programs.
-This should be a list of strings, one string for each argument. It
-may also be a function.
+This should be a list of strings, one string for each argument.
+It may also be a function.
For e.g., if you wish to set the envelope sender address so that bounces
go to the right place or to deal with listserv's usage of that address, you
"*Prefix inserted on the lines of yanked messages.
Fix `message-cite-prefix-regexp' if it is set to an abnormal value.
See also `message-yank-cited-prefix' and `message-yank-empty-prefix'."
+ :version "23.2"
:type 'string
:link '(custom-manual "(message)Insertion Variables")
:group 'message-insertion)
(defcustom message-indentation-spaces 3
"*Number of spaces to insert at the beginning of each cited line.
Used by `message-yank-original' via `message-yank-cite'."
+ :version "23.2"
:group 'message-insertion
:link '(custom-manual "(message)Insertion Variables")
:type 'integer)
-(defcustom message-cite-function 'message-cite-original
+(defcustom message-cite-function 'message-cite-original-without-signature
"*Function for citing an original message.
Predefined functions include `message-cite-original' and
`message-cite-original-without-signature'.
(function-item sc-cite-original)
(function :tag "Other"))
:link '(custom-manual "(message)Insertion Variables")
+ :version "22.3" ;; Gnus 5.10.12 (changed default)
:group 'message-insertion)
(defcustom message-indent-citation-function 'message-indent-citation
If t, the `message-signature-file' file will be inserted instead.
If a function, the result from the function will be used instead.
If a form, the result from the form will be used instead."
+ :version "23.2"
:type 'sexp
:link '(custom-manual "(message)Insertion Variables")
:group 'message-insertion)
If nil, don't insert a signature.
If a path is specified, the value of `message-signature-directory' is ignored,
even if set."
+ :version "23.2"
:type '(choice file (const :tags "None" nil))
:link '(custom-manual "(message)Insertion Variables")
:group 'message-insertion)
(string :tag "name")
(sexp :tag "none" :format "%t" t)))
+;; This can be the name of a buffer, or a cons cell (FUNCTION . ARGS)
+;; for yanking the original buffer.
(defvar message-reply-buffer nil)
(defvar message-reply-headers nil
"The headers of the current replied article.
"*A string containing header lines to be inserted in outgoing messages.
It is inserted before you edit the message, so you can edit or delete
these lines."
+ :version "23.2"
:group 'message-headers
:link '(custom-manual "(message)Message Headers")
:type 'message-header-lines)
-(defcustom message-default-mail-headers ""
+(defcustom message-default-mail-headers
+ ;; Ease the transition from mail-mode to message-mode. See bugs#4431, 5555.
+ (concat (if (and (boundp 'mail-default-reply-to)
+ (stringp mail-default-reply-to))
+ (format "Reply-to: %s\n" mail-default-reply-to))
+ (if (and (boundp 'mail-self-blind)
+ mail-self-blind)
+ (format "BCC: %s\n" user-mail-address))
+ (if (and (boundp 'mail-archive-file-name)
+ (stringp mail-archive-file-name))
+ (format "FCC: %s\n" mail-archive-file-name))
+ ;; Use the value of `mail-default-headers' if available.
+ ;; Note: as for Emacs 21, XEmacs 21.4 and 21.5, it is
+ ;; unavailable unless sendmail.el is loaded.
+ (if (boundp 'mail-default-headers)
+ mail-default-headers))
"*A string of header lines to be inserted in outgoing mails."
+ :version "23.2"
:group 'message-headers
:group 'message-mail
:link '(custom-manual "(message)Mail Headers")
:type '(repeat function))
(defcustom message-auto-save-directory
- (file-name-as-directory (nnheader-concat message-directory "drafts"))
+ (file-name-as-directory (expand-file-name "drafts" message-directory))
"*Directory where Message auto-saves buffers if Gnus isn't running.
If nil, Message won't auto-save."
:group 'message-buffers
:group 'message-faces)
;; backward-compatibility alias
(put 'message-header-to-face 'face-alias 'message-header-to)
+(put 'message-header-to-face 'obsolete-face "22.1")
(defface message-header-cc
'((((class color)
:group 'message-faces)
;; backward-compatibility alias
(put 'message-header-cc-face 'face-alias 'message-header-cc)
+(put 'message-header-cc-face 'obsolete-face "22.1")
(defface message-header-subject
'((((class color)
:group 'message-faces)
;; backward-compatibility alias
(put 'message-header-subject-face 'face-alias 'message-header-subject)
+(put 'message-header-subject-face 'obsolete-face "22.1")
(defface message-header-newsgroups
'((((class color)
:group 'message-faces)
;; backward-compatibility alias
(put 'message-header-newsgroups-face 'face-alias 'message-header-newsgroups)
+(put 'message-header-newsgroups-face 'obsolete-face "22.1")
(defface message-header-other
'((((class color)
:group 'message-faces)
;; backward-compatibility alias
(put 'message-header-other-face 'face-alias 'message-header-other)
+(put 'message-header-other-face 'obsolete-face "22.1")
(defface message-header-name
'((((class color)
:group 'message-faces)
;; backward-compatibility alias
(put 'message-header-name-face 'face-alias 'message-header-name)
+(put 'message-header-name-face 'obsolete-face "22.1")
(defface message-header-xheader
'((((class color)
:group 'message-faces)
;; backward-compatibility alias
(put 'message-header-xheader-face 'face-alias 'message-header-xheader)
+(put 'message-header-xheader-face 'obsolete-face "22.1")
(defface message-separator
'((((class color)
:group 'message-faces)
;; backward-compatibility alias
(put 'message-separator-face 'face-alias 'message-separator)
+(put 'message-separator-face 'obsolete-face "22.1")
(defface message-cited-text
'((((class color)
:group 'message-faces)
;; backward-compatibility alias
(put 'message-cited-text-face 'face-alias 'message-cited-text)
+(put 'message-cited-text-face 'obsolete-face "22.1")
(defface message-mml
'((((class color)
:group 'message-faces)
;; backward-compatibility alias
(put 'message-mml-face 'face-alias 'message-mml)
+(put 'message-mml-face 'obsolete-face "22.1")
(defun message-font-lock-make-header-matcher (regexp)
(let ((form
and Emacs, you may use `iso-2022-7bit' for this value at your own risk.
Note that the coding-system `iso-2022-7bit' isn't suitable to all data.")
-(defcustom message-send-mail-partially-limit 1000000
+(defcustom message-send-mail-partially-limit nil
"The limitation of messages sent as message/partial.
The lower bound of message size in characters, beyond which the message
should be sent in several parts. If it is nil, the size is unlimited."
(defvar message-mime-part nil)
(defvar message-posting-charset nil)
(defvar message-inserted-headers nil)
+(defvar message-inhibit-ecomplete nil)
;; Byte-compiler warning
(defvar gnus-active-hashtb)
:group 'message-headers
:type 'regexp)
-(eval-and-compile
- (autoload 'gnus-alive-p "gnus-util")
- (autoload 'gnus-delay-article "gnus-delay")
- (autoload 'gnus-extract-address-components "gnus-util")
- (autoload 'gnus-find-method-for-group "gnus")
- (autoload 'gnus-group-decoded-name "gnus-group")
- (autoload 'gnus-group-name-charset "gnus-group")
- (autoload 'gnus-group-name-decode "gnus-group")
- (autoload 'gnus-groups-from-server "gnus")
- (autoload 'gnus-make-local-hook "gnus-util")
- (autoload 'gnus-open-server "gnus-int")
- (autoload 'gnus-output-to-mail "gnus-util")
- (autoload 'gnus-output-to-rmail "gnus-util")
- (autoload 'gnus-request-post "gnus-int")
- (autoload 'gnus-select-frame-set-input-focus "gnus-util")
- (autoload 'gnus-server-string "gnus")
- (autoload 'idna-to-ascii "idna")
- (autoload 'message-setup-toolbar "messagexmas")
- (autoload 'mh-new-draft-name "mh-comp")
- (autoload 'mh-send-letter "mh-comp")
- (autoload 'nndraft-request-associate-buffer "nndraft")
- (autoload 'nndraft-request-expire-articles "nndraft")
- (autoload 'nnvirtual-find-group-art "nnvirtual")
- (autoload 'rmail-dont-reply-to "mail-utils")
- (autoload 'rmail-msg-is-pruned "rmail")
- (autoload 'rmail-msg-restore-non-pruned-header "rmail")
- (autoload 'rmail-output "rmailout"))
+(autoload 'gnus-alive-p "gnus-util")
+(autoload 'gnus-delay-article "gnus-delay")
+(autoload 'gnus-extract-address-components "gnus-util")
+(autoload 'gnus-find-method-for-group "gnus")
+(autoload 'gnus-group-decoded-name "gnus-group")
+(autoload 'gnus-group-name-charset "gnus-group")
+(autoload 'gnus-group-name-decode "gnus-group")
+(autoload 'gnus-groups-from-server "gnus")
+(autoload 'gnus-make-local-hook "gnus-util")
+(autoload 'gnus-open-server "gnus-int")
+(autoload 'gnus-output-to-mail "gnus-util")
+(autoload 'gnus-output-to-rmail "gnus-util")
+(autoload 'gnus-request-post "gnus-int")
+(autoload 'gnus-select-frame-set-input-focus "gnus-util")
+(autoload 'gnus-server-string "gnus")
+(autoload 'idna-to-ascii "idna")
+(autoload 'message-setup-toolbar "messagexmas")
+(autoload 'mh-new-draft-name "mh-comp")
+(autoload 'mh-send-letter "mh-comp")
+(autoload 'nndraft-request-associate-buffer "nndraft")
+(autoload 'nndraft-request-expire-articles "nndraft")
+(autoload 'nnvirtual-find-group-art "nnvirtual")
+(autoload 'rmail-dont-reply-to "mail-utils")
+(autoload 'rmail-msg-is-pruned "rmail")
+(autoload 'rmail-output "rmailout")
\f
(setq paren nil))))
(nreverse elems)))))
+(autoload 'nnheader-insert-file-contents "nnheader")
+
(defun message-mail-file-mbox-p (file)
"Say whether FILE looks like a Unix mbox file."
(when (and (file-exists-p file)
(defmacro message-with-reply-buffer (&rest forms)
"Evaluate FORMS in the reply buffer, if it exists."
- `(when (and message-reply-buffer
+ `(when (and (bufferp message-reply-buffer)
(buffer-name message-reply-buffer))
(with-current-buffer message-reply-buffer
,@forms)))
(point-max)))
(goto-char (point-min)))
+;; FIXME: clarify diffference: message-narrow-to-head,
+;; message-narrow-to-headers-or-head, message-narrow-to-headers
(defun message-narrow-to-head ()
"Narrow the buffer to the head of the message.
Point is left at the beginning of the narrowed-to region."
(autoload 'Info-goto-node "info")
+(defvar mml2015-use)
(defun message-info (&optional arg)
"Display the Message manual.
manual. With two \\[universal-argument]'s, display the EasyPG or
PGG manual, depending on the value of `mml2015-use'."
(interactive "p")
+ ;; Don't use `info' because support for `(filename)nodename' is not
+ ;; available in XEmacs < 21.5.12.
(Info-goto-node (format "(%s)Top"
- (cond ((eq arg 16) mml2015-use)
+ (cond ((eq arg 16)
+ (require 'mml2015)
+ mml2015-use)
((eq arg 4) 'emacs-mime)
- ((and (not (booleanp arg))
+ ;; `booleanp' only available in Emacs 22+
+ ((and (not (memq arg '(nil t)))
(symbolp arg))
arg)
(t
;;; Forbidden properties
;;
;; We use `after-change-functions' to keep special text properties
-;; that interfer with the normal function of message mode out of the
+;; that interfere with the normal function of message mode out of the
;; buffer.
(defcustom message-strip-special-text-properties t
(inhibit-read-only t))
(remove-text-properties begin end message-forbidden-properties))))
+(autoload 'ecomplete-setup "ecomplete") ;; for Emacs <23.
+
;;;###autoload
(define-derived-mode message-mode text-mode "Message"
"Major mode for editing mail and news to be sent.
"Widen the reply to include maximum recipients."
(interactive)
(let ((follow-to
- (and message-reply-buffer
+ (and (bufferp message-reply-buffer)
(buffer-name message-reply-buffer)
(with-current-buffer message-reply-buffer
(message-get-reply-headers t)))))
(defun message-kill-to-signature (&optional arg)
"Kill all text up to the signature.
-If a numberic argument or prefix arg is given, leave that number
+If a numeric argument or prefix arg is given, leave that number
of lines before the signature intact."
(interactive "P")
(save-excursion
;; if message-signature-file contains a path.
(not (file-name-directory
message-signature-file)))
- (nnheader-concat message-signature-directory
- message-signature-file)
+ (expand-file-name message-signature-file
+ message-signature-directory)
message-signature-file))
(file-exists-p signature-file))))
(when signature
(point-max)))
(delete-region (message-goto-body) (point-max)))
(set (make-local-variable 'message-cite-reply-above) nil)))
- (delete-windows-on message-reply-buffer t)
+ (if (bufferp message-reply-buffer)
+ (delete-windows-on message-reply-buffer t))
(push-mark (save-excursion
- (insert-buffer-substring message-reply-buffer)
+ (cond
+ ((bufferp message-reply-buffer)
+ (insert-buffer-substring message-reply-buffer))
+ ((and (consp message-reply-buffer)
+ (functionp (car message-reply-buffer)))
+ (apply (car message-reply-buffer)
+ (cdr message-reply-buffer))))
(unless (bolp)
(insert ?\n))
(point)))
(>= i ?a)))
(push i lst)
(push (condition-case nil
- (progn (format-time-string (format "%%%c" i)
- replydate))
- (format ">%c<" i))
+ (format-time-string (format "%%%c" i) replydate)
+ (error (format ">%c<" i)))
lst))
(setq i (1+ i)))
(reverse lst)))
(put-text-property (point-min) (point-max) 'read-only nil))
(message-fix-before-sending)
(run-hooks 'message-send-hook)
+ (when message-confirm-send
+ (or (y-or-n-p "Send message? ")
+ (keyboard-quit)))
(message message-sending-message)
(let ((alist message-send-method-alist)
(success t)
(run-hooks 'message-sent-hook))
(message "Sending...done")
;; Do ecomplete address snarfing.
- (when (message-mail-alias-type-p 'ecomplete)
+ (when (and (message-mail-alias-type-p 'ecomplete)
+ (not message-inhibit-ecomplete))
(message-put-addresses-in-ecomplete))
;; Mark the buffer as unmodified and delete auto-save.
(set-buffer-modified-p nil)
(setq start next)))
(nreverse regions)))
-(defcustom message-bogus-address-regexp nil ;; "noreply\\|nospam\\|invalid"
- "Regexp of potentially bogus mail addresses."
+(defcustom message-bogus-addresses
+ ;; '("noreply" "nospam" "invalid")
+ '("noreply" "nospam" "invalid" "@@" "[^[:ascii:]].*@" "[ \t]")
+ "List of regexps of potentially bogus mail addresses.
+See `message-check-recipients' how to setup checking.
+
+This list should make it possible to catch typos or warn about
+spam-trap addresses. It doesn't aim to verify strict RFC
+conformance."
:version "23.1" ;; No Gnus
:group 'message-headers
- :type 'regexp)
+ :type '(choice
+ (const :tag "None" nil)
+ (list
+ (set :inline t
+ (const "noreply")
+ (const "nospam")
+ (const "invalid")
+ (const :tag "duplicate @" "@@")
+ (const :tag "non-ascii local part" "[^[:ascii:]].*@")
+ ;; Already caught by `message-valid-fqdn-regexp'
+ ;; (const :tag "`_' in domain part" "@.*_")
+ (const :tag "whitespace" "[ \t]"))
+ (repeat :inline t
+ :tag "Other"
+ (regexp)))))
(defun message-fix-before-sending ()
"Do various things to make the message nice before sending it."
(and (mm-multibyte-p)
(memq (char-charset char)
'(eight-bit-control eight-bit-graphic
+ ;; Emacs 23, Bug#1770:
+ eight-bit
control-1))
(not (get-text-property
(point) 'untranslated-utf-8))))
(or (< (mm-char-int char) 128)
(and (mm-multibyte-p)
;; FIXME: Wrong for Emacs 23 (unicode) and for
- ;; things like undecable utf-8. Should at least
- ;; use find-coding-systems-region.
+ ;; things like undecodable utf-8 (in Emacs 21?).
+ ;; Should at least use find-coding-systems-region.
+ ;; -- fx
(memq (char-charset char)
'(eight-bit-control eight-bit-graphic
+ ;; Emacs 23, Bug#1770:
+ eight-bit
control-1))
(not (get-text-property
(point) 'untranslated-utf-8)))))
(forward-char)
(skip-chars-forward mm-7bit-chars)))))
(message-check 'bogus-recipient
- ;; Warn before composing or sending a mail to an invalid address.
+ ;; Warn before sending a mail to an invalid address.
(message-check-recipients)))
(defun message-bogus-recipient-p (recipients)
RECIPIENTS is a mail header. Return a list of potentially bogus
addresses. If none is found, return nil.
-An addresses might be bogus if the domain part is not fully
-qualified, see `message-valid-fqdn-regexp', or if it matches
-`message-bogus-address-regexp'."
+An address might be bogus if the domain part is not fully
+qualified, see `message-valid-fqdn-regexp', or if there's a
+matching entry in `message-bogus-addresses'."
;; FIXME: How about "foo@subdomain", when the MTA adds ".domain.tld"?
(let (found)
(mapc (lambda (address)
(string-match
(concat ".@.*\\("
message-valid-fqdn-regexp "\\)\\'") address)))
- (and (stringp message-bogus-address-regexp)
- (string-match message-bogus-address-regexp address)))
- (push address found)))
+ (and message-bogus-addresses
+ (let ((re
+ (if (listp message-bogus-addresses)
+ (mapconcat 'identity
+ message-bogus-addresses
+ "\\|")
+ message-bogus-addresses)))
+ (string-match re address))))
+ (push address found)))
;;
(mail-extract-address-components recipients t))
found))
(not (y-or-n-p
(format
"Address `%s' might be bogus. Continue? " bog)))
- (error "Bogus address."))))))))
+ (error "Bogus address"))))))))
+
+(custom-add-option 'message-setup-hook 'message-check-recipients)
(defun message-add-action (action &rest types)
"Add ACTION to be performed when doing an exit of type TYPES."
(end-of-line)
(insert (format " (%d/%d)" n total))
(widen)
- (mm-with-unibyte-current-buffer
- (funcall (or message-send-mail-real-function
- message-send-mail-function))))
+ (funcall (or message-send-mail-real-function
+ message-send-mail-function)))
(setq n (+ n 1))
(setq p (pop plist))
(erase-buffer)))
(kill-buffer tembuf))))
+(declare-function hashcash-wait-async "hashcash" (&optional buffer))
+
(defun message-send-mail (&optional arg)
(require 'mail-utils)
(let* ((tembuf (message-generate-new-buffer-clone-locals " message temp"))
(news (message-news-p))
(mailbuf (current-buffer))
(message-this-is-mail t)
+ ;; gnus-setup-posting-charset is autoloaded in mml.el (FIXME
+ ;; maybe it should not be), which this file requires. Hence
+ ;; the fboundp test is always true. Loading it from gnus-msg
+ ;; loads many Gnus files (Bug#5642). If
+ ;; gnus-group-posting-charset-alist hasn't been customized,
+ ;; this is just going to return nil anyway. FIXME it would
+ ;; be good to improve this further, because even if g-g-p-c-a
+ ;; has been customized, that is likely to just be for news.
+ ;; Eg either move the definition from gnus-msg, or separate out
+ ;; the mail and news parts.
(message-posting-charset
- (if (fboundp 'gnus-setup-posting-charset)
+ (if (and (fboundp 'gnus-setup-posting-charset)
+ (boundp 'gnus-group-posting-charset-alist))
(gnus-setup-posting-charset nil)
message-posting-charset))
(headers message-required-mail-headers))
(when (and message-generate-hashcash
(not (eq message-generate-hashcash 'opportunistic)))
(message "Generating hashcash...")
+ (require 'hashcash)
;; Wait for calculations already started to finish...
(hashcash-wait-async)
;; ...and do calculations not already done. mail-add-payment
(message-fetch-field
"content-transfer-encoding")))))))
(message-insert-courtesy-copy))
+ ;; Let's make sure we encoded all the body.
+ (assert (save-excursion
+ (goto-char (point-min))
+ (not (re-search-forward "[^\000-\377]" nil t))))
+ (mm-disable-multibyte)
(if (or (not message-send-mail-partially-limit)
(< (buffer-size) message-send-mail-partially-limit)
(not (message-y-or-n-p
If you always want Gnus to send messages in one piece, set
`message-send-mail-partially-limit' to nil.
")))
- (mm-with-unibyte-current-buffer
+ (progn
(message "Sending via mail...")
(funcall (or message-send-mail-real-function
message-send-mail-function)))
(defun message-send-mail-with-sendmail ()
"Send off the prepared buffer with sendmail."
+ (require 'sendmail)
(let ((errbuf (if message-interactive
(message-generate-new-buffer-clone-locals
" sendmail errors")
;; since some systems have broken sendmails.
;; But some systems are more broken with -f, so
;; we'll let users override this.
- (if (null message-sendmail-f-is-evil)
- (list "-f" (message-sendmail-envelope-from)))
+ (and (null message-sendmail-f-is-evil)
+ (list "-f" (message-sendmail-envelope-from)))
;; These mean "report errors by mail"
;; and "deliver in background".
(if (null message-interactive) '("-oem" "-odb"))
(list resend-to-addresses)
'("-t"))))))
(unless (or (null cpr) (and (numberp cpr) (zerop cpr)))
+ (if errbuf (pop-to-buffer errbuf))
(error "Sending...failed with exit value %d" cpr)))
(when message-interactive
(with-current-buffer errbuf
(apply
'call-process-region (point-min) (point-max)
message-qmail-inject-program nil nil nil
- ;; qmail-inject's default behaviour is to look for addresses on the
+ ;; qmail-inject's default behavior is to look for addresses on the
;; command line; if there're none, it scans the headers.
;; yes, it does The Right Thing w.r.t. Resent-To and it's kin.
;;
(defun message-smtpmail-send-it ()
"Send the prepared message buffer with `smtpmail-send-it'.
-This only differs from `smtpmail-send-it' that this command evaluates
-`message-send-mail-hook' just before sending a message. It is useful
-if your ISP requires the POP-before-SMTP authentication. See the Gnus
-manual for details."
+The only difference from `smtpmail-send-it' is that this command
+evaluates `message-send-mail-hook' just before sending a message.
+It is useful if your ISP requires the POP-before-SMTP
+authentication. See the Gnus manual for details."
(run-hooks 'message-send-mail-hook)
(smtpmail-send-it))
(defun message-send-mail-with-mailclient ()
"Send the prepared message buffer with `mailclient-send-it'.
-This only differs from `smtpmail-send-it' that this command evaluates
-`message-send-mail-hook' just before sending a message."
+The only difference from `mailclient-send-it' is that this
+command evaluates `message-send-mail-hook' just before sending a message."
(run-hooks 'message-send-mail-hook)
(mailclient-send-it))
(prin1-to-string (recent-keys))
(prin1-to-string (garbage-collect))))))
+(defvar canlock-password)
+(defvar canlock-password-for-verify)
+
(defun message-canlock-password ()
"The password used by message for cancel locks.
This is the value of `canlock-password', if that option is non-nil.
Otherwise, generate and save a value for `canlock-password' first."
+ (require 'canlock)
(unless canlock-password
(customize-save-variable 'canlock-password (message-canlock-generate))
(setq canlock-password-for-verify canlock-password))
(message-canlock-password)
(canlock-insert-header)))
+(autoload 'nnheader-get-report "nnheader")
+
+(declare-function gnus-setup-posting-charset "gnus-msg" (group))
+
(defun message-send-news (&optional arg)
+ (require 'gnus-msg)
(let* ((tembuf (message-generate-new-buffer-clone-locals " *message temp*"))
(case-fold-search nil)
(method (if (functionp message-post-method)
"Denied posting -- the From looks strange: \"%s\"." from)
nil)
((let ((addresses (rfc822-addresses from)))
- (while (and addresses
+ ;; `rfc822-addresses' returns a string if parsing fails.
+ (while (and (consp addresses)
(not (eq (string-to-char (car addresses)) ?\()))
(setq addresses (cdr addresses)))
addresses)
nil)))
;; Check the length of the signature.
(message-check 'signature
- (goto-char (point-max))
- (if (> (count-lines (point) (point-max)) 5)
- (y-or-n-p
- (format
- "Your .sig is %d lines; it should be max 4. Really post? "
- (1- (count-lines (point) (point-max)))))
- t))
+ (let (sig-start sig-end)
+ (goto-char (point-max))
+ (if (not (re-search-backward message-signature-separator nil t))
+ t
+ (setq sig-start (1+ (point-at-eol)))
+ (setq sig-end
+ (if (re-search-forward
+ "<#/?\\(multipart\\|part\\|external\\|mml\\)" nil t)
+ (- (point-at-bol) 1)
+ (point-max)))
+ (if (>= (count-lines sig-start sig-end) 5)
+ (if (message-gnksa-enable-p 'signature)
+ (y-or-n-p
+ (format "Signature is excessively long (%d lines). Really post? "
+ (count-lines sig-start sig-end)))
+ (message "Denied posting -- Excessive signature.")
+ nil)
+ t))))
;; Ensure that text follows last quoted portion.
(message-check 'quoting-style
(goto-char (point-max))
(if (and message-fcc-handler-function
(not (eq message-fcc-handler-function 'rmail-output)))
(funcall message-fcc-handler-function file)
+ ;; FIXME this option, rmail-output (also used if
+ ;; message-fcc-handler-function is nil) is not
+ ;; documented anywhere AFAICS. It should work in Emacs
+ ;; 23; I suspect it does not work in Emacs 22.
+ ;; FIXME I don't see the need for the two different cases here.
+ ;; mail-use-rfc822 makes no difference (in Emacs 23),and
+ ;; the third argument just controls \"Wrote file\" message.
(if (and (file-readable-p file) (mail-file-babyl-p file))
(rmail-output file 1 nil t)
(let ((mail-use-rfc822 t))
(* 25 25)))
(let ((tm (current-time)))
(concat
- (if (or (memq system-type '(ms-dos emx vax-vms))
+ (if (or (eq system-type 'ms-dos)
;; message-number-base36 doesn't handle bigints.
(floatp (user-uid)))
(let ((user (downcase (user-login-name))))
(defun message-make-references ()
"Return the References header for this message."
(when message-reply-headers
- (let ((message-id (mail-header-message-id message-reply-headers))
+ (let ((message-id (mail-header-id message-reply-headers))
(references (mail-header-references message-reply-headers)))
(if (or references message-id)
(concat (or references "") (and references " ")
(when message-reply-headers
(let ((from (mail-header-from message-reply-headers))
(date (mail-header-date message-reply-headers))
- (msg-id (mail-header-message-id message-reply-headers)))
+ (msg-id (mail-header-id message-reply-headers)))
(when from
(let ((name (mail-extract-address-components from)))
(concat
;; Quote a string containing non-ASCII characters.
;; It will make the RFC2047 encoder cause an error
;; if there are special characters.
- (let ((default-enable-multibyte-characters t))
- (with-temp-buffer
- (insert (car name))
- (goto-char (point-min))
- (while (search-forward "\"" nil t)
- (when (prog2
- (backward-char)
- (zerop (% (skip-chars-backward "\\\\") 2))
- (goto-char (match-beginning 0)))
- (insert "\\"))
- (forward-char))
- ;; Those quotes will be removed by the RFC2047 encoder.
- (concat "\"" (buffer-string) "\"")))
+ (mm-with-multibyte-buffer
+ (insert (car name))
+ (goto-char (point-min))
+ (while (search-forward "\"" nil t)
+ (when (prog2
+ (backward-char)
+ (zerop (% (skip-chars-backward "\\\\") 2))
+ (goto-char (match-beginning 0)))
+ (insert "\\"))
+ (forward-char))
+ ;; Those quotes will be removed by the RFC2047 encoder.
+ (concat "\"" (buffer-string) "\""))
(car name))
(nth 1 name))
"'s message of \""
(mapcar (lambda (rhs) (or (cadr (split-string rhs "@")) ""))
(mapcar 'downcase
(mapcar
- 'car (mail-header-parse-addresses field))))))
- (setq ace (if (string-match "\\`[[:ascii:]]+\\'" rhs)
+ 'cadr
+ (mail-extract-address-components field t))))))
+ ;; Note that `rhs' will be "" if the address does not have
+ ;; the domain part, i.e., if it is a local user's address.
+ (setq ace (if (string-match "\\`[[:ascii:]]*\\'" rhs)
rhs
(downcase (idna-to-ascii rhs))))
(when (and (not (equal rhs ace))
(when message-use-idna
(save-excursion
(save-restriction
- (message-narrow-to-head)
+ ;; `message-narrow-to-head' that recognizes only the first empty
+ ;; line as the message header separator used to be used here.
+ ;; However, since there is the "--text follows this line--" line
+ ;; normally, it failed in narrowing to the headers and potentially
+ ;; caused the IDNA encoding on lines that look like headers in
+ ;; the message body.
+ (message-narrow-to-headers-or-head)
(message-idna-to-ascii-rhs-1 "From")
(message-idna-to-ascii-rhs-1 "To")
(message-idna-to-ascii-rhs-1 "Reply-To")
(if formatter
(funcall formatter header value)
(insert header-string ": " value))
+ (push header-string message-inserted-headers)
(goto-char (message-fill-field))
;; We check whether the value was ended by a
;; newline. If not, we insert one.
(with-temp-buffer
(insert references)
(goto-char (point-min))
- ;; Cons a list of valid references.
- (while (re-search-forward "<[^>]+>" nil t)
+ ;; Cons a list of valid references. GNKSA says we must not include MIDs
+ ;; with whitespace or missing brackets (7.a "Does not propagate broken
+ ;; Message-IDs in original References").
+ (while (re-search-forward "<[^ <]+@[^ <]+>" nil t)
(push (match-string 0) refs))
(setq refs (nreverse refs)
count (length refs)))
nil
mua)))
-(defun message-setup (headers &optional replybuffer actions
+;; YANK-ACTION, if non-nil, can be a buffer or a yank action of the
+;; form (FUNCTION . ARGS).
+(defun message-setup (headers &optional yank-action actions
continue switch-function)
(let ((mua (message-mail-user-agent))
- subject to field yank-action)
+ subject to field)
(if (not (and message-this-is-mail mua))
- (message-setup-1 headers replybuffer actions)
- (if replybuffer
- (setq yank-action (list 'insert-buffer replybuffer)))
+ (message-setup-1 headers yank-action actions)
(setq headers (copy-sequence headers))
(setq field (assq 'Subject headers))
(when field
(format "%s" (car item))
(cdr item)))
headers)
- continue switch-function yank-action actions)))))
+ continue switch-function
+ (if (bufferp yank-action)
+ (list 'insert-buffer yank-action)
+ yank-action)
+ actions)))))
(defun message-headers-to-generate (headers included-headers excluded-headers)
"Return a list that includes all headers from HEADERS.
(push header result)))
(nreverse result)))
-(defun message-setup-1 (headers &optional replybuffer actions)
+(defun message-setup-1 (headers &optional yank-action actions)
(dolist (action actions)
(condition-case nil
(add-to-list 'message-send-actions
`(apply ',(car action) ',(cdr action)))))
- (setq message-reply-buffer replybuffer)
+ (setq message-reply-buffer
+ (if (and (consp yank-action)
+ (eq (car yank-action) 'insert-buffer))
+ (nth 1 yank-action)
+ yank-action))
(goto-char (point-min))
;; Insert all the headers.
(mail-header-format
(save-restriction
(message-narrow-to-headers)
(run-hooks 'message-header-setup-hook))
- (set-buffer-modified-p nil)
(setq buffer-undo-list nil)
(when message-generate-hashcash
;; Generate hashcash headers for recipients already known
(mail-add-payment-async))
+ ;; Gnus posting styles are applied via buffer-local `message-setup-hook'
+ ;; values.
(run-hooks 'message-setup-hook)
;; Do this last to give it precedence over posting styles, etc.
(when (message-mail-p)
(if message-alternative-emails
(message-use-alternative-email-as-from))))
(message-position-point)
+ ;; Allow correct handling of `message-checksum' in `message-yank-original':
+ (set-buffer-modified-p nil)
(undo-boundary))
(defun message-set-auto-save-file-name ()
(if (gnus-alive-p)
(setq message-draft-article
(nndraft-request-associate-buffer "drafts"))
+
+ ;; If Gnus were alive, draft messages would be saved in the drafts folder.
+ ;; But Gnus is not alive, so arrange to save the draft message in a
+ ;; regular file in message-auto-save-directory. Append a unique
+ ;; time-based suffix to the filename to allow multiple drafts to be saved
+ ;; simultaneously without overwriting each other (which mimics the
+ ;; functionality of the Gnus drafts folder).
(setq buffer-file-name (expand-file-name
+ (concat
(if (memq system-type
- '(ms-dos ms-windows windows-nt
- cygwin cygwin32 win32 w32
- mswindows))
+ '(ms-dos windows-nt cygwin))
"message"
"*message*")
+ (format-time-string "-%Y%m%d-%H%M%S"))
message-auto-save-directory))
(setq buffer-auto-save-file-name (make-auto-save-file-name)))
(clear-visited-file-modtime)
"Disassociate the message buffer from the drafts directory."
(when message-draft-article
(nndraft-request-expire-articles
- (list message-draft-article) "nndraft:drafts" nil t)))
+ (list message-draft-article) "drafts" nil t)))
(defun message-insert-headers ()
"Generate the headers for the article."
to continue editing a message already being composed. SWITCH-FUNCTION
is a function used to switch to and display the mail buffer."
(interactive)
- (let ((message-this-is-mail t) replybuffer)
+ (let ((message-this-is-mail t))
(unless (message-mail-user-agent)
(message-pop-to-buffer
;; Search for the existing message buffer if `continue' is non-nil.
message-generate-new-buffers)))
(message-buffer-name "mail" to))
switch-function))
- ;; FIXME: message-mail should do something if YANK-ACTION is not
- ;; insert-buffer.
- (and (consp yank-action) (eq (car yank-action) 'insert-buffer)
- (setq replybuffer (nth 1 yank-action)))
(message-setup
(nconc
`((To . ,(or to "")) (Subject . ,(or subject "")))
(when other-headers other-headers))
- replybuffer send-actions continue switch-function)
+ yank-action send-actions continue switch-function)
;; FIXME: Should return nil if failure.
t))
(interactive)
(let ((file-name (make-auto-save-file-name)))
(cond ((save-window-excursion
- (if (not (eq system-type 'vax-vms))
- (with-output-to-temp-buffer "*Directory*"
- (with-current-buffer standard-output
- (fundamental-mode)) ; for Emacs 20.4+
- (buffer-disable-undo standard-output)
- (let ((default-directory "/"))
- (call-process
- "ls" nil standard-output nil "-l" file-name))))
+ (with-output-to-temp-buffer "*Directory*"
+ (with-current-buffer standard-output
+ (fundamental-mode)) ; for Emacs 20.4+
+ (buffer-disable-undo standard-output)
+ (let ((default-directory "/"))
+ (call-process
+ "ls" nil standard-output nil "-l" file-name)))
(yes-or-no-p (format "Recover auto save file %s? " file-name)))
(let ((buffer-read-only nil))
(erase-buffer)
(defun message-forward-make-body-plain (forward-buffer)
(insert
"\n-------------------- Start of forwarded message --------------------\n")
- (let ((b (point)) e)
- (insert
- (with-temp-buffer
- (mm-disable-multibyte)
- (insert
- (with-current-buffer forward-buffer
- (mm-with-unibyte-current-buffer (buffer-string))))
- (mm-enable-multibyte)
- (mime-to-mml)
- (goto-char (point-min))
- (when (looking-at "From ")
- (replace-match "X-From-Line: "))
- (buffer-string)))
+ (let ((b (point))
+ (contents (with-current-buffer forward-buffer (buffer-string)))
+ e)
+ (unless (featurep 'xemacs)
+ (unless (mm-multibyte-string-p contents)
+ (error "Attempt to insert unibyte string from the buffer \"%s\"\
+ to the multibyte buffer \"%s\""
+ (if (bufferp forward-buffer)
+ (buffer-name forward-buffer)
+ forward-buffer)
+ (buffer-name))))
+ (insert (mm-with-multibyte-buffer
+ (insert contents)
+ (mime-to-mml)
+ (goto-char (point-min))
+ (when (looking-at "From ")
+ (replace-match "X-From-Line: "))
+ (buffer-string)))
+ (unless (bolp) (insert "\n"))
(setq e (point))
(insert
- "\n-------------------- End of forwarded message --------------------\n")
+ "-------------------- End of forwarded message --------------------\n")
(message-remove-ignored-headers b e)))
(defun message-remove-ignored-headers (b e)
(insert "\n\n<#mml type=message/rfc822 disposition=inline>\n")
(let ((b (point)) e)
(if (not message-forward-decoded-p)
- (insert
- (with-temp-buffer
- (mm-disable-multibyte)
- (insert
- (with-current-buffer forward-buffer
- (mm-with-unibyte-current-buffer (buffer-string))))
- (mm-enable-multibyte)
- (mime-to-mml)
- (goto-char (point-min))
- (when (looking-at "From ")
- (replace-match "X-From-Line: "))
- (buffer-string)))
+ (let ((contents (with-current-buffer forward-buffer (buffer-string))))
+ (unless (featurep 'xemacs)
+ (unless (mm-multibyte-string-p contents)
+ (error "Attempt to insert unibyte string from the buffer \"%s\"\
+ to the multibyte buffer \"%s\""
+ (if (bufferp forward-buffer)
+ (buffer-name forward-buffer)
+ forward-buffer)
+ (buffer-name))))
+ (insert (mm-with-multibyte-buffer
+ (insert contents)
+ (mime-to-mml)
+ (goto-char (point-min))
+ (when (looking-at "From ")
+ (replace-match "X-From-Line: "))
+ (buffer-string))))
(save-restriction
(narrow-to-region (point) (point))
(mml-insert-buffer forward-buffer)
(message-forward-make-body-digest-mime forward-buffer)
(message-forward-make-body-digest-plain forward-buffer)))
-(eval-and-compile
- (autoload 'mm-uu-dissect-text-parts "mm-uu")
- (autoload 'mm-uu-dissect "mm-uu"))
+(autoload 'mm-uu-dissect-text-parts "mm-uu")
+(autoload 'mm-uu-dissect "mm-uu")
(defun message-signed-or-encrypted-p (&optional dont-emulate-mime handles)
"Say whether the current buffer contains signed or encrypted message.
(message-forward-make-body-plain forward-buffer)))
(message-position-point))
+(declare-function rmail-toggle-header "rmail" (&optional arg))
+
;;;###autoload
(defun message-forward-rmail-make-body (forward-buffer)
(save-window-excursion
(set-buffer forward-buffer)
(if (rmail-msg-is-pruned)
- (rmail-msg-restore-non-pruned-header)))
+ (if (fboundp 'rmail-msg-restore-non-pruned-header)
+ (rmail-msg-restore-non-pruned-header) ; Emacs 22
+ (rmail-toggle-header 0)))) ; Emacs 23
(message-forward-make-body forward-buffer))
;; Fixme: Should have defcustom.
(replace-match "X-From-Line: "))
;; Send it.
(let ((message-inhibit-body-encoding t)
+ (message-inhibit-ecomplete t)
message-required-mail-headers
message-generate-hashcash
rfc2047-encode-encoded-words)
(defun message-exchange-point-and-mark ()
"Exchange point and mark, but don't activate region if it was inactive."
- (unless (prog1
- (message-mark-active-p)
- (exchange-point-and-mark))
- (setq mark-active nil)))
+ (goto-char (prog1 (mark t)
+ (set-marker (mark-marker) (point)))))
(defalias 'message-make-overlay 'make-overlay)
(defalias 'message-delete-overlay 'delete-overlay)
(point))
(skip-chars-backward "^, \t\n") (point))))
(completion-ignore-case t)
- (string (buffer-substring b (progn (skip-chars-forward "^,\t\n ")
- (point))))
- (hashtb (and (boundp 'gnus-active-hashtb) gnus-active-hashtb))
- (completions (all-completions string hashtb))
- comp)
- (delete-region b (point))
- (cond
- ((= (length completions) 1)
- (if (string= (car completions) string)
- (progn
- (insert string)
- (message "Only matching group"))
- (insert (car completions))))
- ((and (setq comp (try-completion string hashtb))
- (not (string= comp string)))
- (insert comp))
- (t
- (insert string)
- (if (not comp)
- (message "No matching groups")
- (save-selected-window
- (pop-to-buffer "*Completions*")
- (buffer-disable-undo)
- (let ((buffer-read-only nil))
- (erase-buffer)
- (let ((standard-output (current-buffer)))
- (message-display-completion-list (sort completions 'string<)
- string))
- (setq buffer-read-only nil)
- (goto-char (point-min))
- (delete-region (point) (progn (forward-line 3) (point))))))))))
+ (e (progn (skip-chars-forward "^,\t\n ") (point)))
+ (hashtb (and (boundp 'gnus-active-hashtb) gnus-active-hashtb)))
+ (message-completion-in-region e b hashtb)))
+
+(defalias 'message-completion-in-region
+ (if (fboundp 'completion-in-region)
+ 'completion-in-region
+ (lambda (e b hashtb)
+ (let* ((string (buffer-substring b e))
+ (completions (all-completions string hashtb))
+ comp)
+ (delete-region b (point))
+ (cond
+ ((= (length completions) 1)
+ (if (string= (car completions) string)
+ (progn
+ (insert string)
+ (message "Only matching group"))
+ (insert (car completions))))
+ ((and (setq comp (try-completion string hashtb))
+ (not (string= comp string)))
+ (insert comp))
+ (t
+ (insert string)
+ (if (not comp)
+ (message "No matching groups")
+ (save-selected-window
+ (pop-to-buffer "*Completions*")
+ (buffer-disable-undo)
+ (let ((buffer-read-only nil))
+ (erase-buffer)
+ (let ((standard-output (current-buffer)))
+ (message-display-completion-list (sort completions 'string<)
+ string))
+ (setq buffer-read-only nil)
+ (goto-char (point-min))
+ (delete-region (point)
+ (progn (forward-line 3) (point))))))))))))
(defun message-expand-name ()
(cond ((and (memq 'eudc message-expand-name-databases)
(not result)
result)))
+(declare-function ecomplete-add-item "ecomplete" (type key text))
+(declare-function ecomplete-save "ecomplete" ())
+
(defun message-put-addresses-in-ecomplete ()
+ (require 'ecomplete)
(dolist (header '("to" "cc" "from" "reply-to"))
(let ((value (message-field-value header)))
(dolist (string (mail-header-parse-addresses value 'raw))
string))))
(ecomplete-save))
+(autoload 'ecomplete-display-matches "ecomplete")
+
(defun message-display-abbrev (&optional choose)
"Display the next possible abbrev for the text before point."
(interactive (list t))
(kill-buffer buff))))
(message "%s message(s) sent, %s skipped." sent skipped)))
+(defun message-replace-header (header new-value &optional after force)
+ "Remove HEADER and insert the NEW-VALUE.
+If AFTER, insert after this header. If FORCE, insert new field
+even if NEW-VALUE is empty."
+ ;; Similar to `nnheader-replace-header' but for message buffers.
+ (save-excursion
+ (save-restriction
+ (message-narrow-to-headers)
+ (message-remove-header header))
+ (when (or force (> (length new-value) 0))
+ (if after
+ (message-position-on-field header after)
+ (message-position-on-field header))
+ (insert new-value))))
+
+(defcustom message-recipients-without-full-name
+ (list "ding@gnus.org"
+ "bugs@gnus.org"
+ "emacs-devel@gnu.org"
+ "emacs-pretest-bug@gnu.org"
+ "bug-gnu-emacs@gnu.org")
+ "Mail addresses that have no full name.
+Used in `message-simplify-recipients'."
+ ;; Maybe the addresses could be extracted from
+ ;; `gnus-parameter-to-list-alist'?
+ :type '(choice (const :tag "None" nil)
+ (repeat string))
+ :version "23.1" ;; No Gnus
+ :group 'message-headers)
+
+(defun message-simplify-recipients ()
+ (interactive)
+ (dolist (hdr '("Cc" "To"))
+ (message-replace-header
+ hdr
+ (mapconcat
+ (lambda (addrcomp)
+ (if (and message-recipients-without-full-name
+ (string-match
+ (regexp-opt message-recipients-without-full-name)
+ (cadr addrcomp)))
+ (cadr addrcomp)
+ (if (car addrcomp)
+ (message-make-from (car addrcomp) (cadr addrcomp))
+ (cadr addrcomp))))
+ (when (message-fetch-field hdr)
+ (mail-extract-address-components
+ (message-fetch-field hdr) t))
+ ", "))))
+
(when (featurep 'xemacs)
(require 'messagexmas)
(message-xmas-redefine))