* elmo.el (elmo-folder-list-flagged): New generic function.
[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    ((null node-id)
65     "1")
66    ((numberp node-id)
67     (number-to-string (1+ node-id)))
68    ((listp node-id)
69     (mapconcat
70      'mmimap-entity-section
71      (reverse node-id)
72      "."))))
73
74 (eval-and-compile
75   (defun-maybe mime-decode-parameters (attrlist)
76     (let (ret-val)
77       (while attrlist
78         (setq ret-val (append ret-val
79                               (list (cons (downcase (car attrlist))
80                                           (car (cdr attrlist))))))
81         (setq attrlist (cdr (cdr attrlist))))
82       ret-val)))
83
84 (defun mmimap-make-mime-entity (bodystructure class location node-id number
85                                               parent)
86   "Analyze parsed IMAP4 BODYSTRUCTURE response and make MIME entity.
87 CLASS, LOCATION, NODE-ID, PARENT are set to the returned entity."
88   (setq node-id (if number (cons number node-id) node-id))
89   (cond
90    ((listp (car bodystructure)) ; multipart
91     (let ((num 0)
92           curp children content-type entity)
93       (setq entity
94             (luna-make-entity
95              class
96              :new      t
97              :parent   parent
98              :location location
99              :node-id  node-id))
100       (while (and (setq curp (car bodystructure))
101                   (listp curp))
102         (setq children
103               (nconc children
104                      (list
105                       (mmimap-make-mime-entity curp class
106                                                location
107                                                node-id
108                                                num
109                                                entity))))
110         (setq num (+ num 1))
111         (setq bodystructure (cdr bodystructure)))
112       (mime-entity-set-children-internal entity children)
113       (mime-entity-set-content-type-internal
114        entity
115        (make-mime-content-type 'multipart
116                                (if (car bodystructure)
117                                    (intern (downcase
118                                             (car bodystructure))))
119                                (mime-decode-parameters
120                                 (nth 1 bodystructure))))
121       entity))
122    (t ; singlepart
123     (let (content-type entity)
124       (setq entity
125             (luna-make-entity
126              class
127              :new  t
128              :size (nth 6 bodystructure)
129              :content-type content-type
130              :location location
131              :parent parent
132              :node-id node-id))
133       (mime-entity-set-content-type-internal
134        entity
135        (make-mime-content-type (intern (downcase (car bodystructure)))
136                                (if (nth 1 bodystructure)
137                                    (intern (downcase
138                                             (nth 1 bodystructure))))
139                                (mime-decode-parameters
140                                 (nth 2 bodystructure))))
141       (mime-entity-set-encoding-internal entity
142                                          (and (nth 5 bodystructure)
143                                               (downcase
144                                                (nth 5 bodystructure))))
145       (if (and (nth 7 bodystructure)
146                (nth 8 bodystructure))  ; children.
147           (mime-entity-set-children-internal
148            entity
149            (list (mmimap-make-mime-entity
150                   (nth 8 bodystructure) class
151                   location node-id 0
152                   entity))))
153       entity))))
154
155 (luna-define-method initialize-instance :after ((entity mime-imap-entity)
156                                                 &rest init-args)
157   ;; To prevent infinite loop...
158   (if (mime-imap-entity-new-internal entity)
159       entity
160     (mmimap-make-mime-entity
161      (mime-imap-location-bodystructure
162       (mime-entity-location-internal entity))
163      (luna-class-name entity)
164      (mime-entity-location-internal entity)
165      nil nil nil)))
166
167 ;;; @ entity
168 ;;
169
170 (luna-define-method mime-insert-entity ((entity mime-imap-entity))
171   (if (mime-root-entity-p entity)
172       (progn
173         (insert (mime-imap-entity-header-string entity))
174         (mime-insert-entity-body entity))
175     ;; Insert body if it is not a multipart.
176     (unless (eq (mime-content-type-primary-type
177                  (mime-entity-content-type entity))
178                 'multipart)
179       (mime-insert-entity-body entity))))
180
181 (luna-define-method mime-write-entity ((entity mime-imap-entity) filename)
182   (with-temp-buffer
183     (mime-insert-entity entity)
184     (write-region-as-raw-text-CRLF (point-min) (point-max) filename)))
185
186 ;;; @ entity body
187 ;;
188
189 (luna-define-method mime-entity-body ((entity mime-imap-entity))
190   (or (mime-imap-entity-body-string-internal entity)
191       (if (or (mime-imap-entity-requested-internal entity) ; second time.
192               (mime-imap-location-fetch-entity-p
193                (mime-entity-location-internal entity)
194                entity))
195           (mime-imap-entity-set-body-string-internal
196            entity
197            (mime-imap-location-section-body
198             (mime-entity-location-internal entity)
199             (mmimap-entity-section
200              (mime-entity-node-id-internal entity))))
201         (mime-imap-entity-set-requested-internal entity t)
202         "")))
203
204 (luna-define-method mime-insert-entity-body ((entity mime-imap-entity))
205   (insert (mime-entity-body entity)))
206
207 (luna-define-method mime-write-entity-body ((entity mime-imap-entity)
208                                             filename)
209   (with-temp-buffer
210     (mime-insert-entity-body entity)
211     (write-region-as-binary (point-min) (point-max) filename)))
212
213 ;;; @ entity content
214 ;;
215
216 (luna-define-method mime-entity-content ((entity mime-imap-entity))
217   (let ((ret (mime-entity-body entity)))
218     (if ret
219         (mime-decode-string ret (mime-entity-encoding entity))
220       (message "Cannot decode content.")
221       nil)))
222
223 (luna-define-method mime-insert-entity-content ((entity mime-imap-entity))
224   (insert (mime-entity-content entity)))
225
226 (luna-define-method mime-write-entity-content ((entity mime-imap-entity)
227                                                filename)
228   (with-temp-buffer
229     (mime-insert-entity-body entity)
230     (mime-write-decoded-region (point-min) (point-max)
231                                filename
232                                (or (mime-entity-encoding entity) "7bit"))))
233
234 ;;; @ header field
235 ;;
236
237 (defun mime-imap-entity-header-string (entity)
238   (or (mime-imap-entity-header-string-internal entity)
239       (mime-imap-entity-set-header-string-internal
240        entity
241        (mime-imap-location-section-body
242         (mime-entity-location-internal entity)
243         (if (mime-entity-node-id-internal entity)
244             (concat (mmimap-entity-section
245                      (mime-entity-node-id-internal entity))
246                     ".HEADER")
247           "HEADER")))))
248
249 (luna-define-method mime-entity-fetch-field :around
250   ((entity mime-imap-entity) field-name)
251   (if (mime-root-entity-p entity)
252       (or (luna-call-next-method)
253           (with-temp-buffer
254             (insert (mime-imap-entity-header-string entity))
255             (let ((ret (std11-fetch-field field-name)))
256               (when ret
257                 (or (symbolp field-name)
258                     (setq field-name
259                           (intern (capitalize (capitalize field-name)))))
260                 (mime-entity-set-original-header-internal
261                  entity
262                  (put-alist field-name ret
263                             (mime-entity-original-header-internal entity)))
264                 ret))))))
265
266 (luna-define-method mime-insert-header ((entity mime-imap-entity)
267                                         &optional invisible-fields
268                                         visible-fields)
269   (let ((the-buf (current-buffer))
270         buf p-min p-max)
271     (with-temp-buffer
272       (insert (mime-imap-entity-header-string entity))
273       (setq buf (current-buffer)
274             p-min (point-min)
275             p-max (point-max))
276       (set-buffer the-buf)
277       (mime-insert-header-from-buffer buf p-min p-max
278                                       invisible-fields visible-fields))))
279
280 ;;; @ end
281 ;;
282
283 (provide 'mmimap)
284
285 ;;; mmimap.el ends here