Akonadi

itemcreatejob.cpp
1 /*
2  Copyright (c) 2006 - 2007 Volker Krause <[email protected]>
3  Copyright (c) 2007 Robert Zwerus <[email protected]>
4  Copyright (c) 2014 Daniel Vrátil <[email protected]>
5 
6  This library is free software; you can redistribute it and/or modify it
7  under the terms of the GNU Library General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or (at your
9  option) any later version.
10 
11  This library is distributed in the hope that it will be useful, but WITHOUT
12  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
14  License for more details.
15 
16  You should have received a copy of the GNU Library General Public License
17  along with this library; see the file COPYING.LIB. If not, write to the
18  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19  02110-1301, USA.
20 */
21 
22 #include "itemcreatejob.h"
23 
24 #include "collection.h"
25 #include "item.h"
26 #include "item_p.h"
27 #include "itemserializer_p.h"
28 #include "job_p.h"
29 #include "protocolhelper_p.h"
30 #include "gidextractor_p.h"
31 #include "private/protocol_p.h"
32 
33 
34 #include <QDateTime>
35 #include <QFile>
36 
37 #include <KLocalizedString>
38 
39 using namespace Akonadi;
40 
41 class Akonadi::ItemCreateJobPrivate : public JobPrivate
42 {
43 public:
44  ItemCreateJobPrivate(ItemCreateJob *parent)
45  : JobPrivate(parent)
46  {
47  }
48 
49  Protocol::PartMetaData preparePart(const QByteArray &part);
50 
51  QString jobDebuggingString() const override;
52  Collection mCollection;
53  Item mItem;
54  QSet<QByteArray> mParts;
55  QSet<QByteArray> mForeignParts;
56  QDateTime mDatetime;
57  QByteArray mPendingData;
59  bool mItemReceived = false;
60 
61 };
62 
63 QString Akonadi::ItemCreateJobPrivate::jobDebuggingString() const
64 {
65  const QString collectionName = mCollection.name();
66  QString str = QStringLiteral("%1 Item %2 from col %3")
67  .arg(mMergeOptions == ItemCreateJob::NoMerge ? QStringLiteral("Create") : QStringLiteral("Merge"))
68  .arg(mItem.id()).arg(mCollection.id());
69  if (!collectionName.isEmpty()) {
70  str += QStringLiteral(" (%1)").arg(collectionName);
71  }
72  return str;
73 }
74 
75 Protocol::PartMetaData ItemCreateJobPrivate::preparePart(const QByteArray &partName)
76 {
77  ProtocolHelper::PartNamespace ns; //dummy
78  const QByteArray partLabel = ProtocolHelper::decodePartIdentifier(partName, ns);
79  if (!mParts.remove(partLabel)) {
80  // ERROR?
81  return Protocol::PartMetaData();
82  }
83 
84  int version = 0;
85  if (mForeignParts.contains(partLabel)) {
86  mPendingData = mItem.d_ptr->mPayloadPath.toUtf8();
87  const auto size = QFile(mItem.d_ptr->mPayloadPath).size();
88  return Protocol::PartMetaData(partName, size, version, Protocol::PartMetaData::Foreign);
89  } else {
90  mPendingData.clear();
91  ItemSerializer::serialize(mItem, partLabel, mPendingData, version);
92  return Protocol::PartMetaData(partName, mPendingData.size(), version);
93  }
94 }
95 
96 ItemCreateJob::ItemCreateJob(const Item &item, const Collection &collection, QObject *parent)
97  : Job(new ItemCreateJobPrivate(this), parent)
98 {
99  Q_D(ItemCreateJob);
100 
101  Q_ASSERT(!item.mimeType().isEmpty());
102  d->mItem = item;
103  d->mParts = d->mItem.loadedPayloadParts();
104  d->mCollection = collection;
105 
106  if (!d->mItem.payloadPath().isEmpty()) {
107  d->mForeignParts = ItemSerializer::allowedForeignParts(d->mItem);
108  }
109 }
110 
112 {
113 }
114 
116 {
117  Q_D(ItemCreateJob);
118 
119  if (!d->mCollection.isValid()) {
120  setError(Unknown);
121  setErrorText(i18n("Invalid parent collection"));
122  emitResult();
123  return;
124  }
125 
126  auto cmd = Protocol::CreateItemCommandPtr::create();
127  cmd->setMimeType(d->mItem.mimeType());
128  cmd->setGid(d->mItem.gid());
129  cmd->setRemoteId(d->mItem.remoteId());
130  cmd->setRemoteRevision(d->mItem.remoteRevision());
131 
132  Protocol::CreateItemCommand::MergeModes mergeModes = Protocol::CreateItemCommand::None;
133  if ((d->mMergeOptions & GID) && !d->mItem.gid().isEmpty()) {
134  mergeModes |= Protocol::CreateItemCommand::GID;
135  }
136  if ((d->mMergeOptions & RID) && !d->mItem.remoteId().isEmpty()) {
137  mergeModes |= Protocol::CreateItemCommand::RemoteID;
138  }
139  if ((d->mMergeOptions & Silent)) {
140  mergeModes |= Protocol::CreateItemCommand::Silent;
141  }
142  const bool merge = (mergeModes & Protocol::CreateItemCommand::GID)
143  || (mergeModes & Protocol::CreateItemCommand::RemoteID);
144  cmd->setMergeModes(mergeModes);
145 
146  if (d->mItem.d_ptr->mFlagsOverwritten || !merge) {
147  cmd->setFlags(d->mItem.flags());
148  cmd->setFlagsOverwritten(d->mItem.d_ptr->mFlagsOverwritten);
149  } else {
150  auto addedFlags = ItemChangeLog::instance()->addedFlags(d->mItem.d_ptr);
151  auto deletedFlags = ItemChangeLog::instance()->deletedFlags(d->mItem.d_ptr);
152  cmd->setAddedFlags(addedFlags);
153  cmd->setRemovedFlags(deletedFlags);
154  }
155  auto addedTags = ItemChangeLog::instance()->addedTags(d->mItem.d_ptr);
156  auto deletedTags = ItemChangeLog::instance()->deletedTags(d->mItem.d_ptr);
157  if (!addedTags.isEmpty() && (d->mItem.d_ptr->mTagsOverwritten || !merge)) {
158  cmd->setTags(ProtocolHelper::entitySetToScope(addedTags));
159  } else {
160  if (!addedTags.isEmpty()) {
161  cmd->setAddedTags(ProtocolHelper::entitySetToScope(addedTags));
162  }
163  if (!deletedTags.isEmpty()) {
164  cmd->setRemovedTags(ProtocolHelper::entitySetToScope(deletedTags));
165  }
166  }
167 
168  cmd->setCollection(ProtocolHelper::entityToScope(d->mCollection));
169  cmd->setItemSize(d->mItem.size());
170 
171  cmd->setAttributes(ProtocolHelper::attributesToProtocol(d->mItem));
172  QSet<QByteArray> parts;
173  parts.reserve(d->mParts.size());
174  for (const QByteArray &part : qAsConst(d->mParts)) {
175  parts.insert(ProtocolHelper::encodePartIdentifier(ProtocolHelper::PartPayload, part));
176  }
177  cmd->setParts(parts);
178 
179  d->sendCommand(cmd);
180 }
181 
182 bool ItemCreateJob::doHandleResponse(qint64 tag, const Protocol::CommandPtr &response)
183 {
184  Q_D(ItemCreateJob);
185 
186  if (!response->isResponse() && response->type() == Protocol::Command::StreamPayload) {
187  const auto &streamCmd = Protocol::cmdCast<Protocol::StreamPayloadCommand>(response);
188  auto streamResp = Protocol::StreamPayloadResponsePtr::create();
189  streamResp->setPayloadName(streamCmd.payloadName());
190  if (streamCmd.request() == Protocol::StreamPayloadCommand::MetaData) {
191  streamResp->setMetaData(d->preparePart(streamCmd.payloadName()));
192  } else {
193  if (streamCmd.destination().isEmpty()) {
194  streamResp->setData(d->mPendingData);
195  } else {
197  if (!ProtocolHelper::streamPayloadToFile(streamCmd.destination(), d->mPendingData, error)) {
198  // Error?
199  }
200  }
201  }
202  d->sendCommand(tag, streamResp);
203  return false;
204  }
205 
206  if (response->isResponse() && response->type() == Protocol::Command::FetchItems) {
207  const auto &fetchResp = Protocol::cmdCast<Protocol::FetchItemsResponse>(response);
208  Item item = ProtocolHelper::parseItemFetchResult(fetchResp);
209  if (!item.isValid()) {
210  // Error, maybe?
211  return false;
212  }
213  d->mItem = item;
214  return false;
215  }
216 
217  if (response->isResponse() && response->type() == Protocol::Command::CreateItem) {
218  return true;
219  }
220 
221  return Job::doHandleResponse(tag, response);
222 }
223 
225 {
226  Q_D(ItemCreateJob);
227 
228  d->mMergeOptions = options;
229 }
230 
232 {
233  Q_D(const ItemCreateJob);
234 
235  // Parent collection is available only with non-silent merge/create
236  if (d->mItem.parentCollection().isValid()) {
237  return d->mItem;
238  }
239 
240  Item item(d->mItem);
241  item.setRevision(0);
242  item.setModificationTime(d->mDatetime);
243  item.setParentCollection(d->mCollection);
244  item.setStorageCollectionId(d->mCollection.id());
245 
246  return item;
247 }
Item item() const
Returns the created item with the new unique id, or an invalid item if the job failed.
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:385
void emitResult()
Unknown error.
Definition: job.h:115
Represents a collection of PIM items.
Definition: collection.h:76
void setError(int errorCode)
Base class for all actions in the Akonadi storage.
Definition: job.h:93
QSet::iterator insert(const T &value)
~ItemCreateJob() override
Destroys the item create job.
void setErrorText(const QString &errorText)
void doStart() override
This method must be reimplemented in the concrete jobs.
bool isEmpty() const const
Job that creates a new item in the Akonadi storage.
Definition: itemcreatejob.h:75
virtual qint64 size() const const override
QString i18n(const char *text, const TYPE &arg...)
Helper integration between Akonadi and Qt.
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
void reserve(int size)
Merge by remote id.
int size() const const
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.
Only return the id of the merged/created item.
int error() const
void setMerge(MergeOptions options)
Merge this item into an existing one if available.
KDB_EXPORT KDbVersionInfo version()
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Fri Jun 5 2020 23:08:55 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.