// Copyright (c) 2006-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:
// Name        : CSatNotifyMoSmControlRequest.cpp
// Part of     : Common SIM ATK TSY / commonsimatktsy
// Display text notification functionality of Sat Tsy
// Version     : 1.0
//



//INCLUDES
#include <satcs.h>                  // Etel SAT IPC definitions
#include "CSatTsy.h"                // Tsy class header
#include "CSatNotifyMoSmControlRequest.h"  // Class header
#include "CSatNotificationsTsy.h"   // Tsy class header
#include "CBerTlv.h"                // Ber Tlv data handling
#include "BerTlv_defs.h"            // Ber Tlv specific definitions
#include "TTlv.h"					// TTlv class
#include "CSatDataPackage.h"        // Parameter packing 
#include "TfLogger.h"               // For TFLOGSTRING
#include "TSatUtility.h"            // Utilities
#include "CSatTsyReqHandleStore.h"  // Request handle class
#include "cmmmessagemanagerbase.h" 	// Message manager class for forwarding req.
#include "MSatTsy_IPCDefs.h"        // Sat Tsy internal request types

// -----------------------------------------------------------------------------
// CSatNotifyMoSmControlRequest::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//  
CSatNotifyMoSmControlRequest* CSatNotifyMoSmControlRequest::NewL
        ( 
        CSatNotificationsTsy* aNotificationsTsy 
        )
    {
    TFLOGSTRING("CSAT: CSatNotifyMoSmControlRequest::NewL");
   	CSatNotifyMoSmControlRequest* const satNotifyMoSmControlRequest = 
        new ( ELeave ) CSatNotifyMoSmControlRequest( aNotificationsTsy );
    CleanupStack::PushL( satNotifyMoSmControlRequest );
    satNotifyMoSmControlRequest->ConstructL();
    CleanupStack::Pop( satNotifyMoSmControlRequest );
    TFLOGSTRING("CSAT: CSatNotifyMoSmControlRequest::NewL, end of method");
    return satNotifyMoSmControlRequest;
    }

// -----------------------------------------------------------------------------
// CSatNotifyMoSmControlRequest::~CSatNotifyMoSmControlRequest
// Destructor
// -----------------------------------------------------------------------------
//  
CSatNotifyMoSmControlRequest::~CSatNotifyMoSmControlRequest
        ( 
		// None
        )
    {
    TFLOGSTRING("CSAT: CSatNotifyMoSmControlRequest::\
    	~CSatNotifyMoSmControlRequest");
    }
    
// -----------------------------------------------------------------------------
// CSatNotifyMoSmControlRequest::CSatNotifyMoSmControlRequest
// Default C++ constructor
// -----------------------------------------------------------------------------
//  
CSatNotifyMoSmControlRequest::CSatNotifyMoSmControlRequest
        ( 
        CSatNotificationsTsy* aNotificationsTsy 
        ) : iNotificationsTsy ( aNotificationsTsy )
    {
    // None
    }

// -----------------------------------------------------------------------------
// CSatNotifyMoSmControlRequest::ConstructL
// Symbian 2nd phase constructor
// -----------------------------------------------------------------------------
//  
void CSatNotifyMoSmControlRequest::ConstructL
        (
        // None
        )
    {
    TFLOGSTRING("CSAT: CSatNotifyMoSmControlRequest::ConstructL");
    // Checks if MO-SMS control should be activated
    iNotificationsTsy->iSatTsy->MessageManager()->HandleRequestL( 
    		ESatTsyMoSmsControlActivation );	
    // Initialize MO-SMS Control to deactivated
    iIsMoSmsCtrlActivated = EFalse; 
    TFLOGSTRING("CSAT: CSatNotifyMoSmControlRequest::ConstructL, \
    	end of method"); 	
    }

