aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lisp/gnus/auth-source.el34
-rw-r--r--lisp/gnus/earcon.el6
-rw-r--r--lisp/gnus/flow-fill.el3
-rw-r--r--lisp/gnus/gnus-agent.el24
-rw-r--r--lisp/gnus/gnus-async.el6
-rw-r--r--lisp/gnus/gnus-bcklg.el18
-rw-r--r--lisp/gnus/gnus-cache.el9
-rw-r--r--lisp/gnus/gnus-demon.el8
-rw-r--r--lisp/gnus/gnus-int.el31
-rw-r--r--lisp/gnus/gnus-kill.el12
-rw-r--r--lisp/gnus/gnus-logic.el3
-rw-r--r--lisp/gnus/gnus-range.el30
-rw-r--r--lisp/gnus/gnus-registry.el6
-rw-r--r--lisp/gnus/gnus-score.el30
-rw-r--r--lisp/gnus/gnus-start.el93
-rw-r--r--lisp/gnus/gnus-sum.el27
-rw-r--r--lisp/gnus/gnus-topic.el6
-rw-r--r--lisp/gnus/gnus-util.el9
-rw-r--r--lisp/gnus/gnus-uu.el66
-rw-r--r--lisp/gnus/gnus.el2
-rw-r--r--lisp/gnus/mm-decode.el6
-rw-r--r--lisp/gnus/mm-partial.el6
-rw-r--r--lisp/gnus/nnagent.el3
-rw-r--r--lisp/gnus/nnbabyl.el35
-rw-r--r--lisp/gnus/nndiary.el38
-rw-r--r--lisp/gnus/nndoc.el21
-rw-r--r--lisp/gnus/nndraft.el9
-rw-r--r--lisp/gnus/nneething.el12
-rw-r--r--lisp/gnus/nnfolder.el39
-rw-r--r--lisp/gnus/nnheader.el3
-rw-r--r--lisp/gnus/nnimap.el2651
-rw-r--r--lisp/gnus/nnir.el3
-rw-r--r--lisp/gnus/nnmail.el53
-rw-r--r--lisp/gnus/nnmaildir.el18
-rw-r--r--lisp/gnus/nnmairix.el46
-rw-r--r--lisp/gnus/nnmbox.el27
-rw-r--r--lisp/gnus/nnml.el42
-rw-r--r--lisp/gnus/nnnil.el3
-rw-r--r--lisp/gnus/nnspool.el15
-rw-r--r--lisp/gnus/nntp.el3
-rw-r--r--lisp/gnus/nnvirtual.el12
-rw-r--r--lisp/gnus/nnweb.el21
-rw-r--r--lisp/gnus/pop3.el21
-rw-r--r--lisp/gnus/smime.el3
-rw-r--r--lisp/gnus/spam-report.el6
-rw-r--r--lisp/gnus/spam.el29
-rw-r--r--lisp/gnus/starttls.el3
-rw-r--r--lisp/gnus/utf7.el1
-rw-r--r--lisp/net/netrc.el1
49 files changed, 1289 insertions, 2264 deletions
diff --git a/lisp/gnus/auth-source.el b/lisp/gnus/auth-source.el
index 5b44c0b9937..a0be0ca8ba4 100644
--- a/lisp/gnus/auth-source.el
+++ b/lisp/gnus/auth-source.el
@@ -107,7 +107,8 @@ Only relevant if `auth-source-debug' is not nil."
107 :version "23.2" ;; No Gnus 107 :version "23.2" ;; No Gnus
108 :type `boolean) 108 :type `boolean)
109 109
110(defcustom auth-sources '((:source "~/.authinfo.gpg")) 110(defcustom auth-sources '((:source "~/.authinfo.gpg")
111 (:source "~/.authinfo"))
111 "List of authentication sources. 112 "List of authentication sources.
112 113
113The default will get login and password information from a .gpg 114The default will get login and password information from a .gpg
@@ -311,20 +312,23 @@ Return structure as specified by MODE."
311 (setq result 312 (setq result
312 (mapcar 313 (mapcar
313 (lambda (m) 314 (lambda (m)
314 (if (equal "password" m) 315 (cond
315 (let ((passwd (read-passwd "Password: "))) 316 ((equal "password" m)
316 (cond 317 (let ((passwd (read-passwd
317 ;; Secret Service API. 318 (format "Password for %s on %s: " prot host))))
318 ((consp source) 319 (cond
319 (apply 320 ;; Secret Service API.
320 'secrets-create-item 321 ((consp source)
321 (auth-get-source entry) name passwd spec)) 322 (apply
322 (t)) ;; netrc not implemented yes. 323 'secrets-create-item
323 passwd) 324 (auth-get-source entry) name passwd spec))
324 (or 325 (t)) ;; netrc not implemented yes.
325 ;; the originally requested :user 326 passwd))
326 user 327 ((equal "login" m)
327 "unknown-user"))) 328 (or user
329 (read-string (format "User name for %s on %s: " prot host))))
330 (t
331 "unknownuser")))
328 (if (consp mode) mode (list mode)))) 332 (if (consp mode) mode (list mode))))
329 (if (consp mode) result (car result)))) 333 (if (consp mode) result (car result))))
330 334
diff --git a/lisp/gnus/earcon.el b/lisp/gnus/earcon.el
index 2578abc073d..2086f86c417 100644
--- a/lisp/gnus/earcon.el
+++ b/lisp/gnus/earcon.el
@@ -151,8 +151,7 @@ If N is negative, move backward instead."
151 151
152(defun earcon-button-push (marker) 152(defun earcon-button-push (marker)
153 ;; Push button starting at MARKER. 153 ;; Push button starting at MARKER.
154 (save-excursion 154 (with-current-buffer gnus-article-buffer
155 (set-buffer gnus-article-buffer)
156 (goto-char marker) 155 (goto-char marker)
157 (let* ((entry (earcon-button-entry)) 156 (let* ((entry (earcon-button-entry))
158 (inhibit-point-motion-hooks t) 157 (inhibit-point-motion-hooks t)
@@ -214,8 +213,7 @@ If N is negative, move backward instead."
214(defun gnus-earcon-display () 213(defun gnus-earcon-display ()
215 "Play sounds in message buffers." 214 "Play sounds in message buffers."
216 (interactive) 215 (interactive)
217 (save-excursion 216 (with-current-buffer gnus-article-buffer
218 (set-buffer gnus-article-buffer)
219 (goto-char (point-min)) 217 (goto-char (point-min))
220 ;; Skip headers 218 ;; Skip headers
221 (unless (search-forward "\n\n" nil t) 219 (unless (search-forward "\n\n" nil t)
diff --git a/lisp/gnus/flow-fill.el b/lisp/gnus/flow-fill.el
index c4c64db7ed1..2420577ea45 100644
--- a/lisp/gnus/flow-fill.el
+++ b/lisp/gnus/flow-fill.el
@@ -97,8 +97,7 @@ RFC 2646 suggests 66 characters for readability."
97 97
98;;;###autoload 98;;;###autoload
99(defun fill-flowed (&optional buffer delete-space) 99(defun fill-flowed (&optional buffer delete-space)
100 (save-excursion 100 (with-current-buffer (or (current-buffer) buffer)
101 (set-buffer (or (current-buffer) buffer))
102 (goto-char (point-min)) 101 (goto-char (point-min))
103 ;; Remove space stuffing. 102 ;; Remove space stuffing.
104 (while (re-search-forward "^\\( \\|>+ $\\)" nil t) 103 (while (re-search-forward "^\\( \\|>+ $\\)" nil t)
diff --git a/lisp/gnus/gnus-agent.el b/lisp/gnus/gnus-agent.el
index bbfdc66af99..6dcc77cdfb9 100644
--- a/lisp/gnus/gnus-agent.el
+++ b/lisp/gnus/gnus-agent.el
@@ -305,8 +305,7 @@ buffer. Automatically blocks multiple updates due to recursion."
305`(prog1 (let ((gnus-agent-inhibit-update-total-fetched-for t)) ,@body) 305`(prog1 (let ((gnus-agent-inhibit-update-total-fetched-for t)) ,@body)
306 (when (and gnus-agent-need-update-total-fetched-for 306 (when (and gnus-agent-need-update-total-fetched-for
307 (not gnus-agent-inhibit-update-total-fetched-for)) 307 (not gnus-agent-inhibit-update-total-fetched-for))
308 (save-excursion 308 (with-current-buffer gnus-group-buffer
309 (set-buffer gnus-group-buffer)
310 (setq gnus-agent-need-update-total-fetched-for nil) 309 (setq gnus-agent-need-update-total-fetched-for nil)
311 (gnus-group-update-group ,group t))))) 310 (gnus-group-update-group ,group t)))))
312 311
@@ -474,8 +473,7 @@ manipulated as follows:
474(defun gnus-agent-stop-fetch () 473(defun gnus-agent-stop-fetch ()
475 "Save all data structures and clean up." 474 "Save all data structures and clean up."
476 (setq gnus-agent-spam-hashtb nil) 475 (setq gnus-agent-spam-hashtb nil)
477 (save-excursion 476 (with-current-buffer nntp-server-buffer
478 (set-buffer nntp-server-buffer)
479 (widen))) 477 (widen)))
480 478
481(defmacro gnus-agent-with-fetch (&rest forms) 479(defmacro gnus-agent-with-fetch (&rest forms)
@@ -1608,8 +1606,7 @@ downloaded into the agent."
1608 nntp-server-buffer (point-min) (point-max)) 1606 nntp-server-buffer (point-min) (point-max))
1609 (setq pos (nreverse pos))))) 1607 (setq pos (nreverse pos)))))
1610 ;; Then save these articles into the Agent. 1608 ;; Then save these articles into the Agent.
1611 (save-excursion 1609 (with-current-buffer nntp-server-buffer
1612 (set-buffer nntp-server-buffer)
1613 (while pos 1610 (while pos
1614 (narrow-to-region (cdar pos) (or (cdadr pos) (point-max))) 1611 (narrow-to-region (cdar pos) (or (cdadr pos) (point-max)))
1615 (goto-char (point-min)) 1612 (goto-char (point-min))
@@ -1693,8 +1690,7 @@ downloaded into the agent."
1693 (setq date (or date t)) 1690 (setq date (or date t))
1694 1691
1695 (let (gnus-agent-article-alist group alist beg end) 1692 (let (gnus-agent-article-alist group alist beg end)
1696 (save-excursion 1693 (with-current-buffer gnus-agent-overview-buffer
1697 (set-buffer gnus-agent-overview-buffer)
1698 (when (nnheader-find-nov-line article) 1694 (when (nnheader-find-nov-line article)
1699 (forward-word 1) 1695 (forward-word 1)
1700 (setq beg (point)) 1696 (setq beg (point))
@@ -1705,9 +1701,8 @@ downloaded into the agent."
1705 (push (setq alist (list group (gnus-agent-load-alist (caar crosses)))) 1701 (push (setq alist (list group (gnus-agent-load-alist (caar crosses))))
1706 gnus-agent-group-alist)) 1702 gnus-agent-group-alist))
1707 (setcdr alist (cons (cons (cdar crosses) date) (cdr alist))) 1703 (setcdr alist (cons (cons (cdar crosses) date) (cdr alist)))
1708 (save-excursion 1704 (with-current-buffer (gnus-get-buffer-create
1709 (set-buffer (gnus-get-buffer-create (format " *Gnus agent overview %s*" 1705 (format " *Gnus agent overview %s*"group))
1710 group)))
1711 (when (= (point-max) (point-min)) 1706 (when (= (point-max) (point-min))
1712 (push (cons group (current-buffer)) gnus-agent-buffer-alist) 1707 (push (cons group (current-buffer)) gnus-agent-buffer-alist)
1713 (ignore-errors 1708 (ignore-errors
@@ -1939,9 +1934,7 @@ article numbers will be returned."
1939 10 "gnus-agent-fetch-headers: undownloaded articles are '%s'" 1934 10 "gnus-agent-fetch-headers: undownloaded articles are '%s'"
1940 (gnus-compress-sequence articles t)) 1935 (gnus-compress-sequence articles t))
1941 1936
1942 (save-excursion 1937 (with-current-buffer nntp-server-buffer
1943 (set-buffer nntp-server-buffer)
1944
1945 (if articles 1938 (if articles
1946 (progn 1939 (progn
1947 (gnus-message 7 "Fetching headers for %s..." 1940 (gnus-message 7 "Fetching headers for %s..."
@@ -2767,8 +2760,7 @@ The following commands are available:
2767 2760
2768(defun gnus-category-setup-buffer () 2761(defun gnus-category-setup-buffer ()
2769 (unless (get-buffer gnus-category-buffer) 2762 (unless (get-buffer gnus-category-buffer)
2770 (save-excursion 2763 (with-current-buffer (gnus-get-buffer-create gnus-category-buffer)
2771 (set-buffer (gnus-get-buffer-create gnus-category-buffer))
2772 (gnus-category-mode)))) 2764 (gnus-category-mode))))
2773 2765
2774(defun gnus-category-prepare () 2766(defun gnus-category-prepare ()
diff --git a/lisp/gnus/gnus-async.el b/lisp/gnus/gnus-async.el
index 979e67120d1..a2ab54bea8b 100644
--- a/lisp/gnus/gnus-async.el
+++ b/lisp/gnus/gnus-async.el
@@ -145,8 +145,7 @@ that was fetched."
145 (when (and (gnus-buffer-live-p summary) 145 (when (and (gnus-buffer-live-p summary)
146 gnus-asynchronous 146 gnus-asynchronous
147 (gnus-group-asynchronous-p group)) 147 (gnus-group-asynchronous-p group))
148 (save-excursion 148 (with-current-buffer gnus-summary-buffer
149 (set-buffer gnus-summary-buffer)
150 (let ((next (caadr (gnus-data-find-list article)))) 149 (let ((next (caadr (gnus-data-find-list article))))
151 (when next 150 (when next
152 (if (not (fboundp 'run-with-idle-timer)) 151 (if (not (fboundp 'run-with-idle-timer))
@@ -205,8 +204,7 @@ that was fetched."
205 204
206 (when (and do-fetch article) 205 (when (and do-fetch article)
207 ;; We want to fetch some more articles. 206 ;; We want to fetch some more articles.
208 (save-excursion 207 (with-current-buffer summary
209 (set-buffer summary)
210 (let (mark) 208 (let (mark)
211 (gnus-async-set-buffer) 209 (gnus-async-set-buffer)
212 (goto-char (point-max)) 210 (goto-char (point-max))
diff --git a/lisp/gnus/gnus-bcklg.el b/lisp/gnus/gnus-bcklg.el
index b3851858513..68233328802 100644
--- a/lisp/gnus/gnus-bcklg.el
+++ b/lisp/gnus/gnus-bcklg.el
@@ -40,8 +40,7 @@
40(defun gnus-backlog-buffer () 40(defun gnus-backlog-buffer ()
41 "Return the backlog buffer." 41 "Return the backlog buffer."
42 (or (get-buffer gnus-backlog-buffer) 42 (or (get-buffer gnus-backlog-buffer)
43 (save-excursion 43 (with-current-buffer (gnus-get-buffer-create gnus-backlog-buffer)
44 (set-buffer (gnus-get-buffer-create gnus-backlog-buffer))
45 (buffer-disable-undo) 44 (buffer-disable-undo)
46 (setq buffer-read-only t) 45 (setq buffer-read-only t)
47 (get-buffer gnus-backlog-buffer)))) 46 (get-buffer gnus-backlog-buffer))))
@@ -76,8 +75,7 @@
76 (gnus-backlog-remove-oldest-article)) 75 (gnus-backlog-remove-oldest-article))
77 (push ident gnus-backlog-articles) 76 (push ident gnus-backlog-articles)
78 ;; Insert the new article. 77 ;; Insert the new article.
79 (save-excursion 78 (with-current-buffer (gnus-backlog-buffer)
80 (set-buffer (gnus-backlog-buffer))
81 (let (buffer-read-only) 79 (let (buffer-read-only)
82 (goto-char (point-max)) 80 (goto-char (point-max))
83 (unless (bolp) 81 (unless (bolp)
@@ -90,8 +88,7 @@
90 (gnus-error 3 "Article %d is blank" number)))))))) 88 (gnus-error 3 "Article %d is blank" number))))))))
91 89
92(defun gnus-backlog-remove-oldest-article () 90(defun gnus-backlog-remove-oldest-article ()
93 (save-excursion 91 (with-current-buffer (gnus-backlog-buffer)
94 (set-buffer (gnus-backlog-buffer))
95 (goto-char (point-min)) 92 (goto-char (point-min))
96 (if (zerop (buffer-size)) 93 (if (zerop (buffer-size))
97 () ; The buffer is empty. 94 () ; The buffer is empty.
@@ -114,8 +111,7 @@
114 beg end) 111 beg end)
115 (when (memq ident gnus-backlog-articles) 112 (when (memq ident gnus-backlog-articles)
116 ;; It was in the backlog. 113 ;; It was in the backlog.
117 (save-excursion 114 (with-current-buffer (gnus-backlog-buffer)
118 (set-buffer (gnus-backlog-buffer))
119 (let (buffer-read-only) 115 (let (buffer-read-only)
120 (when (setq beg (text-property-any 116 (when (setq beg (text-property-any
121 (point-min) (point-max) 'gnus-backlog 117 (point-min) (point-max) 'gnus-backlog
@@ -138,8 +134,7 @@
138 beg end) 134 beg end)
139 (when (memq ident gnus-backlog-articles) 135 (when (memq ident gnus-backlog-articles)
140 ;; It was in the backlog. 136 ;; It was in the backlog.
141 (save-excursion 137 (with-current-buffer (gnus-backlog-buffer)
142 (set-buffer (gnus-backlog-buffer))
143 (if (not (setq beg (text-property-any 138 (if (not (setq beg (text-property-any
144 (point-min) (point-max) 'gnus-backlog 139 (point-min) (point-max) 'gnus-backlog
145 ident))) 140 ident)))
@@ -150,8 +145,7 @@
150 (setq end 145 (setq end
151 (next-single-property-change 146 (next-single-property-change
152 (1+ beg) 'gnus-backlog (current-buffer) (point-max))))) 147 (1+ beg) 'gnus-backlog (current-buffer) (point-max)))))
153 (save-excursion 148 (with-current-buffer (or (current-buffer) buffer)
154 (and buffer (set-buffer buffer))
155 (let ((buffer-read-only nil)) 149 (let ((buffer-read-only nil))
156 (erase-buffer) 150 (erase-buffer)
157 (insert-buffer-substring gnus-backlog-buffer beg end))) 151 (insert-buffer-substring gnus-backlog-buffer beg end)))
diff --git a/lisp/gnus/gnus-cache.el b/lisp/gnus/gnus-cache.el
index e3f33be8819..4b2d6705707 100644
--- a/lisp/gnus/gnus-cache.el
+++ b/lisp/gnus/gnus-cache.el
@@ -180,8 +180,7 @@ it's not cached."
180 ;; Save the article in the cache. 180 ;; Save the article in the cache.
181 (if (file-exists-p file) 181 (if (file-exists-p file)
182 t ; The article already is saved. 182 t ; The article already is saved.
183 (save-excursion 183 (with-current-buffer nntp-server-buffer
184 (set-buffer nntp-server-buffer)
185 (require 'gnus-art) 184 (require 'gnus-art)
186 (let ((gnus-use-cache nil) 185 (let ((gnus-use-cache nil)
187 (gnus-article-decode-hook nil)) 186 (gnus-article-decode-hook nil))
@@ -554,8 +553,7 @@ system for example was used.")
554 (let ((cache-buf (gnus-get-buffer-create " *gnus-cache*")) 553 (let ((cache-buf (gnus-get-buffer-create " *gnus-cache*"))
555 beg end) 554 beg end)
556 (gnus-cache-save-buffers) 555 (gnus-cache-save-buffers)
557 (save-excursion 556 (with-current-buffer cache-buf
558 (set-buffer cache-buf)
559 (erase-buffer) 557 (erase-buffer)
560 (let ((coding-system-for-read gnus-cache-overview-coding-system) 558 (let ((coding-system-for-read gnus-cache-overview-coding-system)
561 (file-name-coding-system nnmail-pathname-coding-system)) 559 (file-name-coding-system nnmail-pathname-coding-system))
@@ -844,8 +842,7 @@ supported."
844 ,@body) 842 ,@body)
845 (when (and gnus-cache-need-update-total-fetched-for 843 (when (and gnus-cache-need-update-total-fetched-for
846 (not gnus-cache-inhibit-update-total-fetched-for)) 844 (not gnus-cache-inhibit-update-total-fetched-for))
847 (save-excursion 845 (with-current-buffer gnus-group-buffer
848 (set-buffer gnus-group-buffer)
849 (setq gnus-cache-need-update-total-fetched-for nil) 846 (setq gnus-cache-need-update-total-fetched-for nil)
850 (gnus-group-update-group ,group t))))) 847 (gnus-group-update-group ,group t)))))
851 848
diff --git a/lisp/gnus/gnus-demon.el b/lisp/gnus/gnus-demon.el
index caf9f8784b9..67c1c8ba3bc 100644
--- a/lisp/gnus/gnus-demon.el
+++ b/lisp/gnus/gnus-demon.el
@@ -291,11 +291,9 @@ minutes, the connection is closed."
291 (let ((win (current-window-configuration))) 291 (let ((win (current-window-configuration)))
292 (unwind-protect 292 (unwind-protect
293 (save-window-excursion 293 (save-window-excursion
294 (save-excursion 294 (when (gnus-alive-p)
295 (when (gnus-alive-p) 295 (with-current-buffer gnus-group-buffer
296 (save-excursion 296 (gnus-group-get-new-news))))
297 (set-buffer gnus-group-buffer)
298 (gnus-group-get-new-news)))))
299 (set-window-configuration win)))) 297 (set-window-configuration win))))
300 298
301(defun gnus-demon-add-scan-timestamps () 299(defun gnus-demon-add-scan-timestamps ()
diff --git a/lisp/gnus/gnus-int.el b/lisp/gnus/gnus-int.el
index d805f3104d2..389b1a22a8b 100644
--- a/lisp/gnus/gnus-int.el
+++ b/lisp/gnus/gnus-int.el
@@ -179,10 +179,7 @@ If it is down, start it up (again)."
179 (format " on %s" (nth 1 method))))) 179 (format " on %s" (nth 1 method)))))
180 (gnus-run-hooks 'gnus-open-server-hook) 180 (gnus-run-hooks 'gnus-open-server-hook)
181 (prog1 181 (prog1
182 (condition-case () 182 (setq result (gnus-open-server method))
183 (setq result (gnus-open-server method))
184 (quit (message "Quit gnus-check-server")
185 nil))
186 (unless silent 183 (unless silent
187 (gnus-message 5 "Opening %s server%s...%s" (car method) 184 (gnus-message 5 "Opening %s server%s...%s" (car method)
188 (if (equal (nth 1 method) "") "" 185 (if (equal (nth 1 method) "") ""
@@ -225,6 +222,10 @@ If it is down, start it up (again)."
225;;; Interface functions to the backends. 222;;; Interface functions to the backends.
226;;; 223;;;
227 224
225(defun gnus-method-denied-p (method)
226 (eq (nth 1 (assoc method gnus-opened-servers))
227 'denied))
228
228(defun gnus-open-server (gnus-command-method) 229(defun gnus-open-server (gnus-command-method)
229 "Open a connection to GNUS-COMMAND-METHOD." 230 "Open a connection to GNUS-COMMAND-METHOD."
230 (when (stringp gnus-command-method) 231 (when (stringp gnus-command-method)
@@ -319,6 +320,22 @@ If it is down, start it up (again)."
319 (funcall (gnus-get-function gnus-command-method 'request-list) 320 (funcall (gnus-get-function gnus-command-method 'request-list)
320 (nth 1 gnus-command-method))) 321 (nth 1 gnus-command-method)))
321 322
323(defun gnus-finish-retrieve-group-infos (gnus-command-method infos data)
324 "Read and update infos from GNUS-COMMAND-METHOD."
325 (when (stringp gnus-command-method)
326 (setq gnus-command-method (gnus-server-to-method gnus-command-method)))
327 (funcall (gnus-get-function gnus-command-method 'finish-retrieve-group-infos)
328 (nth 1 gnus-command-method)
329 infos data))
330
331(defun gnus-retrieve-group-data-early (gnus-command-method infos)
332 "Start early async retrival of data from GNUS-COMMAND-METHOD."
333 (when (stringp gnus-command-method)
334 (setq gnus-command-method (gnus-server-to-method gnus-command-method)))
335 (funcall (gnus-get-function gnus-command-method 'retrieve-group-data-early)
336 (nth 1 gnus-command-method)
337 infos))
338
322(defun gnus-request-list-newsgroups (gnus-command-method) 339(defun gnus-request-list-newsgroups (gnus-command-method)
323 "Request the newsgroups file from GNUS-COMMAND-METHOD." 340 "Request the newsgroups file from GNUS-COMMAND-METHOD."
324 (when (stringp gnus-command-method) 341 (when (stringp gnus-command-method)
@@ -490,8 +507,7 @@ If BUFFER, insert the article in that group."
490 (setq res (gnus-request-article article group) 507 (setq res (gnus-request-article article group)
491 clean-up t))) 508 clean-up t)))
492 (when clean-up 509 (when clean-up
493 (save-excursion 510 (with-current-buffer nntp-server-buffer
494 (set-buffer nntp-server-buffer)
495 (goto-char (point-min)) 511 (goto-char (point-min))
496 (when (search-forward "\n\n" nil t) 512 (when (search-forward "\n\n" nil t)
497 (delete-region (1- (point)) (point-max))) 513 (delete-region (1- (point)) (point-max)))
@@ -523,8 +539,7 @@ If BUFFER, insert the article in that group."
523 (setq res (gnus-request-article article group) 539 (setq res (gnus-request-article article group)
524 clean-up t))) 540 clean-up t)))
525 (when clean-up 541 (when clean-up
526 (save-excursion 542 (with-current-buffer nntp-server-buffer
527 (set-buffer nntp-server-buffer)
528 (goto-char (point-min)) 543 (goto-char (point-min))
529 (when (search-forward "\n\n" nil t) 544 (when (search-forward "\n\n" nil t)
530 (delete-region (point-min) (1- (point)))))) 545 (delete-region (point-min) (1- (point))))))
diff --git a/lisp/gnus/gnus-kill.el b/lisp/gnus/gnus-kill.el
index fc564490fc9..5483a741f2f 100644
--- a/lisp/gnus/gnus-kill.el
+++ b/lisp/gnus/gnus-kill.el
@@ -349,8 +349,7 @@ If NEWSGROUP is nil, return the global kill file instead."
349 349
350(defun gnus-expunge (marks) 350(defun gnus-expunge (marks)
351 "Remove lines marked with MARKS." 351 "Remove lines marked with MARKS."
352 (save-excursion 352 (with-current-buffer gnus-summary-buffer
353 (set-buffer gnus-summary-buffer)
354 (gnus-summary-limit-to-marks marks 'reverse))) 353 (gnus-summary-limit-to-marks marks 'reverse)))
355 354
356(defun gnus-apply-kill-file-unless-scored () 355(defun gnus-apply-kill-file-unless-scored ()
@@ -442,8 +441,7 @@ Returns the number of articles marked as read."
442 (progn 441 (progn
443 (delete-region beg (point)) 442 (delete-region beg (point))
444 (insert (or (eval form) ""))) 443 (insert (or (eval form) "")))
445 (save-excursion 444 (with-current-buffer gnus-summary-buffer
446 (set-buffer gnus-summary-buffer)
447 (ignore-errors (eval form))))) 445 (ignore-errors (eval form)))))
448 (and (buffer-modified-p) 446 (and (buffer-modified-p)
449 gnus-kill-save-kill-file 447 gnus-kill-save-kill-file
@@ -555,8 +553,7 @@ COMMAND must be a Lisp expression or a string representing a key sequence."
555 (and (eq 'quote (car (nth 2 object))) 553 (and (eq 'quote (car (nth 2 object)))
556 (not (consp (cdadr (nth 2 object)))))) 554 (not (consp (cdadr (nth 2 object))))))
557 (concat "\n" (gnus-prin1-to-string object)) 555 (concat "\n" (gnus-prin1-to-string object))
558 (save-excursion 556 (with-current-buffer (gnus-get-buffer-create "*Gnus PP*")
559 (set-buffer (gnus-get-buffer-create "*Gnus PP*"))
560 (buffer-disable-undo) 557 (buffer-disable-undo)
561 (erase-buffer) 558 (erase-buffer)
562 (insert (format "\n(%S %S\n '(" (nth 0 object) (nth 1 object))) 559 (insert (format "\n(%S %S\n '(" (nth 0 object) (nth 1 object)))
@@ -610,8 +607,7 @@ COMMAND must be a Lisp expression or a string representing a key sequence."
610 6 "Searching for article: %d..." (mail-header-number header)) 607 6 "Searching for article: %d..." (mail-header-number header))
611 (gnus-article-setup-buffer) 608 (gnus-article-setup-buffer)
612 (gnus-article-prepare (mail-header-number header) t) 609 (gnus-article-prepare (mail-header-number header) t)
613 (when (save-excursion 610 (when (with-current-buffer gnus-article-buffer
614 (set-buffer gnus-article-buffer)
615 (goto-char (point-min)) 611 (goto-char (point-min))
616 (setq did-kill (re-search-forward regexp nil t))) 612 (setq did-kill (re-search-forward regexp nil t)))
617 (cond ((stringp form) ;Keyboard macro. 613 (cond ((stringp form) ;Keyboard macro.
diff --git a/lisp/gnus/gnus-logic.el b/lisp/gnus/gnus-logic.el
index e6d28ae26aa..9637ebfb387 100644
--- a/lisp/gnus/gnus-logic.el
+++ b/lisp/gnus/gnus-logic.el
@@ -179,8 +179,7 @@
179(defun gnus-advanced-body (header match type) 179(defun gnus-advanced-body (header match type)
180 (when (string= header "all") 180 (when (string= header "all")
181 (setq header "article")) 181 (setq header "article"))
182 (save-excursion 182 (with-current-buffer nntp-server-buffer
183 (set-buffer nntp-server-buffer)
184 (let* ((request-func (cond ((string= "head" header) 183 (let* ((request-func (cond ((string= "head" header)
185 'gnus-request-head) 184 'gnus-request-head)
186 ((string= "body" header) 185 ((string= "body" header)
diff --git a/lisp/gnus/gnus-range.el b/lisp/gnus/gnus-range.el
index 5eb8080ac0a..a4262df5328 100644
--- a/lisp/gnus/gnus-range.el
+++ b/lisp/gnus/gnus-range.el
@@ -59,6 +59,36 @@ If RANGE is a single range, return (RANGE). Otherwise, return RANGE."
59 (setq list2 (cdr list2))) 59 (setq list2 (cdr list2)))
60 list1)) 60 list1))
61 61
62(defun gnus-range-nconcat (&rest ranges)
63 "Return a range comprising all the RANGES, which are pre-sorted.
64RANGES will be destructively altered."
65 (setq ranges (delete nil ranges))
66 (let* ((result (gnus-range-normalize (pop ranges)))
67 (last (last result)))
68 (dolist (range ranges)
69 (setq range (gnus-range-normalize range))
70 ;; Normalize the single-number case, so that we don't need to
71 ;; special-case that so much.
72 (when (numberp (car last))
73 (setcar last (cons (car last) (car last))))
74 (when (numberp (car range))
75 (setcar range (cons (car range) (car range))))
76 (if (= (1+ (cdar last)) (caar range))
77 (progn
78 (setcdr (car last) (cdar range))
79 (setcdr last (cdr range)))
80 (setcdr last range)
81 ;; Denormalize back, since we couldn't join the ranges up.
82 (when (= (caar range) (cdar range))
83 (setcar range (caar range)))
84 (when (= (caar last) (cdar last))
85 (setcar last (caar last))))
86 (setq last (last last)))
87 (if (and (consp (car result))
88 (= (length result) 1))
89 (car result)
90 result)))
91
62(defun gnus-range-difference (range1 range2) 92(defun gnus-range-difference (range1 range2)
63 "Return the range of elements in RANGE1 that do not appear in RANGE2. 93 "Return the range of elements in RANGE1 that do not appear in RANGE2.
64Both ranges must be in ascending order." 94Both ranges must be in ascending order."
diff --git a/lisp/gnus/gnus-registry.el b/lisp/gnus/gnus-registry.el
index 8ba6c169bc4..a30847b0e2b 100644
--- a/lisp/gnus/gnus-registry.el
+++ b/lisp/gnus/gnus-registry.el
@@ -241,8 +241,7 @@ considered precious) will not be trimmed."
241 "Save the registry cache file." 241 "Save the registry cache file."
242 (interactive) 242 (interactive)
243 (let ((file gnus-registry-cache-file)) 243 (let ((file gnus-registry-cache-file))
244 (save-excursion 244 (with-current-buffer (gnus-get-buffer-create " *Gnus-registry-cache*")
245 (set-buffer (gnus-get-buffer-create " *Gnus-registry-cache*"))
246 (make-local-variable 'version-control) 245 (make-local-variable 'version-control)
247 (setq version-control gnus-backup-startup-file) 246 (setq version-control gnus-backup-startup-file)
248 (setq buffer-file-name file) 247 (setq buffer-file-name file)
@@ -674,8 +673,7 @@ Consults `gnus-registry-unfollowed-groups' and
674 word words) 673 word words)
675 (if (or (not (gnus-registry-fetch-extra id 'keywords)) 674 (if (or (not (gnus-registry-fetch-extra id 'keywords))
676 force) 675 force)
677 (save-excursion 676 (with-current-buffer gnus-article-buffer
678 (set-buffer gnus-article-buffer)
679 (article-goto-body) 677 (article-goto-body)
680 (save-window-excursion 678 (save-window-excursion
681 (save-restriction 679 (save-restriction
diff --git a/lisp/gnus/gnus-score.el b/lisp/gnus/gnus-score.el
index bd4a39eb7b1..5cd60ddaabf 100644
--- a/lisp/gnus/gnus-score.el
+++ b/lisp/gnus/gnus-score.el
@@ -708,8 +708,7 @@ file for the command instead of the current score file."
708 708
709 ;; Change score file to the "all.SCORE" file. 709 ;; Change score file to the "all.SCORE" file.
710 (when (eq symp 'a) 710 (when (eq symp 'a)
711 (save-excursion 711 (with-current-buffer gnus-summary-buffer
712 (set-buffer gnus-summary-buffer)
713 (gnus-score-load-file 712 (gnus-score-load-file
714 ;; This is a kludge; yes... 713 ;; This is a kludge; yes...
715 (cond 714 (cond
@@ -735,14 +734,12 @@ file for the command instead of the current score file."
735 734
736 (when (eq symp 'a) 735 (when (eq symp 'a)
737 ;; We change the score file back to the previous one. 736 ;; We change the score file back to the previous one.
738 (save-excursion 737 (with-current-buffer gnus-summary-buffer
739 (set-buffer gnus-summary-buffer)
740 (gnus-score-load-file current-score-file))))) 738 (gnus-score-load-file current-score-file)))))
741 739
742(defun gnus-score-insert-help (string alist idx) 740(defun gnus-score-insert-help (string alist idx)
743 (setq gnus-score-help-winconf (current-window-configuration)) 741 (setq gnus-score-help-winconf (current-window-configuration))
744 (save-excursion 742 (with-current-buffer (gnus-get-buffer-create "*Score Help*")
745 (set-buffer (gnus-get-buffer-create "*Score Help*"))
746 (buffer-disable-undo) 743 (buffer-disable-undo)
747 (delete-windows-on (current-buffer)) 744 (delete-windows-on (current-buffer))
748 (erase-buffer) 745 (erase-buffer)
@@ -1270,8 +1267,7 @@ If FORMAT, also format the current score file."
1270 exclude-files)) 1267 exclude-files))
1271 gnus-scores-exclude-files)) 1268 gnus-scores-exclude-files))
1272 (when local 1269 (when local
1273 (save-excursion 1270 (with-current-buffer gnus-summary-buffer
1274 (set-buffer gnus-summary-buffer)
1275 (while local 1271 (while local
1276 (and (consp (car local)) 1272 (and (consp (car local))
1277 (symbolp (caar local)) 1273 (symbolp (caar local))
@@ -1528,8 +1524,7 @@ If FORMAT, also format the current score file."
1528 (cons (cons header (or gnus-summary-default-score 0)) 1524 (cons (cons header (or gnus-summary-default-score 0))
1529 gnus-scores-articles)))) 1525 gnus-scores-articles))))
1530 1526
1531 (save-excursion 1527 (with-current-buffer (gnus-get-buffer-create "*Headers*")
1532 (set-buffer (gnus-get-buffer-create "*Headers*"))
1533 (buffer-disable-undo) 1528 (buffer-disable-undo)
1534 (when (gnus-buffer-live-p gnus-summary-buffer) 1529 (when (gnus-buffer-live-p gnus-summary-buffer)
1535 (message-clone-locals gnus-summary-buffer)) 1530 (message-clone-locals gnus-summary-buffer))
@@ -1854,8 +1849,7 @@ score in `gnus-newsgroup-scored' by SCORE."
1854 1849
1855 ;; Change score file to the adaptive score file. All entries that 1850 ;; Change score file to the adaptive score file. All entries that
1856 ;; this function makes will be put into this file. 1851 ;; this function makes will be put into this file.
1857 (save-excursion 1852 (with-current-buffer gnus-summary-buffer
1858 (set-buffer gnus-summary-buffer)
1859 (gnus-score-load-file 1853 (gnus-score-load-file
1860 (or gnus-newsgroup-adaptive-score-file 1854 (or gnus-newsgroup-adaptive-score-file
1861 (gnus-score-file-name 1855 (gnus-score-file-name
@@ -1946,15 +1940,13 @@ score in `gnus-newsgroup-scored' by SCORE."
1946 (setq rest entries))) 1940 (setq rest entries)))
1947 (setq entries rest)))) 1941 (setq entries rest))))
1948 ;; We change the score file back to the previous one. 1942 ;; We change the score file back to the previous one.
1949 (save-excursion 1943 (with-current-buffer gnus-summary-buffer
1950 (set-buffer gnus-summary-buffer)
1951 (gnus-score-load-file current-score-file)) 1944 (gnus-score-load-file current-score-file))
1952 (list (cons "references" news))))) 1945 (list (cons "references" news)))))
1953 1946
1954(defun gnus-score-add-followups (header score scores &optional thread) 1947(defun gnus-score-add-followups (header score scores &optional thread)
1955 "Add a score entry to the adapt file." 1948 "Add a score entry to the adapt file."
1956 (save-excursion 1949 (with-current-buffer gnus-summary-buffer
1957 (set-buffer gnus-summary-buffer)
1958 (let* ((id (mail-header-id header)) 1950 (let* ((id (mail-header-id header))
1959 (scores (car scores)) 1951 (scores (car scores))
1960 entry dont) 1952 entry dont)
@@ -2282,8 +2274,7 @@ score in `gnus-newsgroup-scored' by SCORE."
2282 "Create adaptive score rules for this newsgroup." 2274 "Create adaptive score rules for this newsgroup."
2283 (when gnus-newsgroup-adaptive 2275 (when gnus-newsgroup-adaptive
2284 ;; We change the score file to the adaptive score file. 2276 ;; We change the score file to the adaptive score file.
2285 (save-excursion 2277 (with-current-buffer gnus-summary-buffer
2286 (set-buffer gnus-summary-buffer)
2287 (gnus-score-load-file 2278 (gnus-score-load-file
2288 (or gnus-newsgroup-adaptive-score-file 2279 (or gnus-newsgroup-adaptive-score-file
2289 (gnus-home-score-file gnus-newsgroup-name t) 2280 (gnus-home-score-file gnus-newsgroup-name t)
@@ -2697,8 +2688,7 @@ GROUP using BNews sys file syntax."
2697 (trans (cdr (assq ?: nnheader-file-name-translation-alist))) 2688 (trans (cdr (assq ?: nnheader-file-name-translation-alist)))
2698 (group-trans (nnheader-translate-file-chars group t)) 2689 (group-trans (nnheader-translate-file-chars group t))
2699 ofiles not-match regexp) 2690 ofiles not-match regexp)
2700 (save-excursion 2691 (with-current-buffer (gnus-get-buffer-create "*gnus score files*")
2701 (set-buffer (gnus-get-buffer-create "*gnus score files*"))
2702 (buffer-disable-undo) 2692 (buffer-disable-undo)
2703 ;; Go through all score file names and create regexp with them 2693 ;; Go through all score file names and create regexp with them
2704 ;; as the source. 2694 ;; as the source.
diff --git a/lisp/gnus/gnus-start.el b/lisp/gnus/gnus-start.el
index 1c06a774203..e25d31ec87e 100644
--- a/lisp/gnus/gnus-start.el
+++ b/lisp/gnus/gnus-start.el
@@ -594,8 +594,7 @@ Can be used to turn version control on or off."
594(defun gnus-subscribe-hierarchically (newgroup) 594(defun gnus-subscribe-hierarchically (newgroup)
595 "Subscribe new NEWGROUP and insert it in hierarchical newsgroup order." 595 "Subscribe new NEWGROUP and insert it in hierarchical newsgroup order."
596 ;; Basic ideas by mike-w@cs.aukuni.ac.nz (Mike Williams) 596 ;; Basic ideas by mike-w@cs.aukuni.ac.nz (Mike Williams)
597 (save-excursion 597 (with-current-buffer (nnheader-find-file-noselect gnus-current-startup-file)
598 (set-buffer (nnheader-find-file-noselect gnus-current-startup-file))
599 (prog1 598 (prog1
600 (let ((groupkey newgroup) before) 599 (let ((groupkey newgroup) before)
601 (while (and (not before) groupkey) 600 (while (and (not before) groupkey)
@@ -857,8 +856,7 @@ prompt the user for the name of an NNTP server to use."
857 ;; it's not needed). 856 ;; it's not needed).
858 ;; (set-window-point (get-buffer-window (current-buffer)) (point-max)) 857 ;; (set-window-point (get-buffer-window (current-buffer)) (point-max))
859 (bury-buffer gnus-dribble-buffer) 858 (bury-buffer gnus-dribble-buffer)
860 (save-excursion 859 (with-current-buffer gnus-group-buffer
861 (set-buffer gnus-group-buffer)
862 (gnus-group-set-mode-line)) 860 (gnus-group-set-mode-line))
863 (set-buffer obuf)))) 861 (set-buffer obuf))))
864 862
@@ -871,10 +869,9 @@ prompt the user for the name of an NNTP server to use."
871 (let ((dribble-file (gnus-dribble-file-name))) 869 (let ((dribble-file (gnus-dribble-file-name)))
872 (unless (file-exists-p (file-name-directory dribble-file)) 870 (unless (file-exists-p (file-name-directory dribble-file))
873 (make-directory (file-name-directory dribble-file) t)) 871 (make-directory (file-name-directory dribble-file) t))
874 (save-excursion 872 (with-current-buffer (setq gnus-dribble-buffer
875 (set-buffer (setq gnus-dribble-buffer 873 (gnus-get-buffer-create
876 (gnus-get-buffer-create 874 (file-name-nondirectory dribble-file)))
877 (file-name-nondirectory dribble-file))))
878 (set (make-local-variable 'file-precious-flag) t) 875 (set (make-local-variable 'file-precious-flag) t)
879 (erase-buffer) 876 (erase-buffer)
880 (setq buffer-file-name dribble-file) 877 (setq buffer-file-name dribble-file)
@@ -923,8 +920,7 @@ prompt the user for the name of an NNTP server to use."
923 (when (file-exists-p (gnus-dribble-file-name)) 920 (when (file-exists-p (gnus-dribble-file-name))
924 (delete-file (gnus-dribble-file-name))) 921 (delete-file (gnus-dribble-file-name)))
925 (when gnus-dribble-buffer 922 (when gnus-dribble-buffer
926 (save-excursion 923 (with-current-buffer gnus-dribble-buffer
927 (set-buffer gnus-dribble-buffer)
928 (let ((auto (make-auto-save-file-name))) 924 (let ((auto (make-auto-save-file-name)))
929 (when (file-exists-p auto) 925 (when (file-exists-p auto)
930 (delete-file auto)) 926 (delete-file auto))
@@ -934,14 +930,12 @@ prompt the user for the name of an NNTP server to use."
934(defun gnus-dribble-save () 930(defun gnus-dribble-save ()
935 (when (and gnus-dribble-buffer 931 (when (and gnus-dribble-buffer
936 (buffer-name gnus-dribble-buffer)) 932 (buffer-name gnus-dribble-buffer))
937 (save-excursion 933 (with-current-buffer gnus-dribble-buffer
938 (set-buffer gnus-dribble-buffer)
939 (save-buffer)))) 934 (save-buffer))))
940 935
941(defun gnus-dribble-clear () 936(defun gnus-dribble-clear ()
942 (when (gnus-buffer-exists-p gnus-dribble-buffer) 937 (when (gnus-buffer-exists-p gnus-dribble-buffer)
943 (save-excursion 938 (with-current-buffer gnus-dribble-buffer
944 (set-buffer gnus-dribble-buffer)
945 (erase-buffer) 939 (erase-buffer)
946 (set-buffer-modified-p nil) 940 (set-buffer-modified-p nil)
947 (setq buffer-saved-size (buffer-size))))) 941 (setq buffer-saved-size (buffer-size)))))
@@ -1302,8 +1296,7 @@ for new groups, and subscribe the new groups as zombies."
1302 (when (gnus-active group) 1296 (when (gnus-active group)
1303 (gnus-group-change-level 1297 (gnus-group-change-level
1304 group gnus-level-default-subscribed gnus-level-killed))) 1298 group gnus-level-default-subscribed gnus-level-killed)))
1305 (save-excursion 1299 (with-current-buffer gnus-group-buffer
1306 (set-buffer gnus-group-buffer)
1307 ;; Don't error if the group already exists. This happens when a 1300 ;; Don't error if the group already exists. This happens when a
1308 ;; first-time user types 'F'. -- didier 1301 ;; first-time user types 'F'. -- didier
1309 (gnus-group-make-help-group t)) 1302 (gnus-group-make-help-group t))
@@ -1734,7 +1727,7 @@ If SCAN, request a scan of that group as well."
1734 'primary) 1727 'primary)
1735 (t 1728 (t
1736 'foreign))) 1729 'foreign)))
1737 (push (setq method-group-list (list method method-type nil)) 1730 (push (setq method-group-list (list method method-type nil nil))
1738 type-cache)) 1731 type-cache))
1739 ;; Only add groups that need updating. 1732 ;; Only add groups that need updating.
1740 (if (<= (gnus-info-level info) 1733 (if (<= (gnus-info-level info)
@@ -1760,19 +1753,28 @@ If SCAN, request a scan of that group as well."
1760 (< (gnus-method-rank (cadr c1) (car c1)) 1753 (< (gnus-method-rank (cadr c1) (car c1))
1761 (gnus-method-rank (cadr c2) (car c2)))))) 1754 (gnus-method-rank (cadr c2) (car c2))))))
1762 1755
1763 (while type-cache 1756 ;; Start early async retrieval of data.
1764 (setq method (nth 0 (car type-cache)) 1757 (dolist (elem type-cache)
1765 method-type (nth 1 (car type-cache)) 1758 (destructuring-bind (method method-type infos dummy) elem
1766 infos (nth 2 (car type-cache))) 1759 (when (and method infos
1767 (pop type-cache) 1760 (not (gnus-method-denied-p method))
1768 1761 (gnus-check-backend-function
1769 (when (and method 1762 'retrieve-group-data-early (car method)))
1770 infos) 1763 (when (gnus-check-backend-function 'request-scan (car method))
1771 ;; See if any of the groups from this method require updating. 1764 (dolist (info infos)
1772 (gnus-read-active-for-groups method infos) 1765 (gnus-request-scan (gnus-info-group info) method)))
1773 (dolist (info infos) 1766 (setcar (nthcdr 3 elem)
1774 (inline (gnus-get-unread-articles-in-group 1767 (gnus-retrieve-group-data-early method infos)))))
1775 info (gnus-active (gnus-info-group info))))))) 1768
1769 ;; Do the rest of the retrieval.
1770 (dolist (elem type-cache)
1771 (destructuring-bind (method method-type infos early-data) elem
1772 (when (and method infos)
1773 ;; See if any of the groups from this method require updating.
1774 (gnus-read-active-for-groups method infos early-data)
1775 (dolist (info infos)
1776 (inline (gnus-get-unread-articles-in-group
1777 info (gnus-active (gnus-info-group info))))))))
1776 (gnus-message 6 "Checking new news...done"))) 1778 (gnus-message 6 "Checking new news...done")))
1777 1779
1778(defun gnus-method-rank (type method) 1780(defun gnus-method-rank (type method)
@@ -1796,9 +1798,14 @@ If SCAN, request a scan of that group as well."
1796 (t 1798 (t
1797 100))) 1799 100)))
1798 1800
1799(defun gnus-read-active-for-groups (method infos) 1801(defun gnus-read-active-for-groups (method infos early-data)
1800 (with-current-buffer nntp-server-buffer 1802 (with-current-buffer nntp-server-buffer
1801 (cond 1803 (cond
1804 ((and
1805 (gnus-check-backend-function 'finish-retrieve-group-infos (car method))
1806 (or (not (gnus-agent-method-p method))
1807 (gnus-online method)))
1808 (gnus-finish-retrieve-group-infos method infos early-data))
1802 ((gnus-check-backend-function 'retrieve-groups (car method)) 1809 ((gnus-check-backend-function 'retrieve-groups (car method))
1803 (when (gnus-check-backend-function 'request-scan (car method)) 1810 (when (gnus-check-backend-function 'request-scan (car method))
1804 (dolist (info infos) 1811 (dolist (info infos)
@@ -1867,8 +1874,7 @@ If SCAN, request a scan of that group as well."
1867 1874
1868(defun gnus-parse-active () 1875(defun gnus-parse-active ()
1869 "Parse active info in the nntp server buffer." 1876 "Parse active info in the nntp server buffer."
1870 (save-excursion 1877 (with-current-buffer nntp-server-buffer
1871 (set-buffer nntp-server-buffer)
1872 (goto-char (point-min)) 1878 (goto-char (point-min))
1873 ;; Parse the result we got from `gnus-request-group'. 1879 ;; Parse the result we got from `gnus-request-group'.
1874 (when (looking-at "[0-9]+ [0-9]+ \\([0-9]+\\) [0-9]+") 1880 (when (looking-at "[0-9]+ [0-9]+ \\([0-9]+\\) [0-9]+")
@@ -2022,8 +2028,7 @@ If SCAN, request a scan of that group as well."
2022 (list "archive"))))) 2028 (list "archive")))))
2023 method) 2029 method)
2024 (setq gnus-have-read-active-file nil) 2030 (setq gnus-have-read-active-file nil)
2025 (save-excursion 2031 (with-current-buffer nntp-server-buffer
2026 (set-buffer nntp-server-buffer)
2027 (while (setq method (pop methods)) 2032 (while (setq method (pop methods))
2028 ;; Only do each method once, in case the methods appear more 2033 ;; Only do each method once, in case the methods appear more
2029 ;; than once in this list. 2034 ;; than once in this list.
@@ -2089,8 +2094,7 @@ If SCAN, request a scan of that group as well."
2089(defun gnus-read-active-file-2 (groups method) 2094(defun gnus-read-active-file-2 (groups method)
2090 "Read an active file for GROUPS in METHOD using `gnus-retrieve-groups'." 2095 "Read an active file for GROUPS in METHOD using `gnus-retrieve-groups'."
2091 (when groups 2096 (when groups
2092 (save-excursion 2097 (with-current-buffer nntp-server-buffer
2093 (set-buffer nntp-server-buffer)
2094 (gnus-check-server method) 2098 (gnus-check-server method)
2095 (let ((list-type (gnus-retrieve-groups groups method))) 2099 (let ((list-type (gnus-retrieve-groups groups method)))
2096 (cond ((not list-type) 2100 (cond ((not list-type)
@@ -2771,8 +2775,7 @@ If FORCE is non-nil, the .newsrc file is read."
2771 (not force) 2775 (not force)
2772 (or (not gnus-dribble-buffer) 2776 (or (not gnus-dribble-buffer)
2773 (not (buffer-name gnus-dribble-buffer)) 2777 (not (buffer-name gnus-dribble-buffer))
2774 (zerop (save-excursion 2778 (zerop (with-current-buffer gnus-dribble-buffer
2775 (set-buffer gnus-dribble-buffer)
2776 (buffer-size))))) 2779 (buffer-size)))))
2777 (gnus-message 4 "(No changes need to be saved)") 2780 (gnus-message 4 "(No changes need to be saved)")
2778 (gnus-run-hooks 'gnus-save-newsrc-hook) 2781 (gnus-run-hooks 'gnus-save-newsrc-hook)
@@ -2906,8 +2909,7 @@ If FORCE is non-nil, the .newsrc file is read."
2906 2909
2907(defun gnus-gnus-to-newsrc-format () 2910(defun gnus-gnus-to-newsrc-format ()
2908 ;; Generate and save the .newsrc file. 2911 ;; Generate and save the .newsrc file.
2909 (save-excursion 2912 (with-current-buffer (create-file-buffer gnus-current-startup-file)
2910 (set-buffer (create-file-buffer gnus-current-startup-file))
2911 (let ((newsrc (cdr gnus-newsrc-alist)) 2913 (let ((newsrc (cdr gnus-newsrc-alist))
2912 (standard-output (current-buffer)) 2914 (standard-output (current-buffer))
2913 info ranges range method) 2915 info ranges range method)
@@ -2980,8 +2982,7 @@ If FORCE is non-nil, the .newsrc file is read."
2980 (gnus-run-hooks 'gnus-slave-mode-hook)) 2982 (gnus-run-hooks 'gnus-slave-mode-hook))
2981 2983
2982(defun gnus-slave-save-newsrc () 2984(defun gnus-slave-save-newsrc ()
2983 (save-excursion 2985 (with-current-buffer gnus-dribble-buffer
2984 (set-buffer gnus-dribble-buffer)
2985 (let ((slave-name 2986 (let ((slave-name
2986 (mm-make-temp-file (concat gnus-current-startup-file "-slave-"))) 2987 (mm-make-temp-file (concat gnus-current-startup-file "-slave-")))
2987 (modes (ignore-errors 2988 (modes (ignore-errors
@@ -3005,8 +3006,7 @@ If FORCE is non-nil, the .newsrc file is read."
3005 (if (not slave-files) 3006 (if (not slave-files)
3006 () ; There are no slave files to read. 3007 () ; There are no slave files to read.
3007 (gnus-message 7 "Reading slave newsrcs...") 3008 (gnus-message 7 "Reading slave newsrcs...")
3008 (save-excursion 3009 (with-current-buffer (gnus-get-buffer-create " *gnus slave*")
3009 (set-buffer (gnus-get-buffer-create " *gnus slave*"))
3010 (setq slave-files 3010 (setq slave-files
3011 (sort (mapcar (lambda (file) 3011 (sort (mapcar (lambda (file)
3012 (list (nth 5 (file-attributes file)) file)) 3012 (list (nth 5 (file-attributes file)) file))
@@ -3126,8 +3126,7 @@ If FORCE is non-nil, the .newsrc file is read."
3126(defun gnus-group-get-description (group) 3126(defun gnus-group-get-description (group)
3127 "Get the description of a group by sending XGTITLE to the server." 3127 "Get the description of a group by sending XGTITLE to the server."
3128 (when (gnus-request-group-description group) 3128 (when (gnus-request-group-description group)
3129 (save-excursion 3129 (with-current-buffer nntp-server-buffer
3130 (set-buffer nntp-server-buffer)
3131 (goto-char (point-min)) 3130 (goto-char (point-min))
3132 (when (looking-at "[^ \t]+[ \t]+\\(.*\\)") 3131 (when (looking-at "[^ \t]+[ \t]+\\(.*\\)")
3133 (match-string 1))))) 3132 (match-string 1)))))
diff --git a/lisp/gnus/gnus-sum.el b/lisp/gnus/gnus-sum.el
index df20456b278..3c3a0590536 100644
--- a/lisp/gnus/gnus-sum.el
+++ b/lisp/gnus/gnus-sum.el
@@ -5504,11 +5504,11 @@ If SELECT-ARTICLES, only select those articles from GROUP."
5504 (mm-decode-coding-string (gnus-status-message group) charset)))) 5504 (mm-decode-coding-string (gnus-status-message group) charset))))
5505 5505
5506 (unless (gnus-request-group group t) 5506 (unless (gnus-request-group group t)
5507 (when (equal major-mode 'gnus-summary-mode) 5507 (when (equal major-mode 'gnus-summary-mode)
5508 (gnus-kill-buffer (current-buffer))) 5508 (gnus-kill-buffer (current-buffer)))
5509 (error "Couldn't request group %s: %s" 5509 (error "Couldn't request group %s: %s"
5510 (mm-decode-coding-string group charset) 5510 (mm-decode-coding-string group charset)
5511 (mm-decode-coding-string (gnus-status-message group) charset))) 5511 (mm-decode-coding-string (gnus-status-message group) charset)))
5512 5512
5513 (when gnus-agent 5513 (when gnus-agent
5514 (gnus-agent-possibly-alter-active group (gnus-active group) info) 5514 (gnus-agent-possibly-alter-active group (gnus-active group) info)
@@ -7394,7 +7394,7 @@ If prefix argument NO-ARTICLE is non-nil, no article is selected initially."
7394 "Go to the first subject satisfying any non-nil constraint. 7394 "Go to the first subject satisfying any non-nil constraint.
7395If UNREAD is non-nil, the article should be unread. 7395If UNREAD is non-nil, the article should be unread.
7396If UNDOWNLOADED is non-nil, the article should be undownloaded. 7396If UNDOWNLOADED is non-nil, the article should be undownloaded.
7397If UNSEEN is non-nil, the article should be unseen. 7397If UNSEEN is non-nil, the article should be unseen as well as unread.
7398Returns the article selected or nil if there are no matching articles." 7398Returns the article selected or nil if there are no matching articles."
7399 (interactive "P") 7399 (interactive "P")
7400 (cond 7400 (cond
@@ -7417,7 +7417,8 @@ Returns the article selected or nil if there are no matching articles."
7417 (and undownloaded 7417 (and undownloaded
7418 (memq num gnus-newsgroup-undownloaded)) 7418 (memq num gnus-newsgroup-undownloaded))
7419 (and unseen 7419 (and unseen
7420 (memq num gnus-newsgroup-unseen))))))) 7420 (memq num gnus-newsgroup-unseen)
7421 (memq num gnus-newsgroup-unreads)))))))
7421 (setq data (cdr data))) 7422 (setq data (cdr data)))
7422 (prog1 7423 (prog1
7423 (if data 7424 (if data
@@ -7908,8 +7909,8 @@ Return nil if there are no unseen articles."
7908 (gnus-summary-position-point))) 7909 (gnus-summary-position-point)))
7909 7910
7910(defun gnus-summary-first-unseen-or-unread-subject () 7911(defun gnus-summary-first-unseen-or-unread-subject ()
7911 "Place the point on the subject line of the first unseen article or, 7912 "Place the point on the subject line of the first unseen and unread article.
7912if all article have been seen, on the subject line of the first unread 7913If all article have been seen, on the subject line of the first unread
7913article." 7914article."
7914 (interactive) 7915 (interactive)
7915 (prog1 7916 (prog1
@@ -9690,7 +9691,8 @@ ACTION can be either `move' (the default), `crosspost' or `copy'."
9690 to-newsgroup (list 'quote select-method) 9691 to-newsgroup (list 'quote select-method)
9691 (not articles) t) ; Accept form 9692 (not articles) t) ; Accept form
9692 (not articles) ; Only save nov last time 9693 (not articles) ; Only save nov last time
9693 move-is-internal))) ; is this move internal? 9694 (and move-is-internal
9695 (gnus-group-real-name to-newsgroup))))) ; is this move internal?
9694 ;; Copy the article. 9696 ;; Copy the article.
9695 ((eq action 'copy) 9697 ((eq action 'copy)
9696 (with-current-buffer copy-buf 9698 (with-current-buffer copy-buf
@@ -9821,8 +9823,9 @@ ACTION can be either `move' (the default), `crosspost' or `copy'."
9821 (gnus-add-marked-articles 9823 (gnus-add-marked-articles
9822 to-group 'expire (list to-article) info)) 9824 to-group 'expire (list to-article) info))
9823 9825
9824 (gnus-request-set-mark 9826 (when to-marks
9825 to-group (list (list (list to-article) 'add to-marks)))) 9827 (gnus-request-set-mark
9828 to-group (list (list (list to-article) 'add to-marks)))))
9826 9829
9827 (gnus-dribble-enter 9830 (gnus-dribble-enter
9828 (concat "(gnus-group-set-info '" 9831 (concat "(gnus-group-set-info '"
diff --git a/lisp/gnus/gnus-topic.el b/lisp/gnus/gnus-topic.el
index 89e61bcb598..7c710357b9d 100644
--- a/lisp/gnus/gnus-topic.el
+++ b/lisp/gnus/gnus-topic.el
@@ -148,8 +148,7 @@ See Info node `(gnus)Formatting Variables'."
148 148
149(defun gnus-group-parent-topic (group) 149(defun gnus-group-parent-topic (group)
150 "Return the topic GROUP is member of by looking at the group buffer." 150 "Return the topic GROUP is member of by looking at the group buffer."
151 (save-excursion 151 (with-current-buffer gnus-group-buffer
152 (set-buffer gnus-group-buffer)
153 (if (gnus-group-goto-group group) 152 (if (gnus-group-goto-group group)
154 (gnus-current-topic) 153 (gnus-current-topic)
155 (gnus-group-topic group)))) 154 (gnus-group-topic group))))
@@ -912,8 +911,7 @@ articles in the topic and its subtopics."
912 911
913(defun gnus-topic-change-level (group level oldlevel &optional previous) 912(defun gnus-topic-change-level (group level oldlevel &optional previous)
914 "Run when changing levels to enter/remove groups from topics." 913 "Run when changing levels to enter/remove groups from topics."
915 (save-excursion 914 (with-current-buffer gnus-group-buffer
916 (set-buffer gnus-group-buffer)
917 (let ((buffer-read-only nil)) 915 (let ((buffer-read-only nil))
918 (unless gnus-topic-inhibit-change-level 916 (unless gnus-topic-inhibit-change-level
919 (gnus-group-goto-group (or (car (nth 2 previous)) group)) 917 (gnus-group-goto-group (or (car (nth 2 previous)) group))
diff --git a/lisp/gnus/gnus-util.el b/lisp/gnus/gnus-util.el
index 7cdb70a3580..334f0eea7db 100644
--- a/lisp/gnus/gnus-util.el
+++ b/lisp/gnus/gnus-util.el
@@ -1115,8 +1115,7 @@ FILENAME exists and is Babyl format."
1115 (gnus-yes-or-no-p 1115 (gnus-yes-or-no-p
1116 (concat "\"" filename "\" does not exist, create it? "))) 1116 (concat "\"" filename "\" does not exist, create it? ")))
1117 (let ((file-buffer (create-file-buffer filename))) 1117 (let ((file-buffer (create-file-buffer filename)))
1118 (save-excursion 1118 (with-current-buffer file-buffer
1119 (set-buffer file-buffer)
1120 (if (fboundp 'rmail-insert-rmail-file-header) 1119 (if (fboundp 'rmail-insert-rmail-file-header)
1121 (rmail-insert-rmail-file-header)) 1120 (rmail-insert-rmail-file-header))
1122 (let ((require-final-newline nil) 1121 (let ((require-final-newline nil)
@@ -1194,8 +1193,7 @@ FILENAME exists and is Babyl format."
1194 (gnus-y-or-n-p 1193 (gnus-y-or-n-p
1195 (concat "\"" filename "\" does not exist, create it? "))) 1194 (concat "\"" filename "\" does not exist, create it? ")))
1196 (let ((file-buffer (create-file-buffer filename))) 1195 (let ((file-buffer (create-file-buffer filename)))
1197 (save-excursion 1196 (with-current-buffer file-buffer
1198 (set-buffer file-buffer)
1199 (let ((require-final-newline nil) 1197 (let ((require-final-newline nil)
1200 (coding-system-for-write mm-text-coding-system)) 1198 (coding-system-for-write mm-text-coding-system))
1201 (gnus-write-buffer filename))) 1199 (gnus-write-buffer filename)))
@@ -1274,8 +1272,7 @@ This function saves the current buffer."
1274 "Say whether Gnus is running or not." 1272 "Say whether Gnus is running or not."
1275 (and (boundp 'gnus-group-buffer) 1273 (and (boundp 'gnus-group-buffer)
1276 (get-buffer gnus-group-buffer) 1274 (get-buffer gnus-group-buffer)
1277 (save-excursion 1275 (with-current-buffer gnus-group-buffer
1278 (set-buffer gnus-group-buffer)
1279 (eq major-mode 'gnus-group-mode)))) 1276 (eq major-mode 'gnus-group-mode))))
1280 1277
1281(defun gnus-remove-if (predicate list) 1278(defun gnus-remove-if (predicate list)
diff --git a/lisp/gnus/gnus-uu.el b/lisp/gnus/gnus-uu.el
index 35120eae767..614a52c176c 100644
--- a/lisp/gnus/gnus-uu.el
+++ b/lisp/gnus/gnus-uu.el
@@ -827,8 +827,7 @@ When called interactively, prompt for REGEXP."
827(defun gnus-uu-save-article (buffer in-state) 827(defun gnus-uu-save-article (buffer in-state)
828 (cond 828 (cond
829 (gnus-uu-save-separate-articles 829 (gnus-uu-save-separate-articles
830 (save-excursion 830 (with-current-buffer buffer
831 (set-buffer buffer)
832 (let ((coding-system-for-write mm-text-coding-system)) 831 (let ((coding-system-for-write mm-text-coding-system))
833 (gnus-write-buffer 832 (gnus-write-buffer
834 (concat gnus-uu-saved-article-name gnus-current-article))) 833 (concat gnus-uu-saved-article-name gnus-current-article)))
@@ -838,8 +837,7 @@ When called interactively, prompt for REGEXP."
838 ((eq in-state 'last) (list 'end)) 837 ((eq in-state 'last) (list 'end))
839 (t (list 'middle))))) 838 (t (list 'middle)))))
840 ((not gnus-uu-save-in-digest) 839 ((not gnus-uu-save-in-digest)
841 (save-excursion 840 (with-current-buffer buffer
842 (set-buffer buffer)
843 (write-region (point-min) (point-max) gnus-uu-saved-article-name t) 841 (write-region (point-min) (point-max) gnus-uu-saved-article-name t)
844 (cond ((eq in-state 'first) (list gnus-uu-saved-article-name 'begin)) 842 (cond ((eq in-state 'first) (list gnus-uu-saved-article-name 'begin))
845 ((eq in-state 'first-and-last) (list gnus-uu-saved-article-name 843 ((eq in-state 'first-and-last) (list gnus-uu-saved-article-name
@@ -857,11 +855,9 @@ When called interactively, prompt for REGEXP."
857 (eq in-state 'first-and-last)) 855 (eq in-state 'first-and-last))
858 (progn 856 (progn
859 (setq state (list 'begin)) 857 (setq state (list 'begin))
860 (save-excursion 858 (with-current-buffer (gnus-get-buffer-create "*gnus-uu-body*")
861 (set-buffer (gnus-get-buffer-create "*gnus-uu-body*"))
862 (erase-buffer)) 859 (erase-buffer))
863 (save-excursion 860 (with-current-buffer (gnus-get-buffer-create "*gnus-uu-pre*")
864 (set-buffer (gnus-get-buffer-create "*gnus-uu-pre*"))
865 (erase-buffer) 861 (erase-buffer)
866 (insert (format 862 (insert (format
867 "Date: %s\nFrom: %s\nSubject: %s Digest\n\n" 863 "Date: %s\nFrom: %s\nSubject: %s Digest\n\n"
@@ -873,8 +869,7 @@ When called interactively, prompt for REGEXP."
873 (insert "Topics:\n"))) 869 (insert "Topics:\n")))
874 (when (not (eq in-state 'end)) 870 (when (not (eq in-state 'end))
875 (setq state (list 'middle)))) 871 (setq state (list 'middle))))
876 (save-excursion 872 (with-current-buffer "*gnus-uu-body*"
877 (set-buffer "*gnus-uu-body*")
878 (goto-char (setq beg (point-max))) 873 (goto-char (setq beg (point-max)))
879 (save-excursion 874 (save-excursion
880 (save-restriction 875 (save-restriction
@@ -940,8 +935,7 @@ When called interactively, prompt for REGEXP."
940 (when (re-search-forward "^Subject: \\(.*\\)$" nil t) 935 (when (re-search-forward "^Subject: \\(.*\\)$" nil t)
941 (setq subj (buffer-substring (match-beginning 1) (match-end 1)))) 936 (setq subj (buffer-substring (match-beginning 1) (match-end 1))))
942 (when subj 937 (when subj
943 (save-excursion 938 (with-current-buffer "*gnus-uu-pre*"
944 (set-buffer "*gnus-uu-pre*")
945 (insert (format " %s\n" subj))))) 939 (insert (format " %s\n" subj)))))
946 (when (or (eq in-state 'last) 940 (when (or (eq in-state 'last)
947 (eq in-state 'first-and-last)) 941 (eq in-state 'first-and-last))
@@ -951,8 +945,7 @@ When called interactively, prompt for REGEXP."
951 (insert-buffer-substring "*gnus-uu-pre*") 945 (insert-buffer-substring "*gnus-uu-pre*")
952 (goto-char (point-max)) 946 (goto-char (point-max))
953 (insert-buffer-substring "*gnus-uu-body*")) 947 (insert-buffer-substring "*gnus-uu-body*"))
954 (save-excursion 948 (with-current-buffer "*gnus-uu-pre*"
955 (set-buffer "*gnus-uu-pre*")
956 (insert (format "\n\n%s\n\n" (make-string 70 ?-))) 949 (insert (format "\n\n%s\n\n" (make-string 70 ?-)))
957 (if gnus-uu-digest-buffer 950 (if gnus-uu-digest-buffer
958 (with-current-buffer gnus-uu-digest-buffer 951 (with-current-buffer gnus-uu-digest-buffer
@@ -960,8 +953,7 @@ When called interactively, prompt for REGEXP."
960 (insert-buffer-substring "*gnus-uu-pre*")) 953 (insert-buffer-substring "*gnus-uu-pre*"))
961 (let ((coding-system-for-write mm-text-coding-system)) 954 (let ((coding-system-for-write mm-text-coding-system))
962 (gnus-write-buffer gnus-uu-saved-article-name)))) 955 (gnus-write-buffer gnus-uu-saved-article-name))))
963 (save-excursion 956 (with-current-buffer "*gnus-uu-body*"
964 (set-buffer "*gnus-uu-body*")
965 (goto-char (point-max)) 957 (goto-char (point-max))
966 (insert 958 (insert
967 (concat (setq end-string (format "End of %s Digest" name)) 959 (concat (setq end-string (format "End of %s Digest" name))
@@ -993,8 +985,7 @@ When called interactively, prompt for REGEXP."
993 985
994(defun gnus-uu-binhex-article (buffer in-state) 986(defun gnus-uu-binhex-article (buffer in-state)
995 (let (state start-char) 987 (let (state start-char)
996 (save-excursion 988 (with-current-buffer buffer
997 (set-buffer buffer)
998 (widen) 989 (widen)
999 (goto-char (point-min)) 990 (goto-char (point-min))
1000 (when (not (re-search-forward gnus-uu-binhex-begin-line nil t)) 991 (when (not (re-search-forward gnus-uu-binhex-begin-line nil t))
@@ -1030,8 +1021,7 @@ When called interactively, prompt for REGEXP."
1030;; yEnc 1021;; yEnc
1031 1022
1032(defun gnus-uu-yenc-article (buffer in-state) 1023(defun gnus-uu-yenc-article (buffer in-state)
1033 (save-excursion 1024 (with-current-buffer gnus-original-article-buffer
1034 (set-buffer gnus-original-article-buffer)
1035 (widen) 1025 (widen)
1036 (let ((file-name (yenc-extract-filename)) 1026 (let ((file-name (yenc-extract-filename))
1037 state start-char) 1027 state start-char)
@@ -1065,8 +1055,7 @@ When called interactively, prompt for REGEXP."
1065(defun gnus-uu-decode-postscript-article (process-buffer in-state) 1055(defun gnus-uu-decode-postscript-article (process-buffer in-state)
1066 (let ((state (list 'ok)) 1056 (let ((state (list 'ok))
1067 start-char end-char file-name) 1057 start-char end-char file-name)
1068 (save-excursion 1058 (with-current-buffer process-buffer
1069 (set-buffer process-buffer)
1070 (goto-char (point-min)) 1059 (goto-char (point-min))
1071 (if (not (re-search-forward gnus-uu-postscript-begin-string nil t)) 1060 (if (not (re-search-forward gnus-uu-postscript-begin-string nil t))
1072 (setq state (list 'wrong-type)) 1061 (setq state (list 'wrong-type))
@@ -1128,8 +1117,7 @@ When called interactively, prompt for REGEXP."
1128 ;; replaces the last thing that looks like "2/3" with "[0-9]+/3" 1117 ;; replaces the last thing that looks like "2/3" with "[0-9]+/3"
1129 ;; or, if it can't find something like that, tries "2 of 3", then 1118 ;; or, if it can't find something like that, tries "2 of 3", then
1130 ;; finally just replaces the next to last number with "[0-9]+". 1119 ;; finally just replaces the next to last number with "[0-9]+".
1131 (save-excursion 1120 (with-current-buffer (gnus-get-buffer-create gnus-uu-output-buffer-name)
1132 (set-buffer (gnus-get-buffer-create gnus-uu-output-buffer-name))
1133 (buffer-disable-undo) 1121 (buffer-disable-undo)
1134 (erase-buffer) 1122 (erase-buffer)
1135 (insert (regexp-quote string)) 1123 (insert (regexp-quote string))
@@ -1228,8 +1216,7 @@ When called interactively, prompt for REGEXP."
1228 ;; decoded in. Returns the list of expanded strings. 1216 ;; decoded in. Returns the list of expanded strings.
1229 (let ((out-list string-list) 1217 (let ((out-list string-list)
1230 string) 1218 string)
1231 (save-excursion 1219 (with-current-buffer (gnus-get-buffer-create gnus-uu-output-buffer-name)
1232 (set-buffer (gnus-get-buffer-create gnus-uu-output-buffer-name))
1233 (buffer-disable-undo) 1220 (buffer-disable-undo)
1234 (while string-list 1221 (while string-list
1235 (erase-buffer) 1222 (erase-buffer)
@@ -1332,11 +1319,9 @@ When called interactively, prompt for REGEXP."
1332 (gnus-summary-display-article article) 1319 (gnus-summary-display-article article)
1333 1320
1334 ;; Push the article to the processing function. 1321 ;; Push the article to the processing function.
1335 (save-excursion 1322 (with-current-buffer gnus-original-article-buffer
1336 (set-buffer gnus-original-article-buffer)
1337 (let ((buffer-read-only nil)) 1323 (let ((buffer-read-only nil))
1338 (save-excursion 1324 (with-current-buffer gnus-summary-buffer
1339 (set-buffer gnus-summary-buffer)
1340 (setq process-state 1325 (setq process-state
1341 (funcall process-function 1326 (funcall process-function
1342 gnus-original-article-buffer state))))) 1327 gnus-original-article-buffer state)))))
@@ -1477,8 +1462,7 @@ When called interactively, prompt for REGEXP."
1477 1462
1478(defun gnus-uu-uustrip-article (process-buffer in-state) 1463(defun gnus-uu-uustrip-article (process-buffer in-state)
1479 ;; Uudecodes a file asynchronously. 1464 ;; Uudecodes a file asynchronously.
1480 (save-excursion 1465 (with-current-buffer process-buffer
1481 (set-buffer process-buffer)
1482 (let ((state (list 'wrong-type)) 1466 (let ((state (list 'wrong-type))
1483 process-connection-type case-fold-search buffer-read-only 1467 process-connection-type case-fold-search buffer-read-only
1484 files start-char) 1468 files start-char)
@@ -1600,8 +1584,7 @@ Gnus might fail to display all of it.")
1600(defun gnus-uu-unshar-article (process-buffer in-state) 1584(defun gnus-uu-unshar-article (process-buffer in-state)
1601 (let ((state (list 'ok)) 1585 (let ((state (list 'ok))
1602 start-char) 1586 start-char)
1603 (save-excursion 1587 (with-current-buffer process-buffer
1604 (set-buffer process-buffer)
1605 (goto-char (point-min)) 1588 (goto-char (point-min))
1606 (if (not (re-search-forward gnus-uu-shar-begin-string nil t)) 1589 (if (not (re-search-forward gnus-uu-shar-begin-string nil t))
1607 (setq state (list 'wrong-type)) 1590 (setq state (list 'wrong-type))
@@ -1688,8 +1671,7 @@ Gnus might fail to display all of it.")
1688 1671
1689 (setq command (format "cd %s ; %s" dir (gnus-uu-command action file-path))) 1672 (setq command (format "cd %s ; %s" dir (gnus-uu-command action file-path)))
1690 1673
1691 (save-excursion 1674 (with-current-buffer (gnus-get-buffer-create gnus-uu-output-buffer-name)
1692 (set-buffer (gnus-get-buffer-create gnus-uu-output-buffer-name))
1693 (erase-buffer)) 1675 (erase-buffer))
1694 1676
1695 (gnus-message 5 "Unpacking: %s..." (gnus-uu-command action file-path)) 1677 (gnus-message 5 "Unpacking: %s..." (gnus-uu-command action file-path))
@@ -2039,9 +2021,8 @@ If no file has been included, the user will be asked for a file."
2039 (setq file-name file-path)) 2021 (setq file-name file-path))
2040 2022
2041 (unwind-protect 2023 (unwind-protect
2042 (if (save-excursion 2024 (if (with-current-buffer
2043 (set-buffer (setq uubuf 2025 (setq uubuf (gnus-get-buffer-create uuencode-buffer-name))
2044 (gnus-get-buffer-create uuencode-buffer-name)))
2045 (erase-buffer) 2026 (erase-buffer)
2046 (funcall gnus-uu-post-encode-method file-path file-name)) 2027 (funcall gnus-uu-post-encode-method file-path file-name))
2047 (insert-buffer-substring uubuf) 2028 (insert-buffer-substring uubuf)
@@ -2073,8 +2054,8 @@ If no file has been included, the user will be asked for a file."
2073 (setq beg-binary (point)) 2054 (setq beg-binary (point))
2074 (setq end-binary (point-max)) 2055 (setq end-binary (point-max))
2075 2056
2076 (save-excursion 2057 (with-current-buffer
2077 (set-buffer (setq uubuf (gnus-get-buffer-create encoded-buffer-name))) 2058 (setq uubuf (gnus-get-buffer-create encoded-buffer-name))
2078 (erase-buffer) 2059 (erase-buffer)
2079 (insert-buffer-substring post-buf beg-binary end-binary) 2060 (insert-buffer-substring post-buf beg-binary end-binary)
2080 (goto-char (point-min)) 2061 (goto-char (point-min))
@@ -2129,8 +2110,7 @@ If no file has been included, the user will be asked for a file."
2129 (insert (format " (%d/%d)" i parts))) 2110 (insert (format " (%d/%d)" i parts)))
2130 2111
2131 (goto-char (point-max)) 2112 (goto-char (point-max))
2132 (save-excursion 2113 (with-current-buffer uubuf
2133 (set-buffer uubuf)
2134 (goto-char beg) 2114 (goto-char beg)
2135 (if (= i parts) 2115 (if (= i parts)
2136 (goto-char (point-max)) 2116 (goto-char (point-max))
diff --git a/lisp/gnus/gnus.el b/lisp/gnus/gnus.el
index 797f8a44bd1..2173d713d11 100644
--- a/lisp/gnus/gnus.el
+++ b/lisp/gnus/gnus.el
@@ -2743,6 +2743,8 @@ a string, be sure to use a valid format, see RFC 2616."
2743 '((seen range) 2743 '((seen range)
2744 (killed range) 2744 (killed range)
2745 (bookmark tuple) 2745 (bookmark tuple)
2746 (uid tuple)
2747 (active tuple)
2746 (score tuple))) 2748 (score tuple)))
2747 2749
2748;; Propagate flags to server, with the following exceptions: 2750;; Propagate flags to server, with the following exceptions:
diff --git a/lisp/gnus/mm-decode.el b/lisp/gnus/mm-decode.el
index c4cbce4abaf..948fc08135d 100644
--- a/lisp/gnus/mm-decode.el
+++ b/lisp/gnus/mm-decode.el
@@ -114,6 +114,7 @@
114 "Render of HTML contents. 114 "Render of HTML contents.
115It is one of defined renderer types, or a rendering function. 115It is one of defined renderer types, or a rendering function.
116The defined renderer types are: 116The defined renderer types are:
117`gnus-article-html' : use Gnus renderer based on w3m;
117`w3m' : use emacs-w3m; 118`w3m' : use emacs-w3m;
118`w3m-standalone': use w3m; 119`w3m-standalone': use w3m;
119`links': use links; 120`links': use links;
@@ -122,8 +123,9 @@ The defined renderer types are:
122`html2text' : use html2text; 123`html2text' : use html2text;
123nil : use external viewer (default web browser)." 124nil : use external viewer (default web browser)."
124 :version "24.1" 125 :version "24.1"
125 :type '(choice (const w3) 126 :type '(choice (const gnus-article-html)
126 (const w3m :tag "emacs-w3m") 127 (const w3)
128 (const w3m :tag "emacs-w3m")
127 (const w3m-standalone :tag "standalone w3m" ) 129 (const w3m-standalone :tag "standalone w3m" )
128 (const links) 130 (const links)
129 (const lynx) 131 (const lynx)
diff --git a/lisp/gnus/mm-partial.el b/lisp/gnus/mm-partial.el
index 3fec4a2a975..6509b648fe7 100644
--- a/lisp/gnus/mm-partial.el
+++ b/lisp/gnus/mm-partial.el
@@ -70,8 +70,7 @@ If NO-DISPLAY is nil, display it. Otherwise, do nothing after replacing."
70 (sort (cons handle 70 (sort (cons handle
71 (mm-partial-find-parts 71 (mm-partial-find-parts
72 id 72 id
73 (save-excursion 73 (with-current-buffer gnus-summary-buffer
74 (set-buffer gnus-summary-buffer)
75 (gnus-summary-article-number)))) 74 (gnus-summary-article-number))))
76 #'(lambda (a b) 75 #'(lambda (a b)
77 (let ((anumber (string-to-number 76 (let ((anumber (string-to-number
@@ -83,8 +82,7 @@ If NO-DISPLAY is nil, display it. Otherwise, do nothing after replacing."
83 (< anumber bnumber))))) 82 (< anumber bnumber)))))
84 (setq gnus-article-mime-handles 83 (setq gnus-article-mime-handles
85 (mm-merge-handles gnus-article-mime-handles phandles)) 84 (mm-merge-handles gnus-article-mime-handles phandles))
86 (save-excursion 85 (with-current-buffer (generate-new-buffer " *mm*")
87 (set-buffer (generate-new-buffer " *mm*"))
88 (while (setq phandle (pop phandles)) 86 (while (setq phandle (pop phandles))
89 (setq nn (string-to-number 87 (setq nn (string-to-number
90 (cdr (assq 'number 88 (cdr (assq 'number
diff --git a/lisp/gnus/nnagent.el b/lisp/gnus/nnagent.el
index 263d721dad2..ccd4e890da7 100644
--- a/lisp/gnus/nnagent.el
+++ b/lisp/gnus/nnagent.el
@@ -252,6 +252,9 @@
252 (nnoo-parent-function 'nnagent 'nnml-request-regenerate 252 (nnoo-parent-function 'nnagent 'nnml-request-regenerate
253 (list (nnagent-server server)))) 253 (list (nnagent-server server))))
254 254
255(deffoo nnagent-retrieve-group-data-early (server infos)
256 nil)
257
255;; Use nnml functions for just about everything. 258;; Use nnml functions for just about everything.
256(nnoo-import nnagent 259(nnoo-import nnagent
257 (nnml)) 260 (nnml))
diff --git a/lisp/gnus/nnbabyl.el b/lisp/gnus/nnbabyl.el
index 58e848bcb5c..512de38559d 100644
--- a/lisp/gnus/nnbabyl.el
+++ b/lisp/gnus/nnbabyl.el
@@ -75,8 +75,7 @@
75(nnoo-define-basics nnbabyl) 75(nnoo-define-basics nnbabyl)
76 76
77(deffoo nnbabyl-retrieve-headers (articles &optional group server fetch-old) 77(deffoo nnbabyl-retrieve-headers (articles &optional group server fetch-old)
78 (save-excursion 78 (with-current-buffer nntp-server-buffer
79 (set-buffer nntp-server-buffer)
80 (erase-buffer) 79 (erase-buffer)
81 (let ((number (length articles)) 80 (let ((number (length articles))
82 (count 0) 81 (count 0)
@@ -136,8 +135,7 @@
136 ;; Restore buffer mode. 135 ;; Restore buffer mode.
137 (when (and (nnbabyl-server-opened) 136 (when (and (nnbabyl-server-opened)
138 nnbabyl-previous-buffer-mode) 137 nnbabyl-previous-buffer-mode)
139 (save-excursion 138 (with-current-buffer nnbabyl-mbox-buffer
140 (set-buffer nnbabyl-mbox-buffer)
141 (narrow-to-region 139 (narrow-to-region
142 (caar nnbabyl-previous-buffer-mode) 140 (caar nnbabyl-previous-buffer-mode)
143 (cdar nnbabyl-previous-buffer-mode)) 141 (cdar nnbabyl-previous-buffer-mode))
@@ -155,8 +153,7 @@
155 153
156(deffoo nnbabyl-request-article (article &optional newsgroup server buffer) 154(deffoo nnbabyl-request-article (article &optional newsgroup server buffer)
157 (nnbabyl-possibly-change-newsgroup newsgroup server) 155 (nnbabyl-possibly-change-newsgroup newsgroup server)
158 (save-excursion 156 (with-current-buffer nnbabyl-mbox-buffer
159 (set-buffer nnbabyl-mbox-buffer)
160 (goto-char (point-min)) 157 (goto-char (point-min))
161 (when (search-forward (nnbabyl-article-string article) nil t) 158 (when (search-forward (nnbabyl-article-string article) nil t)
162 (let (start stop summary-line) 159 (let (start stop summary-line)
@@ -216,8 +213,7 @@
216 (nnmail-get-new-mail 213 (nnmail-get-new-mail
217 'nnbabyl 214 'nnbabyl
218 (lambda () 215 (lambda ()
219 (save-excursion 216 (with-current-buffer nnbabyl-mbox-buffer
220 (set-buffer nnbabyl-mbox-buffer)
221 (save-buffer))) 217 (save-buffer)))
222 (file-name-directory nnbabyl-mbox-file) 218 (file-name-directory nnbabyl-mbox-file)
223 group 219 group
@@ -264,8 +260,7 @@
264 rest) 260 rest)
265 (nnmail-activate 'nnbabyl) 261 (nnmail-activate 'nnbabyl)
266 262
267 (save-excursion 263 (with-current-buffer nnbabyl-mbox-buffer
268 (set-buffer nnbabyl-mbox-buffer)
269 (set-text-properties (point-min) (point-max) nil) 264 (set-text-properties (point-min) (point-max) nil)
270 (while (and articles is-old) 265 (while (and articles is-old)
271 (goto-char (point-min)) 266 (goto-char (point-min))
@@ -308,8 +303,7 @@
308 result) 303 result)
309 (and 304 (and
310 (nnbabyl-request-article article group server) 305 (nnbabyl-request-article article group server)
311 (save-excursion 306 (with-current-buffer buf
312 (set-buffer buf)
313 (insert-buffer-substring nntp-server-buffer) 307 (insert-buffer-substring nntp-server-buffer)
314 (goto-char (point-min)) 308 (goto-char (point-min))
315 (while (re-search-forward 309 (while (re-search-forward
@@ -373,8 +367,7 @@
373 367
374(deffoo nnbabyl-request-replace-article (article group buffer) 368(deffoo nnbabyl-request-replace-article (article group buffer)
375 (nnbabyl-possibly-change-newsgroup group) 369 (nnbabyl-possibly-change-newsgroup group)
376 (save-excursion 370 (with-current-buffer nnbabyl-mbox-buffer
377 (set-buffer nnbabyl-mbox-buffer)
378 (goto-char (point-min)) 371 (goto-char (point-min))
379 (if (not (search-forward (nnbabyl-article-string article) nil t)) 372 (if (not (search-forward (nnbabyl-article-string article) nil t))
380 nil 373 nil
@@ -388,8 +381,7 @@
388 ;; Delete all articles in GROUP. 381 ;; Delete all articles in GROUP.
389 (if (not force) 382 (if (not force)
390 () ; Don't delete the articles. 383 () ; Don't delete the articles.
391 (save-excursion 384 (with-current-buffer nnbabyl-mbox-buffer
392 (set-buffer nnbabyl-mbox-buffer)
393 (goto-char (point-min)) 385 (goto-char (point-min))
394 ;; Delete all articles in this group. 386 ;; Delete all articles in this group.
395 (let ((ident (concat "\nX-Gnus-Newsgroup: " nnbabyl-current-group ":")) 387 (let ((ident (concat "\nX-Gnus-Newsgroup: " nnbabyl-current-group ":"))
@@ -409,8 +401,7 @@
409 401
410(deffoo nnbabyl-request-rename-group (group new-name &optional server) 402(deffoo nnbabyl-request-rename-group (group new-name &optional server)
411 (nnbabyl-possibly-change-newsgroup group server) 403 (nnbabyl-possibly-change-newsgroup group server)
412 (save-excursion 404 (with-current-buffer nnbabyl-mbox-buffer
413 (set-buffer nnbabyl-mbox-buffer)
414 (goto-char (point-min)) 405 (goto-char (point-min))
415 (let ((ident (concat "\nX-Gnus-Newsgroup: " nnbabyl-current-group ":")) 406 (let ((ident (concat "\nX-Gnus-Newsgroup: " nnbabyl-current-group ":"))
416 (new-ident (concat "\nX-Gnus-Newsgroup: " new-name ":")) 407 (new-ident (concat "\nX-Gnus-Newsgroup: " new-name ":"))
@@ -558,9 +549,8 @@
558(defun nnbabyl-create-mbox () 549(defun nnbabyl-create-mbox ()
559 (unless (file-exists-p nnbabyl-mbox-file) 550 (unless (file-exists-p nnbabyl-mbox-file)
560 ;; Create a new, empty RMAIL mbox file. 551 ;; Create a new, empty RMAIL mbox file.
561 (save-excursion 552 (with-current-buffer (setq nnbabyl-mbox-buffer
562 (set-buffer (setq nnbabyl-mbox-buffer 553 (create-file-buffer nnbabyl-mbox-file))
563 (create-file-buffer nnbabyl-mbox-file)))
564 (setq buffer-file-name nnbabyl-mbox-file) 554 (setq buffer-file-name nnbabyl-mbox-file)
565 (insert "BABYL OPTIONS:\n\n\^_") 555 (insert "BABYL OPTIONS:\n\n\^_")
566 (nnmail-write-region 556 (nnmail-write-region
@@ -572,8 +562,7 @@
572 562
573 (unless (and nnbabyl-mbox-buffer 563 (unless (and nnbabyl-mbox-buffer
574 (buffer-name nnbabyl-mbox-buffer) 564 (buffer-name nnbabyl-mbox-buffer)
575 (save-excursion 565 (with-current-buffer nnbabyl-mbox-buffer
576 (set-buffer nnbabyl-mbox-buffer)
577 (= (buffer-size) (nnheader-file-size nnbabyl-mbox-file)))) 566 (= (buffer-size) (nnheader-file-size nnbabyl-mbox-file))))
578 ;; This buffer has changed since we read it last. Possibly. 567 ;; This buffer has changed since we read it last. Possibly.
579 (save-excursion 568 (save-excursion
diff --git a/lisp/gnus/nndiary.el b/lisp/gnus/nndiary.el
index 3189d33dd5a..790e390424e 100644
--- a/lisp/gnus/nndiary.el
+++ b/lisp/gnus/nndiary.el
@@ -380,8 +380,7 @@ all. This may very well take some time.")
380 380
381(deffoo nndiary-retrieve-headers (sequence &optional group server fetch-old) 381(deffoo nndiary-retrieve-headers (sequence &optional group server fetch-old)
382 (when (nndiary-possibly-change-directory group server) 382 (when (nndiary-possibly-change-directory group server)
383 (save-excursion 383 (with-current-buffer nntp-server-buffer
384 (set-buffer nntp-server-buffer)
385 (erase-buffer) 384 (erase-buffer)
386 (let* ((file nil) 385 (let* ((file nil)
387 (number (length sequence)) 386 (number (length sequence))
@@ -615,8 +614,7 @@ all. This may very well take some time.")
615 (let (nndiary-current-directory 614 (let (nndiary-current-directory
616 nndiary-current-group 615 nndiary-current-group
617 nndiary-article-file-alist) 616 nndiary-article-file-alist)
618 (save-excursion 617 (with-current-buffer buf
619 (set-buffer buf)
620 (insert-buffer-substring nntp-server-buffer) 618 (insert-buffer-substring nntp-server-buffer)
621 (setq result (eval accept-form)) 619 (setq result (eval accept-form))
622 (kill-buffer (current-buffer)) 620 (kill-buffer (current-buffer))
@@ -672,8 +670,7 @@ all. This may very well take some time.")
672 670
673(deffoo nndiary-request-replace-article (article group buffer) 671(deffoo nndiary-request-replace-article (article group buffer)
674 (nndiary-possibly-change-directory group) 672 (nndiary-possibly-change-directory group)
675 (save-excursion 673 (with-current-buffer buffer
676 (set-buffer buffer)
677 (nndiary-possibly-create-directory group) 674 (nndiary-possibly-create-directory group)
678 (let ((chars (nnmail-insert-lines)) 675 (let ((chars (nnmail-insert-lines))
679 (art (concat (int-to-string article) "\t")) 676 (art (concat (int-to-string article) "\t"))
@@ -688,8 +685,7 @@ all. This may very well take some time.")
688 t) 685 t)
689 (setq headers (nndiary-parse-head chars article)) 686 (setq headers (nndiary-parse-head chars article))
690 ;; Replace the NOV line in the NOV file. 687 ;; Replace the NOV line in the NOV file.
691 (save-excursion 688 (with-current-buffer (nndiary-open-nov group)
692 (set-buffer (nndiary-open-nov group))
693 (goto-char (point-min)) 689 (goto-char (point-min))
694 (if (or (looking-at art) 690 (if (or (looking-at art)
695 (search-forward (concat "\n" art) nil t)) 691 (search-forward (concat "\n" art) nil t))
@@ -842,8 +838,7 @@ all. This may very well take some time.")
842 838
843;; Find an article number in the current group given the Message-ID. 839;; Find an article number in the current group given the Message-ID.
844(defun nndiary-find-group-number (id) 840(defun nndiary-find-group-number (id)
845 (save-excursion 841 (with-current-buffer (get-buffer-create " *nndiary id*")
846 (set-buffer (get-buffer-create " *nndiary id*"))
847 (let ((alist nndiary-group-alist) 842 (let ((alist nndiary-group-alist)
848 number) 843 number)
849 ;; We want to look through all .overview files, but we want to 844 ;; We want to look through all .overview files, but we want to
@@ -888,8 +883,7 @@ all. This may very well take some time.")
888 (let ((nov (expand-file-name nndiary-nov-file-name 883 (let ((nov (expand-file-name nndiary-nov-file-name
889 nndiary-current-directory))) 884 nndiary-current-directory)))
890 (when (file-exists-p nov) 885 (when (file-exists-p nov)
891 (save-excursion 886 (with-current-buffer nntp-server-buffer
892 (set-buffer nntp-server-buffer)
893 (erase-buffer) 887 (erase-buffer)
894 (nnheader-insert-file-contents nov) 888 (nnheader-insert-file-contents nov)
895 (if (and fetch-old 889 (if (and fetch-old
@@ -989,8 +983,7 @@ all. This may very well take some time.")
989 983
990(defun nndiary-add-nov (group article headers) 984(defun nndiary-add-nov (group article headers)
991 "Add a nov line for the GROUP base." 985 "Add a nov line for the GROUP base."
992 (save-excursion 986 (with-current-buffer (nndiary-open-nov group)
993 (set-buffer (nndiary-open-nov group))
994 (goto-char (point-max)) 987 (goto-char (point-max))
995 (mail-header-set-number headers article) 988 (mail-header-set-number headers article)
996 (nnheader-insert-nov headers))) 989 (nnheader-insert-nov headers)))
@@ -1015,8 +1008,7 @@ all. This may very well take some time.")
1015 (or (cdr (assoc group nndiary-nov-buffer-alist)) 1008 (or (cdr (assoc group nndiary-nov-buffer-alist))
1016 (let ((buffer (get-buffer-create (format " *nndiary overview %s*" 1009 (let ((buffer (get-buffer-create (format " *nndiary overview %s*"
1017 group)))) 1010 group))))
1018 (save-excursion 1011 (with-current-buffer buffer
1019 (set-buffer buffer)
1020 (set (make-local-variable 'nndiary-nov-buffer-file-name) 1012 (set (make-local-variable 'nndiary-nov-buffer-file-name)
1021 (expand-file-name 1013 (expand-file-name
1022 nndiary-nov-file-name 1014 nndiary-nov-file-name
@@ -1103,9 +1095,8 @@ all. This may very well take some time.")
1103 (nov (concat dir nndiary-nov-file-name)) 1095 (nov (concat dir nndiary-nov-file-name))
1104 (nov-buffer (get-buffer-create " *nov*")) 1096 (nov-buffer (get-buffer-create " *nov*"))
1105 chars file headers) 1097 chars file headers)
1106 (save-excursion 1098 ;; Init the nov buffer.
1107 ;; Init the nov buffer. 1099 (with-current-buffer nov-buffer
1108 (set-buffer nov-buffer)
1109 (buffer-disable-undo) 1100 (buffer-disable-undo)
1110 (erase-buffer) 1101 (erase-buffer)
1111 (set-buffer nntp-server-buffer) 1102 (set-buffer nntp-server-buffer)
@@ -1125,20 +1116,17 @@ all. This may very well take some time.")
1125 (unless (zerop (buffer-size)) 1116 (unless (zerop (buffer-size))
1126 (goto-char (point-min)) 1117 (goto-char (point-min))
1127 (setq headers (nndiary-parse-head chars (caar files))) 1118 (setq headers (nndiary-parse-head chars (caar files)))
1128 (save-excursion 1119 (with-current-buffer nov-buffer
1129 (set-buffer nov-buffer)
1130 (goto-char (point-max)) 1120 (goto-char (point-max))
1131 (nnheader-insert-nov headers))) 1121 (nnheader-insert-nov headers)))
1132 (widen)) 1122 (widen))
1133 (setq files (cdr files))) 1123 (setq files (cdr files)))
1134 (save-excursion 1124 (with-current-buffer nov-buffer
1135 (set-buffer nov-buffer)
1136 (nnmail-write-region 1 (point-max) nov nil 'nomesg) 1125 (nnmail-write-region 1 (point-max) nov nil 'nomesg)
1137 (kill-buffer (current-buffer)))))) 1126 (kill-buffer (current-buffer))))))
1138 1127
1139(defun nndiary-nov-delete-article (group article) 1128(defun nndiary-nov-delete-article (group article)
1140 (save-excursion 1129 (with-current-buffer (nndiary-open-nov group)
1141 (set-buffer (nndiary-open-nov group))
1142 (when (nnheader-find-nov-line article) 1130 (when (nnheader-find-nov-line article)
1143 (delete-region (point) (progn (forward-line 1) (point))) 1131 (delete-region (point) (progn (forward-line 1) (point)))
1144 (when (bobp) 1132 (when (bobp)
diff --git a/lisp/gnus/nndoc.el b/lisp/gnus/nndoc.el
index ddeac7f9523..2e492057003 100644
--- a/lisp/gnus/nndoc.el
+++ b/lisp/gnus/nndoc.el
@@ -215,8 +215,7 @@ from the document.")
215 215
216(deffoo nndoc-retrieve-headers (articles &optional newsgroup server fetch-old) 216(deffoo nndoc-retrieve-headers (articles &optional newsgroup server fetch-old)
217 (when (nndoc-possibly-change-buffer newsgroup server) 217 (when (nndoc-possibly-change-buffer newsgroup server)
218 (save-excursion 218 (with-current-buffer nntp-server-buffer
219 (set-buffer nntp-server-buffer)
220 (erase-buffer) 219 (erase-buffer)
221 (let (article entry) 220 (let (article entry)
222 (if (stringp (car articles)) 221 (if (stringp (car articles))
@@ -333,8 +332,7 @@ from the document.")
333 (concat " *nndoc " group "*")))) 332 (concat " *nndoc " group "*"))))
334 nndoc-group-alist) 333 nndoc-group-alist)
335 (setq nndoc-dissection-alist nil) 334 (setq nndoc-dissection-alist nil)
336 (save-excursion 335 (with-current-buffer nndoc-current-buffer
337 (set-buffer nndoc-current-buffer)
338 (erase-buffer) 336 (erase-buffer)
339 (if (and (stringp nndoc-address) 337 (if (and (stringp nndoc-address)
340 (string-match nndoc-binary-file-names nndoc-address)) 338 (string-match nndoc-binary-file-names nndoc-address))
@@ -347,8 +345,7 @@ from the document.")
347 ;; Initialize the nndoc structures according to this new document. 345 ;; Initialize the nndoc structures according to this new document.
348 (when (and nndoc-current-buffer 346 (when (and nndoc-current-buffer
349 (not nndoc-dissection-alist)) 347 (not nndoc-dissection-alist))
350 (save-excursion 348 (with-current-buffer nndoc-current-buffer
351 (set-buffer nndoc-current-buffer)
352 (nndoc-set-delims) 349 (nndoc-set-delims)
353 (if (eq nndoc-article-type 'mime-parts) 350 (if (eq nndoc-article-type 'mime-parts)
354 (nndoc-dissect-mime-parts) 351 (nndoc-dissect-mime-parts)
@@ -588,8 +585,7 @@ from the document.")
588(defun nndoc-generate-clari-briefs-head (article) 585(defun nndoc-generate-clari-briefs-head (article)
589 (let ((entry (cdr (assq article nndoc-dissection-alist))) 586 (let ((entry (cdr (assq article nndoc-dissection-alist)))
590 subject from) 587 subject from)
591 (save-excursion 588 (with-current-buffer nndoc-current-buffer
592 (set-buffer nndoc-current-buffer)
593 (save-restriction 589 (save-restriction
594 (narrow-to-region (car entry) (nth 3 entry)) 590 (narrow-to-region (car entry) (nth 3 entry))
595 (goto-char (point-min)) 591 (goto-char (point-min))
@@ -677,8 +673,7 @@ from the document.")
677 (let ((entry (cdr (assq article nndoc-dissection-alist))) 673 (let ((entry (cdr (assq article nndoc-dissection-alist)))
678 (from "<no address given>") 674 (from "<no address given>")
679 subject date) 675 subject date)
680 (save-excursion 676 (with-current-buffer nndoc-current-buffer
681 (set-buffer nndoc-current-buffer)
682 (save-restriction 677 (save-restriction
683 (narrow-to-region (car entry) (nth 1 entry)) 678 (narrow-to-region (car entry) (nth 1 entry))
684 (goto-char (point-min)) 679 (goto-char (point-min))
@@ -829,8 +824,7 @@ from the document.")
829 (first t) 824 (first t)
830 art-begin head-begin head-end body-begin body-end) 825 art-begin head-begin head-end body-begin body-end)
831 (setq nndoc-dissection-alist nil) 826 (setq nndoc-dissection-alist nil)
832 (save-excursion 827 (with-current-buffer nndoc-current-buffer
833 (set-buffer nndoc-current-buffer)
834 (goto-char (point-min)) 828 (goto-char (point-min))
835 ;; Remove blank lines. 829 ;; Remove blank lines.
836 (while (eq (following-char) ?\n) 830 (while (eq (following-char) ?\n)
@@ -902,8 +896,7 @@ When a MIME entity contains sub-entities, dissection produces one article for
902the header of this entity, and one article per sub-entity." 896the header of this entity, and one article per sub-entity."
903 (setq nndoc-dissection-alist nil 897 (setq nndoc-dissection-alist nil
904 nndoc-mime-split-ordinal 0) 898 nndoc-mime-split-ordinal 0)
905 (save-excursion 899 (with-current-buffer nndoc-current-buffer
906 (set-buffer nndoc-current-buffer)
907 (nndoc-dissect-mime-parts-sub (point-min) (point-max) nil nil nil))) 900 (nndoc-dissect-mime-parts-sub (point-min) (point-max) nil nil nil)))
908 901
909(defun nndoc-dissect-mime-parts-sub (head-begin body-end article-insert 902(defun nndoc-dissect-mime-parts-sub (head-begin body-end article-insert
diff --git a/lisp/gnus/nndraft.el b/lisp/gnus/nndraft.el
index dd2b8a6b48d..e92e00efe6f 100644
--- a/lisp/gnus/nndraft.el
+++ b/lisp/gnus/nndraft.el
@@ -77,8 +77,7 @@ are generated if and only if they are also in `message-draft-headers'.")
77 77
78(deffoo nndraft-retrieve-headers (articles &optional group server fetch-old) 78(deffoo nndraft-retrieve-headers (articles &optional group server fetch-old)
79 (nndraft-possibly-change-group group) 79 (nndraft-possibly-change-group group)
80 (save-excursion 80 (with-current-buffer nntp-server-buffer
81 (set-buffer nntp-server-buffer)
82 (erase-buffer) 81 (erase-buffer)
83 (let* (article) 82 (let* (article)
84 ;; We don't support fetching by Message-ID. 83 ;; We don't support fetching by Message-ID.
@@ -119,8 +118,7 @@ are generated if and only if they are also in `message-draft-headers'.")
119 mm-text-coding-system) 118 mm-text-coding-system)
120 mm-auto-save-coding-system))) 119 mm-auto-save-coding-system)))
121 (nnmail-find-file newest))) 120 (nnmail-find-file newest)))
122 (save-excursion 121 (with-current-buffer nntp-server-buffer
123 (set-buffer nntp-server-buffer)
124 (goto-char (point-min)) 122 (goto-char (point-min))
125 ;; If there's a mail header separator in this file, 123 ;; If there's a mail header separator in this file,
126 ;; we remove it. 124 ;; we remove it.
@@ -209,8 +207,7 @@ are generated if and only if they are also in `message-draft-headers'.")
209 result) 207 result)
210 (and 208 (and
211 (nndraft-request-article article group server) 209 (nndraft-request-article article group server)
212 (save-excursion 210 (with-current-buffer buf
213 (set-buffer buf)
214 (erase-buffer) 211 (erase-buffer)
215 (insert-buffer-substring nntp-server-buffer) 212 (insert-buffer-substring nntp-server-buffer)
216 (setq result (eval accept-form)) 213 (setq result (eval accept-form))
diff --git a/lisp/gnus/nneething.el b/lisp/gnus/nneething.el
index 2f05c7e7900..bd5bfba0468 100644
--- a/lisp/gnus/nneething.el
+++ b/lisp/gnus/nneething.el
@@ -81,8 +81,7 @@ included.")
81(deffoo nneething-retrieve-headers (articles &optional group server fetch-old) 81(deffoo nneething-retrieve-headers (articles &optional group server fetch-old)
82 (nneething-possibly-change-directory group) 82 (nneething-possibly-change-directory group)
83 83
84 (save-excursion 84 (with-current-buffer nntp-server-buffer
85 (set-buffer nntp-server-buffer)
86 (erase-buffer) 85 (erase-buffer)
87 (let* ((number (length articles)) 86 (let* ((number (length articles))
88 (count 0) 87 (count 0)
@@ -323,8 +322,7 @@ included.")
323 (if (equal '(0 0) (nth 5 atts)) "" 322 (if (equal '(0 0) (nth 5 atts)) ""
324 (concat "Date: " (current-time-string (nth 5 atts)) "\n")) 323 (concat "Date: " (current-time-string (nth 5 atts)) "\n"))
325 (or (when buffer 324 (or (when buffer
326 (save-excursion 325 (with-current-buffer buffer
327 (set-buffer buffer)
328 (when (re-search-forward "<[a-zA-Z0-9_]@[-a-zA-Z0-9_]>" 1000 t) 326 (when (re-search-forward "<[a-zA-Z0-9_]@[-a-zA-Z0-9_]>" 1000 t)
329 (concat "From: " (match-string 0) "\n")))) 327 (concat "From: " (match-string 0) "\n"))))
330 (nneething-from-line (nth 2 atts) file)) 328 (nneething-from-line (nth 2 atts) file))
@@ -332,8 +330,7 @@ included.")
332 (concat "Chars: " (int-to-string (nth 7 atts)) "\n") 330 (concat "Chars: " (int-to-string (nth 7 atts)) "\n")
333 "") 331 "")
334 (if buffer 332 (if buffer
335 (save-excursion 333 (with-current-buffer buffer
336 (set-buffer buffer)
337 (concat "Lines: " (int-to-string 334 (concat "Lines: " (int-to-string
338 (count-lines (point-min) (point-max))) 335 (count-lines (point-min) (point-max)))
339 "\n")) 336 "\n"))
@@ -382,8 +379,7 @@ included.")
382 379
383(defun nneething-get-head (file) 380(defun nneething-get-head (file)
384 "Either find the head in FILE or make a head for FILE." 381 "Either find the head in FILE or make a head for FILE."
385 (save-excursion 382 (with-current-buffer (get-buffer-create nneething-work-buffer)
386 (set-buffer (get-buffer-create nneething-work-buffer))
387 (setq case-fold-search nil) 383 (setq case-fold-search nil)
388 (buffer-disable-undo) 384 (buffer-disable-undo)
389 (erase-buffer) 385 (erase-buffer)
diff --git a/lisp/gnus/nnfolder.el b/lisp/gnus/nnfolder.el
index 6413e98cc1e..5cebcb0e5fc 100644
--- a/lisp/gnus/nnfolder.el
+++ b/lisp/gnus/nnfolder.el
@@ -157,8 +157,7 @@ the group. Then the marks file will be regenerated properly by Gnus.")
157(nnoo-define-basics nnfolder) 157(nnoo-define-basics nnfolder)
158 158
159(deffoo nnfolder-retrieve-headers (articles &optional group server fetch-old) 159(deffoo nnfolder-retrieve-headers (articles &optional group server fetch-old)
160 (save-excursion 160 (with-current-buffer nntp-server-buffer
161 (set-buffer nntp-server-buffer)
162 (erase-buffer) 161 (erase-buffer)
163 (let (article start stop num) 162 (let (article start stop num)
164 (nnfolder-possibly-change-group group server) 163 (nnfolder-possibly-change-group group server)
@@ -261,8 +260,7 @@ the group. Then the marks file will be regenerated properly by Gnus.")
261 260
262(deffoo nnfolder-request-article (article &optional group server buffer) 261(deffoo nnfolder-request-article (article &optional group server buffer)
263 (nnfolder-possibly-change-group group server) 262 (nnfolder-possibly-change-group group server)
264 (save-excursion 263 (with-current-buffer nnfolder-current-buffer
265 (set-buffer nnfolder-current-buffer)
266 (goto-char (point-min)) 264 (goto-char (point-min))
267 (when (nnfolder-goto-article article) 265 (when (nnfolder-goto-article article)
268 (let (start stop) 266 (let (start stop)
@@ -360,8 +358,7 @@ the group. Then the marks file will be regenerated properly by Gnus.")
360 nnfolder-current-group (car inf)))) 358 nnfolder-current-group (car inf))))
361 (when (and nnfolder-current-buffer 359 (when (and nnfolder-current-buffer
362 (buffer-name nnfolder-current-buffer)) 360 (buffer-name nnfolder-current-buffer))
363 (save-excursion 361 (with-current-buffer nnfolder-current-buffer
364 (set-buffer nnfolder-current-buffer)
365 ;; If the buffer was modified, write the file out now. 362 ;; If the buffer was modified, write the file out now.
366 (nnfolder-save-buffer) 363 (nnfolder-save-buffer)
367 ;; If we're shutting the server down, we need to kill the 364 ;; If we're shutting the server down, we need to kill the
@@ -447,8 +444,7 @@ the group. Then the marks file will be regenerated properly by Gnus.")
447 target) 444 target)
448 (nnmail-activate 'nnfolder) 445 (nnmail-activate 'nnfolder)
449 446
450 (save-excursion 447 (with-current-buffer nnfolder-current-buffer
451 (set-buffer nnfolder-current-buffer)
452 ;; Since messages are sorted in arrival order and expired in the 448 ;; Since messages are sorted in arrival order and expired in the
453 ;; same order, we can stop as soon as we find a message that is 449 ;; same order, we can stop as soon as we find a message that is
454 ;; too old. 450 ;; too old.
@@ -501,8 +497,7 @@ the group. Then the marks file will be regenerated properly by Gnus.")
501 result) 497 result)
502 (and 498 (and
503 (nnfolder-request-article article group server) 499 (nnfolder-request-article article group server)
504 (save-excursion 500 (with-current-buffer buf
505 (set-buffer buf)
506 (erase-buffer) 501 (erase-buffer)
507 (insert-buffer-substring nntp-server-buffer) 502 (insert-buffer-substring nntp-server-buffer)
508 (goto-char (point-min)) 503 (goto-char (point-min))
@@ -578,8 +573,7 @@ the group. Then the marks file will be regenerated properly by Gnus.")
578 573
579(deffoo nnfolder-request-replace-article (article group buffer) 574(deffoo nnfolder-request-replace-article (article group buffer)
580 (nnfolder-possibly-change-group group) 575 (nnfolder-possibly-change-group group)
581 (save-excursion 576 (with-current-buffer buffer
582 (set-buffer buffer)
583 (goto-char (point-min)) 577 (goto-char (point-min))
584 (if (not (looking-at "X-From-Line: ")) 578 (if (not (looking-at "X-From-Line: "))
585 (insert "From nobody " (current-time-string) "\n") 579 (insert "From nobody " (current-time-string) "\n")
@@ -596,8 +590,7 @@ the group. Then the marks file will be regenerated properly by Gnus.")
596 (nnfolder-delete-mail) 590 (nnfolder-delete-mail)
597 (insert-buffer-substring buffer) 591 (insert-buffer-substring buffer)
598 (unless (or gnus-nov-is-evil nnfolder-nov-is-evil) 592 (unless (or gnus-nov-is-evil nnfolder-nov-is-evil)
599 (save-excursion 593 (with-current-buffer buffer
600 (set-buffer buffer)
601 (let ((headers (nnfolder-parse-head article 594 (let ((headers (nnfolder-parse-head article
602 (point-min) (point-max)))) 595 (point-min) (point-max))))
603 (with-current-buffer (nnfolder-open-nov group) 596 (with-current-buffer (nnfolder-open-nov group)
@@ -630,8 +623,7 @@ the group. Then the marks file will be regenerated properly by Gnus.")
630 623
631(deffoo nnfolder-request-rename-group (group new-name &optional server) 624(deffoo nnfolder-request-rename-group (group new-name &optional server)
632 (nnfolder-possibly-change-group group server) 625 (nnfolder-possibly-change-group group server)
633 (save-excursion 626 (with-current-buffer nnfolder-current-buffer
634 (set-buffer nnfolder-current-buffer)
635 (and (file-writable-p buffer-file-name) 627 (and (file-writable-p buffer-file-name)
636 (ignore-errors 628 (ignore-errors
637 (let ((new-file (nnfolder-group-pathname new-name))) 629 (let ((new-file (nnfolder-group-pathname new-name)))
@@ -671,8 +663,7 @@ the group. Then the marks file will be regenerated properly by Gnus.")
671 (marker (concat "\n" nnfolder-article-marker)) 663 (marker (concat "\n" nnfolder-article-marker))
672 (number "[0-9]+") 664 (number "[0-9]+")
673 (activemin (cdr active))) 665 (activemin (cdr active)))
674 (save-excursion 666 (with-current-buffer nnfolder-current-buffer
675 (set-buffer nnfolder-current-buffer)
676 (goto-char (point-min)) 667 (goto-char (point-min))
677 (while (and (search-forward marker nil t) 668 (while (and (search-forward marker nil t)
678 (re-search-forward number nil t)) 669 (re-search-forward number nil t))
@@ -1114,8 +1105,7 @@ This command does not work if you use short group names."
1114(defun nnfolder-open-nov (group) 1105(defun nnfolder-open-nov (group)
1115 (or (cdr (assoc group nnfolder-nov-buffer-alist)) 1106 (or (cdr (assoc group nnfolder-nov-buffer-alist))
1116 (let ((buffer (get-buffer-create (format " *nnfolder overview %s*" group)))) 1107 (let ((buffer (get-buffer-create (format " *nnfolder overview %s*" group))))
1117 (save-excursion 1108 (with-current-buffer buffer
1118 (set-buffer buffer)
1119 (set (make-local-variable 'nnfolder-nov-buffer-file-name) 1109 (set (make-local-variable 'nnfolder-nov-buffer-file-name)
1120 (nnfolder-group-nov-pathname group)) 1110 (nnfolder-group-nov-pathname group))
1121 (erase-buffer) 1111 (erase-buffer)
@@ -1139,8 +1129,7 @@ This command does not work if you use short group names."
1139 (setq nnfolder-nov-buffer-alist (cdr nnfolder-nov-buffer-alist))))) 1129 (setq nnfolder-nov-buffer-alist (cdr nnfolder-nov-buffer-alist)))))
1140 1130
1141(defun nnfolder-nov-delete-article (group article) 1131(defun nnfolder-nov-delete-article (group article)
1142 (save-excursion 1132 (with-current-buffer (nnfolder-open-nov group)
1143 (set-buffer (nnfolder-open-nov group))
1144 (when (nnheader-find-nov-line article) 1133 (when (nnheader-find-nov-line article)
1145 (delete-region (point) (progn (forward-line 1) (point)))) 1134 (delete-region (point) (progn (forward-line 1) (point))))
1146 t)) 1135 t))
@@ -1150,8 +1139,7 @@ This command does not work if you use short group names."
1150 nil 1139 nil
1151 (let ((nov (nnfolder-group-nov-pathname nnfolder-current-group))) 1140 (let ((nov (nnfolder-group-nov-pathname nnfolder-current-group)))
1152 (when (file-exists-p nov) 1141 (when (file-exists-p nov)
1153 (save-excursion 1142 (with-current-buffer nntp-server-buffer
1154 (set-buffer nntp-server-buffer)
1155 (erase-buffer) 1143 (erase-buffer)
1156 (nnheader-insert-file-contents nov) 1144 (nnheader-insert-file-contents nov)
1157 (if (and fetch-old 1145 (if (and fetch-old
@@ -1187,8 +1175,7 @@ This command does not work if you use short group names."
1187 1175
1188(defun nnfolder-add-nov (group article headers) 1176(defun nnfolder-add-nov (group article headers)
1189 "Add a nov line for the GROUP base." 1177 "Add a nov line for the GROUP base."
1190 (save-excursion 1178 (with-current-buffer (nnfolder-open-nov group)
1191 (set-buffer (nnfolder-open-nov group))
1192 (goto-char (point-max)) 1179 (goto-char (point-max))
1193 (mail-header-set-number headers article) 1180 (mail-header-set-number headers article)
1194 (nnheader-insert-nov headers))) 1181 (nnheader-insert-nov headers)))
diff --git a/lisp/gnus/nnheader.el b/lisp/gnus/nnheader.el
index 9a90a76f7af..1bfdbeab9c4 100644
--- a/lisp/gnus/nnheader.el
+++ b/lisp/gnus/nnheader.el
@@ -835,8 +835,7 @@ The first string in ARGS can be a format string."
835 "Clear the communication buffer and insert FORMAT and ARGS into the buffer. 835 "Clear the communication buffer and insert FORMAT and ARGS into the buffer.
836If FORMAT isn't a format string, it and all ARGS will be inserted 836If FORMAT isn't a format string, it and all ARGS will be inserted
837without formatting." 837without formatting."
838 (save-excursion 838 (with-current-buffer nntp-server-buffer
839 (set-buffer nntp-server-buffer)
840 (erase-buffer) 839 (erase-buffer)
841 (if (string-match "%" format) 840 (if (string-match "%" format)
842 (insert (apply 'format format args)) 841 (insert (apply 'format format args))
diff --git a/lisp/gnus/nnimap.el b/lisp/gnus/nnimap.el
index d412af46d0c..e7bf0f376a8 100644
--- a/lisp/gnus/nnimap.el
+++ b/lisp/gnus/nnimap.el
@@ -1,11 +1,9 @@
1;;; nnimap.el --- imap backend for Gnus 1;;; nnimap.el --- IMAP interface for Gnus
2 2
3;; Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 3;; Copyright (C) 2010 Free Software Foundation, Inc.
4;; 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
5 4
6;; Author: Simon Josefsson <simon@josefsson.org> 5;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
7;; Jim Radford <radford@robby.caltech.edu> 6;; Simon Josefsson <simon@josefsson.org>
8;; Keywords: mail
9 7
10;; This file is part of GNU Emacs. 8;; This file is part of GNU Emacs.
11 9
@@ -24,1791 +22,942 @@
24 22
25;;; Commentary: 23;;; Commentary:
26 24
27;; Todo, major things: 25;; nnimap interfaces Gnus with IMAP servers.
28;;
29;; o Fix Gnus to view correct number of unread/total articles in group buffer
30;; o Fix Gnus to handle leading '.' in group names (fixed?)
31;; o Finish disconnected mode (moving articles between mailboxes unplugged)
32;; o Sieve
33;; o MIME (partial article fetches)
34;; o Split to other backends, different split rules for different
35;; servers/inboxes
36;;
37;; Todo, minor things:
38;;
39;; o Don't require half of Gnus -- backends should be standalone
40;; o Verify that we don't use IMAP4rev1 specific things (RFC2060 App B)
41;; o Dont uid fetch 1,* in nnimap-retrive-groups (slow)
42;; o Split up big fetches (1,* header especially) in smaller chunks
43;; o What do I do with gnus-newsgroup-*?
44;; o Tell Gnus about new groups (how can we tell?)
45;; o Respooling (fix Gnus?) (unnecessary?)
46;; o Add support for the following: (if applicable)
47;; request-list-newsgroups, request-regenerate
48;; list-active-group,
49;; request-associate-buffer, request-restore-buffer,
50;; o Do The Right Thing when UIDVALIDITY changes (what's the right thing?)
51;; o Support RFC2221 (Login referrals)
52;; o IMAP2BIS compatibility? (RFC2061)
53;; o ACAP stuff (perhaps a different project, would be nice to ACAPify
54;; .newsrc.eld)
55;; o What about Gnus's article editing, can we support it? NO!
56;; o Use \Draft to support the draft group??
57;; o Duplicate suppression
58;; o Rewrite UID SEARCH UID X as UID FETCH X (UID) for those with slow servers
59 26
60;;; Code: 27;;; Code:
61 28
62;; For Emacs < 22.2.
63(eval-and-compile 29(eval-and-compile
64 (unless (fboundp 'declare-function) (defmacro declare-function (&rest r)))) 30 (require 'nnheader))
65 31
66(require 'imap) 32(eval-when-compile
67(require 'nnoo) 33 (require 'cl))
68(require 'nnmail)
69(require 'nnheader)
70(require 'mm-util)
71(require 'gnus)
72(require 'gnus-range)
73(require 'gnus-start)
74(require 'gnus-int)
75 34
76(eval-when-compile (require 'cl)) 35(require 'netrc)
77
78(autoload 'auth-source-user-or-password "auth-source")
79 36
80(nnoo-declare nnimap) 37(nnoo-declare nnimap)
81 38
82(defconst nnimap-version "nnimap 1.0")
83
84(defgroup nnimap nil
85 "Reading IMAP mail with Gnus."
86 :group 'gnus)
87
88(defvoo nnimap-address nil 39(defvoo nnimap-address nil
89 "Address of physical IMAP server. If nil, use the virtual server's name.") 40 "The address of the IMAP server.")
90 41
91(defvoo nnimap-server-port nil 42(defvoo nnimap-server-port nil
92 "Port number on physical IMAP server. 43 "The IMAP port used.
93If nil, defaults to 993 for TLS/SSL connections and 143 otherwise.") 44If nnimap-stream is `ssl', this will default to `imaps'. If not,
94 45it will default to `imap'.")
95;; Splitting variables 46
96 47(defvoo nnimap-stream 'ssl
97(defcustom nnimap-split-crosspost t 48 "How nnimap will talk to the IMAP server.
98 "If non-nil, do crossposting if several split methods match the mail. 49Values are `ssl' and `network'.")
99If nil, the first match found will be used." 50
100 :group 'nnimap 51(defvoo nnimap-shell-program (if (boundp 'imap-shell-program)
101 :type 'boolean) 52 (if (listp imap-shell-program)
102 53 (car imap-shell-program)
103(defcustom nnimap-split-inbox nil 54 imap-shell-program)
104 "Name of mailbox to split mail from. 55 "ssh %s imapd"))
105 56
106Mail is read from this mailbox and split according to rules in 57(defvoo nnimap-inbox nil
107`nnimap-split-rule'. 58 "The mail box where incoming mail arrives and should be split out of.")
108 59
109This can be a string or a list of strings." 60(defvoo nnimap-expunge-inbox nil
110 :group 'nnimap 61 "If non-nil, expunge the inbox after fetching mail.
111 :type '(choice (string) 62This is always done if the server supports UID EXPUNGE, but it's
112 (repeat string))) 63not done by default on servers that doesn't support that command.")
113 64
114(define-widget 'nnimap-strict-function 'function 65(defvoo nnimap-connection-alist nil)
115 "This widget only matches values that are functionp. 66(defvar nnimap-process nil)
116 67
117Warning: This means that a value that is the symbol of a not yet 68(defvar nnimap-status-string "")
118loaded function will not match. Use with care."
119 :match 'nnimap-strict-function-match)
120
121(defun nnimap-strict-function-match (widget value)
122 "Ignoring WIDGET, match if VALUE is a function."
123 (functionp value))
124
125(defcustom nnimap-split-rule nil
126 "Mail will be split according to these rules.
127
128Mail is read from mailbox(es) specified in `nnimap-split-inbox'.
129
130If you'd like, for instance, one mail group for mail from the
131\"gnus-imap\" mailing list, one group for junk mail and leave
132everything else in the incoming mailbox, you could do something like
133this:
134
135\(setq nnimap-split-rule '((\"INBOX.gnus-imap\" \"From:.*gnus-imap\")
136 (\"INBOX.junk\" \"Subject:.*buy\")))
137
138As you can see, `nnimap-split-rule' is a list of lists, where the
139first element in each \"rule\" is the name of the IMAP mailbox (or the
140symbol `junk' if you want to remove the mail), and the second is a
141regexp that nnimap will try to match on the header to find a fit.
142
143The second element can also be a function. In that case, it will be
144called narrowed to the headers with the first element of the rule as
145the argument. It should return a non-nil value if it thinks that the
146mail belongs in that group.
147
148This variable can also have a function as its value, the function will
149be called with the headers narrowed and should return a group where it
150thinks the article should be splitted to. See `nnimap-split-fancy'.
151
152To allow for different split rules on different virtual servers, and
153even different split rules in different inboxes on the same server,
154the syntax of this variable have been extended along the lines of:
155
156\(setq nnimap-split-rule
157 '((\"my1server\" (\".*\" ((\"ding\" \"ding@gnus.org\")
158 (\"junk\" \"From:.*Simon\")))
159 (\"my2server\" (\"INBOX\" nnimap-split-fancy))
160 (\"my[34]server\" (\".*\" ((\"private\" \"To:.*Simon\")
161 (\"junk\" my-junk-func)))))
162
163The virtual server name is in fact a regexp, so that the same rules
164may apply to several servers. In the example, the servers
165\"my3server\" and \"my4server\" both use the same rules. Similarly,
166the inbox string is also a regexp. The actual splitting rules are as
167before, either a function, or a list with group/regexp or
168group/function elements."
169 :group 'nnimap
170 ;; FIXME: Doesn't allow `("my2server" ("INBOX" nnimap-split-fancy))'
171 ;; per example above. -- fx
172 :type '(choice :tag "Rule type"
173 (repeat :menu-tag "Single-server"
174 :tag "Single-server list"
175 (list (string :tag "Mailbox")
176 (choice :tag "Predicate"
177 (regexp :tag "A regexp")
178 (nnimap-strict-function :tag "A function"))))
179 (choice :menu-tag "A function"
180 :tag "A function"
181 (function-item nnimap-split-fancy)
182 (function-item nnmail-split-fancy)
183 (nnimap-strict-function :tag "User-defined function"))
184 (repeat :menu-tag "Multi-server (extended)"
185 :tag "Multi-server list"
186 (list (regexp :tag "Server regexp")
187 (list (regexp :tag "Incoming Mailbox regexp")
188 (repeat :tag "Rules for matching server(s) and mailbox(es)"
189 (list (string :tag "Destination mailbox")
190 (choice :tag "Predicate"
191 (regexp :tag "A Regexp")
192 (nnimap-strict-function :tag "A Function")))))))))
193
194(defcustom nnimap-split-predicate "UNSEEN UNDELETED"
195 "The predicate used to find articles to split.
196If you use another IMAP client to peek on articles but always would
197like nnimap to split them once it's started, you could change this to
198\"UNDELETED\". Other available predicates are available in
199RFC2060 section 6.4.4."
200 :group 'nnimap
201 :type 'string)
202
203(defcustom nnimap-split-fancy nil
204 "Like the variable `nnmail-split-fancy'."
205 :group 'nnimap
206 :type 'sexp)
207 69
208(defvar nnimap-split-download-body-default nil 70(defvar nnimap-split-download-body-default nil
209 "Internal variable with default value for `nnimap-split-download-body'.") 71 "Internal variable with default value for `nnimap-split-download-body'.")
210 72
211(defcustom nnimap-split-download-body 'default 73(defstruct nnimap
212 "Whether to download entire articles during splitting. 74 group process commands capabilities)
213This is generally not required, and will slow things down considerably.
214You may need it if you want to use an advanced splitting function that
215analyzes the body before splitting the article.
216If this variable is nil, bodies will not be downloaded; if this
217variable is the symbol `default' the default behavior is
218used (which currently is nil, unless you use a statistical
219spam.el test); if this variable is another non-nil value bodies
220will be downloaded."
221 :version "22.1"
222 :group 'nnimap
223 :type '(choice (const :tag "Let system decide" deault)
224 boolean))
225
226;; Performance / bug workaround variables
227
228(defcustom nnimap-close-asynchronous t
229 "Close mailboxes asynchronously in `nnimap-close-group'.
230This means that errors caught by nnimap when closing the mailbox will
231not prevent Gnus from updating the group status, which may be harmful.
232However, it increases speed."
233 :version "22.1"
234 :type 'boolean
235 :group 'nnimap)
236
237(defcustom nnimap-dont-close t
238 "Never close mailboxes.
239This increases the speed of closing mailboxes (quiting group) but may
240decrease the speed of selecting another mailbox later. Re-selecting
241the same mailbox will be faster though."
242 :version "22.1"
243 :type 'boolean
244 :group 'nnimap)
245
246(defcustom nnimap-retrieve-groups-asynchronous t
247 "Send asynchronous STATUS commands for each mailbox before checking mail.
248If you have mailboxes that rarely receives mail, this speeds up new
249mail checking. It works by first sending STATUS commands for each
250mailbox, and then only checking groups which has a modified UIDNEXT
251more carefully for new mail.
252
253In summary, the default is O((1-p)*k+p*n) and changing it to nil makes
254it O(n). If p is small, then the default is probably faster."
255 :version "22.1"
256 :type 'boolean
257 :group 'nnimap)
258
259(defvoo nnimap-need-unselect-to-notice-new-mail t
260 "Unselect mailboxes before looking for new mail in them.
261Some servers seem to need this under some circumstances.")
262
263(defvoo nnimap-logout-timeout nil
264 "Close server immediately if it can't logout in this number of seconds.
265If it is nil, never close server until logout completes. This variable
266overrides `imap-logout-timeout' on a per-server basis.")
267
268;; Authorization / Privacy variables
269
270(defvoo nnimap-auth-method nil
271 "Obsolete.")
272
273(defvoo nnimap-stream nil
274 "How nnimap will connect to the server.
275
276The default, nil, will try to use the \"best\" method the server can
277handle.
278
279Change this if
280
2811) you want to connect with TLS/SSL. The TLS/SSL integration
282 with IMAP is suboptimal so you'll have to tell it
283 specifically.
284
2852) your server is more capable than your environment -- i.e. your
286 server accept Kerberos login's but you haven't installed the
287 `imtest' program or your machine isn't configured for Kerberos.
288
289Possible choices: gssapi, kerberos4, starttls, tls, ssl, network, shell.
290See also `imap-streams' and `imap-stream-alist'.")
291
292(defvoo nnimap-authenticator nil
293 "How nnimap authenticate itself to the server.
294
295The default, nil, will try to use the \"best\" method the server can
296handle.
297
298There is only one reason for fiddling with this variable, and that is
299if your server is more capable than your environment -- i.e. you
300connect to a server that accept Kerberos login's but you haven't
301installed the `imtest' program or your machine isn't configured for
302Kerberos.
303
304Possible choices: gssapi, kerberos4, digest-md5, cram-md5, login, anonymous.
305See also `imap-authenticators' and `imap-authenticator-alist'")
306
307(defvoo nnimap-directory (nnheader-concat gnus-directory "overview/")
308 "Directory to keep NOV cache files for nnimap groups.
309See also `nnimap-nov-file-name'.")
310
311(defvoo nnimap-nov-file-name "nnimap."
312 "NOV cache base filename.
313The group name and `nnimap-nov-file-name-suffix' will be appended. A
314typical complete file name would be
315~/News/overview/nnimap.pdc.INBOX.ding.nov, or
316~/News/overview/nnimap/pdc/INBOX/ding/nov if
317`nnmail-use-long-file-names' is nil")
318
319(defvoo nnimap-nov-file-name-suffix ".novcache"
320 "Suffix for NOV cache base filename.")
321
322(defvoo nnimap-nov-is-evil gnus-agent
323 "If non-nil, never generate or use a local nov database for this backend.
324Using nov databases should speed up header fetching considerably.
325However, it will invoke a UID SEARCH UID command on the server, and
326some servers implement this command inefficiently by opening each and
327every message in the group, thus making it quite slow.
328Unlike other backends, you do not need to take special care if you
329flip this variable.")
330
331(defvoo nnimap-search-uids-not-since-is-evil nil
332 "If non-nil, avoid \"UID SEARCH UID ... NOT SINCE\" queries when expiring.
333Instead, use \"UID SEARCH SINCE\" to prune the list of expirable
334articles within Gnus. This seems to be faster on Courier in some cases.")
335
336(defvoo nnimap-expunge-on-close 'always ; 'ask, 'never
337 "Whether to expunge a group when it is closed.
338When a IMAP group with articles marked for deletion is closed, this
339variable determine if nnimap should actually remove the articles or
340not.
341
342If always, nnimap always perform a expunge when closing the group.
343If never, nnimap never expunges articles marked for deletion.
344If ask, nnimap will ask you if you wish to expunge marked articles.
345
346When setting this variable to `never', you can only expunge articles
347by using `G x' (gnus-group-nnimap-expunge) from the Group buffer.")
348
349(defvoo nnimap-list-pattern "*"
350 "A string LIMIT or list of strings with mailbox wildcards used to limit available groups.
351See below for available wildcards.
352
353The LIMIT string can be a cons cell (REFERENCE . LIMIT), where
354REFERENCE will be passed as the first parameter to LIST/LSUB. The
355semantics of this are server specific, on the University of Washington
356server you can specify a directory.
357
358Example:
359 '(\"INBOX\" \"mail/*\" (\"~friend/mail/\" . \"list/*\"))
360
361There are two wildcards * and %. * matches everything, % matches
362everything in the current hierarchy.")
363
364(defvoo nnimap-news-groups nil
365 "IMAP support a news-like mode, also known as bulletin board mode,
366where replies is sent via IMAP instead of SMTP.
367
368This variable should contain a regexp matching groups where you wish
369replies to be stored to the mailbox directly.
370
371Example:
372 '(\"^[^I][^N][^B][^O][^X].*$\")
373
374This will match all groups not beginning with \"INBOX\".
375
376Note that there is nothing technically different between mail-like and
377news-like mailboxes. If you wish to have a group with todo items or
378similar which you wouldn't want to set up a mailing list for, you can
379use this to make replies go directly to the group.")
380
381(defvoo nnimap-expunge-search-string "UID %s NOT SINCE %s"
382 "IMAP search command to use for articles that are to be expired.
383The first %s is replaced by a UID set of articles to search on,
384and the second %s is replaced by a date criterium.
385
386One useful (and perhaps the only useful) value to change this to would
387be `UID %s NOT SENTSINCE %s' to make nnimap use the Date: header
388instead of the internal date of messages. See section 6.4.4 of RFC
3892060 for more information on valid strings.
390
391However, if `nnimap-search-uids-not-since-is-evil' is true, this
392variable has no effect since the search logic is reversed.")
393
394(defvoo nnimap-importantize-dormant t
395 "If non-nil, mark \"dormant\" articles as \"ticked\" for other IMAP clients.
396Note that within Gnus, dormant articles will still (only) be
397marked as ticked. This is to make \"dormant\" articles stand out,
398just like \"ticked\" articles, in other IMAP clients.")
399
400(defvoo nnimap-server-address nil
401 "Obsolete. Use `nnimap-address'.")
402
403(defcustom nnimap-authinfo-file "~/.authinfo"
404 "Authorization information for IMAP servers. In .netrc format."
405 :type
406 '(choice file
407 (repeat :tag "Entries"
408 :menu-tag "Inline"
409 (list :format "%v"
410 :value ("" ("login" . "") ("password" . ""))
411 (string :tag "Host")
412 (checklist :inline t
413 (cons :format "%v"
414 (const :format "" "login")
415 (string :format "Login: %v"))
416 (cons :format "%v"
417 (const :format "" "password")
418 (string :format "Password: %v"))))))
419 :group 'nnimap)
420
421(defcustom nnimap-prune-cache t
422 "If non-nil, nnimap check whether articles still exist on server before using data stored in NOV cache."
423 :type 'boolean
424 :group 'nnimap)
425
426(defvar nnimap-request-list-method 'imap-mailbox-list
427 "Method to use to request a list of all folders from the server.
428If this is 'imap-mailbox-lsub, then use a server-side subscription list to
429restrict visible folders.")
430
431(defcustom nnimap-id nil
432 "Plist with client identity to send to server upon login.
433A nil value means no information is sent, symbol `no' to disable ID query
434altogether, or plist with identifier-value pairs to send to
435server. RFC 2971 describes the list as follows:
436
437 Any string may be sent as a field, but the following are defined to
438 describe certain values that might be sent. Implementations are free
439 to send none, any, or all of these. Strings are not case-sensitive.
440 Field strings MUST NOT be longer than 30 octets. Value strings MUST
441 NOT be longer than 1024 octets. Implementations MUST NOT send more
442 than 30 field-value pairs.
443
444 name Name of the program
445 version Version number of the program
446 os Name of the operating system
447 os-version Version of the operating system
448 vendor Vendor of the client/server
449 support-url URL to contact for support
450 address Postal address of contact/vendor
451 date Date program was released, specified as a date-time
452 in IMAP4rev1
453 command Command used to start the program
454 arguments Arguments supplied on the command line, if any
455 if any
456 environment Description of environment, i.e., UNIX environment
457 variables or Windows registry settings
458
459 Implementations MUST NOT send the same field name more than once.
460
461An example plist would be '(\"name\" \"Gnus\" \"version\" gnus-version-number
462\"os\" system-configuration \"vendor\" \"GNU\")."
463 :group 'nnimap
464 :type '(choice (const :tag "No information" nil)
465 (const :tag "Disable ID query" no)
466 (plist :key-type string :value-type string)))
467
468(defcustom nnimap-debug nil
469 "If non-nil, trace nnimap- functions into `nnimap-debug-buffer'.
470Uses `trace-function-background', so you can turn it off with,
471say, `untrace-all'.
472
473Note that username, passwords and other privacy sensitive
474information (such as e-mail) may be stored in the buffer.
475It is not written to disk, however. Do not enable this
476variable unless you are comfortable with that.
477
478This variable only takes effect when loading the `nnimap' library.
479See also `nnimap-log'."
480 :group 'nnimap
481 :type 'boolean)
482
483;; Internal variables:
484
485(defvar nnimap-debug-buffer "*nnimap-debug*")
486(defvar nnimap-mailbox-info (gnus-make-hashtable 997))
487(defvar nnimap-current-move-server nil)
488(defvar nnimap-current-move-group nil)
489(defvar nnimap-current-move-article nil)
490(defvar nnimap-length)
491(defvar nnimap-progress-chars '(?| ?/ ?- ?\\))
492(defvar nnimap-progress-how-often 20)
493(defvar nnimap-counter)
494(defvar nnimap-server-buffer-alist nil) ;; Map server name to buffers.
495(defvar nnimap-current-server nil) ;; Current server
496(defvar nnimap-server-buffer nil) ;; Current servers' buffer
497
498
499
500(nnoo-define-basics nnimap)
501
502;; Utility functions:
503
504(defsubst nnimap-decode-group-name (group)
505 (and group
506 (gnus-group-decoded-name group)))
507
508(defsubst nnimap-encode-group-name (group)
509 (and group
510 (mm-encode-coding-string group (gnus-group-name-charset nil group))))
511
512(defun nnimap-group-prefixed-name (group &optional server)
513 (gnus-group-prefixed-name group
514 (gnus-server-to-method
515 (format "nnimap:%s"
516 (or server nnimap-current-server)))))
517
518(defsubst nnimap-get-server-buffer (server)
519 "Return buffer for SERVER, if nil use current server."
520 (cadr (assoc (or server nnimap-current-server) nnimap-server-buffer-alist)))
521
522(defun nnimap-remove-server-from-buffer-alist (server list)
523 "Remove SERVER from LIST."
524 (let (l)
525 (dolist (e list)
526 (unless (equal server (car-safe e))
527 (push e l)))
528 l))
529
530(defun nnimap-possibly-change-server (server)
531 "Return buffer for SERVER, changing the current server as a side-effect.
532If SERVER is nil, uses the current server."
533 (setq nnimap-current-server (or server nnimap-current-server)
534 nnimap-server-buffer (nnimap-get-server-buffer nnimap-current-server)))
535
536(defun nnimap-verify-uidvalidity (group server)
537 "Verify stored uidvalidity match current one in GROUP on SERVER."
538 (let* ((gnusgroup (nnimap-group-prefixed-name group server))
539 (new-uidvalidity (imap-mailbox-get 'uidvalidity))
540 (old-uidvalidity (gnus-group-get-parameter gnusgroup 'uidvalidity))
541 (dir (file-name-as-directory (expand-file-name nnimap-directory)))
542 (nameuid (nnheader-translate-file-chars
543 (concat nnimap-nov-file-name
544 (if (equal server "")
545 "unnamed"
546 server) "." group "." old-uidvalidity
547 nnimap-nov-file-name-suffix) t))
548 (file (if (or nnmail-use-long-file-names
549 (file-exists-p (expand-file-name nameuid dir)))
550 (expand-file-name nameuid dir)
551 (expand-file-name
552 (mm-encode-coding-string
553 (nnheader-replace-chars-in-string nameuid ?. ?/)
554 nnmail-pathname-coding-system)
555 dir))))
556 (if old-uidvalidity
557 (if (not (equal old-uidvalidity new-uidvalidity))
558 ;; uidvalidity clash
559 (progn
560 (gnus-group-set-parameter gnusgroup 'uidvalidity new-uidvalidity)
561 (gnus-group-remove-parameter gnusgroup 'imap-status)
562 (gnus-sethash (gnus-group-prefixed-name group server)
563 nil nnimap-mailbox-info)
564 (gnus-delete-file file))
565 t)
566 (gnus-group-add-parameter gnusgroup (cons 'uidvalidity new-uidvalidity))
567 (gnus-group-remove-parameter gnusgroup 'imap-status)
568 (gnus-sethash ; Maybe not necessary here.
569 (gnus-group-prefixed-name group server)
570 nil nnimap-mailbox-info)
571 t)))
572 75
573(defun nnimap-before-find-minmax-bugworkaround () 76(defvar nnimap-object nil)
574 "Function called before iterating through mailboxes with 77
575`nnimap-find-minmax-uid'." 78(defvar nnimap-mark-alist
576 (when nnimap-need-unselect-to-notice-new-mail 79 '((read "\\Seen")
577 ;; XXX this is for UoW imapd problem, it doesn't notice new mail in 80 (tick "\\Flagged")
578 ;; currently selected mailbox without a re-select/examine. 81 (reply "\\Answered")
579 (or (null (imap-current-mailbox nnimap-server-buffer)) 82 (expire "gnus-expire")
580 (imap-mailbox-unselect nnimap-server-buffer)))) 83 (dormant "gnus-dormant")
581 84 (score "gnus-score")
582(defun nnimap-find-minmax-uid (group &optional examine) 85 (save "gnus-save")
583 "Find lowest and highest active article number in GROUP. 86 (download "gnus-download")
584If EXAMINE is non-nil the group is selected read-only." 87 (forward "gnus-forward")))
585 (with-current-buffer nnimap-server-buffer 88
586 (let ((decoded-group (nnimap-decode-group-name group))) 89(defvar nnimap-split-methods nil)
587 (when (or (string= decoded-group (imap-current-mailbox)) 90
588 (imap-mailbox-select decoded-group examine)) 91(defun nnimap-buffer ()
589 (let (minuid maxuid) 92 (nnimap-find-process-buffer nntp-server-buffer))
590 (when (> (imap-mailbox-get 'exists) 0) 93
591 (imap-fetch "1:*" "UID" nil 'nouidfetch) 94(defun nnimap-retrieve-headers (articles &optional group server fetch-old)
592 (imap-message-map
593 (lambda (uid Uid)
594 (setq minuid (if minuid (min minuid uid) uid)
595 maxuid (if maxuid (max maxuid uid) uid)))
596 'UID))
597 (list (imap-mailbox-get 'exists) minuid maxuid))))))
598
599(defun nnimap-possibly-change-group (group &optional server)
600 "Make GROUP the current group, and SERVER the current server."
601 (when (nnimap-possibly-change-server server)
602 (let ((decoded-group (nnimap-decode-group-name group)))
603 (with-current-buffer nnimap-server-buffer
604 (if (or (null group) (imap-current-mailbox-p decoded-group))
605 imap-current-mailbox ; Note: utf-7 encoded.
606 (if (imap-mailbox-select decoded-group)
607 (if (or (nnimap-verify-uidvalidity
608 group (or server nnimap-current-server))
609 (zerop (imap-mailbox-get 'exists decoded-group))
610 t ;; for OGnus to see if ignoring uidvalidity
611 ;; changes has any bad effects.
612 (yes-or-no-p
613 (format
614 "nnimap: Group %s is not uidvalid. Continue? "
615 decoded-group)))
616 imap-current-mailbox ; Note: utf-7 encoded.
617 (imap-mailbox-unselect)
618 (error "nnimap: Group %s is not uid-valid" decoded-group))
619 (nnheader-report 'nnimap (imap-error-text))))))))
620
621(defun nnimap-replace-whitespace (string)
622 "Return STRING with all whitespace replaced with space."
623 (when string
624 (while (string-match "[\r\n\t]+" string)
625 (setq string (replace-match " " t t string)))
626 string))
627
628;; Required backend functions
629
630(defun nnimap-retrieve-headers-progress ()
631 "Hook to insert NOV line for current article into `nntp-server-buffer'."
632 (and (numberp nnmail-large-newsgroup)
633 (zerop (% (incf nnimap-counter) nnimap-progress-how-often))
634 (> nnimap-length nnmail-large-newsgroup)
635 (nnheader-message 6 "nnimap: Retrieving headers... %c"
636 (nth (/ (% nnimap-counter
637 (* (length nnimap-progress-chars)
638 nnimap-progress-how-often))
639 nnimap-progress-how-often)
640 nnimap-progress-chars)))
641 (with-current-buffer nntp-server-buffer
642 (let (headers lines chars uid mbx)
643 (with-current-buffer nnimap-server-buffer
644 (setq uid imap-current-message
645 mbx (nnimap-encode-group-name (imap-current-mailbox))
646 headers (if (imap-capability 'IMAP4rev1)
647 ;; xxx don't just use car? alist doesn't contain
648 ;; anything else now, but it might...
649 (nth 2 (car (imap-message-get uid 'BODYDETAIL)))
650 (imap-message-get uid 'RFC822.HEADER))
651 lines (imap-body-lines (imap-message-body imap-current-message))
652 chars (imap-message-get imap-current-message 'RFC822.SIZE)))
653 (nnheader-insert-nov
654 ;; At this stage, we only have bytes, so let's use unibyte buffers
655 ;; to make it more clear.
656 (mm-with-unibyte-buffer
657 (buffer-disable-undo)
658 ;; headers can be nil if article is write-only
659 (when headers (insert headers))
660 (let ((head (nnheader-parse-naked-head uid)))
661 (mail-header-set-number head uid)
662 (mail-header-set-chars head chars)
663 (mail-header-set-lines head lines)
664 (mail-header-set-xref
665 head (format "%s %s:%d" (system-name) mbx uid))
666 head))))))
667
668(defun nnimap-retrieve-which-headers (articles fetch-old)
669 "Get a range of articles to fetch based on ARTICLES and FETCH-OLD."
670 (with-current-buffer nnimap-server-buffer
671 (if (numberp (car-safe articles))
672 (imap-search
673 (concat "UID "
674 (imap-range-to-message-set
675 (gnus-compress-sequence
676 (append (gnus-uncompress-sequence
677 (and fetch-old
678 (cons (if (numberp fetch-old)
679 (max 1 (- (car articles) fetch-old))
680 1)
681 (1- (car articles)))))
682 articles)))))
683 (mapcar (lambda (msgid)
684 (imap-search
685 (format "HEADER Message-Id \"%s\"" msgid)))
686 articles))))
687
688(defun nnimap-group-overview-filename (group server)
689 "Make file name for GROUP on SERVER."
690 (let* ((dir (file-name-as-directory (expand-file-name nnimap-directory)))
691 (uidvalidity (gnus-group-get-parameter
692 (nnimap-group-prefixed-name group server)
693 'uidvalidity))
694 (name (nnheader-translate-file-chars
695 (concat nnimap-nov-file-name
696 (if (equal server "")
697 "unnamed"
698 server) "." group nnimap-nov-file-name-suffix) t))
699 (nameuid (nnheader-translate-file-chars
700 (concat nnimap-nov-file-name
701 (if (equal server "")
702 "unnamed"
703 server) "." group "." uidvalidity
704 nnimap-nov-file-name-suffix) t))
705 (oldfile (if (or nnmail-use-long-file-names
706 (file-exists-p (expand-file-name name dir)))
707 (expand-file-name name dir)
708 (expand-file-name
709 (mm-encode-coding-string
710 (nnheader-replace-chars-in-string name ?. ?/)
711 nnmail-pathname-coding-system)
712 dir)))
713 (newfile (if (or nnmail-use-long-file-names
714 (file-exists-p (expand-file-name nameuid dir)))
715 (expand-file-name nameuid dir)
716 (expand-file-name
717 (mm-encode-coding-string
718 (nnheader-replace-chars-in-string nameuid ?. ?/)
719 nnmail-pathname-coding-system)
720 dir))))
721 (when (and (file-exists-p oldfile) (not (file-exists-p newfile)))
722 (message "nnimap: Upgrading novcache filename...")
723 (sit-for 1)
724 (gnus-make-directory (file-name-directory newfile))
725 (unless (ignore-errors (rename-file oldfile newfile) t)
726 (if (ignore-errors (copy-file oldfile newfile) t)
727 (delete-file oldfile)
728 (error "Can't rename `%s' to `%s'" oldfile newfile))))
729 newfile))
730
731(defun nnimap-retrieve-headers-from-file (group server)
732 (with-current-buffer nntp-server-buffer 95 (with-current-buffer nntp-server-buffer
733 (let ((nov (nnimap-group-overview-filename group server))) 96 (erase-buffer)
734 (when (file-exists-p nov) 97 (when (nnimap-possibly-change-group group server)
735 (mm-insert-file-contents nov) 98 (with-current-buffer (nnimap-buffer)
736 (set-buffer-modified-p nil) 99 (nnimap-send-command "SELECT %S" (utf7-encode group t))
737 (let ((min (ignore-errors (goto-char (point-min)) 100 (erase-buffer)
738 (read (current-buffer)))) 101 (nnimap-wait-for-response
739 (max (ignore-errors (goto-char (point-max)) 102 (nnimap-send-command
740 (forward-line -1) 103 "UID FETCH %s %s"
741 (read (current-buffer))))) 104 (nnimap-article-ranges (gnus-compress-sequence articles))
742 (if (and (numberp min) (numberp max)) 105 (format "(UID RFC822.SIZE BODYSTRUCTURE %s)"
743 (cons min max) 106 (format
744 ;; junk, remove it, it's saved later 107 (if (member "IMAP4REV1"
745 (erase-buffer) 108 (nnimap-capabilities nnimap-object))
746 nil)))))) 109 "BODY.PEEK[HEADER.FIELDS %s]"
747 110 "RFC822.HEADER.LINES %s")
748(defun nnimap-retrieve-headers-from-server (articles group server) 111 (append '(Subject From Date Message-Id
749 (with-current-buffer nnimap-server-buffer 112 References In-Reply-To Xref)
750 (let ((imap-fetch-data-hook '(nnimap-retrieve-headers-progress)) 113 nnmail-extra-headers))))
751 (nnimap-length (gnus-range-length articles)) 114 t)
752 (nnimap-counter 0)) 115 (nnimap-transform-headers))
753 (imap-fetch (imap-range-to-message-set articles) 116 (insert-buffer-substring
754 (concat "(UID RFC822.SIZE BODY " 117 (nnimap-find-process-buffer (current-buffer))))
755 (let ((headers 118 t))
756 (append '(Subject From Date Message-Id 119
757 References In-Reply-To Xref) 120(defun nnimap-transform-headers ()
758 (copy-sequence 121 (goto-char (point-min))
759 nnmail-extra-headers)))) 122 (let (article bytes lines)
760 (if (imap-capability 'IMAP4rev1) 123 (block nil
761 (format "BODY.PEEK[HEADER.FIELDS %s])" headers) 124 (while (not (eobp))
762 (format "RFC822.HEADER.LINES %s)" headers))))) 125 (while (not (looking-at "^\\* [0-9]+ FETCH.*UID \\([0-9]+\\)"))
763 (with-current-buffer nntp-server-buffer 126 (delete-region (point) (progn (forward-line 1) (point)))
764 (sort-numeric-fields 1 (point-min) (point-max))) 127 (when (eobp)
765 (and (numberp nnmail-large-newsgroup) 128 (return)))
766 (> nnimap-length nnmail-large-newsgroup) 129 (setq article (match-string 1)
767 (nnheader-message 6 "nnimap: Retrieving headers...done"))))) 130 bytes (nnimap-get-length)
768 131 lines nil)
769(defun nnimap-dont-use-nov-p (group server) 132 (beginning-of-line)
770 (or gnus-nov-is-evil nnimap-nov-is-evil 133 (when (search-forward "BODYSTRUCTURE" (line-end-position) t)
771 (unless (and (gnus-make-directory 134 (let ((structure (ignore-errors (read (current-buffer)))))
772 (file-name-directory 135 (while (and (consp structure)
773 (nnimap-group-overview-filename group server))) 136 (not (stringp (car structure))))
774 (file-writable-p 137 (setq structure (car structure)))
775 (nnimap-group-overview-filename group server))) 138 (setq lines (nth 7 structure))))
776 (message "nnimap: Nov cache not writable, %s" 139 (delete-region (line-beginning-position) (line-end-position))
777 (nnimap-group-overview-filename group server))))) 140 (insert (format "211 %s Article retrieved." article))
778 141 (forward-line 1)
779(deffoo nnimap-retrieve-headers (articles &optional group server fetch-old) 142 (insert (format "Bytes: %d\n" bytes))
780 (when (nnimap-possibly-change-group group server) 143 (when lines
781 (with-current-buffer nntp-server-buffer 144 (insert (format "Lines: %s\n" lines)))
782 (erase-buffer) 145 (re-search-forward "^\r$")
783 (if (nnimap-dont-use-nov-p group server) 146 (delete-region (line-beginning-position) (line-end-position))
784 (nnimap-retrieve-headers-from-server 147 (insert ".")
785 (gnus-compress-sequence articles) group server) 148 (forward-line 1)))))
786 (let (uids cached low high) 149
787 (when (setq uids (nnimap-retrieve-which-headers articles fetch-old) 150(defun nnimap-get-length ()
788 low (car uids) 151 (and (re-search-forward "{\\([0-9]+\\)}" (line-end-position) t)
789 high (car (last uids))) 152 (string-to-number (match-string 1))))
790 (if (setq cached (nnimap-retrieve-headers-from-file group server)) 153
791 (progn 154(defun nnimap-article-ranges (ranges)
792 ;; fetch articles with uids before cache block 155 (let (result)
793 (when (< low (car cached)) 156 (cond
794 (goto-char (point-min)) 157 ((numberp ranges)
795 (nnimap-retrieve-headers-from-server 158 (number-to-string ranges))
796 (cons low (1- (car cached))) group server)) 159 ((numberp (cdr ranges))
797 ;; fetch articles with uids after cache block 160 (format "%d:%d" (car ranges) (cdr ranges)))
798 (when (> high (cdr cached)) 161 (t
799 (goto-char (point-max)) 162 (dolist (elem ranges)
800 (nnimap-retrieve-headers-from-server 163 (push
801 (cons (1+ (cdr cached)) high) group server)) 164 (if (consp elem)
802 (when nnimap-prune-cache 165 (format "%d:%d" (car elem) (cdr elem))
803 ;; remove nov's for articles which has expired on server 166 (number-to-string elem))
804 (goto-char (point-min)) 167 result))
805 (dolist (uid (gnus-set-difference articles uids)) 168 (mapconcat #'identity (nreverse result) ",")))))
806 (when (re-search-forward (format "^%d\t" uid) nil t) 169
807 (gnus-delete-line))))) 170(defun nnimap-open-server (server &optional defs)
808 ;; nothing cached, fetch whole range from server
809 (nnimap-retrieve-headers-from-server
810 (cons low high) group server))
811 (when (buffer-modified-p)
812 (nnmail-write-region
813 (point-min) (point-max)
814 (nnimap-group-overview-filename group server) nil 'nomesg))
815 (nnheader-nov-delete-outside-range low high))))
816 'nov)))
817
818(declare-function netrc-parse "netrc" (file))
819(declare-function netrc-machine-user-or-password "netrc"
820 (mode authinfo-file-or-list machines ports defaults))
821
822(defun nnimap-open-connection (server)
823 ;; Note: `nnimap-open-server' that calls this function binds
824 ;; `imap-logout-timeout' to `nnimap-logout-timeout'.
825 (if (not (imap-open nnimap-address nnimap-server-port nnimap-stream
826 nnimap-authenticator nnimap-server-buffer))
827 (nnheader-report 'nnimap "Can't open connection to server %s" server)
828 (require 'netrc)
829 (unless (or (imap-capability 'IMAP4 nnimap-server-buffer)
830 (imap-capability 'IMAP4rev1 nnimap-server-buffer))
831 (imap-close nnimap-server-buffer)
832 (nnheader-report 'nnimap "Server %s is not IMAP4 compliant" server))
833 (let* ((list (progn (gnus-message 7 "Parsing authinfo file `%s'."
834 nnimap-authinfo-file)
835 (netrc-parse nnimap-authinfo-file)))
836 (port (if nnimap-server-port
837 (int-to-string nnimap-server-port)
838 "imap"))
839 (auth-info
840 (auth-source-user-or-password '("login" "password") server port))
841 (auth-user (nth 0 auth-info))
842 (auth-passwd (nth 1 auth-info))
843 (user (or
844 auth-user ; this is preferred to netrc-*
845 (netrc-machine-user-or-password
846 "login"
847 list
848 (list server
849 (or nnimap-server-address
850 nnimap-address))
851 (list port)
852 (list "imap" "imaps" "143" "993"))))
853 (passwd (or
854 auth-passwd ; this is preferred to netrc-*
855 (netrc-machine-user-or-password
856 "password"
857 list
858 (list server
859 (or nnimap-server-address
860 nnimap-address))
861 (list port)
862 (list "imap" "imaps" "143" "993")))))
863 (if (imap-authenticate user passwd nnimap-server-buffer)
864 (prog2
865 (setq nnimap-server-buffer-alist
866 (nnimap-remove-server-from-buffer-alist
867 server
868 nnimap-server-buffer-alist))
869 (push (list server nnimap-server-buffer)
870 nnimap-server-buffer-alist)
871 (imap-id nnimap-id nnimap-server-buffer)
872 (nnimap-possibly-change-server server))
873 (imap-close nnimap-server-buffer)
874 (kill-buffer nnimap-server-buffer)
875 (nnheader-report 'nnimap "Could not authenticate to %s" server)))))
876
877(deffoo nnimap-open-server (server &optional defs)
878 (nnheader-init-server-buffer)
879 (if (nnimap-server-opened server) 171 (if (nnimap-server-opened server)
880 t 172 t
881 (unless (assq 'nnimap-server-buffer defs)
882 (push (list 'nnimap-server-buffer (concat " *nnimap* " server)) defs))
883 ;; translate `nnimap-server-address' to `nnimap-address' in defs
884 ;; for people that configured nnimap with a very old version
885 (unless (assq 'nnimap-address defs) 173 (unless (assq 'nnimap-address defs)
886 (if (assq 'nnimap-server-address defs) 174 (setq defs (append defs (list (list 'nnimap-address server)))))
887 (push (list 'nnimap-address
888 (cadr (assq 'nnimap-server-address defs))) defs)
889 (push (list 'nnimap-address server) defs)))
890 (nnoo-change-server 'nnimap server defs) 175 (nnoo-change-server 'nnimap server defs)
891 (or nnimap-server-buffer 176 (or (nnimap-find-connection nntp-server-buffer)
892 (setq nnimap-server-buffer (cadr (assq 'nnimap-server-buffer defs)))) 177 (nnimap-open-connection nntp-server-buffer))))
893 (with-current-buffer (get-buffer-create nnimap-server-buffer) 178
894 (nnoo-change-server 'nnimap server defs)) 179(defun nnimap-make-process-buffer (buffer)
895 (let ((imap-logout-timeout nnimap-logout-timeout)) 180 (with-current-buffer
896 (or (and nnimap-server-buffer 181 (generate-new-buffer (format "*nnimap %s %s %s*"
897 (imap-opened nnimap-server-buffer) 182 nnimap-address nnimap-server-port
898 (if (with-current-buffer nnimap-server-buffer 183 (gnus-buffer-exists-p buffer)))
899 (memq imap-state '(auth selected examine))) 184 (mm-disable-multibyte)
900 t 185 (buffer-disable-undo)
901 (imap-close nnimap-server-buffer) 186 (gnus-add-buffer)
902 (nnimap-open-connection server))) 187 (set (make-local-variable 'after-change-functions) nil)
903 (nnimap-open-connection server))))) 188 (set (make-local-variable 'nnimap-object) (make-nnimap))
904 189 (push (list buffer (current-buffer)) nnimap-connection-alist)
905(deffoo nnimap-server-opened (&optional server) 190 (current-buffer)))
906 "Whether SERVER is opened. 191
907If SERVER is the current virtual server, and the connection to the 192(defun nnimap-open-shell-stream (name buffer host port)
908physical server is alive, this function return a non-nil value. If 193 (let ((process (start-process name buffer shell-file-name
909SERVER is nil, it is treated as the current server." 194 shell-command-switch
910 ;; clean up autologouts?? 195 (format-spec
911 (and (or server nnimap-current-server) 196 nnimap-shell-program
912 (nnoo-server-opened 'nnimap (or server nnimap-current-server)) 197 (format-spec-make
913 (imap-opened (nnimap-get-server-buffer server)))) 198 ?s host
914 199 ?p port)))))
915(deffoo nnimap-close-server (&optional server) 200 process))
916 "Close connection to server and free all resources connected to it. 201
917Return nil if the server couldn't be closed for some reason." 202(defun nnimap-open-connection (buffer)
918 (let ((server (or server nnimap-current-server)) 203 (with-current-buffer (nnimap-make-process-buffer buffer)
919 (imap-logout-timeout nnimap-logout-timeout)) 204 (let* ((coding-system-for-read 'binary)
920 (when (or (nnimap-server-opened server) 205 (coding-system-for-write 'binary)
921 (imap-opened (nnimap-get-server-buffer server))) 206 (credentials
922 (imap-close (nnimap-get-server-buffer server)) 207 (cond
923 (kill-buffer (nnimap-get-server-buffer server)) 208 ((eq nnimap-stream 'network)
924 (setq nnimap-server-buffer nil 209 (open-network-stream "*nnimap*" (current-buffer) nnimap-address
925 nnimap-current-server nil 210 (or nnimap-server-port
926 nnimap-server-buffer-alist 211 (if (netrc-find-service-number "imap")
927 (nnimap-remove-server-from-buffer-alist 212 "imap"
928 server 213 "143")))
929 nnimap-server-buffer-alist))) 214 (auth-source-user-or-password
930 (nnoo-close-server 'nnimap server))) 215 '("login" "password") nnimap-address "imap" nil t))
931 216 ((eq nnimap-stream 'stream)
932(deffoo nnimap-request-close () 217 (nnimap-open-shell-stream
933 "Close connection to all servers and free all resources that the backend have reserved. 218 "*nnimap*" (current-buffer) nnimap-address
934All buffers that have been created by that 219 (or nnimap-server-port "imap"))
935backend should be killed. (Not the nntp-server-buffer, though.) This 220 (auth-source-user-or-password
936function is generally only called when Gnus is shutting down." 221 '("login" "password") nnimap-address "imap" nil t))
937 (mapc (lambda (server) (nnimap-close-server (car server))) 222 ((eq nnimap-stream 'ssl)
938 nnimap-server-buffer-alist) 223 (open-tls-stream "*nnimap*" (current-buffer) nnimap-address
939 (setq nnimap-server-buffer-alist nil)) 224 (or nnimap-server-port
940 225 (if (netrc-find-service-number "imaps")
941(deffoo nnimap-status-message (&optional server) 226 "imaps"
942 "This function returns the last error message from server." 227 "993")))
943 (when (nnimap-possibly-change-server server) 228 (or
944 (nnoo-status-message 'nnimap server))) 229 (auth-source-user-or-password
945 230 '("login" "password") nnimap-address "imap")
946;; We used to use a string-as-multibyte here, but it is really incorrect. 231 (auth-source-user-or-password
947;; This function is used when we're about to insert a unibyte string 232 '("login" "password") nnimap-address "imaps" nil t))))))
948;; into a potentially multibyte buffer. The string is either an article 233 (setf (nnimap-process nnimap-object)
949;; header or body (or both?), undecoded. When Emacs is asked to convert 234 (get-buffer-process (current-buffer)))
950;; a unibyte string to multibyte, it may either use the equivalent of 235 (unless credentials
951;; nothing (e.g. non-Mule XEmacs), string-make-unibyte (i.e. decode using 236 (delete-process (nnimap-process nnimap-object)))
952;; locale), string-as-multibyte (decode using emacs-internal coding system) 237 (when (and (nnimap-process nnimap-object)
953;; or string-to-multibyte (keep the data undecoded as a sequence of bytes). 238 (memq (process-status (nnimap-process nnimap-object))
954;; Only the last one preserves the data such that we can reliably later on 239 '(open run)))
955;; decode the text using the mime info. 240 (gnus-set-process-query-on-exit-flag (nnimap-process nnimap-object) nil)
956(defalias 'nnimap-demule 'mm-string-to-multibyte) 241 (let ((result (nnimap-command "LOGIN %S %S"
957 242 (car credentials) (cadr credentials))))
958(defun nnimap-make-callback (article gnus-callback buffer) 243 (if (not (car result))
959 "Return a callback function." 244 (progn
960 `(lambda () 245 (delete-process (nnimap-process nnimap-object))
961 (nnimap-callback ,article ,gnus-callback ,buffer))) 246 nil)
962 247 (setf (nnimap-capabilities nnimap-object)
963(defun nnimap-callback (article gnus-callback buffer) 248 (mapcar
964 (when (eq article (imap-current-message)) 249 #'upcase
965 (remove-hook 'imap-fetch-data-hook 250 (or (nnimap-find-parameter "CAPABILITY" (cdr result))
966 (nnimap-make-callback article gnus-callback buffer)) 251 (nnimap-find-parameter
967 (with-current-buffer buffer 252 "CAPABILITY" (cdr (nnimap-command "CAPABILITY"))))))
968 (insert 253 (when (member "QRESYNC" (nnimap-capabilities nnimap-object))
969 (with-current-buffer nnimap-server-buffer 254 (nnimap-command "ENABLE QRESYNC"))
970 (nnimap-demule 255 t))))))
971 (if (imap-capability 'IMAP4rev1) 256
972 ;; xxx don't just use car? alist doesn't contain 257(defun nnimap-find-parameter (parameter elems)
973 ;; anything else now, but it might... 258 (let (result)
974 (nth 2 (car (imap-message-get article 'BODYDETAIL))) 259 (dolist (elem elems)
975 (imap-message-get article 'RFC822))))) 260 (cond
976 (nnheader-ms-strip-cr) 261 ((equal (car elem) parameter)
977 (funcall gnus-callback t)))) 262 (setq result (cdr elem)))
978 263 ((and (equal (car elem) "OK")
979(defun nnimap-request-article-part (article part prop &optional 264 (consp (cadr elem))
980 group server to-buffer detail) 265 (equal (caadr elem) parameter))
981 (when (nnimap-possibly-change-group group server) 266 (setq result (cdr (cadr elem))))))
982 (let ((article (if (stringp article) 267 result))
983 (car-safe (imap-search 268
984 (format "HEADER Message-Id \"%s\"" article) 269(defun nnimap-close-server (&optional server)
985 nnimap-server-buffer))
986 article)))
987 (when article
988 (gnus-message 10 "nnimap: Fetching (part of) article %d from %s..."
989 article (or (nnimap-decode-group-name group)
990 (imap-current-mailbox)
991 (nnimap-decode-group-name
992 gnus-newsgroup-name)))
993 (if (not nnheader-callback-function)
994 (with-current-buffer (or to-buffer nntp-server-buffer)
995 (erase-buffer)
996 (let ((data (imap-fetch article part prop nil
997 nnimap-server-buffer)))
998 ;; data can be nil if article is write-only
999 (when data
1000 (insert (nnimap-demule (if detail
1001 (nth 2 (car data))
1002 data)))))
1003 (nnheader-ms-strip-cr)
1004 (gnus-message
1005 10 "nnimap: Fetching (part of) article %d from %s...done"
1006 article (or (nnimap-decode-group-name group)
1007 (imap-current-mailbox)
1008 (nnimap-decode-group-name gnus-newsgroup-name)))
1009 (if (bobp)
1010 (nnheader-report 'nnimap "No such article %d in %s: %s"
1011 article (or (nnimap-decode-group-name group)
1012 (imap-current-mailbox)
1013 (nnimap-decode-group-name
1014 gnus-newsgroup-name))
1015 (imap-error-text nnimap-server-buffer))
1016 (cons group article)))
1017 (add-hook 'imap-fetch-data-hook
1018 (nnimap-make-callback article
1019 nnheader-callback-function
1020 nntp-server-buffer))
1021 (imap-fetch-asynch article part nil nnimap-server-buffer)
1022 (cons group article))))))
1023
1024(deffoo nnimap-asynchronous-p ()
1025 t) 270 t)
1026 271
1027(deffoo nnimap-request-article (article &optional group server to-buffer) 272(defun nnimap-request-close ()
1028 (if (imap-capability 'IMAP4rev1 nnimap-server-buffer) 273 t)
1029 (nnimap-request-article-part
1030 article "BODY.PEEK[]" 'BODYDETAIL group server to-buffer 'detail)
1031 (nnimap-request-article-part
1032 article "RFC822.PEEK" 'RFC822 group server to-buffer)))
1033
1034(deffoo nnimap-request-head (article &optional group server to-buffer)
1035 (if (imap-capability 'IMAP4rev1 nnimap-server-buffer)
1036 (nnimap-request-article-part
1037 article "BODY.PEEK[HEADER]" 'BODYDETAIL group server to-buffer 'detail)
1038 (nnimap-request-article-part
1039 article "RFC822.HEADER" 'RFC822.HEADER group server to-buffer)))
1040
1041(deffoo nnimap-request-body (article &optional group server to-buffer)
1042 (if (imap-capability 'IMAP4rev1 nnimap-server-buffer)
1043 (nnimap-request-article-part
1044 article "BODY.PEEK[TEXT]" 'BODYDETAIL group server to-buffer 'detail)
1045 (nnimap-request-article-part
1046 article "RFC822.TEXT.PEEK" 'RFC822.TEXT group server to-buffer)))
1047
1048(deffoo nnimap-request-group (group &optional server fast)
1049 (nnimap-request-update-info-internal
1050 group
1051 (gnus-get-info (nnimap-group-prefixed-name group server))
1052 server)
1053 (when (nnimap-possibly-change-group group server)
1054 (nnimap-before-find-minmax-bugworkaround)
1055 (let (info)
1056 (cond (fast group)
1057 ((null (setq info (nnimap-find-minmax-uid group t)))
1058 (nnheader-report 'nnimap "Could not get active info for %s"
1059 group))
1060 (t
1061 (nnheader-insert "211 %d %d %d %s\n" (or (nth 0 info) 0)
1062 (max 1 (or (nth 1 info) 1))
1063 (or (nth 2 info) 0) group)
1064 (nnheader-report 'nnimap "Group %s selected" group)
1065 t)))))
1066
1067(defun nnimap-update-unseen (group &optional server)
1068 "Update the unseen count in `nnimap-mailbox-info'."
1069 (gnus-sethash
1070 (gnus-group-prefixed-name group server)
1071 (let ((old (gnus-gethash-safe (gnus-group-prefixed-name group server)
1072 nnimap-mailbox-info)))
1073 (list (nth 0 old) (nth 1 old)
1074 (imap-mailbox-status (nnimap-decode-group-name group)
1075 'unseen nnimap-server-buffer)))
1076 nnimap-mailbox-info))
1077 274
1078(defun nnimap-close-group (group &optional server) 275(defun nnimap-server-opened (&optional server)
1079 (with-current-buffer nnimap-server-buffer 276 (and (nnoo-current-server-p 'nnimap server)
1080 (when (and (imap-opened) 277 nntp-server-buffer
1081 (nnimap-possibly-change-group group server)) 278 (gnus-buffer-live-p nntp-server-buffer)
1082 (nnimap-update-unseen group server) 279 (nnimap-find-connection nntp-server-buffer)))
1083 (case nnimap-expunge-on-close
1084 (always (progn
1085 (imap-mailbox-expunge nnimap-close-asynchronous)
1086 (unless nnimap-dont-close
1087 (imap-mailbox-close nnimap-close-asynchronous))))
1088 (ask (if (and (imap-search "DELETED")
1089 (gnus-y-or-n-p (format "Expunge articles in group `%s'? "
1090 (imap-current-mailbox))))
1091 (progn
1092 (imap-mailbox-expunge nnimap-close-asynchronous)
1093 (unless nnimap-dont-close
1094 (imap-mailbox-close nnimap-close-asynchronous)))
1095 (imap-mailbox-unselect)))
1096 (t (imap-mailbox-unselect)))
1097 (not imap-current-mailbox))))
1098
1099(defun nnimap-pattern-to-list-arguments (pattern)
1100 (mapcar (lambda (p)
1101 (cons (car-safe p) (or (cdr-safe p) p)))
1102 (if (and (listp pattern)
1103 (listp (cdr pattern)))
1104 pattern
1105 (list pattern))))
1106
1107(deffoo nnimap-request-list (&optional server)
1108 (when (nnimap-possibly-change-server server)
1109 (with-current-buffer nntp-server-buffer
1110 (erase-buffer))
1111 (gnus-message 5 "nnimap: Generating active list%s..."
1112 (if (> (length server) 0) (concat " for " server) ""))
1113 (nnimap-before-find-minmax-bugworkaround)
1114 (with-current-buffer nnimap-server-buffer
1115 (dolist (pattern (nnimap-pattern-to-list-arguments nnimap-list-pattern))
1116 (dolist (mbx (funcall nnimap-request-list-method
1117 (cdr pattern) (car pattern)))
1118 (unless (member "\\noselect"
1119 (mapcar #'downcase
1120 (imap-mailbox-get 'list-flags mbx)))
1121 (let* ((encoded-mbx (nnimap-encode-group-name mbx))
1122 (info (nnimap-find-minmax-uid encoded-mbx 'examine)))
1123 (when info
1124 (with-current-buffer nntp-server-buffer
1125 (insert (format "\"%s\" %d %d y\n"
1126 encoded-mbx (or (nth 2 info) 0)
1127 (max 1 (or (nth 1 info) 1)))))))))))
1128 (gnus-message 5 "nnimap: Generating active list%s...done"
1129 (if (> (length server) 0) (concat " for " server) ""))
1130 t))
1131 280
1132(deffoo nnimap-request-post (&optional server) 281(defun nnimap-status-message (&optional server)
1133 (let ((success t)) 282 nnimap-status-string)
1134 (dolist (mbx (message-unquote-tokens
1135 (message-tokenize-header
1136 (message-fetch-field "Newsgroups") ", ")) success)
1137 (let ((to-newsgroup (gnus-group-prefixed-name mbx gnus-command-method)))
1138 (or (gnus-active to-newsgroup)
1139 (gnus-activate-group to-newsgroup)
1140 (if (gnus-y-or-n-p (format "No such group: %s. Create it? "
1141 to-newsgroup))
1142 (or (and (gnus-request-create-group
1143 to-newsgroup gnus-command-method)
1144 (gnus-activate-group to-newsgroup nil nil
1145 gnus-command-method))
1146 (error "Couldn't create group %s" to-newsgroup)))
1147 (error "No such group: %s" to-newsgroup))
1148 (unless (nnimap-request-accept-article mbx (nth 1 gnus-command-method))
1149 (setq success nil))))))
1150
1151;; Optional backend functions
1152
1153(defun nnimap-string-lessp-numerical (s1 s2)
1154 "Return t if first arg string is less than second in numerical order."
1155 (cond ((string= s1 s2)
1156 nil)
1157 ((> (length s1) (length s2))
1158 nil)
1159 ((< (length s1) (length s2))
1160 t)
1161 ((< (string-to-number (substring s1 0 1))
1162 (string-to-number (substring s2 0 1)))
1163 t)
1164 ((> (string-to-number (substring s1 0 1))
1165 (string-to-number (substring s2 0 1)))
1166 nil)
1167 (t
1168 (nnimap-string-lessp-numerical (substring s1 1) (substring s2 1)))))
1169
1170(deffoo nnimap-retrieve-groups (groups &optional server)
1171 (when (nnimap-possibly-change-server server)
1172 (gnus-message 5 "nnimap: Checking mailboxes...")
1173 (with-current-buffer nntp-server-buffer
1174 (erase-buffer)
1175 (nnimap-before-find-minmax-bugworkaround)
1176 (let (asyncgroups slowgroups decoded-group)
1177 (if (null nnimap-retrieve-groups-asynchronous)
1178 (setq slowgroups groups)
1179 (dolist (group groups)
1180 (setq decoded-group (nnimap-decode-group-name group))
1181 (gnus-message 9 "nnimap: Quickly checking mailbox %s"
1182 decoded-group)
1183 (add-to-list (if (gnus-group-get-parameter
1184 (nnimap-group-prefixed-name group)
1185 'imap-status)
1186 'asyncgroups
1187 'slowgroups)
1188 (list group (imap-mailbox-status-asynch
1189 decoded-group
1190 '(uidvalidity uidnext unseen)
1191 nnimap-server-buffer))))
1192 (dolist (asyncgroup asyncgroups)
1193 (let* ((group (nth 0 asyncgroup))
1194 (tag (nth 1 asyncgroup))
1195 (gnusgroup (nnimap-group-prefixed-name group))
1196 (saved-uidvalidity (gnus-group-get-parameter gnusgroup
1197 'uidvalidity))
1198 (saved-imap-status (gnus-group-get-parameter gnusgroup
1199 'imap-status))
1200 (saved-info (and saved-imap-status
1201 (split-string saved-imap-status " "))))
1202 (setq decoded-group (nnimap-decode-group-name group))
1203 (when (imap-ok-p (imap-wait-for-tag tag nnimap-server-buffer))
1204 (if (or (not (equal
1205 saved-uidvalidity
1206 (imap-mailbox-get 'uidvalidity decoded-group
1207 nnimap-server-buffer)))
1208 (not (equal
1209 (nth 0 saved-info)
1210 (imap-mailbox-get 'uidnext decoded-group
1211 nnimap-server-buffer))))
1212 (push (list group) slowgroups)
1213 (gnus-sethash
1214 (gnus-group-prefixed-name group server)
1215 (list (imap-mailbox-get 'uidvalidity
1216 decoded-group nnimap-server-buffer)
1217 (imap-mailbox-get 'uidnext
1218 decoded-group nnimap-server-buffer)
1219 (imap-mailbox-get 'unseen
1220 decoded-group nnimap-server-buffer))
1221 nnimap-mailbox-info)
1222 (insert (format "\"%s\" %s %s y\n" group
1223 (nth 2 saved-info)
1224 (nth 1 saved-info))))))))
1225 (dolist (group slowgroups)
1226 (if nnimap-retrieve-groups-asynchronous
1227 (setq group (car group)))
1228 (setq decoded-group (nnimap-decode-group-name group))
1229 (gnus-message 7 "nnimap: Mailbox %s modified" decoded-group)
1230 (or (member "\\NoSelect" (imap-mailbox-get 'list-flags decoded-group
1231 nnimap-server-buffer))
1232 (let* ((gnusgroup (nnimap-group-prefixed-name group))
1233 (status (imap-mailbox-status
1234 decoded-group '(uidvalidity uidnext unseen)
1235 nnimap-server-buffer))
1236 (info (nnimap-find-minmax-uid group 'examine))
1237 (min-uid (max 1 (or (nth 1 info) 1)))
1238 (max-uid (or (nth 2 info) 0)))
1239 (when (> (or (imap-mailbox-get 'recent decoded-group
1240 nnimap-server-buffer) 0)
1241 0)
1242 (push (list (cons decoded-group 0)) nnmail-split-history))
1243 (insert (format "\"%s\" %d %d y\n" group max-uid min-uid))
1244 (gnus-sethash
1245 (gnus-group-prefixed-name group server)
1246 status
1247 nnimap-mailbox-info)
1248 (if (not (equal (nth 0 status)
1249 (gnus-group-get-parameter gnusgroup
1250 'uidvalidity)))
1251 (nnimap-verify-uidvalidity group nnimap-current-server))
1252 ;; The imap-status parameter is a string on the form
1253 ;; "<uidnext> <min-uid> <max-uid>".
1254 (gnus-group-add-parameter
1255 gnusgroup
1256 (cons 'imap-status
1257 (format "%s %s %s" (nth 1 status) min-uid max-uid))))))))
1258 (gnus-message 5 "nnimap: Checking mailboxes...done")
1259 'active))
1260
1261(deffoo nnimap-request-update-info-internal (group info &optional server)
1262 (when (nnimap-possibly-change-group group server)
1263 (when info ;; xxx what does this mean? should we create a info?
1264 (with-current-buffer nnimap-server-buffer
1265 (gnus-message 5 "nnimap: Updating info for %s..."
1266 (nnimap-decode-group-name (gnus-info-group info)))
1267
1268 (when (nnimap-mark-permanent-p 'read)
1269 (let (seen unseen)
1270 ;; read info could contain articles marked unread by other
1271 ;; imap clients! we correct this
1272 (setq unseen (gnus-compress-sequence
1273 (imap-search "UNSEEN UNDELETED"))
1274 seen (gnus-range-difference (gnus-info-read info) unseen)
1275 seen (gnus-range-add seen
1276 (gnus-compress-sequence
1277 (imap-search "SEEN")))
1278 seen (if (and (integerp (car seen))
1279 (null (cdr seen)))
1280 (list (cons (car seen) (car seen)))
1281 seen))
1282 (gnus-info-set-read info seen)))
1283
1284 (dolist (pred gnus-article-mark-lists)
1285 (when (or (eq (cdr pred) 'recent)
1286 (and (nnimap-mark-permanent-p (cdr pred))
1287 (member (nnimap-mark-to-flag (cdr pred))
1288 (imap-mailbox-get 'flags))))
1289 (gnus-info-set-marks
1290 info
1291 (gnus-update-alist-soft
1292 (cdr pred)
1293 (gnus-compress-sequence
1294 (imap-search (nnimap-mark-to-predicate (cdr pred))))
1295 (gnus-info-marks info))
1296 t)))
1297
1298 (when nnimap-importantize-dormant
1299 ;; nnimap mark dormant article as ticked too (for other clients)
1300 ;; so we remove that mark for gnus since we support dormant
1301 (gnus-info-set-marks
1302 info
1303 (gnus-update-alist-soft
1304 'tick
1305 (gnus-remove-from-range
1306 (cdr-safe (assoc 'tick (gnus-info-marks info)))
1307 (cdr-safe (assoc 'dormant (gnus-info-marks info))))
1308 (gnus-info-marks info))
1309 t))
1310
1311 (gnus-message 5 "nnimap: Updating info for %s...done"
1312 (nnimap-decode-group-name (gnus-info-group info)))
1313
1314 info))))
1315
1316(deffoo nnimap-request-type (group &optional article)
1317 (if (and nnimap-news-groups (string-match nnimap-news-groups group))
1318 'news
1319 'mail))
1320
1321(deffoo nnimap-request-set-mark (group actions &optional server)
1322 (when (nnimap-possibly-change-group group server)
1323 (with-current-buffer nnimap-server-buffer
1324 (let (action)
1325 (gnus-message 7 "nnimap: Setting marks in %s..."
1326 (nnimap-decode-group-name group))
1327 (while (setq action (pop actions))
1328 (let ((range (nth 0 action))
1329 (what (nth 1 action))
1330 (cmdmarks (nth 2 action))
1331 marks)
1332 ;; bookmark can't be stored (not list/range
1333 (setq cmdmarks (delq 'bookmark cmdmarks))
1334 ;; killed can't be stored (not list/range
1335 (setq cmdmarks (delq 'killed cmdmarks))
1336 ;; unsent are for nndraft groups only
1337 (setq cmdmarks (delq 'unsent cmdmarks))
1338 ;; cache flags are pointless on the server
1339 (setq cmdmarks (delq 'cache cmdmarks))
1340 ;; seen flags are local to each gnus
1341 (setq cmdmarks (delq 'seen cmdmarks))
1342 ;; recent marks can't be set
1343 (setq cmdmarks (delq 'recent cmdmarks))
1344 (when nnimap-importantize-dormant
1345 ;; flag dormant articles as ticked
1346 (if (memq 'dormant cmdmarks)
1347 (setq cmdmarks (cons 'tick cmdmarks))))
1348 ;; remove stuff we are forbidden to store
1349 (mapc (lambda (mark)
1350 (if (imap-message-flag-permanent-p
1351 (nnimap-mark-to-flag mark))
1352 (setq marks (cons mark marks))))
1353 cmdmarks)
1354 (when (and range marks)
1355 (cond ((eq what 'del)
1356 (imap-message-flags-del
1357 (imap-range-to-message-set range)
1358 (nnimap-mark-to-flag marks nil t)))
1359 ((eq what 'add)
1360 (imap-message-flags-add
1361 (imap-range-to-message-set range)
1362 (nnimap-mark-to-flag marks nil t)))
1363 ((eq what 'set)
1364 (imap-message-flags-set
1365 (imap-range-to-message-set range)
1366 (nnimap-mark-to-flag marks nil t)))))))
1367 (gnus-message 7 "nnimap: Setting marks in %s...done"
1368 (nnimap-decode-group-name group)))))
1369 nil)
1370 283
1371(defun nnimap-split-fancy () 284(defun nnimap-request-article (article &optional group server to-buffer)
1372 "Like the function `nnmail-split-fancy', but uses `nnimap-split-fancy'."
1373 (let ((nnmail-split-fancy nnimap-split-fancy))
1374 (nnmail-split-fancy)))
1375
1376(defun nnimap-split-to-groups (rules)
1377 ;; tries to match all rules in nnimap-split-rule against content of
1378 ;; nntp-server-buffer, returns a list of groups that matched.
1379 ;; Note: This function takes and returns decoded group names.
1380 (with-current-buffer nntp-server-buffer 285 (with-current-buffer nntp-server-buffer
1381 ;; Fold continuation lines. 286 (let ((result (nnimap-possibly-change-group group server)))
1382 (goto-char (point-min)) 287 (when (stringp article)
1383 (while (re-search-forward "\\(\r?\n[ \t]+\\)+" nil t) 288 (setq article (nnimap-find-article-by-message-id group article)))
1384 (replace-match " " t t)) 289 (when (and result
1385 (if (functionp rules) 290 article)
1386 (funcall rules) 291 (erase-buffer)
1387 (let (to-groups regrepp) 292 (with-current-buffer (nnimap-buffer)
1388 (catch 'split-done 293 (erase-buffer)
1389 (dolist (rule rules to-groups) 294 (setq result
1390 (let ((group (car rule)) 295 (nnimap-command
1391 (regexp (cadr rule))) 296 (if (member "IMAP4REV1" (nnimap-capabilities nnimap-object))
297 "UID FETCH %d BODY.PEEK[]"
298 "UID FETCH %d RFC822.PEEK")
299 article)))
300 (let ((buffer (nnimap-find-process-buffer (current-buffer))))
301 (when (car result)
302 (with-current-buffer to-buffer
303 (insert-buffer-substring buffer)
1392 (goto-char (point-min)) 304 (goto-char (point-min))
1393 (when (and (if (stringp regexp) 305 (let ((bytes (nnimap-get-length)))
1394 (progn 306 (delete-region (line-beginning-position)
1395 (if (not (stringp group)) 307 (progn (forward-line 1) (point)))
1396 (setq group (eval group)) 308 (goto-char (+ (point) bytes))
1397 (setq regrepp 309 (delete-region (point) (point-max))
1398 (string-match "\\\\[0-9&]" group))) 310 (nnheader-ms-strip-cr))
1399 (re-search-forward regexp nil t)) 311 t)))))))
1400 (funcall regexp group)) 312
1401 ;; Don't enter the article into the same group twice. 313(defun nnimap-request-group (group &optional server dont-check)
1402 (not (assoc group to-groups))) 314 (with-current-buffer nntp-server-buffer
1403 (push (if regrepp 315 (let ((result (nnimap-possibly-change-group group server))
1404 (nnmail-expand-newtext group) 316 articles)
1405 group) 317 (when result
1406 to-groups) 318 (setq articles (nnimap-get-flags "1:*"))
1407 (or nnimap-split-crosspost 319 (erase-buffer)
1408 (throw 'split-done to-groups)))))))))) 320 (insert
1409 321 (format
1410(defun nnimap-assoc-match (key alist) 322 "211 %d %d %d %S\n"
1411 (let (element) 323 (length articles)
1412 (while (and alist (not element)) 324 (or (caar articles) 0)
1413 (if (string-match (car (car alist)) key) 325 (or (caar (last articles)) 0)
1414 (setq element (car alist))) 326 group))
1415 (setq alist (cdr alist)))
1416 element))
1417
1418(defun nnimap-split-find-rule (server inbox)
1419 (if (and (listp nnimap-split-rule) (listp (car nnimap-split-rule))
1420 (list (cdar nnimap-split-rule)) (listp (cadar nnimap-split-rule)))
1421 ;; extended format
1422 (cadr (nnimap-assoc-match inbox (cdr (nnimap-assoc-match
1423 server nnimap-split-rule))))
1424 nnimap-split-rule))
1425
1426(defun nnimap-split-find-inbox (server)
1427 (if (listp nnimap-split-inbox)
1428 nnimap-split-inbox
1429 (list nnimap-split-inbox)))
1430
1431(defun nnimap-split-articles (&optional group server)
1432 ;; Note: Assumes decoded group names in nnimap-split-inbox,
1433 ;; nnimap-split-rule, nnimap-split-fancy, and nnmail-split-history.
1434 (when (nnimap-possibly-change-server server)
1435 (with-current-buffer nnimap-server-buffer
1436 (let (rule inbox removeorig
1437 (inboxes (nnimap-split-find-inbox server)))
1438 ;; iterate over inboxes
1439 (while (and (setq inbox (pop inboxes))
1440 (nnimap-possibly-change-group
1441 (nnimap-encode-group-name inbox))) ;; SELECT
1442 ;; find split rule for this server / inbox
1443 (when (setq rule (nnimap-split-find-rule server inbox))
1444 ;; iterate over articles
1445 (dolist (article (imap-search nnimap-split-predicate))
1446 (when (if (if (eq nnimap-split-download-body 'default)
1447 nnimap-split-download-body-default
1448 nnimap-split-download-body)
1449 (and (nnimap-request-article article)
1450 (with-current-buffer nntp-server-buffer (mail-narrow-to-head)))
1451 (nnimap-request-head article))
1452 ;; copy article to right group(s)
1453 (setq removeorig nil)
1454 (dolist (to-group (nnimap-split-to-groups rule))
1455 (cond ((eq to-group 'junk)
1456 (message "IMAP split removed %s:%s:%d" server inbox
1457 article)
1458 (setq removeorig t))
1459 ((imap-message-copy (number-to-string article)
1460 to-group nil 'nocopyuid)
1461 (message "IMAP split moved %s:%s:%d to %s" server
1462 inbox article to-group)
1463 (setq removeorig t)
1464 (when nnmail-cache-accepted-message-ids
1465 (with-current-buffer nntp-server-buffer
1466 (let (msgid)
1467 (and (setq msgid
1468 (nnmail-fetch-field "message-id"))
1469 (nnmail-cache-insert msgid
1470 (nnimap-encode-group-name to-group)
1471 (nnmail-fetch-field "subject"))))))
1472 ;; Add the group-art list to the history list.
1473 (push (list (cons to-group 0)) nnmail-split-history))
1474 (t
1475 (message "IMAP split failed to move %s:%s:%d to %s"
1476 server inbox article to-group))))
1477 (if (if (eq nnimap-split-download-body 'default)
1478 nnimap-split-download-body-default
1479 nnimap-split-download-body)
1480 (widen))
1481 ;; remove article if it was successfully copied somewhere
1482 (and removeorig
1483 (imap-message-flags-add (format "%d" article)
1484 "\\Seen \\Deleted")))))
1485 (when (imap-mailbox-select inbox) ;; just in case
1486 ;; todo: UID EXPUNGE (if available) to remove splitted articles
1487 (imap-mailbox-expunge)
1488 (imap-mailbox-close)))
1489 (when nnmail-cache-accepted-message-ids
1490 (nnmail-cache-close))
1491 t)))) 327 t))))
1492 328
1493(deffoo nnimap-request-scan (&optional group server) 329(defun nnimap-get-flags (spec)
1494 (nnimap-split-articles group server)) 330 (let ((articles nil)
1495 331 elems)
1496(deffoo nnimap-request-newgroups (date &optional server) 332 (with-current-buffer (nnimap-buffer)
1497 (when (nnimap-possibly-change-server server)
1498 (with-current-buffer nntp-server-buffer
1499 (gnus-message 5 "nnimap: Listing subscribed mailboxes%s%s..."
1500 (if (> (length server) 0) " on " "") server)
1501 (erase-buffer) 333 (erase-buffer)
1502 (nnimap-before-find-minmax-bugworkaround) 334 (nnimap-wait-for-response (nnimap-send-command
1503 (dolist (pattern (nnimap-pattern-to-list-arguments 335 "UID FETCH %s FLAGS" spec))
1504 nnimap-list-pattern)) 336 (goto-char (point-min))
1505 (dolist (mbx (funcall nnimap-request-list-method (cdr pattern) (car pattern) nil 337 (while (re-search-forward "^\\* [0-9]+ FETCH (\\(.*\\))" nil t)
1506 nnimap-server-buffer)) 338 (setq elems (nnimap-parse-line (match-string 1)))
1507 (or (catch 'found 339 (push (cons (string-to-number (cadr (member "UID" elems)))
1508 (dolist (mailbox (imap-mailbox-get 'list-flags mbx 340 (cadr (member "FLAGS" elems)))
1509 nnimap-server-buffer)) 341 articles)))
1510 (if (string= (downcase mailbox) "\\noselect") 342 (nreverse articles)))
1511 (throw 'found t)))
1512 nil)
1513 (let* ((encoded-mbx (nnimap-encode-group-name mbx))
1514 (info (nnimap-find-minmax-uid encoded-mbx 'examine)))
1515 (when info
1516 (insert (format "\"%s\" %d %d y\n"
1517 encoded-mbx (or (nth 2 info) 0)
1518 (max 1 (or (nth 1 info) 1)))))))))
1519 (gnus-message 5 "nnimap: Listing subscribed mailboxes%s%s...done"
1520 (if (> (length server) 0) " on " "") server))
1521 t))
1522 343
1523(deffoo nnimap-request-create-group (group &optional server args) 344(defun nnimap-close-group (group &optional server)
1524 (when (nnimap-possibly-change-server server) 345 t)
1525 (let ((decoded-group (nnimap-decode-group-name group)))
1526 (or (imap-mailbox-status decoded-group 'uidvalidity nnimap-server-buffer)
1527 (imap-mailbox-create decoded-group nnimap-server-buffer)
1528 (nnheader-report 'nnimap "%S"
1529 (imap-error-text nnimap-server-buffer))))))
1530
1531(defun nnimap-time-substract (time1 time2)
1532 "Return TIME for TIME1 - TIME2."
1533 (let* ((ms (- (car time1) (car time2)))
1534 (ls (- (nth 1 time1) (nth 1 time2))))
1535 (if (< ls 0)
1536 (list (- ms 1) (+ (expt 2 16) ls))
1537 (list ms ls))))
1538
1539(eval-when-compile (require 'parse-time))
1540(defun nnimap-date-days-ago (daysago)
1541 "Return date, in format \"3-Aug-1998\", for DAYSAGO days ago."
1542 (require 'parse-time)
1543 (let* ((time (nnimap-time-substract (current-time) (days-to-time daysago)))
1544 (date (format-time-string
1545 (format "%%d-%s-%%Y"
1546 (capitalize (car (rassoc (nth 4 (decode-time time))
1547 parse-time-months))))
1548 time)))
1549 (if (eq ?0 (string-to-char date))
1550 (substring date 1)
1551 date)))
1552
1553(defun nnimap-request-expire-articles-progress ()
1554 (gnus-message 5 "nnimap: Marking article %d for deletion..."
1555 imap-current-message))
1556
1557(defun nnimap-expiry-target (arts group server)
1558 (unless (eq nnmail-expiry-target 'delete)
1559 (with-temp-buffer
1560 (dolist (art arts)
1561 (nnimap-request-article art group server (current-buffer))
1562 ;; hints for optimization in `nnimap-request-accept-article'
1563 (let ((nnimap-current-move-article art)
1564 (nnimap-current-move-group group)
1565 (nnimap-current-move-server server))
1566 (nnmail-expiry-target-group nnmail-expiry-target group))))
1567 ;; It is not clear if `nnmail-expiry-target' somehow cause the
1568 ;; current group to be changed or not, so we make sure here.
1569 (nnimap-possibly-change-group group server)))
1570
1571;; Notice that we don't actually delete anything, we just mark them deleted.
1572(deffoo nnimap-request-expire-articles (articles group &optional server force)
1573 (let ((artseq (gnus-compress-sequence articles)))
1574 (when (and artseq (nnimap-possibly-change-group group server))
1575 (with-current-buffer nnimap-server-buffer
1576 (let ((days (or (and nnmail-expiry-wait-function
1577 (funcall nnmail-expiry-wait-function group))
1578 nnmail-expiry-wait)))
1579 (cond ((or force (eq days 'immediate))
1580 (let ((oldarts (imap-search
1581 (concat "UID "
1582 (imap-range-to-message-set artseq)))))
1583 (when oldarts
1584 (nnimap-expiry-target oldarts group server)
1585 (when (imap-message-flags-add
1586 (imap-range-to-message-set
1587 (gnus-compress-sequence oldarts)) "\\Deleted")
1588 (setq articles (gnus-set-difference
1589 articles oldarts))))))
1590 ((and nnimap-search-uids-not-since-is-evil (numberp days))
1591 (let* ((all-new-articles
1592 (gnus-compress-sequence
1593 (imap-search (format "SINCE %s"
1594 (nnimap-date-days-ago days)))))
1595 (oldartseq
1596 (gnus-range-difference artseq all-new-articles))
1597 (oldarts (gnus-uncompress-range oldartseq)))
1598 (when oldarts
1599 (nnimap-expiry-target oldarts group server)
1600 (when (imap-message-flags-add
1601 (imap-range-to-message-set oldartseq)
1602 "\\Deleted")
1603 (setq articles (gnus-set-difference
1604 articles oldarts))))))
1605 ((numberp days)
1606 (let ((oldarts (imap-search
1607 (format nnimap-expunge-search-string
1608 (imap-range-to-message-set artseq)
1609 (nnimap-date-days-ago days))))
1610 (imap-fetch-data-hook
1611 '(nnimap-request-expire-articles-progress)))
1612 (when oldarts
1613 (nnimap-expiry-target oldarts group server)
1614 (when (imap-message-flags-add
1615 (imap-range-to-message-set
1616 (gnus-compress-sequence oldarts)) "\\Deleted")
1617 (setq articles (gnus-set-difference
1618 articles oldarts)))))))))))
1619 ;; return articles not deleted
1620 articles)
1621 346
1622(deffoo nnimap-request-move-article (article group server accept-form 347(deffoo nnimap-request-move-article (article group server accept-form
1623 &optional last move-is-internal) 348 &optional last internal-move-group)
1624 (when (nnimap-possibly-change-server server) 349 (when (nnimap-possibly-change-group group server)
1625 (save-excursion 350 ;; If the move is internal (on the same server), just do it the easy
1626 (let ((buf (get-buffer-create " *nnimap move*")) 351 ;; way.
1627 (nnimap-current-move-article article) 352 (let ((message-id (message-field-value "message-id")))
1628 (nnimap-current-move-group group) 353 (if internal-move-group
1629 (nnimap-current-move-server nnimap-current-server) 354 (let ((result
1630 result) 355 (with-current-buffer (nnimap-buffer)
1631 (gnus-message 10 "nnimap-request-move-article: this is an %s move" 356 (nnimap-command "UID COPY %d %S"
1632 (if move-is-internal 357 article
1633 "internal" 358 (utf7-encode internal-move-group t)))))
1634 "external")) 359 (when (car result)
1635 ;; request the article only when the move is NOT internal 360 (nnimap-delete-article article)
1636 (and (or move-is-internal 361 (cons internal-move-group
1637 (nnimap-request-article article group server)) 362 (nnimap-find-article-by-message-id
1638 (with-current-buffer buf 363 internal-move-group message-id))))
1639 (buffer-disable-undo (current-buffer)) 364 (with-temp-buffer
1640 (insert-buffer-substring nntp-server-buffer) 365 (let ((result (eval accept-form)))
1641 (setq result (eval accept-form)) 366 (when result
1642 (kill-buffer buf) 367 (nnimap-delete-article article)
1643 result) 368 result)))))))
1644 (nnimap-possibly-change-group group server) 369
1645 (imap-message-flags-add 370(deffoo nnimap-request-expire-articles (articles group &optional server force)
1646 (imap-range-to-message-set (list article)) 371 (cond
1647 "\\Deleted" 'silent nnimap-server-buffer)) 372 ((not (nnimap-possibly-change-group group server))
1648 result)))) 373 articles)
374 (force
375 (unless (nnimap-delete-article articles)
376 (message "Article marked for deletion, but not expunged."))
377 nil)
378 (t
379 articles)))
380
381(defun nnimap-find-article-by-message-id (group message-id)
382 (when (nnimap-possibly-change-group group nil)
383 (with-current-buffer (nnimap-buffer)
384 (let ((result
385 (nnimap-command "UID SEARCH HEADER Message-Id %S" message-id))
386 article)
387 (when (car result)
388 ;; Select the last instance of the message in the group.
389 (and (setq article
390 (car (last (assoc "SEARCH" (cdr result)))))
391 (string-to-number article)))))))
392
393(defun nnimap-delete-article (articles)
394 (with-current-buffer (nnimap-buffer)
395 (nnimap-command "UID STORE %s +FLAGS.SILENT (\\Deleted)"
396 (nnimap-article-ranges articles))
397 (when (member "UIDPLUS" (nnimap-capabilities nnimap-object))
398 (nnimap-send-command "UID EXPUNGE %s"
399 (nnimap-article-ranges articles))
400 t)))
401
402(deffoo nnimap-request-scan (&optional group server)
403 (when (and (nnimap-possibly-change-group nil server)
404 (equal group nnimap-inbox)
405 nnimap-inbox
406 nnimap-split-methods)
407 (nnimap-split-incoming-mail)))
408
409(defun nnimap-marks-to-flags (marks)
410 (let (flags flag)
411 (dolist (mark marks)
412 (when (setq flag (cadr (assq mark nnimap-mark-alist)))
413 (push flag flags)))
414 flags))
415
416(defun nnimap-request-set-mark (group actions &optional server)
417 (when (nnimap-possibly-change-group group server)
418 (let (sequence)
419 (with-current-buffer (nnimap-buffer)
420 ;; Just send all the STORE commands without waiting for
421 ;; response. If they're successful, they're successful.
422 (dolist (action actions)
423 (destructuring-bind (range action marks) action
424 (let ((flags (nnimap-marks-to-flags marks)))
425 (when flags
426 (setq sequence (nnimap-send-command
427 "UID STORE %s %sFLAGS.SILENT (%s)"
428 (nnimap-article-ranges range)
429 (if (eq action 'del)
430 "-"
431 "+")
432 (mapconcat #'identity flags " ")))))))
433 ;; Wait for the last command to complete to avoid later
434 ;; syncronisation problems with the stream.
435 (nnimap-wait-for-response sequence)))))
1649 436
1650(deffoo nnimap-request-accept-article (group &optional server last) 437(deffoo nnimap-request-accept-article (group &optional server last)
1651 (when (nnimap-possibly-change-server server) 438 (when (nnimap-possibly-change-group nil server)
1652 (let (uid) 439 (nnmail-check-syntax)
1653 (if (setq uid 440 (let ((message (buffer-string))
1654 (if (string= nnimap-current-server nnimap-current-move-server) 441 (message-id (message-field-value "message-id"))
1655 ;; moving article within same server, speed it up... 442 sequence)
1656 (and (nnimap-possibly-change-group 443 (with-current-buffer (nnimap-buffer)
1657 nnimap-current-move-group) 444 (setq sequence (nnimap-send-command
1658 (imap-message-copy (number-to-string 445 "APPEND %S {%d}" (utf7-encode group t)
1659 nnimap-current-move-article) 446 (length message)))
1660 (nnimap-decode-group-name group) 447 (process-send-string (get-buffer-process (current-buffer)) message)
1661 'dontcreate nil 448 (process-send-string (get-buffer-process (current-buffer)) "\r\n")
1662 nnimap-server-buffer)) 449 (let ((result (nnimap-get-response sequence)))
1663 (with-current-buffer (current-buffer) 450 (when result
1664 (goto-char (point-min)) 451 (cons group
1665 ;; remove any 'From blabla' lines, some IMAP servers 452 (nnimap-find-article-by-message-id group message-id))))))))
1666 ;; reject the entire message otherwise. 453
1667 (when (looking-at "^From[^:]") 454(defun nnimap-add-cr ()
1668 (delete-region (point) (progn (forward-line) (point)))) 455 (goto-char (point-min))
1669 ;; turn into rfc822 format (\r\n eol's) 456 (while (re-search-forward "\r?\n" nil t)
1670 (while (search-forward "\n" nil t) 457 (replace-match "\r\n" t t)))
1671 (replace-match "\r\n")) 458
1672 (when nnmail-cache-accepted-message-ids 459(defun nnimap-get-groups ()
1673 (nnmail-cache-insert (nnmail-fetch-field "message-id") 460 (let ((result (nnimap-command "LIST \"\" \"*\""))
1674 group 461 groups)
1675 (nnmail-fetch-field "subject")))) 462 (when (car result)
1676 (when (and last nnmail-cache-accepted-message-ids) 463 (dolist (line (cdr result))
1677 (nnmail-cache-close)) 464 (when (and (equal (car line) "LIST")
1678 ;; this 'or' is for Cyrus server bug 465 (not (and (caadr line)
1679 (or (null (imap-current-mailbox nnimap-server-buffer)) 466 (string-match "noselect" (caadr line)))))
1680 (imap-mailbox-unselect nnimap-server-buffer)) 467 (push (car (last line)) groups)))
1681 (imap-message-append (nnimap-decode-group-name group) 468 (nreverse groups))))
1682 (current-buffer) nil nil 469
1683 nnimap-server-buffer))) 470(defun nnimap-request-list (&optional server)
1684 (cons group (nth 1 uid)) 471 (nnimap-possibly-change-group nil server)
1685 (nnheader-report 'nnimap (imap-error-text nnimap-server-buffer)))))) 472 (with-current-buffer nntp-server-buffer
1686 473 (erase-buffer)
1687(deffoo nnimap-request-delete-group (group force &optional server) 474 (let ((groups
1688 (when (nnimap-possibly-change-server server) 475 (with-current-buffer (nnimap-buffer)
1689 (setq group (nnimap-decode-group-name group)) 476 (nnimap-get-groups)))
1690 (when (string= group (imap-current-mailbox nnimap-server-buffer)) 477 sequences responses)
1691 (imap-mailbox-unselect nnimap-server-buffer)) 478 (when groups
1692 (with-current-buffer nnimap-server-buffer 479 (with-current-buffer (nnimap-buffer)
1693 (if force 480 (dolist (group groups)
1694 (or (null (imap-mailbox-status group 'uidvalidity)) 481 (push (list (nnimap-send-command "EXAMINE %S" (utf7-encode group t))
1695 (imap-mailbox-delete group)) 482 group)
1696 ;; UNSUBSCRIBE? 483 sequences))
484 (nnimap-wait-for-response (caar sequences))
485 (setq responses
486 (nnimap-get-responses (mapcar #'car sequences))))
487 (dolist (response responses)
488 (let* ((sequence (car response))
489 (response (cadr response))
490 (group (cadr (assoc sequence sequences))))
491 (when (and group
492 (equal (caar response) "OK"))
493 (let ((uidnext (nnimap-find-parameter "UIDNEXT" response))
494 highest exists)
495 (dolist (elem response)
496 (when (equal (cadr elem) "EXISTS")
497 (setq exists (string-to-number (car elem)))))
498 (when uidnext
499 (setq highest (1- (string-to-number (car uidnext)))))
500 (cond
501 ((null highest)
502 (insert (format "%S 0 1 y\n" (utf7-decode group t))))
503 ((zerop exists)
504 ;; Empty group.
505 (insert (format "%S %d %d y\n"
506 (utf7-decode group t) highest (1+ highest))))
507 (t
508 ;; Return the widest possible range.
509 (insert (format "%S %d 1 y\n" (utf7-decode group t)
510 (or highest exists)))))))))
1697 t)))) 511 t))))
1698 512
1699(deffoo nnimap-request-rename-group (group new-name &optional server) 513(defun nnimap-retrieve-group-data-early (server infos)
1700 (when (nnimap-possibly-change-server server) 514 (when (nnimap-possibly-change-group nil server)
1701 (imap-mailbox-rename (nnimap-decode-group-name group) 515 (with-current-buffer (nnimap-buffer)
1702 (nnimap-decode-group-name new-name) 516 ;; QRESYNC handling isn't implemented.
1703 nnimap-server-buffer))) 517 (let ((qresyncp (member "notQRESYNC" (nnimap-capabilities nnimap-object)))
1704 518 marks groups sequences)
1705(defun nnimap-expunge (mailbox server) 519 ;; Go through the infos and gather the data needed to know
1706 (when (nnimap-possibly-change-group mailbox server) 520 ;; what and how to request the data.
1707 (imap-mailbox-expunge nil nnimap-server-buffer))) 521 (dolist (info infos)
1708 522 (setq marks (gnus-info-marks info))
1709(defun nnimap-acl-get (mailbox server) 523 (push (list (gnus-group-real-name (gnus-info-group info))
1710 (when (nnimap-possibly-change-server server) 524 (cdr (assq 'active marks))
1711 (and (imap-capability 'ACL nnimap-server-buffer) 525 (cdr (assq 'uid marks)))
1712 (imap-mailbox-acl-get (nnimap-decode-group-name mailbox) 526 groups))
1713 nnimap-server-buffer)))) 527 ;; Then request the data.
1714 528 (erase-buffer)
1715(defun nnimap-acl-edit (mailbox method old-acls new-acls) 529 (dolist (elem groups)
1716 (when (nnimap-possibly-change-server (cadr method)) 530 (if (and qresyncp
1717 (unless (imap-capability 'ACL nnimap-server-buffer) 531 (nth 2 elem))
1718 (error "Your server does not support ACL editing")) 532 (push
1719 (with-current-buffer nnimap-server-buffer 533 (list 'qresync
1720 ;; delete all removed identifiers 534 (nnimap-send-command "EXAMINE %S (QRESYNC (%s %s))"
1721 (mapc (lambda (old-acl) 535 (car elem)
1722 (unless (assoc (car old-acl) new-acls) 536 (car (nth 2 elem))
1723 (or (imap-mailbox-acl-delete (car old-acl) 537 (cdr (nth 2 elem)))
1724 (nnimap-decode-group-name mailbox)) 538 nil
1725 (error "Can't delete ACL for %s" (car old-acl))))) 539 (car elem))
1726 old-acls) 540 sequences)
1727 ;; set all changed acl's 541 (let ((start
1728 (mapc (lambda (new-acl) 542 (if (nth 1 elem)
1729 (let ((new-rights (cdr new-acl)) 543 ;; Fetch the last 100 flags.
1730 (old-rights (cdr (assoc (car new-acl) old-acls)))) 544 (max 1 (- (cdr (nth 1 elem)) 100))
1731 (unless (and old-rights new-rights 545 1)))
1732 (string= old-rights new-rights)) 546 (push (list (nnimap-send-command "EXAMINE %S" (car elem))
1733 (or (imap-mailbox-acl-set (car new-acl) new-rights 547 (nnimap-send-command "UID FETCH %d:* FLAGS" start)
1734 (nnimap-decode-group-name mailbox)) 548 start
1735 (error "Can't set ACL for %s to %s" (car new-acl) 549 (car elem))
1736 new-rights))))) 550 sequences))))
1737 new-acls) 551 sequences))))
1738 t))) 552
553(defun nnimap-finish-retrieve-group-infos (server infos sequences)
554 (when (and sequences
555 (nnimap-possibly-change-group nil server))
556 (with-current-buffer (nnimap-buffer)
557 ;; Wait for the final data to trickle in.
558 (nnimap-wait-for-response (cadar sequences))
559 ;; Now we should have all the data we need, no matter whether
560 ;; we're QRESYNCING, fetching all the flags from scratch, or
561 ;; just fetching the last 100 flags per group.
562 (nnimap-update-infos (nnimap-flags-to-marks
563 (nnimap-parse-flags
564 (nreverse sequences)))
565 infos))))
566
567(defun nnimap-update-infos (flags infos)
568 (dolist (info infos)
569 (let ((group (gnus-group-real-name (gnus-info-group info))))
570 (nnimap-update-info info (cdr (assoc group flags))))))
571
572(defun nnimap-update-info (info marks)
573 (when marks
574 (destructuring-bind (existing flags high low uidnext start-article) marks
575 (let ((group (gnus-info-group info))
576 (completep (and start-article
577 (= start-article 1))))
578 ;; First set the active ranges based on high/low.
579 (if (or completep
580 (not (gnus-active group)))
581 (gnus-set-active group
582 (if high
583 (cons low high)
584 ;; No articles in this group.
585 (cons (1- uidnext) uidnext)))
586 (setcdr (gnus-active group) high))
587 ;; Then update the list of read articles.
588 (let* ((unread
589 (gnus-compress-sequence
590 (gnus-set-difference
591 (gnus-set-difference
592 existing
593 (cdr (assoc "\\Seen" flags)))
594 (cdr (assoc "\\Flagged" flags)))))
595 (read (gnus-range-difference
596 (cons start-article high) unread)))
597 (when (> start-article 1)
598 (setq read
599 (gnus-range-nconcat
600 (gnus-sorted-range-intersection
601 (cons 1 start-article)
602 (gnus-info-read info))
603 read)))
604 (gnus-info-set-read info read)
605 ;; Update the marks.
606 (setq marks (gnus-info-marks info))
607 ;; Note the active level for the next run-through.
608 (let ((active (assq 'active marks)))
609 (if active
610 (setcdr active (gnus-active group))
611 (push (cons 'active (gnus-active group)) marks)))
612 (dolist (type (cdr nnimap-mark-alist))
613 (let ((old-marks (assoc (car type) marks))
614 (new-marks (gnus-compress-sequence
615 (cdr (assoc (cadr type) flags)))))
616 (setq marks (delq old-marks marks))
617 (pop old-marks)
618 (when (and old-marks
619 (> start-article 1))
620 (setq old-marks (gnus-range-difference
621 (cons start-article high)
622 old-marks))
623 (setq new-marks (gnus-range-nconcat old-marks new-marks)))
624 (when new-marks
625 (push (cons (car type) new-marks) marks)))
626 (gnus-info-set-marks info marks)))))))
627
628(defun nnimap-flags-to-marks (groups)
629 (let (data group totalp uidnext articles start-article mark)
630 (dolist (elem groups)
631 (setq group (car elem)
632 uidnext (cadr elem)
633 start-article (caddr elem)
634 articles (cdddr elem))
635 (let ((high (caar articles))
636 marks low existing)
637 (dolist (article articles)
638 (setq low (car article))
639 (push (car article) existing)
640 (dolist (flag (cdr article))
641 (setq mark (assoc flag marks))
642 (if (not mark)
643 (push (list flag (car article)) marks)
644 (setcdr mark (cons (car article) (cdr mark)))))
645 (push (list group existing marks high low uidnext start-article)
646 data))))
647 data))
648
649(defun nnimap-parse-flags (sequences)
650 (goto-char (point-min))
651 (let (start end articles groups uidnext elems)
652 (dolist (elem sequences)
653 (destructuring-bind (group-sequence flag-sequence totalp group) elem
654 ;; The EXAMINE was successful.
655 (when (and (search-forward (format "\n%d OK " group-sequence) nil t)
656 (progn
657 (forward-line 1)
658 (setq start (point))
659 (if (re-search-backward "UIDNEXT \\([0-9]+\\)"
660 (or end (point-min)) t)
661 (setq uidnext (string-to-number (match-string 1)))
662 (setq uidnext nil))
663 (goto-char start))
664 ;; The UID FETCH FLAGS was successful.
665 (search-forward (format "\n%d OK " flag-sequence) nil t))
666 (setq end (point))
667 (goto-char start)
668 (while (re-search-forward "^\\* [0-9]+ FETCH (\\(.*\\))" end t)
669 (setq elems (nnimap-parse-line (match-string 1)))
670 (push (cons (string-to-number (cadr (member "UID" elems)))
671 (cadr (member "FLAGS" elems)))
672 articles))
673 (push (nconc (list group uidnext totalp) articles) groups)
674 (setq articles nil))))
675 groups))
676
677(defun nnimap-find-process-buffer (buffer)
678 (cadr (assoc buffer nnimap-connection-alist)))
679
680(defun nnimap-request-post (&optional server)
681 (setq nnimap-status-string "Read-only server")
682 nil)
1739 683
1740 684(defun nnimap-possibly-change-group (group server)
1741;;; Internal functions 685 (let ((open-result t))
1742 686 (when (and server
1743;; 687 (not (nnimap-server-opened server)))
1744;; This is confusing. 688 (setq open-result (nnimap-open-server server)))
1745;; 689 (cond
1746;; mark => read, tick, draft, reply etc 690 ((not open-result)
1747;; flag => "\\Seen", "\\Flagged", "\\Draft", "gnus-expire" etc 691 nil)
1748;; predicate => "SEEN", "FLAGGED", "DRAFT", "KEYWORD gnus-expire" etc 692 ((not group)
1749;; 693 t)
1750;; Mark should not really contain 'read since it's not a "mark" in the Gnus 694 (t
1751;; world, but we cheat. Mark == gnus-article-mark-lists + '(read . read). 695 (with-current-buffer (nnimap-buffer)
1752;; 696 (if (equal group (nnimap-group nnimap-object))
1753 697 t
1754(defconst nnimap-mark-to-predicate-alist 698 (let ((result (nnimap-command "SELECT %S" (utf7-encode group t))))
1755 (mapcar 699 (when (car result)
1756 (lambda (pair) ; cdr is the mark 700 (setf (nnimap-group nnimap-object) group)
1757 (or (assoc (cdr pair) 701 result))))))))
1758 '((read . "SEEN") 702
1759 (tick . "FLAGGED") 703(defun nnimap-find-connection (buffer)
1760 (draft . "DRAFT") 704 "Find the connection delivering to BUFFER."
1761 (recent . "RECENT") 705 (let ((entry (assoc buffer nnimap-connection-alist)))
1762 (reply . "ANSWERED"))) 706 (when entry
1763 (cons (cdr pair) 707 (if (and (buffer-name (cadr entry))
1764 (format "KEYWORD gnus-%s" (symbol-name (cdr pair)))))) 708 (get-buffer-process (cadr entry))
1765 (cons '(read . read) gnus-article-mark-lists))) 709 (memq (process-status (get-buffer-process (cadr entry)))
1766 710 '(open run)))
1767(defun nnimap-mark-to-predicate (pred) 711 (get-buffer-process (cadr entry))
1768 "Convert a Gnus mark (a symbol such as read, tick, expire) to a IMAP predicate. 712 (setq nnimap-connection-alist (delq entry nnimap-connection-alist))
1769This is a string such as \"SEEN\", \"FLAGGED\", \"KEYWORD gnus-expire\", 713 nil))))
1770to be used within a IMAP SEARCH query." 714
1771 (cdr (assq pred nnimap-mark-to-predicate-alist))) 715(defvar nnimap-sequence 0)
1772 716
1773(defconst nnimap-mark-to-flag-alist 717(defun nnimap-send-command (&rest args)
1774 (mapcar 718 (process-send-string
1775 (lambda (pair) 719 (get-buffer-process (current-buffer))
1776 (or (assoc (cdr pair) 720 (nnimap-log-command
1777 '((read . "\\Seen") 721 (format "%d %s\r\n"
1778 (tick . "\\Flagged") 722 (incf nnimap-sequence)
1779 (draft . "\\Draft") 723 (apply #'format args))))
1780 (recent . "\\Recent") 724 nnimap-sequence)
1781 (reply . "\\Answered"))) 725
1782 (cons (cdr pair) 726(defun nnimap-log-command (command)
1783 (format "gnus-%s" (symbol-name (cdr pair)))))) 727 (with-current-buffer (get-buffer-create "*imap log*")
1784 (cons '(read . read) gnus-article-mark-lists))) 728 (goto-char (point-max))
1785 729 (insert (format-time-string "%H:%M:%S") " " command))
1786(defun nnimap-mark-to-flag-1 (preds) 730 command)
1787 (if (and (not (null preds)) (listp preds)) 731
1788 (cons (nnimap-mark-to-flag (car preds)) 732(defun nnimap-command (&rest args)
1789 (nnimap-mark-to-flag (cdr preds))) 733 (erase-buffer)
1790 (cdr (assoc preds nnimap-mark-to-flag-alist)))) 734 (let* ((sequence (apply #'nnimap-send-command args))
1791 735 (response (nnimap-get-response sequence)))
1792(defun nnimap-mark-to-flag (preds &optional always-list make-string) 736 (if (equal (caar response) "OK")
1793 "Convert a Gnus mark (a symbol such as read, tick, expire) to a IMAP flag. 737 (cons t response)
1794This is a string such as \"\\Seen\", \"\\Flagged\", \"gnus-expire\", to 738 (nnheader-report 'nnimap "%s"
1795be used in a STORE FLAGS command." 739 (mapconcat #'identity (car response) " "))
1796 (let ((result (nnimap-mark-to-flag-1 preds))) 740 nil)))
1797 (setq result (if (and (or make-string always-list) 741
1798 (not (listp result))) 742(defun nnimap-get-response (sequence)
1799 (list result) 743 (nnimap-wait-for-response sequence)
1800 result)) 744 (nnimap-parse-response))
1801 (if make-string 745
1802 (mapconcat (lambda (flag) 746(defun nnimap-wait-for-response (sequence &optional messagep)
1803 (if (listp flag) 747 (goto-char (point-max))
1804 (mapconcat 'identity flag " ") 748 (while (or (bobp)
1805 flag)) 749 (progn
1806 result " ") 750 (forward-line -1)
1807 result))) 751 (not (looking-at (format "^%d .*\n" sequence)))))
1808 752 (when messagep
1809(defun nnimap-mark-permanent-p (mark &optional group) 753 (message "Read %dKB" (/ (buffer-size) 1000)))
1810 "Return t if MARK can be permanently (between IMAP sessions) saved on articles, in GROUP." 754 (nnheader-accept-process-output (get-buffer-process (current-buffer)))
1811 (imap-message-flag-permanent-p (nnimap-mark-to-flag mark))) 755 (goto-char (point-max))))
756
757(defun nnimap-parse-response ()
758 (let ((lines (split-string (nnimap-last-response-string) "\r\n" t))
759 result)
760 (dolist (line lines)
761 (push (cdr (nnimap-parse-line line)) result))
762 ;; Return the OK/error code first, and then all the "continuation
763 ;; lines" afterwards.
764 (cons (pop result)
765 (nreverse result))))
766
767;; Parse an IMAP response line lightly. They look like
768;; "* OK [UIDVALIDITY 1164213559] UIDs valid", typically, so parse
769;; the lines into a list of strings and lists of string.
770(defun nnimap-parse-line (line)
771 (let (char result)
772 (with-temp-buffer
773 (insert line)
774 (goto-char (point-min))
775 (while (not (eobp))
776 (if (eql (setq char (following-char)) ? )
777 (forward-char 1)
778 (push
779 (cond
780 ((eql char ?\[)
781 (split-string (buffer-substring
782 (1+ (point)) (1- (search-forward "]")))))
783 ((eql char ?\()
784 (split-string (buffer-substring
785 (1+ (point)) (1- (search-forward ")")))))
786 ((eql char ?\")
787 (forward-char 1)
788 (buffer-substring (point) (1- (search-forward "\""))))
789 (t
790 (buffer-substring (point) (if (search-forward " " nil t)
791 (1- (point))
792 (goto-char (point-max))))))
793 result)))
794 (nreverse result))))
795
796(defun nnimap-last-response-string ()
797 (save-excursion
798 (forward-line 1)
799 (let ((end (point)))
800 (forward-line -1)
801 (when (not (bobp))
802 (forward-line -1)
803 (while (and (not (bobp))
804 (eql (following-char) ?*))
805 (forward-line -1))
806 (unless (eql (following-char) ?*)
807 (forward-line 1)))
808 (buffer-substring (point) end))))
809
810(defun nnimap-get-responses (sequences)
811 (let (responses)
812 (dolist (sequence sequences)
813 (goto-char (point-min))
814 (when (re-search-forward (format "^%d " sequence) nil t)
815 (push (list sequence (nnimap-parse-response))
816 responses)))
817 responses))
818
819(defvar nnimap-incoming-split-list nil)
820
821(defun nnimap-fetch-inbox (articles)
822 (erase-buffer)
823 (nnimap-wait-for-response
824 (nnimap-send-command
825 "UID FETCH %s %s"
826 (nnimap-article-ranges articles)
827 (format "(UID %s%s)"
828 (format
829 (if (member "IMAP4REV1"
830 (nnimap-capabilities nnimap-object))
831 "BODY.PEEK[HEADER] BODY.PEEK"
832 "RFC822.PEEK"))
833 (if nnimap-split-download-body-default
834 ""
835 "[1]")))
836 t))
837
838(defun nnimap-split-incoming-mail ()
839 (with-current-buffer (nnimap-buffer)
840 (let ((nnimap-incoming-split-list nil)
841 (nnmail-split-methods nnimap-split-methods)
842 (nnmail-inhibit-default-split-group t)
843 (groups (nnimap-get-groups))
844 new-articles)
845 (erase-buffer)
846 (nnimap-command "SELECT %S" nnimap-inbox)
847 (setq new-articles (nnimap-new-articles (nnimap-get-flags "1:*")))
848 (when new-articles
849 (nnimap-fetch-inbox new-articles)
850 (nnimap-transform-split-mail)
851 (nnheader-ms-strip-cr)
852 (nnmail-cache-open)
853 (nnmail-split-incoming (current-buffer)
854 #'nnimap-save-mail-spec
855 nil nil
856 #'nnimap-dummy-active-number)
857 (when nnimap-incoming-split-list
858 (let ((specs (nnimap-make-split-specs nnimap-incoming-split-list))
859 sequences)
860 ;; Create any groups that doesn't already exist on the
861 ;; server first.
862 (dolist (spec specs)
863 (unless (member (car spec) groups)
864 (nnimap-command "CREATE %S" (utf7-encode (car spec) t))))
865 ;; Then copy over all the messages.
866 (erase-buffer)
867 (dolist (spec specs)
868 (let ((group (car spec))
869 (ranges (cdr spec)))
870 (push (list (nnimap-send-command "UID COPY %s %S"
871 (nnimap-article-ranges ranges)
872 (utf7-encode group t))
873 ranges)
874 sequences)))
875 ;; Wait for the last COPY response...
876 (when sequences
877 (nnimap-wait-for-response (caar sequences))
878 ;; And then mark the successful copy actions as deleted,
879 ;; and possibly expunge them.
880 (nnimap-mark-and-expunge-incoming
881 (nnimap-parse-copied-articles sequences)))))))))
882
883(defun nnimap-mark-and-expunge-incoming (range)
884 (when range
885 (setq range (nnimap-article-ranges range))
886 (nnimap-send-command
887 "UID STORE %s +FLAGS.SILENT (\\Deleted)" range)
888 (cond
889 ;; If the server supports it, we now delete the message we have
890 ;; just copied over.
891 ((member "UIDPLUS" (nnimap-capabilities nnimap-object))
892 (nnimap-send-command "UID EXPUNGE %s" range))
893 ;; If it doesn't support UID EXPUNGE, then we only expunge if the
894 ;; user has configured it.
895 (nnimap-expunge-inbox
896 (nnimap-send-command "EXPUNGE")))))
897
898(defun nnimap-parse-copied-articles (sequences)
899 (let (sequence copied range)
900 (goto-char (point-min))
901 (while (re-search-forward "^\\([0-9]+\\) OK " nil t)
902 (setq sequence (string-to-number (match-string 1)))
903 (when (setq range (cadr (assq sequence sequences)))
904 (push (gnus-uncompress-range range) copied)))
905 (gnus-compress-sequence (sort (apply #'nconc copied) #'<))))
906
907(defun nnimap-new-articles (flags)
908 (let (new)
909 (dolist (elem flags)
910 (when (or (null (cdr elem))
911 (and (not (member "\\Deleted" (cdr elem)))
912 (not (member "\\Seen" (cdr elem)))))
913 (push (car elem) new)))
914 (gnus-compress-sequence (nreverse new))))
915
916(defun nnimap-make-split-specs (list)
917 (let ((specs nil)
918 entry)
919 (dolist (elem list)
920 (destructuring-bind (article spec) elem
921 (dolist (group (delete nil (mapcar #'car spec)))
922 (unless (setq entry (assoc group specs))
923 (push (setq entry (list group)) specs))
924 (setcdr entry (cons article (cdr entry))))))
925 (dolist (entry specs)
926 (setcdr entry (gnus-compress-sequence (sort (cdr entry) #'<))))
927 specs))
928
929(defun nnimap-transform-split-mail ()
930 (goto-char (point-min))
931 (let (article bytes)
932 (block nil
933 (while (not (eobp))
934 (while (not (looking-at "^\\* [0-9]+ FETCH.*UID \\([0-9]+\\)"))
935 (delete-region (point) (progn (forward-line 1) (point)))
936 (when (eobp)
937 (return)))
938 (setq article (match-string 1)
939 bytes (nnimap-get-length))
940 (delete-region (line-beginning-position) (line-end-position))
941 ;; Insert MMDF separator, and a way to remember what this
942 ;; article UID is.
943 (insert (format "\^A\^A\^A\^A\n\nX-nnimap-article: %s" article))
944 (forward-char (1+ bytes))
945 (setq bytes (nnimap-get-length))
946 (delete-region (line-beginning-position) (line-end-position))
947 (forward-char (1+ bytes))
948 (delete-region (line-beginning-position) (line-end-position))))))
949
950(defun nnimap-dummy-active-number (group &optional server)
951 1)
952
953(defun nnimap-save-mail-spec (group-art &optional server full-nov)
954 (let (article)
955 (goto-char (point-min))
956 (if (not (re-search-forward "X-nnimap-article: \\([0-9]+\\)" nil t))
957 (error "Invalid nnimap mail")
958 (setq article (string-to-number (match-string 1))))
959 (push (list article group-art)
960 nnimap-incoming-split-list)))
1812 961
1813(provide 'nnimap) 962(provide 'nnimap)
1814 963
diff --git a/lisp/gnus/nnir.el b/lisp/gnus/nnir.el
index 6096c6fb374..27610e7aba2 100644
--- a/lisp/gnus/nnir.el
+++ b/lisp/gnus/nnir.el
@@ -744,8 +744,7 @@ and show thread that contains this article."
744 nnir-artlist 744 nnir-artlist
745 ;; Cache miss. 745 ;; Cache miss.
746 (setq nnir-artlist (nnir-run-query group))) 746 (setq nnir-artlist (nnir-run-query group)))
747 (save-excursion 747 (with-current-buffer nntp-server-buffer
748 (set-buffer nntp-server-buffer)
749 (if (zerop (length nnir-artlist)) 748 (if (zerop (length nnir-artlist))
750 (progn 749 (progn
751 (setq nnir-current-query nil 750 (setq nnir-current-query nil
diff --git a/lisp/gnus/nnmail.el b/lisp/gnus/nnmail.el
index b7d834ecd8c..3e6cee82521 100644
--- a/lisp/gnus/nnmail.el
+++ b/lisp/gnus/nnmail.el
@@ -614,6 +614,7 @@ using different case (i.e. mailing-list@domain vs Mailing-List@Domain)."
614 614
615(defvar nnmail-split-tracing nil) 615(defvar nnmail-split-tracing nil)
616(defvar nnmail-split-trace nil) 616(defvar nnmail-split-trace nil)
617(defvar nnmail-inhibit-default-split-group nil)
617 618
618 619
619 620
@@ -674,8 +675,7 @@ using different case (i.e. mailing-list@domain vs Mailing-List@Domain)."
674 "Returns an assoc of group names and active ranges. 675 "Returns an assoc of group names and active ranges.
675nn*-request-list should have been called before calling this function." 676nn*-request-list should have been called before calling this function."
676 ;; Go through all groups from the active list. 677 ;; Go through all groups from the active list.
677 (save-excursion 678 (with-current-buffer nntp-server-buffer
678 (set-buffer nntp-server-buffer)
679 (nnmail-parse-active))) 679 (nnmail-parse-active)))
680 680
681(defun nnmail-parse-active () 681(defun nnmail-parse-active ()
@@ -1058,7 +1058,9 @@ If SOURCE is a directory spec, try to return the group name component."
1058(defun nnmail-split-incoming (incoming func &optional exit-func 1058(defun nnmail-split-incoming (incoming func &optional exit-func
1059 group artnum-func) 1059 group artnum-func)
1060 "Go through the entire INCOMING file and pick out each individual mail. 1060 "Go through the entire INCOMING file and pick out each individual mail.
1061FUNC will be called with the buffer narrowed to each mail." 1061FUNC will be called with the buffer narrowed to each mail.
1062INCOMING can also be a buffer object. In that case, the mail
1063will be copied over from that buffer."
1062 (let ( ;; If this is a group-specific split, we bind the split 1064 (let ( ;; If this is a group-specific split, we bind the split
1063 ;; methods to just this group. 1065 ;; methods to just this group.
1064 (nnmail-split-methods (if (and group 1066 (nnmail-split-methods (if (and group
@@ -1066,12 +1068,13 @@ FUNC will be called with the buffer narrowed to each mail."
1066 (list (list group "")) 1068 (list (list group ""))
1067 nnmail-split-methods)) 1069 nnmail-split-methods))
1068 (nnmail-group-names-not-encoded-p t)) 1070 (nnmail-group-names-not-encoded-p t))
1069 (save-excursion 1071 ;; Insert the incoming file.
1070 ;; Insert the incoming file. 1072 (with-current-buffer (get-buffer-create nnmail-article-buffer)
1071 (set-buffer (get-buffer-create nnmail-article-buffer))
1072 (erase-buffer) 1073 (erase-buffer)
1073 (let ((coding-system-for-read nnmail-incoming-coding-system)) 1074 (if (bufferp incoming)
1074 (mm-insert-file-contents incoming)) 1075 (insert-buffer-substring incoming)
1076 (let ((coding-system-for-read nnmail-incoming-coding-system))
1077 (mm-insert-file-contents incoming)))
1075 (prog1 1078 (prog1
1076 (if (zerop (buffer-size)) 1079 (if (zerop (buffer-size))
1077 0 1080 0
@@ -1100,15 +1103,15 @@ FUNC will be called with the group name to determine the article number."
1100 (obuf (current-buffer)) 1103 (obuf (current-buffer))
1101 group-art method grp) 1104 group-art method grp)
1102 (if (and (sequencep methods) 1105 (if (and (sequencep methods)
1103 (= (length methods) 1)) 1106 (= (length methods) 1)
1107 (not nnmail-inhibit-default-split-group))
1104 ;; If there is only just one group to put everything in, we 1108 ;; If there is only just one group to put everything in, we
1105 ;; just return a list with just this one method in. 1109 ;; just return a list with just this one method in.
1106 (setq group-art 1110 (setq group-art
1107 (list (cons (caar methods) (funcall func (caar methods))))) 1111 (list (cons (caar methods) (funcall func (caar methods)))))
1108 ;; We do actual comparison. 1112 ;; We do actual comparison.
1109 (save-excursion 1113 ;; Copy the article into the work buffer.
1110 ;; Copy the article into the work buffer. 1114 (with-current-buffer nntp-server-buffer
1111 (set-buffer nntp-server-buffer)
1112 (erase-buffer) 1115 (erase-buffer)
1113 (insert-buffer-substring obuf) 1116 (insert-buffer-substring obuf)
1114 ;; Narrow to headers. 1117 ;; Narrow to headers.
@@ -1149,7 +1152,8 @@ FUNC will be called with the group name to determine the article number."
1149 ;; just call this function here and use the 1152 ;; just call this function here and use the
1150 ;; result. 1153 ;; result.
1151 (or (funcall nnmail-split-methods) 1154 (or (funcall nnmail-split-methods)
1152 '("bogus")) 1155 (and (not nnmail-inhibit-default-split-group)
1156 '("bogus")))
1153 (error 1157 (error
1154 (nnheader-message 1158 (nnheader-message
1155 5 "Error in `nnmail-split-methods'; using `bogus' mail group: %S" error-info) 1159 5 "Error in `nnmail-split-methods'; using `bogus' mail group: %S" error-info)
@@ -1194,12 +1198,14 @@ FUNC will be called with the group name to determine the article number."
1194 group-art)) 1198 group-art))
1195 ;; This is the final group, which is used as a 1199 ;; This is the final group, which is used as a
1196 ;; catch-all. 1200 ;; catch-all.
1197 (unless group-art 1201 (when (and (not group-art)
1202 (not nnmail-inhibit-default-split-group))
1198 (setq group-art 1203 (setq group-art
1199 (list (cons (car method) 1204 (list (cons (car method)
1200 (funcall func (car method)))))))) 1205 (funcall func (car method))))))))
1201 ;; Fall back on "bogus" if all else fails. 1206 ;; Fall back on "bogus" if all else fails.
1202 (unless group-art 1207 (when (and (not group-art)
1208 (not nnmail-inhibit-default-split-group))
1203 (setq group-art (list (cons "bogus" (funcall func "bogus")))))) 1209 (setq group-art (list (cons "bogus" (funcall func "bogus"))))))
1204 ;; Produce a trace if non-empty. 1210 ;; Produce a trace if non-empty.
1205 (when (and trace nnmail-split-trace) 1211 (when (and trace nnmail-split-trace)
@@ -1572,10 +1578,9 @@ See the documentation for the variable `nnmail-split-fancy' for details."
1572 (and nnmail-cache-buffer 1578 (and nnmail-cache-buffer
1573 (buffer-name nnmail-cache-buffer))) 1579 (buffer-name nnmail-cache-buffer)))
1574 () ; The buffer is open. 1580 () ; The buffer is open.
1575 (save-excursion 1581 (with-current-buffer
1576 (set-buffer
1577 (setq nnmail-cache-buffer 1582 (setq nnmail-cache-buffer
1578 (get-buffer-create " *nnmail message-id cache*"))) 1583 (get-buffer-create " *nnmail message-id cache*"))
1579 (gnus-add-buffer) 1584 (gnus-add-buffer)
1580 (when (file-exists-p nnmail-message-id-cache-file) 1585 (when (file-exists-p nnmail-message-id-cache-file)
1581 (nnheader-insert-file-contents nnmail-message-id-cache-file)) 1586 (nnheader-insert-file-contents nnmail-message-id-cache-file))
@@ -1587,8 +1592,7 @@ See the documentation for the variable `nnmail-split-fancy' for details."
1587 nnmail-treat-duplicates 1592 nnmail-treat-duplicates
1588 (buffer-name nnmail-cache-buffer) 1593 (buffer-name nnmail-cache-buffer)
1589 (buffer-modified-p nnmail-cache-buffer)) 1594 (buffer-modified-p nnmail-cache-buffer))
1590 (save-excursion 1595 (with-current-buffer nnmail-cache-buffer
1591 (set-buffer nnmail-cache-buffer)
1592 ;; Weed out the excess number of Message-IDs. 1596 ;; Weed out the excess number of Message-IDs.
1593 (goto-char (point-max)) 1597 (goto-char (point-max))
1594 (when (search-backward "\n" nil t nnmail-message-id-cache-length) 1598 (when (search-backward "\n" nil t nnmail-message-id-cache-length)
@@ -1623,8 +1627,7 @@ See the documentation for the variable `nnmail-split-fancy' for details."
1623 ;; pass the first (of possibly >1) group which matches. -Josh 1627 ;; pass the first (of possibly >1) group which matches. -Josh
1624 (unless (gnus-buffer-live-p nnmail-cache-buffer) 1628 (unless (gnus-buffer-live-p nnmail-cache-buffer)
1625 (nnmail-cache-open)) 1629 (nnmail-cache-open))
1626 (save-excursion 1630 (with-current-buffer nnmail-cache-buffer
1627 (set-buffer nnmail-cache-buffer)
1628 (goto-char (point-max)) 1631 (goto-char (point-max))
1629 (if (and grp (not (string= "" grp)) 1632 (if (and grp (not (string= "" grp))
1630 (gnus-methods-equal-p gnus-command-method 1633 (gnus-methods-equal-p gnus-command-method
@@ -1657,8 +1660,7 @@ See the documentation for the variable `nnmail-split-fancy' for details."
1657;; cache. 1660;; cache.
1658(defun nnmail-cache-fetch-group (id) 1661(defun nnmail-cache-fetch-group (id)
1659 (when (and nnmail-treat-duplicates nnmail-cache-buffer) 1662 (when (and nnmail-treat-duplicates nnmail-cache-buffer)
1660 (save-excursion 1663 (with-current-buffer nnmail-cache-buffer
1661 (set-buffer nnmail-cache-buffer)
1662 (goto-char (point-max)) 1664 (goto-char (point-max))
1663 (when (search-backward id nil t) 1665 (when (search-backward id nil t)
1664 (beginning-of-line) 1666 (beginning-of-line)
@@ -1702,8 +1704,7 @@ See the Info node `(gnus)Fancy Mail Splitting' for more details."
1702 1704
1703(defun nnmail-cache-id-exists-p (id) 1705(defun nnmail-cache-id-exists-p (id)
1704 (when nnmail-treat-duplicates 1706 (when nnmail-treat-duplicates
1705 (save-excursion 1707 (with-current-buffer nnmail-cache-buffer
1706 (set-buffer nnmail-cache-buffer)
1707 (goto-char (point-max)) 1708 (goto-char (point-max))
1708 (search-backward id nil t)))) 1709 (search-backward id nil t))))
1709 1710
diff --git a/lisp/gnus/nnmaildir.el b/lisp/gnus/nnmaildir.el
index 827eafdc7ed..b79e7103cef 100644
--- a/lisp/gnus/nnmaildir.el
+++ b/lisp/gnus/nnmaildir.el
@@ -208,20 +208,16 @@ by nnmaildir-request-article.")
208 (eval param)) 208 (eval param))
209 209
210(defmacro nnmaildir--with-nntp-buffer (&rest body) 210(defmacro nnmaildir--with-nntp-buffer (&rest body)
211 `(save-excursion 211 `(with-current-buffer nntp-server-buffer
212 (set-buffer nntp-server-buffer)
213 ,@body)) 212 ,@body))
214(defmacro nnmaildir--with-work-buffer (&rest body) 213(defmacro nnmaildir--with-work-buffer (&rest body)
215 `(save-excursion 214 `(with-current-buffer (get-buffer-create " *nnmaildir work*")
216 (set-buffer (get-buffer-create " *nnmaildir work*"))
217 ,@body)) 215 ,@body))
218(defmacro nnmaildir--with-nov-buffer (&rest body) 216(defmacro nnmaildir--with-nov-buffer (&rest body)
219 `(save-excursion 217 `(with-current-buffer (get-buffer-create " *nnmaildir nov*")
220 (set-buffer (get-buffer-create " *nnmaildir nov*"))
221 ,@body)) 218 ,@body))
222(defmacro nnmaildir--with-move-buffer (&rest body) 219(defmacro nnmaildir--with-move-buffer (&rest body)
223 `(save-excursion 220 `(with-current-buffer (get-buffer-create " *nnmaildir move*")
224 (set-buffer (get-buffer-create " *nnmaildir move*"))
225 ,@body)) 221 ,@body))
226 222
227(defmacro nnmaildir--subdir (dir subdir) 223(defmacro nnmaildir--subdir (dir subdir)
@@ -1249,8 +1245,7 @@ by nnmaildir-request-article.")
1249 (setf (nnmaildir--srv-error nnmaildir--cur-server) 1245 (setf (nnmaildir--srv-error nnmaildir--cur-server)
1250 "Article has expired") 1246 "Article has expired")
1251 (throw 'return nil)) 1247 (throw 'return nil))
1252 (save-excursion 1248 (with-current-buffer (or to-buffer nntp-server-buffer)
1253 (set-buffer (or to-buffer nntp-server-buffer))
1254 (erase-buffer) 1249 (erase-buffer)
1255 (nnheader-insert-file-contents nnmaildir-article-file-name)) 1250 (nnheader-insert-file-contents nnmaildir-article-file-name))
1256 (cons gname num-msgid)))) 1251 (cons gname num-msgid))))
@@ -1289,8 +1284,7 @@ by nnmaildir-request-article.")
1289 (setf (nnmaildir--srv-error nnmaildir--cur-server) 1284 (setf (nnmaildir--srv-error nnmaildir--cur-server)
1290 (concat "File exists: " tmpfile)) 1285 (concat "File exists: " tmpfile))
1291 (throw 'return nil)) 1286 (throw 'return nil))
1292 (save-excursion 1287 (with-current-buffer buffer
1293 (set-buffer buffer)
1294 (gmm-write-region (point-min) (point-max) tmpfile nil 'no-message nil 1288 (gmm-write-region (point-min) (point-max) tmpfile nil 'no-message nil
1295 'excl)) 1289 'excl))
1296 (unix-sync) ;; no fsync :( 1290 (unix-sync) ;; no fsync :(
diff --git a/lisp/gnus/nnmairix.el b/lisp/gnus/nnmairix.el
index 04db76b942a..b43a83e3a33 100644
--- a/lisp/gnus/nnmairix.el
+++ b/lisp/gnus/nnmairix.el
@@ -445,8 +445,7 @@ Other back ends might or might not work.")
445 nil) 445 nil)
446 ((not query) 446 ((not query)
447 ;; No query -> return empty group 447 ;; No query -> return empty group
448 (save-excursion 448 (with-current-buffer nntp-server-buffer
449 (set-buffer nntp-server-buffer)
450 (erase-buffer) 449 (erase-buffer)
451 (insert (concat "211 0 1 0 " group)) 450 (insert (concat "211 0 1 0 " group))
452 t)) 451 t))
@@ -501,9 +500,9 @@ Other back ends might or might not work.")
501 (nnmairix-request-group-with-article-number-correction 500 (nnmairix-request-group-with-article-number-correction
502 folder qualgroup))) 501 folder qualgroup)))
503 ((and (= rval 1) 502 ((and (= rval 1)
504 (save-excursion (set-buffer nnmairix-mairix-output-buffer) 503 (with-current-buffer nnmairix-mairix-output-buffer
505 (goto-char (point-min)) 504 (goto-char (point-min))
506 (looking-at "^Matched 0 messages"))) 505 (looking-at "^Matched 0 messages")))
507 ;; No messages found -> return empty group 506 ;; No messages found -> return empty group
508 (nnheader-message 5 "Mairix: No matches found.") 507 (nnheader-message 5 "Mairix: No matches found.")
509 (set-buffer nntp-server-buffer) 508 (set-buffer nntp-server-buffer)
@@ -584,8 +583,7 @@ Other back ends might or might not work.")
584 (when server (nnmairix-open-server server)) 583 (when server (nnmairix-open-server server))
585 (if (nnmairix-call-backend "request-list" nnmairix-backend-server) 584 (if (nnmairix-call-backend "request-list" nnmairix-backend-server)
586 (let (cpoint cur qualgroup folder) 585 (let (cpoint cur qualgroup folder)
587 (save-excursion 586 (with-current-buffer nntp-server-buffer
588 (set-buffer nntp-server-buffer)
589 (goto-char (point-min)) 587 (goto-char (point-min))
590 (setq cpoint (point)) 588 (setq cpoint (point))
591 (while (re-search-forward nnmairix-group-regexp (point-max) t) 589 (while (re-search-forward nnmairix-group-regexp (point-max) t)
@@ -699,8 +697,7 @@ Other back ends might or might not work.")
699 (when (or (eq nnmairix-propagate-marks-upon-close t) 697 (when (or (eq nnmairix-propagate-marks-upon-close t)
700 (and (eq nnmairix-propagate-marks-upon-close 'ask) 698 (and (eq nnmairix-propagate-marks-upon-close 'ask)
701 (y-or-n-p "Propagate marks to original articles? "))) 699 (y-or-n-p "Propagate marks to original articles? ")))
702 (save-excursion 700 (with-current-buffer gnus-group-buffer
703 (set-buffer gnus-group-buffer)
704 (nnmairix-propagate-marks) 701 (nnmairix-propagate-marks)
705 ;; update mairix group 702 ;; update mairix group
706 (gnus-group-jump-to-group qualgroup) 703 (gnus-group-jump-to-group qualgroup)
@@ -998,8 +995,7 @@ with m:msgid of the current article and enabled threads."
998 (if server 995 (if server
999 (if (gnus-buffer-live-p gnus-article-buffer) 996 (if (gnus-buffer-live-p gnus-article-buffer)
1000 (progn 997 (progn
1001 (save-excursion 998 (with-current-buffer gnus-article-buffer
1002 (set-buffer gnus-article-buffer)
1003 (gnus-summary-toggle-header 1) 999 (gnus-summary-toggle-header 1)
1004 (setq mid (message-fetch-field "Message-ID"))) 1000 (setq mid (message-fetch-field "Message-ID")))
1005 (while (string-match "[<>]" mid) 1001 (while (string-match "[<>]" mid)
@@ -1021,8 +1017,7 @@ f:current_from."
1021 (if server 1017 (if server
1022 (if (gnus-buffer-live-p gnus-article-buffer) 1018 (if (gnus-buffer-live-p gnus-article-buffer)
1023 (progn 1019 (progn
1024 (save-excursion 1020 (with-current-buffer gnus-article-buffer
1025 (set-buffer gnus-article-buffer)
1026 (gnus-summary-toggle-header 1) 1021 (gnus-summary-toggle-header 1)
1027 (setq from (cadr (gnus-extract-address-components 1022 (setq from (cadr (gnus-extract-address-components
1028 (gnus-fetch-field "From")))) 1023 (gnus-fetch-field "From"))))
@@ -1046,8 +1041,7 @@ before deleting a group on the back end. SERVER specifies nnmairix server."
1046 (when (nnmairix-call-backend 1041 (when (nnmairix-call-backend
1047 "request-list" nnmairix-backend-server) 1042 "request-list" nnmairix-backend-server)
1048 (let (cur qualgroup folder) 1043 (let (cur qualgroup folder)
1049 (save-excursion 1044 (with-current-buffer nntp-server-buffer
1050 (set-buffer nntp-server-buffer)
1051 (goto-char (point-min)) 1045 (goto-char (point-min))
1052 (while (re-search-forward nnmairix-group-regexp (point-max) t) 1046 (while (re-search-forward nnmairix-group-regexp (point-max) t)
1053 (setq cur (match-string 0) 1047 (setq cur (match-string 0)
@@ -1152,8 +1146,7 @@ nnmairix server. Only marks from current session will be set."
1152 (push (list (car ogroup) (list (list number) (nth 1 mid-marks) (nth 2 mid-marks))) 1146 (push (list (car ogroup) (list (list number) (nth 1 mid-marks) (nth 2 mid-marks)))
1153 number-cache))))) 1147 number-cache)))))
1154 ;; now we set the marks 1148 ;; now we set the marks
1155 (save-excursion 1149 (with-current-buffer gnus-group-buffer
1156 (set-buffer gnus-group-buffer)
1157 (nnheader-message 5 "nnmairix: Propagating marks...") 1150 (nnheader-message 5 "nnmairix: Propagating marks...")
1158 (dolist (cur number-cache) 1151 (dolist (cur number-cache)
1159 (setq method (gnus-find-method-for-group (car cur))) 1152 (setq method (gnus-find-method-for-group (car cur)))
@@ -1272,9 +1265,8 @@ Marks propagation has to be enabled for this to work."
1272 "Call mairix binary with COMMAND, using FOLDER and SEARCHQUERY. 1265 "Call mairix binary with COMMAND, using FOLDER and SEARCHQUERY.
1273If THREADS is non-nil, enable full threads." 1266If THREADS is non-nil, enable full threads."
1274 (let ((args (cons (car command) '(nil t nil)))) 1267 (let ((args (cons (car command) '(nil t nil))))
1275 (save-excursion 1268 (with-current-buffer
1276 (set-buffer 1269 (get-buffer-create nnmairix-mairix-output-buffer)
1277 (get-buffer-create nnmairix-mairix-output-buffer))
1278 (erase-buffer) 1270 (erase-buffer)
1279 (when (> (length command) 1) 1271 (when (> (length command) 1)
1280 (setq args (append args (cdr command)))) 1272 (setq args (append args (cdr command))))
@@ -1291,9 +1283,8 @@ If THREADS is non-nil, enable full threads."
1291(defun nnmairix-call-mairix-binary-raw (command query) 1283(defun nnmairix-call-mairix-binary-raw (command query)
1292 "Call mairix binary with COMMAND and QUERY in raw mode." 1284 "Call mairix binary with COMMAND and QUERY in raw mode."
1293 (let ((args (cons (car command) '(nil t nil)))) 1285 (let ((args (cons (car command) '(nil t nil))))
1294 (save-excursion 1286 (with-current-buffer
1295 (set-buffer 1287 (get-buffer-create nnmairix-mairix-output-buffer)
1296 (get-buffer-create nnmairix-mairix-output-buffer))
1297 (erase-buffer) 1288 (erase-buffer)
1298 (when (> (length command) 1) 1289 (when (> (length command) 1)
1299 (setq args (append args (cdr command)))) 1290 (setq args (append args (cdr command))))
@@ -1430,8 +1421,7 @@ MAIRIXGROUP. NUMC contains values for article number correction."
1430 (corr (not (zerop numc))) 1421 (corr (not (zerop numc)))
1431 (name (buffer-name nntp-server-buffer)) 1422 (name (buffer-name nntp-server-buffer))
1432 header cur xref) 1423 header cur xref)
1433 (save-excursion 1424 (with-current-buffer buf
1434 (set-buffer buf)
1435 (erase-buffer) 1425 (erase-buffer)
1436 (set-buffer nntp-server-buffer) 1426 (set-buffer nntp-server-buffer)
1437 (goto-char (point-min)) 1427 (goto-char (point-min))
@@ -1621,8 +1611,7 @@ search in raw mode."
1621 (let ((server (nth 1 gnus-current-select-method)) 1611 (let ((server (nth 1 gnus-current-select-method))
1622 mid rval group allgroups) 1612 mid rval group allgroups)
1623 ;; get message id 1613 ;; get message id
1624 (save-excursion 1614 (with-current-buffer gnus-article-buffer
1625 (set-buffer gnus-article-buffer)
1626 (gnus-summary-toggle-header 1) 1615 (gnus-summary-toggle-header 1)
1627 (setq mid (message-fetch-field "Message-ID")) 1616 (setq mid (message-fetch-field "Message-ID"))
1628 ;; first check the registry (if available) 1617 ;; first check the registry (if available)
@@ -1678,8 +1667,7 @@ SERVER."
1678 (if (zerop (nnmairix-call-mairix-binary-raw 1667 (if (zerop (nnmairix-call-mairix-binary-raw
1679 (split-string nnmairix-mairix-command) 1668 (split-string nnmairix-mairix-command)
1680 (list (concat "m:" mid)))) 1669 (list (concat "m:" mid))))
1681 (save-excursion 1670 (with-current-buffer nnmairix-mairix-output-buffer
1682 (set-buffer nnmairix-mairix-output-buffer)
1683 (goto-char (point-min)) 1671 (goto-char (point-min))
1684 (while (re-search-forward "^/.*$" nil t) 1672 (while (re-search-forward "^/.*$" nil t)
1685 (push (nnmairix-get-group-from-file-path (match-string 0)) 1673 (push (nnmairix-get-group-from-file-path (match-string 0))
diff --git a/lisp/gnus/nnmbox.el b/lisp/gnus/nnmbox.el
index 7d71dc1c1e4..4b01bfa5c6e 100644
--- a/lisp/gnus/nnmbox.el
+++ b/lisp/gnus/nnmbox.el
@@ -79,8 +79,7 @@
79(nnoo-define-basics nnmbox) 79(nnoo-define-basics nnmbox)
80 80
81(deffoo nnmbox-retrieve-headers (sequence &optional newsgroup server fetch-old) 81(deffoo nnmbox-retrieve-headers (sequence &optional newsgroup server fetch-old)
82 (save-excursion 82 (with-current-buffer nntp-server-buffer
83 (set-buffer nntp-server-buffer)
84 (erase-buffer) 83 (erase-buffer)
85 (let ((number (length sequence)) 84 (let ((number (length sequence))
86 (count 0) 85 (count 0)
@@ -149,8 +148,7 @@
149 148
150(deffoo nnmbox-request-article (article &optional newsgroup server buffer) 149(deffoo nnmbox-request-article (article &optional newsgroup server buffer)
151 (nnmbox-possibly-change-newsgroup newsgroup server) 150 (nnmbox-possibly-change-newsgroup newsgroup server)
152 (save-excursion 151 (with-current-buffer nnmbox-mbox-buffer
153 (set-buffer nnmbox-mbox-buffer)
154 (when (nnmbox-find-article article) 152 (when (nnmbox-find-article article)
155 (let (start stop) 153 (let (start stop)
156 (re-search-backward (concat "^" message-unix-mail-delimiter) nil t) 154 (re-search-backward (concat "^" message-unix-mail-delimiter) nil t)
@@ -208,8 +206,7 @@
208 (nnmail-get-new-mail 206 (nnmail-get-new-mail
209 'nnmbox 207 'nnmbox
210 (lambda () 208 (lambda ()
211 (save-excursion 209 (with-current-buffer nnmbox-mbox-buffer
212 (set-buffer nnmbox-mbox-buffer)
213 (nnmbox-save-buffer))) 210 (nnmbox-save-buffer)))
214 (file-name-directory nnmbox-mbox-file) 211 (file-name-directory nnmbox-mbox-file)
215 group 212 group
@@ -253,8 +250,7 @@
253 rest) 250 rest)
254 (nnmail-activate 'nnmbox) 251 (nnmail-activate 'nnmbox)
255 252
256 (save-excursion 253 (with-current-buffer nnmbox-mbox-buffer
257 (set-buffer nnmbox-mbox-buffer)
258 (while (and articles is-old) 254 (while (and articles is-old)
259 (when (nnmbox-find-article (car articles)) 255 (when (nnmbox-find-article (car articles))
260 (if (setq is-old 256 (if (setq is-old
@@ -292,8 +288,7 @@
292 result) 288 result)
293 (and 289 (and
294 (nnmbox-request-article article group server) 290 (nnmbox-request-article article group server)
295 (save-excursion 291 (with-current-buffer buf
296 (set-buffer buf)
297 (erase-buffer) 292 (erase-buffer)
298 (insert-buffer-substring nntp-server-buffer) 293 (insert-buffer-substring nntp-server-buffer)
299 (goto-char (point-min)) 294 (goto-char (point-min))
@@ -364,8 +359,7 @@
364 359
365(deffoo nnmbox-request-replace-article (article group buffer) 360(deffoo nnmbox-request-replace-article (article group buffer)
366 (nnmbox-possibly-change-newsgroup group) 361 (nnmbox-possibly-change-newsgroup group)
367 (save-excursion 362 (with-current-buffer nnmbox-mbox-buffer
368 (set-buffer nnmbox-mbox-buffer)
369 (if (not (nnmbox-find-article article)) 363 (if (not (nnmbox-find-article article))
370 nil 364 nil
371 (nnmbox-delete-mail t t) 365 (nnmbox-delete-mail t t)
@@ -391,8 +385,7 @@
391 ;; Delete all articles in GROUP. 385 ;; Delete all articles in GROUP.
392 (if (not force) 386 (if (not force)
393 () ; Don't delete the articles. 387 () ; Don't delete the articles.
394 (save-excursion 388 (with-current-buffer nnmbox-mbox-buffer
395 (set-buffer nnmbox-mbox-buffer)
396 (goto-char (point-min)) 389 (goto-char (point-min))
397 ;; Delete all articles in this group. 390 ;; Delete all articles in this group.
398 (let ((ident (concat "\nX-Gnus-Newsgroup: " nnmbox-current-group ":")) 391 (let ((ident (concat "\nX-Gnus-Newsgroup: " nnmbox-current-group ":"))
@@ -412,8 +405,7 @@
412 405
413(deffoo nnmbox-request-rename-group (group new-name &optional server) 406(deffoo nnmbox-request-rename-group (group new-name &optional server)
414 (nnmbox-possibly-change-newsgroup group server) 407 (nnmbox-possibly-change-newsgroup group server)
415 (save-excursion 408 (with-current-buffer nnmbox-mbox-buffer
416 (set-buffer nnmbox-mbox-buffer)
417 (goto-char (point-min)) 409 (goto-char (point-min))
418 (let ((ident (concat "\nX-Gnus-Newsgroup: " nnmbox-current-group ":")) 410 (let ((ident (concat "\nX-Gnus-Newsgroup: " nnmbox-current-group ":"))
419 (new-ident (concat "\nX-Gnus-Newsgroup: " new-name ":")) 411 (new-ident (concat "\nX-Gnus-Newsgroup: " new-name ":"))
@@ -633,8 +625,7 @@
633 (nnmbox-create-mbox) 625 (nnmbox-create-mbox)
634 (if (and nnmbox-mbox-buffer 626 (if (and nnmbox-mbox-buffer
635 (buffer-name nnmbox-mbox-buffer) 627 (buffer-name nnmbox-mbox-buffer)
636 (save-excursion 628 (with-current-buffer nnmbox-mbox-buffer
637 (set-buffer nnmbox-mbox-buffer)
638 (= (buffer-size) (nnheader-file-size nnmbox-mbox-file)))) 629 (= (buffer-size) (nnheader-file-size nnmbox-mbox-file))))
639 () 630 ()
640 (save-excursion 631 (save-excursion
diff --git a/lisp/gnus/nnml.el b/lisp/gnus/nnml.el
index 6d676bb8514..5d62192819e 100644
--- a/lisp/gnus/nnml.el
+++ b/lisp/gnus/nnml.el
@@ -160,8 +160,7 @@ non-nil.")
160 160
161(deffoo nnml-retrieve-headers (sequence &optional group server fetch-old) 161(deffoo nnml-retrieve-headers (sequence &optional group server fetch-old)
162 (when (nnml-possibly-change-directory group server) 162 (when (nnml-possibly-change-directory group server)
163 (save-excursion 163 (with-current-buffer nntp-server-buffer
164 (set-buffer nntp-server-buffer)
165 (erase-buffer) 164 (erase-buffer)
166 (let* ((file nil) 165 (let* ((file nil)
167 (number (length sequence)) 166 (number (length sequence))
@@ -405,8 +404,7 @@ non-nil.")
405 (let (nnml-current-directory 404 (let (nnml-current-directory
406 nnml-current-group 405 nnml-current-group
407 nnml-article-file-alist) 406 nnml-article-file-alist)
408 (save-excursion 407 (with-current-buffer buf
409 (set-buffer buf)
410 (insert-buffer-substring nntp-server-buffer) 408 (insert-buffer-substring nntp-server-buffer)
411 (setq result (eval accept-form)) 409 (setq result (eval accept-form))
412 (kill-buffer (current-buffer)) 410 (kill-buffer (current-buffer))
@@ -462,8 +460,7 @@ non-nil.")
462 460
463(deffoo nnml-request-replace-article (article group buffer) 461(deffoo nnml-request-replace-article (article group buffer)
464 (nnml-possibly-change-directory group) 462 (nnml-possibly-change-directory group)
465 (save-excursion 463 (with-current-buffer buffer
466 (set-buffer buffer)
467 (nnml-possibly-create-directory group) 464 (nnml-possibly-create-directory group)
468 (let ((chars (nnmail-insert-lines)) 465 (let ((chars (nnmail-insert-lines))
469 (art (concat (int-to-string article) "\t")) 466 (art (concat (int-to-string article) "\t"))
@@ -478,8 +475,7 @@ non-nil.")
478 t) 475 t)
479 (setq headers (nnml-parse-head chars article)) 476 (setq headers (nnml-parse-head chars article))
480 ;; Replace the NOV line in the NOV file. 477 ;; Replace the NOV line in the NOV file.
481 (save-excursion 478 (with-current-buffer (nnml-open-nov group)
482 (set-buffer (nnml-open-nov group))
483 (goto-char (point-min)) 479 (goto-char (point-min))
484 (if (or (looking-at art) 480 (if (or (looking-at art)
485 (search-forward (concat "\n" art) nil t)) 481 (search-forward (concat "\n" art) nil t))
@@ -614,8 +610,7 @@ non-nil.")
614 610
615;; Find an article number in the current group given the Message-ID. 611;; Find an article number in the current group given the Message-ID.
616(defun nnml-find-group-number (id server) 612(defun nnml-find-group-number (id server)
617 (save-excursion 613 (with-current-buffer (get-buffer-create " *nnml id*")
618 (set-buffer (get-buffer-create " *nnml id*"))
619 (let ((alist nnml-group-alist) 614 (let ((alist nnml-group-alist)
620 number) 615 number)
621 ;; We want to look through all .overview files, but we want to 616 ;; We want to look through all .overview files, but we want to
@@ -657,8 +652,7 @@ non-nil.")
657 nil 652 nil
658 (let ((nov (expand-file-name nnml-nov-file-name nnml-current-directory))) 653 (let ((nov (expand-file-name nnml-nov-file-name nnml-current-directory)))
659 (when (file-exists-p nov) 654 (when (file-exists-p nov)
660 (save-excursion 655 (with-current-buffer nntp-server-buffer
661 (set-buffer nntp-server-buffer)
662 (erase-buffer) 656 (erase-buffer)
663 (nnheader-insert-file-contents nov) 657 (nnheader-insert-file-contents nov)
664 (if (and fetch-old 658 (if (and fetch-old
@@ -804,16 +798,14 @@ article number. This function is called narrowed to an article."
804 798
805(defun nnml-add-incremental-nov (group article headers) 799(defun nnml-add-incremental-nov (group article headers)
806 "Add a nov line for the GROUP nov headers, incrementally." 800 "Add a nov line for the GROUP nov headers, incrementally."
807 (save-excursion 801 (with-current-buffer (nnml-open-incremental-nov group)
808 (set-buffer (nnml-open-incremental-nov group))
809 (goto-char (point-max)) 802 (goto-char (point-max))
810 (mail-header-set-number headers article) 803 (mail-header-set-number headers article)
811 (nnheader-insert-nov headers))) 804 (nnheader-insert-nov headers)))
812 805
813(defun nnml-add-nov (group article headers) 806(defun nnml-add-nov (group article headers)
814 "Add a nov line for the GROUP base." 807 "Add a nov line for the GROUP base."
815 (save-excursion 808 (with-current-buffer (nnml-open-nov group)
816 (set-buffer (nnml-open-nov group))
817 (goto-char (point-max)) 809 (goto-char (point-max))
818 (mail-header-set-number headers article) 810 (mail-header-set-number headers article)
819 (nnheader-insert-nov headers))) 811 (nnheader-insert-nov headers)))
@@ -844,8 +836,7 @@ article number. This function is called narrowed to an article."
844 "") 836 "")
845 decoded))) 837 decoded)))
846 (file-name-coding-system nnmail-pathname-coding-system)) 838 (file-name-coding-system nnmail-pathname-coding-system))
847 (save-excursion 839 (with-current-buffer buffer
848 (set-buffer buffer)
849 (set (make-local-variable 'nnml-nov-buffer-file-name) 840 (set (make-local-variable 'nnml-nov-buffer-file-name)
850 (nnmail-group-pathname decoded nnml-directory nnml-nov-file-name)) 841 (nnmail-group-pathname decoded nnml-directory nnml-nov-file-name))
851 (erase-buffer) 842 (erase-buffer)
@@ -942,9 +933,8 @@ Unless no-active is non-nil, update the active file too."
942 (nov (concat dir nnml-nov-file-name)) 933 (nov (concat dir nnml-nov-file-name))
943 (nov-buffer (get-buffer-create " *nov*")) 934 (nov-buffer (get-buffer-create " *nov*"))
944 chars file headers) 935 chars file headers)
945 (save-excursion 936 (with-current-buffer nov-buffer
946 ;; Init the nov buffer. 937 ;; Init the nov buffer.
947 (set-buffer nov-buffer)
948 (buffer-disable-undo) 938 (buffer-disable-undo)
949 (erase-buffer) 939 (erase-buffer)
950 (set-buffer nntp-server-buffer) 940 (set-buffer nntp-server-buffer)
@@ -964,20 +954,17 @@ Unless no-active is non-nil, update the active file too."
964 (unless (zerop (buffer-size)) 954 (unless (zerop (buffer-size))
965 (goto-char (point-min)) 955 (goto-char (point-min))
966 (setq headers (nnml-parse-head chars (caar files))) 956 (setq headers (nnml-parse-head chars (caar files)))
967 (save-excursion 957 (with-current-buffer nov-buffer
968 (set-buffer nov-buffer)
969 (goto-char (point-max)) 958 (goto-char (point-max))
970 (nnheader-insert-nov headers))) 959 (nnheader-insert-nov headers)))
971 (widen)) 960 (widen))
972 (setq files (cdr files))) 961 (setq files (cdr files)))
973 (save-excursion 962 (with-current-buffer nov-buffer
974 (set-buffer nov-buffer)
975 (nnmail-write-region (point-min) (point-max) nov nil 'nomesg) 963 (nnmail-write-region (point-min) (point-max) nov nil 'nomesg)
976 (kill-buffer (current-buffer)))))) 964 (kill-buffer (current-buffer))))))
977 965
978(defun nnml-nov-delete-article (group article) 966(defun nnml-nov-delete-article (group article)
979 (save-excursion 967 (with-current-buffer (nnml-open-nov group)
980 (set-buffer (nnml-open-nov group))
981 (when (nnheader-find-nov-line article) 968 (when (nnheader-find-nov-line article)
982 (delete-region (point) (progn (forward-line 1) (point))) 969 (delete-region (point) (progn (forward-line 1) (point)))
983 (when (bobp) 970 (when (bobp)
@@ -1260,8 +1247,7 @@ Use the nov database for the current group if available."
1260 (gnus-info-set-marks info newmarks)) 1247 (gnus-info-set-marks info newmarks))
1261 ;; 3/ Update the NOV entry for this article: 1248 ;; 3/ Update the NOV entry for this article:
1262 (unless nnml-nov-is-evil 1249 (unless nnml-nov-is-evil
1263 (save-excursion 1250 (with-current-buffer (nnml-open-nov group)
1264 (set-buffer (nnml-open-nov group))
1265 (when (nnheader-find-nov-line old-number) 1251 (when (nnheader-find-nov-line old-number)
1266 ;; Replace the article number: 1252 ;; Replace the article number:
1267 (looking-at old-number-string) 1253 (looking-at old-number-string)
diff --git a/lisp/gnus/nnnil.el b/lisp/gnus/nnnil.el
index f6bc35aec3c..dd5e9841c15 100644
--- a/lisp/gnus/nnnil.el
+++ b/lisp/gnus/nnnil.el
@@ -58,8 +58,7 @@
58 58
59(defun nnnil-request-group (group &optional server fast) 59(defun nnnil-request-group (group &optional server fast)
60 (let (deactivate-mark) 60 (let (deactivate-mark)
61 (save-excursion 61 (with-current-buffer nntp-server-buffer
62 (set-buffer nntp-server-buffer)
63 (erase-buffer) 62 (erase-buffer)
64 (insert "411 no such news group\n"))) 63 (insert "411 no such news group\n")))
65 (setq nnnil-status-string "No such group") 64 (setq nnnil-status-string "No such group")
diff --git a/lisp/gnus/nnspool.el b/lisp/gnus/nnspool.el
index cdf2b829ecc..ee1e36f55c7 100644
--- a/lisp/gnus/nnspool.el
+++ b/lisp/gnus/nnspool.el
@@ -109,8 +109,7 @@ there.")
109 109
110(deffoo nnspool-retrieve-headers (articles &optional group server fetch-old) 110(deffoo nnspool-retrieve-headers (articles &optional group server fetch-old)
111 "Retrieve the headers of ARTICLES." 111 "Retrieve the headers of ARTICLES."
112 (save-excursion 112 (with-current-buffer nntp-server-buffer
113 (set-buffer nntp-server-buffer)
114 (erase-buffer) 113 (erase-buffer)
115 (when (nnspool-possibly-change-directory group) 114 (when (nnspool-possibly-change-directory group)
116 (let* ((number (length articles)) 115 (let* ((number (length articles))
@@ -209,8 +208,7 @@ there.")
209 (nnspool-possibly-change-directory group) 208 (nnspool-possibly-change-directory group)
210 (let ((res (nnspool-request-article id))) 209 (let ((res (nnspool-request-article id)))
211 (when res 210 (when res
212 (save-excursion 211 (with-current-buffer nntp-server-buffer
213 (set-buffer nntp-server-buffer)
214 (goto-char (point-min)) 212 (goto-char (point-min))
215 (when (search-forward "\n\n" nil t) 213 (when (search-forward "\n\n" nil t)
216 (delete-region (point-min) (point))) 214 (delete-region (point-min) (point)))
@@ -221,8 +219,7 @@ there.")
221 (nnspool-possibly-change-directory group) 219 (nnspool-possibly-change-directory group)
222 (let ((res (nnspool-request-article id))) 220 (let ((res (nnspool-request-article id)))
223 (when res 221 (when res
224 (save-excursion 222 (with-current-buffer nntp-server-buffer
225 (set-buffer nntp-server-buffer)
226 (goto-char (point-min)) 223 (goto-char (point-min))
227 (when (search-forward "\n\n" nil t) 224 (when (search-forward "\n\n" nil t)
228 (delete-region (1- (point)) (point-max))) 225 (delete-region (1- (point)) (point-max)))
@@ -343,8 +340,7 @@ there.")
343;;; Internal functions. 340;;; Internal functions.
344 341
345(defun nnspool-inews-sentinel (proc status) 342(defun nnspool-inews-sentinel (proc status)
346 (save-excursion 343 (with-current-buffer (process-buffer proc)
347 (set-buffer (process-buffer proc))
348 (goto-char (point-min)) 344 (goto-char (point-min))
349 (if (or (zerop (buffer-size)) 345 (if (or (zerop (buffer-size))
350 (search-forward "spooled" nil t)) 346 (search-forward "spooled" nil t))
@@ -367,8 +363,7 @@ there.")
367 last) 363 last)
368 (if (not (file-exists-p nov)) 364 (if (not (file-exists-p nov))
369 () 365 ()
370 (save-excursion 366 (with-current-buffer nntp-server-buffer
371 (set-buffer nntp-server-buffer)
372 (erase-buffer) 367 (erase-buffer)
373 (if nnspool-sift-nov-with-sed 368 (if nnspool-sift-nov-with-sed
374 (nnspool-sift-nov-with-sed articles nov) 369 (nnspool-sift-nov-with-sed articles nov)
diff --git a/lisp/gnus/nntp.el b/lisp/gnus/nntp.el
index 3cdd63084ef..59f803d8c6a 100644
--- a/lisp/gnus/nntp.el
+++ b/lisp/gnus/nntp.el
@@ -1014,7 +1014,8 @@ command whose response triggered the error."
1014 (unless (assq 'nntp-address defs) 1014 (unless (assq 'nntp-address defs)
1015 (setq defs (append defs (list (list 'nntp-address server))))) 1015 (setq defs (append defs (list (list 'nntp-address server)))))
1016 (nnoo-change-server 'nntp server defs) 1016 (nnoo-change-server 'nntp server defs)
1017 (unless connectionless 1017 (if connectionless
1018 t
1018 (or (nntp-find-connection nntp-server-buffer) 1019 (or (nntp-find-connection nntp-server-buffer)
1019 (nntp-open-connection nntp-server-buffer))))) 1020 (nntp-open-connection nntp-server-buffer)))))
1020 1021
diff --git a/lisp/gnus/nnvirtual.el b/lisp/gnus/nnvirtual.el
index c94d1837fa9..18faa23a80e 100644
--- a/lisp/gnus/nnvirtual.el
+++ b/lisp/gnus/nnvirtual.el
@@ -93,8 +93,7 @@ component group will show up when you enter the virtual group.")
93(deffoo nnvirtual-retrieve-headers (articles &optional newsgroup 93(deffoo nnvirtual-retrieve-headers (articles &optional newsgroup
94 server fetch-old) 94 server fetch-old)
95 (when (nnvirtual-possibly-change-server server) 95 (when (nnvirtual-possibly-change-server server)
96 (save-excursion 96 (with-current-buffer nntp-server-buffer
97 (set-buffer nntp-server-buffer)
98 (erase-buffer) 97 (erase-buffer)
99 (if (stringp (car articles)) 98 (if (stringp (car articles))
100 'headers 99 'headers
@@ -170,8 +169,7 @@ component group will show up when you enter the virtual group.")
170 ;; the nntp-server-buffer, which is where Gnus expects to find 169 ;; the nntp-server-buffer, which is where Gnus expects to find
171 ;; them. 170 ;; them.
172 (prog1 171 (prog1
173 (save-excursion 172 (with-current-buffer nntp-server-buffer
174 (set-buffer nntp-server-buffer)
175 (erase-buffer) 173 (erase-buffer)
176 (insert-buffer-substring vbuf) 174 (insert-buffer-substring vbuf)
177 ;; FIX FIX FIX, we should be able to sort faster than 175 ;; FIX FIX FIX, we should be able to sort faster than
@@ -215,8 +213,7 @@ component group will show up when you enter the virtual group.")
215 (t 213 (t
216 (setq nnvirtual-last-accessed-component-group cgroup) 214 (setq nnvirtual-last-accessed-component-group cgroup)
217 (if buffer 215 (if buffer
218 (save-excursion 216 (with-current-buffer buffer
219 (set-buffer buffer)
220 ;; We bind this here to avoid double decoding. 217 ;; We bind this here to avoid double decoding.
221 (let ((gnus-article-decode-hook nil)) 218 (let ((gnus-article-decode-hook nil))
222 (gnus-request-article-this-buffer (cdr amap) cgroup))) 219 (gnus-request-article-this-buffer (cdr amap) cgroup)))
@@ -335,8 +332,7 @@ component group will show up when you enter the virtual group.")
335 (when (not (numberp (gnus-group-unread g))) 332 (when (not (numberp (gnus-group-unread g)))
336 (gnus-activate-group g))) 333 (gnus-activate-group g)))
337 nnvirtual-component-groups) 334 nnvirtual-component-groups)
338 (save-excursion 335 (with-current-buffer gnus-group-buffer
339 (set-buffer gnus-group-buffer)
340 (gnus-group-catchup-current nil all))))) 336 (gnus-group-catchup-current nil all)))))
341 337
342 338
diff --git a/lisp/gnus/nnweb.el b/lisp/gnus/nnweb.el
index 3b4f71c80aa..e6289c57bca 100644
--- a/lisp/gnus/nnweb.el
+++ b/lisp/gnus/nnweb.el
@@ -104,8 +104,7 @@ Valid types include `google', `dejanews', and `gmane'.")
104 104
105(deffoo nnweb-retrieve-headers (articles &optional group server fetch-old) 105(deffoo nnweb-retrieve-headers (articles &optional group server fetch-old)
106 (nnweb-possibly-change-server group server) 106 (nnweb-possibly-change-server group server)
107 (save-excursion 107 (with-current-buffer nntp-server-buffer
108 (set-buffer nntp-server-buffer)
109 (erase-buffer) 108 (erase-buffer)
110 (let (article header) 109 (let (article header)
111 (mm-with-unibyte-current-buffer 110 (mm-with-unibyte-current-buffer
@@ -147,16 +146,14 @@ Valid types include `google', `dejanews', and `gmane'.")
147(deffoo nnweb-close-group (group &optional server) 146(deffoo nnweb-close-group (group &optional server)
148 (nnweb-possibly-change-server group server) 147 (nnweb-possibly-change-server group server)
149 (when (gnus-buffer-live-p nnweb-buffer) 148 (when (gnus-buffer-live-p nnweb-buffer)
150 (save-excursion 149 (with-current-buffer nnweb-buffer
151 (set-buffer nnweb-buffer)
152 (set-buffer-modified-p nil) 150 (set-buffer-modified-p nil)
153 (kill-buffer nnweb-buffer))) 151 (kill-buffer nnweb-buffer)))
154 t) 152 t)
155 153
156(deffoo nnweb-request-article (article &optional group server buffer) 154(deffoo nnweb-request-article (article &optional group server buffer)
157 (nnweb-possibly-change-server group server) 155 (nnweb-possibly-change-server group server)
158 (save-excursion 156 (with-current-buffer (or buffer nntp-server-buffer)
159 (set-buffer (or buffer nntp-server-buffer))
160 (let* ((header (cadr (assq article nnweb-articles))) 157 (let* ((header (cadr (assq article nnweb-articles)))
161 (url (and header (mail-header-xref header)))) 158 (url (and header (mail-header-xref header))))
162 (when (or (and url 159 (when (or (and url
@@ -185,16 +182,14 @@ Valid types include `google', `dejanews', and `gmane'.")
185(deffoo nnweb-close-server (&optional server) 182(deffoo nnweb-close-server (&optional server)
186 (when (and (nnweb-server-opened server) 183 (when (and (nnweb-server-opened server)
187 (gnus-buffer-live-p nnweb-buffer)) 184 (gnus-buffer-live-p nnweb-buffer))
188 (save-excursion 185 (with-current-buffer nnweb-buffer
189 (set-buffer nnweb-buffer)
190 (set-buffer-modified-p nil) 186 (set-buffer-modified-p nil)
191 (kill-buffer nnweb-buffer))) 187 (kill-buffer nnweb-buffer)))
192 (nnoo-close-server 'nnweb server)) 188 (nnoo-close-server 'nnweb server))
193 189
194(deffoo nnweb-request-list (&optional server) 190(deffoo nnweb-request-list (&optional server)
195 (nnweb-possibly-change-server nil server) 191 (nnweb-possibly-change-server nil server)
196 (save-excursion 192 (with-current-buffer nntp-server-buffer
197 (set-buffer nntp-server-buffer)
198 (nnmail-generate-active (list (assoc server nnweb-group-alist))) 193 (nnmail-generate-active (list (assoc server nnweb-group-alist)))
199 t)) 194 t))
200 195
@@ -402,8 +397,7 @@ Valid types include `google', `dejanews', and `gmane'.")
402 397
403(defun nnweb-google-create-mapping () 398(defun nnweb-google-create-mapping ()
404 "Perform the search and create a number-to-url alist." 399 "Perform the search and create a number-to-url alist."
405 (save-excursion 400 (with-current-buffer nnweb-buffer
406 (set-buffer nnweb-buffer)
407 (erase-buffer) 401 (erase-buffer)
408 (nnheader-message 7 "Searching google...") 402 (nnheader-message 7 "Searching google...")
409 (when (funcall (nnweb-definition 'search) nnweb-search) 403 (when (funcall (nnweb-definition 'search) nnweb-search)
@@ -459,8 +453,7 @@ Valid types include `google', `dejanews', and `gmane'.")
459;;; 453;;;
460(defun nnweb-gmane-create-mapping () 454(defun nnweb-gmane-create-mapping ()
461 "Perform the search and create a number-to-url alist." 455 "Perform the search and create a number-to-url alist."
462 (save-excursion 456 (with-current-buffer nnweb-buffer
463 (set-buffer nnweb-buffer)
464 (let ((case-fold-search t) 457 (let ((case-fold-search t)
465 (active (or (cadr (assoc nnweb-group nnweb-group-alist)) 458 (active (or (cadr (assoc nnweb-group nnweb-group-alist))
466 (cons 1 0))) 459 (cons 1 0)))
diff --git a/lisp/gnus/pop3.el b/lisp/gnus/pop3.el
index 950cae25c4e..63ed8004a9f 100644
--- a/lisp/gnus/pop3.el
+++ b/lisp/gnus/pop3.el
@@ -279,9 +279,9 @@ Returns the process associated with the connection."
279 (let ((coding-system-for-read 'binary) 279 (let ((coding-system-for-read 'binary)
280 (coding-system-for-write 'binary) 280 (coding-system-for-write 'binary)
281 process) 281 process)
282 (with-current-buffer 282 (save-excursion
283 (get-buffer-create (concat " trace of POP session to " 283 (set-buffer (get-buffer-create (concat " trace of POP session to "
284 mailhost)) 284 mailhost)))
285 (erase-buffer) 285 (erase-buffer)
286 (setq pop3-read-point (point-min)) 286 (setq pop3-read-point (point-min))
287 (setq process 287 (setq process
@@ -353,7 +353,8 @@ Returns the process associated with the connection."
353Return the response string if optional second argument is non-nil." 353Return the response string if optional second argument is non-nil."
354 (let ((case-fold-search nil) 354 (let ((case-fold-search nil)
355 match-end) 355 match-end)
356 (with-current-buffer (process-buffer process) 356 (save-excursion
357 (set-buffer (process-buffer process))
357 (goto-char pop3-read-point) 358 (goto-char pop3-read-point)
358 (while (and (memq (process-status process) '(open run)) 359 (while (and (memq (process-status process) '(open run))
359 (not (search-forward "\r\n" nil t))) 360 (not (search-forward "\r\n" nil t)))
@@ -510,7 +511,8 @@ Otherwise, return the size of the message-id MSG"
510 (if msg 511 (if msg
511 (string-to-number (nth 2 (split-string response " "))) 512 (string-to-number (nth 2 (split-string response " ")))
512 (let ((start pop3-read-point) end) 513 (let ((start pop3-read-point) end)
513 (with-current-buffer (process-buffer process) 514 (save-excursion
515 (set-buffer (process-buffer process))
514 (while (not (re-search-forward "^\\.\r\n" nil t)) 516 (while (not (re-search-forward "^\\.\r\n" nil t))
515 (pop3-accept-process-output process) 517 (pop3-accept-process-output process)
516 (goto-char start)) 518 (goto-char start))
@@ -528,7 +530,8 @@ Otherwise, return the size of the message-id MSG"
528 (pop3-send-command process (format "RETR %s" msg)) 530 (pop3-send-command process (format "RETR %s" msg))
529 (pop3-read-response process) 531 (pop3-read-response process)
530 (let ((start pop3-read-point) end) 532 (let ((start pop3-read-point) end)
531 (with-current-buffer (process-buffer process) 533 (save-excursion
534 (set-buffer (process-buffer process))
532 (while (not (re-search-forward "^\\.\r\n" nil t)) 535 (while (not (re-search-forward "^\\.\r\n" nil t))
533 (pop3-accept-process-output process) 536 (pop3-accept-process-output process)
534 (goto-char start)) 537 (goto-char start))
@@ -544,7 +547,8 @@ Otherwise, return the size of the message-id MSG"
544 (setq end (point-marker)) 547 (setq end (point-marker))
545 (pop3-clean-region start end) 548 (pop3-clean-region start end)
546 (pop3-munge-message-separator start end) 549 (pop3-munge-message-separator start end)
547 (with-current-buffer crashbuf 550 (save-excursion
551 (set-buffer crashbuf)
548 (erase-buffer)) 552 (erase-buffer))
549 (copy-to-buffer crashbuf start end) 553 (copy-to-buffer crashbuf start end)
550 (delete-region start end) 554 (delete-region start end)
@@ -581,7 +585,8 @@ and close the connection."
581 (pop3-send-command process "QUIT") 585 (pop3-send-command process "QUIT")
582 (pop3-read-response process t) 586 (pop3-read-response process t)
583 (if process 587 (if process
584 (with-current-buffer (process-buffer process) 588 (save-excursion
589 (set-buffer (process-buffer process))
585 (goto-char (point-max)) 590 (goto-char (point-max))
586 (delete-process process)))) 591 (delete-process process))))
587 592
diff --git a/lisp/gnus/smime.el b/lisp/gnus/smime.el
index d836f320164..a2668199469 100644
--- a/lisp/gnus/smime.el
+++ b/lisp/gnus/smime.el
@@ -708,8 +708,7 @@ The following commands are available:
708 "Go to the SMIME buffer." 708 "Go to the SMIME buffer."
709 (interactive) 709 (interactive)
710 (unless (get-buffer smime-buffer) 710 (unless (get-buffer smime-buffer)
711 (save-excursion 711 (with-current-buffer (get-buffer-create smime-buffer)
712 (set-buffer (get-buffer-create smime-buffer))
713 (smime-mode))) 712 (smime-mode)))
714 (smime-draw-buffer) 713 (smime-draw-buffer)
715 (switch-to-buffer smime-buffer)) 714 (switch-to-buffer smime-buffer))
diff --git a/lisp/gnus/spam-report.el b/lisp/gnus/spam-report.el
index 0e32e934040..e73444e85c0 100644
--- a/lisp/gnus/spam-report.el
+++ b/lisp/gnus/spam-report.el
@@ -109,8 +109,7 @@ Reports is as ham when HAM is set."
109 ;; select this particular article 109 ;; select this particular article
110 (gnus-summary-select-article nil nil nil article) 110 (gnus-summary-select-article nil nil nil article)
111 ;; resend it to the destination address 111 ;; resend it to the destination address
112 (save-excursion 112 (with-current-buffer gnus-original-article-buffer
113 (set-buffer gnus-original-article-buffer)
114 (message-resend spam-report-resend-to)))) 113 (message-resend spam-report-resend-to))))
115 114
116(defun spam-report-resend-ham (articles) 115(defun spam-report-resend-ham (articles)
@@ -292,8 +291,7 @@ symbol `ask', query before flushing the queue file."
292 (gnus-message 7 "Processing requests using `%s'." 291 (gnus-message 7 "Processing requests using `%s'."
293 spam-report-url-ping-function)) 292 spam-report-url-ping-function))
294 (or file (setq file spam-report-requests-file)) 293 (or file (setq file spam-report-requests-file))
295 (save-excursion 294 (with-current-buffer (find-file-noselect file)
296 (set-buffer (find-file-noselect file))
297 (goto-char (point-min)) 295 (goto-char (point-min))
298 (while (and (not (eobp)) 296 (while (and (not (eobp))
299 (re-search-forward 297 (re-search-forward
diff --git a/lisp/gnus/spam.el b/lisp/gnus/spam.el
index d079be2fcd2..b7908e5507b 100644
--- a/lisp/gnus/spam.el
+++ b/lisp/gnus/spam.el
@@ -1605,8 +1605,7 @@ to find it out)."
1605 article)))) 1605 article))))
1606 1606
1607(defun spam-fetch-article-header (article) 1607(defun spam-fetch-article-header (article)
1608 (save-excursion 1608 (with-current-buffer gnus-summary-buffer
1609 (set-buffer gnus-summary-buffer)
1610 (gnus-read-header article) 1609 (gnus-read-header article)
1611 (nth 3 (assq article gnus-newsgroup-data)))) 1610 (nth 3 (assq article gnus-newsgroup-data))))
1612;;}}} 1611;;}}}
@@ -2172,8 +2171,7 @@ See `spam-ifile-database'."
2172 (with-temp-buffer 2171 (with-temp-buffer
2173 (let ((temp-buffer-name (buffer-name)) 2172 (let ((temp-buffer-name (buffer-name))
2174 (db-param (spam-get-ifile-database-parameter))) 2173 (db-param (spam-get-ifile-database-parameter)))
2175 (save-excursion 2174 (with-current-buffer article-buffer-name
2176 (set-buffer article-buffer-name)
2177 (apply 'call-process-region 2175 (apply 'call-process-region
2178 (point-min) (point-max) spam-ifile-program 2176 (point-min) (point-max) spam-ifile-program
2179 nil temp-buffer-name nil "-c" 2177 nil temp-buffer-name nil "-c"
@@ -2318,9 +2316,8 @@ With a non-nil REMOVE, remove the ADDRESSES."
2318 ;; else, we have a list of addresses here 2316 ;; else, we have a list of addresses here
2319 (unless (file-exists-p (file-name-directory file)) 2317 (unless (file-exists-p (file-name-directory file))
2320 (make-directory (file-name-directory file) t)) 2318 (make-directory (file-name-directory file) t))
2321 (save-excursion 2319 (with-current-buffer
2322 (set-buffer 2320 (find-file-noselect file)
2323 (find-file-noselect file))
2324 (dolist (a addresses) 2321 (dolist (a addresses)
2325 (when (stringp a) 2322 (when (stringp a)
2326 (goto-char (point-min)) 2323 (goto-char (point-min))
@@ -2521,8 +2518,7 @@ With a non-nil REMOVE, remove the ADDRESSES."
2521 return) 2518 return)
2522 (with-temp-buffer 2519 (with-temp-buffer
2523 (let ((temp-buffer-name (buffer-name))) 2520 (let ((temp-buffer-name (buffer-name)))
2524 (save-excursion 2521 (with-current-buffer article-buffer-name
2525 (set-buffer article-buffer-name)
2526 (apply 'call-process-region 2522 (apply 'call-process-region
2527 (point-min) (point-max) 2523 (point-min) (point-max)
2528 spam-bogofilter-program 2524 spam-bogofilter-program
@@ -2579,8 +2575,7 @@ With a non-nil REMOVE, remove the ADDRESSES."
2579 (let ((article-buffer-name (buffer-name))) 2575 (let ((article-buffer-name (buffer-name)))
2580 (with-temp-buffer 2576 (with-temp-buffer
2581 (let ((temp-buffer-name (buffer-name))) 2577 (let ((temp-buffer-name (buffer-name)))
2582 (save-excursion 2578 (with-current-buffer article-buffer-name
2583 (set-buffer article-buffer-name)
2584 (let ((status 2579 (let ((status
2585 (apply 'call-process-region 2580 (apply 'call-process-region
2586 (point-min) (point-max) 2581 (point-min) (point-max)
@@ -2656,8 +2651,7 @@ With a non-nil REMOVE, remove the ADDRESSES."
2656 (let ((article-buffer-name (buffer-name))) 2651 (let ((article-buffer-name (buffer-name)))
2657 (with-temp-buffer 2652 (with-temp-buffer
2658 (let ((temp-buffer-name (buffer-name))) 2653 (let ((temp-buffer-name (buffer-name)))
2659 (save-excursion 2654 (with-current-buffer article-buffer-name
2660 (set-buffer article-buffer-name)
2661 (apply 'call-process-region 2655 (apply 'call-process-region
2662 (point-min) (point-max) spam-assassin-program 2656 (point-min) (point-max) spam-assassin-program
2663 nil temp-buffer-name nil spam-spamassassin-arguments)) 2657 nil temp-buffer-name nil spam-spamassassin-arguments))
@@ -2691,8 +2685,7 @@ With a non-nil REMOVE, remove the ADDRESSES."
2691 ;; group the articles into mbox format 2685 ;; group the articles into mbox format
2692 (dolist (article articles) 2686 (dolist (article articles)
2693 (let (article-string) 2687 (let (article-string)
2694 (save-excursion 2688 (with-current-buffer summary-buffer-name
2695 (set-buffer summary-buffer-name)
2696 (setq article-string (spam-get-article-as-string article))) 2689 (setq article-string (spam-get-article-as-string article)))
2697 (when (stringp article-string) 2690 (when (stringp article-string)
2698 (insert "From \n") ; mbox separator (sa-learn only checks the 2691 (insert "From \n") ; mbox separator (sa-learn only checks the
@@ -2755,8 +2748,7 @@ With a non-nil REMOVE, remove the ADDRESSES."
2755 return) 2748 return)
2756 (with-temp-buffer 2749 (with-temp-buffer
2757 (let ((temp-buffer-name (buffer-name))) 2750 (let ((temp-buffer-name (buffer-name)))
2758 (save-excursion 2751 (with-current-buffer article-buffer-name
2759 (set-buffer article-buffer-name)
2760 (apply 'call-process-region 2752 (apply 'call-process-region
2761 (point-min) (point-max) 2753 (point-min) (point-max)
2762 spam-bsfilter-program 2754 spam-bsfilter-program
@@ -2841,8 +2833,7 @@ With a non-nil REMOVE, remove the ADDRESSES."
2841 return) 2833 return)
2842 (with-temp-buffer 2834 (with-temp-buffer
2843 (let ((temp-buffer-name (buffer-name))) 2835 (let ((temp-buffer-name (buffer-name)))
2844 (save-excursion 2836 (with-current-buffer article-buffer-name
2845 (set-buffer article-buffer-name)
2846 (apply 'call-process-region 2837 (apply 'call-process-region
2847 (point-min) (point-max) 2838 (point-min) (point-max)
2848 spam-crm114-program 2839 spam-crm114-program
diff --git a/lisp/gnus/starttls.el b/lisp/gnus/starttls.el
index 02a557de5cc..bf1982f54dd 100644
--- a/lisp/gnus/starttls.el
+++ b/lisp/gnus/starttls.el
@@ -254,8 +254,7 @@ handshake, or nil on failure."
254 (starttls-set-process-query-on-exit-flag process nil) 254 (starttls-set-process-query-on-exit-flag process nil)
255 (while (and (processp process) 255 (while (and (processp process)
256 (eq (process-status process) 'run) 256 (eq (process-status process) 'run)
257 (save-excursion 257 (with-current-buffer buffer
258 (set-buffer buffer)
259 (goto-char old-max) 258 (goto-char old-max)
260 (not (setq done (re-search-forward 259 (not (setq done (re-search-forward
261 starttls-connect nil t))))) 260 starttls-connect nil t)))))
diff --git a/lisp/gnus/utf7.el b/lisp/gnus/utf7.el
index cca647d94b2..74bd092a3dd 100644
--- a/lisp/gnus/utf7.el
+++ b/lisp/gnus/utf7.el
@@ -205,6 +205,7 @@ Characters are in raw byte pairs in narrowed buffer."
205 (mm-decode-coding-region (point-min) (point-max) 'iso-8859-1) 205 (mm-decode-coding-region (point-min) (point-max) 'iso-8859-1)
206 (mm-enable-multibyte)) 206 (mm-enable-multibyte))
207 207
208;;;###autoload
208(defun utf7-encode (string &optional for-imap) 209(defun utf7-encode (string &optional for-imap)
209 "Encode UTF-7 STRING. Use IMAP modification if FOR-IMAP is non-nil." 210 "Encode UTF-7 STRING. Use IMAP modification if FOR-IMAP is non-nil."
210 (if (and (coding-system-p 'utf-7) (coding-system-p 'utf-7-imap)) 211 (if (and (coding-system-p 'utf-7) (coding-system-p 'utf-7-imap))
diff --git a/lisp/net/netrc.el b/lisp/net/netrc.el
index 408eca9bac7..3636c892726 100644
--- a/lisp/net/netrc.el
+++ b/lisp/net/netrc.el
@@ -228,6 +228,7 @@ MODE can be \"login\" or \"password\", suitable for passing to
228 (eq type (car (cddr service))))))) 228 (eq type (car (cddr service)))))))
229 (cadr service))) 229 (cadr service)))
230 230
231;;;###autoload
231(defun netrc-credentials (machine &rest ports) 232(defun netrc-credentials (machine &rest ports)
232 "Return a user name/password pair. 233 "Return a user name/password pair.
233Port specifications will be prioritised in the order they are 234Port specifications will be prioritised in the order they are