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 fqdn::FQDN;
|
||||
use std::collections::HashMap;
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::BTreeMap;
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::io::{self, BufRead};
|
||||
use std::path::Path;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct AliasFile {
|
||||
content: io::Lines<io::BufReader<File>>,
|
||||
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() {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
|
@ -35,16 +50,17 @@ fn main() {
|
|||
|
||||
fn generate_sieve_script(redirects: AliasMap) -> String {
|
||||
let mut script: String = "require [\"envelope\", \"copy\"];\n\n".to_string();
|
||||
for (redirect, destinations) in redirects {
|
||||
script += format!("if envelope :is \"to\" \"{}\" {{\n{}}}\n", redirect, {
|
||||
for (redirect, mut destinations) in redirects {
|
||||
script += format!("if envelope :is \"to\" \"{}\" {{\n{}}}\n", redirect.0, {
|
||||
let mut subscript: String = String::new();
|
||||
destinations.sort();
|
||||
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
|
||||
+ format!(
|
||||
" redirect \"{}\";\n",
|
||||
destinations.iter().next_back().unwrap()
|
||||
destinations.iter().next_back().unwrap().0
|
||||
)
|
||||
.as_str()
|
||||
})
|
||||
|
@ -56,7 +72,7 @@ fn generate_sieve_script(redirects: AliasMap) -> String {
|
|||
fn parse_alias_to_map(alias_files: Vec<AliasFile>) -> AliasMap {
|
||||
// File must exist in the current path
|
||||
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 line in alias_file.content {
|
||||
let line = line.unwrap();
|
||||
|
@ -65,7 +81,7 @@ fn parse_alias_to_map(alias_files: Vec<AliasFile>) -> AliasMap {
|
|||
if destination.is_empty() {
|
||||
continue;
|
||||
}
|
||||
let redirects: Vec<EmailAddress> = line
|
||||
let redirects: Vec<OrdEmailAddress> = line
|
||||
.split_at(line.find(char::is_whitespace).unwrap_or(0))
|
||||
.1
|
||||
.split(' ')
|
||||
|
@ -107,13 +123,13 @@ fn parse_alias_to_map(alias_files: Vec<AliasFile>) -> AliasMap {
|
|||
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();
|
||||
addr = addr.replace(',', "");
|
||||
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.
|
||||
|
|
Loading…
Reference in a new issue