// -----------------------------------------------------------------------------
// CSatNotifyMoSmControlRequest::Notify
// This request allows a client to be notified of a MO-SMS Control proactive 
// command
// -----------------------------------------------------------------------------
//
TInt CSatNotifyMoSmControlRequest::Notify
        (
        const TTsyReqHandle aTsyReqHandle,
        const TDataPackage& aPackage 
        )
    {
    TFLOGSTRING("CSAT: CSatNotifyMoSmControlRequest::Notify");

    // Save data pointer to client side for completion      
    iMoSmControlV1Pckg = reinterpret_cast<RSat::TMoSmControlV1Pckg*>(
    	aPackage.Des1n() );
    
    // Save the request handle
    iNotificationsTsy->iSatTsy->SaveReqHandle( aTsyReqHandle, 
		CSatTsy::ESatNotifyMoSmControlRequestPCmdReqType );  

    return KErrNone;
    }

// -----------------------------------------------------------------------------
// CSatNotifyMoSmControlRequest::CancelNotification
// This method cancels an outstanding asynchronous 
// MoSmControl request.
// -----------------------------------------------------------------------------
//
TInt CSatNotifyMoSmControlRequest::CancelNotification
        (
        const TTsyReqHandle aTsyReqHandle
        )
    {
    TFLOGSTRING("CSAT: CSatNotifyMoSmControlRequest::CancelNotification");
    
    // Reset the request handle
    TTsyReqHandle reqHandle = iNotificationsTsy->iSatReqHandleStore->
        ResetTsyReqHandle( CSatTsy::ESatNotifyMoSmControlRequestPCmdReqType );
	// Reset the data pointer
	iMoSmControlV1Pckg = NULL;
	// Complete the request with KErrCancel
	iNotificationsTsy->iSatTsy->ReqCompleted( aTsyReqHandle, KErrCancel );

    return KErrNone;    
    }

