use crate::config::{ProxyConfig, ProxyConfigSource};
use crate::error::Error;
use crate::mode::ProxyMode;
use super::Env;
use super::desktop::{self, Desktop, Reading};
use super::sandbox::{self, Sandbox};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum Route {
Portal,
Stores { kioslaverc: bool },
}
pub(crate) fn route(sandbox: Sandbox, desktop: Desktop) -> Route {
if sandbox == Sandbox::None {
Route::Stores { kioslaverc: true }
} else if sandbox.gsettings_is_trustworthy() && desktop != Desktop::Kde {
Route::Stores { kioslaverc: false }
} else {
Route::Portal
}
}
pub(crate) fn read_config_in(env: &Env) -> Result<ProxyConfig, Error> {
let sandbox = sandbox::detect(env);
let desktop = desktop::current(env);
crate::trace::debug!(
sandbox = sandbox.name(),
route = ?route(sandbox, desktop),
desktop = ?desktop,
"choosing the Linux configuration route"
);
let config = if let Route::Stores { kioslaverc } = route(sandbox, desktop) {
desktop_config(desktop, env, kioslaverc)?
} else {
crate::trace::info!(
sandbox = sandbox.name(),
"GSettings would answer from GLib's keyfile backend here, so the settings \
are read through org.freedesktop.portal.ProxyResolver instead"
);
let mode = portal_mode(sandbox)?;
ProxyConfig::from_source(ProxyConfigSource::Portal, mode)
};
crate::trace::debug!(
config = %crate::trace::ConfigSummary(&config),
"read the Linux proxy configuration"
);
Ok(config)
}
fn desktop_config(
desktop: Desktop,
env: &Env,
read_kioslaverc: bool,
) -> Result<ProxyConfig, Error> {
let mut fallbacks = Vec::new();
let kde = || {
if read_kioslaverc {
kde_store(env)
} else {
Ok(Reading::Absent)
}
};
let (gsettings, kioslaverc) =
desktop::read_in_order(desktop, gnome_store, kde, &mut fallbacks)?;
crate::trace::debug!(
gsettings = ?gsettings,
kioslaverc = ?kioslaverc,
"read both Linux desktop stores"
);
desktop::note_if_the_leading_store_was_compiled_out(
desktop,
&gsettings,
&kioslaverc,
desktop::is_compiled_in,
&mut fallbacks,
);
let config = desktop::assemble(desktop, &gsettings, &kioslaverc).ok_or(Error::Unsupported)?;
Ok(config.with_fallbacks(fallbacks))
}
#[cfg(feature = "linux-gnome")]
fn gnome_store() -> Result<Reading, Error> {
super::gnome::read_store()
}
#[cfg(not(feature = "linux-gnome"))]
fn gnome_store() -> Result<Reading, Error> {
Ok(Reading::Absent)
}
#[cfg(feature = "linux-kde")]
fn kde_store(env: &Env) -> Result<Reading, Error> {
super::kde::read_store(env)
}
#[cfg(not(feature = "linux-kde"))]
fn kde_store(_env: &Env) -> Result<Reading, Error> {
Ok(Reading::Absent)
}
#[cfg(feature = "linux-gnome")]
fn portal_mode(sandbox: Sandbox) -> Result<ProxyMode, Error> {
super::portal::read_mode(sandbox)
}
#[cfg(not(feature = "linux-gnome"))]
fn portal_mode(sandbox: Sandbox) -> Result<ProxyMode, Error> {
Err(Error::Sandboxed {
sandbox: sandbox.name().to_owned(),
reason: "GSettings would answer from GLib's keyfile backend with the schema \
default mode='none', and the org.freedesktop.portal.ProxyResolver \
fallback needs the `linux-gnome` feature"
.to_owned(),
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn the_route_reads_kioslaverc_only_where_it_is_the_hosts() {
let dconf = Sandbox::Flatpak { dconf_access: true };
let no_dconf = Sandbox::Flatpak {
dconf_access: false,
};
for (sandbox, desktop, expected) in [
(
Sandbox::None,
Desktop::Kde,
Route::Stores { kioslaverc: true },
),
(
Sandbox::None,
Desktop::Gnome,
Route::Stores { kioslaverc: true },
),
(
Sandbox::None,
Desktop::Unknown,
Route::Stores { kioslaverc: true },
),
(dconf, Desktop::Gnome, Route::Stores { kioslaverc: false }),
(dconf, Desktop::Unknown, Route::Stores { kioslaverc: false }),
(dconf, Desktop::Kde, Route::Portal),
(no_dconf, Desktop::Gnome, Route::Portal),
(Sandbox::Snap, Desktop::Gnome, Route::Portal),
(Sandbox::Snap, Desktop::Kde, Route::Portal),
] {
assert_eq!(route(sandbox, desktop), expected, "{sandbox:?} {desktop:?}");
}
}
}