diff --git a/src/transport/smtp/client/mod.rs b/src/transport/smtp/client/mod.rs index c8fe50a..3ce9b21 100644 --- a/src/transport/smtp/client/mod.rs +++ b/src/transport/smtp/client/mod.rs @@ -7,7 +7,7 @@ use crate::{ commands::*, error::Error, extension::{ClientId, Extension, MailBodyParameter, MailParameter, ServerInfo}, - response::Response, + response::{parse_response, Response}, }, Envelope, }; @@ -312,36 +312,30 @@ impl SmtpConnection { /// Gets the SMTP response pub fn read_response(&mut self) -> Result { - let mut raw_response = String::new(); - let mut response = raw_response.parse::(); + let mut buffer = String::with_capacity(100); - while response.is_err() { - if let Error::Parsing(nom::error::ErrorKind::Complete) = - response.as_ref().err().unwrap() - { - break; + while self.stream.read_line(&mut buffer)? > 0 { + #[cfg(feature = "log")] + debug!("<< {}", escape_crlf(&buffer)); + match parse_response(&buffer) { + Ok((_remaining, response)) => { + if response.is_positive() { + return Ok(response); + } + + return Err(response.into()); + } + Err(nom::Err::Failure(e)) => { + return Err(Error::Parsing(e.1)); + } + Err(nom::Err::Incomplete(_)) => { /* read more */ } + Err(nom::Err::Error(e)) => { + return Err(Error::Parsing(e.1)); + } } - // TODO read more than one line - let read_count = self.stream.read_line(&mut raw_response)?; - - // EOF is reached - if read_count == 0 { - break; - } - - response = raw_response.parse::(); } - #[cfg(feature = "log")] - debug!("Read: {}", escape_crlf(raw_response.as_ref())); - - let final_response = response?; - - if final_response.is_positive() { - Ok(final_response) - } else { - Err(From::from(final_response)) - } + Err(io::Error::new(io::ErrorKind::Other, "incomplete").into()) } } diff --git a/src/transport/smtp/response.rs b/src/transport/smtp/response.rs index 8263c7d..b266073 100644 --- a/src/transport/smtp/response.rs +++ b/src/transport/smtp/response.rs @@ -4,7 +4,7 @@ use crate::transport::smtp::Error; use nom::{ branch::alt, - bytes::complete::{tag, take_until}, + bytes::streaming::{tag, take_until}, combinator::{complete, map}, multi::many0, sequence::{preceded, tuple}, @@ -226,7 +226,7 @@ fn parse_detail(i: &str) -> IResult<&str, Detail> { ))(i) } -fn parse_response(i: &str) -> IResult<&str, Response> { +pub(crate) fn parse_response(i: &str) -> IResult<&str, Response> { let (i, lines) = many0(tuple(( parse_code, preceded(tag("-"), take_until("\r\n")), @@ -262,7 +262,7 @@ fn parse_response(i: &str) -> IResult<&str, Response> { #[cfg(test)] mod test { - use super::{Category, Code, Detail, Response, Severity}; + use super::*; #[test] fn test_severity_fmt() { @@ -472,6 +472,16 @@ mod test { ); } + #[test] + fn test_response_incomplete() { + let raw_response = "250-smtp.example.org\r\n"; + let res = parse_response(raw_response); + match res { + Err(nom::Err::Incomplete(_)) => {} + _ => panic!("Expected incomplete response, got {:?}", res), + } + } + #[test] fn test_response_first_line() { assert_eq!(