// -----------------------------------------------------------------------------
// CSatNotifyMoSmControlRequest::CompleteNotifyL
// This method completes an outstanding asynchronous NotifyMoSmControlRequest
// request. 
// -----------------------------------------------------------------------------
//
TInt CSatNotifyMoSmControlRequest::CompleteNotifyL
        (
        CSatDataPackage* aDataPackage,   
        TInt aErrorCode                
        )
    {
    TFLOGSTRING("CSAT: CSatNotifyMoSmControlRequest::CompleteNotifyL" );
    
    CSatNotificationsTsy::TMoSmCtrlData moSmCtrlData;

    // Initialize parameters
    moSmCtrlData.iResult = KMoSmCtrlResultAllowed;
    moSmCtrlData.iAlphaId = NULL;
    
    // The request is completed to the client only if Alpha ID is present,
    // otherwise just handle the message just internally
    if ( KErrNone == aErrorCode )
    	{ 	
    	TBuf8<KAddrMaxLength> addr1;
        TBuf8<KAddrMaxLength> addr2;
        RSat::TAlphaId alphaId;
        alphaId.iAlphaId.Zero();
        alphaId.iStatus = RSat::EAlphaIdNotPresent;
        TBool simRespDataConsistent( ETrue );        
    	TBool isDataOk( ETrue );
    	
    	// Unpack parameters
		TDesC8* atkData = NULL;
		aDataPackage->UnPackData( &atkData );
    	
    	TFLOGSTRING2("CSAT: CSatNotifyMoSmControlRequest::CompleteNotifyL\
    	    Data length: %d", ( *atkData ).Length() );
    	
	    if ( KTlvMaxSize < ( *atkData ).Length() )
	    	{
            TFLOGSTRING("CSAT: CSatNotifyMoSmControlRequest::CompleteNotifyL, \
                Data length exceeded" );                
            // Data not consistent, reject the call
            moSmCtrlData.iResult = KMoSmCtrlResultNotAllowed;
	        isDataOk = EFalse;
            }
        else if ( ( *atkData ).Length() )
            {
            // Note: The alpha id can be provided by the NAA even if the addresses
            // have not been modified.                
            ParseNotification( *atkData, addr1, addr2, alphaId  ); 

            if ( KMoSmCtrlResultAllowedWithModifications == ( *atkData )[0] )
                {
                TFLOGSTRING3("CSAT: CSatNotifyMoSmControlRequest::CompleteNotifyL\
    	            Addr1: %s, Addr2: %s", &addr1, &addr2 );
                simRespDataConsistent = VerifyNotificationData( addr1, addr2 );      
                }
                
            if ( simRespDataConsistent )
                {
            	// atkData[0] --> result
            	moSmCtrlData.iResult = ( *atkData )[0];            
                }
            else
                {
                TFLOGSTRING("CSAT: CSatNotifyMoSmControlRequest::CompleteNotifyL, \
                	NAA response data not consistent" );                
                // Data not consistent, reject the sms
                moSmCtrlData.iResult = KMoSmCtrlResultNotAllowed;
	        	isDataOk = EFalse;
                }
            }
             
        // Prepare rest of the data for response        
        moSmCtrlData.iAddressData.iRPDestinationAddr.Set( addr1 );
        moSmCtrlData.iAddressData.iTPDestinationAddr.Set( addr2 );
        moSmCtrlData.iAlphaId = &alphaId;
        
        // Pack data and send response to NAA
    	CSatDataPackage dataPackage;
    	dataPackage.PackData( &moSmCtrlData );
        iNotificationsTsy->iSatTsy->MessageManager()->HandleRequestL( 
        	ESatNotifyMoSmControlRequest, &dataPackage );
	    
	    // Then start checking whether the client nees to be notified as well..
	    // Check if the MO-SMS is activated and the data is verified ok
	    if ( iIsMoSmsCtrlActivated && isDataOk )
	        {          
		    // Get req handle. Can not be deleted yet, since completion
		    // depends on the presence of Alpha ID
		    TTsyReqHandle reqHandle = 
		        iNotificationsTsy->iSatReqHandleStore->TsyReqHandle( 
		            CSatTsy::ESatNotifyMoSmControlRequestPCmdReqType );
		    
		    // In case the request was ongoing, continue.. But note that
		    // the client is notified only if AlphaID is present, in order 
		    // to inform that the ETel API MO-SMS Control structure 
		    // TMoSmControlV1 has been modified.
	        if ( CSatTsy::ESatReqHandleUnknown != reqHandle &&
	             ( moSmCtrlData.iAlphaId->iAlphaId.Length() || 
	             RSat::EAlphaIdNull == moSmCtrlData.iAlphaId->iStatus ) )
	            {
	            // Now its safe to reset the request handle
		        iNotificationsTsy->iSatReqHandleStore->ResetTsyReqHandle( 
		            CSatTsy::ESatNotifyMoSmControlRequestPCmdReqType );
	            // Fill the call control structure
		        RSat::TMoSmControlV1& moSmControlV1 = 
		        	( *iMoSmControlV1Pckg )();
		        
	            // Control result must be mapped to ETel API values.
	            switch ( ( *atkData )[0] )
	                {
	                case KMoSmCtrlResultAllowed:
	                    {
	                    moSmControlV1.iResult = 
	                    	RSat::EAllowedNoModification;
	                    break;
	                    }
	                case KMoSmCtrlResultAllowedWithModifications:
	                    {
	                    moSmControlV1.iResult = 
	                    	RSat::EAllowedWithModifications;
	                    break;
	                    }
	                case KMoSmCtrlResultNotAllowed:
	                    {
	                    moSmControlV1.iResult = RSat::ENotAllowed;
	                    break;
	                    }
	                default:
	                    {
	                    moSmControlV1.iResult = RSat::EControlResultNotSet;
	                    break;
	                    }
	                }

		        // Set alpha id and status
		        moSmControlV1.iAlphaId.iAlphaId.Append( alphaId.iAlphaId );
		        moSmControlV1.iAlphaId.iStatus = alphaId.iStatus;
		        
		        // Complete notification to the client
	    		iNotificationsTsy->iSatTsy->ReqCompleted( reqHandle, 
	    		    KErrNone );
	            } // If Alpha ID or request handle

	        } // If MO SM Ctrl Activated and data ok
	    else
	        {
	        TFLOGSTRING3("LSAT: CSatMoSmsCtrlMessHandler::CompleteNotifyL, \
    	        iIsMoSmsCtrlActivated: %d, isDataOk: %d ", 
    	        iIsMoSmsCtrlActivated, isDataOk);
	        }
    	} // if KErrNone
    else
        {
        TFLOGSTRING("LSAT: CSatMoSmsCtrlMessHandler::CompleteNotifyL, \
        	Error in notification ");
        moSmCtrlData.iResult = KMoSmCtrlResultNotAllowed;
        // Pack data and send response right away to NAA
    	CSatDataPackage dataPackage;
    	dataPackage.PackData( &moSmCtrlData );
        iNotificationsTsy->iSatTsy->MessageManager()->HandleRequestL( 
        	ESatNotifyMoSmControlRequest, &dataPackage );
        }

    return KErrNone;
    }
     
