style(all): improve the code thanks to rust-clippy
This commit is contained in:
@@ -382,10 +382,9 @@ impl EmailBuilder {
|
||||
|
||||
let message_id = Uuid::new_v4();
|
||||
|
||||
match Header::new_with_value("Message-ID".to_string(),
|
||||
format!("<{}.lettre@localhost>", message_id)) {
|
||||
Ok(header) => self.message.add_header(header),
|
||||
Err(_) => (),
|
||||
if let Ok(header) = Header::new_with_value("Message-ID".to_string(),
|
||||
format!("<{}.lettre@localhost>", message_id)) {
|
||||
self.message.add_header(header)
|
||||
}
|
||||
|
||||
Ok(Email {
|
||||
|
||||
@@ -15,21 +15,21 @@ pub enum Error {
|
||||
/// Transient SMTP error, 4xx reply code
|
||||
///
|
||||
/// [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
|
||||
///
|
||||
/// [RFC 5321, section 4.2.1](https://tools.ietf.org/html/rfc5321#section-4.2.1)
|
||||
PermanentError(Response),
|
||||
Permanent(Response),
|
||||
/// Error parsing a response
|
||||
ResponseParsingError(&'static str),
|
||||
ResponseParsing(&'static str),
|
||||
/// Error parsing a base64 string in response
|
||||
ChallengeParsingError(FromBase64Error),
|
||||
ChallengeParsing(FromBase64Error),
|
||||
/// Internal client error
|
||||
ClientError(&'static str),
|
||||
Client(&'static str),
|
||||
/// DNS resolution error
|
||||
ResolutionError,
|
||||
Resolution,
|
||||
/// IO error
|
||||
IoError(io::Error),
|
||||
Io(io::Error),
|
||||
}
|
||||
|
||||
impl Display for Error {
|
||||
@@ -41,19 +41,19 @@ impl Display for Error {
|
||||
impl StdError for Error {
|
||||
fn description(&self) -> &str {
|
||||
match *self {
|
||||
TransientError(_) => "a transient error occured during the SMTP transaction",
|
||||
PermanentError(_) => "a permanent error occured during the SMTP transaction",
|
||||
ResponseParsingError(_) => "an error occured while parsing an SMTP response",
|
||||
ChallengeParsingError(_) => "an error occured while parsing a CRAM-MD5 challenge",
|
||||
ResolutionError => "could not resolve hostname",
|
||||
ClientError(_) => "an unknown error occured",
|
||||
IoError(_) => "an I/O error occured",
|
||||
Transient(_) => "a transient error occured during the SMTP transaction",
|
||||
Permanent(_) => "a permanent error occured during the SMTP transaction",
|
||||
ResponseParsing(_) => "an error occured while parsing an SMTP response",
|
||||
ChallengeParsing(_) => "an error occured while parsing a CRAM-MD5 challenge",
|
||||
Resolution => "could not resolve hostname",
|
||||
Client(_) => "an unknown error occured",
|
||||
Io(_) => "an I/O error occured",
|
||||
}
|
||||
}
|
||||
|
||||
fn cause(&self) -> Option<&StdError> {
|
||||
match *self {
|
||||
IoError(ref err) => Some(&*err as &StdError),
|
||||
Io(ref err) => Some(&*err as &StdError),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@@ -61,23 +61,23 @@ impl StdError for Error {
|
||||
|
||||
impl From<io::Error> for Error {
|
||||
fn from(err: io::Error) -> Error {
|
||||
IoError(err)
|
||||
Io(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Response> for Error {
|
||||
fn from(response: Response) -> Error {
|
||||
match response.severity() {
|
||||
Severity::TransientNegativeCompletion => TransientError(response),
|
||||
Severity::PermanentNegativeCompletion => PermanentError(response),
|
||||
_ => ClientError("Unknown error code"),
|
||||
Severity::TransientNegativeCompletion => Transient(response),
|
||||
Severity::PermanentNegativeCompletion => Permanent(response),
|
||||
_ => Client("Unknown error code"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'static str> for Error {
|
||||
fn from(string: &'static str) -> Error {
|
||||
ClientError(string)
|
||||
Client(string)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ impl EmailTransport for FileEmailTransport {
|
||||
email.to_addresses().join("> to=<"));
|
||||
|
||||
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);
|
||||
|
||||
|
||||
@@ -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) {
|
||||
()
|
||||
}
|
||||
}
|
||||
@@ -53,9 +53,7 @@ impl Mechanism {
|
||||
match *self {
|
||||
Mechanism::Plain => {
|
||||
match challenge {
|
||||
Some(_) => {
|
||||
Err(Error::ClientError("This mechanism does not expect a challenge"))
|
||||
}
|
||||
Some(_) => Err(Error::Client("This mechanism does not expect a challenge")),
|
||||
None => {
|
||||
Ok(format!("{}{}{}{}", NUL, username, NUL, password)
|
||||
.as_bytes()
|
||||
@@ -66,14 +64,12 @@ impl Mechanism {
|
||||
Mechanism::CramMd5 => {
|
||||
let encoded_challenge = match challenge {
|
||||
Some(challenge) => challenge,
|
||||
None => {
|
||||
return Err(Error::ClientError("This mechanism does expect a challenge"))
|
||||
}
|
||||
None => return Err(Error::Client("This mechanism does expect a challenge")),
|
||||
};
|
||||
|
||||
let decoded_challenge = match encoded_challenge.from_base64() {
|
||||
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());
|
||||
|
||||
@@ -22,7 +22,7 @@ pub mod net;
|
||||
/// Reference : https://tools.ietf.org/html/rfc5321#page-62 (4.5.2. Transparency)
|
||||
#[inline]
|
||||
fn escape_dot(string: &str) -> String {
|
||||
if string.starts_with(".") {
|
||||
if string.starts_with('.') {
|
||||
format!(".{}", string)
|
||||
} else {
|
||||
string.to_string()
|
||||
@@ -193,7 +193,7 @@ impl<S: Connector + Write + Read + Debug + Clone> Client<S> {
|
||||
} else {
|
||||
let encoded_challenge = match try!(self.command("AUTH CRAM-MD5")).first_word() {
|
||||
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);
|
||||
@@ -202,7 +202,7 @@ impl<S: Connector + Write + Read + Debug + Clone> Client<S> {
|
||||
password,
|
||||
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
|
||||
fn get_reply(&mut self) -> EmailResult {
|
||||
|
||||
let mut parser = ResponseParser::new();
|
||||
let mut parser = ResponseParser::default();
|
||||
|
||||
let mut line = String::new();
|
||||
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());
|
||||
|
||||
match response.is_positive() {
|
||||
true => Ok(response),
|
||||
false => Err(From::from(response)),
|
||||
if response.is_positive() {
|
||||
Ok(response)
|
||||
} else {
|
||||
Err(From::from(response))
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -66,9 +66,9 @@ pub enum NetworkStream {
|
||||
impl Clone for NetworkStream {
|
||||
#[inline]
|
||||
fn clone(&self) -> NetworkStream {
|
||||
match self {
|
||||
&NetworkStream::Plain(ref stream) => NetworkStream::Plain(stream.try_clone().unwrap()),
|
||||
&NetworkStream::Ssl(ref stream) => NetworkStream::Ssl(stream.try_clone().unwrap()),
|
||||
match *self {
|
||||
NetworkStream::Plain(ref stream) => NetworkStream::Plain(stream.try_clone().unwrap()),
|
||||
NetworkStream::Ssl(ref stream) => NetworkStream::Ssl(stream.try_clone().unwrap()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ impl ServerInfo {
|
||||
pub fn from_response(response: &Response) -> Result<ServerInfo, Error> {
|
||||
let name = match response.first_word() {
|
||||
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();
|
||||
@@ -77,7 +77,7 @@ impl ServerInfo {
|
||||
for line in response.message() {
|
||||
|
||||
let splitted: Vec<&str> = line.split_whitespace().collect();
|
||||
let _ = match splitted[0] {
|
||||
match splitted[0] {
|
||||
"8BITMIME" => {
|
||||
features.insert(Extension::EightBitMime);
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ pub struct SmtpTransportBuilder {
|
||||
authentication_mechanism: Option<Mechanism>,
|
||||
}
|
||||
|
||||
/// Builder for the SMTP SmtpTransport
|
||||
/// Builder for the SMTP `SmtpTransport`
|
||||
impl SmtpTransportBuilder {
|
||||
/// Creates a new local SMTP client
|
||||
pub fn new<A: ToSocketAddrs>(addr: A) -> Result<SmtpTransportBuilder, Error> {
|
||||
@@ -280,10 +280,8 @@ impl EmailTransport for SmtpTransport {
|
||||
let message = email.message();
|
||||
|
||||
// Check if the connection is still available
|
||||
if self.state.connection_reuse_count > 0 {
|
||||
if !self.client.is_connected() {
|
||||
self.reset();
|
||||
}
|
||||
if (self.state.connection_reuse_count > 0) && (!self.client.is_connected()) {
|
||||
self.reset();
|
||||
}
|
||||
|
||||
if self.state.connection_reuse_count == 0 {
|
||||
@@ -329,12 +327,13 @@ impl EmailTransport for SmtpTransport {
|
||||
let accepted_mechanisms = match self.client_info.authentication_mechanism {
|
||||
Some(mechanism) => vec![mechanism],
|
||||
None => {
|
||||
match self.client.is_encrypted() {
|
||||
if self.client.is_encrypted() {
|
||||
// If encrypted, allow all mechanisms, with a preference for the
|
||||
// simplest
|
||||
true => vec![Mechanism::Plain, Mechanism::CramMd5],
|
||||
vec![Mechanism::Plain, Mechanism::CramMd5]
|
||||
} else {
|
||||
// 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);
|
||||
|
||||
// Recipient
|
||||
for to_address in to_addresses.iter() {
|
||||
for to_address in &to_addresses {
|
||||
try_smtp!(self.client.rcpt(&to_address), self);
|
||||
// Log the rcpt command
|
||||
info!("{}: to=<{}>", message_id, to_address);
|
||||
@@ -387,7 +386,7 @@ impl EmailTransport for SmtpTransport {
|
||||
|
||||
if result.is_ok() {
|
||||
// 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
|
||||
info!("{}: conn_use={}, size={}, status=sent ({})",
|
||||
|
||||
@@ -30,7 +30,7 @@ impl FromStr for Severity {
|
||||
"3" => Ok(PositiveIntermediate),
|
||||
"4" => Ok(TransientNegativeCompletion),
|
||||
"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),
|
||||
"4" => Ok(Unspecified4),
|
||||
"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,
|
||||
})
|
||||
}
|
||||
_ => return Err(Error::ResponseParsingError("Could not parse response code")),
|
||||
_ => Err(Error::ResponseParsing("Could not parse response code")),
|
||||
}
|
||||
} 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
|
||||
#[derive(PartialEq,Eq,Clone,Debug)]
|
||||
#[derive(PartialEq,Eq,Clone,Debug,Default)]
|
||||
pub struct ResponseParser {
|
||||
/// Response code
|
||||
code: Option<Code>,
|
||||
@@ -157,25 +157,17 @@ pub struct 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
|
||||
pub fn read_line(&mut self, line: &str) -> result::Result<bool, Error> {
|
||||
|
||||
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 {
|
||||
Some(ref code) => {
|
||||
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"));
|
||||
}
|
||||
}
|
||||
@@ -184,7 +176,7 @@ impl ResponseParser {
|
||||
|
||||
if line.len() > 4 {
|
||||
self.message.push(line[4..].to_string());
|
||||
Ok(line.as_bytes()[3] == '-' as u8)
|
||||
Ok(line.as_bytes()[3] == b'-')
|
||||
} else {
|
||||
Ok(false)
|
||||
}
|
||||
@@ -195,7 +187,7 @@ impl ResponseParser {
|
||||
match self.code {
|
||||
Some(code) => Ok(Response::new(code, self.message)),
|
||||
None => {
|
||||
Err(Error::ResponseParsingError("Incomplete response, could not read response \
|
||||
Err(Error::ResponseParsing("Incomplete response, could not read response \
|
||||
code"))
|
||||
}
|
||||
}
|
||||
@@ -264,15 +256,15 @@ impl Response {
|
||||
|
||||
/// Returns only the first word of the message if possible
|
||||
pub fn first_word(&self) -> Option<String> {
|
||||
match self.message.is_empty() {
|
||||
true => None,
|
||||
false => {
|
||||
match self.message[0].split_whitespace().next() {
|
||||
Some(word) => Some(word.to_string()),
|
||||
None => None,
|
||||
}
|
||||
if self.message.is_empty() {
|
||||
None
|
||||
} else {
|
||||
match self.message[0].split_whitespace().next() {
|
||||
Some(word) => Some(word.to_string()),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -377,7 +369,7 @@ mod test {
|
||||
|
||||
#[test]
|
||||
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-8BITMIME").unwrap());
|
||||
|
||||
Reference in New Issue
Block a user