22 #include "itemcreatejob.h" 24 #include "collection.h" 25 #include "imapparser_p.h" 28 #include "itemserializer_p.h" 30 #include "protocolhelper_p.h" 31 #include "gid/gidextractor_p.h" 33 #include <QtCore/QDateTime> 34 #include <QtCore/QFile> 40 class Akonadi::ItemCreateJobPrivate :
public JobPrivate 46 , mItemReceived(false)
50 QByteArray nextPartHeader();
54 QSet<QByteArray> mParts;
57 QByteArray mPendingData;
58 ItemCreateJob::MergeOptions mMergeOptions;
62 QByteArray ItemCreateJobPrivate::nextPartHeader()
65 if (!mParts.isEmpty()) {
66 QSetIterator<QByteArray> it(mParts);
67 const QByteArray label = it.next();
74 if (mPendingData.size() > 0) {
75 command +=
" {" + QByteArray::number(mPendingData.size()) +
"}\n";
77 if (mPendingData.isNull()) {
82 command += nextPartHeader();
91 :
Job(new ItemCreateJobPrivate(this), parent)
95 Q_ASSERT(!
item.mimeType().isEmpty());
97 d->mParts = d->mItem.loadedPayloadParts();
98 d->mCollection = collection;
111 QList<QByteArray> flags;
112 flags.append(
"\\MimeType[" + d->mItem.mimeType().toLatin1() +
']');
115 flags.append(ImapParser::quote(
"\\Gid[" + gid.toUtf8() +
']'));
117 if (!d->mItem.remoteId().isEmpty()) {
118 flags.append(ImapParser::quote(
"\\RemoteId[" + d->mItem.remoteId().toUtf8() +
']'));
120 if (!d->mItem.remoteRevision().isEmpty()) {
121 flags.append(ImapParser::quote(
"\\RemoteRevision[" + d->mItem.remoteRevision().toUtf8() +
']'));
123 const bool mergeByGid = (d->mMergeOptions &
GID) && !d->mItem.gid().isEmpty();
124 const bool mergeByRid = (d->mMergeOptions &
RID) && !d->mItem.remoteId().isEmpty();
125 const bool mergeSilent = (d->mMergeOptions &
Silent);
126 const bool merge = mergeByGid || mergeByRid;
127 if (d->mItem.d_func()->mFlagsOverwritten || !merge) {
128 flags += d->mItem.flags().toList();
130 Q_FOREACH(
const QByteArray &flag, d->mItem.d_func()->mAddedFlags.toList()) {
133 Q_FOREACH(
const QByteArray &flag, d->mItem.d_func()->mDeletedFlags.toList()) {
137 if (d->mItem.d_func()->mTagsOverwritten || !merge) {
138 Q_FOREACH(
const Akonadi::Tag &tag, d->mItem.d_func()->mAddedTags) {
139 if (tag.gid().isEmpty() && !tag.remoteId().isEmpty()) {
140 flags +=
"\\RTag[" + tag.remoteId() +
']';
141 }
else if (!tag.gid().isEmpty()) {
142 flags +=
"\\Tag[" + tag.gid() +
']';
146 Q_FOREACH(
const Akonadi::Tag &tag, d->mItem.d_func()->mAddedTags) {
147 if (tag.gid().isEmpty() && !tag.remoteId().isEmpty()) {
148 flags +=
"+\\RTag[" + tag.remoteId() +
']';
149 }
else if (!tag.gid().isEmpty()) {
150 flags +=
"+\\Tag[" + tag.gid() +
']';
153 Q_FOREACH(
const Akonadi::Tag &tag, d->mItem.d_func()->mDeletedTags) {
154 if (tag.gid().isEmpty() && !tag.remoteId().isEmpty()) {
155 flags +=
"-\\RTag[" + tag.remoteId() +
']';
156 }
else if (!tag.gid().isEmpty()) {
157 flags +=
"-\\Tag[" + tag.gid() +
']';
162 QByteArray command = d->newTag();
164 QList<QByteArray> mergeArgs;
169 mergeArgs <<
"REMOTEID";
172 mergeArgs <<
"SILENT";
174 command +=
" MERGE (" + ImapParser::join(mergeArgs,
" ") +
") ";
176 command +=
" X-AKAPPEND ";
179 command += QByteArray::number(d->mCollection.id())
180 +
' ' + QByteArray::number(d->mItem.size())
181 +
" (" + ImapParser::join(flags,
" ") +
")" 184 if (!attrs.isEmpty()) {
188 command += d->nextPartHeader();
190 d->writeData(command);
198 if (data.startsWith(
"STREAM")) {
200 if (!ProtocolHelper::streamPayloadToFile(data, d->mPendingData, error)) {
201 d->writeData(
"* NO " + error);
205 d->writeData(d->mPendingData);
207 d->writeData(d->nextPartHeader());
211 int begin = data.indexOf(
"FETCH");
213 QList<QByteArray> fetchResponse;
214 ImapParser::parseParenthesizedList(data, fetchResponse, begin + 6);
218 if (!
item.isValid()) {
222 d->mItemReceived =
true;
227 if (tag == d->tag()) {
228 int uidNextPos = data.indexOf(
"UIDNEXT");
229 if (uidNextPos != -1) {
231 ImapParser::parseNumber(data, d->mUid, &ok, uidNextPos + 7);
233 kDebug() <<
"Invalid UIDNEXT response to APPEND command: " 237 int dateTimePos = data.indexOf(
"DATETIME");
238 if (dateTimePos != -1) {
239 int resultPos = ImapParser::parseDateTime(data, d->mDatetime, dateTimePos + 8);
240 if (resultPos == (dateTimePos + 8)) {
241 kDebug() <<
"Invalid DATETIME response to APPEND command: " 252 d->mMergeOptions = options;
259 if (d->mItemReceived) {
270 item.setModificationTime(d->mDatetime);
271 item.setParentCollection(d->mCollection);
272 item.setStorageCollectionId(d->mCollection.id());
Represents a collection of PIM items.
static QByteArray attributesToByteArray(const Entity &entity, bool ns=false)
Convert attributes to their protocol representation.
Base class for all actions in the Akonadi storage.
static QByteArray encodePartIdentifier(PartNamespace ns, const QByteArray &label, int version=0)
Encodes part label and namespace.
Job that creates a new item in the Akonadi storage.
virtual void doHandleResponse(const QByteArray &tag, const QByteArray &data)
This method should be reimplemented in the concrete jobs in case you want to handle incoming data...
FreeBusyManager::Singleton.
virtual void doStart()
This method must be reimplemented in the concrete jobs.
ItemCreateJob(const Item &item, const Collection &collection, QObject *parent=0)
Creates a new item create job.
static void serialize(const Item &item, const QByteArray &label, QByteArray &data, int &version)
throws ItemSerializerException on failure
static void parseItemFetchResult(const QList< QByteArray > &lineTokens, Item &item, ProtocolHelperValuePool *valuePool=0)
Parses a single line from an item fetch job result into an Item object.
~ItemCreateJob()
Destroys the item create job.
Only return the id of the merged/created item.
void setMerge(MergeOptions options)
Merge this item into an existing one if available.
Item item() const
Returns the created item with the new unique id, or an invalid item if the job failed.