/*
* Copyright (c) 2002-2005 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:  SyncML HTTP client
*
*/


#include "nsmlhttpclient.h"
#include "nsmlerror.h"
#include <featmgr.h>

//Fix to Remove the Bad Compiler Warnings
#ifndef __WINS__
// This lowers the unnecessary compiler warning (armv5) to remark.
// "Warning:  #174-D: expression has no effect..." is caused by 
// DBG_ARGS8 macro in no-debug builds.
#pragma diag_remark 174
#endif


//============================================================
// Class CHttpEventHandler
//============================================================

//------------------------------------------------------------
// CHttpEventHandler::CHttpEventHandler()
// constructor
//------------------------------------------------------------
CHttpEventHandler::CHttpEventHandler()
	{
	}
//------------------------------------------------------------
// CHttpEventHandler::ConstructL( CNSmlHTTP* aAgent )
// 2-phase constructor
//------------------------------------------------------------
void CHttpEventHandler::ConstructL( CNSmlHTTP* aAgent )
	{
	FeatureManager::InitializeLibL();
	iAgent = aAgent;
	}
//------------------------------------------------------------
// CHttpEventHandler::~CHttpEventHandler()
// destructor
//------------------------------------------------------------
CHttpEventHandler::~CHttpEventHandler()
	{
		FeatureManager::UnInitializeLib();
	}
//------------------------------------------------------------
// CHttpEventHandler::NewLC()
//
//------------------------------------------------------------
CHttpEventHandler* CHttpEventHandler::NewLC()
	{
	CHttpEventHandler* me = new(ELeave)CHttpEventHandler();
	CleanupStack::PushL( me );
	return me;
	}
//------------------------------------------------------------
// CHttpEventHandler::NewL()
//
//------------------------------------------------------------
CHttpEventHandler* CHttpEventHandler::NewL()
	{
	CHttpEventHandler* me = NewLC();
	CleanupStack::Pop( me );
	return me;
	}
