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 =
Format.kasprintf (fun _ -> raise Error) fmt
type user_modes = Set.change
let parse_mode_set str ~of_char ~add ~rem ~init =
let rec loop dir acc i =
if i >= String.length str then acc
@ -142,6 +140,17 @@ module Parse = struct
in
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 =
parse_mode_set str
~of_char:of_char_user
@ -157,13 +166,20 @@ module Parse = struct
chan_modes : Set.change;
chan_key : (string, string) 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
| #chan_a -> fail "TODO: + type A modes"
| #chan_b -> fail "TODO: + type B modes"
| #chan_c -> fail "TODO: + type C modes"
| `k ->
(* type B *)
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 ->
let chan_modes = {
Set.add = Set.add m modes.chan_modes.add;
@ -172,9 +188,16 @@ module Parse = struct
args, { modes with chan_modes }
let chan_modes_rem (args, modes) = function
| #chan_a -> fail "TODO: - type A modes"
| #chan_b -> fail "TODO: - type B modes"
| #chan_c -> fail "TODO: - type C modes"
| `k ->
(* type B *)
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 ->
let chan_modes = {
Set.add = Set.remove m modes.chan_modes.add;
@ -187,7 +210,6 @@ module Parse = struct
chan_modes = Set.no_change;
chan_key = None;
chan_limit = None;
chan_priv = [];
} in
let _, modes =
parse_mode_set str
@ -196,7 +218,7 @@ module Parse = struct
~add:chan_modes_add
~rem:chan_modes_rem
in
{ modes with chan_priv = List.rev modes.chan_priv }
modes
end

View File

@ -81,7 +81,7 @@ module Parse : sig
chan_modes : Set.change;
chan_key : (string, string) 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

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 needmoreparams cmd = "461", [cmd; "Not enough parameters"]
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_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;
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* () = if user != me then Error usersdontmatch_get else Ok () in
Ok [
@ -289,12 +320,23 @@ let on_set_user_mode user me modestr _args =
Ok []
let on_get_chan_mode chan _me =
Ok [
"324", [Chan.name chan; Fmt.str "+%a" Irc.Mode.Set.pp (Chan.mode chan)];
(* TODO: +k *)
(* TODO: +l *)
let rpls =[
["324", [Chan.name chan; Fmt.str "+%a" Irc.Mode.Set.pp (Chan.mode chan)]];
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) *)
]
] in
Ok (List.flatten rpls)
let on_set_chan_mode chan me modestr args =
(* 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
in
set_chan_mode chan chg.chan_modes ~from:me;
(* TODO: chg.chan_key *)
(* TODO: chg.chan_limit *)
(* TODO: chg.chan_priv *)
set_chan_mode chan ~from:me chg.chan_modes;
Option.iter (set_chan_key chan ~from:me) chg.chan_key;
Option.iter (set_chan_limit chan ~from:me) chg.chan_limit;
(* TODO: chg.chan_ban/op/voice *)
Ok []

View File

@ -20,9 +20,9 @@ and chan = {
mutable topic : string option;
mutable members : membership Dllist.t;
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: +k *)
(* TODO: +l *)
(* TODO: creation time *)
}
@ -135,6 +135,8 @@ module Chan = struct
topic = None;
members = Dllist.create ();
chan_mode = Irc.Mode.Set.empty;
chan_limit = None;
chan_key = None;
}
let name t = t.name
@ -143,6 +145,10 @@ module Chan = struct
let no_members t = Dllist.is_empty t.members
let mode t = t.chan_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 =
Hashtbl.replace router.channels t.name_key t