>From 2f05bec6c1d928e16cc345af35d51c391d88a3ce Mon Sep 17 00:00:00 2001 From: Nikolaus Rath Date: Tue, 14 Jul 2015 19:03:09 -0700 Subject: [PATCH 2/2] nnimap.el: Add support for IMAP namespaces. * lisp/nnimap.el (nnimap-use-namespaces): introduced 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/ChangeLog | 7 +++++++ lisp/nnimap.el | 65 +++++++++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 60 insertions(+), 12 deletions(-) diff --git a/lisp/ChangeLog b/lisp/ChangeLog index be5d3fb..27de0d0 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,10 @@ +2015-07-14 Nikolaus Rath + + * nnimap.el (nnimap-use-namespaces): introduced 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. + 2015-07-12 Nikolaus Rath * nnimap.el (nnimap-request-group-scan) diff --git a/lisp/nnimap.el b/lisp/nnimap.el index 19632ad..8cbf187 100644 --- a/lisp/nnimap.el +++ b/lisp/nnimap.el @@ -62,6 +62,13 @@ If nnimap-stream is `ssl', this will default to `imaps'. If not, it will default to `imap'.") +(defvoo nnimap-use-namespaces nil + "Whether to use IMAP namespaces +If in Gnus your folder names in all start with (e.g.) `INBOX', +you probably want to set this to t. The effects of this are +purely cosmetical, but changing this variable will affect the +names of your nnimap groups. ") + (defvoo nnimap-stream 'undecided "How nnimap talks to the IMAP server. The value should be either `undecided', `ssl' or `tls', @@ -124,6 +131,8 @@ some servers.") (defvoo nnimap-current-infos nil) +(setq nnimap-namespaces nil) + (defvoo nnimap-fetch-partial-articles nil "If non-nil, Gnus will fetch partial articles. If t, Gnus will fetch only the first part. If a string, it @@ -180,7 +189,17 @@ If non-nil, articles flagged as deleted (using the IMAP (defun nnimap-group-to-imap (group) "Convert Gnus group name to IMAP mailbox name" - (utf7-encode group t)) + (let* ((prefix (cadr (assoc (nnoo-current-server 'nnimap) + nnimap-namespaces))) + (inbox (substring prefix 0 -1))) + (utf7-encode + (cond ((or (not prefix) + (string-equal group inbox)) + group) + ((string-prefix-p "#" group) + (substring group 1)) + (t + (concat prefix group))) t))) (defun nnimap-buffer () (nnimap-find-process-buffer nntp-server-buffer)) @@ -467,7 +486,8 @@ If non-nil, articles flagged as deleted (using the IMAP (props (cdr stream-list)) (greeting (plist-get props :greeting)) (capabilities (plist-get props :capabilities)) - (stream-type (plist-get props :type))) + (stream-type (plist-get props :type)) + (server (nnoo-current-server 'nnimap))) (when (and stream (not (memq (process-status stream) '(open run)))) (setq stream nil)) @@ -502,9 +522,7 @@ If non-nil, articles flagged as deleted (using the IMAP ;; the virtual server name and the address (nnimap-credentials (gnus-delete-duplicates - (list - (nnoo-current-server 'nnimap) - nnimap-address)) + (list server nnimap-address)) ports nnimap-user)))) (setq nnimap-object nil) @@ -523,7 +541,21 @@ If non-nil, articles flagged as deleted (using the IMAP (dolist (response (cddr (nnimap-command "CAPABILITY"))) (when (string= "CAPABILITY" (upcase (car response))) (setf (nnimap-capabilities nnimap-object) - (mapcar #'upcase (cdr response)))))) + (mapcar #'upcase (cdr response))))) + (when (and nnimap-use-namespaces + (nnimap-capability "NAMESPACE")) + (erase-buffer) + (nnimap-wait-for-response (nnimap-send-command "NAMESPACE")) + (let ((response (nnimap-last-response-string))) + (when (string-match + "^\\*\\W+NAMESPACE\\W+((\"\\([^\"\n]+\\)\"\\W+\"\\(.\\)\"))\\W+" + response) + (let ((namespace (cons (match-string 1 response) + (match-string 2 response))) + (entry (assoc server nnimap-namespaces))) + (if entry + (setcdr entry namespace) + (push (cons server namespace) nnimap-namespaces))))))) ;; If the login failed, then forget the credentials ;; that are now possibly cached. (dolist (host (list (nnoo-current-server 'nnimap) @@ -1311,8 +1343,12 @@ If sync is non-nil, wait for server response." (defun nnimap-get-groups () (erase-buffer) - (let ((sequence (nnimap-send-command "LIST \"\" \"*\"")) - groups) + (let* ((sequence (nnimap-send-command "LIST \"\" \"*\"")) + (prefix (cadr (assoc (nnoo-current-server 'nnimap) + nnimap-namespaces))) + (prefix-len (length prefix)) + (inbox (substring prefix 0 -1)) + groups) (nnimap-wait-for-response sequence) (subst-char-in-region (point-min) (point-max) ?\\ ?% t) @@ -1329,10 +1365,15 @@ If sync is non-nil, wait for server response." (skip-chars-backward " \r\"") (point))))) (unless (member '%NoSelect flags) - (push (utf7-decode (if (stringp group) - group - (format "%s" group)) t) - groups)))) + (let* ((group (utf7-decode (if (stringp group) group + (format "%s" group)) t)) + (group (cond ((equal inbox group) + group) + ((string-prefix-p prefix group) + (substring group prefix-len)) + (t + (concat "#" group))))) + (push group groups))))) (nreverse groups))) (defun nnimap-get-responses (sequences) -- 2.1.4