/*
* 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:           
*
*/











#include <s32strm.h>
#include <SenXmlUtils.h>

//#include "SenHostletConnectionLog.h"
#include "sendebug.h"
#include "senlogger.h"

#include "senhostletconnectionimpl.h"
#include "MSenHostlet.h"              // public
#include "MSenHostletRequest.h"       // public
#include "MSenHostletResponse.h"      // public
#include "senhostletrequest.h"
#include "senhostletresponse.h"

#include "rsenhostletconnection.h"

#include "senservicemanagerdefines.h" // internal Core\inc  - IPC enumerations

#include "SenXmlServiceDescription.h"

#include "senguidgen.h"  // internal: Utils\inc - the prefix length constant for WSF GUIDs
#include "senchunk.h"
#include "senidentifier.h"

#include "MSenMessage.h"
#include "senconnagentserver.h"
#include "senvtcptransportproperties.h"
#include "SenXmlReader.h"

namespace
    {
    _LIT8( KSenCidPostfix, "@example.org" );
    const TInt KMaxCidLength = 512;
    }


CSenHostletConnectionImpl* CSenHostletConnectionImpl::NewL(MSenHostlet& aProvider)
    {
    CSenHostletConnectionImpl* pNew = NewLC(aProvider);
    CleanupStack::Pop();
    return(pNew) ;
    }

CSenHostletConnectionImpl* CSenHostletConnectionImpl::NewLC(MSenHostlet& aProvider)
    {
    CSenHostletConnectionImpl* pNew = new (ELeave) CSenHostletConnectionImpl(aProvider);
    CleanupStack::PushL(pNew);
    pNew->ConstructL();
    return pNew;
    }

void CSenHostletConnectionImpl::ConstructL()
    {
    TInt connErr = iConnection.Connect();
    TInt connAttemp(0); // max 5 attempts are allowed
    while ( (connErr == KErrServerTerminated || connErr == KErrServerBusy)
                     && connAttemp < KSenMaxClientConnectionOpeningAttempts  )
        {
//        TLSLOG_L(iTlsLogChannel, KSenHostletConnectionLogLevel, "CSenHostletConnection::ConstructL - Server busy/going down");
        User::After(1000000); // wait for a second if server has been shut down
//        TLSLOG_L(iTlsLogChannel, KSenHostletConnectionLogLevel, "CSenHostletConnection::ConstructL - Creating connection");
        connErr = iConnection.Connect();
        connAttemp++;
        }
    if ( connErr != KErrNone )
        {
        User::Leave( connErr );
        }

    iConnectionID = iConnection.ConnectionID();
    iTlsLogChannel = KSenHostletConnectionLogChannelBase + iConnectionID;

    ipRegistrationTimer = CSenRegistrationTimer::NewL( *this );

#ifdef _SENDEBUG
    RThread thread;
    RProcess process;
    TFileName logFile;
    logFile.Append( KSenHostletConnectionLogFile().Left(KSenHostletConnectionLogFile().Length()-4) ); // exclude ".log" file extension
    logFile.AppendNum( iConnectionID );
    logFile.Append( KSenUnderline );
    logFile.Append( process.Name().Left(32));
    logFile.Append( KSenUnderline );
    logFile.Append( thread.Name().Left(20));
    logFile.Append( KSenHostletConnectionLogFile().Right(4) ); // postfix with ".log" file extension

    // Open connection to the file logger server
    TLSLOG_OPEN( iTlsLogChannel, KSenHostletConnectionLogLevel, KSenHostletConnectionLogDir, logFile );
    TLSLOG_L(iTlsLogChannel, KMinLogLevel, "CSenHostletConnection::ConstructL - About to establish new hostlet connection..");
    TLSLOG_FORMAT((iTlsLogChannel, KMinLogLevel, _L("- Connection ID: (%d)"), iConnectionID));
#endif

    User::LeaveIfError(EstablishConnectionL(iProvider));
    }

CSenHostletConnectionImpl::CSenHostletConnectionImpl(MSenHostlet& aProvider) :
    iProvider(aProvider),
    iErrorNumber(0),
    iErrorNumberBuffer(NULL, 0),
    iTxnId(KErrNotFound),
    iTxnIdBuffer(NULL, 0),
    iHostletTransactionMap(NULL),
    ipSessionId(NULL),
    iSessionIdBuffer(NULL, 0),
    iChunkNameNumber(0),
    ipChunkName(NULL),
    iAlive(ETrue),
    iConnectionID(KErrNotReady),
    iTlsLogChannel(KSenHostletConnectionLogChannelBase),
    iCancelSession(EFalse),
    ipFileProgressObserver(NULL),
    iRegisterFileObserverDone(EFalse),
    ipRegistrationTimer(NULL)
    {
    CActiveScheduler::Add(this);
    }

