This commit was manufactured by cvs2svn to create branch 'elmo-imap4-new-
[elisp/wanderlust.git] / elmo / elmo-pop3.el
index 06e0a04..07555c6 100644 (file)
 
 (require 'elmo-msgdb)
 (require 'elmo-net)
+(require 'elmo-map)
 
 (eval-when-compile
+  (require 'cl)
   (require 'elmo-util))
 
 (eval-and-compile
@@ -68,7 +70,7 @@ set as non-nil.")
 
 (defvar sasl-mechanism-alist)
 
-(defvar elmo-pop3-total-size nil)
+(defvar elmo-pop3-retrieve-progress-reporter nil)
 
 ;; For debugging.
 (defvar elmo-pop3-debug nil
@@ -88,10 +90,15 @@ Debug information is inserted in the buffer \"*POP3 DEBUG*\"")
 
 ;;; ELMO POP3 folder
 (eval-and-compile
-  (luna-define-class elmo-pop3-folder (elmo-net-folder)
-                    (use-uidl location-alist))
+  (luna-define-class elmo-pop3-folder (elmo-net-folder elmo-location-map)
+                    (use-uidl))
   (luna-define-internal-accessors 'elmo-pop3-folder))
 
+(defsubst elmo-pop3-folder-use-uidl (folder)
+  (if elmo-inhibit-number-mapping
+      nil
+    (elmo-pop3-folder-use-uidl-internal folder)))
+
 (luna-define-method elmo-folder-initialize ((folder elmo-pop3-folder) name)
   (let ((elmo-network-stream-type-alist
         (if elmo-pop3-stream-type-alist
@@ -168,10 +175,7 @@ Debug information is inserted in the buffer \"*POP3 DEBUG*\"")
   "Get POP3 session for FOLDER.
 If IF-EXISTS is non-nil, don't get new session.
 If IF-EXISTS is `any-exists', get BIFF session or normal session if exists."
-  (let ((elmo-pop3-use-uidl-internal (if elmo-inhibit-number-mapping
-                                        nil
-                                      (elmo-pop3-folder-use-uidl-internal
-                                       folder))))
+  (let ((elmo-pop3-use-uidl-internal (elmo-pop3-folder-use-uidl folder)))
     (prog1
        (if (eq if-exists 'any-exists)
            (or (elmo-network-get-session 'elmo-pop3-session
@@ -224,7 +228,8 @@ CODE is one of the following:
          (goto-char elmo-pop3-read-point))
        (setq match-end (point))
        (setq response-string
-             (buffer-substring elmo-pop3-read-point (- match-end 2)))
+             (buffer-substring elmo-pop3-read-point
+                               (max (- match-end 2) elmo-pop3-read-point)))
        (goto-char elmo-pop3-read-point)
        (if (looking-at "\\+.*$")
            (progn
@@ -264,15 +269,8 @@ CODE is one of the following:
       (goto-char (point-max))
       (insert output)
       (elmo-pop3-debug "RECEIVED: %s\n" output)
-      (if (and elmo-pop3-total-size
-              (> elmo-pop3-total-size
-                 (min elmo-display-retrieval-progress-threshold 100)))
-         (elmo-display-progress
-          'elmo-display-retrieval-progress
-          (format "Retrieving (%d/%d bytes)..."
-                  (buffer-size)
-                  elmo-pop3-total-size)
-          (/ (buffer-size) (/ elmo-pop3-total-size 100)))))))
+      (when elmo-pop3-retrieve-progress-reporter
+       (elmo-progress-notify 'elmo-retrieve-message :set (buffer-size))))))
 
 (defun elmo-pop3-auth-user (session)
   (let ((process (elmo-network-session-process-internal session))
@@ -284,7 +282,6 @@ CODE is one of the following:
      nil 'no-log)
     (setq response (elmo-pop3-read-response process t))
     (unless (eq (car response) 'ok)
-      (delete-process process)
       (signal 'elmo-open-error '(elmo-pop-auth-user)))
     (elmo-pop3-send-command  process
                             (format
@@ -293,53 +290,44 @@ CODE is one of the following:
                               (elmo-network-session-password-key session)))
                             nil 'no-log)
     (setq response (elmo-pop3-read-response process t))
-    (unless (eq (car response) 'ok)
-      (delete-process process)
-      (unless (eq 'ok (car response))
-       (if (or (eq (car response) 'in-use)
-               (eq (car response) 'login-delay))
-           (error (cond ((eq (car response) 'in-use)
-                         "Maildrop is currently in use")
-                        ((eq (car response) 'login-delay)
-                         "Not allowed to login \
-until the login delay period has expired")))
-         (signal 'elmo-authenticate-error
-                 '(elmo-pop-auth-user)))))
+    (case (car response)
+      (ok)
+      (in-use
+       (error "Maildrop is currently in use"))
+      (login-delay
+       (error "Not allowed to login until the login delay period has expired"))
+      (t
+       (signal 'elmo-authenticate-error '(elmo-pop-auth-user))))
     (car response)))
 
 (defun elmo-pop3-auth-apop (session)
-  (if (string-match "^\+OK .*\\(<[^\>]+>\\)"
-                   (elmo-network-session-greeting-internal session))
-      ;; good, APOP ready server
-      (progn
-       (elmo-pop3-send-command
-        (elmo-network-session-process-internal session)
-        (format "apop %s %s"
-                (elmo-network-session-user-internal session)
-                (md5
-                 (concat (match-string
-                          1
-                          (elmo-network-session-greeting-internal session))
-                         (elmo-get-passwd
-                          (elmo-network-session-password-key session)))))
-        nil 'no-log)
-       (let ((response (elmo-pop3-read-response
-                        (elmo-network-session-process-internal session)
-                        t)))
-         (unless (eq (car response) 'ok)
-           (delete-process (elmo-network-session-process-internal session))
-           (unless (eq 'ok (car response))
-             (if (or (eq (car response) 'in-use)
-                     (eq (car response) 'login-delay))
-                 (error (cond ((eq (car response) 'in-use)
-                               "Maildrop is currently in use")
-                              ((eq (car response) 'login-delay)
-                               "Not allowed to login \
-until the login delay period has expired")))
-               (signal 'elmo-authenticate-error
-                       '(elmo-pop-auth-apop)))))
-         (car response)))
-    (signal 'elmo-open-error '(elmo-pop3-auth-apop))))
+  (unless (string-match "^\+OK .*\\(<[=!-;?-~]+@[=!-;?-~]+>\\)"
+                       (elmo-network-session-greeting-internal session))
+    (signal 'elmo-open-error '(elmo-pop3-auth-apop)))
+  ;; good, APOP ready server
+  (elmo-pop3-send-command
+   (elmo-network-session-process-internal session)
+   (format "apop %s %s"
+          (elmo-network-session-user-internal session)
+          (md5
+           (concat (match-string
+                    1
+                    (elmo-network-session-greeting-internal session))
+                   (elmo-get-passwd
+                    (elmo-network-session-password-key session)))))
+   nil 'no-log)
+  (let ((response (elmo-pop3-read-response
+                  (elmo-network-session-process-internal session)
+                  t)))
+    (case (car response)
+      (ok)
+      (in-use
+       (error "Maildrop is currently in use"))
+      (login-delay
+       (error "Not allowed to login until the login delay period has expired"))
+      (t
+       (signal 'elmo-authenticate-error '(elmo-pop-auth-apop))))
+    (car response)))
 
 (luna-define-method elmo-network-initialize-session-buffer :after
   ((session elmo-pop3-session) buffer)
@@ -379,16 +367,15 @@ until the login delay period has expired")))
                        (elmo-network-session-process-internal session))
     (let* ((process (elmo-network-session-process-internal session))
           (auth (elmo-network-session-auth-internal session))
-          (auth (mapcar '(lambda (mechanism) (upcase (symbol-name mechanism)))
-                        (if (listp auth) auth (list auth))))
-          sasl-mechanisms
-          client name step response mechanism
-          sasl-read-passphrase)
+          (auth (mapcar (lambda (mechanism) (upcase (symbol-name mechanism)))
+                        (if (listp auth) auth (list auth)))))
       (or (and (string= "USER" (car auth))
               (elmo-pop3-auth-user session))
          (and (string= "APOP" (car auth))
               (elmo-pop3-auth-apop session))
-         (progn
+         (let (sasl-mechanisms
+               client name step response mechanism
+               sasl-read-passphrase)
            (require 'sasl)
            (setq sasl-mechanisms (mapcar 'car sasl-mechanism-alist))
            (setq mechanism (sasl-find-mechanism auth))
@@ -406,10 +393,9 @@ until the login delay period has expired")))
            (elmo-network-session-set-auth-internal session
                                                    (intern (downcase name)))
            (setq sasl-read-passphrase
-                 (function
-                  (lambda (prompt)
-                    (elmo-get-passwd
-                     (elmo-network-session-password-key session)))))
+                 (lambda (prompt)
+                   (elmo-get-passwd
+                    (elmo-network-session-password-key session))))
            (setq step (sasl-next-step client nil))
            (elmo-pop3-send-command
             process
@@ -423,17 +409,17 @@ until the login delay period has expired")))
            (catch 'done
              (while t
                (setq response (elmo-pop3-read-response process t))
-               (unless (eq 'ok (car response))
-                 (if (or (eq (car response) 'in-use)
-                         (eq (car response) 'login-delay))
-                     (error (cond ((eq (car response) 'in-use)
-                                   "Maildrop is currently in use")
-                                  ((eq (car response) 'login-delay)
-                                   "Not allowed to login \
-until the login delay period has expired")))
-                   (signal 'elmo-authenticate-error
-                           (list (intern (concat "elmo-pop3-auth-"
-                                                 (downcase name)))))))
+               (case (car response)
+                 (ok)
+                 (in-use
+                  (error "Maildrop is currently in use"))
+                 (login-delay
+                  (error "Not allowed to login \
+until the login delay period has expired"))
+                 (t
+                  (signal 'elmo-authenticate-error
+                          (list (intern (concat "elmo-pop3-auth-"
+                                                (downcase name)))))))
                (if (sasl-next-step client step)
                    ;; Bogus server?
                    (signal 'elmo-authenticate-error
@@ -484,15 +470,15 @@ until the login delay period has expired")))
 (defun elmo-pop3-read-contents (process)
   (with-current-buffer (process-buffer process)
     (let ((case-fold-search nil)
-         match-end)
-      (goto-char elmo-pop3-read-point)
-      (while (not (re-search-forward "^\\.\r\n" nil t))
-       (accept-process-output process 1)
-       (goto-char elmo-pop3-read-point))
-      (setq match-end (point))
+         (point elmo-pop3-read-point))
+      (while (and (goto-char (- point 2))
+                 (not (search-forward "\r\n.\r\n" nil t)))
+       (setq point (max (- (point-max) 2) ; Care of \r\n.\r[EOF] case
+                        elmo-pop3-read-point))
+       (accept-process-output process 1))
       (elmo-delete-cr
        (buffer-substring elmo-pop3-read-point
-                        (- match-end 3))))))
+                        (- (point) 3))))))
 
 (luna-define-method elmo-folder-expand-msgdb-path ((folder elmo-pop3-folder))
   (convert-standard-filename
@@ -580,32 +566,7 @@ until the login delay period has expired")))
        (error "POP3: Error in UIDL")))))
 
 (defun elmo-pop3-list-folder-by-location (folder locations)
-  (let* ((location-alist (elmo-pop3-folder-location-alist-internal folder))
-        (locations-in-db (mapcar 'cdr location-alist))
-        result new-locs new-alist deleted-locs i)
-    (setq new-locs
-         (elmo-delete-if (function
-                          (lambda (x) (member x locations-in-db)))
-                         locations))
-    (setq deleted-locs
-         (elmo-delete-if (function
-                          (lambda (x) (member x locations)))
-                         locations-in-db))
-    (setq i (or (elmo-max-of-list (mapcar 'car location-alist)) 0))
-    (mapcar
-     (function
-      (lambda (x)
-       (setq location-alist
-             (delq (rassoc x location-alist) location-alist))))
-     deleted-locs)
-    (while new-locs
-      (setq i (1+ i))
-      (setq new-alist (cons (cons i (car new-locs)) new-alist))
-      (setq new-locs (cdr new-locs)))
-    (setq result (nconc location-alist new-alist))
-    (setq result (sort result (lambda (x y) (< (car x)(car y)))))
-    (elmo-pop3-folder-set-location-alist-internal folder result)
-    (mapcar 'car result)))
+  (mapcar #'car (elmo-location-map-update folder locations)))
 
 (defun elmo-pop3-list-by-uidl-subr (folder &optional nonsort)
   (let ((flist (elmo-pop3-list-folder-by-location
@@ -623,7 +584,7 @@ until the login delay period has expired")))
       (if elmo-pop3-list-done
          (progn
            (mapatoms (lambda (atom)
-                       (setq list (cons (string-to-int
+                       (setq list (cons (string-to-number
                                          (substring (symbol-name atom) 1))
                                         list)))
                      elmo-pop3-size-hash)
@@ -631,8 +592,7 @@ until the login delay period has expired")))
        (error "POP3: Error in list")))))
 
 (defsubst elmo-pop3-folder-list-messages (folder)
-  (if (and (not elmo-inhibit-number-mapping)
-          (elmo-pop3-folder-use-uidl-internal folder))
+  (if (elmo-pop3-folder-use-uidl folder)
       (elmo-pop3-list-by-uidl-subr folder)
     (elmo-pop3-list-by-list folder)))
 
@@ -643,15 +603,15 @@ until the login delay period has expired")))
 (luna-define-method elmo-folder-status ((folder elmo-pop3-folder))
   (elmo-folder-open-internal folder)
   (elmo-folder-check folder)
-  (if (elmo-pop3-folder-use-uidl-internal folder)
+  (if (elmo-pop3-folder-use-uidl folder)
       (prog1
          (elmo-pop3-list-by-uidl-subr folder 'nonsort)
        (elmo-folder-close-internal folder))
-    (let* ((process
-           (elmo-network-session-process-internal
-            (elmo-pop3-get-session folder)))
-          (total 0)
-          response)
+    (let ((process
+          (elmo-network-session-process-internal
+           (elmo-pop3-get-session folder)))
+         (total 0)
+         response)
       (with-current-buffer (process-buffer process)
        (elmo-pop3-send-command process "STAT")
        (setq response (cdr (elmo-pop3-read-response process)))
@@ -659,7 +619,7 @@ until the login delay period has expired")))
        (if (not (string-match "^\+OK[ \t]*\\([0-9]*\\)" response))
            (error "POP STAT command failed")
          (setq total
-               (string-to-int
+               (string-to-number
                 (substring response (match-beginning 1)(match-end 1 ))))
          (elmo-folder-close-internal folder)
          (cons total total))))))
@@ -680,44 +640,40 @@ until the login delay period has expired")))
     nil)))
 
 (defun elmo-pop3-retrieve-headers (process tobuffer articles)
-  (save-excursion
-    (set-buffer (process-buffer process))
+  (with-current-buffer (process-buffer process)
     (erase-buffer)
-    (let ((number (length articles))
-         (count 0)
+    (let ((count 0)
          (received 0)
          (last-point (point-min)))
-      ;; Send HEAD commands.
-      (while articles
-       (elmo-pop3-send-command process (format
-                                        "top %s 0" (car articles))
-                               'no-erase)
-;;;    (accept-process-output process 1)
-       (setq articles (cdr articles))
-       (setq count (1+ count))
-       ;; Every 200 requests we have to read the stream in
-       ;; order to avoid deadlocks.
-       (when (or elmo-pop3-send-command-synchronously
-                 (null articles)       ;All requests have been sent.
-                 (zerop (% count elmo-pop3-header-fetch-chop-length)))
-         (unless elmo-pop3-send-command-synchronously
-           (accept-process-output process 1))
-         (discard-input)
-         (while (progn
-                  (goto-char last-point)
-                  ;; Count replies.
-                  (while (elmo-pop3-next-result-arrived-p)
-                    (setq last-point (point))
-                    (setq received (1+ received)))
-                  (< received count))
-           (when (> number elmo-display-progress-threshold)
-             (if (or (zerop (% received 5)) (= received number))
-                 (elmo-display-progress
-                  'elmo-pop3-retrieve-headers "Getting headers..."
-                  (/ (* received 100) number))))
-           (accept-process-output process 1)
-;;;        (accept-process-output process)
-           (discard-input))))
+      (elmo-with-progress-display (elmo-retrieve-header (length articles))
+         "Getting headers"
+       ;; Send HEAD commands.
+       (while articles
+         (elmo-pop3-send-command process
+                                 (format "top %s 0" (car articles))
+                                 'no-erase)
+;;;      (accept-process-output process 1)
+         (setq articles (cdr articles))
+         (setq count (1+ count))
+         ;; Every 200 requests we have to read the stream in
+         ;; order to avoid deadlocks.
+         (when (or elmo-pop3-send-command-synchronously
+                   (null articles)     ;All requests have been sent.
+                   (zerop (% count elmo-pop3-header-fetch-chop-length)))
+           (unless elmo-pop3-send-command-synchronously
+             (accept-process-output process 1))
+           (discard-input)
+           (while (progn
+                    (goto-char last-point)
+                    ;; Count replies.
+                    (while (elmo-pop3-next-result-arrived-p)
+                      (setq last-point (point))
+                      (setq received (1+ received)))
+                    (< received count))
+             (elmo-progress-notify 'elmo-retrieve-header :set received)
+             (accept-process-output process 1)
+;;;          (accept-process-output process)
+             (discard-input)))))
       ;; Replace all CRLF with LF.
       (elmo-delete-cr-buffer)
       (copy-to-buffer tobuffer (point-min) (point-max)))))
@@ -727,30 +683,11 @@ until the login delay period has expired")))
   (let ((process (elmo-network-session-process-internal
                  (elmo-pop3-get-session folder))))
     (with-current-buffer (process-buffer process)
-      (elmo-pop3-sort-msgdb-by-original-number
+      (elmo-pop3-msgdb-create-by-header
        folder
-       (elmo-pop3-msgdb-create-by-header
-       folder
-       process
-       numlist
-       flag-table
-       (if (elmo-pop3-folder-use-uidl-internal folder)
-           (elmo-pop3-folder-location-alist-internal folder)))))))
-
-(defun elmo-pop3-sort-msgdb-by-original-number (folder msgdb)
-  (let ((location-alist (elmo-pop3-folder-location-alist-internal folder)))
-    (when location-alist
-      (elmo-msgdb-sort-entities
-       msgdb
-       (lambda (ent1 ent2 loc-alist)
-        (< (elmo-pop3-uidl-to-number
-            (cdr (assq (elmo-message-entity-number ent1)
-                       loc-alist)))
-           (elmo-pop3-uidl-to-number
-            (cdr (assq (elmo-message-entity-number ent2)
-                       loc-alist)))))
-       location-alist))
-    msgdb))
+       process
+       (sort numlist #'<)
+       flag-table))))
 
 (defun elmo-pop3-uidl-to-number (uidl)
   (string-to-number (elmo-get-hash-val uidl
@@ -761,85 +698,77 @@ until the login delay period has expired")))
                     elmo-pop3-number-uidl-hash))
 
 (defun elmo-pop3-number-to-size (number)
-  (elmo-get-hash-val (format "#%d" number)
-                    elmo-pop3-size-hash))
+  (string-to-number
+   (elmo-get-hash-val (format "#%d" number) elmo-pop3-size-hash)))
 
 (defun elmo-pop3-msgdb-create-by-header (folder process numlist
-                                               flag-table
-                                               loc-alist)
+                                               flag-table)
   (let ((tmp-buffer (get-buffer-create " *ELMO Overview TMP*")))
-    (with-current-buffer (process-buffer process)
-      (if loc-alist ; use uidl.
-         (setq numlist
-               (delq
-                nil
-                (mapcar
-                 (lambda (number)
-                   (elmo-pop3-uidl-to-number (cdr (assq number loc-alist))))
-                 numlist))))
-      (elmo-pop3-retrieve-headers process tmp-buffer numlist)
-      (prog1
+    (unwind-protect
+       (with-current-buffer (process-buffer process)
+         (when (elmo-pop3-folder-use-uidl folder)
+           (setq numlist
+                 (delq
+                  nil
+                  (mapcar
+                   (lambda (number)
+                     (elmo-pop3-uidl-to-number
+                      (elmo-map-message-location folder number)))
+                   numlist))))
+         (elmo-pop3-retrieve-headers process tmp-buffer numlist)
          (elmo-pop3-msgdb-create-message
           folder
           tmp-buffer
           process
           (length numlist)
           numlist
-          flag-table loc-alist)
-       (kill-buffer tmp-buffer)))))
+          flag-table))
+      (kill-buffer tmp-buffer))))
 
 (defun elmo-pop3-msgdb-create-message (folder
                                       buffer
                                       process
                                       num
                                       numlist
-                                      flag-table
-                                      loc-alist)
+                                      flag-table)
   (save-excursion
     (let ((new-msgdb (elmo-make-msgdb))
-         beg entity i number message-id flags)
+         beg entity number message-id flags)
       (set-buffer buffer)
       (set-buffer-multibyte default-enable-multibyte-characters)
       (goto-char (point-min))
-      (setq i 0)
-      (message "Creating msgdb...")
-      (while (not (eobp))
-       (setq beg (save-excursion (forward-line 1) (point)))
-       (elmo-pop3-next-result-arrived-p)
-       (save-excursion
-         (forward-line -1)
-         (save-restriction
-           (narrow-to-region beg (point))
-           (setq entity
-                 (elmo-msgdb-create-message-entity-from-buffer
-                  (elmo-msgdb-message-entity-handler new-msgdb)
-                  (car numlist)))
-           (setq numlist (cdr numlist))
-           (when entity
-             (with-current-buffer (process-buffer process)
-               (elmo-message-entity-set-field
-                entity
-                'size
-                (string-to-number
-                 (elmo-pop3-number-to-size
-                  (elmo-message-entity-number entity))))
-               (if (setq number
-                         (car
-                          (rassoc
-                           (elmo-pop3-number-to-uidl
-                            (elmo-message-entity-number entity))
-                           loc-alist)))
+      (elmo-with-progress-display (elmo-folder-msgdb-create num)
+         "Creating msgdb"
+       (while (not (eobp))
+         (setq beg (save-excursion (forward-line 1) (point)))
+         (elmo-pop3-next-result-arrived-p)
+         (save-excursion
+           (forward-line -1)
+           (save-restriction
+             (narrow-to-region beg (point))
+             (setq entity
+                   (elmo-msgdb-create-message-entity-from-buffer
+                    (elmo-msgdb-message-entity-handler new-msgdb)
+                    (car numlist)))
+             (setq numlist (cdr numlist))
+             (when entity
+               (with-current-buffer (process-buffer process)
+                 (elmo-message-entity-set-field
+                  entity
+                  'size
+                  (elmo-pop3-number-to-size
+                   (elmo-message-entity-number entity)))
+                 (when (setq number
+                             (elmo-map-message-number
+                              folder
+                              (elmo-pop3-number-to-uidl
+                               (elmo-message-entity-number entity))))
                    (elmo-message-entity-set-number entity number)))
-             (setq message-id (elmo-message-entity-field entity 'message-id)
-                   flags (elmo-flag-table-get flag-table message-id))
-             (elmo-global-flags-set flags folder number message-id)
-             (elmo-msgdb-append-entity new-msgdb entity flags))))
-       (when (> num elmo-display-progress-threshold)
-         (setq i (1+ i))
-         (if (or (zerop (% i 5)) (= i num))
-             (elmo-display-progress
-              'elmo-pop3-msgdb-create-message "Creating msgdb..."
-              (/ (* i 100) num)))))
+               (setq message-id (elmo-message-entity-field entity 'message-id)
+                     flags (elmo-flag-table-get flag-table message-id))
+               (elmo-global-flags-set flags folder number message-id)
+               (elmo-msgdb-append-entity new-msgdb entity flags))))
+         (elmo-progress-notify 'elmo-folder-msgdb-create)))
       new-msgdb)))
 
 (defun elmo-pop3-read-body (process outbuf)
@@ -857,19 +786,17 @@ until the login delay period has expired")))
       t)))
 
 (luna-define-method elmo-folder-open-internal ((folder elmo-pop3-folder))
-  (if (and (not elmo-inhibit-number-mapping)
-          (elmo-pop3-folder-use-uidl-internal folder))
-      (elmo-pop3-folder-set-location-alist-internal
-       folder (elmo-msgdb-location-load (elmo-folder-msgdb-path folder)))))
+  (unless (elmo-location-map-alist folder)
+    (when (elmo-pop3-folder-use-uidl folder)
+      (elmo-location-map-load folder (elmo-folder-msgdb-path folder)))))
 
 (luna-define-method elmo-folder-commit :after ((folder elmo-pop3-folder))
-  (when (elmo-folder-persistent-p folder)
-    (elmo-msgdb-location-save (elmo-folder-msgdb-path folder)
-                             (elmo-pop3-folder-location-alist-internal
-                              folder))))
+  (when (and (not elmo-inhibit-number-mapping)
+            (elmo-folder-persistent-p folder))
+    (elmo-location-map-save folder (elmo-folder-msgdb-path folder))))
 
 (luna-define-method elmo-folder-close-internal ((folder elmo-pop3-folder))
-  (elmo-pop3-folder-set-location-alist-internal folder nil)
+  (elmo-location-map-teardown folder)
   ;; Just close connection
   (elmo-folder-check folder))
 
@@ -877,37 +804,23 @@ until the login delay period has expired")))
                                                number strategy
                                                &optional section
                                                outbuf unseen)
-  (let* ((loc-alist (elmo-pop3-folder-location-alist-internal folder))
-        (process (elmo-network-session-process-internal
-                  (elmo-pop3-get-session folder)))
+  (let ((process (elmo-network-session-process-internal
+                 (elmo-pop3-get-session folder)))
        size  response errmsg msg)
     (with-current-buffer (process-buffer process)
-      (if loc-alist
-         (setq number (elmo-pop3-uidl-to-number
-                       (cdr (assq number loc-alist)))))
-      (setq size (string-to-number
-                 (elmo-pop3-number-to-size number)))
+      (when (elmo-pop3-folder-use-uidl folder)
+       (setq number (elmo-pop3-uidl-to-number
+                     (elmo-map-message-location folder number))))
+      (setq size (elmo-pop3-number-to-size number))
       (when number
-       (elmo-pop3-send-command process
-                               (format "retr %s" number))
-       (unless elmo-inhibit-display-retrieval-progress
-         (setq elmo-pop3-total-size size)
-         (elmo-display-progress
-          'elmo-display-retrieval-progress
-          (format "Retrieving (0/%d bytes)..." elmo-pop3-total-size)
-          0))
-       (unwind-protect
-           (progn
-             (when (null (setq response (cdr (elmo-pop3-read-response
-                                              process t))))
-               (error "Fetching message failed"))
-             (setq response  (elmo-pop3-read-body process outbuf)))
-         (setq elmo-pop3-total-size nil))
-       (unless elmo-inhibit-display-retrieval-progress
-         (elmo-display-progress
-          'elmo-display-retrieval-progress
-          "Retrieving..." 100)  ; remove progress bar.
-         (message "Retrieving...done"))
+       (elmo-with-progress-display
+           (elmo-retrieve-message size elmo-pop3-retrieve-progress-reporter)
+           "Retrieving"
+         (elmo-pop3-send-command process (format "retr %s" number))
+         (when (null (setq response (cdr (elmo-pop3-read-response
+                                          process t))))
+           (error "Fetching message failed"))
+         (setq response  (elmo-pop3-read-body process outbuf)))
        (set-buffer outbuf)
        (goto-char (point-min))
        (while (re-search-forward "^\\." nil t)
@@ -916,29 +829,28 @@ until the login delay period has expired")))
        (elmo-delete-cr-buffer)
        response))))
 
-(defun elmo-pop3-delete-msg (process number loc-alist)
-  (with-current-buffer (process-buffer process)
-    (let (response errmsg msg)
-      (if loc-alist
-         (setq number (elmo-pop3-uidl-to-number
-                       (cdr (assq number loc-alist)))))
-      (if number
-         (progn
-           (elmo-pop3-send-command process
-                                   (format "dele %s" number))
-           (when (null (setq response (cdr (elmo-pop3-read-response
-                                            process t))))
-             (error "Deleting message failed")))
-       (error "Deleting message failed")))))
+(defun elmo-pop3-delete-msg (process number)
+  (unless number
+    (error "Deleting message failed"))
+  (elmo-pop3-send-command process (format "dele %s" number))
+  (when (null (cdr (elmo-pop3-read-response process t)))
+    (error "Deleting message failed")))
 
 (luna-define-method elmo-folder-delete-messages-plugged ((folder
                                                          elmo-pop3-folder)
                                                         msgs)
-  (let ((loc-alist (elmo-pop3-folder-location-alist-internal folder))
-       (process (elmo-network-session-process-internal
+  (let ((process (elmo-network-session-process-internal
                  (elmo-pop3-get-session folder))))
-    (mapcar '(lambda (msg) (elmo-pop3-delete-msg process msg loc-alist))
-           msgs)))
+    (with-current-buffer (process-buffer process)
+      (dolist (number (if (elmo-pop3-folder-use-uidl folder)
+                         (mapcar
+                          (lambda (number)
+                            (elmo-pop3-uidl-to-number
+                             (elmo-map-message-location folder number)))
+                          msgs)
+                       msgs))
+       (elmo-pop3-delete-msg process number))
+      t)))
 
 (luna-define-method elmo-message-use-cache-p ((folder elmo-pop3-folder) number)
   elmo-pop3-use-cache)
@@ -950,7 +862,7 @@ until the login delay period has expired")))
 (luna-define-method elmo-folder-clear :around ((folder elmo-pop3-folder)
                                               &optional keep-killed)
   (unless keep-killed
-    (elmo-pop3-folder-set-location-alist-internal folder nil))
+    (elmo-location-map-setup folder))
   (luna-call-next-method))
 
 (luna-define-method elmo-folder-check ((folder elmo-pop3-folder))