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