* wl-draft.el (wl-draft-reply): Decode subject before removing
[elisp/wanderlust.git] / wl / wl-draft.el
1 ;;; wl-draft.el --- Message draft mode for Wanderlust.
2
3 ;; Copyright (C) 1998,1999,2000 Yuuichi Teranishi <teranisi@gohome.org>
4 ;; Copyright (C) 1998,1999,2000 Masahiro MURATA <muse@ba2.so-net.ne.jp>
5
6 ;; Author: Yuuichi Teranishi <teranisi@gohome.org>
7 ;;      Masahiro MURATA <muse@ba2.so-net.ne.jp>
8 ;; Keywords: mail, net news
9
10 ;; This file is part of Wanderlust (Yet Another Message Interface on Emacsen).
11
12 ;; This program is free software; you can redistribute it and/or modify
13 ;; it under the terms of the GNU General Public License as published by
14 ;; the Free Software Foundation; either version 2, or (at your option)
15 ;; any later version.
16 ;;
17 ;; This program is distributed in the hope that it will be useful,
18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 ;; GNU General Public License for more details.
21 ;;
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
24 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25 ;; Boston, MA 02111-1307, USA.
26 ;;
27
28 ;;; Commentary:
29 ;;
30
31 ;;; Code:
32 ;;
33
34 (require 'sendmail)
35 (require 'wl-template)
36 (require 'emu)
37 (condition-case nil (require 'timezone) (error nil))
38 (require 'std11)
39 (require 'wl-vars)
40
41 (defvar x-face-add-x-face-version-header)
42 (defvar mail-reply-buffer)
43 (defvar mail-from-style)
44
45 (eval-when-compile
46   (require 'static)
47   (require 'elmo-pop3)
48   (defalias-maybe 'x-face-insert 'ignore)
49   (defalias-maybe 'x-face-insert-version-header 'ignore)
50   (defalias-maybe 'wl-init 'ignore)
51   (defalias-maybe 'wl-draft-mode 'ignore))
52
53 (eval-and-compile
54   (autoload 'wl-addrmgr "wl-addrmgr"))
55
56 (autoload 'open-ssl-stream "ssl")
57
58 (defvar wl-draft-buffer-message-number nil)
59 (defvar wl-draft-field-completion-list nil)
60 (defvar wl-draft-verbose-send t)
61 (defvar wl-draft-verbose-msg nil)
62 (defvar wl-draft-queue-flushing nil)
63 (defvar wl-draft-config-variables nil)
64 (defvar wl-draft-config-exec-flag t)
65 (defvar wl-draft-buffer-cur-summary-buffer nil)
66 (defvar wl-draft-clone-local-variable-regexp "^\\(wl\\|mime\\)")
67 (defvar wl-draft-sendlog-filename "sendlog")
68 (defvar wl-draft-queue-save-filename "qinfo")
69 (defvar wl-draft-config-save-filename "config")
70 (defvar wl-draft-queue-flush-send-function 'wl-draft-dispatch-message)
71 (defvar wl-sent-message-via nil)
72 (defvar wl-sent-message-modified nil)
73 (defvar wl-sent-message-queued nil)
74 (defvar wl-draft-fcc-list nil)
75 (defvar wl-draft-reedit nil)
76 (defvar wl-draft-reply-buffer nil)
77 (defvar wl-draft-forward nil)
78 (defvar wl-draft-doing-mime-bcc nil)
79
80 (defvar wl-draft-parent-folder nil
81   "Folder name of the summary in which current draft is invoked.
82 This variable is local in each draft buffer.
83 You can refer its value in `wl-draft-config-alist'.
84
85 e.g.
86 \(setq wl-draft-config-alist
87       '(((string-match \".*@domain1$\" wl-draft-parent-folder)
88          (\"From\" . \"user@domain1\"))
89         ((string-match \".*@domain2$\" wl-draft-parent-folder)
90          (\"From\" . \"user@domain2\"))))")
91
92 (defvar wl-draft-parent-number nil)
93
94 (defconst wl-draft-reply-saved-variables
95   '(wl-draft-parent-folder
96     wl-draft-parent-number))
97
98 (defvar wl-draft-config-sub-func-alist
99   '((body               . wl-draft-config-sub-body)
100     (top                . wl-draft-config-sub-top)
101     (bottom             . wl-draft-config-sub-bottom)
102     (header             . wl-draft-config-sub-header)
103     (header-top         . wl-draft-config-sub-header-top)
104     (header-bottom      . wl-draft-config-sub-header)
105     (part-top           . wl-draft-config-sub-part-top)
106     (part-bottom        . wl-draft-config-sub-part-bottom)
107     (body-file          . wl-draft-config-sub-body-file)
108     (top-file           . wl-draft-config-sub-top-file)
109     (bottom-file        . wl-draft-config-sub-bottom-file)
110     (header-file        . wl-draft-config-sub-header-file)
111     (template           . wl-draft-config-sub-template)
112     (x-face             . wl-draft-config-sub-x-face)))
113
114 (make-variable-buffer-local 'wl-draft-buffer-message-number)
115 (make-variable-buffer-local 'wl-draft-buffer-cur-summary-buffer)
116 (make-variable-buffer-local 'wl-draft-config-variables)
117 (make-variable-buffer-local 'wl-draft-config-exec-flag)
118 (make-variable-buffer-local 'wl-sent-message-via)
119 (make-variable-buffer-local 'wl-sent-message-queued)
120 (make-variable-buffer-local 'wl-draft-fcc-list)
121 (make-variable-buffer-local 'wl-draft-reply-buffer)
122 (make-variable-buffer-local 'wl-draft-parent-folder)
123 (make-variable-buffer-local 'wl-draft-parent-number)
124
125 (defvar wl-draft-folder-internal nil
126   "Internal variable for caching `opened' draft folder.")
127
128 (defsubst wl-smtp-password-key (user mechanism server)
129   (format "SMTP:%s/%s@%s"
130           user mechanism server))
131
132 (defmacro wl-smtp-extension-bind (&rest body)
133   (` (let* ((smtp-sasl-mechanisms
134              (if wl-smtp-authenticate-type
135                  (mapcar 'upcase
136                          (if (listp wl-smtp-authenticate-type)
137                              wl-smtp-authenticate-type
138                            (list wl-smtp-authenticate-type)))))
139             (smtp-use-sasl (and smtp-sasl-mechanisms t))
140             (smtp-use-starttls (eq wl-smtp-connection-type 'starttls))
141             (smtp-open-connection-function
142              (if (eq wl-smtp-connection-type 'ssl)
143                  #'open-ssl-stream
144                smtp-open-connection-function))
145             (smtp-end-of-line
146              (if (eq wl-smtp-connection-type 'ssl)
147                  "\n"
148                smtp-end-of-line))
149             smtp-sasl-user-name smtp-sasl-properties sasl-read-passphrase)
150        (if (and (string= (car smtp-sasl-mechanisms) "DIGEST-MD5")
151                 ;; sendmail bug?
152                 (string-match "^\\([^@]*\\)@\\([^@]*\\)"
153                               wl-smtp-posting-user))
154            (setq smtp-sasl-user-name (match-string 1 wl-smtp-posting-user)
155                  smtp-sasl-properties (list 'realm
156                                             (match-string 2 wl-smtp-posting-user)))
157          (setq smtp-sasl-user-name wl-smtp-posting-user
158                smtp-sasl-properties nil))
159        (setq sasl-read-passphrase
160              (function
161               (lambda (prompt)
162                 (elmo-get-passwd
163                  (wl-smtp-password-key
164                   smtp-sasl-user-name
165                   (car smtp-sasl-mechanisms)
166                   smtp-server)))))
167        (,@ body))))
168
169 (defun wl-draft-insert-date-field ()
170   "Insert Date field."
171   (insert "Date: " (wl-make-date-string) "\n"))
172
173 (defun wl-draft-insert-from-field ()
174   "Insert From field."
175   ;; Put the "From:" field in unless for some odd reason
176   ;; they put one in themselves.
177   (let (from)
178     (condition-case err
179         (setq from (wl-draft-eword-encode-address-list wl-from))
180       (error (error "Please look at `wl-from' again")))
181     (insert "From: " from "\n")))
182
183 (defun wl-draft-insert-x-face-field ()
184   "Insert X-Face header."
185   (interactive)
186   (if (not (file-exists-p wl-x-face-file))
187       (error "File %s does not exist" wl-x-face-file)
188     (goto-char (point-min))
189     (search-forward mail-header-separator nil t)
190     (beginning-of-line)
191     (wl-draft-insert-x-face-field-here)
192     (run-hooks 'wl-draft-insert-x-face-field-hook))) ; highlight it if you want.
193
194 (defun wl-draft-insert-x-face-field-here ()
195   "Insert X-Face field at point."
196   (let ((x-face-string (elmo-get-file-string wl-x-face-file)))
197     (when (string-match "^\\(X-Face:\\)?[ \t\n]*" x-face-string)
198       (setq x-face-string (substring x-face-string (match-end 0))))
199     (insert "X-Face: " x-face-string))
200   (when (not (= (preceding-char) ?\n))  ; for chomped (choped) x-face-string
201     (insert ?\n))
202   ;; Insert X-Face-Version: field
203   (when (and (fboundp 'x-face-insert-version-header)
204              (boundp 'x-face-add-x-face-version-header)
205              x-face-add-x-face-version-header)
206     (x-face-insert-version-header)))
207
208 (defun wl-draft-setup ()
209   (let ((field wl-draft-fields)
210         cl)
211     (while field
212       (setq cl (append cl
213                        (list (cons (concat (car field) " ")
214                                    (concat (car field) " ")))))
215       (setq field (cdr field)))
216     (setq cl
217           (cons (cons (concat wl-draft-mime-bcc-field-name  ": ")
218                       (concat wl-draft-mime-bcc-field-name  ": "))
219                 cl))
220     (setq wl-draft-field-completion-list cl)
221     (setq wl-address-complete-header-regexp
222           (wl-regexp-opt
223            (append wl-address-complete-header-list
224                    (list (concat wl-draft-mime-bcc-field-name  ":")))))))
225
226 (defun wl-draft-make-mail-followup-to (recipients)
227   (let ((rlist (wl-address-delete-user-mail-addresses recipients)))
228     (if (elmo-list-member rlist (mapcar 'downcase
229                                         wl-subscribed-mailing-list))
230         rlist
231       (append rlist (list (wl-address-header-extract-address
232                            wl-from))))))
233
234 (defun wl-draft-delete-myself-from-cc (to cc)
235   (cond (wl-draft-always-delete-myself ; always-delete option
236          (wl-address-delete-user-mail-addresses cc))
237         ((elmo-list-member (append to cc) ; subscribed mailing-list
238                            (mapcar 'downcase wl-subscribed-mailing-list))
239          (wl-address-delete-user-mail-addresses cc))
240         (t cc)))
241
242 (defsubst wl-draft-strip-subject-regexp (subject regexp)
243   "Remove REGEXP from SUBJECT string."
244   (if (string-match regexp subject)
245       (substring subject (match-end 0))
246     subject))
247
248 (defun wl-draft-forward-make-subject (original-subject)
249   "Generate subject string for forwarding."
250   (cond ((functionp wl-forward-subject-prefix)
251          (concat (funcall wl-forward-subject-prefix)
252                  original-subject))
253         ((stringp wl-forward-subject-prefix)
254          (concat wl-forward-subject-prefix
255                  (wl-draft-strip-subject-regexp
256                   (or original-subject "")
257                   wl-subject-forward-prefix-regexp)))
258         (t original-subject)))
259
260 (defun wl-draft-reply-make-subject (original-subject)
261   "Generate subject string for replying."
262   (cond ((functionp wl-reply-subject-prefix)
263          (concat (funcall wl-reply-subject-prefix)
264                  original-subject))
265         ((stringp wl-reply-subject-prefix)
266          (concat wl-reply-subject-prefix
267                  (wl-draft-strip-subject-regexp
268                   (or original-subject "")
269                   wl-subject-re-prefix-regexp)))
270         (t original-subject)))
271
272 (defun wl-draft-forward (original-subject summary-buf)
273   (let (references parent-folder subject)
274     (with-current-buffer summary-buf
275       (setq parent-folder (wl-summary-buffer-folder-name)))
276     (setq subject (wl-draft-forward-make-subject original-subject))
277     (with-current-buffer (wl-message-get-original-buffer)
278       (setq references (nconc
279                         (std11-field-bodies '("References" "In-Reply-To"))
280                         (list (std11-field-body "Message-Id"))))
281       (setq references (delq nil references)
282             references (mapconcat 'identity references " ")
283             references (wl-draft-parse-msg-id-list-string references)
284             references (wl-delete-duplicates references)
285             references (when references
286                          (mapconcat 'identity references "\n\t"))))
287     (and wl-draft-use-frame
288          (get-buffer-window summary-buf)
289          (select-window (get-buffer-window summary-buf)))
290     (wl-draft (list (cons 'To "")
291                     (cons 'Subject subject)
292                     (cons 'References references))
293               nil nil nil nil parent-folder))
294   (goto-char (point-max))
295   (wl-draft-insert-message)
296   (mail-position-on-field "To"))
297
298 (defun wl-draft-self-reply-p ()
299   "Return t when From address in the current message is user's self one or not."
300   (wl-address-user-mail-address-p (or (elmo-field-body "From") "")))
301
302 (defun wl-draft-reply (buf with-arg summary-buf &optional number)
303   "Reply to BUF buffer message.
304 Reply to author if WITH-ARG is non-nil."
305 ;;;(save-excursion
306   (let (r-list
307         to mail-followup-to cc subject in-reply-to references newsgroups
308         to-alist cc-alist decoder parent-folder)
309     (when (buffer-live-p summary-buf)
310       (with-current-buffer summary-buf
311         (setq parent-folder (wl-summary-buffer-folder-name))))
312     (set-buffer (or buf mime-mother-buffer))
313     (setq r-list (if with-arg wl-draft-reply-with-argument-list
314                    wl-draft-reply-without-argument-list))
315     (catch 'done
316       (while r-list
317         (when (let ((condition (car (car r-list))))
318                 (cond ((stringp condition)
319                        (std11-field-body condition))
320                       ((listp condition)
321                        (catch 'done
322                          (while condition
323                            (cond
324                             ((stringp (car condition))
325                              (or (std11-field-body (car condition))
326                                  (throw 'done nil)))
327                             ((symbolp (car condition))
328                              (or (funcall (car condition))
329                                  (throw 'done nil)))
330                             (t
331                              (debug)))
332                            (setq condition (cdr condition)))
333                          t))
334                       ((symbolp condition)
335                        (funcall condition))))
336           (let ((r-to-list (nth 0 (cdr (car r-list))))
337                 (r-cc-list (nth 1 (cdr (car r-list))))
338                 (r-ng-list (nth 2 (cdr (car r-list)))))
339             (when (and (member "Followup-To" r-ng-list)
340                        (string= (std11-field-body "Followup-To") "poster"))
341               (setq r-to-list (cons "From" r-to-list))
342               (setq r-ng-list (delete "Followup-To"
343                                       (copy-sequence r-ng-list))))
344             (if (and r-to-list (symbolp r-to-list))
345                 (setq to (wl-concat-list (funcall r-to-list) ","))
346               (setq to (wl-concat-list (cons to
347                                              (elmo-multiple-fields-body-list
348                                               r-to-list))
349                                        ",")))
350             (if (and r-cc-list (symbolp r-cc-list))
351                 (setq cc (wl-concat-list (funcall r-cc-list) ","))
352               (setq cc (wl-concat-list (cons cc
353                                              (elmo-multiple-fields-body-list
354                                               r-cc-list))
355                                        ",")))
356             (if (and r-ng-list (symbolp r-ng-list))
357                 (setq newsgroups (wl-concat-list (funcall r-ng-list) ","))
358               (setq newsgroups (wl-concat-list (cons newsgroups
359                                                      (std11-field-bodies
360                                                       r-ng-list))
361                                                ","))))
362           (throw 'done nil))
363         (setq r-list (cdr r-list)))
364       (error "No match field: check your `wl-draft-reply-%s-argument-list'"
365              (if with-arg "with" "without")))
366     (setq subject (wl-draft-reply-make-subject
367                    (elmo-decoded-field-body "Subject")))
368     (setq to (wl-parse-addresses to)
369           cc (wl-parse-addresses cc))
370     (with-temp-buffer                   ; to keep raw buffer unibyte.
371       (set-buffer-multibyte default-enable-multibyte-characters)
372 ;      (setq decoder (mime-find-field-decoder 'Subject 'plain))
373 ;      (setq subject (if (and subject decoder)
374 ;                       (funcall decoder subject) subject))
375       (setq to-alist
376             (mapcar
377              (lambda (addr)
378                (setq decoder (mime-find-field-decoder 'To 'plain))
379                (cons (nth 1 (std11-extract-address-components addr))
380                      (if decoder (funcall decoder addr) addr)))
381              to))
382       (setq cc-alist
383             (mapcar
384              (lambda (addr)
385                (setq decoder (mime-find-field-decoder 'Cc 'plain))
386                (cons (nth 1 (std11-extract-address-components addr))
387                      (if decoder (funcall decoder addr) addr)))
388              cc)))
389     (setq in-reply-to (std11-field-body "Message-Id"))
390     (setq references (nconc
391                       (std11-field-bodies '("References" "In-Reply-To"))
392                       (list in-reply-to)))
393     (setq to (delq nil (mapcar 'car to-alist)))
394     (setq cc (delq nil (mapcar 'car cc-alist)))
395     ;; if subscribed mailing list is contained in cc or to
396     ;; and myself is contained in cc,
397     ;; delete myself from cc.
398     (setq cc (wl-draft-delete-myself-from-cc to cc))
399     (when wl-insert-mail-followup-to
400       (setq mail-followup-to
401             (wl-draft-make-mail-followup-to (append to cc)))
402       (setq mail-followup-to (wl-delete-duplicates mail-followup-to nil t)))
403     (with-temp-buffer                   ; to keep raw buffer unibyte.
404       (set-buffer-multibyte default-enable-multibyte-characters)
405       (setq newsgroups (wl-parse newsgroups
406                                  "[ \t\f\r\n,]*\\([^ \t\f\r\n,]+\\)")
407             newsgroups (wl-delete-duplicates newsgroups)
408             newsgroups
409             (if newsgroups
410                 (mapconcat
411                  (lambda (grp)
412                    (setq decoder (mime-find-field-decoder 'Newsgroups 'plain))
413                    (if decoder (funcall decoder grp) grp))
414                  newsgroups ","))))
415     (setq to (wl-delete-duplicates to nil t))
416     (setq cc (wl-delete-duplicates
417               (append (wl-delete-duplicates cc nil t)
418                       to (copy-sequence to))
419               t t))
420     (and to (setq to (mapconcat
421                       '(lambda (addr)
422                          (if wl-draft-reply-use-address-with-full-name
423                              (or (cdr (assoc addr to-alist)) addr)
424                            addr))
425                       to ",\n\t")))
426     (and cc (setq cc (mapconcat
427                       '(lambda (addr)
428                          (if wl-draft-reply-use-address-with-full-name
429                              (or (cdr (assoc addr cc-alist)) addr)
430                            addr))
431                       cc ",\n\t")))
432     (and mail-followup-to
433          (setq mail-followup-to
434                (mapconcat
435                 '(lambda (addr)
436                    (if wl-draft-reply-use-address-with-full-name
437                        (or (cdr (assoc addr (append to-alist cc-alist))) addr)
438                      addr))
439                 mail-followup-to ",\n\t")))
440     (and (null to) (setq to cc cc nil))
441     (setq references (delq nil references)
442           references (mapconcat 'identity references " ")
443           references (wl-draft-parse-msg-id-list-string references)
444           references (wl-delete-duplicates references)
445           references (if references
446                          (mapconcat 'identity references "\n\t")))
447     (and wl-draft-use-frame
448          (get-buffer-window summary-buf)
449          (select-window (get-buffer-window summary-buf)))
450     (wl-draft (list (cons 'To to)
451                     (cons 'Cc cc)
452                     (cons 'Newsgroups newsgroups)
453                     (cons 'Subject subject)
454                     (cons 'In-Reply-To in-reply-to)
455                     (cons 'References references)
456                     (cons 'Mail-Followup-To mail-followup-to))
457               nil nil nil nil parent-folder)
458     (setq wl-draft-parent-number number)
459     (setq wl-draft-reply-buffer buf)
460     (setq wl-draft-config-variables
461           (append wl-draft-reply-saved-variables
462                   wl-draft-config-variables)))
463   (run-hooks 'wl-reply-hook))
464
465 (defun wl-draft-reply-position (position)
466   (cond ((eq position 'body)
467          (wl-draft-body-goto-top))
468         ((eq position 'bottom)
469          (wl-draft-body-goto-bottom))
470         ((eq position 'top)
471          (goto-char (point-min)))
472         ((and (stringp position)
473               (std11-field-body position))
474          (progn (mail-position-on-field position)
475                 (wl-draft-beginning-of-line)))
476         ((listp position)
477          (while (car position)
478            (wl-draft-reply-position (car position))
479            (setq position (cdr position))))))
480
481 (defun wl-draft-add-references ()
482   (wl-draft-add-in-reply-to "References"))
483
484 (defun wl-draft-add-in-reply-to (&optional alt-field)
485   (let* ((mes-id (save-excursion
486                    (set-buffer mail-reply-buffer)
487                    (std11-field-body "message-id")))
488          (field (or alt-field "In-Reply-To"))
489          (ref (std11-field-body field))
490          (ref-list nil) (st nil))
491     (when (and mes-id ref)
492       (while (string-match "<[^>]+>" ref st)
493         (setq ref-list
494               (cons (substring ref (match-beginning 0) (setq st (match-end 0)))
495                     ref-list)))
496       (when (and ref-list
497                  (member mes-id ref-list))
498         (setq mes-id nil)))
499     (when mes-id
500       (save-excursion
501         (when (mail-position-on-field field)
502           (forward-line)
503           (while (looking-at "^[ \t]")
504             (forward-line))
505           (setq mes-id (concat "\t" mes-id "\n")))
506         (insert mes-id))
507       t)))
508
509 (defun wl-draft-yank-from-mail-reply-buffer (decode-it
510                                              &optional ignored-fields)
511   (interactive)
512   (save-restriction
513     (narrow-to-region (point)(point))
514     (insert
515      (string-as-multibyte
516       (with-current-buffer mail-reply-buffer
517         (when decode-it
518           (decode-mime-charset-region (point-min) (point-max)
519                                       wl-mime-charset))
520         (buffer-substring-no-properties
521          (point-min) (point-max)))))
522     (when ignored-fields
523       (goto-char (point-min))
524       (wl-draft-delete-fields ignored-fields))
525     (goto-char (point-max))
526     (push-mark (point) nil t)
527     (goto-char (point-min)))
528   (let ((beg (point)))
529     (cond (mail-citation-hook (run-hooks 'mail-citation-hook))
530           (mail-yank-hooks (run-hooks 'mail-yank-hooks))
531           (wl-draft-cite-function (funcall wl-draft-cite-function))) ; default cite
532     (run-hooks 'wl-draft-cited-hook)
533     (when (if wl-draft-add-references
534               (wl-draft-add-references)
535             (if wl-draft-add-in-reply-to
536                 (wl-draft-add-in-reply-to)))
537       (wl-highlight-headers 'for-draft)) ; highlight when added References:
538     (when wl-highlight-body-too
539       (wl-highlight-body-region beg (point-max)))))
540
541 (defun wl-message-news-p ()
542   "If exist valid Newsgroups field, return non-nil."
543   (std11-field-body "Newsgroups"))
544
545 (defun wl-message-field-exists-p (field)
546   "If FIELD exist and FIELD value is not empty, return non-nil."
547   (let ((value (std11-field-body field)))
548     (and value
549          (not (string= value "")))))
550
551 (defun wl-message-mail-p ()
552   "If exist To, Cc or Bcc field, return non-nil."
553   (or (wl-message-field-exists-p "To")
554       (wl-message-field-exists-p "Resent-to")
555       (wl-message-field-exists-p "Cc")
556       (wl-message-field-exists-p "Bcc")
557       (wl-message-field-exists-p wl-draft-mime-bcc-field-name)
558 ;;; This may be needed..
559 ;;;   (wl-message-field-exists-p "Fcc")
560       ))
561
562 (defun wl-draft-edit-string (string)
563   (let ((cur-buf (current-buffer))
564         (tmp-buf (get-buffer-create " *wl-draft-edit-string*"))
565         to subject in-reply-to cc references newsgroups mail-followup-to
566         content-type content-transfer-encoding from
567         body-beg)
568     (set-buffer tmp-buf)
569     (erase-buffer)
570     (insert string)
571     (setq to (std11-field-body "To"))
572     (setq to (and to
573                   (eword-decode-string
574                    (decode-mime-charset-string
575                     to
576                     wl-mime-charset))))
577     (setq subject (std11-field-body "Subject"))
578     (setq subject (and subject
579                        (eword-decode-string
580                         (decode-mime-charset-string
581                          subject
582                          wl-mime-charset))))
583     (setq from (std11-field-body "From")
584           from (and from
585                     (eword-decode-string
586                      (decode-mime-charset-string
587                       from
588                       wl-mime-charset))))
589     (setq in-reply-to (std11-field-body "In-Reply-To"))
590     (setq cc (std11-field-body "Cc"))
591     (setq cc (and cc
592                   (eword-decode-string
593                    (decode-mime-charset-string
594                     cc
595                     wl-mime-charset))))
596     (setq references (std11-field-body "References"))
597     (setq newsgroups (std11-field-body "Newsgroups"))
598     (setq mail-followup-to (std11-field-body "Mail-Followup-To"))
599     (setq content-type (std11-field-body "Content-Type"))
600     (setq content-transfer-encoding (std11-field-body "Content-Transfer-Encoding"))
601     (goto-char (point-min))
602     (or (re-search-forward "\n\n" nil t)
603         (search-forward (concat mail-header-separator "\n") nil t))
604     (unwind-protect
605         (set-buffer
606          (wl-draft (list
607                     (cons 'From
608                           (if (wl-address-user-mail-address-p from) from))
609                     (cons 'To to)
610                     (cons 'Cc cc)
611                     (cons 'Subject subject)
612                     (cons 'Newsgroups newsgroups)
613                     (cons 'Mail-Followup-To mail-followup-to)
614                     (cons 'In-Reply-To in-reply-to)
615                     (cons 'References references))
616                    content-type content-transfer-encoding
617                    (buffer-substring (point) (point-max))
618                    'edit-again))
619       (kill-buffer tmp-buf))
620     ;; Set cursor point to the top.
621     (goto-char (point-min))
622     (search-forward (concat mail-header-separator "\n") nil t)
623     (run-hooks 'wl-draft-reedit-hook)
624     (and to (mail-position-on-field "To"))))
625
626 (defun wl-draft-insert-current-message (dummy)
627   (interactive)
628   (let (original-buffer
629         mail-reply-buffer
630         mail-citation-hook mail-yank-hooks
631         wl-draft-add-references wl-draft-add-in-reply-to
632         wl-draft-cite-function)
633     (if (and wl-draft-buffer-cur-summary-buffer
634              (with-current-buffer wl-draft-buffer-cur-summary-buffer
635                (and wl-message-buffer
636                     (with-current-buffer wl-message-buffer
637                       (setq original-buffer (wl-message-get-original-buffer))
638                       (not (zerop (with-current-buffer original-buffer
639                                     (buffer-size))))))))
640         (progn
641           (setq mail-reply-buffer original-buffer)
642           (wl-draft-yank-from-mail-reply-buffer
643            nil
644            wl-ignored-forwarded-headers))
645       (when (string= (mime-make-tag "message" "rfc822")
646                      (buffer-substring-no-properties (point-at-bol 0)(point-at-eol 0)))
647         (delete-region (point-at-bol 0) (1+ (point-at-eol 0))))
648       (error "No current message"))))
649
650 (defun wl-draft-insert-get-message (dummy)
651   (let ((fld (completing-read
652               "Folder name: "
653               (if (memq 'read-folder wl-use-folder-petname)
654                   (wl-folder-get-entity-with-petname)
655                 wl-folder-entity-hashtb)
656               nil nil wl-default-spec
657               'wl-read-folder-history))
658         (number (call-interactively
659                  (function (lambda (num)
660                              (interactive "nNumber: ")
661                              num))))
662         (mail-reply-buffer (get-buffer-create "*wl-draft-insert-get-message*"))
663         mail-citation-hook mail-yank-hooks
664         wl-draft-cite-function)
665     (unwind-protect
666         (progn
667           (elmo-message-fetch (wl-folder-get-elmo-folder fld)
668                               number
669                               ;; No cache.
670                               (elmo-make-fetch-strategy 'entire)
671                               nil mail-reply-buffer)
672           (wl-draft-yank-from-mail-reply-buffer nil))
673       (kill-buffer mail-reply-buffer))))
674
675 ;;
676 ;; default body citation func
677 ;;
678 (defun wl-default-draft-cite ()
679   (let ((mail-yank-ignored-headers "[^:]+:")
680         (mail-yank-prefix "> ")
681         date from cite-title)
682     (save-restriction
683       (if (< (mark t) (point))
684           (exchange-point-and-mark))
685       (narrow-to-region (point)(point-max))
686       (setq date (std11-field-body "date")
687             from (std11-field-body "from")))
688     (when (or date from)
689       (insert (format "At %s,\n%s wrote:\n"
690                       (or date "some time ago")
691                       (if wl-default-draft-cite-decorate-author
692                           (funcall wl-summary-from-function
693                                    (or from "you"))
694                         (or from "you")))))
695     (mail-indent-citation)))
696
697 (defvar wl-draft-buffer nil "Draft buffer to yank content.")
698 (defun wl-draft-yank-to-draft-buffer (buffer)
699   "Yank BUFFER content to `wl-draft-buffer'."
700   (set-buffer wl-draft-buffer)
701   (let ((mail-reply-buffer buffer))
702     (wl-draft-yank-from-mail-reply-buffer nil)
703     (kill-buffer buffer)))
704
705 (defun wl-draft-yank-original (&optional arg)
706   "Yank original message."
707   (interactive "P")
708   (if arg
709       (let (buf mail-reply-buffer)
710         (elmo-set-work-buf
711          (insert "\n")
712          (yank)
713          (setq buf (current-buffer)))
714         (setq mail-reply-buffer buf)
715         (wl-draft-yank-from-mail-reply-buffer nil))
716     (wl-draft-yank-current-message-entity)))
717
718 (defun wl-draft-hide (editing-buffer)
719   "Hide the editing draft buffer if possible."
720   (when (and editing-buffer
721              (buffer-live-p editing-buffer)
722              (get-buffer-window editing-buffer))
723     (select-window (get-buffer-window editing-buffer))
724     (let ((sum-buf wl-draft-buffer-cur-summary-buffer)
725           fld-buf sum-win fld-win)
726       (if (and wl-draft-use-frame
727                (> (length (visible-frame-list)) 1))
728           ;; hide draft frame
729           (delete-frame)
730         ;; hide draft window
731         (or (one-window-p)
732             (delete-window))
733         ;; stay folder window if required
734         (when wl-stay-folder-window
735           (if (setq fld-buf (get-buffer wl-folder-buffer-name))
736               (if (setq fld-win (get-buffer-window fld-buf))
737                   (select-window fld-win)
738                 (if wl-draft-resume-folder-window ;; resume folder window
739                     (switch-to-buffer fld-buf)))))
740         (if (buffer-live-p sum-buf)
741             (if (setq sum-win (get-buffer-window sum-buf t))
742                 ;; if Summary is on the frame, select it.
743                 (select-window sum-win)
744               ;; if summary is not on the frame, switch to it.
745               (if (and wl-stay-folder-window
746                        (or wl-draft-resume-folder-window fld-win))
747                   (wl-folder-select-buffer sum-buf)
748                 (switch-to-buffer sum-buf))))))))
749
750 (defun wl-draft-delete (editing-buffer)
751   "Kill the editing draft buffer and delete the file corresponds to it."
752   (save-excursion
753     (when editing-buffer
754       (set-buffer editing-buffer)
755       (when wl-draft-buffer-message-number
756         (elmo-folder-delete-messages (wl-draft-get-folder)
757                                      (list
758                                       wl-draft-buffer-message-number))
759         (wl-draft-config-info-operation wl-draft-buffer-message-number
760                                         'delete))
761       (set-buffer-modified-p nil)               ; force kill
762       (kill-buffer editing-buffer))))
763
764 (defun wl-draft-kill (&optional force-kill)
765   "Kill current draft buffer and quit editing."
766   (interactive "P")
767   (save-excursion
768     (when (and (or (eq major-mode 'wl-draft-mode)
769                    (eq major-mode 'mail-mode))
770                (or force-kill
771                    (yes-or-no-p "Kill Current Draft? ")))
772       (let ((cur-buf (current-buffer)))
773         (when (and wl-draft-parent-number
774                    (not (string= wl-draft-parent-folder "")))
775           (let* ((number wl-draft-parent-number)
776                  (folder-name wl-draft-parent-folder)
777                  (folder (wl-folder-get-elmo-folder folder-name))
778                  buffer)
779             (if (and (setq buffer (wl-summary-get-buffer folder-name))
780                      (with-current-buffer buffer
781                        (string= (wl-summary-buffer-folder-name)
782                                 folder-name)))
783                 (with-current-buffer buffer
784                   (elmo-folder-unset-flag folder (list number) 'answered)
785                   (when (wl-summary-jump-to-msg number)
786                     (wl-summary-update-persistent-mark)))
787               (elmo-folder-open folder 'load-msgdb)
788               (elmo-folder-unset-flag folder (list number) 'answered)
789               (elmo-folder-close folder))))
790         (wl-draft-hide cur-buf)
791         (wl-draft-delete cur-buf)))
792     (message "")))
793
794 (defun wl-draft-fcc ()
795   "Add a new Fcc field, with file name completion."
796   (interactive)
797   (or (mail-position-on-field "fcc" t)  ;Put new field after exiting Fcc.
798       (mail-position-on-field "to"))
799   (insert "\nFcc: "))
800
801 ;; Imported from message.el.
802 (defun wl-draft-elide-region (b e)
803   "Elide the text in the region.
804 An ellipsis (from `wl-draft-elide-ellipsis') will be inserted where the
805 text was killed."
806   (interactive "r")
807   (kill-region b e)
808   (insert wl-draft-elide-ellipsis))
809
810 ;; Imported from message.el.
811 (defun wl-draft-beginning-of-line (&optional n)
812   "Move point to beginning of header value or to beginning of line."
813   (interactive "p")
814   (let ((zrs 'zmacs-region-stays))
815     (when (and (interactive-p) (boundp zrs))
816       (set zrs t)))
817   (if (wl-draft-point-in-header-p)
818       (let* ((here (point))
819              (bol (progn (beginning-of-line n) (point)))
820              (eol (line-end-position))
821              (eoh (and (looking-at "[^ \t]")
822                        (re-search-forward ": *" eol t))))
823         (if (and eoh (or (> here eoh) (= here bol)))
824             (goto-char eoh)
825           (goto-char bol)))
826     (beginning-of-line n)))
827
828 (defun wl-draft-point-in-header-p ()
829   "Return t if point is in the header."
830   (save-excursion
831     (let ((p (point)))
832       (goto-char (point-min))
833       (not (re-search-forward
834             (concat "^" (regexp-quote mail-header-separator) "\n")
835             p t)))))
836
837 ;; function for wl-sent-message-via
838
839 (defmacro wl-draft-sent-message-p (type)
840   (` (eq (nth 1 (assq (, type) wl-sent-message-via)) 'sent)))
841
842 (defmacro wl-draft-set-sent-message (type result &optional server-port)
843   (` (let ((element (assq (, type) wl-sent-message-via)))
844        (if element
845            (unless (eq (nth 1 element) (, result))
846              (setcdr element (list (, result) (, server-port)))
847              (setq wl-sent-message-modified t))
848          (push (list (, type) (, result) (, server-port)) wl-sent-message-via)
849          (setq wl-sent-message-modified t)))))
850
851 (defun wl-draft-sent-message-results ()
852   (let ((results wl-sent-message-via)
853         unplugged-via sent-via)
854     (while results
855       (cond ((eq (nth 1 (car results)) 'unplugged)
856              (push (caar results) unplugged-via))
857             ((eq (nth 1 (car results)) 'sent)
858              (push (caar results) sent-via)))
859       (setq results (cdr results)))
860     (list unplugged-via sent-via)))
861
862 (defun wl-draft-write-sendlog (status proto server to id)
863   "Write send log file, if `wl-draft-sendlog' is non-nil."
864   (when wl-draft-sendlog
865     (with-temp-buffer
866       (let* ((filename (expand-file-name wl-draft-sendlog-filename
867                                          elmo-msgdb-directory))
868              (filesize (nth 7 (file-attributes filename)))
869              (server (if server (concat " server=" server) ""))
870              (to (if to (cond
871                          ((memq proto '(fcc queue))
872                           (format " folder=\"%s\"" to))
873                          ((eq proto 'nntp)
874                           (format " ng=<%s>" to))
875                          (t
876                           (concat " to="
877                                   (mapconcat
878                                    'identity
879                                    (mapcar '(lambda(x) (format "<%s>" x)) to)
880                                    ","))))
881                    ""))
882              (id (if id (concat " id=" id) ""))
883              (time (format-time-string "%Y/%m/%d %T")))
884         (insert (format "%s proto=%s stat=%s%s%s%s\n"
885                         time proto status server to id))
886         (if (and wl-draft-sendlog-max-size filesize
887                  (> filesize wl-draft-sendlog-max-size))
888             (rename-file filename (concat filename ".old") t))
889         (if (file-writable-p filename)
890             (write-region-as-binary (point-min) (point-max)
891                                     filename t 'no-msg)
892           (message "%s is not writable." filename))))))
893
894 (defun wl-draft-get-header-delimiter (&optional delete)
895   ;; If DELETE is non-nil, replace the header delimiter with a blank line
896   (let (delimline)
897     (goto-char (point-min))
898     (when (re-search-forward
899            (concat "^" (regexp-quote mail-header-separator) "$\\|^$") nil t)
900       (replace-match "")
901       (if delete
902           (forward-char -1))
903       (setq delimline (point-marker)))
904     delimline))
905
906 (defun wl-draft-send-mail-with-qmail ()
907   "Pass the prepared message buffer to qmail-inject.
908 Refer to the documentation for the variable `send-mail-function'
909 to find out how to use this."
910   (if (and wl-draft-qmail-send-plugged
911            (not (elmo-plugged-p)))
912       (wl-draft-set-sent-message 'mail 'unplugged)
913     ;; send the message
914     (run-hooks 'wl-mail-send-pre-hook) ;; X-PGP-Sig, Cancel-Lock
915     (let ((id (std11-field-body "Message-ID"))
916           (to (std11-field-body "To")))
917       (case
918           (as-binary-process
919            (apply
920             'call-process-region 1 (point-max) wl-qmail-inject-program
921             nil nil nil
922             wl-qmail-inject-args))
923         ;; qmail-inject doesn't say anything on it's stdout/stderr,
924         ;; we have to look at the retval instead
925         (0   (progn
926                (wl-draft-set-sent-message 'mail 'sent)
927                (wl-draft-write-sendlog 'ok 'qmail nil (list to) id)))
928         (1   (error "`qmail-inject' reported permanent failure"))
929         (111 (error "`qmail-inject' reported transient failure"))
930         ;; should never happen
931         (t   (error "`qmail-inject' reported unknown failure"))))))
932
933 (defun wl-draft-parse-msg-id-list-string (string)
934   "Get msg-id list from STRING."
935   (let (msg-id-list)
936     (dolist (parsed-id (std11-parse-msg-ids-string string))
937       (when (eq (car parsed-id) 'msg-id)
938         (setq msg-id-list (cons (std11-msg-id-string parsed-id)
939                                 msg-id-list))))
940     (nreverse msg-id-list)))
941
942 (defun wl-draft-eword-encode-address-list (string &optional column)
943   "Encode header field STRING as list of address, and return the result.
944 Cause an error when STRING contains invalid address.
945 Optional argument COLUMN is start-position of the field."
946   (car (eword-encode-rword-list
947         (or column eword-encode-default-start-column)
948         (eword-encode-addresses-to-rword-list
949          (wl-draft-std11-parse-addresses (std11-lexical-analyze string))))))
950
951 (defun wl-draft-std11-parse-addresses (lal)
952   (let ((ret (std11-parse-address lal)))
953     (when (and (not (and (eq (length lal) 1)
954                          (eq (car (car lal)) 'spaces)))
955                (null ret))
956       (error "Error while parsing address"))
957     (if ret
958         (let ((dest (list (car ret))))
959           (setq lal (cdr ret))
960           (while (and (setq ret (std11-parse-ascii-token lal))
961                       (string-equal (cdr (assq 'specials (car ret))) ",")
962                       (setq ret (std11-parse-address (cdr ret)))
963                       )
964             (setq dest (cons (car ret) dest))
965             (setq lal (cdr ret)))
966           (while (eq 'spaces (car (car lal)))
967             (setq lal (cdr lal)))
968           (if lal (error "Error while parsing address"))
969           (nreverse dest)))))
970
971 (defun wl-draft-parse-mailbox-list (field &optional remove-group-list)
972   "Get mailbox list of FIELD from current buffer.
973 The buffer is expected to be narrowed to just the headers of the message.
974 If optional argument REMOVE-GROUP-LIST is non-nil, remove group list content
975 from current buffer."
976   (save-excursion
977     (let ((case-fold-search t)
978           (inhibit-read-only t)
979           addresses address
980           mailbox-list beg seq has-group-list)
981       (goto-char (point-min))
982       (while (re-search-forward (concat "^" (regexp-quote field) "[\t ]*:")
983                                 nil t)
984         (setq beg (point))
985         (re-search-forward "^[^ \t]" nil 'move)
986         (beginning-of-line)
987         (skip-chars-backward "\n")
988         (setq seq (std11-lexical-analyze
989                    (buffer-substring-no-properties beg (point))))
990         (setq addresses (wl-draft-std11-parse-addresses seq))
991         (while addresses
992           (cond ((eq (car (car addresses)) 'group)
993                  (setq has-group-list t)
994                  (setq mailbox-list
995                        (nconc mailbox-list
996                               (mapcar
997                                'std11-address-string
998                                (nth 2 (car addresses))))))
999                 ((eq (car (car addresses)) 'mailbox)
1000                  (setq address (nth 1 (car addresses)))
1001                  (setq mailbox-list
1002                        (nconc mailbox-list
1003                               (list
1004                                (std11-addr-to-string
1005                                 (if (eq (car address) 'phrase-route-addr)
1006                                     (nth 2 address)
1007                                   (cdr address))))))))
1008           (setq addresses (cdr addresses)))
1009         (when (and remove-group-list has-group-list)
1010           (delete-region beg (point))
1011           (insert (wl-address-string-without-group-list-contents seq))))
1012       mailbox-list)))
1013
1014 (defun wl-draft-deduce-address-list (buffer header-start header-end)
1015   "Get address list suitable for smtp RCPT TO:<address>.
1016 Group list content is removed if `wl-draft-remove-group-list-contents' is
1017 non-nil."
1018   (let ((fields (if (and wl-draft-doing-mime-bcc
1019                          wl-draft-disable-bcc-for-mime-bcc)
1020                     '("to" "cc")
1021                   '("to" "cc" "bcc")))
1022         (resent-fields '("resent-to" "resent-cc" "resent-bcc"))
1023         (case-fold-search t)
1024         addrs recipients)
1025     (save-excursion
1026       (save-restriction
1027         (narrow-to-region header-start header-end)
1028         (goto-char (point-min))
1029         (save-excursion
1030           (if (re-search-forward "^resent-to[\t ]*:" nil t)
1031               (setq fields resent-fields)))
1032         (while fields
1033           (setq recipients
1034                 (nconc recipients
1035                        (wl-draft-parse-mailbox-list
1036                         (car fields)
1037                         wl-draft-remove-group-list-contents)))
1038           (setq fields (cdr fields)))
1039         recipients))))
1040
1041 ;;
1042 ;; from Semi-gnus
1043 ;;
1044 (defun wl-draft-send-mail-with-smtp ()
1045   "Send the prepared message buffer with SMTP."
1046   (require 'smtp)
1047   (let* ((errbuf (if mail-interactive
1048                      (generate-new-buffer " smtp errors")
1049                    0))
1050          (case-fold-search t)
1051          (default-case-fold-search t)
1052          (sender (or wl-envelope-from
1053                      (wl-address-header-extract-address wl-from)))
1054          (delimline (save-excursion
1055                       (goto-char (point-min))
1056                       (re-search-forward
1057                        (concat "^" (regexp-quote mail-header-separator)
1058                                "$\\|^$") nil t)
1059                       (point-marker)))
1060          (smtp-server
1061           (or wl-smtp-posting-server smtp-server "localhost"))
1062          (smtp-service (or wl-smtp-posting-port smtp-service))
1063          (smtp-local-domain (or smtp-local-domain wl-local-domain))
1064          (id (std11-field-body "message-id"))
1065          recipients)
1066     (if (not (elmo-plugged-p smtp-server smtp-service))
1067         (wl-draft-set-sent-message 'mail 'unplugged
1068                                    (cons smtp-server smtp-service))
1069       (unwind-protect
1070           (save-excursion
1071             ;; Instead of `smtp-deduce-address-list'.
1072             (setq recipients (wl-draft-deduce-address-list
1073                               (current-buffer) (point-min) delimline))
1074             (unless recipients (error "No recipients"))
1075             ;; Insert an extra newline if we need it to work around
1076             ;; Sun's bug that swallows newlines.
1077             (goto-char (1+ delimline))
1078             (if (eval mail-mailer-swallows-blank-line)
1079                 (newline))
1080             (run-hooks 'wl-mail-send-pre-hook) ;; X-PGP-Sig, Cancel-Lock
1081             (if mail-interactive
1082                 (save-excursion
1083                   (set-buffer errbuf)
1084                   (erase-buffer)))
1085             (wl-draft-delete-field "bcc" delimline)
1086             (wl-draft-delete-field "resent-bcc" delimline)
1087             (let (process-connection-type)
1088               (as-binary-process
1089                (when recipients
1090                  (wl-smtp-extension-bind
1091                   (condition-case err
1092                       (smtp-send-buffer sender recipients (current-buffer))
1093                     (error
1094                      (wl-draft-write-sendlog 'failed 'smtp smtp-server
1095                                              recipients id)
1096                      (if (and (eq (car err) 'smtp-response-error)
1097                               (= (nth 1 err) 535))
1098                          (elmo-remove-passwd
1099                           (wl-smtp-password-key
1100                            smtp-sasl-user-name
1101                            (car smtp-sasl-mechanisms)
1102                            smtp-server)))
1103                      (signal (car err) (cdr err)))
1104                     (quit
1105                      (wl-draft-write-sendlog 'uncertain 'smtp smtp-server
1106                                              recipients id)
1107                      (signal (car err) (cdr err)))))
1108                  (wl-draft-set-sent-message 'mail 'sent)
1109                  (wl-draft-write-sendlog
1110                   'ok 'smtp smtp-server recipients id)))))
1111         (if (bufferp errbuf)
1112             (kill-buffer errbuf))))))
1113
1114 (defun wl-draft-send-mail-with-pop-before-smtp ()
1115   "Send the prepared message buffer with POP-before-SMTP."
1116   (require 'elmo-pop3)
1117   (let ((folder
1118          (luna-make-entity
1119           'elmo-pop3-folder
1120           :user   (or wl-pop-before-smtp-user
1121                       elmo-pop3-default-user)
1122           :server (or wl-pop-before-smtp-server
1123                       elmo-pop3-default-server)
1124           :port   (or wl-pop-before-smtp-port
1125                       elmo-pop3-default-port)
1126           :auth   (or wl-pop-before-smtp-authenticate-type
1127                       elmo-pop3-default-authenticate-type)
1128           :stream-type (elmo-get-network-stream-type
1129                         (or wl-pop-before-smtp-stream-type
1130                             elmo-pop3-default-stream-type))))
1131         session)
1132     (condition-case error
1133         (progn
1134           (setq session (elmo-pop3-get-session folder))
1135           (when session (elmo-network-close-session session)))
1136       (error
1137        (unless (string= (nth 1 error) "Unplugged")
1138          (signal (car error) (cdr error))))))
1139   (wl-draft-send-mail-with-smtp))
1140
1141 (defun wl-draft-insert-required-fields (&optional force-msgid)
1142   "Insert Message-ID, Date, and From field.
1143 If FORCE-MSGID, insert message-id regardless of `wl-insert-message-id'."
1144   ;; Insert Message-Id field...
1145   (goto-char (point-min))
1146   (when (and (or force-msgid
1147                  wl-insert-message-id)
1148              (not (re-search-forward "^Message-ID[ \t]*:" nil t)))
1149     (insert (concat "Message-ID: "
1150                     (funcall wl-message-id-function)
1151                     "\n")))
1152   ;; Insert date field.
1153   (goto-char (point-min))
1154   (or (re-search-forward "^Date[ \t]*:" nil t)
1155       (wl-draft-insert-date-field))
1156   ;; Insert from field.
1157   (goto-char (point-min))
1158   (or (re-search-forward "^From[ \t]*:" nil t)
1159       (wl-draft-insert-from-field)))
1160
1161 (defun wl-draft-normal-send-func (editing-buffer kill-when-done)
1162   "Send the message in the current buffer."
1163   (save-restriction
1164     (narrow-to-region (goto-char (point-min))
1165                       (if (re-search-forward
1166                            (concat
1167                             "^" (regexp-quote mail-header-separator) "$")
1168                            nil t)
1169                           (match-beginning 0)
1170                         (point-max)))
1171     (wl-draft-insert-required-fields)
1172     ;; ignore any blank lines in the header
1173     (while (progn (goto-char (point-min))
1174                   (re-search-forward "\n[ \t]*\n\n*" nil t))
1175       (replace-match "\n"))
1176     (goto-char (point-min))
1177     (while (re-search-forward 
1178             "^[^ \t\n:]+:[ \t]*\\(.*\\(\n[ \t].*\\)*\\)\n"
1179             nil t)
1180       (when (string= "" (match-string 1))
1181         (replace-match ""))))
1182 ;;;  (run-hooks 'wl-mail-send-pre-hook) ;; X-PGP-Sig, Cancel-Lock
1183   (wl-draft-dispatch-message)
1184   (when kill-when-done
1185     ;; hide editing-buffer.
1186     (wl-draft-hide editing-buffer)
1187     ;; delete editing-buffer and its file.
1188     (wl-draft-delete editing-buffer)))
1189
1190 (defun wl-draft-dispatch-message (&optional mes-string)
1191   "Send the message in the current buffer.  Not modified the header fields."
1192   (let (delimline mime-bcc)
1193     (if (and wl-draft-verbose-send mes-string)
1194         (message "%s" mes-string))
1195     ;; get fcc folders.
1196     (setq delimline (wl-draft-get-header-delimiter t))
1197     (unless wl-draft-fcc-list
1198       (setq wl-draft-fcc-list (wl-draft-get-fcc-list delimline)))
1199     ;;
1200     (setq wl-sent-message-modified nil)
1201     (unwind-protect
1202         (progn
1203           (if (and (wl-message-mail-p)
1204                    (not (wl-draft-sent-message-p 'mail)))
1205               (if (or (not (or wl-draft-force-queuing
1206                                wl-draft-force-queuing-mail))
1207                       (memq 'mail wl-sent-message-queued))
1208                   (progn
1209                     (setq mime-bcc (wl-draft-mime-bcc-field))
1210                     (funcall wl-draft-send-mail-function)
1211                     (when (not (zerop (length mime-bcc)))
1212                       (wl-draft-do-mime-bcc mime-bcc)))
1213                 (push 'mail wl-sent-message-queued)
1214                 (wl-draft-set-sent-message 'mail 'unplugged)))
1215           (if (and (wl-message-news-p)
1216                    (not (wl-draft-sent-message-p 'news))
1217                    (not (wl-message-field-exists-p "Resent-to")))
1218               (if (or (not (or wl-draft-force-queuing
1219                                wl-draft-force-queuing-news))
1220                       (memq 'news wl-sent-message-queued))
1221                   (funcall wl-draft-send-news-function)
1222                 (push 'news wl-sent-message-queued)
1223                 (wl-draft-set-sent-message 'news 'unplugged))))
1224       (let* ((status (wl-draft-sent-message-results))
1225              (unplugged-via (car status))
1226              (sent-via (nth 1 status)))
1227         ;; If one sent, process fcc folder.
1228         (if (and sent-via wl-draft-fcc-list)
1229             (progn
1230               (wl-draft-do-fcc (wl-draft-get-header-delimiter)
1231                                wl-draft-fcc-list)
1232               (setq wl-draft-fcc-list nil)))
1233         (if wl-draft-use-cache
1234             (let ((id (std11-field-body "Message-ID"))
1235                   (elmo-enable-disconnected-operation t))
1236               (elmo-file-cache-save (elmo-file-cache-get-path id)
1237                                     nil)))
1238         ;; If one unplugged, append queue.
1239         (when (and unplugged-via
1240                    wl-sent-message-modified)
1241           (if wl-draft-enable-queuing
1242               (progn
1243                 (wl-draft-queue-append wl-sent-message-via)
1244                 (setq wl-sent-message-modified 'requeue))
1245             (error "Unplugged")))
1246         (when wl-draft-verbose-send
1247           (if (and unplugged-via sent-via);; combined message
1248               (progn
1249                 (setq wl-draft-verbose-msg
1250                       (format "Sending%s and Queuing%s..."
1251                               sent-via unplugged-via))
1252                 (message "%sdone" wl-draft-verbose-msg))
1253             (if mes-string
1254                 (message "%s%s"
1255                          mes-string
1256                          (if sent-via "done" "failed"))))))))
1257   (not wl-sent-message-modified)) ;; return value
1258
1259 (defun wl-draft-raw-send (&optional kill-when-done force-pre-hook mes-string)
1260   "Force send current buffer as raw message."
1261   (interactive)
1262   (save-excursion
1263     (let (wl-interactive-send
1264 ;;;       wl-draft-verbose-send
1265           (wl-mail-send-pre-hook (and force-pre-hook wl-mail-send-pre-hook))
1266           (wl-news-send-pre-hook (and force-pre-hook wl-news-send-pre-hook))
1267           mail-send-hook
1268           mail-send-actions)
1269       (wl-draft-send kill-when-done mes-string))))
1270
1271 (defun wl-draft-clone-local-variables ()
1272   (let ((locals (buffer-local-variables))
1273         result)
1274     (while locals
1275       (when (and (consp (car locals))
1276                  (car (car locals))
1277                  (string-match wl-draft-clone-local-variable-regexp
1278                                (symbol-name (car (car locals)))))
1279         (wl-append result (list (car (car locals)))))
1280       (setq locals (cdr locals)))
1281     result))
1282
1283 (defcustom wl-draft-send-confirm-with-preview t
1284   "Non-nil to invoke preview through confirmation of sending.
1285 This variable is valid when `wl-interactive-send' has non-nil value."
1286   :type 'boolean
1287   :group 'wl-draft)
1288
1289 (defun wl-draft-send-confirm ()
1290   (let (answer)
1291     (unwind-protect
1292         (condition-case quit
1293             (progn
1294               (when wl-draft-send-confirm-with-preview
1295                 (wl-draft-preview-message))
1296               (save-excursion
1297                 (goto-char (point-min)) ; to show recipients in header
1298                 (catch 'done
1299                   (while t
1300                     (discard-input)
1301                     (message "Send current draft? <y/n/j(down)/k(up)> ")
1302                     (setq answer (let ((cursor-in-echo-area t)) (read-char)))
1303                     (cond
1304                      ((or (eq answer ?y)
1305                           (eq answer ?Y)
1306                           (eq answer ? ))
1307                   (throw 'done t))
1308                      ((or (eq answer ?v)
1309                           (eq answer ?j)
1310                           (eq answer ?J))
1311                       (condition-case err
1312                           (scroll-up)
1313                         (error nil)))
1314                      ((or (eq answer ?^)
1315                           (eq answer ?k)
1316                           (eq answer ?K))
1317                       (condition-case err
1318                           (scroll-down)
1319                         (error nil)))
1320                      (t
1321                       (throw 'done nil)))))))
1322           (quit nil))
1323       (when wl-draft-send-confirm-with-preview
1324         (mime-preview-quit)))))
1325
1326 (defun wl-draft-send (&optional kill-when-done mes-string)
1327   "Send current draft message.
1328 If KILL-WHEN-DONE is non-nil, current draft buffer is killed"
1329   (interactive)
1330   ;; Don't call this explicitly.
1331   ;; Added to 'wl-draft-send-hook (by teranisi)
1332   ;; (wl-draft-config-exec)
1333   (run-hooks 'wl-draft-send-hook)
1334   (when (or (not wl-interactive-send)
1335             (wl-draft-send-confirm))
1336     (let ((send-mail-function 'wl-draft-raw-send)
1337           (editing-buffer (current-buffer))
1338           (sending-buffer (wl-draft-generate-clone-buffer
1339                            " *wl-draft-sending-buffer*"
1340                            (append wl-draft-config-variables
1341                                    (wl-draft-clone-local-variables))))
1342           (wl-draft-verbose-msg nil)
1343           err)
1344       (unwind-protect
1345           (save-excursion
1346             (set-buffer sending-buffer)
1347             (if (and (not (wl-message-mail-p))
1348                      (not (wl-message-news-p)))
1349                 (error "No recipient is specified"))
1350             (expand-abbrev)             ; for mail-abbrevs
1351             (let ((mime-header-encode-method-alist
1352                    (append
1353                     '((wl-draft-eword-encode-address-list
1354                        .  (To Cc Bcc Resent-To Resent-Cc Resent-Bcc From)))
1355                     (if (boundp 'mime-header-encode-method-alist)
1356                         (symbol-value 'mime-header-encode-method-alist)))))
1357               (run-hooks 'mail-send-hook) ; translate buffer
1358               )
1359             ;;
1360             (if wl-draft-verbose-send
1361                 (message "%s" (or mes-string "Sending...")))
1362             (funcall wl-draft-send-function editing-buffer kill-when-done)
1363             ;; Now perform actions on successful sending.
1364             (while mail-send-actions
1365               (condition-case ()
1366                   (apply (car (car mail-send-actions))
1367                          (cdr (car mail-send-actions)))
1368                 (error))
1369               (setq mail-send-actions (cdr mail-send-actions)))
1370             (if wl-draft-verbose-send
1371                 (message "%sdone"
1372                          (or wl-draft-verbose-msg
1373                              mes-string
1374                              "Sending..."))))
1375         ;; kill sending buffer, anyway.
1376         (and (buffer-live-p sending-buffer)
1377              (kill-buffer sending-buffer))))))
1378
1379 (defun wl-draft-mime-bcc-field ()
1380   "Return the MIME-Bcc field body.  The field is deleted."
1381   (prog1 (std11-field-body wl-draft-mime-bcc-field-name)
1382     (wl-draft-delete-field wl-draft-mime-bcc-field-name)))
1383
1384 (defun wl-draft-do-mime-bcc (field-body)
1385   "Send MIME-Bcc (Encapsulated blind carbon copy)."
1386   (let ((orig-from (mime-decode-field-body (std11-field-body "from")
1387                                            'From))
1388         (orig-subj (mime-decode-field-body (or (std11-field-body "subject")
1389                                                "")
1390                                            'Subject))
1391         (recipients (wl-parse-addresses field-body))
1392         (draft-buffer (current-buffer))
1393         wl-draft-use-frame)
1394     (save-window-excursion
1395       (when (and (not wl-draft-doing-mime-bcc) ; To avoid infinite loop.
1396                  (not (zerop (length field-body))))
1397         (let ((wl-draft-doing-mime-bcc t))
1398           (dolist (recipient recipients)
1399             (wl-draft-create-buffer)
1400             (wl-draft-create-contents
1401              (append `((From . ,orig-from)
1402                        (To . ,recipient)
1403                        (Subject . ,(concat "A blind carbon copy ("
1404                                            orig-subj
1405                                            ")")))
1406                      (wl-draft-default-headers)))
1407             (wl-draft-insert-mail-header-separator)
1408             (wl-draft-prepare-edit)
1409             (goto-char (point-max))
1410             (insert (or wl-draft-mime-bcc-body
1411                         "This is a blind carbon copy.")
1412                     "\n")
1413             (mime-edit-insert-tag "message" "rfc822")
1414             (insert-buffer draft-buffer)
1415             (let (wl-interactive-send)
1416               (wl-draft-send 'kill-when-done))))))))
1417
1418 (defun wl-draft-save ()
1419   "Save current draft."
1420   (interactive)
1421   (if (buffer-modified-p)
1422       (progn
1423         (message "Saving...")
1424         (let ((msg (buffer-substring-no-properties (point-min) (point-max)))
1425               next-number)
1426           (when wl-draft-buffer-message-number
1427             (elmo-folder-delete-messages (wl-draft-get-folder)
1428                                          (list wl-draft-buffer-message-number))
1429             (wl-draft-config-info-operation wl-draft-buffer-message-number
1430                                             'delete))
1431           (elmo-folder-check (wl-draft-get-folder))
1432           ;; If no header separator, insert it.
1433           (with-temp-buffer
1434             (insert msg)
1435             (goto-char (point-min))
1436             (unless (re-search-forward
1437                      (concat "^" (regexp-quote mail-header-separator) "$")
1438                      nil t)
1439               (goto-char (point-min))
1440               (if (re-search-forward "\n\n" nil t)
1441                   (replace-match (concat "\n" mail-header-separator "\n"))
1442                 (goto-char (point-max))
1443                 (insert (if (eq (char-before) ?\n) "" "\n")
1444                         mail-header-separator "\n")))
1445             (let ((mime-header-encode-method-alist
1446                    '((eword-encode-unstructured-field-body))))
1447               (mime-edit-translate-buffer))
1448             (wl-draft-get-header-delimiter t)
1449             (setq next-number
1450                   (elmo-folder-next-message-number (wl-draft-get-folder)))
1451             (elmo-folder-append-buffer (wl-draft-get-folder)))
1452           (elmo-folder-check (wl-draft-get-folder))
1453           (elmo-folder-commit (wl-draft-get-folder))
1454           (setq wl-draft-buffer-message-number next-number)
1455           (rename-buffer (format "%s/%d" wl-draft-folder next-number))
1456           (setq buffer-file-name (buffer-name))
1457           (set-buffer-modified-p nil)
1458           (wl-draft-config-info-operation wl-draft-buffer-message-number 'save)
1459           (message "Saving...done")))
1460     (message "(No changes need to be saved)")))
1461
1462 (defun wl-draft-mimic-kill-buffer ()
1463   "Kill the current (draft) buffer with query."
1464   (interactive)
1465   (let ((bufname (read-buffer (format "Kill buffer: (default %s) "
1466                                       (buffer-name))))
1467         wl-draft-use-frame)
1468     (if (or (not bufname)
1469             (string-equal bufname "")
1470             (string-equal bufname (buffer-name)))
1471         (let ((bufname (current-buffer)))
1472           (when (or (not (buffer-modified-p))
1473                     (yes-or-no-p
1474                      (format "Buffer %s modified; kill anyway? " bufname)))
1475             (set-buffer-modified-p nil)
1476             (wl-draft-hide bufname)
1477             (kill-buffer bufname)))
1478       (kill-buffer bufname))))
1479
1480 (defun wl-draft-save-and-exit ()
1481   "Save current draft and exit current draft mode."
1482   (interactive)
1483   (wl-draft-save)
1484   (let ((editing-buffer (current-buffer)))
1485     (wl-draft-hide editing-buffer)
1486     (kill-buffer editing-buffer)))
1487
1488 (defun wl-draft-send-and-exit ()
1489   "Send current draft message and kill it."
1490   (interactive)
1491   (wl-draft-send t))
1492
1493 (defun wl-draft-send-from-toolbar ()
1494   (interactive)
1495   (let ((wl-interactive-send t))
1496     (wl-draft-send-and-exit)))
1497
1498 (defun wl-draft-delete-field (field &optional delimline replace)
1499   (wl-draft-delete-fields (regexp-quote field) delimline replace))
1500
1501 (defun wl-draft-delete-fields (field &optional delimline replace)
1502   (save-restriction
1503     (unless delimline
1504       (goto-char (point-min))
1505       (if (search-forward "\n\n" nil t)
1506           (setq delimline (point))
1507         (setq delimline (point-max))))
1508     (narrow-to-region (point-min) delimline)
1509     (goto-char (point-min))
1510     (let ((regexp (concat "^" field ":"))
1511           (case-fold-search t))
1512       (while (not (eobp))
1513         (if (looking-at regexp)
1514             (progn
1515               (delete-region
1516                (point)
1517                (progn
1518                  (forward-line 1)
1519                  (if (re-search-forward "^[^ \t]" nil t)
1520                      (goto-char (match-beginning 0))
1521                    (point-max))))
1522               (if replace
1523                   (insert (concat field ": " replace "\n"))))
1524           (forward-line 1)
1525           (if (re-search-forward "^[^ \t]" nil t)
1526               (goto-char (match-beginning 0))
1527             (point-max)))))))
1528
1529 (defun wl-draft-get-fcc-list (header-end)
1530   (if (and wl-draft-doing-mime-bcc
1531            wl-draft-disable-fcc-for-mime-bcc)
1532       (progn
1533         (wl-draft-delete-field "fcc")
1534         nil)
1535     (let (fcc-list
1536           (case-fold-search t))
1537       (or (markerp header-end) (error "HEADER-END must be a marker"))
1538       (save-excursion
1539         (goto-char (point-min))
1540         (while (re-search-forward "^Fcc:[ \t]*" header-end t)
1541           (save-match-data
1542             (setq fcc-list
1543                   (append fcc-list
1544                           (split-string
1545                            (buffer-substring-no-properties
1546                             (point)
1547                             (progn
1548                               (end-of-line)
1549                               (skip-chars-backward " \t")
1550                               (point)))
1551                            ",[ \t]*")))
1552             (dolist (folder fcc-list)
1553               (wl-folder-confirm-existence
1554                (wl-folder-get-elmo-folder (eword-decode-string folder)))))
1555           (delete-region (match-beginning 0)
1556                          (progn (forward-line 1) (point)))))
1557       fcc-list)))
1558
1559 (defcustom wl-draft-fcc-append-read-folder-history t
1560   "Non-nil to append fcc'ed folder to `wl-read-folder-history'."
1561   :type 'boolean
1562   :group 'wl-draft)
1563
1564 (defun wl-draft-do-fcc (header-end &optional fcc-list)
1565   (let ((send-mail-buffer (current-buffer))
1566         (tembuf (generate-new-buffer " fcc output"))
1567         (case-fold-search t)
1568         beg end)
1569     (or (markerp header-end) (error "HEADER-END must be a marker"))
1570     (save-excursion
1571       (unless fcc-list
1572         (setq fcc-list (wl-draft-get-fcc-list header-end)))
1573       (set-buffer tembuf)
1574       (erase-buffer)
1575       ;; insert just the headers to avoid moving the gap more than
1576       ;; necessary (the message body could be arbitrarily huge.)
1577       (insert-buffer-substring send-mail-buffer 1 header-end)
1578       (wl-draft-insert-required-fields t)
1579       (goto-char (point-max))
1580       (insert-buffer-substring send-mail-buffer header-end)
1581       (let ((id (std11-field-body "Message-ID"))
1582             (elmo-enable-disconnected-operation t)
1583             cache-saved)
1584         (while fcc-list
1585           (unless (or cache-saved
1586                       (elmo-folder-plugged-p
1587                        (wl-folder-get-elmo-folder (car fcc-list))))
1588             (elmo-file-cache-save id nil) ;; for disconnected operation
1589             (setq cache-saved t))
1590           (if (elmo-folder-append-buffer
1591                (wl-folder-get-elmo-folder
1592                 (eword-decode-string (car fcc-list)))
1593                (and wl-fcc-force-as-read '(read)))
1594               (wl-draft-write-sendlog 'ok 'fcc nil (car fcc-list) id)
1595             (wl-draft-write-sendlog 'failed 'fcc nil (car fcc-list) id))
1596           (if (and wl-draft-fcc-append-read-folder-history
1597                    (boundp 'wl-read-folder-history))
1598               (or (equal (car fcc-list) (car wl-read-folder-history))
1599                   (setq wl-read-folder-history
1600                         (append (list (car fcc-list)) wl-read-folder-history))))
1601           (setq fcc-list (cdr fcc-list)))))
1602     (kill-buffer tembuf)))
1603
1604 (defun wl-draft-on-field-p ()
1605   (if (< (point)
1606          (save-excursion
1607            (goto-char (point-min))
1608            (search-forward (concat "\n" mail-header-separator "\n") nil 0)
1609            (point)))
1610       (if (bolp)
1611           (if (bobp)
1612               t
1613             (save-excursion
1614               (forward-line -1)
1615               (if (or (looking-at ".*,[ \t]?$")
1616                       (looking-at "^[^ \t]+:[ \t]+.*:$")); group list name
1617                   nil t)))
1618         (let ((pos (point)))
1619           (save-excursion
1620             (beginning-of-line)
1621             (if (looking-at "^[ \t]")
1622                 nil
1623               (if (re-search-forward ":" pos t) nil t)))))))
1624
1625 ;;;;;;;;;;;;;;;;
1626 ;;;###autoload
1627 (defun wl-draft (&optional header-alist
1628                            content-type content-transfer-encoding
1629                            body edit-again
1630                            parent-folder)
1631   "Write and send mail/news message with Wanderlust."
1632   (interactive)
1633   (require 'wl)
1634   (unless wl-init
1635     (wl-load-profile)
1636     (wl-folder-init)
1637     (elmo-init)
1638     (wl-plugged-init t))
1639   (let (wl-demo)
1640     (wl-init)) ; returns immediately if already initialized.
1641
1642
1643   (let (buffer header-alist-internal)
1644     (setq buffer (wl-draft-create-buffer parent-folder))
1645     (unless (cdr (assq 'From header-alist))
1646       (setq header-alist
1647             (append (list (cons 'From wl-from)) header-alist)))
1648     (unless (cdr (assq 'To header-alist))
1649       (let ((to))
1650         (when (setq to (and
1651                         (interactive-p)
1652                         ""))
1653           (if (assq 'To header-alist)
1654               (setcdr (assq 'To header-alist) to)
1655             (setq header-alist
1656                   (append header-alist
1657                           (list (cons 'To to))))))))
1658     (unless (cdr (assq 'Subject header-alist))
1659       (if (assq 'Subject header-alist)
1660           (setcdr (assq 'Subject header-alist) "")
1661         (setq header-alist
1662               (append header-alist (list (cons 'Subject ""))))))
1663     (setq header-alist (append header-alist
1664                                (wl-draft-default-headers)
1665                                wl-draft-additional-header-alist
1666                                (if body (list "" (cons 'Body body)))))
1667     (wl-draft-create-contents header-alist)
1668     (if edit-again
1669         (wl-draft-decode-body
1670          content-type content-transfer-encoding))
1671     (wl-draft-insert-mail-header-separator)
1672     (wl-draft-prepare-edit)
1673     (if (interactive-p)
1674         (run-hooks 'wl-mail-setup-hook))
1675     (goto-char (point-min))
1676     (setq buffer-undo-list nil)
1677     (wl-user-agent-compose-internal) ;; user-agent
1678     (cond ((and
1679             (interactive-p)
1680             (string= (cdr (assq 'To header-alist)) ""))
1681            (mail-position-on-field "To"))
1682           (t
1683            (goto-char (point-max))))
1684     buffer))
1685
1686 (defun wl-draft-create-buffer (&optional parent-folder)
1687   (let* ((draft-folder (wl-draft-get-folder))
1688          (parent-folder (or parent-folder (wl-summary-buffer-folder-name)))
1689          (summary-buf (wl-summary-get-buffer parent-folder))
1690          (reply-or-forward
1691           (or (eq this-command 'wl-summary-reply)
1692               (eq this-command 'wl-summary-reply-with-citation)
1693               (eq this-command 'wl-summary-forward)
1694               (eq this-command 'wl-summary-target-mark-forward)
1695               (eq this-command 'wl-summary-target-mark-reply-with-citation)))
1696          (buffer (generate-new-buffer "*draft*")) ; Just for initial name.
1697          change-major-mode-hook)
1698     (set-buffer buffer)
1699     ;; switch-buffer according to draft buffer style.
1700     (if wl-draft-use-frame
1701         (switch-to-buffer-other-frame buffer)
1702       (if reply-or-forward
1703           (case wl-draft-reply-buffer-style
1704             (split
1705              (split-window-vertically)
1706              (other-window 1)
1707              (switch-to-buffer buffer))
1708             (keep
1709              (switch-to-buffer buffer))
1710             (full
1711              (delete-other-windows)
1712              (switch-to-buffer buffer))
1713             (t
1714              (if (functionp wl-draft-reply-buffer-style)
1715                  (funcall wl-draft-reply-buffer-style buffer)
1716                (error "Invalid value for wl-draft-reply-buffer-style"))))
1717         (case wl-draft-buffer-style
1718           (split
1719            (when (eq major-mode 'wl-summary-mode)
1720              (wl-summary-toggle-disp-msg 'off))
1721            (split-window-vertically)
1722            (other-window 1)
1723            (switch-to-buffer buffer))
1724           (keep
1725            (switch-to-buffer buffer))
1726           (full
1727            (delete-other-windows)
1728            (switch-to-buffer buffer))
1729           (t (if (functionp wl-draft-buffer-style)
1730                  (funcall wl-draft-buffer-style buffer)
1731                (error "Invalid value for wl-draft-buffer-style"))))))
1732     (auto-save-mode -1)
1733     (wl-draft-mode)
1734     (set-buffer-multibyte t)            ; draft buffer is always multibyte.
1735     (make-local-variable 'truncate-partial-width-windows)
1736     (setq truncate-partial-width-windows nil)
1737     (setq truncate-lines wl-draft-truncate-lines)
1738     (setq wl-sent-message-via nil)
1739     (setq wl-sent-message-queued nil)
1740     (setq wl-draft-config-exec-flag t)
1741     (setq wl-draft-parent-folder (or parent-folder ""))
1742     (or (eq this-command 'wl-folder-write-current-folder)
1743         (setq wl-draft-buffer-cur-summary-buffer summary-buf))
1744     buffer))
1745
1746 (defun wl-draft-create-contents (header-alist)
1747   "header-alist' sample
1748 '(function  ;; funcall
1749   string    ;; insert string
1750   (symbol . string)    ;;  insert symbol-value: string
1751   (symbol . function)  ;;  (funcall) and if it returns string,
1752                        ;;  insert symbol-value: string
1753   (symbol . nil)       ;;  do nothing
1754   nil                  ;;  do nothing
1755   )"
1756   (unless (eq major-mode 'wl-draft-mode)
1757     (error "`wl-draft-create-header' must be use in wl-draft-mode"))
1758   (let ((halist header-alist)
1759         field value)
1760     (while halist
1761       (cond
1762        ;; function
1763        ((functionp (car halist)) (funcall (car halist)))
1764        ;; string
1765        ((stringp (car halist)) (insert (car halist) "\n"))
1766        ;; cons
1767        ((consp (car halist))
1768         (setq field (car (car halist)))
1769         (setq value (cdr (car halist)))
1770         (cond
1771          ((symbolp field)
1772           (cond
1773            ((eq field 'Body) ; body
1774             (insert value))
1775            ((stringp value) (insert (symbol-name field) ": " value "\n"))
1776            ((functionp value)
1777             (let ((value-return (funcall value)))
1778               (when (stringp value-return)
1779                 (insert (symbol-name field) ": " value-return "\n"))))
1780            ((not value))
1781            (t
1782             (debug))))
1783          ;;
1784          ((not field))
1785          (t
1786           (debug))
1787          )))
1788       (setq halist (cdr halist)))))
1789
1790 (defun wl-draft-prepare-edit ()
1791   (unless (eq major-mode 'wl-draft-mode)
1792     (error "`wl-draft-create-header' must be use in wl-draft-mode"))
1793   (let (change-major-mode-hook)
1794     (wl-draft-editor-mode)
1795     (static-when (boundp 'auto-save-file-name-transforms)
1796       (make-local-variable 'auto-save-file-name-transforms)
1797       (setq auto-save-file-name-transforms
1798             (cons (list (concat (regexp-quote wl-draft-folder)
1799                                 "/\\([0-9]+\\)")
1800                         (concat (expand-file-name
1801                                  "auto-save-"
1802                                  (elmo-folder-msgdb-path
1803                                   (wl-draft-get-folder)))
1804                                 "\\1"))
1805                   auto-save-file-name-transforms)))
1806     (when wl-draft-write-file-function
1807       (add-hook 'local-write-file-hooks wl-draft-write-file-function))
1808     (wl-draft-overload-functions)
1809     (wl-highlight-headers 'for-draft)
1810     (wl-draft-save)
1811     (clear-visited-file-modtime)))
1812
1813 (defun wl-draft-decode-header ()
1814   (save-excursion
1815     (std11-narrow-to-header)
1816     (wl-draft-decode-message-in-buffer)
1817     (widen)))
1818
1819 (defun wl-draft-decode-body (&optional content-type content-transfer-encoding)
1820   (let ((content-type
1821          (or content-type
1822                 (std11-field-body "content-type")))
1823         (content-transfer-encoding
1824          (or content-transfer-encoding
1825              (std11-field-body "content-transfer-encoding")))
1826         delimline)
1827     (save-excursion
1828       (std11-narrow-to-header)
1829       (wl-draft-delete-field "content-type")
1830       (wl-draft-delete-field "content-transfer-encoding")
1831       (goto-char (point-max))
1832       (setq delimline (point-marker))
1833       (widen)
1834       (narrow-to-region delimline (point-max))
1835       (goto-char (point-min))
1836       (when content-type
1837         (insert "Content-type: " content-type "\n"))
1838       (when content-transfer-encoding
1839         (insert "Content-Transfer-Encoding: " content-transfer-encoding "\n"))
1840       (wl-draft-decode-message-in-buffer)
1841       (goto-char (point-min))
1842       (unless (re-search-forward "^$" (point-at-eol) t)
1843         (insert "\n"))
1844       (widen)
1845       delimline)))
1846
1847 ;;; subroutine for wl-draft-create-contents
1848 ;;; must be used in wl-draft-mode
1849 (defun wl-draft-check-new-line ()
1850   (if (not (= (preceding-char) ?\n))
1851       (insert ?\n)))
1852
1853 (defsubst wl-draft-trim-ccs (cc)
1854   (let ((field
1855          (if (functionp cc)
1856              (funcall cc)
1857            cc)))
1858     (if (and field
1859              (null (and wl-draft-delete-myself-from-bcc-fcc
1860                         (elmo-list-member
1861                          (mapcar 'wl-address-header-extract-address
1862                                  (append
1863                                   (wl-parse-addresses (std11-field-body "To"))
1864                                   (wl-parse-addresses (std11-field-body "Cc"))))
1865                          (mapcar 'downcase wl-subscribed-mailing-list)))))
1866         field
1867       nil)))
1868
1869 (defsubst wl-draft-default-headers ()
1870   (list
1871    (cons 'Mail-Reply-To (and wl-insert-mail-reply-to
1872                              (wl-address-header-extract-address
1873                               wl-from)))
1874    (cons 'User-Agent wl-generate-mailer-string-function)
1875    (cons 'Reply-To mail-default-reply-to)
1876    (cons 'Bcc (function
1877                (lambda ()
1878                  (wl-draft-trim-ccs
1879                   (or wl-bcc (and mail-self-blind (user-login-name)))))))
1880    (cons 'Fcc (function
1881                (lambda ()
1882                  (wl-draft-trim-ccs wl-fcc))))
1883    (cons 'Organization wl-organization)
1884    (and wl-auto-insert-x-face
1885         (file-exists-p wl-x-face-file)
1886         'wl-draft-insert-x-face-field-here) ;; allow nil
1887    mail-default-headers
1888    ;; check \n at th end of line for `mail-default-headers'
1889    'wl-draft-check-new-line
1890    ))
1891
1892 (defun wl-draft-insert-mail-header-separator (&optional delimline)
1893   (save-excursion
1894     (if delimline
1895         (goto-char delimline)
1896       (goto-char (point-min))
1897       (if (search-forward "\n\n" nil t)
1898           (delete-backward-char 1)
1899         (goto-char (point-max))))
1900     (wl-draft-check-new-line)
1901     (put-text-property (point)
1902                        (progn
1903                          (insert mail-header-separator "\n")
1904                          (1- (point)))
1905                        'category 'mail-header-separator)
1906     (point)))
1907
1908 ;;;;;;;;;;;;;;;;
1909
1910 (defun wl-draft-elmo-nntp-send ()
1911   (let ((elmo-nntp-post-pre-hook wl-news-send-pre-hook)
1912         (elmo-nntp-default-user
1913          (or wl-nntp-posting-user elmo-nntp-default-user))
1914         (elmo-nntp-default-server
1915          (or wl-nntp-posting-server elmo-nntp-default-server))
1916         (elmo-nntp-default-port
1917          (or wl-nntp-posting-port elmo-nntp-default-port))
1918         (elmo-nntp-default-stream-type
1919          (or wl-nntp-posting-stream-type elmo-nntp-default-stream-type))
1920         (elmo-nntp-default-function wl-nntp-posting-function)
1921         condition)
1922     (if (setq condition (cdr (elmo-string-matched-assoc
1923                               (std11-field-body "Newsgroups")
1924                               wl-nntp-posting-config-alist)))
1925         (if (stringp condition)
1926             (setq elmo-nntp-default-server condition)
1927           (while (car condition)
1928             (set (intern (format "elmo-nntp-default-%s"
1929                                  (symbol-name (caar condition))))
1930                  (cdar condition))
1931             (setq condition (cdr condition)))))
1932     (unless elmo-nntp-default-function
1933       (error "wl-draft-nntp-send: posting-function is nil"))
1934     (if (not (elmo-plugged-p elmo-nntp-default-server elmo-nntp-default-port))
1935         (wl-draft-set-sent-message 'news 'unplugged
1936                                    (cons elmo-nntp-default-server
1937                                          elmo-nntp-default-port))
1938       (funcall elmo-nntp-default-function
1939                elmo-nntp-default-server (current-buffer))
1940       (wl-draft-set-sent-message 'news 'sent)
1941       (wl-draft-write-sendlog 'ok 'nntp elmo-nntp-default-server
1942                               (std11-field-body "Newsgroups")
1943                               (std11-field-body "Message-ID")))))
1944
1945 (defun wl-draft-generate-clone-buffer (name &optional local-variables)
1946   "Generate clone of current buffer named NAME."
1947   (let ((editing-buffer (current-buffer)))
1948     (save-excursion
1949       (set-buffer (generate-new-buffer name))
1950       (erase-buffer)
1951       (wl-draft-mode)
1952       (wl-draft-editor-mode)
1953       (insert-buffer editing-buffer)
1954       (message "")
1955       (while local-variables
1956         (make-local-variable (car local-variables))
1957         (set (car local-variables)
1958              (save-excursion
1959                (set-buffer editing-buffer)
1960                (symbol-value (car local-variables))))
1961         (setq local-variables (cdr local-variables)))
1962       (current-buffer))))
1963
1964 (defun wl-draft-remove-text-plain-tag ()
1965   "Remove text/plain tag of mime-edit."
1966   (when (string= (mime-make-text-tag "plain")
1967                  (buffer-substring-no-properties (point-at-bol)(point-at-eol)))
1968     (delete-region (point-at-bol)(1+ (point-at-eol)))))
1969
1970 (defun wl-draft-reedit (number)
1971   (let ((draft-folder (wl-draft-get-folder))
1972         (wl-draft-reedit t)
1973         (num 0)
1974         buffer change-major-mode-hook body-top)
1975     (setq buffer (get-buffer-create (format "%s/%d" wl-draft-folder
1976                                             number)))
1977     (if wl-draft-use-frame
1978         (switch-to-buffer-other-frame buffer)
1979       (switch-to-buffer buffer))
1980     (set-buffer buffer)
1981     (elmo-message-fetch draft-folder number (elmo-make-fetch-strategy 'entire)
1982                         nil (current-buffer))
1983     (elmo-delete-cr-buffer)
1984     (let ((mime-edit-again-ignored-field-regexp
1985            "^\\(Content-.*\\|Mime-Version\\):"))
1986       (wl-draft-decode-message-in-buffer))
1987     (setq body-top (wl-draft-insert-mail-header-separator))
1988     (auto-save-mode -1)
1989     (wl-draft-mode)
1990     (make-local-variable 'truncate-partial-width-windows)
1991     (setq truncate-partial-width-windows nil)
1992     (setq truncate-lines wl-draft-truncate-lines)
1993     (setq wl-sent-message-via nil)
1994     (setq wl-sent-message-queued nil)
1995     (wl-draft-config-info-operation number 'load)
1996     (goto-char (point-min))
1997     (wl-draft-overload-functions)
1998     (wl-draft-editor-mode)
1999     (static-when (boundp 'auto-save-file-name-transforms)
2000       (make-local-variable 'auto-save-file-name-transforms)
2001       (setq auto-save-file-name-transforms
2002             (cons (list (concat (regexp-quote wl-draft-folder)
2003                                 "/\\([0-9]+\\)")
2004                         (concat (expand-file-name
2005                                  "auto-save-"
2006                                  (elmo-folder-msgdb-path
2007                                   (wl-draft-get-folder)))
2008                                 "\\1"))
2009                   auto-save-file-name-transforms)))
2010     (setq buffer-file-name (buffer-name)
2011           wl-draft-parent-folder ""
2012           wl-draft-buffer-message-number number)
2013     (when wl-draft-write-file-function
2014       (add-hook 'local-write-file-hooks wl-draft-write-file-function))
2015     (wl-highlight-headers 'for-draft)
2016     (goto-char body-top)
2017     (run-hooks 'wl-draft-reedit-hook)
2018     (goto-char (point-max))
2019     buffer))
2020
2021 (defmacro wl-draft-body-goto-top ()
2022   (` (progn
2023        (goto-char (point-min))
2024        (if (re-search-forward mail-header-separator nil t)
2025            (forward-char 1)
2026          (goto-char (point-max))))))
2027
2028 (defmacro wl-draft-body-goto-bottom ()
2029   (` (goto-char (point-max))))
2030
2031 (defmacro wl-draft-config-body-goto-header ()
2032   (` (progn
2033        (goto-char (point-min))
2034        (if (re-search-forward mail-header-separator nil t)
2035            (beginning-of-line)
2036          (goto-char (point-max))))))
2037
2038 (defsubst wl-draft-config-sub-eval-insert (content &optional newline)
2039   (let (content-value)
2040     (when (and content
2041                (stringp (setq content-value (eval content))))
2042       (insert content-value)
2043       (if newline (insert "\n")))))
2044
2045 (defun wl-draft-config-sub-body (content)
2046   (wl-draft-body-goto-top)
2047   (delete-region (point) (point-max))
2048   (wl-draft-config-sub-eval-insert content))
2049
2050 (defun wl-draft-config-sub-top (content)
2051   (wl-draft-body-goto-top)
2052   (wl-draft-config-sub-eval-insert content))
2053
2054 (defun wl-draft-config-sub-bottom (content)
2055   (wl-draft-body-goto-bottom)
2056   (wl-draft-config-sub-eval-insert content))
2057
2058 (defun wl-draft-config-sub-header (content)
2059   (wl-draft-config-body-goto-header)
2060   (wl-draft-config-sub-eval-insert content 'newline))
2061
2062 (defun wl-draft-config-sub-header-top (content)
2063   (goto-char (point-min))
2064   (wl-draft-config-sub-eval-insert content 'newline))
2065
2066 (defun wl-draft-config-sub-part-top (content)
2067   (goto-char (mime-edit-content-beginning))
2068   (wl-draft-config-sub-eval-insert content 'newline))
2069
2070 (defun wl-draft-config-sub-part-bottom (content)
2071   (goto-char (mime-edit-content-end))
2072   (wl-draft-config-sub-eval-insert content 'newline))
2073
2074 (defsubst wl-draft-config-sub-file (content)
2075   (let ((coding-system-for-read wl-cs-autoconv)
2076         (file (expand-file-name (eval content))))
2077     (if (file-exists-p file)
2078         (insert-file-contents file)
2079       (error "%s: no exists file" file))))
2080
2081 (defun wl-draft-config-sub-body-file (content)
2082   (wl-draft-body-goto-top)
2083   (delete-region (point) (point-max))
2084   (wl-draft-config-sub-file content))
2085
2086 (defun wl-draft-config-sub-top-file (content)
2087   (wl-draft-body-goto-top)
2088   (wl-draft-config-sub-file content))
2089
2090 (defun wl-draft-config-sub-bottom-file (content)
2091   (wl-draft-body-goto-bottom)
2092   (wl-draft-config-sub-file content))
2093
2094 (defun wl-draft-config-sub-header-file (content)
2095   (wl-draft-config-body-goto-header)
2096   (wl-draft-config-sub-file content))
2097
2098 (defun wl-draft-config-sub-template (content)
2099   (setq wl-draft-config-variables
2100         (wl-template-insert (eval content))))
2101
2102 (defun wl-draft-config-sub-x-face (content)
2103   (if (and (string-match "\\.xbm\\(\\.gz\\)?$" content)
2104            (fboundp 'x-face-insert)) ; x-face.el is installed.
2105       (x-face-insert content)
2106     (wl-draft-replace-field "X-Face" (elmo-get-file-string content t) t)))
2107
2108 (defsubst wl-draft-config-sub-func (field content)
2109   (let (func)
2110     (if (setq func (assq field wl-draft-config-sub-func-alist))
2111         (let (wl-draft-config-variables)
2112           (funcall (cdr func) content)
2113           ;; for wl-draft-config-sub-template
2114           (cons t wl-draft-config-variables)))))
2115
2116 (defsubst wl-draft-config-exec-sub (clist)
2117   (let (config local-variables)
2118     (while clist
2119       (setq config (car clist))
2120       (cond
2121        ((functionp config)
2122         (funcall config))
2123        ((consp config)
2124         (let ((field (car config))
2125               (content (cdr config))
2126               ret-val)
2127           (cond
2128            ((stringp field)
2129             (wl-draft-replace-field field (eval content) t))
2130            ((setq ret-val (wl-draft-config-sub-func field content))
2131             (if (cdr ret-val) ;; for wl-draft-config-sub-template
2132                 (wl-append local-variables (cdr ret-val))))
2133            ((boundp field) ;; variable
2134             (make-local-variable field)
2135             (set field (eval content))
2136             (wl-append local-variables (list field)))
2137            (t
2138             (error "%s: not variable" field)))))
2139        (t
2140         (error "%s: not supported type" config)))
2141       (setq clist (cdr clist)))
2142     local-variables))
2143
2144 (defun wl-draft-prepared-config-exec (&optional config-alist reply-buf)
2145   "Change headers in draft preparation time."
2146   (interactive)
2147   (unless wl-draft-reedit
2148     (let ((config-alist
2149            (or config-alist
2150                (and (boundp 'wl-draft-prepared-config-alist)
2151                     wl-draft-prepared-config-alist)     ;; For compatible.
2152                wl-draft-config-alist)))
2153       (if config-alist
2154           (wl-draft-config-exec config-alist reply-buf)))))
2155
2156 (defun wl-draft-config-exec (&optional config-alist reply-buf)
2157   "Change headers according to the value of `wl-draft-config-alist'.
2158 Automatically applied in draft sending time."
2159   (interactive)
2160   (let ((case-fold-search t)
2161         (alist (or config-alist wl-draft-config-alist))
2162         (reply-buf (or reply-buf (and (buffer-live-p wl-draft-reply-buffer)
2163                                       wl-draft-reply-buffer)))
2164         (local-variables wl-draft-config-variables)
2165         key clist found)
2166     (when (and (or (interactive-p)
2167                    wl-draft-config-exec-flag)
2168                alist)
2169       (save-excursion
2170         (catch 'done
2171           (while alist
2172             (setq key (caar alist)
2173                   clist (cdar alist))
2174             (cond
2175              ((eq key 'reply)
2176               (when (and
2177                      reply-buf
2178                      (save-excursion
2179                        (set-buffer reply-buf)
2180                        (save-restriction
2181                          (std11-narrow-to-header)
2182                          (goto-char (point-min))
2183                          (re-search-forward (car clist) nil t))))
2184                 (wl-draft-config-exec-sub (cdr clist))
2185                 (setq found t)))
2186              ((stringp key)
2187               (when (save-restriction
2188                       (std11-narrow-to-header mail-header-separator)
2189                       (goto-char (point-min))
2190                       (re-search-forward key nil t))
2191                 (wl-append local-variables
2192                            (wl-draft-config-exec-sub clist))
2193                 (setq found t)))
2194              ((eval key)
2195               (wl-append local-variables
2196                          (wl-draft-config-exec-sub clist))
2197               (setq found t)))
2198             (if (and found wl-draft-config-matchone)
2199                 (throw 'done t))
2200             (setq alist (cdr alist)))))
2201       (if found
2202           (setq wl-draft-config-exec-flag nil))
2203       (run-hooks 'wl-draft-config-exec-hook)
2204       (put-text-property (point-min)(point-max) 'face nil)
2205       (wl-highlight-message (point-min)(point-max) t)
2206       (setq wl-draft-config-variables
2207             (elmo-uniq-list local-variables)))))
2208
2209 (defun wl-draft-replace-field (field content &optional add)
2210   (save-excursion
2211     (save-restriction
2212       (let ((case-fold-search t)
2213             (inhibit-read-only t) ;; added by teranisi.
2214             beg)
2215         (std11-narrow-to-header mail-header-separator)
2216         (goto-char (point-min))
2217         (if (re-search-forward (concat "^" (regexp-quote field) ":") nil t)
2218             (if content
2219                 ;; replace field
2220                 (progn
2221                   (setq beg (point))
2222                   (re-search-forward "^[^ \t]" nil 'move)
2223                   (beginning-of-line)
2224                   (skip-chars-backward "\n")
2225                   (delete-region beg (point))
2226                   (insert " " content))
2227               ;; delete field
2228               (save-excursion
2229                 (beginning-of-line)
2230                 (setq beg (point)))
2231               (re-search-forward "^[^ \t]" nil 'move)
2232               (beginning-of-line)
2233               (delete-region beg (point)))
2234           (when (and add content)
2235             ;; add field
2236             (goto-char (point-max))
2237             (insert (concat field ": " content "\n"))))))))
2238
2239 (defun wl-draft-config-info-operation (msg operation)
2240   (let* ((msgdb-dir (elmo-folder-msgdb-path (wl-draft-get-folder)))
2241          (filename
2242           (expand-file-name
2243            (format "%s-%d" wl-draft-config-save-filename msg)
2244            msgdb-dir))
2245          element alist variable)
2246     (cond
2247      ((eq operation 'save)
2248       (let ((variables (elmo-uniq-list wl-draft-config-variables)))
2249         (while (setq variable (pop variables))
2250           (when (boundp variable)
2251             (wl-append alist
2252                        (list (cons variable (eval variable))))))
2253         (elmo-object-save filename alist)))
2254      ((eq operation 'load)
2255       (setq alist (elmo-object-load filename))
2256       (while (setq element (pop alist))
2257         (set (make-local-variable (car element)) (cdr element))
2258         (wl-append wl-draft-config-variables (list (car element)))))
2259      ((eq operation 'delete)
2260       (if (file-exists-p filename)
2261           (delete-file filename))))))
2262
2263 (defun wl-draft-queue-info-operation (msg operation
2264                                           &optional add-sent-message-via)
2265   (let* ((msgdb-dir (elmo-folder-msgdb-path
2266                      (wl-folder-get-elmo-folder wl-queue-folder)))
2267          (filename
2268           (expand-file-name
2269            (format "%s-%d" wl-draft-queue-save-filename msg)
2270            msgdb-dir))
2271          element alist variable)
2272     (cond
2273      ((eq operation 'save)
2274       (let ((variables (elmo-uniq-list
2275                         (append wl-draft-queue-save-variables
2276                                 wl-draft-config-variables
2277                                 (list 'wl-draft-fcc-list)))))
2278         (if add-sent-message-via
2279             (progn
2280               (push 'wl-sent-message-queued variables)
2281               (push 'wl-sent-message-via variables)))
2282         (while (setq variable (pop variables))
2283           (when (boundp variable)
2284             (wl-append alist
2285                        (list (cons variable (eval variable))))))
2286         (elmo-object-save filename alist)))
2287      ((eq operation 'load)
2288       (setq alist (elmo-object-load filename))
2289       (while (setq element (pop alist))
2290         (set (make-local-variable (car element)) (cdr element))))
2291      ((eq operation 'get-sent-via)
2292       (setq alist (elmo-object-load filename))
2293       (cdr (assq 'wl-sent-message-via alist)))
2294      ((eq operation 'delete)
2295       (if (file-exists-p filename)
2296           (delete-file filename))))))
2297
2298 (defun wl-draft-queue-append (wl-sent-message-via)
2299   (if wl-draft-verbose-send
2300       (message "Queuing..."))
2301   (let ((send-buffer (current-buffer))
2302         (folder (wl-folder-get-elmo-folder wl-queue-folder))
2303         (message-id (std11-field-body "Message-ID")))
2304     (if (elmo-folder-append-buffer folder)
2305         (progn
2306           (wl-draft-queue-info-operation
2307            (car (elmo-folder-status folder))
2308            'save wl-sent-message-via)
2309           (wl-draft-write-sendlog 'ok 'queue nil wl-queue-folder message-id)
2310           (when wl-draft-verbose-send
2311             (setq wl-draft-verbose-msg "Queuing...")
2312             (message "Queuing...done")))
2313       (wl-draft-write-sendlog 'failed 'queue nil wl-queue-folder message-id)
2314       (error "Queuing failed"))))
2315
2316 (defun wl-draft-queue-flush ()
2317   "Flush draft queue."
2318   (interactive)
2319   (let* ((queue-folder (wl-folder-get-elmo-folder wl-queue-folder))
2320          (msgs2 (progn
2321                   (elmo-folder-open-internal queue-folder)
2322                   (elmo-folder-list-messages queue-folder)))
2323          (i 0)
2324          (performed 0)
2325          (wl-draft-queue-flushing t)
2326          msgs failure len buffer msgid sent-via)
2327     ;; get plugged send message
2328     (while msgs2
2329       (setq sent-via (wl-draft-queue-info-operation (car msgs2) 'get-sent-via))
2330       (catch 'found
2331         (while sent-via
2332           (when (and (eq (nth 1 (car sent-via)) 'unplugged)
2333                      (or (not (nth 2 (car sent-via)))
2334                          (elmo-plugged-p
2335                           (car (nth 2 (car sent-via)))
2336                           (cdr (nth 2 (car sent-via))))))
2337             (wl-append msgs (list (car msgs2)))
2338             (throw 'found t))
2339           (setq sent-via (cdr sent-via))))
2340       (setq msgs2 (cdr msgs2)))
2341     (when (> (setq len (length msgs)) 0)
2342       (if (elmo-y-or-n-p (format
2343                           "%d message(s) are in the sending queue.  Send now? "
2344                           len)
2345                          (not elmo-dop-flush-confirm) t)
2346           (progn
2347             (save-excursion
2348               (setq buffer (get-buffer-create " *wl-draft-queue-flush*"))
2349               (set-buffer buffer)
2350               (while msgs
2351                 ;; reset buffer local variables
2352                 (kill-all-local-variables)
2353                 (erase-buffer)
2354                 (setq i (+ 1 i)
2355                       failure nil)
2356                 (setq wl-sent-message-via nil)
2357                 (wl-draft-queue-info-operation (car msgs) 'load)
2358                 (elmo-message-fetch queue-folder
2359                                     (car msgs)
2360                                     (elmo-make-fetch-strategy 'entire)
2361                                     nil (current-buffer))
2362                 (condition-case err
2363                     (setq failure (funcall
2364                                    wl-draft-queue-flush-send-function
2365                                    (format "Sending (%d/%d)..." i len)))
2366 ;;;               (wl-draft-raw-send nil nil
2367 ;;;                                  (format "Sending (%d/%d)..." i len))
2368                   (error
2369                    (elmo-display-error err t)
2370                    (setq failure t))
2371                   (quit
2372                    (setq failure t)))
2373                 (if (eq wl-sent-message-modified 'requeue)
2374                     (progn
2375                       (elmo-folder-delete-messages
2376                        queue-folder (cons (car msgs) nil))
2377                       (wl-draft-queue-info-operation (car msgs) 'delete))
2378                   (unless failure
2379                     (elmo-folder-delete-messages
2380                      queue-folder (cons (car msgs) nil))
2381                     (wl-draft-queue-info-operation (car msgs) 'delete)
2382                     (setq performed (+ 1 performed))))
2383                 (setq msgs (cdr msgs)))
2384               (kill-buffer buffer)
2385               (message "%d message(s) are sent." performed)))
2386         (message "%d message(s) are remained to be sent." len))
2387       (elmo-folder-close queue-folder)
2388       len)))
2389
2390 (defun wl-jump-to-draft-buffer (&optional arg)
2391   "Jump to the draft if exists."
2392   (interactive "P")
2393   (if arg
2394       (wl-jump-to-draft-folder)
2395     (let ((draft-bufs (wl-collect-draft))
2396           buf)
2397       (cond
2398        ((null draft-bufs)
2399         (message "No draft buffer exist."))
2400        (t
2401         (setq draft-bufs
2402               (sort (mapcar 'buffer-name draft-bufs)
2403                     (function (lambda (a b)
2404                                 (not (string< a b))))))
2405         (if (setq buf (cdr (member (buffer-name)
2406                                    draft-bufs)))
2407             (setq buf (car buf))
2408           (setq buf (car draft-bufs)))
2409         (switch-to-buffer buf))))))
2410
2411 (defun wl-jump-to-draft-folder ()
2412   (let ((msgs (reverse (elmo-folder-list-messages (wl-draft-get-folder))))
2413         (mybuf (buffer-name))
2414         msg buf)
2415     (if (not msgs)
2416         (message "No draft message exist.")
2417       (if (string-match (concat "^" wl-draft-folder "/") mybuf)
2418           (setq msg (cadr (memq
2419                            (string-to-int (substring mybuf (match-end 0)))
2420                            msgs))))
2421       (or msg (setq msg (car msgs)))
2422       (if (setq buf (get-buffer (format "%s/%d" wl-draft-folder msg)))
2423           (switch-to-buffer buf)
2424         (wl-draft-reedit msg)))))
2425
2426 (defun wl-draft-highlight-and-recenter (&optional n)
2427   (interactive "P")
2428   (when wl-highlight-body-too
2429     (let ((modified (buffer-modified-p)))
2430       (unwind-protect
2431           (progn
2432             (put-text-property (point-min) (point-max) 'face nil)
2433             (wl-highlight-message (point-min) (point-max) t))
2434         (set-buffer-modified-p modified))))
2435   (static-when (featurep 'xemacs)
2436     ;; Cope with one of many XEmacs bugs that `recenter' takes
2437     ;; a long time if there are a lot of invisible text lines.
2438     (redraw-frame))
2439   (recenter n))
2440
2441 ;; insert element from history
2442 (defvar wl-draft-current-history-position nil)
2443 (defvar wl-draft-history-backup-word "")
2444
2445 (defun wl-draft-previous-history-element (n)
2446   (interactive "p")
2447   (let (bol history beg end prev new)
2448     (when (and (not (wl-draft-on-field-p))
2449                (< (point)
2450                   (save-excursion
2451                     (goto-char (point-min))
2452                     (search-forward (concat "\n" mail-header-separator "\n") nil 0)
2453                     (point)))
2454                (save-excursion
2455                  (beginning-of-line)
2456                  (while (and (looking-at "^[ \t]")
2457                              (not (= (point) (point-min))))
2458                    (forward-line -1))
2459                  (cond
2460                   ((looking-at wl-folder-complete-header-regexp)
2461                    (and (boundp 'wl-read-folder-history)
2462                         (setq history wl-read-folder-history)))
2463                   ;; ((looking-at wl-address-complete-header-regexp)
2464                   ;;  (setq history .....))
2465                   (t
2466                    nil)))
2467                (eolp))
2468       (setq bol (save-excursion (beginning-of-line) (point)))
2469       (cond ((and (or (eq last-command 'wl-draft-previous-history-element)
2470                       (eq last-command 'wl-draft-next-history-element))
2471                   wl-draft-current-history-position)
2472              (setq end (point))
2473              (or (search-backward-regexp ",[ \t]*\\(.*\\)" bol t)
2474                  (search-backward-regexp "^[ \t]\\(.*\\)" bol t)
2475                  (search-backward-regexp "^[^ \t]*: \\(.*\\)" bol t))
2476              (setq prev (match-string 1))
2477              (goto-char (match-beginning 1))
2478              (setq beg (point))
2479              (if (cond ((< n 0)
2480                         (>= (+ n wl-draft-current-history-position) 0))
2481                        ((> n 0)
2482                         (<= (+ n wl-draft-current-history-position)
2483                             (length history))))
2484                  (progn
2485                    (setq wl-draft-current-history-position
2486                          (+ n wl-draft-current-history-position))
2487                    (setq new
2488                          (nth wl-draft-current-history-position
2489                               (append (list wl-draft-history-backup-word)
2490                                       history)))
2491                    (delete-region beg end)
2492                    (insert new))
2493                (goto-char end)
2494                (cond ((< n 0)
2495                       (message "End of history; no next item"))
2496                      ((> n 0)
2497                       (message "Beginning of history; no preceding item")))))
2498             ((and (> n 0)
2499                   (save-excursion
2500                     (or (search-backward-regexp ",[ \t]*\\(.*\\)" bol t)
2501                         (search-backward-regexp "^[ \t]\\(.*\\)" bol t)
2502                         (search-backward-regexp "^[^ \t]*: \\(.*\\)" bol t)))
2503                   (car history))
2504              (setq wl-draft-current-history-position 1)
2505              (setq wl-draft-history-backup-word (match-string 1))
2506              (delete-region (match-beginning 1) (match-end 1))
2507              (insert (car history)))
2508             (t
2509              (setq wl-draft-current-history-position nil))))))
2510
2511 (defun wl-draft-next-history-element (n)
2512   (interactive "p")
2513   (wl-draft-previous-history-element (- n)))
2514
2515 ;;;; user-agent support by Sen Nagata
2516
2517 ;; this appears to be necessarily global...
2518 (defvar wl-user-agent-compose-p nil)
2519 (defvar wl-user-agent-headers-and-body-alist nil)
2520
2521 ;; this should be a generic function for mail-mode -- i wish there was
2522 ;; something like it in sendmail.el
2523 (defun wl-user-agent-insert-header (header-name header-value)
2524   "Insert HEADER-NAME w/ value HEADER-VALUE into a message."
2525   ;; it seems like overriding existing headers is acceptable -- should
2526   ;; we provide an option?
2527
2528   ;; plan was: unfold header (might be folded), remove existing value, insert
2529   ;;           new value
2530   ;; wl doesn't seem to fold header lines yet anyway :-)
2531
2532   (let ((kill-whole-line t)
2533         end-of-line)
2534     (mail-position-on-field (capitalize header-name))
2535     (setq end-of-line (point))
2536     (beginning-of-line)
2537     (re-search-forward ":" end-of-line)
2538     (insert (concat " " header-value "\n"))
2539     (kill-line)))
2540
2541 ;; this should be a generic function for mail-mode -- i wish there was
2542 ;; something like it in sendmail.el
2543 ;;
2544 ;; ** haven't dealt w/ case where the body is already set **
2545 (defun wl-user-agent-insert-body (body-text)
2546   "Insert a body of text, BODY-TEXT, into a message."
2547   ;; code defensively... :-P
2548   (goto-char (point-min))
2549   (search-forward mail-header-separator)
2550   (forward-line 1)
2551   (insert body-text))
2552
2553 ;;;###autoload
2554 (defun wl-user-agent-compose (&optional to subject other-headers continue
2555                                         switch-function yank-action
2556                                         send-actions)
2557   "Support the `compose-mail' interface for wl.
2558 Only support for TO, SUBJECT, and OTHER-HEADERS has been implemented.
2559 Support for CONTINUE, YANK-ACTION, and SEND-ACTIONS has not
2560 been implemented yet.  Partial support for SWITCH-FUNCTION now supported."
2561
2562   (unless (featurep 'wl)
2563     (require 'wl))
2564   (or switch-function
2565       (setq switch-function 'keep))
2566   ;; protect these -- to and subject get bound at some point, so it looks
2567   ;; to be necessary to protect the values used w/in
2568   (let ((wl-user-agent-headers-and-body-alist other-headers)
2569         (wl-draft-use-frame (eq switch-function 'switch-to-buffer-other-frame))
2570         (wl-draft-buffer-style switch-function))
2571     (if to
2572         (if (wl-string-match-assoc "to" wl-user-agent-headers-and-body-alist
2573                                    'ignore-case)
2574             (setcdr
2575              (wl-string-match-assoc "to" wl-user-agent-headers-and-body-alist
2576                                     'ignore-case)
2577              to)
2578           (setq wl-user-agent-headers-and-body-alist
2579                 (cons (cons "to" to)
2580                       wl-user-agent-headers-and-body-alist))))
2581     (if subject
2582         (if (wl-string-match-assoc "subject"
2583                                    wl-user-agent-headers-and-body-alist
2584                                    'ignore-case)
2585             (setcdr
2586              (wl-string-match-assoc "subject"
2587                                     wl-user-agent-headers-and-body-alist
2588                                     'ignore-case)
2589              subject)
2590           (setq wl-user-agent-headers-and-body-alist
2591                 (cons (cons "subject" subject)
2592                       wl-user-agent-headers-and-body-alist))))
2593     ;; i think this is what we want to use...
2594     (unwind-protect
2595         (progn
2596           ;; tell the hook-function to do its stuff
2597           (setq wl-user-agent-compose-p t)
2598           ;; because to get the hooks working, wl-draft has to think it has
2599           ;; been called interactively
2600           (call-interactively 'wl-draft))
2601       (setq wl-user-agent-compose-p nil))))
2602
2603 (defun wl-user-agent-compose-internal ()
2604   "Manipulate headers and/or a body of a draft message."
2605   ;; being called from wl-user-agent-compose?
2606   (if wl-user-agent-compose-p
2607       (progn
2608         ;; insert headers
2609         (let ((headers wl-user-agent-headers-and-body-alist)
2610               (case-fold-search t))
2611           (while headers
2612             ;; skip body
2613             (if (not (string-match "^body$" (car (car headers))))
2614                 (wl-user-agent-insert-header
2615                  (car (car headers)) (cdr (car headers)))
2616               t)
2617             (setq headers (cdr headers))))
2618         ;; highlight headers (from wl-draft in wl-draft.el)
2619         (wl-highlight-headers 'for-draft)
2620         ;; insert body
2621         (if (wl-string-match-assoc "body" wl-user-agent-headers-and-body-alist
2622                                    'ignore-case)
2623             (wl-user-agent-insert-body
2624              (cdr (wl-string-match-assoc
2625                    "body"
2626                    wl-user-agent-headers-and-body-alist 'ignore-case)))))
2627     t))
2628
2629 (require 'product)
2630 (product-provide (provide 'wl-draft) (require 'wl-version))
2631
2632 ;;; wl-draft.el ends here