diff --git a/.gitignore b/.gitignore index 9149bb3..532d706 100644 --- a/.gitignore +++ b/.gitignore @@ -22,11 +22,11 @@ target/ # Testdata with private mailadresses testdata/mathebau.aliases +testdata/koma.aliases # might contain private mailadresses as well testdata/virt_aliases - # Added by cargo /target diff --git a/Cargo.lock b/Cargo.lock index 2c0fdae..33171c2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,3 +5,313 @@ version = 3 [[package]] name = "alias_to_sieve" version = "0.1.0" +dependencies = [ + "email-address-parser", + "fqdn", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + +[[package]] +name = "cpufeatures" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "email-address-parser" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe19a4967eca30062be4abaf813d929ba48b3bfb21830367f7e1baae37f213a" +dependencies = [ + "console_error_panic_hook", + "pest", + "pest_derive", + "quick-xml", + "wasm-bindgen", +] + +[[package]] +name = "fqdn" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d649848b92394c9e1357f6574e48ba9b073a20ceac342f7fbfd0ab5f12524d" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "libc" +version = "0.2.164" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f" + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + +[[package]] +name = "pest" +version = "2.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d214365f632b123a47fd913301e14c946c61d1c183ee245fa76eb752e59a02dd" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb55586734301717aea2ac313f50b2eb8f60d2fc3dc01d190eefa2e625f60c4e" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pest_meta" +version = "2.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b75da2a70cf4d9cb76833c990ac9cd3923c9a8905a8929789ce347c84564d03d" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + +[[package]] +name = "proc-macro2" +version = "1.0.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quick-xml" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cc440ee4802a86e357165021e3e255a9143724da31db1e2ea540214c96a0f82" +dependencies = [ + "memchr", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "syn" +version = "2.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + +[[package]] +name = "unicode-ident" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasm-bindgen" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" diff --git a/Cargo.toml b/Cargo.toml index 622f3eb..f9f5c5b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,3 +4,7 @@ version = "0.1.0" edition = "2021" rust-version = "1.68.2" + +[dependencies] +fqdn = {version = "0.4.2", features = ["domain-label-length-limited-to-63", "domain-name-without-special-chars"]} +email-address-parser = "2.0.0" \ No newline at end of file diff --git a/flake.lock b/flake.lock index 216023f..cfd8667 100644 --- a/flake.lock +++ b/flake.lock @@ -74,11 +74,11 @@ "nixpkgs": "nixpkgs_2" }, "locked": { - "lastModified": 1732242723, - "narHash": "sha256-NWI8csIK0ujFlFuEXKnoc+7hWoCiEtINK9r48LUUMeU=", + "lastModified": 1732328983, + "narHash": "sha256-RHt12f/slrzDpSL7SSkydh8wUE4Nr4r23HlpWywed9E=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "a229311fcb45b88a95fdfa5cecd8349c809a272a", + "rev": "ed8aa5b64f7d36d9338eb1d0a3bb60cf52069a72", "type": "github" }, "original": { diff --git a/src/main.rs b/src/main.rs index 252594c..98557ae 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,15 +1,19 @@ -use std::collections::BTreeMap; +use std::collections::HashMap; use std::env; use std::fs::File; use std::io::{self, BufRead}; use std::path::Path; +use std::str::FromStr; +use fqdn::*; +use email_address_parser::EmailAddress; #[derive(Debug)] struct AliasFile { content: io::Lines>, - default_domain: String, + default_domain: FQDN, } +type AliasMap = HashMap>; fn main() { let args: Vec = env::args().collect(); @@ -20,7 +24,7 @@ fn main() { let mut alias_files : Vec = Vec::new(); for i in (1..args.len()).step_by(2) { if let Ok(lines) = read_lines(&args[i]) { - alias_files.push(AliasFile{content: lines, default_domain: args[i+1].to_string()}) + alias_files.push(AliasFile{content: lines, default_domain: FQDN::from_str(&args[i+1]).unwrap()}) } } @@ -29,13 +33,12 @@ fn main() { println!("{}", sieve_script); } -fn generate_sieve_script(redirects: BTreeMap>) -> String { +fn generate_sieve_script(redirects: AliasMap) -> String { let mut script : String = "require [\"envelope\", \"copy\"];\n\n".to_string(); - for (redirect, mut destinations) in redirects { + for (redirect, destinations) in redirects { script += format!("if envelope :is \"to\" \"{}\" {{\n{}}}\n", redirect, { let mut subscript : String = "".to_string(); - destinations.sort(); for destination in destinations.iter().rev().skip(1).rev() { subscript += format!(" redirect :copy \"{}\";\n", destination).as_str(); } @@ -46,10 +49,10 @@ fn generate_sieve_script(redirects: BTreeMap>) -> String { script } -fn parse_alias_to_map(alias_files: Vec) -> BTreeMap> { +fn parse_alias_to_map(alias_files: Vec) -> AliasMap { // File must exist in the current path - let mut redirect_map : BTreeMap> = BTreeMap::new(); - let mut destinations : Vec = Vec::new(); + let mut redirect_map : AliasMap = AliasMap::new(); + let mut destinations : Vec = Vec::new(); for alias_file in alias_files.into_iter() { for line in alias_file.content { let line = line.unwrap(); @@ -58,7 +61,7 @@ fn parse_alias_to_map(alias_files: Vec) -> BTreeMap = line.split_at(line.find(char::is_whitespace).unwrap_or(0)).1.split(" ") + let redirects: Vec = line.split_at(line.find(char::is_whitespace).unwrap_or(0)).1.split(" ") .filter(|address| address.trim().to_string().replace(",","") != "").map(|addr| to_mailaddress(addr, &alias_file.default_domain)).collect(); if redirects.is_empty() { continue; @@ -70,7 +73,7 @@ fn parse_alias_to_map(alias_files: Vec) -> BTreeMap> = BTreeMap::new(); + let mut all_new_redirects : AliasMap = AliasMap::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) { @@ -88,16 +91,15 @@ fn parse_alias_to_map(alias_files: Vec) -> BTreeMap String { +fn to_mailaddress(local_part: &str, default_domain : &FQDN) -> EmailAddress { let mut addr = local_part.trim().to_string(); addr = addr.replace(",", ""); if addr.contains("@") { - return addr; + return EmailAddress::parse(&addr, None).unwrap(); } - addr + "@" + default_domain + EmailAddress::new(&addr, &default_domain.to_string(), None).unwrap() } - // 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>> @@ -106,8 +108,7 @@ where P: AsRef, { Ok(io::BufReader::new(file).lines()) } - fn print_help(){ print!("Reads a virtual alias file and needs a default domain to append to local paths, e.g. - ./alias_to_sieve example.com.txt example.com "); + ./alias_to_sieve example.com.txt example.com"); }