From 76e70185a2bce1269f158b5edfc23dc54b2230f8 Mon Sep 17 00:00:00 2001 From: djcb Date: Thu, 7 Jun 2012 16:24:58 +0300 Subject: [PATCH] * mu4e: support extracting ranges of attachments (C-u e); contributed by Stephen Eglen. --- emacs/mu4e-utils.el | 36 ++++++++++++++++++++++++++++++++++ emacs/mu4e-view.el | 48 +++++++++++++++++++++++++++++++++++++-------- emacs/mu4e.texi | 6 ++++++ 3 files changed, 82 insertions(+), 8 deletions(-) diff --git a/emacs/mu4e-utils.el b/emacs/mu4e-utils.el index d48f67bb..62a04a08 100644 --- a/emacs/mu4e-utils.el +++ b/emacs/mu4e-utils.el @@ -726,6 +726,42 @@ mu4e logs some of its internal workings to a log-buffer. See (unless (buffer-live-p buf) (error "No debug log available")) (switch-to-buffer buf))) + + + +(defun mu4e-split-ranges-to-numbers (str n) + "Convert STR containing attachment numbers into a list of numbers. +STR is a string; N is the highest possible number in the list. +This includes expanding e.g. 3-5 into 3,4,5. If the letter +\"a\" ('all')) is given, that is expanded to a list with numbers [1..n]." + (let ((str-split (split-string str)) + beg end list) + (dolist (elem str-split list) + ;; special number "a" converts into all attachments 1-N. + (when (equal elem "a") + (setq elem (concat "1-" (int-to-string n)))) + (if (string-match "\\([0-9]+\\)-\\([0-9]+\\)" elem) + ;; we have found a range A-B, which needs converting + ;; into the numbers A, A+1, A+2, ... B. + (progn + (setq beg (string-to-int (match-string 1 elem)) + end (string-to-int (match-string 2 elem))) + (while (<= beg end) + (add-to-list 'list beg 'append) + (setq beg (1+ beg)))) + ;; else just a number + (add-to-list 'list (string-to-int elem) 'append))) + ;; Check that all numbers are valid. + (mapc + '(lambda (x) + (cond + ((> x n) + (error "Attachment %d bigger than maximum (%d)" x n)) + ((< x 1) + (error "Attachment number must be greater than 0 (%d)" x)))) + list))) + + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defvar mu4e-imagemagick-identify "identify" diff --git a/emacs/mu4e-view.el b/emacs/mu4e-view.el index da4a3fde..b4d82494 100644 --- a/emacs/mu4e-view.el +++ b/emacs/mu4e-view.el @@ -753,16 +753,23 @@ all messages in the thread at point in the headers view." ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; attachment handling -(defun mu4e~view-get-attach-num (prompt msg) +(defun mu4e~view-get-attach-num (prompt msg &optional multi) "Ask the user with PROMPT for an attachment number for MSG, and ensure it is valid. The number is [1..n] for attachments - [0..(n-1)] in the message." - (let* ((count (hash-table-count mu4e~view-attach-map))) + [0..(n-1)] in the message. If MULTI is nil, return the number for + the attachment; otherwise (MULTI is non-nil), accept ranges of + attachment numbers, as per `mu4e-split-ranges-to-numbers', and + return the corresponding string." + (let* ((count (hash-table-count mu4e~view-attach-map)) (def)) (when (zerop count) (error "No attachments for this message")) - (if (= count 1) - (read-number (mu4e-format "%s: " prompt) 1) - (read-number (mu4e-format "%s (1-%d): " prompt count))))) - + (if (not multi) + (if (= count 1) + (read-number (mu4e-format "%s: " prompt) 1) + (read-number (mu4e-format "%s (1-%d): " prompt count))) + (progn + (setq def (if (= count 1) "1" (format "1-%d" count))) + (read-string (mu4e-format "%s (default %s): " prompt def) nil nil def))))) + (defun mu4e~view-get-attach (msg attnum) "Return the attachment plist in MSG corresponding to attachment number ATTNUM." @@ -773,7 +780,7 @@ number ATTNUM." (plist-get msg :parts)))) -(defun mu4e-view-save-attachment (&optional msg attnum) +(defun mu4e-view-save-attachment-single (&optional msg attnum) "Save attachment number ATTNUM (or ask if nil) from MSG (or message-at-point if nil) to disk." (interactive) @@ -795,6 +802,31 @@ message-at-point if nil) to disk." (mu4e~proc-extract 'save (plist-get msg :docid) index path))) +(defun mu4e-view-save-attachment-multi (&optional msg) + "Offer to save multiple email attachments from the current message. +Default is to save all messages, [1..n], where n is the number of +attachments. You can type multiple values separated by space, e.g. + 1 3-6 8 +will save attachments 1,3,4,5,6 and 8. + +Furthermore, there is a shortcut \"a\" which so means all +attachments, but as this is the default, you may not need it." + (interactive) + (let* ((msg (or msg (mu4e-message-at-point))) + (attachstr (mu4e~view-get-attach-num + "Attachment number range (or 'a' for 'all')" msg t)) + (attachnums (mu4e-split-ranges-to-numbers attachstr count))) + (dolist (num attachnums) + (mu4e-view-save-attachment-single msg num)))) + +(defun mu4e-view-save-attachment (&optional multi) + "Offer to save attachment(s). If MULTI (prefix-argument) is nil, +save a single one, otherwise, offer to save a range of +attachments." + (interactive "P") + (if multi + (mu4e-view-save-attachment-multi) + (mu4e-view-save-attachment-single))) (defun mu4e-view-open-attachment (&optional msg attnum) "Open attachment number ATTNUM (or ask if nil) from MSG (or diff --git a/emacs/mu4e.texi b/emacs/mu4e.texi index 00465faa..2d25e8ce 100644 --- a/emacs/mu4e.texi +++ b/emacs/mu4e.texi @@ -734,6 +734,7 @@ g go to (visit) numbered URL (using `browse-url') (or: or RET with point on url) e extract (save) attachment (asks for number) (or: or RET with point on attachment) + C-u e will extract multiple attachments o open attachment (asks for number) (or: or S-RET with point on attachment) A execute some action on an attachment @@ -761,6 +762,11 @@ variable @code{mu4e-attachment-dir}, for example: (setq mu4e-attachment-dir (file-name-expand "~/Downloads")) @end lisp +If you want to extract multiple attachments at once, you can do so by +prefixing the extracting command by @key{C-u}; so @key{C-u e} will ask you for +a range of attachments to extract (for example, 1 3-6 8). Range @t{a} is a +shortcut for @emph{all} attachments. + @subsection Viewing images inline @anchor{Viewing images inline}