gnus-ems.el: Provide compatibility functions for gnus-set-process-plist by Katsumi...
[bpt/emacs.git] / lisp / gnus / message.el
index 2fe8a4d..2e27dac 100644 (file)
 (eval-when-compile
   (require 'cl))
 
 (eval-when-compile
   (require 'cl))
 
-(require 'hashcash)
-(require 'canlock)
 (require 'mailheader)
 (require 'gmm-utils)
 (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.
 ;; This is apparently necessary even though things are autoloaded.
 ;; Because we dynamically bind mail-abbrev-mode-regexp, we'd better
 ;; require mailabbrev here.
@@ -48,7 +49,6 @@
 (require 'mail-parse)
 (require 'mml)
 (require 'rfc822)
 (require 'mail-parse)
 (require 'mml)
 (require 'rfc822)
-(require 'ecomplete)
 
 (autoload 'mailclient-send-it "mailclient") ;; Emacs 22 or contrib/
 
 
 (autoload 'mailclient-send-it "mailclient") ;; Emacs 22 or contrib/
 
@@ -249,6 +249,14 @@ included.  Organization and User-Agent are optional."
   :link '(custom-manual "(message)Message Headers")
   :type '(repeat sexp))
 
   :link '(custom-manual "(message)Message Headers")
   :type '(repeat sexp))
 
+(defcustom message-prune-recipient-rules nil
+  "Rules for how to prune the list of recipients when doing wide replies.
+This is a list of regexps and regexp matches."
+  :group 'message-mail
+  :group 'message-headers
+  :link '(custom-manual "(message)Wide Reply")
+  :type '(repeat regexp))
+
 (defcustom message-deletable-headers '(Message-ID Date Lines)
   "Headers to be deleted if they already exist and were generated by message previously."
   :group 'message-headers
 (defcustom message-deletable-headers '(Message-ID Date Lines)
   "Headers to be deleted if they already exist and were generated by message previously."
   :group 'message-headers
@@ -655,8 +663,6 @@ Done before generating the new subject of a forward."
   :link '(custom-manual "(message)Canceling News")
   :type 'string)
 
   :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)
 (defun message-send-mail-function ()
   "Return suitable value for the variable `message-send-mail-function'."
   (cond ((and (require 'sendmail)
@@ -665,14 +671,13 @@ Done before generating the new subject of a forward."
              (executable-find sendmail-program))
         'message-send-mail-with-sendmail)
        ((and (locate-library "smtpmail")
              (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
              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
 
 ;; Useful to set in site-init.el
 (defcustom message-send-mail-function
@@ -1280,7 +1285,7 @@ text and it replaces `self-insert-command' with the other command, e.g.
   :type '(repeat function))
 
 (defcustom message-auto-save-directory
   :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
   "*Directory where Message auto-saves buffers if Gnus isn't running.
 If nil, Message won't auto-save."
   :group 'message-buffers
@@ -1623,11 +1628,11 @@ If you'd like to make it possible to share draft files between XEmacs
 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.")
 
 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."
   "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."
-  :version "21.1"
+  :version "24.1"
   :group 'message-buffers
   :link '(custom-manual "(message)Mail Variables")
   :type '(choice (const :tag "unlimited" nil)
   :group 'message-buffers
   :link '(custom-manual "(message)Mail Variables")
   :type '(choice (const :tag "unlimited" nil)
@@ -1742,6 +1747,7 @@ You must have the \"hashcash\" binary installed, see `hashcash-path'."
 (defvar message-mime-part nil)
 (defvar message-posting-charset nil)
 (defvar message-inserted-headers nil)
 (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)
 
 ;; Byte-compiler warning
 (defvar gnus-active-hashtb)
@@ -1956,6 +1962,8 @@ is used by default."
                 (setq paren nil))))
        (nreverse elems)))))
 
                 (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)
 (defun message-mail-file-mbox-p (file)
   "Say whether FILE looks like a Unix mbox file."
   (when (and (file-exists-p file)
@@ -2849,6 +2857,8 @@ See also `message-forbidden-properties'."
          (inhibit-read-only t))
       (remove-text-properties begin end message-forbidden-properties))))
 
          (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.
 ;;;###autoload
 (define-derived-mode message-mode text-mode "Message"
   "Major mode for editing mail and news to be sent.
@@ -3408,8 +3418,8 @@ Message buffers and is not meant to be called directly."
                                ;; if message-signature-file contains a path.
                                (not (file-name-directory
                                      message-signature-file)))
                                ;; 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
                         message-signature-file))
                 (file-exists-p signature-file))))
     (when signature
@@ -4090,7 +4100,8 @@ It should typically alter the sending method in some way or other."
        (run-hooks 'message-sent-hook))
       (message "Sending...done")
       ;; Do ecomplete address snarfing.
        (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)
        (message-put-addresses-in-ecomplete))
       ;; Mark the buffer as unmodified and delete auto-save.
       (set-buffer-modified-p nil)
@@ -4412,6 +4423,8 @@ This function could be useful in `message-setup-hook'."
            (erase-buffer)))
       (kill-buffer tembuf))))
 
            (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"))
 (defun message-send-mail (&optional arg)
   (require 'mail-utils)
   (let* ((tembuf (message-generate-new-buffer-clone-locals " message temp"))
@@ -4419,14 +4432,26 @@ This function could be useful in `message-setup-hook'."
         (news (message-news-p))
         (mailbuf (current-buffer))
         (message-this-is-mail t)
         (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
         (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...")
              (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
       ;; Wait for calculations already started to finish...
       (hashcash-wait-async)
       ;; ...and do calculations not already done.  mail-add-payment
@@ -4548,6 +4573,7 @@ If you always want Gnus to send messages in one piece, set
 
 (defun message-send-mail-with-sendmail ()
   "Send off the prepared buffer with sendmail."
 
 (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")
   (let ((errbuf (if message-interactive
                    (message-generate-new-buffer-clone-locals
                     " sendmail errors")
@@ -4711,10 +4737,14 @@ Do not use this for anything important, it is cryptographically weak."
                  (prin1-to-string (recent-keys))
                  (prin1-to-string (garbage-collect))))))
 
                  (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."
 (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))
   (unless canlock-password
     (customize-save-variable 'canlock-password (message-canlock-generate))
     (setq canlock-password-for-verify canlock-password))
@@ -4725,7 +4755,12 @@ Otherwise, generate and save a value for `canlock-password' first."
     (message-canlock-password)
     (canlock-insert-header)))
 
     (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)
 (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)
   (let* ((tembuf (message-generate-new-buffer-clone-locals " *message temp*"))
         (case-fold-search nil)
         (method (if (functionp message-post-method)
@@ -5406,7 +5441,7 @@ In posting styles use `(\"Expires\" (make-expires-date 30))'."
           (* 25 25)))
   (let ((tm (current-time)))
     (concat
           (* 25 25)))
   (let ((tm (current-time)))
     (concat
-     (if (or (memq system-type '(ms-dos emx))
+     (if (or (eq system-type 'ms-dos)
             ;; message-number-base36 doesn't handle bigints.
             (floatp (user-uid)))
         (let ((user (downcase (user-login-name))))
             ;; message-number-base36 doesn't handle bigints.
             (floatp (user-uid)))
         (let ((user (downcase (user-login-name))))
@@ -5464,7 +5499,7 @@ In posting styles use `(\"Expires\" (make-expires-date 30))'."
 (defun message-make-references ()
   "Return the References header for this message."
   (when message-reply-headers
 (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 " ")
          (references (mail-header-references message-reply-headers)))
       (if (or references message-id)
          (concat (or references "") (and references " ")
@@ -5476,7 +5511,7 @@ In posting styles use `(\"Expires\" (make-expires-date 30))'."
   (when message-reply-headers
     (let ((from (mail-header-from message-reply-headers))
          (date (mail-header-date message-reply-headers))
   (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
       (when from
        (let ((name (mail-extract-address-components from)))
          (concat
@@ -6424,9 +6459,7 @@ are not included."
       (setq buffer-file-name (expand-file-name
                              (concat
                              (if (memq system-type
       (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"
                                "*message*")
                               (format-time-string "-%Y%m%d-%H%M%S"))
@@ -6526,7 +6559,7 @@ The function is called with one parameter, a cons cell ..."
 
 (defun message-get-reply-headers (wide &optional to-address address-headers)
   (let (follow-to mct never-mct to cc author mft recipients extra)
 
 (defun message-get-reply-headers (wide &optional to-address address-headers)
   (let (follow-to mct never-mct to cc author mft recipients extra)
-  ;; Find all relevant headers we need.
+    ;; Find all relevant headers we need.
     (save-restriction
       (message-narrow-to-headers-or-head)
       ;; Gmane renames "To".  Look at "Original-To", too, if it is present in
     (save-restriction
       (message-narrow-to-headers-or-head)
       ;; Gmane renames "To".  Look at "Original-To", too, if it is present in
@@ -6652,6 +6685,8 @@ want to get rid of this query permanently.")))
                (if recip
                    (setq recipients (delq recip recipients))))))))
 
                (if recip
                    (setq recipients (delq recip recipients))))))))
 
+      (setq recipients (message-prune-recipients recipients))
+      
       ;; Build the header alist.  Allow the user to be asked whether
       ;; or not to reply to all recipients in a wide reply.
       (setq follow-to (list (cons 'To (cdr (pop recipients)))))
       ;; Build the header alist.  Allow the user to be asked whether
       ;; or not to reply to all recipients in a wide reply.
       (setq follow-to (list (cons 'To (cdr (pop recipients)))))
@@ -6665,6 +6700,22 @@ want to get rid of this query permanently.")))
        (push (cons 'Cc recipients) follow-to)))
     follow-to))
 
        (push (cons 'Cc recipients) follow-to)))
     follow-to))
 
+(defun message-prune-recipients (recipients)
+  (dolist (rule message-prune-recipient-rules)
+    (let ((match (car rule))
+         dup-match 
+         address)
+      (dolist (recipient recipients)
+       (setq address (car recipient))
+       (when (string-match match address)
+         (setq dup-match (replace-match (cadr rule) nil nil address))
+         (dolist (recipient recipients)
+           ;; Don't delete the address that triggered this.
+           (when (and (not (eq address (car recipient)))
+                      (string-match dup-match (car recipient)))
+             (setq recipients (delq recipient recipients))))))))
+  recipients)
+
 (defcustom message-simplify-subject-functions
   '(message-strip-list-identifiers
     message-strip-subject-re
 (defcustom message-simplify-subject-functions
   '(message-strip-list-identifiers
     message-strip-subject-re
@@ -7136,22 +7187,28 @@ Optional DIGEST will use digest to forward."
 (defun message-forward-make-body-plain (forward-buffer)
   (insert
    "\n-------------------- Start of forwarded message --------------------\n")
 (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
     (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)
     (message-remove-ignored-headers b e)))
 
 (defun message-remove-ignored-headers (b e)
@@ -7187,18 +7244,22 @@ Optional DIGEST will use digest to forward."
   (insert "\n\n<#mml type=message/rfc822 disposition=inline>\n")
   (let ((b (point)) e)
     (if (not message-forward-decoded-p)
   (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)
       (save-restriction
        (narrow-to-region (point) (point))
        (mml-insert-buffer forward-buffer)
@@ -7390,6 +7451,7 @@ is for the internal use."
        (replace-match "X-From-Line: "))
       ;; Send it.
       (let ((message-inhibit-body-encoding t)
        (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)
            message-required-mail-headers
            message-generate-hashcash
            rfc2047-encode-encoded-words)
@@ -8002,7 +8064,11 @@ From headers in the original article."
        (not result)
       result)))
 
        (not result)
       result)))
 
+(declare-function ecomplete-add-item "ecomplete" (type key text))
+(declare-function ecomplete-save "ecomplete" ())
+
 (defun message-put-addresses-in-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))
   (dolist (header '("to" "cc" "from" "reply-to"))
     (let ((value (message-field-value header)))
       (dolist (string (mail-header-parse-addresses value 'raw))
@@ -8013,6 +8079,8 @@ From headers in the original article."
                            string))))
   (ecomplete-save))
 
                            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))
 (defun message-display-abbrev (&optional choose)
   "Display the next possible abbrev for the text before point."
   (interactive (list t))