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