commands/fcontacts/fcontacts.cpp
author Tom Sutcliffe <thomas.sutcliffe@accenture.com>
Thu, 26 Aug 2010 00:49:35 +0100
changeset 45 534b01198c2d
parent 0 7f656887cf89
permissions -rw-r--r--
Added ENotifyKeypresses and ECaptureCtrlC flags to CCommandBase. Commands can now get keypresses and handle ctrl-C via callbacks instead of having to implement custom active objects. As part of this extended the CCommandBase extension interface to MCommandExtensionsV2 for the new virtual functions KeyPressed(TUint aKeyCode, TUint aModifiers) and CtrlCPressed(). sudo now cleans up correctly by using ECaptureCtrlC.

// fcontacts.cpp
// 
// Copyright (c) 2008 - 2010 Accenture. All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the "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:
// Accenture - Initial contribution
//

#include <fshell/ioutils.h>
#include <CNTDB.H>
#include <CNTITEM.H>
#include <CNTFLDST.H>

// Some things that v9.1 doesn't have
#include "fcontacts_support.h"

using namespace IoUtils;

class CCmdContacts : public CCommandBase
	{
public:
	static CCommandBase* NewLC();
	~CCmdContacts();
private:
	CCmdContacts();
	
	TInt CheckDuplicateAndUpdate(CContactItemFieldSet &aFieldSet, CContactItemField &aField);	
	void FillContactFieldSetL(CContactItemFieldSet &aFieldSet, TUid aType);
	void PrintContact(CContactItem* aContact);
	
	void PrintGroupContentsL(CContactItem* aContactGroup, TInt aVerboseLevel);
	void PrintGroupsJoined(CContactItem* aContact, TInt aVerboseLevel);	
	void PrintTime(const TTime& aTime, TBool aNewline=EFalse);
	
	void PrintAcceptedOptions();	
	static const TDesC* UidName(TUid aUid);
private: // From CCommandBase.
	virtual const TDesC& Name() const;
	virtual void DoRunL();
	virtual void ArgumentsL(RCommandArgumentList& aArguments);
	virtual void OptionsL(RCommandOptionList& aOptions);
	
	void DoListL();
	void DoAddL();
	void DoDeleteL();
	void DoChangeL();
	void DoDeleteAllL();
	void DoCreateGroupL();
	void DoAddToGroupL();		
	void DoCompactL();
private:
	
	CContactDatabase* iDb;
	RArray<TBool> iVerbose;
	TInt iOptContactId;
	TInt iOptDestGrpId;
	HBufC* iMatch;
	TBool iShowFirstPhoneOnly;
	
	HBufC* iOptFirstName;
	HBufC* iOptLastName;
	HBufC* iOptTelephone;
	HBufC* iOptMobile;
	TFileName2 iOptPhotoFileName;
	HBufC* iOptGroupName;
	
	HBufC* iOptStr;
	enum
		{
		EList, EAdd, EDelete, EChange, EDeleteAll, ECreateGroup, EAddToGroup, ECompact
		} iCommand;
	};


CCommandBase* CCmdContacts::NewLC()
	{
	CCmdContacts* self = new(ELeave) CCmdContacts();
	CleanupStack::PushL(self);
	self->BaseConstructL();
	return self;
	}

CCmdContacts::~CCmdContacts()
	{
	delete iOptFirstName;
	delete iOptLastName;
	delete iOptTelephone;
	delete iOptMobile;
	delete iOptGroupName;
	delete iOptStr;
	delete iMatch;
	delete iDb;
	iVerbose.Close();
	}

CCmdContacts::CCmdContacts()
	{
	}

const TDesC& CCmdContacts::Name() const
	{
	_LIT(KName, "fcontacts");
	return KName;
	}

void CCmdContacts::ArgumentsL(RCommandArgumentList& aArguments)
	{
	aArguments.AppendEnumL((TInt&)iCommand, _L("command"));
	}

void CCmdContacts::OptionsL(RCommandOptionList& aOptions)
	{
	aOptions.AppendBoolL(iVerbose, _L("verbose"));
	aOptions.AppendUintL((TUint&)iOptContactId, _L("contact-id"));
	aOptions.AppendUintL((TUint&)iOptDestGrpId, _L("group-id"));
	aOptions.AppendStringL(iMatch, _L("match"));
	aOptions.AppendBoolL(iShowFirstPhoneOnly, _L("first-phone-only"));
	aOptions.AppendStringL(iOptFirstName, _L("first-name"));
	aOptions.AppendStringL(iOptLastName, _L("last-name"));
	aOptions.AppendStringL(iOptTelephone, _L("telephone"));
	aOptions.AppendStringL(iOptMobile, _L("mobile"));
	aOptions.AppendFileNameL(iOptPhotoFileName, _L("photo"));
	aOptions.AppendStringL(iOptGroupName, _L("group"));
	}

