this repo has no description

fixes

Changed files
+64 -15
bin
+1
.gitignore
··· 1 1 _build 2 2 .env 3 + .api-key
+63 -15
bin/jmap_test.ml
··· 5 5 6 6 (** JMAP test client - connects to a JMAP server and queries recent emails *) 7 7 8 + let ptime_to_string t = 9 + let (y, m, d), ((hh, mm, ss), _tz) = Ptime.to_date_time t in 10 + Printf.sprintf "%04d-%02d-%02d %02d:%02d:%02d" y m d hh mm ss 11 + 12 + let debug_mode = ref false 13 + 14 + let debug fmt = 15 + if !debug_mode then 16 + Printf.kfprintf (fun oc -> Printf.fprintf oc "\n%!") stderr ("[DEBUG] " ^^ fmt) 17 + else 18 + Printf.ifprintf stderr fmt 19 + 8 20 let () = 9 21 (* Parse command line arguments *) 10 - let usage = "Usage: jmap-test <session-url> <api-key>" in 22 + let usage = "Usage: jmap-test [--debug] <session-url> <api-key>" in 11 23 let args = ref [] in 12 - Arg.parse [] (fun arg -> args := arg :: !args) usage; 24 + let spec = [ 25 + ("--debug", Arg.Set debug_mode, "Enable debug output"); 26 + ("-d", Arg.Set debug_mode, "Enable debug output"); 27 + ] in 28 + Arg.parse spec (fun arg -> args := arg :: !args) usage; 13 29 let session_url, api_key = 14 30 match List.rev !args with 15 31 | [url; key] -> (url, key) ··· 18 34 exit 1 19 35 in 20 36 37 + debug "Session URL: %s" session_url; 38 + debug "API key length: %d chars" (String.length api_key); 39 + 21 40 (* Run with Eio *) 22 41 Eio_main.run @@ fun env -> 23 42 Eio.Switch.run @@ fun sw -> ··· 26 45 let requests = Requests.create ~sw env in 27 46 let auth = Requests.Auth.bearer ~token:api_key in 28 47 48 + debug "Created HTTP client with Bearer auth"; 29 49 Printf.printf "Connecting to %s...\n%!" session_url; 30 50 31 51 (* Create JMAP client from session URL *) ··· 35 55 exit 1 36 56 | Ok client -> 37 57 let session = Jmap_eio.Client.session client in 38 - Printf.printf "Connected! Username: %s\n%!" (Jmap_proto.Session.username session); 58 + debug "Session state: %s" session.state; 59 + debug "API URL: %s" session.api_url; 60 + debug "Upload URL: %s" session.upload_url; 61 + debug "Download URL: %s" session.download_url; 62 + debug "Capabilities: %s" (String.concat ", " (List.map fst session.capabilities)); 63 + debug "Accounts: %d" (List.length session.accounts); 64 + List.iter (fun (id, acct) -> 65 + debug " Account %s: %s (personal=%b, read_only=%b)" 66 + (Jmap_proto.Id.to_string id) 67 + acct.Jmap_proto.Session.Account.name 68 + acct.is_personal 69 + acct.is_read_only 70 + ) session.accounts; 71 + Printf.printf "Connected! Username: %s\n%!" session.username; 39 72 40 73 (* Get primary mail account *) 41 74 let primary_account_id = ··· 45 78 prerr_endline "No primary mail account found"; 46 79 exit 1 47 80 in 81 + debug "Primary accounts: %s" 82 + (String.concat ", " (List.map (fun (cap, id) -> 83 + cap ^ "=" ^ Jmap_proto.Id.to_string id) session.primary_accounts)); 48 84 Printf.printf "Primary mail account: %s\n%!" (Jmap_proto.Id.to_string primary_account_id); 49 85 50 86 (* Query for recent emails - get the 10 most recent *) ··· 63 99 [query_inv] 64 100 in 65 101 102 + debug "Built Email/query request with sort by receivedAt desc, limit 10"; 66 103 Printf.printf "Querying recent emails...\n%!"; 67 104 68 105 match Jmap_eio.Client.request client req with ··· 70 107 Printf.eprintf "Query failed: %s\n" (Jmap_eio.Client.error_to_string e); 71 108 exit 1 72 109 | Ok response -> 110 + debug "Query response received, parsing..."; 73 111 (* Parse the query response *) 74 112 match Jmap_eio.Client.Parse.parse_email_query ~call_id:"q1" response with 75 113 | Error e -> ··· 77 115 exit 1 78 116 | Ok query_result -> 79 117 let email_ids = query_result.ids in 118 + debug "Query state: %s" query_result.query_state; 119 + debug "Can calculate updates: %b" query_result.can_calculate_changes; 120 + debug "Total results: %Ld" (Option.value query_result.total ~default:(-1L)); 121 + debug "Position: %Ld" query_result.position; 122 + debug "Email IDs: %s" 123 + (String.concat ", " (List.map Jmap_proto.Id.to_string email_ids)); 80 124 Printf.printf "Found %d emails\n%!" (List.length email_ids); 81 125 82 126 if List.length email_ids = 0 then ( 83 127 Printf.printf "No emails found.\n%!"; 84 128 ) else ( 85 - (* Fetch the email details *) 129 + (* Fetch the email details - must include required properties *) 86 130 let get_inv = Jmap_eio.Client.Build.email_get 87 131 ~call_id:"g1" 88 132 ~account_id:primary_account_id 89 133 ~ids:email_ids 90 - ~properties:["id"; "subject"; "from"; "receivedAt"; "preview"] 134 + ~properties:["id"; "blobId"; "threadId"; "mailboxIds"; "size"; 135 + "receivedAt"; "subject"; "from"; "preview"] 91 136 () 92 137 in 93 138 ··· 96 141 [get_inv] 97 142 in 98 143 144 + debug "Built Email/get request for %d emails" (List.length email_ids); 99 145 Printf.printf "Fetching email details...\n%!"; 100 146 101 147 match Jmap_eio.Client.request client req2 with ··· 103 149 Printf.eprintf "Get failed: %s\n" (Jmap_eio.Client.error_to_string e); 104 150 exit 1 105 151 | Ok response2 -> 152 + debug "Get response received, parsing..."; 106 153 match Jmap_eio.Client.Parse.parse_email_get ~call_id:"g1" response2 with 107 154 | Error e -> 108 155 Printf.eprintf "Failed to parse get response: %s\n" (Jsont.Error.to_string e); 109 156 exit 1 110 157 | Ok get_result -> 158 + debug "Get state: %s" get_result.state; 159 + debug "Emails returned: %d" (List.length get_result.list); 160 + debug "Not found: %d" (List.length get_result.not_found); 111 161 Printf.printf "\n=== Recent Emails ===\n\n%!"; 112 - List.iter (fun email -> 113 - let id = Jmap_proto.Id.to_string (Jmap_mail.Email.id email) in 114 - let subject = Option.value (Jmap_mail.Email.subject email) ~default:"(no subject)" in 115 - let from_addrs = Option.value (Jmap_mail.Email.from email) ~default:[] in 162 + List.iter (fun (email : Jmap_mail.Email.t) -> 163 + let id = Jmap_proto.Id.to_string email.id in 164 + let subject = Option.value email.subject ~default:"(no subject)" in 165 + let from_addrs = Option.value email.from ~default:[] in 116 166 let from_str = match from_addrs with 117 167 | [] -> "(unknown sender)" 118 168 | addr :: _ -> 119 - let name = Option.value (Jmap_mail.Email_address.name addr) ~default:"" in 120 - let email_addr = Jmap_mail.Email_address.email addr in 169 + let name = Option.value addr.name ~default:"" in 170 + let email_addr = addr.email in 121 171 if name = "" then email_addr 122 172 else Printf.sprintf "%s <%s>" name email_addr 123 173 in 124 - let received = 125 - Jmap_proto.Date.Utc.to_string (Jmap_mail.Email.received_at email) 126 - in 127 - let preview = Jmap_mail.Email.preview email in 174 + let received = ptime_to_string email.received_at in 175 + let preview = email.preview in 128 176 let preview_short = 129 177 if String.length preview > 80 then 130 178 String.sub preview 0 77 ^ "..."