comparison lisp/mh-e/mh-mime.el @ 56406:d36b00b98db0

Upgraded to MH-E version 7.4.4. See etc/MH-E-NEWS and lisp/mh-e/ChangeLog for details.
author Bill Wohler <wohler@newt.com>
date Tue, 13 Jul 2004 03:06:25 +0000
parents 695cf19ef79e
children e9a6cbc8ca5e 97905c4f1a42
comparison
equal deleted inserted replaced
56405:10b68aa88abe 56406:d36b00b98db0
1 ;;; mh-mime.el --- MH-E support for composing MIME messages 1 ;;; mh-mime.el --- MH-E support for composing MIME messages
2 2
3 ;; Copyright (C) 1993, 1995, 2001, 02, 2003 Free Software Foundation, Inc. 3 ;; Copyright (C) 1993, 1995, 2001, 02, 03, 2004 Free Software Foundation, Inc.
4 4
5 ;; Author: Bill Wohler <wohler@newt.com> 5 ;; Author: Bill Wohler <wohler@newt.com>
6 ;; Maintainer: Bill Wohler <wohler@newt.com> 6 ;; Maintainer: Bill Wohler <wohler@newt.com>
7 ;; Keywords: mail 7 ;; Keywords: mail
8 ;; See: mh-e.el 8 ;; See: mh-e.el
32 32
33 ;;; Change Log: 33 ;;; Change Log:
34 34
35 ;;; Code: 35 ;;; Code:
36 36
37 (require 'cl) 37 (require 'mh-utils)
38 (mh-require-cl)
38 (require 'mh-comp) 39 (require 'mh-comp)
39 (require 'mh-utils)
40 (load "mm-decode" t t) ; Non-fatal dependency
41 (load "mm-uu" t t) ; Non-fatal dependency
42 (load "mailcap" t t) ; Non-fatal dependency
43 (load "smiley" t t) ; Non-fatal dependency
44 (require 'gnus-util) 40 (require 'gnus-util)
41 (require 'mh-gnus)
45 42
46 (autoload 'gnus-article-goto-header "gnus-art") 43 (autoload 'gnus-article-goto-header "gnus-art")
47 (autoload 'article-emphasize "gnus-art") 44 (autoload 'article-emphasize "gnus-art")
48 (autoload 'gnus-get-buffer-create "gnus") 45 (autoload 'gnus-get-buffer-create "gnus")
49 (autoload 'gnus-eval-format "gnus-spec") 46 (autoload 'gnus-eval-format "gnus-spec")
448 (defun mh-mml-to-mime () 445 (defun mh-mml-to-mime ()
449 "Compose MIME message from mml directives. 446 "Compose MIME message from mml directives.
450 This step is performed automatically when sending the message, but this 447 This step is performed automatically when sending the message, but this
451 function may be called manually before sending the draft as well." 448 function may be called manually before sending the draft as well."
452 (interactive) 449 (interactive)
450 (require 'message)
453 (when mh-gnus-pgp-support-flag ;; This is only needed for PGP 451 (when mh-gnus-pgp-support-flag ;; This is only needed for PGP
454 (message-options-set-recipient)) 452 (message-options-set-recipient))
455 (mml-to-mime)) 453 (mml-to-mime))
456 454
457 ;;;###mh-autoload 455 ;;;###mh-autoload
527 "\\(<#part\\(.\\|\n\\)*>[ \n\t]*<#/part>\\|^<#secure.+>$\\)" 525 "\\(<#part\\(.\\|\n\\)*>[ \n\t]*<#/part>\\|^<#secure.+>$\\)"
528 nil t))) 526 nil t)))
529 527
530 528
531 529
532 ;;; MIME decoding
533
534 (defmacro mh-defun-compat (function arg-list &rest body)
535 "This is a macro to define functions which are not defined.
536 It is used for Gnus utility functions which were added recently. If FUNCTION
537 is not defined then it is defined to have argument list, ARG-LIST and body,
538 BODY."
539 (let ((defined-p (fboundp function)))
540 (unless defined-p
541 `(defun ,function ,arg-list ,@body))))
542 (put 'mh-defun-compat 'lisp-indent-function 'defun)
543
544 ;; Copy of original function from gnus-util.el
545 (mh-defun-compat gnus-local-map-property (map)
546 "Return a list suitable for a text property list specifying keymap MAP."
547 (cond (mh-xemacs-flag (list 'keymap map))
548 ((>= emacs-major-version 21) (list 'keymap map))
549 (t (list 'local-map map))))
550
551 ;; Copy of original function from mm-decode.el
552 (mh-defun-compat mm-merge-handles (handles1 handles2)
553 (append (if (listp (car handles1)) handles1 (list handles1))
554 (if (listp (car handles2)) handles2 (list handles2))))
555
556 ;; Copy of function from mm-decode.el
557 (mh-defun-compat mm-set-handle-multipart-parameter (handle parameter value)
558 ;; HANDLE could be a CTL.
559 (if handle
560 (put-text-property 0 (length (car handle)) parameter value
561 (car handle))))
562
563 ;; Copy of original macro is in mm-decode.el
564 (mh-defun-compat mm-handle-multipart-ctl-parameter (handle parameter)
565 (get-text-property 0 parameter (car handle)))
566
567 (mh-do-in-xemacs (defvar default-enable-multibyte-characters))
568
569 ;; Copy of original function in mm-decode.el
570 (mh-defun-compat mm-readable-p (handle)
571 "Say whether the content of HANDLE is readable."
572 (and (< (with-current-buffer (mm-handle-buffer handle)
573 (buffer-size)) 10000)
574 (mm-with-unibyte-buffer
575 (mm-insert-part handle)
576 (and (eq (mm-body-7-or-8) '7bit)
577 (not (mm-long-lines-p 76))))))
578
579 ;; Copy of original function in mm-bodies.el
580 (mh-defun-compat mm-long-lines-p (length)
581 "Say whether any of the lines in the buffer is longer than LINES."
582 (save-excursion
583 (goto-char (point-min))
584 (end-of-line)
585 (while (and (not (eobp))
586 (not (> (current-column) length)))
587 (forward-line 1)
588 (end-of-line))
589 (and (> (current-column) length)
590 (current-column))))
591
592 (mh-defun-compat mm-keep-viewer-alive-p (handle)
593 ;; Released Gnus doesn't keep handles associated with externally displayed
594 ;; MIME parts. So this will always return nil.
595 nil)
596
597 (mh-defun-compat mm-destroy-parts (list)
598 "Older emacs don't have this function."
599 nil)
600
601 ;;; This is mm-save-part from gnus 5.10 since that function in emacs21.2 is
602 ;;; buggy (the args to read-file-name are incorrect). When all supported
603 ;;; versions of Emacs come with at least Gnus 5.10, we can delete this
604 ;;; function and rename calls to mh-mm-save-part to mm-save-part.
605 (defun mh-mm-save-part (handle)
606 "Write HANDLE to a file."
607 (let ((name (mail-content-type-get (mm-handle-type handle) 'name))
608 (filename (mail-content-type-get
609 (mm-handle-disposition handle) 'filename))
610 file)
611 (when filename
612 (setq filename (file-name-nondirectory filename)))
613 (setq file (read-file-name "Save MIME part to: "
614 (or mm-default-directory
615 default-directory)
616 nil nil (or filename name "")))
617 (setq mm-default-directory (file-name-directory file))
618 (and (or (not (file-exists-p file))
619 (yes-or-no-p (format "File %s already exists; overwrite? "
620 file)))
621 (mm-save-part-to-file handle file))))
622
623
624
625 ;;; MIME cleanup 530 ;;; MIME cleanup
626 531
627 ;;;###mh-autoload 532 ;;;###mh-autoload
628 (defun mh-mime-cleanup () 533 (defun mh-mime-cleanup ()
629 "Free the decoded MIME parts." 534 "Free the decoded MIME parts."
666 (defun mh-add-missing-mime-version-header () 571 (defun mh-add-missing-mime-version-header ()
667 "Some mail programs don't put a MIME-Version header. 572 "Some mail programs don't put a MIME-Version header.
668 I have seen this only in spam, so maybe we shouldn't fix this ;-)" 573 I have seen this only in spam, so maybe we shouldn't fix this ;-)"
669 (save-excursion 574 (save-excursion
670 (goto-char (point-min)) 575 (goto-char (point-min))
671 (when (and (message-fetch-field "content-type") 576 (re-search-forward "\n\n" nil t)
672 (not (message-fetch-field "mime-version"))) 577 (save-restriction
673 (when (search-forward "\n\n" nil t) 578 (narrow-to-region (point-min) (point))
674 (forward-line -1) 579 (when (and (message-fetch-field "content-type")
580 (not (message-fetch-field "mime-version")))
581 (goto-char (point-min))
675 (insert "MIME-Version: 1.0\n"))))) 582 (insert "MIME-Version: 1.0\n")))))
583
584 (defun mh-small-show-buffer-p ()
585 "Check if show buffer is small.
586 This is used to decide if smileys and graphical emphasis will be displayed."
587 (let ((max nil))
588 (when (and (boundp 'font-lock-maximum-size) font-lock-maximum-size)
589 (cond ((numberp font-lock-maximum-size)
590 (setq max font-lock-maximum-size))
591 ((listp font-lock-maximum-size)
592 (setq max (cdr (or (assoc 'mh-show-mode font-lock-maximum-size)
593 (assoc t font-lock-maximum-size)))))))
594 (or (not (numberp max)) (>= (/ max 8) (buffer-size)))))
676 595
677 ;;;###mh-autoload 596 ;;;###mh-autoload
678 (defun mh-display-smileys () 597 (defun mh-display-smileys ()
679 "Function to display smileys." 598 "Function to display smileys."
680 (when (and mh-graphical-smileys-flag 599 (when (and mh-graphical-smileys-flag (mh-small-show-buffer-p))
681 (fboundp 'smiley-region) 600 (mh-funcall-if-exists smiley-region (point-min) (point-max))))
682 (boundp 'font-lock-maximum-size)
683 font-lock-maximum-size
684 (>= (/ font-lock-maximum-size 8) (buffer-size)))
685 (smiley-region (point-min) (point-max))))
686 601
687 ;;;###mh-autoload 602 ;;;###mh-autoload
688 (defun mh-display-emphasis () 603 (defun mh-display-emphasis ()
689 "Function to display graphical emphasis." 604 "Function to display graphical emphasis."
690 (when (and mh-graphical-emphasis-flag 605 (when (and mh-graphical-emphasis-flag (mh-small-show-buffer-p))
691 (if font-lock-maximum-size
692 (>= (/ font-lock-maximum-size 8) (buffer-size))))
693 (flet ((article-goto-body ())) ; shadow this function to do nothing 606 (flet ((article-goto-body ())) ; shadow this function to do nothing
694 (save-excursion 607 (save-excursion
695 (goto-char (point-min)) 608 (goto-char (point-min))
696 (article-emphasize))))) 609 (article-emphasize)))))
697 610
797 (defvar gnus-newsgroup-name nil) 710 (defvar gnus-newsgroup-name nil)
798 711
799 (defun mh-decode-message-body () 712 (defun mh-decode-message-body ()
800 "Decode message based on charset. 713 "Decode message based on charset.
801 If message has been encoded for transfer take that into account." 714 If message has been encoded for transfer take that into account."
802 (let* ((ct (ignore-errors (mail-header-parse-content-type 715 (let (ct charset cte)
803 (message-fetch-field "Content-Type" t)))) 716 (goto-char (point-min))
804 (charset (mail-content-type-get ct 'charset)) 717 (re-search-forward "\n\n" nil t)
805 (cte (message-fetch-field "Content-Transfer-Encoding"))) 718 (save-restriction
719 (narrow-to-region (point-min) (point))
720 (setq ct (ignore-errors (mail-header-parse-content-type
721 (message-fetch-field "Content-Type" t)))
722 charset (mail-content-type-get ct 'charset)
723 cte (message-fetch-field "Content-Transfer-Encoding")))
806 (when (stringp cte) (setq cte (mail-header-strip cte))) 724 (when (stringp cte) (setq cte (mail-header-strip cte)))
807 (when (or (not ct) (equal (car ct) "text/plain")) 725 (when (or (not ct) (equal (car ct) "text/plain"))
808 (save-restriction 726 (save-restriction
809 (narrow-to-region (min (1+ (mh-mail-header-end)) (point-max)) 727 (narrow-to-region (min (1+ (mh-mail-header-end)) (point-max))
810 (point-max)) 728 (point-max))
879 (t (mh-mime-display-mixed (cdr handle))))) 797 (t (mh-mime-display-mixed (cdr handle)))))
880 798
881 (defun mh-mime-display-alternative (handles) 799 (defun mh-mime-display-alternative (handles)
882 "Choose among the alternatives, HANDLES the part that will be displayed. 800 "Choose among the alternatives, HANDLES the part that will be displayed.
883 If no part is preferred then all the parts are displayed." 801 If no part is preferred then all the parts are displayed."
884 (let ((preferred (mm-preferred-alternative handles))) 802 (let* ((preferred (mm-preferred-alternative handles))
803 (others (loop for x in handles unless (eq x preferred) collect x)))
885 (cond ((and preferred (stringp (car preferred))) 804 (cond ((and preferred (stringp (car preferred)))
886 (mh-mime-display-part preferred)) 805 (mh-mime-display-part preferred)
806 (mh-mime-maybe-display-alternatives others))
887 (preferred 807 (preferred
888 (save-restriction 808 (save-restriction
889 (narrow-to-region (point) (if (eobp) (point) (1+ (point)))) 809 (narrow-to-region (point) (if (eobp) (point) (1+ (point))))
890 (mh-mime-display-single preferred) 810 (mh-mime-display-single preferred)
811 (mh-mime-maybe-display-alternatives others)
891 (goto-char (point-max)))) 812 (goto-char (point-max))))
892 (t (mh-mime-display-mixed handles))))) 813 (t (mh-mime-display-mixed handles)))))
814
815 (defun mh-mime-maybe-display-alternatives (alternatives)
816 "Show buttons for ALTERNATIVES.
817 If `mh-mime-display-alternatives-flag' is non-nil then display buttons for
818 alternative parts that are usually suppressed."
819 (when (and mh-display-buttons-for-alternatives-flag alternatives)
820 (insert "\n----------------------------------------------------\n")
821 (insert "Alternatives:\n")
822 (dolist (x alternatives)
823 (insert "\n")
824 (mh-insert-mime-button x (mh-mime-part-index x) nil))
825 (insert "\n----------------------------------------------------\n")))
893 826
894 (defun mh-mime-display-mixed (handles) 827 (defun mh-mime-display-mixed (handles)
895 "Display the list of MIME parts, HANDLES recursively." 828 "Display the list of MIME parts, HANDLES recursively."
896 (mapcar #'mh-mime-display-part handles)) 829 (mapcar #'mh-mime-display-part handles))
897 830
901 to be displayed multiple times (for instance when nested messages are 834 to be displayed multiple times (for instance when nested messages are
902 opened)." 835 opened)."
903 (or (gethash handle (mh-mime-part-index-hash (mh-buffer-data))) 836 (or (gethash handle (mh-mime-part-index-hash (mh-buffer-data)))
904 (setf (gethash handle (mh-mime-part-index-hash (mh-buffer-data))) 837 (setf (gethash handle (mh-mime-part-index-hash (mh-buffer-data)))
905 (incf (mh-mime-parts-count (mh-buffer-data)))))) 838 (incf (mh-mime-parts-count (mh-buffer-data))))))
906
907 ;;; Avoid compiler warnings for XEmacs functions...
908 (eval-when (compile)
909 (loop for function in '(glyph-width window-pixel-width
910 glyph-height window-pixel-height)
911 do (or (fboundp function) (defalias function 'ignore))))
912 839
913 (defun mh-small-image-p (handle) 840 (defun mh-small-image-p (handle)
914 "Decide whether HANDLE is a \"small\" image that can be displayed inline. 841 "Decide whether HANDLE is a \"small\" image that can be displayed inline.
915 This is only useful if a Content-Disposition header is not present." 842 This is only useful if a Content-Disposition header is not present."
916 (let ((media-test (caddr (assoc (car (mm-handle-type handle)) 843 (let ((media-test (caddr (assoc (car (mm-handle-type handle))
920 (equal (mm-handle-media-supertype handle) "image") 847 (equal (mm-handle-media-supertype handle) "image")
921 (funcall media-test handle) ; Since mm-inline-large-images is T, 848 (funcall media-test handle) ; Since mm-inline-large-images is T,
922 ; this only tells us if the image is 849 ; this only tells us if the image is
923 ; something that emacs can display 850 ; something that emacs can display
924 (let* ((image (mm-get-image handle))) 851 (let* ((image (mm-get-image handle)))
925 (cond ((fboundp 'glyph-width) 852 (or (mh-do-in-xemacs
926 ;; XEmacs -- totally untested, copied from gnus 853 (and (mh-funcall-if-exists glyphp image)
927 (and (mh-funcall-if-exists glyphp image) 854 (< (glyph-width image)
928 (< (glyph-width image) 855 (or mh-max-inline-image-width (window-pixel-width)))
929 (or mh-max-inline-image-width 856 (< (glyph-height image)
930 (window-pixel-width))) 857 (or mh-max-inline-image-height
931 (< (glyph-height image) 858 (window-pixel-height)))))
932 (or mh-max-inline-image-height 859 (mh-do-in-gnu-emacs
933 (window-pixel-height))))) 860 (let ((size (mh-funcall-if-exists image-size image)))
934 ((fboundp 'image-size) 861 (and size
935 ;; Emacs21 -- copied from gnus 862 (< (cdr size) (or mh-max-inline-image-height
936 (let ((size (mh-funcall-if-exists image-size image))) 863 (1- (window-height))))
937 (and size 864 (< (car size) (or mh-max-inline-image-width
938 (< (cdr size) 865 (window-width)))))))))))
939 (or mh-max-inline-image-height
940 (1- (window-height))))
941 (< (car size)
942 (or mh-max-inline-image-width (window-width))))))
943 (t
944 ;; Can't show image inline
945 nil))))))
946 866
947 (defun mh-inline-vcard-p (handle) 867 (defun mh-inline-vcard-p (handle)
948 "Decide if HANDLE is a vcard that must be displayed inline." 868 "Decide if HANDLE is a vcard that must be displayed inline."
949 (let ((type (mm-handle-type handle))) 869 (let ((type (mm-handle-type handle)))
950 (and (or (featurep 'vcard) (fboundp 'vcard-pretty-print)) 870 (and (or (featurep 'vcard) (fboundp 'vcard-pretty-print))
1060 (if (mm-handle-displayed-p handle) 980 (if (mm-handle-displayed-p handle)
1061 ;; This will remove the part. 981 ;; This will remove the part.
1062 (progn 982 (progn
1063 ;; Delete the button and displayed part (if any) 983 ;; Delete the button and displayed part (if any)
1064 (let ((region (get-text-property point 'mh-region))) 984 (let ((region (get-text-property point 'mh-region)))
1065 (when (and region (fboundp 'remove-images)) 985 (when region
1066 (mh-funcall-if-exists 986 (mh-funcall-if-exists
1067 remove-images (car region) (cdr region))) 987 remove-images (car region) (cdr region)))
1068 (mm-display-part handle) 988 (mm-display-part handle)
1069 (when region 989 (when region
1070 (delete-region (car region) (cdr region)))) 990 (delete-region (car region) (cdr region))))
1128 "Click MIME button for EVENT. 1048 "Click MIME button for EVENT.
1129 If the MIME part is visible then it is removed. Otherwise the part is 1049 If the MIME part is visible then it is removed. Otherwise the part is
1130 displayed. This function is called when the mouse is used to click the MIME 1050 displayed. This function is called when the mouse is used to click the MIME
1131 button." 1051 button."
1132 (interactive "e") 1052 (interactive "e")
1133 (save-excursion 1053 (mh-do-at-event-location event
1134 (let* ((event-window 1054 (let ((folder mh-show-folder-buffer)
1135 (or (mh-funcall-if-exists posn-window (event-start event));GNU Emacs 1055 (mm-inline-media-tests mh-mm-inline-media-tests)
1136 (mh-funcall-if-exists event-window event))) ;XEmacs 1056 (data (get-text-property (point) 'mh-data))
1137 (event-position 1057 (function (get-text-property (point) 'mh-callback)))
1138 (or (mh-funcall-if-exists posn-point (event-start event)) ;GNU Emacs 1058 (flet ((mm-handle-set-external-undisplayer (handle func)
1139 (mh-funcall-if-exists event-closest-point event))) ;XEmacs 1059 (mh-handle-set-external-undisplayer folder handle func)))
1140 (original-window (selected-window)) 1060 (and function (funcall function data))))))
1141 (original-position (progn
1142 (set-buffer (window-buffer event-window))
1143 (set-marker (make-marker) (point))))
1144 (folder mh-show-folder-buffer)
1145 (mm-inline-media-tests mh-mm-inline-media-tests)
1146 (data (get-text-property event-position 'mh-data))
1147 (function (get-text-property event-position 'mh-callback))
1148 (buffer-read-only nil))
1149 (unwind-protect
1150 (progn
1151 (select-window event-window)
1152 (flet ((mm-handle-set-external-undisplayer (handle func)
1153 (mh-handle-set-external-undisplayer folder handle func)))
1154 (goto-char event-position)
1155 (and function (funcall function data))))
1156 (set-buffer-modified-p nil)
1157 (goto-char original-position)
1158 (set-marker original-position nil)
1159 (select-window original-window)))))
1160 1061
1161 ;;;###mh-autoload 1062 ;;;###mh-autoload
1162 (defun mh-mime-save-part () 1063 (defun mh-mime-save-part ()
1163 "Save MIME part at point." 1064 "Save MIME part at point."
1164 (interactive) 1065 (interactive)
1165 (let ((data (get-text-property (point) 'mh-data))) 1066 (let ((data (get-text-property (point) 'mh-data)))
1166 (when data 1067 (when data
1167 (let ((mm-default-directory mh-mime-save-parts-directory)) 1068 (let ((mm-default-directory
1069 (file-name-as-directory (or mh-mime-save-parts-directory
1070 default-directory))))
1168 (mh-mm-save-part data) 1071 (mh-mm-save-part data)
1169 (setq mh-mime-save-parts-directory mm-default-directory))))) 1072 (setq mh-mime-save-parts-directory mm-default-directory)))))
1170 1073
1171 ;;;###mh-autoload 1074 ;;;###mh-autoload
1172 (defun mh-mime-inline-part () 1075 (defun mh-mime-inline-part ()