parse and set +k/+l flags

This commit is contained in:
tali 2024-01-20 11:19:29 -05:00
parent 3641f4c773
commit 7372227578
4 changed files with 95 additions and 24 deletions

View File

@ -122,8 +122,6 @@ module Parse = struct
let fail fmt = let fail fmt =
Format.kasprintf (fun _ -> raise Error) fmt Format.kasprintf (fun _ -> raise Error) fmt
type user_modes = Set.change
let parse_mode_set str ~of_char ~add ~rem ~init = let parse_mode_set str ~of_char ~add ~rem ~init =
let rec loop dir acc i = let rec loop dir acc i =
if i >= String.length str then acc if i >= String.length str then acc
@ -142,6 +140,17 @@ module Parse = struct
in in
loop `none init 0 loop `none init 0
let take = function
| [] -> fail "expected argument"
| x :: xs -> x, xs
let take_int = function
| [] -> fail "expected argument"
| x :: xs -> try int_of_string x, xs
with Invalid_argument _ -> fail "invalid integer"
type user_modes = Set.change
let user_modes str = let user_modes str =
parse_mode_set str parse_mode_set str
~of_char:of_char_user ~of_char:of_char_user
@ -157,13 +166,20 @@ module Parse = struct
chan_modes : Set.change; chan_modes : Set.change;
chan_key : (string, string) set_or_unset option; chan_key : (string, string) set_or_unset option;
chan_limit : (int, unit) set_or_unset option; chan_limit : (int, unit) set_or_unset option;
chan_priv : (chan_b * (string, string) set_or_unset) list;
} }
let chan_modes_add (args, modes) = function let chan_modes_add (args, modes) = function
| #chan_a -> fail "TODO: + type A modes" | `k ->
| #chan_b -> fail "TODO: + type B modes" (* type B *)
| #chan_c -> fail "TODO: + type C modes" let key, args = take args in
let chan_key = Some (Set key) in
args, { modes with chan_key }
| `l ->
(* type C *)
let lim, args = take_int args in
let chan_limit = Some (Set lim) in
args, { modes with chan_limit }
| `b | `o | `v -> fail "TODO: + ban/op/voice"
| #chan_d as m -> | #chan_d as m ->
let chan_modes = { let chan_modes = {
Set.add = Set.add m modes.chan_modes.add; Set.add = Set.add m modes.chan_modes.add;
@ -172,9 +188,16 @@ module Parse = struct
args, { modes with chan_modes } args, { modes with chan_modes }
let chan_modes_rem (args, modes) = function let chan_modes_rem (args, modes) = function
| #chan_a -> fail "TODO: - type A modes" | `k ->
| #chan_b -> fail "TODO: - type B modes" (* type B *)
| #chan_c -> fail "TODO: - type C modes" let key, args = take args in
let chan_key = Some (Unset key) in
args, { modes with chan_key }
| `l ->
(* type C *)
let chan_limit = Some (Unset ()) in
args, { modes with chan_limit }
| `b | `o | `v -> fail "TODO: - ban/op/voice"
| #chan_d as m -> | #chan_d as m ->
let chan_modes = { let chan_modes = {
Set.add = Set.remove m modes.chan_modes.add; Set.add = Set.remove m modes.chan_modes.add;
@ -187,7 +210,6 @@ module Parse = struct
chan_modes = Set.no_change; chan_modes = Set.no_change;
chan_key = None; chan_key = None;
chan_limit = None; chan_limit = None;
chan_priv = [];
} in } in
let _, modes = let _, modes =
parse_mode_set str parse_mode_set str
@ -196,7 +218,7 @@ module Parse = struct
~add:chan_modes_add ~add:chan_modes_add
~rem:chan_modes_rem ~rem:chan_modes_rem
in in
{ modes with chan_priv = List.rev modes.chan_priv } modes
end end

View File

@ -81,7 +81,7 @@ module Parse : sig
chan_modes : Set.change; chan_modes : Set.change;
chan_key : (string, string) set_or_unset option; chan_key : (string, string) set_or_unset option;
chan_limit : (int, unit) set_or_unset option; chan_limit : (int, unit) set_or_unset option;
chan_priv : (chan_b * (string, string) set_or_unset) list; (* TODO: bad, op, voice *)
} }
val user_modes : string -> user_modes val user_modes : string -> user_modes

View File

