;;; nnimap.el --- imap backend for Gnus
-;; Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
-;; Free Software Foundation, Inc.
+
+;; Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+;; 2005, 2006, 2007 Free Software Foundation, Inc.
;; Author: Simon Josefsson <jas@pdc.kth.se>
;; Jim Radford <radford@robby.caltech.edu>
;; GNU Emacs is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 2, or (at your option)
+;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to the
-;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
;;; Commentary:
"Whether to download entire articles during splitting.
This is generally not required, and will slow things down considerably.
You may need it if you want to use an advanced splitting function that
-analyses the body before splitting the article.
+analyzes the body before splitting the article.
If this variable is nil, bodies will not be downloaded; if this
-variable is the symbol `default' the default behaviour is
+variable is the symbol `default' the default behavior is
used (which currently is nil, unless you use a statistical
spam.el test); if this variable is another non-nil value bodies
will be downloaded."
:type 'boolean
:group 'nnimap)
-(defvoo nnimap-need-unselect-to-notice-new-mail nil
+(defvoo nnimap-need-unselect-to-notice-new-mail t
"Unselect mailboxes before looking for new mail in them.
Some servers seem to need this under some circumstances.")
+(defvoo nnimap-logout-timeout nil
+ "Close server immediately if it can't logout in this number of seconds.
+If it is nil, never close server until logout completes. This variable
+overrides `imap-logout-timeout' on a per-server basis.")
+
;; Authorization / Privacy variables
(defvoo nnimap-auth-method nil
Unlike other backends, you do not need to take special care if you
flip this variable.")
+(defvoo nnimap-search-uids-not-since-is-evil nil
+ "If non-nil, avoid \"UID SEARCH UID ... NOT SINCE\" queries when expiring.
+Instead, use \"UID SEARCH SINCE\" to prune the list of expirable
+articles within Gnus. This seems to be faster on Courier in some cases.")
+
(defvoo nnimap-expunge-on-close 'always ; 'ask, 'never
"Whether to expunge a group when it is closed.
When a IMAP group with articles marked for deletion is closed, this
One useful (and perhaps the only useful) value to change this to would
be `UID %s NOT SENTSINCE %s' to make nnimap use the Date: header
instead of the internal date of messages. See section 6.4.4 of RFC
-2060 for more information on valid strings.")
+2060 for more information on valid strings.
+
+However, if `nnimap-search-uids-not-since-is-evil' is true, this
+variable has no effect since the search logic is reversed.")
(defvoo nnimap-importantize-dormant t
"If non-nil, mark \"dormant\" articles as \"ticked\" for other IMAP clients.
(format "BODY.PEEK[HEADER.FIELDS %s])" headers)
(format "RFC822.HEADER.LINES %s)" headers)))))
(with-current-buffer nntp-server-buffer
- (sort-numeric-fields 1 1 (buffer-size)))
+ (sort-numeric-fields 1 (point-min) (point-max)))
(and (numberp nnmail-large-newsgroup)
(> nnimap-length nnmail-large-newsgroup)
(nnheader-message 6 "nnimap: Retrieving headers...done")))))
'nov)))
(defun nnimap-open-connection (server)
+ ;; Note: `nnimap-open-server' that calls this function binds
+ ;; `imap-logout-timeout' to `nnimap-logout-timeout'.
(if (not (imap-open nnimap-address nnimap-server-port nnimap-stream
nnimap-authenticator nnimap-server-buffer))
(nnheader-report 'nnimap "Can't open connection to server %s" server)
(imap-capability 'IMAP4rev1 nnimap-server-buffer))
(imap-close nnimap-server-buffer)
(nnheader-report 'nnimap "Server %s is not IMAP4 compliant" server))
- (let* ((list (netrc-parse nnimap-authinfo-file))
+ (let* ((list (progn (gnus-message 7 "Parsing authinfo file `%s'."
+ nnimap-authinfo-file)
+ (netrc-parse nnimap-authinfo-file)))
(port (if nnimap-server-port
(int-to-string nnimap-server-port)
"imap"))
- (user (netrc-machine-user-or-password
+ (user (netrc-machine-user-or-password
"login"
list
(list server
nnimap-address))
(list port)
(list "imap" "imaps")))
- (passwd (netrc-machine-user-or-password
+ (passwd (netrc-machine-user-or-password
"password"
list
(list server
(if (imap-authenticate user passwd nnimap-server-buffer)
(prog2
(setq nnimap-server-buffer-alist
- (nnimap-remove-server-from-buffer-alist
+ (nnimap-remove-server-from-buffer-alist
server
nnimap-server-buffer-alist))
(push (list server nnimap-server-buffer)
(setq nnimap-server-buffer (cadr (assq 'nnimap-server-buffer defs))))
(with-current-buffer (get-buffer-create nnimap-server-buffer)
(nnoo-change-server 'nnimap server defs))
- (or (and nnimap-server-buffer
- (imap-opened nnimap-server-buffer)
- (if (with-current-buffer nnimap-server-buffer
- (memq imap-state '(auth selected examine)))
- t
- (imap-close nnimap-server-buffer)
- (nnimap-open-connection server)))
- (nnimap-open-connection server))))
+ (let ((imap-logout-timeout nnimap-logout-timeout))
+ (or (and nnimap-server-buffer
+ (imap-opened nnimap-server-buffer)
+ (if (with-current-buffer nnimap-server-buffer
+ (memq imap-state '(auth selected examine)))
+ t
+ (imap-close nnimap-server-buffer)
+ (nnimap-open-connection server)))
+ (nnimap-open-connection server)))))
(deffoo nnimap-server-opened (&optional server)
"Whether SERVER is opened.
(deffoo nnimap-close-server (&optional server)
"Close connection to server and free all resources connected to it.
Return nil if the server couldn't be closed for some reason."
- (let ((server (or server nnimap-current-server)))
+ (let ((server (or server nnimap-current-server))
+ (imap-logout-timeout nnimap-logout-timeout))
(when (or (nnimap-server-opened server)
(imap-opened (nnimap-get-server-buffer server)))
(imap-close (nnimap-get-server-buffer server))
(setq nnimap-server-buffer nil
nnimap-current-server nil
nnimap-server-buffer-alist
- (nnimap-remove-server-from-buffer-alist
+ (nnimap-remove-server-from-buffer-alist
server
nnimap-server-buffer-alist)))
(nnoo-close-server 'nnimap server)))
(let (seen unseen)
;; read info could contain articles marked unread by other
;; imap clients! we correct this
- (setq seen (gnus-uncompress-range (gnus-info-read info))
- unseen (imap-search "UNSEEN UNDELETED")
- seen (gnus-set-difference seen unseen)
- ;; seen might lack articles marked as read by other
- ;; imap clients! we correct this
- seen (append seen (imap-search "SEEN"))
- ;; remove dupes
- seen (sort seen '<)
- seen (gnus-compress-sequence seen t)
- ;; we can't return '(1) since this isn't a "list of ranges",
- ;; and we can't return '((1)) since g-list-of-unread-articles
- ;; is buggy so we return '((1 . 1)).
+ (setq unseen (gnus-compress-sequence
+ (imap-search "UNSEEN UNDELETED"))
+ seen (gnus-range-difference (gnus-info-read info) unseen)
+ seen (gnus-range-add seen
+ (gnus-compress-sequence
+ (imap-search "SEEN")))
seen (if (and (integerp (car seen))
(null (cdr seen)))
(list (cons (car seen) (car seen)))
seen))
(gnus-info-set-read info seen)))
- (mapcar (lambda (pred)
- (when (or (eq (cdr pred) 'recent)
- (and (nnimap-mark-permanent-p (cdr pred))
- (member (nnimap-mark-to-flag (cdr pred))
- (imap-mailbox-get 'flags))))
- (gnus-info-set-marks
- info
- (gnus-update-alist-soft
- (cdr pred)
- (gnus-compress-sequence
- (imap-search (nnimap-mark-to-predicate (cdr pred))))
- (gnus-info-marks info))
- t)))
- gnus-article-mark-lists)
+ (dolist (pred gnus-article-mark-lists)
+ (when (or (eq (cdr pred) 'recent)
+ (and (nnimap-mark-permanent-p (cdr pred))
+ (member (nnimap-mark-to-flag (cdr pred))
+ (imap-mailbox-get 'flags))))
+ (gnus-info-set-marks
+ info
+ (gnus-update-alist-soft
+ (cdr pred)
+ (gnus-compress-sequence
+ (imap-search (nnimap-mark-to-predicate (cdr pred))))
+ (gnus-info-marks info))
+ t)))
(when nnimap-importantize-dormant
;; nnimap mark dormant article as ticked too (for other clients)
(list (- ms 1) (+ (expt 2 16) ls))
(list ms ls))))
+(eval-when-compile (require 'parse-time))
(defun nnimap-date-days-ago (daysago)
"Return date, in format \"3-Aug-1998\", for DAYSAGO days ago."
+ (require 'parse-time)
(let* ((time (nnimap-time-substract (current-time) (days-to-time daysago)))
(date (format-time-string
(format "%%d-%s-%%Y"
(gnus-compress-sequence oldarts)) "\\Deleted")
(setq articles (gnus-set-difference
articles oldarts))))))
+ ((and nnimap-search-uids-not-since-is-evil (numberp days))
+ (let* ((all-new-articles
+ (gnus-compress-sequence
+ (imap-search (format "SINCE %s"
+ (nnimap-date-days-ago days)))))
+ (oldartseq
+ (gnus-range-difference artseq all-new-articles))
+ (oldarts (gnus-uncompress-range oldartseq)))
+ (when oldarts
+ (nnimap-expiry-target oldarts group server)
+ (when (imap-message-flags-add
+ (imap-range-to-message-set oldartseq)
+ "\\Deleted")
+ (setq articles (gnus-set-difference
+ articles oldarts))))))
((numberp days)
(let ((oldarts (imap-search
(format nnimap-expunge-search-string
;; return articles not deleted
articles)
-(deffoo nnimap-request-move-article (article group server accept-form
+(deffoo nnimap-request-move-article (article group server accept-form
&optional last move-is-internal)
(when (nnimap-possibly-change-server server)
(save-excursion
(setq result (eval accept-form))
(kill-buffer buf)
result)
+ (nnimap-possibly-change-group group server)
(imap-message-flags-add
(imap-range-to-message-set (list article))
"\\Deleted" 'silent nnimap-server-buffer))
result)))
(defun nnimap-mark-permanent-p (mark &optional group)
- "Return t iff MARK can be permanently (between IMAP sessions) saved on articles, in GROUP."
+ "Return t if MARK can be permanently (between IMAP sessions) saved on articles, in GROUP."
(imap-message-flag-permanent-p (nnimap-mark-to-flag mark)))
(when nnimap-debug
(require 'trace)
(buffer-disable-undo (get-buffer-create nnimap-debug-buffer))
- (mapcar (lambda (f) (trace-function-background f nnimap-debug-buffer))
- '(
- nnimap-possibly-change-server
- nnimap-verify-uidvalidity
- nnimap-find-minmax-uid
- nnimap-before-find-minmax-bugworkaround
- nnimap-possibly-change-group
- ;;nnimap-replace-whitespace
- nnimap-retrieve-headers-progress
- nnimap-retrieve-which-headers
- nnimap-group-overview-filename
- nnimap-retrieve-headers-from-file
- nnimap-retrieve-headers-from-server
- nnimap-retrieve-headers
- nnimap-open-connection
- nnimap-open-server
- nnimap-server-opened
- nnimap-close-server
- nnimap-request-close
- nnimap-status-message
- ;;nnimap-demule
- nnimap-request-article-part
- nnimap-request-article
- nnimap-request-head
- nnimap-request-body
- nnimap-request-group
- nnimap-close-group
- nnimap-pattern-to-list-arguments
- nnimap-request-list
- nnimap-request-post
- nnimap-retrieve-groups
- nnimap-request-update-info-internal
- nnimap-request-type
- nnimap-request-set-mark
- nnimap-split-to-groups
- nnimap-split-find-rule
- nnimap-split-find-inbox
- nnimap-split-articles
- nnimap-request-scan
- nnimap-request-newgroups
- nnimap-request-create-group
- nnimap-time-substract
- nnimap-date-days-ago
- nnimap-request-expire-articles-progress
- nnimap-request-expire-articles
- nnimap-request-move-article
- nnimap-request-accept-article
- nnimap-request-delete-group
- nnimap-request-rename-group
- gnus-group-nnimap-expunge
- gnus-group-nnimap-edit-acl
- gnus-group-nnimap-edit-acl-done
- nnimap-group-mode-hook
- nnimap-mark-to-predicate
- nnimap-mark-to-flag-1
- nnimap-mark-to-flag
- nnimap-mark-permanent-p
- )))
+ (mapc (lambda (f) (trace-function-background f nnimap-debug-buffer))
+ '(
+ nnimap-possibly-change-server
+ nnimap-verify-uidvalidity
+ nnimap-find-minmax-uid
+ nnimap-before-find-minmax-bugworkaround
+ nnimap-possibly-change-group
+ ;;nnimap-replace-whitespace
+ nnimap-retrieve-headers-progress
+ nnimap-retrieve-which-headers
+ nnimap-group-overview-filename
+ nnimap-retrieve-headers-from-file
+ nnimap-retrieve-headers-from-server
+ nnimap-retrieve-headers
+ nnimap-open-connection
+ nnimap-open-server
+ nnimap-server-opened
+ nnimap-close-server
+ nnimap-request-close
+ nnimap-status-message
+ ;;nnimap-demule
+ nnimap-request-article-part
+ nnimap-request-article
+ nnimap-request-head
+ nnimap-request-body
+ nnimap-request-group
+ nnimap-close-group
+ nnimap-pattern-to-list-arguments
+ nnimap-request-list
+ nnimap-request-post
+ nnimap-retrieve-groups
+ nnimap-request-update-info-internal
+ nnimap-request-type
+ nnimap-request-set-mark
+ nnimap-split-to-groups
+ nnimap-split-find-rule
+ nnimap-split-find-inbox
+ nnimap-split-articles
+ nnimap-request-scan
+ nnimap-request-newgroups
+ nnimap-request-create-group
+ nnimap-time-substract
+ nnimap-date-days-ago
+ nnimap-request-expire-articles-progress
+ nnimap-request-expire-articles
+ nnimap-request-move-article
+ nnimap-request-accept-article
+ nnimap-request-delete-group
+ nnimap-request-rename-group
+ gnus-group-nnimap-expunge
+ gnus-group-nnimap-edit-acl
+ gnus-group-nnimap-edit-acl-done
+ nnimap-group-mode-hook
+ nnimap-mark-to-predicate
+ nnimap-mark-to-flag-1
+ nnimap-mark-to-flag
+ nnimap-mark-permanent-p
+ )))
(provide 'nnimap)