use std::io;
use std::path::Path;
use buffered_reader::BufferedReader;
use crate::Result;
use crate::parse::PacketParserResult;
use crate::parse::PacketParser;
use crate::parse::PacketParserEOF;
use crate::parse::PacketParserState;
use crate::parse::PacketParserSettings;
use crate::parse::ParserResult;
use crate::parse::Parse;
use crate::parse::Cookie;
use crate::armor;
use crate::packet;
#[derive(PartialEq)]
pub enum Dearmor {
Enabled(armor::ReaderMode),
Disabled,
Auto(armor::ReaderMode),
}
assert_send_and_sync!(Dearmor);
impl Default for Dearmor {
fn default() -> Self {
Dearmor::Auto(Default::default())
}
}
pub(super) const ARMOR_READER_LEVEL: isize = -2;
pub struct PacketParserBuilder<'a> {
bio: Box<dyn BufferedReader<Cookie> + 'a>,
dearmor: Dearmor,
settings: PacketParserSettings,
}
assert_send_and_sync!(PacketParserBuilder<'_>);
impl<'a> Parse<'a, PacketParserBuilder<'a>> for PacketParserBuilder<'a> {
fn from_reader<R: io::Read + 'a + Send + Sync>(reader: R) -> Result<Self> {
PacketParserBuilder::from_buffered_reader(
Box::new(buffered_reader::Generic::with_cookie(
reader, None, Cookie::default())))
}
fn from_file<P: AsRef<Path>>(path: P) -> Result<Self> {
PacketParserBuilder::from_buffered_reader(
Box::new(buffered_reader::File::with_cookie(path, Cookie::default())?))
}
fn from_bytes<D: AsRef<[u8]> + ?Sized>(data: &'a D) -> Result<PacketParserBuilder<'a>> {
PacketParserBuilder::from_buffered_reader(
Box::new(buffered_reader::Memory::with_cookie(
data.as_ref(), Cookie::default())))
}
}
impl<'a> PacketParserBuilder<'a> {
pub(crate) fn from_buffered_reader(mut bio: Box<dyn BufferedReader<Cookie> + 'a>)
-> Result<Self> {
bio.cookie_mut().level = None;
Ok(PacketParserBuilder {
bio: bio,
dearmor: Default::default(),
settings: PacketParserSettings::default(),
})
}
pub fn max_recursion_depth(mut self, value: u8) -> Self {
self.settings.max_recursion_depth = value;
self
}
pub fn max_packet_size(mut self, value: u32) -> Self {
self.settings.max_packet_size = value;
self
}
pub fn buffer_unread_content(mut self) -> Self {
self.settings.buffer_unread_content = true;
self
}
pub fn drop_unread_content(mut self) -> Self {
self.settings.buffer_unread_content = false;
self
}
pub fn map(mut self, enable: bool) -> Self {
self.settings.map = enable;
self
}
pub fn dearmor(mut self, mode: Dearmor) -> Self {
self.dearmor = mode;
self
}
pub fn build(mut self)
-> Result<PacketParserResult<'a>>
where Self: 'a
{
let state = PacketParserState::new(self.settings);
let dearmor_mode = match self.dearmor {
Dearmor::Enabled(mode) => Some(mode),
Dearmor::Disabled => None,
Dearmor::Auto(mode) => {
if self.bio.eof() {
None
} else {
let mut reader = buffered_reader::Dup::with_cookie(
self.bio, Cookie::default());
let header = packet::Header::parse(&mut reader);
self.bio = Box::new(reader).into_inner().unwrap();
if let Ok(header) = header {
if let Err(_) = header.valid(false) {
Some(mode)
} else {
None
}
} else {
Some(mode)
}
}
}
};
if let Some(mode) = dearmor_mode {
self.bio =
armor::Reader::from_buffered_reader(self.bio, Some(mode),
Cookie::new(ARMOR_READER_LEVEL))
.as_boxed();
}
match PacketParser::parse(Box::new(self.bio), state, vec![ 0 ])? {
ParserResult::Success(mut pp) => {
pp.state.message_validator.push(pp.packet.tag(), &[0]);
pp.state.keyring_validator.push(pp.packet.tag());
pp.state.cert_validator.push(pp.packet.tag());
Ok(PacketParserResult::Some(pp))
},
ParserResult::EOF((reader, state, _path)) => {
Ok(PacketParserResult::EOF(PacketParserEOF::new(state, reader)))
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn armor() {
let msg = crate::tests::message("sig.gpg");
let ppr = PacketParserBuilder::from_bytes(msg).unwrap()
.dearmor(Dearmor::Disabled)
.build();
assert_match!(Ok(PacketParserResult::Some(ref _pp)) = ppr);
let ppr = PacketParserBuilder::from_bytes(msg).unwrap()
.dearmor(Dearmor::Auto(Default::default()))
.build();
assert_match!(Ok(PacketParserResult::Some(ref _pp)) = ppr);
let ppr = PacketParserBuilder::from_bytes(msg).unwrap()
.dearmor(Dearmor::Enabled(Default::default()))
.build();
assert_match!(Err(_) = ppr);
let msg = crate::tests::message("a-cypherpunks-manifesto.txt.ed25519.sig");
let ppr = PacketParserBuilder::from_bytes(msg).unwrap()
.dearmor(Dearmor::Disabled)
.build();
assert_match!(Err(_) = ppr);
let ppr = PacketParserBuilder::from_bytes(msg).unwrap()
.dearmor(Dearmor::Auto(Default::default()))
.build();
assert_match!(Ok(PacketParserResult::Some(ref _pp)) = ppr);
let ppr = PacketParserBuilder::from_bytes(msg).unwrap()
.dearmor(Dearmor::Enabled(Default::default()))
.build();
assert_match!(Ok(PacketParserResult::Some(ref _pp)) = ppr);
}
}