X-Git-Url: http://git.chise.org/gitweb/?a=blobdiff_plain;f=mime-def.el;h=181ae1c9b2ac8743e8369a5c3c935561227fd7e6;hb=b1bfe0242a1404c7c9f86e240d630ee1a497d166;hp=d5387be62f8c4a1f3a83d236b9e57ab7ab58a654;hpb=3669b5e2d7ab5880f1091d7adb4a013252c80af6;p=elisp%2Fflim.git diff --git a/mime-def.el b/mime-def.el index d5387be..181ae1c 100644 --- a/mime-def.el +++ b/mime-def.el @@ -1,8 +1,10 @@ ;;; 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 +;; Author: MORIOKA Tomohiko ;; Keywords: definition, MIME, multimedia, mail, news ;; This file is part of FLIM (Faithful Library about Internet Message). @@ -24,7 +26,34 @@ ;;; 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* + +(eval-and-compile + (defconst mime-library-product ["FLIM" (1 13 2) "Kasanui"] + "Product name, version number and code name of MIME-library package.") + ) + +(defmacro mime-product-name (product) + `(aref ,product 0)) + +(defmacro mime-product-version (product) + `(aref ,product 1)) + +(defmacro mime-product-code-name (product) + `(aref ,product 2)) + +(defconst mime-library-version + (eval-when-compile + (concat (mime-product-name mime-library-product) " " + (mapconcat #'number-to-string + (mime-product-version mime-library-product) ".") + " - \"" (mime-product-code-name mime-library-product) "\""))) ;;; @ variables @@ -32,52 +61,20 @@ (require 'custom) -(eval-when-compile (require 'cl)) - -(defgroup mime nil +(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." +(defcustom mime-uuencode-encoding-name-list '("x-uue" "x-uuencode") + "*List of encoding names for uuencode format." :group 'mime - :type 'directory) + :type '(repeat string)) ;;; @ 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 "*")) @@ -88,29 +85,67 @@ ;;; @ 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]+")) -(defconst mime-charset-regexp mime-token-regexp) +(eval-and-compile + (defconst mime-tspecial-char-list + '(?\] ?\[ ?\( ?\) ?< ?> ?@ ?, ?\; ?: ?\\ ?\" ?/ ?? ?=))) + +(defconst mime-token-exclude-chars-regexp + (eval-when-compile + (concat mime-tspecial-char-list "\000-\040"))) + +(defconst mime-token-regexp + (eval-when-compile + (concat "[^" mime-token-exclude-chars-regexp "]+"))) + +(defconst mime-charset-regexp + (eval-when-compile + (concat "[^" mime-token-exclude-chars-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") @@ -119,6 +154,102 @@ (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)) + +;;; @ Parameter +;;; + +(defsubst make-mime-parameter (name &optional language charset + raw-values encoded-value) + (cons name + (vector language charset raw-values encoded-value)) + ) + +(defsubst mime-parameter-language (parm) + (aref (cdr parm) 0) + ) + +(defsubst mime-parameter-set-language (parm language) + (aset (cdr parm) 0 language) + ) + +(defsubst mime-parameter-set-charset (parm mcs) + (aset (cdr parm) 1 mcs) + ) + +(defsubst mime-parameter-charset (parm) + (aref (cdr parm) 1) + ) + +(defsubst mime-parameter-set-raw-values (parm raw-values) + (aset (cdr parm) 2 raw-values) + ) + +(defsubst mime-parameter-raw-values (parm) + (aref (cdr parm) 2) + ) + +(defsubst mime-parameter-append-raw-value (parm no encoded raw-value) + (aset (cdr parm) 2 (cons (cons no (cons encoded raw-value)) + (mime-parameter-raw-values parm))) + ) + +(defun mime-parameter-value (parm) + (when parm + (or (aref (cdr parm) 3) + (let* ((mcs (mime-parameter-charset parm)) + (sorted-raw + (mime-parameter-set-raw-values + parm + (sort (mime-parameter-raw-values parm) + (function (lambda (a b) + (< (car a) (car b))))))) + (val + (if mcs + (with-temp-buffer + (let (s raw) + (while sorted-raw + (setq raw (cdar sorted-raw) + s (point)) + (insert (cdr raw)) + (when (car raw) + (goto-char s) + (while (re-search-forward "%\\([0-9a-z][0-9a-z]\\)" + nil t) + (replace-match + (char-to-string + (string-to-int (buffer-substring + (match-beginning 1) + (match-end 1)) + 16)) + t t)) + (goto-char (point-max)) + ) + (setq sorted-raw (cdr sorted-raw))) + (decode-mime-charset-region (point-min) (point-max) + mcs) + (buffer-string))) + (mapconcat #'cddr sorted-raw ""))) + (language (mime-parameter-language parm))) + (when language + (put-text-property 0 (length val) + 'mime-language language val)) + (aset (cdr parm) 3 val) + )))) + +(defsubst mime-parameters (parms) + (mapcar (function (lambda (parm) + (cons (car parm) + (mime-parameter-value parm)))) + parms)) + +(defsubst mime-parameter (parms name) + (let ((parm (assoc name parms))) + (cons (car parm) (mime-parameter-value parm)))) ;;; @ Content-Type ;;; @@ -139,11 +270,11 @@ (defsubst mime-content-type-parameters (content-type) "Return primary-type of CONTENT-TYPE." - (cddr content-type)) + (mime-parameters (cddr content-type))) (defsubst mime-content-type-parameter (content-type parameter) "Return PARAMETER value of CONTENT-TYPE." - (cdr (assoc parameter (mime-content-type-parameters content-type)))) + (mime-parameter-value (assoc parameter (cddr content-type)))) (defsubst mime-type/subtype-string (type &optional subtype) @@ -163,11 +294,11 @@ (defsubst mime-content-disposition-parameters (content-disposition) "Return disposition-parameters of CONTENT-DISPOSITION." - (cdr content-disposition)) + (mime-parameters (cdr content-disposition))) (defsubst mime-content-disposition-parameter (content-disposition parameter) "Return PARAMETER value of CONTENT-DISPOSITION." - (cdr (assoc parameter (cdr content-disposition)))) + (mime-parameter-value (assoc parameter (cdr content-disposition)))) (defsubst mime-content-disposition-filename (content-disposition) "Return filename of CONTENT-DISPOSITION." @@ -177,49 +308,92 @@ ;;; @ 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 (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 @@ -231,12 +405,7 @@ Please use reference function `mime-entity-SLOT' to get value of SLOT. 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) @@ -248,6 +417,124 @@ message/rfc822, `mime-entity' structures of them are included in (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 (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))) + (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 ;;;