use nom::{ branch::alt, bytes::complete::is_not, bytes::complete::tag, character::{ self, complete::{alpha1, multispace1}, }, multi::many_m_n, sequence::preceded, IResult, }; use tracing::trace; use crate::{parser::utils::key_value, Methods, ServerSettings}; fn parse_version(input: &str) -> IResult<&str, Vec> { many_m_n( 1, 5, alt(( character::complete::i32, preceded(character::complete::char('.'), character::complete::i32), )), )(input) } fn parse_methods(input: &str) -> IResult<&str, Vec> { let (rem, res) = many_m_n(1, 10, alt((alpha1, preceded(multispace1, alpha1))))(input)?; let methods = res .into_iter() .map(|m| match m { "PLAIN" => Methods::Plain, "OAUTHBEARER" => Methods::OAuthbearer, any => todo!("That method is not yet implemented: {}", any), }) .collect(); Ok((rem, methods)) } fn parse_extensions(input: &str) -> IResult<&str, Vec> { let space_then_word = preceded(tag(" "), is_not(" ")); let word = is_not(" "); let (rem, res) = many_m_n(1, 200, alt((word, space_then_word)))(input)?; let extensions = res.into_iter().map(|m| m.to_string()).collect(); Ok((rem, extensions)) } pub fn parse_server_config(input: &str) -> IResult<&str, ServerSettings> { let (remain, (_key, implementation)) = key_value(input)?; trace!("Implementation:# {}", implementation); let (remain, (_key, version)) = key_value(remain)?; trace!("{}", version); let (_, version) = parse_version(version)?; trace!("Version:# {:?}", version); let (remain, (_key, sasl)) = key_value(remain)?; trace!("{}", sasl); let (_, sasl) = parse_methods(sasl)?; trace!("SASL:# {:?}", sasl); let (remain, (_key, capabilities)) = key_value(remain)?; trace!("{}", capabilities); let (_, capabilities) = parse_extensions(capabilities)?; trace!("Extensions:# {:?}", &capabilities); let (remain, (_key, notify)) = key_value(remain)?; trace!("{}", notify); let (_, notify) = parse_extensions(remain)?; trace!("Notify:# {:?}", ¬ify); let (remain, (_key, max_redirects)) = key_value(remain)?; trace!("{}", max_redirects); let (_, max_redirects) = character::complete::u32(max_redirects)?; trace!("Max Redirects:# {}", max_redirects); IResult::Ok(( remain, ServerSettings { implementation: implementation.to_string(), version, sasl, capabilities, notify, max_redirects, }, )) }