CSenHostletConnectionImpl::~CSenHostletConnectionImpl()
    {
    delete ipRegistrationTimer; // Invokes connagent registrations & subscribes for RProperty updates
    delete ipFileProgressObserver; // Subscriber (observer) for RProperty update
    TLSLOG(iTlsLogChannel, KMinLogLevel, _L("CSenHostletConnectionImpl::~CSenHostletConnectionImpl"));
    CSenHostletConnectionImpl::Cancel(); // Causes call to DoCancel()
    CSenHostletConnectionImpl::iAlive = EFalse;
   if (iFilesObserver)
        {
        CSenConnAgentServer::Close();
        }
    if (iAsyncOpsArray)
        {
        TInt count(iAsyncOpsArray->Count());
        for(TInt i=0; i<count; i++)
            {
            CSenAsyncOperation* pOp = (*iAsyncOpsArray)[i];
            if ( pOp )
                {
                TRequestStatus* status = &pOp->iStatus;
                User::RequestComplete( status, KErrSenCancelled );
                pOp->iActive = NULL;
                }
            }
        iAsyncOpsArray->ResetAndDestroy();
        delete iAsyncOpsArray;
        }

    if ( iHostletTransactionMap )
        {
        iHostletTransactionMap->Reset();
        delete iHostletTransactionMap;
        }

    delete ipSessionId;
    delete ipChunkName;

    iConnection.Close();

    // Close the log file and the connection to the server.
    TLSLOG_L(iTlsLogChannel, KMinLogLevel, "Log file closed.");
    TLSLOG_CLOSE( iTlsLogChannel );
    //TLSLOG_CLOSE( KSenHostletConnectionLogChannel );
    }


TInt CSenHostletConnectionImpl::Identifier()
    {
    return iConnectionID;    
    }

TInt CSenHostletConnectionImpl::RegisterFilesObserver()
    {
    TLSLOG(iTlsLogChannel, KMinLogLevel, _L("CSenHostletConnectionImpl::RegisterFilesObserver"));
    TInt retVal(KErrNone);
    const TDesC& name = CSenConnAgentServer::Open();
    if (name == KNullDesC)
        {
        return KErrGeneral;
        }
    retVal = iConnection.RegisterTransferObserver(&name, iFilesObserver);
    TLSLOG(iTlsLogChannel, KMinLogLevel, _L("CSenHostletConnectionImpl::RegisterFilesObserver Completed"));
    return retVal; 
    }

TPtrC CSenHostletConnectionImpl::SessionID()
    {
    if(ipSessionId)
        {
        return *ipSessionId;
        }
    else
        {
        return KNullDesC();
        }
    }

TInt CSenHostletConnectionImpl::RespondL(MSenHostletResponse& aResponse)
    {
    TLSLOG_L(iTlsLogChannel, KMinLogLevel, "CSenHostletConnectionImpl::RespondL");
    TInt retVal(KErrNone);
    
    retVal = HostletTransactionMapL().Find(aResponse.RequestId());
    
    if ( retVal != KErrNotFound )
        {
        CSenHostletTransaction* pTransaction = (CSenHostletTransaction*)HostletTransactionMapL().ValueAt(retVal);
        CSenChunk* pOperation = (CSenChunk*)pTransaction->Chunk();
        if ( pOperation )
            {
            // First check whether this request has ALREADY BEEN responded (to prevent multiple RespondL
            // calls performed inside MSenHostlet::ServiceL / per single request):
            MSenMessage::TDirection direction = pOperation->ChunkHeader().MessageDirection();
            
            if( direction == MSenMessage::EOutbound )
                {
                // Note: direction is always consumers point of view. So outbound here
                // means "a request from consumer" - inbound would be "response to consumer".
                
                // Note: this sort of really double-safety action, since hostlet transport plugin also turns the 
                // direction to "inbound" before sending responses to consumers. But better be safe than sorry
                pOperation->ChunkHeader().SetMessageDirection( MSenMessage::EInbound );


                MSenProperties* pProperties = aResponse.ResponseProperties();
                if( pProperties )
                    {
                    // Serialize properties
                    HBufC8* pPropsAsXml = pProperties->AsUtf8LC();
                    // Store the properties class type into chunk
                    MSenProperties::TSenPropertiesClassType type
                        = pProperties->PropertiesClassType();
                    pOperation->ChunkHeader().SetPropertiesType( type );
                    // Store response message AND properties into chunk
                    TPtrC8 properties = pPropsAsXml->Des();
                    pOperation->DescsToChunk( aResponse.ResponseUtf8(), properties );
                    CleanupStack::PopAndDestroy(pPropsAsXml);
                    }
                else
                    {
                    // There is only a response message. Store it into chunk.
                    pOperation->ChunkHeader().SetPropertiesType(MSenProperties::ENotInUse);
                    pOperation->DescToChunk( aResponse.ResponseUtf8() );
                    }            
                CSenAsyncOperation* pSenAO = CSenAsyncOperation::NewL(this);
                iConnection.ProvideResponse(pSenAO->iStatus, 
                                            pSenAO->iErrorNumberBuffer,
                                            pSenAO->iTxnIdBuffer,
                                            *pOperation,
                                            aResponse.ResponseCode());
                }
            else
                {
                retVal = KErrAlreadyExists; 
                }                
            }
        else
            {
            retVal = KErrNotFound; 
            }
        }
        
    TLSLOG_FORMAT((iTlsLogChannel, KNormalLogLevel, _L8("- ProvideResponse returned: %d"), retVal));
    return retVal;
    }

