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 { 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> { // File must exist in the current path let mut redirect_map : HashMap> = HashMap::new(); let mut destinations : Vec = 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 = 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> = 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"; }