update dependencies

This commit is contained in:
Shautvast 2026-03-02 14:58:44 +01:00
parent 3b131fefe8
commit e2badaa170
6 changed files with 64 additions and 168 deletions

138
Cargo.lock generated
View file

@ -362,9 +362,9 @@ checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06"
[[package]] [[package]]
name = "bcrypt" name = "bcrypt"
version = "0.15.1" version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e65938ed058ef47d92cf8b346cc76ef48984572ade631927e9937b5ffc7662c7" checksum = "2b1866ecef4f2d06a0bb77880015fdf2b89e25a1c2e5addacb87e459c86dc67e"
dependencies = [ dependencies = [
"base64 0.22.1", "base64 0.22.1",
"blowfish 0.9.1", "blowfish 0.9.1",
@ -399,9 +399,9 @@ checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
[[package]] [[package]]
name = "bitfield" name = "bitfield"
version = "0.14.0" version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d7e60934ceec538daadb9d8432424ed043a904d8e0243f3c6446bce549a46ac" checksum = "f798d2d157e547aa99aab0967df39edd0b70307312b6f8bd2848e6abe40896e0"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
@ -888,7 +888,7 @@ dependencies = [
"cpufeatures", "cpufeatures",
"curve25519-dalek-derive", "curve25519-dalek-derive",
"digest 0.10.7", "digest 0.10.7",
"fiat-crypto 0.2.9", "fiat-crypto",
"rustc_version", "rustc_version",
"subtle", "subtle",
"zeroize", "zeroize",
@ -1156,23 +1156,23 @@ dependencies = [
[[package]] [[package]]
name = "dirs" name = "dirs"
version = "5.0.1" version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e"
dependencies = [ dependencies = [
"dirs-sys", "dirs-sys",
] ]
[[package]] [[package]]
name = "dirs-sys" name = "dirs-sys"
version = "0.4.1" version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab"
dependencies = [ dependencies = [
"libc", "libc",
"option-ext", "option-ext",
"redox_users", "redox_users",
"windows-sys 0.48.0", "windows-sys 0.61.2",
] ]
[[package]] [[package]]
@ -1277,17 +1277,6 @@ dependencies = [
"zeroize", "zeroize",
] ]
[[package]]
name = "ed448-goldilocks"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87b5fa9e9e3dd5fe1369f380acd3dcdfa766dbd0a1cd5b048fb40e38a6a78e79"
dependencies = [
"fiat-crypto 0.1.20",
"hex",
"subtle",
]
[[package]] [[package]]
name = "either" name = "either"
version = "1.15.0" version = "1.15.0"
@ -1477,12 +1466,6 @@ dependencies = [
"subtle", "subtle",
] ]
[[package]]
name = "fiat-crypto"
version = "0.1.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e825f6987101665dea6ec934c09ec6d721de7bc1bf92248e1d5810c8cd636b77"
[[package]] [[package]]
name = "fiat-crypto" name = "fiat-crypto"
version = "0.2.9" version = "0.2.9"
@ -2452,9 +2435,9 @@ dependencies = [
[[package]] [[package]]
name = "mailparse" name = "mailparse"
version = "0.15.0" version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3da03d5980411a724e8aaf7b61a7b5e386ec55a7fb49ee3d0ff79efc7e5e7c7e" checksum = "60819a97ddcb831a5614eb3b0174f3620e793e97e09195a395bfa948fd68ed2f"
dependencies = [ dependencies = [
"charset", "charset",
"data-encoding", "data-encoding",
@ -3016,9 +2999,9 @@ dependencies = [
[[package]] [[package]]
name = "pgp" name = "pgp"
version = "0.14.2" version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1877a97fd422433220ad272eb008ec55691944b1200e9eb204e3cb2cb69d34e9" checksum = "30249ac8a98b356b473b04bc5358c75a260aa96a295d0743ce752fe7b173f235"
dependencies = [ dependencies = [
"aes", "aes",
"aes-gcm", "aes-gcm",
@ -3074,10 +3057,9 @@ dependencies = [
"sha3", "sha3",
"signature", "signature",
"smallvec", "smallvec",
"thiserror 1.0.69", "thiserror 2.0.18",
"twofish", "twofish",
"x25519-dalek", "x25519-dalek",
"x448",
"zeroize", "zeroize",
] ]
@ -3371,10 +3353,8 @@ dependencies = [
name = "proton-bridge" name = "proton-bridge"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"aes",
"base64 0.22.1", "base64 0.22.1",
"bcrypt", "bcrypt",
"cfb-mode",
"chrono", "chrono",
"env_logger", "env_logger",
"keyring", "keyring",
@ -3385,7 +3365,6 @@ dependencies = [
"reqwest", "reqwest",
"serde", "serde",
"serde_json", "serde_json",
"sha1",
"sha2 0.10.9", "sha2 0.10.9",
"tokio", "tokio",
"toml", "toml",
@ -3633,13 +3612,13 @@ dependencies = [
[[package]] [[package]]
name = "redox_users" name = "redox_users"
version = "0.4.6" version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac"
dependencies = [ dependencies = [
"getrandom 0.2.17", "getrandom 0.2.17",
"libredox", "libredox",
"thiserror 1.0.69", "thiserror 2.0.18",
] ]
[[package]] [[package]]
@ -4258,9 +4237,9 @@ dependencies = [
[[package]] [[package]]
name = "subtle" name = "subtle"
version = "2.6.1" version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
[[package]] [[package]]
name = "syn" name = "syn"
@ -5157,15 +5136,6 @@ dependencies = [
"windows-link", "windows-link",
] ]
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets 0.48.5",
]
[[package]] [[package]]
name = "windows-sys" name = "windows-sys"
version = "0.52.0" version = "0.52.0"
@ -5202,21 +5172,6 @@ dependencies = [
"windows-link", "windows-link",
] ]
[[package]]
name = "windows-targets"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [
"windows_aarch64_gnullvm 0.48.5",
"windows_aarch64_msvc 0.48.5",
"windows_i686_gnu 0.48.5",
"windows_i686_msvc 0.48.5",
"windows_x86_64_gnu 0.48.5",
"windows_x86_64_gnullvm 0.48.5",
"windows_x86_64_msvc 0.48.5",
]
[[package]] [[package]]
name = "windows-targets" name = "windows-targets"
version = "0.52.6" version = "0.52.6"
@ -5250,12 +5205,6 @@ dependencies = [
"windows_x86_64_msvc 0.53.1", "windows_x86_64_msvc 0.53.1",
] ]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]] [[package]]
name = "windows_aarch64_gnullvm" name = "windows_aarch64_gnullvm"
version = "0.52.6" version = "0.52.6"
@ -5268,12 +5217,6 @@ version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]] [[package]]
name = "windows_aarch64_msvc" name = "windows_aarch64_msvc"
version = "0.52.6" version = "0.52.6"
@ -5286,12 +5229,6 @@ version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]] [[package]]
name = "windows_i686_gnu" name = "windows_i686_gnu"
version = "0.52.6" version = "0.52.6"
@ -5316,12 +5253,6 @@ version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]] [[package]]
name = "windows_i686_msvc" name = "windows_i686_msvc"
version = "0.52.6" version = "0.52.6"
@ -5334,12 +5265,6 @@ version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]] [[package]]
name = "windows_x86_64_gnu" name = "windows_x86_64_gnu"
version = "0.52.6" version = "0.52.6"
@ -5352,12 +5277,6 @@ version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]] [[package]]
name = "windows_x86_64_gnullvm" name = "windows_x86_64_gnullvm"
version = "0.52.6" version = "0.52.6"
@ -5370,12 +5289,6 @@ version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]] [[package]]
name = "windows_x86_64_msvc" name = "windows_x86_64_msvc"
version = "0.52.6" version = "0.52.6"
@ -5503,17 +5416,6 @@ dependencies = [
"zeroize", "zeroize",
] ]
[[package]]
name = "x448"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4cd07d4fae29e07089dbcacf7077cd52dce7760125ca9a4dd5a35ca603ffebb"
dependencies = [
"ed448-goldilocks",
"hex",
"rand_core 0.5.1",
]
[[package]] [[package]]
name = "xdg-home" name = "xdg-home"
version = "1.3.0" version = "1.3.0"

