a
This commit is contained in:
parent
aa4e336d32
commit
50bd0a83d4
3 changed files with 74 additions and 7 deletions
|
@ -3,12 +3,23 @@ CREATE TABLE "accounts" (
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE "mailboxes" (
|
CREATE TABLE "mailboxes" (
|
||||||
"account" INTEGER,
|
"account" INTEGER NOT NULL,
|
||||||
"name" TEXT,
|
"name" TEXT NOT NULL,
|
||||||
|
"uidvalidity" INTEGER NOT NULL,
|
||||||
|
|
||||||
PRIMARY KEY ("account", "name")
|
PRIMARY KEY ("account", "name")
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE "messages" (
|
CREATE TABLE "messages" (
|
||||||
"id" TEXT PRIMARY KEY
|
"id" TEXT PRIMARY KEY,
|
||||||
|
"date" DATETIME,
|
||||||
|
"subject" TEXT,
|
||||||
|
"from" JSON,
|
||||||
|
"sender" JSON,
|
||||||
|
"reply_to" JSON,
|
||||||
|
"to" JSON,
|
||||||
|
"cc" JSON,
|
||||||
|
"bcc" JSON,
|
||||||
|
"in_reply_to" TEXT,
|
||||||
|
"message_id" TEXT,
|
||||||
);
|
);
|
||||||
|
|
|
@ -219,7 +219,7 @@ impl ClientAuthenticated {
|
||||||
/// Runs the SEARCH command
|
/// Runs the SEARCH command
|
||||||
pub async fn uid_search(&mut self) -> Result<Vec<u32>> {
|
pub async fn uid_search(&mut self) -> Result<Vec<u32>> {
|
||||||
let cmd = Command::UidSearch(CommandSearch {
|
let cmd = Command::UidSearch(CommandSearch {
|
||||||
criteria: SearchCriteria::All,
|
criteria: SearchCriteria::all(),
|
||||||
});
|
});
|
||||||
let stream = self.execute(cmd).await?;
|
let stream = self.execute(cmd).await?;
|
||||||
let (_, data) = stream.wait().await?;
|
let (_, data) = stream.wait().await?;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::io::{self, Write};
|
use std::{collections::HashSet, io::{self, Write}, ops::{Bound, RangeBounds}};
|
||||||
|
|
||||||
use format_bytes::DisplayBytes;
|
use format_bytes::DisplayBytes;
|
||||||
use panorama_proto_common::{quote_string, Bytes};
|
use panorama_proto_common::{quote_string, Bytes};
|
||||||
|
@ -175,7 +175,63 @@ impl DisplayBytes for FetchItems {
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum FetchAttr {}
|
pub enum FetchAttr {}
|
||||||
|
|
||||||
|
// TODO: not the most efficient representation but I'll optimize if this ever actually becomes a
|
||||||
|
// problem
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum SearchCriteria {
|
pub struct SearchCriteria(HashSet<(Bound<u32>, Bound<u32>)>);
|
||||||
All,
|
|
||||||
|
impl SearchCriteria {
|
||||||
|
pub fn all() -> Self {
|
||||||
|
let mut set = HashSet::new();
|
||||||
|
set.insert((Bound::Unbounded, Bound::Unbounded));
|
||||||
|
SearchCriteria(set)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn contains(&self, n: u32) -> bool {
|
||||||
|
for range in self.0.iter() {
|
||||||
|
if range.contains(&n) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DisplayBytes for SearchCriteria {
|
||||||
|
fn display_bytes(&self, w: &mut dyn Write) -> io::Result<()> {
|
||||||
|
// TODO: is it faster to batch these up or not?
|
||||||
|
for (i, range) in self.0.iter().enumerate() {
|
||||||
|
if i != 0 {
|
||||||
|
write_bytes!(w, b",")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
match range.0 {
|
||||||
|
Bound::Excluded(n) => write_bytes!(w, b"{}", &(n + 1))?,
|
||||||
|
Bound::Included(n) => write_bytes!(w, b"{}", &n)?,
|
||||||
|
Bound::Unbounded => write_bytes!(w, b"*")?,
|
||||||
|
}
|
||||||
|
|
||||||
|
write_bytes!(w, b":")?;
|
||||||
|
|
||||||
|
match range.1 {
|
||||||
|
Bound::Excluded(n) => write_bytes!(w, b"{}", &(n - 1))?,
|
||||||
|
Bound::Included(n) => write_bytes!(w, b"{}", &n)?,
|
||||||
|
Bound::Unbounded => write_bytes!(w, b"*")?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn display_search_criteria() {
|
||||||
|
// TODO: is there a trivial case?
|
||||||
|
assert_eq!(format_bytes!(b"{}", SearchCriteria::all()), b"*:*");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue