[PATCH v4 1/1] Make buttons for attachments allow viewing as well as saving
authorMark Walters <markwalters1009@gmail.com>
Thu, 19 Jan 2012 21:23:05 +0000 (21:23 +0000)
committerW. Trevor King <wking@tremily.us>
Fri, 7 Nov 2014 17:42:44 +0000 (09:42 -0800)
2b/8fcb4b2fa28574e5bd2ad95199a55892a7d100 [new file with mode: 0644]

diff --git a/2b/8fcb4b2fa28574e5bd2ad95199a55892a7d100 b/2b/8fcb4b2fa28574e5bd2ad95199a55892a7d100
new file mode 100644 (file)
index 0000000..86ec47d
--- /dev/null
@@ -0,0 +1,238 @@
+Return-Path: <markwalters1009@gmail.com>\r
+X-Original-To: notmuch@notmuchmail.org\r
+Delivered-To: notmuch@notmuchmail.org\r
+Received: from localhost (localhost [127.0.0.1])\r
+       by olra.theworths.org (Postfix) with ESMTP id 29DD2431FAE\r
+       for <notmuch@notmuchmail.org>; Thu, 19 Jan 2012 13:22:42 -0800 (PST)\r
+X-Virus-Scanned: Debian amavisd-new at olra.theworths.org\r
+X-Spam-Flag: NO\r
+X-Spam-Score: 0.201\r
+X-Spam-Level: \r
+X-Spam-Status: No, score=0.201 tagged_above=-999 required=5\r
+       tests=[DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1,\r
+       FREEMAIL_ENVFROM_END_DIGIT=1, FREEMAIL_FROM=0.001,\r
+       RCVD_IN_DNSWL_LOW=-0.7] autolearn=disabled\r
+Received: from olra.theworths.org ([127.0.0.1])\r
+       by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)\r
+       with ESMTP id 092KA9m-pB5d for <notmuch@notmuchmail.org>;\r
+       Thu, 19 Jan 2012 13:22:39 -0800 (PST)\r
+Received: from mail-ww0-f45.google.com (mail-ww0-f45.google.com\r
+ [74.125.82.45])       (using TLSv1 with cipher RC4-SHA (128/128 bits))        (No client\r
+ certificate requested)        by olra.theworths.org (Postfix) with ESMTPS id\r
+ A7725431FB6   for <notmuch@notmuchmail.org>; Thu, 19 Jan 2012 13:22:37 -0800\r
+ (PST)\r
+Received: by wgbdt12 with SMTP id dt12so400608wgb.2\r
+       for <notmuch@notmuchmail.org>; Thu, 19 Jan 2012 13:22:36 -0800 (PST)\r
+DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma;\r
+       h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references;\r
+       bh=jpMQQrJWRh6ucDHFQC2wfBL7Dm+6z/19GhiWGfz9aL4=;\r
+       b=e6WXSXqJ+oMNnQR77xi0HLsjcsBSon5xibhE0Kfp2z1Ac9bmY6j8df6XHJ8e3aH3qn\r
+       SJiczhQo9Ac5kHUG0n3rmYvlw+dxCEuyLYbWndddyXev4GXo6IijyRlTQSH1LX1BGIMY\r
+       K+qEW985xCT74i10xf582X2pV2F+RQ3MVw/DU=\r
+Received: by 10.180.100.100 with SMTP id ex4mr19447700wib.19.1327008156503;\r
+       Thu, 19 Jan 2012 13:22:36 -0800 (PST)\r
+Received: from localhost (94-192-233-223.zone6.bethere.co.uk.\r
+ [94.192.233.223])     by mx.google.com with ESMTPS id\r
+ dr5sm2051181wib.0.2012.01.19.13.22.34 (version=TLSv1/SSLv3 cipher=OTHER);\r
+       Thu, 19 Jan 2012 13:22:35 -0800 (PST)\r
+From: Mark Walters <markwalters1009@gmail.com>\r
+To: notmuch@notmuchmail.org\r
+Subject: [PATCH v4 1/1] Make buttons for attachments allow viewing as well as\r
+       saving\r
+Date: Thu, 19 Jan 2012 21:23:05 +0000\r
+Message-Id: <1327008185-21194-2-git-send-email-markwalters1009@gmail.com>\r
+X-Mailer: git-send-email 1.7.2.3\r
+In-Reply-To: <id:"20120118192147.GF16740@mit.edu">\r
+References: <id:"20120118192147.GF16740@mit.edu">\r
+X-BeenThere: notmuch@notmuchmail.org\r
+X-Mailman-Version: 2.1.13\r
+Precedence: list\r
+List-Id: "Use and development of the notmuch mail system."\r
+       <notmuch.notmuchmail.org>\r
+List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
+       <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
+List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
+List-Post: <mailto:notmuch@notmuchmail.org>\r
+List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
+List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
+       <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
+X-List-Received-Date: Thu, 19 Jan 2012 21:22:42 -0000\r
+\r
+Define a keymap for attachment buttons to allow multiple actions.\r
+Define 3 possible actions:\r
+    save attachment: exactly as currently,\r
+    view attachment: uses mailcap entry,\r
+    view attachment with user chosen program\r
+\r
+Keymap on a button is: s for save, v for view and o for view with\r
+other program. Default (i.e. enter or mouse button) is save but this\r
+is configurable in notmuch customize.\r
+\r
+One implementation detail: the view attachment function forces all\r
+attachments to be "displayed" using mailcap even if emacs could\r
+display them itself. Thus, for example, text/html appears in a browser\r
+and text/plain asks whether to save (on a standard debian setup)\r
+---\r
+ emacs/notmuch-show.el |  116 ++++++++++++++++++++++++++++++++++++++----------\r
+ 1 files changed, 92 insertions(+), 24 deletions(-)\r
+\r
+diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el\r
+index fc13462..1fcd72a 100644\r
+--- a/emacs/notmuch-show.el\r
++++ b/emacs/notmuch-show.el\r
+@@ -112,6 +112,16 @@ indentation."\r
+   :type 'boolean\r
+   :group 'notmuch-show)\r
\r
++(defcustom notmuch-show-part-button-default-action 'notmuch-show-save-part\r
++  "Default part header button action (on ENTER or mouse click)."\r
++  :group 'notmuch-show\r
++  :type '(choice (const :tag "Save part"\r
++                      notmuch-show-save-part)\r
++               (const :tag "View part"\r
++                      notmuch-show-view-part)\r
++               (const :tag "View interactively"\r
++                      notmuch-show-interactively-view-part)))\r
++\r
+ (defmacro with-current-notmuch-show-message (&rest body)\r
+   "Evaluate body with current buffer set to the text of current message"\r
+   `(save-excursion\r
+@@ -283,10 +293,21 @@ message at DEPTH in the current thread."\r
+       (run-hooks 'notmuch-show-markup-headers-hook)))))\r
\r
+ (define-button-type 'notmuch-show-part-button-type\r
+-  'action 'notmuch-show-part-button-action\r
++  'action 'notmuch-show-part-button-default\r
++  'keymap 'notmuch-show-part-button-map\r
+   'follow-link t\r
+   'face 'message-mml)\r
\r
++(defvar notmuch-show-part-button-map\r
++  (let ((map (make-sparse-keymap)))\r
++    (set-keymap-parent map button-map)\r
++    (define-key map "s" 'notmuch-show-part-button-save)\r
++    (define-key map "v" 'notmuch-show-part-button-view)\r
++    (define-key map "o" 'notmuch-show-part-button-interactively-view)\r
++    map)\r
++  "Submap for button commands")\r
++(fset 'notmuch-show-part-button-map notmuch-show-part-button-map)\r
++\r
+ (defun notmuch-show-insert-part-header (nth content-type declared-type &optional name comment)\r
+   (let ((button))\r
+     (setq button\r
+@@ -301,29 +322,58 @@ message at DEPTH in the current thread."\r
+                  " ]")\r
+          :type 'notmuch-show-part-button-type\r
+          :notmuch-part nth\r
+-         :notmuch-filename name))\r
++         :notmuch-filename name\r
++         :notmuch-content-type content-type))\r
+     (insert "\n")\r
+     ;; return button\r
+     button))\r
\r
+ ;; Functions handling particular MIME parts.\r
\r
+-(defun notmuch-show-save-part (message-id nth &optional filename)\r
+-  (let ((process-crypto notmuch-show-process-crypto))\r
+-    (with-temp-buffer\r
+-      (setq notmuch-show-process-crypto process-crypto)\r
+-      ;; Always acquires the part via `notmuch part', even if it is\r
+-      ;; available in the JSON output.\r
+-      (insert (notmuch-show-get-bodypart-internal message-id nth))\r
+-      (let ((file (read-file-name\r
+-                 "Filename to save as: "\r
+-                 (or mailcap-download-directory "~/")\r
+-                 nil nil\r
+-                 filename)))\r
+-      ;; Don't re-compress .gz & al.  Arguably we should make\r
+-      ;; `file-name-handler-alist' nil, but that would chop\r
+-      ;; ange-ftp, which is reasonable to use here.\r
+-      (mm-write-region (point-min) (point-max) file nil nil nil 'no-conversion t)))))\r
++(defmacro notmuch-with-temp-part-buffer (message-id nth &rest body)\r
++  (declare (indent 2))\r
++  (let ((process-crypto (make-symbol "process-crypto")))\r
++    `(let ((,process-crypto notmuch-show-process-crypto))\r
++       (with-temp-buffer\r
++       (setq notmuch-show-process-crypto ,process-crypto)\r
++       ;; Always acquires the part via `notmuch part', even if it is\r
++       ;; available in the JSON output.\r
++       (insert (notmuch-show-get-bodypart-internal ,message-id ,nth))\r
++       ,@body))))\r
++\r
++(defun notmuch-show-save-part (message-id nth &optional filename content-type)\r
++  (notmuch-with-temp-part-buffer message-id nth\r
++    (let ((file (read-file-name\r
++               "Filename to save as: "\r
++               (or mailcap-download-directory "~/")\r
++               nil nil\r
++               filename)))\r
++      ;; Don't re-compress .gz & al.  Arguably we should make\r
++      ;; `file-name-handler-alist' nil, but that would chop\r
++      ;; ange-ftp, which is reasonable to use here.\r
++      (mm-write-region (point-min) (point-max) file nil nil nil 'no-conversion t))))\r
++\r
++(defun notmuch-show-view-part (message-id nth &optional filename content-type )\r
++  (notmuch-with-temp-part-buffer message-id nth\r
++    ;; set mm-inlined-types to nil to force an external viewer\r
++    (let ((handle (mm-make-handle (current-buffer) (list content-type)))\r
++        (mm-inlined-types nil))\r
++      ;; We override mm-save-part as notmuch-show-save-part is better\r
++      ;; since it offers the filename. We need to lexically bind\r
++      ;; everything we need for notmuch-show-save-part to prevent\r
++      ;; potential dynamic shadowing.\r
++      (lexical-let ((message-id message-id)\r
++                  (nth nth)\r
++                  (filename filename)\r
++                  (content-type content-type))\r
++                 (flet ((mm-save-part (&rest args) (notmuch-show-save-part\r
++                                                    message-id nth filename content-type)))\r
++                   (mm-display-part handle))))))\r
++\r
++(defun notmuch-show-interactively-view-part (message-id nth &optional filename content-type)\r
++  (notmuch-with-temp-part-buffer message-id nth\r
++    (let ((handle (mm-make-handle (current-buffer) (list content-type))))\r
++      (mm-interactively-view-part handle))))\r
\r
+ (defun notmuch-show-mm-display-part-inline (msg part nth content-type)\r
+   "Use the mm-decode/mm-view functions to display a part in the\r
+@@ -1504,12 +1554,30 @@ buffer."\r
\r
+ ;; Commands typically bound to buttons.\r
\r
+-(defun notmuch-show-part-button-action (button)\r
+-  (let ((nth (button-get button :notmuch-part)))\r
+-    (if nth\r
+-      (notmuch-show-save-part (notmuch-show-get-message-id) nth\r
+-                              (button-get button :notmuch-filename))\r
+-      (message "Not a valid part (is it a fake part?)."))))\r
++(defun notmuch-show-part-button-default (&optional button)\r
++  (interactive)\r
++  (notmuch-show-part-button-internal button notmuch-show-part-button-default-action))\r
++\r
++(defun notmuch-show-part-button-save (&optional button)\r
++  (interactive)\r
++  (notmuch-show-part-button-internal button #'notmuch-show-save-part))\r
++\r
++(defun notmuch-show-part-button-view (&optional button)\r
++  (interactive)\r
++  (notmuch-show-part-button-internal button #'notmuch-show-view-part))\r
++\r
++(defun notmuch-show-part-button-interactively-view (&optional button)\r
++  (interactive)\r
++  (notmuch-show-part-button-internal button #'notmuch-show-interactively-view-part))\r
++\r
++(defun notmuch-show-part-button-internal (button handler)\r
++  (let ((button (or button (button-at (point)))))\r
++    (if button\r
++      (let ((nth (button-get button :notmuch-part)))\r
++        (if nth\r
++            (funcall handler (notmuch-show-get-message-id) nth\r
++                     (button-get button :notmuch-filename)\r
++                     (button-get button :notmuch-content-type)))))))\r
\r
+ ;;\r
\r
+-- \r
+1.7.2.3\r
+\r