(eword-decode-string, eword-decode-region): Mention language info in doc string.
[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,2004,2005,2006
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., 51 Franklin Street, Fifth Floor,
25 ;; Boston, MA 02110-1301, 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 9) "Gojò"]
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
146           "*'%"                         ; introduced in RFC 2231.
147           "\000-\040"
148           "]"))
149 (defconst mime-non-attribute-char-regexp
150   (concat "[" mime-tspecial-char-list
151           "*'%"                         ; introduced in RFC 2231.
152           "\000-\040\177-\377"          ; non-printable, non-US-ASCII.
153           "]"))
154
155 (defconst mime-charset-regexp
156   (concat "[^" mime-tspecial-char-list "\000-\040"
157           "*'%"                         ; should not include "%"?
158           "]+"))
159
160 ;; More precisely, length of each "[A-Za-z]+" is limited to at most 8.
161 ;; See RFC 3066 "Tags for the Identification of Languages".
162 ;; (defconst mime-language-regexp "[A-Za-z]+\\(-[A-Za-z]+\\)*")
163 (defconst mime-language-regexp "[-A-Za-z]+")
164
165 (defconst mime-encoding-regexp mime-token-regexp)
166
167
168 ;;; @@ base64 / B
169 ;;;
170
171 (defconst base64-token-regexp "[A-Za-z0-9+/]")
172 (defconst base64-token-padding-regexp "[A-Za-z0-9+/=]")
173
174 (defconst B-encoded-text-regexp
175   (concat "\\(\\("
176           base64-token-regexp
177           base64-token-regexp
178           base64-token-regexp
179           base64-token-regexp
180           "\\)*"
181           base64-token-regexp
182           base64-token-regexp
183           base64-token-padding-regexp
184           base64-token-padding-regexp
185           "\\)"))
186
187 ;; (defconst eword-B-encoding-and-encoded-text-regexp
188 ;;   (concat "\\(B\\)\\?" eword-B-encoded-text-regexp))
189
190
191 ;;; @@ Quoted-Printable / Q
192 ;;;
193
194 (defconst quoted-printable-hex-chars "0123456789ABCDEF")
195
196 (defconst quoted-printable-octet-regexp
197   (concat "=[" quoted-printable-hex-chars
198           "][" quoted-printable-hex-chars "]"))
199
200 (defconst Q-encoded-text-regexp
201   (concat "\\([^=?]\\|" quoted-printable-octet-regexp "\\)+"))
202
203 ;; (defconst eword-Q-encoding-and-encoded-text-regexp
204 ;;   (concat "\\(Q\\)\\?" eword-Q-encoded-text-regexp))
205
206
207 ;;; @ Content-Type
208 ;;;
209
210 (defsubst make-mime-content-type (type subtype &optional parameters)
211   (cons (cons 'type type)
212         (cons (cons 'subtype subtype)
213               parameters)))
214
215 (defsubst mime-content-type-primary-type (content-type)
216   "Return primary-type of CONTENT-TYPE."
217   (cdr (car content-type)))
218
219 (defsubst mime-content-type-subtype (content-type)
220   "Return subtype of CONTENT-TYPE."
221   (cdr (car (cdr content-type))))
222
223 (defsubst mime-content-type-parameters (content-type)
224   "Return parameters of CONTENT-TYPE."
225   (cdr (cdr content-type)))
226
227 (defsubst mime-content-type-parameter (content-type parameter)
228   "Return PARAMETER value of CONTENT-TYPE."
229   (cdr (assoc parameter (cdr (cdr content-type)))))
230
231
232 (defsubst mime-type/subtype-string (type &optional subtype)
233   "Return type/subtype string from TYPE and SUBTYPE."
234   (if type
235       (if subtype
236           (format "%s/%s" type subtype)
237         (format "%s" type))))
238
239
240 ;;; @ Content-Disposition
241 ;;;
242
243 (defsubst make-mime-content-disposition (type &optional parameters)
244   (cons (cons 'type type)
245         parameters))
246
247 (defsubst mime-content-disposition-type (content-disposition)
248   "Return disposition-type of CONTENT-DISPOSITION."
249   (cdr (car content-disposition)))
250
251 (defsubst mime-content-disposition-parameters (content-disposition)
252   "Return disposition-parameters of CONTENT-DISPOSITION."
253   (cdr content-disposition))
254
255 (defsubst mime-content-disposition-parameter (content-disposition parameter)
256   "Return PARAMETER value of CONTENT-DISPOSITION."
257   (cdr (assoc parameter (cdr content-disposition))))
258
259 (defsubst mime-content-disposition-filename (content-disposition)
260   "Return filename of CONTENT-DISPOSITION."
261   (mime-content-disposition-parameter content-disposition "filename"))
262
263
264 ;;; @ message structure
265 ;;;
266
267 (defvar mime-message-structure nil
268   "Information about structure of message.
269 Please use reference function `mime-entity-SLOT' to get value of SLOT.
270
271 Following is a list of slots of the structure:
272
273 node-id                 node-id (list of integers)
274 content-type            content-type (content-type)
275 content-disposition     content-disposition (content-disposition)
276 encoding                Content-Transfer-Encoding (string or nil)
277 children                entities included in this entity (list of entity)
278
279 If an entity includes other entities in its body, such as multipart or
280 message/rfc822, `mime-entity' structures of them are included in
281 `children', so the `mime-entity' structure become a tree.")
282
283 (make-variable-buffer-local 'mime-message-structure)
284
285 (make-obsolete-variable 'mime-message-structure "should not use it.")
286
287
288 ;;; @ for mel-backend
289 ;;;
290
291 (defvar mel-service-list nil)
292
293 (defmacro mel-define-service (name &optional args &rest rest)
294   "Define NAME as a service for Content-Transfer-Encodings.
295 If ARGS is specified, NAME is defined as a generic function for the
296 service."
297   `(progn
298      (add-to-list 'mel-service-list ',name)
299      (defvar ,(intern (format "%s-obarray" name)) (make-vector 7 0))
300      ,@(if args
301            `((defun ,name ,args
302                ,@rest
303                (funcall (mel-find-function ',name ,(car (last args)))
304                         ,@(luna-arglist-to-arguments (butlast args)))
305                )))
306      ))
307
308 (put 'mel-define-service 'lisp-indent-function 'defun)
309
310
311 (defvar mel-encoding-module-alist nil)
312
313 (defsubst mel-find-function-from-obarray (ob-array encoding)
314   (let* ((f (intern-soft encoding ob-array)))
315     (or f
316         (let ((rest (cdr (assoc encoding mel-encoding-module-alist))))
317           (while (and rest
318                       (progn
319                         (require (car rest))
320                         (null (setq f (intern-soft encoding ob-array)))
321                         ))
322             (setq rest (cdr rest))
323             )
324           f))))
325
326 (defsubst mel-copy-method (service src-backend dst-backend)
327   (let* ((oa (symbol-value (intern (format "%s-obarray" service))))
328          (f (mel-find-function-from-obarray oa src-backend))
329          sym)
330     (when f
331       (setq sym (intern dst-backend oa))
332       (or (fboundp sym)
333           (fset sym (symbol-function f))
334           ))))
335        
336 (defsubst mel-copy-backend (src-backend dst-backend)
337   (let ((services mel-service-list))
338     (while services
339       (mel-copy-method (car services) src-backend dst-backend)
340       (setq services (cdr services)))))
341
342 (defmacro mel-define-backend (type &optional parents)
343   "Define TYPE as a mel-backend.
344 If PARENTS is specified, TYPE inherits PARENTS.
345 Each parent must be backend name (string)."
346   (cons 'progn
347         (mapcar (lambda (parent)
348                   `(mel-copy-backend ,parent ,type)
349                   )
350                 parents)))
351
352 (defmacro mel-define-method (name args &rest body)
353   "Define NAME as a method function of (nth 1 (car (last ARGS))) backend.
354 ARGS is like an argument list of lambda, but (car (last ARGS)) must be
355 specialized parameter.  (car (car (last ARGS))) is name of variable
356 and (nth 1 (car (last ARGS))) is name of backend (encoding)."
357   (let* ((specializer (car (last args)))
358          (class (nth 1 specializer)))
359     `(progn
360        (mel-define-service ,name)
361        (fset (intern ,class ,(intern (format "%s-obarray" name)))
362              (lambda ,(butlast args)
363                ,@body)))))
364
365 (put 'mel-define-method 'lisp-indent-function 'defun)
366
367 (defmacro mel-define-method-function (spec function)
368   "Set SPEC's function definition to FUNCTION.
369 First element of SPEC is service.
370 Rest of ARGS is like an argument list of lambda, but (car (last ARGS))
371 must be specialized parameter.  (car (car (last ARGS))) is name of
372 variable and (nth 1 (car (last ARGS))) is name of backend (encoding)."
373   (let* ((name (car spec))
374          (args (cdr spec))
375          (specializer (car (last args)))
376          (class (nth 1 specializer)))
377     `(let (sym)
378        (mel-define-service ,name)
379        (setq sym (intern ,class ,(intern (format "%s-obarray" name))))
380        (or (fboundp sym)
381            (fset sym (symbol-function ,function))))))
382
383 (defmacro mel-define-function (function spec)
384   (let* ((name (car spec))
385          (args (cdr spec))
386          (specializer (car (last args)))
387          (class (nth 1 specializer)))
388     `(progn
389        (define-function ,function
390          (intern ,class ,(intern (format "%s-obarray" name))))
391        )))
392
393 (defvar base64-dl-module
394   (if (and (fboundp 'base64-encode-string)
395            (subrp (symbol-function 'base64-encode-string)))
396       nil
397     (if (fboundp 'dynamic-link)
398         (let ((path (expand-file-name "base64.so" exec-directory)))
399           (and (file-exists-p path)
400                path)
401           ))))
402
403
404 ;;; @ end
405 ;;;
406
407 (provide 'mime-def)
408
409 ;;; mime-def.el ends here