1 ;;; elmo-archive.el --- Archive folder of ELMO. -*- coding: euc-japan -*-
3 ;; Copyright (C) 1998,1999,2000 OKUNISHI Fujikazu <fuji0924@mbox.kyoto-inet.or.jp>
4 ;; Copyright (C) 1998,1999,2000 Yuuichi Teranishi <teranisi@gohome.org>
6 ;; Author: OKUNISHI Fujikazu <fuji0924@mbox.kyoto-inet.or.jp>
7 ;; Yuuichi Teranishi <teranisi@gohome.org>
8 ;; Keywords: mail, net news
9 ;; Created: Sep 13, 1998
11 ;; This file is part of ELMO (Elisp Library for Message Orchestration).
13 ;; This program is free software; you can redistribute it and/or modify
14 ;; it under the terms of the GNU General Public License as published by
15 ;; the Free Software Foundation; either version 2, or (at your option)
18 ;; This program is distributed in the hope that it will be useful,
19 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 ;; GNU General Public License for more details.
23 ;; You should have received a copy of the GNU General Public License
24 ;; along with GNU Emacs; see the file COPYING. If not, write to the
25 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
26 ;; Boston, MA 02111-1307, USA.
32 ;; Info-Zip ÀìÍÑ¥¨¡¼¥¸¥§¥ó¥È¤òÍѤ¤¤¿ÆüËܸ측º÷¡ÊOS/2 ÀìÍÑ¡Ë¡£
36 (eval-when-compile (require 'cl
))
42 (defvar elmo-archive-lha-dos-compatible
43 (memq system-type
'(OS/2 emx windows-nt
))
44 "*If non-nil, regard your LHA as compatible to DOS version.")
46 (defvar elmo-archive-use-izip-agent
(memq system-type
'(OS/2 emx
))
47 "*If non-nil, use the special agent in fetching headers.")
49 (defvar elmo-archive-folder-path
"~/Mail"
50 "*Base directory for archive folders.")
52 (defvar elmo-archive-basename
"elmo-archive"
53 "*Common basename of archive folder file, w/o suffix.")
55 (defvar elmo-archive-cmdstr-max-length
8000 ; SASAKI Osamu's suggestion
56 "*Command line string limitation under OS/2, exactly 8190 bytes.")
58 (defvar elmo-archive-fetch-headers-volume
50
59 "*Quantity of article headers to fetch per once.")
61 (defvar elmo-archive-dummy-file
".elmo-archive"
62 "*Name of dummy file that will be appended when the folder is null.")
64 (defvar elmo-archive-check-existance-strict t
65 "*Check existance of archive contents if non-nil.")
67 (defvar elmo-archive-load-hook nil
68 "*Hook called after loading elmo-archive.el.")
70 (defvar elmo-archive-treat-file nil
71 "*Treat archive folder as a file if non-nil.")
73 ;;; User variables for elmo-archive.
74 (defvar elmo-archive-default-type
'zip
75 "*Default archiver type. The value must be a symbol.")
77 (defvar elmo-archive-use-cache nil
78 "Use cache in archive folder.")
80 ;;; ELMO Local directory folder
82 (luna-define-class elmo-archive-folder
(elmo-folder)
83 (archive-name archive-type archive-prefix dir-name
))
84 (luna-define-internal-accessors 'elmo-archive-folder
))
86 (luna-define-generic elmo-archive-folder-path
(folder)
87 "Return local directory path of the FOLDER.")
89 (luna-define-method elmo-archive-folder-path
((folder elmo-archive-folder
))
90 elmo-archive-folder-path
)
92 (luna-define-method elmo-folder-initialize
((folder
95 (elmo-archive-folder-set-dir-name-internal folder name
)
97 "^\\([^;]*\\);?\\([^;]*\\);?\\([^;]*\\)$"
99 ;; Drive letter is OK!
100 (or (elmo-archive-folder-set-archive-name-internal
101 folder
(elmo-match-string 1 name
))
102 (elmo-archive-folder-set-archive-name-internal
104 (or (elmo-archive-folder-set-archive-type-internal
105 folder
(intern-soft (elmo-match-string 2 name
)))
106 (elmo-archive-folder-set-archive-type-internal
107 folder elmo-archive-default-type
))
108 (or (elmo-archive-folder-set-archive-prefix-internal
109 folder
(elmo-match-string 3 name
))
110 (elmo-archive-folder-set-archive-prefix-internal
114 (luna-define-method elmo-folder-expand-msgdb-path
((folder
115 elmo-archive-folder
))
118 (elmo-replace-string-as-filename
119 (elmo-folder-name-internal folder
))
120 (expand-file-name (concat (symbol-name (elmo-folder-type-internal folder
))
123 (elmo-archive-folder-archive-type-internal
125 elmo-msgdb-directory
)))
127 ;;; MMDF parser -- info-zip agent w/ REXX
128 (defvar elmo-mmdf-delimiter
"^\01\01\01\01$"
129 "*Regular expression of MMDF delimiter.")
131 (defvar elmo-unixmail-delimiter
"^From \\([^ \t]+\\) \\(.+\\)"
132 "*Regular expression of UNIX Mail delimiter.")
134 (defvar elmo-archive-header-regexp
"^[ \t]*[-=][-=][-=][-=]"
135 "*Common regexp of the delimiter in listing archive.") ; marche
137 (defvar elmo-archive-file-regexp-alist
139 (if elmo-archive-lha-dos-compatible
140 '((lha .
"^%s\\([0-9]+\\)$")) ; OS/2,DOS w/ "-x"
141 '((lha .
"^.*[ \t]%s\\([0-9]+\\)$")))
142 '((zip .
"^.*[ \t]%s\\([0-9]+\\)$")
143 (zoo .
"^.*[ \t]%s\\([0-9]+\\)$")
144 (tar .
"^%s\\([0-9]+\\)$") ; ok
145 (tgz .
"^%s\\([0-9]+\\)$") ; ok
146 (rar .
"^[ \t]%s\\([0-9]+\\)$"))))
148 (defvar elmo-archive-suffix-alist
149 '((lha .
".lzh") ; default
160 (defvar elmo-archive-lha-method-alist
161 (if elmo-archive-lha-dos-compatible
163 '((cp .
("lha" "u" "-x"))
164 (mv .
("lha" "m" "-x"))
166 (ls .
("lha" "l" "-x"))
167 (cat .
("lha" "p" "-n"))
168 (ext .
("lha" "x")) ; "-x"
176 (ext .
("lha" "x")))))
179 (defvar elmo-archive-zip-method-alist
180 '((cp .
("zip" "-9q"))
181 (cp-pipe .
("zip" "-9q@"))
182 (mv .
("zip" "-mDq9"))
183 (mv-pipe .
("zip" "-mDq9@"))
185 (rm-pipe .
("zip" "-dq@"))
186 (ls .
("unzip" "-lq"))
187 (cat .
("unzip" "-pq"))
189 (cat-headers .
("izwlagent" "--cat"))))
192 (defvar elmo-archive-zoo-method-alist
193 '((cp .
("zoo" "aq"))
194 (cp-pipe .
("zoo" "aqI"))
196 (mv-pipe .
("zoo" "aMqI"))
198 (ls .
("zoo" "l")) ; normal
199 (cat .
("zoo" "xpq"))
200 (ext .
("zoo" "xq"))))
203 (defvar elmo-archive-rar-method-alist
204 '((cp .
("rar" "u" "-m5"))
205 (mv .
("rar" "m" "-m5"))
208 (cat .
("rar" "p" "-inul"))
209 (ext .
("rar" "x"))))
212 (defvar elmo-archive-tar-method-alist
213 (if elmo-archive-lha-dos-compatible
214 '((ls .
("gtar" "-tf"))
215 (cat .
("gtar" "--posix Oxf"))
216 (ext .
("gtar" "-xf"))
217 ;;; (rm . ("gtar" "--posix" "--delete" "-f")) ; well not work
219 '((ls .
("gtar" "-tf"))
220 (cat .
("gtar" "-Oxf"))
221 (ext .
("gtar" "-xf"))
222 ;;; (rm . ("gtar" "--delete" "-f")) ;; well not work
225 ;;; GNU tar (*.tar.gz, *.tar.Z, *.tar.bz2)
226 (defvar elmo-archive-tgz-method-alist
227 '((ls .
("gtar" "-ztf"))
228 (cat .
("gtar" "-Ozxf"))
229 (create .
("gtar" "-zcf"))
230 ;;; (rm . elmo-archive-tgz-rm-func)
231 (cp . elmo-archive-tgz-cp-func
)
232 (mv . elmo-archive-tgz-mv-func
)
233 (ext .
("gtar" "-zxf"))
234 ;; tgz special method
235 (decompress .
("gzip" "-d"))
236 (compress .
("gzip"))
237 (append .
("gtar" "-uf"))
238 ;;; (delete . ("gtar" "--delete" "-f")) ; well not work
241 (defvar elmo-archive-method-list
242 '(elmo-archive-lha-method-alist
243 elmo-archive-zip-method-alist
244 elmo-archive-zoo-method-alist
245 ;;; elmo-archive-tar-method-alist
246 elmo-archive-tgz-method-alist
247 ;;; elmo-archive-arc-method-alist
248 ;;; elmo-archive-arj-method-alist
249 elmo-archive-rar-method-alist
))
252 (defvar elmo-archive-method-alist nil
)
253 (defvar elmo-archive-suffixes nil
)
257 (defmacro elmo-archive-get-method
(type action
)
258 `(cdr (assq ,action
(cdr (assq ,type elmo-archive-method-alist
)))))
260 (defmacro elmo-archive-get-suffix
(type)
261 `(cdr (assq ,type elmo-archive-suffix-alist
)))
263 (defmacro elmo-archive-get-regexp
(type)
264 `(cdr (assq ,type elmo-archive-file-regexp-alist
)))
266 (defsubst elmo-archive-call-process
(prog args
&optional output
)
267 (= (apply 'call-process prog nil output nil args
) 0))
269 (defsubst elmo-archive-call-method
(method args
&optional output
)
272 (funcall method args output
))
274 (elmo-archive-call-process
275 (car method
) (append (cdr method
) args
) output
))))
277 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
280 (defsubst elmo-archive-list-folder-subr
(folder &optional nonsort
)
281 "*Returns list of number-file(int, not string) in archive FILE.
282 TYPE specifies the archiver's symbol."
283 (let* ((type (elmo-archive-folder-archive-type-internal folder
))
284 (prefix (elmo-archive-folder-archive-prefix-internal folder
))
285 (file (elmo-archive-get-archive-name folder
))
286 (method (elmo-archive-get-method type
'ls
))
288 (file-regexp (format (elmo-archive-get-regexp type
)
289 (elmo-concat-path (regexp-quote prefix
) "")))
290 (killed (elmo-folder-killed-list-internal folder
))
291 numbers buf file-list header-end
)
292 (if (file-exists-p file
)
294 (unless (elmo-archive-call-method method args t
)
295 (error "%s exited abnormally!" method
))
296 (goto-char (point-min))
297 (when (re-search-forward elmo-archive-header-regexp nil t
)
299 (setq header-end
(point))
300 (when (re-search-forward elmo-archive-header-regexp nil t
)
302 (narrow-to-region header-end
(point))
303 (goto-char (point-min))))
304 (while (and (re-search-forward file-regexp nil t
)
305 (not (eobp))) ; for GNU tar 981010
306 (setq file-list
(nconc file-list
(list (string-to-number
307 (match-string 1)))))))
308 (error "%s does not exist" file
))
310 (cons (or (elmo-max-of-list file-list
) 0)
312 (- (length file-list
)
313 (elmo-msgdb-killed-list-length killed
))
315 (setq numbers
(sort file-list
'<))
316 (elmo-living-messages numbers killed
))))
318 (luna-define-method elmo-folder-list-messages-internal
((folder
321 (elmo-archive-list-folder-subr folder
))
323 (luna-define-method elmo-folder-status
((folder elmo-archive-folder
))
324 (elmo-archive-list-folder-subr folder t
))
326 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
327 ;;; Folder related functions
329 (defsubst elmo-archive-get-archive-directory
(folder)
330 ;; allow fullpath. return format is "/foo/bar/".
331 (if (file-name-absolute-p (elmo-archive-folder-archive-name-internal folder
))
332 (if (find-file-name-handler
333 (elmo-archive-folder-archive-name-internal folder
)
335 (elmo-archive-folder-archive-name-internal folder
)
336 (expand-file-name (elmo-archive-folder-archive-name-internal folder
)))
337 (expand-file-name (elmo-archive-folder-archive-name-internal folder
)
338 elmo-archive-folder-path
)))
340 (defun elmo-archive-get-archive-name (folder)
341 (let ((dir (elmo-archive-get-archive-directory folder
))
342 (suffix (elmo-archive-get-suffix
343 (elmo-archive-folder-archive-type-internal
347 (error "Unknown archiver type: %s"
348 (elmo-archive-folder-archive-type-internal folder
)))
349 (if elmo-archive-treat-file
350 (if (string-match (concat (regexp-quote suffix
) "$")
351 (elmo-archive-folder-archive-name-internal folder
))
352 (expand-file-name (elmo-archive-folder-archive-name-internal
354 elmo-archive-folder-path
)
355 (expand-file-name (concat (elmo-archive-folder-archive-name-internal
358 elmo-archive-folder-path
))
360 "^\\(ange-ftp\\|efs\\)-"
361 (symbol-name (find-file-name-handler dir
'copy-file
)))
364 (setq filename
(expand-file-name
365 (concat elmo-archive-basename suffix
)
367 (elmo-folder-msgdb-path folder
))))
368 (if (file-directory-p dbdir
)
370 (if (file-exists-p dbdir
)
371 (error "File %s already exists" dbdir
)
372 (elmo-make-directory dbdir
)))
373 (if (not (file-exists-p filename
))
375 (if (file-directory-p dir
)
377 (concat elmo-archive-basename suffix
)
382 (if (or (not (file-exists-p dir
))
383 (file-directory-p dir
))
385 (concat elmo-archive-basename suffix
)
389 (luna-define-method elmo-folder-exists-p
((folder elmo-archive-folder
))
390 (file-exists-p (elmo-archive-get-archive-name folder
)))
392 (luna-define-method elmo-folder-creatable-p
((folder elmo-archive-folder
))
395 (luna-define-method elmo-folder-writable-p
((folder elmo-archive-folder
))
398 (luna-define-method elmo-folder-create
((folder elmo-archive-folder
))
399 (let* ((dir (directory-file-name ; remove tail slash.
400 (elmo-archive-get-archive-directory folder
)))
401 (type (elmo-archive-folder-archive-type-internal folder
))
402 (arc (elmo-archive-get-archive-name folder
)))
403 (if elmo-archive-treat-file
404 (setq dir
(directory-file-name (file-name-directory dir
))))
405 (cond ((and (file-exists-p dir
)
406 (not (file-directory-p dir
)))
408 (error "Create folder failed; File \"%s\" exists" dir
))
409 ((file-directory-p dir
)
410 (if (file-exists-p arc
)
412 (elmo-archive-create-file arc type folder
)))
414 (elmo-make-directory dir
)
415 (elmo-archive-create-file arc type folder
)
418 (defun elmo-archive-create-file (archive type folder
)
420 (let* ((tmp-dir (directory-file-name
421 (elmo-folder-msgdb-path folder
)))
422 (dummy elmo-archive-dummy-file
)
423 (method (or (elmo-archive-get-method type
'create
)
424 (elmo-archive-get-method type
'mv
)))
425 (args (list archive dummy
)))
428 (error "WARNING: read-only mode: %s (method undefined)" type
))
430 ((file-directory-p tmp-dir
)
432 ((file-exists-p tmp-dir
)
434 (error "Create directory failed; File \"%s\" exists" tmp-dir
))
436 (elmo-make-directory tmp-dir
)))
439 (write-region (point) (point) dummy nil
'no-msg
)
441 (elmo-archive-call-method method args
)
442 (if (file-exists-p dummy
)
443 (delete-file dummy
)))
446 (luna-define-method elmo-folder-delete
((folder elmo-archive-folder
))
447 (let ((msgs (and (elmo-folder-exists-p folder
)
448 (elmo-folder-list-messages folder
))))
449 (when (yes-or-no-p (format "%sDelete msgdb and substance of \"%s\"? "
450 (if (> (length msgs
) 0)
451 (format "%d msg(s) exists. " (length msgs
))
453 (elmo-folder-name-internal folder
)))
454 (let ((arc (elmo-archive-get-archive-name folder
)))
455 (if (not (file-exists-p arc
))
456 (error "No such file: %s" arc
)
458 (elmo-msgdb-delete-path folder
)
461 (luna-define-method elmo-folder-rename-internal
((folder elmo-archive-folder
)
463 (let* ((old-arc (elmo-archive-get-archive-name folder
))
464 (new-arc (elmo-archive-get-archive-name new-folder
))
465 (new-dir (directory-file-name
466 (elmo-archive-get-archive-directory new-folder
))))
467 (if elmo-archive-treat-file
468 (setq new-dir
(directory-file-name (file-name-directory new-dir
))))
469 (unless (and (eq (elmo-archive-folder-archive-type-internal folder
)
470 (elmo-archive-folder-archive-type-internal new-folder
))
471 (equal (elmo-archive-folder-archive-prefix-internal
473 (elmo-archive-folder-archive-prefix-internal
475 (error "Not same archive type and prefix"))
476 (unless (file-exists-p old-arc
)
477 (error "No such file: %s" old-arc
))
478 (when (file-exists-p new-arc
)
479 (error "Already exists: %s" new-arc
))
480 (unless (file-directory-p new-dir
)
481 (elmo-make-directory new-dir
))
482 (rename-file old-arc new-arc
)
485 (defun elmo-archive-folder-list-subfolders (folder one-level
)
486 (if elmo-archive-treat-file
487 (let* ((path (elmo-archive-get-archive-directory folder
))
488 (base-folder (or (elmo-archive-folder-archive-name-internal
491 (suffix (elmo-archive-folder-archive-type-internal folder
))
493 (elmo-archive-folder-archive-prefix-internal folder
)
497 (elmo-archive-folder-archive-prefix-internal
499 (dir (if (file-directory-p path
)
500 path
(file-name-directory path
)))
501 (name (if (file-directory-p path
)
502 "" (file-name-nondirectory path
)))
503 (flist (and (file-directory-p dir
)
504 (directory-files dir nil
505 (if (> (length name
) 0)
506 (concat "^" name
"[^A-z][^A-z]")
509 (regexp (format "^\\(.*\\)\\(%s\\)$"
511 '(lambda (x) (regexp-quote (cdr x
)))
512 elmo-archive-suffix-alist
514 (if (string-match "\\(.*\\)/$" base-folder
) ; ends with '/'.
515 (setq base-folder
(elmo-match-string 1 base-folder
))
516 (unless (file-directory-p path
)
517 (setq base-folder
(or (file-name-directory base-folder
) ""))))
522 (when (and (string-match regexp x
)
525 (rassoc (elmo-match-string 2 x
)
526 elmo-archive-suffix-alist
))))
528 (elmo-folder-prefix-internal folder
)
529 (elmo-concat-path base-folder
(elmo-match-string 1 x
))
532 (elmo-mapcar-list-of-list
533 (function (lambda (x)
536 (concat elmo-archive-basename
537 (elmo-archive-get-suffix
538 (elmo-archive-folder-archive-type-internal
542 (elmo-archive-folder-path folder
))))
543 (concat (elmo-folder-prefix-internal folder
) x
))))
544 (elmo-list-subdirectories
545 (elmo-archive-folder-path folder
)
546 (or (elmo-archive-folder-dir-name-internal folder
) "")
549 (luna-define-method elmo-folder-list-subfolders
((folder elmo-archive-folder
)
551 (elmo-archive-folder-list-subfolders folder one-level
))
553 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
554 ;;; Article file related functions
555 ;;; read(extract) / append(move) / delete(delete) / query(list)
557 (defsubst elmo-archive-message-fetch-internal
(folder number
)
558 (let* ((type (elmo-archive-folder-archive-type-internal folder
))
559 (arc (elmo-archive-get-archive-name folder
))
560 (prefix (elmo-archive-folder-archive-prefix-internal folder
))
561 (method (elmo-archive-get-method type
'cat
))
562 (args (list arc
(elmo-concat-path
563 prefix
(int-to-string number
)))))
564 (and (file-exists-p arc
)
566 (elmo-archive-call-method method args t
))
568 (elmo-delete-cr-buffer)
571 (luna-define-method elmo-message-fetch-internal
((folder elmo-archive-folder
)
573 &optional section unseen
)
574 (elmo-archive-message-fetch-internal folder number
))
576 (luna-define-method elmo-folder-append-buffer
((folder elmo-archive-folder
)
577 &optional flags number
)
578 (elmo-archive-folder-append-buffer folder flags number
))
581 (defun elmo-archive-folder-append-buffer (folder flags number
)
582 (let* ((type (elmo-archive-folder-archive-type-internal folder
))
583 (prefix (elmo-archive-folder-archive-prefix-internal folder
))
584 (arc (elmo-archive-get-archive-name folder
))
585 (method (elmo-archive-get-method type
'mv
))
587 (1+ (if (file-exists-p arc
)
589 (elmo-folder-status folder
)) 0))))
590 (tmp-dir (elmo-folder-msgdb-path folder
))
591 (src-buffer (current-buffer))
596 (error "WARNING: read-only mode: %s (method undefined)" type
))
598 (let ((tmp-dir (expand-file-name prefix tmp-dir
)))
599 (when (not (file-directory-p tmp-dir
))
600 (elmo-make-directory (directory-file-name tmp-dir
))))
601 (setq newfile
(elmo-concat-path
603 (int-to-string next-num
)))
606 (if (and (or (functionp method
) (car method
))
607 (file-writable-p newfile
))
609 (setq dst-buffer
(current-buffer))
610 (with-current-buffer src-buffer
611 (copy-to-buffer dst-buffer
(point-min) (point-max)))
612 (as-binary-output-file
613 (write-region (point-min) (point-max) newfile nil
'no-msg
))
614 (when (elmo-archive-call-method method
(list arc newfile
))
615 (elmo-folder-preserve-flags
617 (with-current-buffer src-buffer
618 (elmo-msgdb-get-message-id-from-buffer))
623 (defun elmo-folder-append-messages-*-archive
(folder
627 (let ((prefix (elmo-archive-folder-archive-prefix-internal folder
)))
631 (elmo-folder-message-file-p src-folder
)
632 (elmo-folder-message-file-number-p src-folder
))
633 ;; same-number(localdir, localnews) -> archive
634 (unless (elmo-archive-append-files
636 (elmo-folder-message-file-directory src-folder
)
639 (elmo-progress-notify 'elmo-folder-move-messages
(length numbers
))
641 ((elmo-folder-message-make-temp-file-p src-folder
)
642 ;; not-same-number (localdir, localnews), (archive maildir) -> archive
643 (let ((temp-dir (elmo-folder-message-make-temp-files
647 (1+ (if (file-exists-p (elmo-archive-get-archive-name
649 (car (elmo-folder-status folder
)) 0)))))
650 new-dir base-dir files
)
653 (setq base-dir temp-dir
)
654 (when (> (length prefix
) 0)
655 (when (file-name-directory prefix
)
656 (elmo-make-directory (file-name-directory prefix
)))
662 ;; parent of temp-dir..(works in windows?)
663 (expand-file-name ".." temp-dir
))))
664 ;; now temp-dir has name prefix.
665 (setq temp-dir new-dir
)
666 ;; parent of prefix becomes base-dir.
667 (setq base-dir
(expand-file-name ".." temp-dir
)))
670 '(lambda (x) (elmo-concat-path prefix x
))
671 (directory-files temp-dir nil
"^[^\\.]")))
672 (unless (elmo-archive-append-files folder
676 (elmo-delete-directory temp-dir
)))
677 (elmo-progress-notify 'elmo-folder-move-messages
(length numbers
))
680 (elmo-folder-append-messages folder src-folder numbers same-number
681 'elmo-folder-append-messages-
*-archive
)))))
683 (luna-define-method elmo-folder-message-make-temp-file-p
684 ((folder elmo-archive-folder
))
685 (let ((type (elmo-archive-folder-archive-type-internal folder
)))
686 (or (elmo-archive-get-method type
'ext-pipe
)
687 (elmo-archive-get-method type
'ext
))))
689 (luna-define-method elmo-folder-message-make-temp-files
690 ((folder elmo-archive-folder
) numbers
691 &optional start-number
)
692 (elmo-archive-folder-message-make-temp-files folder numbers start-number
))
694 (defun elmo-archive-folder-message-make-temp-files (folder
697 (let* ((tmp-dir-src (elmo-folder-make-temporary-directory folder
))
698 (tmp-dir-dst (elmo-folder-make-temporary-directory folder
))
699 (arc (elmo-archive-get-archive-name folder
))
700 (type (elmo-archive-folder-archive-type-internal folder
))
701 (prefix (elmo-archive-folder-archive-prefix-internal folder
))
702 (p-method (elmo-archive-get-method type
'ext-pipe
))
703 (n-method (elmo-archive-get-method type
'ext
))
704 (tmp-msgs (mapcar (lambda (x) (elmo-concat-path
706 (int-to-string x
))) numbers
))
708 ;; Expand files in the tmp-dir-src.
712 ((functionp n-method
)
713 (funcall n-method
(cons arc tmp-msgs
)))
715 (let ((p-prog (car p-method
))
716 (p-prog-arg (cdr p-method
)))
717 (elmo-archive-exec-msgs-subr1
718 p-prog
(append p-prog-arg
(list arc
)) tmp-msgs
)))
720 (let ((n-prog (car n-method
))
721 (n-prog-arg (cdr n-method
)))
722 (elmo-archive-exec-msgs-subr2
723 n-prog
(append n-prog-arg
(list arc
)) tmp-msgs
725 ;; Move files to the tmp-dir-dst.
726 (setq number start-number
)
727 (dolist (tmp-file tmp-msgs
)
728 (rename-file (expand-file-name
733 (int-to-string number
)
734 (file-name-nondirectory tmp-file
))
736 (if start-number
(incf number
)))
737 ;; Remove tmp-dir-src.
738 (elmo-delete-directory tmp-dir-src
)
739 ;; tmp-dir-dst is the return directory.
742 (defun elmo-archive-append-files (folder dir
&optional files
)
743 (let* ((dst-type (elmo-archive-folder-archive-type-internal folder
))
744 (arc (elmo-archive-get-archive-name folder
))
745 (prefix (elmo-archive-folder-archive-prefix-internal folder
))
746 (p-method (elmo-archive-get-method dst-type
'cp-pipe
))
747 (n-method (elmo-archive-get-method dst-type
'cp
))
749 (unless (elmo-folder-exists-p folder
) (elmo-folder-create folder
))
750 (unless files
(setq files
(directory-files dir nil
"^[^\\.]")))
751 (when (null (or p-method n-method
))
753 (error "WARNING: read-only mode: %s (method undefined)" dst-type
))
758 ((functionp n-method
)
759 (funcall n-method
(cons arc files
)))
761 (let ((p-prog (car p-method
))
762 (p-prog-arg (cdr p-method
)))
763 (elmo-archive-exec-msgs-subr1
764 p-prog
(append p-prog-arg
(list arc
)) files
)))
766 (let ((n-prog (car n-method
))
767 (n-prog-arg (cdr n-method
)))
768 (elmo-archive-exec-msgs-subr2
769 n-prog
(append n-prog-arg
(list arc
)) files
(length arc
)))))))))
771 (luna-define-method elmo-folder-delete-messages-internal
((folder
774 (let* ((type (elmo-archive-folder-archive-type-internal folder
))
775 (prefix (elmo-archive-folder-archive-prefix-internal folder
))
776 (arc (elmo-archive-get-archive-name folder
))
777 (p-method (elmo-archive-get-method type
'rm-pipe
))
778 (n-method (elmo-archive-get-method type
'rm
))
779 (numbers (mapcar '(lambda (x) (elmo-concat-path
783 (cond ((functionp n-method
)
784 (funcall n-method
(cons arc numbers
)))
786 (let ((p-prog (car p-method
))
787 (p-prog-arg (cdr p-method
)))
788 (elmo-archive-exec-msgs-subr1
789 p-prog
(append p-prog-arg
(list arc
)) numbers
)))
791 (let ((n-prog (car n-method
))
792 (n-prog-arg (cdr n-method
)))
793 (elmo-archive-exec-msgs-subr2
794 n-prog
(append n-prog-arg
(list arc
)) numbers
(length arc
))))
797 (error "WARNING: not delete: %s (method undefined)" type
)))))
799 (defun elmo-archive-exec-msgs-subr1 (prog args msgs
)
801 (insert (mapconcat 'concat msgs
"\n")) ;string
802 (= 0 (apply 'call-process-region
(point-min) (point-max)
803 prog nil nil nil args
))))
805 (defun elmo-archive-exec-msgs-subr2 (prog args msgs arc-length
)
806 (let ((max-len (- elmo-archive-cmdstr-max-length arc-length
))
809 (setq rest msgs
) ;string
813 (while (and rest
(<= i n
))
815 (let* ((len (length x
))
816 (files (member x
(reverse rest
))))
817 ;; total(previous) + current + white space
818 (if (<= max-len
(+ sum len
1))
821 (elmo-archive-call-process
822 prog
(append args files
))
824 (setq sum
0) ;; reset
825 (setq rest
(nthcdr i rest
)))
826 (setq sum
(+ sum len
1)))
827 (setq i
(1+ i
)))) msgs
))
830 (elmo-archive-call-process prog
(append args rest
))))
833 (defsubst elmo-archive-article-exists-p
(arc msg type
)
834 (if (not elmo-archive-check-existance-strict
)
836 (save-excursion ; added 980915
837 (let* ((method (elmo-archive-get-method type
'ls
))
838 (args (list arc msg
))
839 (buf (get-buffer-create " *ELMO ARCHIVE query*"))
840 (error-msg "\\(no file\\|0 files\\)")
844 (elmo-archive-call-method method args t
)
845 ;; pointer: point-max
846 (setq ret-val
(not (re-search-backward error-msg nil t
)))
850 (defun elmo-archive-tgz-common-func (args exec-type
&optional copy
)
851 (let* ((arc (car args
))
852 (tmp-msgs (cdr args
))
853 (decompress (elmo-archive-get-method 'tgz
'decompress
))
854 (compress (elmo-archive-get-method 'tgz
'compress
))
855 (exec (elmo-archive-get-method 'tgz exec-type
))
856 (suffix (elmo-archive-get-suffix 'tgz
))
857 (tar-suffix (elmo-archive-get-suffix 'tar
))
860 (when (null (and decompress compress exec
))
862 (error "WARNING: special method undefined: %s of %s"
863 (or (if (null decompress
) 'decompress
)
864 (if (null compress
) 'compress
)
865 (if (null exec
) exec-type
))
869 (error "WARNING: `tar' suffix undefined"))
870 (if (string-match (concat (regexp-quote suffix
) "$") arc
)
872 (concat (substring arc
0 (match-beginning 0)) tar-suffix
))
873 (error "%s: not match suffix [%s]" arc suffix
))
876 (elmo-archive-call-process
877 (car decompress
) (append (cdr decompress
) (list arc
)))
878 ;; append (or delete)
879 (elmo-archive-exec-msgs-subr2
880 (car exec
) (append (cdr exec
) (list arc-tar
)) tmp-msgs
(length arc-tar
))
883 (elmo-archive-call-process
884 (car compress
) (append (cdr compress
) (list arc-tar
)))))
885 ;; delete temporary messages
887 (eq exec-type
'append
))
889 (if (file-exists-p (car tmp-msgs
))
890 (delete-file (car tmp-msgs
)))
891 (setq tmp-msgs
(cdr tmp-msgs
))))
894 (defun elmo-archive-tgz-cp-func (args &optional output
)
895 (elmo-archive-tgz-common-func args
'append t
))
897 (defun elmo-archive-tgz-mv-func (args &optional output
)
898 (elmo-archive-tgz-common-func args
'append
))
900 (defun elmo-archive-tgz-rm-func (args &optional output
)
901 (elmo-archive-tgz-common-func args
'delete
))
903 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
904 ;;; MessageDB functions (from elmo-localdir.el)
906 (defsubst elmo-archive-msgdb-create-entity-subr
(msgdb number
)
908 (set-buffer-multibyte default-enable-multibyte-characters
)
909 (goto-char (point-min))
910 (if (re-search-forward "\\(^--.*$\\)\\|\\(\n\n\\)" nil t
)
911 (setq header-end
(point))
912 (setq header-end
(point-max)))
913 (narrow-to-region (point-min) header-end
)
914 (elmo-msgdb-create-message-entity-from-buffer
915 (elmo-msgdb-message-entity-handler msgdb
) number
)))
918 (defsubst elmo-archive-msgdb-create-entity
(msgdb
922 (let* ((msg (elmo-concat-path prefix
(int-to-string number
)))
923 (arg-list (list archive msg
)))
924 (when (elmo-archive-article-exists-p archive msg type
)
927 (elmo-archive-call-method method arg-list t
))
928 (elmo-archive-msgdb-create-entity-subr msgdb number
))))
930 (luna-define-method elmo-folder-msgdb-create
((folder elmo-archive-folder
)
933 (save-excursion ;; 981005
934 (elmo-with-progress-display (elmo-folder-create-msgdb (length numbers
))
936 (if (and elmo-archive-use-izip-agent
937 (elmo-archive-get-method
938 (elmo-archive-folder-archive-type-internal folder
)
940 (elmo-archive-msgdb-create-as-numlist-subr2
941 folder numbers flag-table
)
942 (elmo-archive-msgdb-create-as-numlist-subr1
943 folder numbers flag-table
))))))
945 (defun elmo-archive-msgdb-create-as-numlist-subr1 (folder numlist flag-table
)
946 (let* ((type (elmo-archive-folder-archive-type-internal folder
))
947 (file (elmo-archive-get-archive-name folder
))
948 (method (elmo-archive-get-method type
'cat
))
949 (new-msgdb (elmo-make-msgdb))
950 entity message-id flags
)
955 (elmo-archive-msgdb-create-entity
957 method file
(car numlist
) type
958 (elmo-archive-folder-archive-prefix-internal folder
)))
960 (setq message-id
(elmo-message-entity-field entity
'message-id
)
961 flags
(elmo-flag-table-get flag-table message-id
))
962 (elmo-global-flags-set flags folder
(car numlist
) message-id
)
963 (elmo-msgdb-append-entity new-msgdb entity flags
))
964 (elmo-progress-notify 'elmo-folder-msgdb-create
)
965 (setq numlist
(cdr numlist
)))
969 (defun elmo-archive-msgdb-create-as-numlist-subr2 (folder
972 (let* ((delim1 elmo-mmdf-delimiter
) ;; MMDF
973 (delim2 elmo-unixmail-delimiter
) ;; UNIX Mail
974 (type (elmo-archive-folder-archive-type-internal folder
))
975 (prefix (elmo-archive-folder-archive-prefix-internal folder
))
976 (method (elmo-archive-get-method type
'cat-headers
))
979 (arc (elmo-archive-get-archive-name folder
))
980 (new-msgdb (elmo-make-msgdb))
981 n msgs case-fold-search
)
984 (setq n
(min (1- elmo-archive-fetch-headers-volume
)
985 (1- (length numlist
))))
986 (setq msgs
(reverse (memq (nth n numlist
) (reverse numlist
))))
987 (setq numlist
(nthcdr (1+ n
) numlist
))
992 (mapcar '(lambda (x) (elmo-concat-path prefix
(int-to-string x
))) msgs
)
994 (as-binary-process (apply 'call-process-region
995 (point-min) (point-max)
996 prog t t nil
(append args
(list arc
))))
997 (goto-char (point-min))
999 ((looking-at delim1
) ;; MMDF
1002 (elmo-archive-parse-mmdf folder msgs flag-table
)))
1003 ;;; ((looking-at delim2) ;; UNIX MAIL
1004 ;;; (elmo-msgdb-append
1006 ;;; (elmo-archive-parse-unixmail msgs flag-table)))
1007 (t ;; unknown format
1008 (error "Unknown format!")))
1009 (elmo-progress-notify 'elmo-folder-msgdb-create
)))
1012 (defun elmo-archive-parse-mmdf (folder msgs flag-table
)
1013 (let ((delim elmo-mmdf-delimiter
)
1014 (new-msgdb (elmo-make-msgdb))
1015 number sp ep rest entity
1017 (goto-char (point-min))
1019 (while (and rest
(re-search-forward delim nil t
)
1021 (setq number
(car rest
))
1022 (setq sp
(1+ (point)))
1023 (setq ep
(prog2 (re-search-forward delim
)
1024 (1+ (- (point) (length delim
)))))
1025 (if (>= sp ep
) ; no article!
1028 (narrow-to-region sp ep
)
1029 (setq entity
(elmo-archive-msgdb-create-entity-subr new-msgdb number
)
1030 message-id
(elmo-message-entity-field entity
'message-id
)
1031 flags
(elmo-flag-table-get flag-table message-id
))
1032 (elmo-global-flags-set flags folder number message-id
)
1033 (elmo-msgdb-append-entity new-msgdb entity flags
)
1036 (setq rest
(cdr rest
)))
1040 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1041 ;;; Search functions
1043 (defsubst elmo-archive-field-condition-match
(folder number number-list
1046 (let* ((type (elmo-archive-folder-archive-type-internal folder
))
1047 (arc (elmo-archive-get-archive-name folder
))
1048 (method (elmo-archive-get-method type
'cat
))
1049 (args (list arc
(elmo-concat-path prefix
(int-to-string number
)))))
1051 (when (file-exists-p arc
)
1053 (elmo-archive-call-method method args t
))
1054 (set-buffer-multibyte default-enable-multibyte-characters
)
1055 (decode-mime-charset-region (point-min)(point-max) elmo-mime-charset
)
1056 (elmo-message-buffer-match-condition condition number
))))))
1058 (luna-define-method elmo-folder-search
((folder elmo-archive-folder
)
1059 condition
&optional from-msgs
)
1060 (let* (;;(args (elmo-string-to-list key))
1061 ;; XXX: I don't know whether `elmo-archive-list-folder'
1062 ;; updates match-data.
1063 ;; (msgs (or from-msgs (elmo-archive-list-folder spec)))
1064 (msgs (or from-msgs
(elmo-folder-list-messages folder
)))
1065 (case-fold-search nil
)
1067 (elmo-with-progress-display (elmo-folder-search (length msgs
)) "Searching"
1068 (dolist (number msgs
)
1069 (when (elmo-archive-field-condition-match
1072 (elmo-archive-folder-archive-prefix-internal folder
))
1073 (setq ret-val
(cons number ret-val
)))
1074 (elmo-progress-notify 'elmo-folder-search
)))
1075 (nreverse ret-val
)))
1078 (if (null elmo-archive-method-alist
)
1079 (let ((mlist elmo-archive-method-list
) ; from mew-highlight.el
1082 (setq method
(car mlist
))
1083 (setq mlist
(cdr mlist
))
1084 (setq str
(symbol-name method
))
1085 (string-match "elmo-archive-\\([^-].*\\)-method-alist$" str
)
1086 (setq type
(intern-soft
1087 (elmo-match-string 1 str
)))
1088 (setq elmo-archive-method-alist
1090 (symbol-value method
))
1091 elmo-archive-method-alist
)))))
1093 ;;; valid suffix(list)
1094 (if (null elmo-archive-suffixes
)
1095 (let ((slist elmo-archive-suffix-alist
)
1098 (setq tmp
(car slist
))
1099 (setq elmo-archive-suffixes
1100 (nconc elmo-archive-suffixes
(list (cdr tmp
))))
1101 (setq slist
(cdr slist
)))))
1103 (luna-define-method elmo-message-use-cache-p
((folder elmo-archive-folder
)
1105 elmo-archive-use-cache
)
1108 (run-hooks 'elmo-archive-load-hook
)
1111 (product-provide (provide 'elmo-archive
) (require 'elmo-version
))
1113 ;;; elmo-archive.el ends here