--- /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 1F1EE431FBC\r
+ for <notmuch@notmuchmail.org>; Mon, 21 Apr 2014 11:38:18 -0700 (PDT)\r
+X-Virus-Scanned: Debian amavisd-new at olra.theworths.org\r
+X-Spam-Flag: NO\r
+X-Spam-Score: -0.7\r
+X-Spam-Level: \r
+X-Spam-Status: No, score=-0.7 tagged_above=-999 required=5\r
+ tests=[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 26ae3WpmMoN7 for <notmuch@notmuchmail.org>;\r
+ Mon, 21 Apr 2014 11:38:14 -0700 (PDT)\r
+Received: from dmz-mailsec-scanner-3.mit.edu (dmz-mailsec-scanner-3.mit.edu\r
+ [18.9.25.14])\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 33118431FC7\r
+ for <notmuch@notmuchmail.org>; Mon, 21 Apr 2014 11:38:02 -0700 (PDT)\r
+X-AuditID: 1209190e-f79ee6d000000c40-9d-53556589d3f0\r
+Received: from mailhub-auth-3.mit.edu ( [18.9.21.43])\r
+ (using TLS with cipher AES256-SHA (256/256 bits))\r
+ (Client did not present a certificate)\r
+ by dmz-mailsec-scanner-3.mit.edu (Symantec Messaging Gateway) with SMTP\r
+ id 22.75.03136.98565535; Mon, 21 Apr 2014 14:38:01 -0400 (EDT)\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 s3LIc1vd018354; \r
+ Mon, 21 Apr 2014 14:38:01 -0400\r
+Received: from drake.dyndns.org\r
+ (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 s3LIbs8B029726\r
+ (version=TLSv1/SSLv3 cipher=AES256-SHA bits=256 verify=NOT);\r
+ Mon, 21 Apr 2014 14:38:00 -0400\r
+Received: from amthrax by drake.dyndns.org with local (Exim 4.77)\r
+ (envelope-from <amdragon@mit.edu>)\r
+ id 1WcJ6I-0003lI-HQ; Mon, 21 Apr 2014 14:37:54 -0400\r
+From: Austin Clements <amdragon@MIT.EDU>\r
+To: notmuch@notmuchmail.org\r
+Subject: [PATCH 10/11] emacs: Rewrite content ID handling\r
+Date: Mon, 21 Apr 2014 14:37:47 -0400\r
+Message-Id: <1398105468-14317-11-git-send-email-amdragon@mit.edu>\r
+X-Mailer: git-send-email 1.9.1\r
+In-Reply-To: <1398105468-14317-1-git-send-email-amdragon@mit.edu>\r
+References: <1398105468-14317-1-git-send-email-amdragon@mit.edu>\r
+X-Brightmail-Tracker:\r
+ H4sIAAAAAAAAA+NgFtrAIsWRmVeSWpSXmKPExsUixCmqrduZGhpssPmKucX1mzOZHRg9nq26\r
+ xRzAGMVlk5Kak1mWWqRvl8CVsXH6UfaCJ5YV09exNDA+0uti5OSQEDCRmLm8mQXCFpO4cG89\r
+ WxcjF4eQwGwmiYaj05ggnI2MEkcWzmGGcO4wSVy59ROsRUhgLqPEn4nOIDabgIbEtv3LGUFs\r
+ EQFpiZ13Z7N2MXJwMAuoSfzpUgEJCwtYSmxsmcUMEmYRUJVo7NAFCfMKOEos757GDnGEnMTJ\r
+ Y5NZQWxOoHjb6pfsEJscJDbsXcM0gZF/ASPDKkbZlNwq3dzEzJzi1GTd4uTEvLzUIl1jvdzM\r
+ Er3UlNJNjOCAkeTbwfj1oNIhRgEORiUe3gKj0GAh1sSy4srcQ4ySHExKoryvooBCfEn5KZUZ\r
+ icUZ8UWlOanFhxglOJiVRHjXawLleFMSK6tSi/JhUtIcLErivG+trYKFBNITS1KzU1MLUotg\r
+ sjIcHEoSvDdTgBoFi1LTUyvSMnNKENJMHJwgw3mAhl8EqeEtLkjMLc5Mh8ifYlSUEudtA0kI\r
+ gCQySvPgemER/YpRHOgVYd4WkCoeYDKA634FNJgJaPCTLSEgg0sSEVJSDYzuZqW/PxdWPLzy\r
+ arJeqsxH6WW1Szr/rufY6HvztHShkC939ym2LyIB54U0vRIqNu2KS3ZYqdCsJOkefvusYzNL\r
+ YrrjKrUDszzyancweXGu/Zuut3mT3dHPX1YZT6tUWaVhqr/jf6DpyRzOAmPbBx93ndVImXlY\r
+ dsL5cJtLrgKbJDVcxKJby5RYijMSDbWYi4oTASkhZonDAgAA\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: Mon, 21 Apr 2014 18:38:18 -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 9411c9a..f758091 100644\r
+--- a/emacs/notmuch-show.el\r
++++ b/emacs/notmuch-show.el\r
+@@ -503,6 +503,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
+@@ -527,56 +594,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
+@@ -888,6 +910,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
+1.9.1\r
+\r