--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pimappservices/calendar/server/src/agstzruleindex.cpp Tue Feb 02 10:12:19 2010 +0200
@@ -0,0 +1,927 @@
+// Copyright (c) 2008-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 <vtzrules.h>
+#include <tz.h>
+#include "agmentry.h"
+#include "agmtlsproxy.h"
+#include "agmtzrules.h"
+#include "agstzruleindex.h"
+#include "agmpanic.h"
+#include "agmrptdef.h"
+#include "agsfilemanager.h"
+
+const TUid KUidAgnSystemTzIndex = {0x10285b96};
+const TUid KUidAgnImportedTzIndex = {0x10285b97};
+const TUid KUidAgnTimeStamp = {0x102863fb};
+
+const TInt KMinYear = 0;
+const TInt KMaxYear = 9999;
+
+/* ------------------- CAgnTzRuleIndexItem -------------------*/
+CAgnTzRuleIndexItem::CAgnTzRuleIndexItem(TStreamId aStreamId, CTzRules* aRule) :
+ iRefCount(1), iTzRules(aRule)
+ {
+ iStreamId = aStreamId;
+ }
+
+CAgnTzRuleIndexItem::CAgnTzRuleIndexItem() :
+ iRefCount(1), iTzRules(NULL)
+ {
+ }
+
+CAgnTzRuleIndexItem* CAgnTzRuleIndexItem::NewL(RReadStream& aStream)
+ {
+ CAgnTzRuleIndexItem* self = new (ELeave) CAgnTzRuleIndexItem();
+ CleanupStack::PushL(self);
+ self->InternalizeL(aStream);
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+CAgnTzRuleIndexItem* CAgnTzRuleIndexItem::NewL(TStreamId aStreamId, CTzRules* aTzRule)
+ {
+ CAgnTzRuleIndexItem* self = new (ELeave) CAgnTzRuleIndexItem(aStreamId, aTzRule);
+ return self;
+ }
+
+CAgnTzRuleIndexItem::~CAgnTzRuleIndexItem()
+ {
+ delete iTzRules;
+ }
+
+void CAgnTzRuleIndexItem::IncrementRef()
+ {
+ ++iRefCount;
+ }
+
+TInt CAgnTzRuleIndexItem::DecrementRef()
+ {
+ __ASSERT_DEBUG(iRefCount>0, User::Invariant());
+ return --iRefCount;
+ }
+
+void CAgnTzRuleIndexItem::ExternalizeL(RWriteStream& aStream) const
+ {
+ aStream.WriteInt16L(iRefCount);
+ aStream << iStreamId;
+ }
+
+void CAgnTzRuleIndexItem::InternalizeL(RReadStream& aStream)
+ {
+ iRefCount = aStream.ReadInt16L();
+ aStream >> iStreamId;
+ }
+
+void CAgnTzRuleIndexItem::SetRule(CTzRules* aTzRules)
+ {
+ if (iTzRules)
+ {
+ delete iTzRules;
+ }
+ iTzRules = aTzRules;
+ }
+
+CTzRules* CAgnTzRuleIndexItem::TzRule() const
+ {
+ return iTzRules;
+ }
+
+const TStreamId& CAgnTzRuleIndexItem::StreamId() const
+ {
+ return iStreamId;
+ }
+
+TBool CAgnTzRuleIndexItem::IsSystemTzRule() const
+ {
+ return EFalse;
+ }
+
+/* ------------------- CAgnSystemTzRuleIndexItem -------------------*/
+void CAgnSystemTzRuleIndexItem::ConstructL(const TDesC8& aTzId)
+ {
+ iTzId = aTzId.AllocL();
+ }
+
+CAgnSystemTzRuleIndexItem* CAgnSystemTzRuleIndexItem::NewL(TStreamId aStreamId, const TDesC8& aTzId, CTzRules* aRule)
+ {
+ CAgnSystemTzRuleIndexItem* self = new (ELeave) CAgnSystemTzRuleIndexItem(aStreamId, aRule);
+ CleanupStack::PushL(self);
+ self->ConstructL(aTzId);
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+CAgnSystemTzRuleIndexItem::CAgnSystemTzRuleIndexItem() :
+ CAgnTzRuleIndexItem(), iTzId(NULL)
+ {
+ }
+
+CAgnSystemTzRuleIndexItem::CAgnSystemTzRuleIndexItem(TStreamId aStreamId,
+ CTzRules* aRules) :
+ CAgnTzRuleIndexItem(aStreamId, aRules), iTzId(NULL)
+ {
+ }
+
+CAgnSystemTzRuleIndexItem::~CAgnSystemTzRuleIndexItem()
+ {
+ delete iTzId;
+ }
+
+CAgnSystemTzRuleIndexItem* CAgnSystemTzRuleIndexItem::NewL(RReadStream& aStream)
+ {
+ CAgnSystemTzRuleIndexItem* self = new (ELeave) CAgnSystemTzRuleIndexItem();
+ CleanupStack::PushL(self);
+ self->InternalizeL(aStream);
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+const TDesC8& CAgnSystemTzRuleIndexItem::TzId() const
+ {
+ return *iTzId;
+ }
+
+void CAgnSystemTzRuleIndexItem::ExternalizeL(RWriteStream& aStream) const
+ {
+ CAgnTzRuleIndexItem::ExternalizeL(aStream);
+ aStream << *iTzId;
+ }
+
+void CAgnSystemTzRuleIndexItem::InternalizeL(RReadStream& aStream)
+ {
+ CAgnTzRuleIndexItem::InternalizeL(aStream);
+ iTzId = HBufC8::NewL(aStream, KMaxTInt);
+ }
+
+TBool CAgnSystemTzRuleIndexItem::IsSystemTzRule() const
+ {
+ return ETrue;
+ }
+
+/* ------------------- CAgnTzRuleIndex -------------------*/
+CAgnTzRuleIndex::CAgnTzRuleIndex(CStreamDictionary& aDictionary, CFileStore& aStore) :
+ iDictionary(&aDictionary),
+ iStore(&aStore),
+ iPosCurSystemTzRule(KErrNotFound),
+ iPosFetchedLastTime(0),
+ iTzDbChangeTimeStamp(Time::NullTTime()),
+ iTzRulesLastModifiedTime(Time::NullTTime())
+ {
+ }
+
+CAgnTzRuleIndex* CAgnTzRuleIndex::NewL(CStreamDictionary& aDictionary, CFileStore& aStore)
+ {
+ CAgnTzRuleIndex* self = new(ELeave) CAgnTzRuleIndex(aDictionary, aStore);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop();
+ return (self);
+ }
+
+void CAgnTzRuleIndex::ConstructL()
+ {
+ iTimeZoneAccessor = CAgnTlsProxy::CreateL(CAgnTlsProxy::TAgnTlsTzRulesType_Server);
+
+ iSystemRuleStreamId = ReadItemsFromStoreL(KUidAgnSystemTzIndex);
+ iUserDefinedRuleStreamId = ReadItemsFromStoreL(KUidAgnImportedTzIndex);
+
+ RTz& tzServer = iTimeZoneAccessor->TzServer();
+ CTzId* tzid = tzServer.GetTimeZoneIdL();
+ CleanupStack::PushL(tzid);
+ HandleCurrentTimeZoneChangeL(*tzid);
+ CleanupStack::PopAndDestroy(tzid);
+ }
+
+/* Read the time stamp of time zone database has been modified last time.
+
+- If the file is newly created, the time stamp will be set to current time
+- If the file is re-opened, read the time stamp from the file.
+- If the file is re-opened, but there isn't a time stamp, the time stamp will be set to current time
+ */
+void CAgnTzRuleIndex::ReadTimeStampL()
+ {
+ TStreamId streamId = iDictionary->At(KUidAgnTimeStamp);
+
+ if (streamId == KNullStreamId)
+ {//There is not a time stamp in the file either it is newly created or an existing one.
+ TTime currentTime;
+ currentTime.UniversalTime();
+ iTzDbChangeTimeStamp = currentTime;
+
+ if (RefreshTzRulesL())
+ {
+ iTzRulesLastModifiedTime = currentTime;
+ }
+ PersistToStoreL(KUidAgnTimeStamp);
+ }
+ else
+ {//iTzChangTimeStamp is read from file
+ ReadFromStoreL(KUidAgnTimeStamp, EFalse);
+ }
+ }
+
+/** Check if the time zone server has been modified since last time the
+ * Calendar server shut down. If so, the time zones of entries cached in the Calendar
+ * will be updated. Calendar clients will be also notified with the change if
+ * any of time zones associated with Calendar entries have been modified.
+ *
+ * This function is called when a Calendar file is opened.
+ *
+ */
+void CAgnTzRuleIndex::CheckTzDbModificationL(CAgnServFile& aAgnServFile)
+ {
+ iAgnFile = &aAgnServFile;
+ ReadTimeStampL();
+ //This will result in HandleTzRulesChangeL to be called immediatly if a tz change has been published.
+ iTimeZoneAccessor->AddSystemTimeObserverL(this);
+ }
+/*
+ Called when the file is closed. It will write the current time to the Calendar file.
+ */
+void CAgnTzRuleIndex::WriteTimeStampL()
+ {
+ TStreamId streamId = iDictionary->At(KUidAgnTimeStamp);
+ RStoreWriteStream writeStream;
+ writeStream.ReplaceLC(*iStore, streamId);
+ ExternalizeTimesL(writeStream);
+ writeStream.CommitL();
+ CleanupStack::PopAndDestroy(&writeStream);
+ iStore->CommitL();
+
+ }
+void CAgnTzRuleIndex::ExternalizeTimesL(RStoreWriteStream& aWriteStream) const
+ {
+ aWriteStream << I64LOW(iTzDbChangeTimeStamp.Int64());
+ aWriteStream << I64HIGH(iTzDbChangeTimeStamp.Int64());
+ aWriteStream << I64LOW(iTzRulesLastModifiedTime.Int64());
+ aWriteStream << I64HIGH(iTzRulesLastModifiedTime.Int64());
+ }
+
+void CAgnTzRuleIndex::InternalizeTimesL(RReadStream& aReadStream)
+ {
+ TUint32 low = aReadStream.ReadUint32L();
+ TUint32 high = aReadStream.ReadUint32L();
+ iTzDbChangeTimeStamp = TTime(MAKE_TINT64(high, low));
+
+ low = aReadStream.ReadUint32L();
+ high = aReadStream.ReadUint32L();
+ iTzRulesLastModifiedTime = TTime(MAKE_TINT64(high, low));
+ }
+
+/* Externalise an array of tz rules or a time stamp to first time Calendar file.
+
+ @param aUid refer to uid of object to write to the file.
+ @return Stream Id refer to the object being written to the file
+ */
+TStreamId CAgnTzRuleIndex::PersistToStoreL(const TUid& aUid)
+ {
+ RStoreWriteStream writeStream;
+ TStreamId streamId = writeStream.CreateLC(*iStore);
+ if (aUid == KUidAgnSystemTzIndex)
+ {
+ ExternalizeRulesL(writeStream, iSystemTzRules);
+ }
+ else
+ if (aUid == KUidAgnImportedTzIndex)
+ {
+ ExternalizeRulesL(writeStream, iUserDefinedTzRules);
+ }
+ else
+ {
+ __ASSERT_ALWAYS(aUid == KUidAgnTimeStamp,User::Invariant());
+ ExternalizeTimesL(writeStream);
+ }
+
+ writeStream.CommitL();
+ CleanupStack::PopAndDestroy(&writeStream);
+
+ iDictionary->AssignL(aUid, streamId);
+
+ // Re-write the dictionary stream
+ RStoreWriteStream stream;
+ TStreamId rootStreamId = iStore->Root();
+ stream.ReplaceLC(*iStore, rootStreamId);
+ stream<< *iDictionary;
+ stream.CommitL();
+ CleanupStack::PopAndDestroy(); // dictionary stream
+ iStore->CommitL();
+ return streamId;
+ }
+
+void CAgnTzRuleIndex::ReadFromStoreL(const TUid& aUid, TBool aRollback)
+ {
+ TStreamId streamId = iDictionary->At(aUid);
+ __ASSERT_ALWAYS(streamId != KNullStreamId, User::Leave(KErrNotFound));
+ RStoreReadStream readStream;
+ readStream.OpenLC(*iStore, streamId);
+ if (aUid == KUidAgnSystemTzIndex)
+ {
+ InternalizeRulesL(readStream, ETrue, aRollback);
+ }
+ else
+ if (aUid == KUidAgnImportedTzIndex)
+ {
+ InternalizeRulesL(readStream, EFalse, aRollback);
+ }
+ else
+ {
+ __ASSERT_ALWAYS(aUid==KUidAgnTimeStamp,User::Invariant());
+ InternalizeTimesL(readStream);
+ }
+
+ CleanupStack::PopAndDestroy(&readStream);
+ }
+
+TStreamId CAgnTzRuleIndex::ReadItemsFromStoreL(const TUid& aUid, TBool aRollback)
+ {
+ TStreamId streamId = iDictionary->At(aUid);
+
+ if (streamId == KNullStreamId)
+ {
+ streamId = PersistToStoreL(aUid);
+ }
+ else
+ {
+ ReadFromStoreL(aUid, aRollback);
+ }
+
+ return streamId;
+ }
+
+void CAgnTzRuleIndex::InternalizeRulesL(RReadStream& aStream,
+ TBool aIsSystemRule, TBool aRollback)
+ {
+ TInt count = aStream.ReadInt16L();
+ CAgnTzRuleIndexItem* item= NULL;
+ for (TInt ii=0; ii<count; ++ii)
+ {
+ if (aIsSystemRule)
+ {
+ item = CAgnSystemTzRuleIndexItem::NewL(aStream);
+ }
+ else
+ {
+ item = CAgnTzRuleIndexItem::NewL(aStream);
+ }
+
+ CleanupStack::PushL(item);
+ RStoreReadStream readStream;
+
+ readStream.OpenLC(*iStore, item->StreamId());
+ CTzRules* tzRules = CTzRules::NewL(readStream);
+ item->SetRule(tzRules);
+ CleanupStack::PopAndDestroy(&readStream);
+
+ if (aIsSystemRule)
+ {
+ if (aRollback)
+ {
+ CleanupStack::Pop(item);
+ RollbackItemL(iSystemTzRules, item);
+ }
+ else
+ {
+ iSystemTzRules.AppendL(item);
+ CleanupStack::Pop(item);
+ }
+ }
+ else
+ {
+ if (aRollback)
+ {
+ CleanupStack::Pop(item);
+ RollbackItemL(iUserDefinedTzRules, item);
+ }
+ else
+ {
+ iUserDefinedTzRules.AppendL(item);
+ CleanupStack::Pop(item);
+ }
+ }
+ }
+ }
+
+void CAgnTzRuleIndex::ExternalizeRulesL(RWriteStream& aStream, const RPointerArray<CAgnTzRuleIndexItem>& aArray) const
+ {
+ TInt count = aArray.Count();
+ aStream.WriteInt16L(count);
+
+ for (TInt ii=0; ii<count; ++ii)
+ {
+ aArray[ii]->ExternalizeL(aStream);
+ }
+ }
+
+CAgnTzRuleIndex::~CAgnTzRuleIndex()
+ {
+ iSystemTzRules.ResetAndDestroy();
+ iUserDefinedTzRules.ResetAndDestroy();
+ iTimeZoneAccessor->RemoveSystemTimeObserver(this);
+ CAgnTlsProxy::Release(iTimeZoneAccessor);
+ }
+
+/**
+ It is called when:
+
+ Creating a light entry during index building.
+ Fetch an entry
+
+ @param reference to the entry fetching tz rules
+ */
+void CAgnTzRuleIndex::FetchTzRuleL(CAgnSimpleEntry& aEntry)
+ {
+ CAgnTzRules* tzZone = GetTzRulesFromEntry(aEntry);
+ if (tzZone == NULL)
+ {
+ return;
+ }
+
+ TInt pos = KErrNotFound;
+ if (tzZone->SystemTzRule())
+ {
+ pos = FindTzRuleByStreamIdL(tzZone->TzZoneStreamId(), iSystemTzRules,
+ ETrue);
+ if (pos>=0)
+ {
+ tzZone->SetTzRules(iSystemTzRules[pos]->TzRule());
+ tzZone->SetUseCurrentSystemTzRules((pos == iPosCurSystemTzRule));
+ }
+ }
+ else
+ {
+ __ASSERT_DEBUG(!tzZone->UseCurrentSystemTzRules(), User::Invariant());
+ pos = FindTzRuleByStreamIdL(tzZone->TzZoneStreamId(),
+ iUserDefinedTzRules, ETrue);
+ if (pos>=0)
+ {
+ tzZone->SetTzRules(iUserDefinedTzRules[pos]->TzRule());
+ }
+ }
+
+ if (pos == KErrNotFound)
+ {
+ AddCurrentSystemTzRuleL(*tzZone);
+ }
+ }
+
+/**
+ Remove a tz rule from one of tz rule arraies
+
+ It should be called when an entry is removed or an entry is updated
+
+ @param reference to the entry to be deleted
+ */
+void CAgnTzRuleIndex::RemoveTzRuleL(CAgnSimpleEntry& aEntry)
+ {
+ CAgnTzRules* tzZone = GetTzRulesFromEntry(aEntry);
+ if (tzZone == NULL || !tzZone->HasValidTzZoneStreamId())
+ {
+ return;
+ }
+
+ TInt pos = KErrNotFound;
+ if (tzZone->SystemTzRule())
+ {
+ pos = FindTzRuleByStreamIdL(tzZone->TzZoneStreamId(), iSystemTzRules,
+ EFalse);
+ if (pos >=0)
+ {
+ DeleteARuleL(pos, iSystemTzRules, iSystemRuleStreamId);
+ }
+ }
+ else
+ {
+ pos = FindTzRuleByStreamIdL(tzZone->TzZoneStreamId(),
+ iUserDefinedTzRules, EFalse);
+ if (pos >=0)
+ {
+ DeleteARuleL(pos, iUserDefinedTzRules, iUserDefinedRuleStreamId);
+ }
+ }
+
+ __ASSERT_DEBUG(pos != KErrNotFound, Panic(EAgmErrTzRuleIsNotFound));
+
+ User::LeaveIfError(pos);
+ }
+
+/**
+ Add a tz rule to the array if it is not existing in the array otherwise
+ increase the refference count for that rule.
+
+ It is called when:
+
+ An entry is added with a user defined tz rule
+ An old format file (9.4 prior) is converted to a new format
+
+ @param reference to the entry to be added.
+ */
+void CAgnTzRuleIndex::AddTzRuleL(CAgnEntry& aEntry)
+ {
+ CAgnTzRules* tzZone = GetTzRulesFromEntry(aEntry);
+ if (tzZone == NULL)
+ {
+ return;
+ }
+
+ if (tzZone->TzRules() == NULL || tzZone->UseCurrentSystemTzRules())
+ {
+ AddCurrentSystemTzRuleL(*tzZone);
+ return;
+ }
+
+ TBool isSysRule = EFalse;
+ TInt pos = FindRule(*tzZone->TzRules(), isSysRule);
+ if (pos >= 0)
+ {
+ if (isSysRule)
+ {
+ iSystemTzRules[pos]->IncrementRef();
+ }
+ else
+ {
+ iUserDefinedTzRules[pos]->IncrementRef();
+ }
+
+ }
+ else
+ {
+ CTzRules* tzRule = tzZone->TzRules()->CloneL();
+ CleanupStack::PushL(tzRule);
+ TStreamId streamId = PersistTzRuleL(*tzRule);//It will not be commited until model commit the entry into the file
+ CAgnTzRuleIndexItem* item = CAgnTzRuleIndexItem::NewL(streamId, tzRule);
+ CleanupStack::Pop(tzRule);
+
+ CleanupStack::PushL(item);
+ iUserDefinedTzRules.AppendL(item);
+ pos = iUserDefinedTzRules.Count()-1;
+ CleanupStack::Pop(item);
+ }
+
+ if (isSysRule)
+ {
+ UpdateItemsInStoreL(iSystemTzRules, iSystemRuleStreamId);
+ tzZone->SetTzRules(iSystemTzRules[pos]->TzRule());
+ tzZone->SetSystemTzRule(ETrue);
+ tzZone->SetTzZoneStreamId(iSystemTzRules[pos]->StreamId());
+ }
+ else
+ {
+ UpdateItemsInStoreL(iUserDefinedTzRules, iUserDefinedRuleStreamId);
+ tzZone->SetTzRules(iUserDefinedTzRules[pos]->TzRule());
+ tzZone->SetSystemTzRule(EFalse);
+ tzZone->SetTzZoneStreamId(iUserDefinedTzRules[pos]->StreamId());
+ }
+ }
+
+/**
+ Called when entry's tz rule changed
+
+ @param aOldEntry reference to the original entry to be updated.
+ @param aNewEntry reference to the entry containing updated content.
+ */
+void CAgnTzRuleIndex::UpdateTzRuleL(CAgnEntry& aOldEntry, CAgnEntry& aNewEntry)
+ {
+ CAgnTzRules* newTzZone = GetTzRulesFromEntry(aNewEntry);
+ if (newTzZone != NULL && newTzZone->HasValidTzZoneStreamId())
+ {
+ TInt pos = KErrNotFound;
+ if (newTzZone->SystemTzRule())
+ {
+ pos = FindTzRuleByStreamIdL(newTzZone->TzZoneStreamId(), iSystemTzRules, EFalse);
+ iSystemTzRules[pos]->IncrementRef();
+ newTzZone->SetTzRules(iSystemTzRules[pos]->TzRule());
+ UpdateItemsInStoreL(iSystemTzRules, iSystemRuleStreamId);
+ }
+ else
+ {
+ pos = FindTzRuleByStreamIdL(newTzZone->TzZoneStreamId(), iUserDefinedTzRules, EFalse);
+ iUserDefinedTzRules[pos]->IncrementRef();
+ newTzZone->SetTzRules(iUserDefinedTzRules[pos]->TzRule());
+ UpdateItemsInStoreL(iUserDefinedTzRules, iUserDefinedRuleStreamId);
+ }
+
+ __ASSERT_DEBUG(pos !=KErrNotFound, Panic(EAgmErrTzRuleIsNotFound));
+ }
+ else
+ {
+ AddTzRuleL(aNewEntry);
+ }
+
+ RemoveTzRuleL(aOldEntry);
+ }
+
+void CAgnTzRuleIndex::UpdateItemsInStoreL(
+ RPointerArray<CAgnTzRuleIndexItem>& aArray, TStreamId aStreamId)
+ {
+ RStoreWriteStream writeStream;
+ writeStream.ReplaceLC(*iStore, aStreamId);
+ ExternalizeRulesL(writeStream, aArray);
+ writeStream.CommitL();
+ CleanupStack::PopAndDestroy(&writeStream);
+ }
+
+TInt CAgnTzRuleIndex::FindTzRuleByStreamIdL(TStreamId aStreamId, RPointerArray<CAgnTzRuleIndexItem>& aArray, TBool aTryPosLastTime)
+ {
+ TInt count = aArray.Count();
+ if (aTryPosLastTime && iPosFetchedLastTime >= 0 && count
+ > iPosFetchedLastTime)
+ {
+ if (aStreamId == aArray[iPosFetchedLastTime]->StreamId())
+ {
+ return iPosFetchedLastTime;
+ }
+ }
+
+ TInt pos = KErrNotFound;
+ TInt ii = 0;
+ while (pos == KErrNotFound && ii < count)
+ {
+ if (aStreamId == aArray[ii]->StreamId())
+ {
+ pos = ii;
+ }
+ ++ii;
+ }
+
+ if (aTryPosLastTime)
+ {
+ iPosFetchedLastTime = pos;
+ }
+
+ return pos;
+ }
+
+TInt CAgnTzRuleIndex::FindRule(RPointerArray<CAgnTzRuleIndexItem>& aRuleArray, const CTzRules& aRule)
+ {
+ TInt pos = KErrNotFound;
+ TInt count = aRuleArray.Count();
+ TInt ii = 0;
+ while (pos < 0 && ii<count)
+ {
+ if (aRule.IsEqualTo(*(aRuleArray[ii]->TzRule())))
+ {
+ pos = ii;
+ }
+ ++ii;
+ }
+
+ return pos;
+ }
+
+TInt CAgnTzRuleIndex::FindRule(const CTzRules& aTzRule, TBool& aIsSystemRule)
+ {
+ TInt pos = KErrNotFound;
+ pos = FindRule(iSystemTzRules, aTzRule);
+ if (pos>=0)
+ {
+ aIsSystemRule = ETrue;
+ }
+ else
+ {
+ pos = FindRule(iUserDefinedTzRules, aTzRule);
+ if (pos>=0)
+ {
+ aIsSystemRule = EFalse;
+ }
+ }
+ return pos;
+ }
+
+/**
+ Add the current system tz rule to the array if it is not there otherwise
+ increase the refference count for the rule.
+
+
+ It is called when:
+
+ An entry is added with the current tz rule
+ @param reference to a CAgnTzRules object which is added to the index
+ */
+void CAgnTzRuleIndex::AddCurrentSystemTzRuleL(CAgnTzRules& aTzZone)
+ {
+ if (iPosCurSystemTzRule >= 0)
+ {
+ iSystemTzRules[iPosCurSystemTzRule]->IncrementRef();
+ }
+ else
+ {
+ RTz& tzServer = iTimeZoneAccessor->TzServer();
+ CTzId* tzId = tzServer.GetTimeZoneIdL();
+ CleanupStack::PushL(tzId);
+ CTzRules* rule = tzServer.GetTimeZoneRulesL(*tzId, KMinYear, KMaxYear, ETzUtcTimeReference);
+ CleanupStack::PushL(rule);
+ TStreamId streamId = PersistTzRuleL(*rule);//It will not be commited until model commit the entry into the file
+ CAgnSystemTzRuleIndexItem* item = CAgnSystemTzRuleIndexItem::NewL(streamId, tzId->TimeZoneNameID(), rule);
+ CleanupStack::Pop(rule);
+ CleanupStack::PushL(item);
+ iSystemTzRules.AppendL(item);
+ iPosCurSystemTzRule = iSystemTzRules.Count()-1;
+ CleanupStack::Pop(item);
+
+ CleanupStack::PopAndDestroy(tzId);
+ }
+
+ UpdateItemsInStoreL(iSystemTzRules, iSystemRuleStreamId);
+ aTzZone.SetTzZoneStreamId(iSystemTzRules[iPosCurSystemTzRule]->StreamId());
+ aTzZone.SetTzRules(iSystemTzRules[iPosCurSystemTzRule]->TzRule());
+ aTzZone.SetSystemTzRule(ETrue);
+ aTzZone.SetUseCurrentSystemTzRules(ETrue);
+ }
+
+void CAgnTzRuleIndex::DeleteARuleL(TInt aPos, RPointerArray<CAgnTzRuleIndexItem>& aArray, TStreamId aStreamId)
+ {
+ TInt ref = aArray[aPos]->DecrementRef();
+ if (ref ==0)
+ {
+ iStore->DeleteL(aArray[aPos]->StreamId());
+ delete aArray[aPos];
+ aArray.Remove(aPos);
+
+ if (aPos == iPosCurSystemTzRule)
+ {
+ iPosCurSystemTzRule = KErrNotFound;
+ }
+ else if (aPos < iPosCurSystemTzRule)
+ {
+ --iPosCurSystemTzRule;
+ }
+ }
+
+ UpdateItemsInStoreL(aArray, aStreamId);
+ }
+
+TStreamId CAgnTzRuleIndex::PersistTzRuleL(const CTzRules& aTzRule)
+ {
+ TStreamId streamId = iStore->ExtendL();
+ RStoreWriteStream writeStream;
+ writeStream.ReplaceLC(*iStore, streamId);
+ aTzRule.ExternalizeL(writeStream);
+ writeStream.CommitL();//Don't commit to store until the CAgnEntryModel does it
+ CleanupStack::PopAndDestroy(&writeStream);
+ return streamId;
+ }
+
+void CAgnTzRuleIndex::HandleCurrentTimeZoneChangeL(const CTzId& aSystemTzId)
+ {
+ if (iPosCurSystemTzRule != KErrNotFound && 0 == static_cast<CAgnSystemTzRuleIndexItem*>(iSystemTzRules[iPosCurSystemTzRule])->TzId().Compare(aSystemTzId.TimeZoneNameID()))
+ {
+ //the rule doesn't change.
+ return;
+ }
+
+ CTzRules* rule = iTimeZoneAccessor->GetCurrentSystemTzRulesL();
+ CleanupStack::PushL(rule);
+ iPosCurSystemTzRule = FindRule(iSystemTzRules, *rule);
+ CleanupStack::PopAndDestroy(rule);
+ }
+
+void CAgnTzRuleIndex::HandleTzRulesChangeL(const TTime& aTime)
+ {
+ if(!iAgnFile->IsLocked())
+ {
+ if (iTzDbChangeTimeStamp < aTime)
+ {
+ iTzDbChangeTimeStamp = aTime;
+ if (RefreshTzRulesL())
+ {
+ iTzRulesLastModifiedTime = aTime;
+ }
+ WriteTimeStampL();
+ }
+ }
+ else // set the flag so that it can be done later when agendar server is unlocked.
+ {
+ iAgnFile->SetRefreshTzRules(ETrue);
+ }
+ }
+
+/* Refresh cached system tz rules and broadcast the change if any of rules has been updated
+ */
+TBool CAgnTzRuleIndex::RefreshTzRulesL()
+ {
+ TBool rulesChanged = EFalse;
+ const TInt KCount = iSystemTzRules.Count();
+ for (TInt ii = 0; ii<KCount; ++ii)
+ {
+ CTzId* id = CTzId::NewL(static_cast<CAgnSystemTzRuleIndexItem*>(iSystemTzRules[ii])->TzId());
+ CTzRules* rules= NULL;
+ TRAPD(err, rules = iTimeZoneAccessor->TzServer().GetTimeZoneRulesL(*id, KMinYear, KMaxYear , ETzUtcTimeReference));
+ delete id;
+ if(err == KErrNone)
+ {
+ CleanupStack::PushL(rules);
+ if (rules && !iSystemTzRules[ii]->TzRule()->IsEqualTo(*rules))
+ {//If a tz rule cached is different from the one in tz server for the same TZ ID, it needs to be updated with the new one.
+ CAgnTzRuleIndexItem* item = iSystemTzRules[ii];
+ item->TzRule()->CopyL(*rules);
+ RStoreWriteStream writeStream;
+ writeStream.ReplaceLC(*iStore, item->StreamId());
+ item->TzRule()->ExternalizeL(writeStream);
+ writeStream.CommitL();
+ CleanupStack::PopAndDestroy(&writeStream);
+ iStore->CommitL();
+ rulesChanged = ETrue;
+ }
+ CleanupStack::PopAndDestroy(rules);
+ }
+ }
+ if (rulesChanged)
+ {
+ iAgnFile->TzRulesHaveChangedL();
+ }
+ return rulesChanged;
+ }
+
+void CAgnTzRuleIndex::RollBackL()
+ {
+ ReadItemsFromStoreL(KUidAgnSystemTzIndex, ETrue);
+ ReadItemsFromStoreL(KUidAgnImportedTzIndex, ETrue);
+ }
+
+void CAgnTzRuleIndex::ReloadStore(CStreamDictionary& aDictionary, CFileStore& aStore)
+ {
+ iDictionary = &aDictionary;
+ iStore = &aStore;
+ }
+
+CTzRules* CAgnTzRuleIndex::FindTzRuleByStreamIdL(TStreamId aStreamId, TBool aIsSystemRule)
+ {
+ CTzRules* tzRules= NULL;
+ if (aIsSystemRule)
+ {
+ TInt pos = FindTzRuleByStreamIdL(aStreamId, iSystemTzRules, EFalse);
+ if (pos != KErrNotFound)
+ {
+ tzRules = iSystemTzRules[pos]->TzRule()->CloneL();
+ }
+ }
+ else
+ {
+ TInt pos = FindTzRuleByStreamIdL(aStreamId, iUserDefinedTzRules, EFalse);
+ if (pos != KErrNotFound)
+ {
+ tzRules = iUserDefinedTzRules[pos]->TzRule()->CloneL();
+ }
+ }
+
+ if (tzRules == NULL)
+ {
+ tzRules = iTimeZoneAccessor->GetCurrentSystemTzRulesL();
+ }
+
+ return tzRules;
+ }
+
+CAgnTzRules* CAgnTzRuleIndex::GetTzRulesFromEntry(CAgnSimpleEntry& aEntry)
+ {
+ CAgnTzRules* tzZone= NULL;
+ if (aEntry.TimeMode() != MAgnCalendarTimeMode::EFloating)
+ {
+ CAgnRptDef* rptDef = aEntry.RptDef();
+ if (rptDef != NULL)
+ {
+ tzZone = rptDef->AgnTzRules();
+ }
+ }
+
+ return tzZone;
+ }
+
+void CAgnTzRuleIndex::RollbackItemL(RPointerArray<CAgnTzRuleIndexItem>& aRuleArray, CAgnTzRuleIndexItem* aItem)
+ {
+ CleanupStack::PushL(aItem);
+ TInt pos = FindTzRuleByStreamIdL(aItem->StreamId(), aRuleArray, EFalse);
+ if (pos == KErrNotFound)
+ {
+ aRuleArray.AppendL(aItem);
+ CleanupStack::Pop(aItem);
+ }
+ else
+ {
+ CAgnTzRuleIndexItem* item = aRuleArray[pos];
+ item->SetReferenceCount(aItem->ReferenceCount());
+ CleanupStack::PopAndDestroy(aItem);
+ }
+ }
+
+/** Get the last modified time for tz rules
+ * It is called when the client getting the last modified date for an entry since the
+ * last modified time of an entry is not updated when tz database is updated.
+*/
+TTime CAgnTzRuleIndex::TzRulesLastModifiedDateL()
+ {
+ return iTzRulesLastModifiedTime;
+ }