From kde-pim Tue Jul 22 18:58:45 2008 From: Bertjan Broeksema Date: Tue, 22 Jul 2008 18:58:45 +0000 To: kde-pim Subject: [Kde-pim] [patch] Basic item modification time support for items Message-Id: <200807222058.45950.b.broeksema () kdemail ! net> X-MARC-Message: https://marc.info/?l=kde-pim&m=121675317028730 MIME-Version: 1 Content-Type: multipart/mixed; boundary="--Boundary-00=_l3ihIj9Z/UijXZk" --Boundary-00=_l3ihIj9Z/UijXZk Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Content-Disposition: inline For review. These two patches add basic modification time support for items. Modification time is set at creation and modification. A test is added to kdepimlibs/akonadi/tests/itemstoretest.{h,cpp}. Note: This patch does not add support for retrieving items with a modification stamp after some given stamp. This patch also fixes that the item that is returned by ItemCreateJob::item() has ID 0 in stead of -1. regards, Bertjan Broeksema --Boundary-00=_l3ihIj9Z/UijXZk Content-Type: text/x-diff; charset="utf-8"; name="kdepimlibs-akonadi.dif" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="kdepimlibs-akonadi.dif" Index: itemcreatejob.cpp =================================================================== --- itemcreatejob.cpp (revision 836665) +++ itemcreatejob.cpp (working copy) @@ -27,6 +27,8 @@ #include "job_p.h" #include "protocolhelper.h" +#include + #include using namespace Akonadi; @@ -43,6 +45,7 @@ Item mItem; QSet mParts; Item::Id mUid; + QDateTime mDatetime; QByteArray mData; }; @@ -129,6 +132,13 @@ << tag << data; } } + if ( int pos = data.indexOf( "DATETIME" ) ) { + int resultPos = ImapParser::parseDateTime( data, d->mDatetime, pos + 8 ); + if ( resultPos == (pos + 8) ) { + kDebug( 5250 ) << "Invalid DATETIME response to APPEND command: " + << tag << data; + } + } } } @@ -141,6 +151,8 @@ Item item( d->mItem ); item.setId( d->mUid ); + item.setRevision( 0 ); + item.setModificationTime( d->mDatetime ); return item; } Index: itemmodifyjob.cpp =================================================================== --- itemmodifyjob.cpp (revision 836665) +++ itemmodifyjob.cpp (working copy) @@ -159,8 +159,18 @@ } if ( _tag == d->mTag ) { if ( data.startsWith( "OK" ) ) { + QDateTime modificationDateTime; + if ( int pos = data.indexOf( "DATETIME" ) ) { + int resultPos = ImapParser::parseDateTime( data, modificationDateTime, pos + 8 ); + if ( resultPos == (pos + 8) ) { + kDebug( 5250 ) << "Invalid DATETIME response to STORE command: " + << _tag << data; + } + } + // increase item revision of own copy of item d->mItem.setRevision( d->mItem.revision() + 1 ); + d->mItem.setModificationTime( modificationDateTime ); d->mItem.d_ptr->resetChangeLog(); } else { setError( Unknown ); Index: tests/itemstoretest.cpp =================================================================== --- tests/itemstoretest.cpp (revision 836665) +++ tests/itemstoretest.cpp (working copy) @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -322,4 +323,52 @@ QVERIFY( !sjob->exec() ); } +void ItemStoreTest::testModificationTime() +{ + Item item; + item.setMimeType( "text/directory" ); + QVERIFY( item.modificationTime().isNull() ); + + ItemCreateJob *job = new ItemCreateJob( item, res1_foo ); + QVERIFY( job->exec() ); + + // The item should have a datetime set now. + item = job->item(); + QVERIFY( !item.modificationTime().isNull() ); + QDateTime initialDateTime = item.modificationTime(); + + // Fetch the same item again. + Item item2( item.id() ); + ItemFetchJob *fjob = new ItemFetchJob( item2, this ); + QVERIFY( fjob->exec() ); + item2 = fjob->items().first(); + QCOMPARE( initialDateTime, item2.modificationTime() ); + + // Lets wait 5 secs. + QTest::qWait( 5000 ); + + // Modify the item + ItemModifyJob *mjob = new ItemModifyJob( item ); + item.attribute( Item::AddIfMissing )->data = "extra"; + QVERIFY( mjob->exec() ); + + // The item should still have a datetime set and that date should be somewhere + // after the initialDateTime. + item = mjob->item(); + QVERIFY( !item.modificationTime().isNull() ); + QVERIFY( initialDateTime < item.modificationTime() ); + + // Fetch the item after modification. + Item item3( item.id() ); + ItemFetchJob *fjob2 = new ItemFetchJob( item3, this ); + QVERIFY( fjob2->exec() ); + + // item3 should have the same modification time as item. + item3 = fjob2->items().first(); + QCOMPARE( item3.modificationTime(), item.modificationTime() ); + + // Clean up + ItemDeleteJob *idjob = new ItemDeleteJob( item, this ); + QVERIFY( idjob->exec() ); +} #include "itemstoretest.moc" Index: tests/itemstoretest.h =================================================================== --- tests/itemstoretest.h (revision 836665) +++ tests/itemstoretest.h (working copy) @@ -38,6 +38,7 @@ void testMultiPart(); void testPartRemove(); void testRevisionCheck(); + void testModificationTime(); }; #endif Index: item.cpp =================================================================== --- item.cpp (revision 836665) +++ item.cpp (working copy) @@ -91,6 +91,16 @@ d->mFlagsOverwritten = true; } +QDateTime Item::modificationTime() const +{ + return d_func()->mModificationTime; +} + +void Item::setModificationTime( const QDateTime &datetime ) +{ + d_func()->mModificationTime = datetime; +} + bool Item::hasFlag( const QByteArray & name ) const { return d_func()->mFlags.contains( name ); Index: itemfetchjob.cpp =================================================================== --- itemfetchjob.cpp (revision 836665) +++ itemfetchjob.cpp (working copy) @@ -33,6 +33,7 @@ #include +#include #include #include @@ -167,6 +168,7 @@ // create a new item object Item::Id uid = -1; int rev = -1; + QDateTime datetime; QString rid; QString mimeType; @@ -178,20 +180,23 @@ uid = value.toLongLong(); else if ( key == "REV" ) rev = value.toInt(); + else if ( key == "DATETIME" ) + ImapParser::parseDateTime( value, datetime ); else if ( key == "REMOTEID" ) rid = QString::fromUtf8( value ); else if ( key == "MIMETYPE" ) mimeType = QString::fromLatin1( value ); } - if ( uid < 0 || rev < 0 || mimeType.isEmpty() ) { - kWarning( 5250 ) << "Broken fetch response: UID, RID, REV or MIMETYPE missing!"; + if ( uid < 0 || rev < 0 || datetime.isNull() || mimeType.isEmpty() ) { + kWarning( 5250 ) << "Broken fetch response: UID, RID, REV, DATETIME or MIMETYPE missing!"; return; } Item item( uid ); item.setRemoteId( rid ); item.setRevision( rev ); + item.setModificationTime( datetime ); item.setMimeType( mimeType ); if ( !item.isValid() ) return; @@ -200,7 +205,7 @@ for ( int i = 0; i < fetchResponse.count() - 1; i += 2 ) { const QByteArray key = fetchResponse.value( i ); // skip stuff we dealt with already - if ( key == "UID" || key == "REV" || key == "REMOTEID" || key == "MIMETYPE" ) + if ( key == "UID" || key == "REV" || key == "DATETIME" || key == "REMOTEID" || key == "MIMETYPE" ) continue; // flags if ( key == "FLAGS" ) { Index: item.h =================================================================== --- item.h (revision 836665) +++ item.h (working copy) @@ -121,6 +121,19 @@ Flags flags() const; /** + * Returns the timestamp of the last modification of this item. + */ + QDateTime modificationTime() const; + + /** + * Sets the timestamp of the last modification of this item. + * + * @note Do not modify this value from within an application, + * it is updated automatically by the revision checking functions. + */ + void setModificationTime( const QDateTime &datetime ); + + /** * Returns whether the flag with the given @p name is * set in the item. */ Index: item_p.h =================================================================== --- item_p.h (revision 836665) +++ item_p.h (working copy) @@ -20,6 +20,7 @@ #ifndef AKONADI_ITEM_P_H #define AKONADI_ITEM_P_H +#include #include #include "entity_p.h" @@ -37,6 +38,7 @@ : EntityPrivate( id ), mPayload( 0 ), mRevision( -1 ), + mModificationTime(), mFlagsOverwritten( false ) { } @@ -46,6 +48,7 @@ { mFlags = other.mFlags; mRevision = other.mRevision; + mModificationTime = other.mModificationTime; mMimeType = other.mMimeType; if ( other.mPayload ) mPayload = other.mPayload->clone(); @@ -73,6 +76,7 @@ PayloadBase* mPayload; Item::Flags mFlags; int mRevision; + QDateTime mModificationTime; QString mMimeType; Item::Flags mAddedFlags; Item::Flags mDeletedFlags; --Boundary-00=_l3ihIj9Z/UijXZk Content-Type: text/x-diff; charset="utf-8"; name="kdesupport-akonadi.dif" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="kdesupport-akonadi.dif" Index: server/src/handler/append.cpp =================================================================== --- server/src/handler/append.cpp (revision 836660) +++ server/src/handler/append.cpp (working copy) @@ -116,8 +116,14 @@ if ( !mimeType.isValid() ) { return failureResponse( QString::fromLatin1( "Unknown mime type '%1'.").arg( QString::fromLatin1( mt ) ) ); } + + if( m_dateTime == QDateTime() ) { + m_dateTime = QDateTime::currentDateTime(); + } + PimItem item; item.setRev( 0 ); + item.setDatetime( m_dateTime ); // wrap data into a part Part part; @@ -144,9 +150,16 @@ if ( !transaction.commit() ) return failureResponse( "Unable to commit transaction." ); + QString datetime = item.datetime().toString( QLatin1String( "dd-MMM-yyyy hh:mm:ss" ) ); + datetime.append( QLatin1String( " +0000" ) ); + + QByteArray res( "[UIDNEXT " + QByteArray::number( item.id() ) + " " ); + res.append( "DATETIME " + ImapParser::quote( datetime.toUtf8() ) ); + res.append( ']' ); + response.setTag( tag() ); response.setUserDefined(); - response.setString( "[UIDNEXT " + QByteArray::number( item.id() ) + ']' ); + response.setString( res ); emit responseAvailable( response ); response.setSuccess(); Index: server/src/handler/store.cpp =================================================================== --- server/src/handler/store.cpp (revision 836660) +++ server/src/handler/store.cpp (working copy) @@ -85,6 +85,9 @@ else if ( buffer == "NOREV" ) revCheck = false; + // Set the same modification time for each item. + QDateTime modificationtime = QDateTime::currentDateTime(); + for ( int i = 0; i < pimItems.count(); ++i ) { if ( revCheck ) { // check if revision number of given items and their database equivalents match @@ -95,7 +98,7 @@ // update item revision pimItems[ i ].setRev( pimItems[ i ].rev() + 1 ); - pimItems[ i ].setDatetime( QDateTime::currentDateTime() ); + pimItems[ i ].setDatetime( modificationtime ); if ( !pimItems[ i ].update() ) { return failureResponse( "Unable to update item revision" ); } @@ -210,9 +213,12 @@ if ( !transaction.commit() ) return failureResponse( "Cannot commit transaction." ); + QString datetime = modificationtime.toString( QLatin1String( "dd-MMM-yyyy hh:mm:ss" ) ); + datetime.append( QLatin1String( " +0000" ) ); + response.setTag( tag() ); response.setSuccess(); - response.setString( "STORE completed" ); + response.setString( "DATETIME " + ImapParser::quote( datetime.toUtf8() ) + " STORE completed" ); emit responseAvailable( response ); deleteLater(); Index: server/src/handler/fetch.cpp =================================================================== --- server/src/handler/fetch.cpp (revision 836660) +++ server/src/handler/fetch.cpp (working copy) @@ -50,9 +50,10 @@ static const int itemQueryIdColumn = 0; static const int itemQueryRevColumn = 1; -static const int itemQueryRidColumn = 2; -static const int itemQueryMimeTypeColumn = 3; -static const int itemQueryResouceColumn = 4; +static const int itemQueryDatetimeColumn = 2; +static const int itemQueryRidColumn = 3; +static const int itemQueryMimeTypeColumn = 4; +static const int itemQueryResouceColumn = 5; static const int partQueryIdColumn = 0; static const int partQueryNameColumn = 1; @@ -183,9 +184,15 @@ while ( mItemQuery.query().isValid() ) { const qint64 pimItemId = mItemQuery.query().value( itemQueryIdColumn ).toLongLong(); const int pimItemRev = mItemQuery.query().value( itemQueryRevColumn ).toInt(); + const QDateTime pimItemDatetime = mItemQuery.query().value( itemQueryDatetimeColumn ).toDateTime(); + + QString datetime = pimItemDatetime.toString( QLatin1String( "dd-MMM-yyyy hh:mm:ss" ) ); + datetime.append( QLatin1String( " +0000" ) ); + QList attributes; attributes.append( "UID " + QByteArray::number( pimItemId ) ); attributes.append( "REV " + QByteArray::number( pimItemRev ) ); + attributes.append( "DATETIME " + ImapParser::quote( datetime.toUtf8() ) ); attributes.append( "REMOTEID " + ImapParser::quote( mItemQuery.query().value( itemQueryRidColumn ).toString().toUtf8() ) ); attributes.append( "MIMETYPE " + ImapParser::quote( mItemQuery.query().value( itemQueryMimeTypeColumn ).toString().toUtf8() ) ); @@ -323,6 +330,7 @@ // make sure the columns indexes here and in the constants defined above match mItemQuery.addColumn( PimItem::idFullColumnName() ); mItemQuery.addColumn( PimItem::revFullColumnName() ); + mItemQuery.addColumn( PimItem::datetimeFullColumnName() ); mItemQuery.addColumn( PimItem::remoteIdFullColumnName() ); mItemQuery.addColumn( MimeType::nameFullColumnName() ); mItemQuery.addColumn( Resource::nameFullColumnName() ); --Boundary-00=_l3ihIj9Z/UijXZk Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ KDE PIM mailing list kde-pim@kde.org https://mail.kde.org/mailman/listinfo/kde-pim KDE PIM home page at http://pim.kde.org/ --Boundary-00=_l3ihIj9Z/UijXZk--