use super::{BodyStructure, Envelope, Flag};
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq, Eq, Default, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct FetchResponse {
pub seq: u32,
pub uid: Option<u32>,
pub flags: Option<Vec<Flag>>,
pub envelope: Option<Envelope>,
pub body_structure: Option<BodyStructure>,
pub rfc822_size: Option<u64>,
pub internal_date: Option<String>,
pub body_sections: Vec<BodySection>,
pub mod_seq: Option<u64>,
pub save_date: Option<String>,
pub binary_sections: Vec<BinarySection>,
pub binary_sizes: Vec<(Vec<u32>, u64)>,
pub preview: Option<String>,
pub email_id: Option<String>,
pub thread_id: Option<String>,
}
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq, Eq, Default, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct BinarySection {
pub section: Vec<u32>,
pub origin: Option<u64>,
pub data: Option<Vec<u8>>,
}
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq, Eq, Default, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct BodySection {
pub section: String,
pub origin: Option<u64>,
pub data: Option<Vec<u8>>,
}
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum FetchAttr {
Uid,
Flags,
Envelope,
BodyStructure,
Rfc822Size,
InternalDate,
Rfc822,
Rfc822Header,
Rfc822Text,
BodySection {
peek: bool,
section: Option<String>,
partial: Option<(u64, u64)>,
},
ModSeq,
SaveDate,
Binary {
peek: bool,
section: Vec<u32>,
partial: Option<(u64, u64)>,
},
BinarySize {
section: Vec<u32>,
},
Preview,
PreviewLazy,
EmailId,
ThreadId,
}
impl FetchAttr {
pub fn to_imap_string(&self) -> String {
use std::fmt::Write;
match self {
Self::Uid => "UID".into(),
Self::Flags => "FLAGS".into(),
Self::Envelope => "ENVELOPE".into(),
Self::BodyStructure => "BODYSTRUCTURE".into(),
Self::Rfc822Size => "RFC822.SIZE".into(),
Self::InternalDate => "INTERNALDATE".into(),
Self::Rfc822 => "RFC822".into(),
Self::Rfc822Header => "RFC822.HEADER".into(),
Self::Rfc822Text => "RFC822.TEXT".into(),
Self::BodySection {
peek,
section,
partial,
} => {
let mut s = if *peek {
"BODY.PEEK[".to_owned()
} else {
"BODY[".to_owned()
};
if let Some(sec) = section {
s.push_str(sec);
}
s.push(']');
if let Some((offset, count)) = partial {
let _ = write!(s, "<{offset}.{count}>");
}
s
}
Self::ModSeq => "MODSEQ".into(),
Self::SaveDate => "SAVEDATE".into(),
Self::Binary {
peek,
section,
partial,
} => {
let mut s = if *peek {
"BINARY.PEEK[".to_owned()
} else {
"BINARY[".to_owned()
};
let sec_str: Vec<String> = section
.iter()
.map(std::string::ToString::to_string)
.collect();
s.push_str(&sec_str.join("."));
s.push(']');
if let Some((offset, count)) = partial {
let _ = write!(s, "<{offset}.{count}>");
}
s
}
Self::BinarySize { section } => {
let sec_str: Vec<String> = section
.iter()
.map(std::string::ToString::to_string)
.collect();
format!("BINARY.SIZE[{}]", sec_str.join("."))
}
Self::Preview => "PREVIEW".into(),
Self::PreviewLazy => "PREVIEW (LAZY)".into(),
Self::EmailId => "EMAILID".into(),
Self::ThreadId => "THREADID".into(),
}
}
}
pub(crate) fn format_fetch_attrs(attrs: &[FetchAttr]) -> String {
if attrs.len() == 1 {
attrs[0].to_imap_string()
} else {
let items: Vec<String> = attrs.iter().map(FetchAttr::to_imap_string).collect();
format!("({})", items.join(" "))
}
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum StoreOperation {
Add,
Remove,
Replace,
AddSilent,
RemoveSilent,
ReplaceSilent,
}
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq, Eq, Default, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct StoreResult {
pub fetches: Vec<FetchResponse>,
pub code: Option<super::response::ResponseCode>,
}
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct AppendMessage {
pub flags: Vec<Flag>,
pub date: Option<String>,
pub data: Vec<u8>,
}
impl AppendMessage {
pub fn new(data: impl Into<Vec<u8>>) -> Self {
Self {
flags: Vec::new(),
date: None,
data: data.into(),
}
}
}
#[cfg(test)]
#[path = "fetch_tests.rs"]
mod tests;