// Copyright (c) 1998-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 <e32std.h>
#include "MSVSTD.H"
#include "MSVSTORE.H"
#include "MSVIDS.H"
#include "MSVENTRY.H"
#include "MSVSERV.H"
#include "MSVLOPS.H"
#include "MSVMOVE.H"
#include "MSVCOPY.H"
#include "MSVDELET.H"
#include "MSVPANIC.H"
#include <tmsvsystemprogress.h>
#include "msvindexadapter.h"
//**********************************
// CMsvLocalOperation
//**********************************
CMsvLocalOperation::CMsvLocalOperation(const RMessage2& aMessage, TMsvOp aId, CMsvServer& aMsvServer)
: CMsvServerOperation(aMessage, aId, KUidMsvLocalServiceMtm, KMsvLocalServiceIndexEntryId, -1), iMsvServer(aMsvServer)
{
__DECLARE_NAME(_S("CMsvLocalOperation"));
}
const TDesC8& CMsvLocalOperation::Progress()
{
return iProgress;
}
/**
Obtain the local progress information
@param aOutSysProg The TMsvSystemProgress structure to be populated
@return system wide error code
*/
TInt CMsvLocalOperation::SystemProgress(TMsvSystemProgress& aSysProgress)
{
aSysProgress.iErrorCode = iProgress().iError;
aSysProgress.iId = iProgress().iId;
return KErrNone; // This method will not fail
}
//**********************************
// CMsvLocalCopyOperation
//**********************************
CMsvLocalCopyOperation::CMsvLocalCopyOperation(const RMessage2& aMessage, TMsvOp aId, CMsvEntrySelection* aSelection, TMsvId aTarget, CMsvServer& aMsvServer)
: CMsvLocalOperation(aMessage, aId, aMsvServer), iOrigEntries(aSelection), iTarget(aTarget)
//
//
//
{
__DECLARE_NAME(_S("CMsvLocalCopyOperation"));
// set up the progress
iProgress().iType = TMsvLocalOperationProgress::ELocalCopy;
iProgress().iTotalNumberOfEntries = iOrigEntries->Count();
iProgress().iNumberRemaining = iProgress().iTotalNumberOfEntries;
CActiveScheduler::Add(this);
}
CMsvLocalCopyOperation::~CMsvLocalCopyOperation()
//
//
//
{
Cancel();
delete iOrigEntries;
delete iNewEntries;
delete iCopy;
}
void CMsvLocalCopyOperation::DoCancel()
//
//
//
{
iCopy->Cancel();
iProgress().iError = KErrCancel;
Completed();
}
void CMsvLocalCopyOperation::RunL()
//
//
//
{
// sort out descendent copying
if (iDescendentCopying && iDescendentId == KMsvNullIndexEntryId)
iDescendentId = iCopy->NewEntryId();
// record details of the previous move
iProgress().iNumberRemaining--;
if (iStatus!=KErrNone)
{
iProgress().iNumberFailed++;
iProgress().iError=iStatus.Int();
}
else
{
iNewEntries->AppendL(iCopy->NewEntryId()); // will not fail, as space has been reserved
iProgress().iNumberCompleted++;
}
if (iIndex < iOrigEntries->Count())
{
// start the next move
TInt error = CopyNextEntry();
if (error==KErrNone)
return; // doing another move
__ASSERT_DEBUG(iProgress().iNumberRemaining==0, PanicServer(EMsvCopyingOperationInvariant));
}
// complete the operation
Completed();
}
void CMsvLocalCopyOperation::StartL()
//
//
//
{
iNewEntries = new(ELeave) CMsvEntrySelection;
iCopy = CMsvCopy::NewL(iMsvServer);
iIndex = 0;
iNewEntries->SetReserveL(iOrigEntries->Count());
iDescendentId = KMsvNullIndexEntryId;
// check for copying into a descedent
TInt count = iOrigEntries->Count();
while (count--)
{
TMsvId id = iOrigEntries->At(count);
iDescendentCopying = (id==iTarget);
if (!iDescendentCopying)
{
iMsvServer.IndexAdapter().IsADescendent(id, iTarget, iDescendentCopying); // error ignored
}
if (iDescendentCopying)
{
// has to be done first
iOrigEntries->Delete(count);
iOrigEntries->InsertL(0, id);
break;
}
}
TInt error = CopyNextEntry();
if (error==KErrNone)
SetState(EMsvOperationRunning);
else
{
iProgress().iNumberFailed = iProgress().iTotalNumberOfEntries;
iProgress().iNumberRemaining = 0;
iProgress().iError=error;
Completed();
}
}
TInt CMsvLocalCopyOperation::CopyNextEntry()
//
//
//
{
FOREVER
{
TRAPD(error, iCopy->StartL(iOrigEntries->At(iIndex++), iTarget, iStatus, iDescendentCopying));
if (error)
{
iProgress().iNumberRemaining--;
iProgress().iNumberFailed++;
iProgress().iError=error;
if (iIndex==iOrigEntries->Count())
return error;
}
else
{
SetActive();
break;
}
}
return KErrNone;
}
void CMsvLocalCopyOperation::Completed()
//
//
//
{
SetState(EMsvOperationCompleted);
if (iNewEntries->Count())
{
iProgress().iId = iNewEntries->At(0);
iMsvServer.NotifyChanged(EMsvEntriesCreated, *iNewEntries, iTarget);
}
iMessage.Complete(KErrNone);
}
//**********************************
// CMsvLocalMoveOperation
//**********************************
CMsvLocalMoveOperation::CMsvLocalMoveOperation(const RMessage2& aMessage, TMsvOp aId, CMsvEntrySelection* aSelection, TMsvId aTarget, CMsvServer& aMsvServer)
: CMsvLocalOperation(aMessage, aId, aMsvServer), iTarget(aTarget), iParent(KMsvNullIndexEntryId), iOrigEntries(aSelection)
{
__DECLARE_NAME(_S("CMsvLocalMoveOperation"));
// set up the progress
iProgress().iType = TMsvLocalOperationProgress::ELocalMove;
iProgress().iTotalNumberOfEntries = iOrigEntries->Count();
iProgress().iNumberRemaining = iProgress().iTotalNumberOfEntries;
CActiveScheduler::Add(this);
}
CMsvLocalMoveOperation::~CMsvLocalMoveOperation()
{
Cancel();
delete iOrigEntries;
delete iMove;
}
void CMsvLocalMoveOperation::DoCancel()
{
iMove->Cancel();
iOrigEntries->Delete(0,iNextEntry);
iProgress().iError = KErrCancel;
Completed();
}
void CMsvLocalMoveOperation::RunL()
//
//
//
{
// record details of the previous move
iProgress().iNumberRemaining--;
if (iStatus!=KErrNone)
{
iProgress().iNumberFailed++;
iProgress().iError=iStatus.Int();
iOrigEntries->Delete(iNextEntry);
}
else
iProgress().iNumberCompleted++;
TInt error=KErrNone;
if (iNextEntry) // will be zero when completed
{
// start the next move
error = MoveNextEntry();
if (error==KErrNone)
return; // doing another move
__ASSERT_DEBUG(iProgress().iNumberRemaining==0, PanicServer(EMsvMovingOperationInvariant));
}
// complete the operation
Completed();
}
void CMsvLocalMoveOperation::Completed()
//
//
//
{
SetState(EMsvOperationCompleted);
if (iOrigEntries->Count())
{
iProgress().iId = iOrigEntries->At(0);
iMsvServer.NotifyChanged(EMsvEntriesMoved, *iOrigEntries, iTarget, iParent);
}
iMessage.Complete(KErrNone);
}
void CMsvLocalMoveOperation::StartFailed(TInt aError)
//
//
//
{
iProgress().iNumberFailed = iProgress().iTotalNumberOfEntries;
iProgress().iNumberRemaining = 0;
iProgress().iError=aError;
iOrigEntries->Reset();
Completed();
}
void CMsvLocalMoveOperation::StartL()
//
//
//
{
// check if the target exists
TMsvEntry* entry;
TInt err = KErrNone;
err = iMsvServer.IndexAdapter().GetEntry(iTarget, entry);
if (err !=KErrNone)
{
StartFailed(KErrPathNotFound);
return;
}
// find the current parent
TInt count=iOrigEntries->Count();
while (count--)
{
TInt error = KErrNone;
error = iMsvServer.IndexAdapter().GetEntry(iOrigEntries->At(count), entry);
if (error ==KErrNone)
{
iParent=entry->Parent();
break;
}
}
// nothing to copy
if (count==KErrNotFound)
{
StartFailed(count);
return;
}
#if defined(_DEBUG)
// check all the entries are local
TInt dCount=iOrigEntries->Count();
while (dCount--)
{
TInt dSourceLocal;
TInt dError = KErrNone;
dError = iMsvServer.IndexAdapter().IsLocal(iOrigEntries->At(count), dSourceLocal);
__ASSERT_DEBUG(dError!=KErrNone || dSourceLocal, PanicServer(EMsvMovingLocalEntryIsRemote));
}
#endif
// start the copying
iMove = CMsvMove::NewL(iMsvServer);
iNextEntry=iOrigEntries->Count();
TInt error = MoveNextEntry();
if (error==KErrNone)
SetState(EMsvOperationRunning);
else
StartFailed(error);
}
TInt CMsvLocalMoveOperation::MoveNextEntry()
//
//
//
{
TInt error=KErrGeneral;
while (error!=KErrNone && iNextEntry)
{
iMove->Reset();
error=KErrNone;
TRAP(error, iMove->StartL(iOrigEntries->At(--iNextEntry), iTarget, iStatus));
if (error)
{
iProgress().iNumberRemaining--;
iProgress().iNumberFailed++;
iProgress().iError=error;
iOrigEntries->Delete(iNextEntry);
}
}
if (error==KErrNone)
SetActive();
return error;
}
//**********************************
// CMsvLocalDeleteOperation
//**********************************
CMsvLocalDeleteOperation::CMsvLocalDeleteOperation(const RMessage2& aMessage, TMsvOp aId, CMsvEntrySelection* aSelection, CMsvServer& aMsvServer)
: CMsvLocalOperation(aMessage, aId, aMsvServer), iSelection(aSelection)
{
__DECLARE_NAME(_S("CMsvLocalDeleteOperation"));
// set up the progress
iProgress().iType = TMsvLocalOperationProgress::ELocalDelete;
iProgress().iTotalNumberOfEntries = iSelection->Count();
iProgress().iNumberRemaining = iProgress().iTotalNumberOfEntries;
CActiveScheduler::Add(this);
}
CMsvLocalDeleteOperation::~CMsvLocalDeleteOperation()
{
Cancel();
delete iSelection;
delete iDeletedEntries;
delete iMovedEntries;
delete iDelete;
delete iWorkSelection1;
delete iWorkSelection2;
}
void CMsvLocalDeleteOperation::DoCancel()
//
//
//
{
iDelete->Cancel();
iProgress().iError = KErrCancel;
Completed();
// if the last entry was removed, update the notification selections
TRAP_IGNORE(PartialCompletionNotificationL());
}
void CMsvLocalDeleteOperation::PartialCompletionNotificationL()
//
//
//
{
TMsvId id=iSelection->At(iIndex-1);
TBool entryExists = EFalse;
entryExists = iMsvServer.IndexAdapter().EntryExists(id);
if (!entryExists)
id = iParent;
if (iWorkSelection1->Count())
{
iDeletedEntries->Reset();
iDeletedEntries->AppendL(iWorkSelection1->Back(0), iWorkSelection1->Count());
iMsvServer.NotifyChanged(EMsvEntriesDeleted, *iDeletedEntries, id);
}
if (iWorkSelection2->Count())
{
iDeletedEntries->Reset();
iMovedEntries->AppendL(iWorkSelection2->Back(0), iWorkSelection2->Count());
iMsvServer.NotifyChanged(EMsvEntriesMoved, *iMovedEntries, KMsvDeletedEntryFolderEntryId, id);
}
}
void CMsvLocalDeleteOperation::RunL()
//
// Attempts the next delete
//
{
TRAPD(leave, DoRunL());
if (leave)
{
// probably OOM so complete the operation
iProgress().iError = leave;
Completed();
}
}
void CMsvLocalDeleteOperation::DoRunL()
//
//
//
{
// record the result of the last delete
iProgress().iNumberRemaining--;
if (iStatus.Int()==KErrNone)
{
iProgress().iNumberCompleted++;
iDeletedEntries->AppendL(iWorkSelection1->Back(0), iWorkSelection1->Count());
iMovedEntries->AppendL(iWorkSelection2->Back(0), iWorkSelection2->Count());
}
else
{
iProgress().iNumberFailed++;
if (iProgress().iError==KErrNone)
iProgress().iError = iStatus.Int();
}
// start thje next delete or complete the operation
if (iProgress().iNumberRemaining)
{
iWorkSelection1->Reset();
iWorkSelection2->Reset();
iDelete->StartL(iSelection->At(iIndex++), *iWorkSelection1, *iWorkSelection2, iStatus);
SetActive();
}
else
{
__ASSERT_DEBUG(iIndex==iSelection->Count(), PanicServer(EMsvLocalDeletionMisCount));
Completed();
}
}
void CMsvLocalDeleteOperation::Completed()
//
// The operation has completed
//
{
/**
Added code to commit transaction for bulk deletion.
*/
TRAP_IGNORE(iMsvServer.IndexAdapter().GetDbAdapter()->CommitTransactionL());
// notify server of any deletions or moves to the deleted folder
if (iDeletedEntries->Count())
iMsvServer.NotifyChanged(EMsvEntriesDeleted, *iDeletedEntries, iParent);
if (iMovedEntries->Count())
iMsvServer.NotifyChanged(EMsvEntriesMoved, *iMovedEntries, KMsvDeletedEntryFolderEntryId, iParent);
// complete the request
SetState(EMsvOperationCompleted);
iMessage.Complete(KErrNone);
}
void CMsvLocalDeleteOperation::StartL()
{
// reserve space so we don't manage to delete the entries but run
// out of memory when trying to report the fact.
iDeletedEntries = new(ELeave)CMsvEntrySelection;
iDeletedEntries->SetReserveL(iSelection->Count());
iMovedEntries = new(ELeave)CMsvEntrySelection;
iMovedEntries->SetReserveL(iSelection->Count());
iWorkSelection1 = new(ELeave)CMsvEntrySelection;
iWorkSelection2 = new(ELeave)CMsvEntrySelection;
iDelete = CMsvDelete::NewL(iMsvServer);
// find the parent
TInt count=iSelection->Count();
while (count--)
{
TMsvEntry* entry;
TInt error = KErrNone;
error = iMsvServer.IndexAdapter().GetEntry(iSelection->At(count),entry);
if (error)
{
iSelection->Delete(count);
iProgress().iNumberRemaining--;
iProgress().iNumberCompleted++;
}
else
iParent = entry->Parent();
}
if (iSelection->Count())
{
// start deleting the first entry
iDelete->StartL(iSelection->At(iIndex++), *iWorkSelection1, *iWorkSelection2, iStatus);
SetActive();
SetState(EMsvOperationRunning);
}
else
Completed();
}
//**********************************
// CMsvLocalChangeOperation
//**********************************
CMsvLocalChangeOperation::CMsvLocalChangeOperation(const RMessage2& aMessage, TMsvOp aId, const TMsvEntry& aEntry, CMsvServer& aMsvServer)
: CMsvLocalOperation(aMessage, aId, aMsvServer), iEntry(aEntry)
{
__DECLARE_NAME(_S("CMsvLocalChangeOperation"));
// set up the progress
iProgress().iType = TMsvLocalOperationProgress::ELocalChanged;
iProgress().iTotalNumberOfEntries = 1;
iProgress().iId = iEntry.Id();
CActiveScheduler::Add(this);
}
CMsvLocalChangeOperation::~CMsvLocalChangeOperation()
//
//
//
{
Cancel();
delete iDelete;
delete iWorkSelection1;
delete iWorkSelection2;
}
void CMsvLocalChangeOperation::DoCancel()
//
//
//
{
__ASSERT_DEBUG(iDelete!=NULL, PanicServer(EMsvChangeEntryBadState));
iDelete->Cancel();
iProgress().iError = KErrCancel;
Completed();
}
void CMsvLocalChangeOperation::RunL()
//
//
//
{
if (iStatus.Int()==KErrNone)
{
iProgress().iNumberCompleted++;
}
else
{
iProgress().iNumberFailed++;
iProgress().iError = iStatus.Int();
}
Completed();
}
void CMsvLocalChangeOperation::StartL(TSecureId aOwnerId, TBool aForcedUpdate)
//
//
//
{
iId = iEntry.Id();
iParent = iEntry.Parent();
// check if this is actually a deletion
if (iEntry.Deleted() && iEntry.PcSyncCount()==0)
{
iDelete = CMsvDelete::NewL(iMsvServer);
iWorkSelection1 = new(ELeave)CMsvEntrySelection;
iWorkSelection2 = new(ELeave)CMsvEntrySelection;
iDelete->StartL(iEntry.Id(), *iWorkSelection1, *iWorkSelection2, iStatus, ETrue);
SetActive();
return;
}
// otherwise just changing it
TInt error = KErrNone;
error = iMsvServer.IndexAdapter().LockEntry(iId);
if (error==KErrNone)
{
error = iMsvServer.ChangeEntry(iEntry, aOwnerId, aForcedUpdate);
iMsvServer.IndexAdapter().ReleaseEntry(iId); // error ignored
}
if (error==KErrNone)
iProgress().iNumberCompleted++;
else
{
iProgress().iNumberFailed++;
iProgress().iError = error;
}
Completed();
}
void CMsvLocalChangeOperation::Completed()
//
//
//
{
if (iProgress().iError==KErrNone)
iMsvServer.NotifyChanged(iDelete==NULL ? EMsvEntriesChanged : EMsvEntriesDeleted, iId, iParent);
SetState(EMsvOperationCompleted);
iMessage.Complete(KErrNone);
}
//**********************************
// CMsvLocalCreateOperation
//**********************************
CMsvLocalCreateOperation::CMsvLocalCreateOperation(const RMessage2& aMessage, TMsvOp aId, const TMsvEntry& aEntry, CMsvServer& aMsvServer)
: CMsvLocalOperation(aMessage, aId, aMsvServer), iEntry(aEntry)
{
__DECLARE_NAME(_S("CMsvLocalCreateOperation"));
// set up the progress
iProgress().iType = TMsvLocalOperationProgress::ELocalNew;
iProgress().iTotalNumberOfEntries = 1;
CActiveScheduler::Add(this);
}
CMsvLocalCreateOperation::~CMsvLocalCreateOperation()
{}
void CMsvLocalCreateOperation::DoCancel()
{}
void CMsvLocalCreateOperation::RunL()
{}
void CMsvLocalCreateOperation::Start(TSecureId aOwnerId)
{
TMsvEntry entry = iEntry;
TInt error = iMsvServer.AddEntry(entry, aOwnerId, ETrue);
if (error)
{
iProgress().iNumberFailed++;
iProgress().iError = error;
}
else
{
iProgress().iNumberCompleted++;
iProgress().iId = entry.Id();
iMsvServer.NotifyChanged(EMsvEntriesCreated, entry.Id(), entry.Parent());
}
SetState(EMsvOperationCompleted);
iMessage.Complete(KErrNone);
}
//**********************************
// CMsvChangeDriveOperation
//**********************************
CMsvChangeDriveOperation::CMsvChangeDriveOperation(const RMessage2& aMessage, TMsvOp aId, TInt aDrive, CMsvServer& aServer)
: CMsvServerOperation(aMessage, aId, KUidMsvLocalServiceMtm, KMsvLocalServiceIndexEntryId, -1), iDrive(aDrive), iServer(aServer)
{
CActiveScheduler::Add(this);
}
CMsvChangeDriveOperation::~CMsvChangeDriveOperation()
{
Cancel();
}
const TDesC8& CMsvChangeDriveOperation::Progress()
{
if (iServer.NewContext())
iProgress() = iServer.NewContext()->Progress();
return iProgress;
}
void CMsvChangeDriveOperation::DoCancel()
{
if (iServer.NewContext())
iServer.NewContext()->Cancel();
iProgress().iError = KErrCancel;
Completed();
}
void CMsvChangeDriveOperation::RunL()
{
Completed();
}
void CMsvChangeDriveOperation::Completed()
{
// Get progress
if (iServer.NewContext())
{
iProgress() = iServer.NewContext()->Progress();
// If an error occurs we have to delete the new context
iServer.DeleteNewContext();
}
else
iProgress() = iServer.Context().Progress();
SetState(EMsvOperationCompleted);
iMessage.Complete(KErrNone);
}
TInt CMsvChangeDriveOperation::Start()
{
TInt error = iServer.ChangeDrive(iDrive, &iStatus);
if (!error)
SetActive();
return error;
}