Generate sieve script from hashmap
This commit is contained in:
parent
184d8c543e
commit
c6dca99e33
2 changed files with 68 additions and 56 deletions
7
.gitignore
vendored
7
.gitignore
vendored
|
@ -29,3 +29,10 @@ testdata/virt_aliases
|
||||||
|
|
||||||
# Added by cargo
|
# Added by cargo
|
||||||
/target
|
/target
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Nix
|
||||||
|
/result
|
||||||
|
# Direnv
|
||||||
|
/.direnv
|
||||||
|
|
115
main.rs
115
main.rs
|
@ -1,69 +1,74 @@
|
||||||
use std::fs::File;
|
use std::io::{self};
|
||||||
use std::io::{self, BufRead};
|
|
||||||
use std::path::Path;
|
|
||||||
use std::env;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let args: Vec<String> = env::args().collect();
|
let redirects = parse_alias_to_hashmap();
|
||||||
|
let sieve_script = generate_sieve_script(redirects);
|
||||||
|
println!("{}", sieve_script);
|
||||||
|
}
|
||||||
|
|
||||||
let file_path = &args[1];
|
fn generate_sieve_script(redirects: HashMap<String, Vec<String>>) -> String {
|
||||||
|
let mut script : String = "require [\"envelope\", \"copy\"];\n".to_string();
|
||||||
// File must exist in the current path
|
for (redirect, destinations) in redirects {
|
||||||
if let Ok(lines) = read_lines(file_path) {
|
script += format!("if envelope :is \"to\" \"{}\" {{\n{}}}\n", redirect,
|
||||||
// Consumes the iterator, returns an (Optional) String
|
(|| {
|
||||||
let mut redirect_map : HashMap<String, Vec<String>> = HashMap::new();
|
let mut subscript : String = "".to_string();
|
||||||
let mut destinations : Vec<String> = Vec::new();
|
for destination in destinations.iter().rev().skip(1).rev() {
|
||||||
for line in lines.flatten() {
|
subscript += format!(" redirect :copy \"{}\";\n", destination).as_str();
|
||||||
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(", ")
|
|
||||||
.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())));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
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
|
||||||
for (destination, new_redirect) in all_new_redirects {
|
let mut redirect_map : HashMap<String, Vec<String>> = HashMap::new();
|
||||||
*redirect_map.get_mut(&destination).unwrap() = new_redirect;
|
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())));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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 {
|
fn to_mailaddress(local_part: &str) -> String {
|
||||||
let local_part = local_part.trim();
|
let mut addr = local_part.trim().to_string();
|
||||||
if local_part.contains("@") {
|
addr = addr.replace(",", "");
|
||||||
return String::from(local_part);
|
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<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
|
|
||||||
where P: AsRef<Path>, {
|
|
||||||
let file = File::open(filename)?;
|
|
||||||
Ok(io::BufReader::new(file).lines())
|
|
||||||
}
|
}
|
Loading…
Reference in a new issue