locationrequestmgmt/networkrequesthandler/src/EPos_CPosDialogCtrl.cpp
author William Roberts <williamr@symbian.org>
Thu, 22 Jul 2010 16:47:01 +0100
branchGCC_SURGE
changeset 49 5f20f71a57a3
parent 23 2965a06983dc
parent 40 18280709ae43
permissions -rw-r--r--
Catchup to latest Symbian^4

// Copyright (c) 2005-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 FILES
#include <s32mem.h>
#include <e32property.h>
#include <lbs/epos_privacy.h>
#include <lbs/epos_cposcontactrequestor.h>
#include <lbs/epos_cposservicerequestor.h>
#include <lbs/epos_rposrequestorstack.h>
#include <lbs/epos_privacynotifier.hrh>
#include "EPos_CPosDialogCtrl.h"
#include <lbs/lbslocclasstypes.h>

// CONSTANTS
#if defined(NRH_UNIT_TEST)
// For the NRH unit test, use a different Q&N notifier implementation UID.
// This is so that we can have both the unit test Q&N notifier and
// the integration test Q&N notifier (with the real implementation UID)
// in the same ROM.
const TUid KNotifierUid = { 0x10283744 };
#else
const TUid KNotifierUid = { KPosPrivacyNotifierImplUid };
#endif // NRH_UNIT_TEST

// P&S Key so NG can check the status of notifications
const TInt EPrivacyNumberOfRequest = 0x1028720F;

// The output descriptor for Notifier calls. Since we want to pass
// just a dummy null descriptor there is no need to create a HBufC
// each time.
TPtr8 nullPtr(reinterpret_cast<TUint8*>(NULL), 0);


// ================= MEMBER FUNCTIONS =======================

// C++ default constructor can NOT contain any code, that
// might leave.
//
CPosDialogCtrl::CPosDialogCtrl() : CActive(EPriorityNormal),
    iRequestQueue(1) // Set granularity to 1
    {
    CActiveScheduler::Add(this);
    }

// EPOC default constructor can leave.
void CPosDialogCtrl::ConstructL()
    {
    TInt err = iNotifier.Connect();
    User::LeaveIfError(err);
    
    // Define the property
    RProperty::Define(KUidSystemCategory, EPrivacyNumberOfRequest, RProperty::EInt);
    UpdateProperty();
    }

// Two-phased constructor.
CPosDialogCtrl* CPosDialogCtrl::InstanceL()
    {
    CPosDialogCtrl* self = new (ELeave) CPosDialogCtrl;
    CleanupStack::PushL(self);
    self->ConstructL();
    CleanupStack::Pop(self);
    return self;
    }

// Destructor
CPosDialogCtrl::~CPosDialogCtrl()
    {
    Cancel();
    TInt count = iRequestQueue.Count();
    for (TInt i = 0; i < count; i++)
        {
        DoCompleteRequest(0, KErrServerTerminated);
        }

    iNotifier.Close();
    iRequestQueue.Close();
    RProperty::Delete(KUidSystemCategory, EPrivacyNumberOfRequest);
    }

// ---------------------------------------------------------
// CPosDialogCtrl::NotifyL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CPosDialogCtrl::NotifyL(
	TLbsExternalRequestInfo& aRequestInfo,
    const TPosRequestData& aRequestData)
    {
    TRequest request;
    request.iType = TPosQNInputData::ENotification;
    request.iRequestInfo = &aRequestInfo;
    request.iStatus = NULL;
    request.iRequestSource = aRequestData.iRequestSource;
    request.iTimeoutStrategy = aRequestData.iTimeoutStrategy;
    request.iRequestDecision = aRequestData.iRequestDecision;
    request.iCancelReason = aRequestData.iCancelReason;
    request.iNotificationReason = aRequestData.iNotificationReason;

    ScheduleRequestL(request);
    }

// ---------------------------------------------------------
// CPosDialogCtrl::VerifyL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CPosDialogCtrl::VerifyL(
    TRequestStatus& aStatus,
	TLbsExternalRequestInfo& aRequestInfo,
    const TPosRequestData& aRequestData)
    {
    aStatus = KRequestPending;

    TRequest request;
    request.iType = TPosQNInputData::EQuery;
    request.iRequestInfo = &aRequestInfo;
    request.iStatus = &aStatus;
    request.iRequestSource = aRequestData.iRequestSource;
    request.iTimeoutStrategy = aRequestData.iTimeoutStrategy;
    request.iRequestDecision = aRequestData.iRequestDecision;
    request.iCancelReason = aRequestData.iCancelReason;
    request.iNotificationReason = aRequestData.iNotificationReason;

    GivePriorityToVerificationL(request);
    }

