sl@0: // Copyright (c) 2004-2010 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // sl@0: sl@0: #include sl@0: #include sl@0: #include sl@0: #include "LOGADD.H" sl@0: #include "logservpanic.h" sl@0: #include "LOGDUP.H" sl@0: #include "LOGQUERY.H" sl@0: #include "LogServRecentList.h" sl@0: #include "LogServDatabaseTransactionInterface.h" sl@0: #include "LogServResourceInterpreter.h" sl@0: #include "LogServCacheConfig.h" sl@0: #include "LogServDatabaseChangeInterface.h" sl@0: #include sl@0: #include "LogServCacheStrings.h" sl@0: #include "LogServCacheTypes.h" sl@0: #include "LOGREPDEFS.H" sl@0: sl@0: const TInt KMinimumNumberOfDigitsToMatch = 3; sl@0: sl@0: //////////////////////////////////////////////////////////////////////////////////////////// sl@0: // Local functions sl@0: sl@0: #ifdef SYSLIBS_TEST sl@0: sl@0: #pragma BullseyeCoverage off sl@0: sl@0: static void LogStore32IntL(RFs& aFs, const TDesC& aFilePath, TInt aVal) sl@0: { sl@0: RFile file; sl@0: User::LeaveIfError(file.Replace(aFs, aFilePath, EFileWrite)); sl@0: TPtrC8 p((const TUint8*)&aVal, sizeof(aVal)); sl@0: TInt err = file.Write(p); sl@0: if(err == KErrNone) sl@0: { sl@0: err = file.Flush(); sl@0: } sl@0: file.Close(); sl@0: User::LeaveIfError(err); sl@0: } sl@0: sl@0: static void LogStoreContactMatchCountAndNameFormatL(TInt aContactMatchCount, TLogContactNameFormat aContactNameFormat) sl@0: { sl@0: RFs fs; sl@0: CleanupClosePushL(fs); sl@0: User::LeaveIfError(fs.Connect()); sl@0: sl@0: _LIT(KTestDir, "c:\\test\\"); sl@0: TInt err = fs.MkDir(KTestDir); sl@0: if(err != KErrNone && err != KErrAlreadyExists) sl@0: { sl@0: User::Leave(err); sl@0: } sl@0: sl@0: _LIT(KLogengTestFileNameCount, "c:\\test\\test_logengconfig_count.ini"); sl@0: LogStore32IntL(fs, KLogengTestFileNameCount, aContactMatchCount); sl@0: sl@0: _LIT(KLogengTestFileNameFormat, "c:\\test\\test_logengconfig_format.ini"); sl@0: LogStore32IntL(fs, KLogengTestFileNameFormat, (TInt)aContactNameFormat); sl@0: sl@0: CleanupStack::PopAndDestroy(&fs); sl@0: } sl@0: sl@0: #pragma BullseyeCoverage on sl@0: sl@0: #endif //SYSLIBS_TEST sl@0: sl@0: //This function reads logeng repository file and returns the integer value of the given key. sl@0: static TInt LogGetRepositoryValueL(CRepository& aRepository, TInt aKey) sl@0: { sl@0: TInt val = -1; sl@0: User::LeaveIfError(aRepository.Get(aKey, val)); sl@0: return val; sl@0: } sl@0: sl@0: static void LogGetContactmatchCountAndNameFormatL(TInt& aContactMatchCount, TLogContactNameFormat& aContactNameFormat) sl@0: { sl@0: CRepository* repository = NULL; sl@0: TRAPD(err, repository = CRepository::NewL(KUidLogengRepository)); sl@0: if(err == KErrNone) sl@0: { sl@0: CleanupStack::PushL(repository); sl@0: aContactMatchCount = LogGetRepositoryValueL(*repository, KContactMatchCountRepKey); sl@0: aContactNameFormat = static_cast (LogGetRepositoryValueL(*repository, KContactNameFormatRepKey)); sl@0: CleanupStack::PopAndDestroy(repository); sl@0: } sl@0: else if(err == KErrCorrupt) sl@0: { sl@0: __ASSERT_DEBUG(!repository, User::Invariant()); sl@0: User::Leave(err); sl@0: } sl@0: else sl@0: { sl@0: __ASSERT_DEBUG(!repository, User::Invariant()); sl@0: aContactMatchCount = KLogContactMatchCount; sl@0: aContactNameFormat = KLogContactNameFormat; sl@0: } sl@0: #ifdef SYSLIBS_TEST sl@0: LogStoreContactMatchCountAndNameFormatL(aContactMatchCount, aContactNameFormat); sl@0: #endif sl@0: } sl@0: sl@0: //////////////////////////////////////////////////////////////////////////////////////////// sl@0: // CLogAddEvent class sl@0: sl@0: CLogAddEvent::CLogAddEvent(MLogServDatabaseTransactionInterface& aDatabase, TInt aPriority) : sl@0: CLogActive(aPriority), sl@0: iDatabase(aDatabase) sl@0: { sl@0: } sl@0: sl@0: CLogAddEvent::~CLogAddEvent() sl@0: { sl@0: Cancel(); sl@0: sl@0: CloseContactsPlugin(); sl@0: sl@0: delete iDuplicate; sl@0: delete iDuplicateFilter; sl@0: } sl@0: sl@0: CLogAddEvent* CLogAddEvent::NewL(MLogServDatabaseTransactionInterface& aDatabase, TInt aPriority) sl@0: { sl@0: CLogAddEvent* self = new(ELeave) CLogAddEvent(aDatabase, aPriority); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(); sl@0: CleanupStack::Pop(self); sl@0: return self; sl@0: } sl@0: sl@0: void CLogAddEvent::ConstructL() sl@0: { sl@0: iDuplicate = CLogDuplicate::NewL(iDatabase, Priority()); sl@0: iDuplicateFilter = CLogFilter::NewL(); sl@0: ::LogGetContactmatchCountAndNameFormatL(iContactMatchCount, iContactNameFormat); sl@0: } sl@0: sl@0: //This method will open contacts database (if not opened yet), only if the value of sl@0: //iContactMatchCount is not 0. sl@0: //Se how iContactMatchCount data member is initialised. sl@0: TBool CLogAddEvent::PerformContactMatchL() sl@0: { sl@0: if (iContactMatchCount <= 0 || iEvent->Contact() != KLogNullContactId) sl@0: return EFalse; sl@0: sl@0: if (iContactPlugin) sl@0: return ETrue; sl@0: sl@0: // Attempt to load plugin sl@0: TRAPD( err, iContactPlugin=CLogCntModel::NewL()); sl@0: sl@0: // If plugin doesn't exist this is equivalent to matching being disabled so we don't leave sl@0: // for KErrNotFound sl@0: if(err==KEComErrNoInterfaceIdentified) sl@0: { sl@0: // Disable contacts matching so that we don't keep attempting to match sl@0: iContactMatchCount = 0; sl@0: // Plugin doesn't exist sl@0: return EFalse; sl@0: } sl@0: sl@0: User::LeaveIfError(err); sl@0: sl@0: // Open the DB sl@0: OpenContactsL(); sl@0: sl@0: return ETrue; sl@0: } sl@0: sl@0: void CLogAddEvent::StartL(CLogEvent& aEvent, const CLogServRecentList* aRecentList, TRequestStatus& aStatus, const RMessage2& aMessage) sl@0: { sl@0: __ASSERT_ALWAYS(!IsActive(), Panic(ELogAlreadyActive1)); sl@0: sl@0: LOGTEXT("CLogAddEvent::StartL()"); sl@0: sl@0: // Store event details which were obtained from the client side sl@0: iEvent = &aEvent; sl@0: iState = ELogAddEvent; sl@0: sl@0: if (!iDatabase.DTIIsAllowed(EWriteOp, aMessage, iEvent->EventType())) sl@0: { sl@0: User::Leave(KErrPermissionDenied); sl@0: } sl@0: sl@0: if (PerformContactMatchL()) sl@0: iState = ELogSetContactAndRemoteParty; // Go look for a matching contact sl@0: sl@0: iRecentList = aRecentList; sl@0: iEventAdded = EFalse; sl@0: sl@0: // Setup the event's time (UTC) sl@0: TTime time; sl@0: time.UniversalTime(); sl@0: iEvent->SetTime(time); sl@0: sl@0: // Save the observer's request status and set it to KRequestPending sl@0: Queue(aStatus); sl@0: sl@0: // Start this objects RunL chain sl@0: TRequestStatus* status = &iStatus; sl@0: User::RequestComplete(status, KErrNone); sl@0: SetActive(); sl@0: } sl@0: sl@0: void CLogAddEvent::SetEventContact() sl@0: { sl@0: // Start by converting the phone number text into a number sl@0: // check we've got a long enough number to be worth checking sl@0: if(iEvent->Number().Length() >= KMinimumNumberOfDigitsToMatch) sl@0: { sl@0: // now search for a contact by looking up the phone number sl@0: TLogContactItemId contactId = KLogNullContactId; sl@0: TRAPD(err, contactId = iContactPlugin->MatchPhoneNumberL(iEvent->Number(), iContactMatchCount)); sl@0: sl@0: if(err == KErrNone) sl@0: { sl@0: // we have at least one match sl@0: if(contactId != KLogNullContactId) sl@0: { sl@0: // we have a match so set the contact id sl@0: iEvent->SetContact(contactId); sl@0: } sl@0: } sl@0: } sl@0: iEvent->SetFlags(KLogEventContactSearched); sl@0: } sl@0: sl@0: void CLogAddEvent::SetRemoteParty() sl@0: { sl@0: // Get the contact id sl@0: TLogContactItemId contactId = iEvent->Contact(); sl@0: if((contactId != KLogNullContactId) && (iEvent->RemoteParty().Length() == 0)) sl@0: { sl@0: // Look it up and get the remote party info sl@0: // Setup buffer to contain concatenated result sl@0: TBuf<128> buf; sl@0: // Go get the info sl@0: TRAPD(err, iContactPlugin->ReadContactNameL(contactId, buf, iContactNameFormat)); sl@0: sl@0: if(err == KErrNotFound) sl@0: { sl@0: // Couldn't find the contact with that id so set it to NULL sl@0: iEvent->SetContact(KLogNullContactId); sl@0: } sl@0: else sl@0: { sl@0: // Found it so fill in remote party sl@0: iEvent->SetRemoteParty(buf); sl@0: } sl@0: } sl@0: } sl@0: sl@0: void CLogAddEvent::GetConfigL() sl@0: { sl@0: iConfig = iDatabase.DTICacheConfig().Config(); sl@0: if(iConfig.iMaxLogSize == 0) sl@0: { sl@0: LOGTEXT("CLogAddEvent::DoRunL() - logging disabled"); sl@0: User::Leave(KErrNotSupported); sl@0: } sl@0: } sl@0: sl@0: TLogTypeId CLogAddEvent::SetDescriptionL() sl@0: { sl@0: const TLogServCacheTypeEntry& entry = iDatabase.DTICacheTypes().FindByUid(iEvent->EventType()); sl@0: if(entry.iEventTypeId == KLogNullTypeId) sl@0: { sl@0: LOGTEXT("CLogAddEvent::DoRunL() - type not found"); sl@0: User::Leave(KErrNotFound); sl@0: } sl@0: if(!entry.iEventType->LoggingEnabled()) sl@0: { sl@0: LOGTEXT("CLogAddEvent::DoRunL() - type not enabled"); sl@0: User::Leave(KErrNotSupported); sl@0: } sl@0: iEvent->SetDescription(entry.iEventType->Description()); sl@0: return entry.iEventTypeId; sl@0: } sl@0: sl@0: TBool CLogAddEvent::DetectDuplicateEventsL() sl@0: { sl@0: TBool rc = EFalse; sl@0: if(iRecentList) sl@0: { sl@0: iRecentList->GetFilter(*iEvent, *iDuplicateFilter); sl@0: rc = iDuplicate->StartL(iEvent->Id(), iRecentList->Id(), *iDuplicateFilter, iStatus); sl@0: } sl@0: return rc; sl@0: } sl@0: sl@0: void CLogAddEvent::DoRunL() sl@0: { sl@0: LOGTEXT3("CLogAddEvent::DoRunL(%d), state = %d", iStatus.Int(), iState); sl@0: sl@0: switch (iState) sl@0: { sl@0: case ELogSetContactAndRemoteParty: sl@0: { sl@0: SetEventContact(); sl@0: SetRemoteParty(); sl@0: TRequestStatus* status = &iStatus; sl@0: User::RequestComplete(status, KErrNone); sl@0: iState = ELogAddEvent; sl@0: SetActive(); sl@0: break; sl@0: } sl@0: case ELogAddEvent: sl@0: { sl@0: GetConfigL(); sl@0: TLogTypeId typeId = SetDescriptionL(); sl@0: RLogEventDbTable tbl; sl@0: tbl.OpenLC(iDatabase.DTIDatabase()); sl@0: ::LogPurgeMainL(iDatabase, tbl, iConfig.iMaxLogSize, 1); sl@0: DoAddEventL(tbl, typeId, iDatabase.DTICacheStrings().GetIdL(iEvent->Direction()), iDatabase.DTICacheStrings().GetIdL(iEvent->Status())); sl@0: CleanupStack::PopAndDestroy();//tbl sl@0: iEventAdded = ETrue; sl@0: if(DetectDuplicateEventsL()) sl@0: { sl@0: iState = ELogPurgeRecent; sl@0: SetActive(); sl@0: break; sl@0: } sl@0: iState = ELogPurgeRecent; sl@0: TRequestStatus* status = &iStatus; sl@0: User::RequestComplete(status, KErrNone); sl@0: SetActive(); sl@0: break; sl@0: } sl@0: case ELogPurgeRecent: sl@0: { sl@0: // Delete old recent events sl@0: if (iRecentList) sl@0: { sl@0: RArray logIds; sl@0: ::LogGetRecentEventsLC(iDatabase, iRecentList->Id(), iConfig.iMaxRecentLogSize, logIds); sl@0: ::LogPurgeRecentEventsL(iDatabase, logIds); sl@0: CleanupStack::PopAndDestroy(&logIds); sl@0: } sl@0: } sl@0: break; sl@0: default: sl@0: __ASSERT_DEBUG(ETrue, Panic(ELogBadState1)); sl@0: break; sl@0: } sl@0: sl@0: LOGTEXT("CLogAddEvent::DoRunL() - end"); sl@0: } sl@0: sl@0: void CLogAddEvent::DoCancel() sl@0: { sl@0: iDuplicate->Cancel(); sl@0: CLogActive::DoCancel(); sl@0: } sl@0: sl@0: void CLogAddEvent::DoAddEventL(RLogEventDbTable& aTbl, TLogTypeId aTypeId, TLogStringId aDirectionId, TLogStringId aStatusId) sl@0: { sl@0: LOGTEXT("CLogAddEvent::DoAddEventL()"); sl@0: sl@0: // Insert a new record sl@0: aTbl.InsertL(); sl@0: sl@0: aTbl.SetColL(RLogEventDbTable::iTypeColNo, (TUint32)aTypeId); sl@0: sl@0: if (iEvent->RemoteParty().Length() > 0) sl@0: aTbl.SetColL(RLogEventDbTable::iRemotePartyColNo, iEvent->RemoteParty()); sl@0: sl@0: if (iEvent->Direction().Length() > 0) sl@0: aTbl.SetColL(RLogEventDbTable::iDirectionColNo, (TUint32)aDirectionId); sl@0: sl@0: aTbl.SetColL(RLogEventDbTable::iTimeColNo, iEvent->Time()); sl@0: aTbl.SetColL(RLogEventDbTable::iDurationTypeColNo, (TInt32)iEvent->DurationType()); sl@0: sl@0: if (iEvent->DurationType() != KLogNullDurationType) sl@0: aTbl.SetColL(RLogEventDbTable::iDurationColNo, iEvent->Duration()); sl@0: sl@0: if (iEvent->Status().Length() > 0) sl@0: aTbl.SetColL(RLogEventDbTable::iStatusColNo, (TUint32)aStatusId); sl@0: sl@0: if (iEvent->Subject().Length() > 0) sl@0: aTbl.SetColL(RLogEventDbTable::iSubjectColNo, iEvent->Subject()); sl@0: sl@0: if (iEvent->Number().Length() > 0) sl@0: aTbl.SetColL(RLogEventDbTable::iNumberColNo, iEvent->Number()); sl@0: sl@0: if (iEvent->Contact() != KLogNullContactId) sl@0: aTbl.SetColL(RLogEventDbTable::iContactColNo, iEvent->Contact()); sl@0: sl@0: if (iEvent->Link() != KLogNullLink) sl@0: aTbl.SetColL(RLogEventDbTable::iLinkColNo, iEvent->Link()); sl@0: sl@0: if (iEvent->Data().Length() > 0) sl@0: aTbl.SetColL(RLogEventDbTable::iDataColNo, iEvent->Data()); sl@0: sl@0: // Set the flags sl@0: TInt bit = KLogFlagsCount; sl@0: while(bit--) sl@0: { sl@0: aTbl.SetColL(RLogEventDbTable::iFlagColNo[bit], (TUint32)((iEvent->Flags() & 0x1 << bit) ? 1 : 0)); sl@0: } sl@0: sl@0: if (iRecentList) sl@0: { sl@0: __ASSERT_DEBUG(iRecentList->Id() != KLogNullRecentList, Panic(ELogNullRecentList)); sl@0: aTbl.SetColL(RLogEventDbTable::iRecentColNo, (TInt32)iRecentList->Id()); sl@0: } sl@0: sl@0: #ifdef SYMBIAN_ENABLE_EVENTLOGGER_DUALSIM sl@0: if(iEvent->SimId() != KLogNullSimId) sl@0: { sl@0: aTbl.SetColL(RLogEventDbTable::iSimIdColNo, iEvent->SimId()); sl@0: } sl@0: else sl@0: { sl@0: aTbl.SetColNullL(RLogEventDbTable::iSimIdColNo); sl@0: } sl@0: #endif sl@0: sl@0: // Assign event id and end the rowset operation sl@0: const TLogId newId = aTbl.ColInt32(RLogEventDbTable::iIdColNo); sl@0: iEvent->SetId(newId); sl@0: aTbl.PutL(); sl@0: sl@0: // Tell change interface about the addition sl@0: iDatabase.DTIChangeInterface().DCISubmitChangedEventContextL(ELogChangeTypeEventAdded, newId); sl@0: sl@0: LOGTEXT("CLogAddEvent::DoAddEventL() - end"); sl@0: } sl@0: sl@0: void CLogAddEvent::DoComplete(TInt& aStatus) sl@0: { sl@0: LOGTEXT2("CLogAddEvent::DoComplete(%d)", aStatus); sl@0: sl@0: if (iDatabase.DTIInTransaction()) sl@0: { sl@0: LOGTEXT2("CLogAddEvent::DoComplete() - in transaction: %d", aStatus); sl@0: if (aStatus == KErrNone) sl@0: aStatus = iDatabase.DTICommitAndEnd(); sl@0: sl@0: LOGTEXT2("CLogAddEvent::DoComplete() - checking for need to rollback: %d", aStatus); sl@0: if (aStatus < KErrNone) sl@0: iDatabase.DTIRollBack(); sl@0: } sl@0: else sl@0: { sl@0: if (iEventAdded) sl@0: aStatus = KErrNone; sl@0: } sl@0: sl@0: LOGTEXT2("CLogAddEvent::DoComplete() - final status value is: %d", aStatus); sl@0: } sl@0: sl@0: //Opens the default contacts database. sl@0: void CLogAddEvent::OpenContactsL() sl@0: { sl@0: //Sometimes, after a sequence of OpenContactsL()/CloseContacts() calls the Contacts server crashes sl@0: //and OpenContactsL() leaves with error -15. In order to avoid that the following delay has been added. sl@0: //(something related to Contacts server state machine) sl@0: User::After(1000); sl@0: // Attempt to open DB sl@0: TRAPD(err,iContactPlugin->OpenContactsL()); sl@0: if(KErrNone!=err) sl@0: { sl@0: if(err == KErrServerTerminated) sl@0: { sl@0: RDebug::Print(_L("+++LogEng, LogAdd.cpp, Contacts server crashed!\r\n")); sl@0: } sl@0: // If DB doesn't open delete plugin sl@0: delete iContactPlugin; sl@0: iContactPlugin = NULL; sl@0: User::Leave(err); sl@0: } sl@0: } sl@0: sl@0: //Closes the default contacts database and deletes the plugin. sl@0: void CLogAddEvent::CloseContactsPlugin() sl@0: { sl@0: if(iContactPlugin) sl@0: { sl@0: iContactPlugin->CloseContacts(); sl@0: delete iContactPlugin; sl@0: iContactPlugin = NULL; sl@0: //REComSession::FinalClose() call moved here from logcntmodel.cpp. sl@0: //The in-source documentation of REComSession::FinalClose() notes that: sl@0: //"It must never be called from within a plug-in implementations class sl@0: //destructor, especially following a DestroyImplementation() ". sl@0: //That was the case before the function call was moved here. sl@0: REComSession::FinalClose(); sl@0: } sl@0: }