sync: select destination read-write so PERMANENTFLAGS is real (flags were dropped)
This commit is contained in:
1 parent
7e01130172
commit
f723e1eaa8
3 files changed
+14
-4
No files matched your search
+11
-1
@@ -60,6 +60,9 @@ pub struct SelectInfo {
|
|||||||
pub exists: u32,
|
pub exists: u32,
|
||||||
pub uidvalidity: Option<u32>,
|
pub uidvalidity: Option<u32>,
|
||||||
pub permanent_flags: Option<Vec<String>>,
|
pub permanent_flags: Option<Vec<String>>,
|
||||||
|
/// EXAMINE / [READ-ONLY]: PERMANENTFLAGS is then empty and says nothing
|
||||||
|
/// about what APPEND will keep.
|
||||||
|
pub read_only: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SelectInfo {
|
impl SelectInfo {
|
||||||
@@ -67,6 +70,7 @@ impl SelectInfo {
|
|||||||
pub fn accepts_flag(&self, f: &str) -> bool {
|
pub fn accepts_flag(&self, f: &str) -> bool {
|
||||||
match &self.permanent_flags {
|
match &self.permanent_flags {
|
||||||
None => true,
|
None => true,
|
||||||
|
Some(_) if self.read_only => true,
|
||||||
Some(p) => {
|
Some(p) => {
|
||||||
p.iter().any(|x| x.eq_ignore_ascii_case(f)) || (!f.starts_with('\\') && p.iter().any(|x| x == "\\*"))
|
p.iter().any(|x| x.eq_ignore_ascii_case(f)) || (!f.starts_with('\\') && p.iter().any(|x| x == "\\*"))
|
||||||
}
|
}
|
||||||
@@ -426,7 +430,10 @@ impl Client {
|
|||||||
let mut args = vec![Arg::Raw(format!("{verb} "))];
|
let mut args = vec![Arg::Raw(format!("{verb} "))];
|
||||||
args.push(mailbox_arg(wire));
|
args.push(mailbox_arg(wire));
|
||||||
let r = self.run(args, &format!("{verb} {wire}")).await?;
|
let r = self.run(args, &format!("{verb} {wire}")).await?;
|
||||||
let mut info = SelectInfo::default();
|
let mut info = SelectInfo {
|
||||||
|
read_only: readonly || r.status.code.as_deref().is_some_and(|c| c.eq_ignore_ascii_case("READ-ONLY")),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
for u in &r.untagged {
|
for u in &r.untagged {
|
||||||
if let Some(s) = u.status() {
|
if let Some(s) = u.status() {
|
||||||
if let Some(code) = s.code {
|
if let Some(code) = s.code {
|
||||||
@@ -673,5 +680,8 @@ mod tests {
|
|||||||
assert!(!s.accepts_flag("\\Flagged"));
|
assert!(!s.accepts_flag("\\Flagged"));
|
||||||
let s = SelectInfo { permanent_flags: Some(vec!["\\Seen".into()]), ..Default::default() };
|
let s = SelectInfo { permanent_flags: Some(vec!["\\Seen".into()]), ..Default::default() };
|
||||||
assert!(!s.accepts_flag("$Forwarded"));
|
assert!(!s.accepts_flag("$Forwarded"));
|
||||||
|
// EXAMINE: PERMANENTFLAGS () is meaningless for APPEND
|
||||||
|
let s = SelectInfo { permanent_flags: Some(vec![]), read_only: true, ..Default::default() };
|
||||||
|
assert!(s.accepts_flag("\\Seen"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+2
-2
@@ -375,9 +375,9 @@ pub async fn sync_account(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
let (dinfo, dst_meta) = if exists || !opts.dry_run {
|
let (dinfo, dst_meta) = if exists || !opts.dry_run {
|
||||||
let readonly = opts.dry_run || !opts.sync_flags;
|
// Read-write unless dry-run: EXAMINE reports empty PERMANENTFLAGS.
|
||||||
let dinfo = d
|
let dinfo = d
|
||||||
.select(&fm.dst_wire, readonly)
|
.select(&fm.dst_wire, opts.dry_run)
|
||||||
.await
|
.await
|
||||||
.with_context(|| format!("destination folder {}", fm.dst_name))?;
|
.with_context(|| format!("destination folder {}", fm.dst_name))?;
|
||||||
let meta = if dinfo.exists > 0 { d.fetch_meta().await? } else { Vec::new() };
|
let meta = if dinfo.exists > 0 { d.fetch_meta().await? } else { Vec::new() };
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ def inspect(user, password):
|
|||||||
if not isinstance(item, tuple):
|
if not isinstance(item, tuple):
|
||||||
continue
|
continue
|
||||||
meta, hdr = item
|
meta, hdr = item
|
||||||
flags = re.search(rb"FLAGS \((.*?)\)", meta).group(1).decode().split()
|
flags = [f for f in re.search(rb"FLAGS \((.*?)\)", meta).group(1).decode().split() if f != "\\Recent"]
|
||||||
date = re.search(rb'INTERNALDATE "(.*?)"', meta).group(1).decode()
|
date = re.search(rb'INTERNALDATE "(.*?)"', meta).group(1).decode()
|
||||||
size = int(re.search(rb"RFC822.SIZE (\d+)", meta).group(1))
|
size = int(re.search(rb"RFC822.SIZE (\d+)", meta).group(1))
|
||||||
mid = re.search(rb"Message-ID: <(.*?)>", hdr, re.I)
|
mid = re.search(rb"Message-ID: <(.*?)>", hdr, re.I)
|
||||||
|
|||||||
Reference in new issue
Block a user