1 ;;; wl-fldmgr.el --- Folder manager for Wanderlust.
3 ;; Copyright 1998,1999,2000 Masahiro MURATA <muse@ba2.so-net.ne.jp>
4 ;; Yuuichi Teranishi <teranisi@gohome.org>
6 ;; Author: Masahiro MURATA <muse@ba2.so-net.ne.jp>
7 ;; Keywords: mail, net news
9 ;; This file is part of Wanderlust (Yet Another Message Interface on Emacsen).
11 ;; This program is free software; you can redistribute it and/or modify
12 ;; it under the terms of the GNU General Public License as published by
13 ;; the Free Software Foundation; either version 2, or (at your option)
16 ;; This program is distributed in the hope that it will be useful,
17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 ;; GNU General Public License for more details.
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with GNU Emacs; see the file COPYING. If not, write to the
23 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24 ;; Boston, MA 02111-1307, USA.
35 (require 'wl-highlight)
42 (defvar wl-fldmgr-modified nil)
43 (defvar wl-fldmgr-modified-access-list nil)
44 (defvar wl-fldmgr-cut-entity-list nil)
45 (defvar wl-fldmgr-entity-list nil)
46 (defvar wl-fldmgr-group-insert-opened nil)
48 (defconst wl-fldmgr-folders-header
51 # Folder definition file
52 # This file is generated automatically by %s.
54 # If you edit this file by hand, be sure that comment lines
55 # will be washed out by wl-fldmgr.
58 " (product-string-1 'wl-version t)))
62 (defvar wl-fldmgr-mode-map nil)
63 (if wl-fldmgr-mode-map
65 (define-prefix-command 'wl-fldmgr-mode-map)
66 (define-key wl-fldmgr-mode-map "\C-s" 'wl-fldmgr-save-folders)
67 (define-key wl-fldmgr-mode-map "m" 'wl-fldmgr-make-multi)
68 (define-key wl-fldmgr-mode-map "g" 'wl-fldmgr-make-group)
69 (define-key wl-fldmgr-mode-map "A" 'wl-fldmgr-make-access-group)
70 (define-key wl-fldmgr-mode-map "f" 'wl-fldmgr-make-filter)
71 (define-key wl-fldmgr-mode-map "p" 'wl-fldmgr-set-petname)
72 (define-key wl-fldmgr-mode-map "a" 'wl-fldmgr-add)
73 (define-key wl-fldmgr-mode-map "d" 'wl-fldmgr-delete)
74 (define-key wl-fldmgr-mode-map "R" 'wl-fldmgr-rename)
75 (define-key wl-fldmgr-mode-map "c" 'wl-fldmgr-copy)
76 (define-key wl-fldmgr-mode-map "k" 'wl-fldmgr-cut)
77 (define-key wl-fldmgr-mode-map "W" 'wl-fldmgr-copy-region)
78 (define-key wl-fldmgr-mode-map "\C-w" 'wl-fldmgr-cut-region)
79 (define-key wl-fldmgr-mode-map "y" 'wl-fldmgr-yank)
80 (define-key wl-fldmgr-mode-map "s" 'wl-fldmgr-sort)
81 (define-key wl-fldmgr-mode-map "l" 'wl-fldmgr-access-display-normal)
82 (define-key wl-fldmgr-mode-map "L" 'wl-fldmgr-access-display-all)
83 (define-key wl-fldmgr-mode-map "q" 'wl-fldmgr-clear-cut-entity-list)
84 (define-key wl-fldmgr-mode-map "r" 'wl-fldmgr-reconst-entity-hashtb)
85 (define-key wl-fldmgr-mode-map "u" 'wl-fldmgr-unsubscribe)
86 (define-key wl-fldmgr-mode-map "U" 'wl-fldmgr-unsubscribe-region))
88 (add-hook 'wl-folder-mode-hook 'wl-fldmgr-init)
90 (defun wl-fldmgr-init ()
91 (setq wl-fldmgr-cut-entity-list nil)
92 (setq wl-fldmgr-modified nil)
93 (setq wl-fldmgr-modified-access-list nil))
95 (defun wl-fldmgr-exit ()
96 (when (and wl-fldmgr-modified
97 (or (not wl-interactive-save-folders)
99 (concat "Folder view was modified"
100 (and wl-fldmgr-cut-entity-list
101 (format " (%s in cut stack)"
102 (length wl-fldmgr-cut-entity-list)))
103 ". Save current folders? "))))
104 (wl-fldmgr-save-folders)))
106 ;;; Macro and misc Function
109 (defmacro wl-fldmgr-delete-line ()
110 (` (delete-region (save-excursion (beginning-of-line)
112 (save-excursion (end-of-line)
115 (defmacro wl-fldmgr-make-indent (level)
116 (` (concat " " (make-string (* 2 (, level)) ? ))))
118 (defmacro wl-fldmgr-get-entity-id (&optional entity)
119 (` (get-text-property (if (, entity)
125 (defmacro wl-fldmgr-assign-id (entity &optional id)
126 (` (let ((entity-id (or (, id) wl-folder-entity-id)))
127 (put-text-property 0 (length (, entity))
132 (defsubst wl-fldmgr-read-string (str)
133 (if (string-match "\n" str)
134 (error "Not supported name: %s" str)
137 (defsubst wl-fldmgr-add-modified-access-list (group)
138 (if (not (member group wl-fldmgr-modified-access-list))
139 (wl-append wl-fldmgr-modified-access-list (list group))))
141 (defsubst wl-fldmgr-delete-modified-access-list (group)
142 (if (member group wl-fldmgr-modified-access-list)
143 (setq wl-fldmgr-modified-access-list
144 (delete group wl-fldmgr-modified-access-list))))
146 (defsubst wl-fldmgr-add-group (group)
147 (or (assoc group wl-folder-group-alist)
148 (wl-append wl-folder-group-alist
150 wl-fldmgr-group-insert-opened)))))
152 (defsubst wl-fldmgr-delete-group (group)
153 (wl-fldmgr-delete-modified-access-list group)
154 (setq wl-folder-group-alist
155 (delete (assoc group wl-folder-group-alist)
156 wl-folder-group-alist)))
158 (defun wl-fldmgr-add-entity-hashtb (entities)
159 "Update `wl-folder-entity-hashtb', `wl-folder-newsgroups-hashtb'.
160 Return value is diffs '(new unread all)."
164 val entity entity-stack)
165 (setq wl-folder-newsgroups-hashtb
166 (or (wl-folder-create-newsgroups-hashtb entities t)
167 wl-folder-newsgroups-hashtb))
169 (setq entity (wl-pop entities))
172 (wl-fldmgr-add-group (car entity))
174 (wl-push entities entity-stack))
175 (setq entities (nth 2 entity)))
177 (if (not (setq val (wl-folder-get-entity-info entity)))
178 (wl-folder-set-entity-info entity nil)
179 (setq new-diff (+ new-diff (or (nth 0 val) 0)))
180 (setq unread-diff (+ unread-diff (or (nth 1 val) 0)))
181 (setq all-diff (+ all-diff (or (nth 2 val) 0))))))
183 (setq entities (wl-pop entity-stack))))
184 (setq unread-diff (+ unread-diff new-diff))
185 (list new-diff unread-diff all-diff)))
187 (defun wl-fldmgr-delete-entity-hashtb (entities &optional clear)
188 "Update `wl-folder-entity-hashtb'.
189 return value is diffs '(-new -unread -all)."
196 (setq entity (wl-pop entities))
199 (wl-fldmgr-delete-group (car entity))
201 (wl-push entities entity-stack))
202 (setq entities (nth 2 entity)))
204 (when (setq val (wl-folder-get-entity-info entity))
205 (setq new-diff (+ new-diff (or (nth 0 val) 0)))
206 (setq unread-diff (+ unread-diff (or (nth 1 val) 0)))
207 (setq all-diff (+ all-diff (or (nth 2 val) 0)))
208 (and clear (wl-folder-clear-entity-info entity)))))
210 (setq entities (wl-pop entity-stack))))
211 (setq unread-diff (+ unread-diff new-diff))
212 (list (- 0 new-diff) (- 0 unread-diff) (- 0 all-diff))))
215 ;; example: '(("Desktop" group) ("+ml" access) "+ml/wl")
217 (defun wl-fldmgr-get-path (entity target-entity &optional group-target)
218 (let* ((target-id (wl-fldmgr-get-entity-id target-entity))
219 (entities (list entity))
220 entity-stack result-path)
224 (setq entity (wl-pop entities))
227 (if (and (string= target-entity (car entity))
228 (eq target-id (wl-fldmgr-get-entity-id (car entity))))
230 (wl-push (if group-target
232 (list (car entity) (nth 1 entity)))
234 (wl-push (list (car entity) (nth 1 entity))
236 (wl-push entities entity-stack)
237 (setq entities (nth 2 entity)))
239 (if (and (string= target-entity entity)
240 (eq target-id (wl-fldmgr-get-entity-id entity)))
242 (wl-push entity result-path)))))
244 (while (and entity-stack
246 (setq result-path (cdr result-path))
247 (setq entities (wl-pop entity-stack)))))))))
249 ;; (defun wl-fldmgr-get-previous-entity (entity key-id)
250 ;; (cdr (wl-fldmgr-get-previous-entity-internal '(nil . nil) entity key-id)))
252 ;; (defun wl-fldmgr-get-previous-entity-internal (result entity key-id)
255 ;; (if (eq key-id (wl-fldmgr-get-entity-id entity))
257 ;; (cons nil (cons entity entity))))
259 ;; (if (eq key-id (wl-fldmgr-get-entity-id (car entity)))
261 ;; (setcar result (car entity))
262 ;; (let ((flist (nth 2 entity))
264 ;; (while (and flist (not found))
265 ;; (if (car (setq return
266 ;; (wl-fldmgr-get-previous-entity-internal
267 ;; result (car flist) key-id)))
269 ;; (setq result (cdr return))
270 ;; (setq flist (cdr flist)))
271 ;; (cons found result))))))
273 ;; path is get `wl-fldmgr-get-path-from-buffer'.
274 (defun wl-fldmgr-update-group (path diffs)
276 (while (and path (consp (car path)))
277 (if (string= (caar path) wl-folder-desktop-name) ; update desktop
279 (goto-char (point-min))
280 (wl-folder-update-diff-line diffs))
281 ;; goto the path line.
282 (goto-char (point-min))
283 (if (wl-folder-buffer-search-group
284 (wl-folder-get-petname (caar path)))
285 (wl-folder-update-diff-line diffs)))
286 (setq path (cdr path)))))
288 ;;; Function for wl-folder-entity
292 ;; (wl-delete-entity '(("Desktop") ("ML") "+ml/wl") '("+ml/wl") wl-folder-entity)
293 ;; (wl-delete-entity '(("Desktop") "ML") '("+inbox" "ML") wl-folder-entity)
294 ;; (wl-delete-entity '(("Desktop") "ML") nil wl-folder-entity)
296 (defun wl-delete-entity (key-path delete-list entity &optional clear)
297 (let (wl-fldmgr-entity-list)
298 (when (and (string= (caar key-path) (car entity))
299 (wl-delete-entity-sub (cdr key-path) delete-list entity clear))
300 ;; return value is non-nil (diffs)
301 (wl-fldmgr-delete-entity-hashtb wl-fldmgr-entity-list clear))))
303 (defun wl-delete-entity-sub (key-path delete-list entity clear)
304 (let ((flist (nth 2 entity))
308 ((consp key);; into group
309 (if (setq next (assoc (car key) flist))
310 (wl-delete-entity-sub (cdr key-path)
316 ((stringp key) ;; delete entities
317 (if (not delete-list)
318 (setq delete-list (list key)))
319 (let* ((group (car entity))
320 (access (eq (nth 1 entity) 'access))
321 (unsubscribes (and access (nth 3 entity)))
326 (setq key (car delete-list))
327 (cond ((member key flist);; entity
328 (setq flist (delete key flist))
330 (wl-push key wl-fldmgr-cut-entity-list))
331 (wl-append wl-fldmgr-entity-list (list key))
333 ((setq cut-entity (assoc key flist));; group
334 (setq flist (delete cut-entity flist))
336 (wl-push cut-entity wl-fldmgr-cut-entity-list))
337 (wl-append wl-fldmgr-entity-list (list cut-entity))
341 (message "%s not found" key)
344 (when (and access (not clear))
346 (wl-append unsubscribes
347 (list (list (elmo-string key) 'access nil)))
348 (wl-append unsubscribes (list (elmo-string key)))))
349 (setq delete-list (cdr delete-list))))
351 (setcdr (cdr entity) (list flist unsubscribes))
353 (wl-fldmgr-add-modified-access-list group))
358 ;; (wl-add-entity '(("Desktop") ("ML") "ml/wl") '("+ml/new") wl-folder-entity 12)
359 ;; (wl-add-entity '(("Desktop") "ML") '("+ml/new") wl-folder-entity 10)
361 (defun wl-add-entity (key-path new entity prev-entity-id &optional errmes)
362 (when (string= (caar key-path) (car entity))
363 (let ((entities new))
365 (wl-folder-entity-assign-id
366 (pop entities) wl-folder-entity-id-name-hashtb t)))
367 (when (wl-add-entity-sub (cdr key-path) new entity errmes)
368 ;; return value is non-nil (diffs)
369 (wl-fldmgr-add-entity-hashtb new))))
371 (defun wl-add-entity-sub (key-path new entity &optional errmes)
372 (let ((flist (nth 2 entity))
376 ((consp (car key-path));; into group
377 (if (setq entry (assoc (caar key-path) flist))
378 (if (not (wl-add-entity-sub (cdr key-path)
382 (throw 'success nil))
383 (and errmes (message "%s not found" (caar key-path)))
384 (throw 'success nil)))
388 (access (eq (nth 1 entity) 'access))
389 (unsubscribes (and access (nth 3 entity))))
393 ((stringp (car new2)) ;; folder
395 ((elmo-string-member (car new2) flist)
396 (and errmes (message "%s: already exists" (car new2)))
397 (throw 'success nil))
399 (not (elmo-string-member (car new2) unsubscribes)))
400 (and errmes (message "%s: not access group folder" (car new2)))
401 (throw 'success nil))))
404 (not (wl-string-assoc (caar new2) unsubscribes)))
405 (and errmes (message "%s: can't insert access group"
407 (throw 'success nil))))
408 (setq new2 (cdr new2)))
411 ;; remove from unsubscribe
414 (if (consp (car new2))
416 (delq (wl-string-assoc (car (car new2)) unsubscribes)
418 (setq unsubscribes (delete (elmo-string (car new2))
420 (setq new2 (cdr new2)))
421 (setcdr (cddr entity) (list unsubscribes))
422 (wl-fldmgr-add-modified-access-list group))
423 (if (not key-path);; insert group top
425 (setcar (cddr entity) (append new flist))
426 (setcdr (cdr entity) (list new)))
430 (setq akey (car flist))
431 (cond ((consp akey);; group
432 (if (equal (car key-path) (car akey))
435 (if (equal (car key-path) akey)
437 (setq flist (cdr flist))))
438 (setcdr flist (append new (cdr flist)))
439 (and errmes (message "%s not found" (car key-path)))
440 (throw 'success nil)))))))
441 (throw 'success t))))
444 ;; (path indent-level (group . type) previous-entity-id target-entity)
445 ;; previous-entity-id is (id-name-alist-prev-id . entity-alist-prev-id)
447 ;; '((("Desktop" group) ("ML" group) "+ml/wl") '(3 2) ("ML" . group) nil "+ml/wl")
449 (defun wl-fldmgr-get-path-from-buffer (&optional prev)
450 (let ((indent-level 0)
452 folder-path group-type previous-entity entity)
456 ;;; (wl-folder-next-entity-skip-invalid t)
457 ;;; (and (setq previous-entity
458 ;;; (wl-fldmgr-get-previous-entity wl-folder-entity
459 ;;; (wl-fldmgr-get-entity-id)))
460 ;;; ;; change entity to id
461 ;;; (setq previous-entity
463 ;;; (and (car previous-entity)
464 ;;; (wl-fldmgr-get-entity-id (car previous-entity)))
465 ;;; (and (cdr previous-entity)
466 ;;; (wl-fldmgr-get-entity-id (cdr previous-entity))))))
467 (wl-folder-prev-entity-skip-invalid))
469 (wl-folder-buffer-group-p)
470 (looking-at wl-folder-group-regexp)
471 (string= (wl-match-buffer 2) "-"))
472 (setq group-target nil)
473 (if (and prev (bobp))
474 (error "Out of desktop group")))
475 (setq folder-path (wl-fldmgr-get-path wl-folder-entity
476 (wl-folder-get-entity-from-buffer)
477 ;;; (wl-fldmgr-get-entity-id)
479 (let ((fp folder-path))
483 (setq indent-level (1+ indent-level))
484 (setq group-type (cons (caar fp) (nth 1 (car fp)))))
485 (setq entity (car fp)))
487 (list folder-path indent-level group-type previous-entity entity))))
492 (defun wl-fldmgr-clear-cut-entity-list ()
494 (setq wl-fldmgr-cut-entity-list nil)
495 (message "Cleared cut entity list"))
497 (defun wl-fldmgr-reconst-entity-hashtb (&optional arg nomes)
499 (or nomes (message "Reconstructing entity alist..."))
501 (setq wl-folder-entity-id 0)
502 (wl-folder-entity-assign-id wl-folder-entity))
503 (setq wl-folder-entity-hashtb
504 (wl-folder-create-entity-hashtb
506 wl-folder-entity-hashtb
508 ;; reset property on buffer
510 (let ((inhibit-read-only t)
513 (wl-folder-insert-entity " " wl-folder-entity)
514 (goto-char cur-point)
515 (set-buffer-modified-p nil)))
516 (or nomes (message "Reconstructing entity alist...done")))
519 (defun wl-fldmgr-cut-region ()
521 (let* ((p1 (region-beginning))
536 name pre-indent indent)
540 (and (looking-at "^\\([ ]*\\)")
541 (setq pre-indent (wl-match-buffer 1)))
542 (while (< (point) to)
543 (and (looking-at "^\\([ ]*\\)")
544 (setq indent (wl-match-buffer 1)))
545 (cond ((= (length pre-indent) (length indent))
546 (setq pre-indent indent)
547 (setq count (1+ count))
548 (and (setq name (wl-folder-get-entity-from-buffer))
549 (wl-append cut-list (list name)))
551 ((< (length pre-indent) (length indent))
552 (wl-folder-goto-bottom-of-current-folder pre-indent)
555 (setq errmes "bad region")
557 (unless (eq (point) to)
558 (setq errmes "bad region")
561 (let ((count2 (length cut-list))
565 (wl-folder-next-entity-skip-invalid t)
566 (setq tmp (wl-fldmgr-get-path-from-buffer)))
567 (setq path (car tmp))
569 (wl-delete-entity path cut-list wl-folder-entity))
572 (setq ent (looking-at wl-folder-entity-regexp))
573 (if (not (wl-fldmgr-cut (and ent tmp)
574 (and ent (pop cut-list))))
576 (setq count (1- count))))
578 (wl-push count2 wl-fldmgr-cut-entity-list))
580 (wl-fldmgr-update-group path diffs))
584 (message "%s" errmes))))
586 (defun wl-fldmgr-cut (&optional tmp entity clear)
591 (inhibit-read-only t)
594 (message "Can't remove desktop group")
595 (or tmp (setq tmp (wl-fldmgr-get-path-from-buffer)))
596 (setq path (car tmp))
599 (wl-fldmgr-delete-line)) ;; unsubscribe or removed folder
602 (wl-delete-entity path nil wl-folder-entity clear)))
603 (setq wl-fldmgr-modified t)
605 (if (and (wl-folder-buffer-group-p)
606 (looking-at wl-folder-group-regexp))
608 (let (beg end indent opened)
609 (setq indent (wl-match-buffer 1))
610 (setq opened (wl-match-buffer 2))
611 (if (string= opened "+")
612 (wl-fldmgr-delete-line)
618 (wl-folder-goto-bottom-of-current-folder indent)
621 (delete-region beg end)))
623 (wl-fldmgr-delete-line))
625 (wl-fldmgr-update-group path diffs))
626 (set-buffer-modified-p nil))
630 (defun wl-fldmgr-copy-region ()
632 (let* ((p1 (region-beginning))
653 (setq errmes "can't copy desktop group")
655 (and (looking-at "^\\([ ]*\\)")
656 (setq pre-indent (wl-match-buffer 1)))
657 (while (< (point) to)
658 (and (looking-at "^\\([ ]*\\)")
659 (setq indent (wl-match-buffer 1)))
660 (if (wl-folder-buffer-group-p)
662 (setq errmes "can't copy group folder")
664 (cond ((= (length pre-indent) (length indent))
665 (if (setq name (wl-folder-get-entity-from-buffer))
667 (setq pre-indent indent)
668 (wl-push name cut-list)))
670 ((< (length pre-indent) (length indent))
671 (wl-folder-goto-bottom-of-current-folder pre-indent)
674 (setq errmes "bad region")
676 (unless (eq (point) to)
677 (setq errmes "bad region")
680 (setq cut-list (reverse cut-list))
682 (setq name (pop cut-list))
683 (unless (wl-fldmgr-copy name)
685 (setq count (1+ count)))
686 (wl-push count wl-fldmgr-cut-entity-list)
687 (message "Copy %s folders" count)
690 (message "%s" errmes))))
692 (defun wl-fldmgr-copy (&optional ename)
698 (wl-folder-buffer-group-p))
699 (message "Can't copy group folder")
700 (let* ((name (or ename (wl-folder-get-entity-from-buffer)))
701 (entity (elmo-string name)))
703 (if (member entity wl-fldmgr-cut-entity-list)
704 (setq wl-fldmgr-cut-entity-list
705 (delete entity wl-fldmgr-cut-entity-list)))
706 (wl-push entity wl-fldmgr-cut-entity-list)
708 (message "Copy: %s" name))
712 (defun wl-fldmgr-yank ()
717 (message "Can't insert in the out of desktop group")
718 (let ((inhibit-read-only t)
719 (top (car wl-fldmgr-cut-entity-list))
720 tmp indent path count new
721 access new-list diffs)
723 (message "No cut buffer")
724 (setq tmp (wl-fldmgr-get-path-from-buffer t))
725 (setq path (car tmp))
726 (setq indent (wl-fldmgr-make-indent (nth 1 tmp)))
728 (setq count (pop wl-fldmgr-cut-entity-list))
732 (cut-list wl-fldmgr-cut-entity-list))
733 ;; check insert entity
735 (setq new (car cut-list))
736 (wl-push new new-list)
737 (when (consp new);; group
740 (message "Can't insert group in access")
742 ((wl-string-assoc (car new) wl-folder-group-alist)
743 (message "%s: group already exists" (car new))
745 (setq cut-list (cdr cut-list))
746 (setq count (1- count))))
749 path new-list wl-folder-entity (nth 3 tmp) t)))
752 (setq new (pop wl-fldmgr-cut-entity-list))
754 (wl-folder-insert-entity indent new)
755 (setq wl-fldmgr-modified t))
756 (setq count (1- count)))
757 (wl-fldmgr-update-group path diffs)
758 (set-buffer-modified-p nil))
760 (wl-push count wl-fldmgr-cut-entity-list)))))))
762 (defvar wl-fldmgr-add-completion-hashtb (make-vector 7 0))
764 (defun wl-fldmgr-add-completion-all-completions (string)
770 (if (string-match (symbol-name atom) string)
771 (throw 'found (symbol-value atom)))))
772 wl-fldmgr-add-completion-hashtb)))
774 (if (string-match "\\.$"
775 (elmo-folder-prefix-internal
776 (wl-folder-get-elmo-folder string)))
777 (substring string 0 (match-beginning 0))
778 (concat string nil))))
780 (setq table (elmo-folder-list-subfolders
781 (wl-folder-get-elmo-folder pattern)))
783 (or (/= (length table) 1)
784 (elmo-folder-exists-p (wl-folder-get-elmo-folder
787 (if (string-match "\\.[^\\.]+$" string)
788 (substring string 0 (match-beginning 0))
789 (char-to-string (aref string 0)))
790 table (elmo-folder-list-subfolders
791 (wl-folder-get-elmo-folder pattern))))
792 (setq pattern (concat "^" (regexp-quote pattern)))
793 (unless (intern-soft pattern wl-fldmgr-add-completion-hashtb)
794 (set (intern pattern wl-fldmgr-add-completion-hashtb) table))
797 (defun wl-fldmgr-add-completion-subr (string predicate flag)
799 (if (string= string "")
800 (mapcar (function (lambda (spec)
801 (list (char-to-string (car spec)))))
802 elmo-folder-type-alist)
803 (when (assq (aref string 0) elmo-folder-type-alist)
807 (wl-fldmgr-add-completion-all-completions string)
811 (try-completion string table predicate))
813 (eq t (try-completion string table predicate)))
815 (all-completions string table predicate)))))
817 (defun wl-fldmgr-add (&optional name)
822 (inhibit-read-only t)
823 (wl-folder-complete-folder-candidate
824 (if wl-fldmgr-add-complete-with-current-folder-list
825 (function wl-fldmgr-add-completion-subr)))
826 tmp indent path diffs)
828 (message "Can't insert in the out of desktop group")
829 (setq tmp (wl-fldmgr-get-path-from-buffer t))
830 (setq path (car tmp))
831 (setq indent (wl-fldmgr-make-indent (nth 1 tmp)))
833 (setq name (wl-fldmgr-read-string
834 (wl-summary-read-folder wl-default-folder
836 (let ((parent (nth 2 (wl-fldmgr-get-path-from-buffer))))
837 (if (eq (cdr parent) 'access)
839 (format "^%s" (regexp-quote (car parent))) name)
840 ;; force update access group
842 (wl-folder-confirm-existence
843 (wl-folder-get-elmo-folder name))
844 (wl-folder-open-close)
845 (wl-folder-jump-to-current-entity t)
847 (error "Can't insert folder under access group"))
848 (wl-folder-confirm-existence (wl-folder-get-elmo-folder name))
849 ;; maybe add elmo-plugged-alist.
850 (elmo-folder-set-plugged (wl-folder-get-elmo-folder
851 (if (listp name) (car name) name))
855 path (list name) wl-folder-entity (nth 3 tmp) t))
856 (wl-folder-insert-entity indent name)
857 (wl-fldmgr-update-group path diffs)
858 (setq wl-fldmgr-modified t)
859 (set-buffer-modified-p nil)
863 (defun wl-fldmgr-delete ()
867 (if (wl-folder-buffer-group-p)
868 (error "Can't delete group folder"))
869 (let* ((inhibit-read-only t)
870 (tmp (wl-fldmgr-get-path-from-buffer))
871 (entity (elmo-string (nth 4 tmp)))
872 (folder (wl-folder-get-elmo-folder entity)))
873 (when (elmo-folder-delete folder)
874 (wl-folder-clear-entity-info entity)
875 (wl-fldmgr-cut tmp nil t)
876 (wl-fldmgr-save-access-list)))))
878 (defun wl-fldmgr-rename ()
883 (message "Can't rename desktop group")
885 ((and (wl-folder-buffer-group-p)
886 (looking-at wl-folder-group-regexp)) ;; group
887 (let* ((indent (wl-match-buffer 1))
888 (old-group (wl-folder-get-entity-from-buffer))
889 (group-entity (wl-folder-search-group-entity-by-name
890 old-group wl-folder-entity))
892 (if (eq (nth 1 group-entity) 'access)
893 (message "%s: can't rename access group folder" old-group)
894 (setq group (wl-fldmgr-read-string
895 (read-from-minibuffer "Rename: " old-group)))
896 (if (string-match "/$" group)
897 (message "Remove tail slash.")
899 ((or (string= group "")
900 (string= old-group group))
903 (if (wl-string-assoc group wl-folder-group-alist)
904 (message "%s: group already exists" group)
905 (let ((inhibit-read-only t)
906 (id (wl-fldmgr-get-entity-id
907 (car group-entity))))
908 (wl-fldmgr-assign-id group id)
909 (setcar group-entity group)
910 (setcar (wl-string-assoc old-group wl-folder-group-alist)
912 ;;; (setcdr (assq id wl-folder-entity-id-name-alist) group)
913 (wl-folder-set-id-name id group)
914 (wl-fldmgr-delete-line)
915 (wl-folder-insert-entity
918 (setq wl-fldmgr-modified t)
919 (set-buffer-modified-p nil)))))))))
921 (let* ((tmp (wl-fldmgr-get-path-from-buffer))
922 (old-folder (nth 4 tmp))
924 (unless old-folder (error "No folder"))
926 (wl-fldmgr-read-string
927 (wl-summary-read-folder old-folder "to rename" t t old-folder)))
928 (if (or (wl-folder-entity-exists-p new-folder)
929 (file-exists-p (elmo-folder-msgdb-path
930 (wl-folder-get-elmo-folder new-folder))))
931 (error "Already exists folder: %s" new-folder))
932 (if (and (eq (cdr (nth 2 tmp)) 'access)
933 (null wl-fldmgr-allow-rename-access-group)
935 (format "^%s" (regexp-quote (car (nth 2 tmp))))
937 (error "Can't rename access folder"))
938 (elmo-folder-rename (wl-folder-get-elmo-folder old-folder)
940 (wl-folder-set-entity-info
942 (wl-folder-get-entity-info old-folder))
943 (wl-folder-clear-entity-info old-folder)
944 (setq wl-folder-info-alist-modified t)
945 (if (eq (cdr (nth 2 tmp)) 'access)
947 ;; force update access group
949 (wl-folder-open-close)
950 (wl-folder-jump-to-current-entity t)
951 (message "%s is renamed to %s" old-folder new-folder)
953 ;; update folder list
954 (when (wl-fldmgr-cut tmp nil t)
955 (wl-fldmgr-add new-folder)))))))))
957 (defun wl-fldmgr-make-access-group ()
959 (wl-fldmgr-make-group nil t))
961 (defun wl-fldmgr-make-group (&optional group-name access)
966 (message "Can't insert in the out of desktop group")
967 (let ((inhibit-read-only t)
969 group tmp indent path new prev-id flist diffs)
970 (setq tmp (wl-fldmgr-get-path-from-buffer t))
971 (setq path (car tmp))
972 (setq indent (wl-fldmgr-make-indent (nth 1 tmp)))
973 (setq prev-id (nth 3 tmp))
974 (if (eq (cdr (nth 2 tmp)) 'access)
975 (message "Can't insert access group")
976 (setq group (or group-name
977 (wl-fldmgr-read-string
978 (read-from-minibuffer
979 (if access "Access Type Group: " "Group: ")))))
980 ;; To check the folder name is correct.
981 (if access (elmo-make-folder group))
982 (when (or access (string-match "[\t ]*/$" group))
983 (setq group (if access group
984 (substring group 0 (match-beginning 0))))
986 (setq flist (wl-create-access-folder-entity group)))
987 (if (string= group "")
989 (if (wl-string-assoc group wl-folder-group-alist)
990 (message "%s: group already exists" group)
991 (setq new (append (list group type) flist))
992 (when (setq diffs (wl-add-entity path
996 (wl-folder-insert-entity indent new)
997 (wl-fldmgr-update-group path diffs)
998 (setq wl-fldmgr-modified t)
999 (set-buffer-modified-p nil)))))))))
1001 (defun wl-fldmgr-make-multi ()
1003 (if (not wl-fldmgr-cut-entity-list)
1004 (message "No cut buffer")
1005 (let ((cut-entity wl-fldmgr-cut-entity-list)
1013 ((numberp (car cut-entity))
1015 ((consp (car cut-entity))
1016 (message "Can't make multi included group folder")
1019 (let ((folder (wl-folder-get-elmo-folder
1022 (if (eq (elmo-folder-type-internal folder) 'multi)
1024 (substring (car cut-entity) 1)))
1027 (or multi-fld (car cut-entity))
1031 (setq cut-entity (cdr cut-entity)))
1034 (setq new-entity (concat "*" new-entity))
1035 (wl-fldmgr-add new-entity)))))
1037 (defun wl-fldmgr-make-filter ()
1041 (let ((tmp (wl-fldmgr-get-path-from-buffer))
1043 (if (eq (cdr (nth 2 tmp)) 'access)
1044 (message "Can't change access group")
1045 (if (wl-folder-buffer-group-p)
1049 (mapconcat 'identity
1050 (wl-folder-get-entity-list
1051 (wl-folder-search-group-entity-by-name
1053 wl-folder-entity)) ",")))
1054 (setq entity (nth 4 tmp)))
1055 (unless entity (error "No folder"))
1056 (wl-fldmgr-add (concat "/"
1057 (wl-read-search-condition
1058 wl-fldmgr-make-filter-default)
1061 (defun wl-fldmgr-sort (&optional arg)
1065 (let ((inhibit-read-only t)
1066 entity flist indent opened)
1067 (when (and (wl-folder-buffer-group-p)
1068 (looking-at wl-folder-group-regexp)
1070 (y-or-n-p (format "Sort subfolders of %s? "
1071 (wl-folder-get-entity-from-buffer)))
1073 (setq indent (wl-match-buffer 1))
1074 (setq opened (wl-match-buffer 2))
1075 (setq entity (wl-folder-search-group-entity-by-name
1076 (wl-folder-get-entity-from-buffer)
1078 (message "Sorting...")
1079 (setq flist (sort (nth 2 entity) wl-fldmgr-sort-function))
1080 (when arg (setq flist (nreverse flist)))
1081 (setcar (cddr entity) flist)
1082 (wl-fldmgr-add-modified-access-list (car entity))
1083 (setq wl-fldmgr-modified t)
1084 (when (string= opened "-")
1091 (wl-folder-goto-bottom-of-current-folder indent)
1094 (delete-region beg end)
1095 (wl-folder-insert-entity indent entity)))
1096 (message "Sorting...done")
1097 (set-buffer-modified-p nil)))))
1099 (defun wl-fldmgr-sort-standard (x y)
1100 (cond ((and (consp x) (not (consp y)))
1101 wl-fldmgr-sort-group-first)
1102 ((and (not (consp x)) (consp y))
1103 (not wl-fldmgr-sort-group-first))
1104 ((and (consp x) (consp y))
1105 (string-lessp (car x) (car y)))
1107 (string-lessp x y))))
1109 (defun wl-fldmgr-subscribe-region ()
1111 (wl-fldmgr-unsubscribe-region -1))
1113 (defun wl-fldmgr-unsubscribe-region (&optional arg)
1115 (let* ((p1 (region-beginning))
1129 (while (< (point) to)
1130 (setq count (1+ count))
1133 (message "Unsubscribe region...")
1134 (while (and (> count 0)
1135 (wl-fldmgr-unsubscribe (or arg 1) t))
1136 (setq count (1- count)))
1137 (message "Unsubscribe region...done")))
1139 (defun wl-fldmgr-subscribe ()
1141 (wl-fldmgr-unsubscribe -1))
1143 (defun wl-fldmgr-unsubscribe (&optional arg force)
1145 (let ((type (and arg (prefix-numeric-value arg)))
1149 (let ((inhibit-read-only t)
1153 ((looking-at (format "^[ ]*%s\\[[+-]\\]\\(.*\\)" wl-folder-unsubscribe-mark))
1154 (if (and type (> type 0))
1156 (setq folder (list (wl-match-buffer 1) 'access nil))
1157 (if (wl-string-assoc (car folder) wl-folder-group-alist)
1158 (message "%s: group already exists" (car folder))
1159 (wl-fldmgr-delete-line)
1160 (when (wl-fldmgr-add folder)
1161 (wl-folder-maybe-load-folder-list folder)
1162 ;;; (wl-folder-search-group-entity-by-name (car folder)
1163 ;;; wl-folder-entity)
1165 ((looking-at (format "^[ ]*%s\\(.*\\)" wl-folder-unsubscribe-mark))
1166 (if (and type (> type 0))
1168 (setq folder (wl-match-buffer 1))
1169 (wl-fldmgr-delete-line)
1170 (when (wl-fldmgr-add folder)
1173 (if (and type (< type 0))
1175 (setq is-group (wl-folder-buffer-group-p))
1176 (setq tmp (wl-fldmgr-get-path-from-buffer))
1177 (setq indent (wl-fldmgr-make-indent (nth 1 tmp)))
1178 (if (eq (cdr (nth 2 tmp)) 'access)
1179 (when (wl-fldmgr-cut tmp)
1180 ;; don't leave cut-list
1181 (setq wl-fldmgr-cut-entity-list (cdr wl-fldmgr-cut-entity-list))
1183 (insert indent wl-folder-unsubscribe-mark
1185 (concat "[+]" (nth 4 tmp))
1188 (save-excursion (forward-line -1)
1189 (wl-highlight-folder-current-line))
1190 (remove-text-properties beg (point) '(wl-folder-entity-id))
1192 (message "not an access group folder")))))
1193 (set-buffer-modified-p nil)))
1194 (if (or force execed)
1199 (defun wl-fldmgr-access-display-normal (&optional arg)
1201 (wl-fldmgr-access-display-all (not arg)))
1203 (defun wl-fldmgr-access-display-all (&optional arg)
1205 (let ((id (save-excursion
1206 (wl-folder-prev-entity-skip-invalid t)
1207 (wl-fldmgr-get-entity-id))))
1210 (let ((inhibit-read-only t)
1211 entity indent opened
1214 (and (wl-folder-buffer-group-p)
1215 (looking-at wl-folder-group-regexp)))
1216 (wl-folder-goto-top-of-current-folder)
1217 (looking-at wl-folder-group-regexp))
1218 (setq indent (wl-match-buffer 1))
1219 (setq opened (wl-match-buffer 2))
1220 (setq entity (wl-folder-search-group-entity-by-name
1221 (wl-folder-get-entity-from-buffer)
1223 (when (eq (nth 1 entity) 'access)
1225 (if (string= opened "-")
1232 (wl-folder-goto-bottom-of-current-folder indent)
1235 (delete-region beg end))
1236 (wl-fldmgr-delete-line)
1237 (setcdr (assoc (car entity) wl-folder-group-alist) t));; set open
1238 (wl-folder-insert-entity indent entity))
1240 (setq unsubscribes (nth 3 entity))
1244 (insert indent " " wl-folder-unsubscribe-mark
1245 (if (consp (car unsubscribes))
1246 (concat "[+]" (caar unsubscribes))
1249 (remove-text-properties beg (point) '(wl-folder-entity-id))
1250 (save-excursion (forward-line -1)
1251 (wl-highlight-folder-current-line))
1252 (setq unsubscribes (cdr unsubscribes))))
1253 (set-buffer-modified-p nil))))
1254 (wl-folder-move-path id)))
1256 (defun wl-fldmgr-set-petname ()
1260 (let* ((is-group (wl-folder-buffer-group-p))
1261 (name (wl-folder-get-entity-from-buffer))
1262 (searchname (wl-folder-get-petname name))
1263 (pentry (wl-string-assoc name wl-folder-petname-alist))
1264 (old-petname (or (cdr pentry) ""))
1267 (unless name (error "No folder"))
1269 (not (eq (nth 1 (wl-folder-search-group-entity-by-name
1270 name wl-folder-entity))
1272 (message "Can't set petname. please rename.")
1273 (setq petname (wl-fldmgr-read-string
1274 (read-from-minibuffer "Petname: " old-petname)))
1276 ((string= petname "")
1278 (setq wl-folder-petname-alist
1279 (delete pentry wl-folder-petname-alist))
1282 (if (string= petname old-petname)
1284 (if (or (rassoc petname wl-folder-petname-alist)
1286 (wl-string-assoc petname wl-folder-group-alist)))
1287 (message "%s: already exists" petname)
1288 (wl-folder-append-petname name petname)
1291 (let ((inhibit-read-only t)
1293 (goto-char (point-min))
1296 (if (string= old-petname "")
1297 (setq old-petname name))
1298 (while (wl-folder-buffer-search-group old-petname)
1300 (and (looking-at "^\\([ ]*\\)")
1301 (setq indent (wl-match-buffer 1)))
1302 (wl-fldmgr-delete-line)
1303 (wl-folder-insert-entity
1305 (wl-folder-search-group-entity-by-name
1306 name wl-folder-entity)
1308 (while (wl-folder-buffer-search-entity name searchname)
1311 (and (looking-at "^\\([ ]*\\)")
1312 (setq indent (wl-match-buffer 1)))
1313 (wl-fldmgr-delete-line))
1314 (wl-folder-insert-entity indent name)))
1315 (setq wl-fldmgr-modified t)
1316 (set-buffer-modified-p nil)))))))
1318 ;;; Function for save folders
1321 (defun wl-fldmgr-insert-folders-buffer (indent entities &optional pet-entities)
1322 (let ((flist entities)
1325 (setq name (car flist))
1326 (cond ((stringp name)
1327 (if (setq petname (cdr (wl-string-assoc name wl-folder-petname-alist)))
1328 (wl-append pet-entities (list name)))
1331 (concat "\t\"" petname "\"")
1335 (let ((group (car name))
1336 (type (nth 1 name)))
1337 (cond ((eq type 'group)
1338 (insert indent group "{\n")
1340 (wl-fldmgr-insert-folders-buffer
1341 (concat indent wl-fldmgr-folders-indent)
1342 (nth 2 name) pet-entities))
1343 (insert indent "}\n"))
1345 (insert indent group "/\n"))))))
1346 (setq flist (cdr flist))))
1349 (defun wl-fldmgr-insert-petname-buffer (pet-entities)
1350 (let ((alist wl-folder-petname-alist))
1352 (if (wl-string-member (caar alist) pet-entities)
1354 (insert "=\t" (caar alist) "\t\"" (cdar alist) "\"\n"))
1355 (setq alist (cdr alist)))))
1357 (defun wl-fldmgr-delete-disused-petname ()
1358 (let ((alist wl-folder-petname-alist))
1360 (unless (wl-folder-search-entity-by-name (caar alist) wl-folder-entity)
1361 (setq wl-folder-petname-alist
1362 (delete (car alist) wl-folder-petname-alist)))
1363 (setq alist (cdr alist)))))
1365 (defun wl-fldmgr-save-folders ()
1367 (let ((tmp-buf (get-buffer-create " *wl-fldmgr-tmp*"))
1368 save-petname-entities)
1369 (message "Saving folders...")
1370 (set-buffer tmp-buf)
1372 (insert wl-fldmgr-folders-header)
1373 (wl-fldmgr-delete-disused-petname)
1374 (setq save-petname-entities
1375 (wl-fldmgr-insert-folders-buffer "" (nth 2 wl-folder-entity)))
1376 (insert "\n# petname definition (access group, folder in access group)\n")
1377 (wl-fldmgr-insert-petname-buffer save-petname-entities)
1378 (insert "\n# end of file.\n")
1379 (if (and wl-fldmgr-make-backup
1380 (file-exists-p wl-folders-file))
1381 (rename-file wl-folders-file (concat wl-folders-file ".bak") t))
1382 (let ((output-coding-system (mime-charset-to-coding-system
1390 (set-file-modes wl-folders-file (+ (* 64 6) (* 8 0) 0))) ; chmod 0600
1391 (kill-buffer tmp-buf)
1392 (wl-fldmgr-save-access-list)
1393 (setq wl-fldmgr-modified nil)
1394 (message "Saving folders...done")))
1396 (defun wl-fldmgr-save-access-list ()
1397 (let ((access-list wl-fldmgr-modified-access-list)
1400 (setq entity (wl-folder-search-group-entity-by-name
1401 (car access-list) wl-folder-entity))
1402 (elmo-msgdb-flist-save
1405 (wl-folder-make-save-access-list (nth 2 entity))
1406 (wl-folder-make-save-access-list (nth 3 entity))))
1407 (setq access-list (cdr access-list)))
1408 (setq wl-fldmgr-modified-access-list nil)))
1411 (product-provide (provide 'wl-fldmgr) (require 'wl-version))
1413 ;;; wl-fldmgr.el ends here