// This method is executed when one of the static constructors of
// service connection (NewL or NewLC) is called.
TInt CSenHostletConnectionImpl::EstablishConnectionL(MSenHostlet& aProvider)
    {
    TLSLOG_L(iTlsLogChannel, KMinLogLevel, "CSenHostletConnectionImpl::InitializeL");

	TInt retVal = KErrNone;
    ipInterface = NULL;
    ipInterface = aProvider.GetInterfaceByUid(KSenInterfaceUidFilesObserver);
    if(ipInterface)
    {
        iFilesObserver = (MSenFilesObserver*) ipInterface;

        
        if ( !iRegisterFileObserverDone )
            {
            TLSLOG_L( iTlsLogChannel, KMinLogLevel, "EstablishConnectionL(): - Calling IssueRegistrations()");
            ipRegistrationTimer->IssueRegistrations( ETrue );
                TLSLOG_L(iTlsLogChannel, KMinLogLevel ,"- RegisterFilesObserver() failed!");
            } // end of if ( !iRegisterFileObserverDone )
        
    }
    if(retVal == KErrNone)
        {
    TPtrC8 endpoint     = aProvider.Endpoint();
    TPtrC8 contract     = aProvider.Contract();
    TPtrC8 frameworkId  = aProvider.FrameworkId();
    CSenXmlServiceDescription* pDescription = CSenXmlServiceDescription::NewLC(endpoint, contract);
    pDescription->SetFrameworkIdL(frameworkId);

    aProvider.DescribeServiceL(*pDescription);

    if(pDescription->Endpoint().Length()==0 && pDescription->Contract().Length()==0)
        {
        User::Leave(KErrSenNoContractNoEndPoint);
        }
        
    if ( pDescription->Endpoint().Length() == 0 )
        {
#ifdef EKA2            
        RProcess process;
        TSecureId sId = process.SecureId();
        if ( sId == 0 )
            {
            User::Leave(KErrSenNoEndpoint);
            }

        TBuf8<128> buf;
        TUint i(sId);
        _LIT8(KFormat, "%u");
        buf.Format(KFormat, i);

        pDescription->SetEndPointL(buf);
#else
        User::Leave(KErrSenNoEndpoint); // in EKA1, endpoints are not generated!
#endif // EKA2/EKA1        
        }

    // Ensure that hostlet connection transport-plugin cue is applied,
    // unless the application has specified some other plug-in:
    TPtrC8 cue = pDescription->TransportCue();
    if( cue.Length() == 0 )
        {
        // Set the default cue (hostlet connection transport plug-in) to the XML SD:
        pDescription->SetTransportCueL(KSenTransportCueHostletConnection);
//        LOG_WRITEFORMAT((_L8("- Setting the default transport cue: '%S'"), &KSenTransportCueHostletConnection()));
        }


#ifdef _FORCE_DESCRIBED_MSW_2005_08_CONTRACT_TO_2006_10
    /// // Hard coded workaround for update hostlet contract: // ///
    //     Update contract from 2005 => 2006
    _LIT8( KMessaging200508, "http://schemas.live.com/mws/2005/08/messaging" );
    _LIT8( KMessaging200510, "http://schemas.live.com/mws/2006/10/messaging" );
    if( pDescription->Contract() == KMessaging200508 )
        {
        pDescription->SetContractL( KMessaging200510 );
        }
#endif // _FORCE_DESCRIBED_MSW_2005_08_CONTRACT_TO_2006_10


#ifdef _SENDEBUG
    //TPtrC8 providerID  = ((CSenXmlServiceDescription&)aSD).ProviderId();

    TLSLOG_L(iTlsLogChannel, KMinLogLevel, "-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|");
    TLSLOG_FORMAT((iTlsLogChannel, KMinLogLevel, _L8("- FrameworkID:  %S"), &frameworkId ));
    TLSLOG_FORMAT((iTlsLogChannel, KMinLogLevel, _L8("- Endpoint:     %S"), &endpoint ));
    TLSLOG_FORMAT((iTlsLogChannel, KMinLogLevel, _L8("- Contract:     %S"), &contract ));
    TLSLOG_FORMAT((iTlsLogChannel, KMinLogLevel, _L8("- TransportCue: %S"), &cue ));
//    LOG_WRITEFORMAT((iTlsLogChannel, KSenHostletConnectionLogLevel, _L8("- ProviderID:  %S"), &providerID ));
    TLSLOG_L(iTlsLogChannel, KMinLogLevel, "-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|");
#endif //_SENDEBUG            
    
    HBufC8* pServiceDescriptionXml = pDescription->AsXmlL();
    CleanupStack::PopAndDestroy(pDescription);

    CleanupStack::PushL(pServiceDescriptionXml);

#ifdef _SENDEBUG
    TLSLOG_L(iTlsLogChannel, KMinLogLevel, "CSenHostletConnectionImpl::EstablishConnectionL - Service description:");
    if ( pServiceDescriptionXml )
        {
            TPtrC8 xml = pServiceDescriptionXml->Des();
            TLSLOG_ALL(iTlsLogChannel, KMinLogLevel, (xml));
        }
#endif // _SENDEBUG
    
	 if ( pServiceDescriptionXml )
		{
			TPtr8 ptrServiceDescriptionXml(pServiceDescriptionXml->Des());

			retVal = iConnection.Establish(ptrServiceDescriptionXml);
		}
		else
		{
	    TLSLOG_L(iTlsLogChannel, KMinLogLevel, "EstablishConnectionL ---- Returning KErrGeneral");		
		retVal = KErrGeneral;
		}

    TLSLOG_FORMAT((iTlsLogChannel, KNormalLogLevel, _L("- Establish returned: %d"), retVal));
    User::LeaveIfError( retVal );

    CleanupStack::PopAndDestroy(pServiceDescriptionXml);

    // Start awaiting for next hostlet request
    iErrorNumber = 0;
    iTxnId = 0;

    CSenAsyncOperation* pSenAO = CSenAsyncOperation::NewL(this); // appends itself into array

    // NOTE, following ASYNC AwaitRequest() will stay as pending IPC -operation; this is the design:
    iConnection.AwaitRequest(pSenAO->iStatus, pSenAO->iErrorNumberBuffer, pSenAO->iTxnIdBuffer); 
        }
	TLSLOG_L(iTlsLogChannel, KMinLogLevel, "CSenHostletConnectionImpl::InitializeL Completed");        
    return retVal;
    }

