use std::io;
use std::path::Path;
use buffered_reader::BufferedReader;
use Result;
use parse::PacketParserResult;
use parse::PacketParser;
use parse::PacketParserEOF;
use parse::PacketParserState;
use parse::PacketParserSettings;
use parse::ParserResult;
use parse::Parse;
use parse::Cookie;
use armor;
use packet;
#[derive(PartialEq)]
pub enum Dearmor {
Enabled,
Disabled,
Auto,
}
pub struct PacketParserBuilder<'a> {
bio: Box<'a + BufferedReader<Cookie>>,
dearmor: Dearmor,
settings: PacketParserSettings,
}
impl<'a> Parse<'a, PacketParserBuilder<'a>> for PacketParserBuilder<'a> {
fn from_reader<R: io::Read + 'a>(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(bytes: &'a [u8]) -> Result<PacketParserBuilder> {
PacketParserBuilder::from_buffered_reader(
Box::new(buffered_reader::Memory::with_cookie(
bytes, Cookie::default())))
}
}
impl<'a> PacketParserBuilder<'a> {
pub(crate) fn from_buffered_reader(mut bio: Box<'a + BufferedReader<Cookie>>)
-> Result<Self> {
bio.cookie_mut().level = None;
Ok(PacketParserBuilder {
bio: bio,
dearmor: Dearmor::Auto,
settings: PacketParserSettings::default(),
})
}
pub fn max_recursion_depth(mut self, value: u8) -> Self {
self.settings.max_recursion_depth = 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 finalize(mut self)
-> Result<PacketParserResult<'a>>
where Self: 'a
{
let state = PacketParserState::new(self.settings);
let dearmor = match self.dearmor {
Dearmor::Enabled => true,
Dearmor::Disabled => false,
Dearmor::Auto => {
if let Err(_) = packet::Header::plausible(&mut self.bio) {
true
} else {
false
}
}
};
if dearmor {
self.bio = Box::new(buffered_reader::Generic::with_cookie(
armor::Reader::from_buffered_reader(self.bio, None),
None,
Default::default()));
}
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.tpk_validator.push(pp.packet.tag());
Ok(PacketParserResult::Some(pp))
},
ParserResult::EOF((_reader, state, _path)) => {
Ok(PacketParserResult::EOF(PacketParserEOF::new(state)))
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
macro_rules! bytes {
( $x:expr ) => { include_bytes!(concat!("../../tests/data/messages/", $x)) };
}
#[test]
fn armor() {
let msg = bytes!("sig.gpg");
let ppr = PacketParserBuilder::from_bytes(msg).unwrap()
.dearmor(Dearmor::Disabled)
.finalize();
assert_match!(Ok(PacketParserResult::Some(ref _pp)) = ppr);
let ppr = PacketParserBuilder::from_bytes(msg).unwrap()
.dearmor(Dearmor::Auto)
.finalize();
assert_match!(Ok(PacketParserResult::Some(ref _pp)) = ppr);
let ppr = PacketParserBuilder::from_bytes(msg).unwrap()
.dearmor(Dearmor::Enabled)
.finalize();
assert_match!(Ok(PacketParserResult::EOF(ref _pp)) = ppr);
let msg = bytes!("a-cypherpunks-manifesto.txt.ed25519.sig");
let ppr = PacketParserBuilder::from_bytes(msg).unwrap()
.dearmor(Dearmor::Disabled)
.finalize();
assert_match!(Err(_) = ppr);
let ppr = PacketParserBuilder::from_bytes(msg).unwrap()
.dearmor(Dearmor::Auto)
.finalize();
assert_match!(Ok(PacketParserResult::Some(ref _pp)) = ppr);
let ppr = PacketParserBuilder::from_bytes(msg).unwrap()
.dearmor(Dearmor::Enabled)
.finalize();
assert_match!(Ok(PacketParserResult::Some(ref _pp)) = ppr);
}
}