From 57b533c59a74ae4d1be5d763321788bbc3c677ef Mon Sep 17 00:00:00 2001 From: Alexis Mousset Date: Mon, 15 Dec 2014 23:51:52 +0100 Subject: [PATCH] Add some configuration management --- examples/client.rs | 7 +--- src/client/mod.rs | 95 +++++++++++++++++++++++++++++++++------------- src/common.rs | 3 -- src/lib.rs | 17 +++++---- 4 files changed, 79 insertions(+), 43 deletions(-) diff --git a/examples/client.rs b/examples/client.rs index 862f037..9d288b5 100644 --- a/examples/client.rs +++ b/examples/client.rs @@ -35,11 +35,8 @@ fn sendmail(source_address: &str, recipient_addresses: &[&str], message: &str, s email.subject(subject); email.date_now(); - let mut client = - Client::new( - (server, port), - Some(my_hostname), - ); + let mut client = Client::new((server, port)); + client.set_hello_name(my_hostname); client.send(email) } diff --git a/src/client/mod.rs b/src/client/mod.rs index 5882d85..aaaea7e 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -32,6 +32,23 @@ pub mod server_info; pub mod connecter; pub mod stream; +/// Represents the configuration of a client +#[deriving(Clone)] +pub struct Configuration { + /// Maximum connection reuse + /// + /// Zero means no limitation + pub connection_reuse_count_limit: uint, + /// Enable connection reuse + pub enable_connection_reuse: bool, + /// Maximum recipients + pub destination_recipient_limit: uint, + /// Maximum line length + pub line_length_limit: uint, + /// Name sent during HELO or EHLO + pub hello_name: String, +} + /// Structure that implements the SMTP client pub struct Client { /// TCP stream between client and server @@ -39,8 +56,6 @@ pub struct Client { stream: Option, /// Socket we are connecting to server_addr: SocketAddr, - /// Our hostname for HELO/EHLO commands - my_hostname: String, /// Information about the server /// Value is None before HELO/EHLO server_info: Option, @@ -49,9 +64,11 @@ pub struct Client { /// Panic state panic: bool, /// Connection reuse counter - connection_reuse: uint, + connection_reuse_count: uint, /// Current message id current_message: Option, + /// Configuration of the client + configuration: Configuration, } macro_rules! try_smtp ( @@ -87,16 +104,22 @@ impl Client { /// Creates a new SMTP client /// /// It does not connects to the server, but only create the `Client` - pub fn new(addr: A, my_hostname: Option<&str>) -> Client { + pub fn new(addr: A) -> Client { Client{ stream: None, server_addr: addr.to_socket_addr().unwrap(), - my_hostname: my_hostname.unwrap_or("localhost").to_string(), server_info: None, state: TransactionState::new(), panic: false, - connection_reuse: 0, + connection_reuse_count: 0, current_message: None, + configuration: Configuration { + connection_reuse_count_limit: 100, + enable_connection_reuse: false, + line_length_limit: 998, + destination_recipient_limit: 100, + hello_name: "localhost".to_string(), + } } } @@ -104,7 +127,27 @@ impl Client { /// /// It does not connects to the server, but only create the `Client` pub fn localhost() -> Client { - Client::new(("localhost", SMTP_PORT), Some("localhost")) + Client::new(("localhost", SMTP_PORT)) + } + + /// Set the name used during HELO or EHLO + pub fn set_hello_name(&mut self, name: &str) { + self.configuration.hello_name = name.to_string() + } + + /// Set the maximum number of emails sent using one connection + pub fn set_enable_connection_reuse(&mut self, enable: bool) { + self.configuration.enable_connection_reuse = enable + } + + /// Set the maximum number of emails sent using one connection + pub fn set_connection_reuse_count_limit(&mut self, count: uint) { + self.configuration.connection_reuse_count_limit = count + } + + /// Set the client configuration + pub fn set_configuration(&mut self, configuration: Configuration) { + self.configuration = configuration } } @@ -124,26 +167,17 @@ impl Client { self.state = TransactionState::new(); self.server_info = None; self.panic = false; - self.connection_reuse = 0; + self.connection_reuse_count = 0; self.current_message = None; } /// Sends an email - /// - /// This method sends a message and closes the SMTP transaction - pub fn send(&mut self, email: T) -> SmtpResult { - let result = self.send_only(email); - self.close(); - result - } + pub fn send(&mut self, mut email: T) -> SmtpResult { + + let max_reuse_reached = self.connection_reuse_count == self.configuration.connection_reuse_count_limit; - /// Sends an email - /// - /// This method sends a message and lets the connection opened. It has to be closed with the - /// `close` method after. - pub fn send_only(&mut self, mut email: T) -> SmtpResult { // Connect to the server if needed - if self.noop().is_err() { + if max_reuse_reached || self.noop().is_err() { self.reset(); try!(self.connect()); @@ -165,7 +199,8 @@ impl Client { } self.current_message = Some(Uuid::new_v4()); - email.set_message_id(format!("<{}@{}>", self.current_message.as_ref().unwrap(), self.my_hostname)); + email.set_message_id(format!("<{}@{}>", self.current_message.as_ref().unwrap(), + self.configuration.hello_name.clone())); let from_address = email.from_address(); let to_addresses = email.to_addresses(); @@ -185,7 +220,13 @@ impl Client { try_smtp!(self.data() self); // Message content - self.message(message.as_slice()) + let result = self.message(message.as_slice()); + + if !self.configuration.enable_connection_reuse { + self.close(); + } + + result } /// Connects to the configured server @@ -257,7 +298,7 @@ impl Client { /// Send a HELO command and fills `server_info` pub fn helo(&mut self) -> SmtpResult { - let hostname = self.my_hostname.clone(); + let hostname = self.configuration.hello_name.clone(); let result = try!(self.command(Command::Hello(hostname))); self.server_info = Some( ServerInfo{ @@ -270,7 +311,7 @@ impl Client { /// Sends a EHLO command and fills `server_info` pub fn ehlo(&mut self) -> SmtpResult { - let hostname = self.my_hostname.clone(); + let hostname = self.configuration.hello_name.clone(); let result = try!(self.command(Command::ExtendedHello(hostname))); self.server_info = Some( ServerInfo{ @@ -369,10 +410,10 @@ impl Client { if result.is_ok() { // Increment the connection reuse counter - self.connection_reuse = self.connection_reuse + 1; + self.connection_reuse_count = self.connection_reuse_count + 1; // Log the message info!("{}: conn_use={}, status=sent ({})", self.current_message.as_ref().unwrap(), - self.connection_reuse, result.as_ref().ok().unwrap()); + self.connection_reuse_count, result.as_ref().ok().unwrap()); } self.current_message = None; diff --git a/src/common.rs b/src/common.rs index 31bcf6c..46980da 100644 --- a/src/common.rs +++ b/src/common.rs @@ -22,9 +22,6 @@ pub static SMTPS_PORT: Port = 465; /// Default submission port pub static SUBMISSION_PORT: Port = 587; -// Maximum length of an SMTP command line -//pub static MAX_SMTP_LINE_LENGTH: uint = 1034; - /// The word separator for SMTP transactions pub static SP: &'static str = " "; diff --git a/src/lib.rs b/src/lib.rs index dadbd2b..7c84f31 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -44,7 +44,6 @@ //! let mut client = Client::localhost(); //! // Send the email //! let result = client.send(email); -//! client.close(); //! //! assert!(result.is_ok()); //! ``` @@ -73,15 +72,19 @@ //! //! let mut client = Client::new( //! ("server.tld", 10025), // remote server and custom port -//! Some("my.hostname.tld"), // my hostname //! ); +//! // Set the name sent during EHLO/HELO, default is `localhost` +//! client.set_hello_name("my.hostname.tld"); +//! // Enable connection reuse +//! client.set_enable_connection_reuse(true); //! -//! let result_1 = client.send_only(email.clone()); +//! let result_1 = client.send(email.clone()); //! assert!(result_1.is_ok()); -//! let result_2 = client.send_only(email); +//! let result_2 = client.send(email); //! assert!(result_2.is_ok()); -//! // Explicitely close the SMTP transaction -//! client.close() +//! +//! // Explicitely close the SMTP transaction as we enabled connection reuse +//! client.close(); //! ``` //! //! ### Using the client directly @@ -102,7 +105,6 @@ //! //! let mut client = Client::new( //! "localhost", // server socket -//! Some("my.hostname.tld"), // my hostname (default is localhost) //! ); //! let result = client.send(email); //! assert!(result.is_ok()); @@ -119,7 +121,6 @@ //! //! let mut email_client = Client::new( //! ("localhost", SMTP_PORT), // server socket -//! Some("my.hostname.tld"), // my hostname (default is localhost) //! ); //! let _ = email_client.connect(); //! let _ = email_client.ehlo();