Skip to content

Commit

Permalink
[buteo-sync-plugins-social] Fix Google contact sync issues. JB#51541
Browse files Browse the repository at this point in the history
When upsyncing contacts, the server will reply with an updated etag
for each contact in postFinishedHandler(). Save the etags to their
contacts before calling localChangesStoredRemotely(), which will save
the updated contacts to the database. Also save the avatars at this
point instead of in finalize(), as calling QContactManager::saveContacts()
will flag the contacts as modified and cause spurious modification
detections on the next upsync.

Also:
- Ensure the correct detail is looked up for the etag data
- Don't remove contacts from the localAdded/Modified lists in
batchRemoteChanges(), because these lists are then passed onto
localChangesStoredRemotely() for saving
- Save the last sync time in finalize() so that it is not saved if the
sync failed.
  • Loading branch information
blammit committed Oct 21, 2020
1 parent 46d255d commit dbc7cbb
Show file tree
Hide file tree
Showing 7 changed files with 167 additions and 104 deletions.
1 change: 1 addition & 0 deletions rpm/sociald.spec
Expand Up @@ -15,6 +15,7 @@ BuildRequires: pkgconfig(libsignon-qt5)
BuildRequires: pkgconfig(accounts-qt5) >= 1.13
BuildRequires: pkgconfig(socialcache) >= 0.0.48
BuildRequires: pkgconfig(libsailfishkeyprovider)
BuildRequires: pkgconfig(contactcache-qt5)
BuildRequires: pkgconfig(qtcontacts-sqlite-qt5-extensions) >= 0.3.0
BuildRequires: qt5-qttools-linguist
Requires: buteo-syncfw-qt5-msyncd
Expand Down
2 changes: 1 addition & 1 deletion src/google/google-contacts/google-contacts.pri
@@ -1,5 +1,5 @@
CONFIG += link_pkgconfig
PKGCONFIG += Qt5Contacts qtcontacts-sqlite-qt5-extensions
PKGCONFIG += Qt5Contacts qtcontacts-sqlite-qt5-extensions contactcache-qt5
QT += gui

SOURCES += \
Expand Down
2 changes: 2 additions & 0 deletions src/google/google-contacts/googlecontactatom.h
Expand Up @@ -90,12 +90,14 @@ class GoogleContactAtom {
class BatchOperationResponse {
public:
BatchOperationResponse();
QStringList unsupportedElements;
QString operationId;
QString type;
QString code;
QString reason;
QString reasonDescription;
QString contactGuid;
QString etag;
bool isError;
};
void addBatchOperationResponse(const QString &operationId, BatchOperationResponse response);
Expand Down
47 changes: 33 additions & 14 deletions src/google/google-contacts/googlecontactstream.cpp
Expand Up @@ -28,10 +28,14 @@
#include "constants_p.h"
#include "trace.h"

#include <seasidecache.h>

#include <QDateTime>
#include <QContactExtendedDetail>

static void dumpXml(const QByteArray &xml)
namespace {

void dumpXml(const QByteArray &xml)
{
// this algorithm doesn't handle a lot of stuff (escaped slashes/angle-brackets, slashes/angle-brackets in text, etc) but it works:
// see < then read until > and that becomes "tag". Print indent, print tag, print newline. If tag didn't contain /> then indent += " " else deindent.
Expand Down Expand Up @@ -96,7 +100,7 @@ static void dumpXml(const QByteArray &xml)
}
}

static bool traceOutputEnabled()
bool traceOutputEnabled()
{
const QByteArray loggingLevelByteArray = qgetenv("MSYNCD_LOGGING_LEVEL");
const QString loggingLevelStr = QString::fromLocal8Bit(loggingLevelByteArray.constData());
Expand All @@ -108,6 +112,30 @@ static bool traceOutputEnabled()
return ok && level >= 8 && dump == 1;
}

bool saveExtendedDetail(QContact *contact, const QString &detailName, const QVariant &detailData)
{
QContactExtendedDetail matchedDetail;
for (const QContactExtendedDetail &detail : contact->details<QContactExtendedDetail>()) {
if (detail.name() == detailName) {
matchedDetail = detail;
break;
}
}

if (matchedDetail.name().isEmpty()) {
matchedDetail.setName(detailName);
}
matchedDetail.setData(detailData);
return contact->saveDetail(&matchedDetail, QContact::IgnoreAccessConstraints);
}

bool saveContactEtag(QContact *contact, const QString &etag)
{
return saveExtendedDetail(contact, QStringLiteral("etag"), etag);
}

}

GoogleContactStream::GoogleContactStream(bool response, int accountId, const QString &accountEmail, QObject* parent)
: QObject(parent)
, mXmlReader(0)
Expand Down Expand Up @@ -388,18 +416,7 @@ void GoogleContactStream::handleAtomEntry()
// this entry was a contact.
// the etag is the "version identifier".
if (!contactEtag.isEmpty()) {
QContactExtendedDetail etagDetail;
for (const QContactExtendedDetail &detail : entryContact.details<QContactExtendedDetail>()) {
if (etagDetail.name() == QLatin1String("etag")) {
etagDetail = detail;
break;
}
}
if (etagDetail.name().isEmpty()) {
etagDetail.setName(QStringLiteral("etag"));
}
etagDetail.setData(contactEtag);
entryContact.saveDetail(&etagDetail, QContact::IgnoreAccessConstraints);
saveContactEtag(&entryContact, contactEtag);
}

if (isInGroup) {
Expand All @@ -417,6 +434,8 @@ void GoogleContactStream::handleAtomEntry()
if (isBatchOperationResponse) {
if (!entryContact.detail<QContactGuid>().guid().isEmpty()) {
response.contactGuid = entryContact.detail<QContactGuid>().guid();
response.etag = contactEtag;
response.unsupportedElements = unsupportedElements;
}
mAtom->addBatchOperationResponse(response.operationId, response);
}
Expand Down
1 change: 1 addition & 0 deletions src/google/google-contacts/googlecontactstream.h
Expand Up @@ -68,6 +68,7 @@ class GoogleContactStream : public QObject
Modify,
Remove
};
Q_ENUM(UpdateType)

public:
explicit GoogleContactStream(bool response, int accountId, const QString &accountEmail = QString(), QObject* parent = 0);
Expand Down

0 comments on commit dbc7cbb

Please sign in to comment.