void CCmdContacts::DoRunL()
	{
	TRAPD(err, iDb = CContactDatabase::OpenL());
	LeaveIfErr(err, _L("Couldn't open contacts database"));
	
	switch (iCommand)
		{
	case EList:
		DoListL();
		break;
	case EAdd:
		DoAddL();
		break;
	case EDelete:
		DoDeleteL();
		break;
	case EChange:
		DoChangeL();
		break;
	case EDeleteAll:
		DoDeleteAllL();
		break;
	case ECreateGroup:
		DoCreateGroupL();
		break;
	case EAddToGroup:
		DoAddToGroupL();	
		break;
	case ECompact:
		DoCompactL();
		break;
		}
	}


void CCmdContacts::DoListL()
	{
	if (iOptContactId)
		{
		CContactItem* contact = NULL;
		TRAPD(err, contact = iDb->ReadContactL(iOptContactId));
		LeaveIfErr(err, _L("Couldn't read contact %d"), iOptContactId);
		PrintContact(contact);
		delete contact;
		}
	else
		{
		// List all
		TContactIter iter(*iDb);
		TContactItemId id;
		TBool foundMatch = EFalse;
		while ((id = iter.NextL()) != KNullContactId)
			{
			CContactItem* contact = iDb->ReadContactLC(id);
			TBool show = ETrue;
			if (iMatch)
				{
				show = EFalse;
				CContactItemFieldSet& fields = contact->CardFields();
				TInt num = fields.Count();
				for (TInt i = 0; i < num; i++)
					{
					CContactItemField& field = fields[i];
					switch (field.StorageType())
						{
						case KStorageTypeText:
							if (field.TextStorage()->Text().MatchF(*iMatch) != KErrNotFound)
								{
								show = ETrue;
								foundMatch = ETrue;
								}
							break;
						default:
							break;
						}
					if (show) break;
					}
				}
			if (show)
				{
				PrintContact(contact);
				}
			CleanupStack::PopAndDestroy(contact);
			if (show && iShowFirstPhoneOnly)
				{
				break;
				}
			}
		if (iMatch && !foundMatch)
			{
			User::Leave(KErrNotFound);
			}
		}
	}

void CCmdContacts::DoAddL()
	{
	TContactItemId newId = 0;
	//create a "contact card" contact item
	CContactItem* contact = CContactCard::NewLC();
	CContactItemFieldSet& fieldSet = contact->CardFields();
	FillContactFieldSetL(fieldSet, KUidContactCard);
			
	TRAPD(err, newId = iDb->AddNewContactL(*contact));
	LeaveIfErr(err, _L("Could not add this contact"));
	
	Printf(_L("Contact Added\r\nContact ID:%d\r\n"), newId);
	CleanupStack::PopAndDestroy(contact);
	}


void CCmdContacts::DoDeleteL()
	{
	if (iOptContactId)
		{
		TRAPD(err, iDb->DeleteContactL(iOptContactId));
		if (err == KErrNone)
			{
			Printf(_L("Contact %d deleted\r\n"), iOptContactId);
			}
		else
			{
			LeaveIfErr(err, _L("Could not detelet contact item %d"), iOptContactId);
			}
		}
	else
		{
		LeaveIfErr(KErrArgument, _L("No contact id specified. Use -i to specify a contact ID"));						
		}	
	}


void CCmdContacts::DoChangeL()
	{
	if (iOptContactId) 
		{
		PrintAcceptedOptions();		
		CContactItem* contact = NULL;
		TRAPD(err, contact = iDb->OpenContactL(iOptContactId));
		LeaveIfErr(err, _L("could not open contact item %d"), iOptContactId);
				
		CleanupStack::PushL(contact);
		
		CContactItemFieldSet& FieldSet = contact->CardFields();
		FillContactFieldSetL(FieldSet, KUidContactCard);
		
		TRAP(err, iDb->CommitContactL(*contact));
		LeaveIfErr(err, _L("Could not commit the change for item %d"), iOptContactId);
						
		CleanupStack::PopAndDestroy(contact);
		
		}
	else
		{
		LeaveIfErr(KErrArgument, _L("No contact id specified. Use -i to specify a contact ID"));
		}		
	}

