Adding debugging functionality

This commit is contained in:
Matt McCoy 2016-07-14 19:58:25 -04:00
parent e033e4bcde
commit 75410ed5b5

View file

@ -9,11 +9,14 @@ use super::error::{Error, Result};
static TAG_PREFIX: &'static str = "a"; static TAG_PREFIX: &'static str = "a";
const INITIAL_TAG: u32 = 0; const INITIAL_TAG: u32 = 0;
const CR: u8 = 0x0d;
const LF: u8 = 0x0a;
/// Stream to interface with the IMAP server. This interface is only for the command stream. /// Stream to interface with the IMAP server. This interface is only for the command stream.
pub struct Client<T> { pub struct Client<T> {
stream: T, stream: T,
tag: u32 tag: u32,
pub debug: bool
} }
impl Client<TcpStream> { impl Client<TcpStream> {
@ -65,7 +68,8 @@ impl<T: Read+Write> Client<T> {
pub fn new(stream: T) -> Client<T> { pub fn new(stream: T) -> Client<T> {
Client{ Client{
stream: stream, stream: stream,
tag: INITIAL_TAG tag: INITIAL_TAG,
debug: false
} }
} }
@ -85,14 +89,7 @@ impl<T: Read+Write> Client<T> {
let data = try!(parse_authenticate_response(String::from_utf8(line).unwrap())); let data = try!(parse_authenticate_response(String::from_utf8(line).unwrap()));
let auth_response = authenticator.process(data); let auth_response = authenticator.process(data);
if let Err(e) = self.stream.write_all(auth_response.into_bytes().as_slice()) { try!(self.write_line(auth_response.into_bytes().as_slice()))
return Err(Error::Io(e));
}
if let Err(e) = self.stream.write(vec![0x0d, 0x0a].as_slice()) {
return Err(Error::Io(e));
}
} else if line.starts_with(format!("{}{} ", TAG_PREFIX, self.tag).as_bytes()) { } else if line.starts_with(format!("{}{} ", TAG_PREFIX, self.tag).as_bytes()) {
try!(parse_response(vec![String::from_utf8(line).unwrap()])); try!(parse_response(vec![String::from_utf8(line).unwrap()]));
return Ok(()); return Ok(());
@ -248,12 +245,7 @@ impl<T: Read+Write> Client<T> {
/// Runs any command passed to it. /// Runs any command passed to it.
pub fn run_command(&mut self, untagged_command: &str) -> Result<()> { pub 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.to_string());
self.write_line(command.into_bytes().as_slice())
if let Err(_) = self.stream.write_fmt(format_args!("{}", &*command)) {
return Err(Error::Io(io::Error::new(io::ErrorKind::Other, "Failed to write")));
}
return Ok(());
} }
pub fn run_command_and_read_response(&mut self, untagged_command: &str) -> Result<Vec<String>> { pub fn run_command_and_read_response(&mut self, untagged_command: &str) -> Result<Vec<String>> {
@ -284,27 +276,43 @@ impl<T: Read+Write> Client<T> {
} }
fn readline(&mut self) -> Result<Vec<u8>> { fn readline(&mut self) -> Result<Vec<u8>> {
//Carriage return
let cr = 0x0d;
//Line Feed
let lf = 0x0a;
let mut line_buffer: Vec<u8> = Vec::new(); let mut line_buffer: Vec<u8> = Vec::new();
while line_buffer.len() < 2 || (line_buffer[line_buffer.len()-1] != lf && line_buffer[line_buffer.len()-2] != cr) { while line_buffer.len() < 2 || (line_buffer[line_buffer.len()-1] != LF && line_buffer[line_buffer.len()-2] != CR) {
let byte_buffer: &mut [u8] = &mut [0]; let byte_buffer: &mut [u8] = &mut [0];
if let Err(_) = self.stream.read(byte_buffer) { if let Err(_) = self.stream.read(byte_buffer) {
return Err(Error::Io(io::Error::new(io::ErrorKind::Other, "Failed to read line"))); return Err(Error::Io(io::Error::new(io::ErrorKind::Other, "Failed to read line")));
} }
line_buffer.push(byte_buffer[0]); line_buffer.push(byte_buffer[0]);
} }
if self.debug {
let mut line = line_buffer.clone();
// Remove CRLF
line.truncate(line_buffer.len()-2);
print!("S: {}\n", String::from_utf8(line).unwrap());
}
Ok(line_buffer) Ok(line_buffer)
} }
fn create_command(&mut self, command: String) -> String { fn create_command(&mut self, command: String) -> String {
self.tag += 1; self.tag += 1;
let command = format!("{}{} {}\r\n", TAG_PREFIX, self.tag, command); let command = format!("{}{} {}", TAG_PREFIX, self.tag, command);
return command; return command;
} }
fn write_line(&mut self, buf: &[u8]) -> Result<()> {
if let Err(_) = self.stream.write_all(buf) {
return Err(Error::Io(io::Error::new(io::ErrorKind::Other, "Failed to write buf")));
}
if let Err(_) = self.stream.write_all(&[CR, LF]) {
return Err(Error::Io(io::Error::new(io::ErrorKind::Other, "Failed to write CRLF")));
}
if self.debug {
print!("C: {}\n", String::from_utf8(buf.to_vec()).unwrap());
}
Ok(())
}
} }
#[cfg(test)] #[cfg(test)]
@ -346,11 +354,11 @@ mod tests {
let mock_stream = MockStream::new(Vec::new()); let mock_stream = MockStream::new(Vec::new());
let mut imap_stream = Client::new(mock_stream); let mut imap_stream = Client::new(mock_stream);
let expected_command = format!("a1 {}\r\n", 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(String::from(base_command));
assert!(command == expected_command, "expected command doesn't equal actual command"); assert!(command == expected_command, "expected command doesn't equal actual command");
let expected_command2 = format!("a2 {}\r\n", 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(String::from(base_command));
assert!(command2 == expected_command2, "expected command doesn't equal actual command"); assert!(command2 == expected_command2, "expected command doesn't equal actual command");
} }