aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNikolaus Rath2018-07-23 10:21:46 +0100
committerEli Zaretskii2018-08-11 10:46:02 +0300
commit31263d67d591cf2c074fad4f17b968b87c88b5e2 (patch)
tree27805e891b106956a6a4b0b592817557ad9efe1a
parent3f8324e0de182945a809f63766cf9611aa45610c (diff)
downloademacs-31263d67d591cf2c074fad4f17b968b87c88b5e2.tar.gz
emacs-31263d67d591cf2c074fad4f17b968b87c88b5e2.zip
Make nnimap support IMAP namespaces
* lisp/gnus/nnimap.el (nnimap-use-namespaces): Introduce new server variable. (nnimap-group-to-imap, nnimap-get-groups): Transform IMAP group names to Gnus group name by stripping / prefixing personal namespace prefix. (nnimap-open-connection-1): Ask server for namespaces and store them. * lisp/gnus/nnimap.el (nnimap-request-group-scan) (nnimap-request-create-group, nnimap-request-delete-group) (nnimap-request-rename-group, nnimap-request-move-article) (nnimap-process-expiry-targets) (nnimap-request-update-group-status) (nnimap-request-accept-article, nnimap-request-list) (nnimap-retrieve-group-data-early, nnimap-change-group) (nnimap-split-incoming-mail): Use nnimap-group-to-imap. (nnimap-group-to-imap): New function to map Gnus group names to IMAP folder names. (Bug#21057)
-rw-r--r--doc/misc/gnus.texi6
-rw-r--r--etc/NEWS7
-rw-r--r--lisp/gnus/nnimap.el93
3 files changed, 79 insertions, 27 deletions
diff --git a/doc/misc/gnus.texi b/doc/misc/gnus.texi
index 6793ed2e9f1..6ccb9e55f31 100644
--- a/doc/misc/gnus.texi
+++ b/doc/misc/gnus.texi
@@ -14320,6 +14320,12 @@ fetch all textual parts, while leaving the rest on the server.
14320If non-@code{nil}, record all @acronym{IMAP} commands in the 14320If non-@code{nil}, record all @acronym{IMAP} commands in the
14321@samp{"*imap log*"} buffer. 14321@samp{"*imap log*"} buffer.
14322 14322
14323@item nnimap-use-namespaces
14324If non-@code{nil}, omit the IMAP namespace prefix in nnimap group
14325names. If your IMAP mailboxes are called something like @samp{INBOX}
14326and @samp{INBOX.Lists.emacs}, but you'd like the nnimap group names to
14327be @samp{INBOX} and @samp{Lists.emacs}, you should enable this option.
14328
14323@end table 14329@end table
14324 14330
14325 14331
diff --git a/etc/NEWS b/etc/NEWS
index 21887f5bfd3..0b1e6499f41 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -53,6 +53,13 @@ option --enable-check-lisp-object-type is therefore no longer as
53useful and so is no longer enabled by default in developer builds, 53useful and so is no longer enabled by default in developer builds,
54to reduce differences between developer and production builds. 54to reduce differences between developer and production builds.
55 55
56** Gnus
57
58+++
59*** The nnimap backend now has support for IMAP namespaces.
60This feature can be enabled by setting the new 'nnimap-use-namespaces'
61server variable to non-nil.
62
56 63
57* Startup Changes in Emacs 27.1 64* Startup Changes in Emacs 27.1
58 65
diff --git a/lisp/gnus/nnimap.el b/lisp/gnus/nnimap.el
index 3b397319272..12892c516a7 100644
--- a/lisp/gnus/nnimap.el
+++ b/lisp/gnus/nnimap.el
@@ -55,6 +55,13 @@
55If nnimap-stream is `ssl', this will default to `imaps'. If not, 55If nnimap-stream is `ssl', this will default to `imaps'. If not,
56it will default to `imap'.") 56it will default to `imap'.")
57 57
58(defvoo nnimap-use-namespaces nil
59 "Whether to use IMAP namespaces.
60If in Gnus your folder names in all start with (e.g.) `INBOX',
61you probably want to set this to t. The effects of this are
62purely cosmetic, but changing this variable will affect the
63names of your nnimap groups. ")
64
58(defvoo nnimap-stream 'undecided 65(defvoo nnimap-stream 'undecided
59 "How nnimap talks to the IMAP server. 66 "How nnimap talks to the IMAP server.
60The value should be either `undecided', `ssl' or `tls', 67The value should be either `undecided', `ssl' or `tls',
@@ -110,6 +117,8 @@ some servers.")
110 117
111(defvoo nnimap-current-infos nil) 118(defvoo nnimap-current-infos nil)
112 119
120(defvoo nnimap-namespace nil)
121
113(defun nnimap-decode-gnus-group (group) 122(defun nnimap-decode-gnus-group (group)
114 (decode-coding-string group 'utf-8)) 123 (decode-coding-string group 'utf-8))
115 124
@@ -166,6 +175,19 @@ textual parts.")
166 175
167(defvar nnimap-inhibit-logging nil) 176(defvar nnimap-inhibit-logging nil)
168 177
178(defun nnimap-group-to-imap (group)
179 "Convert Gnus group name to IMAP mailbox name."
180 (let* ((inbox (if nnimap-namespace
181 (substring nnimap-namespace 0 -1) nil)))
182 (utf7-encode
183 (cond ((or (not inbox)
184 (string-equal group inbox))
185 group)
186 ((string-prefix-p "#" group)
187 (substring group 1))
188 (t
189 (concat nnimap-namespace group))) t)))
190
169(defun nnimap-buffer () 191(defun nnimap-buffer ()
170 (nnimap-find-process-buffer nntp-server-buffer)) 192 (nnimap-find-process-buffer nntp-server-buffer))
171 193
@@ -442,7 +464,8 @@ textual parts.")
442 (props (cdr stream-list)) 464 (props (cdr stream-list))
443 (greeting (plist-get props :greeting)) 465 (greeting (plist-get props :greeting))
444 (capabilities (plist-get props :capabilities)) 466 (capabilities (plist-get props :capabilities))
445 (stream-type (plist-get props :type))) 467 (stream-type (plist-get props :type))
468 (server (nnoo-current-server 'nnimap)))
446 (when (and stream (not (memq (process-status stream) '(open run)))) 469 (when (and stream (not (memq (process-status stream) '(open run))))
447 (setq stream nil)) 470 (setq stream nil))
448 471
@@ -475,9 +498,7 @@ textual parts.")
475 ;; the virtual server name and the address 498 ;; the virtual server name and the address
476 (nnimap-credentials 499 (nnimap-credentials
477 (gnus-delete-duplicates 500 (gnus-delete-duplicates
478 (list 501 (list server nnimap-address))
479 (nnoo-current-server 'nnimap)
480 nnimap-address))
481 ports 502 ports
482 nnimap-user)))) 503 nnimap-user))))
483 (setq nnimap-object nil) 504 (setq nnimap-object nil)
@@ -496,8 +517,17 @@ textual parts.")
496 (dolist (response (cddr (nnimap-command "CAPABILITY"))) 517 (dolist (response (cddr (nnimap-command "CAPABILITY")))
497 (when (string= "CAPABILITY" (upcase (car response))) 518 (when (string= "CAPABILITY" (upcase (car response)))
498 (setf (nnimap-capabilities nnimap-object) 519 (setf (nnimap-capabilities nnimap-object)
499 (mapcar #'upcase (cdr response)))))) 520 (mapcar #'upcase (cdr response)))))
500 ;; If the login failed, then forget the credentials 521 (when (and nnimap-use-namespaces
522 (nnimap-capability "NAMESPACE"))
523 (erase-buffer)
524 (nnimap-wait-for-response (nnimap-send-command "NAMESPACE"))
525 (let ((response (nnimap-last-response-string)))
526 (when (string-match
527 "^\\*\\W+NAMESPACE\\W+((\"\\([^\"\n]+\\)\"\\W+\"\\(.\\)\"))\\W+"
528 response)
529 (setq nnimap-namespace (match-string 1 response))))))
530 ;; If the login failed, then forget the credentials
501 ;; that are now possibly cached. 531 ;; that are now possibly cached.
502 (dolist (host (list (nnoo-current-server 'nnimap) 532 (dolist (host (list (nnoo-current-server 'nnimap)
503 nnimap-address)) 533 nnimap-address))
@@ -837,7 +867,7 @@ textual parts.")
837 (with-current-buffer (nnimap-buffer) 867 (with-current-buffer (nnimap-buffer)
838 (erase-buffer) 868 (erase-buffer)
839 (let ((group-sequence 869 (let ((group-sequence
840 (nnimap-send-command "SELECT %S" (utf7-encode group t))) 870 (nnimap-send-command "SELECT %S" (nnimap-group-to-imap group)))
841 (flag-sequence 871 (flag-sequence
842 (nnimap-send-command "UID FETCH 1:* FLAGS"))) 872 (nnimap-send-command "UID FETCH 1:* FLAGS")))
843 (setf (nnimap-group nnimap-object) group) 873 (setf (nnimap-group nnimap-object) group)
@@ -870,13 +900,13 @@ textual parts.")
870 (setq group (nnimap-decode-gnus-group group)) 900 (setq group (nnimap-decode-gnus-group group))
871 (when (nnimap-change-group nil server) 901 (when (nnimap-change-group nil server)
872 (with-current-buffer (nnimap-buffer) 902 (with-current-buffer (nnimap-buffer)
873 (car (nnimap-command "CREATE %S" (utf7-encode group t)))))) 903 (car (nnimap-command "CREATE %S" (nnimap-group-to-imap group))))))
874 904
875(deffoo nnimap-request-delete-group (group &optional _force server) 905(deffoo nnimap-request-delete-group (group &optional _force server)
876 (setq group (nnimap-decode-gnus-group group)) 906 (setq group (nnimap-decode-gnus-group group))
877 (when (nnimap-change-group nil server) 907 (when (nnimap-change-group nil server)
878 (with-current-buffer (nnimap-buffer) 908 (with-current-buffer (nnimap-buffer)
879 (car (nnimap-command "DELETE %S" (utf7-encode group t)))))) 909 (car (nnimap-command "DELETE %S" (nnimap-group-to-imap group))))))
880 910
881(deffoo nnimap-request-rename-group (group new-name &optional server) 911(deffoo nnimap-request-rename-group (group new-name &optional server)
882 (setq group (nnimap-decode-gnus-group group)) 912 (setq group (nnimap-decode-gnus-group group))
@@ -884,7 +914,7 @@ textual parts.")
884 (with-current-buffer (nnimap-buffer) 914 (with-current-buffer (nnimap-buffer)
885 (nnimap-unselect-group) 915 (nnimap-unselect-group)
886 (car (nnimap-command "RENAME %S %S" 916 (car (nnimap-command "RENAME %S %S"
887 (utf7-encode group t) (utf7-encode new-name t)))))) 917 (nnimap-group-to-imap group) (nnimap-group-to-imap new-name))))))
888 918
889(defun nnimap-unselect-group () 919(defun nnimap-unselect-group ()
890 ;; Make sure we don't have this group open read/write by asking 920 ;; Make sure we don't have this group open read/write by asking
@@ -944,7 +974,7 @@ textual parts.")
944 "UID COPY %d %S")) 974 "UID COPY %d %S"))
945 (result (nnimap-command 975 (result (nnimap-command
946 command article 976 command article
947 (utf7-encode internal-move-group t)))) 977 (nnimap-group-to-imap internal-move-group))))
948 (when (and (car result) (not can-move)) 978 (when (and (car result) (not can-move))
949 (nnimap-delete-article article)) 979 (nnimap-delete-article article))
950 (cons internal-move-group 980 (cons internal-move-group
@@ -1011,7 +1041,7 @@ textual parts.")
1011 "UID MOVE %s %S" 1041 "UID MOVE %s %S"
1012 "UID COPY %s %S") 1042 "UID COPY %s %S")
1013 (nnimap-article-ranges (gnus-compress-sequence articles)) 1043 (nnimap-article-ranges (gnus-compress-sequence articles))
1014 (utf7-encode (gnus-group-real-name nnmail-expiry-target) t)) 1044 (nnimap-group-to-imap (gnus-group-real-name nnmail-expiry-target)))
1015 (set (if can-move 'deleted-articles 'articles-to-delete) articles)))) 1045 (set (if can-move 'deleted-articles 'articles-to-delete) articles))))
1016 t) 1046 t)
1017 (t 1047 (t
@@ -1136,7 +1166,7 @@ If LIMIT, first try to limit the search to the N last articles."
1136 (unsubscribe "UNSUBSCRIBE"))))) 1166 (unsubscribe "UNSUBSCRIBE")))))
1137 (when command 1167 (when command
1138 (with-current-buffer (nnimap-buffer) 1168 (with-current-buffer (nnimap-buffer)
1139 (nnimap-command "%s %S" (cadr command) (utf7-encode group t))))))) 1169 (nnimap-command "%s %S" (cadr command) (nnimap-group-to-imap group)))))))
1140 1170
1141(deffoo nnimap-request-set-mark (group actions &optional server) 1171(deffoo nnimap-request-set-mark (group actions &optional server)
1142 (setq group (nnimap-decode-gnus-group group)) 1172 (setq group (nnimap-decode-gnus-group group))
@@ -1191,7 +1221,7 @@ If LIMIT, first try to limit the search to the N last articles."
1191 (nnimap-unselect-group)) 1221 (nnimap-unselect-group))
1192 (erase-buffer) 1222 (erase-buffer)
1193 (setq sequence (nnimap-send-command 1223 (setq sequence (nnimap-send-command
1194 "APPEND %S {%d}" (utf7-encode group t) 1224 "APPEND %S {%d}" (nnimap-group-to-imap group)
1195 (length message))) 1225 (length message)))
1196 (unless nnimap-streaming 1226 (unless nnimap-streaming
1197 (nnimap-wait-for-connection "^[+]")) 1227 (nnimap-wait-for-connection "^[+]"))
@@ -1271,8 +1301,12 @@ If LIMIT, first try to limit the search to the N last articles."
1271 1301
1272(defun nnimap-get-groups () 1302(defun nnimap-get-groups ()
1273 (erase-buffer) 1303 (erase-buffer)
1274 (let ((sequence (nnimap-send-command "LIST \"\" \"*\"")) 1304 (let* ((sequence (nnimap-send-command "LIST \"\" \"*\""))
1275 groups) 1305 (prefix nnimap-namespace)
1306 (prefix-len (if prefix (length prefix) nil))
1307 (inbox (if prefix
1308 (substring prefix 0 -1) nil))
1309 groups)
1276 (nnimap-wait-for-response sequence) 1310 (nnimap-wait-for-response sequence)
1277 (subst-char-in-region (point-min) (point-max) 1311 (subst-char-in-region (point-min) (point-max)
1278 ?\\ ?% t) 1312 ?\\ ?% t)
@@ -1289,11 +1323,16 @@ If LIMIT, first try to limit the search to the N last articles."
1289 (skip-chars-backward " \r\"") 1323 (skip-chars-backward " \r\"")
1290 (point))))) 1324 (point)))))
1291 (unless (member '%NoSelect flags) 1325 (unless (member '%NoSelect flags)
1292 (push (utf7-decode (if (stringp group) 1326 (let* ((group (utf7-decode (if (stringp group) group
1293 group 1327 (format "%s" group)) t))
1294 (format "%s" group)) 1328 (group (cond ((or (not prefix)
1295 t) 1329 (equal inbox group))
1296 groups)))) 1330 group)
1331 ((string-prefix-p prefix group)
1332 (substring group prefix-len))
1333 (t
1334 (concat "#" group)))))
1335 (push group groups)))))
1297 (nreverse groups))) 1336 (nreverse groups)))
1298 1337
1299(defun nnimap-get-responses (sequences) 1338(defun nnimap-get-responses (sequences)
@@ -1319,7 +1358,7 @@ If LIMIT, first try to limit the search to the N last articles."
1319 (dolist (group groups) 1358 (dolist (group groups)
1320 (setf (nnimap-examined nnimap-object) group) 1359 (setf (nnimap-examined nnimap-object) group)
1321 (push (list (nnimap-send-command "EXAMINE %S" 1360 (push (list (nnimap-send-command "EXAMINE %S"
1322 (utf7-encode group t)) 1361 (nnimap-group-to-imap group))
1323 group) 1362 group)
1324 sequences)) 1363 sequences))
1325 (nnimap-wait-for-response (caar sequences)) 1364 (nnimap-wait-for-response (caar sequences))
@@ -1391,7 +1430,7 @@ If LIMIT, first try to limit the search to the N last articles."
1391 unexist) 1430 unexist)
1392 (push 1431 (push
1393 (list (nnimap-send-command "EXAMINE %S (%s (%s %s))" 1432 (list (nnimap-send-command "EXAMINE %S (%s (%s %s))"
1394 (utf7-encode group t) 1433 (nnimap-group-to-imap group)
1395 (nnimap-quirk "QRESYNC") 1434 (nnimap-quirk "QRESYNC")
1396 uidvalidity modseq) 1435 uidvalidity modseq)
1397 'qresync 1436 'qresync
@@ -1413,7 +1452,7 @@ If LIMIT, first try to limit the search to the N last articles."
1413 (cl-incf (nnimap-initial-resync nnimap-object)) 1452 (cl-incf (nnimap-initial-resync nnimap-object))
1414 (setq start 1)) 1453 (setq start 1))
1415 (push (list (nnimap-send-command "%s %S" command 1454 (push (list (nnimap-send-command "%s %S" command
1416 (utf7-encode group t)) 1455 (nnimap-group-to-imap group))
1417 (nnimap-send-command "UID FETCH %d:* FLAGS" start) 1456 (nnimap-send-command "UID FETCH %d:* FLAGS" start)
1418 start group command) 1457 start group command)
1419 sequences)))) 1458 sequences))))
@@ -1847,7 +1886,7 @@ Return the server's response to the SELECT or EXAMINE command."
1847 (if read-only 1886 (if read-only
1848 "EXAMINE" 1887 "EXAMINE"
1849 "SELECT") 1888 "SELECT")
1850 (utf7-encode group t)))) 1889 (nnimap-group-to-imap group))))
1851 (when (car result) 1890 (when (car result)
1852 (setf (nnimap-group nnimap-object) group 1891 (setf (nnimap-group nnimap-object) group
1853 (nnimap-select-result nnimap-object) result) 1892 (nnimap-select-result nnimap-object) result)
@@ -2105,7 +2144,7 @@ Return the server's response to the SELECT or EXAMINE command."
2105 (dolist (spec specs) 2144 (dolist (spec specs)
2106 (when (and (not (member (car spec) groups)) 2145 (when (and (not (member (car spec) groups))
2107 (not (eq (car spec) 'junk))) 2146 (not (eq (car spec) 'junk)))
2108 (nnimap-command "CREATE %S" (utf7-encode (car spec) t)))) 2147 (nnimap-command "CREATE %S" (nnimap-group-to-imap (car spec)))))
2109 ;; Then copy over all the messages. 2148 ;; Then copy over all the messages.
2110 (erase-buffer) 2149 (erase-buffer)
2111 (dolist (spec specs) 2150 (dolist (spec specs)
@@ -2121,7 +2160,7 @@ Return the server's response to the SELECT or EXAMINE command."
2121 "UID MOVE %s %S" 2160 "UID MOVE %s %S"
2122 "UID COPY %s %S") 2161 "UID COPY %s %S")
2123 (nnimap-article-ranges ranges) 2162 (nnimap-article-ranges ranges)
2124 (utf7-encode group t)) 2163 (nnimap-group-to-imap group))
2125 ranges) 2164 ranges)
2126 sequences))))) 2165 sequences)))))
2127 ;; Wait for the last COPY response... 2166 ;; Wait for the last COPY response...