diff --git a/Makefile b/Makefile index a72e15e..758d1ba 100644 --- a/Makefile +++ b/Makefile @@ -145,8 +145,6 @@ install: all $(DESTDIR)$(PREFIX)/share/dbus-1/system.d/imsd-ofono.conf install -Dm644 packaging/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: mkdir -p $@ diff --git a/README.md b/README.md index 447043a..e2b3fdf 100644 --- a/README.md +++ b/README.md @@ -173,8 +173,8 @@ private headers that no distro installs. Setup: ```sh -apk add imsd-ofono # enables imsd-ofonod via a systemd preset -systemctl enable --now imsd-ofonod # hand installs: system service, org.ofono is a system name +apk add imsd-ofono # or install the files by hand +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 # override; this is the per-user equivalent) 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. - DTMF is forwarded to imsd, where `SendDtmf` is still a stub (RFC 4733 is not 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 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 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 - `plugins/provider/ofono/calls-ofono-provider.c`. To keep imsd's own - 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. + `plugins/provider/ofono/calls-ofono-provider.c`. Development, without a phone or root: diff --git a/implementations/main.cpp b/implementations/main.cpp index 85f8ac2..f297f42 100644 --- a/implementations/main.cpp +++ b/implementations/main.cpp @@ -41,7 +41,7 @@ import Imsd; namespace { // ---- 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* ObjPath = "/net/catcrafts/IMS1"; constexpr const char* Iface = "net.catcrafts.IMS1"; diff --git a/implementations/ofonod.cpp b/implementations/ofonod.cpp index a93bb15..79c941e 100644 --- a/implementations/ofonod.cpp +++ b/implementations/ofonod.cpp @@ -23,15 +23,9 @@ D-Bus seam a third party can implement. Consumer-shaped details, verified against calls 50.0 plugins/provider/ofono/ — get these wrong and the plugin silently ignores us: - the provider watches `org.ofono` on the SYSTEM bus and proxies `/` as - org.ofono.Manager. A modem is an Origin exactly while its `Interfaces` - property lists "org.ofono.VoiceCallManager" — and Calls 50.0 never - disconnects a removed Origin's CallAdded handler, so every withdraw/ - 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. + org.ofono.Manager. A modem becomes a dialable Origin only while its + `Interfaces` property contains "org.ofono.VoiceCallManager", so that list + is our registration gate — the analogue of the dialerd's deviceUniList. - VoiceCall `State` strings are parsed as CallsCallState enum nicks: dialing / alerting / incoming / active / held / disconnected. imsd's "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 ------------------------------------ bool VoiceUp() { return ImsdUp && Registered; } -// Listed unconditionally: the plugin builds one Origin per appearance of -// this interface and cannot survive a re-appearance (header). Whether calls -// can actually be placed is VoiceUp(), checked in Dial and shown as Online. +// The registration gate: the plugin only builds an Origin while +// org.ofono.VoiceCallManager is listed here. GVariant* InterfacesValue() { GVariantBuilder b; 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); } @@ -541,7 +534,7 @@ void HandleVcmMethod(GDBusConnection*, const gchar*, const gchar*, const gchar*, return; } 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; } Log(std::format("Dial({})", number)); @@ -601,10 +594,11 @@ const GDBusInterfaceVTable VcmVtable = { HandleVcmMethod, nullptr, nullptr, {} } const GDBusInterfaceVTable SsVtable = { HandleSsMethod, nullptr, nullptr, {} }; // ---- imsd events ------------------------------------------------------------ -void PublishVoiceState() { +void PublishInterfaces() { + Emit(ModemPath, ModemIface, "PropertyChanged", PropChanged("Interfaces", InterfacesValue())); Emit(ModemPath, ModemIface, "PropertyChanged", 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) { @@ -646,7 +640,7 @@ void OnImsdSignal(GDBusConnection*, const gchar*, const gchar*, const gchar*, co g_variant_get(params, "(b)", ®); if (Registered == static_cast(reg)) return; Registered = reg; - PublishVoiceState(); + PublishInterfaces(); } } @@ -685,7 +679,7 @@ void OnImsdAppeared(GDBusConnection*, const gchar*, const gchar*, gpointer) { ImsdUp = true; Log("imsd up"); RefreshFromImsd(); - PublishVoiceState(); + PublishInterfaces(); } void OnImsdVanished(GDBusConnection*, const gchar*, gpointer) { @@ -696,7 +690,7 @@ void OnImsdVanished(GDBusConnection*, const gchar*, gpointer) { std::vector live; for (const auto& [uni, rec] : Calls) live.push_back(uni); for (const std::string& uni : live) RemoveCall(uni, "network"); - PublishVoiceState(); + PublishInterfaces(); } gboolean OnTerm(gpointer loop) { diff --git a/packaging/80-imsd-ofono.preset b/packaging/80-imsd-ofono.preset deleted file mode 100644 index c76458b..0000000 --- a/packaging/80-imsd-ofono.preset +++ /dev/null @@ -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 diff --git a/packaging/APKBUILD b/packaging/APKBUILD index b85b738..a048ea7 100644 --- a/packaging/APKBUILD +++ b/packaging/APKBUILD @@ -46,9 +46,4 @@ ofono() { amove usr/lib/systemd/system/imsd-ofonod.service amove usr/share/dbus-1/system.d/imsd-ofono.conf 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 } diff --git a/packaging/APKBUILD.binary b/packaging/APKBUILD.binary index 486f4bc..97a588f 100644 --- a/packaging/APKBUILD.binary +++ b/packaging/APKBUILD.binary @@ -70,8 +70,6 @@ package() { "$pkgdir"/usr/share/dbus-1/system.d/imsd-ofono.conf install -Dm644 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() { @@ -81,11 +79,6 @@ ofono() { amove usr/lib/systemd/system/imsd-ofonod.service amove usr/share/dbus-1/system.d/imsd-ofono.conf 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() { diff --git a/packaging/ims-pdn-up.sh b/packaging/ims-pdn-up.sh index 9cf899f..3ba1603 100644 --- a/packaging/ims-pdn-up.sh +++ b/packaging/ims-pdn-up.sh @@ -72,13 +72,6 @@ fi lookup_profile() { # $1 = log suffix; sets PROFILE_ID, LOOKUP=done on a usable list [ "$LOOKUP" = done ] && return 0 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" ' /^[ \t]*\[[0-9]+\] 3gpp/ { idx = $1; gsub(/[^0-9]/, "", idx) } /APN:/ { a = $0; sub(/.*APN: '"'"'/, "", a); sub(/'"'"'.*/, "", a); diff --git a/packaging/imsd-dialerd.desktop b/packaging/imsd-dialerd.desktop index c1c1b27..9904d01 100644 --- a/packaging/imsd-dialerd.desktop +++ b/packaging/imsd-dialerd.desktop @@ -7,6 +7,5 @@ Comment=Plasma Dialer backend for imsd (replaces plasma-dialer's modem-daemon) Exec=/usr/bin/imsd-dialerd Icon=call-start NoDisplay=true -OnlyShowIn=KDE; X-KDE-autostart-phase=1 X-KDE-StartupNotify=false diff --git a/packaging/make-bin-tarball.sh b/packaging/make-bin-tarball.sh index 72934bb..24e4ffe 100755 --- a/packaging/make-bin-tarball.sh +++ b/packaging/make-bin-tarball.sh @@ -27,7 +27,6 @@ cp "$OFONOD" "$stage/imsd-$VER/imsd-ofonod" cp packaging/ims-pdn-up.sh packaging/imsd.service \ packaging/imsd-dialerd.desktop packaging/imsd-ofonod.service \ packaging/org.ofono.conf packaging/90_imsd-ofono.gschema.override \ - packaging/80-imsd-ofono.preset \ packaging/net.catcrafts.IMS1.conf "$stage/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))"