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