Sync up with main trunk and following.
[elisp/wanderlust.git] / wl / wl-draft.el
index 904a411..7d6f024 100644 (file)
@@ -81,7 +81,7 @@ This variable is local in each draft buffer.
 You can refer its value in `wl-draft-config-alist'.
 
 e.g.
-(setq wl-draft-config-alist
+\(setq wl-draft-config-alist
       '(((string-match \".*@domain1$\" wl-draft-parent-folder)
          (\"From\" . \"user@domain1\"))
         ((string-match \".*@domain2$\" wl-draft-parent-folder)
@@ -89,6 +89,10 @@ e.g.
 
 (defvar wl-draft-parent-number nil)
 
+(defconst wl-draft-reply-saved-variables
+  '(wl-draft-parent-folder
+    wl-draft-parent-number))
+
 (defvar wl-draft-config-sub-func-alist
   '((body              . wl-draft-config-sub-body)
     (top               . wl-draft-config-sub-top)
@@ -157,48 +161,11 @@ e.g.
   "Insert From field."
   ;; Put the "From:" field in unless for some odd reason
   ;; they put one in themselves.
-  (let* ((login (or user-mail-address (user-login-name)))
-        (fullname (user-full-name)))
-    (cond ((eq mail-from-style 'angles)
-          (insert "From: " fullname)
-          (let ((fullname-start (+ (point-min) (length "From: ")))
-                (fullname-end (point-marker)))
-            (goto-char fullname-start)
-            ;; Look for a character that cannot appear unquoted
-            ;; according to RFC 822.
-            (if (re-search-forward "[^- !#-'*+/-9=?A-Z^-~]"
-                                   fullname-end 1)
-                (progn
-                  ;; Quote fullname, escaping specials.
-                  (goto-char fullname-start)
-                  (insert "\"")
-                  (while (re-search-forward "[\"\\]"
-                                            fullname-end 1)
-                    (replace-match "\\\\\\&" t))
-                  (insert "\""))))
-          (insert " <" login ">\n"))
-         ((eq mail-from-style 'parens)
-          (insert "From: " login " (")
-          (let ((fullname-start (point)))
-            (insert fullname)
-            (let ((fullname-end (point-marker)))
-              (goto-char fullname-start)
-              ;; RFC 822 says \ and nonmatching parentheses
-              ;; must be escaped in comments.
-              ;; Escape every instance of ()\ ...
-              (while (re-search-forward "[()\\]" fullname-end 1)
-                (replace-match "\\\\\\&" t))
-              ;; ... then undo escaping of matching parentheses,
-              ;; including matching nested parentheses.
-              (goto-char fullname-start)
-              (while (re-search-forward
-                      "\\(\\=\\|[^\\]\\(\\\\\\\\\\)*\\)\\\\(\\(\\([^\\]\\|\\\\\\\\\\)*\\)\\\\)"
-                      fullname-end 1)
-                (replace-match "\\1(\\3)" t)
-                (goto-char fullname-start))))
-          (insert ")\n"))
-         ((not mail-from-style)
-          (insert "From: " login "\n")))))
+  (let (from)
+    (condition-case err
+       (setq from (wl-draft-eword-encode-address-list wl-from))
+      (error (error "Please look at `wl-from' again")))
+    (insert "From: " from "\n")))
 
 (defun wl-draft-insert-x-face-field ()
   "Insert X-Face header."
@@ -298,6 +265,9 @@ e.g.
            references (wl-delete-duplicates references)
            references (when references
                         (mapconcat 'identity references "\n\t"))))
+    (and wl-draft-use-frame
+        (get-buffer-window summary-buf)
+        (select-window (get-buffer-window summary-buf)))
     (wl-draft (list (cons 'To "")
                    (cons 'Subject
                          (concat wl-forward-subject-prefix original-subject))
@@ -308,21 +278,14 @@ e.g.
   (mail-position-on-field "To"))
 
 (defun wl-draft-strip-subject-re (subject)
-  "Remove \"Re:\" from subject lines. Shamelessly copied from Gnus."
+  "Remove \"Re:\" from SUBJECT string. Shamelessly copied from Gnus."
   (if (string-match wl-subject-prefix-regexp subject)
       (substring subject (match-end 0))
     subject))
 
-(defun wl-draft-reply-list-symbol (with-arg)
-  "Return symbol `wl-draft-reply-*-argument-list' match condition.
-Check WITH-ARG and From: field."
-  (if (wl-address-user-mail-address-p (or (elmo-field-body "From") ""))
-      (if with-arg
-         'wl-draft-reply-myself-with-argument-list
-       'wl-draft-reply-myself-without-argument-list)
-    (if with-arg
-       'wl-draft-reply-with-argument-list
-      'wl-draft-reply-without-argument-list)))
+(defun wl-draft-self-reply-p ()
+  "Return t when From address in the current message is user's self one or not."
+  (wl-address-user-mail-address-p (or (elmo-field-body "From") "")))
 
 (defun wl-draft-reply (buf with-arg summary-buf &optional number)
   "Reply to BUF buffer message.
@@ -335,7 +298,8 @@ Reply to author if WITH-ARG is non-nil."
       (with-current-buffer summary-buf
        (setq parent-folder (wl-summary-buffer-folder-name))))
     (set-buffer (or buf mime-mother-buffer))
-    (setq r-list (symbol-value (wl-draft-reply-list-symbol with-arg)))
+    (setq r-list (if with-arg wl-draft-reply-with-argument-list
+                  wl-draft-reply-without-argument-list))
     (catch 'done
       (while r-list
        (when (let ((condition (car (car r-list))))
@@ -344,8 +308,15 @@ Reply to author if WITH-ARG is non-nil."
                      ((listp condition)
                       (catch 'done
                         (while condition
-                          (if (not (std11-field-body (car condition)))
-                              (throw 'done nil))
+                          (cond
+                           ((stringp (car condition))
+                            (or (std11-field-body (car condition))
+                                (throw 'done nil)))
+                           ((symbolp (car condition))
+                            (or (funcall (car condition))
+                                (throw 'done nil)))
+                           (t
+                            (debug)))
                           (setq condition (cdr condition)))
                         t))
                      ((symbolp condition)
@@ -365,7 +336,7 @@ Reply to author if WITH-ARG is non-nil."
                                              r-to-list))
                                       ",")))
            (if (and r-cc-list (symbolp r-cc-list))
-               (setq cc (wl-concat-list (funcall r-to-list) ","))
+               (setq cc (wl-concat-list (funcall r-cc-list) ","))
              (setq cc (wl-concat-list (cons cc
                                             (elmo-multiple-fields-body-list
                                              r-cc-list))
@@ -378,8 +349,8 @@ Reply to author if WITH-ARG is non-nil."
                                               ","))))
          (throw 'done nil))
        (setq r-list (cdr r-list)))
-      (error "No match field: check your `%s'"
-            (symbol-name (wl-draft-reply-list-symbol with-arg))))
+      (error "No match field: check your `wl-draft-reply-%s-argument-list'"
+            (if with-arg "with" "without")))
     (setq subject (std11-field-body "Subject"))
     (setq to (wl-parse-addresses to)
          cc (wl-parse-addresses cc))
@@ -464,6 +435,9 @@ Reply to author if WITH-ARG is non-nil."
          references (wl-delete-duplicates references)
          references (if references
                         (mapconcat 'identity references "\n\t")))
+    (and wl-draft-use-frame
+        (get-buffer-window summary-buf)
+        (select-window (get-buffer-window summary-buf)))
     (wl-draft (list (cons 'To to)
                    (cons 'Cc cc)
                    (cons 'Newsgroups newsgroups)
@@ -473,9 +447,28 @@ Reply to author if WITH-ARG is non-nil."
                    (cons 'Mail-Followup-To mail-followup-to))
              nil nil nil nil parent-folder)
     (setq wl-draft-parent-number number)
-    (setq wl-draft-reply-buffer buf))
+    (setq wl-draft-reply-buffer buf)
+    (setq wl-draft-config-variables
+         (append wl-draft-reply-saved-variables
+                 wl-draft-config-variables)))
   (run-hooks 'wl-reply-hook))
 
+(defun wl-draft-reply-position (position)
+  (cond ((eq position 'body)
+        (wl-draft-body-goto-top))
+       ((eq position 'bottom)
+        (wl-draft-body-goto-bottom))
+       ((eq position 'top)
+        (goto-char (point-min)))
+       ((and (stringp position)
+             (std11-field-body position))
+        (progn (mail-position-on-field position)
+               (wl-draft-beginning-of-line)))
+       ((listp position)
+        (while (car position)
+          (wl-draft-reply-position (car position))
+          (setq position (cdr position))))))
+
 (defun wl-draft-add-references ()
   (wl-draft-add-in-reply-to "References"))
 
@@ -616,10 +609,12 @@ Reply to author if WITH-ARG is non-nil."
                   content-type content-transfer-encoding
                   (buffer-substring (point) (point-max))
                   'edit-again))
-      (and to (mail-position-on-field "To"))
-      (delete-other-windows)
-      (kill-buffer tmp-buf)))
-  (run-hooks 'wl-draft-reedit-hook))
+      (kill-buffer tmp-buf))
+    ;; Set cursor point to the top.
+    (goto-char (point-min))
+    (search-forward (concat mail-header-separator "\n") nil t)
+    (run-hooks 'wl-draft-reedit-hook)
+    (and to (mail-position-on-field "To"))))
 
 (defun wl-draft-insert-current-message (dummy)
   (interactive)
@@ -671,34 +666,23 @@ Reply to author if WITH-ARG is non-nil."
 (defun wl-default-draft-cite ()
   (let ((mail-yank-ignored-headers "[^:]+:")
        (mail-yank-prefix "> ")
-       (summary-buf wl-current-summary-buffer)
-       (message-buf (get-buffer (wl-current-message-buffer)))
-       from date cite-title num entity)
-    (if (and summary-buf
-            (buffer-live-p summary-buf)
-            message-buf
-            (buffer-live-p message-buf))
-       (progn
-         (with-current-buffer summary-buf
-           (let ((elmo-mime-charset wl-summary-buffer-mime-charset))
-             (setq num (save-excursion
-                         (set-buffer message-buf)
-                         wl-message-buffer-cur-number))
-             (setq entity (elmo-msgdb-overview-get-entity
-                           num (wl-summary-buffer-msgdb)))
-             (setq date (elmo-msgdb-overview-entity-get-date entity))
-             (setq from (elmo-msgdb-overview-entity-get-from entity))))
-         (setq cite-title (format "At %s,\n%s wrote:"
-                                  (or date "some time ago")
-                                  (if wl-default-draft-cite-decorate-author
-                                      (funcall wl-summary-from-function
-                                               (or from "you"))
-                                    (or from "you"))))))
-    (and cite-title
-        (insert cite-title "\n"))
+       date from cite-title)
+    (save-restriction
+      (if (< (mark t) (point))
+         (exchange-point-and-mark))
+      (narrow-to-region (point)(point-max))
+      (setq date (std11-field-body "date")
+           from (std11-field-body "from")))
+    (when (or date from)
+      (insert (format "At %s,\n%s wrote:\n"
+                     (or date "some time ago")
+                     (if wl-default-draft-cite-decorate-author
+                         (funcall wl-summary-from-function
+                                  (or from "you"))
+                       (or from "you")))))
     (mail-indent-citation)))
 
-(defvar wl-draft-buffer nil "Draft buffer to yank content")
+(defvar wl-draft-buffer nil "Draft buffer to yank content.")
 (defun wl-draft-yank-to-draft-buffer (buffer)
   "Yank BUFFER content to `wl-draft-buffer'."
   (set-buffer wl-draft-buffer)
@@ -712,6 +696,7 @@ Reply to author if WITH-ARG is non-nil."
   (if arg
       (let (buf mail-reply-buffer)
        (elmo-set-work-buf
+        (insert "\n")
         (yank)
         (setq buf (current-buffer)))
        (setq mail-reply-buffer buf)
@@ -750,7 +735,7 @@ Reply to author if WITH-ARG is non-nil."
                (switch-to-buffer sum-buf))))))))
 
 (defun wl-draft-delete (editing-buffer)
-  "kill the editing draft buffer and delete the file corresponds to it."
+  "Kill the editing draft buffer and delete the file corresponds to it."
   (save-excursion
     (when editing-buffer
       (set-buffer editing-buffer)
@@ -775,13 +760,23 @@ Reply to author if WITH-ARG is non-nil."
               (or force-kill
                   (y-or-n-p "Kill Current Draft? ")))
       (let ((cur-buf (current-buffer)))
-       (when wl-draft-parent-number
-         (let ((number wl-draft-parent-number))
-           (with-current-buffer wl-draft-buffer-cur-summary-buffer
-             (wl-summary-jump-to-msg number)
-             (elmo-folder-unmark-answered wl-summary-buffer-elmo-folder
-                                          (list number))
-             (wl-summary-update-mark number))))
+       (when (and wl-draft-parent-number
+                  (not (string= wl-draft-parent-folder "")))
+         (let* ((number wl-draft-parent-number)
+                (folder-name wl-draft-parent-folder)
+                (folder (wl-folder-get-elmo-folder folder-name))
+                buffer)
+           (if (and (setq buffer (wl-summary-get-buffer folder-name))
+                    (with-current-buffer buffer
+                      (string= (wl-summary-buffer-folder-name)
+                               folder-name)))
+               (with-current-buffer buffer
+                 (elmo-folder-unmark-answered folder (list number))
+                 (wl-summary-jump-to-msg number)
+                 (wl-summary-update-mark number))
+             (elmo-folder-open folder 'load-msgdb)
+             (elmo-folder-unmark-answered folder (list number))
+             (elmo-folder-close folder))))
        (wl-draft-hide cur-buf)
        (wl-draft-delete cur-buf)))
     (message "")))
@@ -1089,12 +1084,16 @@ non-nil."
                     (wl-draft-write-sendlog 'failed 'smtp smtp-server
                                             recipients id)
                     (if (and (eq (car err) 'smtp-response-error)
-                             (/= (nth 1 err) 334))
+                             (= (nth 1 err) 535))
                         (elmo-remove-passwd
                          (wl-smtp-password-key
                           smtp-sasl-user-name
                           (car smtp-sasl-mechanisms)
                           smtp-server)))
+                    (signal (car err) (cdr err)))
+                   (quit
+                    (wl-draft-write-sendlog 'uncertain 'smtp smtp-server
+                                            recipients id)
                     (signal (car err) (cdr err)))))
                 (wl-draft-set-sent-message 'mail 'sent)
                 (wl-draft-write-sendlog
@@ -1172,7 +1171,7 @@ If FORCE-MSGID, insert message-id regardless of `wl-insert-message-id'."
   "Send the message in the current buffer.  Not modified the header fields."
   (let (delimline mime-bcc)
     (if (and wl-draft-verbose-send mes-string)
-       (message mes-string))
+       (message "%s" mes-string))
     ;; get fcc folders.
     (setq delimline (wl-draft-get-header-delimiter t))
     (unless wl-draft-fcc-list
@@ -1230,10 +1229,11 @@ If FORCE-MSGID, insert message-id regardless of `wl-insert-message-id'."
                (setq wl-draft-verbose-msg
                      (format "Sending%s and Queuing%s..."
                              sent-via unplugged-via))
-               (message (concat wl-draft-verbose-msg "done")))
+               (message "%sdone" wl-draft-verbose-msg))
            (if mes-string
-               (message (concat mes-string
-                                (if sent-via "done" "failed")))))))))
+               (message "%s%s"
+                        mes-string
+                        (if sent-via "done" "failed"))))))))
   (not wl-sent-message-modified)) ;; return value
 
 (defun wl-draft-raw-send (&optional kill-when-done force-pre-hook mes-string)
@@ -1260,6 +1260,48 @@ If FORCE-MSGID, insert message-id regardless of `wl-insert-message-id'."
       (setq locals (cdr locals)))
     result))
 
+(defcustom wl-draft-send-confirm-with-preview t
+  "Non-nil to invoke preview through confirmation of sending.
+This variable is valid when `wl-interactive-send' has non-nil value."
+  :type 'boolean
+  :group 'wl-draft)
+
+(defun wl-draft-send-confirm ()
+  (let (answer)
+    (unwind-protect
+       (condition-case quit
+           (progn
+             (when wl-draft-send-confirm-with-preview
+               (wl-draft-preview-message))
+             (save-excursion
+               (goto-char (point-min)) ; to show recipients in header
+               (catch 'done
+                 (while t
+                   (message "Send current draft? <y/n/j(up)/k(down)> ")
+                   (setq answer (let ((cursor-in-echo-area t)) (read-char)))
+                   (cond
+                    ((or (eq answer ?y)
+                         (eq answer ?Y)
+                         (eq answer ? ))
+                 (throw 'done t))
+                    ((or (eq answer ?v)
+                         (eq answer ?j)
+                         (eq answer ?J))
+                     (condition-case err
+                         (scroll-up)
+                       (error nil)))
+                    ((or (eq answer ?^)
+                         (eq answer ?k)
+                         (eq answer ?K))
+                     (condition-case err
+                         (scroll-down)
+                       (error nil)))
+                    (t
+                     (throw 'done nil)))))))
+         (quit nil))
+      (when wl-draft-send-confirm-with-preview
+       (mime-preview-quit)))))
+
 (defun wl-draft-send (&optional kill-when-done mes-string)
   "Send current draft message.
 If KILL-WHEN-DONE is non-nil, current draft buffer is killed"
@@ -1269,7 +1311,7 @@ If KILL-WHEN-DONE is non-nil, current draft buffer is killed"
   ;; (wl-draft-config-exec)
   (run-hooks 'wl-draft-send-hook)
   (when (or (not wl-interactive-send)
-           (y-or-n-p "Do you really want to send current draft? "))
+           (wl-draft-send-confirm))
     (let ((send-mail-function 'wl-draft-raw-send)
          (editing-buffer (current-buffer))
          (sending-buffer (wl-draft-generate-clone-buffer
@@ -1279,22 +1321,23 @@ If KILL-WHEN-DONE is non-nil, current draft buffer is killed"
          (wl-draft-verbose-msg nil)
          err)
       (unwind-protect
-         (save-excursion (set-buffer sending-buffer)
+         (save-excursion
+           (set-buffer sending-buffer)
            (if (and (not (wl-message-mail-p))
                     (not (wl-message-news-p)))
                (error "No recipient is specified"))
-           (expand-abbrev) ; for mail-abbrevs
+           (expand-abbrev)             ; for mail-abbrevs
            (let ((mime-header-encode-method-alist
                   (append
                    '((wl-draft-eword-encode-address-list
-                      .  (To Cc Bcc Resent-To Resent-Cc Bcc Resent-Bcc)))
+                      .  (To Cc Bcc Resent-To Resent-Cc Resent-Bcc From)))
                    (if (boundp 'mime-header-encode-method-alist)
                        (symbol-value 'mime-header-encode-method-alist)))))
              (run-hooks 'mail-send-hook) ; translate buffer
              )
            ;;
            (if wl-draft-verbose-send
-               (message (or mes-string "Sending...")))
+               (message "%s" (or mes-string "Sending...")))
            (funcall wl-draft-send-function editing-buffer kill-when-done)
            ;; Now perform actions on successful sending.
            (while mail-send-actions
@@ -1304,15 +1347,16 @@ If KILL-WHEN-DONE is non-nil, current draft buffer is killed"
                (error))
              (setq mail-send-actions (cdr mail-send-actions)))
            (if wl-draft-verbose-send
-               (message (concat (or wl-draft-verbose-msg
-                                    mes-string "Sending...")
-                                "done"))))
+               (message "%sdone"
+                        (or wl-draft-verbose-msg
+                            mes-string
+                            "Sending..."))))
        ;; kill sending buffer, anyway.
        (and (buffer-live-p sending-buffer)
             (kill-buffer sending-buffer))))))
 
 (defun wl-draft-mime-bcc-field ()
-  "Return the MIME-Bcc field body. The field is deleted."
+  "Return the MIME-Bcc field body.  The field is deleted."
   (prog1 (std11-field-body wl-draft-mime-bcc-field-name)
     (wl-draft-delete-field wl-draft-mime-bcc-field-name)))
 
@@ -1511,7 +1555,7 @@ If KILL-WHEN-DONE is non-nil, current draft buffer is killed"
          (if (elmo-folder-append-buffer
               (wl-folder-get-elmo-folder
                (eword-decode-string (car fcc-list)))
-              (not wl-fcc-force-as-read))
+              (and wl-fcc-force-as-read 'read))
              (wl-draft-write-sendlog 'ok 'fcc nil (car fcc-list) id)
            (wl-draft-write-sendlog 'failed 'fcc nil (car fcc-list) id))
          (setq fcc-list (cdr fcc-list)))))
@@ -1558,13 +1602,7 @@ If KILL-WHEN-DONE is non-nil, current draft buffer is killed"
 
   (let (buf-name header-alist-internal)
     (setq buf-name
-         (wl-draft-create-buffer
-          (or
-           (eq this-command 'wl-draft)
-           (eq this-command 'wl-summary-write)
-           (eq this-command 'wl-summary-write-current-folder)
-           (eq this-command 'wl-folder-write-current-folder))
-          parent-folder))
+         (wl-draft-create-buffer parent-folder))
 
     (unless (cdr (assq 'From header-alist))
       (setq header-alist
@@ -1606,11 +1644,17 @@ If KILL-WHEN-DONE is non-nil, current draft buffer is killed"
           (goto-char (point-max))))
     buf-name))
 
-(defun wl-draft-create-buffer (&optional full parent-folder)
+(defun wl-draft-create-buffer (&optional parent-folder)
   (let* ((draft-folder (wl-folder-get-elmo-folder wl-draft-folder))
         (parent-folder (or parent-folder (wl-summary-buffer-folder-name)))
         (summary-buf (wl-summary-get-buffer parent-folder))
-       buf-name file-name num change-major-mode-hook)
+        (reply-or-forward
+         (or (eq this-command 'wl-summary-reply)
+             (eq this-command 'wl-summary-reply-with-citation)
+             (eq this-command 'wl-summary-forward)
+             (eq this-command 'wl-summary-target-mark-forward)
+             (eq this-command 'wl-summary-target-mark-reply-with-citation)))
+        buf-name file-name num change-major-mode-hook)
     (if (not (elmo-folder-message-file-p draft-folder))
        (error "%s folder cannot be used for draft folder" wl-draft-folder))
     (setq num (elmo-max-of-list
@@ -1624,16 +1668,43 @@ If KILL-WHEN-DONE is non-nil, current draft buffer is killed"
                          (elmo-message-file-name
                           (wl-folder-get-elmo-folder wl-draft-folder)
                           num))))
+    ;; switch-buffer according to draft buffer style.
     (if wl-draft-use-frame
        (switch-to-buffer-other-frame buf-name)
-      (switch-to-buffer buf-name))
+      (if reply-or-forward
+         (case wl-draft-reply-buffer-style
+           (split
+            (split-window-vertically)
+            (other-window 1)
+            (switch-to-buffer buf-name))
+           (keep
+            (switch-to-buffer buf-name))
+           (full
+            (delete-other-windows)
+            (switch-to-buffer buf-name))
+           (t
+            (if (functionp wl-draft-reply-buffer-style)
+                (funcall wl-draft-reply-buffer-style buf-name)
+              (error "Invalid value for wl-draft-reply-buffer-style"))))
+       (case wl-draft-buffer-style
+         (split
+          (when (eq major-mode 'wl-summary-mode)
+            (wl-summary-toggle-disp-msg 'off))
+          (split-window-vertically)
+          (other-window 1)
+          (switch-to-buffer buf-name))
+         (keep
+          (switch-to-buffer buf-name))
+         (full
+          (delete-other-windows)
+          (switch-to-buffer buf-name))
+         (t (if (functionp wl-draft-buffer-style)
+                (funcall wl-draft-buffer-style buf-name)
+              (error "Invalid value for wl-draft-buffer-style"))))))
     (set-buffer buf-name)
     (if (not (string-match (regexp-quote wl-draft-folder)
                           (buffer-name)))
        (rename-buffer (concat wl-draft-folder "/" (int-to-string num))))
-    (if (or (eq wl-draft-reply-buffer-style 'full)
-           full)
-       (delete-other-windows))
     (auto-save-mode -1)
     (wl-draft-mode)
     (make-local-variable 'truncate-partial-width-windows)
@@ -1657,10 +1728,9 @@ If KILL-WHEN-DONE is non-nil, current draft buffer is killed"
                        ;;  insert symbol-value: string
   (symbol . nil)       ;;  do nothing
   nil                  ;;  do nothing
-  )
-"
+  )"
   (unless (eq major-mode 'wl-draft-mode)
-    (error "wl-draft-create-header must be use in wl-draft-mode."))
+    (error "`wl-draft-create-header' must be use in wl-draft-mode"))
   (let ((halist header-alist)
        field value)
     (while halist
@@ -1695,10 +1765,11 @@ If KILL-WHEN-DONE is non-nil, current draft buffer is killed"
 
 (defun wl-draft-prepare-edit ()
   (unless (eq major-mode 'wl-draft-mode)
-    (error "wl-draft-create-header must be use in wl-draft-mode."))
+    (error "`wl-draft-create-header' must be use in wl-draft-mode"))
   (let (change-major-mode-hook)
     (wl-draft-editor-mode)
-    (add-hook 'local-write-file-hooks 'wl-draft-save)
+    (when wl-draft-write-file-function
+      (add-hook 'local-write-file-hooks wl-draft-write-file-function))
     (wl-draft-overload-functions)
     (wl-highlight-headers 'for-draft)
     (wl-draft-save)
@@ -1796,7 +1867,8 @@ If KILL-WHEN-DONE is non-nil, current draft buffer is killed"
                       (progn
                         (insert mail-header-separator "\n")
                         (1- (point)))
-                      'category 'mail-header-separator)))
+                      'category 'mail-header-separator)
+    (point)))
 
 ;;;;;;;;;;;;;;;;
 
@@ -1823,7 +1895,7 @@ If KILL-WHEN-DONE is non-nil, current draft buffer is killed"
                 (cdar condition))
            (setq condition (cdr condition)))))
     (unless elmo-nntp-default-function
-      (error "wl-draft-nntp-send: posting-function is nil."))
+      (error "wl-draft-nntp-send: posting-function is nil"))
     (if (not (elmo-plugged-p elmo-nntp-default-server elmo-nntp-default-port))
        (wl-draft-set-sent-message 'news 'unplugged
                                   (cons elmo-nntp-default-server
@@ -1854,10 +1926,16 @@ If KILL-WHEN-DONE is non-nil, current draft buffer is killed"
        (setq local-variables (cdr local-variables)))
       (current-buffer))))
 
+(defun wl-draft-remove-text-plain-tag ()
+  "Remove text/plain tag of mime-edit."
+  (when (string= (mime-make-text-tag "plain")
+                (buffer-substring-no-properties (point-at-bol)(point-at-eol)))
+    (delete-region (point-at-bol)(1+ (point-at-eol)))))
+
 (defun wl-draft-reedit (number)
   (let ((draft-folder (wl-folder-get-elmo-folder wl-draft-folder))
        (wl-draft-reedit t)
-       buffer file-name change-major-mode-hook)
+       buffer file-name change-major-mode-hook body-top)
     (setq file-name (elmo-message-file-name draft-folder number))
     (unless (file-exists-p file-name)
       (error "File %s does not exist" file-name))
@@ -1870,15 +1948,30 @@ If KILL-WHEN-DONE is non-nil, current draft buffer is killed"
            (switch-to-buffer buffer))
          (set-buffer buffer))
       (setq buffer (get-buffer-create (number-to-string number)))
+      ;; switch-buffer according to draft buffer style.
       (if wl-draft-use-frame
          (switch-to-buffer-other-frame buffer)
-       (switch-to-buffer buffer))
+       (case wl-draft-buffer-style
+         (split
+          (split-window-vertically)
+          (other-window 1)
+          (switch-to-buffer buffer))
+         (keep
+          (switch-to-buffer buffer))
+         (full
+          (delete-other-windows)
+          (switch-to-buffer buffer))
+         (t (if (functionp wl-draft-buffer-style)
+                (funcall wl-draft-buffer-style buffer)
+              (error "Invalid value for wl-draft-buffer-style")))))
       (set-buffer buffer)
+      (setq wl-draft-parent-folder "")
       (insert-file-contents-as-binary file-name)
+      (elmo-delete-cr-buffer)
       (let((mime-edit-again-ignored-field-regexp
            "^\\(Content-.*\\|Mime-Version\\):"))
        (wl-draft-decode-message-in-buffer))
-      (wl-draft-insert-mail-header-separator)
+      (setq body-top (wl-draft-insert-mail-header-separator))
       (if (not (string-match (regexp-quote wl-draft-folder)
                             (buffer-name)))
          (rename-buffer (concat wl-draft-folder "/" (buffer-name))))
@@ -1895,8 +1988,10 @@ If KILL-WHEN-DONE is non-nil, current draft buffer is killed"
       (goto-char (point-min))
       (wl-draft-overload-functions)
       (wl-draft-editor-mode)
-      (add-hook 'local-write-file-hooks 'wl-draft-save)
+      (when wl-draft-write-file-function
+       (add-hook 'local-write-file-hooks wl-draft-write-file-function))
       (wl-highlight-headers 'for-draft)
+      (goto-char body-top)
       (run-hooks 'wl-draft-reedit-hook)
       (goto-char (point-max))
       buffer)))
@@ -2185,7 +2280,7 @@ Automatically applied in draft sending time."
   (let ((send-buffer (current-buffer))
        (folder (wl-folder-get-elmo-folder wl-queue-folder))
        (message-id (std11-field-body "Message-ID")))
-    (if (elmo-folder-append-buffer folder t)
+    (if (elmo-folder-append-buffer folder)
        (progn
          (wl-draft-queue-info-operation
           (car (elmo-folder-status folder))
@@ -2310,11 +2405,13 @@ Automatically applied in draft sending time."
 
 (defun wl-draft-highlight-and-recenter (&optional n)
   (interactive "P")
-  (if wl-highlight-body-too
-      (let ((beg (point-min))
-           (end (point-max)))
-       (put-text-property beg end 'face nil)
-       (wl-highlight-message beg end t)))
+  (when wl-highlight-body-too
+    (let ((modified (buffer-modified-p)))
+      (unwind-protect
+         (progn
+           (put-text-property (point-min) (point-max) 'face nil)
+           (wl-highlight-message (point-min) (point-max) t))
+       (set-buffer-modified-p modified))))
   (recenter n))
 
 ;;;; user-agent support by Sen Nagata
@@ -2366,16 +2463,13 @@ been implemented yet.  Partial support for SWITCH-FUNCTION now supported."
 
   (unless (featurep 'wl)
     (require 'wl))
+  (or switch-function
+      (setq switch-function 'keep))
   ;; protect these -- to and subject get bound at some point, so it looks
   ;; to be necessary to protect the values used w/in
   (let ((wl-user-agent-headers-and-body-alist other-headers)
        (wl-draft-use-frame (eq switch-function 'switch-to-buffer-other-frame))
-       (wl-draft-reply-buffer-style 'split))
-    (when (eq switch-function 'switch-to-buffer-other-window)
-      (when (one-window-p t)
-       (if (window-minibuffer-p) (other-window 1))
-       (split-window))
-      (other-window 1))
+       (wl-draft-buffer-style switch-function))
     (if to
        (if (wl-string-match-assoc "to" wl-user-agent-headers-and-body-alist
                                   'ignore-case)