;;; mime-def.el --- definition module about MIME
-;; Copyright (C) 1995,1996,1997,1998 Free Software Foundation, Inc.
+;; Copyright (C) 1995,1996,1997,1998,1999 Free Software Foundation, Inc.
+;; Copyright (C) 1999 Electrotechnical Laboratory, JAPAN.
+;; Licensed to the Free Software Foundation.
-;; Author: MORIOKA Tomohiko <morioka@jaist.ac.jp>
+;; Author: MORIOKA Tomohiko <tomo@m17n.org>
;; Keywords: definition, MIME, multimedia, mail, news
;; This file is part of FLIM (Faithful Library about Internet Message).
;;; Code:
-(defconst mime-library-version-string "FLIM 1.6.0 - \"Ogura\"")
+(require 'poe)
+(require 'poem)
+(require 'pcustom)
+(require 'mcharset)
+(require 'alist)
+(eval-when-compile (require 'cl)) ; list*
-;;; @ variables
-;;;
+(eval-and-compile
+ (defconst mime-library-product ["CLIME" (1 13 1) "\e$B0BEH\e(B"]
+ "Product name, version number and code name of MIME-library package.")
+ )
+
+(defmacro mime-product-name (product)
+ (` (aref (, product) 0)))
-(require 'custom)
+(defmacro mime-product-version (product)
+ (` (aref (, product) 1)))
-(eval-when-compile (require 'cl))
+(defmacro mime-product-code-name (product)
+ (` (aref (, product) 2)))
-(defgroup mime nil
+(defconst mime-library-version
+ (eval-when-compile
+ (concat (mime-product-name mime-library-product) " "
+ (mapconcat (function number-to-string)
+ (mime-product-version mime-library-product) ".")
+ " - \"" (mime-product-code-name mime-library-product) "\"")))
+
+
+;;; @ variables
+;;;
+
+(defgroup mime '((default-mime-charset custom-variable))
"Emacs MIME Interfaces"
:group 'news
:group 'mail)
-(custom-handle-keyword 'default-mime-charset :group 'mime
- 'custom-variable)
-
-(defcustom mime-temp-directory (or (getenv "MIME_TMP_DIR")
- (getenv "TM_TMP_DIR")
- (getenv "TMPDIR")
- (getenv "TMP")
- (getenv "TEMP")
- "/tmp/")
- "*Directory for temporary files."
- :group 'mime
- :type 'directory)
-
(defcustom mime-uuencode-encoding-name-list '("x-uue" "x-uuencode")
"*List of encoding names for uuencode format."
:group 'mime
;;; @ required functions
;;;
-(unless (fboundp 'butlast)
- (defun butlast (x &optional n)
- "Returns a copy of LIST with the last N elements removed."
- (if (and n (<= n 0)) x
- (nbutlast (copy-sequence x) n)))
-
- (defun nbutlast (x &optional n)
- "Modifies LIST to remove the last N elements."
- (let ((m (length x)))
- (or n (setq n 1))
- (and (< n m)
- (progn
- (if (> n 0) (setcdr (nthcdr (- (1- m) n) x) nil))
- x))))
- )
-
-(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))
-
(defsubst regexp-* (regexp)
(concat regexp "*"))
;;; @ about STD 11
;;;
-(defconst std11-quoted-pair-regexp "\\\\.")
-(defconst std11-non-qtext-char-list '(?\" ?\\ ?\r ?\n))
-(defconst std11-qtext-regexp
- (concat "[^" (char-list-to-string std11-non-qtext-char-list) "]"))
+(eval-and-compile
+ (defconst std11-quoted-pair-regexp "\\\\.")
+ (defconst std11-non-qtext-char-list '(?\" ?\\ ?\r ?\n))
+ (defconst std11-qtext-regexp
+ (eval-when-compile
+ (concat "[^" std11-non-qtext-char-list "]"))))
(defconst std11-quoted-string-regexp
- (concat "\""
- (regexp-*
- (regexp-or std11-qtext-regexp std11-quoted-pair-regexp))
- "\""))
+ (eval-when-compile
+ (concat "\""
+ (regexp-*
+ (regexp-or std11-qtext-regexp std11-quoted-pair-regexp))
+ "\"")))
;;; @ about MIME
;;;
-(defconst mime-tspecials "][()<>@,\;:\\\"/?=")
-(defconst mime-token-regexp (concat "[^" mime-tspecials "\000-\040]+"))
+(eval-and-compile
+ (defconst mime-tspecial-char-list
+ '(?\] ?\[ ?\( ?\) ?< ?> ?@ ?, ?\; ?: ?\\ ?\" ?/ ?? ?=)))
+(defconst mime-token-regexp
+ (eval-when-compile
+ (concat "[^" mime-tspecial-char-list "\000-\040]+")))
(defconst mime-charset-regexp mime-token-regexp)
(defconst mime-media-type/subtype-regexp
(concat mime-token-regexp "/" mime-token-regexp))
-;;; @@ Quoted-Printable
+;;; @@ base64 / B
+;;;
+
+(defconst base64-token-regexp "[A-Za-z0-9+/]")
+(defconst base64-token-padding-regexp "[A-Za-z0-9+/=]")
+
+(defconst B-encoded-text-regexp
+ (concat "\\(\\("
+ base64-token-regexp
+ base64-token-regexp
+ base64-token-regexp
+ base64-token-regexp
+ "\\)*"
+ base64-token-regexp
+ base64-token-regexp
+ base64-token-padding-regexp
+ base64-token-padding-regexp
+ "\\)"))
+
+;; (defconst eword-B-encoding-and-encoded-text-regexp
+;; (concat "\\(B\\)\\?" eword-B-encoded-text-regexp))
+
+
+;;; @@ Quoted-Printable / Q
;;;
(defconst quoted-printable-hex-chars "0123456789ABCDEF")
(concat "=[" quoted-printable-hex-chars
"][" quoted-printable-hex-chars "]"))
+(defconst Q-encoded-text-regexp
+ (concat "\\([^=?]\\|" quoted-printable-octet-regexp "\\)+"))
+
+;; (defconst eword-Q-encoding-and-encoded-text-regexp
+;; (concat "\\(Q\\)\\?" eword-Q-encoded-text-regexp))
+
;;; @ Content-Type
;;;
;;; @ MIME entity
;;;
-(defsubst make-mime-entity (buffer
- header-start header-end body-start body-end
- &optional node-id
- content-type content-disposition
- encoding children)
- (vector buffer header-start header-end body-start body-end
- node-id content-type content-disposition encoding nil
- children nil))
-
-(defsubst mime-entity-buffer (entity) (aref entity 0))
-(defsubst mime-entity-header-start (entity) (aref entity 1))
-(defsubst mime-entity-header-end (entity) (aref entity 2))
-(defsubst mime-entity-body-start (entity) (aref entity 3))
-(defsubst mime-entity-body-end (entity) (aref entity 4))
-(defsubst mime-entity-node-id (entity) (aref entity 5))
-(defsubst mime-entity-content-type (entity) (aref entity 6))
-(defsubst mime-entity-content-disposition (entity) (aref entity 7))
-(defsubst mime-entity-encoding (entity) (aref entity 8))
-(defsubst mime-entity-original-header (entity) (aref entity 9))
-(defsubst mime-entity-children (entity) (aref entity 10))
-(defsubst mime-entity-parsed-header (entity) (aref entity 11))
-
-(defsubst mime-entity-set-original-header (entity header)
- (aset entity 9 header))
-(defsubst mime-entity-set-parsed-header (entity header)
- (aset entity 11 header))
-
-(defsubst mime-entity-number (entity)
- (reverse (mime-entity-node-id entity)))
-
-(defalias 'mime-entity-point-min 'mime-entity-header-start)
-(defalias 'mime-entity-point-max 'mime-entity-body-end)
-
-(defsubst mime-entity-media-type (entity)
- (mime-content-type-primary-type (mime-entity-content-type entity)))
-(defsubst mime-entity-media-subtype (entity)
- (mime-content-type-subtype (mime-entity-content-type entity)))
-(defsubst mime-entity-parameters (entity)
- (mime-content-type-parameters (mime-entity-content-type entity)))
-
-(defsubst mime-entity-type/subtype (entity-info)
- (mime-type/subtype-string (mime-entity-media-type entity-info)
- (mime-entity-media-subtype entity-info)))
+(require 'luna)
+
+(autoload 'mime-entity-content-type "mime")
+(autoload 'mime-parse-multipart "mime-parse")
+(autoload 'mime-parse-encapsulated "mime-parse")
+(autoload 'mime-entity-content "mime")
+
+(luna-define-class mime-entity ()
+ (location
+ content-type children parent
+ node-id
+ content-disposition encoding
+ ;; for other fields
+ original-header parsed-header))
+
+(defalias 'mime-entity-representation-type-internal 'luna-class-name)
+(defalias 'mime-entity-set-representation-type-internal 'luna-set-class-name)
+
+(luna-define-internal-accessors 'mime-entity)
+
+(luna-define-method mime-entity-fetch-field ((entity mime-entity)
+ field-name)
+ (or (symbolp field-name)
+ (setq field-name (intern (capitalize (capitalize field-name)))))
+ (cdr (assq field-name
+ (mime-entity-original-header-internal entity))))
+
+(luna-define-method mime-entity-children ((entity mime-entity))
+ (let* ((content-type (mime-entity-content-type entity))
+ (primary-type (mime-content-type-primary-type content-type)))
+ (cond ((eq primary-type 'multipart)
+ (mime-parse-multipart entity)
+ )
+ ((and (eq primary-type 'message)
+ (memq (mime-content-type-subtype content-type)
+ '(rfc822 news external-body)
+ ))
+ (mime-parse-encapsulated entity)
+ ))
+ ))
+
+(luna-define-method mime-insert-text-content ((entity mime-entity))
+ (insert
+ (decode-mime-charset-string (mime-entity-content entity)
+ (or (mime-content-type-parameter
+ (mime-entity-content-type entity)
+ "charset")
+ default-mime-charset)
+ 'CRLF)
+ ))
+
+
+;;; @ for mm-backend
+;;;
+
+(defmacro mm-expand-class-name (type)
+ (` (intern (format "mime-%s-entity" (, type)))))
+
+(defmacro mm-define-backend (type &optional parents)
+ (` (luna-define-class (, (mm-expand-class-name type))
+ (, (nconc (mapcar (function
+ (lambda (parent)
+ (mm-expand-class-name parent)
+ ))
+ parents)
+ '(mime-entity))))))
+
+(defmacro mm-define-method (name args &rest body)
+ (or (eq name 'initialize-instance)
+ (setq name (intern (format "mime-%s" name))))
+ (let ((spec (car args)))
+ (setq args
+ (cons (list (car spec)
+ (mm-expand-class-name (nth 1 spec)))
+ (cdr args)))
+ (` (luna-define-method (, name) (, args) (,@ body)))
+ ))
+
+(put 'mm-define-method 'lisp-indent-function 'defun)
+
+(def-edebug-spec mm-define-method
+ (&define name ((arg symbolp)
+ [&rest arg]
+ [&optional ["&optional" arg &rest arg]]
+ &optional ["&rest" arg]
+ )
+ def-body))
;;; @ message structure
Following is a list of slots of the structure:
-buffer buffer includes this entity (buffer).
node-id node-id (list of integers)
-header-start minimum point of header in raw-buffer
-header-end maximum point of header in raw-buffer
-body-start minimum point of body in raw-buffer
-body-end maximum point of body in raw-buffer
content-type content-type (content-type)
content-disposition content-disposition (content-disposition)
encoding Content-Transfer-Encoding (string or nil)
(make-variable-buffer-local 'mime-message-structure)
+(make-obsolete-variable 'mime-message-structure "should not use it.")
+
+
+;;; @ for mel-backend
+;;;
+
+(defvar mel-service-list nil)
+
+(defmacro mel-define-service (name &optional args &rest rest)
+ "Define NAME as a service for Content-Transfer-Encodings.
+If ARGS is specified, NAME is defined as a generic function for the
+service."
+ (` (progn
+ (add-to-list 'mel-service-list '(, name))
+ (defvar (, (intern (format "%s-obarray" name))) (make-vector 7 0))
+ (,@ (if args
+ (` ((defun (, name) (, args)
+ (,@ rest)
+ (funcall (mel-find-function '(, name)
+ (, (car (last args))))
+ (,@ (luna-arglist-to-arguments (butlast args))))
+ )))))
+ )))
+
+(put 'mel-define-service 'lisp-indent-function 'defun)
+
+
+(defvar mel-encoding-module-alist nil)
+
+(defsubst mel-find-function-from-obarray (ob-array encoding)
+ (let* ((f (intern-soft encoding ob-array)))
+ (or f
+ (let ((rest (cdr (assoc encoding mel-encoding-module-alist))))
+ (while (and rest
+ (progn
+ (require (car rest))
+ (null (setq f (intern-soft encoding ob-array)))
+ ))
+ (setq rest (cdr rest))
+ )
+ f))))
+
+(defsubst mel-copy-method (service src-backend dst-backend)
+ (let* ((oa (symbol-value (intern (format "%s-obarray" service))))
+ (f (mel-find-function-from-obarray oa src-backend))
+ sym)
+ (when f
+ (setq sym (intern dst-backend oa))
+ (or (fboundp sym)
+ (fset sym (symbol-function f))
+ ))))
+
+(defsubst mel-copy-backend (src-backend dst-backend)
+ (let ((services mel-service-list))
+ (while services
+ (mel-copy-method (car services) src-backend dst-backend)
+ (setq services (cdr services)))))
+
+(defmacro mel-define-backend (type &optional parents)
+ "Define TYPE as a mel-backend.
+If PARENTS is specified, TYPE inherits PARENTS.
+Each parent must be backend name (string)."
+ (cons 'progn
+ (mapcar (function
+ (lambda (parent)
+ (` (mel-copy-backend (, parent) (, type)))
+ ))
+ parents)))
+
+(defmacro mel-define-method (name args &rest body)
+ "Define NAME as a method function of (nth 1 (car (last ARGS))) backend.
+ARGS is like an argument list of lambda, but (car (last ARGS)) must be
+specialized parameter. (car (car (last ARGS))) is name of variable
+and (nth 1 (car (last ARGS))) is name of backend (encoding)."
+ (let* ((specializer (car (last args)))
+ (class (nth 1 specializer)))
+ (` (progn
+ (mel-define-service (, name))
+ (fset (intern (, class) (, (intern (format "%s-obarray" name))))
+ (function
+ (lambda (, (butlast args))
+ (,@ body))))))))
+
+(put 'mel-define-method 'lisp-indent-function 'defun)
+
+(defmacro mel-define-method-function (spec function)
+ "Set SPEC's function definition to FUNCTION.
+First element of SPEC is service.
+Rest of ARGS is like an argument list of lambda, but (car (last ARGS))
+must be specialized parameter. (car (car (last ARGS))) is name of
+variable and (nth 1 (car (last ARGS))) is name of backend (encoding)."
+ (let* ((name (car spec))
+ (args (cdr spec))
+ (specializer (car (last args)))
+ (class (nth 1 specializer)))
+ (` (let (sym)
+ (mel-define-service (, name))
+ (setq sym (intern (, class) (, (intern (format "%s-obarray" name)))))
+ (or (fboundp sym)
+ (fset sym (symbol-function (, function))))))))
+
+(defmacro mel-define-function (function spec)
+ (let* ((name (car spec))
+ (args (cdr spec))
+ (specializer (car (last args)))
+ (class (nth 1 specializer)))
+ (` (progn
+ (define-function (, function)
+ (intern (, class) (, (intern (format "%s-obarray" name)))))
+ ))))
+
+(defvar base64-dl-module
+ (if (and (fboundp 'base64-encode-string)
+ (subrp (symbol-function 'base64-encode-string)))
+ nil
+ (if (fboundp 'dynamic-link)
+ (let ((path (expand-file-name "base64.so" exec-directory)))
+ (and (file-exists-p path)
+ path)
+ ))))
+
;;; @ end
;;;