Sync up with flim-1_3_0 to flim-1_8_1.
[elisp/flim.git] / eword-decode.el
index 9b87b82..fa07ab1 100644 (file)
@@ -32,7 +32,7 @@
 
 ;;; Code:
 
-(require 'std11-parse)
+(require 'std11)
 (require 'mel)
 (require 'mime-def)
 
@@ -82,7 +82,7 @@ however this behaviour violates RFC2047."
   (concat eword-encoded-word-prefix-regexp
          "\\(" eword-encoded-text-in-phrase-regexp "\\)"
          eword-encoded-word-suffix-regexp))
-(defconst eword-after-encoded-word-in-phrase-regexp "\\([ \t(]\\|$\\)")
+(defconst eword-after-encoded-word-in-phrase-regexp "\\([ \t]\\|$\\)")
 
 (defconst eword-encoded-text-in-comment-regexp "[]!-'*->@-[^-~]+")
 (defconst eword-encoded-word-in-comment-regexp
@@ -129,11 +129,6 @@ however this behaviour violates RFC2047."
 ;;; @@ Quoted-Printable
 ;;;
 
-(defconst quoted-printable-hex-chars "0123456789ABCDEF")
-(defconst quoted-printable-octet-regexp
-  (concat "=[" quoted-printable-hex-chars
-         "][" quoted-printable-hex-chars "]"))
-
 (defconst eword-Q-encoded-text-regexp
   (concat "\\([^=?]\\|" quoted-printable-octet-regexp "\\)+"))
 ;; (defconst eword-Q-encoding-and-encoded-text-regexp
@@ -163,7 +158,7 @@ eword-after-encoded-text-in-phrase-regexp,
 eword-after-encoded-word-in-comment-regexp or
 eword-after-encoded-word-in-quoted-string-regexp.
 
-If beginning of STRING matches EWORD-REGEXP and AFTER-REGEXP,
+If beginning of STRING matches EWORD-REGEXP with AFTER-REGEXP,
 returns a cons cell of decoded string(sequence of characters) and 
 the rest(sequence of octets).
 
@@ -178,14 +173,19 @@ 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 eword-decode-sticked-encoded-word (setq after-regexp ""))
-  (let ((between-ewords-regexp
-         (if eword-decode-sticked-encoded-word
-           "\\(\n?[ \t]\\)*"
-           "\\(\n?[ \t]\\)+"))
-       (src string)    ; sequence of octets.
-       (dst ""))       ; sequence of characters.
-    (if (string-match
-         (concat "\\`\\(" eword-regexp "\\)" after-regexp) src)
+  (let* ((between-ewords-regexp
+          (if eword-decode-sticked-encoded-word
+            "\\(\n?[ \t]\\)*"
+            "\\(\n?[ \t]\\)+"))
+        (between-ewords-eword-after-regexp
+          (concat "\\`\\(" between-ewords-regexp "\\)"
+                     "\\(" eword-regexp "\\)"
+                     after-regexp))
+        (eword-after-regexp
+          (concat "\\`\\(" eword-regexp "\\)" after-regexp))
+        (src string)   ; sequence of octets.
+        (dst ""))      ; sequence of characters.
+    (if (string-match eword-after-regexp src)
       (let* (p
             (q (match-end 1))
             (ew (substring src 0 q))
@@ -196,11 +196,7 @@ such as a version of Net$cape)."
          (progn
            (while
              (and
-               (string-match
-                 (concat "\\`\\(" between-ewords-regexp "\\)"
-                            "\\(" eword-regexp "\\)"
-                            after-regexp)
-                 src)
+               (string-match between-ewords-eword-after-regexp src)
                (progn
                  (setq p (match-end 1)
                        q (match-end 3)
@@ -223,9 +219,13 @@ such as a version of Net$cape)."
                                   safe-regexp
                                   escape ; ?\\ or nil.
                                   delimiters ; list of chars.
-                                  default-charset
-                                  must-unfold)
-  (let ((dst "")
+                                  must-unfold
+                                  code-conversion)
+  (if (and code-conversion
+          (not (mime-charset-to-coding-system code-conversion)))
+      (setq code-conversion default-mime-charset))
+  (let ((equal-safe-regexp (concat "\\`=?" safe-regexp))
+       (dst "")
        (buf "")
        (src string)
        (ew-enable t))
@@ -239,7 +239,7 @@ such as a version of Net$cape)."
                 (or decoded (memq ch delimiters)))
          (setq dst (concat dst
                      (std11-wrap-as-quoted-pairs
-                       (decode-mime-charset-string buf default-charset)
+                       (decode-mime-charset-string buf code-conversion)
                        delimiters))
                buf ""))
        (cond
@@ -261,7 +261,7 @@ such as a version of Net$cape)."
            (setq buf (concat buf (substring src 0 (match-end 0)))
                  src (substring src (match-end 0))
                  ew-enable t))
-         ((and (string-match (concat "\\`=?" safe-regexp) src)
+         ((and (string-match equal-safe-regexp src)
                (< 0 (match-end 0)))
            (setq buf (concat buf (substring src 0 (match-end 0)))
                  src (substring src (match-end 0))
@@ -270,7 +270,7 @@ such as a version of Net$cape)."
     (if (not (string= buf ""))
       (setq dst (concat dst
                  (std11-wrap-as-quoted-pairs
-                   (decode-mime-charset-string buf default-charset)
+                   (decode-mime-charset-string buf code-conversion)
                    delimiters))))
     dst))
 
@@ -278,7 +278,7 @@ such as a version of Net$cape)."
 ;;; @ for string
 ;;;
 
-(defun eword-decode-unstructured (string &optional must-unfold)
+(defun eword-decode-unstructured (string code-conversion &optional must-unfold)
   (eword-decode-entire-string
     string
     eword-encoded-word-in-unstructured-regexp
@@ -286,10 +286,10 @@ such as a version of Net$cape)."
     "[^ \t\n=]*"
     nil
     nil
-    default-mime-charset
-    must-unfold))
+    must-unfold
+    code-conversion))
 
-(defun eword-decode-comment (string &optional must-unfold)
+(defun eword-decode-comment (string code-conversion &optional must-unfold)
   (eword-decode-entire-string
     string
     eword-encoded-word-in-comment-regexp
@@ -297,10 +297,10 @@ such as a version of Net$cape)."
     "[^ \t\n()\\\\=]*"
     ?\\
     '(?\( ?\))
-    default-mime-charset
-    must-unfold))
+    must-unfold
+    code-conversion))
 
-(defun eword-decode-quoted-string (string &optional must-unfold)
+(defun eword-decode-quoted-string (string code-conversion &optional must-unfold)
   (eword-decode-entire-string
     string
     eword-encoded-word-in-quoted-string-regexp
@@ -308,10 +308,10 @@ such as a version of Net$cape)."
     "[^ \t\n\"\\\\=]*"
     ?\\
     '(?\")
-    default-mime-charset
-    must-unfold))
+    must-unfold
+    code-conversion))
 
-(defun eword-decode-string (string &optional must-unfold default-mime-charset)
+(defun eword-decode-string (string &optional must-unfold code-conversion)
   "Decode MIME encoded-words in STRING.
 
 STRING is unfolded before decoding.
@@ -321,9 +321,15 @@ 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)."
+such as a version of Net$cape).
+
+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."
   (eword-decode-unstructured
     (std11-unfold-string string)
+    code-conversion
     must-unfold))
 
 
@@ -331,14 +337,19 @@ such as a version of Net$cape)."
 ;;;
 
 (defun eword-decode-region (start end &optional unfolding must-unfold
-                                               default-mime-charset)
+                                               code-conversion)
   "Decode MIME encoded-words in region between START and END.
 
 If UNFOLDING is not nil, it unfolds before decoding.
 
 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)."
+such as a version of Net$cape).
+
+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."
   (interactive "*r")
   (save-excursion
     (save-restriction
@@ -348,6 +359,7 @@ such as a version of Net$cape)."
        )
       (let ((str (eword-decode-unstructured
                   (buffer-substring (point-min) (point-max))
+                  code-conversion
                   must-unfold)))
        (delete-region (point-min) (point-max))
        (insert str)))))