void CSenHostletConnectionImpl::RunL()
    {
    TLSLOG_FORMAT((iTlsLogChannel, KNormalLogLevel, _L("CSenHostletConnectionImpl::RunL( %d )"),  iStatus.Int()));
    }
    
void CSenHostletConnectionImpl::HandleErrorFromChildAOL(TInt aError, TInt aTxnId, const TDesC8& aDesc, CSenAsyncOperation& aChild )
    {
    TLSLOG_L(iTlsLogChannel, KMinLogLevel, "CSenHostletConnectionImpl::HandleErrorFromChildAOL");
    TInt leaveCode(KErrNone);
    TRAP( leaveCode, iProvider.OnServiceCompleteL(aTxnId, aError, aDesc); )
    
    HostletTransactionMapL().RemoveByKey(aTxnId);
    
    TLSLOG_L(iTlsLogChannel, KMinLogLevel, "CSenHostletConnectionImpl::HandleErrorFromChildAOL:");
#ifdef _SEDEBUG
    if( leaveCode != KErrNone ) 
        {
        TLSLOG_FORMAT((iTlsLogChannel, KMinLogLevel, _L(" - OnServiceCompleteL leaved: %d"), leaveCode));
        }
    if( aChild.iStatus.Int() == ESenOnServiceComplete && aError == KErrSenCancelled )
        {
        TLSLOG_L(iTlsLogChannel, KMinLogLevel, "- Await was cancelled (ESenOnServiceComplete).");
        }
#endif // _SENDEBUG
    if( aChild.iStatus.Int() == ESenOnServiceComplete && iAlive )
        {
        CSenAsyncOperation* pSenAO = CSenAsyncOperation::NewL(this); // appends itself into array
        iConnection.AwaitRequest(pSenAO->iStatus, pSenAO->iErrorNumberBuffer, pSenAO->iTxnIdBuffer); 
        }
    leaveCode = 0; // not used in release builds
    TLSLOG_L(iTlsLogChannel, KMinLogLevel, "CSenHostletConnectionImpl::HandleErrorFromChildAOL Completed");
    }
    
