phonebookengines_old/contactsmodel/src/CNTITEM.CPP
changeset 40 b46a585f6909
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/phonebookengines_old/contactsmodel/src/CNTITEM.CPP	Fri Jun 11 13:29:23 2010 +0300
@@ -0,0 +1,2454 @@
+// 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 <s32std.h>
+#include <f32file.h>
+
+#include <cntdef.h>
+#include <cntitem.h>
+#include <cntfield.h>
+#include <cntfldst.h>
+#include <cntdb.h>
+
+#include "CNTSTD.H"
+#include "CNTPROF.H"
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
+#include "cntfieldheader.h"
+#endif
+
+
+EXPORT_C CContactItemFieldSet* CContactItemFieldSet::NewL()
+/** Allocates and constructs a new field set.
+
+@return Pointer to the newly created field set. */
+	{ // static 
+	CContactItemFieldSet* self=CContactItemFieldSet::NewLC();
+	CleanupStack::Pop(); // self
+	return self;
+	}
+
+EXPORT_C CContactItemFieldSet* CContactItemFieldSet::NewLC()
+/** Allocates and constructs a new field set.
+
+@return Pointer to the newly created field set. This is left on the cleanup 
+stack. */
+	{ // static
+	CContactItemFieldSet* self=new(ELeave) CContactItemFieldSet;
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	return self;
+	}
+
+EXPORT_C CContactItemFieldSet::~CContactItemFieldSet()
+/** The destructor frees all resources owned by the field set, prior to its destruction. */
+	{
+	if (iFields)
+		{
+		iFields->ResetAndDestroy();
+		delete iFields;
+		}
+	}
+
+CContactItemFieldSet::CContactItemFieldSet()
+	{}
+
+void CContactItemFieldSet::ConstructL()
+	{
+	iFields=new(ELeave) CArrayPtrFlat<CContactItemField>(4);
+	}
+
+const CContactItemField* CContactItemFieldSet::FindById(TInt aId) const
+	{
+	const CContactItemField* field=NULL;
+	for (TInt ii=0;ii<iFields->Count();ii++)
+		{
+		field=iFields->At(ii);
+		if (field->Id()==aId)
+			return(field);
+		}
+	return(NULL);
+	}
+
+EXPORT_C TInt CContactItemFieldSet::FindNext(TFieldType aFieldType,TInt aStartPos) const
+/** Finds the next field in the field set with the specified field type.
+
+@param aFieldType The field type of interest.
+@param aStartPos The index within the field set array at which to start the 
+search. By default set to KContactFieldSetSearchAll, to find the first field. 
+Must be a valid array index, or the function raises a panic.
+@return If found, the index of the field within the field set, or KErrNotFound 
+if not found. */
+	{
+	return(FindNext(aFieldType,KUidContactFieldMatchAll,aStartPos));
+	}
+
+EXPORT_C TInt CContactItemFieldSet::FindNext(TFieldType aFieldType,TUid aMapping,TInt aStartPos) const
+/** Finds the next field in the field set containing both the content type mapping 
+and the field type specified.
+
+@param aFieldType The field type of interest.
+@param aMapping The content type mapping of interest.
+@param aStartPos The index within the array at which to start the search. By 
+default set to KContactFieldSetSearchAll, to find the first field. Must be 
+a valid array index, or the function raises a panic.
+@return If found, the index of the field within the field set, or KErrNotFound 
+if not found. */
+	{
+	const TInt count=iFields->Count();
+	TInt pos=(aStartPos==KContactFieldSetSearchAll? 0 : aStartPos);
+	TInt ii=KErrNotFound;
+	for (ii=pos;ii<count;ii++)
+		{
+		const CContentType& contentType=(*iFields)[ii]->ContentType();
+		if (contentType.Mapping()==KUidContactFieldMatchAll || aMapping==KUidContactFieldMatchAll || contentType.Mapping()==aMapping)
+			if (aFieldType==KUidContactFieldMatchAll || contentType.ContainsFieldType(aFieldType))
+				return ii;
+		}
+	return KErrNotFound;
+	}
+
+void CContactItemFieldSet::SetFieldId(CContactItemField& aField)
+	{
+	TInt id=iFields->Count();
+	TInt count=iFields->Count();
+	FOREVER
+		{
+		TInt loop=0;
+		for(;loop<count;loop++)
+			if ((*iFields)[loop]->Id()==id)
+				break;
+		if (loop==count)
+			{
+			aField.SetId(id);
+			break;
+			}
+		id++;
+		}
+	}
+
+EXPORT_C CContactItemFieldSet& CContactItemFieldSet::AddL(CContactItemField& aField)
+/** Appends a field to the field set. The field set takes ownership of the field.
+
+@param aField Reference to the field to add to the field set. The field's 
+ID is updated.
+@return Reference to the current field set. */
+	{
+	__ASSERT_DEBUG(&aField!=NULL,Panic(ECntPanicNullPointer));
+	SetFieldId(aField);
+	iFields->AppendL(&aField);
+	return (*this);
+	}
+
+EXPORT_C void CContactItemFieldSet::Remove(TInt aIndex)
+/** Removes a field from the field set.
+
+@param aIndex The index of the field to delete. Must be a valid index within 
+the field set or the function raises a panic. */
+	{
+	delete (*iFields)[aIndex];
+	iFields->Delete(aIndex);
+	}
+
+EXPORT_C void CContactItemFieldSet::Move(TInt aFrom, TInt aTo)
+/** Changes a field's position within the field set.
+
+Both indexes specified must be valid (i.e. between zero and Count()-1 inclusive), 
+or the function raises a panic.
+
+@param aFrom The index of the field to move.
+@param aTo The index of the new position within the field set. */
+	{
+	CContactItemField *moveField=(*iFields)[aFrom];
+	if (aFrom<aTo)
+		{
+		for(TInt loop=aFrom;loop<aTo;loop++)
+			(*iFields)[loop]=(*iFields)[loop+1];
+		}
+	else
+		{
+		for(TInt loop=aFrom;loop>aTo;loop--)
+			(*iFields)[loop]=(*iFields)[loop-1];
+		}
+	(*iFields)[aTo]=moveField;
+	}
+
+EXPORT_C void CContactItemFieldSet::InsertL(TInt aIndex,CContactItemField& aField)
+/** Inserts a field into the field set.
+
+@param aIndex The position in the field set at which to insert the field. 
+If equal to or greater than the number of elements in the field set, the field 
+is appended to the field set.
+@param aField Reference to the field to add to the field set. The field's ID 
+is updated. */
+	{
+	__ASSERT_DEBUG(&aField!=NULL,Panic(ECntPanicNullPointer));
+	SetFieldId(aField);
+	TInt count=iFields->Count();
+	if (count>aIndex)
+		iFields->InsertL(aIndex,&aField);
+	else
+		iFields->AppendL(&aField);
+	}
+
+/**
+
+Find and return the index of the best matched template field. The method uses a matching algorithm which compares the content type of the template fields with that of the incoming contact item.
+
+Matching Algorithm Steps:
+========================
+
+The algorithm is based on a scoring mechanism counting 'hits' and 'misses' in order to find the best possible field match within the fieldset of the template.
+
+1. Loop through all the contact item fields of the template.
+
+For each template field:
+
+2. Perform a strict, or exact, match between the vCard mappings of the template field and the field to be matched.
+3. If the vCard mappings match exactly, compare User Flags values and amend the overall score accordingly.
+4. Loop through all the field types (TFieldType array) stored as part of the content type of the field to be matched.
+
+For each field type of the field to be matched:
+
+5. Loop through the field types of the iterated template field to find a field type match. Amend the 'hits' and 'misses' count accordingly.
+6. Calculate the overall score weighing the 'hits' and 'misses' count.
+7. Amend the overall score count in order to account for special cases (e.g. user defined fields)
+8. Compare the overall score with the best score. If score > current best score, replace the 'bestScore' count and 'bestMatch' index.
+
+9. Return the 'bestMatch' field index of the template field.
+
+@param aContentType		The content type of the field to find a match for.
+@param aUserFlags		The user flags of the field to find a match for.
+@param aExactMatch		Boolean to indicate an exact field match within the template.
+
+@return The index of the best matched template field, if found, else KErrNotFound.
+
+*/
+
+TInt CContactItemFieldSet::MatchTemplateField(const CContentType& aContentType,TUint aUserFlags,TBool &aExactMatch) const
+	{
+	const TInt count=Count();
+	TInt bestScore=5;	// Has to be better than one or fail the match
+	TInt bestMatch=KErrNotFound;
+	TInt contentTypeCount=aContentType.FieldTypeCount();
+
+	// Loop through all the template fields to find the best field match
+	for (TInt ii=0;ii<count;ii++)
+		{
+		const CContactItemField& field=*(*iFields)[ii];
+		const CContentType &fieldContentType=field.ContentType();
+
+		// Strict matching executed on the vCard mappings in order to avoid matching non-related fields e.g. Fax and Address fields.
+		// NOTE: The vCard mappings are intended to match the vCard PROPERTY (e.g. TEL in TEL;HOME;FAX:01234), wherein the field is to be exported into a vCard.
+		if (fieldContentType.Mapping()==aContentType.Mapping())
+			{
+			TInt score=fieldContentType.Mapping()==KUidContactFieldVCardMapUnusedN?0:100;
+			TInt hits=0;
+			TInt misses=0;
+
+			// The criteria for an exact match of the User Flags has been changed
+			// from a mandatory requirement to a preference within the scoring system
+			if (aUserFlags==0 || field.UserFlags()==aUserFlags)
+				{
+				++score;
+				}
+
+			// NOTE: A common Field Types array stores BOTH the Field Type in addition to the Extra Mappings
+			//
+			// A. Field Type     = Contact item field's type defined internally
+			// B. Extra Mappings = Refer to the vCard PARAMETERS (e.g. FAX and HOME in TEL;HOME;FAX:01234)
+			//
+			// The Field Type and Extra Mappings are defined as part of the FIELD structure within the template (cntmodel.rss)
+			//
+			// C. Field Types array = A (Field Type, first element) + B (Extra Mappings, all elements after the first element)
+			
+			// Loop through the incoming contact item field's Field Types (C)
+			for(TInt contactFieldTypeLoop=0; contactFieldTypeLoop < contentTypeCount; ++contactFieldTypeLoop)
+				{
+				// Match EACH of the incoming contact item field's Field Types (C) within the template field's Field Types (C)
+				if(ContainsFieldTypeMapping(fieldContentType,aContentType.FieldType(contactFieldTypeLoop)))
+					{
+					++hits;
+					}
+				else
+					{
+					++misses;
+					}				
+				}
+
+			// Check if the incoming contact item has a vCard property mapping
+			// that is also present in the current template field's Field Types.
+			// This covers the (unusual) case where a template field is defined
+			// to have a vCard property mapping which is also the same as one of
+			// field types (which contains property parameter mappings).
+			for(TInt fieldTypeIdx=0; fieldTypeIdx < fieldContentType.FieldTypeCount(); ++fieldTypeIdx)
+				{
+				if(fieldContentType.FieldType(fieldTypeIdx) == aContentType.Mapping())
+					{
+					++hits;
+					}
+				}
+			
+			misses+=fieldContentType.FieldTypeCount()-hits;
+			score+=10*hits-5*misses;
+			
+			if (!field.UserAddedField())
+				{
+				score+=3;	// Non-user added field takes priority over user added fields
+				}
+			
+			if (fieldContentType.ContainsFieldType(KUidContactFieldVCardMapWORK))
+				{
+				score+=1;	// Work fields take priority over home fields
+				}
+				
+			if (score>bestScore)
+				{
+				aExactMatch=(misses==0);
+				bestScore=score;
+				bestMatch=ii;
+				}
+			}
+		}
+	return bestMatch;
+	}
+
+// Attempt to find a contact item field type within the Field Types array (Field Types array = Field Type (internal) + Extra Mappings) of the base contact item.
+// NOTE: This function does not include the base contact item field's vCard mapping whilst looking for the Field Type
+TBool CContactItemFieldSet::ContainsFieldTypeMapping(const CContentType& aBaseFieldContentType, const TFieldType& aContactFieldType) const
+	{
+	// Loop through all the template Field Types to attempt to match the individual Field Type of the incoming contact item's field
+	for(TInt templateFieldTypeLoop=0; templateFieldTypeLoop < aBaseFieldContentType.FieldTypeCount(); ++templateFieldTypeLoop)
+		{
+		if(aBaseFieldContentType.FieldType(templateFieldTypeLoop) == aContactFieldType)
+			{
+			return ETrue;
+			}
+		}
+	return EFalse;
+	}
+
+/**
+@internalTechnology 
+*/
+EXPORT_C TStreamId CContactItemFieldSet::StoreL(CStreamStore& aStore,const CContactItem* aTemplate,RWriteStream& aTextStream,CStreamStore& aBlobStore,CContactTables* aTables)
+	{
+	const TInt count=Count();
+	for (TInt ii=0;ii<count;ii++)
+		{
+		CContactItemField* field=(*iFields)[ii];
+		if (aTemplate)
+			{
+			const CContactItemFieldSet& templateFields = aTemplate->CardFields();
+			field->UpdateFieldFlags(templateFields);
+			}
+		else
+			{
+			field->SetLabelUnspecified(EFalse);
+			}
+		}
+	return StoreL(aStore,aTextStream,aBlobStore,aTables);
+	}
+
+EXPORT_C TStreamId CContactItemFieldSet::StoreL(CStreamStore& aStore,RWriteStream& aTextStream,CStreamStore& aBlobStore)
+/** Stores the field set to a stream store.
+@internalTechnology
+@param aStore Stream store to which the field set is written.
+@param aTextStream Stream to which data stored in text fields (with a storage 
+type of KStorageTypeText) is written.
+@param aBlobStore Stream store to which data stored in non-text fields is written.
+@return The ID of the stream store. */
+	{
+	//Overloaded to maintain SC.
+	return (StoreL(aStore,aTextStream,aBlobStore,NULL));
+	}
+	
+/* 
+Store all contact fields in this field set into given header and data stores.
+
+In SQLite data schema, contact field data is saved in the stream store (aStore) as:
+
+contact-item-field-set = number-of-fields *field		
+    ; <field> repeated <number-of-fields> times
+ 
+field = contact-field-atts [ stream-id ] field-id template-id [ hint-value *mapping *additional-field ] [ label-length [ label ] ]
+	; 1st optional part is there if the contact field is NOT stored as text.
+	; if the field uses the template's content type, the 2nd optional part is left out
+	; <additional-field> is repeated a number of times as specified by <number-of-additional-fields> inside hint-value
+	; mapping is there if vcard-mapping-id-mask in hint-valute is set
+	; 3rd optional part is there if there is a label which overrides the template label. <label> is left out if <label-length> is zero
+
+contact-field-atts = attrib-store
+
+attrib-store =	attribs field-type extended-attribs				
+	; 32 bits -- order is endian-dependent
+
+attribs	= 14BIT						
+	; 14 bitfields: Hidden, ReadOnly, Synchronize, Disabled, 
+	;	4 user-defined fields, OverRidesLabel, UsesTemplateData, 
+	;	UserAddedField, Template, LabelUnspecified and Deleted (in that order), 
+	
+field-type = 4BIT						; 0..16
+extended-attribs = 8BIT
+    ; 8 bitfields: Private, SpeedDial, EUserDefinedFilter and 
+    ; EUserDefinedFilter1-4(in that order)		
+
+hint-value = vcard-mapping-id-mask *number-of-additional-fields *hint-value
+    ; 32 bits -- order is endian-dependent
+    ; hint-value and number-of-additional-fields is there if UsesTemplateData is NOT set in attribs
+vcard-mapping-id-mask= 1BIT   
+number-of-additional-fields = 7BIT
+hint-value = 24BIT
+
+mapping = Int32
+field-id =UInt32
+template-id =UInt32
+stream-id =UInt32
+label-length = Int32
+label = Descriptor
+
+@param aStore the stream store for data header
+@param aTextStream the stream to store text data
+@param aBlobStore  the stream store for blob data
+
+@return stream id the data header stored in aStore.
+*/
+
+TStreamId CContactItemFieldSet::StoreL(CStreamStore& aStore, RWriteStream& aTextStream, CStreamStore& aBlobStore, CContactTables* /*aTables*/)
+	{
+	CArrayFix<TInt>* fullFields = new(ELeave) CArrayFixFlat<TInt>(4);
+	CleanupStack::PushL(fullFields);  // push here to make cleanup easier
+	
+	CArrayFix<TFieldHeader>* fieldHeader = new(ELeave) CArrayFixFlat<TFieldHeader>(5);
+	CleanupStack::PushL(fieldHeader);
+	
+	TInt textFieldIndex = 0;
+
+	const TInt KCount = Count();
+	for(TInt ii = 0; ii < KCount; ++ii)
+	    {  
+	    // find all non-empty fields
+		CContactItemField* field = (*iFields)[ii];
+
+		if (!field->IsDeleted()) 
+			{
+			// only save non-empty content in the blob
+			fullFields->AppendL(ii); // save for later
+			
+			//Add the text storage field data from the field to the blob
+			fieldHeader->AppendL(field->StoreL(aTextStream, aBlobStore, textFieldIndex));
+			if (field->StorageType() == KStorageTypeText)
+			    {
+				++textFieldIndex;
+			    }
+			}
+		}
+
+	// adjust the hint values for non-empty fields only
+	RStoreWriteStream rootStream;
+	TStreamId streamId = rootStream.CreateLC(aStore);
+	
+	const TInt KHintCount = fieldHeader->Count();
+	rootStream << TCardinality(KHintCount);
+	
+	for (TInt ii = 0; ii < KHintCount; ++ii)
+		{
+		CContactItemField* field=(*iFields)[(*fullFields)[ii]];
+		field->PopulateStoreL(rootStream, ii, *fieldHeader);
+		}	
+		
+	rootStream.CommitL();
+	aStore.CommitL();
+		
+	CleanupStack::PopAndDestroy(3, fullFields); // rootStream, fieldHeader, fullFields
+	return streamId;
+	}
+	
+HBufC* CContactItemFieldSet::LoadTextStreamLC(RReadStream& aStream)
+	{
+	TInt maxlen=0;
+	if (aStream.Source())
+		maxlen=aStream.Source()->SizeL(); 
+	maxlen=maxlen/2;
+	HBufC* textStream=HBufC::NewLC(maxlen);
+	if (maxlen)
+		{
+		TPtr des=textStream->Des();
+		aStream.ReadL(des,maxlen);
+		}
+	return(textStream);
+	}
+
+void CContactItemFieldSet::RestoreAndAddTemplateL(CStreamStore& aStore, TStreamId aId,CStreamStore* aBlobStore,const CContactItemViewDef& aViewDef,
+									const CContactItem* aTemplate,RReadStream& aReadStream,CContactTables* aContactsTable,RArray<TInt>* aEmailIdArray)
+	{
+	if (aViewDef.Use()==CContactItemViewDef::EIncludeFields && aViewDef.Count()==0)
+		return; // zzz temp kludge, fix this properly
+	if (aTemplate)
+		{
+		CContactItemFieldSet *original=CContactItemFieldSet::NewLC();
+		original->RestoreL(aStore,aId,aBlobStore,aViewDef,aTemplate,aReadStream,aContactsTable,aEmailIdArray);
+		TInt count=original->Count();
+		for(TInt loop=0;loop<count;loop++)
+			{
+			CContactItemField* additionalField=CContactItemField::NewLC((*original)[loop]);
+			AddL(*additionalField);
+			CleanupStack::Pop(); // additionalField
+			}
+		CleanupStack::PopAndDestroy(); // original
+		}
+	else
+		RestoreL(aStore,aId,aBlobStore,aViewDef,NULL,aReadStream,aContactsTable,aEmailIdArray);
+	}
+
+/** 
+Restores the field set using a view definition.
+@internalTechnology
+@param aStore Store from which to restore the field set.
+@param anId The root stream ID of aStore.
+@param aBlobStore If specified, the stream store from which data stored in 
+non-text fields is read.
+@param aViewDef The view definition to use.
+@param aReadStream Read stream from which data stored in text fields (with 
+a storage type of KStorageTypeText) is read. 
+*/
+EXPORT_C void CContactItemFieldSet::RestoreL(CStreamStore& aStore, TStreamId anId,CStreamStore* aBlobStore,const CContactItemViewDef& aViewDef,RReadStream& aReadStream)
+    {
+	//THIS FUNCTION IS TO BE REMOVED....
+	RestoreL(aStore,anId,aBlobStore,aViewDef,NULL,aReadStream,NULL,NULL);
+	}
+
+
+void CContactItemFieldSet::RestoreL(CStreamStore& aStore, TStreamId anId, CStreamStore* aBlobStore,const CContactItemViewDef& aViewDef,const CContactItem* aTemplate,RReadStream& aReadStream,CContactTables* /*aContactsTable*/, RArray<TInt>* /*aEmailIdArray*/)
+	// Overloaded looks in the Contacts Table for cetain fields.
+	{
+	const TBool includeFields=aViewDef.Use()==CContactItemViewDef::EIncludeFields;
+	if (includeFields && aViewDef.Count()==0)
+		return;
+	RStoreReadStream stream;
+	stream.OpenLC(aStore,anId);
+	TCardinality fieldCount;
+	stream>>fieldCount;
+	TStreamId nestedId;
+	TInt textFieldIndex=0;
+	HBufC *textStream=CContactItemFieldSet::LoadTextStreamLC(aReadStream);
+
+	for (TInt ii=0; ii<fieldCount; ++ii)
+		{
+		CContactItemField* field=CContactItemField::NewLC();
+		nestedId=field->RestoreFieldTypesL(stream,aTemplate?&(aTemplate->CardFields()):NULL);
+		const CContentType &type=field->ContentType();
+		TBool fieldDefined=aViewDef.MatchesAll() || (aViewDef.Find(type)!=KErrNotFound);
+		if (!((fieldDefined&&includeFields) || (!fieldDefined&&!includeFields)) || 
+			(field->IsHidden() && aViewDef.Mode()==CContactItemViewDef::EMaskHiddenFields)
+			)
+			{
+			if (field->StorageType()==KStorageTypeText)  
+				textFieldIndex++;
+			CleanupStack::PopAndDestroy(); // field
+			}
+		else
+			{
+			if (field->StorageType()==KStorageTypeText)  // restore from text stream
+				{
+				// restore text from contacts table.
+				TPtrC textPtr;
+				if(textPtr.Length())
+					{
+					field->TextStorage()->SetTextL(textPtr);
+					}
+				else
+					{
+					field->RestoreTextL(textStream,textFieldIndex);
+					}
+				iFields->AppendL(field);
+				CleanupStack::Pop(); // field
+				textFieldIndex++;
+				}
+			else if (aBlobStore)
+				{
+				field->RestoreDataL(*aBlobStore, nestedId);
+				iFields->AppendL(field);
+				CleanupStack::Pop(); // field
+				}
+			else
+				{
+				CleanupStack::PopAndDestroy(); // field
+				}
+			}
+		}
+	CleanupStack::PopAndDestroy(2); // textStream,stream
+    }
+
+/**
+The overload that doesn't use dangerous CContactItemFieldSet::LoadTextStreamLC(aReadStream) method.
+LoadTextStreamLC relies on the stream to know its size, but now all types of streams support this functionality.
+In order to avoid calling LoadTextStreamLC, aTextBuf is already loaded in HBufC in the caller function.
+The caller function had access to the table and can use ColLength() API to get the lebgth of the field.
+@internalTechnology
+*/
+EXPORT_C void CContactItemFieldSet::RestoreL(CStreamStore& aStore, TStreamId anId, CStreamStore* aBlobStore,const CContactItemViewDef& aViewDef,const CContactItem* aTemplate,HBufC* aTextBuf)
+	{
+	const TBool includeFields=aViewDef.Use()==CContactItemViewDef::EIncludeFields;
+	if (includeFields && aViewDef.Count()==0)
+		return;
+	RStoreReadStream stream;
+	stream.OpenLC(aStore,anId);
+	TCardinality fieldCount;
+	stream>>fieldCount;
+	TStreamId nestedId;
+	TInt textFieldIndex=0;
+
+	for (TInt ii=0;ii<fieldCount;ii++)
+		{
+		CContactItemField* field=CContactItemField::NewLC();
+		nestedId=field->RestoreFieldTypesL(stream,aTemplate?&(aTemplate->CardFields()):NULL);
+		const CContentType &type=field->ContentType();
+		TBool fieldDefined=aViewDef.MatchesAll() || (aViewDef.Find(type)!=KErrNotFound);
+		if (!((fieldDefined&&includeFields) || (!fieldDefined&&!includeFields)) || 
+			(field->IsHidden() && aViewDef.Mode()==CContactItemViewDef::EMaskHiddenFields)
+			)
+			{
+			if (field->StorageType()==KStorageTypeText)  
+				textFieldIndex++;
+			CleanupStack::PopAndDestroy(field);
+			}
+		else
+			{
+			if (field->StorageType()==KStorageTypeText)  // restore from text stream
+				{
+				// restore text from contacts table.
+				TPtrC textPtr;
+				if(textPtr.Length())
+					{
+					field->TextStorage()->SetTextL(textPtr);
+					}
+				else
+					{
+					field->RestoreTextL(aTextBuf,textFieldIndex);
+					}
+
+                if (aTemplate)
+                    {
+                    AddL(*field);
+                    }
+                else
+                    {
+                    iFields->AppendL(field);
+                    }
+
+				CleanupStack::Pop(field);
+				textFieldIndex++;
+				}
+			else if (aBlobStore)
+				{
+				field->RestoreDataL(*aBlobStore, nestedId);
+
+                if (aTemplate)
+                    {
+                    AddL(*field);
+                    }
+                else
+                    {
+                    iFields->AppendL(field);
+                    }
+
+				CleanupStack::Pop(field);
+				}
+			else
+				{
+				CleanupStack::PopAndDestroy(field);
+				}
+			}
+		}
+	CleanupStack::PopAndDestroy(&stream); 
+    }
+
+
+
+EXPORT_C void CContactItemFieldSet::UpdateFieldL(const CContactItemField &aField, TInt aMatchCount)
+/** Updates a field in the field set. The field whose content type matches aField's 
+content type is replaced by aField. The second parameter is used to identify 
+which matching field is updated. Specify 1 to update the first matching field, 
+2 for the second and so on. If there is no field in the field set which matches 
+aField's content type, then aField is appended to the field set.
+
+@param aField The new field information.
+@param aMatchCount Identifies which matching field in the field set should 
+be updated. */
+	{
+	const CContentType &newContentType=aField.ContentType();
+	TInt fieldPos=0;
+	for(;fieldPos<iFields->Count();fieldPos++)
+		{
+		if (newContentType==(*iFields)[fieldPos]->ContentType())
+			{
+			--aMatchCount;
+			if (aMatchCount==0)
+				{
+				Remove(fieldPos); 
+				break;
+				}
+			}
+		}
+	if (aField.Storage()->IsFull())
+		{
+		CContactItemField* field=CContactItemField::NewLC(aField);
+		InsertL(fieldPos,*field);
+		CleanupStack::Pop();	// field
+		}
+	}
+
+
+EXPORT_C void CContactItemFieldSet::UpdateFieldSyncL(const CContactItemField& aField, TInt aMatchCount)
+/**
+ *  Updates a field in the field set. 
+ *  Searches the set for a matching field. Deletes the matching set's field if any.
+ *  Adds the aField to the set anyway.
+ *  Uses the IsEqualForSyncUpdate() function to compare two CContentType objects,
+ *  rather than the default equals operator.
+ *  Takes care to hold the PREF, VoiceDial, and SpeedDial properties in the updated field.  
+ *
+ *  @param aField Specifies both the type of the field to update and the updated field's value.
+ *  @param aMatchCount Gives the offset of the matching field to update in the order of the set
+ *          (i.e. 1, means update the first matching field in the set;
+ *                2, means update the second matching field in the set).
+ */
+	{
+	TBool mustAddFieldTypePREF=EFalse;
+	TBool mustAddFieldTypeVoiceDial=EFalse;
+	TUid voiceDialUid=KNullUid;
+		
+	const CContentType& newContentType=aField.ContentType();
+	TInt fieldPos=0;
+	for(;fieldPos<iFields->Count();fieldPos++)
+		{
+		if ((*iFields)[fieldPos]->ContentType().IsEqualForSyncUpdate(newContentType))
+			{
+			--aMatchCount;
+			if (aMatchCount==0)
+				{
+				const CContentType& contentType=(*iFields)[fieldPos]->ContentType(); 
+
+				if (contentType.Mapping().iUid==KIntContactFieldVCardMapTEL)
+					{
+					for(TInt loop=0;loop<contentType.FieldTypeCount();loop++)
+						{
+						if (contentType.FieldType(loop).iUid>=KUidSpeedDialOneValue && contentType.FieldType(loop).iUid<=KUidSpeedDialNineValue)
+							{
+							voiceDialUid.iUid=contentType.FieldType(loop).iUid;
+							break; //only one speed dial property allowed for a field
+							}
+						}
+					
+					if (contentType.ContainsFieldType(KUidContactsVoiceDialField))
+						{
+						mustAddFieldTypeVoiceDial=ETrue;
+						}
+					}
+
+				if (contentType.ContainsFieldType(KUidContactFieldVCardMapPREF) && !newContentType.ContainsFieldType(KUidContactFieldVCardMapPREF))
+					{
+					mustAddFieldTypePREF=ETrue;
+					}	
+				break;
+				}
+			}
+		}
+	if (aField.Storage()->IsFull())
+		{
+		if( fieldPos<iFields->Count() )
+			{
+			Remove(fieldPos);//if updating with full field, then remove old field first
+			}
+		CContactItemField* field=CContactItemField::NewLC(aField);
+		if (mustAddFieldTypePREF)
+			{
+			field->AddFieldTypeL(KUidContactFieldVCardMapPREF);
+			}
+
+		if (mustAddFieldTypeVoiceDial)
+			{
+			field->AddFieldTypeL(KUidContactsVoiceDialField);
+			}
+
+		if (voiceDialUid!=KNullUid)
+			{
+			field->AddFieldTypeL(voiceDialUid);
+			}
+
+		InsertL(fieldPos,*field);
+		CleanupStack::Pop(field);	
+		}
+	else if( fieldPos < iFields->Count() )
+		{
+		(*iFields)[fieldPos]->ResetStore();//if updating with empty field, just reset the field
+		}
+	}
+
+
+
+TInt CContactItemFieldSet::FieldText(TFieldType aFieldType, TDes  &aText, TInt aStartPosition) const
+	{
+	TInt fieldPos=FindNext(aFieldType, aStartPosition);
+	if (fieldPos!=KErrNotFound)
+		(*iFields)[fieldPos]->GetFieldText(aText);
+	return fieldPos;
+	}
+
+/** Get the first non-empty text field*/
+void CContactItemFieldSet::NonZeroFieldText(TFieldType aFieldType, TDes &aText) const
+	{
+	TInt fieldPos=-1;
+	do
+		{
+		fieldPos=FindNext(aFieldType,fieldPos+1);
+		if (fieldPos==KErrNotFound)
+			break;
+		(*iFields)[fieldPos]->GetFieldText(aText);
+		} while(aText.Length()==0);
+	}
+
+
+/** 
+Part of the system template update implementation. 
+This could be used for a generic update method at a later stage.
+@since 7.0
+@internalTechnology
+*/
+CArrayFix<TFieldHeader>* CContactItemFieldSet::ConstructFieldHeaderArrayLC(RWriteStream& aTextStream, CStreamStore& aBlobStore)
+	{
+	CArrayFix<TFieldHeader>* retval = new(ELeave) CArrayFixFlat<TFieldHeader>(5);
+	CleanupStack::PushL(retval);
+	CContactItemField* field = NULL;
+	TPtrC textPointer;
+	HBufC* buffer = NULL;
+	TInt counter = 0;
+	TInt maxFields = 0;
+	TInt textFieldIndex = 0;
+
+	maxFields = Count();
+	for (counter=0;counter < maxFields; counter++)
+		{
+		field = (*iFields)[counter];
+		if (!field->IsDeleted() )
+			{
+			if (field->StorageType()==KStorageTypeText)
+				{
+				textPointer.Set(field->TextStorage()->Text());
+				buffer = textPointer.AllocLC();
+				} // if
+
+			retval->AppendL(field->StoreL(aTextStream,aBlobStore,textFieldIndex));
+
+			if (buffer && buffer->Length() > 0 )
+				{
+				field->TextStorage()->SetTextL(*buffer);
+				}
+
+			if (buffer)
+				{
+				CleanupStack::PopAndDestroy(buffer);
+				buffer = NULL;
+				}
+
+			if (field->StorageType()==KStorageTypeText)
+				{
+				textFieldIndex++;
+				}
+			}//if
+		} // for
+
+	return retval;
+	}
+
+
+
+/*
+ * Iterate through the fields.
+ * If the current field matches the field we are inserting from the template 
+ * return the position of the match. 
+ * 
+ * @param aSystemTemplateFields System template fieldset
+ * @param aStartIndex Field to start from
+ * @param aField Template field
+ * @return KErrNotFound, if no field matching the template field in the fieldset, 
+ * else returns position of match in fieldset
+ */
+
+TInt CContactItemFieldSet::FieldTypeCount(const CContactItemFieldSet& aSystemTemplateFields, TInt aStartIndex, const CContactItemField& aField) const
+	{
+	const TInt fieldSetCount = Count();
+	for (TInt ii=aStartIndex;ii<fieldSetCount;ii++)
+		{
+		const CContactItemField& field=*((*iFields)[ii]);
+		TInt tfId = field.TemplateFieldId();
+		if(tfId==KNullFieldId)
+			{
+			if (field.ContentType()==aField.ContentType())
+				return(ii);
+			}
+		else
+			{
+			const CContactItemField* sysField=aSystemTemplateFields.FindById(tfId);
+			if (sysField->ContentType()==aField.ContentType())
+   				return(ii);
+			}
+		}		
+	return KErrNotFound;
+	}
+	
+void CContactItemFieldSet::InternalizeL(RReadStream& aStream)
+/** Internalises a CContactItemFieldSet object from a read stream. 
+@param aStream Stream from which the object should be internalised. */
+	{
+	TInt fieldCount = aStream.ReadInt32L(); // Number of fields.	
+	
+	for(TInt index=0; index<fieldCount; ++index)
+		{
+		CContactItemField* currentField = CContactItemField::NewLC();	
+		currentField->InternalizeL(aStream);	
+		iFields->AppendL(currentField);
+		CleanupStack::Pop(currentField);	
+		}
+
+	}
+
+void CContactItemFieldSet::ExternalizeL(RWriteStream& aStream) const 
+/** Externalises a CContactItemFieldSet object to a write stream.
+@param aStream Stream to which the object should be externalised. */
+	{
+	TInt fieldCount = Count(); // Number of fields.
+	aStream.WriteInt32L(fieldCount);	
+	for(TInt index=0; index<fieldCount; ++index)
+		{
+			(*iFields)[index]->ExternalizeL(aStream);
+			
+		}
+	}		
+
+
+/*
+ * Constructor. 
+ * This is marked as private because CContactItem is an abstract base class.
+ */
+CContactItem::CContactItem()
+	{
+	}
+
+/** Constructs a new contact item based on a RReadStream.
+@param aStream RReadStream containing object to internalize.
+@return Pointer to the newly created CContactItem. This is left on the cleanup stack. 
+@internalTechnology 
+*/	
+CContactItem* CContactItem::NewLC(RReadStream& aStream)
+	{ // static
+	TUid ContactItemType;
+	ContactItemType.iUid = aStream.ReadInt32L();
+
+	CContactItem* item = NewLC(ContactItemType);
+	item->InternalizeL(aStream);
+	
+	return item;
+	}	
+	
+/** Constructs a new contact item.
+
+@return Pointer to the newly created CContactItem. This is left on the cleanup stack. 
+@internalTechnology 
+*/
+EXPORT_C CContactItem* CContactItem::NewLC(TUid aType)
+	{ // static
+	CContactItem* item=NULL;
+		
+	switch(aType.iUid)
+		{
+		case KUidContactCardValue:
+			item = CContactCard::NewLC();
+			break;
+			
+		case KUidContactGroupValue:
+			item = CContactGroup::NewLC();
+			break;
+						
+		case KUidContactOwnCardValue:
+			item = CContactOwnCard::NewLC();
+			break;
+			
+		case KUidContactICCEntryValue:
+			item=CContactICCEntry::NewL();
+			CleanupStack::PushL(item);
+			break;
+
+		case KUidContactTemplateValue:
+			item = CContactTemplate::NewLC();
+			break;												
+			
+		case KUidContactCardTemplateValue:
+			item = CContactCardTemplate::NewLC();
+			break;	
+			
+		default:
+			User::Leave(KErrNotSupported);
+			break;																
+		
+		}		
+		
+	return item;
+	}			
+
+/*
+ * Second-phase construction.
+ * Set template ID on which this contact item is based as KNullContactId.
+ */
+void CContactItem::ConstructL()
+	{
+	iFieldSet=CContactItemFieldSet::NewL();
+	SetTemplateRefId(KNullContactId);
+	}
+
+/*
+ * Second-phase construction overload.
+ */
+void CContactItem::ConstructL(const CContactItem* aTemplate)
+	{
+	ConstructL();
+
+	const TUid type = Type();
+	if (type==KUidContactCardTemplate || type==KUidContactOwnCard || type==KUidContactGroup)
+		{
+		SetTemplateRefId(KNullContactId);
+		}
+	else if (aTemplate->TemplateRefId()==KNullContactId) // can only be template
+		{//record the contacts template
+		SetTemplateRefId(aTemplate->Id());
+		}
+
+	const CContactItemFieldSet& fieldSet=aTemplate->CardFields();
+	const TInt fieldCount = fieldSet.Count();
+	for(TInt loop=0;loop<fieldCount;loop++)
+		{
+		const CContactItemField& templateField=fieldSet[loop];
+		if (!templateField.IsTemplateLabelField())
+			{
+			CContactItemField* field=CContactItemField::NewLC(templateField);
+			AddFieldL(*field);
+			CleanupStack::Pop(field);	
+			field->CopyStorageL(templateField);
+			}
+		}
+	}
+
+EXPORT_C CContactItem::~CContactItem()
+/** The destructor frees all resources owned by the contact item, prior to its 
+destruction. */
+	{
+	delete iFieldSet;
+	delete iGuid;
+	}
+
+EXPORT_C TContactItemId CContactItem::Id() const
+/** Gets the contact item's ID.
+
+@return The contact item's ID. */
+	{
+	return iId;
+	}
+	
+/**
+Sets the contact item's ID.
+
+@internalTechnology
+@released
+*/	
+EXPORT_C void CContactItem::SetId(TContactItemId aId)
+	{
+	iId = aId;
+	}
+	
+/**
+Returns the contact item's attributes.
+
+@return contact item's attributes
+
+@internalTechnology
+@released
+*/		
+EXPORT_C TUint32 CContactItem::Attributes() const
+	{
+	return iAttributes;	
+	}
+
+/**
+Sest the contact item's attributes.
+
+@internalTechnology
+@released
+*/			
+EXPORT_C void CContactItem::SetAttributes(TUint32 aAttributes)
+	{
+	iAttributes = aAttributes;	
+	}
+	
+/**
+Sest the contact item's access count.
+
+@internalTechnology
+@released
+*/				
+EXPORT_C void CContactItem::SetAccessCount(TUint32 aAccessCount)
+	{
+	iAccessCount = aAccessCount;	
+	}
+	
+/**
+Sest the contact item's creation time.
+
+@internalTechnology
+@released
+*/				
+EXPORT_C void CContactItem::SetCreationDate(const TTime& aTime)
+	{
+	iCreationDate = aTime.Int64();	
+	}
+	
+EXPORT_C TContactItemId CContactItem::TemplateRefId() const
+/** Gets the ID of the template which was used to create this contact item.
+
+@return The ID of the template on which this item is based. KNullContactId 
+if the item is not based on a template. */
+	{
+	return iTemplateRefId;
+	}
+
+EXPORT_C TTime CContactItem::LastModified() const
+/** Gets the contact item's last modified date/time.
+
+@return The contact item's last modified date/time. */
+	{
+	return iLastModified;
+	}
+
+EXPORT_C void CContactItem::SetLastModified(const TTime& aLastModified)
+/** Sets the last modified date/time value stored in the local copy of the contact 
+item. This value is returned by LastModified() for this copy of the item.
+
+This function has no effect on the item's last modified date/time which is 
+stored in the database; this is always the date/time the contact was last 
+committed.
+
+This function is provided for use when synchronising 
+contact items.
+
+@param aLastModified The contact item's last modified date/time. */
+	{
+	iLastModified=aLastModified.Int64();
+	}
+
+EXPORT_C void CContactItem::SetHidden(TBool aHidden)
+/** Sets the contact item's hidden attribute. Hidden means that the item is not 
+displayed if the view definition excludes hidden fields.
+
+@param aHidden ETrue to set the hidden attribute for the item, EFalse to unset 
+it. */
+    	{
+    	if (aHidden)
+    		iAttributes|=EHidden;
+    	else
+    		iAttributes&=~EHidden;
+    	} 
+EXPORT_C void CContactItem::SetSystem(TBool aSystem)
+/** Sets the contact item's system attribute. Note that the system attribute is 
+not currently used in the contacts model.
+
+@param aSystem ETrue to set the system attribute, EFalse to unset it. */
+    	{
+    	if (aSystem)
+    		iAttributes|=ESystem;
+    	else
+    		iAttributes&=~ESystem;
+    	}
+
+EXPORT_C void CContactItem::SetDeleted(TBool aDeleted)
+/** Sets the value of the contact item's Is deleted attribute.
+
+If the attribute is set, this means that an attempt has been made to delete 
+the contact item, but because the item's access count is greater than zero, 
+its data persists and the item is just marked as deleted.
+
+@param aDeleted ETrue to set the Is deleted attribute. EFalse to unset it. */
+    	{
+    	if (aDeleted)
+    		iAttributes|=EDeleted;
+    	else
+    		iAttributes&=~EDeleted;
+    	}
+
+EXPORT_C TBool CContactItem::IsHidden() 
+/** Gets the value of the contact item's hidden attribute. Hidden means that the 
+item is not displayed if the view definition excludes hidden fields.
+
+@return ETrue if hidden, EFalse if not. */
+	{ return iAttributes&EHidden; }
+
+EXPORT_C TBool CContactItem::IsSystem() 
+/** Gets the value of the contact item's system attribute. Note that the system 
+attribute is not currently used in the contacts model.
+
+@return ETrue if system, EFalse if not. */
+	{ return iAttributes&ESystem; }
+
+EXPORT_C TBool CContactItem::IsDeleted()  const
+/** Gets the value of the Is deleted attribute as set by SetDeleted().
+
+@return ETrue if deleted, EFalse if not. */
+	{ return iAttributes&EDeleted; }
+
+EXPORT_C void CContactItem::SetTemplateRefId(TContactItemId aUid)
+/** Sets the ID of the template on which this contact item is based.
+
+@param aUid The ID of the template on which this item is based. */
+	{
+	iTemplateRefId=aUid;
+	}
+
+EXPORT_C void CContactItem::AddFieldL(CContactItemField& aField)
+/** Appends a field to the contact item's field set. The contact item takes ownership 
+of the field.
+
+@param aField The field to append to the contact item's field set. */
+	{
+	__ASSERT_DEBUG(&aField!=NULL,Panic(ECntPanicNullPointer));
+	if (this->Type()==KUidContactCardTemplate)
+		aField.SetTemplateField(ETrue);
+	else 
+		aField.SetTemplateField(EFalse);
+	iFieldSet->AddL(aField);
+	}
+
+EXPORT_C void CContactItem::RemoveField(TInt aFieldPos)
+/** Removes a field from the contact item's field set. A panic occurs if the specified 
+field does not exist in the field set.
+
+@param aFieldPos Index within the field set of the field to remove. */
+	{
+	if (!(*iFieldSet)[aFieldPos].IsTemplateLabelField())
+		iFieldSet->Remove(aFieldPos);
+	}
+
+EXPORT_C void CContactItem::InsertFieldL(CContactItemField& aField,TInt aFieldPos)
+/** Inserts a field into the contact item's field set. The contact item takes ownership 
+of the field.
+
+@param aField The field to insert into the contact item's field set.
+@param aFieldPos The position in the field set at which to insert the field. 
+If this value is greater than the total number of fields, it is appended. 
+The position is relative to zero, i.e. zero implies that the element is inserted 
+at the beginning of the array. */
+	{
+	if (this->Type()==KUidContactCardTemplate)
+		aField.SetTemplateField(ETrue);
+	iFieldSet->InsertL(aFieldPos,aField);
+	}
+
+EXPORT_C void CContactItem::UpdateFieldSet(CContactItemFieldSet* aNewFieldSet)
+/** Replaces the contact item's field set.
+
+@param aNewFieldSet The new field set with which to replace the existing one. */
+	{
+	delete iFieldSet;
+	iFieldSet = NULL;
+	iFieldSet=aNewFieldSet;
+	}
+
+TContactItemId  CContactItem::Agent()
+	{
+	TContactItemId fieldindex=iFieldSet->FindNext(KUidContactFieldMatchAll,KUidContactFieldVCardMapAGENT);
+	if (fieldindex!=KErrNotFound)
+		return(TContactItemId(
+		(*iFieldSet)[fieldindex].AgentStorage()->Value()));
+	else
+		return KNullContactId;
+	}
+
+EXPORT_C CContactItemFieldSet& CContactItem::CardFields() const
+/** Gets a reference to the contact item's field set.
+
+@return A reference to the contact item's field set. */
+	{
+	return *iFieldSet;
+	}
+
+
+EXPORT_C void CContactItem::SetUidStringL(TDesC& aString) 
+/** Sets the item's UID string. This replaces any existing string. Contact items have 
+a globally unique identifier, stored as a descriptor which is provided for 
+vCard support. It is a combination of the database's unique identifier (see 
+CContactDatabase::MachineId()), the contact item ID and the date/time of the 
+contact item's creation.
+
+@param aString The contact item's UID string. */
+	{
+	HBufC* guid=aString.AllocL();
+	if (iGuid)
+		delete iGuid;
+	iGuid=guid;
+	}
+
+EXPORT_C TPtrC CContactItem::UidStringL(TInt64 aMachineUniqueId) const
+/** Returns a descriptor which contains the item's UID string. Contact items have 
+a globally unique identifier, stored as a descriptor. This is provided for 
+vCard support. It is a combination of the database's unique identifier, the 
+contact item ID and the date/time of the contact item's creation.
+
+@param aMachineUniqueId The database's unique identifier. This can be retrieved 
+using CContactDatabase::MachineId().
+@return The item's UID string. */
+	{
+    TPtrC guid;
+	if (iGuid)
+		{
+		if (GuidIsCompressed())
+			CONST_CAST(CContactItem &,*this).MakeUidStringL(aMachineUniqueId);  
+		guid.Set(*iGuid);
+		}
+    return guid;
+	}
+
+void CContactItem::MakeUidStringL(TInt64 aMachineUniqueId) 
+	{
+	HBufC* guid = NULL;
+	if (iGuid->Length())
+		guid=ContactGuid::CreateGuidLC(iGuid->Des(),iId,aMachineUniqueId); // pass creation time
+	else
+		guid=ContactGuid::CreateGuidLC(iId, aMachineUniqueId);
+	delete iGuid;
+	iGuid=guid;
+	iAttributes&=~(ECompressedGuid);
+	CleanupStack::Pop(); // iGuid
+	}
+
+/**
+@internalTechnology 
+*/
+EXPORT_C void CContactItem::SetHasCompressedGuid(TBool aCompressed)
+	{
+	if (aCompressed)
+		iAttributes|=ECompressedGuid;
+	else
+		iAttributes&=~(ECompressedGuid);
+	}
+
+
+TBool CContactItem::GuidIsCompressed() const
+	{return iAttributes&ECompressedGuid;}
+
+
+
+/** 
+Part of the system template update implementation. 
+This could be used for a generic update method at a later stage.
+@since 7.0
+@internalTechnology
+*/
+TInt CContactItem::NumberOfFieldsToStore() const
+	{
+	TInt retval = 0, counter = 0;
+	const TInt max = iFieldSet->Count();
+	for (counter = 0; counter < max; counter++)
+		{
+		if ( !   (*iFieldSet)[counter].IsDeleted() ) retval++;
+		}
+	return retval;
+	}
+
+/** 
+Part of the system template update implementation. 
+This could be used for a generic update method at a later stage.
+@since 7.0
+@internalTechnology
+*/
+TStreamId CContactItem::PopulateStoreL(CStreamStore& aStore, CArrayFix<TFieldHeader>& aFieldHeaderArray) const
+	{
+	RStoreWriteStream rootStream;
+	TInt counter = 0;
+	TStreamId streamId = rootStream.CreateLC(aStore);
+	const TInt hintCount = aFieldHeaderArray.Count();
+
+	rootStream <<TCardinality(NumberOfFieldsToStore());
+
+	for (counter = 0;counter < hintCount; counter++)
+		{
+		(*iFieldSet)[counter].PopulateStoreL(rootStream, counter, aFieldHeaderArray);
+		}
+	rootStream.CommitL();
+	aStore.CommitL();
+	CleanupStack::PopAndDestroy(&rootStream); 
+	return streamId;
+	}
+
+
+void CContactItem::AddLabelFieldL()
+	{
+	TInt pos = iFieldSet->Find(KUidContactFieldTemplateLabel);
+	if (pos==KErrNotFound)	// !HasItemLabelField()
+		{
+		CContactItemField* labelField = CContactItemField::NewLC(KStorageTypeText);
+		labelField->AddFieldTypeL(KUidContactFieldTemplateLabel);
+		if (Type()==KUidContactGroup)
+			{
+			_LIT(KGroupLabel,"Group Label");
+			labelField->SetLabelL(KGroupLabel);
+			}
+		else if (Type()==KUidContactCardTemplate)
+			{
+			_LIT(KTemplateLabel,"Template Label");
+			labelField->SetLabelL(KTemplateLabel);
+			}
+	// field needs to be first in the list
+	// bug in stream retrieval of fields
+		InsertFieldL(*labelField,0);
+		CleanupStack::Pop(); // labelField
+		}
+	else	if (pos!=0)
+		{
+		iFieldSet->Move(pos,0);
+		}
+	}
+
+
+/**
+ Restore fields from the template to the contact item.
+@param aTemplateFields Fields to add
+@param aViewDef View definition to use
+@internalTechnology 
+ */
+EXPORT_C void CContactItem::RestoreTemplateFieldsL(const CContactItemFieldSet& aSystemTemplateFields, const CContactItemFieldSet& aTemplateFields, const CContactItemViewDef& aViewDef)
+	{
+	TInt insertPos=0;
+	const TInt templateFieldCount=aTemplateFields.Count();
+	for (TInt ii=0;ii<templateFieldCount;ii++)
+		{
+		const CContactItemField& templateField=aTemplateFields[ii];
+		TInt fieldPos=iFieldSet->FieldTypeCount(aSystemTemplateFields, insertPos, templateField);
+		if (fieldPos<0 && ((aViewDef.Mode()==CContactItemViewDef::EMaskHiddenFields && !templateField.IsHidden())
+						|| (aViewDef.Mode()==CContactItemViewDef::EIncludeHiddenFields))
+						&& (!templateField.ContentType().ContainsFieldType(KUidContactFieldTemplateLabel)))
+			{
+			CContactItemField* field = CContactItemField::NewLC(templateField);
+			field->SetTemplateField(EFalse); //make sure it isn't set as a template field
+			field->SetOverRidesLabel(EFalse);
+			iFieldSet->InsertL(insertPos++,*field);
+			CleanupStack::Pop(field); 
+			}
+		else 
+			{
+			while(fieldPos>=0)
+				{
+				iFieldSet->Move(fieldPos,insertPos++); //move the field to the correct position
+				fieldPos=iFieldSet->FieldTypeCount(aSystemTemplateFields, insertPos, templateField);
+				}
+			}
+		}
+	}
+
+
+
+void CContactItem::ClearFieldContent()
+	{	
+	for (TInt i=0;i<iFieldSet->Count();i++)
+		{
+		CContactItemField& field=(*iFieldSet)[i];
+		if (!field.IsTemplateLabelField())
+			field.ResetStore();
+		}
+	}	
+	
+void CContactItem::InternalizeL(RReadStream& aStream)
+/** Internalises a CContactItem object from a read stream. 
+@param aStream Stream from which the object should be internalised. */
+	{
+	
+	delete iFieldSet;
+	iFieldSet = NULL;
+	iFieldSet=CContactItemFieldSet::NewL();
+	iFieldSet->InternalizeL(aStream);
+	
+	iAttributes = aStream.ReadUint32L();
+	
+	iId = aStream.ReadInt32L();
+	
+	iTemplateRefId = aStream.ReadInt32L();
+	
+	TInt64 tempInt64;
+	aStream >> tempInt64;
+	iLastModified = TTime(tempInt64);	
+	
+	aStream >> tempInt64;
+	iCreationDate = TTime(tempInt64);	
+		
+	iAccessCount = aStream.ReadUint32L();
+	
+	if (iGuid)
+		{
+		delete iGuid;		
+		iGuid = NULL;
+		}
+
+	const TInt length=aStream.ReadInt32L();
+	if (length)
+		{
+		iGuid=HBufC::NewL(aStream,length);	
+		}	
+				
+	}
+
+void CContactItem::ExternalizeL(RWriteStream& aStream) const 
+/** Externalises a CContactItem object to a write stream.
+@param aStream Stream to which the object should be externalised. */
+	{
+	aStream.WriteInt32L(Type().iUid);
+		
+	iFieldSet->ExternalizeL(aStream);
+	
+	aStream.WriteUint32L(iAttributes);
+	
+	aStream.WriteInt32L(iId);
+	
+	aStream.WriteInt32L(iTemplateRefId);
+	
+	aStream << iLastModified.Int64();
+	
+	aStream << iCreationDate.Int64();
+		
+	aStream.WriteUint32L(iAccessCount);
+	
+	if(iGuid)
+		{
+		
+		const TInt length=iGuid->Length();
+		aStream.WriteInt32L(length);	
+		if (length)
+			{		
+			aStream << *(iGuid);
+			}
+		}
+	else
+		{
+		aStream.WriteInt32L(0);
+		}
+		
+	}		
+
+
+//
+// class CContactCardTemplate
+//
+
+EXPORT_C CContactCardTemplate* CContactCardTemplate::NewL()
+	{ // static
+	/** Allocates and constructs a new Contact Card Template .
+	@return Pointer to the newly created Contact Card Template.     */
+	CContactCardTemplate* card=CContactCardTemplate::NewLC();
+	CleanupStack::Pop(); // card
+	return card;
+	}
+
+EXPORT_C CContactCardTemplate* CContactCardTemplate::NewLC()
+	{ // static
+	/** Allocates and constructs a new Contact Card Template .
+	@return  Pointer to the newly created Contact Card Template. This is left on the cleanup stack. */
+	CContactCardTemplate* card=new(ELeave) CContactCardTemplate;
+	CleanupStack::PushL(card);
+	card->ConstructL();
+	return card;
+	}
+
+EXPORT_C CContactCardTemplate* CContactCardTemplate::NewL(const CContactItem *aTemplate)
+	{
+    /** Allocates and constructs a new Contact Card Template .
+	@param aTemplate Pointer to the template whose field set and field data are copied into the new contact card template
+	@return Pointer to the newly created Contact Card Template.      */   
+	
+	CContactCardTemplate* card=CContactCardTemplate::NewLC(aTemplate);
+	CleanupStack::Pop(); // card
+	return card;
+	}
+
+EXPORT_C CContactCardTemplate* CContactCardTemplate::NewLC(const CContactItem *aTemplate)
+	{ // static
+    /** Allocates and constructs a new Contact Card Template .
+	@param aTemplate Pointer to the template whose field set and field data are copied into the new contact card template 
+	@return  Pointer to the newly created Contact Card Template. This is left on the cleanup stack. */
+	
+	CContactCardTemplate* card=new(ELeave) CContactCardTemplate;
+	CleanupStack::PushL(card);
+	card->ConstructL(aTemplate);
+	return card;
+	}
+
+EXPORT_C void CContactCardTemplate::SetTemplateLabelL(const TDesC& aLabel)
+/** Changes the label for a contact card template. The label is initialised when 
+the template is created. The template label is stored in a text field in the 
+template. This field has a unique content type mapping of KUidContactFieldTemplateLabel. 
+By default, this field is the first field in the field set; it must not be 
+moved from this position.
+
+@param aLabel The new template label.
+@leave KErrNotFound Indicates there is no template label field in the template. */
+	{
+	CContactItemFieldSet& labelFields = this->CardFields();
+	// find label field
+	TInt pos = labelFields.Find(KUidContactFieldTemplateLabel);
+	if (pos==KErrNotFound)
+		User::Leave(pos);
+	labelFields[pos].TextStorage()->SetTextL(aLabel);
+	}		
+
+EXPORT_C TPtrC CContactCardTemplate::GetTemplateLabelL()
+/** Gets the label for a contact card template.
+
+@leave KErrNotFound Indicates there is no template label field in the template. 
+
+@return The template label. */
+	{
+	CContactItemFieldSet& labelFields = this->CardFields();
+	// find 
+	TInt pos = labelFields.Find(KUidContactFieldTemplateLabel);
+	if (pos==KErrNotFound)
+		User::Leave(pos);
+	return(labelFields[pos].TextStorage()->Text());
+	}
+
+EXPORT_C TBool CContactCardTemplate::HasItemLabelField()
+	{
+/** Tests whether a Template label field is present.
+@return ETrue if Template Label Field is present, EFalse otherwise.  */
+	CContactItemFieldSet& labelFields = this->CardFields();
+	TInt pos = labelFields.Find(KUidContactFieldTemplateLabel);
+	if (pos==KErrNotFound)
+		return EFalse;
+	return ETrue;
+	}
+
+EXPORT_C TUid CContactCardTemplate::Type() const
+	{
+	return KUidContactCardTemplate;
+	}
+
+CContactCardTemplate::CContactCardTemplate()
+	{
+	}
+
+//
+// CContactItemPlusGroup
+//
+
+/**
+@internalComponent
+*/
+CContactItemPlusGroup::CContactItemPlusGroup()
+	{}
+
+EXPORT_C CContactItemPlusGroup::~CContactItemPlusGroup()
+/** 
+Frees the array of group IDs to which the derived class object 
+belongs.
+Frees the array of contact item IDs which identify the groups to 
+which the derived class object belongs, prior to its destruction. */
+
+	{
+	delete iGroups;
+	}
+
+EXPORT_C const CContactIdArray* CContactItemPlusGroup::GroupsJoined() const
+/** Returns a pointer to a list of contact item IDs which identify the groups to 
+which the derived class object belongs.
+
+@return A pointer to the array of groups IDs to which the derived class object 
+belongs. NULL if the object is not a member of any groups. */
+	{
+	return(iGroups);
+	}
+
+EXPORT_C CContactIdArray* CContactItemPlusGroup::GroupsJoinedLC() const
+/** Returns a pointer to a list of contact item IDs which identify the groups to 
+which the derived class object belongs.
+
+@return A pointer to a copy of the array of groups IDs to which the derived 
+class object belongs. This array is empty if the object is not a member of 
+any groups. The caller takes ownership of this object, so is responsible for 
+its deletion. */
+	{
+	CContactIdArray* copy=NULL;
+	if (iGroups)
+		copy=CContactIdArray::NewLC(iGroups);
+	else
+		copy=CContactIdArray::NewLC();
+	return copy;
+	}
+	
+void CContactItemPlusGroup::InternalizeL(RReadStream& aStream)
+/** Internalises a CContactItemPlusGroup object from a read stream. 
+@param aStream Stream from which the object should be internalised. */
+	{
+	// Call Parent InternalizeL to internalize all members.
+	CContactItem::InternalizeL(aStream);
+	
+	if (iGroups)
+		{
+		delete iGroups;		
+		iGroups = NULL;
+		}
+	
+	// TBool CheckIfExists = aStream.ReadInt32L();
+	if (aStream.ReadInt32L())
+		{
+		iGroups = CContactIdArray::NewL();		
+		iGroups->InternalizeL(aStream);
+		}	
+		
+	}
+
+void CContactItemPlusGroup::ExternalizeL(RWriteStream& aStream) const 
+/** Externalises a CContactItemPlusGroup object to a write stream.
+@param aStream Stream to which the object should be externalised. */
+	{	
+	// Call Parent ExternalizeL to externalize all members.
+	CContactItem::ExternalizeL(aStream);
+	if(iGroups)
+		{
+		aStream.WriteInt32L(1);
+		iGroups->ExternalizeL(aStream);
+		}
+	else
+		{
+		aStream.WriteInt32L(0); // Empty group
+		}		
+
+	}		
+
+/**
+Resets groups.
+
+@internalTechnology
+@released
+*/	
+EXPORT_C void CContactItemPlusGroup::ResetGroups()
+	{
+	delete iGroups;
+	iGroups = NULL;	
+	}
+	
+/**
+Sets groups.
+
+@internalTechnology
+@released
+*/		
+EXPORT_C void CContactItemPlusGroup::SetGroups(CContactIdArray* aGroups)
+	{
+	iGroups = aGroups;		
+	}
+
+//
+// class CContactCard
+//
+
+EXPORT_C CContactCard::~CContactCard()
+/** Frees all resources owned by the contact card, prior to its 
+destruction. */
+	{
+	}
+
+EXPORT_C CContactCard* CContactCard::NewL()
+/** Allocates and constructs a new contact card.
+
+@return Pointer to the newly created contact card. */
+	{ // static
+	CContactCard* card=CContactCard::NewLC();
+	CleanupStack::Pop(); // card
+	return card;
+	}
+
+EXPORT_C CContactCard* CContactCard::NewLC()
+/** Allocates and constructs a new contact card.
+
+@return Pointer to the newly created contact card. This is left on the 
+cleanup stack.*/
+	{ // static
+	CContactCard* card=new(ELeave) CContactCard;
+	CleanupStack::PushL(card);
+	card->ConstructL();
+	return card;
+	}
+
+EXPORT_C CContactCard* CContactCard::NewL(const CContactItem *aTemplate)
+/** Allocates and constructs a new contact card whose field set is seeded from 
+a template.
+
+@param aTemplate Pointer to the template whose field set and field data are 
+copied into the new contact card.
+@return Pointer to the newly created contact card. */
+	{
+	CContactCard* card=CContactCard::NewLC(aTemplate);
+	CleanupStack::Pop(); // card
+	return card;
+	}
+
+EXPORT_C CContactCard* CContactCard::NewLC(const CContactItem *aTemplate)
+/** Allocates and constructs a new contact card whose field set is seeded from 
+a template.
+
+@param aTemplate Pointer to the template whose field set and field data are 
+copied into the new contact card.
+@return Pointer to the newly created contact card. This is left on the cleanup stack. */
+	{ // static
+	CContactCard* card=new(ELeave) CContactCard;
+	CleanupStack::PushL(card);
+	card->ConstructL(aTemplate);
+	return card;
+	}
+
+EXPORT_C TUid CContactCard::Type() const
+/** Implements CContactItem::Type().
+
+@return KUidContactCard. */
+	{
+	return KUidContactCard;
+	}
+
+EXPORT_C CContactIdArray* CContactCard::GroupsJoinedLC() const
+/** Returns a pointer to a list of contact item IDs which identify the groups to 
+which this contact card belongs.
+
+@return A pointer to a copy of the array of groups IDs to which this contact 
+card belongs. This array is empty if the card is not a member of any groups. 
+The caller takes ownership of this object, so is responsible for its deletion. */
+	{
+	return(CContactItemPlusGroup::GroupsJoinedLC());
+	}
+
+CContactCard::CContactCard()
+	{
+	}
+
+//
+// class CContactOwnCard
+//
+
+EXPORT_C CContactOwnCard::~CContactOwnCard()
+/** Frees all resources owned by the own card, prior to its destruction. */
+	{
+	}
+
+EXPORT_C CContactOwnCard* CContactOwnCard::NewL()
+/** Allocates and constructs a new own card. 
+
+Note: own cards should normally be constructed using the factory functions provided 
+in class CContactDatabase, for example CreateOwnCardL().
+
+@return Pointer to the newly created own card. */
+	{ // static
+	CContactOwnCard* card=CContactOwnCard::NewLC();
+	CleanupStack::Pop(); // card
+	return card;
+	}
+
+EXPORT_C CContactOwnCard* CContactOwnCard::NewLC()
+/** Allocates and constructs a new own card. 
+
+Note: own cards should normally be constructed using the factory functions provided 
+in class CContactDatabase, for example CreateOwnCardL().
+
+@return Pointer to the newly created own card. This is left on the cleanup stack. */
+	{ // static
+	CContactOwnCard* card=new(ELeave) CContactOwnCard;
+	CleanupStack::PushL(card);
+	card->ConstructL();
+	return card;
+	}
+
+EXPORT_C CContactOwnCard* CContactOwnCard::NewL(const CContactItem *aTemplate)
+/** Allocates and constructs a new own card whose field set is seeded from a template. 
+
+Note: own cards should normally be constructed using the factory functions provided 
+in class CContactDatabase, for example CreateOwnCardL().
+
+@param aTemplate Pointer to the template whose field set and field data are 
+copied into the new own card.
+@return Pointer to the newly created own card. */
+	{
+	CContactOwnCard* card=CContactOwnCard::NewLC(aTemplate);
+	CleanupStack::Pop(); // card
+	return card;
+	}
+
+EXPORT_C CContactOwnCard* CContactOwnCard::NewLC(const CContactItem *aTemplate)
+/** Allocates and constructs a new own card whose field set is seeded from a template. 
+
+Note: own cards should normally be constructed using the factory functions provided 
+in class CContactDatabase, for example CreateOwnCardL().
+
+@param aTemplate Pointer to the template whose field set and field data are 
+copied into the new own card.
+@return Pointer to the newly created own card. This is left on the cleanup stack. */
+	{ // static
+	CContactOwnCard* card=new(ELeave) CContactOwnCard;
+	CleanupStack::PushL(card);
+	card->ConstructL(aTemplate);
+	return card;
+	}
+
+EXPORT_C TUid CContactOwnCard::Type() const
+/** Implements CContactItem::Type(). 
+
+@return KUidContactOwnCard. */
+	{
+	return KUidContactOwnCard;
+	}
+
+EXPORT_C CContactIdArray* CContactOwnCard::GroupsJoinedLC() const
+/** Returns a pointer to a list of contact item IDs which identify the groups to 
+which the current own card belongs.
+
+@return A pointer to a copy of the array of groups IDs to which this own card 
+belongs. This array is empty if the own card is not a member of any groups. 
+The caller takes ownership of this object, so is responsible for its deletion. */
+	{
+	return(CContactItemPlusGroup::GroupsJoinedLC());
+	}
+
+/*
+ * Own card.
+ *
+ * An own card is a contact card which contains information about the
+ * device's owner. This can be sent to another compatible electronic
+ * device as a vCard. The contact database recognises a single own card
+ * referred to as the current own card; its ID is returned by
+ * <code>CContactDatabase::OwnCardId()</code>. Like a contact card, an
+ * own card can be a member of one or more contact card groups. The own
+ * card type is identified by a UID of <code>KUidContactOwnCard</code>,
+ * as returned by <code>Type()</code>.Own cards can be constructed using
+ * either <code>CContactDatabase::CreateOwnCardLC()</code> or
+ * <code>CreateOwnCardL()</code>. These functions create an own card,
+ * based on the system template, add it to the database, set it as the
+ * database's current own card and return a pointer to it. To change the
+ * database's current own card, use
+ * <code>CContactDatabase::SetOwnCardL()</code>.
+ *
+ * @since 5.2
+ */
+CContactOwnCard::CContactOwnCard()
+	{
+	}
+
+//
+// class CContactGroup
+//
+EXPORT_C CContactGroup* CContactGroup::NewL()
+/** Allocates and constructs a new default contact card group. The group has no label and 
+its list of members is NULL.
+
+Contact groups should be constructed using the factory functions provided 
+in class CContactDatabase, for example CreateContactGroupL().
+
+@return Pointer to the new contact card group. */
+	{ // static
+	CContactGroup* group=CContactGroup::NewLC();
+	CleanupStack::Pop();
+	return group;
+	}
+
+EXPORT_C CContactGroup* CContactGroup::NewLC()
+/** Allocates and constructs a new default contact card group.
+
+The group has no label and its list of members is NULL.
+
+Contact groups should be constructed using the factory functions provided 
+in class CContactDatabase, for example CreateContactGroupLC().
+
+@return Pointer to the new contact card group. This is left on the cleanup stack.*/
+	{
+	CContactGroup* group=new(ELeave) CContactGroup;
+	CleanupStack::PushL(group);
+	group->ConstructL();
+	return group;
+	}
+
+CContactGroup::CContactGroup()
+	{
+	}
+
+EXPORT_C CContactGroup::~CContactGroup()
+/** The destructor frees all resources owned by the contact group, prior to its 
+destruction. */
+	{
+	delete iItems;
+	}
+
+EXPORT_C TUid CContactGroup::Type() const
+/** Implements CContactItem::Type(). 
+
+@return KUidContactGroup. */
+	{
+	return KUidContactGroup;
+	}
+
+EXPORT_C CContactIdArray* CContactGroup::ItemsContainedLC() const
+/** Returns a pointer to a copy of the group's list of members.
+
+@return Pointer to a copy of the group's list of members. This is left on 
+the cleanup stack. */
+	{
+	if (iItems)
+		{
+		CContactIdArray* copy = CContactIdArray::NewLC(iItems);
+		return copy;
+		}
+	else
+		{
+		// iItems is NULL
+		CleanupStack::PushL(iItems);
+		return NULL;
+		}
+	}
+
+EXPORT_C const CContactIdArray* CContactGroup::ItemsContained() const
+/** Returns a constant pointer to the group's list of members.
+
+@return Pointer to the group's list of members. */
+	{
+	return iItems;
+	}
+
+EXPORT_C TBool CContactGroup::IsSystem() const
+/** Tests the value of the group's system attribute. 
+
+The system attribute is not currently used in the Contacts Model API.
+
+@return ETrue if system, EFalse if not. */
+	{
+	return iAttributes&ESystem;
+	}
+
+EXPORT_C void CContactGroup::SetSystem(TBool aSystem)
+/** Sets the value of the group's system attribute. 
+
+The system attribute is not currently used in the Contacts Model API.
+
+@param aSystem ETrue to set the system attribute, EFalse to unset it. */
+	{
+	if (aSystem)
+		iAttributes|=ESystem;
+	else
+		iAttributes&=~ESystem;
+	}
+
+EXPORT_C TBool CContactGroup::ContainsItem(TContactItemId aContactId)
+/** Tests whether a contact item is a member of the group.
+
+@param aContactId The ID of the contact item to test.
+@return ETrue if the item is a member of the group, EFalse if not. */
+	{
+	if (iItems && iItems->Count())
+		{
+		TInt index=iItems->Find(aContactId);
+		if (index==KErrNotFound)
+			return EFalse;
+		}
+	else
+		return EFalse;
+	return ETrue;
+	}
+
+EXPORT_C void CContactGroup::SetGroupLabelL(const TDesC& aLabel)
+/** Sets the group label, replacing any existing one.
+
+@param aLabel The new group label.
+@leave KErrNotFound The group has no label field (of type KUidContactFieldTemplateLabel). */
+	{
+	CContactItemFieldSet& labelFields = this->CardFields();
+	// find label field
+	TInt pos = labelFields.Find(KUidContactFieldTemplateLabel);
+	if (pos==KErrNotFound)
+		User::Leave(pos);
+	labelFields[pos].TextStorage()->SetTextL(aLabel);
+	}		
+
+EXPORT_C TPtrC CContactGroup::GetGroupLabelL()
+/** Gets the group label.
+
+@leave KErrNotFound The group has no label field (of type KUidContactFieldTemplateLabel).
+
+@return The new group label. */
+	{
+	CContactItemFieldSet& labelFields = this->CardFields();
+	// find 
+	TInt pos = labelFields.Find(KUidContactFieldTemplateLabel);
+	if (pos==KErrNotFound)
+		User::Leave(pos);
+	return(labelFields[pos].TextStorage()->Text());
+	}
+
+EXPORT_C TBool CContactGroup::HasItemLabelField()
+/** Tests whether the group has a label field (of type KUidContactFieldTemplateLabel).
+
+@return ETrue if the group has a label field. EFalse if not. */
+	{
+	CContactItemFieldSet& labelFields = this->CardFields();
+	TInt pos = labelFields.Find(KUidContactFieldTemplateLabel);
+	if (pos==KErrNotFound)
+		return EFalse;
+	return ETrue;
+	}
+
+EXPORT_C CContactIdArray* CContactGroup::GroupsJoinedLC()const
+/** Returns a pointer to a list of contact groups to which the current group belongs 
+(a contact group can belong to other groups).
+
+@return A pointer to a copy of the array of groups IDs to which this group 
+belongs. This array is empty if the group is not a member of any other groups. 
+The caller takes ownership of this object, so is responsible for its deletion. */
+	{
+	return(CContactItemPlusGroup::GroupsJoinedLC());
+	}
+
+
+/**
+Adds a contact with the given Id to the group. This method doesn't make any changes to the database.
+The change should be persisted by means of CContactDatabase::CommitContactL() API.
+
+@param aContactId The Id of the contact being added to the group.
+@leave KErrAlreadyExists The contact is already a member of this group.
+
+@internalTechnology
+*/
+EXPORT_C void CContactGroup::AddContactL(TContactItemId aContactId)
+	{
+	if (!iItems)
+		{
+		iItems = CContactIdArray::NewL(); //No need to push on the stack because it is a member
+		}
+	if (iItems->Find(aContactId) == KErrNotFound)
+		{
+		iItems->AddL(aContactId);
+		}
+	else
+		{
+		User::Leave(KErrAlreadyExists);
+		}
+	}
+
+/**
+Removes a contact with the given Id from the group. This method doesn't make any changes to the database.
+The change should be persisted by means of CContactDatabase::CommitContactL() API.
+
+@param aContactId The Id of the contact being removed from the group.
+@leave KErrNotFound The contact is not a member of this group.
+
+@internalTechnology
+*/
+EXPORT_C void CContactGroup::RemoveContactL(TContactItemId aContactId)
+	{
+	TInt arrIndex(0);
+	if (!iItems || KErrNotFound == (arrIndex = iItems->Find(aContactId)))
+		{ //If array is empty of the contact ID is not found
+		User::Leave(KErrNotFound);
+		}
+	iItems->Remove(arrIndex);
+	}
+
+void CContactGroup::InternalizeL(RReadStream& aStream)
+/** Internalises a CContactGroup object from a read stream. 
+@param aStream Stream from which the object should be internalised. */
+	{
+	// Call Parent InternalizeL to internalize all members.
+	CContactItemPlusGroup::InternalizeL(aStream);
+		
+	if (iItems)
+		{
+		delete iItems;
+		iItems = NULL;		
+		}
+
+	const TBool iItemsExists=aStream.ReadInt32L();
+	if (iItemsExists)
+		{
+		iItems = CContactIdArray::NewL();
+		iItems->InternalizeL(aStream);		
+		}	
+						
+	}
+
+void CContactGroup::ExternalizeL(RWriteStream& aStream) const 
+/** Externalises a CContactGroup object to a write stream.
+@param aStream Stream to which the object should be externalised. */
+	{
+	// Call Parent ExternalizeL to externalize all members.
+	CContactItemPlusGroup::ExternalizeL(aStream);
+
+	if(iItems)
+		{
+		aStream.WriteInt32L(1);
+		iItems->ExternalizeL(aStream);
+		}
+		
+	else
+		{
+		aStream.WriteInt32L(0);
+		}	
+	}	
+	
+/**
+Resets items.
+
+@internalTechnology
+@released
+*/	
+EXPORT_C void CContactGroup::ResetItems()
+	{
+	delete iItems;
+	iItems = NULL;	
+	}
+	
+/**
+Sets groups.
+
+@internalTechnology
+@released
+*/		
+EXPORT_C void CContactGroup::SetItems(CContactIdArray* aItems)
+	{
+	iItems = aItems;		
+	}
+	
+//
+// class CContactTemplate
+//
+
+EXPORT_C CContactTemplate* CContactTemplate::NewL()
+/** Allocates and constructs a new default system template.
+
+@return Pointer to the newly created system template. */
+	{ // static
+	CContactTemplate* item=CContactTemplate::NewLC();
+	CleanupStack::Pop(); // item
+	return item;
+	}
+
+EXPORT_C CContactTemplate* CContactTemplate::NewLC()
+/** Allocates and constructs a new default system template.
+
+@return Pointer to the newly created system template. This is left on the cleanup stack.*/
+	{ // static
+	CContactTemplate* item=new(ELeave) CContactTemplate;
+	CleanupStack::PushL(item);
+	item->ConstructL();
+	return item;
+	}
+
+EXPORT_C CContactTemplate* CContactTemplate::NewL(const CContactItem *aTemplate)
+/** Allocates and constructs a new system template seeded from another one.
+
+@param aTemplate The contact template to copy.
+@return Pointer to the newly created system template. */
+	{
+	CContactTemplate* item=CContactTemplate::NewLC(aTemplate);
+	CleanupStack::Pop(); // item
+	return item;
+	}
+
+EXPORT_C CContactTemplate* CContactTemplate::NewLC(const CContactItem *aTemplate)
+/** Allocates and constructs a new system template seeded from another one.
+
+@param aTemplate The contact template to copy.
+@return Pointer to the newly created system template. This is left on the cleanup stack.*/
+	{
+	CContactTemplate* item=new(ELeave) CContactTemplate;
+	CleanupStack::PushL(item);
+	item->ConstructL(aTemplate);
+	return item;
+	}
+
+EXPORT_C TUid CContactTemplate::Type() const
+/** Implements CContactItem::Type(). 
+
+@return KUidContactTemplate. */
+	{
+	return KUidContactTemplate;
+	}
+
+CContactTemplate::CContactTemplate()
+	{
+	}
+
+
+EXPORT_C CContactICCEntry::~CContactICCEntry()
+/** Empty destructor. */
+	{
+	}
+
+
+/** Allocates and constructs a new ICC entry.
+
+@param The contact template to use.
+@return Pointer to newly created CContactICCEntry.  
+@publishedAll
+@released
+*/
+EXPORT_C CContactICCEntry* CContactICCEntry::NewL(const CContactItem& aTemplate)
+	{
+	CContactICCEntry* entry = new (ELeave) CContactICCEntry();
+	CleanupStack::PushL(entry);
+	entry->ConstructL(&aTemplate);
+	CleanupStack::Pop(entry);
+	return entry;
+	}
+
+/*
+ * Allocates and constructs a new ICC entry.
+ * Not exported - only used by CNTMODEL code.
+ * 
+ * @return Pointer to newly created CContactEntry
+ * @since 7.0
+ */
+CContactICCEntry* CContactICCEntry::NewL()
+	{
+	CContactICCEntry* entry = new (ELeave) CContactICCEntry();
+	CleanupStack::PushL(entry);
+	entry->ConstructL();
+	CleanupStack::Pop(entry);
+	return entry;
+	}
+
+TUid CContactICCEntry::Type() const
+/** Implements CContactItem::Type().
+
+@return KUidContactICCEntry. */
+	{
+	return KUidContactICCEntry;
+	}
+
+CContactICCEntry::CContactICCEntry()
+	{
+	}
+
+
+EXPORT_C TContactItemId ContactGuid::IsLocalContactUidString(const TDesC& aString, TInt64 aMachineUniqueId)
+/** Tests whether a contact item was created in the database with the unique ID 
+specified. If so, the item's contact item ID is returned. If not, returns 
+KErrNotFound.
+
+@param aString The contact item's UID string. Use CContactItem::UidStringL() 
+to get a pointer to the item's UID string.
+@param aMachineUniqueId The database's unique ID. This can be found by calling 
+CContactDatabase::MachineId().
+@return KErrNotFound if the database ID specified is not found in the UID string. 
+Otherwise, the contact item's contact item ID. */
+	{ // static
+	TLex lex(aString);
+	TInt ii=0;
+	TChar c;
+	TInt64 pos=KErrNotFound;
+	// check machine id
+	c=lex.Peek();
+	if (c==KUidStringSeparator)
+		;
+	else
+		{
+		lex.Val(pos,EHex);
+		if ((TInt64)pos!=aMachineUniqueId)
+			return (KErrNotFound);
+		}
+	for(;;)
+		{
+		c=lex.Get();
+		if (c)
+			{
+			if (c==KUidStringSeparator)
+				{
+				ii++;
+				}
+			else
+				{
+				if (ii==2) // extract the field id
+					{
+					lex.UnGet();
+					lex.Val(pos);
+					break;
+					}
+				}
+			}
+		else //EOS
+			break;
+		}
+	return I64INT(pos);
+	}
+
+/** 
+@internalTechnology 
+ */
+EXPORT_C TBool ContactGuid::GetCreationDate(TDes& aString, TInt64 aMachineUniqueId)
+	{ // static
+	if (ContactGuid::IsLocalContactUidString(aString,aMachineUniqueId)>=0)
+		{
+		const TInt startPos=aString.Locate(TChar(KUidStringSeparator));
+		if (startPos!=KErrNotFound)
+			{
+			TInt endPos=aString.Length();
+			while (--endPos>startPos)
+				{
+				if (aString[endPos]==KUidStringSeparator)
+					{
+					aString=aString.Left(endPos);
+					aString=aString.Right(aString.Length()-startPos-1);
+					return ETrue;
+					}
+				}
+			}
+		}
+	return EFalse;
+	}
+
+HBufC* ContactGuid::CreateGuidLC(const TDesC& aCreationDate,TContactItemId aId, TInt64 aMachineUniqueId)
+	{ // static
+	HBufC* guid=HBufC::NewLC(KUidStringLength);
+	TPtr ptr=guid->Des();
+	ptr.AppendFormat(_L("%08x"),I64HIGH(aMachineUniqueId));
+	ptr.AppendFormat(_L("%08x"),I64LOW(aMachineUniqueId));
+	ptr.Append(KUidStringSeparator);
+	ptr.Append(aCreationDate);
+	ptr.Append(KUidStringSeparator);
+	TBuf<20> localId;
+	localId.Num((TInt)aId);
+	ptr.Append(localId);
+	return guid;
+	}
+
+HBufC* ContactGuid::CreateGuidLC(const TTime& aCreationDate,TContactItemId aId, TInt64 aMachineUniqueId)
+	{ // static
+	TBuf<32> time;
+	TInt64 num=aCreationDate.Int64();
+	time.AppendFormat(_L("%08x"),(TInt32)I64HIGH(num));
+	time.AppendFormat(_L("%08x"),(TInt32)I64LOW(num));
+	return ContactGuid::CreateGuidLC(time,aId,aMachineUniqueId);
+	}
+
+HBufC* ContactGuid::CreateGuidLC(TContactItemId aId, TInt64 aMachineUniqueId)
+	{ // static
+	TTime time;
+	time.UniversalTime();
+	return ContactGuid::CreateGuidLC(time,aId,aMachineUniqueId);
+	}