- ;; This make assumptions about the output of `notmuch reply', but
- ;; really only that the headers come first followed by a blank
- ;; line and then the body.
- (with-temp-buffer
- (apply 'call-process (append (list notmuch-command nil (list t t) nil) args))
- (goto-char (point-min))
- (if (re-search-forward "^$" nil t)
- (save-excursion
- (save-restriction
- (narrow-to-region (point-min) (point))
- (goto-char (point-min))
- (setq headers (mail-header-extract)))))
- (forward-line 1)
- (setq body (buffer-substring (point) (point-max))))
- ;; If sender is non-nil, set the From: header to its value.
- (when sender
- (mail-header-set 'from sender headers))
- (let
- ;; Overlay the composition window on that being used to read
- ;; the original message.
- ((same-window-regexps '("\\*mail .*")))
- (notmuch-mua-mail (mail-header 'to headers)
- (mail-header 'subject headers)
- (message-headers-to-generate headers t '(to subject))))
- ;; insert the message body - but put it in front of the signature
- ;; if one is present
- (goto-char (point-max))
- (if (re-search-backward message-signature-separator nil t)
- (forward-line -1)
- (goto-char (point-max)))
- (insert body)
- (push-mark))
- (set-buffer-modified-p nil)
-
- (message-goto-body))
-
-(defun notmuch-mua-forward-message ()
- (message-forward)
-
- (when notmuch-mua-user-agent-function
- (let ((user-agent (funcall notmuch-mua-user-agent-function)))
- (when (not (string= "" user-agent))
- (message-add-header (format "User-Agent: %s" user-agent)))))
- (message-sort-headers)
- (message-hide-headers)
- (set-buffer-modified-p nil)
-
- (message-goto-to))
-
-(defun notmuch-mua-mail (&optional to subject other-headers &rest other-args)
- "Invoke the notmuch mail composition window.
-
-OTHER-ARGS are passed through to `message-mail'."
+ ;; Get the reply object as SEXP, and parse it into an elisp object.
+ (setq reply (apply #'notmuch-call-notmuch-sexp args))
+ ;; Extract the original message to simplify the following code.
+ (setq original (plist-get reply :original))
+ ;; Extract the headers of both the reply and the original message.
+ (let* ((original-headers (plist-get original :headers))
+ (reply-headers (plist-get reply :reply-headers)))
+ ;; If sender is non-nil, set the From: header to its value.
+ (when sender
+ (plist-put reply-headers :From sender))
+ (let
+ ;; Overlay the composition window on that being used to read
+ ;; the original message.
+ ((same-window-regexps '("\\*mail .*")))
+ ;; We modify message-header-format-alist to get around
+ ;; a bug in message.el. See the comment above on
+ ;; notmuch-mua-insert-references.
+ (let ((message-header-format-alist
+ (cl-loop for pair in message-header-format-alist
+ if (eq (car pair) 'References)
+ collect (cons 'References
+ (apply-partially
+ 'notmuch-mua-insert-references
+ (cdr pair)))
+ else
+ collect pair)))
+ (notmuch-mua-mail (plist-get reply-headers :To)
+ (notmuch-sanitize (plist-get reply-headers :Subject))
+ (notmuch-headers-plist-to-alist reply-headers)
+ nil (notmuch-mua-get-switch-function))))
+ ;; Create a buffer-local queue for tag changes triggered when
+ ;; sending the reply.
+ (when notmuch-message-replied-tags
+ (setq-local notmuch-message-queued-tag-changes
+ (list (cons query-string notmuch-message-replied-tags))))
+ ;; Insert the message body - but put it in front of the signature
+ ;; if one is present, and after any other content
+ ;; message*setup-hooks may have added to the message body already.
+ (save-restriction
+ (message-goto-body)
+ (narrow-to-region (point) (point-max))
+ (goto-char (point-max))
+ (if (re-search-backward message-signature-separator nil t)
+ (when message-signature-insert-empty-line
+ (forward-line -1))
+ (goto-char (point-max))))
+ (let ((from (plist-get original-headers :From))
+ (date (plist-get original-headers :Date))
+ (start (point)))
+ ;; notmuch-mua-cite-function constructs a citation line based
+ ;; on the From and Date headers of the original message, which
+ ;; are assumed to be in the buffer.
+ (insert "From: " from "\n")
+ (insert "Date: " date "\n\n")
+ (insert
+ (with-temp-buffer
+ (let
+ ;; Don't attempt to clean up messages, excerpt
+ ;; citations, etc. in the original message before
+ ;; quoting.
+ ((notmuch-show-insert-text/plain-hook nil)
+ ;; Don't omit long parts.
+ (notmuch-show-max-text-part-size 0)
+ ;; Insert headers for parts as appropriate for replying.
+ (notmuch-show-insert-header-p-function
+ notmuch-mua-reply-insert-header-p-function)
+ ;; Ensure that any encrypted parts are
+ ;; decrypted during the generation of the reply
+ ;; text.
+ (notmuch-show-process-crypto process-crypto)
+ ;; Don't indent multipart sub-parts.
+ (notmuch-show-indent-multipart nil))
+ ;; We don't want sigstatus buttons (an information leak and usually wrong anyway).
+ (cl-letf (((symbol-function 'notmuch-crypto-insert-sigstatus-button) #'ignore)
+ ((symbol-function 'notmuch-crypto-insert-encstatus-button) #'ignore))
+ (notmuch-show-insert-body original (plist-get original :body) 0)
+ (buffer-substring-no-properties (point-min) (point-max))))))
+ (set-mark (point))
+ (goto-char start)
+ ;; Quote the original message according to the user's configured style.
+ (funcall notmuch-mua-cite-function)))
+ ;; Crypto processing based crypto content of the original message
+ (when process-crypto
+ (notmuch-mua-reply-crypto (plist-get original :body))))
+ ;; Push mark right before signature, if any.
+ (message-goto-signature)
+ (unless (eobp)
+ (end-of-line -1))
+ (push-mark)
+ (message-goto-body)
+ (set-buffer-modified-p nil))
+
+(defvar notmuch-message-mode-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map (kbd "C-c C-c") #'notmuch-mua-send-and-exit)
+ (define-key map (kbd "C-c C-s") #'notmuch-mua-send)
+ (define-key map (kbd "C-c C-p") #'notmuch-draft-postpone)
+ (define-key map (kbd "C-x C-s") #'notmuch-draft-save)
+ map)
+ "Keymap for `notmuch-message-mode'.")
+
+(define-derived-mode notmuch-message-mode message-mode "Message[Notmuch]"
+ "Notmuch message composition mode. Mostly like `message-mode'."
+ (notmuch-address-setup))
+
+(put 'notmuch-message-mode 'flyspell-mode-predicate 'mail-mode-flyspell-verify)
+
+(defun notmuch-mua-pop-to-buffer (name switch-function)
+ "Pop to buffer NAME, and warn if it already exists and is modified.
+Like `message-pop-to-buffer' but enable `notmuch-message-mode'
+instead of `message-mode' and SWITCH-FUNCTION is mandatory."
+ (let ((buffer (get-buffer name)))
+ (if (and buffer
+ (buffer-name buffer))
+ (let ((window (get-buffer-window buffer 0)))
+ (if window
+ ;; Raise the frame already displaying the message buffer.
+ (progn
+ (select-frame-set-input-focus (window-frame window))
+ (select-window window))
+ (funcall switch-function buffer)
+ (set-buffer buffer))
+ (when (and (buffer-modified-p)
+ (not (prog1
+ (y-or-n-p
+ "Message already being composed; erase? ")
+ (message nil))))
+ (error "Message being composed")))
+ (funcall switch-function name)
+ (set-buffer name))
+ (erase-buffer)
+ (notmuch-message-mode)))
+
+(defun notmuch-mua-mail (&optional to subject other-headers continue
+ switch-function yank-action send-actions
+ return-action &rest ignored)
+ "Invoke the notmuch mail composition window."