Save metadata in DB

This commit is contained in:
FliegendeWurst 2021-03-29 09:19:48 +02:00 committed by Arne Keller
parent 8166a79e3f
commit 094c42d696
4 changed files with 115 additions and 1 deletions

88
Cargo.lock generated
View File

@ -2,6 +2,12 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 3
[[package]]
name = "ahash"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "739f4a8db6605981345c5654f3a85b056ce52f37a39d34da03f25bf2151ea16e"
[[package]] [[package]]
name = "aho-corasick" name = "aho-corasick"
version = "0.7.15" version = "0.7.15"
@ -20,8 +26,9 @@ checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
[[package]] [[package]]
name = "ascii_table" name = "ascii_table"
version = "4.0.0-alpha" version = "4.0.0-alpha"
source = "git+https://gitlab.com/arnekeller/ascii-table.git?branch=master#2d485d6b3408ed8ef2629b6be14189a312d8c60c" source = "git+https://gitlab.com/arnekeller/ascii-table.git?branch=master#2f57befcd2af631301b633af561c7404414f6644"
dependencies = [ dependencies = [
"unicode-segmentation",
"unicode-width", "unicode-width",
] ]
@ -142,6 +149,18 @@ dependencies = [
"cfg-if", "cfg-if",
] ]
[[package]]
name = "fallible-iterator"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
[[package]]
name = "fallible-streaming-iterator"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
[[package]] [[package]]
name = "gethostname" name = "gethostname"
version = "0.2.1" version = "0.2.1"
@ -152,6 +171,24 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "hashbrown"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04"
dependencies = [
"ahash",
]
[[package]]
name = "hashlink"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d99cf782f0dc4372d26846bec3de7804ceb5df083c2d4462c0b8d2330e894fa8"
dependencies = [
"hashbrown",
]
[[package]] [[package]]
name = "imap" name = "imap"
version = "2.4.1" version = "2.4.1"
@ -186,6 +223,7 @@ dependencies = [
"itertools", "itertools",
"maildir", "maildir",
"mailparse", "mailparse",
"rusqlite",
"rustls-connector", "rustls-connector",
] ]
@ -232,6 +270,16 @@ version = "0.2.91"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8916b1f6ca17130ec6568feccee27c156ad12037880833a3b842a823236502e7" checksum = "8916b1f6ca17130ec6568feccee27c156ad12037880833a3b842a823236502e7"
[[package]]
name = "libsqlite3-sys"
version = "0.21.0"
source = "git+https://github.com/rusqlite/rusqlite?branch=master#ed3bfbdf9d9e577e8d4cff937b053a0e429a4cd7"
dependencies = [
"cc",
"pkg-config",
"vcpkg",
]
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.14" version = "0.4.14"
@ -308,6 +356,12 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de"
[[package]]
name = "pkg-config"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c"
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.24" version = "1.0.24"
@ -364,6 +418,20 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "rusqlite"
version = "0.24.2"
source = "git+https://github.com/rusqlite/rusqlite?branch=master#ed3bfbdf9d9e577e8d4cff937b053a0e429a4cd7"
dependencies = [
"bitflags",
"fallible-iterator",
"fallible-streaming-iterator",
"hashlink",
"libsqlite3-sys",
"memchr",
"smallvec",
]
[[package]] [[package]]
name = "rustls" name = "rustls"
version = "0.19.0" version = "0.19.0"
@ -450,6 +518,12 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "smallvec"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
[[package]] [[package]]
name = "spin" name = "spin"
version = "0.5.2" version = "0.5.2"
@ -484,6 +558,12 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "unicode-segmentation"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796"
[[package]] [[package]]
name = "unicode-width" name = "unicode-width"
version = "0.1.8" version = "0.1.8"
@ -502,6 +582,12 @@ version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
[[package]]
name = "vcpkg"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b00bca6106a5e23f3eee943593759b7fcddb00554332e856d990c893966879fb"
[[package]] [[package]]
name = "version_check" name = "version_check"
version = "0.9.3" version = "0.9.3"

View File