@@ -357,17 +369,17 @@ such as a version of Net$cape)."
 ;;;
 
 (defcustom eword-decode-ignored-field-list
-  '(newsgroups path lines nntp-posting-host message-id date)
+  '(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
-            mime-version content-type content-transfer-encoding
-            content-disposition)
+  '(Reply-To Resent-Reply-To From Resent-From Sender Resent-Sender
+            To Resent-To Cc Resent-Cc Bcc Resent-Bcc Dcc
+            Mime-Version Content-Type Content-Transfer-Encoding
+            Content-Disposition)
   "*List of field-names to decode as structured field.
 Each field name must be symbol."
   :group 'eword-decode
@@ -395,7 +407,7 @@ If SEPARATOR is not nil, it is used as header separator."
                    p (match-end 0)
                    field-name (buffer-substring beg (1- p))
                    len (string-width field-name)
-                   field-name (intern (downcase field-name))
+                   field-name (intern (capitalize field-name))
                    end (std11-field-end))
              (cond ((memq field-name eword-decode-ignored-field-list)
                     ;; Don't decode
@@ -416,7 +428,7 @@ If SEPARATOR is not nil, it is used as header separator."
                         code-conversion)
                       (goto-char (point-max))
                       )))))
-       (eword-decode-region (point-min) (point-max) t nil code-conversion)
+       (eword-decode-region (point-min) (point-max) t nil nil)
        ))))
 
 (defun eword-decode-unfold ()
@@ -440,7 +452,18 @@ If SEPARATOR is not nil, it is used as header separator."
 ;;; @ encoded-word decoder
 ;;;
 
-(defvar eword-warning-face nil "Face used for invalid encoded-word.")
+(defvar eword-decode-encoded-word-error-handler
+  'eword-decode-encoded-word-default-error-handler)
+
+(defvar eword-warning-face nil
+  "Face used for invalid encoded-word.")
+
+(defun eword-decode-encoded-word-default-error-handler (word signal)
+  (and (add-text-properties 0 (length word)
+                           (and eword-warning-face
+                                (list 'face eword-warning-face))
+                           word)
+       word))
 
 (defun eword-decode-encoded-word (word &optional must-unfold)
   "Decode WORD if it is an encoded-word.
@@ -465,12 +488,8 @@ as a version of Net$cape)."
             (condition-case err
                 (eword-decode-encoded-text charset encoding text must-unfold)
               (error
-               (and
-               (add-text-properties 0 (length word)
-                                    (and eword-warning-face
-                                         (list 'face eword-warning-face))
-                                    word)
-               word)))
+              (funcall eword-decode-encoded-word-error-handler word err)
+               ))
             ))
       word))
 
