(* when all you can do is type, making things more complicated than a list is hard? we need to design this somehow before implementing it really the graphical drawing / window management funcitons i think at this point. features: - message drafts? more like, if you send too many messages to someone all at once it will hold them so you can respond later and not flood people....... - i mean really what you want is an editable stream, so you can stage messages for later - because i mean, if this is a bicycle, and you can make it however you want, you can just fuck with the conversation thread with computer assistance instaed of just relying on your memory. *) open Lwt open Lwt_react module F = Fmt module Communicator = struct type msg = {content: string; time: string; mutable seen: bool} let create_msg ?(time = "") content = {content; time; seen= false} type channel = { mutable name: string ; mutable content: msg list ; mutable sender: string -> unit } let add_msg (c : channel) msg = c.content <- msg :: c.content type c = {mutable channel: channel; mutable subs: c list} type protocol = Irc | Email | Rss | Mublog let make_channel (c : c) ?(sender = fun _ -> ()) name = c.subs <- {channel= {name; content= []; sender}; subs= []} :: c.subs let make () : c = let c = { name= "top" ; content= [create_msg "Wecome to the Communicator"] ; sender= (fun _ -> ()) } in c.sender <- (fun s -> c.content <- create_msg s :: c.content) ; c.sender "Currently only IRC is implemented" ; {channel= c; subs= []} type connection = unit Lwt.t module Irc = struct module C = Irc_client_tls module M = Irc_message let connection (c : c) server port nick channels : unit Lwt.t = let add_msg cn str = add_msg cn.channel (create_msg str) in C.reconnect_loop ~after:30 ~connect:(fun () -> Lwt_io.printl "Connecting..." >>= fun () -> C.connect_by_name ~server ~port ~nick () ) ~f:(fun connection -> Lwt_io.printl "Connected" >>= fun () -> Lwt_list.iter_p (fun channel -> let joiner = C.send_join ~connection ~channel in (* make_channel c ~sender:(fun s -> C.send_privmsg ~target:channel ~message:s) channel ; *) joiner ) channels ) ~callback:(fun _connection result -> match result with | Result.Ok ({M.command= M.Other _; _} as msg) -> add_msg c (F.str "Got unknown message: %s\n" (M.to_string msg)) ; Lwt.return_unit | Result.Ok ({M.command= M.PRIVMSG (target, data); _} as msg) -> add_msg c (F.str "Got PRIVMSG: target=%s, data=%s; %s\n" target data (M.to_string msg) ) ; Lwt.return_unit | Result.Ok msg -> add_msg c (M.to_string msg) ; Lwt.return_unit | Result.Error e -> Lwt_io.printl e ) () end module Panel = struct let panel c = Panel.prettyprint ~height:20. ~tag:"Communicator" (fun pp -> F.pf pp " <><><> COMMUNICATOR <><><> @.@." ; List.iter (fun msg -> F.pf pp "[%s] %s@." msg.time msg.content) c.channel.content ) end end let _ = let comm = Communicator.make () in let hackint = Communicator.Irc.connection comm "irc.hackint.org" 6697 "cqcaml" ["#CQC"] in root_actor := std_actor (Communicator.Panel.panel comm) ; Lwt.async (fun () -> hackint) (** program starts... - spawn connections to servers - these connections will populate the Channel.t in a Channel.tree **)