messagingfw/scheduledsendmtm/schedulesendmtm/src/MsvScheduleSend.cpp
changeset 62 db3f5fa34ec7
parent 0 8e480a14352b
equal deleted inserted replaced
60:9f5ae1728557 62:db3f5fa34ec7
       
     1 // Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #ifdef _DEBUG
       
    17 #undef _MSG_NO_LOGGING
       
    18 #endif
       
    19 
       
    20 #include <msvschedulesend.h>
       
    21 
       
    22 #include <msventry.h>
       
    23 #include <msvids.h>
       
    24 #include <bautils.h>
       
    25 #include <e32property.h>
       
    26 #include <centralrepository.h>
       
    27 
       
    28 #include <msvschedulesettings.h>
       
    29 #include <msvoffpeaktime.h>
       
    30 #include <msvsysagentaction.h>
       
    31 #include <schsend_panic.h>
       
    32 #include <tmsvschedulesettingsutils.h>
       
    33 #include <schinfointernal.h>
       
    34 
       
    35 #ifndef _MSG_NO_LOGGING
       
    36 #include <flogger.h>
       
    37 #endif
       
    38 
       
    39 
       
    40 _LIT(KSchSendExe, "schsendexe.exe");
       
    41 
       
    42 LOCAL_C TBool operator==(const CArrayFixFlat<TTaskSchedulerCondition>& aConditions1, const CArrayFixFlat<TTaskSchedulerCondition>& aConditions2)
       
    43 	{
       
    44 	TInt count1 = aConditions1.Count();
       
    45 	TInt count2 = aConditions2.Count();
       
    46 	
       
    47 	// Compare the conditions.	
       
    48 	if( count1 != count2 )
       
    49 		{
       
    50 		// Different number of conditions - no match.
       
    51 		return EFalse;
       
    52 		}
       
    53 		
       
    54 	// Search for all the conditions in info1 are in info2
       
    55 	for( TInt ii = 0; ii < count1; ++ii )
       
    56 		{
       
    57 		TTaskSchedulerCondition condition1 = aConditions1[ii];
       
    58 		TTaskSchedulerCondition condition2;
       
    59 		TBool found = EFalse;
       
    60 		TInt jj = 0;
       
    61 		while( !found && jj < count2 )
       
    62 			{
       
    63 			condition2 = aConditions2[jj];
       
    64 			
       
    65 			if( condition2.iKey == condition1.iKey )
       
    66 				found = ETrue;
       
    67 			else
       
    68 				++jj;
       
    69 			}
       
    70 		if( !found || condition2.iState != condition1.iState || condition2.iType != condition1.iType )
       
    71 			{
       
    72 			// Either aConditions2 has not got this condition or it has but it 
       
    73 			// does not match - no match.
       
    74 			return EFalse;
       
    75 			}
       
    76 		}
       
    77 	return ETrue;
       
    78 	}
       
    79 
       
    80 /**
       
    81 Constructor.
       
    82 
       
    83 @param aServerEntry 
       
    84 The CMsvServerEntry of the server MTM of which this CMsvScheduleSend 
       
    85 object is a member.
       
    86 */
       
    87 EXPORT_C CMsvScheduleSend::CMsvScheduleSend(CMsvServerEntry& aServerEntry)
       
    88 	: iServerEntry(aServerEntry)
       
    89 	{
       
    90 	}
       
    91 
       
    92 /**
       
    93 Second phase constructor.
       
    94 
       
    95 This constructor creates instances of the following classes: 
       
    96 CMsvScheduleSettings, CMsvOffPeakTimes, CMsvSendErrorActions,
       
    97 CMsvSysAgentActions and CMsvScheduledEntries.
       
    98 */
       
    99 EXPORT_C void CMsvScheduleSend::ConstructL()
       
   100 	{
       
   101 	iSettings			= CMsvScheduleSettings::NewL();
       
   102 	iOffPeakTimes		= new (ELeave) CMsvOffPeakTimes();
       
   103 	iErrorActions		= CMsvSendErrorActions::NewL();
       
   104 	iAgentActions		= new (ELeave) CMsvSysAgentActions();
       
   105 	iSchEntries			= new (ELeave) CMsvScheduledEntries(KMsvSchsendArrayGrowth);
       
   106 
       
   107 	iSchEntryInfo		= new (ELeave) CArrayFixFlat<TScheduleEntryInfo2>(KMsvSchsendArrayGrowth);
       
   108 	iSchTaskInfo		= new (ELeave) CArrayFixFlat<TTaskInfo>(KMsvSchsendArrayGrowth);
       
   109 	}
       
   110 
       
   111 /**
       
   112 Destructor.
       
   113 */
       
   114 EXPORT_C CMsvScheduleSend::~CMsvScheduleSend()
       
   115 	{
       
   116 	delete iSettings;
       
   117 	delete iOffPeakTimes;
       
   118 	delete iErrorActions;
       
   119 	delete iAgentActions;
       
   120 
       
   121 	if (iScheduler.Handle())
       
   122 		iScheduler.Close();
       
   123 
       
   124 	if (iSchEntries)
       
   125 		iSchEntries->ResetAndDestroy();
       
   126 
       
   127 	delete iSchEntries;
       
   128 
       
   129 	delete iSchTaskInfo;
       
   130 	delete iSchEntryInfo;
       
   131 	}
       
   132 
       
   133 /**
       
   134 Schedules messages on the task scheduler.
       
   135 
       
   136 Messages that are successfully scheduled have their sending state set to
       
   137 KMsvSendStateScheduled.
       
   138 
       
   139 @param aSelection 
       
   140 Array of message IDs that need to be scheduled. This array cannot be empty.
       
   141 All the messages identified in the selection must belong to the same MTM;
       
   142 be scheduled for the same time; have the same setting for their OffPeak() 
       
   143 flag; have the scheduled time stored in the iDate member of their 
       
   144 corresponding TMsvEntry. 
       
   145 
       
   146 @param aPackage 
       
   147 Scheduling options
       
   148 
       
   149 @leave Any error code but KErrLocked and KErrNotFound
       
   150 The method overloading CMsvScheduledEntry::GetMessageL() left with an error,
       
   151 i.e. the scheduling info of one of the messages from the selection could not
       
   152 be retrieved from the message server.
       
   153 
       
   154 @leave Any error code
       
   155 Unable to reset the previous scheduling info for a message.
       
   156 
       
   157 @panic ScheduleSend-DLL 0
       
   158 The array of message IDs is empty.
       
   159 Debug build only.
       
   160 
       
   161 @panic ScheduleSend-DLL 1
       
   162 At least one of the selected messages is scheduled for a different time
       
   163 as the others.
       
   164 Debug build only.
       
   165 
       
   166 @panic ScheduleSend-DLL 2
       
   167 At least one of the selected messages does not belong to the same MTM.
       
   168 Debug build only.
       
   169 
       
   170 @panic ScheduleSend-DLL 3
       
   171 At least one of the selected messages does not have the same off-peak 
       
   172 settings as the others.
       
   173 Debug build only.
       
   174 */
       
   175 EXPORT_C void CMsvScheduleSend::ScheduleL(const CMsvEntrySelection& aSelection, const TMsvSchedulePackage& aPackage)
       
   176 	{
       
   177 	__ASSERT_DEBUG(aSelection.Count() > 0, gPanic(EMessageSelectionEmpty));
       
   178 
       
   179 	iPackage = aPackage;
       
   180 	GetMessagesL(aSelection);	//Leaves with KErrNotFound if there
       
   181 																	//are no messages returned in schEntries
       
   182 	TInt entryCount = iSchEntries->Count();
       
   183 	SCHSENDLOG(FLog(_L8("Asked to schedule %d msgs"), entryCount));
       
   184 	
       
   185 	if (entryCount)
       
   186 		{
       
   187 		TTime startTime;
       
   188 
       
   189 #if defined(_DEBUG)
       
   190 		CMsvScheduledEntry* firstEntry = (*iSchEntries)[0];
       
   191 #endif
       
   192 
       
   193 		while (entryCount--)
       
   194 			{
       
   195 			CMsvScheduledEntry* message = iSchEntries->At(entryCount);
       
   196 			__ASSERT_DEBUG(firstEntry->ScheduleDate() == message->ScheduleDate(), gPanic(EMessagesNotSameTime));
       
   197 
       
   198 			startTime = message->ScheduleDate();
       
   199 
       
   200 			// Reset previous scheduling info
       
   201 			DeleteScheduleForEntryL(*message);
       
   202 			ResetScheduleInfoForEntryL(*message, EFalse);
       
   203 			}
       
   204 
       
   205 		//Schedule the messages
       
   206 		DoScheduleL(*iSchEntries, KMsvSendStateScheduled, startTime, EFalse);
       
   207 		}
       
   208 	}
       
   209 
       
   210 /** 
       
   211 Determines when the messages should be re-scheduled on the task scheduler, 
       
   212 then schedules the messages at the new time(s).
       
   213 
       
   214 Messages that are successfully re-scheduled are updated. The pending conditions
       
   215 flag indicates whether the message has been schedule for a set of conditions 
       
   216 being met (or a timeout occuring) or scheduled for a specified time/date.
       
   217 
       
   218 NOTE - conditions scheduling is only supoprted from 8.1 onwards.
       
   219 
       
   220 In the case of time-scheduling, the date field is the scheduled time/date. In 
       
   221 the case of conditions-scheduling, the date field reflects the timeout value.
       
   222 
       
   223 There are several cases when messages are not re-scheduled. If all recipients 
       
   224 have been sent to - in this case the message's sending state set to 
       
   225 KMsvSendStateSent. If, more commonly, the message's maximum number of re-tries
       
   226 has been exceeded or the error action was ESendActionFail then the message is 
       
   227 not changed.
       
   228 
       
   229 @param aSelection 
       
   230 Array of message IDs that need to be re-scheduled. This array cannot be empty. 
       
   231 All the messages identified must belong to the same MTM. It is not a 
       
   232 precondition that each message has already been scheduled on the task 
       
   233 scheduler.
       
   234 
       
   235 @param aPackage
       
   236 Scheduling options.
       
   237 
       
   238 @param aErrorAction
       
   239 The specific action to take with the messages. If this argument is omitted, 
       
   240 then ReScheduleL() uses the iError member of each TMsvEntry to find the 
       
   241 related TMsvSendErrorAction in iErrorActions.
       
   242 
       
   243 @panic ScheduleSend-DLL 0
       
   244 The array of message IDs is empty.
       
   245 Debug build only.
       
   246 */
       
   247 EXPORT_C void CMsvScheduleSend::ReScheduleL(const CMsvEntrySelection& aSelection, const TMsvSchedulePackage& aPackage, const TMsvSendErrorAction* aErrorAction)
       
   248 	{
       
   249 	__ASSERT_DEBUG(aSelection.Count() > 0, gPanic(EMessageSelectionEmpty));
       
   250 	iPackage = aPackage;
       
   251 	GetMessagesL(aSelection);
       
   252 
       
   253 	TInt entryCount = iSchEntries->Count();
       
   254 	SCHSENDLOG(FLog(_L8("Asked to re-schedule %d msgs"), entryCount));
       
   255 
       
   256 	if (entryCount)
       
   257 		{
       
   258 		TTime curTime;
       
   259 		curTime.UniversalTime();
       
   260 		curTime += iSettings->Latency();
       
   261 
       
   262 		while (entryCount--)
       
   263 			{
       
   264 			CMsvScheduledEntry* message = iSchEntries->At(entryCount);
       
   265 	
       
   266 			SCHSENDLOG(FLog(_L8("\tAttempting to Re-Schedule msg %d"), message->Id()));
       
   267 
       
   268 			if (!SetMessageStartTime(*message, curTime, aErrorAction))
       
   269 				{
       
   270 				SCHSENDLOG(FLog(_L8("\t\tCannot Re-Schedule msg %d (new sending state %d)"), message->Id(), message->SendingState()));
       
   271 				DeleteScheduleForEntryL(*message);
       
   272 				ResetScheduleInfoForEntryL(*message, ETrue);
       
   273 				delete message;
       
   274 				iSchEntries->Delete(entryCount);
       
   275 				}
       
   276 			}
       
   277 
       
   278 		//Send the messages if there are any left to send
       
   279 		if (iSchEntries->Count())
       
   280 			{
       
   281 			DoReScheduleL(*iSchEntries);
       
   282 			}
       
   283 		else
       
   284 			{
       
   285 			SCHSENDLOG(FLog(_L8("\tNo messages to Re-Schedule")));
       
   286 			}
       
   287 		}
       
   288 	}
       
   289 
       
   290 /**
       
   291 Delete the schedules for the specified messages from the task scheduler. 
       
   292 
       
   293 The messages themselves are not deleted.
       
   294 
       
   295 @param aSelection 
       
   296 Array of message IDs that need to be deleted from the task scheduler.
       
   297 
       
   298 @leave Any error code
       
   299 Unable to connect and register with the scheduler.
       
   300 
       
   301 @leave Any error code but KErrLocked and KErrNotFound
       
   302 The method overloading CMsvScheduledEntry::GetMessageL() left with an error,
       
   303 i.e. the scheduling info of one of the messages from the selection could not
       
   304 be retrieved from the message server.
       
   305 
       
   306 @leave Any error code
       
   307 Unable to reset the previous scheduling info for a message.
       
   308 */
       
   309 EXPORT_C void CMsvScheduleSend::DeleteScheduleL(const CMsvEntrySelection& aSelection)
       
   310 	{
       
   311 	ConnectAndRegisterL();
       
   312 
       
   313 	GetMessagesL(aSelection);
       
   314 
       
   315 	TInt entryCount = iSchEntries->Count();
       
   316 	SCHSENDLOG(FLog(_L8("Asked to delete schedule of %d msgs"), entryCount));
       
   317 
       
   318 	while (entryCount--)
       
   319 		{
       
   320 		CMsvScheduledEntry* message = iSchEntries->At(entryCount);
       
   321 		SCHSENDLOG(FLog(_L8("\tDelete schedule for msg %d (mtm %d, oldSendState %d, newSendState %d)"), message->Id(), message->Mtm().iUid, message->SendingState(), KMsvSendStateSuspended));
       
   322 		message->SetSendingState(KMsvSendStateSuspended);
       
   323 		DeleteScheduleForEntryL(*message);
       
   324 		ResetScheduleInfoForEntryL(*message, ETrue);
       
   325 		}
       
   326 	}
       
   327 
       
   328 /*
       
   329 	Sets the message's scheduled flag to EFalse
       
   330 	Resets the schedule data associated with each message
       
   331 	Resets the number of retries for each recipient
       
   332 	Stores the data and recipients (in a stream associated with the TMsvEntry)
       
   333 */
       
   334 void CMsvScheduleSend::SendingCompleteL(CMsvScheduledEntry& aMessage, const TBool aChangeEntry)
       
   335 	{
       
   336 	__ASSERT_DEBUG(iServerEntry.Entry().Id() == aMessage.Id(), gPanic(EServerEntryNotSetToCorrectEntry));
       
   337 	
       
   338 	aMessage.SetScheduled(EFalse);
       
   339 	aMessage.iData.Reset();
       
   340 	aMessage.RecipientsResetRetries();
       
   341 
       
   342 	if (aChangeEntry)
       
   343 		{
       
   344 		TMsvEntry entry = iServerEntry.Entry();
       
   345 		aMessage.Entry(entry);
       
   346 		User::LeaveIfError(iServerEntry.ChangeEntry(entry));
       
   347 		}
       
   348 
       
   349 	CMsvStore* store = iServerEntry.EditStoreL();
       
   350 	CleanupStack::PushL(store);
       
   351 	aMessage.StoreL(*store);
       
   352 	store->CommitL();
       
   353 	CleanupStack::PopAndDestroy(store); 
       
   354 	}
       
   355 
       
   356 /**
       
   357 Tells the scheduler that sending is complete.
       
   358 
       
   359 This method sets the messages's scheduled flag to false, resets the schedule
       
   360 data associated with each message and the number of retries for each 
       
   361 recipient and stores the data and recipients in a stream associated with 
       
   362 the TMsvEntry.
       
   363 
       
   364 @param aSelection 
       
   365 Messages that were either successfully sent or which failed all the attempts
       
   366 to send.
       
   367 */
       
   368 EXPORT_C void CMsvScheduleSend::SendingCompleteL(const CMsvEntrySelection& aSelection)
       
   369 	{
       
   370 	TInt count = aSelection.Count();
       
   371 
       
   372 	while (count--)
       
   373 		{
       
   374 		CMsvScheduledEntry* schEntry = GetMessageL(aSelection[count]);
       
   375 		CleanupStack::PushL(schEntry);
       
   376 		SendingCompleteL(*schEntry, ETrue);
       
   377 		CleanupStack::PopAndDestroy(); //schEntry
       
   378 		}
       
   379 	}
       
   380 
       
   381 /**
       
   382 Tells the scheduler that sending is complete.
       
   383 
       
   384 This function must be called when a message that had previously been scheduled 
       
   385 is either sent or has failed. This function:
       
   386 
       
   387 1. Deletes the TMsvEntryScheduleData associated with the message
       
   388 
       
   389 2. Sets the Scheduled flag to EFalse
       
   390 
       
   391 3. If required, calls ChangeEntry() on the message server entry
       
   392 
       
   393 Note: SendingCompleteL() does not change the sending state of each message, 
       
   394 nor delete each message from the task scheduler.
       
   395 
       
   396 @param aEntry 
       
   397 The message which was either successfully sent or which failed (all the 
       
   398 attempts) to send. It is not a precondition that the message has already 
       
   399 been scheduled on the task scheduler.
       
   400 
       
   401 @param aChangeEntry 
       
   402 If aChangeEntry is ETrue then SendingCompleteL() will call 
       
   403 CMsvServerEntry::ChangeEntry() to update the message on the message server. 
       
   404 
       
   405 @panic ScheduleSend-DLL 24
       
   406 The server entry is not set to the correct entry.
       
   407 Debug build only.
       
   408 */
       
   409 EXPORT_C void CMsvScheduleSend::SendingCompleteL(TMsvEntry& aEntry, const TBool aChangeEntry)
       
   410 	{
       
   411 	__ASSERT_DEBUG(iServerEntry.Entry().Id() == aEntry.Id(), gPanic(EServerEntryNotSetToCorrectEntry));
       
   412 
       
   413 	CMsvScheduledEntry* schEntry = GetMessageL(aEntry.Id());
       
   414 	CleanupStack::PushL(schEntry);
       
   415 
       
   416 	SendingCompleteL(*schEntry, EFalse);
       
   417 	schEntry->Entry(aEntry);
       
   418 
       
   419 	if (aChangeEntry)
       
   420 		{
       
   421 		User::LeaveIfError(iServerEntry.ChangeEntry(aEntry));
       
   422 		}
       
   423 
       
   424 	CleanupStack::PopAndDestroy(); //schEntry
       
   425 	}
       
   426 
       
   427 
       
   428 /**
       
   429 Loads schedule settings from CenRep
       
   430 
       
   431 @param aRepository 
       
   432 CenRep repository to load settings from
       
   433 */
       
   434 EXPORT_C void CMsvScheduleSend::LoadScheduleSettingsL(CRepository& aRepository)
       
   435 	{
       
   436 	TMsvScheduleSettingsUtils::LoadScheduleSettingsL(*iSettings, aRepository);
       
   437 	TMsvScheduleSettingsUtils::LoadOffPeakSettingsL(*iOffPeakTimes, aRepository);
       
   438 	TMsvScheduleSettingsUtils::LoadSendErrorSettingsL(*iErrorActions, aRepository);
       
   439 	TMsvScheduleSettingsUtils::LoadSysAgentSettingsL(*iAgentActions, aRepository);	
       
   440 	}
       
   441 
       
   442 /**
       
   443 Verifies that the schedule information stored in specified messages is the 
       
   444 same as that on the task scheduler.
       
   445 
       
   446 @param aSelection 
       
   447 Array of message IDs that need to be checked against the task scheduler.
       
   448 
       
   449 @panic ScheduleSend-DLL 0
       
   450 The array of message IDs is empty.
       
   451 Debug build only.
       
   452 */
       
   453 EXPORT_C void CMsvScheduleSend::CheckScheduleL(const CMsvEntrySelection& aSelection)
       
   454 	{
       
   455 	__ASSERT_DEBUG(aSelection.Count(), gPanic(EMessageSelectionEmpty));
       
   456 
       
   457 	GetMessagesL(aSelection);	//Leaves with KErrNotFound if there are no messages returned in iSchEntries
       
   458 	TInt entryCount = iSchEntries->Count();
       
   459 	SCHSENDLOG(FLog(_L8("Asked to check schedule for %d msgs"), entryCount));
       
   460 	
       
   461 	ConnectAndRegisterL();
       
   462 
       
   463 	while (entryCount--)
       
   464 		{
       
   465 		TBool found = EFalse;
       
   466 		TTsTime schTime;
       
   467 
       
   468 		CMsvScheduledEntry& sEntry = *iSchEntries->At(entryCount);
       
   469 
       
   470 		if (!sEntry.iData.IsReset())
       
   471 			{
       
   472 			TSchedulerItemRef ref;
       
   473 			TInt size = 0;
       
   474 			TTaskInfo info;
       
   475 			
       
   476 			TInt err = iScheduler.GetTaskDataSize(sEntry.iData.iTaskId, size);
       
   477 
       
   478 			if (!err)
       
   479 				{
       
   480 				HBufC* buf = HBufC::NewLC(size);
       
   481 				TPtr ptr = buf->Des();
       
   482 
       
   483 				User::LeaveIfError(iScheduler.GetTaskInfoL(sEntry.iData.iTaskId, info, ptr, ref, schTime));
       
   484 
       
   485 				CleanupStack::PopAndDestroy(buf);
       
   486 				found = ETrue;
       
   487 				}
       
   488 			else if (err != KErrNotFound)
       
   489 				{
       
   490 				User::Leave(err);
       
   491 				} 
       
   492 			} 
       
   493 			
       
   494 		if (iServerEntry.SetEntry(sEntry.Id()) == KErrNone)
       
   495 			{
       
   496 			TMsvEntry entry = iServerEntry.Entry();
       
   497 			TInt sendingState = entry.SendingState();
       
   498 
       
   499 			if (sendingState == KMsvSendStateScheduled || sendingState == KMsvSendStateResend || entry.Scheduled())
       
   500 				{
       
   501 				if (found)
       
   502 					{
       
   503 					entry.SetScheduled(ETrue);
       
   504 					entry.iDate = schTime.GetUtcTime();
       
   505 					User::LeaveIfError(iServerEntry.ChangeEntry(entry));
       
   506 					}
       
   507 				else
       
   508 					{
       
   509 					entry.SetScheduled(EFalse);
       
   510 					entry.SetSendingState(KMsvSendStateUnknown);
       
   511 					entry.iDate.UniversalTime();
       
   512 					User::LeaveIfError(iServerEntry.ChangeEntry(entry));
       
   513 					SendingCompleteL(sEntry, EFalse);
       
   514 					} 
       
   515 				} 
       
   516 			} 
       
   517 		} 
       
   518 	}
       
   519 
       
   520 /**
       
   521 Determines the schedule time for a message.
       
   522 
       
   523 The schedule time is determined by the error action. If no error action is
       
   524 supplied, then the error action is obtained from the iErrorActions. This is a 
       
   525 list of error codes associated with an error action. The error code with which
       
   526 the message failed to be sent is used to determine the error action from this
       
   527 list.
       
   528 
       
   529 This function also increments the number of re-tries that the message has 
       
   530 undergone.
       
   531 
       
   532 A value of ETrue is returned if the message can be sent or a value of EFalse if
       
   533 the message cannot be sent. 
       
   534 
       
   535 If the message can be sent, then its schedule date and pending conditions flag 
       
   536 are updated.
       
   537 
       
   538 @see CMsvScheduleSend::ReScheduleL().
       
   539 
       
   540 @param	aMessage
       
   541 The message to be re-scheduled.
       
   542 
       
   543 @param	aFromTime
       
   544 The current time. Used to calculate the absolute schedule time once the interval
       
   545 has been established.
       
   546 
       
   547 @param	aErrorAction
       
   548 The error action applied to the message. This can be NULL in which case the error
       
   549 action is obtained from iErrorActions.
       
   550 
       
   551 @return
       
   552 A value of ETrue if the message should be sent or EFalse if it should not
       
   553 */
       
   554 TBool CMsvScheduleSend::SetMessageStartTime(CMsvScheduledEntry& aMessage, const TTime& aFromTime, const TMsvSendErrorAction* aErrorAction)
       
   555 	{
       
   556 	TBool sendMsg = EFalse;
       
   557 	TMsvSendErrorAction action;
       
   558 
       
   559 	if( aErrorAction != NULL )
       
   560 		{
       
   561 		sendMsg = aMessage.CanSendToAnyRecipients(*aErrorAction);
       
   562 		action = *aErrorAction;
       
   563 		}
       
   564 	else 
       
   565 		{
       
   566 		sendMsg = aMessage.CanSendToAnyRecipients(*iErrorActions, action);
       
   567 		}
       
   568 
       
   569 	SCHSENDLOG(FLog(_L8("\t\tCanSendToAnyRecipients() ret %d"), sendMsg));
       
   570 
       
   571 	if( sendMsg )
       
   572 		{
       
   573 		// Increase the number of times this message has been retried.
       
   574 		if( action.iRetries != ESendRetriesInfinite )
       
   575 			{
       
   576 			aMessage.iData.IncreaseRetries();
       
   577 			aMessage.RecipientsIncreaseRetries();
       
   578 			}
       
   579 			
       
   580 		TBool retryConditionMet = action.iAction == ESendActionRetryConditionMet;
       
   581 		
       
   582 		if( retryConditionMet && aMessage.PendingConditions() )
       
   583 			{
       
   584 			// There are two cases in which the message being re-scheduled has 
       
   585 			// already been scheduled for pending conditions met and the error 
       
   586 			// action is retry when conditions met.
       
   587 			// 1.	The timeout has expired - current time exceeds the message's 
       
   588 			//		schedule time (assuming that the message has a timeout).
       
   589 			// 2.	The conditions were temporarily met and by the time the 
       
   590 			//		waiting message tried to be sent the conditions were no 
       
   591 			//		longer true.
       
   592 			if( aMessage.ScheduleDate()!= Time::MaxTTime() && aFromTime > aMessage.ScheduleDate() )
       
   593 				{
       
   594 				// Case 1 - the message should not be re-scheduled (this marks
       
   595 				// the message as failed).
       
   596 				sendMsg = EFalse;
       
   597 				}
       
   598 			// NOTE - the else is case 2; the message should be re-scheduled,
       
   599 			// but the timeout value should NOT be re-calculated -> do nothing.
       
   600 			}
       
   601 		else
       
   602 			{
       
   603 			TTimeIntervalSeconds interval;
       
   604 			if( GetNextRetry(aMessage, action, interval) )
       
   605 				{
       
   606 				if( interval.Int() == 0 && retryConditionMet )
       
   607 					{
       
   608 					// The timeout was set to zero - set a schedule time of
       
   609 					// Time::MaxTTime().
       
   610 					aMessage.SetScheduleDate(Time::MaxTTime());
       
   611 					}
       
   612 				else
       
   613 					{
       
   614 					TTime schTime = aFromTime + interval;
       
   615 					RoundUpToMinute(schTime);
       
   616 					aMessage.SetScheduleDate(schTime);
       
   617 					}
       
   618 				aMessage.SetPendingConditions(retryConditionMet);
       
   619 				}
       
   620 			else
       
   621 				{
       
   622 				sendMsg = EFalse;
       
   623 				}
       
   624 
       
   625 			SCHSENDLOG(FLog(_L8("\t\tGetNextRetry() ret %d"), sendMsg));
       
   626 			}
       
   627 		}
       
   628 
       
   629 	if( !sendMsg )
       
   630 		{
       
   631 		TBool failed = ETrue;
       
   632 		TInt state	 = KMsvSendStateFailed;
       
   633 
       
   634 		if( aMessage.RecipientsAllSent() )
       
   635 			{
       
   636 			failed	= EFalse;
       
   637 			state	= KMsvSendStateSent;
       
   638 			}
       
   639 		else
       
   640 			{
       
   641 			aMessage.RecipientsSetFailed();
       
   642 			}
       
   643 
       
   644 		aMessage.SetFailed(failed);
       
   645 		aMessage.SetSendingState(state);
       
   646 		}
       
   647 
       
   648 	return sendMsg;
       
   649 	}
       
   650 
       
   651 /**
       
   652 Utility function that rounds a specified time up to the nearest minute.
       
   653 
       
   654 @param aTime 
       
   655 On return, the passed value rounded up to the nearest minute.
       
   656 */
       
   657 
       
   658 EXPORT_C void CMsvScheduleSend::RoundUpToMinute(TTime& aTime)
       
   659 	{
       
   660 	TDateTime dt(aTime.DateTime());
       
   661 
       
   662 	if (dt.MicroSecond() != 0 || dt.Second() != 0)
       
   663 		{
       
   664 		dt.SetMicroSecond(0);
       
   665 		dt.SetSecond(0);
       
   666 		aTime = dt;
       
   667 		aTime += (TTimeIntervalMinutes) 1;
       
   668 		}
       
   669 	}
       
   670 
       
   671 /*
       
   672 	Groups messages in aSchEntries by the date (time) they are to be scheduled
       
   673 	and if they are pending conditions met or not and then schedules each group.
       
   674 */
       
   675 
       
   676 void CMsvScheduleSend::DoReScheduleL(CMsvScheduledEntries& aSchEntries)
       
   677 	{
       
   678 	const TInt entryCount = aSchEntries.Count();
       
   679 	__ASSERT_DEBUG(entryCount > 0, gPanic(EMessageSelectionEmpty));
       
   680 
       
   681 	// Sort aSchEntries by CMsvScheduledEntry::iEntry.iDate and if they are 
       
   682 	// pending conditions or not.
       
   683 	SortByDateAndPendingConditionsL(aSchEntries);
       
   684 
       
   685 	//New selection of messages that will be used to store messages
       
   686 	//that are to be sent at the same time.
       
   687 	CMsvScheduledEntries* sel = new (ELeave) CMsvScheduledEntries(KMsvSchsendArrayGrowth);
       
   688 	CleanupStack::PushL(sel);
       
   689 
       
   690 	sel->SetReserveL(entryCount); // so following AppendL()s won't leave
       
   691 
       
   692 	CMsvScheduledEntry* curMessage = aSchEntries[0];
       
   693 	TTime lastTime = curMessage->ScheduleDate();
       
   694 	TBool lastPending = curMessage->PendingConditions();
       
   695 	sel->AppendL(curMessage);
       
   696 
       
   697 	// Delete old schedule
       
   698 	DeleteScheduleForEntryL(*curMessage);
       
   699 
       
   700 	for( TInt curMsg = 1; curMsg < entryCount; ++curMsg ) // must forward traverse the array
       
   701 		{
       
   702 		curMessage = aSchEntries[curMsg];
       
   703 		TTime thisTime = curMessage->ScheduleDate();
       
   704 		TBool thisPending = curMessage->PendingConditions();
       
   705 
       
   706 		// Delete old schedule
       
   707 		DeleteScheduleForEntryL(*curMessage);
       
   708 		if( thisTime == lastTime && lastPending == thisPending )
       
   709 			{
       
   710 			sel->AppendL(curMessage);
       
   711 			}
       
   712 		else
       
   713 			{
       
   714 			// Schedule the messages in the selection
       
   715 			DoScheduleL(*sel, KMsvSendStateResend, lastTime, lastPending);
       
   716 			sel->Reset(); // not ResetandDestroy because the messages are still in schEntries
       
   717 			sel->AppendL(curMessage);
       
   718 			lastTime = thisTime;
       
   719 			lastPending = thisPending;
       
   720 			}
       
   721 		}
       
   722 
       
   723 	if( sel->Count() )
       
   724 		{
       
   725 		// Schedule the remaining messages
       
   726 		DoScheduleL(*sel, KMsvSendStateResend, lastTime, lastPending);
       
   727 		}
       
   728 
       
   729 	sel->Reset(); // not ResetandDestroy because the messages are still in schEntries
       
   730 	CleanupStack::PopAndDestroy(sel);
       
   731 	}
       
   732 
       
   733 /*
       
   734 	Gets the Message ID stored against the task scheduler task aTaskId
       
   735 
       
   736 	@param aTaskId ID of task scheduler task
       
   737 */
       
   738 
       
   739 TMsvId CMsvScheduleSend::GetMessageIdForTaskL(TInt aTaskId)
       
   740 	{
       
   741 	TInt taskSize = 0;
       
   742 	TTaskInfo taskInfo;
       
   743 	TSchedulerItemRef taskSch;
       
   744 	TTsTime taskDue;
       
   745 
       
   746 	User::LeaveIfError(iScheduler.GetTaskDataSize(aTaskId, taskSize));
       
   747 
       
   748 	HBufC* taskData = HBufC::NewLC(taskSize);
       
   749 	TPtr ptr(taskData->Des());
       
   750 
       
   751  	User::LeaveIfError(iScheduler.GetTaskInfoL(aTaskId, taskInfo, ptr, taskSch, taskDue));
       
   752  
       
   753  	//Restore the TMsvSchedulePackage stored against the task scheduler task
       
   754  	TMsvSchedulePackage taskPackage;
       
   755  	taskPackage.UnpackL(taskInfo, *taskData);
       
   756  
       
   757  	CleanupStack::PopAndDestroy(taskData);
       
   758  
       
   759  	return taskPackage.iId;
       
   760  	}
       
   761  
       
   762 /*
       
   763 	Checks whether the message ID stored against task scheduler task aMessage.iData.iTaskId equals aMessage.Id().
       
   764 */
       
   765 
       
   766 TBool CMsvScheduleSend::TaskAndMessageMatchL(const CMsvScheduledEntry& aMessage)
       
   767 	{
       
   768 	TMsvId id = 0;
       
   769 	TRAPD(err, id = GetMessageIdForTaskL(aMessage.iData.iTaskId));
       
   770 
       
   771 	SCHSENDLOG(FLog(_L8("\tGetMessageIdForTask [taskId=%d err=%d id=%d aMessage.Id=%d"), aMessage.iData.iTaskId, err, id, aMessage.Id()));
       
   772 	TBool match = EFalse;
       
   773  
       
   774 	if (err == KErrNone)
       
   775 		{
       
   776 		match = (id == aMessage.Id());
       
   777 		}
       
   778 	else if (err != KErrNotFound)
       
   779 		{
       
   780 		User::Leave(err);
       
   781 		}
       
   782  
       
   783 	return match;
       
   784 	}
       
   785 	
       
   786 void CMsvScheduleSend::ResetScheduleInfoForEntryL(CMsvScheduledEntry& aMessage, const TBool aChangeEntry)
       
   787 	{
       
   788 	// Reset the scheduling info in the entry.
       
   789 	TMsvId oldId = iServerEntry.Entry().Id();
       
   790 	User::LeaveIfError(iServerEntry.SetEntry(aMessage.Id()));
       
   791 	SendingCompleteL(aMessage, aChangeEntry);	
       
   792 	iServerEntry.SetEntry(oldId); // ignore any error	
       
   793 	}
       
   794 	
       
   795 void CMsvScheduleSend::DeleteScheduleForEntryL(CMsvScheduledEntry& aMessage)
       
   796 	{
       
   797 	//Connect and register with the task scheduler
       
   798 	//Delete the task from the task scheduler
       
   799 	ConnectAndRegisterL();
       
   800 
       
   801 	if (TaskAndMessageMatchL(aMessage))
       
   802 		{
       
   803 		TInt err = iScheduler.DeleteTask(aMessage.iData.iTaskId);
       
   804 
       
   805 		SCHSENDLOG(FLog(_L8("\tDeleteTask Task=%d, Err=%d"), aMessage.iData.iTaskId, err));
       
   806 
       
   807 		if (err != KErrNotFound)
       
   808 			User::LeaveIfError(err);
       
   809 
       
   810 		//Delete the schedule if there are no more tasks assigned to it
       
   811 
       
   812 		//Declare variable to pass into GetScheduleL()
       
   813 		TScheduleState2 schState;
       
   814 		TTsTime schDueTime;
       
   815 
       
   816 		// Get the schedule Type
       
   817 		TScheduleType scheduleType;
       
   818 		iScheduler.GetScheduleTypeL(aMessage.iData.iRef.iHandle, scheduleType);
       
   819 		iSchTaskInfo->Reset();
       
   820 		
       
   821 		// Depends on the Schedule Type
       
   822 		if (scheduleType == ETimeSchedule)
       
   823 		    {
       
   824 			//Get details of the existing time schedule
       
   825 			err = iScheduler.GetScheduleL(aMessage.iData.iRef.iHandle, schState, *iSchEntryInfo, *iSchTaskInfo, schDueTime);
       
   826 
       
   827 			SCHSENDLOG(FLog(_L8("\tGetScheduleL Sch=%d, Err=%d"), aMessage.iData.iRef.iHandle, err));
       
   828 		    }
       
   829 
       
   830 		else if (scheduleType == EConditionSchedule)
       
   831 		    {
       
   832 		    CArrayFixFlat<TTaskSchedulerCondition>* schConditions =
       
   833 		        new (ELeave) CArrayFixFlat<TTaskSchedulerCondition>(KMsvSchsendArrayGrowth);
       
   834 
       
   835 		    CleanupStack::PushL(schConditions);
       
   836 			//Get details of the existing condition schedule
       
   837 		    err = iScheduler.GetScheduleL(aMessage.iData.iRef.iHandle, schState, *schConditions, schDueTime, *iSchTaskInfo);
       
   838 
       
   839 			SCHSENDLOG(FLog(_L8("\tGetScheduleL Sch=%d, Err=%d"), aMessage.iData.iRef.iHandle, err));
       
   840 
       
   841 		    CleanupStack::PopAndDestroy(schConditions);
       
   842 
       
   843 		    }
       
   844 		else
       
   845 		    {
       
   846 		    User::Leave(KErrNotFound);
       
   847 		    }
       
   848 		    
       
   849 		if (!err)
       
   850 			{
       
   851 			if (iSchTaskInfo->Count() == 0)
       
   852 				{
       
   853 				SCHSENDLOG(FLog(_L8("\tDeleting schedule %d"), aMessage.iData.iRef.iHandle));
       
   854 				iScheduler.DeleteSchedule(aMessage.iData.iRef.iHandle); //ignore error
       
   855 				}
       
   856 			}
       
   857 		else if (err != KErrNotFound)
       
   858 			{
       
   859 			User::Leave(err);
       
   860 			}
       
   861 		}
       
   862 	}
       
   863 
       
   864 /**
       
   865 Determines whether the message should be sent and if so the time interval (in
       
   866 seconds) that must elapse before aMessage should be sent.
       
   867 
       
   868 The time interval is determined by the error action supplied. In the case of an
       
   869 error action of ESendActionRetryConditionMet, the time interval indicates how
       
   870 long the message can be pending conditions to be met before the message is failed.
       
   871 
       
   872 The actual time period is defined in the iSettings object. This will be either
       
   873 iPendingConditionsTimeout, iShortInterval, iLongInterval or an element of 
       
   874 iVariableIntervals.
       
   875 
       
   876 If the message should be sent then a value of ETrue is returned. A value of 
       
   877 EFalse is returned if the message should not be sent. In this case the output
       
   878 argument aInterval is not valid.
       
   879 
       
   880 @param	aMessage
       
   881 The message to be re-scheduled.
       
   882 
       
   883 @param	aErrorAction
       
   884 The error action that determines the re-schedule behaviour.
       
   885 
       
   886 @param	aInterval
       
   887 An output argument that holds the time interval to when the message should be
       
   888 re-sent or when the message should be failed.
       
   889 
       
   890 @return
       
   891 A value of ETrue if the message should be sent or EFalse if it should not
       
   892 */
       
   893 TBool CMsvScheduleSend::GetNextRetry(CMsvScheduledEntry& aMessage, const TMsvSendErrorAction& aErrorAction, TTimeIntervalSeconds& aInterval) const
       
   894 	{
       
   895 	TBool retVal = (aErrorAction.iAction != ESendActionFail);
       
   896 	aInterval = 0;
       
   897 	
       
   898 	if( retVal )
       
   899 		{
       
   900 		if( aErrorAction.iAction == ESendActionRetryConditionMet )
       
   901 			{
       
   902 			// Interval given by the agent actions timeout value.
       
   903 			aInterval = iSettings->PendingConditionsTimeout().Int() * 60;
       
   904 			}
       
   905 		else if( aErrorAction.iAction == ESendActionRetryImmediately )
       
   906 			{
       
   907 			aInterval = iSettings->ShortInterval();
       
   908 			}
       
   909 		else
       
   910 			{
       
   911 			if( aErrorAction.iRetrySpacing == ESendRetrySpacingVariable )
       
   912 				{
       
   913 				//Retrieve the variable spacing associated with the retry count
       
   914 				const CArrayFixFlat<TTimeIntervalSeconds>& varIntervals = iSettings->VariableIntervals();
       
   915 				const TInt count = varIntervals.Count();
       
   916 				const TInt retry = aMessage.iData.Retries();
       
   917 
       
   918 				if( count == 0 )
       
   919 					{
       
   920 					aInterval = iSettings->LongInterval();
       
   921 					}
       
   922 				else if( retry < count )
       
   923 					{
       
   924 					aInterval = varIntervals[retry];
       
   925 					}
       
   926 				else
       
   927 					{
       
   928 					aInterval = varIntervals[count - 1];
       
   929 					}
       
   930 				}
       
   931 			else 
       
   932 				{
       
   933 				// Got here then aScheduleAction.iRetrySpacing == EStatic.
       
   934 				aInterval = iSettings->LongInterval();
       
   935 				}
       
   936 
       
   937 			__ASSERT_DEBUG(aInterval.Int() > 0, gPanic(ERetryIntervalMustByPositive));
       
   938 			}
       
   939 		}
       
   940 	return retVal;
       
   941 	}
       
   942 
       
   943 /**
       
   944 Searches the scheduler for an existing schedule item with a schedule time that
       
   945 matches with time supplied.
       
   946 
       
   947 @see RScheduler::GetScheduleL()
       
   948 
       
   949 @param aScheduler
       
   950 Handle to the scheduler.
       
   951 
       
   952 @param aStartTime
       
   953 Schedule start time.
       
   954 
       
   955 @param aRef
       
   956 On return, the schedule item.
       
   957 
       
   958 @leave KErrNotFound
       
   959 No schedule found matching the schedule time.
       
   960 */
       
   961 EXPORT_C void CMsvScheduleSend::FindScheduleL(RScheduler& aScheduler, const TTime& aStartTime, TSchedulerItemRef& aRef)
       
   962 	{
       
   963 	CArrayFixFlat<TScheduleEntryInfo2>* entryInfos = new (ELeave) CArrayFixFlat<TScheduleEntryInfo2>(1);
       
   964 	CleanupStack::PushL(entryInfos);
       
   965 
       
   966 	CArrayFixFlat<TTaskInfo>* taskInfos = new (ELeave) CArrayFixFlat<TTaskInfo>(1);
       
   967 	CleanupStack::PushL(taskInfos);
       
   968 
       
   969 	aRef.iHandle = KErrNotFound;
       
   970 
       
   971 	CArrayFixFlat<TSchedulerItemRef>* refs = new (ELeave) CArrayFixFlat<TSchedulerItemRef>(KMsvSchsendArrayGrowth);
       
   972 	CleanupStack::PushL(refs);
       
   973 
       
   974 	User::LeaveIfError(aScheduler.GetTaskRefsL(*refs, EAllSchedules, EMyTasks));
       
   975 
       
   976 	TInt count = refs->Count();
       
   977 	TScheduleState2 state;
       
   978 	TTsTime nextDue;
       
   979 
       
   980 	while (count-- && aRef.iHandle == KErrNotFound)
       
   981 		{
       
   982 		const TSchedulerItemRef& tempRef = (*refs)[count];
       
   983 
       
   984 		TScheduleType type;
       
   985 		User::LeaveIfError(aScheduler.GetScheduleTypeL(tempRef.iHandle, type));
       
   986 		if( type == ETimeSchedule )
       
   987 			{
       
   988 			entryInfos->Reset();
       
   989 			taskInfos->Reset();
       
   990 			const TInt err = aScheduler.GetScheduleL(tempRef.iHandle, state, *entryInfos, *taskInfos, nextDue);
       
   991 			if( err == KErrNone && nextDue.GetUtcTime() == aStartTime )
       
   992 				aRef = tempRef;
       
   993 			}
       
   994 		}
       
   995 
       
   996 	CleanupStack::PopAndDestroy(3, entryInfos);
       
   997 	if (aRef.iHandle == KErrNotFound)
       
   998 		User::Leave(KErrNotFound);
       
   999 	}
       
  1000 
       
  1001 /**
       
  1002 Searches the scheduler for an existing conditions schedule item with a set of 
       
  1003 pending conditions and timeout value that matches with those supplied.
       
  1004 
       
  1005 @see RScheduler::GetScheduleL
       
  1006 
       
  1007 @param aScheduler
       
  1008 Handle to the scheduler.
       
  1009 
       
  1010 @param aConditions
       
  1011 The set of System Agent conditions that are required to be met to trigger the
       
  1012 schedule.
       
  1013 
       
  1014 @param aTimeout
       
  1015 The timeout value for the schedule.
       
  1016 
       
  1017 @param aRef
       
  1018 On return, the schedule item.
       
  1019 
       
  1020 @leave KErrNotFound
       
  1021 No schedule found matching the schedule conditions and timeout.
       
  1022 */
       
  1023 EXPORT_C void CMsvScheduleSend::FindScheduleL(
       
  1024 								RScheduler&										aScheduler, 
       
  1025 								const CArrayFixFlat<TTaskSchedulerCondition>&	aConditions, 
       
  1026 								const TTime&									aTimeout, 
       
  1027 								TSchedulerItemRef& 								aRef)
       
  1028 	{
       
  1029 	CArrayFixFlat<TTaskSchedulerCondition>* schConditions = new (ELeave) CArrayFixFlat<TTaskSchedulerCondition>(KMsvSchsendArrayGrowth);
       
  1030 	CleanupStack::PushL(schConditions);
       
  1031 
       
  1032 	CArrayFixFlat<TTaskInfo>* taskInfos = new (ELeave) CArrayFixFlat<TTaskInfo>(1);
       
  1033 	CleanupStack::PushL(taskInfos);
       
  1034 
       
  1035 	aRef.iHandle = KErrNotFound;
       
  1036 
       
  1037 	CArrayFixFlat<TSchedulerItemRef>* refs = new (ELeave) CArrayFixFlat<TSchedulerItemRef>(KMsvSchsendArrayGrowth);
       
  1038 	CleanupStack::PushL(refs);
       
  1039 	
       
  1040 	User::LeaveIfError(aScheduler.GetTaskRefsL(*refs, EAllSchedules, EMyTasks));
       
  1041 
       
  1042 	TInt count = refs->Count();
       
  1043 	TScheduleState2 state;
       
  1044 	TTsTime nextTimeout;
       
  1045 	
       
  1046 	while( count-- && aRef.iHandle == KErrNotFound )
       
  1047 		{
       
  1048 		const TSchedulerItemRef& tempRef = (*refs)[count];
       
  1049 
       
  1050 		TScheduleType type;
       
  1051 		User::LeaveIfError(aScheduler.GetScheduleTypeL(tempRef.iHandle, type));
       
  1052 		if( type == EConditionSchedule )
       
  1053 			{
       
  1054 			taskInfos->Reset();
       
  1055 			const TInt err = aScheduler.GetScheduleL(tempRef.iHandle, state, *schConditions, nextTimeout, *taskInfos);
       
  1056 			if( err == KErrNone && nextTimeout.GetUtcTime() == aTimeout && *schConditions == aConditions )
       
  1057 				aRef = tempRef;
       
  1058 			}
       
  1059 		}
       
  1060 
       
  1061 	CleanupStack::PopAndDestroy(3, schConditions);
       
  1062 	if (aRef.iHandle == KErrNotFound)
       
  1063 		User::Leave(KErrNotFound);
       
  1064 	}	
       
  1065 
       
  1066 void CMsvScheduleSend::FindScheduleL(const TTime& aTime, const CArrayFixFlat<TTaskSchedulerCondition>& aSchConditions, TBool aPendingConditions, TSchedulerItemRef& aRef)
       
  1067 	{
       
  1068 	if( aPendingConditions )
       
  1069 		FindScheduleL(iScheduler, aSchConditions, aTime, aRef);
       
  1070 	else
       
  1071 		FindScheduleL(iScheduler, aTime, aRef);
       
  1072 	}
       
  1073 	
       
  1074 /**
       
  1075 Does the actual scheduling of the supplied messages.
       
  1076 
       
  1077 This function is called by ScheduleL() and DoReScheduleL(). The supplied messages
       
  1078 are assumed to have the values for the following data - MTM UID, off-peak flag,
       
  1079 schedule date and pending conditions flag. In debug mode, if these info is 
       
  1080 matching in all the messages then a panic will occur.
       
  1081 
       
  1082 @param	aSchEntries
       
  1083 An array with the messages to be scheduled.
       
  1084 
       
  1085 @param	aCommandId
       
  1086 The command id that must be used by the Send.Exe to eventually send the messages.
       
  1087 
       
  1088 @param	aFinalState
       
  1089 The sending state to set to the messages to if the message is successfully 
       
  1090 scheduled.
       
  1091 
       
  1092 @param	aTime
       
  1093 For conditions-scheduled messages this is the timeout, for time-scheduled messages
       
  1094 this is the scheduled time.
       
  1095 
       
  1096 @param 	aPendingConditions
       
  1097 A flag indicating whether the schedule should be pending conditions.
       
  1098 */
       
  1099 void CMsvScheduleSend::DoScheduleL(CMsvScheduledEntries& aSchEntries, const TInt aFinalState, const TTime& aTime, TBool aPendingConditions)
       
  1100 	{
       
  1101 	__ASSERT_DEBUG(aSchEntries.Count(), gPanic(EMessageSelectionEmpty));
       
  1102 	
       
  1103 #ifdef _DEBUG
       
  1104 	// Check that the mtm, time, off peak flag and pending conditions flag are 
       
  1105 	// the same for every message.
       
  1106 	TInt count = aSchEntries.Count();
       
  1107 	CMsvScheduledEntry* schEntry = aSchEntries[0];
       
  1108 
       
  1109 	while (count--)
       
  1110 		{
       
  1111 		CMsvScheduledEntry* entry = aSchEntries[count];
       
  1112 
       
  1113 		__ASSERT_DEBUG(entry->Mtm() == schEntry->Mtm(), gPanic(EMessagesNotSameMtm));
       
  1114 		__ASSERT_DEBUG((entry->OffPeak() && schEntry->OffPeak()) || (!entry->OffPeak() && !schEntry->OffPeak()), gPanic(EMessagesNotSameOffPeak));
       
  1115 		__ASSERT_DEBUG(entry->ScheduleDate() == schEntry->ScheduleDate(), gPanic(EMessagesNotSameTime));
       
  1116 		__ASSERT_DEBUG(entry->PendingConditions() == schEntry->PendingConditions(), gPanic(EMessagesNotSamePendingConditions));
       
  1117 		schEntry = entry;
       
  1118 		}
       
  1119 #endif
       
  1120 
       
  1121 	// Connect and register with the task scheduler
       
  1122 	ConnectAndRegisterL();
       
  1123 	
       
  1124 	// Determine the start time and validity period
       
  1125 	TTime latencyTime;
       
  1126 	latencyTime.UniversalTime();
       
  1127 	latencyTime += iSettings->Latency();
       
  1128 	TTime startTime = latencyTime;
       
  1129 
       
  1130 	if( aTime > startTime )
       
  1131 		{
       
  1132 		// The schedule time is in the future or there is no schedule time
       
  1133 		// (the messages are pending conditions) - update the start time.
       
  1134 		startTime = aTime;
       
  1135 		}
       
  1136 
       
  1137 	TTimeIntervalMinutes valPeriod = iSettings->ValidityPeriod();
       
  1138 	CMsvScheduledEntry* firstMessage = aSchEntries[0];
       
  1139 
       
  1140 	// Determine the start time and validity period of the new schedule - this
       
  1141 	// is not applicable if the messages are schedule for pending conditions.
       
  1142 	if( firstMessage->OffPeak() && !aPendingConditions )
       
  1143 		{
       
  1144 		GetOffPeakL(startTime, startTime, valPeriod);
       
  1145 		}
       
  1146 
       
  1147 	CArrayFixFlat<TTaskSchedulerCondition>* schConditions = new (ELeave) CArrayFixFlat<TTaskSchedulerCondition>(KMsvSchsendArrayGrowth);
       
  1148 	CleanupStack::PushL(schConditions);
       
  1149 	if( aPendingConditions )
       
  1150 		PopulateScheduleConditionsL(*schConditions);
       
  1151 
       
  1152 	// Create a schedule
       
  1153 	TSchedulerItemRef schItemRef;
       
  1154 	TBool schFound = EFalse;
       
  1155 
       
  1156 	// Check to see if a schedule already exists for this particular schedule.
       
  1157 	// Need to consider both the start time and if the schedule is for pending
       
  1158 	// conditions met.
       
  1159 	// NOTE - if the schedule time is not in the future, then there is no need 
       
  1160 	// to search for an existing schedule.	
       
  1161 	if( startTime > latencyTime )
       
  1162 		{
       
  1163 		if( startTime != Time::MaxTTime() )
       
  1164 			RoundUpToMinute(startTime);
       
  1165 		
       
  1166 		TRAPD(err,FindScheduleL(startTime, *schConditions, aPendingConditions, schItemRef));
       
  1167 		if( err == KErrNone )
       
  1168 			{
       
  1169 			SCHSENDLOG(FLog(_L("\tFound schedule %d"), schItemRef.iHandle));
       
  1170 			schFound = ETrue;
       
  1171 			}
       
  1172 		// Else ignore the error and create and new schedule.
       
  1173 		}
       
  1174 
       
  1175 	if( !schFound )
       
  1176 		{
       
  1177 		// The appropriate schedule.
       
  1178 		CreateScheduleL(startTime, valPeriod, *schConditions, aPendingConditions, schItemRef);
       
  1179 		}
       
  1180 
       
  1181 	CleanupStack::PopAndDestroy(schConditions);
       
  1182 	
       
  1183 	// Disable the schedule so that it doesn't fire while scheduling
       
  1184 	User::LeaveIfError(iScheduler.DisableSchedule(schItemRef.iHandle));
       
  1185 
       
  1186 	// Schedule the messages
       
  1187 	const TInt messageCount = aSchEntries.Count();
       
  1188 	TInt schErr = KErrNone;
       
  1189 	TInt curMsg;
       
  1190 
       
  1191 	for( curMsg = 0; curMsg < messageCount; ++curMsg ) // must forward traverse the array
       
  1192 		{
       
  1193 		CMsvScheduledEntry* message = aSchEntries[curMsg];
       
  1194 
       
  1195 		message->SetScheduleDate(startTime);
       
  1196 		TRAP(schErr, ScheduleEntryL(*message, aFinalState, startTime, schItemRef, aPendingConditions));
       
  1197 
       
  1198 		if( schErr != KErrNone )
       
  1199 			break;
       
  1200 		}
       
  1201 
       
  1202 	if( schErr != KErrNone && curMsg == 0 && !schFound )
       
  1203 		{
       
  1204 		iScheduler.DeleteSchedule(schItemRef.iHandle); // ignore error
       
  1205 		}
       
  1206 	else
       
  1207 		{
       
  1208 		User::LeaveIfError(iScheduler.EnableSchedule(schItemRef.iHandle));
       
  1209 		}
       
  1210 		
       
  1211 	User::LeaveIfError(schErr);
       
  1212 	}
       
  1213 
       
  1214 /**
       
  1215 Creates a new schedule on the task scheduler with which each message can be 
       
  1216 associated. 
       
  1217 
       
  1218 The schedule is triggered by a start time being reached.
       
  1219 
       
  1220 @see RScheduler::CreatePersistentSchedule
       
  1221 
       
  1222 @param aScheduler
       
  1223 Handle to scheduler to update.
       
  1224 
       
  1225 @param aSettings
       
  1226 Scheduler settings.
       
  1227 
       
  1228 @param aStartTime
       
  1229 Schedule start time.
       
  1230 
       
  1231 @param aValidityPeriod
       
  1232 Schedule validity period.
       
  1233 
       
  1234 @param aRef 
       
  1235 On return, the new schedule.
       
  1236 */
       
  1237 EXPORT_C void CMsvScheduleSend::CreateScheduleL(RScheduler& aScheduler, const CMsvScheduleSettings& aSettings, const TTime& aStartTime, const TTimeIntervalMinutes& aValidityPeriod, TSchedulerItemRef& aRef)
       
  1238 	{
       
  1239 	//Determine the new schedule entry	
       
  1240 	TScheduleEntryInfo2 taskInfo;
       
  1241 	taskInfo.SetIntervalType(aSettings.IntervalType());
       
  1242 	taskInfo.SetInterval(1);
       
  1243 	TTsTime startTime(aStartTime,ETrue);
       
  1244 	taskInfo.SetStartTime(startTime);
       
  1245 	taskInfo.SetValidityPeriod(aValidityPeriod);
       
  1246 	
       
  1247 	//Create the TScheduleEntryInfo arrag that is required by CreatePersistentSchedule
       
  1248 	CArrayFixFlat<TScheduleEntryInfo2>* entryInfos = new (ELeave) CArrayFixFlat<TScheduleEntryInfo2>(1);
       
  1249 	CleanupStack::PushL(entryInfos);
       
  1250 
       
  1251 	//Append the new schedule entry
       
  1252 	entryInfos->AppendL(taskInfo);
       
  1253 
       
  1254 	//Create the schedule
       
  1255 	User::LeaveIfError(aScheduler.CreatePersistentSchedule(aRef, *entryInfos));
       
  1256 
       
  1257 	CleanupStack::PopAndDestroy(entryInfos);
       
  1258 	}
       
  1259 
       
  1260 /**
       
  1261 Creates a new schedule on the task scheduler with which each message can be 
       
  1262 associated.
       
  1263 
       
  1264 The schedule is triggered by either a set of conditions being met or a timeout
       
  1265 being reached.
       
  1266 
       
  1267 @see RScheduler::CreatePersistentSchedule
       
  1268 @see TSysAgentCondition
       
  1269 
       
  1270 @param aScheduler
       
  1271 Handle to scheduler to update.
       
  1272 
       
  1273 @param aConditions
       
  1274 The set of System Agent conditions that are required to be met to trigger the
       
  1275 schedule.
       
  1276 
       
  1277 @param aTimeout
       
  1278 The timeout value for the schedule.
       
  1279 
       
  1280 @param aRef 
       
  1281 On return, the new schedule.
       
  1282 */
       
  1283 EXPORT_C void CMsvScheduleSend::CreateScheduleL(
       
  1284 								RScheduler& 									aScheduler, 
       
  1285 								const CArrayFixFlat<TTaskSchedulerCondition>&	aConditions, 
       
  1286 								const TTime& 									aTimeout,
       
  1287 								TSchedulerItemRef& 								aRef)
       
  1288 	{
       
  1289 	TTsTime timeout(aTimeout,ETrue);
       
  1290 	User::LeaveIfError(aScheduler.CreatePersistentSchedule(aRef, aConditions, timeout));	
       
  1291 	}
       
  1292 		
       
  1293 void CMsvScheduleSend::CreateScheduleL(const TTime& aTime, const TTimeIntervalMinutes& aValidityPeriod, const CArrayFixFlat<TTaskSchedulerCondition>& aSchConditions, TBool aPendingConditions, TSchedulerItemRef& aRef)
       
  1294 	{
       
  1295 	if( aPendingConditions )
       
  1296 		{
       
  1297 		CreateScheduleL(iScheduler, aSchConditions, aTime, aRef);
       
  1298 	#ifndef _MSG_NO_LOGGING
       
  1299 		TBuf<32> bufDate;
       
  1300 		aTime.FormatL(bufDate, _L("%D%M%Y%/0%1%/1%2%/2%3%/3 %-B%:0%J%:1%T%:2%S%.%*C4%:3%+B"));
       
  1301 		SCHSENDLOG(FLog(_L("\tCreated Schedule %d for pending %d conditions or %S"), aRef.iHandle, aSchConditions.Count(), &bufDate));
       
  1302 	#endif		
       
  1303 		}
       
  1304 	else
       
  1305 		{		
       
  1306 		CreateScheduleL(iScheduler, *iSettings, aTime, aValidityPeriod, aRef);
       
  1307 	#ifndef _MSG_NO_LOGGING
       
  1308 		TBuf<32> bufDate;
       
  1309 		aTime.FormatL(bufDate, _L("%D%M%Y%/0%1%/1%2%/2%3%/3 %-B%:0%J%:1%T%:2%S%.%*C4%:3%+B"));
       
  1310 		SCHSENDLOG(FLog(_L("\tCreated Schedule %d for %S"), aRef.iHandle, &bufDate));
       
  1311 	#endif
       
  1312 		}
       
  1313 	}
       
  1314 	
       
  1315 /**
       
  1316 Adds an entry to an existing schedule.
       
  1317 
       
  1318 @see RScheduler::ScheduleTask()
       
  1319 
       
  1320 @param aScheduler 
       
  1321 Scheduler to access.
       
  1322 
       
  1323 @param aRef 
       
  1324 Id of the schedule.
       
  1325 
       
  1326 @param aPackage 
       
  1327 Scheduler settings.
       
  1328 
       
  1329 @param aInfo 
       
  1330 Information about the entry to be added to the schedule.
       
  1331 
       
  1332 @leave KErrNotFound
       
  1333 No existing schedule with the specified Id.
       
  1334 */
       
  1335 EXPORT_C void CMsvScheduleSend::ScheduleEntryL(RScheduler& aScheduler, const TSchedulerItemRef& aRef, const TMsvSchedulePackage& aPackage, TTaskInfo& aInfo)
       
  1336 	{
       
  1337 	aInfo.iPriority	= EDefaultTaskPriority;
       
  1338 	aInfo.iRepeat	= EDefaultTaskRepeat;
       
  1339 
       
  1340 	HBufC* hBuf = NULL;
       
  1341 	aPackage.PackLC(aInfo, hBuf);
       
  1342 
       
  1343 	//Schedule the task
       
  1344 	User::LeaveIfError(aScheduler.ScheduleTask(aInfo, *hBuf, aRef.iHandle));
       
  1345 
       
  1346 	CleanupStack::PopAndDestroy(hBuf);
       
  1347 	}
       
  1348 
       
  1349 /**
       
  1350 Schedules aMessage on the schedule referred to by aRef.
       
  1351 
       
  1352 Updates the message entry and the schedule data using the utility function 
       
  1353 UpdateEntryAfterSchedule().
       
  1354 
       
  1355 @see	CMsvScheduleSend::UpdateEntryAfterSchedule
       
  1356 
       
  1357 @param	aMessage
       
  1358 The message to be scheduled.
       
  1359 
       
  1360 @param	aFinalState
       
  1361 The sending state to set to the messages to if the message is successfully 
       
  1362 scheduled.
       
  1363 
       
  1364 @param	aFromTime
       
  1365 The time to schedule the messages for sending.
       
  1366 
       
  1367 @param	aRef
       
  1368 The ID of the schedule to add this task to.
       
  1369 
       
  1370 @param	aPendingConditions
       
  1371 A flag indicating whether this message is schedule for conditions.
       
  1372 */
       
  1373 void CMsvScheduleSend::ScheduleEntryL(CMsvScheduledEntry& aMessage, const TInt aFinalState, const TTime& aStartTime, const TSchedulerItemRef& aRef, TBool aPendingConditions)
       
  1374 	{
       
  1375 	//Create a new task to associate with the schedule
       
  1376 	TTaskInfo taskInfo;
       
  1377 	iPackage.iId = aMessage.Id();
       
  1378 	
       
  1379 	ScheduleEntryL(iScheduler, aRef, iPackage, taskInfo);
       
  1380 
       
  1381 	// Change the scheduled flag and sending state of the message
       
  1382 	if( iServerEntry.SetEntry(aMessage.Id()) == KErrNone )
       
  1383 		{
       
  1384 		TMsvEntry entry(iServerEntry.Entry());
       
  1385 
       
  1386 		aMessage.Entry(entry);
       
  1387 		UpdateEntryAfterSchedule(aRef, taskInfo, aStartTime, aFinalState, entry, aMessage.iData);
       
  1388 		entry.SetPendingConditions(aPendingConditions);
       
  1389 
       
  1390 		SCHSENDLOG(FLog(_L8("\t\tScheduled msg %d (Mtm=%d, State=%d, Sch=%d, Task=%d, Pending=%d)"), entry.Id(), entry.iMtm.iUid, aFinalState, aMessage.iData.iRef.iHandle, aMessage.iData.iTaskId, entry.PendingConditions()));
       
  1391 
       
  1392 		User::LeaveIfError(iServerEntry.ChangeEntry(entry));
       
  1393 
       
  1394 		//Store the message data
       
  1395 		CMsvStore* store = iServerEntry.EditStoreL();
       
  1396 		CleanupStack::PushL(store);
       
  1397 		aMessage.StoreL(*store);
       
  1398 		store->CommitL();
       
  1399 		CleanupStack::PopAndDestroy(store);
       
  1400 		iServerEntry.SetEntry(KMsvNullIndexEntryId);
       
  1401 		}
       
  1402 	}
       
  1403 
       
  1404 /**
       
  1405 Utility function that updates message index entry fields to reflect 
       
  1406 the message's scheduling.
       
  1407 
       
  1408 @param aRef 
       
  1409 Scheduler item.
       
  1410 
       
  1411 @param aInfo 
       
  1412 Scheduler task information.
       
  1413 
       
  1414 @param aTime 
       
  1415 Schedule start time.
       
  1416 
       
  1417 @param aFinalState 
       
  1418 Sending state flag.
       
  1419 
       
  1420 @param aEntry 
       
  1421 On return, updated index entry.
       
  1422 
       
  1423 @param aData 
       
  1424 On return, populated messaging scheduling data.
       
  1425 */
       
  1426 EXPORT_C void CMsvScheduleSend::UpdateEntryAfterSchedule(const TSchedulerItemRef& aRef, const TTaskInfo& aInfo, const TTime& aTime, TInt aFinalState, TMsvEntry& aEntry, TMsvEntryScheduleData& aData)
       
  1427 	{
       
  1428 	aEntry.SetScheduled(ETrue);
       
  1429 	aEntry.SetFailed(EFalse);
       
  1430 	aEntry.SetSendingState(aFinalState);
       
  1431 	aEntry.SetConnected(EFalse);
       
  1432 	aEntry.iDate = aTime;
       
  1433 	aData.iRef = aRef;
       
  1434 	aData.iTaskId = aInfo.iTaskId;
       
  1435 	}
       
  1436 
       
  1437 /**
       
  1438 Sorts the supplied array of messages.
       
  1439 
       
  1440 The messages are sorted by their schedule date (held in the iEntry.iDate member
       
  1441 of CMsvScheduledEntry). Messages with the same schedule time are then further
       
  1442 sorted by if they to be scheduled for pending conditions.
       
  1443 
       
  1444 @param	aSchEntries
       
  1445 The input/output parameter that holds the messages to be sorted. This will 
       
  1446 contain the sorted list once the function completes.
       
  1447 */
       
  1448 void CMsvScheduleSend::SortByDateAndPendingConditionsL(CMsvScheduledEntries& aSchEntries)
       
  1449 	{
       
  1450 	//TO DO: Test this function!!!
       
  1451 
       
  1452 	TInt count = aSchEntries.Count();
       
  1453 	CMsvScheduledEntry* curEntry = NULL;
       
  1454 	CMsvScheduledEntry* compEntry = NULL;
       
  1455 
       
  1456 	for (TInt i = 0; i < count - 1; ++i)
       
  1457 		{
       
  1458 		curEntry = aSchEntries[i];
       
  1459 
       
  1460 		for (TInt j = i + 1; j < count; ++j)
       
  1461 			{
       
  1462 			compEntry = aSchEntries[j];
       
  1463 
       
  1464 			//Compare the dates of the two entries
       
  1465 			if( curEntry->ScheduleDate() > compEntry->ScheduleDate() ||
       
  1466 				(curEntry->ScheduleDate() == compEntry->ScheduleDate() &&
       
  1467 				curEntry->PendingConditions() && !compEntry->PendingConditions()) )
       
  1468 				{
       
  1469 				//Swap them
       
  1470 				aSchEntries.Delete(i);
       
  1471 				aSchEntries.InsertL(i, compEntry);
       
  1472 				aSchEntries.Delete(j);
       
  1473 				aSchEntries.InsertL(j, curEntry);
       
  1474 				}
       
  1475 			}
       
  1476 		}
       
  1477 	}
       
  1478 
       
  1479 void CMsvScheduleSend::GetMessagesL(const CMsvEntrySelection& aSelection)
       
  1480 	{
       
  1481 	iSchEntries->ResetAndDestroy();
       
  1482 
       
  1483 	const TInt entryCount = aSelection.Count();
       
  1484 
       
  1485 	iSchEntries->SetReserveL(entryCount); //so following AppendL()s won't leave
       
  1486 
       
  1487 	CMsvScheduledEntry* schEntry = NULL;
       
  1488 
       
  1489 	for (TInt curMsg = 0; curMsg < entryCount; ++curMsg) //not while because must transverse forward
       
  1490 		{
       
  1491 		//Retrieve each message from the message server
       
  1492 		TMsvId msvId = aSelection.At(curMsg);
       
  1493 
       
  1494 		TRAPD(error, schEntry = GetMessageL(msvId));
       
  1495 
       
  1496 		if (error == KErrNone)
       
  1497 			{
       
  1498 			CleanupStack::PushL(schEntry);
       
  1499 			iSchEntries->AppendL(schEntry);
       
  1500 			CleanupStack::Pop(schEntry);
       
  1501 			}
       
  1502 		else if (error != KErrLocked && error != KErrNotFound)
       
  1503 			{
       
  1504 			User::Leave(error);
       
  1505 			}
       
  1506 		}
       
  1507 	}
       
  1508 
       
  1509 /**
       
  1510 Connects to and registers with the task scheduler.
       
  1511 
       
  1512 @param aScheduler 
       
  1513 Handle to the scheduler to connect to.
       
  1514 
       
  1515 @param aSettings 
       
  1516 Schedule settings.
       
  1517 
       
  1518 @leave Any error code
       
  1519 RScheduler::Connect() returned an error.
       
  1520 
       
  1521 @leave Any error code
       
  1522 RFs::Connect() returned an error.
       
  1523 
       
  1524 @leave KErrPathNotFound
       
  1525 The .EXE file to be called by the Task Scheduler when messages are due to 
       
  1526 be sent cannot be found. The filename is part of the schedule settings.
       
  1527 
       
  1528 @leave Any error code
       
  1529 RScheduler::Register() returned an error.
       
  1530 */
       
  1531 
       
  1532 EXPORT_C void CMsvScheduleSend::ConnectAndRegisterL(RScheduler& aScheduler, const CMsvScheduleSettings& aSettings)
       
  1533 	{
       
  1534 	//Connect to the task scheduler
       
  1535 	User::LeaveIfError(aScheduler.Connect());
       
  1536 
       
  1537 	// Register the schsendexe.exe as the executable to run when the schedule
       
  1538 	// fires.
       
  1539 	User::LeaveIfError(aScheduler.Register(KSchSendExe(), aSettings.Priority()));
       
  1540 	}
       
  1541 
       
  1542 
       
  1543 void CMsvScheduleSend::ConnectAndRegisterL()
       
  1544 	{
       
  1545 	//Check to see whether already registered.
       
  1546 	if (iRegistered)
       
  1547 		{
       
  1548 		return;
       
  1549 		}
       
  1550 
       
  1551 	ConnectAndRegisterL(iScheduler, *iSettings);
       
  1552 
       
  1553 	//No errors, so set iRegistered to true.
       
  1554 	iRegistered = ETrue;
       
  1555 	}
       
  1556 
       
  1557 /*
       
  1558 	Retrieves the system off-peak times and
       
  1559 	updates aStartTime and aValidityPeriod
       
  1560 */
       
  1561 
       
  1562 void CMsvScheduleSend::GetOffPeakL(TTime aFromTime, TTime& aStartTime, TTimeIntervalMinutes& aValidityPeriod) const
       
  1563 	{
       
  1564 	__ASSERT_DEBUG(iOffPeakTimes->Count() > 0, gPanic(EOffPeakTimesEmpty));
       
  1565 	
       
  1566 	TMsvOffPeakTime opTime;
       
  1567 
       
  1568 	TTime offPeakStart;
       
  1569 	User::LeaveIfError(iOffPeakTimes->GetNextOffPeakTime(aFromTime, opTime, offPeakStart));
       
  1570 
       
  1571 	aValidityPeriod = opTime.ValidityPeriod();
       
  1572 
       
  1573 	if (offPeakStart < aFromTime) 
       
  1574 		{ //aFromTime is within an off peak time
       
  1575 		aStartTime = aFromTime;
       
  1576 
       
  1577 		TTimeIntervalMinutes mins;
       
  1578 		aStartTime.MinutesFrom(offPeakStart, mins);
       
  1579 		TInt minsInt = mins.Int();
       
  1580 
       
  1581 		__ASSERT_DEBUG(minsInt >= 0, gPanic(EInvalidValidityPeriod));
       
  1582 
       
  1583 		aValidityPeriod = opTime.ValidityPeriod();
       
  1584 
       
  1585 		aValidityPeriod = (TTimeIntervalMinutes) (aValidityPeriod.Int() - minsInt);
       
  1586 		}
       
  1587 	else
       
  1588 		{
       
  1589 		aStartTime = offPeakStart;
       
  1590 		}
       
  1591 
       
  1592 	//To Do: Remove next line after testing
       
  1593 	__ASSERT_DEBUG(aValidityPeriod.Int() > 0, gPanic(EInvalidValidityPeriod));
       
  1594 	}
       
  1595 
       
  1596 void CMsvScheduleSend::PopulateScheduleConditionsL(CArrayFixFlat<TTaskSchedulerCondition>& aSchConditions)
       
  1597 	{
       
  1598 	aSchConditions.Reset();
       
  1599 
       
  1600 	TInt count = iAgentActions->Count();
       
  1601 	TTaskSchedulerCondition condition;
       
  1602 	
       
  1603 	// All system agent condition have a UID of KUidSystemCategory.
       
  1604 	condition.iCategory = KUidSystemCategory;
       
  1605 	
       
  1606 	for( TInt i = 0; i < count; ++i )
       
  1607 		{
       
  1608 
       
  1609 		TMsvCondition agentCondition = iAgentActions->At(i).iCondition;
       
  1610 
       
  1611 		condition.iKey	 = agentCondition.iVariable.iUid;
       
  1612 		condition.iState = agentCondition.iState;
       
  1613 		
       
  1614 		switch( agentCondition.iType )
       
  1615 			{
       
  1616 		case TMsvCondition::EMsvSchSendEquals:
       
  1617 			condition.iType = TTaskSchedulerCondition::EEquals;
       
  1618 			break;
       
  1619 		case TMsvCondition::EMsvSchSendNotEquals:
       
  1620 			condition.iType = TTaskSchedulerCondition::ENotEquals;
       
  1621 			break;
       
  1622 		case TMsvCondition::EMsvSchSendGreaterThan:
       
  1623 			condition.iType = TTaskSchedulerCondition::EGreaterThan;
       
  1624 			break;
       
  1625 		case TMsvCondition::EMsvSchSendLessThan:
       
  1626 			condition.iType = TTaskSchedulerCondition::ELessThan;
       
  1627 			break;
       
  1628 		default:
       
  1629 			User::Invariant();
       
  1630 			break;
       
  1631 			}
       
  1632 			
       
  1633 		aSchConditions.AppendL(condition);
       
  1634 		}
       
  1635 	}
       
  1636 	
       
  1637 _LIT(KScheduleSendPanic, "ScheduleSend-DLL");
       
  1638 
       
  1639 GLDEF_C void gPanic(TScheduleSendPanic aPanic)
       
  1640 	{
       
  1641 	User::Panic(KScheduleSendPanic,aPanic);
       
  1642 	}
       
  1643 
       
  1644 
       
  1645 #ifndef _MSG_NO_LOGGING
       
  1646 void CMsvScheduleSend::FLog(TRefByValue<const TDesC> aFormat, ...)
       
  1647 	{
       
  1648 	VA_LIST list;
       
  1649 	VA_START(list, aFormat);
       
  1650 	RFileLogger::WriteFormat(KSchSendLogDir, KSchSendLogFile, EFileLoggingModeAppend,
       
  1651 		aFormat, list);
       
  1652 	}
       
  1653 
       
  1654 void CMsvScheduleSend::FLog(TRefByValue<const TDesC8> aFormat, ...)
       
  1655 	{
       
  1656 	VA_LIST list;
       
  1657 	VA_START(list, aFormat);
       
  1658 	RFileLogger::WriteFormat(KSchSendLogDir, KSchSendLogFile, EFileLoggingModeAppend,
       
  1659 		aFormat, list);
       
  1660 	}
       
  1661 #endif