(rfc2231-parse-string): Decode encoded value after concatenating segments
[gnus] / lisp / mm-util.el
index 703973d..3dcca9b 100644 (file)
@@ -1,5 +1,6 @@
 ;;; mm-util.el --- Utility functions for Mule and low level things
-;; Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+;; Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004
+;;   Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;;     MORIOKA Tomohiko <morioka@jaist.ac.jp>
      (coding-system-list . ignore)
      (decode-coding-region . ignore)
      (char-int . identity)
-     (device-type . ignore)
      (coding-system-equal . equal)
      (annotationp . ignore)
      (set-buffer-file-coding-system . ignore)
-     (make-char
-      . (lambda (charset int)
-         (int-to-char int)))
      (read-charset
       . (lambda (prompt)
          "Return a charset."
                    mm-mime-mule-charset-alist)
            nil t))))
      (subst-char-in-string
-      . (lambda (from to string) ;; stolen (and renamed) from nnheader.el
-         "Replace characters in STRING from FROM to TO."
-         (let ((string (substring string 0)) ;Copy string.
+      . (lambda (from to string &optional inplace) ;; stolen (and renamed) from nnheader.el
+         "Replace characters in STRING from FROM to TO.
+         Unless optional argument INPLACE is non-nil, return a new string."
+         (let ((string (if inplace string (copy-sequence string)))
                (len (length string))
                (idx 0))
            ;; Replace all occurrences of FROM with TO.
                (aset string idx to))
              (setq idx (1+ idx)))
            string)))
+     (replace-in-string
+      . (lambda (string regexp rep &optional literal)
+         "See `replace-regexp-in-string', only the order of args differs."
+         (replace-regexp-in-string regexp rep string nil literal)))
      (string-as-unibyte . identity)
+     (string-make-unibyte . identity)
      (string-as-multibyte . identity)
-     (multibyte-string-p . ignore))))
+     (multibyte-string-p . ignore)
+     ;; It is not a MIME function, but some MIME functions use it.
+     (make-temp-file . (lambda (prefix &optional dir-flag)
+                        (let ((file (expand-file-name
+                                     (make-temp-name prefix)
+                                     (if (fboundp 'temp-directory)
+                                         (temp-directory)
+                                       temporary-file-directory))))
+                          (if dir-flag
+                              (make-directory file))
+                          file)))
+     (insert-byte . insert-char)
+     (multibyte-char-to-unibyte . identity))))
 
 (eval-and-compile
   (defalias 'mm-char-or-char-int-p
      ((fboundp 'char-valid-p) 'char-valid-p)
      (t 'identity))))
 
+;; Fixme:  This seems always to be used to read a MIME charset, so it
+;; should be re-named and fixed (in Emacs) to offer completion only on
+;; proper charset names (base coding systems which have a
+;; mime-charset defined).  XEmacs doesn't believe in mime-charset;
+;; test with
+;;   `(or (coding-system-get 'iso-8859-1 'mime-charset)
+;;        (coding-system-get 'iso-8859-1 :mime-charset))'
+;; Actually, there should be an `mm-coding-system-mime-charset'.
 (eval-and-compile
   (defalias 'mm-read-coding-system
     (cond
   (or mm-coding-system-list
       (setq mm-coding-system-list (mm-coding-system-list))))
 
-(defun mm-coding-system-p (sym)
-  "Return non-nil if SYM is a coding system."
-  (or (and (fboundp 'coding-system-p) (coding-system-p sym))
-      (memq sym (mm-get-coding-system-list))))
+(defun mm-coding-system-p (cs)
+  "Return non-nil if CS is a symbol naming a coding system.
+In XEmacs, also return non-nil if CS is a coding system object.
+If CS is available, return CS itself in Emacs, and return a coding
+system object in XEmacs."
+  (if (fboundp 'find-coding-system)
+      (find-coding-system cs)
+    (if (fboundp 'coding-system-p)
+       (when (coding-system-p cs)
+         cs)
+      ;; Is this branch ever actually useful?
+      (car (memq cs (mm-get-coding-system-list))))))
 
 (defvar mm-charset-synonym-alist
   `(
-    ;; Perfectly fine?  A valid MIME name, anyhow.
-    ,(unless (mm-coding-system-p 'big5)
-       '(big5 . cn-big5))
     ;; Not in XEmacs, but it's not a proper MIME charset anyhow.
-    ,(unless (mm-coding-system-p 'x-ctext)
-       '(x-ctext . ctext))
-    ;; Apparently not defined in Emacs 20, but is a valid MIME name.
-    ,(unless (mm-coding-system-p 'gb2312)
-       '(gb2312 . cn-gb-2312))
+    ,@(unless (mm-coding-system-p 'x-ctext)
+       '((x-ctext . ctext)))
+    ;; ISO-8859-15 is very similar to ISO-8859-1.  But it's _different_!
+    ,@(unless (mm-coding-system-p 'iso-8859-15)
+       '((iso-8859-15 . iso-8859-1)))
+    ;; BIG-5HKSCS is similar to, but different than, BIG-5.
+    ,@(unless (mm-coding-system-p 'big5-hkscs)
+       '((big5-hkscs . big5)))
     ;; Windows-1252 is actually a superset of Latin-1.  See also
     ;; `gnus-article-dumbquotes-map'.
-    ;;,(unless (mm-coding-system-p 'windows-1252)      
-                                       ; should be defined eventually
-    ;;  '(windows-1252 . iso-8859-1))
-    ;; ISO-8859-15 is very similar to ISO-8859-1.
-    ;;,(unless (mm-coding-system-p 'iso-8859-15) ; Emacs 21 defines it.
-    ;;   '(iso-8859-15 . iso-8859-1))
+    ,@(unless (mm-coding-system-p 'windows-1252)
+       (if (mm-coding-system-p 'cp1252)
+          '((windows-1252 . cp1252))
+        '((windows-1252 . iso-8859-1))))
     ;; Windows-1250 is a variant of Latin-2 heavily used by Microsoft
     ;; Outlook users in Czech republic. Use this to allow reading of their
     ;; e-mails. cp1250 should be defined by M-x codepage-setup.
-    ;;,(unless (mm-coding-system-p 'windows-1250)      
-                                       ; should be defined eventually
-    ;;  '(windows-1250 . cp1250))
+    ,@(if (and (not (mm-coding-system-p 'windows-1250))
+              (mm-coding-system-p 'cp1250))
+         '((windows-1250 . cp1250)))
+    ;; A Microsoft misunderstanding.
+    ,@(if (and (not (mm-coding-system-p 'unicode))
+              (mm-coding-system-p 'utf-16-le))
+         '((unicode . utf-16-le)))
+    ;; A Microsoft misunderstanding.
+    ,@(unless (mm-coding-system-p 'ks_c_5601-1987)
+       (if (mm-coding-system-p 'cp949)
+           '((ks_c_5601-1987 . cp949))
+         '((ks_c_5601-1987 . euc-kr))))
     )
   "A mapping from invalid charset names to the real charset names.")
 
 
 (defvar mm-auto-save-coding-system
   (cond
+   ((mm-coding-system-p 'utf-8-emacs)  ; Mule 7
+    (if (memq system-type '(windows-nt ms-dos ms-windows))
+       (if (mm-coding-system-p 'utf-8-emacs-dos)
+           'utf-8-emacs-dos mm-binary-coding-system)
+      'utf-8-emacs))
    ((mm-coding-system-p 'emacs-mule)
     (if (memq system-type '(windows-nt ms-dos ms-windows))
        (if (mm-coding-system-p 'emacs-mule-dos)
   "Coding system of auto save file.")
 
 (defvar mm-universal-coding-system mm-auto-save-coding-system
-  "The universal Coding system.")
+  "The universal coding system.")
 
 ;; Fixme: some of the cars here aren't valid MIME charsets.  That
 ;; should only matter with XEmacs, though.
     (big5 chinese-big5-1 chinese-big5-2)
     (tibetan tibetan)
     (thai-tis620 thai-tis620)
+    (windows-1251 cyrillic-iso8859-5)
     (iso-2022-7bit ethiopic arabic-1-column arabic-2-column)
     (iso-2022-jp-2 latin-iso8859-1 greek-iso8859-7
                   latin-jisx0201 japanese-jisx0208-1978
                   chinese-gb2312 japanese-jisx0208
-                  korean-ksc5601 japanese-jisx0212
-                  katakana-jisx0201)
+                  korean-ksc5601 japanese-jisx0212)
     (iso-2022-int-1 latin-iso8859-1 greek-iso8859-7
                    latin-jisx0201 japanese-jisx0208-1978
                    chinese-gb2312 japanese-jisx0208
                    chinese-cns11643-3 chinese-cns11643-4
                    chinese-cns11643-5 chinese-cns11643-6
                    chinese-cns11643-7)
+    (iso-2022-jp-3 latin-jisx0201 japanese-jisx0208-1978 japanese-jisx0208
+                  japanese-jisx0213-1 japanese-jisx0213-2)
+    (shift_jis latin-jisx0201 katakana-jisx0201 japanese-jisx0208)
     ,(if (or (not (fboundp 'charsetp)) ;; non-Mule case
             (charsetp 'unicode-a)
             (not (mm-coding-system-p 'mule-utf-8)))
                       (coding-system-get 'mule-utf-8 'safe-charsets)))))
   "Alist of MIME-charset/MULE-charsets.")
 
-;; Correct by construction, but should be unnecessary:
-;; XEmacs hates it.
-(when (and (not (featurep 'xemacs))
-          (fboundp 'coding-system-list)
-          (fboundp 'sort-coding-systems))
-  (setq mm-mime-mule-charset-alist
-       (apply
-        'nconc
-        (mapcar
-         (lambda (cs)
-           (when (and (coding-system-get cs 'mime-charset)
-                      (not (eq t (coding-system-get cs 'safe-charsets))))
-             (list (cons (coding-system-get cs 'mime-charset)
-                         (delq 'ascii
-                               (coding-system-get cs 'safe-charsets))))))
-         (sort-coding-systems (coding-system-list 'base-only))))))
+(defun mm-enrich-utf-8-by-mule-ucs ()
+  "Make the `utf-8' MIME charset usable by the Mule-UCS package.
+This function will run when the `un-define' module is loaded under
+XEmacs, and fill the `utf-8' entry in `mm-mime-mule-charset-alist'
+with Mule charsets.  It is completely useless for Emacs."
+  (unless (cdr (delete '(mm-enrich-utf-8-by-mule-ucs)
+                      (assoc "un-define" after-load-alist)))
+    (setq after-load-alist
+         (delete '("un-define") after-load-alist)))
+  (when (boundp 'unicode-basic-translation-charset-order-list)
+    (condition-case nil
+       (let ((val (delq
+                   'ascii
+                   (copy-sequence
+                    (symbol-value
+                     'unicode-basic-translation-charset-order-list))))
+             (elem (assq 'utf-8 mm-mime-mule-charset-alist)))
+         (if elem
+             (setcdr elem val)
+           (setq mm-mime-mule-charset-alist
+                 (nconc mm-mime-mule-charset-alist
+                        (list (cons 'utf-8 val))))))
+      (error))))
+
+;; Correct by construction, but should be unnecessary for Emacs:
+(if (featurep 'xemacs)
+    (eval-after-load "un-define" '(mm-enrich-utf-8-by-mule-ucs))
+  (when (and (fboundp 'coding-system-list)
+            (fboundp 'sort-coding-systems))
+    (let ((css (sort-coding-systems (coding-system-list 'base-only)))
+         cs mime mule alist)
+      (while css
+       (setq cs (pop css)
+             mime (or (coding-system-get cs :mime-charset) ; Emacs 22
+                      (coding-system-get cs 'mime-charset)))
+       (when (and mime
+                  (not (eq t (setq mule
+                                   (coding-system-get cs 'safe-charsets))))
+                  (not (assq mime alist)))
+         (push (cons mime (delq 'ascii mule)) alist)))
+      (setq mm-mime-mule-charset-alist (nreverse alist)))))
+
+(defvar mm-hack-charsets '(iso-8859-15 iso-2022-jp-2)
+  "A list of special charsets.
+Valid elements include:
+`iso-8859-15'    convert ISO-8859-1, -9 to ISO-8859-15 if ISO-8859-15 exists.
+`iso-2022-jp-2'  convert ISO-2022-jp to ISO-2022-jp-2 if ISO-2022-jp-2 exists."
+)
+
+(defvar mm-iso-8859-15-compatible
+  '((iso-8859-1 "\xA4\xA6\xA8\xB4\xB8\xBC\xBD\xBE")
+    (iso-8859-9 "\xA4\xA6\xA8\xB4\xB8\xBC\xBD\xBE\xD0\xDD\xDE\xF0\xFD\xFE"))
+  "ISO-8859-15 exchangeable coding systems and inconvertible characters.")
+
+(defvar mm-iso-8859-x-to-15-table
+  (and (fboundp 'coding-system-p)
+       (mm-coding-system-p 'iso-8859-15)
+       (mapcar
+       (lambda (cs)
+         (if (mm-coding-system-p (car cs))
+             (let ((c (string-to-char
+                       (decode-coding-string "\341" (car cs)))))
+               (cons (char-charset c)
+                     (cons
+                      (- (string-to-char
+                          (decode-coding-string "\341" 'iso-8859-15)) c)
+                      (string-to-list (decode-coding-string (car (cdr cs))
+                                                            (car cs))))))
+           '(gnus-charset 0)))
+       mm-iso-8859-15-compatible))
+  "A table of the difference character between ISO-8859-X and ISO-8859-15.")
+
+(defcustom mm-coding-system-priorities
+  (if (boundp 'current-language-environment)
+      (let ((lang (symbol-value 'current-language-environment)))
+       (cond ((string= lang "Japanese")
+              ;; Japanese users prefer iso-2022-jp to euc-japan or
+              ;; shift_jis, however iso-8859-1 should be used when
+              ;; there are only ASCII text and Latin-1 characters.
+              '(iso-8859-1 iso-2022-jp iso-2022-jp-2 shift_jis utf-8)))))
+  "Preferred coding systems for encoding outgoing messages.
+
+More than one suitable coding system may be found for some text.
+By default, the coding system with the highest priority is used
+to encode outgoing messages (see `sort-coding-systems').  If this
+variable is set, it overrides the default priority."
+  :version "21.2"
+  :type '(repeat (symbol :tag "Coding system"))
+  :group 'mime)
+
+;; ??
+(defvar mm-use-find-coding-systems-region
+  (fboundp 'find-coding-systems-region)
+  "Use `find-coding-systems-region' to find proper coding systems.
+
+Setting it to nil is useful on Emacsen supporting Unicode if sending
+mail with multiple parts is preferred to sending a Unicode one.")
 
 ;;; Internal variables:
 
 
 (defun mm-mule-charset-to-mime-charset (charset)
   "Return the MIME charset corresponding to the given Mule CHARSET."
-  (if (fboundp 'find-coding-systems-for-charsets)
-      (let (mime)
-       (dolist (cs (find-coding-systems-for-charsets (list charset)))
-         (unless mime
-           (when cs
-             (setq mime (coding-system-get cs 'mime-charset)))))
+  (if (and (fboundp 'find-coding-systems-for-charsets)
+          (fboundp 'sort-coding-systems))
+      (let ((css (sort (sort-coding-systems
+                       (find-coding-systems-for-charsets (list charset)))
+             &nb