(eliminate-top-spaces): New inline-function; copied from tl-str.el.
[elisp/semi.git] / mime-def.el
index e629b97..4cc7917 100644 (file)
@@ -3,7 +3,7 @@
 ;; Copyright (C) 1995,1996,1997 Free Software Foundation, Inc.
 
 ;; Author: MORIOKA Tomohiko <morioka@jaist.ac.jp>
-;; Version: $Id: mime-def.el,v 0.22 1997-02-26 04:31:06 tmorioka Exp $
+;; Version: $Id: mime-def.el,v 0.36 1997-03-01 04:06:22 tmorioka Exp $
 ;; Keywords: definition, MIME, multimedia, mail, news
 
 ;; This file is part of SEMI (SEMI is Emacs MIME Interfaces).
@@ -25,7 +25,7 @@
 
 ;;; Code:
 
-(require 'emu)
+(require 'cl)
 
 
 ;;; @ variables
 (defconst mime/temp-buffer-name " *MIME-temp*")
 
 
+;;; @ definitions about MIME
+;;;
+
+(defconst mime/tspecials "][\000-\040()<>@,\;:\\\"/?.=")
+(defconst mime/token-regexp (concat "[^" mime/tspecials "]+"))
+(defconst mime-charset-regexp mime/token-regexp)
+
+(defconst mime/content-type-subtype-regexp
+  (concat mime/token-regexp "/" mime/token-regexp))
+
+(defconst mime/disposition-type-regexp mime/token-regexp)
+
+
+;;; @ MIME charset
+;;;
+
+(defvar charsets-mime-charset-alist
+  '(((ascii)                                           . us-ascii)
+    ((ascii latin-iso8859-1)                           . iso-8859-1)
+    ((ascii latin-iso8859-2)                           . iso-8859-2)
+    ((ascii latin-iso8859-3)                           . iso-8859-3)
+    ((ascii latin-iso8859-4)                           . iso-8859-4)
+;;; ((ascii cyrillic-iso8859-5)                                . iso-8859-5)
+    ((ascii cyrillic-iso8859-5)                                . koi8-r)
+    ((ascii arabic-iso8859-6)                          . iso-8859-6)
+    ((ascii greek-iso8859-7)                           . iso-8859-7)
+    ((ascii hebrew-iso8859-8)                          . iso-8859-8)
+    ((ascii latin-iso8859-9)                           . iso-8859-9)
+    ((ascii latin-jisx0201
+           japanese-jisx0208-1978 japanese-jisx0208)   . iso-2022-jp)
+    ((ascii korean-ksc5601)                            . euc-kr)
+    ((ascii chinese-gb2312)                            . cn-gb-2312)
+    ((ascii chinese-big5-1 chinese-big5-2)             . cn-big5)
+    ((ascii latin-iso8859-1 greek-iso8859-7
+           latin-jisx0201 japanese-jisx0208-1978
+           chinese-gb2312 japanese-jisx0208
+           korean-ksc5601 japanese-jisx0212)           . iso-2022-jp-2)
+    ((ascii latin-iso8859-1 greek-iso8859-7
+           latin-jisx0201 japanese-jisx0208-1978
+           chinese-gb2312 japanese-jisx0208
+           korean-ksc5601 japanese-jisx0212
+           chinese-cns11643-1 chinese-cns11643-2)      . iso-2022-int-1)
+    ((ascii latin-iso8859-1 latin-iso8859-2
+           cyrillic-iso8859-5 greek-iso8859-7
+           latin-jisx0201 japanese-jisx0208-1978
+           chinese-gb2312 japanese-jisx0208
+           korean-ksc5601 japanese-jisx0212
+           chinese-cns11643-1 chinese-cns11643-2
+           chinese-cns11643-3 chinese-cns11643-4
+           chinese-cns11643-5 chinese-cns11643-6
+           chinese-cns11643-7)                         . iso-2022-cjk)
+    ))
+
+(defvar default-mime-charset 'x-ctext)
+
+(defvar mime-charset-coding-system-alist
+  '((x-ctext           . ctext)
+    (gb2312            . cn-gb-2312)
+    (iso-2022-jp-2     . iso-2022-ss2-7)
+    ))
+
+(defun mime-charset-to-coding-system (charset &optional lbt)
+  (if (stringp charset)
+      (setq charset (intern (downcase charset)))
+    )
+  (let ((cs
+        (or (cdr (assq charset mime-charset-coding-system-alist))
+            (and (coding-system-p charset) charset)
+            )))
+    (if lbt
+       (intern (concat (symbol-name cs) "-" (symbol-name lbt)))
+      cs)))
+
+(defun detect-mime-charset-region (start end)
+  "Return MIME charset for region between START and END."
+  (charsets-to-mime-charset
+   (find-charset-string (buffer-substring start end))
+   ))
+
+(defun encode-mime-charset-region (start end charset)
+  "Encode the text between START and END as MIME CHARSET."
+  (let ((cs (mime-charset-to-coding-system charset)))
+    (if cs
+       (encode-coding-region start end cs)
+      )))
+
+(defun decode-mime-charset-region (start end charset)
+  "Decode the text between START and END as MIME CHARSET."
+  (let ((cs (mime-charset-to-coding-system charset)))
+    (if cs
+       (decode-coding-region start end cs)
+      )))
+
+(defun encode-mime-charset-string (string charset)
+  "Encode the STRING as MIME CHARSET."
+  (let ((cs (mime-charset-to-coding-system charset)))
+    (if cs
+       (encode-coding-string string cs)
+      string)))
+
+(defun decode-mime-charset-string (string charset)
+  "Decode the STRING as MIME CHARSET."
+  (let ((cs (mime-charset-to-coding-system charset)))
+    (if cs
+       (decode-coding-string string cs)
+      string)))
+
+
 ;;; @ button
 ;;;
 
+(defvar running-xemacs (string-match "XEmacs" emacs-version))
+
+(if running-xemacs
+    (require 'overlay)
+  )
+
 (defvar mime-button-face 'bold
   "Face used for content-button or URL-button of MIME-Preview buffer.")
 
 (defvar mime-button-mouse-face 'highlight
   "Face used for MIME-preview buffer mouse highlighting.")
 
-(defun tm:add-button (from to func &optional data)
+(defun mime-add-button (from to func &optional data)
   "Create a button between FROM and TO with callback FUNC and data DATA."
   (and mime-button-face
        (overlay-put (make-overlay from to) 'face mime-button-face))
-  (tl:add-text-properties from to
-                         (nconc
-                          (and mime-button-mouse-face
-                               (list 'mouse-face mime-button-mouse-face))
-                          (list 'mime-button-callback func)
-                          (and data (list 'mime-button-data data))
-                          ))
+  (add-text-properties from to
+                      (nconc
+                       (and mime-button-mouse-face
+                            (list 'mouse-face mime-button-mouse-face))
+                       (list 'mime-button-callback func)
+                       (and data (list 'mime-button-data data))
+                       ))
   )
 
 (defvar mime-button-mother-dispatcher nil)
     (fetch-key         mc-pgp-fetch-key                "mc-pgp")
     (snarf-keys                mc-snarf-keys                   "mc-toplev")
     ;; for mime-edit
-    (mime-sign         tm:mc-pgp-sign-region           "mime-edit-mc")
+    (mime-sign         tm:mc-pgp-sign-region           "mime-mc")
     (traditional-sign  mc-pgp-sign-region              "mc-pgp")
-    (encrypt           tm:mc-pgp-encrypt-region        "mime-edit-mc")
+    (encrypt           tm:mc-pgp-encrypt-region        "mime-mc")
     (insert-key                mc-insert-public-key            "mc-toplev")
     )
   "Alist of service names vs. corresponding functions and its filenames.
@@ -140,17 +254,160 @@ FUNCTION.")
        pgp-function-alist)
 
 
-;;; @ definitions about MIME
+;;; @ method selector kernel
 ;;;
 
-(defconst mime/tspecials "][\000-\040()<>@,\;:\\\"/?.=")
-(defconst mime/token-regexp (concat "[^" mime/tspecials "]+"))
-(defconst mime-charset-regexp mime/token-regexp)
+;;; @@ field unifier
+;;;
 
-(defconst mime/content-type-subtype-regexp
-  (concat mime/token-regexp "/" mime/token-regexp))
+(defun field-unifier-for-default (a b)
+  (let ((ret
+        (cond ((equal a b)    a)
+              ((null (cdr b)) a)
+              ((null (cdr a)) b)
+              )))
+    (if ret
+       (list nil ret nil)
+      )))
+
+(defun field-unifier-for-mode (a b)
+  (let ((va (cdr a)))
+    (if (if (consp va)
+           (member (cdr b) va)
+         (equal va (cdr b))
+         )
+       (list nil b nil)
+      )))
+
+(defun field-unify (a b)
+  (let ((sym (intern (concat "field-unifier-for-" (symbol-name (car a))))))
+    (or (fboundp sym)
+       (setq sym (function field-unifier-for-default))
+       )
+    (funcall sym a b)
+    ))
 
-(defconst mime/disposition-type-regexp mime/token-regexp)
+
+;;; @@ type unifier
+;;;
+
+(defun assoc-unify (class instance)
+  (catch 'tag
+    (let ((cla (copy-alist class))
+         (ins (copy-alist instance))
+         (r class)
+         cell aret ret prev rest)
+      (while r
+       (setq cell (car r))
+       (setq aret (assoc (car cell) ins))
+       (if aret
+           (if (setq ret (field-unify cell aret))
+               (progn
+                 (if (car ret)
+                     (setq prev (put-alist (car (car ret))
+                                           (cdr (car ret))
+                                           prev))
+                   )
+                 (if (nth 2 ret)
+                     (setq rest (put-alist (car (nth 2 ret))
+                                           (cdr (nth 2 ret))
+                                           rest))
+                   )
+                 (setq cla (put-alist (car cell)(cdr (nth 1 ret)) cla))
+                 (setq ins (del-alist (car cell) ins))
+                 )
+             (throw 'tag nil)
+             ))
+       (setq r (cdr r))
+       )
+      (setq r (copy-alist ins))
+      (while r
+       (setq cell (car r))
+       (setq aret (assoc (car cell) cla))
+       (if aret
+           (if (setq ret (field-unify cell aret))
+               (progn
+                 (if (car ret)
+                     (setq prev (put-alist (car (car ret))
+                                           (cdr (car ret))
+                                           prev))
+                   )
+                 (if (nth 2 ret)
+                     (setq rest (put-alist (car (nth 2 ret))
+                                           (cdr (nth 2 ret))
+                                           rest))
+                   )
+                 (setq cla (del-alist (car cell) cla))
+                 (setq ins (put-alist (car cell)(cdr (nth 1 ret)) ins))
+                 )
+             (throw 'tag nil)
+             ))
+       (setq r (cdr r))
+       )
+      (list prev (append cla ins) rest)
+      )))
+
+(defun get-unified-alist (db al)
+  (let ((r db) ret)
+    (catch 'tag
+      (while r
+       (if (setq ret (nth 1 (assoc-unify (car r) al)))
+           (throw 'tag ret)
+         )
+       (setq r (cdr r))
+       ))))
+
+(defun delete-atype (atl al)
+  (let* ((r atl) ret oal)
+    (setq oal
+         (catch 'tag
+           (while r
+             (if (setq ret (nth 1 (assoc-unify (car r) al)))
+                 (throw 'tag (car r))
+               )
+             (setq r (cdr r))
+             )))
+    (delete oal atl)
+    ))
+
+(defun remove-atype (sym al)
+  (and (boundp sym)
+       (set sym (delete-atype (eval sym) al))
+       ))
+
+(defun replace-atype (atl old-al new-al)
+  (let* ((r atl) ret oal)
+    (if (catch 'tag
+         (while r
+           (if (setq ret (nth 1 (assoc-unify (car r) old-al)))
+               (throw 'tag (rplaca r new-al))
+             )
+           (setq r (cdr r))
+           ))
+       atl)))
+
+(defun set-atype (sym al &rest options)
+  (if (null (boundp sym))
+      (set sym al)
+    (let* ((replacement (memq 'replacement options))
+          (ignore-fields (car (cdr (memq 'ignore options))))
+          (remove (or (car (cdr (memq 'remove options)))
+                      (let ((ral (copy-alist al)))
+                        (mapcar (function
+                                 (lambda (type)
+                                   (setq ral (del-alist type ral))
+                                   ))
+                                ignore-fields)
+                        ral)))
+          )
+      (set sym
+          (or (if replacement
+                  (replace-atype (eval sym) remove al)
+                )
+              (cons al
+                    (delete-atype (eval sym) remove)
+                    )
+              )))))
 
 
 ;;; @ rot13-47
@@ -211,6 +468,9 @@ ROT47 will be performed for Japanese text in any case."
 ;;; @ field
 ;;;
 
+(defsubst regexp-or (&rest args)
+  (concat "\\(" (mapconcat (function identity) args "\\|") "\\)"))
+
 (defun tm:set-fields (sym field-list &optional regexp-sym)
   (or regexp-sym
       (setq regexp-sym
@@ -285,6 +545,51 @@ ROT47 will be performed for Japanese text in any case."
        ))
 
 
+;;; @ Other Utility
+;;;
+
+(defsubst eliminate-top-spaces (string)
+  "Eliminate top sequence of space or tab in STRING."
+  (if (string-match "^[ \t]+" string)
+      (substring string (match-end 0))
+    string))
+
+(defun call-after-loaded (module func &optional hook-name)
+  "If MODULE is provided, then FUNC is called.
+Otherwise func is set to MODULE-load-hook.
+If optional argument HOOK-NAME is specified,
+it is used as hook to set."
+  (if (featurep module)
+      (funcall func)
+    (or hook-name
+       (setq hook-name (intern (concat (symbol-name module) "-load-hook")))
+       )
+    (add-hook hook-name func)
+    ))
+
+(defmacro defun-maybe (name &rest everything-else)
+  (or (and (fboundp name)
+          (not (get name 'defun-maybe))
+          )
+      `(or (fboundp (quote ,name))
+          (progn
+            (defun ,name ,@everything-else)
+            (put (quote ,name) 'defun-maybe t)
+            ))
+      ))
+
+(put 'defun-maybe 'lisp-indent-function 'defun)
+
+(defun-maybe functionp (obj)
+  "Returns t if OBJ is a function, nil otherwise.
+\[XEmacs emulating function]"
+  (or (subrp obj)
+      (byte-code-function-p obj)
+      (and (symbolp obj)(fboundp obj))
+      (and (consp obj)(eq (car obj) 'lambda))
+      ))
+
+
 ;;; @ end
 ;;;