View file

@ -6,11 +6,8 @@ name = "tuimail"
version = "0.1.0" version = "0.1.0"
edition = "2024" edition = "2024"
[features]
proton = ["dep:proton-bridge"]
[dependencies] [dependencies]
proton-bridge = { path = "proton-bridge", optional = true } proton-bridge = { path = "proton-bridge", optional = false }
ratatui = "0.30" ratatui = "0.30"
crossterm = "0.29" crossterm = "0.29"
imap = "2.4" imap = "2.4"
@ -18,13 +15,13 @@ native-tls = "0.2"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
toml = "1.0" toml = "1.0"
chrono = "0.4" chrono = "0.4"
mailparse = "0.15" mailparse = "0.16"
fast_html2md = "0.0" fast_html2md = "0.0"
tui-markdown = "0.3" tui-markdown = "0.3"
quoted_printable = "0.5" quoted_printable = "0.5"
regex = "1" regex = "1"
lettre = { version = "0.11", default-features = false, features = ["smtp-transport", "native-tls", "builder"] } lettre = { version = "0.11", default-features = false, features = ["smtp-transport", "native-tls", "builder"] }
dirs = "5" dirs = "6.0"
rand = { version = "0.8", features = ["getrandom"] } rand = { version = "0.8", features = ["getrandom"] }
aes-gcm = "0.10" aes-gcm = "0.10"