// -----------------------------------------------------------------------------
// CSatNotifyMoSmControlRequest::CreateMoSmsCtrlEnvelopeL
// Send an envelope to SIM server in order to check wheter the SMS can be sent 
// or not. The response will be used to send a response to SMS server
// -----------------------------------------------------------------------------
//
void CSatNotifyMoSmControlRequest::CreateMoSmsCtrlEnvelopeL
	    (
	    CSatDataPackage* aDataPackage,
	    TInt /*aResult*/
	    )   
    {   
    TFLOGSTRING("CSAT: CSatNotifyMoSmControlRequest::\
        CreateMoSmsCtrlEnvelopeL"); 
    // Check first if the MO-SMS is activated
    if ( iIsMoSmsCtrlActivated )
        {  
    	TFLOGSTRING("CSAT: CSatNotifyMoSmControlRequest::\
    		CreateMoSmsCtrlEnvelopeL, MO SM Ctrl Activated");
    	
	    CSatNotificationsTsy::TAddressData* addressData;
	    
	    // Unpack data
	    aDataPackage->UnPackData( &addressData );
	    
	    TTlv envelope;

	    envelope.Begin( KBerTlvMoShortMessageControlTag );
	    //device identities
	    envelope.AddTag( KTlvDeviceIdentityTag );
	    envelope.AddByte( KMe );
	    envelope.AddByte( KSim );
	    // Address Data object 1
	    // Ton and Npi is in the first byte of address data
	    envelope.AddTag( KTlvAddressTag );
	    envelope.AddData( addressData->iRPDestinationAddr );
	    // Address Data object 2
	    // Ton and Npi is in the first byte of address data
	    envelope.AddTag( KTlvAddressTag );
	    envelope.AddData( addressData->iTPDestinationAddr );

	    // !!! This part assumes that location info has been received
	    // Mobile Country & Network Codes (MCC & MNC)
	    iNotificationsTsy->AddLocationInformationToTlv( envelope );
	        	
	   	// Prepare data
	    TPtrC8 data = envelope.End();
	    // Pack data
	    CSatDataPackage dataPackage;
	    dataPackage.PackData( &data );
	    
	    // Forward request to the DOS. Send envelope only if its length is less 
	    // than the maximum allowed envelope length.
	    iNotificationsTsy->iSatTsy->MessageManager()->HandleRequestL( 
	        ESatTsySendEnvelope, &dataPackage );
        }
    }
    
// -----------------------------------------------------------------------------
// CSatNotifyMoSmControlRequest::Activate
// Set iIsMoSmsCtrlActivated to ETrue if MO-SMS Control has to be activated
// -----------------------------------------------------------------------------
//
void CSatNotifyMoSmControlRequest::SetActivationStatus
		(
		CSatDataPackage* aDataPackage
		)
    {
    // Unpack data
    aDataPackage->UnPackData( iIsMoSmsCtrlActivated );
    TFLOGSTRING2("CSAT: CSatNotifyMoSmControlRequest::SetActivationStatus, %d",
    	iIsMoSmsCtrlActivated );
    }

