messagingfw/scheduledsendmtm/test/unit/src/t_schsendutils.cpp
changeset 0 8e480a14352b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/messagingfw/scheduledsendmtm/test/unit/src/t_schsendutils.cpp	Mon Jan 18 20:36:02 2010 +0200
@@ -0,0 +1,769 @@
+// Copyright (c) 1999-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 "t_schsendutils.h"
+#include <msvstd.h>
+#include <msvids.h>
+#include <msvuids.h>
+#include <msvschedulesettings.h>
+#include <csch_cli.h>
+#include <msvschedulepackage.h>
+#include <msvoffpeaktime.h>
+
+EXPORT_C CSchSendTestUtils::CSchSendTestUtils(RTest& aTest)
+: CMsvTestUtils(aTest)
+	{
+	}
+
+EXPORT_C void CSchSendTestUtils::InstallMtmGroupsL()
+	{
+	}
+
+EXPORT_C void CSchSendTestUtils::CreateServerMtmRegsL()
+	{
+//CreateServerMtmRegL(KPigeonMtmUid, _L("Pig"), KUidMsvMtmServerDLL, KUidMsvMtmClientDLL, TMsvTestDllInfo(KUidMsvMtmUiDLL,2), TMsvTestDllInfo(KUidMsvMtmUiDLL,1), KPigeonMtmUid, KDataComponentFileName);
+	}
+
+EXPORT_C void CSchSendTestUtils::ConstructL()
+	{
+	CMsvTestUtils::ConstructL(ETuNone);
+	CleanScheduleFolderL();
+	CreateAllTestDirectories();
+	GoClientSideL();
+
+	InstallMtmGroupL(_L("c:\\system\\mtm\\pigmtmu.dat"));
+
+	iSelection = new(ELeave) CMsvEntrySelection;
+	iSchTestActive = CScheduleTestActive::NewL(*this);
+	}
+
+EXPORT_C CSchSendTestUtils::~CSchSendTestUtils()
+	{
+	delete iSchTestActive;
+	delete iSelection;
+	}
+
+EXPORT_C void CSchSendTestUtils::Panic(TInt aPanic)
+	{
+	User::Panic(_L("SchSend Test"), aPanic);
+	}
+
+EXPORT_C void CSchSendTestUtils::StartL()
+	{
+	TRAPD(err, RunAutoL());
+
+	if (err)
+		{
+		if (iCurrentTest)
+			{
+			TestFinish(iCurrentTest, err);
+			}
+
+		TestHarnessFailed(err);
+		}
+	else
+		{
+		TestHarnessCompleted();
+		}
+	}
+
+//Returns approximate difference (rounded down?) in minutes
+EXPORT_C TInt CSchSendTestUtils::DiffInMins(TTime d1, TTime d2)
+	{
+	iRTest<<d1<<d2;
+	TInt64 diffUs64 = d1.Int64() - d2.Int64();
+	TInt64 diffMins64 = diffUs64 / (1000000 * 60);
+	TInt diffMins32 = I64INT(diffMins64);
+	return diffMins32;
+	}
+
+//Returns approximate difference (rounded down?) in seconds
+EXPORT_C TInt CSchSendTestUtils::DiffInSecs(TTime d1, TTime d2)
+	{
+	iRTest<<d1<<d2;
+	TInt64 diffUs64 = d1.Int64() - d2.Int64();
+	TInt64 diffSecs64 = diffUs64 / (1000000);
+	TInt diffSecs32 = I64INT(diffSecs64);
+	return diffSecs32;
+	}
+
+EXPORT_C void CSchSendTestUtils::ChangeMessageTimeL(TMsvId aMessage, TTime aTime)
+	{
+	iMsvEntry->SetEntryL(aMessage);
+	TMsvEntry entry = iMsvEntry->Entry();
+	iRTest<<entry.iDate<<aTime;
+	entry.iDate = aTime;
+
+	CMsvOperationWait* wait = CMsvOperationWait::NewLC();
+	wait->Start();
+	CMsvOperation*  opert = iMsvEntry->ChangeL(entry, wait->iStatus);
+	CleanupStack::PushL(opert);
+	CActiveScheduler::Start(); // operation complete
+	entry = iMsvEntry->Entry();
+	iRTest<<entry.iDate;
+
+	TMsvLocalOperationProgress details;
+	TPckgC<TMsvLocalOperationProgress> package(details);	
+	package.Set(opert->ProgressL());
+
+	if(wait->iStatus.Int()!=KErrNone)
+		User::Leave(wait->iStatus.Int());
+
+	//TInt err = package().iError;
+	//if(err != KErrNone);
+	//	User::Leave(package().iError);
+
+	CleanupStack::PopAndDestroy(2);//opert, wait
+	}
+
+EXPORT_C void CSchSendTestUtils::AssertL(TBool b)
+	{
+	if(!b)
+		{
+		User::Leave(KErrAbort);
+		}
+	}
+
+EXPORT_C TMsvId CSchSendTestUtils::CreateMessageLC(TMsvEntry& aEntry, TMsvId aDestFolder, TTime aSendTime, TBool aOffPeak)
+	{
+	//Make a TMsvEntry
+	iMsvEntry->SetEntryL(aDestFolder);
+	aEntry.iType = KUidMsvMessageEntry;
+	aEntry.iMtm = KSchSendTestMtmUid;
+	
+	aEntry.iServiceId = KMsvLocalServiceIndexEntryId;
+
+	aEntry.iDate = aSendTime;
+	aEntry.SetOffPeak(aOffPeak);
+
+	//Create the entry in the server
+
+	CMsvOperationWait* wait = CMsvOperationWait::NewLC();
+	wait->Start();
+	CMsvOperation*  opert = iMsvEntry->CreateL(aEntry, wait->iStatus);
+	CleanupStack::PushL(opert);
+	CActiveScheduler::Start(); // operation complete
+
+	//Find out the ID of the entry we made
+	TMsvLocalOperationProgress details;
+	TPckgC<TMsvLocalOperationProgress> package(details);	
+	package.Set(opert->ProgressL());
+
+	if(wait->iStatus.Int()!=KErrNone)
+		User::Leave(wait->iStatus.Int());
+
+	if(package().iError!=KErrNone)
+		User::Leave(package().iError);
+	
+	*(TMsvId*)&aEntry = package().iId;
+	TMsvId testMsvId = aEntry.Id();
+
+	CleanupStack::PopAndDestroy(2);//opert, wait
+	iMsvSession->CleanupEntryPushL(testMsvId);
+
+	return testMsvId;
+	}
+
+EXPORT_C void CSchSendTestUtils::DisplayAllSchedulesL(TInt& rSchCount, TInt& rSchSize)
+	{
+	Printf(_L("Displaying all Schedules:\n"));
+	rSchCount = 0;
+	rSchSize = 0;
+
+	TParse parse;
+	TFileName fileName(_L("\\system\\schedules\\")); 
+	_LIT(KCDrive, "C:");
+	parse.Set(fileName, &KCDrive, NULL);
+
+	CDir* entryList;
+	TPtrC drive(parse.DriveAndPath());
+	TInt err = iFs.GetDir(drive, KEntryAttNormal, ESortNone, entryList);
+	
+	if (err)
+		{
+		Printf(_L("\tiFs.GetDir(%S) returned %d\n"), &drive, err);
+		return;
+		}
+
+	CleanupStack::PushL(entryList);
+	
+	TInt count = entryList->Count();
+
+	while (count--)
+		{
+		TEntry entry((*entryList)[count]);
+		rSchSize += entry.iSize;
+		}
+
+	Printf(_L("\tFiles in %S have total size %d\n"), &drive, rSchSize);
+
+	CleanupStack::PopAndDestroy(entryList);
+
+	RScheduler sch;
+	err = sch.Connect();
+
+	if (err)
+		{
+		Printf(_L("\tRScheduler::Connect() returned %d\n"), err);
+		return;
+		}
+	
+	CleanupClosePushL(sch);
+
+	IMPORT_C TInt GetScheduleL(const TInt aScheduleHandle, TScheduleState& aState, 
+			CArrayFixFlat<TScheduleEntryInfo>& aEntries, CArrayFixFlat<TTaskInfo>& aTasks, TTime& aDueTime);
+
+	CArrayFixFlat<TSchedulerItemRef>* schRefArray = new (ELeave) CArrayFixFlat<TSchedulerItemRef>(10);
+	CleanupStack::PushL(schRefArray);
+
+	CArrayFixFlat<TScheduleEntryInfo>* schEntries = new (ELeave) CArrayFixFlat<TScheduleEntryInfo>(10);
+	CleanupStack::PushL(schEntries);
+
+	CArrayFixFlat<TTaskInfo>* schTasks = new (ELeave) CArrayFixFlat<TTaskInfo>(10);
+	CleanupStack::PushL(schTasks);
+
+	err = sch.GetScheduleRefsL(*schRefArray, EAllSchedules);
+
+	if (!err)
+		{
+		TScheduleState schState;
+		TTime schDueTime;
+		count = schRefArray->Count();
+		rSchCount = count;
+		Printf(_L("\t%d schedules in the task scheduler\n"), count);
+
+		while (count--)
+			{
+			err = sch.GetScheduleL((*schRefArray)[count].iHandle, schState, *schEntries, *schTasks, schDueTime);
+
+			if (!err)
+				{
+				TInt taskCount = schTasks->Count();
+				Printf(_L("\tSchedule %d (\"%S\") has %d tasks\n"), (*schRefArray)[count].iHandle, &(*schRefArray)[count].iName, taskCount);
+
+				while (taskCount--)
+					{
+					TTaskInfo taskInfo((*schTasks)[taskCount]);
+					TInt size;
+					err = sch.GetTaskDataSize(taskInfo.iTaskId, size);
+
+					if (!err)
+						{
+						HBufC* hBuf = HBufC::NewLC(size);
+						TPtr ptr(hBuf->Des());
+						TSchedulerItemRef schRef;
+
+						err = sch.GetTaskInfoL(taskInfo.iTaskId, taskInfo, ptr, schRef, schDueTime);
+
+						if (!err)
+							{
+							TPckgBuf<TMsvSchedulePackage> mtmBuf;
+							mtmBuf.Copy(*hBuf);
+							Printf(_L("\t\tTask %d: msvId %d, commandId %d, pollProgress %d\n"), taskInfo.iTaskId, mtmBuf().iId, mtmBuf().iCommandId, mtmBuf().iPollProgress.Int());
+							}
+						else
+							{
+							Printf(_L("\t\tRScheduler::GetTaskInfoL(%d) returned %d\n"), taskInfo.iTaskId, err);
+							}
+
+						CleanupStack::PopAndDestroy(hBuf);
+						}
+					else
+						{
+						Printf(_L("\t\tRScheduler::GetTaskDataSize(%d) returned %d\n"), taskInfo.iTaskId, err);
+						}
+					}
+				}
+			else
+				{
+				Printf(_L("\tRScheduler::GetScheduleL(%d (\"%S\")) returned %d\n"), (*schRefArray)[count].iHandle, &(*schRefArray)[count].iName, err);
+				}
+			}
+		}
+	else
+		{
+		Printf(_L("RScheduler::GetScheduleRefsL() returned %d"), err);
+		}
+
+	CleanupStack::PopAndDestroy(3); //schRefArray, schEntries, schTasks
+	CleanupStack::PopAndDestroy(); //sch
+	}
+
+EXPORT_C void CSchSendTestUtils::CleanScheduleFolderL()
+	{
+	CFileMan* fileMan = CFileMan::NewL(iFs); 
+	CleanupStack::PushL(fileMan);
+	TParse parse;
+	TFileName fileName(_L("\\system\\schedules\\")); 
+	TBuf<4> drive=_L("C:");
+	parse.Set(fileName, &drive, NULL);
+	TInt error = fileMan->RmDir(parse.DriveAndPath()); 
+	error = iFs.RmDir(parse.DriveAndPath());
+	
+	if (!(error==KErrNotFound||error==KErrNone))
+		{
+        TPtrC driveAndPath = parse.DriveAndPath();
+		Printf(_L("Directory %S cannot be removed. Error=%d"), &driveAndPath, error);
+		Printf(_L("Please ensure directory is not in use.\n"));
+		User::Leave(error);
+		}
+
+	iFs.MkDirAll(parse.DriveAndPath());
+
+	CleanupStack::PopAndDestroy(fileMan);
+	}
+
+EXPORT_C TBool CSchSendTestUtils::CompareRoundedTimes(const TTime& aLeft, const TTime& aRight) const
+	{
+	TBool ret = (aLeft == aRight);
+	ret = ret || (RoundUpToMinute(aLeft) == RoundUpToMinute(aRight));
+	ret = ret || (RoundDownToMinute(aLeft) == RoundDownToMinute(aRight));
+	return ret;
+	}
+
+
+EXPORT_C TTime CSchSendTestUtils::RoundUpToMinute(const TTime& aTime) const
+	{
+	TTime ret(aTime);
+	TDateTime dt(ret.DateTime());
+
+	if (dt.Second() != 0 || dt.MicroSecond() != 0)
+		{
+		dt.SetSecond(0);
+		dt.SetMicroSecond(0);
+		ret = dt;
+		ret += (TTimeIntervalMinutes) 1;
+		}
+
+	return ret;
+	}
+
+EXPORT_C TTime CSchSendTestUtils::RoundDownToMinute(const TTime& aTime) const
+	{
+	TTime ret(aTime);
+	TDateTime dt(ret.DateTime());
+
+	if (dt.Second() != 0 || dt.MicroSecond() != 0)
+		{
+		dt.SetSecond(0);
+		dt.SetMicroSecond(0);
+		ret = dt;
+		}
+
+	return ret;
+	}
+
+//
+//
+//
+
+CScheduleTestActive::CScheduleTestActive(CSchSendTestUtils& aTest, TInt aPriority)
+: CActive(aPriority), iTest(aTest), iSession(*aTest.iMsvSession)
+	{
+	CActiveScheduler::Add(this);
+	}
+
+EXPORT_C CScheduleTestActive* CScheduleTestActive::NewL(CSchSendTestUtils& aTest, TInt aPriority)
+	{
+	CScheduleTestActive* self = new (ELeave) CScheduleTestActive(aTest, aPriority);
+	CleanupStack::PushL(self);
+	self->iSession.AddObserverL(*self);
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+EXPORT_C CScheduleTestActive::~CScheduleTestActive()
+	{
+	Cancel();
+	iSession.RemoveObserver(*this);
+	delete iSelection;
+	delete iOperation;
+	}
+
+//Set aStopAtRunL to true to stop the active scheduler. 
+//False will make us wait for someone else to stop it
+EXPORT_C const TSchSendTestProgress& CScheduleTestActive::TransferCommandSyncL(TSchSendTestOperation aCommand, const CMsvEntrySelection& aSelection, TBool aStopAtRunL)
+	{
+	return TransferCommandSyncL(aCommand, aSelection, _L8("aaaa"), aStopAtRunL);
+	}
+
+EXPORT_C const TSchSendTestProgress& CScheduleTestActive::TransferCommandSyncL(TSchSendTestOperation aCommand, const CMsvEntrySelection& aSelection, const TDesC8& aParameter, TBool aStopAtRunL)
+	{
+	iTest.Printf(_L("TransferCommandSyncL Command %d Count %d StopAtRunL %d\n"), aCommand, aSelection.Count(), aStopAtRunL);
+
+	if (IsActive())
+		User::Leave(KErrInUse);
+
+	delete iSelection;
+	iSelection = NULL;
+	iSelection = aSelection.CopyL();
+	iCommand = aCommand;
+	iStopAtRunL = aStopAtRunL;
+	iStatus = KRequestPending;
+	SetActive();
+
+	delete iOperation;
+	iOperation = NULL;
+	iOperation = iSession.TransferCommandL (*iSelection, 
+				aCommand,
+				aParameter, 
+				iStatus);
+
+	CActiveScheduler::Start(); // will not return from this until the command is transferred
+
+	iProgress.iError = iStatus.Int();
+	if(iStatus.Int()!=KErrNone)
+		User::Leave(iStatus.Int());
+
+	TPckgC<TSchSendTestProgress> pkg(iProgress);
+	pkg.Set(iOperation->ProgressL());
+	iProgress = pkg();
+	return iProgress;
+	}
+
+
+TInt CScheduleTestActive::RunError(TInt aError)
+	{
+	if (iProgress.iError == KErrNone)
+		iProgress.iError = aError;
+
+	CActiveScheduler::Stop();
+	return KErrNone;
+	}
+
+void CScheduleTestActive::RunL()
+	{
+	iTest.Printf(_L("CScheduleTestActive::RunL() iStatus %d\n"), iStatus.Int());
+	User::LeaveIfError(iStatus.Int());
+
+	if(iStopAtRunL) 
+		{
+		CActiveScheduler::Stop();
+		return;
+		}
+
+	switch (iCommand)
+		{
+		case EScheduleAllL:
+		case EReScheduleAllL:
+			{
+			TInt count = iSelection->Count();
+			TBool stopped = EFalse;
+			while (!stopped && count--)
+				{
+				CMsvEntry* entry = iSession.GetEntryL(iSelection->At(count));
+				CleanupStack::PushL(entry);
+				const TInt state = entry->Entry().SendingState();
+				switch(state)
+					{
+					case KMsvSendStateScheduled:
+					case KMsvSendStateResend:
+						break;
+					default: // The message sent or failed
+						stopped = ETrue;
+						CActiveScheduler::Stop();
+						break;
+					}
+				CleanupStack::PopAndDestroy(entry);
+				}
+		
+			break;
+			}
+		default:
+			CActiveScheduler::Stop(); //Added by AA 9/6/2000. Is this correct?
+			break;
+		}
+	}
+
+void CScheduleTestActive::HandleSessionEventL(TMsvSessionEvent eventType, TAny* p1, TAny*, TAny*)
+	{
+	if (iStopAtRunL) return;
+	if (eventType != EMsvEntriesCreated) return;
+
+	CMsvEntrySelection* entries = STATIC_CAST(CMsvEntrySelection*, p1);
+
+	CMsvEntry* cEntry = iSession.GetEntryL((*entries)[0]);
+	CleanupStack::PushL(cEntry);
+
+	TMsvEntry entry(cEntry->Entry());
+	
+	if(entry.iDetails == KSchSendTestDetails)
+		{
+		iTest.Printf(_L("Scheduled message has been sent\n"));
+
+		//We found the right message!
+		CActiveScheduler::Stop();
+
+		//Delete the new message
+		CMsvOperationWait* wait = CMsvOperationWait::NewLC();
+		wait->Start();
+		cEntry->SetEntryL(entry.Parent());
+		CMsvOperation* op = cEntry->DeleteL(entry.Id(), wait->iStatus);
+		CActiveScheduler::Start();
+		delete op;
+		CleanupStack::PopAndDestroy(wait);
+		}
+
+	CleanupStack::PopAndDestroy(cEntry);
+	}
+
+
+//
+//
+//
+
+
+//
+//
+//
+
+EXPORT_C CSchSendTestTimer* CSchSendTestTimer::NewL(TInt aPriority)
+    {
+    CSchSendTestTimer* self = new (ELeave) CSchSendTestTimer(aPriority);
+    CleanupStack::PushL(self);
+    self->ConstructL();		// Inherited from CTimer.
+    CleanupStack::Pop();
+    return self;
+    }
+
+CSchSendTestTimer::CSchSendTestTimer(TInt aPriority)
+: CTimer(aPriority)
+	{
+    CActiveScheduler::Add(this);
+	}
+
+void CSchSendTestTimer::RunL()
+    {
+    CActiveScheduler::Stop();
+    }
+
+EXPORT_C RTest& operator<<(RTest& aTest, TTime t)
+	{
+	TBuf<100> buf;
+	t.FormatL(buf, _L("%D%M%Y%/0%1%/1%2%/2%3%/3 %-B%:0%J%:1%T%:2%S%.%*C4%:3%+B\n"));
+	aTest.Printf(buf);
+	return aTest;
+	}
+
+EXPORT_C TBool operator==(const CMsvSendErrorActions& one, const CMsvSendErrorActions& two)
+	{
+	TMsvSendErrorAction action1 = one.Default();
+	TMsvSendErrorAction action2 = two.Default();
+	if(!(action1==action2)) return EFalse;
+
+	const CArrayFixFlat<TMsvSendErrorAction>& actionArray1 = one.Errors();
+	const CArrayFixFlat<TMsvSendErrorAction>& actionArray2 = two.Errors();
+
+	if(actionArray1.Count()!=actionArray2.Count()) return EFalse;
+	for(int i = 0; i < actionArray1.Count(); i++)
+		if(!(actionArray1[i]==actionArray2[i])) return EFalse;
+
+	return ETrue;
+
+	}
+
+EXPORT_C TBool operator==(const TMsvSchedulePackage& a1, const TMsvSchedulePackage& a2)
+	{
+	if (a1.iId				!= a2.iId) return EFalse;
+	if (a1.iCommandId		!= a2.iCommandId) return EFalse;
+	if (a1.iPollProgress	!= a2.iPollProgress) return EFalse;
+	if (a1.iParameter		!= a2.iParameter) return EFalse;
+	return ETrue;
+	}
+
+
+EXPORT_C TBool operator==(const TMsvSendErrorAction& a1, const TMsvSendErrorAction& a2)
+	{
+	if(a1.iAction			!= a2.iAction) return EFalse;
+	if(a1.iRetrySpacing		!= a2.iRetrySpacing) return EFalse;
+	if(a1.iError			!= a2.iError) return EFalse;
+	if(a1.MaxRetries()		!= a2.MaxRetries()) return EFalse;
+	if(a1.iRetries			!= a2.iRetries) return EFalse;
+	return ETrue;
+	}
+
+EXPORT_C TBool operator==(const TMsvOffPeakTime& time1, const TMsvOffPeakTime& time2)
+	{
+	if(time1.Day()!=time2.Day()) return EFalse;
+	if(time1.Hour()!=time2.Hour()) return EFalse;
+	if(time1.Minute()!=time2.Minute()) return EFalse;
+	if(time1.ValidityPeriod()!=time2.ValidityPeriod()) return EFalse;
+	return ETrue;
+	}
+
+EXPORT_C TBool StartsAt(const TMsvOffPeakTime& time1, const TTime& time2)
+	{
+	TDateTime dateTime2 = time2.DateTime();
+
+	if(time1.Day() != time2.DayNoInWeek()) return EFalse;
+	if(time1.Hour() != dateTime2.Hour()) return EFalse;
+	if(time1.Minute() != dateTime2.Minute()) return EFalse;
+	return ETrue;
+	}
+
+EXPORT_C TBool operator==(const CMsvScheduleSettings& aSettings1, const CMsvScheduleSettings& aSettings2)
+	{
+	if(aSettings1.Priority()!=aSettings2.Priority()) return EFalse;
+	if(aSettings1.ValidityPeriod()!=aSettings2.ValidityPeriod()) return EFalse;
+	if(aSettings1.IntervalType()!=aSettings2.IntervalType()) return EFalse;
+	if(aSettings1.LongInterval()!=aSettings2.LongInterval()) return EFalse;
+	if(aSettings1.ShortInterval()!=aSettings2.ShortInterval()) return EFalse;
+	if(aSettings1.VariableIntervals().Count()!=aSettings2.VariableIntervals().Count()) return EFalse;
+	for(int i = 0; i < aSettings1.VariableIntervals().Count(); i++)
+		{
+		if(aSettings1.VariableIntervals()[i]!=aSettings2.VariableIntervals()[i])
+			return EFalse;
+		}
+	if(aSettings1.Latency()!=aSettings2.Latency()) return EFalse;
+	return ETrue;
+	}
+
+
+//
+
+EXPORT_C CSchSendTestWaitForState* CSchSendTestWaitForState::NewL(CSchSendTestUtils& aTest)
+	{
+	CSchSendTestWaitForState* self = new (ELeave) CSchSendTestWaitForState(aTest);
+	CleanupStack::PushL(self);
+	User::LeaveIfError(self->iTimer.CreateLocal());
+	aTest.iMsvSession->AddObserverL(*self);
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+EXPORT_C CSchSendTestWaitForState::~CSchSendTestWaitForState()
+	{
+	Reset();
+	iTimer.Close();
+	iTest.iMsvSession->RemoveObserver(*this);
+	}
+
+void CSchSendTestWaitForState::DoStartL(const CMsvEntrySelection& aSelection, TTimeIntervalMicroSeconds32 aAfter, TBool aWaitForever)
+	{
+	iTest(iSendingStates.Count() != 0);
+
+	iAfter = aAfter;
+	iWaitForever = aWaitForever;
+
+	delete iSelection;
+	iSelection = NULL;
+	iSelection = aSelection.CopyL();
+
+	iTimer.After(iStatus, iAfter);
+	SetActive();
+
+	CActiveScheduler::Start();
+	}
+
+EXPORT_C void CSchSendTestWaitForState::StartL(const CMsvEntrySelection& aSelection)
+	{
+	DoStartL(aSelection, KSchSendTestWaitForStateDefault, ETrue);
+	}
+
+EXPORT_C void CSchSendTestWaitForState::StartL(const CMsvEntrySelection& aSelection, TTimeIntervalMicroSeconds32 aAfter)
+	{
+	DoStartL(aSelection, aAfter, EFalse);
+	}
+
+
+CSchSendTestWaitForState::CSchSendTestWaitForState(CSchSendTestUtils& aTest)
+: CActive(CActive::EPriorityStandard), iTest(aTest), iAfter(KSchSendTestWaitForStateDefault)
+	{
+	CActiveScheduler::Add(this);
+	}
+
+void CSchSendTestWaitForState::RunL()
+	{
+	User::LeaveIfError(iStatus.Int());
+
+	TInt count = iSelection->Count();
+	TBool stop = ETrue;
+	while (count--)
+		{
+		const TMsvId id = (*iSelection)[count];
+		stop = stop && CheckStateL(id);
+		}
+
+	if (stop || !iWaitForever)
+		{
+		if (!stop)
+			iStatus = KErrGeneral;
+
+		CActiveScheduler::Stop();
+		}
+	}
+
+TBool CSchSendTestWaitForState::CheckStateL(TMsvId aId)
+	{
+	iTest.SetEntryL(aId);
+	iTest.SetEntryL(iTest.Entry().Parent());
+	iTest.SetEntryL(aId);
+
+	const TInt sendingState = iTest.Entry().SendingState();
+	TInt count = iSendingStates.Count();
+	while (count--)
+		{
+		if (sendingState == iSendingStates[count])
+			return ETrue;
+		}
+
+	return EFalse;
+	}
+
+TInt CSchSendTestWaitForState::RunError(TInt aError)
+	{
+	if (iStatus.Int() == KErrNone)
+		iStatus = aError;
+
+	CActiveScheduler::Stop();
+	return KErrNone;
+	}
+
+void CSchSendTestWaitForState::DoCancel()
+	{
+	iTimer.Cancel();
+	}
+
+EXPORT_C void CSchSendTestWaitForState::Reset()
+	{
+	Cancel();
+	delete iSelection;
+	iSelection = NULL;
+	iSendingStates.Reset();
+	}
+
+void CSchSendTestWaitForState::HandleSessionEventL(TMsvSessionEvent aEvent, TAny*, TAny*, TAny*)
+	{
+	iTest.Printf(_L("CSchSendTestWaitForState::HandleSessionEventL [Event=%d IsActive=%d Count=%d]\n"), aEvent, IsActive(), iSelection->Count());
+	if ((aEvent != EMsvEntriesChanged && aEvent != EMsvEntriesCreated) || !IsActive() || iSelection->Count() == 0)
+		return;
+
+	TInt count = iSelection->Count();
+
+	while (count--)
+		{
+		const TMsvId id = iSelection->At(count);
+		if (CheckStateL(id))
+			iSelection->Delete(count);
+		}
+
+	if (iSelection->Count() == 0)
+		{
+		Cancel();
+		TRequestStatus* status = &iStatus;
+		User::RequestComplete(status, KErrNone);
+		SetActive();
+		}
+	}