X-Git-Url: https://git.cworth.org/git?p=notmuch;a=blobdiff_plain;f=devel%2Fschemata;h=01810888e5a62d0ee28569cd5406ba19cefb7050;hp=728a46f214ac5a1597c48a62f6d00efbd41ffcd6;hb=HEAD;hpb=596a2076dcc1ebec2dc217f6d967397ef125aac4 diff --git a/devel/schemata b/devel/schemata index 728a46f2..4e05cdac 100644 --- a/devel/schemata +++ b/devel/schemata @@ -1,12 +1,44 @@ This file describes the schemata used for notmuch's structured output -format (currently JSON). +format (currently JSON and S-Expressions). []'s indicate lists. List items can be marked with a '?', meaning they are optional; or a '*', meaning there can be zero or more of that item. {}'s indicate an object that maps from field identifiers to -values. An object field marked '?' is optional. |'s indicate -alternates (e.g., int|string means something can be an int or a -string). +values. An object field marked '?' is optional; one marked with '*' +can repeat (with a different name). |'s indicate alternates (e.g., +int|string means something can be an int or a string). + +For S-Expression output, lists are printed delimited by () instead of +[]. Objects are printed as p-lists, i.e. lists where the keys and values +are interleaved. Keys are printed as keywords (symbols preceded by a +colon), e.g. (:id "123" :time 54321 :from "foobar"). Null is printed as +nil, true as t and false as nil. + +This is version 5 of the structured output format. + +Version history +--------------- + +v1 +- First versioned schema release. +- Added part.content-length and part.content-transfer-encoding fields. + +v2 +- Added the thread_summary.query field. + +v3 +- Replaced message.filename string with a list of filenames. +- Added part.content-disposition field. + +v4 +- replace signature error integer bitmask with a set of flags for + individual errors. +- (notmuch 0.29) added message.crypto to identify overall message + cryptographic state + +v5 +- sorting support for notmuch show (no change to actual schema, + just new command line argument) Common non-terminals -------------------- @@ -20,6 +52,9 @@ threadid = string # Message ID, sans "id:" messageid = string +# E-mail header name, sans trailing colon, like "Subject" or "In-Reply-To" +header_name = string + notmuch show schema ------------------- @@ -32,37 +67,57 @@ thread = [thread_node*] # A message and its replies (show_messages) thread_node = [ - message?, # present if --entire-thread or matched + message|null, # null if not matched and not --entire-thread [thread_node*] # children of message ] -# A message (show_message) +# A message (format_part_sprinter) message = { - # (format_message_json) + # (format_message_sprinter) id: messageid, match: bool, - filename: string, + excluded: bool, + filename: [string*], timestamp: unix_time, # date header as unix time date_relative: string, # user-friendly timestamp tags: [string*], headers: headers, - body: [part] + crypto: crypto, + duplicate: integer, + body?: [part] # omitted if --body=false +} + +# when showing the message, was any or all of it decrypted? +msgdecstatus: "full"|"partial" + +# The overall cryptographic state of the message as a whole: +crypto = { + signed?: { + status: sigstatus, + # was the set of signatures described under encrypted cover? + encrypted: bool, + # which of the headers is covered by sigstatus? + headers: [header_name*] + }, + decrypted?: { + status: msgdecstatus, + # map encrypted headers that differed from the outside headers. + # the value of each item in the map is what that field showed externally + # (maybe null if it was not present in the external headers). + header-mask: { header_name*: string|null } + } } -# A MIME part (show_message_body) +# A MIME part (format_part_sprinter) part = { - # format_part_start_json id: int|string, # part id (currently DFS part number) - # format_part_encstatus_json encstatus?: encstatus, - - # format_part_sigstatus_json sigstatus?: sigstatus, - # format_part_content_json content-type: string, + content-disposition?: string, content-id?: string, # if content-type starts with "multipart/": content: [part*], @@ -74,60 +129,81 @@ part = { # A leaf part's body content is optional, but may be included if # it can be correctly encoded as a string. Consumers should use # this in preference to fetching the part content separately. - content?: string + content?: string, + # If a leaf part's body content is not included, the length of + # the encoded content (in bytes) may be given instead. + content-length?: int, + # If a leaf part's body content is not included, its transfer encoding + # may be given. Using this and the encoded content length, it is + # possible for the consumer to estimate the decoded content length. + content-transfer-encoding?: string } -# The headers of a message (format_headers_json with raw headers -# and reply = FALSE) or a part (format_headers_message_part_json -# with pretty-printed headers) +# The headers of a message or part (format_headers_sprinter with reply = FALSE) headers = { Subject: string, From: string, To?: string, Cc?: string, Bcc?: string, - Date: string + Reply-To?: string, + Date: string, + extra_header_pair* } -# Encryption status (format_part_encstatus_json) +extra_header_pair= (header_name: string) +# Encryption status (format_part_sprinter) encstatus = [{status: "good"|"bad"}] -# Signature status (format_part_sigstatus_json) +# Signature status (format_part_sigstatus_sprinter) sigstatus = [signature*] signature = { - # signature_status_to_string - status: "none"|"good"|"bad"|"error"|"unknown", + # (signature_status_to_string) + status: "good"|"bad"|"error"|"unknown", # if status is "good": fingerprint?: string, created?: unix_time, expires?: unix_time, userid?: string + email?: string # if status is not "good": keyid?: string - # if the signature has errors: - errors?: int + errors?: sig_errors +} + +sig_errors = { + key-revoked?: bool, + key-expired?: bool, + sig-expired?: bool, + key-missing?: bool, + alg-unsupported?: bool, + crl-missing?: bool, + crl-too-old?: bool, + bad-policy?: bool, + sys-error?: bool, + tofu-conflict?: bool } notmuch search schema --------------------- # --output=summary -summary = [thread*] +search_summary = [thread_summary*] # --output=threads -threads = [threadid*] +search_threads = [threadid*] # --output=messages -messages = [messageid*] +search_messages = [messageid*] # --output=files -files = [string*] +search_files = [string*] # --output=tags -tags = [string*] +search_tags = [string*] -thread = { +thread_summary = { thread: threadid, timestamp: unix_time, date_relative: string, # user-friendly timestamp @@ -135,21 +211,30 @@ thread = { total: int, # total messages in thread authors: string, # comma-separated names with | between # matched and unmatched - subject: string + subject: string, + tags: [string*], + + # Two stable query strings identifying exactly the matched and + # unmatched messages currently in this thread. The messages + # matched by these queries will not change even if more messages + # arrive in the thread. If there are no matched or unmatched + # messages, the corresponding query will be null (there is no + # query that matches nothing). (Added in schema version 2.) + query: [string|null, string|null], } notmuch reply schema -------------------- reply = { - # The headers of the constructed reply (format_headers_json with - # raw headers and reply = TRUE) + # The headers of the constructed reply reply-headers: reply_headers, - # As in the show format (format_part_json) + # As in the show format (format_part_sprinter) original: message } +# Reply headers (format_headers_sprinter with reply = TRUE) reply_headers = { Subject: string, From: string,