aboutsummaryrefslogtreecommitdiffstats
path: root/lisp/mail
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/mail')
-rw-r--r--lisp/mail/rmail.el83
-rw-r--r--lisp/mail/rmailmm.el4
-rw-r--r--lisp/mail/sendmail.el88
-rw-r--r--lisp/mail/smtpmail.el66
4 files changed, 166 insertions, 75 deletions
diff --git a/lisp/mail/rmail.el b/lisp/mail/rmail.el
index c43ec9e561..ac07f07a76 100644
--- a/lisp/mail/rmail.el
+++ b/lisp/mail/rmail.el
@@ -4249,7 +4249,7 @@ TEXT and INDENT are not used."
;; rmail-output expands non-absolute filenames against rmail-default-file.
;; What is the point of that, anyway?
(rmail-output (expand-file-name token))))
-
+
;; 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,"
@@ -4300,6 +4300,85 @@ encoded string (and the same mask) will decode the string."
(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)))))))))))))
+
;;;; Desktop support
(defun rmail-restore-desktop-buffer (desktop-buffer-file-name
@@ -4403,7 +4482,7 @@ With prefix argument N moves forward N messages with these labels.
;;;***
-;;;### (autoloads (rmail-mime) "rmailmm" "rmailmm.el" "a7d3e7205efa4e20ca9038c9b260ce83")
+;;;### (autoloads (rmail-mime) "rmailmm" "rmailmm.el" "2c8675d7c069c68bc36a4003b15448d1")
;;; Generated autoloads from rmailmm.el
(autoload 'rmail-mime "rmailmm" "\
diff --git a/lisp/mail/rmailmm.el b/lisp/mail/rmailmm.el
index 597068562b..d335125558 100644
--- a/lisp/mail/rmailmm.el
+++ b/lisp/mail/rmailmm.el
@@ -426,7 +426,7 @@ The value is a vector [ INDEX HEADER TAGLINE BODY END], where
"Insert a tag line for MIME-entity ENTITY.
ITEM-LIST is a list of strings or button-elements (list) to be added
to the tag line."
- (insert "[")
+ (insert "\n[")
(let ((tag (aref (rmail-mime-entity-tagline entity) 0)))
(if (> (length tag) 0) (insert (substring tag 1) ":")))
(insert (car (rmail-mime-entity-type entity)) " ")
@@ -439,7 +439,7 @@ to the tag line."
(if (stringp item)
(insert item)
(apply 'insert-button item))))
- (insert "]\n"))
+ (insert "]\n\n"))
(defun rmail-mime-update-tagline (entity)
"Update the current tag line for MIME-entity ENTITY."
diff --git a/lisp/mail/sendmail.el b/lisp/mail/sendmail.el
index fe20ad921d..cb02a4b374 100644
--- a/lisp/mail/sendmail.el
+++ b/lisp/mail/sendmail.el
@@ -156,49 +156,6 @@ This is used by the default mail-sending commands. See also
:version "24.1"
:group 'sendmail)
-(defvar sendmail-query-once-function 'query
- "Either a function to send email, or the symbol `query'.")
-
-;;;###autoload
-(defun sendmail-query-once ()
- "Send an email via `sendmail-query-once-function'.
-If `sendmail-query-once-function' is `query', ask the user what
-function to use, and then save that choice."
- (when (equal sendmail-query-once-function 'query)
- (let* ((default
- (cond
- ((or (and window-system (eq system-type 'darwin))
- (eq system-type 'windows-nt))
- 'mailclient-send-it)
- ((and sendmail-program
- (executable-find sendmail-program))
- 'sendmail-send-it)))
- (function
- (if (or (not default)
- ;; We have detected no OS-level mail senders, or we
- ;; have already configured smtpmail, so we use the
- ;; internal SMTP service.
- (and (boundp 'smtpmail-smtp-server)
- smtpmail-smtp-server))
- 'smtpmail-send-it
- ;; Query the user.
- (unwind-protect
- (progn
- (pop-to-buffer "*Mail Help*")
- (erase-buffer)
- (insert "Sending mail from Emacs hasn't been set up yet.\n\n"
- "Type `y' to configure outgoing SMTP, or `n' to use\n"
- "the default mail sender on your system.\n\n"
- "To change this again at a later date, customize the\n"
- "`send-mail-function' variable.\n")
- (goto-char (point-min))
- (if (y-or-n-p "Configure outgoing SMTP in Emacs? ")
- 'smtpmail-send-it
- default))
- (kill-buffer (current-buffer))))))
- (customize-save-variable 'sendmail-query-once-function function)))
- (funcall sendmail-query-once-function))
-
;;;###autoload
(defcustom mail-header-separator (purecopy "--text follows this line--")
"Line used to separate headers from text in messages being composed."
@@ -541,6 +498,51 @@ by Emacs.)")
"Additional expressions to highlight in Mail mode.")
+;;;###autoload
+(defun sendmail-query-once ()
+ "Query for `send-mail-function' and send mail with it.
+This also saves the value of `send-mail-function' via Customize."
+ (let* ((mail-buffer (current-buffer))
+ ;; Compute default mail sender, preferring smtpmail if it's
+ ;; already configured.
+ (default (cond
+ ((and (boundp 'smtpmail-smtp-server)
+ smtpmail-smtp-server)
+ 'smtpmail-send-it)
+ ((or (and window-system (eq system-type 'darwin))
+ (eq system-type 'windows-nt))
+ 'mailclient-send-it)
+ ((and sendmail-program
+ (executable-find sendmail-program))
+ 'sendmail-send-it)))
+ (send-function (if (eq default 'smtpmail-send-it)
+ 'smtpmail-send-it)))
+ (unless send-function
+ ;; Query the user.
+ (with-temp-buffer
+ (rename-buffer "*Mail Help*" t)
+ (erase-buffer)
+ (insert "Emacs has not been set up for sending mail.\n
+Type `y' to configure and use Emacs as a mail client,
+or `n' to use your system's default mailer.\n
+To change your decision later, customize `send-mail-function'.\n")
+ (goto-char (point-min))
+ (display-buffer (current-buffer))
+ (if (y-or-n-p "Set up Emacs for sending SMTP mail? ")
+ ;; FIXME: We should check and correct the From: field too.
+ (setq send-function 'smtpmail-send-it)
+ (setq send-function default))))
+ (when send-function
+ (customize-save-variable 'send-mail-function send-function)
+ ;; HACK: Message mode stupidly has `message-send-mail-function',
+ ;; so we must update it too or sending again in the current
+ ;; Emacs session will still call `sendmail-query-once'.
+ (and (boundp 'message-send-mail-function)
+ (eq message-send-mail-function 'sendmail-query-once)
+ (customize-set-variable 'message-send-mail-function
+ send-function))
+ (funcall send-function))))
+
(defun sendmail-sync-aliases ()
(when mail-personal-alias-file
(let ((modtime (nth 5 (file-attributes mail-personal-alias-file))))
diff --git a/lisp/mail/smtpmail.el b/lisp/mail/smtpmail.el
index cc46660712..544570a1bc 100644
--- a/lisp/mail/smtpmail.el
+++ b/lisp/mail/smtpmail.el
@@ -55,15 +55,12 @@
;;; Code:
(require 'sendmail)
+(require 'auth-source)
(autoload 'mail-strip-quoted-names "mail-utils")
(autoload 'message-make-date "message")
(autoload 'message-make-message-id "message")
(autoload 'rfc2104-hash "rfc2104")
-(autoload 'netrc-parse "netrc")
-(autoload 'netrc-machine "netrc")
-(autoload 'netrc-get "netrc")
(autoload 'password-read "password-cache")
-(autoload 'auth-source-search "auth-source")
;;;
(defgroup smtpmail nil
@@ -89,6 +86,12 @@ The default value would be \"smtp\" or 25."
:type '(choice (integer :tag "Port") (string :tag "Service"))
:group 'smtpmail)
+(defcustom smtpmail-smtp-user nil
+ "User name to use when looking up credentials."
+ :version "24.1"
+ :type '(choice (const nil) string)
+ :group 'smtpmail)
+
(defcustom smtpmail-local-domain nil
"Local domain name without a host name.
If the function `system-name' returns the full internet address,
@@ -487,12 +490,13 @@ The list is in preference order.")
(let* ((mechs (cdr-safe (assoc 'auth supported-extensions)))
(mech (car (smtpmail-intersection mechs smtpmail-auth-supported)))
(auth-source-creation-prompts
- '((user . "SMTP user at %h: ")
+ '((user . "SMTP user name for %h: ")
(secret . "SMTP password for %u@%h: ")))
(auth-info (car
(auth-source-search
:host host
:port port
+ :user smtpmail-smtp-user
:max 1
:require (and ask-for-password
'(:user :secret))
@@ -502,6 +506,8 @@ The list is in preference order.")
(save-function (and ask-for-password
(plist-get auth-info :save-function)))
ret)
+ (when (functionp password)
+ (setq password (funcall password)))
(when (and user
(not password))
;; The user has stored the user name, but not the password, so
@@ -513,6 +519,7 @@ The list is in preference order.")
:max 1
:host host
:port port
+ :user smtpmail-smtp-user
:require '(:user :secret)
:create t))
password (plist-get auth-info :secret)))
@@ -589,15 +596,17 @@ The list is in preference order.")
(defun smtpmail-query-smtp-server ()
(let ((server (read-string "Outgoing SMTP mail server: "))
- (ports '(587 "smtp"))
+ (ports '("smtp" 587))
stream port)
(when (and smtpmail-smtp-server
(not (member smtpmail-smtp-server ports)))
(push smtpmail-smtp-server ports))
(while (and (not smtpmail-smtp-server)
(setq port (pop ports)))
- (when (setq stream (ignore-errors
- (open-network-stream "smtp" nil server port)))
+ (when (setq stream (condition-case ()
+ (open-network-stream "smtp" nil server port)
+ (quit nil)
+ (error nil)))
(customize-save-variable 'smtpmail-smtp-server server)
(customize-save-variable 'smtpmail-smtp-service port)
(delete-process stream)))
@@ -618,8 +627,6 @@ The list is in preference order.")
(and mail-specify-envelope-from
(mail-envelope-from))
user-mail-address))
- (coding-system-for-read 'binary)
- (coding-system-for-write 'binary)
response-code
process-buffer
result
@@ -638,21 +645,23 @@ The list is in preference order.")
(erase-buffer))
;; open the connection to the server
- (setq result
- (open-network-stream
- "smtpmail" process-buffer host port
- :type smtpmail-stream-type
- :return-list t
- :capability-command (format "EHLO %s\r\n" (smtpmail-fqdn))
- :end-of-command "^[0-9]+ .*\r\n"
- :success "^2.*\n"
- :always-query-capabilities t
- :starttls-function
- (lambda (capabilities)
- (and (string-match "-STARTTLS" capabilities)
- "STARTTLS\r\n"))
- :client-certificate t
- :use-starttls-if-possible t))
+ (let ((coding-system-for-read 'binary)
+ (coding-system-for-write 'binary))
+ (setq result
+ (open-network-stream
+ "smtpmail" process-buffer host port
+ :type smtpmail-stream-type
+ :return-list t
+ :capability-command (format "EHLO %s\r\n" (smtpmail-fqdn))
+ :end-of-command "^[0-9]+ .*\r\n"
+ :success "^2.*\n"
+ :always-query-capabilities t
+ :starttls-function
+ (lambda (capabilities)
+ (and (string-match "-STARTTLS" capabilities)
+ "STARTTLS\r\n"))
+ :client-certificate t
+ :use-starttls-if-possible t)))
;; If we couldn't access the server at all, we give up.
(unless (setq process (car result))
@@ -669,7 +678,7 @@ The list is in preference order.")
(throw 'done (format "No greeting: %s" greeting)))
(when (>= code 400)
(throw 'done (format "Connection not allowed: %s" greeting))))
-
+
(with-current-buffer process-buffer
(set-buffer-process-coding-system 'raw-text-unix 'raw-text-unix)
(make-local-variable 'smtpmail-read-point)
@@ -722,7 +731,7 @@ The list is in preference order.")
(when (member 'xusr supported-extensions)
(smtpmail-command-or-throw process (format "XUSR")))
-
+
;; MAIL FROM:<sender>
(let ((size-part
(if (or (member 'size supported-extensions)
@@ -761,7 +770,7 @@ The list is in preference order.")
)
((and auth-mechanisms
(not ask-for-password)
- (= (car result) 530))
+ (eq (car result) 530))
;; We got a "530 auth required", so we close and try
;; again, this time asking the user for a password.
(smtpmail-send-command process "QUIT")
@@ -788,6 +797,7 @@ The list is in preference order.")
nil)
((and auth-mechanisms
(not ask-for-password)
+ (integerp (car result))
(>= (car result) 550)
(<= (car result) 554))
;; We got a "550 relay not permitted" (or the like),