b8a167c5384365a9e5ad660db3f20e65cbd84d4d
[elisp/wanderlust.git] / elmo / mmimap.el
1 ;;; mmimap.el --- MIME entity module for IMAP4rev1 (RFC2060).
2 ;;                **** This is EXPERIMENTAL *****
3
4 ;; Copyright (C) 2000 Yuuichi Teranishi <teranisi@gohome.org>
5
6 ;; Author: Yuuichi Teranishi <teranisi@gohome.org>
7 ;; Keywords: IMAP, MIME, multimedia, mail, news
8
9 ;; This file is part of FLIM (Faithful Library about Internet Message).
10
11 ;; This program is free software; you can redistribute it and/or
12 ;; modify it under the terms of the GNU General Public License as
13 ;; published by the Free Software Foundation; either version 2, or (at
14 ;; your option) any later version.
15
16 ;; This program is distributed in the hope that it will be useful, but
17 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19 ;; General Public License for more details.
20
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.
25
26 ;;; Commentary:
27 ;;
28
29 ;;; Code:
30
31 (require 'mmgeneric)
32 (require 'mime)
33 (require 'pces)
34 (require 'static)
35 (require 'mime-parse)
36
37 (eval-and-compile
38   (luna-define-class mime-imap-entity (mime-entity)
39                      (size header-string body-string new requested))
40   (luna-define-internal-accessors 'mime-imap-entity))
41
42 ;;; @ MIME IMAP location
43 ;;    It should contain server, mailbox and uid (sequence number).
44 (eval-and-compile
45   (luna-define-class mime-imap-location () ()))
46
47 (luna-define-generic mime-imap-location-section-body (location section)
48   "Return a body string from LOCATION which corresponds to SECTION.
49 SECTION is a section string which is defined in RFC2060.")
50
51 (luna-define-generic mime-imap-location-bodystructure (location)
52   "Return a parsed bodystructure of LOCATION.
53 `NIL' should be converted to nil, `astring' should be converted to a string.")
54
55 (luna-define-generic mime-imap-location-fetch-entity-p (location entity)
56   "Return non-nil when LOCATION may fetch the ENTITY.")
57
58 ;;; @ Subroutines
59 ;;
60
61 (defun mmimap-entity-section (node-id)
62   "Return a section string from NODE-ID"
63   (cond
64    ((numberp node-id)
65     (number-to-string (1+ node-id)))
66    ((listp node-id)
67     (mapconcat
68      'mmimap-entity-section
69      (reverse node-id)
70      "."))))
71
72 (eval-and-compile
73   (defun-maybe mime-decode-parameters (attrlist)
74     (let (ret-val)
75       (while attrlist
76         (setq ret-val (append ret-val
77                               (list (cons (downcase (car attrlist))
78                                           (car (cdr attrlist))))))
79         (setq attrlist (cdr (cdr attrlist))))
80       ret-val)))
81
82 (defun mmimap-make-mime-entity (bodystructure class location node-id number
83                                               parent)
84   "Analyze parsed IMAP4 BODYSTRUCTURE response and make MIME entity.
85 CLASS, LOCATION, NODE-ID, PARENT are set to the returned entity."
86   (setq node-id (if number (cons number node-id) node-id))
87   (cond
88    ((listp (car bodystructure)) ; multipart
89     (let ((num 0)
90           curp children content-type entity)
91       (setq entity
92             (luna-make-entity
93              class
94              :new      t
95              :parent   parent
96              :location location
97              :node-id  node-id))
98       (while (and (setq curp (car bodystructure))
99                   (listp curp))
100         (setq children
101               (nconc children
102                      (list
103                       (mmimap-make-mime-entity curp class
104                                                location
105                                                node-id
106                                                num
107                                                entity))))
108         (setq num (+ num 1))
109         (setq bodystructure (cdr bodystructure)))
110       (mime-entity-set-children-internal entity children)
111       (mime-entity-set-content-type-internal
112        entity
113        (make-mime-content-type 'multipart
114                                (if (car bodystructure)
115                                    (intern (downcase
116                                             (car bodystructure))))
117                                (mime-decode-parameters
118                                 (nth 1 bodystructure))))
119       entity))
120    (t ; singlepart
121     (let (content-type entity)
122       (setq entity
123             (luna-make-entity
124              class
125              :new  t
126              :size (nth 6 bodystructure)
127              :content-type content-type
128              :location location
129              :parent parent
130              :node-id node-id))
131       (mime-entity-set-content-type-internal
132        entity
133        (make-mime-content-type (intern (downcase (car bodystructure)))
134                                (if (nth 1 bodystructure)
135                                    (intern (downcase
136                                             (nth 1 bodystructure))))
137                                (mime-decode-parameters
138                                 (nth 2 bodystructure))))
139       (mime-entity-set-encoding-internal entity
140                                          (and (nth 5 bodystructure)
141                                               (downcase
142                                                (nth 5 bodystructure))))
143       (if (and (nth 7 bodystructure)
144                (nth 8 bodystructure))  ; children.
145           (mime-entity-set-children-internal
146            entity
147            (list (mmimap-make-mime-entity
148                   (nth 8 bodystructure) class
149                   location node-id 0
150                   entity))))
151       entity))))
152
153 (luna-define-method initialize-instance :after ((entity mime-imap-entity)
154                                                 &rest init-args)
155   ;; To prevent infinite loop...
156   (if (mime-imap-entity-new-internal entity)
157       entity
158     (mmimap-make-mime-entity
159      (mime-imap-location-bodystructure
160       (mime-entity-location-internal entity))
161      (luna-class-name entity)
162      (mime-entity-location-internal entity)
163      nil nil nil)))
164
165 ;;; @ entity
166 ;;
167
168 (luna-define-method mime-insert-entity ((entity mime-imap-entity))
169   (if (mime-root-entity-p entity)
170       (progn
171         (insert (mime-imap-entity-header-string entity))
172         (mime-insert-entity-body entity))
173     ;; Insert body if it is not a multipart.
174     (unless (eq (mime-content-type-primary-type
175                  (mime-entity-content-type entity))
176                 'multipart)
177       (mime-insert-entity-body entity))))
178
179 (luna-define-method mime-write-entity ((entity mime-imap-entity) filename)
180   (with-temp-buffer
181     (mime-insert-entity entity)
182     (write-region-as-raw-text-CRLF (point-min) (point-max) filename)))
183
184 ;;; @ entity body
185 ;;
186
187 (luna-define-method mime-entity-body ((entity mime-imap-entity))
188   (or (mime-imap-entity-body-string-internal entity)
189       (if (or (mime-imap-entity-requested-internal entity) ; second time.
190               (mime-imap-location-fetch-entity-p
191                (mime-entity-location-internal entity)
192                entity))
193           (mime-imap-entity-set-body-string-internal
194            entity
195            (mime-imap-location-section-body
196             (mime-entity-location-internal entity)
197             (mmimap-entity-section
198              (mime-entity-node-id-internal entity))))
199         (mime-imap-entity-set-requested-internal entity t)
200         "")))
201
202 (luna-define-method mime-insert-entity-body ((entity mime-imap-entity))
203   (insert (mime-entity-body entity)))
204
205 (luna-define-method mime-write-entity-body ((entity mime-imap-entity)
206                                             filename)
207   (with-temp-buffer
208     (mime-insert-entity-body entity)
209     (write-region-as-binary (point-min) (point-max) filename)))
210
211 ;;; @ entity content
212 ;;
213
214 (luna-define-method mime-entity-content ((entity mime-imap-entity))
215   (let ((ret (mime-entity-body entity)))
216     (if ret
217         (mime-decode-string ret (mime-entity-encoding entity))
218       (message "Cannot decode content.")
219       nil)))
220
221 (luna-define-method mime-insert-entity-content ((entity mime-imap-entity))
222   (insert (mime-entity-content entity)))
223
224 (luna-define-method mime-write-entity-content ((entity mime-imap-entity)
225                                                filename)
226   (with-temp-buffer
227     (mime-insert-entity-body entity)
228     (mime-write-decoded-region (point-min) (point-max)
229                                filename
230                                (or (mime-entity-encoding entity) "7bit"))))
231
232 ;;; @ header field
233 ;;
234
235 (defun mime-imap-entity-header-string (entity)
236   (or (mime-imap-entity-header-string-internal entity)
237       (mime-imap-entity-set-header-string-internal
238        entity
239        (mime-imap-location-section-body
240         (mime-entity-location-internal entity)
241         (if (mime-entity-node-id-internal entity)
242             (concat (mmimap-entity-section
243                      (mime-entity-node-id-internal entity))
244                     ".HEADER")
245           "HEADER")))))
246
247 (luna-define-method mime-entity-fetch-field :around
248   ((entity mime-imap-entity) field-name)
249   (if (mime-root-entity-p entity)
250       (or (luna-call-next-method)
251           (with-temp-buffer
252             (insert (mime-imap-entity-header-string entity))
253             (let ((ret (std11-fetch-field field-name)))
254               (when ret
255                 (or (symbolp field-name)
256                     (setq field-name
257                           (intern (capitalize (capitalize field-name)))))
258                 (mime-entity-set-original-header-internal
259                  entity
260                  (put-alist field-name ret
261                             (mime-entity-original-header-internal entity)))
262                 ret))))))
263
264 (luna-define-method mime-insert-header ((entity mime-imap-entity)
265                                         &optional invisible-fields
266                                         visible-fields)
267   (let ((the-buf (current-buffer))
268         buf p-min p-max)
269     (with-temp-buffer
270       (insert (mime-imap-entity-header-string entity))
271       (setq buf (current-buffer)
272             p-min (point-min)
273             p-max (point-max))
274       (set-buffer the-buf)
275       (mime-insert-header-from-buffer buf p-min p-max
276                                       invisible-fields visible-fields))))
277
278 ;;; @ end
279 ;;
280
281 (provide 'mmimap)
282
283 ;;; mmimap.el ends here