Subject: bug#58227: 29.0.50; gnus-read-ephemeral-bug-group overrides `coding` cookie in url/cookies

From: Stefan Monnier <[email-masked]>
Date: Sat, 01 Oct 2022 10:35:33 -0400

Package: Emacs
Version: 29.0.50

`gnus-read-ephemeral-bug-group` can cause the ~/emacs.d/url/cookies
file (which is labeled with a `coding: utf-8-emacs-unix` cookie) to be
read as a binary file.  This may look somewhat minor but it's a symptom
of a further reaching problem.

The code does the following:

          (let ((coding-system-for-write 'binary)
                (coding-system-for-read 'binary))
            (with-temp-file tmpfile
              (mm-disable-multibyte)
              (dolist (id ids)
                (let ((file (expand-file-name id (locate-user-emacs-file
                                                  "debbugs-cache"))))
                  (if (and (not gnus-plugged)
                           (file-exists-p file))
                      (insert-file-contents file)
                    ;; Pass non-nil VISIT to avoid errors with non-nil
                    ;; `url-automatic-caching' (bug#26063, bug#29008)
                    ;; and immediately unvisit.
                    ;; FIXME: This masks real errors!
                    (url-insert-file-contents (format mbox-url id) t)
                    (setq buffer-file-name nil))))
	      (goto-char (point-min))
              ;; Throw an informative error early instead of passing nonsense
              ;; to `gnus-group-read-ephemeral-group' (bug#36433).
              (unless (save-excursion (re-search-forward delim nil t))
                (error "Invalid mbox format for bug IDs: %s"
                       (string-join ids ", ")))
              (while (re-search-forward delim nil t)
                (narrow-to-region (point)
                                  (if (search-forward "\n\n" nil t)
                                      (1- (point))
                                    (point-max)))
                (unless (string-match-p address-re
                                        (concat (message-fetch-field "to") " "
                                                (message-fetch-field "cc")))
                  (goto-char (point-min))
                  (if (not (re-search-forward "^To:" nil t))
                      (insert "To: " address "\n")
		    (message-next-header)
		    (skip-chars-backward "\t\n ")
                    (insert ", " address)))
                (goto-char (point-max))
                (widen))))

Any ELisp source file loaded while executing this code (such as
autoloaded files, or ~/.emacs.d/url/cookies which gets read via
url-insert-file-contents => url-retrieve-synchronously => url-do-setup
=> url-cookie-parse-file) will be decoded as a binary file rather than
as UTF-8.

And any other auxiliary reading/writing of files and processes that
could be happening along the way would also be affected by the
`coding-system-for-read/write` bindings.

This is a general problem with let-binding
`coding-system-for-read/write`, which is sometimes the only way to get
what we need from ELisp.  In this case, maybe we can use
`insert-file-contents-literally` (and maybe we should introduce
a `url-insert-file-contents-literally` too?).

        Stefan