1 ;;; elmo-file.el --- File interface for ELMO.
3 ;; Copyright (C) 2000 Yuuichi Teranishi <teranisi@gohome.org>
5 ;; Author: Yuuichi Teranishi <teranisi@gohome.org>
6 ;; Keywords: mail, net news
8 ;; This file is part of ELMO (Elisp Library for Message Orchestration).
10 ;; This program is free software; you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation; either version 2, or (at your option)
15 ;; This program is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;; GNU General Public License for more details.
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs; see the file COPYING. If not, write to the
22 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 ;; Boston, MA 02111-1307, USA.
31 (eval-when-compile (require 'cl
))
37 (defun elmo-file-find (files)
38 "Return the first existing filename in the FILES."
41 (when (file-exists-p (car files
))
42 (setq file
(car files
)
44 (setq files
(cdr files
)))
45 (and file
(expand-file-name file
))))
47 (defcustom elmo-file-command
(exec-installed-p "file")
48 "*Program name of the file type detection command `file'."
49 :type
'(string :tag
"Program name of the file")
52 (defcustom elmo-file-command-argument
53 (let ((magic-file (elmo-file-find
54 '("/usr/share/magic.mime"
55 "/usr/share/file/magic.mime"
56 "/cygwin/usr/share/file/magic.mime"))))
57 (if magic-file
(list "-m" magic-file
)))
58 "*Argument list for the `file' command.
59 \(It should return the MIME content type\)"
60 :type
'(repeat string
)
63 (defcustom elmo-file-fetch-max-size
(* 1024 1024)
64 "*Max size of the message fetching."
69 (luna-define-class elmo-file-folder
(elmo-map-folder elmo-file-tag
)
71 (luna-define-internal-accessors 'elmo-file-folder
))
73 (luna-define-method elmo-folder-initialize
((folder
76 (elmo-file-folder-set-file-path-internal folder name
)
79 (luna-define-method elmo-folder-expand-msgdb-path
((folder
82 (elmo-replace-string-as-filename (elmo-folder-name-internal folder
))
83 (expand-file-name "file" elmo-msgdb-directory
)))
85 (defun elmo-file-make-date-string (attrs)
86 (let ((s (current-time-string (nth 5 attrs
))))
87 (string-match "\\`\\([A-Z][a-z][a-z]\\) +[A-Z][a-z][a-z] +[0-9][0-9]? *[0-9][0-9]?:[0-9][0-9]:[0-9][0-9] *[0-9]?[0-9]?[0-9][0-9]"
89 (concat (elmo-match-string 1 s
) ", "
90 (timezone-make-date-arpa-standard s
(current-time-zone)))))
92 (defun elmo-file-detect-content-type (file)
93 "Return content-type of the FILE."
94 (if (or (not (file-exists-p file
))
95 (file-directory-p file
))
96 "application/octet-stream"
98 (setq type
(mime-find-file-type file
))
99 (if (and (string= (nth 0 type
) "application")
100 (string= (nth 1 type
) "octet-stream"))
101 (if (and elmo-file-command
102 elmo-file-command-argument
)
104 (if (zerop (apply 'call-process elmo-file-command
105 nil
`(,(current-buffer) nil
)
106 nil
(append elmo-file-command-argument
107 (list (expand-file-name file
)))))
109 (goto-char (point-min))
110 (when (re-search-forward ": *" nil t
)
111 (setq type
(buffer-substring (match-end 0)
114 ((string= "empty" type
)
115 "application/octet-stream")
116 ((string-match "text" type
)
119 (car (split-string type
)))))
120 "application/octet-stream"))
121 (concat (nth 0 type
) "/" (nth 1 type
)))
122 (concat (nth 0 type
) "/" (nth 1 type
))))))
124 (defun elmo-file-msgdb-create-entity (msgdb folder number
)
125 "Create msgdb entity for the message in the FOLDER with NUMBER."
126 (let* ((file (elmo-message-file-name folder number
))
127 (attrs (file-attributes file
)))
128 (and (not (file-directory-p file
))
130 (elmo-msgdb-make-message-entity
131 (elmo-msgdb-message-entity-handler msgdb
)
132 :message-id
(concat "<" (elmo-replace-in-string
137 :date
(elmo-file-make-date-string attrs
)
138 :subject
(file-name-nondirectory file
)
139 :from
(concat (user-full-name (nth 2 attrs
))
140 " <" (user-login-name (nth 2 attrs
)) "@"
141 (system-name) ">")))))
143 (luna-define-method elmo-folder-msgdb-create
((folder elmo-file-folder
)
145 (let ((new-msgdb (elmo-make-msgdb))
147 (elmo-with-progress-display (elmo-folder-msgdb-create (length numlist
))
149 (dolist (number numlist
)
150 (setq entity
(elmo-file-msgdb-create-entity new-msgdb folder number
))
152 (elmo-msgdb-append-entity new-msgdb entity
'(new unread
)))
153 (elmo-progress-notify 'elmo-folder-msgdb-create
)))
156 (luna-define-method elmo-folder-message-file-p
((folder elmo-file-folder
))
159 (luna-define-method elmo-message-file-name
((folder elmo-file-folder
)
161 (expand-file-name (car (split-string
162 (elmo-map-message-location folder number
)
164 (elmo-file-folder-file-path-internal folder
)))
166 (luna-define-method elmo-folder-message-make-temp-file-p
167 ((folder elmo-file-folder
))
170 (luna-define-method elmo-folder-diff
((folder elmo-file-folder
))
173 (luna-define-method elmo-folder-message-make-temp-files
((folder
178 (let ((temp-dir (elmo-folder-make-temporary-directory folder
))
179 (cur-number (or start-number
0)))
180 (dolist (number numbers
)
182 (elmo-message-file-name folder number
)
184 (int-to-string (if start-number cur-number number
))
189 (luna-define-method elmo-map-message-fetch
((folder elmo-file-folder
)
191 &optional section unseen
)
192 (let ((file (expand-file-name (car (split-string location
"/"))
193 (elmo-file-folder-file-path-internal folder
)))
194 charset guess uid is-text
)
195 (when (file-exists-p file
)
196 (set-buffer-multibyte nil
)
198 (insert-file-contents-as-binary file nil
0 elmo-file-fetch-max-size
)
199 (unless (or (std11-field-body "To")
200 (std11-field-body "Cc")
201 (std11-field-body "Subject"))
202 (setq guess
(elmo-file-detect-content-type file
))
203 (setq is-text
(string-match "^text/" guess
))
205 (set-buffer-multibyte t
)
206 (decode-coding-region
207 (point-min) (point-max)
208 elmo-mime-display-as-is-coding-system
)
209 (setq charset
(detect-mime-charset-region (point-min)
211 (goto-char (point-min))
212 (setq uid
(nth 2 (file-attributes file
)))
213 (insert "From: " (concat (user-full-name uid
)
214 " <"(user-login-name uid
) "@"
215 (system-name) ">") "\n")
216 (insert "Subject: " (file-name-nondirectory file
) "\n")
218 (elmo-file-make-date-string (file-attributes file
))
220 (insert "Message-ID: "
221 (concat "<" (elmo-replace-in-string file
"/" ":")
222 "@" (system-name) ">\n"))
223 (insert "Content-Type: "
227 "; charset=" (upcase (symbol-name charset
))))
229 "\nMIME-Version: 1.0\n\n")
231 (encode-mime-charset-region (point-min) (point-max) charset
))
232 (set-buffer-multibyte nil
))))))
234 (luna-define-method elmo-map-folder-list-message-locations
235 ((folder elmo-file-folder
))
239 (when (not (file-directory-p file
))
244 (nth 5 (file-attributes (expand-file-name
246 (elmo-file-folder-file-path-internal
249 (directory-files (elmo-file-folder-file-path-internal folder
)))))
251 (luna-define-method elmo-folder-exists-p
((folder elmo-file-folder
))
252 (file-directory-p (elmo-file-folder-file-path-internal folder
)))
254 (luna-define-method elmo-folder-list-subfolders
((folder elmo-file-folder
)
256 (when (file-directory-p (elmo-file-folder-file-path-internal folder
))
258 (list (elmo-folder-name-internal folder
))
262 (when (and (file-directory-p
265 (elmo-file-folder-file-path-internal folder
)))
266 (not (string= file
"."))
267 (not (string= file
"..")))
268 (concat (elmo-folder-name-internal folder
) "/" file
)))
269 (directory-files (elmo-file-folder-file-path-internal
273 (product-provide (provide 'elmo-file
) (require 'elmo-version
))
275 ;;; elmo-file.el ends here