void CCmdContacts::DoDeleteAllL()
	{
	TInt TotalErrors = 0;	//how many items are not deleted due to error 
	TInt ContactItemCnt = iDb->CountL();
	Printf(_L("Database contains %d items \r\n"), ContactItemCnt);
	// List all
	TContactIter iter(*iDb);
	TContactItemId id;
	while ((id = iter.NextL()) != KNullContactId)
		{
		Printf(_L("Deleting contact item %d ..."), id);
		TRAPD(err, iDb->DeleteContactL(id));
		
		if (err==KErrNone)
			Printf(_L("done \r\n"), id);
		else 
			{
			TotalErrors++;
			Printf(_L("fail, error code=%d \r\n"), err);
			}		
		}
	
	if (TotalErrors > 0)
		{
		LeaveIfErr(KErrGeneral, _L("%d items are not deleted due to error"), TotalErrors);
		}	
	}

void CCmdContacts::DoCreateGroupL()
	{
	Printf(_L("Creating a new group... \r\n"));
	CContactItem* contact = NULL;
	TRAPD(err, contact = iDb->CreateContactGroupL());
	LeaveIfErr(err, _L("Could not create contact group"));
	
	CleanupStack::PushL(contact);
	TContactItemId GroupId = contact->Id();
	CleanupStack::PopAndDestroy(contact);
	contact = NULL;
	
	///////////////////////////////////////////////////
	TRAP(err, contact = iDb->OpenContactL(GroupId));
	LeaveIfErr(err, _L("Could not open contact group for editing"));
	CleanupStack::PushL(contact);
	
	Printf(_L("Changing group name for contact item %d... \r\n"), GroupId);
	
	CContactItemFieldSet& FieldSet = contact->CardFields();
	FillContactFieldSetL(FieldSet, KUidContactGroup);
	TRAP(err, iDb->CommitContactL(*contact));
	LeaveIfErr(err, _L("Could not sumbit the change"));

	CleanupStack::PopAndDestroy(contact);

	}

void CCmdContacts::DoCompactL()
	{
	TRAPD(err, iDb->CompactL());
	LeaveIfErr(err, _L("Could not compact the database"));
	}

void CCmdContacts::DoAddToGroupL()
	{
	if (iOptContactId && iOptDestGrpId)
		{
		Printf(_L("Adding contact item %d to destination group item %d \r\n"), 
				iOptContactId, iOptDestGrpId);
		TRAPD(err, iDb->AddContactToGroupL( (TContactItemId)iOptContactId, (TContactItemId)iOptDestGrpId) ) ;
		
		//this is most common mistake, need to point out especially to remind the user.
		if (err==KErrNotSupported)
			PrintError(KErrNotSupported, _L("Destination is not a group"));
		
		User::LeaveIfError(err);
		
		}
	else 
		{
		LeaveIfErr(KErrArgument, _L("No contact id specified. Use -i to specify a contact ID"));						
		}	
	}


// FOR TEST PURPOSE
//to check if a field of the same type has already existed in a FieldSet.
//if yes, delete that field first and then add it
TInt CCmdContacts::CheckDuplicateAndUpdate(CContactItemFieldSet &aFieldSet, CContactItemField &aField) 
	{
	const CContentType &newContentType=aField.ContentType();
	TInt fieldPos=0;
	
	TInt FieldCnt = aFieldSet.Count();
	for(; fieldPos<FieldCnt ; fieldPos++ )
		{
		CContactItemField& TestedField = aFieldSet[fieldPos];
		if (newContentType == TestedField.ContentType())
			{
				aFieldSet.Remove(fieldPos);
				break;
			}
		}
	
	if (aField.Storage()->IsFull())
		{
		CContactItemField* field=CContactItemField::NewLC(aField);
		aFieldSet.InsertL(fieldPos,*field);
		CleanupStack::Pop();	// field
		}	
	
	return 0;
	}

