commit
1a62f1b24b
6 changed files with 33 additions and 39 deletions
|
|
@ -26,10 +26,10 @@ macro_rules! quote {
|
||||||
|
|
||||||
fn validate_str(value: &str) -> Result<String> {
|
fn validate_str(value: &str) -> Result<String> {
|
||||||
let quoted = quote!(value);
|
let quoted = quote!(value);
|
||||||
if let Some(_) = quoted.find("\n") {
|
if quoted.find('\n').is_some() {
|
||||||
return Err(Error::Validate(ValidateError('\n')));
|
return Err(Error::Validate(ValidateError('\n')));
|
||||||
}
|
}
|
||||||
if let Some(_) = quoted.find("\r") {
|
if quoted.find('\r').is_some() {
|
||||||
return Err(Error::Validate(ValidateError('\r')));
|
return Err(Error::Validate(ValidateError('\r')));
|
||||||
}
|
}
|
||||||
Ok(quoted)
|
Ok(quoted)
|
||||||
|
|
@ -126,7 +126,7 @@ pub trait SetReadTimeout {
|
||||||
impl<'a, T: Read + Write + 'a> IdleHandle<'a, T> {
|
impl<'a, T: Read + Write + 'a> IdleHandle<'a, T> {
|
||||||
fn new(session: &'a mut Session<T>) -> Result<Self> {
|
fn new(session: &'a mut Session<T>) -> Result<Self> {
|
||||||
let mut h = IdleHandle {
|
let mut h = IdleHandle {
|
||||||
session: session,
|
session,
|
||||||
keepalive: Duration::from_secs(29 * 60),
|
keepalive: Duration::from_secs(29 * 60),
|
||||||
done: false,
|
done: false,
|
||||||
};
|
};
|
||||||
|
|
@ -239,7 +239,7 @@ impl<'a, T: Read + Write + 'a> Drop for IdleHandle<'a, T> {
|
||||||
|
|
||||||
impl<'a> SetReadTimeout for TcpStream {
|
impl<'a> SetReadTimeout for TcpStream {
|
||||||
fn set_read_timeout(&mut self, timeout: Option<Duration>) -> Result<()> {
|
fn set_read_timeout(&mut self, timeout: Option<Duration>) -> Result<()> {
|
||||||
TcpStream::set_read_timeout(self, timeout).map_err(|e| Error::Io(e))
|
TcpStream::set_read_timeout(self, timeout).map_err(Error::Io)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -247,7 +247,7 @@ impl<'a> SetReadTimeout for TlsStream<TcpStream> {
|
||||||
fn set_read_timeout(&mut self, timeout: Option<Duration>) -> Result<()> {
|
fn set_read_timeout(&mut self, timeout: Option<Duration>) -> Result<()> {
|
||||||
self.get_ref()
|
self.get_ref()
|
||||||
.set_read_timeout(timeout)
|
.set_read_timeout(timeout)
|
||||||
.map_err(|e| Error::Io(e))
|
.map_err(Error::Io)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -368,13 +368,13 @@ impl<T: Read + Write> Client<T> {
|
||||||
authenticator: A,
|
authenticator: A,
|
||||||
) -> ::std::result::Result<Session<T>, (Error, Client<T>)> {
|
) -> ::std::result::Result<Session<T>, (Error, Client<T>)> {
|
||||||
ok_or_unauth_client_err!(self.run_command(&format!("AUTHENTICATE {}", auth_type)), self);
|
ok_or_unauth_client_err!(self.run_command(&format!("AUTHENTICATE {}", auth_type)), self);
|
||||||
self.do_auth_handshake(authenticator)
|
self.do_auth_handshake(&authenticator)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This func does the handshake process once the authenticate command is made.
|
/// This func does the handshake process once the authenticate command is made.
|
||||||
fn do_auth_handshake<A: Authenticator>(
|
fn do_auth_handshake<A: Authenticator>(
|
||||||
mut self,
|
mut self,
|
||||||
authenticator: A
|
authenticator: &A
|
||||||
) -> ::std::result::Result<Session<T>, (Error, Client<T>)> {
|
) -> ::std::result::Result<Session<T>, (Error, Client<T>)> {
|
||||||
// TODO Clean up this code
|
// TODO Clean up this code
|
||||||
loop {
|
loop {
|
||||||
|
|
@ -466,7 +466,7 @@ impl <T: Read + Write> Session<T> {
|
||||||
/// server responses in RFC 3501](https://tools.ietf.org/html/rfc3501#section-7).
|
/// server responses in RFC 3501](https://tools.ietf.org/html/rfc3501#section-7).
|
||||||
pub fn fetch(&mut self, sequence_set: &str, query: &str) -> ZeroCopyResult<Vec<Fetch>> {
|
pub fn fetch(&mut self, sequence_set: &str, query: &str) -> ZeroCopyResult<Vec<Fetch>> {
|
||||||
self.run_command_and_read_response(&format!("FETCH {} {}", sequence_set, query))
|
self.run_command_and_read_response(&format!("FETCH {} {}", sequence_set, query))
|
||||||
.and_then(|lines| parse_fetches(lines))
|
.and_then(parse_fetches)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fetch retreives data associated with a set of messages by UID in the mailbox.
|
/// Fetch retreives data associated with a set of messages by UID in the mailbox.
|
||||||
|
|
@ -476,7 +476,7 @@ impl <T: Read + Write> Session<T> {
|
||||||
/// server responses in RFC 3501](https://tools.ietf.org/html/rfc3501#section-7).
|
/// server responses in RFC 3501](https://tools.ietf.org/html/rfc3501#section-7).
|
||||||
pub fn uid_fetch(&mut self, uid_set: &str, query: &str) -> ZeroCopyResult<Vec<Fetch>> {
|
pub fn uid_fetch(&mut self, uid_set: &str, query: &str) -> ZeroCopyResult<Vec<Fetch>> {
|
||||||
self.run_command_and_read_response(&format!("UID FETCH {} {}", uid_set, query))
|
self.run_command_and_read_response(&format!("UID FETCH {} {}", uid_set, query))
|
||||||
.and_then(|lines| parse_fetches(lines))
|
.and_then(parse_fetches)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Noop always succeeds, and it does nothing.
|
/// Noop always succeeds, and it does nothing.
|
||||||
|
|
@ -522,8 +522,8 @@ impl <T: Read + Write> Session<T> {
|
||||||
|
|
||||||
/// Capability requests a listing of capabilities that the server supports.
|
/// Capability requests a listing of capabilities that the server supports.
|
||||||
pub fn capabilities(&mut self) -> ZeroCopyResult<Capabilities> {
|
pub fn capabilities(&mut self) -> ZeroCopyResult<Capabilities> {
|
||||||
self.run_command_and_read_response(&format!("CAPABILITY"))
|
self.run_command_and_read_response("CAPABILITY")
|
||||||
.and_then(|lines| parse_capabilities(lines))
|
.and_then(parse_capabilities)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Expunge permanently removes all messages that have the \Deleted flag set from the currently
|
/// Expunge permanently removes all messages that have the \Deleted flag set from the currently
|
||||||
|
|
@ -546,12 +546,12 @@ impl <T: Read + Write> Session<T> {
|
||||||
/// Store alters data associated with a message in the mailbox.
|
/// Store alters data associated with a message in the mailbox.
|
||||||
pub fn store(&mut self, sequence_set: &str, query: &str) -> ZeroCopyResult<Vec<Fetch>> {
|
pub fn store(&mut self, sequence_set: &str, query: &str) -> ZeroCopyResult<Vec<Fetch>> {
|
||||||
self.run_command_and_read_response(&format!("STORE {} {}", sequence_set, query))
|
self.run_command_and_read_response(&format!("STORE {} {}", sequence_set, query))
|
||||||
.and_then(|lines| parse_fetches(lines))
|
.and_then(parse_fetches)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn uid_store(&mut self, uid_set: &str, query: &str) -> ZeroCopyResult<Vec<Fetch>> {
|
pub fn uid_store(&mut self, uid_set: &str, query: &str) -> ZeroCopyResult<Vec<Fetch>> {
|
||||||
self.run_command_and_read_response(&format!("UID STORE {} {}", uid_set, query))
|
self.run_command_and_read_response(&format!("UID STORE {} {}", uid_set, query))
|
||||||
.and_then(|lines| parse_fetches(lines))
|
.and_then(parse_fetches)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Copy copies the specified message to the end of the specified destination mailbox.
|
/// Copy copies the specified message to the end of the specified destination mailbox.
|
||||||
|
|
@ -574,7 +574,7 @@ impl <T: Read + Write> Session<T> {
|
||||||
"LIST {} {}",
|
"LIST {} {}",
|
||||||
quote!(reference_name),
|
quote!(reference_name),
|
||||||
mailbox_search_pattern
|
mailbox_search_pattern
|
||||||
)).and_then(|lines| parse_names(lines))
|
)).and_then(parse_names)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The LSUB command returns a subset of names from the set of names
|
/// The LSUB command returns a subset of names from the set of names
|
||||||
|
|
@ -588,7 +588,7 @@ impl <T: Read + Write> Session<T> {
|
||||||
"LSUB {} {}",
|
"LSUB {} {}",
|
||||||
quote!(reference_name),
|
quote!(reference_name),
|
||||||
mailbox_search_pattern
|
mailbox_search_pattern
|
||||||
)).and_then(|lines| parse_names(lines))
|
)).and_then(parse_names)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The STATUS command requests the status of the indicated mailbox.
|
/// The STATUS command requests the status of the indicated mailbox.
|
||||||
|
|
@ -623,7 +623,7 @@ impl <T: Read + Write> Session<T> {
|
||||||
// these are only here because they are public interface, the rest is in `Connection`
|
// these are only here because they are public interface, the rest is in `Connection`
|
||||||
/// Runs a command and checks if it returns OK.
|
/// Runs a command and checks if it returns OK.
|
||||||
pub fn run_command_and_check_ok(&mut self, command: &str) -> Result<()> {
|
pub fn run_command_and_check_ok(&mut self, command: &str) -> Result<()> {
|
||||||
self.run_command_and_read_response(command).map(|_| (()))
|
self.run_command_and_read_response(command).map(|_| ())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Runs any command passed to it.
|
/// Runs any command passed to it.
|
||||||
|
|
@ -654,7 +654,7 @@ impl <T: Read + Write> Connection<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_command(&mut self, untagged_command: &str) -> Result<()> {
|
fn run_command(&mut self, untagged_command: &str) -> Result<()> {
|
||||||
let command = self.create_command(untagged_command.to_string());
|
let command = self.create_command(untagged_command);
|
||||||
self.write_line(command.into_bytes().as_slice())
|
self.write_line(command.into_bytes().as_slice())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -725,12 +725,12 @@ impl <T: Read + Write> Connection<T> {
|
||||||
match status {
|
match status {
|
||||||
Status::Bad => {
|
Status::Bad => {
|
||||||
break Err(Error::BadResponse(
|
break Err(Error::BadResponse(
|
||||||
expl.unwrap_or("no explanation given".to_string()),
|
expl.unwrap_or_else(|| "no explanation given".to_string()),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
Status::No => {
|
Status::No => {
|
||||||
break Err(Error::NoResponse(
|
break Err(Error::NoResponse(
|
||||||
expl.unwrap_or("no explanation given".to_string()),
|
expl.unwrap_or_else(|| "no explanation given".to_string()),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
_ => break Err(Error::Parse(ParseError::Invalid(data.split_off(0)))),
|
_ => break Err(Error::Parse(ParseError::Invalid(data.split_off(0)))),
|
||||||
|
|
@ -758,10 +758,9 @@ impl <T: Read + Write> Connection<T> {
|
||||||
Ok(read)
|
Ok(read)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_command(&mut self, command: String) -> String {
|
fn create_command(&mut self, command: &str) -> String {
|
||||||
self.tag += 1;
|
self.tag += 1;
|
||||||
let command = format!("{}{} {}", TAG_PREFIX, self.tag, command);
|
format!("{}{} {}", TAG_PREFIX, self.tag, command)
|
||||||
return command;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_line(&mut self, buf: &[u8]) -> Result<()> {
|
fn write_line(&mut self, buf: &[u8]) -> Result<()> {
|
||||||
|
|
@ -858,14 +857,14 @@ mod tests {
|
||||||
let mut imap_stream = Client::new(mock_stream);
|
let mut imap_stream = Client::new(mock_stream);
|
||||||
|
|
||||||
let expected_command = format!("a1 {}", base_command);
|
let expected_command = format!("a1 {}", base_command);
|
||||||
let command = imap_stream.create_command(String::from(base_command));
|
let command = imap_stream.create_command(&base_command);
|
||||||
assert!(
|
assert!(
|
||||||
command == expected_command,
|
command == expected_command,
|
||||||
"expected command doesn't equal actual command"
|
"expected command doesn't equal actual command"
|
||||||
);
|
);
|
||||||
|
|
||||||
let expected_command2 = format!("a2 {}", base_command);
|
let expected_command2 = format!("a2 {}", base_command);
|
||||||
let command2 = imap_stream.create_command(String::from(base_command));
|
let command2 = imap_stream.create_command(&base_command);
|
||||||
assert!(
|
assert!(
|
||||||
command2 == expected_command2,
|
command2 == expected_command2,
|
||||||
"expected command doesn't equal actual command"
|
"expected command doesn't equal actual command"
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ use super::types::*;
|
||||||
pub fn parse_authenticate_response(line: String) -> Result<String> {
|
pub fn parse_authenticate_response(line: String) -> Result<String> {
|
||||||
let authenticate_regex = Regex::new("^+(.*)\r\n").unwrap();
|
let authenticate_regex = Regex::new("^+(.*)\r\n").unwrap();
|
||||||
|
|
||||||
for cap in authenticate_regex.captures_iter(line.as_str()) {
|
if let Some(cap) = authenticate_regex.captures_iter(line.as_str()).next() {
|
||||||
let data = cap.get(1).map(|x| x.as_str()).unwrap_or("");
|
let data = cap.get(1).map(|x| x.as_str()).unwrap_or("");
|
||||||
return Ok(String::from(data));
|
return Ok(String::from(data));
|
||||||
}
|
}
|
||||||
|
|
@ -112,9 +112,7 @@ pub fn parse_fetches(lines: Vec<u8>) -> ZeroCopyResult<Vec<Fetch>> {
|
||||||
AttributeValue::Rfc822(rfc) => fetch.rfc822 = rfc,
|
AttributeValue::Rfc822(rfc) => fetch.rfc822 = rfc,
|
||||||
AttributeValue::Rfc822Header(rfc) => fetch.rfc822_header = rfc,
|
AttributeValue::Rfc822Header(rfc) => fetch.rfc822_header = rfc,
|
||||||
AttributeValue::BodySection {
|
AttributeValue::BodySection {
|
||||||
section: _,
|
data, ..
|
||||||
index: _,
|
|
||||||
data,
|
|
||||||
} => fetch.body = data,
|
} => fetch.body = data,
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ impl Capabilities {
|
||||||
self.0.contains(s)
|
self.0.contains(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter<'a>(&'a self) -> Iter<'a, &'a str> {
|
pub fn iter(&self) -> Iter<&str> {
|
||||||
self.0.iter()
|
self.0.iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,19 +11,19 @@ pub struct Fetch {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Fetch {
|
impl Fetch {
|
||||||
pub fn flags<'a>(&'a self) -> &'a [&'a str] {
|
pub fn flags(&self) -> &[&str] {
|
||||||
&self.flags[..]
|
&self.flags[..]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rfc822_header<'a>(&'a self) -> Option<&'a [u8]> {
|
pub fn rfc822_header(&self) -> Option<&[u8]> {
|
||||||
self.rfc822_header
|
self.rfc822_header
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rfc822<'a>(&'a self) -> Option<&'a [u8]> {
|
pub fn rfc822(&self) -> Option<&[u8]> {
|
||||||
self.rfc822
|
self.rfc822
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn body<'a>(&'a self) -> Option<&'a [u8]> {
|
pub fn body(&self) -> Option<&[u8]> {
|
||||||
self.body
|
self.body
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -66,9 +66,6 @@ impl<D: PartialEq> PartialEq for ZeroCopy<D> {
|
||||||
fn eq(&self, other: &ZeroCopy<D>) -> bool {
|
fn eq(&self, other: &ZeroCopy<D>) -> bool {
|
||||||
**self == **other
|
**self == **other
|
||||||
}
|
}
|
||||||
fn ne(&self, other: &ZeroCopy<D>) -> bool {
|
|
||||||
**self != **other
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
impl<D: Eq> Eq for ZeroCopy<D> {}
|
impl<D: Eq> Eq for ZeroCopy<D> {}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,15 +8,15 @@ pub struct Name {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Name {
|
impl Name {
|
||||||
pub fn attributes<'a>(&'a self) -> &'a [&'a str] {
|
pub fn attributes(&self) -> &[&str] {
|
||||||
&self.attributes[..]
|
&self.attributes[..]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn delimiter<'a>(&'a self) -> &'a str {
|
pub fn delimiter(&self) -> &str {
|
||||||
self.delimiter
|
self.delimiter
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn name<'a>(&'a self) -> &'a str {
|
pub fn name(&self) -> &str {
|
||||||
self.name
|
self.name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue