IMAP in OCaml
at main 86 lines 3.6 kB view raw
1(*--------------------------------------------------------------------------- 2 Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved. 3 SPDX-License-Identifier: ISC 4 ---------------------------------------------------------------------------*) 5 6(** {1 RFC 5256 THREAD Extension} 7 8 Message threading algorithms as specified in 9 {{:https://datatracker.ietf.org/doc/html/rfc5256}RFC 5256 Section 3}. 10 11 The THREAD command allows clients to retrieve messages organized into 12 conversation threads based on message relationships. *) 13 14(** {1 Threading Algorithms} 15 16 RFC 5256 Section 3 defines two threading algorithms. Servers MUST 17 implement at least ORDEREDSUBJECT and SHOULD implement REFERENCES. *) 18 19(** Threading algorithm used to organize messages into threads. 20 21 @rfc 5256 Section 3 *) 22type algorithm = 23 | Orderedsubject 24 (** ORDEREDSUBJECT algorithm (RFC 5256 Section 3.1). 25 Groups messages by base subject (stripping Re:/Fwd: prefixes), 26 then sorts each group by sent date. Simple but effective for 27 basic threading. *) 28 | References 29 (** REFERENCES algorithm (RFC 5256 Section 3.2). 30 Implements the JWZ threading algorithm using Message-ID, 31 In-Reply-To, and References headers to build a complete 32 parent/child thread tree. More accurate than ORDEREDSUBJECT 33 but computationally more expensive. *) 34 | Extension of string 35 (** Future algorithm extensions. Servers may advertise additional 36 threading algorithms via the THREAD capability. *) 37 38(** {1 Thread Result Structure} 39 40 Thread results form a forest of trees. Each tree represents a 41 conversation thread, with messages as nodes. *) 42 43(** A thread node in the result tree. 44 45 Thread responses use a nested parenthesized structure where each 46 message may have zero or more child messages (replies). 47 48 @rfc 5256 Section 4 *) 49type 'a node = 50 | Message of 'a * 'a node list 51 (** A message with its sequence number or UID (depending on whether 52 UID THREAD was used) and a list of child messages (replies). 53 The children are ordered by the threading algorithm. *) 54 | Dummy of 'a node list 55 (** A placeholder for a missing parent message. This occurs when 56 replies reference a message that is not in the search results 57 (e.g., it was deleted or not matched by the search criteria). 58 The REFERENCES algorithm may produce dummy nodes to maintain 59 thread structure. *) 60 61(** Thread result: a list of root-level thread trees. 62 63 Each element is a top-level thread. The threads are ordered according 64 to the threading algorithm (typically by date of the first message 65 in each thread). 66 67 @rfc 5256 Section 4 *) 68type 'a t = 'a node list 69 70(** {1 Pretty Printers} *) 71 72val pp_algorithm : Format.formatter -> algorithm -> unit 73(** [pp_algorithm ppf alg] prints the algorithm name in IMAP wire format. *) 74 75val algorithm_to_string : algorithm -> string 76(** [algorithm_to_string alg] returns the algorithm name as a string. *) 77 78val algorithm_of_string : string -> algorithm 79(** [algorithm_of_string s] parses an algorithm name from a string. 80 Unrecognized names are returned as [Extension s]. *) 81 82val pp_node : (Format.formatter -> 'a -> unit) -> Format.formatter -> 'a node -> unit 83(** [pp_node pp_elt ppf node] prints a thread node using [pp_elt] for elements. *) 84 85val pp : (Format.formatter -> 'a -> unit) -> Format.formatter -> 'a t -> unit 86(** [pp pp_elt ppf threads] prints a thread result using [pp_elt] for elements. *)