BackendOp: change fetch_flags retval to Result<Flag>

memfd
Manos Pitsidianakis 2020-06-28 16:53:52 +03:00
parent ee10cdbcd5
commit 8c1fc031e5
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
8 changed files with 85 additions and 114 deletions

View File

@ -415,7 +415,7 @@ pub trait MailBackend: ::std::fmt::Debug + Send + Sync {
/// fn as_bytes(&mut self) -> Result<&[u8]> { /// fn as_bytes(&mut self) -> Result<&[u8]> {
/// unimplemented!() /// unimplemented!()
/// } /// }
/// fn fetch_flags(&self) -> Flag { /// fn fetch_flags(&self) -> Result<Flag> {
/// unimplemented!() /// unimplemented!()
/// } /// }
/// } /// }
@ -426,7 +426,7 @@ pub trait MailBackend: ::std::fmt::Debug + Send + Sync {
pub trait BackendOp: ::std::fmt::Debug + ::std::marker::Send { pub trait BackendOp: ::std::fmt::Debug + ::std::marker::Send {
fn description(&self) -> String; fn description(&self) -> String;
fn as_bytes(&mut self) -> Result<&[u8]>; fn as_bytes(&mut self) -> Result<&[u8]>;
fn fetch_flags(&self) -> Flag; fn fetch_flags(&self) -> Result<Flag>;
fn set_flag(&mut self, envelope: &mut Envelope, flag: Flag, value: bool) -> Result<()>; fn set_flag(&mut self, envelope: &mut Envelope, flag: Flag, value: bool) -> Result<()>;
fn set_tag(&mut self, envelope: &mut Envelope, tag: String, value: bool) -> Result<()>; fn set_tag(&mut self, envelope: &mut Envelope, tag: String, value: bool) -> Result<()>;
} }
@ -453,7 +453,7 @@ impl BackendOp for ReadOnlyOp {
fn as_bytes(&mut self) -> Result<&[u8]> { fn as_bytes(&mut self) -> Result<&[u8]> {
self.op.as_bytes() self.op.as_bytes()
} }
fn fetch_flags(&self) -> Flag { fn fetch_flags(&self) -> Result<Flag> {
self.op.fetch_flags() self.op.fetch_flags()
} }
fn set_flag(&mut self, _envelope: &mut Envelope, _flag: Flag, _value: bool) -> Result<()> { fn set_flag(&mut self, _envelope: &mut Envelope, _flag: Flag, _value: bool) -> Result<()> {

View File

@ -109,63 +109,48 @@ impl BackendOp for ImapOp {
Ok(self.bytes.as_ref().unwrap().as_bytes()) Ok(self.bytes.as_ref().unwrap().as_bytes())
} }
fn fetch_flags(&self) -> Flag { fn fetch_flags(&self) -> Result<Flag> {
macro_rules! or_return_default {
($expr:expr) => {
match $expr {
Ok(ok) => ok,
Err(_) => return Default::default(),
}
};
}
if self.flags.get().is_some() { if self.flags.get().is_some() {
return self.flags.get().unwrap(); return Ok(self.flags.get().unwrap());
} }
let mut bytes_cache = or_return_default!(self.uid_store.byte_cache.lock()); let mut bytes_cache = self.uid_store.byte_cache.lock()?;
let cache = bytes_cache.entry(self.uid).or_default(); let cache = bytes_cache.entry(self.uid).or_default();
if cache.flags.is_some() { if cache.flags.is_some() {
self.flags.set(cache.flags); self.flags.set(cache.flags);
} else { } else {
let mut response = String::with_capacity(8 * 1024); let mut response = String::with_capacity(8 * 1024);
let mut conn = or_return_default!(try_lock( let mut conn = try_lock(&self.connection, Some(std::time::Duration::new(2, 0)))?;
&self.connection, conn.examine_mailbox(self.mailbox_hash, &mut response, false)?;
Some(std::time::Duration::new(2, 0)) conn.send_command(format!("UID FETCH {} FLAGS", self.uid).as_bytes())?;
)); conn.read_response(&mut response, RequiredResponses::FETCH_REQUIRED)?;
or_return_default!(conn.examine_mailbox(self.mailbox_hash, &mut response, false));
or_return_default!(
conn.send_command(format!("UID FETCH {} FLAGS", self.uid).as_bytes())
);
or_return_default!(conn.read_response(&mut response, RequiredResponses::FETCH_REQUIRED));
debug!( debug!(
"fetch response is {} bytes and {} lines", "fetch response is {} bytes and {} lines",
response.len(), response.len(),
response.lines().collect::<Vec<&str>>().len() response.lines().collect::<Vec<&str>>().len()
); );
match protocol_parser::uid_fetch_flags_response(response.as_bytes()) let v = protocol_parser::uid_fetch_flags_response(response.as_bytes())
.map(|(_, v)| v) .map(|(_, v)| v)
.map_err(MeliError::from) .map_err(MeliError::from)?;
{ if v.len() != 1 {
Ok(v) => { debug!("responses len is {}", v.len());
if v.len() != 1 { debug!(&response);
debug!("responses len is {}", v.len()); /* TODO: Trigger cache invalidation here. */
debug!(response); debug!(format!("message with UID {} was not found", self.uid));
/* TODO: Trigger cache invalidation here. */ return Err(
debug!(format!("message with UID {} was not found", self.uid)); MeliError::new(format!("Invalid/unexpected response: {:?}", response))
return Flag::default(); .set_summary(format!("message with UID {} was not found?", self.uid)),
} );
let (uid, (flags, _)) = v[0];
assert_eq!(uid, self.uid);
cache.flags = Some(flags);
self.flags.set(Some(flags));
}
Err(e) => or_return_default!(Err(e)),
} }
let (uid, (flags, _)) = v[0];
assert_eq!(uid, self.uid);
cache.flags = Some(flags);
self.flags.set(Some(flags));
} }
self.flags.get().unwrap() Ok(self.flags.get().unwrap())
} }
fn set_flag(&mut self, _envelope: &mut Envelope, f: Flag, value: bool) -> Result<()> { fn set_flag(&mut self, _envelope: &mut Envelope, f: Flag, value: bool) -> Result<()> {
let mut flags = self.fetch_flags(); let mut flags = self.fetch_flags()?;
flags.set(f, value); flags.set(f, value);
let mut response = String::with_capacity(8 * 1024); let mut response = String::with_capacity(8 * 1024);

View File

@ -97,8 +97,8 @@ impl BackendOp for JmapOp {
Ok(&self.bytes.as_ref().unwrap().as_bytes()) Ok(&self.bytes.as_ref().unwrap().as_bytes())
} }
fn fetch_flags(&self) -> Flag { fn fetch_flags(&self) -> Result<Flag> {
Flag::default() Ok(Flag::default())
} }
fn set_flag(&mut self, _envelope: &mut Envelope, _f: Flag, _value: bool) -> Result<()> { fn set_flag(&mut self, _envelope: &mut Envelope, _f: Flag, _value: bool) -> Result<()> {

View File

@ -101,9 +101,9 @@ impl<'a> BackendOp for MaildirOp {
Ok(unsafe { self.slice.as_ref().unwrap().as_slice() }) Ok(unsafe { self.slice.as_ref().unwrap().as_slice() })
} }
fn fetch_flags(&self) -> Flag { fn fetch_flags(&self) -> Result<Flag> {
let path = self.path(); let path = self.path();
path.flags() Ok(path.flags())
} }
fn set_flag(&mut self, envelope: &mut Envelope, f: Flag, value: bool) -> Result<()> { fn set_flag(&mut self, envelope: &mut Envelope, f: Flag, value: bool) -> Result<()> {
@ -114,7 +114,7 @@ impl<'a> BackendOp for MaildirOp {
.ok_or_else(|| MeliError::new(format!("Invalid email filename: {:?}", self)))? .ok_or_else(|| MeliError::new(format!("Invalid email filename: {:?}", self)))?
+ 3; + 3;
let mut new_name: String = path[..idx].to_string(); let mut new_name: String = path[..idx].to_string();
let mut flags = self.fetch_flags(); let mut flags = self.fetch_flags()?;
flags.set(f, value); flags.set(f, value);
if !(flags & Flag::DRAFT).is_empty() { if !(flags & Flag::DRAFT).is_empty() {

View File

@ -201,72 +201,60 @@ impl BackendOp for MboxOp {
}) })
} }
fn fetch_flags(&self) -> Flag { fn fetch_flags(&self) -> Result<Flag> {
let mut flags = Flag::empty(); let mut flags = Flag::empty();
let file = match std::fs::OpenOptions::new() let file = std::fs::OpenOptions::new()
.read(true) .read(true)
.write(true) .write(true)
.open(&self.path) .open(&self.path)?;
{
Ok(f) => f,
Err(e) => {
debug!(e);
return flags;
}
};
get_rw_lock_blocking(&file); get_rw_lock_blocking(&file);
let mut buf_reader = BufReader::new(file); let mut buf_reader = BufReader::new(file);
let mut contents = Vec::new(); let mut contents = Vec::new();
if let Err(e) = buf_reader.read_to_end(&mut contents) { buf_reader.read_to_end(&mut contents)?;
debug!(e); let (_, headers) = parser::headers::headers_raw(contents.as_slice())?;
return flags; if let Some(start) = headers.find(b"Status:") {
}; if let Some(end) = headers[start..].find(b"\n") {
let start = start + b"Status:".len();
if let Ok((_, headers)) = parser::headers::headers_raw(contents.as_slice()) { let status = headers[start..start + end].trim();
if let Some(start) = headers.find(b"Status:") { if status.contains(&b'F') {
if let Some(end) = headers[start..].find(b"\n") { flags.set(Flag::FLAGGED, true);
let start = start + b"Status:".len();
let status = headers[start..start + end].trim();
if status.contains(&b'F') {
flags.set(Flag::FLAGGED, true);
}
if status.contains(&b'A') {
flags.set(Flag::REPLIED, true);
}
if status.contains(&b'R') {
flags.set(Flag::SEEN, true);
}
if status.contains(&b'D') {
flags.set(Flag::TRASHED, true);
}
if status.contains(&b'T') {
flags.set(Flag::DRAFT, true);
}
} }
} if status.contains(&b'A') {
if let Some(start) = headers.find(b"X-Status:") { flags.set(Flag::REPLIED, true);
let start = start + b"X-Status:".len(); }
if let Some(end) = headers[start..].find(b"\n") { if status.contains(&b'R') {
let status = headers[start..start + end].trim(); flags.set(Flag::SEEN, true);
if status.contains(&b'F') { }
flags.set(Flag::FLAGGED, true); if status.contains(&b'D') {
} flags.set(Flag::TRASHED, true);
if status.contains(&b'A') { }
flags.set(Flag::REPLIED, true); if status.contains(&b'T') {
} flags.set(Flag::DRAFT, true);
if status.contains(&b'R') {
flags.set(Flag::SEEN, true);
}
if status.contains(&b'D') {
flags.set(Flag::TRASHED, true);
}
if status.contains(&b'T') {
flags.set(Flag::DRAFT, true);
}
} }
} }
} }
flags if let Some(start) = headers.find(b"X-Status:") {
let start = start + b"X-Status:".len();
if let Some(end) = headers[start..].find(b"\n") {
let status = headers[start..start + end].trim();
if status.contains(&b'F') {
flags.set(Flag::FLAGGED, true);
}
if status.contains(&b'A') {
flags.set(Flag::REPLIED, true);
}
if status.contains(&b'R') {
flags.set(Flag::SEEN, true);
}
if status.contains(&b'D') {
flags.set(Flag::TRASHED, true);
}
if status.contains(&b'T') {
flags.set(Flag::DRAFT, true);
}
}
}
Ok(flags)
} }
fn set_flag(&mut self, _envelope: &mut Envelope, _flag: Flag, _value: bool) -> Result<()> { fn set_flag(&mut self, _envelope: &mut Envelope, _flag: Flag, _value: bool) -> Result<()> {
@ -915,7 +903,7 @@ impl MailBackend for MboxType {
Err(MeliError::new("Unimplemented.")) Err(MeliError::new("Unimplemented."))
} }
fn as_any(&self) -> &dyn::std::any::Any { fn as_any(&self) -> &dyn ::std::any::Any {
self self
} }
} }

View File

@ -624,7 +624,7 @@ impl MailBackend for NotmuchDb {
crate::backends::MaildirType::save_to_mailbox(path, bytes, flags) crate::backends::MaildirType::save_to_mailbox(path, bytes, flags)
} }
fn as_any(&self) -> &dyn::std::any::Any { fn as_any(&self) -> &dyn ::std::any::Any {
self self
} }
@ -667,7 +667,7 @@ impl BackendOp for NotmuchOp {
Ok(self.bytes.as_ref().unwrap().as_bytes()) Ok(self.bytes.as_ref().unwrap().as_bytes())
} }
fn fetch_flags(&self) -> Flag { fn fetch_flags(&self) -> Result<Flag> {
let mut message: *mut notmuch_message_t = std::ptr::null_mut(); let mut message: *mut notmuch_message_t = std::ptr::null_mut();
let index_lck = self.index.write().unwrap(); let index_lck = self.index.write().unwrap();
unsafe { unsafe {
@ -678,11 +678,11 @@ impl BackendOp for NotmuchOp {
) )
}; };
let (flags, _tags) = TagIterator::new(self.lib.clone(), message).collect_flags_and_tags(); let (flags, _tags) = TagIterator::new(self.lib.clone(), message).collect_flags_and_tags();
flags Ok(flags)
} }
fn set_flag(&mut self, envelope: &mut Envelope, f: Flag, value: bool) -> Result<()> { fn set_flag(&mut self, envelope: &mut Envelope, f: Flag, value: bool) -> Result<()> {
let mut flags = self.fetch_flags(); let mut flags = self.fetch_flags()?;
flags.set(f, value); flags.set(f, value);
envelope.set_flags(flags); envelope.set_flags(flags);
let mut message: *mut notmuch_message_t = std::ptr::null_mut(); let mut message: *mut notmuch_message_t = std::ptr::null_mut();

View File

@ -225,7 +225,7 @@ impl Envelope {
} }
pub fn from_token(mut operation: Box<dyn BackendOp>, hash: EnvelopeHash) -> Option<Envelope> { pub fn from_token(mut operation: Box<dyn BackendOp>, hash: EnvelopeHash) -> Option<Envelope> {
let mut e = Envelope::new(hash); let mut e = Envelope::new(hash);
e.flags = operation.fetch_flags(); e.flags = operation.fetch_flags().unwrap_or_default();
if let Ok(bytes) = operation.as_bytes() { if let Ok(bytes) = operation.as_bytes() {
let res = e.populate_headers(bytes).ok(); let res = e.populate_headers(bytes).ok();
if res.is_some() { if res.is_some() {

View File

@ -225,7 +225,7 @@ impl MailBackend for PluginBackend {
fn tags(&self) -> Option<Arc<RwLock<BTreeMap<u64, String>>>> { fn tags(&self) -> Option<Arc<RwLock<BTreeMap<u64, String>>>> {
self.tag_index.clone() self.tag_index.clone()
} }
fn as_any(&self) -> &dyn::std::any::Any { fn as_any(&self) -> &dyn ::std::any::Any {
self self
} }
} }
@ -314,10 +314,8 @@ impl BackendOp for PluginOp {
} }
} }
fn fetch_flags(&self) -> Flag { fn fetch_flags(&self) -> Result<Flag> {
let flag = Flag::default(); Err(MeliError::new("Unimplemented."))
flag
} }
fn set_flag(&mut self, __envelope: &mut Envelope, _f: Flag, _value: bool) -> Result<()> { fn set_flag(&mut self, __envelope: &mut Envelope, _f: Flag, _value: bool) -> Result<()> {