Reintroduce ordering
This commit is contained in:
parent
2cc90cd920
commit
390e714233
2 changed files with 29 additions and 13 deletions
40
src/main.rs
40
src/main.rs
|
@ -1,19 +1,34 @@
|
||||||
use email_address_parser::EmailAddress;
|
use email_address_parser::EmailAddress;
|
||||||
use fqdn::FQDN;
|
use fqdn::FQDN;
|
||||||
use std::collections::HashMap;
|
use std::cmp::Ordering;
|
||||||
|
use std::collections::BTreeMap;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{self, BufRead};
|
use std::io::{self, BufRead};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct AliasFile {
|
struct AliasFile {
|
||||||
content: io::Lines<io::BufReader<File>>,
|
content: io::Lines<io::BufReader<File>>,
|
||||||
default_domain: FQDN,
|
default_domain: FQDN,
|
||||||
}
|
}
|
||||||
|
|
||||||
type AliasMap = HashMap<EmailAddress, Vec<EmailAddress>>;
|
#[derive(PartialEq, Eq, Clone)]
|
||||||
|
struct OrdEmailAddress(EmailAddress);
|
||||||
|
|
||||||
|
impl PartialOrd for OrdEmailAddress {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
|
Some(self.0.to_string().cmp(&other.0.to_string()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ord for OrdEmailAddress {
|
||||||
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
|
self.0.to_string().cmp(&other.0.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type AliasMap = BTreeMap<OrdEmailAddress, Vec<OrdEmailAddress>>;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let args: Vec<String> = env::args().collect();
|
let args: Vec<String> = env::args().collect();
|
||||||
|
@ -35,16 +50,17 @@ fn main() {
|
||||||
|
|
||||||
fn generate_sieve_script(redirects: AliasMap) -> String {
|
fn generate_sieve_script(redirects: AliasMap) -> String {
|
||||||
let mut script: String = "require [\"envelope\", \"copy\"];\n\n".to_string();
|
let mut script: String = "require [\"envelope\", \"copy\"];\n\n".to_string();
|
||||||
for (redirect, destinations) in redirects {
|
for (redirect, mut destinations) in redirects {
|
||||||
script += format!("if envelope :is \"to\" \"{}\" {{\n{}}}\n", redirect, {
|
script += format!("if envelope :is \"to\" \"{}\" {{\n{}}}\n", redirect.0, {
|
||||||
let mut subscript: String = String::new();
|
let mut subscript: String = String::new();
|
||||||
|
destinations.sort();
|
||||||
for destination in destinations.iter().rev().skip(1).rev() {
|
for destination in destinations.iter().rev().skip(1).rev() {
|
||||||
subscript += format!(" redirect :copy \"{destination}\";\n").as_str();
|
subscript += format!(" redirect :copy \"{}\";\n", destination.0).as_str();
|
||||||
}
|
}
|
||||||
subscript
|
subscript
|
||||||
+ format!(
|
+ format!(
|
||||||
" redirect \"{}\";\n",
|
" redirect \"{}\";\n",
|
||||||
destinations.iter().next_back().unwrap()
|
destinations.iter().next_back().unwrap().0
|
||||||
)
|
)
|
||||||
.as_str()
|
.as_str()
|
||||||
})
|
})
|
||||||
|
@ -56,7 +72,7 @@ fn generate_sieve_script(redirects: AliasMap) -> String {
|
||||||
fn parse_alias_to_map(alias_files: Vec<AliasFile>) -> AliasMap {
|
fn parse_alias_to_map(alias_files: Vec<AliasFile>) -> AliasMap {
|
||||||
// File must exist in the current path
|
// File must exist in the current path
|
||||||
let mut redirect_map: AliasMap = AliasMap::new();
|
let mut redirect_map: AliasMap = AliasMap::new();
|
||||||
let mut destinations: Vec<EmailAddress> = Vec::new();
|
let mut destinations: Vec<OrdEmailAddress> = Vec::new();
|
||||||
for alias_file in alias_files {
|
for alias_file in alias_files {
|
||||||
for line in alias_file.content {
|
for line in alias_file.content {
|
||||||
let line = line.unwrap();
|
let line = line.unwrap();
|
||||||
|
@ -65,7 +81,7 @@ fn parse_alias_to_map(alias_files: Vec<AliasFile>) -> AliasMap {
|
||||||
if destination.is_empty() {
|
if destination.is_empty() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let redirects: Vec<EmailAddress> = line
|
let redirects: Vec<OrdEmailAddress> = line
|
||||||
.split_at(line.find(char::is_whitespace).unwrap_or(0))
|
.split_at(line.find(char::is_whitespace).unwrap_or(0))
|
||||||
.1
|
.1
|
||||||
.split(' ')
|
.split(' ')
|
||||||
|
@ -107,13 +123,13 @@ fn parse_alias_to_map(alias_files: Vec<AliasFile>) -> AliasMap {
|
||||||
redirect_map
|
redirect_map
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_mailaddress(local_part: &str, default_domain: &FQDN) -> EmailAddress {
|
fn to_mailaddress(local_part: &str, default_domain: &FQDN) -> OrdEmailAddress {
|
||||||
let mut addr = local_part.trim().to_string();
|
let mut addr = local_part.trim().to_string();
|
||||||
addr = addr.replace(',', "");
|
addr = addr.replace(',', "");
|
||||||
if addr.contains('@') {
|
if addr.contains('@') {
|
||||||
return EmailAddress::parse(&addr, None).unwrap();
|
return OrdEmailAddress(EmailAddress::parse(&addr, None).unwrap());
|
||||||
}
|
}
|
||||||
EmailAddress::new(&addr, &default_domain.to_string(), None).unwrap()
|
OrdEmailAddress(EmailAddress::new(&addr, &default_domain.to_string(), None).unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
// The output is wrapped in a Result to allow matching on errors.
|
// The output is wrapped in a Result to allow matching on errors.
|
||||||
|
|
Loading…
Reference in a new issue