+(defun notmuch-show-archive-thread-maybe-mark-read (markread)
+ (save-excursion
+ (goto-char (point-min))
+ (while (not (eobp))
+ (if markread
+ (notmuch-show-remove-tag "unread" "inbox")
+ (notmuch-show-remove-tag "inbox"))
+ (if (not (eobp))
+ (forward-char))
+ (if (not (re-search-forward notmuch-show-message-begin-regexp nil t))
+ (goto-char (point-max)))))
+ (let ((parent-buffer notmuch-show-parent-buffer))
+ (kill-this-buffer)
+ (if parent-buffer
+ (progn
+ (switch-to-buffer parent-buffer)
+ (forward-line)
+ (notmuch-search-show-thread)))))
+
+(defun notmuch-show-mark-read-then-archive-thread ()
+ "Remove unread tags from thread, then archive and show next thread.
+
+Archive each message currently shown by removing the \"unread\"
+and \"inbox\" tag from each. Then kill this buffer and show the
+next thread from the search from which this thread was originally
+shown.
+
+Note: This command is safe from any race condition of new messages
+being delivered to the same thread. It does not archive the
+entire thread, but only the messages shown in the current
+buffer."
+ (interactive)
+ (notmuch-show-archive-thread-maybe-mark-read t))
+
+(defun notmuch-show-archive-thread ()
+ "Archive each message in thread, then show next thread from search.
+
+Archive each message currently shown by removing the \"inbox\"
+tag from each. Then kill this buffer and show the next thread
+from the search from which this thread was originally shown.
+
+Note: This command is safe from any race condition of new messages
+being delivered to the same thread. It does not archive the
+entire thread, but only the messages shown in the current
+buffer."
+ (interactive)
+ (notmuch-show-archive-thread-maybe-mark-read nil))
+
+(defun notmuch-show-archive-thread-then-exit ()
+ "Archive each message in thread, then exit back to search results."
+ (interactive)
+ (notmuch-show-archive-thread)
+ (kill-this-buffer))
+
+(defun notmuch-show-mark-read-then-archive-then-exit ()
+ "Remove unread tags from thread, then archive and exit to search results."
+ (interactive)
+ (notmuch-show-mark-read-then-archive-thread)
+ (kill-this-buffer))
+
+(defun notmuch-show-view-raw-message ()
+ "View the raw email of the current message."
+ (interactive)
+ (view-file (notmuch-show-get-filename)))
+
+(defmacro with-current-notmuch-show-message (&rest body)
+ "Evaluate body with current buffer set to the text of current message"
+ `(save-excursion
+ (let ((filename (notmuch-show-get-filename)))
+ (let ((buf (generate-new-buffer (concat "*notmuch-msg-" filename "*"))))
+ (with-current-buffer buf
+ (insert-file-contents filename nil nil nil t)
+ ,@body)
+ (kill-buffer buf)))))
+
+(defun notmuch-show-view-all-mime-parts ()
+ "Use external viewers to view all attachments from the current message."
+ (interactive)
+ (with-current-notmuch-show-message
+ (mm-display-parts (mm-dissect-buffer))))
+
+(defun notmuch-foreach-mime-part (function mm-handle)
+ (cond ((stringp (car mm-handle))
+ (dolist (part (cdr mm-handle))
+ (notmuch-foreach-mime-part function part)))
+ ((bufferp (car mm-handle))
+ (funcall function mm-handle))
+ (t (dolist (part mm-handle)
+ (notmuch-foreach-mime-part function part)))))
+
+(defun notmuch-count-attachments (mm-handle)
+ (let ((count 0))
+ (notmuch-foreach-mime-part
+ (lambda (p)
+ (let ((disposition (mm-handle-disposition p)))
+ (and (listp disposition)
+ (equal (car disposition) "attachment")
+ (incf count))))
+ mm-handle)
+ count))
+
+(defun notmuch-save-attachments (mm-handle &optional queryp)
+ (notmuch-foreach-mime-part
+ (lambda (p)
+ (let ((disposition (mm-handle-disposition p)))
+ (and (listp disposition)
+ (equal (car disposition) "attachment")
+ (or (not queryp)
+ (y-or-n-p
+ (concat "Save '" (cdr (assq 'filename disposition)) "' ")))
+ (mm-save-part p))))
+ mm-handle))
+
+(defun notmuch-show-save-attachments ()
+ "Save all attachments from the current message."
+ (interactive)
+ (with-current-notmuch-show-message
+ (let ((mm-handle (mm-dissect-buffer)))
+ (notmuch-save-attachments
+ mm-handle (> (notmuch-count-attachments mm-handle) 1))))
+ (message "Done"))
+
+(defun notmuch-reply (query-string)
+ (switch-to-buffer (generate-new-buffer "notmuch-draft"))
+ (call-process notmuch-command nil t nil "reply" query-string)
+ (message-insert-signature)
+ (goto-char (point-min))
+ (if (re-search-forward "^$" nil t)
+ (progn
+ (insert "--text follows this line--")
+ (forward-line)))
+ (message-mode))
+
+(defun notmuch-show-reply ()
+ "Begin composing a reply to the current message in a new buffer."
+ (interactive)
+ (let ((message-id (notmuch-show-get-message-id)))
+ (notmuch-reply message-id)))
+
+(defun notmuch-show-forward-current ()
+ "Forward the current message."
+ (interactive)
+ (with-current-notmuch-show-message
+ (message-forward)))
+
+(defun notmuch-show-pipe-message (command)
+ "Pipe the contents of the current message to the given command.
+
+The given command will be executed with the raw contents of the
+current email message as stdin. Anything printed by the command
+to stdout or stderr will appear in the *Messages* buffer."
+ (interactive "sPipe message to command: ")
+ (apply 'start-process-shell-command "notmuch-pipe-command" "*notmuch-pipe*"
+ (list command " < " (shell-quote-argument (notmuch-show-get-filename)))))
+
+(defun notmuch-show-move-to-current-message-summary-line ()
+ "Move to the beginning of the one-line summary of the current message.
+
+This gives us a stable place to move to and work from since the
+summary line is always visible. This is important since moving to
+an invisible location is unreliable, (the main command loop moves
+point either forward or backward to the next visible character
+when a command ends with point on an invisible character).
+
+Emits an error if point is not within a valid message, (that is
+no pattern of `notmuch-show-message-begin-regexp' could be found
+by searching backward)."