|
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 |