Merge flim-1_10_4.
[elisp/flim.git] / mime-def.el
1 ;;; mime-def.el --- definition module about MIME
2
3 ;; Copyright (C) 1995,1996,1997,1998 Free Software Foundation, Inc.
4
5 ;; Author: MORIOKA Tomohiko <morioka@jaist.ac.jp>
6 ;; Keywords: definition, MIME, multimedia, mail, news
7
8 ;; This file is part of FLIM (Faithful Library about Internet Message).
9
10 ;; This program is free software; you can redistribute it and/or
11 ;; modify it under the terms of the GNU General Public License as
12 ;; published by the Free Software Foundation; either version 2, or (at
13 ;; your option) any later version.
14
15 ;; This program is distributed in the hope that it will be useful, but
16 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18 ;; General Public License for more details.
19
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.
24
25 ;;; Code:
26
27 (eval-and-compile
28   (defconst mime-library-product ["FLIM" (1 10 4) "Shin-H\e.D\8eòsono"]
29     "Product name, version number and code name of MIME-library package.")
30   )
31
32 (defmacro mime-product-name (product)
33   `(aref ,product 0))
34
35 (defmacro mime-product-version (product)
36   `(aref ,product 1))
37
38 (defmacro mime-product-code-name (product)
39   `(aref ,product 2))
40
41 (defconst mime-library-version
42   (eval-when-compile
43     (concat (mime-product-name mime-library-product) " "
44             (mapconcat #'number-to-string
45                        (mime-product-version mime-library-product) ".")
46             " - \"" (mime-product-code-name mime-library-product) "\"")))
47
48
49 ;;; @ variables
50 ;;;
51
52 (require 'custom)
53
54 (eval-when-compile (require 'cl))
55
56 (defgroup mime nil
57   "Emacs MIME Interfaces"
58   :group 'news
59   :group 'mail)
60
61 (custom-handle-keyword 'default-mime-charset :group 'mime
62                        'custom-variable)
63
64 (defcustom mime-temp-directory (or (getenv "MIME_TMP_DIR")
65                                    (getenv "TM_TMP_DIR")
66                                    (getenv "TMPDIR")
67                                    (getenv "TMP")
68                                    (getenv "TEMP")
69                                    "/tmp/")
70   "*Directory for temporary files."
71   :group 'mime
72   :type 'directory)
73
74 (defcustom mime-uuencode-encoding-name-list '("x-uue" "x-uuencode")
75   "*List of encoding names for uuencode format."
76   :group 'mime
77   :type '(repeat string))
78
79
80 ;;; @ required functions
81 ;;;
82
83 (defsubst eliminate-top-spaces (string)
84   "Eliminate top sequence of space or tab in STRING."
85   (if (string-match "^[ \t]+" string)
86       (substring string (match-end 0))
87     string))
88
89 (defsubst regexp-* (regexp)
90   (concat regexp "*"))
91
92 (defsubst regexp-or (&rest args)
93   (concat "\\(" (mapconcat (function identity) args "\\|") "\\)"))
94
95
96 ;;; @ about STD 11
97 ;;;
98
99 (defconst std11-quoted-pair-regexp "\\\\.")
100 (defconst std11-non-qtext-char-list '(?\" ?\\ ?\r ?\n))
101 (defconst std11-qtext-regexp
102   (concat "[^" (char-list-to-string std11-non-qtext-char-list) "]"))
103 (defconst std11-quoted-string-regexp
104   (concat "\""
105           (regexp-*
106            (regexp-or std11-qtext-regexp std11-quoted-pair-regexp))
107           "\""))
108
109
110 ;;; @ about MIME
111 ;;;
112
113 (defconst mime-tspecials "][()<>@,\;:\\\"/?=")
114 (defconst mime-token-regexp (concat "[^" mime-tspecials "\000-\040]+"))
115 (defconst mime-charset-regexp mime-token-regexp)
116
117 (defconst mime-media-type/subtype-regexp
118   (concat mime-token-regexp "/" mime-token-regexp))
119
120
121 ;;; @@ base64 / B
122 ;;;
123
124 (defconst base64-token-regexp "[A-Za-z0-9+/]")
125 (defconst base64-token-padding-regexp "[A-Za-z0-9+/=]")
126
127 (defconst B-encoded-text-regexp
128   (concat "\\(\\("
129           base64-token-regexp
130           base64-token-regexp
131           base64-token-regexp
132           base64-token-regexp
133           "\\)*"
134           base64-token-regexp
135           base64-token-regexp
136           base64-token-padding-regexp
137           base64-token-padding-regexp
138           "\\)"))
139
140 ;; (defconst eword-B-encoding-and-encoded-text-regexp
141 ;;   (concat "\\(B\\)\\?" eword-B-encoded-text-regexp))
142
143
144 ;;; @@ Quoted-Printable / Q
145 ;;;
146
147 (defconst quoted-printable-hex-chars "0123456789ABCDEF")
148
149 (defconst quoted-printable-octet-regexp
150   (concat "=[" quoted-printable-hex-chars
151           "][" quoted-printable-hex-chars "]"))
152
153 (defconst Q-encoded-text-regexp
154   (concat "\\([^=?]\\|" quoted-printable-octet-regexp "\\)+"))
155
156 ;; (defconst eword-Q-encoding-and-encoded-text-regexp
157 ;;   (concat "\\(Q\\)\\?" eword-Q-encoded-text-regexp))
158
159
160 ;;; @ Content-Type
161 ;;;
162
163 (defsubst make-mime-content-type (type subtype &optional parameters)
164   (list* (cons 'type type)
165          (cons 'subtype subtype)
166          (nreverse parameters))
167   )
168
169 (defsubst mime-content-type-primary-type (content-type)
170   "Return primary-type of CONTENT-TYPE."
171   (cdr (car content-type)))
172
173 (defsubst mime-content-type-subtype (content-type)
174   "Return primary-type of CONTENT-TYPE."
175   (cdr (cadr content-type)))
176
177 (defsubst mime-content-type-parameters (content-type)
178   "Return primary-type of CONTENT-TYPE."
179   (cddr content-type))
180
181 (defsubst mime-content-type-parameter (content-type parameter)
182   "Return PARAMETER value of CONTENT-TYPE."
183   (cdr (assoc parameter (mime-content-type-parameters content-type))))
184
185
186 (defsubst mime-type/subtype-string (type &optional subtype)
187   "Return type/subtype string from TYPE and SUBTYPE."
188   (if type
189       (if subtype
190           (format "%s/%s" type subtype)
191         (format "%s" type))))
192
193
194 ;;; @ Content-Disposition
195 ;;;
196
197 (defsubst mime-content-disposition-type (content-disposition)
198   "Return disposition-type of CONTENT-DISPOSITION."
199   (cdr (car content-disposition)))
200
201 (defsubst mime-content-disposition-parameters (content-disposition)
202   "Return disposition-parameters of CONTENT-DISPOSITION."
203   (cdr content-disposition))
204
205 (defsubst mime-content-disposition-parameter (content-disposition parameter)
206   "Return PARAMETER value of CONTENT-DISPOSITION."
207   (cdr (assoc parameter (cdr content-disposition))))
208
209 (defsubst mime-content-disposition-filename (content-disposition)
210   "Return filename of CONTENT-DISPOSITION."
211   (mime-content-disposition-parameter content-disposition "filename"))
212
213
214 ;;; @ MIME entity
215 ;;;
216
217 (defsubst make-mime-entity-internal (representation-type location
218                                      &optional content-type
219                                      children parent node-id
220                                      buffer
221                                      header-start header-end
222                                      body-start body-end)
223   (vector representation-type location
224           content-type nil nil children parent node-id
225           buffer header-start header-end body-start body-end
226           nil nil))
227
228 (defsubst mime-entity-representation-type-internal (entity)
229   (aref entity 0))
230 (defsubst mime-entity-set-representation-type-internal (entity type)
231   (aset entity 0 type))
232 (defsubst mime-entity-location-internal (entity)
233   (aref entity 1))
234
235 (defsubst mime-entity-content-type-internal (entity)
236   (aref entity 2))
237 (defsubst mime-entity-set-content-type-internal (entity type)
238   (aset entity 2 type))
239 (defsubst mime-entity-content-disposition-internal (entity)
240   (aref entity 3))
241 (defsubst mime-entity-set-content-disposition-internal (entity disposition)
242   (aset entity 3 disposition))
243 (defsubst mime-entity-encoding-internal (entity)
244   (aref entity 4))
245 (defsubst mime-entity-set-encoding-internal (entity encoding)
246   (aset entity 4 encoding))
247
248 (defsubst mime-entity-children-internal (entity)
249   (aref entity 5))
250 (defsubst mime-entity-set-children-internal (entity children)
251   (aset entity 5 children))
252 (defsubst mime-entity-parent-internal (entity)
253   (aref entity 6))
254 (defsubst mime-entity-node-id-internal (entity)
255   (aref entity 7))
256
257 (defsubst mime-entity-buffer-internal (entity)
258   (aref entity 8))
259 (defsubst mime-entity-set-buffer-internal (entity buffer)
260   (aset entity 8 buffer))
261 (defsubst mime-entity-header-start-internal (entity)
262   (aref entity 9))
263 (defsubst mime-entity-set-header-start-internal (entity point)
264   (aset entity 9 point))
265 (defsubst mime-entity-header-end-internal (entity)
266   (aref entity 10))
267 (defsubst mime-entity-set-header-end-internal (entity point)
268   (aset entity 10 point))
269 (defsubst mime-entity-body-start-internal (entity)
270   (aref entity 11))
271 (defsubst mime-entity-set-body-start-internal (entity point)
272   (aset entity 11 point))
273 (defsubst mime-entity-body-end-internal (entity)
274   (aref entity 12))
275 (defsubst mime-entity-set-body-end-internal (entity point)
276   (aset entity 12 point))
277
278 (defsubst mime-entity-original-header-internal (entity)
279   (aref entity 13))
280 (defsubst mime-entity-set-original-header-internal (entity header)
281   (aset entity 13 header))
282 (defsubst mime-entity-parsed-header-internal (entity)
283   (aref entity 14))
284 (defsubst mime-entity-set-parsed-header-internal (entity header)
285   (aset entity 14 header))
286
287
288 ;;; @ message structure
289 ;;;
290
291 (defvar mime-message-structure nil
292   "Information about structure of message.
293 Please use reference function `mime-entity-SLOT' to get value of SLOT.
294
295 Following is a list of slots of the structure:
296
297 buffer                  buffer includes this entity (buffer).
298 node-id                 node-id (list of integers)
299 header-start            minimum point of header in raw-buffer
300 header-end              maximum point of header in raw-buffer
301 body-start              minimum point of body in raw-buffer
302 body-end                maximum point of body in raw-buffer
303 content-type            content-type (content-type)
304 content-disposition     content-disposition (content-disposition)
305 encoding                Content-Transfer-Encoding (string or nil)
306 children                entities included in this entity (list of entity)
307
308 If an entity includes other entities in its body, such as multipart or
309 message/rfc822, `mime-entity' structures of them are included in
310 `children', so the `mime-entity' structure become a tree.")
311
312 (make-variable-buffer-local 'mime-message-structure)
313
314
315 ;;; @ for mm-backend
316 ;;;
317
318 (require 'alist)
319
320 (defvar mime-entity-implementation-alist nil)
321
322 (defmacro mm-define-backend (type &optional parents)
323   "Define TYPE as a mm-backend.
324 If PARENTS is specified, TYPE inherits PARENTS.
325 Each parent must be backend name (symbol)."
326   (if parents
327       `(let ((rest ',(reverse parents)))
328          (while rest
329            (set-alist 'mime-entity-implementation-alist
330                       ',type
331                       (copy-alist
332                        (cdr (assq (car rest)
333                                   mime-entity-implementation-alist))))
334            (setq rest (cdr rest))
335            ))))
336
337 (defmacro mm-define-method (name args &rest body)
338   "Define NAME as a method function of (nth 1 (car ARGS)) backend.
339
340 ARGS is like an argument list of lambda, but (car ARGS) must be
341 specialized parameter.  (car (car ARGS)) is name of variable and (nth
342 1 (car ARGS)) is name of backend."
343   (let* ((specializer (car args))
344          (class (nth 1 specializer))
345          (self (car specializer)))
346     `(let ((imps (cdr (assq ',class mime-entity-implementation-alist)))
347            (func (lambda ,(if self
348                               (cons self (cdr args))
349                             (cdr args))
350                    ,@body)))
351        (if imps
352            (set-alist 'mime-entity-implementation-alist
353                       ',class (put-alist ',name func imps))
354          (set-alist 'mime-entity-implementation-alist
355                     ',class
356                     (list (cons ',name func)))
357          ))))
358
359 (put 'mm-define-method 'lisp-indent-function 'defun)
360 (put 'mm-define-method 'edebug-form-spec
361      '(&define name ((arg symbolp) &rest arg) def-body))
362
363 (defsubst mm-arglist-to-arguments (arglist)
364   (let (dest)
365     (while arglist
366       (let ((arg (car arglist)))
367         (or (memq arg '(&optional &rest))
368             (setq dest (cons arg dest)))
369         )
370       (setq arglist (cdr arglist)))
371     (nreverse dest)))
372
373
374 ;;; @ for mel-backend
375 ;;;
376
377 (defvar mel-service-list nil)
378
379 (defmacro mel-define-service (name &optional args &rest rest)
380   "Define NAME as a service for Content-Transfer-Encodings.
381 If ARGS is specified, NAME is defined as a generic function for the
382 service."
383   `(progn
384      (add-to-list 'mel-service-list ',name)
385      (defvar ,(intern (format "%s-obarray" name)) (make-vector 1 nil))
386      ,@(if args
387            `((defun ,name ,args
388                ,@rest
389                (funcall (mel-find-function ',name ,(car (last args)))
390                         ,@(mm-arglist-to-arguments (butlast args)))
391                )))
392      ))
393
394 (put 'mel-define-service 'lisp-indent-function 'defun)
395
396
397 (defvar mel-encoding-module-alist nil)
398
399 (defsubst mel-find-function-from-obarray (ob-array encoding)
400   (let* ((f (intern-soft encoding ob-array)))
401     (or f
402         (let ((rest (cdr (assoc encoding mel-encoding-module-alist))))
403           (while (and rest
404                       (progn
405                         (require (car rest))
406                         (null (setq f (intern-soft encoding ob-array)))
407                         ))
408             (setq rest (cdr rest))
409             )
410           f))))
411
412 (defsubst mel-copy-method (service src-backend dst-backend)
413   (let* ((oa (symbol-value (intern (format "%s-obarray" service))))
414          (f (mel-find-function-from-obarray oa src-backend))
415          sym)
416     (when f
417       (setq sym (intern dst-backend oa))
418       (or (fboundp sym)
419           (fset sym (symbol-function f))
420           ))))
421        
422 (defsubst mel-copy-backend (src-backend dst-backend)
423   (let ((services mel-service-list))
424     (while services
425       (mel-copy-method (car services) src-backend dst-backend)
426       (setq services (cdr services)))))
427
428 (defmacro mel-define-backend (type &optional parents)
429   "Define TYPE as a mel-backend.
430 If PARENTS is specified, TYPE inherits PARENTS.
431 Each parent must be backend name (string)."
432   (cons 'progn
433         (mapcar (lambda (parent)
434                   `(mel-copy-backend ,parent ,type)
435                   )
436                 parents)))
437
438 (defmacro mel-define-method (name args &rest body)
439   "Define NAME as a method function of (nth 1 (car (last ARGS))) backend.
440 ARGS is like an argument list of lambda, but (car (last ARGS)) must be
441 specialized parameter.  (car (car (last ARGS))) is name of variable
442 and (nth 1 (car (last ARGS))) is name of backend (encoding)."
443   (let* ((specializer (car (last args)))
444          (class (nth 1 specializer)))
445     `(progn
446        (mel-define-service ,name)
447        (fset (intern ,class ,(intern (format "%s-obarray" name)))
448              (lambda ,(butlast args)
449                ,@body)))))
450
451 (put 'mel-define-method 'lisp-indent-function 'defun)
452
453 (defmacro mel-define-method-function (spec function)
454   "Set SPEC's function definition to FUNCTION.
455 First element of SPEC is service.
456 Rest of ARGS is like an argument list of lambda, but (car (last ARGS))
457 must be specialized parameter.  (car (car (last ARGS))) is name of
458 variable and (nth 1 (car (last ARGS))) is name of backend (encoding)."
459   (let* ((name (car spec))
460          (args (cdr spec))
461          (specializer (car (last args)))
462          (class (nth 1 specializer)))
463     `(let (sym)
464        (mel-define-service ,name)
465        (setq sym (intern ,class ,(intern (format "%s-obarray" name))))
466        (or (fboundp sym)
467            (fset sym (symbol-function ,function))))))
468
469 (defmacro mel-define-function (function spec)
470   (let* ((name (car spec))
471          (args (cdr spec))
472          (specializer (car (last args)))
473          (class (nth 1 specializer)))
474     `(progn
475        (define-function ,function
476          (intern ,class ,(intern (format "%s-obarray" name))))
477        )))
478
479 (defvar base64-dl-module
480   (and (fboundp 'dynamic-link)
481        (let ((path (expand-file-name "base64.so" exec-directory)))
482          (and (file-exists-p path)
483               path))))
484
485
486 ;;; @ end
487 ;;;
488
489 (provide 'mime-def)
490
491 ;;; mime-def.el ends here