mel of MEL 2.0.
[elisp/flim.git] / mel-q.el
1 ;;;
2 ;;; $Id: mel-q.el,v 2.0 1995/09/11 11:33:47 morioka Exp $
3 ;;;
4
5 ;;; @ constants
6 ;;;
7
8 (defconst quoted-printable-hex-chars "0123456789ABCDEF")
9 (defconst quoted-printable-octet-regexp
10   (concat "=[" quoted-printable-hex-chars
11           "][" quoted-printable-hex-chars "]"))
12
13
14 ;;; @ variables
15 ;;;
16
17 (defvar quoted-printable-external-encoder '("mmencode" "-q")
18   "*list of quoted-printable encoder program name and its arguments.")
19
20 (defvar quoted-printable-external-decoder '("mmencode" "-q" "-u")
21   "*list of quoted-printable decoder program name and its arguments.")
22
23 (defvar quoted-printable-internal-encoding-limit 10000
24   "*limit size to use internal quoted-printable encoder.
25 If size of input to encode is larger than this limit,
26 external encoder is called.")
27
28 (defvar quoted-printable-internal-decoding-limit nil
29   "*limit size to use internal quoted-printable decoder.
30 If size of input to decode is larger than this limit,
31 external decoder is called.")
32
33
34 ;;; @ Quoted-Printable (Q-encode) encoder/decoder
35 ;;;
36
37 (defun quoted-printable-quote-char (chr)
38   (concat "="
39           (char-to-string (elt quoted-printable-hex-chars (ash chr -4)))
40           (char-to-string (elt quoted-printable-hex-chars (logand chr 15)))
41           ))
42
43
44 ;;; @@ Quoted-Printable encode/decode string
45 ;;;
46
47 (defun quoted-printable-encode-string (str)
48   (let ((i 0))
49     (mapconcat (function
50                 (lambda (chr)
51                   (cond ((or (< chr 32) (< 126 chr) (eq chr ?=))
52                          (if (>= i 73)
53                              (progn
54                                (setq i 0)
55                                (concat "=\n" (quoted-printable-quote-char chr))
56                                )
57                            (progn
58                              (setq i (+ i 3))
59                              (quoted-printable-quote-char chr)
60                              )))
61                         (t (if (>= i 75)
62                                (progn
63                                  (setq i 0)
64                                  (concat "=\n" (char-to-string chr))
65                                  )
66                              (progn
67                                (setq i (1+ i))
68                                (char-to-string chr)
69                                )))
70                         )))
71                str "")))
72
73 (defun quoted-printable-decode-string (str)
74   (let (q h l)
75     (mapconcat (function
76                 (lambda (chr)
77                   (cond ((eq chr ?=)
78                          (setq q t)
79                          "")
80                         (q (setq h
81                                  (cond ((<= ?a chr) (+ (- chr ?a) 10))
82                                        ((<= ?A chr) (+ (- chr ?A) 10))
83                                        ((<= ?0 chr) (- chr ?0))
84                                        ))
85                            (setq q nil)
86                            "")
87                         (h (setq l (cond ((<= ?a chr) (+ (- chr ?a) 10))
88                                          ((<= ?A chr) (+ (- chr ?A) 10))
89                                          ((<= ?0 chr) (- chr ?0))
90                                          ))
91                            (prog1
92                                (char-to-string (logior (ash h 4) l))
93                              (setq h nil)
94                              )
95                            )
96                         (t (char-to-string chr))
97                         )))
98                str "")))
99
100
101 ;;; @@ Quoted-Printable encode/decode region
102 ;;;
103
104 (defun quoted-printable-internal-encode-region (beg end)
105   (save-excursion
106     (save-restriction
107       (narrow-to-region beg end)
108       (goto-char (point-min))
109       (catch 'tag
110         (let (b e str)
111           (while t
112             (beginning-of-line) (setq b (point))
113             (end-of-line)       (setq e (point))
114             (if (< b e)
115                 (progn
116                   (setq str (buffer-substring b e))
117                   (delete-region b e)
118                   (insert (quoted-printable-encode-string str))
119                   ))
120             (if (eobp)
121                 (throw 'tag nil)
122               )
123             (forward-char 1)
124             )))
125       )))
126
127 (defun quoted-printable-internal-decode-region (beg end)
128   (save-excursion
129     (save-restriction
130       (narrow-to-region beg end)
131       (goto-char (point-min))
132       (while (re-search-forward "=\n" nil t)
133         (replace-match "")
134         )
135       (goto-char (point-min))
136       (let (b e str)
137         (while (re-search-forward quoted-printable-octet-regexp nil t)
138           (setq b (match-beginning 0))
139           (setq e (match-end 0))
140           (setq str (buffer-substring b e))
141           (delete-region b e)
142           (insert (quoted-printable-decode-string str))
143           ))
144       )))
145
146 (cond ((boundp 'MULE)
147        (define-program-coding-system
148          nil (car quoted-printable-external-encoder) *noconv*)
149        (define-program-coding-system
150          nil (car quoted-printable-external-decoder) *noconv*)
151        )
152       ((boundp 'NEMACS)
153        (define-program-kanji-code
154          nil (car quoted-printable-external-encoder) 0)
155        (define-program-kanji-code
156          nil (car quoted-printable-external-decoder) 0)
157        ))
158
159 (defun quoted-printable-external-encode-region (beg end)
160   (save-excursion
161     (apply (function call-process-region)
162            beg end (car quoted-printable-external-encoder)
163            t t nil (cdr quoted-printable-external-encoder))
164     ))
165
166 (defun quoted-printable-external-decode-region (beg end)
167   (save-excursion
168     (apply (function call-process-region)
169            beg end (car quoted-printable-external-decoder)
170            t t nil (cdr quoted-printable-external-decoder))
171     ))
172
173 (defun quoted-printable-encode-region (beg end)
174   (interactive "r")
175   (if (and quoted-printable-internal-encoding-limit
176            (> (- end beg) quoted-printable-internal-encoding-limit))
177       (quoted-printable-external-encode-region beg end)
178     (quoted-printable-internal-encode-region beg end)
179     ))
180
181 (defun quoted-printable-decode-region (beg end)
182   (interactive "r")
183   (if (and quoted-printable-internal-decoding-limit
184            (> (- end beg) quoted-printable-internal-decoding-limit))
185       (quoted-printable-external-decode-region beg end)
186     (quoted-printable-internal-decode-region beg end)
187     ))
188
189
190 ;;; @ Q-encoding encode/decode string
191 ;;;
192
193 (defun q-encoding-encode-string-for-text (str)
194   (mapconcat (function
195               (lambda (chr)
196                 (cond ((eq chr 32) "_")
197                       ((or (< chr 32) (< 126 chr) (eq chr ?=))
198                        (quoted-printable-quote-char chr)
199                        )
200                       (t (char-to-string chr))
201                       )))
202              str ""))
203
204 (defun q-encoding-encode-string-for-comment (str)
205   (mapconcat (function
206               (lambda (chr)
207                 (cond ((eq chr 32) "_")
208                       ((or (< chr 32) (< 126 chr)
209                            (memq chr '(?= ?\( ?\) ?\\))
210                            )
211                        (quoted-printable-quote-char chr)
212                        )
213                       (t (char-to-string chr))
214                       )))
215              str ""))
216
217 (defun q-encoding-encode-string-for-phrase (str)
218   (mapconcat (function
219               (lambda (chr)
220                 (cond ((eq chr 32) "_")
221                       ((or (and (<= ?A chr)(<= chr ?Z))
222                            (and (<= ?a chr)(<= chr ?z))
223                            (and (<= ?0 chr)(<= chr ?9))
224                            (memq chr '(?! ?* ?+ ?- ?/))
225                            )
226                        (char-to-string chr)
227                        )
228                       (t (quoted-printable-quote-char chr))
229                       )))
230              str ""))
231
232 (defun q-encoding-encode-string (str &optional mode)
233   (cond ((eq mode 'text)
234          (q-encoding-encode-string-for-text str)
235          )
236         ((eq mode 'comment)
237          (q-encoding-encode-string-for-comment str)
238          )
239         (t
240          (q-encoding-encode-string-for-phrase str)
241          )))
242
243 (defun q-encoding-decode-string (str)
244   (let (q h l)
245     (mapconcat (function
246                 (lambda (chr)
247                   (cond ((eq chr ?_) " ")
248                         ((eq chr ?=)
249                          (setq q t)
250                          "")
251                         (q (setq h (cond ((<= ?a chr) (+ (- chr ?a) 10))
252                                          ((<= ?A chr) (+ (- chr ?A) 10))
253                                          ((<= ?0 chr) (- chr ?0))
254                                          ))
255                            (setq q nil)
256                            "")
257                         (h (setq l (cond ((<= ?a chr) (+ (- chr ?a) 10))
258                                          ((<= ?A chr) (+ (- chr ?A) 10))
259                                          ((<= ?0 chr) (- chr ?0))
260                                          ))
261                            (prog1
262                                (char-to-string (logior (ash h 4) l))
263                              (setq h nil)
264                              )
265                            )
266                         (t (char-to-string chr))
267                         )))
268                str "")))
269
270
271 ;;; @@ etc
272 ;;;
273
274 (defun q-encoding-encoded-length (string &optional mode)
275   (let ((l 0)(i 0)(len (length string)) chr)
276     (while (< i len)
277       (setq chr (elt string i))
278       (if (string-match "[A-Za-z0-9!*+/=_---]" (char-to-string chr))
279           (setq l (+ l 1))
280         (setq l (+ l 3))
281         )
282       (setq i (+ i 1)) )
283     l))
284
285
286 ;;; @ end
287 ;;;
288
289 (provide 'mel-q)