Update doc for advice changes.
[bpt/emacs.git] / lisp / mail / rmail.el
index 372b120..246ee5f 100644 (file)
@@ -1,7 +1,7 @@
 ;;; rmail.el --- main code of "RMAIL" mail reader for Emacs
 
-;; Copyright (C) 1985-1988, 1993-1998, 2000-2012
-;;   Free Software Foundation, Inc.
+;; Copyright (C) 1985-1988, 1993-1998, 2000-2013 Free Software
+;; Foundation, Inc.
 
 ;; Maintainer: FSF
 ;; Keywords: mail
@@ -100,6 +100,10 @@ its character representation and its display representation.")
   "The current header display style choice, one of
 'normal (selected headers) or 'full (all headers).")
 
+(defvar rmail-mime-decoded nil
+  "Non-nil if message has been processed by `rmail-show-mime-function'.")
+(put 'rmail-mime-decoded 'permanent-local t) ; for rmail-edit
+
 (defgroup rmail nil
   "Mail reader for Emacs."
   :group 'mail)
@@ -1081,6 +1085,7 @@ The buffer is expected to be narrowed to just the header of the message."
     (define-key map "<"      'rmail-first-message)
     (define-key map ">"      'rmail-last-message)
     (define-key map " "      'scroll-up-command)
+    (define-key map [?\S-\ ] 'scroll-down-command)
     (define-key map "\177"   'scroll-down-command)
     (define-key map "?"      'describe-mode)
     (define-key map "\C-c\C-s\C-d" 'rmail-sort-by-date)
@@ -1503,6 +1508,8 @@ If so restore the actual mbox message collection."
   (setq file-precious-flag t)
   (make-local-variable 'desktop-save-buffer)
   (setq desktop-save-buffer t)
+  (make-local-variable 'save-buffer-coding-system)
+  (setq save-buffer-coding-system 'no-conversion)
   (setq next-error-move-function 'rmail-next-error-move))
 \f
 ;; Handle M-x revert-buffer done in an rmail-mode buffer.
@@ -2169,20 +2176,35 @@ If MSGNUM is nil, use the current message."
 
 (defun rmail-set-header-1 (name value)
   "Subroutine of `rmail-set-header'.
-Narrow to header, set header NAME to VALUE, replacing existing if present.
-VALUE nil means to remove NAME altogether."
+Narrow to headers, set header NAME to VALUE, replacing existing if present.
+VALUE nil means to remove NAME altogether.
+
+Only changes the first instance of NAME.  If VALUE is multi-line,
+continuation lines should already be indented.  VALUE should not
+end in a newline."
   (if (search-forward "\n\n" nil t)
       (progn
        (forward-char -1)
        (narrow-to-region (point-min) (point))
+       ;; cf mail-fetch-field.
        (goto-char (point-min))
-       (if (re-search-forward (concat "^" (regexp-quote name) ":") nil 'move)
+       (if (let ((case-fold-search t))
+             (re-search-forward (concat "^" (regexp-quote name) "[ \t]*:")
+                                nil 'move))
+           (let ((start (point))
+                 end)
+             (while (and (zerop (forward-line 1))
+                         (looking-at "[ \t]")))
+             ;; Back up over newline.
+             (forward-char -1)
+             (setq end (point))
+             (goto-char start)
             (if value
                 (progn
-                  (delete-region (point) (line-end-position))
+                   (delete-region start end)
                   (insert " " value))
-              (delete-region (line-beginning-position)
-                             (line-beginning-position 2)))
+               (delete-region (line-beginning-position) (1+ end))))
+         ;; Not already present: insert at end of headers.
           (if value (insert name ": " value "\n"))))
     (rmail-error-bad-format)))
 
@@ -2699,6 +2721,27 @@ N defaults to the current message."
   :group 'rmail
   :version "23.1")
 
+;; FIXME?
+;; rmail-show-mime-function does not unquote >From lines.  Should it?
+(defcustom rmail-mbox-format 'mboxrd
+  "The mbox format that your system uses.
+There is no way to determine this, so you should set the appropriate value.
+The formats quote lines containing \"From \" differently.
+The choices are:
+  `mboxo' : lines that start with \"From \" quoted as \">From \"
+  `mboxrd': lines that start with \">*From \" quoted with another \">\"
+The `mboxo' format is ambiguous, in that one cannot know whether
+a line starting with \">From \" originally had a \">\" or not.
+
+It is not critical to set this to the correct value; it only affects
+how Rmail displays lines starting with \">*From \" in non-MIME messages.
+
+See also `unrmail-mbox-format'."
+  :type '(choice (const mboxrd)
+                (const mboxro))
+  :version "24.4"
+  :group 'rmail-files)
+
 (defun rmail-show-message-1 (&optional msg)
   "Show message MSG (default: current message) using `rmail-view-buffer'.
 Return text to display in the minibuffer if MSG is out of
@@ -2747,6 +2790,7 @@ The current mail message becomes the message displayed."
                 (re-search-forward "mime-version: 1.0" nil t))
            (let ((rmail-buffer mbox-buf)
                  (rmail-view-buffer view-buf))
+             (set (make-local-variable 'rmail-mime-decoded) t)
              (funcall rmail-show-mime-function))
          (setq body-start (search-forward "\n\n" nil t))
          (narrow-to-region beg (point))
@@ -2791,11 +2835,15 @@ The current mail message becomes the message displayed."
            ;; Prepare the separator (blank line) before the body.
            (goto-char (point-min))
            (insert "\n")
-           ;; Unquote quoted From lines
-           (while (re-search-forward "^>+From " nil t)
-             (beginning-of-line)
-             (delete-char 1)
-             (forward-line))
+           ;; Unquote quoted From lines.
+           (let ((fromline (if (eq 'mboxrd rmail-mbox-format)
+                               "^>+From "
+                             "^>From "))
+                 case-fold-search)
+             (while (re-search-forward fromline nil t)
+               (beginning-of-line)
+               (delete-char 1)
+               (forward-line)))
            (goto-char (point-min)))
          ;; Copy the headers to the front of the message view buffer.
          (rmail-copy-headers beg end)
@@ -3677,7 +3725,7 @@ to switch to."
    ;; If the frame was probably made for this buffer, the user
    ;; probably wants to delete it now.
    ((display-multi-frame-p)
-    (delete-frame (selected-frame)))
+    (delete-frame))
    ;; The previous frame is where normally they have the Rmail buffer
    ;; displayed.
    (t (other-frame -1))))
@@ -3869,6 +3917,7 @@ see the documentation of `rmail-resend'."
          (msgnum rmail-current-message)
          (subject (concat "["
                           (let ((from (or (mail-fetch-field "From")
+                                          ;; FIXME - huh?
                                           (mail-fetch-field ">From"))))
                             (if from
                                 (concat (mail-strip-quoted-names from) ": ")
@@ -4056,6 +4105,9 @@ The message should be narrowed to just the headers."
 
 (autoload 'mail-position-on-field "sendmail")
 
+(declare-function rmail-mime-message-p "rmailmm" ())
+(declare-function rmail-mime-toggle-raw "rmailmm" (&optional state))
+
 (defun rmail-retry-failure ()
   "Edit a mail message which is based on the contents of the current message.
 For a message rejected by the mail system, extract the interesting headers and
@@ -4068,7 +4120,13 @@ The variable `rmail-retry-ignored-headers' is a regular expression
 specifying headers which should not be copied into the new message."
   (interactive)
   (require 'mail-utils)
-  (if rmail-enable-mime
+  ;; FIXME This does not handle rmail-mime-feature != 'rmailmm.
+  ;; There is no API defined for rmail-mime-feature to provide
+  ;; rmail-mime-message-p, rmail-mime-toggle-raw equivalents.
+  ;; But does anyone actually use rmail-mime-feature != 'rmailmm?
+  (if (and rmail-enable-mime
+          (eq rmail-mime-feature 'rmailmm)
+          (featurep rmail-mime-feature))
       (with-current-buffer rmail-buffer
        (if (rmail-mime-message-p)
            (let ((rmail-mime-mbox-buffer rmail-view-buffer)
@@ -4193,29 +4251,25 @@ This has an effect only if a summary buffer exists."
 
 ;; Put the summary buffer back on the screen, if user wants that.
 (defun rmail-maybe-display-summary ()
-  (let ((selected (selected-window))
-       window)
-    ;; If requested, make sure the summary is displayed.
-    (and rmail-summary-buffer (buffer-name rmail-summary-buffer)
-        rmail-redisplay-summary
-        (if (get-buffer-window rmail-summary-buffer 0)
-            ;; It's already in some frame; show that one.
-            (let ((frame (window-frame
-                          (get-buffer-window rmail-summary-buffer 0))))
-              (make-frame-visible frame)
-              (raise-frame frame))
-          (display-buffer rmail-summary-buffer)))
-    ;; If requested, set the height of the summary window.
-    (and rmail-summary-buffer (buffer-name rmail-summary-buffer)
-        rmail-summary-window-size
-        (setq window (get-buffer-window rmail-summary-buffer))
-        ;; Don't try to change the size if just one window in frame.
-        (not (eq window (frame-root-window (window-frame window))))
-        (unwind-protect
-            (progn
-              (select-window window)
-              (enlarge-window (- rmail-summary-window-size (window-height))))
-          (select-window selected)))))
+  (cond
+   ((or (not rmail-summary-buffer)
+       (not (buffer-name rmail-summary-buffer))))
+   (rmail-redisplay-summary
+    ;; If `rmail-redisplay-summary' is non-nil, make sure the summary
+    ;; buffer is displayed.
+    (display-buffer
+     rmail-summary-buffer
+     `(nil
+       (reusable-frames . 0)
+       ,(when rmail-summary-window-size
+         `(window-height . ,rmail-summary-window-size)))))
+   (rmail-summary-window-size
+    ;; If `rmail-summary-window-size' is non-nil and the summary buffer
+    ;; is displayed, make sure it gets resized.
+    (let ((window (get-buffer-window rmail-summary-buffer 0)))
+      (when window
+       (window-resize-no-error
+        window (- rmail-summary-window-size (window-height window))))))))
 \f
 ;;;; *** Rmail Local Fontification ***
 
@@ -4256,8 +4310,6 @@ This has an effect only if a summary buffer exists."
                  (restore-buffer-modified-p nil)))))))
 \f
 ;;; Speedbar support for RMAIL files.
-(eval-when-compile (require 'speedbar))
-
 (defcustom rmail-speedbar-match-folder-regexp "^[A-Z0-9]+\\(\\.[A-Z0-9]+\\)?$"
   "Regexp matching Rmail folder names to be displayed in Speedbar.
 Enabling this permits Speedbar to display your folders for easy
@@ -4272,12 +4324,12 @@ browsing, and moving of messages."
 (defvar rmail-speedbar-key-map nil
   "Keymap used when in rmail display mode.")
 
+(declare-function speedbar-make-specialized-keymap "speedbar" ())
+
 (defun rmail-install-speedbar-variables ()
   "Install those variables used by speedbar to enhance rmail."
-  (if rmail-speedbar-key-map
-      nil
+  (unless rmail-speedbar-key-map
     (setq rmail-speedbar-key-map (speedbar-make-specialized-keymap))
-
     (define-key rmail-speedbar-key-map "e" 'speedbar-edit-line)
     (define-key rmail-speedbar-key-map "r" 'speedbar-edit-line)
     (define-key rmail-speedbar-key-map "\C-m" 'speedbar-edit-line)
@@ -4292,6 +4344,9 @@ browsing, and moving of messages."
                     (looking-at "<M> "))])
   "Additional menu-items to add to speedbar frame.")
 
+(declare-function speedbar-insert-button "speedbar"
+                 (text face mouse function &optional token prevline))
+
 ;; Make sure our special speedbar major mode is loaded
 (if (featurep 'speedbar)
     (rmail-install-speedbar-variables)
@@ -4333,19 +4388,27 @@ current message into that RMAIL folder."
            (speedbar-insert-button file 'speedbar-file-face 'highlight
                                    'rmail-speedbar-find-file nil t)))))))
 
+(eval-when-compile (require 'dframe))
+;; Part of the macro expansion of dframe-with-attached-buffer.
+;; At runtime, will be pulled in as a require of speedbar.
+(declare-function dframe-select-attached-frame "dframe" (&optional frame))
+(declare-function dframe-maybee-jump-to-attached-frame "dframe" ())
+
 (defun rmail-speedbar-button (text token indent)
   "Execute an rmail command specified by TEXT.
 The command used is TOKEN.  INDENT is not used."
-  (speedbar-with-attached-buffer
+  (dframe-with-attached-buffer
    (funcall token t)))
 
 (defun rmail-speedbar-find-file (text token indent)
   "Load in the rmail file TEXT.
 TOKEN and INDENT are not used."
-  (speedbar-with-attached-buffer
+  (dframe-with-attached-buffer
    (message "Loading in RMAIL file %s..." text)
    (rmail text)))
 
+(declare-function speedbar-do-function-pointer "speedbar" ())
+
 (defun rmail-speedbar-move-message-to-folder-on-line ()
   "If the current line is a folder, move current message to it."
   (interactive)
@@ -4359,7 +4422,7 @@ TOKEN and INDENT are not used."
 (defun rmail-speedbar-move-message (text token indent)
   "From button TEXT, copy current message to the rmail file specified by TOKEN.
 TEXT and INDENT are not used."
-  (speedbar-with-attached-buffer
+  (dframe-with-attached-buffer
    (message "Moving message to %s" token)
    ;; expand-file-name is needed due to the unhelpful way in which
    ;; rmail-output expands non-absolute filenames against rmail-default-file.
@@ -4550,7 +4613,7 @@ encoded string (and the same mask) will decode the string."
 ;;; Start of automatically extracted autoloads.
 \f
 ;;;### (autoloads (rmail-edit-current-message) "rmailedit" "rmailedit.el"
-;;;;;;  "78b8b7d5c679935c118d595d473d7c5e")
+;;;;;;  "0b056146d4775080a1847b8ce7527bc5")
 ;;; Generated autoloads from rmailedit.el
 
 (autoload 'rmail-edit-current-message "rmailedit" "\
@@ -4562,7 +4625,7 @@ Edit the contents of this message.
 \f
 ;;;### (autoloads (rmail-next-labeled-message rmail-previous-labeled-message
 ;;;;;;  rmail-read-label rmail-kill-label rmail-add-label) "rmailkwd"
-;;;;;;  "rmailkwd.el" "4ae5660d86d49e524f4a6bcbc6d9a984")
+;;;;;;  "rmailkwd.el" "b5337290fd35bbc11888afb25d767195")
 ;;; Generated autoloads from rmailkwd.el
 
 (autoload 'rmail-add-label "rmailkwd" "\
@@ -4605,7 +4668,7 @@ With prefix argument N moves forward N messages with these labels.
 
 ;;;***
 \f
-;;;### (autoloads (rmail-mime) "rmailmm" "rmailmm.el" "f1937f85a1258de8880a089fa5ae5621")
+;;;### (autoloads nil "rmailmm" "rmailmm.el" "8c14f4cf6e7dacb0c94fd300d814caf7")
 ;;; Generated autoloads from rmailmm.el
 
 (autoload 'rmail-mime "rmailmm" "\
@@ -4632,7 +4695,7 @@ The arguments ARG and STATE have no effect in this case.
 ;;;***
 \f
 ;;;### (autoloads (set-rmail-inbox-list) "rmailmsc" "rmailmsc.el"
-;;;;;;  "e2212ea15561d60365ffa1f7a5902939")
+;;;;;;  "8a2466563b4a463710531d01766c07a3")
 ;;; Generated autoloads from rmailmsc.el
 
 (autoload 'set-rmail-inbox-list "rmailmsc" "\
@@ -4648,7 +4711,7 @@ This applies only to the current session.
 \f
 ;;;### (autoloads (rmail-sort-by-labels rmail-sort-by-lines rmail-sort-by-correspondent
 ;;;;;;  rmail-sort-by-recipient rmail-sort-by-author rmail-sort-by-subject
-;;;;;;  rmail-sort-by-date) "rmailsort" "rmailsort.el" "38da5f17d4ed0dcd2b09c158642cef63")
+;;;;;;  rmail-sort-by-date) "rmailsort" "rmailsort.el" "3e3a30326fc95d7f17835906c2ccb19f")
 ;;; Generated autoloads from rmailsort.el
 
 (autoload 'rmail-sort-by-date "rmailsort" "\
@@ -4705,9 +4768,7 @@ If prefix argument REVERSE is non-nil, sorts in reverse order.
 
 ;;;***
 \f
-;;;### (autoloads (rmail-summary-by-senders rmail-summary-by-topic
-;;;;;;  rmail-summary-by-regexp rmail-summary-by-recipients rmail-summary-by-labels
-;;;;;;  rmail-summary) "rmailsum" "rmailsum.el" "856fc6e337d5398b302c448ee7a2315e")
+;;;### (autoloads nil "rmailsum" "rmailsum.el" "9005bd5da3e21d1cc173e86fd9fec3c9")
 ;;; Generated autoloads from rmailsum.el
 
 (autoload 'rmail-summary "rmailsum" "\
@@ -4755,7 +4816,7 @@ SENDERS is a string of regexps separated by commas.
 ;;;***
 \f
 ;;;### (autoloads (unforward-rmail-message undigestify-rmail-message)
-;;;;;;  "undigest" "undigest.el" "9f270a2571bbbbfabc27498a8d4089c7")
+;;;;;;  "undigest" "undigest.el" "9b273a3e15b5496ab6121b585d8bd3b3")
 ;;; Generated autoloads from undigest.el
 
 (autoload 'undigestify-rmail-message "undigest" "\