//this function will retrieve infomation from command line arguments and fill them into 
//a field set, FieldSet doesn't have to be empty
//aType: either KUidContactCard or KUidContactGroup
void CCmdContacts::FillContactFieldSetL(CContactItemFieldSet &aFieldSet, TUid aType)
	{	
	if (aType == KUidContactGroup)
		{
		//group name
		if (iOptGroupName && iOptGroupName->Length())
			{		
			CContactItemField* field = NULL;
			field = CContactItemField::NewLC(KStorageTypeText);
			field->SetLabelL(_L("Group Label"));
			field->SetMapping(KUidContactFieldNone);
			field->AddFieldTypeL(KUidContactFieldTemplateLabel);	
			CContactTextField* pFieldText = field->TextStorage();
			pFieldText->SetTextL(*iOptGroupName);
			aFieldSet.UpdateFieldL(*field, 1);
			CleanupStack::PopAndDestroy(field);	
			}
		}
	
	//Synchronization, for both Group and normal contacts
		{
		CContactItemField* field = NULL;		
		field = CContactItemField::NewLC(KStorageTypeText);
		field->SetLabelL(_L("Synchronization"));
		field->SetMapping(KUidContactFieldVCardMapClass);
		field->AddFieldTypeL(KUidContactFieldClass);	
		CContactTextField* pFieldText = field->TextStorage();
		pFieldText->SetTextL(_L("private"));
		aFieldSet.UpdateFieldL(*field, 1);
		CleanupStack::PopAndDestroy(field);		
		}
		
	if (aType == KUidContactCard)
		{
		//last name
		if (iOptLastName && iOptLastName->Length())
			{		
			CContactItemField* field = NULL;
			field = CContactItemField::NewLC(KStorageTypeText);
			field->SetLabelL(_L("Last name"));
			field->SetMapping(KUidContactFieldVCardMapUnusedN);
			field->AddFieldTypeL(KUidContactFieldFamilyName);	
			CContactTextField* pFieldText = field->TextStorage();
			pFieldText->SetTextL(*iOptLastName);
			aFieldSet.UpdateFieldL(*field, 1);
			CleanupStack::PopAndDestroy(field);	
			}
		
		//first name
		if (iOptFirstName && iOptFirstName->Length())
			{	
			CContactItemField* field = NULL;
			field = CContactItemField::NewLC(KStorageTypeText);
			field->SetLabelL(_L("First name"));
			field->SetMapping(KUidContactFieldVCardMapUnusedN);
			field->AddFieldTypeL(KUidContactFieldGivenName);	
			CContactTextField* pFieldText = field->TextStorage();
			pFieldText->SetTextL(*iOptFirstName);
			aFieldSet.UpdateFieldL(*field, 1);
			CleanupStack::PopAndDestroy(field);	
			}			
		//general telephone
		if (iOptTelephone && iOptTelephone->Length())
			{	
			CContactItemField* field = NULL;
			field = CContactItemField::NewLC(KStorageTypeText);
			field->SetLabelL(_L("Telephone"));
			field->SetMapping(KUidContactFieldVCardMapTEL);
			field->AddFieldTypeL(KUidContactFieldPhoneNumber);	
			field->AddFieldTypeL(KUidContactFieldVCardMapVOICE);		
			CContactTextField* pFieldText = field->TextStorage();
			pFieldText->SetTextL(*iOptTelephone);
			aFieldSet.UpdateFieldL(*field, 1);
			CleanupStack::PopAndDestroy(field);	
			}			
		//mobile phone
		if (iOptMobile && iOptMobile->Length())
			{	
			CContactItemField* field = NULL;
			field = CContactItemField::NewLC(KStorageTypeText);
			field->SetLabelL(_L("Mobile"));
			field->SetMapping(KUidContactFieldVCardMapTEL);
			field->AddFieldTypeL(KUidContactFieldPhoneNumber);
			field->AddFieldTypeL(KUidContactFieldVCardMapCELL);
			CContactTextField* pFieldText = field->TextStorage();
			pFieldText->SetTextL(*iOptMobile);
			aFieldSet.UpdateFieldL(*field, 1);
			CleanupStack::PopAndDestroy(field);	
			}
		
		//photo
		if (iOptPhotoFileName.Length())
			{
			RFile file;
			LeaveIfErr(file.Open(FsL(), iOptPhotoFileName, EFileRead), _L("Couldn't open file \"%S\""), &iOptPhotoFileName);
			TInt fileSize;
			LeaveIfErr(file.Size(fileSize), _L("Couldn't read the size of file \"%S\""), &iOptPhotoFileName);
			RBuf8 buf;
			buf.Create(fileSize);
			buf.CleanupClosePushL();
			LeaveIfErr(file.Read(buf), _L("Couldn't read the contents of file \"%S\""), &iOptPhotoFileName);

			CContactItemField* field = CContactItemField::NewLC(KStorageTypeStore);
			field->SetLabelL(_L("Photo"));
			field->SetMapping(KUidContactFieldVCardMapPHOTO);
			field->AddFieldTypeL(KUidContactFieldPicture);
			CContactStoreField* storeField = field->StoreStorage();
			storeField->SetThingL(buf);
			aFieldSet.UpdateFieldL(*field, 1);

			CleanupStack::PopAndDestroy(2, &buf);	
			}
		}
	}

