Compare commits
10 changed files with 18 additions and 56 deletions
2
Makefile
2
Makefile
|
|
@ -145,8 +145,6 @@ install: all
|
||||||
$(DESTDIR)$(PREFIX)/share/dbus-1/system.d/imsd-ofono.conf
|
$(DESTDIR)$(PREFIX)/share/dbus-1/system.d/imsd-ofono.conf
|
||||||
install -Dm644 packaging/90_imsd-ofono.gschema.override \
|
install -Dm644 packaging/90_imsd-ofono.gschema.override \
|
||||||
$(DESTDIR)$(PREFIX)/share/glib-2.0/schemas/90_imsd-ofono.gschema.override
|
$(DESTDIR)$(PREFIX)/share/glib-2.0/schemas/90_imsd-ofono.gschema.override
|
||||||
install -Dm644 packaging/80-imsd-ofono.preset \
|
|
||||||
$(DESTDIR)$(PREFIX)/lib/systemd/system-preset/80-imsd-ofono.preset
|
|
||||||
|
|
||||||
$(PCM) $(OBJ) $(O)/tests:
|
$(PCM) $(OBJ) $(O)/tests:
|
||||||
mkdir -p $@
|
mkdir -p $@
|
||||||
|
|
|
||||||
12
README.md
12
README.md
|
|
@ -173,8 +173,8 @@ private headers that no distro installs.
|
||||||
Setup:
|
Setup:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
apk add imsd-ofono # enables imsd-ofonod via a systemd preset
|
apk add imsd-ofono # or install the files by hand
|
||||||
systemctl enable --now imsd-ofonod # hand installs: system service, org.ofono is a system name
|
systemctl enable --now imsd-ofonod # system service; org.ofono is a system name
|
||||||
# point Calls at the ofono provider (the package ships this as a gschema
|
# point Calls at the ofono provider (the package ships this as a gschema
|
||||||
# override; this is the per-user equivalent)
|
# override; this is the per-user equivalent)
|
||||||
gsettings set org.gnome.Calls autoload-plugins "['ofono']"
|
gsettings set org.gnome.Calls autoload-plugins "['ofono']"
|
||||||
|
|
@ -218,17 +218,13 @@ Known gaps, all inherited rather than introduced:
|
||||||
normal dialpad is unaffected — that reaches imsd's own classifier.
|
normal dialpad is unaffected — that reaches imsd's own classifier.
|
||||||
- DTMF is forwarded to imsd, where `SendDtmf` is still a stub (RFC 4733 is not
|
- DTMF is forwarded to imsd, where `SendDtmf` is still a stub (RFC 4733 is not
|
||||||
implemented yet) — the same limitation Plasma has.
|
implemented yet) — the same limitation Plasma has.
|
||||||
- **Restart GNOME Calls after restarting `imsd-ofonod` itself.** When the
|
- **Restart GNOME Calls after restarting `imsd-ofonod` (or imsd).** When the
|
||||||
modem's `VoiceCallManager` interface goes away and comes back, Calls 50.0
|
modem's `VoiceCallManager` interface goes away and comes back, Calls 50.0
|
||||||
adds a new origin but leaves the old origin's `CallAdded` handler connected:
|
adds a new origin but leaves the old origin's `CallAdded` handler connected:
|
||||||
after one such cycle every call is added twice, after a few the stale handler
|
after one such cycle every call is added twice, after a few the stale handler
|
||||||
runs on freed memory and Calls dies with SIGBUS in `g_hash_table_lookup`
|
runs on freed memory and Calls dies with SIGBUS in `g_hash_table_lookup`
|
||||||
(measured on the FP6). Calls-side; an upstream fix belongs in
|
(measured on the FP6). Calls-side; an upstream fix belongs in
|
||||||
`plugins/provider/ofono/calls-ofono-provider.c`. To keep imsd's own
|
`plugins/provider/ofono/calls-ofono-provider.c`.
|
||||||
restarts and registration drops from triggering it, `imsd-ofonod` lists the
|
|
||||||
interface permanently: `Online` tracks registration, and `Dial` fails with
|
|
||||||
"imsd is not registered" / "imsd is not running" instead. Only `org.ofono`
|
|
||||||
vanishing — this daemon restarting — still cycles the origin.
|
|
||||||
|
|
||||||
Development, without a phone or root:
|
Development, without a phone or root:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ import Imsd;
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// ---- static config (env-overridable, same knobs as imsd.py) ---------------
|
// ---- static config (env-overridable, same knobs as imsd.py) ---------------
|
||||||
constexpr const char* Version = "0.3.8";
|
constexpr const char* Version = "0.3.7";
|
||||||
constexpr const char* BusName = "net.catcrafts.IMS1";
|
constexpr const char* BusName = "net.catcrafts.IMS1";
|
||||||
constexpr const char* ObjPath = "/net/catcrafts/IMS1";
|
constexpr const char* ObjPath = "/net/catcrafts/IMS1";
|
||||||
constexpr const char* Iface = "net.catcrafts.IMS1";
|
constexpr const char* Iface = "net.catcrafts.IMS1";
|
||||||
|
|
|
||||||
|
|
@ -23,15 +23,9 @@ D-Bus seam a third party can implement.
|
||||||
Consumer-shaped details, verified against calls 50.0
|
Consumer-shaped details, verified against calls 50.0
|
||||||
plugins/provider/ofono/ — get these wrong and the plugin silently ignores us:
|
plugins/provider/ofono/ — get these wrong and the plugin silently ignores us:
|
||||||
- the provider watches `org.ofono` on the SYSTEM bus and proxies `/` as
|
- the provider watches `org.ofono` on the SYSTEM bus and proxies `/` as
|
||||||
org.ofono.Manager. A modem is an Origin exactly while its `Interfaces`
|
org.ofono.Manager. A modem becomes a dialable Origin only while its
|
||||||
property lists "org.ofono.VoiceCallManager" — and Calls 50.0 never
|
`Interfaces` property contains "org.ofono.VoiceCallManager", so that list
|
||||||
disconnects a removed Origin's CallAdded handler, so every withdraw/
|
is our registration gate — the analogue of the dialerd's deviceUniList.
|
||||||
re-add cycle leaves a stale handler behind (calls announced twice, then
|
|
||||||
a crash on freed memory; measured on the FP6). The interface is
|
|
||||||
therefore listed PERMANENTLY; registration is reported through the
|
|
||||||
modem's `Online` property and enforced in Dial, which fails legibly
|
|
||||||
while imsd is down or unregistered. Only this daemon's own restart
|
|
||||||
(org.ofono vanishing) still cycles the Origin.
|
|
||||||
- VoiceCall `State` strings are parsed as CallsCallState enum nicks:
|
- VoiceCall `State` strings are parsed as CallsCallState enum nicks:
|
||||||
dialing / alerting / incoming / active / held / disconnected. imsd's
|
dialing / alerting / incoming / active / held / disconnected. imsd's
|
||||||
"ringing" (a 180 from the far end) is oFono's "alerting".
|
"ringing" (a 180 from the far end) is oFono's "alerting".
|
||||||
|
|
@ -165,13 +159,12 @@ GVariant* PropChanged(const char* name, GVariant* value) {
|
||||||
// ---- Modem / VoiceCallManager properties ------------------------------------
|
// ---- Modem / VoiceCallManager properties ------------------------------------
|
||||||
bool VoiceUp() { return ImsdUp && Registered; }
|
bool VoiceUp() { return ImsdUp && Registered; }
|
||||||
|
|
||||||
// Listed unconditionally: the plugin builds one Origin per appearance of
|
// The registration gate: the plugin only builds an Origin while
|
||||||
// this interface and cannot survive a re-appearance (header). Whether calls
|
// org.ofono.VoiceCallManager is listed here.
|
||||||
// can actually be placed is VoiceUp(), checked in Dial and shown as Online.
|
|
||||||
GVariant* InterfacesValue() {
|
GVariant* InterfacesValue() {
|
||||||
GVariantBuilder b;
|
GVariantBuilder b;
|
||||||
g_variant_builder_init(&b, G_VARIANT_TYPE("as"));
|
g_variant_builder_init(&b, G_VARIANT_TYPE("as"));
|
||||||
g_variant_builder_add(&b, "s", VcmIface);
|
if (VoiceUp()) g_variant_builder_add(&b, "s", VcmIface);
|
||||||
return g_variant_builder_end(&b);
|
return g_variant_builder_end(&b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -541,7 +534,7 @@ void HandleVcmMethod(GDBusConnection*, const gchar*, const gchar*, const gchar*,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!VoiceUp()) {
|
if (!VoiceUp()) {
|
||||||
g_dbus_method_invocation_return_dbus_error(inv, ErrFailed, ImsdUp ? "imsd is not registered" : "imsd is not running");
|
g_dbus_method_invocation_return_dbus_error(inv, ErrFailed, "imsd is not registered");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Log(std::format("Dial({})", number));
|
Log(std::format("Dial({})", number));
|
||||||
|
|
@ -601,10 +594,11 @@ const GDBusInterfaceVTable VcmVtable = { HandleVcmMethod, nullptr, nullptr, {} }
|
||||||
const GDBusInterfaceVTable SsVtable = { HandleSsMethod, nullptr, nullptr, {} };
|
const GDBusInterfaceVTable SsVtable = { HandleSsMethod, nullptr, nullptr, {} };
|
||||||
|
|
||||||
// ---- imsd events ------------------------------------------------------------
|
// ---- imsd events ------------------------------------------------------------
|
||||||
void PublishVoiceState() {
|
void PublishInterfaces() {
|
||||||
|
Emit(ModemPath, ModemIface, "PropertyChanged", PropChanged("Interfaces", InterfacesValue()));
|
||||||
Emit(ModemPath, ModemIface, "PropertyChanged",
|
Emit(ModemPath, ModemIface, "PropertyChanged",
|
||||||
PropChanged("Online", g_variant_new_boolean(VoiceUp() ? TRUE : FALSE)));
|
PropChanged("Online", g_variant_new_boolean(VoiceUp() ? TRUE : FALSE)));
|
||||||
Log(std::format("voice {}", VoiceUp() ? "registered" : (ImsdUp ? "unregistered" : "unavailable (imsd down)")));
|
Log(std::format("voice interface {}", VoiceUp() ? "available" : "withdrawn"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnImsdSignal(GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar* signal, GVariant* params, gpointer) {
|
void OnImsdSignal(GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar* signal, GVariant* params, gpointer) {
|
||||||
|
|
@ -646,7 +640,7 @@ void OnImsdSignal(GDBusConnection*, const gchar*, const gchar*, const gchar*, co
|
||||||
g_variant_get(params, "(b)", ®);
|
g_variant_get(params, "(b)", ®);
|
||||||
if (Registered == static_cast<bool>(reg)) return;
|
if (Registered == static_cast<bool>(reg)) return;
|
||||||
Registered = reg;
|
Registered = reg;
|
||||||
PublishVoiceState();
|
PublishInterfaces();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -685,7 +679,7 @@ void OnImsdAppeared(GDBusConnection*, const gchar*, const gchar*, gpointer) {
|
||||||
ImsdUp = true;
|
ImsdUp = true;
|
||||||
Log("imsd up");
|
Log("imsd up");
|
||||||
RefreshFromImsd();
|
RefreshFromImsd();
|
||||||
PublishVoiceState();
|
PublishInterfaces();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnImsdVanished(GDBusConnection*, const gchar*, gpointer) {
|
void OnImsdVanished(GDBusConnection*, const gchar*, gpointer) {
|
||||||
|
|
@ -696,7 +690,7 @@ void OnImsdVanished(GDBusConnection*, const gchar*, gpointer) {
|
||||||
std::vector<std::string> live;
|
std::vector<std::string> live;
|
||||||
for (const auto& [uni, rec] : Calls) live.push_back(uni);
|
for (const auto& [uni, rec] : Calls) live.push_back(uni);
|
||||||
for (const std::string& uni : live) RemoveCall(uni, "network");
|
for (const std::string& uni : live) RemoveCall(uni, "network");
|
||||||
PublishVoiceState();
|
PublishInterfaces();
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean OnTerm(gpointer loop) {
|
gboolean OnTerm(gpointer loop) {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
# SPDX-License-Identifier: GPL-3.0-only
|
|
||||||
# SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts®
|
|
||||||
# imsd-ofono is the opt-in GNOME Calls backend: installing it is the choice
|
|
||||||
# to run it (the unit itself refuses to coexist with a real ofonod).
|
|
||||||
enable imsd-ofonod.service
|
|
||||||
|
|
@ -46,9 +46,4 @@ ofono() {
|
||||||
amove usr/lib/systemd/system/imsd-ofonod.service
|
amove usr/lib/systemd/system/imsd-ofonod.service
|
||||||
amove usr/share/dbus-1/system.d/imsd-ofono.conf
|
amove usr/share/dbus-1/system.d/imsd-ofono.conf
|
||||||
amove usr/share/glib-2.0/schemas/90_imsd-ofono.gschema.override
|
amove usr/share/glib-2.0/schemas/90_imsd-ofono.gschema.override
|
||||||
amove usr/lib/systemd/system-preset/80-imsd-ofono.preset
|
|
||||||
# enabled on install, like imsd.service in the main package
|
|
||||||
mkdir -p "$subpkgdir"/etc/systemd/system/multi-user.target.wants
|
|
||||||
ln -s /usr/lib/systemd/system/imsd-ofonod.service \
|
|
||||||
"$subpkgdir"/etc/systemd/system/multi-user.target.wants/imsd-ofonod.service
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -70,8 +70,6 @@ package() {
|
||||||
"$pkgdir"/usr/share/dbus-1/system.d/imsd-ofono.conf
|
"$pkgdir"/usr/share/dbus-1/system.d/imsd-ofono.conf
|
||||||
install -Dm644 90_imsd-ofono.gschema.override \
|
install -Dm644 90_imsd-ofono.gschema.override \
|
||||||
"$pkgdir"/usr/share/glib-2.0/schemas/90_imsd-ofono.gschema.override
|
"$pkgdir"/usr/share/glib-2.0/schemas/90_imsd-ofono.gschema.override
|
||||||
install -Dm644 80-imsd-ofono.preset \
|
|
||||||
"$pkgdir"/usr/lib/systemd/system-preset/80-imsd-ofono.preset
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ofono() {
|
ofono() {
|
||||||
|
|
@ -81,11 +79,6 @@ ofono() {
|
||||||
amove usr/lib/systemd/system/imsd-ofonod.service
|
amove usr/lib/systemd/system/imsd-ofonod.service
|
||||||
amove usr/share/dbus-1/system.d/imsd-ofono.conf
|
amove usr/share/dbus-1/system.d/imsd-ofono.conf
|
||||||
amove usr/share/glib-2.0/schemas/90_imsd-ofono.gschema.override
|
amove usr/share/glib-2.0/schemas/90_imsd-ofono.gschema.override
|
||||||
amove usr/lib/systemd/system-preset/80-imsd-ofono.preset
|
|
||||||
# enabled on install, like imsd.service in the main package
|
|
||||||
mkdir -p "$subpkgdir"/etc/systemd/system/multi-user.target.wants
|
|
||||||
ln -s /usr/lib/systemd/system/imsd-ofonod.service \
|
|
||||||
"$subpkgdir"/etc/systemd/system/multi-user.target.wants/imsd-ofonod.service
|
|
||||||
}
|
}
|
||||||
|
|
||||||
systemd() {
|
systemd() {
|
||||||
|
|
|
||||||
|
|
@ -72,13 +72,6 @@ fi
|
||||||
lookup_profile() { # $1 = log suffix; sets PROFILE_ID, LOOKUP=done on a usable list
|
lookup_profile() { # $1 = log suffix; sets PROFILE_ID, LOOKUP=done on a usable list
|
||||||
[ "$LOOKUP" = done ] && return 0
|
[ "$LOOKUP" = done ] && return 0
|
||||||
if OUT=$(qmicli -d qrtr://0 --wds-get-profile-list=3gpp 2>&1); then
|
if OUT=$(qmicli -d qrtr://0 --wds-get-profile-list=3gpp 2>&1); then
|
||||||
# a list with no profiles at all is the modem still coming up, not
|
|
||||||
# a modem without an ims profile (dev phone cold boot 2026-09-20
|
|
||||||
# 16:47: exit 0, no entries, index 2 present a minute later)
|
|
||||||
if ! printf '%s\n' "$OUT" | grep -q -E '^[[:space:]]*\[[0-9]+\] 3gpp'; then
|
|
||||||
log "ims profile lookup returned no profiles$1"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
PROFILE_ID=$(printf '%s\n' "$OUT" | awk -v apn="$IMS_APN" '
|
PROFILE_ID=$(printf '%s\n' "$OUT" | awk -v apn="$IMS_APN" '
|
||||||
/^[ \t]*\[[0-9]+\] 3gpp/ { idx = $1; gsub(/[^0-9]/, "", idx) }
|
/^[ \t]*\[[0-9]+\] 3gpp/ { idx = $1; gsub(/[^0-9]/, "", idx) }
|
||||||
/APN:/ { a = $0; sub(/.*APN: '"'"'/, "", a); sub(/'"'"'.*/, "", a);
|
/APN:/ { a = $0; sub(/.*APN: '"'"'/, "", a); sub(/'"'"'.*/, "", a);
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,5 @@ Comment=Plasma Dialer backend for imsd (replaces plasma-dialer's modem-daemon)
|
||||||
Exec=/usr/bin/imsd-dialerd
|
Exec=/usr/bin/imsd-dialerd
|
||||||
Icon=call-start
|
Icon=call-start
|
||||||
NoDisplay=true
|
NoDisplay=true
|
||||||
OnlyShowIn=KDE;
|
|
||||||
X-KDE-autostart-phase=1
|
X-KDE-autostart-phase=1
|
||||||
X-KDE-StartupNotify=false
|
X-KDE-StartupNotify=false
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,6 @@ cp "$OFONOD" "$stage/imsd-$VER/imsd-ofonod"
|
||||||
cp packaging/ims-pdn-up.sh packaging/imsd.service \
|
cp packaging/ims-pdn-up.sh packaging/imsd.service \
|
||||||
packaging/imsd-dialerd.desktop packaging/imsd-ofonod.service \
|
packaging/imsd-dialerd.desktop packaging/imsd-ofonod.service \
|
||||||
packaging/org.ofono.conf packaging/90_imsd-ofono.gschema.override \
|
packaging/org.ofono.conf packaging/90_imsd-ofono.gschema.override \
|
||||||
packaging/80-imsd-ofono.preset \
|
|
||||||
packaging/net.catcrafts.IMS1.conf "$stage/imsd-$VER/"
|
packaging/net.catcrafts.IMS1.conf "$stage/imsd-$VER/"
|
||||||
tar -C "$stage" -czf "imsd-$VER.tar.gz" "imsd-$VER"
|
tar -C "$stage" -czf "imsd-$VER.tar.gz" "imsd-$VER"
|
||||||
echo "wrote imsd-$VER.tar.gz ($(du -h "imsd-$VER.tar.gz" | cut -f1))"
|
echo "wrote imsd-$VER.tar.gz ($(du -h "imsd-$VER.tar.gz" | cut -f1))"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue