8.1 KiB
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:lineor 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, branchdev(the only branch), HEADd03b5f6. 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/localand was removed; only one copy exists now). - Artifacts:
libQt6Contacts.so.6.12.0,libQt6Versit.so.6.12.0(vCard),libQt6VersitOrganizer, QML modulesQtContacts+QtOrganizer,Qt6Contacts.pc(6.12.0). - QML plugin links clean:
libdeclarative_contactsplugin.soresolveslibQt6Contacts.so.6with 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:14doesfind_package(Qt6 6.12.0). The phone has Qt 6.11.1.QT_NO_PACKAGE_VERSION_CHECK=TRUEforces past that gate. It compiles and links clean, so the gate is bureaucratic, not a real API break — but libs are versioned6.12.0against 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-moduleis broken on Arch — it looks forqt-cmake-privateat/usr/lib/qt6/lib/qt6/, actual location is/usr/lib/qt6/. Useqt-cmakedirectly (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.so — RAM 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.pri→config.pri.orig:PKGCONFIG += Qt5Contacts→Qt6Contacts,c++11→c++17, db pathqtcontacts-sqlite-qt5/→-qt6/.src/engine/contactstransientstore.cpp→.orig:QMutex::Recursive→QRecursiveMutex(Qt6 split the class), added#include <QRecursiveMutex>,QMutexLocker→QMutexLocker<QRecursiveMutex>at 3 sites.src/engine/contactsengine.h+.cpp→.orig: droppedconstfromcollection()/collections()— Qt6'sQContactManagerEngine(/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,958—QMutexLockerneeds template args (JobThread::MutexUnlocker/m_locker)contactsengine.cpp:1244,1273— deletedQMutexLockercopy ctorcontactsengine.cpp:1297—qRegisterMetaTypeStreamOperatorsremoved 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/qtpimfork atsrc/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
- Finish the mechanical fixes, then invent semantics for
IgnoreAccessConstraintsagainst upstream. Cheap up front, quiet wrongness later. Not recommended. - 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.
- Write a sqlite engine against upstream dev. Template is the in-tree
memorybackend:~/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 1–3 built and working:
persons/person_addresses/person_link_exceptionstables atHISTORY_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.ccurrently 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 1–3 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.