* wl-draft.el (wl-draft-insert-get-message): Follow the API change.
[elisp/wanderlust.git] / wl / wl-mime.el
1 ;;; wl-mime.el --- SEMI implementations of MIME processing on Wanderlust.
2
3 ;; Copyright (C) 1998,1999,2000 Yuuichi Teranishi <teranisi@gohome.org>
4
5 ;; Author: Yuuichi Teranishi <teranisi@gohome.org>
6 ;; Keywords: mail, net news
7
8 ;; This file is part of Wanderlust (Yet Another Message Interface on Emacsen).
9
10 ;; This program is free software; you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation; either version 2, or (at your option)
13 ;; any later version.
14 ;;
15 ;; This program is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 ;; GNU General Public License for more details.
19 ;;
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
22 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 ;; Boston, MA 02111-1307, USA.
24 ;;
25
26 ;;; Commentary:
27 ;;
28
29 ;;; Code:
30 ;;
31
32 (require 'mime-view)
33 (require 'mime-edit)
34 (require 'mime-play)
35 (require 'elmo)
36
37 (eval-when-compile
38   (defalias-maybe 'pgg-decrypt-region 'ignore)
39   (defalias-maybe 'pgg-display-output-buffer 'ignore)
40   (defalias-maybe 'pgg-verify-region 'ignore))
41
42 ;;; Draft
43
44 (defalias 'wl-draft-editor-mode 'mime-edit-mode)
45
46 (defalias 'wl-draft-decode-message-in-buffer
47   'mime-edit-decode-message-in-buffer)
48
49 (defun wl-draft-yank-current-message-entity ()
50   "Yank currently displayed message entity.
51 By setting following-method as yank-content.
52
53 If region is active, yank region contents instead. \(this feature is available
54 if and only if `transient-mark-mode' \(GNU Emacs\) or `zmacs-regions' \(XEmacs\)
55 has Non-nil value\)"
56   (let ((wl-draft-buffer (current-buffer))
57         (mime-view-following-method-alist
58          (list (cons 'wl-original-message-mode
59                      (function wl-draft-yank-to-draft-buffer))))
60         (mime-preview-following-method-alist
61          (list (cons 'wl-original-message-mode
62                      (function wl-draft-yank-to-draft-buffer))))
63         (message-buffer (wl-current-message-buffer)))
64     (if message-buffer
65         (save-excursion
66           (set-buffer message-buffer)
67           (save-restriction
68             (widen)
69             (cond
70              ((wl-region-exists-p)
71               (wl-mime-preview-follow-current-region))
72              ((not (wl-message-mime-analysis-p
73                     (wl-message-buffer-display-type)))
74               (wl-mime-preview-follow-no-mime
75                (wl-message-buffer-display-type)))
76              (t
77               (mime-preview-follow-current-entity)))))
78       (error "No message."))))
79
80 ;; modified mime-preview-follow-current-entity from mime-view.el
81 (defun wl-mime-preview-follow-no-mime (display-type)
82   "Write follow message to current message, without mime.
83 It calls following-method selected from variable
84 `mime-preview-following-method-alist'."
85   (interactive)
86   (let* ((mode (mime-preview-original-major-mode 'recursive))
87          (new-name (format "%s-no-mime" (buffer-name)))
88          new-buf min beg end
89          (entity (get-text-property (point-min) 'elmo-as-is-entity))
90          (the-buf (current-buffer))
91          fields)
92     (save-excursion
93       (goto-char (point-min))
94       (setq min (point-min)
95             beg (re-search-forward "^$" nil t)
96             end (point-max)))
97     (save-excursion
98       (set-buffer (setq new-buf (get-buffer-create new-name)))
99       (erase-buffer)
100       (insert-buffer-substring the-buf beg end)
101       (goto-char (point-min))
102       ;; Insert all headers.
103       (let ((elmo-mime-display-header-analysis
104              (wl-message-mime-analysis-p display-type 'header)))
105         (elmo-mime-insert-sorted-header entity))
106       (let ((f (cdr (assq mode mime-preview-following-method-alist))))
107         (if (functionp f)
108             (funcall f new-buf)
109           (message
110            "Sorry, following method for %s is not implemented yet."
111            mode))))))
112
113 ;; modified mime-preview-follow-current-entity from mime-view.el
114 (defun wl-mime-preview-follow-current-region ()
115   "Write follow message to current region.
116 It calls following-method selected from variable
117 `mime-preview-following-method-alist'."
118   (interactive)
119   (let ((r-beg (region-beginning))
120         (r-end (region-end))
121         (entity (get-text-property (point-min)
122                                    'mime-view-entity)))
123     (let* ((mode (mime-preview-original-major-mode 'recursive))
124            (new-name
125             (format "%s-active-region" (buffer-name)))
126            new-buf
127            (the-buf (current-buffer))
128            fields)
129       (save-excursion
130         (set-buffer (setq new-buf (get-buffer-create new-name)))
131         (erase-buffer)
132         (insert ?\n)
133         (insert-buffer-substring the-buf r-beg r-end)
134         (goto-char (point-min))
135         (let ((current-entity
136                (if (and entity
137                         (eq (mime-entity-media-type entity) 'message)
138                         (eq (mime-entity-media-subtype entity) 'rfc822))
139                    (car (mime-entity-children entity))
140                  entity)))
141           (while (and current-entity
142                       (if (and (eq (mime-entity-media-type
143                                     current-entity) 'message)
144                                (eq (mime-entity-media-subtype
145                                     current-entity) 'rfc822))
146                           nil
147                         (mime-insert-header current-entity fields)
148                         t))
149             (setq fields (std11-collect-field-names)
150                   current-entity (mime-entity-parent current-entity))))
151         (let ((rest mime-view-following-required-fields-list)
152               field-name ret)
153           (while rest
154             (setq field-name (car rest))
155             (or (std11-field-body field-name)
156                 (progn
157                   (save-excursion
158                     (set-buffer the-buf)
159                     (let ((entity (when mime-mother-buffer
160                                     (set-buffer mime-mother-buffer)
161                                     (get-text-property (point)
162                                                        'mime-view-entity))))
163                       (while (and entity
164                                   (null (setq ret (mime-entity-fetch-field
165                                                    entity field-name))))
166                         (setq entity (mime-entity-parent entity)))))
167                   (if ret
168                       (insert (concat field-name ": " ret "\n")))))
169             (setq rest (cdr rest)))))
170       (let ((f (cdr (assq mode mime-preview-following-method-alist))))
171         (if (functionp f)
172             (funcall f new-buf)
173           (message
174            "Sorry, following method for %s is not implemented yet."
175            mode))))))
176
177 (defalias 'wl-draft-enclose-digest-region 'mime-edit-enclose-digest-region)
178
179 (defun wl-draft-attribute-recipients ()
180   (concat (mapconcat
181            'identity
182            (wl-draft-deduce-address-list
183             (current-buffer)
184             (point-min)
185             (save-excursion
186               (goto-char (point-min))
187               (re-search-forward
188                (concat
189                 "^"
190                 (regexp-quote mail-header-separator)
191                 "$")
192                nil t)
193               (point)))
194            ", ")))
195
196 (defun wl-draft-attribute-envelope-from ()
197   (or wl-envelope-from
198       (wl-address-header-extract-address wl-from)))
199
200 (defun wl-draft-attribute-smtp-posting-server ()
201   (or wl-smtp-posting-server
202       (progn (require 'smtp) smtp-server)
203       "localhost"))
204
205 (defun wl-draft-attribute-smtp-posting-port ()
206   (or wl-smtp-posting-port
207       (progn (require 'smtp) smtp-service)))
208
209 (defun wl-draft-attribute-value (attr)
210   (let ((name (symbol-name attr))
211         fsymbol symbol)
212     (cond ((and (setq fsymbol (intern-soft
213                                (format "wl-draft-attribute-%s" name)))
214                 (fboundp fsymbol))
215            (funcall fsymbol))
216           ((and (setq symbol (intern-soft (format "wl-%s" name)))
217                 (boundp symbol))
218            (symbol-value symbol))
219           ((boundp attr)
220            (symbol-value attr)))))
221
222 (defun wl-mime-quit-preview ()
223   "Quitting method for mime-view."
224   (let* ((temp (and (boundp 'mime-edit-temp-message-buffer) ;; for SEMI <= 1.14.6
225                     mime-edit-temp-message-buffer))
226          (window (selected-window))
227          buf)
228     (mime-preview-kill-buffer)
229     (set-buffer temp)
230     (setq buf mime-edit-buffer)
231     (kill-buffer temp)
232     (select-window window)
233     (switch-to-buffer buf)))
234
235 (defun wl-draft-preview-message ()
236   "Preview editing message."
237   (interactive)
238   (let* (attribute-list
239          (orig-buffer (current-buffer))
240          (current-point (point))
241          (config-exec-flag wl-draft-config-exec-flag)
242          (parent-folder wl-draft-parent-folder)
243          (mime-display-header-hook 'wl-highlight-headers)
244          (mime-header-encode-method-alist
245           (append
246            '((wl-draft-eword-encode-address-list
247               .  (To Cc Bcc Resent-To Resent-Cc Resent-Bcc From)))
248            (if (boundp 'mime-header-encode-method-alist)
249                (symbol-value 'mime-header-encode-method-alist))))
250          mime-view-ignored-field-list   ; all header.
251          (mime-edit-translate-buffer-hook
252           (append
253            (list
254             (lambda ()
255               (let ((wl-draft-config-exec-flag config-exec-flag)
256                     (wl-draft-parent-folder parent-folder)
257                     (copy-buffer (current-buffer)))
258                 (with-current-buffer orig-buffer
259                   (wl-copy-local-variables
260                    orig-buffer
261                    copy-buffer
262                    (append wl-draft-config-variables
263                            (wl-draft-clone-local-variables))))
264                 (goto-char current-point)
265                 (run-hooks 'wl-draft-send-hook)
266                 (condition-case err
267                     (setq attribute-list
268                           (mapcar
269                            (lambda (attr)
270                              (cons attr (wl-draft-attribute-value attr)))
271                            wl-draft-preview-attributes-list))
272                   (error
273                    (kill-buffer (current-buffer))
274                    (signal (car err) (cdr err)))))))
275            mime-edit-translate-buffer-hook)))
276     (mime-edit-preview-message)
277     (make-local-variable 'mime-preview-quitting-method-alist)
278     (setq mime-preview-quitting-method-alist
279           '((mime-temp-message-mode . wl-mime-quit-preview)))
280     (let ((buffer-read-only nil))
281       (when wl-highlight-body-too
282         (wl-highlight-body))
283       (run-hooks 'wl-draft-preview-message-hook))
284     (make-local-hook 'kill-buffer-hook)
285     (add-hook 'kill-buffer-hook
286               (lambda ()
287                 (when (get-buffer-window
288                        wl-draft-preview-attributes-buffer-name)
289                   (select-window (get-buffer-window
290                                   wl-draft-preview-attributes-buffer-name))
291                   (delete-window))
292                 (when (get-buffer wl-draft-preview-attributes-buffer-name)
293                   (kill-buffer (get-buffer
294                                 wl-draft-preview-attributes-buffer-name))))
295               nil t)
296     (if (not wl-draft-preview-attributes)
297         (message (concat "Recipients: "
298                          (cdr (assq 'recipients attribute-list))))
299       (ignore-errors ; in case when the window is too small
300         (let* ((cur-win (selected-window))
301                (size (min
302                       (- (window-height cur-win)
303                          window-min-height 1)
304                       (- (window-height cur-win)
305                          (max
306                           window-min-height
307                           (1+ wl-draft-preview-attributes-buffer-lines))))))
308           (split-window cur-win (if (> size 0) size window-min-height))
309           (select-window (next-window))
310           (let ((pop-up-windows nil))
311             (switch-to-buffer (get-buffer-create
312                                wl-draft-preview-attributes-buffer-name)))
313           (with-current-buffer
314               (get-buffer wl-draft-preview-attributes-buffer-name)
315             (setq buffer-read-only t)
316             (let (buffer-read-only)
317               (erase-buffer)
318               (dolist (pair attribute-list)
319                 (insert (capitalize (symbol-name (car pair))) ": "
320                         (format "%s" (or (cdr pair) ""))
321                         "\n"))
322               (goto-char (point-min))
323               (wl-highlight-headers)))
324           (select-window cur-win))))))
325
326 (defalias 'wl-draft-caesar-region  'mule-caesar-region)
327
328 (defalias 'wl-draft-insert-message 'mime-edit-insert-message)
329
330 (defalias 'wl-draft-insert-mail 'mime-edit-insert-mail)
331
332 ;;; Message
333
334 (defun wl-message-decode-mode (outbuf inbuf)
335   (let ((mime-view-content-header-filter-hook 'wl-highlight-headers)
336         (mime-display-header-hook 'wl-highlight-headers))
337     (mime-view-mode nil nil nil inbuf outbuf)))
338
339 (defun wl-message-decode-with-all-header (outbuf inbuf)
340   (let ((mime-view-ignored-field-regexp "^:$")
341         (mime-view-content-header-filter-hook 'wl-highlight-headers)
342         (mime-display-header-hook 'wl-highlight-headers)
343         mime-view-ignored-field-list)
344     (mime-view-mode nil nil nil inbuf outbuf)))
345
346 (defun wl-message-delete-mime-out-buf ()
347   (let (mime-out-buf mime-out-win)
348     (if (setq mime-out-buf (get-buffer mime-echo-buffer-name))
349         (if (setq mime-out-win (get-buffer-window mime-out-buf))
350             (delete-window mime-out-win)))))
351
352 (defun wl-message-request-partial (folder number)
353   (elmo-set-work-buf
354    (elmo-message-fetch (wl-folder-get-elmo-folder folder)
355                        number
356                        (elmo-make-fetch-strategy 'entire)
357                        'unread)
358    (mime-parse-buffer nil)))
359
360 (defalias 'wl-message-read              'mime-preview-scroll-up-entity)
361 (defalias 'wl-message-next-content      'mime-preview-move-to-next)
362 (defalias 'wl-message-prev-content      'mime-preview-move-to-previous)
363 (defalias 'wl-message-play-content      'mime-preview-play-current-entity)
364 (defalias 'wl-message-extract-content   'mime-preview-extract-current-entity)
365 (defalias 'wl-message-quit              'mime-preview-quit)
366 (defalias 'wl-message-button-dispatcher-internal
367   'mime-button-dispatcher)
368
369 (defsubst wl-mime-node-id-to-string (node-id)
370   (if (consp node-id)
371       (mapconcat (function (lambda (num) (format "%s" (1+ num))))
372                  (reverse node-id)
373                  ".")
374     "0"))
375
376 (defun wl-message-delete-current-part ()
377   "Delete a part under the cursor from the multipart message."
378   (interactive)
379   (save-restriction
380     (widen)
381     (let* ((entity (get-text-property (point) 'mime-view-entity))
382            (node-id (mime-entity-node-id entity))
383            (filename (mime-entity-safe-filename entity))
384            (header-start (mime-buffer-entity-header-start-internal entity))
385            (body-end (mime-buffer-entity-body-end-internal entity))
386            (folder (wl-folder-get-elmo-folder wl-message-buffer-cur-folder))
387            (number wl-message-buffer-cur-number)
388            (msgid (elmo-message-field folder number 'message-id))
389            (orig-buf wl-message-buffer-original-buffer))
390       (if (eq (luna-class-name entity) 'mime-elmo-imap-entity)
391           (error "Please fetch the entire message (by typing 'C-u .') and try again"))
392       (with-current-buffer orig-buf
393         (unless (string-equal
394                  (buffer-string)
395                  (elmo-message-fetch-string
396                   folder number
397                   (elmo-make-fetch-strategy 'entire)))
398           (error "Buffer content differs from actual message")))
399       (when (and (elmo-folder-writable-p folder)
400                  (buffer-live-p orig-buf)
401                  node-id
402                  (yes-or-no-p
403                   (format "Do you really want to delete part %s? "
404                           (wl-mime-node-id-to-string node-id))))
405         (when (with-temp-buffer
406                 (insert-buffer orig-buf)
407                 (delete-region header-start body-end)
408                 (goto-char header-start)
409                 (insert "Content-Type: text/plain; charset=US-ASCII\n")
410                 (when filename
411                   (insert
412                    "Content-Disposition:"
413                    (mime-encode-field-body
414                          (concat ""
415                                  (and filename
416                                       (concat " inline; filename=" (std11-wrap-as-quoted-string filename))))
417                          "Content-Disposition")
418                    "\n"))
419                 (insert "\n")
420                 (insert "** This part has been removed by Wanderlust **\n\n")
421                 (elmo-folder-append-buffer folder))
422
423           (elmo-folder-move-messages
424            folder (list number)
425            (wl-folder-get-elmo-folder wl-trash-folder))
426           (when (and (elmo-cache-get-path msgid)
427                      (file-exists-p (elmo-cache-get-path msgid)))
428             (delete-file (elmo-cache-get-path msgid)))
429
430           (mime-preview-quit)
431           (wl-summary-delete-messages-on-buffer (list number))
432           (wl-summary-toggle-disp-msg 'off)
433           (setq wl-message-buffer nil)
434           (wl-summary-sync nil "update"))))))
435
436 (defun wl-message-decrypt-pgp-nonmime ()
437   "Decrypt PGP encrypted region"
438   (interactive)
439   (require 'pgg)
440   (save-excursion
441     (beginning-of-line)
442     (if (or (re-search-forward "^-+END PGP MESSAGE-+$" nil t)
443             (re-search-backward "^-+END PGP MESSAGE-+$" nil t))
444         (let (beg end status)
445           (setq end (match-end 0))
446           (if (setq beg (re-search-backward "^-+BEGIN PGP MESSAGE-+$" nil t))
447               (let ((inhibit-read-only t)
448                     (buffer-file-coding-system wl-cs-autoconv))
449                 (setq status (pgg-decrypt-region beg end))
450                 (pgg-display-output-buffer beg end status))
451             (message "Cannot find pgp encrypted region")))
452       (message "Cannot find pgp encrypted region"))))
453
454 (defun wl-message-verify-pgp-nonmime ()
455   "Verify PGP signed region"
456   (interactive)
457   (require 'pgg)
458   (save-excursion
459     (beginning-of-line)
460     (if (and (or (re-search-forward "^-+END PGP SIGNATURE-+$" nil t)
461                  (re-search-backward "^-+END PGP SIGNATURE-+$" nil t))
462              (re-search-backward "^-+BEGIN PGP SIGNED MESSAGE-+$" nil t))
463         (let (status)
464           (let* ((beg (point))
465                  (situation (mime-preview-find-boundary-info))
466                  (p-end (aref situation 1))
467                  (entity (aref situation 2))
468                  (count 0))
469             (goto-char p-end)
470             (while (< beg (point))
471               (if (re-search-backward "^-+BEGIN PGP SIGNED MESSAGE-+$" nil t)
472                   (setq count (+ count 1))
473                 (debug)))
474             (with-temp-buffer
475               (set-buffer-multibyte nil)
476               (insert (mime-entity-body entity))
477               (goto-char (point-max))
478               (while (> count 0)
479                 (if (re-search-backward "^-+BEGIN PGP SIGNED MESSAGE-+$" nil t)
480                     (setq count (- count 1))
481                   (debug)))
482               (let ((r-beg (point))
483                     (r-end (re-search-forward "^-+END PGP SIGNATURE-+$" nil t)))
484                 (if r-end
485                     (setq status (pgg-verify-region r-beg r-end nil 'fetch))
486                   (debug)))))
487           (mime-show-echo-buffer)
488           (set-buffer mime-echo-buffer-name)
489           (set-window-start
490            (get-buffer-window mime-echo-buffer-name)
491            (point-max))
492           (insert-buffer-substring
493            (if status pgg-output-buffer pgg-errors-buffer)))
494       (message "Cannot find pgp signed region"))))
495
496 ;; XXX: encrypted multipart isn't represented as multipart
497 (defun wl-mime-preview-application/pgp (parent-entity entity situation)
498   (require 'pgg)
499   (goto-char (point-max))
500   (let ((p (point))
501         raw-buf to-buf representation-type child-entity)
502     (goto-char p)
503     (save-restriction
504       (narrow-to-region p p)
505       (setq to-buf (current-buffer))
506       (with-temp-buffer
507         (setq raw-buf (current-buffer))
508         (mime-insert-entity entity)
509         (when (progn
510                 (goto-char (point-min))
511                 (re-search-forward "^-+BEGIN PGP MESSAGE-+$" nil t))
512           (pgg-decrypt-region (point-min)(point-max))
513           (delete-region (point-min) (point-max))
514           (insert-buffer pgg-output-buffer)
515           (setq representation-type 'elmo-buffer))
516         (setq child-entity (mime-parse-message
517                             (mm-expand-class-name representation-type)
518                             nil
519                             parent-entity
520                             (mime-entity-node-id-internal parent-entity)))
521         (mime-display-entity
522          child-entity
523          nil
524          `((header . visible)
525            (body . visible)
526            (entity-button . invisible))
527          to-buf)))))
528
529 (defun wl-mime-preview-application/pgp-encrypted (entity situation)
530   (let* ((entity-node-id (mime-entity-node-id entity))
531          (mother (mime-entity-parent entity))
532          (knum (car entity-node-id))
533          (onum (if (> knum 0)
534                    (1- knum)
535                  (1+ knum)))
536          (orig-entity (nth onum (mime-entity-children mother))))
537     (wl-mime-preview-application/pgp entity orig-entity situation)))
538
539 ;;; Summary
540 (defun wl-summary-burst-subr (message-entity target number)
541   ;; returns new number.
542   (let (content-type entity)
543     (setq content-type (mime-entity-content-type message-entity))
544     (cond ((eq (cdr (assq 'type content-type)) 'multipart)
545            (dolist (entity (mime-entity-children message-entity))
546              (setq number (wl-summary-burst-subr
547                            entity
548                            target
549                            number))))
550           ((and (eq (cdr (assq 'type content-type)) 'message)
551                 (eq (cdr (assq 'subtype content-type)) 'rfc822))
552            (message "Bursting...%s" (setq number (+ 1 number)))
553            (setq entity
554                  (car (mime-entity-children message-entity)))
555            (with-temp-buffer
556              (insert (mime-entity-body message-entity))
557              (elmo-folder-append-buffer target))))
558     number))
559
560 (defun wl-summary-burst (&optional arg)
561   "De-capsulate embedded messages in MIME format.
562 With ARG, ask destination folder."
563   (interactive "P")
564   (let ((raw-buf (wl-summary-get-original-buffer))
565         (view-buf wl-message-buffer)
566         message-entity target)
567     (save-excursion
568       (when (and (null arg)
569                  (elmo-folder-writable-p wl-summary-buffer-elmo-folder))
570         (setq target wl-summary-buffer-elmo-folder))
571       (while (null target)
572         (let ((name (wl-summary-read-folder wl-default-folder
573                                             "to extract to")))
574           (setq target (wl-folder-get-elmo-folder name))
575           (unless (elmo-folder-writable-p target)
576             (message "%s is not writable" name)
577             (setq target nil)
578             (sit-for 1))))
579       (wl-summary-set-message-buffer-or-redisplay)
580       (with-current-buffer view-buf
581         (setq message-entity
582               (get-text-property (point-min) 'mime-view-entity)))
583       (when message-entity
584         (message "Bursting...")
585         (with-current-buffer raw-buf
586           (wl-summary-burst-subr message-entity target 0))
587         (message "Bursting...done"))
588       (if (elmo-folder-plugged-p target)
589           (elmo-folder-check target)))
590     (when (and target
591                (string= wl-summary-buffer-folder-name
592                         (elmo-folder-name-internal target)))
593       (save-excursion (wl-summary-sync-update)))))
594
595 ;; internal variable.
596 (defvar wl-mime-save-directory nil "Last saved directory.")
597 ;;; Yet another save method.
598 (defun wl-mime-save-content (entity situation)
599   (let ((filename (expand-file-name
600                    (read-file-name "Save to file: "
601                                    (expand-file-name
602                                     (or (mime-entity-safe-filename entity)
603                                         ".")
604                                     (or wl-mime-save-directory
605                                         wl-temporary-file-directory))))))
606     (while (file-directory-p filename)
607       (setq filename (read-file-name "Please set filename (not directory): "
608                                      filename)))
609     (if (and (file-exists-p filename)
610              (not (yes-or-no-p (format "File %s exists. Save anyway? "
611                                        filename))))
612         (message "Not saved")
613       (setq wl-mime-save-directory (file-name-directory filename))
614       (mime-write-entity-content entity filename))))
615
616 ;;; Yet another combine method.
617 (defun wl-mime-combine-message/partial-pieces (entity situation)
618   "Internal method for wl to combine message/partial messages automatically."
619   (interactive)
620   (let* ((folder (with-current-buffer wl-message-buffer-cur-summary-buffer
621                    wl-summary-buffer-elmo-folder))
622          (mime-display-header-hook 'wl-highlight-headers)
623          (id (or (cdr (assoc "id" situation)) ""))
624          (mother (current-buffer))
625          (summary-buf wl-message-buffer-cur-summary-buffer)
626          subject-id overviews
627          (root-dir (expand-file-name
628                     (concat "m-prts-" (user-login-name))
629                     temporary-file-directory))
630          full-file point)
631     (setq root-dir (concat root-dir "/" (replace-as-filename id)))
632     (setq full-file (concat root-dir "/FULL"))
633     (if (or (file-exists-p full-file)
634             (not (y-or-n-p "Merge partials? ")))
635         (with-current-buffer mother
636           (mime-store-message/partial-piece entity situation)
637           (setq wl-message-buffer-cur-summary-buffer summary-buf)
638           (make-variable-buffer-local 'mime-preview-over-to-next-method-alist)
639           (setq mime-preview-over-to-next-method-alist
640                 (cons (cons 'mime-show-message-mode 'wl-message-exit)
641                       mime-preview-over-to-next-method-alist))
642           (make-variable-buffer-local 'mime-preview-over-to-previous-method-alist)
643           (setq mime-preview-over-to-previous-method-alist
644                 (cons (cons 'mime-show-message-mode 'wl-message-exit)
645                       mime-preview-over-to-previous-method-alist)))
646       (setq subject-id
647             (eword-decode-string
648              (decode-mime-charset-string
649               (mime-entity-read-field entity 'Subject)
650               wl-summary-buffer-mime-charset)))
651       (if (string-match "[0-9\n]+" subject-id)
652           (setq subject-id (substring subject-id 0 (match-beginning 0))))
653       (catch 'tag
654         (elmo-folder-do-each-message-entity (entity folder)
655           (when (string-match
656                  (regexp-quote subject-id)
657                  (elmo-message-entity-field entity 'subject 'decode))
658             (let* ((message
659                     ;; request message at the cursor in Subject buffer.
660                     (wl-message-request-partial
661                      (elmo-folder-name-internal folder)
662                      (elmo-message-entity-number entity)))
663                    (situation (mime-entity-situation message))
664                    (the-id (or (cdr (assoc "id" situation)) "")))
665               (when (string= (downcase the-id)
666                              (downcase id))
667                 (with-current-buffer mother
668                   (mime-store-message/partial-piece message situation))
669                 (if (file-exists-p full-file)
670                     (throw 'tag nil))))))
671         (message "Not all partials found.")))))
672
673 (defun wl-mime-display-text/plain (entity situation)
674   (let ((beg (point)))
675     (mime-display-text/plain entity situation)
676     (wl-highlight-message beg (point-max) t t)))
677
678 (defun wl-mime-display-header (entity situation)
679   (let ((elmo-message-ignored-field-list
680          (if wl-message-buffer-require-all-header
681              nil
682            wl-message-ignored-field-list))
683         (elmo-message-visible-field-list wl-message-visible-field-list)
684         (elmo-message-sorted-field-list wl-message-sort-field-list))
685     (elmo-mime-insert-header entity situation)
686     (wl-highlight-headers)))
687
688 (defun wl-mime-decrypt-application/pgp-encrypted (entity situation)
689   (let ((summary-buffer wl-message-buffer-cur-summary-buffer)
690         (original-buffer wl-message-buffer-original-buffer))
691     (mime-decrypt-application/pgp-encrypted entity situation)
692     (setq wl-message-buffer-cur-summary-buffer summary-buffer)
693     (setq wl-message-buffer-original-buffer original-buffer)))
694
695
696 ;;; Setup methods.
697 (defun wl-mime-setup ()
698   (set-alist 'mime-preview-quitting-method-alist
699              'wl-original-message-mode 'wl-message-exit)
700   (set-alist 'mime-view-over-to-previous-method-alist
701              'wl-original-message-mode 'wl-message-exit)
702   (set-alist 'mime-view-over-to-next-method-alist
703              'wl-original-message-mode 'wl-message-exit)
704   (set-alist 'mime-preview-over-to-previous-method-alist
705              'wl-original-message-mode 'wl-message-exit)
706   (set-alist 'mime-preview-over-to-next-method-alist
707              'wl-original-message-mode 'wl-message-exit)
708   (add-hook 'wl-summary-redisplay-hook 'wl-message-delete-mime-out-buf)
709   (add-hook 'wl-message-exit-hook 'wl-message-delete-mime-out-buf)
710
711   (ctree-set-calist-strictly
712    'mime-preview-condition
713    '((type . text) (subtype . plain)
714      (body . visible)
715      (body-presentation-method . wl-mime-display-text/plain)
716      (major-mode . wl-original-message-mode)))
717
718   (ctree-set-calist-strictly
719    'mime-preview-condition
720    '((type . application)(subtype . pgp-encrypted)
721      (encoding . t)
722      (body . invisible)
723      (body-presentation-method . wl-mime-preview-application/pgp-encrypted)
724      (major-mode . wl-original-message-mode)))
725
726   (ctree-set-calist-strictly
727    'mime-acting-condition
728    '((type . message) (subtype . partial)
729      (method .  wl-mime-combine-message/partial-pieces)
730      (request-partial-message-method . wl-message-request-partial)
731      (major-mode . wl-original-message-mode)))
732
733   (ctree-set-calist-strictly
734    'mime-acting-condition
735    '((type . application) (subtype . pgp-encrypted)
736      (method . wl-mime-decrypt-application/pgp-encrypted)
737      (major-mode . wl-original-message-mode)))
738
739   (ctree-set-calist-strictly
740    'mime-acting-condition
741    '((mode . "extract")
742      (major-mode . wl-original-message-mode)
743      (method . wl-mime-save-content)))
744   (set-alist 'mime-preview-following-method-alist
745              'wl-original-message-mode
746              (function wl-message-follow-current-entity))
747   (set-alist 'mime-view-following-method-alist
748              'wl-original-message-mode
749              (function wl-message-follow-current-entity))
750   (set-alist 'mime-edit-message-inserter-alist
751              'wl-draft-mode (function wl-draft-insert-current-message))
752   (set-alist 'mime-edit-mail-inserter-alist
753              'wl-draft-mode (function wl-draft-insert-get-message))
754   (set-alist 'mime-edit-split-message-sender-alist
755              'wl-draft-mode
756              (cdr (assq 'mail-mode mime-edit-split-message-sender-alist)))
757   (set-alist 'mime-raw-representation-type-alist
758              'wl-original-message-mode 'binary)
759   ;; Sort and highlight header fields.
760   (or wl-message-ignored-field-list
761       (setq wl-message-ignored-field-list
762             mime-view-ignored-field-list))
763   (or wl-message-visible-field-list
764       (setq wl-message-visible-field-list
765             mime-view-visible-field-list))
766   (set-alist 'mime-header-presentation-method-alist
767              'wl-original-message-mode
768              'wl-mime-display-header)
769   ;; To avoid overriding wl-draft-mode-map.
770   (when (boundp 'mime-setup-signature-key-alist)
771     (unless (assq 'wl-draft-mode mime-setup-signature-key-alist)
772       (setq mime-setup-signature-key-alist
773             (cons '(wl-draft-mode . "\C-c\C-w")
774                   mime-setup-signature-key-alist)))))
775
776 (require 'product)
777 (product-provide (provide 'wl-mime) (require 'wl-version))
778
779 ;;; wl-mime.el ends here