* wl-vars.el (wl-draft-send-hook): Changed default value to
[elisp/wanderlust.git] / wl / wl-folder.el
1 ;;; wl-folder.el -- Folder mode for Wanderlust.
2
3 ;; Copyright 1998,1999,2000 Yuuichi Teranishi <teranisi@gohome.org>
4 ;;                          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-newsgroup)
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                                    (current-buffer)))
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           (save-window-excursion
985             (save-excursion
986               (wl-summary-goto-folder-subr entity
987                                            (wl-summary-get-sync-range entity)
988                                            nil nil nil t)
989               (wl-summary-exit))))))))
990
991 (defun wl-folder-sync-current-entity (&optional unread-only)
992   "Synchronize the folder at position.
993 If current line is group folder, check all subfolders."
994   (interactive "P")
995   (save-excursion
996     (let ((entity-name (wl-folder-get-entity-from-buffer))
997           (group (wl-folder-buffer-group-p)))
998       (when (and entity-name
999                  (y-or-n-p (format "Sync %s?" entity-name)))
1000         (wl-folder-sync-entity
1001          (if group
1002              (wl-folder-search-group-entity-by-name entity-name
1003                                                     wl-folder-entity)
1004            entity-name)
1005          unread-only)
1006         (message "Syncing %s is done!" entity-name)))))
1007
1008 (defun wl-folder-mark-as-read-all-entity (entity)
1009   "Mark as read all messages in the ENTITY."
1010   (cond
1011    ((consp entity)
1012     (let ((flist (nth 2 entity)))
1013       (while flist
1014         (wl-folder-mark-as-read-all-entity (car flist))
1015         (setq flist (cdr flist)))))
1016    ((stringp entity)
1017     (let ((nums (wl-folder-get-entity-info entity))
1018           (wl-summary-highlight (if (or (wl-summary-sticky-p entity)
1019                                         (wl-summary-always-sticky-folder-p
1020                                          entity))
1021                                     wl-summary-highlight))
1022           wl-auto-select-first new unread)
1023       (setq new (or (car nums) 0))
1024       (setq unread (or (cadr nums) 0))
1025       (if (or (< 0 new) (< 0 unread))
1026         (save-window-excursion
1027           (save-excursion
1028             (wl-summary-goto-folder-subr entity
1029                                          (wl-summary-get-sync-range entity)
1030                                          nil)
1031             (wl-summary-mark-as-read-all)
1032             (wl-summary-exit)))
1033         (sit-for 0))))))
1034
1035 (defun wl-folder-mark-as-read-all-current-entity ()
1036   "Mark as read all messages in the folder at position.
1037 If current line is group folder, all subfolders are marked."
1038   (interactive)
1039   (save-excursion
1040     (let ((entity-name (wl-folder-get-entity-from-buffer))
1041           (group (wl-folder-buffer-group-p))
1042           summary-buf)
1043       (when (and entity-name
1044                  (y-or-n-p (format "Mark all messages in %s as read?" entity-name)))
1045         (wl-folder-mark-as-read-all-entity
1046          (if group
1047              (wl-folder-search-group-entity-by-name entity-name
1048                                                     wl-folder-entity)
1049            entity-name))
1050         (message "All messages in %s are marked!" entity-name)))))
1051
1052 (defun wl-folder-check-region (beg end)
1053   (interactive "r")
1054   (goto-char beg)
1055   (beginning-of-line)
1056   (setq beg (point))
1057   (goto-char end)
1058   (beginning-of-line)
1059   (setq end (point))
1060   (goto-char beg)
1061   (let ((inhibit-read-only t)
1062         entity)
1063     (while (< (point) end)
1064       ;; normal folder entity
1065       (if (looking-at "^[\t ]*\\([^\\[]+\\):\\(.*\\)\n")
1066           (save-excursion
1067             (setq entity (wl-folder-get-entity-from-buffer))
1068             (if (not (elmo-folder-plugged-p entity))
1069                 (message "Uncheck %s" entity)
1070               (message "Checking %s" entity)
1071               (wl-folder-check-one-entity entity)
1072               (sit-for 0))))
1073       (forward-line 1)))
1074   (message ""))
1075
1076 (defun wl-folder-sync-region (beg end)
1077   (interactive "r")
1078   (goto-char beg)
1079   (beginning-of-line)
1080   (setq beg (point))
1081   (goto-char end)
1082   (end-of-line)
1083   (setq end (point))
1084   (goto-char beg)
1085   (while (< (point) end)
1086     ;; normal folder entity
1087     (if (looking-at "^[\t ]*\\([^\\[]+\\):\\(.*\\)\n")
1088         (save-excursion
1089           (let ((inhibit-read-only t)
1090                 entity)
1091             (setq entity (wl-folder-get-entity-from-buffer))
1092             (wl-folder-sync-entity entity)
1093             (message "Syncing %s is done!" entity)
1094             (sit-for 0))))
1095     (forward-line 1))
1096   (message ""))
1097
1098 (defun wl-folder-mark-as-read-all-region (beg end)
1099   (interactive "r")
1100   (goto-char beg)
1101   (beginning-of-line)
1102   (setq beg (point))
1103   (goto-char end)
1104   (end-of-line)
1105   (setq end (point))
1106   (goto-char beg)
1107   (while (< (point) end)
1108     ;; normal folder entity
1109     (if (looking-at "^[\t ]*\\([^\\[]+\\):\\(.*\\)\n")
1110         (save-excursion
1111           (let ((inhibit-read-only t)
1112                 entity)
1113             (setq entity (wl-folder-get-entity-from-buffer))
1114             (wl-folder-mark-as-read-all-entity entity)
1115             (message "All messages in %s are marked!" entity)
1116             (sit-for 0))))
1117     (forward-line 1))
1118   (message ""))
1119
1120 (defsubst wl-create-access-init-load-p (folder)
1121   (let ((no-load-regexp (when (and
1122                                (not wl-folder-init-load-access-folders)
1123                                wl-folder-init-no-load-access-folders)
1124                           (mapconcat 'identity
1125                                      wl-folder-init-no-load-access-folders
1126                                      "\\|")))
1127         (load-regexp (and wl-folder-init-load-access-folders
1128                           (mapconcat 'identity
1129                                      wl-folder-init-load-access-folders
1130                                      "\\|"))))
1131     (cond (load-regexp (string-match load-regexp folder))
1132           (t (not (and no-load-regexp
1133                        (string-match no-load-regexp folder)))))))
1134
1135 (defun wl-create-access-folder-entity (name)
1136   (let (flists flist)
1137     (when (wl-create-access-init-load-p name)
1138       (setq flists (elmo-msgdb-flist-load name)) ; load flist.
1139       (setq flist (car flists))
1140       (while flist
1141         (when (consp (car flist))
1142           (setcdr (cdar flist)
1143                   (wl-create-access-folder-entity (caar flist))))
1144         (setq flist (cdr flist)))
1145       flists)))
1146
1147 (defun wl-create-folder-entity-from-buffer ()
1148   "Create folder entity recursively."
1149   (cond
1150    ((looking-at "^[ \t]*$")             ; blank line
1151     (goto-char (+ 1(match-end 0)))
1152     'ignore)
1153    ((looking-at "^#.*$")                ; comment
1154     (goto-char (+ 1 (match-end 0)))
1155     'ignore)
1156    ((looking-at "^[\t ]*\\(.+\\)[\t ]*{[\t ]*$") ; group definition
1157     (let (name entity flist)
1158       (setq name (wl-match-buffer 1))
1159       (goto-char (+ 1 (match-end 0)))
1160       (while (setq entity (wl-create-folder-entity-from-buffer))
1161         (unless (eq entity 'ignore)
1162           (wl-append flist (list entity))))
1163       (if (looking-at "^[\t ]*}[\t ]*$") ; end of group
1164           (progn
1165             (goto-char (+ 1 (match-end 0)))
1166             (if (wl-string-assoc name wl-folder-petname-alist)
1167                 (error "%s already defined as petname" name))
1168             (list name 'group flist))
1169         (error "Syntax error in folder definition"))))
1170    ((looking-at "^[\t ]*\\([^\t \n]+\\)[\t ]*/$") ; access it!
1171     (let (name)
1172       (setq name (wl-match-buffer 1))
1173       (goto-char (+ 1 (match-end 0)))
1174 ;      (condition-case ()
1175 ;         (unwind-protect
1176 ;             (setq flist (elmo-list-folders name)))
1177 ;       (error (message "Access to folder %s failed." name)))
1178 ;;       (setq flist (elmo-msgdb-flist-load name)) ; load flist.
1179 ;;       (setq unsublist (nth 1 flist))
1180 ;;       (setq flist (car flist))
1181 ;;       (list name 'access flist unsublist)))
1182       (append (list name 'access) (wl-create-access-folder-entity name))))
1183    ;((looking-at "^[\t ]*\\([^\t \n}]+\\)[\t ]*\\(\"[^\"]*\"\\)?[\t ]*$") ; normal folder entity
1184    ((looking-at "^[\t ]*=[ \t]+\\([^\n]+\\)$"); petname definition
1185     (goto-char (+ 1 (match-end 0)))
1186     (let ((rest (elmo-match-buffer 1))
1187           petname)
1188       (when (string-match "\\(\"[^\"]*\"\\)[\t ]*$" rest)
1189         (setq petname (elmo-delete-char ?\" (elmo-match-string 1 rest)))
1190         (setq rest (substring rest 0 (match-beginning 0))))
1191       (when (string-match "^[\t ]*\\(.*[^\t ]+\\)[\t ]+$" rest)
1192         (wl-folder-append-petname (elmo-match-string 1 rest)
1193                                   petname))
1194       'ignore))
1195    ((looking-at "^[ \t]*}[ \t]*$") ; end of group
1196     nil)
1197    ((looking-at "^.*$") ; normal folder entity
1198     (goto-char (+ 1 (match-end 0)))
1199     (let ((rest (elmo-match-buffer 0))
1200           realname petname)
1201       (if (string-match "\\(\"[^\"]*\"\\)[\t ]*$" rest)
1202           (progn
1203             (setq petname (elmo-delete-char ?\" (elmo-match-string 1 rest)))
1204             (setq rest (substring rest 0 (match-beginning 0)))
1205             (when (string-match "^[\t ]*\\(.*[^\t ]+\\)[\t ]+$" rest)
1206               (wl-folder-append-petname
1207                (setq realname (elmo-match-string 1 rest))
1208                petname)
1209               realname))
1210         (if (string-match "^[\t ]*\\(.+\\)$" rest)
1211             (elmo-match-string 1 rest)
1212           rest))))))
1213
1214 (defun wl-folder-create-folder-entity ()
1215   "Create folder entries."
1216   (let ((tmp-buf (get-buffer-create " *wl-folder-tmp*"))
1217         entity ret-val)
1218     (condition-case ()
1219         (progn
1220           (with-current-buffer tmp-buf
1221             (erase-buffer)
1222             (insert-file-contents wl-folders-file)
1223             (goto-char (point-min))
1224             (while (and (not (eobp))
1225                         (setq entity (wl-create-folder-entity-from-buffer)))
1226               (unless (eq entity 'ignore)
1227                 (wl-append ret-val (list entity)))))
1228           (kill-buffer tmp-buf))
1229       (file-error nil))
1230     (setq ret-val (list wl-folder-desktop-name 'group ret-val))))
1231
1232 (defun wl-folder-entity-assign-id (entity &optional hashtb on-noid)
1233   (let ((hashtb (or hashtb
1234                     (setq wl-folder-entity-id-name-hashtb
1235                           (elmo-make-hash wl-folder-entity-id))))
1236         (entities (list entity))
1237         entity-stack)
1238     (while entities
1239       (setq entity (wl-pop entities))
1240       (cond
1241        ((consp entity)
1242         (when (not (and on-noid
1243                         (get-text-property 0
1244                                            'wl-folder-entity-id
1245                                            (car entity))))
1246           (put-text-property 0 (length (car entity))
1247                              'wl-folder-entity-id
1248                              wl-folder-entity-id
1249                              (car entity))
1250           (wl-folder-set-id-name wl-folder-entity-id
1251                                  (car entity) hashtb))
1252         (and entities
1253              (wl-push entities entity-stack))
1254         (setq entities (nth 2 entity)))
1255        ((stringp entity)
1256         (when (not (and on-noid
1257                         (get-text-property 0
1258                                            'wl-folder-entity-id
1259                                            entity)))
1260           (put-text-property 0 (length entity)
1261                              'wl-folder-entity-id
1262                              wl-folder-entity-id
1263                              entity)
1264           (wl-folder-set-id-name wl-folder-entity-id
1265                                  entity hashtb))))
1266       (setq wl-folder-entity-id (+ 1 wl-folder-entity-id))
1267       (unless entities
1268         (setq entities (wl-pop entity-stack))))))
1269
1270 (defun wl-folder-click (e)
1271   (interactive "e")
1272   (mouse-set-point e)
1273   (beginning-of-line)
1274   (save-excursion
1275     (wl-folder-jump-to-current-entity)))
1276
1277 (defun wl-folder-select-buffer (buffer)
1278   (let ((gbw (get-buffer-window buffer))
1279         ret-val)
1280     (if gbw
1281         (progn (select-window gbw)
1282                (setq ret-val t))
1283       (condition-case ()
1284           (unwind-protect
1285               (split-window-horizontally wl-folder-window-width)
1286             (other-window 1))
1287         (error nil)))
1288     (set-buffer buffer)
1289     (switch-to-buffer buffer)
1290     ret-val
1291     ))
1292
1293 (defun wl-folder-toggle-disp-summary (&optional arg folder)
1294   (interactive)
1295   (if (or (and folder (assoc folder wl-folder-group-alist))
1296           (and (interactive-p) (wl-folder-buffer-group-p)))
1297       (error "This command is not available on Group"))
1298   (beginning-of-line)
1299   (let (wl-auto-select-first)
1300     (cond
1301      ((eq arg 'on)
1302       (setq wl-folder-buffer-disp-summary t))
1303      ((eq arg 'off)
1304       (setq wl-folder-buffer-disp-summary nil)
1305       ;; hide wl-summary window.
1306       (let ((cur-buf (current-buffer))
1307             (summary-buffer (wl-summary-get-buffer folder)))
1308         (wl-folder-select-buffer summary-buffer)
1309         (delete-window)
1310         (select-window (get-buffer-window cur-buf))))
1311      (t
1312       (setq wl-folder-buffer-disp-summary
1313             (not wl-folder-buffer-disp-summary))
1314       (let ((cur-buf (current-buffer))
1315             folder-name)
1316         (when (looking-at "^[ ]*\\([^\\[].+\\):.*\n")
1317           (setq folder-name (wl-folder-get-entity-from-buffer))
1318           (if wl-folder-buffer-disp-summary
1319               (progn
1320                 (wl-folder-select-buffer
1321                  (wl-summary-get-buffer-create folder-name))
1322                 (unwind-protect
1323                     (wl-summary-goto-folder-subr folder-name 'no-sync nil)
1324                   (select-window (get-buffer-window cur-buf))))
1325             (wl-folder-select-buffer (wl-summary-get-buffer folder-name))
1326             (delete-window)
1327             (select-window (get-buffer-window cur-buf)))))))))
1328
1329 (defun wl-folder-prev-unsync ()
1330   "Move cursor to the previous unsync folder."
1331   (interactive)
1332   (let (start-point)
1333     (setq start-point (point))
1334     (beginning-of-line)
1335     (if (re-search-backward wl-folder-unsync-regexp nil t)
1336         (beginning-of-line)
1337       (goto-char start-point)
1338       (message "No more unsync folder"))))
1339
1340 (defun wl-folder-next-unsync (&optional plugged)
1341   "Move cursor to the next unsync."
1342   (interactive)
1343   (let (start-point entity)
1344     (setq start-point (point))
1345     (end-of-line)
1346     (if (catch 'found
1347           (while (re-search-forward wl-folder-unsync-regexp nil t)
1348             (if (or (wl-folder-buffer-group-p)
1349                     (not plugged)
1350                     (setq entity
1351                           (wl-folder-get-realname
1352                            (wl-folder-folder-name)))
1353                     (elmo-folder-plugged-p entity))
1354                 (throw 'found t))))
1355         (beginning-of-line)
1356       (goto-char start-point)
1357       (message "No more unsync folder"))))
1358
1359 (defun wl-folder-prev-unread (&optional group)
1360   "Move cursor to the previous unread folder."
1361   (interactive "P")
1362   (let (start-point)
1363     (setq start-point (point))
1364     (beginning-of-line)
1365     (if (re-search-backward (wl-folder-unread-regex group) nil t)
1366         (progn
1367           (beginning-of-line)
1368           (wl-folder-folder-name))
1369       (goto-char start-point)
1370       (message "No more unread folder")
1371       nil)))
1372
1373 (defun wl-folder-next-unread (&optional group)
1374   "Move cursor to the next unread folder."
1375   (interactive "P")
1376   (let (start-point)
1377     (setq start-point (point))
1378     (end-of-line)
1379     (if (re-search-forward (wl-folder-unread-regex group) nil t)
1380         (progn
1381           (beginning-of-line)
1382           (wl-folder-folder-name))
1383       (goto-char start-point)
1384       (message "No more unread folder")
1385       nil)))
1386
1387 (defun wl-folder-mode ()
1388   "Major mode for Wanderlust Folder.
1389 See info under Wanderlust for full documentation.
1390
1391 Special commands:
1392 \\{wl-folder-mode-map}
1393
1394 Entering Folder mode calls the value of `wl-folder-mode-hook'."
1395   (interactive)
1396   (setq major-mode 'wl-folder-mode)
1397   (setq mode-name "Folder")
1398   (use-local-map wl-folder-mode-map)
1399   (setq buffer-read-only t)
1400   (setq inhibit-read-only nil)
1401   (setq truncate-lines t)
1402   (setq wl-folder-buffer-cur-entity-id nil
1403         wl-folder-buffer-cur-path nil
1404         wl-folder-buffer-cur-point nil)
1405   (wl-mode-line-buffer-identification)
1406   (easy-menu-add wl-folder-mode-menu)
1407   ;; This hook may contain the functions `wl-folder-init-icons' and
1408   ;; `wl-setup-folder' for reasons of system internal to accord
1409   ;; facilities for the Emacs variants.
1410   (run-hooks 'wl-folder-mode-hook))
1411
1412 (defun wl-folder-append-petname (realname petname)
1413   (let (pentry)
1414     ;; check group name.
1415     (if (wl-folder-search-group-entity-by-name petname wl-folder-entity)
1416         (error "%s already defined as group name" petname))
1417     (when (setq pentry (wl-string-assoc realname wl-folder-petname-alist))
1418       (setq wl-folder-petname-alist
1419             (delete pentry wl-folder-petname-alist)))
1420     (wl-append wl-folder-petname-alist
1421                (list (cons realname petname)))))
1422
1423 (defun wl-folder (&optional arg)
1424   (interactive "P")
1425   (let (initialize)
1426 ;;; (delete-other-windows)
1427     (if (get-buffer wl-folder-buffer-name)
1428         (switch-to-buffer  wl-folder-buffer-name)
1429       (switch-to-buffer (get-buffer-create wl-folder-buffer-name))
1430       (wl-folder-mode)
1431       (wl-folder-init)
1432       (set-buffer wl-folder-buffer-name)
1433       (let ((inhibit-read-only t)
1434             (buffer-read-only nil))
1435         (erase-buffer)
1436         (setcdr (assoc (car wl-folder-entity) wl-folder-group-alist) t)
1437         (save-excursion
1438           (wl-folder-insert-entity " " wl-folder-entity)))
1439       (set-buffer-modified-p nil)
1440       ;(sit-for 0)
1441       (setq initialize t))
1442     initialize))
1443
1444 (defun wl-folder-auto-check ()
1445   "Check and update folders in `wl-auto-check-folder-name'."
1446   (interactive)
1447   (when (get-buffer wl-folder-buffer-name)
1448     (switch-to-buffer  wl-folder-buffer-name)
1449     (cond
1450      ((eq wl-auto-check-folder-name 'none))
1451      ((or (consp wl-auto-check-folder-name)
1452           (stringp wl-auto-check-folder-name))
1453       (let ((folder-list (if (consp wl-auto-check-folder-name)
1454                              wl-auto-check-folder-name
1455                            (list wl-auto-check-folder-name)))
1456             entity)
1457         (while folder-list
1458           (if (setq entity (wl-folder-search-entity-by-name
1459                             (car folder-list)
1460                             wl-folder-entity))
1461               (wl-folder-check-entity entity 'auto))
1462           (setq folder-list (cdr folder-list)))))
1463      (t
1464       (wl-folder-check-entity wl-folder-entity 'auto)))))
1465
1466 (defun wl-folder-set-folder-updated (name value)
1467   (save-excursion
1468     (let (buf)
1469       (if (setq buf (get-buffer wl-folder-buffer-name))
1470           (wl-folder-entity-hashtb-set
1471            wl-folder-entity-hashtb name value buf))
1472 ;;;   (elmo-folder-set-info-hashtb (elmo-string name)
1473 ;;;                                nil
1474 ;;;                                (nth 2 value)
1475 ;;;                                (nth 0 value)
1476 ;;;                                (nth 1 value))
1477       (setq wl-folder-info-alist-modified t))))
1478
1479 (defun wl-folder-calc-finfo (entity)
1480   ;; calcurate finfo without inserting.
1481   (let ((entities (list entity))
1482         entity-stack
1483         new unread all nums)
1484     (while entities
1485       (setq entity (wl-pop entities))
1486       (cond
1487        ((consp entity)
1488         (and entities
1489              (wl-push entities entity-stack))
1490         (setq entities (nth 2 entity)))
1491        ((stringp entity)
1492         (setq nums (wl-folder-get-entity-info entity))
1493         (setq new    (+ (or new 0) (or (nth 0 nums) 0)))
1494         (setq unread (+ (or unread 0)
1495                         (or (and (nth 0 nums)(nth 1 nums)
1496                                  (+ (nth 0 nums)(nth 1 nums))) 0)))
1497         (setq all    (+ (or all 0) (or (nth 2 nums) 0)))))
1498       (unless entities
1499         (setq entities (wl-pop entity-stack))))
1500     (list new unread all)))
1501
1502 (defsubst wl-folder-make-save-access-list (list)
1503   (mapcar '(lambda (x)
1504              (cond
1505               ((consp x)
1506                (list (elmo-string (car x)) 'access))
1507               (t
1508                (elmo-string x))))
1509           list))
1510
1511 (defun wl-folder-update-newest (indent entity)
1512   (let (ret-val new unread all)
1513     (cond
1514      ((consp entity)
1515       (let ((inhibit-read-only t)
1516             (buffer-read-only nil)
1517             (flist (nth 2 entity))
1518             (as-opened (cdr (assoc (car entity) wl-folder-group-alist)))
1519             beg
1520             )
1521         (setq beg (point))
1522         (if as-opened
1523             (let (update-flist flist-unsub new-flist removed group-name-end)
1524               (when (and (eq (cadr entity) 'access)
1525                          (elmo-folder-plugged-p (car entity)))
1526                 (message "Fetching folder entries...")
1527                 (when (setq new-flist
1528                             (elmo-list-folders
1529                              (elmo-string (car entity))
1530                              (wl-string-member
1531                               (car entity)
1532                               wl-folder-hierarchy-access-folders)))
1533                   (setq update-flist
1534                         (wl-folder-update-access-group entity new-flist))
1535                   (setq flist (nth 1 update-flist))
1536                   (when (car update-flist) ;; diff
1537                     (setq flist-unsub (nth 2 update-flist))
1538                     (setq removed (nth 3 update-flist))
1539                     (elmo-msgdb-flist-save
1540                      (car entity)
1541                      (list
1542                       (wl-folder-make-save-access-list flist)
1543                       (wl-folder-make-save-access-list flist-unsub)))
1544                     (wl-folder-entity-assign-id
1545                      entity
1546                      wl-folder-entity-id-name-hashtb
1547                      t)
1548                     (setq wl-folder-entity-hashtb
1549                           (wl-folder-create-entity-hashtb
1550                            entity
1551                            wl-folder-entity-hashtb
1552                            t))
1553                     (setq wl-folder-newsgroups-hashtb
1554                           (or
1555                            (wl-folder-create-newsgroups-hashtb
1556                             entity nil)
1557                            wl-folder-newsgroups-hashtb))))
1558                 (message "Fetching folder entries...done"))
1559               (wl-folder-insert-entity indent entity))))))))
1560
1561 (defun wl-folder-insert-entity (indent entity &optional onlygroup)
1562   (let (ret-val new unread all)
1563     (cond
1564      ((consp entity)
1565       (let ((inhibit-read-only t)
1566             (buffer-read-only nil)
1567             (flist (nth 2 entity))
1568             (as-opened (cdr (assoc (car entity) wl-folder-group-alist)))
1569             beg
1570             )
1571 ;;;     (insert indent "[" (if as-opened "-" "+") "]" (car entity) "\n")
1572 ;;;     (save-excursion (forward-line -1)
1573 ;;;                     (wl-highlight-folder-current-line))
1574         (setq beg (point))
1575         (if (and as-opened
1576                  (not onlygroup))
1577             (let (update-flist flist-unsub new-flist removed group-name-end)
1578 ;;;           (when (and (eq (cadr entity) 'access)
1579 ;;;                      newest)
1580 ;;;             (message "fetching folder entries...")
1581 ;;;             (when (setq new-flist
1582 ;;;                         (elmo-list-folders
1583 ;;;                          (elmo-string (car entity))
1584 ;;;                          (wl-string-member
1585 ;;;                           (car entity)
1586 ;;;                           wl-folder-hierarchy-access-folders)
1587 ;;;                          ))
1588 ;;;               (setq update-flist
1589 ;;;                     (wl-folder-update-access-group entity new-flist))
1590 ;;;               (setq flist (nth 1 update-flist))
1591 ;;;               (when (car update-flist) ;; diff
1592 ;;;                 (setq flist-unsub (nth 2 update-flist))
1593 ;;;                 (setq removed (nth 3 update-flist))
1594 ;;;                 (elmo-msgdb-flist-save
1595 ;;;                  (car entity)
1596 ;;;                  (list
1597 ;;;                   (wl-folder-make-save-access-list flist)
1598 ;;;                   (wl-folder-make-save-access-list flist-unsub)))
1599 ;;;                 ;;
1600 ;;;                 ;; reconstruct wl-folder-entity-id-name-hashtb and
1601 ;;;                 ;;           wl-folder-entity-hashtb
1602 ;;;                 ;;
1603 ;;;                 (wl-folder-entity-assign-id
1604 ;;;                  entity
1605 ;;;                  wl-folder-entity-id-name-hashtb
1606 ;;;                  t)
1607 ;;;                 (setq wl-folder-entity-hashtb
1608 ;;;                       (wl-folder-create-entity-hashtb
1609 ;;;                        entity
1610 ;;;                        wl-folder-entity-hashtb
1611 ;;;                        t))
1612 ;;;                 (setq wl-folder-newsgroups-hashtb
1613 ;;;                       (or
1614 ;;;                        (wl-folder-create-newsgroups-hashtb
1615 ;;;                         entity nil)
1616 ;;;                        wl-folder-newsgroups-hashtb))))
1617 ;;;             (message "fetching folder entries...done"))
1618               (insert indent "[" (if as-opened "-" "+") "]"
1619                       (wl-folder-get-petname (car entity)))
1620               (setq group-name-end (point))
1621               (insert ":0/0/0\n")
1622               (put-text-property beg (point) 'wl-folder-entity-id
1623                                  (get-text-property 0 'wl-folder-entity-id
1624                                                     (car entity)))
1625               (when removed
1626                 (setq beg (point))
1627                 (while removed
1628                   (insert indent "  "
1629                           wl-folder-removed-mark
1630                           (if (listp (car removed))
1631                               (concat "[+]" (caar removed))
1632                             (car removed))
1633                           "\n")
1634                   (save-excursion (forward-line -1)
1635                                   (wl-highlight-folder-current-line))
1636                   (setq removed (cdr removed)))
1637                 (remove-text-properties beg (point) '(wl-folder-entity-id)))
1638               (let* ((len (length flist))
1639                      (mes (> len 100))
1640                      (i 0))
1641                 (while flist
1642                   (setq ret-val
1643                         (wl-folder-insert-entity
1644                          (concat indent "  ") (car flist)))
1645                   (setq new    (+ (or new 0) (or (nth 0 ret-val) 0)))
1646                   (setq unread (+ (or unread 0) (or (nth 1 ret-val) 0)))
1647                   (setq all    (+ (or all 0) (or (nth 2 ret-val) 0)))
1648                   (when (and mes
1649                              (> len elmo-display-progress-threshold))
1650                     (setq i (1+ i))
1651                     (elmo-display-progress
1652                      'wl-folder-insert-entity "Inserting group %s..."
1653                      (/ (* i 100) len) (car entity)))
1654                   (setq flist (cdr flist))))
1655               (save-excursion
1656                 (goto-char group-name-end)
1657                 (delete-region (point) (save-excursion (end-of-line)
1658                                                        (point)))
1659                 (insert (format ":%d/%d/%d" (or new 0)
1660                                 (or unread 0) (or all 0)))
1661                 (setq ret-val (list new unread all))
1662                 (wl-highlight-folder-current-line ret-val)))
1663           (setq ret-val (wl-folder-calc-finfo entity))
1664           (insert indent "[" (if as-opened "-" "+") "]"
1665                   (wl-folder-get-petname (car entity))
1666                   (format ":%d/%d/%d"
1667                           (or (nth 0 ret-val) 0)
1668                           (or (nth 1 ret-val) 0)
1669                           (or (nth 2 ret-val) 0))
1670                   "\n")
1671           (put-text-property beg (point) 'wl-folder-entity-id
1672                              (get-text-property 0 'wl-folder-entity-id
1673                                                 (car entity)))
1674           (save-excursion (forward-line -1)
1675                           (wl-highlight-folder-current-line ret-val)))))
1676      ((stringp entity)
1677       (let* ((inhibit-read-only t)
1678              (buffer-read-only nil)
1679              (nums (wl-folder-get-entity-info entity))
1680              beg)
1681         (setq beg (point))
1682         (insert indent (wl-folder-get-petname entity)
1683                 (format ":%s/%s/%s\n"
1684                         (or (setq new (nth 0 nums)) "*")
1685                         (or (setq unread (and (nth 0 nums)(nth 1 nums)
1686                                               (+ (nth 0 nums)(nth 1 nums))))
1687                             "*")
1688                         (or (setq all (nth 2 nums)) "*")))
1689         (put-text-property beg (point) 'wl-folder-entity-id
1690                            (get-text-property 0 'wl-folder-entity-id entity))
1691         (save-excursion (forward-line -1)
1692                         (wl-highlight-folder-current-line nums))
1693         (setq ret-val (list new unread all)))))
1694     (set-buffer-modified-p nil)
1695     ret-val))
1696
1697 (defun wl-folder-check-all ()
1698   (interactive)
1699   (wl-folder-check-entity wl-folder-entity))
1700
1701 (defun wl-folder-entity-hashtb-set (entity-hashtb name value buffer)
1702   (let (cur-val
1703         (new-diff 0)
1704         (unread-diff 0)
1705         (all-diff 0)
1706         diffs
1707         entity-list)
1708     (setq cur-val (wl-folder-get-entity-info name entity-hashtb))
1709     (setq new-diff    (- (or (nth 0 value) 0) (or (nth 0 cur-val) 0)))
1710     (setq unread-diff
1711           (+ new-diff
1712              (- (or (nth 1 value) 0) (or (nth 1 cur-val) 0))))
1713     (setq all-diff    (- (or (nth 2 value) 0) (or (nth 2 cur-val) 0)))
1714     (setq diffs (list new-diff unread-diff all-diff))
1715     (unless (and (nth 0 cur-val)
1716                  (equal diffs '(0 0 0)))
1717       (wl-folder-set-entity-info name value entity-hashtb)
1718       (save-match-data
1719         (save-excursion
1720           (set-buffer buffer)
1721           (setq entity-list (wl-folder-search-entity-list-by-name
1722                              name wl-folder-entity))
1723           (while entity-list
1724             (wl-folder-update-group (car entity-list) diffs)
1725             (setq entity-list (cdr entity-list)))
1726           (goto-char (point-min))
1727           (while (wl-folder-buffer-search-entity name)
1728             (wl-folder-update-line value)))))))
1729
1730 (defun wl-folder-update-unread (folder unread)
1731   (save-window-excursion
1732     (let ((buf (get-buffer wl-folder-buffer-name))
1733           cur-unread
1734           (unread-diff 0)
1735           ;;(fld (elmo-string folder))
1736           value newvalue entity-list)
1737 ;;; Update folder-info
1738 ;;;    (elmo-folder-set-info-hashtb fld nil nil nil unread)
1739       (setq cur-unread (or (nth 1 (wl-folder-get-entity-info folder)) 0))
1740       (setq unread-diff (- (or unread 0) cur-unread))
1741       (setq value (wl-folder-get-entity-info folder))
1742
1743       (setq newvalue (list (nth 0 value)
1744                            unread
1745                            (nth 2 value)))
1746       (wl-folder-set-entity-info folder newvalue)
1747       (setq wl-folder-info-alist-modified t)
1748       (when (and buf
1749                  (not (eq unread-diff 0)))
1750         (save-match-data
1751           (save-excursion
1752             (set-buffer buf)
1753             (save-excursion
1754               (setq entity-list (wl-folder-search-entity-list-by-name
1755                                  folder wl-folder-entity))
1756               (while entity-list
1757                 (wl-folder-update-group (car entity-list) (list 0
1758                                                                 unread-diff
1759                                                                 0))
1760                 (setq entity-list (cdr entity-list)))
1761               (goto-char (point-min))
1762               (while (wl-folder-buffer-search-entity folder)
1763                 (wl-folder-update-line newvalue)))))))))
1764
1765 (defun wl-folder-create-entity-hashtb (entity &optional hashtb reconst)
1766   (let ((hashtb (or hashtb (elmo-make-hash wl-folder-entity-id)))
1767         (entities (list entity))
1768         entity-stack)
1769     (while entities
1770       (setq entity (wl-pop entities))
1771       (cond
1772        ((consp entity)
1773         (and entities
1774              (wl-push entities entity-stack))
1775         (setq entities (nth 2 entity)))
1776        ((stringp entity)
1777         (when (not (and reconst
1778                         (wl-folder-get-entity-info entity)))
1779           (wl-folder-set-entity-info entity
1780                                      nil
1781                                      hashtb))))
1782       (unless entities
1783         (setq entities (wl-pop entity-stack))))
1784     hashtb))
1785
1786 ;; Unsync number is reserved.
1787 ;;(defun wl-folder-reconstruct-entity-hashtb (entity &optional hashtb id-name)
1788 ;;  (let* ((hashtb (or hashtb (elmo-make-hash wl-folder-entity-id)))
1789 ;;       (entities (list entity))
1790 ;;       entity-stack)
1791 ;;    (while entities
1792 ;;      (setq entity (wl-pop entities))
1793 ;;      (cond
1794 ;;       ((consp entity)
1795 ;;      (if id-name
1796 ;;          (wl-folder-set-id-name (wl-folder-get-entity-id (car entity))
1797 ;;                                 (car entity)))
1798 ;;      (and entities
1799 ;;           (wl-push entities entity-stack))
1800 ;;      (setq entities (nth 2 entity))
1801 ;;      )
1802 ;;       ((stringp entity)
1803 ;;      (wl-folder-set-entity-info entity
1804 ;;                                 (wl-folder-get-entity-info entity)
1805 ;;                                 hashtb)
1806 ;;      (if id-name
1807 ;;          (wl-folder-set-id-name (wl-folder-get-entity-id entity)
1808 ;;                                 entity))))
1809 ;;      (unless entities
1810 ;;      (setq entities (wl-pop entity-stack))))
1811 ;;    hashtb))
1812
1813 (defun wl-folder-create-newsgroups-from-nntp-access2 (entity)
1814   (let ((flist (nth 2 entity))
1815         folders)
1816     (and
1817      (setq folders
1818            (delq
1819             nil
1820             (mapcar
1821              '(lambda (fld)
1822                 (if (consp fld)
1823                     (wl-folder-create-newsgroups-from-nntp-access2 fld)
1824                   (nth 1 (elmo-folder-get-spec fld))))
1825              flist)))
1826      (elmo-nntp-make-groups-hashtb folders 1024))
1827     nil))
1828
1829 (defun wl-folder-create-newsgroups-from-nntp-access (entity)
1830   (let ((flist (nth 2 entity))
1831         folders)
1832     (while flist
1833       (wl-append folders
1834                  (cond
1835                   ((consp (car flist))
1836                    (wl-folder-create-newsgroups-from-nntp-access (car flist)))
1837                   (t
1838                    (list (nth 1 (elmo-folder-get-spec (car flist)))))))
1839       (setq flist (cdr flist)))
1840     folders))
1841
1842 (defun wl-folder-create-newsgroups-hashtb (entity &optional is-list info)
1843   (let ((entities (if is-list entity (list entity)))
1844         entity-stack spec-list folders fld make-hashtb)
1845     (and info (message "Creating newsgroups..."))
1846     (while entities
1847       (setq entity (wl-pop entities))
1848       (cond
1849        ((consp entity)
1850         (if (eq (nth 1 entity) 'access)
1851             (when (eq (elmo-folder-get-type (car entity)) 'nntp)
1852               (wl-append folders
1853                          (wl-folder-create-newsgroups-from-nntp-access entity))
1854               (setq make-hashtb t))
1855           (and entities
1856                (wl-push entities entity-stack))
1857           (setq entities (nth 2 entity))))
1858        ((stringp entity)
1859         (setq spec-list (elmo-folder-get-primitive-spec-list entity))
1860         (while spec-list
1861           (when (and (eq (caar spec-list) 'nntp)
1862                      (setq fld (nth 1 (car spec-list))))
1863             (wl-append folders (list (elmo-string fld))))
1864           (setq spec-list (cdr spec-list)))))
1865       (unless entities
1866         (setq entities (wl-pop entity-stack))))
1867     (and info (message "Creating newsgroups...done"))
1868     (if (or folders make-hashtb)
1869         (elmo-nntp-make-groups-hashtb folders))))
1870
1871 (defun wl-folder-get-path (entity target-id &optional string)
1872   (let ((entities (list entity))
1873         entity-stack result-path)
1874     (reverse
1875      (catch 'done
1876        (while entities
1877          (setq entity (wl-pop entities))
1878          (cond
1879           ((consp entity)
1880            (if (and (or (not string) (string= string (car entity)))
1881                     ;; don't use eq, `id' is string on Nemacs.
1882                     (equal target-id (wl-folder-get-entity-id (car entity))))
1883                (throw 'done
1884                       (wl-push target-id result-path))
1885              (wl-push (wl-folder-get-entity-id (car entity)) result-path))
1886            (wl-push entities entity-stack)
1887            (setq entities (nth 2 entity)))
1888           ((stringp entity)
1889            (if (and (or (not string) (string= string entity))
1890                     ;; don't use eq, `id' is string on Nemacs.
1891                     (equal target-id (wl-folder-get-entity-id entity)))
1892                (throw 'done
1893                       (wl-push target-id result-path)))))
1894          (unless entities
1895            (while (and entity-stack
1896                        (not entities))
1897              (setq result-path (cdr result-path))
1898              (setq entities (wl-pop entity-stack)))))))))
1899
1900 (defun wl-folder-create-group-alist (entity)
1901   (if (consp entity)
1902       (let ((flist (nth 2 entity))
1903             (cur-alist (list (cons (car entity) nil)))
1904              append-alist)
1905         (while flist
1906           (if (consp (car flist))
1907               (wl-append append-alist
1908                          (wl-folder-create-group-alist (car flist))))
1909           (setq flist (cdr flist)))
1910         (append cur-alist append-alist))))
1911
1912 (defun wl-folder-init-info-hashtb ()
1913   (let ((info-alist (and wl-folder-info-save
1914                          (elmo-msgdb-finfo-load))))
1915     (elmo-folder-info-make-hashtb
1916      info-alist
1917      wl-folder-entity-hashtb)))
1918 ;;; (wl-folder-resume-entity-hashtb-by-finfo
1919 ;;;  wl-folder-entity-hashtb
1920 ;;;  info-alist)))
1921
1922 (defun wl-folder-cleanup-variables ()
1923   (setq wl-folder-entity nil
1924         wl-folder-entity-hashtb nil
1925         wl-folder-entity-id-name-hashtb nil
1926         wl-folder-group-alist nil
1927         wl-folder-petname-alist nil
1928         wl-folder-newsgroups-hashtb nil
1929         wl-fldmgr-cut-entity-list nil
1930         wl-fldmgr-modified nil
1931         wl-fldmgr-modified-access-list nil
1932         wl-score-cache nil
1933         ))
1934
1935 (defun wl-make-plugged-alist ()
1936   (let ((entity-list (wl-folder-get-entity-list wl-folder-entity))
1937         (add (not wl-reset-plugged-alist)))
1938     (while entity-list
1939       (elmo-folder-set-plugged
1940        (elmo-string (car entity-list)) wl-plugged add)
1941       (setq entity-list (cdr entity-list)))
1942     ;; smtp posting server
1943     (when wl-smtp-posting-server
1944       (elmo-set-plugged wl-plugged
1945                         wl-smtp-posting-server  ; server
1946                         (or (and (boundp 'smtp-service) smtp-service)
1947                             "smtp")     ; port
1948                         nil nil "smtp" add))
1949     ;; nntp posting server
1950     (when wl-nntp-posting-server
1951       (elmo-set-plugged wl-plugged
1952                         wl-nntp-posting-server
1953                         elmo-default-nntp-port
1954                         nil nil "nntp" add))
1955     ;; This hook may contain the functions `wl-plugged-init-icons' and
1956     ;; `wl-biff-init-icons' for reasons of system internal to accord
1957     ;; facilities for the Emacs variants.
1958     (run-hooks 'wl-make-plugged-hook)))
1959
1960 (defvar wl-folder-init-func 'wl-local-folder-init)
1961
1962 (defun wl-folder-init ()
1963   "Call `wl-folder-init-func' function."
1964   (interactive)
1965   (funcall wl-folder-init-func))
1966
1967 (defun wl-local-folder-init ()
1968   "Initialize local folder."
1969   (message "Initializing folder...")
1970   (save-excursion
1971     (set-buffer wl-folder-buffer-name)
1972     (let ((entity (wl-folder-create-folder-entity))
1973           (inhibit-read-only t))
1974       (setq wl-folder-entity entity)
1975       (setq wl-folder-entity-id 0)
1976       (wl-folder-entity-assign-id wl-folder-entity)
1977       (setq wl-folder-entity-hashtb
1978             (wl-folder-create-entity-hashtb entity))
1979       (setq wl-folder-group-alist
1980             (wl-folder-create-group-alist entity))
1981       (setq wl-folder-newsgroups-hashtb
1982             (wl-folder-create-newsgroups-hashtb wl-folder-entity))
1983       (wl-folder-init-info-hashtb)))
1984   (message "Initializing folder...done"))
1985
1986 (defun wl-folder-get-realname (petname)
1987   (or (car
1988        (wl-string-rassoc
1989         petname
1990         wl-folder-petname-alist))
1991       petname))
1992
1993 (defun wl-folder-get-petname (folder)
1994   (or (cdr
1995        (wl-string-assoc
1996         folder
1997         wl-folder-petname-alist))
1998       folder))
1999
2000 (defun wl-folder-get-entity-with-petname ()
2001   (let ((alist wl-folder-petname-alist)
2002         (hashtb (copy-sequence wl-folder-entity-hashtb)))
2003     (while alist
2004       (wl-folder-set-entity-info (cdar alist) nil hashtb)
2005       (setq alist (cdr alist)))
2006     hashtb))
2007
2008 (defun wl-folder-update-diff-line (diffs)
2009   (let ((inhibit-read-only t)
2010         (buffer-read-only nil)
2011         cur-new new-new
2012         cur-unread new-unread
2013         cur-all new-all
2014         id)
2015     (save-excursion
2016       (beginning-of-line)
2017       (setq id (get-text-property (point) 'wl-folder-entity-id))
2018       (when (looking-at "^[ ]*\\(.*\\):\\([0-9\\*-]*\\)/\\([0-9\\*-]*\\)/\\([0-9\\*]*\\)")
2019         ;;(looking-at "^[ ]*\\([^\\[].+\\):\\([0-9\\*-]*/[0-9\\*-]*/[0-9\\*]*\\)")
2020         (setq cur-new (string-to-int
2021                        (wl-match-buffer 2)))
2022         (setq cur-unread (string-to-int
2023                           (wl-match-buffer 3)))
2024         (setq cur-all (string-to-int
2025                        (wl-match-buffer 4)))
2026         (delete-region (match-beginning 2)
2027                        (match-end 4))
2028         (goto-char (match-beginning 2))
2029         (insert (format "%s/%s/%s"
2030                         (setq new-new (+ cur-new (nth 0 diffs)))
2031                         (setq new-unread (+ cur-unread (nth 1 diffs)))
2032                         (setq new-all (+ cur-all (nth 2 diffs)))))
2033         (put-text-property (match-beginning 2) (point)
2034                            'wl-folder-entity-id id)
2035         (if wl-use-highlight-mouse-line
2036             (put-text-property (match-beginning 2) (point)
2037                                'mouse-face 'highlight))
2038         (wl-highlight-folder-group-line (list new-new new-unread new-all))
2039         (setq buffer-read-only t)
2040         (set-buffer-modified-p nil)))))
2041
2042 (defun wl-folder-update-line (nums &optional is-group)
2043   (let ((inhibit-read-only t)
2044         (buffer-read-only nil)
2045         id)
2046     (save-excursion
2047       (beginning-of-line)
2048       (setq id (get-text-property (point) 'wl-folder-entity-id))
2049       (if (looking-at "^[ ]*\\(.*\\):\\([0-9\\*-]*/[0-9\\*-]*/[0-9\\*]*\\)")
2050 ;;;       (looking-at "^[ ]*\\([^\\[].+\\):\\([0-9\\*-]*/[0-9\\*-]*/[0-9\\*]*\\)")
2051           (progn
2052             (delete-region (match-beginning 2)
2053                            (match-end 2))
2054             (goto-char (match-beginning 2))
2055             (insert (format "%s/%s/%s"
2056                             (or (nth 0 nums) "*")
2057                             (or (and (nth 0 nums)(nth 1 nums)
2058                                      (+ (nth 0 nums)(nth 1 nums)))
2059                                 "*")
2060                             (or (nth 2 nums) "*")))
2061             (put-text-property (match-beginning 2) (point)
2062                                'wl-folder-entity-id id)
2063             (if is-group
2064                 ;; update only colors
2065                 (wl-highlight-folder-group-line nums)
2066               (wl-highlight-folder-current-line nums))
2067             (set-buffer-modified-p nil))))))
2068
2069 (defun wl-folder-goto-folder (&optional arg)
2070   (interactive "P")
2071   (wl-folder-goto-folder-subr nil arg))
2072
2073 (defun wl-folder-goto-folder-subr (&optional folder sticky)
2074   (beginning-of-line)
2075   (let (summary-buf fld-name entity id error-selecting)
2076 ;;; (setq fld-name (wl-folder-get-entity-from-buffer))
2077 ;;; (if (or (null fld-name)
2078 ;;;         (assoc fld-name wl-folder-group-alist))
2079     (setq fld-name wl-default-folder)
2080     (setq fld-name (or folder
2081                        (wl-summary-read-folder fld-name)))
2082     (if (and (setq entity
2083                    (wl-folder-search-entity-by-name fld-name
2084                                                     wl-folder-entity
2085                                                     'folder))
2086              (setq id (wl-folder-get-entity-id entity)))
2087         (wl-folder-set-current-entity-id id))
2088     (setq summary-buf (wl-summary-get-buffer-create fld-name sticky))
2089     (if wl-stay-folder-window
2090         (wl-folder-select-buffer summary-buf)
2091       (if (and summary-buf
2092                (get-buffer-window summary-buf))
2093           (delete-window)))
2094     (wl-summary-goto-folder-subr fld-name
2095                                  (wl-summary-get-sync-range fld-name)
2096                                  nil sticky t)))
2097
2098 (defun wl-folder-suspend ()
2099   (interactive)
2100   (run-hooks 'wl-folder-suspend-hook)
2101   (wl-folder-info-save)
2102   (wl-crosspost-alist-save)
2103   (wl-kill-buffers
2104    (format "^\\(%s\\)$"
2105            (mapconcat 'identity
2106                       (list (format "%s\\(:.*\\)?"
2107                                     (default-value 'wl-message-buf-name))
2108                             wl-original-buf-name)
2109                       "\\|")))
2110   (if (fboundp 'mmelmo-cleanup-entity-buffers)
2111       (mmelmo-cleanup-entity-buffers))
2112   (bury-buffer wl-folder-buffer-name)
2113   (delete-windows-on wl-folder-buffer-name t))
2114
2115 (defun wl-folder-info-save ()
2116   (when (and wl-folder-info-save
2117              wl-folder-info-alist-modified)
2118     (let ((entities (list wl-folder-entity))
2119           entity entity-stack info-alist info)
2120       (while entities
2121         (setq entity (wl-pop entities))
2122         (cond
2123          ((consp entity)
2124           (and entities
2125                (wl-push entities entity-stack))
2126           (setq entities (nth 2 entity)))
2127          ((stringp entity)
2128           (when (and (setq info (elmo-folder-get-info entity))
2129                      (not (equal info '(nil))))
2130             (wl-append info-alist (list (list (elmo-string entity)
2131                                               (list (nth 3 info)  ;; max
2132                                                     (nth 2 info)  ;; length
2133                                                     (nth 0 info)  ;; new
2134                                                     (nth 1 info)) ;; unread
2135                                               ))))))
2136         (unless entities
2137           (setq entities (wl-pop entity-stack))))
2138       (elmo-msgdb-finfo-save info-alist)
2139       (setq wl-folder-info-alist-modified nil))))
2140
2141 (defun wl-folder-goto-first-unread-folder (&optional arg)
2142   (interactive "P")
2143   (let ((entities (list wl-folder-entity))
2144         entity entity-stack ret-val
2145         first-entity finfo)
2146     (setq first-entity
2147           (catch 'done
2148             (while entities
2149               (setq entity (wl-pop entities))
2150               (cond
2151                ((consp entity)
2152                 (and entities
2153                      (wl-push entities entity-stack))
2154                 (setq entities (nth 2 entity)))
2155                ((stringp entity)
2156                 (if (and (setq finfo (wl-folder-get-entity-info entity))
2157                          (and (nth 0 finfo)(nth 1 finfo))
2158                          (> (+ (nth 0 finfo)(nth 1 finfo)) 0))
2159                     (throw 'done entity))
2160                 (wl-append ret-val (list entity))))
2161               (unless entities
2162                 (setq entities (wl-pop entity-stack))))))
2163     (if first-entity
2164         (progn
2165           (when arg
2166             (wl-folder-jump-folder first-entity)
2167             (sit-for 0))
2168           (wl-folder-goto-folder-subr first-entity))
2169       (message "No unread folder"))))
2170
2171 (defun wl-folder-jump-folder (&optional fld-name noopen)
2172   (interactive)
2173   (if (not fld-name)
2174       (setq fld-name (wl-summary-read-folder wl-default-folder)))
2175   (goto-char (point-min))
2176   (if (not noopen)
2177       (wl-folder-open-folder fld-name))
2178   (and (wl-folder-buffer-search-entity fld-name)
2179        (beginning-of-line)))
2180
2181 (defun wl-folder-get-entity-list (entity)
2182   (let ((entities (list entity))
2183         entity-stack ret-val)
2184     (while entities
2185       (setq entity (wl-pop entities))
2186       (cond
2187        ((consp entity)
2188         (and entities
2189              (wl-push entities entity-stack))
2190         (setq entities (nth 2 entity)))
2191        ((stringp entity)
2192         (wl-append ret-val (list entity))))
2193       (unless entities
2194         (setq entities (wl-pop entity-stack))))
2195     ret-val))
2196
2197 (defun wl-folder-open-unread-folder (entity)
2198   (save-excursion
2199     (let ((alist (wl-folder-get-entity-list entity))
2200           (unread 0)
2201           finfo path-list path id)
2202       (while alist
2203         (when (and (setq finfo (wl-folder-get-entity-info (car alist)))
2204                    (nth 0 finfo) (nth 1 finfo)
2205                    (> (+ (nth 0 finfo)(nth 1 finfo)) 0))
2206           (setq unread (+ unread (+ (nth 0 finfo)(nth 1 finfo))))
2207           (setq id (wl-folder-get-entity-id (car alist)))
2208           (setq path (delete id (wl-folder-get-path
2209                                  wl-folder-entity
2210                                  id
2211                                  (car alist))))
2212           (if (not (member path path-list))
2213               (wl-append path-list (list path))))
2214         (setq alist (cdr alist)))
2215       (while path-list
2216         (wl-folder-open-folder-sub (car path-list))
2217         (setq path-list (cdr path-list)))
2218       (message "%s unread folder"
2219                (if (> unread 0) unread "No")))))
2220
2221 (defun wl-folder-open-unread-current-entity ()
2222   (interactive)
2223   (let ((entity-name (wl-folder-get-entity-from-buffer))
2224         (group (wl-folder-buffer-group-p)))
2225     (when entity-name
2226       (wl-folder-open-unread-folder
2227        (if group
2228            (wl-folder-search-group-entity-by-name entity-name
2229                                                   wl-folder-entity)
2230          entity-name)))))
2231
2232 (defun wl-folder-open-only-unread-folder ()
2233   (interactive)
2234   (let ((id (progn
2235               (wl-folder-prev-entity-skip-invalid t)
2236               (wl-folder-get-entity-from-buffer t))))
2237     (wl-folder-open-all-unread-folder)
2238     (save-excursion
2239       (goto-char (point-max))
2240       (while (and (re-search-backward
2241                    "^[ ]*\\[[-]\\].+:0/0/[0-9-]+" nil t)
2242                   (not (bobp)))
2243         (wl-folder-jump-to-current-entity) ;; close it
2244         ))
2245     (wl-folder-move-path id)
2246     (recenter)))
2247
2248 (defun wl-folder-open-all-unread-folder (&optional arg)
2249   (interactive "P")
2250   (let ((id (progn
2251               (wl-folder-prev-entity-skip-invalid t)
2252               (wl-folder-get-entity-from-buffer t))))
2253     (wl-folder-open-unread-folder wl-folder-entity)
2254     (if (not arg)
2255         (wl-folder-move-path id)
2256       (goto-char (point-min))
2257       (wl-folder-next-unread t))))
2258
2259 (defun wl-folder-open-folder (&optional fld-name)
2260   (interactive)
2261   (if (not fld-name)
2262       (setq fld-name (wl-summary-read-folder wl-default-folder)))
2263   (let* ((id (wl-folder-get-entity-id
2264               (wl-folder-search-entity-by-name fld-name wl-folder-entity
2265                                                'folder)))
2266          (path (and id (wl-folder-get-path wl-folder-entity id))))
2267       (if path
2268           (wl-folder-open-folder-sub path))))
2269
2270 (defun wl-folder-open-folder-sub (path)
2271   (let ((inhibit-read-only t)
2272         (buffer-read-only nil)
2273         indent name entity
2274         err)
2275     (save-excursion
2276       (goto-char (point-min))
2277       (while (and path
2278                   (wl-folder-buffer-search-group
2279                    (wl-folder-get-petname
2280                     (if (stringp (car path))
2281                         (car path)
2282                       (wl-folder-get-folder-name-by-id
2283                        (car path))))))
2284         (beginning-of-line)
2285         (setq path (cdr path))
2286         (if (and (looking-at wl-folder-group-regexp)
2287                  (string= "+" (wl-match-buffer 2)));; closed group
2288             (save-excursion
2289               (setq indent (wl-match-buffer 1))
2290               (setq name (wl-folder-get-realname (wl-match-buffer 3)))
2291               (setq entity (wl-folder-search-group-entity-by-name
2292                             name
2293                             wl-folder-entity))
2294               ;; insert as opened
2295               (setcdr (assoc (car entity) wl-folder-group-alist) t)
2296               (if (eq 'access (cadr entity))
2297                   (wl-folder-maybe-load-folder-list entity))
2298               (wl-folder-insert-entity indent entity)
2299               (delete-region (save-excursion (beginning-of-line)
2300                                              (point))
2301                              (save-excursion (end-of-line)
2302                                              (+ 1 (point)))))))
2303       (set-buffer-modified-p nil))))
2304
2305 (defun wl-folder-open-all-pre ()
2306   (let ((entities (list wl-folder-entity))
2307         entity entity-stack group-entry)
2308     (while entities
2309       (setq entity (wl-pop entities))
2310       (cond
2311        ((consp entity)
2312         (unless (or (not (setq group-entry
2313                                (assoc (car entity) wl-folder-group-alist)))
2314                     (cdr group-entry))
2315           (setcdr group-entry t)
2316           (when (eq 'access (cadr entity))
2317             (wl-folder-maybe-load-folder-list entity)))
2318         (and entities
2319              (wl-push entities entity-stack))
2320         (setq entities (nth 2 entity))))
2321       (unless entities
2322         (setq entities (wl-pop entity-stack))))))
2323
2324 (defun wl-folder-open-all (&optional refresh)
2325   (interactive "P")
2326   (let* ((inhibit-read-only t)
2327          (buffer-read-only nil)
2328          (len (length wl-folder-group-alist))
2329          (i 0)
2330          indent name entity)
2331     (if refresh
2332         (let ((id (progn
2333                     (wl-folder-prev-entity-skip-invalid t)
2334                     (wl-folder-get-entity-from-buffer t)))
2335               (alist wl-folder-group-alist))
2336           (while alist
2337             (setcdr (pop alist) t))
2338           (erase-buffer)
2339           (wl-folder-insert-entity " " wl-folder-entity)
2340           (wl-folder-move-path id))
2341       (message "Opening all folders...")
2342       (wl-folder-open-all-pre)
2343       (save-excursion
2344         (goto-char (point-min))
2345         (while (re-search-forward
2346                 "^\\([ ]*\\)\\[\\([+]\\)\\]\\(.+\\):[-0-9-]+/[0-9-]+/[0-9-]+\n"
2347                 nil t)
2348           (setq indent (wl-match-buffer 1))
2349           (setq name (wl-folder-get-realname (wl-match-buffer 3)))
2350           (setq entity (wl-folder-search-group-entity-by-name
2351                         name
2352                         wl-folder-entity))
2353           ;; insert as opened
2354           (setcdr (assoc (car entity) wl-folder-group-alist) t)
2355           (forward-line -1)
2356           (wl-folder-insert-entity indent entity)
2357           (delete-region (save-excursion (beginning-of-line)
2358                                          (point))
2359                          (save-excursion (end-of-line)
2360                                          (+ 1 (point))))
2361           (when (> len elmo-display-progress-threshold)
2362             (setq i (1+ i))
2363             (if (or (zerop (% i 5)) (= i len))
2364                 (elmo-display-progress
2365                  'wl-folder-open-all "Opening all folders..."
2366                  (/ (* i 100) len)))))
2367         (when (> len elmo-display-progress-threshold)
2368           (elmo-display-progress
2369            'wl-folder-open-all "Opening all folders..." 100))))
2370     (message "Opening all folders...done")
2371     (set-buffer-modified-p nil)))
2372
2373 (defun wl-folder-close-all ()
2374   (interactive)
2375   (let ((inhibit-read-only t)
2376         (buffer-read-only nil)
2377         (alist wl-folder-group-alist)
2378         (id (progn
2379               (wl-folder-prev-entity-skip-invalid t)
2380               (wl-folder-get-entity-from-buffer t))))
2381     (while alist
2382       (setcdr (car alist) nil)
2383       (setq alist (cdr alist)))
2384     (setcdr (assoc (car wl-folder-entity) wl-folder-group-alist) t)
2385     (erase-buffer)
2386     (wl-folder-insert-entity " " wl-folder-entity)
2387     (wl-folder-move-path id)
2388     (recenter)
2389     (set-buffer-modified-p nil)))
2390
2391 (defun wl-folder-open-close ()
2392   "Open or close parent entity."
2393   (interactive)
2394   (save-excursion
2395     (beginning-of-line)
2396     (if (wl-folder-buffer-group-p)
2397         ;; if group (whether opend or closed.)
2398         (wl-folder-jump-to-current-entity)
2399       ;; if folder
2400       (let (indent)
2401         (setq indent (save-excursion
2402                        (re-search-forward "\\([ ]*\\)." nil t)
2403                        (wl-match-buffer 1)))
2404         (while (looking-at indent)
2405           (forward-line -1)))
2406       (wl-folder-jump-to-current-entity))))
2407
2408 (defsubst wl-folder-access-subscribe-p (group folder)
2409   (let (subscr regexp match)
2410     (if (setq subscr (wl-get-assoc-list-value
2411                       wl-folder-access-subscribe-alist
2412                       group))
2413         (progn
2414           (setq regexp (mapconcat 'identity (cdr subscr) "\\|"))
2415           (setq match (string-match regexp folder))
2416           (if (car subscr)
2417               match
2418             (not match)))
2419       t)))
2420
2421 (defun wl-folder-update-access-group (entity new-flist)
2422   (let* ((flist (nth 2 entity))
2423          (unsubscribes (nth 3 entity))
2424          (len (+ (length flist) (length unsubscribes)))
2425          (i 0)
2426          diff new-unsubscribes removes
2427          subscribed-list folder group entry)
2428     ;; check subscribed groups
2429     (while flist
2430       (cond
2431        ((listp (car flist))     ;; group
2432         (setq group (elmo-string (caar flist)))
2433         (cond
2434          ((assoc group new-flist)       ;; found in new-flist
2435           (setq new-flist (delete (assoc group new-flist)
2436                                   new-flist))
2437           (if (wl-folder-access-subscribe-p (car entity) group)
2438               (wl-append subscribed-list (list (car flist)))
2439             (wl-append new-unsubscribes (list (car flist)))
2440             (setq diff t)))
2441          (t
2442           (setq wl-folder-group-alist
2443                 (delete (wl-string-assoc group wl-folder-group-alist)
2444                         wl-folder-group-alist))
2445           (wl-append removes (list (list group))))))
2446        (t                       ;; folder
2447         (setq folder (elmo-string (car flist)))
2448         (cond
2449          ((member folder new-flist)     ;; found in new-flist
2450           (setq new-flist (delete folder new-flist))
2451           (if (wl-folder-access-subscribe-p (car entity) folder)
2452               (wl-append subscribed-list (list (car flist)))
2453             (wl-append new-unsubscribes (list folder))
2454             (setq diff t)))
2455          (t
2456           (wl-append removes (list folder))))))
2457       (when (> len elmo-display-progress-threshold)
2458         (setq i (1+ i))
2459         (if (or (zerop (% i 10)) (= i len))
2460             (elmo-display-progress
2461              'wl-folder-update-access-group "Updating access group..."
2462              (/ (* i 100) len))))
2463       (setq flist (cdr flist)))
2464     ;; check unsubscribed groups
2465     (while unsubscribes
2466       (cond
2467        ((listp (car unsubscribes))
2468         (when (setq entry (assoc (caar unsubscribes) new-flist))
2469           (setq new-flist (delete entry new-flist))
2470           (wl-append new-unsubscribes (list (car unsubscribes)))))
2471        (t
2472         (when (member (car unsubscribes) new-flist)
2473           (setq new-flist (delete (car unsubscribes) new-flist))
2474           (wl-append new-unsubscribes (list (car unsubscribes))))))
2475       (when (> len elmo-display-progress-threshold)
2476         (setq i (1+ i))
2477         (if (or (zerop (% i 10)) (= i len))
2478             (elmo-display-progress
2479              'wl-folder-update-access-group "Updating access group..."
2480              (/ (* i 100) len))))
2481       (setq unsubscribes (cdr unsubscribes)))
2482     ;;
2483     (if (or new-flist removes)
2484         (setq diff t))
2485     (setq new-flist
2486           (mapcar '(lambda (x)
2487                      (cond ((consp x) (list (car x) 'access))
2488                            (t x)))
2489                   new-flist))
2490     ;; check new groups
2491     (let ((new-list new-flist))
2492       (while new-list
2493         (if (not (wl-folder-access-subscribe-p
2494                   (car entity)
2495                   (if (listp (car new-list))
2496                       (caar new-list)
2497                     (car new-list))))
2498             ;; auto unsubscribe
2499             (progn
2500               (wl-append new-unsubscribes (list (car new-list)))
2501               (setq new-flist (delete (car new-list) new-flist)))
2502           (cond
2503            ((listp (car new-list))
2504             ;; check group exists
2505             (if (wl-string-assoc (caar new-list) wl-folder-group-alist)
2506                 (progn
2507                   (message "%s: group already exists." (caar new-list))
2508                   (sit-for 1)
2509                   (wl-append new-unsubscribes (list (car new-list)))
2510                   (setq new-flist (delete (car new-list) new-flist)))
2511               (wl-append wl-folder-group-alist
2512                          (list (cons (caar new-list) nil)))))))
2513         (setq new-list (cdr new-list))))
2514     (if new-flist
2515         (message "%d new folder(s)." (length new-flist))
2516       (message "Updating access group...done"))
2517     (wl-append new-flist subscribed-list)       ;; new is first
2518     (run-hooks 'wl-folder-update-access-group-hook)
2519     (setcdr (cdr entity) (list new-flist new-unsubscribes))
2520     (list diff new-flist new-unsubscribes removes)))
2521
2522 (defun wl-folder-prefetch-entity (entity)
2523   "Prefetch all new messages in the ENTITY."
2524   (cond
2525    ((consp entity)
2526     (let ((flist (nth 2 entity))
2527           (sum-done 0)
2528           (sum-all 0)
2529           result)
2530       (while flist
2531         (setq result (wl-folder-prefetch-entity (car flist)))
2532         (setq sum-done (+ sum-done (car result)))
2533         (setq sum-all (+ sum-all (cdr result)))
2534         (setq flist (cdr flist)))
2535       (message "Prefetched %d/%d message(s) in \"%s\"."
2536                sum-done sum-all
2537                (wl-folder-get-petname (car entity)))
2538       (cons sum-done sum-all)))
2539    ((stringp entity)
2540     (let ((nums (wl-folder-get-entity-info entity))
2541           (wl-summary-highlight (if (or (wl-summary-sticky-p entity)
2542                                         (wl-summary-always-sticky-folder-p
2543                                          entity))
2544                                     wl-summary-highlight))
2545           wl-summary-exit-next-move
2546           wl-auto-select-first ret-val
2547           count)
2548       (setq count (or (car nums) 0))
2549       (setq count (+ count (wl-folder-count-incorporates entity)))
2550       (if (or (null (car nums)) ; unknown
2551               (< 0 count))
2552           (save-window-excursion
2553             (save-excursion
2554               (wl-summary-goto-folder-subr entity
2555                                            (wl-summary-get-sync-range entity)
2556                                            nil)
2557               (setq ret-val (wl-summary-incorporate))
2558               (wl-summary-exit)
2559               ret-val))
2560         (cons 0 0))))))
2561
2562 (defun wl-folder-count-incorporates (folder)
2563   (let ((marks (elmo-msgdb-mark-load (elmo-msgdb-expand-path folder)))
2564         (sum 0))
2565     (while marks
2566       (if (member (cadr (car marks))
2567                   wl-summary-incorporate-marks)
2568           (incf sum))
2569       (setq marks (cdr marks)))
2570     sum))
2571
2572 (defun wl-folder-prefetch-current-entity (&optional no-check)
2573   "Prefetch all uncached messages in the folder at position.
2574 If current line is group folder, all subfolders are prefetched."
2575   (interactive "P")
2576   (save-excursion
2577     (let ((entity-name (wl-folder-get-entity-from-buffer))
2578           (group (wl-folder-buffer-group-p))
2579           wl-folder-check-entity-hook
2580           summary-buf entity)
2581       (when entity-name
2582         (setq entity
2583               (if group
2584                   (wl-folder-search-group-entity-by-name entity-name
2585                                                          wl-folder-entity)
2586                 entity-name))
2587         (if (not no-check)
2588             (wl-folder-check-entity entity))
2589         (wl-folder-prefetch-entity entity)))))
2590
2591 (defun wl-folder-drop-unsync-entity (entity)
2592   "Drop all unsync messages in the ENTITY."
2593   (cond
2594    ((consp entity)
2595     (let ((flist (nth 2 entity)))
2596       (while flist
2597         (wl-folder-drop-unsync-entity (car flist))
2598         (setq flist (cdr flist)))))
2599    ((stringp entity)
2600     (let ((nums (wl-folder-get-entity-info entity))
2601           wl-summary-highlight wl-auto-select-first new)
2602       (setq new (or (car nums) 0))
2603       (if (< 0 new)
2604           (save-window-excursion
2605             (save-excursion
2606               (wl-summary-goto-folder-subr entity 'no-sync nil)
2607               (wl-summary-drop-unsync)
2608               (wl-summary-exit))))))))
2609
2610 (defun wl-folder-drop-unsync-current-entity (&optional force-check)
2611   "Drop all unsync messages in the folder at position.
2612 If current line is group folder, all subfolders are dropped.
2613 If optional arg exists, don't check any folders."
2614   (interactive "P")
2615   (save-excursion
2616     (let ((entity-name (wl-folder-get-entity-from-buffer))
2617           (group (wl-folder-buffer-group-p))
2618           wl-folder-check-entity-hook
2619           summary-buf entity)
2620       (when (and entity-name
2621                  (y-or-n-p (format
2622                             "Drop all unsync messages in %s?" entity-name)))
2623         (setq entity
2624               (if group
2625                   (wl-folder-search-group-entity-by-name entity-name
2626                                                          wl-folder-entity)
2627                 entity-name))
2628         (if (null force-check)
2629             (wl-folder-check-entity entity))
2630         (wl-folder-drop-unsync-entity entity)
2631         (message "All unsync messages in %s are dropped!" entity-name)))))
2632
2633 (defun wl-folder-write-current-newsgroup ()
2634   ""
2635   (interactive)
2636   (wl-summary-write-current-newsgroup (wl-folder-entity-name)))
2637
2638 (defun wl-folder-mimic-kill-buffer ()
2639   "Kill the current (Folder) buffer with query."
2640   (interactive)
2641   (let ((bufname (read-buffer (format "Kill buffer: (default %s) "
2642                                       (buffer-name))))
2643         wl-interactive-exit)
2644     (if (or (not bufname)
2645             (string-equal bufname "")
2646             (string-equal bufname (buffer-name)))
2647         (wl-exit)
2648       (kill-buffer bufname))))
2649
2650 (defun wl-folder-create-subr (entity)
2651   (if (not (elmo-folder-creatable-p entity))
2652       (error "Folder %s is not found" entity)
2653     (if (y-or-n-p
2654          (format "Folder %s does not exist, create it?"
2655                  entity))
2656         (progn
2657           (setq wl-folder-entity-hashtb
2658                 (wl-folder-create-entity-hashtb
2659                  entity wl-folder-entity-hashtb))
2660           (unless (elmo-create-folder entity)
2661             (error "Create folder failed")))
2662       (error "Folder %s is not created" entity))))
2663
2664 (defun wl-folder-confirm-existence (folder &optional force)
2665   (if force
2666       (unless (elmo-folder-exists-p folder)
2667         (wl-folder-create-subr folder))
2668     (unless (or (wl-folder-entity-exists-p folder)
2669                 (file-exists-p (elmo-msgdb-expand-path folder))
2670                 (elmo-folder-exists-p folder))
2671       (wl-folder-create-subr folder))))
2672
2673 (require 'product)
2674 (product-provide (provide 'wl-folder) (require 'wl-version))
2675
2676 ;;; wl-folder.el ends here