From 279cc6406e034c2188ec561c6a8f6175b01b4c4f Mon Sep 17 00:00:00 2001 From: Fathi Ben Nasr Date: Sat, 5 Sep 2026 03:37:09 +0000 Subject: [PATCH] PdoAddressBook: GetContactByEmail() passed the wrong columns GetContactByEmail() runs SELECT DISTINCT id_contact FROM rainloop_ab_properties WHERE ... and hands the statement to getContactsFromPDO(), which unconditionally reads id_contact_str, changed, etag and jcard from every row. None of those are selected, so every match raises three PHP warnings: Undefined array key "id_contact_str" Undefined array key "changed" Undefined array key "etag" and the Contact that comes back carries IdContactStr '' with Changed and Etag both 0 -- values a CardDAV sync would use. The lookup itself still works: with no jcard column either, every row falls into the follow-up properties query, so the contact data is right and only the metadata is wrong. That is what makes it easy to miss. It is not rare. The avatars plugin calls GetContactByEmail() for the sender of a message, so a mailbox view triggers it repeatedly -- 23 warnings in a single session on one of our installs. Fix: look the contact up by id instead. GetContactByID() already selects the columns getContactsFromPDO() expects, so the Contact comes back complete, and the search query keeps doing what it is good at -- finding the id. The unused $oContact and $iIdContact locals go with it. Verified against a real PDO: the current query returns one column and the reader warns on id_contact_str; the replacement returns all of them, warns nothing, and yields the real IdContactStr and changed instead of '' and 0. Note: this layer has no test suite upstream, so the verification is a standalone reproduction rather than an added test. --- .../Providers/AddressBook/PdoAddressBook.php | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/PdoAddressBook.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/PdoAddressBook.php index 155ea781d..129942975 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/PdoAddressBook.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/PdoAddressBook.php @@ -723,14 +723,20 @@ class PdoAddressBook $aParams[':search_lower'] = array($sLowerSearch, \PDO::PARAM_STR); } - $oContact = null; - $iIdContact = 0; + // This query selects id_contact only, so it must not be handed to + // getContactsFromPDO(), which unconditionally reads id_contact_str, + // changed, etag and jcard from every row. Look the contact up by id + // instead: GetContactByID() selects those columns, so the Contact it + // returns carries a real etag and changed value rather than 0. + $oStmt = $this->prepareAndExecute($sSql, $aParams); + if ($oStmt) { + $aFetch = $oStmt->fetchAll(\PDO::FETCH_ASSOC); + if (\is_array($aFetch) && \count($aFetch) && !empty($aFetch[0]['id_contact'])) { + return $this->GetContactByID((int) $aFetch[0]['id_contact']); + } + } - $aContacts = $this->getContactsFromPDO( - $this->prepareAndExecute($sSql, $aParams) - ); - - return $aContacts ? $aContacts[0] : null; + return null; } /**