Split common.rs
This commit is contained in:
@@ -13,8 +13,8 @@ use std::string::String;
|
||||
use std::io::net::ip::Port;
|
||||
use std::error::FromError;
|
||||
|
||||
use common::{get_first_word, unquote_email_address};
|
||||
use common::{CRLF, SMTP_PORT, MESSAGE_ENDING};
|
||||
use tools::{get_first_word, unquote_email_address};
|
||||
use common::{SMTP_PORT, CRLF, MESSAGE_ENDING};
|
||||
use response::Response;
|
||||
use extension;
|
||||
use extension::Extension;
|
||||
@@ -149,7 +149,7 @@ impl<S: Connecter + ClientStream + Clone> Client<S> {
|
||||
}
|
||||
|
||||
/// Sends an SMTP command
|
||||
fn send_command(&mut self, command: Command) -> SmtpResult {
|
||||
pub fn send_command(&mut self, command: Command) -> SmtpResult {
|
||||
// for now we do not support SMTPUTF8
|
||||
if !command.is_ascii() {
|
||||
fail_with_err!("Non-ASCII string" self);
|
||||
|
||||
@@ -17,7 +17,7 @@ use error::SmtpResult;
|
||||
use std::error::FromError;
|
||||
|
||||
use response::Response;
|
||||
use common::{escape_crlf, escape_dot};
|
||||
use tools::{escape_crlf, escape_dot};
|
||||
|
||||
static BUFFER_SIZE: uint = 1024;
|
||||
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
use std::error::FromError;
|
||||
use std::fmt::{Show, Formatter, Result};
|
||||
|
||||
use common::SP;
|
||||
use response::Response;
|
||||
use error::SmtpResult;
|
||||
use common::SP;
|
||||
|
||||
/// Supported SMTP commands
|
||||
///
|
||||
|
||||
136
src/common.rs
136
src/common.rs
@@ -7,13 +7,9 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Contains mixed-up tools for SMTP
|
||||
//!
|
||||
//! TODO : Clean up and split this file
|
||||
//! Contains constants defined in SMTP RFCs
|
||||
|
||||
use std::io::net::ip::Port;
|
||||
use std::string::String;
|
||||
use std::str::replace;
|
||||
|
||||
/// Default smtp port
|
||||
pub static SMTP_PORT: Port = 25;
|
||||
@@ -34,132 +30,6 @@ pub static SP: &'static str = " ";
|
||||
pub static CRLF: &'static str = "\r\n";
|
||||
pub static CR: &'static str = "\r";
|
||||
pub static LF: &'static str = "\n";
|
||||
|
||||
/// The ending of message content
|
||||
pub static MESSAGE_ENDING: &'static str = "\r\n.\r\n";
|
||||
|
||||
/// Adds quotes to emails if needed
|
||||
pub fn quote_email_address(address: &str) -> String {
|
||||
match address.len() {
|
||||
0 ... 1 => format!("<{}>", address),
|
||||
_ => match (address.slice_to(1),
|
||||
address.slice_from(address.len() - 1)) {
|
||||
("<", ">") => address.to_string(),
|
||||
_ => format!("<{}>", address)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes quotes from emails if needed
|
||||
pub fn unquote_email_address(address: &str) -> &str {
|
||||
match address.len() {
|
||||
0 ... 1 => address,
|
||||
_ => match (address.slice_to(1),
|
||||
address.slice_from(address.len() - 1)) {
|
||||
("<", ">") => address.slice(1, address.len() - 1),
|
||||
_ => address
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes the trailing line return at the end of a string
|
||||
pub fn remove_trailing_crlf(string: &str) -> &str {
|
||||
if string.ends_with(CRLF) {
|
||||
string.slice_to(string.len() - 2)
|
||||
} else if string.ends_with(CR) {
|
||||
string.slice_to(string.len() - 1)
|
||||
} else {
|
||||
string
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the first word of a string, or the string if it contains no space
|
||||
pub fn get_first_word(string: &str) -> &str {
|
||||
string.split_str(CRLF).next().unwrap().splitn(1, ' ').next().unwrap()
|
||||
}
|
||||
|
||||
/// Returns the string replacing all the CRLF with "<CRLF>"
|
||||
#[inline]
|
||||
pub fn escape_crlf(string: &str) -> String {
|
||||
replace(string, CRLF, "<CR><LF>")
|
||||
}
|
||||
|
||||
/// Returns the string after adding a dot at the beginning of each line starting with a dot
|
||||
///
|
||||
/// Reference : https://tools.ietf.org/html/rfc5321#page-62 (4.5.2. Transparency)
|
||||
#[inline]
|
||||
pub fn escape_dot(string: &str) -> String {
|
||||
if string.starts_with(".") {
|
||||
format!(".{}", string)
|
||||
} else {
|
||||
string.to_string()
|
||||
}.replace(format!("{}.", CR).as_slice(), format!("{}..", CR).as_slice())
|
||||
.replace(format!("{}.", LF).as_slice(), format!("{}..", LF).as_slice())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::{quote_email_address, unquote_email_address,
|
||||
remove_trailing_crlf, get_first_word, escape_crlf, escape_dot};
|
||||
|
||||
#[test]
|
||||
fn test_quote_email_address() {
|
||||
assert_eq!(quote_email_address("address").as_slice(), "<address>");
|
||||
assert_eq!(quote_email_address("<address>").as_slice(), "<address>");
|
||||
assert_eq!(quote_email_address("a").as_slice(), "<a>");
|
||||
assert_eq!(quote_email_address("").as_slice(), "<>");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_unquote_email_address() {
|
||||
assert_eq!(unquote_email_address("<address>"), "address");
|
||||
assert_eq!(unquote_email_address("address"), "address");
|
||||
assert_eq!(unquote_email_address("<address"), "<address");
|
||||
assert_eq!(unquote_email_address("<>"), "");
|
||||
assert_eq!(unquote_email_address("a"), "a");
|
||||
assert_eq!(unquote_email_address(""), "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_remove_trailing_crlf() {
|
||||
assert_eq!(remove_trailing_crlf("word"), "word");
|
||||
assert_eq!(remove_trailing_crlf("word\r\n"), "word");
|
||||
assert_eq!(remove_trailing_crlf("word\r\n "), "word\r\n ");
|
||||
assert_eq!(remove_trailing_crlf("word\r"), "word");
|
||||
assert_eq!(remove_trailing_crlf("\r\n"), "");
|
||||
assert_eq!(remove_trailing_crlf("\r"), "");
|
||||
assert_eq!(remove_trailing_crlf("a"), "a");
|
||||
assert_eq!(remove_trailing_crlf(""), "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_first_word() {
|
||||
assert_eq!(get_first_word("first word"), "first");
|
||||
assert_eq!(get_first_word("first word\r\ntest"), "first");
|
||||
assert_eq!(get_first_word("first"), "first");
|
||||
assert_eq!(get_first_word(""), "");
|
||||
assert_eq!(get_first_word("\r\n"), "");
|
||||
assert_eq!(get_first_word("a\r\n"), "a");
|
||||
// Manage cases of empty line, spaces at the beginning
|
||||
//assert_eq!(get_first_word(" a"), "a");
|
||||
//assert_eq!(get_first_word("\r\n a"), "a");
|
||||
assert_eq!(get_first_word(" \r\n"), "");
|
||||
assert_eq!(get_first_word("\r\n "), "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_escape_crlf() {
|
||||
assert_eq!(escape_crlf("\r\n").as_slice(), "<CR><LF>");
|
||||
assert_eq!(escape_crlf("EHLO my_name\r\n").as_slice(), "EHLO my_name<CR><LF>");
|
||||
assert_eq!(
|
||||
escape_crlf("EHLO my_name\r\nSIZE 42\r\n").as_slice(),
|
||||
"EHLO my_name<CR><LF>SIZE 42<CR><LF>"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_escape_dot() {
|
||||
assert_eq!(escape_dot(".test").as_slice(), "..test");
|
||||
assert_eq!(escape_dot("\r.\n.\r\n").as_slice(), "\r..\n..\r\n");
|
||||
assert_eq!(escape_dot("test\r\n.test\r\n").as_slice(), "test\r\n..test\r\n");
|
||||
assert_eq!(escape_dot("test\r\n.\r\ntest").as_slice(), "test\r\n..\r\ntest");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
use std::from_str::FromStr;
|
||||
use std::fmt::{Show, Formatter, Result};
|
||||
|
||||
use common::{CRLF};
|
||||
use common::CRLF;
|
||||
use response::Response;
|
||||
|
||||
/// Supported ESMTP keywords
|
||||
|
||||
@@ -64,3 +64,4 @@ pub mod response;
|
||||
pub mod transaction;
|
||||
pub mod common;
|
||||
pub mod error;
|
||||
pub mod tools;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
use std::from_str::FromStr;
|
||||
use std::fmt::{Show, Formatter, Result};
|
||||
|
||||
use common::remove_trailing_crlf;
|
||||
use tools::remove_trailing_crlf;
|
||||
|
||||
/// Contains an SMTP reply, with separed code and message
|
||||
///
|
||||
|
||||
147
src/tools.rs
Normal file
147
src/tools.rs
Normal file
@@ -0,0 +1,147 @@
|
||||
// Copyright 2014 Alexis Mousset. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Contains tools for common string manipulations
|
||||
|
||||
use std::string::String;
|
||||
use std::str::replace;
|
||||
|
||||
use common::{CR, LF, CRLF};
|
||||
|
||||
/// Adds quotes to emails if needed
|
||||
#[inline]
|
||||
pub fn quote_email_address(address: &str) -> String {
|
||||
match address.len() {
|
||||
0 ... 1 => format!("<{}>", address),
|
||||
_ => match (address.slice_to(1),
|
||||
address.slice_from(address.len() - 1)) {
|
||||
("<", ">") => address.to_string(),
|
||||
_ => format!("<{}>", address)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes quotes from emails if needed
|
||||
#[inline]
|
||||
pub fn unquote_email_address(address: &str) -> &str {
|
||||
match address.len() {
|
||||
0 ... 1 => address,
|
||||
_ => match (address.slice_to(1),
|
||||
address.slice_from(address.len() - 1)) {
|
||||
("<", ">") => address.slice(1, address.len() - 1),
|
||||
_ => address
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes the trailing line return at the end of a string
|
||||
#[inline]
|
||||
pub fn remove_trailing_crlf(string: &str) -> &str {
|
||||
if string.ends_with(CRLF) {
|
||||
string.slice_to(string.len() - 2)
|
||||
} else if string.ends_with(CR) {
|
||||
string.slice_to(string.len() - 1)
|
||||
} else {
|
||||
string
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the first word of a string, or the string if it contains no space
|
||||
#[inline]
|
||||
pub fn get_first_word(string: &str) -> &str {
|
||||
string.split_str(CRLF).next().unwrap().splitn(1, ' ').next().unwrap()
|
||||
}
|
||||
|
||||
/// Returns the string replacing all the CRLF with "<CRLF>"
|
||||
#[inline]
|
||||
pub fn escape_crlf(string: &str) -> String {
|
||||
replace(string, CRLF, "<CR><LF>")
|
||||
}
|
||||
|
||||
/// Returns the string after adding a dot at the beginning of each line starting with a dot
|
||||
///
|
||||
/// Reference : https://tools.ietf.org/html/rfc5321#page-62 (4.5.2. Transparency)
|
||||
#[inline]
|
||||
pub fn escape_dot(string: &str) -> String {
|
||||
if string.starts_with(".") {
|
||||
format!(".{}", string)
|
||||
} else {
|
||||
string.to_string()
|
||||
}.replace(format!("{}.", CR).as_slice(), format!("{}..", CR).as_slice())
|
||||
.replace(format!("{}.", LF).as_slice(), format!("{}..", LF).as_slice())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::{quote_email_address, unquote_email_address,
|
||||
remove_trailing_crlf, get_first_word, escape_crlf, escape_dot};
|
||||
|
||||
#[test]
|
||||
fn test_quote_email_address() {
|
||||
assert_eq!(quote_email_address("address").as_slice(), "<address>");
|
||||
assert_eq!(quote_email_address("<address>").as_slice(), "<address>");
|
||||
assert_eq!(quote_email_address("a").as_slice(), "<a>");
|
||||
assert_eq!(quote_email_address("").as_slice(), "<>");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_unquote_email_address() {
|
||||
assert_eq!(unquote_email_address("<address>"), "address");
|
||||
assert_eq!(unquote_email_address("address"), "address");
|
||||
assert_eq!(unquote_email_address("<address"), "<address");
|
||||
assert_eq!(unquote_email_address("<>"), "");
|
||||
assert_eq!(unquote_email_address("a"), "a");
|
||||
assert_eq!(unquote_email_address(""), "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_remove_trailing_crlf() {
|
||||
assert_eq!(remove_trailing_crlf("word"), "word");
|
||||
assert_eq!(remove_trailing_crlf("word\r\n"), "word");
|
||||
assert_eq!(remove_trailing_crlf("word\r\n "), "word\r\n ");
|
||||
assert_eq!(remove_trailing_crlf("word\r"), "word");
|
||||
assert_eq!(remove_trailing_crlf("\r\n"), "");
|
||||
assert_eq!(remove_trailing_crlf("\r"), "");
|
||||
assert_eq!(remove_trailing_crlf("a"), "a");
|
||||
assert_eq!(remove_trailing_crlf(""), "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_first_word() {
|
||||
assert_eq!(get_first_word("first word"), "first");
|
||||
assert_eq!(get_first_word("first word\r\ntest"), "first");
|
||||
assert_eq!(get_first_word("first"), "first");
|
||||
assert_eq!(get_first_word(""), "");
|
||||
assert_eq!(get_first_word("\r\n"), "");
|
||||
assert_eq!(get_first_word("a\r\n"), "a");
|
||||
// Manage cases of empty line, spaces at the beginning
|
||||
//assert_eq!(get_first_word(" a"), "a");
|
||||
//assert_eq!(get_first_word("\r\n a"), "a");
|
||||
assert_eq!(get_first_word(" \r\n"), "");
|
||||
assert_eq!(get_first_word("\r\n "), "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_escape_crlf() {
|
||||
assert_eq!(escape_crlf("\r\n").as_slice(), "<CR><LF>");
|
||||
assert_eq!(escape_crlf("EHLO my_name\r\n").as_slice(), "EHLO my_name<CR><LF>");
|
||||
assert_eq!(
|
||||
escape_crlf("EHLO my_name\r\nSIZE 42\r\n").as_slice(),
|
||||
"EHLO my_name<CR><LF>SIZE 42<CR><LF>"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_escape_dot() {
|
||||
assert_eq!(escape_dot(".test").as_slice(), "..test");
|
||||
assert_eq!(escape_dot("\r.\n.\r\n").as_slice(), "\r..\n..\r\n");
|
||||
assert_eq!(escape_dot("test\r\n.test\r\n").as_slice(), "test\r\n..test\r\n");
|
||||
assert_eq!(escape_dot("test\r\n.\r\ntest").as_slice(), "test\r\n..\r\ntest");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user