From c6dca99e339ba101147c9d8830824a8a0f29b499 Mon Sep 17 00:00:00 2001 From: Gonne Date: Sun, 3 Nov 2024 08:46:55 +0100 Subject: [PATCH] Generate sieve script from hashmap --- .gitignore | 7 ++++ main.rs | 117 ++++++++++++++++++++++++++++------------------------- 2 files changed, 68 insertions(+), 56 deletions(-) diff --git a/.gitignore b/.gitignore index fcac908..9149bb3 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,10 @@ testdata/virt_aliases # Added by cargo /target + + + +# Nix +/result +# Direnv +/.direnv diff --git a/main.rs b/main.rs index f4279ee..cd31b7a 100644 --- a/main.rs +++ b/main.rs @@ -1,69 +1,74 @@ -use std::fs::File; -use std::io::{self, BufRead}; -use std::path::Path; -use std::env; +use std::io::{self}; use std::collections::HashMap; fn main() { - let args: Vec = env::args().collect(); + let redirects = parse_alias_to_hashmap(); + let sieve_script = generate_sieve_script(redirects); + println!("{}", sieve_script); +} - let file_path = &args[1]; - - // File must exist in the current path - if let Ok(lines) = read_lines(file_path) { - // Consumes the iterator, returns an (Optional) String - let mut redirect_map : HashMap> = HashMap::new(); - let mut destinations : Vec = Vec::new(); - for line in lines.flatten() { - 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(", ") - .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()))); - } +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; } } - println!("{:#?}", redirect_map); + 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 local_part = local_part.trim(); - if local_part.contains("@") { - return String::from(local_part); + let mut addr = local_part.trim().to_string(); + addr = addr.replace(",", ""); + if addr.contains("@") { + return addr; } - return local_part.to_string() + "@mathebau.de"; + return addr + "@mathebau.de"; } - -// The output is wrapped in a Result to allow matching on errors. -// Returns an Iterator to the Reader of the lines of the file. -fn read_lines

(filename: P) -> io::Result>> -where P: AsRef, { - let file = File::open(filename)?; - Ok(io::BufReader::new(file).lines()) -} \ No newline at end of file