Skip to content

Commit

Permalink
Move to maildirpp
Browse files Browse the repository at this point in the history
  • Loading branch information
williamdes committed Jul 31, 2024
1 parent b2ac3ca commit ff22eff
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 58 deletions.
52 changes: 7 additions & 45 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions crates/cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ futures = "0.3.28"
pwhash = "1.0.0"
rand = "0.8.5"
mail-auth = { version = "0.4" }
maildir = { version = "0.6.4", default-features = false, optional = true }
maildirpp = { version = "0.3.0", default-features = false, optional = true }

[features]
default = ["maildir"]
maildir = ["dep:maildir"]
maildir = ["dep:maildirpp"]
112 changes: 101 additions & 11 deletions crates/cli/src/modules/export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -271,31 +271,121 @@ pub async fn fetch_emails(
results
}

#[cfg(feature = "maildir")]
fn update_mail_id(mut mail_entry: maildirpp::MailEntry, email: &jmap_client::email::Email) {
use std::os::unix::fs::MetadataExt;
use std::{
fs,
sync::atomic::{AtomicUsize, Ordering},
time::{Duration, SystemTime, UNIX_EPOCH},
};

let storage_id = email.id().unwrap_or_default();
let received_at = email.received_at();

static COUNTER: AtomicUsize = AtomicUsize::new(0);
let sequence_number = COUNTER.fetch_add(1, Ordering::SeqCst);

let meta: fs::Metadata = match mail_entry.path().metadata() {
Err(err) => {
eprintln!("Error: email {storage_id} could not fetch metadata for file: {err}");
return;
}
Ok(meta) => meta,
};

let timestamp = match received_at {
None => SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or(Duration::from_secs(0)),
Some(ts) => Duration::from_secs(ts.try_into().unwrap()),
};

let secs = timestamp.as_secs();
let nanos = timestamp.subsec_nanos();

#[cfg(unix)]
let dev = meta.dev();
#[cfg(windows)]
let dev: u64 = 0;

#[cfg(unix)]
let ino = meta.ino();
#[cfg(windows)]
let ino: u64 = 0;

#[cfg(unix)]
let size = meta.size();
#[cfg(windows)]
let size = meta.file_size();

let hostname = "todo".to_string(); //TODO: hostname

let id = format!("{secs}.#{sequence_number:x}M{nanos}V{dev}I{ino}.{hostname},S={size}");

// Update the mail ID
if let Err(err) = mail_entry.set_id(&id) {
eprintln!("Error: email {storage_id} could not update email id to {id}: {err}");
return;
}
}

#[cfg(feature = "maildir")]
async fn export_emails_maildir(
client: &jmap_client::client::Client,
max_objects_in_get: usize,
path: &Path,
) {
use maildir::Maildir;
use maildirpp::Maildir;

let emails = fetch_emails(client, max_objects_in_get).await;
let mailboxes: Vec<Mailbox> = fetch_mailboxes(client, max_objects_in_get).await;

let maildir = Maildir::from(path.join("maildir"));
if let Err(err) = maildir.create_dirs() {
eprintln!("Error: dirs count not be created: {err}");
return;
}
let maildir = match Maildir::new(path.join("maildir")) {
Err(err) => {
eprintln!("Error: maildir could not be created: {err}");
return;
}
Ok(maildir) => maildir,
};

for email in &emails {
let mailbox_names: Vec<&str> = email
.mailbox_ids()
.iter()
.map(|id| {
mailboxes
.iter()
.filter(|mb| mb.name().is_some() && mb.id().is_some())
.find(|mb| mb.id().unwrap() == *id)
})
.filter(|mb| mb.is_some())
.map(|mb| mb.unwrap().name().unwrap())
.collect();

if let Some(blob_id) = email.blob_id() {
match client.download(&blob_id).await {
Ok(bytes) => {
if let Err(err) = maildir.store_new(bytes.as_slice()) {
eprintln!(
"Error: email {:?} could not be stored: {err}",
email.id().unwrap_or_default()
);
for mailbox_name in mailbox_names {
match maildir.create_folder(mailbox_name) {
Ok(maildir_folder) => {
match maildir_folder.store_cur(bytes.as_slice()) {
Err(err) => {
eprintln!(
"Error: email {:?} could not be stored: {err}",
email.id().unwrap_or_default()
);
}
Ok(mail_entry) => {
update_mail_id(mail_entry, &email);
}
}
}
Err(err) => {
eprintln!("Error: maildir could not be created: {err}");
return;
}
}
}
}
Err(err) => {
Expand Down

0 comments on commit ff22eff

Please sign in to comment.