Watch
1
0
Fork
You've already forked SouveraineOS
0
SouveraineOS/docs/qtpim-contacts-handoff.md

8.1 KiB
Raw Blame History

qtpim contacts — state as of 2026-07-15

Casey (he/him). Pixel 3, mainline Arch. Ani + Aster = Annie. Souveraine = an OS, an agent substrate, and an agent.

Constraints (non-negotiable, learned the hard way this session)

  • No GNOME or KDE library dependencies. This rules out EDS/libebook (Evolution stack) and Akonadi/KPeople. EDS was investigated at length and rejected. Do not resurrect it.
  • The only thing EDS ever offered was "Chatty already reads it." Chatty is Casey's fork — teach Chatty to read the new store instead. The EDS book on the phone is empty (0 contacts). There is no sunk value there.
  • Cite file:line or say "not in the code / undecided." Never state a guess as established fact.

What is actually built and installed on the phone

qtpim dev — DONE, working.

  • Source: ~/Projects/qtpim, branch dev (the only branch), HEAD d03b5f6. Actively maintained upstream by Axel Spoerl (Qt Company), commits through July 2026.
  • Built native aarch64, 268/268 targets clean.
  • Installed to /usr (NOT /usr/local — Qt6's prefix is /usr/lib; a first attempt landed in /usr/local and was removed; only one copy exists now).
  • Artifacts: libQt6Contacts.so.6.12.0, libQt6Versit.so.6.12.0 (vCard), libQt6VersitOrganizer, QML modules QtContacts + QtOrganizer, Qt6Contacts.pc (6.12.0).
  • QML plugin links clean: libdeclarative_contactsplugin.so resolves libQt6Contacts.so.6 with no missing symbols.

Reconfigure line (idempotent):

cd ~/Projects/qtpim/_build
/usr/lib/qt6/bin/qt-cmake .. -GNinja -DCMAKE_BUILD_TYPE=Release \
  -DQT_NO_PACKAGE_VERSION_CHECK=TRUE \
  -DQT_NO_PACKAGE_VERSION_INCOMPATIBLE_WARNING=TRUE \
  -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_STAGING_PREFIX=/usr
ninja && sudo ninja install && sudo ldconfig

Caveats on the qtpim install

  • qtpim dev's CMakeLists.txt:14 does find_package(Qt6 6.12.0). The phone has Qt 6.11.1. QT_NO_PACKAGE_VERSION_CHECK=TRUE forces past that gate. It compiles and links clean, so the gate is bureaucratic, not a real API break — but libs are versioned 6.12.0 against a 6.11.1 Qt. Works; not blessed. Clean alternative: qt6-base-git (AUR) for a real 6.12 dev Qt, then no override needed. Big native build on a Pixel 3.
  • /usr/lib/qt6/bin/qt-configure-module is broken on Arch — it looks for qt-cmake-private at /usr/lib/qt6/lib/qt6/, actual location is /usr/lib/qt6/. Use qt-cmake directly (above).
  • This is a manual ninja install, not a package. A Qt update can stomp it. No PKGBUILD tracks it. (Casey's standing rule: untracked hand-installed binaries are a known gap — worth a PKGBUILD eventually.)

The actual blocker: there is no persistent backend

Only backend installed is libqtcontacts_memory.soRAM only, gone on restart. qtpim upstream ships only memory and serviceactionmanager.

So Chatty cannot swap to qtpim yet. There is nothing persistent to swap to. The store must exist first.

qtcontacts-sqlite attempt — BLOCKED, decision needed

~/Projects/qtcontacts-sqlite, cloned from sailfishos/qtcontacts-sqlite, HEAD 2939cf2. Active upstream (May 2026). qmake .pro, Qt5-era, RPM packaging.

Patched so far (all reversible; .orig files sit next to each):

  • config.priconfig.pri.orig: PKGCONFIG += Qt5ContactsQt6Contacts, c++11c++17, db path qtcontacts-sqlite-qt5/-qt6/.
  • src/engine/contactstransientstore.cpp.orig: QMutex::RecursiveQRecursiveMutex (Qt6 split the class), added #include <QRecursiveMutex>, QMutexLockerQMutexLocker<QRecursiveMutex> at 3 sites.
  • src/engine/contactsengine.h + .cpp.orig: dropped const from collection() / collections() — Qt6's QContactManagerEngine (/usr/include/qt6/QtContacts/qcontactmanagerengine.h:77-78) declares them non-const.

Those fixes worked — those errors are gone. qmake6 configures, exit 0.

Remaining errors, two kinds:

Mechanical Qt5→Qt6 drift (known fixes, tedious):

  • contactsengine.cpp:948,950,951,953,958QMutexLocker needs template args (JobThread::MutexUnlocker / m_locker)
  • contactsengine.cpp:1244,1273 — deleted QMutexLocker copy ctor
  • contactsengine.cpp:1297qRegisterMetaTypeStreamOperators removed in Qt6

The real problem — QContact::IgnoreAccessConstraints:

Verified by grep:

  • NOT in /usr/include/qt6/QtContacts/ (upstream Qt6 headers)
  • NOT in ~/Projects/qtpim/src/contacts/*.h (upstream dev source)
  • IS in sailfishos/qtpim fork at src/contacts/qcontact.h:59

So qtcontacts-sqlite is not a Qt5 engine needing a port. It is written against Sailfish's forked qtpim, which carries API upstream never had. Call sites: contactreader.cpp:764,1997, contactwriter.cpp:3473,3512,3558, 3954,3967,3976,3984, contactsengine.cpp — 8+ places.

Stubbing it out means silently changing access-constraint semantics in a contacts store. Not a safe sed.

Three paths — Casey's call, not to be picked unilaterally

  1. Finish the mechanical fixes, then invent semantics for IgnoreAccessConstraints against upstream. Cheap up front, quiet wrongness later. Not recommended.
  2. Build Sailfish's qtpim fork instead of upstream dev. qtcontacts-sqlite then compiles as designed. But Casey asked for dev specifically, and the Sailfish fork was last touched 2021. Trades dev for fork debt.
  3. Write a sqlite engine against upstream dev. Template is the in-tree memory backend: ~/Projects/qtpim/src/plugins/contacts/memory/, 1,070 lines, complete working reference. Only 2 pure virtuals are mandatory (managerName(), managerVersion()); the other 33 virtuals have working defaults — implement save/remove/fetch, inherit the rest. More work up front, no fork debt, it's Casey's.

Why qtpim over EDS (settled, don't relitigate)

qtpim EDS
Shape in-process library + plugin engine D-Bus daemon, mandatory
D-Bus in source zero (verified by grep) the entire architecture
Backend yours, swappable Evolution's model
QML native module in-tree none
vCard in-tree (src/versit) yes
Must implement 2 methods n/a — you adapt to it

Precedent: UBports ships this exact stack today — gitlab.com/ubports/development/core/lomiri-addressbook-app (active 2026-06-23) builds against qtpim5-dev + qml-module-qtcontacts. They pin a git snapshot (qtpim5-dev (>= 5.0~git20171109~0bd985b)) — that's what vendoring an unreleased module looks like. They also have a separate lomiri-address-book-service because multiple apps share one store. Chatty is a second reader, so that concern is real — but solve it when there are two readers; "both open the same sqlite store" may be enough. Don't pre-build it.

Note UBports/Sailfish use qtcontacts-sqlite (their own DB), not EDS. Nobody in that lineage uses EDS.

Chatty state (unchanged this session — no code touched)

~/Projects/Chatty, design doc PAF-chatty-identity-layer.md.

  • Steps 13 built and working: persons / person_addresses / person_link_exceptions tables at HISTORY_VERSION 6; ChattyPerson + chatty_identity_* API; chatty_chat_get_priority_section() re-keyed onto Person. Matrix rooms no longer auto-bucket as Known — the original bug.
  • chatty-identity.c currently forwards to Chatty's private SQL tables. That's the seam that would repoint at a qtpim store.
  • Binding seam to be aware of: Chatty is C/GObject, qtpim is C++/Qt. Not a blocker, not free.
  • The design doc still contains an EDS pivot section — that is dead. Superseded by this file. Steps 13 in it are still valid.
  • Still missing: any favoriting UI at all. That gap is what started this whole investigation ("what is the methodology to favorite someone?").

Open question that was never answered

What are contacts for in Souveraine? An address book, or people Annie knows (stable referent across transports + git-backed memory)? That answer probably determines whether the store is a contacts DB at all. This was asked and never resolved — resolve it before writing an engine.