1 ;;; nnimap.el --- IMAP interface for Gnus
3 ;; Copyright (C) 2010 Free Software Foundation, Inc.
5 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
6 ;; Simon Josefsson <simon@josefsson.org>
8 ;; This file is part of GNU Emacs.
10 ;; GNU Emacs is free software: you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation, either version 3 of the License, or
13 ;; (at your option) any later version.
15 ;; GNU Emacs is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;; GNU General Public License for more details.
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
25 ;; nnimap interfaces Gnus with IMAP servers.
43 (autoload 'auth-source-forget-user-or-password "auth-source")
44 (autoload 'auth-source-user-or-password "auth-source")
48 (defvoo nnimap-address nil
49 "The address of the IMAP server.")
51 (defvoo nnimap-server-port nil
53 If nnimap-stream is `ssl', this will default to `imaps'. If not,
54 it will default to `imap'.")
56 (defvoo nnimap-stream 'ssl
57 "How nnimap will talk to the IMAP server.
58 Values are `ssl', `network', `starttls' or `shell'.")
60 (defvoo nnimap-shell-program (if (boundp 'imap-shell-program)
61 (if (listp imap-shell-program)
62 (car imap-shell-program)
66 (defvoo nnimap-inbox nil
67 "The mail box where incoming mail arrives and should be split out of.")
69 (defvoo nnimap-split-methods nil
71 Uses the same syntax as nnmail-split-methods")
73 (make-obsolete-variable 'nnimap-split-rule "see `nnimap-split-methods'"
76 (defvoo nnimap-authenticator nil
77 "How nnimap authenticate itself to the server.
78 Possible choices are nil (use default methods) or `anonymous'.")
80 (defvoo nnimap-expunge t
81 "If non-nil, expunge articles after deleting them.
82 This is always done if the server supports UID EXPUNGE, but it's
83 not done by default on servers that doesn't support that command.")
85 (defvoo nnimap-streaming t
86 "If non-nil, try to use streaming commands with IMAP servers.
87 Switching this off will make nnimap slower, but it helps with
90 (defvoo nnimap-connection-alist nil)
92 (defvoo nnimap-current-infos nil)
94 (defvoo nnimap-fetch-partial-articles nil
95 "If non-nil, Gnus will fetch partial articles.
96 If t, nnimap will fetch only the first part. If a string, it
97 will fetch all parts that have types that match that string. A
98 likely value would be \"text/\" to automatically fetch all
101 (defvar nnimap-process nil)
103 (defvar nnimap-status-string "")
105 (defvar nnimap-split-download-body-default nil
106 "Internal variable with default value for `nnimap-split-download-body'.")
108 (defvar nnimap-keepalive-timer nil)
109 (defvar nnimap-process-buffers nil)
112 group process commands capabilities select-result newlinep server
113 last-command-time greeting)
115 (defvar nnimap-object nil)
117 (defvar nnimap-mark-alist
118 '((read "\\Seen" %Seen)
119 (tick "\\Flagged" %Flagged)
120 (reply "\\Answered" %Answered)
121 (expire "gnus-expire")
122 (dormant "gnus-dormant")
125 (download "gnus-download")
126 (forward "gnus-forward")))
128 (defun nnimap-buffer ()
129 (nnimap-find-process-buffer nntp-server-buffer))
131 (deffoo nnimap-retrieve-headers (articles &optional group server fetch-old)
132 (with-current-buffer nntp-server-buffer
134 (when (nnimap-possibly-change-group group server)
135 (with-current-buffer (nnimap-buffer)
137 (nnimap-wait-for-response
140 (nnimap-article-ranges (gnus-compress-sequence articles))
141 (format "(UID RFC822.SIZE BODYSTRUCTURE %s)"
144 "BODY.PEEK[HEADER.FIELDS %s]"
145 "RFC822.HEADER.LINES %s")
146 (append '(Subject From Date Message-Id
147 References In-Reply-To Xref)
148 nnmail-extra-headers))))
150 (nnimap-transform-headers))
151 (insert-buffer-substring
152 (nnimap-find-process-buffer (current-buffer))))
155 (defun nnimap-transform-headers ()
156 (goto-char (point-min))
157 (let (article bytes lines size string)
160 (while (not (looking-at "^\\* [0-9]+ FETCH.*UID \\([0-9]+\\)"))
161 (delete-region (point) (progn (forward-line 1) (point)))
164 (setq article (match-string 1))
165 ;; Unfold quoted {number} strings.
166 (while (re-search-forward "[^]] {\\([0-9]+\\)}\r\n"
167 (1+ (line-end-position)) t)
168 (setq size (string-to-number (match-string 1)))
169 (delete-region (+ (match-beginning 0) 2) (point))
170 (setq string (delete-region (point) (+ (point) size)))
171 (insert (format "%S" string)))
172 (setq bytes (nnimap-get-length)
176 (and (re-search-forward "RFC822.SIZE \\([0-9]+\\)"
181 (when (search-forward "BODYSTRUCTURE" (line-end-position) t)
182 (let ((structure (ignore-errors
183 (read (current-buffer)))))
184 (while (and (consp structure)
185 (not (stringp (car structure))))
186 (setq structure (car structure)))
187 (setq lines (nth 7 structure))))
188 (delete-region (line-beginning-position) (line-end-position))
189 (insert (format "211 %s Article retrieved." article))
192 (insert (format "Chars: %s\n" size)))
194 (insert (format "Lines: %s\n" lines)))
195 (re-search-forward "^\r$")
196 (delete-region (line-beginning-position) (line-end-position))
200 (defun nnimap-get-length ()
201 (and (re-search-forward "{\\([0-9]+\\)}" (line-end-position) t)
202 (string-to-number (match-string 1))))
204 (defun nnimap-article-ranges (ranges)
208 (number-to-string ranges))
209 ((numberp (cdr ranges))
210 (format "%d:%d" (car ranges) (cdr ranges)))