Latest bug-fixes with added tests.
// Copyright (c) 2006-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:
//
#include "Gsmumain.h"
#include "gsmunonieoperations.h"
#include "Gsmumsg.h"
#include "gsmumsgadditionalattributes.h"
#include "Gsmuelem.h"
#include "smsstacklog.h"
/**
* @internalComponent
*
* This is used by the CSmsMessage to create a CSmsNonIEOperation.
* Each instance is owned by the CSmsMessage which created it.
* Therefore only the CSmsMessage (GSMU component) is allowed to
* create and delete CSmsNonIEOperations.
*
* @param aId The ID for the element for which an operation class needs to be created.
* @param aMessage The CSmsMessage that this operations class belongs to.
*/
CSmsNonIEOperation* CSmsNonIEOperation::NewL(TSmsNonIEIdentifier aId, CSmsMessage& aMessage)
{
CSmsNonIEOperation* nonIEOperation = NULL;
if(aId == ESmsTPSRRParameter)
{
nonIEOperation = new (ELeave) CSmsTPSRROperations(aId, aMessage);
}
else if (aId == ESmsIncompleteClass0MessageParameter)
{
nonIEOperation = new (ELeave) CIncompleteClass0MessageInfo(aId, aMessage);
}
else
{
User::Leave(KErrArgument);
}
CleanupStack::PushL(nonIEOperation);
nonIEOperation->ConstructL();
CleanupStack::Pop();
return nonIEOperation;
}
/**
* @publishedAll
*
* Identifies the element which is supported by this operations class.
*
* @return The element ID supported by this operations class.
*
* @capability None
*/
EXPORT_C TSmsNonIEIdentifier CSmsNonIEOperation::Id() const
{
return iId;
}
/**
* @internalComponent
*
* Identifies whether the message type supports is supported
*
* @return True if the message type is supported. False otherwise.
*/
TBool CSmsNonIEOperation::MessageTypeSupported() const
{
CSmsPDU::TSmsPDUType type = iMessage.Type();
return ((type == CSmsPDU::ESmsDeliver) ||
(type == CSmsPDU::ESmsSubmit));
}
CSmsNonIEOperation::CSmsNonIEOperation(TSmsNonIEIdentifier aId, CSmsMessage& aMessage) : iId(aId), iMessage(aMessage)
{
}
/**
* @internalComponent
*
* Prevent clients from using the assignment operator by including it in the class definition
* but making it protected and not exporting it.
*
* @capability None
*/
void CSmsNonIEOperation::operator=(const CSmsNonIEOperation&)
{
// Ignore in code coverage - not intended to be used
BULLSEYE_OFF
LOGGSMU1("CSmsNonIEOperation::operator=");
Panic(KGsmuPanicMethodBodyNotImplemented1);
BULLSEYE_RESTORE
}
/**
* @internalComponent
*
* Prevent clients from using the equality operator by including it in the class definition
* but making it protected and not exporting it.
*
* @capability None
*/
TBool CSmsNonIEOperation::operator==(const CSmsNonIEOperation&)
{
// Ignore in code coverage - not intended to be used
BULLSEYE_OFF
LOGGSMU1("CSmsNonIEOperation::operator==");
Panic(KGsmuPanicMethodBodyNotImplemented1);
return EFalse;
BULLSEYE_RESTORE
}
/**
* @internalComponent
*
* Prevent clients from using the assignment operator by including it in the class definition
* but making it protected and not exporting it.
*
* @capability None
*/
void CSmsCtrlNonIEOperation::operator=(const CSmsCtrlNonIEOperation&)
{
// Ignore in code coverage - not intended to be used
BULLSEYE_OFF
LOGGSMU1("CSmsCtrlNonIEOperation::operator=");
Panic(KGsmuPanicMethodBodyNotImplemented1);
BULLSEYE_RESTORE
}
/**
* @internalComponent
*
* Prevent clients from using the equality operator by including it in the class definition
* but making it protected and not exporting it.
*
* @capability None
*/
TBool CSmsCtrlNonIEOperation::operator==(const CSmsCtrlNonIEOperation&)
{
// Ignore in code coverage - not intended to be used
BULLSEYE_OFF
LOGGSMU1("CSmsCtrlNonIEOperation::operator==");
Panic(KGsmuPanicMethodBodyNotImplemented1);
return EFalse;
BULLSEYE_RESTORE
}
CSmsCtrlNonIEOperation::CSmsCtrlNonIEOperation(TSmsNonIEIdentifier aId, CSmsMessage& aMessage) : CSmsNonIEOperation(aId, aMessage)
{
}
void CSmsNonIEOperation::ConstructL()
{
}
/**
* Status Reporting.
*
* @note This should be the last thing that should be configured in CSmsMessage.
* If anything is changed after this then the number of PDUs might change which
* will affect status reporting.
*/
CSmsTPSRROperations::CSmsTPSRROperations(TSmsNonIEIdentifier aId, CSmsMessage& aMessage)
: CSmsCtrlNonIEOperation(aId, aMessage)
{
}
/**
* @internalComponent
*
* Prevent clients from using the assignment operator by including it in the class definition
* but making it protected and not exporting it.
*
* @capability None
*/
void CSmsTPSRROperations::operator=(const CSmsTPSRROperations&)
{
// Ignore in code coverage - not intended to be used
BULLSEYE_OFF
LOGGSMU1("CSmsTPSRROperations::operator=");
Panic(KGsmuPanicMethodBodyNotImplemented1);
BULLSEYE_RESTORE
}
/**
* @internalComponent
*
* Prevent clients from using the equality operator by including it in the class definition
* but making it protected and not exporting it.
*
* @capability None
*/
TBool CSmsTPSRROperations::operator==(const CSmsTPSRROperations&)
{
// Ignore in code coverage - not intended to be used
BULLSEYE_OFF
LOGGSMU1("CSmsTPSRROperations::operator==");
Panic(KGsmuPanicMethodBodyNotImplemented1);
return EFalse;
BULLSEYE_RESTORE
}
/**
* @internalComponent
*
* Identifies whether the message type or version supports this operation
*
* @leave If the message type or version does not support this operation.
*/
void CSmsTPSRROperations::ValidateOperationL() const
{
if (iMessage.Version() < CSmsMessage::ESmsMessageV2)
{
LOGGSMU2("CSmsTPSRROperations Operation not supported, Msg Version %d", iMessage.Version());
User::Leave(KErrNotSupported);
}
if (!MessageTypeSupported())
{
LOGGSMU2("CSmsTPSRROperations Operation not supported by this PDU type, type = %d", iMessage.Type());
User::Leave(KErrNotSupported);
}
}
/**
* @publishedAll
*
* Sets the TPSRR bit for the last PDU depending on the value of aEnable.
* First the scheme is obtained by calling the GetStatusReportScheme.
* Then the array iTPSRRStatusReport is traversed to find the last segement.
* Once that is done the TPSRR bit for it is updated. If the last segment is
* not present in the array then it is appended to it with its TPSRR status.
*
* @param aEnable
* ETrue to set the TPSRR bit to TSmsFirstOctet::ESmsStatusReportRequested
* or EFalse to set it to TSmsFirstOctet::ESmsStatusReportNotRequested.
*
* @leave KErrNotFound If the scheme is not valid.
*
* @capability None
*/
EXPORT_C void CSmsTPSRROperations::SetLastSegmentStatusReportL(TBool aEnable)
{
ValidateOperationL();
CSmsMessageAdditionalAttributes& additionalAttributes = *((CSmsMessageAdditionalAttributes*) iMessage.AdditionalInfo());
CSmsMessageAdditionalAttributes::CSmsStatusReportScheme& scheme = additionalAttributes.GetStatusReportScheme();
if (scheme.Id() == ETPSRRScheme)
{
CSmsMessageAdditionalAttributes::CTPSRRScheme& tpsrrScheme = (CSmsMessageAdditionalAttributes::CTPSRRScheme&)scheme;
TBool found(EFalse);
TInt count = (tpsrrScheme.iTPSRRStatusReport).Count();
for (TInt ii=0; !found && ii<count; ii++)
{
if ((tpsrrScheme.iTPSRRStatusReport[ii]).iSegmentSequenceNum == tpsrrScheme.iNumOfPDUs-1)
{
if(aEnable)
{
(tpsrrScheme.iTPSRRStatusReport[ii]).iTPSRRStatus = TSmsFirstOctet::ESmsStatusReportRequested;
}
else
{
(tpsrrScheme.iTPSRRStatusReport[ii]).iTPSRRStatus = TSmsFirstOctet::ESmsStatusReportNotRequested;
}
found = ETrue;
break;
}
}
if (!found)
{
CSmsMessageAdditionalAttributes::CTPSRRScheme::TSmsTPSRRStatus tpsrrStatus;
tpsrrStatus.iSegmentSequenceNum = tpsrrScheme.iNumOfPDUs-1;
if(aEnable)
{
tpsrrStatus.iTPSRRStatus = TSmsFirstOctet::ESmsStatusReportRequested;
}
else
{
tpsrrStatus.iTPSRRStatus = TSmsFirstOctet::ESmsStatusReportNotRequested;
}
(tpsrrScheme.iTPSRRStatusReport).AppendL(tpsrrStatus);
}
}
else
{
User::Leave(KErrNotFound);
}
}
/**
* @publishedAll
*
* Sets the TPSRR bit for any PDU depending on the value of aEnable.
* First the scheme is obtained by calling the GetStatusReportScheme.
* Then the array iTPSRRStatusReport is traversed to find the segment
* which has the reference number = aSegmentSequenceNum. Once that is done
* the TPSRR bit for it is updated.
*
* If the refernce number is not found then it is added to the array.
*
* @param aSegmentSequenceNum
* Segment Sequence number of the PDU that is to be updated.
* @param aEnable
* ETrue to set the TPSRR bit to TSmsFirstOctet::ESmsStatusReportRequested
* or EFalse to set it to TSmsFirstOctet::ESmsStatusReportNotRequested.
*
* @return KErrNone if the operation is successful.
* KErrNotFound if the Segment Sequence Number is out of range or
* if the scheme is not valid.
*
* @leave If ValidateOperationL or AppendL leaves.
*
* @capability None
*/
EXPORT_C TInt CSmsTPSRROperations::SetSegmentStatusReportL(TUint aSegmentSequenceNum, TBool aEnable)
{
ValidateOperationL();
CSmsMessageAdditionalAttributes& additionalAttributes = *((CSmsMessageAdditionalAttributes*) iMessage.AdditionalInfo());
CSmsMessageAdditionalAttributes::CSmsStatusReportScheme& scheme = additionalAttributes.GetStatusReportScheme();
if (scheme.Id() == ETPSRRScheme)
{
CSmsMessageAdditionalAttributes::CTPSRRScheme& tpsrrScheme = (CSmsMessageAdditionalAttributes::CTPSRRScheme&)scheme;
if( aSegmentSequenceNum>=tpsrrScheme.iNumOfPDUs)
{
return KErrNotFound; // aSegmentSequenceNum out of range.
}
TBool found(EFalse);
TInt count = (tpsrrScheme.iTPSRRStatusReport).Count();
for (TInt ii=0; !found && ii<count; ii++)
{
if ((tpsrrScheme.iTPSRRStatusReport[ii]).iSegmentSequenceNum == aSegmentSequenceNum)
{
if(aEnable)
{
(tpsrrScheme.iTPSRRStatusReport[ii]).iTPSRRStatus = TSmsFirstOctet::ESmsStatusReportRequested;
}
else
{
(tpsrrScheme.iTPSRRStatusReport[ii]).iTPSRRStatus = TSmsFirstOctet::ESmsStatusReportNotRequested;
}
found = ETrue;
break;
}
}
if (!found)
{
CSmsMessageAdditionalAttributes::CTPSRRScheme::TSmsTPSRRStatus tpsrrStatus;
tpsrrStatus.iSegmentSequenceNum = aSegmentSequenceNum;
if(aEnable)
{
tpsrrStatus.iTPSRRStatus = TSmsFirstOctet::ESmsStatusReportRequested;
}
else
{
tpsrrStatus.iTPSRRStatus = TSmsFirstOctet::ESmsStatusReportNotRequested;
}
(tpsrrScheme.iTPSRRStatusReport).AppendL(tpsrrStatus);
}
return KErrNone;
}
else
{
return KErrNotFound; // Invalid Scheme
}
}
/**
* @publishedAll
*
* Gets the selective status for a PDU if the scheme is set to the TPSRR Scheme.
*
* @param aSegmentSequenceNum The segment sequence number of the PDU whose status report
* is required.
*
* @return The TPSRR bit for the PDU.
*
* @capability None
*/
EXPORT_C TInt CSmsTPSRROperations::GetStatusReport(TUint aSegmentSequenceNum) const
{
CSmsMessageAdditionalAttributes* additionalAttributes = (CSmsMessageAdditionalAttributes*) iMessage.AdditionalInfo();
CSmsMessageAdditionalAttributes::CSmsStatusReportScheme& scheme = additionalAttributes->GetStatusReportScheme();
if (scheme.Id() == ETPSRRScheme)
{
CSmsMessageAdditionalAttributes::CTPSRRScheme& tpsrrScheme = (CSmsMessageAdditionalAttributes::CTPSRRScheme&)scheme;
if(aSegmentSequenceNum>=tpsrrScheme.iNumOfPDUs)
{
return KErrNotFound; // aSegmentSequenceNum out of range.
}
TInt count = (tpsrrScheme.iTPSRRStatusReport).Count();
for (TInt ii=0; ii<count; ii++)
{
if ((tpsrrScheme.iTPSRRStatusReport[ii]).iSegmentSequenceNum == aSegmentSequenceNum)
{
return (tpsrrScheme.iTPSRRStatusReport[ii]).iTPSRRStatus;
}
}
return tpsrrScheme.iDefaultStatusReport;
}
else
{
return KErrNotFound;
}
}
/**
* @publishedAll
*
* Sets the default value of the status report to requested or not requested as per aEnable.
*
* @param aEnable To set the default to Requested or Not Requested.
*
* @capability None
*/
EXPORT_C void CSmsTPSRROperations::SetDefaultL(TBool aEnable)
{
CSmsMessageAdditionalAttributes& additionalAttributes = *((CSmsMessageAdditionalAttributes*) iMessage.AdditionalInfo());
CSmsMessageAdditionalAttributes::CSmsStatusReportScheme& scheme = additionalAttributes.GetStatusReportScheme();
if (scheme.Id() == ETPSRRScheme)
{
CSmsMessageAdditionalAttributes::CTPSRRScheme& tpsrrScheme = (CSmsMessageAdditionalAttributes::CTPSRRScheme&)scheme;
if(aEnable)
{
tpsrrScheme.iDefaultStatusReport = TSmsFirstOctet::ESmsStatusReportRequested;
}
else
{
tpsrrScheme.iDefaultStatusReport = TSmsFirstOctet::ESmsStatusReportNotRequested;
}
}
else
{
User::Leave(KErrNotFound);
}
}
/**
* @publishedAll
*
* This method is called to set the scheme to TPSRR Scheme.
* First iStatusReportScheme, which is obtained by calling GetStatusReportScheme,
* is deleted and the set to NULL. Then a new scheme is created and a default value is set.
* The last segment is set to have TPSRR bit as Requested. This should be the last method
* to be called in a message sending process as all the operations in this interface depend
* on the number of PDUs being set.
*
* @leave If ValidateOperationL or NumMessagePDUsL leaves.
*
* @capability None
*/
EXPORT_C void CSmsTPSRROperations::SetSchemeL()
{
ValidateOperationL();
//check if UserData has SMSC Information Element, if so delete it
CSmsUserData& userData = iMessage.SmsPDU().UserData();
TInt index=0;
TBool hasSMSC=userData.InformationElementIndex(CSmsInformationElement::ESmsIEISMSCControlParameters,index);
if(hasSMSC)
{
userData.RemoveInformationElement(index);
}
CSmsMessageAdditionalAttributes& additionalAttributes = *((CSmsMessageAdditionalAttributes*) iMessage.AdditionalInfo());
additionalAttributes.SetStatusReportSchemeL(ETPSRRScheme);
CSmsMessageAdditionalAttributes::CSmsStatusReportScheme& scheme = additionalAttributes.GetStatusReportScheme();
CSmsMessageAdditionalAttributes::CTPSRRScheme& tpsrrScheme = (CSmsMessageAdditionalAttributes::CTPSRRScheme&)scheme;
tpsrrScheme.iNumOfPDUs = iMessage.NumMessagePDUsL();
SetDefaultL(EFalse);
}
/**
* @publishedAll
*
* Gets the current scheme being used.
*
* @return ETPSRRScheme is returned when TPSRR Scheme is being used.
*
* @capability None
*/
EXPORT_C TSmsStatusReportScheme CSmsTPSRROperations::GetScheme() const
{
CSmsMessageAdditionalAttributes* additionalAttributes = (CSmsMessageAdditionalAttributes*) iMessage.AdditionalInfo();
return (additionalAttributes->GetStatusReportScheme()).Id();
}
/**
* @publishedAll
*
* If the current scheme is set to TPSRR Scheme then
* this method sets the scheme to the Default scheme.
*
* @capability None
*/
EXPORT_C void CSmsTPSRROperations::ResetSchemeL()
{
CSmsMessageAdditionalAttributes& additionalAttributes = *((CSmsMessageAdditionalAttributes*) iMessage.AdditionalInfo());
additionalAttributes.SetStatusReportSchemeL(EDefaultScheme);
}
/**
* constructor
*
*/
CIncompleteClass0MessageInfo::CIncompleteClass0MessageInfo(TSmsNonIEIdentifier aId, CSmsMessage& aMessage)
: CSmsNonIEOperation(aId, aMessage)
{
LOGGSMU1("CIncompleteClass0MessageInfo constructor");
}
/**
* @publishedAll
*
* Gets the incomplete message info.
* This information will indicate the partial complete message consists of which PDUs.
*
* @param aStartPos Starting PDU position of decoded message.
* @param aEndPos End PDU position of decoded message.
* @param aLastPartialCompleteMsg boolean value indicating this is the last
* incomplete message for a particular concatenated message.
* @capability None
*/
EXPORT_C void CIncompleteClass0MessageInfo::GetIncompleteMessageInfoL(TInt& aStartPos, TInt& aEndPos, TBool& aIsLastIncompleteMessage)
{
LOGGSMU1("CIncompleteClass0MessageInfo::GetIncompleteMessageInfoL");
ValidateOperationL();
aStartPos = iStartPos;
aEndPos = iEndPos;
aIsLastIncompleteMessage = iIsLastIncompleteMessage;
}
/**
* @publishedAll
*
* Sets the incomplete message info.
* This information will indicate the partial complete message consists of which PDUs.
*
* @param aStartPos Starting PDU position of decoded message.
* @param aEndPos End PDU position of decoded message.
* @param aLastPartialCompleteMsg boolean value indicating this is the last
* incomplete message for a particular concatenated message.
* @capability None
*/
EXPORT_C void CIncompleteClass0MessageInfo::SetIncompleteMessageInfoL(TInt aStartPos, TInt aEndPos, TBool aIsLastIncompleteMessage)
{
LOGGSMU1("CIncompleteClass0MessageInfo::SetIncompleteMessageInfoL");
ValidateOperationL();
iStartPos = aStartPos;
iEndPos = aEndPos;
iIsLastIncompleteMessage = aIsLastIncompleteMessage;
}
/**
* @internalComponent
*
* Prevent clients from using the assignment operator by including it in the class definition
* but making it protected and not exporting it.
*
* @capability None
*/
void CIncompleteClass0MessageInfo::operator=(const CIncompleteClass0MessageInfo&)
{
// Ignore in code coverage - not intended to be used
BULLSEYE_OFF
LOGGSMU1("CIncompleteClass0MessageInfo::operator=");
Panic(KGsmuPanicMethodBodyNotImplemented1);
BULLSEYE_RESTORE
}
/**
* @internalComponent
*
* Prevent clients from using the equality operator by including it in the class definition
* but making it protected and not exporting it.
*
* @capability None
*/
TBool CIncompleteClass0MessageInfo::operator==(const CIncompleteClass0MessageInfo&)
{
// Ignore in code coverage - not intended to be used
BULLSEYE_OFF
LOGGSMU1("CIncompleteClass0MessageInfo::operator==");
Panic(KGsmuPanicMethodBodyNotImplemented1);
return EFalse;
BULLSEYE_RESTORE
}
/**
* @internalComponent
*
* Identifies which message type is supported
*
* @return True if the message type is supported. False otherwise.
*/
TBool CIncompleteClass0MessageInfo::MessageTypeSupported() const
{
LOGGSMU1("CIncompleteClass0MessageInfo::MessageTypeSupported");
CSmsPDU::TSmsPDUType type = iMessage.Type();
return (type == CSmsPDU::ESmsDeliver);
}
/**
* @internalComponent
*
* Identifies whether the message type or version supports this operation
*
* @leave If the message type or version does not support this operation.
*/
void CIncompleteClass0MessageInfo::ValidateOperationL() const
{
LOGGSMU1("CIncompleteClass0MessageInfo::ValidateOperationL");
if (iMessage.Version() != CSmsMessage::ESmsIncompleteClass0MessageV)
{
LOGGSMU2("CIncompleteClass0MessageInfo Operation not supported, Msg Version %d", iMessage.Version());
User::Leave(KErrNotSupported);
}
if (!MessageTypeSupported())
{
LOGGSMU2("CIncompleteClass0MessageInfo Operation not supported by this PDU type, type = %d", iMessage.Type());
User::Leave(KErrNotSupported);
}
}
/**
* Returns the incomplete class 0 message version number.
* @capability
*/
TInt CIncompleteClass0MessageInfo::Version()
{
// Ignore in code coverage - as there is only one version of this
// class, no need to check the version. Expected to be used if
// a new version of the class is added
BULLSEYE_OFF
LOGGSMU1("CIncompleteClass0MessageInfo::Version()");
return iVersion;
BULLSEYE_RESTORE
}
/**
* @internalComponent
* Validates and sets the message version number.
*
* @param aVersion version number to set.
* @capability None
*/
void CIncompleteClass0MessageInfo::SetVersion(TInt aVersion)
{
LOGGSMU2("CIncompleteClass0MessageInfo::SetVersion()", aVersion);
__ASSERT_DEBUG((aVersion<EMaxSmsIncompleteClass0MessageV),Panic(KGsmuPanicVersionNotSupported));
iVersion=aVersion;
} // CSmsMessage::SetVersion
/**
* Internalises all object data.
*
* @param aStream Stream to read from
* @capability None
*/
void CIncompleteClass0MessageInfo::InternalizeL(RReadStream& aStream)
{
LOGGSMU1("CIncompleteClass0MessageInfo::InternalizeL()");
iVersion = aStream.ReadInt32L();
iStartPos = aStream.ReadInt32L();
iEndPos = aStream.ReadInt32L();
iIsLastIncompleteMessage = aStream.ReadInt32L();
}
/**
* Externalises all object data.
*
* @param aStream Stream to write to
* @capability None
*/
void CIncompleteClass0MessageInfo::ExternalizeL(RWriteStream& aStream) const
{
LOGGSMU1("CIncompleteClass0MessageInfo::ExternalizeL()");
aStream.WriteInt32L(iVersion);
aStream.WriteInt32L(iStartPos);
aStream.WriteInt32L(iEndPos);
aStream.WriteInt32L(iIsLastIncompleteMessage);
}