This is always done if the server supports UID EXPUNGE, but it's
not done by default on servers that doesn't support that command.")
+(defvoo nnimap-authenticator nil
+ "How nnimap authenticate itself to the server.
+Possible choices are nil (use default methods) or `anonymous'.")
+
+(defvoo nnimap-fetch-partial-articles nil
+ "If non-nil, nnimap will fetch partial articles.
+If t, nnimap will fetch only the first part. If a string, it
+will fetch all parts that have types that match that string. A
+likely value would be \"text/\" to automatically fetch all
+textual parts.")
+
(defvoo nnimap-connection-alist nil)
(defvoo nnimap-current-infos nil)
(defun nnimap-transform-headers ()
(goto-char (point-min))
- (let (article bytes lines)
+ (let (article bytes lines size)
(block nil
(while (not (eobp))
(while (not (looking-at "^\\* [0-9]+ FETCH.*UID \\([0-9]+\\)"))
bytes (nnimap-get-length)
lines nil)
(beginning-of-line)
+ (setq size
+ (and (re-search-forward "RFC822.SIZE \\([0-9]+\\)"
+ (line-end-position)
+ t)
+ (match-string 1)))
+ (beginning-of-line)
(when (search-forward "BODYSTRUCTURE" (line-end-position) t)
(let ((structure (ignore-errors (read (current-buffer)))))
(while (and (consp structure)
(delete-region (line-beginning-position) (line-end-position))
(insert (format "211 %s Article retrieved." article))
(forward-line 1)
- (insert (format "Bytes: %d\n" bytes))
+ (when size
+ (insert (format "Chars: %s\n" size)))
(when lines
(insert (format "Lines: %s\n" lines)))
(re-search-forward "^\r$")
(when (setq connection-result (nnimap-wait-for-connection))
(unless (equal connection-result "PREAUTH")
(if (not (setq credentials
- (nnimap-credentials nnimap-address ports)))
+ (if (eq nnimap-authenticator 'anonymous)
+ (list "anonymous"
+ (message-make-address))
+ (nnimap-credentials
+ nnimap-address
+ (if nnimap-server-port
+ (cons (format "%s" nnimap-server-port) ports)
+ ports)))))
(setq nnimap-object nil)
(setq login-result (nnimap-command "LOGIN %S %S"
(car credentials)
(deffoo nnimap-request-article (article &optional group server to-buffer)
(with-current-buffer nntp-server-buffer
- (let ((result (nnimap-possibly-change-group group server)))
+ (let ((result (nnimap-possibly-change-group group server))
+ parts)
(when (stringp article)
(setq article (nnimap-find-article-by-message-id group article)))
(when (and result
(erase-buffer)
(with-current-buffer (nnimap-buffer)
(erase-buffer)
+ (when nnimap-fetch-partial-articles
+ (if (eq nnimap-fetch-partial-articles t)
+ (setq parts '(1))
+ (nnimap-command "UID FETCH %d (BODYSTRUCTURE)" article)
+ (goto-char (point-min))
+ (when (re-search-forward "FETCH.*BODYSTRUCTURE" nil t)
+ (let ((structure (ignore-errors (read (current-buffer)))))
+ (setq parts (nnimap-find-wanted-parts structure))))))
(setq result
(nnimap-command
(if (member "IMAP4REV1" (nnimap-capabilities nnimap-object))
(goto-char (+ (point) bytes))
(delete-region (point) (point-max))
(nnheader-ms-strip-cr))
- t)))))))
+ (cons group article))))))))
+
+(defun nnimap-find-wanted-parts (structure)
+ (message-flatten-list (nnimap-find-wanted-parts-1 structure "")))
+
+(defun nnimap-find-wanted-parts-1 (structure prefix)
+ (let ((num 1)
+ parts)
+ (while (consp (car structure))
+ (let ((sub (pop structure)))
+ (if (consp (car sub))
+ (push (nnimap-find-wanted-parts-1
+ sub (if (string= prefix "")
+ (number-to-string num)
+ (format "%s.%s" prefix num)))
+ parts)
+ (let ((type (format "%s/%s" (nth 0 sub) (nth 1 sub))))
+ (when (string-match nnimap-fetch-partial-articles type)
+ (push (if (string= prefix "")
+ (number-to-string num)
+ (format "%s.%s" prefix num))
+ parts)))
+ (incf num))))
+ (nreverse parts)))
(deffoo nnimap-request-group (group &optional server dont-check info)
- (with-current-buffer nntp-server-buffer
- (let ((result (nnimap-possibly-change-group group server))
- articles active marks high low)
+ (let ((result (nnimap-possibly-change-group group server))
+ articles active marks high low)
+ (with-current-buffer nntp-server-buffer
(when result
(if (and dont-check
(setq active (nth 2 (assoc group nnimap-current-infos))))
(with-current-buffer (nnimap-buffer)
(erase-buffer)
(let ((group-sequence
- (nnimap-send-command "SELECT %S" (utf7-encode group)))
+ (nnimap-send-command "SELECT %S" (utf7-encode group t)))
(flag-sequence
(nnimap-send-command "UID FETCH 1:* FLAGS")))
(nnimap-wait-for-response flag-sequence)
(setq high (nth 3 (car marks))
low (nth 4 (car marks))))
((re-search-backward "UIDNEXT \\([0-9]+\\)" nil t)
- (setq high (string-to-number (match-string 1))
+ (setq high (1- (string-to-number (match-string 1)))
low 1)))))
(erase-buffer)
(insert
(format
- "211 %d %d %d %S\n"
- (1+ (- high low))
- low high group))))
+ "211 %d %d %d %S\n" (1+ (- high low)) low high group))))
t)))
+(deffoo nnimap-request-create-group (group &optional server args)
+ (when (nnimap-possibly-change-group nil server)
+ (with-current-buffer (nnimap-buffer)
+ (car (nnimap-command "CREATE %S" (utf7-encode group t))))))
+
+(deffoo nnimap-request-delete-group (group &optional force server)
+ (when (nnimap-possibly-change-group nil server)
+ (with-current-buffer (nnimap-buffer)
+ (car (nnimap-command "DELETE %S" (utf7-encode group t))))))
+
+(deffoo nnimap-request-expunge-group (group &optional server)
+ (when (nnimap-possibly-change-group group server)
+ (with-current-buffer (nnimap-buffer)
+ (car (nnimap-command "EXPUNGE")))))
+
(defun nnimap-get-flags (spec)
(let ((articles nil)
elems)
(nnimap-find-article-by-message-id
internal-move-group message-id))))
(with-temp-buffer
- (let ((result (eval accept-form)))
- (when result
- (nnimap-delete-article article)
- result)))))))
+ (when (nnimap-request-article article group server (current-buffer))
+ (let ((result (eval accept-form)))
+ (when result
+ (nnimap-delete-article article)
+ result))))))))
(deffoo nnimap-request-expire-articles (articles group &optional server force)
(cond
((not (nnimap-possibly-change-group group server))
articles)
- (force
+ ((and force
+ (eq nnmail-expiry-target 'delete))
(unless (nnimap-delete-article articles)
(message "Article marked for deletion, but not expunged."))
nil)
(mapconcat #'identity flags " ")))))))
;; Wait for the last command to complete to avoid later
;; syncronisation problems with the stream.
- (nnimap-wait-for-response sequence)))))
+ (when sequence
+ (nnimap-wait-for-response sequence))))))
(deffoo nnimap-request-accept-article (group &optional server last)
(when (nnimap-possibly-change-group nil server)
(if (equal (caar response) "OK")
(cons t response)
(nnheader-report 'nnimap "%s"
- (mapconcat #'identity (car response) " "))
+ (mapconcat (lambda (a)
+ (format "%s" a))
+ (car response) " "))
nil)))
(defun nnimap-get-response (sequence)
(goto-char (point-min))
(while (and (memq (process-status process)
'(open run))
- (not (re-search-forward "^\\* " nil t)))
+ (not (re-search-forward "^\\* .*\n" nil t)))
(nnheader-accept-process-output process)
(goto-char (point-min)))
- (and (looking-at "[A-Z0-9]+")
- (match-string 0))))
+ (forward-line -1)
+ (and (looking-at "\\* \\([A-Z0-9]+\\)")
+ (match-string 1))))
(defun nnimap-wait-for-response (sequence &optional messagep)
- (goto-char (point-max))
- (while (not (re-search-backward (format "^%d .*\n" sequence)
- (max (point-min) (- (point) 500))
- t))
- (when messagep
- (message "Read %dKB" (/ (buffer-size) 1000)))
- (nnheader-accept-process-output (get-buffer-process (current-buffer)))
- (goto-char (point-max))))
+ (let ((process (get-buffer-process (current-buffer))))
+ (goto-char (point-max))
+ (while (and (memq (process-status process)
+ '(open run))
+ (not (re-search-backward (format "^%d .*\n" sequence)
+ (max (point-min) (- (point) 500))
+ t)))
+ (when messagep
+ (message "Read %dKB" (/ (buffer-size) 1000)))
+ (nnheader-accept-process-output process)
+ (goto-char (point-max)))))
(defun nnimap-parse-response ()
(let ((lines (split-string (nnimap-last-response-string) "\r\n" t))
"BODY.PEEK[HEADER] BODY.PEEK"
"RFC822.PEEK"))
(if nnimap-split-download-body-default
- ""
+ "[]"
"[1]")))
t))