void CCmdContacts::PrintContact(CContactItem* aContact)
	{
	TContactItemId ContactId = aContact->Id();
	TUid ContactType = aContact->Type();
	CContactItemFieldSet& fields = aContact->CardFields();

	TBool verbose = (iVerbose.Count() > 0);
	TBool veryverbose = (iVerbose.Count() > 1);

	if (verbose)
		{
		Printf(_L("Contact item id %d:\r\n"), aContact->Id());
		Printf(_L("\tLast modified: "));
		PrintTime(aContact->LastModified(), ETrue);
		if (veryverbose)
			{
			Printf(_L("\tHidden=%d System=%d AccessCount=%d Deleted=%d\r\n"), aContact->IsHidden(), aContact->IsSystem(), aContact->AccessCount(), aContact->IsDeleted());
			TPtrC uid = aContact->UidStringL(iDb->MachineId()); // Don't understand the syntax of this function
			Printf(_L("\tUid: %S\r\n"), &uid);
			TUint32 type = aContact->Type().iUid;
			Printf(_L("\tType: 0x%08x "), type);
			switch (type)
				{
				case KUidContactCardValue:
					Printf(_L("(KUidContactCard)\r\n")); break;
				case KUidContactGroupValue:
					Printf(_L("(KUidContactGroup)\r\n")); break;
				case KUidContactOwnCardValue:
					Printf(_L("(KUidContactOwnCard)\r\n")); break;
				case KUidContactICCEntryValue:
					Printf(_L("(KUidContactICCEntry)\r\n")); break;
				case KUidContactTemplateValue:
					Printf(_L("(KUidContactTemplate)\r\n")); break;
				case KUidContactCardTemplateValue:
					Printf(_L("(KUidContactCardTemplate)\r\n")); break;
				default:
					Printf(_L("(Unknown)\r\n")); break;
				}
			}
		
		PrintGroupContentsL(aContact, iVerbose.Count());
		PrintGroupsJoined(aContact, iVerbose.Count());
		
		TInt num = fields.Count();
		for (TInt i = 0; i < num; i++)
			{
			CContactItemField& field = fields[i];
			TPtrC label = field.Label();
			Printf(_L("\t%d [%S]: "), field.Id(), &label);
			switch (field.StorageType())
				{
				case KStorageTypeText:
					{					
					TPtrC fieldText = field.TextStorage()->Text();
					Printf(_L("KStorageTypeText: %S\r\n"), &fieldText);
					break;
					}
				case KStorageTypeDateTime:
					{
					TTime time = field.DateTimeStorage()->Time();
					PrintTime(time, ETrue);
					break;
					}
				case KStorageTypeStore:
					{
					HBufC8* thing = field.StoreStorage()->Thing();
					if (thing)
						{
						Printf(_L("<Binary data of length %d>\r\n"), thing->Size());
						}
					else
						{
						Printf(_L("<Null binary data>\r\n"));
						}
					break;
					}
				case KStorageTypeContactItemId:
					{
					Printf(_L("<Contact item id %d>\r\n"), field.AgentStorage()->Value());
					break;
					}
				default:
					Printf(_L("<Unknown storage type>"));
					break;
				}
			if (veryverbose)
				{
				Printf(_L("\t\tDeleted=%d Disabled=%d Hidden=%d Private=%d Readonly=%d SpeedDial=%d\r\n"), field.IsDeleted(), field.IsDisabled(), field.IsHidden(), field.IsPrivate(), field.IsReadOnly(), field.IsSpeedDial());
				Printf(_L("\t\tUser flags:    0x%08x\r\n"), field.UserFlags());
				const CContentType& contentType = field.ContentType();
				Printf(_L("\t\tVCard mapping: 0x%08x (%S)\r\n"), contentType.Mapping(), UidName(contentType.Mapping()));
				TInt fieldTypeCount = contentType.FieldTypeCount();
				for (TInt i = 0; i < fieldTypeCount; i++)
					{
					TUid fieldType = contentType.FieldType(i);
					Printf(_L("\t\tField type %d:  0x%08x (%S)\r\n"), i, fieldType, UidName(fieldType));
					}
				}
			}
		}
	else
		{
		TInt found;
		if (ContactType == KUidContactGroup)
			{
			TPtrC GroupName;
			found = fields.Find(KUidContactFieldTemplateLabel, KUidContactFieldNone);
			if (found != KErrNotFound)
				GroupName.Set( fields[found].TextStorage()->Text() );
			else
				GroupName.Set(_L("[Unnamed]"));
			
			Printf(_L("%d. [Group] %S "), ContactId, &GroupName);
			
			//list containing items...
			PrintGroupContentsL(aContact, 0);
			}
		else
			{
			if (iShowFirstPhoneOnly)
				{
				found = fields.Find(KUidContactFieldPhoneNumber);
				if (found != KErrNotFound)
					{
					TPtrC phone = TPtrC(fields[found].TextStorage()->Text());
					Printf(_L("%S"), &phone);
					}
				}
			else
				{
				TPtrC first;
				found = fields.Find(KUidContactFieldGivenName);
				if (found != KErrNotFound) first.Set(fields[found].TextStorage()->Text());
				TPtrC last;
				found = fields.Find(KUidContactFieldFamilyName);
				if (found != KErrNotFound) last.Set(fields[found].TextStorage()->Text());
				TPtrC phone;
				found = fields.Find(KUidContactFieldPhoneNumber);
				if (found != KErrNotFound) phone.Set(fields[found].TextStorage()->Text());
				Printf(_L("%d. %S %S %S\r\n"), ContactId, &first, &last, &phone);			
				}
			}
		
		}
	}

