Skip to content

Commit

Permalink
[buteo-sync-plugin-carddav] Allow sync of non .vcf resources. Contrib…
Browse files Browse the repository at this point in the history
…utes to MER#1863

Previously, we only synced resources returned by the server in
response to an etags request, if those resources ended in ".vcf".

This commit modifies the behaviour so that we assume that any resource
which has a suffix which is not ".vcf" (e.g., ".ics" or ".eml") should
be ignored, but other resources without a suffix should be synced.

This allows us to sync in cases where the remote resource is found at
a path like "/carddav/Addressbooks/personal/johnsmith" rather than
a path like "/carddav/Addressbooks/personal/johnsmith.vcf".

Contributes to MER#1863
  • Loading branch information
Chris Adams committed Apr 2, 2019
1 parent e30631b commit ff465bd
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 2 deletions.
1 change: 1 addition & 0 deletions rpm/buteo-sync-plugin-carddav.spec
Expand Up @@ -65,6 +65,7 @@ This package contains unit tests for the CardDAV Buteo sync plugin.
/opt/tests/buteo/plugins/carddav/data/replyparser_synctokendelta_single-well-formed-addition.xml
/opt/tests/buteo/plugins/carddav/data/replyparser_contactmetadata_empty.xml
/opt/tests/buteo/plugins/carddav/data/replyparser_contactmetadata_single-well-formed-add-mod-rem-unch.xml
/opt/tests/buteo/plugins/carddav/data/replyparser_contactmetadata_single-vcf-and-non-vcf.xml
/opt/tests/buteo/plugins/carddav/data/replyparser_contactdata_empty.xml
/opt/tests/buteo/plugins/carddav/data/replyparser_contactdata_single-well-formed.xml
/opt/tests/buteo/plugins/carddav/data/replyparser_contactdata_single-hs-utc-iso8601-bday.xml
Expand Down
22 changes: 20 additions & 2 deletions src/replyparser.cpp
Expand Up @@ -506,9 +506,17 @@ QList<ReplyParser::ContactInformation> ReplyParser::parseSyncTokenDelta(const QB
status = rmap.value("status").toMap().value("@text").toString();
}
if (status.contains(QLatin1String("200 OK"))) {
if (!currInfo.uri.endsWith(QStringLiteral(".vcf"), Qt::CaseInsensitive)) {
if (currInfo.uri.endsWith(QChar('/'))) {
// this is probably a response for the addressbook resource,
// rather than for a contact resource within the addressbook.
LOG_DEBUG(Q_FUNC_INFO << "ignoring non-contact (addressbook?) resource:" << currInfo.uri << currInfo.etag << status);
continue;
} else if (currInfo.uri.length() > 5
&& (currInfo.uri.at(currInfo.uri.length()-4) == QChar('.')
|| currInfo.uri.at(currInfo.uri.length()-3) == QChar('.'))
&& !currInfo.uri.endsWith(QStringLiteral(".vcf"), Qt::CaseInsensitive)) {
// the uri has a file suffix like .ics or .eml rather than .vcf.
// this is probably not a contact resource, but instead some other file reported erroneously.
LOG_DEBUG(Q_FUNC_INFO << "ignoring non-contact resource:" << currInfo.uri << currInfo.etag << status);
continue;
}
Expand Down Expand Up @@ -582,12 +590,22 @@ QList<ReplyParser::ContactInformation> ReplyParser::parseContactMetadata(const Q
if (status.isEmpty()) {
status = rmap.value("status").toMap().value("@text").toString();
}
if (!currInfo.uri.endsWith(QStringLiteral(".vcf"), Qt::CaseInsensitive)) {

if (currInfo.uri.endsWith(QChar('/'))) {
// this is probably a response for the addressbook resource,
// rather than for a contact resource within the addressbook.
LOG_DEBUG(Q_FUNC_INFO << "ignoring non-contact (addressbook?) resource:" << currInfo.uri << currInfo.etag << status);
continue;
} else if (currInfo.uri.length() > 5
&& (currInfo.uri.at(currInfo.uri.length()-4) == QChar('.')
|| currInfo.uri.at(currInfo.uri.length()-3) == QChar('.'))
&& !currInfo.uri.endsWith(QStringLiteral(".vcf"), Qt::CaseInsensitive)) {
// the uri has a file suffix like .ics or .eml rather than .vcf.
// this is probably not a contact resource, but instead some other file reported erroneously.
LOG_DEBUG(Q_FUNC_INFO << "ignoring non-contact resource:" << currInfo.uri << currInfo.etag << status);
continue;
}

QMap<QString, QString>::const_iterator it = q->m_contactUris.constBegin();
for ( ; it != q->m_contactUris.constEnd(); ++it) {
if (it.value() == currInfo.uri) {
Expand Down
3 changes: 3 additions & 0 deletions src/requestgenerator.cpp
Expand Up @@ -359,6 +359,9 @@ QNetworkReply *RequestGenerator::contactMultiget(const QString &serverUrl, const
}
if (uri.endsWith(QStringLiteral(".vcf")) && uri.startsWith(addressbookPath)) {
uriHrefs.append(QStringLiteral("<d:href>%1</d:href>").arg(href));
} else if (uri.startsWith(addressbookPath)) {
// contact resource which doesn't end in .vcf but is otherwise well-formed / fully specified.
uriHrefs.append(QStringLiteral("<d:href>%1</d:href>").arg(href));
} else {
uriHrefs.append(QStringLiteral("<d:href>%1/%2.vcf</d:href>").arg(addressbookPath).arg(href));
}
Expand Down
@@ -0,0 +1,20 @@
<d:multistatus xmlns:d="DAV:" xmlns:card="urn:ietf:params:xml:ns:carddav">
<d:response>
<d:href>/addressbooks/johndoe/contacts/new.vcf</d:href>
<d:propstat>
<d:prop>
<d:getetag>"0021-0021"</d:getetag> <!-- new uri/etag :. added -->
</d:prop>
<d:status>HTTP/1.1 200 OK</d:status>
</d:propstat>
</d:response>
<d:response>
<d:href>/addressbooks/johndoe/contacts/alsonew</d:href>
<d:propstat>
<d:prop>
<d:getetag>"0022-0022"</d:getetag> <!-- new uri/etag :. added -->
</d:prop>
<d:status>HTTP/1.1 200 OK</d:status>
</d:propstat>
</d:response>
</d:multistatus>
21 changes: 21 additions & 0 deletions tests/replyparser/tst_replyparser.cpp
Expand Up @@ -425,6 +425,27 @@ void tst_replyparser::parseContactMetadata_data()
<< mContactUris
<< mContactEtags
<< infos;

infos.clear();
mContactUris.clear();
mContactEtags.clear();
ReplyParser::ContactInformation c5;
c5.modType = ReplyParser::ContactInformation::Addition;
c5.uri = QStringLiteral("/addressbooks/johndoe/contacts/new.vcf");
c5.guid = QString();
c5.etag = QStringLiteral("\"0021-0021\"");
ReplyParser::ContactInformation c6;
c6.modType = ReplyParser::ContactInformation::Addition;
c6.uri = QStringLiteral("/addressbooks/johndoe/contacts/alsonew");
c6.guid = QString();
c6.etag = QStringLiteral("\"0022-0022\"");
infos << c5 << c6;
QTest::newRow("two contact additions with vcf and non-vcf extenions in well-formed sync token delta response")
<< QStringLiteral("data/replyparser_contactmetadata_single-vcf-and-non-vcf.xml")
<< QStringLiteral("/addressbooks/johndoe/contacts/")
<< mContactUris
<< mContactEtags
<< infos;
}

void tst_replyparser::parseContactMetadata()
Expand Down

0 comments on commit ff465bd

Please sign in to comment.