diff --git a/mu4e/mu4e-helpers.el b/mu4e/mu4e-helpers.el index 8060d518..ab7ff4c8 100644 --- a/mu4e/mu4e-helpers.el +++ b/mu4e/mu4e-helpers.el @@ -534,11 +534,16 @@ string after PROMPT." (let ((timestr (read-string (mu4e-format "%s" prompt)))) (apply 'encode-time (parse-time-string timestr)))) + +(defvar mu4e--temp-dir nil "Directory for temporary files. +Created when mu4e starts, and removed when it closes.") + (defun mu4e-make-temp-file (ext) "Create a self-destructing temporary file with extension EXT. The file will self-destruct in a short while, enough to open it in an external program." - (let ((tmpfile (make-temp-file "mu4e-" nil (concat "." ext)))) + (let* ((temporary-file-directory (or mu4e--temp-dir temporary-file-directory)) + (tmpfile (make-temp-file "mu4e-" nil (concat "." ext)))) (run-at-time "30 sec" nil (lambda () (ignore-errors (delete-file tmpfile)))) tmpfile)) diff --git a/mu4e/mu4e-mime-parts.el b/mu4e/mu4e-mime-parts.el index 02514f95..351d2f38 100644 --- a/mu4e/mu4e-mime-parts.el +++ b/mu4e/mu4e-mime-parts.el @@ -1,6 +1,6 @@ ;;; mu4e-mime-parts.el --- Dealing with MIME-parts & URLs -*- lexical-binding: t -*- -;; Copyright (C) 2023-2024 Dirk-Jan C. Binnema +;; Copyright (C) 2023-2026 Dirk-Jan C. Binnema ;; Author: Dirk-Jan C. Binnema ;; Maintainer: Dirk-Jan C. Binnema @@ -63,25 +63,25 @@ See `mu4e--uniquify-file-name' for an example." ;; remember the mime-handles, so we can clean them up when ;; we quit this buffer. -(defvar-local mu4e--view-gnus-article-mime-handles nil) + +(defvar-local mu4e--view-gnus-article-mime-handles nil + "MIME handles for the message in this buffer.") (put 'mu4e--view-gnus-article-mime-handles 'permanent-local t) -(defun mu4e--view-kill-mime-handles () - "Kill cached MIME-handles, if any." +(defvar-local mu4e--view-temp-files nil + "Temporary files.") +(put 'mu4e--view-temp-files 'permanent-local t) + +(defun mu4e--view-buffer-cleanup () + "Clean-up some internals when killing the view buffer." + ;; Kill cached MIME-handles, if any. (when mu4e--view-gnus-article-mime-handles (mm-destroy-parts mu4e--view-gnus-article-mime-handles) - (setq mu4e--view-gnus-article-mime-handles nil))) - -;; Temp directories created to hand attachments to external openers; cleaned up -;; when the view buffer is killed. -(defvar-local mu4e--view-temp-dirs nil) -(put 'mu4e--view-temp-dirs 'permanent-local t) - -(defun mu4e--view-kill-temp-dirs () - "Delete temp dirs created for opening MIME-parts externally." - (dolist (dir mu4e--view-temp-dirs) - (ignore-errors (delete-directory dir))) - (setq mu4e--view-temp-dirs nil)) + (setq mu4e--view-gnus-article-mime-handles nil)) + ;; Delete temp files created for opening MIME-parts externally. + (dolist (file mu4e--view-temp-files) + (ignore-errors (delete-file file))) + (setq mu4e--view-temp-files nil)) ;;; MIME-parts (defvar-local mu4e--view-mime-parts nil @@ -438,23 +438,25 @@ Each of the actions is a plist with keys (defun mu4e--view-mime-part-to-temp-file (handle) "Write MIME-part HANDLE to a temporary file and return the file name. + The filename is deduced from the MIME-part's filename, or otherwise random; the result is placed in a temporary directory with a unique name. Returns the full path for the file created. -The directory is registered for cleanup when the current view -buffer is killed (see `mu4e--view-kill-temp-dirs')." - (let* ((tmpdir (make-temp-file "mu4e-temp-" t)) - (fname (mm-handle-filename handle)) + +The file is registered for cleanup when the current view +buffer is killed." + (let* ((fname (mm-handle-filename handle)) (fname (and fname (gnus-map-function mm-file-name-rewrite-functions (file-name-nondirectory fname)))) (fname (if fname (mu4e-join-paths - tmpdir (replace-regexp-in-string "/" "-" fname)) - (let ((temporary-file-directory tmpdir)) - (make-temp-file "mimepart"))))) + mu4e--temp-dir + (replace-regexp-in-string "/" "-" fname)) + (let ((temporary-file-directory mu4e--temp-dir)) + (make-temp-file "mime-part-"))))) (mm-save-part-to-file handle fname) - (push tmpdir mu4e--view-temp-dirs) + (push fname mu4e--view-temp-files) fname)) (defun mu4e--view-open-file (file &optional force-ask) diff --git a/mu4e/mu4e-view.el b/mu4e/mu4e-view.el index 04948e21..b8117ba2 100644 --- a/mu4e/mu4e-view.el +++ b/mu4e/mu4e-view.el @@ -654,8 +654,7 @@ activates URLs (in plain-text mode only)." (setq mu4e--view-gnus-article-mime-handles gnus-article-mime-handles gnus-article-decoded-p gnus-article-decode-hook) (set-buffer-modified-p nil) - (add-hook 'kill-buffer-hook #'mu4e--view-kill-mime-handles) - (add-hook 'kill-buffer-hook #'mu4e--view-kill-temp-dirs)) + (add-hook 'kill-buffer-hook #'mu4e--view-buffer-cleanup)) (epg-error (mu4e-message "EPG error: %s; fall back to raw view" (error-message-string err)))))) diff --git a/mu4e/mu4e.el b/mu4e/mu4e.el index 75e3ed23..97c9a45d 100644 --- a/mu4e/mu4e.el +++ b/mu4e/mu4e.el @@ -158,6 +158,9 @@ mu4e is already running, invoke FUNC (if non-nil). Otherwise, check requirements, then start mu4e. When successful, invoke FUNC (if available) afterwards." + ;; create dir for temporary files. + (unless (and mu4e--temp-dir (file-directory-p mu4e--temp-dir)) + (setq mu4e--temp-dir (make-temp-file "mu4e-" t))) (unless (mu4e-context-current) (mu4e--context-autoswitch nil mu4e-context-policy)) (setq mu4e-pong-func @@ -216,7 +219,10 @@ invoke FUNC (if available) afterwards." (when (member major-mode '(mu4e-headers-mode mu4e-view-mode mu4e-main-mode)) (kill-buffer))))) - (buffer-list))) + (buffer-list)) + (when mu4e--temp-dir + (ignore-errors (delete-directory mu4e--temp-dir 'recursive)) + (setq mu4e--temp-dir nil))) ;;; Handlers (defun mu4e--default-handler (&rest args)