Compare commits

...

4 commits
v1.0.0 ... main

Author SHA1 Message Date
ade2ff496a Merge branch 'process-multiple-mailboxes' into 'main'
add feature to process multiple mailboxes

See merge request c4181/email2matrix-message-service!3
2024-09-21 21:15:16 +00:00
d1c3083a8f add better error handling 2024-05-19 22:49:50 -04:00
0525230731 add logging with log4rs 2024-05-19 22:21:44 -04:00
6de17253d8 add feature to process multiple mailboxes 2024-05-19 21:55:21 -04:00
4 changed files with 353 additions and 21 deletions

271
Cargo.lock generated
View file

@ -41,6 +41,18 @@ dependencies = [
"libc",
]
[[package]]
name = "anyhow"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
[[package]]
name = "arc-swap"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457"
[[package]]
name = "arrayvec"
version = "0.5.2"
@ -164,6 +176,23 @@ version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
[[package]]
name = "derivative"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "destructure_traitobject"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c877555693c14d2f84191cfd3ad8582790fc52b5e2274b40b59cf5f5cea25c7"
[[package]]
name = "directories"
version = "5.0.1"
@ -187,10 +216,12 @@ dependencies = [
[[package]]
name = "email2matrix-message-service"
version = "1.0.0"
version = "1.1.0"
dependencies = [
"confy",
"imap",
"log",
"log4rs",
"reqwest",
"serde",
"serde_json",
@ -395,6 +426,12 @@ version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904"
[[package]]
name = "humantime"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "hyper"
version = "1.3.1"
@ -581,11 +618,58 @@ version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
[[package]]
name = "lock_api"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
dependencies = [
"autocfg",
"scopeguard",
]
[[package]]
name = "log"
version = "0.4.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
dependencies = [
"serde",
]
[[package]]
name = "log-mdc"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a94d21414c1f4a51209ad204c1776a3d0765002c76c6abcb602a6f09f1e881c7"
[[package]]
name = "log4rs"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0816135ae15bd0391cf284eab37e6e3ee0a6ee63d2ceeb659862bd8d0a984ca6"
dependencies = [
"anyhow",
"arc-swap",
"chrono",
"derivative",
"fnv",
"humantime",
"libc",
"log",
"log-mdc",
"once_cell",
"parking_lot",
"rand",
"serde",
"serde-value",
"serde_json",
"serde_yaml",
"thiserror",
"thread-id",
"typemap-ors",
"winapi",
]
[[package]]
name = "memchr"
@ -705,7 +789,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.63",
]
[[package]]
@ -732,6 +816,38 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
[[package]]
name = "ordered-float"
version = "2.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c"
dependencies = [
"num-traits",
]
[[package]]
name = "parking_lot"
version = "0.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb"
dependencies = [
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.9.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
"windows-targets 0.52.5",
]
[[package]]
name = "percent-encoding"
version = "2.3.1"
@ -755,7 +871,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.63",
]
[[package]]
@ -776,6 +892,12 @@ version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
[[package]]
name = "ppv-lite86"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "proc-macro2"
version = "1.0.82"
@ -794,6 +916,45 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
]
[[package]]
name = "redox_syscall"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e"
dependencies = [
"bitflags 2.5.0",
]
[[package]]
name = "redox_users"
version = "0.4.5"
@ -927,6 +1088,12 @@ dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "security-framework"
version = "2.11.0"
@ -959,6 +1126,16 @@ dependencies = [
"serde_derive",
]
[[package]]
name = "serde-value"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c"
dependencies = [
"ordered-float",
"serde",
]
[[package]]
name = "serde_derive"
version = "1.0.202"
@ -967,7 +1144,7 @@ checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.63",
]
[[package]]
@ -1002,6 +1179,19 @@ dependencies = [
"serde",
]
[[package]]
name = "serde_yaml"
version = "0.9.34+deprecated"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
dependencies = [
"indexmap",
"itoa",
"ryu",
"serde",
"unsafe-libyaml",
]
[[package]]
name = "slab"
version = "0.4.9"
@ -1033,6 +1223,17 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "syn"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "syn"
version = "2.0.63"
@ -1100,7 +1301,17 @@ checksum = "e2470041c06ec3ac1ab38d0356a6119054dedaea53e12fbefc0de730a1c08524"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.63",
]
[[package]]
name = "thread-id"
version = "4.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0ec81c46e9eb50deaa257be2f148adf052d1fb7701cfd55ccfab2525280b70b"
dependencies = [
"libc",
"winapi",
]
[[package]]
@ -1245,6 +1456,15 @@ version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
[[package]]
name = "typemap-ors"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a68c24b707f02dd18f1e4ccceb9d49f2058c2fb86384ef9972592904d7a28867"
dependencies = [
"unsafe-any-ors",
]
[[package]]
name = "unicode-bidi"
version = "0.3.15"
@ -1266,6 +1486,21 @@ dependencies = [
"tinyvec",
]
[[package]]
name = "unsafe-any-ors"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0a303d30665362d9680d7d91d78b23f5f899504d4f08b3c4cf08d055d87c0ad"
dependencies = [
"destructure_traitobject",
]
[[package]]
name = "unsafe-libyaml"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
[[package]]
name = "url"
version = "2.5.0"
@ -1325,7 +1560,7 @@ dependencies = [
"once_cell",
"proc-macro2",
"quote",
"syn",
"syn 2.0.63",
"wasm-bindgen-shared",
]
@ -1359,7 +1594,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.63",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@ -1380,6 +1615,28 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-core"
version = "0.52.0"

