diff --git a/Cargo.toml b/Cargo.toml index cc38e65..f831da3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" categories = ["gateway", "bridge", "transport", "modemmanager"] [dependencies] +async-trait = "0.1.56" mmdbus = "1.18.6" dbus-tokio = "0.7.5" tokio = { version = "1.19.2", features = [ "time", "macros", "rt-multi-thread" ] } diff --git a/src/main.rs b/src/main.rs index ff57c15..722e5f0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,10 +13,12 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -use std::collections::HashMap; -use std::error::Error as StdError; +pub mod mm; +use mm::modem::Modem as ModemAccess; + use std::fmt; use std::sync::Arc; + use tokio::{ task::JoinHandle, time::Duration, @@ -24,16 +26,13 @@ use tokio::{ use mmdbus::{ dbus::{ - arg::{PropMap, RefArg, Variant}, - nonblock::{SyncConnection, stdintf::org_freedesktop_dbus::ObjectManager, Proxy}, - // channel::MatchingReceiver, - // message::{MatchRule, Message}, - strings::{Path as DBusPath}, // Interface, Member, - // Error as DBusError, + nonblock::{ + SyncConnection, Proxy, + stdintf::org_freedesktop_dbus::ObjectManager, + }, + strings::{Path as DBusPath}, + Error as DBusError, }, - modem::Modem as ModemAccess, - modem_messaging::ModemMessaging, - sms::Sms as SmsAccess, }; use dbus_tokio::connection; @@ -44,7 +43,6 @@ use dbus_tokio::connection; const MM_NAME: &str = "org.freedesktop.ModemManager1"; const MM_PATH: &str = "/org/freedesktop/ModemManager1"; const TIMEOUT: Duration = Duration::from_secs(5); -const SMSC: &str = "+33609001390"; // SFR #[derive(Clone)] pub struct DBus { @@ -53,7 +51,7 @@ pub struct DBus { } impl DBus { - pub fn connect() -> Result> { + pub fn connect() -> Result { let (resource, conn) = connection::new_system_sync()?; let handle: JoinHandle<()> = tokio::spawn(async { @@ -78,22 +76,26 @@ pub struct ModemManager { } impl ModemManager { - pub fn connect() -> Result> { - Ok(DBus::connect().map(|dbus| Self { dbus })?) + pub fn connect() -> Result { + DBus::connect().map(|dbus| Self { dbus }) } - pub async fn modems(&self) -> Result>, Box> { + pub async fn modems(&self) -> Result, DBusError> { let objects = self.dbus.proxy(MM_PATH).get_managed_objects().await?; let modems = objects .into_iter() - .map(|(path, _)| path ) + .map(|(path, _)| { + Modem { + dbus: self.dbus.clone(), + path, + } + }) .collect(); Ok(modems) } } -/* #[derive(Clone)] pub struct Modem { dbus: DBus, @@ -102,14 +104,13 @@ pub struct Modem { impl fmt::Debug for Modem { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let numbers = self.own_numbers().unwrap_or(vec![String::new()]); - write!(f, "Modem {{ {}, {:?}, .. }}", self.path, numbers) + write!(f, "Modem {{ {}, {:?}, .. }}", self.path, "1234") } } impl Modem { - pub fn enabled(&self) -> Result> { - let state: ModemState = ModemAccess::state(&self.dbus.proxy(&self.path)).map(Into::into)?; + pub async fn enabled(&self) -> Result { + let state: ModemState = ModemAccess::state(&self.dbus.proxy(&self.path)).await.map(Into::into)?; Ok(match state { ModemState::Enabling | ModemState::Enabled @@ -121,38 +122,9 @@ impl Modem { }) } - pub fn model(&self) -> Result> { - Ok(ModemAccess::model(&self.dbus.proxy(&self.path))?) + pub async fn model(&self) -> Result { + ModemAccess::model(&self.dbus.proxy(&self.path)).await } - - pub fn manufacturer(&self) -> Result> { - Ok(ModemAccess::manufacturer(&self.dbus.proxy(&self.path))?) - } - - pub fn own_numbers(&self) -> Result, Box> { - Ok(ModemAccess::own_numbers(&self.dbus.proxy(&self.path))?) - } - - /* - pub fn list_sms(&self) -> Result, Box> { - Ok(ModemMessaging::list(&self.dbus.proxy(&self.path))? - .into_iter() - .map(|p| Sms { - dbus: self.dbus.clone(), - modem: self.clone(), - path: p, - }) - .collect()) - } - - pub fn create_sms(&self, number: String, text: String) -> Result> { - Sms::new(self, number, text) - } - - pub fn delete_sms(&self, path: DBusPath) -> Result<(), Box> { - Ok(ModemMessaging::delete(&self.dbus.proxy(&self.path), path)?) - } - */ } #[repr(i32)] @@ -203,122 +175,17 @@ impl From for ModemState { } } } -*/ - -/* -// include/ModemManager-enums.h MMSmsState -/// State of a given SMS. -#[repr(u32)] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum SmsState { - /// State unknown or not reportable. - Unknown = 0, - /// The message has been neither received not yet sent. - Stored = 1, - /// The message is being received but is not yet complete. - Receiving = 2, - /// The message has been completely received. - Received = 3, - /// The message is queued for delivery. - Sending = 4, - /// The message was successfully sent. - Sent = 5, -} - -impl fmt::Display for SmsState { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", match self { - SmsState::Unknown => "unknown", - SmsState::Stored => "stored", - SmsState::Receiving => "receiving", - SmsState::Received => "received", - SmsState::Sending => "sending", - SmsState::Sent => "sent", - }) - } -} - -impl From for SmsState { - fn from(num: u32) -> Self { - if num > 5 { - Self::Unknown - } else { - unsafe { *(&num as *const u32 as *const Self) } - } - } -} - -pub struct Sms { - dbus: DBus, - modem: Modem, - path: DBusPath<'static>, -} - -impl Sms { - pub fn new(modem: &Modem, number: String, text: String) -> Result> { - let props: PropMap = { - let mut tmp = HashMap::new(); - tmp.insert( - String::from("number"), - Variant(Box::new(number) as Box), - ); - tmp.insert( - String::from("text"), - Variant(Box::new(text) as Box), - ); - tmp.insert( - String::from("smsc"), - Variant(Box::new(String::from(SMSC)) as Box), - ); - tmp - }; - let path = ModemMessaging::create(&modem.dbus.proxy(&modem.path), props)?; - Ok(Sms { - dbus: modem.dbus.clone(), - modem: modem.clone(), - path: path, - }) - } - - pub fn state(&self) -> Result> { - Ok(SmsAccess::state(&self.dbus.proxy(&self.path)).map(Into::into)?) - } - - pub fn send(&self) -> Result<(), Box> { - Ok(SmsAccess::send(&self.dbus.proxy(&self.path))?) - } - - pub fn number(&self) -> Result> { - Ok(SmsAccess::number(&self.dbus.proxy(&self.path))?) - } - - pub fn text(&self) -> Result> { - Ok(SmsAccess::text(&self.dbus.proxy(&self.path))?) - } -} - -impl fmt::Debug for Sms { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let state = self.state().unwrap_or(SmsState::Unknown); - write!(f, "Sms ({}) {{ {}, {:?}, .. }}", state, self.path, self.modem) - } -} - -impl fmt::Display for Sms { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let state = self.state().unwrap_or(SmsState::Unknown); - let number = self.number().unwrap_or(String::new()); - let text = self.text().unwrap_or(String::new()); - write!(f, "Sms ({}) {{ number: {}, text: {} }}", state, number, text) - } -} -*/ #[tokio::main] -async fn main() -> Result<(), Box> { - let modems = ModemManager::connect()?.modems().await; +async fn main() -> Result<(), DBusError> { + let modems = ModemManager::connect()?.modems().await?; println!("Modems: {:?}", modems); + for modem in modems { + println!("Modem: {:?}", modem); + println!("Enabled: {:?}", modem.enabled().await); + println!("Model: {:?}", modem.model().await); + } Ok(()) } diff --git a/src/mm/mod.rs b/src/mm/mod.rs new file mode 100644 index 0000000..733a648 --- /dev/null +++ b/src/mm/mod.rs @@ -0,0 +1,16 @@ +// Copyright (C) 2022 Maxime “pep” Buquet +// +// This program is free software: you can redistribute it and/or modify it +// under the terms of the GNU Affero General Public License as published by the +// Free Software Foundation, either version 3 of the License, or (at your +// option) any later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License +// for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +pub mod modem; diff --git a/src/mm/modem.rs b/src/mm/modem.rs new file mode 100644 index 0000000..4ef7ff0 --- /dev/null +++ b/src/mm/modem.rs @@ -0,0 +1,42 @@ +// Copyright (C) 2022 Maxime “pep” Buquet +// +// This program is free software: you can redistribute it and/or modify it +// under the terms of the GNU Affero General Public License as published by the +// Free Software Foundation, either version 3 of the License, or (at your +// option) any later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License +// for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +use std::ops::Deref; +use std::marker::Sync; + +use async_trait::async_trait; +use mmdbus::dbus::{nonblock, Error as DBusError}; + +#[async_trait] +pub trait Modem { + async fn enable(&self, enable: bool) -> Result<(), DBusError>; + async fn state(&self) -> Result; + async fn model(&self) -> Result; +} + +#[async_trait] +impl<'a, T: nonblock::NonblockReply, C: Deref + Sync> Modem for nonblock::Proxy<'a, C> { + async fn enable(&self, enable: bool) -> Result<(), DBusError> { + self.method_call("org.freedesktop.ModemManager1.Modem", "Enable", (enable,)).await + } + + async fn state(&self) -> Result { + ::get(&self, "org.freedesktop.ModemManager1.Modem", "State").await + } + + async fn model(&self) -> Result { + ::get(&self, "org.freedesktop.ModemManager1.Modem", "Model").await + } +}