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) (file-path))
70
(luna-define-internal-accessors 'elmo-file-folder))
72
(luna-define-method elmo-folder-initialize ((folder
75
(elmo-file-folder-set-file-path-internal folder name)
78
(luna-define-method elmo-folder-expand-msgdb-path ((folder
81
(elmo-replace-string-as-filename (elmo-folder-name-internal folder))
82
(expand-file-name "file" elmo-msgdb-directory)))
84
(defun elmo-file-make-date-string (attrs)
85
(let ((s (current-time-string (nth 5 attrs))))
86
(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]"
88
(concat (elmo-match-string 1 s) ", "
89
(timezone-make-date-arpa-standard s (current-time-zone)))))
91
(defun elmo-file-detect-content-type (file)
92
"Return content-type of the FILE."
93
(if (or (not (file-exists-p file))
94
(file-directory-p file))
95
"application/octet-stream"
97
(setq type (mime-find-file-type file))
98
(if (and (string= (nth 0 type) "application")
99
(string= (nth 1 type) "octet-stream"))
100
(if (and elmo-file-command
101
elmo-file-command-argument)
103
(if (zerop (apply 'call-process elmo-file-command
104
nil `(,(current-buffer) nil)
105
nil (append elmo-file-command-argument
106
(list (expand-file-name file)))))
108
(goto-char (point-min))
109
(when (re-search-forward ": *" nil t)
110
(setq type (buffer-substring (match-end 0)
113
((string= "empty" type)
114
"application/octet-stream")
115
((string-match "text" type)
118
(car (split-string type)))))
119
"application/octet-stream"))
120
(concat (nth 0 type) "/" (nth 1 type)))
121
(concat (nth 0 type) "/" (nth 1 type))))))
123
(defun elmo-file-msgdb-create-entity (msgdb folder number)
124
"Create msgdb entity for the message in the FOLDER with NUMBER."
125
(let* ((file (elmo-message-file-name folder number))
126
(attrs (file-attributes file)))
127
(and (not (file-directory-p file))
129
(elmo-msgdb-make-message-entity
130
(elmo-msgdb-message-entity-handler msgdb)
131
:message-id (concat "<" (elmo-replace-in-string
136
:date (elmo-file-make-date-string attrs)
137
:subject (file-name-nondirectory file)
138
:from (concat (user-full-name (nth 2 attrs))
139
" <" (user-login-name (nth 2 attrs)) "@"
140
(system-name) ">")))))
142
(luna-define-method elmo-folder-msgdb-create ((folder elmo-file-folder)
144
(let ((new-msgdb (elmo-make-msgdb))
145
entity mark i percent num)
146
(setq num (length numlist))
148
(message "Creating msgdb...")
151
(elmo-file-msgdb-create-entity new-msgdb folder (car numlist)))
153
(elmo-msgdb-append-entity new-msgdb entity '(new unread)))
154
(when (> num elmo-display-progress-threshold)
156
(setq percent (/ (* i 100) num))
157
(elmo-display-progress
158
'elmo-folder-msgdb-create "Creating msgdb..."
160
(setq numlist (cdr numlist)))
161
(message "Creating msgdb...done")
164
(luna-define-method elmo-folder-message-file-p ((folder elmo-file-folder))
167
(luna-define-method elmo-message-file-name ((folder elmo-file-folder)
169
(expand-file-name (car (split-string
170
(elmo-map-message-location folder number)
172
(elmo-file-folder-file-path-internal folder)))
174
(luna-define-method elmo-folder-message-make-temp-file-p
175
((folder elmo-file-folder))
178
(luna-define-method elmo-folder-diff ((folder elmo-file-folder))
181
(luna-define-method elmo-folder-message-make-temp-files ((folder
186
(let ((temp-dir (elmo-folder-make-temporary-directory folder))
187
(cur-number (if start-number 0)))
188
(dolist (number numbers)
190
(elmo-message-file-name folder number)
192
(int-to-string (if start-number (incf cur-number) number))
196
(luna-define-method elmo-map-message-fetch ((folder elmo-file-folder)
198
&optional section unseen)
199
(let ((file (expand-file-name (car (split-string location "/"))
200
(elmo-file-folder-file-path-internal folder)))
201
charset guess uid is-text)
202
(when (file-exists-p file)
203
(set-buffer-multibyte nil)
205
(insert-file-contents-as-binary file nil 0 elmo-file-fetch-max-size)
206
(unless (or (std11-field-body "To")
207
(std11-field-body "Cc")
208
(std11-field-body "Subject"))
209
(setq guess (elmo-file-detect-content-type file))
210
(setq is-text (string-match "^text/" guess))
212
(set-buffer-multibyte t)
213
(decode-coding-region
214
(point-min) (point-max)
215
elmo-mime-display-as-is-coding-system)
216
(setq charset (detect-mime-charset-region (point-min)
218
(goto-char (point-min))
219
(setq uid (nth 2 (file-attributes file)))
220
(insert "From: " (concat (user-full-name uid)
221
" <"(user-login-name uid) "@"
222
(system-name) ">") "\n")
223
(insert "Subject: " (file-name-nondirectory file) "\n")
225
(elmo-file-make-date-string (file-attributes file))
227
(insert "Message-ID: "
228
(concat "<" (elmo-replace-in-string file "/" ":")
229
"@" (system-name) ">\n"))
230
(insert "Content-Type: "
234
"; charset=" (upcase (symbol-name charset))))
236
"\nMIME-Version: 1.0\n\n")
238
(encode-mime-charset-region (point-min) (point-max) charset))
239
(set-buffer-multibyte nil))))))
241
(luna-define-method elmo-map-folder-list-message-locations
242
((folder elmo-file-folder))
246
(when (not (file-directory-p file))
251
(nth 5 (file-attributes (expand-file-name
253
(elmo-file-folder-file-path-internal
256
(directory-files (elmo-file-folder-file-path-internal folder)))))
258
(luna-define-method elmo-folder-exists-p ((folder elmo-file-folder))
259
(file-directory-p (elmo-file-folder-file-path-internal folder)))
261
(luna-define-method elmo-folder-list-subfolders ((folder elmo-file-folder)
263
(when (file-directory-p (elmo-file-folder-file-path-internal folder))
265
(list (elmo-folder-name-internal folder))
269
(when (and (file-directory-p
272
(elmo-file-folder-file-path-internal folder)))
273
(not (string= file "."))
274
(not (string= file "..")))
275
(concat (elmo-folder-name-internal folder) "/" file)))
276
(directory-files (elmo-file-folder-file-path-internal
280
(product-provide (provide 'elmo-file) (require 'elmo-version))
282
;;; elmo-file.el ends here