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