mirror of
https://bitbucket.org/smil3y/kde-playground.git
synced 2025-02-23 10:22:50 +00:00
275 lines
8.3 KiB
C++
275 lines
8.3 KiB
C++
/*
|
|
Copyright (c) 2006 - 2007 Volker Krause <vkrause@kde.org>
|
|
Copyright (c) 2007 Robert Zwerus <arzie@dds.nl>
|
|
Copyright (c) 2014 Daniel Vrátil <dvratil@redhat.com>
|
|
|
|
This library is free software; you can redistribute it and/or modify it
|
|
under the terms of the GNU Library General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or (at your
|
|
option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful, but WITHOUT
|
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
|
|
License for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
along with this library; see the file COPYING.LIB. If not, write to the
|
|
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
02110-1301, USA.
|
|
*/
|
|
|
|
#include "itemcreatejob.h"
|
|
|
|
#include "collection.h"
|
|
#include "imapparser_p.h"
|
|
#include "item.h"
|
|
#include "item_p.h"
|
|
#include "itemserializer_p.h"
|
|
#include "job_p.h"
|
|
#include "protocolhelper_p.h"
|
|
#include "gid/gidextractor_p.h"
|
|
|
|
#include <QtCore/QDateTime>
|
|
#include <QtCore/QFile>
|
|
|
|
#include <kdebug.h>
|
|
|
|
using namespace Akonadi;
|
|
|
|
class Akonadi::ItemCreateJobPrivate : public JobPrivate
|
|
{
|
|
public:
|
|
ItemCreateJobPrivate(ItemCreateJob *parent)
|
|
: JobPrivate(parent)
|
|
, mMergeOptions(ItemCreateJob::NoMerge)
|
|
, mItemReceived(false)
|
|
{
|
|
}
|
|
|
|
QByteArray nextPartHeader();
|
|
|
|
Collection mCollection;
|
|
Item mItem;
|
|
QSet<QByteArray> mParts;
|
|
Item::Id mUid;
|
|
QDateTime mDatetime;
|
|
QByteArray mPendingData;
|
|
ItemCreateJob::MergeOptions mMergeOptions;
|
|
bool mItemReceived;
|
|
};
|
|
|
|
QByteArray ItemCreateJobPrivate::nextPartHeader()
|
|
{
|
|
QByteArray command;
|
|
if (!mParts.isEmpty()) {
|
|
QSetIterator<QByteArray> it(mParts);
|
|
const QByteArray label = it.next();
|
|
mParts.remove(label);
|
|
|
|
mPendingData.clear();
|
|
int version = 0;
|
|
ItemSerializer::serialize(mItem, label, mPendingData, version);
|
|
command += ' ' + ProtocolHelper::encodePartIdentifier(ProtocolHelper::PartPayload, label, version);
|
|
if (mPendingData.size() > 0) {
|
|
command += " {" + QByteArray::number(mPendingData.size()) + "}\n";
|
|
} else {
|
|
if (mPendingData.isNull()) {
|
|
command += " NIL";
|
|
} else {
|
|
command += " \"\"";
|
|
}
|
|
command += nextPartHeader();
|
|
}
|
|
} else {
|
|
command += ")\n";
|
|
}
|
|
return command;
|
|
}
|
|
|
|
ItemCreateJob::ItemCreateJob(const Item &item, const Collection &collection, QObject *parent)
|
|
: Job(new ItemCreateJobPrivate(this), parent)
|
|
{
|
|
Q_D(ItemCreateJob);
|
|
|
|
Q_ASSERT(!item.mimeType().isEmpty());
|
|
d->mItem = item;
|
|
d->mParts = d->mItem.loadedPayloadParts();
|
|
d->mCollection = collection;
|
|
}
|
|
|
|
ItemCreateJob::~ItemCreateJob()
|
|
{
|
|
}
|
|
|
|
void ItemCreateJob::doStart()
|
|
{
|
|
Q_D(ItemCreateJob);
|
|
|
|
QByteArray remoteId;
|
|
|
|
QList<QByteArray> flags;
|
|
flags.append("\\MimeType[" + d->mItem.mimeType().toLatin1() + ']');
|
|
const QString gid = GidExtractor::getGid(d->mItem);
|
|
if (!gid.isNull()) {
|
|
flags.append(ImapParser::quote("\\Gid[" + gid.toUtf8() + ']'));
|
|
}
|
|
if (!d->mItem.remoteId().isEmpty()) {
|
|
flags.append(ImapParser::quote("\\RemoteId[" + d->mItem.remoteId().toUtf8() + ']'));
|
|
}
|
|
if (!d->mItem.remoteRevision().isEmpty()) {
|
|
flags.append(ImapParser::quote("\\RemoteRevision[" + d->mItem.remoteRevision().toUtf8() + ']'));
|
|
}
|
|
const bool mergeByGid = (d->mMergeOptions & GID) && !d->mItem.gid().isEmpty();
|
|
const bool mergeByRid = (d->mMergeOptions & RID) && !d->mItem.remoteId().isEmpty();
|
|
const bool mergeSilent = (d->mMergeOptions & Silent);
|
|
const bool merge = mergeByGid || mergeByRid;
|
|
if (d->mItem.d_func()->mFlagsOverwritten || !merge) {
|
|
flags += d->mItem.flags().toList();
|
|
} else {
|
|
Q_FOREACH(const QByteArray &flag, d->mItem.d_func()->mAddedFlags.toList()) {
|
|
flags += "+" + flag;
|
|
}
|
|
Q_FOREACH(const QByteArray &flag, d->mItem.d_func()->mDeletedFlags.toList()) {
|
|
flags += "-" + flag;
|
|
}
|
|
}
|
|
if (d->mItem.d_func()->mTagsOverwritten || !merge) {
|
|
Q_FOREACH(const Akonadi::Tag &tag, d->mItem.d_func()->mAddedTags) {
|
|
if (tag.gid().isEmpty() && !tag.remoteId().isEmpty()) {
|
|
flags += "\\RTag[" + tag.remoteId() + ']';
|
|
} else if (!tag.gid().isEmpty()) {
|
|
flags += "\\Tag[" + tag.gid() + ']';
|
|
}
|
|
}
|
|
} else {
|
|
Q_FOREACH(const Akonadi::Tag &tag, d->mItem.d_func()->mAddedTags) {
|
|
if (tag.gid().isEmpty() && !tag.remoteId().isEmpty()) {
|
|
flags += "+\\RTag[" + tag.remoteId() + ']';
|
|
} else if (!tag.gid().isEmpty()) {
|
|
flags += "+\\Tag[" + tag.gid() + ']';
|
|
}
|
|
}
|
|
Q_FOREACH(const Akonadi::Tag &tag, d->mItem.d_func()->mDeletedTags) {
|
|
if (tag.gid().isEmpty() && !tag.remoteId().isEmpty()) {
|
|
flags += "-\\RTag[" + tag.remoteId() + ']';
|
|
} else if (!tag.gid().isEmpty()) {
|
|
flags += "-\\Tag[" + tag.gid() + ']';
|
|
}
|
|
}
|
|
}
|
|
|
|
QByteArray command = d->newTag();
|
|
if (merge) {
|
|
QList<QByteArray> mergeArgs;
|
|
if (mergeByGid) {
|
|
mergeArgs << "GID";
|
|
}
|
|
if (mergeByRid) {
|
|
mergeArgs << "REMOTEID";
|
|
}
|
|
if (mergeSilent) {
|
|
mergeArgs << "SILENT";
|
|
}
|
|
command += " MERGE (" + ImapParser::join(mergeArgs, " ") + ") ";
|
|
} else {
|
|
command += " X-AKAPPEND ";
|
|
}
|
|
|
|
command += QByteArray::number(d->mCollection.id())
|
|
+ ' ' + QByteArray::number(d->mItem.size())
|
|
+ " (" + ImapParser::join(flags, " ") + ")"
|
|
+ " ("; // list of parts
|
|
const QByteArray attrs = ProtocolHelper::attributesToByteArray(d->mItem, true);
|
|
if (!attrs.isEmpty()) {
|
|
command += attrs;
|
|
}
|
|
|
|
command += d->nextPartHeader();
|
|
|
|
d->writeData(command);
|
|
}
|
|
|
|
void ItemCreateJob::doHandleResponse(const QByteArray &tag, const QByteArray &data)
|
|
{
|
|
Q_D(ItemCreateJob);
|
|
|
|
if (tag == "+") { // ready for literal data
|
|
if (data.startsWith("STREAM")) {
|
|
QByteArray error;
|
|
if (!ProtocolHelper::streamPayloadToFile(data, d->mPendingData, error)) {
|
|
d->writeData("* NO " + error);
|
|
return;
|
|
}
|
|
} else {
|
|
d->writeData(d->mPendingData);
|
|
}
|
|
d->writeData(d->nextPartHeader());
|
|
return;
|
|
}
|
|
if (tag == "*") {
|
|
int begin = data.indexOf("FETCH");
|
|
if (begin >= 0) {
|
|
QList<QByteArray> fetchResponse;
|
|
ImapParser::parseParenthesizedList(data, fetchResponse, begin + 6);
|
|
|
|
Item item;
|
|
ProtocolHelper::parseItemFetchResult(fetchResponse, item);
|
|
if (!item.isValid()) {
|
|
// Error, maybe?
|
|
return;
|
|
}
|
|
d->mItemReceived = true;
|
|
d->mItem = item;
|
|
}
|
|
return;
|
|
}
|
|
if (tag == d->tag()) {
|
|
int uidNextPos = data.indexOf("UIDNEXT");
|
|
if (uidNextPos != -1) {
|
|
bool ok = false;
|
|
ImapParser::parseNumber(data, d->mUid, &ok, uidNextPos + 7);
|
|
if (!ok) {
|
|
kDebug() << "Invalid UIDNEXT response to APPEND command: "
|
|
<< tag << data;
|
|
}
|
|
}
|
|
int dateTimePos = data.indexOf("DATETIME");
|
|
if (dateTimePos != -1) {
|
|
int resultPos = ImapParser::parseDateTime(data, d->mDatetime, dateTimePos + 8);
|
|
if (resultPos == (dateTimePos + 8)) {
|
|
kDebug() << "Invalid DATETIME response to APPEND command: "
|
|
<< tag << data;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void ItemCreateJob::setMerge(ItemCreateJob::MergeOptions options)
|
|
{
|
|
Q_D(ItemCreateJob);
|
|
|
|
d->mMergeOptions = options;
|
|
}
|
|
|
|
Item ItemCreateJob::item() const
|
|
{
|
|
Q_D(const ItemCreateJob);
|
|
|
|
if (d->mItemReceived) {
|
|
return d->mItem;
|
|
}
|
|
|
|
if (d->mUid == 0) {
|
|
return Item();
|
|
}
|
|
|
|
Item item(d->mItem);
|
|
item.setId(d->mUid);
|
|
item.setRevision(0);
|
|
item.setModificationTime(d->mDatetime);
|
|
item.setParentCollection(d->mCollection);
|
|
item.setStorageCollectionId(d->mCollection.id());
|
|
|
|
return item;
|
|
}
|