@ -74,7 +74,7 @@ let notonchannel chan = "442", [chan; "You're not on that channel"]
let notregistered = "451", ["You have not registered"] let notregistered = "451", ["You have not registered"]
let needmoreparams cmd = "461", [cmd; "Not enough parameters"] let needmoreparams cmd = "461", [cmd; "Not enough parameters"]
let alreadyregistered = "462", ["Unauthorized command (already registered)"] let alreadyregistered = "462", ["Unauthorized command (already registered)"]
let modeunknownflag = "501", ["Unknown MODE flag"] let modeunknownflag = "501", ["Didn't understand MODE command"]
let usersdontmatch_set = "502", ["Can't change mode for other users"] let usersdontmatch_set = "502", ["Can't change mode for other users"]
let usersdontmatch_get = "502", ["Can't view mode for other users"] let usersdontmatch_get = "502", ["Can't view mode for other users"]
@ -270,6 +270,37 @@ let set_chan_mode chan ~from chg =
Chan.set_mode chan mode; Chan.set_mode chan mode;
end end
let set_chan_key chan ~from = function
| Irc.Mode.Parse.Set key ->
let msg = Irc.Msg.make "MODE" [Chan.name chan; "+k"; key] ~always_trailing:true in
begin
Router.relay msg ~from [`to_chan chan; `to_self];
Chan.set_key chan (Some key);
end
| Irc.Mode.Parse.Unset _key ->
if Chan.key chan <> None then
let msg = Irc.Msg.make "MODE" [Chan.name chan; "-k"; "*"] in
begin
Router.relay msg ~from [`to_chan chan; `to_self];
Chan.set_key chan None;
end
let set_chan_limit chan ~from = function
| Irc.Mode.Parse.Set lim ->
if Chan.limit chan <> Some lim then
let msg = Irc.Msg.make "MODE" [Chan.name chan; "+l"; string_of_int lim] in
begin
Router.relay msg ~from [`to_chan chan; `to_self];
Chan.set_limit chan (Some lim);
end
| Irc.Mode.Parse.Unset () ->
if Chan.limit chan <> None then
let msg = Irc.Msg.make "MODE" [Chan.name chan; "-l"] in
begin
Router.relay msg ~from [`to_chan chan; `to_self];
Chan.set_limit chan None;
end
let on_get_user_mode user me = let on_get_user_mode user me =
let* () = if user != me then Error usersdontmatch_get else Ok () in let* () = if user != me then Error usersdontmatch_get else Ok () in
Ok [ Ok [
@ -289,12 +320,23 @@ let on_set_user_mode user me modestr _args =
Ok [] Ok []
let on_get_chan_mode chan _me = let on_get_chan_mode chan _me =
Ok [ let rpls =[
"324", [Chan.name chan; Fmt.str "+%a" Irc.Mode.Set.pp (Chan.mode chan)]; ["324", [Chan.name chan; Fmt.str "+%a" Irc.Mode.Set.pp (Chan.mode chan)]];
(* TODO: +k *)
(* TODO: +l *) begin match Chan.limit chan with
| Some lim -> ["324", [Chan.name chan; "+l"; string_of_int lim]]
| None -> []
end;
(* TODO: only display key if priveledged enough to see it *)
begin match Chan.key chan with
| Some key -> ["324", [Chan.name chan; "+k"; key]]
| None -> []
end;
(* TODO: RPL_CREATIONTIME (329) *) (* TODO: RPL_CREATIONTIME (329) *)
] ] in
Ok (List.flatten rpls)
let on_set_chan_mode chan me modestr args = let on_set_chan_mode chan me modestr args =
(* TODO: If <modestring> is given, the user sending the command MUST have appropriate (* TODO: If <modestring> is given, the user sending the command MUST have appropriate
@ -311,10 +353,11 @@ let on_set_chan_mode chan me modestr args =
Error modeunknownflag Error modeunknownflag
in in
set_chan_mode chan chg.chan_modes ~from:me; set_chan_mode chan ~from:me chg.chan_modes;
(* TODO: chg.chan_key *) Option.iter (set_chan_key chan ~from:me) chg.chan_key;
(* TODO: chg.chan_limit *) Option.iter (set_chan_limit chan ~from:me) chg.chan_limit;
(* TODO: chg.chan_priv *)
(* TODO: chg.chan_ban/op/voice *)
Ok [] Ok []

View File

@ -20,9 +20,9 @@ and chan = {
mutable topic : string option; mutable topic : string option;
mutable members : membership Dllist.t; mutable members : membership Dllist.t;
mutable chan_mode : Irc.Mode.Set.t; (* +imstn *) mutable chan_mode : Irc.Mode.Set.t; (* +imstn *)
mutable chan_limit : int option; (* +l *)
mutable chan_key : string option; (* +k *)
(* TODO: +b, +o, +v *) (* TODO: +b, +o, +v *)
(* TODO: +k *)
(* TODO: +l *)
(* TODO: creation time *) (* TODO: creation time *)
} }
@ -135,6 +135,8 @@ module Chan = struct
topic = None; topic = None;
members = Dllist.create (); members = Dllist.create ();
chan_mode = Irc.Mode.Set.empty; chan_mode = Irc.Mode.Set.empty;
chan_limit = None;
chan_key = None;
} }
let name t = t.name let name t = t.name
@ -143,6 +145,10 @@ module Chan = struct
let no_members t = Dllist.is_empty t.members let no_members t = Dllist.is_empty t.members
let mode t = t.chan_mode let mode t = t.chan_mode
let set_mode t new_mode = t.chan_mode <- new_mode let set_mode t new_mode = t.chan_mode <- new_mode
let limit t = t.chan_limit
let set_limit t n = t.chan_limit <- n
let key t = t.chan_key
let set_key t k = t.chan_key <- k
let register t ~router = let register t ~router =
Hashtbl.replace router.channels t.name_key t Hashtbl.replace router.channels t.name_key t