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
8 ;; Time-stamp: <2000-04-07 10:40:40 teranisi>
10 ;; This file is part of Wanderlust (Yet Another Message Interface on Emacsen).
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)
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.
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.
36 (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
50 # Folder definition file
51 # This file is generated automatically by %s %s (%s).
56 (defconst wl-fldmgr-filter-completion-alist
71 (defvar wl-fldmgr-mode-map nil)
72 (if wl-fldmgr-mode-map
74 (define-prefix-command 'wl-fldmgr-mode-map)
75 (define-key wl-fldmgr-mode-map "\C-s" 'wl-fldmgr-save-folders)
76 (define-key wl-fldmgr-mode-map "m" 'wl-fldmgr-make-multi)
77 (define-key wl-fldmgr-mode-map "g" 'wl-fldmgr-make-group)
78 (define-key wl-fldmgr-mode-map "A" 'wl-fldmgr-make-access-group)
79 (define-key wl-fldmgr-mode-map "f" 'wl-fldmgr-make-filter)
80 (define-key wl-fldmgr-mode-map "p" 'wl-fldmgr-set-petname)
81 (define-key wl-fldmgr-mode-map "a" 'wl-fldmgr-add)
82 (define-key wl-fldmgr-mode-map "d" 'wl-fldmgr-delete)
83 (define-key wl-fldmgr-mode-map "R" 'wl-fldmgr-rename)
84 (define-key wl-fldmgr-mode-map "c" 'wl-fldmgr-copy)
85 (define-key wl-fldmgr-mode-map "k" 'wl-fldmgr-cut)
86 (define-key wl-fldmgr-mode-map "W" 'wl-fldmgr-copy-region)
87 (define-key wl-fldmgr-mode-map "\C-w" 'wl-fldmgr-cut-region)
88 (define-key wl-fldmgr-mode-map "y" 'wl-fldmgr-yank)
89 (define-key wl-fldmgr-mode-map "s" 'wl-fldmgr-sort)
90 (define-key wl-fldmgr-mode-map "l" 'wl-fldmgr-access-display-normal)
91 (define-key wl-fldmgr-mode-map "L" 'wl-fldmgr-access-display-all)
92 (define-key wl-fldmgr-mode-map "q" 'wl-fldmgr-clear-cut-entity-list)
93 (define-key wl-fldmgr-mode-map "r" 'wl-fldmgr-reconst-entity-hashtb)
94 (define-key wl-fldmgr-mode-map "u" 'wl-fldmgr-unsubscribe)
95 (define-key wl-fldmgr-mode-map "U" 'wl-fldmgr-unsubscribe-region))
97 (add-hook 'wl-folder-mode-hook 'wl-fldmgr-init)
99 (defun wl-fldmgr-init ()
100 (setq wl-fldmgr-cut-entity-list nil)
101 (setq wl-fldmgr-modified nil)
102 (setq wl-fldmgr-modified-access-list nil))
104 (defun wl-fldmgr-exit ()
105 (when (and wl-fldmgr-modified
106 (or (not wl-interactive-save-folders)
107 (y-or-n-p "Folder view was modified. Save current folders? ")))
108 (wl-fldmgr-save-folders)))
110 ;;; Macro and misc Function
113 (defmacro wl-fldmgr-delete-line ()
114 (` (delete-region (save-excursion (beginning-of-line)
116 (save-excursion (end-of-line)
119 (defmacro wl-fldmgr-make-indent (level)
120 (` (concat " " (make-string (* 2 (, level)) ? ))))
122 (defmacro wl-fldmgr-get-entity-id (&optional entity)
123 (` (get-text-property (if (, entity)
129 (defmacro wl-fldmgr-assign-id (entity &optional id)
130 (` (let ((entity-id (or (, id) wl-folder-entity-id)))
131 (put-text-property 0 (length (, entity))
136 (defsubst wl-fldmgr-read-string (str)
137 (if (string-match "\n" str)
138 (error "Not supported name: %s" str)
141 (defsubst wl-fldmgr-add-modified-access-list (group)
142 (if (not (member group wl-fldmgr-modified-access-list))
143 (wl-append wl-fldmgr-modified-access-list (list group))))
145 (defsubst wl-fldmgr-delete-modified-access-list (group)
146 (if (member group wl-fldmgr-modified-access-list)
147 (setq wl-fldmgr-modified-access-list
148 (delete group wl-fldmgr-modified-access-list))))
150 (defsubst wl-fldmgr-add-group (group)
151 (or (assoc group wl-folder-group-alist)
152 (wl-append wl-folder-group-alist
154 wl-fldmgr-group-insert-opened)))))
156 (defsubst wl-fldmgr-delete-group (group)
157 (wl-fldmgr-delete-modified-access-list group)
158 (setq wl-folder-group-alist
159 (delete (assoc group wl-folder-group-alist)
160 wl-folder-group-alist)))
162 (defun wl-fldmgr-add-entity-hashtb (entities)
163 "update `wl-folder-entity-hashtb', `wl-folder-newsgroups-hashtb'.
164 return value is diffs '(new unread all)."
168 val entity entity-stack)
169 (setq wl-folder-newsgroups-hashtb
170 (or (wl-folder-create-newsgroups-hashtb entities t)
171 wl-folder-newsgroups-hashtb))
173 (setq entity (wl-pop entities))
176 (wl-fldmgr-add-group (car entity))
178 (wl-push entities entity-stack))
179 (setq entities (nth 2 entity)))
181 (if (not (setq val (wl-folder-get-entity-info entity)))
182 (wl-folder-set-entity-info entity nil)
183 (setq new-diff (+ new-diff (or (nth 0 val) 0)))
184 (setq unread-diff (+ unread-diff (or (nth 1 val) 0)))
185 (setq all-diff (+ all-diff (or (nth 2 val) 0))))))
187 (setq entities (wl-pop entity-stack))))
188 (setq unread-diff (+ unread-diff new-diff))
189 (list new-diff unread-diff all-diff)))
191 (defun wl-fldmgr-delete-entity-hashtb (entities &optional clear)
192 "update `wl-folder-entity-hashtb'.
193 return value is diffs '(-new -unread -all)."
200 (setq entity (wl-pop entities))
203 (wl-fldmgr-delete-group (car entity))
205 (wl-push entities entity-stack))
206 (setq entities (nth 2 entity)))
208 (when (setq val (wl-folder-get-entity-info entity))
209 (setq new-diff (+ new-diff (or (nth 0 val) 0)))
210 (setq unread-diff (+ unread-diff (or (nth 1 val) 0)))
211 (setq all-diff (+ all-diff (or (nth 2 val) 0)))
212 (and clear (wl-folder-clear-entity-info entity)))))
214 (setq entities (wl-pop entity-stack))))
215 (setq unread-diff (+ unread-diff new-diff))
216 (list (- 0 new-diff) (- 0 unread-diff) (- 0 all-diff))))
219 ;; example: '(("Desktop" group) ("+ml" access) "+ml/wl")
221 (defun wl-fldmgr-get-path (entity target-entity &optional group-target)
222 (let* ((target-id (wl-fldmgr-get-entity-id target-entity))
223 (entities (list entity))
224 entity-stack result-path)
228 (setq entity (wl-pop entities))
231 (if (and (string= target-entity (car entity))
232 (eq target-id (wl-fldmgr-get-entity-id (car entity))))
234 (wl-push (if group-target
236 (list (car entity) (nth 1 entity)))
238 (wl-push (list (car entity) (nth 1 entity))
240 (wl-push entities entity-stack)
241 (setq entities (nth 2 entity)))
243 (if (and (string= target-entity entity)
244 (eq target-id (wl-fldmgr-get-entity-id entity)))
246 (wl-push entity result-path)))))
248 (while (and entity-stack
250 (setq result-path (cdr result-path))
251 (setq entities (wl-pop entity-stack)))))))))
253 ;; (defun wl-fldmgr-get-previous-entity (entity key-id)
254 ;; (cdr (wl-fldmgr-get-previous-entity-internal '(nil . nil) entity key-id)))
256 ;; (defun wl-fldmgr-get-previous-entity-internal (result entity key-id)
259 ;; (if (eq key-id (wl-fldmgr-get-entity-id entity))
261 ;; (cons nil (cons entity entity))))
263 ;; (if (eq key-id (wl-fldmgr-get-entity-id (car entity)))
265 ;; (setcar result (car entity))
266 ;; (let ((flist (nth 2 entity))
268 ;; (while (and flist (not found))
269 ;; (if (car (setq return
270 ;; (wl-fldmgr-get-previous-entity-internal
271 ;; result (car flist) key-id)))
273 ;; (setq result (cdr return))
274 ;; (setq flist (cdr flist)))
275 ;; (cons found result))))))
277 ;; path is get `wl-fldmgr-get-path-from-buffer'.
278 (defun wl-fldmgr-update-group (path diffs)
280 (while (and path (consp (car path)))
281 (if (string= (caar path) wl-folder-desktop-name) ; update desktop
283 (goto-char (point-min))
284 (wl-folder-update-diff-line diffs))
285 ;; goto the path line.
286 (goto-char (point-min))
287 (if (wl-folder-buffer-search-group
288 (wl-folder-get-petname (caar path)))
289 (wl-folder-update-diff-line diffs)))
290 (setq path (cdr path)))))
292 ;;; Function for wl-folder-entity
296 ;; (wl-delete-entity '(("Desktop") ("ML") "+ml/wl") '("+ml/wl") wl-folder-entity)
297 ;; (wl-delete-entity '(("Desktop") "ML") '("+inbox" "ML") wl-folder-entity)
298 ;; (wl-delete-entity '(("Desktop") "ML") nil wl-folder-entity)
300 (defun wl-delete-entity (key-path delete-list entity &optional clear)
301 (let (wl-fldmgr-entity-list)
302 (when (and (string= (caar key-path) (car entity))
303 (wl-delete-entity-sub (cdr key-path) delete-list entity clear))
304 ;; return value is non-nil (diffs)
305 (wl-fldmgr-delete-entity-hashtb wl-fldmgr-entity-list clear))))
307 (defun wl-delete-entity-sub (key-path delete-list entity clear)
308 (let ((flist (nth 2 entity))
312 ((consp key);; into group
313 (if (setq next (assoc (car key) flist))
314 (wl-delete-entity-sub (cdr key-path)
320 ((stringp key) ;; delete entities
321 (if (not delete-list)
322 (setq delete-list (list key)))
323 (let* ((group (car entity))
324 (access (eq (nth 1 entity) 'access))
325 (unsubscribes (and access (nth 3 entity)))
330 (setq key (car delete-list))
331 (cond ((member key flist);; entity
332 (setq flist (delete key flist))
334 (wl-push key wl-fldmgr-cut-entity-list))
335 (wl-append wl-fldmgr-entity-list (list key))
337 ((setq cut-entity (assoc key flist));; group
338 (setq flist (delete cut-entity flist))
340 (wl-push cut-entity wl-fldmgr-cut-entity-list))
341 (wl-append wl-fldmgr-entity-list (list cut-entity))
345 (message "%s not found" key)
350 (wl-append unsubscribes
351 (list (list (elmo-string key) 'access nil)))
352 (wl-append unsubscribes (list (elmo-string key)))))
353 (setq delete-list (cdr delete-list))))
355 (setcdr (cdr entity) (list flist unsubscribes))
357 (wl-fldmgr-add-modified-access-list group))
362 ;; (wl-add-entity '(("Desktop") ("ML") "ml/wl") '("+ml/new") wl-folder-entity 12)
363 ;; (wl-add-entity '(("Desktop") "ML") '("+ml/new") wl-folder-entity 10)
365 (defun wl-add-entity (key-path new entity prev-entity-id &optional errmes)
366 (when (string= (caar key-path) (car entity))
369 (wl-folder-entity-assign-id
371 wl-folder-entity-id-name-hashtb
374 (when (wl-add-entity-sub (cdr key-path) new entity errmes)
375 ;; return value is non-nil (diffs)
376 (wl-fldmgr-add-entity-hashtb new))))
378 (defun wl-add-entity-sub (key-path new entity &optional errmes)
379 (let ((flist (nth 2 entity))
383 ((consp (car key-path));; into group
384 (if (setq entry (assoc (caar key-path) flist))
385 (if (not (wl-add-entity-sub (cdr key-path)
389 (throw 'success nil))
390 (and errmes (message "%s not found" (caar key-path)))
391 (throw 'success nil)))
395 (access (eq (nth 1 entity) 'access))
396 (unsubscribes (and access (nth 3 entity))))
400 ((stringp (car new2)) ;; folder
402 ((wl-string-member (car new2) flist)
403 (and errmes (message "%s: already exists" (car new2)))
404 (throw 'success nil))
406 (not (wl-string-member (car new2) unsubscribes)))
407 (and errmes (message "%s: not access group folder" (car new2)))
408 (throw 'success nil))))
411 (not (wl-string-assoc (caar new2) unsubscribes)))
412 (and errmes (message "%s: can't insert access group"
414 (throw 'success nil))))
415 (setq new2 (cdr new2)))
418 ;; remove from unsubscribe
424 (delete (wl-string-assoc (car x) unsubscribes)
427 (setq unsubscribes (delete (elmo-string x) unsubscribes)))))
431 ;; (setq unsubscribes (delete (elmo-string (car new2)) unsubscribes))
432 ;; (setq new2 (cdr new2)))
433 (setcdr (cddr entity) (list unsubscribes))
434 (wl-fldmgr-add-modified-access-list group))
435 (if (not key-path);; insert group top
437 (setcar (cddr entity) (append new flist))
438 (setcdr (cdr entity) (list new)))
442 (setq akey (car flist))
443 (cond ((consp akey);; group
444 (if (equal (car key-path) (car akey))
447 (if (equal (car key-path) akey)
449 (setq flist (cdr flist))))
450 (setcdr flist (append new (cdr flist)))
451 (and errmes (message "%s not found" (car key-path)))
452 (throw 'success nil)))))))
453 (throw 'success t))))
456 ;; (path indent-level (group . type) previous-entity-id target-entity)
457 ;; previous-entity-id is (id-name-alist-prev-id . entity-alist-prev-id)
459 ;; '((("Desktop" group) ("ML" group) "+ml/wl") '(3 2) ("ML" . group) nil "+ml/wl")
461 (defun wl-fldmgr-get-path-from-buffer (&optional prev)
462 (let ((indent-level 0)
464 folder-path group-type previous-entity entity)
468 ;; (wl-folder-next-entity-skip-invalid t)
469 ;; (and (setq previous-entity
470 ;; (wl-fldmgr-get-previous-entity wl-folder-entity
471 ;; (wl-fldmgr-get-entity-id)))
472 ;; ;; change entity to id
473 ;; (setq previous-entity
475 ;; (and (car previous-entity)
476 ;; (wl-fldmgr-get-entity-id (car previous-entity)))
477 ;; (and (cdr previous-entity)
478 ;; (wl-fldmgr-get-entity-id (cdr previous-entity))))))
479 (wl-folder-prev-entity-skip-invalid))
481 (looking-at wl-folder-group-regexp)
482 (string= (wl-match-buffer 2) "-"))
483 (setq group-target nil)
484 (if (and prev (bobp))
485 (error "out of desktop group")))
486 (setq folder-path (wl-fldmgr-get-path wl-folder-entity
487 (wl-folder-get-entity-from-buffer)
488 ;;(wl-fldmgr-get-entity-id)
490 (let ((fp folder-path))
494 (setq indent-level (1+ indent-level))
495 (setq group-type (cons (caar fp) (nth 1 (car fp)))))
496 (setq entity (car fp)))
498 (list folder-path indent-level group-type previous-entity entity))))
503 (defun wl-fldmgr-clear-cut-entity-list ()
505 (setq wl-fldmgr-cut-entity-list nil)
506 (message "Cleared cut entity list"))
508 (defun wl-fldmgr-reconst-entity-hashtb (&optional arg nomes)
510 (or nomes (message "Reconstructing entity alist..."))
512 (setq wl-folder-entity-id 0)
513 (wl-folder-entity-assign-id wl-folder-entity))
514 (setq wl-folder-entity-hashtb
515 (wl-folder-create-entity-hashtb
517 wl-folder-entity-hashtb
519 ;; reset property on buffer
521 (let ((inhibit-read-only t)
524 (wl-folder-insert-entity " " wl-folder-entity)
525 (goto-char cur-point)
526 (set-buffer-modified-p nil)))
527 (or nomes (message "Reconstructing entity alist...done")))
530 (defun wl-fldmgr-cut-region ()
532 (let* ((p1 (region-beginning))
547 name pre-indent indent)
551 (and (looking-at "^\\([ ]*\\)")
552 (setq pre-indent (wl-match-buffer 1)))
553 (while (< (point) to)
554 (and (looking-at "^\\([ ]*\\)")
555 (setq indent (wl-match-buffer 1)))
556 (cond ((= (length pre-indent) (length indent))
557 (setq pre-indent indent)
558 (setq count (1+ count))
559 (and (setq name (wl-folder-get-entity-from-buffer))
560 (wl-append cut-list (list name)))
562 ((< (length pre-indent) (length indent))
563 (wl-folder-goto-bottom-of-current-folder pre-indent)
566 (setq errmes "bad region")
568 (unless (eq (point) to)
569 (setq errmes "bad region")
572 (let ((count2 (length cut-list))
576 (wl-folder-next-entity-skip-invalid t)
577 (setq tmp (wl-fldmgr-get-path-from-buffer)))
578 (setq path (car tmp))
580 (wl-delete-entity path cut-list wl-folder-entity))
583 (setq ent (looking-at wl-folder-entity-regexp))
584 (if (not (wl-fldmgr-cut (and ent tmp)
585 (and ent (pop cut-list))))
587 (setq count (1- count))))
589 (wl-push count2 wl-fldmgr-cut-entity-list))
591 (wl-fldmgr-update-group path diffs))
595 (message "%s" errmes))))
597 (defun wl-fldmgr-cut (&optional tmp entity clear)
602 (inhibit-read-only t)
605 (message "Can't remove desktop group")
606 (or tmp (setq tmp (wl-fldmgr-get-path-from-buffer)))
607 (setq path (car tmp))
610 (wl-fldmgr-delete-line)) ;; unsubscribe or removed folder
613 (wl-delete-entity path nil wl-folder-entity clear)))
614 (setq wl-fldmgr-modified t)
616 (if (looking-at wl-folder-group-regexp)
618 (let (beg end indent opened)
619 (setq indent (wl-match-buffer 1))
620 (setq opened (wl-match-buffer 2))
621 (if (string= opened "+")
622 (wl-fldmgr-delete-line)
628 (wl-folder-goto-bottom-of-current-folder indent)
631 (delete-region beg end)))
633 (wl-fldmgr-delete-line))
635 (wl-fldmgr-update-group path diffs))
636 (set-buffer-modified-p nil))
640 (defun wl-fldmgr-copy-region ()
642 (let* ((p1 (region-beginning))
663 (setq errmes "can't copy desktop group")
665 (and (looking-at "^\\([ ]*\\)")
666 (setq pre-indent (wl-match-buffer 1)))
667 (while (< (point) to)
668 (and (looking-at "^\\([ ]*\\)")
669 (setq indent (wl-match-buffer 1)))
670 (if (looking-at wl-folder-group-regexp)
672 (setq errmes "can't copy group folder")
674 (cond ((= (length pre-indent) (length indent))
675 (if (setq name (wl-folder-get-entity-from-buffer))
677 (setq pre-indent indent)
678 (wl-push name cut-list)))
680 ((< (length pre-indent) (length indent))
681 (wl-folder-goto-bottom-of-current-folder pre-indent)
684 (setq errmes "bad region")
686 (unless (eq (point) to)
687 (setq errmes "bad region")
690 (setq cut-list (reverse cut-list))
692 (setq name (pop cut-list))
693 (unless (wl-fldmgr-copy name)
695 (setq count (1+ count)))
696 (wl-push count wl-fldmgr-cut-entity-list)
697 (message "Copy %s folders" count)
700 (message "%s" errmes))))
702 (defun wl-fldmgr-copy (&optional ename)
708 (looking-at wl-folder-group-regexp))
709 (message "Can't copy group folder")
710 (let* ((name (or ename (wl-folder-get-entity-from-buffer)))
711 (entity (elmo-string name)))
713 (if (member entity wl-fldmgr-cut-entity-list)
714 (setq wl-fldmgr-cut-entity-list
715 (delete entity wl-fldmgr-cut-entity-list)))
716 (wl-push entity wl-fldmgr-cut-entity-list)
718 (message "Copy: %s" name))
722 (defun wl-fldmgr-yank ()
727 (message "Can't insert in the out of desktop group")
728 (let ((inhibit-read-only t)
729 (top (car wl-fldmgr-cut-entity-list))
730 tmp indent path count new
731 access new-list diffs)
733 (message "No cut buffer")
734 (setq tmp (wl-fldmgr-get-path-from-buffer t))
735 (setq path (car tmp))
736 (setq indent (wl-fldmgr-make-indent (nth 1 tmp)))
738 (setq count (pop wl-fldmgr-cut-entity-list))
742 (cut-list wl-fldmgr-cut-entity-list))
743 ;; check insert entity
745 (setq new (car cut-list))
746 (wl-push new new-list)
747 (when (consp new);; group
750 (message "Can't insert group in access")
752 ((wl-string-assoc (car new) wl-folder-group-alist)
753 (message "%s: group already exists" (car new))
755 (setq cut-list (cdr cut-list))
756 (setq count (1- count))))
759 path new-list wl-folder-entity (nth 3 tmp) t)))
762 (setq new (pop wl-fldmgr-cut-entity-list))
764 (wl-folder-insert-entity indent new)
765 (setq wl-fldmgr-modified t))
766 (setq count (1- count)))
767 (wl-fldmgr-update-group path diffs)
768 (set-buffer-modified-p nil))
770 (wl-push count wl-fldmgr-cut-entity-list)))))))
772 (defvar wl-fldmgr-add-completion-hashtb (make-vector 7 0))
774 (defun wl-fldmgr-add-completion-all-completions (string)
780 (if (string-match (symbol-name atom) string)
781 (throw 'found (symbol-value atom)))))
782 wl-fldmgr-add-completion-hashtb)))
784 (if (string-match "\\.$"
785 (car (elmo-network-get-spec
786 string nil nil nil)))
787 (substring string 0 (match-beginning 0))
788 (concat string nil))))
790 (setq table (elmo-list-folders pattern))
792 (or (/= (length table) 1)
793 (elmo-folder-exists-p (car table))))
795 (if (string-match "\\.[^\\.]+$" string)
796 (substring string 0 (match-beginning 0))
797 (char-to-string (aref string 0)))
798 table (elmo-list-folders pattern)))
799 (setq pattern (concat "^" (regexp-quote pattern)))
800 (unless (intern-soft pattern wl-fldmgr-add-completion-hashtb)
801 (set (intern pattern wl-fldmgr-add-completion-hashtb) table))
804 (defun wl-fldmgr-add-completion-subr (string predicate flag)
806 (if (string= string "")
807 (mapcar (function (lambda (spec)
808 (list (char-to-string (car spec)))))
810 (when (assq (aref string 0) elmo-spec-alist)
814 (wl-fldmgr-add-completion-all-completions string)
817 (try-completion string table predicate)
818 (if (eq flag 'lambda)
819 (eq t (try-completion string table predicate))
821 (all-completions string table predicate))))))
823 (defun wl-fldmgr-add (&optional name)
828 (inhibit-read-only t)
829 (wl-folder-completion-func
830 (if wl-fldmgr-add-complete-with-current-folder-list
831 (function wl-fldmgr-add-completion-subr)))
832 tmp indent path diffs)
834 (message "Can't insert in the out of desktop group")
835 (setq tmp (wl-fldmgr-get-path-from-buffer t))
836 (setq path (car tmp))
837 (setq indent (wl-fldmgr-make-indent (nth 1 tmp)))
839 (setq name (wl-fldmgr-read-string
840 (wl-summary-read-folder wl-default-folder "to add"))))
841 ;; maybe add elmo-plugged-alist.
843 (elmo-folder-set-plugged name wl-plugged t))
846 path (list name) wl-folder-entity (nth 3 tmp) t))
847 (wl-folder-insert-entity indent name)
848 (wl-fldmgr-update-group path diffs)
849 (setq wl-fldmgr-modified t)
850 (set-buffer-modified-p nil)
854 (defun wl-fldmgr-delete ()
858 (if (looking-at wl-folder-group-regexp)
859 (error "can't delete group folder"))
860 (let* ((inhibit-read-only t)
861 (tmp (wl-fldmgr-get-path-from-buffer))
862 (entity (elmo-string (nth 4 tmp)))
863 (msgs (and (elmo-folder-exists-p entity)
864 (elmo-list-folder entity))))
865 (when (yes-or-no-p (format "%sDo you really delete \"%s\"? "
866 (if (> (length msgs) 0)
867 (format "%d msg(s) exists. " (length msgs))
870 (elmo-delete-folder entity)
871 (wl-fldmgr-cut tmp nil t)))))
873 (defun wl-fldmgr-rename ()
878 (message "Can't rename desktop group")
880 ((looking-at wl-folder-group-regexp) ;; group
881 (let* ((indent (wl-match-buffer 1))
882 (old-group (wl-folder-get-realname (wl-match-buffer 3)))
883 (group-entity (wl-folder-search-group-entity-by-name
884 old-group wl-folder-entity))
886 (if (eq (nth 1 group-entity) 'access)
887 (message "%s: can't rename access group folder" old-group)
888 (setq group (wl-fldmgr-read-string
889 (read-from-minibuffer "Rename: " old-group)))
890 (if (string-match "/$" group)
891 (message "Remove tail slash.")
893 ((or (string= group "")
894 (string= old-group group))
897 (if (wl-string-assoc group wl-folder-group-alist)
898 (message "%s: group already exists" group)
899 (let ((inhibit-read-only t)
900 (id (wl-fldmgr-get-entity-id
901 (car group-entity))))
902 (wl-fldmgr-assign-id group id)
903 (setcar group-entity group)
904 (setcar (wl-string-assoc old-group wl-folder-group-alist)
906 ;;(setcdr (assq id wl-folder-entity-id-name-alist) group)
907 (wl-folder-set-id-name id group)
908 (wl-fldmgr-delete-line)
909 (wl-folder-insert-entity
912 (setq wl-fldmgr-modified t)
913 (set-buffer-modified-p nil)))))))))
915 (let* ((tmp (wl-fldmgr-get-path-from-buffer))
916 (old-folder (nth 4 tmp))
918 (if (eq (cdr (nth 2 tmp)) 'access)
919 (error "can't rename access folder"))
921 (wl-fldmgr-read-string
922 (wl-summary-read-folder old-folder "to rename" t t old-folder)))
923 (if (or (wl-folder-entity-exists-p new-folder)
924 (file-exists-p (elmo-msgdb-expand-path new-folder)))
925 (error "already exists folder: %s" new-folder))
926 (elmo-rename-folder old-folder new-folder)
927 (wl-folder-set-entity-info
929 (wl-folder-get-entity-info old-folder))
930 (when (wl-fldmgr-cut tmp nil t)
931 (wl-fldmgr-add new-folder))))))))
933 (defun wl-fldmgr-make-access-group ()
935 (wl-fldmgr-make-group nil t))
937 (defun wl-fldmgr-make-group (&optional group-name access)
942 (message "Can't insert in the out of desktop group")
943 (let ((inhibit-read-only t)
945 group tmp indent path new prev-id flist diffs)
946 (setq tmp (wl-fldmgr-get-path-from-buffer t))
947 (setq path (car tmp))
948 (setq indent (wl-fldmgr-make-indent (nth 1 tmp)))
949 (setq prev-id (nth 3 tmp))
950 (if (eq (cdr (nth 2 tmp)) 'access)
951 (message "Can't insert access group")
952 (setq group (or group-name
953 (wl-fldmgr-read-string
954 (read-from-minibuffer
955 (if access "Access Type Group: " "Group: ")))))
956 (when (or access (string-match "[\t ]*/$" group))
957 (setq group (if access group
958 (substring group 0 (match-beginning 0))))
960 (setq flist (wl-create-access-folder-entity group)))
961 (if (string= group "")
963 (if (wl-string-assoc group wl-folder-group-alist)
964 (message "%s: group already exists" group)
965 (setq new (append (list group type) flist))
966 (when (setq diffs (wl-add-entity path
970 (wl-folder-insert-entity indent new)
971 (wl-fldmgr-update-group path diffs)
972 (setq wl-fldmgr-modified t)
973 (set-buffer-modified-p nil)))))))))
975 (defun wl-fldmgr-make-multi ()
977 (if (not wl-fldmgr-cut-entity-list)
978 (message "No cut buffer")
979 (let ((cut-entity wl-fldmgr-cut-entity-list)
987 ((numberp (car cut-entity))
989 ((consp (car cut-entity))
990 (message "Can't make multi included group folder")
993 (let ((spec (elmo-folder-get-spec (car cut-entity)))
995 (if (eq (car spec) 'multi)
997 (substring (car cut-entity) 1)))
1000 (or multi-fld (car cut-entity))
1004 (setq cut-entity (cdr cut-entity)))
1007 (setq new-entity (concat "*" new-entity))
1008 (wl-fldmgr-add new-entity)))))
1010 (defun wl-fldmgr-make-filter ()
1014 (if (looking-at wl-folder-group-regexp)
1015 (message "This folder is group")
1016 (let ((tmp (wl-fldmgr-get-path-from-buffer)))
1017 (if (eq (cdr (nth 2 tmp)) 'access)
1018 (message "Tan't change access group")
1019 (let* ((entity (nth 4 tmp))
1023 (unless entity (error "no folder"))
1024 (when (string-match "^\\(\\(/[^/]+/\\)+\\)\\(.*\\)" entity)
1025 (setq old-filter (substring entity
1028 (setq old-entity (substring entity
1031 (setq filter (completing-read "Filter: "
1032 wl-fldmgr-filter-completion-alist
1034 (or old-filter "/")))
1035 (unless (or (string= filter "")
1036 (string-match "/$" filter))
1037 (setq filter (concat filter "/")))
1038 (setq new-entity (concat filter old-entity))
1039 (let ((entity new-entity)
1041 ;; check filter syntax
1043 (car (setq spec (elmo-folder-get-spec entity)))
1045 (setq entity (nth 2 spec))))
1046 (wl-fldmgr-add new-entity)))))))
1048 (defun wl-fldmgr-sort ()
1052 (let ((inhibit-read-only t)
1053 entity flist indent opened)
1054 (when (looking-at wl-folder-group-regexp)
1055 (setq indent (wl-match-buffer 1))
1056 (setq opened (wl-match-buffer 2))
1057 (setq entity (wl-folder-search-group-entity-by-name
1058 (wl-folder-get-realname (wl-match-buffer 3))
1060 (message "Sorting...")
1061 (setq flist (sort (nth 2 entity) wl-fldmgr-sort-func))
1062 (setcar (cddr entity) flist)
1063 (wl-fldmgr-add-modified-access-list (car entity))
1064 (setq wl-fldmgr-modified t)
1066 (when (string= opened "-")
1073 (wl-folder-goto-bottom-of-current-folder indent)
1076 (delete-region beg end)
1077 (wl-folder-insert-entity indent entity)))
1078 ;;(wl-fldmgr-reconst-entity-hashtb t t)
1079 (message "Sorting...done")
1080 (set-buffer-modified-p nil)))))
1082 (defun wl-fldmgr-sort-standard (x y)
1083 (cond ((and (consp x) (not (consp y)))
1084 wl-fldmgr-sort-group-first)
1085 ((and (not (consp x)) (consp y))
1086 (not wl-fldmgr-sort-group-first))
1087 ((and (consp x) (consp y))
1088 (string-lessp (car x) (car y)))
1090 (string-lessp x y))))
1092 (defun wl-fldmgr-subscribe-region ()
1094 (wl-fldmgr-unsubscribe-region -1))
1096 (defun wl-fldmgr-unsubscribe-region (&optional arg)
1098 (let* ((p1 (region-beginning))
1112 (while (< (point) to)
1113 (setq count (1+ count))
1116 (message "Unsubscribe region...")
1117 (while (and (> count 0)
1118 (wl-fldmgr-unsubscribe (or arg 1) t))
1119 (setq count (1- count)))
1120 (message "Unsubscribe region...done")))
1122 (defun wl-fldmgr-subscribe ()
1124 (wl-fldmgr-unsubscribe -1))
1126 (defun wl-fldmgr-unsubscribe (&optional arg force)
1128 (let ((type (and arg (prefix-numeric-value arg)))
1132 (let ((inhibit-read-only t)
1136 ((looking-at (format "^[ ]*%s\\[[+-]\\]\\(.*\\)" wl-folder-unsubscribe-mark))
1137 (if (and type (> type 0))
1139 (setq folder (list (wl-match-buffer 1) 'access nil))
1140 (if (wl-string-assoc (car folder) wl-folder-group-alist)
1141 (message "%s: group already exists" (car folder))
1142 (wl-fldmgr-delete-line)
1143 (when (wl-fldmgr-add folder)
1144 (wl-folder-maybe-load-folder-list folder)
1145 ;; (wl-folder-search-group-entity-by-name (car folder)
1146 ;; wl-folder-entity))
1148 ((looking-at (format "^[ ]*%s\\(.*\\)" wl-folder-unsubscribe-mark))
1149 (if (and type (> type 0))
1151 (setq folder (wl-match-buffer 1))
1152 (wl-fldmgr-delete-line)
1153 (when (wl-fldmgr-add folder)
1156 (if (and type (< type 0))
1158 (setq is-group (looking-at wl-folder-group-regexp))
1159 (setq tmp (wl-fldmgr-get-path-from-buffer))
1160 (setq indent (wl-fldmgr-make-indent (nth 1 tmp)))
1161 (if (eq (cdr (nth 2 tmp)) 'access)
1162 (when (wl-fldmgr-cut tmp)
1163 (pop wl-fldmgr-cut-entity-list) ;; don't leave cut-list
1165 (insert indent wl-folder-unsubscribe-mark
1167 (concat "[+]" (nth 4 tmp))
1170 (save-excursion (forward-line -1)
1171 (wl-highlight-folder-current-line))
1172 (remove-text-properties beg (point) '(wl-folder-entity-id))
1173 (setq execed t))))))
1174 (set-buffer-modified-p nil)))
1175 (if (or force execed)
1180 (defun wl-fldmgr-access-display-normal (&optional arg)
1182 (wl-fldmgr-access-display-all (not arg)))
1184 (defun wl-fldmgr-access-display-all (&optional arg)
1186 (let ((id (save-excursion
1187 (wl-folder-prev-entity-skip-invalid t)
1188 (wl-fldmgr-get-entity-id))))
1191 (let ((inhibit-read-only t)
1192 entity indent opened
1194 (when (not (looking-at wl-folder-group-regexp))
1195 (wl-folder-goto-top-of-current-folder)
1196 (looking-at wl-folder-group-regexp))
1197 (setq indent (wl-match-buffer 1))
1198 (setq opened (wl-match-buffer 2))
1199 (setq entity (wl-folder-search-group-entity-by-name
1200 (wl-folder-get-realname (wl-match-buffer 3))
1202 (when (eq (nth 1 entity) 'access)
1204 (if (string= opened "-")
1211 (wl-folder-goto-bottom-of-current-folder indent)
1214 (delete-region beg end))
1215 (wl-fldmgr-delete-line)
1216 (setcdr (assoc (car entity) wl-folder-group-alist) t));; set open
1217 (wl-folder-insert-entity indent entity))
1219 (setq unsubscribes (nth 3 entity))
1223 (insert indent " " wl-folder-unsubscribe-mark
1224 (if (consp (car unsubscribes))
1225 (concat "[+]" (caar unsubscribes))
1228 (remove-text-properties beg (point) '(wl-folder-entity-id))
1229 (save-excursion (forward-line -1)
1230 (wl-highlight-folder-current-line))
1231 (setq unsubscribes (cdr unsubscribes))))
1232 (set-buffer-modified-p nil))))
1233 (wl-folder-move-path id)))
1235 (defun wl-fldmgr-set-petname ()
1239 (let* ((is-group (looking-at wl-folder-group-regexp))
1240 (name (wl-folder-get-entity-from-buffer))
1241 (searchname (wl-folder-get-petname name))
1242 (pentry (wl-string-assoc name wl-folder-petname-alist))
1243 (old-petname (or (cdr pentry) ""))
1246 (unless name (error "no folder"))
1248 (not (eq (nth 1 (wl-folder-search-group-entity-by-name
1249 name wl-folder-entity))
1251 (message "Can't set petname. please rename.")
1252 (setq petname (wl-fldmgr-read-string
1253 (read-from-minibuffer "Petname: " old-petname)))
1255 ((string= petname "")
1257 (setq wl-folder-petname-alist
1258 (delete pentry wl-folder-petname-alist))
1261 (if (string= petname old-petname)
1263 (if (or (rassoc petname wl-folder-petname-alist)
1264 (wl-string-assoc petname wl-folder-group-alist))
1265 (message "%s: already exists" petname)
1266 (wl-folder-append-petname name petname)
1269 (let ((inhibit-read-only t)
1271 (goto-char (point-min))
1274 (if (string= old-petname "")
1275 (setq old-petname name))
1276 (while (wl-folder-buffer-search-group old-petname)
1278 (and (looking-at "^\\([ ]*\\)")
1279 (setq indent (wl-match-buffer 1)))
1280 (wl-fldmgr-delete-line)
1281 (wl-folder-insert-entity
1283 (wl-folder-search-group-entity-by-name
1284 name wl-folder-entity)
1286 (while (wl-folder-buffer-search-entity name searchname)
1289 (and (looking-at "^\\([ ]*\\)")
1290 (setq indent (wl-match-buffer 1)))
1291 (wl-fldmgr-delete-line))
1292 (wl-folder-insert-entity indent name)))
1293 (setq wl-fldmgr-modified t)
1294 (set-buffer-modified-p nil)))))))
1296 ;;; Function for save folders
1299 (defun wl-fldmgr-insert-folders-buffer (indent entities &optional pet-entities)
1300 (let ((flist entities)
1303 (setq name (car flist))
1304 (cond ((stringp name)
1305 (if (setq petname (cdr (wl-string-assoc name wl-folder-petname-alist)))
1306 (wl-append pet-entities (list name)))
1309 (concat "\t\"" petname "\"")
1313 (let ((group (wl-folder-get-realname (car name)))
1314 (type (nth 1 name)))
1315 (if (not (string= group (car name))) ; petname.
1316 (wl-append pet-entities (list (car name))))
1317 (cond ((eq type 'group)
1318 (insert indent group "{\n")
1320 (wl-fldmgr-insert-folders-buffer
1321 (concat indent wl-fldmgr-folders-indent)
1322 (nth 2 name) pet-entities))
1323 (insert indent "}\n"))
1325 (insert indent group "/\n"))))))
1326 (setq flist (cdr flist))))
1329 (defun wl-fldmgr-insert-petname-buffer (pet-entities)
1330 (let ((alist wl-folder-petname-alist))
1332 (if (wl-string-member (caar alist) pet-entities)
1334 (insert "=\t" (caar alist) "\t\"" (cdar alist) "\"\n"))
1335 (setq alist (cdr alist)))))
1337 (defun wl-fldmgr-delete-disused-petname ()
1338 (let ((alist wl-folder-petname-alist))
1340 (unless (wl-folder-search-entity-by-name (caar alist) wl-folder-entity)
1341 (setq wl-folder-petname-alist
1342 (delete (car alist) wl-folder-petname-alist)))
1343 (setq alist (cdr alist)))))
1345 (defun wl-fldmgr-save-folders ()
1347 (let ((tmp-buf (get-buffer-create " *wl-fldmgr-tmp*"))
1348 (access-list wl-fldmgr-modified-access-list)
1350 save-petname-entities)
1351 (message "Saving folders...")
1352 (set-buffer tmp-buf)
1354 (insert (format wl-fldmgr-folders-header
1355 wl-appname wl-version wl-codename))
1356 (wl-fldmgr-delete-disused-petname)
1357 (setq save-petname-entities
1358 (wl-fldmgr-insert-folders-buffer "" (nth 2 wl-folder-entity)))
1359 (insert "\n# petname definition (group, folder in access group)\n")
1360 (wl-fldmgr-insert-petname-buffer save-petname-entities)
1361 (insert "\n# end of file.\n")
1362 (if (and wl-fldmgr-make-backup
1363 (file-exists-p wl-folders-file))
1364 (rename-file wl-folders-file (concat wl-folders-file ".bak") t))
1365 (let ((output-coding-system (mime-charset-to-coding-system
1373 (set-file-modes wl-folders-file 384)) ; 600
1374 (kill-buffer tmp-buf)
1376 (setq entity (wl-folder-search-group-entity-by-name
1377 (car access-list) wl-folder-entity))
1378 (elmo-msgdb-flist-save
1381 (wl-folder-make-save-access-list (nth 2 entity))
1382 (wl-folder-make-save-access-list (nth 3 entity))))
1383 (setq access-list (cdr access-list)))
1384 (setq wl-fldmgr-modified nil)
1385 (setq wl-fldmgr-modified-access-list nil)
1386 (message "Saving folders...done")))
1388 (provide 'wl-fldmgr)
1390 ;;; wl-fldmgr.el ends here