--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/smsprotocols/smsstack/smsprot/Src/smspmondsk.cpp Tue Feb 02 01:41:59 2010 +0200
@@ -0,0 +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 <barsc.h>
+#include <bautils.h>
+
+#include "smspcomm.h"
+#include "smspmondsk.h"
+#include "smsstacklog.h"
+#include "smspmain.h"
+#include "smspver.h"
+#include <smsu.rsg>
+
+
+_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<KMaxFileName> 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