View file

@ -1,6 +1,6 @@
[package]
name = "email2matrix-message-service"
version = "1.0.0"
version = "1.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@ -11,3 +11,5 @@ imap = "2.4.1"
serde = { version = "1.0.201", features = ["derive"] }
serde_json = "1.0.117"
reqwest = { version = "0.12.4", features = ["json", "blocking"] }
log = "0.4.21"
log4rs = "1.3.0"

33
log4rs.yaml Normal file
View file

@ -0,0 +1,33 @@
# Scan this file for changes every 30 seconds
refresh_rate: 30 seconds
appenders:
# An appender named "stdout" that writes to stdout
stdout:
kind: console
# An appender named "requests" that writes to a file with a custom pattern encoder
requests:
kind: file
path: "log/requests.log"
encoder:
pattern: "{d} - {m}{n}"
# Set the default logging level to "warn" and attach the "stdout" appender to the root
root:
level: debug
appenders:
- stdout
loggers:
# Raise the maximum log level for events sent to the "app::backend::db" logger to "info"
app::backend::db:
level: info
# Route log events sent to the "app::requests" logger to the "requests" appender,
# and *not* the normal appenders installed at the root
app::requests:
level: info
appenders:
- requests
additive: false

View file

@ -3,6 +3,7 @@ use std::collections::HashMap;
use std::fmt::Display;
use std::net::TcpStream;
use std::path::Path;
use log::{debug, error, info, warn};
use reqwest::blocking::Response;
use serde::{Deserialize, Serialize};
@ -10,8 +11,33 @@ use serde::{Deserialize, Serialize};
fn main() {
let args: Vec<String> = env::args().collect();
let cfg: AppConfig = confy::load_path(Path::new(&args[1])).expect("Couldn't read config");
match Path::new("log4rs.yaml").exists() {
true => log4rs::init_file("log4rs.yaml", Default::default()).unwrap(),
false => println!("No log4rs.yaml file found. Logging will not be enabled")
}
let mut imap_session = get_imap_session(&cfg);
for mailbox in cfg.mailboxes.values() {
process_mailbox(&cfg.imap.ip, &mailbox);
}
}
fn process_mailbox(imap_ip: &str, mailbox: &Mailbox) {
let mut imap_session = match get_imap_session(imap_ip, mailbox) {
Ok(x) => x,
Err(error) => {
info!("Unable to start session for {}", mailbox.user);
debug!("{}", error.0);
return;
}
};
match imap_session.select("INBOX") {
Err(error) => {
error!("Unable to select INBOX: {}", error);
return;
}
_ => {}
}
let message = get_emails(&mut imap_session);
@ -19,7 +45,7 @@ fn main() {
Some(x) => {
let mut messages_sent_successfully = Vec::new();
for email in x {
let response = post_to_hookshot(&cfg.hookshot_url, &email.1);
let response = post_to_hookshot(&mailbox.hookshot_url, &email.1);
match response {
Ok(x) => {
if x.status().is_success() {
@ -32,17 +58,16 @@ fn main() {
delete_emails(messages_sent_successfully, &mut imap_session);
},
None => println!("No emails")
None => info!("No emails for {}", mailbox.user)
}
imap_session.logout().unwrap();
}
fn get_imap_session(config: &AppConfig) -> imap::Session<TcpStream> {
let stream = TcpStream::connect(&config.imap_ip).unwrap();
fn get_imap_session(imap_ip: &str, mailbox: &Mailbox) -> Result<imap::Session<TcpStream>, (imap::Error, imap::Client<TcpStream>)> {
let stream = TcpStream::connect(imap_ip).unwrap();
let client = imap::Client::new(stream);
let mut imap_session = client.login(&config.imap_user, &config.imap_password).expect("Couldn't login");
imap_session.select("INBOX").unwrap();
let mut imap_session = client.login(&mailbox.user, &mailbox.password);
return imap_session;
}
@ -86,11 +111,16 @@ fn get_emails(imap_session: &mut imap::Session<TcpStream>) -> Option<HashMap<u32
fn delete_emails(ordinals: Vec<u32>, imap_session: &mut imap::Session<TcpStream>) {
for ordinal in ordinals {
imap_session.store(format!("{}", ordinal), "+FLAGS (\\Deleted)")
.expect("Couldn't delete message");
match imap_session.store(format!("{}", ordinal), "+FLAGS (\\Deleted)") {
Err(error) => warn!("Failed to delete message {ordinal}: {error}"),
_ => {}
}
}
imap_session.expunge().unwrap();
match imap_session.expunge() {
Err(error) => warn!("Failed to expunge session: {error}"),
_ => {}
}
}
fn post_to_hookshot(hookshot_url: &str, email: &Email) -> reqwest::Result<Response> {
@ -119,9 +149,19 @@ fn post_to_hookshot(hookshot_url: &str, email: &Email) -> reqwest::Result<Respon
#[derive(Debug, Serialize, Deserialize)]
struct AppConfig {
imap_ip: String,
imap_user: String,
imap_password: String,
imap: Imap,
mailboxes: HashMap<String, Mailbox>,
}
#[derive(Debug, Serialize, Deserialize)]
struct Imap {
ip: String
}
#[derive(Debug, Serialize, Deserialize)]
struct Mailbox {
user: String,
password: String,
hookshot_url: String
}