void CSenHostletConnectionImpl::HandleMessageFromChildAOL(TInt aStatus, CSenAsyncOperation& aChild)
    {
    TLSLOG_FORMAT((iTlsLogChannel, KMinLogLevel, _L("CSenHostletConnectionImpl::HandleMessageFromChildAOL( %d )"), aStatus));

    iAsyncOpsCount--;
//    TLSLOG_FORMAT((iTlsLogChannel, KSenHostletConnectionLogLevel, _L("One asynchronous operation completed. Pending iAsyncOpsCount: %i"), iAsyncOpsCount));
    
    TLSLOG_FORMAT((iTlsLogChannel, KNormalLogLevel, _L("One asynchronous operation completed. Pending iAsyncOpsCount: %i"), iAsyncOpsCount));
    
    if ( aStatus == ESenOnServiceComplete) // temporary: implement "acquire request handle" operation and use switch case here..
        {
        TInt leaveCode(KErrNone);
        TRAP(leaveCode, iProvider.OnServiceCompleteL(aChild.iTxnId, aChild.iErrorNumber, KNullDesC8); ) 
        
        HostletTransactionMapL().RemoveByKey(aChild.iTxnId);
        
        TLSLOG_L(iTlsLogChannel, KMinLogLevel, "CSenHostletConnectionImpl::HandleMessageFromChildAOL: ESenOnServiceComplete");
#ifdef _SEDEBUG
        if( leaveCode != KErrNone ) 
            {
            TLSLOG_FORMAT((iTlsLogChannel, KMinLogLevel, _L(" - OnServiceCompleteL leaved: %d"), leaveCode));
            }
        if( aChild.iErrorNumber == KErrSenCancelled )
            {
            TLSLOG_L(iTlsLogChannel, KMinLogLevel, "- Await was cancelled.");
            }
#endif // _SENDEBUG
        if( aChild.iErrorNumber != KErrSenCancelled && iAlive )
            {
            CSenAsyncOperation* pSenAO = CSenAsyncOperation::NewL(this); // appends itself into array

            // NOTE, following ASYNC AwaitRequest() will stay as pending IPC -operation; this is the design:
            iConnection.AwaitRequest(pSenAO->iStatus, pSenAO->iErrorNumberBuffer, pSenAO->iTxnIdBuffer); 
            }
        leaveCode = 0; // not used in release builds
        }
    else if ( aStatus > KErrNone )
        {
        TLSLOG_L(iTlsLogChannel, KMinLogLevel, "- handle received.");
        CSenChunk* pOperation = CSenChunk::NewLC(KNullDesC);
        TInt retVal = pOperation->OpenChunkFromHandleNumberL(aStatus);
        if ( retVal == KErrNone )
            {
            CSenHostletTransaction* pHostletTxn = CSenHostletTransaction::NewL(pOperation);
            CleanupStack::Pop(pOperation);
            CleanupStack::PushL(pHostletTxn);
            
            TInt* pTxnId = new (ELeave) TInt(pOperation->ChunkHeader().TransactionId());
            CleanupStack::PushL(pTxnId);
            retVal = HostletTransactionMapL().Append(pTxnId, pHostletTxn);
            
            if ( retVal == KErrNone )
                {
                CleanupStack::Pop(pTxnId);
                CleanupStack::Pop(pHostletTxn);
                TPtrC8 request;
                retVal = pOperation->DescFromChunk(request);
                
                if ( retVal == KErrNone )
                    {
                    RThread thread;
                    CSenIdentifier* pIdentifier = CSenIdentifier::NewL();
                    pHostletTxn->SetIdentifier(pIdentifier);
                    
                    CSenHostletRequest* pRequest =
                            CSenHostletRequest::NewL(pOperation->ChunkHeader().TransactionId(),
                                                     request,
                                                     thread,
                                                     *pIdentifier,
                                                     pOperation);
                    pHostletTxn->SetRequest(pRequest);
                                                     
                    CSenHostletResponse* pResponse = 
                            CSenHostletResponse::NewL(pOperation->ChunkHeader().TransactionId());
                    pHostletTxn->SetResponse(pResponse);
                    
					MSenProperties::TSenPropertiesClassType type = MSenProperties::ESenVtcpTransportProperties ;
					TPtrC8 properties = pRequest->Properties(type) ;
					if (properties != KNullDesC8)
						{
						CSenXmlReader* pXmlReader = CSenXmlReader::NewL();
						if(pXmlReader)	
							{
							CleanupStack::PushL(pXmlReader);
							CSenVtcpTransportProperties * vtcpTransProp = CSenVtcpTransportProperties::NewL(properties, *pXmlReader);
							if(vtcpTransProp)
							    {
							    CleanupStack::PushL(vtcpTransProp);
								TBool boolValue = EFalse ;
								if (vtcpTransProp->OnewayMessageOnOffL(boolValue) != KErrNotFound
									&& boolValue)
									{
									//Now hostlet implementation can automaticaly reply with zero-length
									//string (KNullDesC8)
									//NOW SET THE ONE WAY RESPONSE PROPERTY AS WELL
									pResponse->SetResponseUtf8L(KNullDesC8(), KErrNone, vtcpTransProp) ;
						            iProvider.ServiceL(*pRequest, *pResponse);
									//RespondL(*pResponse) ; 
									}
									else
									{
						      		iProvider.ServiceL(*pRequest, *pResponse);
									//RespondL(*pResponse) ; 
									}
								CleanupStack::PopAndDestroy(vtcpTransProp) ;
								}
							CleanupStack::PopAndDestroy(pXmlReader) ;					
							}
						}
					else
						{
			            iProvider.ServiceL(*pRequest, *pResponse);
						}
//                    if( iAlive )
//                        {
//                        CSenAsyncOperation* pSenAO = CSenAsyncOperation::NewL(this); // appends itself into array
//                        iConnection.AwaitRequest(pSenAO->iStatus, pSenAO->iErrorNumberBuffer, pSenAO->iTxnIdBuffer); 
//                        }
                    }
                else
                    {
                    User::Leave(retVal);
                    }
                }
            else
                {
                CleanupStack::PopAndDestroy(pTxnId);
                CleanupStack::PopAndDestroy(pHostletTxn);
                User::Leave(retVal);
                }
            }
        else
            {
            CleanupStack::PopAndDestroy(pOperation);
            User::Leave(retVal);
            }
        }
    else
        {
        User::Leave(aStatus);
        }
                  
    /*                                         
    switch (aStatus)
        {
        case ESenHostletRequestPending:
            {
            TLSLOG_L(iTlsLogChannel, KSenHostletConnectionLogLevel, "HandleMessageFromChildAOL: ESenHostletRequestPending");
            if (iErrorNumber == KErrNone)
                {
                TLSLOG_FORMAT((iTlsLogChannel, KSenHostletConnectionLogLevel, _L("- Request from consumer received:"), iSessionIdBuffer.Length()));


                //TInt handle = iConnection.AcquireRequestHandle(aChild.iErrorNumberBuffer, aChild.iTxnIdBuffer);
                //CSenChunk* pChunk = CSenChunk::OpenChunkFromRMsgL

                }

            }
        break;

        case ESenInternalError:
            {
            // we could have someting in iErrorNumber in some cases
            TLSLOG_L(iTlsLogChannel, KSenHostletConnectionLogLevel, "HandleMessageFromChildAOL: ESenInternalError");
            TLSLOG_FORMAT((iTlsLogChannel, KSenHostletConnectionLogLevel, 
                _L("- Last received error from server: (%d)"),
                    iErrorNumber));

            //DeliverResponseL(KNullDesC8, KErrSenInternal);
            }
            break;


        default:
            {
#ifdef _SENDEBUG                
            if(aStatus == KErrPermissionDenied)
                {
                TLSLOG_L(iTlsLogChannel, KSenHostletConnectionLogLevel, "HandleMessageFromChildAOL: default - KErrPermissionDenied");
                }
            else
                {
                TLSLOG_L(iTlsLogChannel, KSenHostletConnectionLogLevel, "RunL: default - unexpected error.");
                TLSLOG_FORMAT((iTlsLogChannel, KSenHostletConnectionLogLevel, _L("Last received error from server: (%d)"), iErrorNumber));
                }
            TLSLOG_FORMAT((iTlsLogChannel, KSenHostletConnectionLogLevel, _L("RunL, iStatus.Int(): (%d)"), iStatus.Int()));
            
#endif // _SENDEBUG             
            // WSF does not generalize errors:
            //DeliverResponseL(KNullDesC8, aStatus);
            break ;
            }
        }*/
    TLSLOG_L(iTlsLogChannel, KMinLogLevel, "CSenHostletConnectionImpl::HandleMessageFromChildAOL Completed");
    }