// ---------------------------------------------------------
// CPosDialogCtrl::CancelLaunch
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CPosDialogCtrl::CancelLaunch(TRequestStatus& aStatus)
    {
    TInt count = iRequestQueue.Count();

    if (count > 0 && iRequestQueue[0].iStatus == &aStatus)
        {
        Cancel();
        DoCompleteRequest(0, KErrCancel);
        NextRequest();
        }
    else
        {
        for (TInt i = 1; i < count; ++i)
            {
            if (iRequestQueue[i].iStatus == &aStatus)
                {
                DoCompleteRequest(i, KErrCancel);
                return;
                }
            }
        }
    }

// ---------------------------------------------------------
// CPosDialogCtrl::CancelLaunch
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CPosDialogCtrl::CancelLaunch(
    TRequestStatus& aStatus,
    TInt& aErrorCode,
    TInt& aResponse,
    TBool& aRequestQueued,
    TPosVerifyCancelReason aCancelReason)
    {
    TInt count = iRequestQueue.Count();

    if (count > 0 && iRequestQueue[0].iStatus == &aStatus)
        {
        TPtr8 nullPtr(reinterpret_cast<TUint8*>(NULL), 0);
        TPosQNInputData data;
        data.iId = iRequestQueue[0].iId;
        data.iCancelReason = aCancelReason;

        TPckg<TPosQNInputData> dataPtr(data);

        aErrorCode = iNotifier.UpdateNotifier(KNotifierUid, dataPtr, nullPtr);
        if( KErrNone==aErrorCode  /* && iRequestQueue[0].iTimeoutStrategy == EPosDecisionAccepted  */)  
	        {
	        // If there is an error, notifications will be triggered through PrivManager
	        TRAPD(err,CreateNotificationAndEnqueueL());
	        err = err; // To avoid compiler warning
	        }
        aResponse = iStatus.Int();
        aRequestQueued = EFalse;
        }
    else
        {
        aResponse = KErrNone;
        aErrorCode = KErrNone;
        aRequestQueued = ETrue;
        }
    CancelLaunch(aStatus);
    }

// ---------------------------------------------------------
// CPosDialogCtrl::RunL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CPosDialogCtrl::RunL()
    {
    if (iRequestQueue.Count() > 0)
        {
        DoCompleteRequest(0, iStatus.Int());
        NextRequest();
        }
    }

// ---------------------------------------------------------
// CPosDialogCtrl::DoCancel
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CPosDialogCtrl::DoCancel()
    {
    if (iStatus == KRequestPending)
        {
        iNotifier.CancelNotifier(KNotifierUid);
        }
    }

// ---------------------------------------------------------
// CPosDialogCtrl::DialogActive
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
TBool CPosDialogCtrl::DialogActive() const
    {
    return iRequestQueue.Count() > 0;
    }

// ---------------------------------------------------------
// CPosDialogCtrl::NextRequest
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CPosDialogCtrl::NextRequest()
    {
    while (iRequestQueue.Count() > 0)
        {
        TInt err = StartNotifierRequest();
        if (err)
            {
            DoCompleteRequest(0, err);
            }
        else
            {
            return;
            }
        }
    }

// ---------------------------------------------------------
// CPosDialogCtrl::DoCompleteRequest
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CPosDialogCtrl::DoCompleteRequest(
    TInt aIndex,
    TInt aCompletionCode)
    {
    TRequest request = iRequestQueue[aIndex];
    if (request.iType == TPosQNInputData::ENotification)
        {
        delete request.iRequestInfo;
        }
    else
        {
        TRequestStatus* status = request.iStatus;
        User::RequestComplete(status, aCompletionCode);
        }
    iRequestQueue.Remove(aIndex);
    iRequestQueue.Compress();
    UpdateProperty();
    }

// ---------------------------------------------------------
// CPosDialogCtrl::ScheduleRequestL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CPosDialogCtrl::ScheduleRequestL(TRequest& aRequest)
    {
    // Start a new request.    
    aRequest.iId = ++iRequestId;
    User::LeaveIfError(iRequestQueue.Append(aRequest));
    UpdateProperty();

    if (iRequestQueue.Count() == 1)
        {
        TInt err = StartNotifierRequest();

        if (err != KErrNone)
            {
            DoCompleteRequest(0, err);
            }
        }
    }