@@ -508,21 +527,18 @@ as a version of Net$cape)."
                  (error "Invalid encoding %s" encoding)
                  )))
               )
-         (if dest
-             (progn
-               (setq dest (decode-coding-string dest cs))
-               (if must-unfold
-                   (mapconcat (function
-                               (lambda (chr)
-                                 (cond
-                                   ((eq chr ?\n) "")
-                                   ((eq chr ?\t) " ")
-                                   (t (char-to-string chr)))
-                                 ))
-                              (std11-unfold-string dest)
-                              "")
-                 dest)
-               ))))))
+         (when dest
+           (setq dest (decode-mime-charset-string dest charset))
+           (if must-unfold
+               (mapconcat (function
+                           (lambda (chr)
+                             (cond ((eq chr ?\n) "")
+                                   ((eq chr ?\t) " ")
+                                   (t (char-to-string chr)))
+                             ))
+                          (std11-unfold-string dest)
+                          "")
+             dest))))))
 
 
 ;;; @ lexical analyze
@@ -560,9 +576,15 @@ be the result."
   (let ((p (std11-check-enclosure string ?\" ?\")))
     (if p
        (cons (cons 'quoted-string
-                   (eword-decode-quoted-string (substring string 0 p)))
-             (substring string p))
-      )))
+                   (if eword-decode-quoted-encoded-word
+                       (eword-decode-quoted-string
+                        (substring string 0 p)
+                        default-mime-charset)
+                     (decode-mime-charset-string
+                      (std11-strip-quoted-pair (substring string 0 p))
+                      default-mime-charset)))
+             (substring string p)))
+      ))
 
 (defun eword-analyze-domain-literal (string &optional must-unfold)
   (std11-analyze-domain-literal string))
@@ -575,7 +597,9 @@ be the result."
            (setq p (std11-check-enclosure string ?\( ?\) t p)))
          (setq p (or p len))
          (cons (cons 'comment
-                     (eword-decode-comment (substring string 0 p)))
+                     (eword-decode-comment
+                       (std11-unfold-string (substring string 0 p))
+                       default-mime-charset))
                (substring string p)))
       nil)))