Subject: bug#70994: [PATCH] Make cache regeneration work in group names with /

From: James Thomas <[email-masked]>
Date: Fri, 17 May 2024 10:26:36 +0530

Reproduction steps for bug:

- emacs -Q
- (setq gnus-secondary-select-methods
    '((nnatom "github.com/vedang/pdf-tools/commits.atom")))
  (setq gnus-select-method '(nnnil ""))
- M-x gnus
- Open a message in the new group and press *
- Add the cache virtual server (info "(gnus) Creating a Virtual Server")
- ^ (server buffer) and: g on the cache
- RET to open (fails)

This is a possible fix that I've tested only on my (limited) setup, for
now:

From 1252b4541b265f6da13c07d9a2ce16fdecd51731 Mon Sep 17 00:00:00 2001
From: James Thomas <[email-masked]>
Date: Fri, 17 May 2024 10:18:14 +0530
Subject: [PATCH] Make cache regeneration work in group names with /

* lisp/gnus/nnheader.el (nnheader-file-to-group): Account for /
in the last part of the group name.
* lisp/gnus/nnmail.el (nnmail-group-pathname): Url-encode only
the last part of the group name.
---
 lisp/gnus/nnheader.el | 25 +++++++++++++++----------
 lisp/gnus/nnmail.el   | 19 ++++++++++++++++---
 2 files changed, 31 insertions(+), 13 deletions(-)

diff --git a/lisp/gnus/nnheader.el b/lisp/gnus/nnheader.el
index ea679759f3e..85a9f1bd8af 100644
--- a/lisp/gnus/nnheader.el
+++ b/lisp/gnus/nnheader.el
@@ -827,16 +827,21 @@ nnheader-replace-duplicate-chars-in-string

 (defun nnheader-file-to-group (file &optional top)
   "Return a group name based on FILE and TOP."
-  (nnheader-replace-chars-in-string
-   (if (not top)
-       file
-     (condition-case ()
-	 (substring (expand-file-name file)
-		    (length
-		     (expand-file-name
-		      (file-name-as-directory top))))
-       (error "")))
-   nnheader-directory-separator-character ?.))
+  (setq file
+        (if (not top)
+            file
+          (condition-case ()
+	      (substring (expand-file-name file)
+		         (length
+		          (expand-file-name
+		           (file-name-as-directory top))))
+            (error ""))))
+  ;; The last part could have slashes.
+  (concat
+   (nnheader-replace-chars-in-string
+    (file-name-directory file)
+    nnheader-directory-separator-character ?.)
+   (url-unhex-string (file-name-nondirectory file))))

 (defun nnheader-message (level &rest args)
   "Message if the Gnus backends are talkative."
diff --git a/lisp/gnus/nnmail.el b/lisp/gnus/nnmail.el
index a9f5b89c6fe..0e1bcf849ce 100644
--- a/lisp/gnus/nnmail.el
+++ b/lisp/gnus/nnmail.el
@@ -627,9 +627,21 @@ nnmail-group-pathname
   "Make file name for GROUP."
   (concat
    (let ((dir (file-name-as-directory (expand-file-name dir))))
+     (setq group
+           ;; The last part is allowed slashes. So url-encode.
+           (let ((split-list (split-string group "\\.")))
+             (string-join
+              (append
+               (butlast split-list)
+               (list (browse-url-url-encode-chars
+                      (car (last split-list))
+                      (concat "[%"
+                       (char-to-string
+                        nnheader-directory-separator-character)
+                       "]"))))
+	      ".")))
      (setq group (nnheader-replace-duplicate-chars-in-string
-		  (browse-url-url-encode-chars group "[/%]")
-		  ?. ?_))
+		  group ?. ?_))
      (setq group (nnheader-translate-file-chars group))
      ;; If this directory exists, we use it directly.
      (file-name-as-directory
@@ -638,7 +650,8 @@ nnmail-group-pathname
 	  (expand-file-name group dir)
 	;; If not, we translate dots into slashes.
 	(expand-file-name
-	 (nnheader-replace-chars-in-string group ?. ?/)
+	 (nnheader-replace-chars-in-string
+          group ?. nnheader-directory-separator-character)
 	 dir))))
    (or file "")))

--
2.40.1

Regards,
James