alias_to_sieve/main.rs

74 lines
3 KiB
Rust

use std::io::{self};
use std::collections::HashMap;
fn main() {
let redirects = parse_alias_to_hashmap();
let sieve_script = generate_sieve_script(redirects);
println!("{}", sieve_script);
}
fn generate_sieve_script(redirects: HashMap<String, Vec<String>>) -> String {
let mut script : String = "require [\"envelope\", \"copy\"];\n".to_string();
for (redirect, destinations) in redirects {
script += format!("if envelope :is \"to\" \"{}\" {{\n{}}}\n", redirect,
(|| {
let mut subscript : String = "".to_string();
for destination in destinations.iter().rev().skip(1).rev() {
subscript += format!(" redirect :copy \"{}\";\n", destination).as_str();
}
subscript += format!(" redirect \"{}\";\n", destinations.iter().rev().next().unwrap()).as_str();
return subscript;
})()
).as_str();
}
return script;
}
fn parse_alias_to_hashmap() -> HashMap<String, Vec<String>> {
// File must exist in the current path
let mut redirect_map : HashMap<String, Vec<String>> = HashMap::new();
let mut destinations : Vec<String> = Vec::new();
for line in io::stdin().lines() {
let line = line.unwrap();
let line = String::from(line.split_at(line.find("#").unwrap_or(line.len())).0);
let destination = line.split_at(line.find(char::is_whitespace).unwrap_or(0)).0;
if destination == "" {
continue;
}
let redirects: Vec<String> = line.split_at(line.find(char::is_whitespace).unwrap_or(0)).1.split(" ")
.filter(|address| address.trim().to_string().replace(",","") != "").map(|address| to_mailaddress(address)).collect();
if redirects.len() == 0 {
continue;
}
destinations.push(to_mailaddress(destination));
redirect_map.insert(to_mailaddress(destination), redirects);
}
let mut changed = true;
while changed {
changed = false;
let mut all_new_redirects : HashMap<String, Vec<String>> = HashMap::new();
for destination in destinations.iter() {
for forward_to in redirect_map.get(destination).unwrap().iter() {
if let Some(new_redirects) = redirect_map.get(forward_to) {
changed = true;
all_new_redirects.entry(destination.clone()).or_insert(redirect_map.get(destination).unwrap().clone())
.retain(|dest| *dest != *forward_to);
all_new_redirects.entry(destination.clone()).and_modify(|d| d.extend(new_redirects.iter().map(|x| x.clone())));
}
}
}
for (destination, new_redirect) in all_new_redirects {
*redirect_map.get_mut(&destination).unwrap() = new_redirect;
}
}
return redirect_map;
}
fn to_mailaddress(local_part: &str) -> String {
let mut addr = local_part.trim().to_string();
addr = addr.replace(",", "");
if addr.contains("@") {
return addr;
}
return addr + "@mathebau.de";
}