commit 752894ef54958d5bb6fbf7fc18f4a591d140bf39 (HEAD, refs/remotes/origin/master) Author: Po Lu Date: Mon Sep 29 09:47:02 2025 +0800 ; * configure.ac: Document why AC_CONFIG_SUBDIRS is not suitable for `exec'. diff --git a/configure.ac b/configure.ac index 55f01b9f554..a6a603d8f35 100644 --- a/configure.ac +++ b/configure.ac @@ -191,8 +191,9 @@ AS_IF([test "$XCONFIGURE" = "android"],[ AS_MKDIR_P([exec]) # Enter exec and configure it, using the C compiler as both the - # assembler and the linker. Determine the absolute name of the - # source directory. + # assembler and the linker; it is for this reason that + # AC_CONFIG_SUBDIRS is not suitable in this context. Establish the + # absolute name of the source directory. # N.B. that the linker is actually cc, so pass -nostdlib, lest # the crt be linked in. Likewise for as. commit 52ed6750636beb728b9187f32504d80ae075c856 Author: Liu Hui Date: Fri Sep 5 21:32:47 2025 +0800 Fix etags-regen-mode for remote projects (bug#79358) * lisp/progmodes/etags-regen.el (etags-regen--process-file-region): New function. (etags-regen--tags-generate, etags-regen--append-tags): Use the new helper function to run the program, and use relative file name if TAGS file is in the project root. (etags-regen--update-file): Use relative file name if possible. diff --git a/lisp/progmodes/etags-regen.el b/lisp/progmodes/etags-regen.el index cde82956c24..ed18eb5a564 100644 --- a/lisp/progmodes/etags-regen.el +++ b/lisp/progmodes/etags-regen.el @@ -271,11 +271,43 @@ File extensions to generate the tags for." ;; Either match a full name segment, or eos. "\\(?:/\\|\\'\\)")))) +(defun etags-regen--process-file-region ( start end program + &optional output-buffer error-buffer + &rest args) + (let ((error-file (and error-buffer (make-temp-file "erpfr-err"))) + infile) + (unwind-protect + (progn + (if (not (file-remote-p default-directory)) + (if (and start end) + (apply #'call-process-region + start end program nil + (list output-buffer error-file) nil args) + (apply #'call-process + program nil (list output-buffer error-file) nil args)) + (when (and start end) + (setq infile (make-temp-file "erpfr")) + (write-region start end infile nil 'silent)) + (apply #'process-file + program infile (list output-buffer error-file) nil args)) + (when (and error-file + (file-exists-p error-file) + (< 0 (file-attribute-size (file-attributes error-file)))) + (with-current-buffer (get-buffer-create error-buffer) + (erase-buffer) + (format-insert-file error-file nil) + (display-buffer (current-buffer))))) + (if infile (delete-file infile)) + (if error-file (delete-file error-file))))) + (defun etags-regen--tags-generate (proj) (let* ((root (project-root proj)) (default-directory root) (files (etags-regen--all-files proj)) (tags-file (etags-regen--choose-tags-file proj)) + (fun (if (equal (file-name-directory tags-file) + (expand-file-name root)) + #'file-relative-name #'file-local-name)) (ctags-p (etags-regen--ctags-p)) (command (format "%s %s %s - -o %s" etags-regen-program @@ -284,13 +316,19 @@ File extensions to generate the tags for." " ") ;; ctags's etags requires '-L' for stdin input. (if ctags-p "-L" "") - (shell-quote-argument tags-file)))) + (shell-quote-argument (file-local-name tags-file))))) (with-temp-buffer (mapc (lambda (f) - (insert f "\n")) + (insert (funcall fun f) "\n")) files) - (shell-command-on-region (point-min) (point-max) command - nil nil etags-regen--errors-buffer-name t)) + (with-connection-local-variables + (etags-regen--process-file-region (point-min) + (point-max) + shell-file-name + nil + etags-regen--errors-buffer-name + shell-command-switch + command))) (etags-regen--visit-table tags-file root))) (defun etags-regen--visit-table (tags-file root) @@ -334,6 +372,9 @@ File extensions to generate the tags for." (get-file-buffer etags-regen--tags-file))) (relname (concat "/" (file-relative-name file-name etags-regen--tags-root))) + (fun (if (equal (file-name-directory etags-regen--tags-file) + (expand-file-name etags-regen--tags-root)) + #'file-relative-name #'file-local-name)) (ignores etags-regen-ignores) pr should-scan) (save-excursion @@ -347,7 +388,7 @@ File extensions to generate the tags for." (set-buffer tags-file-buf) (setq should-scan t)) ((progn (set-buffer tags-file-buf) - (etags-regen--remove-tag file-name)) + (etags-regen--remove-tag (funcall fun file-name))) (setq should-scan t)))) (when (and should-scan (not (cl-some @@ -376,15 +417,17 @@ File extensions to generate the tags for." (defun etags-regen--append-tags (&rest file-names) (goto-char (point-max)) (let ((options (etags-regen--build-program-options (etags-regen--ctags-p))) + (fun (if (equal (file-name-directory etags-regen--tags-file) + (expand-file-name etags-regen--tags-root)) + #'file-relative-name #'file-local-name)) (inhibit-read-only t)) - ;; XXX: call-process is significantly faster, though. - ;; Like 10ms vs 20ms here. But `shell-command' makes it easy to - ;; direct stderr to a separate buffer. - (shell-command - (format "%s %s -o - %s" - etags-regen-program (mapconcat #'identity options " ") - (mapconcat #'identity file-names " ")) - t etags-regen--errors-buffer-name)) + (with-connection-local-variables + (etags-regen--process-file-region + nil nil shell-file-name t etags-regen--errors-buffer-name + shell-command-switch + (format "%s %s -o - %s" + etags-regen-program (mapconcat #'identity options " ") + (mapconcat fun file-names " "))))) ;; FIXME: Is there a better way to do this? ;; Completion table is the only remaining place where the ;; update is not incremental. commit 38c658de7de0d9b1caa41f8261aa11c81aa9faa5 Author: Eli Zaretskii Date: Sun Sep 28 15:35:17 2025 +0300 Make textsec descriptive texts more user-friendly * lisp/international/textsec.el (textsec-domain-suspicious-p) (textsec-local-address-suspicious-p, textsec-name-suspicious-p) (textsec-suspicious-nonspacing-p): Clarify descriptive texts. diff --git a/lisp/international/textsec.el b/lisp/international/textsec.el index ffb652a823f..25d422e6029 100644 --- a/lisp/international/textsec.el +++ b/lisp/international/textsec.el @@ -290,7 +290,7 @@ or use certain other unusual mixtures of characters." (lambda (char) (when (eq (elt idna-mapping-table char) t) (throw 'found - (format "Disallowed character%s (#x%x, %s)" + (format "Disallowed character in domain%s (#x%x, %s)" (if (eq (get-char-code-property char 'general-category) 'Cf) "" @@ -308,7 +308,8 @@ or use certain other unusual mixtures of characters." ;; an ASCII-only segment. (dolist (elem (split-string domain "\\.")) (when (textsec-ascii-confusable-p elem) - (throw 'found (format "`%s' is confusable with ASCII" elem)))) + (throw 'found (format "`%s' includes characters confusable with ASCII" + elem)))) nil)) (defun textsec-local-address-suspicious-p (local) @@ -323,14 +324,14 @@ that can look similar to other characters when displayed, or use certain other unusual mixtures of characters." (cond ((not (equal local (ucs-normalize-NFKC-string local))) - (format "`%s' is not in normalized format `%s'" + (format "`%s' is not in normalized form `%s', its display might deceive" local (ucs-normalize-NFKC-string local))) ((textsec-mixed-numbers-p local) (format "`%s' contains numbers from different number systems" local)) ((eq (textsec-restriction-level local) 'unrestricted) - (format "`%s' isn't restrictive enough" local)) + (format "`%s' uses characters from too many unusual scripts" local)) ((string-match-p "\\`\\.\\|\\.\\'\\|\\.\\." local) - (format "`%s' contains invalid dots" local)))) + (format "`%s' contains invalid dot characters" local)))) (defun textsec-bidi-controls-suspicious-p (string) "Return non-nil of STRING uses bidirectional controls in suspicious ways. @@ -364,7 +365,7 @@ look similar to other characters when displayed, or use certain other unusual mixtures of characters." (cond ((not (equal name (ucs-normalize-NFC-string name))) - (format "`%s' is not in normalized format `%s'" + (format "`%s' is not in normalized form `%s', its display might deceive" name (ucs-normalize-NFC-string name))) ((and (seq-find (lambda (char) (and (member char bidi-control-characters) @@ -403,13 +404,13 @@ consecutive nonspacing characters." '(Mn Me)))) (when (and nonspacing (equal char prev)) - (throw 'found "Two identical consecutive nonspacing characters")) + (throw 'found "Two identical consecutive accent/diacritic characters")) (setq nonspace-count (if nonspacing (1+ nonspace-count) 0)) (when (> nonspace-count 4) (throw 'found - "Too many consecutive nonspacing characters")) + "Too many consecutive accent/diacritic characters")) (setq prev char))) string) nil))) commit 3f230d84656156c3bf5296f618e1bfe1bb8866ad Author: Eli Zaretskii Date: Sun Sep 28 14:35:46 2025 +0300 Detect suspicious email addresses in Rmail and Sendmail * lisp/mail/rmail.el (rmail-detect-suspicious-headers): New user option. (rmail-check-suspicious-from): New function, highlights suspicious "From" addresses. (rmail-show-message-1): Call 'rmail-check-suspicious-from' if 'rmail-detect-suspicious-headers' is non-nil. * lisp/mail/sendmail.el (mail-send): Detect suspicious addresses before sending. * etc/NEWS: Announce the new features. diff --git a/etc/NEWS b/etc/NEWS index a402811f473..320f7e40fb7 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1623,6 +1623,16 @@ Predefined values include visiting the file in Emacs, jumping to the file in Dired, or opening the file with an external program. You can also provide a custom function. +--- +*** Rmail now detects email messages from suspicious sender addresses. +If the "From" header of a message contains a suspicious email address, +Rmail will now highlight it in a distinct face and provide a 'help-echo' +tooltip explaining the reason. (What exactly is considered as +suspicious email addresses is determined by the function +'textsec-suspicious-p', which see.) This is controlled by the new user +option 'rmail-detect-suspicious-headers', whose default value is +non-nil; customize to nil to disable the check. + ** Message +++ @@ -1634,6 +1644,17 @@ honored if it was already set. +++ *** 'message-strip-subject-re' now matches case-insensitively. +** Sendmail + +--- +*** Sending an email via 'sendmail' checks for suspicious addressees. +The command 'mail-send', used to send email in Mail mode, now checks the +addressees for suspicious email addresses. If such addresses are found, +the command will show them and the reason they are considered +suspicious, and will request a confirmation before sending the message. +This follows the behavior of Message mode, and affects users who +customize 'mail-user-agent' to the value 'sendmail-user-agent'. + ** SHR +++ diff --git a/lisp/mail/rmail.el b/lisp/mail/rmail.el index b8aa937aec2..c298496d641 100644 --- a/lisp/mail/rmail.el +++ b/lisp/mail/rmail.el @@ -2753,6 +2753,64 @@ See also `unrmail-mbox-format'." :group 'rmail :version "28.1") +(defcustom rmail-detect-suspicious-headers t + "If non-nil, detect and highlight suspicious email addresses in Rmail buffer. +Currently, only the From address is checked." + :type 'boolean + :version "31.1" + :group 'rmail + :group 'security) + +(defun rmail-check-suspicious-from () + "Look for suspicious email addresses in message headers; highlight if found. +This checks the From header of the email message using `textsec-suspicious-p', +and if a suspicious address is found, highlights it with a specialized +face. + +Should be called with point at the beginning of the message." + (save-excursion + (search-forward "\n\n" nil 'move) + (save-restriction + (narrow-to-region (point-min) (point)) + (goto-char (point-min)) + (let ((case-fold-search t) + (inhibit-read-only t) + (overlays rmail-overlay-list)) + (when (re-search-forward "^From:" nil t) + (skip-chars-forward " \t") + (let ((beg (point)) + end from overlay) + (while (progn (forward-line 1) + (looking-at "[ \t]"))) + ;; Back up over newline, then trailing spaces or tabs + (forward-char -1) + (skip-chars-backward " \t" beg) + (setq end (point) + ;; RFC 2047 encode to escape quotes and other + ;; problematic characters. + from (rfc2047-encode-string + (buffer-substring-no-properties beg end))) + ;; Is "From" address suspicious? If yes, make it stand out. + (when-let* ((warning (textsec-suspicious-p + from 'email-address-header))) + (if overlays + ;; Reuse an overlay we already have. + (progn + (setq overlay (car overlays) + overlays (cdr overlays)) + (overlay-put overlay 'face 'textsec-suspicious) + ;; Override any other faces + (overlay-put overlay 'priority 100) + (move-overlay overlay beg end)) + ;; Make a new overlay and add it to + ;; rmail-overlay-list. + (setq overlay (make-overlay beg end)) + (overlay-put overlay 'face 'textsec-suspicious) + (overlay-put overlay 'priority 100) + (setq rmail-overlay-list + (cons overlay rmail-overlay-list))) + (insert (propertize "⚠️" 'help-echo warning))))))))) + (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 @@ -2882,6 +2940,8 @@ The current mail message becomes the message displayed." (rmail-highlight-headers) ;(rmail-activate-urls) ;(rmail-process-quoted-material) + (if rmail-detect-suspicious-headers + (rmail-check-suspicious-from)) ) ;; Update the mode-line with message status information and swap ;; the view buffer/mail buffer contents. diff --git a/lisp/mail/sendmail.el b/lisp/mail/sendmail.el index fda10cdfefe..e61a79d33f9 100644 --- a/lisp/mail/sendmail.el +++ b/lisp/mail/sendmail.el @@ -29,6 +29,7 @@ ;;; Code: (require 'mail-utils) (require 'rfc2047) +(require 'mail-parse) (autoload 'message-make-date "message") (autoload 'message-narrow-to-headers "message") @@ -934,7 +935,7 @@ the user from the mailer." (error "Message contains non-ASCII characters")))) ;; Complain about any invalid line. (goto-char (point-min)) - ;; Search for mail-header-eeparator as whole line. + ;; Search for mail-header-separator as whole line. (re-search-forward (concat "^" (regexp-quote mail-header-separator) "$") (point-max) t) (let ((header-end (or (match-beginning 0) (point-max)))) @@ -944,6 +945,24 @@ the user from the mailer." (push-mark opoint) (error "Invalid header line (maybe a continuation line lacks initial whitespace)")) (forward-line 1))) + ;; Check for suspicious addresses and ask for confirmation if found. + (save-restriction + (goto-char (point-min)) + (narrow-to-region (point-min) (mail-header-end)) + (dolist (hdr '("To" "Cc" "Bcc")) + (let ((addr (mail-fetch-field hdr))) + (when (stringp addr) + (dolist (address (mail-header-parse-addresses addr t)) + (when-let* ((warning (textsec-suspicious-p + ;; RFC 2047 encode to escape + ;; quotes and other problematic + ;; characters. + (rfc2047-encode-string address) + 'email-address-header))) + (unless (y-or-n-p + (format "Suspicious address: %s; send anyway?" + warning)) + (user-error "Suspicious \"%s\" address %s" hdr address)))))))) (goto-char opoint) (require 'mml) (when (or mail-encode-mml