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