--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/phonebookengines/VirtualPhonebook/VPbkSimStoreImpl/src/CVPbkETelCntConverter.cpp Wed Sep 01 12:29:52 2010 +0100
@@ -0,0 +1,619 @@
+/*
+* Copyright (c) 2002-2007 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: A class that can convert sim contacts to etel contacts and vice
+* versa
+*
+*/
+
+
+
+// INCLUDE FILES
+#include "CVPbkETelCntConverter.h"
+
+// From Virtual Phonebook
+#include "VPbkSimStoreImplError.h"
+#include <VPbkSimCntFieldTypes.hrh>
+#include <CVPbkSimCntField.h>
+#include <CVPbkSimContact.h>
+#include <VPbkSimStoreCommon.h>
+#include <CVPbkSimContactBuf.h>
+#include <VPbkDebug.h>
+
+// System includes
+#include <mpbutil.h> // CPhoneBookBuffer
+
+namespace {
+// CONSTANTS
+// An amount of space to add to estimate of the size of the field
+// due to ETel padding bytes.
+const TInt KExtraFieldDataSpace = 3;
+// A buf size for the test buffer used to test CPhoneBookBuffer
+const TInt KTestBufSize = 20;
+}
+// ============================= LOCAL FUNCTIONS ===============================
+
+namespace {
+
+// -----------------------------------------------------------------------------
+// FieldConversion
+// Converts native sim field type to ETel field type
+// -----------------------------------------------------------------------------
+//
+TUint8 FieldConversion( TVPbkSimCntFieldType aType )
+ {
+ TUint8 result = 0;
+ switch ( aType )
+ {
+ case EVPbkSimName:
+ {
+ result = RMobilePhoneBookStore::ETagPBText;
+ break;
+ }
+ case EVPbkSimGsmNumber: // FALLTHROUGH
+ case EVPbkSimAdditionalNumber1: // FALLTHROUGH
+ case EVPbkSimAdditionalNumber2: // FALLTHROUGH
+ case EVPbkSimAdditionalNumber3: // FALLTHROUGH
+ case EVPbkSimAdditionalNumberLast: // same as EVPbkSimAdditionalNumber
+ {
+ result = RMobilePhoneBookStore::ETagPBNumber;
+ break;
+ }
+ case EVPbkSimNickName: // FALLTHROUGH
+ case EVPbkSimReading:
+ {
+ result = RMobilePhoneBookStore::ETagPBSecondName;
+ break;
+ }
+ case EVPbkSimEMailAddress:
+ {
+ result = RMobilePhoneBookStore::ETagPBEmailAddress;
+ break;
+ }
+ default:
+ {
+ // Do nothing
+ break;
+ }
+ }
+ return result;
+ }
+
+// -----------------------------------------------------------------------------
+// FieldConversion
+// Converts ETel field type to native field type
+// -----------------------------------------------------------------------------
+//
+TVPbkSimCntFieldType FieldConversion( TUint8 aType )
+ {
+ TVPbkSimCntFieldType result = EVPbkSimUnknownType;
+ switch ( aType )
+ {
+ case RMobilePhoneBookStore::ETagPBText:
+ {
+ result = EVPbkSimName;
+ break;
+ }
+ case RMobilePhoneBookStore::ETagPBNumber:
+ {
+ result = EVPbkSimGsmNumber;
+ break;
+ }
+ case RMobilePhoneBookStore::ETagPBSecondName:
+ {
+ result = EVPbkSimNickName;
+ break;
+ }
+ case RMobilePhoneBookStore::ETagPBEmailAddress:
+ {
+ result = EVPbkSimEMailAddress;
+ break;
+ }
+ default:
+ {
+ // Do nothing
+ break;
+ }
+ }
+ return result;
+ }
+
+// -----------------------------------------------------------------------------
+// GetFieldData
+// Gets the first field data of given ETel field type
+// -----------------------------------------------------------------------------
+//
+template<class T>
+void GetFieldData( CPhoneBookBuffer& aETelBuffer, T& aData, TUint8 aFieldType )
+ {
+ TUint8 fieldTag;
+ CPhoneBookBuffer::TPhBkTagType dataType;
+ while ( aETelBuffer.GetTagAndType( fieldTag, dataType) == KErrNone )
+ {
+ if ( fieldTag == aFieldType )
+ {
+ aETelBuffer.GetValue( aData );
+ return;
+ }
+ else
+ {
+ aETelBuffer.SkipValue( dataType );
+ }
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// EstimateDataSize
+// Estimates the size that the data will take in ETel buffer
+// -----------------------------------------------------------------------------
+//
+inline TInt EstimateDataSize( const TArray<CVPbkSimCntField*>& aFieldArray )
+ {
+ // Initialize to zero size
+ TInt size = 0;
+ TInt count = aFieldArray.Count();
+ for ( TInt i = 0; i < count; ++i )
+ {
+ // Add one byte for the field tag, then two bytes for data size
+ // information, so 3 bytes will be added
+ size += KExtraFieldDataSpace;
+
+ // Add the size of the data
+ size += aFieldArray[i]->Data().Size();
+
+ // ETel buffer uses word aligned data -> 0-3 padding bytes
+ size += KExtraFieldDataSpace;
+ }
+ return size;
+ }
+
+// -----------------------------------------------------------------------------
+// Adds a new data field to ETel contact
+// -----------------------------------------------------------------------------
+//
+inline TInt AddNewETelField( CPhoneBookBuffer& aETelBuffer,
+ CVPbkSimCntField& aField )
+ {
+ TUint8 etelType = FieldConversion( aField.Type() );
+ __ASSERT_DEBUG( etelType != 0, VPbkSimStoreImpl::Panic(
+ VPbkSimStoreImpl::EInvalidVPbkToETelTypeConversion ) );
+ const TDesC& data = aField.Data();
+ if ( data.Length() > 0 )
+ {
+ if( aField.Type() == EVPbkSimAdditionalNumber1
+ || aField.Type() == EVPbkSimAdditionalNumber2
+ || aField.Type() == EVPbkSimAdditionalNumber3
+ || aField.Type()== EVPbkSimAdditionalNumberLast ) // all these four types are all additional field types.
+ {
+ // Additional number needs own tag that must be added before data
+ aETelBuffer.AddNewNumberTag();
+ }
+ return aETelBuffer.PutTagAndValue( etelType, data );
+ }
+ return KErrNotFound;
+ }
+
+} // unnamed
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CVPbkETelCntConverter::CVPbkETelCntConverter
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CVPbkETelCntConverter::CVPbkETelCntConverter()
+ {
+ }
+
+// -----------------------------------------------------------------------------
+// CVPbkETelCntConverter::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CVPbkETelCntConverter::ConstructL()
+ {
+ // Create a Symbian utility for the contact data
+ iETelBuffer = new( ELeave ) CPhoneBookBuffer;
+ // Check how much space new entry tag takes and how much space
+ // is needed for the contact that has only sim index
+ HBufC8* testBuf = HBufC8::NewLC( KTestBufSize );
+ TPtr8 ptr( testBuf->Des() );
+ iETelBuffer->Set( &ptr );
+ iETelBuffer->AddNewEntryTag();
+ iNewEntryTagLength = ptr.Length();
+ TUint16 exampleIndex = 1;
+ iETelBuffer->PutTagAndValue(
+ RMobilePhoneBookStore::ETagPBAdnIndex, exampleIndex );
+ // Safe solution -> double the space
+ iMinContactLength = 2 * ptr.Length();
+ CleanupStack::PopAndDestroy( testBuf );
+ }
+
+// -----------------------------------------------------------------------------
+// CVPbkETelCntConverter::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+EXPORT_C CVPbkETelCntConverter* CVPbkETelCntConverter::NewL()
+ {
+ CVPbkETelCntConverter* self = NewLC();
+ CleanupStack::Pop();
+ return self;
+ }
+
+// -----------------------------------------------------------------------------
+// CVPbkETelCntConverter::NewLC
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+EXPORT_C CVPbkETelCntConverter* CVPbkETelCntConverter::NewLC()
+ {
+ CVPbkETelCntConverter* self = new( ELeave ) CVPbkETelCntConverter;
+ CleanupStack::PushL( self );
+ self->ConstructL();
+ return self;
+ }
+
+// Destructor
+CVPbkETelCntConverter::~CVPbkETelCntConverter()
+ {
+ delete iETelBuffer;
+ }
+
+// -----------------------------------------------------------------------------
+// CVPbkETelCntConverter::ConvertFromETelToVPbkSimContactsL
+// -----------------------------------------------------------------------------
+//
+void CVPbkETelCntConverter::ConvertFromETelToVPbkSimContactsL(
+ RPointerArray<CVPbkSimContactBuf>& aResultArray,
+ TDes8& aETelContactData, MVPbkSimCntStore& aSimStore ) const
+ {
+ CleanupResetAndDestroyPushL( aResultArray );
+ iETelBuffer->Set( &aETelContactData );
+ User::LeaveIfError( StartRead() );
+
+ TInt cntCounter = 0;
+ TPtrC8 etelCnt( GetNextContactData( aETelContactData ) );
+ while ( etelCnt.Length() > 0 )
+ {
+ CVPbkSimContactBuf* cnt = CVPbkSimContactBuf::NewLC( etelCnt,
+ aSimStore );
+ aResultArray.AppendL( cnt );
+ CleanupStack::Pop();
+ ++cntCounter;
+ etelCnt.Set( GetNextContactData( aETelContactData ) );
+ }
+
+ // Check if there was no contacts in the ETel descriptor
+ if ( cntCounter == 0 )
+ {
+ User::Leave( KErrBadDescriptor );
+ }
+ CleanupStack::Pop( &aResultArray );
+ }
+
+// -----------------------------------------------------------------------------
+// CVPbkETelCntConverter::ConvertFromETelToVPbkSimContactL
+// -----------------------------------------------------------------------------
+//
+void CVPbkETelCntConverter::ConvertFromETelToVPbkSimContactL(
+ TDes8& aETelContact, CVPbkSimContact& aEmptyContact ) const
+ {
+ CVPbkSimCntField* tmpField =
+ aEmptyContact.CreateFieldLC( EVPbkSimUnknownType );
+ TInt error = KErrNone;
+ const TInt count = DoFieldCount( aETelContact, error );
+ User::LeaveIfError( error );
+
+ for ( TInt i = 0; i < count; ++i )
+ {
+ FieldAt( aETelContact, i, *tmpField );
+ CVPbkSimCntField* newField =
+ aEmptyContact.CreateFieldLC( tmpField->Type() );
+ newField->SetInitialSimDataL( tmpField->Data() );
+ aEmptyContact.AddFieldL( newField );
+ CleanupStack::Pop( newField );
+ }
+ CleanupStack::PopAndDestroy( tmpField );
+ aEmptyContact.SetSimIndex( SimIndex( aETelContact ) );
+ }
+
+// -----------------------------------------------------------------------------
+// CVPbkETelCntConverter::ConvertFromVPbkSimFieldsToETelCntLC
+// -----------------------------------------------------------------------------
+//
+HBufC8* CVPbkETelCntConverter::ConvertFromVPbkSimFieldsToETelCntLC(
+ const TArray<CVPbkSimCntField*>& aFieldArray, TInt aSimIndex ) const
+ {
+ // Create a buffer for the ETel contact
+ TInt size = iMinContactLength + EstimateDataSize( aFieldArray );
+ HBufC8* buf = HBufC8::NewLC( size );
+ TPtr8 ptr( buf->Des() );
+ iETelBuffer->Set( &ptr );
+
+ // Add new entry tag and the SIM index if not a new contact
+ iETelBuffer->AddNewEntryTag();
+ if ( aSimIndex != KVPbkSimStoreFirstFreeIndex )
+ {
+ iETelBuffer->PutTagAndValue(
+ RMobilePhoneBookStore::ETagPBAdnIndex, (TUint16) aSimIndex );
+ }
+
+ const TInt count = aFieldArray.Count();
+ for( TInt i = 0; i < count; ++i )
+ {
+ TInt result = AddNewETelField( *iETelBuffer, *aFieldArray[i] );
+ while ( result == KErrOverflow )
+ {
+ // If the buffer is too small for some reason -> double the size
+ HBufC8* newBuf = buf->ReAllocL( 2 * buf->Size() );
+ CleanupStack::Pop( buf );
+ buf = newBuf;
+ CleanupStack::PushL( buf );
+
+ ptr.Set( buf->Des() );
+ iETelBuffer->Set( &ptr );
+ result = AddNewETelField( *iETelBuffer, *aFieldArray[i] );
+ }
+ }
+ return buf;
+ }
+
+// -----------------------------------------------------------------------------
+// CVPbkETelCntConverter::SimIndex
+// -----------------------------------------------------------------------------
+//
+TInt CVPbkETelCntConverter::SimIndex( TDes8& aETelContact ) const
+ {
+ iETelBuffer->Set( &aETelContact );
+ if ( StartRead() == KErrNone )
+ {
+ TUint16 simIndex = 0;
+ GetFieldData( *iETelBuffer, simIndex,
+ RMobilePhoneBookStore::ETagPBAdnIndex );
+ if ( simIndex > 0 )
+ {
+ return simIndex;
+ }
+ else
+ {
+ return KVPbkSimStoreFirstFreeIndex;
+ }
+ }
+ return KErrBadDescriptor;
+ }
+
+// -----------------------------------------------------------------------------
+// CVPbkETelCntConverter::FieldCount
+// -----------------------------------------------------------------------------
+//
+TInt CVPbkETelCntConverter::FieldCount( TDes8& aETelContact ) const
+ {
+ // If client gives an invalid buffer KErrBadDescriptor is returned
+ TInt error = KErrNone;
+ TInt result = DoFieldCount( aETelContact, error );
+ if ( error == KErrNone )
+ {
+ return result;
+ }
+ return error;
+ }
+
+// -----------------------------------------------------------------------------
+// CVPbkETelCntConverter::FieldAt
+// -----------------------------------------------------------------------------
+//
+void CVPbkETelCntConverter::FieldAt( TDes8& aETelContact, TInt aIndex,
+ CVPbkSimCntField& aField ) const
+ {
+ iETelBuffer->Set( &aETelContact );
+ if ( StartRead() == KErrNone )
+ {
+ for ( TInt i = 0; i <= aIndex; ++i )
+ {
+ GetNextField( aField );
+ }
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CVPbkETelCntConverter::MoveToNextContact
+// Moves pointer to the next contact
+// -----------------------------------------------------------------------------
+//
+TBool CVPbkETelCntConverter::MoveToNextContact() const
+ {
+ TUint8 fieldTag;
+ CPhoneBookBuffer::TPhBkTagType dataType;
+ while ( iETelBuffer->GetTagAndType( fieldTag, dataType) == KErrNone )
+ {
+ switch ( fieldTag )
+ {
+ case RMobilePhoneBookStore::ETagPBNewEntry:
+ {
+ return ETrue;
+ }
+ default:
+ {
+ iETelBuffer->SkipValue( dataType );
+ break;
+ }
+ }
+ }
+ return EFalse;
+ }
+
+// -----------------------------------------------------------------------------
+// CVPbkETelCntConverter::StartRead
+// Sets the pointer in the ETel buffer to the beginning of the first contact
+// Returns KErrBadDescriptor if the header was not found
+// -----------------------------------------------------------------------------
+//
+TInt CVPbkETelCntConverter::StartRead() const
+ {
+ iETelBuffer->StartRead();
+
+ if ( MoveToNextContact() )
+ {
+ return KErrNone;
+ }
+ return KErrBadDescriptor;
+ }
+
+// -----------------------------------------------------------------------------
+// CVPbkETelCntConverter::GetNextField
+// Gets the next field that has native support, returns EFalse if not found
+// -----------------------------------------------------------------------------
+//
+TBool CVPbkETelCntConverter::GetNextField( CVPbkSimCntField& aField ) const
+ {
+ TPtrC16 data;
+ TUint8 fieldTag;
+ CPhoneBookBuffer::TPhBkTagType dataType;
+ TBool readingAnr = EFalse;
+ while ( iETelBuffer->GetTagAndType( fieldTag, dataType) == KErrNone )
+ {
+ if ( fieldTag == RMobilePhoneBookStore::ETagPBAnrStart )
+ {
+ readingAnr = ETrue;
+ }
+ else if ( dataType == CPhoneBookBuffer::EPhBkTypeDes16 )
+ {
+ iETelBuffer->GetValue( data );
+ TVPbkSimCntFieldType nativeType = FieldConversion( fieldTag );
+ /// Text field of the ANR is not supported. If it's supported
+ /// then the CVPbkSimCntField must have a label and it should
+ /// be set here.
+ if ( readingAnr && nativeType == EVPbkSimGsmNumber )
+ {
+ // VPbk SIM contact has an own type for additional number
+ nativeType = EVPbkSimAdditionalNumber;
+ }
+
+ if ( nativeType != EVPbkSimUnknownType )
+ {
+ aField.SetDataPtr( data );
+ aField.SetType( nativeType );
+ return ETrue;
+ }
+ }
+ else
+ {
+ iETelBuffer->SkipValue( dataType );
+ }
+ }
+
+ return EFalse;
+ }
+
+// -----------------------------------------------------------------------------
+// CVPbkETelCntConverter::NumberOfFields
+// Returns the number of VPbk supported fields in the buffer
+// -----------------------------------------------------------------------------
+//
+TInt CVPbkETelCntConverter::NumberOfFields() const
+ {
+ TUint8 fieldTag;
+ CPhoneBookBuffer::TPhBkTagType dataType;
+ TBool readingAnr = EFalse;
+ TInt count = 0;
+ while ( iETelBuffer->GetTagAndType( fieldTag, dataType) == KErrNone )
+ {
+ if ( fieldTag == RMobilePhoneBookStore::ETagPBAnrStart )
+ {
+ // Tag type is EPhBkTypeNoData so it's not needed to get value
+ readingAnr = ETrue;
+ ++count;
+ }
+ else if ( dataType == CPhoneBookBuffer::EPhBkTypeDes16 )
+ {
+ TVPbkSimCntFieldType nativeType = FieldConversion( fieldTag );
+ if ( !readingAnr && nativeType != EVPbkSimUnknownType )
+ {
+ ++count;
+ }
+ // ANR number field ends the reading of ANR
+ else if ( nativeType == EVPbkSimGsmNumber )
+ {
+ readingAnr = EFalse;
+ }
+ // Data must be always read from the buffer to make it work
+ iETelBuffer->SkipValue( dataType );
+ }
+ else
+ {
+ iETelBuffer->SkipValue( dataType );
+ }
+ }
+
+ return count;
+ }
+
+// -----------------------------------------------------------------------------
+// GetNextContactData
+// Gets the next contact from the buffer that contains many contacts
+// -----------------------------------------------------------------------------
+//
+TPtrC8 CVPbkETelCntConverter::GetNextContactData( TDes8& aBuffer ) const
+ {
+ TInt newEntryTagLength = 1;
+ TInt remainBefore = iETelBuffer->RemainingReadLength();
+
+ if ( MoveToNextContact() )
+ {
+ TInt remainAfter = iETelBuffer->RemainingReadLength();
+ TInt contactLength = remainBefore - remainAfter;
+ TInt startPos = iETelBuffer->BufferLength() - remainBefore -
+ newEntryTagLength;
+ return aBuffer.Mid( startPos, contactLength );
+ }
+
+ // 1 or 0 contacts left
+ if ( remainBefore > 0 )
+ {
+ // 1 contact left
+ TInt startPos = iETelBuffer->BufferLength() - remainBefore -
+ newEntryTagLength;
+ return aBuffer.Mid( startPos );
+ }
+ else
+ {
+ // 0 contacts left, return zero length pointer
+ return TPtrC8();
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// DoFieldCount
+// Counts the number of fields of the contact
+// -----------------------------------------------------------------------------
+//
+TInt CVPbkETelCntConverter::DoFieldCount(
+ TDes8& aETelContact, TInt& aError ) const
+ {
+ TInt count = 0;
+ iETelBuffer->Set( &aETelContact );
+
+ TInt result = StartRead();
+ if ( result == KErrNone )
+ {
+ count = NumberOfFields();
+ }
+ aError = result;
+
+ return count;
+ }
+
+// End of File