• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.10.5 API Reference
  • KDE Home
  • Contact Us
 

akonadi

  • akonadi
itemmodifyjob.cpp
1 /*
2  Copyright (c) 2006 - 2007 Volker Krause <vkrause@kde.org>
3 
4  This library is free software; you can redistribute it and/or modify it
5  under the terms of the GNU Library General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or (at your
7  option) any later version.
8 
9  This library is distributed in the hope that it will be useful, but WITHOUT
10  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12  License for more details.
13 
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB. If not, write to the
16  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  02110-1301, USA.
18 */
19 
20 #include "itemmodifyjob.h"
21 #include "itemmodifyjob_p.h"
22 
23 #include "changemediator_p.h"
24 #include "collection.h"
25 #include "conflicthandling/conflicthandler_p.h"
26 #include "entity_p.h"
27 #include "imapparser_p.h"
28 #include "item_p.h"
29 #include "itemserializer_p.h"
30 #include "job_p.h"
31 #include "protocolhelper_p.h"
32 
33 #include <kdebug.h>
34 
35 using namespace Akonadi;
36 
37 ItemModifyJobPrivate::ItemModifyJobPrivate( ItemModifyJob *parent )
38  : JobPrivate( parent ),
39  mRevCheck( true ),
40  mIgnorePayload( false ),
41  mAutomaticConflictHandlingEnabled( true )
42 {
43 }
44 
45 void ItemModifyJobPrivate::setClean()
46 {
47  mOperations.insert( Dirty );
48 }
49 
50 QByteArray ItemModifyJobPrivate::nextPartHeader()
51 {
52  QByteArray command;
53  if ( !mParts.isEmpty() ) {
54  QSetIterator<QByteArray> it( mParts );
55  const QByteArray label = it.next();
56  mParts.remove( label );
57 
58  mPendingData.clear();
59  int version = 0;
60  ItemSerializer::serialize( mItems.first(), label, mPendingData, version );
61  command += ' ' + ProtocolHelper::encodePartIdentifier( ProtocolHelper::PartPayload, label, version );
62  if ( mPendingData.size() > 0 ) {
63  command += " {" + QByteArray::number( mPendingData.size() ) + "}\n";
64  } else {
65  if ( mPendingData.isNull() )
66  command += " NIL";
67  else
68  command += " \"\"";
69  command += nextPartHeader();
70  }
71  } else {
72  command += ")\n";
73  }
74  return command;
75 }
76 
77 void ItemModifyJobPrivate::conflictResolved()
78 {
79  Q_Q( ItemModifyJob );
80 
81  q->setError( KJob::NoError );
82  q->setErrorText( QString() );
83  q->emitResult();
84 }
85 
86 void ItemModifyJobPrivate::conflictResolveError( const QString &message )
87 {
88  Q_Q( ItemModifyJob );
89 
90  q->setErrorText( q->errorText() + message );
91  q->emitResult();
92 }
93 
94 void ItemModifyJobPrivate::doUpdateItemRevision( Akonadi::Item::Id itemId, int oldRevision, int newRevision )
95 {
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 );
99 }
100 
101 
102 ItemModifyJob::ItemModifyJob( const Item &item, QObject * parent )
103  : Job( new ItemModifyJobPrivate( this ), parent )
104 {
105  Q_D( ItemModifyJob );
106 
107  d->mItems.append( item );
108  d->mParts = item.loadedPayloadParts();
109 
110  d->mOperations.insert( ItemModifyJobPrivate::RemoteId );
111  d->mOperations.insert( ItemModifyJobPrivate::RemoteRevision );
112 }
113 
114 ItemModifyJob::ItemModifyJob( const Akonadi::Item::List &items, QObject *parent)
115  : Job( new ItemModifyJobPrivate( this ), parent )
116 {
117  Q_ASSERT( !items.isEmpty() );
118  Q_D( ItemModifyJob );
119  d->mItems = items;
120 
121  // same as single item ctor
122  if ( d->mItems.size() == 1 ) {
123  d->mParts = items.first().loadedPayloadParts();
124  d->mOperations.insert( ItemModifyJobPrivate::RemoteId );
125  d->mOperations.insert( ItemModifyJobPrivate::RemoteRevision );
126  } else {
127  d->mIgnorePayload = true;
128  d->mRevCheck = false;
129  }
130 }
131 
132 
133 ItemModifyJob::~ItemModifyJob()
134 {
135 }
136 
137 void ItemModifyJob::doStart()
138 {
139  Q_D( ItemModifyJob );
140 
141  const Akonadi::Item item = d->mItems.first();
142  QList<QByteArray> changes;
143  foreach ( int op, d->mOperations ) {
144  switch ( op ) {
145  case ItemModifyJobPrivate::RemoteId:
146  if ( !item.remoteId().isNull() ) {
147  changes << "REMOTEID";
148  changes << ImapParser::quote( item.remoteId().toUtf8() );
149  }
150  break;
151  case ItemModifyJobPrivate::RemoteRevision:
152  if ( !item.remoteRevision().isNull() ) {
153  changes << "REMOTEREVISION";
154  changes << ImapParser::quote( item.remoteRevision().toUtf8() );
155  }
156  break;
157  case ItemModifyJobPrivate::Dirty:
158  changes << "DIRTY";
159  changes << "false";
160  break;
161  }
162  }
163 
164  if ( item.d_func()->mClearPayload )
165  changes << "INVALIDATECACHE";
166 
167  if ( item.d_func()->mFlagsOverwritten ) {
168  changes << "FLAGS";
169  changes << '(' + ImapParser::join( item.flags(), " " ) + ')';
170  } else {
171  if ( !item.d_func()->mAddedFlags.isEmpty() ) {
172  changes << "+FLAGS";
173  changes << '(' + ImapParser::join( item.d_func()->mAddedFlags, " " ) + ')';
174  }
175  if ( !item.d_func()->mDeletedFlags.isEmpty() ) {
176  changes << "-FLAGS";
177  changes << '(' + ImapParser::join( item.d_func()->mDeletedFlags, " " ) + ')';
178  }
179  }
180 
181  if ( !item.d_func()->mDeletedAttributes.isEmpty() ) {
182  changes << "-PARTS";
183  QList<QByteArray> attrs;
184  foreach ( const QByteArray &attr, item.d_func()->mDeletedAttributes )
185  attrs << ProtocolHelper::encodePartIdentifier( ProtocolHelper::PartAttribute, attr );
186  changes << '(' + ImapParser::join( attrs, " " ) + ')';
187  }
188 
189  // nothing to do
190  if ( changes.isEmpty() && d->mParts.isEmpty() && item.attributes().isEmpty() ) {
191  emitResult();
192  return;
193  }
194 
195  d->mTag = d->newTag();
196  QByteArray command = d->mTag;
197  try {
198  command += ProtocolHelper::entitySetToByteArray( d->mItems, "STORE" );
199  } catch ( const Exception &e ) {
200  setError( Job::Unknown );
201  setErrorText( QString::fromUtf8( e.what() ) );
202  emitResult();
203  return;
204  }
205  command += ' ';
206  if ( !d->mRevCheck || item.revision() < 0 ) {
207  command += "NOREV ";
208  } else {
209  command += "REV " + QByteArray::number( item.revision() ) + ' ';
210  }
211 
212  if ( item.d_func()->mSizeChanged )
213  command += "SIZE " + QByteArray::number( item.size() );
214 
215  command += " (" + ImapParser::join( changes, " " );
216  const QByteArray attrs = ProtocolHelper::attributesToByteArray( item, true );
217  if ( !attrs.isEmpty() )
218  command += ' ' + attrs;
219  command += d->nextPartHeader();
220  d->writeData( command );
221  d->newTag(); // hack to circumvent automatic response handling
222 }
223 
224 void ItemModifyJob::doHandleResponse(const QByteArray &_tag, const QByteArray & data)
225 {
226  Q_D( ItemModifyJob );
227 
228  if ( _tag == "+" ) { // ready for literal data
229  d->writeData( d->mPendingData );
230  d->writeData( d->nextPartHeader() );
231  return;
232  }
233 
234  if ( _tag == d->mTag ) {
235  if ( data.startsWith( "OK" ) ) { //krazy:exclude=strings
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;
242  }
243  }
244 
245  Item &item = d->mItems.first();
246  item.setModificationTime( modificationDateTime );
247  item.d_ptr->resetChangeLog();
248  } else {
249  setError( Unknown );
250  setErrorText( QString::fromUtf8( data ) );
251 
252  if ( data.contains( "[LLCONFLICT]" ) ) {
253  if ( d->mAutomaticConflictHandlingEnabled ) {
254  ConflictHandler *handler = new ConflictHandler( ConflictHandler::LocalLocalConflict, this );
255  handler->setConflictingItems( d->mItems.first(), d->mItems.first() );
256  connect( handler, SIGNAL(conflictResolved()), SLOT(conflictResolved()) );
257  connect( handler, SIGNAL(error(QString)), SLOT(conflictResolveError(QString)) );
258 
259  QMetaObject::invokeMethod( handler, "start", Qt::QueuedConnection );
260  return;
261  }
262  }
263  }
264 
265  foreach ( const Item &item, d->mItems ) {
266  ChangeMediator::invalidateItem(item);
267  }
268 
269  emitResult();
270  return;
271  }
272 
273  if ( _tag == "*" ) {
274  Akonadi::Item::Id id;
275  ImapParser::parseNumber( data, id );
276  int pos = data.indexOf( '(' );
277  if ( pos <= 0 || id <= 0 ) {
278  kDebug() << "Ignoring strange response: " << _tag << data;
279  return;
280  }
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;
284  return;
285  }
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 )
294  continue;
295  d->itemRevisionChanged( (*it).id(), oldRev, newRev );
296  (*it).setRevision( newRev );
297  }
298  }
299  return;
300  }
301 
302  kDebug() << "Unhandled response: " << _tag << data;
303 }
304 
305 void ItemModifyJob::setIgnorePayload( bool ignore )
306 {
307  Q_D( ItemModifyJob );
308 
309  if ( d->mIgnorePayload == ignore )
310  return;
311 
312  d->mIgnorePayload = ignore;
313  if ( d->mIgnorePayload )
314  d->mParts = QSet<QByteArray>();
315  else {
316  Q_ASSERT( !d->mItems.first().mimeType().isEmpty() );
317  d->mParts = d->mItems.first().loadedPayloadParts();
318  }
319 }
320 
321 bool ItemModifyJob::ignorePayload() const
322 {
323  Q_D( const ItemModifyJob );
324 
325  return d->mIgnorePayload;
326 }
327 
328 void ItemModifyJob::disableRevisionCheck()
329 {
330  Q_D( ItemModifyJob );
331 
332  d->mRevCheck = false;
333 }
334 
335 void ItemModifyJob::disableAutomaticConflictHandling()
336 {
337  Q_D( ItemModifyJob );
338 
339  d->mAutomaticConflictHandlingEnabled = false;
340 }
341 
342 Item ItemModifyJob::item() const
343 {
344  Q_D( const ItemModifyJob );
345  Q_ASSERT( d->mItems.size() == 1 );
346 
347  return d->mItems.first();
348 }
349 
350 Item::List ItemModifyJob::items() const
351 {
352  Q_D( const ItemModifyJob );
353  return d->mItems;
354 }
355 
356 #include "moc_itemmodifyjob.cpp"
This file is part of the KDE documentation.
Documentation copyright © 1996-2013 The KDE developers.
Generated on Sat Jul 13 2013 01:27:38 by doxygen 1.8.3.1 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

akonadi

Skip menu "akonadi"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • Modules
  • Related Pages

kdepimlibs-4.10.5 API Reference

Skip menu "kdepimlibs-4.10.5 API Reference"
  • akonadi
  •   contact
  •   kmime
  •   socialutils
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal