* 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         ret-val)
1290     (if gbw
1291         (progn (select-window gbw)
1292                (setq ret-val t))
1293       (condition-case ()
1294           (unwind-protect
1295               (split-window-horizontally wl-folder-window-width)
1296             (other-window 1))
1297         (error nil)))
1298     (set-buffer buffer)
1299     (switch-to-buffer buffer)
1300     ret-val
1301     ))
1302
1303 (defun wl-folder-toggle-disp-summary (&optional arg folder)
1304   (interactive)
1305   (if (or (and folder (assoc folder wl-folder-group-alist))
1306           (and (interactive-p) (wl-folder-buffer-group-p)))
1307       (error "This command is not available on Group"))
1308   (beginning-of-line)
1309   (let (wl-auto-select-first)
1310     (cond
1311      ((eq arg 'on)
1312       (setq wl-folder-buffer-disp-summary t))
1313      ((eq arg 'off)
1314       (setq wl-folder-buffer-disp-summary nil)
1315       ;; hide wl-summary window.
1316       (let ((cur-buf (current-buffer))
1317             (summary-buffer (wl-summary-get-buffer folder)))
1318         (wl-folder-select-buffer summary-buffer)
1319         (delete-window)
1320         (select-window (get-buffer-window cur-buf))))
1321      (t
1322       (setq wl-folder-buffer-disp-summary
1323             (not wl-folder-buffer-disp-summary))
1324       (let ((cur-buf (current-buffer))
1325             folder-name)
1326         (when (looking-at "^[ ]*\\([^\\[].+\\):.*\n")
1327           (setq folder-name (wl-folder-get-entity-from-buffer))
1328           (if wl-folder-buffer-disp-summary
1329               (progn
1330                 (wl-folder-select-buffer
1331                  (wl-summary-get-buffer-create folder-name))
1332                 (unwind-protect
1333                     (wl-summary-goto-folder-subr folder-name 'no-sync nil)
1334                   (select-window (get-buffer-window cur-buf))))
1335             (wl-folder-select-buffer (wl-summary-get-buffer folder-name))
1336             (delete-window)
1337             (select-window (get-buffer-window cur-buf)))))))))
1338
1339 (defun wl-folder-prev-unsync ()
1340   "Move cursor to the previous unsync folder."
1341   (interactive)
1342   (let (start-point)
1343     (setq start-point (point))
1344     (beginning-of-line)
1345     (if (re-search-backward wl-folder-unsync-regexp nil t)
1346         (beginning-of-line)
1347       (goto-char start-point)
1348       (message "No more unsync folder"))))
1349
1350 (defun wl-folder-next-unsync (&optional plugged)
1351   "Move cursor to the next unsync."
1352   (interactive)
1353   (let (start-point entity)
1354     (setq start-point (point))
1355     (end-of-line)
1356     (if (catch 'found
1357           (while (re-search-forward wl-folder-unsync-regexp nil t)
1358             (if (or (wl-folder-buffer-group-p)
1359                     (not plugged)
1360                     (setq entity
1361                           (wl-folder-get-realname
1362                            (wl-folder-folder-name)))
1363                     (elmo-folder-plugged-p entity))
1364                 (throw 'found t))))
1365         (beginning-of-line)
1366       (goto-char start-point)
1367       (message "No more unsync folder"))))
1368
1369 (defun wl-folder-prev-unread (&optional group)
1370   "Move cursor to the previous unread folder."
1371   (interactive "P")
1372   (let (start-point)
1373     (setq start-point (point))
1374     (beginning-of-line)
1375     (if (re-search-backward (wl-folder-unread-regex group) nil t)
1376         (progn
1377           (beginning-of-line)
1378           (wl-folder-folder-name))
1379       (goto-char start-point)
1380       (message "No more unread folder")
1381       nil)))
1382
1383 (defun wl-folder-next-unread (&optional group)
1384   "Move cursor to the next unread folder."
1385   (interactive "P")
1386   (let (start-point)
1387     (setq start-point (point))
1388     (end-of-line)
1389     (if (re-search-forward (wl-folder-unread-regex group) nil t)
1390         (progn
1391           (beginning-of-line)
1392           (wl-folder-folder-name))
1393       (goto-char start-point)
1394       (message "No more unread folder")
1395       nil)))
1396
1397 (defun wl-folder-mode ()
1398   "Major mode for Wanderlust Folder.
1399 See Info under Wanderlust for full documentation.
1400
1401 Special commands:
1402 \\{wl-folder-mode-map}
1403
1404 Entering Folder mode calls the value of `wl-folder-mode-hook'."
1405   (interactive)
1406   (setq major-mode 'wl-folder-mode)
1407   (setq mode-name "Folder")
1408   (use-local-map wl-folder-mode-map)
1409   (setq buffer-read-only t)
1410   (setq inhibit-read-only nil)
1411   (setq truncate-lines t)
1412   (setq wl-folder-buffer-cur-entity-id nil
1413         wl-folder-buffer-cur-path nil
1414         wl-folder-buffer-cur-point nil)
1415   (wl-mode-line-buffer-identification)
1416   (easy-menu-add wl-folder-mode-menu)
1417   ;; This hook may contain the functions `wl-folder-init-icons' and
1418   ;; `wl-setup-folder' for reasons of system internal to accord
1419   ;; facilities for the Emacs variants.
1420   (run-hooks 'wl-folder-mode-hook))
1421
1422 (defun wl-folder-append-petname (realname petname)
1423   (let (pentry)
1424     ;; check group name.
1425     (if (wl-folder-search-group-entity-by-name petname wl-folder-entity)
1426         (error "%s already defined as group name" petname))
1427     (when (setq pentry (wl-string-assoc realname wl-folder-petname-alist))
1428       (setq wl-folder-petname-alist
1429             (delete pentry wl-folder-petname-alist)))
1430     (wl-append wl-folder-petname-alist
1431                (list (cons realname petname)))))
1432
1433 (defun wl-folder (&optional arg)
1434   (interactive "P")
1435   (let (initialize)
1436 ;;; (delete-other-windows)
1437     (if (get-buffer wl-folder-buffer-name)
1438         (switch-to-buffer  wl-folder-buffer-name)
1439       (switch-to-buffer (get-buffer-create wl-folder-buffer-name))
1440       (wl-folder-mode)
1441       (wl-folder-init)
1442       (set-buffer wl-folder-buffer-name)
1443       (let ((inhibit-read-only t)
1444             (buffer-read-only nil))
1445         (erase-buffer)
1446         (setcdr (assoc (car wl-folder-entity) wl-folder-group-alist) t)
1447         (save-excursion
1448           (wl-folder-insert-entity " " wl-folder-entity)))
1449       (set-buffer-modified-p nil)
1450       ;(sit-for 0)
1451       (setq initialize t))
1452     initialize))
1453
1454 (defun wl-folder-auto-check ()
1455   "Check and update folders in `wl-auto-check-folder-name'."
1456   (interactive)
1457   (when (get-buffer wl-folder-buffer-name)
1458     (switch-to-buffer  wl-folder-buffer-name)
1459     (cond
1460      ((eq wl-auto-check-folder-name 'none))
1461      ((or (consp wl-auto-check-folder-name)
1462           (stringp wl-auto-check-folder-name))
1463       (let ((folder-list (if (consp wl-auto-check-folder-name)
1464                              wl-auto-check-folder-name
1465                            (list wl-auto-check-folder-name)))
1466             entity)
1467         (while folder-list
1468           (if (setq entity (wl-folder-search-entity-by-name
1469                             (car folder-list)
1470                             wl-folder-entity))
1471               (wl-folder-check-entity entity 'auto))
1472           (setq folder-list (cdr folder-list)))))
1473      (t
1474       (wl-folder-check-entity wl-folder-entity 'auto)))))
1475
1476 (defun wl-folder-set-folder-updated (name value)
1477   (save-excursion
1478     (let (buf)
1479       (if (setq buf (get-buffer wl-folder-buffer-name))
1480           (wl-folder-entity-hashtb-set
1481            wl-folder-entity-hashtb name value buf))
1482 ;;;   (elmo-folder-set-info-hashtb (elmo-string name)
1483 ;;;                                nil
1484 ;;;                                (nth 2 value)
1485 ;;;                                (nth 0 value)
1486 ;;;                                (nth 1 value))
1487       (setq wl-folder-info-alist-modified t))))
1488
1489 (defun wl-folder-calc-finfo (entity)
1490   ;; calcurate finfo without inserting.
1491   (let ((entities (list entity))
1492         entity-stack
1493         new unread all nums)
1494     (while entities
1495       (setq entity (wl-pop entities))
1496       (cond
1497        ((consp entity)
1498         (and entities
1499              (wl-push entities entity-stack))
1500         (setq entities (nth 2 entity)))
1501        ((stringp entity)
1502         (setq nums (wl-folder-get-entity-info entity))
1503         (setq new    (+ (or new 0) (or (nth 0 nums) 0)))
1504         (setq unread (+ (or unread 0)
1505                         (or (and (nth 0 nums)(nth 1 nums)
1506                                  (+ (nth 0 nums)(nth 1 nums))) 0)))
1507         (setq all    (+ (or all 0) (or (nth 2 nums) 0)))))
1508       (unless entities
1509         (setq entities (wl-pop entity-stack))))
1510     (list new unread all)))
1511
1512 (defsubst wl-folder-make-save-access-list (list)
1513   (mapcar '(lambda (x)
1514              (cond
1515               ((consp x)
1516                (list (elmo-string (car x)) 'access))
1517               (t
1518                (elmo-string x))))
1519           list))
1520
1521 (defun wl-folder-update-newest (indent entity)
1522   (let (ret-val new unread all)
1523     (cond
1524      ((consp entity)
1525       (let ((inhibit-read-only t)
1526             (buffer-read-only nil)
1527             (flist (nth 2 entity))
1528             (as-opened (cdr (assoc (car entity) wl-folder-group-alist)))
1529             beg
1530             )
1531         (setq beg (point))
1532         (if as-opened
1533             (let (update-flist flist-unsub new-flist removed group-name-end)
1534               (when (and (eq (cadr entity) 'access)
1535                          (elmo-folder-plugged-p (car entity)))
1536                 (message "Fetching folder entries...")
1537                 (when (setq new-flist
1538                             (elmo-list-folders
1539                              (elmo-string (car entity))
1540                              (wl-string-member
1541                               (car entity)
1542                               wl-folder-hierarchy-access-folders)))
1543                   (setq update-flist
1544                         (wl-folder-update-access-group entity new-flist))
1545                   (setq flist (nth 1 update-flist))
1546                   (when (car update-flist) ;; diff
1547                     (setq flist-unsub (nth 2 update-flist))
1548                     (setq removed (nth 3 update-flist))
1549                     (elmo-msgdb-flist-save
1550                      (car entity)
1551                      (list
1552                       (wl-folder-make-save-access-list flist)
1553                       (wl-folder-make-save-access-list flist-unsub)))
1554                     (wl-folder-entity-assign-id
1555                      entity
1556                      wl-folder-entity-id-name-hashtb
1557                      t)
1558                     (setq wl-folder-entity-hashtb
1559                           (wl-folder-create-entity-hashtb
1560                            entity
1561                            wl-folder-entity-hashtb
1562                            t))
1563                     (setq wl-folder-newsgroups-hashtb
1564                           (or
1565                            (wl-folder-create-newsgroups-hashtb
1566                             entity nil)
1567                            wl-folder-newsgroups-hashtb))))
1568                 (message "Fetching folder entries...done"))
1569               (wl-folder-insert-entity indent entity))))))))
1570
1571 (defun wl-folder-insert-entity (indent entity &optional onlygroup)
1572   (let (ret-val new unread all)
1573     (cond
1574      ((consp entity)
1575       (let ((inhibit-read-only t)
1576             (buffer-read-only nil)
1577             (flist (nth 2 entity))
1578             (as-opened (cdr (assoc (car entity) wl-folder-group-alist)))
1579             beg
1580             )
1581 ;;;     (insert indent "[" (if as-opened "-" "+") "]" (car entity) "\n")
1582 ;;;     (save-excursion (forward-line -1)
1583 ;;;                     (wl-highlight-folder-current-line))
1584         (setq beg (point))
1585         (if (and as-opened
1586                  (not onlygroup))
1587             (let (update-flist flist-unsub new-flist removed group-name-end)
1588 ;;;           (when (and (eq (cadr entity) 'access)
1589 ;;;                      newest)
1590 ;;;             (message "fetching folder entries...")
1591 ;;;             (when (setq new-flist
1592 ;;;                         (elmo-list-folders
1593 ;;;                          (elmo-string (car entity))
1594 ;;;                          (wl-string-member
1595 ;;;                           (car entity)
1596 ;;;                           wl-folder-hierarchy-access-folders)
1597 ;;;                          ))
1598 ;;;               (setq update-flist
1599 ;;;                     (wl-folder-update-access-group entity new-flist))
1600 ;;;               (setq flist (nth 1 update-flist))
1601 ;;;               (when (car update-flist) ;; diff
1602 ;;;                 (setq flist-unsub (nth 2 update-flist))
1603 ;;;                 (setq removed (nth 3 update-flist))
1604 ;;;                 (elmo-msgdb-flist-save
1605 ;;;                  (car entity)
1606 ;;;                  (list
1607 ;;;                   (wl-folder-make-save-access-list flist)
1608 ;;;                   (wl-folder-make-save-access-list flist-unsub)))
1609 ;;;                 ;;
1610 ;;;                 ;; reconstruct wl-folder-entity-id-name-hashtb and
1611 ;;;                 ;;           wl-folder-entity-hashtb
1612 ;;;                 ;;
1613 ;;;                 (wl-folder-entity-assign-id
1614 ;;;                  entity
1615 ;;;                  wl-folder-entity-id-name-hashtb
1616 ;;;                  t)
1617 ;;;                 (setq wl-folder-entity-hashtb
1618 ;;;                       (wl-folder-create-entity-hashtb
1619 ;;;                        entity
1620 ;;;                        wl-folder-entity-hashtb
1621 ;;;                        t))
1622 ;;;                 (setq wl-folder-newsgroups-hashtb
1623 ;;;                       (or
1624 ;;;                        (wl-folder-create-newsgroups-hashtb
1625 ;;;                         entity nil)
1626 ;;;                        wl-folder-newsgroups-hashtb))))
1627 ;;;             (message "fetching folder entries...done"))
1628               (insert indent "[" (if as-opened "-" "+") "]"
1629                       (wl-folder-get-petname (car entity)))
1630               (setq group-name-end (point))
1631               (insert ":0/0/0\n")
1632               (put-text-property beg (point) 'wl-folder-entity-id
1633                                  (get-text-property 0 'wl-folder-entity-id
1634                                                     (car entity)))
1635               (when removed
1636                 (setq beg (point))
1637                 (while removed
1638                   (insert indent "  "
1639                           wl-folder-removed-mark
1640                           (if (listp (car removed))
1641                               (concat "[+]" (caar removed))
1642                             (car removed))
1643                           "\n")
1644                   (save-excursion (forward-line -1)
1645                                   (wl-highlight-folder-current-line))
1646                   (setq removed (cdr removed)))
1647                 (remove-text-properties beg (point) '(wl-folder-entity-id)))
1648               (let* ((len (length flist))
1649                      (mes (> len 100))
1650                      (i 0))
1651                 (while flist
1652                   (setq ret-val
1653                         (wl-folder-insert-entity
1654                          (concat indent "  ") (car flist)))
1655                   (setq new    (+ (or new 0) (or (nth 0 ret-val) 0)))
1656                   (setq unread (+ (or unread 0) (or (nth 1 ret-val) 0)))
1657                   (setq all    (+ (or all 0) (or (nth 2 ret-val) 0)))
1658                   (when (and mes
1659                              (> len elmo-display-progress-threshold))
1660                     (setq i (1+ i))
1661                     (elmo-display-progress
1662                      'wl-folder-insert-entity "Inserting group %s..."
1663                      (/ (* i 100) len) (car entity)))
1664                   (setq flist (cdr flist))))
1665               (save-excursion
1666                 (goto-char group-name-end)
1667                 (delete-region (point) (save-excursion (end-of-line)
1668                                                        (point)))
1669                 (insert (format ":%d/%d/%d" (or new 0)
1670                                 (or unread 0) (or all 0)))
1671                 (setq ret-val (list new unread all))
1672                 (wl-highlight-folder-current-line ret-val)))
1673           (setq ret-val (wl-folder-calc-finfo entity))
1674           (insert indent "[" (if as-opened "-" "+") "]"
1675                   (wl-folder-get-petname (car entity))
1676                   (format ":%d/%d/%d"
1677                           (or (nth 0 ret-val) 0)
1678                           (or (nth 1 ret-val) 0)
1679                           (or (nth 2 ret-val) 0))
1680                   "\n")
1681           (put-text-property beg (point) 'wl-folder-entity-id
1682                              (get-text-property 0 'wl-folder-entity-id
1683                                                 (car entity)))
1684           (save-excursion (forward-line -1)
1685                           (wl-highlight-folder-current-line ret-val)))))
1686      ((stringp entity)
1687       (let* ((inhibit-read-only t)
1688              (buffer-read-only nil)
1689              (nums (wl-folder-get-entity-info entity))
1690              beg)
1691         (setq beg (point))
1692         (insert indent (wl-folder-get-petname entity)
1693                 (format ":%s/%s/%s\n"
1694                         (or (setq new (nth 0 nums)) "*")
1695                         (or (setq unread (and (nth 0 nums)(nth 1 nums)
1696                                               (+ (nth 0 nums)(nth 1 nums))))
1697                             "*")
1698                         (or (setq all (nth 2 nums)) "*")))
1699         (put-text-property beg (point) 'wl-folder-entity-id
1700                            (get-text-property 0 'wl-folder-entity-id entity))
1701         (save-excursion (forward-line -1)
1702                         (wl-highlight-folder-current-line nums))
1703         (setq ret-val (list new unread all)))))
1704     (set-buffer-modified-p nil)
1705     ret-val))
1706
1707 (defun wl-folder-check-all ()
1708   (interactive)
1709   (wl-folder-check-entity wl-folder-entity))
1710
1711 (defun wl-folder-entity-hashtb-set (entity-hashtb name value buffer)
1712   (let (cur-val
1713         (new-diff 0)
1714         (unread-diff 0)
1715         (all-diff 0)
1716         diffs
1717         entity-list)
1718     (setq cur-val (wl-folder-get-entity-info name entity-hashtb))
1719     (setq new-diff    (- (or (nth 0 value) 0) (or (nth 0 cur-val) 0)))
1720     (setq unread-diff
1721           (+ new-diff
1722              (- (or (nth 1 value) 0) (or (nth 1 cur-val) 0))))
1723     (setq all-diff    (- (or (nth 2 value) 0) (or (nth 2 cur-val) 0)))
1724     (setq diffs (list new-diff unread-diff all-diff))
1725     (unless (and (nth 0 cur-val)
1726                  (equal diffs '(0 0 0)))
1727       (wl-folder-set-entity-info name value entity-hashtb)
1728       (save-match-data
1729         (save-excursion
1730           (set-buffer buffer)
1731           (setq entity-list (wl-folder-search-entity-list-by-name
1732                              name wl-folder-entity))
1733           (while entity-list
1734             (wl-folder-update-group (car entity-list) diffs)
1735             (setq entity-list (cdr entity-list)))
1736           (goto-char (point-min))
1737           (while (wl-folder-buffer-search-entity name)
1738             (wl-folder-update-line value)))))))
1739
1740 (defun wl-folder-update-unread (folder unread)
1741   (save-window-excursion
1742     (let ((buf (get-buffer wl-folder-buffer-name))
1743           cur-unread
1744           (unread-diff 0)
1745           ;;(fld (elmo-string folder))
1746           value newvalue entity-list)
1747 ;;; Update folder-info
1748 ;;;    (elmo-folder-set-info-hashtb fld nil nil nil unread)
1749       (setq cur-unread (or (nth 1 (wl-folder-get-entity-info folder)) 0))
1750       (setq unread-diff (- (or unread 0) cur-unread))
1751       (setq value (wl-folder-get-entity-info folder))
1752
1753       (setq newvalue (list (nth 0 value)
1754                            unread
1755                            (nth 2 value)))
1756       (wl-folder-set-entity-info folder newvalue)
1757       (setq wl-folder-info-alist-modified t)
1758       (when (and buf
1759                  (not (eq unread-diff 0)))
1760         (save-match-data
1761           (save-excursion
1762             (set-buffer buf)
1763             (save-excursion
1764               (setq entity-list (wl-folder-search-entity-list-by-name
1765                                  folder wl-folder-entity))
1766               (while entity-list
1767                 (wl-folder-update-group (car entity-list) (list 0
1768                                                                 unread-diff
1769                                                                 0))
1770                 (setq entity-list (cdr entity-list)))
1771               (goto-char (point-min))
1772               (while (wl-folder-buffer-search-entity folder)
1773                 (wl-folder-update-line newvalue)))))))))
1774
1775 (defun wl-folder-create-entity-hashtb (entity &optional hashtb reconst)
1776   (let ((hashtb (or hashtb (elmo-make-hash wl-folder-entity-id)))
1777         (entities (list entity))
1778         entity-stack)
1779     (while entities
1780       (setq entity (wl-pop entities))
1781       (cond
1782        ((consp entity)
1783         (and entities
1784              (wl-push entities entity-stack))
1785         (setq entities (nth 2 entity)))
1786        ((stringp entity)
1787         (when (not (and reconst
1788                         (wl-folder-get-entity-info entity)))
1789           (wl-folder-set-entity-info entity
1790                                      nil
1791                                      hashtb))))
1792       (unless entities
1793         (setq entities (wl-pop entity-stack))))
1794     hashtb))
1795
1796 ;; Unsync number is reserved.
1797 ;;(defun wl-folder-reconstruct-entity-hashtb (entity &optional hashtb id-name)
1798 ;;  (let* ((hashtb (or hashtb (elmo-make-hash wl-folder-entity-id)))
1799 ;;       (entities (list entity))
1800 ;;       entity-stack)
1801 ;;    (while entities
1802 ;;      (setq entity (wl-pop entities))
1803 ;;      (cond
1804 ;;       ((consp entity)
1805 ;;      (if id-name
1806 ;;          (wl-folder-set-id-name (wl-folder-get-entity-id (car entity))
1807 ;;                                 (car entity)))
1808 ;;      (and entities
1809 ;;           (wl-push entities entity-stack))
1810 ;;      (setq entities (nth 2 entity))
1811 ;;      )
1812 ;;       ((stringp entity)
1813 ;;      (wl-folder-set-entity-info entity
1814 ;;                                 (wl-folder-get-entity-info entity)
1815 ;;                                 hashtb)
1816 ;;      (if id-name
1817 ;;          (wl-folder-set-id-name (wl-folder-get-entity-id entity)
1818 ;;                                 entity))))
1819 ;;      (unless entities
1820 ;;      (setq entities (wl-pop entity-stack))))
1821 ;;    hashtb))
1822
1823 (defun wl-folder-create-newsgroups-from-nntp-access2 (entity)
1824   (let ((flist (nth 2 entity))
1825         folders)
1826     (and
1827      (setq folders
1828            (delq
1829             nil
1830             (mapcar
1831              '(lambda (fld)
1832                 (if (consp fld)
1833                     (wl-folder-create-newsgroups-from-nntp-access2 fld)
1834                   (nth 1 (elmo-folder-get-spec fld))))
1835              flist)))
1836      (elmo-nntp-make-groups-hashtb folders 1024))
1837     nil))
1838
1839 (defun wl-folder-create-newsgroups-from-nntp-access (entity)
1840   (let ((flist (nth 2 entity))
1841         folders)
1842     (while flist
1843       (wl-append folders
1844                  (cond
1845                   ((consp (car flist))
1846                    (wl-folder-create-newsgroups-from-nntp-access (car flist)))
1847                   (t
1848                    (list (nth 1 (elmo-folder-get-spec (car flist)))))))
1849       (setq flist (cdr flist)))
1850     folders))
1851
1852 (defun wl-folder-create-newsgroups-hashtb (entity &optional is-list info)
1853   (let ((entities (if is-list entity (list entity)))
1854         entity-stack spec-list folders fld make-hashtb)
1855     (and info (message "Creating newsgroups..."))
1856     (while entities
1857       (setq entity (wl-pop entities))
1858       (cond
1859        ((consp entity)
1860         (if (eq (nth 1 entity) 'access)
1861             (when (eq (elmo-folder-get-type (car entity)) 'nntp)
1862               (wl-append folders
1863                          (wl-folder-create-newsgroups-from-nntp-access entity))
1864               (setq make-hashtb t))
1865           (and entities
1866                (wl-push entities entity-stack))
1867           (setq entities (nth 2 entity))))
1868        ((stringp entity)
1869         (setq spec-list (elmo-folder-get-primitive-spec-list entity))
1870         (while spec-list
1871           (when (and (eq (caar spec-list) 'nntp)
1872                      (setq fld (nth 1 (car spec-list))))
1873             (wl-append folders (list (elmo-string fld))))
1874           (setq spec-list (cdr spec-list)))))
1875       (unless entities
1876         (setq entities (wl-pop entity-stack))))
1877     (and info (message "Creating newsgroups...done"))
1878     (if (or folders make-hashtb)
1879         (elmo-nntp-make-groups-hashtb folders))))
1880
1881 (defun wl-folder-get-path (entity target-id &optional string)
1882   (let ((entities (list entity))
1883         entity-stack result-path)
1884     (reverse
1885      (catch 'done
1886        (while entities
1887          (setq entity (wl-pop entities))
1888          (cond
1889           ((consp entity)
1890            (if (and (or (not string) (string= string (car entity)))
1891                     ;; don't use eq, `id' is string on Nemacs.
1892                     (equal target-id (wl-folder-get-entity-id (car entity))))
1893                (throw 'done
1894                       (wl-push target-id result-path))
1895              (wl-push (wl-folder-get-entity-id (car entity)) result-path))
1896            (wl-push entities entity-stack)
1897            (setq entities (nth 2 entity)))
1898           ((stringp entity)
1899            (if (and (or (not string) (string= string entity))
1900                     ;; don't use eq, `id' is string on Nemacs.
1901                     (equal target-id (wl-folder-get-entity-id entity)))
1902                (throw 'done
1903                       (wl-push target-id result-path)))))
1904          (unless entities
1905            (while (and entity-stack
1906                        (not entities))
1907              (setq result-path (cdr result-path))
1908              (setq entities (wl-pop entity-stack)))))))))
1909
1910 (defun wl-folder-create-group-alist (entity)
1911   (if (consp entity)
1912       (let ((flist (nth 2 entity))
1913             (cur-alist (list (cons (car entity) nil)))
1914              append-alist)
1915         (while flist
1916           (if (consp (car flist))
1917               (wl-append append-alist
1918                          (wl-folder-create-group-alist (car flist))))
1919           (setq flist (cdr flist)))
1920         (append cur-alist append-alist))))
1921
1922 (defun wl-folder-init-info-hashtb ()
1923   (let ((info-alist (and wl-folder-info-save
1924                          (elmo-msgdb-finfo-load))))
1925     (elmo-folder-info-make-hashtb
1926      info-alist
1927      wl-folder-entity-hashtb)))
1928 ;;; (wl-folder-resume-entity-hashtb-by-finfo
1929 ;;;  wl-folder-entity-hashtb
1930 ;;;  info-alist)))
1931
1932 (defun wl-folder-cleanup-variables ()
1933   (setq wl-folder-entity nil
1934         wl-folder-entity-hashtb nil
1935         wl-folder-entity-id-name-hashtb nil
1936         wl-folder-group-alist nil
1937         wl-folder-petname-alist nil
1938         wl-folder-newsgroups-hashtb nil
1939         wl-fldmgr-cut-entity-list nil
1940         wl-fldmgr-modified nil
1941         wl-fldmgr-modified-access-list nil
1942         wl-score-cache nil
1943         ))
1944
1945 (defun wl-make-plugged-alist ()
1946   (let ((entity-list (wl-folder-get-entity-list wl-folder-entity))
1947         (add (not wl-reset-plugged-alist)))
1948     (while entity-list
1949       (elmo-folder-set-plugged
1950        (elmo-string (car entity-list)) wl-plugged add)
1951       (setq entity-list (cdr entity-list)))
1952     ;; smtp posting server
1953     (when wl-smtp-posting-server
1954       (elmo-set-plugged wl-plugged
1955                         wl-smtp-posting-server  ; server
1956                         (or (and (boundp 'smtp-service) smtp-service)
1957                             "smtp")     ; port
1958                         nil nil "smtp" add))
1959     ;; nntp posting server
1960     (when wl-nntp-posting-server
1961       (elmo-set-plugged wl-plugged
1962                         wl-nntp-posting-server
1963                         elmo-default-nntp-port
1964                         nil nil "nntp" add))
1965     (run-hooks 'wl-make-plugged-hook)))
1966
1967 (defvar wl-folder-init-func 'wl-local-folder-init)
1968
1969 (defun wl-folder-init ()
1970   "Call `wl-folder-init-func' function."
1971   (interactive)
1972   (funcall wl-folder-init-func))
1973
1974 (defun wl-local-folder-init ()
1975   "Initialize local folder."
1976   (message "Initializing folder...")
1977   (save-excursion
1978     (set-buffer wl-folder-buffer-name)
1979     (let ((entity (wl-folder-create-folder-entity))
1980           (inhibit-read-only t))
1981       (setq wl-folder-entity entity)
1982       (setq wl-folder-entity-id 0)
1983       (wl-folder-entity-assign-id wl-folder-entity)
1984       (setq wl-folder-entity-hashtb
1985             (wl-folder-create-entity-hashtb entity))
1986       (setq wl-folder-group-alist
1987             (wl-folder-create-group-alist entity))
1988       (setq wl-folder-newsgroups-hashtb
1989             (wl-folder-create-newsgroups-hashtb wl-folder-entity))
1990       (wl-folder-init-info-hashtb)))
1991   (message "Initializing folder...done"))
1992
1993 (defun wl-folder-get-realname (petname)
1994   (or (car
1995        (wl-string-rassoc
1996         petname
1997         wl-folder-petname-alist))
1998       petname))
1999
2000 (defun wl-folder-get-petname (folder)
2001   (or (cdr
2002        (wl-string-assoc
2003         folder
2004         wl-folder-petname-alist))
2005       folder))
2006
2007 (defun wl-folder-get-entity-with-petname ()
2008   (let ((alist wl-folder-petname-alist)
2009         (hashtb (copy-sequence wl-folder-entity-hashtb)))
2010     (while alist
2011       (wl-folder-set-entity-info (cdar alist) nil hashtb)
2012       (setq alist (cdr alist)))
2013     hashtb))
2014
2015 (defun wl-folder-get-newsgroups (folder)
2016   "Return Newsgroups field value string for FOLDER newsgroup.
2017 If FOLDER is multi, return comma separated string (cross post)."
2018   (let ((flist (elmo-folder-get-primitive-folder-list folder)) ; multi
2019         newsgroups fld ret)
2020     (while (setq fld (car flist))
2021       (if (setq ret
2022                 (cond ((eq 'nntp (elmo-folder-get-type fld))
2023                        (nth 1 (elmo-folder-get-spec fld)))
2024                       ((eq 'localnews (elmo-folder-get-type fld))
2025                        (elmo-replace-in-string
2026                         (nth 1 (elmo-folder-get-spec fld)) "/" "\\."))))
2027           ;; append newsgroup
2028           (setq newsgroups (if (stringp newsgroups)
2029                                (concat newsgroups "," ret)
2030                              ret)))
2031       (setq flist (cdr flist)))
2032     (list nil nil newsgroups)))
2033
2034 (defun wl-folder-guess-mailing-list-by-refile-rule (folder)
2035   "Return ML address guess by FOLDER.
2036 Use `wl-subscribed-mailing-list' and `wl-refile-rule-alist'.
2037 Don't care multi."
2038   (setq folder (car (elmo-folder-get-primitive-folder-list folder)))
2039   (unless (memq (elmo-folder-get-type folder)
2040                 '(localnews nntp))
2041     (let ((rules wl-refile-rule-alist)
2042           mladdress tokey toalist histkey)
2043       (while rules
2044         (if (or (and (stringp (car (car rules)))
2045                      (string-match "[Tt]o" (car (car rules))))
2046                 (and (listp (car (car rules)))
2047                      (elmo-string-matched-member "to" (car (car rules))
2048                                                  'case-ignore)))
2049             (setq toalist (append toalist (cdr (car rules)))))
2050         (setq rules (cdr rules)))
2051       (setq tokey (car (rassoc folder toalist)))
2052 ;;;     (setq histkey (car (rassoc folder wl-refile-alist)))
2053       ;; case-ignore search `wl-subscribed-mailing-list'
2054       (if (stringp tokey)
2055           (list
2056            (elmo-string-matched-member tokey wl-subscribed-mailing-list t)
2057            nil nil)
2058         nil))))
2059
2060 (defun wl-folder-guess-mailing-list-by-folder-name (folder)
2061   "Return ML address guess by FOLDER name's last hierarchy.
2062 Use `wl-subscribed-mailing-list'."
2063   (setq folder (car (elmo-folder-get-primitive-folder-list folder)))
2064   (when (memq (elmo-folder-get-type folder)
2065               '(localdir imap4 maildir))
2066     (let (key mladdress)
2067       (setq folder                      ; make folder name simple
2068             (if (eq 'imap4 (elmo-folder-get-type folder))
2069                 (elmo-imap4-spec-mailbox (elmo-imap4-get-spec folder))
2070               (substring folder 1)))
2071       (when (string-match "[^\\./]+$" folder) ; last hierarchy
2072         (setq key (regexp-quote
2073                    (concat (substring folder (match-beginning 0)) "@")))
2074         (setq mladdress
2075               (elmo-string-matched-member
2076                key wl-subscribed-mailing-list 'case-ignore))
2077         (if (stringp mladdress)
2078             (list mladdress nil nil)
2079           nil)))))
2080
2081 (defun wl-folder-update-diff-line (diffs)
2082   (let ((inhibit-read-only t)
2083         (buffer-read-only nil)
2084         cur-new new-new
2085         cur-unread new-unread
2086         cur-all new-all
2087         id)
2088     (save-excursion
2089       (beginning-of-line)
2090       (setq id (get-text-property (point) 'wl-folder-entity-id))
2091       (when (looking-at "^[ ]*\\(.*\\):\\([0-9\\*-]*\\)/\\([0-9\\*-]*\\)/\\([0-9\\*]*\\)")
2092         ;;(looking-at "^[ ]*\\([^\\[].+\\):\\([0-9\\*-]*/[0-9\\*-]*/[0-9\\*]*\\)")
2093         (setq cur-new (string-to-int
2094                        (wl-match-buffer 2)))
2095         (setq cur-unread (string-to-int
2096                           (wl-match-buffer 3)))
2097         (setq cur-all (string-to-int
2098                        (wl-match-buffer 4)))
2099         (delete-region (match-beginning 2)
2100                        (match-end 4))
2101         (goto-char (match-beginning 2))
2102         (insert (format "%s/%s/%s"
2103                         (setq new-new (+ cur-new (nth 0 diffs)))
2104                         (setq new-unread (+ cur-unread (nth 1 diffs)))
2105                         (setq new-all (+ cur-all (nth 2 diffs)))))
2106         (put-text-property (match-beginning 2) (point)
2107                            'wl-folder-entity-id id)
2108         (if wl-use-highlight-mouse-line
2109             (put-text-property (match-beginning 2) (point)
2110                                'mouse-face 'highlight))
2111         (wl-highlight-folder-group-line (list new-new new-unread new-all))
2112         (setq buffer-read-only t)
2113         (set-buffer-modified-p nil)))))
2114
2115 (defun wl-folder-update-line (nums &optional is-group)
2116   (let ((inhibit-read-only t)
2117         (buffer-read-only nil)
2118         id)
2119     (save-excursion
2120       (beginning-of-line)
2121       (setq id (get-text-property (point) 'wl-folder-entity-id))
2122       (if (looking-at "^[ ]*\\(.*\\):\\([0-9\\*-]*/[0-9\\*-]*/[0-9\\*]*\\)")
2123 ;;;       (looking-at "^[ ]*\\([^\\[].+\\):\\([0-9\\*-]*/[0-9\\*-]*/[0-9\\*]*\\)")
2124           (progn
2125             (delete-region (match-beginning 2)
2126                            (match-end 2))
2127             (goto-char (match-beginning 2))
2128             (insert (format "%s/%s/%s"
2129                             (or (nth 0 nums) "*")
2130                             (or (and (nth 0 nums)(nth 1 nums)
2131                                      (+ (nth 0 nums)(nth 1 nums)))
2132                                 "*")
2133                             (or (nth 2 nums) "*")))
2134             (put-text-property (match-beginning 2) (point)
2135                                'wl-folder-entity-id id)
2136             (if is-group
2137                 ;; update only colors
2138                 (wl-highlight-folder-group-line nums)
2139               (wl-highlight-folder-current-line nums))
2140             (set-buffer-modified-p nil))))))
2141
2142 (defun wl-folder-goto-folder (&optional arg)
2143   (interactive "P")
2144   (wl-folder-goto-folder-subr nil arg))
2145
2146 (defun wl-folder-goto-folder-subr (&optional folder sticky)
2147   (beginning-of-line)
2148   (let (summary-buf fld-name entity id error-selecting)
2149 ;;; (setq fld-name (wl-folder-get-entity-from-buffer))
2150 ;;; (if (or (null fld-name)
2151 ;;;         (assoc fld-name wl-folder-group-alist))
2152     (setq fld-name wl-default-folder)
2153     (setq fld-name (or folder
2154                        (wl-summary-read-folder fld-name)))
2155     (if (and (setq entity
2156                    (wl-folder-search-entity-by-name fld-name
2157                                                     wl-folder-entity
2158                                                     'folder))
2159              (setq id (wl-folder-get-entity-id entity)))
2160         (wl-folder-set-current-entity-id id))
2161     (setq summary-buf (wl-summary-get-buffer-create fld-name sticky))
2162     (if wl-stay-folder-window
2163         (wl-folder-select-buffer summary-buf)
2164       (if (and summary-buf
2165                (get-buffer-window summary-buf))
2166           (delete-window)))
2167     (wl-summary-goto-folder-subr fld-name
2168                                  (wl-summary-get-sync-range fld-name)
2169                                  nil sticky t)))
2170
2171 (defun wl-folder-suspend ()
2172   (interactive)
2173   (run-hooks 'wl-folder-suspend-hook)
2174   (wl-folder-info-save)
2175   (wl-crosspost-alist-save)
2176   (wl-kill-buffers
2177    (format "^\\(%s\\)$"
2178            (mapconcat 'identity
2179                       (list (format "%s\\(:.*\\)?"
2180                                     (default-value 'wl-message-buf-name))
2181                             wl-original-buf-name)
2182                       "\\|")))
2183   (if (fboundp 'mmelmo-cleanup-entity-buffers)
2184       (mmelmo-cleanup-entity-buffers))
2185   (bury-buffer wl-folder-buffer-name)
2186   (delete-windows-on wl-folder-buffer-name t))
2187
2188 (defun wl-folder-info-save ()
2189   (when (and wl-folder-info-save
2190              wl-folder-info-alist-modified)
2191     (let ((entities (list wl-folder-entity))
2192           entity entity-stack info-alist info)
2193       (while entities
2194         (setq entity (wl-pop entities))
2195         (cond
2196          ((consp entity)
2197           (and entities
2198                (wl-push entities entity-stack))
2199           (setq entities (nth 2 entity)))
2200          ((stringp entity)
2201           (when (and (setq info (elmo-folder-get-info entity))
2202                      (not (equal info '(nil))))
2203             (wl-append info-alist (list (list (elmo-string entity)
2204                                               (list (nth 3 info)  ;; max
2205                                                     (nth 2 info)  ;; length
2206                                                     (nth 0 info)  ;; new
2207                                                     (nth 1 info)) ;; unread
2208                                               ))))))
2209         (unless entities
2210           (setq entities (wl-pop entity-stack))))
2211       (elmo-msgdb-finfo-save info-alist)
2212       (setq wl-folder-info-alist-modified nil))))
2213
2214 (defun wl-folder-goto-first-unread-folder (&optional arg)
2215   (interactive "P")
2216   (let ((entities (list wl-folder-entity))
2217         entity entity-stack ret-val
2218         first-entity finfo)
2219     (setq first-entity
2220           (catch 'done
2221             (while entities
2222               (setq entity (wl-pop entities))
2223               (cond
2224                ((consp entity)
2225                 (and entities
2226                      (wl-push entities entity-stack))
2227                 (setq entities (nth 2 entity)))
2228                ((stringp entity)
2229                 (if (and (setq finfo (wl-folder-get-entity-info entity))
2230                          (and (nth 0 finfo)(nth 1 finfo))
2231                          (> (+ (nth 0 finfo)(nth 1 finfo)) 0))
2232                     (throw 'done entity))
2233                 (wl-append ret-val (list entity))))
2234               (unless entities
2235                 (setq entities (wl-pop entity-stack))))))
2236     (if first-entity
2237         (progn
2238           (when arg
2239             (wl-folder-jump-folder first-entity)
2240             (sit-for 0))
2241           (wl-folder-goto-folder-subr first-entity))
2242       (message "No unread folder"))))
2243
2244 (defun wl-folder-jump-folder (&optional fld-name noopen)
2245   (interactive)
2246   (if (not fld-name)
2247       (setq fld-name (wl-summary-read-folder wl-default-folder)))
2248   (goto-char (point-min))
2249   (if (not noopen)
2250       (wl-folder-open-folder fld-name))
2251   (and (wl-folder-buffer-search-entity fld-name)
2252        (beginning-of-line)))
2253
2254 (defun wl-folder-get-entity-list (entity)
2255   (let ((entities (list entity))
2256         entity-stack ret-val)
2257     (while entities
2258       (setq entity (wl-pop entities))
2259       (cond
2260        ((consp entity)
2261         (and entities
2262              (wl-push entities entity-stack))
2263         (setq entities (nth 2 entity)))
2264        ((stringp entity)
2265         (wl-append ret-val (list entity))))
2266       (unless entities
2267         (setq entities (wl-pop entity-stack))))
2268     ret-val))
2269
2270 (defun wl-folder-open-unread-folder (entity)
2271   (save-excursion
2272     (let ((alist (wl-folder-get-entity-list entity))
2273           (unread 0)
2274           finfo path-list path id)
2275       (while alist
2276         (when (and (setq finfo (wl-folder-get-entity-info (car alist)))
2277                    (nth 0 finfo) (nth 1 finfo)
2278                    (> (+ (nth 0 finfo)(nth 1 finfo)) 0))
2279           (setq unread (+ unread (+ (nth 0 finfo)(nth 1 finfo))))
2280           (setq id (wl-folder-get-entity-id (car alist)))
2281           (setq path (delete id (wl-folder-get-path
2282                                  wl-folder-entity
2283                                  id
2284                                  (car alist))))
2285           (if (not (member path path-list))
2286               (wl-append path-list (list path))))
2287         (setq alist (cdr alist)))
2288       (while path-list
2289         (wl-folder-open-folder-sub (car path-list))
2290         (setq path-list (cdr path-list)))
2291       (message "%s unread folder"
2292                (if (> unread 0) unread "No")))))
2293
2294 (defun wl-folder-open-unread-current-entity ()
2295   (interactive)
2296   (let ((entity-name (wl-folder-get-entity-from-buffer))
2297         (group (wl-folder-buffer-group-p)))
2298     (when entity-name
2299       (wl-folder-open-unread-folder
2300        (if group
2301            (wl-folder-search-group-entity-by-name entity-name
2302                                                   wl-folder-entity)
2303          entity-name)))))
2304
2305 (defun wl-folder-open-only-unread-folder ()
2306   (interactive)
2307   (let ((id (progn
2308               (wl-folder-prev-entity-skip-invalid t)
2309               (wl-folder-get-entity-from-buffer t))))
2310     (wl-folder-open-all-unread-folder)
2311     (save-excursion
2312       (goto-char (point-max))
2313       (while (and (re-search-backward
2314                    "^[ ]*\\[[-]\\].+:0/0/[0-9-]+" nil t)
2315                   (not (bobp)))
2316         (wl-folder-jump-to-current-entity) ;; close it
2317         ))
2318     (wl-folder-move-path id)
2319     (recenter)))
2320
2321 (defun wl-folder-open-all-unread-folder (&optional arg)
2322   (interactive "P")
2323   (let ((id (progn
2324               (wl-folder-prev-entity-skip-invalid t)
2325               (wl-folder-get-entity-from-buffer t))))
2326     (wl-folder-open-unread-folder wl-folder-entity)
2327     (if (not arg)
2328         (wl-folder-move-path id)
2329       (goto-char (point-min))
2330       (wl-folder-next-unread t))))
2331
2332 (defun wl-folder-open-folder (&optional fld-name)
2333   (interactive)
2334   (if (not fld-name)
2335       (setq fld-name (wl-summary-read-folder wl-default-folder)))
2336   (let* ((id (wl-folder-get-entity-id
2337               (wl-folder-search-entity-by-name fld-name wl-folder-entity
2338                                                'folder)))
2339          (path (and id (wl-folder-get-path wl-folder-entity id))))
2340       (if path
2341           (wl-folder-open-folder-sub path))))
2342
2343 (defun wl-folder-open-folder-sub (path)
2344   (let ((inhibit-read-only t)
2345         (buffer-read-only nil)
2346         indent name entity
2347         err)
2348     (save-excursion
2349       (goto-char (point-min))
2350       (while (and path
2351                   (wl-folder-buffer-search-group
2352                    (wl-folder-get-petname
2353                     (if (stringp (car path))
2354                         (car path)
2355                       (wl-folder-get-folder-name-by-id
2356                        (car path))))))
2357         (beginning-of-line)
2358         (setq path (cdr path))
2359         (if (and (looking-at wl-folder-group-regexp)
2360                  (string= "+" (wl-match-buffer 2)));; closed group
2361             (save-excursion
2362               (setq indent (wl-match-buffer 1))
2363               (setq name (wl-folder-get-realname (wl-match-buffer 3)))
2364               (setq entity (wl-folder-search-group-entity-by-name
2365                             name
2366                             wl-folder-entity))
2367               ;; insert as opened
2368               (setcdr (assoc (car entity) wl-folder-group-alist) t)
2369               (if (eq 'access (cadr entity))
2370                   (wl-folder-maybe-load-folder-list entity))
2371               (wl-folder-insert-entity indent entity)
2372               (delete-region (save-excursion (beginning-of-line)
2373                                              (point))
2374                              (save-excursion (end-of-line)
2375                                              (+ 1 (point)))))))
2376       (set-buffer-modified-p nil))))
2377
2378 (defun wl-folder-open-all-pre ()
2379   (let ((entities (list wl-folder-entity))
2380         entity entity-stack group-entry)
2381     (while entities
2382       (setq entity (wl-pop entities))
2383       (cond
2384        ((consp entity)
2385         (unless (or (not (setq group-entry
2386                                (assoc (car entity) wl-folder-group-alist)))
2387                     (cdr group-entry))
2388           (setcdr group-entry t)
2389           (when (eq 'access (cadr entity))
2390             (wl-folder-maybe-load-folder-list entity)))
2391         (and entities
2392              (wl-push entities entity-stack))
2393         (setq entities (nth 2 entity))))
2394       (unless entities
2395         (setq entities (wl-pop entity-stack))))))
2396
2397 (defun wl-folder-open-all (&optional refresh)
2398   (interactive "P")
2399   (let* ((inhibit-read-only t)
2400          (buffer-read-only nil)
2401          (len (length wl-folder-group-alist))
2402          (i 0)
2403          indent name entity)
2404     (if refresh
2405         (let ((id (progn
2406                     (wl-folder-prev-entity-skip-invalid t)
2407                     (wl-folder-get-entity-from-buffer t)))
2408               (alist wl-folder-group-alist))
2409           (while alist
2410             (setcdr (pop alist) t))
2411           (erase-buffer)
2412           (wl-folder-insert-entity " " wl-folder-entity)
2413           (wl-folder-move-path id))
2414       (message "Opening all folders...")
2415       (wl-folder-open-all-pre)
2416       (save-excursion
2417         (goto-char (point-min))
2418         (while (re-search-forward
2419                 "^\\([ ]*\\)\\[\\([+]\\)\\]\\(.+\\):[-0-9-]+/[0-9-]+/[0-9-]+\n"
2420                 nil t)
2421           (setq indent (wl-match-buffer 1))
2422           (setq name (wl-folder-get-realname (wl-match-buffer 3)))
2423           (setq entity (wl-folder-search-group-entity-by-name
2424                         name
2425                         wl-folder-entity))
2426           ;; insert as opened
2427           (setcdr (assoc (car entity) wl-folder-group-alist) t)
2428           (forward-line -1)
2429           (wl-folder-insert-entity indent entity)
2430           (delete-region (save-excursion (beginning-of-line)
2431                                          (point))
2432                          (save-excursion (end-of-line)
2433                                          (+ 1 (point))))
2434           (when (> len elmo-display-progress-threshold)
2435             (setq i (1+ i))
2436             (if (or (zerop (% i 5)) (= i len))
2437                 (elmo-display-progress
2438                  'wl-folder-open-all "Opening all folders..."
2439                  (/ (* i 100) len)))))
2440         (when (> len elmo-display-progress-threshold)
2441           (elmo-display-progress
2442            'wl-folder-open-all "Opening all folders..." 100))))
2443     (message "Opening all folders...done")
2444     (set-buffer-modified-p nil)))
2445
2446 (defun wl-folder-close-all ()
2447   (interactive)
2448   (let ((inhibit-read-only t)
2449         (buffer-read-only nil)
2450         (alist wl-folder-group-alist)
2451         (id (progn
2452               (wl-folder-prev-entity-skip-invalid t)
2453               (wl-folder-get-entity-from-buffer t))))
2454     (while alist
2455       (setcdr (car alist) nil)
2456       (setq alist (cdr alist)))
2457     (setcdr (assoc (car wl-folder-entity) wl-folder-group-alist) t)
2458     (erase-buffer)
2459     (wl-folder-insert-entity " " wl-folder-entity)
2460     (wl-folder-move-path id)
2461     (recenter)
2462     (set-buffer-modified-p nil)))
2463
2464 (defun wl-folder-open-close ()
2465   "Open or close parent entity."
2466   (interactive)
2467   (save-excursion
2468     (beginning-of-line)
2469     (if (wl-folder-buffer-group-p)
2470         ;; if group (whether opend or closed.)
2471         (wl-folder-jump-to-current-entity)
2472       ;; if folder
2473       (let (indent)
2474         (setq indent (save-excursion
2475                        (re-search-forward "\\([ ]*\\)." nil t)
2476                        (wl-match-buffer 1)))
2477         (while (looking-at indent)
2478           (forward-line -1)))
2479       (wl-folder-jump-to-current-entity))))
2480
2481 (defsubst wl-folder-access-subscribe-p (group folder)
2482   (let (subscr regexp match)
2483     (if (setq subscr (wl-get-assoc-list-value
2484                       wl-folder-access-subscribe-alist
2485                       group))
2486         (progn
2487           (setq regexp (mapconcat 'identity (cdr subscr) "\\|"))
2488           (setq match (string-match regexp folder))
2489           (if (car subscr)
2490               match
2491             (not match)))
2492       t)))
2493
2494 (defun wl-folder-update-access-group (entity new-flist)
2495   (let* ((flist (nth 2 entity))
2496          (unsubscribes (nth 3 entity))
2497          (len (+ (length flist) (length unsubscribes)))
2498          (i 0)
2499          diff new-unsubscribes removes
2500          subscribed-list folder group entry)
2501     ;; check subscribed groups
2502     (while flist
2503       (cond
2504        ((listp (car flist))     ;; group
2505         (setq group (elmo-string (caar flist)))
2506         (cond
2507          ((assoc group new-flist)       ;; found in new-flist
2508           (setq new-flist (delete (assoc group new-flist)
2509                                   new-flist))
2510           (if (wl-folder-access-subscribe-p (car entity) group)
2511               (wl-append subscribed-list (list (car flist)))
2512             (wl-append new-unsubscribes (list (car flist)))
2513             (setq diff t)))
2514          (t
2515           (setq wl-folder-group-alist
2516                 (delete (wl-string-assoc group wl-folder-group-alist)
2517                         wl-folder-group-alist))
2518           (wl-append removes (list (list group))))))
2519        (t                       ;; folder
2520         (setq folder (elmo-string (car flist)))
2521         (cond
2522          ((member folder new-flist)     ;; found in new-flist
2523           (setq new-flist (delete folder new-flist))
2524           (if (wl-folder-access-subscribe-p (car entity) folder)
2525               (wl-append subscribed-list (list (car flist)))
2526             (wl-append new-unsubscribes (list folder))
2527             (setq diff t)))
2528          (t
2529           (wl-append removes (list folder))))))
2530       (when (> len elmo-display-progress-threshold)
2531         (setq i (1+ i))
2532         (if (or (zerop (% i 10)) (= i len))
2533             (elmo-display-progress
2534              'wl-folder-update-access-group "Updating access group..."
2535              (/ (* i 100) len))))
2536       (setq flist (cdr flist)))
2537     ;; check unsubscribed groups
2538     (while unsubscribes
2539       (cond
2540        ((listp (car unsubscribes))
2541         (when (setq entry (assoc (caar unsubscribes) new-flist))
2542           (setq new-flist (delete entry new-flist))
2543           (wl-append new-unsubscribes (list (car unsubscribes)))))
2544        (t
2545         (when (member (car unsubscribes) new-flist)
2546           (setq new-flist (delete (car unsubscribes) new-flist))
2547           (wl-append new-unsubscribes (list (car unsubscribes))))))
2548       (when (> len elmo-display-progress-threshold)
2549         (setq i (1+ i))
2550         (if (or (zerop (% i 10)) (= i len))
2551             (elmo-display-progress
2552              'wl-folder-update-access-group "Updating access group..."
2553              (/ (* i 100) len))))
2554       (setq unsubscribes (cdr unsubscribes)))
2555     ;;
2556     (if (or new-flist removes)
2557         (setq diff t))
2558     (setq new-flist
2559           (mapcar '(lambda (x)
2560                      (cond ((consp x) (list (car x) 'access))
2561                            (t x)))
2562                   new-flist))
2563     ;; check new groups
2564     (let ((new-list new-flist))
2565       (while new-list
2566         (if (not (wl-folder-access-subscribe-p
2567                   (car entity)
2568                   (if (listp (car new-list))
2569                       (caar new-list)
2570                     (car new-list))))
2571             ;; auto unsubscribe
2572             (progn
2573               (wl-append new-unsubscribes (list (car new-list)))
2574               (setq new-flist (delete (car new-list) new-flist)))
2575           (cond
2576            ((listp (car new-list))
2577             ;; check group exists
2578             (if (wl-string-assoc (caar new-list) wl-folder-group-alist)
2579                 (progn
2580                   (message "%s: group already exists." (caar new-list))
2581                   (sit-for 1)
2582                   (wl-append new-unsubscribes (list (car new-list)))
2583                   (setq new-flist (delete (car new-list) new-flist)))
2584               (wl-append wl-folder-group-alist
2585                          (list (cons (caar new-list) nil)))))))
2586         (setq new-list (cdr new-list))))
2587     (if new-flist
2588         (message "%d new folder(s)." (length new-flist))
2589       (message "Updating access group...done"))
2590     (wl-append new-flist subscribed-list)       ;; new is first
2591     (run-hooks 'wl-folder-update-access-group-hook)
2592     (setcdr (cdr entity) (list new-flist new-unsubscribes))
2593     (list diff new-flist new-unsubscribes removes)))
2594
2595 (defun wl-folder-prefetch-entity (entity)
2596   "Prefetch all new messages in the ENTITY."
2597   (cond
2598    ((consp entity)
2599     (let ((flist (nth 2 entity))
2600           (sum-done 0)
2601           (sum-all 0)
2602           result)
2603       (while flist
2604         (setq result (wl-folder-prefetch-entity (car flist)))
2605         (setq sum-done (+ sum-done (car result)))
2606         (setq sum-all (+ sum-all (cdr result)))
2607         (setq flist (cdr flist)))
2608       (message "Prefetched %d/%d message(s) in \"%s\"."
2609                sum-done sum-all
2610                (wl-folder-get-petname (car entity)))
2611       (cons sum-done sum-all)))
2612    ((stringp entity)
2613     (let ((nums (wl-folder-get-entity-info entity))
2614           (wl-summary-highlight (if (or (wl-summary-sticky-p entity)
2615                                         (wl-summary-always-sticky-folder-p
2616                                          entity))
2617                                     wl-summary-highlight))
2618           wl-summary-exit-next-move
2619           wl-auto-select-first ret-val
2620           count)
2621       (setq count (or (car nums) 0))
2622       (setq count (+ count (wl-folder-count-incorporates entity)))
2623       (if (or (null (car nums)) ; unknown
2624               (< 0 count))
2625           (let ((wl-summary-buffer-name (concat
2626                                          wl-summary-buffer-name
2627                                          (symbol-name this-command)))
2628                 (wl-message-buf-name (concat wl-message-buf-name
2629                                              (symbol-name this-command))))
2630             (save-window-excursion
2631               (save-excursion
2632                 (wl-summary-goto-folder-subr entity
2633                                              (wl-summary-get-sync-range entity)
2634                                              nil)
2635                 (setq ret-val (wl-summary-incorporate))
2636                 (wl-summary-exit)
2637                 ret-val)))
2638         (cons 0 0))))))
2639
2640 (defun wl-folder-count-incorporates (folder)
2641   (let ((marks (elmo-msgdb-mark-load (elmo-msgdb-expand-path folder)))
2642         (sum 0))
2643     (while marks
2644       (if (member (cadr (car marks))
2645                   wl-summary-incorporate-marks)
2646           (incf sum))
2647       (setq marks (cdr marks)))
2648     sum))
2649
2650 (defun wl-folder-prefetch-current-entity (&optional no-check)
2651   "Prefetch all uncached messages in the folder at position.
2652 If current line is group folder, all subfolders are prefetched."
2653   (interactive "P")
2654   (save-excursion
2655     (let ((entity-name (wl-folder-get-entity-from-buffer))
2656           (group (wl-folder-buffer-group-p))
2657           wl-folder-check-entity-hook
2658           summary-buf entity)
2659       (when entity-name
2660         (setq entity
2661               (if group
2662                   (wl-folder-search-group-entity-by-name entity-name
2663                                                          wl-folder-entity)
2664                 entity-name))
2665         (if (not no-check)
2666             (wl-folder-check-entity entity))
2667         (wl-folder-prefetch-entity entity)))))
2668
2669 (defun wl-folder-drop-unsync-entity (entity)
2670   "Drop all unsync messages in the ENTITY."
2671   (cond
2672    ((consp entity)
2673     (let ((flist (nth 2 entity)))
2674       (while flist
2675         (wl-folder-drop-unsync-entity (car flist))
2676         (setq flist (cdr flist)))))
2677    ((stringp entity)
2678     (let ((nums (wl-folder-get-entity-info entity))
2679           wl-summary-highlight wl-auto-select-first new)
2680       (setq new (or (car nums) 0))
2681       (if (< 0 new)
2682           (let ((wl-summary-buffer-name (concat
2683                                          wl-summary-buffer-name
2684                                          (symbol-name this-command)))
2685                 (wl-message-buf-name (concat wl-message-buf-name
2686                                              (symbol-name this-command))))
2687             (save-window-excursion
2688               (save-excursion
2689                 (wl-summary-goto-folder-subr entity 'no-sync nil)
2690                 (wl-summary-drop-unsync)
2691                 (wl-summary-exit)))))))))
2692
2693 (defun wl-folder-drop-unsync-current-entity (&optional force-check)
2694   "Drop all unsync messages in the folder at position.
2695 If current line is group folder, all subfolders are dropped.
2696 If optional arg exists, don't check any folders."
2697   (interactive "P")
2698   (save-excursion
2699     (let ((entity-name (wl-folder-get-entity-from-buffer))
2700           (group (wl-folder-buffer-group-p))
2701           wl-folder-check-entity-hook
2702           summary-buf entity)
2703       (when (and entity-name
2704                  (y-or-n-p (format
2705                             "Drop all unsync messages in %s?" entity-name)))
2706         (setq entity
2707               (if group
2708                   (wl-folder-search-group-entity-by-name entity-name
2709                                                          wl-folder-entity)
2710                 entity-name))
2711         (if (null force-check)
2712             (wl-folder-check-entity entity))
2713         (wl-folder-drop-unsync-entity entity)
2714         (message "All unsync messages in %s are dropped!" entity-name)))))
2715
2716 (defun wl-folder-write-current-folder ()
2717   "Write message to current folder's newsgroup or mailing-list.
2718 Call `wl-summary-write-current-folder' with current folder name."
2719   (interactive)
2720   (unless (wl-folder-buffer-group-p)
2721     (wl-summary-write-current-folder
2722      (wl-folder-get-realname (wl-folder-entity-name)))))
2723
2724 (defun wl-folder-mimic-kill-buffer ()
2725   "Kill the current (Folder) buffer with query."
2726   (interactive)
2727   (let ((bufname (read-buffer (format "Kill buffer: (default %s) "
2728                                       (buffer-name))))
2729         wl-interactive-exit)
2730     (if (or (not bufname)
2731             (string-equal bufname "")
2732             (string-equal bufname (buffer-name)))
2733         (wl-exit)
2734       (kill-buffer bufname))))
2735
2736 (defun wl-folder-create-subr (entity)
2737   (if (not (elmo-folder-creatable-p entity))
2738       (error "Folder %s is not found" entity)
2739     (if (y-or-n-p
2740          (format "Folder %s does not exist, create it?"
2741                  entity))
2742         (progn
2743           (setq wl-folder-entity-hashtb
2744                 (wl-folder-create-entity-hashtb
2745                  entity wl-folder-entity-hashtb))
2746           (unless (elmo-create-folder entity)
2747             (error "Create folder failed")))
2748       (error "Folder %s is not created" entity))))
2749
2750 (defun wl-folder-confirm-existence (folder &optional force)
2751   (if force
2752       (unless (elmo-folder-exists-p folder)
2753         (wl-folder-create-subr folder))
2754     (unless (or (wl-folder-entity-exists-p folder)
2755                 (file-exists-p (elmo-msgdb-expand-path folder))
2756                 (elmo-folder-exists-p folder))
2757       (wl-folder-create-subr folder))))
2758
2759 (require 'product)
2760 (product-provide (provide 'wl-folder) (require 'wl-version))
2761
2762 ;;; wl-folder.el ends here