* wl-folder.el (wl-folder-guess-mailing-list-by-folder-name):
[elisp/wanderlust.git] / wl / wl-folder.el
1 ;;; wl-folder.el -- Folder mode for Wanderlust.
2
3 ;; Copyright (C) 1998,1999,2000 Yuuichi Teranishi <teranisi@gohome.org>
4 ;; Copyright (C) 1998,1999,2000 Masahiro MURATA <muse@ba2.so-net.ne.jp>
5
6 ;; Author: Yuuichi Teranishi <teranisi@gohome.org>
7 ;;      Masahiro MURATA <muse@ba2.so-net.ne.jp>
8 ;; Keywords: mail, net news
9
10 ;; This file is part of Wanderlust (Yet Another Message Interface on Emacsen).
11
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)
15 ;; any later version.
16 ;;
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.
21 ;;
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.
26 ;;
27
28 ;;; Commentary:
29 ;;
30
31 ;;; Code:
32 ;;
33
34 (require 'elmo-vars)
35 (require 'elmo-util)
36 (require 'elmo2)
37 (require 'wl-vars)
38 (condition-case ()
39     (require 'easymenu) ; needed here.
40   (error))
41
42 (eval-when-compile
43   (require 'cl)
44   (require 'wl-util)
45   (provide 'wl-folder)
46   (require 'wl)
47   (require 'elmo-nntp)
48   (if wl-use-semi
49       (require 'mmelmo))
50   (unless (boundp ':file)
51     (set (make-local-variable ':file) nil))
52   (defun-maybe mmelmo-cleanup-entity-buffers ()))
53
54 (defvar wl-folder-buffer-name "Folder")
55 (defvar wl-folder-entity nil)           ; desktop entity.
56 (defvar wl-folder-group-alist nil)      ; opened or closed
57 (defvar wl-folder-entity-id nil) ; id
58 (defvar wl-folder-entity-hashtb nil)
59 (defvar wl-folder-entity-id-name-hashtb nil)
60 (defvar wl-folder-newsgroups-hashtb nil)
61 (defvar wl-folder-info-alist-modified nil)
62 (defvar wl-folder-completion-func nil)
63
64 (defvar wl-folder-mode-map nil)
65
66 (defvar wl-folder-buffer-disp-summary nil)
67 (defvar wl-folder-buffer-cur-entity-id nil)
68 (defvar wl-folder-buffer-cur-path nil)
69 (defvar wl-folder-buffer-cur-point nil)
70
71 (make-variable-buffer-local 'wl-folder-buffer-disp-summary)
72 (make-variable-buffer-local 'wl-folder-buffer-cur-entity-id)
73 (make-variable-buffer-local 'wl-folder-buffer-cur-path)
74 (make-variable-buffer-local 'wl-folder-buffer-cur-point)
75
76 (defconst wl-folder-entity-regexp "^\\([ ]*\\)\\(\\[[\\+-]\\]\\)?\\([^\\[].+\\):[-*0-9]+/[-*0-9]+/[-*0-9]+")
77 (defconst wl-folder-group-regexp  "^\\([ ]*\\)\\[\\([\\+-]\\)\\]\\(.+\\):[-0-9-]+/[0-9-]+/[0-9-]+\n")
78 ;;                              1:indent 2:opened 3:group-name
79 (defconst wl-folder-unsync-regexp ":[^0\\*][0-9]*/[0-9\\*-]+/[0-9\\*-]+$")
80
81 (defvar wl-folder-mode-menu-spec
82   '("Folder"
83     ["Enter Current Folder" wl-folder-jump-to-current-entity t]
84     ["Prev Folder"          wl-folder-prev-entity t]
85     ["Next Folder"          wl-folder-next-entity t]
86     ["Check Current Folder" wl-folder-check-current-entity t]
87     ["Sync Current Folder"  wl-folder-sync-current-entity t]
88     ["Drop Current Folder" wl-folder-drop-unsync-current-entity t]
89     ["Prefetch Current Folder" wl-folder-prefetch-current-entity t]
90     ["Mark as Read all Current Folder" wl-folder-mark-as-read-all-current-entity t]
91     ["Expire Current Folder" wl-folder-expire-current-entity t]
92     ["Empty trash" wl-folder-empty-trash t]
93     ["Flush queue" wl-folder-flush-queue t]
94     ["Open All" wl-folder-open-all t]
95     ["Open All Unread folder" wl-folder-open-all-unread-folder t]
96     ["Close All" wl-folder-close-all t]
97     ("Folder Manager"
98      ["Add folder" wl-fldmgr-add t]
99      ["Add group" wl-fldmgr-make-group t]
100      ["Copy" wl-fldmgr-copy t]
101      ["Cut" wl-fldmgr-cut t]
102      ["Paste" wl-fldmgr-yank t]
103      ["Set petname" wl-fldmgr-set-petname t]
104      ["Rename" wl-fldmgr-rename t]
105      ["Save" wl-fldmgr-save-folders t]
106      "----"
107      ["Unsubscribe" wl-fldmgr-unsubscribe t]
108      ["Display all" wl-fldmgr-access-display-all t])
109     "----"
110     ["Write a message" wl-draft t]
111     "----"
112     ["Toggle Plug Status" wl-toggle-plugged t]
113     ["Change Plug Status" wl-plugged-change t]
114     "----"
115     ["Save Current Status"  wl-save t]
116     ["Update Satus"         wl-status-update t]
117     ["Exit"                 wl-exit t]
118     ))
119
120 (if wl-on-xemacs
121     (defun wl-folder-setup-mouse ()
122       (define-key wl-folder-mode-map 'button2 'wl-folder-click)
123       (define-key wl-folder-mode-map 'button4 'wl-folder-prev-entity)
124       (define-key wl-folder-mode-map 'button5 'wl-folder-next-entity)
125       (define-key wl-folder-mode-map [(shift button4)]
126         'wl-folder-prev-unread)
127       (define-key wl-folder-mode-map [(shift button5)]
128         'wl-folder-next-unread))
129   (if wl-on-nemacs
130       (defun wl-folder-setup-mouse ())
131     (defun wl-folder-setup-mouse ()
132       (define-key wl-folder-mode-map [mouse-2] 'wl-folder-click)
133       (define-key wl-folder-mode-map [mouse-4] 'wl-folder-prev-entity)
134       (define-key wl-folder-mode-map [mouse-5] 'wl-folder-next-entity)
135       (define-key wl-folder-mode-map [S-mouse-4] 'wl-folder-prev-unread)
136       (define-key wl-folder-mode-map [S-mouse-5] 'wl-folder-next-unread))))
137
138 (if wl-folder-mode-map
139     nil
140   (setq wl-folder-mode-map (make-sparse-keymap))
141   (define-key wl-folder-mode-map " "    'wl-folder-jump-to-current-entity)
142 ;  (define-key wl-folder-mode-map "\M- " 'wl-folder-open-close)
143   (define-key wl-folder-mode-map "/"    'wl-folder-open-close)
144   (define-key wl-folder-mode-map "\C-m" 'wl-folder-jump-to-current-entity)
145   (define-key wl-folder-mode-map "\M-\C-m" 'wl-folder-update-recursive-current-entity)
146   (define-key wl-folder-mode-map "rc"    'wl-folder-mark-as-read-all-region)
147   (define-key wl-folder-mode-map "c"    'wl-folder-mark-as-read-all-current-entity)
148   (define-key wl-folder-mode-map "g"    'wl-folder-goto-folder)
149   (define-key wl-folder-mode-map "j"    'wl-folder-jump-to-current-entity)
150   (define-key wl-folder-mode-map "w"    'wl-draft)
151   (define-key wl-folder-mode-map "W"    'wl-folder-write-current-folder)
152   (define-key wl-folder-mode-map "\C-c\C-o" 'wl-jump-to-draft-buffer)
153   (define-key wl-folder-mode-map "rS"   'wl-folder-sync-region)
154   (define-key wl-folder-mode-map "S"    'wl-folder-sync-current-entity)
155   (define-key wl-folder-mode-map "rs"   'wl-folder-check-region)
156   (define-key wl-folder-mode-map "s"    'wl-folder-check-current-entity)
157   (define-key wl-folder-mode-map "I"    'wl-folder-prefetch-current-entity)
158   (define-key wl-folder-mode-map "D"    'wl-folder-drop-unsync-current-entity)
159   (define-key wl-folder-mode-map "p"    'wl-folder-prev-entity)
160   (define-key wl-folder-mode-map "n"    'wl-folder-next-entity)
161   (define-key wl-folder-mode-map "v"    'wl-folder-toggle-disp-summary)
162   (define-key wl-folder-mode-map "P"    'wl-folder-prev-unread)
163   (define-key wl-folder-mode-map "N"    'wl-folder-next-unread)
164   (define-key wl-folder-mode-map "J"    'wl-folder-jump-folder)
165   (define-key wl-folder-mode-map "f"    'wl-folder-goto-first-unread-folder)
166   (define-key wl-folder-mode-map "o"    'wl-folder-open-all-unread-folder)
167   (define-key wl-folder-mode-map "["    'wl-folder-open-all)
168   (define-key wl-folder-mode-map "]"    'wl-folder-close-all)
169   (define-key wl-folder-mode-map "e"    'wl-folder-expire-current-entity)
170   (define-key wl-folder-mode-map "E"    'wl-folder-empty-trash)
171   (define-key wl-folder-mode-map "F"    'wl-folder-flush-queue)
172   (define-key wl-folder-mode-map "q"    'wl-exit)
173   (define-key wl-folder-mode-map "z"    'wl-folder-suspend)
174   (define-key wl-folder-mode-map "\M-t" 'wl-toggle-plugged)
175   (define-key wl-folder-mode-map "\C-t" 'wl-plugged-change)
176   (define-key wl-folder-mode-map "<"    'beginning-of-buffer)
177   (define-key wl-folder-mode-map ">"    'end-of-buffer)
178   ;; wl-fldmgr
179   (unless wl-on-nemacs
180     (define-key wl-folder-mode-map "m"    'wl-fldmgr-mode-map))
181   (define-key wl-folder-mode-map "*"    'wl-fldmgr-make-multi)
182   (define-key wl-folder-mode-map "+"    'wl-fldmgr-make-group)
183   (define-key wl-folder-mode-map "|"    'wl-fldmgr-make-filter)
184   (define-key wl-folder-mode-map "\M-c" 'wl-fldmgr-copy)
185   (define-key wl-folder-mode-map "\M-w" 'wl-fldmgr-copy-region)
186   (define-key wl-folder-mode-map "\C-k" 'wl-fldmgr-cut)
187   (define-key wl-folder-mode-map "\C-w" 'wl-fldmgr-cut-region)
188   (define-key wl-folder-mode-map "\C-y" 'wl-fldmgr-yank)
189   (define-key wl-folder-mode-map "R"    'wl-fldmgr-rename)
190   (define-key wl-folder-mode-map "u"    'wl-fldmgr-unsubscribe)
191   (define-key wl-folder-mode-map "ru"   'wl-fldmgr-unsubscribe-region)
192   (define-key wl-folder-mode-map "U"    'wl-fldmgr-unsubscribe-region)
193   (define-key wl-folder-mode-map "l"    'wl-fldmgr-access-display-normal)
194   (define-key wl-folder-mode-map "L"    'wl-fldmgr-access-display-all)
195   (define-key wl-folder-mode-map "Z"    'wl-status-update)
196   (define-key wl-folder-mode-map "\C-x\C-s" 'wl-save)
197   (define-key wl-folder-mode-map "\M-s"     'wl-save)
198   (define-key wl-folder-mode-map "\C-xk"    'wl-folder-mimic-kill-buffer)
199   (define-key wl-folder-mode-map "\M-\C-a"
200     'wl-folder-goto-top-of-current-folder)
201   (define-key wl-folder-mode-map "\M-\C-e"
202     'wl-folder-goto-bottom-of-current-folder)
203
204   (wl-folder-setup-mouse)
205   (easy-menu-define
206    wl-folder-mode-menu
207    wl-folder-mode-map
208    "Menu used in Folder mode."
209    wl-folder-mode-menu-spec))
210
211 (defmacro wl-folder-unread-regex (group)
212   (` (concat "^[ ]*.+:[0-9\\*-]+/[^0\\*][0-9]*/[0-9\\*-]+$"
213              (if (, group)
214                  "\\|^[ ]*\\[[+-]\\]"
215                ""))))
216
217 (defmacro wl-folder-buffer-group-p ()
218   (` (save-excursion (beginning-of-line)
219                      (looking-at wl-folder-group-regexp))))
220
221 (defmacro wl-folder-folder-name ()
222   (` (save-excursion
223        (beginning-of-line)
224        (if (or (looking-at "^[ ]*\\[[\\+-]\\]\\(.+\\):[-0-9\\*-]+/[0-9\\*-]+/[0-9\\*-]+\n")
225                (looking-at "^[ ]*\\([^\\[].+\\):.*\n"))
226            (wl-match-buffer 1)))))
227
228 (defmacro wl-folder-entity-name ()
229   (` (save-excursion
230        (beginning-of-line)
231        (if (looking-at "^[ ]*\\([^\\[].+\\):.*\n")
232            (wl-match-buffer 1)))))
233
234 (defun wl-folder-buffer-search-group (group)
235   (re-search-forward
236    (concat
237     "^\\([ \t]*\\)\\[[\\+-]\\]"
238     (regexp-quote group) ":[-0-9-]+/[0-9-]+/[0-9-]+") nil t))
239
240 (defun wl-folder-buffer-search-entity (folder &optional searchname)
241   (let ((search (or searchname (wl-folder-get-petname folder))))
242     (re-search-forward
243      (concat
244       "^[ \t]*"
245       (regexp-quote search) ":[-0-9\\*-]+/[0-9\\*-]+/[0-9\\*-]+") nil t)))
246
247 (defsubst wl-folder-get-folder-name-by-id (entity-id &optional hashtb)
248   (and (numberp entity-id)
249        (elmo-get-hash-val (format "#%d" entity-id)
250                           (or hashtb wl-folder-entity-id-name-hashtb))))
251
252 (defsubst wl-folder-set-id-name (entity-id entity &optional hashtb)
253   (and (numberp entity-id)
254        (elmo-set-hash-val (format "#%d" entity-id)
255                           entity (or hashtb wl-folder-entity-id-name-hashtb))))
256
257 (defmacro wl-folder-get-entity-id (entity)
258   (` (or (get-text-property 0
259                             'wl-folder-entity-id
260                             (, entity))
261          (, entity)))) ;; for nemacs
262
263 (defmacro wl-folder-get-entity-from-buffer (&optional getid)
264   (` (let ((id (get-text-property (point)
265                                   'wl-folder-entity-id)))
266        (if (not id) ;; for nemacs
267            (wl-folder-get-realname (wl-folder-folder-name))
268          (if (, getid)
269              id
270            (wl-folder-get-folder-name-by-id id))))))
271
272 (defmacro wl-folder-entity-exists-p (entity &optional hashtb)
273   (` (let ((sym (intern-soft (, entity)
274                              (or (, hashtb) wl-folder-entity-hashtb))))
275        (and sym (boundp sym)))))
276
277 (defmacro wl-folder-clear-entity-info (entity &optional hashtb)
278   (` (let ((sym (intern-soft (, entity)
279                              (or (, hashtb) wl-folder-entity-hashtb))))
280        (if (boundp sym)
281            (makunbound sym)))))
282
283 (defmacro wl-folder-get-entity-info (entity &optional hashtb)
284   (` (elmo-get-hash-val (, entity) (or (, hashtb) wl-folder-entity-hashtb))))
285
286 (defmacro wl-folder-set-entity-info (entity value &optional hashtb)
287   (` (let* ((hashtb (or (, hashtb) wl-folder-entity-hashtb))
288             (info (wl-folder-get-entity-info (, entity) hashtb)))
289        (elmo-set-hash-val (, entity)
290                           (if (< (length (, value)) 4)
291                               (append (, value) (list (nth 3 info)))
292                             (, value))
293                           hashtb))))
294
295 (defun wl-folder-persistent-p (folder)
296   (or (elmo-get-hash-val folder wl-folder-entity-hashtb) ; on Folder mode.
297       (catch 'found
298         (let ((li wl-save-folder-list))
299           (while li
300             (if (string-match (car li) folder)
301                 (throw 'found t))
302             (setq li (cdr li)))))
303       (not (catch 'found
304              (let ((li wl-no-save-folder-list))
305                (while li
306                  (if (string-match (car li) folder)
307                      (throw 'found t))
308                  (setq li (cdr li))))))))
309
310 (defun wl-folder-prev-entity ()
311   (interactive)
312   (forward-line -1))
313
314 (defun wl-folder-next-entity ()
315   (interactive)
316   (forward-line 1))
317
318 (defun wl-folder-prev-entity-skip-invalid (&optional hereto)
319   "move to previous entity. skip unsubscribed or removed entity."
320   (interactive)
321   (if hereto
322       (end-of-line))
323   (if (re-search-backward wl-folder-entity-regexp nil t)
324       (beginning-of-line)
325     (goto-char (point-min))))
326
327 (defun wl-folder-next-entity-skip-invalid (&optional hereto)
328   "Move to next entity. skip unsubscribed or removed entity."
329   (interactive)
330   (beginning-of-line)
331   (if (not hereto)
332       (forward-line 1))
333   (if (re-search-forward wl-folder-entity-regexp nil t)
334       (beginning-of-line)
335     (goto-char (point-max))))
336
337 (defun wl-folder-search-group-entity-by-name (name entity)
338   (wl-folder-search-entity-by-name name entity 'group))
339
340 (defun wl-folder-search-entity-by-name (name entity &optional type)
341   (let ((entities (list entity))
342         entity-stack)
343     (catch 'done
344       (while entities
345         (setq entity (wl-pop entities))
346         (cond
347          ((consp entity)
348           (if (and (not (eq type 'folder))
349                    (string= name (car entity)))
350               (throw 'done entity))
351           (and entities
352                (wl-push entities entity-stack))
353           (setq entities (nth 2 entity)))
354          ((and (not (eq type 'group))
355                (stringp entity))
356           (if (string= name entity)
357               (throw 'done entity))))
358         (unless entities
359           (setq entities (wl-pop entity-stack)))))))
360
361 (defun wl-folder-search-entity-list-by-name (name entity &optional get-id)
362   (let ((entities (list entity))
363         entity-stack ret-val)
364     (while entities
365       (setq entity (wl-pop entities))
366       (cond
367        ((consp entity)
368         (and entities
369              (wl-push entities entity-stack))
370         (setq entities (nth 2 entity)))
371        ((stringp entity)
372         (if (string= name entity)
373             (wl-append ret-val (if get-id
374                                    (list (wl-folder-get-entity-id entity))
375                                  (list entity))))))
376       (unless entities
377         (setq entities (wl-pop entity-stack))))
378     ret-val))
379
380 (defun wl-folder-get-prev-folder (id &optional unread)
381   (let ((name (if (stringp id)
382                   id
383                 (wl-folder-get-folder-name-by-id id)))
384         entity entity-stack last-entity finfo
385         (entities (list wl-folder-entity)))
386     (catch 'done
387       (while entities
388         (setq entity (wl-pop entities))
389         (cond
390          ((consp entity)
391 ;;        (if (and (string= name (car entity))
392 ;;                 (eq id (wl-folder-get-entity-id (car entity))))
393 ;;            (throw 'done last-entity))
394           (and entities
395                (wl-push entities entity-stack))
396           (setq entities (nth 2 entity)))
397          ((stringp entity)
398           (if (and (string= name entity)
399                    ;; don't use eq, `id' is string on Nemacs.
400                    (equal id (wl-folder-get-entity-id entity)))
401               (throw 'done last-entity))
402           (if (or (not unread)
403                   (and (setq finfo (wl-folder-get-entity-info entity))
404                        (and (nth 0 finfo)(nth 1 finfo))
405                        (> (+ (nth 0 finfo)(nth 1 finfo)) 0)))
406               (setq last-entity entity))))
407         (unless entities
408           (setq entities (wl-pop entity-stack)))))))
409
410 (defun wl-folder-get-next-folder (id &optional unread)
411   (let ((name (if (stringp id)
412                   id
413                 (wl-folder-get-folder-name-by-id id)))
414         entity entity-stack found finfo
415         (entities (list wl-folder-entity)))
416     (catch 'done
417       (while entities
418         (setq entity (wl-pop entities))
419         (cond
420          ((consp entity)
421 ;;;       (if (and (string= name (car entity))
422 ;;;                (eq id (wl-folder-get-entity-id (car entity))))
423 ;;;           (setq found t))
424           (and entities
425                (wl-push entities entity-stack))
426           (setq entities (nth 2 entity)))
427          ((stringp entity)
428           (if found
429               (when (or (not unread)
430                         (and (setq finfo (wl-folder-get-entity-info entity))
431                              (and (nth 0 finfo)(nth 1 finfo))
432                              (> (+ (nth 0 finfo)(nth 1 finfo)) 0)))
433                 (throw 'done entity))
434             (if (and (string= name entity)
435                      ;; don't use eq, `id' is string on Nemacs.
436                      (equal id (wl-folder-get-entity-id entity)))
437                 (setq found t)))))
438         (unless entities
439           (setq entities (wl-pop entity-stack)))))))
440
441 (defun wl-folder-flush-queue ()
442   "Flush queue."
443   (interactive)
444   (let ((cur-buf (current-buffer))
445         (wl-auto-select-first nil)
446         (wl-plugged t)
447         emptied)
448     (if elmo-enable-disconnected-operation
449         (elmo-dop-queue-flush 'force)) ; Try flushing all queue.
450     (if (not (elmo-list-folder wl-queue-folder))
451         (message "No sending queue exists.")
452       (if wl-stay-folder-window
453           (wl-folder-select-buffer
454            (wl-summary-get-buffer-create wl-queue-folder)))
455       (wl-summary-goto-folder-subr wl-queue-folder 'force-update nil)
456       (unwind-protect
457           (wl-draft-queue-flush)
458         (if (get-buffer-window cur-buf)
459             (select-window (get-buffer-window cur-buf)))
460         (set-buffer cur-buf)
461         (if wl-stay-folder-window
462             (wl-folder-toggle-disp-summary 'off wl-queue-folder)
463           (switch-to-buffer cur-buf))))))
464
465 (defun wl-folder-empty-trash ()
466   "Empty trash."
467   (interactive)
468   (let ((cur-buf (current-buffer))
469         (wl-auto-select-first nil)
470         trash-buf emptied)
471     (if wl-stay-folder-window
472         (wl-folder-select-buffer
473          (wl-summary-get-buffer-create wl-trash-folder)))
474     (wl-summary-goto-folder-subr wl-trash-folder 'force-update nil nil t)
475     (setq trash-buf (current-buffer))
476     (unwind-protect
477         (setq emptied (wl-summary-delete-all-msgs))
478       (when emptied
479         (setq wl-thread-entities nil
480               wl-thread-entity-list nil)
481         (if wl-summary-cache-use (wl-summary-save-view-cache))
482         (wl-summary-msgdb-save))
483       (if (get-buffer-window cur-buf)
484           (select-window (get-buffer-window cur-buf)))
485       (set-buffer cur-buf)
486       (if emptied
487           (wl-folder-set-folder-updated wl-trash-folder '(0 0 0)))
488       (if wl-stay-folder-window
489           (wl-folder-toggle-disp-summary 'off wl-trash-folder)
490         (switch-to-buffer cur-buf))
491       (and trash-buf
492            (kill-buffer trash-buf)))))
493
494 (defun wl-folder-goto-top-of-current-folder (&optional arg)
495   "Move backward to the top of the current folder group.
496 Optional argument ARG is repeart count."
497   (interactive "P")
498   (if (re-search-backward
499        "^ *\\[[\\+-]\\]" nil t (if arg (prefix-numeric-value arg)))
500       (beginning-of-line)
501     (goto-char (point-min))))
502
503 (defun wl-folder-goto-bottom-of-current-folder (indent)
504   "Move forward to the bottom of the current folder group."
505   (interactive
506    (let ((indent
507           (save-excursion
508             (beginning-of-line)
509             (if (looking-at "^ *")
510                 (buffer-substring (match-beginning 0)(1- (match-end 0)))
511               ""))))
512      (list indent)))
513   (if (catch 'done
514         (while (re-search-forward "^ *" nil t)
515           (if (<= (length (match-string 0))
516                   (length indent))
517               (throw 'done nil)))
518         (throw 'done t))
519       (goto-char (point-max))))
520
521 (defsubst wl-folder-update-group (entity diffs &optional is-group)
522   (let ((path (wl-folder-get-path
523                wl-folder-entity
524                (wl-folder-get-entity-id entity)
525                entity)))
526     (if (not is-group)
527         ;; delete itself from path
528         (setq path (delete (nth (- (length path) 1) path) path)))
529     (goto-char (point-min))
530     (catch 'done
531       (while path
532         ;; goto the path line.
533         (if (or (eq (car path) 0) ; update desktop
534                 (wl-folder-buffer-search-group
535                  (wl-folder-get-petname
536                   (if (stringp (car path))
537                       (car path)
538                     (wl-folder-get-folder-name-by-id
539                      (car path))))))
540             ;; update it.
541             (wl-folder-update-diff-line diffs)
542           (throw 'done t))
543         (setq path (cdr path))))))
544
545 (defun wl-folder-maybe-load-folder-list (entity)
546   (when (null (caddr entity))
547     (setcdr (cdr entity)
548             (elmo-msgdb-flist-load (car entity)))
549     (when (cddr entity)
550       (let (diffs)
551         (save-excursion
552           (wl-folder-entity-assign-id entity
553                                       wl-folder-entity-id-name-hashtb
554                                       t)
555           (setq diffs (wl-fldmgr-add-entity-hashtb (list entity)))
556           (unless (equal diffs '(0 0 0))
557             (wl-folder-update-group (car entity) diffs t)))))))
558
559 (defsubst wl-folder-force-fetch-p (entity)
560   (cond
561    ((consp wl-force-fetch-folders)
562     (wl-string-match-member entity wl-force-fetch-folders))
563    (t
564     wl-force-fetch-folders)))
565
566 (defun wl-folder-jump-to-current-entity (&optional arg)
567   "Enter the current folder.  If optional ARG exists, update folder list."
568   (interactive "P")
569   (beginning-of-line)
570   (let (entity beg end indent opened fname err fld-name)
571     (cond
572      ((looking-at wl-folder-group-regexp)
573       (save-excursion
574         (setq fname (wl-folder-get-realname (wl-match-buffer 3)))
575         (setq indent (wl-match-buffer 1))
576         (setq opened (wl-match-buffer 2))
577         (if (string= opened "+")
578             (progn
579               (setq entity (wl-folder-search-group-entity-by-name
580                             fname
581                             wl-folder-entity))
582               (setq beg (point))
583               (if arg
584                   (wl-folder-update-recursive-current-entity entity)
585               ;; insert as opened
586               (setcdr (assoc (car entity) wl-folder-group-alist) t)
587               (if (eq 'access (cadr entity))
588                   (wl-folder-maybe-load-folder-list entity))
589               (condition-case errobj
590                   (progn
591                     (if (or (wl-folder-force-fetch-p (car entity))
592                             (and
593                              (eq 'access (cadr entity))
594                              (null (caddr entity))))
595                         (wl-folder-update-newest indent entity)
596                       (wl-folder-insert-entity indent entity))
597                     (wl-highlight-folder-path wl-folder-buffer-cur-path))
598                 (quit
599                  (setq err t)
600                  (setcdr (assoc fname wl-folder-group-alist) nil))
601                 (error
602                  (elmo-display-error errobj t)
603                  (ding)
604                  (setq err t)
605                  (setcdr (assoc fname wl-folder-group-alist) nil)))
606               (if (not err)
607                   (let ((buffer-read-only nil))
608                     (delete-region (save-excursion (beginning-of-line)
609                                                    (point))
610                                    (save-excursion (end-of-line)
611                                                    (+ 1 (point))))))))
612           (setq beg (point))
613           (end-of-line)
614           (save-match-data
615             (setq end
616                   (progn (wl-folder-goto-bottom-of-current-folder indent)
617                          (beginning-of-line)
618                          (point))))
619           (setq entity (wl-folder-search-group-entity-by-name
620                         fname
621                         wl-folder-entity))
622           (let ((buffer-read-only nil))
623             (delete-region beg end))
624           (setcdr (assoc (car entity) wl-folder-group-alist) nil)
625           (wl-folder-insert-entity indent entity) ; insert entity
626           (forward-line -1)
627           (wl-highlight-folder-path wl-folder-buffer-cur-path)
628 ;         (wl-delete-all-overlays)
629 ;         (wl-highlight-folder-current-line)
630           )))
631      ((setq fld-name (wl-folder-entity-name))
632       (if wl-on-nemacs
633           (progn
634             (wl-folder-set-current-entity-id
635              (wl-folder-get-entity-from-buffer))
636             (setq fld-name (wl-folder-get-realname fld-name)))
637         (wl-folder-set-current-entity-id
638          (get-text-property (point) 'wl-folder-entity-id))
639         (setq fld-name (wl-folder-get-folder-name-by-id
640                         wl-folder-buffer-cur-entity-id)))
641       (let ((summary-buf (wl-summary-get-buffer-create fld-name arg))
642             error-selecting)
643         (if wl-stay-folder-window
644             (wl-folder-select-buffer summary-buf)
645           (if (and summary-buf
646                    (get-buffer-window summary-buf))
647               (delete-window)))
648         (wl-summary-goto-folder-subr fld-name
649                                      (wl-summary-get-sync-range fld-name)
650                                      nil arg t)))))
651   (set-buffer-modified-p nil))
652
653 (defun wl-folder-close-entity (entity)
654   (let ((entities (list entity))
655         entity-stack)
656     (while entities
657       (setq entity (wl-pop entities))
658       (cond
659        ((consp entity)
660         (setcdr (assoc (car entity) wl-folder-group-alist) nil)
661         (and entities
662              (wl-push entities entity-stack))
663         (setq entities (nth 2 entity))))
664       (unless entities
665         (setq entities (wl-pop entity-stack))))))
666
667 (defun wl-folder-update-recursive-current-entity (&optional entity)
668   (interactive)
669   (when (wl-folder-buffer-group-p)
670     (cond
671      ((string= (wl-match-buffer 2) "+")
672       (save-excursion
673         (if entity ()
674           (setq entity
675                 (wl-folder-search-group-entity-by-name
676                  (wl-folder-get-realname (wl-match-buffer 3))
677                  wl-folder-entity)))
678         (let ((inhibit-read-only t)
679               (entities (list entity))
680               entity-stack err indent)
681           (while (and entities (not err))
682             (setq entity (wl-pop entities))
683             (cond
684              ((consp entity)
685               (wl-folder-close-entity entity)
686               (setcdr (assoc (car entity) wl-folder-group-alist) t)
687               (unless (wl-folder-buffer-search-group
688                        (wl-folder-get-petname (car entity)))
689                 (error "%s: not found group" (car entity)))
690               (setq indent (wl-match-buffer 1))
691               (if (eq 'access (cadr entity))
692                   (wl-folder-maybe-load-folder-list entity))
693               (beginning-of-line)
694               (setq err nil)
695               (save-excursion
696                 (condition-case errobj
697                     (wl-folder-update-newest indent entity)
698                   (quit
699                    (setq err t)
700                    (setcdr (assoc (car entity) wl-folder-group-alist) nil))
701                   (error
702                    (elmo-display-error errobj t)
703                    (ding)
704                    (setq err t)
705                    (setcdr (assoc (car entity) wl-folder-group-alist) nil)))
706                 (if (not err)
707                     (delete-region (save-excursion (beginning-of-line)
708                                                    (point))
709                                    (save-excursion (end-of-line)
710                                                    (+ 1 (point))))))
711               ;;
712               (and entities
713                    (wl-push entities entity-stack))
714               (setq entities (nth 2 entity))))
715             (unless entities
716               (setq entities (wl-pop entity-stack)))))
717         (set-buffer-modified-p nil)))
718      (t
719       (wl-folder-jump-to-current-entity)))))
720
721 (defun wl-folder-no-auto-check-folder-p (folder)
722   (if (stringp folder)
723       (if (catch 'found
724             (let ((li wl-auto-check-folder-list))
725               (while li
726                 (if (string-match (car li) folder)
727                     (throw 'found t))
728                 (setq li (cdr li)))))
729           nil
730         (catch 'found
731           (let ((li wl-auto-uncheck-folder-list))
732             (while li
733               (if (string-match (car li) folder)
734                   (throw 'found t))     ; no check!
735               (setq li (cdr li))))))))
736
737 (defsubst wl-folder-add-folder-info (pre-value value)
738   (list
739    (+ (or (nth 0 pre-value) 0) (or (nth 0 value) 0))
740    (+ (or (nth 1 pre-value) 0) (or (nth 1 value) 0))
741    (+ (or (nth 2 pre-value) 0) (or (nth 2 value) 0))))
742
743 (defun wl-folder-check-entity (entity &optional auto)
744   "Check unsync message number."
745   (let ((start-pos (point))
746         ret-val)
747     (run-hooks 'wl-folder-check-entity-pre-hook)
748     (if (and (consp entity)             ;; group entity
749              wl-folder-check-async)     ;; very fast
750         (setq ret-val (wl-folder-check-entity-async entity auto))
751       (save-excursion
752         (cond
753          ((consp entity)
754           (let ((flist (if auto
755                            (elmo-delete-if
756                             'wl-folder-no-auto-check-folder-p
757                             (nth 2 entity))
758                          (nth 2 entity)))
759                 (wl-folder-check-entity-pre-hook nil)
760                 (wl-folder-check-entity-hook nil)
761                 new unread all)
762             (while flist
763               (setq ret-val
764                     (wl-folder-add-folder-info
765                      ret-val
766                      (wl-folder-check-entity (car flist))))
767               (setq flist (cdr flist)))
768             ;(wl-folder-buffer-search-entity (car entity))
769             ;(wl-folder-update-line ret-val)
770             ))
771          ((and (stringp entity)
772                (elmo-folder-plugged-p entity))
773           (message "Checking \"%s\"" entity)
774           (setq ret-val (wl-folder-check-one-entity entity))
775           (goto-char start-pos)
776           (sit-for 0))
777          (t
778           (message "Uncheck(unplugged) \"%s\"" entity)))))
779     (if ret-val
780         (message "Checking \"%s\" is done."
781                  (if (consp entity) (car entity) entity)))
782     (run-hooks 'wl-folder-check-entity-hook)
783     ret-val))
784
785 ;; All contained folders are imap4 and persistent flag, then
786 ;; use server diff.
787 (defun wl-folder-use-server-diff-p (folder)
788   (let ((spec (elmo-folder-get-spec folder)))
789     (cond
790      ((eq (car spec) 'multi)
791       (let ((folders (cdr spec)))
792         (catch 'done
793           (while folders
794             (if (wl-folder-use-server-diff-p (car folders))
795                 (throw 'done t))
796             (setq folders (cdr folders)))
797           nil)))
798     ((eq (car spec) 'filter)
799      (wl-folder-use-server-diff-p (nth 2 spec)))
800     ((eq (car spec) 'imap4)
801      (and wl-folder-use-server-diff
802           (elmo-imap4-use-flag-p spec)))
803     (t nil))))
804
805 (defun wl-folder-check-one-entity (entity)
806   (let* ((elmo-use-server-diff (wl-folder-use-server-diff-p entity))
807          (nums (condition-case err
808                    (if (wl-string-match-member entity wl-strict-diff-folders)
809                        (elmo-strict-folder-diff entity)
810                      (elmo-folder-diff entity))
811                  (error
812                   ;; maybe not exist folder.
813                   (if (and (not (memq 'elmo-open-error
814                                       (get (car err) 'error-conditions)))
815                            (not (elmo-folder-exists-p entity)))
816                       (wl-folder-create-subr entity)
817                     (signal (car err) (cdr err))))))
818          unread unsync nomif)
819     (if (and (eq wl-folder-notify-deleted 'sync)
820              (car nums)
821              (or (> 0 (car nums)) (> 0 (cdr nums))))
822         (progn
823           (wl-folder-sync-entity entity)
824           (setq nums (elmo-folder-diff entity)))
825       (unless wl-folder-notify-deleted
826         (setq unsync (if (and (car nums) (> 0 (car nums))) 0 (car nums)))
827         (setq nomif (if (and (car nums) (> 0 (cdr nums))) 0 (cdr nums)))
828         (setq nums (cons unsync nomif)))
829       (wl-folder-entity-hashtb-set wl-folder-entity-hashtb entity
830                                    (list (car nums)
831                                          (setq
832                                           unread
833                                           (or
834                                            ;; If server diff, All unreads are
835                                            ;; treated as unsync.
836                                            (if elmo-use-server-diff 0)
837                                            (elmo-folder-get-info-unread entity)
838                                            (wl-summary-count-unread
839                                             (elmo-msgdb-mark-load
840                                              (elmo-msgdb-expand-path entity))
841                                             entity)))
842                                          (cdr nums))
843                                    (get-buffer wl-folder-buffer-name)))
844     (setq wl-folder-info-alist-modified t)
845     (sit-for 0)
846     (list (if wl-folder-notify-deleted
847               (car nums)
848             (max (or (car nums) 0))) unread (cdr nums))))
849
850 (defun wl-folder-check-entity-async (entity &optional auto)
851   (let ((elmo-nntp-groups-async t)
852         (elist (if auto
853                    (elmo-delete-if
854                     'wl-folder-no-auto-check-folder-p
855                     (wl-folder-get-entity-list entity))
856                  (wl-folder-get-entity-list entity)))
857         (nntp-connection-keys nil)
858         folder spec-list local-elist net-elist server
859         ret-val)
860     (while elist
861       (if (not (elmo-folder-plugged-p (car elist)))
862           (message "Uncheck \"%s\"" (car elist))
863         (setq spec-list
864               (elmo-folder-get-primitive-spec-list (elmo-string (car elist))))
865         (cond ((assq 'nntp spec-list)
866                (wl-append net-elist (list (car elist)))
867                (while spec-list
868                  (when (eq (caar spec-list) 'nntp)
869                    (when (not (string= server (elmo-nntp-spec-hostname (car spec-list))))
870                      (setq server (elmo-nntp-spec-hostname (car spec-list)))
871                      (message "Checking on \"%s\"" server))
872                    (setq nntp-connection-keys
873                          (elmo-nntp-get-folders-info-prepare
874                           (car spec-list)
875                           nntp-connection-keys)))
876                  (setq spec-list (cdr spec-list))))
877               (t
878                (wl-append local-elist (list (car elist))))))
879       (setq elist (cdr elist)))
880     ;; check local entity at first
881     (while (setq folder (pop local-elist))
882       (if (not (elmo-folder-plugged-p folder))
883           (message "Uncheck \"%s\"" folder)
884         (message "Checking \"%s\"" folder)
885         (setq ret-val
886               (wl-folder-add-folder-info
887                ret-val
888                (wl-folder-check-one-entity folder)))
889         ;;(sit-for 0)
890         ))
891     ;; check network entity at last
892     (when net-elist
893       (elmo-nntp-get-folders-info nntp-connection-keys)
894       (while (setq folder (pop net-elist))
895         (if (not (elmo-folder-plugged-p folder))
896             (message "Uncheck \"%s\"" folder)
897           (message "Checking \"%s\"" folder)
898           (setq ret-val
899                 (wl-folder-add-folder-info
900                  ret-val
901                  (wl-folder-check-one-entity folder)))
902           ;;(sit-for 0)
903           )))
904     ret-val))
905
906 ;;
907 (defun wl-folder-resume-entity-hashtb-by-finfo (entity-hashtb info-alist)
908   "Resume unread info for entity alist."
909   (let (info)
910     (while info-alist
911       (setq info (nth 1 (car info-alist)))
912       (wl-folder-set-entity-info (caar info-alist)
913                                  (list (nth 2 info)(nth 3 info)(nth 1 info))
914                                  entity-hashtb)
915       (setq info-alist (cdr info-alist)))))
916
917 (defun wl-folder-move-path (path)
918   (let ((fp (if (consp path)
919                 path
920               ;; path is entity-id
921               (wl-folder-get-path wl-folder-entity path))))
922     (goto-char (point-min))
923     (while (and fp
924                 (not (eobp)))
925       (when (equal (car fp)
926                    (wl-folder-get-entity-from-buffer t))
927         (setq fp (cdr fp))
928         (setq wl-folder-buffer-cur-point (point)))
929       (forward-line 1))
930     (and wl-folder-buffer-cur-point
931          (goto-char wl-folder-buffer-cur-point))))
932
933 (defun wl-folder-set-current-entity-id (entity-id)
934   (let ((buf (get-buffer wl-folder-buffer-name)))
935     (if buf
936         (save-excursion
937           (set-buffer buf)
938           (setq wl-folder-buffer-cur-entity-id entity-id)
939           (setq wl-folder-buffer-cur-path (wl-folder-get-path wl-folder-entity
940                                                               entity-id))
941           (wl-highlight-folder-path wl-folder-buffer-cur-path)
942           (and wl-folder-move-cur-folder
943                wl-folder-buffer-cur-point
944                (goto-char wl-folder-buffer-cur-point))))
945     (if (eq (current-buffer) buf)
946         (and wl-folder-move-cur-folder
947              wl-folder-buffer-cur-point
948              (goto-char wl-folder-buffer-cur-point)))))
949
950 (defun wl-folder-check-current-entity ()
951   "Check folder at position.
952 If current line is group folder, check all sub entries."
953   (interactive)
954   (let* ((entity-name (wl-folder-get-entity-from-buffer))
955          (group (wl-folder-buffer-group-p))
956          (desktop (string= entity-name wl-folder-desktop-name)))
957     (when entity-name
958       (wl-folder-check-entity
959        (if group
960            (wl-folder-search-group-entity-by-name entity-name
961                                                   wl-folder-entity)
962          entity-name)
963        desktop))))
964
965 (defun wl-folder-sync-entity (entity &optional unread-only)
966   "Synchronize the msgdb of ENTITY."
967   (cond
968    ((consp entity)
969     (let ((flist (nth 2 entity)))
970       (while flist
971         (wl-folder-sync-entity (car flist) unread-only)
972         (setq flist (cdr flist)))))
973    ((stringp entity)
974     (let ((nums (wl-folder-get-entity-info entity))
975           (wl-summary-highlight (if (or (wl-summary-sticky-p entity)
976                                         (wl-summary-always-sticky-folder-p
977                                          entity))
978                                     wl-summary-highlight))
979           wl-auto-select-first new unread)
980       (setq new (or (car nums) 0))
981       (setq unread (or (cadr nums) 0))
982       (if (or (not unread-only)
983               (or (< 0 new) (< 0 unread)))
984           (let ((wl-summary-buffer-name (concat
985                                          wl-summary-buffer-name
986                                          (symbol-name this-command)))
987                 (wl-message-buf-name (concat wl-message-buf-name
988                                              (symbol-name this-command))))
989             (save-window-excursion
990               (save-excursion
991                 (wl-summary-goto-folder-subr entity
992                                              (wl-summary-get-sync-range entity)
993                                              nil nil nil t)
994                 (wl-summary-exit)))))))))
995
996 (defun wl-folder-sync-current-entity (&optional unread-only)
997   "Synchronize the folder at position.
998 If current line is group folder, check all subfolders."
999   (interactive "P")
1000   (save-excursion
1001     (let ((entity-name (wl-folder-get-entity-from-buffer))
1002           (group (wl-folder-buffer-group-p)))
1003       (when (and entity-name
1004                  (y-or-n-p (format "Sync %s?" entity-name)))
1005         (wl-folder-sync-entity
1006          (if group
1007              (wl-folder-search-group-entity-by-name entity-name
1008                                                     wl-folder-entity)
1009            entity-name)
1010          unread-only)
1011         (message "Syncing %s is done!" entity-name)))))
1012
1013 (defun wl-folder-mark-as-read-all-entity (entity)
1014   "Mark as read all messages in the ENTITY."
1015   (cond
1016    ((consp entity)
1017     (let ((flist (nth 2 entity)))
1018       (while flist
1019         (wl-folder-mark-as-read-all-entity (car flist))
1020         (setq flist (cdr flist)))))
1021    ((stringp entity)
1022     (let ((nums (wl-folder-get-entity-info entity))
1023           (wl-summary-highlight (if (or (wl-summary-sticky-p entity)
1024                                         (wl-summary-always-sticky-folder-p
1025                                          entity))
1026                                     wl-summary-highlight))
1027           wl-auto-select-first new unread)
1028       (setq new (or (car nums) 0))
1029       (setq unread (or (cadr nums) 0))
1030       (if (or (< 0 new) (< 0 unread))
1031           (let ((wl-summary-buffer-name (concat
1032                                          wl-summary-buffer-name
1033                                          (symbol-name this-command)))
1034                 (wl-message-buf-name (concat wl-message-buf-name
1035                                              (symbol-name this-command))))
1036             (save-window-excursion
1037               (save-excursion
1038                 (wl-summary-goto-folder-subr entity
1039                                            (wl-summary-get-sync-range entity)
1040                                            nil)
1041                 (wl-summary-mark-as-read-all)
1042                 (wl-summary-exit))))
1043         (sit-for 0))))))
1044
1045 (defun wl-folder-mark-as-read-all-current-entity ()
1046   "Mark as read all messages in the folder at position.
1047 If current line is group folder, all subfolders are marked."
1048   (interactive)
1049   (save-excursion
1050     (let ((entity-name (wl-folder-get-entity-from-buffer))
1051           (group (wl-folder-buffer-group-p))
1052           summary-buf)
1053       (when (and entity-name
1054                  (y-or-n-p (format "Mark all messages in %s as read?" entity-name)))
1055         (wl-folder-mark-as-read-all-entity
1056          (if group
1057              (wl-folder-search-group-entity-by-name entity-name
1058                                                     wl-folder-entity)
1059            entity-name))
1060         (message "All messages in %s are marked!" entity-name)))))
1061
1062 (defun wl-folder-check-region (beg end)
1063   (interactive "r")
1064   (goto-char beg)
1065   (beginning-of-line)
1066   (setq beg (point))
1067   (goto-char end)
1068   (beginning-of-line)
1069   (setq end (point))
1070   (goto-char beg)
1071   (let ((inhibit-read-only t)
1072         entity)
1073     (while (< (point) end)
1074       ;; normal folder entity
1075       (if (looking-at "^[\t ]*\\([^\\[]+\\):\\(.*\\)\n")
1076           (save-excursion
1077             (setq entity (wl-folder-get-entity-from-buffer))
1078             (if (not (elmo-folder-plugged-p entity))
1079                 (message "Uncheck %s" entity)
1080               (message "Checking %s" entity)
1081               (wl-folder-check-one-entity entity)
1082               (sit-for 0))))
1083       (forward-line 1)))
1084   (message ""))
1085
1086 (defun wl-folder-sync-region (beg end)
1087   (interactive "r")
1088   (goto-char beg)
1089   (beginning-of-line)
1090   (setq beg (point))
1091   (goto-char end)
1092   (end-of-line)
1093   (setq end (point))
1094   (goto-char beg)
1095   (while (< (point) end)
1096     ;; normal folder entity
1097     (if (looking-at "^[\t ]*\\([^\\[]+\\):\\(.*\\)\n")
1098         (save-excursion
1099           (let ((inhibit-read-only t)
1100                 entity)
1101             (setq entity (wl-folder-get-entity-from-buffer))
1102             (wl-folder-sync-entity entity)
1103             (message "Syncing %s is done!" entity)
1104             (sit-for 0))))
1105     (forward-line 1))
1106   (message ""))
1107
1108 (defun wl-folder-mark-as-read-all-region (beg end)
1109   (interactive "r")
1110   (goto-char beg)
1111   (beginning-of-line)
1112   (setq beg (point))
1113   (goto-char end)
1114   (end-of-line)
1115   (setq end (point))
1116   (goto-char beg)
1117   (while (< (point) end)
1118     ;; normal folder entity
1119     (if (looking-at "^[\t ]*\\([^\\[]+\\):\\(.*\\)\n")
1120         (save-excursion
1121           (let ((inhibit-read-only t)
1122                 entity)
1123             (setq entity (wl-folder-get-entity-from-buffer))
1124             (wl-folder-mark-as-read-all-entity entity)
1125             (message "All messages in %s are marked!" entity)
1126             (sit-for 0))))
1127     (forward-line 1))
1128   (message ""))
1129
1130 (defsubst wl-create-access-init-load-p (folder)
1131   (let ((no-load-regexp (when (and
1132                                (not wl-folder-init-load-access-folders)
1133                                wl-folder-init-no-load-access-folders)
1134                           (mapconcat 'identity
1135                                      wl-folder-init-no-load-access-folders
1136                                      "\\|")))
1137         (load-regexp (and wl-folder-init-load-access-folders
1138                           (mapconcat 'identity
1139                                      wl-folder-init-load-access-folders
1140                                      "\\|"))))
1141     (cond (load-regexp (string-match load-regexp folder))
1142           (t (not (and no-load-regexp
1143                        (string-match no-load-regexp folder)))))))
1144
1145 (defun wl-create-access-folder-entity (name)
1146   (let (flists flist)
1147     (when (wl-create-access-init-load-p name)
1148       (setq flists (elmo-msgdb-flist-load name)) ; load flist.
1149       (setq flist (car flists))
1150       (while flist
1151         (when (consp (car flist))
1152           (setcdr (cdar flist)
1153                   (wl-create-access-folder-entity (caar flist))))
1154         (setq flist (cdr flist)))
1155       flists)))
1156
1157 (defun wl-create-folder-entity-from-buffer ()
1158   "Create folder entity recursively."
1159   (cond
1160    ((looking-at "^[ \t]*$")             ; blank line
1161     (goto-char (+ 1(match-end 0)))
1162     'ignore)
1163    ((looking-at "^#.*$")                ; comment
1164     (goto-char (+ 1 (match-end 0)))
1165     'ignore)
1166    ((looking-at "^[\t ]*\\(.+\\)[\t ]*{[\t ]*$") ; group definition
1167     (let (name entity flist)
1168       (setq name (wl-match-buffer 1))
1169       (goto-char (+ 1 (match-end 0)))
1170       (while (setq entity (wl-create-folder-entity-from-buffer))
1171         (unless (eq entity 'ignore)
1172           (wl-append flist (list entity))))
1173       (if (looking-at "^[\t ]*}[\t ]*$") ; end of group
1174           (progn
1175             (goto-char (+ 1 (match-end 0)))
1176             (if (wl-string-assoc name wl-folder-petname-alist)
1177                 (error "%s already defined as petname" name))
1178             (list name 'group flist))
1179         (error "Syntax error in folder definition"))))
1180    ((looking-at "^[\t ]*\\([^\t \n]+\\)[\t ]*/$") ; access it!
1181     (let (name)
1182       (setq name (wl-match-buffer 1))
1183       (goto-char (+ 1 (match-end 0)))
1184 ;      (condition-case ()
1185 ;         (unwind-protect
1186 ;             (setq flist (elmo-list-folders name)))
1187 ;       (error (message "Access to folder %s failed." name)))
1188 ;;       (setq flist (elmo-msgdb-flist-load name)) ; load flist.
1189 ;;       (setq unsublist (nth 1 flist))
1190 ;;       (setq flist (car flist))
1191 ;;       (list name 'access flist unsublist)))
1192       (append (list name 'access) (wl-create-access-folder-entity name))))
1193    ;((looking-at "^[\t ]*\\([^\t \n}]+\\)[\t ]*\\(\"[^\"]*\"\\)?[\t ]*$") ; normal folder entity
1194    ((looking-at "^[\t ]*=[ \t]+\\([^\n]+\\)$"); petname definition
1195     (goto-char (+ 1 (match-end 0)))
1196     (let ((rest (elmo-match-buffer 1))
1197           petname)
1198       (when (string-match "\\(\"[^\"]*\"\\)[\t ]*$" rest)
1199         (setq petname (elmo-delete-char ?\" (elmo-match-string 1 rest)))
1200         (setq rest (substring rest 0 (match-beginning 0))))
1201       (when (string-match "^[\t ]*\\(.*[^\t ]+\\)[\t ]+$" rest)
1202         (wl-folder-append-petname (elmo-match-string 1 rest)
1203                                   petname))
1204       'ignore))
1205    ((looking-at "^[ \t]*}[ \t]*$") ; end of group
1206     nil)
1207    ((looking-at "^.*$") ; normal folder entity
1208     (goto-char (+ 1 (match-end 0)))
1209     (let ((rest (elmo-match-buffer 0))
1210           realname petname)
1211       (if (string-match "\\(\"[^\"]*\"\\)[\t ]*$" rest)
1212           (progn
1213             (setq petname (elmo-delete-char ?\" (elmo-match-string 1 rest)))
1214             (setq rest (substring rest 0 (match-beginning 0)))
1215             (when (string-match "^[\t ]*\\(.*[^\t ]+\\)[\t ]+$" rest)
1216               (wl-folder-append-petname
1217                (setq realname (elmo-match-string 1 rest))
1218                petname)
1219               realname))
1220         (if (string-match "^[\t ]*\\(.+\\)$" rest)
1221             (elmo-match-string 1 rest)
1222           rest))))))
1223
1224 (defun wl-folder-create-folder-entity ()
1225   "Create folder entries."
1226   (let ((tmp-buf (get-buffer-create " *wl-folder-tmp*"))
1227         entity ret-val)
1228     (condition-case ()
1229         (progn
1230           (with-current-buffer tmp-buf
1231             (erase-buffer)
1232             (insert-file-contents wl-folders-file)
1233             (goto-char (point-min))
1234             (while (and (not (eobp))
1235                         (setq entity (wl-create-folder-entity-from-buffer)))
1236               (unless (eq entity 'ignore)
1237                 (wl-append ret-val (list entity)))))
1238           (kill-buffer tmp-buf))
1239       (file-error nil))
1240     (setq ret-val (list wl-folder-desktop-name 'group ret-val))))
1241
1242 (defun wl-folder-entity-assign-id (entity &optional hashtb on-noid)
1243   (let ((hashtb (or hashtb
1244                     (setq wl-folder-entity-id-name-hashtb
1245                           (elmo-make-hash wl-folder-entity-id))))
1246         (entities (list entity))
1247         entity-stack)
1248     (while entities
1249       (setq entity (wl-pop entities))
1250       (cond
1251        ((consp entity)
1252         (when (not (and on-noid
1253                         (get-text-property 0
1254                                            'wl-folder-entity-id
1255                                            (car entity))))
1256           (put-text-property 0 (length (car entity))
1257                              'wl-folder-entity-id
1258                              wl-folder-entity-id
1259                              (car entity))
1260           (wl-folder-set-id-name wl-folder-entity-id
1261                                  (car entity) hashtb))
1262         (and entities
1263              (wl-push entities entity-stack))
1264         (setq entities (nth 2 entity)))
1265        ((stringp entity)
1266         (when (not (and on-noid
1267                         (get-text-property 0
1268                                            'wl-folder-entity-id
1269                                            entity)))
1270           (put-text-property 0 (length entity)
1271                              'wl-folder-entity-id
1272                              wl-folder-entity-id
1273                              entity)
1274           (wl-folder-set-id-name wl-folder-entity-id
1275                                  entity hashtb))))
1276       (setq wl-folder-entity-id (+ 1 wl-folder-entity-id))
1277       (unless entities
1278         (setq entities (wl-pop entity-stack))))))
1279
1280 (defun wl-folder-click (e)
1281   (interactive "e")
1282   (mouse-set-point e)
1283   (beginning-of-line)
1284   (save-excursion
1285     (wl-folder-jump-to-current-entity)))
1286
1287 (defun wl-folder-select-buffer (buffer)
1288   (let ((gbw (get-buffer-window buffer))
1289         exists)
1290     (if gbw
1291         (progn (select-window gbw)
1292                (setq exists t))
1293       (unless wl-summary-use-frame
1294         (condition-case ()
1295             (unwind-protect
1296                 (split-window-horizontally wl-folder-window-width)
1297               (other-window 1))
1298           (error nil))))
1299     (set-buffer buffer)
1300     (if wl-summary-use-frame
1301         (switch-to-buffer-other-frame buffer)
1302       (switch-to-buffer buffer))
1303     exists))
1304
1305 (defun wl-folder-toggle-disp-summary (&optional arg folder)
1306   (interactive)
1307   (if (or (and folder (assoc folder wl-folder-group-alist))
1308           (and (interactive-p) (wl-folder-buffer-group-p)))
1309       (error "This command is not available on Group"))
1310   (beginning-of-line)
1311   (let (wl-auto-select-first)
1312     (cond
1313      ((eq arg 'on)
1314       (setq wl-folder-buffer-disp-summary t))
1315      ((eq arg 'off)
1316       (setq wl-folder-buffer-disp-summary nil)
1317       ;; hide wl-summary window.
1318       (let ((cur-buf (current-buffer))
1319             (summary-buffer (wl-summary-get-buffer folder)))
1320         (wl-folder-select-buffer summary-buffer)
1321         (delete-window)
1322         (select-window (get-buffer-window cur-buf))))
1323      (t
1324       (setq wl-folder-buffer-disp-summary
1325             (not wl-folder-buffer-disp-summary))
1326       (let ((cur-buf (current-buffer))
1327             folder-name)
1328         (when (looking-at "^[ ]*\\([^\\[].+\\):.*\n")
1329           (setq folder-name (wl-folder-get-entity-from-buffer))
1330           (if wl-folder-buffer-disp-summary
1331               (progn
1332                 (wl-folder-select-buffer
1333                  (wl-summary-get-buffer-create folder-name))
1334                 (unwind-protect
1335                     (wl-summary-goto-folder-subr folder-name 'no-sync nil)
1336                   (select-window (get-buffer-window cur-buf))))
1337             (wl-folder-select-buffer (wl-summary-get-buffer folder-name))
1338             (delete-window)
1339             (select-window (get-buffer-window cur-buf)))))))))
1340
1341 (defun wl-folder-prev-unsync ()
1342   "Move cursor to the previous unsync folder."
1343   (interactive)
1344   (let (start-point)
1345     (setq start-point (point))
1346     (beginning-of-line)
1347     (if (re-search-backward wl-folder-unsync-regexp nil t)
1348         (beginning-of-line)
1349       (goto-char start-point)
1350       (message "No more unsync folder"))))
1351
1352 (defun wl-folder-next-unsync (&optional plugged)
1353   "Move cursor to the next unsync."
1354   (interactive)
1355   (let (start-point entity)
1356     (setq start-point (point))
1357     (end-of-line)
1358     (if (catch 'found
1359           (while (re-search-forward wl-folder-unsync-regexp nil t)
1360             (if (or (wl-folder-buffer-group-p)
1361                     (not plugged)
1362                     (setq entity
1363                           (wl-folder-get-realname
1364                            (wl-folder-folder-name)))
1365                     (elmo-folder-plugged-p entity))
1366                 (throw 'found t))))
1367         (beginning-of-line)
1368       (goto-char start-point)
1369       (message "No more unsync folder"))))
1370
1371 (defun wl-folder-prev-unread (&optional group)
1372   "Move cursor to the previous unread folder."
1373   (interactive "P")
1374   (let (start-point)
1375     (setq start-point (point))
1376     (beginning-of-line)
1377     (if (re-search-backward (wl-folder-unread-regex group) nil t)
1378         (progn
1379           (beginning-of-line)
1380           (wl-folder-folder-name))
1381       (goto-char start-point)
1382       (message "No more unread folder")
1383       nil)))
1384
1385 (defun wl-folder-next-unread (&optional group)
1386   "Move cursor to the next unread folder."
1387   (interactive "P")
1388   (let (start-point)
1389     (setq start-point (point))
1390     (end-of-line)
1391     (if (re-search-forward (wl-folder-unread-regex group) nil t)
1392         (progn
1393           (beginning-of-line)
1394           (wl-folder-folder-name))
1395       (goto-char start-point)
1396       (message "No more unread folder")
1397       nil)))
1398
1399 (defun wl-folder-mode ()
1400   "Major mode for Wanderlust Folder.
1401 See Info under Wanderlust for full documentation.
1402
1403 Special commands:
1404 \\{wl-folder-mode-map}
1405
1406 Entering Folder mode calls the value of `wl-folder-mode-hook'."
1407   (interactive)
1408   (setq major-mode 'wl-folder-mode)
1409   (setq mode-name "Folder")
1410   (use-local-map wl-folder-mode-map)
1411   (setq buffer-read-only t)
1412   (setq inhibit-read-only nil)
1413   (setq truncate-lines t)
1414   (setq wl-folder-buffer-cur-entity-id nil
1415         wl-folder-buffer-cur-path nil
1416         wl-folder-buffer-cur-point nil)
1417   (wl-mode-line-buffer-identification)
1418   (easy-menu-add wl-folder-mode-menu)
1419   ;; This hook may contain the functions `wl-folder-init-icons' and
1420   ;; `wl-setup-folder' for reasons of system internal to accord
1421   ;; facilities for the Emacs variants.
1422   (run-hooks 'wl-folder-mode-hook))
1423
1424 (defun wl-folder-append-petname (realname petname)
1425   (let (pentry)
1426     ;; check group name.
1427     (if (wl-folder-search-group-entity-by-name petname wl-folder-entity)
1428         (error "%s already defined as group name" petname))
1429     (when (setq pentry (wl-string-assoc realname wl-folder-petname-alist))
1430       (setq wl-folder-petname-alist
1431             (delete pentry wl-folder-petname-alist)))
1432     (wl-append wl-folder-petname-alist
1433                (list (cons realname petname)))))
1434
1435 (defun wl-folder (&optional arg)
1436   (interactive "P")
1437   (let (initialize folder-buf)
1438     (if (setq folder-buf (get-buffer wl-folder-buffer-name))
1439         (if wl-folder-use-frame
1440             (let (select-frame)
1441               (save-selected-window
1442                 (dolist (frame (visible-frame-list))
1443                   (select-frame frame)
1444                   (if (get-buffer-window folder-buf)
1445                       (setq select-frame frame))))
1446               (if select-frame
1447                   (select-frame select-frame)
1448                 (switch-to-buffer folder-buf)))
1449           (switch-to-buffer folder-buf))
1450       (if wl-folder-use-frame
1451           (switch-to-buffer-other-frame
1452            (get-buffer-create wl-folder-buffer-name))
1453         (switch-to-buffer (get-buffer-create wl-folder-buffer-name)))
1454       (switch-to-buffer (get-buffer wl-folder-buffer-name))
1455       (wl-folder-mode)
1456       (wl-folder-init)
1457       (set-buffer wl-folder-buffer-name)
1458       (let ((inhibit-read-only t)
1459             (buffer-read-only nil))
1460         (erase-buffer)
1461         (setcdr (assoc (car wl-folder-entity) wl-folder-group-alist) t)
1462         (save-excursion
1463           (wl-folder-insert-entity " " wl-folder-entity)))
1464       (set-buffer-modified-p nil)
1465       ;(sit-for 0)
1466       (setq initialize t))
1467     initialize))
1468
1469 (defun wl-folder-auto-check ()
1470   "Check and update folders in `wl-auto-check-folder-name'."
1471   (interactive)
1472   (when (get-buffer wl-folder-buffer-name)
1473     (switch-to-buffer  wl-folder-buffer-name)
1474     (cond
1475      ((eq wl-auto-check-folder-name 'none))
1476      ((or (consp wl-auto-check-folder-name)
1477           (stringp wl-auto-check-folder-name))
1478       (let ((folder-list (if (consp wl-auto-check-folder-name)
1479                              wl-auto-check-folder-name
1480                            (list wl-auto-check-folder-name)))
1481             entity)
1482         (while folder-list
1483           (if (setq entity (wl-folder-search-entity-by-name
1484                             (car folder-list)
1485                             wl-folder-entity))
1486               (wl-folder-check-entity entity 'auto))
1487           (setq folder-list (cdr folder-list)))))
1488      (t
1489       (wl-folder-check-entity wl-folder-entity 'auto)))))
1490
1491 (defun wl-folder-set-folder-updated (name value)
1492   (save-excursion
1493     (let (buf)
1494       (if (setq buf (get-buffer wl-folder-buffer-name))
1495           (wl-folder-entity-hashtb-set
1496            wl-folder-entity-hashtb name value buf))
1497 ;;;   (elmo-folder-set-info-hashtb (elmo-string name)
1498 ;;;                                nil
1499 ;;;                                (nth 2 value)
1500 ;;;                                (nth 0 value)
1501 ;;;                                (nth 1 value))
1502       (setq wl-folder-info-alist-modified t))))
1503
1504 (defun wl-folder-calc-finfo (entity)
1505   ;; calcurate finfo without inserting.
1506   (let ((entities (list entity))
1507         entity-stack
1508         new unread all nums)
1509     (while entities
1510       (setq entity (wl-pop entities))
1511       (cond
1512        ((consp entity)
1513         (and entities
1514              (wl-push entities entity-stack))
1515         (setq entities (nth 2 entity)))
1516        ((stringp entity)
1517         (setq nums (wl-folder-get-entity-info entity))
1518         (setq new    (+ (or new 0) (or (nth 0 nums) 0)))
1519         (setq unread (+ (or unread 0)
1520                         (or (and (nth 0 nums)(nth 1 nums)
1521                                  (+ (nth 0 nums)(nth 1 nums))) 0)))
1522         (setq all    (+ (or all 0) (or (nth 2 nums) 0)))))
1523       (unless entities
1524         (setq entities (wl-pop entity-stack))))
1525     (list new unread all)))
1526
1527 (defsubst wl-folder-make-save-access-list (list)
1528   (mapcar '(lambda (x)
1529              (cond
1530               ((consp x)
1531                (list (elmo-string (car x)) 'access))
1532               (t
1533                (elmo-string x))))
1534           list))
1535
1536 (defun wl-folder-update-newest (indent entity)
1537   (let (ret-val new unread all)
1538     (cond
1539      ((consp entity)
1540       (let ((inhibit-read-only t)
1541             (buffer-read-only nil)
1542             (flist (nth 2 entity))
1543             (as-opened (cdr (assoc (car entity) wl-folder-group-alist)))
1544             beg
1545             )
1546         (setq beg (point))
1547         (if as-opened
1548             (let (update-flist flist-unsub new-flist removed group-name-end)
1549               (when (and (eq (cadr entity) 'access)
1550                          (elmo-folder-plugged-p (car entity)))
1551                 (message "Fetching folder entries...")
1552                 (when (setq new-flist
1553                             (elmo-list-folders
1554                              (elmo-string (car entity))
1555                              (wl-string-member
1556                               (car entity)
1557                               wl-folder-hierarchy-access-folders)))
1558                   (setq update-flist
1559                         (wl-folder-update-access-group entity new-flist))
1560                   (setq flist (nth 1 update-flist))
1561                   (when (car update-flist) ;; diff
1562                     (setq flist-unsub (nth 2 update-flist))
1563                     (setq removed (nth 3 update-flist))
1564                     (elmo-msgdb-flist-save
1565                      (car entity)
1566                      (list
1567                       (wl-folder-make-save-access-list flist)
1568                       (wl-folder-make-save-access-list flist-unsub)))
1569                     (wl-folder-entity-assign-id
1570                      entity
1571                      wl-folder-entity-id-name-hashtb
1572                      t)
1573                     (setq wl-folder-entity-hashtb
1574                           (wl-folder-create-entity-hashtb
1575                            entity
1576                            wl-folder-entity-hashtb
1577                            t))
1578                     (setq wl-folder-newsgroups-hashtb
1579                           (or
1580                            (wl-folder-create-newsgroups-hashtb
1581                             entity nil)
1582                            wl-folder-newsgroups-hashtb))))
1583                 (message "Fetching folder entries...done"))
1584               (wl-folder-insert-entity indent entity))))))))
1585
1586 (defun wl-folder-insert-entity (indent entity &optional onlygroup)
1587   (let (ret-val new unread all)
1588     (cond
1589      ((consp entity)
1590       (let ((inhibit-read-only t)
1591             (buffer-read-only nil)
1592             (flist (nth 2 entity))
1593             (as-opened (cdr (assoc (car entity) wl-folder-group-alist)))
1594             beg
1595             )
1596 ;;;     (insert indent "[" (if as-opened "-" "+") "]" (car entity) "\n")
1597 ;;;     (save-excursion (forward-line -1)
1598 ;;;                     (wl-highlight-folder-current-line))
1599         (setq beg (point))
1600         (if (and as-opened
1601                  (not onlygroup))
1602             (let (update-flist flist-unsub new-flist removed group-name-end)
1603 ;;;           (when (and (eq (cadr entity) 'access)
1604 ;;;                      newest)
1605 ;;;             (message "fetching folder entries...")
1606 ;;;             (when (setq new-flist
1607 ;;;                         (elmo-list-folders
1608 ;;;                          (elmo-string (car entity))
1609 ;;;                          (wl-string-member
1610 ;;;                           (car entity)
1611 ;;;                           wl-folder-hierarchy-access-folders)
1612 ;;;                          ))
1613 ;;;               (setq update-flist
1614 ;;;                     (wl-folder-update-access-group entity new-flist))
1615 ;;;               (setq flist (nth 1 update-flist))
1616 ;;;               (when (car update-flist) ;; diff
1617 ;;;                 (setq flist-unsub (nth 2 update-flist))
1618 ;;;                 (setq removed (nth 3 update-flist))
1619 ;;;                 (elmo-msgdb-flist-save
1620 ;;;                  (car entity)
1621 ;;;                  (list
1622 ;;;                   (wl-folder-make-save-access-list flist)
1623 ;;;                   (wl-folder-make-save-access-list flist-unsub)))
1624 ;;;                 ;;
1625 ;;;                 ;; reconstruct wl-folder-entity-id-name-hashtb and
1626 ;;;                 ;;           wl-folder-entity-hashtb
1627 ;;;                 ;;
1628 ;;;                 (wl-folder-entity-assign-id
1629 ;;;                  entity
1630 ;;;                  wl-folder-entity-id-name-hashtb
1631 ;;;                  t)
1632 ;;;                 (setq wl-folder-entity-hashtb
1633 ;;;                       (wl-folder-create-entity-hashtb
1634 ;;;                        entity
1635 ;;;                        wl-folder-entity-hashtb
1636 ;;;                        t))
1637 ;;;                 (setq wl-folder-newsgroups-hashtb
1638 ;;;                       (or
1639 ;;;                        (wl-folder-create-newsgroups-hashtb
1640 ;;;                         entity nil)
1641 ;;;                        wl-folder-newsgroups-hashtb))))
1642 ;;;             (message "fetching folder entries...done"))
1643               (insert indent "[" (if as-opened "-" "+") "]"
1644                       (wl-folder-get-petname (car entity)))
1645               (setq group-name-end (point))
1646               (insert ":0/0/0\n")
1647               (put-text-property beg (point) 'wl-folder-entity-id
1648                                  (get-text-property 0 'wl-folder-entity-id
1649                                                     (car entity)))
1650               (when removed
1651                 (setq beg (point))
1652                 (while removed
1653                   (insert indent "  "
1654                           wl-folder-removed-mark
1655                           (if (listp (car removed))
1656                               (concat "[+]" (caar removed))
1657                             (car removed))
1658                           "\n")
1659                   (save-excursion (forward-line -1)
1660                                   (wl-highlight-folder-current-line))
1661                   (setq removed (cdr removed)))
1662                 (remove-text-properties beg (point) '(wl-folder-entity-id)))
1663               (let* ((len (length flist))
1664                      (mes (> len 100))
1665                      (i 0))
1666                 (while flist
1667                   (setq ret-val
1668                         (wl-folder-insert-entity
1669                          (concat indent "  ") (car flist)))
1670                   (setq new    (+ (or new 0) (or (nth 0 ret-val) 0)))
1671                   (setq unread (+ (or unread 0) (or (nth 1 ret-val) 0)))
1672                   (setq all    (+ (or all 0) (or (nth 2 ret-val) 0)))
1673                   (when (and mes
1674                              (> len elmo-display-progress-threshold))
1675                     (setq i (1+ i))
1676                     (elmo-display-progress
1677                      'wl-folder-insert-entity "Inserting group %s..."
1678                      (/ (* i 100) len) (car entity)))
1679                   (setq flist (cdr flist))))
1680               (save-excursion
1681                 (goto-char group-name-end)
1682                 (delete-region (point) (save-excursion (end-of-line)
1683                                                        (point)))
1684                 (insert (format ":%d/%d/%d" (or new 0)
1685                                 (or unread 0) (or all 0)))
1686                 (setq ret-val (list new unread all))
1687                 (wl-highlight-folder-current-line ret-val)))
1688           (setq ret-val (wl-folder-calc-finfo entity))
1689           (insert indent "[" (if as-opened "-" "+") "]"
1690                   (wl-folder-get-petname (car entity))
1691                   (format ":%d/%d/%d"
1692                           (or (nth 0 ret-val) 0)
1693                           (or (nth 1 ret-val) 0)
1694                           (or (nth 2 ret-val) 0))
1695                   "\n")
1696           (put-text-property beg (point) 'wl-folder-entity-id
1697                              (get-text-property 0 'wl-folder-entity-id
1698                                                 (car entity)))
1699           (save-excursion (forward-line -1)
1700                           (wl-highlight-folder-current-line ret-val)))))
1701      ((stringp entity)
1702       (let* ((inhibit-read-only t)
1703              (buffer-read-only nil)
1704              (nums (wl-folder-get-entity-info entity))
1705              beg)
1706         (setq beg (point))
1707         (insert indent (wl-folder-get-petname entity)
1708                 (format ":%s/%s/%s\n"
1709                         (or (setq new (nth 0 nums)) "*")
1710                         (or (setq unread (and (nth 0 nums)(nth 1 nums)
1711                                               (+ (nth 0 nums)(nth 1 nums))))
1712                             "*")
1713                         (or (setq all (nth 2 nums)) "*")))
1714         (put-text-property beg (point) 'wl-folder-entity-id
1715                            (get-text-property 0 'wl-folder-entity-id entity))
1716         (save-excursion (forward-line -1)
1717                         (wl-highlight-folder-current-line nums))
1718         (setq ret-val (list new unread all)))))
1719     (set-buffer-modified-p nil)
1720     ret-val))
1721
1722 (defun wl-folder-check-all ()
1723   (interactive)
1724   (wl-folder-check-entity wl-folder-entity))
1725
1726 (defun wl-folder-entity-hashtb-set (entity-hashtb name value buffer)
1727   (let (cur-val
1728         (new-diff 0)
1729         (unread-diff 0)
1730         (all-diff 0)
1731         diffs
1732         entity-list)
1733     (setq cur-val (wl-folder-get-entity-info name entity-hashtb))
1734     (setq new-diff    (- (or (nth 0 value) 0) (or (nth 0 cur-val) 0)))
1735     (setq unread-diff
1736           (+ new-diff
1737              (- (or (nth 1 value) 0) (or (nth 1 cur-val) 0))))
1738     (setq all-diff    (- (or (nth 2 value) 0) (or (nth 2 cur-val) 0)))
1739     (setq diffs (list new-diff unread-diff all-diff))
1740     (unless (and (nth 0 cur-val)
1741                  (equal diffs '(0 0 0)))
1742       (wl-folder-set-entity-info name value entity-hashtb)
1743       (save-match-data
1744         (save-excursion
1745           (set-buffer buffer)
1746           (setq entity-list (wl-folder-search-entity-list-by-name
1747                              name wl-folder-entity))
1748           (while entity-list
1749             (wl-folder-update-group (car entity-list) diffs)
1750             (setq entity-list (cdr entity-list)))
1751           (goto-char (point-min))
1752           (while (wl-folder-buffer-search-entity name)
1753             (wl-folder-update-line value)))))))
1754
1755 (defun wl-folder-update-unread (folder unread)
1756   (save-window-excursion
1757     (let ((buf (get-buffer wl-folder-buffer-name))
1758           cur-unread
1759           (unread-diff 0)
1760           ;;(fld (elmo-string folder))
1761           value newvalue entity-list)
1762 ;;; Update folder-info
1763 ;;;    (elmo-folder-set-info-hashtb fld nil nil nil unread)
1764       (setq cur-unread (or (nth 1 (wl-folder-get-entity-info folder)) 0))
1765       (setq unread-diff (- (or unread 0) cur-unread))
1766       (setq value (wl-folder-get-entity-info folder))
1767
1768       (setq newvalue (list (nth 0 value)
1769                            unread
1770                            (nth 2 value)))
1771       (wl-folder-set-entity-info folder newvalue)
1772       (setq wl-folder-info-alist-modified t)
1773       (when (and buf
1774                  (not (eq unread-diff 0)))
1775         (save-match-data
1776           (save-excursion
1777             (set-buffer buf)
1778             (save-excursion
1779               (setq entity-list (wl-folder-search-entity-list-by-name
1780                                  folder wl-folder-entity))
1781               (while entity-list
1782                 (wl-folder-update-group (car entity-list) (list 0
1783                                                                 unread-diff
1784                                                                 0))
1785                 (setq entity-list (cdr entity-list)))
1786               (goto-char (point-min))
1787               (while (wl-folder-buffer-search-entity folder)
1788                 (wl-folder-update-line newvalue)))))))))
1789
1790 (defun wl-folder-create-entity-hashtb (entity &optional hashtb reconst)
1791   (let ((hashtb (or hashtb (elmo-make-hash wl-folder-entity-id)))
1792         (entities (list entity))
1793         entity-stack)
1794     (while entities
1795       (setq entity (wl-pop entities))
1796       (cond
1797        ((consp entity)
1798         (and entities
1799              (wl-push entities entity-stack))
1800         (setq entities (nth 2 entity)))
1801        ((stringp entity)
1802         (when (not (and reconst
1803                         (wl-folder-get-entity-info entity)))
1804           (wl-folder-set-entity-info entity
1805                                      nil
1806                                      hashtb))))
1807       (unless entities
1808         (setq entities (wl-pop entity-stack))))
1809     hashtb))
1810
1811 ;; Unsync number is reserved.
1812 ;;(defun wl-folder-reconstruct-entity-hashtb (entity &optional hashtb id-name)
1813 ;;  (let* ((hashtb (or hashtb (elmo-make-hash wl-folder-entity-id)))
1814 ;;       (entities (list entity))
1815 ;;       entity-stack)
1816 ;;    (while entities
1817 ;;      (setq entity (wl-pop entities))
1818 ;;      (cond
1819 ;;       ((consp entity)
1820 ;;      (if id-name
1821 ;;          (wl-folder-set-id-name (wl-folder-get-entity-id (car entity))
1822 ;;                                 (car entity)))
1823 ;;      (and entities
1824 ;;           (wl-push entities entity-stack))
1825 ;;      (setq entities (nth 2 entity))
1826 ;;      )
1827 ;;       ((stringp entity)
1828 ;;      (wl-folder-set-entity-info entity
1829 ;;                                 (wl-folder-get-entity-info entity)
1830 ;;                                 hashtb)
1831 ;;      (if id-name
1832 ;;          (wl-folder-set-id-name (wl-folder-get-entity-id entity)
1833 ;;                                 entity))))
1834 ;;      (unless entities
1835 ;;      (setq entities (wl-pop entity-stack))))
1836 ;;    hashtb))
1837
1838 (defun wl-folder-create-newsgroups-from-nntp-access2 (entity)
1839   (let ((flist (nth 2 entity))
1840         folders)
1841     (and
1842      (setq folders
1843            (delq
1844             nil
1845             (mapcar
1846              '(lambda (fld)
1847                 (if (consp fld)
1848                     (wl-folder-create-newsgroups-from-nntp-access2 fld)
1849                   (nth 1 (elmo-folder-get-spec fld))))
1850              flist)))
1851      (elmo-nntp-make-groups-hashtb folders 1024))
1852     nil))
1853
1854 (defun wl-folder-create-newsgroups-from-nntp-access (entity)
1855   (let ((flist (nth 2 entity))
1856         folders)
1857     (while flist
1858       (wl-append folders
1859                  (cond
1860                   ((consp (car flist))
1861                    (wl-folder-create-newsgroups-from-nntp-access (car flist)))
1862                   (t
1863                    (list (nth 1 (elmo-folder-get-spec (car flist)))))))
1864       (setq flist (cdr flist)))
1865     folders))
1866
1867 (defun wl-folder-create-newsgroups-hashtb (entity &optional is-list info)
1868   (let ((entities (if is-list entity (list entity)))
1869         entity-stack spec-list folders fld make-hashtb)
1870     (and info (message "Creating newsgroups..."))
1871     (while entities
1872       (setq entity (wl-pop entities))
1873       (cond
1874        ((consp entity)
1875         (if (eq (nth 1 entity) 'access)
1876             (when (eq (elmo-folder-get-type (car entity)) 'nntp)
1877               (wl-append folders
1878                          (wl-folder-create-newsgroups-from-nntp-access entity))
1879               (setq make-hashtb t))
1880           (and entities
1881                (wl-push entities entity-stack))
1882           (setq entities (nth 2 entity))))
1883        ((stringp entity)
1884         (setq spec-list (elmo-folder-get-primitive-spec-list entity))
1885         (while spec-list
1886           (when (and (eq (caar spec-list) 'nntp)
1887                      (setq fld (nth 1 (car spec-list))))
1888             (wl-append folders (list (elmo-string fld))))
1889           (setq spec-list (cdr spec-list)))))
1890       (unless entities
1891         (setq entities (wl-pop entity-stack))))
1892     (and info (message "Creating newsgroups...done"))
1893     (if (or folders make-hashtb)
1894         (elmo-nntp-make-groups-hashtb folders))))
1895
1896 (defun wl-folder-get-path (entity target-id &optional string)
1897   (let ((entities (list entity))
1898         entity-stack result-path)
1899     (reverse
1900      (catch 'done
1901        (while entities
1902          (setq entity (wl-pop entities))
1903          (cond
1904           ((consp entity)
1905            (if (and (or (not string) (string= string (car entity)))
1906                     ;; don't use eq, `id' is string on Nemacs.
1907                     (equal target-id (wl-folder-get-entity-id (car entity))))
1908                (throw 'done
1909                       (wl-push target-id result-path))
1910              (wl-push (wl-folder-get-entity-id (car entity)) result-path))
1911            (wl-push entities entity-stack)
1912            (setq entities (nth 2 entity)))
1913           ((stringp entity)
1914            (if (and (or (not string) (string= string entity))
1915                     ;; don't use eq, `id' is string on Nemacs.
1916                     (equal target-id (wl-folder-get-entity-id entity)))
1917                (throw 'done
1918                       (wl-push target-id result-path)))))
1919          (unless entities
1920            (while (and entity-stack
1921                        (not entities))
1922              (setq result-path (cdr result-path))
1923              (setq entities (wl-pop entity-stack)))))))))
1924
1925 (defun wl-folder-create-group-alist (entity)
1926   (if (consp entity)
1927       (let ((flist (nth 2 entity))
1928             (cur-alist (list (cons (car entity) nil)))
1929              append-alist)
1930         (while flist
1931           (if (consp (car flist))
1932               (wl-append append-alist
1933                          (wl-folder-create-group-alist (car flist))))
1934           (setq flist (cdr flist)))
1935         (append cur-alist append-alist))))
1936
1937 (defun wl-folder-init-info-hashtb ()
1938   (let ((info-alist (and wl-folder-info-save
1939                          (elmo-msgdb-finfo-load))))
1940     (elmo-folder-info-make-hashtb
1941      info-alist
1942      wl-folder-entity-hashtb)))
1943 ;;; (wl-folder-resume-entity-hashtb-by-finfo
1944 ;;;  wl-folder-entity-hashtb
1945 ;;;  info-alist)))
1946
1947 (defun wl-folder-cleanup-variables ()
1948   (setq wl-folder-entity nil
1949         wl-folder-entity-hashtb nil
1950         wl-folder-entity-id-name-hashtb nil
1951         wl-folder-group-alist nil
1952         wl-folder-petname-alist nil
1953         wl-folder-newsgroups-hashtb nil
1954         wl-fldmgr-cut-entity-list nil
1955         wl-fldmgr-modified nil
1956         wl-fldmgr-modified-access-list nil
1957         wl-score-cache nil
1958         ))
1959
1960 (defun wl-make-plugged-alist ()
1961   (let ((entity-list (wl-folder-get-entity-list wl-folder-entity))
1962         (add (not wl-reset-plugged-alist)))
1963     (while entity-list
1964       (elmo-folder-set-plugged
1965        (elmo-string (car entity-list)) wl-plugged add)
1966       (setq entity-list (cdr entity-list)))
1967     ;; smtp posting server
1968     (when wl-smtp-posting-server
1969       (elmo-set-plugged wl-plugged
1970                         wl-smtp-posting-server  ; server
1971                         (or (and (boundp 'smtp-service) smtp-service)
1972                             "smtp")     ; port
1973                         nil nil "smtp" add))
1974     ;; nntp posting server
1975     (when wl-nntp-posting-server
1976       (elmo-set-plugged wl-plugged
1977                         wl-nntp-posting-server
1978                         elmo-default-nntp-port
1979                         nil nil "nntp" add))
1980     (run-hooks 'wl-make-plugged-hook)))
1981
1982 (defvar wl-folder-init-func 'wl-local-folder-init)
1983
1984 (defun wl-folder-init ()
1985   "Call `wl-folder-init-func' function."
1986   (interactive)
1987   (funcall wl-folder-init-func))
1988
1989 (defun wl-local-folder-init ()
1990   "Initialize local folder."
1991   (message "Initializing folder...")
1992   (save-excursion
1993     (set-buffer wl-folder-buffer-name)
1994     (let ((entity (wl-folder-create-folder-entity))
1995           (inhibit-read-only t))
1996       (setq wl-folder-entity entity)
1997       (setq wl-folder-entity-id 0)
1998       (wl-folder-entity-assign-id wl-folder-entity)
1999       (setq wl-folder-entity-hashtb
2000             (wl-folder-create-entity-hashtb entity))
2001       (setq wl-folder-group-alist
2002             (wl-folder-create-group-alist entity))
2003       (setq wl-folder-newsgroups-hashtb
2004             (wl-folder-create-newsgroups-hashtb wl-folder-entity))
2005       (wl-folder-init-info-hashtb)))
2006   (message "Initializing folder...done"))
2007
2008 (defun wl-folder-get-realname (petname)
2009   (or (car
2010        (wl-string-rassoc
2011         petname
2012         wl-folder-petname-alist))
2013       petname))
2014
2015 (defun wl-folder-get-petname (folder)
2016   (or (cdr
2017        (wl-string-assoc
2018         folder
2019         wl-folder-petname-alist))
2020       folder))
2021
2022 (defun wl-folder-get-entity-with-petname ()
2023   (let ((alist wl-folder-petname-alist)
2024         (hashtb (copy-sequence wl-folder-entity-hashtb)))
2025     (while alist
2026       (wl-folder-set-entity-info (cdar alist) nil hashtb)
2027       (setq alist (cdr alist)))
2028     hashtb))
2029
2030 (defun wl-folder-get-newsgroups (folder)
2031   "Return Newsgroups field value string for FOLDER newsgroup.
2032 If FOLDER is multi, return comma separated string (cross post)."
2033   (let ((flist (elmo-folder-get-primitive-folder-list folder)) ; multi
2034         newsgroups fld ret)
2035     (while (setq fld (car flist))
2036       (if (setq ret
2037                 (cond ((eq 'nntp (elmo-folder-get-type fld))
2038                        (nth 1 (elmo-folder-get-spec fld)))
2039                       ((eq 'localnews (elmo-folder-get-type fld))
2040                        (elmo-replace-in-string
2041                         (nth 1 (elmo-folder-get-spec fld)) "/" "\\."))))
2042           ;; append newsgroup
2043           (setq newsgroups (if (stringp newsgroups)
2044                                (concat newsgroups "," ret)
2045                              ret)))
2046       (setq flist (cdr flist)))
2047     (list nil nil newsgroups)))
2048
2049 (defun wl-folder-guess-mailing-list-by-refile-rule (folder)
2050   "Return ML address guess by FOLDER.
2051 Use `wl-subscribed-mailing-list' and `wl-refile-rule-alist'.
2052 Don't care multi."
2053   (setq folder (car (elmo-folder-get-primitive-folder-list folder)))
2054   (unless (memq (elmo-folder-get-type folder)
2055                 '(localnews nntp))
2056     (let ((rules wl-refile-rule-alist)
2057           mladdress tokey toalist histkey)
2058       (while rules
2059         (if (or (and (stringp (car (car rules)))
2060                      (string-match "[Tt]o" (car (car rules))))
2061                 (and (listp (car (car rules)))
2062                      (elmo-string-matched-member "to" (car (car rules))
2063                                                  'case-ignore)))
2064             (setq toalist (append toalist (cdr (car rules)))))
2065         (setq rules (cdr rules)))
2066       (setq tokey (car (rassoc folder toalist)))
2067 ;;;     (setq histkey (car (rassoc folder wl-refile-alist)))
2068       ;; case-ignore search `wl-subscribed-mailing-list'
2069       (if (stringp tokey)
2070           (list
2071            (elmo-string-matched-member tokey wl-subscribed-mailing-list t)
2072            nil nil)
2073         nil))))
2074
2075 (defun wl-folder-guess-mailing-list-by-folder-name (folder)
2076   "Return ML address guess by FOLDER name's last hierarchy.
2077 Use `wl-subscribed-mailing-list'."
2078   (setq folder (car (elmo-folder-get-primitive-folder-list folder)))
2079   (when (memq (elmo-folder-get-type folder)
2080               '(localdir imap4 maildir))
2081     (let (key mladdress)
2082       (setq folder                      ; make folder name simple
2083             (if (eq 'imap4 (elmo-folder-get-type folder))
2084                 (elmo-imap4-spec-mailbox (elmo-imap4-get-spec folder))
2085               (substring folder 1)))
2086       (if (string-match "@" folder)
2087           (setq folder (substring folder 0 (match-beginning 0))))
2088       (when (string-match "[^\\./]+$" folder) ; last hierarchy
2089         (setq key (regexp-quote
2090                    (concat (substring folder (match-beginning 0)) "@")))
2091         (setq mladdress
2092               (elmo-string-matched-member
2093                key wl-subscribed-mailing-list 'case-ignore))
2094         (if (stringp mladdress)
2095             (list mladdress nil nil)
2096           nil)))))
2097
2098 (defun wl-folder-update-diff-line (diffs)
2099   (let ((inhibit-read-only t)
2100         (buffer-read-only nil)
2101         cur-new new-new
2102         cur-unread new-unread
2103         cur-all new-all
2104         id)
2105     (save-excursion
2106       (beginning-of-line)
2107       (setq id (get-text-property (point) 'wl-folder-entity-id))
2108       (when (looking-at "^[ ]*\\(.*\\):\\([0-9\\*-]*\\)/\\([0-9\\*-]*\\)/\\([0-9\\*]*\\)")
2109         ;;(looking-at "^[ ]*\\([^\\[].+\\):\\([0-9\\*-]*/[0-9\\*-]*/[0-9\\*]*\\)")
2110         (setq cur-new (string-to-int
2111                        (wl-match-buffer 2)))
2112         (setq cur-unread (string-to-int
2113                           (wl-match-buffer 3)))
2114         (setq cur-all (string-to-int
2115                        (wl-match-buffer 4)))
2116         (delete-region (match-beginning 2)
2117                        (match-end 4))
2118         (goto-char (match-beginning 2))
2119         (insert (format "%s/%s/%s"
2120                         (setq new-new (+ cur-new (nth 0 diffs)))
2121                         (setq new-unread (+ cur-unread (nth 1 diffs)))
2122                         (setq new-all (+ cur-all (nth 2 diffs)))))
2123         (put-text-property (match-beginning 2) (point)
2124                            'wl-folder-entity-id id)
2125         (if wl-use-highlight-mouse-line
2126             (put-text-property (match-beginning 2) (point)
2127                                'mouse-face 'highlight))
2128         (wl-highlight-folder-group-line (list new-new new-unread new-all))
2129         (setq buffer-read-only t)
2130         (set-buffer-modified-p nil)))))
2131
2132 (defun wl-folder-update-line (nums &optional is-group)
2133   (let ((inhibit-read-only t)
2134         (buffer-read-only nil)
2135         id)
2136     (save-excursion
2137       (beginning-of-line)
2138       (setq id (get-text-property (point) 'wl-folder-entity-id))
2139       (if (looking-at "^[ ]*\\(.*\\):\\([0-9\\*-]*/[0-9\\*-]*/[0-9\\*]*\\)")
2140 ;;;       (looking-at "^[ ]*\\([^\\[].+\\):\\([0-9\\*-]*/[0-9\\*-]*/[0-9\\*]*\\)")
2141           (progn
2142             (delete-region (match-beginning 2)
2143                            (match-end 2))
2144             (goto-char (match-beginning 2))
2145             (insert (format "%s/%s/%s"
2146                             (or (nth 0 nums) "*")
2147                             (or (and (nth 0 nums)(nth 1 nums)
2148                                      (+ (nth 0 nums)(nth 1 nums)))
2149                                 "*")
2150                             (or (nth 2 nums) "*")))
2151             (put-text-property (match-beginning 2) (point)
2152                                'wl-folder-entity-id id)
2153             (if is-group
2154                 ;; update only colors
2155                 (wl-highlight-folder-group-line nums)
2156               (wl-highlight-folder-current-line nums))
2157             (set-buffer-modified-p nil))))))
2158
2159 (defun wl-folder-goto-folder (&optional arg)
2160   (interactive "P")
2161   (wl-folder-goto-folder-subr nil arg))
2162
2163 (defun wl-folder-goto-folder-subr (&optional folder sticky)
2164   (beginning-of-line)
2165   (let (summary-buf fld-name entity id error-selecting)
2166 ;;; (setq fld-name (wl-folder-get-entity-from-buffer))
2167 ;;; (if (or (null fld-name)
2168 ;;;         (assoc fld-name wl-folder-group-alist))
2169     (setq fld-name wl-default-folder)
2170     (setq fld-name (or folder
2171                        (wl-summary-read-folder fld-name)))
2172     (if (and (setq entity
2173                    (wl-folder-search-entity-by-name fld-name
2174                                                     wl-folder-entity
2175                                                     'folder))
2176              (setq id (wl-folder-get-entity-id entity)))
2177         (wl-folder-set-current-entity-id id))
2178     (setq summary-buf (wl-summary-get-buffer-create fld-name sticky))
2179     (if wl-stay-folder-window
2180         (wl-folder-select-buffer summary-buf)
2181       (if (and summary-buf
2182                (get-buffer-window summary-buf))
2183           (delete-window)))
2184     (wl-summary-goto-folder-subr fld-name
2185                                  (wl-summary-get-sync-range fld-name)
2186                                  nil sticky t)))
2187
2188 (defun wl-folder-suspend ()
2189   (interactive)
2190   (run-hooks 'wl-folder-suspend-hook)
2191   (wl-folder-info-save)
2192   (wl-crosspost-alist-save)
2193   (wl-kill-buffers
2194    (format "^\\(%s\\)$"
2195            (mapconcat 'identity
2196                       (list (format "%s\\(:.*\\)?"
2197                                     (default-value 'wl-message-buf-name))
2198                             wl-original-buf-name)
2199                       "\\|")))
2200   (if (fboundp 'mmelmo-cleanup-entity-buffers)
2201       (mmelmo-cleanup-entity-buffers))
2202   (bury-buffer wl-folder-buffer-name)
2203   (delete-windows-on wl-folder-buffer-name t))
2204
2205 (defun wl-folder-info-save ()
2206   (when (and wl-folder-info-save
2207              wl-folder-info-alist-modified)
2208     (let ((entities (list wl-folder-entity))
2209           entity entity-stack info-alist info)
2210       (while entities
2211         (setq entity (wl-pop entities))
2212         (cond
2213          ((consp entity)
2214           (and entities
2215                (wl-push entities entity-stack))
2216           (setq entities (nth 2 entity)))
2217          ((stringp entity)
2218           (when (and (setq info (elmo-folder-get-info entity))
2219                      (not (equal info '(nil))))
2220             (wl-append info-alist (list (list (elmo-string entity)
2221                                               (list (nth 3 info)  ;; max
2222                                                     (nth 2 info)  ;; length
2223                                                     (nth 0 info)  ;; new
2224                                                     (nth 1 info)) ;; unread
2225                                               ))))))
2226         (unless entities
2227           (setq entities (wl-pop entity-stack))))
2228       (elmo-msgdb-finfo-save info-alist)
2229       (setq wl-folder-info-alist-modified nil))))
2230
2231 (defun wl-folder-goto-first-unread-folder (&optional arg)
2232   (interactive "P")
2233   (let ((entities (list wl-folder-entity))
2234         entity entity-stack ret-val
2235         first-entity finfo)
2236     (setq first-entity
2237           (catch 'done
2238             (while entities
2239               (setq entity (wl-pop entities))
2240               (cond
2241                ((consp entity)
2242                 (and entities
2243                      (wl-push entities entity-stack))
2244                 (setq entities (nth 2 entity)))
2245                ((stringp entity)
2246                 (if (and (setq finfo (wl-folder-get-entity-info entity))
2247                          (and (nth 0 finfo)(nth 1 finfo))
2248                          (> (+ (nth 0 finfo)(nth 1 finfo)) 0))
2249                     (throw 'done entity))
2250                 (wl-append ret-val (list entity))))
2251               (unless entities
2252                 (setq entities (wl-pop entity-stack))))))
2253     (if first-entity
2254         (progn
2255           (when arg
2256             (wl-folder-jump-folder first-entity)
2257             (sit-for 0))
2258           (wl-folder-goto-folder-subr first-entity))
2259       (message "No unread folder"))))
2260
2261 (defun wl-folder-jump-folder (&optional fld-name noopen)
2262   (interactive)
2263   (if (not fld-name)
2264       (setq fld-name (wl-summary-read-folder wl-default-folder)))
2265   (goto-char (point-min))
2266   (if (not noopen)
2267       (wl-folder-open-folder fld-name))
2268   (and (wl-folder-buffer-search-entity fld-name)
2269        (beginning-of-line)))
2270
2271 (defun wl-folder-get-entity-list (entity)
2272   (let ((entities (list entity))
2273         entity-stack ret-val)
2274     (while entities
2275       (setq entity (wl-pop entities))
2276       (cond
2277        ((consp entity)
2278         (and entities
2279              (wl-push entities entity-stack))
2280         (setq entities (nth 2 entity)))
2281        ((stringp entity)
2282         (wl-append ret-val (list entity))))
2283       (unless entities
2284         (setq entities (wl-pop entity-stack))))
2285     ret-val))
2286
2287 (defun wl-folder-open-unread-folder (entity)
2288   (save-excursion
2289     (let ((alist (wl-folder-get-entity-list entity))
2290           (unread 0)
2291           finfo path-list path id)
2292       (while alist
2293         (when (and (setq finfo (wl-folder-get-entity-info (car alist)))
2294                    (nth 0 finfo) (nth 1 finfo)
2295                    (> (+ (nth 0 finfo)(nth 1 finfo)) 0))
2296           (setq unread (+ unread (+ (nth 0 finfo)(nth 1 finfo))))
2297           (setq id (wl-folder-get-entity-id (car alist)))
2298           (setq path (delete id (wl-folder-get-path
2299                                  wl-folder-entity
2300                                  id
2301                                  (car alist))))
2302           (if (not (member path path-list))
2303               (wl-append path-list (list path))))
2304         (setq alist (cdr alist)))
2305       (while path-list
2306         (wl-folder-open-folder-sub (car path-list))
2307         (setq path-list (cdr path-list)))
2308       (message "%s unread folder"
2309                (if (> unread 0) unread "No")))))
2310
2311 (defun wl-folder-open-unread-current-entity ()
2312   (interactive)
2313   (let ((entity-name (wl-folder-get-entity-from-buffer))
2314         (group (wl-folder-buffer-group-p)))
2315     (when entity-name
2316       (wl-folder-open-unread-folder
2317        (if group
2318            (wl-folder-search-group-entity-by-name entity-name
2319                                                   wl-folder-entity)
2320          entity-name)))))
2321
2322 (defun wl-folder-open-only-unread-folder ()
2323   (interactive)
2324   (let ((id (progn
2325               (wl-folder-prev-entity-skip-invalid t)
2326               (wl-folder-get-entity-from-buffer t))))
2327     (wl-folder-open-all-unread-folder)
2328     (save-excursion
2329       (goto-char (point-max))
2330       (while (and (re-search-backward
2331                    "^[ ]*\\[[-]\\].+:0/0/[0-9-]+" nil t)
2332                   (not (bobp)))
2333         (wl-folder-jump-to-current-entity) ;; close it
2334         ))
2335     (wl-folder-move-path id)
2336     (recenter)))
2337
2338 (defun wl-folder-open-all-unread-folder (&optional arg)
2339   (interactive "P")
2340   (let ((id (progn
2341               (wl-folder-prev-entity-skip-invalid t)
2342               (wl-folder-get-entity-from-buffer t))))
2343     (wl-folder-open-unread-folder wl-folder-entity)
2344     (if (not arg)
2345         (wl-folder-move-path id)
2346       (goto-char (point-min))
2347       (wl-folder-next-unread t))))
2348
2349 (defun wl-folder-open-folder (&optional fld-name)
2350   (interactive)
2351   (if (not fld-name)
2352       (setq fld-name (wl-summary-read-folder wl-default-folder)))
2353   (let* ((id (wl-folder-get-entity-id
2354               (wl-folder-search-entity-by-name fld-name wl-folder-entity
2355                                                'folder)))
2356          (path (and id (wl-folder-get-path wl-folder-entity id))))
2357       (if path
2358           (wl-folder-open-folder-sub path))))
2359
2360 (defun wl-folder-open-folder-sub (path)
2361   (let ((inhibit-read-only t)
2362         (buffer-read-only nil)
2363         indent name entity
2364         err)
2365     (save-excursion
2366       (goto-char (point-min))
2367       (while (and path
2368                   (wl-folder-buffer-search-group
2369                    (wl-folder-get-petname
2370                     (if (stringp (car path))
2371                         (car path)
2372                       (wl-folder-get-folder-name-by-id
2373                        (car path))))))
2374         (beginning-of-line)
2375         (setq path (cdr path))
2376         (if (and (looking-at wl-folder-group-regexp)
2377                  (string= "+" (wl-match-buffer 2)));; closed group
2378             (save-excursion
2379               (setq indent (wl-match-buffer 1))
2380               (setq name (wl-folder-get-realname (wl-match-buffer 3)))
2381               (setq entity (wl-folder-search-group-entity-by-name
2382                             name
2383                             wl-folder-entity))
2384               ;; insert as opened
2385               (setcdr (assoc (car entity) wl-folder-group-alist) t)
2386               (if (eq 'access (cadr entity))
2387                   (wl-folder-maybe-load-folder-list entity))
2388               (wl-folder-insert-entity indent entity)
2389               (delete-region (save-excursion (beginning-of-line)
2390                                              (point))
2391                              (save-excursion (end-of-line)
2392                                              (+ 1 (point)))))))
2393       (set-buffer-modified-p nil))))
2394
2395 (defun wl-folder-open-all-pre ()
2396   (let ((entities (list wl-folder-entity))
2397         entity entity-stack group-entry)
2398     (while entities
2399       (setq entity (wl-pop entities))
2400       (cond
2401        ((consp entity)
2402         (unless (or (not (setq group-entry
2403                                (assoc (car entity) wl-folder-group-alist)))
2404                     (cdr group-entry))
2405           (setcdr group-entry t)
2406           (when (eq 'access (cadr entity))
2407             (wl-folder-maybe-load-folder-list entity)))
2408         (and entities
2409              (wl-push entities entity-stack))
2410         (setq entities (nth 2 entity))))
2411       (unless entities
2412         (setq entities (wl-pop entity-stack))))))
2413
2414 (defun wl-folder-open-all (&optional refresh)
2415   (interactive "P")
2416   (let* ((inhibit-read-only t)
2417          (buffer-read-only nil)
2418          (len (length wl-folder-group-alist))
2419          (i 0)
2420          indent name entity)
2421     (if refresh
2422         (let ((id (progn
2423                     (wl-folder-prev-entity-skip-invalid t)
2424                     (wl-folder-get-entity-from-buffer t)))
2425               (alist wl-folder-group-alist))
2426           (while alist
2427             (setcdr (pop alist) t))
2428           (erase-buffer)
2429           (wl-folder-insert-entity " " wl-folder-entity)
2430           (wl-folder-move-path id))
2431       (message "Opening all folders...")
2432       (wl-folder-open-all-pre)
2433       (save-excursion
2434         (goto-char (point-min))
2435         (while (re-search-forward
2436                 "^\\([ ]*\\)\\[\\([+]\\)\\]\\(.+\\):[-0-9-]+/[0-9-]+/[0-9-]+\n"
2437                 nil t)
2438           (setq indent (wl-match-buffer 1))
2439           (setq name (wl-folder-get-realname (wl-match-buffer 3)))
2440           (setq entity (wl-folder-search-group-entity-by-name
2441                         name
2442                         wl-folder-entity))
2443           ;; insert as opened
2444           (setcdr (assoc (car entity) wl-folder-group-alist) t)
2445           (forward-line -1)
2446           (wl-folder-insert-entity indent entity)
2447           (delete-region (save-excursion (beginning-of-line)
2448                                          (point))
2449                          (save-excursion (end-of-line)
2450                                          (+ 1 (point))))
2451           (when (> len elmo-display-progress-threshold)
2452             (setq i (1+ i))
2453             (if (or (zerop (% i 5)) (= i len))
2454                 (elmo-display-progress
2455                  'wl-folder-open-all "Opening all folders..."
2456                  (/ (* i 100) len)))))
2457         (when (> len elmo-display-progress-threshold)
2458           (elmo-display-progress
2459            'wl-folder-open-all "Opening all folders..." 100))))
2460     (message "Opening all folders...done")
2461     (set-buffer-modified-p nil)))
2462
2463 (defun wl-folder-close-all ()
2464   (interactive)
2465   (let ((inhibit-read-only t)
2466         (buffer-read-only nil)
2467         (alist wl-folder-group-alist)
2468         (id (progn
2469               (wl-folder-prev-entity-skip-invalid t)
2470               (wl-folder-get-entity-from-buffer t))))
2471     (while alist
2472       (setcdr (car alist) nil)
2473       (setq alist (cdr alist)))
2474     (setcdr (assoc (car wl-folder-entity) wl-folder-group-alist) t)
2475     (erase-buffer)
2476     (wl-folder-insert-entity " " wl-folder-entity)
2477     (wl-folder-move-path id)
2478     (recenter)
2479     (set-buffer-modified-p nil)))
2480
2481 (defun wl-folder-open-close ()
2482   "Open or close parent entity."
2483   (interactive)
2484   (save-excursion
2485     (beginning-of-line)
2486     (if (wl-folder-buffer-group-p)
2487         ;; if group (whether opend or closed.)
2488         (wl-folder-jump-to-current-entity)
2489       ;; if folder
2490       (let (indent)
2491         (setq indent (save-excursion
2492                        (re-search-forward "\\([ ]*\\)." nil t)
2493                        (wl-match-buffer 1)))
2494         (while (looking-at indent)
2495           (forward-line -1)))
2496       (wl-folder-jump-to-current-entity))))
2497
2498 (defsubst wl-folder-access-subscribe-p (group folder)
2499   (let (subscr regexp match)
2500     (if (setq subscr (wl-get-assoc-list-value
2501                       wl-folder-access-subscribe-alist
2502                       group))
2503         (progn
2504           (setq regexp (mapconcat 'identity (cdr subscr) "\\|"))
2505           (setq match (string-match regexp folder))
2506           (if (car subscr)
2507               match
2508             (not match)))
2509       t)))
2510
2511 (defun wl-folder-update-access-group (entity new-flist)
2512   (let* ((flist (nth 2 entity))
2513          (unsubscribes (nth 3 entity))
2514          (len (+ (length flist) (length unsubscribes)))
2515          (i 0)
2516          diff new-unsubscribes removes
2517          subscribed-list folder group entry)
2518     ;; check subscribed groups
2519     (while flist
2520       (cond
2521        ((listp (car flist))     ;; group
2522         (setq group (elmo-string (caar flist)))
2523         (cond
2524          ((assoc group new-flist)       ;; found in new-flist
2525           (setq new-flist (delete (assoc group new-flist)
2526                                   new-flist))
2527           (if (wl-folder-access-subscribe-p (car entity) group)
2528               (wl-append subscribed-list (list (car flist)))
2529             (wl-append new-unsubscribes (list (car flist)))
2530             (setq diff t)))
2531          (t
2532           (setq wl-folder-group-alist
2533                 (delete (wl-string-assoc group wl-folder-group-alist)
2534                         wl-folder-group-alist))
2535           (wl-append removes (list (list group))))))
2536        (t                       ;; folder
2537         (setq folder (elmo-string (car flist)))
2538         (cond
2539          ((member folder new-flist)     ;; found in new-flist
2540           (setq new-flist (delete folder new-flist))
2541           (if (wl-folder-access-subscribe-p (car entity) folder)
2542               (wl-append subscribed-list (list (car flist)))
2543             (wl-append new-unsubscribes (list folder))
2544             (setq diff t)))
2545          (t
2546           (wl-append removes (list folder))))))
2547       (when (> len elmo-display-progress-threshold)
2548         (setq i (1+ i))
2549         (if (or (zerop (% i 10)) (= i len))
2550             (elmo-display-progress
2551              'wl-folder-update-access-group "Updating access group..."
2552              (/ (* i 100) len))))
2553       (setq flist (cdr flist)))
2554     ;; check unsubscribed groups
2555     (while unsubscribes
2556       (cond
2557        ((listp (car unsubscribes))
2558         (when (setq entry (assoc (caar unsubscribes) new-flist))
2559           (setq new-flist (delete entry new-flist))
2560           (wl-append new-unsubscribes (list (car unsubscribes)))))
2561        (t
2562         (when (member (car unsubscribes) new-flist)
2563           (setq new-flist (delete (car unsubscribes) new-flist))
2564           (wl-append new-unsubscribes (list (car unsubscribes))))))
2565       (when (> len elmo-display-progress-threshold)
2566         (setq i (1+ i))
2567         (if (or (zerop (% i 10)) (= i len))
2568             (elmo-display-progress
2569              'wl-folder-update-access-group "Updating access group..."
2570              (/ (* i 100) len))))
2571       (setq unsubscribes (cdr unsubscribes)))
2572     ;;
2573     (if (or new-flist removes)
2574         (setq diff t))
2575     (setq new-flist
2576           (mapcar '(lambda (x)
2577                      (cond ((consp x) (list (car x) 'access))
2578                            (t x)))
2579                   new-flist))
2580     ;; check new groups
2581     (let ((new-list new-flist))
2582       (while new-list
2583         (if (not (wl-folder-access-subscribe-p
2584                   (car entity)
2585                   (if (listp (car new-list))
2586                       (caar new-list)
2587                     (car new-list))))
2588             ;; auto unsubscribe
2589             (progn
2590               (wl-append new-unsubscribes (list (car new-list)))
2591               (setq new-flist (delete (car new-list) new-flist)))
2592           (cond
2593            ((listp (car new-list))
2594             ;; check group exists
2595             (if (wl-string-assoc (caar new-list) wl-folder-group-alist)
2596                 (progn
2597                   (message "%s: group already exists." (caar new-list))
2598                   (sit-for 1)
2599                   (wl-append new-unsubscribes (list (car new-list)))
2600                   (setq new-flist (delete (car new-list) new-flist)))
2601               (wl-append wl-folder-group-alist
2602                          (list (cons (caar new-list) nil)))))))
2603         (setq new-list (cdr new-list))))
2604     (if new-flist
2605         (message "%d new folder(s)." (length new-flist))
2606       (message "Updating access group...done"))
2607     (wl-append new-flist subscribed-list)       ;; new is first
2608     (run-hooks 'wl-folder-update-access-group-hook)
2609     (setcdr (cdr entity) (list new-flist new-unsubscribes))
2610     (list diff new-flist new-unsubscribes removes)))
2611
2612 (defun wl-folder-prefetch-entity (entity)
2613   "Prefetch all new messages in the ENTITY."
2614   (cond
2615    ((consp entity)
2616     (let ((flist (nth 2 entity))
2617           (sum-done 0)
2618           (sum-all 0)
2619           result)
2620       (while flist
2621         (setq result (wl-folder-prefetch-entity (car flist)))
2622         (setq sum-done (+ sum-done (car result)))
2623         (setq sum-all (+ sum-all (cdr result)))
2624         (setq flist (cdr flist)))
2625       (message "Prefetched %d/%d message(s) in \"%s\"."
2626                sum-done sum-all
2627                (wl-folder-get-petname (car entity)))
2628       (cons sum-done sum-all)))
2629    ((stringp entity)
2630     (let ((nums (wl-folder-get-entity-info entity))
2631           (wl-summary-highlight (if (or (wl-summary-sticky-p entity)
2632                                         (wl-summary-always-sticky-folder-p
2633                                          entity))
2634                                     wl-summary-highlight))
2635           wl-summary-exit-next-move
2636           wl-auto-select-first ret-val
2637           count)
2638       (setq count (or (car nums) 0))
2639       (setq count (+ count (wl-folder-count-incorporates entity)))
2640       (if (or (null (car nums)) ; unknown
2641               (< 0 count))
2642           (let ((wl-summary-buffer-name (concat
2643                                          wl-summary-buffer-name
2644                                          (symbol-name this-command)))
2645                 (wl-message-buf-name (concat wl-message-buf-name
2646                                              (symbol-name this-command))))
2647             (save-window-excursion
2648               (save-excursion
2649                 (wl-summary-goto-folder-subr entity
2650                                              (wl-summary-get-sync-range entity)
2651                                              nil)
2652                 (setq ret-val (wl-summary-incorporate))
2653                 (wl-summary-exit)
2654                 ret-val)))
2655         (cons 0 0))))))
2656
2657 (defun wl-folder-count-incorporates (folder)
2658   (let ((marks (elmo-msgdb-mark-load (elmo-msgdb-expand-path folder)))
2659         (sum 0))
2660     (while marks
2661       (if (member (cadr (car marks))
2662                   wl-summary-incorporate-marks)
2663           (incf sum))
2664       (setq marks (cdr marks)))
2665     sum))
2666
2667 (defun wl-folder-prefetch-current-entity (&optional no-check)
2668   "Prefetch all uncached messages in the folder at position.
2669 If current line is group folder, all subfolders are prefetched."
2670   (interactive "P")
2671   (save-excursion
2672     (let ((entity-name (wl-folder-get-entity-from-buffer))
2673           (group (wl-folder-buffer-group-p))
2674           wl-folder-check-entity-hook
2675           summary-buf entity)
2676       (when entity-name
2677         (setq entity
2678               (if group
2679                   (wl-folder-search-group-entity-by-name entity-name
2680                                                          wl-folder-entity)
2681                 entity-name))
2682         (if (not no-check)
2683             (wl-folder-check-entity entity))
2684         (wl-folder-prefetch-entity entity)))))
2685
2686 (defun wl-folder-drop-unsync-entity (entity)
2687   "Drop all unsync messages in the ENTITY."
2688   (cond
2689    ((consp entity)
2690     (let ((flist (nth 2 entity)))
2691       (while flist
2692         (wl-folder-drop-unsync-entity (car flist))
2693         (setq flist (cdr flist)))))
2694    ((stringp entity)
2695     (let ((nums (wl-folder-get-entity-info entity))
2696           wl-summary-highlight wl-auto-select-first new)
2697       (setq new (or (car nums) 0))
2698       (if (< 0 new)
2699           (let ((wl-summary-buffer-name (concat
2700                                          wl-summary-buffer-name
2701                                          (symbol-name this-command)))
2702                 (wl-message-buf-name (concat wl-message-buf-name
2703                                              (symbol-name this-command))))
2704             (save-window-excursion
2705               (save-excursion
2706                 (wl-summary-goto-folder-subr entity 'no-sync nil)
2707                 (wl-summary-drop-unsync)
2708                 (wl-summary-exit)))))))))
2709
2710 (defun wl-folder-drop-unsync-current-entity (&optional force-check)
2711   "Drop all unsync messages in the folder at position.
2712 If current line is group folder, all subfolders are dropped.
2713 If optional arg exists, don't check any folders."
2714   (interactive "P")
2715   (save-excursion
2716     (let ((entity-name (wl-folder-get-entity-from-buffer))
2717           (group (wl-folder-buffer-group-p))
2718           wl-folder-check-entity-hook
2719           summary-buf entity)
2720       (when (and entity-name
2721                  (y-or-n-p (format
2722                             "Drop all unsync messages in %s?" entity-name)))
2723         (setq entity
2724               (if group
2725                   (wl-folder-search-group-entity-by-name entity-name
2726                                                          wl-folder-entity)
2727                 entity-name))
2728         (if (null force-check)
2729             (wl-folder-check-entity entity))
2730         (wl-folder-drop-unsync-entity entity)
2731         (message "All unsync messages in %s are dropped!" entity-name)))))
2732
2733 (defun wl-folder-write-current-folder ()
2734   "Write message to current folder's newsgroup or mailing-list.
2735 Call `wl-summary-write-current-folder' with current folder name."
2736   (interactive)
2737   (unless (wl-folder-buffer-group-p)
2738     (wl-summary-write-current-folder
2739      (wl-folder-get-realname (wl-folder-entity-name)))))
2740
2741 (defun wl-folder-mimic-kill-buffer ()
2742   "Kill the current (Folder) buffer with query."
2743   (interactive)
2744   (let ((bufname (read-buffer (format "Kill buffer: (default %s) "
2745                                       (buffer-name))))
2746         wl-interactive-exit)
2747     (if (or (not bufname)
2748             (string-equal bufname "")
2749             (string-equal bufname (buffer-name)))
2750         (wl-exit)
2751       (kill-buffer bufname))))
2752
2753 (defun wl-folder-create-subr (entity)
2754   (if (not (elmo-folder-creatable-p entity))
2755       (error "Folder %s is not found" entity)
2756     (if (y-or-n-p
2757          (format "Folder %s does not exist, create it?"
2758                  entity))
2759         (progn
2760           (setq wl-folder-entity-hashtb
2761                 (wl-folder-create-entity-hashtb
2762                  entity wl-folder-entity-hashtb))
2763           (unless (elmo-create-folder entity)
2764             (error "Create folder failed")))
2765       (error "Folder %s is not created" entity))))
2766
2767 (defun wl-folder-confirm-existence (folder &optional force)
2768   (if force
2769       (unless (elmo-folder-exists-p folder)
2770         (wl-folder-create-subr folder))
2771     (unless (or (wl-folder-entity-exists-p folder)
2772                 (file-exists-p (elmo-msgdb-expand-path folder))
2773                 (elmo-folder-exists-p folder))
2774       (wl-folder-create-subr folder))))
2775
2776 (require 'product)
2777 (product-provide (provide 'wl-folder) (require 'wl-version))
2778
2779 ;;; wl-folder.el ends here