// ---------------------------------------------------------
// CPosDialogCtrl::StartNotifierRequest
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
TInt CPosDialogCtrl::StartNotifierRequest()
    {
    TRequest request = iRequestQueue[0];
    
    // Convert the TLbsExternalRequestInfo into a CPosRequestorStack
    RPosRequestorStack reqStack;
    TRAPD(err, ExtractRequestorsL(*request.iRequestInfo, reqStack));
    if (err != KErrNone)
    	{
    	return err;
    	}
    TInt dataSize = CalcSize(reqStack);

    HBufC8* reqStackBuf = HBufC8::New(dataSize);
    if (!reqStackBuf)
        {
        reqStack.ResetAndDestroy();
        return KErrNoMemory;
        }

    TPtr8 ptr = reqStackBuf->Des();
    TRAP(err, CreateSerializedStackL(ptr, reqStack));
    if (err == KErrNone)
        {
        TPosQNInputData data;
        data.iId = request.iId;
        data.iType = request.iType;
        data.iDataSize = dataSize;
        data.iDataPtr = NULL;
        data.iRequestSource = request.iRequestSource;
        data.iTimeoutStrategy = request.iTimeoutStrategy;
        data.iRequestDecision = request.iRequestDecision;
        data.iNotificationReason = request.iNotificationReason;
        data.iCancelReason = request.iCancelReason;

        TPckg<TPosQNInputData> dataPtr(data);

        HBufC8* buffer = HBufC8::New(KPosQNInputDataClassSize +
            reqStackBuf->Size());
        if (!buffer)
            {
            delete reqStackBuf;
            return KErrNoMemory;
            }

        buffer->Des().Append(dataPtr);
        buffer->Des().Append(*reqStackBuf);

        delete reqStackBuf;
        reqStackBuf = NULL;

        iNotifier.StartNotifierAndGetResponse(
            iStatus, KNotifierUid, nullPtr, nullPtr);
        SetActive();

        err = iNotifier.UpdateNotifier(KNotifierUid, *buffer, nullPtr);
        if (err != KErrNone)
            {
            Cancel();
            }
        delete buffer;
        }

    delete reqStackBuf;
    reqStack.ResetAndDestroy();
    return err;
    }

// ---------------------------------------------------------
// CPosDialogCtrl::CreateSerializedStackL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CPosDialogCtrl::CreateSerializedStackL(
    TDes8& aBuffer,
    const RPosRequestorStack& aRequestStack)
    {
    RDesWriteStream writeStream(aBuffer);
    CleanupClosePushL(writeStream);
    aRequestStack.ExternalizeL(writeStream);
    writeStream.CommitL();
    CleanupStack::PopAndDestroy(1, &writeStream);
    }

// ---------------------------------------------------------
// CPosDialogCtrl::CalcSize
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
TInt CPosDialogCtrl::CalcSize(
    const RPosRequestorStack& aRequestStack)
    {
    TInt size = sizeof(TInt);	// One TInt for number of requestors.
    const TInt numRequestors = aRequestStack.Count();
    for (TInt i = 0; i < numRequestors; i++)
    	{
    	const CPosRequestor* requestor = aRequestStack[i];
    	
    	// Add on the size of the requestor class, the 
    	// descriptor it contains, and an extra TInt which
    	// is used to store the length of the descriptor.
    	size += sizeof(CPosRequestor);
    	size += sizeof(TInt);
    	size += requestor->RequestorIdString().Size();
    	}

    return size;
    }

/** Convert a TLbsExternalRequestInfo into a RPosRequestorStack.
 */
