Revision: miles@gnu.org--gnu-2005/emacs--unicode--0--patch-13
[bpt/emacs.git] / lisp / mail / unrmail.el
index 20e4128..db6990d 100644 (file)
@@ -1,7 +1,8 @@
-;;; unrmail.el --- convert Rmail files to mailbox files.
+;;; unrmail.el --- convert Rmail files to mailbox files
 
-;;; Copyright (C) 1992 Free Software Foundation, Inc.
+;;; Copyright (C) 1992, 2002 Free Software Foundation, Inc.
 
+;; Maintainer: FSF
 ;; Keywords: mail
 
 ;; This file is part of GNU Emacs.
 ;; 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, 675 Mass Ave, Cambridge, MA 02139, USA.
+;; 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.
+
+;;; Commentary:
 
 ;;; Code:
 
@@ -47,17 +51,179 @@ For example, invoke `emacs -batch -f batch-unrmail RMAIL'."
 (defun unrmail (file to-file)
   "Convert Rmail file FILE to system inbox format file TO-FILE."
   (interactive "fUnrmail (rmail file): \nFUnrmail into (new mailbox file): ")
-  (let ((message-count 0)
-       ;; Prevent rmail from making, or switching to, a summary buffer.
-       (rmail-display-summary nil)
-       (rmail-delete-after-output nil))
-    (rmail file)
+  (with-temp-buffer
+    ;; Read in the old Rmail file with no decoding.
+    (let ((coding-system-for-read 'raw-text))
+      (insert-file-contents file))
+    ;; But make it multibyte.
+    (set-buffer-multibyte t)
+
+    (if (not (looking-at "BABYL OPTIONS"))
+       (error "This file is not in Babyl format"))
+
+    ;; Decode the file contents just as Rmail did.
+    (let ((modifiedp (buffer-modified-p))
+         (coding-system rmail-file-coding-system)
+         from to)
+      (goto-char (point-min))
+      (search-forward "\n\^_" nil t)   ; Skip BABYL header.
+      (setq from (point))
+      (goto-char (point-max))
+      (search-backward "\n\^_" from 'mv)
+      (setq to (point))
+      (unless (and coding-system
+                  (coding-system-p coding-system))
+       (setq coding-system
+             ;; Emacs 21.1 and later writes RMAIL files in emacs-mule, but
+             ;; earlier versions did that with the current buffer's encoding.
+             ;; So we want to favor detection of emacs-mule (whose normal
+             ;; priority is quite low), but still allow detection of other
+             ;; encodings if emacs-mule won't fit.  The call to
+             ;; detect-coding-with-priority below achieves that.
+             (car (detect-coding-with-priority
+                   from to
+                   '((coding-category-emacs-mule . emacs-mule))))))
+      (unless (memq coding-system
+                   '(undecided undecided-unix))
+       (set-buffer-modified-p t)       ; avoid locking when decoding
+       (let ((buffer-undo-list t))
+         (decode-coding-region from to coding-system))
+       (setq coding-system last-coding-system-used))
+
+      (setq buffer-file-coding-system nil)
+
+      ;; We currently don't use this value, but maybe we should.
+      (setq save-buffer-coding-system
+           (or coding-system 'undecided)))
+
+    ;; Default the directory of TO-FILE based on where FILE is.
+    (setq to-file (expand-file-name to-file default-directory))
+    (condition-case ()
+       (delete-file to-file)
+      (file-error nil))
     (message "Writing messages to %s..." to-file)
-    (while (< message-count rmail-total-messages)
-      (rmail-show-message
-       (setq message-count (1+ message-count)))
-      (rmail-toggle-header)
-      (rmail-output to-file 1 t))
+    (goto-char (point-min))
+
+    (let ((temp-buffer (get-buffer-create " unrmail"))
+         (from-buffer (current-buffer)))
+
+      ;; Process the messages one by one.
+      (while (search-forward "\^_\^l" nil t)
+       (let ((beg (point))
+             (end (save-excursion
+                    (if (search-forward "\^_" nil t)
+                        (1- (point)) (point-max))))
+             (coding 'raw-text)
+             label-line attrs keywords
+             mail-from reformatted)
+         (with-current-buffer temp-buffer
+           (setq buffer-undo-list t)
+           (erase-buffer)
+           (setq buffer-file-coding-system coding)
+           (insert-buffer-substring from-buffer beg end)
+           (goto-char (point-min))
+           (forward-line 1)
+           ;; Record whether the header is reformatted.
+           (setq reformatted (= (following-char) ?1))
+
+           ;; Collect the label line, then get the attributes
+           ;; and the keywords from it.
+           (setq label-line
+                 (buffer-substring (point)
+                                   (save-excursion (forward-line 1)
+                                                   (point))))
+           (search-forward ",,")
+           (unless (eolp)
+             (setq keywords
+                   (buffer-substring (point)
+                                     (progn (end-of-line)
+                                            (1- (point)))))
+             (setq keywords
+                   (replace-regexp-in-string ", " "," keywords)))
+
+           (setq attrs
+                 (list
+                  (if (string-match ", answered," label-line) ?A ?-)
+                  (if (string-match ", deleted," label-line) ?D ?-)
+                  (if (string-match ", edited," label-line) ?E ?-)
+                  (if (string-match ", filed," label-line) ?F ?-)
+                  (if (string-match ", resent," label-line) ?R ?-)
+                  (if (string-match ", unseen," label-line) ?\  ?-)
+                  (if (string-match ", stored," label-line) ?S ?-)))
+
+           ;; Delete the special Babyl lines at the start,
+           ;; and the ***EOOH*** line, and the reformatted header if any.
+           (goto-char (point-min))
+           (if reformatted
+               (progn
+                 (forward-line 2)
+                 ;; Delete Summary-Line headers.
+                 (let ((case-fold-search t))
+                   (while (looking-at "Summary-Line:")
+                     (forward-line 1)))
+                 (delete-region (point-min) (point))
+                 ;; Delete the old reformatted header.
+                 (re-search-forward "^[*][*][*] EOOH [*][*][*]\n")
+                 (forward-line -1)
+                 (let ((start (point)))
+                   (search-forward "\n\n")
+                   (delete-region start (point))))
+             ;; Not reformatted.  Delete the special
+             ;; lines before the real header.
+             (re-search-forward "^[*][*][*] EOOH [*][*][*]\n")
+             (delete-region (point-min) (point)))
+
+           ;; Some operations on the message header itself.
+           (goto-char (point-min))
+           (save-restriction
+             (narrow-to-region 
+              (point-min)
+              (save-excursion (search-forward "\n\n" nil 'move) (point)))
+
+             ;; Fetch or construct what we should use in the `From ' line.
+             (setq mail-from
+                   (or (mail-fetch-field "Mail-From")
+                       (concat "From "
+                               (mail-strip-quoted-names (or (mail-fetch-field "from")
+                                                            (mail-fetch-field "really-from")
+                                                            (mail-fetch-field "sender")
+                                                            "unknown"))
+                               " " (current-time-string))))
+
+             ;; If the message specifies a coding system, use it.
+             (let ((maybe-coding (mail-fetch-field "X-Coding-System")))
+               (if maybe-coding
+                   (setq coding (intern maybe-coding))))
+
+             ;; Delete the Mail-From: header field if any.
+             (when (re-search-forward "^Mail-from:" nil t)
+               (beginning-of-line)
+               (delete-region (point)
+                              (progn (forward-line 1) (point)))))
+
+           (goto-char (point-min))
+           ;; Insert the `From ' line.
+           (insert mail-from "\n")
+           ;; Record the keywords and attributes in our special way.
+           (insert "X-BABYL-V6-ATTRIBUTES: " (apply 'string attrs) "\n")
+           (when keywords
+             (insert "X-BABYL-V6-KEYWORDS: " keywords "\n"))
+           (goto-char (point-min))
+           ;; ``Quote'' "\nFrom " as "\n>From "
+           ;;  (note that this isn't really quoting, as there is no requirement
+           ;;   that "\n[>]+From " be quoted in the same transparent way.)
+           (let ((case-fold-search nil))
+             (while (search-forward "\nFrom " nil t)
+               (forward-char -5)
+               (insert ?>)))
+           ;; Write it to the output file.
+           (write-region (point-min) (point-max) to-file t
+                         'nomsg))))
+      (kill-buffer temp-buffer))
     (message "Writing messages to %s...done" to-file)))
 
+(provide 'unrmail)
+
 ;;; unrmail.el ends here
+
+;;; arch-tag: 14c6290d-60b2-456f-8909-5c2387de6acb