Fix typo.
[elisp/wanderlust.git] / elmo / elmo-localdir.el
index 0c8597d..46b7ebe 100644 (file)
@@ -1,10 +1,13 @@
 ;;; elmo-localdir.el -- Localdir Interface for ELMO.
 
-;; Copyright 1998,1999,2000 Yuuichi Teranishi <teranisi@gohome.org>
+;; Copyright (C) 1998,1999,2000 Yuuichi Teranishi <teranisi@gohome.org>
+;; Copyright (C) 1998,1999,2000 Masahiro MURATA <muse@ba2.so-net.ne.jp>
+;; Copyright (C) 1999,2000      Kenichi OKADA  <okada@opaopa.org>
 
 ;; Author: Yuuichi Teranishi <teranisi@gohome.org>
+;;     Masahiro MURATA <muse@ba2.so-net.ne.jp>
+;;     Kenichi OKADA <okada@opaopa.org>
 ;; Keywords: mail, net news
-;; Time-stamp: <2000-05-18 17:12:55 teranisi>
 
 ;; This file is part of ELMO (Elisp Library for Message Orchestration).
 
@@ -69,8 +72,8 @@
       (when (file-exists-p file)
        ;; Read until header separator is found.
        (while (and (eq elmo-localdir-header-chop-length
-                       (nth 1 
-                            (as-binary-input-file 
+                       (nth 1
+                            (as-binary-input-file
                              (insert-file-contents
                               file nil beg
                               (incf beg elmo-localdir-header-chop-length)))))
              (elmo-localdir-insert-header file)
            (error (throw 'done nil)))
          (goto-char (point-min))
-         (setq header-end 
+         (setq header-end
                (if (re-search-forward "\\(^--.*$\\)\\|\\(\n\n\\)" nil t)
                    (point)
                  (point-max)))
   (elmo-localdir-msgdb-create-overview-entity-from-file
    number (expand-file-name (int-to-string number) dir)))
 
-(defun elmo-localdir-msgdb-create-as-numlist (spec numlist new-mark 
-                                                  already-mark seen-mark 
+(defun elmo-localdir-msgdb-create-as-numlist (spec numlist new-mark
+                                                  already-mark seen-mark
                                                   important-mark seen-list)
   (when numlist
     (let ((dir (elmo-localdir-get-folder-directory spec))
          overview number-alist mark-alist entity message-id
-         i percent len num seen gmark)
-      (setq len (length numlist))
-      (setq i 0)
+         num seen gmark
+         (i 0)
+         (len (length numlist)))
       (message "Creating msgdb...")
       (while numlist
        (setq entity
-             (elmo-localdir-msgdb-create-entity 
+             (elmo-localdir-msgdb-create-entity
               dir (car numlist)))
        (if (null entity)
            ()
          (setq num (elmo-msgdb-overview-entity-get-number entity))
-         (setq overview 
+         (setq overview
                (elmo-msgdb-append-element
                 overview entity))
-         (setq number-alist
-               (elmo-msgdb-number-add number-alist
-                                      num
-                                      (elmo-msgdb-overview-entity-get-id
-                                       entity)))
          (setq message-id (elmo-msgdb-overview-entity-get-id entity))
+         (setq number-alist
+               (elmo-msgdb-number-add number-alist
+                                      num
+                                      message-id))
          (setq seen (member message-id seen-list))
          (if (setq gmark (or (elmo-msgdb-global-mark-get message-id)
                              (if (elmo-cache-exists-p message-id) ; XXX
-                                 (if seen 
+                                 (if seen
                                      nil
                                    already-mark)
-                               (if seen 
+                               (if seen
                                    nil ;;seen-mark
                                  new-mark))))
              (setq mark-alist
-                   (elmo-msgdb-mark-append 
-                    mark-alist 
+                   (elmo-msgdb-mark-append
+                    mark-alist
                     num
                     gmark))))
-       (setq i (1+ i))
-       (setq percent (/ (* i 100) len))
-       (elmo-display-progress
-        'elmo-localdir-msgdb-create-as-numlist "Creating msgdb..."
-        percent)
+       (when (> len elmo-display-progress-threshold)
+         (setq i (1+ i))
+         (elmo-display-progress
+          'elmo-localdir-msgdb-create-as-numlist "Creating msgdb..."
+          (/ (* i 100) len)))
        (setq numlist (cdr numlist)))
-      (message "Creating msgdb...done.")
+      (message "Creating msgdb...done")
       (list overview number-alist mark-alist))))
 
 (defalias 'elmo-localdir-msgdb-create 'elmo-localdir-msgdb-create-as-numlist)
 
 (defun elmo-localdir-list-folders-subr (folder &optional hierarchy)
   (let ((case-fold-search t)
+       (w32-get-true-file-link-count t) ; for Meadow
        folders curdir dirent relpath abspath attr
        subprefix subfolder)
     (condition-case ()
            (setq dirent (cdr dirent))
            (setq abspath (expand-file-name relpath curdir))
            (and
-            (not (string-match 
+            (not (string-match
                   elmo-localdir-list-folders-filter-regexp
                   relpath))
             (eq (nth 0 (setq attr (file-attributes abspath))) t)
 (defsubst elmo-localdir-list-folder-subr (spec &optional nonsort)
   (let* ((dir (elmo-localdir-get-folder-directory spec))
         (flist (mapcar 'string-to-int
-                       (directory-files dir nil "^[0-9]+$" t))))
+                       (directory-files dir nil "^[0-9]+$" t)))
+        (killed (and elmo-use-killed-list
+                     (elmo-msgdb-killed-list-load
+                      (elmo-msgdb-expand-path spec))))
+        numbers)
     (if nonsort
-       (cons (or (elmo-max-of-list flist) 0) (length flist))
-      (sort flist '<))))
+       (cons (or (elmo-max-of-list flist) 0)
+             (if killed
+                 (- (length flist)
+                    (elmo-msgdb-killed-list-length killed))
+               (length flist)))
+      (setq numbers (sort flist '<))
+      (elmo-living-messages numbers killed))))
 
 (defun elmo-localdir-append-msg (spec string &optional msg no-see)
   (let ((dir (elmo-localdir-get-folder-directory spec))
        (tmp-buffer (get-buffer-create " *ELMO Temp buffer*"))
        (next-num (or msg
-                     (1+ (car (elmo-localdir-list-folder-subr spec t)))))
+                     (1+ (car (elmo-localdir-max-of-folder spec)))))
        filename)
     (save-excursion
       (set-buffer tmp-buffer)
     (setq file (expand-file-name number dir))
     (if (and (string-match "[0-9]+" number) ; for safety.
             (file-exists-p file)
-            (file-writable-p file) 
+            (file-writable-p file)
             (not (file-directory-p file)))
        (progn (delete-file file)
               t))))
 
-(defun elmo-localdir-read-msg (spec number outbuf &optional set-mark)
+(defun elmo-localdir-read-msg (spec number outbuf &optional msgdb unread)
   (save-excursion
     (let* ((number (int-to-string number))
           (dir (elmo-localdir-get-folder-directory spec))
   (mapcar '(lambda (msg) (elmo-localdir-delete-msg spec msg))
          msgs))
 
-(defun elmo-localdir-list-folder (spec); called by elmo-localdir-search()
+(defun elmo-localdir-list-folder (spec &optional nohide); called by elmo-localdir-search()
   (elmo-localdir-list-folder-subr spec))
 
 (defun elmo-localdir-max-of-folder (spec)
 (defun elmo-localdir-check-validity (spec validity-file)
   (let* ((dir (elmo-localdir-get-folder-directory spec))
         (cur-val (nth 5 (file-attributes dir)))
-        (file-val (read 
+        (file-val (read
                    (or (elmo-get-file-string validity-file)
                        "nil"))))
     (cond
       (prin1 (nth 5 (file-attributes dir)) tmp-buffer)
       (princ "\n" tmp-buffer)
       (if (file-writable-p validity-file)
-         (write-region (point-min) (point-max) 
+         (write-region (point-min) (point-max)
                        validity-file nil 'no-msg)
        (message (format "%s is not writable." number-file)))
       (kill-buffer tmp-buffer))))
 (defun elmo-localdir-delete-folder (spec)
   (let* ((dir (elmo-localdir-get-folder-directory spec)))
     (if (not (file-directory-p dir))
-       (error "no such directory: %s" dir)
+       (error "No such directory: %s" dir)
       (elmo-delete-directory dir t)
       t)))
 
         (new (elmo-localdir-get-folder-directory new-spec))
         (new-dir (directory-file-name (file-name-directory new))))
     (if (not (file-directory-p old))
-       (error "no such directory: %s" old)
+       (error "No such directory: %s" old)
       (if (file-exists-p new)
-         (error "already exists directory: %s" new)
+         (error "Already exists directory: %s" new)
        (if (not (file-exists-p new-dir))
            (elmo-make-directory new-dir))
        (rename-file old new)
        t))))
 
-(defsubst elmo-localdir-field-condition-match (spec number condition)
-  (elmo-file-field-condition-match 
-   (expand-file-name (int-to-string number)
-                    (elmo-localdir-get-folder-directory spec))
-   condition))
+(defsubst elmo-localdir-field-primitive-condition-match (spec
+                                                        condition
+                                                        number
+                                                        number-list)
+  (let (result)
+    (goto-char (point-min))
+    (cond
+     ((string= (elmo-filter-key condition) "last")
+      (setq result (<= (length (memq number number-list))
+                      (string-to-int (elmo-filter-value condition)))))
+     ((string= (elmo-filter-key condition) "first")
+      (setq result (< (- (length number-list)
+                        (length (memq number number-list)))
+                     (string-to-int (elmo-filter-value condition)))))
+     (t
+      (elmo-set-work-buf
+       (as-binary-input-file (insert-file-contents
+                             (expand-file-name
+                              (int-to-string number)
+                              (elmo-localdir-get-folder-directory spec))))
+       (elmo-set-buffer-multibyte default-enable-multibyte-characters)
+       ;; Should consider charset?
+       (decode-mime-charset-region (point-min)(point-max) elmo-mime-charset)
+       (setq result
+            (elmo-buffer-field-primitive-condition-match
+             condition number number-list)))))
+    (if (eq (elmo-filter-type condition) 'unmatch)
+       (setq result (not result)))
+    result))
+
+(defun elmo-localdir-field-condition-match (spec condition number number-list)
+  (cond
+   ((vectorp condition)
+    (elmo-localdir-field-primitive-condition-match
+     spec condition number number-list))
+   ((eq (car condition) 'and)
+    (and (elmo-localdir-field-condition-match
+         spec (nth 1 condition) number number-list)
+        (elmo-localdir-field-condition-match
+         spec (nth 2 condition) number number-list)))
+   ((eq (car condition) 'or)
+    (or (elmo-localdir-field-condition-match
+        spec (nth 1 condition) number number-list)
+       (elmo-localdir-field-condition-match
+        spec (nth 2 condition) number number-list)))))
 
 (defun elmo-localdir-search (spec condition &optional from-msgs)
   (let* ((msgs (or from-msgs (elmo-localdir-list-folder spec)))
         (num (length msgs))
-        (i 0) case-fold-search ret-val)
-    (while msgs
-      (if (elmo-localdir-field-condition-match spec (car msgs)
-                                              condition)
-         (setq ret-val (cons (car msgs) ret-val)))
-      (setq i (1+ i))
-      (elmo-display-progress
-       'elmo-localdir-search "Searching..."
-       (/ (* i 100) num))
-      (setq msgs (cdr msgs)))
-    (nreverse ret-val)))
+        (i 0)
+        last cur number-list case-fold-search ret-val)
+    (cond
+     ;; short cut.
+     ((and (vectorp condition)
+          (string= (elmo-filter-key condition) "last"))
+      (nthcdr (max (- (length msgs)
+                     (string-to-int (elmo-filter-value condition)))
+                  0)
+             msgs))
+     ((and (vectorp condition)
+          (string= (elmo-filter-key condition) "first"))
+      (let ((rest (nthcdr (string-to-int (elmo-filter-value condition) )
+                         msgs)))
+       (mapcar '(lambda (x)
+                  (delete x msgs)) rest))
+      msgs)
+     (t
+      (setq number-list msgs)
+      (while msgs
+       (if (elmo-localdir-field-condition-match spec condition
+                                                (car msgs) number-list)
+           (setq ret-val (cons (car msgs) ret-val)))
+       (when (> num elmo-display-progress-threshold)
+         (setq i (1+ i))
+         (setq cur (/ (* i 100) num))
+         (unless (eq cur last)
+           (elmo-display-progress
+            'elmo-localdir-search "Searching..."
+            cur)
+           (setq last cur)))
+       (setq msgs (cdr msgs)))
+      (nreverse ret-val)))))
 
 ;;; (localdir, maildir, localnews) -> localdir
 (defun elmo-localdir-copy-msgs (dst-spec msgs src-spec
                                         &optional loc-alist same-number)
   (let ((dst-dir
         (elmo-localdir-get-folder-directory dst-spec))
-       (next-num (1+ (car (elmo-localdir-list-folder-subr dst-spec t)))))
+       (next-num (1+ (car (elmo-localdir-max-of-folder dst-spec)))))
     (while msgs
       (elmo-copy-file
        ;; src file
                (if (and (eq (car dst-spec) 'localdir)
                         (elmo-localdir-locked-p))
                    ;; MDA is running.
-                   (1+ (car (elmo-localdir-list-folder-subr dst-spec t)))
+                   (1+ (car (elmo-localdir-max-of-folder dst-spec)))
                  (1+ next-num)))))
     t))
 
   (let ((dir (elmo-localdir-get-folder-directory spec))
        (onum-alist (elmo-msgdb-get-number-alist msgdb))
        (omark-alist (elmo-msgdb-get-mark-alist msgdb))
-       (oov (elmo-msgdb-get-overview msgdb))
-       i flist onum mark new-mark-alist total)
-    (setq i 0)
+       (new-number 1)                  ; first ordinal position in localdir
+       flist onum mark new-mark-alist total)
     (setq flist
          (if elmo-pack-number-check-strict
-             (elmo-call-func spec "list-folder") ;; allow localnews
+             (elmo-call-func spec "list-folder") ; allow localnews
            (mapcar 'car onum-alist)))
     (setq total (length flist))
     (while flist
-      (elmo-display-progress
-       'elmo-localdir-pack-number "Packing..."
-       (/ (* i 100) total))
+      (when (> total elmo-display-progress-threshold)
+       (elmo-display-progress
+        'elmo-localdir-pack-number "Packing..."
+        (/ (* new-number 100) total)))
       (setq onum (car flist))
-      (when (not (eq onum i)) ;; why \=() is wrong..
+      (when (not (eq onum new-number))         ; why \=() is wrong..
         (elmo-bind-directory
         dir
         ;; xxx  nfs,hardlink
-        (rename-file (int-to-string onum) (int-to-string i) t))
+        (rename-file (int-to-string onum) (int-to-string new-number) t))
         ;; update overview
         (elmo-msgdb-overview-entity-set-number
-        (elmo-msgdb-overview-get-entity-by-number
-         oov onum) i)
+        (elmo-msgdb-overview-get-entity onum msgdb)
+        new-number)
        ;; update number-alist
-       (setcar (assq onum onum-alist) i))
+       (setcar (assq onum onum-alist) new-number))
       ;; update mark-alist
       (when (setq mark (cadr (assq onum omark-alist)))
        (setq new-mark-alist
              (elmo-msgdb-mark-append
               new-mark-alist
-              i mark)))
-      (setq i (1+ i))
+              new-number mark)))
+      (setq new-number (1+ new-number))
       (setq flist (cdr flist)))
-    (message "Packing...done.")
+    (message "Packing...done")
     (list (elmo-msgdb-get-overview msgdb)
          onum-alist
          new-mark-alist
-         (elmo-msgdb-get-location msgdb))))
+         (elmo-msgdb-get-location msgdb)
+         ;; remake hash table
+         (elmo-msgdb-make-overview-hashtb (elmo-msgdb-get-overview msgdb)))))
 
 (defun elmo-localdir-use-cache-p (spec number)
   nil)
   t)
 
 (defun elmo-localdir-get-msg-filename (spec number &optional loc-alist)
-  (expand-file-name 
+  (expand-file-name
    (int-to-string number)
    (elmo-localdir-get-folder-directory spec)))
 
                (throw 'found t))
            (setq lock (cdr lock)))))))
 
-(defalias 'elmo-localdir-sync-number-alist 
+(defalias 'elmo-localdir-sync-number-alist
   'elmo-generic-sync-number-alist)
-(defalias 'elmo-localdir-list-folder-unread 
+(defalias 'elmo-localdir-list-folder-unread
   'elmo-generic-list-folder-unread)
 (defalias 'elmo-localdir-list-folder-important
   'elmo-generic-list-folder-important)
 (defalias 'elmo-localdir-commit 'elmo-generic-commit)
+(defalias 'elmo-localdir-folder-diff 'elmo-generic-folder-diff)
 
-(provide 'elmo-localdir)
+(require 'product)
+(product-provide (provide 'elmo-localdir) (require 'elmo-version))
 
 ;;; elmo-localdir.el ends here