//This function will not LEAVE for the moment
//aVerboseLevel: possible values: 0 1 2
//
void CCmdContacts::PrintGroupContentsL(CContactItem* aContactGroup, TInt /*aVerboseLevel*/)
	{
	if (aContactGroup->Type() == KUidContactGroup)
		{
		CContactGroup* pContactGroup = (CContactGroup*)aContactGroup;
		const CContactIdArray* pContactIdAry = pContactGroup->ItemsContained();	
		
		//
		TInt ElementCount = pContactIdAry->Count();
		Printf(_L("\tThis Group contains %d items."), ElementCount);
		if (ElementCount)
			{
			Printf(_L(" Member contact ID list: "));
			TInt i;
			for (i=0; i<ElementCount; i++)
				{
				TContactItemId ID = (*pContactIdAry) [i];
				Printf(_L("%d "), ID);
				}
			}
		Printf(_L("\r\n"));
		
		}	
	}

void CCmdContacts::PrintGroupsJoined(CContactItem* aContact, TInt aVerboseLevel)
	{
	if (aVerboseLevel < 1) return;
	TUid ContactType = aContact->Type();
	if (ContactType == KUidContactGroup || ContactType == KUidContactCard)
		{
		CContactItemPlusGroup * pContact = (CContactItemPlusGroup *)aContact;
		const CContactIdArray* pContactIdAry = pContact->GroupsJoined();
		
		if (!pContactIdAry) 
			return;
					
		TInt ElementCount = pContactIdAry->Count();
		Printf(_L("\tThis item belongs to %d groups."), ElementCount);
		if (ElementCount)
			{
			Printf(_L(" Group contact ID list: "));
			TInt i;
			for (i=0; i<ElementCount; i++)
				{
				TContactItemId ID = (*pContactIdAry) [i];
				Printf(_L("%d "), ID);
				}
			}
		Printf(_L("\r\n"));		
		}	
	}

void CCmdContacts::PrintTime(const TTime& aTime, TBool aNewline)
	{
	_LIT8(KDateTimeFormat, "%d-%02d-%02d %02d:%02d:%02d");
	TDateTime dt = aTime.DateTime();
	Printf(KDateTimeFormat, dt.Year(), dt.Month()+1, dt.Day()+1, dt.Hour(), dt.Minute(), dt.Second());
	if (aNewline) Printf(_L("\r\n"));
	}

//print the accepted options from the command line
void CCmdContacts::PrintAcceptedOptions()
	{
	//surname
	if (iOptLastName && iOptLastName->Length())
		Printf(_L("surname: %S \r\n"), iOptLastName );				
	//first name
	if (iOptFirstName && iOptFirstName->Length())
		Printf(_L("first name: %S \r\n"), iOptFirstName );					
	//general telephone
	if (iOptTelephone && iOptTelephone->Length())
		Printf(_L("general telephone: %S \r\n"), iOptTelephone );
	//mobile phone
	if (iOptMobile && iOptMobile->Length())
		Printf(_L("mobile: %S \r\n"), iOptMobile );
	//photo
	if (iOptPhotoFileName.Length())
		Printf(_L("photo: %S \r\n"), &iOptPhotoFileName );
	}


