Mercurial > emacs
comparison lisp/gnus/nnimap.el @ 88155:d7ddb3e565de
sync with trunk
author | Henrik Enberg <henrik.enberg@telia.com> |
---|---|
date | Mon, 16 Jan 2006 00:03:54 +0000 |
parents | 0d8b17d428b5 |
children |
comparison
equal
deleted
inserted
replaced
88154:8ce476d3ba36 | 88155:d7ddb3e565de |
---|---|
1 ;;; nnimap.el --- imap backend for Gnus | 1 ;;; nnimap.el --- imap backend for Gnus |
2 ;; Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. | 2 |
3 ;; Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, | |
4 ;; 2005 Free Software Foundation, Inc. | |
3 | 5 |
4 ;; Author: Simon Josefsson <jas@pdc.kth.se> | 6 ;; Author: Simon Josefsson <jas@pdc.kth.se> |
5 ;; Jim Radford <radford@robby.caltech.edu> | 7 ;; Jim Radford <radford@robby.caltech.edu> |
6 ;; Keywords: mail | 8 ;; Keywords: mail |
7 | 9 |
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
18 ;; GNU General Public License for more details. | 20 ;; GNU General Public License for more details. |
19 | 21 |
20 ;; You should have received a copy of the GNU General Public License | 22 ;; You should have received a copy of the GNU General Public License |
21 ;; along with GNU Emacs; see the file COPYING. If not, write to the | 23 ;; along with GNU Emacs; see the file COPYING. If not, write to the |
22 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, | 24 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
23 ;; Boston, MA 02111-1307, USA. | 25 ;; Boston, MA 02110-1301, USA. |
24 | 26 |
25 ;;; Commentary: | 27 ;;; Commentary: |
26 | 28 |
27 ;; Todo, major things: | 29 ;; Todo, major things: |
28 ;; | 30 ;; |
53 ;; o ACAP stuff (perhaps a different project, would be nice to ACAPify | 55 ;; o ACAP stuff (perhaps a different project, would be nice to ACAPify |
54 ;; .newsrc.eld) | 56 ;; .newsrc.eld) |
55 ;; o What about Gnus's article editing, can we support it? NO! | 57 ;; o What about Gnus's article editing, can we support it? NO! |
56 ;; o Use \Draft to support the draft group?? | 58 ;; o Use \Draft to support the draft group?? |
57 ;; o Duplicate suppression | 59 ;; o Duplicate suppression |
60 ;; o Rewrite UID SEARCH UID X as UID FETCH X (UID) for those with slow servers | |
58 | 61 |
59 ;;; Code: | 62 ;;; Code: |
60 | 63 |
61 (eval-and-compile | 64 (require 'imap) |
62 (require 'cl) | |
63 (require 'imap)) | |
64 | |
65 (require 'nnoo) | 65 (require 'nnoo) |
66 (require 'nnmail) | 66 (require 'nnmail) |
67 (require 'nnheader) | 67 (require 'nnheader) |
68 (require 'mm-util) | 68 (require 'mm-util) |
69 (require 'gnus) | 69 (require 'gnus) |
70 (require 'gnus-range) | 70 (require 'gnus-range) |
71 (require 'gnus-start) | 71 (require 'gnus-start) |
72 (require 'gnus-int) | 72 (require 'gnus-int) |
73 | 73 |
74 (eval-when-compile (require 'cl)) | |
75 | |
74 (nnoo-declare nnimap) | 76 (nnoo-declare nnimap) |
75 | 77 |
76 (defconst nnimap-version "nnimap 0.131") | 78 (defconst nnimap-version "nnimap 1.0") |
79 | |
80 (defgroup nnimap nil | |
81 "Reading IMAP mail with Gnus." | |
82 :group 'gnus) | |
77 | 83 |
78 (defvoo nnimap-address nil | 84 (defvoo nnimap-address nil |
79 "Address of physical IMAP server. If nil, use the virtual server's name.") | 85 "Address of physical IMAP server. If nil, use the virtual server's name.") |
80 | 86 |
81 (defvoo nnimap-server-port nil | 87 (defvoo nnimap-server-port nil |
82 "Port number on physical IMAP server. | 88 "Port number on physical IMAP server. |
83 If nil, defaults to 993 for SSL connections and 143 otherwise.") | 89 If nil, defaults to 993 for TLS/SSL connections and 143 otherwise.") |
84 | 90 |
85 ;; Splitting variables | 91 ;; Splitting variables |
86 | 92 |
87 (defvar nnimap-split-crosspost t | 93 (defcustom nnimap-split-crosspost t |
88 "If non-nil, do crossposting if several split methods match the mail. | 94 "If non-nil, do crossposting if several split methods match the mail. |
89 If nil, the first match found will be used.") | 95 If nil, the first match found will be used." |
90 | 96 :group 'nnimap |
91 (defvar nnimap-split-inbox nil | 97 :type 'boolean) |
92 "*Name of mailbox to split mail from. | 98 |
99 (defcustom nnimap-split-inbox nil | |
100 "Name of mailbox to split mail from. | |
93 | 101 |
94 Mail is read from this mailbox and split according to rules in | 102 Mail is read from this mailbox and split according to rules in |
95 `nnimap-split-rules'. | 103 `nnimap-split-rule'. |
96 | 104 |
97 This can be a string or a list of strings.") | 105 This can be a string or a list of strings." |
98 | 106 :group 'nnimap |
99 (defvar nnimap-split-rule nil | 107 :type '(choice (string) |
100 "*Mail will be split according to these rules. | 108 (repeat string))) |
109 | |
110 (define-widget 'nnimap-strict-function 'function | |
111 "This widget only matches values that are functionp. | |
112 | |
113 Warning: This means that a value that is the symbol of a not yet | |
114 loaded function will not match. Use with care." | |
115 :match 'nnimap-strict-function-match) | |
116 | |
117 (defun nnimap-strict-function-match (widget value) | |
118 "Ignoring WIDGET, match if VALUE is a function." | |
119 (functionp value)) | |
120 | |
121 (defcustom nnimap-split-rule nil | |
122 "Mail will be split according to these rules. | |
101 | 123 |
102 Mail is read from mailbox(es) specified in `nnimap-split-inbox'. | 124 Mail is read from mailbox(es) specified in `nnimap-split-inbox'. |
103 | 125 |
104 If you'd like, for instance, one mail group for mail from the | 126 If you'd like, for instance, one mail group for mail from the |
105 \"gnus-imap\" mailing list, one group for junk mail and leave | 127 \"gnus-imap\" mailing list, one group for junk mail and leave |
107 this: | 129 this: |
108 | 130 |
109 \(setq nnimap-split-rule '((\"INBOX.gnus-imap\" \"From:.*gnus-imap\") | 131 \(setq nnimap-split-rule '((\"INBOX.gnus-imap\" \"From:.*gnus-imap\") |
110 (\"INBOX.junk\" \"Subject:.*buy\"))) | 132 (\"INBOX.junk\" \"Subject:.*buy\"))) |
111 | 133 |
112 As you can see, `nnimap-split-rule' is a list of lists, where the first | 134 As you can see, `nnimap-split-rule' is a list of lists, where the |
113 element in each \"rule\" is the name of the IMAP mailbox, and the | 135 first element in each \"rule\" is the name of the IMAP mailbox (or the |
114 second is a regexp that nnimap will try to match on the header to find | 136 symbol `junk' if you want to remove the mail), and the second is a |
115 a fit. | 137 regexp that nnimap will try to match on the header to find a fit. |
116 | 138 |
117 The second element can also be a function. In that case, it will be | 139 The second element can also be a function. In that case, it will be |
118 called narrowed to the headers with the first element of the rule as | 140 called narrowed to the headers with the first element of the rule as |
119 the argument. It should return a non-nil value if it thinks that the | 141 the argument. It should return a non-nil value if it thinks that the |
120 mail belongs in that group. | 142 mail belongs in that group. |
127 even different split rules in different inboxes on the same server, | 149 even different split rules in different inboxes on the same server, |
128 the syntax of this variable have been extended along the lines of: | 150 the syntax of this variable have been extended along the lines of: |
129 | 151 |
130 \(setq nnimap-split-rule | 152 \(setq nnimap-split-rule |
131 '((\"my1server\" (\".*\" ((\"ding\" \"ding@gnus.org\") | 153 '((\"my1server\" (\".*\" ((\"ding\" \"ding@gnus.org\") |
132 (\"junk\" \"From:.*Simon\"))) | 154 (\"junk\" \"From:.*Simon\"))) |
133 (\"my2server\" (\"INBOX\" nnimap-split-fancy)) | 155 (\"my2server\" (\"INBOX\" nnimap-split-fancy)) |
134 (\"my[34]server\" (\".*\" ((\"private\" \"To:.*Simon\") | 156 (\"my[34]server\" (\".*\" ((\"private\" \"To:.*Simon\") |
135 (\"junk\" my-junk-func))))) | 157 (\"junk\" my-junk-func))))) |
136 | 158 |
137 The virtual server name is in fact a regexp, so that the same rules | 159 The virtual server name is in fact a regexp, so that the same rules |
138 may apply to several servers. In the example, the servers | 160 may apply to several servers. In the example, the servers |
139 \"my3server\" and \"my4server\" both use the same rules. Similarly, | 161 \"my3server\" and \"my4server\" both use the same rules. Similarly, |
140 the inbox string is also a regexp. The actual splitting rules are as | 162 the inbox string is also a regexp. The actual splitting rules are as |
141 before, either a function, or a list with group/regexp or | 163 before, either a function, or a list with group/regexp or |
142 group/function elements.") | 164 group/function elements." |
143 | 165 :group 'nnimap |
144 (defvar nnimap-split-predicate "UNSEEN UNDELETED" | 166 :type '(choice :tag "Rule type" |
167 (repeat :menu-tag "Single-server" | |
168 :tag "Single-server list" | |
169 (list (string :tag "Mailbox") | |
170 (choice :tag "Predicate" | |
171 (regexp :tag "A regexp") | |
172 (nnimap-strict-function :tag "A function")))) | |
173 (choice :menu-tag "A function" | |
174 :tag "A function" | |
175 (function-item nnimap-split-fancy) | |
176 (function-item nnmail-split-fancy) | |
177 (nnimap-strict-function :tag "User-defined function")) | |
178 (repeat :menu-tag "Multi-server (extended)" | |
179 :tag "Multi-server list" | |
180 (list (regexp :tag "Server regexp") | |
181 (list (regexp :tag "Incoming Mailbox regexp") | |
182 (repeat :tag "Rules for matching server(s) and mailbox(es)" | |
183 (list (string :tag "Destination mailbox") | |
184 (choice :tag "Predicate" | |
185 (regexp :tag "A Regexp") | |
186 (nnimap-strict-function :tag "A Function"))))))))) | |
187 | |
188 (defcustom nnimap-split-predicate "UNSEEN UNDELETED" | |
145 "The predicate used to find articles to split. | 189 "The predicate used to find articles to split. |
146 If you use another IMAP client to peek on articles but always would | 190 If you use another IMAP client to peek on articles but always would |
147 like nnimap to split them once it's started, you could change this to | 191 like nnimap to split them once it's started, you could change this to |
148 \"UNDELETED\". Other available predicates are available in | 192 \"UNDELETED\". Other available predicates are available in |
149 RFC2060 section 6.4.4.") | 193 RFC2060 section 6.4.4." |
150 | 194 :group 'nnimap |
151 (defvar nnimap-split-fancy nil | 195 :type 'string) |
152 "Like `nnmail-split-fancy', which see.") | 196 |
197 (defcustom nnimap-split-fancy nil | |
198 "Like the variable `nnmail-split-fancy'." | |
199 :group 'nnimap | |
200 :type 'sexp) | |
201 | |
202 (defvar nnimap-split-download-body-default nil | |
203 "Internal variable with default value for `nnimap-split-download-body'.") | |
204 | |
205 (defcustom nnimap-split-download-body 'default | |
206 "Whether to download entire articles during splitting. | |
207 This is generally not required, and will slow things down considerably. | |
208 You may need it if you want to use an advanced splitting function that | |
209 analyzes the body before splitting the article. | |
210 If this variable is nil, bodies will not be downloaded; if this | |
211 variable is the symbol `default' the default behaviour is | |
212 used (which currently is nil, unless you use a statistical | |
213 spam.el test); if this variable is another non-nil value bodies | |
214 will be downloaded." | |
215 :version "22.1" | |
216 :group 'nnimap | |
217 :type '(choice (const :tag "Let system decide" deault) | |
218 boolean)) | |
219 | |
220 ;; Performance / bug workaround variables | |
221 | |
222 (defcustom nnimap-close-asynchronous t | |
223 "Close mailboxes asynchronously in `nnimap-close-group'. | |
224 This means that errors caught by nnimap when closing the mailbox will | |
225 not prevent Gnus from updating the group status, which may be harmful. | |
226 However, it increases speed." | |
227 :version "22.1" | |
228 :type 'boolean | |
229 :group 'nnimap) | |
230 | |
231 (defcustom nnimap-dont-close t | |
232 "Never close mailboxes. | |
233 This increases the speed of closing mailboxes (quiting group) but may | |
234 decrease the speed of selecting another mailbox later. Re-selecting | |
235 the same mailbox will be faster though." | |
236 :version "22.1" | |
237 :type 'boolean | |
238 :group 'nnimap) | |
239 | |
240 (defcustom nnimap-retrieve-groups-asynchronous t | |
241 "Send asynchronous STATUS commands for each mailbox before checking mail. | |
242 If you have mailboxes that rarely receives mail, this speeds up new | |
243 mail checking. It works by first sending STATUS commands for each | |
244 mailbox, and then only checking groups which has a modified UIDNEXT | |
245 more carefully for new mail. | |
246 | |
247 In summary, the default is O((1-p)*k+p*n) and changing it to nil makes | |
248 it O(n). If p is small, then the default is probably faster." | |
249 :version "22.1" | |
250 :type 'boolean | |
251 :group 'nnimap) | |
252 | |
253 (defvoo nnimap-need-unselect-to-notice-new-mail nil | |
254 "Unselect mailboxes before looking for new mail in them. | |
255 Some servers seem to need this under some circumstances.") | |
153 | 256 |
154 ;; Authorization / Privacy variables | 257 ;; Authorization / Privacy variables |
155 | 258 |
156 (defvoo nnimap-auth-method nil | 259 (defvoo nnimap-auth-method nil |
157 "Obsolete.") | 260 "Obsolete.") |
162 The default, nil, will try to use the \"best\" method the server can | 265 The default, nil, will try to use the \"best\" method the server can |
163 handle. | 266 handle. |
164 | 267 |
165 Change this if | 268 Change this if |
166 | 269 |
167 1) you want to connect with SSL. The SSL integration with IMAP is | 270 1) you want to connect with TLS/SSL. The TLS/SSL integration |
168 brain-dead so you'll have to tell it specifically. | 271 with IMAP is suboptimal so you'll have to tell it |
272 specifically. | |
169 | 273 |
170 2) your server is more capable than your environment -- i.e. your | 274 2) your server is more capable than your environment -- i.e. your |
171 server accept Kerberos login's but you haven't installed the | 275 server accept Kerberos login's but you haven't installed the |
172 `imtest' program or your machine isn't configured for Kerberos. | 276 `imtest' program or your machine isn't configured for Kerberos. |
173 | 277 |
174 Possible choices: kerberos4, ssl, network") | 278 Possible choices: gssapi, kerberos4, starttls, tls, ssl, network, shell. |
279 See also `imap-streams' and `imap-stream-alist'.") | |
175 | 280 |
176 (defvoo nnimap-authenticator nil | 281 (defvoo nnimap-authenticator nil |
177 "How nnimap authenticate itself to the server. | 282 "How nnimap authenticate itself to the server. |
178 | 283 |
179 The default, nil, will try to use the \"best\" method the server can | 284 The default, nil, will try to use the \"best\" method the server can |
183 if your server is more capable than your environment -- i.e. you | 288 if your server is more capable than your environment -- i.e. you |
184 connect to a server that accept Kerberos login's but you haven't | 289 connect to a server that accept Kerberos login's but you haven't |
185 installed the `imtest' program or your machine isn't configured for | 290 installed the `imtest' program or your machine isn't configured for |
186 Kerberos. | 291 Kerberos. |
187 | 292 |
188 Possible choices: kerberos4, cram-md5, login, anonymous.") | 293 Possible choices: gssapi, kerberos4, digest-md5, cram-md5, login, anonymous. |
294 See also `imap-authenticators' and `imap-authenticator-alist'") | |
189 | 295 |
190 (defvoo nnimap-directory (nnheader-concat gnus-directory "overview/") | 296 (defvoo nnimap-directory (nnheader-concat gnus-directory "overview/") |
191 "Directory to keep NOV cache files for nnimap groups. | 297 "Directory to keep NOV cache files for nnimap groups. |
192 See also `nnimap-nov-file-name'.") | 298 See also `nnimap-nov-file-name'.") |
193 | 299 |
200 `nnmail-use-long-file-names' is nil") | 306 `nnmail-use-long-file-names' is nil") |
201 | 307 |
202 (defvoo nnimap-nov-file-name-suffix ".novcache" | 308 (defvoo nnimap-nov-file-name-suffix ".novcache" |
203 "Suffix for NOV cache base filename.") | 309 "Suffix for NOV cache base filename.") |
204 | 310 |
205 (defvoo nnimap-nov-is-evil nil | 311 (defvoo nnimap-nov-is-evil gnus-agent |
206 "If non-nil, nnimap will never generate or use a local nov database for this backend. | 312 "If non-nil, never generate or use a local nov database for this backend. |
207 Using nov databases will speed up header fetching considerably. | 313 Using nov databases should speed up header fetching considerably. |
314 However, it will invoke a UID SEARCH UID command on the server, and | |
315 some servers implement this command inefficiently by opening each and | |
316 every message in the group, thus making it quite slow. | |
208 Unlike other backends, you do not need to take special care if you | 317 Unlike other backends, you do not need to take special care if you |
209 flip this variable.") | 318 flip this variable.") |
319 | |
320 (defvoo nnimap-search-uids-not-since-is-evil nil | |
321 "If non-nil, avoid \"UID SEARCH UID ... NOT SINCE\" queries when expiring. | |
322 Instead, use \"UID SEARCH SINCE\" to prune the list of expirable | |
323 articles within Gnus. This seems to be faster on Courier in some cases.") | |
210 | 324 |
211 (defvoo nnimap-expunge-on-close 'always ; 'ask, 'never | 325 (defvoo nnimap-expunge-on-close 'always ; 'ask, 'never |
212 "Whether to expunge a group when it is closed. | 326 "Whether to expunge a group when it is closed. |
213 When a IMAP group with articles marked for deletion is closed, this | 327 When a IMAP group with articles marked for deletion is closed, this |
214 variable determine if nnimap should actually remove the articles or | 328 variable determine if nnimap should actually remove the articles or |
235 | 349 |
236 There are two wildcards * and %. * matches everything, % matches | 350 There are two wildcards * and %. * matches everything, % matches |
237 everything in the current hierarchy.") | 351 everything in the current hierarchy.") |
238 | 352 |
239 (defvoo nnimap-news-groups nil | 353 (defvoo nnimap-news-groups nil |
240 "IMAP support a news-like mode, also known as bulletin board mode, where replies is sent via IMAP instead of SMTP. | 354 "IMAP support a news-like mode, also known as bulletin board mode, |
355 where replies is sent via IMAP instead of SMTP. | |
241 | 356 |
242 This variable should contain a regexp matching groups where you wish | 357 This variable should contain a regexp matching groups where you wish |
243 replies to be stored to the mailbox directly. | 358 replies to be stored to the mailbox directly. |
244 | 359 |
245 Example: | 360 Example: |
249 | 364 |
250 Note that there is nothing technically different between mail-like and | 365 Note that there is nothing technically different between mail-like and |
251 news-like mailboxes. If you wish to have a group with todo items or | 366 news-like mailboxes. If you wish to have a group with todo items or |
252 similar which you wouldn't want to set up a mailing list for, you can | 367 similar which you wouldn't want to set up a mailing list for, you can |
253 use this to make replies go directly to the group.") | 368 use this to make replies go directly to the group.") |
369 | |
370 (defvoo nnimap-expunge-search-string "UID %s NOT SINCE %s" | |
371 "IMAP search command to use for articles that are to be expired. | |
372 The first %s is replaced by a UID set of articles to search on, | |
373 and the second %s is replaced by a date criterium. | |
374 | |
375 One useful (and perhaps the only useful) value to change this to would | |
376 be `UID %s NOT SENTSINCE %s' to make nnimap use the Date: header | |
377 instead of the internal date of messages. See section 6.4.4 of RFC | |
378 2060 for more information on valid strings.") | |
379 | |
380 (defvoo nnimap-importantize-dormant t | |
381 "If non-nil, mark \"dormant\" articles as \"ticked\" for other IMAP clients. | |
382 Note that within Gnus, dormant articles will still (only) be | |
383 marked as ticked. This is to make \"dormant\" articles stand out, | |
384 just like \"ticked\" articles, in other IMAP clients.") | |
254 | 385 |
255 (defvoo nnimap-server-address nil | 386 (defvoo nnimap-server-address nil |
256 "Obsolete. Use `nnimap-address'.") | 387 "Obsolete. Use `nnimap-address'.") |
257 | 388 |
258 (defcustom nnimap-authinfo-file "~/.authinfo" | 389 (defcustom nnimap-authinfo-file "~/.authinfo" |
268 (cons :format "%v" | 399 (cons :format "%v" |
269 (const :format "" "login") | 400 (const :format "" "login") |
270 (string :format "Login: %v")) | 401 (string :format "Login: %v")) |
271 (cons :format "%v" | 402 (cons :format "%v" |
272 (const :format "" "password") | 403 (const :format "" "password") |
273 (string :format "Password: %v"))))))) | 404 (string :format "Password: %v")))))) |
405 :group 'nnimap) | |
274 | 406 |
275 (defcustom nnimap-prune-cache t | 407 (defcustom nnimap-prune-cache t |
276 "If non-nil, nnimap check whether articles still exist on server before using data stored in NOV cache." | 408 "If non-nil, nnimap check whether articles still exist on server before using data stored in NOV cache." |
277 :type 'boolean) | 409 :type 'boolean |
410 :group 'nnimap) | |
278 | 411 |
279 (defvar nnimap-request-list-method 'imap-mailbox-list | 412 (defvar nnimap-request-list-method 'imap-mailbox-list |
280 "Method to use to request a list of all folders from the server. | 413 "Method to use to request a list of all folders from the server. |
281 If this is 'imap-mailbox-lsub, then use a server-side subscription list to | 414 If this is 'imap-mailbox-lsub, then use a server-side subscription list to |
282 restrict visible folders.") | 415 restrict visible folders.") |
283 | 416 |
417 (defcustom nnimap-debug nil | |
418 "If non-nil, random debug spews are placed in *nnimap-debug* buffer. | |
419 Note that username, passwords and other privacy sensitive | |
420 information (such as e-mail) may be stored in the *nnimap-debug* | |
421 buffer. It is not written to disk, however. Do not enable this | |
422 variable unless you are comfortable with that." | |
423 :group 'nnimap | |
424 :type 'boolean) | |
425 | |
284 ;; Internal variables: | 426 ;; Internal variables: |
285 | 427 |
286 (defvar nnimap-debug nil | 428 (defvar nnimap-debug-buffer "*nnimap-debug*") |
287 "Name of buffer to record debugging info. | 429 (defvar nnimap-mailbox-info (gnus-make-hashtable 997)) |
288 For example: (setq nnimap-debug \"*nnimap-debug*\")") | |
289 (defvar nnimap-current-move-server nil) | 430 (defvar nnimap-current-move-server nil) |
290 (defvar nnimap-current-move-group nil) | 431 (defvar nnimap-current-move-group nil) |
291 (defvar nnimap-current-move-article nil) | 432 (defvar nnimap-current-move-article nil) |
292 (defvar nnimap-length) | 433 (defvar nnimap-length) |
293 (defvar nnimap-progress-chars '(?| ?/ ?- ?\\)) | 434 (defvar nnimap-progress-chars '(?| ?/ ?- ?\\)) |
294 (defvar nnimap-progress-how-often 20) | 435 (defvar nnimap-progress-how-often 20) |
295 (defvar nnimap-counter) | 436 (defvar nnimap-counter) |
296 (defvar nnimap-callback-callback-function nil | |
297 "Gnus callback the nnimap asynchronous callback should call.") | |
298 (defvar nnimap-callback-buffer nil | |
299 "Which buffer the asynchronous article prefetch callback should work in.") | |
300 (defvar nnimap-server-buffer-alist nil) ;; Map server name to buffers. | 437 (defvar nnimap-server-buffer-alist nil) ;; Map server name to buffers. |
301 (defvar nnimap-current-server nil) ;; Current server | 438 (defvar nnimap-current-server nil) ;; Current server |
302 (defvar nnimap-server-buffer nil) ;; Current servers' buffer | 439 (defvar nnimap-server-buffer nil) ;; Current servers' buffer |
303 | 440 |
304 | 441 |
305 | 442 |
306 (nnoo-define-basics nnimap) | 443 (nnoo-define-basics nnimap) |
307 | 444 |
323 group (gnus-server-to-method | 460 group (gnus-server-to-method |
324 (format "nnimap:%s" server)))) | 461 (format "nnimap:%s" server)))) |
325 (new-uidvalidity (imap-mailbox-get 'uidvalidity)) | 462 (new-uidvalidity (imap-mailbox-get 'uidvalidity)) |
326 (old-uidvalidity (gnus-group-get-parameter gnusgroup 'uidvalidity)) | 463 (old-uidvalidity (gnus-group-get-parameter gnusgroup 'uidvalidity)) |
327 (dir (file-name-as-directory (expand-file-name nnimap-directory))) | 464 (dir (file-name-as-directory (expand-file-name nnimap-directory))) |
328 (nameuid (nnheader-translate-file-chars | 465 (nameuid (nnheader-translate-file-chars |
329 (concat nnimap-nov-file-name | 466 (concat nnimap-nov-file-name |
330 (if (equal server "") | 467 (if (equal server "") |
331 "unnamed" | 468 "unnamed" |
332 server) "." group "." old-uidvalidity | 469 server) "." group "." old-uidvalidity |
333 nnimap-nov-file-name-suffix) t)) | 470 nnimap-nov-file-name-suffix) t)) |
334 (file (if (or nnmail-use-long-file-names | 471 (file (if (or nnmail-use-long-file-names |
335 (file-exists-p (expand-file-name nameuid dir))) | 472 (file-exists-p (expand-file-name nameuid dir))) |
336 (expand-file-name nameuid dir) | 473 (expand-file-name nameuid dir) |
337 (expand-file-name | 474 (expand-file-name |
338 (mm-encode-coding-string | 475 (mm-encode-coding-string |
339 (nnheader-replace-chars-in-string nameuid ?. ?/) | 476 (nnheader-replace-chars-in-string nameuid ?. ?/) |
349 t))) | 486 t))) |
350 | 487 |
351 (defun nnimap-before-find-minmax-bugworkaround () | 488 (defun nnimap-before-find-minmax-bugworkaround () |
352 "Function called before iterating through mailboxes with | 489 "Function called before iterating through mailboxes with |
353 `nnimap-find-minmax-uid'." | 490 `nnimap-find-minmax-uid'." |
354 ;; XXX this is for UoW imapd problem, it doesn't notice new mail in | 491 (when nnimap-need-unselect-to-notice-new-mail |
355 ;; currently selected mailbox without a re-select/examine. | 492 ;; XXX this is for UoW imapd problem, it doesn't notice new mail in |
356 (or (null (imap-current-mailbox nnimap-server-buffer)) | 493 ;; currently selected mailbox without a re-select/examine. |
357 (imap-mailbox-unselect nnimap-server-buffer))) | 494 (or (null (imap-current-mailbox nnimap-server-buffer)) |
495 (imap-mailbox-unselect nnimap-server-buffer)))) | |
358 | 496 |
359 (defun nnimap-find-minmax-uid (group &optional examine) | 497 (defun nnimap-find-minmax-uid (group &optional examine) |
360 "Find lowest and highest active article number in GROUP. | 498 "Find lowest and highest active article number in GROUP. |
361 If EXAMINE is non-nil the group is selected read-only." | 499 If EXAMINE is non-nil the group is selected read-only." |
362 (with-current-buffer nnimap-server-buffer | 500 (with-current-buffer nnimap-server-buffer |
363 (when (imap-mailbox-select group examine) | 501 (when (or (string= group (imap-current-mailbox)) |
502 (imap-mailbox-select group examine)) | |
364 (let (minuid maxuid) | 503 (let (minuid maxuid) |
365 (when (> (imap-mailbox-get 'exists) 0) | 504 (when (> (imap-mailbox-get 'exists) 0) |
366 (imap-fetch "1,*" "UID" nil 'nouidfetch) | 505 (imap-fetch "1,*" "UID" nil 'nouidfetch) |
367 (imap-message-map (lambda (uid Uid) | 506 (imap-message-map (lambda (uid Uid) |
368 (setq minuid (if minuid (min minuid uid) uid) | 507 (setq minuid (if minuid (min minuid uid) uid) |
378 imap-current-mailbox | 517 imap-current-mailbox |
379 (if (imap-mailbox-select group) | 518 (if (imap-mailbox-select group) |
380 (if (or (nnimap-verify-uidvalidity | 519 (if (or (nnimap-verify-uidvalidity |
381 group (or server nnimap-current-server)) | 520 group (or server nnimap-current-server)) |
382 (zerop (imap-mailbox-get 'exists group)) | 521 (zerop (imap-mailbox-get 'exists group)) |
522 t ;; for OGnus to see if ignoring uidvalidity | |
523 ;; changes has any bad effects. | |
383 (yes-or-no-p | 524 (yes-or-no-p |
384 (format | 525 (format |
385 "nnimap: Group %s is not uidvalid. Continue? " group))) | 526 "nnimap: Group %s is not uidvalid. Continue? " group))) |
386 imap-current-mailbox | 527 imap-current-mailbox |
387 (imap-mailbox-unselect) | 528 (imap-mailbox-unselect) |
423 chars (imap-message-get imap-current-message 'RFC822.SIZE))) | 564 chars (imap-message-get imap-current-message 'RFC822.SIZE))) |
424 (nnheader-insert-nov | 565 (nnheader-insert-nov |
425 (with-temp-buffer | 566 (with-temp-buffer |
426 (buffer-disable-undo) | 567 (buffer-disable-undo) |
427 (insert headers) | 568 (insert headers) |
428 (nnheader-ms-strip-cr) | 569 (let ((head (nnheader-parse-naked-head))) |
429 (nnheader-fold-continuation-lines) | |
430 (subst-char-in-region (point-min) (point-max) ?\t ? ) | |
431 (let ((head (nnheader-parse-head 'naked))) | |
432 (mail-header-set-number head uid) | 570 (mail-header-set-number head uid) |
433 (mail-header-set-chars head chars) | 571 (mail-header-set-chars head chars) |
434 (mail-header-set-lines head lines) | 572 (mail-header-set-lines head lines) |
435 (mail-header-set-xref | 573 (mail-header-set-xref |
436 head (format "%s %s:%d" (system-name) mbx uid)) | 574 head (format "%s %s:%d" (system-name) mbx uid)) |
451 1) | 589 1) |
452 (1- (car articles))))) | 590 (1- (car articles))))) |
453 articles))))) | 591 articles))))) |
454 (mapcar (lambda (msgid) | 592 (mapcar (lambda (msgid) |
455 (imap-search | 593 (imap-search |
456 (format "HEADER Message-Id %s" msgid))) | 594 (format "HEADER Message-Id \"%s\"" msgid))) |
457 articles)))) | 595 articles)))) |
458 | 596 |
459 (defun nnimap-group-overview-filename (group server) | 597 (defun nnimap-group-overview-filename (group server) |
460 "Make file name for GROUP on SERVER." | 598 "Make file name for GROUP on SERVER." |
461 (let* ((dir (file-name-as-directory (expand-file-name nnimap-directory))) | 599 (let* ((dir (file-name-as-directory (expand-file-name nnimap-directory))) |
462 (uidvalidity (gnus-group-get-parameter | 600 (uidvalidity (gnus-group-get-parameter |
463 (gnus-group-prefixed-name | 601 (gnus-group-prefixed-name |
464 group (gnus-server-to-method | 602 group (gnus-server-to-method |
465 (format "nnimap:%s" server))) | 603 (format "nnimap:%s" server))) |
466 'uidvalidity)) | 604 'uidvalidity)) |
467 (name (nnheader-translate-file-chars | 605 (name (nnheader-translate-file-chars |
468 (concat nnimap-nov-file-name | 606 (concat nnimap-nov-file-name |
469 (if (equal server "") | 607 (if (equal server "") |
470 "unnamed" | 608 "unnamed" |
471 server) "." group nnimap-nov-file-name-suffix) t)) | 609 server) "." group nnimap-nov-file-name-suffix) t)) |
472 (nameuid (nnheader-translate-file-chars | 610 (nameuid (nnheader-translate-file-chars |
473 (concat nnimap-nov-file-name | 611 (concat nnimap-nov-file-name |
474 (if (equal server "") | 612 (if (equal server "") |
475 "unnamed" | 613 "unnamed" |
476 server) "." group "." uidvalidity | 614 server) "." group "." uidvalidity |
477 nnimap-nov-file-name-suffix) t)) | 615 nnimap-nov-file-name-suffix) t)) |
478 (oldfile (if (or nnmail-use-long-file-names | 616 (oldfile (if (or nnmail-use-long-file-names |
479 (file-exists-p (expand-file-name name dir))) | 617 (file-exists-p (expand-file-name name dir))) |
480 (expand-file-name name dir) | 618 (expand-file-name name dir) |
481 (expand-file-name | 619 (expand-file-name |
482 (mm-encode-coding-string | 620 (mm-encode-coding-string |
483 (nnheader-replace-chars-in-string name ?. ?/) | 621 (nnheader-replace-chars-in-string name ?. ?/) |
484 nnmail-pathname-coding-system) | 622 nnmail-pathname-coding-system) |
485 dir))) | 623 dir))) |
486 (newfile (if (or nnmail-use-long-file-names | 624 (newfile (if (or nnmail-use-long-file-names |
487 (file-exists-p (expand-file-name nameuid dir))) | 625 (file-exists-p (expand-file-name nameuid dir))) |
488 (expand-file-name nameuid dir) | 626 (expand-file-name nameuid dir) |
489 (expand-file-name | 627 (expand-file-name |
490 (mm-encode-coding-string | 628 (mm-encode-coding-string |
491 (nnheader-replace-chars-in-string nameuid ?. ?/) | 629 (nnheader-replace-chars-in-string nameuid ?. ?/) |
492 nnmail-pathname-coding-system) | 630 nnmail-pathname-coding-system) |
493 dir)))) | 631 dir)))) |
494 (when (and (file-exists-p oldfile) (not (file-exists-p newfile))) | 632 (when (and (file-exists-p oldfile) (not (file-exists-p newfile))) |
495 (message "nnimap: Upgrading novcache filename...") | 633 (message "nnimap: Upgrading novcache filename...") |
496 (sit-for 1) | 634 (sit-for 1) |
497 (gnus-make-directory (file-name-directory newfile)) | 635 (gnus-make-directory (file-name-directory newfile)) |
498 (unless (ignore-errors (rename-file oldfile newfile) t) | 636 (unless (ignore-errors (rename-file oldfile newfile) t) |
531 (copy-sequence | 669 (copy-sequence |
532 nnmail-extra-headers)))) | 670 nnmail-extra-headers)))) |
533 (if (imap-capability 'IMAP4rev1) | 671 (if (imap-capability 'IMAP4rev1) |
534 (format "BODY.PEEK[HEADER.FIELDS %s])" headers) | 672 (format "BODY.PEEK[HEADER.FIELDS %s])" headers) |
535 (format "RFC822.HEADER.LINES %s)" headers))))) | 673 (format "RFC822.HEADER.LINES %s)" headers))))) |
674 (with-current-buffer nntp-server-buffer | |
675 (sort-numeric-fields 1 (point-min) (point-max))) | |
536 (and (numberp nnmail-large-newsgroup) | 676 (and (numberp nnmail-large-newsgroup) |
537 (> nnimap-length nnmail-large-newsgroup) | 677 (> nnimap-length nnmail-large-newsgroup) |
538 (nnheader-message 6 "nnimap: Retrieving headers...done"))))) | 678 (nnheader-message 6 "nnimap: Retrieving headers...done"))))) |
539 | 679 |
540 (defun nnimap-use-nov-p (group server) | 680 (defun nnimap-dont-use-nov-p (group server) |
541 (or gnus-nov-is-evil nnimap-nov-is-evil | 681 (or gnus-nov-is-evil nnimap-nov-is-evil |
542 (unless (and (gnus-make-directory | 682 (unless (and (gnus-make-directory |
543 (file-name-directory | 683 (file-name-directory |
544 (nnimap-group-overview-filename group server))) | 684 (nnimap-group-overview-filename group server))) |
545 (file-writable-p | 685 (file-writable-p |
549 | 689 |
550 (deffoo nnimap-retrieve-headers (articles &optional group server fetch-old) | 690 (deffoo nnimap-retrieve-headers (articles &optional group server fetch-old) |
551 (when (nnimap-possibly-change-group group server) | 691 (when (nnimap-possibly-change-group group server) |
552 (with-current-buffer nntp-server-buffer | 692 (with-current-buffer nntp-server-buffer |
553 (erase-buffer) | 693 (erase-buffer) |
554 (if (nnimap-use-nov-p group server) | 694 (if (nnimap-dont-use-nov-p group server) |
555 (nnimap-retrieve-headers-from-server | 695 (nnimap-retrieve-headers-from-server |
556 (gnus-compress-sequence articles) group server) | 696 (gnus-compress-sequence articles) group server) |
557 (let (uids cached low high) | 697 (let (uids cached low high) |
558 (when (setq uids (nnimap-retrieve-which-headers articles fetch-old) | 698 (when (setq uids (nnimap-retrieve-which-headers articles fetch-old) |
559 low (car uids) | 699 low (car uids) |
572 (cons (1+ (cdr cached)) high) group server)) | 712 (cons (1+ (cdr cached)) high) group server)) |
573 (when nnimap-prune-cache | 713 (when nnimap-prune-cache |
574 ;; remove nov's for articles which has expired on server | 714 ;; remove nov's for articles which has expired on server |
575 (goto-char (point-min)) | 715 (goto-char (point-min)) |
576 (dolist (uid (gnus-set-difference articles uids)) | 716 (dolist (uid (gnus-set-difference articles uids)) |
577 (when (re-search-forward (format "^%d\t" uid) nil t) | 717 (when (re-search-forward (format "^%d\t" uid) nil t) |
578 (gnus-delete-line))))) | 718 (gnus-delete-line))))) |
579 ;; nothing cached, fetch whole range from server | 719 ;; nothing cached, fetch whole range from server |
580 (nnimap-retrieve-headers-from-server | 720 (nnimap-retrieve-headers-from-server |
581 (cons low high) group server)) | 721 (cons low high) group server)) |
582 (when (buffer-modified-p) | 722 (when (buffer-modified-p) |
583 (nnmail-write-region | 723 (nnmail-write-region |
592 (nnheader-report 'nnimap "Can't open connection to server %s" server) | 732 (nnheader-report 'nnimap "Can't open connection to server %s" server) |
593 (unless (or (imap-capability 'IMAP4 nnimap-server-buffer) | 733 (unless (or (imap-capability 'IMAP4 nnimap-server-buffer) |
594 (imap-capability 'IMAP4rev1 nnimap-server-buffer)) | 734 (imap-capability 'IMAP4rev1 nnimap-server-buffer)) |
595 (imap-close nnimap-server-buffer) | 735 (imap-close nnimap-server-buffer) |
596 (nnheader-report 'nnimap "Server %s is not IMAP4 compliant" server)) | 736 (nnheader-report 'nnimap "Server %s is not IMAP4 compliant" server)) |
597 (let* ((list (gnus-parse-netrc nnimap-authinfo-file)) | 737 (let* ((list (progn (gnus-message 7 "Parsing authinfo file `%s'." |
738 nnimap-authinfo-file) | |
739 (gnus-parse-netrc nnimap-authinfo-file))) | |
598 (port (if nnimap-server-port | 740 (port (if nnimap-server-port |
599 (int-to-string nnimap-server-port) | 741 (int-to-string nnimap-server-port) |
600 "imap")) | 742 "imap")) |
601 (alist (gnus-netrc-machine list (or nnimap-server-address | 743 (alist (or (gnus-netrc-machine list server port "imap") |
602 nnimap-address server) | 744 (gnus-netrc-machine list server port "imaps") |
603 port "imap")) | 745 (gnus-netrc-machine list |
746 (or nnimap-server-address | |
747 nnimap-address) | |
748 port "imap") | |
749 (gnus-netrc-machine list | |
750 (or nnimap-server-address | |
751 nnimap-address) | |
752 port "imaps"))) | |
604 (user (gnus-netrc-get alist "login")) | 753 (user (gnus-netrc-get alist "login")) |
605 (passwd (gnus-netrc-get alist "password"))) | 754 (passwd (gnus-netrc-get alist "password"))) |
606 (if (imap-authenticate user passwd nnimap-server-buffer) | 755 (if (imap-authenticate user passwd nnimap-server-buffer) |
607 (prog1 | 756 (prog1 |
608 (push (list server nnimap-server-buffer) | 757 (push (list server nnimap-server-buffer) |
624 (if (assq 'nnimap-server-address defs) | 773 (if (assq 'nnimap-server-address defs) |
625 (push (list 'nnimap-address | 774 (push (list 'nnimap-address |
626 (cadr (assq 'nnimap-server-address defs))) defs) | 775 (cadr (assq 'nnimap-server-address defs))) defs) |
627 (push (list 'nnimap-address server) defs))) | 776 (push (list 'nnimap-address server) defs))) |
628 (nnoo-change-server 'nnimap server defs) | 777 (nnoo-change-server 'nnimap server defs) |
778 (or nnimap-server-buffer | |
779 (setq nnimap-server-buffer (cadr (assq 'nnimap-server-buffer defs)))) | |
629 (with-current-buffer (get-buffer-create nnimap-server-buffer) | 780 (with-current-buffer (get-buffer-create nnimap-server-buffer) |
630 (nnoo-change-server 'nnimap server defs)) | 781 (nnoo-change-server 'nnimap server defs)) |
631 (or (and nnimap-server-buffer | 782 (or (and nnimap-server-buffer |
632 (imap-opened nnimap-server-buffer)) | 783 (imap-opened nnimap-server-buffer) |
784 (if (with-current-buffer nnimap-server-buffer | |
785 (memq imap-state '(auth select examine))) | |
786 t | |
787 (imap-close nnimap-server-buffer) | |
788 (nnimap-open-connection server))) | |
633 (nnimap-open-connection server)))) | 789 (nnimap-open-connection server)))) |
634 | 790 |
635 (deffoo nnimap-server-opened (&optional server) | 791 (deffoo nnimap-server-opened (&optional server) |
636 "Whether SERVER is opened. | 792 "Whether SERVER is opened. |
637 If SERVER is the current virtual server, and the connection to the | 793 If SERVER is the current virtual server, and the connection to the |
669 "This function returns the last error message from server." | 825 "This function returns the last error message from server." |
670 (when (nnimap-possibly-change-server server) | 826 (when (nnimap-possibly-change-server server) |
671 (nnoo-status-message 'nnimap server))) | 827 (nnoo-status-message 'nnimap server))) |
672 | 828 |
673 (defun nnimap-demule (string) | 829 (defun nnimap-demule (string) |
830 ;; BEWARE: we used to use string-as-multibyte here which is braindead | |
831 ;; because it will turn accidental emacs-mule-valid byte sequences | |
832 ;; into multibyte chars. --Stef | |
833 ;; Reverted, braindead got 7.5 out of 10 on imdb, so it can't be | |
834 ;; that bad. --Simon | |
674 (funcall (if (and (fboundp 'string-as-multibyte) | 835 (funcall (if (and (fboundp 'string-as-multibyte) |
675 (subrp (symbol-function 'string-as-multibyte))) | 836 (subrp (symbol-function 'string-as-multibyte))) |
676 'string-as-multibyte | 837 'string-as-multibyte |
677 'identity) | 838 'identity) |
678 (or string ""))) | 839 (or string ""))) |
679 | 840 |
680 (defun nnimap-callback () | 841 (defun nnimap-make-callback (article gnus-callback buffer) |
681 (remove-hook 'imap-fetch-data-hook 'nnimap-callback) | 842 "Return a callback function." |
682 (with-current-buffer nnimap-callback-buffer | 843 `(lambda () |
683 (insert | 844 (nnimap-callback ,article ,gnus-callback ,buffer))) |
684 (with-current-buffer nnimap-server-buffer | 845 |
685 (nnimap-demule | 846 (defun nnimap-callback (article gnus-callback buffer) |
686 (if (imap-capability 'IMAP4rev1) | 847 (when (eq article (imap-current-message)) |
687 ;; xxx don't just use car? alist doesn't contain | 848 (remove-hook 'imap-fetch-data-hook |
688 ;; anything else now, but it might... | 849 (nnimap-make-callback article gnus-callback buffer)) |
689 (nth 2 (car (imap-message-get (imap-current-message) 'BODYDETAIL))) | 850 (with-current-buffer buffer |
690 (imap-message-get (imap-current-message) 'RFC822))))) | 851 (insert |
691 (nnheader-ms-strip-cr) | 852 (with-current-buffer nnimap-server-buffer |
692 (funcall nnimap-callback-callback-function t))) | 853 (nnimap-demule |
854 (if (imap-capability 'IMAP4rev1) | |
855 ;; xxx don't just use car? alist doesn't contain | |
856 ;; anything else now, but it might... | |
857 (nth 2 (car (imap-message-get article 'BODYDETAIL))) | |
858 (imap-message-get article 'RFC822))))) | |
859 (nnheader-ms-strip-cr) | |
860 (funcall gnus-callback t)))) | |
693 | 861 |
694 (defun nnimap-request-article-part (article part prop &optional | 862 (defun nnimap-request-article-part (article part prop &optional |
695 group server to-buffer detail) | 863 group server to-buffer detail) |
696 (when (nnimap-possibly-change-group group server) | 864 (when (nnimap-possibly-change-group group server) |
697 (let ((article (if (stringp article) | 865 (let ((article (if (stringp article) |
698 (car-safe (imap-search | 866 (car-safe (imap-search |
699 (format "HEADER Message-Id %s" article) | 867 (format "HEADER Message-Id \"%s\"" article) |
700 nnimap-server-buffer)) | 868 nnimap-server-buffer)) |
701 article))) | 869 article))) |
702 (when article | 870 (when article |
703 (gnus-message 10 "nnimap: Fetching (part of) article %d..." article) | 871 (gnus-message 10 "nnimap: Fetching (part of) article %d from %s..." |
872 article (or group imap-current-mailbox | |
873 gnus-newsgroup-name)) | |
704 (if (not nnheader-callback-function) | 874 (if (not nnheader-callback-function) |
705 (with-current-buffer (or to-buffer nntp-server-buffer) | 875 (with-current-buffer (or to-buffer nntp-server-buffer) |
706 (erase-buffer) | 876 (erase-buffer) |
707 (let ((data (imap-fetch article part prop nil | 877 (let ((data (imap-fetch article part prop nil |
708 nnimap-server-buffer))) | 878 nnimap-server-buffer))) |
709 (insert (nnimap-demule (if detail | 879 (insert (nnimap-demule (if detail |
710 (nth 2 (car data)) | 880 (nth 2 (car data)) |
711 data)))) | 881 data)))) |
712 (nnheader-ms-strip-cr) | 882 (nnheader-ms-strip-cr) |
713 (gnus-message 10 "nnimap: Fetching (part of) article %d...done" | 883 (gnus-message |
714 article) | 884 10 "nnimap: Fetching (part of) article %d from %s...done" |
885 article (or group imap-current-mailbox gnus-newsgroup-name)) | |
715 (if (bobp) | 886 (if (bobp) |
716 (nnheader-report 'nnimap "No such article: %s" | 887 (nnheader-report 'nnimap "No such article %d in %s: %s" |
888 article (or group imap-current-mailbox | |
889 gnus-newsgroup-name) | |
717 (imap-error-text nnimap-server-buffer)) | 890 (imap-error-text nnimap-server-buffer)) |
718 (cons group article))) | 891 (cons group article))) |
719 (add-hook 'imap-fetch-data-hook 'nnimap-callback) | 892 (add-hook 'imap-fetch-data-hook |
720 (setq nnimap-callback-callback-function nnheader-callback-function | 893 (nnimap-make-callback article |
721 nnimap-callback-buffer nntp-server-buffer) | 894 nnheader-callback-function |
895 nntp-server-buffer)) | |
722 (imap-fetch-asynch article part nil nnimap-server-buffer) | 896 (imap-fetch-asynch article part nil nnimap-server-buffer) |
723 (cons group article)))))) | 897 (cons group article)))))) |
724 | 898 |
725 (deffoo nnimap-asynchronous-p () | 899 (deffoo nnimap-asynchronous-p () |
726 t) | 900 t) |
764 (max 1 (or (nth 1 info) 1)) | 938 (max 1 (or (nth 1 info) 1)) |
765 (or (nth 2 info) 0) group) | 939 (or (nth 2 info) 0) group) |
766 (nnheader-report 'nnimap "Group %s selected" group) | 940 (nnheader-report 'nnimap "Group %s selected" group) |
767 t))))) | 941 t))))) |
768 | 942 |
943 (defun nnimap-update-unseen (group &optional server) | |
944 "Update the unseen count in `nnimap-mailbox-info'." | |
945 (gnus-sethash | |
946 (gnus-group-prefixed-name group server) | |
947 (let ((old (gnus-gethash-safe (gnus-group-prefixed-name group server) | |
948 nnimap-mailbox-info))) | |
949 (list (nth 0 old) (nth 1 old) | |
950 (imap-mailbox-status group 'unseen nnimap-server-buffer) | |
951 (nth 3 old))) | |
952 nnimap-mailbox-info)) | |
953 | |
769 (defun nnimap-close-group (group &optional server) | 954 (defun nnimap-close-group (group &optional server) |
770 (with-current-buffer nnimap-server-buffer | 955 (with-current-buffer nnimap-server-buffer |
771 (when (and (imap-opened) | 956 (when (and (imap-opened) |
772 (nnimap-possibly-change-group group server)) | 957 (nnimap-possibly-change-group group server)) |
958 (nnimap-update-unseen group server) | |
773 (case nnimap-expunge-on-close | 959 (case nnimap-expunge-on-close |
774 ('always (imap-mailbox-expunge) | 960 (always (progn |
775 (imap-mailbox-close)) | 961 (imap-mailbox-expunge nnimap-close-asynchronous) |
776 ('ask (if (and (imap-search "DELETED") | 962 (unless nnimap-dont-close |
777 (gnus-y-or-n-p (format | 963 (imap-mailbox-close nnimap-close-asynchronous)))) |
778 "Expunge articles in group `%s'? " | 964 (ask (if (and (imap-search "DELETED") |
779 imap-current-mailbox))) | 965 (gnus-y-or-n-p (format "Expunge articles in group `%s'? " |
780 (progn (imap-mailbox-expunge) | 966 imap-current-mailbox))) |
781 (imap-mailbox-close)) | 967 (progn |
782 (imap-mailbox-unselect))) | 968 (imap-mailbox-expunge nnimap-close-asynchronous) |
969 (unless nnimap-dont-close | |
970 (imap-mailbox-close nnimap-close-asynchronous))) | |
971 (imap-mailbox-unselect))) | |
783 (t (imap-mailbox-unselect))) | 972 (t (imap-mailbox-unselect))) |
784 (not imap-current-mailbox)))) | 973 (not imap-current-mailbox)))) |
785 | 974 |
786 (defun nnimap-pattern-to-list-arguments (pattern) | 975 (defun nnimap-pattern-to-list-arguments (pattern) |
787 (mapcar (lambda (p) | 976 (mapcar (lambda (p) |
804 (cdr pattern) (car pattern))) | 993 (cdr pattern) (car pattern))) |
805 (or (member "\\NoSelect" (imap-mailbox-get 'list-flags mbx)) | 994 (or (member "\\NoSelect" (imap-mailbox-get 'list-flags mbx)) |
806 (let ((info (nnimap-find-minmax-uid mbx 'examine))) | 995 (let ((info (nnimap-find-minmax-uid mbx 'examine))) |
807 (when info | 996 (when info |
808 (with-current-buffer nntp-server-buffer | 997 (with-current-buffer nntp-server-buffer |
809 (insert (format "\"%s\" %d %d y\n" | 998 (insert (format "\"%s\" %d %d y\n" |
810 mbx (or (nth 2 info) 0) | 999 mbx (or (nth 2 info) 0) |
811 (max 1 (or (nth 1 info) 1))))))))))) | 1000 (max 1 (or (nth 1 info) 1))))))))))) |
812 (gnus-message 5 "nnimap: Generating active list%s...done" | 1001 (gnus-message 5 "nnimap: Generating active list%s...done" |
813 (if (> (length server) 0) (concat " for " server) "")) | 1002 (if (> (length server) 0) (concat " for " server) "")) |
814 t)) | 1003 t)) |
815 | 1004 |
816 (deffoo nnimap-request-post (&optional server) | 1005 (deffoo nnimap-request-post (&optional server) |
817 (let ((success t)) | 1006 (let ((success t)) |
818 (dolist (mbx (message-unquote-tokens | 1007 (dolist (mbx (message-unquote-tokens |
819 (message-tokenize-header | 1008 (message-tokenize-header |
820 (message-fetch-field "Newsgroups") ", ")) success) | 1009 (message-fetch-field "Newsgroups") ", ")) success) |
821 (let ((to-newsgroup (gnus-group-prefixed-name mbx gnus-command-method))) | 1010 (let ((to-newsgroup (gnus-group-prefixed-name mbx gnus-command-method))) |
822 (or (gnus-active to-newsgroup) | 1011 (or (gnus-active to-newsgroup) |
823 (gnus-activate-group to-newsgroup) | 1012 (gnus-activate-group to-newsgroup) |
824 (if (gnus-y-or-n-p (format "No such group: %s. Create it? " | 1013 (if (gnus-y-or-n-p (format "No such group: %s. Create it? " |
825 to-newsgroup)) | 1014 to-newsgroup)) |
832 (unless (nnimap-request-accept-article mbx (nth 1 gnus-command-method)) | 1021 (unless (nnimap-request-accept-article mbx (nth 1 gnus-command-method)) |
833 (setq success nil)))))) | 1022 (setq success nil)))))) |
834 | 1023 |
835 ;; Optional backend functions | 1024 ;; Optional backend functions |
836 | 1025 |
1026 (defun nnimap-string-lessp-numerical (s1 s2) | |
1027 "Return t if first arg string is less than second in numerical order." | |
1028 (cond ((string= s1 s2) | |
1029 nil) | |
1030 ((> (length s1) (length s2)) | |
1031 nil) | |
1032 ((< (length s1) (length s2)) | |
1033 t) | |
1034 ((< (string-to-number (substring s1 0 1)) | |
1035 (string-to-number (substring s2 0 1))) | |
1036 t) | |
1037 ((> (string-to-number (substring s1 0 1)) | |
1038 (string-to-number (substring s2 0 1))) | |
1039 nil) | |
1040 (t | |
1041 (nnimap-string-lessp-numerical (substring s1 1) (substring s2 1))))) | |
1042 | |
837 (deffoo nnimap-retrieve-groups (groups &optional server) | 1043 (deffoo nnimap-retrieve-groups (groups &optional server) |
838 (when (nnimap-possibly-change-server server) | 1044 (when (nnimap-possibly-change-server server) |
839 (gnus-message 5 "nnimap: Checking mailboxes...") | 1045 (gnus-message 5 "nnimap: Checking mailboxes...") |
840 (with-current-buffer nntp-server-buffer | 1046 (with-current-buffer nntp-server-buffer |
841 (erase-buffer) | 1047 (erase-buffer) |
842 (nnimap-before-find-minmax-bugworkaround) | 1048 (nnimap-before-find-minmax-bugworkaround) |
843 (dolist (group groups) | 1049 (let (asyncgroups slowgroups) |
844 (gnus-message 7 "nnimap: Checking mailbox %s" group) | 1050 (if (null nnimap-retrieve-groups-asynchronous) |
845 (or (member "\\NoSelect" | 1051 (setq slowgroups groups) |
846 (imap-mailbox-get 'list-flags group nnimap-server-buffer)) | 1052 (dolist (group groups) |
847 (let ((info (nnimap-find-minmax-uid group 'examine))) | 1053 (gnus-message 9 "nnimap: Quickly checking mailbox %s" group) |
848 (insert (format "\"%s\" %d %d y\n" group | 1054 (add-to-list (if (gnus-gethash-safe |
849 (or (nth 2 info) 0) | 1055 (gnus-group-prefixed-name group server) |
850 (max 1 (or (nth 1 info) 1)))))))) | 1056 nnimap-mailbox-info) |
1057 'asyncgroups | |
1058 'slowgroups) | |
1059 (list group (imap-mailbox-status-asynch | |
1060 group '(uidvalidity uidnext unseen) | |
1061 nnimap-server-buffer)))) | |
1062 (dolist (asyncgroup asyncgroups) | |
1063 (let ((group (nth 0 asyncgroup)) | |
1064 (tag (nth 1 asyncgroup)) | |
1065 new old) | |
1066 (when (imap-ok-p (imap-wait-for-tag tag nnimap-server-buffer)) | |
1067 (if (or (not (string= | |
1068 (nth 0 (gnus-gethash (gnus-group-prefixed-name | |
1069 group server) | |
1070 nnimap-mailbox-info)) | |
1071 (imap-mailbox-get 'uidvalidity group | |
1072 nnimap-server-buffer))) | |
1073 (not (string= | |
1074 (nth 1 (gnus-gethash (gnus-group-prefixed-name | |
1075 group server) | |
1076 nnimap-mailbox-info)) | |
1077 (imap-mailbox-get 'uidnext group | |
1078 nnimap-server-buffer)))) | |
1079 (push (list group) slowgroups) | |
1080 (insert (nth 3 (gnus-gethash (gnus-group-prefixed-name | |
1081 group server) | |
1082 nnimap-mailbox-info)))))))) | |
1083 (dolist (group slowgroups) | |
1084 (if nnimap-retrieve-groups-asynchronous | |
1085 (setq group (car group))) | |
1086 (gnus-message 7 "nnimap: Mailbox %s modified" group) | |
1087 (imap-mailbox-put 'uidnext nil group nnimap-server-buffer) | |
1088 (or (member "\\NoSelect" (imap-mailbox-get 'list-flags group | |
1089 nnimap-server-buffer)) | |
1090 (let* ((info (nnimap-find-minmax-uid group 'examine)) | |
1091 (str (format "\"%s\" %d %d y\n" group | |
1092 (or (nth 2 info) 0) | |
1093 (max 1 (or (nth 1 info) 1))))) | |
1094 (when (> (or (imap-mailbox-get 'recent group | |
1095 nnimap-server-buffer) 0) | |
1096 0) | |
1097 (push (list (cons group 0)) nnmail-split-history)) | |
1098 (insert str) | |
1099 (when nnimap-retrieve-groups-asynchronous | |
1100 (gnus-sethash | |
1101 (gnus-group-prefixed-name group server) | |
1102 (list (or (imap-mailbox-get | |
1103 'uidvalidity group nnimap-server-buffer) | |
1104 (imap-mailbox-status | |
1105 group 'uidvalidity nnimap-server-buffer)) | |
1106 (or (imap-mailbox-get | |
1107 'uidnext group nnimap-server-buffer) | |
1108 (imap-mailbox-status | |
1109 group 'uidnext nnimap-server-buffer)) | |
1110 (or (imap-mailbox-get | |
1111 'unseen group nnimap-server-buffer) | |
1112 (imap-mailbox-status | |
1113 group 'unseen nnimap-server-buffer)) | |
1114 str) | |
1115 nnimap-mailbox-info))))))) | |
851 (gnus-message 5 "nnimap: Checking mailboxes...done") | 1116 (gnus-message 5 "nnimap: Checking mailboxes...done") |
852 'active)) | 1117 'active)) |
853 | 1118 |
854 (deffoo nnimap-request-update-info-internal (group info &optional server) | 1119 (deffoo nnimap-request-update-info-internal (group info &optional server) |
855 (when (nnimap-possibly-change-group group server) | 1120 (when (nnimap-possibly-change-group group server) |
856 (when info;; xxx what does this mean? should we create a info? | 1121 (when info ;; xxx what does this mean? should we create a info? |
857 (with-current-buffer nnimap-server-buffer | 1122 (with-current-buffer nnimap-server-buffer |
858 (gnus-message 5 "nnimap: Updating info for %s..." | 1123 (gnus-message 5 "nnimap: Updating info for %s..." |
859 (gnus-info-group info)) | 1124 (gnus-info-group info)) |
860 | 1125 |
861 (when (nnimap-mark-permanent-p 'read) | 1126 (when (nnimap-mark-permanent-p 'read) |
879 (list (cons (car seen) (car seen))) | 1144 (list (cons (car seen) (car seen))) |
880 seen)) | 1145 seen)) |
881 (gnus-info-set-read info seen))) | 1146 (gnus-info-set-read info seen))) |
882 | 1147 |
883 (mapcar (lambda (pred) | 1148 (mapcar (lambda (pred) |
884 (when (and (nnimap-mark-permanent-p (cdr pred)) | 1149 (when (or (eq (cdr pred) 'recent) |
885 (member (nnimap-mark-to-flag (cdr pred)) | 1150 (and (nnimap-mark-permanent-p (cdr pred)) |
886 (imap-mailbox-get 'flags))) | 1151 (member (nnimap-mark-to-flag (cdr pred)) |
1152 (imap-mailbox-get 'flags)))) | |
887 (gnus-info-set-marks | 1153 (gnus-info-set-marks |
888 info | 1154 info |
889 (nnimap-update-alist-soft | 1155 (gnus-update-alist-soft |
890 (cdr pred) | 1156 (cdr pred) |
891 (gnus-compress-sequence | 1157 (gnus-compress-sequence |
892 (imap-search (nnimap-mark-to-predicate (cdr pred)))) | 1158 (imap-search (nnimap-mark-to-predicate (cdr pred)))) |
893 (gnus-info-marks info)) | 1159 (gnus-info-marks info)) |
894 t))) | 1160 t))) |
895 gnus-article-mark-lists) | 1161 gnus-article-mark-lists) |
896 | 1162 |
897 ;; nnimap mark dormant article as ticked too (for other clients) | 1163 (when nnimap-importantize-dormant |
898 ;; so we remove that mark for gnus since we support dormant | 1164 ;; nnimap mark dormant article as ticked too (for other clients) |
899 (gnus-info-set-marks | 1165 ;; so we remove that mark for gnus since we support dormant |
900 info | 1166 (gnus-info-set-marks |
901 (nnimap-update-alist-soft | 1167 info |
902 'tick | 1168 (gnus-update-alist-soft |
903 (gnus-remove-from-range | 1169 'tick |
904 (cdr-safe (assoc 'tick (gnus-info-marks info))) | 1170 (gnus-remove-from-range |
905 (cdr-safe (assoc 'dormant (gnus-info-marks info)))) | 1171 (cdr-safe (assoc 'tick (gnus-info-marks info))) |
906 (gnus-info-marks info)) | 1172 (cdr-safe (assoc 'dormant (gnus-info-marks info)))) |
907 t) | 1173 (gnus-info-marks info)) |
1174 t)) | |
908 | 1175 |
909 (gnus-message 5 "nnimap: Updating info for %s...done" | 1176 (gnus-message 5 "nnimap: Updating info for %s...done" |
910 (gnus-info-group info)) | 1177 (gnus-info-group info)) |
911 | 1178 |
912 info)))) | 1179 info)))) |
924 (while (setq action (pop actions)) | 1191 (while (setq action (pop actions)) |
925 (let ((range (nth 0 action)) | 1192 (let ((range (nth 0 action)) |
926 (what (nth 1 action)) | 1193 (what (nth 1 action)) |
927 (cmdmarks (nth 2 action)) | 1194 (cmdmarks (nth 2 action)) |
928 marks) | 1195 marks) |
1196 ;; bookmark can't be stored (not list/range | |
1197 (setq cmdmarks (delq 'bookmark cmdmarks)) | |
1198 ;; killed can't be stored (not list/range | |
1199 (setq cmdmarks (delq 'killed cmdmarks)) | |
1200 ;; unsent are for nndraft groups only | |
1201 (setq cmdmarks (delq 'unsent cmdmarks)) | |
929 ;; cache flags are pointless on the server | 1202 ;; cache flags are pointless on the server |
930 (setq cmdmarks (delq 'cache cmdmarks)) | 1203 (setq cmdmarks (delq 'cache cmdmarks)) |
931 ;; flag dormant articles as ticked | 1204 ;; seen flags are local to each gnus |
932 (if (memq 'dormant cmdmarks) | 1205 (setq cmdmarks (delq 'seen cmdmarks)) |
933 (setq cmdmarks (cons 'tick cmdmarks))) | 1206 ;; recent marks can't be set |
1207 (setq cmdmarks (delq 'recent cmdmarks)) | |
1208 (when nnimap-importantize-dormant | |
1209 ;; flag dormant articles as ticked | |
1210 (if (memq 'dormant cmdmarks) | |
1211 (setq cmdmarks (cons 'tick cmdmarks)))) | |
934 ;; remove stuff we are forbidden to store | 1212 ;; remove stuff we are forbidden to store |
935 (mapcar (lambda (mark) | 1213 (mapcar (lambda (mark) |
936 (if (imap-message-flag-permanent-p | 1214 (if (imap-message-flag-permanent-p |
937 (nnimap-mark-to-flag mark)) | 1215 (nnimap-mark-to-flag mark)) |
938 (setq marks (cons mark marks)))) | 1216 (setq marks (cons mark marks)))) |
952 (nnimap-mark-to-flag marks nil t))))))) | 1230 (nnimap-mark-to-flag marks nil t))))))) |
953 (gnus-message 7 "nnimap: Setting marks in %s...done" group)))) | 1231 (gnus-message 7 "nnimap: Setting marks in %s...done" group)))) |
954 nil) | 1232 nil) |
955 | 1233 |
956 (defun nnimap-split-fancy () | 1234 (defun nnimap-split-fancy () |
957 "Like nnmail-split-fancy, but uses nnimap-split-fancy." | 1235 "Like the function `nnmail-split-fancy', but uses `nnimap-split-fancy'." |
958 (let ((nnmail-split-fancy nnimap-split-fancy)) | 1236 (let ((nnmail-split-fancy nnimap-split-fancy)) |
959 (nnmail-split-fancy))) | 1237 (nnmail-split-fancy))) |
960 | 1238 |
961 (defun nnimap-split-to-groups (rules) | 1239 (defun nnimap-split-to-groups (rules) |
962 ;; tries to match all rules in nnimap-split-rule against content of | 1240 ;; tries to match all rules in nnimap-split-rule against content of |
974 (let ((group (car rule)) | 1252 (let ((group (car rule)) |
975 (regexp (cadr rule))) | 1253 (regexp (cadr rule))) |
976 (goto-char (point-min)) | 1254 (goto-char (point-min)) |
977 (when (and (if (stringp regexp) | 1255 (when (and (if (stringp regexp) |
978 (progn | 1256 (progn |
979 (setq regrepp (string-match "\\\\[0-9&]" group)) | 1257 (if (not (stringp group)) |
1258 (setq group (eval group)) | |
1259 (setq regrepp | |
1260 (string-match "\\\\[0-9&]" group))) | |
980 (re-search-forward regexp nil t)) | 1261 (re-search-forward regexp nil t)) |
981 (funcall regexp group)) | 1262 (funcall regexp group)) |
982 ;; Don't enter the article into the same group twice. | 1263 ;; Don't enter the article into the same group twice. |
983 (not (assoc group to-groups))) | 1264 (not (assoc group to-groups))) |
984 (push (if regrepp | 1265 (push (if regrepp |
996 (setq alist (cdr alist))) | 1277 (setq alist (cdr alist))) |
997 element)) | 1278 element)) |
998 | 1279 |
999 (defun nnimap-split-find-rule (server inbox) | 1280 (defun nnimap-split-find-rule (server inbox) |
1000 (if (and (listp nnimap-split-rule) (listp (car nnimap-split-rule)) | 1281 (if (and (listp nnimap-split-rule) (listp (car nnimap-split-rule)) |
1001 (list (cdar nnimap-split-rule)) (listp (cadar nnimap-split-rule))) | 1282 (list (cdar nnimap-split-rule)) (listp (cadar nnimap-split-rule))) |
1002 ;; extended format | 1283 ;; extended format |
1003 (cadr (nnimap-assoc-match inbox (cdr (nnimap-assoc-match | 1284 (cadr (nnimap-assoc-match inbox (cdr (nnimap-assoc-match |
1004 server nnimap-split-rule)))) | 1285 server nnimap-split-rule)))) |
1005 nnimap-split-rule)) | 1286 nnimap-split-rule)) |
1006 | 1287 |
1013 (when (nnimap-possibly-change-server server) | 1294 (when (nnimap-possibly-change-server server) |
1014 (with-current-buffer nnimap-server-buffer | 1295 (with-current-buffer nnimap-server-buffer |
1015 (let (rule inbox removeorig (inboxes (nnimap-split-find-inbox server))) | 1296 (let (rule inbox removeorig (inboxes (nnimap-split-find-inbox server))) |
1016 ;; iterate over inboxes | 1297 ;; iterate over inboxes |
1017 (while (and (setq inbox (pop inboxes)) | 1298 (while (and (setq inbox (pop inboxes)) |
1018 (nnimap-possibly-change-group inbox));; SELECT | 1299 (nnimap-possibly-change-group inbox)) ;; SELECT |
1019 ;; find split rule for this server / inbox | 1300 ;; find split rule for this server / inbox |
1020 (when (setq rule (nnimap-split-find-rule server inbox)) | 1301 (when (setq rule (nnimap-split-find-rule server inbox)) |
1021 ;; iterate over articles | 1302 ;; iterate over articles |
1022 (dolist (article (imap-search nnimap-split-predicate)) | 1303 (dolist (article (imap-search nnimap-split-predicate)) |
1023 (when (nnimap-request-head article) | 1304 (when (if (if (eq nnimap-split-download-body 'default) |
1305 nnimap-split-download-body-default | |
1306 nnimap-split-download-body) | |
1307 (and (nnimap-request-article article) | |
1308 (with-current-buffer nntp-server-buffer (mail-narrow-to-head))) | |
1309 (nnimap-request-head article)) | |
1024 ;; copy article to right group(s) | 1310 ;; copy article to right group(s) |
1025 (setq removeorig nil) | 1311 (setq removeorig nil) |
1026 (dolist (to-group (nnimap-split-to-groups rule)) | 1312 (dolist (to-group (nnimap-split-to-groups rule)) |
1027 (if (imap-message-copy (number-to-string article) | 1313 (cond ((eq to-group 'junk) |
1028 to-group nil 'nocopyuid) | 1314 (message "IMAP split removed %s:%s:%d" server inbox |
1029 (progn | 1315 article) |
1030 (message "IMAP split moved %s:%s:%d to %s" server inbox | 1316 (setq removeorig t)) |
1031 article to-group) | 1317 ((imap-message-copy (number-to-string article) |
1032 (setq removeorig t) | 1318 to-group nil 'nocopyuid) |
1033 ;; Add the group-art list to the history list. | 1319 (message "IMAP split moved %s:%s:%d to %s" server |
1034 (push (list (cons to-group 0)) nnmail-split-history)) | 1320 inbox article to-group) |
1035 (message "IMAP split failed to move %s:%s:%d to %s" server | 1321 (setq removeorig t) |
1036 inbox article to-group))) | 1322 (when nnmail-cache-accepted-message-ids |
1323 (with-current-buffer nntp-server-buffer | |
1324 (let (msgid) | |
1325 (and (setq msgid | |
1326 (nnmail-fetch-field "message-id")) | |
1327 (nnmail-cache-insert msgid | |
1328 to-group | |
1329 (nnmail-fetch-field "subject")))))) | |
1330 ;; Add the group-art list to the history list. | |
1331 (push (list (cons to-group 0)) nnmail-split-history)) | |
1332 (t | |
1333 (message "IMAP split failed to move %s:%s:%d to %s" | |
1334 server inbox article to-group)))) | |
1335 (if (if (eq nnimap-split-download-body 'default) | |
1336 nnimap-split-download-body-default | |
1337 nnimap-split-download-body) | |
1338 (widen)) | |
1037 ;; remove article if it was successfully copied somewhere | 1339 ;; remove article if it was successfully copied somewhere |
1038 (and removeorig | 1340 (and removeorig |
1039 (imap-message-flags-add (format "%d" article) | 1341 (imap-message-flags-add (format "%d" article) |
1040 "\\Seen \\Deleted"))))) | 1342 "\\Seen \\Deleted"))))) |
1041 (when (imap-mailbox-select inbox);; just in case | 1343 (when (imap-mailbox-select inbox) ;; just in case |
1042 ;; todo: UID EXPUNGE (if available) to remove splitted articles | 1344 ;; todo: UID EXPUNGE (if available) to remove splitted articles |
1043 (imap-mailbox-expunge) | 1345 (imap-mailbox-expunge) |
1044 (imap-mailbox-close))) | 1346 (imap-mailbox-close))) |
1347 (when nnmail-cache-accepted-message-ids | |
1348 (nnmail-cache-close)) | |
1045 t)))) | 1349 t)))) |
1046 | 1350 |
1047 (deffoo nnimap-request-scan (&optional group server) | 1351 (deffoo nnimap-request-scan (&optional group server) |
1048 (nnimap-split-articles group server)) | 1352 (nnimap-split-articles group server)) |
1049 | 1353 |
1054 (if (> (length server) 0) " on " "") server) | 1358 (if (> (length server) 0) " on " "") server) |
1055 (erase-buffer) | 1359 (erase-buffer) |
1056 (nnimap-before-find-minmax-bugworkaround) | 1360 (nnimap-before-find-minmax-bugworkaround) |
1057 (dolist (pattern (nnimap-pattern-to-list-arguments | 1361 (dolist (pattern (nnimap-pattern-to-list-arguments |
1058 nnimap-list-pattern)) | 1362 nnimap-list-pattern)) |
1059 (dolist (mbx (imap-mailbox-lsub "*" (car pattern) nil | 1363 (dolist (mbx (imap-mailbox-lsub (cdr pattern) (car pattern) nil |
1060 nnimap-server-buffer)) | 1364 nnimap-server-buffer)) |
1061 (or (catch 'found | 1365 (or (catch 'found |
1062 (dolist (mailbox (imap-mailbox-get 'list-flags mbx | 1366 (dolist (mailbox (imap-mailbox-get 'list-flags mbx |
1063 nnimap-server-buffer)) | 1367 nnimap-server-buffer)) |
1064 (if (string= (downcase mailbox) "\\noselect") | 1368 (if (string= (downcase mailbox) "\\noselect") |
1065 (throw 'found t))) | 1369 (throw 'found t))) |
1066 nil) | 1370 nil) |
1067 (let ((info (nnimap-find-minmax-uid mbx 'examine))) | 1371 (let ((info (nnimap-find-minmax-uid mbx 'examine))) |
1068 (when info | 1372 (when info |
1069 (insert (format "\"%s\" %d %d y\n" | 1373 (insert (format "\"%s\" %d %d y\n" |
1070 mbx (or (nth 2 info) 0) | 1374 mbx (or (nth 2 info) 0) |
1071 (max 1 (or (nth 1 info) 1))))))))) | 1375 (max 1 (or (nth 1 info) 1))))))))) |
1072 (gnus-message 5 "nnimap: Listing subscribed mailboxes%s%s...done" | 1376 (gnus-message 5 "nnimap: Listing subscribed mailboxes%s%s...done" |
1073 (if (> (length server) 0) " on " "") server)) | 1377 (if (> (length server) 0) " on " "") server)) |
1074 t)) | 1378 t)) |
1075 | 1379 |
1076 (deffoo nnimap-request-create-group (group &optional server args) | 1380 (deffoo nnimap-request-create-group (group &optional server args) |
1077 (when (nnimap-possibly-change-server server) | 1381 (when (nnimap-possibly-change-server server) |
1078 (or (imap-mailbox-status group 'uidvalidity nnimap-server-buffer) | 1382 (or (imap-mailbox-status group 'uidvalidity nnimap-server-buffer) |
1079 (imap-mailbox-create group nnimap-server-buffer)))) | 1383 (imap-mailbox-create group nnimap-server-buffer) |
1384 (nnheader-report 'nnimap "%S" | |
1385 (imap-error-text nnimap-server-buffer))))) | |
1080 | 1386 |
1081 (defun nnimap-time-substract (time1 time2) | 1387 (defun nnimap-time-substract (time1 time2) |
1082 "Return TIME for TIME1 - TIME2." | 1388 "Return TIME for TIME1 - TIME2." |
1083 (let* ((ms (- (car time1) (car time2))) | 1389 (let* ((ms (- (car time1) (car time2))) |
1084 (ls (- (nth 1 time1) (nth 1 time2)))) | 1390 (ls (- (nth 1 time1) (nth 1 time2)))) |
1085 (if (< ls 0) | 1391 (if (< ls 0) |
1086 (list (- ms 1) (+ (expt 2 16) ls)) | 1392 (list (- ms 1) (+ (expt 2 16) ls)) |
1087 (list ms ls)))) | 1393 (list ms ls)))) |
1088 | 1394 |
1395 (eval-when-compile (require 'parse-time)) | |
1089 (defun nnimap-date-days-ago (daysago) | 1396 (defun nnimap-date-days-ago (daysago) |
1090 "Return date, in format \"3-Aug-1998\", for DAYSAGO days ago." | 1397 "Return date, in format \"3-Aug-1998\", for DAYSAGO days ago." |
1398 (require 'parse-time) | |
1091 (let* ((time (nnimap-time-substract (current-time) (days-to-time daysago))) | 1399 (let* ((time (nnimap-time-substract (current-time) (days-to-time daysago))) |
1092 (date (format-time-string | 1400 (date (format-time-string |
1093 (format "%%d-%s-%%Y" | 1401 (format "%%d-%s-%%Y" |
1094 (capitalize (car (rassoc (nth 4 (decode-time time)) | 1402 (capitalize (car (rassoc (nth 4 (decode-time time)) |
1095 parse-time-months)))) | 1403 parse-time-months)))) |
1100 | 1408 |
1101 (defun nnimap-request-expire-articles-progress () | 1409 (defun nnimap-request-expire-articles-progress () |
1102 (gnus-message 5 "nnimap: Marking article %d for deletion..." | 1410 (gnus-message 5 "nnimap: Marking article %d for deletion..." |
1103 imap-current-message)) | 1411 imap-current-message)) |
1104 | 1412 |
1413 (defun nnimap-expiry-target (arts group server) | |
1414 (unless (eq nnmail-expiry-target 'delete) | |
1415 (with-temp-buffer | |
1416 (dolist (art arts) | |
1417 (nnimap-request-article art group server (current-buffer)) | |
1418 ;; hints for optimization in `nnimap-request-accept-article' | |
1419 (let ((nnimap-current-move-article art) | |
1420 (nnimap-current-move-group group) | |
1421 (nnimap-current-move-server server)) | |
1422 (nnmail-expiry-target-group nnmail-expiry-target group)))) | |
1423 ;; It is not clear if `nnmail-expiry-target' somehow cause the | |
1424 ;; current group to be changed or not, so we make sure here. | |
1425 (nnimap-possibly-change-group group server))) | |
1426 | |
1105 ;; Notice that we don't actually delete anything, we just mark them deleted. | 1427 ;; Notice that we don't actually delete anything, we just mark them deleted. |
1106 (deffoo nnimap-request-expire-articles (articles group &optional server force) | 1428 (deffoo nnimap-request-expire-articles (articles group &optional server force) |
1107 (let ((artseq (gnus-compress-sequence articles))) | 1429 (let ((artseq (gnus-compress-sequence articles))) |
1108 (when (and artseq (nnimap-possibly-change-group group server)) | 1430 (when (and artseq (nnimap-possibly-change-group group server)) |
1109 (with-current-buffer nnimap-server-buffer | 1431 (with-current-buffer nnimap-server-buffer |
1110 (if force | 1432 (let ((days (or (and nnmail-expiry-wait-function |
1111 (and (imap-message-flags-add | 1433 (funcall nnmail-expiry-wait-function group)) |
1112 (imap-range-to-message-set artseq) "\\Deleted") | 1434 nnmail-expiry-wait))) |
1113 (setq articles nil)) | 1435 (cond ((or force (eq days 'immediate)) |
1114 (let ((days (or (and nnmail-expiry-wait-function | 1436 (let ((oldarts (imap-search |
1115 (funcall nnmail-expiry-wait-function group)) | 1437 (concat "UID " |
1116 nnmail-expiry-wait))) | 1438 (imap-range-to-message-set artseq))))) |
1117 (cond ((eq days 'immediate) | 1439 (when oldarts |
1118 (and (imap-message-flags-add | 1440 (nnimap-expiry-target oldarts group server) |
1119 (imap-range-to-message-set artseq) "\\Deleted") | 1441 (when (imap-message-flags-add |
1120 (setq articles nil))) | 1442 (imap-range-to-message-set |
1121 ((numberp days) | 1443 (gnus-compress-sequence oldarts)) "\\Deleted") |
1122 (let ((oldarts (imap-search | 1444 (setq articles (gnus-set-difference |
1123 (format "UID %s NOT SINCE %s" | 1445 articles oldarts)))))) |
1124 (imap-range-to-message-set artseq) | 1446 ((and nnimap-search-uids-not-since-is-evil (numberp days)) |
1125 (nnimap-date-days-ago days)))) | 1447 (let* ((all-new-articles |
1126 (imap-fetch-data-hook | 1448 (gnus-compress-sequence |
1127 '(nnimap-request-expire-articles-progress))) | 1449 (imap-search (format "SINCE %s" |
1128 (and oldarts | 1450 (nnimap-date-days-ago days))))) |
1129 (imap-message-flags-add | 1451 (oldartseq |
1130 (imap-range-to-message-set | 1452 (gnus-range-difference artseq all-new-articles)) |
1131 (gnus-compress-sequence oldarts)) | 1453 (oldarts (gnus-uncompress-range oldartseq))) |
1132 "\\Deleted") | 1454 (when oldarts |
1133 (setq articles (gnus-set-difference | 1455 (nnimap-expiry-target oldarts group server) |
1134 articles oldarts))))))))))) | 1456 (when (imap-message-flags-add |
1457 (imap-range-to-message-set oldartseq) | |
1458 "\\Deleted") | |
1459 (setq articles (gnus-set-difference | |
1460 articles oldarts)))))) | |
1461 ((numberp days) | |
1462 (let ((oldarts (imap-search | |
1463 (format nnimap-expunge-search-string | |
1464 (imap-range-to-message-set artseq) | |
1465 (nnimap-date-days-ago days)))) | |
1466 (imap-fetch-data-hook | |
1467 '(nnimap-request-expire-articles-progress))) | |
1468 (when oldarts | |
1469 (nnimap-expiry-target oldarts group server) | |
1470 (when (imap-message-flags-add | |
1471 (imap-range-to-message-set | |
1472 (gnus-compress-sequence oldarts)) "\\Deleted") | |
1473 (setq articles (gnus-set-difference | |
1474 articles oldarts))))))))))) | |
1135 ;; return articles not deleted | 1475 ;; return articles not deleted |
1136 articles) | 1476 articles) |
1137 | 1477 |
1138 (deffoo nnimap-request-move-article (article group server | 1478 (deffoo nnimap-request-move-article (article group server |
1139 accept-form &optional last) | 1479 accept-form &optional last) |
1150 (buffer-disable-undo (current-buffer)) | 1490 (buffer-disable-undo (current-buffer)) |
1151 (insert-buffer-substring nntp-server-buffer) | 1491 (insert-buffer-substring nntp-server-buffer) |
1152 (setq result (eval accept-form)) | 1492 (setq result (eval accept-form)) |
1153 (kill-buffer buf) | 1493 (kill-buffer buf) |
1154 result) | 1494 result) |
1155 (nnimap-request-expire-articles (list article) group server t)) | 1495 (imap-message-flags-add |
1496 (imap-range-to-message-set (list article)) | |
1497 "\\Deleted" 'silent nnimap-server-buffer)) | |
1156 result)))) | 1498 result)))) |
1157 | 1499 |
1158 (deffoo nnimap-request-accept-article (group &optional server last) | 1500 (deffoo nnimap-request-accept-article (group &optional server last) |
1159 (when (nnimap-possibly-change-server server) | 1501 (when (nnimap-possibly-change-server server) |
1160 (let (uid) | 1502 (let (uid) |
1170 (with-current-buffer (current-buffer) | 1512 (with-current-buffer (current-buffer) |
1171 (goto-char (point-min)) | 1513 (goto-char (point-min)) |
1172 ;; remove any 'From blabla' lines, some IMAP servers | 1514 ;; remove any 'From blabla' lines, some IMAP servers |
1173 ;; reject the entire message otherwise. | 1515 ;; reject the entire message otherwise. |
1174 (when (looking-at "^From[^:]") | 1516 (when (looking-at "^From[^:]") |
1175 (kill-region (point) (progn (forward-line) (point)))) | 1517 (delete-region (point) (progn (forward-line) (point)))) |
1176 ;; turn into rfc822 format (\r\n eol's) | 1518 ;; turn into rfc822 format (\r\n eol's) |
1177 (while (search-forward "\n" nil t) | 1519 (while (search-forward "\n" nil t) |
1178 (replace-match "\r\n"))) | 1520 (replace-match "\r\n")) |
1179 ;; this 'or' is for Cyrus server bug | 1521 (when nnmail-cache-accepted-message-ids |
1180 (or (null (imap-current-mailbox nnimap-server-buffer)) | 1522 (nnmail-cache-insert (nnmail-fetch-field "message-id") |
1181 (imap-mailbox-unselect nnimap-server-buffer)) | 1523 group |
1524 (nnmail-fetch-field "subject")))) | |
1525 (when (and last nnmail-cache-accepted-message-ids) | |
1526 (nnmail-cache-close)) | |
1527 ;; this 'or' is for Cyrus server bug | |
1528 (or (null (imap-current-mailbox nnimap-server-buffer)) | |
1529 (imap-mailbox-unselect nnimap-server-buffer)) | |
1182 (imap-message-append group (current-buffer) nil nil | 1530 (imap-message-append group (current-buffer) nil nil |
1183 nnimap-server-buffer))) | 1531 nnimap-server-buffer))) |
1184 (cons group (nth 1 uid)) | 1532 (cons group (nth 1 uid)) |
1185 (nnheader-report 'nnimap (imap-error-text nnimap-server-buffer)))))) | 1533 (nnheader-report 'nnimap (imap-error-text nnimap-server-buffer)))))) |
1186 | 1534 |
1197 (when (nnimap-possibly-change-server server) | 1545 (when (nnimap-possibly-change-server server) |
1198 (imap-mailbox-rename group new-name nnimap-server-buffer))) | 1546 (imap-mailbox-rename group new-name nnimap-server-buffer))) |
1199 | 1547 |
1200 (defun nnimap-expunge (mailbox server) | 1548 (defun nnimap-expunge (mailbox server) |
1201 (when (nnimap-possibly-change-group mailbox server) | 1549 (when (nnimap-possibly-change-group mailbox server) |
1202 (imap-mailbox-expunge nnimap-server-buffer))) | 1550 (imap-mailbox-expunge nil nnimap-server-buffer))) |
1203 | 1551 |
1204 (defun nnimap-acl-get (mailbox server) | 1552 (defun nnimap-acl-get (mailbox server) |
1205 (when (nnimap-possibly-change-server server) | 1553 (when (nnimap-possibly-change-server server) |
1206 (and (imap-capability 'ACL nnimap-server-buffer) | 1554 (and (imap-capability 'ACL nnimap-server-buffer) |
1207 (imap-mailbox-acl-get mailbox nnimap-server-buffer)))) | 1555 (imap-mailbox-acl-get mailbox nnimap-server-buffer)))) |
1245 | 1593 |
1246 (defconst nnimap-mark-to-predicate-alist | 1594 (defconst nnimap-mark-to-predicate-alist |
1247 (mapcar | 1595 (mapcar |
1248 (lambda (pair) ; cdr is the mark | 1596 (lambda (pair) ; cdr is the mark |
1249 (or (assoc (cdr pair) | 1597 (or (assoc (cdr pair) |
1250 '((read . "SEEN") | 1598 '((read . "SEEN") |
1251 (tick . "FLAGGED") | 1599 (tick . "FLAGGED") |
1252 (draft . "DRAFT") | 1600 (draft . "DRAFT") |
1253 (reply . "ANSWERED"))) | 1601 (recent . "RECENT") |
1254 (cons (cdr pair) | 1602 (reply . "ANSWERED"))) |
1255 (format "KEYWORD gnus-%s" (symbol-name (cdr pair)))))) | 1603 (cons (cdr pair) |
1604 (format "KEYWORD gnus-%s" (symbol-name (cdr pair)))))) | |
1256 (cons '(read . read) gnus-article-mark-lists))) | 1605 (cons '(read . read) gnus-article-mark-lists))) |
1257 | 1606 |
1258 (defun nnimap-mark-to-predicate (pred) | 1607 (defun nnimap-mark-to-predicate (pred) |
1259 "Convert a Gnus mark (a symbol such as read, tick, expire) to a IMAP predicate. | 1608 "Convert a Gnus mark (a symbol such as read, tick, expire) to a IMAP predicate. |
1260 This is a string such as \"SEEN\", \"FLAGGED\", \"KEYWORD gnus-expire\", | 1609 This is a string such as \"SEEN\", \"FLAGGED\", \"KEYWORD gnus-expire\", |
1263 | 1612 |
1264 (defconst nnimap-mark-to-flag-alist | 1613 (defconst nnimap-mark-to-flag-alist |
1265 (mapcar | 1614 (mapcar |
1266 (lambda (pair) | 1615 (lambda (pair) |
1267 (or (assoc (cdr pair) | 1616 (or (assoc (cdr pair) |
1268 '((read . "\\Seen") | 1617 '((read . "\\Seen") |
1269 (tick . "\\Flagged") | 1618 (tick . "\\Flagged") |
1270 (draft . "\\Draft") | 1619 (draft . "\\Draft") |
1271 (reply . "\\Answered"))) | 1620 (recent . "\\Recent") |
1272 (cons (cdr pair) | 1621 (reply . "\\Answered"))) |
1273 (format "gnus-%s" (symbol-name (cdr pair)))))) | 1622 (cons (cdr pair) |
1623 (format "gnus-%s" (symbol-name (cdr pair)))))) | |
1274 (cons '(read . read) gnus-article-mark-lists))) | 1624 (cons '(read . read) gnus-article-mark-lists))) |
1275 | 1625 |
1276 (defun nnimap-mark-to-flag-1 (preds) | 1626 (defun nnimap-mark-to-flag-1 (preds) |
1277 (if (and (not (null preds)) (listp preds)) | 1627 (if (and (not (null preds)) (listp preds)) |
1278 (cons (nnimap-mark-to-flag (car preds)) | 1628 (cons (nnimap-mark-to-flag (car preds)) |
1298 | 1648 |
1299 (defun nnimap-mark-permanent-p (mark &optional group) | 1649 (defun nnimap-mark-permanent-p (mark &optional group) |
1300 "Return t iff MARK can be permanently (between IMAP sessions) saved on articles, in GROUP." | 1650 "Return t iff MARK can be permanently (between IMAP sessions) saved on articles, in GROUP." |
1301 (imap-message-flag-permanent-p (nnimap-mark-to-flag mark))) | 1651 (imap-message-flag-permanent-p (nnimap-mark-to-flag mark))) |
1302 | 1652 |
1303 (defun nnimap-remassoc (key alist) | |
1304 "Delete by side effect any elements of LIST whose car is `equal' to KEY. | |
1305 The modified LIST is returned. If the first member | |
1306 of LIST has a car that is `equal' to KEY, there is no way to remove it | |
1307 by side effect; therefore, write `(setq foo (remassoc key foo))' to be | |
1308 sure of changing the value of `foo'." | |
1309 (when alist | |
1310 (if (equal key (caar alist)) | |
1311 (cdr alist) | |
1312 (setcdr alist (nnimap-remassoc key (cdr alist))) | |
1313 alist))) | |
1314 | |
1315 (defun nnimap-update-alist-soft (key value alist) | |
1316 (if value | |
1317 (cons (cons key value) (nnimap-remassoc key alist)) | |
1318 (nnimap-remassoc key alist))) | |
1319 | |
1320 (when nnimap-debug | 1653 (when nnimap-debug |
1321 (require 'trace) | 1654 (require 'trace) |
1322 (buffer-disable-undo (get-buffer-create nnimap-debug)) | 1655 (buffer-disable-undo (get-buffer-create nnimap-debug-buffer)) |
1323 (mapcar (lambda (f) (trace-function-background f nnimap-debug)) | 1656 (mapcar (lambda (f) (trace-function-background f nnimap-debug-buffer)) |
1324 '( | 1657 '( |
1325 nnimap-possibly-change-server | 1658 nnimap-possibly-change-server |
1326 nnimap-verify-uidvalidity | 1659 nnimap-verify-uidvalidity |
1327 nnimap-find-minmax-uid | 1660 nnimap-find-minmax-uid |
1328 nnimap-before-find-minmax-bugworkaround | 1661 nnimap-before-find-minmax-bugworkaround |
1329 nnimap-possibly-change-group | 1662 nnimap-possibly-change-group |
1330 ;;nnimap-replace-whitespace | 1663 ;;nnimap-replace-whitespace |
1331 nnimap-retrieve-headers-progress | 1664 nnimap-retrieve-headers-progress |
1332 nnimap-retrieve-which-headers | 1665 nnimap-retrieve-which-headers |
1333 nnimap-group-overview-filename | 1666 nnimap-group-overview-filename |
1334 nnimap-retrieve-headers-from-file | 1667 nnimap-retrieve-headers-from-file |
1335 nnimap-retrieve-headers-from-server | 1668 nnimap-retrieve-headers-from-server |
1336 nnimap-retrieve-headers | 1669 nnimap-retrieve-headers |
1337 nnimap-open-connection | 1670 nnimap-open-connection |
1338 nnimap-open-server | 1671 nnimap-open-server |
1339 nnimap-server-opened | 1672 nnimap-server-opened |
1340 nnimap-close-server | 1673 nnimap-close-server |
1341 nnimap-request-close | 1674 nnimap-request-close |
1342 nnimap-status-message | 1675 nnimap-status-message |
1343 ;;nnimap-demule | 1676 ;;nnimap-demule |
1344 nnimap-request-article-part | 1677 nnimap-request-article-part |
1345 nnimap-request-article | 1678 nnimap-request-article |
1346 nnimap-request-head | 1679 nnimap-request-head |
1347 nnimap-request-body | 1680 nnimap-request-body |
1348 nnimap-request-group | 1681 nnimap-request-group |
1349 nnimap-close-group | 1682 nnimap-close-group |
1350 nnimap-pattern-to-list-arguments | 1683 nnimap-pattern-to-list-arguments |
1351 nnimap-request-list | 1684 nnimap-request-list |
1352 nnimap-request-post | 1685 nnimap-request-post |
1353 nnimap-retrieve-groups | 1686 nnimap-retrieve-groups |
1354 nnimap-request-update-info-internal | 1687 nnimap-request-update-info-internal |
1355 nnimap-request-type | 1688 nnimap-request-type |
1356 nnimap-request-set-mark | 1689 nnimap-request-set-mark |
1357 nnimap-split-to-groups | 1690 nnimap-split-to-groups |
1358 nnimap-split-find-rule | 1691 nnimap-split-find-rule |
1359 nnimap-split-find-inbox | 1692 nnimap-split-find-inbox |
1360 nnimap-split-articles | 1693 nnimap-split-articles |
1361 nnimap-request-scan | 1694 nnimap-request-scan |
1362 nnimap-request-newgroups | 1695 nnimap-request-newgroups |
1363 nnimap-request-create-group | 1696 nnimap-request-create-group |
1364 nnimap-time-substract | 1697 nnimap-time-substract |
1365 nnimap-date-days-ago | 1698 nnimap-date-days-ago |
1366 nnimap-request-expire-articles-progress | 1699 nnimap-request-expire-articles-progress |
1367 nnimap-request-expire-articles | 1700 nnimap-request-expire-articles |
1368 nnimap-request-move-article | 1701 nnimap-request-move-article |
1369 nnimap-request-accept-article | 1702 nnimap-request-accept-article |
1370 nnimap-request-delete-group | 1703 nnimap-request-delete-group |
1371 nnimap-request-rename-group | 1704 nnimap-request-rename-group |
1372 gnus-group-nnimap-expunge | 1705 gnus-group-nnimap-expunge |
1373 gnus-group-nnimap-edit-acl | 1706 gnus-group-nnimap-edit-acl |
1374 gnus-group-nnimap-edit-acl-done | 1707 gnus-group-nnimap-edit-acl-done |
1375 nnimap-group-mode-hook | 1708 nnimap-group-mode-hook |
1376 nnimap-mark-to-predicate | 1709 nnimap-mark-to-predicate |
1377 nnimap-mark-to-flag-1 | 1710 nnimap-mark-to-flag-1 |
1378 nnimap-mark-to-flag | 1711 nnimap-mark-to-flag |
1379 nnimap-mark-permanent-p | 1712 nnimap-mark-permanent-p |
1380 nnimap-remassoc | 1713 ))) |
1381 nnimap-update-alist-soft | |
1382 ))) | |
1383 | 1714 |
1384 (provide 'nnimap) | 1715 (provide 'nnimap) |
1385 | 1716 |
1717 ;; arch-tag: 2b001f20-3ff9-4094-a0ad-46807c1ba70b | |
1386 ;;; nnimap.el ends here | 1718 ;;; nnimap.el ends here |