tm 7.52.1.
[elisp/tm.git] / tm-def.el
1 ;;;
2 ;;; tm-def.el --- definition module for tm
3 ;;;
4 ;;; Copyright (C) 1995 Free Software Foundation, Inc.
5 ;;; Copyright (C) 1995,1996 MORIOKA Tomohiko
6 ;;;
7 ;;; Author: MORIOKA Tomohiko <morioka@jaist.ac.jp>
8 ;;; Version:
9 ;;;     $Id: tm-def.el,v 7.33 1996/04/22 12:40:55 morioka Exp $
10 ;;; Keywords: mail, news, MIME, multimedia, definition
11 ;;;
12 ;;; This file is part of tm (Tools for MIME).
13 ;;;
14 ;;; This program is free software; you can redistribute it and/or
15 ;;; modify it under the terms of the GNU General Public License as
16 ;;; published by the Free Software Foundation; either version 2, or
17 ;;; (at your option) any later version.
18 ;;;
19 ;;; This program is distributed in the hope that it will be useful,
20 ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
21 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22 ;;; General Public License for more details.
23 ;;;
24 ;;; You should have received a copy of the GNU General Public License
25 ;;; along with This program.  If not, write to the Free Software
26 ;;; Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
27 ;;;
28 ;;; Code:
29
30 (require 'emu)
31 (require 'tl-822)
32
33
34 ;;; @ variables
35 ;;;
36
37 (defvar mime/tmp-dir (or (getenv "TM_TMP_DIR") "/tmp/"))
38
39 (defvar mime/use-multi-frame
40   (and (>= emacs-major-version 19) window-system))
41
42 (defvar mime/find-file-function
43   (if mime/use-multi-frame
44       (function find-file-other-frame)
45     (function find-file)
46     ))
47
48
49 ;;; @ constants
50 ;;;
51
52 (defconst mime/output-buffer-name "*MIME-out*")
53 (defconst mime/temp-buffer-name " *MIME-temp*")
54
55
56 ;;; @ leading-character and charset
57 ;;;
58
59 (defvar mime/lc-charset-alist
60   (foldr (function
61           (lambda (a cell)
62             (or (catch 'tag
63                   (cons (cons (foldr (function
64                                       (lambda (a sym)
65                                         (if (boundp sym)
66                                             (cons (symbol-value sym) a)
67                                           (throw 'tag nil)
68                                           )))
69                                      nil
70                                      (car cell))
71                               (cdr cell))
72                         a))
73                 a)
74             ))
75          nil
76          '(((lc-ascii)         . "US-ASCII")
77            ((lc-ascii lc-ltn1) . "ISO-8859-1")
78            ((lc-ascii lc-ltn2) . "ISO-8859-2")
79            ((lc-ascii lc-ltn3) . "ISO-8859-3")
80            ((lc-ascii lc-ltn4) . "ISO-8859-4")
81 ;;;        ((lc-ascii lc-crl)  . "ISO-8859-5")
82            ((lc-ascii lc-crl)  . "KOI8-R")
83            ((lc-ascii lc-grk)  . "ISO-8859-7")
84            ((lc-ascii lc-hbw)  . "ISO-8859-8")
85            ((lc-ascii lc-ltn5) . "ISO-8859-9")
86            ((lc-ascii lc-jp)   . "ISO-2022-JP")
87            ((lc-ascii lc-kr)   . "EUC-KR")
88            ((lc-ascii
89              lc-jp lc-cn
90              lc-kr lc-jp2
91              lc-ltn1 lc-grk)   . "ISO-2022-JP-2")
92            ((lc-ascii
93              lc-jp lc-cn
94              lc-kr lc-jp2
95              lc-cns1 lc-cns2
96              lc-ltn1 lc-grk)   . "ISO-2022-INT-1")
97            )))
98
99 (defvar mime/unknown-charset "ISO-2022-INT-1")
100
101
102 ;;; @ charset and encoding
103 ;;;
104
105 (defun mime/find-charset (lcl)
106   (if lcl
107       (or (cdr (some-element
108                 (function
109                  (lambda (elt)
110                    (subsetp lcl (car elt))
111                    ))
112                 mime/lc-charset-alist)
113                )
114           mime/unknown-charset)
115     ))
116
117 (defun mime/find-charset-region (beg end)
118   (mime/find-charset (cons lc-ascii (find-charset-region beg end)))
119   )
120
121 (defvar mime/charset-type-list
122   '(("US-ASCII"       7 nil)
123     ("ISO-8859-1"     8 "quoted-printable")
124     ("ISO-8859-2"     8 "quoted-printable")
125     ("ISO-8859-3"     8 "quoted-printable")
126     ("ISO-8859-4"     8 "quoted-printable")
127     ("ISO-8859-5"     8 "quoted-printable")
128     ("KOI8-R"         8 "quoted-printable")
129     ("ISO-8859-7"     8 "quoted-printable")
130     ("ISO-8859-8"     8 "quoted-printable")
131     ("ISO-8859-9"     8 "quoted-printable")
132     ("ISO-2022-JP"    7 "base64")
133     ("ISO-2022-KR"    7 "base64")
134     ("EUC-KR"         8 "base64")
135     ("ISO-2022-JP-2"  7 "base64")
136     ("ISO-2022-INT-1" 7 "base64")
137     ))
138
139 (defun mime/encoding-name (transfer-level &optional not-omit)
140   (cond ((> transfer-level 8) "binary")
141         ((= transfer-level 8) "8bit")
142         (not-omit "7bit")
143         ))
144
145 (defun mime/make-charset-default-encoding-alist (transfer-level)
146   (mapcar (function
147            (lambda (charset-type)
148              (let ((charset  (car charset-type))
149                    (type     (nth 1 charset-type))
150                    (encoding (nth 2 charset-type))
151                    )
152                (if (<= type transfer-level)
153                    (cons charset (mime/encoding-name type))
154                  (cons charset encoding)
155                  ))))
156           mime/charset-type-list))
157
158
159 ;;; @ coding-system
160 ;;;
161
162 (defvar mime/charset-coding-system-alist
163   (foldr (function
164           (lambda (a cell)
165             (if (boundp (cdr cell))
166                 (cons (cons (car cell) (symbol-value (cdr cell))) a)
167               a)))
168          nil
169          '(("ISO-2022-JP"     . *junet*)
170            ("ISO-2022-KR"     . *iso-2022-kr*)
171            ("EUC-KR"          . *euc-kr*)
172            ("ISO-8859-1"      . *ctext*)
173            ("ISO-8859-2"      . *iso-8859-2*)
174            ("ISO-8859-3"      . *iso-8859-3*)
175            ("ISO-8859-4"      . *iso-8859-4*)
176            ("ISO-8859-5"      . *iso-8859-5*)
177            ("KOI8-R"          . *koi8*)
178            ("ISO-8859-7"      . *iso-8859-7*)
179            ("ISO-8859-8"      . *iso-8859-8*)
180            ("ISO-8859-9"      . *iso-8859-9*)
181            ("ISO-2022-JP-2"   . *iso-2022-ss2-7*)
182            ("X-ISO-2022-JP-2" . *iso-2022-ss2-7*)
183            ("ISO-2022-INT-1"  . *iso-2022-int-1*)
184            ("SHIFT_JIS"       . *sjis*)
185            ("X-SHIFTJIS"      . *sjis*)
186            )))
187
188 (defvar mime/default-coding-system *ctext*)
189
190 (defun mime/convert-string-to-emacs (str charset)
191   (let ((cs (cdr (assoc charset mime/charset-coding-system-alist))))
192     (if cs
193         (code-convert-string str cs *internal*)
194       )))
195
196 (defun mime/convert-string-from-emacs (str charset)
197   (let ((cs (cdr (assoc charset mime/charset-coding-system-alist))))
198     (if cs
199         (code-convert-string str *internal* cs)
200       )))
201
202 (defun mime/code-convert-region-to-emacs (beg end charset &optional encoding)
203   (let ((ct
204          (if (stringp charset)
205              (cdr (assoc (upcase charset) mime/charset-coding-system-alist))
206            mime/default-coding-system)))
207     (if ct
208         (code-convert-region beg end ct *internal*)
209       )))
210
211 (defun mime/code-convert-region-from-emacs (beg end charset &optional encoding)
212   (let ((ct
213          (if (stringp charset)
214              (cdr (assoc (upcase charset) mime/charset-coding-system-alist))
215            mime/default-coding-system)))
216     (if ct
217         (code-convert-region beg end *internal* ct)
218       )))
219
220
221 ;;; @ button
222 ;;;
223
224 (defun tm:set-face-region (b e face)
225   (let ((overlay (tl:make-overlay b e)))
226     (tl:overlay-put overlay 'face face)
227     ))
228
229 (setq tm:button-face 'bold)
230 (setq tm:mouse-face 'highlight)
231
232 (defun tm:add-button (from to func &optional data)
233   "Create a button between FROM and TO with callback FUNC and data DATA."
234   (and tm:button-face
235        (tl:overlay-put (tl:make-overlay from to) 'face tm:button-face))
236   (tl:add-text-properties from to
237                           (append (and tm:mouse-face
238                                        (list 'mouse-face tm:mouse-face))
239                                   (list 'tm-callback func)
240                                   (and data (list 'tm-data data))
241                                   ))
242   )
243
244 (defvar tm:mother-button-dispatcher nil)
245
246 (defun tm:button-dispatcher (event)
247   "Select the button under point."
248   (interactive "e")
249   (mouse-set-point event)
250   (let ((func (get-text-property (point) 'tm-callback))
251         (data (get-text-property (point) 'tm-data))
252         )
253     (if func
254         (apply func data)
255       (if (fboundp tm:mother-button-dispatcher)
256           (funcall tm:mother-button-dispatcher event)
257         )
258       )))
259
260
261 ;;; @ for URL
262 ;;;
263
264 (defvar tm:URL-regexp
265   "\\(http\\|ftp\\|file\\|gopher\\|news\\|telnet\\|wais\\|mailto\\):\\(//[-a-zA-Z0-9_.]+:[0-9]*\\)?[-a-zA-Z0-9_=?#$@~`%&*+|\\/.,]*[-a-zA-Z0-9_=#$@~`%&*+|\\/]")
266
267 (defvar browse-url-browser-function nil)
268
269 (defun tm:browse-url (&optional url)
270   (if (fboundp browse-url-browser-function)
271       (call-interactively browse-url-browser-function)
272     (if (fboundp tm:mother-button-dispatcher)
273         (call-interactively tm:mother-button-dispatcher)
274       )
275     ))
276
277
278 ;;; @ definitions about MIME
279 ;;;
280
281 (defconst mime/tspecials "][\000-\040()<>@,\;:\\\"/?.=")
282 (defconst mime/token-regexp (concat "[^" mime/tspecials "]+"))
283 (defconst mime/charset-regexp mime/token-regexp)
284
285 (defconst mime/content-type-subtype-regexp
286   (concat mime/token-regexp "/" mime/token-regexp))
287 (defconst mime/content-parameter-value-regexp
288   (concat "\\("
289           rfc822/quoted-string-regexp
290           "\\|[^; \t\n]*\\)"))
291
292 (defconst mime/disposition-type-regexp mime/token-regexp)
293
294
295 ;;; @@ Base64
296 ;;;
297
298 (defconst base64-token-regexp "[A-Za-z0-9+/=]")
299
300 (defconst mime/B-encoded-text-regexp
301   (concat "\\("
302           base64-token-regexp
303           base64-token-regexp
304           base64-token-regexp
305           base64-token-regexp
306           "\\)+"))
307 (defconst mime/B-encoding-and-encoded-text-regexp
308   (concat "\\(B\\)\\?" mime/B-encoded-text-regexp))
309
310
311 ;;; @@ Quoted-Printable
312 ;;;
313
314 (defconst quoted-printable-hex-chars "0123456789ABCDEF")
315 (defconst quoted-printable-octet-regexp
316   (concat "=[" quoted-printable-hex-chars
317           "][" quoted-printable-hex-chars "]"))
318
319 (defconst mime/Q-encoded-text-regexp
320   (concat "\\([^=?]\\|" quoted-printable-octet-regexp "\\)+"))
321 (defconst mime/Q-encoding-and-encoded-text-regexp
322   (concat "\\(Q\\)\\?" mime/Q-encoded-text-regexp))
323
324
325 ;;; @ rot13-47
326 ;;;
327 ;; caesar-region written by phr@prep.ai.mit.edu  Nov 86
328 ;; modified by tower@prep Nov 86
329 ;; gnus-caesar-region
330 ;; Modified by umerin@flab.flab.Fujitsu.JUNET for ROT47.
331 (defun tm:caesar-region (&optional n)
332   "Caesar rotation of region by N, default 13, for decrypting netnews.
333 ROT47 will be performed for Japanese text in any case."
334   (interactive (if current-prefix-arg   ; Was there a prefix arg?
335                    (list (prefix-numeric-value current-prefix-arg))
336                  (list nil)))
337   (cond ((not (numberp n)) (setq n 13))
338         (t (setq n (mod n 26))))        ;canonicalize N
339   (if (not (zerop n))           ; no action needed for a rot of 0
340       (progn
341         (if (or (not (boundp 'caesar-translate-table))
342                 (/= (aref caesar-translate-table ?a) (+ ?a n)))
343             (let ((i 0) (lower "abcdefghijklmnopqrstuvwxyz") upper)
344               (message "Building caesar-translate-table...")
345               (setq caesar-translate-table (make-vector 256 0))
346               (while (< i 256)
347                 (aset caesar-translate-table i i)
348                 (setq i (1+ i)))
349               (setq lower (concat lower lower) upper (upcase lower) i 0)
350               (while (< i 26)
351                 (aset caesar-translate-table (+ ?a i) (aref lower (+ i n)))
352                 (aset caesar-translate-table (+ ?A i) (aref upper (+ i n)))
353                 (setq i (1+ i)))
354               ;; ROT47 for Japanese text.
355               ;; Thanks to ichikawa@flab.fujitsu.junet.
356               (setq i 161)
357               (let ((t1 (logior ?O 128))
358                     (t2 (logior ?! 128))
359                     (t3 (logior ?~ 128)))
360                 (while (< i 256)
361                   (aset caesar-translate-table i
362                         (let ((v (aref caesar-translate-table i)))
363                           (if (<= v t1) (if (< v t2) v (+ v 47))
364                             (if (<= v t3) (- v 47) v))))
365                   (setq i (1+ i))))
366               (message "Building caesar-translate-table...done")))
367         (let ((from (region-beginning))
368               (to (region-end))
369               (i 0) str len)
370           (setq str (buffer-substring from to))
371           (setq len (length str))
372           (while (< i len)
373             (aset str i (aref caesar-translate-table (aref str i)))
374             (setq i (1+ i)))
375           (goto-char from)
376           (delete-region from to)
377           (insert str)))))
378
379
380 ;;; @ field
381 ;;;
382
383 (defun tm:set-fields (sym field-list &optional regexp-sym)
384   (or regexp-sym
385       (setq regexp-sym
386             (let ((name (symbol-name sym)))
387               (intern
388                (concat (if (string-match "\\(.*\\)-list" name)
389                            (substring name 0 (match-end 1))
390                          name)
391                        "-regexp")
392                )))
393       )
394   (set sym field-list)
395   (set regexp-sym
396        (concat "^" (apply (function regexp-or) field-list) ":"))
397   )
398
399 (defun tm:add-fields (sym field-list &optional regexp-sym)
400   (or regexp-sym
401       (setq regexp-sym
402             (let ((name (symbol-name sym)))
403               (intern
404                (concat (if (string-match "\\(.*\\)-list" name)
405                            (substring name 0 (match-end 1))
406                          name)
407                        "-regexp")
408                )))
409       )
410   (let ((fields (eval sym)))
411     (mapcar (function
412              (lambda (field)
413                (or (member field fields)
414                    (setq fields (cons field fields))
415                    )
416                ))
417             (reverse field-list)
418             )
419     (set regexp-sym
420          (concat "^" (apply (function regexp-or) fields) ":"))
421     (set sym fields)
422     ))
423
424 (defun tm:delete-fields (sym field-list &optional regexp-sym)
425   (or regexp-sym
426       (setq regexp-sym
427             (let ((name (symbol-name sym)))
428               (intern
429                (concat (if (string-match "\\(.*\\)-list" name)
430                            (substring name 0 (match-end 1))
431                          name)
432                        "-regexp")
433                )))
434       )
435   (let ((fields (eval sym)))
436     (mapcar (function
437              (lambda (field)
438                (setq fields (delete field fields))
439                ))
440             field-list)
441     (set regexp-sym
442          (concat "^" (apply (function regexp-or) fields) ":"))
443     (set sym fields)
444     ))
445
446
447 ;;; @ end
448 ;;;
449
450 (provide 'tm-def)
451
452 ;;; tm-def.el ends here