void CSenHostletConnectionImpl::DoCancel()
    {
    TLSLOG(iTlsLogChannel, KMinLogLevel, _L("CSenHostletConnectionImpl::DoCancel"));
    TInt cancelLeaveCode(KErrNone);
    if (iCancelSession == EFalse)
        {
        CSenAsyncOperation* pSenAO = CSenAsyncOperation::NewL(this);
        TRAP(cancelLeaveCode, iConnection.CancelSession(pSenAO->iStatus));
        
    #ifdef _SENDEBUG
        if(cancelLeaveCode!=KErrNone)
            {
            TLSLOG_FORMAT((iTlsLogChannel, KMinLogLevel, _L("- CancelSession leaved: %d)"), cancelLeaveCode));
            }
    #endif
        cancelLeaveCode=0;   
        iCancelSession = ETrue; 
        }
    TLSLOG(iTlsLogChannel, KMinLogLevel, _L("CSenHostletConnectionImpl::DoCancel Completed"));
    }
RHostletTransactionMap& CSenHostletConnectionImpl::HostletTransactionMapL()
    {
    if ( !iHostletTransactionMap )
        {
        iHostletTransactionMap = new (ELeave) RHostletTransactionMap(ETrue, ETrue);
        }
    return *iHostletTransactionMap;
    }
    
RPointerArray<CSenAsyncOperation>& CSenHostletConnectionImpl::AsyncOpsArrayL()
    {
    if(!iAsyncOpsArray)
        {
        iAsyncOpsArray = new (ELeave) RPointerArray<CSenAsyncOperation>;
        }
    return *iAsyncOpsArray;
    }

TInt CSenHostletConnectionImpl::RegisterAndSubscribeFileProgressObserversL()
    {
    TInt retCode( KErrNone );
#ifndef RD_SEN_DISABLE_TRANSFER_PROGRESS_FOR_HC        
    if(iFilesObserver && !iRegisterFileObserverDone)
    	{
    	
  #ifndef RD_SEN_USE_PUBSUB_FOR_OUTGOING_FILE_PROGRESS // pub&sub not in use for outgoing file progress
        TLSLOG( iTlsLogChannel, KMinLogLevel,(_L("CSenHostletConnectionImpl::RegisterAndSubscribeFileProgressObserversL: RD_SEN_USE_PUBSUB_FOR_OUTGOING_FILE_PROGRESS == FALSE")));
    	retCode = RegisterFilesObserver();
  #else // RD_SEN_USE_PUBSUB_FOR_OUTGOING_FILE_PROGRESS == TRUE
        TLSLOG( iTlsLogChannel, KMinLogLevel,(_L("CSenHostletConnectionImpl::RegisterAndSubscribeFileProgressObserversL: RD_SEN_USE_PUBSUB_FOR_OUTGOING_FILE_PROGRESS == TRUE")));
    	ipFileProgressObserver = CSenFileProgressObserver::NewL( *iFilesObserver, iConnectionID );

    #ifdef RD_SEN_USE_CONNAGENT_FOR_SOAP_PROGRESS
        TLSLOG_L( iTlsLogChannel, KMinLogLevel, "CSenHostletConnectionImpl::RegisterAndSubscribeFileProgressObserversL: RD_SEN_USE_CONNAGENT_FOR_SOAP_PROGRESS == TRUE");
        TLSLOG_L( iTlsLogChannel, KMinLogLevel, "=> calling RegisterFilesObserver()");
        retCode = RegisterFilesObserver(); // MIXED MODE, using conn agent for SOAP progress..
    #else // RD_SEN_USE_CONNAGENT_FOR_SOAP_PROGRESS == FALSE
        TLSLOG_L( iTlsLogChannel, KMinLogLevel, "CSenHostletConnectionImpl::RegisterAndSubscribeFileProgressObserversL: RD_SEN_USE_CONNAGENT_FOR_SOAP_PROGRESS == FALSE");
    #endif // RD_SEN_USE_CONNAGENT_FOR_SOAP_PROGRESS

  #endif // RD_SEN_USE_PUBSUB_FOR_OUTGOING_FILE_PROGRESS end 	
    	iRegisterFileObserverDone = ETrue; // register only once
    	}
#else
    TLSLOG_L( iTlsLogChannel, KMinLogLevel, "CSenHostletConnectionImpl::RegisterAndSubscribeFileProgressObserversL: RD_SEN_DISABLE_TRANSFER_PROGRESS_FOR_HC == TRUE, not registering connagent, nor subscribing for the RProperty");
#endif // end of: #ifndef RD_SEN_DISABLE_TRANSFER_PROGRESS_FOR_HC    
    return retCode;
    }
        




