diff -r 6b1d113cdff3 -r 6638e7f4bd8f smsprotocols/smsstack/smsprot/Src/smspmondsk.cpp --- a/smsprotocols/smsstack/smsprot/Src/smspmondsk.cpp Mon May 03 13:37:20 2010 +0300 +++ b/smsprotocols/smsstack/smsprot/Src/smspmondsk.cpp Thu May 06 15:10:38 2010 +0100 @@ -1,593 +1,593 @@ -// Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies). -// All rights reserved. -// This component and the accompanying materials are made available -// under the terms of "Eclipse Public License v1.0" -// which accompanies this distribution, and is available -// at the URL "http://www.eclipse.org/legal/epl-v10.html". -// -// Initial Contributors: -// Nokia Corporation - initial contribution. -// -// Contributors: -// -// Description: -// Implementation for a CActive based class that monitors for low disk space -// and is informed when a PDU is being received. Should memory be too low, -// an error code is returned causing a NAck. The class will then monitor -// for the point at which PDUs can be received again, and a Resume Reception -// will be sent to the network. -// The are two limits - a high limit for general SMSs and a low limit for -// class 0 SMSs. However there is only one way to resume reception of SMSs. So -// once a resume reception is sent, it resumes hoth types of SMSs. The algorithm -// is a bit simiplier because of this: -// IF sending non-Class 0 AND we are below the high limit THEN -// N'Ack SMS -// IF not waiting for free diskspace THEN -// Wait for free diskspace to rise above the high limit -// Resume SMS Reception. -// ELSE -// Continue waiting for either high limit or low limit -// Resume SMS Reception as previously intended -// END_IF -// ELSE IF sending Class 0 AND we are below the low limit THEN -// Wait for free diskspace to rise above the low limit -// Resume SMS Reception. -// END_IF -// Note that in the second and last case, SMS reception may be resumed before -// we are above the high limit, but in that case montioring will repeat when -// the next non-class 0 SMS is attempted to be delivered. This is necessary as -// there is no way to resume just class 0 SMSs. -// -// - -/** - @file - @internalComponent -*/ - -#include -#include - -#include "smspcomm.h" -#include "smspmondsk.h" -#include "smsstacklog.h" -#include "smspmain.h" -#include "smspver.h" -#include - - -_LIT(KSmsResourceFile, "sms\\smsu.rsc"); - - -/** - * 2 phase constructor. - * - * @leave Leaves if not enough memory is available. - * - * @return a newly created CSmsMonitorDiskSpace object. - */ -CSmsMonitorDiskSpace* CSmsMonitorDiskSpace::NewL(MSmsComm& aSmsComm, RMobileSmsMessaging& aSmsMessaging,RFs& aFs) - { - LOGSMSPROT1("CSmsMonitorDiskSpace::NewL()"); - - CSmsMonitorDiskSpace* self = new(ELeave) CSmsMonitorDiskSpace(aSmsComm, aSmsMessaging, aFs); - CleanupStack::PushL(self); - self->ConstructL(); - CleanupStack::Pop(); - - return self; - } // CSmsMonitorDiskSpace::NewL - - -/** - * Private constructor used in the first phase of construction. - */ -CSmsMonitorDiskSpace::CSmsMonitorDiskSpace(MSmsComm& aSmsComm, RMobileSmsMessaging& aSmsMessaging,RFs& aFs) - : CActive(KSmsSessionPriority), - iState(ESmsMonitorDiskSpaceIdle), - iSmsMessaging(aSmsMessaging), - iFs(aFs), - iSmsComm(aSmsComm), - iLowLimit(8*1024), - iHighLimit(16*1024) - { - CActiveScheduler::Add(this); - } // CSmsMonitorDiskSpace::CSmsMonitorDiskSpace - - -/** - * Destructor. Ensures any outstanding operation is cancelled. - */ -CSmsMonitorDiskSpace::~CSmsMonitorDiskSpace() - { - Cancel(); - -#ifdef _DEBUG - iFreeDiskSpaceProperty.Close(); -#endif - - } // CSmsMonitorDiskSpace::~CSmsMonitorDiskSpace - - -/** - * Initialize values for LowLimitDiskSpace and HighLimitDiskSpace - * from resource file - */ -void CSmsMonitorDiskSpace::ConstructL() - { - RResourceFile resourceFile; - TFileName fileName; - Dll::FileName(fileName); - TParse parse; - TFileName resourceFileName; - - // - // Create the path to the resource file... - // - iFs.PrivatePath(resourceFileName); - resourceFileName.Append(KSmsResourceFile); - parse.Set(resourceFileName, &fileName, 0); - fileName = parse.FullName(); - BaflUtils::NearestLanguageFile(iFs, fileName); - - // - // To enable adequate CSmsMonitorDiskSpace testing we allow the SMSU.RSC - // file to be loaded from the C: drive if it exists. This is only for a - // DEBUG version of course! Later WINSCW is also added to allow the testing - // on WINSCW UREL version. - // -#if (defined __WINSCW__) || (defined _DEBUG) - TUint attValue; - TChar oldDriveLetter = fileName[0]; - - // - // Change the filename to look on C: and then see if it exists... - // - fileName[0] = 'C'; - - if (iFs.Att(fileName, attValue) != KErrNone) - { - // - // The file does not exist on C: so revert the change... - // - fileName[0] = oldDriveLetter; - } -#endif - - // - // Log the filename in use and whether it is ROM based... - // -#ifdef _SMS_LOGGING_ENABLED - TBuf8 buf8; - buf8.Copy(fileName); - LOGSMSPROT2("CSmsMonitorDiskSpace::ConstructL(): fileName=\"%S\"", &buf8); -#endif - - if (iFs.IsFileInRom(fileName) == NULL) - { - LOGSMSPROT1("CSmsMonitorDiskSpace::ConstructL(): Smsu.rsc not in ROM"); - } - - // - // Read the low and high limits... - // - TResourceReader reader; - HBufC8* buf; - - resourceFile.OpenL(iFs, fileName); - CleanupClosePushL(resourceFile); - - buf = resourceFile.AllocReadLC(R_LOWLIMIT_DISKSPACE_HOLDER); - reader.SetBuffer(buf); - iLowLimit = reader.ReadInt32(); - CleanupStack::PopAndDestroy(buf); - - buf = resourceFile.AllocReadLC(R_HIGHLIMIT_DISKSPACE_HOLDER); - reader.SetBuffer(buf); - iHighLimit=reader.ReadInt32(); - CleanupStack::PopAndDestroy(buf); - - CleanupStack::PopAndDestroy(&resourceFile); - -#ifdef _DEBUG - TInt freeSpace; - TInt err = RProperty::Get(KUidPSSMSStackCategory, KUidPSSMSStackFreeDiskSpaceKey, freeSpace); - if (err == KErrNone) - { - iInOODTesting = ETrue; - - TInt ret = iFreeDiskSpaceProperty.Attach(KUidPSSMSStackCategory, KUidPSSMSStackFreeDiskSpaceKey); - if (ret != KErrNone) - { - LOGSMSPROT2("iFreeDiskSpaceProperty.Attach(): error=%d", ret); - User::Leave(ret); - } - } -#endif - - LOGSMSPROT3("CSmsMonitorDiskSpace::ConstructL(): iLowLimit=%d, iHighLimit=%d", - iLowLimit, iHighLimit); - } // CSmsMonitorDiskSpace::ConstructL - - -/** - * Handles a completed disk monitor or resume request. - */ -void CSmsMonitorDiskSpace::RunL() - { - LOGSMSPROT3("CSmsMonitorDiskSpace:RunL(): iStatus=%d, iState=%d", - iStatus.Int(), iState ); - - switch (iState) - { - case ESmsMonitorDiskSpaceMonitorLowLimit: - { - iState = ESmsMonitorDiskSpaceIdle; - - // - // If the disk space has gone above the low limit, then - // resume reception. Otherwise (assuming the notify was - // successful) then start monitoring the low limit again... - // - TInt freeDiskSpace = GetFreeDiskSpace(); - - if (freeDiskSpace >= iLowLimit) - { - ResumeSmsReception(); - } - else if (iStatus.Int() == KErrNone) - { - NotifyDiskSpace(iLowLimit, ESmsMonitorDiskSpaceMonitorLowLimit); - } - } - break; - - case ESmsMonitorDiskSpaceMonitorHighLimit: - { - iState = ESmsMonitorDiskSpaceIdle; - - // - // If the disk space has gone above the high limit, then - // resume reception. Otherwise (assuming the notify was - // successful) then start monitoring the high limit again... - // - TInt freeDiskSpace = GetFreeDiskSpace(); - - if (freeDiskSpace >= iHighLimit) - { - ResumeSmsReception(); - } - else if (iStatus.Int() == KErrNone) - { - NotifyDiskSpace(iHighLimit, ESmsMonitorDiskSpaceMonitorHighLimit); - } - } - break; - - case ESmsMonitorDiskSpaceResumeReception: - { - // - // We are finished. However, check if any N'Acks were sent between - // the time we began the resume and now incase we need to restart - // the monitoring. - // - if (iNAckdClassZero) - { - NotifyDiskSpace(iLowLimit, ESmsMonitorDiskSpaceMonitorLowLimit); - } - else if (iNAckdClassOther) - { - NotifyDiskSpace(iHighLimit, ESmsMonitorDiskSpaceMonitorHighLimit); - } - else - { - iState = ESmsMonitorDiskSpaceIdle; - } - } - break; - - default: - { - SmspPanic(KSmspPanicUnexpectedState); - } - break; - } - } // CSmsMonitorDiskSpace::RunL - - -/** - * Handles a request to cancel the current state machine operation. - */ -void CSmsMonitorDiskSpace::DoCancel() - { - LOGSMSPROT2("CSmsMonitorDiskSpace::DoCancel(): iState=%d", iState); - - switch (iState) - { - case ESmsMonitorDiskSpaceIdle: - { - // NOP - } - break; - - case ESmsMonitorDiskSpaceMonitorLowLimit: - case ESmsMonitorDiskSpaceMonitorHighLimit: - { -#ifdef _DEBUG - if (iInOODTesting) - { - iFreeDiskSpaceProperty.Cancel(); - } - else -#endif - { - iFs.NotifyDiskSpaceCancel(); - } - - } - break; - - case ESmsMonitorDiskSpaceResumeReception: - { - iSmsMessaging.CancelAsyncRequest(EMobileSmsMessagingResumeSmsReception); - } - break; - - default: - { - SmspPanic(KSmspPanicUnexpectedState); - } - } - - iState = ESmsMonitorDiskSpaceIdle; - } // CSmsMonitorDiskSpace::DoCancel - - -/** - * Checks for enough disk space, and starts monitoring disk space if needed. - */ -void CSmsMonitorDiskSpace::CheckDiskSpaceForPDUL(TBool aPDUIsClass0) - { - LOGSMSPROT2("CSmsMonitorDiskSpace::CheckDiskSpaceForPDUL(): aPDUIsClass0=%d", - aPDUIsClass0); - - // - // First check the actual disk space before working out what to do. - // - // If enough space exists, then we don't need to do anything else (even if - // we where previously monitoring, because that will be handled later as - // it would without this function call). - // - TInt freeDiskSpace = GetFreeDiskSpace(); - - if (freeDiskSpace >= iHighLimit || - (freeDiskSpace >= iLowLimit && aPDUIsClass0)) - { - // - // There is enough space for the PDU, so nothing more to do. - // - return; - } - - // - // There is not enough diskspace so record that a PDU will be N'Ack'd. - // - if (aPDUIsClass0) - { - iNAckdClassZero = ETrue; - } - else - { - iNAckdClassOther = ETrue; - } - - // - // Ensure we are monitoring the disk space. This will then cause a - // ResumeReception() to be sent when the disk space increases above the - // appropriate limit. - // - if (freeDiskSpace < iLowLimit) - { - // - // Start montioring the low limit, if not already monitoring or if - // we are currently monitoring the high limit. - // - if (iState == ESmsMonitorDiskSpaceIdle || - iState == ESmsMonitorDiskSpaceMonitorHighLimit) - { - NotifyDiskSpace(iLowLimit, ESmsMonitorDiskSpaceMonitorLowLimit); - } - } - else // (freeDiskSpace < iHighLimit) - { - // - // Start monitoring the high limit if not already monitoring... - // - if (iState == ESmsMonitorDiskSpaceIdle) - { - NotifyDiskSpace(iHighLimit, ESmsMonitorDiskSpaceMonitorHighLimit); - } - } - - // - // Imform the caller that the SMS should be N'Ack'd... - // - User::Leave(KErrDiskFull); - } // CSmsMonitorDiskSpace::CheckDiskSpaceForPDUL - - -/** - * Starts monitoring the free disk space to spot when it rises above the - * requested limit. - * - * Unfortunately the File System API does not distiguish between going below - * or above a limit, so some checking is needed to ensure that the correct - * behaviour is requested, since it is possible in theory for the disk space - * to change between the calls. - * - * In theory this is unlikely since the priority of the SMS Stack is higher - * but not impossible to happen. We guard against it anyway since the mere - * fact it could happen poses questions when the defects come in from handsets. - * - * @note The current disk space is assumed to be below the limit requested. - * If it is found to be above, this will cause an imediate completion. - * - * @param aLimit Limit to monitor. - * @param aState State to transition to when this request is made. - */ -void CSmsMonitorDiskSpace::NotifyDiskSpace(TInt aLimit, - TSmsMonitorDiskSpaceState aState) - { - LOGSMSPROT3("CSmsMonitorDiskSpace::NotifyDiskSpace(): aLimit=%d, aState=%d", - aLimit, aState); - - // - // Cancel any previously outstanding requests... - // - if (iState != ESmsMonitorDiskSpaceIdle) - { - Cancel(); - } - - // - // Start the notification... - // - iState = aState; - -#ifdef _DEBUG - if (iInOODTesting) - { - iFreeDiskSpaceProperty.Subscribe(iStatus); - } - else -#endif - { - iFs.NotifyDiskSpace(aLimit, EDriveC, iStatus); - } - - iSmsComm.DiskSpaceMonitorStateChange(ESmsDiskSpaceFull); - SetActive(); - - // - // Now, as a sanity check, check the diskspace again. If the disk space - // has advanced above the limit in the time between the request and now, - // or since the last call to GetFreeDiskSpace() then the request will - // either be invalid, or have completed. If either of these are the case - // we need to control the situation and ensure a completion occurs... - // - TInt freeDiskSpace = GetFreeDiskSpace(); - - if (freeDiskSpace > aLimit) - { - // - // Cancel the request... - // - Cancel(); - - // - // Force a fake completion for this state... - // - TRequestStatus* status = &iStatus; - - iState = aState; - iStatus = KRequestPending; - SetActive(); - User::RequestComplete(status, KErrNone); - } - } // CSmsMonitorDiskSpace::NotifyDiskSpace - - -/** - * Performs the required actions for the case when leaving either the low - * limit or the high limit. It doesn't really matter which limit you are - * leaving since the resume applies for all SMSs. This gives three scenarios: - * - * 1) You leave the high limit. This is not a problem as all SMSs can - * now be received. - * 2) You leave the low limit and go above the high limit. This is also - * not a problem as all SMSs can be received. - * 3) You leave the low limit but stay below the high limit. In this case - * the N'Ack'd SMS was class 0 and you can now receive it. A non-class 0 - * SMS may attempt to be delivered, but monitoring will restart as - * before. So again no problem. - */ -void CSmsMonitorDiskSpace::ResumeSmsReception() - { - LOGSMSPROT1("CSmsMonitorDiskSpace::ResumeSmsReception"); - - // - // Cancel any previously outstanding requests... - // - if (iState != ESmsMonitorDiskSpaceIdle) - { - Cancel(); - } - - // - // Clear the N'Ackd flags... - // - iNAckdClassZero = EFalse; - iNAckdClassOther = EFalse; - - // - // Start the resume request... - // - iState = ESmsMonitorDiskSpaceResumeReception; - iSmsMessaging.ResumeSmsReception(iStatus); - iSmsComm.DiskSpaceMonitorStateChange(ESmsDiskSpaceAvailable); - SetActive(); - } // CSmsMonitorDiskSpace::ResumeSmsReception - - -/** - * Utilility function to determine amount of free disk space. The actual - * free space is limited at 2GB. - */ -TInt CSmsMonitorDiskSpace::GetFreeDiskSpace() - { - TVolumeInfo volumeInfo; - TInt ret; - -#ifdef _DEBUG - if( iInOODTesting ) - { - TInt value = 0; - ret = iFreeDiskSpaceProperty.Get(value); - - // update volumeInfo with value regardless of error as error handled later - volumeInfo.iFree = value; - } - else -#endif - { - ret = iFs.Volume(volumeInfo, EDriveC); - } - - // - // Get the volume info for drive C:... - // - - if (ret != KErrNone) - { - LOGSMSPROT2("CSmsMonitorDiskSpace::GetFreeDiskSpace(): error=%d", ret); - return KErrGeneral; - } - - // - // Convert the disk space value to a TInt (allowing 2GB limits)... - // - TInt freeSpace; - - if (volumeInfo.iFree >= 0x7fffffff) - { - freeSpace = 0x7fffffff; - } - else - { - freeSpace = (TInt) volumeInfo.iFree; - } - - LOGSMSPROT2("CSmsMonitorDiskSpace::GetFreeDiskSpace(): freeSpace=%d", freeSpace); - - return freeSpace; - } // CSmsMonitorDiskSpace::GetFreeDiskSpace +// Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// Implementation for a CActive based class that monitors for low disk space +// and is informed when a PDU is being received. Should memory be too low, +// an error code is returned causing a NAck. The class will then monitor +// for the point at which PDUs can be received again, and a Resume Reception +// will be sent to the network. +// The are two limits - a high limit for general SMSs and a low limit for +// class 0 SMSs. However there is only one way to resume reception of SMSs. So +// once a resume reception is sent, it resumes hoth types of SMSs. The algorithm +// is a bit simiplier because of this: +// IF sending non-Class 0 AND we are below the high limit THEN +// N'Ack SMS +// IF not waiting for free diskspace THEN +// Wait for free diskspace to rise above the high limit +// Resume SMS Reception. +// ELSE +// Continue waiting for either high limit or low limit +// Resume SMS Reception as previously intended +// END_IF +// ELSE IF sending Class 0 AND we are below the low limit THEN +// Wait for free diskspace to rise above the low limit +// Resume SMS Reception. +// END_IF +// Note that in the second and last case, SMS reception may be resumed before +// we are above the high limit, but in that case montioring will repeat when +// the next non-class 0 SMS is attempted to be delivered. This is necessary as +// there is no way to resume just class 0 SMSs. +// +// + +/** + @file + @internalComponent +*/ + +#include +#include + +#include "smspcomm.h" +#include "smspmondsk.h" +#include "smsstacklog.h" +#include "smspmain.h" +#include "smspver.h" +#include + + +_LIT(KSmsResourceFile, "sms\\smsu.rsc"); + + +/** + * 2 phase constructor. + * + * @leave Leaves if not enough memory is available. + * + * @return a newly created CSmsMonitorDiskSpace object. + */ +CSmsMonitorDiskSpace* CSmsMonitorDiskSpace::NewL(MSmsComm& aSmsComm, RMobileSmsMessaging& aSmsMessaging,RFs& aFs) + { + LOGSMSPROT1("CSmsMonitorDiskSpace::NewL()"); + + CSmsMonitorDiskSpace* self = new(ELeave) CSmsMonitorDiskSpace(aSmsComm, aSmsMessaging, aFs); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(); + + return self; + } // CSmsMonitorDiskSpace::NewL + + +/** + * Private constructor used in the first phase of construction. + */ +CSmsMonitorDiskSpace::CSmsMonitorDiskSpace(MSmsComm& aSmsComm, RMobileSmsMessaging& aSmsMessaging,RFs& aFs) + : CActive(KSmsSessionPriority), + iState(ESmsMonitorDiskSpaceIdle), + iSmsMessaging(aSmsMessaging), + iFs(aFs), + iSmsComm(aSmsComm), + iLowLimit(8*1024), + iHighLimit(16*1024) + { + CActiveScheduler::Add(this); + } // CSmsMonitorDiskSpace::CSmsMonitorDiskSpace + + +/** + * Destructor. Ensures any outstanding operation is cancelled. + */ +CSmsMonitorDiskSpace::~CSmsMonitorDiskSpace() + { + Cancel(); + +#ifdef _DEBUG + iFreeDiskSpaceProperty.Close(); +#endif + + } // CSmsMonitorDiskSpace::~CSmsMonitorDiskSpace + + +/** + * Initialize values for LowLimitDiskSpace and HighLimitDiskSpace + * from resource file + */ +void CSmsMonitorDiskSpace::ConstructL() + { + RResourceFile resourceFile; + TFileName fileName; + Dll::FileName(fileName); + TParse parse; + TFileName resourceFileName; + + // + // Create the path to the resource file... + // + iFs.PrivatePath(resourceFileName); + resourceFileName.Append(KSmsResourceFile); + parse.Set(resourceFileName, &fileName, 0); + fileName = parse.FullName(); + BaflUtils::NearestLanguageFile(iFs, fileName); + + // + // To enable adequate CSmsMonitorDiskSpace testing we allow the SMSU.RSC + // file to be loaded from the C: drive if it exists. This is only for a + // DEBUG version of course! Later WINSCW is also added to allow the testing + // on WINSCW UREL version. + // +#if (defined __WINSCW__) || (defined _DEBUG) + TUint attValue; + TChar oldDriveLetter = fileName[0]; + + // + // Change the filename to look on C: and then see if it exists... + // + fileName[0] = 'C'; + + if (iFs.Att(fileName, attValue) != KErrNone) + { + // + // The file does not exist on C: so revert the change... + // + fileName[0] = oldDriveLetter; + } +#endif + + // + // Log the filename in use and whether it is ROM based... + // +#ifdef _SMS_LOGGING_ENABLED + TBuf8 buf8; + buf8.Copy(fileName); + LOGSMSPROT2("CSmsMonitorDiskSpace::ConstructL(): fileName=\"%S\"", &buf8); +#endif + + if (iFs.IsFileInRom(fileName) == NULL) + { + LOGSMSPROT1("CSmsMonitorDiskSpace::ConstructL(): Smsu.rsc not in ROM"); + } + + // + // Read the low and high limits... + // + TResourceReader reader; + HBufC8* buf; + + resourceFile.OpenL(iFs, fileName); + CleanupClosePushL(resourceFile); + + buf = resourceFile.AllocReadLC(R_LOWLIMIT_DISKSPACE_HOLDER); + reader.SetBuffer(buf); + iLowLimit = reader.ReadInt32(); + CleanupStack::PopAndDestroy(buf); + + buf = resourceFile.AllocReadLC(R_HIGHLIMIT_DISKSPACE_HOLDER); + reader.SetBuffer(buf); + iHighLimit=reader.ReadInt32(); + CleanupStack::PopAndDestroy(buf); + + CleanupStack::PopAndDestroy(&resourceFile); + +#ifdef _DEBUG + TInt freeSpace; + TInt err = RProperty::Get(KUidPSSMSStackCategory, KUidPSSMSStackFreeDiskSpaceKey, freeSpace); + if (err == KErrNone) + { + iInOODTesting = ETrue; + + TInt ret = iFreeDiskSpaceProperty.Attach(KUidPSSMSStackCategory, KUidPSSMSStackFreeDiskSpaceKey); + if (ret != KErrNone) + { + LOGSMSPROT2("iFreeDiskSpaceProperty.Attach(): error=%d", ret); + User::Leave(ret); + } + } +#endif + + LOGSMSPROT3("CSmsMonitorDiskSpace::ConstructL(): iLowLimit=%d, iHighLimit=%d", + iLowLimit, iHighLimit); + } // CSmsMonitorDiskSpace::ConstructL + + +/** + * Handles a completed disk monitor or resume request. + */ +void CSmsMonitorDiskSpace::RunL() + { + LOGSMSPROT3("CSmsMonitorDiskSpace:RunL(): iStatus=%d, iState=%d", + iStatus.Int(), iState ); + + switch (iState) + { + case ESmsMonitorDiskSpaceMonitorLowLimit: + { + iState = ESmsMonitorDiskSpaceIdle; + + // + // If the disk space has gone above the low limit, then + // resume reception. Otherwise (assuming the notify was + // successful) then start monitoring the low limit again... + // + TInt freeDiskSpace = GetFreeDiskSpace(); + + if (freeDiskSpace >= iLowLimit) + { + ResumeSmsReception(); + } + else if (iStatus.Int() == KErrNone) + { + NotifyDiskSpace(iLowLimit, ESmsMonitorDiskSpaceMonitorLowLimit); + } + } + break; + + case ESmsMonitorDiskSpaceMonitorHighLimit: + { + iState = ESmsMonitorDiskSpaceIdle; + + // + // If the disk space has gone above the high limit, then + // resume reception. Otherwise (assuming the notify was + // successful) then start monitoring the high limit again... + // + TInt freeDiskSpace = GetFreeDiskSpace(); + + if (freeDiskSpace >= iHighLimit) + { + ResumeSmsReception(); + } + else if (iStatus.Int() == KErrNone) + { + NotifyDiskSpace(iHighLimit, ESmsMonitorDiskSpaceMonitorHighLimit); + } + } + break; + + case ESmsMonitorDiskSpaceResumeReception: + { + // + // We are finished. However, check if any N'Acks were sent between + // the time we began the resume and now incase we need to restart + // the monitoring. + // + if (iNAckdClassZero) + { + NotifyDiskSpace(iLowLimit, ESmsMonitorDiskSpaceMonitorLowLimit); + } + else if (iNAckdClassOther) + { + NotifyDiskSpace(iHighLimit, ESmsMonitorDiskSpaceMonitorHighLimit); + } + else + { + iState = ESmsMonitorDiskSpaceIdle; + } + } + break; + + default: + { + SmspPanic(KSmspPanicUnexpectedState); + } + break; + } + } // CSmsMonitorDiskSpace::RunL + + +/** + * Handles a request to cancel the current state machine operation. + */ +void CSmsMonitorDiskSpace::DoCancel() + { + LOGSMSPROT2("CSmsMonitorDiskSpace::DoCancel(): iState=%d", iState); + + switch (iState) + { + case ESmsMonitorDiskSpaceIdle: + { + // NOP + } + break; + + case ESmsMonitorDiskSpaceMonitorLowLimit: + case ESmsMonitorDiskSpaceMonitorHighLimit: + { +#ifdef _DEBUG + if (iInOODTesting) + { + iFreeDiskSpaceProperty.Cancel(); + } + else +#endif + { + iFs.NotifyDiskSpaceCancel(); + } + + } + break; + + case ESmsMonitorDiskSpaceResumeReception: + { + iSmsMessaging.CancelAsyncRequest(EMobileSmsMessagingResumeSmsReception); + } + break; + + default: + { + SmspPanic(KSmspPanicUnexpectedState); + } + } + + iState = ESmsMonitorDiskSpaceIdle; + } // CSmsMonitorDiskSpace::DoCancel + + +/** + * Checks for enough disk space, and starts monitoring disk space if needed. + */ +void CSmsMonitorDiskSpace::CheckDiskSpaceForPDUL(TBool aPDUIsClass0) + { + LOGSMSPROT2("CSmsMonitorDiskSpace::CheckDiskSpaceForPDUL(): aPDUIsClass0=%d", + aPDUIsClass0); + + // + // First check the actual disk space before working out what to do. + // + // If enough space exists, then we don't need to do anything else (even if + // we where previously monitoring, because that will be handled later as + // it would without this function call). + // + TInt freeDiskSpace = GetFreeDiskSpace(); + + if (freeDiskSpace >= iHighLimit || + (freeDiskSpace >= iLowLimit && aPDUIsClass0)) + { + // + // There is enough space for the PDU, so nothing more to do. + // + return; + } + + // + // There is not enough diskspace so record that a PDU will be N'Ack'd. + // + if (aPDUIsClass0) + { + iNAckdClassZero = ETrue; + } + else + { + iNAckdClassOther = ETrue; + } + + // + // Ensure we are monitoring the disk space. This will then cause a + // ResumeReception() to be sent when the disk space increases above the + // appropriate limit. + // + if (freeDiskSpace < iLowLimit) + { + // + // Start montioring the low limit, if not already monitoring or if + // we are currently monitoring the high limit. + // + if (iState == ESmsMonitorDiskSpaceIdle || + iState == ESmsMonitorDiskSpaceMonitorHighLimit) + { + NotifyDiskSpace(iLowLimit, ESmsMonitorDiskSpaceMonitorLowLimit); + } + } + else // (freeDiskSpace < iHighLimit) + { + // + // Start monitoring the high limit if not already monitoring... + // + if (iState == ESmsMonitorDiskSpaceIdle) + { + NotifyDiskSpace(iHighLimit, ESmsMonitorDiskSpaceMonitorHighLimit); + } + } + + // + // Imform the caller that the SMS should be N'Ack'd... + // + User::Leave(KErrDiskFull); + } // CSmsMonitorDiskSpace::CheckDiskSpaceForPDUL + + +/** + * Starts monitoring the free disk space to spot when it rises above the + * requested limit. + * + * Unfortunately the File System API does not distiguish between going below + * or above a limit, so some checking is needed to ensure that the correct + * behaviour is requested, since it is possible in theory for the disk space + * to change between the calls. + * + * In theory this is unlikely since the priority of the SMS Stack is higher + * but not impossible to happen. We guard against it anyway since the mere + * fact it could happen poses questions when the defects come in from handsets. + * + * @note The current disk space is assumed to be below the limit requested. + * If it is found to be above, this will cause an imediate completion. + * + * @param aLimit Limit to monitor. + * @param aState State to transition to when this request is made. + */ +void CSmsMonitorDiskSpace::NotifyDiskSpace(TInt aLimit, + TSmsMonitorDiskSpaceState aState) + { + LOGSMSPROT3("CSmsMonitorDiskSpace::NotifyDiskSpace(): aLimit=%d, aState=%d", + aLimit, aState); + + // + // Cancel any previously outstanding requests... + // + if (iState != ESmsMonitorDiskSpaceIdle) + { + Cancel(); + } + + // + // Start the notification... + // + iState = aState; + +#ifdef _DEBUG + if (iInOODTesting) + { + iFreeDiskSpaceProperty.Subscribe(iStatus); + } + else +#endif + { + iFs.NotifyDiskSpace(aLimit, EDriveC, iStatus); + } + + iSmsComm.DiskSpaceMonitorStateChange(ESmsDiskSpaceFull); + SetActive(); + + // + // Now, as a sanity check, check the diskspace again. If the disk space + // has advanced above the limit in the time between the request and now, + // or since the last call to GetFreeDiskSpace() then the request will + // either be invalid, or have completed. If either of these are the case + // we need to control the situation and ensure a completion occurs... + // + TInt freeDiskSpace = GetFreeDiskSpace(); + + if (freeDiskSpace > aLimit) + { + // + // Cancel the request... + // + Cancel(); + + // + // Force a fake completion for this state... + // + TRequestStatus* status = &iStatus; + + iState = aState; + iStatus = KRequestPending; + SetActive(); + User::RequestComplete(status, KErrNone); + } + } // CSmsMonitorDiskSpace::NotifyDiskSpace + + +/** + * Performs the required actions for the case when leaving either the low + * limit or the high limit. It doesn't really matter which limit you are + * leaving since the resume applies for all SMSs. This gives three scenarios: + * + * 1) You leave the high limit. This is not a problem as all SMSs can + * now be received. + * 2) You leave the low limit and go above the high limit. This is also + * not a problem as all SMSs can be received. + * 3) You leave the low limit but stay below the high limit. In this case + * the N'Ack'd SMS was class 0 and you can now receive it. A non-class 0 + * SMS may attempt to be delivered, but monitoring will restart as + * before. So again no problem. + */ +void CSmsMonitorDiskSpace::ResumeSmsReception() + { + LOGSMSPROT1("CSmsMonitorDiskSpace::ResumeSmsReception"); + + // + // Cancel any previously outstanding requests... + // + if (iState != ESmsMonitorDiskSpaceIdle) + { + Cancel(); + } + + // + // Clear the N'Ackd flags... + // + iNAckdClassZero = EFalse; + iNAckdClassOther = EFalse; + + // + // Start the resume request... + // + iState = ESmsMonitorDiskSpaceResumeReception; + iSmsMessaging.ResumeSmsReception(iStatus); + iSmsComm.DiskSpaceMonitorStateChange(ESmsDiskSpaceAvailable); + SetActive(); + } // CSmsMonitorDiskSpace::ResumeSmsReception + + +/** + * Utilility function to determine amount of free disk space. The actual + * free space is limited at 2GB. + */ +TInt CSmsMonitorDiskSpace::GetFreeDiskSpace() + { + TVolumeInfo volumeInfo; + TInt ret; + +#ifdef _DEBUG + if( iInOODTesting ) + { + TInt value = 0; + ret = iFreeDiskSpaceProperty.Get(value); + + // update volumeInfo with value regardless of error as error handled later + volumeInfo.iFree = value; + } + else +#endif + { + ret = iFs.Volume(volumeInfo, EDriveC); + } + + // + // Get the volume info for drive C:... + // + + if (ret != KErrNone) + { + LOGSMSPROT2("CSmsMonitorDiskSpace::GetFreeDiskSpace(): error=%d", ret); + return KErrGeneral; + } + + // + // Convert the disk space value to a TInt (allowing 2GB limits)... + // + TInt freeSpace; + + if (volumeInfo.iFree >= 0x7fffffff) + { + freeSpace = 0x7fffffff; + } + else + { + freeSpace = (TInt) volumeInfo.iFree; + } + + LOGSMSPROT2("CSmsMonitorDiskSpace::GetFreeDiskSpace(): freeSpace=%d", freeSpace); + + return freeSpace; + } // CSmsMonitorDiskSpace::GetFreeDiskSpace