View file

@ -12,15 +12,12 @@ toml = "1.0"
sha2 = "0.10" sha2 = "0.10"
num-bigint = "0.4" num-bigint = "0.4"
base64 = "0.22" base64 = "0.22"
rand = "0.8" rand = { version = "0.8.5", features = ["getrandom"] }
pwhash = "0.3" # bcrypt with caller-supplied salt (used for SRP) pwhash = "0.3" # bcrypt with caller-supplied salt (used for SRP)
bcrypt = "0.15" # reference bcrypt impl for key passphrase derivation bcrypt = "0.16" # reference bcrypt impl for key passphrase derivation
pgp = { version = "0.14", default-features = false } # rpgp — OpenPGP decrypt pgp = { version = "0.15", default-features = false } # rpgp — OpenPGP decrypt
chrono = "0.4" chrono = "0.4"
env_logger = "0.11" env_logger = "0.11"
aes = "0.8"
cfb-mode = "0.8"
sha1 = "0.10"
tracing = "0.1.44" tracing = "0.1.44"
[target.'cfg(target_os = "macos")'.dependencies] [target.'cfg(target_os = "macos")'.dependencies]

View file

@ -5,13 +5,13 @@
/// the ProtonMail v4 API (create draft → send). /// the ProtonMail v4 API (create draft → send).
use std::sync::Arc; use std::sync::Arc;
use base64::engine::general_purpose::STANDARD as B64; use crate::api::ApiClient;
use crate::{SharedState, crypto};
use base64::Engine; use base64::Engine;
use base64::engine::general_purpose::STANDARD as B64;
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader}; use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
use tokio::net::{TcpListener, TcpStream}; use tokio::net::{TcpListener, TcpStream};
use tracing::{error, info}; use tracing::error;
use crate::api::ApiClient;
use crate::{crypto, SharedState};
// ── Public entry point ──────────────────────────────────────────────────────── // ── Public entry point ────────────────────────────────────────────────────────
@ -49,7 +49,9 @@ async fn handle_connection(
// auth_step: 0 = not in AUTH, 1 = sent "Username:", 2 = sent "Password:" // auth_step: 0 = not in AUTH, 1 = sent "Username:", 2 = sent "Password:"
let mut auth_step: u8 = 0; let mut auth_step: u8 = 0;
writer.write_all(b"220 ProtonBridge ESMTP ready\r\n").await?; writer
.write_all(b"220 ProtonBridge ESMTP ready\r\n")
.await?;
while let Some(raw) = lines.next_line().await? { while let Some(raw) = lines.next_line().await? {
let line = raw.trim_end().to_string(); let line = raw.trim_end().to_string();
@ -61,8 +63,7 @@ async fn handle_connection(
if in_data { if in_data {
if line == "." { if line == "." {
in_data = false; in_data = false;
let resp = let resp = handle_send(&mail_from, &rcpt_to, &data_lines, &state).await;
handle_send(&mail_from, &rcpt_to, &data_lines, &state).await;
writer.write_all(resp.as_bytes()).await?; writer.write_all(resp.as_bytes()).await?;
mail_from.clear(); mail_from.clear();
rcpt_to.clear(); rcpt_to.clear();
@ -198,9 +199,7 @@ async fn handle_send(
let plaintext = data_lines[blank + 1..].join("\n"); let plaintext = data_lines[blank + 1..].join("\n");
for recipient in to { for recipient in to {
if let Err(e) = if let Err(e) = send_to_one(from, recipient, &subject, &plaintext, state).await {
send_to_one(from, recipient, &subject, &plaintext, state).await
{
// Log the full error in the bridge console; return a short fixed // Log the full error in the bridge console; return a short fixed
// message to skim so the status line doesn't overflow. // message to skim so the status line doesn't overflow.
eprintln!("SMTP send to {recipient} FAILED:\n {e}"); eprintln!("SMTP send to {recipient} FAILED:\n {e}");
@ -264,7 +263,13 @@ async fn send_to_one(
.map_err(|e| format!("encrypt draft body: {e}"))?, .map_err(|e| format!("encrypt draft body: {e}"))?,
}; };
(st.http_client.clone(), st.session.clone(), aid, db, signing_key) (
st.http_client.clone(),
st.session.clone(),
aid,
db,
signing_key,
)
}; };
let api = ApiClient::new(&http_client, &session); let api = ApiClient::new(&http_client, &session);
@ -283,7 +288,8 @@ async fn send_to_one(
// message body arrives clean (no PGP armor visible in Gmail / other clients). // message body arrives clean (no PGP armor visible in Gmail / other clients).
// ProtonMail decrypts the SEIPD using BodyKey and relays the multipart/signed // ProtonMail decrypts the SEIPD using BodyKey and relays the multipart/signed
// MIME entity to the external recipient over SMTP. // MIME entity to the external recipient over SMTP.
let signing_key = signing_key_opt.as_ref() let signing_key = signing_key_opt
.as_ref()
.ok_or("no signing key available for external send")?; .ok_or("no signing key available for external send")?;
let (seipd, session_key) = crypto::build_pgp_mime_for_external_send(plaintext, signing_key) let (seipd, session_key) = crypto::build_pgp_mime_for_external_send(plaintext, signing_key)
.map_err(|e| format!("PGP/MIME external body: {e}"))?; .map_err(|e| format!("PGP/MIME external body: {e}"))?;
@ -298,8 +304,15 @@ async fn send_to_one(
.create_draft(&address_id, subject, from, "", to, "", &draft_body) .create_draft(&address_id, subject, from, "", to, "", &draft_body)
.await?; .await?;
api.send_draft(&draft_id, to, send_type, &body_b64, &key_packet_b64, body_signed) api.send_draft(
.await?; &draft_id,
to,
send_type,
&body_b64,
&key_packet_b64,
body_signed,
)
.await?;
Ok(()) Ok(())
} }

View file

@ -187,7 +187,6 @@ impl Config {
/// Convert to the `proton-bridge` crate's `Config` type. /// Convert to the `proton-bridge` crate's `Config` type.
/// Only valid when `provider = "proton"`. /// Only valid when `provider = "proton"`.
#[cfg(feature = "proton")]
pub fn as_bridge_config(&self) -> Result<proton_bridge::config::Config, String> { pub fn as_bridge_config(&self) -> Result<proton_bridge::config::Config, String> {
let p = self.proton.as_ref().ok_or("[proton] section missing")?; let p = self.proton.as_ref().ok_or("[proton] section missing")?;
let b = self.bridge.as_ref().ok_or("[bridge] section missing")?; let b = self.bridge.as_ref().ok_or("[bridge] section missing")?;

View file

@ -3,13 +3,10 @@ use std::process::exit;
use crossterm::{ use crossterm::{
execute, execute,
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, terminal::{EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode},
}; };
use ratatui::{Terminal, backend::CrosstermBackend};
use tuimail::config::{Config, Provider}; use tuimail::config::{Config, Provider};
use ratatui::{
backend::CrosstermBackend,
Terminal,
};
fn main() -> io::Result<()> { fn main() -> io::Result<()> {
// ── Parse --configure flag ── // ── Parse --configure flag ──
@ -51,25 +48,16 @@ fn main() -> io::Result<()> {
// ── Start bridge if needed (before entering raw mode so output is clean) ── // ── Start bridge if needed (before entering raw mode so output is clean) ──
if config.provider == Provider::Proton { if config.provider == Provider::Proton {
#[cfg(feature = "proton")] let bridge_cfg = config.as_bridge_config().unwrap_or_else(|e| {
{ eprintln!("Bridge config error: {e}");
let bridge_cfg = config.as_bridge_config().unwrap_or_else(|e| {
eprintln!("Bridge config error: {e}");
exit(1);
});
eprint!("Starting ProtonMail bridge...");
proton_bridge::start(bridge_cfg).unwrap_or_else(|e| {
eprintln!("\nBridge failed to start: {e}");
exit(1);
});
eprintln!(" ready.");
}
#[cfg(not(feature = "proton"))]
{
eprintln!("tuimail was not compiled with ProtonMail support.");
eprintln!("Rebuild with: cargo build --features proton");
exit(1); exit(1);
} });
eprint!("Starting ProtonMail bridge...");
proton_bridge::start(bridge_cfg).unwrap_or_else(|e| {
eprintln!("\nBridge failed to start: {e}");
exit(1);
});
eprintln!(" ready.");
} }
// ── Derive effective IMAP/SMTP configs for the chosen provider ── // ── Derive effective IMAP/SMTP configs for the chosen provider ──