diff -r 000000000000 -r f979ecb2b13e pimappservices/calendar/server/src/agsattachmentindex.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pimappservices/calendar/server/src/agsattachmentindex.cpp Tue Feb 02 10:12:19 2010 +0200 @@ -0,0 +1,473 @@ +// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// + +#include "agsattachmentindex.h" +#include "agmentry.h" +#include "agmpanic.h" +#include "agsfilemanager.h" +#include "agmdebug.h" + +#include + +// CAgnAttachmentIndexItem // + +// Create a new attachment index item for a given attachment and the entry that owns it +CAgnAttachmentIndexItem* CAgnAttachmentIndexItem::NewL(const CAgnAttachmentFile& aAttachment, TCalLocalUid aLocalUid) + { + CAgnAttachmentIndexItem* self = new (ELeave) CAgnAttachmentIndexItem(aAttachment); + CleanupStack::PushL(self); + self->ConstructL(aAttachment, aLocalUid); + CleanupStack::Pop(self); + return self; + } + +// Create a new attachment index from a read stream +CAgnAttachmentIndexItem* CAgnAttachmentIndexItem::NewL(RReadStream& aReadStream) + { + CAgnAttachmentIndexItem* self = new (ELeave) CAgnAttachmentIndexItem(); + CleanupStack::PushL(self); + self->InternalizeL(aReadStream); + CleanupStack::Pop(self); + return self; + } + + +// Create a new attachment index item for a given attachment +CAgnAttachmentIndexItem::CAgnAttachmentIndexItem(const CAgnAttachmentFile& aAttachment) : + iSize(aAttachment.Size()), + iLastModifiedDateUtc(aAttachment.LastModifiedTimeUtc()), + iUid(aAttachment.Uid()) + { + } + +CAgnAttachmentIndexItem::CAgnAttachmentIndexItem() + { + } + +void CAgnAttachmentIndexItem::ConstructL(const CAgnAttachmentFile& aAttachment, TCalLocalUid aLocalUid) + { + iEntries.AppendL(aLocalUid); + iFileName = aAttachment.FileName().AllocL(); + } + +CAgnAttachmentIndexItem::~CAgnAttachmentIndexItem() + { + delete iFileName; + iEntries.Reset(); + } + +TInt CAgnAttachmentIndexItem::Size() const + { + return iSize; + } + +void CAgnAttachmentIndexItem::SetFileName(HBufC* aFileName) + { + delete iFileName; + iFileName = aFileName; + } + +const TTime& CAgnAttachmentIndexItem::LastModifiedDateUtc() const + { + return iLastModifiedDateUtc; + } + +const TDesC& CAgnAttachmentIndexItem::FileName() const + { + if (iFileName) + { + return *iFileName; + } + return KNullDesC; + } + +void CAgnAttachmentIndexItem::InternalizeL(RReadStream& aReadStream) + { + iSize = aReadStream.ReadInt32L(); + + TInt64 time64; + aReadStream >> time64; + TTime temptime(time64); + iLastModifiedDateUtc = temptime; + + iFileName = HBufC::NewL(aReadStream, KMaxTInt); + + TUint32 count = aReadStream.ReadUint32L(); + for (TUint32 i = 0; i < count; ++i) + { + TCalLocalUid localid = static_cast(aReadStream.ReadUint32L()); + iEntries.Append(localid); + } + + iUid = static_cast(aReadStream.ReadUint32L()); + } + +void CAgnAttachmentIndexItem::ExternalizeL(RWriteStream& aWriteStream) const + { + aWriteStream.WriteInt32L(iSize); + + TInt64 time64 = iLastModifiedDateUtc.Int64(); + aWriteStream << time64; + + aWriteStream << *iFileName; + + TUint32 count = iEntries.Count(); + aWriteStream.WriteUint32L(count); + for (TUint32 i=0; i < count; ++i) + { + aWriteStream.WriteUint32L(iEntries[i]); + } + + aWriteStream.WriteUint32L(iUid); + } + + +// Return the array of entries that contain this attachment. +// Multiple entries owning the same attachment can only occur if an entry is copied. +const RArray& CAgnAttachmentIndexItem::Entries() const + { + return iEntries; + } + +TCalAttachmentUid CAgnAttachmentIndexItem::Uid() const + { + return iUid; + } + +// Called when another entry is added with the same attachment +void CAgnAttachmentIndexItem::AddEntryL(TCalLocalUid aLocalUid) + { + // Don't allow duplicate local UIDs. This would only happen if an entry was associated with an attachment more than once + // which is invalid anyway. + if (iEntries.Find(aLocalUid) == KErrNotFound) + { + iEntries.AppendL(aLocalUid); + } + } + +// Called when an entry containing this attachment has been deleted +void CAgnAttachmentIndexItem::DeleteEntry(TCalLocalUid aLocalUid) + { + TInt pos = iEntries.Find(aLocalUid); + if (pos != KErrNotFound) + { + iEntries.Remove(pos); + } + } + +// CAgnAttachmentIndex // +void CAgnAttachmentIndex::InternalizeL(RReadStream& aReadStream) + { + TUint32 count = aReadStream.ReadUint32L(); + for (TUint32 i=0; i < count; ++i) + { + CAgnAttachmentIndexItem* item = CAgnAttachmentIndexItem::NewL(aReadStream); + iIndex.Append(item); + } + } + + +void CAgnAttachmentIndex::ExternalizeL(RWriteStream& aWriteStream) const + { + TUint32 count = iIndex.Count(); + aWriteStream.WriteUint32L(count); + for (TUint32 i=0; i < count; ++i) + { + iIndex[i]->ExternalizeL(aWriteStream); + } + + } + + +CAgnAttachmentIndex::CAgnAttachmentIndex() + { + } + +CAgnAttachmentIndex::~CAgnAttachmentIndex() + { + delete iFileRollbackArray; + Reset(); + } + +void CAgnAttachmentIndex::Reset() + { + iIndex.ResetAndDestroy(); + } + +// add an entry's attachments to the index +void CAgnAttachmentIndex::AddEntryL(CAgnEntry& aEntry) + { + const TInt KAttachCount = aEntry.AttachmentCount(); + for (TInt ii = 0; ii < KAttachCount; ++ii) + { + CAgnAttachment& attach = aEntry.Attachment(ii); + if (attach.Uid() && attach.Type() == CCalContent::EDispositionInline) + { + TInt index = AttachmentIndex(attach.Uid()); + CAgnAttachmentFile* attachFile = static_cast(&attach); + // Add a new attach item to the attach index if the attachment uid is not found from the index + //Otherwise, there is existing attachment already in the index. Whether should the entry share or update the attach item depends on: + // 1. Update the attach item if the entry has the same entry uid as the one in the index (In this case, the entry is to be updated) + // 2. Add an attach item if the drive name of the attachment of the entry is different from the one in the index + // 3. Share the attachment if the drive name of the attachment of the entry is the same as the one in the index + + TBool addNewItem = ETrue; + TBool shareItem = EFalse; + + if (index >= 0) + {// An attacment with the same attach uid has been found from the attach index + const TDesC& filename = iIndex[index]->FileName(); + TDriveName oldDrive = filename.Left(2); + TDriveName newDrive = attachFile->Drive(); + TBool isSameDrive = (oldDrive.CompareF(newDrive) == 0); + const RArray entries = iIndex[index]->Entries(); + TInt entryCount = entries.Count();//Those entries have shared the same attachments. + TInt jj=entryCount; + for (jj=0; jjDes().Replace(0,2,newDrive); + iIndex[index]->SetFileName(newfilename); + } + break; + } + } + + if (jj == entryCount)//This is newly added entry + {//check the drive has been changed or not + if(isSameDrive)//drive is the same + { + addNewItem = EFalse;//This entry will share an exiting attachment + shareItem = ETrue; + } + } + } + + if(addNewItem && attachFile->FileName().Length() > 0) + { + CAgnAttachmentIndexItem* newItem = CAgnAttachmentIndexItem::NewL(*attachFile, aEntry.LocalUid()); + CleanupStack::PushL(newItem); + iIndex.AppendL(newItem); + CleanupStack::Pop(newItem); + } + else if (shareItem ) + {//The entry will share this attachment + iIndex[index]->AddEntryL(aEntry.LocalUid()); + } + } + } + + // see if this entry replaces an existing entry and some of the attachments are no longer present + const TInt KEntryLocalUid = aEntry.LocalUid(); + for (TInt i = iIndex.Count() - 1; i >= 0; --i) + { + // check every attachment + const CAgnAttachmentIndexItem* KAttachmentItem = iIndex[i]; + for (TInt j = 0; j < KAttachmentItem->Entries().Count(); ++j) + { + // check every entry associated with each attachment + if (KEntryLocalUid == (KAttachmentItem->Entries())[j]) + { + // If the entry being updated used to contain this attachment, check it still does + TBool attachmentFound = EFalse; + for (TInt k = 0; k < KAttachCount; ++k) + { + if (aEntry.Attachment(k).Uid() == KAttachmentItem->Uid()) + { + attachmentFound = ETrue; + break; + } + } + if ( ! attachmentFound) + { + // this entry used to be associated with this attachment but isn't any more + RemoveEntryFromAttachmentL(aEntry.LocalUid(), KAttachmentItem->Uid()); + } + } + } + } + } + +// remove an entry's attachments from the index +void CAgnAttachmentIndex::DeleteEntryL(CAgnEntry& aEntry) + { + const TInt KAttachCount = aEntry.AttachmentCount(); + for (TInt j = 0; j < KAttachCount; ++j) + { + CAgnAttachment& attach = aEntry.Attachment(j); + if (attach.Type() == CCalContent::EDispositionInline) + { + RemoveEntryFromAttachmentL(aEntry.LocalUid(), attach.Uid()); + } + } + } + +// remove a particular entry from a particular attachment in the index +void CAgnAttachmentIndex::RemoveEntryFromAttachmentL(TCalLocalUid aEntryUid, TCalAttachmentUid aAttachmentUid) + { + TInt index = AttachmentIndex(aAttachmentUid); + if (index != KErrNotFound && iIndex[index]) + { + iIndex[index]->DeleteEntry(aEntryUid); + _DBGLOG_ATTACH(AgmDebug::DebugLog("Remove Entry Attachment: Removing entry from attachment using Entry UID='%d', Attachment UID='%d'",aEntryUid,aAttachmentUid);) + if (iIndex[index]->Entries().Count() == 0) + { + // if there are no more entries with this attachment, mark this file for deletion + if (!iFileRollbackArray) + { + iFileRollbackArray = new (ELeave) CDesCArraySeg(8); + } + iFileRollbackArray->AppendL(iIndex[index]->FileName()); + delete iIndex[index]; + iIndex.Remove(index); + } + } + } + +void CAgnAttachmentIndex::RemoveAttachment(TCalAttachmentUid aUid) + { + TInt index = AttachmentIndex(aUid); + if (index != KErrNotFound) + { + _DBGLOG_ATTACH(AgmDebug::DebugLog("Remove Attachment: Removing attachment with Attachment UID='%d'", aUid);) + delete iIndex[index]; + iIndex.Remove(index); + } + } + +// delete all attachment files already marked for deletion in RemoveEntryFromAttachmentL +void CAgnAttachmentIndex::CommitL(CAgnServFile& aServFile) + { + if (iFileRollbackArray) + { + for (TInt i = 0; i < iFileRollbackArray->Count(); ++i) + { + aServFile.DeleteFileL((*iFileRollbackArray)[i]); + } + + delete iFileRollbackArray; + iFileRollbackArray = NULL; + } + } + +// cancel any file deletes +void CAgnAttachmentIndex::Rollback() + { + delete iFileRollbackArray; + iFileRollbackArray = NULL; + } + +TInt CAgnAttachmentIndex::AttachmentIndex(TCalAttachmentUid aUid) const + { + const TInt KCount = iIndex.Count(); + for (TInt i = 0; i < KCount; ++i) + { + if (iIndex[i]->Uid() == aUid) + { + return i; + } + } + return KErrNotFound; + } + +const CAgnAttachmentIndexItem* CAgnAttachmentIndex::Attachment(TCalAttachmentUid aUid) const + { + _DBGLOG_ATTACH(AgmDebug::DebugLog("Attachment: Getting attachment using Uid - %d",aUid);) + + TInt index = AttachmentIndex(aUid); + if (index != KErrNotFound) + { + return iIndex[index]; + } + return NULL; + } + +TInt CAgnAttachmentIndex::Count() const + { + return iIndex.Count(); + } + +typedef TInt (*SortFunctionPtr)(const CAgnAttachmentIndexItem&, const CAgnAttachmentIndexItem&); + +// return a new array of pointers to attachments, ordered by size of last modified date +void CAgnAttachmentIndex::GetSortedIndexL(CCalAttachmentManager::TSortOrder aSortOrder, RPointerArray& aAttachments) const + { + SortFunctionPtr sortFunction = NULL; + switch (aSortOrder) + { + case CCalAttachmentManager::ESortBySizeLargestFirst: + sortFunction = CAgnAttachmentIndex::SortBySizeLargestFirst; + break; + case CCalAttachmentManager::ESortByDateModifiedNewestFirst: + sortFunction = CAgnAttachmentIndex::SortByDateModifiedNewestFirst; + break; + case CCalAttachmentManager::ESortByDateModifiedOldestFirst: + sortFunction = CAgnAttachmentIndex::SortByDateModifiedOldestFirst; + break; + default: + Panic(EAgmErrInvalidAttachmentSortOrder); + } + TLinearOrder order(*sortFunction); + + const TInt KCount = iIndex.Count(); + for (TInt i = 0; i < KCount; ++i) + { + aAttachments.InsertInOrderAllowRepeatsL(iIndex[i], order); + } + } + +/*static*/ TInt CAgnAttachmentIndex::SortBySizeLargestFirst(const CAgnAttachmentIndexItem& aLeft, const CAgnAttachmentIndexItem& aRight) + { + return aRight.Size() - aLeft.Size(); + } + +/*static*/ TInt CAgnAttachmentIndex::SortByDateModifiedNewestFirst(const CAgnAttachmentIndexItem& aLeft, const CAgnAttachmentIndexItem& aRight) + { + if (aRight.LastModifiedDateUtc() > aLeft.LastModifiedDateUtc()) + { + return 1; + } + else if (aRight.LastModifiedDateUtc() == aLeft.LastModifiedDateUtc()) + { + return 0; + } + return -1; + } + +/*static*/ TInt CAgnAttachmentIndex::SortByDateModifiedOldestFirst(const CAgnAttachmentIndexItem& aLeft, const CAgnAttachmentIndexItem& aRight) + { + // return opposite value of SortByDateModifiedNewestFirst + return ( - SortByDateModifiedNewestFirst(aLeft, aRight)); + } + +const TDesC& CAgnAttachmentIndex::FileName(TCalAttachmentUid aUid) + { + // Get the file name for given attachment uid. Return KNullDesC if it the attachment with that uid is not found + + TInt index = AttachmentIndex(aUid); + + if (index >= 0) + { + return iIndex[index]->FileName(); + } + + return KNullDesC(); + }