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
) ,(string-to-char " "))))
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
"to add"))))
835 ;; maybe add elmo-plugged-alist.
836 (elmo-folder-set-plugged (wl-folder-get-elmo-folder
837 (if (listp name
) (car name
) name
))
841 path
(list name
) wl-folder-entity
(nth 3 tmp
) t
))
842 (wl-folder-insert-entity indent name
)
843 (wl-fldmgr-update-group path diffs
)
844 (setq wl-fldmgr-modified t
)
845 (set-buffer-modified-p nil
)
849 (defun wl-fldmgr-delete ()
853 (if (wl-folder-buffer-group-p)
854 (error "Can't delete group folder"))
855 (let* ((inhibit-read-only t
)
856 (tmp (wl-fldmgr-get-path-from-buffer))
857 (entity (elmo-string (nth 4 tmp
)))
858 (folder (wl-folder-get-elmo-folder entity
)))
859 (when (elmo-folder-delete folder
)
860 (wl-folder-clear-entity-info entity
)
861 (wl-fldmgr-cut tmp nil t
)
862 (wl-fldmgr-save-access-list)))))
864 (defun wl-fldmgr-rename ()
869 (message "Can't rename desktop group")
871 ((and (wl-folder-buffer-group-p)
872 (looking-at wl-folder-group-regexp
)) ;; group
873 (let* ((indent (wl-match-buffer 1))
874 (old-group (wl-folder-get-entity-from-buffer))
875 (group-entity (wl-folder-search-group-entity-by-name
876 old-group wl-folder-entity
))
878 (if (eq (nth 1 group-entity
) 'access
)
879 (message "%s: can't rename access group folder" old-group
)
880 (setq group
(wl-fldmgr-read-string
881 (read-from-minibuffer "Rename: " old-group
)))
882 (if (string-match "/$" group
)
883 (message "Remove tail slash.")
885 ((or (string= group
"")
886 (string= old-group group
))
889 (if (wl-string-assoc group wl-folder-group-alist
)
890 (message "%s: group already exists" group
)
891 (let ((inhibit-read-only t
)
892 (id (wl-fldmgr-get-entity-id
893 (car group-entity
))))
894 (wl-fldmgr-assign-id group id
)
895 (setcar group-entity group
)
896 (setcar (wl-string-assoc old-group wl-folder-group-alist
)
898 ;;; (setcdr (assq id wl-folder-entity-id-name-alist) group)
899 (wl-folder-set-id-name id group
)
900 (wl-fldmgr-delete-line)
901 (wl-folder-insert-entity
904 (setq wl-fldmgr-modified t
)
905 (set-buffer-modified-p nil
)))))))))
907 (let* ((tmp (wl-fldmgr-get-path-from-buffer))
908 (old-folder (nth 4 tmp
))
910 (unless old-folder
(error "No folder"))
912 (wl-fldmgr-read-string
913 (wl-summary-read-folder old-folder
"to rename" t t old-folder
)))
914 (if (or (wl-folder-entity-exists-p new-folder
)
915 (file-exists-p (elmo-folder-msgdb-path
916 (wl-folder-get-elmo-folder new-folder
))))
917 (error "Already exists folder: %s" new-folder
))
918 (if (and (eq (cdr (nth 2 tmp
)) 'access
)
919 (null wl-fldmgr-allow-rename-access-group
)
921 (format "^%s" (regexp-quote (car (nth 2 tmp
))))
923 (error "Can't rename access folder"))
924 (elmo-folder-rename (wl-folder-get-elmo-folder old-folder
)
926 (wl-folder-set-entity-info
928 (wl-folder-get-entity-info old-folder
))
929 (wl-folder-clear-entity-info old-folder
)
930 (setq wl-folder-info-alist-modified t
)
931 (if (eq (cdr (nth 2 tmp
)) 'access
)
933 ;; force update access group
935 (wl-folder-open-close)
936 (wl-folder-jump-to-current-entity t
)
937 (message "%s is renamed to %s" old-folder new-folder
)
939 ;; update folder list
940 (when (wl-fldmgr-cut tmp nil t
)
941 (wl-fldmgr-add new-folder
)))))))))
943 (defun wl-fldmgr-make-access-group ()
945 (wl-fldmgr-make-group nil t
))
947 (defun wl-fldmgr-make-group (&optional group-name access
)
952 (message "Can't insert in the out of desktop group")
953 (let ((inhibit-read-only t
)
955 group tmp indent path new prev-id flist diffs
)
956 (setq tmp
(wl-fldmgr-get-path-from-buffer t
))
957 (setq path
(car tmp
))
958 (setq indent
(wl-fldmgr-make-indent (nth 1 tmp
)))
959 (setq prev-id
(nth 3 tmp
))
960 (if (eq (cdr (nth 2 tmp
)) 'access
)
961 (message "Can't insert access group")
962 (setq group
(or group-name
963 (wl-fldmgr-read-string
964 (read-from-minibuffer
965 (if access
"Access Type Group: " "Group: ")))))
966 ;; To check the folder name is correct.
967 (if access
(elmo-make-folder group
))
968 (when (or access
(string-match "[\t ]*/$" group
))
969 (setq group
(if access group
970 (substring group
0 (match-beginning 0))))
972 (setq flist
(wl-create-access-folder-entity group
)))
973 (if (string= group
"")
975 (if (wl-string-assoc group wl-folder-group-alist
)
976 (message "%s: group already exists" group
)
977 (setq new
(append (list group type
) flist
))
978 (when (setq diffs
(wl-add-entity path
982 (wl-folder-insert-entity indent new
)
983 (wl-fldmgr-update-group path diffs
)
984 (setq wl-fldmgr-modified t
)
985 (set-buffer-modified-p nil
)))))))))
987 (defun wl-fldmgr-make-multi ()
989 (if (not wl-fldmgr-cut-entity-list
)
990 (message "No cut buffer")
991 (let ((cut-entity wl-fldmgr-cut-entity-list
)
999 ((numberp (car cut-entity
))
1001 ((consp (car cut-entity
))
1002 (message "Can't make multi included group folder")
1005 (let ((folder (wl-folder-get-elmo-folder
1008 (if (eq (elmo-folder-type-internal folder
) 'multi
)
1010 (substring (car cut-entity
) 1)))
1013 (or multi-fld
(car cut-entity
))
1017 (setq cut-entity
(cdr cut-entity
)))
1020 (setq new-entity
(concat "*" new-entity
))
1021 (wl-fldmgr-add new-entity
)))))
1023 (defun wl-fldmgr-make-filter ()
1027 (let ((tmp (wl-fldmgr-get-path-from-buffer))
1029 (if (eq (cdr (nth 2 tmp
)) 'access
)
1030 (message "Can't change access group")
1031 (if (wl-folder-buffer-group-p)
1035 (mapconcat 'identity
1036 (wl-folder-get-entity-list
1037 (wl-folder-search-group-entity-by-name
1039 wl-folder-entity
)) ",")))
1040 (setq entity
(nth 4 tmp
)))
1041 (unless entity
(error "No folder"))
1042 (wl-fldmgr-add (concat "/"
1043 (wl-read-search-condition
1044 wl-fldmgr-make-filter-default
)
1047 (defun wl-fldmgr-sort (&optional arg
)
1051 (let ((inhibit-read-only t
)
1052 entity flist indent opened
)
1053 (when (and (wl-folder-buffer-group-p)
1054 (looking-at wl-folder-group-regexp
)
1056 (y-or-n-p (format "Sort subfolders of %s? "
1057 (wl-folder-get-entity-from-buffer)))
1059 (setq indent
(wl-match-buffer 1))
1060 (setq opened
(wl-match-buffer 2))
1061 (setq entity
(wl-folder-search-group-entity-by-name
1062 (wl-folder-get-entity-from-buffer)
1064 (message "Sorting...")
1065 (setq flist
(sort (nth 2 entity
) wl-fldmgr-sort-function
))
1066 (when arg
(setq flist
(nreverse flist
)))
1067 (setcar (cddr entity
) flist
)
1068 (wl-fldmgr-add-modified-access-list (car entity
))
1069 (setq wl-fldmgr-modified t
)
1070 (when (string= opened
"-")
1077 (wl-folder-goto-bottom-of-current-folder indent
)
1080 (delete-region beg end
)
1081 (wl-folder-insert-entity indent entity
)))
1082 (message "Sorting...done")
1083 (set-buffer-modified-p nil
)))))
1085 (defun wl-fldmgr-sort-standard (x y
)
1086 (cond ((and (consp x
) (not (consp y
)))
1087 wl-fldmgr-sort-group-first
)
1088 ((and (not (consp x
)) (consp y
))
1089 (not wl-fldmgr-sort-group-first
))
1090 ((and (consp x
) (consp y
))
1091 (string-lessp (car x
) (car y
)))
1093 (string-lessp x y
))))
1095 (defun wl-fldmgr-subscribe-region ()
1097 (wl-fldmgr-unsubscribe-region -
1))
1099 (defun wl-fldmgr-unsubscribe-region (&optional arg
)
1101 (let* ((p1 (region-beginning))
1115 (while (< (point) to
)
1116 (setq count
(1+ count
))
1119 (message "Unsubscribe region...")
1120 (while (and (> count
0)
1121 (wl-fldmgr-unsubscribe (or arg
1) t
))
1122 (setq count
(1- count
)))
1123 (message "Unsubscribe region...done")))
1125 (defun wl-fldmgr-subscribe ()
1127 (wl-fldmgr-unsubscribe -
1))
1129 (defun wl-fldmgr-unsubscribe (&optional arg force
)
1131 (let ((type (and arg
(prefix-numeric-value arg
)))
1135 (let ((inhibit-read-only t
)
1139 ((looking-at (format "^[ ]*%s\\[[+-]\\]\\(.*\\)" wl-folder-unsubscribe-mark
))
1140 (if (and type
(> type
0))
1142 (setq folder
(list (wl-match-buffer 1) 'access nil
))
1143 (if (wl-string-assoc (car folder
) wl-folder-group-alist
)
1144 (message "%s: group already exists" (car folder
))
1145 (wl-fldmgr-delete-line)
1146 (when (wl-fldmgr-add folder
)
1147 (wl-folder-maybe-load-folder-list folder
)
1148 ;;; (wl-folder-search-group-entity-by-name (car folder)
1149 ;;; wl-folder-entity)
1151 ((looking-at (format "^[ ]*%s\\(.*\\)" wl-folder-unsubscribe-mark
))
1152 (if (and type
(> type
0))
1154 (setq folder
(wl-match-buffer 1))
1155 (wl-fldmgr-delete-line)
1156 (when (wl-fldmgr-add folder
)
1159 (if (and type
(< type
0))
1161 (setq is-group
(wl-folder-buffer-group-p))
1162 (setq tmp
(wl-fldmgr-get-path-from-buffer))
1163 (setq indent
(wl-fldmgr-make-indent (nth 1 tmp
)))
1164 (if (eq (cdr (nth 2 tmp
)) 'access
)
1165 (when (wl-fldmgr-cut tmp
)
1166 ;; don't leave cut-list
1167 (setq wl-fldmgr-cut-entity-list
(cdr wl-fldmgr-cut-entity-list
))
1169 (insert indent wl-folder-unsubscribe-mark
1171 (concat "[+]" (nth 4 tmp
))
1174 (save-excursion (forward-line -
1)
1175 (wl-highlight-folder-current-line))
1176 (remove-text-properties beg
(point) '(wl-folder-entity-id))
1178 (message "not an access group folder")))))
1179 (set-buffer-modified-p nil
)))
1180 (if (or force execed
)
1185 (defun wl-fldmgr-access-display-normal (&optional arg
)
1187 (wl-fldmgr-access-display-all (not arg
)))
1189 (defun wl-fldmgr-access-display-all (&optional arg
)
1191 (let ((id (save-excursion
1192 (wl-folder-prev-entity-skip-invalid t
)
1193 (wl-fldmgr-get-entity-id))))
1196 (let ((inhibit-read-only t
)
1197 entity indent opened
1200 (and (wl-folder-buffer-group-p)
1201 (looking-at wl-folder-group-regexp
)))
1202 (wl-folder-goto-top-of-current-folder)
1203 (looking-at wl-folder-group-regexp
))
1204 (setq indent
(wl-match-buffer 1))
1205 (setq opened
(wl-match-buffer 2))
1206 (setq entity
(wl-folder-search-group-entity-by-name
1207 (wl-folder-get-entity-from-buffer)
1209 (when (eq (nth 1 entity
) 'access
)
1211 (if (string= opened
"-")
1218 (wl-folder-goto-bottom-of-current-folder indent
)
1221 (delete-region beg end
))
1222 (wl-fldmgr-delete-line)
1223 (setcdr (assoc (car entity
) wl-folder-group-alist
) t
));; set open
1224 (wl-folder-insert-entity indent entity
))
1226 (setq unsubscribes
(nth 3 entity
))
1230 (insert indent
" " wl-folder-unsubscribe-mark
1231 (if (consp (car unsubscribes
))
1232 (concat "[+]" (caar unsubscribes
))
1235 (remove-text-properties beg
(point) '(wl-folder-entity-id))
1236 (save-excursion (forward-line -
1)
1237 (wl-highlight-folder-current-line))
1238 (setq unsubscribes
(cdr unsubscribes
))))
1239 (set-buffer-modified-p nil
))))
1240 (wl-folder-move-path id
)))
1242 (defun wl-fldmgr-set-petname ()
1246 (let* ((is-group (wl-folder-buffer-group-p))
1247 (name (wl-folder-get-entity-from-buffer))
1248 (searchname (wl-folder-get-petname name
))
1249 (pentry (wl-string-assoc name wl-folder-petname-alist
))
1250 (old-petname (or (cdr pentry
) ""))
1253 (unless name
(error "No folder"))
1255 (not (eq (nth 1 (wl-folder-search-group-entity-by-name
1256 name wl-folder-entity
))
1258 (message "Can't set petname. please rename.")
1259 (setq petname
(wl-fldmgr-read-string
1260 (read-from-minibuffer "Petname: " old-petname
)))
1262 ((string= petname
"")
1264 (setq wl-folder-petname-alist
1265 (delete pentry wl-folder-petname-alist
))
1268 (if (string= petname old-petname
)
1270 (if (or (rassoc petname wl-folder-petname-alist
)
1272 (wl-string-assoc petname wl-folder-group-alist
)))
1273 (message "%s: already exists" petname
)
1274 (wl-folder-append-petname name petname
)
1277 (let ((inhibit-read-only t
)
1279 (goto-char (point-min))
1282 (if (string= old-petname
"")
1283 (setq old-petname name
))
1284 (while (wl-folder-buffer-search-group old-petname
)
1286 (and (looking-at "^\\([ ]*\\)")
1287 (setq indent
(wl-match-buffer 1)))
1288 (wl-fldmgr-delete-line)
1289 (wl-folder-insert-entity
1291 (wl-folder-search-group-entity-by-name
1292 name wl-folder-entity
)
1294 (while (wl-folder-buffer-search-entity name searchname
)
1297 (and (looking-at "^\\([ ]*\\)")
1298 (setq indent
(wl-match-buffer 1)))
1299 (wl-fldmgr-delete-line))
1300 (wl-folder-insert-entity indent name
)))
1301 (setq wl-fldmgr-modified t
)
1302 (set-buffer-modified-p nil
)))))))
1304 ;;; Function for save folders
1307 (defun wl-fldmgr-insert-folders-buffer (indent entities
&optional pet-entities
)
1308 (let ((flist entities
)
1311 (setq name
(car flist
))
1312 (cond ((stringp name
)
1313 (if (setq petname
(cdr (wl-string-assoc name wl-folder-petname-alist
)))
1314 (wl-append pet-entities
(list name
)))
1317 (concat "\t\"" petname
"\"")
1321 (let ((group (car name
))
1322 (type (nth 1 name
)))
1323 (cond ((eq type
'group
)
1324 (insert indent group
"{\n")
1326 (wl-fldmgr-insert-folders-buffer
1327 (concat indent wl-fldmgr-folders-indent
)
1328 (nth 2 name
) pet-entities
))
1329 (insert indent
"}\n"))
1331 (insert indent group
"/\n"))))))
1332 (setq flist
(cdr flist
))))
1335 (defun wl-fldmgr-insert-petname-buffer (pet-entities)
1336 (let ((alist wl-folder-petname-alist
))
1338 (if (wl-string-member (caar alist
) pet-entities
)
1340 (insert "=\t" (caar alist
) "\t\"" (cdar alist
) "\"\n"))
1341 (setq alist
(cdr alist
)))))
1343 (defun wl-fldmgr-delete-disused-petname ()
1344 (let ((alist wl-folder-petname-alist
))
1346 (unless (wl-folder-search-entity-by-name (caar alist
) wl-folder-entity
)
1347 (setq wl-folder-petname-alist
1348 (delete (car alist
) wl-folder-petname-alist
)))
1349 (setq alist
(cdr alist
)))))
1351 (defun wl-fldmgr-save-folders ()
1353 (let ((tmp-buf (get-buffer-create " *wl-fldmgr-tmp*"))
1354 save-petname-entities
)
1355 (message "Saving folders...")
1356 (set-buffer tmp-buf
)
1358 (insert wl-fldmgr-folders-header
)
1359 (wl-fldmgr-delete-disused-petname)
1360 (setq save-petname-entities
1361 (wl-fldmgr-insert-folders-buffer "" (nth 2 wl-folder-entity
)))
1362 (insert "\n# petname definition (access group, folder in access group)\n")
1363 (wl-fldmgr-insert-petname-buffer save-petname-entities
)
1364 (insert "\n# end of file.\n")
1365 (if (and wl-fldmgr-make-backup
1366 (file-exists-p wl-folders-file
))
1367 (rename-file wl-folders-file
(concat wl-folders-file
".bak") t
))
1368 (let ((output-coding-system (mime-charset-to-coding-system
1376 (set-file-modes wl-folders-file
(+ (* 64 6) (* 8 0) 0))) ; chmod 0600
1377 (kill-buffer tmp-buf
)
1378 (wl-fldmgr-save-access-list)
1379 (setq wl-fldmgr-modified nil
)
1380 (message "Saving folders...done")))
1382 (defun wl-fldmgr-save-access-list ()
1383 (let ((access-list wl-fldmgr-modified-access-list
)
1386 (setq entity
(wl-folder-search-group-entity-by-name
1387 (car access-list
) wl-folder-entity
))
1388 (elmo-msgdb-flist-save
1391 (wl-folder-make-save-access-list (nth 2 entity
))
1392 (wl-folder-make-save-access-list (nth 3 entity
))))
1393 (setq access-list
(cdr access-list
)))
1394 (setq wl-fldmgr-modified-access-list nil
)))
1397 (product-provide (provide 'wl-fldmgr
) (require 'wl-version
))
1399 ;;; wl-fldmgr.el ends here