#define CASE_LIT(x) case x: { _LIT(KName, #x); return &KName; }
const TDesC* CCmdContacts::UidName(TUid aUid)
	{
	switch (aUid.iUid)
		{
		CASE_LIT(KUidContactFieldAddressValue)
		CASE_LIT(KUidContactFieldPostOfficeValue)
		CASE_LIT(KUidContactFieldExtendedAddressValue)
		CASE_LIT(KUidContactFieldLocalityValue)
		CASE_LIT(KUidContactFieldRegionValue)
		CASE_LIT(KUidContactFieldPostCodeValue)
		CASE_LIT(KUidContactFieldCountryValue)
		CASE_LIT(KUidContactFieldCompanyNameValue)
		CASE_LIT(KUidContactFieldCompanyNamePronunciationValue)
		CASE_LIT(KUidContactFieldPhoneNumberValue)
		CASE_LIT(KUidContactFieldGivenNameValue)
		CASE_LIT(KUidContactFieldFamilyNameValue)
		CASE_LIT(KUidContactFieldGivenNamePronunciationValue)
		CASE_LIT(KUidContactFieldFamilyNamePronunciationValue)
		CASE_LIT(KUidContactFieldAdditionalNameValue)
		CASE_LIT(KUidContactFieldSuffixNameValue)
		CASE_LIT(KUidContactFieldPrefixNameValue)
		CASE_LIT(KUidContactFieldHiddenValue)
		CASE_LIT(KUidContactFieldEMailValue)
		CASE_LIT(KUidContactFieldMsgValue)
		CASE_LIT(KUidContactFieldSmsValue)
		CASE_LIT(KUidContactFieldFaxValue)
		CASE_LIT(KUidContactFieldDefinedTextValue)
		CASE_LIT(KUidContactFieldNoteValue)
		CASE_LIT(KUidContactFieldBirthdayValue)
		CASE_LIT(KUidContactFieldUrlValue)
		CASE_LIT(KUidContactFieldStorageInlineValue)
		CASE_LIT(KUidContactFieldTemplateLabelValue)
		CASE_LIT(KUidContactFieldPictureValue)
		CASE_LIT(KUidContactFieldRingToneValue)
		CASE_LIT(KUidContactFieldDTMFValue)
		CASE_LIT(KUidContactsVoiceDialFieldValue)
		CASE_LIT(KUidContactFieldNoneValue)
		CASE_LIT(KUidContactFieldJobTitleValue)
		CASE_LIT(KUidContactFieldICCSlotValue)
		CASE_LIT(KUidContactFieldICCPhonebookValue)
		CASE_LIT(KUidContactFieldICCGroupValue)
		CASE_LIT(KUidContactFieldIMAddressValue)
		CASE_LIT(KUidContactFieldSecondNameValue)
		CASE_LIT(KUidContactFieldSIPIDValue)
		CASE_LIT(KUidContactFieldAssistantValue)
		CASE_LIT(KUidContactFieldAnniversaryValue)
		CASE_LIT(KUidContactFieldSpouseValue)
		CASE_LIT(KUidContactFieldChildrenValue)
		CASE_LIT(KUidContactFieldClassValue)
		CASE_LIT(KUidContactFieldDepartmentNameValue)
		CASE_LIT(KIntContactFieldVCardMapWORK)
		CASE_LIT(KIntContactFieldVCardMapHOME)
		CASE_LIT(KIntContactFieldVCardMapMSG)
		CASE_LIT(KIntContactFieldVCardMapVOICE)
		CASE_LIT(KIntContactFieldVCardMapFAX)
		CASE_LIT(KIntContactFieldVCardMapPREF)
		CASE_LIT(KIntContactFieldVCardMapCELL)
		CASE_LIT(KIntContactFieldVCardMapPAGER)
		CASE_LIT(KIntContactFieldVCardMapBBS)
		CASE_LIT(KIntContactFieldVCardMapMODEM)
		CASE_LIT(KIntContactFieldVCardMapCAR)
		CASE_LIT(KIntContactFieldVCardMapISDN)
		CASE_LIT(KIntContactFieldVCardMapVIDEO)
		CASE_LIT(KIntContactFieldVCardMapDOM)
		CASE_LIT(KIntContactFieldVCardMapADR)
		CASE_LIT(KIntContactFieldVCardMapPOSTOFFICE)
		CASE_LIT(KIntContactFieldVCardMapEXTENDEDADR)
		CASE_LIT(KIntContactFieldVCardMapLOCALITY)
		CASE_LIT(KIntContactFieldVCardMapREGION)
		CASE_LIT(KIntContactFieldVCardMapPOSTCODE)
		CASE_LIT(KIntContactFieldVCardMapCOUNTRY)
		CASE_LIT(KIntContactFieldVCardMapAGENT)
		CASE_LIT(KIntContactFieldVCardMapBDAY)
		CASE_LIT(KIntContactFieldVCardMapEMAILINTERNET)
		CASE_LIT(KIntContactFieldVCardMapGEO)
		CASE_LIT(KIntContactFieldVCardMapLABEL)
		CASE_LIT(KIntContactFieldVCardMapLOGO)
		CASE_LIT(KIntContactFieldVCardMapMAILER)
		CASE_LIT(KIntContactFieldVCardMapNOTE)
		CASE_LIT(KIntContactFieldVCardMapORG)
		CASE_LIT(KIntContactFieldVCardMapORGPronunciation)
		CASE_LIT(KIntContactFieldVCardMapPHOTO)
		CASE_LIT(KIntContactFieldVCardMapROLE)
		CASE_LIT(KIntContactFieldVCardMapSOUND)
		CASE_LIT(KIntContactFieldVCardMapTEL)
		CASE_LIT(KIntContactFieldVCardMapTELFAX)
		CASE_LIT(KIntContactFieldVCardMapTITLE)
		CASE_LIT(KIntContactFieldVCardMapURL)
		CASE_LIT(KIntContactFieldVCardMapUnusedN)
		CASE_LIT(KIntContactFieldVCardMapUnusedFN)
		CASE_LIT(KIntContactFieldVCardMapNotRequired)
		CASE_LIT(KIntContactFieldVCardMapUnknownXDash)
		CASE_LIT(KIntContactFieldVCardMapUnknown)
		CASE_LIT(KIntContactFieldVCardMapUID)
		CASE_LIT(KIntContactFieldVCardMapINTL)
		CASE_LIT(KIntContactFieldVCardMapPOSTAL)
		CASE_LIT(KIntContactFieldVCardMapPARCEL)
		CASE_LIT(KIntContactFieldVCardMapGIF)
		CASE_LIT(KIntContactFieldVCardMapCGM)
		CASE_LIT(KIntContactFieldVCardMapWMF)
		CASE_LIT(KIntContactFieldVCardMapBMP)
		CASE_LIT(KIntContactFieldVCardMapMET)
		CASE_LIT(KIntContactFieldVCardMapPMB)
		CASE_LIT(KIntContactFieldVCardMapDIB)
		CASE_LIT(KIntContactFieldVCardMapPICT)
		CASE_LIT(KIntContactFieldVCardMapTIFF)
		CASE_LIT(KIntContactFieldVCardMapPDF)
		CASE_LIT(KIntContactFieldVCardMapPS)
		CASE_LIT(KIntContactFieldVCardMapJPEG)
		CASE_LIT(KIntContactFieldVCardMapMPEG)
		CASE_LIT(KIntContactFieldVCardMapMPEG2)
		CASE_LIT(KIntContactFieldVCardMapAVI)
		CASE_LIT(KIntContactFieldVCardMapQTIME)
		CASE_LIT(KIntContactFieldVCardMapTZ)
		CASE_LIT(KIntContactFieldVCardMapKEY)
		CASE_LIT(KIntContactFieldVCardMapX509)
		CASE_LIT(KIntContactFieldVCardMapPGP)
		CASE_LIT(KIntContactFieldVCardMapSMIME)
		CASE_LIT(KIntContactFieldVCardMapWV)
		CASE_LIT(KIntContactFieldVCardMapSECONDNAME)
		CASE_LIT(KIntContactFieldVCardMapSIPID)
		CASE_LIT(KIntContactFieldVCardMapPOC)
		CASE_LIT(KIntContactFieldVCardMapSWIS)
		CASE_LIT(KIntContactFieldVCardMapVOIP)
		CASE_LIT(KIntContactFieldVCardMapAssistant)
		CASE_LIT(KIntContactFieldVCardMapAssistantTel)
		CASE_LIT(KIntContactFieldVCardMapAnniversary)
		CASE_LIT(KIntContactFieldVCardMapSpouse)
		CASE_LIT(KIntContactFieldVCardMapChildren)
		CASE_LIT(KIntContactFieldVCardMapClass)
		CASE_LIT(KIntContactFieldVCardMapDepartment)
		default:
			{
			_LIT(KUnknown, "Unknown");
			return &KUnknown;
			}
		}
	}

EXE_BOILER_PLATE(CCmdContacts)