CSenAsyncOperation* CSenAsyncOperation::NewL(CSenHostletConnectionImpl* aActive)
    {
    CSenAsyncOperation* pNew = NewLC(aActive);
    CleanupStack::Pop();
    return(pNew);
    }

CSenAsyncOperation* CSenAsyncOperation::NewLC(CSenHostletConnectionImpl* aActive)
    {
    CSenAsyncOperation* pNew = new (ELeave) CSenAsyncOperation(aActive);
    CleanupStack::PushL(pNew);
    pNew->ConstructL();
    return pNew;
    }
    
CSenAsyncOperation::CSenAsyncOperation(CSenHostletConnectionImpl* aActive)
:   CActive(EPriorityNormal),
    iActive(aActive),
    iErrorNumber(0),
    iErrorNumberBuffer(NULL, 0),
    iTxnId(0),
    iTxnIdBuffer(NULL, 0)
    {
    CActiveScheduler::Add(this);
    }

void CSenAsyncOperation::ConstructL()
    {
    iErrorNumberBuffer.Set(reinterpret_cast<TUint8*>(&iErrorNumber),
                           sizeof(TInt),
                           sizeof(TInt));
                           
    iTxnIdBuffer.Set(reinterpret_cast<TUint8*>(&iTxnId),
                     sizeof(TInt),
                     sizeof(TInt));
                     
    SetActive();
#ifdef EKA2
    iActive->AsyncOpsArrayL().AppendL(this);
#else
    RPointerArray<CSenAsyncOperation>& ops = iActive->AsyncOpsArrayL();
    User::LeaveIfError(ops.Append(this));
#endif

    iActive->iAsyncOpsCount++;
    }

CSenAsyncOperation::~CSenAsyncOperation()
    {
    Cancel(); // invokes CSenAsyncOperation::DoCancel()
    }

void CSenAsyncOperation::RunL()
    {
    if ( iActive )
        {
        iActive->iErrorNumber = iErrorNumber;
        iActive->iTxnId = iTxnId;    
        iActive->HandleMessageFromChildAOL(iStatus.Int(), *this);
            
        TInt idx = iActive->AsyncOpsArrayL().Find(this);
        if (idx >= 0)
            {
            iActive->AsyncOpsArrayL().Remove(idx);
            }
        }
    delete this;
    }
    
TInt CSenAsyncOperation::RunError(TInt aError)
    {
    TInt leaveCode( KErrNone );
    if (iActive)
        {
        TRAP( leaveCode, iActive->HandleErrorFromChildAOL(aError, iTxnId, KNullDesC8, *this); ) 

        RPointerArray<CSenAsyncOperation>* pOps = NULL;
        TRAP( leaveCode, pOps = &(iActive->AsyncOpsArrayL()); )
        if ( pOps )
            {
            TInt idx = pOps->Find(this);
            if ( idx != KErrNotFound )
                {
                pOps->Remove( idx );
                }
            }
        delete this;
        }
    return leaveCode; // return != KErrNone ONLY and ONLY IF the error really could not be handled by this AO!
    }
        
void CSenAsyncOperation::DoCancel()
    {
    }

CSenHostletTransaction* CSenHostletTransaction::NewL(CSenChunk* aSenChunk)
    {
    CSenHostletTransaction* pNew = NewLC(aSenChunk);
    CleanupStack::Pop(pNew);
    return(pNew);
    }

CSenHostletTransaction* CSenHostletTransaction::NewLC(CSenChunk* aSenChunk)
    {
    CSenHostletTransaction* pNew = new (ELeave) CSenHostletTransaction(aSenChunk);
    CleanupStack::PushL(pNew);
    return pNew;
    }

CSenHostletTransaction::~CSenHostletTransaction()
    {
    delete iIdentifier;
    delete iSenChunk;
    delete iRequest;
    delete iResponse;
    }

CSenHostletTransaction::CSenHostletTransaction(CSenChunk* aSenChunk)
    : iSenChunk( aSenChunk )
    {
    }

void CSenHostletTransaction::SetChunk(CSenChunk* aChunk)
    {
    iSenChunk = aChunk;
    }
        
CSenChunk* CSenHostletTransaction::Chunk()
    {
    return iSenChunk;
    }

void CSenHostletTransaction::SetIdentifier(CSenIdentifier* aIdentifier)
    {
    iIdentifier = aIdentifier;
    }
    
CSenIdentifier* CSenHostletTransaction::Identifier()
    {
    return iIdentifier;
    }

void CSenHostletTransaction::SetRequest(CSenHostletRequest* aRequest)
    {
    iRequest = aRequest;
    }
    
CSenHostletRequest* CSenHostletTransaction::Request()
    {
    return iRequest;
    }