// -----------------------------------------------------------------------------
// CSatNotifyMoSmControlRequest::ActivationStatus
// Returns ETrue if MO-SMS Control is activated
// -----------------------------------------------------------------------------
//
TBool CSatNotifyMoSmControlRequest::ActivationStatus
		(
		void
		)
    {
    TFLOGSTRING("CSAT: CSatNotifyMoSmControlRequest::ActivationStatus");
    return iIsMoSmsCtrlActivated;
    }
    
// -----------------------------------------------------------------------------
// CSatNotifyMoSmControlRequest::CleanAddressData
// This method cleans the input address data, so that all the bytes found
// after a 0xXF or a 0xFX are removed.
// -----------------------------------------------------------------------------
//
void CSatNotifyMoSmControlRequest::CleanAddressData
		( 
		TDes8& aAddr 
		)
    {
    TFLOGSTRING("CSAT: CSatNotifyMoSmControlRequest::CleanAddressData");
    // Starts from index 1, since index 0 is for TON/NPI    
    for ( TInt i=1; i < aAddr.Length(); i++ )
        {
        if ( 0xF0 == ( aAddr[i] & 0xF0 ) )
            {
            if ( ( i + 1 ) < aAddr.Length() )
                {
                aAddr.Delete( i + 1, aAddr.Length() - i - 1 );
                }
            break;
            }
        else if ( 0x0F == ( aAddr[i] & 0x0F ) )
            {
            aAddr.Delete( i, aAddr.Length() - i );
            break;
            }        
        }
    }
    
// -----------------------------------------------------------------------------
// CSatNotifyMoSmControlRequest::ParseNotification
// Extracts data from proactive command data
// -----------------------------------------------------------------------------
//
void CSatNotifyMoSmControlRequest::ParseNotification
		(
	    const TDesC8& aAtkData,
	    TDes8& aAddr1,
	    TDes8& aAddr2,
	    RSat::TAlphaId& aAlphaId
	    )
    {
    TFLOGSTRING("CSAT: CSatNotifyMoSmControlRequest::ParseNotification");
    
    // Input data:
    // aAtkData[0] : result
    // aAtkData[1][2] : length of BER-TLV, set n=1 if aAtkData[1]=0x81
    // aAtkData[2+n] : tag of first TLV
    // aAtkData[3+n][4+n] : length of first TLV, set nn=1 if aAtkData[3+n]=0x81
    // etc..
    
    // Comments drawn from SAT TS lab test cases:
    // - The NAA may insert a wild '0xD' character in addresses and therefore 
    // the phone sw should prevent the sending of the SMS. At the time this 
    // comment is being written, it is not clear which part prevents it, if 
    // prevents ? And this is not yet handled in SIM ATK TSY.
    // - The NAA may insert a 0xF in addresses, and the phone sw should discard
    // all characters placed after the 0xF. At the time when this
    // comment is being written, it is not clear which part should do that,
    // and this is not yet handled in SIM ATK TSY.
    
    // Check if the BER-TLV length is coded with 2 bytes.
    TInt indexInBerTlv( 1 );
    TUint8 tag( aAtkData[indexInBerTlv] );
    TUint8 lengthBerTlv( 0 );
    TInt n( ( KTwoByteLengthCoding == tag ) ? 1:0 );    
    lengthBerTlv = aAtkData[1 + n];
    indexInBerTlv = 2 + n;
    
    // Initialize Alpha ID
    aAlphaId.iAlphaId.Zero();
    
    // Extract TLVs and fill in output variables
    TBool address1_got( EFalse );
    while( lengthBerTlv )
        {
        // Get tag value without 'comprehension required' bit
        tag = aAtkData[indexInBerTlv] & 0x7F;
        // Length of TLV with 2 bytes ?
        TInt nn( ( KTwoByteLengthCoding == aAtkData[indexInBerTlv +1 ] )?1:0 );
        // Length of TLV
        TInt lengthTlv( aAtkData[indexInBerTlv + nn + 1] );
        
        // Check which TLV is received
        if ( ( KTlvAddressTag == tag ) && ( !address1_got ) )
            {
            TFLOGSTRING("CSAT: CSatNotifyMoSmControlRequest::ParseNotification\
                Address 1");
            // RP address first
            address1_got = ETrue;
            // Copy data to output variable
            aAddr1.Copy( aAtkData.Mid( indexInBerTlv + nn + 2, lengthTlv ) );
            if ( KReservedTonNpi1 != aAddr1[0] && 
            	 KReservedTonNpi2 != aAddr1[0] && ( 1 < lengthTlv ) )
                {
                CleanAddressData( aAddr1 );
                }            
            }
        else if ( KTlvAddressTag == tag )
            {
            TFLOGSTRING("CSAT: CSatNotifyMoSmControlRequest::ParseNotification\
                Address 2");
            // TP address. Copy data to output variable
            aAddr2.Copy( aAtkData.Mid( indexInBerTlv + nn + 2, lengthTlv ) );         
            if ( KReservedTonNpi1 != aAddr2[0] && 
            	 KReservedTonNpi2 != aAddr2[0] && ( 1 < lengthTlv ) )
                {
                CleanAddressData( aAddr2 );
                }    
            }
        else if ( KTlvAlphaIdentifierTag == tag )
            {
            TFLOGSTRING("CSAT: CSatNotifyMoSmControlRequest::ParseNotification\
                Alpha ID");
            // Alpha id must be converted to TBuf16/unicode
            if ( lengthTlv )
                {
                // Set Alpha id status
			        aAlphaId.iStatus = RSat::EAlphaIdProvided;
                TSatUtility::SetAlphaId( aAtkData.Mid( indexInBerTlv + nn + 2, 
                    lengthTlv ), aAlphaId.iAlphaId );                                
                }
            else
                {
                TFLOGSTRING("CSAT: CSatNotifyMoSmControlRequest:: \
                	ParseNotification. Alpha ID is NULL");
                aAlphaId.iStatus = RSat::EAlphaIdNull;
                }  
            }
 
        // Update length for the while loop    
        lengthBerTlv -= ( lengthTlv + 2 + nn );
        // Updata index for the while loop
        indexInBerTlv += ( lengthTlv + 2 + nn );
        }    
    }
    
