Commit e49f49a1 authored by Daniel Vrátil's avatar Daniel Vrátil 🤖
Browse files

Fix clearing Item flags

For instance when an email is marked as unread on an IMAP server, it
means that the \\SEEN flag is removed. If this was the only flag
set on the email, then Akonadi::ItemSync will end up calling
Akonadi::Item::setFlags() with an empty QSet. When the AKAPPEND handler
is in the MERGE mode and runs into an empty Flags field in the
CreateItemCommand it fallsback to checking AddedFlags and RemovedFlags
fields, but those are empty too.

Akonadi::Item internally tracks when setFlags() is called, even with
an empty QSet through flagsOverwritten flag. With this change the
flag is sent as part of the command to the server and the AKAPPEND
handler now falls back to AddedFlags/RemovedFlags fields only if
the flag is false.

This fixes syncing email flags when email state changes from read to
unread on IMAP, but due to how IMAP emails are synced this will only
affect future changes and will not sync existing out-of-sync emails.

BUG: 375146
FIXED-IN: 5.5.1
parent 2e91f5f0
......@@ -39,7 +39,7 @@ void ProtocolTest::testProtocolVersion()
// If it wasn't you who broke it, please go find that person who was too
// lazy to extend the test case and beat them with a stick. -- Dan
QCOMPARE(Akonadi::Protocol::version(), 56);
QCOMPARE(Akonadi::Protocol::version(), 57);
}
void ProtocolTest::testFactory_data()
......@@ -612,6 +612,7 @@ void ProtocolTest::testCreateItemCommand()
in.setRemoteRevision(QStringLiteral("RREV"));
in.setDateTime(QDateTime(QDate(2015, 8, 11), QTime(14, 32, 21), Qt::UTC));
in.setFlags({ "\\SEEN", "FLAG" });
in.setFlagsOverwritten(true);
in.setAddedFlags({ "FLAG2" });
in.setRemovedFlags({ "FLAG3" });
in.setTags(Scope(2));
......@@ -632,6 +633,7 @@ void ProtocolTest::testCreateItemCommand()
QCOMPARE(out.remoteRevision(), QStringLiteral("RREV"));
QCOMPARE(out.dateTime(), QDateTime(QDate(2015, 8, 11), QTime(14, 32, 21), Qt::UTC));
QCOMPARE(out.flags(), QSet<QByteArray>() << "\\SEEN" << "FLAG");
QCOMPARE(out.flagsOverwritten(), true);
QCOMPARE(out.addedFlags(), QSet<QByteArray>{ "FLAG2" });
QCOMPARE(out.removedFlags(), QSet<QByteArray>{ "FLAG3" });
QCOMPARE(out.tags(), Scope(2));
......
......@@ -63,7 +63,9 @@ public:
QString Akonadi::ItemCreateJobPrivate::jobDebuggingString() const
{
const QString collectionName = mCollection.name();
QString str = QStringLiteral("Create Item %1 from col %2").arg(mItem.id()).arg(mCollection.id());
QString str = QStringLiteral("%1 Item %2 from col %3")
.arg(mMergeOptions == ItemCreateJob::NoMerge ? QStringLiteral("Create") : QStringLiteral("Merge"))
.arg(mItem.id()).arg(mCollection.id());
if (!collectionName.isEmpty()) {
str += QStringLiteral(" (%1)").arg(collectionName);
}
......@@ -134,6 +136,7 @@ void ItemCreateJob::doStart()
if (d->mItem.d_ptr->mFlagsOverwritten || !merge) {
cmd.setFlags(d->mItem.flags());
cmd.setFlagsOverwritten(d->mItem.d_ptr->mFlagsOverwritten);
} else {
auto addedFlags = ItemChangeLog::instance()->addedFlags(d->mItem.d_ptr);
auto deletedFlags = ItemChangeLog::instance()->deletedFlags(d->mItem.d_ptr);
......
......@@ -51,7 +51,7 @@ namespace Protocol
int version()
{
return 56;
return 57;
}
}
......@@ -1835,6 +1835,7 @@ public:
: CommandPrivate(Command::CreateItem)
, mergeMode(CreateItemCommand::None)
, itemSize(0)
, flagsOverwritten(false)
{}
CreateItemCommandPrivate(const CreateItemCommandPrivate &other)
......@@ -1855,6 +1856,7 @@ public:
, attributes(other.attributes)
, mergeMode(other.mergeMode)
, itemSize(other.itemSize)
, flagsOverwritten(other.flagsOverwritten)
{}
bool compare(const CommandPrivate *other) const Q_DECL_OVERRIDE
......@@ -1875,7 +1877,8 @@ public:
&& COMPARE(addedFlags)
&& COMPARE(removedFlags)
&& COMPARE(attributes)
&& COMPARE(parts);
&& COMPARE(parts)
&& COMPARE(flagsOverwritten);
}
DataStream &serialize(DataStream &stream) const Q_DECL_OVERRIDE
......@@ -1896,7 +1899,8 @@ public:
<< addedTags
<< removedTags
<< attributes
<< parts;
<< parts
<< flagsOverwritten;
}
DataStream &deserialize(DataStream &stream) Q_DECL_OVERRIDE {
......@@ -1916,7 +1920,8 @@ public:
>> addedTags
>> removedTags
>> attributes
>> parts;
>> parts
>> flagsOverwritten;
}
void debugString(DebugBlock &blck) const Q_DECL_OVERRIDE
......@@ -1950,6 +1955,7 @@ public:
blck.write("Added Tags", addedTags);
blck.write("Removed Tags", removedTags);
blck.write("Flags", flags);
blck.write("Flags overwritten", flagsOverwritten);
blck.write("Added Flags", addedFlags);
blck.write("Removed Flags", removedFlags);
blck.beginBlock("Attributes");
......@@ -1981,6 +1987,7 @@ public:
Attributes attributes;
CreateItemCommand::MergeModes mergeMode;
qint64 itemSize;
bool flagsOverwritten;
};
AKONADI_DECLARE_PRIVATE(CreateItemCommand)
......@@ -2069,6 +2076,16 @@ QDateTime CreateItemCommand::dateTime() const
return d_func()->dateTime;
}
void CreateItemCommand::setFlagsOverwritten(bool overwritten)
{
d_func()->flagsOverwritten = overwritten;
}
bool CreateItemCommand::flagsOverwritten() const
{
return d_func()->flagsOverwritten;
}
void CreateItemCommand::setFlags(const QSet<QByteArray> &flags)
{
d_func()->flags = flags;
......
......@@ -570,6 +570,8 @@ public:
void setDateTime(const QDateTime &dateTime);
QDateTime dateTime() const;
void setFlagsOverwritten(bool overwritten);
bool flagsOverwritten() const;
void setFlags(const QSet<QByteArray> &flags);
QSet<QByteArray> flags() const;
void setAddedFlags(const QSet<QByteArray> &flags);
......
......@@ -186,7 +186,7 @@ bool AkAppend::mergeItem(const Protocol::CreateItemCommand &cmd,
}
const Collection col = Collection::retrieveById(parentCol.id());
if (cmd.flags().isEmpty()) {
if (cmd.flags().isEmpty() && !cmd.flagsOverwritten()) {
bool flagsAdded = false, flagsRemoved = false;
if (!cmd.addedFlags().isEmpty()) {
const Flag::List addedFlags = HandlerHelper::resolveFlags(cmd.addedFlags());
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment