* sasl.texi: Texinfo markup fixes. From Jesper Harder
[elisp/flim.git] / mime-def.el
1 ;;; mime-def.el --- definition module about MIME -*- coding: iso-8859-4; -*-
2
3 ;; Copyright (C) 1995,96,97,98,99,2000,2001,2002,2003
4 ;;   Free Software Foundation, Inc.
5
6 ;; Author: MORIOKA Tomohiko <tomo@m17n.org>
7 ;;      Shuhei KOBAYASHI <shuhei@aqua.ocn.ne.jp>
8 ;; Keywords: definition, MIME, multimedia, mail, news
9
10 ;; This file is part of FLIM (Faithful Library about Internet Message).
11
12 ;; This program is free software; you can redistribute it and/or
13 ;; modify it under the terms of the GNU General Public License as
14 ;; published by the Free Software Foundation; either version 2, or (at
15 ;; your option) any later version.
16
17 ;; This program is distributed in the hope that it will be useful, but
18 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20 ;; General Public License for more details.
21
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
24 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25 ;; Boston, MA 02111-1307, USA.
26
27 ;;; Code:
28
29 (require 'custom)
30 (require 'mcharset)
31 (require 'alist)
32
33 (eval-when-compile (require 'luna))     ; luna-arglist-to-arguments
34
35 (eval-and-compile
36   (defconst mime-library-product ["FLIM" (1 14 6) "Marutamachi"]
37     "Product name, version number and code name of MIME-library package."))
38
39 (defmacro mime-product-name (product)
40   `(aref ,product 0))
41
42 (defmacro mime-product-version (product)
43   `(aref ,product 1))
44
45 (defmacro mime-product-code-name (product)
46   `(aref ,product 2))
47
48 (defconst mime-library-version
49   (eval-when-compile
50     (concat (mime-product-name mime-library-product) " "
51             (mapconcat #'number-to-string
52                        (mime-product-version mime-library-product) ".")
53             " - \"" (mime-product-code-name mime-library-product) "\"")))
54
55
56 ;;; @ variables
57 ;;;
58
59 (defgroup mime '((default-mime-charset custom-variable))
60   "Emacs MIME Interfaces"
61   :group 'news
62   :group 'mail)
63
64 (defcustom mime-uuencode-encoding-name-list '("x-uue" "x-uuencode")
65   "*List of encoding names for uuencode format."
66   :group 'mime
67   :type '(repeat string))
68
69
70 ;;; @@ for encoded-word
71 ;;;
72
73 (defgroup mime-header nil
74   "Header representation, specially encoded-word"
75   :group 'mime)
76
77 ;;; @@@ decoding
78 ;;;
79
80 (defcustom mime-field-decoding-max-size 1000
81   "*Max size to decode header field."
82   :group 'mime-header
83   :type '(choice (integer :tag "Limit (bytes)")
84                  (const :tag "Don't limit" nil)))
85
86 (defcustom mime-header-accept-quoted-encoded-words nil
87   "*Accept encoded-words in quoted-strings."
88   :group 'mime-header
89   :type 'boolean)
90
91
92 ;;; @@@ encoding
93 ;;;
94
95 (defcustom mime-field-encoding-method-alist
96   '(("X-Nsubject" . iso-2022-jp-2)
97     ("Newsgroups" . nil)
98     ("Message-ID" . nil)
99     (t            . mime)
100     )
101   "*Alist to specify field encoding method.
102 Its key is field-name, value is encoding method.
103
104 If method is `mime', this field will be encoded into MIME format.
105
106 If method is a MIME-charset, this field will be encoded as the charset
107 when it must be convert into network-code.
108
109 If method is `default-mime-charset', this field will be encoded as
110 variable `default-mime-charset' when it must be convert into
111 network-code.
112
113 If method is nil, this field will not be encoded."
114   :group 'mime-header
115   :type '(repeat (cons (choice :tag "Field"
116                                (string :tag "Name")
117                                (const :tag "Default" t))
118                        (choice :tag "Method"
119                                (const :tag "MIME conversion" mime)
120                                (symbol :tag "non-MIME conversion")
121                                (const :tag "no-conversion" nil)))))
122
123
124 ;;; @ required functions
125 ;;;
126
127 (defsubst regexp-* (regexp)
128   (concat regexp "*"))
129
130 (defsubst regexp-or (&rest args)
131   (concat "\\(" (mapconcat (function identity) args "\\|") "\\)"))
132
133 (or (fboundp 'char-int)
134     (defalias 'char-int 'identity))
135
136
137 ;;; @ MIME constants
138 ;;;
139
140 (defconst mime-tspecial-char-list
141   '(?\] ?\[ ?\( ?\) ?< ?> ?@ ?, ?\; ?: ?\\ ?\" ?/ ?? ?=))
142 (defconst mime-token-regexp
143   (concat "[^" mime-tspecial-char-list "\000-\040]+"))
144 (defconst mime-attribute-char-regexp
145   (concat "[^" mime-tspecial-char-list "\000-\040"
146           "*'%"                         ; introduced in RFC 2231.
147           "]"))
148
149 (defconst mime-charset-regexp
150   (concat "[^" mime-tspecial-char-list "\000-\040"
151           "*'%"                         ; should not include "%"?
152           "]+"))
153
154 ;; More precisely, length of "[A-Za-z]+" is limited to at most 8.
155 ;; (defconst mime-language-regexp "[A-Za-z]+\\(-[A-Za-z]+\\)*")
156 (defconst mime-language-regexp "[-A-Za-z]+")
157
158 (defconst mime-encoding-regexp mime-token-regexp)
159
160
161 ;;; @@ base64 / B
162 ;;;
163
164 (defconst base64-token-regexp "[A-Za-z0-9+/]")
165 (defconst base64-token-padding-regexp "[A-Za-z0-9+/=]")
166
167 (defconst B-encoded-text-regexp
168   (concat "\\(\\("
169           base64-token-regexp
170           base64-token-regexp
171           base64-token-regexp
172           base64-token-regexp
173           "\\)*"
174           base64-token-regexp
175           base64-token-regexp
176           base64-token-padding-regexp
177           base64-token-padding-regexp
178           "\\)"))
179
180 ;; (defconst eword-B-encoding-and-encoded-text-regexp
181 ;;   (concat "\\(B\\)\\?" eword-B-encoded-text-regexp))
182
183
184 ;;; @@ Quoted-Printable / Q
185 ;;;
186
187 (defconst quoted-printable-hex-chars "0123456789ABCDEF")
188
189 (defconst quoted-printable-octet-regexp
190   (concat "=[" quoted-printable-hex-chars
191           "][" quoted-printable-hex-chars "]"))
192
193 (defconst Q-encoded-text-regexp
194   (concat "\\([^=?]\\|" quoted-printable-octet-regexp "\\)+"))
195
196 ;; (defconst eword-Q-encoding-and-encoded-text-regexp
197 ;;   (concat "\\(Q\\)\\?" eword-Q-encoded-text-regexp))
198
199
200 ;;; @ Content-Type
201 ;;;
202
203 (defsubst make-mime-content-type (type subtype &optional parameters)
204   (cons (cons 'type type)
205         (cons (cons 'subtype subtype)
206               parameters)))
207
208 (defsubst mime-content-type-primary-type (content-type)
209   "Return primary-type of CONTENT-TYPE."
210   (cdr (car content-type)))
211
212 (defsubst mime-content-type-subtype (content-type)
213   "Return subtype of CONTENT-TYPE."
214   (cdr (car (cdr content-type))))
215
216 (defsubst mime-content-type-parameters (content-type)
217   "Return parameters of CONTENT-TYPE."
218   (cdr (cdr content-type)))
219
220 (defsubst mime-content-type-parameter (content-type parameter)
221   "Return PARAMETER value of CONTENT-TYPE."
222   (cdr (assoc parameter (cdr (cdr content-type)))))
223
224
225 (defsubst mime-type/subtype-string (type &optional subtype)
226   "Return type/subtype string from TYPE and SUBTYPE."
227   (if type
228       (if subtype
229           (format "%s/%s" type subtype)
230         (format "%s" type))))
231
232
233 ;;; @ Content-Disposition
234 ;;;
235
236 (defsubst make-mime-content-disposition (type &optional parameters)
237   (cons (cons 'type type)
238         parameters))
239
240 (defsubst mime-content-disposition-type (content-disposition)
241   "Return disposition-type of CONTENT-DISPOSITION."
242   (cdr (car content-disposition)))
243
244 (defsubst mime-content-disposition-parameters (content-disposition)
245   "Return disposition-parameters of CONTENT-DISPOSITION."
246   (cdr content-disposition))
247
248 (defsubst mime-content-disposition-parameter (content-disposition parameter)
249   "Return PARAMETER value of CONTENT-DISPOSITION."
250   (cdr (assoc parameter (cdr content-disposition))))
251
252 (defsubst mime-content-disposition-filename (content-disposition)
253   "Return filename of CONTENT-DISPOSITION."
254   (mime-content-disposition-parameter content-disposition "filename"))
255
256
257 ;;; @ message structure
258 ;;;
259
260 (defvar mime-message-structure nil
261   "Information about structure of message.
262 Please use reference function `mime-entity-SLOT' to get value of SLOT.
263
264 Following is a list of slots of the structure:
265
266 node-id                 node-id (list of integers)
267 content-type            content-type (content-type)
268 content-disposition     content-disposition (content-disposition)
269 encoding                Content-Transfer-Encoding (string or nil)
270 children                entities included in this entity (list of entity)
271
272 If an entity includes other entities in its body, such as multipart or
273 message/rfc822, `mime-entity' structures of them are included in
274 `children', so the `mime-entity' structure become a tree.")
275
276 (make-variable-buffer-local 'mime-message-structure)
277
278 (make-obsolete-variable 'mime-message-structure "should not use it.")
279
280
281 ;;; @ for mel-backend
282 ;;;
283
284 (defvar mel-service-list nil)
285
286 (defmacro mel-define-service (name &optional args &rest rest)
287   "Define NAME as a service for Content-Transfer-Encodings.
288 If ARGS is specified, NAME is defined as a generic function for the
289 service."
290   `(progn
291      (add-to-list 'mel-service-list ',name)
292      (defvar ,(intern (format "%s-obarray" name)) (make-vector 7 0))
293      ,@(if args
294            `((defun ,name ,args
295                ,@rest
296                (funcall (mel-find-function ',name ,(car (last args)))
297                         ,@(luna-arglist-to-arguments (butlast args)))
298                )))
299      ))
300
301 (put 'mel-define-service 'lisp-indent-function 'defun)
302
303
304 (defvar mel-encoding-module-alist nil)
305
306 (defsubst mel-find-function-from-obarray (ob-array encoding)
307   (let* ((f (intern-soft encoding ob-array)))
308     (or f
309         (let ((rest (cdr (assoc encoding mel-encoding-module-alist))))
310           (while (and rest
311                       (progn
312                         (require (car rest))
313                         (null (setq f (intern-soft encoding ob-array)))
314                         ))
315             (setq rest (cdr rest))
316             )
317           f))))
318
319 (defsubst mel-copy-method (service src-backend dst-backend)
320   (let* ((oa (symbol-value (intern (format "%s-obarray" service))))
321          (f (mel-find-function-from-obarray oa src-backend))
322          sym)
323     (when f
324       (setq sym (intern dst-backend oa))
325       (or (fboundp sym)
326           (fset sym (symbol-function f))
327           ))))
328        
329 (defsubst mel-copy-backend (src-backend dst-backend)
330   (let ((services mel-service-list))
331     (while services
332       (mel-copy-method (car services) src-backend dst-backend)
333       (setq services (cdr services)))))
334
335 (defmacro mel-define-backend (type &optional parents)
336   "Define TYPE as a mel-backend.
337 If PARENTS is specified, TYPE inherits PARENTS.
338 Each parent must be backend name (string)."
339   (cons 'progn
340         (mapcar (lambda (parent)
341                   `(mel-copy-backend ,parent ,type)
342                   )
343                 parents)))
344
345 (defmacro mel-define-method (name args &rest body)
346   "Define NAME as a method function of (nth 1 (car (last ARGS))) backend.
347 ARGS is like an argument list of lambda, but (car (last ARGS)) must be
348 specialized parameter.  (car (car (last ARGS))) is name of variable
349 and (nth 1 (car (last ARGS))) is name of backend (encoding)."
350   (let* ((specializer (car (last args)))
351          (class (nth 1 specializer)))
352     `(progn
353        (mel-define-service ,name)
354        (fset (intern ,class ,(intern (format "%s-obarray" name)))
355              (lambda ,(butlast args)
356                ,@body)))))
357
358 (put 'mel-define-method 'lisp-indent-function 'defun)
359
360 (defmacro mel-define-method-function (spec function)
361   "Set SPEC's function definition to FUNCTION.
362 First element of SPEC is service.
363 Rest of ARGS is like an argument list of lambda, but (car (last ARGS))
364 must be specialized parameter.  (car (car (last ARGS))) is name of
365 variable and (nth 1 (car (last ARGS))) is name of backend (encoding)."
366   (let* ((name (car spec))
367          (args (cdr spec))
368          (specializer (car (last args)))
369          (class (nth 1 specializer)))
370     `(let (sym)
371        (mel-define-service ,name)
372        (setq sym (intern ,class ,(intern (format "%s-obarray" name))))
373        (or (fboundp sym)
374            (fset sym (symbol-function ,function))))))
375
376 (defmacro mel-define-function (function spec)
377   (let* ((name (car spec))
378          (args (cdr spec))
379          (specializer (car (last args)))
380          (class (nth 1 specializer)))
381     `(progn
382        (define-function ,function
383          (intern ,class ,(intern (format "%s-obarray" name))))
384        )))
385
386 (defvar base64-dl-module
387   (if (and (fboundp 'base64-encode-string)
388            (subrp (symbol-function 'base64-encode-string)))
389       nil
390     (if (fboundp 'dynamic-link)
391         (let ((path (expand-file-name "base64.so" exec-directory)))
392           (and (file-exists-p path)
393                path)
394           ))))
395
396
397 ;;; @ end
398 ;;;
399
400 (provide 'mime-def)
401
402 ;;; mime-def.el ends here