20 #include "itemmodifyjob.h"
21 #include "itemmodifyjob_p.h"
23 #include "changemediator_p.h"
24 #include "collection.h"
25 #include "conflicthandling/conflicthandler_p.h"
27 #include "imapparser_p.h"
29 #include "itemserializer_p.h"
31 #include "protocolhelper_p.h"
35 using namespace Akonadi;
37 ItemModifyJobPrivate::ItemModifyJobPrivate(
ItemModifyJob *parent )
40 mIgnorePayload( false ),
41 mAutomaticConflictHandlingEnabled( true )
45 void ItemModifyJobPrivate::setClean()
47 mOperations.insert( Dirty );
50 QByteArray ItemModifyJobPrivate::nextPartHeader()
53 if ( !mParts.isEmpty() ) {
54 QSetIterator<QByteArray> it( mParts );
55 const QByteArray label = it.next();
56 mParts.remove( label );
62 if ( mPendingData.size() > 0 ) {
63 command +=
" {" + QByteArray::number( mPendingData.size() ) +
"}\n";
65 if ( mPendingData.isNull() )
69 command += nextPartHeader();
77 void ItemModifyJobPrivate::conflictResolved()
81 q->setError( KJob::NoError );
82 q->setErrorText( QString() );
86 void ItemModifyJobPrivate::conflictResolveError(
const QString &message )
90 q->setErrorText( q->errorText() + message );
96 Item::List::iterator it = std::find_if( mItems.begin(), mItems.end(), boost::bind( &
Item::id, _1 ) == itemId );
97 if ( it != mItems.end() && (*it).revision() == oldRevision )
98 (*it).setRevision( newRevision );
107 d->mItems.append( item );
110 d->mOperations.insert( ItemModifyJobPrivate::RemoteId );
111 d->mOperations.insert( ItemModifyJobPrivate::RemoteRevision );
117 Q_ASSERT( !items.isEmpty() );
122 if ( d->mItems.size() == 1 ) {
123 d->mParts = items.first().loadedPayloadParts();
124 d->mOperations.insert( ItemModifyJobPrivate::RemoteId );
125 d->mOperations.insert( ItemModifyJobPrivate::RemoteRevision );
127 d->mIgnorePayload =
true;
128 d->mRevCheck =
false;
142 QList<QByteArray> changes;
143 foreach (
int op, d->mOperations ) {
145 case ItemModifyJobPrivate::RemoteId:
147 changes <<
"REMOTEID";
148 changes << ImapParser::quote( item.
remoteId().toUtf8() );
151 case ItemModifyJobPrivate::RemoteRevision:
153 changes <<
"REMOTEREVISION";
157 case ItemModifyJobPrivate::Dirty:
164 if ( item.d_func()->mClearPayload )
165 changes <<
"INVALIDATECACHE";
167 if ( item.d_func()->mFlagsOverwritten ) {
169 changes <<
'(' + ImapParser::join( item.
flags(),
" " ) +
')';
171 if ( !item.d_func()->mAddedFlags.isEmpty() ) {
173 changes <<
'(' + ImapParser::join( item.d_func()->mAddedFlags,
" " ) +
')';
175 if ( !item.d_func()->mDeletedFlags.isEmpty() ) {
177 changes <<
'(' + ImapParser::join( item.d_func()->mDeletedFlags,
" " ) +
')';
181 if ( !item.d_func()->mDeletedAttributes.isEmpty() ) {
183 QList<QByteArray> attrs;
184 foreach (
const QByteArray &attr, item.d_func()->mDeletedAttributes )
186 changes <<
'(' + ImapParser::join( attrs,
" " ) +
')';
190 if ( changes.isEmpty() && d->mParts.isEmpty() && item.
attributes().isEmpty() ) {
195 d->mTag = d->newTag();
196 QByteArray command = d->mTag;
201 setErrorText( QString::fromUtf8( e.
what() ) );
206 if ( !d->mRevCheck || item.
revision() < 0 ) {
209 command +=
"REV " + QByteArray::number( item.
revision() ) +
' ';
212 if ( item.d_func()->mSizeChanged )
213 command +=
"SIZE " + QByteArray::number( item.
size() );
215 command +=
" (" + ImapParser::join( changes,
" " );
217 if ( !attrs.isEmpty() )
218 command +=
' ' + attrs;
219 command += d->nextPartHeader();
220 d->writeData( command );
229 d->writeData( d->mPendingData );
230 d->writeData( d->nextPartHeader() );
234 if ( _tag == d->mTag ) {
235 if ( data.startsWith(
"OK" ) ) {
236 QDateTime modificationDateTime;
237 int dateTimePos = data.indexOf(
"DATETIME" );
238 if ( dateTimePos != -1 ) {
239 int resultPos = ImapParser::parseDateTime( data, modificationDateTime, dateTimePos + 8 );
240 if ( resultPos == (dateTimePos + 8) ) {
241 kDebug() <<
"Invalid DATETIME response to STORE command: " << _tag << data;
247 item.d_ptr->resetChangeLog();
250 setErrorText( QString::fromUtf8( data ) );
252 if ( data.contains(
"[LLCONFLICT]" ) ) {
253 if ( d->mAutomaticConflictHandlingEnabled ) {
256 connect( handler, SIGNAL(conflictResolved()), SLOT(conflictResolved()) );
257 connect( handler, SIGNAL(error(QString)), SLOT(conflictResolveError(QString)) );
259 QMetaObject::invokeMethod( handler,
"start", Qt::QueuedConnection );
265 foreach (
const Item &
item, d->mItems ) {
266 ChangeMediator::invalidateItem(item);
275 ImapParser::parseNumber( data,
id );
276 int pos = data.indexOf(
'(' );
277 if ( pos <= 0 ||
id <= 0 ) {
278 kDebug() <<
"Ignoring strange response: " << _tag << data;
281 Item::List::iterator it = std::find_if( d->mItems.begin(), d->mItems.end(), boost::bind( &
Item::id, _1 ) == id );
282 if ( it == d->mItems.end() ) {
283 kDebug() <<
"Received STORE response for an item we did not modify: " << _tag << data;
286 QList<QByteArray> attrs;
287 ImapParser::parseParenthesizedList( data, attrs, pos );
288 for (
int i = 0; i < attrs.size() - 1; i += 2 ) {
289 const QByteArray key = attrs.at( i );
290 if ( key ==
"REV" ) {
291 const int newRev = attrs.at( i + 1 ).toInt();
292 const int oldRev = (*it).revision();
293 if ( newRev < oldRev || newRev < 0 )
295 d->itemRevisionChanged( (*it).id(), oldRev, newRev );
296 (*it).setRevision( newRev );
302 kDebug() <<
"Unhandled response: " << _tag << data;
309 if ( d->mIgnorePayload == ignore )
312 d->mIgnorePayload = ignore;
313 if ( d->mIgnorePayload )
314 d->mParts = QSet<QByteArray>();
316 Q_ASSERT( !d->mItems.first().mimeType().isEmpty() );
317 d->mParts = d->mItems.first().loadedPayloadParts();
325 return d->mIgnorePayload;
332 d->mRevCheck =
false;
339 d->mAutomaticConflictHandlingEnabled =
false;
345 Q_ASSERT( d->mItems.size() == 1 );
347 return d->mItems.first();
356 #include "moc_itemmodifyjob.cpp"