pimprotocols/phonebooksync/Server/PhonebookIniFile.cpp
changeset 0 e686773b3f54
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pimprotocols/phonebooksync/Server/PhonebookIniFile.cpp	Tue Feb 02 10:12:17 2010 +0200
@@ -0,0 +1,642 @@
+// Copyright (c) 2002-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:
+// Implementation of CPhoneBookIniFile class which manages the PhBkSync.INI
+// file.
+// 
+//
+
+/**
+ @file
+ @internalComponent
+*/
+
+#include "phbksync.h"
+#include "Phonebook.h"
+#include "PhonebookIniFile.h"
+#include "PhonebookManager.h"
+#include "phbksynclog.h"
+#include "common.h"
+
+
+//
+// Constants for the INI file.  Do not change these.
+//
+_LIT8(KPhBkSyncStartOptionText, "PhBkSyncStartOption");
+_LIT8(KPhBkSyncTemplateIdText,  "PhBkSyncTemplateId");
+_LIT8(KPhBkSyncGroupIdText,     "PhBkSyncGroupId");
+_LIT8(KPhBkSyncPhonebookIdText, "PhBkSyncPhonebookId");
+
+
+//
+// Minimum and maximum dimensions of an INI file...
+//
+const TInt KIniFileMaxPhonebooks = KMaxPhonebooks;
+const TInt KIniFileMinimumSize   = 1;
+const TInt KIniFileNoOfSettings  = 4;
+const TInt KIniFileMaxLineLength = 64; // Approx. 20+1+9+1+15=46 max.
+const TInt KIniFileMaximumSize   = (KIniFileMaxPhonebooks *
+                                    KIniFileNoOfSettings *
+                                    KIniFileMaxLineLength);
+
+
+/**
+ *  Static factory method used to create a CPhoneBookIniFile object.
+ *
+ *  @param aPhonebookList  A list of phonebook UIDs supported by the Phonebook
+ *                         synchroniser.
+ *
+ *  @return  Pointer to the created CPhoneBookIniFile object, or NULL.
+ */
+CPhoneBookIniFile* CPhoneBookIniFile::NewL(RPointerArray<CPhoneBook>& aPhonebookList)
+	{
+	LOGINIFILE2(_L8("NewL(%d phonebooks)"), aPhonebookList.Count());
+
+	CPhoneBookIniFile*  ptr = new (ELeave) CPhoneBookIniFile(aPhonebookList);
+	CleanupStack::PushL(ptr);
+	ptr->ConstructL();
+	CleanupStack::Pop(ptr);
+	return ptr;
+	} // CPhoneBookIniFile::NewL
+
+
+/**
+ *  Standard constructor.
+ *
+ *  @param aPhonebookList  A list of phonebook UIDs supported by the Phonebook
+ *                         synchroniser.
+ */
+CPhoneBookIniFile::CPhoneBookIniFile(RPointerArray<CPhoneBook>& aPhonebookList)
+  : iPhonebookList(aPhonebookList),
+    iIsIniFileCacheValid(EFalse)
+	{
+	// NOP
+	} // CPhoneBookIniFile::CPhoneBookIniFile
+
+
+/**
+ *  Standard destructor.
+ */
+CPhoneBookIniFile::~CPhoneBookIniFile()
+	{
+	// NOP
+	} // CPhoneBookIniFile::~CPhoneBookIniFile
+
+
+/**
+ *  Second stage contructor.
+ */
+void CPhoneBookIniFile::ConstructL()
+	{
+	LOGINIFILE1(_L8("ConstructL()"));
+	
+	__ASSERT_DEBUG(iPhonebookList.Count() <= KMaxPhonebooks,
+				   PhBkSyncPanic(EPhBkSyncPanicTooManyPhonebooks));
+
+	//
+	// Read the INI file and initialise the cache. If a problem occurs
+	// during the read of the INI file then we let it go as the server
+	// must still start. If the file is corrupt then we write a new one
+	// out straight away.
+	//
+	TRAPD(result, ReadIniFileL());
+	LOGINIFILE2(_L8("Read of the INI file returned %d"), result);
+
+	if (result == KErrNone)
+		{
+		UpdatePhonebookParamsCache();
+		}
+	else if (result == KErrCorrupt)
+		{
+		WriteIniFileSettingsIfNeeded();
+		}
+	} // CPhoneBookIniFile::ConstructL
+
+
+/**
+ *  Requests the writting of the Ini file if required.
+ *
+ *  @return KErrNone if successful or a Standard Symbian error code.
+ */
+TInt CPhoneBookIniFile::WriteIniFileSettingsIfNeeded()
+	{
+	LOGINIFILE1(_L8("WriteIniFileSettingsIfNeeded()"));
+	
+	//
+	// Check the current cached values against the phonebooks to see if
+	// we need to file the INI file. If so then write the file.
+	//
+	TInt  result(KErrNone);
+	
+	if (CheckPhonebookParamsForChanges())
+		{
+		TRAP(result, WriteIniFileL());
+		LOGINIFILE2(_L8("Write of the INI file returned %d"), result);
+	
+		//
+		// If the INI file was written ok, then update the cache...
+		//
+		if (result == KErrNone)
+			{
+			UpdatePhonebookParamsCache();
+			}
+		}
+	
+	return result;
+	} // CPhoneBookIniFile::WriteIniFileSettingsIfNeeded
+
+
+/**
+ *  Checks if any of the phonebook parameters have changed. This would indicate
+ *  that the INI file should be re-written.
+ *
+ *  @return ETrue if the phonebook parameters have changed, EFalse otherwise.
+ */
+TBool CPhoneBookIniFile::CheckPhonebookParamsForChanges() const
+	{
+	LOGINIFILE1(_L8("CheckPhonebookParamsForChanges()"));
+				
+	//
+	// If the INI file does not exist or is corrupt, then write it...
+	//
+	if (iIsIniFileCacheValid == EFalse)
+		{
+		LOGINIFILE1(_L8("No INI file data loaded so file needs writting"));
+		return ETrue;
+		}
+	
+	//
+	// Check each phonebook against the cache for unwritten changes.
+	//
+	TInt  needsWriting(EFalse);
+	TInt  phonebookCount(iPhonebookList.Count());
+	
+	for (TInt index = 0;  index < phonebookCount;  index++)
+		{
+		CPhoneBook*  phonebook = iPhonebookList[index];
+
+		if (phonebook != NULL)
+			{
+			RMobilePhoneBookStore::TMobilePhoneBookInfoV5  phBkInfo;
+			
+			phBkInfo = phonebook->GetPhoneBookInfo();
+
+			if (iIniFileSyncModeCache[index] != phonebook->GetSyncMode()  ||
+				iIniFileTemplateIdCache[index] != phonebook->GetTemplateId()  ||
+				iIniFileGroupIdCache[index] != phonebook->GetGroupId()  ||
+				iIniFileIdentityCache[index] != phBkInfo.iIdentity)
+				{
+				needsWriting = ETrue;
+				break;
+				}
+			}
+		}
+	
+	//
+	// Log if the INI file needs writing...
+	//
+	if (needsWriting == EFalse)
+		{
+		LOGINIFILE1(_L8("INI file does not need to be written"));
+		}
+	else
+		{
+		LOGINIFILE1(_L8("INI file needs to be written"));
+		}
+	
+	return needsWriting;
+	} // CPhoneBookIniFile::CheckPhonebookParamsForChanges
+
+
+/**
+ *  Get the full path name for the INI file.
+ *
+ *  @param aFs           File server handle.
+ *  @param aIniFileName  Path will be returned in aPath.
+ */
+void CPhoneBookIniFile::GetIniFileName(RFs& aFs, TDes& aIniFileName) const
+	{
+	LOGINIFILE1(_L8("GetIniFileName()"));
+	
+	//
+	// Name is made up of the system drive, private path and INI file name...
+	//
+	_LIT(KPhBkSyncIniFileName, "PhBkSync.ini");
+
+	TDriveUnit  systemDrive(aFs.GetSystemDrive()); 
+	TPath  privatePath;
+	
+	aFs.PrivatePath(privatePath);
+
+	aIniFileName.Zero();
+	aIniFileName.Append(systemDrive.Name());
+	aIniFileName.Append(privatePath);
+	aIniFileName.Append(KPhBkSyncIniFileName);
+
+	//
+	// Debug logging of the INI file name...
+	//	
+#ifdef _DEBUG
+	TBuf8<KMaxFileName>  aIniFileNameIn8Bit;
+	aIniFileNameIn8Bit.Copy(aIniFileName);
+	LOGINIFILE2(_L8("INI file \"%S\""), &aIniFileNameIn8Bit);
+#endif
+	} // CPhoneBookIniFile::GetIniFileName
+
+
+/**
+ *  Write all phonebook settings to the Phonebook INI file. If the file
+ *  does not exist it will create one.
+ */
+void CPhoneBookIniFile::WriteIniFileL() const
+	{
+	LOGINIFILE1(_L8("WriteIniFileL()"));
+
+	//
+	// Connect to the File Server...
+	//
+	RFs  fs;
+
+	User::LeaveIfError(fs.Connect());
+	CleanupClosePushL(fs);
+
+	//
+	// Get the name of the INI file...
+	//
+	TFileName  iniFileName;
+	GetIniFileName(fs, iniFileName);
+
+	//
+	// Ensure that the private directory exists...
+	//
+	TInt  result = fs.MkDirAll(iniFileName);
+	if (result != KErrAlreadyExists  &&  result != KErrNone)
+		{
+		User::Leave(result);
+		}
+	
+	//
+	// Open the file for writing, truncating it if needed...
+	//
+	RFile  file;
+
+	User::LeaveIfError(file.Replace(fs, iniFileName, EFileShareAny|EFileWrite));
+	CleanupClosePushL(file);
+
+	//
+	// Write the settings for each phonebook...
+	//
+	_LIT8(KIniLineValueFormat, "%S= %d %d\r\n");
+	_LIT8(KIniLineStringFormat, "%S= %d %S\r\n");
+	TInt  phonebookCount(iPhonebookList.Count());
+	TBuf8<KIniFileMaxLineLength>  line;
+	
+	for (TInt index = 0;  index < phonebookCount;  index++)
+		{
+		CPhoneBook*  phonebook = iPhonebookList[index];
+
+		if (phonebook != NULL)
+			{
+			TUid  phonebookUid = phonebook->GetPhonebookUid();
+
+			// Phonebook Sync Mode...
+			line.Format(KIniLineValueFormat, &KPhBkSyncStartOptionText,
+						phonebookUid.iUid, phonebook->GetSyncMode());
+			User::LeaveIfError(file.Write(line));
+#ifdef _DEBUG
+			line.SetLength(line.Length() - 2);
+			LOGINIFILE2(_L8("INI line \"%S\""), &line);
+#endif
+
+			// Phonebook Template ID...
+			line.Format(KIniLineValueFormat, &KPhBkSyncTemplateIdText,
+						phonebookUid.iUid, phonebook->GetTemplateId());
+			User::LeaveIfError(file.Write(line));
+#ifdef _DEBUG
+			line.SetLength(line.Length() - 2);
+			LOGINIFILE2(_L8("INI line \"%S\""), &line);
+#endif
+
+			// Phonebook Group ID...
+			line.Format(KIniLineValueFormat, &KPhBkSyncGroupIdText,
+						phonebookUid.iUid, phonebook->GetGroupId());
+			User::LeaveIfError(file.Write(line));
+#ifdef _DEBUG
+			line.SetLength(line.Length() - 2);
+			LOGINIFILE2(_L8("INI line \"%S\""), &line);
+#endif
+
+			// Phonebook ID string...
+			RMobilePhoneBookStore::TMobilePhoneBookInfoV5  phBkInfo;
+			
+			phBkInfo = phonebook->GetPhoneBookInfo();
+
+			line.Format(KIniLineStringFormat, &KPhBkSyncPhonebookIdText,
+						phonebookUid.iUid, &phBkInfo.iIdentity);
+			User::LeaveIfError(file.Write(line));
+#ifdef _DEBUG
+			line.SetLength(line.Length() - 2);
+			LOGINIFILE2(_L8("INI line \"%S\""), &line);
+#endif
+			}
+		}
+
+	CleanupStack::PopAndDestroy(2, &fs); // fs, file
+	} // CPhoneBookIniFile::WriteIniFileL
+
+
+/**
+ *  Read all phonebook settings from the Phonebook INI file if it exists.
+ */
+void CPhoneBookIniFile::ReadIniFileL() const
+	{
+	LOGINIFILE1(_L8("ReadIniFileL()"));
+
+	//
+	// Connect to the File Server...
+	//
+	RFs  fs;
+
+	User::LeaveIfError(fs.Connect());
+	CleanupClosePushL(fs);
+
+	//
+	// Get the name of the INI file...
+	//
+	TFileName  iniFileName;
+	GetIniFileName(fs, iniFileName);
+
+	//
+	// Open the INI file...
+	//
+	RFile  file;
+
+	User::LeaveIfError(file.Open(fs, iniFileName, EFileShareAny | EFileRead));
+	CleanupClosePushL(file);
+
+	//
+	// Load the file into memory...
+	//
+	TInt  fileSize;
+
+	User::LeaveIfError(file.Size(fileSize));
+
+	if (fileSize < KIniFileMinimumSize  ||  fileSize > KIniFileMaximumSize)
+		{
+		User::Leave(KErrCorrupt);
+		}
+
+	HBufC8*  iniFileBuf = HBufC8::NewLC(fileSize);
+	TPtr8  iniFilePtr(iniFileBuf->Des());
+	User::LeaveIfError(file.Read(0, iniFilePtr));
+
+	//
+	// Parse the INI file text...
+	//
+	TLex8  iniFile(*iniFileBuf);
+
+	while (!iniFile.Eos()) 
+		{
+		//
+		// The settings for each follow the pattern:
+		//
+		//   <Setting>= <Phonebook> <Value>
+		//
+		TPtrC8  settingsToken(iniFile.NextToken());
+		iniFile.SkipSpace();
+
+		//
+		// Check the setting field is correct...
+		//
+		if (iniFile.Eos())
+			{
+			break;
+			}
+
+		if (settingsToken.Find(KPhBkSyncStartOptionText) != KErrNone  &&
+			settingsToken.Find(KPhBkSyncTemplateIdText) != KErrNone  &&
+			settingsToken.Find(KPhBkSyncGroupIdText) != KErrNone  &&
+			settingsToken.Find(KPhBkSyncPhonebookIdText) != KErrNone)
+			{
+			LOGINIFILE2(_L8("Invalid setting token (%S)"), &settingsToken);
+			continue;
+			}
+
+		//
+		// Get the phonebook. This is the UID value but was previously
+		// a constant, so we read both.
+		//
+		iniFile.SkipSpace();
+		if (iniFile.Eos())
+			{
+			break;
+			}
+
+		TInt  phonebookNum(0);
+		TUid  phonebookUid;
+
+		TInt  result = iniFile.Val(phonebookNum);
+		if (result != KErrNone)
+			{
+			LOGINIFILE2(_L8("Invalid phonebook number (error %d)"), result);
+			continue;
+			}
+		
+		switch (phonebookNum)
+			{
+			case 1:
+				{
+				phonebookUid = KUidIccGlobalAdnPhonebook;
+				}
+				break;
+				
+			case 2:
+				{
+				phonebookUid = KUidIccGlobalSdnPhonebook;
+				}
+				break;
+				
+			case 3:
+				{
+				phonebookUid = KUidIccGlobalLndPhonebook;
+				}
+				break;
+				
+			case 4:
+				{
+				phonebookUid = KUidUsimAppAdnPhonebook;
+				}
+				break;
+				
+			case 5:
+				{
+				phonebookUid = KUidIccGlobalFdnPhonebook;
+				}
+				break;
+				
+			default:
+				{
+				phonebookUid = TUid::Uid(phonebookNum);
+				}
+				break;
+			}	
+
+		TInt  phonebookCount(iPhonebookList.Count());
+		CPhoneBook*  phonebook(NULL);
+
+		for (TInt index = 0;  index < phonebookCount;  index++)
+			{
+			if (iPhonebookList[index]->GetPhonebookUid() == phonebookUid)
+				{
+				phonebook = iPhonebookList[index];
+				break;
+				}
+			}
+
+		if (phonebook == NULL)
+			{
+			LOGINIFILE2(_L8("Phonebook does not exist (%d)"), phonebookNum);
+			continue;
+			}
+
+		//
+		// Read the value and set it...
+		//
+		iniFile.SkipSpace();
+		if (iniFile.Eos())
+			{
+			break;
+			}
+
+		if (settingsToken.Find(KPhBkSyncStartOptionText) == KErrNone)
+			{
+			TInt  syncModeNum(-1);
+			
+			result = iniFile.Val(syncModeNum);
+			if (result != KErrNone)
+				{
+				LOGINIFILE2(_L8("Invalid sync mode number (error %d)"), result);
+				continue;
+				}
+
+			RPhoneBookSession::TPhonebookSyncMode  syncMode;
+
+			syncMode = static_cast<RPhoneBookSession::TPhonebookSyncMode>(syncModeNum);
+
+			if (syncMode != RPhoneBookSession::EAutoCurrentIcc  &&
+				syncMode != RPhoneBookSession::EAutoSameIcc  &&
+				syncMode != RPhoneBookSession::EManual)
+				{
+				LOGINIFILE2(_L8("Invalid sync mode value (%d)"),
+				            (TInt) syncMode);
+				continue;
+				}
+
+			phonebook->SetSyncMode(syncMode);
+			
+			LOGINIFILE4(_L8("INI read as \"%S %d %d\""),
+						&KPhBkSyncStartOptionText,
+						phonebook->GetPhonebookUid().iUid, (TInt) syncMode);
+			}
+		else if (settingsToken.Find(KPhBkSyncTemplateIdText) == KErrNone)
+			{
+			TContactItemId  templateId(-1);
+			
+			result = iniFile.Val(templateId);
+			if (result != KErrNone)
+				{
+				LOGINIFILE3(_L8("Invalid template Id number (error %d, number %d)"),
+				            result, templateId);
+				continue;
+				}
+
+			phonebook->SetTemplateId(templateId);
+
+			LOGINIFILE4(_L8("INI read as \"%S %d %d\""),
+						&KPhBkSyncTemplateIdText,
+						phonebook->GetPhonebookUid().iUid, templateId);
+			}
+		else if (settingsToken.Find(KPhBkSyncGroupIdText) == KErrNone)
+			{
+			TContactItemId  groupId(0);
+			
+			result = iniFile.Val(groupId);
+			if (result != KErrNone)
+				{
+				LOGINIFILE3(_L8("Invalid group ID number (error %d, number %d)"),
+				            result, groupId);
+				continue;
+				}
+
+			phonebook->SetGroupId(groupId);
+
+			LOGINIFILE4(_L8("INI read as \"%S %d %d\""),
+						&KPhBkSyncGroupIdText,
+						phonebook->GetPhonebookUid().iUid, groupId);
+			}
+		else if (settingsToken.Find(KPhBkSyncPhonebookIdText) == KErrNone)
+			{
+			TPtrC8  phonebookId(iniFile.NextToken());
+			RMobilePhoneBookStore::TMobilePhoneBookInfoV5  phBkInfo;
+
+			phBkInfo = phonebook->GetPhoneBookInfo();
+
+			if (phonebookId.Length() > phBkInfo.iIdentity.MaxSize())
+				{
+				LOGINIFILE2(_L8("Invalid phonebook ID (\"%S\")"), &phonebookId);
+				}
+
+			phBkInfo.iIdentity.Copy(phonebookId);
+			phonebook->SetPhoneBookInfo(phBkInfo);
+
+			LOGINIFILE4(_L8("INI read as \"%S %d %S\""),
+						&KPhBkSyncPhonebookIdText,
+						phonebook->GetPhonebookUid().iUid, &phBkInfo.iIdentity);
+			}
+		}
+
+	CleanupStack::PopAndDestroy(3, &fs); // fs, file, contents
+	} // CPhoneBookIniFile::ReadIniFileL
+
+
+/**
+ *  Update the internal cache of phonebook parameters with the real values.
+ *  This function is used after the INI file is written.
+ */
+void CPhoneBookIniFile::UpdatePhonebookParamsCache()
+	{
+	LOGINIFILE1(_L8("UpdatePhonebookParamsCache()"));
+				
+	TInt  phonebookCount(iPhonebookList.Count());
+	
+	for (TInt index = 0;  index < phonebookCount;  index++)
+		{
+		CPhoneBook*  phonebook = iPhonebookList[index];
+
+		if (phonebook != NULL)
+			{
+			RMobilePhoneBookStore::TMobilePhoneBookInfoV5  phBkInfo;
+			
+			phBkInfo = phonebook->GetPhoneBookInfo();
+
+			iIniFileSyncModeCache[index] = phonebook->GetSyncMode();
+			iIniFileTemplateIdCache[index] = phonebook->GetTemplateId();
+			iIniFileGroupIdCache[index] = phonebook->GetGroupId();
+			iIniFileIdentityCache[index].Copy(phBkInfo.iIdentity);
+			}
+		}
+
+	iIsIniFileCacheValid = ETrue;
+	} // CPhoneBookIniFile::UpdatePhonebookParamsCache
+
+