// 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:
// Implements CSmsReassemblyStore and CSmsSegmentationStore.
//
//
/**
@file
*/
#include <e32svr.h>
#include <es_ini.h>
#include "smspstor.h"
#include "smspmain.h"
#include "smsuaddr.H"
#include "Gsmumsg.h"
#include "gsmubuf.h"
#include <logwrap.h>
#include <logwraplimits.h>
#include "Gsmuelem.h"
#include "gsmuieoperations.h"
#include "gsmunonieoperations.h"
LOCAL_C TPtrC TrimLeadingZeros(const TDesC& aString)
{
LOGSMSPROT1("CSARStore::ExternalizeEntryArrayL()");
const TInt len = aString.Length();
if (len == 0)
return aString;
const TUint16* startChar = &aString[0];
const TUint16* endChar = &aString[len-1];
while (startChar <= endChar && *startChar == '0')
{
++startChar;
}
return TPtrC(startChar, endChar - startChar + 1);
} // TrimLeadingZeros
/**
* Creates new CSmsReassemblyStore instance
*
* @param aFs File Server handle.
*/
CSmsReassemblyStore* CSmsReassemblyStore::NewL(RFs& aFs)
{
LOGSMSPROT1("CSmsReassemblyStore::NewL()");
CSmsReassemblyStore* self = new (ELeave) CSmsReassemblyStore(aFs);
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop(self);
return self;
} // CSmsReassemblyStore::NewL
/**
* Creates and starts timer
*/
void CSmsReassemblyStore::ConstructL()
{
LOGSMSPROT1("CSmsReassemblyStore::ConstructL()");
//
// Generate the full path to the reassembly store.
//
PrivatePath(iFullPathBuf);
iFullPathBuf.Append(KReassemblyStoreName);
iLastReceivedTime.UniversalTime();
iLastRealTime = iLastReceivedTime;
} // CSmsReassemblyStore::ConstructL
/**
* Destructor
*/
CSmsReassemblyStore::~CSmsReassemblyStore()
{
// NOP
} // CSmsReassemblyStore::~CSmsReassemblyStore
void CSmsReassemblyStore::UpdateLogServerIdL(TInt aIndex, TLogId aLogServerId)
{
LOGSMSPROT1("CSmsReassemblyStore::UpdateLogServerIdL()");
TSmsReassemblyEntry entry(reinterpret_cast<const TSmsReassemblyEntry&>(Entries()[aIndex]));
if (entry.LogServerId() != aLogServerId)
{
entry.SetLogServerId(aLogServerId);
BeginTransactionLC();
ChangeEntryL(aIndex, entry);
CommitTransactionL();
}
} // CSmsReassemblyStore::UpdateLogServerIdL
/**
* Searches the reassembly store for a CSmsMessage and returns its index.
*
* @param aSmsMessage Message to search for.
* @param aPassed Determines if we are searching for a message already
* passed to the client.
* @param aIndex Return index value.
*
* @return True and an index if aSmsMessage is found in this reassembly store
*/
TBool CSmsReassemblyStore::FindMessageL(const CSmsMessage& aSmsMessage,
TBool aPassed,
TInt& aIndex)
{
LOGSMSPROT1("CSmsReassemblyStore::FindMessageL()");
//
// Parse the GSM data from the SMS message...
//
TGsmSmsTelNumber parsedAddress;
aSmsMessage.ParsedToFromAddress(parsedAddress);
//
// Search the store for a matching message...
//
for (TInt index = Entries().Count() - 1; index >= 0; index--)
{
const TSmsReassemblyEntry& entry = reinterpret_cast<const TSmsReassemblyEntry&>(Entries()[index]);
// Always search the basic types first and strings last!
if (entry.PduType() == aSmsMessage.Type() &&
entry.PassedToClient() == aPassed &&
entry.Storage() == aSmsMessage.Storage() &&
entry.Time() == aSmsMessage.Time() &&
entry.Description2().Right(8) == parsedAddress.iTelNumber.Right(8))
{
//
// Found!
//
LOGSMSPROT2("CSmsReassemblyStore::FindMessage(): Found! index=%d", index);
aIndex = index;
return ETrue;
}
}
//
// Not found...
//
LOGSMSPROT1("CSmsReassemblyStore::FindMessage(): Not found!");
return EFalse;
} // CSmsReassemblyStore::FindMessageL
/**
* Adds Pdu to reassembly store
*
* @param aSmsMessage PDU to
* @param aGsmSms Used to
* @param aIndex Used to
* @param aComplete Used to
* @param aServiceCenterAddressPresent Used to
*/
void CSmsReassemblyStore::MatchPDUToExistingMessage(const CSmsMessage& aSmsMessage,
TInt& aIndex)
{
LOGSMSPROT1("CSmsReassemblyStore::MatchPDUToExistingMessage()");
__ASSERT_ALWAYS(!aSmsMessage.IsDecoded(), SmspPanic(KSmspPanicMessageConcatenated));
aIndex = KErrNotFound;
TGsmSmsTelNumber parsedAddress;
aSmsMessage.ParsedToFromAddress(parsedAddress);
//
// Search the reassembly store for a matching entry (start from the
// end as the most recent PDUs appear at the end)...
//
TInt reassemblyCount = Entries().Count();
for (TInt index = reassemblyCount - 1; index >= 0; index--)
{
TSmsReassemblyEntry& entry = (TSmsReassemblyEntry&) Entries()[index];
// Always check the fields in order of the quickest to check...
if (entry.IsComplete() == EFalse &&
entry.PduType() == aSmsMessage.Type() &&
entry.Storage() == aSmsMessage.Storage())
{
TInt telLen = Min(entry.Description2().Length(),
parsedAddress.iTelNumber.Length());
if (entry.Description2().Right(telLen) == parsedAddress.iTelNumber.Right(telLen) &&
entry.Total() == aSmsMessage.SmsPDU().NumConcatenatedMessagePDUs() &&
entry.Reference() == aSmsMessage.SmsPDU().ConcatenatedMessageReference())
{
//
// Found it!
//
aIndex = index;
break;
}
}
}
LOGSMSPROT3("CSmsReassemblyStore::MatchPDUToExistingMessage(): reassemblyCount=%d, aIndex=%d", reassemblyCount, aIndex);
} // CSmsReassemblyStore::MatchPDUToExistingMessage
void CSmsReassemblyStore::UpdateExistingMessageL(const CSmsMessage& aSmsMessage,
const TGsmSms& aGsmSms, TInt aIndex,
TBool& aComplete,
TBool& aDuplicateMsgRef,
TBool& aDuplicateSlot)
{
LOGSMSPROT1("CSmsReassemblyStore::UpdateExistingMessageL()");
aComplete = EFalse;
aDuplicateMsgRef = EFalse;
aDuplicateSlot = EFalse;
//
// Read the segment from the store into a CSmsMessage buffer...
//
TSmsReassemblyEntry entry = (TSmsReassemblyEntry&) Entries()[aIndex];
CArrayFix<TInt>* indexArray = new(ELeave) CArrayFixFlat<TInt>(8);
CleanupStack::PushL(indexArray);
CArrayFixFlat<TGsmSms>* smsArray = new(ELeave) CArrayFixFlat<TGsmSms>(8);
CleanupStack::PushL(smsArray);
CSmsBuffer* buffer = CSmsBuffer::NewL();
CSmsMessage* smsMessage = CSmsMessage::NewL(iFs, CSmsPDU::ESmsDeliver, buffer);
CleanupStack::PushL(smsMessage);
InternalizeEntryL(entry.DataStreamId(), *smsMessage, *indexArray, *smsArray);
//
// Check if this is a duplicated enumerated PDU (e.g. on the SIM or phone memory)
// or a duplicated PDU (e.g. in the Reassembly Store)...
//
TInt concatPDUIndex = aSmsMessage.SmsPDU().ConcatenatedMessagePDUIndex();
if (smsMessage->Storage() == CSmsMessage::ESmsSIMStorage ||
smsMessage->Storage() == CSmsMessage::ESmsCombinedStorage)
{
//
// In most cases this PDU is being enumerated, but not always. It is
// possible for the PDU to be stored on the SIM first before it is
// received.
//
const TGsmSmsSlotEntry& newSlot = aSmsMessage.iSlotArray[0];
TInt slotArrayCount = smsMessage->iSlotArray.Count();
for (TInt slotNum = 0; slotNum < slotArrayCount; slotNum++ )
{
const TGsmSmsSlotEntry& slot = smsMessage->iSlotArray[slotNum];
if (slot.iIndex == newSlot.iIndex && slot.iStore == newSlot.iStore)
{
LOGSMSPROT1("CSmsReassemblyStore::UpdateExistingMessageL(): Duplicate enumerated PDU.");
// It is a duplicate that was already stored on the SIM...
aDuplicateSlot = ETrue;
break;
}
}
}
TInt indexArrayCount = indexArray->Count();
for (TInt index = 0; index < indexArrayCount; index++ )
{
if (indexArray->At(index) == concatPDUIndex)
{
LOGSMSPROT1("CSmsReassemblyStore::UpdateExistingMessageL(): Duplicate concatenated PDU.");
// The PDU is already stored in the reassembly store.
aDuplicateMsgRef = ETrue;
break;
}
}
if (aDuplicateMsgRef || aDuplicateSlot)
{
CleanupStack::PopAndDestroy(3, indexArray); // smsMessage, smsArray, indexArray
return;
}
//
// If the PDU is stored then add the slot information...
//
if (smsMessage->Storage() == CSmsMessage::ESmsSIMStorage ||
smsMessage->Storage() == CSmsMessage::ESmsCombinedStorage)
{
smsMessage->AddSlotL(aSmsMessage.iSlotArray[0]);
}
//
// If the PDU is Unsent or Unread, then store that information...
//
NMobileSmsStore::TMobileSmsStoreStatus status = aSmsMessage.Status();
if (status == NMobileSmsStore::EStoredMessageUnsent ||
status == NMobileSmsStore::EStoredMessageUnread)
{
smsMessage->SetStatus(status);
}
//
// Does this PDU mean the message is complete? If so then decode the message,
// reset the index and sms arrays (to save space for completed SMSs).
//
indexArray->AppendL(concatPDUIndex);
smsArray->AppendL(aGsmSms);
if (smsArray->Count() == smsMessage->SmsPDU().NumConcatenatedMessagePDUs())
{
smsMessage->DecodeMessagePDUsL(*smsArray);
indexArray->Reset();
smsArray->Reset();
aComplete = ETrue;
}
//
// Write the entry back into the store...
//
TStreamId streamid = entry.DataStreamId();
smsMessage->SetLogServerId(entry.LogServerId());
BeginTransactionLC();
ExternalizeEntryL(streamid, *smsMessage, *indexArray, *smsArray);
PopulateEntry(entry, *smsMessage, smsArray->Count());
ChangeEntryL(aIndex, entry);
CommitTransactionL();
CleanupStack::PopAndDestroy(3, indexArray); // smsMessage, smsArray, indexArray
} // CSmsReassemblyStore::UpdateExistingMessageL
void CSmsReassemblyStore::NewMessagePDUL(TInt& aIndex,CSmsMessage& aSmsMessage,const TGsmSms& aGsmSms)
{
LOGSMSPROT1("CSmsReassemblyStore::NewMessagePDUL");
CArrayFix<TInt>* indexarray=new(ELeave) CArrayFixFlat<TInt>(8);
CleanupStack::PushL(indexarray);
CArrayFixFlat<TGsmSms>* smsarray=new(ELeave) CArrayFixFlat<TGsmSms>(8);
CleanupStack::PushL(smsarray);
TInt index=aSmsMessage.IsDecoded()? 0: aSmsMessage.SmsPDU().ConcatenatedMessagePDUIndex();
indexarray->AppendL(index);
smsarray->AppendL(aGsmSms);
aIndex=Entries().Count();
CreateEntryL(aSmsMessage,*indexarray,*smsarray);
CleanupStack::PopAndDestroy(2);
} // CSmsReassemblyStore::NewMessagePDUL
void CSmsReassemblyStore::GetMessageL(TInt aIndex,CSmsMessage& aSmsMessage)
{
LOGSMSPROT2("CSmsReassemblyStore::GetMessageL [aIndex=%d]", aIndex);
CArrayFix<TInt>* indexarray=new(ELeave) CArrayFixFlat<TInt>(8);
CleanupStack::PushL(indexarray);
CArrayFixFlat<TGsmSms>* smsarray=new(ELeave) CArrayFixFlat<TGsmSms>(8);
CleanupStack::PushL(smsarray);
InternalizeEntryL(Entries()[aIndex].DataStreamId(),aSmsMessage,*indexarray,*smsarray);
TInt logid=Entries()[aIndex].LogServerId();
if(aSmsMessage.LogServerId() == KLogNullId && logid != KLogNullId)
aSmsMessage.SetLogServerId(logid);
CleanupStack::PopAndDestroy(2); // smsarray, indexarray
} // CSmsReassemblyStore::GetMessageL
/**
* internalize all the entries from the permanent file store to internal memory
*
* NOTE! You have to call CSARStore::OpenFileLC() before calling this function
*/
void CSmsReassemblyStore::InternalizeEntryL(const TStreamId& aStreamId,CSmsMessage& aSmsMessage,CArrayFix<TInt>& aIndexArray,CArrayFix<TGsmSms>& aSmsArray)
{
LOGSMSPROT2("CSmsReassemblyStore::InternalizeEntryL Start [sid=%d]", aStreamId.Value());
RStoreReadStream readstream;
readstream.OpenLC(FileStore(),aStreamId);
readstream >> aSmsMessage;
TInt count=readstream.ReadInt32L();
aIndexArray.Reset();
TInt i;
for (i=0; i<count; i++)
{
TInt index=readstream.ReadInt32L();
aIndexArray.AppendL(index);
}
count=readstream.ReadInt32L();
if(count!=aIndexArray.Count())
User::Leave(KErrCorrupt);
aSmsArray.Reset();
for (i=0; i<count; i++)
{
RMobileSmsMessaging::TMobileSmsGsmTpdu pdu;
readstream >> pdu;
TGsmSms sms;
sms.SetPdu(pdu);
aSmsArray.AppendL(sms);
}
CleanupStack::PopAndDestroy();
LOGSMSPROT2("CSmsReassemblyStore::InternalizeEntryL End [count=%d]", count);
} // CSARStore::OpenFileLC
/**
* externalizes all the entries from the internal memory to the permanent file store
*
* NOTE! You have to call CSARStore::OpenFileLC() before calling this function
*/
void CSmsReassemblyStore::ExternalizeEntryL(TStreamId& aStreamId,const CSmsMessage& aSmsMessage,const CArrayFix<TInt>& aIndexArray,const CArrayFix<TGsmSms>& aSmsArray)
{
LOGSMSPROT2("CSmsReassemblyStore::ExternalizeEntryL Start [sid=%d]", aStreamId.Value());
RStoreWriteStream writestream;
if (aStreamId==KNullStreamId)
aStreamId=writestream.CreateLC(FileStore());
else
writestream.ReplaceLC(FileStore(),aStreamId);
writestream << aSmsMessage;
TInt count=aIndexArray.Count();
__ASSERT_ALWAYS(count==aIndexArray.Count(),SmspPanic(KSmspPanicBadIndexArray));
writestream.WriteInt32L(count);
TInt i=0;
for (; i<count; i++)
writestream.WriteInt32L(aIndexArray[i]);
count=aSmsArray.Count();
writestream.WriteInt32L(count);
for (i=0; i<count; i++)
{
RMobileSmsMessaging::TMobileSmsGsmTpdu pdu;
pdu=aSmsArray[i].Pdu();
writestream << pdu;
}
writestream.CommitL();
CleanupStack::PopAndDestroy();
LOGSMSPROT2("CSmsReassemblyStore::ExternalizeEntryL End [count=%d]", count);
} // CSARStore::OpenFileLC
void CSmsReassemblyStore::PopulateEntry(TSmsReassemblyEntry& aEntry,const CSmsMessage& aSmsMessage,TInt aNumSmss)
{
LOGSMSPROT1("CSmsReassemblyStore::PopulateEntry");
aEntry.SetReference(0);
aEntry.SetTotal(1);
aEntry.SetCount(1);
if (aSmsMessage.TextPresent())
{
if (aSmsMessage.SmsPDU().TextConcatenated())
{
aEntry.SetReference(aSmsMessage.SmsPDU().ConcatenatedMessageReference());
aEntry.SetTotal(aSmsMessage.SmsPDU().NumConcatenatedMessagePDUs());
aEntry.SetCount(aSmsMessage.IsComplete()? aEntry.Total(): aNumSmss);
}
TInt bits7to4=aSmsMessage.SmsPDU().Bits7To4();
TInt count=aSmsMessage.SmsPDU().UserData().NumInformationElements();
TInt identifier1=0xFF;
TInt identifier2=0x00;
for (TInt i=0; i<count; i++)
{
TInt identifier=aSmsMessage.SmsPDU().UserData().InformationElement(i).Identifier();
if ((identifier!=CSmsInformationElement::ESmsIEIConcatenatedShortMessages8BitReference) && (identifier!=CSmsInformationElement::ESmsIEIConcatenatedShortMessages16BitReference))
{
if (identifier<identifier1)
identifier1=identifier;
if (identifier>identifier2)
identifier2=identifier;
}
}
if ((bits7to4>=TSmsDataCodingScheme::ESmsDCSMessageWaitingIndicationDiscardMessage) && (bits7to4<=TSmsDataCodingScheme::ESmsDCSMessageWaitingIndicationUCS2))
aEntry.SetBits7to4andIdentifiers(bits7to4, identifier1, identifier2);
else
aEntry.SetBits7to4andIdentifiers(0, identifier1, identifier2);
}
//Set the logServerId to aSmsMessage.LogServerId()
aEntry.SetLogServerId(aSmsMessage.LogServerId());
const CSmsPDU::TSmsPDUType type(aSmsMessage.Type());
aEntry.SetPduType(type);
aEntry.SetPassedToClient(EFalse);
aEntry.SetStorage(aSmsMessage.Storage());
if ((type!=CSmsPDU::ESmsSubmitReport) && (type!=CSmsPDU::ESmsDeliverReport))
{
// Strip out spaces etc from address
TGsmSmsTelNumber parsedaddress;
aSmsMessage.ParsedToFromAddress(parsedaddress);
aEntry.SetDescription2(parsedaddress.iTelNumber);
}
aEntry.SetTime(aSmsMessage.Time());
} // CSmsReassemblyStore::PopulateEntry
void CSmsReassemblyStore::CreateEntryL(CSmsMessage& aSmsMessage,const CArrayFix<TInt>& aIndexArray,const CArrayFix<TGsmSms>& aSmsArray)
{
LOGSMSPROT1("CSmsReassemblyStore::CreateEntryL");
TStreamId streamid=KNullStreamId;
if (aSmsMessage.Time() >= iLastRealTime)
{
iLastRealTime=aSmsMessage.Time();
if(iLastReceivedTime >= aSmsMessage.Time())
{
aSmsMessage.SetTime(iLastReceivedTime+(TTimeIntervalMicroSeconds32)1);
}
iLastReceivedTime=aSmsMessage.Time(); //provide uniqueness of time
}
else // clock turned back
{
iLastReceivedTime=aSmsMessage.Time();
}
BeginTransactionLC();
ExternalizeEntryL(streamid,aSmsMessage,aIndexArray,aSmsArray);
TSmsReassemblyEntry entry;
entry.SetDataStreamId(streamid);
PopulateEntry(entry,aSmsMessage,aSmsArray.Count());
AddEntryL(entry);
CommitTransactionL();
} // CSmsReassemblyStore::CreateEntryL
TBool CSmsReassemblyStore::PassedToClient( TInt aIndex ) const
{
LOGSMSPROT1("CSmsReassemblyStore::PassedToClient()");
const TSmsReassemblyEntry& entry = reinterpret_cast<const TSmsReassemblyEntry&>(Entries()[ aIndex ]);
return entry.PassedToClient();
} // CSmsReassemblyStore::PassedToClient
void CSmsReassemblyStore::SetPassedToClientL(TInt aIndex, TBool aPassed)
{
LOGSMSPROT1("CSmsReassemblyStore::SetPassedToClientL()");
TSmsReassemblyEntry entry(reinterpret_cast<const TSmsReassemblyEntry&>(Entries()[aIndex]));
const TBool alreadyPassed = entry.PassedToClient();
if ((!aPassed && alreadyPassed) || (aPassed && !alreadyPassed))
{
entry.SetPassedToClient(aPassed);
ChangeEntryL(aIndex, entry);
}
} // CSmsReassemblyStore::SetPassedToClientL
/**
* Open the sms reassembly store.
*/
void CSmsReassemblyStore::OpenStoreL()
{
LOGSMSPROT1("CSmsReassemblyStore::OpenStoreL()");
this->OpenL(iFullPathBuf,KReassemblyStoreUid);
} // CSmsReassemblyStore::OpenStoreL
/**
* Constructor
*
* @param aFs Used to set CSARStore object
*/
CSmsReassemblyStore::CSmsReassemblyStore(RFs& aFs)
:CSARStore(aFs)
{
// NOP
} // CSmsReassemblyStore::CSmsReassemblyStore
CSmsSegmentationStore* CSmsSegmentationStore::NewL(RFs& aFs)
{
LOGSMSPROT1("CSmsSegmentationStore::NewL()");
CSmsSegmentationStore* segmentationStore = new(ELeave) CSmsSegmentationStore(aFs);
CleanupStack::PushL( segmentationStore );
segmentationStore->ConstructL();
CleanupStack::Pop( segmentationStore );
return segmentationStore;
} // CSmsSegmentationStore::NewL
void CSmsSegmentationStore::ConstructL()
{
LOGSMSPROT1("CSmsSegmentationStore::ConstructL()");
//generate fullpath of segmentation store.
PrivatePath(iFullPathBuf);
//append store name
iFullPathBuf.Append(KSegmentationStoreName);
// Set the default value for the maxmum number messages in the segmentation store.
iMaxmumNumberOfMessagesInSegmentationStore = KDefaultMaxmumNumberOfMessagesInSegmentationStore;
CESockIniData* ini = NULL;
_LIT(KSmseskfile, "smswap.sms.esk");
TRAPD(ret, ini=CESockIniData::NewL(KSmseskfile));
if(ret == KErrNone)
{
// Get the maximum number of messages allowed in the segmentation store from .ESK file
CleanupStack::PushL(ini);
TPtrC value;
if((ini->FindVar(_L("SegmentationStoreOptions"),_L("MaxNumOfMessInSegStore"),value)))
{
TLex16 valueconv(value);
valueconv.Val(iMaxmumNumberOfMessagesInSegmentationStore);
}
CleanupStack::PopAndDestroy(ini);
}
else if (ret != KErrNotFound && ret != KErrPathNotFound)
{
User::Leave(ret);
}
} // CSmsSegmentationStore::ConstructL
CSmsSegmentationStore::~CSmsSegmentationStore()
{
// NOP
} // CSmsSegmentationStore::~CSmsSegmentationStore
TInt CSmsSegmentationStore::Next8BitReferenceL()
{
LOGSMSPROT1("CSmsSegmentationStore::Next8BitReferenceL");
TInt reference8bit=0;
TInt reference16bit=0;
TStreamId streamid=ExtraStreamId();
//
// access file store
//
BeginTransactionLC();
if (streamid!=KNullStreamId)
{
TRAPD(ret,InternalizeConcatenationReferencesL(streamid,reference8bit,reference16bit));
if(ret != KErrNone)
{
// We have to leave on any error; otherwise a duplicate reference number will be generated
// The transaction will revert
LOGSMSPROT2("WARNING! CSmsSegmentationStore::InternalizeConcatenationReferencesL left with %d", ret);
User::Leave(ret); // stream not corrupted
}
reference8bit=(reference8bit+1)%0x100;
}
TRAPD(ret, ExternalizeConcatenationReferencesL(streamid,reference8bit,reference16bit));
if(ret != KErrNone)
{
// We have to leave on any error; otherwise a duplicate reference number will be generated
// The transaction will revert
LOGSMSPROT2("WARNING! CSmsSegmentationStore::ExternalizeConcatenationReferencesL left with %d", ret);
User::Leave(ret); // stream not corrupted
}
SetExtraStreamIdL(streamid);
CommitTransactionL();
return reference8bit;
} // CSmsSegmentationStore::Next8BitReferenceL
TInt CSmsSegmentationStore::Next16BitReferenceL()
{
LOGSMSPROT1("CSmsSegmentationStore::Next16BitReferenceL");
TInt reference8bit=0;
TInt reference16bit=0x100;
TStreamId streamid=ExtraStreamId();
//
// access file store
//
BeginTransactionLC();
if (streamid!=KNullStreamId)
{
TRAPD(ret,InternalizeConcatenationReferencesL(streamid,reference8bit,reference16bit));
if(ret != KErrNone)
{
// We have to leave on any error; otherwise a duplicate reference number will be generated
// The transaction will revert
LOGSMSPROT2("WARNING! CSmsSegmentationStore::InternalizeConcatenationReferencesL left with %d", ret);
User::Leave(ret); // stream not corrupted
}
reference16bit=((reference16bit+1)%0xFF00)+0x100;
}
TRAPD(ret, ExternalizeConcatenationReferencesL(streamid,reference8bit,reference16bit));
if(ret != KErrNone)
{
// We have to leave on any error; otherwise a duplicate reference number will be generated
// The transaction will revert
LOGSMSPROT2("WARNING! CSmsSegmentationStore::ExternalizeConcatenationReferencesL left with %d", ret);
User::Leave(ret); // stream not corrupted
}
SetExtraStreamIdL(streamid);
CommitTransactionL();
return reference16bit;
} // CSmsSegmentationStore::Next16BitReferenceL
/**
* Adds a CSmsMessage to the segmentation store
*
* @note aSumbit.Buffer() may be shortened to TSAREntry::ESmsSAREntryDescriptionLength
*
* @param aSubmit Message to add to the segmentation store
* @pre aSubmit.Type() is ESmsSubmit
* @pre aSubmit.EncodeMessagePdusL() has been called. This is so PopulateEntry sets the correct total on the TSAREntry
*/
void CSmsSegmentationStore::AddSubmitL(const TSmsAddr& aSmsAddr,CSmsMessage& aSubmit)
{
LOGSMSPROT1("CSmsSegmentationStore::AddSubmitL");
__ASSERT_ALWAYS(aSubmit.Type()==CSmsPDU::ESmsSubmit,SmspPanic(KSmspPanicNotSubmit));
BeginTransactionLC();
RSmsSegmentationStoreRefStatusArray refStatus;
CleanupClosePushL(refStatus);
TStreamId streamid=KNullStreamId;
CSmsBufferBase& buffer=aSubmit.Buffer();
TInt length=buffer.Length();
if (length>TSAREntry::ESmsSAREntryDescriptionLength)
buffer.DeleteL(TSAREntry::ESmsSAREntryDescriptionLength,length-TSAREntry::ESmsSAREntryDescriptionLength);
ExternalizeEntryL(streamid,aSmsAddr,aSubmit, refStatus);
TSmsSegmentationEntry entry;
entry.SetDataStreamId(streamid);
PopulateEntry(entry, aSubmit, refStatus);
CleanupStack::PopAndDestroy(&refStatus);
AddEntryL(entry);
CommitTransactionL();
} // CSmsSegmentationStore::AddSubmitL
TBool CSmsSegmentationStore::AddCommandL(const TSmsAddr& aSmsAddr,const CSmsMessage& aCommand, CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray& aRefStatus)
{
LOGSMSPROT1("CSmsSegmentationStore::AddCommandL");
__ASSERT_ALWAYS(aCommand.Type()==CSmsPDU::ESmsCommand,SmspPanic(KSmspPanicNotCommand));
const TInt count=Entries().Count();
const TLogId logid=(TLogId) aCommand.LogServerId();
BeginTransactionLC();
for (TInt i=count-1; i>=0; --i)
{
if ((logid!=KLogNullId) && (logid==Entries()[i].LogServerId()))
{
DeleteEntryL(i);
break;
}
}
TBool found=EFalse;
CSmsBuffer* buffer=CSmsBuffer::NewL();
CSmsMessage* smsmessage=CSmsMessage::NewL(iFs, CSmsPDU::ESmsSubmit,buffer);
CleanupStack::PushL(smsmessage);
TGsmSmsTelNumber parsedaddress;
aCommand.ParsedToFromAddress(parsedaddress);
TInt telLen;
for (TInt j=0; j<count; j++)
{
TSmsSegmentationEntry entry = (TSmsSegmentationEntry&)Entries()[j];
const CSmsPDU::TSmsPDUType type = entry.PduType();
telLen=Min(entry.Description2().Length(),parsedaddress.iTelNumber.Length());
if ((type==CSmsPDU::ESmsSubmit) &&
entry.IsComplete() &&
(entry.Description2().Right(telLen)==parsedaddress.iTelNumber.Right(telLen)) &&
(entry.Time()==aCommand.Time()))
{
found=ETrue;
TSmsAddr smsaddr;
InternalizeEntryL(entry.DataStreamId(),smsaddr,*smsmessage, aRefStatus);
TStreamId streamid;
CSmsSubmit& submit=(CSmsSubmit&) smsmessage->SmsPDU();
if ((((CSmsCommand&) aCommand.SmsPDU()).CommandType()==TSmsCommandType::ESmsCommandTypeEnableStatusReportRequest) &&
(!submit.StatusReportRequest()))
{
submit.SetStatusReportRequest(ETrue);
streamid=entry.DataStreamId();
ExternalizeEntryL(streamid,smsaddr,*smsmessage, aRefStatus);
PopulateEntry(entry,*smsmessage, aRefStatus);
ChangeEntryL(j,entry);
}
RSmsSegmentationStoreRefStatusArray refStatusTemp;
CleanupClosePushL(refStatusTemp);
streamid=KNullStreamId;
ExternalizeEntryL(streamid,aSmsAddr,aCommand, refStatusTemp);
entry.SetDataStreamId(streamid);
PopulateEntry(entry,aCommand, refStatusTemp);
CleanupStack::PopAndDestroy(&refStatusTemp);
AddEntryL(entry);
break;
}
}
CleanupStack::PopAndDestroy(smsmessage); // smsmessage
CommitTransactionL();
return found;
} // CSmsSegmentationStore::AddCommandL
TBool CSmsSegmentationStore::AddReferenceL(const CSmsMessage& aSmsMessage,TInt aReference)
{
const TInt count=Entries().Count();
LOGSMSPROT3("CSmsSegmentationStore::AddReferenceL [count=%d, ref=%d]", count, aReference);
TInt i=0;
TInt logserverid=aSmsMessage.LogServerId();
if (logserverid!=KLogNullId)
{
for (i=0; i<count; i++)
{
if (logserverid==((TSmsSegmentationEntry&)Entries()[i]).LogServerId())
break;
}
}
else
{
TGsmSmsTelNumber parsedaddress;
aSmsMessage.ParsedToFromAddress(parsedaddress);
TInt telLen;
for (i=0; i<count; i++)
{
TSAREntry tsareenty = Entries()[i];
TSmsSegmentationEntry& entry = static_cast<TSmsSegmentationEntry&>(tsareenty);
telLen=Min(entry.Description2().Length(),parsedaddress.iTelNumber.Length());
const CSmsPDU::TSmsPDUType type=entry.PduType();
if ((type==aSmsMessage.Type()) && (!entry.IsComplete()) && (aSmsMessage.Time()==entry.Time()) && (entry.Description2().Right(telLen)==parsedaddress.iTelNumber.Right(telLen)))
break;
}
}
if(i>=count)
{
LOGSMSPROT3("WARNING! KSmspPanicEntryWithLogServerIdNotFound [i=%d, count=%d]", i, count);
return EFalse;
}
RSmsSegmentationStoreRefStatusArray refStatusArray;
CleanupClosePushL(refStatusArray);
TSAREntry tsareenty = Entries()[i];
TSmsSegmentationEntry& entry = static_cast<TSmsSegmentationEntry&>(tsareenty);
TStreamId streamid=entry.DataStreamId();
TSmsAddr smsaddr;
CSmsBuffer* buffer=CSmsBuffer::NewL();
CSmsMessage* smsmessage=CSmsMessage::NewL(iFs, CSmsPDU::ESmsDeliver,buffer);
CleanupStack::PushL(smsmessage);
//
// access the file store
//
InternalizeEntryL(streamid,smsaddr,*smsmessage, refStatusArray);
refStatusArray.InsertL(aReference);
BeginTransactionLC();
ExternalizeEntryL(streamid,smsaddr,*smsmessage, refStatusArray);
PopulateEntry(entry,/*smsaddr,*/*smsmessage, refStatusArray);
ChangeEntryL(i,entry);
CommitTransactionL();
//
// AEH: moved here because if is done before calling ChangeEntryL
// it will pop and destroy the filestore which is also on
// the cleanup stack
//
CleanupStack::PopAndDestroy(2); // smsmessage, refStatus
return entry.Total()==entry.Count();
}
/**
* Does exactly the same thing as AddReferenceL() i.e. adds the the segment refernce to a list. But
* to support the new status report schemes a slight change has been made. Instead of inserting
* just a reference now its status is inserted as well. This is provided one of the two new schemes
* is being used. If the status is required then we do exactly the same as AddReferenceL(), but if
* it's not then we just call the InsertL() method with an extra parameter: EStatusComplete.
*
* @param aSmsMessage Reference to CSmsMessage.
* @param aReference The PDU reference.
*/
TBool CSmsSegmentationStore::AddReferenceStatusPairL(const CSmsMessage& aSmsMessage,TInt aReference, TUint aSegmentSequenceNumber)
{
const TInt count=Entries().Count();
LOGSMSPROT3("CSmsSegmentationStore::AddReferenceStatusPairL [count=%d, ref=%d]", count, aReference);
TInt i=0;
TInt logserverid=aSmsMessage.LogServerId();
if (logserverid!=KLogNullId)
{
for (i=0; i<count; i++)
{
if (logserverid==((TSmsSegmentationEntry&)Entries()[i]).LogServerId())
break;
}
}
else
{
TGsmSmsTelNumber parsedaddress;
aSmsMessage.ParsedToFromAddress(parsedaddress);
TInt telLen;
for (i=0; i<count; i++)
{
TSAREntry tsareenty = Entries()[i];
TSmsSegmentationEntry& entry = static_cast<TSmsSegmentationEntry&>(tsareenty);
telLen=Min(entry.Description2().Length(),parsedaddress.iTelNumber.Length());
const CSmsPDU::TSmsPDUType type=entry.PduType();
if ((type==aSmsMessage.Type()) && (!entry.IsComplete()) && (aSmsMessage.Time()==entry.Time()) && (entry.Description2().Right(telLen)==parsedaddress.iTelNumber.Right(telLen)))
break;
}
}
if(i>=count)
{
LOGSMSPROT3("WARNING! KSmspPanicEntryWithLogServerIdNotFound [i=%d, count=%d]", i, count);
return EFalse;
}
RSmsSegmentationStoreRefStatusArray refStatusArray;
CleanupClosePushL(refStatusArray);
TSAREntry tsareenty = Entries()[i];
TSmsSegmentationEntry& entry = static_cast<TSmsSegmentationEntry&>(tsareenty);
TStreamId streamid=entry.DataStreamId();
TSmsAddr smsaddr;
CSmsBuffer* buffer=CSmsBuffer::NewL();
CSmsMessage* smsmessage=CSmsMessage::NewL(iFs, CSmsPDU::ESmsDeliver,buffer);
CleanupStack::PushL(smsmessage);
//
// access the file store
//
InternalizeEntryL(streamid,smsaddr,*smsmessage, refStatusArray);
if (aSmsMessage.Scheme() == EControlParametersScheme)
{
TUint8 octet(0);
TInt ret;
ret = ((CSmsSMSCCtrlParameterOperations&)aSmsMessage.GetOperationsForIEL(CSmsInformationElement::ESmsIEISMSCControlParameters)).GetStatusReport(aSegmentSequenceNumber, octet);
if (ret == KErrNone)
{
if (octet & ESmsSMSCControlParametersMask)
{
refStatusArray.InsertL(aReference);
}
else
{
refStatusArray.InsertL(TSmsSegmentationStoreRefStatus(aReference, EStatusComplete));
}
}
}
else if(aSmsMessage.Scheme() == ETPSRRScheme)
{
TInt tpsrr;
tpsrr = ((CSmsTPSRROperations&)aSmsMessage.GetOperationsForNonIEL(ESmsTPSRRParameter)).GetStatusReport(aSegmentSequenceNumber);
if(tpsrr == TSmsFirstOctet::ESmsStatusReportNotRequested)
{
refStatusArray.InsertL(TSmsSegmentationStoreRefStatus(aReference, EStatusComplete));
}
else if(tpsrr == TSmsFirstOctet::ESmsStatusReportRequested)
{
refStatusArray.InsertL(aReference);
}
}
else
{
User::Leave(KErrArgument);
}
BeginTransactionLC();
ExternalizeEntryL(streamid,smsaddr,*smsmessage, refStatusArray);
PopulateEntry(entry,/*smsaddr,*/*smsmessage, refStatusArray);
ChangeEntryL(i,entry);
CommitTransactionL();
//
// AEH: moved here because if is done before calling ChangeEntryL
// it will pop and destroy the filestore which is also on
// the cleanup stack
//
CleanupStack::PopAndDestroy(2); // smsmessage, refStatus
return entry.Total()==entry.Count();
} // CSmsSegmentationStore::AddReferenceStatusPairL
TBool CSmsSegmentationStore::AddStatusReportL(TInt& aIndex,TBool& aComplete,const CSmsMessage& aStatusReport)
{
LOGSMSPROT1("CSmsSegmentationStore::AddStatusReportL");
__ASSERT_DEBUG(aStatusReport.Type()==CSmsPDU::ESmsStatusReport,SmspPanic(KSmspPanicNotStatusReport));
const CSmsStatusReport& statusreport=(CSmsStatusReport&) aStatusReport.SmsPDU();
const TInt reference=statusreport.MessageReference();
const TInt status=statusreport.Status();
const TInt isPerm = IsPermanentStatus(status);
const TSmsFirstOctet::TSmsStatusReportQualifier qualifier=statusreport.StatusReportQualifier();
TBool found=EFalse;
aComplete=EFalse;
LOGSMSPROT4("CSmsSegmentationStore::AddStatusReportL [ref=%d status=%d IsPerm=%d]", reference, status, isPerm);
if(!isPerm)
{
return EFalse;
}
RSmsSegmentationStoreRefStatusArray refStatusArray;
CleanupClosePushL(refStatusArray);
const TInt count1=Entries().Count();
TSmsAddr smsaddr;
CSmsBuffer* buffer=CSmsBuffer::NewL();
CSmsMessage* smsmessage=CSmsMessage::NewL(iFs, CSmsPDU::ESmsDeliver,buffer);
CleanupStack::PushL(smsmessage);
TGsmSmsTelNumber parsedaddress;
aStatusReport.ParsedToFromAddress(parsedaddress);
BeginTransactionLC();
aIndex = count1;
TInt telLen;
while (!found && aIndex--)
{
TSAREntry tsareenty = Entries()[aIndex];
TSmsSegmentationEntry& entry = static_cast<TSmsSegmentationEntry&>(tsareenty);
// Remove leading zeros of national numbers
TPtrC trimmedTelNumber(TrimLeadingZeros(entry.Description2()));
TPtrC trimmedParsedTelNumber(TrimLeadingZeros(parsedaddress.iTelNumber));
telLen=Min(trimmedTelNumber.Length(),trimmedParsedTelNumber.Length());
const CSmsPDU::TSmsPDUType type = entry.PduType();
const TInt startref = entry.Reference1();
const TInt stopref = entry.Reference2();
TBool sameTelNumbers = entry.Description2().Right(telLen) == parsedaddress.iTelNumber.Right(telLen);
if (sameTelNumbers)
{
LOGSMSPROT1("CSmsSegmentationStore::AddStatusReportL telNumber from submit report matches that from SMS message");
}
else
{
LOGSMSPROT1("CSmsSegmentationStore::AddStatusReportL telNumber from submit report does NOT match that from SMS message");
}
if (sameTelNumbers &&
(((qualifier==TSmsFirstOctet::ESmsStatusReportResultOfCommand) && (type==CSmsPDU::ESmsCommand)) ||
((qualifier==TSmsFirstOctet::ESmsStatusReportResultOfSubmit) && (type==CSmsPDU::ESmsSubmit))) &&
(((stopref>=startref) &&(reference>=startref) && (reference<=stopref))||((stopref<startref) &&((reference>=startref) || (reference<=stopref))))
)
{
InternalizeEntryL(entry.DataStreamId(),smsaddr,*smsmessage, refStatusArray);
TInt refStatusPos = refStatusArray.Find(reference); //assumes Find returns the first matching reference in the array
TInt numMessagePDUs=entry.Total();
if (refStatusPos != KErrNotFound)
{
const TInt refStatusArrayCount = refStatusArray.Count();
//Find an element in refStatusArray where Reference() == reference and Status() is not permanent
while (!found && refStatusPos < refStatusArrayCount && refStatusArray[refStatusPos].Reference() == reference)
{
//@note This loop assumes refStatusArray is sorted iReference
if (!IsPermanentStatus(refStatusArray[refStatusPos].Status())&&(refStatusArrayCount <= numMessagePDUs))
{
found = ETrue;
}
else
{
LOGSMSPROT4("CSmsSegmentationStore::AddStatusReportL WARNING: Status already perm [status=%d refStatusPos=%d count=%d]", refStatusArray[refStatusPos].Status(), refStatusPos, refStatusArrayCount);
refStatusPos++;
}
}
if (found)
{
LOGSMSPROT2("CSmsSegmentationStore::AddStatusReportL Found [refStatusPos=%d]", refStatusPos);
refStatusArray[refStatusPos].SetStatus(status);
TStreamId streamid=entry.DataStreamId();
ExternalizeEntryL(streamid,smsaddr,*smsmessage, refStatusArray);
PopulateEntry(entry,*smsmessage, refStatusArray);
ChangeEntryL(aIndex,entry);
aComplete=StatusArrayComplete(refStatusArray, entry);
LOGSMSPROT2("CSmsSegmentationStore::AddStatusReportL StatusArrayComplete %d", aComplete);
}
}
}
}
if (found && (smsmessage->Type()==CSmsPDU::ESmsCommand)) // look for original submit
{
TTime time=smsmessage->Time();
found=EFalse;
RSmsSegmentationStoreRefStatusArray refStatusArray2;
CleanupClosePushL(refStatusArray2);
refStatusArray2.CopyL(refStatusArray);
refStatusArray2.ResetAllStatus();
aComplete=EFalse;
TInt telLen;
for (aIndex=0; aIndex<count1; aIndex++)
{
TSAREntry tsareenty = Entries()[aIndex];
TSmsSegmentationEntry& entry = static_cast<TSmsSegmentationEntry&>(tsareenty);
telLen=Min(entry.Description2().Length(),parsedaddress.iTelNumber.Length());
const CSmsPDU::TSmsPDUType type = entry.PduType();
if ((type==CSmsPDU::ESmsSubmit) &&
entry.IsComplete() &&
(entry.Time()==time) &&
(entry.Description2().Right(telLen)==parsedaddress.iTelNumber.Right(telLen)))
{
/*
TODO ahe - this should take out of the for loop
only set/delete flags in the for loop and let the methods:
InternalizeXXX
ExternalizeXXX
PopulateEntry
ChangeEntry
... all ... other big CSarStore methods
have only to run once -> internal loop in this function through
the array of flags
*/
found=ETrue;
InternalizeEntryL(entry.DataStreamId(),smsaddr,*smsmessage, refStatusArray2);
const TInt count2 = refStatusArray.Count();
__ASSERT_DEBUG(count2 == refStatusArray2.Count(),SmspPanic(KSmspPanicBadReferenceArray));
for (TInt i=0; i<count2; i++)
{
TSmsSegmentationStoreRefStatus& refStatus2 = refStatusArray2[i];
if (!IsPermanentStatus(refStatus2.Status()))
{
refStatus2.SetStatus(refStatusArray[i].Status());
}
}
TStreamId streamid=entry.DataStreamId();
ExternalizeEntryL(streamid,smsaddr,*smsmessage, refStatusArray2);
PopulateEntry(entry,/*smsaddr,*/*smsmessage, refStatusArray2);
ChangeEntryL(aIndex,entry);
aComplete=StatusArrayComplete(refStatusArray2, entry);
LOGSMSPROT3("CSmsSegmentationStore::StatusArrayComplete [aStatus=%d, ret=%d]", status, aComplete);
break;
}
}
CleanupStack::PopAndDestroy(&refStatusArray2);
}
CommitTransactionL();
CleanupStack::PopAndDestroy(2); // smsmessage, refStatusArray
LOGSMSPROT2("CSmsSegmentationStore::AddStatusReportL Exit [found=%d]", found);
return found;
} // CSmsSegmentationStore::AddStatusReportL
void CSmsSegmentationStore::GetMessageL(TInt aIndex,TSmsAddr& aSmsAddr,CSmsMessage& aSmsMessage, RSmsSegmentationStoreRefStatusArray& aRefStatusArray)
{
LOGSMSPROT2("CSmsSegmentationStore::GetMessageL [aIndex=%d]", aIndex);
InternalizeEntryL(Entries()[aIndex].DataStreamId(),aSmsAddr,aSmsMessage, aRefStatusArray);
} // CSmsSegmentationStore::GetMessageL
/**
* internalize the concat refs from the permanent file store to internal memory
*
* @note You have to call CSARStore::OpenFileLC() before calling this function
* and CSARStore::CloseFile() after.
*/
void CSmsSegmentationStore::InternalizeConcatenationReferencesL(const TStreamId& aStreamId,TInt& aReference8bit,TInt& aReference16bit)
{
LOGSMSPROT1("CSmsSegmentationStore::InternalizeConcatenationReferencesL Start");
RStoreReadStream readstream;
readstream.OpenLC(FileStore(),aStreamId);
aReference8bit=readstream.ReadInt32L();
aReference16bit=readstream.ReadInt32L();
CleanupStack::PopAndDestroy();
LOGSMSPROT1("CSmsSegmentationStore::InternalizeConcatenationReferencesL End");
} // CSmsSegmentationStore::InternalizeConcatenationReferencesL
/**
* externalize the concat refs from the permanent file store to internal memory
*
* @note You have to call CSARStore::OpenFileLC() before calling this function
* and CSARStore::CloseFile() after.
*/
void CSmsSegmentationStore::ExternalizeConcatenationReferencesL(TStreamId& aStreamId,TInt aReference8bit,TInt aReference16bit)
{
LOGSMSPROT1("CSmsSegmentationStore::ExternalizeConcatenationReferencesL Start");
RStoreWriteStream writestream;
if (aStreamId==KNullStreamId)
aStreamId=writestream.CreateLC(FileStore());
else
writestream.ReplaceLC(FileStore(),aStreamId);
writestream.WriteInt32L(aReference8bit);
writestream.WriteInt32L(aReference16bit);
writestream.CommitL();
CleanupStack::PopAndDestroy();
LOGSMSPROT1("CSmsSegmentationStore::ExternalizeConcatenationReferencesL End");
} // CSmsSegmentationStore::ExternalizeConcatenationReferencesL
/**
* internalize all the entries from the permanent file store to internal memory
*
* @note You have to call CSARStore::OpenFileLC() before calling this function
* and CSARStore::CloseFile() after.
*/
void CSmsSegmentationStore::InternalizeEntryL(const TStreamId& aStreamId,TSmsAddr& aSmsAddr,CSmsMessage& aSmsMessage, RSmsSegmentationStoreRefStatusArray& aRefStatusArray)
{
LOGSMSPROT1("CSmsSegmentationStore::InternalizeEntryL Start");
aRefStatusArray.Reset();
RStoreReadStream readstream;
readstream.OpenLC(FileStore(),aStreamId);
readstream >> aSmsAddr;
readstream >> aSmsMessage;
readstream >> aRefStatusArray;
CleanupStack::PopAndDestroy(&readstream);
LOGSMSPROT2("CSmsSegmentationStore::InternalizeEntryL End [count=%d]", aRefStatusArray.Count());
} // CSmsSegmentationStore::InternalizeEntryL
/**
* externalizes all the entries from the internal memory to the permanent file store
*/
void CSmsSegmentationStore::ExternalizeEntryL(TStreamId& aStreamId,const TSmsAddr& aSmsAddr,const CSmsMessage& aSmsMessage, const RSmsSegmentationStoreRefStatusArray& aRefStatusArray)
{
LOGSMSPROT1("CSmsSegmentationStore::ExternalizeEntryL Start");
RStoreWriteStream writestream;
if (aStreamId==KNullStreamId)
aStreamId=writestream.CreateLC(FileStore());
else
writestream.ReplaceLC(FileStore(),aStreamId);
writestream << aSmsAddr;
writestream << aSmsMessage;
writestream << aRefStatusArray;
writestream.CommitL();
CleanupStack::PopAndDestroy(&writestream);
LOGSMSPROT2("CSmsSegmentationStore::ExternalizeEntryL End [count=%d]", aRefStatusArray.Count());
} // CSmsSegmentationStore::ExternalizeEntryL
/**
* Populates an SMS message into SAR store entry
*
* @pre aSmsMessage.EncodeMessagePdusL() has been called
*
* @param aEntry Entry to be populated to
* @param aSmsMessage SMS message to be populated from
* @param aReferenceArray Array containing references
* @param aStatusArray Array containing status
*/
void CSmsSegmentationStore::PopulateEntry(TSmsSegmentationEntry& aEntry,
const CSmsMessage& aSmsMessage,
const RSmsSegmentationStoreRefStatusArray& aRefStatusArray)
{
LOGSMSPROT1("CSmsSegmentationStore::PopulateEntry");
TBool statusreportrequest=EFalse;
if (aSmsMessage.Type()==CSmsPDU::ESmsSubmit)
{
aEntry.SetReference(0);
aEntry.SetTotal(1);
CSmsSubmit& submit=(CSmsSubmit&) aSmsMessage.SmsPDU();
aEntry.SetValidityPeriod(submit.ValidityPeriod().Int());
if (aSmsMessage.Scheme() == EDefaultScheme)
{
statusreportrequest=((CSmsSubmit&) aSmsMessage.SmsPDU()).StatusReportRequest();
}
else
{
statusreportrequest = ETrue;
}
}
else
{
statusreportrequest=((CSmsCommand&) aSmsMessage.SmsPDU()).StatusReportRequest();
}
if (aSmsMessage.TextPresent())
{
if (aSmsMessage.SmsPDU().TextConcatenated())
{
aEntry.SetReference(aSmsMessage.SmsPDU().ConcatenatedMessageReference());
//
// aSmsMessage.EncodeMessagePdusL() must have been called before this point,
// otherwise aSmsMessage.SmsPDU().NumConcatenatedMessagePDUs() will return 1.
//
aEntry.SetTotal(aSmsMessage.SmsPDU().NumConcatenatedMessagePDUs());
}
}
aEntry.SetLogServerId(aSmsMessage.LogServerId());
// Strip out spaces etc from address
TGsmSmsTelNumber parsedaddress;
aSmsMessage.ParsedToFromAddress(parsedaddress);
aEntry.SetDescription2(parsedaddress.iTelNumber);
aEntry.SetTime(aSmsMessage.Time());
const TInt count= aRefStatusArray.Count();
__ASSERT_DEBUG((count>=0) && (count<=aEntry.Total()),SmspPanic(KSmspPanicBadReferenceArray));
aEntry.SetCount(count);
TInt reference1=0xFF;
TInt reference2=0x00;
TInt startref=reference1;
TInt stopref=reference2;
if(count>0 && statusreportrequest)
{
startref=aRefStatusArray[0].Reference();
stopref=aRefStatusArray[count-1].Reference();
}
TInt delivered=0;
TInt failed=0;
for (TInt i=0; i<count; i++)
{
const TSmsSegmentationStoreRefStatus& refStatus = aRefStatusArray[i];
if (refStatus.Status() == TSmsStatus::ESmsShortMessageReceivedBySME)
delivered++;
else if (IsPermanentStatus(refStatus.Status()))
failed++;
}
//
// AEH: Defect fix for EDNPAHN-4WADW3 'Unreliable logging'
//
// a little hack here to store information about whether
// we need Status Report or not, in the TSAREntry. This
// is because we want to retrieve it later in PurgeL.
// An extra bit is added iData4, LSB of byte 3. See gsmustor.h
// for more documentation.
//
aEntry.SetDeliveredAndFailed(delivered, failed);
TBool have_sr = EFalse;
if (aSmsMessage.Scheme() == EDefaultScheme)
{
have_sr=((CSmsSubmit&) aSmsMessage.SmsPDU()).StatusReportRequest();
}
else
{
have_sr = ETrue;
}
aEntry.SetPduTypeAndRefs(have_sr, aSmsMessage.Type(), startref, stopref);
} // CSmsSegmentationStore::PopulateEntry
/**
* Returns ETrue if the status array is complete
*
* @param aStatusArray Array containing status
* @param aEntry SAR Entry
*/
TBool CSmsSegmentationStore::StatusArrayComplete(const RSmsSegmentationStoreRefStatusArray& aRefStatusArray, TSAREntry& aEntry)
{
TInt permanent=0;
const TInt count= aRefStatusArray.Count();
for (TInt i=0; i<count; i++)
{
const TBool ret = IsPermanentStatus(aRefStatusArray[i].Status());
LOGSMSPROT4("CSmsSegmentationStore::IsPermanentStatus [Status: %d, RetVal: %d, count=%d]", aRefStatusArray[i].Status(), ret, count);
if (ret)
permanent++;
}
return (permanent==count) && (permanent==aEntry.Total() );
} // CSmsSegmentationStore::StatusArrayComplete
/**
* C'tor
*/
CSmsSegmentationStore::CSmsSegmentationStore(RFs& aFs)
:CSARStore(aFs)
{
LOGSMSPROT1("CSmsSegmentationStore::CSmsSegmentationStore()");
} // CSmsSegmentationStore::CSmsSegmentationStore
TInt CSmsSegmentationStore::TSmsSegmentationStoreRefStatus::Compare(const TSmsSegmentationStoreRefStatus& aLeft, const TSmsSegmentationStoreRefStatus& aRight)
{
LOGSMSPROT1("CSmsSegmentationStore::TSmsSegmentationStoreRefStatus::Compare()");
return aLeft.iReference - aRight.iReference;
} // CSmsSegmentationStore::TSmsSegmentationStoreRefStatus::Compare
void CSmsSegmentationStore::TSmsSegmentationStoreRefStatus::InternalizeL(RReadStream& aStream)
{
LOGSMSPROT1("CSmsSegmentationStore::TSmsSegmentationStoreRefStatus::InternalizeL()");
iReference = aStream.ReadInt32L();
iStatus = aStream.ReadInt32L();
} // CSmsSegmentationStore::TSmsSegmentationStoreRefStatus::InternalizeL
void CSmsSegmentationStore::TSmsSegmentationStoreRefStatus::ExternalizeL(RWriteStream& aStream) const
{
LOGSMSPROT1("CSmsSegmentationStore::TSmsSegmentationStoreRefStatus::ExternalizeL()");
aStream.WriteInt32L(iReference);
aStream.WriteInt32L(iStatus);
} // CSmsSegmentationStore::TSmsSegmentationStoreRefStatus::ExternalizeL
void CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::InsertL(const TSmsSegmentationStoreRefStatus& aRefStatus)
{
LOGSMSPROT1("CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::InsertL()");
TLinearOrder<TSmsSegmentationStoreRefStatus> order(TSmsSegmentationStoreRefStatus::Compare);
User::LeaveIfError(InsertInOrderAllowRepeats(aRefStatus, order));
} // CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::InsertL
TInt CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::Find(const TSmsSegmentationStoreRefStatus& aRefStatus) const
{
LOGSMSPROT1("CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::Find()");
TLinearOrder<TSmsSegmentationStoreRefStatus> order(TSmsSegmentationStoreRefStatus::Compare);
TInt index = FindInOrder(aRefStatus, order);
if (index != KErrNotFound)
{
//The function is to return the first occurence. However FindInOrder()
//uses a binary search algorithm and does not guarantee to return the 1st item if there are duplicate items.
//Therefore we manually check for duplicates to the left of the found item.
while (index > 0 && (operator[](index-1).Reference() == aRefStatus.Reference()))
{
--index;
}
}
return index;
} // CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::Find
void CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::CopyL(const RSmsSegmentationStoreRefStatusArray& aOther)
{
LOGSMSPROT1("CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::CopyL()");
Reset();
TInt count = aOther.Count();
while (count--)
{
InsertL(aOther[count]);
}
} // CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::CopyL
void CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::ResetAllStatus(TInt aStatus)
{
LOGSMSPROT1("CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::ResetAllStatus()");
TInt count = Count();
while (count--)
{
(*this)[count].SetStatus(aStatus);
}
} // CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::ResetAllStatus
void CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::InternalizeL(RReadStream& aStream)
{
LOGSMSPROT1("CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::InternalizeL()");
TInt count = aStream.ReadInt32L();
while (count--)
{
TSmsSegmentationStoreRefStatus refStatus;
aStream >> refStatus;
InsertL(refStatus); //maintain order
}
} // CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::InternalizeL
void CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::ExternalizeL(RWriteStream& aStream) const
{
LOGSMSPROT1("CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::ExternalizeL()");
const TInt count = Count();
aStream.WriteInt32L(count);
for (TInt i = 0; i < count; i++)
{
aStream << (*this)[i];
}
} // CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::ExternalizeL
TBool CSmsSegmentationStore::HasEntryWithLogIdL(TLogId aLogID,TInt& aRefNo,TInt& aSent)
{
LOGSMSPROT1("CSmsSegmentationStore::HasEntryWithLogIdL()");
TInt count=Entries().Count();
TBool found=EFalse;
if(aLogID != KLogNullId)
{
TInt total;
TInt sent;
BeginTransactionLC();
for (TInt i=count-1; i>=0; --i)
{
if (aLogID==Entries()[i].LogServerId())
{
const TSAREntry& entry=Entries()[i];
total=entry.Total();
sent=entry.Count();
if( sent < total)
{
aSent=sent;
aRefNo=entry.Reference();
found=ETrue;
}
else
{
DeleteEntryL(i);
LOGSMSPROT3("CSmsSegmentationStore::HasEntryWithLogIdL [Entry: %d LogId %d - deleted]", i, aLogID );
}
break;
}
}
CommitTransactionL();
}
return found;
} // CSmsSegmentationStore::HasEntryWithLogIdL
/**
* Open the sms segmentation store.
*/
void CSmsSegmentationStore::OpenStoreL()
{
LOGSMSPROT1("CSmsSegmentationStore::OpenStoreL()");
this->OpenL(iFullPathBuf,KSegmentationStoreUid);
} // CSmsSegmentationStore::OpenStoreL