9#include "itemcreatejob.h"
11#include "collection.h"
12#include "gidextractor_p.h"
15#include "itemserializer_p.h"
17#include "private/protocol_p.h"
18#include "protocolhelper_p.h"
22#include <KLocalizedString>
26class Akonadi::ItemCreateJobPrivate :
public JobPrivate
34 Protocol::PartMetaData preparePart(
const QByteArray &part);
36 QString jobDebuggingString()
const override;
52 bool mItemReceived =
false;
55QString Akonadi::ItemCreateJobPrivate::jobDebuggingString()
const
57 const QString collectionName = mCollection.name();
58 QString str = QStringLiteral(
"%1 Item %2 from col %3")
61 .
arg(mCollection.id());
62 if (!collectionName.
isEmpty()) {
63 str += QStringLiteral(
" (%1)").
arg(collectionName);
68Protocol::PartMetaData ItemCreateJobPrivate::preparePart(
const QByteArray &partName)
70 ProtocolHelper::PartNamespace ns;
71 const QByteArray partLabel = ProtocolHelper::decodePartIdentifier(partName, ns);
72 if (!mParts.
remove(partLabel)) {
74 return Protocol::PartMetaData();
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);
84 mPendingPart.name = partName;
85 ItemSerializer::serialize(mItem, partLabel, mPendingPart.data, version);
86 return Protocol::PartMetaData(partName, mPendingPart.data.
size(), version);
91 :
Job(new ItemCreateJobPrivate(this), parent)
98 d->mCollection = collection;
100 if (!d->mItem.payloadPath().isEmpty()) {
101 d->mForeignParts = ItemSerializer::allowedForeignParts(d->mItem);
113 if (!d->mCollection.isValid()) {
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());
127 Protocol::CreateItemCommand::MergeModes mergeModes = Protocol::CreateItemCommand::None;
128 if ((d->mMergeOptions &
GID) && !d->mItem.gid().isEmpty()) {
129 mergeModes |= Protocol::CreateItemCommand::GID;
131 if ((d->mMergeOptions &
RID) && !d->mItem.remoteId().isEmpty()) {
132 mergeModes |= Protocol::CreateItemCommand::RemoteID;
134 if ((d->mMergeOptions &
Silent)) {
135 mergeModes |= Protocol::CreateItemCommand::Silent;
137 const bool merge = (mergeModes & Protocol::CreateItemCommand::GID) || (mergeModes & Protocol::CreateItemCommand::RemoteID);
138 cmd->setMergeModes(mergeModes);
140 if (d->mItem.d_ptr->mFlagsOverwritten || !merge) {
141 cmd->setFlags(d->mItem.flags());
142 cmd->setFlagsOverwritten(d->mItem.d_ptr->mFlagsOverwritten);
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);
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));
156 const auto addedTags = ItemChangeLog::instance()->addedTags(d->mItem.d_ptr);
157 if (!addedTags.isEmpty()) {
158 cmd->setAddedTags(ProtocolHelper::entitySetToScope(addedTags));
160 const auto deletedTags = ItemChangeLog::instance()->deletedTags(d->mItem.d_ptr);
161 if (!deletedTags.isEmpty()) {
162 cmd->setRemovedTags(ProtocolHelper::entitySetToScope(deletedTags));
166 cmd->setCollection(ProtocolHelper::entityToScope(d->mCollection));
167 cmd->setItemSize(d->mItem.size());
169 cmd->setAttributes(ProtocolHelper::attributesToProtocol(d->mItem));
171 parts.
reserve(d->mParts.size());
172 for (
const QByteArray &part : std::as_const(d->mParts)) {
173 parts.
insert(ProtocolHelper::encodePartIdentifier(ProtocolHelper::PartPayload, part));
175 cmd->setParts(parts);
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);
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)));
202 streamResp->setError(1, QStringLiteral(
"Unknown stream payload request"));
204 d->sendCommand(tag, streamResp);
208 if (response->isResponse() && response->type() == Protocol::Command::FetchItems) {
209 const auto &fetchResp = Protocol::cmdCast<Protocol::FetchItemsResponse>(response);
210 Item item = ProtocolHelper::parseItemFetchResult(fetchResp);
219 if (response->isResponse() && response->type() == Protocol::Command::CreateItem) {
230 d->mMergeOptions = options;
238 if (d->mItem.parentCollection().isValid()) {
245 item.setStorageCollectionId(d->mCollection.id());
250#include "moc_itemcreatejob.cpp"
Represents a collection of PIM items.
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.
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.
void setParentCollection(const Collection &parent)
Set the parent collection of this object.
QString mimeType() const
Returns the mime type of the item.
void setRevision(int revision)
Sets the revision number of the item.
bool isValid() const
Returns whether the item is valid.
QSet< QByteArray > loadedPayloadParts() const
Returns the list of loaded payload parts.
Base class for all actions in the Akonadi storage.
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.
void setErrorText(const QString &errorText)
void setError(int errorCode)
QString i18n(const char *text, const TYPE &arg...)
Helper integration between Akonadi and Qt.
KCOREADDONS_EXPORT unsigned int version()
qsizetype size() const const
virtual qint64 size() const const override
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