* implement additional attachment handling functions; update for new backend protocol

This commit is contained in:
djcb 2012-04-15 14:22:43 +03:00
parent c71ccfcd65
commit 6b4ced1f4f
3 changed files with 119 additions and 44 deletions

View File

@ -114,7 +114,7 @@ Also see `mu4e-headers-visible-lines' and `mu4e-headers-visible-columns'.")
"E-mail-sending related settings for mu4e." "E-mail-sending related settings for mu4e."
:group 'mu4e) :group 'mu4e)
;; Folders ;; Folders
(defgroup mu4e-folders nil (defgroup mu4e-folders nil
"Special folders." "Special folders."
@ -525,6 +525,10 @@ the server process.")
(defvar mu4e-pong-func 'mu4e--default-handler (defvar mu4e-pong-func 'mu4e--default-handler
"A function called for each (:pong type ....) sexp received from "A function called for each (:pong type ....) sexp received from
the server process.") the server process.")
(defvar mu4e-temp-func 'mu4e--default-handler
"A function called for each (:temp <file> <cookie>) sexp received
from the server process.")
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

View File

@ -41,7 +41,7 @@
(defun mu4e-view-message-with-msgid (msgid) (defun mu4e-view-message-with-msgid (msgid)
"View message with MSGID. This is meant for external programs "View message with MSGID. This is meant for external programs
wanting to show specific messages - for example, `mu4e-org'." wanting to show specific messages - for example, `mu4e-org'."
(mu4e-proc-view-msg msgid)) (mu4e-proc-view msgid))
(defun mu4e-view (msg hdrsbuf &optional update) (defun mu4e-view (msg hdrsbuf &optional update)
"Display the message MSG in a new buffer, and keep in sync with HDRSBUF. "Display the message MSG in a new buffer, and keep in sync with HDRSBUF.
@ -57,6 +57,7 @@ marking if it still had that."
(inhibit-read-only t)) (inhibit-read-only t))
(with-current-buffer buf (with-current-buffer buf
(setq mu4e-view-buffer buf) (setq mu4e-view-buffer buf)
(setq mu4e-attach-map nil) ;; clear any old attachment stuff
(erase-buffer) (erase-buffer)
(insert (insert
(mapconcat (mapconcat
@ -160,16 +161,15 @@ marking if it still had that."
(defvar mu4e-attach-map nil (defvar mu4e-attach-map nil
"*internal* Hash which maps a number to a (part-id name mime-type).") "*internal* Hash which maps a number to a (part-id name mime-type).")
(defun mu4e-open-save-attach-func (num is-open) (defun mu4e-open-save-attach-func (num is-open)
"Return a function that offers to extracts (saves) attachment NUM "Return a function that offers to save attachment NUM. If IS-OPEN
if IS-OPEN is nil, and otherwise open it." is nil, and otherwise open it."
(lexical-let ((num num) (is-open is-open)) (lexical-let ((num num) (is-open is-open))
(lambda () (lambda ()
(interactive) (interactive)
(if is-open (if is-open
(mu4e-view-open-attachment num) (mu4e-view-open-attachment num)
(mu4e-view-extract-attachment num))))) (mu4e-view-save-attachment num)))))
(defun mu4e-view-attachments (msg) (defun mu4e-view-attachments (msg)
"Display attachment information; the field looks like something like: "Display attachment information; the field looks like something like:
@ -264,10 +264,10 @@ if IS-OPEN is nil, and otherwise open it."
(define-key map "y" 'mu4e-select-other-view) (define-key map "y" 'mu4e-select-other-view)
;; attachments ;; attachments
(define-key map "e" 'mu4e-view-extract-attachment) (define-key map "e" 'mu4e-view-save-attachment)
(define-key map "o" 'mu4e-view-open-attachment) (define-key map "o" 'mu4e-view-open-attachment)
(define-key map "a" 'mu4e-view-handle-attachment) (define-key map "a" 'mu4e-view-handle-attachment)
;; marking/unmarking ;; marking/unmarking
(define-key map (kbd "<backspace>") 'mu4e-mark-for-trash) (define-key map (kbd "<backspace>") 'mu4e-mark-for-trash)
(define-key map "d" 'mu4e-view-mark-for-trash) (define-key map "d" 'mu4e-view-mark-for-trash)
@ -315,7 +315,7 @@ if IS-OPEN is nil, and otherwise open it."
(define-key menumap [open-att] (define-key menumap [open-att]
'("Open attachment" . mu4e-view-open-attachment)) '("Open attachment" . mu4e-view-open-attachment))
(define-key menumap [extract-att] (define-key menumap [extract-att]
'("Extract attachment" . mu4e-view-extract-attachment)) '("Extract attachment" . mu4e-view-save-attachment))
(define-key menumap [goto-url] (define-key menumap [goto-url]
'("Visit URL" . mu4e-view-go-to-url)) '("Visit URL" . mu4e-view-go-to-url))
@ -367,8 +367,8 @@ if IS-OPEN is nil, and otherwise open it."
(setq truncate-lines t)) (setq truncate-lines t))
;; we mark messages are as read when we leave the message; i.e., when skipping to ;; we mark messages are as read when we leave the message; i.e., when skipping
;; the next/previous one, or leaving the view buffer altogether. ;; to the next/previous one, or leaving the view buffer altogether.
(defun mu4e-view-mark-as-read-maybe () (defun mu4e-view-mark-as-read-maybe ()
"Clear the current message's New/Unread status and set it to "Clear the current message's New/Unread status and set it to
@ -378,8 +378,7 @@ Seen; if the message is not New/Unread, do nothing."
(docid (plist-get mu4e-current-msg :docid))) (docid (plist-get mu4e-current-msg :docid)))
;; is it a new message? ;; is it a new message?
(when (or (member 'unread flags) (member 'new flags)) (when (or (member 'unread flags) (member 'new flags))
(mu4e-proc-flag docid "+S-u-N"))))) (mu4e-proc-move docid nil "+S-u-N")))))
(defun mu4e-color-cited () (defun mu4e-color-cited ()
"Colorize message content based on the citation level." "Colorize message content based on the citation level."
@ -574,35 +573,87 @@ citations."
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; attachment handling ;; attachment handling
(defun mu4e--get-attach-count ()
"Get the number of attachments for this message."
(if (null mu4e-attach-map)
0
(hash-table-count mu4e-attach-map)))
(defun mu4e-view-extract-attachment (attnum) (defun mu4e--get-valid-attach (prompt &optional attachnum)
"Extract the attachment with ATTNUM." "Find an attachment sexp for attachment by asking user with
(interactive "nAttachment to extract:") PROMPT. Return the sexp with this is present in the message, nil
(unless mu4e-attachment-dir (error "`mu4e-attachment-dir' is not set")) otherwise. If (optional) INDEX is provided, don't ask user but just
(when (or (null mu4e-attach-map) (zerop (hash-table-count mu4e-attach-map))) return the corresponding attachment sexp."
(error "No attachments for this message")) (let ((count (mu4e--get-attach-count)))
(let* ((att (gethash attnum mu4e-attach-map)) (when (zerop count)
(path (and att (concat mu4e-attachment-dir (error "No attachments for this message"))
"/" (plist-get att :name)))) (let* ((attnum
(id (and att (plist-get att :index))) (or attachnum
(if (= count 1)
(read-number (format "%s (1): " prompt) 1)
(read-number (format "%s (1-%d): " prompt count)))))
(att (gethash attnum mu4e-attach-map)))
(unless att
(error "Not a valid attachment number"))
att)))
(defun mu4e-view-save-attachment (&optional attachnum)
"Save some attachment (ask user which)."
(interactive)
(unless mu4e-attachment-dir
(error "`mu4e-attachment-dir' is not set"))
(let* ((att (mu4e--get-valid-attach "Attachment to save" attachnum))
(path (concat mu4e-attachment-dir
"/" (plist-get att :name)))
(index (plist-get att :index))
(retry t)) (retry t))
(unless att (error "Not a valid attachment number"))
(while retry (while retry
(setq path (expand-file-name (read-string "Save as " path))) (setq path (expand-file-name (read-string "Save as " path)))
(setq retry (setq retry
(and (file-exists-p path) (and (file-exists-p path)
(not (y-or-n-p (concat "Overwrite " path "?")))))) (not (y-or-n-p (concat "Overwrite " path "?"))))))
(mu4e-proc-save (plist-get mu4e-current-msg :docid) id path))) (mu4e-proc-extract
'save (plist-get mu4e-current-msg :docid) index path)))
(defun mu4e-view-open-attachment (attnum) (defun mu4e-view-open-attachment (&optional attachnum)
"Extract the attachment with ATTNUM" "Open some attachment (ask user which)."
(interactive "nAttachment to open:") (interactive)
(unless mu4e-attach-map (let* ((att (mu4e--get-valid-attach "Attachment to open" attachnum))
(error "No attachments for this message")) (index (plist-get att :index)))
(let* ((att (gethash attnum mu4e-attach-map)) (mu4e-proc-extract 'open
(id (and att (plist-get att :index)))) (plist-get mu4e-current-msg :docid) index)))
(unless id (error "Not a valid attachment number"))
(mu4e-proc-open (plist-get mu4e-current-msg :docid) id))) (defun mu4e--temp-action (docid index what &optional param)
"Open attachment INDEX for message with DOCID, and invoke
ACTION."
(interactive)
(mu4e-proc-extract 'temp docid index nil what param))
(defun mu4e-view-open-attachment-with ()
"Open some attachment with some program (ask user which)."
(interactive)
(let* ((att (mu4e--get-valid-attach "Attachment to open"))
(cmd (read-string "Shell command to open it with: "))
(index (plist-get att :index)))
(mu4e--temp-action (plist-get mu4e-current-msg :docid) index
"open-with" cmd)))
(defun mu4e-view-pipe-attachment ()
"Open some attachment with some program (ask user which)."
(interactive)
(let* ((att (mu4e--get-valid-attach "Attachment to process"))
(cmd (read-string "Pipe: "))
(index (plist-get att :index)))
(mu4e--temp-action (plist-get mu4e-current-msg :docid) index
"pipe" cmd)))
(defun mu4e-view-open-attachment-emacs ()
"Open some attachment in the current emacs instance."
(interactive)
(let* ((att (mu4e--get-valid-attach "Attachment to open in current emacs"))
(index (plist-get att :index)))
(mu4e--temp-action (plist-get mu4e-current-msg :docid) index
"emacs")))
(defun mu4e-view-handle-attachment () (defun mu4e-view-handle-attachment ()
"Ask user what to do with attachments, then do it." "Ask user what to do with attachments, then do it."
@ -610,17 +661,34 @@ citations."
(let ((choice (let ((choice
(mu4e-read-option (mu4e-read-option
"Handle attachments: " "Handle attachments: "
'(("open") '(("open-with" ?w)
("pen all" ?O) ("in emacs" ?e)
("save") ("pipe" ?|)))))
("ave all" ?S)
("ipe" ?p)
("macs" ?e)))))
(case choice (case choice
(?o (call-interactively 'mu4e-view-open-attachment)) (?w (call-interactively 'mu4e-view-open-attachment-with))
(?s (call-interactively 'mu4e-view-extract-attachment)) (?| (call-interactively 'mu4e-view-pipe-attachment))
(?e (call-interactively 'mu4e-view-open-attachment-emacs))
(otherwise (message "Not yet implemented"))))) (otherwise (message "Not yet implemented")))))
;; handler-function to handle the response we get from the server when we
;; want to do something with one of the attachments.
(defun mu4e-view-temp-handler (path what param)
"Handler function for doing things with temp files (ie.,
attachments) in response to a (mu4e-proc-extract 'temp ... )."
(cond
((string= what "open-with")
;; 'param' will be the program to open-with
(start-file-process-shell-command "*mu4e-open-with*" nil
(concat param " " path)))
((string= what "pipe")
;; 'param' will be the pipe command, path the infile for this
(switch-to-buffer (get-buffer-create "*mu4e-output*"))
(erase-buffer)
(call-process-shell-command param path t t)
(view-mode))
((string= what "emacs")
(find-file path))
(t (error "Unsupported action %S" what))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun mu4e--in-split-view () (defun mu4e--in-split-view ()
@ -674,5 +742,4 @@ results."
(mu4e-view-shell-command-on-raw-message mu4e-current-msg (mu4e-view-shell-command-on-raw-message mu4e-current-msg
(current-buffer) cmd)) (current-buffer) cmd))
(provide 'mu4e-view) (provide 'mu4e-view)

View File

@ -42,7 +42,7 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; register our handler functions; these connect server messages to functions ;; register our handler functions; these connect server messages to functions
;; to handle them. ;; to handle them.
;; ;;
;; ;;
;; these are all defined in mu4e-hdrs ;; these are all defined in mu4e-hdrs
@ -64,6 +64,10 @@
;; note: mu4e-compose.el dynamically registers mu4e-sent-func ;; note: mu4e-compose.el dynamically registers mu4e-sent-func
;; we don't do that here, because it's only a local (temporary) ;; we don't do that here, because it's only a local (temporary)
;; handler ;; handler
;; this one is defined in mu4e-view
(setq mu4e-temp-func 'mu4e-view-temp-handler)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;