Akonadi

itemcreatejob.cpp
1 /*
2  SPDX-FileCopyrightText: 2006-2007 Volker Krause <[email protected]>
3  SPDX-FileCopyrightText: 2007 Robert Zwerus <[email protected]>
4  SPDX-FileCopyrightText: 2014 Daniel Vrátil <[email protected]>
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 
24 using namespace Akonadi;
25 
26 class Akonadi::ItemCreateJobPrivate : public JobPrivate
27 {
28 public:
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  QByteArray mPendingData;
43  bool mItemReceived = false;
44 };
45 
46 QString Akonadi::ItemCreateJobPrivate::jobDebuggingString() const
47 {
48  const QString collectionName = mCollection.name();
49  QString str = QStringLiteral("%1 Item %2 from col %3")
50  .arg(mMergeOptions == ItemCreateJob::NoMerge ? QStringLiteral("Create") : QStringLiteral("Merge"))
51  .arg(mItem.id())
52  .arg(mCollection.id());
53  if (!collectionName.isEmpty()) {
54  str += QStringLiteral(" (%1)").arg(collectionName);
55  }
56  return str;
57 }
58 
59 Protocol::PartMetaData ItemCreateJobPrivate::preparePart(const QByteArray &partName)
60 {
61  ProtocolHelper::PartNamespace ns; // dummy
62  const QByteArray partLabel = ProtocolHelper::decodePartIdentifier(partName, ns);
63  if (!mParts.remove(partLabel)) {
64  // ERROR?
65  return Protocol::PartMetaData();
66  }
67 
68  int version = 0;
69  if (mForeignParts.contains(partLabel)) {
70  mPendingData = mItem.d_ptr->mPayloadPath.toUtf8();
71  const auto size = QFile(mItem.d_ptr->mPayloadPath).size();
72  return Protocol::PartMetaData(partName, size, version, Protocol::PartMetaData::Foreign);
73  } else {
74  mPendingData.clear();
75  ItemSerializer::serialize(mItem, partLabel, mPendingData, version);
76  return Protocol::PartMetaData(partName, mPendingData.size(), version);
77  }
78 }
79 
80 ItemCreateJob::ItemCreateJob(const Item &item, const Collection &collection, QObject *parent)
81  : Job(new ItemCreateJobPrivate(this), parent)
82 {
84 
85  Q_ASSERT(!item.mimeType().isEmpty());
86  d->mItem = item;
87  d->mParts = d->mItem.loadedPayloadParts();
88  d->mCollection = collection;
89 
90  if (!d->mItem.payloadPath().isEmpty()) {
91  d->mForeignParts = ItemSerializer::allowedForeignParts(d->mItem);
92  }
93 }
94 
96 {
97 }
98 
100 {
102 
103  if (!d->mCollection.isValid()) {
104  setError(Unknown);
105  setErrorText(i18n("Invalid parent collection"));
106  emitResult();
107  return;
108  }
109 
110  auto cmd = Protocol::CreateItemCommandPtr::create();
111  cmd->setMimeType(d->mItem.mimeType());
112  cmd->setGid(d->mItem.gid());
113  cmd->setRemoteId(d->mItem.remoteId());
114  cmd->setRemoteRevision(d->mItem.remoteRevision());
115 
116  Protocol::CreateItemCommand::MergeModes mergeModes = Protocol::CreateItemCommand::None;
117  if ((d->mMergeOptions & GID) && !d->mItem.gid().isEmpty()) {
118  mergeModes |= Protocol::CreateItemCommand::GID;
119  }
120  if ((d->mMergeOptions & RID) && !d->mItem.remoteId().isEmpty()) {
121  mergeModes |= Protocol::CreateItemCommand::RemoteID;
122  }
123  if ((d->mMergeOptions & Silent)) {
124  mergeModes |= Protocol::CreateItemCommand::Silent;
125  }
126  const bool merge = (mergeModes & Protocol::CreateItemCommand::GID) || (mergeModes & Protocol::CreateItemCommand::RemoteID);
127  cmd->setMergeModes(mergeModes);
128 
129  if (d->mItem.d_ptr->mFlagsOverwritten || !merge) {
130  cmd->setFlags(d->mItem.flags());
131  cmd->setFlagsOverwritten(d->mItem.d_ptr->mFlagsOverwritten);
132  } else {
133  const auto addedFlags = ItemChangeLog::instance()->addedFlags(d->mItem.d_ptr);
134  const auto deletedFlags = ItemChangeLog::instance()->deletedFlags(d->mItem.d_ptr);
135  cmd->setAddedFlags(addedFlags);
136  cmd->setRemovedFlags(deletedFlags);
137  }
138 
139  if (d->mItem.d_ptr->mTagsOverwritten || !merge) {
140  const auto tags = d->mItem.tags();
141  if (!tags.isEmpty()) {
142  cmd->setTags(ProtocolHelper::entitySetToScope(tags));
143  }
144  } else {
145  const auto addedTags = ItemChangeLog::instance()->addedTags(d->mItem.d_ptr);
146  if (!addedTags.isEmpty()) {
147  cmd->setAddedTags(ProtocolHelper::entitySetToScope(addedTags));
148  }
149  const auto deletedTags = ItemChangeLog::instance()->deletedTags(d->mItem.d_ptr);
150  if (!deletedTags.isEmpty()) {
151  cmd->setRemovedTags(ProtocolHelper::entitySetToScope(deletedTags));
152  }
153  }
154 
155  cmd->setCollection(ProtocolHelper::entityToScope(d->mCollection));
156  cmd->setItemSize(d->mItem.size());
157 
158  cmd->setAttributes(ProtocolHelper::attributesToProtocol(d->mItem));
159  QSet<QByteArray> parts;
160  parts.reserve(d->mParts.size());
161  for (const QByteArray &part : std::as_const(d->mParts)) {
162  parts.insert(ProtocolHelper::encodePartIdentifier(ProtocolHelper::PartPayload, part));
163  }
164  cmd->setParts(parts);
165 
166  d->sendCommand(cmd);
167 }
168 
169 bool ItemCreateJob::doHandleResponse(qint64 tag, const Protocol::CommandPtr &response)
170 {
172 
173  if (!response->isResponse() && response->type() == Protocol::Command::StreamPayload) {
174  const auto &streamCmd = Protocol::cmdCast<Protocol::StreamPayloadCommand>(response);
175  auto streamResp = Protocol::StreamPayloadResponsePtr::create();
176  streamResp->setPayloadName(streamCmd.payloadName());
177  if (streamCmd.request() == Protocol::StreamPayloadCommand::MetaData) {
178  streamResp->setMetaData(d->preparePart(streamCmd.payloadName()));
179  } else {
180  if (streamCmd.destination().isEmpty()) {
181  streamResp->setData(d->mPendingData);
182  } else {
184  if (!ProtocolHelper::streamPayloadToFile(streamCmd.destination(), d->mPendingData, error)) {
185  // Error?
186  }
187  }
188  }
189  d->sendCommand(tag, streamResp);
190  return false;
191  }
192 
193  if (response->isResponse() && response->type() == Protocol::Command::FetchItems) {
194  const auto &fetchResp = Protocol::cmdCast<Protocol::FetchItemsResponse>(response);
195  Item item = ProtocolHelper::parseItemFetchResult(fetchResp);
196  if (!item.isValid()) {
197  // Error, maybe?
198  return false;
199  }
200  d->mItem = item;
201  return false;
202  }
203 
204  if (response->isResponse() && response->type() == Protocol::Command::CreateItem) {
205  return true;
206  }
207 
208  return Job::doHandleResponse(tag, response);
209 }
210 
212 {
214 
215  d->mMergeOptions = options;
216 }
217 
219 {
220  Q_D(const ItemCreateJob);
221 
222  // Parent collection is available only with non-silent merge/create
223  if (d->mItem.parentCollection().isValid()) {
224  return d->mItem;
225  }
226 
227  Item item(d->mItem);
228  item.setRevision(0);
229  item.setParentCollection(d->mCollection);
230  item.setStorageCollectionId(d->mCollection.id());
231 
232  return item;
233 }
bool isValid() const
Returns whether the item is valid.
Definition: item.cpp:88
void setRevision(int revision)
Sets the revision number of the item.
Definition: item.cpp:316
@ Unknown
Unknown error.
Definition: job.h:102
void setErrorText(const QString &errorText)
Job that creates a new item in the Akonadi storage.
Definition: itemcreatejob.h:60
void setMerge(MergeOptions options)
Merge this item into an existing one if available.
@ RID
Merge by remote id.
Definition: itemcreatejob.h:87
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.
void reserve(int size)
void setParentCollection(const Collection &parent)
Set the parent collection of this object.
Definition: item.cpp:170
Represents a collection of PIM items.
Definition: collection.h:61
void doStart() override
This method must be reimplemented in the concrete jobs.
@ GID
Merge by GID.
Definition: itemcreatejob.h:88
QString mimeType() const
Returns the mime type of the item.
Definition: item.cpp:331
QString i18n(const char *text, const TYPE &arg...)
@ NoMerge
Don't merge.
Definition: itemcreatejob.h:86
bool isEmpty() const const
Base class for all actions in the Akonadi storage.
Definition: job.h:80
Item item() const
Returns the created item with the new unique id, or an invalid item if the job failed.
virtual qint64 size() const const override
ItemCreateJob(const Item &item, const Collection &collection, QObject *parent=nullptr)
Creates a new item create job.
@ Silent
Only return the id of the merged/created item.
Definition: itemcreatejob.h:89
KDB_EXPORT KDbVersionInfo version()
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
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
QSet::iterator insert(const T &value)
~ItemCreateJob() override
Destroys the item create job.
void emitResult()
int error() const
QSet< QByteArray > loadedPayloadParts() const
Returns the list of loaded payload parts.
Definition: item.cpp:288
void setError(int errorCode)
Represents a PIM item stored in Akonadi storage.
Definition: item.h:105
Q_D(Todo)
Helper integration between Akonadi and Qt.
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Wed Jun 7 2023 03:53:31 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.