diff --git a/src/args.rs b/src/args.rs index 7ebc013..799e6c3 100644 --- a/src/args.rs +++ b/src/args.rs @@ -43,6 +43,8 @@ pub enum GetCommands { Signal, /// Router internet connection information. Internet, + /// Active APN (access point) configuration. + Apn, /// Router device information. Device, /// Router wifi config information. diff --git a/src/main.rs b/src/main.rs index a5c8da5..208cc09 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,6 +15,7 @@ async fn main() -> EyreResult<()> { GetCommands::System => router.show_multi::().await?, GetCommands::Signal => router.show_signal().await?, GetCommands::Internet => router.show_internet().await?, + GetCommands::Apn => router.show_apn().await?, GetCommands::Device => router.show_device().await?, GetCommands::Wifi => router.show_multi::().await?, GetCommands::Devices => router.show::().await?, diff --git a/src/proc_get.rs b/src/proc_get.rs index 4794149..0b280b9 100644 --- a/src/proc_get.rs +++ b/src/proc_get.rs @@ -445,3 +445,84 @@ impl Show for DeviceReport { Ok(()) } } + +#[derive(Debug, Deserialize)] +pub struct ApnStatus { + pub apn_mode: BoxStr, +} + +impl ProcGet for ApnStatus { + const CMD: &str = "apn_mode"; + type Params = (); +} + +#[derive(Debug)] +pub struct ApnProfile { + pub profile_name: BoxStr, + pub apn: BoxStr, + pub pdp_type: BoxStr, + pub auth_mode: BoxStr, + pub username: BoxStr, + pub password: BoxStr, + pub dns_mode: BoxStr, +} + +impl<'de> serde::Deserialize<'de> for ApnProfile { + fn deserialize>(deserializer: D) -> Result { + let raw = BoxStr::deserialize(deserializer)?; + let fields: BoxList<&str> = raw.split("($)").collect(); + let [name, apn, _, _, auth, user, pass, pdp, _, _, dns, ..] = fields.as_ref() else { + return Err(serde::de::Error::custom(format!("malformed APN config: {raw:?}"))); + }; + + Ok(Self { + profile_name: name.trim().into(), + apn: apn.trim().into(), + pdp_type: pdp.trim().into(), + auth_mode: auth.trim().into(), + username: user.trim().into(), + password: pass.trim().into(), + dns_mode: dns.trim().into(), + }) + } +} + +#[derive(Debug, Deserialize)] +pub struct ApnConfig { + #[serde(rename = "APN_config0")] + pub profile: ApnProfile, +} + +impl ProcGet for ApnConfig { + const CMD: &str = "APN_config0"; + type Params = (); +} + +#[derive(Debug)] +pub struct ApnReport { + pub status: ApnStatus, + pub profile: ApnProfile, +} + +impl Show for ApnReport { + fn show(&self) -> EyreResult<()> { + let profile = &self.profile; + + let mut table = create_table(); + + table + .set_header(["APN", "Value"]) + .add_row(["Mode", &self.status.apn_mode]) + .add_row(["Profile", or_dash(&profile.profile_name)]) + .add_row(["APN", or_dash(&profile.apn)]) + .add_row(["PDP Type", or_dash(&profile.pdp_type)]) + .add_row(["Auth Mode", or_dash(&profile.auth_mode)]) + .add_row(["Username", or_dash(&profile.username)]) + .add_row(["Password", or_dash(&profile.password)]) + .add_row(["DNS Mode", or_dash(&profile.dns_mode)]); + + println!("{table}"); + + Ok(()) + } +} diff --git a/src/router.rs b/src/router.rs index 773aab7..6298b5a 100644 --- a/src/router.rs +++ b/src/router.rs @@ -271,6 +271,17 @@ impl Router { InternetReport { internet, wan }.show() } + pub async fn show_apn(&self) -> EyreResult<()> { + let status = self.get::().await?; + let config = self.get::().await?; + + ApnReport { + status, + profile: config.profile, + } + .show() + } + /// Device identity comes from `home_get`, but the SIM ICCID only /// exists as a standalone cmd; join the two reads into one report. pub async fn show_device(&self) -> EyreResult<()> {