Skip to content

Commit f6968c9

Browse files
committed
Read bytes when fetching or uid_fetching.
1 parent 08c2b68 commit f6968c9

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.9"
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::{SslConnector, 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;
@@ -270,13 +271,48 @@ impl<T: Read+Write> Client<T> {
270271
parse_select_or_examine(lines)
271272
}
272273

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

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

282318
/// 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

@@ -37,6 +38,12 @@ impl From<SslError<TcpStream>> for Error {
3738
}
3839
}
3940

41+
impl From<FromUtf8Error> for Error {
42+
fn from(err: FromUtf8Error) -> Error {
43+
Error::Parse(ParseError::FromUtf8(err))
44+
}
45+
}
46+
4047
impl fmt::Display for Error {
4148
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4249
match *self {
@@ -70,6 +77,10 @@ impl StdError for Error {
7077

7178
#[derive(Debug)]
7279
pub enum ParseError {
80+
// Error in the decoding of data.
81+
FromUtf8(FromUtf8Error),
82+
// Indicates an error parsing the fetch or uid fetch response.
83+
FetchResponse(String),
7384
// Indicates an error parsing the status response. Such as OK, NO, and BAD.
7485
StatusResponse(Vec<String>),
7586
// Error parsing the cabability response.
@@ -89,14 +100,17 @@ impl fmt::Display for ParseError {
89100
impl StdError for ParseError {
90101
fn description(&self) -> &str {
91102
match *self {
103+
ParseError::FromUtf8(_) => "Unable to decode the response as UTF-8.",
104+
ParseError::FetchResponse(_) => "Unable to parse fetch response.",
92105
ParseError::StatusResponse(_) => "Unable to parse status response",
93106
ParseError::Capability(_) => "Unable to parse capability response",
94107
ParseError::Authentication(_) => "Unable to parse authentication response"
95108
}
96109
}
97110

98111
fn cause(&self) -> Option<&StdError> {
99-
match *self {
112+
match self {
113+
&ParseError::FromUtf8(ref e) => Some(e),
100114
_ => None
101115
}
102116
}

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)