Compare commits
1 commit
main
...
xmpp-send-
Author | SHA1 | Date | |
---|---|---|---|
f963d9c0b3 |
7 changed files with 303 additions and 479 deletions
19
Cargo.toml
19
Cargo.toml
|
@ -7,8 +7,21 @@ edition = "2021"
|
||||||
categories = ["gateway", "bridge", "transport", "modemmanager", "xmpp", "jabber"]
|
categories = ["gateway", "bridge", "transport", "modemmanager", "xmpp", "jabber"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
tokio = { version = "1", features = [ "macros", "rt-multi-thread" ] }
|
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" ] }
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
|
futures-util = "0.3"
|
||||||
|
tokio-xmpp = "3.2"
|
||||||
|
xmpp = "0.3"
|
||||||
|
xmpp-parsers = "0.19"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
pretty_env_logger = "0.5"
|
env_logger = "0.8"
|
||||||
zbus = "3.14.1"
|
|
||||||
|
[patch.crates-io]
|
||||||
|
jid = { path = "../xmpp-rs/jid" }
|
||||||
|
minidom = { path = "../xmpp-rs/minidom" }
|
||||||
|
tokio-xmpp = { path = "../xmpp-rs/tokio-xmpp" }
|
||||||
|
xmpp = { path = "../xmpp-rs/xmpp" }
|
||||||
|
xmpp-parsers = { path = "../xmpp-rs/parsers" }
|
||||||
|
|
30
src/error.rs
30
src/error.rs
|
@ -18,17 +18,22 @@
|
||||||
use std::convert::From;
|
use std::convert::From;
|
||||||
use std::error::Error as StdError;
|
use std::error::Error as StdError;
|
||||||
|
|
||||||
|
use mmdbus::dbus;
|
||||||
|
use xmpp_parsers::JidParseError;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
Zbus(zbus::Error),
|
DBusError(dbus::Error),
|
||||||
ZbusFdo(zbus::fdo::Error),
|
InvalidArgs,
|
||||||
|
JidParseError(JidParseError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StdError for Error {
|
impl StdError for Error {
|
||||||
fn cause(&self) -> Option<&dyn StdError> {
|
fn cause(&self) -> Option<&dyn StdError> {
|
||||||
match self {
|
match self {
|
||||||
Error::Zbus(e) => Some(e),
|
Error::DBusError(e) => Some(e),
|
||||||
Error::ZbusFdo(e) => Some(e),
|
Error::InvalidArgs => None,
|
||||||
|
Error::JidParseError(e) => Some(e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,20 +41,21 @@ impl StdError for Error {
|
||||||
impl std::fmt::Display for Error {
|
impl std::fmt::Display for Error {
|
||||||
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
|
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Error::Zbus(e) => write!(fmt, "zbus error: {}", e),
|
Error::DBusError(e) => write!(fmt, "dbus error: {}", e),
|
||||||
Error::ZbusFdo(e) => write!(fmt, "zbus fdo error: {}", e),
|
Error::InvalidArgs => write!(fmt, "invalid arguments"),
|
||||||
|
Error::JidParseError(e) => write!(fmt, "jid parse error: {}", e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<zbus::Error> for Error {
|
impl From<dbus::Error> for Error {
|
||||||
fn from(err: zbus::Error) -> Error {
|
fn from(err: dbus::Error) -> Error {
|
||||||
Error::Zbus(err)
|
Error::DBusError(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<zbus::fdo::Error> for Error {
|
impl From<JidParseError> for Error {
|
||||||
fn from(err: zbus::fdo::Error) -> Error {
|
fn from(err: JidParseError) -> Error {
|
||||||
Error::ZbusFdo(err)
|
Error::JidParseError(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
238
src/main.rs
238
src/main.rs
|
@ -13,45 +13,227 @@
|
||||||
// You should have received a copy of the GNU Affero General Public License
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
mod error;
|
pub mod error;
|
||||||
mod modem;
|
pub mod mm;
|
||||||
|
|
||||||
use crate::error::Error;
|
use error::Error;
|
||||||
use crate::modem::ModemManager;
|
use mm::modem::Modem as ModemAccess;
|
||||||
|
|
||||||
use futures::{StreamExt, future::join_all};
|
use std::fmt;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::str::FromStr;
|
||||||
|
use std::env::args;
|
||||||
|
|
||||||
#[tokio::main]
|
use env_logger;
|
||||||
async fn main() -> Result<(), Error> {
|
|
||||||
pretty_env_logger::init();
|
|
||||||
|
|
||||||
let mut join_handlers = vec![];
|
use tokio::{
|
||||||
let manager = ModemManager::connect().await?;
|
task::JoinHandle,
|
||||||
for modem in manager {
|
time::Duration,
|
||||||
println!("FOO0: {:?}", modem);
|
};
|
||||||
println!("FOO0: {:?}", modem.foo().manufacturer().await?);
|
|
||||||
println!("FOO0: {:?}", modem.foo().model().await?);
|
|
||||||
|
|
||||||
println!("FOO1: {:?}", modem.messaging().list().await?);
|
use mmdbus::{
|
||||||
|
dbus::{
|
||||||
|
// message::MatchRule,
|
||||||
|
nonblock::{
|
||||||
|
SyncConnection, Proxy,
|
||||||
|
stdintf::org_freedesktop_dbus::ObjectManager,
|
||||||
|
},
|
||||||
|
strings::{Path as DBusPath},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
let mut sms_added_stream = modem.messaging().receive_added().await?;
|
use dbus_tokio::connection;
|
||||||
let mut call_added_stream = modem.voice().receive_call_added().await?;
|
|
||||||
|
|
||||||
let handle_sms = tokio::spawn(async move {
|
use xmpp::{ClientBuilder, ClientType};
|
||||||
while let Some(sms) = sms_added_stream.next().await {
|
use xmpp_parsers::{
|
||||||
println!("BAR0: {:?}", sms);
|
Jid, BareJid,
|
||||||
|
message::MessageType,
|
||||||
|
};
|
||||||
|
|
||||||
|
// The following source has been used as an example:
|
||||||
|
// https://github.com/soerenmeier/linux-info/blob/master/src/network/modem_manager.rs
|
||||||
|
|
||||||
|
const MM_NAME: &str = "org.freedesktop.ModemManager1";
|
||||||
|
const MM_PATH: &str = "/org/freedesktop/ModemManager1";
|
||||||
|
const TIMEOUT: Duration = Duration::from_secs(5);
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct DBus {
|
||||||
|
pub conn: Arc<SyncConnection>,
|
||||||
|
pub handle: Arc<JoinHandle<()>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl DBus {
|
||||||
|
pub fn connect() -> Result<Self, Error> {
|
||||||
|
let (resource, conn) = connection::new_system_sync()?;
|
||||||
|
|
||||||
|
let handle: JoinHandle<()> = tokio::spawn(async {
|
||||||
|
let err = resource.await;
|
||||||
|
panic!("Lost connection to D-Bus: {}", err);
|
||||||
});
|
});
|
||||||
let handle_call = tokio::spawn(async move {
|
|
||||||
while let Some(call) = call_added_stream.next().await {
|
Ok(Self { conn, handle: Arc::new(handle) })
|
||||||
println!("MEH0: {:?}", call);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
join_handlers.push(handle_sms);
|
|
||||||
join_handlers.push(handle_call);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = join_all(join_handlers).await;
|
pub fn proxy<'a, 'b, P>(&'b self, path: P) -> Proxy<'a, &'b SyncConnection>
|
||||||
|
where
|
||||||
|
P: Into<DBusPath<'a>>,
|
||||||
|
{
|
||||||
|
Proxy::new(MM_NAME, path, TIMEOUT, &*self.conn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct ModemManager {
|
||||||
|
dbus: DBus,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ModemManager {
|
||||||
|
pub fn connect() -> Result<Self, Error> {
|
||||||
|
DBus::connect().map(|dbus| Self { dbus })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn modems(&self) -> Result<Vec<Modem>, Error> {
|
||||||
|
let objects = self.dbus.proxy(MM_PATH).get_managed_objects().await?;
|
||||||
|
let modems = objects
|
||||||
|
.into_iter()
|
||||||
|
.map(|(path, _)| {
|
||||||
|
Modem {
|
||||||
|
dbus: self.dbus.clone(),
|
||||||
|
path,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Ok(modems)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Modem {
|
||||||
|
dbus: DBus,
|
||||||
|
pub path: DBusPath<'static>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for Modem {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "Modem {{ {}, {:?}, .. }}", self.path, "1234")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Modem {
|
||||||
|
pub async fn enabled(&self) -> Result<bool, Error> {
|
||||||
|
let state: ModemState = ModemAccess::state(&self.dbus.proxy(&self.path)).await.map(Into::into)?;
|
||||||
|
Ok(match state {
|
||||||
|
ModemState::Enabling
|
||||||
|
| ModemState::Enabled
|
||||||
|
| ModemState::Searching
|
||||||
|
| ModemState::Registered
|
||||||
|
| ModemState::Connecting
|
||||||
|
| ModemState::Connected => true,
|
||||||
|
_ => false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn model(&self) -> Result<String, Error> {
|
||||||
|
ModemAccess::model(&self.dbus.proxy(&self.path)).await.map_err(Error::DBusError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(i32)]
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum ModemState {
|
||||||
|
/// The modem is unusable.
|
||||||
|
Failed = -1,
|
||||||
|
/// State unknown or not reportable.
|
||||||
|
Unknown = 0,
|
||||||
|
/// The modem is currently being initialized.
|
||||||
|
Initializing = 1,
|
||||||
|
/// The modem needs to be unlocked.
|
||||||
|
Locked = 2,
|
||||||
|
/// The modem is not enabled and is powered down.
|
||||||
|
Disabled = 3,
|
||||||
|
/// The modem is currently transitioning to the MM_MODEM_STATE_DISABLED
|
||||||
|
/// state.
|
||||||
|
Disabling = 4,
|
||||||
|
/// The modem is currently transitioning to the MM_MODEM_STATE_ENABLED
|
||||||
|
/// state.
|
||||||
|
Enabling = 5,
|
||||||
|
/// The modem is enabled and powered on but not registered with a network
|
||||||
|
/// provider and not available for data connections.
|
||||||
|
Enabled = 6,
|
||||||
|
/// The modem is searching for a network provider to register with.
|
||||||
|
Searching = 7,
|
||||||
|
/// The modem is registered with a network provider, and data connections
|
||||||
|
/// and messaging may be available for use.
|
||||||
|
Registered = 8,
|
||||||
|
/// The modem is disconnecting and deactivating the last active packet data
|
||||||
|
/// bearer. This state will not be entered if more than one packet data
|
||||||
|
/// bearer is active and one of the active bearers is deactivated.
|
||||||
|
Disconnecting = 9,
|
||||||
|
/// The modem is activating and connecting the first packet data bearer.
|
||||||
|
/// Subsequent bearer activations when another bearer is already active
|
||||||
|
/// do not cause this state to be entered.
|
||||||
|
Connecting = 10,
|
||||||
|
/// One or more packet data bearers is active and connected.
|
||||||
|
Connected = 11,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<i32> for ModemState {
|
||||||
|
fn from(num: i32) -> Self {
|
||||||
|
if num < -1 || num > 11 {
|
||||||
|
Self::Unknown
|
||||||
|
} else {
|
||||||
|
unsafe { *(&num as *const i32 as *const Self) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn print_foo(mm: ModemManager) -> Result<(), Error> {
|
||||||
|
let modems = mm.modems().await?;
|
||||||
|
println!("Modems: {:?}", modems);
|
||||||
|
for modem in modems {
|
||||||
|
println!("Modem: {:?}", modem);
|
||||||
|
println!("Enabled: {:?}", modem.enabled().await);
|
||||||
|
println!("Model: {:?}", modem.model().await);
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
pub async fn main() -> Result<(), Error> {
|
||||||
|
env_logger::init();
|
||||||
|
|
||||||
|
let args: Vec<String> = args().collect();
|
||||||
|
if args.len() != 3 {
|
||||||
|
println!("Usage: {} <jid> <password>", args[0]);
|
||||||
|
return Err(Error::InvalidArgs)
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut interval = tokio::time::interval(Duration::from_secs(5));
|
||||||
|
|
||||||
|
// XMPP
|
||||||
|
let jid_str = args[1].as_str();
|
||||||
|
let jid = Jid::Bare(BareJid::from_str(jid_str).unwrap());
|
||||||
|
let passwd = args[2].as_str();
|
||||||
|
|
||||||
|
// Client instance
|
||||||
|
let mut xmpp = ClientBuilder::new(jid_str, passwd)
|
||||||
|
.set_client(ClientType::Bot, "gateway_mm")
|
||||||
|
.set_website("https://codeberg.org/pep./gateway_mm")
|
||||||
|
.build()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
tokio::select! {
|
||||||
|
events = xmpp.wait_for_events() => {
|
||||||
|
println!("Events: {:?}", events);
|
||||||
|
},
|
||||||
|
_ = interval.tick() => {
|
||||||
|
println!("Foo1");
|
||||||
|
// Uncomment to have tokio-xmpp stall right after successful bind.
|
||||||
|
// xmpp.send_message(jid.clone(), MessageType::Chat, "en", "Bar").await;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
16
src/mm/mod.rs
Normal file
16
src/mm/mod.rs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
// Copyright (C) 2022 Maxime “pep” Buquet <pep@bouah.net>
|
||||||
|
//
|
||||||
|
// 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 <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
pub mod modem;
|
42
src/mm/modem.rs
Normal file
42
src/mm/modem.rs
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
// Copyright (C) 2022 Maxime “pep” Buquet <pep@bouah.net>
|
||||||
|
//
|
||||||
|
// 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 <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
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<i32, DBusError>;
|
||||||
|
async fn model(&self) -> Result<String, DBusError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl<'a, T: nonblock::NonblockReply, C: Deref<Target=T> + 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<i32, DBusError> {
|
||||||
|
<Self as nonblock::stdintf::org_freedesktop_dbus::Properties>::get(&self, "org.freedesktop.ModemManager1.Modem", "State").await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn model(&self) -> Result<String, DBusError> {
|
||||||
|
<Self as nonblock::stdintf::org_freedesktop_dbus::Properties>::get(&self, "org.freedesktop.ModemManager1.Modem", "Model").await
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,320 +0,0 @@
|
||||||
//! DBus interface proxies for:
|
|
||||||
//!
|
|
||||||
//! - `org.freedesktop.ModemManager1.Modem`,
|
|
||||||
//! - `org.freedesktop.ModemManager1.Modem.Messaging`,
|
|
||||||
//! - `org.freedesktop.ModemManager1.Modem.Simple`,
|
|
||||||
//! - `org.freedesktop.ModemManager1.Modem.Voice`
|
|
||||||
//!
|
|
||||||
//! This code was generated by `zbus-xmlgen` `3.1.1` from DBus introspection data.
|
|
||||||
//! Source: `ModemManager1.xml`.
|
|
||||||
|
|
||||||
use zbus::dbus_proxy;
|
|
||||||
|
|
||||||
#[dbus_proxy(
|
|
||||||
interface = "org.freedesktop.ModemManager1.Modem.Messaging",
|
|
||||||
default_service = "org.freedesktop.ModemManager1",
|
|
||||||
assume_defaults = true
|
|
||||||
)]
|
|
||||||
trait Messaging {
|
|
||||||
/// Create method
|
|
||||||
fn create(
|
|
||||||
&self,
|
|
||||||
properties: std::collections::HashMap<&str, zbus::zvariant::Value<'_>>,
|
|
||||||
) -> zbus::Result<zbus::zvariant::OwnedObjectPath>;
|
|
||||||
|
|
||||||
/// Delete method
|
|
||||||
fn delete(&self, path: &zbus::zvariant::ObjectPath<'_>) -> zbus::Result<()>;
|
|
||||||
|
|
||||||
/// List method
|
|
||||||
fn list(&self) -> zbus::Result<Vec<zbus::zvariant::OwnedObjectPath>>;
|
|
||||||
|
|
||||||
/// Added signal
|
|
||||||
#[dbus_proxy(signal)]
|
|
||||||
fn added(&self, path: zbus::zvariant::ObjectPath<'_>, received: bool) -> zbus::Result<()>;
|
|
||||||
|
|
||||||
/// Deleted signal
|
|
||||||
#[dbus_proxy(signal)]
|
|
||||||
fn deleted(&self, path: zbus::zvariant::ObjectPath<'_>) -> zbus::Result<()>;
|
|
||||||
|
|
||||||
/// DefaultStorage property
|
|
||||||
#[dbus_proxy(property)]
|
|
||||||
fn default_storage(&self) -> zbus::Result<u32>;
|
|
||||||
|
|
||||||
/// Messages property
|
|
||||||
#[dbus_proxy(property)]
|
|
||||||
fn messages(&self) -> zbus::Result<Vec<zbus::zvariant::OwnedObjectPath>>;
|
|
||||||
|
|
||||||
/// SupportedStorages property
|
|
||||||
#[dbus_proxy(property)]
|
|
||||||
fn supported_storages(&self) -> zbus::Result<Vec<u32>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[dbus_proxy(
|
|
||||||
interface = "org.freedesktop.ModemManager1.Modem",
|
|
||||||
default_service = "org.freedesktop.ModemManager1",
|
|
||||||
assume_defaults = true
|
|
||||||
)]
|
|
||||||
trait Modem {
|
|
||||||
/// Command method
|
|
||||||
fn command(&self, cmd: &str, timeout: u32) -> zbus::Result<String>;
|
|
||||||
|
|
||||||
/// CreateBearer method
|
|
||||||
fn create_bearer(
|
|
||||||
&self,
|
|
||||||
properties: std::collections::HashMap<&str, zbus::zvariant::Value<'_>>,
|
|
||||||
) -> zbus::Result<zbus::zvariant::OwnedObjectPath>;
|
|
||||||
|
|
||||||
/// DeleteBearer method
|
|
||||||
fn delete_bearer(&self, bearer: &zbus::zvariant::ObjectPath<'_>) -> zbus::Result<()>;
|
|
||||||
|
|
||||||
/// Enable method
|
|
||||||
fn enable(&self, enable: bool) -> zbus::Result<()>;
|
|
||||||
|
|
||||||
/// FactoryReset method
|
|
||||||
fn factory_reset(&self, code: &str) -> zbus::Result<()>;
|
|
||||||
|
|
||||||
/// GetCellInfo method
|
|
||||||
fn get_cell_info(
|
|
||||||
&self,
|
|
||||||
) -> zbus::Result<Vec<std::collections::HashMap<String, zbus::zvariant::OwnedValue>>>;
|
|
||||||
|
|
||||||
/// ListBearers method
|
|
||||||
fn list_bearers(&self) -> zbus::Result<Vec<zbus::zvariant::OwnedObjectPath>>;
|
|
||||||
|
|
||||||
/// Reset method
|
|
||||||
fn reset(&self) -> zbus::Result<()>;
|
|
||||||
|
|
||||||
/// SetCurrentBands method
|
|
||||||
fn set_current_bands(&self, bands: &[u32]) -> zbus::Result<()>;
|
|
||||||
|
|
||||||
/// SetCurrentCapabilities method
|
|
||||||
fn set_current_capabilities(&self, capabilities: u32) -> zbus::Result<()>;
|
|
||||||
|
|
||||||
/// SetCurrentModes method
|
|
||||||
fn set_current_modes(&self, modes: &(u32, u32)) -> zbus::Result<()>;
|
|
||||||
|
|
||||||
/// SetPowerState method
|
|
||||||
fn set_power_state(&self, state: u32) -> zbus::Result<()>;
|
|
||||||
|
|
||||||
/// SetPrimarySimSlot method
|
|
||||||
fn set_primary_sim_slot(&self, sim_slot: u32) -> zbus::Result<()>;
|
|
||||||
|
|
||||||
// TODO: This fails to compile: duplicate definitions for `receive_state_changed`
|
|
||||||
// /// StateChanged signal
|
|
||||||
// #[dbus_proxy(signal)]
|
|
||||||
// fn state_changed(&self, old: i32, new: i32, reason: u32) -> zbus::Result<()>;
|
|
||||||
|
|
||||||
/// AccessTechnologies property
|
|
||||||
#[dbus_proxy(property)]
|
|
||||||
fn access_technologies(&self) -> zbus::Result<u32>;
|
|
||||||
|
|
||||||
/// Bearers property
|
|
||||||
#[dbus_proxy(property)]
|
|
||||||
fn bearers(&self) -> zbus::Result<Vec<zbus::zvariant::OwnedObjectPath>>;
|
|
||||||
|
|
||||||
/// CarrierConfiguration property
|
|
||||||
#[dbus_proxy(property)]
|
|
||||||
fn carrier_configuration(&self) -> zbus::Result<String>;
|
|
||||||
|
|
||||||
/// CarrierConfigurationRevision property
|
|
||||||
#[dbus_proxy(property)]
|
|
||||||
fn carrier_configuration_revision(&self) -> zbus::Result<String>;
|
|
||||||
|
|
||||||
/// CurrentBands property
|
|
||||||
#[dbus_proxy(property)]
|
|
||||||
fn current_bands(&self) -> zbus::Result<Vec<u32>>;
|
|
||||||
|
|
||||||
/// CurrentCapabilities property
|
|
||||||
#[dbus_proxy(property)]
|
|
||||||
fn current_capabilities(&self) -> zbus::Result<u32>;
|
|
||||||
|
|
||||||
/// CurrentModes property
|
|
||||||
#[dbus_proxy(property)]
|
|
||||||
fn current_modes(&self) -> zbus::Result<(u32, u32)>;
|
|
||||||
|
|
||||||
/// Device property
|
|
||||||
#[dbus_proxy(property)]
|
|
||||||
fn device(&self) -> zbus::Result<String>;
|
|
||||||
|
|
||||||
/// DeviceIdentifier property
|
|
||||||
#[dbus_proxy(property)]
|
|
||||||
fn device_identifier(&self) -> zbus::Result<String>;
|
|
||||||
|
|
||||||
/// Drivers property
|
|
||||||
#[dbus_proxy(property)]
|
|
||||||
fn drivers(&self) -> zbus::Result<Vec<String>>;
|
|
||||||
|
|
||||||
/// EquipmentIdentifier property
|
|
||||||
#[dbus_proxy(property)]
|
|
||||||
fn equipment_identifier(&self) -> zbus::Result<String>;
|
|
||||||
|
|
||||||
/// HardwareRevision property
|
|
||||||
#[dbus_proxy(property)]
|
|
||||||
fn hardware_revision(&self) -> zbus::Result<String>;
|
|
||||||
|
|
||||||
/// Manufacturer property
|
|
||||||
#[dbus_proxy(property)]
|
|
||||||
fn manufacturer(&self) -> zbus::Result<String>;
|
|
||||||
|
|
||||||
/// MaxActiveBearers property
|
|
||||||
#[dbus_proxy(property)]
|
|
||||||
fn max_active_bearers(&self) -> zbus::Result<u32>;
|
|
||||||
|
|
||||||
/// MaxActiveMultiplexedBearers property
|
|
||||||
#[dbus_proxy(property)]
|
|
||||||
fn max_active_multiplexed_bearers(&self) -> zbus::Result<u32>;
|
|
||||||
|
|
||||||
/// MaxBearers property
|
|
||||||
#[dbus_proxy(property)]
|
|
||||||
fn max_bearers(&self) -> zbus::Result<u32>;
|
|
||||||
|
|
||||||
/// Model property
|
|
||||||
#[dbus_proxy(property)]
|
|
||||||
fn model(&self) -> zbus::Result<String>;
|
|
||||||
|
|
||||||
/// OwnNumbers property
|
|
||||||
#[dbus_proxy(property)]
|
|
||||||
fn own_numbers(&self) -> zbus::Result<Vec<String>>;
|
|
||||||
|
|
||||||
/// Plugin property
|
|
||||||
#[dbus_proxy(property)]
|
|
||||||
fn plugin(&self) -> zbus::Result<String>;
|
|
||||||
|
|
||||||
/// Ports property
|
|
||||||
#[dbus_proxy(property)]
|
|
||||||
fn ports(&self) -> zbus::Result<Vec<(String, u32)>>;
|
|
||||||
|
|
||||||
/// PowerState property
|
|
||||||
#[dbus_proxy(property)]
|
|
||||||
fn power_state(&self) -> zbus::Result<u32>;
|
|
||||||
|
|
||||||
/// PrimaryPort property
|
|
||||||
#[dbus_proxy(property)]
|
|
||||||
fn primary_port(&self) -> zbus::Result<String>;
|
|
||||||
|
|
||||||
/// PrimarySimSlot property
|
|
||||||
#[dbus_proxy(property)]
|
|
||||||
fn primary_sim_slot(&self) -> zbus::Result<u32>;
|
|
||||||
|
|
||||||
/// Revision property
|
|
||||||
#[dbus_proxy(property)]
|
|
||||||
fn revision(&self) -> zbus::Result<String>;
|
|
||||||
|
|
||||||
/// SignalQuality property
|
|
||||||
#[dbus_proxy(property)]
|
|
||||||
fn signal_quality(&self) -> zbus::Result<(u32, bool)>;
|
|
||||||
|
|
||||||
/// Sim property
|
|
||||||
#[dbus_proxy(property)]
|
|
||||||
fn sim(&self) -> zbus::Result<zbus::zvariant::OwnedObjectPath>;
|
|
||||||
|
|
||||||
/// SimSlots property
|
|
||||||
#[dbus_proxy(property)]
|
|
||||||
fn sim_slots(&self) -> zbus::Result<Vec<zbus::zvariant::OwnedObjectPath>>;
|
|
||||||
|
|
||||||
/// State property
|
|
||||||
#[dbus_proxy(property)]
|
|
||||||
fn state(&self) -> zbus::Result<i32>;
|
|
||||||
|
|
||||||
/// StateFailedReason property
|
|
||||||
#[dbus_proxy(property)]
|
|
||||||
fn state_failed_reason(&self) -> zbus::Result<u32>;
|
|
||||||
|
|
||||||
/// SupportedBands property
|
|
||||||
#[dbus_proxy(property)]
|
|
||||||
fn supported_bands(&self) -> zbus::Result<Vec<u32>>;
|
|
||||||
|
|
||||||
/// SupportedCapabilities property
|
|
||||||
#[dbus_proxy(property)]
|
|
||||||
fn supported_capabilities(&self) -> zbus::Result<Vec<u32>>;
|
|
||||||
|
|
||||||
/// SupportedIpFamilies property
|
|
||||||
#[dbus_proxy(property)]
|
|
||||||
fn supported_ip_families(&self) -> zbus::Result<u32>;
|
|
||||||
|
|
||||||
/// SupportedModes property
|
|
||||||
#[dbus_proxy(property)]
|
|
||||||
fn supported_modes(&self) -> zbus::Result<Vec<(u32, u32)>>;
|
|
||||||
|
|
||||||
/// UnlockRequired property
|
|
||||||
#[dbus_proxy(property)]
|
|
||||||
fn unlock_required(&self) -> zbus::Result<u32>;
|
|
||||||
|
|
||||||
/// UnlockRetries property
|
|
||||||
#[dbus_proxy(property)]
|
|
||||||
fn unlock_retries(&self) -> zbus::Result<std::collections::HashMap<u32, u32>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[dbus_proxy(
|
|
||||||
interface = "org.freedesktop.ModemManager1.Modem.Simple",
|
|
||||||
default_service = "org.freedesktop.ModemManager1",
|
|
||||||
assume_defaults = true
|
|
||||||
)]
|
|
||||||
trait Simple {
|
|
||||||
/// Connect method
|
|
||||||
fn connect(
|
|
||||||
&self,
|
|
||||||
properties: std::collections::HashMap<&str, zbus::zvariant::Value<'_>>,
|
|
||||||
) -> zbus::Result<zbus::zvariant::OwnedObjectPath>;
|
|
||||||
|
|
||||||
/// Disconnect method
|
|
||||||
fn disconnect(&self, bearer: &zbus::zvariant::ObjectPath<'_>) -> zbus::Result<()>;
|
|
||||||
|
|
||||||
/// GetStatus method
|
|
||||||
fn get_status(
|
|
||||||
&self,
|
|
||||||
) -> zbus::Result<std::collections::HashMap<String, zbus::zvariant::OwnedValue>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[dbus_proxy(
|
|
||||||
interface = "org.freedesktop.ModemManager1.Modem.Voice",
|
|
||||||
default_service = "org.freedesktop.ModemManager1",
|
|
||||||
assume_defaults = true
|
|
||||||
)]
|
|
||||||
trait Voice {
|
|
||||||
/// CallWaitingQuery method
|
|
||||||
fn call_waiting_query(&self) -> zbus::Result<bool>;
|
|
||||||
|
|
||||||
/// CallWaitingSetup method
|
|
||||||
fn call_waiting_setup(&self, enable: bool) -> zbus::Result<()>;
|
|
||||||
|
|
||||||
/// CreateCall method
|
|
||||||
fn create_call(
|
|
||||||
&self,
|
|
||||||
properties: std::collections::HashMap<&str, zbus::zvariant::Value<'_>>,
|
|
||||||
) -> zbus::Result<zbus::zvariant::OwnedObjectPath>;
|
|
||||||
|
|
||||||
/// DeleteCall method
|
|
||||||
fn delete_call(&self, path: &zbus::zvariant::ObjectPath<'_>) -> zbus::Result<()>;
|
|
||||||
|
|
||||||
/// HangupAll method
|
|
||||||
fn hangup_all(&self) -> zbus::Result<()>;
|
|
||||||
|
|
||||||
/// HangupAndAccept method
|
|
||||||
fn hangup_and_accept(&self) -> zbus::Result<()>;
|
|
||||||
|
|
||||||
/// HoldAndAccept method
|
|
||||||
fn hold_and_accept(&self) -> zbus::Result<()>;
|
|
||||||
|
|
||||||
/// ListCalls method
|
|
||||||
fn list_calls(&self) -> zbus::Result<Vec<zbus::zvariant::OwnedObjectPath>>;
|
|
||||||
|
|
||||||
/// Transfer method
|
|
||||||
fn transfer(&self) -> zbus::Result<()>;
|
|
||||||
|
|
||||||
/// CallAdded signal
|
|
||||||
#[dbus_proxy(signal)]
|
|
||||||
fn call_added(&self, path: zbus::zvariant::ObjectPath<'_>) -> zbus::Result<()>;
|
|
||||||
|
|
||||||
/// CallDeleted signal
|
|
||||||
#[dbus_proxy(signal)]
|
|
||||||
fn call_deleted(&self, path: zbus::zvariant::ObjectPath<'_>) -> zbus::Result<()>;
|
|
||||||
|
|
||||||
/// Calls property
|
|
||||||
#[dbus_proxy(property)]
|
|
||||||
fn calls(&self) -> zbus::Result<Vec<zbus::zvariant::OwnedObjectPath>>;
|
|
||||||
|
|
||||||
/// EmergencyOnly property
|
|
||||||
#[dbus_proxy(property)]
|
|
||||||
fn emergency_only(&self) -> zbus::Result<bool>;
|
|
||||||
}
|
|
115
src/modem/mod.rs
115
src/modem/mod.rs
|
@ -1,115 +0,0 @@
|
||||||
// Copyright (C) 2022 Maxime “pep” Buquet <pep@bouah.net>
|
|
||||||
//
|
|
||||||
// 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 <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
mod introspect;
|
|
||||||
|
|
||||||
use crate::error::Error;
|
|
||||||
use crate::modem::introspect::{ModemProxy, MessagingProxy, VoiceProxy};
|
|
||||||
|
|
||||||
use std::fmt;
|
|
||||||
|
|
||||||
use zbus::{fdo::ObjectManagerProxy, zvariant::ObjectPath, Connection};
|
|
||||||
|
|
||||||
const MM_NAME: &str = "org.freedesktop.ModemManager1";
|
|
||||||
const MM_PATH: &str = "/org/freedesktop/ModemManager1";
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct ModemManager<'a> {
|
|
||||||
connection: Connection,
|
|
||||||
modems: Vec<Modem<'a>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> ModemManager<'a> {
|
|
||||||
pub async fn connect() -> Result<ModemManager<'a>, Error> {
|
|
||||||
let connection = Connection::system().await?;
|
|
||||||
Ok(ModemManager {
|
|
||||||
modems: ModemManager::modems(&connection).await?,
|
|
||||||
connection,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn modems(conn: &Connection) -> Result<Vec<Modem<'a>>, Error> {
|
|
||||||
let proxy = ObjectManagerProxy::builder(&conn)
|
|
||||||
.destination(MM_NAME)?
|
|
||||||
.path(MM_PATH)?
|
|
||||||
.build()
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let mut res = vec![];
|
|
||||||
for (path, _) in proxy.get_managed_objects().await? {
|
|
||||||
res.push(Modem::new(&conn, path.into()).await?)
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(res)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for ModemManager<'_> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
f.debug_struct("ModemManager")
|
|
||||||
.field("modems", &self.modems)
|
|
||||||
.finish_non_exhaustive()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> IntoIterator for ModemManager<'a> {
|
|
||||||
type Item = Modem<'a>;
|
|
||||||
type IntoIter = std::vec::IntoIter<Self::Item>;
|
|
||||||
|
|
||||||
fn into_iter(self) -> Self::IntoIter {
|
|
||||||
self.modems.into_iter()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Modem<'a> {
|
|
||||||
modem: ModemProxy<'a>,
|
|
||||||
messaging: MessagingProxy<'a>,
|
|
||||||
voice: VoiceProxy<'a>,
|
|
||||||
path: ObjectPath<'a>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Modem<'a> {
|
|
||||||
pub async fn new(connection: &Connection, path: ObjectPath<'a>) -> Result<Modem<'a>, Error> {
|
|
||||||
Ok(Modem {
|
|
||||||
modem: ModemProxy::builder(connection).path(path.clone())?.build().await?,
|
|
||||||
messaging: MessagingProxy::builder(connection).path(path.clone())?.build().await?,
|
|
||||||
voice: VoiceProxy::builder(connection).path(path.clone())?.build().await?,
|
|
||||||
path,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn foo(&self) -> &ModemProxy<'a> {
|
|
||||||
&self.modem
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn messaging(&self) -> &MessagingProxy<'a> {
|
|
||||||
&self.messaging
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn voice(&self) -> &VoiceProxy<'a> {
|
|
||||||
&self.voice
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for Modem<'_> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
f.debug_struct("Modem")
|
|
||||||
.field("destination", &self.foo().destination())
|
|
||||||
.field("path", &self.foo().inner().path())
|
|
||||||
.field("interface", &self.foo().inner().interface())
|
|
||||||
.finish_non_exhaustive()
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue