use std::num::NonZeroU32;
use abnf_core::streaming::SP;
use imap_types::{
core::NonEmptyVec,
fetch_attributes::{FetchAttribute, FetchAttributeValue},
};
use nom::{
branch::alt,
bytes::streaming::{tag, tag_no_case},
combinator::{map, opt, value},
multi::separated_list1,
sequence::{delimited, tuple},
IResult,
};
use crate::rfc3501::{
body::body,
core::{nstring, number, nz_number},
datetime::date_time,
envelope::envelope,
flag::flag_fetch,
section::section,
};
pub fn fetch_att(input: &[u8]) -> IResult<&[u8], FetchAttribute> {
alt((
value(FetchAttribute::Envelope, tag_no_case(b"ENVELOPE")),
value(FetchAttribute::Flags, tag_no_case(b"FLAGS")),
value(FetchAttribute::InternalDate, tag_no_case(b"INTERNALDATE")),
value(FetchAttribute::BodyStructure, tag_no_case(b"BODYSTRUCTURE")),
map(
tuple((
tag_no_case(b"BODY.PEEK"),
section,
opt(delimited(
tag(b"<"),
tuple((number, tag(b"."), nz_number)),
tag(b">"),
)),
)),
|(_, section, byterange)| FetchAttribute::BodyExt {
section,
partial: byterange.map(|(start, _, end)| (start, end)),
peek: true,
},
),
map(
tuple((
tag_no_case(b"BODY"),
section,
opt(delimited(
tag(b"<"),
tuple((number, tag(b"."), nz_number)),
tag(b">"),
)),
)),
|(_, section, byterange)| FetchAttribute::BodyExt {
section,
partial: byterange.map(|(start, _, end)| (start, end)),
peek: false,
},
),
value(FetchAttribute::Body, tag_no_case(b"BODY")),
value(FetchAttribute::Uid, tag_no_case(b"UID")),
value(FetchAttribute::Rfc822Header, tag_no_case(b"RFC822.HEADER")),
value(FetchAttribute::Rfc822Size, tag_no_case(b"RFC822.SIZE")),
value(FetchAttribute::Rfc822Text, tag_no_case(b"RFC822.TEXT")),
value(FetchAttribute::Rfc822, tag_no_case(b"RFC822")),
))(input)
}
pub fn msg_att(input: &[u8]) -> IResult<&[u8], NonEmptyVec<FetchAttributeValue>> {
delimited(
tag(b"("),
map(
separated_list1(SP, alt((msg_att_dynamic, msg_att_static))),
|attrs| unsafe { NonEmptyVec::new_unchecked(attrs) },
),
tag(b")"),
)(input)
}
pub fn msg_att_dynamic(input: &[u8]) -> IResult<&[u8], FetchAttributeValue> {
let mut parser = tuple((
tag_no_case(b"FLAGS"),
SP,
delimited(tag(b"("), opt(separated_list1(SP, flag_fetch)), tag(b")")),
));
let (remaining, (_, _, flags)) = parser(input)?;
Ok((
remaining,
FetchAttributeValue::Flags(flags.unwrap_or_default()),
))
}
pub fn msg_att_static(input: &[u8]) -> IResult<&[u8], FetchAttributeValue> {
alt((
map(
tuple((tag_no_case(b"ENVELOPE"), SP, envelope)),
|(_, _, envelope)| FetchAttributeValue::Envelope(envelope),
),
map(
tuple((tag_no_case(b"INTERNALDATE"), SP, date_time)),
|(_, _, date_time)| FetchAttributeValue::InternalDate(date_time),
),
alt((
map(
tuple((tag_no_case(b"RFC822.HEADER"), SP, nstring)),
|(_, _, nstring)| FetchAttributeValue::Rfc822Header(nstring),
),
map(
tuple((tag_no_case(b"RFC822.TEXT"), SP, nstring)),
|(_, _, nstring)| FetchAttributeValue::Rfc822Text(nstring),
),
map(
tuple((tag_no_case(b"RFC822"), SP, nstring)),
|(_, _, nstring)| FetchAttributeValue::Rfc822(nstring),
),
)),
map(
tuple((tag_no_case(b"RFC822.SIZE"), SP, number)),
|(_, _, num)| FetchAttributeValue::Rfc822Size(num),
),
alt((
map(
tuple((tag_no_case(b"BODYSTRUCTURE"), SP, body(8))),
|(_, _, body)| FetchAttributeValue::BodyStructure(body),
),
map(
tuple((tag_no_case(b"BODY"), SP, body(8))),
|(_, _, body)| FetchAttributeValue::Body(body),
),
)),
map(
tuple((
tag_no_case(b"BODY"),
section,
opt(delimited(tag(b"<"), number, tag(b">"))),
SP,
nstring,
)),
|(_, section, origin, _, data)| FetchAttributeValue::BodyExt {
section,
origin,
data,
},
),
map(tuple((tag_no_case(b"UID"), SP, uniqueid)), |(_, _, uid)| {
FetchAttributeValue::Uid(uid)
}),
))(input)
}
#[inline]
pub fn uniqueid(input: &[u8]) -> IResult<&[u8], NonZeroU32> {
nz_number(input)
}