@ -15,3 +15,5 @@ mailparse = "0.13.2"
rustls-connector = "0.13.1" rustls-connector = "0.13.1"
ascii_table = { git = "https://gitlab.com/arnekeller/ascii-table.git", branch = "master" } ascii_table = { git = "https://gitlab.com/arnekeller/ascii-table.git", branch = "master" }
chrono = "0.4.19" chrono = "0.4.19"
# remove when 0.24.3 is released
rusqlite = { git = "https://github.com/rusqlite/rusqlite", branch = "master", features = ["bundled"] }

View File

@ -4,6 +4,8 @@ use itertools::Itertools;
use maildir::Maildir; use maildir::Maildir;
use inboxid::*; use inboxid::*;
use mailparse::{MailHeaderMap, parse_headers};
use rusqlite::params;
fn main() -> Result<()> { fn main() -> Result<()> {
let host = env::var("MAILHOST").expect("missing envvar MAILHOST"); let host = env::var("MAILHOST").expect("missing envvar MAILHOST");
@ -23,6 +25,7 @@ fn fetch_inbox_top(
mailbox: &str, mailbox: &str,
maildir: Maildir, maildir: Maildir,
) -> Result<()> { ) -> Result<()> {
let db = get_db()?;
let mut imap_session = connect(host, port, user, password)?; let mut imap_session = connect(host, port, user, password)?;
println!("getting capabilities.."); println!("getting capabilities..");
let caps = imap_session.capabilities()?; let caps = imap_session.capabilities()?;
@ -63,14 +66,22 @@ fn fetch_inbox_top(
let messages = imap_session.uid_fetch(&fetch_range, "RFC822")?; let messages = imap_session.uid_fetch(&fetch_range, "RFC822")?;
let mut largest_uid = prev_uid; let mut largest_uid = prev_uid;
let mut save_mail = db.prepare("INSERT INTO mail VALUES (?,?,?)")?;
for mail in messages.iter() { for mail in messages.iter() {
let uid = mail.uid.unwrap(); let uid = mail.uid.unwrap();
largest_uid = cmp::max(largest_uid, uid); largest_uid = cmp::max(largest_uid, uid);
println!("mail {:?}", uid); println!("mail {:?}", uid);
let id = format!("{}_{}", uid_validity, uid); let id = format!("{}_{}", uid_validity, uid);
let uid = ((uid_validity as u64) << 32) | uid as u64;
if !maildir.exists(&id).unwrap_or(false) { if !maildir.exists(&id).unwrap_or(false) {
let mail_data = mail.body().unwrap_or_default(); let mail_data = mail.body().unwrap_or_default();
maildir.store_new_with_id(&id, mail_data)?; maildir.store_new_with_id(&id, mail_data)?;
let headers = parse_headers(&mail_data)?.0;
let message_id = headers.get_all_values("Message-ID").join(" ");
save_mail.execute(params![mailbox, uid, message_id])?;
} }
} }
let uid = cmp::max(uid_next - 1, largest_uid); let uid = cmp::max(uid_next - 1, largest_uid);

View File

@ -2,6 +2,7 @@ use std::{env, net::TcpStream};
use imap::Session; use imap::Session;
use maildir::Maildir; use maildir::Maildir;
use rusqlite::{Connection, params};
use rustls_connector::{RustlsConnector, rustls::{ClientSession, StreamOwned}}; use rustls_connector::{RustlsConnector, rustls::{ClientSession, StreamOwned}};
pub type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>; pub type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
@ -28,3 +29,17 @@ pub fn get_maildir(mailbox: &str) -> Result<Maildir> {
maildir.create_dirs()?; maildir.create_dirs()?;
Ok(maildir) Ok(maildir)
} }
pub fn get_db() -> Result<Connection> {
let db = env::var("MAILDB").expect("missing envvar MAILDB");
let conn = Connection::open(&db)?;
conn.execute("
CREATE TABLE IF NOT EXISTS mail(
mailbox STRING NOT NULL,
uid INTEGER NOT NULL,
message_id STRING NOT NULL
)", params![])?;
Ok(conn)
}