// -----------------------------------------------------------------------------
// CSatNotifyMoSmControlRequest::VerifyNotificationData
// This method checks the consistency of the data sent by the NAA to the ME, 
// when the call is allowed and modified.
// -----------------------------------------------------------------------------
//
TBool CSatNotifyMoSmControlRequest::VerifyNotificationData
		( 
		TDes8& aRPAddr, 
		TDes8& aTPAddr 
		)
    {
    TFLOGSTRING("CSAT: CSatNotifyMoSmControlRequest::VerifyNotificationData");
    TBool ret( ETrue );    
    if ( ( 0 == aRPAddr.Length() && 0 == aTPAddr.Length() ) || 
         ( KMoSmCtrlMaxLengthAddr1Addr2 <= ( 
         	aRPAddr.Length() + aTPAddr.Length() ) ) ) 
        {
        ret = EFalse;
        }
    else
        {
        // Detect the presence of 'wild' values in the digits of the addresses       
        for ( TInt i = 0; i < aRPAddr.Length(); i++)
            {
            if ( ( 0x0A < ( 0x0F & aRPAddr[i] ) && 
                   0x0F > ( 0x0F & aRPAddr[i] ) ) ||
                 ( 0xA0 < ( 0xF0 & aRPAddr[i] ) && 
                   0xF0 > ( 0xF0 & aRPAddr[i] ) ) )
                {
                ret = EFalse;
                break;
                }            
            }
        for ( TInt i = 0; i < aTPAddr.Length(); i++)
            {
            if ( ( 0x09 < ( 0x0F & aTPAddr[i] ) && 
                   0x0F > ( 0x0F & aTPAddr[i] ) ) ||
                 ( 0x90 < ( 0xF0 & aTPAddr[i] ) && 
                   0xF0 > ( 0xF0 & aTPAddr[i] ) ) )
                {
                ret = EFalse;
                break;
                }            
            }        
        }    
    return ret;
    }
    
// End of File

