Process the input
This commit is contained in:
parent
783a8b1bf2
commit
aa43eb9999
3 changed files with 80 additions and 2 deletions
46
src/input.rs
Normal file
46
src/input.rs
Normal file
|
@ -0,0 +1,46 @@
|
|||
use crate::address::CodedAddress;
|
||||
use anyhow::{anyhow, ensure, Result};
|
||||
use std::str::FromStr;
|
||||
|
||||
macro_rules! next_param {
|
||||
($it: ident) => {
|
||||
$it.next().ok_or(anyhow!("missing parameter"))
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Input {
|
||||
session_id: String,
|
||||
token: String,
|
||||
address: CodedAddress,
|
||||
}
|
||||
|
||||
impl Input {
|
||||
pub fn answer(&self, msg: &str) {
|
||||
println!("filter‐result|{0}|{1}|{msg}", self.session_id, self.token);
|
||||
}
|
||||
|
||||
pub fn get_coded_address(&self) -> &CodedAddress {
|
||||
&self.address
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_input(input: &str) -> Result<Input> {
|
||||
let mut params_it = input.split(crate::PARAM_SEPARATOR);
|
||||
let stream = next_param!(params_it)?;
|
||||
ensure!(stream == "filter", "{stream}: invalid stream");
|
||||
let _version = next_param!(params_it)?;
|
||||
let _timestamp = next_param!(params_it)?;
|
||||
let _subsystem = next_param!(params_it)?;
|
||||
let filter = next_param!(params_it)?;
|
||||
ensure!(filter == "rcpt‐to", "{filter}: invalid filter");
|
||||
let session_id = next_param!(params_it)?.to_string();
|
||||
let token = next_param!(params_it)?.to_string();
|
||||
let address = next_param!(params_it)?.trim_end();
|
||||
let address = CodedAddress::from_str(address)?;
|
||||
Ok(Input {
|
||||
session_id,
|
||||
token,
|
||||
address,
|
||||
})
|
||||
}
|
|
@ -2,11 +2,13 @@ use std::process::ExitCode;
|
|||
|
||||
mod address;
|
||||
mod config;
|
||||
mod input;
|
||||
mod service;
|
||||
|
||||
const COMMENT_CHAR: char = '#';
|
||||
const DEFAULT_SEPARATOR: char = '+';
|
||||
const KEY_SEPARATOR: char = ':';
|
||||
const PARAM_SEPARATOR: char = '|';
|
||||
|
||||
fn main() -> ExitCode {
|
||||
match service::start_service() {
|
||||
|
|
|
@ -1,14 +1,19 @@
|
|||
use crate::address::CodedAddress;
|
||||
use crate::address::KeyedAddress;
|
||||
use crate::config::Config;
|
||||
use crate::input::{parse_input, Input};
|
||||
use anyhow::Result;
|
||||
use clap::Parser;
|
||||
use std::collections::HashSet;
|
||||
use std::io;
|
||||
|
||||
pub const BUFF_SIZE: usize = 4096;
|
||||
pub const CONFIG_END: &str = "config|ready\n";
|
||||
pub const ANSWER_OK: &str = "proceed";
|
||||
pub const ANSWER_ERR: &str = "reject|550 No such recipient here";
|
||||
|
||||
pub fn start_service() -> Result<()> {
|
||||
let cfg = Config::parse();
|
||||
let addresses = cfg.addresses()?;
|
||||
let mut buffer = String::with_capacity(BUFF_SIZE);
|
||||
let stdin = io::stdin();
|
||||
|
||||
|
@ -20,12 +25,37 @@ pub fn start_service() -> Result<()> {
|
|||
break;
|
||||
}
|
||||
}
|
||||
println!("register|report|smtp‐in|tx‐rcpt");
|
||||
println!("register|filter|smtp‐in|rcpt‐to");
|
||||
println!("register|ready");
|
||||
|
||||
// Input processing
|
||||
loop {
|
||||
buffer.clear();
|
||||
stdin.read_line(&mut buffer)?;
|
||||
if buffer.is_empty() {
|
||||
continue;
|
||||
}
|
||||
match parse_input(&buffer) {
|
||||
Ok(input) => {
|
||||
if allow_email(&input, &addresses) {
|
||||
input.answer(ANSWER_OK);
|
||||
} else {
|
||||
input.answer(ANSWER_ERR);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("error: {e:#}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn allow_email(input: &Input, addr_lst: &HashSet<KeyedAddress>) -> bool {
|
||||
let address = input.get_coded_address();
|
||||
for addr_k in addr_lst {
|
||||
if addr_k == address {
|
||||
return addr_k.check_code(&address);
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue