Skip to content

Commit df93576

Browse files
committed
Read bytes when fetching or uid_fetching.
1 parent 39f8894 commit df93576

File tree

6 files changed

+61
-8
lines changed

6 files changed

+61
-8
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ path = "src/lib.rs"
1818
[dependencies]
1919
openssl = "0.8"
2020
regex = "0.2"
21+
lazy_static = "0.2"
2122

2223
[dev-dependencies]
2324
base64 = "0.2"

examples/basic.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ fn main() {
3131
match imap_socket.fetch("2", "body[text]") {
3232
Ok(lines) => {
3333
for line in lines.iter() {
34-
print!("{}", line);
34+
print!("{}", String::from_utf8(line.1.clone()).unwrap());
3535
}
3636
},
3737
Err(e) => println!("Error Fetching email 2: {}", e)

examples/gmail_oauth2.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ fn main() {
3636
match imap_socket.fetch("2", "body[text]") {
3737
Ok(lines) => {
3838
for line in lines.iter() {
39-
print!("{}", line);
39+
print!("{}", String::from_utf8(line.1.clone()).unwrap());
4040
}
4141
},
4242
Err(e) => println!("Error Fetching email 2: {}", e)

src/client.rs

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@ use std::net::{TcpStream, ToSocketAddrs};
22
use openssl::ssl::{SslContext, SslStream};
33
use std::io::{self, Read, Write};
44
use std::time::Duration;
5+
use regex::Regex;
56

67
use super::mailbox::Mailbox;
78
use super::authenticator::Authenticator;
89
use super::parse::{parse_response_ok, parse_capability, parse_select_or_examine, parse_response, parse_authenticate_response};
9-
use super::error::{Error, Result};
10+
use super::error::{Error, Result, ParseError};
1011

1112
static TAG_PREFIX: &'static str = "a";
1213
const INITIAL_TAG: u32 = 0;
@@ -268,13 +269,48 @@ impl<T: Read+Write> Client<T> {
268269
parse_select_or_examine(lines)
269270
}
270271

272+
fn fetch_result(&mut self, first_line: String) -> Result<(u32, Vec<u8>)> {
273+
lazy_static! {
274+
static ref START_RE: Regex = Regex::new("^\\* \\d+ FETCH \\D*(\\d+).*\\{(\\d+)\\}\r\n$").unwrap();
275+
}
276+
let (id, size) = if let Some(captures) = START_RE.captures(&first_line.clone()) {
277+
(captures.get(1).unwrap().as_str().parse::<u32>().unwrap(),
278+
captures.get(2).unwrap().as_str().parse::<usize>().unwrap())
279+
} else {
280+
return Err(Error::Parse(ParseError::FetchResponse(first_line)));
281+
};
282+
let mut data = Vec::new();
283+
data.resize(size, 0);
284+
try!(self.stream.read_exact(&mut data));
285+
try!(self.readline()); // should be ")\r\n"
286+
Ok((id, data))
287+
}
288+
289+
fn fetch_common(&mut self, untagged_command: &str) -> Result<Vec<(u32, Vec<u8>)>> {
290+
try!(self.run_command(untagged_command));
291+
let mut found_tag_line = false;
292+
let start_str = format!("{}{} ", TAG_PREFIX, self.tag);
293+
let mut results = Vec::new();
294+
295+
while !found_tag_line {
296+
let raw_data = try!(self.readline());
297+
let line = String::from_utf8(raw_data).unwrap();
298+
if (&*line).starts_with(&*start_str) {
299+
found_tag_line = true;
300+
} else {
301+
results.push(try!(self.fetch_result(line)));
302+
}
303+
}
304+
Ok(results)
305+
}
306+
271307
/// Fetch retreives data associated with a message in the mailbox.
272-
pub fn fetch(&mut self, sequence_set: &str, query: &str) -> Result<Vec<String>> {
273-
self.run_command_and_read_response(&format!("FETCH {} {}", sequence_set, query).to_string())
308+
pub fn fetch(&mut self, sequence_set: &str, query: &str) -> Result<Vec<(u32, Vec<u8>)>> {
309+
self.fetch_common(&format!("FETCH {} {}", sequence_set, query).to_string())
274310
}
275311

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

280316
/// Noop always succeeds, and it does nothing.

src/error.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::result;
33
use std::fmt;
44
use std::error::Error as StdError;
55
use std::net::TcpStream;
6+
use std::string::FromUtf8Error;
67

78
use openssl::ssl::HandshakeError as SslError;
89

@@ -35,6 +36,12 @@ impl From<SslError<TcpStream>> for Error {
3536
}
3637
}
3738

39+
impl From<FromUtf8Error> for Error {
40+
fn from(err: FromUtf8Error) -> Error {
41+
Error::Parse(ParseError::FromUtf8(err))
42+
}
43+
}
44+
3845
impl fmt::Display for Error {
3946
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4047
match *self {
@@ -67,6 +74,10 @@ impl StdError for Error {
6774

6875
#[derive(Debug)]
6976
pub enum ParseError {
77+
// Error in the decoding of data.
78+
FromUtf8(FromUtf8Error),
79+
// Indicates an error parsing the fetch or uid fetch response.
80+
FetchResponse(String),
7081
// Indicates an error parsing the status response. Such as OK, NO, and BAD.
7182
StatusResponse(Vec<String>),
7283
// Error parsing the cabability response.
@@ -86,14 +97,17 @@ impl fmt::Display for ParseError {
8697
impl StdError for ParseError {
8798
fn description(&self) -> &str {
8899
match *self {
100+
ParseError::FromUtf8(_) => "Unable to decode the response as UTF-8.",
101+
ParseError::FetchResponse(_) => "Unable to parse fetch response.",
89102
ParseError::StatusResponse(_) => "Unable to parse status response",
90103
ParseError::Capability(_) => "Unable to parse capability response",
91104
ParseError::Authentication(_) => "Unable to parse authentication response"
92105
}
93106
}
94107

95108
fn cause(&self) -> Option<&StdError> {
96-
match *self {
109+
match self {
110+
&ParseError::FromUtf8(ref e) => Some(e),
97111
_ => None
98112
}
99113
}

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
66
extern crate openssl;
77
extern crate regex;
8+
#[macro_use]
9+
extern crate lazy_static;
810

911
pub mod authenticator;
1012
pub mod client;

0 commit comments

Comments
 (0)