Revision: miles@gnu.org--gnu-2005/emacs--unicode--0--patch-57
[bpt/emacs.git] / lisp / mail / rmail.el
index c97f048..e97f7d7 100644 (file)
   :group 'rmail)
 
 (defcustom rmail-movemail-program nil
-  "If non-nil, name of program for fetching new mail."
+  "If non-nil, the file name of the `movemail' program."
   :group 'rmail-retrieve
   :type '(choice (const nil) string))
 
 (defcustom rmail-pop-password nil
-  "*Password to use when reading mail from POP server. Please, use rmail-remote-password instead."
+  "*Password to use when reading mail from POP server.
+Please use `rmail-remote-password' instead."
   :type '(choice (string :tag "Password")
                 (const :tag "Not Required" nil))
   :group 'rmail-obsolete)
 
 (defcustom rmail-pop-password-required nil
-  "*Non-nil if a password is required when reading mail from a POP server. Please, use rmail-remote-password-required instead."
+  "*Non-nil if a password is required when reading mail from a POP server. 
+Please use rmail-remote-password-required instead."
   :type 'boolean
   :group 'rmail-obsolete)
 
 (defcustom rmail-remote-password nil
-  "*Password to use when reading mail from a remote server. This setting is ignored for mailboxes whose URL already contains a password."
+  "*Password to use when reading mail from a remote server.
+This setting is ignored for mailboxes whose URL already contains a password."
   :type '(choice (string :tag "Password")
                 (const :tag "Not Required" nil))
   :set-after '(rmail-pop-password)
   :set #'(lambda (symbol value)
-          (set-default symbol 
+          (set-default symbol
                        (if (and (not value)
                                  (boundp 'rmail-pop-password)
                                 rmail-pop-password)
                          value))
           (setq rmail-pop-password nil))
   :group 'rmail-retrieve
-  :version "21.3.50.1")
+  :version "22.1")
 
 (defcustom rmail-remote-password-required nil
   "*Non-nil if a password is required when reading mail from a remote server."
   :type 'boolean
   :set-after '(rmail-pop-password-required)
   :set #'(lambda (symbol value)
-          (set-default symbol 
+          (set-default symbol
                        (if (and (not value)
                                  (boundp 'rmail-pop-password-required)
                                 rmail-pop-password-required)
                          value))
           (setq rmail-pop-password-required nil))
   :group 'rmail-retrieve
-  :version "21.3.50.1")
+  :version "22.1")
 
 (defcustom rmail-movemail-flags nil
   "*List of flags to pass to movemail.
@@ -160,8 +163,7 @@ please report it with \\[report-emacs-bug].")
 (defvar rmail-encoded-remote-password nil)
 
 (defcustom rmail-preserve-inbox nil
-  "*Non-nil if incoming mail should be left in the user's inbox,
-rather than deleted, after it is retrieved."
+  "*Non-nil means leave incoming mail in the user's inbox--don't delete it."
   :type 'boolean
   :group 'rmail-retrieve)
 
@@ -171,8 +173,8 @@ rather than deleted, after it is retrieved."
     :type '(repeat (directory)))
 
 (defun rmail-probe (prog)
-  "Determine what flavor of movemail PROG is by executing it with --version
-command line option and analyzing its output."
+  "Determine what flavor of movemail PROG is.
+We do this by executing it with `--version' and analyzing its output."
   (with-temp-buffer
     (let ((tbuf (current-buffer)))
       (buffer-disable-undo tbuf)
@@ -191,10 +193,10 @@ command line option and analyzing its output."
          'emacs))))))
 
 (defun rmail-autodetect ()
-  "Determine and return the flavor of `movemail' program in use. If
-rmail-movemail-program is set, use it. Otherwise, look for `movemail'
-in the path constructed by appending rmail-movemail-search-path,
-exec-path and exec-directory."
+  "Determine and return the file name of the `movemail' program.
+If `rmail-movemail-program' is non-nil, use it.
+Otherwise, look for `movemail' in the directories in
+`rmail-movemail-search-path', those in `exec-path', and `exec-directory'."
   (if rmail-movemail-program
       (rmail-probe rmail-movemail-program)
     (catch 'scan
@@ -244,7 +246,7 @@ It is useful to set this variable in the site customization file.")
 
 ;;;###autoload
 (defcustom rmail-ignored-headers
-  (concat "^via:\\|^mail-from:\\|^origin:\\|^references:"
+  (concat "^via:\\|^mail-from:\\|^origin:\\|^references:\\|^sender:"
          "\\|^status:\\|^received:\\|^x400-originator:\\|^x400-recipients:"
          "\\|^x400-received:\\|^x400-mts-identifier:\\|^x400-content-type:"
          "\\|^\\(resent-\\|\\)message-id:\\|^summary-line:\\|^resent-date:"
@@ -252,14 +254,17 @@ It is useful to set this variable in the site customization file.")
          "\\|^x-mailer:\\|^delivered-to:\\|^lines:\\|^mime-version:"
          "\\|^content-transfer-encoding:\\|^x-coding-system:"
          "\\|^return-path:\\|^errors-to:\\|^return-receipt-to:"
-         "\\|^x-sign:\\|^x-beenthere:\\|^x-mailman-version:"
+         "\\|^x-sign:\\|^x-beenthere:\\|^x-mailman-version:\\|^x-mailman-copy:"
          "\\|^precedence:\\|^list-help:\\|^list-post:\\|^list-subscribe:"
          "\\|^list-id:\\|^list-unsubscribe:\\|^list-archive:"
          "\\|^content-type:\\|^content-length:"
          "\\|^x-attribution:\\|^x-disclaimer:\\|^x-trace:"
          "\\|^x-complaints-to:\\|^nntp-posting-date:\\|^user-agent"
          "\\|^importance:\\|^envelope-to:\\|^delivery-date"
-         "\\|^x.*-priority:\\|^x-mimeole:")
+         "\\|^x.*-priority:\\|^x-mimeole:\\|^x-archive:"
+         "\\|^resent-face:\\|^resent-x.*:\\|^resent-organization\\|^resent-openpgp"
+         "\\|^openpgp:\\|^x-request-pgp:\\|^x-original.*:"
+         "\\|^x-virus-scanned:\\|^x-spam-[^s].*:")
   "*Regexp to match header fields that Rmail should normally hide.
 This variable is used for reformatting the message header,
 which normally happens once for each message,
@@ -651,17 +656,18 @@ The first parenthesized expression should match the MIME-charset name.")
              . font-lock-function-name-face)
            '("^Reply-To:.*$" . font-lock-function-name-face)
            '("^Subject:" . font-lock-comment-face)
+           '("^X-Spam-Status:" . font-lock-keyword-face)
            '("^\\(To\\|Apparently-To\\|Cc\\|Newsgroups\\):"
              . font-lock-keyword-face)
            ;; Use MATCH-ANCHORED to effectively anchor the regexp left side.
            `(,cite-chars
              (,(concat "\\=[ \t]*"
-                       "\\(\\([" cite-prefix "]+[" cite-suffix "]*\\)?"
-                       "\\(" cite-chars "[ \t]*\\)\\)+"
+                       "\\(\\(\\([" cite-prefix "]+[" cite-suffix "]*\\)?"
+                       "\\(" cite-chars "[ \t]*\\)\\)+\\)"
                        "\\(.*\\)")
               (beginning-of-line) (end-of-line)
-              (2 font-lock-constant-face nil t)
-              (4 font-lock-comment-face nil t)))
+              (1 font-lock-comment-delimiter-face nil t)
+              (5 font-lock-comment-face nil t)))
            '("^\\(X-[a-z0-9-]+\\|In-reply-to\\|Date\\):.*\\(\n[ \t]+.*\\)*$"
              . font-lock-string-face))))
   "Additional expressions to highlight in Rmail mode.")
@@ -1150,7 +1156,7 @@ Instead, these commands are available:
       (when rmail-display-summary
        (rmail-summary))
       (rmail-construct-io-menu))
-    (run-hooks 'rmail-mode-hook)))
+    (run-mode-hooks 'rmail-mode-hook)))
 
 (defun rmail-mode-2 ()
   (kill-all-local-variables)
@@ -1620,19 +1626,21 @@ a remote mailbox, PASSWORD is the password if it should be
 supplied as a separate argument to `movemail' or nil otherwise, GOT-PASSWORD
 is non-nil if the user has supplied the password interactively.
 "
-  (if (string-match "^\\([^:]+\\)://\\(\\([^:@]+\\)\\(:\\([^@]+\\)\\)?@\\)?.*" file)
-      (let (got-password supplied-password 
+  (cond
+   ((string-match "^\\([^:]+\\)://\\(\\([^:@]+\\)\\(:\\([^@]+\\)\\)?@\\)?.*" file)
+      (let (got-password supplied-password
            (proto (match-string 1 file))
            (user  (match-string 3 file))
            (pass  (match-string 5 file))
            (host  (substring file (or (match-end 2)
                                       (+ 3 (match-end 1))))))
+       
        (if (not pass)
            (when rmail-remote-password-required
              (setq got-password (not (rmail-have-password)))
              (setq supplied-password (rmail-get-remote-password
                                       (string-equal proto "imap")))))
-                             
+
        (if (rmail-movemail-variant-p 'emacs)
            (if (string-equal proto "pop")
                (list (concat "po:" user ":" host)
@@ -1643,8 +1651,22 @@ is non-nil if the user has supplied the password interactively.
          (list file
                (or (string-equal proto "pop") (string-equal proto "imap"))
                supplied-password
-               got-password)))
-    (list file nil nil nil)))
+               got-password))))
+   
+   ((string-match "^po:\\([^:]+\\)\\(:\\(.*\\)\\)?" file)
+    (let (got-password supplied-password
+          (proto "pop")
+         (user  (match-string 1 file))
+         (host  (match-string 3 file)))
+      
+      (when rmail-remote-password-required
+       (setq got-password (not (rmail-have-password)))
+       (setq supplied-password (rmail-get-remote-password nil)))
+
+      (list file "pop" supplied-password got-password)))
+   
+   (t
+    (list file nil nil nil))))
 
 (defun rmail-insert-inbox-text (files renamep)
   ;; Detect a locked file now, so that we avoid moving mail
@@ -1671,7 +1693,7 @@ is non-nil if the user has supplied the password interactively.
                    ;; Generate name to move to from inbox name,
                    ;; in case of multiple inboxes that need moving.
                    (concat ".newmail-"
-                           (file-name-nondirectory 
+                           (file-name-nondirectory
                             (if (memq system-type '(windows-nt cygwin))
                                 ;; cannot have "po:" in file name
                                 (substring file 3)
@@ -1684,15 +1706,7 @@ is non-nil if the user has supplied the password interactively.
                     (expand-file-name buffer-file-name))))
       ;; Always use movemail to rename the file,
       ;; since there can be mailboxes in various directories.
-      (setq movemail t)
-;;;      ;; If getting from mail spool directory,
-;;;      ;; use movemail to move rather than just renaming,
-;;;      ;; so as to interlock with the mailer.
-;;;      (setq movemail (string= file
-;;;                          (file-truename
-;;;                           (concat rmail-spool-directory
-;;;                                   (file-name-nondirectory file)))))
-      (if (and movemail (not popmail))
+      (if (not popmail)
          (progn
            ;; On some systems, /usr/spool/mail/foo is a directory
            ;; and the actual inbox is /usr/spool/mail/foo/foo.
@@ -1714,23 +1728,6 @@ is non-nil if the user has supplied the password interactively.
            ((or (file-exists-p tofile) (and (not popmail)
                                             (not (file-exists-p file))))
             nil)
-           ((and (not movemail) (not popmail))
-            ;; Try copying.  If that fails (perhaps no space) and
-            ;; we're allowed to blow away the inbox, rename instead.
-            (if rmail-preserve-inbox
-                (copy-file file tofile nil)
-              (condition-case nil
-                  (copy-file file tofile nil)
-                (error
-                 ;; Third arg is t so we can replace existing file TOFILE.
-                 (rename-file file tofile t))))
-            ;; Make the real inbox file empty.
-            ;; Leaving it deleted could cause lossage
-            ;; because mailers often won't create the file.
-            (if (not rmail-preserve-inbox)
-                (condition-case ()
-                    (write-region (point) (point) file)
-                  (file-error nil))))
            (t
             (with-temp-buffer
               (let ((errors (current-buffer)))
@@ -1777,14 +1774,14 @@ is non-nil if the user has supplied the password interactively.
                     (goto-char (point-min))
                     (when (looking-at "[A-Z][A-Z0-9_]*:")
                       (delete-region (point-min) (match-end 0))))
-                  
+
                   (message "movemail: %s"
                            (buffer-substring (point-min)
                                              (point-max)))
-                      
+
                   (sit-for 3)
                   nil)))))
-              
+
       ;; At this point, TOFILE contains the name to read:
       ;; Either the alternate name (if we renamed)
       ;; or the actual inbox (if not renaming).
@@ -1993,7 +1990,7 @@ is non-nil if the user has supplied the password interactively.
                                              header-end t)
                              (let ((beg (point))
                                    (eol (progn (end-of-line) (point))))
-                               (string-to-int (buffer-substring beg eol)))))))
+                               (string-to-number (buffer-substring beg eol)))))))
                 (and size
                      (if (and (natnump size)
                               (<= (+ header-end size) (point-max))
@@ -2609,6 +2606,39 @@ change the invisible header text."
   (interactive)
   (rmail-show-message rmail-current-message))
 
+(defun rmail-unknown-mail-followup-to ()
+  "Handle a \"Mail-Followup-To\" header field with an unknown mailing list.
+Ask the user whether to add that list name to `mail-mailing-lists'."
+   (save-restriction
+     (rmail-narrow-to-non-pruned-header)
+     (let ((mail-followup-to (mail-fetch-field "mail-followup-to" nil t)))
+       (when mail-followup-to
+        (let ((addresses
+               (split-string 
+                (mail-strip-quoted-names mail-followup-to)
+                ",[[:space:]]+" t)))
+          (dolist (addr addresses)
+            (when (and (not (member addr mail-mailing-lists))
+                       (not
+                        ;; taken from rmailsum.el
+                        (string-match
+                         (or rmail-user-mail-address-regexp
+                             (concat "^\\("
+                                     (regexp-quote (user-login-name))
+                                     "\\($\\|@\\)\\|"
+                                     (regexp-quote
+                                      (or user-mail-address
+                                          (concat (user-login-name) "@"
+                                                  (or mail-host-address
+                                                      (system-name)))))
+                                     "\\>\\)"))
+                         addr))
+                       (y-or-n-p
+                        (format "Add `%s' to `mail-mailing-lists'? "
+                                addr)))
+              (customize-save-variable 'mail-mailing-lists
+                                       (cons addr mail-mailing-lists)))))))))
+
 (defun rmail-show-message (&optional n no-summary)
   "Show message number N (prefix argument), counting from start of file.
 If summary buffer is currently displayed, update current message there also."
@@ -2677,8 +2707,9 @@ If summary buffer is currently displayed, update current message there also."
        (rmail-display-labels)
        (if (eq rmail-enable-mime t)
            (funcall rmail-show-mime-function)
-         (setq rmail-view-buffer rmail-buffer)
-         )
+         (setq rmail-view-buffer rmail-buffer))
+       (when mail-mailing-lists
+         (rmail-unknown-mail-followup-to))
        (rmail-highlight-headers)
        (if transient-mark-mode (deactivate-mark))
        (run-hooks 'rmail-show-message-hook)
@@ -3367,9 +3398,14 @@ use \\[mail-yank-original] to yank the original message into it."
                              (progn (search-forward "\n*** EOOH ***\n")
                                     (beginning-of-line) (point)))))
        (setq from (mail-fetch-field "from")
-             reply-to (or (mail-fetch-field "reply-to" nil t)
+             reply-to (or (if just-sender
+                              (mail-fetch-field "mail-reply-to" nil t)
+                            (mail-fetch-field "mail-followup-to" nil t))
+                          (mail-fetch-field "reply-to" nil t)
                           from)
              cc (and (not just-sender)
+                     ;; mail-followup-to, if given, overrides cc.
+                     (not (mail-fetch-field "mail-followup-to" nil t))
                      (mail-fetch-field "cc" nil t))
              subject (mail-fetch-field "subject")
              date (mail-fetch-field "date")
@@ -3408,7 +3444,11 @@ use \\[mail-yank-original] to yank the original message into it."
      ;; I don't know whether there are other mailers that still
      ;; need the names to be stripped.
 ;;;     (mail-strip-quoted-names reply-to)
-     reply-to
+     ;; Remove unwanted names from reply-to, since Mail-Followup-To
+     ;; header causes all the names in it to wind up in reply-to, not
+     ;; in cc.  But if what's left is an empty list, use the original.
+     (let* ((reply-to-list (rmail-dont-reply-to reply-to)))
+       (if (string= reply-to-list "") reply-to reply-to-list))
      subject
      (rmail-make-in-reply-to-field from date message-id)
      (if just-sender