Akonadi

itemcreatejob.cpp
1/*
2 SPDX-FileCopyrightText: 2006-2007 Volker Krause <vkrause@kde.org>
3 SPDX-FileCopyrightText: 2007 Robert Zwerus <arzie@dds.nl>
4 SPDX-FileCopyrightText: 2014 Daniel Vrátil <dvratil@redhat.com>
5
6 SPDX-License-Identifier: LGPL-2.0-or-later
7*/
8
9#include "itemcreatejob.h"
10
11#include "collection.h"
12#include "gidextractor_p.h"
13#include "item.h"
14#include "item_p.h"
15#include "itemserializer_p.h"
16#include "job_p.h"
17#include "private/protocol_p.h"
18#include "protocolhelper_p.h"
19
20#include <QFile>
21
22#include <KLocalizedString>
23
24using namespace Akonadi;
25
26class Akonadi::ItemCreateJobPrivate : public JobPrivate
27{
28public:
29 explicit ItemCreateJobPrivate(ItemCreateJob *parent)
30 : JobPrivate(parent)
31 {
32 }
33
34 Protocol::PartMetaData preparePart(const QByteArray &part);
35
36 QString jobDebuggingString() const override;
37 Collection mCollection;
38 Item mItem;
39 QSet<QByteArray> mParts;
40 QSet<QByteArray> mForeignParts;
41 struct PendingPart {
42 void clear()
43 {
44 name.clear();
45 data.clear();
46 }
47
48 QByteArray name;
49 QByteArray data;
50 } mPendingPart;
52 bool mItemReceived = false;
53};
54
55QString Akonadi::ItemCreateJobPrivate::jobDebuggingString() const
56{
57 const QString collectionName = mCollection.name();
58 QString str = QStringLiteral("%1 Item %2 from col %3")
59 .arg(mMergeOptions == ItemCreateJob::NoMerge ? QStringLiteral("Create") : QStringLiteral("Merge"))
60 .arg(mItem.id())
61 .arg(mCollection.id());
62 if (!collectionName.isEmpty()) {
63 str += QStringLiteral(" (%1)").arg(collectionName);
64 }
65 return str;
66}
67
68Protocol::PartMetaData ItemCreateJobPrivate::preparePart(const QByteArray &partName)
69{
70 ProtocolHelper::PartNamespace ns; // dummy
71 const QByteArray partLabel = ProtocolHelper::decodePartIdentifier(partName, ns);
72 if (!mParts.remove(partLabel)) {
73 // ERROR?
74 return Protocol::PartMetaData();
75 }
76
77 int version = 0;
78 if (mForeignParts.contains(partLabel)) {
79 mPendingPart = PendingPart{.name = partName, .data = mItem.d_ptr->mPayloadPath.toUtf8()};
80 const auto size = QFile(mItem.d_ptr->mPayloadPath).size();
81 return Protocol::PartMetaData(partName, size, version, Protocol::PartMetaData::Foreign);
82 } else {
83 mPendingPart.clear();
84 mPendingPart.name = partName;
85 ItemSerializer::serialize(mItem, partLabel, mPendingPart.data, version);
86 return Protocol::PartMetaData(partName, mPendingPart.data.size(), version);
87 }
88}
89
90ItemCreateJob::ItemCreateJob(const Item &item, const Collection &collection, QObject *parent)
91 : Job(new ItemCreateJobPrivate(this), parent)
92{
94
96 d->mItem = item;
97 d->mParts = d->mItem.loadedPayloadParts();
98 d->mCollection = collection;
99
100 if (!d->mItem.payloadPath().isEmpty()) {
101 d->mForeignParts = ItemSerializer::allowedForeignParts(d->mItem);
102 }
103}
104
108
110{
112
113 if (!d->mCollection.isValid()) {
115 setErrorText(i18n("Invalid parent collection"));
116 emitResult();
117 return;
118 }
119
120 auto cmd = Protocol::CreateItemCommandPtr::create();
121 cmd->setMimeType(d->mItem.mimeType());
122 cmd->setGid(d->mItem.gid());
123 cmd->setRemoteId(d->mItem.remoteId());
124 cmd->setRemoteRevision(d->mItem.remoteRevision());
125 cmd->setModificationTime(d->mItem.modificationTime());
126
127 Protocol::CreateItemCommand::MergeModes mergeModes = Protocol::CreateItemCommand::None;
128 if ((d->mMergeOptions & GID) && !d->mItem.gid().isEmpty()) {
129 mergeModes |= Protocol::CreateItemCommand::GID;
130 }
131 if ((d->mMergeOptions & RID) && !d->mItem.remoteId().isEmpty()) {
132 mergeModes |= Protocol::CreateItemCommand::RemoteID;
133 }
134 if ((d->mMergeOptions & Silent)) {
135 mergeModes |= Protocol::CreateItemCommand::Silent;
136 }
137 const bool merge = (mergeModes & Protocol::CreateItemCommand::GID) || (mergeModes & Protocol::CreateItemCommand::RemoteID);
138 cmd->setMergeModes(mergeModes);
139
140 if (d->mItem.d_ptr->mFlagsOverwritten || !merge) {
141 cmd->setFlags(d->mItem.flags());
142 cmd->setFlagsOverwritten(d->mItem.d_ptr->mFlagsOverwritten);
143 } else {
144 const auto addedFlags = ItemChangeLog::instance()->addedFlags(d->mItem.d_ptr);
145 const auto deletedFlags = ItemChangeLog::instance()->deletedFlags(d->mItem.d_ptr);
146 cmd->setAddedFlags(addedFlags);
147 cmd->setRemovedFlags(deletedFlags);
148 }
149
150 if (d->mItem.d_ptr->mTagsOverwritten || !merge) {
151 const auto tags = d->mItem.tags();
152 if (!tags.isEmpty()) {
153 cmd->setTags(ProtocolHelper::entitySetToScope(tags));
154 }
155 } else {
156 const auto addedTags = ItemChangeLog::instance()->addedTags(d->mItem.d_ptr);
157 if (!addedTags.isEmpty()) {
158 cmd->setAddedTags(ProtocolHelper::entitySetToScope(addedTags));
159 }
160 const auto deletedTags = ItemChangeLog::instance()->deletedTags(d->mItem.d_ptr);
161 if (!deletedTags.isEmpty()) {
162 cmd->setRemovedTags(ProtocolHelper::entitySetToScope(deletedTags));
163 }
164 }
165
166 cmd->setCollection(ProtocolHelper::entityToScope(d->mCollection));
167 cmd->setItemSize(d->mItem.size());
168
169 cmd->setAttributes(ProtocolHelper::attributesToProtocol(d->mItem));
170 QSet<QByteArray> parts;
171 parts.reserve(d->mParts.size());
172 for (const QByteArray &part : std::as_const(d->mParts)) {
173 parts.insert(ProtocolHelper::encodePartIdentifier(ProtocolHelper::PartPayload, part));
174 }
175 cmd->setParts(parts);
176
177 d->sendCommand(cmd);
178}
179
181{
183
184 if (!response->isResponse() && response->type() == Protocol::Command::StreamPayload) {
185 const auto &streamCmd = Protocol::cmdCast<Protocol::StreamPayloadCommand>(response);
186 auto streamResp = Protocol::StreamPayloadResponsePtr::create();
187 streamResp->setPayloadName(streamCmd.payloadName());
188 if (streamCmd.request() == Protocol::StreamPayloadCommand::MetaData) {
189 streamResp->setMetaData(d->preparePart(streamCmd.payloadName()));
190 } else if (streamCmd.request() == Protocol::StreamPayloadCommand::Data) {
191 if (streamCmd.payloadName() != d->mPendingPart.name) {
192 streamResp->setError(1, QStringLiteral("Unexpected payload name"));
193 } else if (streamCmd.destination().isEmpty()) {
194 streamResp->setData(d->mPendingPart.data);
195 } else {
197 if (!ProtocolHelper::streamPayloadToFile(streamCmd.destination(), d->mPendingPart.data, error)) {
198 streamResp->setError(1, QStringLiteral("Failed to stream payload to file: %1").arg(QString::fromUtf8(error)));
199 }
200 }
201 } else {
202 streamResp->setError(1, QStringLiteral("Unknown stream payload request"));
203 }
204 d->sendCommand(tag, streamResp);
205 return false;
206 }
207
208 if (response->isResponse() && response->type() == Protocol::Command::FetchItems) {
209 const auto &fetchResp = Protocol::cmdCast<Protocol::FetchItemsResponse>(response);
210 Item item = ProtocolHelper::parseItemFetchResult(fetchResp);
211 if (!item.isValid()) {
212 // Error, maybe?
213 return false;
214 }
215 d->mItem = item;
216 return false;
217 }
218
219 if (response->isResponse() && response->type() == Protocol::Command::CreateItem) {
220 return true;
221 }
222
223 return Job::doHandleResponse(tag, response);
224}
225
227{
229
230 d->mMergeOptions = options;
231}
232
234{
235 Q_D(const ItemCreateJob);
236
237 // Parent collection is available only with non-silent merge/create
238 if (d->mItem.parentCollection().isValid()) {
239 return d->mItem;
240 }
241
242 Item item(d->mItem);
243 item.setRevision(0);
244 item.setParentCollection(d->mCollection);
245 item.setStorageCollectionId(d->mCollection.id());
246
247 return item;
248}
249
250#include "moc_itemcreatejob.cpp"
Represents a collection of PIM items.
Definition collection.h:62
Job that creates a new item in the Akonadi storage.
bool doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) override
This method should be reimplemented in the concrete jobs in case you want to handle incoming data.
ItemCreateJob(const Item &item, const Collection &collection, QObject *parent=nullptr)
Creates a new item create job.
void doStart() override
This method must be reimplemented in the concrete jobs.
Item item() const
Returns the created item with the new unique id, or an invalid item if the job failed.
@ Silent
Only return the id of the merged/created item.
@ RID
Merge by remote id.
void setMerge(MergeOptions options)
Merge this item into an existing one if available.
~ItemCreateJob() override
Destroys the item create job.
Represents a PIM item stored in Akonadi storage.
Definition item.h:101
void setParentCollection(const Collection &parent)
Set the parent collection of this object.
Definition item.cpp:170
QString mimeType() const
Returns the mime type of the item.
Definition item.cpp:331
void setRevision(int revision)
Sets the revision number of the item.
Definition item.cpp:316
bool isValid() const
Returns whether the item is valid.
Definition item.cpp:88
QSet< QByteArray > loadedPayloadParts() const
Returns the list of loaded payload parts.
Definition item.cpp:288
Base class for all actions in the Akonadi storage.
Definition job.h:81
virtual bool doHandleResponse(qint64 tag, const Protocol::CommandPtr &response)
This method should be reimplemented in the concrete jobs in case you want to handle incoming data.
Definition job.cpp:381
@ Unknown
Unknown error.
Definition job.h:102
void setErrorText(const QString &errorText)
void emitResult()
int error() const
void setError(int errorCode)
QString i18n(const char *text, const TYPE &arg...)
Helper integration between Akonadi and Qt.
KDB_EXPORT KDbVersionInfo version()
void clear()
char * data()
qsizetype size() const const
virtual qint64 size() const const override
T qobject_cast(QObject *object)
bool contains(const QSet< T > &other) const const
iterator insert(const T &value)
bool remove(const T &value)
void reserve(qsizetype size)
QString arg(Args &&... args) const const
QString fromUtf8(QByteArrayView str)
bool isEmpty() const const
Q_D(Todo)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:13:38 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.