style(all): improve the code thanks to rust-clippy

This commit is contained in:
Alexis Mousset
2016-05-17 00:50:22 +02:00
parent 0acc57d36d
commit 97da0c0869
10 changed files with 67 additions and 154 deletions

View File

@@ -382,10 +382,9 @@ impl EmailBuilder {
let message_id = Uuid::new_v4(); let message_id = Uuid::new_v4();
match Header::new_with_value("Message-ID".to_string(), if let Ok(header) = Header::new_with_value("Message-ID".to_string(),
format!("<{}.lettre@localhost>", message_id)) { format!("<{}.lettre@localhost>", message_id)) {
Ok(header) => self.message.add_header(header), self.message.add_header(header)
Err(_) => (),
} }
Ok(Email { Ok(Email {

View File

@@ -15,21 +15,21 @@ pub enum Error {
/// Transient SMTP error, 4xx reply code /// Transient SMTP error, 4xx reply code
/// ///
/// [RFC 5321, section 4.2.1](https://tools.ietf.org/html/rfc5321#section-4.2.1) /// [RFC 5321, section 4.2.1](https://tools.ietf.org/html/rfc5321#section-4.2.1)
TransientError(Response), Transient(Response),
/// Permanent SMTP error, 5xx reply code /// Permanent SMTP error, 5xx reply code
/// ///
/// [RFC 5321, section 4.2.1](https://tools.ietf.org/html/rfc5321#section-4.2.1) /// [RFC 5321, section 4.2.1](https://tools.ietf.org/html/rfc5321#section-4.2.1)
PermanentError(Response), Permanent(Response),
/// Error parsing a response /// Error parsing a response
ResponseParsingError(&'static str), ResponseParsing(&'static str),
/// Error parsing a base64 string in response /// Error parsing a base64 string in response
ChallengeParsingError(FromBase64Error), ChallengeParsing(FromBase64Error),
/// Internal client error /// Internal client error
ClientError(&'static str), Client(&'static str),
/// DNS resolution error /// DNS resolution error
ResolutionError, Resolution,
/// IO error /// IO error
IoError(io::Error), Io(io::Error),
} }
impl Display for Error { impl Display for Error {
@@ -41,19 +41,19 @@ impl Display for Error {
impl StdError for Error { impl StdError for Error {
fn description(&self) -> &str { fn description(&self) -> &str {
match *self { match *self {
TransientError(_) => "a transient error occured during the SMTP transaction", Transient(_) => "a transient error occured during the SMTP transaction",
PermanentError(_) => "a permanent error occured during the SMTP transaction", Permanent(_) => "a permanent error occured during the SMTP transaction",
ResponseParsingError(_) => "an error occured while parsing an SMTP response", ResponseParsing(_) => "an error occured while parsing an SMTP response",
ChallengeParsingError(_) => "an error occured while parsing a CRAM-MD5 challenge", ChallengeParsing(_) => "an error occured while parsing a CRAM-MD5 challenge",
ResolutionError => "could not resolve hostname", Resolution => "could not resolve hostname",
ClientError(_) => "an unknown error occured", Client(_) => "an unknown error occured",
IoError(_) => "an I/O error occured", Io(_) => "an I/O error occured",
} }
} }
fn cause(&self) -> Option<&StdError> { fn cause(&self) -> Option<&StdError> {
match *self { match *self {
IoError(ref err) => Some(&*err as &StdError), Io(ref err) => Some(&*err as &StdError),
_ => None, _ => None,
} }
} }
@@ -61,23 +61,23 @@ impl StdError for Error {
impl From<io::Error> for Error { impl From<io::Error> for Error {
fn from(err: io::Error) -> Error { fn from(err: io::Error) -> Error {
IoError(err) Io(err)
} }
} }
impl From<Response> for Error { impl From<Response> for Error {
fn from(response: Response) -> Error { fn from(response: Response) -> Error {
match response.severity() { match response.severity() {
Severity::TransientNegativeCompletion => TransientError(response), Severity::TransientNegativeCompletion => Transient(response),
Severity::PermanentNegativeCompletion => PermanentError(response), Severity::PermanentNegativeCompletion => Permanent(response),
_ => ClientError("Unknown error code"), _ => Client("Unknown error code"),
} }
} }
} }
impl From<&'static str> for Error { impl From<&'static str> for Error {
fn from(string: &'static str) -> Error { fn from(string: &'static str) -> Error {
ClientError(string) Client(string)
} }
} }

View File

@@ -38,7 +38,7 @@ impl EmailTransport for FileEmailTransport {
email.to_addresses().join("> to=<")); email.to_addresses().join("> to=<"));
try!(f.write_all(log_line.as_bytes())); try!(f.write_all(log_line.as_bytes()));
try!(f.write_all(format!("{}", email.message()).as_bytes())); try!(f.write_all(email.message().clone().as_bytes()));
info!("{} status=<written>", log_line); info!("{} status=<written>", log_line);

View File

@@ -1,75 +0,0 @@
//! This transport creates a file for each email, containing the enveloppe information and the email
//! itself.
use transport::EmailTransport;
use transport::error::EmailResult;
use transport::smtp::response::Response;
use transport::smtp::response::{Category, Code, Severity};
use email::SendableEmail;
/// Writes the content and the enveloppe information to a file
pub struct SendmailEmailTransport {
command: String,
}
impl SendmailEmailTransport {
/// Creates a new transport to the default "sendmail" command
pub fn new() -> SendmailEmailTransport {
SendmailEmailTransport { command: "sendmail".to_string() }
}
/// Creates a new transport with a custom sendmail command
pub fn new_with_command(command: &str) -> SendmailEmailTransport {
SendmailEmailTransport { command: command.to_string() }
}
}
impl EmailTransport for SendmailEmailTransport {
fn send<T: SendableEmail>(&mut self, email: T) -> EmailResult {
// Build TO list
// Set FROM
// Send content
let sendmail_sh_frist_half = "sendmail ".to_string() + &to_address;
let sendmail_sh_second_half = " < email.txt".to_string();
let sendmail_sh = sendmail_sh_frist_half + &sendmail_sh_second_half;
let output = Command::new(self.command)
.arg("-c")
.arg(sendmail_sh)
.output()
.unwrap_or_else(|e| panic!("failed to execute process: {}", e));
println!("status: {}", output.status);
println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
println!("stderr: {}", String::from_utf8_lossy(&output.stderr));
let mut file = self.path.clone();
file.push(format!("{}.txt", email.message_id()));
let mut f = try!(File::create(file.as_path()));
let log_line = format!("{}: from=<{}> to=<{}>\n",
email.message_id(),
email.from_address(),
email.to_addresses().join("> to=<"));
try!(f.write_all(log_line.as_bytes()));
try!(f.write_all(format!("{}", email.message()).as_bytes()));
info!("{} status=<written>", log_line);
Ok(Response::new(Code::new(Severity::PositiveCompletion, Category::MailSystem, 0),
vec![format!("Ok: email written to {}",
file.to_str().unwrap_or("non-UTF-8 path"))]))
}
fn close(&mut self) {
()
}
}

View File

@@ -53,9 +53,7 @@ impl Mechanism {
match *self { match *self {
Mechanism::Plain => { Mechanism::Plain => {
match challenge { match challenge {
Some(_) => { Some(_) => Err(Error::Client("This mechanism does not expect a challenge")),
Err(Error::ClientError("This mechanism does not expect a challenge"))
}
None => { None => {
Ok(format!("{}{}{}{}", NUL, username, NUL, password) Ok(format!("{}{}{}{}", NUL, username, NUL, password)
.as_bytes() .as_bytes()
@@ -66,14 +64,12 @@ impl Mechanism {
Mechanism::CramMd5 => { Mechanism::CramMd5 => {
let encoded_challenge = match challenge { let encoded_challenge = match challenge {
Some(challenge) => challenge, Some(challenge) => challenge,
None => { None => return Err(Error::Client("This mechanism does expect a challenge")),
return Err(Error::ClientError("This mechanism does expect a challenge"))
}
}; };
let decoded_challenge = match encoded_challenge.from_base64() { let decoded_challenge = match encoded_challenge.from_base64() {
Ok(challenge) => challenge, Ok(challenge) => challenge,
Err(error) => return Err(Error::ChallengeParsingError(error)), Err(error) => return Err(Error::ChallengeParsing(error)),
}; };
let mut hmac = Hmac::new(Md5::new(), password.as_bytes()); let mut hmac = Hmac::new(Md5::new(), password.as_bytes());

View File

@@ -22,7 +22,7 @@ pub mod net;
/// Reference : https://tools.ietf.org/html/rfc5321#page-62 (4.5.2. Transparency) /// Reference : https://tools.ietf.org/html/rfc5321#page-62 (4.5.2. Transparency)
#[inline] #[inline]
fn escape_dot(string: &str) -> String { fn escape_dot(string: &str) -> String {
if string.starts_with(".") { if string.starts_with('.') {
format!(".{}", string) format!(".{}", string)
} else { } else {
string.to_string() string.to_string()
@@ -193,7 +193,7 @@ impl<S: Connector + Write + Read + Debug + Clone> Client<S> {
} else { } else {
let encoded_challenge = match try!(self.command("AUTH CRAM-MD5")).first_word() { let encoded_challenge = match try!(self.command("AUTH CRAM-MD5")).first_word() {
Some(challenge) => challenge, Some(challenge) => challenge,
None => return Err(Error::ResponseParsingError("Could not read CRAM challenge")), None => return Err(Error::ResponseParsing("Could not read CRAM challenge")),
}; };
debug!("CRAM challenge: {}", encoded_challenge); debug!("CRAM challenge: {}", encoded_challenge);
@@ -202,7 +202,7 @@ impl<S: Connector + Write + Read + Debug + Clone> Client<S> {
password, password,
Some(&encoded_challenge))); Some(&encoded_challenge)));
self.command(&format!("{}", cram_response)) self.command(&cram_response.clone())
} }
} }
@@ -233,7 +233,7 @@ impl<S: Connector + Write + Read + Debug + Clone> Client<S> {
/// Gets the SMTP response /// Gets the SMTP response
fn get_reply(&mut self) -> EmailResult { fn get_reply(&mut self) -> EmailResult {
let mut parser = ResponseParser::new(); let mut parser = ResponseParser::default();
let mut line = String::new(); let mut line = String::new();
try!(self.stream.as_mut().unwrap().read_line(&mut line)); try!(self.stream.as_mut().unwrap().read_line(&mut line));
@@ -247,10 +247,12 @@ impl<S: Connector + Write + Read + Debug + Clone> Client<S> {
let response = try!(parser.response()); let response = try!(parser.response());
match response.is_positive() { if response.is_positive() {
true => Ok(response), Ok(response)
false => Err(From::from(response)), } else {
Err(From::from(response))
} }
} }
} }

View File

@@ -66,9 +66,9 @@ pub enum NetworkStream {
impl Clone for NetworkStream { impl Clone for NetworkStream {
#[inline] #[inline]
fn clone(&self) -> NetworkStream { fn clone(&self) -> NetworkStream {
match self { match *self {
&NetworkStream::Plain(ref stream) => NetworkStream::Plain(stream.try_clone().unwrap()), NetworkStream::Plain(ref stream) => NetworkStream::Plain(stream.try_clone().unwrap()),
&NetworkStream::Ssl(ref stream) => NetworkStream::Ssl(stream.try_clone().unwrap()), NetworkStream::Ssl(ref stream) => NetworkStream::Ssl(stream.try_clone().unwrap()),
} }
} }
} }

View File

@@ -69,7 +69,7 @@ impl ServerInfo {
pub fn from_response(response: &Response) -> Result<ServerInfo, Error> { pub fn from_response(response: &Response) -> Result<ServerInfo, Error> {
let name = match response.first_word() { let name = match response.first_word() {
Some(name) => name, Some(name) => name,
None => return Err(Error::ResponseParsingError("Could not read server name")), None => return Err(Error::ResponseParsing("Could not read server name")),
}; };
let mut features: HashSet<Extension> = HashSet::new(); let mut features: HashSet<Extension> = HashSet::new();
@@ -77,7 +77,7 @@ impl ServerInfo {
for line in response.message() { for line in response.message() {
let splitted: Vec<&str> = line.split_whitespace().collect(); let splitted: Vec<&str> = line.split_whitespace().collect();
let _ = match splitted[0] { match splitted[0] {
"8BITMIME" => { "8BITMIME" => {
features.insert(Extension::EightBitMime); features.insert(Extension::EightBitMime);
} }

View File

@@ -87,7 +87,7 @@ pub struct SmtpTransportBuilder {
authentication_mechanism: Option<Mechanism>, authentication_mechanism: Option<Mechanism>,
} }
/// Builder for the SMTP SmtpTransport /// Builder for the SMTP `SmtpTransport`
impl SmtpTransportBuilder { impl SmtpTransportBuilder {
/// Creates a new local SMTP client /// Creates a new local SMTP client
pub fn new<A: ToSocketAddrs>(addr: A) -> Result<SmtpTransportBuilder, Error> { pub fn new<A: ToSocketAddrs>(addr: A) -> Result<SmtpTransportBuilder, Error> {
@@ -280,10 +280,8 @@ impl EmailTransport for SmtpTransport {
let message = email.message(); let message = email.message();
// Check if the connection is still available // Check if the connection is still available
if self.state.connection_reuse_count > 0 { if (self.state.connection_reuse_count > 0) && (!self.client.is_connected()) {
if !self.client.is_connected() { self.reset();
self.reset();
}
} }
if self.state.connection_reuse_count == 0 { if self.state.connection_reuse_count == 0 {
@@ -329,12 +327,13 @@ impl EmailTransport for SmtpTransport {
let accepted_mechanisms = match self.client_info.authentication_mechanism { let accepted_mechanisms = match self.client_info.authentication_mechanism {
Some(mechanism) => vec![mechanism], Some(mechanism) => vec![mechanism],
None => { None => {
match self.client.is_encrypted() { if self.client.is_encrypted() {
// If encrypted, allow all mechanisms, with a preference for the // If encrypted, allow all mechanisms, with a preference for the
// simplest // simplest
true => vec![Mechanism::Plain, Mechanism::CramMd5], vec![Mechanism::Plain, Mechanism::CramMd5]
} else {
// If not encrypted, do not all clear-text passwords // If not encrypted, do not all clear-text passwords
false => vec![Mechanism::CramMd5], vec![Mechanism::CramMd5]
} }
} }
}; };
@@ -373,7 +372,7 @@ impl EmailTransport for SmtpTransport {
info!("{}: from=<{}>", message_id, from_address); info!("{}: from=<{}>", message_id, from_address);
// Recipient // Recipient
for to_address in to_addresses.iter() { for to_address in &to_addresses {
try_smtp!(self.client.rcpt(&to_address), self); try_smtp!(self.client.rcpt(&to_address), self);
// Log the rcpt command // Log the rcpt command
info!("{}: to=<{}>", message_id, to_address); info!("{}: to=<{}>", message_id, to_address);
@@ -387,7 +386,7 @@ impl EmailTransport for SmtpTransport {
if result.is_ok() { if result.is_ok() {
// Increment the connection reuse counter // Increment the connection reuse counter
self.state.connection_reuse_count = self.state.connection_reuse_count + 1; self.state.connection_reuse_count += 1;
// Log the message // Log the message
info!("{}: conn_use={}, size={}, status=sent ({})", info!("{}: conn_use={}, size={}, status=sent ({})",

View File

@@ -30,7 +30,7 @@ impl FromStr for Severity {
"3" => Ok(PositiveIntermediate), "3" => Ok(PositiveIntermediate),
"4" => Ok(TransientNegativeCompletion), "4" => Ok(TransientNegativeCompletion),
"5" => Ok(PermanentNegativeCompletion), "5" => Ok(PermanentNegativeCompletion),
_ => Err(Error::ResponseParsingError("First digit must be between 2 and 5")), _ => Err(Error::ResponseParsing("First digit must be between 2 and 5")),
} }
} }
} }
@@ -75,7 +75,7 @@ impl FromStr for Category {
"3" => Ok(Unspecified3), "3" => Ok(Unspecified3),
"4" => Ok(Unspecified4), "4" => Ok(Unspecified4),
"5" => Ok(MailSystem), "5" => Ok(MailSystem),
_ => Err(Error::ResponseParsingError("Second digit must be between 0 and 5")), _ => Err(Error::ResponseParsing("Second digit must be between 0 and 5")),
} }
} }
} }
@@ -122,10 +122,10 @@ impl FromStr for Code {
detail: detail, detail: detail,
}) })
} }
_ => return Err(Error::ResponseParsingError("Could not parse response code")), _ => Err(Error::ResponseParsing("Could not parse response code")),
} }
} else { } else {
Err(Error::ResponseParsingError("Wrong code length (should be 3 digit)")) Err(Error::ResponseParsing("Wrong code length (should be 3 digit)"))
} }
} }
} }
@@ -147,7 +147,7 @@ impl Code {
} }
/// Parses an SMTP response /// Parses an SMTP response
#[derive(PartialEq,Eq,Clone,Debug)] #[derive(PartialEq,Eq,Clone,Debug,Default)]
pub struct ResponseParser { pub struct ResponseParser {
/// Response code /// Response code
code: Option<Code>, code: Option<Code>,
@@ -157,25 +157,17 @@ pub struct ResponseParser {
} }
impl ResponseParser { impl ResponseParser {
/// Creates a new parser
pub fn new() -> ResponseParser {
ResponseParser {
code: None,
message: vec![],
}
}
/// Parses a line and return a `bool` indicating if there are more lines to come /// Parses a line and return a `bool` indicating if there are more lines to come
pub fn read_line(&mut self, line: &str) -> result::Result<bool, Error> { pub fn read_line(&mut self, line: &str) -> result::Result<bool, Error> {
if line.len() < 3 { if line.len() < 3 {
return Err(Error::ResponseParsingError("Wrong code length (should be 3 digit)")); return Err(Error::ResponseParsing("Wrong code length (should be 3 digit)"));
} }
match self.code { match self.code {
Some(ref code) => { Some(ref code) => {
if code.code() != line[0..3] { if code.code() != line[0..3] {
return Err(Error::ResponseParsingError("Response code has changed during a \ return Err(Error::ResponseParsing("Response code has changed during a \
reponse")); reponse"));
} }
} }
@@ -184,7 +176,7 @@ impl ResponseParser {
if line.len() > 4 { if line.len() > 4 {
self.message.push(line[4..].to_string()); self.message.push(line[4..].to_string());
Ok(line.as_bytes()[3] == '-' as u8) Ok(line.as_bytes()[3] == b'-')
} else { } else {
Ok(false) Ok(false)
} }
@@ -195,7 +187,7 @@ impl ResponseParser {
match self.code { match self.code {
Some(code) => Ok(Response::new(code, self.message)), Some(code) => Ok(Response::new(code, self.message)),
None => { None => {
Err(Error::ResponseParsingError("Incomplete response, could not read response \ Err(Error::ResponseParsing("Incomplete response, could not read response \
code")) code"))
} }
} }
@@ -264,15 +256,15 @@ impl Response {
/// Returns only the first word of the message if possible /// Returns only the first word of the message if possible
pub fn first_word(&self) -> Option<String> { pub fn first_word(&self) -> Option<String> {
match self.message.is_empty() { if self.message.is_empty() {
true => None, None
false => { } else {
match self.message[0].split_whitespace().next() { match self.message[0].split_whitespace().next() {
Some(word) => Some(word.to_string()), Some(word) => Some(word.to_string()),
None => None, None => None,
}
} }
} }
} }
} }
@@ -377,7 +369,7 @@ mod test {
#[test] #[test]
fn test_response_parser() { fn test_response_parser() {
let mut parser = ResponseParser::new(); let mut parser = ResponseParser::default();
assert!(parser.read_line("250-me").unwrap()); assert!(parser.read_line("250-me").unwrap());
assert!(parser.read_line("250-8BITMIME").unwrap()); assert!(parser.read_line("250-8BITMIME").unwrap());