Delete comment of `mime-raw-find-entity-from-point'.
[elisp/semi.git] / mime-view.el
1 ;;; mime-view.el --- interactive MIME viewer for GNU Emacs
2
3 ;; Copyright (C) 1995,1996,1997,1998,1999,2000 Free Software Foundation, Inc.
4
5 ;; Author: MORIOKA Tomohiko <tomo@m17n.org>
6 ;; Created: 1994/07/13
7 ;;      Renamed: 1994/08/31 from tm-body.el
8 ;;      Renamed: 1997/02/19 from tm-view.el
9 ;; Keywords: MIME, multimedia, mail, news
10
11 ;; This file is part of SEMI (Sample of Elastic MIME Interfaces).
12
13 ;; This program is free software; you can redistribute it and/or
14 ;; modify it under the terms of the GNU General Public License as
15 ;; published by the Free Software Foundation; either version 2, or (at
16 ;; your option) any later version.
17
18 ;; This program is distributed in the hope that it will be useful, but
19 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21 ;; General Public License for more details.
22
23 ;; You should have received a copy of the GNU General Public License
24 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
25 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
26 ;; Boston, MA 02111-1307, USA.
27
28 ;;; Code:
29
30 (require 'emu)
31 (require 'mime)
32 (require 'semi-def)
33 (require 'calist)
34 (require 'alist)
35 (require 'mailcap)
36
37
38 ;;; @ version
39 ;;;
40
41 (defconst mime-view-version
42   (concat (mime-product-name mime-user-interface-product) " MIME-View "
43           (mapconcat #'number-to-string
44                      (mime-product-version mime-user-interface-product) ".")
45           " (" (mime-product-code-name mime-user-interface-product) ")"))
46
47
48 ;;; @ variables
49 ;;;
50
51 (defgroup mime-view nil
52   "MIME view mode"
53   :group 'mime)
54
55 (defvar mime-view-find-every-situations t
56   "*Find every available situations if non-nil.")
57
58 (defcustom mime-situation-examples-file "~/.mime-example"
59   "*File name of situation-examples demonstrated by user."
60   :group 'mime-view
61   :type 'file)
62
63 (defcustom mime-preview-move-scroll nil
64   "*Decides whether to scroll when moving to next entity.
65 When t, scroll the buffer. Non-nil but not t means scroll when
66 the next entity is within next-screen-context-lines from top or
67 buttom. Nil means don't scroll at all."
68   :group 'mime-view
69   :type '(choice (const :tag "Off" nil)
70                  (const :tag "On" t)
71                  (sexp :tag "Situation" 1)))
72
73
74 ;;; @ in raw-buffer (representation space)
75 ;;;
76
77 (defvar mime-preview-buffer nil
78   "MIME-preview buffer corresponding with the (raw) buffer.")
79 (make-variable-buffer-local 'mime-preview-buffer)
80
81
82 (defvar mime-raw-representation-type-alist
83   '((mime-show-message-mode     . binary)
84     (mime-temp-message-mode     . binary)
85     (t                          . cooked)
86     )
87   "Alist of major-mode vs. representation-type of mime-raw-buffer.
88 Each element looks like (SYMBOL . REPRESENTATION-TYPE).  SYMBOL is
89 major-mode or t.  t means default.  REPRESENTATION-TYPE must be
90 `binary' or `cooked'.")
91
92
93 ;;; @ in preview-buffer (presentation space)
94 ;;;
95
96 (defvar mime-mother-buffer nil
97   "Mother buffer corresponding with the (MIME-preview) buffer.
98 If current MIME-preview buffer is generated by other buffer, such as
99 message/partial, it is called `mother-buffer'.")
100 (make-variable-buffer-local 'mime-mother-buffer)
101
102 ;; (defvar mime-raw-buffer nil
103 ;;   "Raw buffer corresponding with the (MIME-preview) buffer.")
104 ;; (make-variable-buffer-local 'mime-raw-buffer)
105
106 (defvar mime-preview-original-window-configuration nil
107   "Window-configuration before mime-view-mode is called.")
108 (make-variable-buffer-local 'mime-preview-original-window-configuration)
109
110 (defun mime-preview-original-major-mode (&optional recursive point)
111   "Return major-mode of original buffer.
112 If optional argument RECURSIVE is non-nil and current buffer has
113 mime-mother-buffer, it returns original major-mode of the
114 mother-buffer."
115   (if (and recursive mime-mother-buffer)
116       (save-excursion
117         (set-buffer mime-mother-buffer)
118         (mime-preview-original-major-mode recursive)
119         )
120     (cdr (assq 'major-mode
121                (get-text-property (or point
122                                       (if (> (point) (buffer-size))
123                                           (max (1- (point-max)) (point-min))
124                                         (point)))
125                                   'mime-view-situation)))))
126
127
128 ;;; @ entity information
129 ;;;
130
131 (defun mime-entity-situation (entity &optional situation)
132   "Return situation of ENTITY."
133   (let (rest param name)
134     ;; Content-Type
135     (unless (assq 'type situation)
136       (setq rest (or (mime-entity-content-type entity)
137                      (make-mime-content-type 'text 'plain))
138             situation (cons (car rest) situation)
139             rest (cdr rest))
140       )
141     (unless (assq 'subtype situation)
142       (or rest
143           (setq rest (or (cdr (mime-entity-content-type entity))
144                          '((subtype . plain)))))
145       (setq situation (cons (car rest) situation)
146             rest (cdr rest))
147       )
148     (while rest
149       (setq param (car rest))
150       (or (assoc (car param) situation)
151           (setq situation (cons param situation)))
152       (setq rest (cdr rest)))
153     
154     ;; Content-Disposition
155     (setq rest nil)
156     (unless (assq 'disposition-type situation)
157       (setq rest (mime-entity-content-disposition entity))
158       (if rest
159           (setq situation (cons (cons 'disposition-type
160                                       (mime-content-disposition-type rest))
161                                 situation)
162                 rest (mime-content-disposition-parameters rest))
163         ))
164     (while rest
165       (setq param (car rest)
166             name (car param))
167       (if (cond ((string= name "filename")
168                  (if (assq 'filename situation)
169                      nil
170                    (setq name 'filename)))
171                 ((string= name "creation-date")
172                  (if (assq 'creation-date situation)
173                      nil
174                    (setq name 'creation-date)))
175                 ((string= name "modification-date")
176                  (if (assq 'modification-date situation)
177                      nil
178                    (setq name 'modification-date)))
179                 ((string= name "read-date")
180                  (if (assq 'read-date situation)
181                      nil
182                    (setq name 'read-date)))
183                 ((string= name "size")
184                  (if (assq 'size situation)
185                      nil
186                    (setq name 'size)))
187                 (t (setq name (cons 'disposition name))
188                    (if (assoc name situation)
189                        nil
190                      name)))
191           (setq situation
192                 (cons (cons name (cdr param))
193                       situation)))
194       (setq rest (cdr rest)))
195     
196     ;; Content-Transfer-Encoding
197     (or (assq 'encoding situation)
198         (setq situation
199               (cons (cons 'encoding (or (mime-entity-encoding entity)
200                                         "7bit"))
201                     situation)))
202     
203     situation))
204
205 (defsubst mime-delq-null-situation (situations field
206                                                &optional ignored-value)
207   (let (dest)
208     (while situations
209       (let* ((situation (car situations))
210              (cell (assq field situation)))
211         (if cell
212             (or (eq (cdr cell) ignored-value)
213                 (setq dest (cons situation dest))
214                 )))
215       (setq situations (cdr situations)))
216     dest))
217
218 (defun mime-compare-situation-with-example (situation example)
219   (let ((example (copy-alist example))
220         (match 0))
221     (while situation
222       (let* ((cell (car situation))
223              (key (car cell))
224              (ecell (assoc key example)))
225         (when ecell
226           (if (equal cell ecell)
227               (setq match (1+ match))
228             (setq example (delq ecell example))
229             ))
230         )
231       (setq situation (cdr situation))
232       )
233     (cons match example)
234     ))
235
236 (defun mime-sort-situation (situation)
237   (sort situation
238         #'(lambda (a b)
239             (let ((a-t (car a))
240                   (b-t (car b))
241                   (order '((type . 1)
242                            (subtype . 2)
243                            (mode . 3)
244                            (method . 4)
245                            (major-mode . 5)
246                            (disposition-type . 6)
247                            ))
248                   a-order b-order)
249               (if (symbolp a-t)
250                   (let ((ret (assq a-t order)))
251                     (if ret
252                         (setq a-order (cdr ret))
253                       (setq a-order 7)
254                       ))
255                 (setq a-order 8)
256                 )
257               (if (symbolp b-t)
258                   (let ((ret (assq b-t order)))
259                     (if ret
260                         (setq b-order (cdr ret))
261                       (setq b-order 7)
262                       ))
263                 (setq b-order 8)
264                 )
265               (if (= a-order b-order)
266                   (string< (format "%s" a-t)(format "%s" b-t))
267                 (< a-order b-order))
268               )))
269   )
270
271 (defun mime-unify-situations (entity-situation
272                               condition situation-examples
273                               &optional required-name ignored-value)
274   (let (ret)
275     (in-calist-package 'mime-view)
276     (setq ret
277           (ctree-find-calist condition entity-situation
278                              mime-view-find-every-situations))
279     (if required-name
280         (setq ret (mime-delq-null-situation ret required-name ignored-value)))
281     (or (assq 'ignore-examples entity-situation)
282         (if (cdr ret)
283             (let ((rest ret)
284                   (max-score 0)
285                   (max-escore 0)
286                   max-examples
287                   max-situations)
288               (while rest
289                 (let ((situation (car rest))
290                       (examples situation-examples))
291                   (while examples
292                     (let* ((ret
293                             (mime-compare-situation-with-example
294                              situation (caar examples)))
295                            (ret-score (car ret)))
296                       (cond ((> ret-score max-score)
297                              (setq max-score ret-score
298                                    max-escore (cdar examples)
299                                    max-examples (list (cdr ret))
300                                    max-situations (list situation))
301                              )
302                             ((= ret-score max-score)
303                              (cond ((> (cdar examples) max-escore)
304                                     (setq max-escore (cdar examples)
305                                           max-examples (list (cdr ret))
306                                           max-situations (list situation))
307                                     )
308                                    ((= (cdar examples) max-escore)
309                                     (setq max-examples
310                                           (cons (cdr ret) max-examples))
311                                     (or (member situation max-situations)
312                                         (setq max-situations
313                                               (cons situation max-situations)))
314                                     )))))
315                     (setq examples (cdr examples))))
316                 (setq rest (cdr rest)))
317               (when max-situations
318                 (setq ret max-situations)
319                 (while max-examples
320                   (let* ((example (car max-examples))
321                          (cell
322                           (assoc example situation-examples)))
323                     (if cell
324                         (setcdr cell (1+ (cdr cell)))
325                       (setq situation-examples
326                             (cons (cons example 0)
327                                   situation-examples))
328                       ))
329                   (setq max-examples (cdr max-examples))
330                   )))))
331     (cons ret situation-examples)
332     ;; ret: list of situations
333     ;; situation-examples: new examples (notoce that contents of
334     ;;                     argument `situation-examples' has bees modified)
335     ))
336
337 (defun mime-view-entity-title (entity)
338   (or (mime-entity-read-field entity 'Content-Description)
339       (mime-entity-read-field entity 'Subject)
340       (mime-entity-filename entity)
341       ""))
342
343 (defvar mime-preview-situation-example-list nil)
344 (defvar mime-preview-situation-example-list-max-size 16)
345 ;; (defvar mime-preview-situation-example-condition nil)
346
347 (defun mime-find-entity-preview-situation (entity
348                                            &optional default-situation)
349   (or (let ((ret
350              (mime-unify-situations
351               (append (mime-entity-situation entity)
352                       default-situation)
353               mime-preview-condition
354               mime-preview-situation-example-list)))
355         (setq mime-preview-situation-example-list
356               (cdr ret))
357         (caar ret))
358       default-situation))
359
360   
361 (defvar mime-acting-situation-example-list nil)
362 (defvar mime-acting-situation-example-list-max-size 16)
363
364 (defun mime-save-situation-examples ()
365   (if (or mime-preview-situation-example-list
366           mime-acting-situation-example-list)
367       (let* ((file mime-situation-examples-file)
368              (buffer (get-buffer-create " *mime-example*")))
369         (unwind-protect
370             (save-excursion
371               (set-buffer buffer)
372               (setq buffer-file-name file)
373               (erase-buffer)
374               (insert ";;; " (file-name-nondirectory file) "\n")
375               (insert "\n;; This file is generated automatically by "
376                       mime-view-version "\n\n")
377               (insert ";;; Code:\n\n")
378               (if mime-preview-situation-example-list
379                   (pp `(setq mime-preview-situation-example-list
380                              ',mime-preview-situation-example-list)
381                       (current-buffer)))
382               (if mime-acting-situation-example-list
383                   (pp `(setq mime-acting-situation-example-list
384                              ',mime-acting-situation-example-list)
385                       (current-buffer)))
386               (insert "\n;;; "
387                       (file-name-nondirectory file)
388                       " ends here.\n")
389               (save-buffer))
390           (kill-buffer buffer)))))
391
392 (add-hook 'kill-emacs-hook 'mime-save-situation-examples)
393
394 (defun mime-reduce-situation-examples (situation-examples)
395   (let ((len (length situation-examples))
396         i ir ic j jr jc ret
397         dest d-i d-j
398         (max-sim 0) sim
399         min-det-ret det-ret
400         min-det-org det-org
401         min-freq freq)
402     (setq i 0
403           ir situation-examples)
404     (while (< i len)
405       (setq ic (car ir)
406             j 0
407             jr situation-examples)
408       (while (< j len)
409         (unless (= i j)
410           (setq jc (car jr))
411           (setq ret (mime-compare-situation-with-example (car ic)(car jc))
412                 sim (car ret)
413                 det-ret (+ (length (car ic))(length (car jc)))
414                 det-org (length (cdr ret))
415                 freq (+ (cdr ic)(cdr jc)))
416           (cond ((< max-sim sim)
417                  (setq max-sim sim
418                        min-det-ret det-ret
419                        min-det-org det-org
420                        min-freq freq
421                        d-i i
422                        d-j j
423                        dest (cons (cdr ret) freq))
424                  )
425                 ((= max-sim sim)
426                  (cond ((> min-det-ret det-ret)
427                         (setq min-det-ret det-ret
428                               min-det-org det-org
429                               min-freq freq
430                               d-i i
431                               d-j j
432                               dest (cons (cdr ret) freq))
433                         )
434                        ((= min-det-ret det-ret)
435                         (cond ((> min-det-org det-org)
436                                (setq min-det-org det-org
437                                      min-freq freq
438                                      d-i i
439                                      d-j j
440                                      dest (cons (cdr ret) freq))
441                                )
442                               ((= min-det-org det-org)
443                                (cond ((> min-freq freq)
444                                       (setq min-freq freq
445                                             d-i i
446                                             d-j j
447                                             dest (cons (cdr ret) freq))
448                                       ))
449                                ))
450                         ))
451                  ))
452           )
453         (setq jr (cdr jr)
454               j (1+ j)))
455       (setq ir (cdr ir)
456             i (1+ i)))
457     (if (> d-i d-j)
458         (setq i d-i
459               d-i d-j
460               d-j i))
461     (setq jr (nthcdr (1- d-j) situation-examples))
462     (setcdr jr (cddr jr))
463     (if (= d-i 0)
464         (setq situation-examples
465               (cdr situation-examples))
466       (setq ir (nthcdr (1- d-i) situation-examples))
467       (setcdr ir (cddr ir))
468       )
469     (if (setq ir (assoc (car dest) situation-examples))
470         (progn
471           (setcdr ir (+ (cdr ir)(cdr dest)))
472           situation-examples)
473       (cons dest situation-examples)
474       ;; situation-examples may be modified.
475       )))
476
477
478 ;;; @ presentation of preview
479 ;;;
480
481 ;;; @@ entity-button
482 ;;;
483
484 ;;; @@@ predicate function
485 ;;;
486
487 ;; (defun mime-view-entity-button-visible-p (entity)
488 ;;   "Return non-nil if header of ENTITY is visible.
489 ;; Please redefine this function if you want to change default setting."
490 ;;   (let ((media-type (mime-entity-media-type entity))
491 ;;         (media-subtype (mime-entity-media-subtype entity)))
492 ;;     (or (not (eq media-type 'application))
493 ;;         (and (not (eq media-subtype 'x-selection))
494 ;;              (or (not (eq media-subtype 'octet-stream))
495 ;;                  (let ((mother-entity (mime-entity-parent entity)))
496 ;;                    (or (not (eq (mime-entity-media-type mother-entity)
497 ;;                                 'multipart))
498 ;;                        (not (eq (mime-entity-media-subtype mother-entity)
499 ;;                                 'encrypted)))
500 ;;                    )
501 ;;                  )))))
502
503 ;;; @@@ entity button generator
504 ;;;
505
506 (defun mime-view-insert-entity-button (entity)
507   "Insert entity-button of ENTITY."
508   (let ((entity-node-id (mime-entity-node-id entity))
509         (params (mime-entity-parameters entity))
510         (subject (mime-view-entity-title entity)))
511     (mime-insert-button
512      (let ((access-type (assoc "access-type" params))
513            (num (or (cdr (assoc "x-part-number" params))
514                     (if (consp entity-node-id)
515                         (mapconcat (function
516                                     (lambda (num)
517                                       (format "%s" (1+ num))
518                                       ))
519                                    (reverse entity-node-id) ".")
520                       "0"))
521                 ))
522        (cond (access-type
523               (let ((server (assoc "server" params)))
524                 (setq access-type (cdr access-type))
525                 (if server
526                     (format "%s %s ([%s] %s)"
527                             num subject access-type (cdr server))
528                 (let ((site (cdr (assoc "site" params)))
529                       (dir (cdr (assoc "directory" params)))
530                       (url (cdr (assoc "url" params)))
531                       )
532                   (if url
533                       (format "%s %s ([%s] %s)"
534                               num subject access-type url)
535                     (format "%s %s ([%s] %s:%s)"
536                             num subject access-type site dir))
537                   )))
538             )
539            (t
540             (let ((media-type (mime-entity-media-type entity))
541                   (media-subtype (mime-entity-media-subtype entity))
542                   (charset (cdr (assoc "charset" params)))
543                   (encoding (mime-entity-encoding entity)))
544               (concat
545                num " " subject
546                (let ((rest
547                       (format " <%s/%s%s%s>"
548                               media-type media-subtype
549                               (if charset
550                                   (concat "; " charset)
551                                 "")
552                               (if encoding
553                                   (concat " (" encoding ")")
554                                 ""))))
555                  (if (>= (+ (current-column)(length rest))(window-width))
556                      "\n\t")
557                  rest)))
558             )))
559      (function mime-preview-play-current-entity))
560     ))
561
562
563 ;;; @@ entity-header
564 ;;;
565
566 (defvar mime-header-presentation-method-alist nil
567   "Alist of major mode vs. corresponding header-presentation-method functions.
568 Each element looks like (SYMBOL . FUNCTION).
569 SYMBOL must be major mode in raw-buffer or t.  t means default.
570 Interface of FUNCTION must be (ENTITY SITUATION).")
571
572 (defvar mime-view-ignored-field-list
573   '(".*Received:" ".*Path:" ".*Id:" "^References:"
574     "^Replied:" "^Errors-To:"
575     "^Lines:" "^Sender:" ".*Host:" "^Xref:"
576     "^Content-Type:" "^Precedence:"
577     "^Status:" "^X-VM-.*:")
578   "All fields that match this list will be hidden in MIME preview buffer.
579 Each elements are regexp of field-name.")
580
581 (defvar mime-view-visible-field-list '("^Dnas.*:" "^Message-Id:")
582   "All fields that match this list will be displayed in MIME preview buffer.
583 Each elements are regexp of field-name.")
584
585
586 ;;; @@ entity-body
587 ;;;
588
589 ;;; @@@ predicate function
590 ;;;
591
592 (in-calist-package 'mime-view)
593
594 (defun mime-calist::field-match-method-as-default-rule (calist
595                                                         field-type field-value)
596   (let ((s-field (assq field-type calist)))
597     (cond ((null s-field)
598            (cons (cons field-type field-value) calist)
599            )
600           (t calist))))
601
602 (define-calist-field-match-method
603   'header #'mime-calist::field-match-method-as-default-rule)
604
605 (define-calist-field-match-method
606   'body #'mime-calist::field-match-method-as-default-rule)
607
608
609 (defvar mime-preview-condition nil
610   "Condition-tree about how to display entity.")
611
612 (ctree-set-calist-strictly
613  'mime-preview-condition '((type . application)(subtype . octet-stream)
614                            (encoding . nil)
615                            (body . visible)))
616 (ctree-set-calist-strictly
617  'mime-preview-condition '((type . application)(subtype . octet-stream)
618                            (encoding . "7bit")
619                            (body . visible)))
620 (ctree-set-calist-strictly
621  'mime-preview-condition '((type . application)(subtype . octet-stream)
622                            (encoding . "8bit")
623                            (body . visible)))
624
625 (ctree-set-calist-strictly
626  'mime-preview-condition '((type . application)(subtype . pgp)
627                            (body . visible)))
628
629 (ctree-set-calist-strictly
630  'mime-preview-condition '((type . application)(subtype . x-latex)
631                            (body . visible)))
632
633 (ctree-set-calist-strictly
634  'mime-preview-condition '((type . application)(subtype . x-selection)
635                            (body . visible)))
636
637 (ctree-set-calist-strictly
638  'mime-preview-condition '((type . application)(subtype . x-comment)
639                            (body . visible)))
640
641 (ctree-set-calist-strictly
642  'mime-preview-condition '((type . message)(subtype . delivery-status)
643                            (body . visible)))
644
645 (ctree-set-calist-strictly
646  'mime-preview-condition
647  '((body . visible)
648    (body-presentation-method . mime-display-text/plain)))
649
650 (ctree-set-calist-strictly
651  'mime-preview-condition
652  '((type . nil)
653    (body . visible)
654    (body-presentation-method . mime-display-text/plain)))
655
656 (ctree-set-calist-strictly
657  'mime-preview-condition
658  '((type . text)(subtype . enriched)
659    (body . visible)
660    (body-presentation-method . mime-display-text/enriched)))
661
662 (ctree-set-calist-strictly
663  'mime-preview-condition
664  '((type . text)(subtype . richtext)
665    (body . visible)
666    (body-presentation-method . mime-display-text/richtext)))
667
668 (autoload 'mime-display-application/x-postpet "postpet")
669
670 (ctree-set-calist-strictly
671  'mime-preview-condition
672  '((type . application)(subtype . x-postpet)
673    (body . visible)
674    (body-presentation-method . mime-display-application/x-postpet)))
675
676 (ctree-set-calist-strictly
677  'mime-preview-condition
678  '((type . text)(subtype . t)
679    (body . visible)
680    (body-presentation-method . mime-display-text/plain)))
681
682 (ctree-set-calist-strictly
683  'mime-preview-condition
684  '((type . multipart)(subtype . alternative)
685    (body . visible)
686    (body-presentation-method . mime-display-multipart/alternative)))
687
688 (ctree-set-calist-strictly
689  'mime-preview-condition '((type . message)(subtype . partial)
690                            (body-presentation-method
691                             . mime-display-message/partial-button)))
692
693 (ctree-set-calist-strictly
694  'mime-preview-condition '((type . message)(subtype . rfc822)
695                            (body-presentation-method . nil)
696                            (childrens-situation (header . visible)
697                                                 (entity-button . invisible))))
698
699 (ctree-set-calist-strictly
700  'mime-preview-condition '((type . message)(subtype . news)
701                            (body-presentation-method . nil)
702                            (childrens-situation (header . visible)
703                                                 (entity-button . invisible))))
704
705
706 ;;; @@@ entity presentation
707 ;;;
708
709 (defun mime-display-text/plain (entity situation)
710   (save-restriction
711     (narrow-to-region (point-max)(point-max))
712     (mime-insert-text-content entity)
713     (run-hooks 'mime-text-decode-hook)
714     (goto-char (point-max))
715     (if (not (eq (char-after (1- (point))) ?\n))
716         (insert "\n")
717       )
718     (mime-add-url-buttons)
719     (run-hooks 'mime-display-text/plain-hook)
720     ))
721
722 (defun mime-display-text/richtext (entity situation)
723   (save-restriction
724     (narrow-to-region (point-max)(point-max))
725     (mime-insert-text-content entity)
726     (run-hooks 'mime-text-decode-hook)
727     (let ((beg (point-min)))
728       (remove-text-properties beg (point-max) '(face nil))
729       (richtext-decode beg (point-max))
730       )))
731
732 (defun mime-display-text/enriched (entity situation)
733   (save-restriction
734     (narrow-to-region (point-max)(point-max))
735     (mime-insert-text-content entity)
736     (run-hooks 'mime-text-decode-hook)
737     (let ((beg (point-min)))
738       (remove-text-properties beg (point-max) '(face nil))
739       (enriched-decode beg (point-max))
740       )))
741
742
743 (defvar mime-view-announcement-for-message/partial
744   (if (and (>= emacs-major-version 19) window-system)
745       "\
746 \[[ This is message/partial style split message. ]]
747 \[[ Please press `v' key in this buffer          ]]
748 \[[ or click here by mouse button-2.             ]]"
749     "\
750 \[[ This is message/partial style split message. ]]
751 \[[ Please press `v' key in this buffer.         ]]"
752     ))
753
754 (defun mime-display-message/partial-button (&optional entity situation)
755   (save-restriction
756     (goto-char (point-max))
757     (if (not (search-backward "\n\n" nil t))
758         (insert "\n")
759       )
760     (goto-char (point-max))
761     (narrow-to-region (point-max)(point-max))
762     (insert mime-view-announcement-for-message/partial)
763     (mime-add-button (point-min)(point-max)
764                      #'mime-preview-play-current-entity)
765     ))
766
767 (defun mime-display-multipart/mixed (entity situation)
768   (let ((children (mime-entity-children entity))
769         (original-major-mode-cell (assq 'major-mode situation))
770         (default-situation
771           (cdr (assq 'childrens-situation situation))))
772     (if original-major-mode-cell
773         (setq default-situation
774               (cons original-major-mode-cell default-situation)))
775     (while children
776       (mime-display-entity (car children) nil default-situation)
777       (setq children (cdr children))
778       )))
779
780 (defcustom mime-view-type-subtype-score-alist
781   '(((text . enriched) . 3)
782     ((text . richtext) . 2)
783     ((text . plain)    . 1)
784     (t . 0))
785   "Alist MEDIA-TYPE vs corresponding score.
786 MEDIA-TYPE must be (TYPE . SUBTYPE), TYPE or t.  t means default."
787   :group 'mime-view
788   :type '(repeat (cons (choice :tag "Media-Type"
789                                (cons :tag "Type/Subtype"
790                                      (symbol :tag "Primary-type")
791                                      (symbol :tag "Subtype"))
792                                (symbol :tag "Type")
793                                (const :tag "Default" t))
794                        integer)))
795
796 (defun mime-display-multipart/alternative (entity situation)
797   (let* ((children (mime-entity-children entity))
798          (original-major-mode-cell (assq 'major-mode situation))
799          (default-situation
800            (cdr (assq 'childrens-situation situation)))
801          (i 0)
802          (p 0)
803          (max-score 0)
804          situations)
805     (if original-major-mode-cell
806         (setq default-situation
807               (cons original-major-mode-cell default-situation)))
808     (setq situations
809           (mapcar (function
810                    (lambda (child)
811                      (let ((situation
812                             (mime-find-entity-preview-situation
813                              child default-situation)))
814                        (if (cdr (assq 'body-presentation-method situation))
815                            (let ((score
816                                   (cdr
817                                    (or (assoc
818                                         (cons
819                                          (cdr (assq 'type situation))
820                                          (cdr (assq 'subtype situation)))
821                                         mime-view-type-subtype-score-alist)
822                                        (assq
823                                         (cdr (assq 'type situation))
824                                         mime-view-type-subtype-score-alist)
825                                        (assq
826                                         t
827                                         mime-view-type-subtype-score-alist)
828                                        ))))
829                              (if (> score max-score)
830                                  (setq p i
831                                        max-score score)
832                                )))
833                        (setq i (1+ i))
834                        situation)
835                      ))
836                   children))
837     (setq i 0)
838     (while children
839       (let ((child (car children))
840             (situation (car situations)))
841         (mime-display-entity child (if (= i p)
842                                        situation
843                                      (del-alist 'body-presentation-method
844                                                 (copy-alist situation))))
845         )
846       (setq children (cdr children)
847             situations (cdr situations)
848             i (1+ i))
849       )))
850
851
852 ;;; @ acting-condition
853 ;;;
854
855 (defvar mime-acting-condition nil
856   "Condition-tree about how to process entity.")
857
858 (if (file-readable-p mailcap-file)
859     (let ((entries (mailcap-parse-file)))
860       (while entries
861         (let ((entry (car entries))
862               view print shared)
863           (while entry
864             (let* ((field (car entry))
865                    (field-type (car field)))
866               (cond ((eq field-type 'view)  (setq view field))
867                     ((eq field-type 'print) (setq print field))
868                     ((memq field-type '(compose composetyped edit)))
869                     (t (setq shared (cons field shared))))
870               )
871             (setq entry (cdr entry))
872             )
873           (setq shared (nreverse shared))
874           (ctree-set-calist-with-default
875            'mime-acting-condition
876            (append shared (list '(mode . "play")(cons 'method (cdr view)))))
877           (if print
878               (ctree-set-calist-with-default
879                'mime-acting-condition
880                (append shared
881                        (list '(mode . "print")(cons 'method (cdr view))))
882                ))
883           )
884         (setq entries (cdr entries))
885         )))
886
887 (ctree-set-calist-strictly
888  'mime-acting-condition
889  '((type . application)(subtype . octet-stream)
890    (mode . "play")
891    (method . mime-detect-content)
892    ))
893
894 (ctree-set-calist-with-default
895  'mime-acting-condition
896  '((mode . "extract")
897    (method . mime-save-content)))
898
899 (ctree-set-calist-strictly
900  'mime-acting-condition
901  '((type . text)(subtype . x-rot13-47)(mode . "play")
902    (method . mime-view-caesar)
903    ))
904 (ctree-set-calist-strictly
905  'mime-acting-condition
906  '((type . text)(subtype . x-rot13-47-48)(mode . "play")
907    (method . mime-view-caesar)
908    ))
909
910 (ctree-set-calist-strictly
911  'mime-acting-condition
912  '((type . message)(subtype . rfc822)(mode . "play")
913    (method . mime-view-message/rfc822)
914    ))
915 (ctree-set-calist-strictly
916  'mime-acting-condition
917  '((type . message)(subtype . partial)(mode . "play")
918    (method . mime-store-message/partial-piece)
919    ))
920
921 (ctree-set-calist-strictly
922  'mime-acting-condition
923  '((type . message)(subtype . external-body)
924    ("access-type" . "anon-ftp")
925    (method . mime-view-message/external-anon-ftp)
926    ))
927
928 (ctree-set-calist-strictly
929  'mime-acting-condition
930  '((type . message)(subtype . external-body)
931    ("access-type" . "url")
932    (method . mime-view-message/external-url)
933    ))
934
935 (ctree-set-calist-strictly
936  'mime-acting-condition
937  '((type . application)(subtype . octet-stream)
938    (method . mime-save-content)
939    ))
940
941
942 ;;; @ quitting method
943 ;;;
944
945 (defvar mime-preview-quitting-method-alist
946   '((mime-show-message-mode
947      . mime-preview-quitting-method-for-mime-show-message-mode))
948   "Alist of major-mode vs. quitting-method of mime-view.")
949
950 (defvar mime-preview-over-to-previous-method-alist nil
951   "Alist of major-mode vs. over-to-previous-method of mime-view.")
952
953 (defvar mime-preview-over-to-next-method-alist nil
954   "Alist of major-mode vs. over-to-next-method of mime-view.")
955
956
957 ;;; @ following method
958 ;;;
959
960 (defvar mime-preview-following-method-alist nil
961   "Alist of major-mode vs. following-method of mime-view.")
962
963 (defvar mime-view-following-required-fields-list
964   '("From"))
965
966
967 ;;; @ buffer setup
968 ;;;
969
970 (defun mime-display-entity (entity &optional situation
971                                    default-situation preview-buffer)
972   (or preview-buffer
973       (setq preview-buffer (current-buffer)))
974   (let* (e nb ne nhb nbb)
975     (mime-goto-header-start-point entity)
976     (in-calist-package 'mime-view)
977     (or situation
978         (setq situation
979               (mime-find-entity-preview-situation entity default-situation)))
980     (let ((button-is-invisible
981            (eq (cdr (or (assq '*entity-button situation)
982                         (assq 'entity-button situation)))
983                'invisible))
984           (header-is-visible
985            (eq (cdr (or (assq '*header situation)
986                         (assq 'header situation)))
987                'visible))
988           (header-presentation-method
989            (or (cdr (assq 'header-presentation-method situation))
990                (cdr (assq (cdr (assq 'major-mode situation))
991                           mime-header-presentation-method-alist))))
992           (body-presentation-method
993            (cdr (assq 'body-presentation-method situation)))
994           (children (mime-entity-children entity)))
995       (set-buffer preview-buffer)
996       (setq nb (point))
997       (narrow-to-region nb nb)
998       (or button-is-invisible
999           ;; (if (mime-view-entity-button-visible-p entity)
1000           (mime-view-insert-entity-button entity)
1001           ;;   )
1002           )
1003       (when header-is-visible
1004         (setq nhb (point))
1005         (if header-presentation-method
1006             (funcall header-presentation-method entity situation)
1007           (mime-insert-header entity
1008                               mime-view-ignored-field-list
1009                               mime-view-visible-field-list))
1010         (run-hooks 'mime-display-header-hook)
1011         (put-text-property nhb (point-max) 'mime-view-entity-header entity)
1012         (goto-char (point-max))
1013         (insert "\n")
1014         )
1015       (setq nbb (point))
1016       (cond (children)
1017             ((functionp body-presentation-method)
1018              (funcall body-presentation-method entity situation)
1019              )
1020             (t
1021              (when button-is-invisible
1022                (goto-char (point-max))
1023                (mime-view-insert-entity-button entity)
1024                )
1025              (or header-is-visible
1026                  (progn
1027                    (goto-char (point-max))
1028                    (insert "\n")
1029                    ))
1030              ))
1031       (setq ne (point-max))
1032       (widen)
1033       (put-text-property nb ne 'mime-view-entity entity)
1034       (put-text-property nb ne 'mime-view-situation situation)
1035       (put-text-property nbb ne 'mime-view-entity-body entity)
1036       (goto-char ne)
1037       (if children
1038           (if (functionp body-presentation-method)
1039               (funcall body-presentation-method entity situation)
1040             (mime-display-multipart/mixed entity situation)
1041             ))
1042       )))
1043
1044
1045 ;;; @ MIME viewer mode
1046 ;;;
1047
1048 (defconst mime-view-menu-title "MIME-View")
1049 (defconst mime-view-menu-list
1050   '((up          "Move to upper entity"    mime-preview-move-to-upper)
1051     (previous    "Move to previous entity" mime-preview-move-to-previous)
1052     (next        "Move to next entity"     mime-preview-move-to-next)
1053     (scroll-down "Scroll-down"             mime-preview-scroll-down-entity)
1054     (scroll-up   "Scroll-up"               mime-preview-scroll-up-entity)
1055     (play        "Play current entity"     mime-preview-play-current-entity)
1056     (extract     "Extract current entity"  mime-preview-extract-current-entity)
1057     (print       "Print current entity"    mime-preview-print-current-entity)
1058     )
1059   "Menu for MIME Viewer")
1060
1061 (cond ((featurep 'xemacs)
1062        (defvar mime-view-xemacs-popup-menu
1063          (cons mime-view-menu-title
1064                (mapcar (function
1065                         (lambda (item)
1066                           (vector (nth 1 item)(nth 2 item) t)
1067                           ))
1068                        mime-view-menu-list)))
1069        (defun mime-view-xemacs-popup-menu (event)
1070          "Popup the menu in the MIME Viewer buffer"
1071          (interactive "e")
1072          (select-window (event-window event))
1073          (set-buffer (event-buffer event))
1074          (popup-menu 'mime-view-xemacs-popup-menu))
1075        (defvar mouse-button-2 'button2)
1076        )
1077       (t
1078        (defvar mime-view-popup-menu 
1079          (let ((menu (make-sparse-keymap mime-view-menu-title)))
1080            (nconc menu
1081                   (mapcar (function
1082                            (lambda (item)
1083                              (list (intern (nth 1 item)) 'menu-item 
1084                                    (nth 1 item)(nth 2 item))
1085                              ))
1086                           mime-view-menu-list))))
1087        (defun mime-view-popup-menu (event)
1088          "Popup the menu in the MIME Viewer buffer"
1089          (interactive "@e")
1090          (let ((menu mime-view-popup-menu) events func)
1091            (setq events (x-popup-menu t menu))
1092            (and events
1093                 (setq func (lookup-key menu (apply #'vector events)))
1094                 (commandp func)
1095                 (funcall func))))
1096        (defvar mouse-button-2 [mouse-2])
1097        ))
1098
1099 (defun mime-view-define-keymap (&optional default)
1100   (let ((mime-view-mode-map (if (keymapp default)
1101                                 (copy-keymap default)
1102                               (make-sparse-keymap)
1103                               )))
1104     (define-key mime-view-mode-map
1105       "u"        (function mime-preview-move-to-upper))
1106     (define-key mime-view-mode-map
1107       "p"        (function mime-preview-move-to-previous))
1108     (define-key mime-view-mode-map
1109       "n"        (function mime-preview-move-to-next))
1110     (define-key mime-view-mode-map
1111       "\e\t"     (function mime-preview-move-to-previous))
1112     (define-key mime-view-mode-map
1113       "\t"       (function mime-preview-move-to-next))
1114     (define-key mime-view-mode-map
1115       " "        (function mime-preview-scroll-up-entity))
1116     (define-key mime-view-mode-map
1117       "\M- "     (function mime-preview-scroll-down-entity))
1118     (define-key mime-view-mode-map
1119       "\177"     (function mime-preview-scroll-down-entity))
1120     (define-key mime-view-mode-map
1121       "\C-m"     (function mime-preview-next-line-entity))
1122     (define-key mime-view-mode-map
1123       "\C-\M-m"  (function mime-preview-previous-line-entity))
1124     (define-key mime-view-mode-map
1125       "v"        (function mime-preview-play-current-entity))
1126     (define-key mime-view-mode-map
1127       "e"        (function mime-preview-extract-current-entity))
1128     (define-key mime-view-mode-map
1129       "\C-c\C-p" (function mime-preview-print-current-entity))
1130     (define-key mime-view-mode-map
1131       "\C-c\C-t\C-h" (function mime-preview-toggle-header))
1132     (define-key mime-view-mode-map
1133       "a"        (function mime-preview-follow-current-entity))
1134     (define-key mime-view-mode-map
1135       "q"        (function mime-preview-quit))
1136     (define-key mime-view-mode-map
1137       "\C-c\C-x" (function mime-preview-kill-buffer))
1138     ;; (define-key mime-view-mode-map
1139     ;;   "<"        (function beginning-of-buffer))
1140     ;; (define-key mime-view-mode-map
1141     ;;   ">"        (function end-of-buffer))
1142     (define-key mime-view-mode-map
1143       "?"        (function describe-mode))
1144     (define-key mime-view-mode-map
1145       [tab] (function mime-preview-move-to-next))
1146     (define-key mime-view-mode-map
1147       [delete] (function mime-preview-scroll-down-entity))
1148     (define-key mime-view-mode-map
1149       [backspace] (function mime-preview-scroll-down-entity))
1150     (if (functionp default)
1151         (cond ((featurep 'xemacs)
1152                (set-keymap-default-binding mime-view-mode-map default)
1153                )
1154               (t
1155                (setq mime-view-mode-map
1156                      (append mime-view-mode-map (list (cons t default))))
1157                )))
1158     (if mouse-button-2
1159         (define-key mime-view-mode-map
1160           mouse-button-2 (function mime-button-dispatcher))
1161       )
1162     (cond ((featurep 'xemacs)
1163            (define-key mime-view-mode-map
1164              mouse-button-3 (function mime-view-xemacs-popup-menu))
1165            )
1166           ((>= emacs-major-version 19)
1167            (define-key mime-view-mode-map
1168              mouse-button-3 (function mime-view-popup-menu))
1169            (define-key mime-view-mode-map [menu-bar mime-view]
1170              (cons mime-view-menu-title
1171                    (make-sparse-keymap mime-view-menu-title)))
1172            (mapcar (function
1173                     (lambda (item)
1174                       (define-key mime-view-mode-map
1175                         (vector 'menu-bar 'mime-view (car item))
1176                         (cons (nth 1 item)(nth 2 item))
1177                         )
1178                       ))
1179                    (reverse mime-view-menu-list)
1180                    )
1181            ))
1182     (use-local-map mime-view-mode-map)
1183     (run-hooks 'mime-view-define-keymap-hook)
1184     ))
1185
1186 (defsubst mime-maybe-hide-echo-buffer ()
1187   "Clear mime-echo buffer and delete window for it."
1188   (let ((buf (get-buffer mime-echo-buffer-name)))
1189     (if buf
1190         (save-excursion
1191           (set-buffer buf)
1192           (erase-buffer)
1193           (let ((win (get-buffer-window buf)))
1194             (if win
1195                 (delete-window win)
1196               ))
1197           (bury-buffer buf)
1198           ))))
1199
1200 (defvar mime-view-redisplay nil)
1201
1202 ;;;###autoload
1203 (defun mime-display-message (message &optional preview-buffer
1204                                      mother default-keymap-or-function
1205                                      original-major-mode)
1206   "View MESSAGE in MIME-View mode.
1207
1208 Optional argument PREVIEW-BUFFER specifies the buffer of the
1209 presentation.  It must be either nil or a name of preview buffer.
1210
1211 Optional argument MOTHER specifies mother-buffer of the preview-buffer.
1212
1213 Optional argument DEFAULT-KEYMAP-OR-FUNCTION is nil, keymap or
1214 function.  If it is a keymap, keymap of MIME-View mode will be added
1215 to it.  If it is a function, it will be bound as default binding of
1216 keymap of MIME-View mode."
1217   (mime-maybe-hide-echo-buffer)
1218   (let ((win-conf (current-window-configuration)))
1219     (or preview-buffer
1220         (setq preview-buffer
1221               (concat "*Preview-" (mime-entity-name message) "*")))
1222     (or original-major-mode
1223         (setq original-major-mode major-mode))
1224     (let ((inhibit-read-only t))
1225       (set-buffer (get-buffer-create preview-buffer))
1226       (widen)
1227       (erase-buffer)
1228       (if mother
1229           (setq mime-mother-buffer mother)
1230         )
1231       (setq mime-preview-original-window-configuration win-conf)
1232       (setq major-mode 'mime-view-mode)
1233       (setq mode-name "MIME-View")
1234       (mime-display-entity message nil
1235                            `((entity-button . invisible)
1236                              (header . visible)
1237                              (major-mode . ,original-major-mode))
1238                            preview-buffer)
1239       (mime-view-define-keymap default-keymap-or-function)
1240       (let ((point
1241              (next-single-property-change (point-min) 'mime-view-entity)))
1242         (if point
1243             (goto-char point)
1244           (goto-char (point-min))
1245           (search-forward "\n\n" nil t)
1246           ))
1247       (run-hooks 'mime-view-mode-hook)
1248       (set-buffer-modified-p nil)
1249       (setq buffer-read-only t)
1250       preview-buffer)))
1251
1252 ;;;###autoload
1253 (defun mime-view-buffer (&optional raw-buffer preview-buffer mother
1254                                    default-keymap-or-function
1255                                    representation-type)
1256   "View RAW-BUFFER in MIME-View mode.
1257 Optional argument PREVIEW-BUFFER is either nil or a name of preview
1258 buffer.
1259 Optional argument DEFAULT-KEYMAP-OR-FUNCTION is nil, keymap or
1260 function.  If it is a keymap, keymap of MIME-View mode will be added
1261 to it.  If it is a function, it will be bound as default binding of
1262 keymap of MIME-View mode.
1263 Optional argument REPRESENTATION-TYPE is representation-type of
1264 message.  It must be nil, `binary' or `cooked'.  If it is nil,
1265 `cooked' is used as default."
1266   (interactive)
1267   (or raw-buffer
1268       (setq raw-buffer (current-buffer)))
1269   (or representation-type
1270       (setq representation-type
1271             (save-excursion
1272               (set-buffer raw-buffer)
1273               (cdr (or (assq major-mode mime-raw-representation-type-alist)
1274                        (assq t mime-raw-representation-type-alist)))
1275               )))
1276   (if (eq representation-type 'binary)
1277       (setq representation-type 'buffer)
1278     )
1279   (setq preview-buffer (mime-display-message
1280                         (mime-open-entity representation-type raw-buffer)
1281                         preview-buffer mother default-keymap-or-function))
1282   (or (get-buffer-window preview-buffer)
1283       (let ((r-win (get-buffer-window raw-buffer)))
1284         (if r-win
1285             (set-window-buffer r-win preview-buffer)
1286           (let ((m-win (and mother (get-buffer-window mother))))
1287             (if m-win
1288                 (set-window-buffer m-win preview-buffer)
1289               (switch-to-buffer preview-buffer)
1290               ))))))
1291
1292 (defun mime-view-mode (&optional mother ctl encoding
1293                                  raw-buffer preview-buffer
1294                                  default-keymap-or-function)
1295   "Major mode for viewing MIME message.
1296
1297 Here is a list of the standard keys for mime-view-mode.
1298
1299 key             feature
1300 ---             -------
1301
1302 u               Move to upper content
1303 p or M-TAB      Move to previous content
1304 n or TAB        Move to next content
1305 SPC             Scroll up or move to next content
1306 M-SPC or DEL    Scroll down or move to previous content
1307 RET             Move to next line
1308 M-RET           Move to previous line
1309 v               Decode current content as `play mode'
1310 e               Decode current content as `extract mode'
1311 C-c C-p         Decode current content as `print mode'
1312 a               Followup to current content.
1313 q               Quit
1314 button-2        Move to point under the mouse cursor
1315                 and decode current content as `play mode'
1316 "
1317   (interactive)
1318   (unless mime-view-redisplay
1319     (save-excursion
1320       (if raw-buffer (set-buffer raw-buffer))
1321       (let ((type
1322              (cdr
1323               (or (assq major-mode mime-raw-representation-type-alist)
1324                   (assq t mime-raw-representation-type-alist)))))
1325         (if (eq type 'binary)
1326             (setq type 'buffer)
1327           )
1328         (setq mime-message-structure (mime-open-entity type raw-buffer))
1329         (or (mime-entity-content-type mime-message-structure)
1330             (mime-entity-set-content-type-internal
1331              mime-message-structure ctl))
1332         )
1333       (or (mime-entity-encoding mime-message-structure)
1334           (mime-entity-set-encoding-internal mime-message-structure encoding))
1335       ))
1336   (mime-display-message mime-message-structure preview-buffer
1337                         mother default-keymap-or-function)
1338   )
1339
1340
1341 ;;; @@ utility
1342 ;;;
1343
1344 (defun mime-preview-find-boundary-info (&optional get-mother)
1345   (let (entity
1346         p-beg p-end
1347         entity-node-id len)
1348     (while (null (setq entity
1349                        (get-text-property (point) 'mime-view-entity)))
1350       (backward-char))
1351     (setq p-beg (previous-single-property-change (point) 'mime-view-entity))
1352     (setq entity-node-id (mime-entity-node-id entity))
1353     (setq len (length entity-node-id))
1354     (cond ((null p-beg)
1355            (setq p-beg
1356                  (if (eq (next-single-property-change (point-min)
1357                                                       'mime-view-entity)
1358                          (point))
1359                      (point)
1360                    (point-min)))
1361            )
1362           ((eq (next-single-property-change p-beg 'mime-view-entity)
1363                (point))
1364            (setq p-beg (point))
1365            ))
1366     (setq p-end (next-single-property-change p-beg 'mime-view-entity))
1367     (cond ((null p-end)
1368            (setq p-end (point-max))
1369            )
1370           ((null entity-node-id)
1371            (setq p-end (point-max))
1372            )
1373           (get-mother
1374            (save-excursion
1375              (goto-char p-end)
1376              (catch 'tag
1377                (let (e i)
1378                  (while (setq e
1379                               (next-single-property-change
1380                                (point) 'mime-view-entity))
1381                    (goto-char e)
1382                    (let ((rc (mime-entity-node-id
1383                               (get-text-property (1- (point))
1384                                                  'mime-view-entity))))
1385                      (or (and (>= (setq i (- (length rc) len)) 0)
1386                               (equal entity-node-id (nthcdr i rc)))
1387                          (throw 'tag nil)))
1388                    (setq p-end e)))
1389                (setq p-end (point-max))))
1390            ))
1391     (vector p-beg p-end entity)))
1392
1393
1394 ;;; @@ playing
1395 ;;;
1396
1397 (autoload 'mime-preview-play-current-entity "mime-play"
1398   "Play current entity." t)
1399
1400 (defun mime-preview-extract-current-entity (&optional ignore-examples)
1401   "Extract current entity into file (maybe).
1402 It decodes current entity to call internal or external method as
1403 \"extract\" mode.  The method is selected from variable
1404 `mime-acting-condition'."
1405   (interactive "P")
1406   (mime-preview-play-current-entity ignore-examples "extract")
1407   )
1408
1409 (defun mime-preview-print-current-entity (&optional ignore-examples)
1410   "Print current entity (maybe).
1411 It decodes current entity to call internal or external method as
1412 \"print\" mode.  The method is selected from variable
1413 `mime-acting-condition'."
1414   (interactive "P")
1415   (mime-preview-play-current-entity ignore-examples "print")
1416   )
1417
1418
1419 ;;; @@ following
1420 ;;;
1421
1422 (defun mime-preview-follow-current-entity ()
1423   "Write follow message to current entity.
1424 It calls following-method selected from variable
1425 `mime-preview-following-method-alist'."
1426   (interactive)
1427   (let ((entity (mime-preview-find-boundary-info t))
1428         p-beg p-end
1429         pb-beg)
1430     (setq p-beg (aref entity 0)
1431           p-end (aref entity 1)
1432           entity (aref entity 2))
1433     (if (get-text-property p-beg 'mime-view-entity-body)
1434         (setq pb-beg p-beg)
1435       (setq pb-beg
1436             (next-single-property-change
1437              p-beg 'mime-view-entity-body nil
1438              (or (next-single-property-change p-beg 'mime-view-entity)
1439                  p-end))))
1440     (let* ((mode (mime-preview-original-major-mode 'recursive))
1441            (entity-node-id (mime-entity-node-id entity))
1442            (new-name
1443             (format "%s-%s" (buffer-name) (reverse entity-node-id)))
1444            new-buf
1445            (the-buf (current-buffer))
1446            fields)
1447       (save-excursion
1448         (set-buffer (setq new-buf (get-buffer-create new-name)))
1449         (erase-buffer)
1450         (insert ?\n)
1451         (insert-buffer-substring the-buf pb-beg p-end)
1452         (goto-char (point-min))
1453         (let ((current-entity
1454                (if (and (eq (mime-entity-media-type entity) 'message)
1455                         (eq (mime-entity-media-subtype entity) 'rfc822))
1456                    (car (mime-entity-children entity))
1457                  entity))
1458               str)
1459           (while (and current-entity
1460                       (if (and (eq (mime-entity-media-type
1461                                     current-entity) 'message)
1462                                (eq (mime-entity-media-subtype
1463                                     current-entity) 'rfc822))
1464                           nil
1465                         (mime-insert-header current-entity fields)
1466                         t))
1467             (setq fields (std11-collect-field-names)
1468                   current-entity (mime-entity-parent current-entity))
1469             ))
1470         (let ((rest mime-view-following-required-fields-list)
1471               field-name ret)
1472           (while rest
1473             (setq field-name (car rest))
1474             (or (std11-field-body field-name)
1475                 (progn
1476                   (save-excursion
1477                     (set-buffer the-buf)
1478                     (let ((entity (when mime-mother-buffer
1479                                     (set-buffer mime-mother-buffer)
1480                                     (get-text-property (point)
1481                                                        'mime-view-entity))))
1482                       (while (and entity
1483                                   (null (setq ret (mime-entity-fetch-field
1484                                                    entity field-name))))
1485                         (setq entity (mime-entity-parent entity)))))
1486                   (if ret
1487                       (insert (concat field-name ": " ret "\n"))
1488                     )))
1489             (setq rest (cdr rest))
1490             ))
1491         )
1492       (let ((f (cdr (assq mode mime-preview-following-method-alist))))
1493         (if (functionp f)
1494             (funcall f new-buf)
1495           (message
1496            (format
1497             "Sorry, following method for %s is not implemented yet."
1498             mode))
1499           ))
1500       )))
1501
1502
1503 ;;; @@ moving
1504 ;;;
1505
1506 (defun mime-preview-move-to-upper ()
1507   "Move to upper entity.
1508 If there is no upper entity, call function `mime-preview-quit'."
1509   (interactive)
1510   (let (cinfo)
1511     (while (null (setq cinfo
1512                        (get-text-property (point) 'mime-view-entity)))
1513       (backward-char)
1514       )
1515     (let ((r (mime-entity-parent cinfo))
1516           point)
1517       (catch 'tag
1518         (while (setq point (previous-single-property-change
1519                             (point) 'mime-view-entity))
1520           (goto-char point)
1521           (when (eq r (get-text-property (point) 'mime-view-entity))
1522             (if (or (eq mime-preview-move-scroll t)
1523                     (and mime-preview-move-scroll
1524                          (>= point
1525                              (save-excursion
1526                                (move-to-window-line -1)
1527                                (forward-line (* -1 next-screen-context-lines))
1528                                (beginning-of-line)
1529                                (point)))))
1530                 (recenter next-screen-context-lines))
1531             (throw 'tag t)
1532             )
1533           )
1534         (mime-preview-quit)
1535         ))))
1536
1537 (defun mime-preview-move-to-previous ()
1538   "Move to previous entity.
1539 If there is no previous entity, it calls function registered in
1540 variable `mime-preview-over-to-previous-method-alist'."
1541   (interactive)
1542   (while (and (not (bobp))
1543               (null (get-text-property (point) 'mime-view-entity)))
1544     (backward-char)
1545     )
1546   (let ((point (previous-single-property-change (point) 'mime-view-entity)))
1547     (if (and point
1548              (>= point (point-min)))
1549         (if (get-text-property (1- point) 'mime-view-entity)
1550             (progn (goto-char point)
1551                    (if
1552                     (or (eq mime-preview-move-scroll t)
1553                         (and mime-preview-move-scroll
1554                              (<= point
1555                                 (save-excursion
1556                                   (move-to-window-line 0)
1557                                   (forward-line next-screen-context-lines)
1558                                   (end-of-line)
1559                                   (point)))))
1560                         (recenter (* -1 next-screen-context-lines))))
1561           (goto-char (1- point))
1562           (mime-preview-move-to-previous)
1563           )
1564       (let ((f (assq (mime-preview-original-major-mode)
1565                      mime-preview-over-to-previous-method-alist)))
1566         (if f
1567             (funcall (cdr f))
1568           ))
1569       )))
1570
1571 (defun mime-preview-move-to-next ()
1572   "Move to next entity.
1573 If there is no previous entity, it calls function registered in
1574 variable `mime-preview-over-to-next-method-alist'."
1575   (interactive)
1576   (while (and (not (eobp))
1577               (null (get-text-property (point) 'mime-view-entity)))
1578     (forward-char)
1579     )
1580   (let ((point (next-single-property-change (point) 'mime-view-entity)))
1581     (if (and point
1582              (<= point (point-max)))
1583         (progn
1584           (goto-char point)
1585           (if (null (get-text-property point 'mime-view-entity))
1586               (mime-preview-move-to-next)
1587             (and
1588              (or (eq mime-preview-move-scroll t)
1589                  (and mime-preview-move-scroll
1590                       (>= point
1591                          (save-excursion
1592                            (move-to-window-line -1)
1593                            (forward-line
1594                             (* -1 next-screen-context-lines))
1595                            (beginning-of-line)
1596                            (point)))))
1597                  (recenter next-screen-context-lines))
1598             ))
1599       (let ((f (assq (mime-preview-original-major-mode)
1600                      mime-preview-over-to-next-method-alist)))
1601         (if f
1602             (funcall (cdr f))
1603           ))
1604       )))
1605
1606 (defun mime-preview-scroll-up-entity (&optional h)
1607   "Scroll up current entity.
1608 If reached to (point-max), it calls function registered in variable
1609 `mime-preview-over-to-next-method-alist'."
1610   (interactive)
1611   (if (eobp)
1612       (let ((f (assq (mime-preview-original-major-mode)
1613                      mime-preview-over-to-next-method-alist)))
1614         (if f
1615             (funcall (cdr f))
1616           ))
1617     (let ((point
1618            (or (next-single-property-change (point) 'mime-view-entity)
1619                (point-max)))
1620           (bottom (window-end (selected-window))))
1621       (if (and (not h)
1622                (> bottom point))
1623           (progn (goto-char point)
1624                  (recenter next-screen-context-lines))
1625         (condition-case nil
1626             (scroll-up h)
1627           (end-of-buffer
1628            (goto-char (point-max)))))
1629       )))
1630
1631 (defun mime-preview-scroll-down-entity (&optional h)
1632   "Scroll down current entity.
1633 If reached to (point-min), it calls function registered in variable
1634 `mime-preview-over-to-previous-method-alist'."
1635   (interactive)
1636   (if (bobp)
1637       (let ((f (assq (mime-preview-original-major-mode)
1638                      mime-preview-over-to-previous-method-alist)))
1639         (if f
1640             (funcall (cdr f))
1641           ))
1642     (let ((point
1643            (or (previous-single-property-change (point) 'mime-view-entity)
1644                (point-min)))
1645           (top (window-start (selected-window))))
1646       (if (and (not h)
1647                (< top point))
1648           (progn (goto-char point)
1649                  (recenter (* -1 next-screen-context-lines)))
1650         (condition-case nil
1651             (scroll-down h)
1652           (beginning-of-buffer
1653            (goto-char (point-min)))))
1654       )))
1655
1656 (defun mime-preview-next-line-entity (&optional lines)
1657   "Scroll up one line (or prefix LINES lines).
1658 If LINES is negative, scroll down LINES lines."
1659   (interactive "p")
1660   (mime-preview-scroll-up-entity (or lines 1))
1661   )
1662
1663 (defun mime-preview-previous-line-entity (&optional lines)
1664   "Scrroll down one line (or prefix LINES lines).
1665 If LINES is negative, scroll up LINES lines."
1666   (interactive "p")
1667   (mime-preview-scroll-down-entity (or lines 1))
1668   )
1669
1670
1671 ;;; @@ display
1672 ;;;
1673
1674 (defun mime-preview-toggle-header ()
1675   (interactive)
1676   (let ((situation (mime-preview-find-boundary-info))
1677         entity p-beg p-end)
1678     (setq p-beg (aref situation 0)
1679           p-end (aref situation 1)
1680           entity (aref situation 2)
1681           situation (get-text-property p-beg 'mime-view-situation))
1682     (let ((cell (assq '*header situation)))
1683       (if (null cell)
1684           (setq cell (assq 'header situation)))
1685       (if (eq (cdr cell) 'visible)
1686           (setq situation (put-alist '*header 'invisible situation))
1687         (setq situation (put-alist '*header 'visible situation))))
1688     (save-excursion
1689       (let ((inhibit-read-only t))
1690         (delete-region p-beg p-end)
1691         (mime-display-entity entity situation)))
1692     ;; (ctree-set-calist-strictly 'mime-preview-condition situation)
1693     (let ((ret (assoc situation mime-preview-situation-example-list)))
1694       (if ret
1695           (setcdr ret (1+ (cdr ret)))
1696         (add-to-list 'mime-preview-situation-example-list
1697                      (cons situation 0))))))
1698
1699     
1700 ;;; @@ quitting
1701 ;;;
1702
1703 (defun mime-preview-quit ()
1704   "Quit from MIME-preview buffer.
1705 It calls function registered in variable
1706 `mime-preview-quitting-method-alist'."
1707   (interactive)
1708   (let ((r (assq (mime-preview-original-major-mode)
1709                  mime-preview-quitting-method-alist)))
1710     (if r
1711         (funcall (cdr r))
1712       )))
1713
1714 (defun mime-preview-kill-buffer ()
1715   (interactive)
1716   (kill-buffer (current-buffer))
1717   )
1718
1719
1720 ;;; @ end
1721 ;;;
1722
1723 (provide 'mime-view)
1724
1725 (let* ((file mime-situation-examples-file)
1726        (buffer (get-buffer-create " *mime-example*")))
1727   (if (file-readable-p file)
1728       (unwind-protect
1729           (save-excursion
1730             (set-buffer buffer)
1731             (erase-buffer)
1732             (insert-file-contents file)
1733             (eval-buffer)
1734             ;; format check
1735             (condition-case nil
1736                 (let ((i 0))
1737                   (while (and (> (length mime-preview-situation-example-list)
1738                                  mime-preview-situation-example-list-max-size)
1739                               (< i 16))
1740                     (setq mime-preview-situation-example-list
1741                           (mime-reduce-situation-examples
1742                            mime-preview-situation-example-list))
1743                     (setq i (1+ i))
1744                     ))
1745               (error (setq mime-preview-situation-example-list nil)))
1746             ;; (let ((rest mime-preview-situation-example-list))
1747             ;;   (while rest
1748             ;;     (ctree-set-calist-strictly 'mime-preview-condition
1749             ;;                                (caar rest))
1750             ;;     (setq rest (cdr rest))))
1751             (condition-case nil
1752                 (let ((i 0))
1753                   (while (and (> (length mime-acting-situation-example-list)
1754                                  mime-acting-situation-example-list-max-size)
1755                               (< i 16))
1756                     (setq mime-acting-situation-example-list
1757                           (mime-reduce-situation-examples
1758                            mime-acting-situation-example-list))
1759                     (setq i (1+ i))
1760                     ))
1761               (error (setq mime-acting-situation-example-list nil)))
1762             )
1763         (kill-buffer buffer))))
1764
1765 ;;; mime-view.el ends here