:group 'notmuch)
(defcustom notmuch-draft-tags '("+draft")
- "List of tags changes to apply to a draft message when it is saved in the database.
+ "List of tag changes to apply when saving a draft message in the database.
Tags starting with \"+\" (or not starting with either \"+\" or
\"-\") in the list will be added, and tags starting with \"-\"
Possible values are `oldest-first', `newest-first'
or nil. Nil means use the default sort order.
:search-type Specify whether to run the search in search-mode,
- tree mode or unthreaded mode. Set to 'tree to specify tree
- mode, 'unthreaded to specify unthreaded mode, and set to nil
- (or anything except tree and unthreaded) to specify search mode.
+ tree mode or unthreaded mode. Set to `tree' to
+ specify tree mode, 'unthreaded to specify
+ unthreaded mode, and set to nil (or anything
+ except tree and unthreaded) to specify search
+ mode.
Other accepted forms are a cons cell of the form (NAME . QUERY)
or a list of the form (NAME QUERY COUNT-QUERY)."
(start (point)))
(if is-hidden
(widget-create 'push-button
- :notify `(lambda (widget &rest _ignore)
- (setq notmuch-hello-hidden-sections
- (delete ,title notmuch-hello-hidden-sections))
- (notmuch-hello-update))
+ :notify (lambda (&rest _ignore)
+ (setq notmuch-hello-hidden-sections
+ (delete title notmuch-hello-hidden-sections))
+ (notmuch-hello-update))
"show")
(widget-create 'push-button
- :notify `(lambda (widget &rest _ignore)
- (add-to-list 'notmuch-hello-hidden-sections
- ,title)
- (notmuch-hello-update))
+ :notify (lambda (&rest _ignore)
+ (add-to-list 'notmuch-hello-hidden-sections
+ title)
+ (notmuch-hello-update))
"hide"))
(widget-insert "\n")
(unless is-hidden
(require 'notmuch-lib)
(require 'notmuch-hello)
+(declare-function notmuch-search "notmuch")
+(declare-function notmuch-tree "notmuch-tree")
+(declare-function notmuch-unthreaded "notmuch-tree")
+
;;;###autoload
(defun notmuch-jump-search ()
"Jump to a saved search by shortcut key.
(push (list key name
(cond
((eq (plist-get saved-search :search-type) 'tree)
- `(lambda () (notmuch-tree ',query)))
+ (lambda () (notmuch-tree query)))
((eq (plist-get saved-search :search-type) 'unthreaded)
- `(lambda () (notmuch-unthreaded ',query)))
+ (lambda () (notmuch-unthreaded query)))
(t
- `(lambda () (notmuch-search ',query ',oldest-first)))))
+ (lambda () (notmuch-search query oldest-first)))))
action-map)))))
(setq action-map (nreverse action-map))
(if action-map
(pcase-dolist (`(,key ,_name ,fn) action-map)
(when (= (length key) 1)
(define-key map key
- `(lambda () (interactive)
- (setq notmuch-jump--action ',fn)
- (exit-minibuffer)))))
+ (lambda ()
+ (interactive)
+ (setq notmuch-jump--action fn)
+ (exit-minibuffer)))))
;; By doing this in two passes (and checking if we already have a
;; binding) we avoid problems if the user specifies a binding which
;; is a prefix of another binding.
action-submap)
(setq action-submap (nreverse action-submap))
(define-key map keystr
- `(lambda () (interactive)
- (setq notmuch-jump--action
- ',(apply-partially #'notmuch-jump
- action-submap
- new-prompt))
- (exit-minibuffer)))))))
+ (lambda ()
+ (interactive)
+ (setq notmuch-jump--action
+ (apply-partially #'notmuch-jump
+ action-submap
+ new-prompt))
+ (exit-minibuffer)))))))
map))
(provide 'notmuch-jump)
t)
(defun notmuch-show-insert-part-message/rfc822 (msg part _content-type _nth depth _button)
- (let* ((message (car (plist-get part :content)))
- (body (car (plist-get message :body)))
- (start (point)))
- ;; Override `notmuch-message-headers' to force `From' to be
- ;; displayed.
- (let ((notmuch-message-headers '("From" "Subject" "To" "Cc" "Date")))
- (notmuch-show-insert-headers (plist-get message :headers)))
- ;; Blank line after headers to be compatible with the normal
- ;; message display.
- (insert "\n")
- ;; Show the body
- (notmuch-show-insert-bodypart msg body depth)
- (when notmuch-show-indent-multipart
- (indent-rigidly start (point) 1)))
- t)
+ (let ((message (car (plist-get part :content))))
+ (and
+ message
+ (let ((body (car (plist-get message :body)))
+ (start (point)))
+ ;; Override `notmuch-message-headers' to force `From' to be
+ ;; displayed.
+ (let ((notmuch-message-headers '("From" "Subject" "To" "Cc" "Date")))
+ (notmuch-show-insert-headers (plist-get message :headers)))
+ ;; Blank line after headers to be compatible with the normal
+ ;; message display.
+ (insert "\n")
+ ;; Show the body
+ (notmuch-show-insert-bodypart msg body depth)
+ (when notmuch-show-indent-multipart
+ (indent-rigidly start (point) 1))
+ t))))
(defun notmuch-show-insert-part-text/plain (msg part _content-type _nth depth button)
;; For backward compatibility we want to apply the text/plain hook
(let ((cwd default-directory)
(buf (get-buffer-create (concat "*notmuch-pipe*"))))
(with-current-buffer buf
- (setq buffer-read-only nil)
- (erase-buffer)
- ;; Use the originating buffer's working directory instead of
- ;; that of the pipe buffer.
- (cd cwd)
- (let ((exit-code (call-process-shell-command shell-command nil buf)))
- (goto-char (point-max))
- (set-buffer-modified-p nil)
- (setq buffer-read-only t)
- (unless (zerop exit-code)
- (pop-to-buffer buf)
- (message (format "Command '%s' exited abnormally with code %d"
- shell-command exit-code))))))))
+ (setq buffer-read-only t)
+ (let ((inhibit-read-only t))
+ (erase-buffer)
+ ;; Use the originating buffer's working directory instead of
+ ;; that of the pipe buffer.
+ (cd cwd)
+ (let ((exit-code (call-process-shell-command shell-command nil buf)))
+ (goto-char (point-max))
+ (set-buffer-modified-p nil)
+ (unless (zerop exit-code)
+ (pop-to-buffer buf)
+ (message (format "Command '%s' exited abnormally with code %d"
+ shell-command exit-code)))))))))
(defun notmuch-show-tag-message (&rest tag-changes)
"Change tags for the current message.
name)
(mapconcat #'identity tag-change " "))))
(push (list key name-string
- `(lambda () (,tag-function ',tag-change)))
+ (lambda () (funcall tag-function tag-change)))
action-map)))
(push (list notmuch-tag-jump-reverse-key
(if reverse
(defcustom notmuch-tree-result-format
`(("date" . "%12s ")
("authors" . "%-20s")
- ((("tree" . "%s")("subject" . "%s")) ." %-54s ")
+ ((("tree" . "%s")
+ ("subject" . "%s"))
+ . " %-54s ")
("tags" . "(%s)"))
- "Result formatting for tree view. Supported fields are: date,
-authors, subject, tree, tags. Tree means the thread tree
-box graphics. The field may also be a list in which case
-the formatting rules are applied recursively and then the
-output of all the fields in the list is inserted
-according to format-string.
-
-Note the author string should not contain
-whitespace (put it in the neighbouring fields instead).
-For example:
- (setq notmuch-tree-result-format \(\(\"authors\" . \"%-40s\"\)
- \(\"subject\" . \"%s\"\)\)\)"
- :type '(alist :key-type (string) :value-type (string))
+ "Result formatting for tree view.
+
+Supported fields are: date, authors, subject, tree, tags.
+
+Tree means the thread tree box graphics. The field may
+also be a list in which case the formatting rules are
+applied recursively and then the output of all the fields
+in the list is inserted according to format-string.
+
+Note that the author string should not contain whitespace
+\(put it in the neighbouring fields instead). For example:
+ (setq notmuch-tree-result-format
+ '((\"authors\" . \"%-40s\")
+ (\"subject\" . \"%s\")))"
+ :type '(alist :key-type (choice string
+ (alist :key-type string
+ :value-type string))
+ :value-type string)
:group 'notmuch-tree)
(defcustom notmuch-unthreaded-result-format
("authors" . "%-20s")
((("subject" . "%s")) ." %-54s ")
("tags" . "(%s)"))
- "Result formatting for unthreaded tree view. Supported fields are: date,
-authors, subject, tree, tags. Tree means the thread tree
-box graphics. The field may also be a list in which case
-the formatting rules are applied recursively and then the
-output of all the fields in the list is inserted
-according to format-string.
-
-Note the author string should not contain
-whitespace (put it in the neighbouring fields instead).
-For example:
- (setq notmuch-tree-result-format \(\(\"authors\" . \"%-40s\"\)
- \(\"subject\" . \"%s\"\)\)\)"
- :type '(alist :key-type (string) :value-type (string))
+ "Result formatting for unthreaded tree view.
+
+Supported fields are: date, authors, subject, tree, tags.
+
+Tree means the thread tree box graphics. The field may
+also be a list in which case the formatting rules are
+applied recursively and then the output of all the fields
+in the list is inserted according to format-string.
+
+Note that the author string should not contain whitespace
+\(put it in the neighbouring fields instead). For example:
+ (setq notmuch-unthreaded-result-format
+ '((\"authors\" . \"%-40s\")
+ (\"subject\" . \"%s\")))"
+ :type '(alist :key-type (choice string
+ (alist :key-type string
+ :value-type string))
+ :value-type string)
:group 'notmuch-tree)
(defun notmuch-tree-result-format ()
("authors" . "%-20s ")
("subject" . "%s ")
("tags" . "(%s)"))
- "Search result formatting. Supported fields are:
- date, count, authors, subject, tags
+ "Search result formatting.
+
+Supported fields are: date, count, authors, subject, tags.
For example:
- (setq notmuch-search-result-format \(\(\"authors\" . \"%-40s\"\)
- \(\"subject\" . \"%s\"\)\)\)
+ (setq notmuch-search-result-format
+ '((\"authors\" . \"%-40s\")
+ (\"subject\" . \"%s\")))
+
Line breaks are permitted in format strings (though this is
currently experimental). Note that a line break at the end of an
\"authors\" field will get elided if the authors list is long;
place it instead at the beginning of the following field. To
enter a line break when setting this variable with setq, use \\n.
To enter a line break in customize, press \\[quoted-insert] C-j."
- :type '(alist :key-type (string) :value-type (string))
+ :type '(alist :key-type string :value-type string)
:group 'notmuch-search)
;; The name of this variable `notmuch-init-file' is consistent with the
if (value)
return value;
- if (strcasecmp (header, "received") == 0) {
+ if (strcasecmp (header, "received") == 0 ||
+ strcasecmp (header, "delivered-to") == 0) {
/*
- * The Received: header is special. We concatenate all
- * instances of the header as we use this when analyzing the
- * path the mail has taken from sender to recipient.
+ * The Received: header is special. We concatenate all instances of the
+ * header as we use this when analyzing the path the mail has taken
+ * from sender to recipient.
+ *
+ * Similarly, multiple instances of Delivered-To may be present. We
+ * concatenate them so the one with highest priority may be picked (eg.
+ * primary_email before other_email).
*/
decoded = _notmuch_message_file_get_combined_header (message, header);
} else {
* (last Received: header added) and try to extract from them
* indications to which email address this message was delivered.
*
- * The Received: header is special in our get_header function and is
- * always concatenated.
+ * The Received: header is among special ones in our get_header function
+ * and is always concatenated.
*
* Return the address that was found, if any, and NULL otherwise.
*/
* headers: Envelope-To, X-Original-To, and Delivered-To (searched in
* that order).
*
+ * The Delivered-To: header is among special ones in our get_header
+ * function and is always concatenated.
+ *
* Return the address that was found, if any, and NULL otherwise.
*/
static const char *
> From guessing
OK"
+test_begin_subtest "From guessing: multiple Delivered-To"
+add_message '[from]="Sender <sender@example.com>"' \
+ '[to]="Recipient <recipient@example.com>"' \
+ '[subject]="From guessing"' \
+ '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
+ '[body]="From guessing"' \
+ '[header]="Delivered-To: test_suite_other@notmuchmail.org
+Delivered-To: test_suite@notmuchmail.org"'
+
+output=$(notmuch reply id:${gen_msg_id} 2>&1 && echo OK)
+test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
+Subject: Re: From guessing
+To: Sender <sender@example.com>, Recipient <recipient@example.com>
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
+> From guessing
+OK"
+
test_begin_subtest "Reply with RFC 2047-encoded headers"
add_message '[subject]="=?iso-8859-1?q?=e0=df=e7?="' \
'[from]="=?utf-8?q?=e2=98=83?= <snowman@example.com>"' \
"crypto": {},
"date_relative": "2010-01-05",
"excluded": false,
- "filename": ["'${MAIL_DIR}'/msg-014"],
+ "filename": ["'${MAIL_DIR}'/msg-015"],
"headers": {
"Date": "Tue, 05 Jan 2010 15:43:56 +0000",
"From": "\u2603 <snowman@example.com>",
expected='#= simple-encrypted@crypto.notmuchmail.org index.decryption=failure
#notmuch-dump batch-tag:3 config,properties,tags
+encrypted +inbox +unread -- id:basic-encrypted@crypto.notmuchmail.org
++encrypted +inbox +unread -- id:encrypted-rfc822-attachment@crypto.notmuchmail.org
+encrypted +inbox +unread -- id:encrypted-signed@crypto.notmuchmail.org
+encrypted +inbox +unread -- id:simple-encrypted@crypto.notmuchmail.org'
test_expect_equal \
(test-visible-output)'
test_expect_equal_file $EXPECTED/notmuch-show-decrypted-message OUTPUT
+test_begin_subtest "show encrypted rfc822 message"
+test_subtest_known_broken
+test_emacs '(notmuch-show "id:encrypted-rfc822-attachment@crypto.notmuchmail.org")
+ (test-visible-output)'
+test_expect_code 1 'fgrep "!!!" OUTPUT'
+
test_begin_subtest "show undecryptable message"
test_emacs '(notmuch-show "id:simple-encrypted@crypto.notmuchmail.org")
(test-visible-output)'
--- /dev/null
+Content-Type: multipart/encrypted; protocol="application/pgp-encrypted"; boundary="===============9060418334135509864=="
+MIME-Version: 1.0
+From: Notmuch test suite <test_suite@notmuchmail.org>
+To: test_suite@notmuchmail.org
+Subject: testing encrypted rfc822 attachments
+Date: Sat, 03 Jul 2021 16:00:02 -0300
+Message-ID: <encrypted-rfc822-attachment@crypto.notmuchmail.org>
+User-Agent: alot/0.9.1
+
+--===============9060418334135509864==
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Content-Type: application/pgp-encrypted; charset="us-ascii"
+
+Version: 1
+--===============9060418334135509864==
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Content-Type: application/octet-stream; charset="us-ascii"
+
+-----BEGIN PGP MESSAGE-----
+
+hIwDxE023q1UqxYBBACGKSDv5/rcwScSf9n33cZZPPxltQgxkDaClMGY2DARgebE
+9rpE2O/4eoaEbdu+2shahPLIbD0wuRiGVpMIIloNNucl3f15h1wXPZbTwK7sNxJq
+HycSf8sT1fkolmC9s9X0r5xHgk0G4klAqr5C3GOk7Y6wsHTYGqzDvBFEB0LvaoUC
+DANw48DehwaEUQEP/iaiYeMDUsOzFZodKZOlQWese2JPTsRwF7KrTl8C93MrZqAh
+A1pQjUH9cafj8mwDXA9ZCsYZs7r84IxShI+dUhinBSCq8F61OlLP859wq+wpKU7n
+PNVA5bfd//4hRFvDT33ZlgeeeCcRo7h4IDjJwFDYsf0Ysqvo+IKipVNXXlAcGYYI
+DVBucB0fYaVHWRKxw50mo02zKP2/GW6K3p1nxGTf73cKjc9of+VOvvMByODaJ+ne
+WIuzZMqz0vfQ0UvRVBjlsXtB7VpCqJZWkubqqwwP6+2WOCA/c5LC3z2f/BK90EQh
+/JrKfDR083UNhu4SjNwL/TF4ET33JHf1u5Gmzqx+eO00pfhVvkyz6LYImkE8ky/+
+bXyJY8iDq7dxtfqhzZbeNe4fafU/avXxTA5UkWTnYhCqyd2bvAYH3Ep3L7lSv6SQ
+Tsy0jjTsWJoSq6jRIzJuo2mX2MBKPBfLZs4tH71/4RppECletNnS4ZlxiV4LNrWE
+LrXQvE1V+mJ82muucIe7w52nf3UWjQqTA73+Ml0aK+lIhbckRIovAw1sGzRrbTEX
+xLCgz7BYDMhs5mgtfiMAzGox4xGxi56Ge519vdbddan4G92mPlLl1IPOXkO8GyLO
+D4IiPp5ilPy6uThuxxIFemxxUREbPrfLJNA8W7aRPrHz4YcgZhrAV9I4C+xE0ukB
+i8MoJeFvbCGPyTwVDn8XfFKynlZYm1f8NIVMSj5JfV8J3Om9jzDp6hx+52iUQEbW
+C9g4kfPZY8h0RMggdOlZsaR8j26xuW+fEtz7ucJIqfJ/ElTH+4bm8MK2qPZniRWv
+ej2md4bP4Bo5DXydzxz7O7TBL6/Jsp7pJhHUUb36OnTWvInyg71LPT1QIxdRvXr9
+vNhrEBDX3MNf7RyXczvBcc+cLRo+zV+T4b8wd2kwXskWgKrGUJEe2TItdsafaQ9B
+BkuVGu6cIDa6STyCJiOB68KIXiDuADSWJiiR+gZr4eU6vzfhR27LMQt/g+oPW+U4
+1AvzUl9uXjTMC2vFuTQ4M2g0WmksCNpPpzOu/QlBmRqpP2Fg9UuLv6ITWeCxp439
+g5NT5KXE2IiruL/DS0KEpWVNe4ayGzRvMawFuU582xbIzXjvilUZrW+p6req+oeF
+QWTWHGDojTvULQPV2c91lWnLaNXVethfF4hrM5MIL+EwVs3sUXFMr1kX7VNrK0QH
+Uos7nc4G9xngpdvwF4ImldD83O8qxOVzIfk5Dhz+etTH4HbnnDvmQ/FIYvjzGviR
+ZeVwdCjv/9TC4yY3nJFKMwGp70jVa1vbmWL68HVNRyAVwnQnu2UlI8UR43iVZyUH
+ZY0Nr0rbse/pvZyX4//EVOFLUR7K4GG0N4Kz41q5ZB8rI4Fl6QJhgIFJds13iM77
+n+wqLQE7kllgI32E4U9B
+=YlXg
+-----END PGP MESSAGE-----
+
+--===============9060418334135509864==--