]> git.cworth.org Git - notmuch/blob - devel/schemata
CLI/show: support --duplicate for structured 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; one marked with '*'
8 can repeat (with a different name). |'s indicate alternates (e.g.,
9 int|string means something can be an int or a 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 5 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 v5
40 - sorting support for notmuch show (no change to actual schema,
41   just new command line argument)
42
43 Common non-terminals
44 --------------------
45
46 # Number of seconds since the Epoch
47 unix_time = int
48
49 # Thread ID, sans "thread:"
50 threadid = string
51
52 # Message ID, sans "id:"
53 messageid = string
54
55 # E-mail header name, sans trailing colon, like "Subject" or "In-Reply-To"
56 header_name = string
57
58 notmuch show schema
59 -------------------
60
61 # A top-level set of threads (do_show)
62 # Returned by notmuch show without a --part argument
63 thread_set = [thread*]
64
65 # Top-level messages in a thread (show_messages)
66 thread = [thread_node*]
67
68 # A message and its replies (show_messages)
69 thread_node = [
70     message|null,             # null if not matched and not --entire-thread
71     [thread_node*]            # children of message
72 ]
73
74 # A message (format_part_sprinter)
75 message = {
76     # (format_message_sprinter)
77     id:             messageid,
78     match:          bool,
79     filename:       [string*],
80     timestamp:      unix_time, # date header as unix time
81     date_relative:  string,   # user-friendly timestamp
82     tags:           [string*],
83
84     headers:        headers,
85     crypto:         crypto,
86     duplicate:      integer,
87     body?:          [part]    # omitted if --body=false
88 }
89
90 # when showing the message, was any or all of it decrypted?
91 msgdecstatus: "full"|"partial"
92
93 # The overall cryptographic state of the message as a whole:
94 crypto = {
95     signed?:    {
96                   status:      sigstatus,
97                   # was the set of signatures described under encrypted cover?
98                   encrypted:   bool,
99                   # which of the headers is covered by sigstatus?
100                   headers:     [header_name*]
101                 },
102     decrypted?: {
103                   status: msgdecstatus,
104                   # map encrypted headers that differed from the outside headers.
105                   # the value of each item in the map is what that field showed externally
106                   # (maybe null if it was not present in the external headers).
107                   header-mask:  { header_name*: string|null }
108                 }
109 }
110
111 # A MIME part (format_part_sprinter)
112 part = {
113     id:             int|string, # part id (currently DFS part number)
114
115     encstatus?:     encstatus,
116     sigstatus?:     sigstatus,
117
118     content-type:   string,
119     content-disposition?:       string,
120     content-id?:    string,
121     # if content-type starts with "multipart/":
122     content:        [part*],
123     # if content-type is "message/rfc822":
124     content:        [{headers: headers, body: [part]}],
125     # otherwise (leaf parts):
126     filename?:      string,
127     content-charset?: string,
128     # A leaf part's body content is optional, but may be included if
129     # it can be correctly encoded as a string.  Consumers should use
130     # this in preference to fetching the part content separately.
131     content?:       string,
132     # If a leaf part's body content is not included, the length of
133     # the encoded content (in bytes) may be given instead.
134     content-length?: int,
135     # If a leaf part's body content is not included, its transfer encoding
136     # may be given.  Using this and the encoded content length, it is
137     # possible for the consumer to estimate the decoded content length.
138     content-transfer-encoding?: string
139 }
140
141 # The headers of a message or part (format_headers_sprinter with reply = FALSE)
142 headers = {
143     Subject:        string,
144     From:           string,
145     To?:            string,
146     Cc?:            string,
147     Bcc?:           string,
148     Reply-To?:      string,
149     Date:           string,
150     extra_header_pair*
151 }
152
153 extra_header_pair=  (header_name: string)
154 # Encryption status (format_part_sprinter)
155 encstatus = [{status: "good"|"bad"}]
156
157 # Signature status (format_part_sigstatus_sprinter)
158 sigstatus = [signature*]
159
160 signature = {
161     # (signature_status_to_string)
162     status:         "good"|"bad"|"error"|"unknown",
163     # if status is "good":
164     fingerprint?:   string,
165     created?:       unix_time,
166     expires?:       unix_time,
167     userid?:        string
168     email?:         string
169     # if status is not "good":
170     keyid?:         string
171     errors?:        sig_errors
172 }
173
174 sig_errors = {
175     key-revoked?: bool,
176     key-expired?: bool,
177     sig-expired?: bool,
178     key-missing?: bool,
179     alg-unsupported?: bool,
180     crl-missing?: bool,
181     crl-too-old?: bool,
182     bad-policy?: bool,
183     sys-error?: bool,
184     tofu-conflict?: bool
185 }
186
187 notmuch search schema
188 ---------------------
189
190 # --output=summary
191 search_summary = [thread_summary*]
192
193 # --output=threads
194 search_threads = [threadid*]
195
196 # --output=messages
197 search_messages = [messageid*]
198
199 # --output=files
200 search_files = [string*]
201
202 # --output=tags
203 search_tags = [string*]
204
205 thread_summary = {
206     thread:         threadid,
207     timestamp:      unix_time,
208     date_relative:  string,   # user-friendly timestamp
209     matched:        int,      # number of matched messages
210     total:          int,      # total messages in thread
211     authors:        string,   # comma-separated names with | between
212                               # matched and unmatched
213     subject:        string,
214     tags:           [string*],
215
216     # Two stable query strings identifying exactly the matched and
217     # unmatched messages currently in this thread.  The messages
218     # matched by these queries will not change even if more messages
219     # arrive in the thread.  If there are no matched or unmatched
220     # messages, the corresponding query will be null (there is no
221     # query that matches nothing).  (Added in schema version 2.)
222     query:          [string|null, string|null],
223 }
224
225 notmuch reply schema
226 --------------------
227
228 reply = {
229     # The headers of the constructed reply
230     reply-headers: reply_headers,
231
232     # As in the show format (format_part_sprinter)
233     original: message
234 }
235
236 # Reply headers (format_headers_sprinter with reply = TRUE)
237 reply_headers = {
238     Subject:        string,
239     From:           string,
240     To?:            string,
241     Cc?:            string,
242     Bcc?:           string,
243     In-reply-to:    string,
244     References:     string
245 }