(mime-message-structure): Define as obsolete variable.
[elisp/flim.git] / mel.el
1 ;;; mel.el : a MIME encoding/decoding library
2
3 ;; Copyright (C) 1995,1996,1997,1998,1999 Free Software Foundation, Inc.
4
5 ;; Author: MORIOKA Tomohiko <tomo@m17n.org>
6 ;; Created: 1995/6/25
7 ;; Keywords: MIME, Base64, Quoted-Printable, uuencode, gzip64
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 'mime-def)
29 (require 'poem)
30 (require 'alist)
31
32 (defcustom mime-encoding-list
33   '("7bit" "8bit" "binary" "base64" "quoted-printable")
34   "List of Content-Transfer-Encoding.  Each encoding must be string."
35   :group 'mime
36   :type '(repeat string))
37
38 (defun mime-encoding-list (&optional service)
39   "Return list of Content-Transfer-Encoding.
40 If SERVICE is specified, it returns available list of
41 Content-Transfer-Encoding for it."
42   (if service
43       (let (dest)
44         (mapatoms (lambda (sym)
45                     (or (eq sym nil)
46                         (setq dest (cons (symbol-name sym) dest)))
47                     )
48                   (symbol-value (intern (format "%s-obarray" service))))
49         (let ((rest mel-encoding-module-alist)
50               pair)
51           (while (setq pair (car rest))
52             (let ((key (car pair)))
53               (or (member key dest)
54                   (<= (length key) 1)
55                   (setq dest (cons key dest))))
56             (setq rest (cdr rest)))
57           )
58         dest)
59     mime-encoding-list))
60
61 (defun mime-encoding-alist (&optional service)
62   "Return table of Content-Transfer-Encoding for completion."
63   (mapcar #'list (mime-encoding-list service))
64   )
65
66 (defsubst mel-use-module (name encodings)
67   (let (encoding)
68     (while (setq encoding (car encodings))
69       (set-alist 'mel-encoding-module-alist
70                  encoding
71                  (cons name (cdr (assoc encoding mel-encoding-module-alist))))
72       (setq encodings (cdr encodings))
73       )))
74
75 (defsubst mel-find-function (service encoding)
76   (mel-find-function-from-obarray
77    (symbol-value (intern (format "%s-obarray" service))) encoding))
78
79
80 ;;; @ setting for modules
81 ;;;
82
83 (mel-define-backend "7bit")
84 (mel-define-method-function (mime-encode-string string (nil "7bit"))
85                             'identity)
86 (mel-define-method-function (mime-decode-string string (nil "7bit"))
87                             'identity)
88 (mel-define-method mime-encode-region (start end (nil "7bit")))
89 (mel-define-method mime-decode-region (start end (nil "7bit")))
90 (mel-define-method-function (mime-insert-encoded-file filename (nil "7bit"))
91                             'insert-file-contents-as-binary)
92 (mel-define-method-function (mime-write-decoded-region
93                              start end filename (nil "7bit"))
94                             'write-region-as-binary)
95
96 (mel-define-backend "8bit" ("7bit"))
97
98 (mel-define-backend "binary" ("8bit"))
99
100 (defvar mel-b-builtin
101    (and (fboundp 'base64-encode-string)
102         (subrp (symbol-function 'base64-encode-string))))
103
104 (when mel-b-builtin
105   (mel-define-backend "base64")
106   (mel-define-method-function (mime-encode-string string (nil "base64"))
107                               'base64-encode-string)
108   (mel-define-method-function (mime-decode-string string (nil "base64"))
109                               'base64-decode-string)
110   (mel-define-method-function (mime-encode-region start end (nil "base64"))
111                               'base64-encode-region)
112   (mel-define-method-function (mime-decode-region start end (nil "base64"))
113                               'base64-decode-region)  
114   (mel-define-method mime-insert-encoded-file (filename (nil "base64"))
115     "Encode contents of file FILENAME to base64, and insert the result.
116 It calls external base64 encoder specified by
117 `base64-external-encoder'.  So you must install the program (maybe
118 mmencode included in metamail or XEmacs package)."
119     (interactive (list (read-file-name "Insert encoded file: ")))
120     (insert (base64-encode-string
121              (with-temp-buffer
122                (set-buffer-multibyte nil)
123                (insert-file-contents-as-binary filename)
124                (buffer-string))))
125     (or (bolp)
126         (insert "\n"))
127     )
128     
129   (mel-define-method-function (encoded-text-encode-string string (nil "B"))
130                               'base64-encode-string)
131   (mel-define-method encoded-text-decode-string (string (nil "B"))
132     (if (and (string-match B-encoded-text-regexp string)
133              (string= string (match-string 0 string)))
134         (base64-decode-string string)
135       (error "Invalid encoded-text %s" string)))
136   )
137
138 (mel-use-module 'mel-b-el '("base64" "B"))
139 (mel-use-module 'mel-q '("quoted-printable" "Q"))
140 (mel-use-module 'mel-g '("x-gzip64"))
141 (mel-use-module 'mel-u '("x-uue" "x-uuencode"))
142
143 (defvar mel-b-ccl-module
144   (and (featurep 'mule)
145        (progn
146          (require 'path-util)
147          (module-installed-p 'mel-b-ccl)
148          )))
149
150 (defvar mel-q-ccl-module
151   (and (featurep 'mule)
152        (progn
153          (require 'path-util)
154          (module-installed-p 'mel-q-ccl)
155          )))
156
157 (if mel-b-ccl-module
158     (mel-use-module 'mel-b-ccl '("base64" "B"))
159   )
160
161 (if mel-q-ccl-module
162     (mel-use-module 'mel-q-ccl '("quoted-printable" "Q"))
163   )
164
165 (if base64-dl-module
166     (mel-use-module 'mel-b-dl '("base64" "B"))
167   )
168
169
170 ;;; @ region
171 ;;;
172
173 ;;;###autoload
174 (defun mime-encode-region (start end encoding)
175   "Encode region START to END of current buffer using ENCODING.
176 ENCODING must be string."
177   (interactive
178    (list (region-beginning) (region-end)
179          (completing-read "encoding: "
180                           (mime-encoding-alist)
181                           nil t "base64")))
182   (funcall (mel-find-function 'mime-encode-region encoding) start end)
183   )
184
185
186 ;;;###autoload
187 (defun mime-decode-region (start end encoding)
188   "Decode region START to END of current buffer using ENCODING.
189 ENCODING must be string."
190   (interactive
191    (list (region-beginning) (region-end)
192          (completing-read "encoding: "
193                           (mime-encoding-alist 'mime-decode-region)
194                           nil t "base64")))
195   (funcall (mel-find-function 'mime-decode-region encoding)
196            start end))
197
198
199 ;;; @ string
200 ;;;
201
202 ;;;###autoload
203 (defun mime-decode-string (string encoding)
204   "Decode STRING using ENCODING.
205 ENCODING must be string.  If ENCODING is found in
206 `mime-string-decoding-method-alist' as its key, this function decodes
207 the STRING by its value."
208   (let ((f (mel-find-function 'mime-decode-string encoding)))
209     (if f
210         (funcall f string)
211       string)))
212
213
214 (mel-define-service encoded-text-encode-string (string encoding)
215   "Encode STRING as encoded-text using ENCODING.
216 ENCODING must be string.")
217
218 (mel-define-service encoded-text-decode-string (string encoding)
219   "Decode STRING as encoded-text using ENCODING.
220 ENCODING must be string.")
221
222 (defun base64-encoded-length (string)
223   (* (/ (+ (length string) 2) 3) 4))
224
225 (defsubst Q-encoding-printable-char-p (chr mode)
226   (and (not (memq chr '(?= ?? ?_)))
227        (<= ?\   chr)(<= chr ?~)
228        (cond ((eq mode 'text) t)
229              ((eq mode 'comment)
230               (not (memq chr '(?\( ?\) ?\\)))
231               )
232              (t
233               (string-match "[A-Za-z0-9!*+/=_---]" (char-to-string chr))
234               ))))
235
236 (defun Q-encoded-text-length (string &optional mode)
237   (let ((l 0)(i 0)(len (length string)) chr)
238     (while (< i len)
239       (setq chr (aref string i))
240       (if (or (Q-encoding-printable-char-p chr mode)
241               (eq chr ? ))
242           (setq l (+ l 1))
243         (setq l (+ l 3))
244         )
245       (setq i (+ i 1)) )
246     l))
247
248
249 ;;; @ file
250 ;;;
251
252 ;;;###autoload
253 (defun mime-insert-encoded-file (filename encoding)
254   "Insert file FILENAME encoded by ENCODING format."
255   (interactive
256    (list (read-file-name "Insert encoded file: ")
257          (completing-read "encoding: "
258                           (mime-encoding-alist)
259                           nil t "base64")))
260   (funcall (mel-find-function 'mime-insert-encoded-file encoding)
261            filename))
262
263
264 ;;;###autoload
265 (defun mime-write-decoded-region (start end filename encoding)
266   "Decode and write current region encoded by ENCODING into FILENAME.
267 START and END are buffer positions."
268   (interactive
269    (list (region-beginning) (region-end)
270          (read-file-name "Write decoded region to file: ")
271          (completing-read "encoding: "
272                           (mime-encoding-alist 'mime-write-decoded-region)
273                           nil t "base64")))
274   (funcall (mel-find-function 'mime-write-decoded-region encoding)
275            start end filename))
276
277
278 ;;; @ end
279 ;;;
280
281 (provide 'mel)
282
283 ;;; mel.el ends here.