it will default to `imap'.")
(defvoo nnimap-stream 'undecided
- "How nnimap will talk to the IMAP server.
-Values are `ssl', `network', `starttls' or `shell'.
-The default is to try `ssl' first, and then `network'.")
+ "How nnimap talks to the IMAP server.
+The value should be either `undecided', `ssl' or `tls',
+`network', `starttls', `plain', or `shell'.
+
+If the value is `undecided', nnimap tries `ssl' first, then falls
+back on `network'.")
(defvoo nnimap-shell-program (if (boundp 'imap-shell-program)
(if (listp imap-shell-program)
"ssh %s imapd"))
(defvoo nnimap-inbox nil
- "The mail box where incoming mail arrives and should be split out of.")
+ "The mail box where incoming mail arrives and should be split out of.
+For example, \"INBOX\".")
(defvoo nnimap-split-methods nil
"How mail is split.
-Uses the same syntax as nnmail-split-methods")
+Uses the same syntax as `nnmail-split-methods'.")
(defvoo nnimap-split-fancy nil
- "Uses the same syntax as nnmail-split-fancy.")
+ "Uses the same syntax as `nnmail-split-fancy'.")
(defvoo nnimap-unsplittable-articles '(%Deleted %Seen)
"Articles with the flags in the list will not be considered when splitting.")
(current-buffer)))
(defun nnimap-credentials (address ports)
- (let ((found (nth 0 (auth-source-search :max 1
- :host address
- :port ports
- :create t))))
+ (let* ((auth-source-creation-prompts
+ '((user . "IMAP user at %h: ")
+ (secret . "IMAP password for %u@%h: ")))
+ (found (nth 0 (auth-source-search :max 1
+ :host address
+ :port ports
+ :require '(:user :secret)
+ :create t))))
(if found
(list (plist-get found :user)
(let ((secret (plist-get found :secret)))
(if (functionp secret)
(funcall secret)
- secret)))
+ secret))
+ (plist-get found :save-function))
nil)))
(defun nnimap-keepalive ()
(port nil)
(ports
(cond
- ((or (eq nnimap-stream 'network)
- (eq nnimap-stream 'starttls))
+ ((memq nnimap-stream '(network plain starttls))
(nnheader-message 7 "Opening connection to %s..."
nnimap-address)
- '("143" "imap"))
+ '("imap" "143"))
((eq nnimap-stream 'shell)
(nnheader-message 7 "Opening connection to %s via shell..."
nnimap-address)
((memq nnimap-stream '(ssl tls))
(nnheader-message 7 "Opening connection to %s via tls..."
nnimap-address)
- '("143" "993" "imap" "imaps"))
+ '("imaps" "imap" "993" "143"))
(t
(error "Unknown stream type: %s" nnimap-stream))))
- (proto-stream-always-use-starttls t)
login-result credentials)
(when nnimap-server-port
- (setq ports (append ports (list nnimap-server-port))))
- (destructuring-bind (stream greeting capabilities stream-type)
- (open-protocol-stream
- "*nnimap*" (current-buffer) nnimap-address (car (last ports))
- :type nnimap-stream
- :shell-command nnimap-shell-program
- :capability-command "1 CAPABILITY\r\n"
- :success " OK "
- :starttls-function
- (lambda (capabilities)
- (when (gnus-string-match-p "STARTTLS" capabilities)
- "1 STARTTLS\r\n")))
+ (push nnimap-server-port ports))
+ (let* ((stream-list
+ (open-protocol-stream
+ "*nnimap*" (current-buffer) nnimap-address (car ports)
+ :type nnimap-stream
+ :return-list t
+ :shell-command nnimap-shell-program
+ :capability-command "1 CAPABILITY\r\n"
+ :success " OK "
+ :starttls-function
+ (lambda (capabilities)
+ (when (gnus-string-match-p "STARTTLS" capabilities)
+ "1 STARTTLS\r\n"))))
+ (stream (car stream-list))
+ (props (cdr stream-list))
+ (greeting (plist-get props :greeting))
+ (capabilities (plist-get props :capabilities))
+ (stream-type (plist-get props :type)))
+ (when (and stream (not (memq (process-status stream) '(open run))))
+ (setq stream nil))
(setf (nnimap-process nnimap-object) stream)
(setf (nnimap-stream-type nnimap-object) stream-type)
(if (not stream)
(let ((nnimap-inhibit-logging t))
(setq login-result
(nnimap-login (car credentials) (cadr credentials))))
- (unless (car login-result)
+ (if (car login-result)
+ (progn
+ ;; Save the credentials if a save function exists
+ ;; (such a function will only be passed if a new
+ ;; token was created).
+ (when (functionp (nth 2 credentials))
+ (funcall (nth 2 credentials)))
+ ;; See if CAPABILITY is set as part of login
+ ;; response.
+ (dolist (response (cddr login-result))
+ (when (string= "CAPABILITY" (upcase (car response)))
+ (setf (nnimap-capabilities nnimap-object)
+ (mapcar #'upcase (cdr response))))))
;; If the login failed, then forget the credentials
;; that are now possibly cached.
(dolist (host (list (nnoo-current-server 'nnimap)
(setf (nnimap-examined nnimap-object) group)
(if (and qresyncp
uidvalidity
+ active
modseq)
(push
(list (nnimap-send-command "EXAMINE %S (%s (%s %s))"
;; Change \Delete etc to %Delete, so that the reader can read it.
(subst-char-in-region (point-min) (point-max)
?\\ ?% t)
+ ;; Remove any MODSEQ entries in the buffer, because they may contain
+ ;; numbers that are too large for 32-bit Emacsen.
+ (while (re-search-forward " MODSEQ ([0-9]+)" nil t)
+ (replace-match "" t t))
+ (goto-char (point-min))
(let (start end articles groups uidnext elems permanent-flags
uidvalidity vanished highestmodseq)
(dolist (elem sequences)
(match-string 1)))
(goto-char start)
(setq highestmodseq
- (and (search-forward "HIGHESTMODSEQ "
+ (and (re-search-forward "HIGHESTMODSEQ \\([0-9]+\\)"
(or end (point-min)) t)
- (read (current-buffer))))
+ (match-string 1)))
(goto-char end)
(forward-line -1))
;; The UID FETCH FLAGS was successful.
(setq start (point))
(goto-char end))
(while (re-search-forward "^\\* [0-9]+ FETCH " start t)
- (setq elems (read (current-buffer)))
- (push (cons (cadr (memq 'UID elems))
- (cadr (memq 'FLAGS elems)))
- articles))
+ (let ((p (point)))
+ (setq elems (read (current-buffer)))
+ (push (cons (cadr (memq 'UID elems))
+ (cadr (memq 'FLAGS elems)))
+ articles)))
(push (nconc (list group uidnext totalp permanent-flags uidvalidity
vanished highestmodseq)
articles)
refid refid value)))))
(result (with-current-buffer (nnimap-buffer)
(nnimap-command "UID SEARCH %s" cmd))))
- (gnus-fetch-headers
- (and (car result) (delete 0 (mapcar #'string-to-number
- (cdr (assoc "SEARCH" (cdr result))))))
- nil t)))
+ (when result
+ (gnus-fetch-headers
+ (and (car result) (delete 0 (mapcar #'string-to-number
+ (cdr (assoc "SEARCH" (cdr result))))))
+ nil t))))
(defun nnimap-possibly-change-group (group server)
(let ((open-result t))
(goto-char (point-max)))
openp)
(quit
+ (when debug-on-quit
+ (debug "Quit"))
;; The user hit C-g while we were waiting: kill the process, in case
;; it's a gnutls-cli process that's stuck (tends to happen a lot behind
;; NAT routers).
(format "(UID %s%s)"
(format
(if (nnimap-ver4-p)
- "BODY.PEEK[HEADER] BODY.PEEK"
+ "BODY.PEEK"
"RFC822.PEEK"))
- (if nnimap-split-download-body-default
- "[]"
- "[1]")))
+ (cond
+ (nnimap-split-download-body-default
+ "[]")
+ ((nnimap-ver4-p)
+ "[HEADER]")
+ (t
+ "[1]"))))
t))
(defun nnimap-split-incoming-mail ()