Merge flim-1_11_3.
[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 (require 'mcharset)
28
29 (eval-and-compile
30   (defconst mime-library-product ["FLIM" (1 11 3) "Saidaiji"]
31     "Product name, version number and code name of MIME-library package.")
32   )
33
34 (defmacro mime-product-name (product)
35   `(aref ,product 0))
36
37 (defmacro mime-product-version (product)
38   `(aref ,product 1))
39
40 (defmacro mime-product-code-name (product)
41   `(aref ,product 2))
42
43 (defconst mime-library-version
44   (eval-when-compile
45     (concat (mime-product-name mime-library-product) " "
46             (mapconcat #'number-to-string
47                        (mime-product-version mime-library-product) ".")
48             " - \"" (mime-product-code-name mime-library-product) "\"")))
49
50
51 ;;; @ variables
52 ;;;
53
54 (require 'custom)
55
56 (eval-when-compile (require 'cl))
57
58 (defgroup mime nil
59   "Emacs MIME Interfaces"
60   :group 'news
61   :group 'mail)
62
63 (custom-handle-keyword 'default-mime-charset :group 'mime
64                        'custom-variable)
65
66 (defcustom mime-uuencode-encoding-name-list '("x-uue" "x-uuencode")
67   "*List of encoding names for uuencode format."
68   :group 'mime
69   :type '(repeat string))
70
71
72 ;;; @ required functions
73 ;;;
74
75 (defsubst eliminate-top-spaces (string)
76   "Eliminate top sequence of space or tab in STRING."
77   (if (string-match "^[ \t]+" string)
78       (substring string (match-end 0))
79     string))
80
81 (defsubst regexp-* (regexp)
82   (concat regexp "*"))
83
84 (defsubst regexp-or (&rest args)
85   (concat "\\(" (mapconcat (function identity) args "\\|") "\\)"))
86
87
88 ;;; @ about STD 11
89 ;;;
90
91 (eval-and-compile
92   (defconst std11-quoted-pair-regexp "\\\\.")
93   (defconst std11-non-qtext-char-list '(?\" ?\\ ?\r ?\n))
94   (defconst std11-qtext-regexp
95     (eval-when-compile
96       (concat "[^" (apply #'string std11-non-qtext-char-list) "]"))))
97 (defconst std11-quoted-string-regexp
98   (eval-when-compile
99     (concat "\""
100             (regexp-*
101              (regexp-or std11-qtext-regexp std11-quoted-pair-regexp))
102             "\"")))
103
104
105 ;;; @ about MIME
106 ;;;
107
108 (defconst mime-tspecials "][()<>@,\;:\\\"/?=")
109 (defconst mime-token-regexp (concat "[^" mime-tspecials "\000-\040]+"))
110 (defconst mime-charset-regexp mime-token-regexp)
111
112 (defconst mime-media-type/subtype-regexp
113   (concat mime-token-regexp "/" mime-token-regexp))
114
115
116 ;;; @@ base64 / B
117 ;;;
118
119 (defconst base64-token-regexp "[A-Za-z0-9+/]")
120 (defconst base64-token-padding-regexp "[A-Za-z0-9+/=]")
121
122 (defconst B-encoded-text-regexp
123   (concat "\\(\\("
124           base64-token-regexp
125           base64-token-regexp
126           base64-token-regexp
127           base64-token-regexp
128           "\\)*"
129           base64-token-regexp
130           base64-token-regexp
131           base64-token-padding-regexp
132           base64-token-padding-regexp
133           "\\)"))
134
135 ;; (defconst eword-B-encoding-and-encoded-text-regexp
136 ;;   (concat "\\(B\\)\\?" eword-B-encoded-text-regexp))
137
138
139 ;;; @@ Quoted-Printable / Q
140 ;;;
141
142 (defconst quoted-printable-hex-chars "0123456789ABCDEF")
143
144 (defconst quoted-printable-octet-regexp
145   (concat "=[" quoted-printable-hex-chars
146           "][" quoted-printable-hex-chars "]"))
147
148 (defconst Q-encoded-text-regexp
149   (concat "\\([^=?]\\|" quoted-printable-octet-regexp "\\)+"))
150
151 ;; (defconst eword-Q-encoding-and-encoded-text-regexp
152 ;;   (concat "\\(Q\\)\\?" eword-Q-encoded-text-regexp))
153
154
155 ;;; @ Content-Type
156 ;;;
157
158 (defsubst make-mime-content-type (type subtype &optional parameters)
159   (list* (cons 'type type)
160          (cons 'subtype subtype)
161          (nreverse parameters))
162   )
163
164 (defsubst mime-content-type-primary-type (content-type)
165   "Return primary-type of CONTENT-TYPE."
166   (cdr (car content-type)))
167
168 (defsubst mime-content-type-subtype (content-type)
169   "Return primary-type of CONTENT-TYPE."
170   (cdr (cadr content-type)))
171
172 (defsubst mime-content-type-parameters (content-type)
173   "Return primary-type of CONTENT-TYPE."
174   (cddr content-type))
175
176 (defsubst mime-content-type-parameter (content-type parameter)
177   "Return PARAMETER value of CONTENT-TYPE."
178   (cdr (assoc parameter (mime-content-type-parameters content-type))))
179
180
181 (defsubst mime-type/subtype-string (type &optional subtype)
182   "Return type/subtype string from TYPE and SUBTYPE."
183   (if type
184       (if subtype
185           (format "%s/%s" type subtype)
186         (format "%s" type))))
187
188
189 ;;; @ Content-Disposition
190 ;;;
191
192 (defsubst mime-content-disposition-type (content-disposition)
193   "Return disposition-type of CONTENT-DISPOSITION."
194   (cdr (car content-disposition)))
195
196 (defsubst mime-content-disposition-parameters (content-disposition)
197   "Return disposition-parameters of CONTENT-DISPOSITION."
198   (cdr content-disposition))
199
200 (defsubst mime-content-disposition-parameter (content-disposition parameter)
201   "Return PARAMETER value of CONTENT-DISPOSITION."
202   (cdr (assoc parameter (cdr content-disposition))))
203
204 (defsubst mime-content-disposition-filename (content-disposition)
205   "Return filename of CONTENT-DISPOSITION."
206   (mime-content-disposition-parameter content-disposition "filename"))
207
208
209 ;;; @ MIME entity
210 ;;;
211
212 (defmacro make-mime-entity-internal (representation-type location
213                                      &optional content-type
214                                      children parent node-id
215                                      ;; for NOV
216                                      decoded-subject decoded-from
217                                      date message-id references
218                                      chars lines
219                                      xref
220                                      ;; for other fields
221                                      original-header parsed-header
222                                      ;; for buffer representation
223                                      buffer
224                                      header-start header-end
225                                      body-start body-end)
226   `(vector ,representation-type ,location
227            ,content-type nil nil ,children ,parent ,node-id
228            ;; for NOV
229            ,decoded-subject ,decoded-from
230            ,date ,message-id ,references
231            ,chars ,lines
232            ,xref
233            ;; for other fields
234            ,original-header ,parsed-header
235            ;; for buffer representation
236            ,buffer ,header-start ,header-end ,body-start ,body-end))
237
238 (defmacro mime-entity-representation-type-internal (entity)
239   `(aref ,entity 0))
240 (defmacro mime-entity-set-representation-type-internal (entity type)
241   `(aset ,entity 0 ,type))
242 (defmacro mime-entity-location-internal (entity)
243   `(aref ,entity 1))
244 (defmacro mime-entity-set-location-internal (entity location)
245   `(aset ,entity 1 ,location))
246
247 (defmacro mime-entity-content-type-internal (entity)
248   `(aref ,entity 2))
249 (defmacro mime-entity-set-content-type-internal (entity type)
250   `(aset ,entity 2 ,type))
251 (defmacro mime-entity-content-disposition-internal (entity)
252   `(aref ,entity 3))
253 (defmacro mime-entity-set-content-disposition-internal (entity disposition)
254   `(aset ,entity 3 ,disposition))
255 (defmacro mime-entity-encoding-internal (entity)
256   `(aref ,entity 4))
257 (defmacro mime-entity-set-encoding-internal (entity encoding)
258   `(aset ,entity 4 ,encoding))
259
260 (defmacro mime-entity-children-internal (entity)
261   `(aref ,entity 5))
262 (defmacro mime-entity-set-children-internal (entity children)
263   `(aset ,entity 5 ,children))
264 (defmacro mime-entity-parent-internal (entity)
265   `(aref ,entity 6))
266 (defmacro mime-entity-node-id-internal (entity)
267   `(aref ,entity 7))
268
269 (defmacro mime-entity-decoded-subject-internal (entity)
270   `(aref ,entity 8))
271 (defmacro mime-entity-set-decoded-subject-internal (entity subject)
272   `(aset ,entity 8 ,subject))
273 (defmacro mime-entity-decoded-from-internal (entity)
274   `(aref ,entity 9))
275 (defmacro mime-entity-set-decoded-from-internal (entity from)
276   `(aset ,entity 9 ,from))
277 (defmacro mime-entity-date-internal (entity)
278   `(aref ,entity 10))
279 (defmacro mime-entity-set-date-internal (entity date)
280   `(aset ,entity 10 ,date))
281 (defmacro mime-entity-message-id-internal (entity)
282   `(aref ,entity 11))
283 (defmacro mime-entity-set-message-id-internal (entity message-id)
284   `(aset ,entity 11 ,message-id))
285 (defmacro mime-entity-references-internal (entity)
286   `(aref ,entity 12))
287 (defmacro mime-entity-set-references-internal (entity references)
288   `(aset ,entity 12 ,references))
289 (defmacro mime-entity-chars-internal (entity)
290   `(aref ,entity 13))
291 (defmacro mime-entity-set-chars-internal (entity chars)
292   `(aset ,entity 13 ,chars))
293 (defmacro mime-entity-lines-internal (entity)
294   `(aref ,entity 14))
295 (defmacro mime-entity-set-lines-internal (entity lines)
296   `(aset ,entity 14 ,lines))
297 (defmacro mime-entity-xref-internal (entity)
298   `(aref ,entity 15))
299 (defmacro mime-entity-set-xref-internal (entity xref)
300   `(aset ,entity 15 ,xref))
301
302 (defmacro mime-entity-original-header-internal (entity)
303   `(aref ,entity 16))
304 (defmacro mime-entity-set-original-header-internal (entity header)
305   `(aset ,entity 16 ,header))
306 (defmacro mime-entity-parsed-header-internal (entity)
307   `(aref ,entity 17))
308 (defmacro mime-entity-set-parsed-header-internal (entity header)
309   `(aset ,entity 17 ,header))
310
311 (defmacro mime-entity-buffer-internal (entity)
312   `(aref ,entity 18))
313 (defmacro mime-entity-set-buffer-internal (entity buffer)
314   `(aset ,entity 18 ,buffer))
315 (defmacro mime-entity-header-start-internal (entity)
316   `(aref ,entity 19))
317 (defmacro mime-entity-set-header-start-internal (entity point)
318   `(aset ,entity 19 ,point))
319 (defmacro mime-entity-header-end-internal (entity)
320   `(aref ,entity 20))
321 (defmacro mime-entity-set-header-end-internal (entity point)
322   `(aset ,entity 20 ,point))
323 (defmacro mime-entity-body-start-internal (entity)
324   `(aref ,entity 21))
325 (defmacro mime-entity-set-body-start-internal (entity point)
326   `(aset ,entity 21 ,point))
327 (defmacro mime-entity-body-end-internal (entity)
328   `(aref ,entity 22))
329 (defmacro mime-entity-set-body-end-internal (entity point)
330   `(aset ,entity 22 ,point))
331
332
333 ;;; @ message structure
334 ;;;
335
336 (defvar mime-message-structure nil
337   "Information about structure of message.
338 Please use reference function `mime-entity-SLOT' to get value of SLOT.
339
340 Following is a list of slots of the structure:
341
342 buffer                  buffer includes this entity (buffer).
343 node-id                 node-id (list of integers)
344 header-start            minimum point of header in raw-buffer
345 header-end              maximum point of header in raw-buffer
346 body-start              minimum point of body in raw-buffer
347 body-end                maximum point of body in raw-buffer
348 content-type            content-type (content-type)
349 content-disposition     content-disposition (content-disposition)
350 encoding                Content-Transfer-Encoding (string or nil)
351 children                entities included in this entity (list of entity)
352
353 If an entity includes other entities in its body, such as multipart or
354 message/rfc822, `mime-entity' structures of them are included in
355 `children', so the `mime-entity' structure become a tree.")
356
357 (make-variable-buffer-local 'mime-message-structure)
358
359
360 ;;; @ for mm-backend
361 ;;;
362
363 (require 'alist)
364
365 (defvar mime-entity-implementation-alist nil)
366
367 (defmacro mm-define-backend (type &optional parents)
368   "Define TYPE as a mm-backend.
369 If PARENTS is specified, TYPE inherits PARENTS.
370 Each parent must be backend name (symbol)."
371   (if parents
372       `(let ((rest ',(reverse parents)))
373          (while rest
374            (set-alist 'mime-entity-implementation-alist
375                       ',type
376                       (copy-alist
377                        (cdr (assq (car rest)
378                                   mime-entity-implementation-alist))))
379            (setq rest (cdr rest))
380            ))))
381
382 (defmacro mm-define-method (name args &rest body)
383   "Define NAME as a method function of (nth 1 (car ARGS)) backend.
384
385 ARGS is like an argument list of lambda, but (car ARGS) must be
386 specialized parameter.  (car (car ARGS)) is name of variable and (nth
387 1 (car ARGS)) is name of backend."
388   (let* ((specializer (car args))
389          (class (nth 1 specializer))
390          (self (car specializer)))
391     `(let ((imps (cdr (assq ',class mime-entity-implementation-alist)))
392            (func (lambda ,(if self
393                               (cons self (cdr args))
394                             (cdr args))
395                    ,@body)))
396        (if imps
397            (set-alist 'mime-entity-implementation-alist
398                       ',class (put-alist ',name func imps))
399          (set-alist 'mime-entity-implementation-alist
400                     ',class
401                     (list (cons ',name func)))
402          ))))
403
404 (put 'mm-define-method 'lisp-indent-function 'defun)
405 (def-edebug-spec mm-define-method
406   (&define name ((arg symbolp)
407                  [&rest arg]
408                  [&optional ["&optional" arg &rest arg]]
409                  &optional ["&rest" arg]
410                  )
411            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   (if (and (fboundp 'base64-encode-string)
531            (subrp (symbol-function 'base64-encode-string)))
532       nil
533     (if (fboundp 'dynamic-link)
534         (let ((path (expand-file-name "base64.so" exec-directory)))
535           (and (file-exists-p path)
536                path)
537           ))))
538
539
540 ;;; @ end
541 ;;;
542
543 (provide 'mime-def)
544
545 ;;; mime-def.el ends here