phoneengine/loghandling/src/cpeloghandling.cpp
changeset 0 5f000ab63145
child 9 8871b09be73b
child 21 92ab7f8d0eab
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/phoneengine/loghandling/src/cpeloghandling.cpp	Mon Jan 18 20:18:27 2010 +0200
@@ -0,0 +1,844 @@
+/*
+* Copyright (c) 2003-2006 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:  This file contains the implementation of CPELogHandling class 
+*                member functions.
+*
+*/
+
+
+
+//  INCLUDE FILES
+#include <spsettings.h>
+#include <spproperty.h>
+#include <telloggingextension.h>
+#include <ecom.h> 
+#include "cpeloghandling.h"
+#include "cpelogevent.h"
+#include "cpeloghandlingcommand.h"
+#include "cpelogexternaldata.h"
+#include <talogger.h>
+#include <logcli.h>
+#include <pepanic.pan>
+#include <mpephonemodelinternal.h>
+#include <mpedatastore.h>
+#include "cpeloginfo.h"
+#include "cpelogextensionwrapper.h"
+
+// EXTERNAL DATA STRUCTURES
+// None
+
+// EXTERNAL FUNCTION PROTOTYPES  
+/// None
+
+// CONSTANTS
+// None
+
+// MACROS
+// None
+
+// LOCAL CONSTANTS AND MACROS
+// None
+
+// MODULE DATA STRUCTURES
+// None
+
+// LOCAL FUNCTION PROTOTYPES
+// None
+
+// -----------------------------------------------------------------------------
+// CPELogHandling::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+MPELogHandling* CPELogHandling::NewL
+        ( 
+        MPEPhoneModelInternal& aModel,        // Owner of the object
+        RFs& aFsSession                       // Handle to a file server session
+        )  
+    {
+    TEFLOGSTRING(KTAOBJECT, "LOG CPELogHandling::NewL start.");
+    CPELogHandling* self = 
+        new ( ELeave ) CPELogHandling( aModel, aFsSession );
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop( self );
+    TEFLOGSTRING(KTAOBJECT, "LOG CPELogHandling::NewL complete.");
+    return self;
+    }
+ 
+// -----------------------------------------------------------------------------
+// CPELogHandling::~CPELogHandling
+// Destructor.
+// -----------------------------------------------------------------------------
+//
+/*****************************************************
+*    Series 60 Customer / LOGENG
+*    Series 60  LOGENG API
+*****************************************************/
+EXPORT_C CPELogHandling::~CPELogHandling()
+    {
+    TEFLOGSTRING( KTAOBJECT, "LOG CPELogHandling::~CPELogHandling" );
+    
+    delete iLogExternalData;
+
+    iFreeLogEventArray.ResetAndDestroy();
+    iActiveLogEventArray.ResetAndDestroy();
+    // All created CPELogEvent objects must be either in Free or Active array
+    // That is, it would be error to destroy objects in queued array.
+    iQueuedLogEventArray.Reset();
+    iActiveCallIds.Close();
+
+    delete iLogHandlingCommand;
+    delete iLogClient;
+    iPlugins.ResetAndDestroy();
+    REComSession::FinalClose();
+    }
+    
+// -----------------------------------------------------------------------------
+// CPELogHandling::CPELogHandling
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CPELogHandling::CPELogHandling
+        ( 
+        MPEPhoneModelInternal& aModel,
+        RFs& aFsSession        
+        ) : iModel( aModel ),
+            iDataStore( *( aModel.DataStore( ) ) ),
+            iFsSession( aFsSession ),
+            iLogEventUnderProcessing( NULL )
+    {
+    TEFLOGSTRING( KTAOBJECT, "LOG CPELogHandling::CPELogHandling" );
+    }
+
+// -----------------------------------------------------------------------------
+// CPELogHandling::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+/*****************************************************
+*    Series 60 Customer / LOGENG
+*    Series 60  LOGENG API
+*****************************************************/
+void CPELogHandling::ConstructL()
+    {
+    TEFLOGSTRING( KTAOBJECT, "LOG CPELogHandling::ConstructL" );
+    // Create new instace of the Log Client
+    iLogClient = CLogClient::NewL( iFsSession ); 
+
+    // Enumeration for incoming call, get from database 
+    User::LeaveIfError( iLogClient->GetString( iLogStringIn, R_LOG_DIR_IN ) ); 
+    // Enumeration for outgoing call, get from database 
+    User::LeaveIfError( iLogClient->GetString( iLogStringOut, R_LOG_DIR_OUT ) );   
+    // Enumeration for missed call, get from database
+    User::LeaveIfError( iLogClient->GetString( iLogStringMissed, R_LOG_DIR_MISSED ) );   
+    // Enumeration for delivery call, get from database  
+    User::LeaveIfError( iLogClient->GetString( iLogStringDelivery, R_LOG_DEL_NONE ) ); 
+    // Enumeration for incoming auxiliary line, get from database 
+    User::LeaveIfError( iLogClient->GetString( iLogStringInAlt, R_LOG_DIR_IN_ALT ) );   
+    // Enumeration for outgoing auxiliary line, get from database  
+    User::LeaveIfError( iLogClient->GetString( iLogStringOutAlt, R_LOG_DIR_OUT_ALT ) );
+    // Enumeration for unknown name, get from database  
+    User::LeaveIfError( iLogClient->GetString( iLogStringUnknown, R_LOG_REMOTE_UNKNOWN ) );
+      
+    iLogHandlingCommand = new (ELeave) CPELogHandlingCommand( *this, *iLogClient );
+ 
+    // Reserve some log events here. We delete these log event objects only on the destructor.
+    for( TInt entryIndex = 0; entryIndex < KPEMaximumNumberOfLogEvents; entryIndex++ )
+        {
+        CPELogEvent* logEvent = CPELogEvent::NewL( *this, *iLogHandlingCommand );
+        CleanupStack::PushL( logEvent );
+        iFreeLogEventArray.AppendL( logEvent );
+        CleanupStack::Pop( logEvent );
+        }
+    // Compress free log event array as it would never contain more objects than create here
+    iFreeLogEventArray.Compress( );
+
+    iLogExternalData = CPELogExternalData::NewL( *this );
+    }
+
+// -----------------------------------------------------------------------------
+// CPELogHandling::SaveCallEntry
+// Creates log info and initiates saving call log info by calling SaveCallInfoL.
+// Do log handling cleanup in case of a leave.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TInt CPELogHandling::SaveCallEntry
+        ( 
+        const TInt aCallId
+        )
+    {
+    TInt errorCode( KErrArgument );
+    if ( CallIdCheck::IsVoice( aCallId ) || 
+         CallIdCheck::IsVideo( aCallId )
+       ) 
+        {
+		CPELogInfo* logInfo( NULL );
+        TRAP( errorCode, logInfo = CPELogInfo::NewL(); );
+            
+        if ( logInfo )
+            {
+            // continue gathering log data
+            
+		    // set phonenumber and/or voip address
+			SetRemoteContact( aCallId, *logInfo );
+            logInfo->SetEventData( aCallId, iDataStore ); 
+            TRAP_IGNORE( 
+                // Contact link can be big, not critical for basic functionality.
+                if ( &iDataStore.ContactId( aCallId ) )
+                    {
+                    // Pack and add link
+                    HBufC8* buf( iDataStore.ContactId( aCallId ).PackLC() );
+                    TEFLOGSTRING( KTAINT, "Contact id packed" );
+                    logInfo->SetContactLink( buf ); 
+                    CleanupStack::Pop( buf );
+                    }
+                // default logging strategy is used if error happens while using extension
+                UpdateLogInfoWithExtensionDataL( aCallId, *logInfo ) );
+            
+            TRAP( errorCode, SaveCallInfoL( *logInfo ) );
+            delete logInfo;
+            }
+        
+        if( errorCode != KErrNone )
+            {
+            DoCleanup();
+            }
+        }
+    return errorCode;
+    }
+
+// -----------------------------------------------------------------------------
+// CPELogHandling::SendMessage
+// Method reroutes messages from other modules to the CPEPho-object
+// Note that it does not use base class SendMessage.
+// -----------------------------------------------------------------------------
+//
+void CPELogHandling::SendMessage
+        ( 
+        const MEngineMonitor::TPEMessagesFromPhoneEngine aMessage, // The message id number of the message.
+        TInt aErrorCode
+        )
+    {
+    if ( aMessage == MEngineMonitor::EPEMessageLogEventSaved )
+        {
+        TEFLOGSTRING( KTAINT, "LOG CPELogHandling::SendMessage(), Log event saved" );                        
+        
+        if (aErrorCode == KErrNone )
+            {
+            // flag event entry as added; next event is to be just entry update.
+            iLogEventUnderProcessing->SetAdded( );
+            }
+        
+        if ( iLogEventUnderProcessing->IsCompleted( ) )
+            {
+            TEFLOGSTRING( KTAINT, "LOG CPELogHandling::SendMessage(), Log entry completed" );                       
+                       
+            DeleteArrayEntry( iLogEventUnderProcessing );
+            }
+
+        // Indicate that no processing of log event is in progress
+        iLogEventUnderProcessing = NULL;            
+            
+        if ( iQueuedLogEventArray.Count( ) > 0 )
+            {
+            TEFLOGSTRING( KTAINT, "LOG CPELogHandling::SendMessage(), Executing queued request" );
+            
+            CPELogEvent* logEvent = iQueuedLogEventArray[0];
+            iQueuedLogEventArray.Remove( 0 );
+            iLogEventUnderProcessing = logEvent;
+            TRAPD( error, logEvent->SaveL( ) );
+            if ( error != KErrNone )
+                {
+                DoCleanup();
+                }
+            }
+        }
+    else
+        {
+        TEFLOGSTRING2( KTAINT, "LOG CPELogHandling::SendMessage(), Message %d not supported", aMessage );
+        }   
+    }
+        
+// -----------------------------------------------------------------------------
+// CPELogHandling::LogStringIn
+// Get log string.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TLogString& CPELogHandling::LogStringIn
+        (
+        // None
+        )
+    {
+    return iLogStringIn;
+    }
+
+// -----------------------------------------------------------------------------
+// CPELogHandling::LogStringOut
+// Get log string.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TLogString& CPELogHandling::LogStringOut
+        (
+        // None
+        )
+    {
+    return iLogStringOut;
+    }
+    
+// -----------------------------------------------------------------------------
+// CPELogHandling::LogStringMissed
+// Get log string.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TLogString& CPELogHandling::LogStringMissed
+        (
+        // None
+        )
+    {
+    return iLogStringMissed;
+    }
+    
+// -----------------------------------------------------------------------------
+// CPELogHandling::LogStringIn
+// Get log string.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TLogString& CPELogHandling::LogStringDelivery
+        (
+        // None
+        )
+    {
+    return iLogStringDelivery;
+    }        
+
+// -----------------------------------------------------------------------------
+// CPELogHandling::LogStringIn
+// Get log string.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TLogString& CPELogHandling::LogStringInAlt
+        (
+        // None
+        )
+    {
+    return iLogStringInAlt;
+    }
+
+// -----------------------------------------------------------------------------
+// CPELogHandling::LogStringOutAlt
+// Get log string.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TLogString& CPELogHandling::LogStringOutAlt
+        (
+        // None
+        )
+    {
+    return iLogStringOutAlt;
+    }
+
+// -----------------------------------------------------------------------------
+// CPELogHandling::LogStringUnknown
+// Get log string.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TLogString& CPELogHandling::LogStringUnknown
+        (
+        // None
+        )
+    {
+    return iLogStringUnknown;
+    }
+
+// -----------------------------------------------------------------------------
+// CPELogHandling::SetRemoteContact
+// -----------------------------------------------------------------------------
+//
+void CPELogHandling::SetRemoteContact( TInt aCallId, CPELogInfo& aLogInfo )
+    {
+    aLogInfo.SetVoipAddress( KNullDesC() );
+    
+    if ( iDataStore.CallDirection( aCallId ) 
+            == RMobileCall::EMobileOriginated )
+        {
+        TEFLOGSTRING2(KTAINT, 
+            "LOG CPELogHandling::CreateLogInfo, WholeOutgoingPhoneNumber, aCallId: %d"
+            , aCallId )
+        aLogInfo.SetPhoneNumber( iDataStore.WholeOutgoingPhoneNumber( aCallId ) );
+        }
+    else
+        {
+        aLogInfo.SetPhoneNumber( iDataStore.RemotePhoneNumber( aCallId ) );
+        }
+    
+    if ( EPECallTypeVoIP == iDataStore.CallType( aCallId ) )
+        {
+        // voip address field must be used for voip calls
+        aLogInfo.SetVoipAddress( aLogInfo.PhoneNumber() );
+        aLogInfo.SetPhoneNumber( KNullDesC() );
+        }
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPELogHandling::SaveCallInfoL
+// Update log external data.
+// Call SaveEventL if event should be saved to log db.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CPELogHandling::SaveCallInfoL
+        ( 
+        const CPELogInfo& aLogInfo // Call information
+        )
+    {
+    TEFLOGSTRING3( KTAINT, "LOG CPELogHandling::SaveCallInfoL(), [CallID: %d], [CallState: %d]", aLogInfo.CallId(), aLogInfo.CallState() );
+    
+    if ( EPEStateConnected == aLogInfo.CallState() )
+        {
+        // Insert the call ID to the active call array when the call state is connected.
+        TInt err = iActiveCallIds.InsertInOrder( aLogInfo.CallId() );
+        if ( err != KErrAlreadyExists )
+            {
+            User::LeaveIfError( err );
+            }
+        
+        // Only for the first call set the first call start time
+        if ( iActiveCallIds.Count() == 1 )
+            {
+            // For Last active call timer. See end part of UpdateLastCallTimer.
+            iLogExternalData->SetFirstCallStartTime( aLogInfo.CallStartTime() );
+            }
+  
+        // We have already store the start time to log database on dialling/ringing state,
+        // but this is the real start time of call.
+        TBuf<KPEESDWFormattedTimeLength> formattedTime;
+        formattedTime.Zero();
+        aLogInfo.CallStartTime().FormatL( formattedTime, KPEESDWTimeFormat ); 
+        TEFLOGSTRING2( KTAINT, "LOG CPELogHandling::SaveCallInfoL() Connected state iCallStartTime > formattedTime: %S", &formattedTime );
+        }
+    else
+        {
+        // logsEntry handling only on Dialling/Ringing and Idle states.
+        if ( EPEStateIdle == aLogInfo.CallState() )
+            {          
+            iLogExternalData->UpdateCallTimers( aLogInfo );
+            if ( aLogInfo.MissedCall() )  
+                {
+                iLogExternalData->IncreaseMissedCallValue( aLogInfo.CallId() );
+                }
+
+            TInt index = iActiveCallIds.FindInOrder( aLogInfo.CallId() );
+            if ( index >= 0 )
+                {
+                // When a call is disconnected, its ID is removed from the active call array.
+                iActiveCallIds.Remove( index );
+                iLogExternalData->UpdateLastCallTimerByLine( aLogInfo );
+                if ( iActiveCallIds.Count() == 0 )
+                    {
+                    TInt duration = iLogExternalData->UpdateLastCallTimer( aLogInfo );
+                    iModel.DataStore()->SetCallDuration( duration );
+                    }
+                }
+            }
+        if ( aLogInfo.LoggingEnabled() ) 
+            {
+            // We log all voice calls and the following data/fax calls to Log database
+            // MO external Data calls,
+            // MO external Fax calls,
+            // MT external Data calls
+            // MT external Fax calls,
+            // MT internal Data calls,
+            // We don't log the following data/fax calls to Log database
+            // MO internal Data calls
+            // MO internal Fax calls,
+            // MT internal Fax calls, 
+            // these are logged by CSD agent.
+            // But we have to update timers for these calls.            
+            
+            SaveEventL( aLogInfo );
+            }
+        }
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPELogHandling::SaveEventL
+// Update log database entry for an event. Manages event queueing.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CPELogHandling::SaveEventL
+        ( 
+        const CPELogInfo& aLogInfo  // Log information
+        ) 
+    {
+    TInt index;
+    CPELogEvent* logEvent;
+    
+    
+    index = FindEventIndexById( aLogInfo.CallId() ); 
+    if ( index == KErrNotFound ) 
+        {
+        // a log event object can't be reused;  
+        TEFLOGSTRING2( KTAINT, "LOG CPELogHandling::SaveEventL(), [CallID: %d]",aLogInfo.CallId() );
+        TEFLOGSTRING2( KTAINT, "LOG CPELogHandling::SaveEventL(), [CallDirection: %d]", aLogInfo.CallDirection() );
+
+        if ( iFreeLogEventArray.Count() > 0 )
+            {
+            // reuse an already created object from the array of the freed log event objects
+            logEvent = iFreeLogEventArray[ 0 ];
+            iFreeLogEventArray.Remove( 0 );
+            }
+        else 
+            {
+            // create a new object; none available to be reused
+            logEvent = CPELogEvent::NewL( *this, *iLogHandlingCommand );
+            }
+            
+        CleanupStack::PushL( logEvent );
+        iActiveLogEventArray.AppendL( logEvent );
+        CleanupStack::Pop( logEvent );            
+        }
+    else
+        {
+        // the log event object is already active but not completed. reuse it.
+        logEvent = iActiveLogEventArray[ index ];
+        }
+        
+    __ASSERT_ALWAYS( logEvent, Panic(EPEPanicNullPointer) );
+        
+
+    // Save logInfo for possible queueing.
+    logEvent->UpdateLogInfoL( aLogInfo );
+       
+    if ( iLogEventUnderProcessing )
+        {
+        // queueing can not be done per event because log client
+        // would fail if new request is sent before the previous one
+        // has been processed even if they are for two different events.
+        // See Symbian doc for more details.
+        if ( iQueuedLogEventArray.Find( logEvent ) == KErrNotFound )  
+            {
+            TEFLOGSTRING( KTAINT, "LOG CPELogHandling::SaveEventL(), AO busy, request queued" );                
+            // queue the updated event only if event is not already queued
+            TInt error = iQueuedLogEventArray.Append( logEvent );
+            if ( error != KErrNone )
+                {
+                TEFLOGSTRING( KTAERROR, "LOG CPELogHandling::SaveEventL(), Append to QueuedArray failed!" );
+                TEFLOGSTRING( KTAERROR, "LOG CPELogHandling::SaveEventL(), WARNING: Array Entry will be deleted to prevent memory leak." );
+                       
+                DeleteArrayEntry( logEvent );
+                
+                User::LeaveIfError( error );
+                }
+            }
+        else // the existing queued request will be executed with updated info
+            {
+            TEFLOGSTRING( KTAINT, "LOG CPELogHandling::SaveEvent(), AO busy, queued request already exists" );
+            }
+        }   
+    else
+        {
+        iLogEventUnderProcessing = logEvent;
+        logEvent->SaveL( );            
+        }
+    }
+    
+// -----------------------------------------------------------------------------
+// CPELogsHandling::FindEventIndexById
+// Find index number from array with given callid.
+// -----------------------------------------------------------------------------
+//
+TInt CPELogHandling::FindEventIndexById
+        ( 
+        const TInt aCallId // Call identification number
+        )
+    {
+    TEFLOGSTRING( KTAINT, 
+        "Log Handling: CPELogHandling::FindEventIndexById() - 1" );
+    for( TInt index = 0; index < iActiveLogEventArray.Count(); index++ )
+        { 
+        TEFLOGSTRING( KTAINT, 
+            "Log Handling: CPELogHandling::FindEventIndexById() - 2" );        
+        if( (iActiveLogEventArray[ index ]->CallId() == aCallId) &&
+            !(iActiveLogEventArray[ index ]->IsCompleted()) )
+            {
+            TEFLOGSTRING( KTAINT, 
+                "LOG CPELogHandling::FindEventIndexById() - 3" );
+            return index;
+            }
+        }
+    TEFLOGSTRING( KTAINT, 
+        "LOG CPELogHandling::FindEventIndexById() - 4" );
+    return KErrNotFound;
+    }
+
+// -----------------------------------------------------------------------------
+// CPELogsHandling::DeleteArrayEntry
+// Delete array's enty by given callid.
+// -----------------------------------------------------------------------------
+//
+void CPELogHandling::DeleteArrayEntry
+        ( 
+        CPELogEvent* aLogEvent
+        )
+    {
+    TInt index = iActiveLogEventArray.Find( aLogEvent );
+    TInt queuedIndex = iQueuedLogEventArray.Find( aLogEvent );
+    TInt freeIndex = iFreeLogEventArray.Find( aLogEvent );
+    
+    // Reset event before deletion
+    aLogEvent->ResetEvent( );
+    aLogEvent->ResetLogInfo();
+    
+    // Remove event from queued array as it is there by error and should not be processed after deletion
+    if ( queuedIndex != KErrNotFound )
+        {
+        TEFLOGSTRING( KTAERROR, "LOG CPELogHandling::DeleteArrayEntry: WARNING Log event removed from queued event array. This should not happen." )
+        iQueuedLogEventArray.Remove( queuedIndex );
+        }
+    
+    if ( index != KErrNotFound )
+        {
+        iActiveLogEventArray.Remove( index );
+        }
+    else
+        {
+        TEFLOGSTRING( KTAERROR, "LOG CPELogHandling::DeleteArrayEntry: WARNING Log event NOT in active event array. This should not happen." )
+        }
+        
+    if ( freeIndex == KErrNotFound )
+        {   
+        if ( iFreeLogEventArray.Count( ) < KPEMaximumNumberOfLogEvents )
+            {
+            if (iFreeLogEventArray.Append( aLogEvent ) != KErrNone)
+                {
+                // prevent memory leak
+                delete aLogEvent;
+                }
+            }
+        else
+            {
+            // prevent memory leak
+            delete aLogEvent;
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CPELogsHandling::DoCleanup
+// Do log handling cleanup in case of leave during handling of a log event.
+// -----------------------------------------------------------------------------
+//
+void CPELogHandling::DoCleanup()
+    {
+    if ( iLogEventUnderProcessing ) 
+        {
+        // delete log event entry only if save leaves and event is completed
+        // otherwise we expect more log events for the same entry that is no need to delete
+        if ( iLogEventUnderProcessing->SaveLeave( ) && 
+             iLogEventUnderProcessing->IsCompleted( ) )
+            {
+            TEFLOGSTRING( KTAERROR, 
+                "LOG CPELogHandling::DoCleanup(), WARNING: Array Entry will be deleted to prevent memory leak." );
+            
+            DeleteArrayEntry( iLogEventUnderProcessing );
+            }
+        }
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPELogsHandling::ResetMissedCalls()
+// Reset missed call.
+// -----------------------------------------------------------------------------
+//
+void CPELogHandling::ResetMissedCalls( TInt aCallId )
+    {
+    TEFLOGSTRING( KTAINT, 
+        "LOG CPELogsHandling::ResetMissedCalls > SetMissedCall" );
+    
+    TEFLOGSTRING2(KTAINT, 
+            "LOG CPELogHandling::ResetMissedCalls, aCallId: %d"
+            , iDataStore.CallId() );
+    iDataStore.SetMissedCall( EFalse, aCallId );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPELogHandling::UpdateLogInfoWithExtensionDataL
+// Log information is not changed if some error happens with extension usage. 
+// -----------------------------------------------------------------------------
+//
+void CPELogHandling::UpdateLogInfoWithExtensionDataL( TInt aCallId, 
+        CPELogInfo& aLogInfo )
+    {
+    TUint serviceId( iDataStore.ServiceId( aCallId ) );
+    CTelLoggingExtension& extension = LoggingExtensionL( serviceId );
+    
+    // initialize extension with original remote contact number/address
+    const TPEPhoneNumber* origRemoteContact = NULL;
+    RMobileCall::EMobileOriginated == iDataStore.CallDirection( aCallId )
+        ? origRemoteContact = &iDataStore.WholeOutgoingPhoneNumber( aCallId )
+        : origRemoteContact = &iDataStore.RemotePhoneNumber( aCallId );
+    __ASSERT_ALWAYS( NULL != origRemoteContact, User::Leave( KErrNotFound ) );
+    extension.InitializeL( serviceId, *origRemoteContact );
+    
+    RBuf phoneNumber;
+    CleanupClosePushL( phoneNumber );
+    User::LeaveIfError( extension.GetPhoneNumber( phoneNumber ) );
+    
+    RBuf voipAddress;
+    CleanupClosePushL( voipAddress );
+    User::LeaveIfError( extension.GetVoipAddress( voipAddress ) );
+    
+    RBuf myAddress;
+    CleanupClosePushL( myAddress );
+    User::LeaveIfError( extension.GetMyAddress( myAddress ) );
+    
+    RBuf remotePartyName;
+    CleanupClosePushL( remotePartyName );
+    User::LeaveIfError( extension.GetRemotePartyName( remotePartyName ) );
+    
+    // update log info with successfully queried extension data
+    SetExtensionData( aLogInfo, phoneNumber, voipAddress, 
+        myAddress, remotePartyName );
+    
+    CleanupStack::PopAndDestroy( 4, &phoneNumber );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPELogHandling::LoggingExtensionL
+// -----------------------------------------------------------------------------
+//
+CTelLoggingExtension& CPELogHandling::LoggingExtensionL( TUint aServiceId )
+    {
+    TUid pluginUid = LoggingPluginIdentifierL( aServiceId );
+    
+    CPELogExtensionWrapper* wrapper = NULL;
+    TInt pluginInd = 
+        iPlugins.Find( pluginUid, CPELogExtensionWrapper::MatchByUid );
+    if ( KErrNotFound == pluginInd )
+        {
+        wrapper = CreateExtensionWrapperLC( pluginUid );
+        iPlugins.AppendL( wrapper );
+        CleanupStack::Pop( wrapper );
+        }
+    else
+        {
+        wrapper = iPlugins[pluginInd];
+        }
+    
+    __ASSERT_ALWAYS( NULL != wrapper, User::Leave( KErrNotFound ) );
+    return *wrapper;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPELogHandling::LoggingPluginIdentifierL
+// Resolves plugin identifier for the given service.
+// -----------------------------------------------------------------------------
+//
+TUid CPELogHandling::LoggingPluginIdentifierL( TUint aServiceId ) const
+    {
+    TInt pluginUid( 0 );
+    CSPSettings* settings = CSPSettings::NewLC();
+    CSPProperty* property = CSPProperty::NewLC();
+    
+    TInt result = settings->FindPropertyL( aServiceId, 
+        EPropertyCallLoggingPluginId, *property );
+    User::LeaveIfError( result );
+    User::LeaveIfError( property->GetValue( pluginUid ) );
+    CleanupStack::PopAndDestroy( property );
+    CleanupStack::PopAndDestroy( settings );
+    
+    return TUid::Uid( pluginUid );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPELogHandling::SetExtensionData
+// Lengths of the descriptors gotten from plugin must be checked, because
+// extension API does not set limits for data length. In case that phone number
+// is available, voip address is not saved to logs. That enables user to select
+// call type s/he wants when calling from logs.
+// -----------------------------------------------------------------------------
+//
+void CPELogHandling::SetExtensionData( CPELogInfo& aLogInfo, 
+        const TDesC& aPhoneNumber, const TDesC& aVoipAddress, 
+        const TDesC& aMyAddress, const TDesC& aRemotePartyName )
+    {
+    if ( aPhoneNumber.Length() <= aLogInfo.PhoneNumber().MaxLength() )
+        {
+        aLogInfo.SetPhoneNumber( aPhoneNumber );
+        aLogInfo.SetVoipAddress( KNullDesC() );
+        }
+    
+    if ( aVoipAddress.Length() <= aLogInfo.VoipAddress().MaxLength() )
+        {
+        if ( KNullDesC() == aLogInfo.PhoneNumber() )
+            {
+            aLogInfo.SetVoipAddress( aVoipAddress );
+            }
+        }
+    
+    if ( aMyAddress.Length() <= aLogInfo.MyAddress().MaxLength() )
+        {
+        aLogInfo.SetMyAddress( aMyAddress );
+        }
+    
+    // Try to use user defined contact name from contacts, remote party name
+    // from extension or voip address from extension as a contact name to be
+    // saved in logs, in that order.
+    TBool noContactMatch = ( KNullDesC() == aLogInfo.Name() ); 
+    if ( noContactMatch )
+        {
+        if ( aRemotePartyName.Length() != 0 )
+            {
+            aLogInfo.SetName( aRemotePartyName.Left( aLogInfo.Name().MaxSize() ) );
+            }
+        else if ( KNullDesC() != aLogInfo.VoipAddress() )
+            {
+            aLogInfo.SetName( aLogInfo.VoipAddress() );
+            }
+        else
+            {
+            aLogInfo.SetName( aLogInfo.PhoneNumber() );
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CPELogHandling::CreateExtensionWrapperLC
+// -----------------------------------------------------------------------------
+//
+CPELogExtensionWrapper* CPELogHandling::CreateExtensionWrapperLC( 
+        const TUid& aPluginUid ) const
+    {
+    return CPELogExtensionWrapper::NewLC( aPluginUid );
+    }
+
+// End of File