forked from
anil.recoil.org/ocaml-imap
IMAP in OCaml
1(*---------------------------------------------------------------------------
2 Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved.
3 SPDX-License-Identifier: ISC
4 ---------------------------------------------------------------------------*)
5
6(** IMAP Client Errors
7
8 Error types for IMAP client operations, integrated with Eio's exception
9 handling. *)
10
11(** {1 Error Types} *)
12
13type t =
14 | Connection_error of { reason : string }
15 | Protocol_error of { code : Code.t option; text : string }
16 | Parse_error of { reason : string; data : string option }
17 | State_error of { expected : string; actual : string }
18 | Timeout of { operation : string }
19 | Capability_missing of { capability : string }
20 | Authentication_error of { mechanism : string; reason : string }
21
22(** {1 Pretty Printing} *)
23
24let pp ppf = function
25 | Connection_error { reason } -> Fmt.pf ppf "Connection error: %s" reason
26 | Protocol_error { code; text } ->
27 let code_str = Option.fold ~none:"" ~some:(Fmt.str " [%a]" Code.pp) code in
28 Fmt.pf ppf "Protocol error%s: %s" code_str text
29 | Parse_error { reason; data } ->
30 let truncate d = if String.length d > 50 then String.sub d 0 50 ^ "..." else d in
31 let suffix = Option.fold ~none:"" ~some:(fun d -> Fmt.str " (near: %s)" (truncate d)) data in
32 Fmt.pf ppf "Parse error: %s%s" reason suffix
33 | State_error { expected; actual } ->
34 Fmt.pf ppf "State error: expected %s, got %s" expected actual
35 | Timeout { operation } -> Fmt.pf ppf "Timeout: %s" operation
36 | Capability_missing { capability } ->
37 Fmt.pf ppf "Capability missing: %s" capability
38 | Authentication_error { mechanism; reason } ->
39 Fmt.pf ppf "Authentication error (%s): %s" mechanism reason
40
41let to_string e = Fmt.str "%a" pp e
42
43(** {1 Eio Integration} *)
44
45type Eio.Exn.err += E of t
46
47let () =
48 Eio.Exn.register_pp (fun ppf exn ->
49 match exn with
50 | E e ->
51 pp ppf e;
52 true
53 | _ -> false)
54
55let err e = Eio.Exn.create (E e)
56let raise e = Stdlib.raise (err e)
57
58let of_eio_exn = function
59 | Eio.Exn.Io (E e, _) -> Some e
60 | _ -> None
61
62(** {1 Error Classification} *)
63
64let is_retryable = function
65 | Connection_error _ | Timeout _ -> true
66 | Protocol_error { code = Some Code.Unavailable; _ } -> true
67 | _ -> false
68
69let is_auth_error = function
70 | Protocol_error { code = Some Code.Authenticationfailed; _ } -> true
71 | Protocol_error { code = Some Code.Authorizationfailed; _ } -> true
72 | Authentication_error _ -> true
73 | _ -> false
74
75let is_state_error = function State_error _ -> true | _ -> false