]> git.notmuchmail.org Git - notmuch/blob - devel/schemata
cli/show: emit new whole-message crypto status output
[notmuch] / devel / schemata
1 This file describes the schemata used for notmuch's structured output
2 format (currently JSON and S-Expressions).
3
4 []'s indicate lists.  List items can be marked with a '?', meaning
5 they are optional; or a '*', meaning there can be zero or more of that
6 item.  {}'s indicate an object that maps from field identifiers to
7 values.  An object field marked '?' is optional.  |'s indicate
8 alternates (e.g., int|string means something can be an int or a
9 string).
10
11 For S-Expression output, lists are printed delimited by () instead of
12 []. Objects are printed as p-lists, i.e. lists where the keys and values
13 are interleaved. Keys are printed as keywords (symbols preceded by a
14 colon), e.g. (:id "123" :time 54321 :from "foobar"). Null is printed as
15 nil, true as t and false as nil.
16
17 This is version 4 of the structured output format.
18
19 Version history
20 ---------------
21
22 v1
23 - First versioned schema release.
24 - Added part.content-length and part.content-transfer-encoding fields.
25
26 v2
27 - Added the thread_summary.query field.
28
29 v3
30 - Replaced message.filename string with a list of filenames.
31 - Added part.content-disposition field.
32
33 v4
34 - replace signature error integer bitmask with a set of flags for
35   individual errors.
36 - (notmuch 0.29) added message.crypto to identify overall message
37   cryptographic state
38
39 Common non-terminals
40 --------------------
41
42 # Number of seconds since the Epoch
43 unix_time = int
44
45 # Thread ID, sans "thread:"
46 threadid = string
47
48 # Message ID, sans "id:"
49 messageid = string
50
51 notmuch show schema
52 -------------------
53
54 # A top-level set of threads (do_show)
55 # Returned by notmuch show without a --part argument
56 thread_set = [thread*]
57
58 # Top-level messages in a thread (show_messages)
59 thread = [thread_node*]
60
61 # A message and its replies (show_messages)
62 thread_node = [
63     message|null,             # null if not matched and not --entire-thread
64     [thread_node*]            # children of message
65 ]
66
67 # A message (format_part_sprinter)
68 message = {
69     # (format_message_sprinter)
70     id:             messageid,
71     match:          bool,
72     filename:       [string*],
73     timestamp:      unix_time, # date header as unix time
74     date_relative:  string,   # user-friendly timestamp
75     tags:           [string*],
76
77     headers:        headers,
78     crypto:         crypto,
79     body?:          [part]    # omitted if --body=false
80 }
81
82 # when showing the message, was any or all of it decrypted?
83 msgdecstatus: "full"|"partial"
84
85 # The overall cryptographic state of the message as a whole:
86 crypto = {
87     signed?:    {
88                   status:      sigstatus,
89                   # was the set of signatures described under encrypted cover?
90                   encrypted:   bool,
91                 },
92     decrypted?: {
93                   status: msgdecstatus,
94                 }
95 }
96
97 # A MIME part (format_part_sprinter)
98 part = {
99     id:             int|string, # part id (currently DFS part number)
100
101     encstatus?:     encstatus,
102     sigstatus?:     sigstatus,
103
104     content-type:   string,
105     content-disposition?:       string,
106     content-id?:    string,
107     # if content-type starts with "multipart/":
108     content:        [part*],
109     # if content-type is "message/rfc822":
110     content:        [{headers: headers, body: [part]}],
111     # otherwise (leaf parts):
112     filename?:      string,
113     content-charset?: string,
114     # A leaf part's body content is optional, but may be included if
115     # it can be correctly encoded as a string.  Consumers should use
116     # this in preference to fetching the part content separately.
117     content?:       string,
118     # If a leaf part's body content is not included, the length of
119     # the encoded content (in bytes) may be given instead.
120     content-length?: int,
121     # If a leaf part's body content is not included, its transfer encoding
122     # may be given.  Using this and the encoded content length, it is
123     # possible for the consumer to estimate the decoded content length.
124     content-transfer-encoding?: string
125 }
126
127 # The headers of a message or part (format_headers_sprinter with reply = FALSE)
128 headers = {
129     Subject:        string,
130     From:           string,
131     To?:            string,
132     Cc?:            string,
133     Bcc?:           string,
134     Reply-To?:      string,
135     Date:           string
136 }
137
138 # Encryption status (format_part_sprinter)
139 encstatus = [{status: "good"|"bad"}]
140
141 # Signature status (format_part_sigstatus_sprinter)
142 sigstatus = [signature*]
143
144 signature = {
145     # (signature_status_to_string)
146     status:         "good"|"bad"|"error"|"unknown",
147     # if status is "good":
148     fingerprint?:   string,
149     created?:       unix_time,
150     expires?:       unix_time,
151     userid?:        string
152     # if status is not "good":
153     keyid?:         string
154     errors?:        sig_errors
155 }
156
157 sig_errors = {
158     key-revoked?: bool,
159     key-expired?: bool,
160     sig-expired?: bool,
161     key-missing?: bool,
162     alg-unsupported?: bool,
163     crl-missing?: bool,
164     crl-too-old?: bool,
165     bad-policy?: bool,
166     sys-error?: bool,
167     tofu-conflict?: bool
168 }
169
170 notmuch search schema
171 ---------------------
172
173 # --output=summary
174 search_summary = [thread_summary*]
175
176 # --output=threads
177 search_threads = [threadid*]
178
179 # --output=messages
180 search_messages = [messageid*]
181
182 # --output=files
183 search_files = [string*]
184
185 # --output=tags
186 search_tags = [string*]
187
188 thread_summary = {
189     thread:         threadid,
190     timestamp:      unix_time,
191     date_relative:  string,   # user-friendly timestamp
192     matched:        int,      # number of matched messages
193     total:          int,      # total messages in thread
194     authors:        string,   # comma-separated names with | between
195                               # matched and unmatched
196     subject:        string,
197     tags:           [string*],
198
199     # Two stable query strings identifying exactly the matched and
200     # unmatched messages currently in this thread.  The messages
201     # matched by these queries will not change even if more messages
202     # arrive in the thread.  If there are no matched or unmatched
203     # messages, the corresponding query will be null (there is no
204     # query that matches nothing).  (Added in schema version 2.)
205     query:          [string|null, string|null],
206 }
207
208 notmuch reply schema
209 --------------------
210
211 reply = {
212     # The headers of the constructed reply
213     reply-headers: reply_headers,
214
215     # As in the show format (format_part_sprinter)
216     original: message
217 }
218
219 # Reply headers (format_headers_sprinter with reply = TRUE)
220 reply_headers = {
221     Subject:        string,
222     From:           string,
223     To?:            string,
224     Cc?:            string,
225     Bcc?:           string,
226     In-reply-to:    string,
227     References:     string
228 }