this repo has no description
at main 9.5 kB view raw
1(*--------------------------------------------------------------------------- 2 Copyright (c) 2025 Anil Madhavapeddy. All rights reserved. 3 SPDX-License-Identifier: ISC 4 ---------------------------------------------------------------------------*) 5 6(** Email header types as defined in RFC 8621 Section 4.1.2 7 8 @canonical Jmap.Proto.Email_header *) 9 10(** {1 Raw Headers} *) 11 12(** A raw email header name-value pair. *) 13type t = { 14 name : string; 15 (** The header field name. *) 16 value : string; 17 (** The raw header field value. *) 18} 19 20val create : name:string -> value:string -> t 21 22val name : t -> string 23val value : t -> string 24 25val jsont : t Jsont.t 26 27(** {1 Header Categories} 28 29 RFC 8621 Section 4.1.2 restricts which parsed forms can be used with 30 which headers. These polymorphic variant types encode those restrictions 31 at the type level. 32 33 Each category corresponds to headers that share the same allowed forms: 34 - Address headers: can use [Addresses] and [Grouped_addresses] forms 35 - Message-ID headers: can use [Message_ids] form 36 - Date headers: can use [Date] form 37 - URL headers: can use [Urls] form 38 - Text headers: can use [Text] form 39 - All headers can use [Raw] form 40 - Custom headers (not in RFC 5322/2369) can use any form *) 41 42(** Headers that allow the [Addresses] and [Grouped_addresses] forms. 43 These are address-list headers per RFC 5322. *) 44type address_header = [ 45 | `From 46 | `Sender 47 | `Reply_to 48 | `To 49 | `Cc 50 | `Bcc 51 | `Resent_from 52 | `Resent_sender 53 | `Resent_reply_to 54 | `Resent_to 55 | `Resent_cc 56 | `Resent_bcc 57] 58 59(** Headers that allow the [Message_ids] form. 60 These contain msg-id values per RFC 5322. *) 61type message_id_header = [ 62 | `Message_id 63 | `In_reply_to 64 | `References 65 | `Resent_message_id 66] 67 68(** Headers that allow the [Date] form. 69 These contain date-time values per RFC 5322. *) 70type date_header = [ 71 | `Date 72 | `Resent_date 73] 74 75(** Headers that allow the [Urls] form. 76 These are list-* headers per RFC 2369. *) 77type url_header = [ 78 | `List_help 79 | `List_unsubscribe 80 | `List_subscribe 81 | `List_post 82 | `List_owner 83 | `List_archive 84] 85 86(** Headers that allow the [Text] form. 87 These contain unstructured or phrase content. *) 88type text_header = [ 89 | `Subject 90 | `Comments 91 | `Keywords 92 | `List_id 93] 94 95(** All standard headers defined in RFC 5322 and RFC 2369. *) 96type standard_header = [ 97 | address_header 98 | message_id_header 99 | date_header 100 | url_header 101 | text_header 102] 103 104(** A custom header not defined in RFC 5322 or RFC 2369. 105 Custom headers can use any parsed form. *) 106type custom_header = [ `Custom of string ] 107 108(** Any header - standard or custom. *) 109type any_header = [ standard_header | custom_header ] 110 111(** {2 Header Name Conversion} *) 112 113val standard_header_to_string : [< standard_header ] -> string 114(** Convert a standard header variant to its wire name (e.g., [`From] -> "From"). *) 115 116val standard_header_of_string : string -> standard_header option 117(** Parse a header name to a standard header variant, case-insensitive. 118 Returns [None] for non-standard headers. *) 119 120val any_header_to_string : [< any_header ] -> string 121(** Convert any header variant to its wire name. *) 122 123(** {1 Header Parsed Forms} 124 125 RFC 8621 defines several parsed forms for headers. 126 These can be requested via the [header:Name:form] properties. *) 127 128(** The parsed form to request for a header value. *) 129type form = [ 130 | `Raw (** Raw octets, available for all headers *) 131 | `Text (** Decoded text, for text headers or custom *) 132 | `Addresses (** Flat address list, for address headers or custom *) 133 | `Grouped_addresses (** Address list with groups, for address headers or custom *) 134 | `Message_ids (** List of message-id strings, for message-id headers or custom *) 135 | `Date (** Parsed date, for date headers or custom *) 136 | `Urls (** List of URLs, for url headers or custom *) 137] 138 139val form_to_string : [< form ] -> string 140(** Convert form to wire suffix (e.g., [`Addresses] -> "asAddresses"). 141 [`Raw] returns the empty string (raw is the default). *) 142 143val form_of_string : string -> form option 144(** Parse a form suffix (e.g., "asAddresses" -> [`Addresses]). 145 Empty string returns [`Raw]. *) 146 147(** {1 Header Property Requests} 148 149 Type-safe construction of [header:Name:form:all] property strings. 150 The GADT ensures that only valid form/header combinations are allowed. *) 151 152(** A header property request with type-safe form selection. 153 154 The type parameter encodes what forms are allowed: 155 - Address headers allow [Addresses] and [Grouped_addresses] 156 - Message-ID headers allow [Message_ids] 157 - Date headers allow [Date] 158 - URL headers allow [Urls] 159 - Text headers allow [Text] 160 - All headers allow [Raw] 161 - Custom headers allow any form *) 162type header_property = 163 | Raw of { name : string; all : bool } 164 (** Raw form, available for any header. *) 165 166 | Text of { header : [ text_header | custom_header ]; all : bool } 167 (** Text form, for text headers or custom. *) 168 169 | Addresses of { header : [ address_header | custom_header ]; all : bool } 170 (** Addresses form, for address headers or custom. *) 171 172 | Grouped_addresses of { header : [ address_header | custom_header ]; all : bool } 173 (** GroupedAddresses form, for address headers or custom. *) 174 175 | Message_ids of { header : [ message_id_header | custom_header ]; all : bool } 176 (** MessageIds form, for message-id headers or custom. *) 177 178 | Date of { header : [ date_header | custom_header ]; all : bool } 179 (** Date form, for date headers or custom. *) 180 181 | Urls of { header : [ url_header | custom_header ]; all : bool } 182 (** URLs form, for URL headers or custom. *) 183 184val header_property_to_string : header_property -> string 185(** Convert a header property request to wire format. 186 E.g., [Addresses { header = `From; all = true }] -> "header:From:asAddresses:all" *) 187 188val header_property_of_string : string -> header_property option 189(** Parse a header property string. 190 Returns [None] if the string doesn't match [header:*] format. *) 191 192(** {2 Convenience Constructors} *) 193 194val raw : ?all:bool -> string -> header_property 195(** [raw ?all name] creates a raw header property request. *) 196 197val text : ?all:bool -> [ text_header | custom_header ] -> header_property 198(** [text ?all header] creates a text header property request. *) 199 200val addresses : ?all:bool -> [ address_header | custom_header ] -> header_property 201(** [addresses ?all header] creates an addresses header property request. *) 202 203val grouped_addresses : ?all:bool -> [ address_header | custom_header ] -> header_property 204(** [grouped_addresses ?all header] creates a grouped addresses header property request. *) 205 206val message_ids : ?all:bool -> [ message_id_header | custom_header ] -> header_property 207(** [message_ids ?all header] creates a message-ids header property request. *) 208 209val date : ?all:bool -> [ date_header | custom_header ] -> header_property 210(** [date ?all header] creates a date header property request. *) 211 212val urls : ?all:bool -> [ url_header | custom_header ] -> header_property 213(** [urls ?all header] creates a URLs header property request. *) 214 215(** {1 Header Values in Responses} 216 217 When fetching dynamic headers, the response value type depends on the 218 requested form. This type captures all possible response shapes. *) 219 220(** A header value from the response. 221 222 The variant encodes both the form and whether [:all] was requested: 223 - [*_single] variants: value of the last header instance, or [None] if absent 224 - [*_all] variants: list of values for all instances, empty if absent *) 225type header_value = 226 | String_single of string option 227 (** Raw or Text form, single instance. *) 228 229 | String_all of string list 230 (** Raw or Text form, all instances. *) 231 232 | Addresses_single of Mail_address.t list option 233 (** Addresses form, single instance. *) 234 235 | Addresses_all of Mail_address.t list list 236 (** Addresses form, all instances. *) 237 238 | Grouped_single of Mail_address.Group.t list option 239 (** GroupedAddresses form, single instance. *) 240 241 | Grouped_all of Mail_address.Group.t list list 242 (** GroupedAddresses form, all instances. *) 243 244 | Date_single of Ptime.t option 245 (** Date form, single instance. *) 246 247 | Date_all of Ptime.t option list 248 (** Date form, all instances. *) 249 250 | Strings_single of string list option 251 (** MessageIds or URLs form, single instance. *) 252 253 | Strings_all of string list option list 254 (** MessageIds or URLs form, all instances. *) 255 256val header_value_jsont : form:form -> all:bool -> header_value Jsont.t 257(** [header_value_jsont ~form ~all] returns a JSON codec for header values 258 with the given form and multiplicity. *) 259 260(** {1 Low-level JSON Codecs} 261 262 These codecs are used internally and for custom header processing. *) 263 264(** The raw form - header value as-is. *) 265val raw_jsont : string Jsont.t 266 267(** The text form - decoded and unfolded value. *) 268val text_jsont : string Jsont.t 269 270(** The addresses form - list of email addresses. *) 271val addresses_jsont : Mail_address.t list Jsont.t 272 273(** The grouped addresses form - addresses with group info. *) 274val grouped_addresses_jsont : Mail_address.Group.t list Jsont.t 275 276(** The message IDs form - list of message-id strings. *) 277val message_ids_jsont : string list Jsont.t 278 279(** The date form - parsed RFC 3339 date. *) 280val date_jsont : Ptime.t Jsont.t 281 282(** The URLs form - list of URL strings. *) 283val urls_jsont : string list Jsont.t