void CPosDialogCtrl::ExtractRequestorsL(
 		const TLbsExternalRequestInfo& aRequestInfo,
     	RPosRequestorStack& aRequestors)
 	{	
 	// Convert the Client name into a CPosRequestor::ERequestorService requestor.
 	switch (aRequestInfo.ClassType())
 		{
 		case EExternalRequestInfoClass:
 			{
 			TBuf<KLbsMaxClientNameSize> buf;
 			aRequestInfo.GetClientName(buf);
 			AddRequestorL(CPosRequestor::ERequestorService,
 						  aRequestInfo.ClientNameFormat(),
 						  aRequestInfo.RequestType(),
 						  aRequestInfo.NetworkType(),
 						  buf,
 						  aRequestors
 						  );
 			break;
 			}
 		case (EExternalRequestInfoClass 
 			  | EExternalRequestInfoClass2):
 		  	{
   			const TLbsExternalRequestInfo2& info = static_cast<const TLbsExternalRequestInfo2&>(aRequestInfo);
   			TBuf<KLbsMaxClientNameSize2> buf;
 			info.GetClientName(buf);
 			AddRequestorL(CPosRequestor::ERequestorService,
 						  aRequestInfo.ClientNameFormat(),
 						  aRequestInfo.RequestType(),
 						  aRequestInfo.NetworkType(),
 						  buf,
 						  aRequestors
 						  );		
 		  	break;
 		  	}
 		default:
 			{
 			// Unrecognised TLbsExternalRequestInfo class type, so ignore it.
 			break;
 			}
 		}	
 	
 	// Convert the Requestor name into a CPosRequestor::ERequestorContact requestor.
 	switch (aRequestInfo.ClassType())
 		{
 		case EExternalRequestInfoClass:
 			{
 			TBuf<KLbsMaxRequesterIdSize> buf;
 			aRequestInfo.GetRequesterId(buf);
 			AddRequestorL(CPosRequestor::ERequestorContact,
 						  aRequestInfo.RequesterIdFormat(),
 						  aRequestInfo.RequestType(),
 						  aRequestInfo.NetworkType(),
 						  buf,
 						  aRequestors
 						  );
 			break;
 			}
 		case (EExternalRequestInfoClass 
 			  | EExternalRequestInfoClass2):
 		  	{
   			const TLbsExternalRequestInfo2& info = static_cast<const TLbsExternalRequestInfo2&>(aRequestInfo);
   			TBuf<KLbsMaxRequesterIdSize2> buf;
 			info.GetRequesterId(buf);
 			AddRequestorL(CPosRequestor::ERequestorContact,
 						  aRequestInfo.RequesterIdFormat(),
 						  aRequestInfo.RequestType(),
 						  aRequestInfo.NetworkType(),
 						  buf,
 						  aRequestors
 						  );
 		  	break;
 		  	}
 		default:
 			{
 			// Unrecognised TLbsExternalRequestInfo class type, so ignore it.
 			break;
 			}
 		}
 	}

 /**
 */	
void CPosDialogCtrl::AddRequestorL(
 		CPosRequestor::TRequestorType aRequestorType,
 		TLbsExternalRequestInfo::TFormatIndicator aIdType,
 	    CPosRequestor::TRequestType aRequestType,
 	    CPosRequestor::TNetworkType aNetworkType,
 		const TDesC& aId,
 		RPosRequestorStack& aRequestors)
 	{
 	CPosRequestor::TRequestorIdFormat format = CPosRequestor::EIdFormatUnknown;
 	switch (aIdType)
 		{
 		case TLbsExternalRequestInfo::EFormatLogicalName :
 			format = CPosRequestor::EIdFormatGenericName;
 			break;
 		case TLbsExternalRequestInfo::EFormatMSISDN :
 			format = CPosRequestor::EIdFormatPhoneNumber;
 			break;
 		case TLbsExternalRequestInfo::EFormatEmailAddress :
 			format = CPosRequestor::EIdFormatEmail;
 			break;
 		case TLbsExternalRequestInfo::EFormatURL :
 			format = CPosRequestor::EIdFormatUrl;
 			break;
 		case TLbsExternalRequestInfo::EFormatSIPURL :
 			format = CPosRequestor::EIdFormatSIPUrl;
 			break;
 		case TLbsExternalRequestInfo::EFormatIMSPublicIdentity :
 			format = CPosRequestor::EIdFormatIMSPublicIdentity;
 			break;
 		case TLbsExternalRequestInfo::EFormatMIN:
 			format = CPosRequestor::EIdFormatMIN;
 			break;
 		case TLbsExternalRequestInfo::EFormatMDN:
 			format = CPosRequestor::EIdFormatMDN;
 			break;
 		}

 	// Only add the requestor to the stack if it is a recognised format.
 	if (format != CPosRequestor::EIdFormatUnknown)
 		{
 	    CPosRequestor* requestor = NULL;
 	    if (aRequestorType == CPosRequestor::ERequestorContact)
 	        {
 	        requestor = CPosContactRequestor::NewLC(format, aId);
 	        }
 	    else
 	        {
 	        requestor = CPosServiceRequestor::NewLC(format, aId);
 	        }
 	        
 	    requestor->SetRequestType(aRequestType);
 	    requestor->SetNetworkType(aNetworkType);
     	User::LeaveIfError(aRequestors.Append(requestor));
     	CleanupStack::Pop(requestor);
 		}	
 	}
 
 
