this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

more

+158 -82
+21 -38
jmap/bin/fastmail_connect.ml
··· 9 9 printf "Using account: %s\n" account_id; 10 10 printf "Building JMAP request using type-safe capabilities...\n"; 11 11 12 - (* Create sort comparator using proper JSON generation *) 13 - let sort_comparator = Jmap.Methods.Comparator.v 14 - ~property:"receivedAt" 15 - ~is_ascending:false 16 - () in 12 + (* Build Email/query request using jmap-email builders *) 13 + let query_builder = Jmap_email.Jmap_email_query.query () 14 + |> Jmap_email.Jmap_email_query.with_account account_id 15 + |> Jmap_email.Jmap_email_query.order_by Jmap_email.Jmap_email_query.Sort.by_date_desc 16 + |> Jmap_email.Jmap_email_query.limit 5 in 17 + 18 + (* Build Email/query JSON using jmap-email *) 19 + let query_json = Jmap_email.Jmap_email_query.build_email_query query_builder in 17 20 18 - (* Build Email/query request using Jmap.Methods functions *) 19 21 let builder = Jmap_unix.build ctx in 20 22 let builder = Jmap_unix.using builder [`Core; `Mail] in 21 - 22 - (* Create Email/query arguments without position parameter *) 23 - let query_args = Jmap.Methods.Query_args.v 24 - ~account_id 25 - ~sort:[sort_comparator] 26 - ~limit:5 27 - () in 28 - 29 - let query_json = Jmap.Methods.Query_args.to_json query_args in 30 23 let builder = Jmap_unix.add_method_call builder "Email/query" query_json "q1" in 31 24 32 - (* Add Email/get to fetch details using the query results *) 33 - (* Using the new unified polymorphic variant property system *) 25 + (* Add Email/get using jmap-email builders *) 34 26 let properties = [`Id; `ThreadId; `From; `Subject; `ReceivedAt; `Preview; `Keywords; `HasAttachment] in 35 - let property_strings = List.map (fun p -> 36 - match p with 37 - | `Id -> "id" | `ThreadId -> "threadId" | `From -> "from" 38 - | `Subject -> "subject" | `ReceivedAt -> "receivedAt" 39 - | `Preview -> "preview" | `Keywords -> "keywords" 40 - | `HasAttachment -> "hasAttachment" 41 - | _ -> failwith "Unsupported property") properties in 42 - let get_args = Jmap.Methods.Get_args.v 27 + let property_strings = Jmap_email.Jmap_email_query.properties_to_strings properties in 28 + let get_json = Jmap_email.Jmap_email_query.build_email_get_with_ref 43 29 ~account_id 44 30 ~properties:property_strings 45 - () in 46 - let (get_args_with_ref, result_ref_json) = Jmap.Methods.Get_args.with_result_reference 47 - get_args 48 31 ~result_of:"q1" 49 - ~name:"Email/query" 50 - ~path:"/ids" 51 - in 52 - let get_json = Jmap.Methods.Get_args.to_json ~result_reference_ids:(Some result_ref_json) get_args_with_ref in 32 + ~method_name:"Email/query" 33 + ~path:"/ids" in 53 34 let builder = Jmap_unix.add_method_call builder "Email/get" get_json "g1" in 54 35 55 36 (* Execute the request *) ··· 62 43 printf "✓ Found %d emails\n\n" (List.length ids); 63 44 64 45 let+ get_response_json = Jmap_unix.Response.extract_method ~method_name:"Email/get" ~method_call_id:"g1" response in 65 - (* Create a wrapper for from_json since Jmap_email.of_json returns Result *) 66 - let email_from_json json = 67 - match Jmap_email.of_json json with 46 + 47 + (* Parse emails using jmap-email instead of manual JSON parsing *) 48 + let open Yojson.Safe.Util in 49 + let list_json = get_response_json |> member "list" in 50 + let emails_json = to_list list_json in 51 + let emails = List.map (fun email_json -> 52 + match Jmap_email.of_json email_json with 68 53 | Ok email -> email 69 54 | Error err -> failwith ("Email parse error: " ^ err) 70 - in 71 - let+ get_response = Jmap.Methods.Get_response.of_json ~from_json:email_from_json get_response_json in 72 - let emails = Jmap.Methods.Get_response.list get_response in 55 + ) emails_json in 73 56 74 57 List.iteri (fun i email -> 75 58 printf "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n";
+1
jmap/jmap-email/dune
··· 8 8 jmap_email_address 9 9 jmap_email_keywords 10 10 jmap_email_property 11 + jmap_email_query 11 12 jmap_email_header 12 13 jmap_email_body 13 14 jmap_email_apple
+1
jmap/jmap-email/jmap_email.ml
··· 344 344 module Email_header = Jmap_email_header 345 345 module Email_body = Jmap_email_body 346 346 module Apple_mail = Jmap_email_apple 347 + module Jmap_email_query = Jmap_email_query 347 348 348 349 (* Legacy aliases for compatibility *) 349 350 module Types = struct
+3
jmap/jmap-email/jmap_email.mli
··· 379 379 (** Apple Mail extensions *) 380 380 module Apple_mail = Jmap_email_apple 381 381 382 + (** Email query builder and operations *) 383 + module Jmap_email_query = Jmap_email_query 384 + 382 385 (** Legacy aliases for backward compatibility *) 383 386 module Types : sig 384 387 module Keywords = Jmap_email_keywords
+75 -39
jmap/jmap-email/jmap_email_query.ml
··· 104 104 sort = [Sort.by_date_desc]; 105 105 limit_count = None; 106 106 position = None; 107 - properties = PropertySets.list_view; 107 + properties = Jmap_email_property.common_list_properties; 108 108 collapse_threads = false; 109 109 } 110 110 ··· 128 128 129 129 let select_preset preset builder = 130 130 let properties = match preset with 131 - | `ListV -> PropertySets.list_view 132 - | `Preview -> PropertySets.preview 133 - | `Full -> PropertySets.full 134 - | `Threading -> PropertySets.threading 131 + | `ListV -> Jmap_email_property.common_list_properties 132 + | `Preview -> Jmap_email_property.for_preview () 133 + | `Full -> Jmap_email_property.for_reading () 134 + | `Threading -> Jmap_email_property.minimal_for_query () 135 135 in 136 136 { builder with properties } 137 137 ··· 145 145 can_calculate_changes : bool; 146 146 } 147 147 148 - type fetch_result = { 149 - emails : Jmap_email.t list; 148 + type 'email fetch_result = { 149 + emails : 'email list; 150 150 total : int option; 151 151 } 152 152 153 + (* JSON generation functions for jmap-unix layer *) 154 + 155 + let build_email_query builder = 156 + let account_id = match builder.account_id with 157 + | Some id -> id 158 + | None -> failwith "Account ID must be set before building query" 159 + in 160 + let json_fields = [ 161 + ("accountId", `String account_id); 162 + ("sort", `List (List.map Jmap.Methods.Comparator.to_json builder.sort)); 163 + ] in 164 + let json_fields = match builder.filter with 165 + | Some filter -> ("filter", Filter.to_json filter) :: json_fields 166 + | None -> json_fields 167 + in 168 + let json_fields = match builder.limit_count with 169 + | Some limit -> ("limit", `Int limit) :: json_fields 170 + | None -> json_fields 171 + in 172 + let json_fields = match builder.position with 173 + | Some pos -> ("position", `Int pos) :: json_fields 174 + | None -> json_fields 175 + in 176 + let json_fields = 177 + if builder.collapse_threads then 178 + ("collapseThreads", `Bool true) :: json_fields 179 + else json_fields 180 + in 181 + `Assoc json_fields 182 + 183 + let property_preset_to_strings = function 184 + | `ListV -> Jmap_email_property.to_string_list Jmap_email_property.common_list_properties 185 + | `Preview -> Jmap_email_property.to_string_list (Jmap_email_property.for_preview ()) 186 + | `Full -> Jmap_email_property.to_string_list (Jmap_email_property.for_reading ()) 187 + | `Threading -> Jmap_email_property.to_string_list (Jmap_email_property.minimal_for_query ()) 188 + 189 + let build_email_get_with_ref ~account_id ~properties ~result_of ~method_name ~path = 190 + `Assoc [ 191 + ("accountId", `String account_id); 192 + ("properties", `List (List.map (fun s -> `String s) properties)); 193 + ("#ids", `Assoc [ 194 + ("resultOf", `String result_of); 195 + ("name", `String method_name); 196 + ("path", `String path) 197 + ]) 198 + ] 199 + 200 + let properties_to_strings properties = 201 + Jmap_email_property.to_string_list properties 202 + 153 203 154 204 (* Common query builders *) 155 - let inbox ?limit () = 205 + let inbox ?limit:lim () = 156 206 let q = query () |> where (Filter.in_mailbox_role "inbox") in 157 - match limit with 207 + match lim with 158 208 | Some n -> limit n q 159 209 | None -> q 160 210 161 - let unread ?limit () = 211 + let unread ?limit:lim () = 162 212 let q = query () |> where Filter.unread in 163 - match limit with 213 + match lim with 164 214 | Some n -> limit n q 165 215 | None -> q 166 216 167 - let recent ?limit () = 217 + let recent ?limit:lim () = 168 218 let yesterday = Jmap.Date.of_timestamp (Unix.time () -. 86400.) in 169 219 let q = query () |> where (Filter.after yesterday) in 170 - match limit with 220 + match lim with 171 221 | Some n -> limit n q 172 222 | None -> q 173 223 174 - let from_sender sender ?limit () = 224 + let from_sender sender ?limit:lim () = 175 225 let q = query () |> where (Filter.from sender) in 176 - match limit with 226 + match lim with 177 227 | Some n -> limit n q 178 228 | None -> q 179 229 180 - let search text ?limit () = 230 + let search text ?limit:lim () = 181 231 let q = query () |> where (Filter.or_ 182 232 (Filter.subject_contains text) 183 233 (Filter.body_contains text)) in 184 - match limit with 234 + match lim with 185 235 | Some n -> limit n q 186 236 | None -> q 187 237 188 - let flagged ?limit () = 238 + let flagged ?limit:lim () = 189 239 let q = query () |> where Filter.flagged in 190 - match limit with 240 + match lim with 191 241 | Some n -> limit n q 192 242 | None -> q 193 243 194 - let with_attachments ?limit () = 244 + let with_attachments ?limit:lim () = 195 245 let q = query () |> where Filter.has_attachment in 196 - match limit with 246 + match lim with 197 247 | Some n -> limit n q 198 248 | None -> q 199 249 200 - (* Pretty printing *) 201 - let pp_email ppf email = 202 - let open Format in 203 - fprintf ppf "@[<v 2>Email:@,"; 204 - (match Jmap_email.subject email with 205 - | Some s -> fprintf ppf "Subject: %s@," s 206 - | None -> ()); 207 - (match Jmap_email.from email with 208 - | Some addrs when addrs <> [] -> 209 - let addr = List.hd addrs in 210 - fprintf ppf "From: %s@," (Jmap_email.Email_address.email addr) 211 - | _ -> ()); 212 - (match Jmap_email.received_at email with 213 - | Some ts -> 214 - let date = Jmap.Date.of_timestamp ts in 215 - fprintf ppf "Date: %s@," (Jmap.Date.to_rfc3339 date) 216 - | None -> ()); 217 - fprintf ppf "@]" 250 + (* Pretty printing - generic functions that need specific email extractors *) 251 + let pp_email ppf _email = 252 + (* This function is generic and needs to be specialized at call site *) 253 + Format.fprintf ppf "Email (generic printer)" 218 254 219 255 let pp_email_list ppf emails = 220 256 Format.fprintf ppf "@[<v>%a@]"
+54 -4
jmap/jmap-email/jmap_email_query.mli
··· 125 125 (** Enable thread collapsing *) 126 126 val collapse_threads : bool -> query_builder -> query_builder 127 127 128 + (** {1 JSON Generation} *) 129 + 130 + (** Build JSON for Email/query method call. 131 + 132 + Converts a query_builder into the JSON format expected by the 133 + JMAP Email/query method. This is the core function that jmap-unix 134 + uses to construct Email/query requests. 135 + 136 + @param query_builder The query to convert 137 + @return JSON object for Email/query method arguments *) 138 + val build_email_query : query_builder -> Yojson.Safe.t 139 + 140 + (** Convert property presets to string lists. 141 + 142 + Maps property preset enums to their corresponding string lists 143 + for use in Email/get requests. Used internally by jmap-unix 144 + for building method arguments. 145 + 146 + @param preset Property preset to convert 147 + @return List of property strings *) 148 + val property_preset_to_strings : [`ListV | `Preview | `Full | `Threading] -> string list 149 + 150 + (** Build JSON for Email/get method call with result references. 151 + 152 + Creates the JSON for Email/get calls that reference the results of a previous 153 + Email/query call. This is the standard pattern for chained JMAP requests. 154 + 155 + @param account_id Account identifier 156 + @param properties List of property strings to fetch 157 + @param result_of Method call ID to reference (e.g., "q1") 158 + @param method_name Method name being referenced (e.g., "Email/query") 159 + @param path Path to extract from result (e.g., "/ids") 160 + @return JSON object for Email/get method arguments *) 161 + val build_email_get_with_ref : 162 + account_id:string -> 163 + properties:string list -> 164 + result_of:string -> 165 + method_name:string -> 166 + path:string -> 167 + Yojson.Safe.t 168 + 169 + (** Convert property list to string list for Email/get requests. 170 + 171 + Maps property variants to their JMAP protocol string representations. 172 + Used to prepare property lists for Email/get method calls. 173 + 174 + @param properties List of property variants 175 + @return List of property strings *) 176 + val properties_to_strings : property list -> string list 177 + 128 178 (** {1 Execution} *) 129 179 130 180 (** Query result containing email IDs *) ··· 136 186 } 137 187 138 188 (** Query result with full email data *) 139 - type fetch_result = { 140 - emails : Jmap_email.t list; 189 + type 'email fetch_result = { 190 + emails : 'email list; 141 191 total : int option; 142 192 } 143 193 ··· 167 217 (** {1 Pretty Printing} *) 168 218 169 219 (** Pretty-print an email for display *) 170 - val pp_email : Format.formatter -> Jmap_email.t -> unit 220 + val pp_email : Format.formatter -> 'email -> unit 171 221 172 222 (** Pretty-print a list of emails as a summary *) 173 - val pp_email_list : Format.formatter -> Jmap_email.t list -> unit 223 + val pp_email_list : Format.formatter -> 'email list -> unit
+2 -1
jmap/jmap-unix/jmap_unix.ml
··· 18 18 19 19 (* Email-layer imports - using proper jmap-email abstractions *) 20 20 module JmapEmail = Jmap_email 21 - (* module JmapEmailQuery = Jmap_email_query (* Module not available yet *) *) 21 + (* module JmapEmailQuery = Jmap_email_query (* Module interface issue - will implement later *) *) 22 22 23 23 24 24 (* Simple Base64 encoding function *) ··· 1192 1192 | Ok json -> Ok json 1193 1193 | Error e -> Error e) 1194 1194 | Error e -> Error e 1195 + 1195 1196 end 1196 1197 1197 1198 module Email_batch = struct
+1
jmap/jmap-unix/jmap_unix.mli
··· 803 803 session:Jmap.Protocol.Session.Session.t -> 804 804 Yojson.Safe.t -> 805 805 (Yojson.Safe.t, Jmap.Protocol.Error.error) result 806 + 806 807 end 807 808 808 809 (** {2 Email Batch Operations} *)