package tiny_libs
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>
From-scratch libraries for teaching: graphics, audio, compression, crypto, networking and more
Install
dune-project
Dependency
Authors
Maintainers
Sources
0.3.6.tar.gz
md5=7c636383d146d30ac6f2fa234a6253c8
sha512=c79f3823c5f8f57e5038eb640d487c61168b84aa07c61999d6622ef9fd0c890e2b03b4c6a7cdbbe9352a49e25dda00ac7bb14693cee8e3d7beeed251351a2af0
doc/src/tiny_libs.networking_protocols/Pop3.ml.html
Source file Pop3.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89(* Claude Code * * Copyright (C) 2026 Yoann Padioleau * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public License * (LGPL) as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. *) (* See Pop3.mli *) let status (line : string) : (string, string) result option = let after p = String.trim (String.sub line (String.length p) (String.length line - String.length p)) in let starts p = String.length line >= String.length p && String.sub line 0 (String.length p) = p in if starts "+OK" then Some (Ok (after "+OK")) else if starts "-ERR" then Some (Error (after "-ERR")) else None (* the same transparency as SMTP's *) let unstuff = Smtp.unstuff let stuff = Smtp.stuff (*****************************************************************************) (* The client *) (*****************************************************************************) type phase = | Greeting | User | Pass | Stat | Listing of bool (* the status line read: the list's lines follow *) | Retr of int * bool (* the message, and whether its lines follow *) | Dele of int | Quitting | Closed of string option type client = { user : string; pass : string; leave : bool; known : string list; limit : int option; phase : phase; lines : string list; (* a multi-line reply so far, the latest first *) wanted : (int * string) list; (* the messages to fetch, and their uid *) fetched : (string * string) list; (* the latest first *) } let client ~user ~pass ~leave ~known ?limit () = { user; pass; leave; known; limit; phase = Greeting; lines = []; wanted = []; fetched = [] } let say c phase line = ({ c with phase; lines = [] }, [ line ]) let quit c = say c Quitting "QUIT" (* the next message to fetch, or goodbye *) let next c = match c.wanted with (n, _) :: _ -> say c (Retr (n, false)) (Printf.sprintf "RETR %d" n) | [] -> quit c let step (c : client) (line : string) : client * string list = let failed why = say c (Closed (Some why)) "QUIT" in match c.phase with (* inside a multi-line reply: its lines, until the "." *) | Listing true | Retr (_, true) when line <> "." -> ({ c with lines = line :: c.lines }, []) | Listing true -> (* "1 120", or with UIDL "1 whqtswO00WBw418f9t5JxYwZ" *) let items = List.rev c.lines |> List.filter_map (fun l -> match String.split_on_char ' ' l with n :: rest -> Option.map (fun n -> (n, String.concat " " rest)) (int_of_string_opt n) | [] -> None) in let wanted = if c.leave then List.filter (fun (_, uid) -> not (List.mem uid c.known)) items else List.map (fun (n, _) -> (n, "")) items in let wanted = match c.limit with Some k -> List.filteri (fun i _ -> i >= List.length wanted - k) wanted | None -> wanted in next { c with wanted } | Retr (n, true) -> let uid = List.assoc n c.wanted in let c = { c with fetched = (uid, unstuff (List.rev c.lines)) :: c.fetched; wanted = List.remove_assoc n c.wanted } in if c.leave then next c else say c (Dele n) (Printf.sprintf "DELE %d" n) | _ -> ( match (status line, c.phase) with | None, _ -> (c, []) | Some (Error why), Quitting -> ({ c with phase = Closed (Some why) }, []) | Some (Error why), _ -> failed why | Some (Ok _), Greeting -> say c User ("USER " ^ c.user) | Some (Ok _), User -> say c Pass ("PASS " ^ c.pass) | Some (Ok _), Pass -> say c Stat "STAT" | Some (Ok count), Stat -> if String.length count > 0 && count.[0] = '0' then quit c else say c (Listing false) (if c.leave then "UIDL" else "LIST") | Some (Ok _), Listing false -> ({ c with phase = Listing true; lines = [] }, []) | Some (Ok _), Retr (n, false) -> ({ c with phase = Retr (n, true); lines = [] }, []) | Some (Ok _), Dele _ -> next c | Some (Ok _), Quitting -> ({ c with phase = Closed None }, []) | Some (Ok _), _ -> (c, [])) let finished (c : client) : ((string * string) list, string) result option = match c.phase with Closed None -> Some (Ok (List.rev c.fetched)) | Closed (Some why) -> Some (Error why) | _ -> None
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>