From: morioka Date: Sat, 22 Feb 1997 16:57:58 +0000 (+0000) Subject: *** empty log message *** X-Git-Tag: Hokutetsu-Ishikawa-new~339 X-Git-Url: http://git.chise.org/gitweb/?a=commitdiff_plain;h=002173811eab6ff693bf0260071ba495e8109638;p=elisp%2Fsemi.git *** empty log message *** --- diff --git a/eword-encode.el b/eword-encode.el new file mode 100644 index 0000000..890cc21 --- /dev/null +++ b/eword-encode.el @@ -0,0 +1,625 @@ +;;; eword-encode.el --- RFC 2047 based encoded-word encoder for GNU Emacs + +;; Copyright (C) 1995,1996,1997 Free Software Foundation, Inc. + +;; Author: MORIOKA Tomohiko +;; Version: $Revision: 0.0 $ +;; Keywords: encoded-word, MIME, multilingual, header, mail, news + +;; This file is part of SEMI (SEMI is Emacs MIME Interfaces). + +;; This program is free software; you can redistribute it and/or +;; modify it under the terms of the GNU General Public License as +;; published by the Free Software Foundation; either version 2, or (at +;; your option) any later version. + +;; This program is distributed in the hope that it will be useful, but +;; WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Code: + +(require 'mel) +(require 'std11) +(require 'mime-def) +(require 'tl-list) + + +;;; @ version +;;; + +(defconst eword-encode-RCS-ID + "$Id: eword-encode.el,v 0.0 1997-02-22 16:57:58 morioka Exp $") +(defconst eword-encode-version (get-version-string eword-encode-RCS-ID)) + + +;;; @ variables +;;; + +(defvar mime/field-encoding-method-alist + (if (boundp 'mime/no-encoding-header-fields) + (nconc + (mapcar (function + (lambda (field-name) + (cons field-name 'default-mime-charset) + )) + mime/no-encoding-header-fields) + '((t . mime)) + ) + '(("X-Nsubject" . iso-2022-jp-2) + ("Newsgroups" . nil) + (t . mime) + )) + "*Alist to specify field encoding method. +Its key is field-name, value is encoding method. + +If method is `mime', this field will be encoded into MIME format. + +If method is a MIME-charset, this field will be encoded as the charset +when it must be convert into network-code. + +If method is `default-mime-charset', this field will be encoded as +variable `default-mime-charset' when it must be convert into +network-code. + +If method is nil, this field will not be encoded.") + +(defvar mime/generate-X-Nsubject + (and (boundp 'mime/use-X-Nsubject) + mime/use-X-Nsubject) + "*If it is not nil, X-Nsubject field is generated +when Subject field is encoded by `eword-encode-message-header'.") + +(defvar eword-charset-encoding-alist + '((us-ascii . nil) + (iso-8859-1 . "Q") + (iso-8859-2 . "Q") + (iso-8859-3 . "Q") + (iso-8859-4 . "Q") + (iso-8859-5 . "Q") + (koi8-r . "Q") + (iso-8859-7 . "Q") + (iso-8859-8 . "Q") + (iso-8859-9 . "Q") + (iso-2022-jp . "B") + (iso-2022-kr . "B") + (gb2312 . "B") + (cn-gb . "B") + (cn-gb-2312 . "B") + (euc-kr . "B") + (iso-2022-jp-2 . "B") + (iso-2022-int-1 . "B") + )) + + +;;; @ encoded-text encoder +;;; + +(defun tm-eword::encode-encoded-text (charset encoding string &optional mode) + (let ((text + (cond ((string= encoding "B") + (base64-encode-string string)) + ((string= encoding "Q") + (q-encoding-encode-string string mode)) + ) + )) + (if text + (concat "=?" (upcase (symbol-name charset)) "?" + encoding "?" text "?=") + ))) + + +;;; @ leading char +;;; + +(defun tm-eword::char-type (chr) + (if (or (= chr 32)(= chr ?\t)) + nil + (char-charset chr) + )) + +(defun tm-eword::parse-lc-word (str) + (let* ((chr (sref str 0)) + (lc (tm-eword::char-type chr)) + (i (char-length chr)) + (len (length str)) + ) + (while (and (< i len) + (setq chr (sref str i)) + (eq lc (tm-eword::char-type chr)) + ) + (setq i (+ i (char-length chr))) + ) + (cons (cons lc (substring str 0 i)) (substring str i)) + )) + +(defun tm-eword::split-to-lc-words (str) + (let (ret dest) + (while (and (not (string= str "")) + (setq ret (tm-eword::parse-lc-word str)) + ) + (setq dest (cons (car ret) dest)) + (setq str (cdr ret)) + ) + (reverse dest) + )) + + +;;; @ word +;;; + +(defun tm-eword::parse-word (lcwl) + (let* ((lcw (car lcwl)) + (lc (car lcw)) + ) + (if (null lc) + lcwl + (let ((lcl (list lc)) + (str (cdr lcw)) + ) + (catch 'tag + (while (setq lcwl (cdr lcwl)) + (setq lcw (car lcwl)) + (setq lc (car lcw)) + (if (null lc) + (throw 'tag nil) + ) + (if (not (memq lc lcl)) + (setq lcl (cons lc lcl)) + ) + (setq str (concat str (cdr lcw))) + )) + (cons (cons lcl str) lcwl) + )))) + +(defun tm-eword::lc-words-to-words (lcwl) + (let (ret dest) + (while (setq ret (tm-eword::parse-word lcwl)) + (setq dest (cons (car ret) dest)) + (setq lcwl (cdr ret)) + ) + (reverse dest) + )) + + +;;; @ rule +;;; + +(defmacro tm-eword::make-rword (text charset encoding type) + (` (list (, text)(, charset)(, encoding)(, type)))) +(defmacro tm-eword::rword-text (rword) + (` (car (, rword)))) +(defmacro tm-eword::rword-charset (rword) + (` (car (cdr (, rword))))) +(defmacro tm-eword::rword-encoding (rword) + (` (car (cdr (cdr (, rword)))))) +(defmacro tm-eword::rword-type (rword) + (` (car (cdr (cdr (cdr (, rword))))))) + +(defun tm-eword::find-charset-rule (charsets) + (if charsets + (let* ((charset (charsets-to-mime-charset charsets)) + (encoding (cdr (assq charset eword-charset-encoding-alist))) + ) + (list charset encoding) + ))) + +(defun tm-eword::words-to-ruled-words (wl &optional mode) + (mapcar (function + (lambda (word) + (let ((ret (tm-eword::find-charset-rule (car word)))) + (tm-eword::make-rword (cdr word) (car ret)(nth 1 ret) mode) + ))) + wl)) + +(defun tm-eword::space-process (seq) + (let (prev a ac b c cc) + (while seq + (setq b (car seq)) + (setq seq (cdr seq)) + (setq c (car seq)) + (setq cc (tm-eword::rword-charset c)) + (if (null (tm-eword::rword-charset b)) + (progn + (setq a (car prev)) + (setq ac (tm-eword::rword-charset a)) + (if (and (tm-eword::rword-encoding a) + (tm-eword::rword-encoding c)) + (cond ((eq ac cc) + (setq prev (cons + (cons (concat (car a)(car b)(car c)) + (cdr a)) + (cdr prev) + )) + (setq seq (cdr seq)) + ) + (t + (setq prev (cons + (cons (concat (car a)(car b)) + (cdr a)) + (cdr prev) + )) + )) + (setq prev (cons b prev)) + )) + (setq prev (cons b prev)) + )) + (reverse prev) + )) + +(defun tm-eword::split-string (str &optional mode) + (tm-eword::space-process + (tm-eword::words-to-ruled-words (tm-eword::lc-words-to-words + (tm-eword::split-to-lc-words str)) + mode))) + + +;;; @ length +;;; + +(defun tm-eword::encoded-word-length (rword) + (let ((string (tm-eword::rword-text rword)) + (charset (tm-eword::rword-charset rword)) + (encoding (tm-eword::rword-encoding rword)) + ret) + (setq ret + (cond ((string-equal encoding "B") + (setq string (encode-mime-charset-string string charset)) + (base64-encoded-length string) + ) + ((string-equal encoding "Q") + (setq string (encode-mime-charset-string string charset)) + (q-encoding-encoded-length string + (tm-eword::rword-type rword)) + ))) + (if ret + (cons (+ 7 (length (symbol-name charset)) ret) string) + ))) + + +;;; @ encode-string +;;; + +(defun tm-eword::encode-string-1 (column rwl) + (let* ((rword (car rwl)) + (ret (tm-eword::encoded-word-length rword)) + string len) + (if (null ret) + (cond ((and (setq string (car rword)) + (<= (setq len (+ (length string) column)) 76) + ) + (setq rwl (cdr rwl)) + ) + (t + (setq string "\n ") + (setq len 1) + )) + (cond ((and (setq len (car ret)) + (<= (+ column len) 76) + ) + (setq string + (tm-eword::encode-encoded-text + (tm-eword::rword-charset rword) + (tm-eword::rword-encoding rword) + (cdr ret) + (tm-eword::rword-type rword) + )) + (setq len (+ (length string) column)) + (setq rwl (cdr rwl)) + ) + (t + (setq string (car rword)) + (let* ((p 0) np + (str "") nstr) + (while (and (< p len) + (progn + (setq np (+ p (char-length (sref string p)))) + (setq nstr (substring string 0 np)) + (setq ret (tm-eword::encoded-word-length + (cons nstr (cdr rword)) + )) + (setq nstr (cdr ret)) + (setq len (+ (car ret) column)) + (<= len 76) + )) + (setq str nstr + p np)) + (if (string-equal str "") + (setq string "\n " + len 1) + (setq rwl (cons (cons (substring string p) (cdr rword)) + (cdr rwl))) + (setq string + (tm-eword::encode-encoded-text + (tm-eword::rword-charset rword) + (tm-eword::rword-encoding rword) + str + (tm-eword::rword-type rword))) + (setq len (+ (length string) column)) + ) + ))) + ) + (list string len rwl) + )) + +(defun tm-eword::encode-rwl (column rwl) + (let (ret dest ps special str ew-f pew-f) + (while rwl + (setq ew-f (nth 2 (car rwl))) + (if (and pew-f ew-f) + (setq rwl (cons '(" ") rwl) + pew-f nil) + (setq pew-f ew-f) + ) + (setq ret (tm-eword::encode-string-1 column rwl)) + (setq str (car ret)) + (if (eq (elt str 0) ?\n) + (if (eq special ?\() + (progn + (setq dest (concat dest "\n (")) + (setq ret (tm-eword::encode-string-1 2 rwl)) + (setq str (car ret)) + )) + (cond ((eq special 32) + (if (string= str "(") + (setq ps t) + (setq dest (concat dest " ")) + (setq ps nil) + )) + ((eq special ?\() + (if ps + (progn + (setq dest (concat dest " (")) + (setq ps nil) + ) + (setq dest (concat dest "(")) + ) + ))) + (cond ((string= str " ") + (setq special 32) + ) + ((string= str "(") + (setq special ?\() + ) + (t + (setq special nil) + (setq dest (concat dest str)) + )) + (setq column (nth 1 ret) + rwl (nth 2 ret)) + ) + (list dest column) + )) + +(defun tm-eword::encode-string (column str &optional mode) + (tm-eword::encode-rwl column (tm-eword::split-string str mode)) + ) + + +;;; @ converter +;;; + +(defun tm-eword::phrase-to-rwl (phrase) + (let (token type dest str) + (while phrase + (setq token (car phrase)) + (setq type (car token)) + (cond ((eq type 'quoted-string) + (setq str (concat "\"" (cdr token) "\"")) + (setq dest + (append dest + (list + (let ((ret (tm-eword::find-charset-rule + (find-non-ascii-charset-string str)))) + (tm-eword::make-rword + str (car ret)(nth 1 ret) 'phrase) + ) + ))) + ) + ((eq type 'comment) + (setq dest + (append dest + '(("(" nil nil)) + (tm-eword::words-to-ruled-words + (tm-eword::lc-words-to-words + (tm-eword::split-to-lc-words (cdr token))) + 'comment) + '((")" nil nil)) + )) + ) + (t + (setq dest (append dest + (tm-eword::words-to-ruled-words + (tm-eword::lc-words-to-words + (tm-eword::split-to-lc-words (cdr token)) + ) 'phrase))) + )) + (setq phrase (cdr phrase)) + ) + (tm-eword::space-process dest) + )) + +(defun tm-eword::phrase-route-addr-to-rwl (phrase-route-addr) + (if (eq (car phrase-route-addr) 'phrase-route-addr) + (let ((phrase (nth 1 phrase-route-addr)) + (route (nth 2 phrase-route-addr)) + dest) + (if (eq (car (car phrase)) 'spaces) + (setq phrase (cdr phrase)) + ) + (setq dest (tm-eword::phrase-to-rwl phrase)) + (if dest + (setq dest (append dest '((" " nil nil)))) + ) + (append + dest + (list (list (concat "<" (std11-addr-to-string route) ">") nil nil)) + )))) + +(defun tm-eword::addr-spec-to-rwl (addr-spec) + (if (eq (car addr-spec) 'addr-spec) + (list (list (std11-addr-to-string (cdr addr-spec)) nil nil)) + )) + +(defun tm-eword::mailbox-to-rwl (mbox) + (let ((addr (nth 1 mbox)) + (comment (nth 2 mbox)) + dest) + (setq dest (or (tm-eword::phrase-route-addr-to-rwl addr) + (tm-eword::addr-spec-to-rwl addr) + )) + (if comment + (setq dest + (append dest + '((" " nil nil) + ("(" nil nil)) + (tm-eword::split-string comment 'comment) + '((")" nil nil)) + ))) + dest)) + +(defun tm-eword::addresses-to-rwl (addresses) + (let ((dest (tm-eword::mailbox-to-rwl (car addresses)))) + (if dest + (while (setq addresses (cdr addresses)) + (setq dest (append dest + '(("," nil nil)) + '((" " nil nil)) + (tm-eword::mailbox-to-rwl (car addresses)) + )) + )) + dest)) + +(defun tm-eword::encode-address-list (column str) + (tm-eword::encode-rwl + column + (tm-eword::addresses-to-rwl (std11-parse-addresses-string str)) + )) + + +;;; @ application interfaces +;;; + +(defun eword-encode-field (str) + (setq str (std11-unfold-string str)) + (let ((ret (string-match std11-field-head-regexp str))) + (or (if ret + (let ((field-name (substring str 0 (1- (match-end 0)))) + (field-body (eliminate-top-spaces + (substring str (match-end 0)))) + fname) + (if (setq ret + (cond ((string-equal field-body "") "") + ((member (setq fname (downcase field-name)) + '("reply-to" "from" "sender" + "resent-reply-to" "resent-from" + "resent-sender" "to" "resent-to" + "cc" "resent-cc" + "bcc" "resent-bcc" "dcc") + ) + (car (tm-eword::encode-address-list + (+ (length field-name) 2) field-body)) + ) + (t + (car (tm-eword::encode-string + (+ (length field-name) 1) + field-body 'text)) + )) + ) + (concat field-name ": " ret) + ))) + (car (tm-eword::encode-string 0 str)) + ))) + +(defun mime/exist-encoded-word-in-subject () + (let ((str (std11-field-body "Subject"))) + (if (and str (string-match mime/encoded-word-regexp str)) + str))) + +(defun eword-encode-message-header (&optional code-conversion) + (interactive "*") + (save-excursion + (save-restriction + (std11-narrow-to-header mail-header-separator) + (goto-char (point-min)) + (let ((default-cs (mime-charset-to-coding-system default-mime-charset)) + beg end field-name) + (while (re-search-forward std11-field-head-regexp nil t) + (setq beg (match-beginning 0)) + (setq field-name (buffer-substring beg (1- (match-end 0)))) + (setq end (std11-field-end)) + (and (find-non-ascii-charset-region beg end) + (let ((ret (or (ASSOC (downcase field-name) + mime/field-encoding-method-alist + :test (function + (lambda (str1 str2) + (and (stringp str2) + (string= str1 + (downcase str2)) + )))) + (assq t mime/field-encoding-method-alist) + ))) + (if ret + (let ((method (cdr ret))) + (cond ((eq method 'mime) + (let ((field + (buffer-substring-no-properties beg end) + )) + (delete-region beg end) + (insert (eword-encode-field field)) + )) + (code-conversion + (let ((cs + (or (mime-charset-to-coding-system + method) + default-cs))) + (encode-coding-region beg end cs) + ))) + )) + )) + )) + (and mime/generate-X-Nsubject + (or (std11-field-body "X-Nsubject") + (let ((str (mime/exist-encoded-word-in-subject))) + (if str + (progn + (setq str + (eword-decode-string + (std11-unfold-string str))) + (if code-conversion + (setq str + (encode-mime-charset-string + str + (or (cdr (ASSOC + "x-nsubject" + mime/field-encoding-method-alist + :test + (function + (lambda (str1 str2) + (and (stringp str2) + (string= str1 + (downcase str2)) + ))))) + 'iso-2022-jp-2))) + ) + (insert (concat "\nX-Nsubject: " str)) + ))))) + ))) + +(defun eword-encode-string (str &optional column mode) + (car (tm-eword::encode-rwl (or column 0) (tm-eword::split-string str mode))) + ) + + +;;; @ end +;;; + +(provide 'eword-encode) + +;;; eword-encode.el ends here