messagingfw/scheduledsendmtm/schedulesendexe/src/SchSendExe.cpp
changeset 0 8e480a14352b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/messagingfw/scheduledsendmtm/schedulesendexe/src/SchSendExe.cpp	Mon Jan 18 20:36:02 2010 +0200
@@ -0,0 +1,787 @@
+// Copyright (c) 2001-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:
+//
+
+
+#ifdef _DEBUG
+#undef _MSG_NO_LOGGING
+#endif
+
+
+#include <csch_cli.h>
+#include <msvapi.h>
+#include <msvschedulepackage.h>
+#include "SchSendExe.h"
+#include <msvschedulesend.h>
+#include <msvschedulesettings.h>
+#include <msvids.h>
+#include <msvuids.h>
+#include <tmsvschedulesettingsutils.h>
+#include <centralrepository.h>
+
+
+#ifndef _MSG_NO_LOGGING
+	#include <flogger.h>
+	_LIT(KSchSendExeLogFile, "SchSendExe.txt");
+	const TFileLoggingMode KSchSendExeLoggingMode = EFileLoggingModeAppend;
+#endif
+
+
+_LIT_SECURE_ID(KSchSendExeSid, 0x100056A1);
+_LIT_SECURE_ID(KTaskSchedulerSid, 0x10005399);
+
+_LIT(KSchSendThreadName, "SchSend");
+
+#include <u32std.h>
+#include <miutset.h>
+
+
+GLDEF_C TInt E32Main()
+	{
+	if(User::CreatorSecureId() != KTaskSchedulerSid)
+		{
+		// Not launched by Task Scheduler - exit
+		return KErrPermissionDenied;
+		}
+
+	TBuf<0x100> fileName;
+	RFile taskFile;
+ 	// Adopt the task file using the RFs handle into environment  slot 
+ 	// 1 and the RFile handle into slot 2
+ 	TInt err = taskFile.AdoptFromCreator(1,2);
+ 	if(KErrNone !=err)
+ 		{
+ 		return err;
+ 		}
+ 	taskFile.Name(fileName);
+ 	return Execute(fileName, taskFile);
+ 	
+	}
+
+
+
+TInt Execute(const TDesC& aFileName, RFile& aFile )
+	{
+	__UHEAP_MARK;
+	CTrapCleanup* cleanup = CTrapCleanup::New();
+	SCHSENDLOG(CMsvSendExe::FLog(aFileName, _L("Processing file %S"), &aFileName));
+
+	TRAPD(leaveValue, DoExecuteL(aFileName, aFile ));
+
+	if (leaveValue != KErrNone)
+		{
+		// DoExecuteL will only leave in the unlikely event that available memory is too low
+		// to create an instance of the active scheduler or the CMsvSendExe object or in the
+		// event that we cannot rename the thread. Once the CMsvSendObject has been created
+		// leaves are handled cleanly by the object. We could retry the call to DoExecuteL,
+		// but it's unlikely to succeed a second time around.
+		}
+
+	SCHSENDLOG(CMsvSendExe::FLog(aFileName, _L("DoExecuteL completed with error %d"), leaveValue));
+
+	delete cleanup;
+	__UHEAP_MARKEND;
+	
+	return leaveValue;
+
+	}
+
+void DoExecuteL(const TDesC& aFileName, RFile& aFile )
+	{
+	CleanupClosePushL(aFile);
+
+	User::LeaveIfError(User::RenameThread(KSchSendThreadName));
+
+	CActiveScheduler* activeSch = new (ELeave) CActiveScheduler();
+	CleanupStack::PushL(activeSch);
+
+	CActiveScheduler::Install(activeSch);
+
+	CMsvSendExe::StartLC(aFileName, aFile );
+
+	CleanupStack::PopAndDestroy(3, &aFile);
+	}
+
+//
+// CMsvSendExe Implementation
+//
+
+/**
+
+The CMsvSendExe Constructor
+
+@return			
+@internalAll
+@param				 aFile
+*/
+CMsvSendExe::CMsvSendExe(const TDesC& aFileName, RFile& aFile )
+	: CActive(KDefaultPriority), iFileName(aFileName), iTaskFile(aFile )
+	{
+	//Add this to the Active Scheduler.
+	//This is a requirement if a class is derived from CActive
+	CActiveScheduler::Add(this);
+	iCreated.UniversalTime();
+	}
+
+CMsvSendExe::~CMsvSendExe()
+/*
+	CMsvSendExe Destructor
+*/
+	{
+	Cancel();
+	delete iSession;
+
+	iOperations.ResetAndDestroy();
+	iPackages.Reset();
+	}
+
+
+/**
+
+The CMsvSendExe::StartLC method
+1. Constructs CMsvSendExe
+2. Processes the task scheduler file
+3. Attempts to send the messages
+
+@return			
+@internalAll
+@param				 aFile File containing the task information
+*/
+CMsvSendExe* CMsvSendExe::StartLC(const TDesC& aFileName, RFile& aFile )
+	{
+	CMsvSendExe* self = new (ELeave) CMsvSendExe(aFileName,aFile );
+
+	CleanupStack::PushL(self);
+
+	self->ConstructL();
+	return self;
+	}
+
+void CMsvSendExe::ConstructL()
+	{
+	TRAPD(err, ProcessFileL());
+	
+	if(err == KErrPermissionDenied)
+		{
+		//security violation
+		User::Leave(err);
+		}
+
+	if (err != KErrNone)
+		RescheduleAllL(err);
+
+	}
+
+void CMsvSendExe::ProcessFileL()
+/*
+	ProcessFileL
+*/
+	{
+	RetrievePackagesL();
+	RetrieveMessagesL();
+
+	if (iOperations.Count())
+		{
+		CallMtmL();
+		iActiveSchedulerWait.Start();
+		}
+	else
+		{
+		SCHSENDLOG(FLog(iFileName, _L("\tNO msg to send!")));
+		}
+	}
+
+
+void CMsvSendExe::RetrievePackagesL()
+	{
+	
+	//open the filestore 	
+	CFileStore* store = CDirectFileStore::FromLC(iTaskFile);//pushes store
+
+	RStoreReadStream instream;
+	instream.OpenLC(*store,store->Root());//pushes instream
+
+	//get task count
+	TInt taskCount = instream.ReadInt32L();
+
+	SCHSENDLOG(FLog(iFileName, _L("\tTask Count=%d"), taskCount));
+
+	for (TInt curTask = 0; curTask < taskCount; curTask++)
+		{
+		CScheduledTask* task = CScheduledTask::NewLC(instream);
+
+		AddPackageL(*task);
+
+		CleanupStack::PopAndDestroy(task);
+		}
+
+	CleanupStack::PopAndDestroy(2, store);
+	}
+
+#ifndef _MSG_NO_LOGGING
+void CMsvSendExe::FLog(const TDesC& aFileName, TRefByValue<const TDesC16> aFmt, ...)
+	{
+	VA_LIST list;
+	VA_START(list, aFmt);
+
+	TParse parse;
+	parse.Set(aFileName, NULL, NULL);
+
+	TBuf<256> buf;
+	buf.Append(parse.Name());
+	buf.Append(_L(": "));
+	buf.AppendFormatList(aFmt, list);
+
+	RFileLogger::Write(KSchSendLogDir, KSchSendExeLogFile, KSchSendExeLoggingMode,
+				buf);
+	}
+#endif
+
+
+/**
+
+The CMsvSendExe::CallMtmL method
+Attempts to send the messages in the operation selection
+
+@internalAll
+*/
+void CMsvSendExe::CallMtmL()
+	{
+	__ASSERT_DEBUG(iOperations.Count(), gPanic(ENoMessagesInSelection));
+
+	TInt count = iOperations.Count();
+
+	while (count--)
+		{
+		CMsvSendExeActive& active = *iOperations[count];
+		SCHSENDLOG(FLog(iFileName, _L("\tStarting operation for %d msgs (Mtm=%d CommandId=%d)"), active.MsgCount(), active.Mtm().iUid, active.Package().iCommandId));
+		active.StartL();
+		SCHSENDLOG(FLog(iFileName, _L("\tStarted (Mtm=%d CommandId=%d)"), active.Mtm().iUid, active.Package().iCommandId));
+		}
+
+	iStatus = KRequestPending;
+	SetActive();
+	}
+
+
+/**
+
+The CMsvSendExe::DoCancel method
+Cancels all outstanding operations and stops the active scheduler.
+
+@return			
+@internalAll
+*/
+void CMsvSendExe::DoCancel()
+	{
+	SCHSENDLOG(FLog(iFileName, _L("\tOperations cancelled"), iStatus.Int()));
+
+	TInt count = iOperations.Count();
+	while (count--)
+		iOperations[count]->Cancel();
+
+	iActiveSchedulerWait.AsyncStop();
+	}
+
+
+/**
+
+The CMsvSendExe::RunL method
+Called when all operations in iOperations have completed.
+Stops the active scheduler.
+
+@return			
+@internalAll
+*/
+void CMsvSendExe::RunL()
+	{
+	SCHSENDLOG(FLog(iFileName, _L("All operations completed")));
+	iActiveSchedulerWait.AsyncStop();
+	}
+
+void CMsvSendExe::AddPackageL(const CScheduledTask& aTask)
+	{
+	TMsvSchedulePackage pkg;
+	TSecurityInfo securityInfo = aTask.SecurityInfo();
+	
+	if( (securityInfo.iSecureId.iId != KSchSendExeSid) && (securityInfo.iSecureId.iId != KMsvServerId) )
+		{
+		if( PlatSec::ConfigSetting(PlatSec::EPlatSecDiagnotics) )
+			{
+             _LIT(KMessage,"CMsvSendExe::AddPackageL ERROR %d");
+             RDebug::Print(KMessage,  KErrPermissionDenied);
+			}
+		if( PlatSec::ConfigSetting(PlatSec::EPlatSecEnforcement) )
+			{
+			//security violation
+			User::Leave(KErrPermissionDenied);
+			}
+		}
+
+	
+	pkg.UnpackL(aTask.Info(), aTask.Data());
+	User::LeaveIfError(iPackages.Append(pkg));
+	}
+
+/**
+
+The CMsvSendExe::RetrieveMessagesL method
+Retrieves the message selection from the task file.
+
+@internalAll
+*/
+void CMsvSendExe::RetrieveMessagesL()
+	{
+	iSession = CMsvSession::OpenSyncL(*this);
+	TInt count = iPackages.Count();
+
+	while(count--)
+		{
+
+		AddTaskL(iPackages[count]);
+
+		iPackages.Remove(count);
+		}
+	}
+
+
+void CMsvSendExe::AddTaskL(const TMsvSchedulePackage& aPackage)
+	{
+	CMsvEntry* cEntry = NULL;
+	TRAPD(err, cEntry = iSession->GetEntryL(aPackage.iId));
+
+	if (err != KErrNotFound)
+		{
+		User::LeaveIfError(err);
+		CleanupStack::PushL(cEntry);
+
+		TMsvEntry entry = cEntry->Entry();
+		const TInt sendState = entry.SendingState();
+
+		//Only send the message if sending state is Scheduled or Resend.
+		if (entry.Scheduled() && (sendState == KMsvSendStateScheduled || sendState == KMsvSendStateResend))
+			{
+			entry.SetSendingState(KMsvSendStateWaiting);
+
+			// Fix for DEF000924: Need to be able to send/cancel an sms while another is being sent
+			if (entry.iServiceId == KMsvLocalServiceIndexEntryId && entry.iRelatedId != KMsvNullIndexEntryId)
+				{
+				SCHSENDLOG(  FLog(iFileName, _L("Changing service from %x to %x"), entry.iServiceId, entry.iRelatedId));
+				entry.iServiceId = entry.iRelatedId;
+				}
+			else
+				{
+				SCHSENDLOG(  FLog(iFileName, _L("Not changing service from %x (related=%x)"), entry.iServiceId, entry.iRelatedId));
+				}
+			// End of fix
+
+ 			cEntry->ChangeL(entry);
+			AddTaskL(aPackage, entry.iMtm);
+			SCHSENDLOG(FLog(iFileName, _L("\t\tMsg=%d [Mtm=%d SendState=%d]"), aPackage.iId, entry.iMtm.iUid, entry.SendingState()));
+			}
+		else
+			{
+			SCHSENDLOG(FLog(iFileName, _L("\t\tIGNORING Msg=%d (Mtm=%d SendState=%d Scheduled=%d)"), aPackage.iId, entry.iMtm.iUid, sendState, entry.Scheduled()));
+			}
+
+		CleanupStack::PopAndDestroy(cEntry);
+		}
+	else
+		{
+		SCHSENDLOG(FLog(iFileName, _L("\t\tIGNORING Msg=%d: NOT FOUND"), aPackage.iId));
+		}
+	}
+
+/**
+
+The CMsvSendExe::AddTaskL method
+Finds a CMsvSendExeActive in iOperations that corresponds to aPackage and aMtm.
+If not found, then creates a new CMsvSendExeActive, and appends it to iOperations.
+Then the message in aPackage is appended to the CMsvSendExeActive.
+
+@internalAll
+@param				aPackage	Information about what operation to start
+@param				aMtm		The MTM of the message identified in aPackage
+*/
+void CMsvSendExe::AddTaskL(const TMsvSchedulePackage& aPackage, const TUid& aMtm)
+	{
+	//Add the task to an object in iOperations
+
+	CMsvSendExeActive* active = NULL;
+	TInt count = iOperations.Count();
+
+	while (active == NULL && count--)
+		{
+		CMsvSendExeActive* tempActive = iOperations[count];
+
+		if (tempActive->Mtm() == aMtm &&
+			tempActive->Package().iCommandId == aPackage.iCommandId &&
+			tempActive->Package().iParameter == aPackage.iParameter &&
+			tempActive->Package().iPollProgress == aPackage.iPollProgress)
+			active = tempActive;
+		}
+
+	if (active == NULL)
+		{
+		active = CMsvSendExeActive::NewLC(*iSession, *this, aPackage, aMtm, Priority());
+		User::LeaveIfError(iOperations.Append(active));
+		CleanupStack::Pop(active);
+		}
+
+	active->AppendL(aPackage.iId);
+	}
+
+
+/**
+
+The CMsvSendExe::OperationComplete method
+Called by a CMsvSendExeActive when it completes
+If all operations in iOperations are complete, then CMsvSendExe completes itself
+
+@return			
+@internalAll
+@param				 aActive The operation that has just completed
+@param				 aError  
+*/
+void CMsvSendExe::OperationComplete(const CMsvSendExeActive& aActive, TInt aError)
+	{
+	SCHSENDLOG(FLog(iFileName, _L("\tOperation Complete (Mtm=%d CommandId=%d Err=%d)"), aActive.Mtm().iUid, aActive.Package().iCommandId, aError));
+
+	if (aError != KErrNone)
+		RescheduleOnError(aActive, aError);
+
+#ifdef _DEBUG
+	iOperationsComplete++;
+#endif
+
+	__ASSERT_DEBUG(!aActive.IsActive(), gPanic(EOperationCompletedTooSoon));
+
+	TInt count = iOperations.Count();
+
+	while (count--)
+		{
+		if (iOperations[count]->IsActive())
+			{
+			__ASSERT_DEBUG(iOperationsComplete < iOperations.Count(), gPanic(ETooManyOperationsCompleted));
+			return;
+			}
+		}
+
+	TRequestStatus* status = &iStatus;
+	User::RequestComplete(status, KErrNone);
+	}
+
+_LIT(KSchSendExePanic, "SchSendExe");
+
+GLDEF_C void gPanic(TSchSendExePanic aPanic)
+	{
+	User::Panic(KSchSendExePanic,aPanic);
+	}
+
+GLDEF_C void gPanic(TInt aPanic)
+	{
+	User::Panic(KSchSendExePanic,aPanic);
+	}
+
+
+void CMsvSendExe::RescheduleOnError(const CMsvSendExeActive& aActive, TInt aError)
+	{
+	SCHSENDLOG(FLog(iFileName, _L("\tRescheduleOnError (Mtm=%d CommandId=%d InCount=%d)"), aActive.Mtm().iUid, aActive.Package().iCommandId, aActive.Selection().Count()));
+	RescheduleOnError(aActive.Selection(), aActive.Package(), aError);
+	}
+
+void CMsvSendExe::RescheduleAllL(TInt aError)
+	{
+	SCHSENDLOG(FLog(iFileName, _L("\tRescheduleAllL [aError=%d]"), aError));
+	RScheduler scheduler;
+	TSchedulerItemRef ref;
+	ref.iHandle = KErrNotFound;
+	TInt count = 0;
+	TInt err = KErrNone;
+	TTime start;
+	start.UniversalTime();
+
+	TInt activeCount = iOperations.Count();
+	while (activeCount--)
+		{
+		CMsvSendExeActive& active = *iOperations[activeCount];
+		active.Cancel();
+		TRAP(err, DoResheduleOnErrorL(scheduler, active.Selection(), active.Package(), aError, ref, count, start)); //ignore error
+		FailOnError(active.Selection(), aError);
+		}
+
+	activeCount = iPackages.Count();
+	CMsvEntrySelection* sel = new (ELeave) CMsvEntrySelection;
+	CleanupStack::PushL(sel);
+	while (activeCount--)
+		{
+		const TMsvSchedulePackage& package = iPackages[activeCount];
+		sel->Reset();
+		sel->AppendL(package.iId);
+		TRAP(err, DoResheduleOnErrorL(scheduler, *sel, package, aError, ref, count, start)); //ignore error
+		FailOnError(*sel, aError);
+		}
+	CleanupStack::PopAndDestroy(sel);
+
+	CompleteReschedule(scheduler, ref, count);
+	}
+
+void CMsvSendExe::CompleteReschedule(RScheduler& aScheduler, const TSchedulerItemRef& aRef, TInt aCount)
+	{
+	if (aCount != 0)
+		{
+		aScheduler.EnableSchedule(aRef.iHandle);
+		}
+	else if (aRef.iHandle != KErrNotFound)
+		{
+		aScheduler.DeleteSchedule(aRef.iHandle);
+		}
+	aScheduler.Close();
+
+	SCHSENDLOG(FLog(iFileName, _L("\tCompleteReschedule [Ref=%d OutCount=%d]"), aRef.iHandle, aCount));
+	}
+
+void CMsvSendExe::RescheduleOnError(const CMsvEntrySelection& aSelection, const TMsvSchedulePackage& aPackage, TInt aError)
+	{
+	RScheduler scheduler;
+	TTime start;
+	start.UniversalTime();
+	TSchedulerItemRef ref;
+	ref.iHandle = KErrNotFound;
+	TInt count = 0;
+	TRAPD(err, DoResheduleOnErrorL(scheduler, aSelection, aPackage, aError, ref, count, start)); //ignore error
+
+	CompleteReschedule(scheduler, ref, count);
+	FailOnError(aSelection, aError); //fails outstanding messages that weren't rescheduled. Ignore error
+	}
+
+
+void CMsvSendExe::DoResheduleOnErrorL(RScheduler& aScheduler, const CMsvEntrySelection& aSelection, const TMsvSchedulePackage& aPackage, TInt aError, TSchedulerItemRef& aRef, TInt& aCount, TTime& aStartTime)
+	{
+	SCHSENDLOG(FLog(iFileName, _L("\tDoRescheduleOnError [aError=%d]"), aError));
+
+	CMsvScheduleSettings* settings = CMsvScheduleSettings::NewL();
+	CleanupStack::PushL(settings);
+
+	TMsvSchedulePackage package(aPackage);
+	TInt selCount = aSelection.Count();
+	TTaskInfo info;
+	TInt err = KErrNone;
+
+	//Schedule each message
+	while (selCount--)
+		{
+		const TMsvId id = aSelection[selCount];
+
+		TBool scheduleMessage = ETrue;
+		CMsvEntry* cEntry = NULL;
+		TMsvEntry entry;
+
+		if (iSession != NULL)
+			TRAP(err, cEntry = iSession->GetEntryL(id));
+
+		SCHSENDLOG(FLog(iFileName, _L("\t\tScheduling Task [Id=%d Err=%d iSession=0x%X cEntry=0x%X]..."), id, err, iSession, cEntry));
+
+		if (cEntry != NULL)
+			{
+			CleanupStack::PushL(cEntry);
+			entry = cEntry->Entry();
+			switch (entry.SendingState())
+				{
+				case KMsvSendStateWaiting:
+				case KMsvSendStateScheduled:
+				case KMsvSendStateResend:
+
+					scheduleMessage = ETrue;
+					break;
+
+				case KMsvSendStateFailed:
+				case KMsvSendStateSent:
+				case KMsvSendStateSuspended:
+				default:
+
+					scheduleMessage = EFalse;
+					SCHSENDLOG(FLog(iFileName, _L("\t\tNot Scheduled Task [Id=%d State=%d Err=%d]"), id, entry.SendingState(), entry.iError));
+					break;
+				}
+			} //end if
+
+		if (scheduleMessage)
+			{
+			if (aRef.iHandle == KErrNotFound)
+				{
+				//Find or create the schedule
+				if (cEntry != NULL)
+					{
+					TRAP(err, RestoreScheduleSettingsL(entry.iServiceId, entry.iMtm, *settings)); //use default if err != KErrNone
+					SCHSENDLOG(FLog(iFileName, _L("\t\tRestoreScheduleSettings [Err=%d]"), err));
+					}
+
+				CMsvScheduleSend::ConnectAndRegisterL(aScheduler, *settings);
+				
+				if (FindorCreateScheduleL(aScheduler, aStartTime, *settings, aRef))
+					aCount++;
+				
+				User::LeaveIfError(aScheduler.DisableSchedule(aRef.iHandle));
+				}
+			
+			//Schedule the message
+			package.iId = id;
+			CMsvScheduleSend::ScheduleEntryL(aScheduler, aRef, package, info);
+			SCHSENDLOG(FLog(iFileName, _L("\t\tScheduleEntryL [Id=%d Task=%d]"), id, info.iTaskId));
+
+			if (cEntry != NULL)
+				{
+				//Update the message
+				entry.iError = aError;
+				TRAP(err, UpdateEntryL(*cEntry, entry, aRef, info, aStartTime));
+				SCHSENDLOG(FLog(iFileName, _L("\t\tEntry updated [Err=%d]"), err));
+				}
+
+			aCount++;
+
+			SCHSENDLOG(FLog(iFileName, _L("\t\tScheduled Task Complete [Id=%d Task=%d]"), id, info.iTaskId));
+			}
+
+		if (cEntry)
+			CleanupStack::PopAndDestroy(cEntry);
+		} //end while
+
+	CleanupStack::PopAndDestroy(settings);
+	}
+
+TBool CMsvSendExe::FindorCreateScheduleL(RScheduler& aScheduler, TTime& aStartTime, const CMsvScheduleSettings& aSettings, TSchedulerItemRef& aRef)
+	{
+	aStartTime.UniversalTime();
+	aStartTime += (TTimeIntervalMicroSeconds32) (KSchSendExeMinReschedule - KMsvSendExeOneMinute);
+	TInt err = KErrNotFound;
+	const TInt max = (KSchSendExeMaxReschedule - KSchSendExeMinReschedule) / KMsvSendExeOneMinute;
+
+	for (TInt i = 0; err != KErrNone && i < max; i++)
+		{
+		aStartTime += (TTimeIntervalMicroSeconds32) KMsvSendExeOneMinute;
+		CMsvScheduleSend::RoundUpToMinute(aStartTime);
+		TRAP(err, CMsvScheduleSend::FindScheduleL(aScheduler, aStartTime, aRef));
+		}
+
+	if (err != KErrNone)
+		{
+		CMsvScheduleSend::CreateScheduleL(aScheduler, aSettings, aStartTime, aSettings.ValidityPeriod(), aRef);
+		SCHSENDLOG(FLog(iFileName, _L("\t\tSchedule Created (Ref=%d) for:"), aRef.iHandle));
+		}
+	else
+		SCHSENDLOG(FLog(iFileName, _L("\t\tSchedule Found (Ref=%d) for:"), aRef.iHandle));
+
+#ifndef _MSG_NO_LOGGING
+	TBuf<32> bufDate;
+	aStartTime.FormatL(bufDate, _L("%D%M%Y%/0%1%/1%2%/2%3%/3 %-B%:0%J%:1%T%:2%S%.%*C4%:3%+B"));
+	SCHSENDLOG(FLog(iFileName, _L("\t\t%S"), &bufDate));
+#endif
+
+	return (err == KErrNone);
+	}
+
+void CMsvSendExe::RestoreScheduleSettingsL(TMsvId aServiceId, const TUid& aMtm, CMsvScheduleSettings& aSettings)
+	{
+	TMsvSelectionOrdering order;
+	order.SetShowInvisibleEntries(ETrue);
+	CMsvEntry* cEntry = CMsvEntry::NewL(*iSession, KMsvRootIndexEntryId, order);
+	CleanupStack::PushL(cEntry);
+
+	if (aServiceId == KMsvLocalServiceIndexEntryId)
+		{
+		const TInt count = cEntry->Count();
+
+		for (TInt i = 0; i < count; i++)
+			{
+			const TMsvEntry& entry = (*cEntry)[i];
+			if (entry.iType == KUidMsvServiceEntry && entry.iMtm == aMtm)
+				{
+				aServiceId = entry.Id();
+				break;
+				}
+			}
+		}
+
+	if (aServiceId == KMsvLocalServiceIndexEntryId)
+		User::Leave(KErrNotFound);
+	
+	CRepository* repository = CRepository::NewLC(aMtm);
+	TMsvScheduleSettingsUtils::LoadScheduleSettingsL(aSettings, *repository);
+	CleanupStack::PopAndDestroy(2, cEntry); // repository, cEntry
+	}
+
+void CMsvSendExe::FailOnError(const CMsvEntrySelection& aSelection, TInt aError)
+	{
+	if (iSession == NULL)
+		return;
+
+	TInt selCount = aSelection.Count();
+	TInt err = KErrNone;
+	CMsvEntry* cEntry = NULL;
+
+	while (selCount--)
+		{
+		const TMsvId id = aSelection[selCount];
+		TRAP(err, cEntry = iSession->GetEntryL(id));
+		//no need for the cleanup stack
+
+		if (err == KErrNone)
+			{
+			TMsvEntry entry(cEntry->Entry());
+			switch (entry.SendingState())
+				{
+				case KMsvSendStateWaiting:
+				case KMsvSendStateScheduled:
+				case KMsvSendStateResend:
+
+					if (entry.iDate < iCreated)
+						{
+						//Message has not been rescheduled
+						entry.SetSendingState(KMsvSendStateFailed);
+						entry.SetScheduled(EFalse);
+						entry.SetFailed(ETrue);
+						entry.iError = aError;
+						TRAP(err, cEntry->ChangeL(entry)); //ignore error
+						}
+
+					break;
+
+				default:
+					break;
+				}
+
+			delete cEntry;
+			cEntry = NULL;
+			} //end if
+		} //end while
+	}
+
+void CMsvSendExe::UpdateEntryL(CMsvEntry& aMsvEntry, TMsvEntry& aEntry, const TSchedulerItemRef& aRef, const TTaskInfo& aInfo, const TTime& aStartTime)
+	{
+	CMsvStore* store = aMsvEntry.EditStoreL();
+	CleanupStack::PushL(store);
+
+	TMsvEntryScheduleData data;
+	data.RestoreL(*store);
+
+	CMsvScheduleSend::UpdateEntryAfterSchedule(aRef, aInfo, aStartTime, KMsvSendStateResend, aEntry, data);
+
+	data.StoreL(*store);
+	store->CommitL();
+
+	CleanupStack::PopAndDestroy(store);
+	aMsvEntry.ChangeL(aEntry);
+	}
+