My agentic slop goes here. Not intended for anyone else!
at main 7.5 kB view raw
1(** Implementation of JMAP Email/import method (RFC 8621 Section 4.8) *) 2 3(** {1 EmailImport Object} *) 4 5type email_import = { 6 blob_id : Jmap.Id.t; 7 mailbox_ids : (Jmap.Id.t * bool) list; 8 keywords : (string * bool) list; 9 received_at : Jmap.Date.t option; 10} 11 12let create_email_import ~blob_id ~mailbox_ids ?(keywords=[]) ?received_at () = { 13 blob_id; 14 mailbox_ids; 15 keywords; 16 received_at; 17} 18 19(** JSON serialization for EmailImport objects *) 20let email_import_to_json ei = 21 let json_fields = [ 22 ("blobId", `String (Jmap.Id.to_string ei.blob_id)); 23 ("mailboxIds", `Assoc (List.map (fun (id, v) -> (Jmap.Id.to_string id, `Bool v)) ei.mailbox_ids)); 24 ] in 25 let json_fields = if ei.keywords = [] then json_fields 26 else ("keywords", `Assoc (List.map (fun (k, v) -> (k, `Bool v)) ei.keywords)) :: json_fields 27 in 28 let json_fields = match ei.received_at with 29 | Some date -> ("receivedAt", `String (Jmap.Date.to_rfc3339 date)) :: json_fields 30 | None -> json_fields 31 in 32 `Assoc (List.rev json_fields) 33 34let email_import_of_json json = 35 try 36 let open Yojson.Safe.Util in 37 let blob_id_str = json |> member "blobId" |> to_string in 38 let blob_id = match Jmap.Id.of_string blob_id_str with 39 | Ok id -> id 40 | Error _ -> failwith ("Invalid blobId: " ^ blob_id_str) 41 in 42 let mailbox_ids_assoc = json |> member "mailboxIds" |> to_assoc in 43 let mailbox_ids = List.map (fun (id_str, v) -> 44 let id = match Jmap.Id.of_string id_str with 45 | Ok id -> id 46 | Error _ -> failwith ("Invalid mailbox ID: " ^ id_str) 47 in 48 (id, to_bool v) 49 ) mailbox_ids_assoc in 50 let keywords = match json |> member "keywords" with 51 | `Null -> [] 52 | keywords_json -> List.map (fun (k, v) -> (k, to_bool v)) (to_assoc keywords_json) 53 in 54 let received_at = match json |> member "receivedAt" with 55 | `Null -> None 56 | date_json -> match Jmap.Date.of_rfc3339 (to_string date_json) with 57 | Ok date -> Some date 58 | Error _ -> failwith "Invalid receivedAt date format" 59 in 60 Ok (create_email_import ~blob_id ~mailbox_ids ~keywords ?received_at ()) 61 with 62 | exn -> Error ("Failed to parse EmailImport: " ^ Printexc.to_string exn) 63 64(** {1 Email/import Arguments} *) 65 66module Import_args = struct 67 type t = { 68 account_id : string; 69 if_in_state : string option; 70 emails : (string * email_import) list; 71 } 72 73 let create ~account_id ?if_in_state ~emails () = { 74 account_id; 75 if_in_state; 76 emails; 77 } 78 79 let account_id t = t.account_id 80 let if_in_state t = t.if_in_state 81 let emails t = t.emails 82 83 let to_json t = 84 let json_fields = [ 85 ("accountId", `String t.account_id); 86 ("emails", `Assoc (List.map (fun (creation_id, ei) -> (creation_id, email_import_to_json ei)) t.emails)); 87 ] in 88 let json_fields = match t.if_in_state with 89 | Some state -> ("ifInState", `String state) :: json_fields 90 | None -> json_fields 91 in 92 `Assoc (List.rev json_fields) 93 94 let of_json json = 95 try 96 let open Yojson.Safe.Util in 97 let account_id = json |> member "accountId" |> to_string in 98 let if_in_state = json |> member "ifInState" |> to_string_option in 99 let emails_assoc = json |> member "emails" |> to_assoc in 100 let emails = List.map (fun (creation_id, ei_json) -> 101 match email_import_of_json ei_json with 102 | Ok ei -> (creation_id, ei) 103 | Error err -> failwith err 104 ) emails_assoc in 105 Ok (create ~account_id ?if_in_state ~emails ()) 106 with 107 | exn -> Error ("Failed to parse Email/import args: " ^ Printexc.to_string exn) 108end 109 110(** {1 Email/import Response} *) 111 112type email_creation_result = { 113 id : Jmap.Id.t; 114 blob_id : Jmap.Id.t; 115 thread_id : Jmap.Id.t; 116 size : int; 117} 118 119let email_creation_result_to_json ecr = 120 `Assoc [ 121 ("id", `String (Jmap.Id.to_string ecr.id)); 122 ("blobId", `String (Jmap.Id.to_string ecr.blob_id)); 123 ("threadId", `String (Jmap.Id.to_string ecr.thread_id)); 124 ("size", `Int ecr.size); 125 ] 126 127let email_creation_result_of_json json = 128 try 129 let open Yojson.Safe.Util in 130 let id_str = json |> member "id" |> to_string in 131 let id = match Jmap.Id.of_string id_str with 132 | Ok id -> id 133 | Error _ -> failwith ("Invalid id: " ^ id_str) 134 in 135 let blob_id_str = json |> member "blobId" |> to_string in 136 let blob_id = match Jmap.Id.of_string blob_id_str with 137 | Ok id -> id 138 | Error _ -> failwith ("Invalid blobId: " ^ blob_id_str) 139 in 140 let thread_id_str = json |> member "threadId" |> to_string in 141 let thread_id = match Jmap.Id.of_string thread_id_str with 142 | Ok id -> id 143 | Error _ -> failwith ("Invalid threadId: " ^ thread_id_str) 144 in 145 let size = json |> member "size" |> to_int in 146 Ok {id; blob_id; thread_id; size} 147 with 148 | exn -> Error ("Failed to parse EmailCreationResult: " ^ Printexc.to_string exn) 149 150module Import_response = struct 151 type response = { 152 account_id : string; 153 old_state : string option; 154 new_state : string option; 155 created : (string * email_creation_result) list; 156 not_created : (string * Jmap.Error.Set_error.t) list; 157 } 158 159 let create ~account_id ?old_state ?new_state ?(created=[]) ?(not_created=[]) () = { 160 account_id; 161 old_state; 162 new_state; 163 created; 164 not_created; 165 } 166 167 let account_id t = t.account_id 168 let old_state t = t.old_state 169 let new_state t = t.new_state 170 let created t = t.created 171 let not_created t = t.not_created 172 173 let to_json t = 174 let json_fields = [ 175 ("accountId", `String t.account_id); 176 ] in 177 let json_fields = match t.old_state with 178 | Some state -> ("oldState", `String state) :: json_fields 179 | None -> json_fields 180 in 181 let json_fields = match t.new_state with 182 | Some state -> ("newState", `String state) :: json_fields 183 | None -> json_fields 184 in 185 let json_fields = if t.created = [] then 186 ("created", `Null) :: json_fields 187 else 188 ("created", `Assoc (List.map (fun (cid, ecr) -> (cid, email_creation_result_to_json ecr)) t.created)) :: json_fields 189 in 190 let json_fields = if t.not_created = [] then 191 ("notCreated", `Null) :: json_fields 192 else 193 ("notCreated", `Assoc (List.map (fun (cid, err) -> (cid, Jmap.Error.Set_error.to_json err)) t.not_created)) :: json_fields 194 in 195 `Assoc (List.rev json_fields) 196 197 let of_json json = 198 try 199 let open Yojson.Safe.Util in 200 let account_id = json |> member "accountId" |> to_string in 201 let old_state = json |> member "oldState" |> to_string_option in 202 let new_state = json |> member "newState" |> to_string_option in 203 let created = match json |> member "created" with 204 | `Null -> [] 205 | created_json -> List.map (fun (cid, ecr_json) -> 206 match email_creation_result_of_json ecr_json with 207 | Ok ecr -> (cid, ecr) 208 | Error err -> failwith err 209 ) (to_assoc created_json) 210 in 211 let not_created = match json |> member "notCreated" with 212 | `Null -> [] 213 | not_created_json -> List.map (fun (cid, err_json) -> 214 match Jmap.Error.Set_error.of_json err_json with 215 | Ok err -> (cid, err) 216 | Error err_msg -> failwith err_msg 217 ) (to_assoc not_created_json) 218 in 219 Ok (create ~account_id ?old_state ?new_state ~created ~not_created ()) 220 with 221 | exn -> Error ("Failed to parse Email/import response: " ^ Printexc.to_string exn) 222end