1use std::io;
2use std::mem;
3
4use bytes::{BufMut, Bytes, BytesMut};
5use nom::{self, Needed};
6use tokio_util::codec::{Decoder, Encoder, Framed};
7
8use imap_proto;
9use imap_proto::types::{Request, RequestId, Response};
10
11pub struct ImapCodec {
12 decode_need_message_bytes: usize,
13}
14
15impl Default for ImapCodec {
16 fn default() -> Self {
17 Self {
18 decode_need_message_bytes: 0,
19 }
20 }
21}
22
23impl<'a> Decoder for ImapCodec {
24 type Item = ResponseData;
25 type Error = io::Error;
26 fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<Self::Item>, io::Error> {
27 if self.decode_need_message_bytes > buf.len() {
28 return Ok(None);
29 }
30 let (response, rsp_len) = match imap_proto::parse_response(buf) {
31 Ok((remaining, response)) => {
32 let response = unsafe { mem::transmute(response) };
37 (response, buf.len() - remaining.len())
38 }
39 Err(nom::Err::Incomplete(Needed::Size(min))) => {
40 self.decode_need_message_bytes = min;
41 return Ok(None);
42 }
43 Err(nom::Err::Incomplete(_)) => {
44 return Ok(None);
45 }
46 Err(nom::Err::Error((_input, err_kind)))
47 | Err(nom::Err::Failure((_input, err_kind))) => {
48 return Err(io::Error::new(
49 io::ErrorKind::Other,
50 format!("{:?} during parsing of {:?}", err_kind, buf),
51 ));
52 }
53 };
54 let raw = buf.split_to(rsp_len).freeze();
55 self.decode_need_message_bytes = 0;
56 Ok(Some(ResponseData { raw, response }))
57 }
58}
59
60impl Encoder for ImapCodec {
61 type Item = Request;
62 type Error = io::Error;
63 fn encode(&mut self, msg: Self::Item, dst: &mut BytesMut) -> Result<(), io::Error> {
64 dst.put(msg.0.as_bytes());
65 dst.put_u8(b' ');
66 dst.put_slice(&msg.1);
67 dst.put("\r\n".as_bytes());
68 Ok(())
69 }
70}
71
72#[derive(Debug)]
73pub struct ResponseData {
74 raw: Bytes,
75 response: Response<'static>,
84}
85
86impl ResponseData {
87 pub fn request_id(&self) -> Option<&RequestId> {
88 match self.response {
89 Response::Done { ref tag, .. } => Some(tag),
90 _ => None,
91 }
92 }
93 pub fn parsed<'a>(&'a self) -> &'a Response {
94 &self.response
95 }
96}
97
98pub type ImapTransport<T> = Framed<T, ImapCodec>;