Importing Pterodactyl Gnus v0.95.
[elisp/gnus.git-] / lisp / rfc2047.el
index c96aeb2..6e7512c 100644 (file)
@@ -1,5 +1,5 @@
 ;;; rfc2047.el --- Functions for encoding and decoding rfc2047 messages
 ;;; rfc2047.el --- Functions for encoding and decoding rfc2047 messages
-;; Copyright (C) 1998 Free Software Foundation, Inc.
+;; Copyright (C) 1998,99 Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;;     MORIOKA Tomohiko <morioka@jaist.ac.jp>
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;;     MORIOKA Tomohiko <morioka@jaist.ac.jp>
 ;;; Code:
 
 (eval-and-compile
 ;;; Code:
 
 (eval-and-compile
-  (if (not (fboundp 'base64-encode-string))
-      (require 'base64)))
+  (eval
+   '(unless (fboundp 'base64-decode-string)
+      (require 'base64))))
+
 (require 'qp)
 (require 'mm-util)
 (require 'qp)
 (require 'mm-util)
-
-(defvar rfc2047-default-charset 'iso-8859-1
-  "Default MIME charset -- does not need encoding.")
+(require 'ietf-drums)
+(require 'mail-prsvr)
 
 (defvar rfc2047-header-encoding-alist
   '(("Newsgroups" . nil)
 
 (defvar rfc2047-header-encoding-alist
   '(("Newsgroups" . nil)
@@ -56,7 +57,7 @@ The values can be:
     (iso-8859-3 . Q)
     (iso-8859-4 . Q)
     (iso-8859-5 . B)
     (iso-8859-3 . Q)
     (iso-8859-4 . Q)
     (iso-8859-5 . B)
-    (koi8-r . Q)
+    (koi8-r . B)
     (iso-8859-7 . Q)
     (iso-8859-8 . Q)
     (iso-8859-9 . Q)
     (iso-8859-7 . Q)
     (iso-8859-8 . Q)
     (iso-8859-9 . Q)
@@ -100,13 +101,13 @@ Valid encodings are nil, `Q' and `B'.")
        (point-max))))
   (goto-char (point-min)))
 
        (point-max))))
   (goto-char (point-min)))
 
-;;;###autoload
 (defun rfc2047-encode-message-header ()
   "Encode the message header according to `rfc2047-header-encoding-alist'.
 Should be called narrowed to the head of the message."
   (interactive "*")
   (when (featurep 'mule)
     (save-excursion
 (defun rfc2047-encode-message-header ()
   "Encode the message header according to `rfc2047-header-encoding-alist'.
 Should be called narrowed to the head of the message."
   (interactive "*")
   (when (featurep 'mule)
     (save-excursion
+      (goto-char (point-min))
       (let ((alist rfc2047-header-encoding-alist)
            elem method)
        (while (not (eobp))
       (let ((alist rfc2047-header-encoding-alist)
            elem method)
        (while (not (eobp))
@@ -123,17 +124,22 @@ Should be called narrowed to the head of the message."
              (when method
                (cond
                 ((eq method 'mime)
              (when method
                (cond
                 ((eq method 'mime)
-                 (rfc2047-encode-region (point-min) (point-max)))
+                 (rfc2047-encode-region (point-min) (point-max))
+                 (rfc2047-fold-region (point-min) (point-max)))
                 ;; Hm.
                 (t))))
                 ;; Hm.
                 (t))))
-           (goto-char (point-max))))))))
+           (goto-char (point-max)))))
+      (when mail-parse-charset
+       (encode-coding-region (point-min) (point-max)
+                             mail-parse-charset)))))
 
 (defun rfc2047-encodable-p ()
   "Say whether the current (narrowed) buffer contains characters that need encoding."
 
 (defun rfc2047-encodable-p ()
   "Say whether the current (narrowed) buffer contains characters that need encoding."
-  (let ((charsets (mapcar
-                  'mm-mule-charset-to-mime-charset
-                  (find-charset-region (point-min) (point-max))))
-       (cs (list 'us-ascii rfc2047-default-charset))
+  (let ((charsets
+        (mapcar
+         'mm-mime-charset
+         (mm-find-charset-region (point-min) (point-max))))
+       (cs (list 'us-ascii mail-parse-charset))
        found)
     (while charsets
       (unless (memq (pop charsets) cs)
        found)
     (while charsets
       (unless (memq (pop charsets) cs)
@@ -141,18 +147,17 @@ Should be called narrowed to the head of the message."
     found))
 
 (defun rfc2047-dissect-region (b e)
     found))
 
 (defun rfc2047-dissect-region (b e)
-  "Dissect the region between B and E."
+  "Dissect the region between B and E into words."
   (let (words)
     (save-restriction
       (narrow-to-region b e)
       (goto-char (point-min))
   (let (words)
     (save-restriction
       (narrow-to-region b e)
       (goto-char (point-min))
-      (while (re-search-forward "[^ \t\n]+" nil t)
+      (while (re-search-forward
+             (concat "[^" ietf-drums-tspecials " \t\n]+") nil t)
        (push
         (list (match-beginning 0) (match-end 0)
        (push
         (list (match-beginning 0) (match-end 0)
-              (car
-               (delq 'ascii
-                     (find-charset-region (match-beginning 0)
-                                          (match-end 0)))))
+              (car (delq 'ascii (mm-find-charset-region
+                                 (match-beginning 0) (match-end 0)))))
         words))
       words)))
 
         words))
       words)))
 
@@ -180,35 +185,66 @@ Should be called narrowed to the head of the message."
 
 (defun rfc2047-encode (b e charset)
   "Encode the word in the region with CHARSET."
 
 (defun rfc2047-encode (b e charset)
   "Encode the word in the region with CHARSET."
-  (let* ((mime-charset
-         (mm-mime-charset charset b e))
+  (let* ((mime-charset (mm-mime-charset charset))
         (encoding (or (cdr (assq mime-charset
         (encoding (or (cdr (assq mime-charset
-                             rfc2047-charset-encoding-alist))
+                                 rfc2047-charset-encoding-alist))
                       'B))
         (start (concat
                 "=?" (downcase (symbol-name mime-charset)) "?"
                       'B))
         (start (concat
                 "=?" (downcase (symbol-name mime-charset)) "?"
-                (downcase (symbol-name encoding)) "?")))
+                (downcase (symbol-name encoding)) "?"))
+        (first t))
     (save-restriction
       (narrow-to-region b e)
     (save-restriction
       (narrow-to-region b e)
-      (mm-encode-coding-region b e mime-charset)
+      (when (eq encoding 'B)
+       ;; break into lines before encoding
+       (goto-char (point-min))
+       (while (not (eobp))
+         (goto-char (min (point-max) (+ 15 (point))))
+         (unless (eobp)
+           (insert "\n"))))
+      (mm-encode-coding-region (point-min) (point-max) mime-charset)
       (funcall (cdr (assq encoding rfc2047-encoding-function-alist))
               (point-min) (point-max))
       (goto-char (point-min))
       (funcall (cdr (assq encoding rfc2047-encoding-function-alist))
               (point-min) (point-max))
       (goto-char (point-min))
-      (insert start)
-      (goto-char (point-max))
-      (insert "?=")
-      ;; Encoded words can't be more than 75 chars long, so we have to
-      ;; split the long ones up.
-      (end-of-line)
-      (while (> (current-column) 74)
-       (beginning-of-line)
-       (forward-char 73)
-       (insert "?=\n " start)
-       (end-of-line)))))
+      (while (not (eobp))
+       (unless first
+         (insert " "))
+       (setq first nil)
+       (insert start)
+       (end-of-line)
+       (insert "?=")
+       (forward-line 1)))))
+
+(defun rfc2047-fold-region (b e)
+  "Fold the long lines in the region."
+  (save-restriction
+    (narrow-to-region b e)
+    (goto-char (point-min))
+    (let ((break nil))
+      (while (not (eobp))
+       (cond
+        ((memq (char-after) '(?  ?\t))
+         (setq break (point)))
+        ((and (not break)
+              (looking-at "=\\?"))
+         (setq break (point)))
+        ((and (looking-at "\\?=")
+              (> (- (point) (save-excursion (beginning-of-line) (point))) 76))
+         (goto-char break)
+         (insert "\n ")
+         (forward-line 1)))
+       (unless (eobp)
+         (forward-char 1))))))
 
 (defun rfc2047-b-encode-region (b e)
   "Encode the header contained in REGION with the B encoding."
 
 (defun rfc2047-b-encode-region (b e)
   "Encode the header contained in REGION with the B encoding."
-  (base64-encode-region b e t))
+  (save-restriction
+    (narrow-to-region (goto-char b) e)
+    (while (not (eobp))
+      (base64-encode-region (point) (progn (end-of-line) (point)) t)
+      (if (and (bolp) (eolp))
+         (delete-backward-char 1))
+      (forward-line))))
 
 (defun rfc2047-q-encode-region (b e)
   "Encode the header contained in REGION with the Q encoding."
 
 (defun rfc2047-q-encode-region (b e)
   "Encode the header contained in REGION with the Q encoding."
@@ -219,17 +255,23 @@ Should be called narrowed to the head of the message."
        (while alist
          (when (looking-at (caar alist))
            (quoted-printable-encode-region b e nil (cdar alist))
        (while alist
          (when (looking-at (caar alist))
            (quoted-printable-encode-region b e nil (cdar alist))
-           (subst-char-in-region (point-min) (point-max) ?  ?_))
-         (pop alist))))))
+           (subst-char-in-region (point-min) (point-max) ?  ?_)
+           (setq alist nil))
+         (pop alist))
+       (goto-char (point-min))
+       (while (not (eobp))
+         (goto-char (min (point-max) (+ 64 (point))))
+         (search-backward "=" (- (point) 2) t)
+         (unless (eobp)
+           (insert "\n")))))))
 
 ;;;
 ;;; Functions for decoding RFC2047 messages
 ;;;
 
 (defvar rfc2047-encoded-word-regexp
 
 ;;;
 ;;; Functions for decoding RFC2047 messages
 ;;;
 
 (defvar rfc2047-encoded-word-regexp
-  "=\\?\\([^][\000-\040()<>@,\;:\\\"/?.=]+\\)\\?\\(B\\|Q\\)\\?\\([!->@-~ ]+\\)\\?=")
+  "=\\?\\([^][\000-\040()<>@,\;:\\\"/?.=]+\\)\\?\\(B\\|Q\\)\\?\\([!->@-~ +]+\\)\\?=")
 
 
-;;;###autoload
 (defun rfc2047-decode-region (start end)
   "Decode MIME-encoded words in region between START and END."
   (interactive "r")
 (defun rfc2047-decode-region (start end)
   "Decode MIME-encoded words in region between START and END."
   (interactive "r")
@@ -254,19 +296,25 @@ Should be called narrowed to the head of the message."
                   (prog1
                       (match-string 0)
                     (delete-region (match-beginning 0) (match-end 0)))))
                   (prog1
                       (match-string 0)
                     (delete-region (match-beginning 0) (match-end 0)))))
-         (mm-decode-coding-region b e rfc2047-default-charset)
+         (when (and (mm-multibyte-p)
+                    mail-parse-charset)
+           (mm-decode-coding-region b e mail-parse-charset))
          (setq b (point)))
          (setq b (point)))
-       (mm-decode-coding-region b (point-max) rfc2047-default-charset)))))
+       (when (and (mm-multibyte-p)
+                  mail-parse-charset
+                  (not (eq mail-parse-charset 'us-ascii)))
+         (mm-decode-coding-region b (point-max) mail-parse-charset))))))
 
 
-;;;###autoload
 (defun rfc2047-decode-string (string)
 (defun rfc2047-decode-string (string)
- "Decode the quoted-printable-encoded STRING and return the results."
- (with-temp-buffer
-   (mm-enable-multibyte)
-   (insert string)
-   (inline
-     (rfc2047-decode-region (point-min) (point-max)))
-   (buffer-string)))
+  "Decode the quoted-printable-encoded STRING and return the results."
+  (let ((m (mm-multibyte-p)))
+    (with-temp-buffer
+      (when m
+       (mm-enable-multibyte))
+      (insert string)
+      (inline
+       (rfc2047-decode-region (point-min) (point-max)))
+      (buffer-string))))
 
 (defun rfc2047-parse-and-decode (word)
   "Decode WORD and return it if it is an encoded word.
 
 (defun rfc2047-parse-and-decode (word)
   "Decode WORD and return it if it is an encoded word.
@@ -286,14 +334,19 @@ Return WORD if not."
   "Decode STRING that uses CHARSET with ENCODING.
 Valid ENCODINGs are \"B\" and \"Q\".
 If your Emacs implementation can't decode CHARSET, it returns nil."
   "Decode STRING that uses CHARSET with ENCODING.
 Valid ENCODINGs are \"B\" and \"Q\".
 If your Emacs implementation can't decode CHARSET, it returns nil."
+  (if (stringp charset)
+    (setq charset (intern (downcase charset))))
+  (if (or (not charset) (memq charset mail-parse-ignored-charsets))
+      (setq charset mail-parse-charset))
   (let ((cs (mm-charset-to-coding-system charset)))
     (when cs
   (let ((cs (mm-charset-to-coding-system charset)))
     (when cs
+      (when (and (eq cs 'ascii)
+                mail-parse-charset)
+       (setq cs mail-parse-charset))
       (mm-decode-coding-string
        (cond
        ((equal "B" encoding)
       (mm-decode-coding-string
        (cond
        ((equal "B" encoding)
-        (if (fboundp 'base64-decode-string)
-            (base64-decode-string string)
-          (base64-decode string)))
+        (base64-decode-string string))
        ((equal "Q" encoding)
         (quoted-printable-decode-string
          (mm-replace-chars-in-string string ?_ ? )))
        ((equal "Q" encoding)
         (quoted-printable-decode-string
          (mm-replace-chars-in-string string ?_ ? )))