1 ;;; wl-expire.el -- Message expire modules for Wanderlust.
3 ;; Copyright (C) 1998,1999,2000 Masahiro MURATA <muse@ba2.so-net.ne.jp>
4 ;; Copyright (C) 1998,1999,2000 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.
38 (require 'elmo-archive))
42 (defvar wl-expired-alist nil)
43 (defvar wl-expired-alist-file-name "expired-alist")
44 (defvar wl-expired-log-alist nil)
45 (defvar wl-expired-log-alist-file-name "expired-log")
47 (defun wl-expired-alist-load ()
48 (elmo-object-load (expand-file-name
49 wl-expired-alist-file-name
52 (defun wl-expired-alist-save (&optional alist)
53 (elmo-object-save (expand-file-name
54 wl-expired-alist-file-name
56 (or alist wl-expired-alist)))
58 (defsubst wl-expire-msg-p (msg-num mark-alist)
59 (cond ((consp wl-summary-expire-reserve-marks)
60 (let ((mark (nth 1 (assq msg-num mark-alist))))
61 (not (or (member mark wl-summary-expire-reserve-marks)
62 (and wl-summary-buffer-disp-msg
63 (eq msg-num wl-summary-buffer-current-msg))))))
64 ((eq wl-summary-expire-reserve-marks 'all)
65 (not (or (assq msg-num mark-alist)
66 (and wl-summary-buffer-disp-msg
67 (eq msg-num wl-summary-buffer-current-msg)))))
68 ((eq wl-summary-expire-reserve-marks 'none)
71 (error "Invalid marks: %s" wl-summary-expire-reserve-marks))))
73 (defmacro wl-expire-make-sortable-date (date)
74 (` (timezone-make-sortable-date
75 (aref (, date) 0) (aref (, date) 1) (aref (, date) 2)
76 (timezone-make-time-string
77 (aref (, date) 3) (aref (, date) 4) (aref (, date) 5)))))
79 (defsubst wl-expire-date-p (key-datevec date)
80 (let ((datevec (condition-case nil
81 (timezone-fix-time date nil nil)
84 datevec (> (aref datevec 1) 0)
86 (wl-expire-make-sortable-date datevec)
87 (wl-expire-make-sortable-date key-datevec)))))
89 (defun wl-expire-delete-reserve-marked-msgs-from-list (msgs mark-alist)
92 (unless (wl-expire-msg-p (car dlist) mark-alist)
93 (setq msgs (delq (car dlist) msgs)))
94 (setq dlist (cdr dlist)))
97 (defun wl-expire-delete (folder delete-list msgdb &optional no-reserve-marks)
98 "Delete message for expire."
99 (unless no-reserve-marks
101 (wl-expire-delete-reserve-marked-msgs-from-list
102 delete-list (elmo-msgdb-get-mark-alist msgdb))))
105 (format "Expiring (delete) %s msgs..."
106 (length delete-list))))
108 (if (elmo-delete-msgs folder
112 (elmo-msgdb-delete-msgs folder
116 (wl-expire-append-log folder delete-list nil 'delete)
117 (message "%s" (concat mess "done")))
118 (error (concat mess "failed!")))))
119 (cons delete-list (length delete-list)))
121 (defun wl-expire-refile (folder refile-list msgdb dst-folder
122 &optional no-reserve-marks preserve-number copy)
123 "Refile message for expire. If COPY is non-nil, copy message."
124 (when (not (string= folder dst-folder))
125 (unless no-reserve-marks
127 (wl-expire-delete-reserve-marked-msgs-from-list
128 refile-list (elmo-msgdb-get-mark-alist msgdb))))
130 (let* ((doingmes (if copy
132 "Expiring (move %s)"))
133 (mess (format (concat doingmes " %s msgs...")
134 dst-folder (length refile-list))))
136 (unless (or (elmo-folder-exists-p dst-folder)
137 (elmo-create-folder dst-folder))
138 (error "%s: create folder failed" dst-folder))
139 (if wl-expire-add-seen-list
140 (elmo-msgdb-add-msgs-to-seen-list
144 (concat wl-summary-important-mark
145 wl-summary-read-uncached-mark)))
146 (if (elmo-move-msgs folder
154 (wl-expire-append-log folder refile-list dst-folder (if copy 'copy 'move))
155 (message "%s" (concat mess "done")))
156 (error (concat mess "failed!")))))
157 (cons refile-list (length refile-list))))
159 (defun wl-expire-refile-with-copy-reserve-msg
160 (folder refile-list msgdb dst-folder
161 &optional no-reserve-marks preserve-number copy)
162 "Refile message for expire.
163 If REFILE-LIST includes reserve mark message, so copy."
164 (when (not (string= folder dst-folder))
165 (let ((msglist refile-list)
166 (mark-alist (elmo-msgdb-get-mark-alist msgdb))
167 (number-alist (elmo-msgdb-get-number-alist msgdb))
169 (copy-reserve-message)
172 (message "Expiring (move %s) %s msgs..."
173 dst-folder (length refile-list))
174 (unless (or (elmo-folder-exists-p dst-folder)
175 (elmo-create-folder dst-folder))
176 (error "%s: create folder failed" dst-folder))
177 (while (setq msg (wl-pop msglist))
178 (unless (wl-expire-msg-p msg mark-alist)
179 (setq msg-id (cdr (assq msg number-alist)))
180 (if (assoc msg-id wl-expired-alist)
181 ;; reserve mark message already refiled or expired
182 (setq refile-list (delq msg refile-list))
183 ;; reserve mark message not refiled
184 (wl-append wl-expired-alist (list (cons msg-id dst-folder)))
185 (setq copy-reserve-message t))))
187 (if wl-expire-add-seen-list
188 (elmo-msgdb-add-msgs-to-seen-list
192 (concat wl-summary-important-mark
193 wl-summary-read-uncached-mark)))
196 (elmo-move-msgs folder
203 (error "Expire: move msgs to %s failed" dst-folder))
204 (wl-expire-append-log folder refile-list dst-folder
205 (if copy-reserve-message 'copy 'move))
206 (setq copy-len (length refile-list))
207 (when copy-reserve-message
209 (wl-expire-delete-reserve-marked-msgs-from-list
214 (elmo-delete-msgs folder
218 (elmo-msgdb-delete-msgs folder
222 (wl-expire-append-log folder refile-list nil 'delete))))))
223 (let ((mes (format "Expiring (move %s) %s msgs..."
224 dst-folder (length refile-list))))
226 (message (concat mes "done"))
227 (error (concat mes "failed!"))))
228 (cons refile-list copy-len))))
230 (defun wl-expire-archive-get-folder (src-folder &optional fmt)
231 "Get archive folder name from SRC-FOLDER."
232 (let* ((spec (elmo-folder-get-spec src-folder))
233 (fmt (or fmt wl-expire-archive-folder-name-fmt))
234 (archive-spec (char-to-string
235 (car (rassq 'archive elmo-spec-alist))))
236 dst-folder-base dst-folder-fmt prefix)
237 (cond ((eq (car spec) 'localdir)
238 (setq dst-folder-base (concat archive-spec (nth 1 spec))))
239 ((stringp (nth 1 spec))
240 (setq dst-folder-base
241 (elmo-concat-path (format "%s%s" archive-spec (car spec))
244 (setq dst-folder-base
245 (elmo-concat-path (format "%s%s" archive-spec (car spec))
246 (elmo-replace-msgid-as-filename
248 (setq dst-folder-fmt (format fmt
250 wl-expire-archive-folder-type))
251 (setq dst-folder-base (format "%s;%s"
253 wl-expire-archive-folder-type))
254 (when (and wl-expire-archive-folder-prefix
255 (stringp (nth 1 spec)))
256 (cond ((eq wl-expire-archive-folder-prefix 'short)
257 (setq prefix (file-name-nondirectory (nth 1 spec))))
259 (setq prefix (nth 1 spec))))
260 (setq dst-folder-fmt (concat dst-folder-fmt ";" prefix))
261 (setq dst-folder-base (concat dst-folder-base ";" prefix)))
262 (cons dst-folder-base dst-folder-fmt)))
264 (defsubst wl-expire-archive-get-max-number (dst-folder-base &optional regexp)
265 (let ((files (reverse (sort (elmo-list-folders dst-folder-base)
267 (regexp (or regexp wl-expire-archive-folder-num-regexp))
271 (when (string-match regexp (car files))
272 (setq filenum (elmo-match-string 1 (car files)))
273 (setq in-folder (elmo-max-of-folder (car files)))
274 (throw 'done (cons in-folder filenum)))
275 (setq files (cdr files))))))
277 (defun wl-expire-archive-number-delete-old (dst-folder-base
278 preserve-number msgs mark-alist
279 &optional no-confirm regexp file)
280 (let ((len 0) (max-num 0)
282 (if (or (and file (setq folder-info
283 (cons (elmo-max-of-folder file) nil)))
284 (setq folder-info (wl-expire-archive-get-max-number dst-folder-base
287 (setq len (cdar folder-info))
288 (when preserve-number
289 ;; delete small number than max number of dst-folder
290 (setq max-num (caar folder-info))
291 (while (and msgs (>= max-num (car msgs)))
292 (wl-append dels (list (car msgs)))
293 (setq msgs (cdr msgs)))
294 (setq dels (wl-expire-delete-reserve-marked-msgs-from-list
297 (or (or no-confirm (not wl-expire-delete-oldmsg-confirm))
299 (if (eq major-mode 'wl-summary-mode)
300 (wl-thread-jump-to-msg (car dels)))
301 (y-or-n-p (format "Delete old messages %s? "
304 (list msgs dels max-num (cdr folder-info) len))
305 (list msgs dels 0 "0" 0))))
307 (defun wl-expire-archive-number1 (folder delete-list msgdb
308 &optional preserve-number no-delete)
309 "Standard function for `wl-summary-expire'.
310 Refile to archive folder followed message number."
311 (let* ((elmo-archive-treat-file t) ;; treat archive folder as a file.
312 (dst-folder-fmt (funcall
313 wl-expire-archive-get-folder-func folder))
314 (dst-folder-base (car dst-folder-fmt))
315 (dst-folder-fmt (cdr dst-folder-fmt))
316 (refile-func (if no-delete
318 'wl-expire-refile-with-copy-reserve-msg))
320 prev-arcnum arcnum msg arcmsg-list
321 deleted-list ret-val)
322 (setq tmp (wl-expire-archive-number-delete-old
323 dst-folder-base preserve-number delete-list
324 (elmo-msgdb-get-mark-alist msgdb)
326 (when (and (not no-delete)
327 (setq dels (nth 1 tmp)))
328 (wl-append deleted-list (car (wl-expire-delete folder dels msgdb))))
329 (setq delete-list (car tmp))
332 (if (setq msg (wl-pop delete-list))
333 (setq arcnum (/ msg wl-expire-archive-files))
335 (when (and prev-arcnum
336 (not (eq arcnum prev-arcnum)))
337 (setq dst-folder (format dst-folder-fmt
338 (* prev-arcnum wl-expire-archive-files)))
342 folder arcmsg-list msgdb dst-folder t preserve-number
344 (wl-append deleted-list (car ret-val)))
345 (setq arcmsg-list nil))
348 (wl-append arcmsg-list (list msg))
349 (setq prev-arcnum arcnum)))
353 (defun wl-expire-archive-number2 (folder delete-list msgdb
354 &optional preserve-number no-delete)
355 "Standard function for `wl-summary-expire'.
356 Refile to archive folder followed the number of message in one archive folder."
357 (let* ((elmo-archive-treat-file t) ;; treat archive folder as a file.
358 (dst-folder-fmt (funcall
359 wl-expire-archive-get-folder-func folder))
360 (dst-folder-base (car dst-folder-fmt))
361 (dst-folder-fmt (cdr dst-folder-fmt))
362 (refile-func (if no-delete
364 'wl-expire-refile-with-copy-reserve-msg))
367 arc-len msg arcmsg-list
368 deleted-list ret-val)
369 (setq tmp (wl-expire-archive-number-delete-old
370 dst-folder-base preserve-number delete-list
371 (elmo-msgdb-get-mark-alist msgdb)
373 (when (and (not no-delete)
374 (setq dels (nth 1 tmp)))
375 (wl-append deleted-list (car (wl-expire-delete folder dels msgdb))))
376 (setq delete-list (car tmp)
377 filenum (string-to-int (nth 3 tmp))
382 (if (setq msg (wl-pop delete-list))
384 (setq len (1+ wl-expire-archive-files)))
385 (when (> len wl-expire-archive-files)
387 (setq dst-folder (format dst-folder-fmt filenum))
391 folder arcmsg-list msgdb dst-folder t preserve-number
393 (wl-append deleted-list (car ret-val)))
394 (setq arc-len (+ arc-len (cdr ret-val))))
395 (setq arcmsg-list nil)
396 (if (< arc-len wl-expire-archive-files)
397 (setq len (1+ arc-len))
398 (setq filenum (+ filenum wl-expire-archive-files)
399 len (- len arc-len) ;; maybe 1
400 arc-len (1- len) ;; maybe 0
404 (wl-append arcmsg-list (list msg))))
408 (defun wl-expire-archive-date (folder delete-list msgdb
409 &optional preserve-number no-delete)
410 "Standard function for `wl-summary-expire'.
411 Refile to archive folder followed message date."
412 (let* ((elmo-archive-treat-file t) ;; treat archive folder as a file.
413 (number-alist (elmo-msgdb-get-number-alist msgdb))
414 (overview (elmo-msgdb-get-overview msgdb))
415 (dst-folder-fmt (funcall
416 wl-expire-archive-get-folder-func
418 wl-expire-archive-date-folder-name-fmt
420 (dst-folder-base (car dst-folder-fmt))
421 (dst-folder-fmt (cdr dst-folder-fmt))
422 (refile-func (if no-delete
424 'wl-expire-refile-with-copy-reserve-msg))
425 tmp dels dst-folder date time
426 msg arcmsg-alist arcmsg-list
427 deleted-list ret-val)
428 (setq tmp (wl-expire-archive-number-delete-old
429 dst-folder-base preserve-number delete-list
430 (elmo-msgdb-get-mark-alist msgdb)
432 wl-expire-archive-date-folder-num-regexp))
433 (when (and (not no-delete)
434 (setq dels (nth 1 tmp)))
435 (wl-append deleted-list (car (wl-expire-delete folder dels msgdb))))
436 (setq delete-list (car tmp))
437 (while (setq msg (wl-pop delete-list))
438 (setq date (elmo-msgdb-overview-entity-get-date
439 (assoc (cdr (assq msg number-alist)) overview)))
442 (timezone-fix-time date nil nil)
443 (error [0 0 0 0 0 0 0])))
444 (if (= (aref time 1) 0) ;; if (month == 0)
445 (aset time 0 0)) ;; year = 0
446 (setq dst-folder (format dst-folder-fmt
447 (aref time 0) ;; year
448 (aref time 1) ;; month
451 (wl-append-assoc-list
456 (setq dst-folder (caar arcmsg-alist))
457 (setq arcmsg-list (cdar arcmsg-alist))
461 folder arcmsg-list msgdb dst-folder t preserve-number
463 (wl-append deleted-list (car ret-val)))
464 (setq arcmsg-alist (cdr arcmsg-alist)))
468 (defun wl-expire-hide (folder hide-list msgdb &optional no-reserve-marks)
469 "Hide message for expire."
470 (unless no-reserve-marks
472 (wl-expire-delete-reserve-marked-msgs-from-list
473 hide-list (elmo-msgdb-get-mark-alist msgdb))))
474 (let ((mess (format "Hiding %s msgs..." (length hide-list))))
476 (elmo-msgdb-delete-msgs folder hide-list msgdb t)
477 (elmo-msgdb-append-to-killed-list folder hide-list)
478 (elmo-msgdb-save folder msgdb)
479 (message (concat mess "done"))
480 (cons hide-list (length hide-list))))
482 (defsubst wl-expire-folder-p (folder)
483 "Return non-nil, when FOLDER matched `wl-expire-alist'."
484 (wl-get-assoc-list-value wl-expire-alist folder))
486 (defun wl-summary-expire (&optional folder-name notsummary nolist)
489 (let ((folder (or folder-name wl-summary-buffer-folder-name))
490 (alist wl-expire-alist)
491 (deleting-info "Expiring...")
493 (when (and (or (setq expires (wl-expire-folder-p folder))
494 (progn (and (interactive-p)
495 (message "no match %s in wl-expire-alist"
498 (or (not (interactive-p))
499 (y-or-n-p (format "Expire %s? " folder))))
500 (let* ((msgdb (or wl-summary-buffer-msgdb
501 (elmo-msgdb-load folder)))
502 (number-alist (elmo-msgdb-get-number-alist msgdb))
503 (mark-alist (elmo-msgdb-get-mark-alist msgdb))
504 expval rm-type val-type value more args
507 (setq expval (car expires)
508 rm-type (nth 1 expires)
510 (setq val-type (car expval)
513 (run-hooks 'wl-summary-expire-pre-hook)
516 ((eq val-type 'number)
517 (let* ((msgs (if (not nolist)
518 (elmo-list-folder folder)
519 (mapcar 'car number-alist)))
520 (msglen (length msgs))
521 (more (or more (1+ value)))
523 (when (>= msglen more)
524 (setq count (- msglen value))
525 (while (and msgs (> count 0))
526 (when (assq (car msgs) number-alist) ;; don't expire new message
527 (wl-append delete-list (list (car msgs)))
528 (when (or (not wl-expire-number-with-reserve-marks)
529 (wl-expire-msg-p (car msgs) mark-alist))
530 (setq count (1- count))))
531 (setq msgs (cdr msgs))))))
533 (let* ((overview (elmo-msgdb-get-overview msgdb))
534 (key-date (elmo-date-get-offset-datevec
535 (timezone-fix-time (current-time-string)
536 (current-time-zone) nil)
539 (when (wl-expire-date-p
541 (elmo-msgdb-overview-entity-get-date
543 (wl-append delete-list
544 (list (elmo-msgdb-overview-entity-get-number
546 (setq overview (cdr overview)))))
548 (error "%s: not supported" val-type)))
551 (setq wl-expired-alist (wl-expired-alist-load)))
553 (cond ((eq rm-type nil) nil)
554 ((eq rm-type 'remove)
555 (setq deleting-info "Deleting...")
556 (car (wl-expire-delete folder delete-list msgdb)))
558 (setq deleting-info "Deleting...")
559 (car (wl-expire-refile folder delete-list msgdb wl-trash-folder)))
561 (setq deleting-info "Hiding...")
562 (car (wl-expire-hide folder delete-list msgdb)))
564 (setq deleting-info "Refiling...")
565 (car (wl-expire-refile folder delete-list msgdb rm-type)))
567 (apply rm-type (append (list folder delete-list msgdb)
570 (error "%s: invalid type" rm-type))))
571 (when (and (not notsummary) delete-list)
572 (wl-summary-delete-messages-on-buffer delete-list deleting-info)
573 (wl-summary-folder-info-update)
574 (wl-summary-set-message-modified)
575 (wl-summary-set-mark-modified)
577 (set-buffer-modified-p nil))
578 (wl-expired-alist-save))
579 (run-hooks 'wl-summary-expire-hook)
581 (message "Expiring %s is done" folder)
583 (message "No expire"))))
587 (defun wl-folder-expire-entity (entity)
590 (let ((flist (nth 2 entity)))
592 (wl-folder-expire-entity (car flist))
593 (setq flist (cdr flist)))))
595 (when (wl-expire-folder-p entity)
596 (let ((update-msgdb (cond
597 ((consp wl-expire-folder-update-msgdb)
598 (wl-string-match-member
600 wl-expire-folder-update-msgdb))
602 wl-expire-folder-update-msgdb)))
603 (wl-summary-highlight (if (or (wl-summary-sticky-p entity)
604 (wl-summary-always-sticky-folder-p
606 wl-summary-highlight))
607 wl-auto-select-first ret-val)
608 (save-window-excursion
611 (wl-summary-goto-folder-subr entity 'force-update nil))
612 (setq ret-val (wl-summary-expire entity (not update-msgdb)))
614 (wl-summary-save-status 'keep)
616 (wl-folder-check-entity entity))))))))))
620 (defun wl-folder-expire-current-entity ()
623 (or (wl-folder-get-folder-name-by-id
624 (get-text-property (point) 'wl-folder-entity-id))
625 (wl-folder-get-realname (wl-folder-folder-name)))))
626 (when (and entity-name
627 (or (not (interactive-p))
628 (y-or-n-p (format "Expire %s? " entity-name))))
629 (wl-folder-expire-entity
630 (wl-folder-search-entity-by-name entity-name
632 (if (get-buffer wl-summary-buffer-name)
633 (kill-buffer wl-summary-buffer-name))
634 (message "Expiring %s is done" entity-name))))
638 (defun wl-folder-archive-current-entity ()
641 (or (wl-folder-get-folder-name-by-id
642 (get-text-property (point) 'wl-folder-entity-id))
643 (wl-folder-get-realname (wl-folder-folder-name)))))
644 (when (and entity-name
645 (or (not (interactive-p))
646 (y-or-n-p (format "Archive %s? " entity-name))))
647 (wl-folder-archive-entity
648 (wl-folder-search-entity-by-name entity-name
650 (message "Archiving %s is done" entity-name))))
652 (defun wl-archive-number1 (folder archive-list msgdb)
653 (wl-expire-archive-number1 folder archive-list msgdb t t))
655 (defun wl-archive-number2 (folder archive-list msgdb)
656 (wl-expire-archive-number2 folder archive-list msgdb t t))
658 (defun wl-archive-date (folder archive-list msgdb)
659 (wl-expire-archive-date folder archive-list msgdb t t))
661 (defun wl-archive-folder (folder archive-list msgdb dst-folder)
662 (let* ((elmo-archive-treat-file t) ;; treat archive folder as a file.
665 (car (wl-expire-archive-number-delete-old
667 (elmo-msgdb-get-mark-alist msgdb)
673 folder archive-list msgdb dst-folder t t t)) ;; copy!!
674 (wl-append copied-list ret-val)))
678 (defun wl-summary-archive (&optional arg folder-name notsummary nolist)
680 (let* ((folder (or folder-name wl-summary-buffer-folder-name))
681 (msgdb (or wl-summary-buffer-msgdb
682 (elmo-msgdb-load folder)))
683 (msgs (if (not nolist)
684 (elmo-list-folder folder)
685 (mapcar 'car (elmo-msgdb-get-number-alist msgdb))))
686 (alist wl-archive-alist)
687 func dst-folder archive-list)
689 (let ((wl-default-spec (char-to-string
690 (car (rassq 'archive elmo-spec-alist)))))
691 (setq dst-folder (wl-summary-read-folder
692 (concat wl-default-spec (substring folder 1))
694 (run-hooks 'wl-summary-archive-pre-hook)
696 (wl-archive-folder folder msgs msgdb dst-folder)
697 (when (and (catch 'match
699 (when (string-match (caar alist) folder)
700 (setq func (cadar alist))
702 (setq alist (cdr alist)))
704 (message "No match %s in wl-archive-alist" folder))
706 (or (not (interactive-p))
707 (y-or-n-p (format "Archive %s? " folder))))
709 (funcall func folder msgs msgdb))
710 (run-hooks 'wl-summary-archive-hook)
712 (message "Archiving %s is done" folder)
714 (message "No archive")))))))
716 (defun wl-folder-archive-entity (entity)
719 (let ((flist (nth 2 entity)))
721 (wl-folder-archive-entity (car flist))
722 (setq flist (cdr flist)))))
724 (wl-summary-archive nil entity t))))
728 (defun wl-expire-append-log (src-folder msgs dst-folder action)
729 (when wl-expire-use-log
731 (let ((tmp-buf (get-buffer-create " *wl-expire work*"))
732 (filename (expand-file-name wl-expired-log-alist-file-name
737 (insert (format "%s\t%s -> %s\t%s\n"
739 src-folder dst-folder msgs))
740 (insert (format "%s\t%s\t%s\n"
743 (if (file-writable-p filename)
744 (write-region (point-min) (point-max)
746 (message (format "%s is not writable." filename)))
747 (kill-buffer tmp-buf)))))
750 (product-provide (provide 'wl-expire) (require 'wl-version))
752 ;;; wl-expire.el ends here