diff --git a/Cargo.toml b/Cargo.toml index 3134e48..16ddea4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,7 @@ imap-proto = "0.8" nom = "4.0" base64 = "0.10" chrono = "0.4" +lazy_static = "1.4" [dev-dependencies] lettre = "0.9" diff --git a/src/client.rs b/src/client.rs index 9e0a02c..8ec0db9 100644 --- a/src/client.rs +++ b/src/client.rs @@ -6,6 +6,7 @@ use std::collections::HashSet; use std::io::{Read, Write}; use std::net::{TcpStream, ToSocketAddrs}; use std::ops::{Deref, DerefMut}; +use std::str; use std::sync::mpsc; use super::authenticator::Authenticator; @@ -346,13 +347,19 @@ impl Client { ok_or_unauth_client_err!(self.readline(&mut line), self); if line.starts_with(b"+ ") { - let data = ok_or_unauth_client_err!( - parse_authenticate_response(String::from_utf8(line).unwrap()), + let line_str = ok_or_unauth_client_err!( + match str::from_utf8(line.as_slice()) { + Ok(line_str) => Ok(line_str), + Err(e) => Err(Error::Parse(ParseError::DataNotUtf8(line, e))), + }, self ); + let data = ok_or_unauth_client_err!(parse_authenticate_response(line_str), self); let challenge = ok_or_unauth_client_err!( - base64::decode(data.as_str()) - .map_err(|e| Error::Parse(ParseError::Authentication(data, Some(e)))), + base64::decode(data).map_err(|e| Error::Parse(ParseError::Authentication( + data.to_string(), + Some(e) + ))), self ); let raw_response = &authenticator.process(&challenge); diff --git a/src/error.rs b/src/error.rs index 50ba919..3acc429 100644 --- a/src/error.rs +++ b/src/error.rs @@ -5,7 +5,7 @@ use std::fmt; use std::io::Error as IoError; use std::net::TcpStream; use std::result; -use std::string::FromUtf8Error; +use std::str::Utf8Error; use base64::DecodeError; use bufstream::IntoInnerError as BufError; @@ -111,7 +111,7 @@ impl StdError for Error { Error::Io(ref e) => Some(e), Error::Tls(ref e) => Some(e), Error::TlsHandshake(ref e) => Some(e), - Error::Parse(ParseError::DataNotUtf8(ref e)) => Some(e), + Error::Parse(ParseError::DataNotUtf8(_, ref e)) => Some(e), _ => None, } } @@ -127,7 +127,7 @@ pub enum ParseError { /// The client could not find or decode the server's authentication challenge. Authentication(String, Option), /// The client receive data that was not UTF-8 encoded. - DataNotUtf8(FromUtf8Error), + DataNotUtf8(Vec, Utf8Error), } impl fmt::Display for ParseError { @@ -144,7 +144,7 @@ impl StdError for ParseError { ParseError::Invalid(_) => "Unable to parse status response", ParseError::Unexpected(_) => "Encountered unexpected parsed response", ParseError::Authentication(_, _) => "Unable to parse authentication response", - ParseError::DataNotUtf8(_) => "Unable to parse data as UTF-8 text", + ParseError::DataNotUtf8(_, _) => "Unable to parse data as UTF-8 text", } } diff --git a/src/parse.rs b/src/parse.rs index a2de763..dbcb27f 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -1,4 +1,5 @@ use imap_proto::{self, MailboxDatum, Response}; +use lazy_static::lazy_static; use regex::Regex; use std::collections::HashSet; use std::sync::mpsc; @@ -6,15 +7,19 @@ use std::sync::mpsc; use super::error::{Error, ParseError, Result}; use super::types::*; -pub fn parse_authenticate_response(line: String) -> Result { - let authenticate_regex = Regex::new("^\\+ (.*)\r\n").unwrap(); +lazy_static! { + static ref AUTH_RESP_REGEX: Regex = Regex::new("^\\+ (.*)\r\n").unwrap(); +} - if let Some(cap) = authenticate_regex.captures_iter(line.as_str()).next() { +pub fn parse_authenticate_response(line: &str) -> Result<&str> { + if let Some(cap) = AUTH_RESP_REGEX.captures_iter(line).next() { let data = cap.get(1).map(|x| x.as_str()).unwrap_or(""); - return Ok(String::from(data)); + return Ok(data); } - - Err(Error::Parse(ParseError::Authentication(line, None))) + Err(Error::Parse(ParseError::Authentication( + line.to_string(), + None, + ))) } enum MapOrNot {