mirror of
https://github.com/rustmailer/bichon.git
synced 2026-08-03 07:48:34 +02:00
151 lines
4.8 KiB
Rust
151 lines
4.8 KiB
Rust
//
|
|
// Copyright (c) 2025-2026 rustmailer.com (https://rustmailer.com)
|
|
//
|
|
// This file is part of the Bichon Email Archiving Project
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Affero General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Affero General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
use std::{
|
|
collections::HashMap,
|
|
fs,
|
|
path::{Path, PathBuf},
|
|
};
|
|
|
|
use console::style;
|
|
use dialoguer::{theme::ColorfulTheme, Input};
|
|
use mail_parser::MessageParser;
|
|
use reqwest::Client;
|
|
|
|
use bichon_core::base64_encode_url_safe;
|
|
|
|
use crate::{BichonCliConfig, api::sender::send_batch_request};
|
|
|
|
pub async fn handle_eml_directory_import(
|
|
config: &BichonCliConfig,
|
|
account_id: u64,
|
|
theme: &ColorfulTheme,
|
|
) {
|
|
let root_str: String = Input::with_theme(theme)
|
|
.with_prompt("Enter the ROOT directory to scan for .eml files")
|
|
.validate_with(|input: &String| {
|
|
let p = std::path::Path::new(input);
|
|
if p.exists() && p.is_dir() {
|
|
Ok(())
|
|
} else {
|
|
Err("Directory not found.")
|
|
}
|
|
})
|
|
.interact_text()
|
|
.unwrap();
|
|
|
|
let root_path = std::path::PathBuf::from(root_str);
|
|
let mut tasks: HashMap<String, Vec<PathBuf>> = HashMap::new();
|
|
println!(
|
|
"{}",
|
|
style("🔍 Scanning recursively using std::fs...").dim()
|
|
);
|
|
if let Err(e) = scan_dir(&root_path, &root_path, &mut tasks) {
|
|
eprintln!("Error scanning directory: {}", e);
|
|
return;
|
|
}
|
|
|
|
if tasks.is_empty() {
|
|
println!("{}", style("No .eml files found.").yellow());
|
|
} else {
|
|
process_and_upload(config, account_id, tasks).await;
|
|
}
|
|
}
|
|
|
|
fn scan_dir(
|
|
root: &Path,
|
|
current: &Path,
|
|
tasks: &mut HashMap<String, Vec<PathBuf>>,
|
|
) -> std::io::Result<()> {
|
|
if current.is_dir() {
|
|
for entry in fs::read_dir(current)? {
|
|
let entry = entry?;
|
|
let path = entry.path();
|
|
|
|
if path.is_dir() {
|
|
scan_dir(root, &path, tasks)?;
|
|
} else if path.is_file() {
|
|
if path.extension().and_then(|s| s.to_str()) == Some("eml") {
|
|
let rel_path = path.strip_prefix(root).unwrap_or(Path::new(""));
|
|
let mailbox_name = rel_path
|
|
.parent()
|
|
.map(|p| p.to_string_lossy().replace('\\', "/"))
|
|
.unwrap_or_default();
|
|
let folder = if mailbox_name.is_empty() {
|
|
"Inbox".to_string()
|
|
} else {
|
|
mailbox_name
|
|
};
|
|
tasks.entry(folder).or_insert_with(|| Vec::new()).push(path);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
async fn process_and_upload(
|
|
config: &BichonCliConfig,
|
|
account_id: u64,
|
|
tasks: HashMap<String, Vec<PathBuf>>,
|
|
) {
|
|
let client = Client::new();
|
|
let batch_size = 50;
|
|
|
|
for (mailbox, files) in tasks {
|
|
println!("\n🚀 Processing mailbox: {}", style(&mailbox).cyan().bold());
|
|
|
|
let mut current_batch = Vec::new();
|
|
|
|
for file_path in files {
|
|
let body = match fs::read(&file_path) {
|
|
Ok(b) => b,
|
|
Err(e) => {
|
|
eprintln!(
|
|
" {} Failed to read file {:?}: {}",
|
|
style("✘").red(),
|
|
file_path,
|
|
e
|
|
);
|
|
continue;
|
|
}
|
|
};
|
|
|
|
if MessageParser::new().parse(&body).is_some() {
|
|
let b64_content = base64_encode_url_safe!(&body);
|
|
current_batch.push(b64_content);
|
|
|
|
if current_batch.len() >= batch_size {
|
|
let to_send = current_batch;
|
|
current_batch = Vec::with_capacity(batch_size);
|
|
send_batch_request(&client, config, account_id, &mailbox, to_send).await;
|
|
}
|
|
} else {
|
|
eprintln!(
|
|
" {} Invalid format, skipping: {:?}",
|
|
style("⚠").yellow(),
|
|
file_path
|
|
);
|
|
}
|
|
}
|
|
if !current_batch.is_empty() {
|
|
send_batch_request(&client, config, account_id, &mailbox, current_batch).await;
|
|
}
|
|
}
|
|
}
|