// Copyright (c) 1997-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 "wappstor.h"
#include "ws_main.h"
#include "smsstackutils.h"
_LIT(KStoreName,"wapreast.dat");
const TInt KWapReassemblyStoreUidValue=0x100008CB;
const TUid KWapReassemblyStoreUid={KWapReassemblyStoreUidValue}; // Used for second uid of SAR stores
CWapReassemblyStore* CWapReassemblyStore::NewL(RFs& aFs)
{
LOGWAPPROT1("CWapReassemblyStore::NewL()");
CWapReassemblyStore* reassembly=new (ELeave)CWapReassemblyStore(aFs);
CleanupStack::PushL(reassembly);
reassembly->ConstructL();
CleanupStack::Pop(reassembly);
return reassembly;
} // CWapReassemblyStore::NewL
CWapReassemblyStore::~CWapReassemblyStore()
{
this->Close();
}
TBool CWapReassemblyStore::AddMessageL( TInt& aIndex, const CWapDatagram& aDatagram)
{
LOGWAPPROT1("CWapReassemblyStore::AddMessageL()");
CArrayPtrFlat<CWapDatagram::TSegmentData>* segmentArray = new
(ELeave) CArrayPtrFlat<CWapDatagram::TSegmentData> (8);
CleanupStack::PushL(segmentArray);
CleanupResetAndDestroyPushL(*segmentArray);
TBool isComplete = aDatagram.IsComplete();
// count of incomplete WAP short messages
TInt Count = Entries().Count();
if (!isComplete)
{
TWapReassemblyEntry Entry;
TBool isFound = EFalse;
// go through all entries in the reassembly store
// and find the short message entry,
// which matches with the given entry
for(aIndex=0;aIndex<Count; aIndex++)
{
TInt ToPort = 0;
TInt FromPort = 0;
aDatagram.Ports(FromPort,ToPort);
Entry = (TWapReassemblyEntry&)Entries()[aIndex];
isFound = ((Entry.Reference() ==
aDatagram.ConcatenatedMessageReference())
&& (Entry.Total() ==
aDatagram.NumConcatenatedMessages())
&& (Entry.ToPort() == ToPort)
&& (Entry.Description1() ==
aDatagram.FromAddress()));
if (isFound)
break;
}
if (isFound)
{
isFound = EFalse;
// new short message fragment received for an existing
// incomplete WAP datagram
TStreamId StreamdId = Entry.DataStreamId();
CWapDatagram* tempDatagram = CWapDatagram::NewL(KNullDesC8);
CleanupStack::PushL(tempDatagram);
// defect fix for EDNJJUN-4WYJGP
// Unable to send sms cause sms*.dat is corrupted
// TODO - has to be back ported to higher versions
TRAPD(ret, InternalizeEntryL(StreamdId,*tempDatagram,*segmentArray));
if(ret == KErrCorrupt)
{
Close();
User::LeaveIfError(iFs.Delete(iFullPathBuf));
DoOpenL(); //create a new file
}
else
User::LeaveIfError(ret);
// For the first: discard duplicates
// It takes place by comparing indexes of TSegmentDatas
CWapDatagram::TSegmentData *segmentData = new (ELeave)CWapDatagram::TSegmentData;
CleanupStack::PushL(segmentData);
aDatagram.SegmentData(*segmentData);
if(aDatagram.NumConcatenatedMessages() < segmentData->iSegmentNumber)
{
isFound = ETrue; // out of range discard
CleanupStack::PopAndDestroy(segmentData);
}
else
{
Count=segmentArray->Count();
for (TInt i=0; i<Count; i++)
{
CWapDatagram::TSegmentData* thisSegmentData =
segmentArray->At(i);
if (thisSegmentData->iSegmentNumber
== segmentData->iSegmentNumber)
{
// duplicate found. It is not saved.
isFound = ETrue;
CleanupStack::PopAndDestroy(segmentData);
break;
}
}
}
if (!isFound)
{
TInt j=0;
for (; (j<segmentArray->Count()) && (segmentData->iSegmentNumber>(*segmentArray)[j]->iSegmentNumber); j++)
{
}
segmentArray->InsertL(j,segmentData);
CleanupStack::Pop(segmentData);
if (segmentArray->Count() ==
aDatagram.NumConcatenatedMessages())
// all fragments of a datagram are available
isComplete = ETrue;
BeginTransactionLC();
ExternalizeEntryL(StreamdId,*tempDatagram,*segmentArray);
PopulateEntry(Entry,*tempDatagram,segmentArray->Count());
ChangeEntryL(aIndex,Entry);
CommitTransactionL();
}
CleanupStack::PopAndDestroy(tempDatagram);
}
// else - a duplicate was found. Ignored.
else
{
// a first short message fragment received for a
// non-existing WAP datagram
CWapDatagram::TSegmentData *segmentData = new (ELeave)CWapDatagram::TSegmentData;
CleanupStack::PushL(segmentData);
aDatagram.SegmentData(*segmentData);
if(aDatagram.NumConcatenatedMessages() < segmentData->iSegmentNumber)
{
CleanupStack::PopAndDestroy(segmentData);
isComplete=EFalse;
}
else
{
segmentArray->AppendL(segmentData);
CleanupStack::Pop(segmentData);
aIndex = Count;
CreateEntryL(aDatagram,*segmentArray);
}
}
}
else // the datagram is complete
{
CWapDatagram::TSegmentData *segmentData = new (ELeave)CWapDatagram::TSegmentData;
CleanupStack::PushL(segmentData);
aDatagram.SegmentData(*segmentData);
if(aDatagram.NumConcatenatedMessages() < segmentData->iSegmentNumber)
{
CleanupStack::PopAndDestroy(segmentData);
isComplete=EFalse;
}
else
{
segmentArray->AppendL(segmentData);
CleanupStack::Pop(segmentData);
aIndex = Count;
CreateEntryL(aDatagram,*segmentArray);
}
}
CleanupStack::PopAndDestroy(2, segmentArray); // segmentArray elements (Reset and Destroy), segmentArray
return isComplete;
} // CWapReassemblyStore::AddMessageL
void CWapReassemblyStore::GetDatagramL( TInt aIndex,
CWapDatagram& aDatagram)
{
LOGWAPPROT1("CWapReassemblyStore::GetDatagramL()");
CArrayPtrFlat<CWapDatagram::TSegmentData>* segmentArray = new
(ELeave) CArrayPtrFlat<CWapDatagram::TSegmentData> (8);
// here we need to push 'segmentArray' pointer to the cleanup stack, since it's a heap allocation (pointer must be deleted)
// CleanupResetAndDestroyPushL() just trigers ResetAndDestroy() to be called on CleanupStack::PopAndDestroy()
CleanupStack::PushL(segmentArray);
CleanupResetAndDestroyPushL(*segmentArray);
// defect fix for EDNJJUN-4WYJGP
// Unable to send sms cause sms*.dat is corrupted
// TODO - has to be back ported to higher versions
TRAPD(ret, InternalizeEntryL(Entries()[aIndex].DataStreamId(), aDatagram,*segmentArray));
if(ret == KErrCorrupt)
{
Close(); //because the file is in use
User::LeaveIfError(iFs.Delete(iFullPathBuf));
DoOpenL(); //create a new file
}
else
User::LeaveIfError(ret);
if(aDatagram.Alphabet() == TSmsDataCodingScheme::ESmsAlphabet7Bit)
{
aDatagram.DecodeConcatenatedMessagesL(*segmentArray);
}
CleanupStack::PopAndDestroy(2, segmentArray); // segmentArray elements (Reset and Destroy), segmentArray
} // CWapReassemblyStore::GetDatagramL
TBool CWapReassemblyStore::FindAndDeleteDatagramL( CWapDatagram& aDatagram)
{
LOGWAPPROT1("CWapReassemblyStore::FindAndDeleteDatagramL()");
TInt index;
TBool isFound = EFalse;
TWapReassemblyEntry entry;
TInt toPort = 0;
TInt fromPort = 0;
aDatagram.Ports(fromPort,toPort);
TInt Count = Entries().Count();
for(index=0;index<Count; index++)
{
entry = (TWapReassemblyEntry&)Entries()[index];
isFound = ((entry.Reference() ==
aDatagram.ConcatenatedMessageReference())
&& (entry.ToPort() == toPort)
&&(entry.Total() ==
aDatagram.NumConcatenatedMessages()));
if (isFound)
{
BeginTransactionLC();
DeleteEntryL(index);
CommitTransactionL();
return isFound;
}
}
return isFound;
} // CWapReassemblyStore::FindAndDeleteDatagramL
void CWapReassemblyStore::ConstructL()
{
LOGWAPPROT1("CWapReassemblyStore::ConstructL()");
//get full path of reassembly store
PrivatePath(iFullPathBuf);
//append store name
iFullPathBuf.Append(KStoreName);
OpenStoreL();
} // CWapReassemblyStore::ConstructL
/**
* internalize all the entries from the permanent file store to internal memory
*
* @note You have to call CSARStore::OpenFileLC() before calling this function
* @param aStreamId, unique id associated with the stream
* @param aDatagram, the datagram which will be internalized
* @param aSegmentArray, the array of segments for the datagram
*/
void CWapReassemblyStore::InternalizeEntryL(
TStreamId aStreamId,
CWapDatagram& aDatagram,
CArrayPtr<CWapDatagram::TSegmentData>& aSegmentArray)
{
LOGWAPPROT1("CWapReassemblyStore::InternalizeEntryL Start");
BeginTransactionLC();
RStoreReadStream ReadStream;
TInt32 Count;
ReadStream.OpenLC(FileStore(),aStreamId);
ReadStream >> aDatagram;
if(aDatagram.Alphabet() == TSmsDataCodingScheme::ESmsAlphabet8Bit)
{
aDatagram.InternalizeBufferL(ReadStream);
}
else
{
Count=ReadStream.ReadInt32L();
aSegmentArray.Reset();
for (TInt i=0; i<Count; i++)
{
CWapDatagram::TSegmentData* Segment = new (ELeave) CWapDatagram::TSegmentData;
CleanupStack::PushL(Segment);
aSegmentArray.AppendL(Segment);
CleanupStack::Pop();
Segment->iSegmentNumber = ReadStream.ReadInt32L();
ReadStream >> Segment->iData;
}
}
// Closes the ReadStream
CleanupStack::PopAndDestroy();
CommitTransactionL();
LOGWAPPROT1("CWapReassemblyStore::InternalizeEntryL End");
} // CWapReassemblyStore::InternalizeEntryL
/**
* externalizes all the entries from the internal memory to the permanent file store
*
* @note You have to call CSARStore::OpenFileLC() before calling this function
* @param aStreamId, unique id associated with the stream
* @param aDatagram, the datagram which should be externalized
* @param aSegmentArray, the array of segments for the datagram
*/
void CWapReassemblyStore::ExternalizeEntryL(
TStreamId& aStreamId,
const CWapDatagram& aDatagram,
const CArrayPtr<CWapDatagram::TSegmentData>& aSegmentArray)
{
LOGWAPPROT1("CWapReassemblyStore::ExternalizeEntryL Start");
TInt32 Count = aSegmentArray.Count();
RStoreWriteStream WriteStream;
if (aStreamId==KNullStreamId)
aStreamId=WriteStream.CreateLC(FileStore());
else
WriteStream.ReplaceLC(FileStore(),aStreamId);
WriteStream<<aDatagram;
if(aDatagram.Alphabet() == TSmsDataCodingScheme::ESmsAlphabet8Bit)
{
aDatagram.ExternalizeBufferL(WriteStream);
}
else
{
WriteStream.WriteInt32L(Count);
for(TInt i=0; i<Count; i++)
{
WriteStream.WriteInt32L(aSegmentArray[i]->iSegmentNumber);
WriteStream<<aSegmentArray[i]->iData;
}
}
// Closes the ReadStream
WriteStream.CommitL();
CleanupStack::PopAndDestroy();
} // CWapReassemblyStore::ExternalizeEntryL
void CWapReassemblyStore::PopulateEntry(TWapReassemblyEntry& aEntry,
const CWapDatagram& aDatagram,
TInt aNumDatagrams)
{
LOGWAPPROT1("CWapReassemblyStore::PopulateEntry()");
TInt ToPort = 0;
TInt FromPort = 0;
aDatagram.Ports(FromPort,ToPort);
// complete or not complete
if (!aDatagram.IsComplete())
{
aEntry.SetReference(aDatagram.ConcatenatedMessageReference());
aEntry.SetTotal(aDatagram.NumConcatenatedMessages());
aEntry.SetCount(aNumDatagrams);
}
else
{
//Wap Datagram might contain reference number which will be
//needed at the time of deleting the datagram from permanent store file
//Refer To Defect Fix: PDEF114607.
aEntry.SetReference(aDatagram.ConcatenatedMessageReference());
aEntry.SetTotal(1);
aEntry.SetCount(1);
}
aEntry.SetToPort(ToPort);
aEntry.SetDescription1(aDatagram.FromAddress());
aEntry.SetTime(aDatagram.Time());
} // CWapReassemblyStore::PopulateEntry
void CWapReassemblyStore::CreateEntryL(const CWapDatagram& aDatagram,
const CArrayPtr<CWapDatagram::TSegmentData>& aSegmentArray)
{
LOGWAPPROT1("CWapReassemblyStore::CreateEntryL");
TWapReassemblyEntry Entry;
TStreamId WriteStream = KNullStreamId;
BeginTransactionLC();
ExternalizeEntryL(WriteStream,aDatagram,aSegmentArray);
Entry.SetDataStreamId(WriteStream);
PopulateEntry(Entry,aDatagram,aDatagram.NumConcatenatedMessages());
AddEntryL(Entry);
CommitTransactionL();
} // CWapReassemblyStore::CreateEntryL
CWapReassemblyStore::CWapReassemblyStore(RFs& aFs)
:CSARStore(aFs)
{
} // CWapReassemblyStore::CWapReassemblyStore
/**
* Open the wap reassembly store.
* Use RFs::PrivatePath to generate private path.
*/
void CWapReassemblyStore::OpenStoreL()
{
LOGWAPPROT1("CWapReassemblyStore::OpenStoreL()");
OpenL(iFullPathBuf,KWapReassemblyStoreUid);
} // CWapReassemblyStore::OpenStoreL
// EOF - WAPPSTOR.CPP