(defvar messages-head)
(defvar total-messages)
(defvar tool-bar-map)
+(defvar mail-encode-mml)
(defvar rmail-header-style 'normal
"The current header display style choice, one of
(declare-function mail-dont-reply-to "mail-utils" (destinations))
(declare-function rmail-update-summary "rmailsum" (&rest ignore))
+(declare-function rmail-mime-toggle-hidden "rmailmm" ())
(defun rmail-probe (prog)
"Determine what flavor of movemail PROG is.
:group 'rmail-headers)
;;;###autoload
-(defcustom rmail-retry-ignored-headers (purecopy "^x-authentication-warning:\\|^x-detected-operating-system:\\|^x-spam[-a-z]*:\\|content-type:\\|content-transfer-encoding:\\|mime-version:")
+(defcustom rmail-retry-ignored-headers (purecopy "^x-authentication-warning:\\|^x-detected-operating-system:\\|^x-spam[-a-z]*:\\|content-type:\\|content-transfer-encoding:\\|mime-version:\\|message-id:")
"Headers that should be stripped when retrying a failed message."
:type '(choice regexp (const nil :tag "None"))
:group 'rmail-headers
\"subject\" or \"from\". A FIELD of \"to\" will automatically include
all text from the \"cc\" field as well.
-REGEXP is an expression to match in the preceeding specified FIELD.
+REGEXP is an expression to match in the preceding specified FIELD.
FIELD/REGEXP pairs continue in the list.
examples:
This is set to nil by default.")
(defcustom rmail-enable-mime t
- "If non-nil, RMAIL uses MIME features.
-If the value is t, RMAIL automatically shows MIME decoded message.
-If the value is neither t nor nil, RMAIL does not show MIME decoded message
-until a user explicitly requires it.
-
-Even if the value is non-nil, you can't use MIME features
-unless the feature specified by `rmail-mime-feature' is available."
- :type '(choice (const :tag "on" t)
- (const :tag "off" nil)
- (other :tag "when asked" ask))
+ "If non-nil, RMAIL automatically displays decoded MIME messages.
+For this to work, the feature specified by `rmail-mime-feature' must
+be available."
+ :type 'boolean
:version "23.3"
:group 'rmail)
-(defvar rmail-enable-mime-composing nil
+(defvar rmail-enable-mime-composing t
"*If non-nil, RMAIL uses `rmail-insert-mime-forwarded-message-function' to forward.")
-;; FIXME unused.
(defvar rmail-show-mime-function nil
- "Function to show MIME decoded message of RMAIL file.
+ "Function of no argument called to show a decoded MIME message.
This function is called when `rmail-enable-mime' is non-nil.
-It is called with no argument.")
+The package providing MIME support should set this.")
;;;###autoload
(defvar rmail-insert-mime-forwarded-message-function nil
expression, LIMIT is the position specifying the end of header.")
(defvar rmail-mime-feature 'rmailmm
- "Feature to require to load MIME support in Rmail.
+ "Feature to require for MIME support in Rmail.
When starting Rmail, if `rmail-enable-mime' is non-nil,
this feature is required with `require'.
(display-warning
'rmail
(format "Although MIME support is requested
-by setting `rmail-enable-mime' to non-nil, the required feature
+through `rmail-enable-mime' being non-nil, the required feature
`%s' (the value of `rmail-mime-feature')
is not available in the current session.
-So, the MIME support is turned off for the moment."
+So, MIME support is turned off for the moment."
rmail-mime-feature)
:warning)
(setq rmail-enable-mime nil)))))
(define-key map "\e\C-l" 'rmail-summary-by-labels)
(define-key map "\e\C-r" 'rmail-summary-by-recipients)
(define-key map "\e\C-s" 'rmail-summary-by-regexp)
+ (define-key map "\e\C-f" 'rmail-summary-by-senders)
(define-key map "\e\C-t" 'rmail-summary-by-topic)
(define-key map "m" 'rmail-mail)
(define-key map "\em" 'rmail-retry-failure)
(define-key map "/" 'rmail-end-of-message)
(define-key map "<" 'rmail-first-message)
(define-key map ">" 'rmail-last-message)
- (define-key map " " 'scroll-up)
- (define-key map "\177" 'scroll-down)
+ (define-key map " " 'scroll-up-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)
(define-key map "\C-c\C-s\C-s" 'rmail-sort-by-subject)
(if (and (local-variable-p 'rmail-view-buffer)
(buffer-live-p rmail-view-buffer))
rmail-view-buffer
- (generate-new-buffer
- (format " *message-viewer %s*"
- (file-name-nondirectory (or buffer-file-name (buffer-name)))))))
+ (let ((newbuf
+ (generate-new-buffer
+ (format " *message-viewer %s*"
+ (file-name-nondirectory
+ (or buffer-file-name (buffer-name)))))))
+ (with-current-buffer newbuf
+ (add-hook 'kill-buffer-hook 'rmail-view-buffer-kill-buffer-hook nil t))
+ newbuf)))
(defun rmail-swap-buffers ()
"Swap text between current buffer and `rmail-view-buffer'.
(message "Marking buffer unmodified to avoid rewriting Babyl file as mbox file")))
(defun rmail-mode-kill-buffer-hook ()
- (if (buffer-live-p rmail-view-buffer) (kill-buffer rmail-view-buffer)))
+ ;; Turn off the hook on the view buffer, so we can kill it, then kill it.
+ (if (buffer-live-p rmail-view-buffer)
+ (with-current-buffer rmail-view-buffer
+ (setq kill-buffer-hook nil)
+ (kill-buffer rmail-view-buffer))))
+
+(defun rmail-view-buffer-kill-buffer-hook ()
+ (error "Can't kill message view buffer by itself"))
;; Set up the permanent locals associated with an Rmail file.
(defun rmail-perm-variables ()
(make-local-variable 'file-precious-flag)
(setq file-precious-flag t)
(make-local-variable 'desktop-save-buffer)
- (setq desktop-save-buffer t))
+ (setq desktop-save-buffer t)
+ (setq next-error-move-function 'rmail-next-error-move))
\f
;; Handle M-x revert-buffer done in an rmail-mode buffer.
(defun rmail-revert (arg noconfirm)
(setq all-files (cdr all-files)))
;; Put them back in their original order.
(setq files (nreverse files))
- ;; In case of brain damage caused by require-final-newline.
(goto-char (point-max))
- (skip-chars-backward " \t\n")
- (delete-region (point) (point-max))
+ ;; Make sure we end with a blank line unless there are
+ ;; no messages, as required by mbox format (Bug#9974).
+ (unless (bobp)
+ (while (not (looking-back "\n\n"))
+ (insert "\n")))
(setq found (or
(rmail-get-new-mail-1 file-name files delete-files)
found))))
(rmail-unrmail-new-mail-maybe
tofile
(nth 1 (insert-file-contents tofile))))
- ;; Determine if a pair of newline message separators need
- ;; to be added to the new collection of messages. This is
- ;; the case for all new message collections added to a
- ;; non-empty mail file.
- (unless (zerop size)
- (save-restriction
- (let ((start (point-min)))
- (widen)
- (unless (eq start (point-min))
- (goto-char start)
- (insert "\n\n")
- (setq size (+ 2 size))))))
(goto-char (point-max))
- (or (= (preceding-char) ?\n)
- (zerop size)
- (insert ?\n))
+ ;; Make sure the read-in mbox data properly ends with a
+ ;; blank line unless it is of size 0.
+ (unless (zerop size)
+ (while (not (looking-back "\n\n"))
+ (insert "\n")))
(if (not (and rmail-preserve-inbox (string= file tofile)))
(setq delete-files (cons tofile delete-files)))))
(message "")
(defun rmail-add-mbox-headers ()
"Validate the RFC2822 format for the new messages.
Point should be at the first new message.
-An error is signalled if the new messages are not RFC2822
+An error is signaled if the new messages are not RFC2822
compliant.
Unless an Rmail attribute header already exists, add it to the
new messages. Return the number of new messages."
;;;; *** Rmail Message Selection And Support ***
(defun rmail-msgend (n)
- "Return the start position for message number N."
+ "Return the end position for message number N."
(marker-position (aref rmail-message-vector (1+ n))))
(defun rmail-msgbeg (n)
- "Return the end position for message number N."
+ "Return the start position for message number N."
(marker-position (aref rmail-message-vector n)))
(defun rmail-apply-in-message (msgnum function &rest args)
;; the entry for message N+1, which marks
;; the end of message N. (N = number of messages).
(setq messages-head (list (point-marker)))
- (setq messages-after-point
+ (setq messages-after-point
(or (rmail-set-message-counters-counter (min (point) point-save))
0))
"Return nil if there is mail, else \"No mail.\"."
(if (zerop rmail-total-messages)
(save-excursion
+ ;; Eg we deleted all the messages, so remove the old N/M mark.
+ (with-current-buffer rmail-buffer (setq mode-line-process nil))
(with-current-buffer rmail-view-buffer
(erase-buffer)
"No mail."))))
(t (setq rmail-current-message msg)))
(with-current-buffer rmail-buffer
(setq header-style rmail-header-style)
- ;; Mark the message as seen
- (rmail-set-attribute rmail-unseen-attr-index nil)
+ ;; Mark the message as seen, but preserve buffer modified flag.
+ (let ((modiff (buffer-modified-p)))
+ (rmail-set-attribute rmail-unseen-attr-index nil)
+ (unless modiff
+ (restore-buffer-modified-p modiff)))
;; bracket the message in the mail
;; buffer and determine the coding system the transfer encoding.
(rmail-swap-buffers-maybe)
;; inspect this value to determine how to toggle.
(set (make-local-variable 'rmail-header-style) header-style))
(if (and rmail-enable-mime
+ rmail-show-mime-function
(re-search-forward "mime-version: 1.0" nil t))
(let ((rmail-buffer mbox-buf)
(rmail-view-buffer view-buf))
(rmail-maybe-set-message-counters)
(rmail-show-message rmail-total-messages))
-(defun rmail-what-message ()
- "For debugging Rmail: find the message number that point is in."
+(defun rmail-next-error-move (msg-pos bad-marker)
+ "Move to an error locus (probably grep hit) in an Rmail buffer.
+MSG-POS is a marker pointing at the error message in the grep buffer.
+BAD-MARKER is a marker that ought to point at where to move to,
+but probably is garbage."
+
+ (let* ((message-loc (compilation--message->loc
+ (get-text-property msg-pos 'compilation-message
+ (marker-buffer msg-pos))))
+ (column (car message-loc))
+ (linenum (cadr message-loc))
+ line-text
+ pos
+ msgnum msgbeg msgend
+ header-field
+ line-number-within)
+
+ ;; Look at the whole Rmail file.
+ (rmail-swap-buffers-maybe)
+
+ (save-restriction
+ (widen)
+ (save-excursion
+ ;; Find the line that the error message points at.
+ (goto-char (point-min))
+ (forward-line (1- linenum))
+ (setq pos (point))
+
+ ;; Find the text at the start of the line,
+ ;; before the first = sign.
+ ;; This text has a good chance of being also in the
+ ;; decoded message.
+ (save-excursion
+ (skip-chars-forward "^=\n")
+ (setq line-text (buffer-substring pos (point))))
+
+ ;; Find which message this position is in,
+ ;; and the limits of that message.
+ (setq msgnum (rmail-what-message pos))
+ (setq msgbeg (rmail-msgbeg msgnum))
+ (setq msgend (rmail-msgend msgnum))
+
+ ;; Find which header this locus is in,
+ ;; or if it's in the message body,
+ ;; and the line-based position within that.
+ (goto-char msgbeg)
+ (let ((header-end msgend))
+ (if (search-forward "\n\n" nil t)
+ (setq header-end (point)))
+ (if (>= pos header-end)
+ (setq line-number-within
+ (count-lines header-end pos))
+ (goto-char pos)
+ (unless (looking-at "^[^ \t]")
+ (re-search-backward "^[^ \t]"))
+ (looking-at "[^:\n]*[:\n]")
+ (setq header-field (match-string 0)
+ line-number-within (count-lines (point) pos))))))
+
+ ;; Display the right message.
+ (rmail-show-message msgnum)
+
+ ;; Move to the right position within the displayed message.
+ ;; Or at least try. The decoded message's lines may not
+ ;; correspond to the lines in the inbox file.
+ (goto-char (point-min))
+ (if header-field
+ (progn
+ (re-search-forward (concat "^" (regexp-quote header-field)) nil t)
+ (forward-line line-number-within))
+ (search-forward "\n\n" nil t)
+ (if (re-search-forward (concat "^" (regexp-quote line-text)) nil t)
+ (goto-char (match-beginning 0))))
+ (if (eobp)
+ ;; If the decoded message doesn't have enough lines,
+ ;; go to the beginning rather than the end.
+ (goto-char (point-min))
+ ;; Otherwise, go to the right column.
+ (if column
+ (forward-char column)))))
+
+(defun rmail-what-message (&optional pos)
+ "Return message number POS (or point) is in."
(let* ((high rmail-total-messages)
(mid (/ high 2))
(low 1)
- (where (with-current-buffer (if (rmail-buffers-swapped-p)
- rmail-view-buffer
- (current-buffer))
- (point))))
+ (where (or pos
+ (with-current-buffer (if (rmail-buffers-swapped-p)
+ rmail-view-buffer
+ (current-buffer))
+ (point)))))
(while (> (- high low) 1)
(if (>= where (rmail-msgbeg mid))
(setq low mid)
Simplifying the subject means stripping leading and trailing whitespace,
and typical reply prefixes such as Re:."
(let ((subject (or (rmail-get-header "Subject" msgnum) "")))
+ (setq subject (rfc2047-decode-string subject))
(if (string-match "\\`[ \t]+" subject)
(setq subject (substring subject (match-end 0))))
(if (string-match rmail-reply-regexp subject)
(setq yank-action (list 'insert-buffer replybuffer)))
(push (cons "cc" cc) other-headers)
(push (cons "in-reply-to" in-reply-to) other-headers)
+ (setq other-headers
+ (mapcar #'(lambda (elt)
+ (cons (car elt) (if (stringp (cdr elt))
+ (rfc2047-decode-string (cdr elt)))))
+ other-headers))
+ (if (stringp to) (setq to (rfc2047-decode-string to)))
+ (if (stringp in-reply-to)
+ (setq in-reply-to (rfc2047-decode-string in-reply-to)))
+ (if (stringp cc) (setq cc (rfc2047-decode-string cc)))
+ (if (stringp subject) (setq subject (rfc2047-decode-string subject)))
(prog1
(compose-mail to subject other-headers noerase
- switch-function yank-action sendactions
- '(rmail-mail-return))
+ switch-function yank-action sendactions)
(if (eq switch-function 'switch-to-buffer-other-frame)
;; This is not a standard frame parameter; nothing except
;; sendmail.el looks at it.
- (modify-frame-parameters (selected-frame)
+ (modify-frame-parameters (selected-frame)
'((mail-dedicated-frame . t)))))))
-(defun rmail-mail-return ()
+(defun rmail-mail-return (&optional newbuf)
+ "NEWBUF is a buffer to switch to."
(cond
;; If there is only one visible frame with no special handling,
;; consider deleting the mail window to return to Rmail.
(if rmail-flag
;; If the Rmail buffer has a summary, show that.
(if summary-buffer (switch-to-buffer summary-buffer)
- (delete-window)))))
+ (delete-window))
+ (switch-to-buffer newbuf))))
;; If the frame was probably made for this buffer, the user
;; probably wants to delete it now.
((display-multi-frame-p)
;; Insert after header separator--before signature if any.
(rfc822-goto-eoh)
(forward-line 1)
- (if (or rmail-enable-mime rmail-enable-mime-composing)
- (funcall rmail-insert-mime-forwarded-message-function
- forward-buffer)
+ (if (and rmail-enable-mime rmail-enable-mime-composing)
+ (prog1
+ (funcall rmail-insert-mime-forwarded-message-function
+ forward-buffer)
+ ;; rmail-insert-mime-forwarded-message-function
+ ;; works by inserting MML tags into forward-buffer.
+ ;; The MUA will need to convert it to MIME before
+ ;; sending. mail-encode-mml tells them to do that.
+ ;; message.el does that automagically.
+ (or (eq mail-user-agent 'message-user-agent)
+ (setq mail-encode-mml t)))
(insert "------- Start of forwarded message -------\n")
;; Quote lines with `- ' if they start with `-'.
(let ((beg (point)) end)
;; rmail-output expands non-absolute filenames against rmail-default-file.
;; What is the point of that, anyway?
(rmail-output (expand-file-name token))))
-
+\f
;; Functions for setting, getting and encoding the POP password.
;; The password is encoded to prevent it from being easily accessible
;; to "prying eyes." Obviously, this encoding isn't "real security,"
(setq i (1+ i)))
(concat string-vector)))
+(defun rmail-epa-decrypt ()
+ "Decrypt OpenPGP armors in current message."
+ (interactive)
+
+ ;; Save the current buffer here for cleanliness, in case we
+ ;; change it in one of the calls to `epa-decrypt-region'.
+
+ (save-excursion
+ (let (decrypts)
+ (goto-char (point-min))
+
+ ;; In case the encrypted data is inside a mime attachment,
+ ;; show it. This is a kludge; to be clean, it should not
+ ;; modify the buffer, but I don't see how to do that.
+ (when (search-forward "octet-stream" nil t)
+ (beginning-of-line)
+ (forward-button 1)
+ (if (looking-at "Show")
+ (rmail-mime-toggle-hidden)))
+
+ ;; Now find all armored messages in the buffer
+ ;; and decrypt them one by one.
+ (goto-char (point-min))
+ (while (re-search-forward "-----BEGIN PGP MESSAGE-----$" nil t)
+ (let ((coding-system-for-read coding-system-for-read)
+ armor-start armor-end after-end)
+ (setq armor-start (match-beginning 0)
+ armor-end (re-search-forward "^-----END PGP MESSAGE-----$"
+ nil t))
+ (unless armor-end
+ (error "Encryption armor beginning has no matching end"))
+ (goto-char armor-start)
+
+ ;; Because epa--find-coding-system-for-mime-charset not autoloaded.
+ (require 'epa)
+
+ ;; Use the charset specified in the armor.
+ (unless coding-system-for-read
+ (if (re-search-forward "^Charset: \\(.*\\)" armor-end t)
+ (setq coding-system-for-read
+ (epa--find-coding-system-for-mime-charset
+ (intern (downcase (match-string 1)))))))
+
+ ;; Advance over this armor.
+ (goto-char armor-end)
+ (setq after-end (- (point-max) armor-end))
+
+ ;; Decrypt it, maybe in place, maybe making new buffer.
+ (epa-decrypt-region
+ armor-start armor-end
+ ;; Call back this function to prepare the output.
+ (lambda ()
+ (let ((inhibit-read-only t))
+ (delete-region armor-start armor-end)
+ (goto-char armor-start)
+ (current-buffer))))
+
+ (push (list armor-start (- (point-max) after-end))
+ decrypts)))
+
+ (when (and decrypts (rmail-buffers-swapped-p))
+ (when (y-or-n-p "Replace the original message? ")
+ (setq decrypts (nreverse decrypts))
+ (let ((beg (rmail-msgbeg rmail-current-message))
+ (end (rmail-msgend rmail-current-message))
+ (from-buffer (current-buffer)))
+ (with-current-buffer rmail-view-buffer
+ (narrow-to-region beg end)
+ (goto-char (point-min))
+ (dolist (d decrypts)
+ (if (re-search-forward "-----BEGIN PGP MESSAGE-----$" nil t)
+ (let (armor-start armor-end)
+ (setq armor-start (match-beginning 0)
+ armor-end (re-search-forward "^-----END PGP MESSAGE-----$"
+ nil t))
+ (when armor-end
+ (delete-region armor-start armor-end)
+ (insert-buffer-substring from-buffer (nth 0 d) (nth 1 d)))))))))))))
+\f
;;;; Desktop support
(defun rmail-restore-desktop-buffer (desktop-buffer-file-name
;;;***
\f
-;;;### (autoloads (rmail-mime) "rmailmm" "rmailmm.el" "04902da045706fb7f2b0915529ed161b")
+;;;### (autoloads (rmail-mime) "rmailmm" "rmailmm.el" "5d992206e382290d07ad7d9a2bf250c9")
;;; Generated autoloads from rmailmm.el
(autoload 'rmail-mime "rmailmm" "\
\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" "3817e21639db697abe5832d3223ecfc2")
+;;;;;; rmail-summary) "rmailsum" "rmailsum.el" "35e07b0a5ea8e41971f31a8780eba6bb")
;;; Generated autoloads from rmailsum.el
(autoload 'rmail-summary "rmailsum" "\