cli/show: list all filenames of a message in the formatted 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 2 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
32 Common non-terminals
33 --------------------
34
35 # Number of seconds since the Epoch
36 unix_time = int
37
38 # Thread ID, sans "thread:"
39 threadid = string
40
41 # Message ID, sans "id:"
42 messageid = string
43
44 notmuch show schema
45 -------------------
46
47 # A top-level set of threads (do_show)
48 # Returned by notmuch show without a --part argument
49 thread_set = [thread*]
50
51 # Top-level messages in a thread (show_messages)
52 thread = [thread_node*]
53
54 # A message and its replies (show_messages)
55 thread_node = [
56     message|null,             # null if not matched and not --entire-thread
57     [thread_node*]            # children of message
58 ]
59
60 # A message (format_part_sprinter)
61 message = {
62     # (format_message_sprinter)
63     id:             messageid,
64     match:          bool,
65     filename:       [string*],
66     timestamp:      unix_time, # date header as unix time
67     date_relative:  string,   # user-friendly timestamp
68     tags:           [string*],
69
70     headers:        headers,
71     body?:          [part]    # omitted if --body=false
72 }
73
74 # A MIME part (format_part_sprinter)
75 part = {
76     id:             int|string, # part id (currently DFS part number)
77
78     encstatus?:     encstatus,
79     sigstatus?:     sigstatus,
80
81     content-type:   string,
82     content-id?:    string,
83     # if content-type starts with "multipart/":
84     content:        [part*],
85     # if content-type is "message/rfc822":
86     content:        [{headers: headers, body: [part]}],
87     # otherwise (leaf parts):
88     filename?:      string,
89     content-charset?: string,
90     # A leaf part's body content is optional, but may be included if
91     # it can be correctly encoded as a string.  Consumers should use
92     # this in preference to fetching the part content separately.
93     content?:       string,
94     # If a leaf part's body content is not included, the length of
95     # the encoded content (in bytes) may be given instead.
96     content-length?: int,
97     # If a leaf part's body content is not included, its transfer encoding
98     # may be given.  Using this and the encoded content length, it is
99     # possible for the consumer to estimate the decoded content length.
100     content-transfer-encoding?: string
101 }
102
103 # The headers of a message or part (format_headers_sprinter with reply = FALSE)
104 headers = {
105     Subject:        string,
106     From:           string,
107     To?:            string,
108     Cc?:            string,
109     Bcc?:           string,
110     Reply-To?:      string,
111     Date:           string
112 }
113
114 # Encryption status (format_part_sprinter)
115 encstatus = [{status: "good"|"bad"}]
116
117 # Signature status (format_part_sigstatus_sprinter)
118 sigstatus = [signature*]
119
120 signature = {
121     # (signature_status_to_string)
122     status:         "none"|"good"|"bad"|"error"|"unknown",
123     # if status is "good":
124     fingerprint?:   string,
125     created?:       unix_time,
126     expires?:       unix_time,
127     userid?:        string
128     # if status is not "good":
129     keyid?:         string
130     # if the signature has errors:
131     errors?:        int
132 }
133
134 notmuch search schema
135 ---------------------
136
137 # --output=summary
138 search_summary = [thread_summary*]
139
140 # --output=threads
141 search_threads = [threadid*]
142
143 # --output=messages
144 search_messages = [messageid*]
145
146 # --output=files
147 search_files = [string*]
148
149 # --output=tags
150 search_tags = [string*]
151
152 thread_summary = {
153     thread:         threadid,
154     timestamp:      unix_time,
155     date_relative:  string,   # user-friendly timestamp
156     matched:        int,      # number of matched messages
157     total:          int,      # total messages in thread
158     authors:        string,   # comma-separated names with | between
159                               # matched and unmatched
160     subject:        string,
161     tags:           [string*],
162
163     # Two stable query strings identifying exactly the matched and
164     # unmatched messages currently in this thread.  The messages
165     # matched by these queries will not change even if more messages
166     # arrive in the thread.  If there are no matched or unmatched
167     # messages, the corresponding query will be null (there is no
168     # query that matches nothing).  (Added in schema version 2.)
169     query:          [string|null, string|null],
170 }
171
172 notmuch reply schema
173 --------------------
174
175 reply = {
176     # The headers of the constructed reply
177     reply-headers: reply_headers,
178
179     # As in the show format (format_part_sprinter)
180     original: message
181 }
182
183 # Reply headers (format_headers_sprinter with reply = TRUE)
184 reply_headers = {
185     Subject:        string,
186     From:           string,
187     To?:            string,
188     Cc?:            string,
189     Bcc?:           string,
190     In-reply-to:    string,
191     References:     string
192 }