// ---------------------------------------------------------
// CPosDialogCtrl::GivePriorityToVerificationL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CPosDialogCtrl::GivePriorityToVerificationL(TRequest& aRequest)
    {
    TBool notificationDeferred = EFalse;
    
    if( iRequestQueue.Count() == 0 )
	    {
	    ScheduleRequestL(aRequest);
	    return;
	    }
	if ( iRequestQueue[0].iType == TPosQNInputData::ENotification )
		{
		notificationDeferred=ETrue; // To indicate that notification is deferred,dont remove it from queue.
		}
		
	EnqueueRequestL(aRequest);
	
	if(notificationDeferred)
		{
		Cancel();	
	    DeferNotificationL();
		}
    }
// ---------------------------------------------------------
// CPosDialogCtrl::EnqueueRequestL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CPosDialogCtrl::EnqueueRequestL(TRequest& aRequest)
    {
    aRequest.iId = ++iRequestId;
    
    for( TInt i = 1; i < iRequestQueue.Count(); i++ )
		{
		if ( iRequestQueue[i].iType == TPosQNInputData::ENotification )
			{
			User::LeaveIfError(iRequestQueue.Insert( aRequest,i ));
			UpdateProperty();
			return;
			}
		}
	
    User::LeaveIfError(iRequestQueue.Append(aRequest));
    UpdateProperty();
    }

// ---------------------------------------------------------
// CPosDialogCtrl::DeferNotificationL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CPosDialogCtrl::DeferNotificationL()
	{
	if( KErrCancel == iStatus.Int() )
		{
		//Notification request has been cancelled..Defer it by adding 
		// after verification requests,remove it from first place & schedule next request.
		TRequest request = iRequestQueue[0];
		EnqueueRequestL(request);
		}
	iRequestQueue.Remove(0);
    iRequestQueue.Compress();
    UpdateProperty();
	NextRequest();	
	}

// ---------------------------------------------------------
// CPosDialogCtrl::CreateNotificationAndEnqueueL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CPosDialogCtrl::CreateNotificationAndEnqueueL()
	{   
    TRequest verifyRequest = iRequestQueue[0];   
    TRequest notifyRequest;
    TLbsExternalRequestInfo* requestinfocopy = NULL;
    
    if (verifyRequest.iRequestInfo->ClassType() == EExternalRequestInfoClass) 
        {        
        requestinfocopy = new (ELeave) TLbsExternalRequestInfo;
        CleanupStack::PushL(requestinfocopy);
        Mem::Copy(requestinfocopy, verifyRequest.iRequestInfo, sizeof(TLbsExternalRequestInfo));
        }
    else 
        {
        __ASSERT_DEBUG(verifyRequest.iRequestInfo->ClassType() == EExternalRequestInfoClass | EExternalRequestInfoClass2, User::Invariant());
        requestinfocopy = new (ELeave) TLbsExternalRequestInfo2;
        CleanupStack::PushL(requestinfocopy);
        Mem::Copy(requestinfocopy, verifyRequest.iRequestInfo, sizeof(TLbsExternalRequestInfo2));        
        }

    notifyRequest.iRequestInfo = requestinfocopy;    
    notifyRequest.iType = TPosQNInputData::ENotification;
    notifyRequest.iStatus = NULL;
    notifyRequest.iRequestSource = EPosRequestSourceNetwork;
    
    notifyRequest.iTimeoutStrategy = EPosDecisionNotAvailable;
    notifyRequest.iRequestDecision = verifyRequest.iTimeoutStrategy;
    
    notifyRequest.iCancelReason = EPosCancelReasonTimeout; 
    notifyRequest.iNotificationReason = EPosVerificationTimeout;
    
    EnqueueRequestL(notifyRequest);        
    CleanupStack::Pop(requestinfocopy);
    
	}

void CPosDialogCtrl::UpdateProperty()
    {
    RProperty::Set(KUidSystemCategory, EPrivacyNumberOfRequest, iRequestQueue.Count());
    }


//  End of File