;;; mm-decode.el --- Functions for decoding MIME things
-;; Copyright (C) 1998-2013 Free Software Foundation, Inc.
+;; Copyright (C) 1998-2014 Free Software Foundation, Inc.
;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
;; MORIOKA Tomohiko <morioka@jaist.ac.jp>
(defvar gnus-current-window-configuration)
(add-hook 'gnus-exit-gnus-hook 'mm-destroy-postponed-undisplay-list)
+(add-hook 'gnus-exit-gnus-hook 'mm-temp-files-delete)
(defgroup mime-display ()
"Display of MIME in mail and news articles."
:group 'news
:group 'multimedia)
+(defface mm-command-output
+ '((((class color)
+ (background dark))
+ (:foreground "ForestGreen"))
+ (((class color)
+ (background light))
+ (:foreground "red3"))
+ (t
+ (:italic t)))
+ "Face used for displaying output from commands."
+ :group 'mime-display)
+
;;; Convenience macros.
(defmacro mm-handle-buffer (handle)
(defvar mm-content-id-alist nil)
(defvar mm-postponed-undisplay-list nil)
(defvar mm-inhibit-auto-detect-attachment nil)
+(defvar mm-temp-files-to-be-deleted nil
+ "List of temporary files scheduled to be deleted.")
+(defvar mm-temp-files-cache-file (concat ".mm-temp-files-" (user-login-name))
+ "Name of a file that caches a list of temporary files to be deleted.
+The file will be saved in the directory `mm-tmp-directory'.")
;; According to RFC2046, in particular, in a digest, the default
;; Content-Type value for a body part is changed from "text/plain" to
map)
"Keymap for input viewer with completion.")
-(defvar mm-viewer-completion-map
- (let ((map (make-sparse-keymap 'mm-viewer-completion-map)))
- (set-keymap-parent map minibuffer-local-completion-map)
- ;; Should we bind other key to minibuffer-complete-word?
- (define-key map " " 'self-insert-command)
- map)
- "Keymap for input viewer with completion.")
-
;;; The functions.
(defun mm-alist-to-plist (alist)
(message "Destroying external MIME viewers")
(mm-destroy-parts mm-postponed-undisplay-list)))
+(defun mm-temp-files-delete ()
+ "Delete temporary files and those parent directories.
+Note that the deletion may fail if a program is catching hold of a file
+under Windows or Cygwin. In that case, it schedules the deletion of
+files left at the next time."
+ (let* ((coding-system-for-read mm-universal-coding-system)
+ (coding-system-for-write mm-universal-coding-system)
+ (cache-file (expand-file-name mm-temp-files-cache-file
+ mm-tmp-directory))
+ (cache (when (file-exists-p cache-file)
+ (mm-with-multibyte-buffer
+ (insert-file-contents cache-file)
+ (split-string (buffer-string) "\n" t))))
+ fails)
+ (dolist (temp (append cache mm-temp-files-to-be-deleted))
+ (when (and (file-exists-p temp)
+ (if (file-directory-p temp)
+ ;; A parent directory left at the previous time.
+ (progn
+ (ignore-errors (delete-directory temp))
+ (file-exists-p temp))
+ ;; Delete a temporary file and its parent directory.
+ (ignore-errors (delete-file temp))
+ (or (file-exists-p temp)
+ (progn
+ (setq temp (file-name-directory temp))
+ (ignore-errors (delete-directory temp))
+ (file-exists-p temp)))))
+ (push temp fails)))
+ (if fails
+ ;; Schedule the deletion of the files left at the next time.
+ (progn
+ (write-region (concat (mapconcat 'identity (nreverse fails) "\n")
+ "\n")
+ nil cache-file nil 'silent)
+ (set-file-modes cache-file #o600))
+ (when (file-exists-p cache-file)
+ (ignore-errors (delete-file cache-file))))
+ (setq mm-temp-files-to-be-deleted nil)))
+
(autoload 'message-fetch-field "message")
(defun mm-dissect-buffer (&optional no-strict-mime loose-mime from)
description)))))
(if (or (not ctl)
(not (string-match "/" (car ctl))))
- (mm-dissect-singlepart
+ (mm-dissect-singlepart
(list mm-dissect-default-type)
- (and cte (intern (downcase (mail-header-strip cte))))
+ (and cte (intern (downcase (mail-header-strip cte))))
no-strict-mime
(and cd (mail-header-parse-content-disposition cd))
description)
method file (mm-handle-type handle))))
(unwind-protect
(if window-system
- (start-process "*display*" nil
- mm-external-terminal-program
- "-e" shell-file-name
- shell-command-switch command)
+ (set-process-sentinel
+ (start-process "*display*" nil
+ mm-external-terminal-program
+ "-e" shell-file-name
+ shell-command-switch command)
+ `(lambda (process state)
+ (if (eq 'exit (process-status process))
+ (run-at-time
+ 60.0 nil
+ (lambda ()
+ (ignore-errors (delete-file ,file))
+ (ignore-errors (delete-directory
+ ,(file-name-directory
+ file))))))))
(require 'term)
(require 'gnus-win)
(set-buffer
(set-process-sentinel
(get-buffer-process buffer)
`(lambda (process state)
- (if (eq 'exit (process-status process))
- (gnus-configure-windows
- ',gnus-current-window-configuration))))
+ (when (eq 'exit (process-status process))
+ (ignore-errors (delete-file ,file))
+ (ignore-errors
+ (delete-directory ,(file-name-directory file)))
+ (gnus-configure-windows
+ ',gnus-current-window-configuration))))
(gnus-configure-windows 'display-term))
- (mm-handle-set-external-undisplayer handle (cons file buffer)))
+ (mm-handle-set-external-undisplayer handle (cons file buffer))
+ (add-to-list 'mm-temp-files-to-be-deleted file t))
(message "Displaying %s..." command))
'external)
(copiousoutput
(let ((command (mm-mailcap-command
method file (mm-handle-type handle))))
(unwind-protect
- (progn
+ (let ((process-connection-type nil))
(start-process "*display*"
(setq buffer
(generate-new-buffer " *mm*"))
(buffer buffer)
(command command)
(handle handle))
- (run-at-time
- 30.0 nil
- (lambda ()
- (ignore-errors
- (delete-file file))
- (ignore-errors
- (delete-directory (file-name-directory file)))))
(lambda (process state)
(when (eq (process-status process) 'exit)
- (condition-case nil
- (delete-file file)
- (error))
- (condition-case nil
- (delete-directory (file-name-directory file))
- (error))
+ (run-at-time
+ 60.0 nil
+ (lambda ()
+ (ignore-errors (delete-file file))
+ (ignore-errors (delete-directory
+ (file-name-directory file)))))
(when (buffer-live-p outbuf)
(with-current-buffer outbuf
(let ((buffer-read-only nil)
(point (point)))
(forward-line 2)
- (mm-insert-inline
- handle (with-current-buffer buffer
- (buffer-string)))
+ (let ((start (point)))
+ (mm-insert-inline
+ handle (with-current-buffer buffer
+ (buffer-string)))
+ (put-text-property start (point)
+ 'face 'mm-command-output))
(goto-char point))))
(when (buffer-live-p buffer)
(kill-buffer buffer)))
(message "Displaying %s...done" command)))))
(mm-handle-set-external-undisplayer
- handle (cons file buffer)))
+ handle (cons file buffer))
+ (add-to-list 'mm-temp-files-to-be-deleted file t))
(message "Displaying %s..." command))
'external)))))))
(goto-char (point-min))
(if (re-search-forward "\
<meta\\s-+http-equiv=[\"']?content-type[\"']?\\s-+content=[\"']\
-text/\\(\\sw+\\)\\(?:\;\\s-*charset=\\(.+\\)\\)?[\"'][^>]*>" nil t)
+text/\\(\\sw+\\)\\(?:\;\\s-*charset=\\([^\"'>]+\\)\\)?[^>]*>" nil t)
(if (and (not force-charset)
(match-beginning 2)
(string-match "\\`html\\'" (match-string 1)))
(defvar shr-map)
+(autoload 'widget-convert-button "wid-edit")
+
(defun mm-convert-shr-links ()
(let ((start (point-min))
end)