Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
194e545a5a |
|||
|
8cce77bc7d |
|||
|
540ced4e32 |
10 changed files with 56 additions and 18 deletions
2
Makefile
2
Makefile
|
|
@ -145,6 +145,8 @@ 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 $@
|
||||
|
|
|
|||
12
README.md
12
README.md
|
|
@ -173,8 +173,8 @@ private headers that no distro installs.
|
|||
Setup:
|
||||
|
||||
```sh
|
||||
apk add imsd-ofono # or install the files by hand
|
||||
systemctl enable --now imsd-ofonod # system service; org.ofono is a system name
|
||||
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
|
||||
# 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,13 +218,17 @@ 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` (or imsd).** When the
|
||||
- **Restart GNOME Calls after restarting `imsd-ofonod` itself.** 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`.
|
||||
`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.
|
||||
|
||||
Development, without a phone or root:
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ import Imsd;
|
|||
namespace {
|
||||
|
||||
// ---- static config (env-overridable, same knobs as imsd.py) ---------------
|
||||
constexpr const char* Version = "0.3.7";
|
||||
constexpr const char* Version = "0.3.8";
|
||||
constexpr const char* BusName = "net.catcrafts.IMS1";
|
||||
constexpr const char* ObjPath = "/net/catcrafts/IMS1";
|
||||
constexpr const char* Iface = "net.catcrafts.IMS1";
|
||||
|
|
|
|||
|
|
@ -23,9 +23,15 @@ 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 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.
|
||||
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.
|
||||
- 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".
|
||||
|
|
@ -159,12 +165,13 @@ GVariant* PropChanged(const char* name, GVariant* value) {
|
|||
// ---- Modem / VoiceCallManager properties ------------------------------------
|
||||
bool VoiceUp() { return ImsdUp && Registered; }
|
||||
|
||||
// The registration gate: the plugin only builds an Origin while
|
||||
// org.ofono.VoiceCallManager is listed here.
|
||||
// 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.
|
||||
GVariant* InterfacesValue() {
|
||||
GVariantBuilder b;
|
||||
g_variant_builder_init(&b, G_VARIANT_TYPE("as"));
|
||||
if (VoiceUp()) g_variant_builder_add(&b, "s", VcmIface);
|
||||
g_variant_builder_add(&b, "s", VcmIface);
|
||||
return g_variant_builder_end(&b);
|
||||
}
|
||||
|
||||
|
|
@ -534,7 +541,7 @@ void HandleVcmMethod(GDBusConnection*, const gchar*, const gchar*, const gchar*,
|
|||
return;
|
||||
}
|
||||
if (!VoiceUp()) {
|
||||
g_dbus_method_invocation_return_dbus_error(inv, ErrFailed, "imsd is not registered");
|
||||
g_dbus_method_invocation_return_dbus_error(inv, ErrFailed, ImsdUp ? "imsd is not registered" : "imsd is not running");
|
||||
return;
|
||||
}
|
||||
Log(std::format("Dial({})", number));
|
||||
|
|
@ -594,11 +601,10 @@ const GDBusInterfaceVTable VcmVtable = { HandleVcmMethod, nullptr, nullptr, {} }
|
|||
const GDBusInterfaceVTable SsVtable = { HandleSsMethod, nullptr, nullptr, {} };
|
||||
|
||||
// ---- imsd events ------------------------------------------------------------
|
||||
void PublishInterfaces() {
|
||||
Emit(ModemPath, ModemIface, "PropertyChanged", PropChanged("Interfaces", InterfacesValue()));
|
||||
void PublishVoiceState() {
|
||||
Emit(ModemPath, ModemIface, "PropertyChanged",
|
||||
PropChanged("Online", g_variant_new_boolean(VoiceUp() ? TRUE : FALSE)));
|
||||
Log(std::format("voice interface {}", VoiceUp() ? "available" : "withdrawn"));
|
||||
Log(std::format("voice {}", VoiceUp() ? "registered" : (ImsdUp ? "unregistered" : "unavailable (imsd down)")));
|
||||
}
|
||||
|
||||
void OnImsdSignal(GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar* signal, GVariant* params, gpointer) {
|
||||
|
|
@ -640,7 +646,7 @@ void OnImsdSignal(GDBusConnection*, const gchar*, const gchar*, const gchar*, co
|
|||
g_variant_get(params, "(b)", ®);
|
||||
if (Registered == static_cast<bool>(reg)) return;
|
||||
Registered = reg;
|
||||
PublishInterfaces();
|
||||
PublishVoiceState();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -679,7 +685,7 @@ void OnImsdAppeared(GDBusConnection*, const gchar*, const gchar*, gpointer) {
|
|||
ImsdUp = true;
|
||||
Log("imsd up");
|
||||
RefreshFromImsd();
|
||||
PublishInterfaces();
|
||||
PublishVoiceState();
|
||||
}
|
||||
|
||||
void OnImsdVanished(GDBusConnection*, const gchar*, gpointer) {
|
||||
|
|
@ -690,7 +696,7 @@ void OnImsdVanished(GDBusConnection*, const gchar*, gpointer) {
|
|||
std::vector<std::string> live;
|
||||
for (const auto& [uni, rec] : Calls) live.push_back(uni);
|
||||
for (const std::string& uni : live) RemoveCall(uni, "network");
|
||||
PublishInterfaces();
|
||||
PublishVoiceState();
|
||||
}
|
||||
|
||||
gboolean OnTerm(gpointer loop) {
|
||||
|
|
|
|||
5
packaging/80-imsd-ofono.preset
Normal file
5
packaging/80-imsd-ofono.preset
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# 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,4 +46,9 @@ 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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,6 +70,8 @@ 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() {
|
||||
|
|
@ -79,6 +81,11 @@ 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() {
|
||||
|
|
|
|||
|
|
@ -72,6 +72,13 @@ 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);
|
||||
|
|
|
|||
|
|
@ -7,5 +7,6 @@ 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
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ 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))"
|
||||
|
|
|
|||
Loading…
Reference in a new issue