--- /dev/null
+Return-Path: <amdragon@mit.edu>\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 C9DC0431FAE\r
+ for <notmuch@notmuchmail.org>; Sat, 24 Jan 2015 13:17:25 -0800 (PST)\r
+X-Virus-Scanned: Debian amavisd-new at olra.theworths.org\r
+X-Spam-Flag: NO\r
+X-Spam-Score: 0.138\r
+X-Spam-Level: \r
+X-Spam-Status: No, score=0.138 tagged_above=-999 required=5\r
+ tests=[DNS_FROM_AHBL_RHSBL=2.438, RCVD_IN_DNSWL_MED=-2.3]\r
+ 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 77GkLXxtUMUA for <notmuch@notmuchmail.org>;\r
+ Sat, 24 Jan 2015 13:17:22 -0800 (PST)\r
+Received: from dmz-mailsec-scanner-2.mit.edu (dmz-mailsec-scanner-2.mit.edu\r
+ [18.9.25.13])\r
+ (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits))\r
+ (No client certificate requested)\r
+ by olra.theworths.org (Postfix) with ESMTPS id D13F0431FD6\r
+ for <notmuch@notmuchmail.org>; Sat, 24 Jan 2015 13:17:13 -0800 (PST)\r
+X-AuditID: 1209190d-f79006d000000cfe-3e-54c40bd77bcd\r
+Received: from mailhub-auth-3.mit.edu ( [18.9.21.43])\r
+ (using TLS with cipher DHE-RSA-AES256-SHA (256/256 bits))\r
+ (Client did not present a certificate)\r
+ by dmz-mailsec-scanner-2.mit.edu (Symantec Messaging Gateway) with SMTP\r
+ id BD.F2.03326.7DB04C45; Sat, 24 Jan 2015 16:17:11 -0500 (EST)\r
+Received: from outgoing.mit.edu (outgoing-auth-1.mit.edu [18.9.28.11])\r
+ by mailhub-auth-3.mit.edu (8.13.8/8.9.2) with ESMTP id t0OLHA06027949; \r
+ Sat, 24 Jan 2015 16:17:10 -0500\r
+Received: from drake (216-15-114-40.c3-0.arl-ubr1.sbo-arl.ma.cable.rcn.com\r
+ [216.15.114.40]) (authenticated bits=0)\r
+ (User authenticated as amdragon@ATHENA.MIT.EDU)\r
+ by outgoing.mit.edu (8.13.8/8.12.4) with ESMTP id t0OLH6ma007462\r
+ (version=TLSv1/SSLv3 cipher=AES128-SHA bits=128 verify=NOT);\r
+ Sat, 24 Jan 2015 16:17:07 -0500\r
+Received: from amthrax by drake with local (Exim 4.84)\r
+ (envelope-from <amdragon@mit.edu>)\r
+ id 1YF84n-0005Ro-Mw; Sat, 24 Jan 2015 16:17:05 -0500\r
+From: Austin Clements <amdragon@mit.edu>\r
+To: notmuch@notmuchmail.org\r
+Subject: [PATCH v2 7/8] emacs: Rewrite content ID handling\r
+Date: Sat, 24 Jan 2015 16:17:02 -0500\r
+Message-Id: <1422134223-20739-8-git-send-email-amdragon@mit.edu>\r
+X-Mailer: git-send-email 2.1.3\r
+In-Reply-To: <1422134223-20739-1-git-send-email-amdragon@mit.edu>\r
+References: <1422134223-20739-1-git-send-email-amdragon@mit.edu>\r
+X-Brightmail-Tracker:\r
+ H4sIAAAAAAAAA+NgFrrJIsWRmVeSWpSXmKPExsUixCmqrXud+0iIwc3X0hY3WrsZLfbd2cJk\r
+ sXouj8X1mzOZLd6snMfqwOqx6/lfJo+ds+6yexz+upDF49mqW8weWw69Zw5gjeKySUnNySxL\r
+ LdK3S+DKOHfoKXPBE8uKVVPOMDYwPtLrYuTkkBAwkZh2s50RwhaTuHBvPVsXIxeHkMBiJokT\r
+ bdPYIZyNjBLNTQ+ZIJyLTBJbn02HKpvEKPFszy2wfjYBDYnftxYzgdgiAtISO+/OZgWxmQXq\r
+ JP7OOQ9WIyxgJXHmTT9QDQcHi4CqxK2jISBhXgEHifv9exlBwhICchJb13mDhDkFHCVubNjF\r
+ AmILAZV0f25km8DIv4CRYRWjbEpulW5uYmZOcWqybnFyYl5eapGukV5uZoleakrpJkZwCEry\r
+ 7mB8d1DpEKMAB6MSD++Pf4dChFgTy4orcw8xSnIwKYnyrvp1OESILyk/pTIjsTgjvqg0J7X4\r
+ EKMEB7OSCO+FDUA53pTEyqrUonyYlDQHi5I476YffCFCAumJJanZqakFqUUwWRkODiUJ3sVc\r
+ R0KEBItS01Mr0jJzShDSTBycIMN5gIZ3g9TwFhck5hZnpkPkTzEqSonzrgdJCIAkMkrz4Hph\r
+ KeIVozjQK8K89SBVPMD0Atf9CmgwE9Dggu0HQAaXJCKkpBoYV534esOlOupyud5Pk+Xhmp/+\r
+ qzmFbLwsJi4/+3mt9coNer9u2nbe7uYWeysV9jPxeeqTTWuOm/ZYs//YfTpF4Wax3YId37TM\r
+ bpxKvvxUrzrpbanmTqWv6tbm26RYStRfT25eff9gfkh32XUl972VTam2zBGvdk3Z6qt3RrDt\r
+ z//ty+QUTm2JUGIpzkg01GIuKk4EAAEqXh3sAgAA\r
+Cc: tomi.ollila@iki.fi\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: Sat, 24 Jan 2015 21:17:26 -0000\r
+\r
+Besides generally cleaning up the code and separating the general\r
+content ID handling from the w3m-specific code, this fixes several\r
+problems.\r
+\r
+Foremost is that, previously, the code roughly assumed that referenced\r
+parts would be in the same multipart/related as the reference.\r
+According to RFC 2392, nothing could be further from the truth:\r
+content IDs are supposed to be globally unique and globally\r
+addressable. This is nonsense, but this patch at least fixes things\r
+so content IDs can be anywhere in the same message.\r
+\r
+As a side-effect of the above, this handles multipart/alternate\r
+content-IDs more in line with RFC 2046 section 5.1.2 (not that I've\r
+ever seen this in the wild). This also properly URL-decodes cid:\r
+URLs, as per RFC 2392 (the previous code did not), and applies crypto\r
+settings from the show buffer (the previous code used the global\r
+crypto settings).\r
+---\r
+ emacs/notmuch-show.el | 120 +++++++++++++++++++++++++++++++-------------------\r
+ 1 file changed, 74 insertions(+), 46 deletions(-)\r
+\r
+diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el\r
+index 11eac5f..34dcedd 100644\r
+--- a/emacs/notmuch-show.el\r
++++ b/emacs/notmuch-show.el\r
+@@ -525,6 +525,73 @@ (defun notmuch-show-toggle-part-invisibility (&optional button)\r
+ (overlay-put overlay 'invisible (not show))\r
+ t)))))\r
+ \r
++;; Part content ID handling\r
++\r
++(defvar notmuch-show--cids nil\r
++ "Alist from raw content ID to (MSG PART).")\r
++(make-variable-buffer-local 'notmuch-show--cids)\r
++\r
++(defun notmuch-show--register-cids (msg part)\r
++ "Register content-IDs in PART and all of PART's sub-parts."\r
++ (let ((content-id (plist-get part :content-id)))\r
++ (when content-id\r
++ ;; Note that content-IDs are globally unique, except when they\r
++ ;; aren't: RFC 2046 section 5.1.4 permits children of a\r
++ ;; multipart/alternative to have the same content-ID, in which\r
++ ;; case the MUA is supposed to pick the best one it can render.\r
++ ;; We simply add the content-ID to the beginning of our alist;\r
++ ;; so if this happens, we'll take the last (and "best")\r
++ ;; alternative (even if we can't render it).\r
++ (push (list content-id msg part) notmuch-show--cids)))\r
++ ;; Recurse on sub-parts\r
++ (let ((ctype (notmuch-split-content-type\r
++ (downcase (plist-get part :content-type)))))\r
++ (cond ((equal (first ctype) "multipart")\r
++ (mapc (apply-partially #'notmuch-show--register-cids msg)\r
++ (plist-get part :content)))\r
++ ((equal ctype '("message" "rfc822"))\r
++ (notmuch-show--register-cids\r
++ msg\r
++ (first (plist-get (first (plist-get part :content)) :body)))))))\r
++\r
++(defun notmuch-show--get-cid-content (cid)\r
++ "Return a list (CID-content content-type) or nil.\r
++\r
++This will only find parts from messages that have been inserted\r
++into the current buffer. CID must be a raw content ID, without\r
++enclosing angle brackets, a cid: prefix, or URL encoding. This\r
++will return nil if the CID is unknown or cannot be retrieved."\r
++ (let ((descriptor (cdr (assoc cid notmuch-show--cids))))\r
++ (when descriptor\r
++ (let* ((msg (first descriptor))\r
++ (part (second descriptor))\r
++ ;; Request caching for this content, as some messages\r
++ ;; reference the same cid: part many times (hundreds!).\r
++ (content (notmuch-get-bodypart-binary\r
++ msg part notmuch-show-process-crypto 'cache))\r
++ (content-type (plist-get part :content-type)))\r
++ (list content content-type)))))\r
++\r
++(defun notmuch-show-setup-w3m ()\r
++ "Instruct w3m how to retrieve content from a \"related\" part of a message."\r
++ (interactive)\r
++ (if (boundp 'w3m-cid-retrieve-function-alist)\r
++ (unless (assq 'notmuch-show-mode w3m-cid-retrieve-function-alist)\r
++ (push (cons 'notmuch-show-mode #'notmuch-show--cid-w3m-retrieve)\r
++ w3m-cid-retrieve-function-alist)))\r
++ (setq mm-inline-text-html-with-images t))\r
++\r
++(defvar w3m-current-buffer) ;; From `w3m.el'.\r
++(defun notmuch-show--cid-w3m-retrieve (url &rest args)\r
++ ;; url includes the cid: prefix and is URL encoded (see RFC 2392).\r
++ (let* ((cid (url-unhex-string (substring url 4)))\r
++ (content-and-type\r
++ (with-current-buffer w3m-current-buffer\r
++ (notmuch-show--get-cid-content cid))))\r
++ (when content-and-type\r
++ (insert (first content-and-type))\r
++ (second content-and-type))))\r
++\r
+ ;; MIME part renderers\r
+ \r
+ (defun notmuch-show-multipart/*-to-list (part)\r
+@@ -549,56 +616,11 @@ (defun notmuch-show-insert-part-multipart/alternative (msg part content-type nth\r
+ (indent-rigidly start (point) 1)))\r
+ t)\r
+ \r
+-(defun notmuch-show-setup-w3m ()\r
+- "Instruct w3m how to retrieve content from a \"related\" part of a message."\r
+- (interactive)\r
+- (if (boundp 'w3m-cid-retrieve-function-alist)\r
+- (unless (assq 'notmuch-show-mode w3m-cid-retrieve-function-alist)\r
+- (push (cons 'notmuch-show-mode 'notmuch-show-w3m-cid-retrieve)\r
+- w3m-cid-retrieve-function-alist)))\r
+- (setq mm-inline-text-html-with-images t))\r
+-\r
+-(defvar w3m-current-buffer) ;; From `w3m.el'.\r
+-(defvar notmuch-show-w3m-cid-store nil)\r
+-(make-variable-buffer-local 'notmuch-show-w3m-cid-store)\r
+-\r
+-(defun notmuch-show-w3m-cid-store-internal (content-id msg part)\r
+- (push (list content-id msg part) notmuch-show-w3m-cid-store))\r
+-\r
+-(defun notmuch-show-w3m-cid-store (msg part)\r
+- (let ((content-id (plist-get part :content-id)))\r
+- (when content-id\r
+- (notmuch-show-w3m-cid-store-internal (concat "cid:" content-id)\r
+- msg part))))\r
+-\r
+-(defun notmuch-show-w3m-cid-retrieve (url &rest args)\r
+- (let ((matching-part (with-current-buffer w3m-current-buffer\r
+- (assoc url notmuch-show-w3m-cid-store))))\r
+- (if matching-part\r
+- (let* ((msg (nth 1 matching-part))\r
+- (part (nth 2 matching-part))\r
+- (content-type (plist-get part :content-type)))\r
+- ;; Request content caching, as some messages reference the\r
+- ;; same cid: part many times (hundreds!), which results in\r
+- ;; many calls to `notmuch show'.\r
+- (insert (notmuch-get-bodypart-binary\r
+- msg part notmuch-show-process-crypto 'cache))\r
+- content-type)\r
+- nil)))\r
+-\r
+ (defun notmuch-show-insert-part-multipart/related (msg part content-type nth depth button)\r
+ (let ((inner-parts (plist-get part :content))\r
+ (start (point)))\r
+ \r
+- ;; We assume that the first part is text/html and the remainder\r
+- ;; things that it references.\r
+-\r
+- ;; Stash the non-primary parts.\r
+- (mapc (lambda (part)\r
+- (notmuch-show-w3m-cid-store msg part))\r
+- (cdr inner-parts))\r
+-\r
+- ;; Render the primary part.\r
++ ;; Render the primary part. FIXME: Support RFC 2387 Start header.\r
+ (notmuch-show-insert-bodypart msg (car inner-parts) depth)\r
+ ;; Add hidden buttons for the rest\r
+ (mapc (lambda (inner-part)\r
+@@ -910,6 +932,12 @@ (defun notmuch-show-insert-bodypart (msg part depth &optional hide)\r
+ \r
+ (defun notmuch-show-insert-body (msg body depth)\r
+ "Insert the body BODY at depth DEPTH in the current thread."\r
++\r
++ ;; Register all content IDs for this message. According to RFC\r
++ ;; 2392, content IDs are *global*, but it's okay if an MUA treats\r
++ ;; them as only global within a message.\r
++ (notmuch-show--register-cids msg (first body))\r
++\r
+ (mapc (lambda (part) (notmuch-show-insert-bodypart msg part depth)) body))\r
+ \r
+ (defun notmuch-show-make-symbol (type)\r
+-- \r
+2.1.3\r
+\r