1 ;;; elmo-pop3.el --- POP3 Interface for ELMO.
3 ;; Copyright (C) 1998,1999,2000 Yuuichi Teranishi <teranisi@gohome.org>
4 ;; Copyright (C) 1999,2000 Kenichi OKADA <okada@opaopa.org>
6 ;; Author: Yuuichi Teranishi <teranisi@gohome.org>
7 ;; Kenichi OKADA <okada@opaopa.org>
8 ;; Keywords: mail, net news
10 ;; This file is part of ELMO (Elisp Library for Message Orchestration).
12 ;; This program is free software; you can redistribute it and/or modify
13 ;; it under the terms of the GNU General Public License as published by
14 ;; the Free Software Foundation; either version 2, or (at your option)
17 ;; This program is distributed in the hope that it will be useful,
18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 ;; GNU General Public License for more details.
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with GNU Emacs; see the file COPYING. If not, write to the
24 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25 ;; Boston, MA 02111-1307, USA.
41 (autoload 'md5 "md5"))
43 (defcustom elmo-pop3-default-use-uidl t
44 "If non-nil, use UIDL on POP3."
48 (defvar elmo-pop3-use-uidl-internal t
49 "(Internal switch for using UIDL on POP3).")
51 (defvar elmo-pop3-use-cache t
52 "Use cache in pop3 folder.")
54 (defvar elmo-pop3-send-command-synchronously nil
55 "If non-nil, commands are send synchronously.
56 If server doesn't accept asynchronous commands, this variable should be
59 (defcustom elmo-pop3-exists-exactly nil
60 "If non-nil, POP3 folder existence is checked everytime before the session."
64 (defvar sasl-mechanism-alist)
66 (defvar elmo-pop3-total-size nil)
69 (defvar elmo-pop3-debug nil
70 "Non-nil forces POP3 folder as debug mode.
71 Debug information is inserted in the buffer \"*POP3 DEBUG*\"")
74 (defsubst elmo-pop3-debug (message &rest args)
76 (let ((biff (string-match "BIFF-" (buffer-name)))
78 (with-current-buffer (get-buffer-create (concat "*POP3 DEBUG*"
80 (goto-char (point-max))
82 (insert (apply 'format message args) "\n")))))
86 (luna-define-class elmo-pop3-folder (elmo-net-folder)
87 (use-uidl location-alist))
88 (luna-define-internal-accessors 'elmo-pop3-folder))
90 (luna-define-method elmo-folder-initialize :around ((folder
93 (let ((elmo-network-stream-type-alist
94 (if elmo-pop3-stream-type-alist
95 (append elmo-pop3-stream-type-alist
96 elmo-network-stream-type-alist)
97 elmo-network-stream-type-alist))
99 (setq name (luna-call-next-method))
101 (setq parse (elmo-parse-token name "/:"))
102 (elmo-net-folder-set-user-internal folder
103 (if (eq (length (car parse)) 0)
104 elmo-pop3-default-user
107 (setq parse (elmo-parse-prefixed-element ?/ (cdr parse) ":"))
108 (elmo-net-folder-set-auth-internal folder
109 (if (eq (length (car parse)) 0)
110 elmo-pop3-default-authenticate-type
111 (intern (downcase (car parse)))))
113 (setq parse (elmo-parse-prefixed-element ?: (cdr parse)))
114 (elmo-pop3-folder-set-use-uidl-internal folder
115 (if (eq (length (car parse)) 0)
116 elmo-pop3-default-use-uidl
117 (string= (car parse) "uidl")))
118 (unless (elmo-net-folder-server-internal folder)
119 (elmo-net-folder-set-server-internal folder
120 elmo-pop3-default-server))
121 (unless (elmo-net-folder-port-internal folder)
122 (elmo-net-folder-set-port-internal folder
123 elmo-pop3-default-port))
124 (unless (elmo-net-folder-stream-type-internal folder)
125 (elmo-net-folder-set-stream-type-internal
127 (elmo-get-network-stream-type
128 elmo-pop3-default-stream-type)))
132 (luna-define-class elmo-pop3-session (elmo-network-session) ())
135 (defvar elmo-pop3-read-point nil)
136 (defvar elmo-pop3-number-uidl-hash nil) ; number -> uidl
137 (defvar elmo-pop3-uidl-number-hash nil) ; uidl -> number
138 (defvar elmo-pop3-size-hash nil) ; number -> size
139 (defvar elmo-pop3-uidl-done nil)
140 (defvar elmo-pop3-list-done nil)
141 (defvar elmo-pop3-lock nil)
143 (defvar elmo-pop3-local-variables '(elmo-pop3-read-point
144 elmo-pop3-uidl-number-hash
145 elmo-pop3-number-uidl-hash
151 (luna-define-method elmo-network-close-session ((session elmo-pop3-session))
152 (when (elmo-network-session-process-internal session)
153 (when (memq (process-status
154 (elmo-network-session-process-internal session))
156 (elmo-pop3-send-command (elmo-network-session-process-internal session)
159 (or (elmo-pop3-read-response
160 (elmo-network-session-process-internal session)
162 (error "POP error: QUIT failed")))
163 (kill-buffer (process-buffer
164 (elmo-network-session-process-internal session)))
165 (delete-process (elmo-network-session-process-internal session))))
167 (defun elmo-pop3-get-session (folder &optional if-exists)
168 "Get POP3 session for FOLDER.
169 If IF-EXISTS is non-nil, don't get new session.
170 If IF-EXISTS is `any-exists', get BIFF session or normal session if exists."
171 (let ((elmo-pop3-use-uidl-internal (if elmo-inhibit-number-mapping
173 (elmo-pop3-folder-use-uidl-internal
176 (if (eq if-exists 'any-exists)
177 (or (elmo-network-get-session 'elmo-pop3-session
180 (elmo-network-get-session 'elmo-pop3-session
183 (elmo-network-get-session 'elmo-pop3-session
185 (if (elmo-folder-biff-internal folder)
189 ;; For saving existency.
190 (unless (file-exists-p (elmo-folder-msgdb-path folder))
191 (elmo-make-directory (elmo-folder-msgdb-path folder))))))
193 (defun elmo-pop3-send-command (process command &optional no-erase no-log)
194 (with-current-buffer (process-buffer process)
197 (goto-char (point-min))
198 (setq elmo-pop3-read-point (point))
199 (elmo-pop3-debug "SEND: %s\n" (if no-log "<NO LOGGING>" command))
200 (process-send-string process (concat command "\r\n"))))
202 (defun elmo-pop3-read-response (process &optional not-command)
203 ;; buffer is in case for process is dead.
204 (with-current-buffer (process-buffer process)
205 (let ((case-fold-search nil)
206 (response-string nil)
207 (response-continue t)
210 (while response-continue
211 (goto-char elmo-pop3-read-point)
212 (while (not (re-search-forward "\r?\n" nil t))
213 (accept-process-output process 1)
214 (goto-char elmo-pop3-read-point))
215 (setq match-end (point))
216 (setq response-string
217 (buffer-substring elmo-pop3-read-point (- match-end 2)))
218 (goto-char elmo-pop3-read-point)
219 (if (looking-at "\\+.*$")
221 (setq response-continue nil)
222 (setq elmo-pop3-read-point match-end)
225 (concat return-value "\n" response-string)
227 (if (looking-at "\\-.*$")
229 (setq response-continue nil)
230 (setq elmo-pop3-read-point match-end)
231 (setq return-value nil))
232 (setq elmo-pop3-read-point match-end)
234 (setq response-continue nil))
237 (concat return-value "\n" response-string)
239 (setq elmo-pop3-read-point match-end)))
242 (defun elmo-pop3-process-filter (process output)
243 (when (buffer-live-p (process-buffer process))
244 (with-current-buffer (process-buffer process)
245 (goto-char (point-max))
247 (elmo-pop3-debug "RECEIVED: %s\n" output)
248 (if (and elmo-pop3-total-size
249 (> elmo-pop3-total-size
250 (min elmo-display-retrieval-progress-threshold 100)))
251 (elmo-display-progress
252 'elmo-display-retrieval-progress
253 (format "Retrieving (%d/%d bytes)..."
255 elmo-pop3-total-size)
256 (/ (buffer-size) (/ elmo-pop3-total-size 100)))))))
258 (defun elmo-pop3-auth-user (session)
259 (let ((process (elmo-network-session-process-internal session)))
261 (elmo-pop3-send-command
263 (format "user %s" (elmo-network-session-user-internal session))
265 (or (elmo-pop3-read-response process t)
267 (delete-process process)
268 (signal 'elmo-authenticate-error
269 '(elmo-pop-auth-user))))
270 (elmo-pop3-send-command process
274 (elmo-network-session-password-key session)))
276 (or (elmo-pop3-read-response process t)
278 (delete-process process)
279 (signal 'elmo-authenticate-error
280 '(elmo-pop-auth-user))))))
282 (defun elmo-pop3-auth-apop (session)
283 (if (string-match "^\+OK .*\\(<[^\>]+>\\)"
284 (elmo-network-session-greeting-internal session))
285 ;; good, APOP ready server
287 (elmo-pop3-send-command
288 (elmo-network-session-process-internal session)
290 (elmo-network-session-user-internal session)
292 (concat (match-string
294 (elmo-network-session-greeting-internal session))
296 (elmo-network-session-password-key session)))))
298 (or (elmo-pop3-read-response
299 (elmo-network-session-process-internal session)
302 (delete-process (elmo-network-session-process-internal session))
303 (signal 'elmo-authenticate-error
304 '(elmo-pop3-auth-apop)))))
305 (signal 'elmo-open-error '(elmo-pop3-auth-apop))))
307 (luna-define-method elmo-network-initialize-session-buffer :after
308 ((session elmo-pop3-session) buffer)
309 (with-current-buffer buffer
310 (mapcar 'make-variable-buffer-local elmo-pop3-local-variables)))
312 (luna-define-method elmo-network-initialize-session ((session
314 (let ((process (elmo-network-session-process-internal session))
316 (with-current-buffer (process-buffer process)
317 (set-process-filter process 'elmo-pop3-process-filter)
318 (setq elmo-pop3-read-point (point-min))
319 ;; Skip garbage output from process before greeting.
320 (while (and (memq (process-status process) '(open run))
321 (goto-char (point-max))
323 (not (looking-at "+OK")))
324 (accept-process-output process 1))
325 (setq elmo-pop3-read-point (point))
326 (or (elmo-network-session-set-greeting-internal
328 (elmo-pop3-read-response process t))
329 (signal 'elmo-open-error
330 '(elmo-network-intialize-session)))
331 (when (eq (elmo-network-stream-type-symbol
332 (elmo-network-session-stream-type-internal session))
334 (elmo-pop3-send-command process "stls")
335 (if (string-match "^\+OK"
336 (elmo-pop3-read-response process))
337 (starttls-negotiate process)
338 (signal 'elmo-open-error
339 '(elmo-pop3-starttls-error)))))))
341 (luna-define-method elmo-network-authenticate-session ((session
343 (with-current-buffer (process-buffer
344 (elmo-network-session-process-internal session))
345 (let* ((process (elmo-network-session-process-internal session))
346 (auth (elmo-network-session-auth-internal session))
347 (auth (mapcar '(lambda (mechanism) (upcase (symbol-name mechanism)))
348 (if (listp auth) auth (list auth))))
350 client name step response mechanism
351 sasl-read-passphrase)
352 (or (and (string= "USER" (car auth))
353 (elmo-pop3-auth-user session))
354 (and (string= "APOP" (car auth))
355 (elmo-pop3-auth-apop session))
358 (setq sasl-mechanisms (mapcar 'car sasl-mechanism-alist))
359 (setq mechanism (sasl-find-mechanism auth))
361 (signal 'elmo-authenticate-error '(elmo-pop3-auth-no-mechanisms)))
365 (elmo-network-session-user-internal session)
367 (elmo-network-session-server-internal session)))
368 ;;; (if elmo-pop3-auth-user-realm
369 ;;; (sasl-client-set-property client 'realm elmo-pop3-auth-user-realm))
370 (setq name (sasl-mechanism-name mechanism))
371 (elmo-network-session-set-auth-internal session
372 (intern (downcase name)))
373 (setq sasl-read-passphrase
377 (elmo-network-session-password-key session)))))
378 (setq step (sasl-next-step client nil))
379 (elmo-pop3-send-command
382 (and (sasl-step-data step)
385 (elmo-base64-encode-string
386 (sasl-step-data step) 'no-line-break))))
390 (unless (setq response (elmo-pop3-read-response process t))
391 ;; response is NO or BAD.
392 (signal 'elmo-authenticate-error
394 (concat "elmo-pop3-auth-"
396 (if (string-match "^\+OK" response)
397 (if (sasl-next-step client step)
399 (signal 'elmo-authenticate-error
401 (concat "elmo-pop3-auth-"
403 ;; The authentication process is finished.
407 (elmo-base64-decode-string
408 (cadr (split-string response " "))))
409 (setq step (sasl-next-step client step))
410 (elmo-pop3-send-command
412 (if (sasl-step-data step)
413 (elmo-base64-encode-string (sasl-step-data step)
415 "") nil 'no-log))))))))
417 (luna-define-method elmo-network-setup-session ((session
419 (let ((process (elmo-network-session-process-internal session))
421 (with-current-buffer (process-buffer process)
422 (setq elmo-pop3-size-hash (elmo-make-hash 31))
423 ;; To get obarray of uidl and size
424 (elmo-pop3-send-command process "list")
425 (if (null (elmo-pop3-read-response process))
426 (error "POP LIST command failed"))
427 (if (null (setq response
428 (elmo-pop3-read-contents
429 (current-buffer) process)))
430 (error "POP LIST command failed"))
431 ;; POP server always returns a sequence of serial numbers.
432 (setq count (elmo-pop3-parse-list-response response))
434 (when elmo-pop3-use-uidl-internal
435 (setq elmo-pop3-uidl-number-hash (elmo-make-hash (* count 2)))
436 (setq elmo-pop3-number-uidl-hash (elmo-make-hash (* count 2)))
438 (elmo-pop3-send-command process "uidl")
439 (unless (elmo-pop3-read-response process)
440 (error "POP UIDL failed"))
441 (unless (setq response (elmo-pop3-read-contents
442 (current-buffer) process))
443 (error "POP UIDL failed"))
444 (elmo-pop3-parse-uidl-response response)))))
446 (defun elmo-pop3-read-contents (buffer process)
447 (with-current-buffer buffer
448 (let ((case-fold-search nil)
450 (goto-char elmo-pop3-read-point)
451 (while (not (re-search-forward "^\\.\r\n" nil t))
452 (accept-process-output process 1)
453 (goto-char elmo-pop3-read-point))
454 (setq match-end (point))
456 (buffer-substring elmo-pop3-read-point
459 (luna-define-method elmo-folder-expand-msgdb-path ((folder elmo-pop3-folder))
460 (convert-standard-filename
462 (elmo-safe-filename (elmo-net-folder-user-internal folder))
463 (expand-file-name (elmo-net-folder-server-internal folder)
466 elmo-msgdb-directory)))))
468 (luna-define-method elmo-folder-exists-p ((folder elmo-pop3-folder))
469 (if (and elmo-pop3-exists-exactly
470 (elmo-folder-plugged-p folder))
472 (let (elmo-auto-change-plugged ; don't change plug status.
473 (elmo-inhibit-number-mapping t) ; No need to use uidl.
476 (setq session (elmo-pop3-get-session folder))
478 (elmo-network-close-session session)))))
479 (or (file-directory-p (elmo-folder-msgdb-path folder))
481 (when (elmo-folder-plugged-p folder)
482 (let ((elmo-pop3-exists-exactly t))
483 (elmo-folder-exists-p folder))))))
485 (defun elmo-pop3-parse-uidl-response (string)
486 (let ((buffer (current-buffer))
489 (let (number uid list)
491 (goto-char (point-min))
492 (while (re-search-forward "^\\([0-9]+\\)[\t ]+\\([^ \n]+\\)$" nil t)
493 (setq number (elmo-match-buffer 1))
494 (setq uid (elmo-match-buffer 2))
495 (with-current-buffer buffer
496 (elmo-set-hash-val uid number elmo-pop3-uidl-number-hash)
497 (elmo-set-hash-val (concat "#" number) uid
498 elmo-pop3-number-uidl-hash))
499 (setq list (cons uid list)))
500 (with-current-buffer buffer (setq elmo-pop3-uidl-done t))
503 (defun elmo-pop3-parse-list-response (string)
504 (let ((buffer (current-buffer))
509 (goto-char (point-min))
510 (while (re-search-forward "^\\([0-9]+\\)[\t ]+\\([0-9]+\\)$" nil t)
513 (cons (elmo-match-buffer 1)
514 (elmo-match-buffer 2))
516 (setq count (1+ count)))
517 (with-current-buffer buffer
518 (setq elmo-pop3-size-hash (elmo-make-hash (* (length alist) 2)))
520 (elmo-set-hash-val (concat "#" (car (car alist)))
523 (setq alist (cdr alist)))
524 (setq elmo-pop3-list-done t))
527 (defun elmo-pop3-list-location (folder)
528 (with-current-buffer (process-buffer
529 (elmo-network-session-process-internal
530 (elmo-pop3-get-session folder)))
532 (if elmo-pop3-uidl-done
536 (setq locations (cons (symbol-name atom) locations)))
537 elmo-pop3-uidl-number-hash)
540 (< (elmo-pop3-uidl-to-number loc1)
541 (elmo-pop3-uidl-to-number loc2)))))
542 (error "POP3: Error in UIDL")))))
544 (defun elmo-pop3-list-folder-by-location (folder locations)
545 (let* ((location-alist (elmo-pop3-folder-location-alist-internal folder))
546 (locations-in-db (mapcar 'cdr location-alist))
547 result new-locs new-alist deleted-locs i)
549 (elmo-delete-if (function
550 (lambda (x) (member x locations-in-db)))
553 (elmo-delete-if (function
554 (lambda (x) (member x locations)))
556 (setq i (or (elmo-max-of-list (mapcar 'car location-alist)) 0))
561 (delq (rassoc x location-alist) location-alist))))
565 (setq new-alist (cons (cons i (car new-locs)) new-alist))
566 (setq new-locs (cdr new-locs)))
567 (setq result (nconc location-alist new-alist))
568 (setq result (sort result (lambda (x y) (< (car x)(car y)))))
569 (elmo-pop3-folder-set-location-alist-internal folder result)
570 (mapcar 'car result)))
572 (defun elmo-pop3-list-by-uidl-subr (folder &optional nonsort)
573 (let ((flist (elmo-pop3-list-folder-by-location
575 (elmo-pop3-list-location folder))))
577 (cons (elmo-max-of-list flist) (length flist))
580 (defun elmo-pop3-list-by-list (folder)
581 (with-current-buffer (process-buffer
582 (elmo-network-session-process-internal
583 (elmo-pop3-get-session folder)))
585 (if elmo-pop3-list-done
587 (mapatoms (lambda (atom)
588 (setq list (cons (string-to-int
589 (substring (symbol-name atom) 1))
593 (error "POP3: Error in list")))))
595 (defsubst elmo-pop3-folder-list-messages (folder)
596 (if (and (not elmo-inhibit-number-mapping)
597 (elmo-pop3-folder-use-uidl-internal folder))
598 (elmo-pop3-list-by-uidl-subr folder)
599 (elmo-pop3-list-by-list folder)))
601 (luna-define-method elmo-folder-list-messages-plugged
602 ((folder elmo-pop3-folder) &optional nohide)
603 (elmo-pop3-folder-list-messages folder))
605 (luna-define-method elmo-folder-status ((folder elmo-pop3-folder))
606 (elmo-folder-open-internal folder)
607 (elmo-folder-check folder)
608 (if (elmo-pop3-folder-use-uidl-internal folder)
610 (elmo-pop3-list-by-uidl-subr folder 'nonsort)
611 (elmo-folder-close-internal folder))
613 (elmo-network-session-process-internal
614 (elmo-pop3-get-session folder)))
617 (with-current-buffer (process-buffer process)
618 (elmo-pop3-send-command process "STAT")
619 (setq response (elmo-pop3-read-response process))
620 ;; response: "^\+OK 2 7570$"
621 (if (not (string-match "^\+OK[ \t]*\\([0-9]*\\)" response))
622 (error "POP STAT command failed")
625 (substring response (match-beginning 1)(match-end 1 ))))
626 (elmo-folder-close-internal folder)
627 (cons total total))))))
629 (defvar elmo-pop3-header-fetch-chop-length 200)
631 (defsubst elmo-pop3-next-result-arrived-p ()
633 ((eq (following-char) ?+)
634 (if (re-search-forward "\n\\.\r?\n" nil t)
638 (if (search-forward "\n" nil t)
644 (defun elmo-pop3-retrieve-headers (buffer tobuffer process articles)
648 (let ((number (length articles))
651 (last-point (point-min)))
652 ;; Send HEAD commands.
654 (elmo-pop3-send-command process (format
655 "top %s 0" (car articles))
657 ;;; (accept-process-output process 1)
658 (setq articles (cdr articles))
659 (setq count (1+ count))
660 ;; Every 200 requests we have to read the stream in
661 ;; order to avoid deadlocks.
662 (when (or elmo-pop3-send-command-synchronously
663 (null articles) ;All requests have been sent.
664 (zerop (% count elmo-pop3-header-fetch-chop-length)))
665 (unless elmo-pop3-send-command-synchronously
666 (accept-process-output process 1))
670 (goto-char last-point)
672 (while (elmo-pop3-next-result-arrived-p)
673 (setq last-point (point))
674 (setq received (1+ received)))
676 (when (> number elmo-display-progress-threshold)
677 (if (or (zerop (% received 5)) (= received number))
678 (elmo-display-progress
679 'elmo-pop3-retrieve-headers "Getting headers..."
680 (/ (* received 100) number))))
681 (accept-process-output process 1)
682 ;;; (accept-process-output process)
684 ;; Remove all "\r"'s.
685 (goto-char (point-min))
686 (while (search-forward "\r\n" nil t)
687 (replace-match "\n"))
688 (copy-to-buffer tobuffer (point-min) (point-max)))))
690 (luna-define-method elmo-folder-msgdb-create ((folder elmo-pop3-folder)
692 (let ((process (elmo-network-session-process-internal
693 (elmo-pop3-get-session folder))))
694 (with-current-buffer (process-buffer process)
695 (elmo-pop3-sort-msgdb-by-original-number
697 (elmo-pop3-msgdb-create-by-header
702 (if (elmo-pop3-folder-use-uidl-internal folder)
703 (elmo-pop3-folder-location-alist-internal folder)))))))
705 (defun elmo-pop3-sort-msgdb-by-original-number (folder msgdb)
706 (let ((location-alist (elmo-pop3-folder-location-alist-internal folder)))
708 (elmo-msgdb-sort-entities
710 (lambda (ent1 ent2 loc-alist)
711 (< (elmo-pop3-uidl-to-number
712 (cdr (assq (elmo-message-entity-number ent1)
714 (elmo-pop3-uidl-to-number
715 (cdr (assq (elmo-message-entity-number ent2)
720 (defun elmo-pop3-uidl-to-number (uidl)
721 (string-to-number (elmo-get-hash-val uidl
722 elmo-pop3-uidl-number-hash)))
724 (defun elmo-pop3-number-to-uidl (number)
725 (elmo-get-hash-val (format "#%d" number)
726 elmo-pop3-number-uidl-hash))
728 (defun elmo-pop3-number-to-size (number)
729 (elmo-get-hash-val (format "#%d" number)
730 elmo-pop3-size-hash))
732 (defun elmo-pop3-msgdb-create-by-header (folder process numlist
735 (let ((tmp-buffer (get-buffer-create " *ELMO Overview TMP*")))
736 (with-current-buffer (process-buffer process)
737 (if loc-alist ; use uidl.
743 (elmo-pop3-uidl-to-number (cdr (assq number loc-alist))))
745 (elmo-pop3-retrieve-headers (process-buffer process)
746 tmp-buffer process numlist)
748 (elmo-pop3-msgdb-create-message
754 flag-table loc-alist)
755 (kill-buffer tmp-buffer)))))
757 (defun elmo-pop3-msgdb-create-message (folder
765 (let ((new-msgdb (elmo-make-msgdb))
766 beg entity i number message-id flags)
768 (elmo-set-buffer-multibyte default-enable-multibyte-characters)
769 (goto-char (point-min))
771 (message "Creating msgdb...")
773 (setq beg (save-excursion (forward-line 1) (point)))
774 (elmo-pop3-next-result-arrived-p)
778 (narrow-to-region beg (point))
780 (elmo-msgdb-create-message-entity-from-buffer
781 (elmo-msgdb-message-entity-handler new-msgdb)
783 (setq numlist (cdr numlist))
785 (with-current-buffer (process-buffer process)
786 (elmo-message-entity-set-field
790 (elmo-pop3-number-to-size
791 (elmo-message-entity-number entity))))
795 (elmo-pop3-number-to-uidl
796 (elmo-message-entity-number entity))
798 (elmo-message-entity-set-number entity number)))
799 (setq message-id (elmo-message-entity-field entity 'message-id)
800 flags (elmo-flag-table-get flag-table message-id))
801 (elmo-global-flags-set flags folder number message-id)
802 (elmo-msgdb-append-entity new-msgdb entity flags))))
803 (when (> num elmo-display-progress-threshold)
805 (if (or (zerop (% i 5)) (= i num))
806 (elmo-display-progress
807 'elmo-pop3-msgdb-create-message "Creating msgdb..."
808 (/ (* i 100) num)))))
811 (defun elmo-pop3-read-body (process outbuf)
812 (with-current-buffer (process-buffer process)
813 (let ((start elmo-pop3-read-point)
816 (while (not (re-search-forward "^\\.\r?\n" nil t))
817 (accept-process-output process 1)
820 (with-current-buffer outbuf
822 (insert-buffer-substring (process-buffer process) start (- end 3)))
825 (luna-define-method elmo-folder-open-internal ((folder elmo-pop3-folder))
826 (if (and (not elmo-inhibit-number-mapping)
827 (elmo-pop3-folder-use-uidl-internal folder))
828 (elmo-pop3-folder-set-location-alist-internal
829 folder (elmo-msgdb-location-load (elmo-folder-msgdb-path folder)))))
831 (luna-define-method elmo-folder-commit :after ((folder elmo-pop3-folder))
832 (when (elmo-folder-persistent-p folder)
833 (elmo-msgdb-location-save (elmo-folder-msgdb-path folder)
834 (elmo-pop3-folder-location-alist-internal
837 (luna-define-method elmo-folder-close-internal ((folder elmo-pop3-folder))
838 (elmo-pop3-folder-set-location-alist-internal folder nil)
839 ;; Just close connection
840 (elmo-folder-check folder))
842 (luna-define-method elmo-message-fetch-plugged ((folder elmo-pop3-folder)
846 (let* ((loc-alist (elmo-pop3-folder-location-alist-internal folder))
847 (process (elmo-network-session-process-internal
848 (elmo-pop3-get-session folder)))
849 size response errmsg msg)
850 (with-current-buffer (process-buffer process)
852 (setq number (elmo-pop3-uidl-to-number
853 (cdr (assq number loc-alist)))))
854 (setq size (string-to-number
855 (elmo-pop3-number-to-size number)))
857 (elmo-pop3-send-command process
858 (format "retr %s" number))
859 (unless elmo-inhibit-display-retrieval-progress
860 (setq elmo-pop3-total-size size)
861 (elmo-display-progress
862 'elmo-display-retrieval-progress
863 (format "Retrieving (0/%d bytes)..." elmo-pop3-total-size)
867 (when (null (setq response (elmo-pop3-read-response
869 (error "Fetching message failed"))
870 (setq response (elmo-pop3-read-body process outbuf)))
871 (setq elmo-pop3-total-size nil))
872 (unless elmo-inhibit-display-retrieval-progress
873 (elmo-display-progress
874 'elmo-display-retrieval-progress
875 "Retrieving..." 100) ; remove progress bar.
876 (message "Retrieving...done"))
878 (goto-char (point-min))
879 (while (re-search-forward "^\\." nil t)
882 (elmo-delete-cr-buffer)
885 (defun elmo-pop3-delete-msg (process number loc-alist)
886 (with-current-buffer (process-buffer process)
887 (let (response errmsg msg)
889 (setq number (elmo-pop3-uidl-to-number
890 (cdr (assq number loc-alist)))))
893 (elmo-pop3-send-command process
894 (format "dele %s" number))
895 (when (null (setq response (elmo-pop3-read-response
897 (error "Deleting message failed")))
898 (error "Deleting message failed")))))
900 (luna-define-method elmo-folder-delete-messages-plugged ((folder
903 (let ((loc-alist (elmo-pop3-folder-location-alist-internal folder))
904 (process (elmo-network-session-process-internal
905 (elmo-pop3-get-session folder))))
906 (mapcar '(lambda (msg) (elmo-pop3-delete-msg process msg loc-alist))
909 (luna-define-method elmo-message-use-cache-p ((folder elmo-pop3-folder) number)
912 (luna-define-method elmo-folder-persistent-p ((folder elmo-pop3-folder))
913 (and (elmo-folder-persistent-internal folder)
914 (elmo-pop3-folder-use-uidl-internal folder)))
916 (luna-define-method elmo-folder-clear :around ((folder elmo-pop3-folder)
917 &optional keep-killed)
919 (elmo-pop3-folder-set-location-alist-internal folder nil))
920 (luna-call-next-method))
922 (luna-define-method elmo-folder-check ((folder elmo-pop3-folder))
923 (if (elmo-folder-plugged-p folder)
924 (let ((session (elmo-pop3-get-session folder 'if-exists)))
926 (elmo-network-close-session session)))))
929 (product-provide (provide 'elmo-pop3) (require 'elmo-version))
931 ;;; elmo-pop3.el ends here