Set of administration tools for 42l's infrastructure
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

368 lines
11 KiB

use crate::db_config::CONFIG;
use crate::db_structs::*;
use crate::globals::FastConfig;
use crate::globals::*;
use crate::main_menu;
use crate::term::*;
use crate::texts::*;
use crate::crossterm::style::{Colorize, Styler};
use crossterm::style::style;
use diskus::walk::Error::*;
use diskus::{FilesizeType, Walk};
use std::collections::HashMap;
use std::fs;
use std::fs::File;
use std::fs::ReadDir;
use std::io::Read;
use std::path::PathBuf;
use std::{thread, time};
pub fn emailacc_main(fast_config: FastConfig) -> usize {
display_template();
if fast_config.mail_cache.is_none() {
emailacc_refresh_cache(fast_config)
} else {
let mail_cache = fast_config.mail_cache.unwrap();
println!(
"Cached mail logs: {} days\nLogged emails: {} sent / {} received\n",
mail_cache.logs_days, mail_cache.logs_sent_all, mail_cache.logs_received_all
);
display_menu(&EMAILACC_MAIN_TXT, fast_config)
}
}
pub fn emailacc_chkdsk(fast_config: FastConfig) -> usize {
display_template();
print_title(&EMAILACC_MAIN_TXT, 0);
let mail_cache = fast_config.mail_cache.unwrap();
println!("Domain list");
for (dom, size) in mail_cache.size_by_domain.iter() {
println!(
"{:<15}\t\t{} MB",
style(dom).blue().bold(),
size / 1024 / 1024
);
}
println!("\n");
input_line("Press Enter to continue...");
emailacc_main(fast_config)
}
pub fn emailacc_getinfo_addr(fast_config: FastConfig) -> usize {
display_template();
print_title(&EMAILACC_MAIN_TXT, 1);
let mail_cache = fast_config.mail_cache.unwrap();
let question = "Please enter an email address:";
let addr = input_line(question).trim().to_lowercase();
println!("\nAddress: {}", style(&addr).green().bold());
// search in mailbox sizes
if let Some(a) = mail_cache.size_by_mailbox.get(&addr) {
println!("Mailbox size: {} MB", a / 1024 / 1024);
} else {
println!("{}", style("Mailbox not found.").red().bold());
};
// search in Email and Alias
if let Some(email) = Email::get_by_email(&addr) {
println!(
"\nMailbox found, owned by {}",
User::get_by_id(email.user_id).unwrap().username_plain
);
}
let alias_list = Alias::get_by_from_email(&addr);
if !alias_list.is_empty() {
println!("\nOutgoing alias found:");
} else {
println!("No outgoing alias found.");
}
for alias in alias_list {
let sent = mail_cache.logs_sent_emails.get(&alias.from_email);
let recv = mail_cache.logs_received_emails.get(&alias.from_email);
println!(
"- {:<30} -> {:<30}, {:<5} sent / {:<5} received",
style(alias.from_email).green().bold(),
alias.to_email,
sent.unwrap_or(&0),
recv.unwrap_or(&0)
);
}
let to_alias_list = Alias::get_by_to_email(&addr);
if !to_alias_list.is_empty() {
println!("\nIncoming alias found:");
} else {
println!("No incoming alias found.");
}
for alias in to_alias_list {
let sent = mail_cache.logs_sent_emails.get(&alias.to_email);
let recv = mail_cache.logs_received_emails.get(&alias.to_email);
println!(
"- {:<30} -> {:<30}, {:<5} sent / {:<5} received",
alias.from_email,
style(alias.to_email).green().bold(),
sent.unwrap_or(&0),
recv.unwrap_or(&0)
);
}
println!("\n");
input_line("Press Enter to continue...");
emailacc_main(fast_config)
}
pub fn emailacc_getinfo_user(fast_config: FastConfig) -> usize {
display_template();
print_title(&EMAILACC_MAIN_TXT, 2);
let mail_cache = fast_config.mail_cache.unwrap();
let question = "Please enter an user name:";
let user = if let Some(v) = User::get(&input_line(question).trim().to_lowercase()) {
v
} else {
println!("User not found in database");
thread::sleep(time::Duration::from_millis(2000));
return emailacc_main(fast_config);
};
println!("\nUser: {}", style(user.username_plain).green().bold());
let alias_list = Alias::get_by_user(user.id);
if !alias_list.is_empty() {
println!("\nList of aliases:");
} else {
println!("No alias found.");
}
for alias in alias_list {
let sent = mail_cache.logs_sent_emails.get(&alias.from_email);
let recv = mail_cache.logs_received_emails.get(&alias.from_email);
println!(
"- {:<30} -> {:<30}, {:<5} sent / {:<5} received",
alias.from_email,
alias.to_email,
sent.unwrap_or(&0),
recv.unwrap_or(&0)
);
}
let email_list = Email::get_by_user(user.id);
if !email_list.is_empty() {
println!("\nList of mailboxes:");
} else {
println!("No mailbox found.");
}
for email in email_list {
let size = mail_cache.size_by_mailbox.get(&email.address);
let sent = mail_cache.logs_sent_emails.get(&email.address);
let recv = mail_cache.logs_received_emails.get(&email.address);
println!(
"- {:<30} -> {:<5}, {:<5} sent / {:<5} received",
email.address,
size.unwrap_or(&0) / 1024 / 1024,
sent.unwrap_or(&0),
recv.unwrap_or(&0)
);
}
println!("\n");
input_line("Press Enter to continue...");
emailacc_main(fast_config)
}
pub fn emailacc_activetop_send(fast_config: FastConfig) -> usize {
display_template();
print_title(&EMAILACC_MAIN_TXT, 3);
let mail_cache = fast_config.mail_cache.unwrap();
let most_active_send = hashmap_biggest(&mail_cache.logs_sent_emails);
println!("List of the most active addresses (sending):");
for send in most_active_send {
println!("\t- {:<35} {} emails", send.0, send.1);
}
println!("\n");
input_line("Press Enter to continue...");
emailacc_main(fast_config)
}
pub fn emailacc_activetop_recv(fast_config: FastConfig) -> usize {
display_template();
print_title(&EMAILACC_MAIN_TXT, 4);
let mail_cache = fast_config.mail_cache.unwrap();
let most_active_recv = hashmap_biggest(&mail_cache.logs_received_emails);
println!("List of the most active addresses (reception):");
for send in most_active_recv {
println!("\t- {:<35} {} emails", send.0, send.1);
}
println!("\n");
input_line("Press Enter to continue...");
emailacc_main(fast_config)
}
pub fn emailacc_size(fast_config: FastConfig) -> usize {
display_template();
print_title(&EMAILACC_MAIN_TXT, 5);
let mail_cache = fast_config.mail_cache.unwrap();
let heaviest = hashmap_biggest(&mail_cache.size_by_mailbox);
println!("List of the biggest mailboxes:");
for send in heaviest {
println!("\t- {:<35} {} MB", send.0, send.1 / 1024 / 1024);
}
println!("\n");
input_line("Press Enter to continue...");
emailacc_main(fast_config)
}
pub fn hashmap_biggest(hash: &HashMap<String, u64>) -> Vec<(String, u64)> {
let mut biggest: Vec<(String, u64)> = Vec::new();
// returns the highest 10% or 10 items
let end = if hash.len() / 10 > 10 {
hash.len() / 10
} else {
10
};
for _ in 0..end {
let mut item: (&str, u64) = ("", 0);
for (key, val) in hash.iter() {
if val > &item.1 && !biggest.contains(&(key.clone(), *val)) {
item = (key, *val);
}
}
biggest.push((item.0.to_owned(), item.1));
}
biggest
}
// this function is very messy
pub fn emailacc_refresh_cache(fast_config: FastConfig) -> usize {
display_template();
print_title(&EMAILACC_MAIN_TXT, 6);
println!("Scanning folders for all domains...");
// analyze disk usage for all domains
let mail_storage: Vec<PathBuf> = if let Some(v) = open_dir(&CONFIG.mail_storage_path) {
v.map(|dir| dir.unwrap().path()).collect()
} else {
return main_menu(fast_config);
};
// analyze disk usage for each mailbox for each domain
let mut mailbox_array = HashMap::new();
for dom in mail_storage {
if dom.is_file() {
continue;
}
println!(
"Scanning mailboxes for domain {}...",
style(dom.to_str().unwrap().split('/').last().unwrap())
.blue()
.bold()
);
let dom_mail_storage = if let Some(v) = open_dir(dom.to_str().unwrap()) {
v
} else {
return main_menu(fast_config);
};
mailbox_array.insert(
dom.to_str().unwrap().to_owned(),
analyze_folder(dom_mail_storage),
);
}
println!("Scanning mail logs...");
// natively checks for mail.log and mail.log.1
// if reading mail.log fails, the operation is cancelled.
// if reading mail.log.1 fails, the operation keeps running with mail.log
let mut log_content =
if let Some(v) = open_log(&format!("{}{}", &CONFIG.mail_logs_path, "mail.log")) {
v
} else {
return main_menu(fast_config);
};
if let Some(u) = open_log(&format!("{}{}", &CONFIG.mail_logs_path, "mail.log.1")) {
log_content = [u, log_content].concat();
} else {
println!("mail.log.1 not found. Falling back to mail.log only.");
}
emailacc_main(FastConfig {
user: fast_config.user,
domain: fast_config.domain,
mail_cache: Some(&MailCache::init(&log_content, mailbox_array)),
})
}
fn open_log(logfile: &str) -> Option<String> {
match File::open(logfile) {
Ok(mut r) => {
let mut logstr = String::new();
if r.read_to_string(&mut logstr).is_ok() {
Some(logstr)
} else {
println!("Failed to read the file to string");
None
}
}
Err(e) => {
println!("Couldn't access the mail logs file mail.log: {:?}", e);
thread::sleep(time::Duration::from_millis(2000));
None
}
}
}
fn open_dir(folder: &str) -> Option<ReadDir> {
if let Ok(v) = fs::read_dir(folder) {
Some(v)
} else {
println!("Couldn't access the mail storage folder");
println!("Please ensure that the software has required permissions.");
thread::sleep(time::Duration::from_millis(2000));
None
}
}
fn analyze_folder(folder: ReadDir) -> HashMap<String, u64> {
let mut folder_map = HashMap::new();
for subfolder in folder {
let subf = [subfolder.expect("I/O error during folder read").path()];
let walk = Walk::new(&subf, 1, FilesizeType::DiskUsage);
let (size_in_bytes, errors) = walk.run();
for e in errors {
match e {
NoMetadataForPath(err) => println!("No metadata for : {:?}", err),
CouldNotReadDir(err) => println!("Could not read : {:?}", err),
}
}
let subf_str = subf[0].to_str().expect("Invalid unicode in subfolder");
folder_map.insert(
subf_str.split('/').last().unwrap().to_owned(),
size_in_bytes,
);
}
folder_map
}