phonebookengines/VirtualPhonebook/VPbkVCardEng/src/CVPbkVCardCompactBCardImporter.cpp
/*
* Copyright (c) 2006-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: Virtual Phonebook VCard compact BCard importer
*
*/
// System includes
#include <versit.h>
#include "CVPbkVCardData.h"
#include "CVPbkVCardCompactBCardImporter.h"
#include "VPbkVCardEngError.h"
#include "CVPbkVCardFieldTypeProperty.h"
#include <VPbkEng.rsg>
// From Virtual Phonebook engine
#include <MVPbkContactFieldTextData.h>
#include <MVPbkFieldType.h>
#include <MVPbkSingleContactOperationObserver.h>
#include <MVPbkStoreContactField.h>
#include <MVPbkStoreContact.h>
#include <MVPbkContactStore.h>
#include <MVPbkContactStoreProperties.h>
#include <MVPbkContactCopyPolicy.h>
#include <MVPbkContactOperationBase.h>
#ifdef _DEBUG
using namespace VPbkVCardEngError;
#endif // _DEBUG
namespace
{
enum TVPbkBCardImporterState
{
EGetLine,
EStartTitleCopy,
EAddAddress,
EStop
};
_LIT(KBusinessCardText, "Business Card"); // Business card signature
_LIT(KCloseParenthesis, ")");
_LIT(KTelText, "tel ");
_LIT(KFaxText, "fax ");
_LIT(KSeparatorText, ", ");
const TText KOpenParenthesis = '(';
// Assume compact business card is corrupted if single field length
// exceeds 200 bytes. This value is not officially specified anywhere.
const TInt KBufferSize = 200;
const TInt KStartPosition = 4;
const TInt KLabelStartPosition = 5;
const TInt KLabelValueDelimiterLength = 2;
const TInt KGranularity( 2 );
// Comapct business card fixed field line numbers.
enum TVPbkCBCFieldLines
{
ECBCSignatureLine = 1,
ECBCNameLine,
ECBCCompanyLine,
ECBCTitleLine
};
} // namespace
CVPbkVCardCompactBCardImporter::CVPbkVCardCompactBCardImporter(
RPointerArray<MVPbkStoreContact>& aImportedContacts,
MVPbkContactStore& aTargetStore,
RReadStream &aSourceStream,
CVPbkVCardData& aData )
: CActive( EPriorityStandard ),
iImportedContacts( aImportedContacts ),
iTargetStore(aTargetStore),
iData( aData ),
iSource( aSourceStream )
{
}
CVPbkVCardCompactBCardImporter* CVPbkVCardCompactBCardImporter::NewL(
RPointerArray<MVPbkStoreContact>& aImportedContacts,
MVPbkContactStore& aTargetStore,
RReadStream &aSourceStream,
CVPbkVCardData& aData )
{
CVPbkVCardCompactBCardImporter* self = new (ELeave)
CVPbkVCardCompactBCardImporter(
aImportedContacts,
aTargetStore,
aSourceStream,
aData );
CleanupStack::PushL( self );
self->ConstructL();
CleanupStack::Pop( self );
return self;
}
void CVPbkVCardCompactBCardImporter::ConstructL()
{
CActiveScheduler::Add(this);
iAddressArray = new( ELeave ) CDesCArrayFlat( KGranularity );
iCopyPolicy = &iData.CopyPolicyL( iTargetStore.StoreProperties().Uri() );
}
CVPbkVCardCompactBCardImporter::~CVPbkVCardCompactBCardImporter()
{
Cancel();
delete iAddToFieldOperation;
delete iCurContact;
delete iAddressArray;
delete iValue;
delete iLabel;
delete iLine;
}
void CVPbkVCardCompactBCardImporter::StartL()
{
iCurContact = iTargetStore.CreateNewContactLC();
CleanupStack::Pop();
iState = EGetLine;
IssueRequest();
}
void CVPbkVCardCompactBCardImporter::SetObserver(
MVPbkImportOperationObserver& aObserver )
{
iObserver = &aObserver;
}
void CVPbkVCardCompactBCardImporter::RunL()
{
switch (iState)
{
case EGetLine:
{
if (GetLineL())
{
ParseLineL();
}
break;
}
case EAddAddress:
{
AddAddressL();
break;
}
case EStartTitleCopy:
{
StartTitleCopyL();
break;
}
case EStop:
{
iObserver->ContactsImportingCompleted();
break;
}
default:
{
// Do nothing
break;
}
}
}
void CVPbkVCardCompactBCardImporter::DoCancel()
{
delete iAddToFieldOperation;
iAddToFieldOperation = NULL;
}
TInt CVPbkVCardCompactBCardImporter::RunError(TInt aError)
{
iObserver->ContactImportingFailed( aError );
return KErrNone;
}
void CVPbkVCardCompactBCardImporter::FieldAddedToContact(
MVPbkContactOperationBase& aOperation)
{
if ( &aOperation == iAddToFieldOperation )
{
delete iAddToFieldOperation;
iAddToFieldOperation = NULL;
IssueRequest();
}
}
void CVPbkVCardCompactBCardImporter::FieldAddingFailed(
MVPbkContactOperationBase& aOperation, TInt aError)
{
if ( &aOperation == iAddToFieldOperation )
{
delete iAddToFieldOperation;
iAddToFieldOperation = NULL;
if (aError == KErrNotSupported )
{
// Target contact didn't support field -> continue
IssueRequest();
}
else if ( aError == KErrOverflow )
{
// Target contact is full of that field
TRAPD( res, HandleContactSwitchL() );
HandleError( res );
}
else
{
iObserver->ContactImportingFailed( aError );
}
}
}
void CVPbkVCardCompactBCardImporter::FieldsCopiedToContact(
MVPbkContactOperationBase& /*aOperation*/)
{
++iTargetContactIndex;
if ( iTargetContactIndex >= iImportedContacts.Count() )
{
iObserver->ContactsImported();
}
else
{
TRAPD( res, CopyTitleL() );
HandleError( res );
}
}
void CVPbkVCardCompactBCardImporter::FieldsCopyFailed(
MVPbkContactOperationBase& /*aOperation*/,
TInt aError)
{
HandleError( aError );
}
void CVPbkVCardCompactBCardImporter::IssueRequest()
{
TRequestStatus* status = &iStatus;
User::RequestComplete(status, KErrNone);
SetActive();
}
TBool CVPbkVCardCompactBCardImporter::GetLineL()
{
delete iLine;
iLine = NULL;
iLine = HBufC::NewL( KBufferSize );
TPtr line = iLine->Des();
TBool result = EFalse;
TInt retVal( GetLineFromStreamL( line, iSource ) );
if ( retVal == KErrNone || retVal == KErrEof )
{
if(line.Length() > 0)
{
++iLineCount;
result = ETrue;
}
else
{
iState = EStop;
IssueRequest();
}
}
if(retVal == KErrEof && line.Length() > 0 )
{
iState = EAddAddress;
}
return result;
}
void CVPbkVCardCompactBCardImporter::ParseLineL()
{
TPtr line = iLine->Des();
TInt resId( ResolveFieldTypeResIdL( line ) );
if ( resId == KErrNotFound )
{
IssueRequest();
}
else if ( resId == R_VPBK_FIELD_TYPE_LANDPHONEGEN ||
resId == R_VPBK_FIELD_TYPE_FAXNUMBERGEN )
{
// Asynchronous
ValueAndLabelToBufL( line, resId );
}
else if ( resId == R_VPBK_FIELD_TYPE_ADDRLABELGEN )
{
// Synchronous
ValueToArrayL( line );
IssueRequest();
}
else
{
// Asynchronous
ValueToBufL( line, resId );
}
}
void CVPbkVCardCompactBCardImporter::ValueToBufL(
const TDesC& aBuffer, TInt aResId )
{
const MVPbkFieldType* fieldType = FindFieldTypeL( aResId );
__ASSERT_DEBUG( fieldType,
VPbkVCardEngError::Panic( VPbkVCardEngError::ENullFieldType ) );
AddFieldWithValueL( *fieldType, aBuffer, NULL );
}
void CVPbkVCardCompactBCardImporter::ValueToArrayL( const TDesC& aBuffer )
{
// Address is saved after all other fields have been saved
iAddressArray->AppendL( aBuffer );
if( iValueLength )
{
iValueLength += KSeparatorText().Length();
}
iValueLength += aBuffer.Length();
}
void CVPbkVCardCompactBCardImporter::ValueAndLabelToBufL(
const TDesC& aBuffer, TInt aResId )
{
const MVPbkFieldType* fieldType = FindFieldTypeL( aResId );
__ASSERT_DEBUG( fieldType,
VPbkVCardEngError::Panic( VPbkVCardEngError::ENullFieldType ) );
// Read tel num label
TInt position( KStartPosition );
delete iLabel;
iLabel = NULL;
if( aBuffer[KStartPosition] == KOpenParenthesis )
{
position = aBuffer.Find( KCloseParenthesis );
if( position == KErrNotFound )
{
return;
}
iLabel = HBufC::NewL( position - KStartPosition );
TPtr writebuf = iLabel->Des();
writebuf = KNullDesC;
for( TInt i = KLabelStartPosition; i<position; i++ )
{
writebuf.Append( aBuffer[i] );
}
// Jump few characters
position += KLabelValueDelimiterLength;
}
// Read value
delete iValue;
iValue = NULL;
iValue = HBufC::NewL( aBuffer.Length() - position );
TPtr writebuf = iValue->Des();
writebuf = KNullDesC;
for( TInt i = position; i < aBuffer.Length(); i++ )
{
writebuf.Append( aBuffer[i] );
}
AddFieldWithValueL( *fieldType, *iValue, iLabel );
}
void CVPbkVCardCompactBCardImporter::AddAddressL()
{
if ( iAddressArray->Count() > 0 )
{
// Then concatenate them with commas into one string
// and use that as field value.
HBufC* fielddata = HBufC::NewLC( iValueLength );
TPtr writebuf = fielddata->Des();
writebuf = KNullDesC;
TInt count = iAddressArray->Count();
for( TInt i = 0; i < count; ++i )
{
if( i )
{
writebuf.Append( KSeparatorText );
}
writebuf.Append( iAddressArray->MdcaPoint( i ) );
}
const MVPbkFieldType* fieldType = FindFieldTypeL( R_VPBK_FIELD_TYPE_ADDRLABELGEN );
__ASSERT_DEBUG( fieldType,
VPbkVCardEngError::Panic( VPbkVCardEngError::ENullFieldType ) );
AddFieldWithValueL( *fieldType, *fielddata, NULL );
CleanupStack::PopAndDestroy( fielddata );
}
else
{
IssueRequest();
}
// Address is the last field so continue with titles after address
// has been added, or not added
iState = EStartTitleCopy;
}
TInt CVPbkVCardCompactBCardImporter::ResolveFieldTypeResIdL( const TDesC& aBuffer )
{
TInt resId( KErrNotFound );
switch ( iLineCount )
{
case ECBCSignatureLine:
{
if ( aBuffer.Match( KBusinessCardText() ) == KErrNotFound )
{
User::Leave( KErrNotSupported );
}
return resId;
}
case ECBCNameLine: // Name
{
resId = R_VPBK_FIELD_TYPE_LASTNAME;
break;
}
case ECBCCompanyLine: // Company name
{
resId = R_VPBK_FIELD_TYPE_COMPANYNAME;
break;
}
case ECBCTitleLine: // Title
{
resId = R_VPBK_FIELD_TYPE_JOBTITLE;
break;
}
}
if ( resId == KErrNotFound ) // Tel numbers
{
if ( aBuffer.Find( KTelText ) >= 0 )
{
resId = R_VPBK_FIELD_TYPE_LANDPHONEGEN;
}
else if ( aBuffer.Find( KFaxText ) >= 0 )
{
resId = R_VPBK_FIELD_TYPE_FAXNUMBERGEN;
}
}
if ( !iEMailFetchedFlag && resId == KErrNotFound )
{
resId = R_VPBK_FIELD_TYPE_EMAILGEN; // Email address
iEMailFetchedFlag = ETrue;
}
if ( resId == KErrNotFound )// Postal address
{
resId = R_VPBK_FIELD_TYPE_ADDRLABELGEN;
}
return resId;
}
void CVPbkVCardCompactBCardImporter::AddFieldWithValueL(
const MVPbkFieldType& aFieldType, const TDesC& aValue, HBufC* aLabel )
{
__ASSERT_DEBUG( !iAddToFieldOperation,
VPbkVCardEngError::Panic(
VPbkVCardEngError::EAddToFieldOperationAlreadyExists ) );
iAddToFieldOperation = iCopyPolicy->AddFieldToContactL(
*iCurContact, aFieldType, aValue, aLabel, NULL, *this);
}
void CVPbkVCardCompactBCardImporter::StartTitleCopyL()
{
MoveCurrentContactToImportsL();
// If vcard was split to multiple contacts then copy
// title fields from the first imported contact to the other contacts.
const TInt oneContactImported = 1;
if ( iImportedContacts.Count() <= oneContactImported )
{
iObserver->ContactsImported();
}
else
{
iTargetContactIndex = oneContactImported;
CopyTitleL();
}
}
const MVPbkFieldType* CVPbkVCardCompactBCardImporter::FindFieldTypeL(
TInt aFieldIndex )
{
return iData.SupportedFieldTypes().Find( aFieldIndex );
}
TInt CVPbkVCardCompactBCardImporter::GetByteFromStream(
TInt8& aByte, RReadStream& aSourceStream)
{
TRAPD(err, aByte = aSourceStream.ReadInt8L());
return err;
}
TInt CVPbkVCardCompactBCardImporter::GetLineFromStreamL(
TDes& aBuf, RReadStream& aSourceStream)
{
aBuf.SetLength(0);
TInt8 byte=0;
TInt retVal( KErrNone );
while( ( retVal = GetByteFromStream(byte, aSourceStream) ) == KErrNone)
{
if(byte == EKeyLineFeed)
{
break;
}
if(byte != EKeyEnter)
{
if (aBuf.Length() < aBuf.MaxLength())
{
aBuf.Append(byte);
}
else
{
User::Leave(KErrCorrupt);
}
}
}
return retVal;
}
void CVPbkVCardCompactBCardImporter::HandleContactSwitchL()
{
// Current contact is full -> Create a new contact and
// add the same line to that one.
MoveCurrentContactToImportsL();
iCurContact = iTargetStore.CreateNewContactLC();
CleanupStack::Pop();
if ( iLine && iLine->Length() > 0 )
{
// Parse same line again
ParseLineL();
}
else
{
// End of file -> continue with address
AddAddressL();
}
}
void CVPbkVCardCompactBCardImporter::CopyTitleL()
{
delete iAddToFieldOperation;
iAddToFieldOperation = NULL;
iAddToFieldOperation = iCopyPolicy->CopyTitleFieldsL(
*iImportedContacts[0],
*iImportedContacts[iTargetContactIndex],
*this );
}
void CVPbkVCardCompactBCardImporter::MoveCurrentContactToImportsL()
{
iImportedContacts.AppendL( iCurContact );
iCurContact = NULL;
}
void CVPbkVCardCompactBCardImporter::HandleError( TInt aError )
{
if ( aError != KErrNone )
{
iObserver->ContactImportingFailed( aError );
}
}
TBool CVPbkVCardCompactBCardImporter::IsOwncard()
{
return EFalse;
}
// End of file