Skip to content

Commit

Permalink
Read bytes when fetching or uid_fetching.
Browse files Browse the repository at this point in the history
  • Loading branch information
vandenoever committed Oct 31, 2017
1 parent 542ee15 commit 4ca1d15
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 7 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ path = "src/lib.rs"
native-tls = "0.1"
regex = "0.2"
bufstream = "0.1"
lazy_static = "0.2"

[dev-dependencies]
base64 = "0.7"
2 changes: 1 addition & 1 deletion examples/basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ fn main() {

match imap_socket.fetch("2", "body[text]") {
Ok(lines) => for line in lines.iter() {
print!("{}", line);
print!("{}", String::from_utf8(line.1.clone()).unwrap());
},
Err(e) => println!("Error Fetching email 2: {}", e),
};
Expand Down
2 changes: 1 addition & 1 deletion examples/gmail_oauth2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ fn main() {

match imap_socket.fetch("2", "body[text]") {
Ok(lines) => for line in lines.iter() {
print!("{}", line);
print!("{}", String::from_utf8(line.1.clone()).unwrap());
},
Err(e) => println!("Error Fetching email 2: {}", e),
};
Expand Down
44 changes: 40 additions & 4 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use native_tls::{TlsConnector, TlsStream};
use std::io::{self, Read, Write};
use std::time::Duration;
use bufstream::BufStream;
use regex::Regex;

use super::mailbox::Mailbox;
use super::authenticator::Authenticator;
Expand Down Expand Up @@ -293,13 +294,48 @@ impl<T: Read + Write> Client<T> {
parse_select_or_examine(lines)
}

fn fetch_result(&mut self, first_line: String) -> Result<(u32, Vec<u8>)> {
lazy_static! {
static ref START_RE: Regex = Regex::new("^\\* \\d+ FETCH \\D*(\\d+).*\\{(\\d+)\\}\r\n$").unwrap();
}
let (id, size) = if let Some(captures) = START_RE.captures(&first_line.clone()) {
(captures.get(1).unwrap().as_str().parse::<u32>().unwrap(),
captures.get(2).unwrap().as_str().parse::<usize>().unwrap())
} else {
return Err(Error::Parse(ParseError::FetchResponse(first_line)));
};
let mut data = Vec::new();
data.resize(size, 0);
try!(self.stream.read_exact(&mut data));
try!(self.readline()); // should be ")\r\n"
Ok((id, data))
}

fn fetch_common(&mut self, untagged_command: &str) -> Result<Vec<(u32, Vec<u8>)>> {
try!(self.run_command(untagged_command));
let mut found_tag_line = false;
let start_str = format!("{}{} ", TAG_PREFIX, self.tag);
let mut results = Vec::new();

while !found_tag_line {
let raw_data = try!(self.readline());
let line = String::from_utf8(raw_data).unwrap();
if (&*line).starts_with(&*start_str) {
found_tag_line = true;
} else {
results.push(try!(self.fetch_result(line)));
}
}
Ok(results)
}

/// Fetch retreives data associated with a message in the mailbox.
pub fn fetch(&mut self, sequence_set: &str, query: &str) -> Result<Vec<String>> {
self.run_command_and_read_response(&format!("FETCH {} {}", sequence_set, query))
pub fn fetch(&mut self, sequence_set: &str, query: &str) -> Result<Vec<(u32, Vec<u8>)>> {
self.fetch_common(&format!("FETCH {} {}", sequence_set, query).to_string())
}

pub fn uid_fetch(&mut self, uid_set: &str, query: &str) -> Result<Vec<String>> {
self.run_command_and_read_response(&format!("UID FETCH {} {}", uid_set, query))
pub fn uid_fetch(&mut self, uid_set: &str, query: &str) -> Result<Vec<(u32, Vec<u8>)>> {
self.fetch_common(&format!("UID FETCH {} {}", uid_set, query).to_string())
}

/// Noop always succeeds, and it does nothing.
Expand Down
15 changes: 14 additions & 1 deletion src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ impl From<TlsError> for Error {
}
}

impl From<FromUtf8Error> for Error {
fn from(err: FromUtf8Error) -> Error {
Error::Parse(ParseError::FromUtf8(err))
}
}

impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Expand Down Expand Up @@ -94,6 +100,10 @@ impl StdError for Error {

#[derive(Debug)]
pub enum ParseError {
// Error in the decoding of data.
FromUtf8(FromUtf8Error),
// Indicates an error parsing the fetch or uid fetch response.
FetchResponse(String),
// Indicates an error parsing the status response. Such as OK, NO, and BAD.
StatusResponse(Vec<String>),
// Error parsing the cabability response.
Expand All @@ -114,6 +124,8 @@ impl fmt::Display for ParseError {
impl StdError for ParseError {
fn description(&self) -> &str {
match *self {
ParseError::FromUtf8(_) => "Unable to decode the response as UTF-8.",
ParseError::FetchResponse(_) => "Unable to parse fetch response.",
ParseError::StatusResponse(_) => "Unable to parse status response",
ParseError::Capability(_) => "Unable to parse capability response",
ParseError::Authentication(_) => "Unable to parse authentication response",
Expand All @@ -122,7 +134,8 @@ impl StdError for ParseError {
}

fn cause(&self) -> Option<&StdError> {
match *self {
match self {
&ParseError::FromUtf8(ref e) => Some(e),
_ => None,
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
extern crate bufstream;
extern crate native_tls;
extern crate regex;
#[macro_use]
extern crate lazy_static;

pub mod authenticator;
pub mod client;
Expand Down

0 comments on commit 4ca1d15

Please sign in to comment.