actually start synchronizing emails
This commit is contained in:
parent
eb880e1b92
commit
3e0e3d5561
6 changed files with 67 additions and 10 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -1954,6 +1954,7 @@ dependencies = [
|
|||
"format-bytes",
|
||||
"futures 0.3.13",
|
||||
"gluon",
|
||||
"hex 0.4.3",
|
||||
"inotify",
|
||||
"log",
|
||||
"notify-rust",
|
||||
|
@ -1962,6 +1963,7 @@ dependencies = [
|
|||
"parking_lot",
|
||||
"quoted_printable",
|
||||
"serde",
|
||||
"sha2",
|
||||
"sqlx",
|
||||
"structopt",
|
||||
"tokio 1.3.0",
|
||||
|
|
|
@ -42,6 +42,8 @@ xdg = "2.2.0"
|
|||
downcast-rs = "1.2.0"
|
||||
quoted_printable = "0.4.2"
|
||||
sqlx = { version = "0.5.1", features = ["runtime-tokio-rustls", "sqlite"] }
|
||||
sha2 = "0.9.3"
|
||||
hex = "0.4.3"
|
||||
|
||||
[dependencies.panorama-imap]
|
||||
path = "imap"
|
||||
|
|
|
@ -184,7 +184,7 @@ fn build_msg_att_static(pair: Pair<Rule>) -> AttributeValue {
|
|||
Rule::number => Some(build_number(unwrap1(pairs.next().unwrap()))),
|
||||
_ => None,
|
||||
};
|
||||
let data = Some(pairs.next().unwrap().as_str().to_owned());
|
||||
let data = build_nstring(pairs.next().unwrap());
|
||||
AttributeValue::BodySection(BodySection {
|
||||
section,
|
||||
index,
|
||||
|
|
|
@ -8,5 +8,7 @@ CREATE TABLE IF NOT EXISTS "mail" (
|
|||
"id" INTEGER PRIMARY KEY,
|
||||
"account" TEXT,
|
||||
"folder" TEXT,
|
||||
"uid" INTEGER
|
||||
"uidvalidity" INTEGER,
|
||||
"uid" INTEGER,
|
||||
"filename" TEXT
|
||||
);
|
||||
|
|
|
@ -73,14 +73,16 @@ pub async fn sync_main(
|
|||
let select = authed.select(folder).await?;
|
||||
debug!("select response: {:?}", select);
|
||||
|
||||
if let Some(exists) = select.exists {
|
||||
if let (Some(exists), Some(uidvalidity)) = (select.exists, select.uid_validity) {
|
||||
if exists < 10 {
|
||||
let mut fetched = authed
|
||||
.uid_fetch(&(1..=exists).collect::<Vec<_>>(), FetchItems::PanoramaAll)
|
||||
.await?;
|
||||
while let Some((uid, attrs)) = fetched.next().await {
|
||||
debug!("- {} : {:?}", uid, attrs);
|
||||
mail_store.store_email(&acct_name, &folder, uid).await?;
|
||||
mail_store
|
||||
.store_email(&acct_name, &folder, uid, uidvalidity, attrs)
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,9 +3,12 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use anyhow::Result;
|
||||
use panorama_imap::response::AttributeValue;
|
||||
use sha2::{Digest, Sha256, Sha512};
|
||||
use sqlx::{
|
||||
migrate::{MigrateDatabase, Migrator},
|
||||
sqlite::{Sqlite, SqlitePool},
|
||||
Error,
|
||||
};
|
||||
use tokio::fs;
|
||||
|
||||
|
@ -51,19 +54,65 @@ impl MailStore {
|
|||
acct: impl AsRef<str>,
|
||||
folder: impl AsRef<str>,
|
||||
uid: u32,
|
||||
uidvalidity: u32,
|
||||
attrs: Vec<AttributeValue>,
|
||||
) -> Result<()> {
|
||||
let id = sqlx::query(STORE_EMAIL_SQL)
|
||||
.bind(acct.as_ref())
|
||||
.bind(folder.as_ref())
|
||||
.bind(uid)
|
||||
.execute(&self.pool)
|
||||
.await?
|
||||
.last_insert_rowid();
|
||||
Ok(())
|
||||
let mut body = None;
|
||||
for attr in attrs {
|
||||
if let AttributeValue::BodySection(body_attr) = attr {
|
||||
body = body_attr.data;
|
||||
}
|
||||
}
|
||||
|
||||
const STORE_EMAIL_SQL: &str = r#"
|
||||
INSERT INTO "mail" (account, folder, uid)
|
||||
VALUES (?, ?, ?)
|
||||
"#;
|
||||
let body = match body {
|
||||
Some(v) => v,
|
||||
None => return Ok(()),
|
||||
};
|
||||
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.update(body.as_bytes());
|
||||
let hash = hasher.finalize();
|
||||
let filename = format!("{}.mail", hex::encode(hash));
|
||||
let path = self.mail_dir.join(&filename);
|
||||
fs::write(path, body).await?;
|
||||
|
||||
let existing = sqlx::query(
|
||||
r#"
|
||||
SELECT FROM "mail"
|
||||
WHERE account = ? AND folder = ?
|
||||
AND uid = ? AND uidvalidity = ?
|
||||
"#,
|
||||
)
|
||||
.bind(acct.as_ref())
|
||||
.bind(folder.as_ref())
|
||||
.bind(uid)
|
||||
.bind(uidvalidity)
|
||||
.fetch_one(&self.pool)
|
||||
.await;
|
||||
|
||||
let exists = match existing {
|
||||
Ok(_) => true,
|
||||
Err(Error::RowNotFound) => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
if !exists {
|
||||
let id = sqlx::query(
|
||||
r#"
|
||||
INSERT INTO "mail" (account, folder, uid, uidvalidity, filename)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
"#,
|
||||
)
|
||||
.bind(acct.as_ref())
|
||||
.bind(folder.as_ref())
|
||||
.bind(uid)
|
||||
.bind(uidvalidity)
|
||||
.bind(filename)
|
||||
.execute(&self.pool)
|
||||
.await?
|
||||
.last_insert_rowid();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue