0533956551ffc651515987deb76ebefb0fd3d5da
[elisp/flim.git] / mmbuffer.el
1 ;;; mmbuffer.el --- MIME entity module for binary buffer
2
3 ;; Copyright (C) 1998,1999 Free Software Foundation, Inc.
4 ;; Copyright (C) 1999 Electrotechnical Laboratory, JAPAN.
5 ;; Licensed to the Free Software Foundation.
6
7 ;; Author: MORIOKA Tomohiko <tomo@m17n.org>
8 ;; Keywords: MIME, multimedia, mail, news
9
10 ;; This file is part of FLIM (Faithful Library about Internet Message).
11
12 ;; This program is free software; you can redistribute it and/or
13 ;; modify it under the terms of the GNU General Public License as
14 ;; published by the Free Software Foundation; either version 2, or (at
15 ;; your option) any later version.
16
17 ;; This program is distributed in the hope that it will be useful, but
18 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20 ;; General Public License for more details.
21
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
24 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25 ;; Boston, MA 02111-1307, USA.
26
27 ;;; Code:
28
29 (require 'mime)
30
31 (eval-and-compile
32   (luna-define-class mime-buffer-entity (mime-entity)
33                      (buffer
34                       header-start
35                       header-end
36                       body-start
37                       body-end))
38
39   (luna-define-internal-accessors 'mime-buffer-entity)
40   )
41
42 (luna-define-method initialize-instance :after ((entity mime-buffer-entity)
43                                                 &rest init-args)
44   (mime-buffer-entity-set-buffer-internal
45    entity (mime-entity-location-internal entity))
46   (save-excursion
47     (set-buffer (mime-buffer-entity-buffer-internal entity))
48     (setq mime-message-structure entity)
49     (let ((header-start (point-min))
50           header-end
51           body-start
52           (body-end (point-max)))
53       (goto-char header-start)
54       (if (re-search-forward "^$" nil t)
55           (setq header-end (match-end 0)
56                 body-start (if (= header-end body-end)
57                                body-end
58                              (1+ header-end)))
59         (setq header-end (point-min)
60               body-start (point-min)))
61       (save-restriction
62         (narrow-to-region header-start header-end)
63         (mime-entity-set-content-type-internal
64          entity
65          (let ((str (std11-fetch-field "Content-Type")))
66            (if str
67                (mime-parse-Content-Type str)
68              )))
69         )
70       (mime-buffer-entity-set-header-start-internal entity header-start)
71       (mime-buffer-entity-set-header-end-internal entity header-end)
72       (mime-buffer-entity-set-body-start-internal entity body-start)
73       (mime-buffer-entity-set-body-end-internal entity body-end)
74       ))
75   entity)
76
77 (luna-define-method mime-entity-name ((entity mime-buffer-entity))
78   (buffer-name (mime-buffer-entity-buffer-internal entity))
79   )
80
81
82 ;;; @ message parser
83 ;;;
84
85 (defun mime-parse-multipart (entity)
86   (goto-char (point-min))
87   (let* ((representation-type
88           (mime-entity-representation-type-internal entity))
89          (content-type (mime-entity-content-type-internal entity))
90          (dash-boundary
91           (concat "--" (mime-content-type-parameter content-type "boundary")))
92          (delimiter       (concat "\n" (regexp-quote dash-boundary)))
93          (close-delimiter (concat delimiter "--[ \t]*$"))
94          (rsep (concat delimiter "[ \t]*\n"))
95          (dc-ctl
96           (if (eq (mime-content-type-subtype content-type) 'digest)
97               (make-mime-content-type 'message 'rfc822)
98             (make-mime-content-type 'text 'plain)
99             ))
100          (header-end (mime-buffer-entity-header-end-internal entity))
101          (body-end (mime-buffer-entity-body-end-internal entity)))
102     (save-restriction
103       (goto-char body-end)
104       (narrow-to-region header-end
105                         (if (re-search-backward close-delimiter nil t)
106                             (match-beginning 0)
107                           body-end))
108       (goto-char header-end)
109       (if (re-search-forward rsep nil t)
110           (let ((cb (match-end 0))
111                 ce ncb ret children
112                 (node-id (mime-entity-node-id-internal entity))
113                 (i 0))
114             (while (re-search-forward rsep nil t)
115               (setq ce (match-beginning 0))
116               (setq ncb (match-end 0))
117               (save-restriction
118                 (narrow-to-region cb ce)
119                 (setq ret (mime-parse-message representation-type dc-ctl
120                                               entity (cons i node-id)))
121                 )
122               (setq children (cons ret children))
123               (goto-char (setq cb ncb))
124               (setq i (1+ i))
125               )
126             (setq ce (point-max))
127             (save-restriction
128               (narrow-to-region cb ce)
129               (setq ret (mime-parse-message representation-type dc-ctl
130                                             entity (cons i node-id)))
131               )
132             (setq children (cons ret children))
133             (mime-entity-set-children-internal entity (nreverse children))
134             )
135         (mime-entity-set-content-type-internal
136          entity (make-mime-content-type 'message 'x-broken))
137         nil)
138       )))
139
140 (defun mime-parse-encapsulated (entity)
141   (mime-entity-set-children-internal
142    entity
143    (save-restriction
144      (narrow-to-region (mime-buffer-entity-body-start-internal entity)
145                        (mime-buffer-entity-body-end-internal entity))
146      (list (mime-parse-message
147             (mime-entity-representation-type-internal entity) nil
148             entity (cons 0 (mime-entity-node-id-internal entity))))
149      )))
150
151 (defun mime-parse-message (representation-type &optional default-ctl 
152                                                parent node-id)
153   (let ((header-start (point-min))
154         header-end
155         body-start
156         (body-end (point-max))
157         content-type)
158     (goto-char header-start)
159     (if (re-search-forward "^$" nil t)
160         (setq header-end (match-end 0)
161               body-start (if (= header-end body-end)
162                              body-end
163                            (1+ header-end)))
164       (setq header-end (point-min)
165             body-start (point-min)))
166     (save-restriction
167       (narrow-to-region header-start header-end)
168       (setq content-type (or (let ((str (std11-fetch-field "Content-Type")))
169                                (if str
170                                    (mime-parse-Content-Type str)
171                                  ))
172                              default-ctl))
173       )
174     (luna-make-entity representation-type
175                       :location (current-buffer)
176                       :content-type content-type
177                       :parent parent
178                       :node-id node-id
179                       :buffer (current-buffer)
180                       :header-start header-start
181                       :header-end header-end
182                       :body-start body-start
183                       :body-end body-end)
184     ))
185
186 (luna-define-method mime-entity-children ((entity mime-buffer-entity))
187   (let* ((content-type (mime-entity-content-type entity))
188          (primary-type (mime-content-type-primary-type content-type)))
189     (cond ((eq primary-type 'multipart)
190            (mime-parse-multipart entity)
191            )
192           ((and (eq primary-type 'message)
193                 (memq (mime-content-type-subtype content-type)
194                       '(rfc822 news external-body)
195                       ))
196            (mime-parse-encapsulated entity)
197            ))
198     ))
199
200
201 (luna-define-method mime-goto-header-start-point ((entity mime-buffer-entity))
202   (set-buffer (mime-buffer-entity-buffer-internal entity))
203   (goto-char (mime-buffer-entity-header-start-internal entity))
204   )
205
206 (defun mime-visible-field-p (field-name visible-fields invisible-fields)
207   (or (catch 'found
208         (while visible-fields
209           (let ((regexp (car visible-fields)))
210             (if (string-match regexp field-name)
211                 (throw 'found t)
212               ))
213           (setq visible-fields (cdr visible-fields))
214           ))
215       (catch 'found
216         (while invisible-fields
217           (let ((regexp (car invisible-fields)))
218             (if (string-match regexp field-name)
219                 (throw 'found nil)
220               ))
221           (setq invisible-fields (cdr invisible-fields))
222           )
223         t)))
224
225 (defun mime-insert-header-from-buffer (buffer start end
226                                               &optional invisible-fields
227                                               visible-fields)
228   (let ((the-buf (current-buffer))
229         (mode-obj (mime-find-field-presentation-method 'wide))
230         field-decoder
231         f-b p f-e field-name len field field-body)
232     (save-excursion
233       (set-buffer buffer)
234       (save-restriction
235         (narrow-to-region start end)
236         (goto-char start)
237         (while (re-search-forward std11-field-head-regexp nil t)
238           (setq f-b (match-beginning 0)
239                 p (match-end 0)
240                 field-name (buffer-substring f-b p)
241                 len (string-width field-name)
242                 f-e (std11-field-end))
243           (when (mime-visible-field-p field-name
244                                       visible-fields invisible-fields)
245             (setq field (intern
246                          (capitalize (buffer-substring f-b (1- p))))
247                   field-body (buffer-substring p f-e)
248                   field-decoder (inline (mime-find-field-decoder-internal
249                                          field mode-obj)))
250             (with-current-buffer the-buf
251               (insert field-name)
252               (insert (if field-decoder
253                           (funcall field-decoder field-body len)
254                         ;; Don't decode
255                         field-body))
256               (insert "\n")
257               )))))))
258
259 (luna-define-method mime-insert-header ((entity mime-buffer-entity)
260                                         &optional invisible-fields
261                                         visible-fields)
262   (mime-insert-header-from-buffer
263    (mime-buffer-entity-buffer-internal entity)
264    (mime-buffer-entity-header-start-internal entity)
265    (mime-buffer-entity-header-end-internal entity)
266    invisible-fields visible-fields)
267   )
268
269 (luna-define-method mime-entity-content ((entity mime-buffer-entity))
270   (save-excursion
271     (set-buffer (mime-buffer-entity-buffer-internal entity))
272     (mime-decode-string
273      (buffer-substring (mime-buffer-entity-body-start-internal entity)
274                        (mime-buffer-entity-body-end-internal entity))
275      (mime-entity-encoding entity))))
276
277 (luna-define-method mime-insert-text-content ((entity mime-buffer-entity))
278   (insert
279    (decode-mime-charset-string (mime-entity-content entity)
280                                (or (mime-content-type-parameter
281                                     (mime-entity-content-type entity)
282                                     "charset")
283                                    default-mime-charset)
284                                'CRLF)
285    ))
286
287 ;;; redefine to speed up
288
289 (mm-define-method entity-point-min ((entity buffer))
290   (mime-buffer-entity-header-start-internal entity))
291
292 (mm-define-method entity-point-max ((entity buffer))
293   (mime-buffer-entity-body-end-internal entity))
294
295 (luna-define-method mime-entity-fetch-field ((entity mime-buffer-entity)
296                                              field-name)
297   (save-excursion
298     (set-buffer (mime-buffer-entity-buffer-internal entity))
299     (save-restriction
300       (narrow-to-region (mime-buffer-entity-header-start-internal entity)
301                         (mime-buffer-entity-header-end-internal entity))
302       (std11-fetch-field field-name)
303       )))
304
305 (mm-define-method insert-entity-content ((entity buffer))
306   (insert (with-current-buffer (mime-buffer-entity-buffer-internal entity)
307             (mime-decode-string
308              (buffer-substring (mime-buffer-entity-body-start-internal entity)
309                                (mime-buffer-entity-body-end-internal entity))
310              (mime-entity-encoding entity)))))
311
312 (mm-define-method write-entity-content ((entity buffer) filename)
313   (save-excursion
314     (set-buffer (mime-buffer-entity-buffer-internal entity))
315     (mime-write-decoded-region (mime-buffer-entity-body-start-internal entity)
316                                (mime-buffer-entity-body-end-internal entity)
317                                filename
318                                (or (mime-entity-encoding entity) "7bit"))
319     ))
320
321 (mm-define-method insert-entity ((entity buffer))
322   (insert-buffer-substring (mime-buffer-entity-buffer-internal entity)
323                            (mime-buffer-entity-header-start-internal entity)
324                            (mime-buffer-entity-body-end-internal entity))
325   )
326
327 (mm-define-method write-entity ((entity buffer) filename)
328   (save-excursion
329     (set-buffer (mime-buffer-entity-buffer-internal entity))
330     (write-region-as-raw-text-CRLF
331      (mime-buffer-entity-header-start-internal entity)
332      (mime-buffer-entity-body-end-internal entity)
333      filename)
334     ))
335
336 (mm-define-method write-entity-body ((entity buffer) filename)
337   (save-excursion
338     (set-buffer (mime-buffer-entity-buffer-internal entity))
339     (write-region-as-binary (mime-buffer-entity-body-start-internal entity)
340                             (mime-buffer-entity-body-end-internal entity)
341                             filename)
342     ))
343
344
345 ;;; @ buffer
346 ;;;
347
348 (luna-define-method mime-entity-header-buffer ((entity mime-buffer-entity))
349   (mime-buffer-entity-buffer-internal entity)
350   )
351
352 (luna-define-method mime-entity-body-buffer ((entity mime-buffer-entity))
353   (mime-buffer-entity-buffer-internal entity)
354   )
355
356 (luna-define-method mime-entity-buffer ((entity mime-buffer-entity))
357   (mime-buffer-entity-buffer-internal entity)
358   )
359
360 (luna-define-method mime-entity-point-min ((entity mime-buffer-entity))
361   (mime-buffer-entity-header-start-internal entity)
362   )
363
364 (luna-define-method mime-entity-point-max ((entity mime-buffer-entity))
365   (mime-buffer-entity-body-end-internal entity)
366   )
367
368
369 ;;; @ utility
370 ;;;
371
372 ;;;###autoload
373 (defun mime-parse-buffer (&optional buffer representation-type)
374   "Parse BUFFER as a MIME message.
375 If buffer is omitted, it parses current-buffer."
376   (save-excursion
377     (if buffer (set-buffer buffer))
378     (setq mime-message-structure
379           (mime-parse-message (or representation-type 'buffer) nil))
380     ))
381
382
383 ;;; @ end
384 ;;;
385
386 (provide 'mmbuffer)
387
388 ;;; mmbuffer.el ends here