comparison lisp/gnus/nnimap.el @ 110615:84a76c5e1b1c

Merge changes made in Gnus trunk. sieve-manage.el (sieve-manage-default-stream): Make default stream customizable. nnimap.el (nnimap-request-accept-article): Send a "." at the end, which may or may not help. nnimap.el (nnimap-open-connection): Have the `network' nnimap connection use STARTTLS opportunistically. gnus-sum.el (gnus-summary-insert-new-articles): Copy the old-high watermark so that nothing alters it while scanning for new messages. nnimap.el (nnimap-request-accept-article): Remove the "." at the end, since some servers don't like it. nnimap.el (nnimap-open-connection): Forget credentials if the server says the password was wrong. nnimap.el (nnimap-parse-line): Protect against invalid data. gnus-art.el, gnus-sum.el, nnimap.el: Allow setting the partial fetch per server instead of globally. message.el (message-cite-prefix-regexp): Revert last edit. nnmairix.el: Make it work with latest changes in nnimap. gnus-sum.el (gnus-summary-move-article): Don't alter gnus-newsgroup-active. gnus-sum.el (gnus-summary-exit): Kill the article buffer later, so that you don't get flashes of other buffers. nnimap.el: Fix up partial nnimap fetching. gnus-sum.el: Rework the `/ N' based on the new gnus-newsgroup-highest variable.
author Katsumi Yamaoka <yamaoka@jpl.org>
date Mon, 27 Sep 2010 23:07:47 +0000
parents 5bd3c6bdbcb0
children b1c50a3d738a
comparison
equal deleted inserted replaced
110614:ced897c0b9f0 110615:84a76c5e1b1c
82 some servers.") 82 some servers.")
83 83
84 (defvoo nnimap-connection-alist nil) 84 (defvoo nnimap-connection-alist nil)
85 85
86 (defvoo nnimap-current-infos nil) 86 (defvoo nnimap-current-infos nil)
87
88 (defvoo nnimap-fetch-partial-articles nil
89 "If non-nil, Gnus will fetch partial articles.
90 If t, nnimap will fetch only the first part. If a string, it
91 will fetch all parts that have types that match that string. A
92 likely value would be \"text/\" to automatically fetch all
93 textual parts.")
87 94
88 (defvar nnimap-process nil) 95 (defvar nnimap-process nil)
89 96
90 (defvar nnimap-status-string "") 97 (defvar nnimap-status-string "")
91 98
269 276
270 (defun nnimap-open-connection (buffer) 277 (defun nnimap-open-connection (buffer)
271 (unless nnimap-keepalive-timer 278 (unless nnimap-keepalive-timer
272 (setq nnimap-keepalive-timer (run-at-time (* 60 15) (* 60 15) 279 (setq nnimap-keepalive-timer (run-at-time (* 60 15) (* 60 15)
273 'nnimap-keepalive))) 280 'nnimap-keepalive)))
274 (with-current-buffer (nnimap-make-process-buffer buffer) 281 (block nil
275 (let* ((coding-system-for-read 'binary) 282 (with-current-buffer (nnimap-make-process-buffer buffer)
276 (coding-system-for-write 'binary) 283 (let* ((coding-system-for-read 'binary)
277 (port nil) 284 (coding-system-for-write 'binary)
278 (ports 285 (port nil)
279 (cond 286 (ports
280 ((eq nnimap-stream 'network) 287 (cond
281 (open-network-stream 288 ((eq nnimap-stream 'network)
282 "*nnimap*" (current-buffer) nnimap-address 289 (open-network-stream
283 (setq port 290 "*nnimap*" (current-buffer) nnimap-address
284 (or nnimap-server-port 291 (setq port
285 (if (netrc-find-service-number "imap") 292 (or nnimap-server-port
286 "imap" 293 (if (netrc-find-service-number "imap")
287 "143")))) 294 "imap"
288 '("143" "imap")) 295 "143"))))
289 ((eq nnimap-stream 'shell) 296 '("143" "imap"))
290 (nnimap-open-shell-stream 297 ((eq nnimap-stream 'shell)
291 "*nnimap*" (current-buffer) nnimap-address 298 (nnimap-open-shell-stream
292 (setq port (or nnimap-server-port "imap"))) 299 "*nnimap*" (current-buffer) nnimap-address
293 '("imap")) 300 (setq port (or nnimap-server-port "imap")))
294 ((eq nnimap-stream 'starttls) 301 '("imap"))
295 (starttls-open-stream 302 ((eq nnimap-stream 'starttls)
296 "*nnimap*" (current-buffer) nnimap-address 303 (starttls-open-stream
297 (setq port (or nnimap-server-port "imap"))) 304 "*nnimap*" (current-buffer) nnimap-address
298 '("imap")) 305 (setq port (or nnimap-server-port "imap")))
299 ((eq nnimap-stream 'ssl) 306 '("imap"))
300 (open-tls-stream 307 ((eq nnimap-stream 'ssl)
301 "*nnimap*" (current-buffer) nnimap-address 308 (open-tls-stream
302 (setq port 309 "*nnimap*" (current-buffer) nnimap-address
303 (or nnimap-server-port 310 (setq port
304 (if (netrc-find-service-number "imaps") 311 (or nnimap-server-port
305 "imaps" 312 (if (netrc-find-service-number "imaps")
306 "993")))) 313 "imaps"
307 '("143" "993" "imap" "imaps")))) 314 "993"))))
308 connection-result login-result credentials) 315 '("143" "993" "imap" "imaps"))))
309 (setf (nnimap-process nnimap-object) 316 connection-result login-result credentials)
310 (get-buffer-process (current-buffer))) 317 (setf (nnimap-process nnimap-object)
311 (if (not (and (nnimap-process nnimap-object) 318 (get-buffer-process (current-buffer)))
312 (memq (process-status (nnimap-process nnimap-object)) 319 (if (not (and (nnimap-process nnimap-object)
313 '(open run)))) 320 (memq (process-status (nnimap-process nnimap-object))
314 (nnheader-report 'nnimap "Unable to contact %s:%s via %s" 321 '(open run))))
315 nnimap-address port nnimap-stream) 322 (nnheader-report 'nnimap "Unable to contact %s:%s via %s"
316 (gnus-set-process-query-on-exit-flag (nnimap-process nnimap-object) nil) 323 nnimap-address port nnimap-stream)
317 (if (not (setq connection-result (nnimap-wait-for-connection))) 324 (gnus-set-process-query-on-exit-flag (nnimap-process nnimap-object) nil)
318 (nnheader-report 'nnimap 325 (if (not (setq connection-result (nnimap-wait-for-connection)))
319 "%s" (buffer-substring 326 (nnheader-report 'nnimap
320 (point) (line-end-position))) 327 "%s" (buffer-substring
321 (setf (nnimap-greeting nnimap-object) 328 (point) (line-end-position)))
322 (buffer-substring (line-beginning-position) 329 ;; Store the greeting (for debugging purposes).
323 (line-end-position))) 330 (setf (nnimap-greeting nnimap-object)
324 (when (eq nnimap-stream 'starttls) 331 (buffer-substring (line-beginning-position)
325 (nnimap-command "STARTTLS") 332 (line-end-position)))
326 (starttls-negotiate (nnimap-process nnimap-object))) 333 ;; Store the capabilities.
327 (when nnimap-server-port
328 (push (format "%s" nnimap-server-port) ports))
329 (unless (equal connection-result "PREAUTH")
330 (if (not (setq credentials
331 (if (eq nnimap-authenticator 'anonymous)
332 (list "anonymous"
333 (message-make-address))
334 (or
335 ;; First look for the credentials based
336 ;; on the virtual server name.
337 (nnimap-credentials
338 (nnoo-current-server 'nnimap) ports t)
339 ;; Then look them up based on the
340 ;; physical address.
341 (nnimap-credentials nnimap-address ports)))))
342 (setq nnimap-object nil)
343 (setq login-result (nnimap-command "LOGIN %S %S"
344 (car credentials)
345 (cadr credentials)))
346 (unless (car login-result)
347 (delete-process (nnimap-process nnimap-object))
348 (setq nnimap-object nil))))
349 (when nnimap-object
350 (setf (nnimap-capabilities nnimap-object) 334 (setf (nnimap-capabilities nnimap-object)
351 (mapcar 335 (mapcar
352 #'upcase 336 #'upcase
353 (or (nnimap-find-parameter "CAPABILITY" (cdr login-result)) 337 (nnimap-find-parameter
354 (nnimap-find-parameter 338 "CAPABILITY" (cdr (nnimap-command "CAPABILITY")))))
355 "CAPABILITY" (cdr (nnimap-command "CAPABILITY")))))) 339 (when (eq nnimap-stream 'starttls)
356 (when (member "QRESYNC" (nnimap-capabilities nnimap-object)) 340 (nnimap-command "STARTTLS")
357 (nnimap-command "ENABLE QRESYNC")) 341 (starttls-negotiate (nnimap-process nnimap-object)))
358 t)))))) 342 ;; If this is a STARTTLS-capable server, then sever the
343 ;; connection and start a STARTTLS connection instead.
344 (when (and (eq nnimap-stream 'network)
345 (member "STARTTLS" (nnimap-capabilities nnimap-object)))
346 (let ((nnimap-stream 'starttls))
347 (delete-process (nnimap-process nnimap-object))
348 (kill-buffer (current-buffer))
349 (return
350 (nnimap-open-connection buffer))))
351 (when nnimap-server-port
352 (push (format "%s" nnimap-server-port) ports))
353 (unless (equal connection-result "PREAUTH")
354 (if (not (setq credentials
355 (if (eq nnimap-authenticator 'anonymous)
356 (list "anonymous"
357 (message-make-address))
358 (or
359 ;; First look for the credentials based
360 ;; on the virtual server name.
361 (nnimap-credentials
362 (nnoo-current-server 'nnimap) ports t)
363 ;; Then look them up based on the
364 ;; physical address.
365 (nnimap-credentials nnimap-address ports)))))
366 (setq nnimap-object nil)
367 (setq login-result (nnimap-command "LOGIN %S %S"
368 (car credentials)
369 (cadr credentials)))
370 (unless (car login-result)
371 ;; If the login failed, then forget the credentials
372 ;; that are now possibly cached.
373 (dolist (host (list (nnoo-current-server 'nnimap)
374 nnimap-address))
375 (dolist (port ports)
376 (dolist (element '("login" "password"))
377 (auth-source-forget-user-or-password
378 element host port))))
379 (delete-process (nnimap-process nnimap-object))
380 (setq nnimap-object nil))))
381 (when nnimap-object
382 (when (member "QRESYNC" (nnimap-capabilities nnimap-object))
383 (nnimap-command "ENABLE QRESYNC"))
384 t)))))))
359 385
360 (defun nnimap-find-parameter (parameter elems) 386 (defun nnimap-find-parameter (parameter elems)
361 (let (result) 387 (let (result)
362 (dolist (elem elems) 388 (dolist (elem elems)
363 (cond 389 (cond
393 (when (and result 419 (when (and result
394 article) 420 article)
395 (erase-buffer) 421 (erase-buffer)
396 (with-current-buffer (nnimap-buffer) 422 (with-current-buffer (nnimap-buffer)
397 (erase-buffer) 423 (erase-buffer)
398 (when gnus-fetch-partial-articles 424 (when nnimap-fetch-partial-articles
399 (if (eq gnus-fetch-partial-articles t) 425 (nnimap-command "UID FETCH %d (BODYSTRUCTURE)" article)
400 (setq parts '(1)) 426 (goto-char (point-min))
401 (nnimap-command "UID FETCH %d (BODYSTRUCTURE)" article) 427 (when (re-search-forward "FETCH.*BODYSTRUCTURE" nil t)
402 (goto-char (point-min)) 428 (setq structure (ignore-errors (read (current-buffer)))
403 (when (re-search-forward "FETCH.*BODYSTRUCTURE" nil t) 429 parts (nnimap-find-wanted-parts structure))))
404 (setq structure (ignore-errors (read (current-buffer)))
405 parts (nnimap-find-wanted-parts structure)))))
406 (when (if parts 430 (when (if parts
407 (nnimap-get-partial-article article parts structure) 431 (nnimap-get-partial-article article parts structure)
408 (nnimap-get-whole-article article)) 432 (nnimap-get-whole-article article))
409 (let ((buffer (current-buffer))) 433 (let ((buffer (current-buffer)))
410 (with-current-buffer (or to-buffer nntp-server-buffer) 434 (with-current-buffer (or to-buffer nntp-server-buffer)
523 (let ((type (format "%s/%s" (nth 0 sub) (nth 1 sub))) 547 (let ((type (format "%s/%s" (nth 0 sub) (nth 1 sub)))
524 (id (if (string= prefix "") 548 (id (if (string= prefix "")
525 (number-to-string num) 549 (number-to-string num)
526 (format "%s.%s" prefix num)))) 550 (format "%s.%s" prefix num))))
527 (setcar (nthcdr 9 sub) id) 551 (setcar (nthcdr 9 sub) id)
528 (when (string-match gnus-fetch-partial-articles type) 552 (when (if (eq nnimap-fetch-partial-articles t)
553 (equal id "1")
554 (string-match nnimap-fetch-partial-articles type))
529 (push id parts)))) 555 (push id parts))))
530 (incf num))) 556 (incf num)))
531 (nreverse parts))) 557 (nreverse parts)))
532 558
533 (deffoo nnimap-request-group (group &optional server dont-check info) 559 (deffoo nnimap-request-group (group &optional server dont-check info)
939 (start-article 965 (start-article
940 (cons start-article (1- start-article))) 966 (cons start-article (1- start-article)))
941 (t 967 (t
942 ;; No articles and no uidnext. 968 ;; No articles and no uidnext.
943 nil))) 969 nil)))
944 (setcdr (gnus-active group) (or high (1- uidnext)))) 970 (gnus-set-active
971 group
972 (cons (car (gnus-active group))
973 (or high (1- uidnext)))))
945 (when (and (not high) 974 (when (and (not high)
946 uidnext) 975 uidnext)
947 (setq high (1- uidnext))) 976 (setq high (1- uidnext)))
948 ;; Then update the list of read articles. 977 ;; Then update the list of read articles.
949 (let* ((unread 978 (let* ((unread
1191 (forward-char 1) 1220 (forward-char 1)
1192 (push 1221 (push
1193 (cond 1222 (cond
1194 ((eql char ?\[) 1223 ((eql char ?\[)
1195 (split-string (buffer-substring 1224 (split-string (buffer-substring
1196 (1+ (point)) (1- (search-forward "]"))))) 1225 (1+ (point))
1226 (1- (search-forward "]" (line-end-position) 'move)))))
1197 ((eql char ?\() 1227 ((eql char ?\()
1198 (split-string (buffer-substring 1228 (split-string (buffer-substring
1199 (1+ (point)) (1- (search-forward ")"))))) 1229 (1+ (point))
1230 (1- (search-forward ")" (line-end-position) 'move)))))
1200 ((eql char ?\") 1231 ((eql char ?\")
1201 (forward-char 1) 1232 (forward-char 1)
1202 (buffer-substring (point) (1- (search-forward "\"")))) 1233 (buffer-substring
1234 (point)
1235 (1- (or (search-forward "\"" (line-end-position) 'move)
1236 (point)))))
1203 (t 1237 (t
1204 (buffer-substring (point) (if (search-forward " " nil t) 1238 (buffer-substring (point) (if (search-forward " " nil t)
1205 (1- (point)) 1239 (1- (point))
1206 (goto-char (point-max)))))) 1240 (goto-char (point-max))))))
1207 result))) 1241 result)))