Merge flim-1_11_0.
[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 11 0) "Yamadagawa"]
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 (defmacro make-mime-entity-internal (representation-type location
218                                      &optional content-type
219                                      children parent node-id
220                                      ;; for NOV
221                                      decoded-subject decoded-from
222                                      date message-id references
223                                      chars lines
224                                      xref
225                                      ;; for other fields
226                                      original-header parsed-header
227                                      ;; for buffer representation
228                                      buffer
229                                      header-start header-end
230                                      body-start body-end)
231   `(vector ,representation-type ,location
232            ,content-type nil nil ,children ,parent ,node-id
233            ;; for NOV
234            ,decoded-subject ,decoded-from
235            ,date ,message-id ,references
236            ,chars ,lines
237            ,xref
238            ;; for other fields
239            ,original-header ,parsed-header
240            ;; for buffer representation
241            ,buffer ,header-start ,header-end ,body-start ,body-end))
242
243 (defmacro mime-entity-representation-type-internal (entity)
244   `(aref ,entity 0))
245 (defmacro mime-entity-set-representation-type-internal (entity type)
246   `(aset ,entity 0 ,type))
247 (defmacro mime-entity-location-internal (entity)
248   `(aref ,entity 1))
249 (defmacro mime-entity-set-location-internal (entity location)
250   `(aset ,entity 1 ,location))
251
252 (defmacro mime-entity-content-type-internal (entity)
253   `(aref ,entity 2))
254 (defmacro mime-entity-set-content-type-internal (entity type)
255   `(aset ,entity 2 ,type))
256 (defmacro mime-entity-content-disposition-internal (entity)
257   `(aref ,entity 3))
258 (defmacro mime-entity-set-content-disposition-internal (entity disposition)
259   `(aset ,entity 3 ,disposition))
260 (defmacro mime-entity-encoding-internal (entity)
261   `(aref ,entity 4))
262 (defmacro mime-entity-set-encoding-internal (entity encoding)
263   `(aset ,entity 4 ,encoding))
264
265 (defmacro mime-entity-children-internal (entity)
266   `(aref ,entity 5))
267 (defmacro mime-entity-set-children-internal (entity children)
268   `(aset ,entity 5 ,children))
269 (defmacro mime-entity-parent-internal (entity)
270   `(aref ,entity 6))
271 (defmacro mime-entity-node-id-internal (entity)
272   `(aref ,entity 7))
273
274 (defmacro mime-entity-decoded-subject-internal (entity)
275   `(aref ,entity 8))
276 (defmacro mime-entity-set-decoded-subject-internal (entity subject)
277   `(aset ,entity 8 ,subject))
278 (defmacro mime-entity-decoded-from-internal (entity)
279   `(aref ,entity 9))
280 (defmacro mime-entity-set-decoded-from-internal (entity from)
281   `(aset ,entity 9 ,from))
282 (defmacro mime-entity-date-internal (entity)
283   `(aref ,entity 10))
284 (defmacro mime-entity-set-date-internal (entity date)
285   `(aset ,entity 10 ,date))
286 (defmacro mime-entity-message-id-internal (entity)
287   `(aref ,entity 11))
288 (defmacro mime-entity-set-message-id-internal (entity message-id)
289   `(aset ,entity 11 ,message-id))
290 (defmacro mime-entity-references-internal (entity)
291   `(aref ,entity 12))
292 (defmacro mime-entity-set-references-internal (entity references)
293   `(aset ,entity 12 ,references))
294 (defmacro mime-entity-chars-internal (entity)
295   `(aref ,entity 13))
296 (defmacro mime-entity-set-chars-internal (entity chars)
297   `(aset ,entity 13 ,chars))
298 (defmacro mime-entity-lines-internal (entity)
299   `(aref ,entity 14))
300 (defmacro mime-entity-set-lines-internal (entity lines)
301   `(aset ,entity 14 ,lines))
302 (defmacro mime-entity-xref-internal (entity)
303   `(aref ,entity 15))
304 (defmacro mime-entity-set-xref-internal (entity xref)
305   `(aset ,entity 15 ,xref))
306
307 (defmacro mime-entity-original-header-internal (entity)
308   `(aref ,entity 16))
309 (defmacro mime-entity-set-original-header-internal (entity header)
310   `(aset ,entity 16 ,header))
311 (defmacro mime-entity-parsed-header-internal (entity)
312   `(aref ,entity 17))
313 (defmacro mime-entity-set-parsed-header-internal (entity header)
314   `(aset ,entity 17 ,header))
315
316 (defmacro mime-entity-buffer-internal (entity)
317   `(aref ,entity 18))
318 (defmacro mime-entity-set-buffer-internal (entity buffer)
319   `(aset ,entity 18 ,buffer))
320 (defmacro mime-entity-header-start-internal (entity)
321   `(aref ,entity 19))
322 (defmacro mime-entity-set-header-start-internal (entity point)
323   `(aset ,entity 19 ,point))
324 (defmacro mime-entity-header-end-internal (entity)
325   `(aref ,entity 20))
326 (defmacro mime-entity-set-header-end-internal (entity point)
327   `(aset ,entity 20 ,point))
328 (defmacro mime-entity-body-start-internal (entity)
329   `(aref ,entity 21))
330 (defmacro mime-entity-set-body-start-internal (entity point)
331   `(aset ,entity 21 ,point))
332 (defmacro mime-entity-body-end-internal (entity)
333   `(aref ,entity 22))
334 (defmacro mime-entity-set-body-end-internal (entity point)
335   `(aset ,entity 22 ,point))
336
337
338 ;;; @ message structure
339 ;;;
340
341 (defvar mime-message-structure nil
342   "Information about structure of message.
343 Please use reference function `mime-entity-SLOT' to get value of SLOT.
344
345 Following is a list of slots of the structure:
346
347 buffer                  buffer includes this entity (buffer).
348 node-id                 node-id (list of integers)
349 header-start            minimum point of header in raw-buffer
350 header-end              maximum point of header in raw-buffer
351 body-start              minimum point of body in raw-buffer
352 body-end                maximum point of body in raw-buffer
353 content-type            content-type (content-type)
354 content-disposition     content-disposition (content-disposition)
355 encoding                Content-Transfer-Encoding (string or nil)
356 children                entities included in this entity (list of entity)
357
358 If an entity includes other entities in its body, such as multipart or
359 message/rfc822, `mime-entity' structures of them are included in
360 `children', so the `mime-entity' structure become a tree.")
361
362 (make-variable-buffer-local 'mime-message-structure)
363
364
365 ;;; @ for mm-backend
366 ;;;
367
368 (require 'alist)
369
370 (defvar mime-entity-implementation-alist nil)
371
372 (defmacro mm-define-backend (type &optional parents)
373   "Define TYPE as a mm-backend.
374 If PARENTS is specified, TYPE inherits PARENTS.
375 Each parent must be backend name (symbol)."
376   (if parents
377       `(let ((rest ',(reverse parents)))
378          (while rest
379            (set-alist 'mime-entity-implementation-alist
380                       ',type
381                       (copy-alist
382                        (cdr (assq (car rest)
383                                   mime-entity-implementation-alist))))
384            (setq rest (cdr rest))
385            ))))
386
387 (defmacro mm-define-method (name args &rest body)
388   "Define NAME as a method function of (nth 1 (car ARGS)) backend.
389
390 ARGS is like an argument list of lambda, but (car ARGS) must be
391 specialized parameter.  (car (car ARGS)) is name of variable and (nth
392 1 (car ARGS)) is name of backend."
393   (let* ((specializer (car args))
394          (class (nth 1 specializer))
395          (self (car specializer)))
396     `(let ((imps (cdr (assq ',class mime-entity-implementation-alist)))
397            (func (lambda ,(if self
398                               (cons self (cdr args))
399                             (cdr args))
400                    ,@body)))
401        (if imps
402            (set-alist 'mime-entity-implementation-alist
403                       ',class (put-alist ',name func imps))
404          (set-alist 'mime-entity-implementation-alist
405                     ',class
406                     (list (cons ',name func)))
407          ))))
408
409 (put 'mm-define-method 'lisp-indent-function 'defun)
410 (put 'mm-define-method 'edebug-form-spec
411      '(&define name ((arg symbolp) &rest arg) def-body))
412
413 (defsubst mm-arglist-to-arguments (arglist)
414   (let (dest)
415     (while arglist
416       (let ((arg (car arglist)))
417         (or (memq arg '(&optional &rest))
418             (setq dest (cons arg dest)))
419         )
420       (setq arglist (cdr arglist)))
421     (nreverse dest)))
422
423
424 ;;; @ for mel-backend
425 ;;;
426
427 (defvar mel-service-list nil)
428
429 (defmacro mel-define-service (name &optional args &rest rest)
430   "Define NAME as a service for Content-Transfer-Encodings.
431 If ARGS is specified, NAME is defined as a generic function for the
432 service."
433   `(progn
434      (add-to-list 'mel-service-list ',name)
435      (defvar ,(intern (format "%s-obarray" name)) (make-vector 1 nil))
436      ,@(if args
437            `((defun ,name ,args
438                ,@rest
439                (funcall (mel-find-function ',name ,(car (last args)))
440                         ,@(mm-arglist-to-arguments (butlast args)))
441                )))
442      ))
443
444 (put 'mel-define-service 'lisp-indent-function 'defun)
445
446
447 (defvar mel-encoding-module-alist nil)
448
449 (defsubst mel-find-function-from-obarray (ob-array encoding)
450   (let* ((f (intern-soft encoding ob-array)))
451     (or f
452         (let ((rest (cdr (assoc encoding mel-encoding-module-alist))))
453           (while (and rest
454                       (progn
455                         (require (car rest))
456                         (null (setq f (intern-soft encoding ob-array)))
457                         ))
458             (setq rest (cdr rest))
459             )
460           f))))
461
462 (defsubst mel-copy-method (service src-backend dst-backend)
463   (let* ((oa (symbol-value (intern (format "%s-obarray" service))))
464          (f (mel-find-function-from-obarray oa src-backend))
465          sym)
466     (when f
467       (setq sym (intern dst-backend oa))
468       (or (fboundp sym)
469           (fset sym (symbol-function f))
470           ))))
471        
472 (defsubst mel-copy-backend (src-backend dst-backend)
473   (let ((services mel-service-list))
474     (while services
475       (mel-copy-method (car services) src-backend dst-backend)
476       (setq services (cdr services)))))
477
478 (defmacro mel-define-backend (type &optional parents)
479   "Define TYPE as a mel-backend.
480 If PARENTS is specified, TYPE inherits PARENTS.
481 Each parent must be backend name (string)."
482   (cons 'progn
483         (mapcar (lambda (parent)
484                   `(mel-copy-backend ,parent ,type)
485                   )
486                 parents)))
487
488 (defmacro mel-define-method (name args &rest body)
489   "Define NAME as a method function of (nth 1 (car (last ARGS))) backend.
490 ARGS is like an argument list of lambda, but (car (last ARGS)) must be
491 specialized parameter.  (car (car (last ARGS))) is name of variable
492 and (nth 1 (car (last ARGS))) is name of backend (encoding)."
493   (let* ((specializer (car (last args)))
494          (class (nth 1 specializer)))
495     `(progn
496        (mel-define-service ,name)
497        (fset (intern ,class ,(intern (format "%s-obarray" name)))
498              (lambda ,(butlast args)
499                ,@body)))))
500
501 (put 'mel-define-method 'lisp-indent-function 'defun)
502
503 (defmacro mel-define-method-function (spec function)
504   "Set SPEC's function definition to FUNCTION.
505 First element of SPEC is service.
506 Rest of ARGS is like an argument list of lambda, but (car (last ARGS))
507 must be specialized parameter.  (car (car (last ARGS))) is name of
508 variable and (nth 1 (car (last ARGS))) is name of backend (encoding)."
509   (let* ((name (car spec))
510          (args (cdr spec))
511          (specializer (car (last args)))
512          (class (nth 1 specializer)))
513     `(let (sym)
514        (mel-define-service ,name)
515        (setq sym (intern ,class ,(intern (format "%s-obarray" name))))
516        (or (fboundp sym)
517            (fset sym (symbol-function ,function))))))
518
519 (defmacro mel-define-function (function spec)
520   (let* ((name (car spec))
521          (args (cdr spec))
522          (specializer (car (last args)))
523          (class (nth 1 specializer)))
524     `(progn
525        (define-function ,function
526          (intern ,class ,(intern (format "%s-obarray" name))))
527        )))
528
529 (defvar base64-dl-module
530   (and (fboundp 'dynamic-link)
531        (let ((path (expand-file-name "base64.so" exec-directory)))
532          (and (file-exists-p path)
533               path))))
534
535
536 ;;; @ end
537 ;;;
538
539 (provide 'mime-def)
540
541 ;;; mime-def.el ends here