//------------------------------------------------------------
// CHttpEventHandler::MHFRunL( RHTTPTransaction aTransaction, 
// const THTTPEvent& aEvent )
//
//------------------------------------------------------------
void CHttpEventHandler::MHFRunL( 
    RHTTPTransaction aTransaction, 
    const THTTPEvent& aEvent )
	{
	TRequestStatus* iStatusForAgent = &this->iAgent->iStatus;
	
	switch ( aEvent.iStatus )
		{
        case THTTPEvent::EGotResponseHeaders:
			{
			DBG_FILE_CODE( aEvent.iStatus, 
                    _S8("EGotResponseHeaders...") );
//tarm start
if(FeatureManager::FeatureSupported(KFeatureIdSapPolicyManagement))
{
			this->iAgent->SaveCertificateL( aTransaction );
}
//tarm end
			// HTTP response headers have been received. 
			// We can determine now if there is
			// going to be a response body to save.
			RHTTPResponse resp = aTransaction.Response();

			// check that content-type is appropriate
			RStringPool strPool = aTransaction.Session().StringPool();
			RHTTPHeaders hdr = resp.GetHeaderCollection();
			RStringF contentType = strPool.OpenFStringL( KSmlContentType );
			THTTPHdrVal value;
			hdr.GetField( contentType, 0, value );
			
			RStringF fieldValStr = strPool.StringF( value.StrF() ); 
			const TDesC8& contentTypeStr = fieldValStr.DesC();
			
			TInt status = resp.StatusCode();
			DBG_FILE_CODE( status, _S8("Received HTTP status...") );
			
			DBG_ARGS8(_S8("CHttpEventHandler::MHFRunL() contentTypeStr: %S"), &contentTypeStr );
			
			if ( contentTypeStr != KSmlContentTypeDS 
				&& contentTypeStr != KSmlContentTypeDM )
				{
				//Error fix for BPSS-7H7H5S				
				DBG_FILE( _S8("CHttpEventHandler::MHFRunL() There is a mismatch in the Content Type") );
				
				status = CNSmlHTTP::SetErrorStatus( status );
				
				if (status == resp.StatusCode() )
				{
					DBG_FILE( _S8("Error in Communication string is set"));
					status = TNSmlError::ESmlCommunicationInterrupted;
				}
					
				// content mismatch
				aTransaction.Close();
				User::RequestComplete( iStatusForAgent, status);
				
				break;
				}

			if(this->iAgent->iSession == ESyncMLDSSession)
			    {
    	         RStringF serverContentEncoding = strPool.OpenFStringL( KSmlContentEncodingType );
    	         THTTPHdrVal serverContentEncodingValue;
    	         if(hdr.GetField( serverContentEncoding, 0, serverContentEncodingValue ) != KErrNotFound)	         
    	             {
        	         RStringF fieldServerContentEncodingValStr = strPool.StringF( serverContentEncodingValue.StrF() ); 
        	         const TDesC8& serverContentEncodingStr = fieldServerContentEncodingValStr.DesC();
        	         if( serverContentEncodingStr == KSmlContentDeflate)
        	             {
        	             this->iAgent->iServerContentEncoding = CNSmlHTTP::ExptDeflate;
        	             }
    	             }
    
    			 RStringF serverAcceptEncoding = strPool.OpenFStringL( KSmlAcceptEncodingType );
    	         THTTPHdrVal serverAcceptEncodingValue;
    	         if(hdr.GetField( serverAcceptEncoding, 0, serverAcceptEncodingValue )  != KErrNotFound )	         
    	             {
        	         RStringF fieldServerAcceptEncodingValStr = strPool.StringF( serverAcceptEncodingValue.StrF() ); 
        	         const TDesC8& serverAcceptEncodingStr = fieldServerAcceptEncodingValStr.DesC();
        	         if( serverAcceptEncodingStr.Find(KSmlContentDeflate) != KErrNotFound)
        	             {
        	             this->iAgent->iServerAcceptEncoding = CNSmlHTTP::ExptDeflate;
        	             }
    	             }
			    }
			
			if ( status == 200 )
				{
				this->iAgent->iDocumentLength = 0;
				}
			else if ( resp.HasBody() 
					&& ( status >= 200 ) 
					&& ( status < 300 ) 
					&& ( status != 204 ) )
				{
				TInt dataSize = resp.Body()->OverallDataSize();
				this->iAgent->iDocumentLength = dataSize;
				DBG_FILE_CODE( dataSize, _S8("Incoming packet length...") );
				}
			else
				{
				// canceling
				aTransaction.Close();
				DBG_FILE_CODE( status, _S8("Adding offset to http status...") );
				status = CNSmlHTTP::SetErrorStatus( status );
				DBG_FILE_CODE( status, _S8("Complete with internal \
				                http status value ...") );
				User::RequestComplete( iStatusForAgent, status );
				} 
			delete this->iAgent->iData;
			this->iAgent->iData = NULL;
			this->iAgent->iData = HBufC8::NewL( this->iAgent->iMaxMsgSize );
			} break;
        case THTTPEvent::EGotResponseBodyData:
            {
			DBG_FILE_CODE( aEvent.iStatus, _S8("EGotResponseBodyData...") );
			// Get the body data supplier
			iRespBody = aTransaction.Response().Body();
			RHTTPResponse resp = aTransaction.Response();
			TInt respDataSize = resp.Body()->OverallDataSize();
			DBG_FILE_CODE( respDataSize, _S8("number of bytes received...") );
			
			TPtrC8 bodyData;
			iRespBody->GetNextDataPart( bodyData );

			TPtr8 iDataPtr( this->iAgent->iData->Des() );
			if (respDataSize > this->iAgent->iMaxMsgSize)
				{	
				User::LeaveIfError( TNSmlError::ESmlStatusSizeMismatch );
				}
			else
				{
				iDataPtr.Append( bodyData );	
				}			

			// Done with that bit of body data
			iRespBody->ReleaseData();
			} break;
        case THTTPEvent::EResponseComplete:
            {
			DBG_FILE_CODE( aEvent.iStatus, _S8("EResponseComplete...") );
			} break;
        case THTTPEvent::ESucceeded:
            {
			DBG_FILE_CODE( aEvent.iStatus, _S8("ESucceeded...") );
			aTransaction.Close();
            User::RequestComplete( iStatusForAgent, KErrNone ); 
            } break;
        case THTTPEvent::EFailed:
            {
			DBG_FILE_CODE( aEvent.iStatus, _S8("EFailed...") );
			DBG_FILE_CODE( this->iAgent->iPreemptRequest, _S8("was this  prempted , is it > 0 so ignore ") );
			if(this->iAgent->iPreemptRequest==0)
			{
			aTransaction.Close();
            User::RequestComplete( iStatusForAgent, aEvent.iStatus );    	
			}
			else
			{
			 aTransaction.Close();
			 this->iAgent->iPreemptRequest--;	
			}
            } break;
		case THTTPEvent::ERedirectedPermanently:
			{
			DBG_FILE_CODE( aEvent.iStatus, _S8("ERedirectedPermanently...") );
			} break;
		case THTTPEvent::ERedirectedTemporarily:
			{
			DBG_FILE_CODE( aEvent.iStatus, _S8("ERedirectedTemporarily...") );
			} break;
       case  KServerUntrusted:
		    {
		    	if(FeatureManager::FeatureSupported(KFeatureIdSapPolicyManagement))
		    	{
		    DBG_FILE_CODE( aEvent.iStatus, _S8("Euntrustedcert") );	
		    aTransaction.Close();
            User::RequestComplete( iStatusForAgent, TNSmlError::ESmlUntrustedCert );
          }
		    }break;
        default:
            {
			if ( aEvent.iStatus < 0 )
				{
				DBG_FILE_CODE( aEvent.iStatus, _S8("error...") );
				}
            } break;
        }
	}
//------------------------------------------------------------
// CHttpEventHandler::MHFRunError( TInt /*aError*/, 
// RHTTPTransaction /*aTransaction*/, const THTTPEvent& /*aEvent*/ )
//
//------------------------------------------------------------
TInt CHttpEventHandler::MHFRunError( 
    TInt /*aError*/, 
    RHTTPTransaction /*aTransaction*/, 
    const THTTPEvent& /*aEvent*/ )
	{
	return KErrNone;
	}