void CSenHostletTransaction::SetResponse(CSenHostletResponse* aResponse)
    {
    iResponse = aResponse;
    }

CSenHostletResponse* CSenHostletTransaction::Response()
    {
    return iResponse;
    }
    


// ------------------------------------------------------------------------------------------------------------

CSenFileProgressObserver* CSenFileProgressObserver::NewL( MSenFilesObserver& aObserver,
                                                          TInt aConnectionID )
    {
    CSenFileProgressObserver* pNew = NewLC( aObserver, aConnectionID );
    CleanupStack::Pop();
    return(pNew);
    }

CSenFileProgressObserver* CSenFileProgressObserver::NewLC( MSenFilesObserver& aObserver,
                                                           TInt aConnectionID )
    {
    CSenFileProgressObserver* pNew = new (ELeave) CSenFileProgressObserver( aObserver, aConnectionID );
    CleanupStack::PushL(pNew);
    pNew->ConstructL();
    return pNew;
    }
    
    

CSenFileProgressObserver::CSenFileProgressObserver( MSenFilesObserver& aObserver,
                                                    TInt aConnectionID )
//:   CActive(EPriorityNormal),
:   CActive(EPriorityMore),
    iFileProgressObserver(&aObserver),
    iConnectionID(aConnectionID)
    {
    }

void CSenFileProgressObserver::ConstructL()
    {
    _LIT_SECURITY_POLICY_PASS(KReadPropPassAll);
    _LIT_SECURITY_POLICY_S0(KWritePropSenCoreSidOnlyPolicy, KServerUid3.iUid);
    
    // Define the property
    TInt err = RProperty::Define( KSenInterfaceUidFilesObserver,
                                  iConnectionID,
                                  RProperty::ELargeByteArray, 
                                  KReadPropPassAll,
                                  KWritePropSenCoreSidOnlyPolicy,
                                  512 );
	// Use KSenInterfaceUidFilesObserver extended consumer interface UID
	User::LeaveIfError(iFileProgressProperty.Attach(KSenInterfaceUidFilesObserver,  iConnectionID)); // KSenInterfaceUidFilesObserver UID will be category
    CActiveScheduler::Add(this);
    // Initial subscription
    iFileProgressProperty.Subscribe(iStatus);
    SetActive();
    iStatus = KRequestPending;
    }

CSenFileProgressObserver::~CSenFileProgressObserver()
    {
    Cancel();
    iFileProgressProperty.Close();
    
    TInt err = RProperty::Delete( KSenInterfaceUidFilesObserver, iConnectionID );
    
    }

void CSenFileProgressObserver::DoCancel()
    {
    iFileProgressProperty.Cancel();
    }

void CSenFileProgressObserver::RunL()
    {
    // Resubscribe before processing new value to prevent missing updates(!):
	iFileProgressProperty.Subscribe( iStatus );
    SetActive();
    iStatus = KRequestPending;

    TLSLOG_L( KSenHostletConnectionLogChannelBase + iConnectionID, KSenServiceConnectionStatusLogLevel, "CSenFileProgressObserver::RunL" );
       
    TPckgBuf<TFileOutgoingTransferProgressBase> progress;
    TInt getPropertyCode = iFileProgressProperty.Get( progress );
    if ( getPropertyCode == KErrNone )
        {
        TLSLOG_L( KSenHostletConnectionLogChannelBase + iConnectionID, KSenServiceConnectionStatusLogLevel, "CSenFileProgressObserver::RunL [new value published] - Calling TransferProgress" );
        TFileOutgoingTransferProgressBase data = progress();

        HBufC8* pCid = HBufC8::NewLC( KMaxCidLength );
        TPtr8 cid = pCid->Des();
        cid.Num( data.iCid );
        if( data.iCid2 != KErrNotFound )
            {
            cid.AppendNum( data.iCid2 );
            }
        if( data.iHasCidPostfix )
            {
            cid.Append( KSenCidPostfix );
            }
        TLSLOG_FORMAT(( KSenHostletConnectionLogChannelBase + iConnectionID, KSenServiceConnectionStatusLogLevel, _L8("- txn '%d', progress '%d', isIncoming '%d', cid '%S',  '"), data.iTxnId, data.iProgress, data.iIsIncoming, &cid ));
        TRAP_IGNORE( iFileProgressObserver->TransferProgress( data.iTxnId, data.iIsIncoming, KNullDesC8, cid, data.iProgress );	)
        CleanupStack::PopAndDestroy( pCid );
        }
#ifdef _SENDEBUG
    else
        {
        TLSLOG_FORMAT(( KSenHostletConnectionLogChannelBase + iConnectionID, KSenServiceConnectionStatusLogLevel, _L8("- MAJOR: iFileProgressProperty.Get(propertyValue) failed: %d"), getPropertyCode ));
        }
#endif // _SENDEBUG 
    }
    
TInt CSenFileProgressObserver::RunError( TInt aError )
	{
	TLSLOG_FORMAT(( KSenHostletConnectionLogChannelBase + iConnectionID, KSenServiceConnectionStatusLogLevel, _L8("CSenFileProgressObserver::RunError:[%d]"), aError ));
	// return aError;
	return KErrNone; // ignore the error, this is conscious decision.
	}


// ------------------------------------------------------------------------------------------------------------
    
    
// End of file

