+1998-11-10 Tanaka Akira <akr@jaist.ac.jp>
+
+ * FLIM-ELS: require 'pccl.
+ (flim-modules): Check CCL availability by broken facility.
+
+1998-11-08 MORIOKA Tomohiko <morioka@jaist.ac.jp>
+
+ * eword-decode.el (eword-decode-structured-field-body): New
+ implementation; abolish optional argument `must-unfold'; delete
+ DOC-string.
+ (eword-decode-and-unfold-structured-field-body): Renamed from
+ `eword-decode-and-unfold-structured-field'; delete DOC-string.
+ (eword-decode-and-fold-structured-field-body): Renamed from
+ `eword-decode-and-fold-structured-field'; abolish optional
+ argument `must-unfold'; delete DOC-string.
+ (eword-decode-unstructured-field-body): Abolish optional argument
+ `must-unfold'; delete DOC-string.
+ (eword-decode-and-unfold-unstructured-field-body): Renamed from
+ `eword-decode-and-unfold-unstructured-field'; delete DOC-string.
+ (eword-decode-unfolded-unstructured-field-body): New function.
+
+1998-11-08 MORIOKA Tomohiko <morioka@jaist.ac.jp>
+
+ * mmgeneric.el (mime-insert-header-from-buffer): Use
+ `mime-find-field-presentation-method' and
+ `mime-find-field-decoder-internal'.
+
+ * eword-decode.el (mime-find-field-presentation-method): New
+ macro.
+ (mime-find-field-decoder-internal): New function.
+ (mime-find-field-decoder): New implementation (use
+ mime-find-field-decoder-internal).
+ (mime-decode-header-in-region): Use
+ `mime-find-field-presentation-method' and
+ `mime-find-field-decoder-internal'.
+
+1998-11-08 MORIOKA Tomohiko <morioka@jaist.ac.jp>
+
+ * mmgeneric.el (mime-insert-header-from-buffer): Rename
+ field-presentation-mode `folding' to `wide'.
+
+ * eword-decode.el: Rename field-presentation-modes from `native',
+ `folding', `unfolding', `unfolding-xover' to `plain', `wide',
+ `summary', `nov'.
+
+1998-11-07 Tanaka Akira <akr@jaist.ac.jp>
+
+ * eword-decode.el (mime-set-field-decoder): Add mode `unfolding-xover'.
+ (mime-find-field-decoder): Ditto.
+
+1998-11-04 MORIOKA Tomohiko <morioka@jaist.ac.jp>
+
+ * eword-encode.el (eword-encode-phrase-route-addr-to-rword-list):
+ Don't delete the front spaces.
+ (eword-encode-addresses-to-rword-list): Don't supplement space;
+ use `nconc' instead of `append'.
+ (eword-encode-msg-id-to-rword-list): Supplement the front space;
+ use `nconc' instead of `append'.
+
+1998-11-02 Tanaka Akira <akr@jaist.ac.jp>
+
+ * eword-decode.el (mime-field-decoder-cache): New variable.
+ (mime-find-field-decoder): Use `mime-field-decoder-cache'.
+ (mime-update-field-decoder-cache): New variable.
+ (mime-update-field-decoder-cache): New function.
+ (mime-decode-header-in-region): Use `mime-field-decoder-cache'.
+
+ * mmgeneric.el (mime-insert-header-from-buffer): Use
+ `mime-field-decoder-cache'.
+
+1998-11-02 MORIOKA Tomohiko <morioka@jaist.ac.jp>
+
+ * eword-decode.el (mime-decode-header-in-region): New function.
+ (mime-decode-header-in-buffer): Use function
+ `mime-decode-header-in-region'.
+
+1998-10-28 MORIOKA Tomohiko <morioka@jaist.ac.jp>
+
+ * mmgeneric.el (mime-insert-header-from-buffer): Refer
+ `mime-field-decoder-alist' instead of hard-coding.
+
+ * mime.el (mime-read-field): Use `mime-decode-field-body'.
+
+ * eword-decode.el (eword-decode-and-unfold-structured-field): Add
+ optional dummy argument `start-column' and `max-column'.
+ (eword-decode-structured-field-body): Change interface.
+ (eword-decode-unstructured-field-body): Change interface to add
+ optional dummy argument `start-column' and `max-column'.
+ (eword-decode-and-unfold-unstructured-field): Add optional dummy
+ argument `start-column' and `max-column'.
+ (mime-field-decoder-alist): New variable; abolish user option
+ `eword-decode-ignored-field-list' and
+ `eword-decode-structured-field-list'.
+ (mime-set-field-decoder): New function.
+ (mime-find-field-decoder): New function.
+ (mime-decode-field-body): New function; abolish function
+ `eword-decode-field-body'.
+ (mime-decode-header-in-buffer): Renamed from
+ `eword-decode-header'; refer `mime-field-decoder-alist' instead of
+ hard-coding; add obsolete alias `eword-decode-header'.
+
1998-10-28 MORIOKA Tomohiko <morioka@jaist.ac.jp>
* mime-def.el: Avoid compile error when ediff is missing.
(require 'mel)
(require 'mime-def)
+(eval-when-compile (require 'cl))
+
(defgroup eword-decode nil
"Encoded-word decoding"
:group 'mime)
(concat dest string)
))
-(defun eword-decode-and-fold-structured-field
- (string start-column &optional max-column must-unfold)
- "Decode and fold (fill) STRING as structured field body.
+(defun eword-decode-structured-field-body (string
+ &optional start-column max-column)
+ (let ((tokens (eword-lexical-analyze string 'must-unfold))
+ (result ""))
+ (while tokens
+ (let* ((token (car tokens))
+ (type (car token)))
+ (setq tokens (cdr tokens))
+ (setq result
+ (concat result (eword-decode-token token)))
+ ))
+ result))
+
+(defun eword-decode-and-unfold-structured-field-body (string
+ &optional
+ start-column
+ max-column)
+ "Decode and unfold STRING as structured field body.
It decodes non us-ascii characters in FULL-NAME encoded as
encoded-words or invalid \"raw\" string. \"Raw\" non us-ascii
characters are regarded as variable `default-mime-charset'.
If an encoded-word is broken or your emacs implementation can not
-decode the charset included in it, it is not decoded.
-
-If MAX-COLUMN is omitted, `fill-column' is used.
+decode the charset included in it, it is not decoded."
+ (let ((tokens (eword-lexical-analyze string 'must-unfold))
+ (result ""))
+ (while tokens
+ (let* ((token (car tokens))
+ (type (car token)))
+ (setq tokens (cdr tokens))
+ (setq result
+ (if (eq type 'spaces)
+ (concat result " ")
+ (concat result (eword-decode-token token))
+ ))))
+ result))
-If MUST-UNFOLD is non-nil, it unfolds and eliminates line-breaks even
-if there are in decoded encoded-words (generated by bad manner MUA
-such as a version of Net$cape)."
+(defun eword-decode-and-fold-structured-field-body (string
+ start-column
+ &optional max-column)
(if (and eword-max-size-to-decode
(> (length string) eword-max-size-to-decode))
string
(or max-column
(setq max-column fill-column))
(let ((c start-column)
- (tokens (eword-lexical-analyze string must-unfold))
+ (tokens (eword-lexical-analyze string 'must-unfold))
(result "")
token)
(while (and (setq token (car tokens))
(concat result (eword-decode-token token))
result))))
-(defun eword-decode-and-unfold-structured-field (string)
- "Decode and unfold STRING as structured field body.
-It decodes non us-ascii characters in FULL-NAME encoded as
-encoded-words or invalid \"raw\" string. \"Raw\" non us-ascii
-characters are regarded as variable `default-mime-charset'.
-
-If an encoded-word is broken or your emacs implementation can not
-decode the charset included in it, it is not decoded."
- (let ((tokens (eword-lexical-analyze string 'must-unfold))
- (result ""))
- (while tokens
- (let* ((token (car tokens))
- (type (car token)))
- (setq tokens (cdr tokens))
- (setq result
- (if (eq type 'spaces)
- (concat result " ")
- (concat result (eword-decode-token token))
- ))))
- result))
-
-(defun eword-decode-structured-field-body (string &optional must-unfold
- start-column max-column)
- "Decode non us-ascii characters in STRING as structured field body.
-STRING is unfolded before decoding.
-
-It decodes non us-ascii characters in FULL-NAME encoded as
-encoded-words or invalid \"raw\" string. \"Raw\" non us-ascii
-characters are regarded as variable `default-mime-charset'.
-
-If an encoded-word is broken or your emacs implementation can not
-decode the charset included in it, it is not decoded.
-
-If MUST-UNFOLD is non-nil, it unfolds and eliminates line-breaks even
-if there are in decoded encoded-words (generated by bad manner MUA
-such as a version of Net$cape)."
- (if start-column
- ;; fold with max-column
- (eword-decode-and-fold-structured-field
- string start-column max-column must-unfold)
- ;; Don't fold
- (mapconcat (function eword-decode-token)
- (eword-lexical-analyze string must-unfold)
- "")
- ))
-
-(defun eword-decode-unstructured-field-body (string &optional must-unfold)
- "Decode non us-ascii characters in STRING as unstructured field body.
-STRING is unfolded before decoding.
-
-It decodes non us-ascii characters in FULL-NAME encoded as
-encoded-words or invalid \"raw\" string. \"Raw\" non us-ascii
-characters are regarded as variable `default-mime-charset'.
-
-If an encoded-word is broken or your emacs implementation can not
-decode the charset included in it, it is not decoded.
-
-If MUST-UNFOLD is non-nil, it unfolds and eliminates line-breaks even
-if there are in decoded encoded-words (generated by bad manner MUA
-such as a version of Net$cape)."
+(defun eword-decode-unstructured-field-body (string &optional start-column
+ max-column)
(eword-decode-string
- (decode-mime-charset-string string default-mime-charset)
- must-unfold))
-
-(defun eword-decode-and-unfold-unstructured-field (string)
- "Decode and unfold STRING as unstructured field body.
-It decodes non us-ascii characters in FULL-NAME encoded as
-encoded-words or invalid \"raw\" string. \"Raw\" non us-ascii
-characters are regarded as variable `default-mime-charset'.
+ (decode-mime-charset-string string default-mime-charset)))
-If an encoded-word is broken or your emacs implementation can not
-decode the charset included in it, it is not decoded."
+(defun eword-decode-and-unfold-unstructured-field-body (string
+ &optional start-column
+ max-column)
(eword-decode-string
(decode-mime-charset-string (std11-unfold-string string)
default-mime-charset)
'must-unfold))
+(defun eword-decode-unfolded-unstructured-field-body (string
+ &optional start-column
+ max-column)
+ (eword-decode-string
+ (decode-mime-charset-string string default-mime-charset)
+ 'must-unfold))
+
;;; @ for region
;;;
)
)))
+(defun eword-decode-unfold ()
+ (goto-char (point-min))
+ (let (field beg end)
+ (while (re-search-forward std11-field-head-regexp nil t)
+ (setq beg (match-beginning 0)
+ end (std11-field-end))
+ (setq field (buffer-substring beg end))
+ (if (string-match eword-encoded-word-regexp field)
+ (save-restriction
+ (narrow-to-region (goto-char beg) end)
+ (while (re-search-forward "\n\\([ \t]\\)" nil t)
+ (replace-match (match-string 1))
+ )
+ (goto-char (point-max))
+ ))
+ )))
+
;;; @ for message header
;;;
-(defcustom eword-decode-ignored-field-list
- '(Newsgroups Path Lines Nntp-Posting-Host Received Message-Id Date)
- "*List of field-names to be ignored when decoding.
-Each field name must be symbol."
- :group 'eword-decode
- :type '(repeat symbol))
-
-(defcustom eword-decode-structured-field-list
- '(Reply-To Resent-Reply-To From Resent-From Sender Resent-Sender
- To Resent-To Cc Resent-Cc Bcc Resent-Bcc Dcc
- Mail-Followup-To
- Mime-Version Content-Type Content-Transfer-Encoding
- Content-Disposition User-Agent)
- "*List of field-names to decode as structured field.
-Each field name must be symbol."
- :group 'eword-decode
- :type '(repeat symbol))
+(defvar mime-field-decoder-alist nil)
+
+(defvar mime-field-decoder-cache nil)
+
+(defvar mime-update-field-decoder-cache 'mime-update-field-decoder-cache
+ "*Field decoder cache update function.")
+
+;;;###autoload
+(defun mime-set-field-decoder (field &rest specs)
+ "Set decoder of FILED.
+SPECS must be like `MODE1 DECODER1 MODE2 DECODER2 ...'.
+Each mode must be `nil', `plain', `wide', `summary' or `nov'.
+If mode is `nil', corresponding decoder is set up for every modes."
+ (when specs
+ (let ((mode (pop specs))
+ (function (pop specs)))
+ (if mode
+ (progn
+ (let ((cell (assq mode mime-field-decoder-alist)))
+ (if cell
+ (setcdr cell (put-alist field function (cdr cell)))
+ (setq mime-field-decoder-alist
+ (cons (cons mode (list (cons field function)))
+ mime-field-decoder-alist))
+ ))
+ (apply (function mime-set-field-decoder) field specs)
+ )
+ (mime-set-field-decoder field
+ 'plain function
+ 'wide function
+ 'summary function
+ 'nov function)
+ ))))
+
+;;;###autoload
+(defmacro mime-find-field-presentation-method (name)
+ "Return field-presentation-method from NAME.
+NAME must be `plain', `wide', `summary' or `nov'."
+ (cond ((eq name nil)
+ `(or (assq 'summary mime-field-decoder-cache)
+ '(summary))
+ )
+ ((and (consp name)
+ (car name)
+ (consp (cdr name))
+ (symbolp (car (cdr name)))
+ (null (cdr (cdr name))))
+ `(or (assq ,name mime-field-decoder-cache)
+ (cons ,name nil))
+ )
+ (t
+ `(or (assq (or ,name 'summary) mime-field-decoder-cache)
+ (cons (or ,name 'summary) nil))
+ )))
+
+(defun mime-find-field-decoder-internal (field &optional mode)
+ "Return function to decode field-body of FIELD in MODE.
+Optional argument MODE must be object of field-presentation-method."
+ (cdr (or (assq field (cdr mode))
+ (prog1
+ (funcall mime-update-field-decoder-cache
+ field (car mode))
+ (setcdr mode
+ (cdr (assq (car mode) mime-field-decoder-cache)))
+ ))))
+
+;;;###autoload
+(defun mime-find-field-decoder (field &optional mode)
+ "Return function to decode field-body of FIELD in MODE.
+Optional argument MODE must be object or name of
+field-presentation-method. Name of field-presentation-method must be
+`plain', `wide', `summary' or `nov'.
+Default value of MODE is `summary'."
+ (if (symbolp mode)
+ (let ((p (cdr (mime-find-field-presentation-method mode))))
+ (if (and p (setq p (assq field p)))
+ (cdr p)
+ (cdr (funcall mime-update-field-decoder-cache
+ field (or mode 'summary)))))
+ (inline (mime-find-field-decoder-internal field mode))
+ ))
-(defun eword-decode-field-body
- (field-body field-name &optional unfolded max-column)
- "Decode FIELD-BODY as FIELD-NAME, and return the result.
+;;;###autoload
+(defun mime-update-field-decoder-cache (field mode &optional function)
+ "Update field decoder cache `mime-field-decoder-cache'."
+ (cond ((eq function 'identity)
+ (setq function nil)
+ )
+ ((null function)
+ (let ((decoder-alist
+ (cdr (assq (or mode 'summary) mime-field-decoder-alist))))
+ (setq function (cdr (or (assq field decoder-alist)
+ (assq t decoder-alist)))))
+ ))
+ (let ((cell (assq mode mime-field-decoder-cache))
+ ret)
+ (if cell
+ (if (setq ret (assq field (cdr cell)))
+ (setcdr ret function)
+ (setcdr cell (cons (setq ret (cons field function)) (cdr cell))))
+ (setq mime-field-decoder-cache
+ (cons (cons mode (list (setq ret (cons field function))))
+ mime-field-decoder-cache)))
+ ret))
+
+;; ignored fields
+(mime-set-field-decoder 'Archive nil nil)
+(mime-set-field-decoder 'Content-Md5 nil nil)
+(mime-set-field-decoder 'Control nil nil)
+(mime-set-field-decoder 'Date nil nil)
+(mime-set-field-decoder 'Distribution nil nil)
+(mime-set-field-decoder 'Followup-Host nil nil)
+(mime-set-field-decoder 'Followup-To nil nil)
+(mime-set-field-decoder 'Lines nil nil)
+(mime-set-field-decoder 'Message-Id nil nil)
+(mime-set-field-decoder 'Newsgroups nil nil)
+(mime-set-field-decoder 'Nntp-Posting-Host nil nil)
+(mime-set-field-decoder 'Path nil nil)
+(mime-set-field-decoder 'Posted-And-Mailed nil nil)
+(mime-set-field-decoder 'Received nil nil)
+(mime-set-field-decoder 'Status nil nil)
+(mime-set-field-decoder 'X-Face nil nil)
+(mime-set-field-decoder 'X-Face-Version nil nil)
+(mime-set-field-decoder 'X-Info nil nil)
+(mime-set-field-decoder 'X-Pgp-Key-Info nil nil)
+(mime-set-field-decoder 'X-Pgp-Sig nil nil)
+(mime-set-field-decoder 'X-Pgp-Sig-Version nil nil)
+(mime-set-field-decoder 'Xref nil nil)
+
+;; structured fields
+(let ((fields
+ '(Reply-To Resent-Reply-To From Resent-From Sender Resent-Sender
+ To Resent-To Cc Resent-Cc Bcc Resent-Bcc Dcc
+ Mail-Followup-To
+ Mime-Version Content-Type Content-Transfer-Encoding
+ Content-Disposition User-Agent))
+ field)
+ (while fields
+ (setq field (pop fields))
+ (mime-set-field-decoder
+ field
+ 'plain #'eword-decode-structured-field-body
+ 'wide #'eword-decode-and-fold-structured-field-body
+ 'summary #'eword-decode-and-unfold-structured-field-body
+ 'nov #'eword-decode-and-unfold-structured-field-body)
+ ))
-If UNFOLDED is non-nil, it is assumed that FIELD-BODY is
-already unfolded.
+;; unstructured fields (default)
+(mime-set-field-decoder
+ t
+ 'plain #'eword-decode-unstructured-field-body
+ 'wide #'eword-decode-unstructured-field-body
+ 'summary #'eword-decode-and-unfold-unstructured-field-body
+ 'nov #'eword-decode-unfolded-unstructured-field-body)
-If MAX-COLUMN is non-nil, the result is folded with MAX-COLUMN
-or `fill-column' if MAX-COLUMN is t.
-Otherwise, the result is unfolded.
+;;;###autoload
+(defun mime-decode-field-body (field-body field-name
+ &optional mode max-column)
+ "Decode FIELD-BODY as FIELD-NAME in MODE, and return the result.
+Optional argument MODE must be `plain', `wide', `summary' or `nov'.
+Default mode is `summary'.
-MIME encoded-word in FIELD-BODY is recognized according to
-`eword-decode-ignored-field-list',
-`eword-decode-structured-field-list' and FIELD-NAME.
+If MODE is `wide' and MAX-COLUMN is non-nil, the result is folded with
+MAX-COLUMN.
Non MIME encoded-word part in FILED-BODY is decoded with
`default-mime-charset'."
- (when (eq max-column t)
- (setq max-column fill-column))
- (let (field-name-symbol len)
+ (let (field-name-symbol len decoder)
(if (symbolp field-name)
(setq field-name-symbol field-name
len (1+ (string-width (symbol-name field-name))))
(setq field-name-symbol (intern (capitalize field-name))
len (1+ (string-width field-name))))
- (if (memq field-name-symbol eword-decode-ignored-field-list)
- ;; Don't decode
- (if max-column
- field-body
- (std11-unfold-string field-body))
- (if (memq field-name-symbol eword-decode-structured-field-list)
- ;; Decode as structured field
- (if max-column
- (eword-decode-and-fold-structured-field
- field-body len max-column t)
- (eword-decode-and-unfold-structured-field field-body))
- ;; Decode as unstructured field
- (if max-column
- (eword-decode-unstructured-field-body field-body len)
- (eword-decode-unstructured-field-body
- (std11-unfold-string field-body) len))))))
-
-(defun eword-decode-header (&optional code-conversion separator)
- "Decode MIME encoded-words in header fields.
+ (setq decoder (mime-find-field-decoder field-name-symbol mode))
+ (if decoder
+ (funcall decoder field-body len max-column)
+ ;; Don't decode
+ (if (eq mode 'summary)
+ (std11-unfold-string field-body)
+ field-body)
+ )))
+
+;;;###autoload
+(defun mime-decode-header-in-region (start end
+ &optional code-conversion)
+ "Decode MIME encoded-words in region between START and END.
If CODE-CONVERSION is nil, it decodes only encoded-words. If it is
mime-charset, it decodes non-ASCII bit patterns as the mime-charset.
Otherwise it decodes non-ASCII bit patterns as the
-default-mime-charset.
-If SEPARATOR is not nil, it is used as header separator."
- (interactive "*")
+default-mime-charset."
+ (interactive "*r")
(save-excursion
(save-restriction
- (std11-narrow-to-header separator)
+ (narrow-to-region start end)
(let ((default-charset
(if code-conversion
(if (mime-charset-to-coding-system code-conversion)
code-conversion
default-mime-charset))))
(if default-charset
- (let (beg p end field-name len)
+ (let ((mode-obj (mime-find-field-presentation-method 'wide))
+ beg p end field-name len field-decoder)
(goto-char (point-min))
(while (re-search-forward std11-field-head-regexp nil t)
(setq beg (match-beginning 0)
field-name (buffer-substring beg (1- p))
len (string-width field-name)
field-name (intern (capitalize field-name))
- end (std11-field-end))
- (cond ((memq field-name eword-decode-ignored-field-list)
- ;; Don't decode
- )
- ((memq field-name eword-decode-structured-field-list)
- ;; Decode as structured field
- (let ((body (buffer-substring p end))
- (default-mime-charset default-charset))
- (delete-region p end)
- (insert (eword-decode-and-fold-structured-field
- body (1+ len)))
- ))
- (t
- ;; Decode as unstructured field
- (save-restriction
- (narrow-to-region beg (1+ end))
- (decode-mime-charset-region p end default-charset)
- (goto-char p)
- (if (re-search-forward eword-encoded-word-regexp
- nil t)
- (eword-decode-region beg (point-max) 'unfold))
- )))))
+ field-decoder (inline
+ (mime-find-field-decoder-internal
+ field-name mode-obj)))
+ (when field-decoder
+ (setq end (std11-field-end))
+ (let ((body (buffer-substring p end))
+ (default-mime-charset default-charset))
+ (delete-region p end)
+ (insert (funcall field-decoder body (1+ len)))
+ ))
+ ))
(eword-decode-region (point-min) (point-max) t)
)))))
-(defun eword-decode-unfold ()
- (goto-char (point-min))
- (let (field beg end)
- (while (re-search-forward std11-field-head-regexp nil t)
- (setq beg (match-beginning 0)
- end (std11-field-end))
- (setq field (buffer-substring beg end))
- (if (string-match eword-encoded-word-regexp field)
- (save-restriction
- (narrow-to-region (goto-char beg) end)
- (while (re-search-forward "\n\\([ \t]\\)" nil t)
- (replace-match (match-string 1))
- )
- (goto-char (point-max))
- ))
- )))
+;;;###autoload
+(defun mime-decode-header-in-buffer (&optional code-conversion separator)
+ "Decode MIME encoded-words in header fields.
+If CODE-CONVERSION is nil, it decodes only encoded-words. If it is
+mime-charset, it decodes non-ASCII bit patterns as the mime-charset.
+Otherwise it decodes non-ASCII bit patterns as the
+default-mime-charset.
+If SEPARATOR is not nil, it is used as header separator."
+ (interactive "*")
+ (mime-decode-header-in-region
+ (point-min)
+ (save-excursion
+ (goto-char (point-min))
+ (if (re-search-forward
+ (concat "^\\(" (regexp-quote (or separator "")) "\\)?$")
+ nil t)
+ (match-beginning 0)
+ (point-max)
+ ))
+ code-conversion))
+
+(define-obsolete-function-alias 'eword-decode-header
+ 'mime-decode-header-in-buffer)
;;; @ encoded-word decoder