|
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 // Implementation for a CActive based class that monitors for low disk space |
|
15 // and is informed when a PDU is being received. Should memory be too low, |
|
16 // an error code is returned causing a NAck. The class will then monitor |
|
17 // for the point at which PDUs can be received again, and a Resume Reception |
|
18 // will be sent to the network. |
|
19 // The are two limits - a high limit for general SMSs and a low limit for |
|
20 // class 0 SMSs. However there is only one way to resume reception of SMSs. So |
|
21 // once a resume reception is sent, it resumes hoth types of SMSs. The algorithm |
|
22 // is a bit simiplier because of this: |
|
23 // IF sending non-Class 0 AND we are below the high limit THEN |
|
24 // N'Ack SMS |
|
25 // IF not waiting for free diskspace THEN |
|
26 // Wait for free diskspace to rise above the high limit |
|
27 // Resume SMS Reception. |
|
28 // ELSE |
|
29 // Continue waiting for either high limit or low limit |
|
30 // Resume SMS Reception as previously intended |
|
31 // END_IF |
|
32 // ELSE IF sending Class 0 AND we are below the low limit THEN |
|
33 // Wait for free diskspace to rise above the low limit |
|
34 // Resume SMS Reception. |
|
35 // END_IF |
|
36 // Note that in the second and last case, SMS reception may be resumed before |
|
37 // we are above the high limit, but in that case montioring will repeat when |
|
38 // the next non-class 0 SMS is attempted to be delivered. This is necessary as |
|
39 // there is no way to resume just class 0 SMSs. |
|
40 // |
|
41 // |
|
42 |
|
43 /** |
|
44 @file |
|
45 @internalComponent |
|
46 */ |
|
47 |
|
48 #include <barsc.h> |
|
49 #include <bautils.h> |
|
50 |
|
51 #include "smspcomm.h" |
|
52 #include "smspmondsk.h" |
|
53 #include "smsstacklog.h" |
|
54 #include "smspmain.h" |
|
55 #include "smspver.h" |
|
56 #include <smsu.rsg> |
|
57 |
|
58 |
|
59 _LIT(KSmsResourceFile, "sms\\smsu.rsc"); |
|
60 |
|
61 |
|
62 /** |
|
63 * 2 phase constructor. |
|
64 * |
|
65 * @leave Leaves if not enough memory is available. |
|
66 * |
|
67 * @return a newly created CSmsMonitorDiskSpace object. |
|
68 */ |
|
69 CSmsMonitorDiskSpace* CSmsMonitorDiskSpace::NewL(MSmsComm& aSmsComm, RMobileSmsMessaging& aSmsMessaging,RFs& aFs) |
|
70 { |
|
71 LOGSMSPROT1("CSmsMonitorDiskSpace::NewL()"); |
|
72 |
|
73 CSmsMonitorDiskSpace* self = new(ELeave) CSmsMonitorDiskSpace(aSmsComm, aSmsMessaging, aFs); |
|
74 CleanupStack::PushL(self); |
|
75 self->ConstructL(); |
|
76 CleanupStack::Pop(); |
|
77 |
|
78 return self; |
|
79 } // CSmsMonitorDiskSpace::NewL |
|
80 |
|
81 |
|
82 /** |
|
83 * Private constructor used in the first phase of construction. |
|
84 */ |
|
85 CSmsMonitorDiskSpace::CSmsMonitorDiskSpace(MSmsComm& aSmsComm, RMobileSmsMessaging& aSmsMessaging,RFs& aFs) |
|
86 : CActive(KSmsSessionPriority), |
|
87 iState(ESmsMonitorDiskSpaceIdle), |
|
88 iSmsMessaging(aSmsMessaging), |
|
89 iFs(aFs), |
|
90 iSmsComm(aSmsComm), |
|
91 iLowLimit(8*1024), |
|
92 iHighLimit(16*1024) |
|
93 { |
|
94 CActiveScheduler::Add(this); |
|
95 } // CSmsMonitorDiskSpace::CSmsMonitorDiskSpace |
|
96 |
|
97 |
|
98 /** |
|
99 * Destructor. Ensures any outstanding operation is cancelled. |
|
100 */ |
|
101 CSmsMonitorDiskSpace::~CSmsMonitorDiskSpace() |
|
102 { |
|
103 Cancel(); |
|
104 |
|
105 #ifdef _DEBUG |
|
106 iFreeDiskSpaceProperty.Close(); |
|
107 #endif |
|
108 |
|
109 } // CSmsMonitorDiskSpace::~CSmsMonitorDiskSpace |
|
110 |
|
111 |
|
112 /** |
|
113 * Initialize values for LowLimitDiskSpace and HighLimitDiskSpace |
|
114 * from resource file |
|
115 */ |
|
116 void CSmsMonitorDiskSpace::ConstructL() |
|
117 { |
|
118 RResourceFile resourceFile; |
|
119 TFileName fileName; |
|
120 Dll::FileName(fileName); |
|
121 TParse parse; |
|
122 TFileName resourceFileName; |
|
123 |
|
124 // |
|
125 // Create the path to the resource file... |
|
126 // |
|
127 iFs.PrivatePath(resourceFileName); |
|
128 resourceFileName.Append(KSmsResourceFile); |
|
129 parse.Set(resourceFileName, &fileName, 0); |
|
130 fileName = parse.FullName(); |
|
131 BaflUtils::NearestLanguageFile(iFs, fileName); |
|
132 |
|
133 // |
|
134 // To enable adequate CSmsMonitorDiskSpace testing we allow the SMSU.RSC |
|
135 // file to be loaded from the C: drive if it exists. This is only for a |
|
136 // DEBUG version of course! Later WINSCW is also added to allow the testing |
|
137 // on WINSCW UREL version. |
|
138 // |
|
139 #if (defined __WINSCW__) || (defined _DEBUG) |
|
140 TUint attValue; |
|
141 TChar oldDriveLetter = fileName[0]; |
|
142 |
|
143 // |
|
144 // Change the filename to look on C: and then see if it exists... |
|
145 // |
|
146 fileName[0] = 'C'; |
|
147 |
|
148 if (iFs.Att(fileName, attValue) != KErrNone) |
|
149 { |
|
150 // |
|
151 // The file does not exist on C: so revert the change... |
|
152 // |
|
153 fileName[0] = oldDriveLetter; |
|
154 } |
|
155 #endif |
|
156 |
|
157 // |
|
158 // Log the filename in use and whether it is ROM based... |
|
159 // |
|
160 #ifdef _SMS_LOGGING_ENABLED |
|
161 TBuf8<KMaxFileName> buf8; |
|
162 buf8.Copy(fileName); |
|
163 LOGSMSPROT2("CSmsMonitorDiskSpace::ConstructL(): fileName=\"%S\"", &buf8); |
|
164 #endif |
|
165 |
|
166 if (iFs.IsFileInRom(fileName) == NULL) |
|
167 { |
|
168 LOGSMSPROT1("CSmsMonitorDiskSpace::ConstructL(): Smsu.rsc not in ROM"); |
|
169 } |
|
170 |
|
171 // |
|
172 // Read the low and high limits... |
|
173 // |
|
174 TResourceReader reader; |
|
175 HBufC8* buf; |
|
176 |
|
177 resourceFile.OpenL(iFs, fileName); |
|
178 CleanupClosePushL(resourceFile); |
|
179 |
|
180 buf = resourceFile.AllocReadLC(R_LOWLIMIT_DISKSPACE_HOLDER); |
|
181 reader.SetBuffer(buf); |
|
182 iLowLimit = reader.ReadInt32(); |
|
183 CleanupStack::PopAndDestroy(buf); |
|
184 |
|
185 buf = resourceFile.AllocReadLC(R_HIGHLIMIT_DISKSPACE_HOLDER); |
|
186 reader.SetBuffer(buf); |
|
187 iHighLimit=reader.ReadInt32(); |
|
188 CleanupStack::PopAndDestroy(buf); |
|
189 |
|
190 CleanupStack::PopAndDestroy(&resourceFile); |
|
191 |
|
192 #ifdef _DEBUG |
|
193 TInt freeSpace; |
|
194 TInt err = RProperty::Get(KUidPSSMSStackCategory, KUidPSSMSStackFreeDiskSpaceKey, freeSpace); |
|
195 if (err == KErrNone) |
|
196 { |
|
197 iInOODTesting = ETrue; |
|
198 |
|
199 TInt ret = iFreeDiskSpaceProperty.Attach(KUidPSSMSStackCategory, KUidPSSMSStackFreeDiskSpaceKey); |
|
200 if (ret != KErrNone) |
|
201 { |
|
202 LOGSMSPROT2("iFreeDiskSpaceProperty.Attach(): error=%d", ret); |
|
203 User::Leave(ret); |
|
204 } |
|
205 } |
|
206 #endif |
|
207 |
|
208 LOGSMSPROT3("CSmsMonitorDiskSpace::ConstructL(): iLowLimit=%d, iHighLimit=%d", |
|
209 iLowLimit, iHighLimit); |
|
210 } // CSmsMonitorDiskSpace::ConstructL |
|
211 |
|
212 |
|
213 /** |
|
214 * Handles a completed disk monitor or resume request. |
|
215 */ |
|
216 void CSmsMonitorDiskSpace::RunL() |
|
217 { |
|
218 LOGSMSPROT3("CSmsMonitorDiskSpace:RunL(): iStatus=%d, iState=%d", |
|
219 iStatus.Int(), iState ); |
|
220 |
|
221 switch (iState) |
|
222 { |
|
223 case ESmsMonitorDiskSpaceMonitorLowLimit: |
|
224 { |
|
225 iState = ESmsMonitorDiskSpaceIdle; |
|
226 |
|
227 // |
|
228 // If the disk space has gone above the low limit, then |
|
229 // resume reception. Otherwise (assuming the notify was |
|
230 // successful) then start monitoring the low limit again... |
|
231 // |
|
232 TInt freeDiskSpace = GetFreeDiskSpace(); |
|
233 |
|
234 if (freeDiskSpace >= iLowLimit) |
|
235 { |
|
236 ResumeSmsReception(); |
|
237 } |
|
238 else if (iStatus.Int() == KErrNone) |
|
239 { |
|
240 NotifyDiskSpace(iLowLimit, ESmsMonitorDiskSpaceMonitorLowLimit); |
|
241 } |
|
242 } |
|
243 break; |
|
244 |
|
245 case ESmsMonitorDiskSpaceMonitorHighLimit: |
|
246 { |
|
247 iState = ESmsMonitorDiskSpaceIdle; |
|
248 |
|
249 // |
|
250 // If the disk space has gone above the high limit, then |
|
251 // resume reception. Otherwise (assuming the notify was |
|
252 // successful) then start monitoring the high limit again... |
|
253 // |
|
254 TInt freeDiskSpace = GetFreeDiskSpace(); |
|
255 |
|
256 if (freeDiskSpace >= iHighLimit) |
|
257 { |
|
258 ResumeSmsReception(); |
|
259 } |
|
260 else if (iStatus.Int() == KErrNone) |
|
261 { |
|
262 NotifyDiskSpace(iHighLimit, ESmsMonitorDiskSpaceMonitorHighLimit); |
|
263 } |
|
264 } |
|
265 break; |
|
266 |
|
267 case ESmsMonitorDiskSpaceResumeReception: |
|
268 { |
|
269 // |
|
270 // We are finished. However, check if any N'Acks were sent between |
|
271 // the time we began the resume and now incase we need to restart |
|
272 // the monitoring. |
|
273 // |
|
274 if (iNAckdClassZero) |
|
275 { |
|
276 NotifyDiskSpace(iLowLimit, ESmsMonitorDiskSpaceMonitorLowLimit); |
|
277 } |
|
278 else if (iNAckdClassOther) |
|
279 { |
|
280 NotifyDiskSpace(iHighLimit, ESmsMonitorDiskSpaceMonitorHighLimit); |
|
281 } |
|
282 else |
|
283 { |
|
284 iState = ESmsMonitorDiskSpaceIdle; |
|
285 } |
|
286 } |
|
287 break; |
|
288 |
|
289 default: |
|
290 { |
|
291 SmspPanic(KSmspPanicUnexpectedState); |
|
292 } |
|
293 break; |
|
294 } |
|
295 } // CSmsMonitorDiskSpace::RunL |
|
296 |
|
297 |
|
298 /** |
|
299 * Handles a request to cancel the current state machine operation. |
|
300 */ |
|
301 void CSmsMonitorDiskSpace::DoCancel() |
|
302 { |
|
303 LOGSMSPROT2("CSmsMonitorDiskSpace::DoCancel(): iState=%d", iState); |
|
304 |
|
305 switch (iState) |
|
306 { |
|
307 case ESmsMonitorDiskSpaceIdle: |
|
308 { |
|
309 // NOP |
|
310 } |
|
311 break; |
|
312 |
|
313 case ESmsMonitorDiskSpaceMonitorLowLimit: |
|
314 case ESmsMonitorDiskSpaceMonitorHighLimit: |
|
315 { |
|
316 #ifdef _DEBUG |
|
317 if (iInOODTesting) |
|
318 { |
|
319 iFreeDiskSpaceProperty.Cancel(); |
|
320 } |
|
321 else |
|
322 #endif |
|
323 { |
|
324 iFs.NotifyDiskSpaceCancel(); |
|
325 } |
|
326 |
|
327 } |
|
328 break; |
|
329 |
|
330 case ESmsMonitorDiskSpaceResumeReception: |
|
331 { |
|
332 iSmsMessaging.CancelAsyncRequest(EMobileSmsMessagingResumeSmsReception); |
|
333 } |
|
334 break; |
|
335 |
|
336 default: |
|
337 { |
|
338 SmspPanic(KSmspPanicUnexpectedState); |
|
339 } |
|
340 } |
|
341 |
|
342 iState = ESmsMonitorDiskSpaceIdle; |
|
343 } // CSmsMonitorDiskSpace::DoCancel |
|
344 |
|
345 |
|
346 /** |
|
347 * Checks for enough disk space, and starts monitoring disk space if needed. |
|
348 */ |
|
349 void CSmsMonitorDiskSpace::CheckDiskSpaceForPDUL(TBool aPDUIsClass0) |
|
350 { |
|
351 LOGSMSPROT2("CSmsMonitorDiskSpace::CheckDiskSpaceForPDUL(): aPDUIsClass0=%d", |
|
352 aPDUIsClass0); |
|
353 |
|
354 // |
|
355 // First check the actual disk space before working out what to do. |
|
356 // |
|
357 // If enough space exists, then we don't need to do anything else (even if |
|
358 // we where previously monitoring, because that will be handled later as |
|
359 // it would without this function call). |
|
360 // |
|
361 TInt freeDiskSpace = GetFreeDiskSpace(); |
|
362 |
|
363 if (freeDiskSpace >= iHighLimit || |
|
364 (freeDiskSpace >= iLowLimit && aPDUIsClass0)) |
|
365 { |
|
366 // |
|
367 // There is enough space for the PDU, so nothing more to do. |
|
368 // |
|
369 return; |
|
370 } |
|
371 |
|
372 // |
|
373 // There is not enough diskspace so record that a PDU will be N'Ack'd. |
|
374 // |
|
375 if (aPDUIsClass0) |
|
376 { |
|
377 iNAckdClassZero = ETrue; |
|
378 } |
|
379 else |
|
380 { |
|
381 iNAckdClassOther = ETrue; |
|
382 } |
|
383 |
|
384 // |
|
385 // Ensure we are monitoring the disk space. This will then cause a |
|
386 // ResumeReception() to be sent when the disk space increases above the |
|
387 // appropriate limit. |
|
388 // |
|
389 if (freeDiskSpace < iLowLimit) |
|
390 { |
|
391 // |
|
392 // Start montioring the low limit, if not already monitoring or if |
|
393 // we are currently monitoring the high limit. |
|
394 // |
|
395 if (iState == ESmsMonitorDiskSpaceIdle || |
|
396 iState == ESmsMonitorDiskSpaceMonitorHighLimit) |
|
397 { |
|
398 NotifyDiskSpace(iLowLimit, ESmsMonitorDiskSpaceMonitorLowLimit); |
|
399 } |
|
400 } |
|
401 else // (freeDiskSpace < iHighLimit) |
|
402 { |
|
403 // |
|
404 // Start monitoring the high limit if not already monitoring... |
|
405 // |
|
406 if (iState == ESmsMonitorDiskSpaceIdle) |
|
407 { |
|
408 NotifyDiskSpace(iHighLimit, ESmsMonitorDiskSpaceMonitorHighLimit); |
|
409 } |
|
410 } |
|
411 |
|
412 // |
|
413 // Imform the caller that the SMS should be N'Ack'd... |
|
414 // |
|
415 User::Leave(KErrDiskFull); |
|
416 } // CSmsMonitorDiskSpace::CheckDiskSpaceForPDUL |
|
417 |
|
418 |
|
419 /** |
|
420 * Starts monitoring the free disk space to spot when it rises above the |
|
421 * requested limit. |
|
422 * |
|
423 * Unfortunately the File System API does not distiguish between going below |
|
424 * or above a limit, so some checking is needed to ensure that the correct |
|
425 * behaviour is requested, since it is possible in theory for the disk space |
|
426 * to change between the calls. |
|
427 * |
|
428 * In theory this is unlikely since the priority of the SMS Stack is higher |
|
429 * but not impossible to happen. We guard against it anyway since the mere |
|
430 * fact it could happen poses questions when the defects come in from handsets. |
|
431 * |
|
432 * @note The current disk space is assumed to be below the limit requested. |
|
433 * If it is found to be above, this will cause an imediate completion. |
|
434 * |
|
435 * @param aLimit Limit to monitor. |
|
436 * @param aState State to transition to when this request is made. |
|
437 */ |
|
438 void CSmsMonitorDiskSpace::NotifyDiskSpace(TInt aLimit, |
|
439 TSmsMonitorDiskSpaceState aState) |
|
440 { |
|
441 LOGSMSPROT3("CSmsMonitorDiskSpace::NotifyDiskSpace(): aLimit=%d, aState=%d", |
|
442 aLimit, aState); |
|
443 |
|
444 // |
|
445 // Cancel any previously outstanding requests... |
|
446 // |
|
447 if (iState != ESmsMonitorDiskSpaceIdle) |
|
448 { |
|
449 Cancel(); |
|
450 } |
|
451 |
|
452 // |
|
453 // Start the notification... |
|
454 // |
|
455 iState = aState; |
|
456 |
|
457 #ifdef _DEBUG |
|
458 if (iInOODTesting) |
|
459 { |
|
460 iFreeDiskSpaceProperty.Subscribe(iStatus); |
|
461 } |
|
462 else |
|
463 #endif |
|
464 { |
|
465 iFs.NotifyDiskSpace(aLimit, EDriveC, iStatus); |
|
466 } |
|
467 |
|
468 iSmsComm.DiskSpaceMonitorStateChange(ESmsDiskSpaceFull); |
|
469 SetActive(); |
|
470 |
|
471 // |
|
472 // Now, as a sanity check, check the diskspace again. If the disk space |
|
473 // has advanced above the limit in the time between the request and now, |
|
474 // or since the last call to GetFreeDiskSpace() then the request will |
|
475 // either be invalid, or have completed. If either of these are the case |
|
476 // we need to control the situation and ensure a completion occurs... |
|
477 // |
|
478 TInt freeDiskSpace = GetFreeDiskSpace(); |
|
479 |
|
480 if (freeDiskSpace > aLimit) |
|
481 { |
|
482 // |
|
483 // Cancel the request... |
|
484 // |
|
485 Cancel(); |
|
486 |
|
487 // |
|
488 // Force a fake completion for this state... |
|
489 // |
|
490 TRequestStatus* status = &iStatus; |
|
491 |
|
492 iState = aState; |
|
493 iStatus = KRequestPending; |
|
494 SetActive(); |
|
495 User::RequestComplete(status, KErrNone); |
|
496 } |
|
497 } // CSmsMonitorDiskSpace::NotifyDiskSpace |
|
498 |
|
499 |
|
500 /** |
|
501 * Performs the required actions for the case when leaving either the low |
|
502 * limit or the high limit. It doesn't really matter which limit you are |
|
503 * leaving since the resume applies for all SMSs. This gives three scenarios: |
|
504 * |
|
505 * 1) You leave the high limit. This is not a problem as all SMSs can |
|
506 * now be received. |
|
507 * 2) You leave the low limit and go above the high limit. This is also |
|
508 * not a problem as all SMSs can be received. |
|
509 * 3) You leave the low limit but stay below the high limit. In this case |
|
510 * the N'Ack'd SMS was class 0 and you can now receive it. A non-class 0 |
|
511 * SMS may attempt to be delivered, but monitoring will restart as |
|
512 * before. So again no problem. |
|
513 */ |
|
514 void CSmsMonitorDiskSpace::ResumeSmsReception() |
|
515 { |
|
516 LOGSMSPROT1("CSmsMonitorDiskSpace::ResumeSmsReception"); |
|
517 |
|
518 // |
|
519 // Cancel any previously outstanding requests... |
|
520 // |
|
521 if (iState != ESmsMonitorDiskSpaceIdle) |
|
522 { |
|
523 Cancel(); |
|
524 } |
|
525 |
|
526 // |
|
527 // Clear the N'Ackd flags... |
|
528 // |
|
529 iNAckdClassZero = EFalse; |
|
530 iNAckdClassOther = EFalse; |
|
531 |
|
532 // |
|
533 // Start the resume request... |
|
534 // |
|
535 iState = ESmsMonitorDiskSpaceResumeReception; |
|
536 iSmsMessaging.ResumeSmsReception(iStatus); |
|
537 iSmsComm.DiskSpaceMonitorStateChange(ESmsDiskSpaceAvailable); |
|
538 SetActive(); |
|
539 } // CSmsMonitorDiskSpace::ResumeSmsReception |
|
540 |
|
541 |
|
542 /** |
|
543 * Utilility function to determine amount of free disk space. The actual |
|
544 * free space is limited at 2GB. |
|
545 */ |
|
546 TInt CSmsMonitorDiskSpace::GetFreeDiskSpace() |
|
547 { |
|
548 TVolumeInfo volumeInfo; |
|
549 TInt ret; |
|
550 |
|
551 #ifdef _DEBUG |
|
552 if( iInOODTesting ) |
|
553 { |
|
554 TInt value = 0; |
|
555 ret = iFreeDiskSpaceProperty.Get(value); |
|
556 |
|
557 // update volumeInfo with value regardless of error as error handled later |
|
558 volumeInfo.iFree = value; |
|
559 } |
|
560 else |
|
561 #endif |
|
562 { |
|
563 ret = iFs.Volume(volumeInfo, EDriveC); |
|
564 } |
|
565 |
|
566 // |
|
567 // Get the volume info for drive C:... |
|
568 // |
|
569 |
|
570 if (ret != KErrNone) |
|
571 { |
|
572 LOGSMSPROT2("CSmsMonitorDiskSpace::GetFreeDiskSpace(): error=%d", ret); |
|
573 return KErrGeneral; |
|
574 } |
|
575 |
|
576 // |
|
577 // Convert the disk space value to a TInt (allowing 2GB limits)... |
|
578 // |
|
579 TInt freeSpace; |
|
580 |
|
581 if (volumeInfo.iFree >= 0x7fffffff) |
|
582 { |
|
583 freeSpace = 0x7fffffff; |
|
584 } |
|
585 else |
|
586 { |
|
587 freeSpace = (TInt) volumeInfo.iFree; |
|
588 } |
|
589 |
|
590 LOGSMSPROT2("CSmsMonitorDiskSpace::GetFreeDiskSpace(): freeSpace=%d", freeSpace); |
|
591 |
|
592 return freeSpace; |
|
593 } // CSmsMonitorDiskSpace::GetFreeDiskSpace |