Synch to No Gnus 200501120840.
[elisp/gnus.git-] / lisp / mm-util.el
index cbaff05..6a11e97 100644 (file)
 
 (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."
+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)
-       (coding-system-p cs)
+       (when (coding-system-p cs)
+         cs)
       ;; Is this branch ever actually useful?
-      (memq cs (mm-get-coding-system-list)))))
+      (car (memq cs (mm-get-coding-system-list))))))
 
 (defvar mm-charset-synonym-alist
   `(
@@ -160,6 +163,10 @@ In XEmacs, also return non-nil if CS is a coding system object."
               (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))
@@ -229,6 +236,7 @@ In XEmacs, also return non-nil if CS is a coding system object."
     (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
@@ -261,24 +269,47 @@ In XEmacs, also return non-nil if CS is a coding system object."
                       (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 (or (coding-system-get cs :mime-charset) ; Emacs 22
-                          (coding-system-get cs 'mime-charset))
-                      (not (eq t (coding-system-get cs 'safe-charsets))))
-             (list (cons (or (coding-system-get cs :mime-charset)
-                             (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.
@@ -314,14 +345,17 @@ Valid elements include:
   (if (boundp 'current-language-environment)
       (let ((lang (symbol-value 'current-language-environment)))
        (cond ((string= lang "Japanese")
-              ;; Japanese users may prefer iso-2022-jp to shift_jis.
-              '(iso-2022-jp iso-2022-jp-2 shift_jis iso-8859-1 utf-8)))))
+              ;; 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)
 
@@ -544,15 +578,92 @@ This affects whether coding conversion should be attempted generally."
   (let ((priorities
         (mapcar (lambda (cs)
                   ;; Note: invalid entries are dropped silently
-                  (and (mm-coding-system-p cs)
+                  (and (setq cs (mm-coding-system-p cs))
                        (coding-system-base cs)))
                 mm-coding-system-priorities)))
-    (and (mm-coding-system-p a)
-        (if (mm-coding-system-p b)
+    (and (setq a (mm-coding-system-p a))
+        (if (setq b (mm-coding-system-p b))
             (> (length (memq (coding-system-base a) priorities))
                (length (memq (coding-system-base b) priorities)))
           t))))
 
+(eval-when-compile
+  (autoload 'latin-unity-massage-name "latin-unity")
+  (autoload 'latin-unity-maybe-remap "latin-unity")
+  (autoload 'latin-unity-representations-feasible-region "latin-unity")
+  (autoload 'latin-unity-representations-present-region "latin-unity")
+  (defvar latin-unity-coding-systems)
+  (defvar latin-unity-ucs-list))
+
+(defun mm-xemacs-find-mime-charset-1 (begin end)
+  "Determine which MIME charset to use to send region as message.
+This uses the XEmacs-specific latin-unity package to better handle the
+case where identical characters from diverse ISO-8859-? character sets
+can be encoded using a single one of the corresponding coding systems.
+
+It treats `mm-coding-system-priorities' as the list of preferred
+coding systems; a useful example setting for this list in Western
+Europe would be '(iso-8859-1 iso-8859-15 utf-8), which would default
+to the very standard Latin 1 coding system, and only move to coding
+systems that are less supported as is necessary to encode the
+characters that exist in the buffer.
+
+Latin Unity doesn't know about those non-ASCII Roman characters that
+are available in various East Asian character sets.  As such, its
+behavior if you have a JIS 0212 LATIN SMALL LETTER A WITH ACUTE in a
+buffer and it can otherwise be encoded as Latin 1, won't be ideal.
+But this is very much a corner case, so don't worry about it."
+  (let ((systems mm-coding-system-priorities) csets psets curset)
+
+    ;; Load the Latin Unity library, if available.
+    (when (and (not (featurep 'latin-unity)) (locate-library "latin-unity"))
+      (require 'latin-unity))
+
+    ;; Now, can we use it?
+    (if (featurep 'latin-unity)
+       (progn
+         (setq csets (latin-unity-representations-feasible-region begin end)
+               psets (latin-unity-representations-present-region begin end))
+
+         (catch 'done
+
+           ;; Pass back the first coding system in the preferred list
+           ;; that can encode the whole region.
+           (dolist (curset systems)
+             (setq curset (latin-unity-massage-name 'buffer-default curset))
+
+             ;; If the coding system is a universal coding system, then
+             ;; it can certainly encode all the characters in the region.
+             (if (memq curset latin-unity-ucs-list)
+                 (throw 'done (list curset)))
+
+             ;; If a coding system isn't universal, and isn't in
+             ;; the list that latin unity knows about, we can't
+             ;; decide whether to use it here. Leave that until later
+             ;; in `mm-find-mime-charset-region' function, whence we
+             ;; have been called.
+             (unless (memq curset latin-unity-coding-systems)
+               (throw 'done nil))
+
+             ;; Right, we know about this coding system, and it may
+             ;; conceivably be able to encode all the characters in
+             ;; the region.
+             (if (latin-unity-maybe-remap begin end curset csets psets t)
+                 (throw 'done (list curset))))
+
+           ;; Can't encode using anything from the
+           ;; `mm-coding-system-priorities' list.
+           ;; Leave `mm-find-mime-charset' to do most of the work.
+           nil))
+
+      ;; Right, latin unity isn't available; let `mm-find-charset-region'
+      ;; take its default action, which equally applies to GNU Emacs.
+      nil)))
+
+(defmacro mm-xemacs-find-mime-charset (begin end)
+  (when (featurep 'xemacs)
+    `(mm-xemacs-find-mime-charset-1 ,begin ,end)))
+
 (defun mm-find-mime-charset-region (b e &optional hack-charsets)
   "Return the MIME charsets needed to encode the region between B and E.
 nil means ASCII, a single-element list represents an appropriate MIME
@@ -594,8 +705,12 @@ charset, and a longer list means no appropriate charset."
                         (setq systems nil
                               charsets (list cs))))))
               charsets))
-       ;; Otherwise we're not multibyte, we're XEmacs, or a single
-       ;; coding system won't cover it.
+       ;; If we're XEmacs, and some coding system is appropriate,
+       ;; mm-xemacs-find-mime-charset will return an appropriate list.
+       ;; Otherwise, we'll get nil, and the next setq will get invoked.
+       (setq charsets (mm-xemacs-find-mime-charset b e))
+
+       ;; We're not multibyte, or a single coding system won't cover it.
        (setq charsets
              (mm-delete-duplicates
               (mapcar 'mm-mime-charset